@playdrop/playdrop-cli 0.3.4-build.1 → 0.3.5-build.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -23
- package/config/client-meta.json +5 -5
- package/dist/apps/upload.js +5 -3
- package/dist/assets/model-artifacts.js +1 -1
- package/dist/catalogue.d.ts +6 -0
- package/dist/catalogue.js +38 -1
- package/dist/commandContext.d.ts +1 -0
- package/dist/commandContext.js +45 -15
- package/dist/commands/browse.d.ts +16 -0
- package/dist/commands/browse.js +370 -0
- package/dist/commands/build.js +4 -9
- package/dist/commands/capture.js +24 -24
- package/dist/commands/captureRemote.d.ts +11 -0
- package/dist/commands/captureRemote.js +90 -0
- package/dist/commands/comments.d.ts +14 -0
- package/dist/commands/comments.js +189 -0
- package/dist/commands/create.js +112 -72
- package/dist/commands/creations.d.ts +49 -0
- package/dist/commands/creations.js +657 -0
- package/dist/commands/credits.d.ts +10 -0
- package/dist/commands/credits.js +91 -0
- package/dist/commands/detail.d.ts +2 -2
- package/dist/commands/detail.js +148 -290
- package/dist/commands/dev.js +24 -24
- package/dist/commands/devShared.js +2 -2
- package/dist/commands/documentation.d.ts +4 -1
- package/dist/commands/documentation.js +79 -104
- package/dist/commands/feedback.d.ts +12 -9
- package/dist/commands/feedback.js +125 -257
- package/dist/commands/format.js +6 -13
- package/dist/commands/generation.d.ts +11 -0
- package/dist/commands/generation.js +204 -42
- package/dist/commands/gettingStarted.d.ts +1 -0
- package/dist/commands/gettingStarted.js +26 -0
- package/dist/commands/init.js +26 -24
- package/dist/commands/login.js +9 -8
- package/dist/commands/logout.js +2 -1
- package/dist/commands/notifications.d.ts +14 -0
- package/dist/commands/notifications.js +179 -0
- package/dist/commands/search.d.ts +13 -0
- package/dist/commands/search.js +198 -0
- package/dist/commands/upload.js +20 -17
- package/dist/commands/validate.js +15 -1
- package/dist/commands/versionsBrowse.d.ts +7 -0
- package/dist/commands/versionsBrowse.js +209 -0
- package/dist/commands/whoami.js +9 -8
- package/dist/errors.d.ts +9 -0
- package/dist/errors.js +52 -0
- package/dist/externalAssetPackValidation.d.ts +2 -0
- package/dist/externalAssetPackValidation.js +115 -0
- package/dist/http.js +1 -1
- package/dist/index.js +570 -630
- package/dist/messages.js +11 -11
- package/dist/output.d.ts +5 -0
- package/dist/output.js +45 -0
- package/dist/playwright.js +1 -1
- package/dist/refs.d.ts +18 -0
- package/dist/refs.js +105 -0
- package/node_modules/@playdrop/ai-client/dist/index.d.ts +42 -15
- package/node_modules/@playdrop/ai-client/dist/index.d.ts.map +1 -1
- package/node_modules/@playdrop/ai-client/package.json +1 -0
- package/node_modules/@playdrop/api-client/dist/client.d.ts +39 -27
- package/node_modules/@playdrop/api-client/dist/client.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/client.js +280 -1669
- package/node_modules/@playdrop/api-client/dist/core/errors.d.ts +9 -0
- package/node_modules/@playdrop/api-client/dist/core/errors.d.ts.map +1 -0
- package/node_modules/@playdrop/api-client/dist/core/errors.js +46 -0
- package/node_modules/@playdrop/api-client/dist/core/request.d.ts +27 -0
- package/node_modules/@playdrop/api-client/dist/core/request.d.ts.map +1 -0
- package/node_modules/@playdrop/api-client/dist/core/request.js +122 -0
- package/node_modules/@playdrop/api-client/dist/domains/admin.d.ts +75 -0
- package/node_modules/@playdrop/api-client/dist/domains/admin.d.ts.map +1 -0
- package/node_modules/@playdrop/api-client/dist/domains/admin.js +282 -0
- package/node_modules/@playdrop/api-client/dist/domains/ai.d.ts +22 -0
- package/node_modules/@playdrop/api-client/dist/domains/ai.d.ts.map +1 -0
- package/node_modules/@playdrop/api-client/dist/domains/ai.js +15 -0
- package/node_modules/@playdrop/api-client/dist/domains/apps.d.ts +60 -0
- package/node_modules/@playdrop/api-client/dist/domains/apps.d.ts.map +1 -0
- package/node_modules/@playdrop/api-client/dist/domains/apps.js +301 -0
- package/node_modules/@playdrop/api-client/dist/domains/asset-packs.d.ts +59 -0
- package/node_modules/@playdrop/api-client/dist/domains/asset-packs.d.ts.map +1 -0
- package/node_modules/@playdrop/api-client/dist/domains/asset-packs.js +297 -0
- package/node_modules/@playdrop/api-client/dist/domains/assets.d.ts +62 -0
- package/node_modules/@playdrop/api-client/dist/domains/assets.d.ts.map +1 -0
- package/node_modules/@playdrop/api-client/dist/domains/assets.js +297 -0
- package/node_modules/@playdrop/api-client/dist/domains/auth.d.ts +28 -0
- package/node_modules/@playdrop/api-client/dist/domains/auth.d.ts.map +1 -0
- package/node_modules/@playdrop/api-client/dist/domains/auth.js +78 -0
- package/node_modules/@playdrop/api-client/dist/domains/comments.d.ts +29 -0
- package/node_modules/@playdrop/api-client/dist/domains/comments.d.ts.map +1 -0
- package/node_modules/@playdrop/api-client/dist/domains/comments.js +65 -0
- package/node_modules/@playdrop/api-client/dist/domains/me.d.ts +24 -0
- package/node_modules/@playdrop/api-client/dist/domains/me.d.ts.map +1 -0
- package/node_modules/@playdrop/api-client/dist/domains/me.js +35 -0
- package/node_modules/@playdrop/api-client/dist/domains/payments.d.ts +37 -0
- package/node_modules/@playdrop/api-client/dist/domains/payments.d.ts.map +1 -0
- package/node_modules/@playdrop/api-client/dist/domains/payments.js +148 -0
- package/node_modules/@playdrop/api-client/dist/domains/search.d.ts +27 -0
- package/node_modules/@playdrop/api-client/dist/domains/search.d.ts.map +1 -0
- package/node_modules/@playdrop/api-client/dist/domains/search.js +65 -0
- package/node_modules/@playdrop/api-client/dist/index.d.ts +33 -56
- package/node_modules/@playdrop/api-client/dist/index.d.ts.map +1 -1
- package/node_modules/@playdrop/api-client/dist/index.js +103 -44
- package/node_modules/@playdrop/api-client/package.json +3 -2
- package/node_modules/@playdrop/boxel-core/package.json +1 -1
- package/node_modules/@playdrop/boxel-three/dist/test/glb-skinned.test.js +1 -1
- package/node_modules/@playdrop/boxel-three/dist/test/instantiate.test.js +1 -1
- package/node_modules/@playdrop/boxel-three/dist/test/skinned-mesh.test.js +1 -1
- package/node_modules/@playdrop/boxel-three/package.json +2 -1
- package/node_modules/@playdrop/config/client-meta.json +5 -5
- package/node_modules/@playdrop/config/dist/src/constants.d.ts +5 -0
- package/node_modules/@playdrop/config/dist/src/constants.d.ts.map +1 -1
- package/node_modules/@playdrop/config/dist/src/constants.js +5 -1
- 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 +178 -17
- package/node_modules/@playdrop/types/dist/api.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/api.js +30 -1
- package/node_modules/@playdrop/types/dist/app.d.ts +0 -14
- package/node_modules/@playdrop/types/dist/app.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/app.js +0 -10
- package/node_modules/@playdrop/types/dist/asset-pack.d.ts +11 -1
- package/node_modules/@playdrop/types/dist/asset-pack.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/asset.d.ts +65 -0
- package/node_modules/@playdrop/types/dist/asset.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/realtime.d.ts +26 -26
- package/node_modules/@playdrop/types/dist/realtime.d.ts.map +1 -1
- package/node_modules/@playdrop/types/dist/version.d.ts +5 -0
- package/node_modules/@playdrop/types/dist/version.d.ts.map +1 -1
- package/package.json +2 -3
- package/bin/playdrop-cli +0 -2
- package/dist/commands/asset-packs.d.ts +0 -27
- package/dist/commands/asset-packs.js +0 -508
- package/dist/commands/assets.d.ts +0 -35
- package/dist/commands/assets.js +0 -668
- package/dist/commands/list.d.ts +0 -7
- package/dist/commands/list.js +0 -347
- package/dist/commands/migrateCatalogueV2.d.ts +0 -1
- package/dist/commands/migrateCatalogueV2.js +0 -142
- package/dist/commands/versions.d.ts +0 -17
- package/dist/commands/versions.js +0 -384
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.browseNotifications = browseNotifications;
|
|
4
|
+
exports.readNotification = readNotification;
|
|
5
|
+
exports.readAllNotifications = readAllNotifications;
|
|
6
|
+
const commandContext_1 = require("../commandContext");
|
|
7
|
+
const errors_1 = require("../errors");
|
|
8
|
+
const messages_1 = require("../messages");
|
|
9
|
+
const output_1 = require("../output");
|
|
10
|
+
function parseStatus(raw) {
|
|
11
|
+
if (!raw || raw.trim().length === 0) {
|
|
12
|
+
return 'unread';
|
|
13
|
+
}
|
|
14
|
+
const normalized = raw.trim().toLowerCase();
|
|
15
|
+
if (normalized === 'all' || normalized === 'read' || normalized === 'unread') {
|
|
16
|
+
return normalized;
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
function parsePositiveInteger(raw, label, fallback) {
|
|
21
|
+
if (raw === undefined) {
|
|
22
|
+
return fallback;
|
|
23
|
+
}
|
|
24
|
+
const parsed = typeof raw === 'number' ? raw : Number.parseInt(String(raw), 10);
|
|
25
|
+
if (!Number.isInteger(parsed) || parsed < 0) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
if (label === 'limit' && parsed <= 0) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
return parsed;
|
|
32
|
+
}
|
|
33
|
+
async function fetchNotificationsByStatus(fetchPage, status, limit, offset) {
|
|
34
|
+
if (status === 'all' || status === 'unread') {
|
|
35
|
+
return fetchPage(status, limit, offset);
|
|
36
|
+
}
|
|
37
|
+
const pageSize = Math.max(limit, 50);
|
|
38
|
+
const collected = [];
|
|
39
|
+
let unreadCount = 0;
|
|
40
|
+
let cursor = 0;
|
|
41
|
+
let hasMore = true;
|
|
42
|
+
while (hasMore && collected.length < offset + limit) {
|
|
43
|
+
const response = await fetchPage('all', pageSize, cursor);
|
|
44
|
+
unreadCount = response.unreadCount;
|
|
45
|
+
const matching = response.notifications.filter((notification) => notification.readAt !== null);
|
|
46
|
+
collected.push(...matching);
|
|
47
|
+
if (!response.pagination.hasMore || response.notifications.length === 0) {
|
|
48
|
+
hasMore = false;
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
cursor += response.notifications.length;
|
|
52
|
+
}
|
|
53
|
+
const notifications = collected.slice(offset, offset + limit);
|
|
54
|
+
return {
|
|
55
|
+
notifications,
|
|
56
|
+
unreadCount,
|
|
57
|
+
pagination: {
|
|
58
|
+
limit,
|
|
59
|
+
offset,
|
|
60
|
+
count: notifications.length,
|
|
61
|
+
hasMore: collected.length > offset + limit || hasMore,
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
async function browseNotifications(options = {}) {
|
|
66
|
+
const status = parseStatus(options.status);
|
|
67
|
+
if (!status) {
|
|
68
|
+
(0, messages_1.printErrorWithHelp)(`Status "${options.status ?? ''}" is not supported.`, ['Use one of: unread, read, all.'], { command: 'notifications browse' });
|
|
69
|
+
process.exitCode = 1;
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const limit = parsePositiveInteger(options.limit, 'limit', 20);
|
|
73
|
+
if (limit === null) {
|
|
74
|
+
(0, messages_1.printErrorWithHelp)('The --limit value must be a positive integer.', ['Example: --limit 20'], { command: 'notifications browse' });
|
|
75
|
+
process.exitCode = 1;
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const offset = parsePositiveInteger(options.offset, 'offset', 0);
|
|
79
|
+
if (offset === null) {
|
|
80
|
+
(0, messages_1.printErrorWithHelp)('The --offset value must be zero or a positive integer.', ['Example: --offset 20'], { command: 'notifications browse' });
|
|
81
|
+
process.exitCode = 1;
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
await (0, commandContext_1.withEnvironment)('notifications browse', 'Checking your notifications', async ({ client }) => {
|
|
85
|
+
try {
|
|
86
|
+
const response = await fetchNotificationsByStatus(async (requestStatus, requestLimit, requestOffset) => client.fetchNotifications({
|
|
87
|
+
status: requestStatus,
|
|
88
|
+
limit: requestLimit,
|
|
89
|
+
offset: requestOffset,
|
|
90
|
+
}), status, limit, offset);
|
|
91
|
+
if (options.json) {
|
|
92
|
+
(0, output_1.printJson)({
|
|
93
|
+
notifications: response.notifications,
|
|
94
|
+
unreadCount: response.unreadCount,
|
|
95
|
+
pagination: response.pagination,
|
|
96
|
+
});
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (response.notifications.length === 0) {
|
|
100
|
+
console.log(`No ${status} notifications found.`);
|
|
101
|
+
console.log('Next: run "playdrop browse" or "playdrop creations browse" to check recent activity.');
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
console.log(`Notifications (${status}):\n`);
|
|
105
|
+
for (const notification of response.notifications) {
|
|
106
|
+
const state = notification.readAt ? 'read' : 'unread';
|
|
107
|
+
console.log(`#${notification.id} | ${state} | ${(0, output_1.formatTimestamp)(notification.createdAt)}`);
|
|
108
|
+
console.log(` ${notification.title}`);
|
|
109
|
+
if (notification.body) {
|
|
110
|
+
console.log(` ${notification.body}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
console.log('\nNext: run "playdrop notifications read <id>" or "playdrop notifications read-all".');
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
const handled = (0, errors_1.handleCommandFailure)(error, 'notifications browse', 'Notification lookup', {
|
|
117
|
+
apiMessage: (apiError) => ({
|
|
118
|
+
problem: `Notification lookup failed with status ${apiError.status}.`,
|
|
119
|
+
suggestions: ['Run "playdrop auth login" and retry.'],
|
|
120
|
+
}),
|
|
121
|
+
});
|
|
122
|
+
if (!handled) {
|
|
123
|
+
throw error;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
async function readNotification(rawId, options = {}) {
|
|
129
|
+
const id = parsePositiveInteger(rawId, 'Notification id', 0);
|
|
130
|
+
if (id === null || id === 0) {
|
|
131
|
+
(0, messages_1.printErrorWithHelp)('Notification id must be a positive integer.', ['Example: playdrop notifications read 42'], { command: 'notifications read' });
|
|
132
|
+
process.exitCode = 1;
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
await (0, commandContext_1.withEnvironment)('notifications read', 'Marking a notification as read', async ({ client }) => {
|
|
136
|
+
try {
|
|
137
|
+
const response = await client.markNotificationRead(id);
|
|
138
|
+
if (options.json) {
|
|
139
|
+
(0, output_1.printJson)({ success: Boolean(response.success), unreadCount: response.unreadCount });
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
(0, output_1.printSuccess)(`Notification #${id} marked as read.`, ['Next: run "playdrop notifications browse --status unread" to review what remains.']);
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
const handled = (0, errors_1.handleCommandFailure)(error, 'notifications read', 'Notification update', {
|
|
146
|
+
apiMessage: (apiError) => ({
|
|
147
|
+
problem: `Notification update failed with status ${apiError.status}.`,
|
|
148
|
+
suggestions: ['Run "playdrop auth login" and retry.'],
|
|
149
|
+
}),
|
|
150
|
+
});
|
|
151
|
+
if (!handled) {
|
|
152
|
+
throw error;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
async function readAllNotifications(options = {}) {
|
|
158
|
+
await (0, commandContext_1.withEnvironment)('notifications read-all', 'Marking all notifications as read', async ({ client }) => {
|
|
159
|
+
try {
|
|
160
|
+
const response = await client.markAllNotificationsRead();
|
|
161
|
+
if (options.json) {
|
|
162
|
+
(0, output_1.printJson)({ success: Boolean(response.success), unreadCount: response.unreadCount });
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
(0, output_1.printSuccess)('All notifications marked as read.', ['Next: run "playdrop notifications browse --status unread" to confirm your inbox is clear.']);
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
const handled = (0, errors_1.handleCommandFailure)(error, 'notifications read-all', 'Notification update', {
|
|
169
|
+
apiMessage: (apiError) => ({
|
|
170
|
+
problem: `Notification update failed with status ${apiError.status}.`,
|
|
171
|
+
suggestions: ['Run "playdrop auth login" and retry.'],
|
|
172
|
+
}),
|
|
173
|
+
});
|
|
174
|
+
if (!handled) {
|
|
175
|
+
throw error;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
type SearchOptions = {
|
|
2
|
+
kind?: string;
|
|
3
|
+
appType?: string;
|
|
4
|
+
assetCategory?: string;
|
|
5
|
+
assetSubcategory?: string;
|
|
6
|
+
packContainsCategory?: string;
|
|
7
|
+
packContainsSubcategory?: string;
|
|
8
|
+
limit?: string | number;
|
|
9
|
+
offset?: string | number;
|
|
10
|
+
json?: boolean;
|
|
11
|
+
};
|
|
12
|
+
export declare function search(query: string | undefined, options?: SearchOptions): Promise<void>;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.search = search;
|
|
4
|
+
const types_1 = require("@playdrop/types");
|
|
5
|
+
const commandContext_1 = require("../commandContext");
|
|
6
|
+
const errors_1 = require("../errors");
|
|
7
|
+
const messages_1 = require("../messages");
|
|
8
|
+
const output_1 = require("../output");
|
|
9
|
+
const refs_1 = require("../refs");
|
|
10
|
+
function parseSearchKind(raw) {
|
|
11
|
+
if (!raw || raw.trim().length === 0) {
|
|
12
|
+
return 'all';
|
|
13
|
+
}
|
|
14
|
+
const normalized = raw.trim().toLowerCase();
|
|
15
|
+
if (normalized === 'app' || normalized === 'asset' || normalized === 'asset-pack' || normalized === 'all') {
|
|
16
|
+
return normalized;
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
function parsePositiveInteger(raw, label, fallback) {
|
|
21
|
+
if (raw === undefined) {
|
|
22
|
+
return fallback;
|
|
23
|
+
}
|
|
24
|
+
const parsed = typeof raw === 'number' ? raw : Number.parseInt(String(raw), 10);
|
|
25
|
+
if (!Number.isInteger(parsed) || parsed < 0) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
if (label === 'limit' && parsed <= 0) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
return parsed;
|
|
32
|
+
}
|
|
33
|
+
function parseAssetCategory(raw) {
|
|
34
|
+
if (!raw || raw.trim().length === 0) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
const normalized = raw.trim().toUpperCase().replace(/[-\s]/g, '_');
|
|
38
|
+
if (normalized === '3D' || normalized === 'MODEL3D') {
|
|
39
|
+
return 'MODEL_3D';
|
|
40
|
+
}
|
|
41
|
+
if (types_1.ASSET_CATEGORY_VALUES.includes(normalized)) {
|
|
42
|
+
return normalized;
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
function parseAssetSubcategory(raw) {
|
|
47
|
+
if (!raw || raw.trim().length === 0) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
const normalized = (0, types_1.normalizeAssetSubcategory)(raw);
|
|
51
|
+
return normalized.length > 0 ? normalized : null;
|
|
52
|
+
}
|
|
53
|
+
function toSearchItem(result) {
|
|
54
|
+
if (result.kind === 'app') {
|
|
55
|
+
return {
|
|
56
|
+
kind: 'app',
|
|
57
|
+
ref: `${result.app.creatorUsername}/app/${result.app.name}`,
|
|
58
|
+
targetPath: result.targetPath,
|
|
59
|
+
item: result.app,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
if (result.kind === 'asset') {
|
|
63
|
+
return {
|
|
64
|
+
kind: 'asset',
|
|
65
|
+
ref: `${result.asset.creatorUsername}/asset/${result.asset.name}`,
|
|
66
|
+
targetPath: result.targetPath,
|
|
67
|
+
item: result.asset,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
if (result.kind === 'pack') {
|
|
71
|
+
return {
|
|
72
|
+
kind: 'asset-pack',
|
|
73
|
+
ref: `${result.pack.creatorUsername}/asset-pack/${result.pack.name}`,
|
|
74
|
+
targetPath: result.targetPath,
|
|
75
|
+
item: result.pack,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
function itemSummary(item) {
|
|
81
|
+
if (item.kind === 'app') {
|
|
82
|
+
return item.item.type.toLowerCase();
|
|
83
|
+
}
|
|
84
|
+
if (item.kind === 'asset') {
|
|
85
|
+
const subcategory = item.item.currentVersion?.subcategory;
|
|
86
|
+
return subcategory ? `${item.item.category.toLowerCase()}/${subcategory}` : item.item.category.toLowerCase();
|
|
87
|
+
}
|
|
88
|
+
return 'asset-pack';
|
|
89
|
+
}
|
|
90
|
+
async function search(query, options = {}) {
|
|
91
|
+
const trimmedQuery = typeof query === 'string' ? query.trim() : '';
|
|
92
|
+
if (!trimmedQuery) {
|
|
93
|
+
(0, messages_1.printErrorWithHelp)('A search query is required.', ['Example: playdrop search "city builder"'], { command: 'search' });
|
|
94
|
+
process.exitCode = 1;
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const kind = parseSearchKind(options.kind);
|
|
98
|
+
if (!kind) {
|
|
99
|
+
(0, messages_1.printErrorWithHelp)(`Kind "${options.kind ?? ''}" is not supported.`, ['Use one of: app, asset, asset-pack, all.'], { command: 'search' });
|
|
100
|
+
process.exitCode = 1;
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const limit = parsePositiveInteger(options.limit, 'limit', 10);
|
|
104
|
+
if (limit === null) {
|
|
105
|
+
(0, messages_1.printErrorWithHelp)('The --limit value must be a positive integer.', ['Example: --limit 10'], { command: 'search' });
|
|
106
|
+
process.exitCode = 1;
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const offset = parsePositiveInteger(options.offset, 'offset', 0);
|
|
110
|
+
if (offset === null) {
|
|
111
|
+
(0, messages_1.printErrorWithHelp)('The --offset value must be zero or a positive integer.', ['Example: --offset 20'], { command: 'search' });
|
|
112
|
+
process.exitCode = 1;
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const appType = options.appType ? (0, types_1.parseAppType)(options.appType.trim().toUpperCase()) : undefined;
|
|
116
|
+
if (options.appType !== undefined && !appType) {
|
|
117
|
+
(0, messages_1.printErrorWithHelp)(`App type "${options.appType}" is not supported.`, ['Use one of: game, demo, tool, template.'], { command: 'search' });
|
|
118
|
+
process.exitCode = 1;
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const assetCategory = parseAssetCategory(options.assetCategory);
|
|
122
|
+
if (assetCategory === null) {
|
|
123
|
+
(0, messages_1.printErrorWithHelp)(`Asset category "${options.assetCategory}" is not supported.`, ['Use a canonical asset category like IMAGE, VIDEO, AUDIO, SPRITESHEET, or MODEL_3D.'], { command: 'search' });
|
|
124
|
+
process.exitCode = 1;
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const assetSubcategory = parseAssetSubcategory(options.assetSubcategory);
|
|
128
|
+
if (assetSubcategory === null) {
|
|
129
|
+
(0, messages_1.printErrorWithHelp)(`Asset subcategory "${options.assetSubcategory}" is invalid.`, ['Use lowercase slug values like generic, avatar, music, or sfx.'], { command: 'search' });
|
|
130
|
+
process.exitCode = 1;
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const packContainsCategory = parseAssetCategory(options.packContainsCategory);
|
|
134
|
+
if (packContainsCategory === null) {
|
|
135
|
+
(0, messages_1.printErrorWithHelp)(`Pack category "${options.packContainsCategory}" is not supported.`, ['Use a canonical asset category like IMAGE, VIDEO, AUDIO, SPRITESHEET, or MODEL_3D.'], { command: 'search' });
|
|
136
|
+
process.exitCode = 1;
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const packContainsSubcategory = parseAssetSubcategory(options.packContainsSubcategory);
|
|
140
|
+
if (packContainsSubcategory === null) {
|
|
141
|
+
(0, messages_1.printErrorWithHelp)(`Pack subcategory "${options.packContainsSubcategory}" is invalid.`, ['Use lowercase slug values like generic, avatar, music, or sfx.'], { command: 'search' });
|
|
142
|
+
process.exitCode = 1;
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
await (0, commandContext_1.withPublicEnvironment)('search', async ({ client }) => {
|
|
146
|
+
try {
|
|
147
|
+
const requestLimit = limit + offset;
|
|
148
|
+
const response = await client.search({
|
|
149
|
+
q: trimmedQuery,
|
|
150
|
+
mode: 'flat',
|
|
151
|
+
kind: (0, refs_1.contentKindToSearchKind)(kind),
|
|
152
|
+
page: 1,
|
|
153
|
+
pageSize: requestLimit,
|
|
154
|
+
appType: appType,
|
|
155
|
+
assetCategory: assetCategory ?? undefined,
|
|
156
|
+
assetSubcategory: assetSubcategory ?? undefined,
|
|
157
|
+
packContainsCategory: packContainsCategory ?? undefined,
|
|
158
|
+
packContainsSubcategory: packContainsSubcategory ?? undefined,
|
|
159
|
+
});
|
|
160
|
+
const normalizedItems = (response.results ?? [])
|
|
161
|
+
.map((result) => toSearchItem(result))
|
|
162
|
+
.filter((item) => Boolean(item));
|
|
163
|
+
const items = normalizedItems.slice(offset, offset + limit);
|
|
164
|
+
const pagination = {
|
|
165
|
+
limit,
|
|
166
|
+
offset,
|
|
167
|
+
count: items.length,
|
|
168
|
+
hasMore: normalizedItems.length > offset + limit || Boolean(response.pagination?.hasMore),
|
|
169
|
+
};
|
|
170
|
+
if (options.json) {
|
|
171
|
+
(0, output_1.printJson)({ items, pagination });
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
if (items.length === 0) {
|
|
175
|
+
console.log(`No results found for "${trimmedQuery}".`);
|
|
176
|
+
console.log('Next: adjust your filters or run "playdrop browse" to explore available content.');
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
console.log(`Search results for "${trimmedQuery}":\n`);
|
|
180
|
+
for (const [index, item] of items.entries()) {
|
|
181
|
+
const displayName = item.item.displayName || item.item.name;
|
|
182
|
+
console.log(`${index + 1}. [${item.kind}] ${item.ref} | ${displayName} | @${item.item.creatorUsername} | ${itemSummary(item)}`);
|
|
183
|
+
}
|
|
184
|
+
console.log('\nNext: run "playdrop detail <creator>/<kind>/<name>" to inspect one result.');
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
const handled = (0, errors_1.handleCommandFailure)(error, 'search', 'Search', {
|
|
188
|
+
apiMessage: (apiError) => ({
|
|
189
|
+
problem: `Search failed with status ${apiError.status}.`,
|
|
190
|
+
suggestions: ['Retry in a moment.', 'Use "playdrop help search" for usage details.'],
|
|
191
|
+
}),
|
|
192
|
+
});
|
|
193
|
+
if (!handled) {
|
|
194
|
+
throw error;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
}
|
package/dist/commands/upload.js
CHANGED
|
@@ -242,7 +242,11 @@ async function uploadAssetTask(client, task, sourceAppVersionId, creatorUsername
|
|
|
242
242
|
fieldName: role,
|
|
243
243
|
filename: (0, node_path_1.basename)(filePath),
|
|
244
244
|
}));
|
|
245
|
-
const
|
|
245
|
+
const targetCreatorUsername = typeof creatorUsername === 'string' ? creatorUsername.trim() : '';
|
|
246
|
+
if (!targetCreatorUsername) {
|
|
247
|
+
throw new Error(`Asset "${task.name}" upload is missing creator username.`);
|
|
248
|
+
}
|
|
249
|
+
const response = await client.createAssetVersion(targetCreatorUsername, task.name, {
|
|
246
250
|
displayName: task.kind === 'asset' ? task.displayName : undefined,
|
|
247
251
|
category: task.category,
|
|
248
252
|
subcategory,
|
|
@@ -253,8 +257,6 @@ async function uploadAssetTask(client, task, sourceAppVersionId, creatorUsername
|
|
|
253
257
|
shopListed: task.shopListed,
|
|
254
258
|
shopPriceCredits: task.shopPriceCredits,
|
|
255
259
|
files,
|
|
256
|
-
}, {
|
|
257
|
-
creatorUsername,
|
|
258
260
|
});
|
|
259
261
|
const uploadedCreatorUsername = response.asset.creatorUsername;
|
|
260
262
|
const name = response.asset.name;
|
|
@@ -329,10 +331,19 @@ async function uploadAssetPackTask(client, task, creatorUsername, uploadedAssets
|
|
|
329
331
|
for (const ref of task.assets) {
|
|
330
332
|
assetRefs.push(await resolveAssetReference(client, ref, creatorUsername, uploadedAssets));
|
|
331
333
|
}
|
|
332
|
-
const
|
|
334
|
+
const mutationCreatorUsername = typeof targetCreatorUsername === 'string' && targetCreatorUsername.trim().length > 0
|
|
335
|
+
? targetCreatorUsername.trim()
|
|
336
|
+
: creatorUsername.trim();
|
|
337
|
+
if (!mutationCreatorUsername) {
|
|
338
|
+
throw new Error(`Asset pack "${task.name}@${task.version}" upload is missing creator username.`);
|
|
339
|
+
}
|
|
340
|
+
const response = await client.uploadAssetPackVersion(mutationCreatorUsername, task.name, {
|
|
333
341
|
request: {
|
|
334
342
|
version: task.version,
|
|
335
343
|
visibility: task.visibility,
|
|
344
|
+
hostingMode: task.hostingMode,
|
|
345
|
+
externalUrl: task.externalUrl,
|
|
346
|
+
downloadUrl: task.downloadUrl,
|
|
336
347
|
releaseNotes: task.releaseNotes,
|
|
337
348
|
assets: assetRefs.map((assetRef) => ({ assetRef })),
|
|
338
349
|
},
|
|
@@ -343,8 +354,6 @@ async function uploadAssetPackTask(client, task, creatorUsername, uploadedAssets
|
|
|
343
354
|
screenshotsLandscape: task.listing?.screenshotLandscapePaths?.map((filePath) => createListingFileFromPath(filePath, 'image/png')),
|
|
344
355
|
videosPortrait: task.listing?.videoPortraitPaths?.map((filePath) => createListingFileFromPath(filePath, 'video/mp4')),
|
|
345
356
|
videosLandscape: task.listing?.videoLandscapePaths?.map((filePath) => createListingFileFromPath(filePath, 'video/mp4')),
|
|
346
|
-
}, {
|
|
347
|
-
creatorUsername: targetCreatorUsername,
|
|
348
357
|
});
|
|
349
358
|
const versionNodeId = typeof response.versionNodeId === 'string' ? response.versionNodeId.trim() : '';
|
|
350
359
|
if (!versionNodeId) {
|
|
@@ -497,7 +506,7 @@ async function processUploadTasks(client, tasks, owner, ownerUsername, currentUs
|
|
|
497
506
|
if (task.kind === 'app') {
|
|
498
507
|
const { upload } = await (0, apps_1.runAppPipeline)(client, task, {
|
|
499
508
|
skipEcs: options?.skipEcs,
|
|
500
|
-
creatorUsername:
|
|
509
|
+
creatorUsername: taskCreator,
|
|
501
510
|
});
|
|
502
511
|
if (!upload.versionCreated || !upload.version) {
|
|
503
512
|
throw new Error(`App "${task.name}" upload did not return a created version.`);
|
|
@@ -542,10 +551,7 @@ async function processUploadTasks(client, tasks, owner, ownerUsername, currentUs
|
|
|
542
551
|
console.log((0, uploadLog_1.formatTaskLogLine)(entry));
|
|
543
552
|
}
|
|
544
553
|
else if (task.kind === 'asset') {
|
|
545
|
-
const
|
|
546
|
-
? taskCreator
|
|
547
|
-
: undefined;
|
|
548
|
-
const uploaded = await uploadAssetTask(client, task, undefined, mutationTargetCreator);
|
|
554
|
+
const uploaded = await uploadAssetTask(client, task, undefined, taskCreator);
|
|
549
555
|
uploadedAssetsByKey.set(`${uploaded.creatorUsername}/${uploaded.name}`, uploaded);
|
|
550
556
|
registerCanonicalNode(graphState, uploaded.ref, uploaded.versionNodeId);
|
|
551
557
|
registerLocalRef(graphState.localAssetNodeByName, graphState.ambiguousAssetNames, task.name, uploaded.versionNodeId);
|
|
@@ -569,10 +575,7 @@ async function processUploadTasks(client, tasks, owner, ownerUsername, currentUs
|
|
|
569
575
|
if (!sourceApp) {
|
|
570
576
|
throw new Error(`Embedded asset "${task.name}" references app "${task.appName}" that was not uploaded in this run.`);
|
|
571
577
|
}
|
|
572
|
-
const
|
|
573
|
-
? sourceApp.creatorUsername
|
|
574
|
-
: undefined;
|
|
575
|
-
const uploaded = await uploadAssetTask(client, task, sourceApp.versionId, mutationTargetCreator);
|
|
578
|
+
const uploaded = await uploadAssetTask(client, task, sourceApp.versionId, sourceApp.creatorUsername);
|
|
576
579
|
uploadedAssetsByKey.set(`${uploaded.creatorUsername}/${uploaded.name}`, uploaded);
|
|
577
580
|
registerCanonicalNode(graphState, uploaded.ref, uploaded.versionNodeId);
|
|
578
581
|
registerLocalRef(graphState.localAssetNodeByName, graphState.ambiguousAssetNames, task.name, uploaded.versionNodeId);
|
|
@@ -664,7 +667,7 @@ async function processUploadTasks(client, tasks, owner, ownerUsername, currentUs
|
|
|
664
667
|
return results;
|
|
665
668
|
}
|
|
666
669
|
async function upload(pathOrName, options) {
|
|
667
|
-
await (0, commandContext_1.withEnvironment)('
|
|
670
|
+
await (0, commandContext_1.withEnvironment)('project publish', 'Publishing content', async ({ client, env, envConfig }) => {
|
|
668
671
|
let userInfo = { username: null, role: null };
|
|
669
672
|
try {
|
|
670
673
|
userInfo = await fetchCurrentUserInfo(client, envConfig.apiBase);
|
|
@@ -680,7 +683,7 @@ async function upload(pathOrName, options) {
|
|
|
680
683
|
: 'unknown';
|
|
681
684
|
const selection = (0, taskSelection_1.selectTasks)(pathOrName);
|
|
682
685
|
if (selection.errors.length > 0) {
|
|
683
|
-
(0, taskSelection_1.reportTaskErrors)(selection.errors, '
|
|
686
|
+
(0, taskSelection_1.reportTaskErrors)(selection.errors, 'project publish');
|
|
684
687
|
process.exitCode = 1;
|
|
685
688
|
return;
|
|
686
689
|
}
|
|
@@ -5,10 +5,21 @@ const taskSelection_1 = require("../taskSelection");
|
|
|
5
5
|
const taskUtils_1 = require("../taskUtils");
|
|
6
6
|
const uploadLog_1 = require("../uploadLog");
|
|
7
7
|
const apps_1 = require("../apps");
|
|
8
|
+
const externalAssetPackValidation_1 = require("../externalAssetPackValidation");
|
|
8
9
|
async function validate(pathOrName) {
|
|
9
10
|
const selection = (0, taskSelection_1.selectTasks)(pathOrName);
|
|
10
11
|
if (selection.errors.length > 0) {
|
|
11
|
-
(0, taskSelection_1.reportTaskErrors)(selection.errors, 'validate');
|
|
12
|
+
(0, taskSelection_1.reportTaskErrors)(selection.errors, 'project validate');
|
|
13
|
+
process.exitCode = 1;
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const externalAssetPackErrors = await (0, externalAssetPackValidation_1.validateExternalAssetPackTasks)(selection.tasks);
|
|
17
|
+
if (externalAssetPackErrors.length > 0) {
|
|
18
|
+
(0, taskSelection_1.reportTaskErrors)(externalAssetPackErrors.map((message) => ({
|
|
19
|
+
type: 'invalid-catalogue',
|
|
20
|
+
message,
|
|
21
|
+
help: ['Update the asset pack downloadUrl to a public hostname that resolves successfully, then try again.'],
|
|
22
|
+
})), 'project validate');
|
|
12
23
|
process.exitCode = 1;
|
|
13
24
|
return;
|
|
14
25
|
}
|
|
@@ -25,6 +36,9 @@ async function validate(pathOrName) {
|
|
|
25
36
|
if (task.kind === 'app') {
|
|
26
37
|
await (0, apps_1.validateAppTask)(task);
|
|
27
38
|
}
|
|
39
|
+
else {
|
|
40
|
+
throw new Error(`project validate does not support ${task.kind} "${entityId}".`);
|
|
41
|
+
}
|
|
28
42
|
const entry = {
|
|
29
43
|
action: 'validate',
|
|
30
44
|
status: 'success',
|