@playdrop/playdrop-cli 0.3.8-build.3 → 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 +43 -38
- 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 +10 -1
- 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 +10 -1
- 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 +10 -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 +20 -12
- 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 +1 -0
- package/node_modules/@playdrop/api-client/dist/domains/apps.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/apps.js +127 -128
- 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 +1 -0
- package/node_modules/@playdrop/api-client/dist/domains/assets.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/assets.js +150 -115
- 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/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 +34 -31
- package/node_modules/@playdrop/api-client/dist/index.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/index.js +19 -9
- 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/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 +27 -7
- package/node_modules/@playdrop/types/dist/api.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/api.js +15 -8
- package/node_modules/@playdrop/types/dist/asset-pack.d.ts +105 -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/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/package.json +1 -1
package/config/client-meta.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.3.
|
|
2
|
+
"version": "0.3.9",
|
|
3
3
|
"build": 1,
|
|
4
4
|
"platforms": {
|
|
5
5
|
"ios": {
|
|
@@ -26,19 +26,19 @@
|
|
|
26
26
|
},
|
|
27
27
|
"clients": {
|
|
28
28
|
"web": {
|
|
29
|
-
"minimumVersion": "0.3.
|
|
29
|
+
"minimumVersion": "0.3.9",
|
|
30
30
|
"minimumBuild": 1
|
|
31
31
|
},
|
|
32
32
|
"admin": {
|
|
33
|
-
"minimumVersion": "0.3.
|
|
33
|
+
"minimumVersion": "0.3.9",
|
|
34
34
|
"minimumBuild": 1
|
|
35
35
|
},
|
|
36
36
|
"apple": {
|
|
37
|
-
"minimumVersion": "0.3.
|
|
37
|
+
"minimumVersion": "0.3.9",
|
|
38
38
|
"minimumBuild": 1
|
|
39
39
|
},
|
|
40
40
|
"cli": {
|
|
41
|
-
"minimumVersion": "0.3.
|
|
41
|
+
"minimumVersion": "0.3.9",
|
|
42
42
|
"minimumBuild": 1
|
|
43
43
|
}
|
|
44
44
|
}
|
package/dist/apps/build.js
CHANGED
|
@@ -182,6 +182,47 @@ function isPathWithinRoot(rootDir, targetPath) {
|
|
|
182
182
|
const rootPrefix = normalizedRoot.endsWith(node_path_1.sep) ? normalizedRoot : `${normalizedRoot}${node_path_1.sep}`;
|
|
183
183
|
return normalizedTarget.startsWith(rootPrefix);
|
|
184
184
|
}
|
|
185
|
+
function readProjectDirEntries(current) {
|
|
186
|
+
try {
|
|
187
|
+
return (0, node_fs_1.readdirSync)(current, { withFileTypes: true });
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
return [];
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function appendIncludedProjectFile(rootDir, includePath, fileByRelativePath, results, enforceReservedBundleNames) {
|
|
194
|
+
const normalizedIncludePath = (0, node_path_1.normalize)(includePath).split(node_path_1.sep).join('/');
|
|
195
|
+
if (!normalizedIncludePath || normalizedIncludePath === '.') {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
if (normalizedIncludePath.startsWith('..')) {
|
|
199
|
+
throw new Error(`[apps][build] Invalid include file path "${includePath}".`);
|
|
200
|
+
}
|
|
201
|
+
if (fileByRelativePath.has(normalizedIncludePath)) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const absolutePath = (0, node_path_1.resolve)(rootDir, normalizedIncludePath);
|
|
205
|
+
if (!isPathWithinRoot(rootDir, absolutePath)) {
|
|
206
|
+
throw new Error(`[apps][build] Included file "${includePath}" escapes the project root.`);
|
|
207
|
+
}
|
|
208
|
+
if (!(0, node_fs_1.existsSync)(absolutePath)) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
const stats = (0, node_fs_1.statSync)(absolutePath);
|
|
212
|
+
if (!stats.isFile()) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
if (enforceReservedBundleNames && isReservedBundlePath(normalizedIncludePath)) {
|
|
216
|
+
throw new Error(`[apps][build] Reserved bundle filename "${normalizedIncludePath}" is not allowed. Use dedicated source/ecs/server upload fields.`);
|
|
217
|
+
}
|
|
218
|
+
const record = {
|
|
219
|
+
absolutePath,
|
|
220
|
+
relativePath: normalizedIncludePath,
|
|
221
|
+
mtime: stats.mtime,
|
|
222
|
+
};
|
|
223
|
+
results.push(record);
|
|
224
|
+
fileByRelativePath.set(record.relativePath, record);
|
|
225
|
+
}
|
|
185
226
|
function collectProjectFiles(rootDir, rules, options) {
|
|
186
227
|
const includeRelativeFiles = options?.includeRelativeFiles ?? [];
|
|
187
228
|
const enforceReservedBundleNames = options?.enforceReservedBundleNames ?? false;
|
|
@@ -194,13 +235,7 @@ function collectProjectFiles(rootDir, rules, options) {
|
|
|
194
235
|
if (visited.has(current))
|
|
195
236
|
continue;
|
|
196
237
|
visited.add(current);
|
|
197
|
-
|
|
198
|
-
try {
|
|
199
|
-
dirEntries = (0, node_fs_1.readdirSync)(current, { withFileTypes: true });
|
|
200
|
-
}
|
|
201
|
-
catch {
|
|
202
|
-
continue;
|
|
203
|
-
}
|
|
238
|
+
const dirEntries = readProjectDirEntries(current);
|
|
204
239
|
for (const entry of dirEntries) {
|
|
205
240
|
const absolutePath = (0, node_path_1.join)(current, entry.name);
|
|
206
241
|
const relativePath = normalizeRelativePath(rootDir, absolutePath);
|
|
@@ -238,37 +273,7 @@ function collectProjectFiles(rootDir, rules, options) {
|
|
|
238
273
|
}
|
|
239
274
|
}
|
|
240
275
|
for (const includePath of includeRelativeFiles) {
|
|
241
|
-
|
|
242
|
-
if (!normalizedIncludePath || normalizedIncludePath === '.') {
|
|
243
|
-
continue;
|
|
244
|
-
}
|
|
245
|
-
if (normalizedIncludePath.startsWith('..')) {
|
|
246
|
-
throw new Error(`[apps][build] Invalid include file path "${includePath}".`);
|
|
247
|
-
}
|
|
248
|
-
if (fileByRelativePath.has(normalizedIncludePath)) {
|
|
249
|
-
continue;
|
|
250
|
-
}
|
|
251
|
-
const absolutePath = (0, node_path_1.resolve)(rootDir, normalizedIncludePath);
|
|
252
|
-
if (!isPathWithinRoot(rootDir, absolutePath)) {
|
|
253
|
-
throw new Error(`[apps][build] Included file "${includePath}" escapes the project root.`);
|
|
254
|
-
}
|
|
255
|
-
if (!(0, node_fs_1.existsSync)(absolutePath)) {
|
|
256
|
-
continue;
|
|
257
|
-
}
|
|
258
|
-
const stats = (0, node_fs_1.statSync)(absolutePath);
|
|
259
|
-
if (!stats.isFile()) {
|
|
260
|
-
continue;
|
|
261
|
-
}
|
|
262
|
-
if (enforceReservedBundleNames && isReservedBundlePath(normalizedIncludePath)) {
|
|
263
|
-
throw new Error(`[apps][build] Reserved bundle filename "${normalizedIncludePath}" is not allowed. Use dedicated source/ecs/server upload fields.`);
|
|
264
|
-
}
|
|
265
|
-
const record = {
|
|
266
|
-
absolutePath,
|
|
267
|
-
relativePath: normalizedIncludePath,
|
|
268
|
-
mtime: stats.mtime,
|
|
269
|
-
};
|
|
270
|
-
results.push(record);
|
|
271
|
-
fileByRelativePath.set(record.relativePath, record);
|
|
276
|
+
appendIncludedProjectFile(rootDir, includePath, fileByRelativePath, results, enforceReservedBundleNames);
|
|
272
277
|
}
|
|
273
278
|
results.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
|
|
274
279
|
return results;
|
package/dist/catalogue-utils.js
CHANGED
|
@@ -42,6 +42,27 @@ function parseSurfaceTargets(input) {
|
|
|
42
42
|
return { map, list };
|
|
43
43
|
}
|
|
44
44
|
const DEFAULT_SURFACE_TARGETS_OBJECT = { desktop: true, mobileLandscape: false, mobilePortrait: false };
|
|
45
|
+
function parseCatalogueEntries(cataloguePath) {
|
|
46
|
+
try {
|
|
47
|
+
const raw = (0, node_fs_1.readFileSync)(cataloguePath, 'utf8');
|
|
48
|
+
const data = raw.trim() ? JSON.parse(raw) : {};
|
|
49
|
+
const entries = Array.isArray(data) ? data : data?.apps;
|
|
50
|
+
return Array.isArray(entries)
|
|
51
|
+
? entries.filter((entry) => Boolean(entry && typeof entry === 'object'))
|
|
52
|
+
: [];
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
throw new Error(`Failed to parse ${cataloguePath}. Fix the JSON and retry.`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function findMatchingCatalogueEntries(apps, relativePath, fileName) {
|
|
59
|
+
return apps.filter((entry) => {
|
|
60
|
+
const entryName = typeof entry.name === 'string' ? entry.name.trim() : '';
|
|
61
|
+
const entryFile = typeof entry.file === 'string' ? entry.file.trim() : `${entryName}.html`;
|
|
62
|
+
const normalized = entryFile.replace(/\\/g, '/');
|
|
63
|
+
return normalized === relativePath || normalized === fileName;
|
|
64
|
+
});
|
|
65
|
+
}
|
|
45
66
|
function cloneSurfaceTargets(targets) {
|
|
46
67
|
return {
|
|
47
68
|
list: [...targets.list],
|
|
@@ -54,25 +75,9 @@ function findAppCatalogueInfo(htmlPath) {
|
|
|
54
75
|
for (let dir = (0, node_path_1.dirname)(absolute);; dir = (0, node_path_1.dirname)(dir)) {
|
|
55
76
|
const cataloguePath = (0, node_path_1.join)(dir, 'catalogue.json');
|
|
56
77
|
if ((0, node_fs_1.existsSync)(cataloguePath) && (0, node_fs_1.statSync)(cataloguePath).isFile()) {
|
|
57
|
-
let entries;
|
|
58
|
-
try {
|
|
59
|
-
const raw = (0, node_fs_1.readFileSync)(cataloguePath, 'utf8');
|
|
60
|
-
const data = raw.trim() ? JSON.parse(raw) : {};
|
|
61
|
-
entries = Array.isArray(data) ? data : data?.apps;
|
|
62
|
-
}
|
|
63
|
-
catch {
|
|
64
|
-
throw new Error(`Failed to parse ${cataloguePath}. Fix the JSON and retry.`);
|
|
65
|
-
}
|
|
66
|
-
const apps = Array.isArray(entries) ? entries : [];
|
|
67
78
|
const rel = (0, node_path_1.relative)(dir, absolute).replace(/\\/g, '/');
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
return false;
|
|
71
|
-
const entryName = typeof entry.name === 'string' ? entry.name.trim() : '';
|
|
72
|
-
const entryFile = typeof entry.file === 'string' ? entry.file.trim() : `${entryName}.html`;
|
|
73
|
-
const normalized = entryFile.replace(/\\/g, '/');
|
|
74
|
-
return normalized === rel || normalized === fileName;
|
|
75
|
-
});
|
|
79
|
+
const apps = parseCatalogueEntries(cataloguePath);
|
|
80
|
+
const matches = findMatchingCatalogueEntries(apps, rel, fileName);
|
|
76
81
|
if (matches.length > 1) {
|
|
77
82
|
throw new Error(`Multiple entries in ${cataloguePath} reference ${absolute}.`);
|
|
78
83
|
}
|
package/dist/catalogue.d.ts
CHANGED
|
@@ -85,7 +85,6 @@ export type AssetPackCatalogueEntry = {
|
|
|
85
85
|
hostingMode?: string;
|
|
86
86
|
externalUrl?: string;
|
|
87
87
|
downloadUrl?: string;
|
|
88
|
-
previewApp?: string;
|
|
89
88
|
visibility?: string;
|
|
90
89
|
releaseNotes?: string;
|
|
91
90
|
listing?: AppListingConfig;
|
|
@@ -200,7 +199,6 @@ export type AssetPackTask = {
|
|
|
200
199
|
hostingMode?: AppHostingMode;
|
|
201
200
|
externalUrl?: string;
|
|
202
201
|
downloadUrl?: string;
|
|
203
|
-
previewApp?: string;
|
|
204
202
|
visibility?: string;
|
|
205
203
|
releaseNotes?: string;
|
|
206
204
|
listing?: ResolvedListingAssets;
|
package/dist/catalogue.js
CHANGED
|
@@ -396,6 +396,48 @@ function normalizeAssetSubcategoryValue(raw, category, errors, label) {
|
|
|
396
396
|
}
|
|
397
397
|
return normalized;
|
|
398
398
|
}
|
|
399
|
+
function validateOptionalEmoji(value, hasEmojiField, errors) {
|
|
400
|
+
const emoji = value;
|
|
401
|
+
if (!hasEmojiField) {
|
|
402
|
+
return emoji;
|
|
403
|
+
}
|
|
404
|
+
if (emoji !== null && typeof emoji === 'string') {
|
|
405
|
+
const trimmed = emoji.trim();
|
|
406
|
+
if (!trimmed) {
|
|
407
|
+
return null;
|
|
408
|
+
}
|
|
409
|
+
if (Array.from(trimmed).length > 4) {
|
|
410
|
+
errors.push('emoji must be a single character');
|
|
411
|
+
return emoji;
|
|
412
|
+
}
|
|
413
|
+
return trimmed;
|
|
414
|
+
}
|
|
415
|
+
if (emoji !== null) {
|
|
416
|
+
errors.push('emoji must be a string or null');
|
|
417
|
+
}
|
|
418
|
+
return emoji;
|
|
419
|
+
}
|
|
420
|
+
function validateOptionalColor(value, hasColorField, errors) {
|
|
421
|
+
const color = value;
|
|
422
|
+
if (!hasColorField) {
|
|
423
|
+
return color;
|
|
424
|
+
}
|
|
425
|
+
if (color !== null && typeof color === 'string') {
|
|
426
|
+
const trimmed = color.trim();
|
|
427
|
+
if (!trimmed) {
|
|
428
|
+
return null;
|
|
429
|
+
}
|
|
430
|
+
if (!HEX_COLOR_REGEX.test(trimmed)) {
|
|
431
|
+
errors.push('color must be a hex RGB value like #FFAA00');
|
|
432
|
+
return color;
|
|
433
|
+
}
|
|
434
|
+
return trimmed.startsWith('#') ? trimmed.toUpperCase() : `#${trimmed.toUpperCase()}`;
|
|
435
|
+
}
|
|
436
|
+
if (color !== null) {
|
|
437
|
+
errors.push('color must be a string or null');
|
|
438
|
+
}
|
|
439
|
+
return color;
|
|
440
|
+
}
|
|
399
441
|
function validateAppMetadata(entry) {
|
|
400
442
|
const warnings = [];
|
|
401
443
|
const errors = [];
|
|
@@ -403,42 +445,8 @@ function validateAppMetadata(entry) {
|
|
|
403
445
|
if (missingFields.length > 0) {
|
|
404
446
|
warnings.push(formatMissingMetadata(missingFields));
|
|
405
447
|
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
if (emoji !== null && typeof emoji === 'string') {
|
|
409
|
-
const trimmed = emoji.trim();
|
|
410
|
-
if (!trimmed) {
|
|
411
|
-
emoji = null;
|
|
412
|
-
}
|
|
413
|
-
else if (Array.from(trimmed).length > 4) {
|
|
414
|
-
errors.push('emoji must be a single character');
|
|
415
|
-
}
|
|
416
|
-
else {
|
|
417
|
-
emoji = trimmed;
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
else if (emoji !== null) {
|
|
421
|
-
errors.push('emoji must be a string or null');
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
let color = entry.color;
|
|
425
|
-
if (Object.prototype.hasOwnProperty.call(entry, 'color')) {
|
|
426
|
-
if (color !== null && typeof color === 'string') {
|
|
427
|
-
const trimmed = color.trim();
|
|
428
|
-
if (!trimmed) {
|
|
429
|
-
color = null;
|
|
430
|
-
}
|
|
431
|
-
else if (!HEX_COLOR_REGEX.test(trimmed)) {
|
|
432
|
-
errors.push('color must be a hex RGB value like #FFAA00');
|
|
433
|
-
}
|
|
434
|
-
else {
|
|
435
|
-
color = trimmed.startsWith('#') ? trimmed.toUpperCase() : `#${trimmed.toUpperCase()}`;
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
else if (color !== null) {
|
|
439
|
-
errors.push('color must be a string or null');
|
|
440
|
-
}
|
|
441
|
-
}
|
|
448
|
+
const emoji = validateOptionalEmoji(entry.emoji, Object.prototype.hasOwnProperty.call(entry, 'emoji'), errors);
|
|
449
|
+
const color = validateOptionalColor(entry.color, Object.prototype.hasOwnProperty.call(entry, 'color'), errors);
|
|
442
450
|
let type;
|
|
443
451
|
if (typeof entry.type === 'string' && entry.type.trim()) {
|
|
444
452
|
const parsedType = (0, types_1.parseAppType)(entry.type.trim());
|
|
@@ -626,7 +634,6 @@ function buildAppTasks(rootDir, catalogues, options) {
|
|
|
626
634
|
serverPath = absoluteServerPath;
|
|
627
635
|
}
|
|
628
636
|
// Parse versioning fields (required in schema v2)
|
|
629
|
-
let version;
|
|
630
637
|
const rawVersion = typeof entry.version === 'string' ? entry.version.trim() : '';
|
|
631
638
|
if (!rawVersion) {
|
|
632
639
|
errors.push(`[${label}] Skipping ${rawName}: app version is required in schema v2 (e.g., "1.0.0").`);
|
|
@@ -636,7 +643,7 @@ function buildAppTasks(rootDir, catalogues, options) {
|
|
|
636
643
|
errors.push(`[${label}] Skipping ${rawName}: version must be in Major.Minor.Patch format (e.g., "1.0.0").`);
|
|
637
644
|
continue;
|
|
638
645
|
}
|
|
639
|
-
version = rawVersion;
|
|
646
|
+
const version = rawVersion;
|
|
640
647
|
const releaseNotes = typeof entry.releaseNotes === 'string' ? entry.releaseNotes : undefined;
|
|
641
648
|
let versionVisibility;
|
|
642
649
|
const rawVisibility = typeof entry.visibility === 'string' ? entry.visibility.trim().toUpperCase() : '';
|
|
@@ -936,7 +943,7 @@ function buildAppTasks(rootDir, catalogues, options) {
|
|
|
936
943
|
category,
|
|
937
944
|
subcategory,
|
|
938
945
|
format: embeddedFormat,
|
|
939
|
-
visibility: normalizeAssetVisibilityValue(embedded?.visibility, errors, `${label} embedded asset
|
|
946
|
+
visibility: normalizeAssetVisibilityValue(embedded?.visibility, errors, `${label} embedded asset "${embeddedName}"`),
|
|
940
947
|
shopListed: typeof embedded?.shopListed === 'boolean' ? embedded.shopListed : undefined,
|
|
941
948
|
shopPriceCredits: Number.isInteger(embedded?.shopPriceCredits) ? Number(embedded.shopPriceCredits) : undefined,
|
|
942
949
|
files,
|
|
@@ -1107,7 +1114,7 @@ function buildAssetTasks(catalogues) {
|
|
|
1107
1114
|
username,
|
|
1108
1115
|
remix,
|
|
1109
1116
|
format,
|
|
1110
|
-
visibility: normalizeAssetVisibilityValue(entry.visibility, errors, `${label} asset
|
|
1117
|
+
visibility: normalizeAssetVisibilityValue(entry.visibility, errors, `${label} asset "${name}"`),
|
|
1111
1118
|
shopListed: typeof entry.shopListed === 'boolean' ? entry.shopListed : undefined,
|
|
1112
1119
|
shopPriceCredits: Number.isInteger(entry.shopPriceCredits) ? Number(entry.shopPriceCredits) : undefined,
|
|
1113
1120
|
files,
|
|
@@ -1351,6 +1358,13 @@ function buildAssetPackTasks(catalogues) {
|
|
|
1351
1358
|
}
|
|
1352
1359
|
listing = resolvedListing;
|
|
1353
1360
|
}
|
|
1361
|
+
const previewApp = typeof entry.previewApp === 'string'
|
|
1362
|
+
? String(entry.previewApp).trim()
|
|
1363
|
+
: '';
|
|
1364
|
+
if (previewApp.length > 0) {
|
|
1365
|
+
errors.push(`[${label}] Skipping asset pack "${name}": previewApp is no longer supported during publish. Upload the pack first, then set previewAppVersionId explicitly with creations asset-packs update.`);
|
|
1366
|
+
continue;
|
|
1367
|
+
}
|
|
1354
1368
|
tasks.push({
|
|
1355
1369
|
kind: 'asset-pack',
|
|
1356
1370
|
name,
|
|
@@ -1363,7 +1377,6 @@ function buildAssetPackTasks(catalogues) {
|
|
|
1363
1377
|
hostingMode,
|
|
1364
1378
|
externalUrl,
|
|
1365
1379
|
downloadUrl,
|
|
1366
|
-
previewApp: typeof entry.previewApp === 'string' && entry.previewApp.trim().length > 0 ? entry.previewApp.trim() : undefined,
|
|
1367
1380
|
visibility,
|
|
1368
1381
|
releaseNotes: typeof entry.releaseNotes === 'string' ? entry.releaseNotes : undefined,
|
|
1369
1382
|
listing,
|
package/dist/clientInfo.js
CHANGED
|
@@ -12,14 +12,28 @@ const os_1 = __importDefault(require("os"));
|
|
|
12
12
|
const config_1 = require("@playdrop/config");
|
|
13
13
|
function mapPlatform(platform) {
|
|
14
14
|
switch (platform) {
|
|
15
|
+
case 'aix':
|
|
16
|
+
return 'aix';
|
|
17
|
+
case 'android':
|
|
18
|
+
return 'android';
|
|
19
|
+
case 'cygwin':
|
|
20
|
+
return 'cygwin';
|
|
15
21
|
case 'darwin':
|
|
16
22
|
return 'macos';
|
|
23
|
+
case 'freebsd':
|
|
24
|
+
return 'freebsd';
|
|
25
|
+
case 'haiku':
|
|
26
|
+
return 'haiku';
|
|
17
27
|
case 'win32':
|
|
18
28
|
return 'windows';
|
|
19
29
|
case 'linux':
|
|
20
30
|
return 'linux';
|
|
21
|
-
|
|
22
|
-
return
|
|
31
|
+
case 'netbsd':
|
|
32
|
+
return 'netbsd';
|
|
33
|
+
case 'openbsd':
|
|
34
|
+
return 'openbsd';
|
|
35
|
+
case 'sunos':
|
|
36
|
+
return 'sunos';
|
|
23
37
|
}
|
|
24
38
|
}
|
|
25
39
|
function detectPlatformVersion() {
|
package/dist/commands/browse.js
CHANGED
|
@@ -91,7 +91,16 @@ function formatCountValue(value) {
|
|
|
91
91
|
}
|
|
92
92
|
function buildCountsSuffix(item) {
|
|
93
93
|
const parts = [];
|
|
94
|
-
if (
|
|
94
|
+
if (item.kind === 'app' && typeof item.item.playCount === 'number') {
|
|
95
|
+
if (typeof item.item.viewCount === 'number') {
|
|
96
|
+
parts.push(`view ${formatCountValue(item.item.viewCount)}`);
|
|
97
|
+
}
|
|
98
|
+
parts.push(`launch ${formatCountValue(item.item.playCount)}`);
|
|
99
|
+
}
|
|
100
|
+
if (item.kind === 'asset' && typeof item.item.playCount === 'number') {
|
|
101
|
+
if (typeof item.item.viewCount === 'number') {
|
|
102
|
+
parts.push(`view ${formatCountValue(item.item.viewCount)}`);
|
|
103
|
+
}
|
|
95
104
|
parts.push(`play ${formatCountValue(item.item.playCount)}`);
|
|
96
105
|
}
|
|
97
106
|
if (typeof item.item.likeCount === 'number') {
|
package/dist/commands/capture.js
CHANGED
|
@@ -35,6 +35,8 @@ function formatAppTypeSlug(type) {
|
|
|
35
35
|
return 'template';
|
|
36
36
|
case 'DEMO':
|
|
37
37
|
return 'demo';
|
|
38
|
+
case undefined:
|
|
39
|
+
return 'game';
|
|
38
40
|
default:
|
|
39
41
|
return 'game';
|
|
40
42
|
}
|
|
@@ -414,8 +416,7 @@ async function capture(targetArg, options = {}) {
|
|
|
414
416
|
projectInfo,
|
|
415
417
|
});
|
|
416
418
|
signalHandler = () => {
|
|
417
|
-
cleanup()
|
|
418
|
-
.finally(() => process.exit(130));
|
|
419
|
+
void cleanup().finally(() => process.exit(130));
|
|
419
420
|
};
|
|
420
421
|
process.on('SIGINT', signalHandler);
|
|
421
422
|
process.on('SIGTERM', signalHandler);
|
package/dist/commands/create.js
CHANGED
|
@@ -602,55 +602,58 @@ function parseRemixRef(value) {
|
|
|
602
602
|
ref: (0, types_1.formatContentVersionRef)(parsed),
|
|
603
603
|
};
|
|
604
604
|
}
|
|
605
|
+
function parseRemixScaffoldResponse(response, version) {
|
|
606
|
+
const remixMode = typeof response?.remixMode === 'string' ? response.remixMode : '';
|
|
607
|
+
const archiveUrl = typeof response?.archiveUrl === 'string' && response.archiveUrl.trim().length > 0
|
|
608
|
+
? response.archiveUrl.trim()
|
|
609
|
+
: null;
|
|
610
|
+
const htmlContent = typeof response?.html === 'string' ? response.html : null;
|
|
611
|
+
const externalListingUrl = typeof response?.externalListingUrl === 'string' && response.externalListingUrl.trim().length > 0
|
|
612
|
+
? response.externalListingUrl.trim()
|
|
613
|
+
: null;
|
|
614
|
+
const metadata = response.metadata;
|
|
615
|
+
const entryPoint = extractEntryPointFromMetadata(metadata);
|
|
616
|
+
if (remixMode === 'archive') {
|
|
617
|
+
if (!archiveUrl) {
|
|
618
|
+
throw new Error('Remix response missing archiveUrl');
|
|
619
|
+
}
|
|
620
|
+
return {
|
|
621
|
+
html: null,
|
|
622
|
+
metadata,
|
|
623
|
+
archiveUrl,
|
|
624
|
+
entryPoint,
|
|
625
|
+
sourceVersion: version,
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
if (remixMode === 'inline-html') {
|
|
629
|
+
if (!htmlContent) {
|
|
630
|
+
throw new Error('Remix response missing html');
|
|
631
|
+
}
|
|
632
|
+
return {
|
|
633
|
+
html: htmlContent,
|
|
634
|
+
metadata,
|
|
635
|
+
entryPoint,
|
|
636
|
+
sourceVersion: null,
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
if (remixMode === 'external-metadata-only') {
|
|
640
|
+
if (!externalListingUrl) {
|
|
641
|
+
throw new Error('Remix response missing externalListingUrl');
|
|
642
|
+
}
|
|
643
|
+
return {
|
|
644
|
+
html: null,
|
|
645
|
+
metadata,
|
|
646
|
+
externalListingUrl,
|
|
647
|
+
entryPoint,
|
|
648
|
+
sourceVersion: null,
|
|
649
|
+
};
|
|
650
|
+
}
|
|
651
|
+
throw new Error(`Unsupported remix mode: ${remixMode || 'missing'}`);
|
|
652
|
+
}
|
|
605
653
|
async function fetchRemixScaffold(client, creator, app, version) {
|
|
606
654
|
try {
|
|
607
655
|
const response = await client.fetchRemixScaffold(creator, app, version);
|
|
608
|
-
|
|
609
|
-
const archiveUrl = typeof response?.archiveUrl === 'string' && response.archiveUrl.trim().length > 0
|
|
610
|
-
? response.archiveUrl.trim()
|
|
611
|
-
: null;
|
|
612
|
-
const htmlContent = typeof response?.html === 'string' ? response.html : null;
|
|
613
|
-
const externalListingUrl = typeof response?.externalListingUrl === 'string' && response.externalListingUrl.trim().length > 0
|
|
614
|
-
? response.externalListingUrl.trim()
|
|
615
|
-
: null;
|
|
616
|
-
const metadata = response.metadata;
|
|
617
|
-
const entryPoint = extractEntryPointFromMetadata(metadata);
|
|
618
|
-
if (remixMode === 'archive') {
|
|
619
|
-
if (!archiveUrl) {
|
|
620
|
-
throw new Error('Remix response missing archiveUrl');
|
|
621
|
-
}
|
|
622
|
-
return {
|
|
623
|
-
html: null,
|
|
624
|
-
metadata,
|
|
625
|
-
archiveUrl,
|
|
626
|
-
entryPoint,
|
|
627
|
-
sourceVersion: version,
|
|
628
|
-
};
|
|
629
|
-
}
|
|
630
|
-
if (remixMode === 'inline-html') {
|
|
631
|
-
if (!htmlContent) {
|
|
632
|
-
throw new Error('Remix response missing html');
|
|
633
|
-
}
|
|
634
|
-
return {
|
|
635
|
-
html: htmlContent,
|
|
636
|
-
metadata,
|
|
637
|
-
entryPoint,
|
|
638
|
-
sourceVersion: null,
|
|
639
|
-
};
|
|
640
|
-
}
|
|
641
|
-
if (remixMode === 'external-metadata-only') {
|
|
642
|
-
if (!externalListingUrl) {
|
|
643
|
-
throw new Error('Remix response missing externalListingUrl');
|
|
644
|
-
}
|
|
645
|
-
return {
|
|
646
|
-
html: null,
|
|
647
|
-
metadata,
|
|
648
|
-
externalListingUrl,
|
|
649
|
-
entryPoint,
|
|
650
|
-
sourceVersion: null,
|
|
651
|
-
};
|
|
652
|
-
}
|
|
653
|
-
throw new Error(`Unsupported remix mode: ${remixMode || 'missing'}`);
|
|
656
|
+
return parseRemixScaffoldResponse(response, version);
|
|
654
657
|
}
|
|
655
658
|
catch (unknownError) {
|
|
656
659
|
if (unknownError instanceof types_1.UnsupportedClientError) {
|
|
@@ -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
|
|
@@ -99,7 +99,16 @@ function formatCountValue(value) {
|
|
|
99
99
|
}
|
|
100
100
|
function buildCountsSuffix(item) {
|
|
101
101
|
const parts = [];
|
|
102
|
-
if ('playCount' in item.item && typeof item.item.playCount === 'number') {
|
|
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
|
+
}
|
|
103
112
|
parts.push(`play ${formatCountValue(item.item.playCount)}`);
|
|
104
113
|
}
|
|
105
114
|
if (typeof item.item.likeCount === 'number') {
|
|
@@ -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;
|