@playdrop/playdrop-cli 0.3.8-build.2 → 0.3.9
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 +5 -5
- package/dist/apps/build.js +45 -39
- package/dist/catalogue-utils.js +23 -18
- package/dist/catalogue.d.ts +0 -2
- package/dist/catalogue.js +54 -41
- package/dist/clientInfo.js +16 -2
- package/dist/commands/browse.js +66 -23
- package/dist/commands/capture.js +3 -2
- package/dist/commands/create.js +49 -46
- package/dist/commands/createRemixContent.js +29 -44
- package/dist/commands/creations.js +51 -13
- package/dist/commands/devServer.d.ts +1 -1
- package/dist/commands/devShared.js +1 -1
- package/dist/commands/generation.js +91 -74
- package/dist/commands/gettingStarted.js +1 -1
- package/dist/commands/search.js +29 -1
- package/dist/commands/upload-content.d.ts +70 -0
- package/dist/commands/upload-content.js +627 -0
- package/dist/commands/upload-graph.d.ts +23 -0
- package/dist/commands/upload-graph.js +108 -0
- package/dist/commands/upload.js +264 -543
- package/dist/http.d.ts +1 -1
- package/dist/playwright.d.ts +12 -4
- package/dist/proxyFetch.js +3 -2
- package/node_modules/@playdrop/ai-client/dist/index.d.ts.map +1 -1
- package/node_modules/@playdrop/ai-client/dist/index.js +74 -54
- package/node_modules/@playdrop/api-client/dist/client.d.ts +34 -14
- package/node_modules/@playdrop/api-client/dist/client.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/client.js +6 -8
- package/node_modules/@playdrop/api-client/dist/core/errors.js +11 -11
- package/node_modules/@playdrop/api-client/dist/core/request.d.ts +2 -0
- package/node_modules/@playdrop/api-client/dist/core/request.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/core/request.js +10 -3
- package/node_modules/@playdrop/api-client/dist/domains/admin.d.ts +12 -10
- package/node_modules/@playdrop/api-client/dist/domains/admin.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/admin.js +33 -30
- package/node_modules/@playdrop/api-client/dist/domains/apps.d.ts +8 -1
- package/node_modules/@playdrop/api-client/dist/domains/apps.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/apps.js +140 -124
- package/node_modules/@playdrop/api-client/dist/domains/asset-packs.d.ts +9 -5
- package/node_modules/@playdrop/api-client/dist/domains/asset-packs.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/asset-packs.js +151 -88
- package/node_modules/@playdrop/api-client/dist/domains/assets.d.ts +4 -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 +153 -112
- package/node_modules/@playdrop/api-client/dist/domains/auth.d.ts +3 -1
- package/node_modules/@playdrop/api-client/dist/domains/auth.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/auth.js +21 -0
- package/node_modules/@playdrop/api-client/dist/domains/me.d.ts +6 -2
- package/node_modules/@playdrop/api-client/dist/domains/me.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/me.js +13 -2
- package/node_modules/@playdrop/api-client/dist/domains/payments.d.ts +1 -0
- package/node_modules/@playdrop/api-client/dist/domains/payments.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/payments.js +10 -0
- package/node_modules/@playdrop/api-client/dist/index.d.ts +65 -24
- package/node_modules/@playdrop/api-client/dist/index.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/index.js +38 -13
- package/node_modules/@playdrop/boxel-core/dist/src/entity-cleaner.js +2 -0
- package/node_modules/@playdrop/boxel-core/dist/src/entity-cleaner.js.map +1 -1
- package/node_modules/@playdrop/boxel-core/dist/src/humanoid/r15/textured-builder.js +1 -1
- package/node_modules/@playdrop/boxel-core/dist/src/humanoid/r15/textured-builder.js.map +1 -1
- package/node_modules/@playdrop/boxel-core/dist/src/humanoid/r15/voxel-builder.js +1 -1
- package/node_modules/@playdrop/boxel-core/dist/src/humanoid/r15/voxel-builder.js.map +1 -1
- package/node_modules/@playdrop/boxel-core/dist/src/humanoid/r6/builder.js +95 -75
- package/node_modules/@playdrop/boxel-core/dist/src/humanoid/r6/builder.js.map +1 -1
- package/node_modules/@playdrop/boxel-core/dist/src/humanoid/r6/scanner.d.ts +2 -3
- package/node_modules/@playdrop/boxel-core/dist/src/humanoid/r6/scanner.js.map +1 -1
- package/node_modules/@playdrop/boxel-core/dist/src/humanoid/r6/textures/face-map.js +4 -4
- package/node_modules/@playdrop/boxel-core/dist/src/humanoid/r6/textures/face-map.js.map +1 -1
- package/node_modules/@playdrop/boxel-core/dist/src/palette_tools.d.ts +2 -2
- package/node_modules/@playdrop/boxel-core/dist/src/transforms/textured-boxes/slice.d.ts +5 -5
- package/node_modules/@playdrop/boxel-core/dist/src/transforms/voxels/textured-to-voxel.d.ts +3 -3
- package/node_modules/@playdrop/boxel-core/dist/src/types.d.ts +25 -25
- package/node_modules/@playdrop/boxel-core/dist/src/validation.js +2 -1
- package/node_modules/@playdrop/boxel-core/dist/src/validation.js.map +1 -1
- package/node_modules/@playdrop/boxel-three/dist/src/exporters/glb.js +5 -0
- package/node_modules/@playdrop/boxel-three/package.json +3 -3
- package/node_modules/@playdrop/config/client-meta.json +5 -5
- package/node_modules/@playdrop/config/dist/src/index.js +6 -6
- package/node_modules/@playdrop/config/dist/test/validateClientEnvironment.test.js +2 -2
- package/node_modules/@playdrop/config/dist/tsconfig.tsbuildinfo +1 -1
- package/node_modules/@playdrop/types/dist/api.d.ts +33 -8
- package/node_modules/@playdrop/types/dist/api.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/api.js +16 -8
- package/node_modules/@playdrop/types/dist/asset-pack.d.ts +107 -11
- package/node_modules/@playdrop/types/dist/asset-pack.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/asset-pack.js +2 -0
- package/node_modules/@playdrop/types/dist/asset.d.ts +15 -0
- package/node_modules/@playdrop/types/dist/asset.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/asset.js +1 -0
- package/node_modules/@playdrop/types/dist/ecs.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/ecs.js +10 -6
- package/node_modules/@playdrop/types/dist/entity.d.ts +5 -10
- package/node_modules/@playdrop/types/dist/entity.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/entity.js +40 -23
- package/node_modules/@playdrop/types/dist/graph.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/graph.js +13 -5
- package/node_modules/@playdrop/types/dist/version.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/version.js +7 -3
- package/node_modules/@playdrop/vox-three/dist/src/vox.d.ts +1 -0
- package/node_modules/@playdrop/vox-three/dist/src/vox.js +15 -6
- package/node_modules/@playdrop/vox-three/dist/src/vox.js.map +1 -1
- package/node_modules/@playdrop/vox-three/dist/test/vox.test.js +16 -0
- package/node_modules/@playdrop/vox-three/dist/test/vox.test.js.map +1 -1
- package/node_modules/@playdrop/vox-three/package.json +3 -3
- package/package.json +1 -1
|
@@ -13,6 +13,31 @@ const http_1 = require("../http");
|
|
|
13
13
|
const messages_1 = require("../messages");
|
|
14
14
|
const init_1 = require("./init");
|
|
15
15
|
const CATALOGUE_FILENAME = 'catalogue.json';
|
|
16
|
+
const MIME_TYPE_TO_EXTENSION = {
|
|
17
|
+
'image/png': '.png',
|
|
18
|
+
'image/jpeg': '.jpg',
|
|
19
|
+
'image/webp': '.webp',
|
|
20
|
+
'image/gif': '.gif',
|
|
21
|
+
'audio/mpeg': '.mp3',
|
|
22
|
+
'audio/wav': '.wav',
|
|
23
|
+
'audio/ogg': '.ogg',
|
|
24
|
+
'video/mp4': '.mp4',
|
|
25
|
+
'video/webm': '.webm',
|
|
26
|
+
'model/gltf+json': '.gltf',
|
|
27
|
+
'model/gltf-binary': '.glb',
|
|
28
|
+
'application/json': '.json',
|
|
29
|
+
};
|
|
30
|
+
function inferExtensionFromCandidate(candidate) {
|
|
31
|
+
try {
|
|
32
|
+
if (candidate.startsWith('http://') || candidate.startsWith('https://')) {
|
|
33
|
+
return (0, node_path_1.extname)(new URL(candidate).pathname);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return (0, node_path_1.extname)(candidate);
|
|
38
|
+
}
|
|
39
|
+
return (0, node_path_1.extname)(candidate);
|
|
40
|
+
}
|
|
16
41
|
async function ensureWorkspaceCataloguePath() {
|
|
17
42
|
const path = (0, node_path_1.resolve)(process.cwd(), CATALOGUE_FILENAME);
|
|
18
43
|
if ((0, node_fs_1.existsSync)(path) && (0, node_fs_1.statSync)(path).isFile()) {
|
|
@@ -100,53 +125,13 @@ function parseAssetManifestFiles(value) {
|
|
|
100
125
|
function inferExtensionFromManifestEntry(entry) {
|
|
101
126
|
const candidates = [entry.key, entry.url].filter((value) => typeof value === 'string' && value.length > 0);
|
|
102
127
|
for (const candidate of candidates) {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
if (extension) {
|
|
107
|
-
return extension;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
else {
|
|
111
|
-
const extension = (0, node_path_1.extname)(candidate);
|
|
112
|
-
if (extension) {
|
|
113
|
-
return extension;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
catch {
|
|
118
|
-
const extension = (0, node_path_1.extname)(candidate);
|
|
119
|
-
if (extension) {
|
|
120
|
-
return extension;
|
|
121
|
-
}
|
|
128
|
+
const extension = inferExtensionFromCandidate(candidate);
|
|
129
|
+
if (extension) {
|
|
130
|
+
return extension;
|
|
122
131
|
}
|
|
123
132
|
}
|
|
124
133
|
const mimeType = typeof entry.contentType === 'string' ? entry.contentType.trim().toLowerCase() : '';
|
|
125
|
-
|
|
126
|
-
return '.png';
|
|
127
|
-
if (mimeType === 'image/jpeg')
|
|
128
|
-
return '.jpg';
|
|
129
|
-
if (mimeType === 'image/webp')
|
|
130
|
-
return '.webp';
|
|
131
|
-
if (mimeType === 'image/gif')
|
|
132
|
-
return '.gif';
|
|
133
|
-
if (mimeType === 'audio/mpeg')
|
|
134
|
-
return '.mp3';
|
|
135
|
-
if (mimeType === 'audio/wav')
|
|
136
|
-
return '.wav';
|
|
137
|
-
if (mimeType === 'audio/ogg')
|
|
138
|
-
return '.ogg';
|
|
139
|
-
if (mimeType === 'video/mp4')
|
|
140
|
-
return '.mp4';
|
|
141
|
-
if (mimeType === 'video/webm')
|
|
142
|
-
return '.webm';
|
|
143
|
-
if (mimeType === 'model/gltf+json')
|
|
144
|
-
return '.gltf';
|
|
145
|
-
if (mimeType === 'model/gltf-binary')
|
|
146
|
-
return '.glb';
|
|
147
|
-
if (mimeType === 'application/json')
|
|
148
|
-
return '.json';
|
|
149
|
-
return '';
|
|
134
|
+
return MIME_TYPE_TO_EXTENSION[mimeType] ?? '';
|
|
150
135
|
}
|
|
151
136
|
function buildLocalFilename(entry, usedNames) {
|
|
152
137
|
const sourceName = typeof entry.key === 'string' && entry.key.length > 0
|
|
@@ -94,6 +94,34 @@ function parseVersion(raw, command) {
|
|
|
94
94
|
function kindLabel(kind) {
|
|
95
95
|
return kind === 'all' ? 'content' : kind === 'asset-pack' ? 'asset packs' : `${kind}s`;
|
|
96
96
|
}
|
|
97
|
+
function formatCountValue(value) {
|
|
98
|
+
return value.toLocaleString('en-US');
|
|
99
|
+
}
|
|
100
|
+
function buildCountsSuffix(item) {
|
|
101
|
+
const parts = [];
|
|
102
|
+
if (item.kind === 'app' && 'playCount' in item.item && typeof item.item.playCount === 'number') {
|
|
103
|
+
if (typeof item.item.viewCount === 'number') {
|
|
104
|
+
parts.push(`view ${formatCountValue(item.item.viewCount)}`);
|
|
105
|
+
}
|
|
106
|
+
parts.push(`launch ${formatCountValue(item.item.playCount)}`);
|
|
107
|
+
}
|
|
108
|
+
if (item.kind === 'asset' && 'playCount' in item.item && typeof item.item.playCount === 'number') {
|
|
109
|
+
if (typeof item.item.viewCount === 'number') {
|
|
110
|
+
parts.push(`view ${formatCountValue(item.item.viewCount)}`);
|
|
111
|
+
}
|
|
112
|
+
parts.push(`play ${formatCountValue(item.item.playCount)}`);
|
|
113
|
+
}
|
|
114
|
+
if (typeof item.item.likeCount === 'number') {
|
|
115
|
+
parts.push(`like ${formatCountValue(item.item.likeCount)}`);
|
|
116
|
+
}
|
|
117
|
+
if (typeof item.item.remixCount === 'number') {
|
|
118
|
+
parts.push(`remix ${formatCountValue(item.item.remixCount)}`);
|
|
119
|
+
}
|
|
120
|
+
if (typeof item.item.commentCount === 'number') {
|
|
121
|
+
parts.push(`comment ${formatCountValue(item.item.commentCount)}`);
|
|
122
|
+
}
|
|
123
|
+
return parts.length > 0 ? ` | ${parts.join(' | ')}` : '';
|
|
124
|
+
}
|
|
97
125
|
async function collectPaginatedItems(fetchPage) {
|
|
98
126
|
const items = [];
|
|
99
127
|
let offset = 0;
|
|
@@ -127,6 +155,12 @@ function sliceMergedItems(items, limit, offset) {
|
|
|
127
155
|
},
|
|
128
156
|
};
|
|
129
157
|
}
|
|
158
|
+
function requirePagination(pagination, context) {
|
|
159
|
+
if (!pagination) {
|
|
160
|
+
throw new Error(`missing_pagination:${context}`);
|
|
161
|
+
}
|
|
162
|
+
return pagination;
|
|
163
|
+
}
|
|
130
164
|
function parseManagedName(raw, command) {
|
|
131
165
|
try {
|
|
132
166
|
return (0, refs_1.parseScopedName)(raw ?? '', 'name');
|
|
@@ -179,12 +213,11 @@ async function browseCreations(options = {}) {
|
|
|
179
213
|
const items = [];
|
|
180
214
|
let pagination;
|
|
181
215
|
if (kind === 'app') {
|
|
182
|
-
const
|
|
183
|
-
?
|
|
184
|
-
:
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
pagination = sliced.pagination;
|
|
216
|
+
const response = !usingCurrentCreator
|
|
217
|
+
? await client.fetchAppsByCreator(creator, { limit, offset })
|
|
218
|
+
: await client.fetchMyApps({ limit, offset });
|
|
219
|
+
items.push(...(response.apps ?? []).map((item) => ({ kind: 'app', ref: `${item.creatorUsername}/app/${item.name}`, item })));
|
|
220
|
+
pagination = requirePagination(response.pagination, 'creations_browse_app');
|
|
188
221
|
}
|
|
189
222
|
else if (kind === 'asset') {
|
|
190
223
|
const response = await client.listAssetsForCreator(creator, { limit, offset });
|
|
@@ -198,9 +231,13 @@ async function browseCreations(options = {}) {
|
|
|
198
231
|
}
|
|
199
232
|
else {
|
|
200
233
|
const [appsResponse, assetsResponse, packsResponse] = await Promise.all([
|
|
201
|
-
!usingCurrentCreator
|
|
202
|
-
? client.fetchAppsByCreator(creator)
|
|
203
|
-
: client.fetchMyApps()
|
|
234
|
+
collectPaginatedItems((pageLimit, pageOffset) => (!usingCurrentCreator
|
|
235
|
+
? client.fetchAppsByCreator(creator, { limit: pageLimit, offset: pageOffset })
|
|
236
|
+
: client.fetchMyApps({ limit: pageLimit, offset: pageOffset }))
|
|
237
|
+
.then((response) => ({
|
|
238
|
+
items: response.apps ?? [],
|
|
239
|
+
pagination: requirePagination(response.pagination, 'creations_browse_all_apps'),
|
|
240
|
+
}))),
|
|
204
241
|
collectPaginatedItems((pageLimit, pageOffset) => client.listAssetsForCreator(creator, { limit: pageLimit, offset: pageOffset }).then((response) => ({
|
|
205
242
|
items: response.assets ?? [],
|
|
206
243
|
pagination: response.pagination,
|
|
@@ -211,7 +248,7 @@ async function browseCreations(options = {}) {
|
|
|
211
248
|
}))),
|
|
212
249
|
]);
|
|
213
250
|
const combined = [
|
|
214
|
-
...(
|
|
251
|
+
...(appsResponse.items.map((item) => ({ kind: 'app', ref: `${item.creatorUsername}/app/${item.name}`, item }))),
|
|
215
252
|
...(assetsResponse.items.map((item) => ({ kind: 'asset', ref: `${item.creatorUsername}/asset/${item.name}`, item }))),
|
|
216
253
|
...(packsResponse.items.map((item) => ({ kind: 'asset-pack', ref: `${item.creatorUsername}/asset-pack/${item.name}`, item }))),
|
|
217
254
|
];
|
|
@@ -238,7 +275,7 @@ async function browseCreations(options = {}) {
|
|
|
238
275
|
console.log(`Creations for @${creator}:\n`);
|
|
239
276
|
}
|
|
240
277
|
for (const [index, item] of items.entries()) {
|
|
241
|
-
console.log(`${index + 1}. [${item.kind}] ${item.ref} | ${item.item.displayName || item.item.name}`);
|
|
278
|
+
console.log(`${index + 1}. [${item.kind}] ${item.ref} | ${item.item.displayName || item.item.name}${buildCountsSuffix(item)}`);
|
|
242
279
|
}
|
|
243
280
|
console.log('\nNext: run "playdrop detail <creator>/<kind>/<name>" or a "playdrop creations ..." command to manage one item.');
|
|
244
281
|
}
|
|
@@ -260,12 +297,13 @@ async function updateCreationApp(nameArg, options = {}) {
|
|
|
260
297
|
if (!name) {
|
|
261
298
|
return;
|
|
262
299
|
}
|
|
263
|
-
const
|
|
264
|
-
if (options.type !== undefined && !
|
|
300
|
+
const parsedAppType = options.type ? (0, types_1.parseAppType)(options.type.trim().toUpperCase()) : undefined;
|
|
301
|
+
if (options.type !== undefined && !parsedAppType) {
|
|
265
302
|
(0, messages_1.printErrorWithHelp)('The --type value is invalid.', ['Use one of: game, demo, tool, template.'], { command: 'creations apps update' });
|
|
266
303
|
process.exitCode = 1;
|
|
267
304
|
return;
|
|
268
305
|
}
|
|
306
|
+
const appType = parsedAppType ?? undefined;
|
|
269
307
|
if (!options.displayName && !appType) {
|
|
270
308
|
(0, messages_1.printErrorWithHelp)('At least one update field is required.', ['Use --display-name and/or --type.'], { command: 'creations apps update' });
|
|
271
309
|
process.exitCode = 1;
|
|
@@ -63,7 +63,7 @@ async function assertAppRegistered(client, creatorUsername, appName) {
|
|
|
63
63
|
}
|
|
64
64
|
function findNearestCatalogue(startDir) {
|
|
65
65
|
let current = (0, node_path_1.resolve)(startDir);
|
|
66
|
-
while (true) {
|
|
66
|
+
while (true) {
|
|
67
67
|
const candidate = (0, node_path_1.join)(current, 'catalogue.json');
|
|
68
68
|
if ((0, node_fs_1.existsSync)(candidate)) {
|
|
69
69
|
return candidate;
|
|
@@ -36,6 +36,95 @@ const LOCAL_IMAGE_MIME_BY_EXTENSION = {
|
|
|
36
36
|
'.jpeg': 'image/jpeg',
|
|
37
37
|
'.webp': 'image/webp',
|
|
38
38
|
};
|
|
39
|
+
function handleGenerateBuildRequestError(message) {
|
|
40
|
+
const errorByCode = {
|
|
41
|
+
missing_type: {
|
|
42
|
+
title: 'A generation type is required.',
|
|
43
|
+
details: ['Use one of: image, music, sfx, video, model_3d.'],
|
|
44
|
+
},
|
|
45
|
+
missing_prompt: {
|
|
46
|
+
title: 'A prompt is required.',
|
|
47
|
+
details: ['Example: playdrop ai create image "A pixel art hero portrait"'],
|
|
48
|
+
},
|
|
49
|
+
invalid_type: {
|
|
50
|
+
title: 'The generation type is invalid.',
|
|
51
|
+
details: ['Use one of: image, music, sfx, video, model_3d.'],
|
|
52
|
+
},
|
|
53
|
+
invalid_duration: {
|
|
54
|
+
title: 'The --duration value is invalid.',
|
|
55
|
+
details: ['Use a positive value like 20000, 20s, or 20000ms.'],
|
|
56
|
+
},
|
|
57
|
+
invalid_video_duration: {
|
|
58
|
+
title: 'The --duration value for video is invalid.',
|
|
59
|
+
details: ['Use 4s or 8s for video generation.'],
|
|
60
|
+
},
|
|
61
|
+
invalid_aspect_ratio: {
|
|
62
|
+
title: 'The --ratio value is invalid.',
|
|
63
|
+
details: ['Image: 1:1, 3:4, 9:16, 4:3, 16:9. Video: 16:9, 9:16.'],
|
|
64
|
+
},
|
|
65
|
+
missing_model3d_images: {
|
|
66
|
+
title: 'Model 3D IMAGE source mode requires at least one reference image.',
|
|
67
|
+
details: ['Provide --image1 <url> or --image2 <url>, or switch to --source-mode TEXT.'],
|
|
68
|
+
},
|
|
69
|
+
model3d_text_mode_disallows_images: {
|
|
70
|
+
title: 'Model 3D TEXT source mode cannot include reference images.',
|
|
71
|
+
details: ['Remove --image1/--image2 or switch to --source-mode IMAGE.'],
|
|
72
|
+
},
|
|
73
|
+
invalid_asset_subcategory: {
|
|
74
|
+
title: 'The --subcategory value is invalid.',
|
|
75
|
+
details: ['Use a lowercase slug such as generic, music, sfx, or avatar.'],
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
const entry = errorByCode[message];
|
|
79
|
+
if (!entry) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
(0, messages_1.printErrorWithHelp)(entry.title, entry.details, { command: 'ai create' });
|
|
83
|
+
process.exitCode = 1;
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
function handleGenerateImageReferenceError(message) {
|
|
87
|
+
const imageRefHandlers = [
|
|
88
|
+
{
|
|
89
|
+
prefix: 'image_ref_not_found:',
|
|
90
|
+
title: (optionName) => `The ${optionName || 'image'} reference file was not found.`,
|
|
91
|
+
details: (path) => [path ? `Missing file: ${path}` : 'Provide a valid local file path or HTTPS URL.'],
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
prefix: 'image_ref_not_file:',
|
|
95
|
+
title: (optionName) => `The ${optionName || 'image'} reference is not a file.`,
|
|
96
|
+
details: (path) => [path ? `Path must point to a file: ${path}` : 'Provide a valid local file path.'],
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
prefix: 'image_ref_invalid_scheme:',
|
|
100
|
+
title: (optionName) => `The ${optionName || 'image'} reference URL uses an unsupported scheme.`,
|
|
101
|
+
details: (scheme) => [`Use an HTTPS URL or a local file path. Received: ${scheme || 'unknown'}`],
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
prefix: 'image_ref_signature_mismatch:',
|
|
105
|
+
title: (optionName) => `The ${optionName || 'image'} reference file extension does not match its image signature.`,
|
|
106
|
+
details: (path) => [path ? `Fix file type mismatch for: ${path}` : 'Ensure extension and file signature match (.png, .jpg, .jpeg, .webp).'],
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
prefix: 'image_ref_unsupported_type:',
|
|
110
|
+
title: (optionName) => `The ${optionName || 'image'} reference file type is unsupported.`,
|
|
111
|
+
details: (path) => [
|
|
112
|
+
path ? `Unsupported file: ${path}` : 'Provide a supported local file.',
|
|
113
|
+
'Supported local image types: .png, .jpg, .jpeg, .webp.',
|
|
114
|
+
],
|
|
115
|
+
},
|
|
116
|
+
];
|
|
117
|
+
for (const handler of imageRefHandlers) {
|
|
118
|
+
if (!message.startsWith(handler.prefix)) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
const [, optionName, value] = message.split(':');
|
|
122
|
+
(0, messages_1.printErrorWithHelp)(handler.title(optionName), handler.details(value), { command: 'ai create' });
|
|
123
|
+
process.exitCode = 1;
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
39
128
|
function sleep(ms) {
|
|
40
129
|
return new Promise((resolve) => {
|
|
41
130
|
setTimeout(resolve, ms);
|
|
@@ -442,82 +531,10 @@ async function generate(typeInput, promptInput, options = {}) {
|
|
|
442
531
|
}
|
|
443
532
|
catch (error) {
|
|
444
533
|
const message = typeof error?.message === 'string' ? error.message : 'invalid_input';
|
|
445
|
-
if (message
|
|
446
|
-
(0, messages_1.printErrorWithHelp)('A generation type is required.', ['Use one of: image, music, sfx, video, model_3d.'], { command: 'ai create' });
|
|
447
|
-
process.exitCode = 1;
|
|
448
|
-
return;
|
|
449
|
-
}
|
|
450
|
-
if (message === 'missing_prompt') {
|
|
451
|
-
(0, messages_1.printErrorWithHelp)('A prompt is required.', ['Example: playdrop ai create image "A pixel art hero portrait"'], { command: 'ai create' });
|
|
452
|
-
process.exitCode = 1;
|
|
453
|
-
return;
|
|
454
|
-
}
|
|
455
|
-
if (message === 'invalid_type') {
|
|
456
|
-
(0, messages_1.printErrorWithHelp)('The generation type is invalid.', ['Use one of: image, music, sfx, video, model_3d.'], { command: 'ai create' });
|
|
457
|
-
process.exitCode = 1;
|
|
534
|
+
if (handleGenerateBuildRequestError(message)) {
|
|
458
535
|
return;
|
|
459
536
|
}
|
|
460
|
-
if (message
|
|
461
|
-
(0, messages_1.printErrorWithHelp)('The --duration value is invalid.', ['Use a positive value like 20000, 20s, or 20000ms.'], { command: 'ai create' });
|
|
462
|
-
process.exitCode = 1;
|
|
463
|
-
return;
|
|
464
|
-
}
|
|
465
|
-
if (message === 'invalid_video_duration') {
|
|
466
|
-
(0, messages_1.printErrorWithHelp)('The --duration value for video is invalid.', ['Use 4s or 8s for video generation.'], { command: 'ai create' });
|
|
467
|
-
process.exitCode = 1;
|
|
468
|
-
return;
|
|
469
|
-
}
|
|
470
|
-
if (message === 'invalid_aspect_ratio') {
|
|
471
|
-
(0, messages_1.printErrorWithHelp)('The --ratio value is invalid.', ['Image: 1:1, 3:4, 9:16, 4:3, 16:9. Video: 16:9, 9:16.'], { command: 'ai create' });
|
|
472
|
-
process.exitCode = 1;
|
|
473
|
-
return;
|
|
474
|
-
}
|
|
475
|
-
if (message === 'missing_model3d_images') {
|
|
476
|
-
(0, messages_1.printErrorWithHelp)('Model 3D IMAGE source mode requires at least one reference image.', ['Provide --image1 <url> or --image2 <url>, or switch to --source-mode TEXT.'], { command: 'ai create' });
|
|
477
|
-
process.exitCode = 1;
|
|
478
|
-
return;
|
|
479
|
-
}
|
|
480
|
-
if (message === 'model3d_text_mode_disallows_images') {
|
|
481
|
-
(0, messages_1.printErrorWithHelp)('Model 3D TEXT source mode cannot include reference images.', ['Remove --image1/--image2 or switch to --source-mode IMAGE.'], { command: 'ai create' });
|
|
482
|
-
process.exitCode = 1;
|
|
483
|
-
return;
|
|
484
|
-
}
|
|
485
|
-
if (message === 'invalid_asset_subcategory') {
|
|
486
|
-
(0, messages_1.printErrorWithHelp)('The --subcategory value is invalid.', ['Use a lowercase slug such as generic, music, sfx, or avatar.'], { command: 'ai create' });
|
|
487
|
-
process.exitCode = 1;
|
|
488
|
-
return;
|
|
489
|
-
}
|
|
490
|
-
if (message.startsWith('image_ref_not_found:')) {
|
|
491
|
-
const [, optionName, path] = message.split(':');
|
|
492
|
-
(0, messages_1.printErrorWithHelp)(`The ${optionName || 'image'} reference file was not found.`, [path ? `Missing file: ${path}` : 'Provide a valid local file path or HTTPS URL.'], { command: 'ai create' });
|
|
493
|
-
process.exitCode = 1;
|
|
494
|
-
return;
|
|
495
|
-
}
|
|
496
|
-
if (message.startsWith('image_ref_not_file:')) {
|
|
497
|
-
const [, optionName, path] = message.split(':');
|
|
498
|
-
(0, messages_1.printErrorWithHelp)(`The ${optionName || 'image'} reference is not a file.`, [path ? `Path must point to a file: ${path}` : 'Provide a valid local file path.'], { command: 'ai create' });
|
|
499
|
-
process.exitCode = 1;
|
|
500
|
-
return;
|
|
501
|
-
}
|
|
502
|
-
if (message.startsWith('image_ref_invalid_scheme:')) {
|
|
503
|
-
const [, optionName, scheme] = message.split(':');
|
|
504
|
-
(0, messages_1.printErrorWithHelp)(`The ${optionName || 'image'} reference URL uses an unsupported scheme.`, [`Use an HTTPS URL or a local file path. Received: ${scheme || 'unknown'}`], { command: 'ai create' });
|
|
505
|
-
process.exitCode = 1;
|
|
506
|
-
return;
|
|
507
|
-
}
|
|
508
|
-
if (message.startsWith('image_ref_signature_mismatch:')) {
|
|
509
|
-
const [, optionName, path] = message.split(':');
|
|
510
|
-
(0, messages_1.printErrorWithHelp)(`The ${optionName || 'image'} reference file extension does not match its image signature.`, [path ? `Fix file type mismatch for: ${path}` : 'Ensure extension and file signature match (.png, .jpg, .jpeg, .webp).'], { command: 'ai create' });
|
|
511
|
-
process.exitCode = 1;
|
|
512
|
-
return;
|
|
513
|
-
}
|
|
514
|
-
if (message.startsWith('image_ref_unsupported_type:')) {
|
|
515
|
-
const [, optionName, path] = message.split(':');
|
|
516
|
-
(0, messages_1.printErrorWithHelp)(`The ${optionName || 'image'} reference file type is unsupported.`, [
|
|
517
|
-
path ? `Unsupported file: ${path}` : 'Provide a supported local file.',
|
|
518
|
-
'Supported local image types: .png, .jpg, .jpeg, .webp.',
|
|
519
|
-
], { command: 'ai create' });
|
|
520
|
-
process.exitCode = 1;
|
|
537
|
+
if (handleGenerateImageReferenceError(message)) {
|
|
521
538
|
return;
|
|
522
539
|
}
|
|
523
540
|
(0, messages_1.printErrorWithHelp)(`Invalid AI create input: ${message}.`, ['Run "playdrop help ai create" for valid options.'], {
|
|
@@ -10,7 +10,7 @@ function printGettingStarted() {
|
|
|
10
10
|
console.log(' playdrop project init .');
|
|
11
11
|
console.log('');
|
|
12
12
|
console.log('3. Create an app');
|
|
13
|
-
console.log(' playdrop project create app my-app --template playdrop/template/
|
|
13
|
+
console.log(' playdrop project create app my-app --template playdrop/template/typescript_template');
|
|
14
14
|
console.log('');
|
|
15
15
|
console.log('4. Preview locally');
|
|
16
16
|
console.log(' playdrop project dev my-app');
|
package/dist/commands/search.js
CHANGED
|
@@ -87,6 +87,34 @@ function itemSummary(item) {
|
|
|
87
87
|
}
|
|
88
88
|
return 'asset-pack';
|
|
89
89
|
}
|
|
90
|
+
function formatCountValue(value) {
|
|
91
|
+
return value.toLocaleString('en-US');
|
|
92
|
+
}
|
|
93
|
+
function buildCountsSuffix(item) {
|
|
94
|
+
const parts = [];
|
|
95
|
+
if (item.kind === 'app' && typeof item.item.playCount === 'number') {
|
|
96
|
+
if (typeof item.item.viewCount === 'number') {
|
|
97
|
+
parts.push(`view ${formatCountValue(item.item.viewCount)}`);
|
|
98
|
+
}
|
|
99
|
+
parts.push(`launch ${formatCountValue(item.item.playCount)}`);
|
|
100
|
+
}
|
|
101
|
+
if (item.kind === 'asset' && typeof item.item.playCount === 'number') {
|
|
102
|
+
if (typeof item.item.viewCount === 'number') {
|
|
103
|
+
parts.push(`view ${formatCountValue(item.item.viewCount)}`);
|
|
104
|
+
}
|
|
105
|
+
parts.push(`play ${formatCountValue(item.item.playCount)}`);
|
|
106
|
+
}
|
|
107
|
+
if (typeof item.item.likeCount === 'number') {
|
|
108
|
+
parts.push(`like ${formatCountValue(item.item.likeCount)}`);
|
|
109
|
+
}
|
|
110
|
+
if (typeof item.item.remixCount === 'number') {
|
|
111
|
+
parts.push(`remix ${formatCountValue(item.item.remixCount)}`);
|
|
112
|
+
}
|
|
113
|
+
if (typeof item.item.commentCount === 'number') {
|
|
114
|
+
parts.push(`comment ${formatCountValue(item.item.commentCount)}`);
|
|
115
|
+
}
|
|
116
|
+
return parts.length > 0 ? ` | ${parts.join(' | ')}` : '';
|
|
117
|
+
}
|
|
90
118
|
async function search(query, options = {}) {
|
|
91
119
|
const trimmedQuery = typeof query === 'string' ? query.trim() : '';
|
|
92
120
|
if (!trimmedQuery) {
|
|
@@ -179,7 +207,7 @@ async function search(query, options = {}) {
|
|
|
179
207
|
console.log(`Search results for "${trimmedQuery}":\n`);
|
|
180
208
|
for (const [index, item] of items.entries()) {
|
|
181
209
|
const displayName = item.item.displayName || item.item.name;
|
|
182
|
-
console.log(`${index + 1}. [${item.kind}] ${item.ref} | ${displayName} | @${item.item.creatorUsername} | ${itemSummary(item)}`);
|
|
210
|
+
console.log(`${index + 1}. [${item.kind}] ${item.ref} | ${displayName} | @${item.item.creatorUsername} | ${itemSummary(item)}${buildCountsSuffix(item)}`);
|
|
183
211
|
}
|
|
184
212
|
console.log('\nNext: run "playdrop detail <creator>/<kind>/<name>" to inspect one result.');
|
|
185
213
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { ApiClient } from '@playdrop/api-client';
|
|
2
|
+
import { type AssetPackUploadedLocalAsset } from '@playdrop/types';
|
|
3
|
+
import type { AssetPackTask, AssetTask, EmbeddedAssetTask } from '../catalogue';
|
|
4
|
+
import type { CliTask } from '../taskUtils';
|
|
5
|
+
export type CurrentUserRole = 'USER' | 'CREATOR' | 'ADMIN' | null;
|
|
6
|
+
export type UploadedAssetInfo = {
|
|
7
|
+
creatorUsername: string;
|
|
8
|
+
name: string;
|
|
9
|
+
revision: number;
|
|
10
|
+
ref: string;
|
|
11
|
+
versionNodeId: string;
|
|
12
|
+
};
|
|
13
|
+
export type UploadedAppInfo = {
|
|
14
|
+
creatorUsername: string;
|
|
15
|
+
name: string;
|
|
16
|
+
version: string;
|
|
17
|
+
versionId: number;
|
|
18
|
+
versionNodeId: string;
|
|
19
|
+
ref: string;
|
|
20
|
+
};
|
|
21
|
+
export type UploadedPackInfo = {
|
|
22
|
+
creatorUsername: string;
|
|
23
|
+
name: string;
|
|
24
|
+
version: string;
|
|
25
|
+
versionNodeId: string;
|
|
26
|
+
ref: string;
|
|
27
|
+
assetRefs: string[];
|
|
28
|
+
uploadedLocalAssets: AssetPackUploadedLocalAsset[];
|
|
29
|
+
};
|
|
30
|
+
export type PreparedUploadFile = {
|
|
31
|
+
fieldName: string;
|
|
32
|
+
filename: string;
|
|
33
|
+
filePath: string;
|
|
34
|
+
file: File;
|
|
35
|
+
contentType: string;
|
|
36
|
+
sizeBytes: number;
|
|
37
|
+
sha256: string;
|
|
38
|
+
};
|
|
39
|
+
export type PackUploadPlan = {
|
|
40
|
+
packKey: string;
|
|
41
|
+
packTask: AssetPackTask;
|
|
42
|
+
packCreator: string;
|
|
43
|
+
ownedAssetKeys: string[];
|
|
44
|
+
uploadKeyByAssetKey: Map<string, string>;
|
|
45
|
+
};
|
|
46
|
+
export type PackUploadPlanningResult = {
|
|
47
|
+
ok: true;
|
|
48
|
+
packPlansByKey: Map<string, PackUploadPlan>;
|
|
49
|
+
ownedPackByAssetKey: Map<string, PackUploadPlan>;
|
|
50
|
+
} | {
|
|
51
|
+
ok: false;
|
|
52
|
+
task: CliTask;
|
|
53
|
+
message: string;
|
|
54
|
+
};
|
|
55
|
+
type TaskCreatorResult = {
|
|
56
|
+
requestedTaskOwner: string;
|
|
57
|
+
taskCreator: string;
|
|
58
|
+
creatorTargetError: string | null;
|
|
59
|
+
};
|
|
60
|
+
export declare function buildAssetKey(creatorUsername: string, name: string): string;
|
|
61
|
+
export declare function buildPackKey(creatorUsername: string, name: string, version: string): string;
|
|
62
|
+
export declare function getTaskCreatorResult(task: CliTask, defaultCreator: string, currentUserRole: CurrentUserRole): TaskCreatorResult;
|
|
63
|
+
export declare function parseUnversionedAssetTaskRef(rawRef: string, fallbackCreator: string): {
|
|
64
|
+
creatorUsername: string;
|
|
65
|
+
name: string;
|
|
66
|
+
} | null;
|
|
67
|
+
export declare function buildAssetPackUploadPlans(tasks: CliTask[], defaultCreator: string, currentUserRole: CurrentUserRole): PackUploadPlanningResult;
|
|
68
|
+
export declare function uploadAssetTask(client: ApiClient, task: AssetTask | EmbeddedAssetTask, sourceAppVersionId?: number, creatorUsername?: string): Promise<UploadedAssetInfo>;
|
|
69
|
+
export declare function uploadAssetPackTask(client: ApiClient, task: AssetPackTask, creatorUsername: string, uploadedAssets: Map<string, UploadedAssetInfo>, localAssetTasks: AssetTask[], uploadKeyByAssetKey: Map<string, string>, targetCreatorUsername?: string): Promise<UploadedPackInfo>;
|
|
70
|
+
export {};
|