@playdrop/playdrop-cli 0.5.1 → 0.5.3
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 +7 -7
- package/dist/apps/build.js +49 -6
- package/dist/apps/index.d.ts +2 -0
- package/dist/apps/index.js +2 -0
- package/dist/apps/upload.d.ts +2 -0
- package/dist/apps/upload.js +132 -28
- package/dist/assetSpecs.d.ts +16 -0
- package/dist/assetSpecs.js +263 -0
- package/dist/assets/model-artifacts.js +3 -0
- package/dist/catalogue.d.ts +57 -3
- package/dist/catalogue.js +342 -16
- package/dist/clientInfo.js +19 -3
- package/dist/commands/ads.d.ts +8 -0
- package/dist/commands/ads.js +124 -0
- package/dist/commands/boosts.d.ts +25 -0
- package/dist/commands/boosts.js +209 -0
- package/dist/commands/browse.d.ts +6 -1
- package/dist/commands/browse.js +365 -124
- package/dist/commands/captureListing.d.ts +53 -0
- package/dist/commands/captureListing.js +804 -0
- package/dist/commands/captureRemote.js +33 -0
- package/dist/commands/create.d.ts +1 -0
- package/dist/commands/create.js +183 -3
- package/dist/commands/credits.d.ts +6 -0
- package/dist/commands/credits.js +47 -1
- package/dist/commands/detail.js +38 -4
- package/dist/commands/devServer.js +10 -5
- package/dist/commands/generation.d.ts +2 -0
- package/dist/commands/generation.js +1 -0
- package/dist/commands/search.d.ts +5 -0
- package/dist/commands/search.js +139 -17
- package/dist/commands/tags.d.ts +7 -0
- package/dist/commands/tags.js +63 -0
- package/dist/commands/upload-content.d.ts +13 -3
- package/dist/commands/upload-content.js +86 -20
- package/dist/commands/upload.d.ts +2 -0
- package/dist/commands/upload.js +187 -11
- package/dist/commands/validate.js +163 -2
- package/dist/commands/versionsBrowse.js +128 -91
- package/dist/index.js +145 -3
- package/dist/refs.d.ts +2 -2
- package/dist/refs.js +13 -1
- package/dist/taskSelection.js +6 -3
- package/dist/taskUtils.d.ts +2 -2
- package/dist/taskUtils.js +1 -0
- package/dist/uploadLog.d.ts +1 -1
- package/dist/uploadLog.js +2 -2
- package/node_modules/@playdrop/ai-client/package.json +1 -1
- package/node_modules/@playdrop/api-client/dist/client.d.ts +131 -10
- package/node_modules/@playdrop/api-client/dist/client.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/client.js +6 -0
- package/node_modules/@playdrop/api-client/dist/domains/admin.d.ts +9 -1
- package/node_modules/@playdrop/api-client/dist/domains/admin.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/admin.js +45 -0
- package/node_modules/@playdrop/api-client/dist/domains/apps.d.ts +3 -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 +27 -0
- package/node_modules/@playdrop/api-client/dist/domains/asset-packs.d.ts +2 -0
- 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 +16 -0
- package/node_modules/@playdrop/api-client/dist/domains/assets.d.ts +44 -2
- package/node_modules/@playdrop/api-client/dist/domains/assets.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/assets.js +260 -3
- package/node_modules/@playdrop/api-client/dist/domains/payments.d.ts +17 -1
- package/node_modules/@playdrop/api-client/dist/domains/payments.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/payments.js +173 -0
- package/node_modules/@playdrop/api-client/dist/domains/search.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/domains/search.js +39 -11
- package/node_modules/@playdrop/api-client/dist/domains/tags.d.ts +34 -0
- package/node_modules/@playdrop/api-client/dist/domains/tags.d.ts.map +1 -0
- package/node_modules/@playdrop/api-client/dist/domains/tags.js +111 -0
- package/node_modules/@playdrop/api-client/dist/index.d.ts +61 -1
- package/node_modules/@playdrop/api-client/dist/index.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/index.js +50 -0
- package/node_modules/@playdrop/api-client/package.json +1 -1
- package/node_modules/@playdrop/boxel-core/dist/test/entity-utils.test.d.ts +1 -0
- package/node_modules/@playdrop/boxel-core/dist/test/entity-utils.test.js +92 -0
- package/node_modules/@playdrop/boxel-core/dist/test/entity-utils.test.js.map +1 -0
- package/node_modules/@playdrop/boxel-core/dist/test/greedy-mesher.test.d.ts +1 -0
- package/node_modules/@playdrop/boxel-core/dist/test/greedy-mesher.test.js +48 -0
- package/node_modules/@playdrop/boxel-core/dist/test/greedy-mesher.test.js.map +1 -0
- package/node_modules/@playdrop/boxel-core/dist/test/humanoid/humanoid-builders.test.d.ts +1 -0
- package/node_modules/@playdrop/boxel-core/dist/test/humanoid/humanoid-builders.test.js +270 -0
- package/node_modules/@playdrop/boxel-core/dist/test/humanoid/humanoid-builders.test.js.map +1 -0
- package/node_modules/@playdrop/boxel-core/dist/test/index.test.d.ts +1 -0
- package/node_modules/@playdrop/boxel-core/dist/test/index.test.js +48 -0
- package/node_modules/@playdrop/boxel-core/dist/test/index.test.js.map +1 -0
- package/node_modules/@playdrop/boxel-core/dist/test/layer-mode.test.d.ts +1 -0
- package/node_modules/@playdrop/boxel-core/dist/test/layer-mode.test.js +67 -0
- package/node_modules/@playdrop/boxel-core/dist/test/layer-mode.test.js.map +1 -0
- package/node_modules/@playdrop/boxel-core/dist/test/materials.test.d.ts +1 -0
- package/node_modules/@playdrop/boxel-core/dist/test/materials.test.js +55 -0
- package/node_modules/@playdrop/boxel-core/dist/test/materials.test.js.map +1 -0
- package/node_modules/@playdrop/boxel-core/dist/test/palette-tools.test.d.ts +1 -0
- package/node_modules/@playdrop/boxel-core/dist/test/palette-tools.test.js +124 -0
- package/node_modules/@playdrop/boxel-core/dist/test/palette-tools.test.js.map +1 -0
- package/node_modules/@playdrop/boxel-core/dist/test/serialization.test.d.ts +1 -0
- package/node_modules/@playdrop/boxel-core/dist/test/serialization.test.js +35 -0
- package/node_modules/@playdrop/boxel-core/dist/test/serialization.test.js.map +1 -0
- package/node_modules/@playdrop/boxel-core/dist/test/textures.test.d.ts +1 -0
- package/node_modules/@playdrop/boxel-core/dist/test/textures.test.js +120 -0
- package/node_modules/@playdrop/boxel-core/dist/test/textures.test.js.map +1 -0
- package/node_modules/@playdrop/boxel-core/dist/test/types.test.d.ts +1 -0
- package/node_modules/@playdrop/boxel-core/dist/test/types.test.js +32 -0
- package/node_modules/@playdrop/boxel-core/dist/test/types.test.js.map +1 -0
- package/node_modules/@playdrop/boxel-core/dist/test/upscale.test.d.ts +1 -0
- package/node_modules/@playdrop/boxel-core/dist/test/upscale.test.js +100 -0
- package/node_modules/@playdrop/boxel-core/dist/test/upscale.test.js.map +1 -0
- package/node_modules/@playdrop/boxel-core/dist/test/validation.test.d.ts +1 -0
- package/node_modules/@playdrop/boxel-core/dist/test/validation.test.js +61 -0
- package/node_modules/@playdrop/boxel-core/dist/test/validation.test.js.map +1 -0
- package/node_modules/@playdrop/boxel-core/dist/test/voxels.test.d.ts +1 -0
- package/node_modules/@playdrop/boxel-core/dist/test/voxels.test.js +51 -0
- package/node_modules/@playdrop/boxel-core/dist/test/voxels.test.js.map +1 -0
- 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 +7 -7
- package/node_modules/@playdrop/config/dist/src/constants.d.ts +11 -0
- package/node_modules/@playdrop/config/dist/src/constants.d.ts.map +1 -1
- package/node_modules/@playdrop/config/dist/src/constants.js +12 -1
- package/node_modules/@playdrop/config/dist/src/creator-docs.d.ts +24 -0
- package/node_modules/@playdrop/config/dist/src/creator-docs.d.ts.map +1 -0
- package/node_modules/@playdrop/config/dist/src/creator-docs.js +253 -0
- package/node_modules/@playdrop/config/dist/src/creator-faq.d.ts +17 -0
- package/node_modules/@playdrop/config/dist/src/creator-faq.d.ts.map +1 -0
- package/node_modules/@playdrop/config/dist/src/creator-faq.js +141 -0
- package/node_modules/@playdrop/config/dist/test/creator-docs.test.d.ts +2 -0
- package/node_modules/@playdrop/config/dist/test/creator-docs.test.d.ts.map +1 -0
- package/node_modules/@playdrop/config/dist/test/creator-docs.test.js +36 -0
- package/node_modules/@playdrop/config/dist/tsconfig.tsbuildinfo +1 -1
- package/node_modules/@playdrop/config/package.json +1 -1
- package/node_modules/@playdrop/types/dist/api.d.ts +346 -6
- package/node_modules/@playdrop/types/dist/api.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/api.js +52 -1
- package/node_modules/@playdrop/types/dist/asset-pack.d.ts +7 -1
- package/node_modules/@playdrop/types/dist/asset-pack.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/asset-spec-contract-meta-schema.json +86 -0
- package/node_modules/@playdrop/types/dist/asset-spec.d.ts +163 -0
- package/node_modules/@playdrop/types/dist/asset-spec.d.ts.map +1 -0
- package/node_modules/@playdrop/types/dist/asset-spec.js +101 -0
- package/node_modules/@playdrop/types/dist/asset.d.ts +23 -6
- package/node_modules/@playdrop/types/dist/asset.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/asset.js +4 -1
- package/node_modules/@playdrop/types/dist/graph.d.ts +4 -2
- package/node_modules/@playdrop/types/dist/graph.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/graph.js +9 -2
- package/node_modules/@playdrop/types/dist/index.d.ts +1 -0
- package/node_modules/@playdrop/types/dist/index.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/index.js +1 -0
- package/node_modules/@playdrop/types/dist/version.d.ts +13 -0
- package/node_modules/@playdrop/types/dist/version.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/version.js +21 -0
- package/node_modules/@playdrop/types/package.json +6 -1
- package/node_modules/@playdrop/vox-three/package.json +1 -1
- package/package.json +3 -1
package/dist/commands/search.js
CHANGED
|
@@ -12,7 +12,7 @@ function parseSearchKind(raw) {
|
|
|
12
12
|
return 'all';
|
|
13
13
|
}
|
|
14
14
|
const normalized = raw.trim().toLowerCase();
|
|
15
|
-
if (normalized === 'app' || normalized === 'asset' || normalized === 'asset-pack' || normalized === 'all') {
|
|
15
|
+
if (normalized === 'app' || normalized === 'asset' || normalized === 'asset-pack' || normalized === 'asset-spec' || normalized === 'all') {
|
|
16
16
|
return normalized;
|
|
17
17
|
}
|
|
18
18
|
return null;
|
|
@@ -50,6 +50,16 @@ function parseAssetSubcategory(raw) {
|
|
|
50
50
|
const normalized = (0, types_1.normalizeAssetSubcategory)(raw);
|
|
51
51
|
return normalized.length > 0 ? normalized : null;
|
|
52
52
|
}
|
|
53
|
+
function parseSearchSort(raw) {
|
|
54
|
+
if (!raw || raw.trim().length === 0) {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
const normalized = raw.trim().toLowerCase();
|
|
58
|
+
if (types_1.SEARCH_SORT_VALUES.includes(normalized)) {
|
|
59
|
+
return normalized;
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
53
63
|
function toSearchItem(result) {
|
|
54
64
|
if (result.kind === 'app') {
|
|
55
65
|
return {
|
|
@@ -67,6 +77,14 @@ function toSearchItem(result) {
|
|
|
67
77
|
item: result.asset,
|
|
68
78
|
};
|
|
69
79
|
}
|
|
80
|
+
if (result.kind === 'asset-spec') {
|
|
81
|
+
return {
|
|
82
|
+
kind: 'asset-spec',
|
|
83
|
+
ref: `${result.assetSpec.creatorUsername}/asset-spec/${result.assetSpec.name}`,
|
|
84
|
+
targetPath: result.targetPath,
|
|
85
|
+
item: result.assetSpec,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
70
88
|
if (result.kind === 'pack') {
|
|
71
89
|
return {
|
|
72
90
|
kind: 'asset-pack',
|
|
@@ -85,6 +103,9 @@ function itemSummary(item) {
|
|
|
85
103
|
const subcategory = item.item.currentVersion?.subcategory;
|
|
86
104
|
return subcategory ? `${item.item.category.toLowerCase()}/${subcategory}` : item.item.category.toLowerCase();
|
|
87
105
|
}
|
|
106
|
+
if (item.kind === 'asset-spec') {
|
|
107
|
+
return item.item.currentVersionRef ? `current ${item.item.currentVersionRef.split('@')[1] ?? 'none'}` : 'no current version';
|
|
108
|
+
}
|
|
88
109
|
return 'asset-pack';
|
|
89
110
|
}
|
|
90
111
|
function formatCountValue(value) {
|
|
@@ -98,15 +119,28 @@ function buildCountsSuffix(item) {
|
|
|
98
119
|
}
|
|
99
120
|
parts.push(`launch ${formatCountValue(item.item.playCount)}`);
|
|
100
121
|
}
|
|
101
|
-
if (item.kind === 'asset'
|
|
122
|
+
if (item.kind === 'asset') {
|
|
102
123
|
if (typeof item.item.viewCount === 'number') {
|
|
103
124
|
parts.push(`view ${formatCountValue(item.item.viewCount)}`);
|
|
104
125
|
}
|
|
105
|
-
|
|
126
|
+
if (typeof item.item.downloadCount === 'number') {
|
|
127
|
+
parts.push(`download ${formatCountValue(item.item.downloadCount)}`);
|
|
128
|
+
}
|
|
129
|
+
if (typeof item.item.playCount === 'number') {
|
|
130
|
+
parts.push(`play ${formatCountValue(item.item.playCount)}`);
|
|
131
|
+
}
|
|
106
132
|
}
|
|
107
133
|
if (item.kind === 'asset-pack' && typeof item.item.downloadCount === 'number') {
|
|
108
134
|
parts.push(`download ${formatCountValue(item.item.downloadCount)}`);
|
|
109
135
|
}
|
|
136
|
+
if (item.kind === 'asset-spec') {
|
|
137
|
+
parts.push(`assets ${formatCountValue(item.item.publicAssetCount)}`);
|
|
138
|
+
parts.push(`apps ${formatCountValue(item.item.supportingAppCount)}`);
|
|
139
|
+
if (item.item.documentationAvailable) {
|
|
140
|
+
parts.push('docs yes');
|
|
141
|
+
}
|
|
142
|
+
return ` | ${parts.join(' | ')}`;
|
|
143
|
+
}
|
|
110
144
|
if (typeof item.item.likeCount === 'number') {
|
|
111
145
|
parts.push(`like ${formatCountValue(item.item.likeCount)}`);
|
|
112
146
|
}
|
|
@@ -118,6 +152,71 @@ function buildCountsSuffix(item) {
|
|
|
118
152
|
}
|
|
119
153
|
return parts.length > 0 ? ` | ${parts.join(' | ')}` : '';
|
|
120
154
|
}
|
|
155
|
+
function normalizeOptionalString(value) {
|
|
156
|
+
if (typeof value !== 'string') {
|
|
157
|
+
return undefined;
|
|
158
|
+
}
|
|
159
|
+
const normalized = value.trim();
|
|
160
|
+
return normalized.length > 0 ? normalized : undefined;
|
|
161
|
+
}
|
|
162
|
+
function normalizeTagFilters(rawTags) {
|
|
163
|
+
if (!Array.isArray(rawTags) || rawTags.length === 0) {
|
|
164
|
+
return [];
|
|
165
|
+
}
|
|
166
|
+
const normalizedRefs = [];
|
|
167
|
+
const seenRefs = new Set();
|
|
168
|
+
for (const rawTag of rawTags) {
|
|
169
|
+
if (typeof rawTag !== 'string' || rawTag.trim().length === 0) {
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
let normalizedRef = '';
|
|
173
|
+
try {
|
|
174
|
+
normalizedRef = (0, types_1.normalizeTagRef)(rawTag);
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
if (seenRefs.has(normalizedRef)) {
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
seenRefs.add(normalizedRef);
|
|
183
|
+
normalizedRefs.push(normalizedRef);
|
|
184
|
+
}
|
|
185
|
+
if (normalizedRefs.length > 5) {
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
return normalizedRefs;
|
|
189
|
+
}
|
|
190
|
+
function buildTagSuffix(tags) {
|
|
191
|
+
const normalizedTags = Array.isArray(tags) ? tags : [];
|
|
192
|
+
if (normalizedTags.length === 0) {
|
|
193
|
+
return '';
|
|
194
|
+
}
|
|
195
|
+
const label = normalizedTags
|
|
196
|
+
.slice(0, 3)
|
|
197
|
+
.map((tag) => tag.ref)
|
|
198
|
+
.join(', ');
|
|
199
|
+
return ` | tags ${label}`;
|
|
200
|
+
}
|
|
201
|
+
function buildSearchRequest(input) {
|
|
202
|
+
return {
|
|
203
|
+
q: input.trimmedQuery,
|
|
204
|
+
mode: 'flat',
|
|
205
|
+
kind: (0, refs_1.contentKindToSearchKind)(input.kind),
|
|
206
|
+
page: 1,
|
|
207
|
+
pageSize: input.limit + input.offset,
|
|
208
|
+
...(input.sort ? { sort: input.sort } : {}),
|
|
209
|
+
appType: input.appType,
|
|
210
|
+
assetCategory: input.assetCategory,
|
|
211
|
+
assetSubcategory: input.assetSubcategory,
|
|
212
|
+
assetSpec: input.assetSpec,
|
|
213
|
+
assetSpecOwner: input.assetSpecOwner,
|
|
214
|
+
assetSpecName: input.assetSpecName,
|
|
215
|
+
packContainsCategory: input.packContainsCategory,
|
|
216
|
+
packContainsSubcategory: input.packContainsSubcategory,
|
|
217
|
+
tags: input.tags,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
121
220
|
async function search(query, options = {}) {
|
|
122
221
|
const trimmedQuery = typeof query === 'string' ? query.trim() : '';
|
|
123
222
|
if (!trimmedQuery) {
|
|
@@ -127,7 +226,7 @@ async function search(query, options = {}) {
|
|
|
127
226
|
}
|
|
128
227
|
const kind = parseSearchKind(options.kind);
|
|
129
228
|
if (!kind) {
|
|
130
|
-
(0, messages_1.printErrorWithHelp)(`Kind "${options.kind ?? ''}" is not supported.`, ['Use one of: app, asset, asset-pack, all.'], { command: 'search' });
|
|
229
|
+
(0, messages_1.printErrorWithHelp)(`Kind "${options.kind ?? ''}" is not supported.`, ['Use one of: app, asset, asset-pack, asset-spec, all.'], { command: 'search' });
|
|
131
230
|
process.exitCode = 1;
|
|
132
231
|
return;
|
|
133
232
|
}
|
|
@@ -143,6 +242,12 @@ async function search(query, options = {}) {
|
|
|
143
242
|
process.exitCode = 1;
|
|
144
243
|
return;
|
|
145
244
|
}
|
|
245
|
+
const sort = parseSearchSort(options.sort);
|
|
246
|
+
if (sort === null) {
|
|
247
|
+
(0, messages_1.printErrorWithHelp)(`Sort "${options.sort ?? ''}" is not supported.`, ['Use one of: relevance, recent, likes, downloads, remixes, comments, assets, apps, alpha.'], { command: 'search' });
|
|
248
|
+
process.exitCode = 1;
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
146
251
|
const appType = options.appType ? (0, types_1.parseAppType)(options.appType.trim().toUpperCase()) : undefined;
|
|
147
252
|
if (options.appType !== undefined && !appType) {
|
|
148
253
|
(0, messages_1.printErrorWithHelp)(`App type "${options.appType}" is not supported.`, ['Use one of: game, demo, tool, template.'], { command: 'search' });
|
|
@@ -173,21 +278,30 @@ async function search(query, options = {}) {
|
|
|
173
278
|
process.exitCode = 1;
|
|
174
279
|
return;
|
|
175
280
|
}
|
|
281
|
+
const tags = normalizeTagFilters(options.tag);
|
|
282
|
+
if (tags === null) {
|
|
283
|
+
(0, messages_1.printErrorWithHelp)('The --tag value is invalid.', ['Use canonical refs like theme/pirate or visual-style/pixel-art.', 'Pass at most 5 unique tag refs.'], { command: 'search' });
|
|
284
|
+
process.exitCode = 1;
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
176
287
|
await (0, commandContext_1.withPublicEnvironment)('search', async ({ client }) => {
|
|
177
288
|
try {
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
pageSize: requestLimit,
|
|
289
|
+
const response = await client.search(buildSearchRequest({
|
|
290
|
+
trimmedQuery,
|
|
291
|
+
kind,
|
|
292
|
+
limit,
|
|
293
|
+
offset,
|
|
294
|
+
sort: sort ?? undefined,
|
|
185
295
|
appType: appType,
|
|
186
296
|
assetCategory: assetCategory ?? undefined,
|
|
187
297
|
assetSubcategory: assetSubcategory ?? undefined,
|
|
298
|
+
assetSpec: normalizeOptionalString(options.assetSpec),
|
|
299
|
+
assetSpecOwner: normalizeOptionalString(options.assetSpecOwner),
|
|
300
|
+
assetSpecName: normalizeOptionalString(options.assetSpecName),
|
|
188
301
|
packContainsCategory: packContainsCategory ?? undefined,
|
|
189
302
|
packContainsSubcategory: packContainsSubcategory ?? undefined,
|
|
190
|
-
|
|
303
|
+
tags,
|
|
304
|
+
}));
|
|
191
305
|
const normalizedItems = (response.results ?? [])
|
|
192
306
|
.map((result) => toSearchItem(result))
|
|
193
307
|
.filter((item) => Boolean(item));
|
|
@@ -210,16 +324,24 @@ async function search(query, options = {}) {
|
|
|
210
324
|
console.log(`Search results for "${trimmedQuery}":\n`);
|
|
211
325
|
for (const [index, item] of items.entries()) {
|
|
212
326
|
const displayName = item.item.displayName || item.item.name;
|
|
213
|
-
console.log(`${index + 1}. [${item.kind}] ${item.ref} | ${displayName} | @${item.item.creatorUsername} | ${itemSummary(item)}${buildCountsSuffix(item)}`);
|
|
327
|
+
console.log(`${index + 1}. [${item.kind}] ${item.ref} | ${displayName} | @${item.item.creatorUsername} | ${itemSummary(item)}${buildCountsSuffix(item)}${buildTagSuffix(item.item.tags)}`);
|
|
214
328
|
}
|
|
215
329
|
console.log('\nNext: run "playdrop detail <creator>/<kind>/<name>" to inspect one result.');
|
|
216
330
|
}
|
|
217
331
|
catch (error) {
|
|
218
332
|
const handled = (0, errors_1.handleCommandFailure)(error, 'search', 'Search', {
|
|
219
|
-
apiMessage: (apiError) =>
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
333
|
+
apiMessage: (apiError) => {
|
|
334
|
+
if (apiError.code === 'invalid_tag_ref' || apiError.code === 'duplicate_tag_ref' || apiError.code === 'tag_filter_limit_exceeded') {
|
|
335
|
+
return {
|
|
336
|
+
problem: 'One or more tag filters are invalid.',
|
|
337
|
+
suggestions: ['Use canonical refs like theme/pirate.', 'Pass at most 5 unique --tag values.'],
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
return {
|
|
341
|
+
problem: `Search failed with status ${apiError.status}.`,
|
|
342
|
+
suggestions: ['Retry in a moment.', 'Use "playdrop help search" for usage details.'],
|
|
343
|
+
};
|
|
344
|
+
},
|
|
223
345
|
});
|
|
224
346
|
if (!handled) {
|
|
225
347
|
throw error;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.browseTags = browseTags;
|
|
4
|
+
const types_1 = require("@playdrop/types");
|
|
5
|
+
const commandContext_1 = require("../commandContext");
|
|
6
|
+
const messages_1 = require("../messages");
|
|
7
|
+
function normalizeGroupSlug(value) {
|
|
8
|
+
const normalized = typeof value === 'string' ? value.trim().toLowerCase() : '';
|
|
9
|
+
return normalized.length > 0 ? normalized : null;
|
|
10
|
+
}
|
|
11
|
+
function normalizeTargetKind(value) {
|
|
12
|
+
const normalized = typeof value === 'string' ? value.trim().toUpperCase() : '';
|
|
13
|
+
if (!normalized) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
return types_1.SAVED_ITEM_KIND_VALUES.includes(normalized)
|
|
17
|
+
? normalized
|
|
18
|
+
: null;
|
|
19
|
+
}
|
|
20
|
+
function formatAllowedTargetKinds(kinds) {
|
|
21
|
+
if (!Array.isArray(kinds) || kinds.length === 0) {
|
|
22
|
+
return 'all';
|
|
23
|
+
}
|
|
24
|
+
return kinds.join(', ');
|
|
25
|
+
}
|
|
26
|
+
async function browseTags(options) {
|
|
27
|
+
const groupSlug = normalizeGroupSlug(options.group);
|
|
28
|
+
const targetKind = normalizeTargetKind(options.kind);
|
|
29
|
+
if (options.group && (!groupSlug || !(0, types_1.isValidTagSlug)(groupSlug))) {
|
|
30
|
+
(0, messages_1.printErrorWithHelp)(`Invalid group slug "${options.group}".`, ['Use lowercase letters, numbers, and hyphens only.'], { command: 'tags browse' });
|
|
31
|
+
process.exitCode = 1;
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (options.kind && !targetKind) {
|
|
35
|
+
(0, messages_1.printErrorWithHelp)(`Unsupported target kind "${options.kind}".`, [`Use one of: ${types_1.SAVED_ITEM_KIND_VALUES.join(', ')}.`], { command: 'tags browse' });
|
|
36
|
+
process.exitCode = 1;
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
await (0, commandContext_1.withPublicEnvironment)('tags browse', async ({ client }) => {
|
|
40
|
+
const response = await client.fetchTags({
|
|
41
|
+
...(groupSlug ? { groupSlug } : {}),
|
|
42
|
+
...(targetKind ? { targetKind } : {}),
|
|
43
|
+
});
|
|
44
|
+
if (options.json) {
|
|
45
|
+
console.log(JSON.stringify(response, null, 2));
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (response.groups.length === 0) {
|
|
49
|
+
console.log('No tags found.');
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
for (const [groupIndex, group] of response.groups.entries()) {
|
|
53
|
+
if (groupIndex > 0) {
|
|
54
|
+
console.log('');
|
|
55
|
+
}
|
|
56
|
+
console.log(`${group.displayName} (${group.slug})`);
|
|
57
|
+
console.log(`Allowed targets: ${formatAllowedTargetKinds(group.allowedTargetKinds)}`);
|
|
58
|
+
for (const tag of group.tags) {
|
|
59
|
+
console.log(`${tag.ref} ${tag.displayName}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ApiClient } from '@playdrop/api-client';
|
|
2
2
|
import { type AssetPackUploadedLocalAsset } from '@playdrop/types';
|
|
3
|
-
import type { AssetPackTask, AssetTask, EmbeddedAssetTask } from '../catalogue';
|
|
3
|
+
import type { AssetPackTask, AssetSpecTask, AssetTask, EmbeddedAssetTask } from '../catalogue';
|
|
4
4
|
import type { CliTask } from '../taskUtils';
|
|
5
5
|
export type CurrentUserRole = 'USER' | 'CREATOR' | 'ADMIN' | null;
|
|
6
6
|
export type UploadedAssetInfo = {
|
|
@@ -10,6 +10,11 @@ export type UploadedAssetInfo = {
|
|
|
10
10
|
ref: string;
|
|
11
11
|
versionNodeId: string;
|
|
12
12
|
};
|
|
13
|
+
export type UploadedAssetSpecInfo = {
|
|
14
|
+
creatorUsername: string;
|
|
15
|
+
name: string;
|
|
16
|
+
version: string;
|
|
17
|
+
};
|
|
13
18
|
export type UploadedAppInfo = {
|
|
14
19
|
creatorUsername: string;
|
|
15
20
|
name: string;
|
|
@@ -65,6 +70,11 @@ export declare function parseUnversionedAssetTaskRef(rawRef: string, fallbackCre
|
|
|
65
70
|
name: string;
|
|
66
71
|
} | null;
|
|
67
72
|
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
|
|
69
|
-
|
|
73
|
+
export declare function uploadAssetTask(client: ApiClient, task: AssetTask | EmbeddedAssetTask, sourceAppVersionId?: number, creatorUsername?: string, options?: {
|
|
74
|
+
clearTags?: boolean;
|
|
75
|
+
}): Promise<UploadedAssetInfo>;
|
|
76
|
+
export declare function uploadAssetSpecTask(client: ApiClient, task: AssetSpecTask, creatorUsername?: string): Promise<UploadedAssetSpecInfo>;
|
|
77
|
+
export declare function uploadAssetPackTask(client: ApiClient, task: AssetPackTask, creatorUsername: string, uploadedAssets: Map<string, UploadedAssetInfo>, localAssetTasks: AssetTask[], uploadKeyByAssetKey: Map<string, string>, targetCreatorUsername?: string, options?: {
|
|
78
|
+
clearTags?: boolean;
|
|
79
|
+
}): Promise<UploadedPackInfo>;
|
|
70
80
|
export {};
|
|
@@ -6,6 +6,7 @@ exports.getTaskCreatorResult = getTaskCreatorResult;
|
|
|
6
6
|
exports.parseUnversionedAssetTaskRef = parseUnversionedAssetTaskRef;
|
|
7
7
|
exports.buildAssetPackUploadPlans = buildAssetPackUploadPlans;
|
|
8
8
|
exports.uploadAssetTask = uploadAssetTask;
|
|
9
|
+
exports.uploadAssetSpecTask = uploadAssetSpecTask;
|
|
9
10
|
exports.uploadAssetPackTask = uploadAssetPackTask;
|
|
10
11
|
const node_crypto_1 = require("node:crypto");
|
|
11
12
|
const node_fs_1 = require("node:fs");
|
|
@@ -316,6 +317,22 @@ function validateAssetSubcategoryCompatibility(task, format) {
|
|
|
316
317
|
return subcategory;
|
|
317
318
|
}
|
|
318
319
|
async function prepareAssetTaskUploadData(task) {
|
|
320
|
+
if ('assetSpec' in task && typeof task.assetSpec === 'string' && task.assetSpec.trim().length > 0) {
|
|
321
|
+
const uploadFiles = Object.entries(task.filePaths)
|
|
322
|
+
.sort(([leftRole], [rightRole]) => leftRole.localeCompare(rightRole))
|
|
323
|
+
.map(([role, filePath]) => prepareUploadFile(filePath, role));
|
|
324
|
+
return {
|
|
325
|
+
assetSpec: task.assetSpec.trim(),
|
|
326
|
+
uploadFiles,
|
|
327
|
+
manifestFiles: uploadFiles.map((entry) => ({
|
|
328
|
+
role: entry.fieldName,
|
|
329
|
+
filename: entry.filename,
|
|
330
|
+
contentType: entry.contentType,
|
|
331
|
+
sizeBytes: entry.sizeBytes,
|
|
332
|
+
sha256: entry.sha256,
|
|
333
|
+
})),
|
|
334
|
+
};
|
|
335
|
+
}
|
|
319
336
|
const format = resolveAssetFormat(task);
|
|
320
337
|
const subcategory = validateAssetSubcategoryCompatibility(task, format);
|
|
321
338
|
await (0, model_artifacts_1.prepareModel3DAssetArtifacts)(task);
|
|
@@ -335,7 +352,7 @@ async function prepareAssetTaskUploadData(task) {
|
|
|
335
352
|
})),
|
|
336
353
|
};
|
|
337
354
|
}
|
|
338
|
-
async function uploadAssetTask(client, task, sourceAppVersionId, creatorUsername) {
|
|
355
|
+
async function uploadAssetTask(client, task, sourceAppVersionId, creatorUsername, options) {
|
|
339
356
|
const prepared = await prepareAssetTaskUploadData(task);
|
|
340
357
|
const visibility = task.visibility;
|
|
341
358
|
const files = prepared.uploadFiles.map((entry) => ({
|
|
@@ -347,19 +364,35 @@ async function uploadAssetTask(client, task, sourceAppVersionId, creatorUsername
|
|
|
347
364
|
if (!targetCreatorUsername) {
|
|
348
365
|
throw new Error(`Asset "${task.name}" upload is missing creator username.`);
|
|
349
366
|
}
|
|
350
|
-
const response = await client.createAssetVersion(targetCreatorUsername, task.name,
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
367
|
+
const response = await client.createAssetVersion(targetCreatorUsername, task.name, prepared.assetSpec
|
|
368
|
+
? {
|
|
369
|
+
displayName: task.kind === 'asset' ? task.displayName : undefined,
|
|
370
|
+
assetSpec: prepared.assetSpec,
|
|
371
|
+
remixRef: task.kind === 'asset' ? task.remix : undefined,
|
|
372
|
+
visibility: visibility,
|
|
373
|
+
sourceKind: sourceAppVersionId ? 'APP_EMBEDDED' : 'UPLOAD',
|
|
374
|
+
sourceAppVersionId,
|
|
375
|
+
tags: task.kind === 'asset' ? task.tags : undefined,
|
|
376
|
+
clearTags: task.kind === 'asset' ? options?.clearTags : undefined,
|
|
377
|
+
shopListed: task.shopListed,
|
|
378
|
+
shopPriceCredits: task.shopPriceCredits,
|
|
379
|
+
files,
|
|
380
|
+
}
|
|
381
|
+
: {
|
|
382
|
+
displayName: task.kind === 'asset' ? task.displayName : undefined,
|
|
383
|
+
category: task.category,
|
|
384
|
+
subcategory: prepared.subcategory,
|
|
385
|
+
format: prepared.format,
|
|
386
|
+
remixRef: task.kind === 'asset' ? task.remix : undefined,
|
|
387
|
+
visibility: visibility,
|
|
388
|
+
sourceKind: sourceAppVersionId ? 'APP_EMBEDDED' : 'UPLOAD',
|
|
389
|
+
sourceAppVersionId,
|
|
390
|
+
tags: task.kind === 'asset' ? task.tags : undefined,
|
|
391
|
+
clearTags: task.kind === 'asset' ? options?.clearTags : undefined,
|
|
392
|
+
shopListed: task.shopListed,
|
|
393
|
+
shopPriceCredits: task.shopPriceCredits,
|
|
394
|
+
files,
|
|
395
|
+
});
|
|
363
396
|
const uploadedCreatorUsername = response.asset.creatorUsername;
|
|
364
397
|
const name = response.asset.name;
|
|
365
398
|
const revision = response.version.revision;
|
|
@@ -378,6 +411,35 @@ async function uploadAssetTask(client, task, sourceAppVersionId, creatorUsername
|
|
|
378
411
|
versionNodeId,
|
|
379
412
|
};
|
|
380
413
|
}
|
|
414
|
+
async function uploadAssetSpecTask(client, task, creatorUsername) {
|
|
415
|
+
const targetCreatorUsername = typeof creatorUsername === 'string' ? creatorUsername.trim() : '';
|
|
416
|
+
if (!targetCreatorUsername) {
|
|
417
|
+
throw new Error(`Asset spec "${task.name}@${task.version}" upload is missing creator username.`);
|
|
418
|
+
}
|
|
419
|
+
const symbol = prepareUploadFile(task.symbolPath, 'symbol', 'image/svg+xml');
|
|
420
|
+
const contract = prepareUploadFile(task.contractPath, 'contract', 'application/json');
|
|
421
|
+
const documentation = task.documentationPath
|
|
422
|
+
? prepareUploadFile(task.documentationPath, 'documentation', 'text/markdown')
|
|
423
|
+
: null;
|
|
424
|
+
await client.createAssetSpecVersion(targetCreatorUsername, task.name, {
|
|
425
|
+
version: task.version,
|
|
426
|
+
displayName: task.displayName,
|
|
427
|
+
description: task.description,
|
|
428
|
+
visibility: task.visibility,
|
|
429
|
+
validationKind: task.validationKind,
|
|
430
|
+
status: task.status,
|
|
431
|
+
releaseNotes: task.releaseNotes,
|
|
432
|
+
successorVersion: task.successorVersion,
|
|
433
|
+
symbol: symbol.file,
|
|
434
|
+
contract: contract.file,
|
|
435
|
+
...(documentation ? { documentation: documentation.file } : {}),
|
|
436
|
+
});
|
|
437
|
+
return {
|
|
438
|
+
creatorUsername: targetCreatorUsername,
|
|
439
|
+
name: task.name,
|
|
440
|
+
version: task.version,
|
|
441
|
+
};
|
|
442
|
+
}
|
|
381
443
|
function parseAssetRef(raw) {
|
|
382
444
|
const trimmed = raw.trim();
|
|
383
445
|
const canonicalMatch = /^asset:([^/]+)\/([^@]+)@r(\d+)$/i.exec(trimmed);
|
|
@@ -459,11 +521,13 @@ function buildLocalAssetManifestEntries(preparedLocalAssets) {
|
|
|
459
521
|
uploadKey,
|
|
460
522
|
name: localAsset.task.name,
|
|
461
523
|
displayName: localAsset.task.displayName,
|
|
462
|
-
category: localAsset.task.category,
|
|
463
|
-
subcategory: localAsset.prepared.subcategory,
|
|
464
|
-
format: localAsset.prepared.format,
|
|
524
|
+
category: (localAsset.task.assetSpec ? 'CUSTOM' : localAsset.task.category),
|
|
525
|
+
subcategory: localAsset.prepared.subcategory ?? null,
|
|
526
|
+
format: (localAsset.prepared.format ?? 'CUSTOM'),
|
|
527
|
+
...(localAsset.task.assetSpec ? { assetSpec: localAsset.task.assetSpec } : {}),
|
|
465
528
|
visibility: localAsset.task.visibility,
|
|
466
529
|
remixRef: localAsset.task.remix,
|
|
530
|
+
tags: localAsset.task.tags,
|
|
467
531
|
shopListed: localAsset.task.shopListed,
|
|
468
532
|
shopPriceCredits: localAsset.task.shopPriceCredits,
|
|
469
533
|
files: localAsset.prepared.manifestFiles,
|
|
@@ -534,12 +598,14 @@ function buildPackListingPayload(listingUploads) {
|
|
|
534
598
|
videosLandscape: listingUploads.filter((entry) => entry.mediaKey.startsWith('videosLandscape:')).map((entry) => entry.entry),
|
|
535
599
|
};
|
|
536
600
|
}
|
|
537
|
-
function buildPackInitializeRequest(task, localAssets, existingAssets, members, listingUploads) {
|
|
601
|
+
function buildPackInitializeRequest(task, localAssets, existingAssets, members, listingUploads, options) {
|
|
538
602
|
return {
|
|
539
603
|
version: task.version,
|
|
540
604
|
displayName: task.displayName,
|
|
541
605
|
remixRef: task.remix,
|
|
542
606
|
visibility: task.visibility,
|
|
607
|
+
tags: task.tags,
|
|
608
|
+
clearTags: options?.clearTags,
|
|
543
609
|
hostingMode: task.hostingMode,
|
|
544
610
|
externalUrl: task.externalUrl,
|
|
545
611
|
downloadUrl: task.downloadUrl,
|
|
@@ -586,13 +652,13 @@ function buildUploadedPackInfo(creatorUsername, task, versionNodeId, versionAsse
|
|
|
586
652
|
uploadedLocalAssets: uploadedLocalAssets ?? [],
|
|
587
653
|
};
|
|
588
654
|
}
|
|
589
|
-
async function uploadAssetPackTask(client, task, creatorUsername, uploadedAssets, localAssetTasks, uploadKeyByAssetKey, targetCreatorUsername) {
|
|
655
|
+
async function uploadAssetPackTask(client, task, creatorUsername, uploadedAssets, localAssetTasks, uploadKeyByAssetKey, targetCreatorUsername, options) {
|
|
590
656
|
const mutationCreatorUsername = resolveMutationCreatorUsername(task, creatorUsername, targetCreatorUsername);
|
|
591
657
|
const preparedLocalAssets = await prepareLocalPackAssets(task, mutationCreatorUsername, localAssetTasks, uploadKeyByAssetKey);
|
|
592
658
|
const localAssets = buildLocalAssetManifestEntries(preparedLocalAssets);
|
|
593
659
|
const { existingAssets, members } = await buildPackMembersAndExistingAssets(client, task, mutationCreatorUsername, uploadedAssets, uploadKeyByAssetKey);
|
|
594
660
|
const listingUploads = buildPackListingUploads(task);
|
|
595
|
-
const initializeBody = buildPackInitializeRequest(task, localAssets, existingAssets, members, listingUploads);
|
|
661
|
+
const initializeBody = buildPackInitializeRequest(task, localAssets, existingAssets, members, listingUploads, options);
|
|
596
662
|
const initializeResponse = await client.initializeAssetPackUpload(mutationCreatorUsername, task.name, initializeBody);
|
|
597
663
|
if (initializeResponse.status === 'finalized') {
|
|
598
664
|
if (!initializeResponse.versionNodeId || !initializeResponse.version) {
|