'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 });