@playdrop/playdrop-cli 0.10.21 → 0.11.4
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 +1 -1
- package/dist/appUrls.d.ts +3 -0
- package/dist/appUrls.js +12 -0
- package/dist/apps/launchCheck.d.ts +8 -1
- package/dist/apps/launchCheck.js +96 -10
- package/dist/apps/upload.js +5 -0
- package/dist/apps/validate.js +0 -1
- package/dist/captureRuntime.js +8 -1
- package/dist/catalogue.d.ts +3 -1
- package/dist/catalogue.js +12 -0
- package/dist/commands/captureRemote.d.ts +1 -0
- package/dist/commands/captureRemote.js +45 -1
- package/dist/commands/upload.js +346 -101
- package/dist/commands/worker.d.ts +12 -1
- package/dist/commands/worker.js +228 -26
- package/dist/index.js +10 -0
- package/node_modules/@playdrop/api-client/dist/client.d.ts +3 -1
- package/node_modules/@playdrop/api-client/dist/client.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/agent-tasks.d.ts +3 -1
- package/node_modules/@playdrop/api-client/dist/domains/agent-tasks.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/agent-tasks.js +23 -0
- package/node_modules/@playdrop/config/client-meta.json +1 -1
- package/node_modules/@playdrop/types/dist/api.d.ts +89 -1
- package/node_modules/@playdrop/types/dist/api.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/api.js +17 -1
- package/node_modules/@playdrop/types/dist/version.d.ts +22 -0
- package/node_modules/@playdrop/types/dist/version.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/version.js +108 -0
- package/package.json +1 -1
package/config/client-meta.json
CHANGED
package/dist/appUrls.d.ts
CHANGED
|
@@ -7,6 +7,9 @@ export type AppUrlInput = {
|
|
|
7
7
|
export declare function normalizePlaydropWebBase(webBase?: string | null): string;
|
|
8
8
|
export declare function getAppTypeSlug(type: AppType | string | null | undefined): string;
|
|
9
9
|
export declare function buildPlatformPlayUrl(webBase: string | null | undefined, input: AppUrlInput): string;
|
|
10
|
+
export declare function buildPlatformPrivateDraftPlayUrl(webBase: string | null | undefined, input: AppUrlInput & {
|
|
11
|
+
version: string;
|
|
12
|
+
}): string;
|
|
10
13
|
export declare function buildPlatformDevUrl(webBase: string | null | undefined, input: AppUrlInput & {
|
|
11
14
|
devAuth?: 'prompt' | 'anonymous' | 'viewer' | 'player';
|
|
12
15
|
player?: string | null;
|
package/dist/appUrls.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.normalizePlaydropWebBase = normalizePlaydropWebBase;
|
|
4
4
|
exports.getAppTypeSlug = getAppTypeSlug;
|
|
5
5
|
exports.buildPlatformPlayUrl = buildPlatformPlayUrl;
|
|
6
|
+
exports.buildPlatformPrivateDraftPlayUrl = buildPlatformPrivateDraftPlayUrl;
|
|
6
7
|
exports.buildPlatformDevUrl = buildPlatformDevUrl;
|
|
7
8
|
exports.buildUploadLaunchCheckUrl = buildUploadLaunchCheckUrl;
|
|
8
9
|
const DEFAULT_WEB_BASE = 'https://www.playdrop.ai';
|
|
@@ -33,6 +34,17 @@ function buildPlatformPlayUrl(webBase, input) {
|
|
|
33
34
|
const appName = encodeURIComponent(input.appName);
|
|
34
35
|
return `${base}/creators/${creator}/apps/${typeSlug}/${appName}/play`;
|
|
35
36
|
}
|
|
37
|
+
function buildPlatformPrivateDraftPlayUrl(webBase, input) {
|
|
38
|
+
const base = normalizePlaydropWebBase(webBase);
|
|
39
|
+
const creator = encodeURIComponent(input.creatorUsername);
|
|
40
|
+
const typeSlug = getAppTypeSlug(input.appType);
|
|
41
|
+
const appName = encodeURIComponent(input.appName);
|
|
42
|
+
const version = encodeURIComponent(input.version.trim());
|
|
43
|
+
if (!version) {
|
|
44
|
+
throw new Error('invalid_private_draft_play_version');
|
|
45
|
+
}
|
|
46
|
+
return `${base}/_auth/creators/${creator}/apps/${typeSlug}/${appName}/play?v=${version}`;
|
|
47
|
+
}
|
|
36
48
|
function buildPlatformDevUrl(webBase, input) {
|
|
37
49
|
const base = normalizePlaydropWebBase(webBase);
|
|
38
50
|
const creator = encodeURIComponent(input.creatorUsername);
|
|
@@ -8,7 +8,7 @@ export type HostedLaunchCheckResult = {
|
|
|
8
8
|
checkedAt: string;
|
|
9
9
|
artifactFingerprint: string | null;
|
|
10
10
|
};
|
|
11
|
-
export declare function formatHostedLaunchCheckFailure(taskName: string, result: HostedLaunchCheckResult, scope?: 'local' | 'staged'): string;
|
|
11
|
+
export declare function formatHostedLaunchCheckFailure(taskName: string, result: HostedLaunchCheckResult, scope?: 'local' | 'staged' | 'final'): string;
|
|
12
12
|
export declare function runLocalHostedLaunchCheck(input: {
|
|
13
13
|
client: ApiClient;
|
|
14
14
|
apiBase: string;
|
|
@@ -30,3 +30,10 @@ export declare function runUploadedHostedLaunchCheck(input: {
|
|
|
30
30
|
token?: string | null;
|
|
31
31
|
currentUser?: UserResponse | null;
|
|
32
32
|
}): Promise<HostedLaunchCheckResult>;
|
|
33
|
+
export declare function runPublishedHostedPlayCheck(input: {
|
|
34
|
+
targetUrl: string;
|
|
35
|
+
surfaceTargets?: unknown;
|
|
36
|
+
timeoutMs?: number;
|
|
37
|
+
token?: string | null;
|
|
38
|
+
currentUser?: UserResponse | null;
|
|
39
|
+
}): Promise<HostedLaunchCheckResult>;
|
package/dist/apps/launchCheck.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.formatHostedLaunchCheckFailure = formatHostedLaunchCheckFailure;
|
|
4
4
|
exports.runLocalHostedLaunchCheck = runLocalHostedLaunchCheck;
|
|
5
5
|
exports.runUploadedHostedLaunchCheck = runUploadedHostedLaunchCheck;
|
|
6
|
+
exports.runPublishedHostedPlayCheck = runPublishedHostedPlayCheck;
|
|
6
7
|
const appUrls_1 = require("../appUrls");
|
|
7
8
|
const captureRuntime_1 = require("../captureRuntime");
|
|
8
9
|
const devShared_1 = require("../commands/devShared");
|
|
@@ -13,13 +14,67 @@ const devRuntimeAssets_1 = require("../commands/devRuntimeAssets");
|
|
|
13
14
|
const registration_1 = require("./registration");
|
|
14
15
|
const DEFAULT_HOSTED_LAUNCH_TIMEOUT_MS = 15000;
|
|
15
16
|
const POST_READY_SETTLE_MS = 750;
|
|
16
|
-
const
|
|
17
|
+
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';
|
|
18
|
+
const LAUNCH_CHECK_SURFACE_ORDER = ['DESKTOP', 'MOBILE_LANDSCAPE', 'MOBILE_PORTRAIT'];
|
|
19
|
+
const LAUNCH_CHECK_SURFACE_CONTEXT_OPTIONS = {
|
|
20
|
+
DESKTOP: {
|
|
21
|
+
viewport: { width: 1280, height: 720 },
|
|
22
|
+
deviceScaleFactor: 1,
|
|
23
|
+
isMobile: false,
|
|
24
|
+
hasTouch: false,
|
|
25
|
+
},
|
|
26
|
+
MOBILE_LANDSCAPE: {
|
|
27
|
+
viewport: { width: 896, height: 414 },
|
|
28
|
+
deviceScaleFactor: 2,
|
|
29
|
+
isMobile: true,
|
|
30
|
+
hasTouch: true,
|
|
31
|
+
userAgent: MOBILE_USER_AGENT,
|
|
32
|
+
},
|
|
33
|
+
MOBILE_PORTRAIT: {
|
|
34
|
+
viewport: { width: 414, height: 896 },
|
|
35
|
+
deviceScaleFactor: 2,
|
|
36
|
+
isMobile: true,
|
|
37
|
+
hasTouch: true,
|
|
38
|
+
userAgent: MOBILE_USER_AGENT,
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
function normalizeLaunchCheckSurface(value) {
|
|
42
|
+
if (typeof value !== 'string') {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
const normalized = value.trim().toUpperCase();
|
|
46
|
+
return LAUNCH_CHECK_SURFACE_ORDER.includes(normalized)
|
|
47
|
+
? normalized
|
|
48
|
+
: null;
|
|
49
|
+
}
|
|
50
|
+
function normalizeLaunchCheckSurfaceTargets(value) {
|
|
51
|
+
if (!Array.isArray(value)) {
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
return Array.from(new Set(value.map(normalizeLaunchCheckSurface).filter((entry) => Boolean(entry))));
|
|
55
|
+
}
|
|
56
|
+
function resolveLaunchCheckSurface(surfaceTargets) {
|
|
57
|
+
const targets = normalizeLaunchCheckSurfaceTargets(surfaceTargets);
|
|
58
|
+
for (const surface of LAUNCH_CHECK_SURFACE_ORDER) {
|
|
59
|
+
if (targets.includes(surface)) {
|
|
60
|
+
return surface;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return 'DESKTOP';
|
|
64
|
+
}
|
|
65
|
+
function cloneLaunchCheckContextOptions(surface) {
|
|
66
|
+
const source = LAUNCH_CHECK_SURFACE_CONTEXT_OPTIONS[surface];
|
|
67
|
+
return {
|
|
68
|
+
...source,
|
|
69
|
+
viewport: source.viewport ? { ...source.viewport } : source.viewport,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
17
72
|
function resolvePostAuthHostedLaunchState(controllerMode) {
|
|
18
73
|
return controllerMode === 'REQUIRED' ? 'controller_required' : 'ready';
|
|
19
74
|
}
|
|
20
75
|
function resolveAnonymousHostedLaunchState(input) {
|
|
21
|
-
const surfaceTargets =
|
|
22
|
-
if (!surfaceTargets.includes(
|
|
76
|
+
const surfaceTargets = normalizeLaunchCheckSurfaceTargets(input.surfaceTargets);
|
|
77
|
+
if (!surfaceTargets.includes(input.captureSurface)) {
|
|
23
78
|
return 'surface_unsupported';
|
|
24
79
|
}
|
|
25
80
|
if (input.authMode === 'REQUIRED') {
|
|
@@ -64,7 +119,11 @@ function formatCaptureErrors(errors) {
|
|
|
64
119
|
return ` First error${normalized.length === 1 ? '' : 's'}: ${normalized.join(' | ')}`;
|
|
65
120
|
}
|
|
66
121
|
function formatHostedLaunchCheckFailure(taskName, result, scope = 'local') {
|
|
67
|
-
const scopeLabel = scope === '
|
|
122
|
+
const scopeLabel = scope === 'final'
|
|
123
|
+
? 'final owner play route'
|
|
124
|
+
: scope === 'staged'
|
|
125
|
+
? 'staged upload preview'
|
|
126
|
+
: 'local hosted preview';
|
|
68
127
|
const errorCode = result.errorCode?.trim() || 'startup_failure';
|
|
69
128
|
const message = normalizeLaunchCheckMessage(result.message);
|
|
70
129
|
return `hosted_launch_check_failed: ${taskName} failed the ${scopeLabel} launch-check (${errorCode}). ${message}`;
|
|
@@ -102,13 +161,10 @@ function buildRegistrationRequiredLaunchCheckFailure(taskName) {
|
|
|
102
161
|
return buildFailedLaunchCheckResult('app_registration_required_for_auth_validation', `Auth-required hosted app "${taskName}" must be registered on PlayDrop before viewer launch validation can run. Run "playdrop project create app ${taskName}" and try again.`, null);
|
|
103
162
|
}
|
|
104
163
|
function appendLaunchCheckParams(targetUrl, devAuth) {
|
|
105
|
-
|
|
164
|
+
return (0, devAuth_1.applyHostedDevAuthSelectionToUrl)(targetUrl, {
|
|
106
165
|
devAuth,
|
|
107
166
|
player: null,
|
|
108
167
|
});
|
|
109
|
-
const nextUrl = new URL(withAuth);
|
|
110
|
-
nextUrl.searchParams.set('launchCheck', '1');
|
|
111
|
-
return nextUrl.toString();
|
|
112
168
|
}
|
|
113
169
|
async function runHostedLaunchCheckWithCapture(options) {
|
|
114
170
|
const expectedHostedLaunchState = options.expectedHostedLaunchState ?? 'ready';
|
|
@@ -125,6 +181,7 @@ async function runHostedLaunchCheckWithCapture(options) {
|
|
|
125
181
|
token: options.token ?? null,
|
|
126
182
|
user: options.user ?? null,
|
|
127
183
|
savedSessionBootstrap: options.savedSessionBootstrap ?? false,
|
|
184
|
+
contextOptions: options.contextOptions,
|
|
128
185
|
});
|
|
129
186
|
if (result.errorCount > 0) {
|
|
130
187
|
return buildFailedLaunchCheckResult('startup_failure', `Hosted app emitted ${result.errorCount} console, page, or network error(s) during startup.${formatCaptureErrors(result.errors)}`, options.artifactFingerprint ?? null);
|
|
@@ -210,7 +267,12 @@ async function runLocalHostedLaunchCheck(input) {
|
|
|
210
267
|
? null
|
|
211
268
|
: input.devRouterPort;
|
|
212
269
|
const localAppMetadata = mountedRuntime.runtimeAssetManifest.response.localAppMetadata;
|
|
213
|
-
const
|
|
270
|
+
const captureSurface = resolveLaunchCheckSurface(localAppMetadata.surfaceTargets);
|
|
271
|
+
const contextOptions = cloneLaunchCheckContextOptions(captureSurface);
|
|
272
|
+
const anonymousExpectedState = resolveAnonymousHostedLaunchState({
|
|
273
|
+
...localAppMetadata,
|
|
274
|
+
captureSurface,
|
|
275
|
+
});
|
|
214
276
|
if (anonymousExpectedState === 'login_required') {
|
|
215
277
|
const registeredApp = await (0, registration_1.fetchRegisteredAppShell)(input.client, input.creatorUsername, input.task.name);
|
|
216
278
|
const canLaunchUnregisteredViewer = input.allowUnregisteredViewerLaunch === true
|
|
@@ -230,6 +292,7 @@ async function runLocalHostedLaunchCheck(input) {
|
|
|
230
292
|
}),
|
|
231
293
|
timeoutMs: input.timeoutMs,
|
|
232
294
|
expectedHostedLaunchState: anonymousExpectedState,
|
|
295
|
+
contextOptions,
|
|
233
296
|
});
|
|
234
297
|
if (anonymousGateResult.status !== 'PASSED') {
|
|
235
298
|
return anonymousGateResult;
|
|
@@ -248,6 +311,7 @@ async function runLocalHostedLaunchCheck(input) {
|
|
|
248
311
|
token: input.token ?? null,
|
|
249
312
|
user: input.currentUser ?? null,
|
|
250
313
|
savedSessionBootstrap: true,
|
|
314
|
+
contextOptions,
|
|
251
315
|
});
|
|
252
316
|
}
|
|
253
317
|
return await runHostedLaunchCheckWithCapture({
|
|
@@ -261,6 +325,7 @@ async function runLocalHostedLaunchCheck(input) {
|
|
|
261
325
|
}),
|
|
262
326
|
timeoutMs: input.timeoutMs,
|
|
263
327
|
expectedHostedLaunchState: anonymousExpectedState,
|
|
328
|
+
contextOptions,
|
|
264
329
|
});
|
|
265
330
|
}
|
|
266
331
|
finally {
|
|
@@ -271,7 +336,12 @@ async function runLocalHostedLaunchCheck(input) {
|
|
|
271
336
|
}
|
|
272
337
|
async function runUploadedHostedLaunchCheck(input) {
|
|
273
338
|
const preview = await input.client.fetchAppUploadLaunchCheckPreview(input.creatorUsername, input.task.name, input.sessionId);
|
|
274
|
-
const
|
|
339
|
+
const captureSurface = resolveLaunchCheckSurface(preview.localAppMetadata.surfaceTargets);
|
|
340
|
+
const contextOptions = cloneLaunchCheckContextOptions(captureSurface);
|
|
341
|
+
const anonymousExpectedState = resolveAnonymousHostedLaunchState({
|
|
342
|
+
...preview.localAppMetadata,
|
|
343
|
+
captureSurface,
|
|
344
|
+
});
|
|
275
345
|
let result;
|
|
276
346
|
if (anonymousExpectedState === 'login_required') {
|
|
277
347
|
if (!preview.app?.id) {
|
|
@@ -283,6 +353,7 @@ async function runUploadedHostedLaunchCheck(input) {
|
|
|
283
353
|
artifactFingerprint: preview.session.manifestHash,
|
|
284
354
|
timeoutMs: input.timeoutMs,
|
|
285
355
|
expectedHostedLaunchState: anonymousExpectedState,
|
|
356
|
+
contextOptions,
|
|
286
357
|
});
|
|
287
358
|
if (anonymousGateResult.status !== 'PASSED') {
|
|
288
359
|
result = anonymousGateResult;
|
|
@@ -296,6 +367,7 @@ async function runUploadedHostedLaunchCheck(input) {
|
|
|
296
367
|
token: input.token ?? null,
|
|
297
368
|
user: input.currentUser ?? null,
|
|
298
369
|
savedSessionBootstrap: true,
|
|
370
|
+
contextOptions,
|
|
299
371
|
});
|
|
300
372
|
}
|
|
301
373
|
}
|
|
@@ -306,6 +378,7 @@ async function runUploadedHostedLaunchCheck(input) {
|
|
|
306
378
|
artifactFingerprint: preview.session.manifestHash,
|
|
307
379
|
timeoutMs: input.timeoutMs,
|
|
308
380
|
expectedHostedLaunchState: anonymousExpectedState,
|
|
381
|
+
contextOptions,
|
|
309
382
|
});
|
|
310
383
|
}
|
|
311
384
|
const recorded = await input.client.recordAppUploadLaunchCheck(input.creatorUsername, input.task.name, input.sessionId, {
|
|
@@ -326,3 +399,16 @@ async function runUploadedHostedLaunchCheck(input) {
|
|
|
326
399
|
artifactFingerprint: recordedLaunchCheck.artifactFingerprint,
|
|
327
400
|
};
|
|
328
401
|
}
|
|
402
|
+
async function runPublishedHostedPlayCheck(input) {
|
|
403
|
+
const captureSurface = resolveLaunchCheckSurface(input.surfaceTargets);
|
|
404
|
+
return runHostedLaunchCheckWithCapture({
|
|
405
|
+
targetUrl: input.targetUrl,
|
|
406
|
+
artifactFingerprint: null,
|
|
407
|
+
timeoutMs: input.timeoutMs,
|
|
408
|
+
expectedHostedLaunchState: 'ready',
|
|
409
|
+
token: input.token ?? null,
|
|
410
|
+
user: input.currentUser ?? null,
|
|
411
|
+
savedSessionBootstrap: true,
|
|
412
|
+
contextOptions: cloneLaunchCheckContextOptions(captureSurface),
|
|
413
|
+
});
|
|
414
|
+
}
|
package/dist/apps/upload.js
CHANGED
|
@@ -253,6 +253,7 @@ async function uploadAppVersion(client, task, artifacts, options) {
|
|
|
253
253
|
})),
|
|
254
254
|
usesPacks: task.uses.packs,
|
|
255
255
|
tags: task.tags,
|
|
256
|
+
design: task.design,
|
|
256
257
|
clearTags: options?.clearTags,
|
|
257
258
|
surfaceTargets: task.surfaceTargets,
|
|
258
259
|
assetSpecSupport: (task.assetSpecSupport ?? []).map((row) => ({
|
|
@@ -409,6 +410,10 @@ async function uploadAppVersion(client, task, artifacts, options) {
|
|
|
409
410
|
+ `Delete one old version: playdrop creations apps versions delete ${task.name} <version>`);
|
|
410
411
|
}
|
|
411
412
|
if (unknownError.status === 409 && unknownError.code === 'version_exists') {
|
|
413
|
+
if (options?.agentTaskId !== undefined) {
|
|
414
|
+
throw new Error(`Version ${task.version} already exists for app "${task.name}".\n` +
|
|
415
|
+
'This task has a fixed outputVersion; do not bump catalogue.json. The required task version has already been consumed by an upload attempt, so fail the task with the operational reason.');
|
|
416
|
+
}
|
|
412
417
|
throw new Error(`Version ${task.version} already exists for app "${task.name}".\n` +
|
|
413
418
|
`Hint: Update "version" in catalogue.json to a new version (e.g., bump to the next patch).`);
|
|
414
419
|
}
|
package/dist/apps/validate.js
CHANGED
|
@@ -48,7 +48,6 @@ const SDK_REFERENCE_PATTERNS = [
|
|
|
48
48
|
const SDK_INIT_PATTERNS = [
|
|
49
49
|
/\bwindow\s*\.\s*playdrop\s*\.\s*init\s*\(/g,
|
|
50
50
|
/\bplaydrop\s*\.\s*init\s*\(/g,
|
|
51
|
-
/\bsdk\s*\.\s*initialize\s*\(/g,
|
|
52
51
|
];
|
|
53
52
|
const SDK_READY_PATTERNS = [
|
|
54
53
|
/\bsdk\s*\??\.\s*host\s*\??\.\s*ready\s*\(/g,
|
package/dist/captureRuntime.js
CHANGED
|
@@ -16,6 +16,7 @@ const FRAME_SELECTOR = 'iframe[title="Game"]';
|
|
|
16
16
|
exports.CAPTURE_LOG_LEVEL_VALUES = ['debug', 'info', 'warn', 'error'];
|
|
17
17
|
exports.MAX_CAPTURE_TIMEOUT_SECONDS = 600;
|
|
18
18
|
const GOOGLE_TELEMETRY_HOSTS = [
|
|
19
|
+
'analytics.google.com',
|
|
19
20
|
'googletagmanager.com',
|
|
20
21
|
'google-analytics.com',
|
|
21
22
|
'googleadservices.com',
|
|
@@ -97,7 +98,13 @@ function extractRefusedResourceUrls(text) {
|
|
|
97
98
|
}
|
|
98
99
|
function isKnownGoogleTelemetryConsoleIssue(text, locationUrl) {
|
|
99
100
|
if (/Content Security Policy/i.test(text)) {
|
|
100
|
-
|
|
101
|
+
const refusedUrls = extractRefusedResourceUrls(text);
|
|
102
|
+
if (refusedUrls.some(isKnownGoogleTelemetryUrl)) {
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
const messageUrls = extractHttpUrls(text);
|
|
106
|
+
return messageUrls.some(isKnownGoogleTelemetryUrl)
|
|
107
|
+
&& !messageUrls.some(isLoopbackOrLocalUrl);
|
|
101
108
|
}
|
|
102
109
|
if (!/ERR_BLOCKED_BY_CLIENT/i.test(text)) {
|
|
103
110
|
return false;
|
package/dist/catalogue.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AppSurface, type AppType, type AppHostingMode, type AppAuthMode, type AppControllerMode, type AppVersionVisibility, type AppAchievementCatalogueDefinition, type AppLeaderboardCatalogueDefinition, type PlayerMetaDefinitionStatus, type CatalogueTagGroupDefinition, type AppMetadataAssetSpecSupport, type AssetSpecContract, type AssetSpecStatus, type AssetSpecValidationKind, type ContentLicense } from '@playdrop/types';
|
|
1
|
+
import { type AppSurface, type AppType, type AppHostingMode, type AppAuthMode, type AppControllerMode, type AppVersionVisibility, type AppVersionDesign, type AppAchievementCatalogueDefinition, type AppLeaderboardCatalogueDefinition, type PlayerMetaDefinitionStatus, type CatalogueTagGroupDefinition, type AppMetadataAssetSpecSupport, type AssetSpecContract, type AssetSpecStatus, type AssetSpecValidationKind, type ContentLicense } from '@playdrop/types';
|
|
2
2
|
import { type AssetSpecSupportDeclaration } from './assetSpecs';
|
|
3
3
|
export type CatalogueJson = {
|
|
4
4
|
apps?: Array<Record<string, unknown>>;
|
|
@@ -41,6 +41,7 @@ export type AppCatalogueEntry = {
|
|
|
41
41
|
remixSource?: string | null;
|
|
42
42
|
remix?: string;
|
|
43
43
|
surfaceTargets?: Record<string, unknown> | AppSurface[] | null;
|
|
44
|
+
design?: unknown;
|
|
44
45
|
version?: string;
|
|
45
46
|
releaseNotes?: string;
|
|
46
47
|
visibility?: string;
|
|
@@ -177,6 +178,7 @@ export type AppTask = {
|
|
|
177
178
|
emoji?: string | null;
|
|
178
179
|
color?: string | null;
|
|
179
180
|
surfaceTargets: AppSurface[];
|
|
181
|
+
design?: AppVersionDesign;
|
|
180
182
|
missingMetadata: string[];
|
|
181
183
|
ecsPath?: string;
|
|
182
184
|
serverPath?: string;
|
package/dist/catalogue.js
CHANGED
|
@@ -1300,6 +1300,17 @@ function buildAppTasks(rootDir, catalogues, options) {
|
|
|
1300
1300
|
if (errors.length > errorCountBeforeDependencies) {
|
|
1301
1301
|
continue;
|
|
1302
1302
|
}
|
|
1303
|
+
let design;
|
|
1304
|
+
if (Object.prototype.hasOwnProperty.call(entry, 'design')) {
|
|
1305
|
+
const parsedDesign = (0, types_1.normalizeAppVersionDesign)(entry.design, {
|
|
1306
|
+
allowedPackRefs: usesPacks,
|
|
1307
|
+
});
|
|
1308
|
+
if (!parsedDesign.ok) {
|
|
1309
|
+
errors.push(`[${label}] App "${rawName}" ${parsedDesign.error}`);
|
|
1310
|
+
continue;
|
|
1311
|
+
}
|
|
1312
|
+
design = parsedDesign.value;
|
|
1313
|
+
}
|
|
1303
1314
|
const errorCountBeforeTagMetadata = errors.length;
|
|
1304
1315
|
const remix = normalizeCatalogueRemixRef(entry.remix, 'app', errors, `[${label}] App "${rawName}"`);
|
|
1305
1316
|
const tags = normalizeCatalogueTags(entry.tags, errors, `[${label}] App "${rawName}"`);
|
|
@@ -1500,6 +1511,7 @@ function buildAppTasks(rootDir, catalogues, options) {
|
|
|
1500
1511
|
emoji: metadata.emoji === undefined ? undefined : metadata.emoji,
|
|
1501
1512
|
color: metadata.color === undefined ? undefined : metadata.color,
|
|
1502
1513
|
surfaceTargets: metadata.surfaceTargets,
|
|
1514
|
+
design,
|
|
1503
1515
|
missingMetadata: metadata.missingFields,
|
|
1504
1516
|
ecsPath,
|
|
1505
1517
|
serverPath,
|
|
@@ -9,6 +9,7 @@ type CaptureRemoteOptions = {
|
|
|
9
9
|
loginUrl?: string;
|
|
10
10
|
actions?: string;
|
|
11
11
|
viewport?: string;
|
|
12
|
+
surface?: string;
|
|
12
13
|
fpsSampleMs?: string | number;
|
|
13
14
|
};
|
|
14
15
|
export declare function buildCaptureRemoteCommandArgs(url: string | undefined, options?: CaptureRemoteOptions): string[] | null;
|
|
@@ -10,6 +10,29 @@ const http_1 = require("../http");
|
|
|
10
10
|
const messages_1 = require("../messages");
|
|
11
11
|
const devShared_1 = require("./devShared");
|
|
12
12
|
const captureRuntime_1 = require("../captureRuntime");
|
|
13
|
+
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';
|
|
14
|
+
const SURFACE_CONTEXT_OPTIONS = {
|
|
15
|
+
desktop: {
|
|
16
|
+
viewport: { width: 1280, height: 720 },
|
|
17
|
+
deviceScaleFactor: 1,
|
|
18
|
+
isMobile: false,
|
|
19
|
+
hasTouch: false,
|
|
20
|
+
},
|
|
21
|
+
'mobile-landscape': {
|
|
22
|
+
viewport: { width: 896, height: 414 },
|
|
23
|
+
deviceScaleFactor: 2,
|
|
24
|
+
isMobile: true,
|
|
25
|
+
hasTouch: true,
|
|
26
|
+
userAgent: MOBILE_USER_AGENT,
|
|
27
|
+
},
|
|
28
|
+
'mobile-portrait': {
|
|
29
|
+
viewport: { width: 414, height: 896 },
|
|
30
|
+
deviceScaleFactor: 2,
|
|
31
|
+
isMobile: true,
|
|
32
|
+
hasTouch: true,
|
|
33
|
+
userAgent: MOBILE_USER_AGENT,
|
|
34
|
+
},
|
|
35
|
+
};
|
|
13
36
|
function readUnsupportedPlaydropCaptureMessage(targetUrl) {
|
|
14
37
|
let parsed;
|
|
15
38
|
try {
|
|
@@ -69,6 +92,16 @@ function parseViewport(raw) {
|
|
|
69
92
|
}
|
|
70
93
|
return { width, height };
|
|
71
94
|
}
|
|
95
|
+
function parseSurface(raw) {
|
|
96
|
+
const normalized = raw?.trim().toLowerCase();
|
|
97
|
+
if (!normalized) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
if (normalized === 'desktop' || normalized === 'mobile-landscape' || normalized === 'mobile-portrait') {
|
|
101
|
+
return normalized;
|
|
102
|
+
}
|
|
103
|
+
throw new Error('invalid_surface');
|
|
104
|
+
}
|
|
72
105
|
function parseFpsSampleMs(raw) {
|
|
73
106
|
if (raw === undefined) {
|
|
74
107
|
return null;
|
|
@@ -172,6 +205,7 @@ function buildCaptureRemoteCommandArgs(url, options = {}) {
|
|
|
172
205
|
pushOptionalArg(args, '--expected-url', options.expectedUrl);
|
|
173
206
|
pushOptionalArg(args, '--actions', options.actions);
|
|
174
207
|
pushOptionalArg(args, '--viewport', options.viewport);
|
|
208
|
+
pushOptionalArg(args, '--surface', options.surface);
|
|
175
209
|
if (options.fpsSampleMs !== undefined) {
|
|
176
210
|
args.push('--fps-sample-ms', String(parseFpsSampleMs(options.fpsSampleMs)));
|
|
177
211
|
}
|
|
@@ -205,6 +239,7 @@ function parseOptions(url, options = {}) {
|
|
|
205
239
|
logPath: options.log?.trim() ? (0, node_path_1.resolve)(process.cwd(), options.log.trim()) : null,
|
|
206
240
|
actionsPath: options.actions?.trim() ? (0, node_path_1.resolve)(process.cwd(), options.actions.trim()) : null,
|
|
207
241
|
viewport: parseViewport(options.viewport),
|
|
242
|
+
surface: parseSurface(options.surface),
|
|
208
243
|
fpsSampleMs: parseFpsSampleMs(options.fpsSampleMs),
|
|
209
244
|
login: username
|
|
210
245
|
? {
|
|
@@ -247,6 +282,11 @@ async function captureRemote(url, options = {}) {
|
|
|
247
282
|
process.exitCode = 1;
|
|
248
283
|
return;
|
|
249
284
|
}
|
|
285
|
+
if (error instanceof Error && error.message === 'invalid_surface') {
|
|
286
|
+
(0, messages_1.printErrorWithHelp)('The --surface value must be desktop, mobile-landscape, or mobile-portrait.', [], { command: 'project capture remote' });
|
|
287
|
+
process.exitCode = 1;
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
250
290
|
if (error instanceof Error && error.message === 'invalid_fps_sample_ms') {
|
|
251
291
|
(0, messages_1.printErrorWithHelp)('The --fps-sample-ms value must be an integer between 100 and 60000 milliseconds.', [], { command: 'project capture remote' });
|
|
252
292
|
process.exitCode = 1;
|
|
@@ -318,7 +358,11 @@ async function captureRemote(url, options = {}) {
|
|
|
318
358
|
user: parsed.login ? undefined : currentUser,
|
|
319
359
|
login: parsed.login,
|
|
320
360
|
actions: actions ?? undefined,
|
|
321
|
-
contextOptions: parsed.
|
|
361
|
+
contextOptions: parsed.surface
|
|
362
|
+
? { ...SURFACE_CONTEXT_OPTIONS[parsed.surface], ...(parsed.viewport ? { viewport: parsed.viewport } : {}) }
|
|
363
|
+
: parsed.viewport
|
|
364
|
+
? { viewport: parsed.viewport }
|
|
365
|
+
: undefined,
|
|
322
366
|
frameRateSampleMs: parsed.fpsSampleMs ?? undefined,
|
|
323
367
|
});
|
|
324
368
|
if (result.errorCount > 0) {
|