@playdrop/playdrop-cli 0.7.3 → 0.7.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/README.md +6 -4
- package/config/client-meta.json +5 -5
- package/dist/apps/launchCheck.js +11 -0
- package/dist/apps/upload.js +6 -0
- package/dist/captureRuntime.js +8 -1
- package/dist/catalogue.d.ts +9 -0
- package/dist/catalogue.js +14 -0
- package/dist/commandContext.d.ts +1 -0
- package/dist/commandContext.js +54 -17
- package/dist/commands/capture.js +1 -1
- package/dist/commands/devBrowser.js +2 -0
- package/dist/commands/devServer.d.ts +1 -0
- package/dist/commands/devServer.js +57 -3
- package/dist/commands/upload-content.js +5 -2
- package/dist/commands/upload.d.ts +1 -0
- package/dist/commands/upload.js +613 -33
- package/dist/commands/validate.d.ts +3 -1
- package/dist/commands/validate.js +28 -9
- package/dist/commands/whoami.d.ts +3 -1
- package/dist/commands/whoami.js +13 -3
- package/dist/index.js +13 -5
- package/dist/playwright.d.ts +5 -2
- package/dist/playwright.js +24 -3
- package/dist/taskSelection.js +2 -3
- package/dist/taskUtils.js +4 -4
- package/dist/uploadLog.d.ts +1 -1
- package/dist/uploadLog.js +12 -3
- package/node_modules/@playdrop/config/client-meta.json +5 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,11 +16,11 @@ npm install -g @playdrop/playdrop-cli
|
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
18
|
playdrop auth login
|
|
19
|
-
playdrop auth whoami
|
|
19
|
+
playdrop auth whoami --env dev
|
|
20
20
|
playdrop project init .
|
|
21
21
|
playdrop project create app my-first-game --template playdrop/template/typescript_template
|
|
22
22
|
playdrop project dev my-first-game
|
|
23
|
-
playdrop project publish .
|
|
23
|
+
playdrop project publish --env dev .
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
## What You Can Do
|
|
@@ -52,6 +52,7 @@ playdrop project publish .
|
|
|
52
52
|
|
|
53
53
|
```bash
|
|
54
54
|
playdrop auth login
|
|
55
|
+
playdrop auth whoami --env dev
|
|
55
56
|
playdrop browse
|
|
56
57
|
playdrop search "city builder"
|
|
57
58
|
playdrop detail playdrop/app/hangingout
|
|
@@ -65,7 +66,7 @@ playdrop ai create image "Wide fantasy vista" --ratio 16:9 --size 4K
|
|
|
65
66
|
playdrop project init .
|
|
66
67
|
playdrop project create app my-app --template playdrop/template/html_template
|
|
67
68
|
playdrop project dev my-app
|
|
68
|
-
playdrop project publish .
|
|
69
|
+
playdrop project publish --env dev .
|
|
69
70
|
playdrop documentation browse
|
|
70
71
|
playdrop feedback send --title "Bug report" --comment "Details here."
|
|
71
72
|
playdrop getting-started
|
|
@@ -95,10 +96,11 @@ Examples:
|
|
|
95
96
|
|
|
96
97
|
```bash
|
|
97
98
|
playdrop auth login
|
|
99
|
+
playdrop auth whoami --env dev
|
|
98
100
|
playdrop project init .
|
|
99
101
|
playdrop project create app my-app --template playdrop/template/html_template
|
|
100
102
|
playdrop project dev my-app
|
|
101
|
-
playdrop project publish .
|
|
103
|
+
playdrop project publish --env dev .
|
|
102
104
|
```
|
|
103
105
|
|
|
104
106
|
## Documentation
|
package/config/client-meta.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.7.
|
|
3
|
-
"build":
|
|
2
|
+
"version": "0.7.4",
|
|
3
|
+
"build": 3,
|
|
4
4
|
"platforms": {
|
|
5
5
|
"ios": {
|
|
6
6
|
"minimumVersion": "16.0"
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
"clients": {
|
|
28
28
|
"web": {
|
|
29
29
|
"minimumVersion": "0.7.3",
|
|
30
|
-
"minimumBuild":
|
|
30
|
+
"minimumBuild": 2
|
|
31
31
|
},
|
|
32
32
|
"admin": {
|
|
33
33
|
"minimumVersion": "0.7.3",
|
|
34
|
-
"minimumBuild":
|
|
34
|
+
"minimumBuild": 2
|
|
35
35
|
},
|
|
36
36
|
"apple": {
|
|
37
37
|
"minimumVersion": "0.3.10",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
},
|
|
48
48
|
"android-games": {
|
|
49
49
|
"minimumVersion": "0.7.3",
|
|
50
|
-
"minimumBuild":
|
|
50
|
+
"minimumBuild": 2
|
|
51
51
|
},
|
|
52
52
|
"cli": {
|
|
53
53
|
"minimumVersion": "0.7.3"
|
package/dist/apps/launchCheck.js
CHANGED
|
@@ -58,6 +58,17 @@ function formatHostedLaunchCheckFailure(taskName, result, scope = 'local') {
|
|
|
58
58
|
function normalizeLaunchCheckFailure(error, artifactFingerprint) {
|
|
59
59
|
const rawMessage = error instanceof Error ? error.message : String(error);
|
|
60
60
|
const message = normalizeLaunchCheckMessage(rawMessage);
|
|
61
|
+
const errorCodeMatch = message.match(/\berrorCode=([a-z0-9_]+)\b/i);
|
|
62
|
+
if (errorCodeMatch?.[1]) {
|
|
63
|
+
return buildFailedLaunchCheckResult(errorCodeMatch[1], message, artifactFingerprint);
|
|
64
|
+
}
|
|
65
|
+
const prefixedCodeMatch = message.match(/^([a-z0-9_]+):/i);
|
|
66
|
+
if (prefixedCodeMatch?.[1]
|
|
67
|
+
&& (prefixedCodeMatch[1].startsWith('hosted_app_')
|
|
68
|
+
|| prefixedCodeMatch[1].startsWith('local_dev_')
|
|
69
|
+
|| prefixedCodeMatch[1].startsWith('dev_auth_'))) {
|
|
70
|
+
return buildFailedLaunchCheckResult(prefixedCodeMatch[1], message, artifactFingerprint);
|
|
71
|
+
}
|
|
61
72
|
if (/errorCode=missing_init\b/i.test(message) || /hosted_app_missing_client_init:/i.test(message)) {
|
|
62
73
|
return buildFailedLaunchCheckResult('missing_init', message, artifactFingerprint);
|
|
63
74
|
}
|
package/dist/apps/upload.js
CHANGED
|
@@ -111,12 +111,15 @@ async function prepareOwnedAssetUpload(task) {
|
|
|
111
111
|
uploadKey: task.name,
|
|
112
112
|
runtimeKey: task.runtimeKey,
|
|
113
113
|
name: task.name,
|
|
114
|
+
displayName: task.displayName,
|
|
115
|
+
description: task.description,
|
|
114
116
|
category: task.category,
|
|
115
117
|
subcategory: task.subcategory,
|
|
116
118
|
format: task.format || (0, node_path_1.extname)(files[0]?.filename || '').replace(/^\./, '').toUpperCase() || 'GLB',
|
|
117
119
|
visibility: task.visibility,
|
|
118
120
|
license: task.license,
|
|
119
121
|
assetSpec: task.assetSpec,
|
|
122
|
+
tags: task.tags,
|
|
120
123
|
shopListed: task.shopListed,
|
|
121
124
|
shopPriceCredits: task.shopPriceCredits,
|
|
122
125
|
files,
|
|
@@ -311,12 +314,15 @@ async function uploadAppVersion(client, task, artifacts, options) {
|
|
|
311
314
|
uploadKey: ownedAsset.uploadKey,
|
|
312
315
|
runtimeKey: ownedAsset.runtimeKey,
|
|
313
316
|
name: ownedAsset.name,
|
|
317
|
+
displayName: ownedAsset.displayName,
|
|
318
|
+
description: ownedAsset.description,
|
|
314
319
|
category: ownedAsset.category,
|
|
315
320
|
subcategory: ownedAsset.subcategory,
|
|
316
321
|
format: ownedAsset.format,
|
|
317
322
|
assetSpec: ownedAsset.assetSpec,
|
|
318
323
|
visibility: ownedAsset.visibility,
|
|
319
324
|
license: ownedAsset.license,
|
|
325
|
+
tags: ownedAsset.tags,
|
|
320
326
|
shopListed: ownedAsset.shopListed,
|
|
321
327
|
shopPriceCredits: ownedAsset.shopPriceCredits,
|
|
322
328
|
files: ownedAsset.files.map((file) => ({
|
package/dist/captureRuntime.js
CHANGED
|
@@ -79,6 +79,10 @@ function normalizeComparableUrl(rawUrl) {
|
|
|
79
79
|
const pathname = parsed.pathname.replace(/\/+$/, '') || '/';
|
|
80
80
|
return `${parsed.origin}${pathname}`;
|
|
81
81
|
}
|
|
82
|
+
function resolveAutomationOrigin(targetUrl) {
|
|
83
|
+
const parsed = new URL(targetUrl);
|
|
84
|
+
return parsed.searchParams.get('launchCheck') === '1' ? parsed.origin : null;
|
|
85
|
+
}
|
|
82
86
|
function normalizeHostedLaunchStatePayload(payload) {
|
|
83
87
|
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
|
|
84
88
|
return null;
|
|
@@ -511,7 +515,10 @@ async function runCapture(options) {
|
|
|
511
515
|
await page.screenshot({ path: options.screenshotPath, fullPage: true });
|
|
512
516
|
console.log(`[capture] Saved screenshot to ${(0, node_path_1.relative)(process.cwd(), options.screenshotPath) || options.screenshotPath}`);
|
|
513
517
|
}
|
|
514
|
-
},
|
|
518
|
+
}, {
|
|
519
|
+
...(options.contextOptions ?? {}),
|
|
520
|
+
automationOrigin: resolveAutomationOrigin(options.targetUrl),
|
|
521
|
+
});
|
|
515
522
|
}
|
|
516
523
|
finally {
|
|
517
524
|
await writeLogFile(options.logPath, outputLines);
|
package/dist/catalogue.d.ts
CHANGED
|
@@ -104,12 +104,15 @@ export type AssetSpecCatalogueEntry = {
|
|
|
104
104
|
export type OwnedAssetCatalogueEntry = {
|
|
105
105
|
name: string;
|
|
106
106
|
runtimeKey?: string;
|
|
107
|
+
displayName?: string;
|
|
108
|
+
description?: string;
|
|
107
109
|
category?: string;
|
|
108
110
|
subcategory?: string;
|
|
109
111
|
format?: string;
|
|
110
112
|
files?: Record<string, string>;
|
|
111
113
|
visibility?: string;
|
|
112
114
|
license?: string;
|
|
115
|
+
tags?: string[];
|
|
113
116
|
shopListed?: boolean;
|
|
114
117
|
shopPriceCredits?: number;
|
|
115
118
|
};
|
|
@@ -254,6 +257,8 @@ export type OwnedAssetTask = {
|
|
|
254
257
|
appName: string;
|
|
255
258
|
name: string;
|
|
256
259
|
runtimeKey?: string;
|
|
260
|
+
displayName?: string;
|
|
261
|
+
description?: string;
|
|
257
262
|
cataloguePath: string;
|
|
258
263
|
category: string;
|
|
259
264
|
subcategory: string | null;
|
|
@@ -262,6 +267,7 @@ export type OwnedAssetTask = {
|
|
|
262
267
|
format?: string;
|
|
263
268
|
visibility?: string;
|
|
264
269
|
license: ContentLicense;
|
|
270
|
+
tags: string[];
|
|
265
271
|
shopListed?: boolean;
|
|
266
272
|
shopPriceCredits?: number;
|
|
267
273
|
files: Record<string, string>;
|
|
@@ -270,6 +276,8 @@ export type OwnedAssetTask = {
|
|
|
270
276
|
export type PackOwnedAssetTask = {
|
|
271
277
|
name: string;
|
|
272
278
|
cataloguePath: string;
|
|
279
|
+
displayName?: string;
|
|
280
|
+
description?: string;
|
|
273
281
|
category: string;
|
|
274
282
|
subcategory: string | null;
|
|
275
283
|
assetSpec?: string;
|
|
@@ -277,6 +285,7 @@ export type PackOwnedAssetTask = {
|
|
|
277
285
|
format?: string;
|
|
278
286
|
visibility?: string;
|
|
279
287
|
license: ContentLicense;
|
|
288
|
+
tags: string[];
|
|
280
289
|
shopListed?: boolean;
|
|
281
290
|
shopPriceCredits?: number;
|
|
282
291
|
files: Record<string, string>;
|
package/dist/catalogue.js
CHANGED
|
@@ -1382,11 +1382,17 @@ function buildAppTasks(rootDir, catalogues, options) {
|
|
|
1382
1382
|
if (!ownedLicense) {
|
|
1383
1383
|
continue;
|
|
1384
1384
|
}
|
|
1385
|
+
const ownedTags = normalizeCatalogueTags(owned.tags, errors, `[${label}] Owned asset "${ownedName}"`);
|
|
1386
|
+
if (ownedTags === null) {
|
|
1387
|
+
continue;
|
|
1388
|
+
}
|
|
1385
1389
|
ownedAssets.push({
|
|
1386
1390
|
kind: 'owned-asset',
|
|
1387
1391
|
appName: rawName,
|
|
1388
1392
|
name: ownedName,
|
|
1389
1393
|
runtimeKey,
|
|
1394
|
+
displayName: typeof owned?.displayName === 'string' && owned.displayName.trim().length > 0 ? owned.displayName.trim() : undefined,
|
|
1395
|
+
description: typeof owned?.description === 'string' ? owned.description : undefined,
|
|
1390
1396
|
cataloguePath: label,
|
|
1391
1397
|
category,
|
|
1392
1398
|
subcategory,
|
|
@@ -1394,6 +1400,7 @@ function buildAppTasks(rootDir, catalogues, options) {
|
|
|
1394
1400
|
format: ownedFormat,
|
|
1395
1401
|
visibility: normalizeAssetVisibilityValue(owned?.visibility, errors, `${label} owned asset "${ownedName}"`),
|
|
1396
1402
|
license: ownedLicense,
|
|
1403
|
+
tags: ownedTags,
|
|
1397
1404
|
shopListed: typeof owned?.shopListed === 'boolean' ? owned.shopListed : undefined,
|
|
1398
1405
|
shopPriceCredits: Number.isInteger(owned?.shopPriceCredits) ? Number(owned.shopPriceCredits) : undefined,
|
|
1399
1406
|
files,
|
|
@@ -1922,15 +1929,22 @@ function buildAssetPackTasks(catalogues) {
|
|
|
1922
1929
|
if (!ownedLicense) {
|
|
1923
1930
|
continue;
|
|
1924
1931
|
}
|
|
1932
|
+
const ownedTags = normalizeCatalogueTags(owned.tags, errors, `[${label}] Asset pack "${name}" owned asset "${ownedName}"`);
|
|
1933
|
+
if (ownedTags === null) {
|
|
1934
|
+
continue;
|
|
1935
|
+
}
|
|
1925
1936
|
ownedAssets.push({
|
|
1926
1937
|
name: ownedName,
|
|
1927
1938
|
cataloguePath: label,
|
|
1939
|
+
displayName: typeof owned?.displayName === 'string' && owned.displayName.trim().length > 0 ? owned.displayName.trim() : undefined,
|
|
1940
|
+
description: typeof owned?.description === 'string' ? owned.description : undefined,
|
|
1928
1941
|
category,
|
|
1929
1942
|
subcategory,
|
|
1930
1943
|
assetSpec,
|
|
1931
1944
|
format: ownedFormat,
|
|
1932
1945
|
visibility: normalizeAssetVisibilityValue(owned?.visibility, errors, `${label} asset pack "${name}" owned asset "${ownedName}"`),
|
|
1933
1946
|
license: ownedLicense,
|
|
1947
|
+
tags: ownedTags,
|
|
1934
1948
|
shopListed: typeof owned?.shopListed === 'boolean' ? owned.shopListed : undefined,
|
|
1935
1949
|
shopPriceCredits: Number.isInteger(owned?.shopPriceCredits) ? Number(owned.shopPriceCredits) : undefined,
|
|
1936
1950
|
files,
|
package/dist/commandContext.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export type EnvironmentContext = {
|
|
|
15
15
|
};
|
|
16
16
|
type EnvironmentCallback = (ctx: EnvironmentContext) => Promise<void> | void;
|
|
17
17
|
export type ResolveAuthenticatedEnvironmentOptions = {
|
|
18
|
+
env?: string;
|
|
18
19
|
workspacePath?: string;
|
|
19
20
|
};
|
|
20
21
|
export declare function resolveAuthenticatedEnvironmentContext(command: string, actionLabel: string, options?: ResolveAuthenticatedEnvironmentOptions): Promise<EnvironmentContext | null>;
|
package/dist/commandContext.js
CHANGED
|
@@ -10,6 +10,13 @@ const environment_1 = require("./environment");
|
|
|
10
10
|
const messages_1 = require("./messages");
|
|
11
11
|
const workspaceAuth_1 = require("./workspaceAuth");
|
|
12
12
|
const DEFAULT_PUBLIC_ENV = 'prod';
|
|
13
|
+
function normalizeRequestedEnv(value) {
|
|
14
|
+
if (typeof value !== 'string') {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
const normalized = value.trim();
|
|
18
|
+
return normalized.length > 0 ? normalized : undefined;
|
|
19
|
+
}
|
|
13
20
|
function resolveConfiguredEnvironment(envName, command, options) {
|
|
14
21
|
if (!envName && options.requireAuth) {
|
|
15
22
|
(0, messages_1.printConfigEnvironmentMissing)(command);
|
|
@@ -113,11 +120,12 @@ async function loadWorkspaceAwareConfig(command, options) {
|
|
|
113
120
|
}
|
|
114
121
|
return { cfg, workspaceAuth };
|
|
115
122
|
}
|
|
116
|
-
function resolveWorkspaceSelectedAccount(cfg, currentAccount, workspaceAuth) {
|
|
123
|
+
function resolveWorkspaceSelectedAccount(cfg, currentAccount, workspaceAuth, requestedEnv) {
|
|
117
124
|
const matchingSessions = (0, config_1.listAccountSessionsForUsername)(workspaceAuth.config.ownerUsername, cfg);
|
|
118
|
-
|
|
125
|
+
const preferredEnv = normalizeRequestedEnv(requestedEnv) ?? workspaceAuth.config.env;
|
|
126
|
+
if (preferredEnv) {
|
|
119
127
|
return {
|
|
120
|
-
account: (0, config_1.findAccountSession)(workspaceAuth.config.ownerUsername,
|
|
128
|
+
account: (0, config_1.findAccountSession)(workspaceAuth.config.ownerUsername, preferredEnv, cfg),
|
|
121
129
|
matchingSessions,
|
|
122
130
|
};
|
|
123
131
|
}
|
|
@@ -138,6 +146,16 @@ function resolveWorkspaceSelectedAccount(cfg, currentAccount, workspaceAuth) {
|
|
|
138
146
|
matchingSessions,
|
|
139
147
|
};
|
|
140
148
|
}
|
|
149
|
+
function resolveRequestedCurrentAccount(cfg, currentAccount, requestedEnv) {
|
|
150
|
+
const preferredEnv = normalizeRequestedEnv(requestedEnv);
|
|
151
|
+
if (!currentAccount) {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
if (!preferredEnv || currentAccount.env === preferredEnv) {
|
|
155
|
+
return currentAccount;
|
|
156
|
+
}
|
|
157
|
+
return (0, config_1.findAccountSession)(currentAccount.username, preferredEnv, cfg);
|
|
158
|
+
}
|
|
141
159
|
async function resolveAuthenticatedEnvironment(command, actionLabel, options = {}) {
|
|
142
160
|
const loaded = await loadWorkspaceAwareConfig(command, options);
|
|
143
161
|
if (!loaded) {
|
|
@@ -146,27 +164,37 @@ async function resolveAuthenticatedEnvironment(command, actionLabel, options = {
|
|
|
146
164
|
const { cfg, workspaceAuth } = loaded;
|
|
147
165
|
const currentAccount = (0, config_1.getCurrentAccountSession)(cfg) ?? buildLegacyAccountSession(cfg);
|
|
148
166
|
const selectedAccount = workspaceAuth
|
|
149
|
-
? resolveWorkspaceSelectedAccount(cfg, currentAccount, workspaceAuth).account
|
|
150
|
-
: currentAccount;
|
|
167
|
+
? resolveWorkspaceSelectedAccount(cfg, currentAccount, workspaceAuth, options.env).account
|
|
168
|
+
: resolveRequestedCurrentAccount(cfg, currentAccount, options.env);
|
|
151
169
|
if (!selectedAccount) {
|
|
152
170
|
if (workspaceAuth) {
|
|
153
171
|
const matchingSessions = (0, config_1.listAccountSessionsForUsername)(workspaceAuth.config.ownerUsername, cfg);
|
|
154
|
-
|
|
172
|
+
const preferredEnv = normalizeRequestedEnv(options.env) ?? workspaceAuth.config.env;
|
|
173
|
+
if (!preferredEnv && matchingSessions.length > 1) {
|
|
155
174
|
(0, messages_1.printErrorWithHelp)(`This workspace is pinned to ${workspaceAuth.config.ownerUsername}, but that account is logged in on multiple environments.`, [
|
|
156
|
-
`Run "playdrop
|
|
157
|
-
|
|
175
|
+
`Run "playdrop ${command} --env <env>" to target the matching workspace environment.`,
|
|
176
|
+
`Or run "playdrop auth use ${workspaceAuth.config.ownerUsername} --env <env>" to change your global default account.`,
|
|
158
177
|
], { command });
|
|
159
178
|
process.exitCode = 1;
|
|
160
179
|
return null;
|
|
161
180
|
}
|
|
162
|
-
const envSuffix =
|
|
181
|
+
const envSuffix = preferredEnv ? ` on ${preferredEnv}` : '';
|
|
163
182
|
(0, messages_1.printErrorWithHelp)(`This workspace is pinned to ${workspaceAuth.config.ownerUsername}${envSuffix}, but that account is not logged in.`, [
|
|
164
|
-
`Run "playdrop auth login${
|
|
183
|
+
`Run "playdrop auth login${preferredEnv ? ` --env ${preferredEnv}` : ''}" while authenticated as ${workspaceAuth.config.ownerUsername}.`,
|
|
165
184
|
'Or remove .playdrop.json if this workspace should use your current default account.',
|
|
166
185
|
], { command });
|
|
167
186
|
process.exitCode = 1;
|
|
168
187
|
return null;
|
|
169
188
|
}
|
|
189
|
+
const preferredEnv = normalizeRequestedEnv(options.env);
|
|
190
|
+
if (currentAccount && preferredEnv) {
|
|
191
|
+
(0, messages_1.printErrorWithHelp)(`${currentAccount.username} is not logged in on ${preferredEnv}.`, [
|
|
192
|
+
`Run "playdrop auth login --env ${preferredEnv}" while authenticated as ${currentAccount.username}.`,
|
|
193
|
+
`Or run "playdrop auth use <username> --env ${preferredEnv}" to switch accounts.`,
|
|
194
|
+
], { command });
|
|
195
|
+
process.exitCode = 1;
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
170
198
|
(0, messages_1.printLoginRequired)(actionLabel, command);
|
|
171
199
|
process.exitCode = 1;
|
|
172
200
|
return null;
|
|
@@ -203,26 +231,35 @@ async function resolveOptionalEnvironmentContext(command, options = {}) {
|
|
|
203
231
|
return null;
|
|
204
232
|
}
|
|
205
233
|
const selectedAccount = workspaceAuth
|
|
206
|
-
? resolveWorkspaceSelectedAccount(cfg, currentAccount, workspaceAuth).account
|
|
207
|
-
: currentAccount;
|
|
234
|
+
? resolveWorkspaceSelectedAccount(cfg, currentAccount, workspaceAuth, options.env).account
|
|
235
|
+
: resolveRequestedCurrentAccount(cfg, currentAccount, options.env);
|
|
208
236
|
if (!selectedAccount) {
|
|
209
237
|
if (workspaceAuth) {
|
|
210
238
|
const matchingSessions = (0, config_1.listAccountSessionsForUsername)(workspaceAuth.config.ownerUsername, cfg);
|
|
211
|
-
|
|
239
|
+
const preferredEnv = normalizeRequestedEnv(options.env) ?? workspaceAuth.config.env;
|
|
240
|
+
if (!preferredEnv && matchingSessions.length > 1) {
|
|
212
241
|
(0, messages_1.printErrorWithHelp)(`This workspace is pinned to ${workspaceAuth.config.ownerUsername}, but that account is logged in on multiple environments.`, [
|
|
213
|
-
`Run "playdrop
|
|
214
|
-
|
|
242
|
+
`Run "playdrop ${command} --env <env>" to target the matching workspace environment.`,
|
|
243
|
+
`Or run "playdrop auth use ${workspaceAuth.config.ownerUsername} --env <env>" to change your global default account.`,
|
|
215
244
|
], { command });
|
|
216
245
|
}
|
|
217
246
|
else {
|
|
218
|
-
const envSuffix =
|
|
247
|
+
const envSuffix = preferredEnv ? ` on ${preferredEnv}` : '';
|
|
219
248
|
(0, messages_1.printErrorWithHelp)(`This workspace is pinned to ${workspaceAuth.config.ownerUsername}${envSuffix}, but that account is not logged in.`, [
|
|
220
|
-
`Run "playdrop auth login${
|
|
249
|
+
`Run "playdrop auth login${preferredEnv ? ` --env ${preferredEnv}` : ''}" while authenticated as ${workspaceAuth.config.ownerUsername}.`,
|
|
221
250
|
'Or remove .playdrop.json if this workspace should use your current default account.',
|
|
222
251
|
], { command });
|
|
223
252
|
}
|
|
224
253
|
process.exitCode = 1;
|
|
225
254
|
}
|
|
255
|
+
else if (currentAccount && normalizeRequestedEnv(options.env)) {
|
|
256
|
+
const preferredEnv = normalizeRequestedEnv(options.env);
|
|
257
|
+
(0, messages_1.printErrorWithHelp)(`${currentAccount.username} is not logged in on ${preferredEnv}.`, [
|
|
258
|
+
`Run "playdrop auth login --env ${preferredEnv}" while authenticated as ${currentAccount.username}.`,
|
|
259
|
+
`Or run "playdrop auth use <username> --env ${preferredEnv}" to switch accounts.`,
|
|
260
|
+
], { command });
|
|
261
|
+
process.exitCode = 1;
|
|
262
|
+
}
|
|
226
263
|
return null;
|
|
227
264
|
}
|
|
228
265
|
const envConfig = resolveConfiguredEnvironment(selectedAccount.env, command, {
|
package/dist/commands/capture.js
CHANGED
|
@@ -455,7 +455,7 @@ async function capture(targetArg, options = {}) {
|
|
|
455
455
|
appType: appTypeSlug,
|
|
456
456
|
devAuth: devOptions.selection.devAuth,
|
|
457
457
|
player: devOptions.selection.player ? String(devOptions.selection.player) : null,
|
|
458
|
-
launchCheck:
|
|
458
|
+
launchCheck: true,
|
|
459
459
|
});
|
|
460
460
|
const frameUrl = (0, devAuth_1.applyHostedDevAuthSelectionToUrl)(captureBaseUrl, devOptions.selection);
|
|
461
461
|
console.log(`[capture] Launching Playwright against ${frameUrl}`);
|
|
@@ -253,6 +253,7 @@ async function devBrowser(targetArg, options = {}) {
|
|
|
253
253
|
appType: appTypeSlug,
|
|
254
254
|
devAuth: devAuthSelection.devAuth,
|
|
255
255
|
player: devAuthSelection.player ? String(devAuthSelection.player) : null,
|
|
256
|
+
launchCheck: devAuthSelection.devAuth !== 'prompt',
|
|
256
257
|
});
|
|
257
258
|
let launchUrl = devUrl;
|
|
258
259
|
if (devAuthSelection.devAuth !== 'anonymous') {
|
|
@@ -335,6 +336,7 @@ async function devBrowser(targetArg, options = {}) {
|
|
|
335
336
|
process.on('SIGTERM', handleSignal);
|
|
336
337
|
try {
|
|
337
338
|
context = await (0, playwright_1.launchPersistentChromiumContext)(profileDir, {
|
|
339
|
+
automationOrigin: devAuthSelection.devAuth === 'prompt' ? null : new URL(devUrl).origin,
|
|
338
340
|
viewport: { width: 1440, height: 960 },
|
|
339
341
|
});
|
|
340
342
|
}
|
|
@@ -32,6 +32,7 @@ export declare function buildLocalDevAppUrl(input: {
|
|
|
32
32
|
appName: string;
|
|
33
33
|
port?: number;
|
|
34
34
|
}): string;
|
|
35
|
+
export declare function terminateChildProcessTree(child: ChildProcess | null, timeoutMs?: number): Promise<void>;
|
|
35
36
|
export declare function ensureDevRouterRunning(port?: number): Promise<void>;
|
|
36
37
|
export declare function updateMountedDevRuntimeAssetManifest(input: {
|
|
37
38
|
creatorUsername: string;
|
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.DEV_ROUTER_PORT = void 0;
|
|
7
7
|
exports.parseMountConflictError = parseMountConflictError;
|
|
8
8
|
exports.buildLocalDevAppUrl = buildLocalDevAppUrl;
|
|
9
|
+
exports.terminateChildProcessTree = terminateChildProcessTree;
|
|
9
10
|
exports.ensureDevRouterRunning = ensureDevRouterRunning;
|
|
10
11
|
exports.updateMountedDevRuntimeAssetManifest = updateMountedDevRuntimeAssetManifest;
|
|
11
12
|
exports.startDevServer = startDevServer;
|
|
@@ -223,9 +224,64 @@ function spawnDevScript(projectInfo) {
|
|
|
223
224
|
cwd: projectInfo.projectDir,
|
|
224
225
|
stdio: 'inherit',
|
|
225
226
|
env: { ...process.env },
|
|
227
|
+
detached: process.platform !== 'win32',
|
|
226
228
|
});
|
|
227
229
|
return child;
|
|
228
230
|
}
|
|
231
|
+
function signalProcess(pid, signal, useGroup) {
|
|
232
|
+
const targetPid = useGroup ? -pid : pid;
|
|
233
|
+
try {
|
|
234
|
+
process.kill(targetPid, signal);
|
|
235
|
+
return true;
|
|
236
|
+
}
|
|
237
|
+
catch (error) {
|
|
238
|
+
if (error?.code === 'ESRCH') {
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
throw error;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
async function waitForChildExit(child, timeoutMs) {
|
|
245
|
+
const pid = child.pid;
|
|
246
|
+
if (!pid || !isPidAlive(pid)) {
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
return await new Promise((resolvePromise) => {
|
|
250
|
+
let settled = false;
|
|
251
|
+
const onExit = () => {
|
|
252
|
+
if (settled) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
settled = true;
|
|
256
|
+
clearTimeout(timeout);
|
|
257
|
+
child.off('exit', onExit);
|
|
258
|
+
resolvePromise(true);
|
|
259
|
+
};
|
|
260
|
+
const timeout = setTimeout(() => {
|
|
261
|
+
if (settled) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
settled = true;
|
|
265
|
+
child.off('exit', onExit);
|
|
266
|
+
resolvePromise(!pid || !isPidAlive(pid));
|
|
267
|
+
}, timeoutMs);
|
|
268
|
+
timeout.unref?.();
|
|
269
|
+
child.once('exit', onExit);
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
async function terminateChildProcessTree(child, timeoutMs = 2000) {
|
|
273
|
+
const pid = child?.pid;
|
|
274
|
+
if (!child || !pid || !isPidAlive(pid)) {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
const useGroup = process.platform !== 'win32';
|
|
278
|
+
signalProcess(pid, 'SIGTERM', useGroup);
|
|
279
|
+
if (await waitForChildExit(child, timeoutMs)) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
signalProcess(pid, 'SIGKILL', useGroup);
|
|
283
|
+
await waitForChildExit(child, timeoutMs);
|
|
284
|
+
}
|
|
229
285
|
async function fetchRouterJson(path, init = {}, port = exports.DEV_ROUTER_PORT) {
|
|
230
286
|
const response = await fetch(`http://${DEV_ROUTER_HOST}:${port}${path}`, init);
|
|
231
287
|
if (!response.ok) {
|
|
@@ -411,9 +467,7 @@ async function startDevServer(options) {
|
|
|
411
467
|
await unregisterDevMount(mountId, port);
|
|
412
468
|
}
|
|
413
469
|
finally {
|
|
414
|
-
|
|
415
|
-
devProcess.kill();
|
|
416
|
-
}
|
|
470
|
+
await terminateChildProcessTree(devProcess);
|
|
417
471
|
}
|
|
418
472
|
},
|
|
419
473
|
};
|
|
@@ -357,7 +357,7 @@ async function uploadAssetTask(client, task, sourceAppVersionId, creatorUsername
|
|
|
357
357
|
sourceAppVersionId,
|
|
358
358
|
runtimeKey: task.kind === 'owned-asset' ? task.runtimeKey : undefined,
|
|
359
359
|
tags: task.kind === 'asset' ? task.tags : undefined,
|
|
360
|
-
clearTags: task.kind === 'asset' ? options?.clearTags : undefined,
|
|
360
|
+
clearTags: task.kind === 'asset' || task.kind === 'owned-asset' ? options?.clearTags : undefined,
|
|
361
361
|
shopListed: task.shopListed,
|
|
362
362
|
shopPriceCredits: task.shopPriceCredits,
|
|
363
363
|
files,
|
|
@@ -374,7 +374,7 @@ async function uploadAssetTask(client, task, sourceAppVersionId, creatorUsername
|
|
|
374
374
|
sourceAppVersionId,
|
|
375
375
|
runtimeKey: task.kind === 'owned-asset' ? task.runtimeKey : undefined,
|
|
376
376
|
tags: task.kind === 'asset' ? task.tags : undefined,
|
|
377
|
-
clearTags: task.kind === 'asset' ? options?.clearTags : undefined,
|
|
377
|
+
clearTags: task.kind === 'asset' || task.kind === 'owned-asset' ? options?.clearTags : undefined,
|
|
378
378
|
shopListed: task.shopListed,
|
|
379
379
|
shopPriceCredits: task.shopPriceCredits,
|
|
380
380
|
files,
|
|
@@ -506,11 +506,14 @@ function buildLocalAssetManifestEntries(preparedLocalAssets) {
|
|
|
506
506
|
localAssets.push({
|
|
507
507
|
uploadKey,
|
|
508
508
|
name: localAsset.task.name,
|
|
509
|
+
displayName: localAsset.task.displayName,
|
|
510
|
+
description: localAsset.task.description,
|
|
509
511
|
category: localAsset.task.category,
|
|
510
512
|
subcategory: localAsset.prepared.subcategory ?? null,
|
|
511
513
|
format: localAsset.prepared.format,
|
|
512
514
|
visibility: localAsset.task.visibility,
|
|
513
515
|
license: localAsset.task.license,
|
|
516
|
+
tags: localAsset.task.tags,
|
|
514
517
|
shopListed: localAsset.task.shopListed,
|
|
515
518
|
shopPriceCredits: localAsset.task.shopPriceCredits,
|
|
516
519
|
files: localAsset.prepared.manifestFiles,
|