@playdrop/playdrop-cli 0.5.5 → 0.6.0
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 +2 -1
- package/config/client-meta.json +4 -4
- package/dist/apps/upload.js +226 -80
- package/dist/assetSpecs.d.ts +1 -0
- package/dist/assetSpecs.js +22 -1
- package/dist/assets/model-artifacts.d.ts +2 -2
- package/dist/assets/model-artifacts.js +1 -1
- package/dist/captureRuntime.d.ts +1 -0
- package/dist/captureRuntime.js +3 -2
- package/dist/catalogue.d.ts +33 -8
- package/dist/catalogue.js +364 -46
- package/dist/commandContext.d.ts +5 -1
- package/dist/commandContext.js +90 -29
- package/dist/commands/browse.d.ts +3 -0
- package/dist/commands/browse.js +90 -17
- package/dist/commands/build.js +1 -1
- package/dist/commands/capture.d.ts +3 -0
- package/dist/commands/capture.js +121 -9
- package/dist/commands/captureListing.d.ts +2 -0
- package/dist/commands/captureListing.js +157 -61
- package/dist/commands/create.js +6 -28
- package/dist/commands/createRemixContent.js +4 -26
- package/dist/commands/creations.js +2 -3
- package/dist/commands/detail.js +25 -3
- package/dist/commands/dev.d.ts +8 -1
- package/dist/commands/dev.js +180 -2
- package/dist/commands/devRuntimeAssets.d.ts +34 -0
- package/dist/commands/devRuntimeAssets.js +308 -0
- package/dist/commands/devServer.d.ts +11 -0
- package/dist/commands/devServer.js +196 -13
- package/dist/commands/init.js +6 -24
- package/dist/commands/search.d.ts +4 -0
- package/dist/commands/search.js +68 -11
- package/dist/commands/upload-content.d.ts +3 -3
- package/dist/commands/upload-content.js +19 -38
- package/dist/commands/upload.js +67 -77
- package/dist/commands/validate.js +13 -20
- package/dist/commands/whoami.js +23 -26
- package/dist/devAuth.d.ts +16 -0
- package/dist/devAuth.js +60 -0
- package/dist/index.js +22 -4
- package/dist/taskSelection.js +4 -3
- package/dist/taskUtils.d.ts +2 -2
- package/dist/taskUtils.js +1 -1
- package/dist/uploadLog.d.ts +1 -1
- package/node_modules/@playdrop/ai-client/package.json +1 -1
- package/node_modules/@playdrop/api-client/dist/client.d.ts +46 -115
- package/node_modules/@playdrop/api-client/dist/client.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/client.js +22 -0
- package/node_modules/@playdrop/api-client/dist/domains/apps.d.ts +14 -20
- package/node_modules/@playdrop/api-client/dist/domains/apps.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/apps.js +152 -108
- package/node_modules/@playdrop/api-client/dist/domains/assets.d.ts +2 -1
- package/node_modules/@playdrop/api-client/dist/domains/assets.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/assets.js +13 -0
- package/node_modules/@playdrop/api-client/dist/domains/payments.d.ts +5 -5
- package/node_modules/@playdrop/api-client/dist/domains/payments.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/payments.js +8 -8
- package/node_modules/@playdrop/api-client/dist/domains/search.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/search.js +24 -2
- package/node_modules/@playdrop/api-client/dist/domains/tags.d.ts +13 -1
- package/node_modules/@playdrop/api-client/dist/domains/tags.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/tags.js +52 -0
- package/node_modules/@playdrop/api-client/dist/index.d.ts +29 -31
- package/node_modules/@playdrop/api-client/dist/index.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/index.js +33 -12
- package/node_modules/@playdrop/api-client/package.json +1 -1
- package/node_modules/@playdrop/boxel-core/package.json +1 -1
- package/node_modules/@playdrop/boxel-three/package.json +1 -1
- package/node_modules/@playdrop/config/client-meta.json +4 -4
- package/node_modules/@playdrop/config/package.json +1 -1
- package/node_modules/@playdrop/types/dist/api.d.ts +153 -3
- package/node_modules/@playdrop/types/dist/api.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/api.js +30 -0
- package/node_modules/@playdrop/types/dist/app-capability-filters.d.ts +24 -0
- package/node_modules/@playdrop/types/dist/app-capability-filters.d.ts.map +1 -0
- package/node_modules/@playdrop/types/dist/app-capability-filters.js +72 -0
- package/node_modules/@playdrop/types/dist/asset-pack.d.ts +3 -2
- package/node_modules/@playdrop/types/dist/asset-pack.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/asset.d.ts +2 -3
- package/node_modules/@playdrop/types/dist/asset.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/asset.js +1 -1
- package/node_modules/@playdrop/types/dist/index.d.ts +2 -0
- package/node_modules/@playdrop/types/dist/index.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/index.js +2 -0
- package/node_modules/@playdrop/types/dist/owned-assets.d.ts +21 -0
- package/node_modules/@playdrop/types/dist/owned-assets.d.ts.map +1 -0
- package/node_modules/@playdrop/types/dist/owned-assets.js +35 -0
- package/node_modules/@playdrop/types/dist/player-meta.d.ts +28 -0
- package/node_modules/@playdrop/types/dist/player-meta.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/version.d.ts +111 -1
- package/node_modules/@playdrop/types/dist/version.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/version.js +3 -0
- package/node_modules/@playdrop/types/package.json +1 -1
- package/node_modules/@playdrop/vox-three/package.json +1 -1
- package/package.json +1 -1
package/dist/commandContext.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveAuthenticatedEnvironmentContext = resolveAuthenticatedEnvironmentContext;
|
|
4
|
+
exports.resolveOptionalEnvironmentContext = resolveOptionalEnvironmentContext;
|
|
3
5
|
exports.withEnvironment = withEnvironment;
|
|
4
6
|
exports.withPublicEnvironment = withPublicEnvironment;
|
|
5
7
|
const config_1 = require("./config");
|
|
@@ -27,7 +29,7 @@ function resolveConfiguredEnvironment(envName, command, options) {
|
|
|
27
29
|
}
|
|
28
30
|
return envConfig;
|
|
29
31
|
}
|
|
30
|
-
function buildContext(cfg, envConfig, account) {
|
|
32
|
+
function buildContext(cfg, envConfig, account, workspaceAuth = null) {
|
|
31
33
|
const token = account?.token ?? cfg.token ?? '';
|
|
32
34
|
const client = (0, apiClient_1.createCliApiClient)({ baseUrl: envConfig.apiBase, token });
|
|
33
35
|
const aiClient = (0, apiClient_1.createCliAiClient)({ baseUrl: envConfig.aiBase, token });
|
|
@@ -39,6 +41,7 @@ function buildContext(cfg, envConfig, account) {
|
|
|
39
41
|
token,
|
|
40
42
|
config: cfg,
|
|
41
43
|
account,
|
|
44
|
+
workspaceAuth,
|
|
42
45
|
};
|
|
43
46
|
}
|
|
44
47
|
function buildLegacyAccountSession(cfg) {
|
|
@@ -77,32 +80,7 @@ async function migrateLegacyConfigIfNeeded(cfg, envConfig, command) {
|
|
|
77
80
|
return null;
|
|
78
81
|
}
|
|
79
82
|
}
|
|
80
|
-
function
|
|
81
|
-
const matchingSessions = (0, config_1.listAccountSessionsForUsername)(workspaceAuth.config.ownerUsername, cfg);
|
|
82
|
-
if (workspaceAuth.config.env) {
|
|
83
|
-
return {
|
|
84
|
-
account: (0, config_1.findAccountSession)(workspaceAuth.config.ownerUsername, workspaceAuth.config.env, cfg),
|
|
85
|
-
matchingSessions,
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
if (matchingSessions.length === 1) {
|
|
89
|
-
return {
|
|
90
|
-
account: matchingSessions[0],
|
|
91
|
-
matchingSessions,
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
if (currentAccount && currentAccount.username === workspaceAuth.config.ownerUsername) {
|
|
95
|
-
return {
|
|
96
|
-
account: (0, config_1.findAccountSession)(workspaceAuth.config.ownerUsername, currentAccount.env, cfg),
|
|
97
|
-
matchingSessions,
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
return {
|
|
101
|
-
account: null,
|
|
102
|
-
matchingSessions,
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
async function resolveAuthenticatedEnvironment(command, actionLabel, options = {}) {
|
|
83
|
+
async function loadWorkspaceAwareConfig(command, options) {
|
|
106
84
|
let cfg = (0, config_1.loadConfig)();
|
|
107
85
|
let workspaceAuth = null;
|
|
108
86
|
try {
|
|
@@ -133,6 +111,39 @@ async function resolveAuthenticatedEnvironment(command, actionLabel, options = {
|
|
|
133
111
|
}
|
|
134
112
|
cfg = migrated;
|
|
135
113
|
}
|
|
114
|
+
return { cfg, workspaceAuth };
|
|
115
|
+
}
|
|
116
|
+
function resolveWorkspaceSelectedAccount(cfg, currentAccount, workspaceAuth) {
|
|
117
|
+
const matchingSessions = (0, config_1.listAccountSessionsForUsername)(workspaceAuth.config.ownerUsername, cfg);
|
|
118
|
+
if (workspaceAuth.config.env) {
|
|
119
|
+
return {
|
|
120
|
+
account: (0, config_1.findAccountSession)(workspaceAuth.config.ownerUsername, workspaceAuth.config.env, cfg),
|
|
121
|
+
matchingSessions,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
if (matchingSessions.length === 1) {
|
|
125
|
+
return {
|
|
126
|
+
account: matchingSessions[0],
|
|
127
|
+
matchingSessions,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
if (currentAccount && currentAccount.username === workspaceAuth.config.ownerUsername) {
|
|
131
|
+
return {
|
|
132
|
+
account: (0, config_1.findAccountSession)(workspaceAuth.config.ownerUsername, currentAccount.env, cfg),
|
|
133
|
+
matchingSessions,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
account: null,
|
|
138
|
+
matchingSessions,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
async function resolveAuthenticatedEnvironment(command, actionLabel, options = {}) {
|
|
142
|
+
const loaded = await loadWorkspaceAwareConfig(command, options);
|
|
143
|
+
if (!loaded) {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
const { cfg, workspaceAuth } = loaded;
|
|
136
147
|
const currentAccount = (0, config_1.getCurrentAccountSession)(cfg) ?? buildLegacyAccountSession(cfg);
|
|
137
148
|
const selectedAccount = workspaceAuth
|
|
138
149
|
? resolveWorkspaceSelectedAccount(cfg, currentAccount, workspaceAuth).account
|
|
@@ -171,14 +182,64 @@ async function resolveAuthenticatedEnvironment(command, actionLabel, options = {
|
|
|
171
182
|
cfg: (0, config_1.loadConfig)(),
|
|
172
183
|
account: selectedAccount,
|
|
173
184
|
envConfig,
|
|
185
|
+
workspaceAuth,
|
|
174
186
|
};
|
|
175
187
|
}
|
|
176
|
-
async function
|
|
188
|
+
async function resolveAuthenticatedEnvironmentContext(command, actionLabel, options = {}) {
|
|
177
189
|
const resolved = await resolveAuthenticatedEnvironment(command, actionLabel, options);
|
|
178
190
|
if (!resolved) {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
return buildContext(resolved.cfg, resolved.envConfig, resolved.account, resolved.workspaceAuth);
|
|
194
|
+
}
|
|
195
|
+
async function resolveOptionalEnvironmentContext(command, options = {}) {
|
|
196
|
+
const loaded = await loadWorkspaceAwareConfig(command, options);
|
|
197
|
+
if (!loaded) {
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
const { cfg, workspaceAuth } = loaded;
|
|
201
|
+
const currentAccount = (0, config_1.getCurrentAccountSession)(cfg) ?? buildLegacyAccountSession(cfg);
|
|
202
|
+
if (!currentAccount && !workspaceAuth) {
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
const selectedAccount = workspaceAuth
|
|
206
|
+
? resolveWorkspaceSelectedAccount(cfg, currentAccount, workspaceAuth).account
|
|
207
|
+
: currentAccount;
|
|
208
|
+
if (!selectedAccount) {
|
|
209
|
+
if (workspaceAuth) {
|
|
210
|
+
const matchingSessions = (0, config_1.listAccountSessionsForUsername)(workspaceAuth.config.ownerUsername, cfg);
|
|
211
|
+
if (!workspaceAuth.config.env && matchingSessions.length > 1) {
|
|
212
|
+
(0, messages_1.printErrorWithHelp)(`This workspace is pinned to ${workspaceAuth.config.ownerUsername}, but that account is logged in on multiple environments.`, [
|
|
213
|
+
`Run "playdrop auth use ${workspaceAuth.config.ownerUsername} --env <env>" to select the matching environment.`,
|
|
214
|
+
'Or add an "env" field to .playdrop.json.',
|
|
215
|
+
], { command });
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
const envSuffix = workspaceAuth.config.env ? ` on ${workspaceAuth.config.env}` : '';
|
|
219
|
+
(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${workspaceAuth.config.env ? ` --env ${workspaceAuth.config.env}` : ''}" while authenticated as ${workspaceAuth.config.ownerUsername}.`,
|
|
221
|
+
'Or remove .playdrop.json if this workspace should use your current default account.',
|
|
222
|
+
], { command });
|
|
223
|
+
}
|
|
224
|
+
process.exitCode = 1;
|
|
225
|
+
}
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
const envConfig = resolveConfiguredEnvironment(selectedAccount.env, command, {
|
|
229
|
+
requireAuth: true,
|
|
230
|
+
allowDefaultPublicEnv: false,
|
|
231
|
+
});
|
|
232
|
+
if (!envConfig) {
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
return buildContext((0, config_1.loadConfig)(), envConfig, selectedAccount, workspaceAuth);
|
|
236
|
+
}
|
|
237
|
+
async function withEnvironment(command, actionLabel, callback, options = {}) {
|
|
238
|
+
const ctx = await resolveAuthenticatedEnvironmentContext(command, actionLabel, options);
|
|
239
|
+
if (!ctx) {
|
|
179
240
|
return;
|
|
180
241
|
}
|
|
181
|
-
await callback(
|
|
242
|
+
await callback(ctx);
|
|
182
243
|
}
|
|
183
244
|
async function withPublicEnvironment(command, callback) {
|
|
184
245
|
const cfg = (0, config_1.loadConfig)();
|
package/dist/commands/browse.js
CHANGED
|
@@ -71,6 +71,9 @@ function parseBrowseSort(raw) {
|
|
|
71
71
|
return undefined;
|
|
72
72
|
}
|
|
73
73
|
const normalized = raw.trim().toLowerCase();
|
|
74
|
+
if (types_1.APP_LIST_SORT_VALUES.includes(normalized)) {
|
|
75
|
+
return normalized;
|
|
76
|
+
}
|
|
74
77
|
if (types_1.ASSET_LIST_SORT_VALUES.includes(normalized)) {
|
|
75
78
|
return normalized;
|
|
76
79
|
}
|
|
@@ -117,12 +120,6 @@ function buildCountsSuffix(item) {
|
|
|
117
120
|
if (typeof item.item.viewCount === 'number') {
|
|
118
121
|
parts.push(`view ${formatCountValue(item.item.viewCount)}`);
|
|
119
122
|
}
|
|
120
|
-
if (typeof item.item.downloadCount === 'number') {
|
|
121
|
-
parts.push(`download ${formatCountValue(item.item.downloadCount)}`);
|
|
122
|
-
}
|
|
123
|
-
if (typeof item.item.playCount === 'number') {
|
|
124
|
-
parts.push(`play ${formatCountValue(item.item.playCount)}`);
|
|
125
|
-
}
|
|
126
123
|
}
|
|
127
124
|
if (item.kind === 'asset-pack' && typeof item.item.downloadCount === 'number') {
|
|
128
125
|
parts.push(`download ${formatCountValue(item.item.downloadCount)}`);
|
|
@@ -249,12 +246,17 @@ function buildTagSuffix(tags) {
|
|
|
249
246
|
function parseBrowseSortOption(rawSort, kind) {
|
|
250
247
|
const sort = parseBrowseSort(rawSort);
|
|
251
248
|
if (sort === null) {
|
|
252
|
-
(0, messages_1.printErrorWithHelp)(`Sort "${rawSort ?? ''}" is not supported.`, ['Use one of:
|
|
249
|
+
(0, messages_1.printErrorWithHelp)(`Sort "${rawSort ?? ''}" is not supported.`, ['Use one of: newest, updated, views, likes, used, recent, remixes, comments, assets, apps, alpha.'], { command: 'browse' });
|
|
253
250
|
process.exitCode = 1;
|
|
254
251
|
return null;
|
|
255
252
|
}
|
|
256
253
|
if (sort && kind === 'all') {
|
|
257
|
-
(0, messages_1.printErrorWithHelp)('The --sort option is not supported with --kind all.', ['Choose --kind asset or --kind asset-spec when sorting browse results.'], { command: 'browse' });
|
|
254
|
+
(0, messages_1.printErrorWithHelp)('The --sort option is not supported with --kind all.', ['Choose --kind app, --kind asset, or --kind asset-spec when sorting browse results.'], { command: 'browse' });
|
|
255
|
+
process.exitCode = 1;
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
if (sort && kind === 'app' && !types_1.APP_LIST_SORT_VALUES.includes(sort)) {
|
|
259
|
+
(0, messages_1.printErrorWithHelp)(`Sort "${sort}" is not supported for apps.`, ['Use one of: newest, updated, views, likes, used.'], { command: 'browse' });
|
|
258
260
|
process.exitCode = 1;
|
|
259
261
|
return null;
|
|
260
262
|
}
|
|
@@ -264,7 +266,7 @@ function parseBrowseSortOption(rawSort, kind) {
|
|
|
264
266
|
return null;
|
|
265
267
|
}
|
|
266
268
|
if (sort && kind === 'asset' && !types_1.ASSET_LIST_SORT_VALUES.includes(sort)) {
|
|
267
|
-
(0, messages_1.printErrorWithHelp)(`Sort "${sort}" is not supported for assets.`, ['Use one of: recent, likes,
|
|
269
|
+
(0, messages_1.printErrorWithHelp)(`Sort "${sort}" is not supported for assets.`, ['Use one of: recent, likes, remixes, comments.'], { command: 'browse' });
|
|
268
270
|
process.exitCode = 1;
|
|
269
271
|
return null;
|
|
270
272
|
}
|
|
@@ -321,6 +323,30 @@ function parseBrowseCommandOptions(options) {
|
|
|
321
323
|
process.exitCode = 1;
|
|
322
324
|
return { ok: false };
|
|
323
325
|
}
|
|
326
|
+
const auth = options.auth === undefined ? undefined : (0, types_1.parseAppAuthFilter)(options.auth);
|
|
327
|
+
if (options.auth !== undefined && !auth) {
|
|
328
|
+
(0, messages_1.printErrorWithHelp)(`Auth filter "${options.auth}" is not supported.`, ['Use one of: required, optional, none.'], { command: 'browse' });
|
|
329
|
+
process.exitCode = 1;
|
|
330
|
+
return { ok: false };
|
|
331
|
+
}
|
|
332
|
+
const controller = options.controller === undefined ? undefined : (0, types_1.parseAppControllerFilter)(options.controller);
|
|
333
|
+
if (options.controller !== undefined && !controller) {
|
|
334
|
+
(0, messages_1.printErrorWithHelp)(`Controller filter "${options.controller}" is not supported.`, ['Use one of: required, optional, none.'], { command: 'browse' });
|
|
335
|
+
process.exitCode = 1;
|
|
336
|
+
return { ok: false };
|
|
337
|
+
}
|
|
338
|
+
const surface = options.surface === undefined ? undefined : (0, types_1.parseAppSurfaceFilter)(options.surface);
|
|
339
|
+
if (options.surface !== undefined && !surface) {
|
|
340
|
+
(0, messages_1.printErrorWithHelp)(`Surface filter "${options.surface}" is not supported.`, ['Use one of: desktop, mobile-portrait, mobile-landscape.'], { command: 'browse' });
|
|
341
|
+
process.exitCode = 1;
|
|
342
|
+
return { ok: false };
|
|
343
|
+
}
|
|
344
|
+
const hasCapabilityFilters = Boolean(auth || controller || surface);
|
|
345
|
+
if (hasCapabilityFilters && kind !== 'app') {
|
|
346
|
+
(0, messages_1.printErrorWithHelp)('Capability filters only support app browse.', ['Use --kind app together with --auth, --surface, or --controller.'], { command: 'browse' });
|
|
347
|
+
process.exitCode = 1;
|
|
348
|
+
return { ok: false };
|
|
349
|
+
}
|
|
324
350
|
const browseFilters = parseBrowseLimitsAndFilters(options);
|
|
325
351
|
if (!browseFilters) {
|
|
326
352
|
return { ok: false };
|
|
@@ -341,6 +367,9 @@ function parseBrowseCommandOptions(options) {
|
|
|
341
367
|
kind,
|
|
342
368
|
creator,
|
|
343
369
|
appType: appType ?? undefined,
|
|
370
|
+
auth: auth ?? undefined,
|
|
371
|
+
controller: controller ?? undefined,
|
|
372
|
+
surface: surface ?? undefined,
|
|
344
373
|
...browseFilters,
|
|
345
374
|
assetSpec: normalizeOptionalOption(options.assetSpec),
|
|
346
375
|
assetSpecOwner: normalizeOptionalOption(options.assetSpecOwner),
|
|
@@ -353,17 +382,33 @@ function parseBrowseCommandOptions(options) {
|
|
|
353
382
|
async function loadMergedBrowseResults(input) {
|
|
354
383
|
const { client, creator, creatorUsername, appType, assetCategory, assetSubcategory, assetSpec, assetSpecOwner, assetSpecName, limit, offset, tags, } = input;
|
|
355
384
|
const appResultsPromise = creatorUsername
|
|
356
|
-
? collectPaginatedItems((pageLimit, pageOffset) => client.fetchAppsByCreator(creatorUsername, {
|
|
385
|
+
? collectPaginatedItems((pageLimit, pageOffset) => client.fetchAppsByCreator(creatorUsername, {
|
|
386
|
+
limit: pageLimit,
|
|
387
|
+
offset: pageOffset,
|
|
388
|
+
type: appType,
|
|
389
|
+
...(tags.length > 0 ? { tags } : {}),
|
|
390
|
+
...(input.sort ? { sort: input.sort } : {}),
|
|
391
|
+
})
|
|
357
392
|
.then((response) => ({
|
|
358
393
|
items: response.apps ?? [],
|
|
359
394
|
pagination: requirePagination(response.pagination, 'browse_all_creator_apps'),
|
|
360
395
|
})))
|
|
361
396
|
: (appType
|
|
362
|
-
? collectPaginatedItems((pageLimit, pageOffset) => client.fetchAppsByType(appType, {
|
|
397
|
+
? collectPaginatedItems((pageLimit, pageOffset) => client.fetchAppsByType(appType, {
|
|
398
|
+
limit: pageLimit,
|
|
399
|
+
offset: pageOffset,
|
|
400
|
+
...(tags.length > 0 ? { tags } : {}),
|
|
401
|
+
...(input.sort ? { sort: input.sort } : {}),
|
|
402
|
+
}).then((response) => ({
|
|
363
403
|
items: response.apps ?? [],
|
|
364
404
|
pagination: requirePagination(response.pagination, 'browse_all_type_apps'),
|
|
365
405
|
})))
|
|
366
|
-
: collectPaginatedItems((pageLimit, pageOffset) => client.fetchApps({
|
|
406
|
+
: collectPaginatedItems((pageLimit, pageOffset) => client.fetchApps({
|
|
407
|
+
limit: pageLimit,
|
|
408
|
+
offset: pageOffset,
|
|
409
|
+
...(tags.length > 0 ? { tags } : {}),
|
|
410
|
+
...(input.sort ? { sort: input.sort } : {}),
|
|
411
|
+
}).then((response) => ({
|
|
367
412
|
items: response.apps ?? [],
|
|
368
413
|
pagination: requirePagination(response.pagination, 'browse_all_apps'),
|
|
369
414
|
}))));
|
|
@@ -501,23 +546,48 @@ async function runAssetPackBrowseCommand(input) {
|
|
|
501
546
|
};
|
|
502
547
|
}
|
|
503
548
|
async function runBrowseCommand(input) {
|
|
504
|
-
const { client, kind, creator, creatorUsername, appType, limit, offset, tags, } = input;
|
|
549
|
+
const { client, kind, creator, creatorUsername, appType, auth, controller, surface, sort, limit, offset, tags, } = input;
|
|
505
550
|
if (kind === 'app') {
|
|
506
551
|
if (creatorUsername) {
|
|
507
|
-
const response = await client.fetchAppsByCreator(creatorUsername, {
|
|
552
|
+
const response = await client.fetchAppsByCreator(creatorUsername, {
|
|
553
|
+
limit,
|
|
554
|
+
offset,
|
|
555
|
+
type: appType,
|
|
556
|
+
...(auth ? { auth } : {}),
|
|
557
|
+
...(controller ? { controller } : {}),
|
|
558
|
+
...(surface ? { surface } : {}),
|
|
559
|
+
...(tags.length > 0 ? { tags } : {}),
|
|
560
|
+
...(sort ? { sort: sort } : {}),
|
|
561
|
+
});
|
|
508
562
|
return {
|
|
509
563
|
items: (response.apps ?? []).map((item) => toBrowseItem('app', item)),
|
|
510
564
|
pagination: requirePagination(response.pagination, 'browse_app_creator'),
|
|
511
565
|
};
|
|
512
566
|
}
|
|
513
567
|
if (appType) {
|
|
514
|
-
const response = await client.fetchAppsByType(appType, {
|
|
568
|
+
const response = await client.fetchAppsByType(appType, {
|
|
569
|
+
limit,
|
|
570
|
+
offset,
|
|
571
|
+
...(auth ? { auth } : {}),
|
|
572
|
+
...(controller ? { controller } : {}),
|
|
573
|
+
...(surface ? { surface } : {}),
|
|
574
|
+
...(tags.length > 0 ? { tags } : {}),
|
|
575
|
+
...(sort ? { sort: sort } : {}),
|
|
576
|
+
});
|
|
515
577
|
return {
|
|
516
578
|
items: (response.apps ?? []).map((item) => toBrowseItem('app', item)),
|
|
517
579
|
pagination: requirePagination(response.pagination, 'browse_app_type'),
|
|
518
580
|
};
|
|
519
581
|
}
|
|
520
|
-
const response = await client.fetchApps({
|
|
582
|
+
const response = await client.fetchApps({
|
|
583
|
+
limit,
|
|
584
|
+
offset,
|
|
585
|
+
...(auth ? { auth } : {}),
|
|
586
|
+
...(controller ? { controller } : {}),
|
|
587
|
+
...(surface ? { surface } : {}),
|
|
588
|
+
...(tags.length > 0 ? { tags } : {}),
|
|
589
|
+
...(sort ? { sort: sort } : {}),
|
|
590
|
+
});
|
|
521
591
|
return {
|
|
522
592
|
items: (response.apps ?? []).map((item) => toBrowseItem('app', item)),
|
|
523
593
|
pagination: requirePagination(response.pagination, 'browse_app_all'),
|
|
@@ -539,7 +609,7 @@ async function browse(options = {}) {
|
|
|
539
609
|
if (!parsed.ok) {
|
|
540
610
|
return;
|
|
541
611
|
}
|
|
542
|
-
const { kind, creator, appType, assetCategory, assetSubcategory, assetSpec, assetSpecOwner, assetSpecName, sort, limit, offset, tags } = parsed.input;
|
|
612
|
+
const { kind, creator, appType, auth, controller, surface, assetCategory, assetSubcategory, assetSpec, assetSpecOwner, assetSpecName, sort, limit, offset, tags, } = parsed.input;
|
|
543
613
|
await (0, commandContext_1.withPublicEnvironment)('browse', async ({ client }) => {
|
|
544
614
|
try {
|
|
545
615
|
const creatorUsername = await resolveCreatorUsername(creator, 'browse', async () => {
|
|
@@ -559,6 +629,9 @@ async function browse(options = {}) {
|
|
|
559
629
|
creator,
|
|
560
630
|
creatorUsername,
|
|
561
631
|
appType,
|
|
632
|
+
auth,
|
|
633
|
+
controller,
|
|
634
|
+
surface,
|
|
562
635
|
assetCategory,
|
|
563
636
|
assetSubcategory,
|
|
564
637
|
assetSpec,
|
package/dist/commands/build.js
CHANGED
|
@@ -27,7 +27,7 @@ async function build(pathOrName) {
|
|
|
27
27
|
await (0, apps_1.validateAppTask)(task);
|
|
28
28
|
await (0, apps_1.buildApp)(task);
|
|
29
29
|
}
|
|
30
|
-
else if (task.kind === 'asset' || task.kind === '
|
|
30
|
+
else if (task.kind === 'asset' || task.kind === 'owned-asset') {
|
|
31
31
|
const generated = await (0, model_artifacts_1.prepareModel3DAssetArtifacts)(task);
|
|
32
32
|
if (!generated) {
|
|
33
33
|
throw new Error(`project build does not support ${task.kind} "${entityId}" because it has no local build step.`);
|
package/dist/commands/capture.js
CHANGED
|
@@ -7,11 +7,15 @@ const types_1 = require("@playdrop/types");
|
|
|
7
7
|
const http_1 = require("../http");
|
|
8
8
|
const messages_1 = require("../messages");
|
|
9
9
|
const catalogue_utils_1 = require("../catalogue-utils");
|
|
10
|
+
const catalogue_1 = require("../catalogue");
|
|
10
11
|
const devShared_1 = require("./devShared");
|
|
11
12
|
const devServer_1 = require("./devServer");
|
|
12
13
|
const commandContext_1 = require("../commandContext");
|
|
13
14
|
const appUrls_1 = require("../appUrls");
|
|
14
15
|
const captureRuntime_1 = require("../captureRuntime");
|
|
16
|
+
const devAuth_1 = require("../devAuth");
|
|
17
|
+
const devRuntimeAssets_1 = require("./devRuntimeAssets");
|
|
18
|
+
const dev_1 = require("./dev");
|
|
15
19
|
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';
|
|
16
20
|
const SURFACE_PRESETS = {
|
|
17
21
|
desktop: {
|
|
@@ -96,22 +100,55 @@ function resolveCaptureLoginOverride(options) {
|
|
|
96
100
|
}
|
|
97
101
|
return { username, password };
|
|
98
102
|
}
|
|
103
|
+
function resolveCaptureDevOptions(options) {
|
|
104
|
+
const selection = (0, devAuth_1.parseHostedDevAuthSelection)({
|
|
105
|
+
devAuth: options.devAuth,
|
|
106
|
+
player: options.player,
|
|
107
|
+
defaultMode: 'anonymous',
|
|
108
|
+
allowPrompt: false,
|
|
109
|
+
});
|
|
110
|
+
const resetMode = (0, devAuth_1.parseResetDevPlayerMode)(options.resetDevPlayer);
|
|
111
|
+
if (selection.devAuth !== 'player' && resetMode !== 'never') {
|
|
112
|
+
throw new Error('reset_dev_player_requires_player_auth');
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
selection,
|
|
116
|
+
resetMode,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
99
119
|
// eslint-disable-next-line max-lines-per-function
|
|
100
120
|
async function capture(targetArg, options = {}) {
|
|
101
121
|
const timeoutSeconds = (0, captureRuntime_1.validateCaptureTimeout)(options.timeoutSeconds);
|
|
102
122
|
const timeoutMs = Math.round(timeoutSeconds * 1000);
|
|
103
123
|
let minimumLogLevel;
|
|
104
124
|
let loginOverride;
|
|
125
|
+
let devOptions;
|
|
105
126
|
try {
|
|
106
127
|
minimumLogLevel = (0, captureRuntime_1.resolveCaptureLogLevel)(options.logLevel);
|
|
107
128
|
loginOverride = resolveCaptureLoginOverride(options);
|
|
129
|
+
devOptions = resolveCaptureDevOptions(options);
|
|
108
130
|
}
|
|
109
131
|
catch (error) {
|
|
110
132
|
if (error instanceof Error && error.message === 'invalid_credentials_pair') {
|
|
111
133
|
(0, messages_1.printErrorWithHelp)('Use --username and --password together.', [], { command: 'project capture' });
|
|
112
134
|
}
|
|
135
|
+
else if (error instanceof Error && error.message === 'dev_auth_prompt_not_supported') {
|
|
136
|
+
(0, messages_1.printErrorWithHelp)('Use --dev-auth anonymous, viewer, or player for deterministic capture.', [], { command: 'project capture' });
|
|
137
|
+
}
|
|
138
|
+
else if (error instanceof Error && error.message === 'dev_auth_player_slot_required') {
|
|
139
|
+
(0, messages_1.printErrorWithHelp)('Use --player 1, 2, 3, or 4 when --dev-auth player is selected.', [], { command: 'project capture' });
|
|
140
|
+
}
|
|
141
|
+
else if (error instanceof Error && error.message === 'reset_dev_player_requires_player_auth') {
|
|
142
|
+
(0, messages_1.printErrorWithHelp)('Use --reset-dev-player only with --dev-auth player.', [], { command: 'project capture' });
|
|
143
|
+
}
|
|
144
|
+
else if (error instanceof Error && error.message === 'reset_dev_player_invalid') {
|
|
145
|
+
(0, messages_1.printErrorWithHelp)('Use --reset-dev-player before, after, before-and-after, or never.', [], { command: 'project capture' });
|
|
146
|
+
}
|
|
113
147
|
else {
|
|
114
|
-
(0, messages_1.printErrorWithHelp)(error?.message || 'Invalid
|
|
148
|
+
(0, messages_1.printErrorWithHelp)(error?.message || 'Invalid capture options.', [
|
|
149
|
+
'Valid log levels: debug, info, warn, error',
|
|
150
|
+
'Valid --dev-auth values: anonymous, viewer, player',
|
|
151
|
+
], { command: 'project capture' });
|
|
115
152
|
}
|
|
116
153
|
process.exitCode = 1;
|
|
117
154
|
return;
|
|
@@ -203,11 +240,10 @@ async function capture(targetArg, options = {}) {
|
|
|
203
240
|
}
|
|
204
241
|
const projectInfo = (0, devShared_1.findProjectInfo)(filePath);
|
|
205
242
|
const devScriptAvailable = Boolean(projectInfo.projectDir && projectInfo.packageJson && typeof projectInfo.packageJson.scripts?.dev === 'string');
|
|
206
|
-
await (0, commandContext_1.withEnvironment)('project capture', 'Capturing app logs', async ({ client, env, envConfig
|
|
207
|
-
let currentUser = null;
|
|
243
|
+
await (0, commandContext_1.withEnvironment)('project capture', 'Capturing app logs', async ({ client, env, envConfig }) => {
|
|
208
244
|
let currentUsername = '';
|
|
209
245
|
try {
|
|
210
|
-
currentUser = await (0, devShared_1.fetchDevUser)(client);
|
|
246
|
+
const currentUser = await (0, devShared_1.fetchDevUser)(client);
|
|
211
247
|
currentUsername = currentUser.username.trim();
|
|
212
248
|
}
|
|
213
249
|
catch (error) {
|
|
@@ -242,8 +278,14 @@ async function capture(targetArg, options = {}) {
|
|
|
242
278
|
}
|
|
243
279
|
throw error;
|
|
244
280
|
}
|
|
281
|
+
if ((devOptions.selection.devAuth === 'viewer' || devOptions.selection.devAuth === 'player') && !loginOverride) {
|
|
282
|
+
(0, messages_1.printErrorWithHelp)(`Use --username and --password to establish a browser session before running --dev-auth ${devOptions.selection.devAuth}.`, [], { command: 'project capture' });
|
|
283
|
+
process.exitCode = 1;
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
let registeredApp = null;
|
|
245
287
|
try {
|
|
246
|
-
await (0, devShared_1.assertAppRegistered)(client, currentUsername, appName);
|
|
288
|
+
registeredApp = await (0, devShared_1.assertAppRegistered)(client, currentUsername, appName);
|
|
247
289
|
}
|
|
248
290
|
catch (error) {
|
|
249
291
|
if (error instanceof http_1.CLIUnsupportedClientError) {
|
|
@@ -302,6 +344,35 @@ async function capture(targetArg, options = {}) {
|
|
|
302
344
|
}
|
|
303
345
|
}
|
|
304
346
|
};
|
|
347
|
+
let runtimeAssetManifest = (0, devRuntimeAssets_1.createEmptyDevRuntimeAssetManifest)();
|
|
348
|
+
const taskLookup = (0, catalogue_1.findAppTaskByFile)(filePath);
|
|
349
|
+
if (taskLookup.errors.length > 0) {
|
|
350
|
+
(0, messages_1.printErrorWithHelp)(taskLookup.errors[0] || 'Failed to resolve the app task from catalogue.json.', taskLookup.errors.slice(1), { command: 'project capture' });
|
|
351
|
+
process.exitCode = 1;
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
if (taskLookup.task) {
|
|
355
|
+
try {
|
|
356
|
+
runtimeAssetManifest = await (0, devRuntimeAssets_1.buildDevRuntimeAssetManifest)({
|
|
357
|
+
client,
|
|
358
|
+
apiBase: envConfig.apiBase,
|
|
359
|
+
task: taskLookup.task,
|
|
360
|
+
creatorUsername: currentUsername,
|
|
361
|
+
appBaseUrl: new URL('.', (0, devServer_1.buildLocalDevAppUrl)({
|
|
362
|
+
creatorUsername: currentUsername,
|
|
363
|
+
appType: appTypeSlug,
|
|
364
|
+
appName,
|
|
365
|
+
port: devServer_1.DEV_ROUTER_PORT,
|
|
366
|
+
})).toString(),
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
catch (error) {
|
|
370
|
+
const formatted = (0, dev_1.formatDevRuntimeAssetManifestFailure)(error);
|
|
371
|
+
(0, messages_1.printErrorWithHelp)(formatted.message, formatted.suggestions, { command: 'project capture' });
|
|
372
|
+
process.exitCode = 1;
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
305
376
|
if (serverAlreadyRunning) {
|
|
306
377
|
console.log(`[capture] Reusing dev server at ${(0, devServer_1.buildLocalDevAppUrl)({
|
|
307
378
|
creatorUsername: currentUsername,
|
|
@@ -309,6 +380,21 @@ async function capture(targetArg, options = {}) {
|
|
|
309
380
|
appName,
|
|
310
381
|
port: devServer_1.DEV_ROUTER_PORT,
|
|
311
382
|
})}`);
|
|
383
|
+
try {
|
|
384
|
+
await (0, devServer_1.updateMountedDevRuntimeAssetManifest)({
|
|
385
|
+
creatorUsername: currentUsername,
|
|
386
|
+
appName,
|
|
387
|
+
runtimeAssetManifest,
|
|
388
|
+
port: devServer_1.DEV_ROUTER_PORT,
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
catch (error) {
|
|
392
|
+
(0, messages_1.printErrorWithHelp)(error?.message || 'Failed to refresh the local runtime asset manifest on the shared dev router.', [
|
|
393
|
+
'Restart "playdrop project dev" for this app and try capture again.',
|
|
394
|
+
], { command: 'project capture' });
|
|
395
|
+
process.exitCode = 1;
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
312
398
|
}
|
|
313
399
|
else {
|
|
314
400
|
try {
|
|
@@ -319,6 +405,7 @@ async function capture(targetArg, options = {}) {
|
|
|
319
405
|
htmlPath: filePath,
|
|
320
406
|
port: devServer_1.DEV_ROUTER_PORT,
|
|
321
407
|
projectInfo,
|
|
408
|
+
runtimeAssetManifest,
|
|
322
409
|
});
|
|
323
410
|
signalHandler = () => {
|
|
324
411
|
void cleanup().finally(() => process.exit(130));
|
|
@@ -355,8 +442,22 @@ async function capture(targetArg, options = {}) {
|
|
|
355
442
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
356
443
|
}
|
|
357
444
|
const webBase = envConfig.webBase ?? 'https://www.playdrop.ai';
|
|
358
|
-
const frameUrl = `${webBase}/creators/${encodeURIComponent(currentUsername)}/apps/${appTypeSlug}/${encodeURIComponent(appName)}/dev
|
|
445
|
+
const frameUrl = (0, devAuth_1.applyHostedDevAuthSelectionToUrl)(`${webBase}/creators/${encodeURIComponent(currentUsername)}/apps/${appTypeSlug}/${encodeURIComponent(appName)}/dev`, devOptions.selection);
|
|
359
446
|
console.log(`[capture] Launching Playwright against ${frameUrl}`);
|
|
447
|
+
const shouldResetBefore = devOptions.selection.devAuth === 'player'
|
|
448
|
+
&& (devOptions.resetMode === 'before' || devOptions.resetMode === 'before-and-after');
|
|
449
|
+
const shouldResetAfter = devOptions.selection.devAuth === 'player'
|
|
450
|
+
&& (devOptions.resetMode === 'after' || devOptions.resetMode === 'before-and-after');
|
|
451
|
+
const selectedPlayerSlot = devOptions.selection.player;
|
|
452
|
+
const registeredAppId = typeof registeredApp.id === 'number' ? registeredApp.id : null;
|
|
453
|
+
if ((shouldResetBefore || shouldResetAfter) && registeredAppId === null) {
|
|
454
|
+
(0, messages_1.printErrorWithHelp)('The registered app is missing a numeric id, so test-player reset is unavailable.', [], { command: 'project capture' });
|
|
455
|
+
process.exitCode = 1;
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
if (shouldResetBefore && selectedPlayerSlot !== null) {
|
|
459
|
+
await client.resetDevPlayer(registeredAppId, selectedPlayerSlot);
|
|
460
|
+
}
|
|
360
461
|
try {
|
|
361
462
|
const result = await (0, captureRuntime_1.runCapture)({
|
|
362
463
|
targetUrl: frameUrl,
|
|
@@ -365,9 +466,11 @@ async function capture(targetArg, options = {}) {
|
|
|
365
466
|
minimumLogLevel,
|
|
366
467
|
screenshotPath,
|
|
367
468
|
contextOptions: surfaceContextOptions,
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
469
|
+
login: loginOverride ? {
|
|
470
|
+
username: loginOverride.username,
|
|
471
|
+
password: loginOverride.password,
|
|
472
|
+
} : undefined,
|
|
473
|
+
savedSessionBootstrap: false,
|
|
371
474
|
enableCaptureBridge: true,
|
|
372
475
|
});
|
|
373
476
|
if (result.errorCount > 0) {
|
|
@@ -396,6 +499,15 @@ async function capture(targetArg, options = {}) {
|
|
|
396
499
|
process.exitCode = 1;
|
|
397
500
|
}
|
|
398
501
|
finally {
|
|
502
|
+
if (shouldResetAfter && selectedPlayerSlot !== null) {
|
|
503
|
+
try {
|
|
504
|
+
await client.resetDevPlayer(registeredAppId, selectedPlayerSlot);
|
|
505
|
+
}
|
|
506
|
+
catch (error) {
|
|
507
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
508
|
+
process.exitCode = 1;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
399
511
|
if (signalHandler) {
|
|
400
512
|
process.off('SIGINT', signalHandler);
|
|
401
513
|
process.off('SIGTERM', signalHandler);
|
|
@@ -45,6 +45,8 @@ type CropRect = {
|
|
|
45
45
|
width: number;
|
|
46
46
|
height: number;
|
|
47
47
|
};
|
|
48
|
+
export declare function resolveListingCaptureRouteSegment(previewable: boolean): 'dev' | 'dev-preview';
|
|
49
|
+
export declare function resolveListingCaptureSceneId(width: number, height: number): 'listing-landscape' | 'listing-portrait';
|
|
48
50
|
export declare function parseCaptureListingOptions(targetArg: string | undefined, options?: CaptureListingOptions): ParsedCaptureListingOptions;
|
|
49
51
|
export declare function assertSupportedListingEnvironment(platform?: NodeJS.Platform, macosVersion?: string): void;
|
|
50
52
|
export declare function resolveListingRecorderPath(baseDir?: string): string;
|