@playdrop/playdrop-cli 0.9.6 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config/client-meta.json +2 -2
- package/dist/apiClient.d.ts +10 -0
- package/dist/apiClient.js +55 -2
- package/dist/appUrls.d.ts +1 -0
- package/dist/appUrls.js +9 -0
- package/dist/apps/build.js +39 -28
- package/dist/apps/index.d.ts +1 -0
- package/dist/apps/index.js +2 -0
- package/dist/apps/launchCheck.d.ts +2 -0
- package/dist/apps/launchCheck.js +31 -6
- package/dist/apps/registration.d.ts +1 -0
- package/dist/apps/registration.js +1 -0
- package/dist/apps/upload.d.ts +1 -0
- package/dist/apps/upload.js +4 -17
- package/dist/captureRuntime.d.ts +14 -0
- package/dist/captureRuntime.js +329 -0
- package/dist/catalogue.d.ts +4 -2
- package/dist/catalogue.js +50 -7
- package/dist/commandContext.js +61 -4
- package/dist/commands/capture.d.ts +1 -0
- package/dist/commands/capture.js +30 -13
- package/dist/commands/captureRemote.d.ts +2 -0
- package/dist/commands/captureRemote.js +90 -0
- package/dist/commands/create.d.ts +0 -1
- package/dist/commands/create.js +2 -151
- package/dist/commands/creations.d.ts +0 -13
- package/dist/commands/creations.js +0 -141
- package/dist/commands/dev.d.ts +2 -1
- package/dist/commands/dev.js +23 -6
- package/dist/commands/devServer.js +3 -1
- package/dist/commands/generation.d.ts +1 -0
- package/dist/commands/generation.js +274 -0
- package/dist/commands/review.d.ts +46 -0
- package/dist/commands/review.js +353 -0
- package/dist/commands/upload.d.ts +27 -1
- package/dist/commands/upload.js +962 -21
- package/dist/commands/validate.js +5 -0
- package/dist/commands/worker/runtime.d.ts +81 -0
- package/dist/commands/worker/runtime.js +458 -0
- package/dist/commands/worker.d.ts +158 -0
- package/dist/commands/worker.js +2626 -0
- package/dist/config.d.ts +2 -0
- package/dist/config.js +23 -0
- package/dist/index.js +116 -30
- package/dist/shellProbe.d.ts +1 -1
- package/dist/shellProbe.js +3 -3
- package/dist/workspaceAuth.d.ts +3 -0
- package/dist/workspaceAuth.js +14 -0
- package/node_modules/@playdrop/api-client/dist/client.d.ts +36 -15
- package/node_modules/@playdrop/api-client/dist/client.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/client.js +2 -2
- package/node_modules/@playdrop/api-client/dist/domains/admin.d.ts +5 -2
- package/node_modules/@playdrop/api-client/dist/domains/admin.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/admin.js +51 -3
- package/node_modules/@playdrop/api-client/dist/domains/agent-tasks.d.ts +75 -0
- package/node_modules/@playdrop/api-client/dist/domains/agent-tasks.d.ts.map +1 -0
- package/node_modules/@playdrop/api-client/dist/domains/agent-tasks.js +478 -0
- package/node_modules/@playdrop/api-client/dist/index.d.ts +36 -15
- package/node_modules/@playdrop/api-client/dist/index.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/index.js +153 -42
- package/node_modules/@playdrop/config/client-meta.json +2 -2
- package/node_modules/@playdrop/types/dist/api.d.ts +662 -75
- package/node_modules/@playdrop/types/dist/api.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/api.js +100 -9
- package/node_modules/@playdrop/types/dist/app.d.ts +2 -0
- package/node_modules/@playdrop/types/dist/app.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/app.js +3 -0
- package/node_modules/@playdrop/types/dist/version.d.ts +1 -0
- package/node_modules/@playdrop/types/dist/version.d.ts.map +1 -1
- package/package.json +2 -1
- package/node_modules/@playdrop/api-client/dist/domains/game-ideas.d.ts +0 -46
- package/node_modules/@playdrop/api-client/dist/domains/game-ideas.d.ts.map +0 -1
- package/node_modules/@playdrop/api-client/dist/domains/game-ideas.js +0 -177
package/dist/commands/capture.js
CHANGED
|
@@ -16,6 +16,7 @@ const captureRuntime_1 = require("../captureRuntime");
|
|
|
16
16
|
const devAuth_1 = require("../devAuth");
|
|
17
17
|
const devRuntimeAssets_1 = require("./devRuntimeAssets");
|
|
18
18
|
const dev_1 = require("./dev");
|
|
19
|
+
const dev_2 = require("./dev");
|
|
19
20
|
const MOBILE_USER_AGENT = 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1';
|
|
20
21
|
const SURFACE_PRESETS = {
|
|
21
22
|
desktop: {
|
|
@@ -120,6 +121,7 @@ function resolveCaptureDevOptions(options) {
|
|
|
120
121
|
async function capture(targetArg, options = {}) {
|
|
121
122
|
const timeoutSeconds = (0, captureRuntime_1.validateCaptureTimeout)(options.timeoutSeconds);
|
|
122
123
|
const timeoutMs = Math.round(timeoutSeconds * 1000);
|
|
124
|
+
const devRouterPort = (0, dev_2.resolveDevRouterPort)(options.port ?? process.env.PLAYDROP_DEV_ROUTER_PORT);
|
|
123
125
|
let minimumLogLevel;
|
|
124
126
|
let loginOverride;
|
|
125
127
|
let devOptions;
|
|
@@ -242,11 +244,13 @@ async function capture(targetArg, options = {}) {
|
|
|
242
244
|
}
|
|
243
245
|
const projectInfo = (0, devShared_1.findProjectInfo)(filePath);
|
|
244
246
|
const devScriptAvailable = Boolean(projectInfo.projectDir && projectInfo.packageJson && typeof projectInfo.packageJson.scripts?.dev === 'string');
|
|
245
|
-
await (0, commandContext_1.withEnvironment)('project capture', 'Capturing app logs', async ({ client, env, envConfig }) => {
|
|
247
|
+
await (0, commandContext_1.withEnvironment)('project capture', 'Capturing app logs', async ({ client, env, envConfig, token, workspaceAuth }) => {
|
|
246
248
|
let currentUsername = '';
|
|
249
|
+
let currentUser = null;
|
|
247
250
|
try {
|
|
248
|
-
const
|
|
249
|
-
|
|
251
|
+
const fetchedCurrentUser = await (0, devShared_1.fetchDevUser)(client);
|
|
252
|
+
currentUser = fetchedCurrentUser;
|
|
253
|
+
currentUsername = fetchedCurrentUser.username.trim();
|
|
250
254
|
}
|
|
251
255
|
catch (error) {
|
|
252
256
|
if (error instanceof http_1.CLIUnsupportedClientError) {
|
|
@@ -280,8 +284,14 @@ async function capture(targetArg, options = {}) {
|
|
|
280
284
|
}
|
|
281
285
|
throw error;
|
|
282
286
|
}
|
|
283
|
-
|
|
284
|
-
|
|
287
|
+
const taskScoped = Boolean(workspaceAuth?.config.taskToken);
|
|
288
|
+
if (devOptions.selection.devAuth === 'viewer' && !loginOverride && !taskScoped) {
|
|
289
|
+
(0, messages_1.printErrorWithHelp)('Use --username and --password to establish a browser session before running --dev-auth viewer.', [], { command: 'project capture' });
|
|
290
|
+
process.exitCode = 1;
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
if (devOptions.selection.devAuth === 'player' && !loginOverride) {
|
|
294
|
+
(0, messages_1.printErrorWithHelp)('Use --username and --password to establish a browser session before running --dev-auth player.', [], { command: 'project capture' });
|
|
285
295
|
process.exitCode = 1;
|
|
286
296
|
return;
|
|
287
297
|
}
|
|
@@ -291,7 +301,7 @@ async function capture(targetArg, options = {}) {
|
|
|
291
301
|
creatorUsername: currentUsername,
|
|
292
302
|
appType: appTypeSlug,
|
|
293
303
|
appName,
|
|
294
|
-
port:
|
|
304
|
+
port: devRouterPort,
|
|
295
305
|
}, 750);
|
|
296
306
|
const devServerStartedByCapture = !serverAlreadyRunning;
|
|
297
307
|
let serverHandle = null;
|
|
@@ -328,7 +338,7 @@ async function capture(targetArg, options = {}) {
|
|
|
328
338
|
creatorUsername: currentUsername,
|
|
329
339
|
appType: appTypeSlug,
|
|
330
340
|
appName,
|
|
331
|
-
port:
|
|
341
|
+
port: devRouterPort,
|
|
332
342
|
})).toString(),
|
|
333
343
|
});
|
|
334
344
|
}
|
|
@@ -344,14 +354,14 @@ async function capture(targetArg, options = {}) {
|
|
|
344
354
|
creatorUsername: currentUsername,
|
|
345
355
|
appType: appTypeSlug,
|
|
346
356
|
appName,
|
|
347
|
-
port:
|
|
357
|
+
port: devRouterPort,
|
|
348
358
|
})}`);
|
|
349
359
|
try {
|
|
350
360
|
await (0, devServer_1.updateMountedDevRuntimeAssetManifest)({
|
|
351
361
|
creatorUsername: currentUsername,
|
|
352
362
|
appName,
|
|
353
363
|
runtimeAssetManifest,
|
|
354
|
-
port:
|
|
364
|
+
port: devRouterPort,
|
|
355
365
|
});
|
|
356
366
|
}
|
|
357
367
|
catch (error) {
|
|
@@ -369,7 +379,7 @@ async function capture(targetArg, options = {}) {
|
|
|
369
379
|
appType: appTypeSlug,
|
|
370
380
|
creatorUsername: currentUsername,
|
|
371
381
|
htmlPath: filePath,
|
|
372
|
-
port:
|
|
382
|
+
port: devRouterPort,
|
|
373
383
|
projectInfo,
|
|
374
384
|
runtimeAssetManifest,
|
|
375
385
|
});
|
|
@@ -389,7 +399,7 @@ async function capture(targetArg, options = {}) {
|
|
|
389
399
|
], { command: 'project capture' });
|
|
390
400
|
}
|
|
391
401
|
else {
|
|
392
|
-
(0, messages_1.printErrorWithHelp)(error?.message || `Failed to start the shared dev router on port ${
|
|
402
|
+
(0, messages_1.printErrorWithHelp)(error?.message || `Failed to start the shared dev router on port ${devRouterPort}.`, [
|
|
393
403
|
'Close the conflicting process or wait for the stale mount to exit.',
|
|
394
404
|
'Ensure the HTML file exists and is readable.',
|
|
395
405
|
], { command: 'project capture' });
|
|
@@ -412,7 +422,11 @@ async function capture(targetArg, options = {}) {
|
|
|
412
422
|
&& (devOptions.resetMode === 'before' || devOptions.resetMode === 'before-and-after');
|
|
413
423
|
const shouldResetAfter = devOptions.selection.devAuth === 'player'
|
|
414
424
|
&& (devOptions.resetMode === 'after' || devOptions.resetMode === 'before-and-after');
|
|
415
|
-
const
|
|
425
|
+
const savedSessionViewerCapture = devOptions.selection.devAuth === 'viewer' && !loginOverride && taskScoped;
|
|
426
|
+
const requiresRegisteredApp = devOptions.selection.devAuth === 'player'
|
|
427
|
+
|| shouldResetBefore
|
|
428
|
+
|| shouldResetAfter
|
|
429
|
+
|| (devOptions.selection.devAuth === 'viewer' && !savedSessionViewerCapture);
|
|
416
430
|
let registeredApp = null;
|
|
417
431
|
if (requiresRegisteredApp) {
|
|
418
432
|
try {
|
|
@@ -458,6 +472,7 @@ async function capture(targetArg, options = {}) {
|
|
|
458
472
|
devAuth: devOptions.selection.devAuth,
|
|
459
473
|
player: devOptions.selection.player ? String(devOptions.selection.player) : null,
|
|
460
474
|
launchCheck: true,
|
|
475
|
+
localDevPort: devRouterPort === devServer_1.DEV_ROUTER_PORT ? null : devRouterPort,
|
|
461
476
|
});
|
|
462
477
|
const frameUrl = (0, devAuth_1.applyHostedDevAuthSelectionToUrl)(captureBaseUrl, devOptions.selection);
|
|
463
478
|
console.log(`[capture] Launching Playwright against ${frameUrl}`);
|
|
@@ -484,7 +499,9 @@ async function capture(targetArg, options = {}) {
|
|
|
484
499
|
username: loginOverride.username,
|
|
485
500
|
password: loginOverride.password,
|
|
486
501
|
} : undefined,
|
|
487
|
-
|
|
502
|
+
token: savedSessionViewerCapture ? token : undefined,
|
|
503
|
+
user: savedSessionViewerCapture ? currentUser : undefined,
|
|
504
|
+
savedSessionBootstrap: savedSessionViewerCapture,
|
|
488
505
|
enableCaptureBridge: true,
|
|
489
506
|
requireHostedLaunchReady: true,
|
|
490
507
|
});
|
|
@@ -6,6 +6,8 @@ type CaptureRemoteOptions = {
|
|
|
6
6
|
username?: string;
|
|
7
7
|
password?: string;
|
|
8
8
|
loginUrl?: string;
|
|
9
|
+
actions?: string;
|
|
10
|
+
viewport?: string;
|
|
9
11
|
};
|
|
10
12
|
export declare function buildCaptureRemoteCommandArgs(url: string | undefined, options?: CaptureRemoteOptions): string[] | null;
|
|
11
13
|
export declare function captureRemote(url: string | undefined, options?: CaptureRemoteOptions): Promise<void>;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.buildCaptureRemoteCommandArgs = buildCaptureRemoteCommandArgs;
|
|
4
4
|
exports.captureRemote = captureRemote;
|
|
5
|
+
const promises_1 = require("node:fs/promises");
|
|
5
6
|
const node_path_1 = require("node:path");
|
|
6
7
|
const types_1 = require("@playdrop/types");
|
|
7
8
|
const commandContext_1 = require("../commandContext");
|
|
@@ -42,6 +43,75 @@ function parseTimeout(raw) {
|
|
|
42
43
|
}
|
|
43
44
|
return parsed;
|
|
44
45
|
}
|
|
46
|
+
function parseViewport(raw) {
|
|
47
|
+
const value = raw?.trim();
|
|
48
|
+
if (!value) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
const match = /^(\d{2,5})x(\d{2,5})$/i.exec(value);
|
|
52
|
+
if (!match) {
|
|
53
|
+
throw new Error('invalid_viewport');
|
|
54
|
+
}
|
|
55
|
+
const width = Number.parseInt(match[1], 10);
|
|
56
|
+
const height = Number.parseInt(match[2], 10);
|
|
57
|
+
if (width < 320 || width > 4096 || height < 320 || height > 4096) {
|
|
58
|
+
throw new Error('invalid_viewport');
|
|
59
|
+
}
|
|
60
|
+
return { width, height };
|
|
61
|
+
}
|
|
62
|
+
function normalizeCaptureAction(raw, index) {
|
|
63
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
64
|
+
throw new Error(`invalid_action:${index}`);
|
|
65
|
+
}
|
|
66
|
+
const action = raw;
|
|
67
|
+
const type = typeof action.type === 'string' ? action.type.trim() : '';
|
|
68
|
+
if (type === 'click') {
|
|
69
|
+
const x = typeof action.x === 'number' ? action.x : Number.NaN;
|
|
70
|
+
const y = typeof action.y === 'number' ? action.y : Number.NaN;
|
|
71
|
+
const button = typeof action.button === 'string' ? action.button.trim() : undefined;
|
|
72
|
+
if (!Number.isFinite(x) || !Number.isFinite(y) || x < 0 || y < 0) {
|
|
73
|
+
throw new Error(`invalid_action:${index}:click_coordinates`);
|
|
74
|
+
}
|
|
75
|
+
if (button !== undefined && button !== 'left' && button !== 'right' && button !== 'middle') {
|
|
76
|
+
throw new Error(`invalid_action:${index}:click_button`);
|
|
77
|
+
}
|
|
78
|
+
return button ? { type: 'click', x, y, button } : { type: 'click', x, y };
|
|
79
|
+
}
|
|
80
|
+
if (type === 'press') {
|
|
81
|
+
const key = typeof action.key === 'string' ? action.key.trim() : '';
|
|
82
|
+
if (!key) {
|
|
83
|
+
throw new Error(`invalid_action:${index}:press_key`);
|
|
84
|
+
}
|
|
85
|
+
return { type: 'press', key };
|
|
86
|
+
}
|
|
87
|
+
if (type === 'wait') {
|
|
88
|
+
const ms = typeof action.ms === 'number' ? action.ms : Number.NaN;
|
|
89
|
+
if (!Number.isInteger(ms) || ms < 0 || ms > 60000) {
|
|
90
|
+
throw new Error(`invalid_action:${index}:wait_ms`);
|
|
91
|
+
}
|
|
92
|
+
return { type: 'wait', ms };
|
|
93
|
+
}
|
|
94
|
+
throw new Error(`invalid_action:${index}:type`);
|
|
95
|
+
}
|
|
96
|
+
async function readCaptureActions(actionsPath) {
|
|
97
|
+
if (!actionsPath) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
let parsed;
|
|
101
|
+
try {
|
|
102
|
+
parsed = JSON.parse(await (0, promises_1.readFile)(actionsPath, 'utf8'));
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
throw new Error(`invalid_actions_file:${error instanceof Error ? error.message : String(error)}`);
|
|
106
|
+
}
|
|
107
|
+
if (!Array.isArray(parsed)) {
|
|
108
|
+
throw new Error('invalid_actions_file:expected_array');
|
|
109
|
+
}
|
|
110
|
+
if (parsed.length > 100) {
|
|
111
|
+
throw new Error('invalid_actions_file:too_many_actions');
|
|
112
|
+
}
|
|
113
|
+
return parsed.map((entry, index) => normalizeCaptureAction(entry, index));
|
|
114
|
+
}
|
|
45
115
|
function assertValidUrl(value, errorCode) {
|
|
46
116
|
try {
|
|
47
117
|
new URL(value);
|
|
@@ -77,6 +147,8 @@ function buildCaptureRemoteCommandArgs(url, options = {}) {
|
|
|
77
147
|
pushOptionalArg(args, '--screenshot', options.screenshot);
|
|
78
148
|
pushOptionalArg(args, '--log', options.log);
|
|
79
149
|
pushOptionalArg(args, '--expected-url', options.expectedUrl);
|
|
150
|
+
pushOptionalArg(args, '--actions', options.actions);
|
|
151
|
+
pushOptionalArg(args, '--viewport', options.viewport);
|
|
80
152
|
if (username) {
|
|
81
153
|
args.push('--username', username, '--password', password);
|
|
82
154
|
}
|
|
@@ -104,6 +176,8 @@ function parseOptions(url, options = {}) {
|
|
|
104
176
|
timeoutSeconds: parseTimeout(options.timeout),
|
|
105
177
|
screenshotPath: (0, node_path_1.resolve)(process.cwd(), options.screenshot?.trim() || 'output/playwright/capture-url.png'),
|
|
106
178
|
logPath: options.log?.trim() ? (0, node_path_1.resolve)(process.cwd(), options.log.trim()) : null,
|
|
179
|
+
actionsPath: options.actions?.trim() ? (0, node_path_1.resolve)(process.cwd(), options.actions.trim()) : null,
|
|
180
|
+
viewport: parseViewport(options.viewport),
|
|
107
181
|
login: username
|
|
108
182
|
? {
|
|
109
183
|
username,
|
|
@@ -135,6 +209,11 @@ async function captureRemote(url, options = {}) {
|
|
|
135
209
|
process.exitCode = 1;
|
|
136
210
|
return;
|
|
137
211
|
}
|
|
212
|
+
if (error instanceof Error && error.message === 'invalid_viewport') {
|
|
213
|
+
(0, messages_1.printErrorWithHelp)('The --viewport value must be WIDTHxHEIGHT with each side between 320 and 4096 pixels.', [], { command: 'project capture remote' });
|
|
214
|
+
process.exitCode = 1;
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
138
217
|
if (error instanceof Error && error.message === 'invalid_credentials_pair') {
|
|
139
218
|
(0, messages_1.printErrorWithHelp)('Use --username and --password together.', [], { command: 'project capture remote' });
|
|
140
219
|
process.exitCode = 1;
|
|
@@ -149,6 +228,15 @@ async function captureRemote(url, options = {}) {
|
|
|
149
228
|
process.exitCode = 1;
|
|
150
229
|
return;
|
|
151
230
|
}
|
|
231
|
+
let actions = null;
|
|
232
|
+
try {
|
|
233
|
+
actions = await readCaptureActions(parsed.actionsPath);
|
|
234
|
+
}
|
|
235
|
+
catch (error) {
|
|
236
|
+
(0, messages_1.printErrorWithHelp)(error instanceof Error ? error.message : String(error), [], { command: 'project capture remote' });
|
|
237
|
+
process.exitCode = 1;
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
152
240
|
await (0, commandContext_1.withEnvironment)('project capture remote', 'Capturing remote app logs', async ({ client, token }) => {
|
|
153
241
|
let currentUser = null;
|
|
154
242
|
try {
|
|
@@ -190,6 +278,8 @@ async function captureRemote(url, options = {}) {
|
|
|
190
278
|
token: parsed.login ? undefined : token,
|
|
191
279
|
user: parsed.login ? undefined : currentUser,
|
|
192
280
|
login: parsed.login,
|
|
281
|
+
actions: actions ?? undefined,
|
|
282
|
+
contextOptions: parsed.viewport ? { viewport: parsed.viewport } : undefined,
|
|
193
283
|
});
|
|
194
284
|
if (result.errorCount > 0) {
|
|
195
285
|
console.error(`[capture] Completed with ${result.errorCount} error(s) after ${parsed.timeoutSeconds} seconds.`);
|
package/dist/commands/create.js
CHANGED
|
@@ -24,8 +24,6 @@ const clientInfo_1 = require("../clientInfo");
|
|
|
24
24
|
const CATALOGUE_FILENAME = 'catalogue.json';
|
|
25
25
|
const LEGACY_CATALOGUE_VERSION_KEY = ['schema', 'Version'].join('');
|
|
26
26
|
const ALLOWED_CATALOGUE_TOP_LEVEL_KEYS = new Set(['apps', 'assetSpecs', 'assets', 'assetPacks']);
|
|
27
|
-
const DEFAULT_GAME_IDEA_TEMPLATE = 'playdrop/template/typescript_template';
|
|
28
|
-
const GAME_IDEA_LOOKUP_PAGE_SIZE = 200;
|
|
29
27
|
function buildArchiveDownloadHeaders(url, apiBase, token) {
|
|
30
28
|
const targetUrl = new URL(url, apiBase);
|
|
31
29
|
const apiOrigin = new URL(apiBase).origin;
|
|
@@ -1017,50 +1015,13 @@ function describeInitSummary(summary) {
|
|
|
1017
1015
|
}
|
|
1018
1016
|
return `Project bootstrap recap: ${parts.join('; ')}.`;
|
|
1019
1017
|
}
|
|
1020
|
-
function gameIdeaMatchesRef(gameIdea, ref) {
|
|
1021
|
-
return String(gameIdea.id) === ref || gameIdea.slug === ref;
|
|
1022
|
-
}
|
|
1023
|
-
async function findGameIdeaForCreate(client, gameIdeaRef) {
|
|
1024
|
-
let offset = 0;
|
|
1025
|
-
for (;;) {
|
|
1026
|
-
const response = await client.listGameIdeas({
|
|
1027
|
-
state: 'ALL',
|
|
1028
|
-
limit: GAME_IDEA_LOOKUP_PAGE_SIZE,
|
|
1029
|
-
offset,
|
|
1030
|
-
});
|
|
1031
|
-
const match = response.gameIdeas.find((gameIdea) => gameIdeaMatchesRef(gameIdea, gameIdeaRef));
|
|
1032
|
-
if (match) {
|
|
1033
|
-
return match;
|
|
1034
|
-
}
|
|
1035
|
-
if (!response.pagination.hasMore) {
|
|
1036
|
-
throw new Error('game_idea_not_found');
|
|
1037
|
-
}
|
|
1038
|
-
offset += response.pagination.limit;
|
|
1039
|
-
}
|
|
1040
|
-
}
|
|
1041
|
-
function inferCreateSourceFromGameIdea(gameIdea) {
|
|
1042
|
-
if (gameIdea.inputMode !== 'REMIX') {
|
|
1043
|
-
return { template: DEFAULT_GAME_IDEA_TEMPLATE };
|
|
1044
|
-
}
|
|
1045
|
-
const sourceAppRef = typeof gameIdea.inputData.sourceAppRef === 'string' ? gameIdea.inputData.sourceAppRef.trim() : '';
|
|
1046
|
-
if (!sourceAppRef) {
|
|
1047
|
-
throw new Error('game_idea_remix_source_missing');
|
|
1048
|
-
}
|
|
1049
|
-
return { remix: sourceAppRef };
|
|
1050
|
-
}
|
|
1051
|
-
async function inferCreateSourceOptionsForGameIdea(client, gameIdeaRef) {
|
|
1052
|
-
const gameIdea = await findGameIdeaForCreate(client, gameIdeaRef);
|
|
1053
|
-
return inferCreateSourceFromGameIdea(gameIdea);
|
|
1054
|
-
}
|
|
1055
1018
|
async function create(name, options = {}) {
|
|
1056
1019
|
const file = (0, node_path_1.resolve)(`${name}.html`);
|
|
1057
1020
|
const projectDirCandidate = (0, node_path_1.resolve)(name);
|
|
1058
|
-
const gameIdeaRef = typeof options.gameIdea === 'string' ? options.gameIdea.trim() : '';
|
|
1059
1021
|
let templateOptionRaw = options.template?.trim();
|
|
1060
1022
|
let remixOptionRaw = options.remix?.trim();
|
|
1061
1023
|
let parsedTemplate = null;
|
|
1062
1024
|
let parsedRemix = null;
|
|
1063
|
-
let ctx = null;
|
|
1064
1025
|
const existingLookup = (0, catalogue_1.resolveCatalogueEntries)(process.cwd(), { filterName: name });
|
|
1065
1026
|
if (existingLookup.errors.length > 0) {
|
|
1066
1027
|
for (const error of existingLookup.errors) {
|
|
@@ -1085,51 +1046,7 @@ async function create(name, options = {}) {
|
|
|
1085
1046
|
process.exitCode = 1;
|
|
1086
1047
|
return;
|
|
1087
1048
|
}
|
|
1088
|
-
|
|
1089
|
-
if (!reuseExistingApp && !templateOptionRaw && !remixOptionRaw && gameIdeaRef) {
|
|
1090
|
-
ctx = await (0, commandContext_1.resolveAuthenticatedEnvironmentContext)('project create app', 'Creating an app', { workspacePath: process.cwd() });
|
|
1091
|
-
if (!ctx) {
|
|
1092
|
-
return;
|
|
1093
|
-
}
|
|
1094
|
-
try {
|
|
1095
|
-
const inferredSource = await inferCreateSourceOptionsForGameIdea(ctx.client, gameIdeaRef);
|
|
1096
|
-
templateOptionRaw = inferredSource.template;
|
|
1097
|
-
remixOptionRaw = inferredSource.remix;
|
|
1098
|
-
}
|
|
1099
|
-
catch (error) {
|
|
1100
|
-
if (error instanceof http_1.CLIUnsupportedClientError) {
|
|
1101
|
-
process.exitCode = 1;
|
|
1102
|
-
return;
|
|
1103
|
-
}
|
|
1104
|
-
if (error instanceof types_1.UnsupportedClientError) {
|
|
1105
|
-
(0, http_1.handleUnsupportedError)(error, 'Resolve game idea');
|
|
1106
|
-
process.exitCode = 1;
|
|
1107
|
-
return;
|
|
1108
|
-
}
|
|
1109
|
-
if (error instanceof types_1.ApiError) {
|
|
1110
|
-
(0, messages_1.printErrorWithHelp)(`Failed to load game idea ${gameIdeaRef} (status ${error.status}).`, ['Confirm the game idea id or slug, then retry with "playdrop creations ideas browse --state all".'], { command: 'project create app' });
|
|
1111
|
-
process.exitCode = 1;
|
|
1112
|
-
return;
|
|
1113
|
-
}
|
|
1114
|
-
if (error instanceof TypeError) {
|
|
1115
|
-
(0, messages_1.printNetworkIssue)('Could not reach the Playdrop API to load the game idea.', 'project create app');
|
|
1116
|
-
process.exitCode = 1;
|
|
1117
|
-
return;
|
|
1118
|
-
}
|
|
1119
|
-
if (error instanceof Error && error.message === 'game_idea_not_found') {
|
|
1120
|
-
(0, messages_1.printErrorWithHelp)(`Could not find game idea ${gameIdeaRef}.`, ['Run "playdrop creations ideas browse --state all" and retry with the exact id or slug.'], { command: 'project create app' });
|
|
1121
|
-
process.exitCode = 1;
|
|
1122
|
-
return;
|
|
1123
|
-
}
|
|
1124
|
-
if (error instanceof Error && error.message === 'game_idea_remix_source_missing') {
|
|
1125
|
-
(0, messages_1.printErrorWithHelp)(`Game idea ${gameIdeaRef} is a remix idea but does not include a source app ref.`, ['Create a new game idea from the web remix flow, then retry with that id or slug.'], { command: 'project create app' });
|
|
1126
|
-
process.exitCode = 1;
|
|
1127
|
-
return;
|
|
1128
|
-
}
|
|
1129
|
-
throw error;
|
|
1130
|
-
}
|
|
1131
|
-
}
|
|
1132
|
-
reuseExistingApp = existingTask !== null && !templateOptionRaw && !remixOptionRaw;
|
|
1049
|
+
const reuseExistingApp = existingTask !== null && !templateOptionRaw && !remixOptionRaw;
|
|
1133
1050
|
if (!reuseExistingApp && ((0, node_fs_1.existsSync)(file) || (0, node_fs_1.existsSync)(projectDirCandidate))) {
|
|
1134
1051
|
(0, messages_1.printErrorWithHelp)(`Cannot create ${name} because a file or directory with that name already exists.`, [
|
|
1135
1052
|
'Choose a different app name or remove the existing file before running "playdrop project create app" again.'
|
|
@@ -1171,7 +1088,7 @@ async function create(name, options = {}) {
|
|
|
1171
1088
|
return;
|
|
1172
1089
|
}
|
|
1173
1090
|
}
|
|
1174
|
-
ctx =
|
|
1091
|
+
const ctx = await (0, commandContext_1.resolveAuthenticatedEnvironmentContext)('project create app', 'Creating an app', { workspacePath: process.cwd() });
|
|
1175
1092
|
if (!ctx) {
|
|
1176
1093
|
return;
|
|
1177
1094
|
}
|
|
@@ -1470,7 +1387,6 @@ async function create(name, options = {}) {
|
|
|
1470
1387
|
}
|
|
1471
1388
|
registrationTask = selectedTask;
|
|
1472
1389
|
}
|
|
1473
|
-
let gameIdeaAppRef = null;
|
|
1474
1390
|
if (registrationTask) {
|
|
1475
1391
|
const metadataWarning = (0, catalogue_1.formatMissingMetadataWarnings)(registrationTask);
|
|
1476
1392
|
if (metadataWarning) {
|
|
@@ -1591,7 +1507,6 @@ async function create(name, options = {}) {
|
|
|
1591
1507
|
throw error;
|
|
1592
1508
|
}
|
|
1593
1509
|
}
|
|
1594
|
-
gameIdeaAppRef = `${creatorUsername}/${name}`;
|
|
1595
1510
|
}
|
|
1596
1511
|
const projectDirLabel = projectDir ? ((0, node_path_1.relative)(process.cwd(), projectDir) || projectDir) : null;
|
|
1597
1512
|
const entryPointLabel = (0, node_path_1.relative)(process.cwd(), htmlFilePath) || (0, node_path_1.basename)(htmlFilePath);
|
|
@@ -1629,70 +1544,6 @@ async function create(name, options = {}) {
|
|
|
1629
1544
|
catalogueLabel = (0, node_path_1.relative)(process.cwd(), existingTask.catalogueAbsolutePath) || CATALOGUE_FILENAME;
|
|
1630
1545
|
}
|
|
1631
1546
|
}
|
|
1632
|
-
if (gameIdeaRef) {
|
|
1633
|
-
if (!gameIdeaAppRef) {
|
|
1634
|
-
try {
|
|
1635
|
-
const creatorUsername = await resolveAuthenticatedCreatorUsername(client);
|
|
1636
|
-
gameIdeaAppRef = `${creatorUsername}/${name}`;
|
|
1637
|
-
}
|
|
1638
|
-
catch (error) {
|
|
1639
|
-
if (error instanceof http_1.CLIUnsupportedClientError) {
|
|
1640
|
-
process.exitCode = 1;
|
|
1641
|
-
return;
|
|
1642
|
-
}
|
|
1643
|
-
if (error instanceof types_1.UnsupportedClientError) {
|
|
1644
|
-
(0, http_1.handleUnsupportedError)(error, 'Resolve creator account');
|
|
1645
|
-
process.exitCode = 1;
|
|
1646
|
-
return;
|
|
1647
|
-
}
|
|
1648
|
-
if (error instanceof types_1.ApiError) {
|
|
1649
|
-
(0, messages_1.printErrorWithHelp)(`Failed to resolve your creator account (status ${error.status}).`, ['Run "playdrop auth login" to refresh your session, then try again.'], { command: 'project create app' });
|
|
1650
|
-
process.exitCode = 1;
|
|
1651
|
-
return;
|
|
1652
|
-
}
|
|
1653
|
-
if (error instanceof TypeError) {
|
|
1654
|
-
(0, messages_1.printNetworkIssue)('Could not reach the Playdrop API to resolve your creator account.', 'project create app');
|
|
1655
|
-
process.exitCode = 1;
|
|
1656
|
-
return;
|
|
1657
|
-
}
|
|
1658
|
-
if (error instanceof Error && error.message === 'missing_creator_username') {
|
|
1659
|
-
(0, messages_1.printErrorWithHelp)('The API did not return a creator username.', ['Run "playdrop auth login" again, then retry.'], { command: 'project create app' });
|
|
1660
|
-
process.exitCode = 1;
|
|
1661
|
-
return;
|
|
1662
|
-
}
|
|
1663
|
-
throw error;
|
|
1664
|
-
}
|
|
1665
|
-
}
|
|
1666
|
-
if (!gameIdeaAppRef) {
|
|
1667
|
-
throw new Error('missing_game_idea_app_ref');
|
|
1668
|
-
}
|
|
1669
|
-
try {
|
|
1670
|
-
const response = await client.startGameIdea(gameIdeaRef, { app: gameIdeaAppRef });
|
|
1671
|
-
console.log(`Marked game idea ${response.gameIdea.slug} as started.`);
|
|
1672
|
-
}
|
|
1673
|
-
catch (error) {
|
|
1674
|
-
if (error instanceof http_1.CLIUnsupportedClientError) {
|
|
1675
|
-
process.exitCode = 1;
|
|
1676
|
-
return;
|
|
1677
|
-
}
|
|
1678
|
-
if (error instanceof types_1.UnsupportedClientError) {
|
|
1679
|
-
(0, http_1.handleUnsupportedError)(error, 'Mark game idea started');
|
|
1680
|
-
process.exitCode = 1;
|
|
1681
|
-
return;
|
|
1682
|
-
}
|
|
1683
|
-
if (error instanceof types_1.ApiError) {
|
|
1684
|
-
(0, messages_1.printErrorWithHelp)(`Failed to mark game idea ${gameIdeaRef} as started (status ${error.status}).`, ['Confirm the game idea id or slug, then retry with "playdrop creations ideas start <id-or-slug>".'], { command: 'project create app' });
|
|
1685
|
-
process.exitCode = 1;
|
|
1686
|
-
return;
|
|
1687
|
-
}
|
|
1688
|
-
if (error instanceof TypeError) {
|
|
1689
|
-
(0, messages_1.printNetworkIssue)('Could not reach the Playdrop API to mark the game idea started.', 'project create app');
|
|
1690
|
-
process.exitCode = 1;
|
|
1691
|
-
return;
|
|
1692
|
-
}
|
|
1693
|
-
throw error;
|
|
1694
|
-
}
|
|
1695
|
-
}
|
|
1696
1547
|
logNextSteps(name, {
|
|
1697
1548
|
hasCatalogue,
|
|
1698
1549
|
catalogueLabel,
|
|
@@ -5,16 +5,6 @@ type BrowseCreationsOptions = {
|
|
|
5
5
|
offset?: string | number;
|
|
6
6
|
json?: boolean;
|
|
7
7
|
};
|
|
8
|
-
type BrowseIdeasOptions = {
|
|
9
|
-
state?: string;
|
|
10
|
-
limit?: string | number;
|
|
11
|
-
offset?: string | number;
|
|
12
|
-
json?: boolean;
|
|
13
|
-
};
|
|
14
|
-
type IdeaMutationOptions = {
|
|
15
|
-
app?: string;
|
|
16
|
-
json?: boolean;
|
|
17
|
-
};
|
|
18
8
|
type AppUpdateOptions = {
|
|
19
9
|
creator?: string;
|
|
20
10
|
displayName?: string;
|
|
@@ -38,9 +28,6 @@ type MutationOptions = {
|
|
|
38
28
|
json?: boolean;
|
|
39
29
|
};
|
|
40
30
|
export declare function browseCreations(options?: BrowseCreationsOptions): Promise<void>;
|
|
41
|
-
export declare function browseCreationIdeas(options?: BrowseIdeasOptions): Promise<void>;
|
|
42
|
-
export declare function startCreationIdea(idOrSlug: string | undefined, options?: IdeaMutationOptions): Promise<void>;
|
|
43
|
-
export declare function shipCreationIdea(idOrSlug: string | undefined, options?: IdeaMutationOptions): Promise<void>;
|
|
44
31
|
export declare function updateCreationApp(nameArg: string | undefined, options?: AppUpdateOptions): Promise<void>;
|
|
45
32
|
export declare function deleteCreationApp(nameArg: string | undefined, options?: MutationOptions): Promise<void>;
|
|
46
33
|
export declare function setCurrentCreationAppVersion(nameArg: string | undefined, versionArg: string | undefined, options?: MutationOptions): Promise<void>;
|