'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator'); var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2); var _extends2 = require('babel-runtime/helpers/extends'); var _extends3 = _interopRequireDefault(_extends2); var _config = require('@expo/config'); var ConfigUtils = _interopRequireWildcard(_config); var _xdl = require('@expo/xdl'); var _graphqlTools = require('graphql-tools'); var _iterall = require('iterall'); var _mergeAsyncIterators = require('../asynciterators/mergeAsyncIterators'); var _mergeAsyncIterators2 = _interopRequireDefault(_mergeAsyncIterators); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // for prettier const graphql = text => text; const typeDefs = graphql` enum Platform { ANDROID IOS } enum HostType { lan localhost tunnel } type User { username: String } type Project { id: ID! # Absolute path of the project directory. projectDir: String! # The URL where the Expo manifest is being served. manifestUrl: String # Settings specific to this project, e.g. URL settings. settings: ProjectSettings! # Project configuration from app.json. config: ProjectConfig # Things that can send messages sources: [Source] # All messages from all sources messages: MessageConnection! } type ProjectSettings { hostType: HostType! dev: Boolean! minify: Boolean! } input ProjectSettingsInput { hostType: HostType dev: Boolean minify: Boolean } type ProjectConfig { name: String description: String slug: String githubUrl: String } input ProjectConfigInput { name: String description: String slug: String githubUrl: String } type UserSettings { id: ID! sendTo: String } enum SendMedium { email sms } type SendProjectResult { medium: SendMedium! url: String! } union OpenSimulatorResult = OpenSimulatorSuccess | OpenSimulatorError type OpenSimulatorSuccess { url: String! } type OpenSimulatorError { error: String! } type PublishProjectResult { url: String! } interface Source { id: ID! name: String! messages: MessageConnection! } type Issues implements Source { id: ID! name: String! messages: MessageConnection! } type Process implements Source { id: ID! name: String! messages: MessageConnection! } type Device implements Source { id: ID! name: String! messages: MessageConnection! } enum LogLevel { DEBUG INFO WARN ERROR } interface Message { id: ID! msg: String! time: String! source: Source! level: LogLevel! } type Issue implements Message { id: ID! msg: String! time: String! source: Issues! level: LogLevel! } type LogMessage implements Message { id: ID! msg: String! time: String! source: Process! level: LogLevel! } type DeviceMessage implements Message { id: ID! msg: String! time: String! source: Device! level: LogLevel! includesStack: Boolean } type MetroInitializeStarted implements Message { id: ID! msg: String! time: String! source: Process! level: LogLevel! } type BuildProgress implements Message { id: ID! msg: String! time: String! source: Process! level: LogLevel! progress: Int! duration: Int! } type BuildFinished implements Message { id: ID! msg: String! time: String! source: Process! level: LogLevel! duration: Int! } type BuildError implements Message { id: ID! msg: String! time: String! source: Process! level: LogLevel! error: String! duration: Int! } type TunnelReady implements Message { id: ID! msg: String! time: String! source: Process! level: LogLevel! } type PageInfo { lastReadCursor: String lastCursor: String } type MessageConnection { count: Int! unreadCount: Int! nodes: [Message!] pageInfo: PageInfo } enum MessagePayloadType { ADDED UPDATED DELETED } union MessageSubscriptionPayload = MessagePayload | SourceClearedPayload type MessagePayload { type: MessagePayloadType! cursor: String node: Message! } type SourceClearedPayload { source: Source } type ProjectManagerLayout { id: ID! selected: Source sources: [Source] } input ProjectManagerLayoutInput { selected: ID sources: [ID!] } type ProcessInfo { isAndroidSimulatorSupported: Boolean isIosSimulatorSupported: Boolean webAppUrl: String } type Query { # The project this instance of the XDL server is serving. currentProject: Project! # Globally persisted user preferences. userSettings: UserSettings! # Layout of the sections in project manager projectManagerLayout: ProjectManagerLayout # Information about the current process processInfo: ProcessInfo # Current logged-in user user: User } type Mutation { # Opens the app in an iOS simulator or and Android device/emulator. openSimulator(platform: Platform!): OpenSimulatorResult # Publishes the current project to expo.io publishProject(releaseChannel: String): PublishProjectResult # Sends the project URL by email. sendProjectUrl(recipient: String!): SendProjectResult # Compresses the images in a project optimizeAssets: Project # Updates specified project settings. setProjectSettings(settings: ProjectSettingsInput!): Project # Update projectConfig setProjectConfig(input: ProjectConfigInput!): Project # Update the layout setProjectManagerLayout(input: ProjectManagerLayoutInput): ProjectManagerLayout # Update a last read status for a source updateLastRead(sourceId: ID!, lastReadCursor: String!): Source # Clear a log from a source clearMessages(sourceId: ID!): Source } type Subscription { # TODO(freiksenet): per-project log messages(after: String): MessageSubscriptionPayload } `; const messageResolvers = { level(message) { if (message.level <= _xdl.Logger.DEBUG) return 'DEBUG'; if (message.level <= _xdl.Logger.INFO) return 'INFO'; if (message.level <= _xdl.Logger.WARN) return 'WARN'; return 'ERROR'; } }; const USER_SETTINGS_ID = 'UserSettings'; const PROJECT_MANAGER_LAYOUT_ID = 'ProjectManagerLayout'; const resolvers = { OpenSimulatorResult: { __resolveType(result) { if (result.success) { return 'OpenSimulatorSuccess'; } else { return 'OpenSimulatorError'; } } }, Message: { __resolveType(message) { if (message.tag === 'device') { return 'DeviceMessage'; } else if (message.issueId) { return 'Issue'; } else if (message._metroEventType) { switch (message._metroEventType) { case 'METRO_INITIALIZE_STARTED': { return 'MetroInitializeStarted'; } case 'BUILD_STARTED': case 'BUILD_PROGRESS': { return 'BuildProgress'; } case 'FINISHED': { return 'BuildFinished'; } case 'FAILED': { return 'BuildError'; } } } else if (message._expoEventType === 'TUNNEL_READY') { return 'TunnelReady'; } return 'LogMessage'; } }, Issue: (0, _extends3.default)({}, messageResolvers, { id(issue) { return `Issue:${issue.id}`; }, source(issue, args, context) { return context.getIssuesSource(); } }), LogMessage: (0, _extends3.default)({}, messageResolvers, { source(message, args, context) { return context.getProcessSource(); } }), MetroInitializeStarted: (0, _extends3.default)({}, messageResolvers, { source(message, args, context) { return context.getProcessSource(); } }), BuildProgress: (0, _extends3.default)({}, messageResolvers, { source(message, args, context) { return context.getProcessSource(); } }), BuildFinished: (0, _extends3.default)({}, messageResolvers, { source(message, args, context) { return context.getProcessSource(); } }), BuildError: (0, _extends3.default)({}, messageResolvers, { source(message, args, context) { return context.getProcessSource(); } }), TunnelReady: (0, _extends3.default)({}, messageResolvers, { source(message, args, context) { return context.getProcessSource(); } }), DeviceMessage: (0, _extends3.default)({}, messageResolvers, { source(message) { return { id: message.deviceId, name: message.deviceName }; } }), MessageSubscriptionPayload: { __resolveType(payload) { if (payload.type === 'CLEARED') { return 'SourceClearedPayload'; } else { return 'MessagePayload'; } } }, SourceClearedPayload: { source(payload, args, context) { return context.getSourceById(payload.sourceId); } }, Project: { id(project) { return Buffer.from(project.projectDir).toString('base64'); }, manifestUrl(project) { return (0, _asyncToGenerator3.default)(function* () { if ((yield _xdl.Project.currentStatus(project.projectDir)) === 'running') { return _xdl.UrlUtils.constructManifestUrlAsync(project.projectDir); } else { return null; } })(); }, settings(project) { return _xdl.ProjectSettings.readAsync(project.projectDir); }, config(project) { return (0, _asyncToGenerator3.default)(function* () { var _ref = yield _xdl.ProjectUtils.readConfigJsonAsync(project.projectDir); let exp = _ref.exp; return exp; })(); }, sources(project, args, context) { return context.getSources(); }, messages(project, args, context) { return context.getMessageConnection(); } }, ProjectSettings: { hostType(projectSettings) { if (_xdl.Config.offline && projectSettings.hostType === 'tunnel') { return 'lan'; } else { return projectSettings.hostType; } } }, Source: { __resolveType(source) { return source.__typename; } }, Issues: { messages(source, args, context) { return context.getMessageConnection(source); } }, Process: { messages(source, args, context) { return context.getMessageConnection(source); } }, Device: { messages(source, args, context) { return context.getMessageConnection(source); } }, ProjectManagerLayout: { id() { return PROJECT_MANAGER_LAYOUT_ID; }, selected(layout, args, context) { const sources = context.getSources(); return sources.find(source => source.id === layout.selected); }, sources(layout, args, context) { const sources = context.getSources(); if (!layout.sources) { return []; } else { return layout.sources.map(sourceId => sources.find(source => source.id === sourceId)).filter(source => source); } } }, UserSettings: { id() { return USER_SETTINGS_ID; } }, Query: { currentProject(parent, args, context) { return context.getCurrentProject(); }, userSettings() { return _xdl.UserSettings.readAsync(); }, projectManagerLayout(parent, args, context) { return context.getProjectManagerLayout(); }, processInfo(parent, args, context) { return (0, _asyncToGenerator3.default)(function* () { const currentProject = context.getCurrentProject(); var _ref2 = yield _xdl.ProjectUtils.readConfigJsonAsync(currentProject.projectDir); const exp = _ref2.exp; return { isAndroidSimulatorSupported: _xdl.Android.isPlatformSupported(), isIosSimulatorSupported: _xdl.Simulator.isPlatformSupported(), webAppUrl: exp.platforms.includes('web') ? yield _xdl.UrlUtils.constructWebAppUrlAsync(currentProject.projectDir) : null }; })(); }, user() { return (0, _asyncToGenerator3.default)(function* () { const username = yield _xdl.UserManager.getCurrentUsernameAsync(); return { username }; })(); } }, Mutation: { openSimulator(parent, { platform }, context) { return (0, _asyncToGenerator3.default)(function* () { const currentProject = context.getCurrentProject(); let result; if (platform === 'ANDROID') { result = yield _xdl.Android.openProjectAsync(currentProject.projectDir); } else { result = yield _xdl.Simulator.openProjectAsync(currentProject.projectDir); } if (result.success) { return result; } else { return { success: false, error: result.error.toString() }; } })(); }, publishProject(parent, { releaseChannel }, context) { return (0, _asyncToGenerator3.default)(function* () { var _context$getCurrentPr = context.getCurrentProject(); const projectDir = _context$getCurrentPr.projectDir; try { const result = yield _xdl.Project.publishAsync(projectDir, { releaseChannel }); return result; } catch (error) { _xdl.ProjectUtils.logError(projectDir, 'expo', error.message); throw error; } })(); }, setProjectSettings(parent, { settings }, context) { return (0, _asyncToGenerator3.default)(function* () { const currentProject = context.getCurrentProject(); let updatedSettings = yield _xdl.ProjectSettings.setAsync(currentProject.projectDir, settings); return (0, _extends3.default)({}, currentProject, { settings: updatedSettings }); })(); }, optimizeAssets(parent, { settings }, context) { return (0, _asyncToGenerator3.default)(function* () { const currentProject = context.getCurrentProject(); yield _xdl.Project.optimizeAsync(currentProject.projectDir); return (0, _extends3.default)({}, currentProject); })(); }, setProjectConfig(parent, { input }, context) { return (0, _asyncToGenerator3.default)(function* () { const currentProject = context.getCurrentProject(); const filteredInput = (0, _extends3.default)({}, input, { githubUrl: input.githubUrl.match(/^https:\/\/github.com\//) ? input.githubUrl : undefined }); var _ref3 = yield ConfigUtils.writeConfigJsonAsync(currentProject.projectDir, filteredInput); let exp = _ref3.exp; return (0, _extends3.default)({}, currentProject, { config: exp }); })(); }, sendProjectUrl(parent, { recipient }, context) { return (0, _asyncToGenerator3.default)(function* () { const currentProject = context.getCurrentProject(); let url = yield _xdl.UrlUtils.constructManifestUrlAsync(currentProject.projectDir); let result = yield _xdl.Exp.sendAsync(recipient, url); yield _xdl.UserSettings.setAsync('sendTo', recipient); return { medium: result.medium, url }; })(); }, setProjectManagerLayout(parent, { input }, context) { context.setProjectManagerLayout(input); return context.getProjectManagerLayout(); }, updateLastRead(parent, { sourceId, lastReadCursor }, context) { const source = context.getSourceById(sourceId); if (source) { context.setLastRead(sourceId, lastReadCursor); return source; } else { return null; } }, clearMessages(parent, { sourceId }, context) { const source = context.getSourceById(sourceId); context.clearMessages(source.id); return source; } }, Subscription: { messages: { subscribe(parent, { after }, context) { let parsedCursor = null; if (after) { parsedCursor = parseInt(after, 10); } const issueIterator = context.getIssueIterator(); const messageIterator = context.getMessageIterator(parsedCursor); const iterator = (0, _mergeAsyncIterators2.default)(issueIterator, messageIterator); return { next() { return (0, _asyncToGenerator3.default)(function* () { const result = yield iterator.next(); const done = result.done, value = result.value; return { value: { messages: (0, _extends3.default)({}, value) }, done }; })(); }, [_iterall.$$asyncIterator]() { return this; } }; } } } }; exports.default = (0, _graphqlTools.makeExecutableSchema)({ typeDefs, resolvers });