@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.
Files changed (141) hide show
  1. package/README.md +60 -23
  2. package/config/client-meta.json +5 -5
  3. package/dist/apps/upload.js +5 -3
  4. package/dist/assets/model-artifacts.js +1 -1
  5. package/dist/catalogue.d.ts +6 -0
  6. package/dist/catalogue.js +38 -1
  7. package/dist/commandContext.d.ts +1 -0
  8. package/dist/commandContext.js +45 -15
  9. package/dist/commands/browse.d.ts +16 -0
  10. package/dist/commands/browse.js +370 -0
  11. package/dist/commands/build.js +4 -9
  12. package/dist/commands/capture.js +24 -24
  13. package/dist/commands/captureRemote.d.ts +11 -0
  14. package/dist/commands/captureRemote.js +90 -0
  15. package/dist/commands/comments.d.ts +14 -0
  16. package/dist/commands/comments.js +189 -0
  17. package/dist/commands/create.js +112 -72
  18. package/dist/commands/creations.d.ts +49 -0
  19. package/dist/commands/creations.js +657 -0
  20. package/dist/commands/credits.d.ts +10 -0
  21. package/dist/commands/credits.js +91 -0
  22. package/dist/commands/detail.d.ts +2 -2
  23. package/dist/commands/detail.js +148 -290
  24. package/dist/commands/dev.js +24 -24
  25. package/dist/commands/devShared.js +2 -2
  26. package/dist/commands/documentation.d.ts +4 -1
  27. package/dist/commands/documentation.js +79 -104
  28. package/dist/commands/feedback.d.ts +12 -9
  29. package/dist/commands/feedback.js +125 -257
  30. package/dist/commands/format.js +6 -13
  31. package/dist/commands/generation.d.ts +11 -0
  32. package/dist/commands/generation.js +204 -42
  33. package/dist/commands/gettingStarted.d.ts +1 -0
  34. package/dist/commands/gettingStarted.js +26 -0
  35. package/dist/commands/init.js +26 -24
  36. package/dist/commands/login.js +9 -8
  37. package/dist/commands/logout.js +2 -1
  38. package/dist/commands/notifications.d.ts +14 -0
  39. package/dist/commands/notifications.js +179 -0
  40. package/dist/commands/search.d.ts +13 -0
  41. package/dist/commands/search.js +198 -0
  42. package/dist/commands/upload.js +20 -17
  43. package/dist/commands/validate.js +15 -1
  44. package/dist/commands/versionsBrowse.d.ts +7 -0
  45. package/dist/commands/versionsBrowse.js +209 -0
  46. package/dist/commands/whoami.js +9 -8
  47. package/dist/errors.d.ts +9 -0
  48. package/dist/errors.js +52 -0
  49. package/dist/externalAssetPackValidation.d.ts +2 -0
  50. package/dist/externalAssetPackValidation.js +115 -0
  51. package/dist/http.js +1 -1
  52. package/dist/index.js +570 -630
  53. package/dist/messages.js +11 -11
  54. package/dist/output.d.ts +5 -0
  55. package/dist/output.js +45 -0
  56. package/dist/playwright.js +1 -1
  57. package/dist/refs.d.ts +18 -0
  58. package/dist/refs.js +105 -0
  59. package/node_modules/@playdrop/ai-client/dist/index.d.ts +42 -15
  60. package/node_modules/@playdrop/ai-client/dist/index.d.ts.map +1 -1
  61. package/node_modules/@playdrop/ai-client/package.json +1 -0
  62. package/node_modules/@playdrop/api-client/dist/client.d.ts +39 -27
  63. package/node_modules/@playdrop/api-client/dist/client.d.ts.map +1 -1
  64. package/node_modules/@playdrop/api-client/dist/client.js +280 -1669
  65. package/node_modules/@playdrop/api-client/dist/core/errors.d.ts +9 -0
  66. package/node_modules/@playdrop/api-client/dist/core/errors.d.ts.map +1 -0
  67. package/node_modules/@playdrop/api-client/dist/core/errors.js +46 -0
  68. package/node_modules/@playdrop/api-client/dist/core/request.d.ts +27 -0
  69. package/node_modules/@playdrop/api-client/dist/core/request.d.ts.map +1 -0
  70. package/node_modules/@playdrop/api-client/dist/core/request.js +122 -0
  71. package/node_modules/@playdrop/api-client/dist/domains/admin.d.ts +75 -0
  72. package/node_modules/@playdrop/api-client/dist/domains/admin.d.ts.map +1 -0
  73. package/node_modules/@playdrop/api-client/dist/domains/admin.js +282 -0
  74. package/node_modules/@playdrop/api-client/dist/domains/ai.d.ts +22 -0
  75. package/node_modules/@playdrop/api-client/dist/domains/ai.d.ts.map +1 -0
  76. package/node_modules/@playdrop/api-client/dist/domains/ai.js +15 -0
  77. package/node_modules/@playdrop/api-client/dist/domains/apps.d.ts +60 -0
  78. package/node_modules/@playdrop/api-client/dist/domains/apps.d.ts.map +1 -0
  79. package/node_modules/@playdrop/api-client/dist/domains/apps.js +301 -0
  80. package/node_modules/@playdrop/api-client/dist/domains/asset-packs.d.ts +59 -0
  81. package/node_modules/@playdrop/api-client/dist/domains/asset-packs.d.ts.map +1 -0
  82. package/node_modules/@playdrop/api-client/dist/domains/asset-packs.js +297 -0
  83. package/node_modules/@playdrop/api-client/dist/domains/assets.d.ts +62 -0
  84. package/node_modules/@playdrop/api-client/dist/domains/assets.d.ts.map +1 -0
  85. package/node_modules/@playdrop/api-client/dist/domains/assets.js +297 -0
  86. package/node_modules/@playdrop/api-client/dist/domains/auth.d.ts +28 -0
  87. package/node_modules/@playdrop/api-client/dist/domains/auth.d.ts.map +1 -0
  88. package/node_modules/@playdrop/api-client/dist/domains/auth.js +78 -0
  89. package/node_modules/@playdrop/api-client/dist/domains/comments.d.ts +29 -0
  90. package/node_modules/@playdrop/api-client/dist/domains/comments.d.ts.map +1 -0
  91. package/node_modules/@playdrop/api-client/dist/domains/comments.js +65 -0
  92. package/node_modules/@playdrop/api-client/dist/domains/me.d.ts +24 -0
  93. package/node_modules/@playdrop/api-client/dist/domains/me.d.ts.map +1 -0
  94. package/node_modules/@playdrop/api-client/dist/domains/me.js +35 -0
  95. package/node_modules/@playdrop/api-client/dist/domains/payments.d.ts +37 -0
  96. package/node_modules/@playdrop/api-client/dist/domains/payments.d.ts.map +1 -0
  97. package/node_modules/@playdrop/api-client/dist/domains/payments.js +148 -0
  98. package/node_modules/@playdrop/api-client/dist/domains/search.d.ts +27 -0
  99. package/node_modules/@playdrop/api-client/dist/domains/search.d.ts.map +1 -0
  100. package/node_modules/@playdrop/api-client/dist/domains/search.js +65 -0
  101. package/node_modules/@playdrop/api-client/dist/index.d.ts +33 -56
  102. package/node_modules/@playdrop/api-client/dist/index.d.ts.map +1 -1
  103. package/node_modules/@playdrop/api-client/dist/index.js +103 -44
  104. package/node_modules/@playdrop/api-client/package.json +3 -2
  105. package/node_modules/@playdrop/boxel-core/package.json +1 -1
  106. package/node_modules/@playdrop/boxel-three/dist/test/glb-skinned.test.js +1 -1
  107. package/node_modules/@playdrop/boxel-three/dist/test/instantiate.test.js +1 -1
  108. package/node_modules/@playdrop/boxel-three/dist/test/skinned-mesh.test.js +1 -1
  109. package/node_modules/@playdrop/boxel-three/package.json +2 -1
  110. package/node_modules/@playdrop/config/client-meta.json +5 -5
  111. package/node_modules/@playdrop/config/dist/src/constants.d.ts +5 -0
  112. package/node_modules/@playdrop/config/dist/src/constants.d.ts.map +1 -1
  113. package/node_modules/@playdrop/config/dist/src/constants.js +5 -1
  114. package/node_modules/@playdrop/config/dist/tsconfig.tsbuildinfo +1 -1
  115. package/node_modules/@playdrop/config/package.json +1 -1
  116. package/node_modules/@playdrop/types/dist/api.d.ts +178 -17
  117. package/node_modules/@playdrop/types/dist/api.d.ts.map +1 -1
  118. package/node_modules/@playdrop/types/dist/api.js +30 -1
  119. package/node_modules/@playdrop/types/dist/app.d.ts +0 -14
  120. package/node_modules/@playdrop/types/dist/app.d.ts.map +1 -1
  121. package/node_modules/@playdrop/types/dist/app.js +0 -10
  122. package/node_modules/@playdrop/types/dist/asset-pack.d.ts +11 -1
  123. package/node_modules/@playdrop/types/dist/asset-pack.d.ts.map +1 -1
  124. package/node_modules/@playdrop/types/dist/asset.d.ts +65 -0
  125. package/node_modules/@playdrop/types/dist/asset.d.ts.map +1 -1
  126. package/node_modules/@playdrop/types/dist/realtime.d.ts +26 -26
  127. package/node_modules/@playdrop/types/dist/realtime.d.ts.map +1 -1
  128. package/node_modules/@playdrop/types/dist/version.d.ts +5 -0
  129. package/node_modules/@playdrop/types/dist/version.d.ts.map +1 -1
  130. package/package.json +2 -3
  131. package/bin/playdrop-cli +0 -2
  132. package/dist/commands/asset-packs.d.ts +0 -27
  133. package/dist/commands/asset-packs.js +0 -508
  134. package/dist/commands/assets.d.ts +0 -35
  135. package/dist/commands/assets.js +0 -668
  136. package/dist/commands/list.d.ts +0 -7
  137. package/dist/commands/list.js +0 -347
  138. package/dist/commands/migrateCatalogueV2.d.ts +0 -1
  139. package/dist/commands/migrateCatalogueV2.js +0 -142
  140. package/dist/commands/versions.d.ts +0 -17
  141. package/dist/commands/versions.js +0 -384
@@ -1,21 +1,24 @@
1
- import { ApiError, UnsupportedClientError } from '@playdrop/types/api';
2
- import { FOLLOWING_FEED_SECTION_VALUES, FOLLOWING_SORT_VALUES, LIBRARY_CATEGORY_VALUES, LIBRARY_SORT_VALUES, NOTIFICATION_STATUS_VALUES, SAVED_ITEM_KIND_VALUES, } from '@playdrop/types';
3
- const DEFAULT_REQUEST_TIMEOUT_MS = 15000;
1
+ import { FOLLOWING_FEED_SECTION_VALUES, FOLLOWING_SORT_VALUES, ENGAGEMENT_EVENT_TYPE_VALUES, ENGAGEMENT_TARGET_KIND_VALUES, LIBRARY_CATEGORY_VALUES, LIBRARY_SORT_VALUES, NOTIFICATION_STATUS_VALUES, SAVED_ITEM_KIND_VALUES, SEARCH_ASSET_TYPE_VALUES, SEARCH_KIND_VALUES, SEARCH_MODE_VALUES, } from '@playdrop/types';
2
+ import { buildMeApiClientMethods } from './domains/me.js';
3
+ import { buildSearchApiClientMethods } from './domains/search.js';
4
+ import { buildAppsApiClientMethods } from './domains/apps.js';
5
+ import { buildAssetsApiClientMethods } from './domains/assets.js';
6
+ import { buildAssetPacksApiClientMethods } from './domains/asset-packs.js';
7
+ import { buildAuthApiClientMethods } from './domains/auth.js';
8
+ import { buildCommentsApiClientMethods } from './domains/comments.js';
9
+ import { buildPaymentsApiClientMethods } from './domains/payments.js';
10
+ import { buildAdminApiClientMethods } from './domains/admin.js';
11
+ import { buildAiApiClientMethods } from './domains/ai.js';
12
+ import { createBaseUrlResolver, createRequestExecutor, parseResponseBody, resolveRequestTimeoutMs, resolveUrl, } from './core/request.js';
13
+ import { handleApiError } from './core/errors.js';
4
14
  export function createApiClient(config = {}) {
5
15
  const fetchImpl = config.fetchImpl ?? globalThis.fetch?.bind(globalThis);
6
16
  if (!fetchImpl) {
7
17
  throw new Error('api_client_missing_fetch');
8
18
  }
9
- const requestTimeoutMs = (() => {
10
- if (config.requestTimeoutMs === undefined) {
11
- return DEFAULT_REQUEST_TIMEOUT_MS;
12
- }
13
- const parsed = Number(config.requestTimeoutMs);
14
- if (!Number.isFinite(parsed) || parsed <= 0) {
15
- throw new Error('invalid_api_request_timeout_ms');
16
- }
17
- return Math.floor(parsed);
18
- })();
19
+ const requestTimeoutMs = resolveRequestTimeoutMs(config.requestTimeoutMs);
20
+ const resolveBaseUrl = createBaseUrlResolver(config.baseUrl);
21
+ const getClientHeaders = () => (config.clientHeaders ? config.clientHeaders() : {});
19
22
  async function resolveToken() {
20
23
  if (config.tokenProvider) {
21
24
  const token = await config.tokenProvider();
@@ -31,34 +34,6 @@ export function createApiClient(config = {}) {
31
34
  }
32
35
  return null;
33
36
  }
34
- function resolveBaseUrl() {
35
- if (config.baseUrl) {
36
- return config.baseUrl;
37
- }
38
- if (typeof process !== 'undefined' && process.env.NEXT_PUBLIC_API_BASE) {
39
- return process.env.NEXT_PUBLIC_API_BASE;
40
- }
41
- if (typeof window !== 'undefined') {
42
- const { protocol, hostname } = window.location;
43
- if (hostname.includes('www.') && hostname.includes('.')) {
44
- return `${protocol}//api.${hostname.replace('www.', '')}`;
45
- }
46
- if (hostname === 'play.local' || hostname === 'www.localhost') {
47
- const apiDomain = hostname.includes('localhost') ? 'api.localhost' : 'api.local';
48
- return `${protocol}//${apiDomain}`;
49
- }
50
- return `${protocol}//${hostname}:4000`;
51
- }
52
- return 'http://localhost:4000';
53
- }
54
- function resolveUrl(base, path) {
55
- if (/^https?:/i.test(path)) {
56
- return path;
57
- }
58
- const normalizedBase = base.endsWith('/') ? base : `${base}/`;
59
- const trimmedPath = path.startsWith('/') ? path.slice(1) : path;
60
- return new URL(trimmedPath, normalizedBase).toString();
61
- }
62
37
  function buildIapQuery(params) {
63
38
  if (!params) {
64
39
  return '';
@@ -131,6 +106,12 @@ export function createApiClient(config = {}) {
131
106
  function normalizeSavedItemKindInput(kind) {
132
107
  return normalizeEnumInput(kind, SAVED_ITEM_KIND_VALUES, 'invalid_saved_item_kind');
133
108
  }
109
+ function normalizeEngagementEventTypeInput(eventType) {
110
+ return normalizeEnumInput(eventType, ENGAGEMENT_EVENT_TYPE_VALUES, 'invalid_engagement_event_type');
111
+ }
112
+ function normalizeEngagementTargetKindInput(targetKind) {
113
+ return normalizeEnumInput(targetKind, ENGAGEMENT_TARGET_KIND_VALUES, 'invalid_engagement_target_kind');
114
+ }
134
115
  function normalizeLibraryCategoryInput(category) {
135
116
  return normalizeEnumInput(category, LIBRARY_CATEGORY_VALUES, 'invalid_library_category');
136
117
  }
@@ -146,6 +127,15 @@ export function createApiClient(config = {}) {
146
127
  function normalizeNotificationStatusInput(status) {
147
128
  return normalizeEnumInput(status, NOTIFICATION_STATUS_VALUES, 'invalid_notification_status');
148
129
  }
130
+ function normalizeSearchKindInput(kind) {
131
+ return normalizeEnumInput(kind, SEARCH_KIND_VALUES, 'invalid_search_kind');
132
+ }
133
+ function normalizeSearchModeInput(mode) {
134
+ return normalizeEnumInput(mode, SEARCH_MODE_VALUES, 'invalid_search_mode');
135
+ }
136
+ function normalizeSearchAssetTypeInput(assetType) {
137
+ return normalizeEnumInput(assetType, SEARCH_ASSET_TYPE_VALUES, 'invalid_search_asset_type');
138
+ }
149
139
  function normalizePositiveIntegerInput(value, errorCode) {
150
140
  if (!Number.isInteger(value) || value <= 0) {
151
141
  throw new Error(errorCode);
@@ -165,6 +155,56 @@ export function createApiClient(config = {}) {
165
155
  }
166
156
  return trimmed;
167
157
  }
158
+ function normalizeWebPushSubscriptionRequest(requestBody) {
159
+ const subscription = requestBody?.subscription;
160
+ const endpoint = typeof subscription?.endpoint === 'string' ? subscription.endpoint.trim() : '';
161
+ const expirationTime = subscription?.expirationTime;
162
+ const p256dh = typeof subscription?.keys?.p256dh === 'string' ? subscription.keys.p256dh.trim() : '';
163
+ const auth = typeof subscription?.keys?.auth === 'string' ? subscription.keys.auth.trim() : '';
164
+ if (!endpoint || !endpoint.startsWith('https://')) {
165
+ throw new Error('invalid_web_push_subscription');
166
+ }
167
+ if (expirationTime !== null && expirationTime !== undefined && !Number.isFinite(expirationTime)) {
168
+ throw new Error('invalid_web_push_subscription');
169
+ }
170
+ if (!p256dh || !auth) {
171
+ throw new Error('invalid_web_push_subscription');
172
+ }
173
+ return {
174
+ subscription: {
175
+ endpoint,
176
+ expirationTime: expirationTime === undefined ? null : expirationTime,
177
+ keys: {
178
+ p256dh,
179
+ auth,
180
+ },
181
+ },
182
+ };
183
+ }
184
+ function buildCreatorAppMutationPath(creatorUsername, appName, suffix = '') {
185
+ const creator = normalizeCreatorItemSlug(creatorUsername, 'creator');
186
+ if (!appName) {
187
+ return `/creators/${encodeURIComponent(creator)}/apps${suffix}`;
188
+ }
189
+ const name = normalizeCreatorItemSlug(appName, 'name');
190
+ return `/creators/${encodeURIComponent(creator)}/apps/${encodeURIComponent(name)}${suffix}`;
191
+ }
192
+ function buildCreatorAssetMutationPath(creatorUsername, assetName, suffix = '') {
193
+ const creator = normalizeCreatorItemSlug(creatorUsername, 'creator');
194
+ if (!assetName) {
195
+ return `/creators/${encodeURIComponent(creator)}/assets${suffix}`;
196
+ }
197
+ const name = normalizeCreatorItemSlug(assetName, 'name');
198
+ return `/creators/${encodeURIComponent(creator)}/assets/${encodeURIComponent(name)}${suffix}`;
199
+ }
200
+ function buildCreatorAssetPackMutationPath(creatorUsername, packName, suffix = '') {
201
+ const creator = normalizeCreatorItemSlug(creatorUsername, 'creator');
202
+ if (!packName) {
203
+ return `/creators/${encodeURIComponent(creator)}/asset-packs${suffix}`;
204
+ }
205
+ const name = normalizeCreatorItemSlug(packName, 'name');
206
+ return `/creators/${encodeURIComponent(creator)}/asset-packs/${encodeURIComponent(name)}${suffix}`;
207
+ }
168
208
  function parseContentDispositionFilename(headerValue) {
169
209
  if (!headerValue) {
170
210
  return null;
@@ -181,162 +221,22 @@ export function createApiClient(config = {}) {
181
221
  const plainMatch = /filename="?([^";]+)"?/i.exec(headerValue);
182
222
  return plainMatch?.[1] ?? null;
183
223
  }
184
- async function parseResponseBody(response) {
185
- if (response.status === 204 || response.status === 205 || response.status === 304) {
186
- return undefined;
187
- }
188
- const contentType = response.headers.get('content-type') || '';
189
- if (contentType.includes('application/json')) {
190
- try {
191
- return (await response.clone().json());
192
- }
193
- catch {
194
- // fall through to text if parsing fails
195
- }
196
- }
197
- try {
198
- const text = await response.clone().text();
199
- return text;
200
- }
201
- catch {
202
- return undefined;
203
- }
204
- }
205
- function parseUnsupportedError(status, payload) {
206
- if (status !== 426 && status !== 400) {
207
- return null;
208
- }
209
- const data = (payload && typeof payload === 'object') ? payload : null;
210
- const code = typeof data?.error === 'string' ? data.error : undefined;
211
- const unsupportedCodes = new Set([
212
- 'unsupported_client',
213
- 'unsupported_client_version',
214
- 'unsupported_client_build',
215
- 'unsupported_platform_version',
216
- 'missing_client_metadata',
217
- ]);
218
- const isGuardResponse = status === 426 || (status === 400 && code !== undefined && unsupportedCodes.has(code));
219
- if (!isGuardResponse) {
220
- return null;
221
- }
222
- const message = typeof data?.message === 'string' ? data.message : 'Unsupported client version';
223
- return new UnsupportedClientError(code ?? 'unsupported_client', message, data ?? null);
224
- }
225
- async function request(req) {
226
- const base = resolveBaseUrl();
227
- const targetUrl = resolveUrl(base, req.path);
228
- const headers = new Headers();
229
- // Add client headers if provided
230
- if (config.clientHeaders) {
231
- const clientHeaders = config.clientHeaders();
232
- for (const [key, value] of Object.entries(clientHeaders)) {
233
- headers.set(key, value);
234
- }
235
- }
236
- headers.set('accept', 'application/json');
237
- if (req.body !== undefined && req.body !== null && req.method !== 'GET') {
238
- headers.set('content-type', 'application/json');
239
- }
240
- if (req.headers) {
241
- for (const [key, value] of Object.entries(req.headers)) {
242
- headers.set(key, value);
243
- }
244
- }
245
- const token = await resolveToken();
246
- if (token) {
247
- headers.set('authorization', `Bearer ${token}`);
248
- }
249
- const init = {
250
- method: req.method,
251
- headers,
252
- };
253
- if (req.body !== undefined && req.body !== null && req.method !== 'GET') {
254
- init.body = typeof req.body === 'string' ? req.body : JSON.stringify(req.body);
255
- }
256
- let timeoutHandle = null;
257
- let controller = null;
258
- if (typeof AbortController !== 'undefined') {
259
- controller = new AbortController();
260
- init.signal = controller.signal;
261
- timeoutHandle = setTimeout(() => {
262
- controller?.abort();
263
- }, requestTimeoutMs);
264
- }
265
- try {
266
- const response = await fetchImpl(targetUrl, init);
267
- const parsed = await parseResponseBody(response);
268
- return {
269
- status: response.status,
270
- body: parsed,
271
- headers: response.headers,
272
- };
273
- }
274
- catch (error) {
275
- if (controller?.signal.aborted) {
276
- throw new Error(`api_request_timeout:${req.method}:${req.path}`);
277
- }
278
- throw error;
279
- }
280
- finally {
281
- if (timeoutHandle) {
282
- clearTimeout(timeoutHandle);
283
- }
284
- }
285
- }
286
- function handleApiError(response, context) {
287
- const unsupported = parseUnsupportedError(response.status, response.body);
288
- if (unsupported) {
289
- throw unsupported;
290
- }
291
- const payload = response.body && typeof response.body === 'object' ? response.body : {};
292
- const code = typeof payload.error === 'string' ? payload.error : context;
293
- // Build a meaningful error message from the response
294
- let message;
295
- if (typeof payload.message === 'string') {
296
- message = payload.message;
297
- }
298
- else if (typeof payload.error === 'string') {
299
- // Use the error code as the base message
300
- message = payload.error;
301
- // Append errorPath if available (e.g., "ecs_invalid: systems.serverSim[0] uses reserved...")
302
- if (typeof payload.errorPath === 'string') {
303
- message = `${payload.error}: ${payload.errorPath}`;
304
- }
305
- // Append missing exports if available (for server_exports_missing)
306
- if (Array.isArray(payload.missing) && payload.missing.length > 0) {
307
- message = `${payload.error}: missing exports [${payload.missing.join(', ')}]`;
308
- }
309
- }
310
- else {
311
- message = `${context} failed`;
312
- }
313
- throw new ApiError(message, response.status, code);
314
- }
224
+ const request = createRequestExecutor({
225
+ fetchImpl,
226
+ resolveBaseUrl,
227
+ resolveUrl,
228
+ parseResponseBody,
229
+ resolveToken,
230
+ getClientHeaders,
231
+ requestTimeoutMs,
232
+ });
315
233
  // Implementation of all API methods
316
234
  return {
317
235
  request,
318
- async login(loginRequest) {
319
- const response = await request({
320
- method: 'POST',
321
- path: '/auth/login',
322
- body: loginRequest,
323
- });
324
- if (response.status !== 200) {
325
- handleApiError(response, 'login');
326
- }
327
- return response.body;
328
- },
329
- async register(registerRequest) {
330
- const response = await request({
331
- method: 'POST',
332
- path: '/auth/register',
333
- body: registerRequest,
334
- });
335
- if (response.status !== 201) {
336
- handleApiError(response, 'register');
337
- }
338
- return response.body;
339
- },
236
+ ...buildAuthApiClientMethods({
237
+ request,
238
+ handleApiError,
239
+ }),
340
240
  async me() {
341
241
  const response = await request({
342
242
  method: 'GET',
@@ -379,57 +279,6 @@ export function createApiClient(config = {}) {
379
279
  }
380
280
  return response.body;
381
281
  },
382
- async unlinkX() {
383
- const response = await request({
384
- method: 'POST',
385
- path: '/auth/x/unlink',
386
- });
387
- if (response.status !== 200) {
388
- handleApiError(response, 'unlink_x');
389
- }
390
- return response.body;
391
- },
392
- async unlinkGoogle() {
393
- const response = await request({
394
- method: 'POST',
395
- path: '/auth/google/unlink',
396
- });
397
- if (response.status !== 200) {
398
- handleApiError(response, 'unlink_google');
399
- }
400
- return response.body;
401
- },
402
- async fetchGooglePendingSignup(token) {
403
- const response = await request({
404
- method: 'GET',
405
- path: `/auth/google/pending/${encodeURIComponent(token)}`,
406
- });
407
- if (response.status !== 200) {
408
- handleApiError(response, 'fetch_google_pending_signup');
409
- }
410
- return response.body;
411
- },
412
- async checkUsernameAvailable(username) {
413
- const response = await request({
414
- method: 'GET',
415
- path: `/auth/username-available/${encodeURIComponent(username)}`,
416
- });
417
- if (response.status !== 200) {
418
- handleApiError(response, 'check_username_available');
419
- }
420
- return response.body;
421
- },
422
- async completeGoogleSignup(signupRequest) {
423
- const response = await request({
424
- method: 'POST',
425
- path: '/auth/google/complete-signup',
426
- body: signupRequest,
427
- });
428
- if (response.status !== 201) {
429
- handleApiError(response, 'complete_google_signup');
430
- }
431
- return response.body;
432
- },
433
282
  async fetchUserById(userId) {
434
283
  if (!Number.isFinite(userId) || userId <= 0) {
435
284
  throw new Error('invalid_user_id');
@@ -493,6 +342,52 @@ export function createApiClient(config = {}) {
493
342
  }
494
343
  return response.body;
495
344
  },
345
+ async likeItem(kind, creatorUsername, itemName) {
346
+ const normalizedKind = normalizeSavedItemKindInput(kind);
347
+ const creator = normalizeCreatorItemSlug(creatorUsername, 'creator');
348
+ const name = normalizeCreatorItemSlug(itemName, 'name');
349
+ const response = await request({
350
+ method: 'PUT',
351
+ path: `/me/likes/${encodeURIComponent(normalizedKind)}/${encodeURIComponent(creator)}/${encodeURIComponent(name)}`,
352
+ });
353
+ if (response.status !== 200) {
354
+ handleApiError(response, 'like_item');
355
+ }
356
+ return response.body;
357
+ },
358
+ async unlikeItem(kind, creatorUsername, itemName) {
359
+ const normalizedKind = normalizeSavedItemKindInput(kind);
360
+ const creator = normalizeCreatorItemSlug(creatorUsername, 'creator');
361
+ const name = normalizeCreatorItemSlug(itemName, 'name');
362
+ const response = await request({
363
+ method: 'DELETE',
364
+ path: `/me/likes/${encodeURIComponent(normalizedKind)}/${encodeURIComponent(creator)}/${encodeURIComponent(name)}`,
365
+ });
366
+ if (response.status !== 200) {
367
+ handleApiError(response, 'unlike_item');
368
+ }
369
+ return response.body;
370
+ },
371
+ async trackEngagementEvent(payload) {
372
+ const eventType = normalizeEngagementEventTypeInput(payload.eventType);
373
+ const targetKind = normalizeEngagementTargetKindInput(payload.targetKind);
374
+ const creatorUsername = normalizeCreatorItemSlug(payload.creatorUsername, 'creator');
375
+ const itemName = payload.itemName === undefined ? undefined : normalizeCreatorItemSlug(payload.itemName, 'name');
376
+ const response = await request({
377
+ method: 'POST',
378
+ path: '/engagement-events',
379
+ body: {
380
+ eventType,
381
+ targetKind,
382
+ creatorUsername,
383
+ ...(itemName !== undefined ? { itemName } : {}),
384
+ },
385
+ });
386
+ if (response.status !== 200) {
387
+ handleApiError(response, 'track_engagement_event');
388
+ }
389
+ return response.body;
390
+ },
496
391
  async fetchLibrary(options = {}) {
497
392
  const params = new URLSearchParams();
498
393
  if (options.category) {
@@ -607,1496 +502,212 @@ export function createApiClient(config = {}) {
607
502
  }
608
503
  return response.body;
609
504
  },
610
- async fetchApps() {
611
- const response = await request({
612
- method: 'GET',
613
- path: '/apps',
614
- });
615
- if (response.status !== 200) {
616
- handleApiError(response, 'fetch_apps');
617
- }
618
- return response.body;
619
- },
620
- async fetchAppsByType(type, options = {}) {
621
- const params = new URLSearchParams();
622
- if (typeof options.limit === 'number' && Number.isFinite(options.limit)) {
623
- params.set('limit', String(options.limit));
624
- }
625
- const query = params.toString();
505
+ async fetchWebPushConfig() {
626
506
  const response = await request({
627
507
  method: 'GET',
628
- path: `/apps/types/${encodeURIComponent(type)}` + (query ? `?${query}` : ''),
508
+ path: '/me/push/web/config',
629
509
  });
630
510
  if (response.status !== 200) {
631
- handleApiError(response, 'fetch_apps_by_type');
511
+ handleApiError(response, 'fetch_web_push_config');
632
512
  }
633
513
  return response.body;
634
514
  },
635
- async fetchAppsByCreator(creatorUsername, options = {}) {
636
- const normalizedCreator = creatorUsername.trim();
637
- const params = new URLSearchParams();
638
- if (typeof options.limit === 'number' && Number.isFinite(options.limit)) {
639
- params.set('limit', String(options.limit));
640
- }
641
- const query = params.toString();
515
+ async fetchWebPushSubscriptionStatus(requestBody) {
642
516
  const response = await request({
643
- method: 'GET',
644
- path: `/apps/creators/${encodeURIComponent(normalizedCreator)}` + (query ? `?${query}` : ''),
517
+ method: 'POST',
518
+ path: '/me/push/web/subscription/status',
519
+ body: normalizeWebPushSubscriptionRequest(requestBody),
645
520
  });
646
521
  if (response.status !== 200) {
647
- handleApiError(response, 'fetch_apps_by_creator');
522
+ handleApiError(response, 'fetch_web_push_subscription_status');
648
523
  }
649
524
  return response.body;
650
525
  },
651
- async fetchAppBySlug(creatorUsername, appName) {
526
+ async upsertWebPushSubscription(requestBody) {
652
527
  const response = await request({
653
- method: 'GET',
654
- path: `/apps/${encodeURIComponent(creatorUsername)}/${encodeURIComponent(appName)}`,
528
+ method: 'PUT',
529
+ path: '/me/push/web/subscription',
530
+ body: normalizeWebPushSubscriptionRequest(requestBody),
655
531
  });
656
532
  if (response.status !== 200) {
657
- handleApiError(response, 'fetch_app');
533
+ handleApiError(response, 'upsert_web_push_subscription');
658
534
  }
659
535
  return response.body;
660
536
  },
661
- async requestAppAccessToken(appId) {
537
+ async deleteWebPushSubscription(requestBody) {
662
538
  const response = await request({
663
- method: 'POST',
664
- path: `/apps/${encodeURIComponent(String(appId))}/token`,
665
- });
666
- if (response.status !== 200) {
667
- handleApiError(response, 'request_app_access_token');
668
- }
669
- return response.body;
670
- },
671
- async sendAppLog(appId, entry) {
539
+ method: 'DELETE',
540
+ path: '/me/push/web/subscription',
541
+ body: normalizeWebPushSubscriptionRequest(requestBody),
542
+ });
543
+ if (response.status !== 200) {
544
+ handleApiError(response, 'delete_web_push_subscription');
545
+ }
546
+ return response.body;
547
+ },
548
+ ...buildSearchApiClientMethods({
549
+ request,
550
+ handleApiError,
551
+ normalizeSearchModeInput,
552
+ normalizeSearchKindInput,
553
+ normalizeSearchAssetTypeInput,
554
+ normalizePositiveIntegerInput,
555
+ }),
556
+ ...buildCommentsApiClientMethods({
557
+ request,
558
+ handleApiError,
559
+ normalizeSavedItemKindInput,
560
+ normalizeCreatorItemSlug,
561
+ normalizePositiveIntegerInput,
562
+ }),
563
+ ...buildAppsApiClientMethods({
564
+ request,
565
+ handleApiError,
566
+ fetchImpl,
567
+ resolveBaseUrl,
568
+ resolveUrl,
569
+ parseResponseBody,
570
+ resolveToken,
571
+ getClientHeaders: () => config.clientHeaders ? config.clientHeaders() : {},
572
+ buildCreatorAppMutationPath,
573
+ normalizeCreatorItemSlug,
574
+ normalizeSemverInput,
575
+ parseContentDispositionFilename,
576
+ }),
577
+ ...buildAssetsApiClientMethods({
578
+ request,
579
+ handleApiError,
580
+ fetchImpl,
581
+ resolveBaseUrl,
582
+ resolveUrl,
583
+ parseResponseBody,
584
+ resolveToken,
585
+ getClientHeaders: () => config.clientHeaders ? config.clientHeaders() : {},
586
+ buildCreatorAssetMutationPath,
587
+ normalizeAssetRevisionInput,
588
+ parseContentDispositionFilename,
589
+ }),
590
+ ...buildAssetPacksApiClientMethods({
591
+ request,
592
+ handleApiError,
593
+ fetchImpl,
594
+ resolveBaseUrl,
595
+ resolveUrl,
596
+ parseResponseBody,
597
+ resolveToken,
598
+ getClientHeaders: () => config.clientHeaders ? config.clientHeaders() : {},
599
+ buildCreatorAssetPackMutationPath,
600
+ normalizeSemverInput,
601
+ parseContentDispositionFilename,
602
+ }),
603
+ ...buildMeApiClientMethods({ request, handleApiError }),
604
+ async batchUpsertGraphRelations(body) {
672
605
  const response = await request({
673
606
  method: 'POST',
674
- path: `/apps/${encodeURIComponent(String(appId))}/logs`,
675
- body: entry,
676
- });
677
- if (response.status !== 200) {
678
- handleApiError(response, 'send_app_log');
679
- }
680
- return response.body;
681
- },
682
- async fetchCreatorApps() {
683
- const response = await request({
684
- method: 'GET',
685
- path: '/creator/apps',
607
+ path: '/me/graph/relations:batchUpsert',
608
+ body,
686
609
  });
687
610
  if (response.status !== 200) {
688
- handleApiError(response, 'fetch_creator_apps');
611
+ handleApiError(response, 'batch_upsert_graph_relations');
689
612
  }
690
613
  return response.body;
691
614
  },
692
- async createApp(createRequest) {
615
+ async submitFeedback(feedbackRequest) {
693
616
  const response = await request({
694
617
  method: 'POST',
695
- path: '/creator/apps',
696
- body: createRequest,
618
+ path: '/feedback',
619
+ body: feedbackRequest,
697
620
  });
698
- if (response.status !== 200) {
699
- handleApiError(response, 'create_app');
621
+ if (response.status !== 201 && response.status !== 200) {
622
+ handleApiError(response, 'submit_feedback');
700
623
  }
701
624
  return response.body;
702
625
  },
703
- async updateApp(name, updateRequest, options = {}) {
626
+ async listFeedback(options = {}) {
704
627
  const params = new URLSearchParams();
705
- if (typeof options.creatorUsername === 'string' && options.creatorUsername.trim().length > 0) {
706
- params.set('creatorUsername', options.creatorUsername.trim());
707
- }
708
- const query = params.toString();
709
- const response = await request({
710
- method: 'PATCH',
711
- path: `/creator/apps/${encodeURIComponent(name)}${query ? `?${query}` : ''}`,
712
- body: updateRequest,
713
- });
714
- if (response.status !== 200) {
715
- handleApiError(response, 'update_app');
716
- }
717
- return response.body;
718
- },
719
- async uploadAppVersion(appName, options) {
720
- const base = resolveBaseUrl();
721
- const form = new FormData();
722
- // Required field
723
- form.append('version', options.version);
724
- // Optional text fields
725
- if (options.releaseNotes !== undefined) {
726
- form.append('releaseNotes', options.releaseNotes);
727
- }
728
- if (options.visibility !== undefined) {
729
- form.append('visibility', options.visibility);
730
- }
731
- if (options.surfaceTargets && options.surfaceTargets.length > 0) {
732
- form.append('surfaceTargets', JSON.stringify(options.surfaceTargets));
733
- }
734
- if (options.entryPoint !== undefined) {
735
- form.append('entryPoint', options.entryPoint);
736
- }
737
- if (options.setAsCurrent !== undefined) {
738
- form.append('setAsCurrent', String(options.setAsCurrent));
739
- }
740
- if (options.externalUrl !== undefined) {
741
- form.append('externalUrl', options.externalUrl);
742
- }
743
- // App metadata fields (for creating app if it doesn't exist)
744
- if (options.displayName !== undefined) {
745
- form.append('displayName', options.displayName);
746
- }
747
- if (options.description !== undefined) {
748
- form.append('description', options.description);
749
- }
750
- if (options.type !== undefined) {
751
- form.append('type', options.type);
752
- }
753
- if (options.emoji !== undefined) {
754
- form.append('emoji', options.emoji);
755
- }
756
- if (options.color !== undefined) {
757
- form.append('color', options.color);
758
- }
759
- // Admin-only field
760
- if (options.creatorUsername !== undefined) {
761
- form.append('creatorUsername', options.creatorUsername);
762
- }
763
- // Bundle files (HOSTED mode)
764
- if (options.bundle) {
765
- form.append('bundle', options.bundle);
766
- }
767
- if (options.source) {
768
- form.append('source', options.source);
769
- }
770
- if (options.ecs) {
771
- form.append('ecs', options.ecs);
772
- }
773
- if (options.server) {
774
- form.append('server', options.server);
775
- }
776
- // Listing assets - images must be PNG, videos must be MP4
777
- if (options.icon) {
778
- form.append('icon', options.icon);
779
- }
780
- if (options.heroPortrait) {
781
- form.append('heroPortrait', options.heroPortrait);
782
- }
783
- if (options.heroLandscape) {
784
- form.append('heroLandscape', options.heroLandscape);
785
- }
786
- if (options.screenshotsPortrait) {
787
- for (const screenshot of options.screenshotsPortrait) {
788
- form.append('screenshotsPortrait', screenshot);
789
- }
790
- }
791
- if (options.screenshotsLandscape) {
792
- for (const screenshot of options.screenshotsLandscape) {
793
- form.append('screenshotsLandscape', screenshot);
794
- }
795
- }
796
- if (options.videosPortrait) {
797
- for (const video of options.videosPortrait) {
798
- form.append('videosPortrait', video);
799
- }
800
- }
801
- if (options.videosLandscape) {
802
- for (const video of options.videosLandscape) {
803
- form.append('videosLandscape', video);
804
- }
628
+ if (options.limit !== undefined) {
629
+ params.set('limit', String(options.limit));
805
630
  }
806
- const path = `/creator/apps/${encodeURIComponent(appName)}/versions`;
807
- const headers = new Headers();
808
- if (config.clientHeaders) {
809
- const clientHeaders = config.clientHeaders();
810
- for (const [key, value] of Object.entries(clientHeaders)) {
811
- headers.set(key, value);
812
- }
631
+ if (options.offset !== undefined) {
632
+ params.set('offset', String(options.offset));
813
633
  }
814
- const token = await resolveToken();
815
- if (token) {
816
- headers.set('authorization', `Bearer ${token}`);
634
+ if (typeof options.source === 'string' && options.source.trim().length > 0) {
635
+ params.set('source', options.source.trim());
817
636
  }
818
- const response = await fetchImpl(resolveUrl(base, path), {
819
- method: 'POST',
820
- headers,
821
- body: form,
822
- });
823
- const parsed = await parseResponseBody(response);
824
- const apiResponse = { status: response.status, body: parsed, headers: response.headers };
825
- if (response.status !== 201) {
826
- handleApiError(apiResponse, 'upload_app_version');
637
+ if (options.userId !== undefined) {
638
+ params.set('userId', String(options.userId));
827
639
  }
828
- return parsed;
829
- },
830
- async listAppVersions(creatorUsername, appName) {
831
- const path = `/apps/${encodeURIComponent(creatorUsername)}/${encodeURIComponent(appName)}/versions`;
640
+ const query = params.toString();
641
+ const path = `/feedback${query ? `?${query}` : ''}`;
832
642
  const response = await request({
833
643
  method: 'GET',
834
644
  path,
835
645
  });
836
646
  if (response.status !== 200) {
837
- handleApiError(response, 'list_app_versions');
647
+ handleApiError(response, 'list_feedback');
838
648
  }
839
649
  return response.body;
840
650
  },
841
- async getAppVersion(creatorUsername, appName, version) {
842
- const path = `/apps/${encodeURIComponent(creatorUsername)}/${encodeURIComponent(appName)}/versions/${encodeURIComponent(version)}`;
651
+ async deleteFeedback(id) {
843
652
  const response = await request({
844
- method: 'GET',
845
- path,
653
+ method: 'DELETE',
654
+ path: `/feedback/${encodeURIComponent(String(id))}`,
846
655
  });
847
656
  if (response.status !== 200) {
848
- handleApiError(response, 'get_app_version');
657
+ handleApiError(response, 'delete_feedback');
849
658
  }
850
659
  return response.body;
851
660
  },
852
- async updateAppVersion(appName, version, updates, options = {}) {
853
- const params = new URLSearchParams();
854
- if (typeof options.creatorUsername === 'string' && options.creatorUsername.trim().length > 0) {
855
- params.set('creatorUsername', options.creatorUsername.trim());
856
- }
857
- const query = params.toString();
858
- const path = `/creator/apps/${encodeURIComponent(appName)}/versions/${encodeURIComponent(version)}${query ? `?${query}` : ''}`;
661
+ async setSelectedProfileAsset(profileAssetRequest) {
859
662
  const response = await request({
860
- method: 'PATCH',
861
- path,
862
- body: updates,
663
+ method: 'POST',
664
+ path: '/me/profile-asset',
665
+ body: profileAssetRequest,
863
666
  });
864
667
  if (response.status !== 200) {
865
- handleApiError(response, 'update_app_version');
668
+ handleApiError(response, 'set_profile_asset');
866
669
  }
867
670
  return response.body;
868
671
  },
869
- async deleteAppVersion(appName, version, options = {}) {
672
+ async fetchHome(options = {}) {
870
673
  const params = new URLSearchParams();
871
- if (typeof options.creatorUsername === 'string' && options.creatorUsername.trim().length > 0) {
872
- params.set('creatorUsername', options.creatorUsername.trim());
674
+ if (typeof options.section === 'string' && options.section.trim().length > 0) {
675
+ params.set('section', options.section.trim());
676
+ }
677
+ if (typeof options.limit === 'number') {
678
+ params.set('limit', String(options.limit));
679
+ }
680
+ if (typeof options.offset === 'number') {
681
+ params.set('offset', String(options.offset));
873
682
  }
874
683
  const query = params.toString();
875
- const path = `/creator/apps/${encodeURIComponent(appName)}/versions/${encodeURIComponent(version)}${query ? `?${query}` : ''}`;
876
684
  const response = await request({
877
- method: 'DELETE',
878
- path,
685
+ method: 'GET',
686
+ path: `/home${query ? `?${query}` : ''}`,
879
687
  });
880
688
  if (response.status !== 200) {
881
- handleApiError(response, 'delete_app_version');
882
- }
883
- return response.body;
884
- },
885
- async createAssetVersion(name, options, mutationTarget = {}) {
886
- const assetName = typeof name === 'string' ? name.trim() : '';
887
- if (!assetName) {
888
- throw new Error('invalid_asset_name');
889
- }
890
- if (!Array.isArray(options.files) || options.files.length === 0) {
891
- throw new Error('missing_asset_files');
892
- }
893
- const form = new FormData();
894
- form.set('category', options.category);
895
- form.set('subcategory', options.subcategory);
896
- form.set('format', options.format);
897
- if (options.visibility) {
898
- form.set('visibility', options.visibility);
899
- }
900
- if (options.sourceKind) {
901
- form.set('sourceKind', options.sourceKind);
902
- }
903
- if (typeof options.sourceAppVersionId === 'number') {
904
- form.set('sourceAppVersionId', String(options.sourceAppVersionId));
905
- }
906
- if (typeof options.sourceGenerationId === 'string' && options.sourceGenerationId.trim().length > 0) {
907
- form.set('sourceGenerationId', options.sourceGenerationId.trim());
908
- }
909
- if (typeof options.shopListed === 'boolean') {
910
- form.set('shopListed', options.shopListed ? 'true' : 'false');
911
- }
912
- if (typeof options.shopPriceCredits === 'number') {
913
- form.set('shopPriceCredits', String(options.shopPriceCredits));
914
- }
915
- if (typeof options.displayName === 'string' && options.displayName.trim().length > 0) {
916
- form.set('displayName', options.displayName.trim());
917
- }
918
- if (typeof options.description === 'string') {
919
- form.set('description', options.description);
920
- }
921
- for (let index = 0; index < options.files.length; index++) {
922
- const item = options.files[index];
923
- const fieldName = typeof item.fieldName === 'string' && item.fieldName.trim().length > 0
924
- ? item.fieldName.trim()
925
- : 'file';
926
- if (typeof item.filename === 'string' && item.filename.trim().length > 0) {
927
- form.append(fieldName, item.file, item.filename.trim());
928
- }
929
- else {
930
- form.append(fieldName, item.file);
931
- }
932
- }
933
- const base = resolveBaseUrl();
934
- const headers = new Headers();
935
- if (config.clientHeaders) {
936
- const clientHeaders = config.clientHeaders();
937
- for (const [key, value] of Object.entries(clientHeaders)) {
938
- headers.set(key, value);
939
- }
940
- }
941
- const token = await resolveToken();
942
- if (token) {
943
- headers.set('authorization', `Bearer ${token}`);
944
- }
945
- const params = new URLSearchParams();
946
- if (typeof mutationTarget.creatorUsername === 'string' && mutationTarget.creatorUsername.trim().length > 0) {
947
- params.set('creatorUsername', mutationTarget.creatorUsername.trim());
948
- }
949
- const query = params.toString();
950
- const path = `/creator/assets/${encodeURIComponent(assetName)}/versions${query ? `?${query}` : ''}`;
951
- const response = await fetchImpl(resolveUrl(base, path), {
952
- method: 'POST',
953
- headers,
954
- body: form,
955
- });
956
- const parsed = await parseResponseBody(response);
957
- const apiResponse = { status: response.status, body: parsed, headers: response.headers };
958
- if (response.status !== 201 && response.status !== 200) {
959
- handleApiError(apiResponse, 'create_asset_version');
960
- }
961
- return parsed;
962
- },
963
- async listAssetCategories() {
964
- const response = await request({
965
- method: 'GET',
966
- path: '/asset-categories',
967
- });
968
- if (response.status !== 200) {
969
- handleApiError(response, 'list_asset_categories');
970
- }
971
- return response.body;
972
- },
973
- async listAssets(options = {}) {
974
- const params = new URLSearchParams();
975
- if (typeof options.limit === 'number') {
976
- params.set('limit', String(options.limit));
977
- }
978
- if (typeof options.offset === 'number') {
979
- params.set('offset', String(options.offset));
980
- }
981
- if (typeof options.category === 'string' && options.category.trim().length > 0) {
982
- params.set('category', options.category.trim());
983
- }
984
- if (typeof options.subcategory === 'string' && options.subcategory.trim().length > 0) {
985
- params.set('subcategory', options.subcategory.trim());
986
- }
987
- const query = params.toString();
988
- const path = `/assets${query ? `?${query}` : ''}`;
989
- const response = await request({
990
- method: 'GET',
991
- path,
992
- });
993
- if (response.status !== 200) {
994
- handleApiError(response, 'list_assets');
995
- }
996
- return response.body;
997
- },
998
- async listAssetsForCreator(creatorUsername, options = {}) {
999
- const params = new URLSearchParams();
1000
- if (typeof options.limit === 'number') {
1001
- params.set('limit', String(options.limit));
1002
- }
1003
- if (typeof options.offset === 'number') {
1004
- params.set('offset', String(options.offset));
1005
- }
1006
- if (typeof options.category === 'string' && options.category.trim().length > 0) {
1007
- params.set('category', options.category.trim());
1008
- }
1009
- if (typeof options.subcategory === 'string' && options.subcategory.trim().length > 0) {
1010
- params.set('subcategory', options.subcategory.trim());
1011
- }
1012
- const query = params.toString();
1013
- const path = `/creators/${encodeURIComponent(creatorUsername)}/assets${query ? `?${query}` : ''}`;
1014
- const response = await request({
1015
- method: 'GET',
1016
- path,
1017
- });
1018
- if (response.status !== 200) {
1019
- handleApiError(response, 'list_assets_for_creator');
1020
- }
1021
- return response.body;
1022
- },
1023
- async fetchAssetBySlug(creatorUsername, assetName) {
1024
- const path = `/assets/${encodeURIComponent(creatorUsername)}/${encodeURIComponent(assetName)}`;
1025
- const response = await request({
1026
- method: 'GET',
1027
- path,
1028
- });
1029
- if (response.status !== 200) {
1030
- handleApiError(response, 'fetch_asset_by_slug');
1031
- }
1032
- return response.body;
1033
- },
1034
- async listAssetVersions(creatorUsername, assetName, options = {}) {
1035
- const params = new URLSearchParams();
1036
- if (typeof options.limit === 'number') {
1037
- params.set('limit', String(options.limit));
1038
- }
1039
- if (typeof options.offset === 'number') {
1040
- params.set('offset', String(options.offset));
1041
- }
1042
- const query = params.toString();
1043
- const path = `/assets/${encodeURIComponent(creatorUsername)}/${encodeURIComponent(assetName)}/versions${query ? `?${query}` : ''}`;
1044
- const response = await request({
1045
- method: 'GET',
1046
- path,
1047
- });
1048
- if (response.status !== 200) {
1049
- handleApiError(response, 'list_asset_versions');
1050
- }
1051
- return response.body;
1052
- },
1053
- async updateAsset(name, requestBody, mutationTarget = {}) {
1054
- const assetName = typeof name === 'string' ? name.trim() : '';
1055
- if (!assetName) {
1056
- throw new Error('invalid_asset_name');
1057
- }
1058
- const params = new URLSearchParams();
1059
- if (typeof mutationTarget.creatorUsername === 'string' && mutationTarget.creatorUsername.trim().length > 0) {
1060
- params.set('creatorUsername', mutationTarget.creatorUsername.trim());
1061
- }
1062
- const query = params.toString();
1063
- const response = await request({
1064
- method: 'PATCH',
1065
- path: `/creator/assets/${encodeURIComponent(assetName)}${query ? `?${query}` : ''}`,
1066
- body: requestBody,
1067
- });
1068
- if (response.status !== 200) {
1069
- handleApiError(response, 'update_asset');
1070
- }
1071
- return response.body;
1072
- },
1073
- async updateAssetVersion(name, revision, requestBody, mutationTarget = {}) {
1074
- const assetName = typeof name === 'string' ? name.trim() : '';
1075
- if (!assetName) {
1076
- throw new Error('invalid_asset_name');
1077
- }
1078
- const normalizedRevision = normalizeAssetRevisionInput(revision);
1079
- const params = new URLSearchParams();
1080
- if (typeof mutationTarget.creatorUsername === 'string' && mutationTarget.creatorUsername.trim().length > 0) {
1081
- params.set('creatorUsername', mutationTarget.creatorUsername.trim());
1082
- }
1083
- const query = params.toString();
1084
- const response = await request({
1085
- method: 'PATCH',
1086
- path: `/creator/assets/${encodeURIComponent(assetName)}/versions/${encodeURIComponent(normalizedRevision)}${query ? `?${query}` : ''}`,
1087
- body: requestBody,
1088
- });
1089
- if (response.status !== 200) {
1090
- handleApiError(response, 'update_asset_version');
1091
- }
1092
- return response.body;
1093
- },
1094
- async deleteAssetVersion(name, revision, mutationTarget = {}) {
1095
- const assetName = typeof name === 'string' ? name.trim() : '';
1096
- if (!assetName) {
1097
- throw new Error('invalid_asset_name');
1098
- }
1099
- const normalizedRevision = normalizeAssetRevisionInput(revision);
1100
- const params = new URLSearchParams();
1101
- if (typeof mutationTarget.creatorUsername === 'string' && mutationTarget.creatorUsername.trim().length > 0) {
1102
- params.set('creatorUsername', mutationTarget.creatorUsername.trim());
1103
- }
1104
- const query = params.toString();
1105
- const response = await request({
1106
- method: 'DELETE',
1107
- path: `/creator/assets/${encodeURIComponent(assetName)}/versions/${encodeURIComponent(normalizedRevision)}${query ? `?${query}` : ''}`,
1108
- });
1109
- if (response.status !== 200) {
1110
- handleApiError(response, 'delete_asset_version');
1111
- }
1112
- return response.body;
1113
- },
1114
- async deleteAsset(name, mutationTarget = {}) {
1115
- const assetName = typeof name === 'string' ? name.trim() : '';
1116
- if (!assetName) {
1117
- throw new Error('invalid_asset_name');
1118
- }
1119
- const params = new URLSearchParams();
1120
- if (typeof mutationTarget.creatorUsername === 'string' && mutationTarget.creatorUsername.trim().length > 0) {
1121
- params.set('creatorUsername', mutationTarget.creatorUsername.trim());
1122
- }
1123
- const query = params.toString();
1124
- const response = await request({
1125
- method: 'DELETE',
1126
- path: `/creator/assets/${encodeURIComponent(assetName)}${query ? `?${query}` : ''}`,
1127
- });
1128
- if (response.status !== 200) {
1129
- handleApiError(response, 'delete_asset');
1130
- }
1131
- return response.body;
1132
- },
1133
- async downloadAssetFile(creatorUsername, assetName, revision, options = {}) {
1134
- const creator = typeof creatorUsername === 'string' ? creatorUsername.trim() : '';
1135
- const name = typeof assetName === 'string' ? assetName.trim() : '';
1136
- if (!creator || !name) {
1137
- throw new Error('invalid_asset_key');
1138
- }
1139
- const normalizedRevision = normalizeAssetRevisionInput(revision);
1140
- const params = new URLSearchParams();
1141
- if (typeof options.role === 'string' && options.role.trim().length > 0) {
1142
- params.set('role', options.role.trim());
1143
- }
1144
- const query = params.toString();
1145
- const path = `/assets/${encodeURIComponent(creator)}/${encodeURIComponent(name)}/versions/${encodeURIComponent(normalizedRevision)}/file${query ? `?${query}` : ''}`;
1146
- const base = resolveBaseUrl();
1147
- const headers = new Headers();
1148
- if (config.clientHeaders) {
1149
- const clientHeaders = config.clientHeaders();
1150
- for (const [key, value] of Object.entries(clientHeaders)) {
1151
- headers.set(key, value);
1152
- }
1153
- }
1154
- const token = await resolveToken();
1155
- if (token) {
1156
- headers.set('authorization', `Bearer ${token}`);
1157
- }
1158
- const response = await fetchImpl(resolveUrl(base, path), {
1159
- method: 'GET',
1160
- headers,
1161
- });
1162
- if (!response.ok) {
1163
- const parsed = await parseResponseBody(response);
1164
- handleApiError({ status: response.status, body: parsed, headers: response.headers }, 'download_asset_file');
1165
- }
1166
- return response.blob();
1167
- },
1168
- async downloadAssetSource(creatorUsername, assetName, revision) {
1169
- const creator = typeof creatorUsername === 'string' ? creatorUsername.trim() : '';
1170
- const name = typeof assetName === 'string' ? assetName.trim() : '';
1171
- if (!creator || !name) {
1172
- throw new Error('invalid_asset_key');
1173
- }
1174
- const normalizedRevision = normalizeAssetRevisionInput(revision);
1175
- const path = `/assets/${encodeURIComponent(creator)}/${encodeURIComponent(name)}/versions/${encodeURIComponent(normalizedRevision)}/source`;
1176
- const base = resolveBaseUrl();
1177
- const headers = new Headers();
1178
- if (config.clientHeaders) {
1179
- const clientHeaders = config.clientHeaders();
1180
- for (const [key, value] of Object.entries(clientHeaders)) {
1181
- headers.set(key, value);
1182
- }
1183
- }
1184
- const token = await resolveToken();
1185
- if (token) {
1186
- headers.set('authorization', `Bearer ${token}`);
1187
- }
1188
- const response = await fetchImpl(resolveUrl(base, path), {
1189
- method: 'GET',
1190
- headers,
1191
- });
1192
- if (!response.ok) {
1193
- const parsed = await parseResponseBody(response);
1194
- handleApiError({ status: response.status, body: parsed, headers: response.headers }, 'download_asset_source');
1195
- }
1196
- const blob = await response.blob();
1197
- const filename = parseContentDispositionFilename(response.headers.get('content-disposition'))
1198
- ?? `${name}-r${normalizedRevision}-source.zip`;
1199
- const headerSize = response.headers.get('content-length');
1200
- const parsedSize = headerSize ? Number.parseInt(headerSize, 10) : Number.NaN;
1201
- const checksumHeader = response.headers.get('x-asset-source-checksum');
1202
- return {
1203
- blob,
1204
- metadata: {
1205
- filename,
1206
- sizeBytes: Number.isFinite(parsedSize) && parsedSize >= 0 ? parsedSize : blob.size,
1207
- checksum: checksumHeader ?? null,
1208
- },
1209
- };
1210
- },
1211
- async createAssetPackVersion(name, body, mutationTarget = {}) {
1212
- const packName = typeof name === 'string' ? name.trim() : '';
1213
- if (!packName) {
1214
- throw new Error('invalid_pack_name');
1215
- }
1216
- const params = new URLSearchParams();
1217
- if (typeof mutationTarget.creatorUsername === 'string' && mutationTarget.creatorUsername.trim().length > 0) {
1218
- params.set('creatorUsername', mutationTarget.creatorUsername.trim());
1219
- }
1220
- const query = params.toString();
1221
- const response = await request({
1222
- method: 'POST',
1223
- path: `/creator/asset-packs/${encodeURIComponent(packName)}/versions${query ? `?${query}` : ''}`,
1224
- body,
1225
- });
1226
- if (response.status !== 201 && response.status !== 200) {
1227
- handleApiError(response, 'create_asset_pack_version');
1228
- }
1229
- return response.body;
1230
- },
1231
- async uploadAssetPackVersion(name, options, mutationTarget = {}) {
1232
- const packName = typeof name === 'string' ? name.trim() : '';
1233
- if (!packName) {
1234
- throw new Error('invalid_pack_name');
1235
- }
1236
- if (!options || !options.request) {
1237
- throw new Error('invalid_pack_upload_request');
1238
- }
1239
- const requestBody = options.request;
1240
- const form = new FormData();
1241
- form.append('version', requestBody.version);
1242
- if (requestBody.visibility !== undefined) {
1243
- form.append('visibility', requestBody.visibility);
1244
- }
1245
- if (requestBody.releaseNotes !== undefined) {
1246
- form.append('releaseNotes', requestBody.releaseNotes);
1247
- }
1248
- if (requestBody.displayName !== undefined) {
1249
- form.append('displayName', requestBody.displayName);
1250
- }
1251
- if (requestBody.description !== undefined) {
1252
- form.append('description', requestBody.description);
1253
- }
1254
- if (requestBody.previewAppVersionId !== undefined) {
1255
- form.append('previewAppVersionId', String(requestBody.previewAppVersionId));
1256
- }
1257
- form.append('assets', JSON.stringify(requestBody.assets ?? []));
1258
- const relations = requestBody.relations;
1259
- if (Array.isArray(relations) && relations.length > 0) {
1260
- form.append('relations', JSON.stringify(relations));
1261
- }
1262
- if (options.icon) {
1263
- form.append('icon', options.icon);
1264
- }
1265
- if (options.heroPortrait) {
1266
- form.append('heroPortrait', options.heroPortrait);
1267
- }
1268
- if (options.heroLandscape) {
1269
- form.append('heroLandscape', options.heroLandscape);
1270
- }
1271
- if (options.screenshotsPortrait) {
1272
- for (const screenshot of options.screenshotsPortrait) {
1273
- form.append('screenshotsPortrait', screenshot);
1274
- }
1275
- }
1276
- if (options.screenshotsLandscape) {
1277
- for (const screenshot of options.screenshotsLandscape) {
1278
- form.append('screenshotsLandscape', screenshot);
1279
- }
1280
- }
1281
- if (options.videosPortrait) {
1282
- for (const video of options.videosPortrait) {
1283
- form.append('videosPortrait', video);
1284
- }
1285
- }
1286
- if (options.videosLandscape) {
1287
- for (const video of options.videosLandscape) {
1288
- form.append('videosLandscape', video);
1289
- }
1290
- }
1291
- const params = new URLSearchParams();
1292
- if (typeof mutationTarget.creatorUsername === 'string' && mutationTarget.creatorUsername.trim().length > 0) {
1293
- params.set('creatorUsername', mutationTarget.creatorUsername.trim());
1294
- }
1295
- const query = params.toString();
1296
- const path = `/creator/asset-packs/${encodeURIComponent(packName)}/versions${query ? `?${query}` : ''}`;
1297
- const base = resolveBaseUrl();
1298
- const headers = new Headers();
1299
- if (config.clientHeaders) {
1300
- const clientHeaders = config.clientHeaders();
1301
- for (const [key, value] of Object.entries(clientHeaders)) {
1302
- headers.set(key, value);
1303
- }
1304
- }
1305
- const token = await resolveToken();
1306
- if (token) {
1307
- headers.set('authorization', `Bearer ${token}`);
1308
- }
1309
- const response = await fetchImpl(resolveUrl(base, path), {
1310
- method: 'POST',
1311
- headers,
1312
- body: form,
1313
- });
1314
- const parsed = await parseResponseBody(response);
1315
- const apiResponse = { status: response.status, body: parsed, headers: response.headers };
1316
- if (response.status !== 201 && response.status !== 200) {
1317
- handleApiError(apiResponse, 'upload_asset_pack_version');
1318
- }
1319
- return parsed;
1320
- },
1321
- async listAssetPacks(options = {}) {
1322
- const params = new URLSearchParams();
1323
- if (typeof options.limit === 'number') {
1324
- params.set('limit', String(options.limit));
1325
- }
1326
- if (typeof options.offset === 'number') {
1327
- params.set('offset', String(options.offset));
1328
- }
1329
- if (typeof options.containsCategory === 'string' && options.containsCategory.trim().length > 0) {
1330
- params.set('containsCategory', options.containsCategory.trim());
1331
- }
1332
- if (typeof options.containsSubcategory === 'string' && options.containsSubcategory.trim().length > 0) {
1333
- params.set('containsSubcategory', options.containsSubcategory.trim());
1334
- }
1335
- const query = params.toString();
1336
- const path = `/asset-packs${query ? `?${query}` : ''}`;
1337
- const response = await request({
1338
- method: 'GET',
1339
- path,
1340
- });
1341
- if (response.status !== 200) {
1342
- handleApiError(response, 'list_asset_packs');
1343
- }
1344
- return response.body;
1345
- },
1346
- async listAssetPacksForCreator(creatorUsername, options = {}) {
1347
- const params = new URLSearchParams();
1348
- if (typeof options.limit === 'number') {
1349
- params.set('limit', String(options.limit));
1350
- }
1351
- if (typeof options.offset === 'number') {
1352
- params.set('offset', String(options.offset));
1353
- }
1354
- if (typeof options.containsCategory === 'string' && options.containsCategory.trim().length > 0) {
1355
- params.set('containsCategory', options.containsCategory.trim());
1356
- }
1357
- if (typeof options.containsSubcategory === 'string' && options.containsSubcategory.trim().length > 0) {
1358
- params.set('containsSubcategory', options.containsSubcategory.trim());
1359
- }
1360
- const query = params.toString();
1361
- const path = `/creators/${encodeURIComponent(creatorUsername)}/asset-packs${query ? `?${query}` : ''}`;
1362
- const response = await request({
1363
- method: 'GET',
1364
- path,
1365
- });
1366
- if (response.status !== 200) {
1367
- handleApiError(response, 'list_asset_packs_for_creator');
1368
- }
1369
- return response.body;
1370
- },
1371
- async fetchAssetPackBySlug(creatorUsername, packName) {
1372
- const path = `/asset-packs/${encodeURIComponent(creatorUsername)}/${encodeURIComponent(packName)}`;
1373
- const response = await request({
1374
- method: 'GET',
1375
- path,
1376
- });
1377
- if (response.status !== 200) {
1378
- handleApiError(response, 'fetch_asset_pack_by_slug');
1379
- }
1380
- return response.body;
1381
- },
1382
- async downloadAssetPackSource(creatorUsername, packName, version) {
1383
- const creator = typeof creatorUsername === 'string' ? creatorUsername.trim() : '';
1384
- const name = typeof packName === 'string' ? packName.trim() : '';
1385
- if (!creator || !name) {
1386
- throw new Error('invalid_pack_key');
1387
- }
1388
- const normalizedVersion = normalizeSemverInput(version);
1389
- const path = `/asset-packs/${encodeURIComponent(creator)}/${encodeURIComponent(name)}/versions/${encodeURIComponent(normalizedVersion)}/source`;
1390
- const base = resolveBaseUrl();
1391
- const headers = new Headers();
1392
- if (config.clientHeaders) {
1393
- const clientHeaders = config.clientHeaders();
1394
- for (const [key, value] of Object.entries(clientHeaders)) {
1395
- headers.set(key, value);
1396
- }
1397
- }
1398
- const token = await resolveToken();
1399
- if (token) {
1400
- headers.set('authorization', `Bearer ${token}`);
1401
- }
1402
- const response = await fetchImpl(resolveUrl(base, path), {
1403
- method: 'GET',
1404
- headers,
1405
- });
1406
- if (!response.ok) {
1407
- const parsed = await parseResponseBody(response);
1408
- handleApiError({ status: response.status, body: parsed, headers: response.headers }, 'download_asset_pack_source');
1409
- }
1410
- const blob = await response.blob();
1411
- const filename = parseContentDispositionFilename(response.headers.get('content-disposition'))
1412
- ?? `${name}-${normalizedVersion}-source.zip`;
1413
- const headerSize = response.headers.get('content-length');
1414
- const parsedSize = headerSize ? Number.parseInt(headerSize, 10) : Number.NaN;
1415
- const checksumHeader = response.headers.get('x-pack-source-checksum');
1416
- return {
1417
- blob,
1418
- metadata: {
1419
- filename,
1420
- sizeBytes: Number.isFinite(parsedSize) && parsedSize >= 0 ? parsedSize : blob.size,
1421
- checksum: checksumHeader ?? null,
1422
- },
1423
- };
1424
- },
1425
- async listAssetPackVersions(creatorUsername, packName, options = {}) {
1426
- const params = new URLSearchParams();
1427
- if (typeof options.limit === 'number') {
1428
- params.set('limit', String(options.limit));
1429
- }
1430
- if (typeof options.offset === 'number') {
1431
- params.set('offset', String(options.offset));
1432
- }
1433
- const query = params.toString();
1434
- const path = `/asset-packs/${encodeURIComponent(creatorUsername)}/${encodeURIComponent(packName)}/versions${query ? `?${query}` : ''}`;
1435
- const response = await request({
1436
- method: 'GET',
1437
- path,
1438
- });
1439
- if (response.status !== 200) {
1440
- handleApiError(response, 'list_asset_pack_versions');
1441
- }
1442
- return response.body;
1443
- },
1444
- async updateAssetPack(name, requestBody, mutationTarget = {}) {
1445
- const packName = typeof name === 'string' ? name.trim() : '';
1446
- if (!packName) {
1447
- throw new Error('invalid_pack_name');
1448
- }
1449
- const params = new URLSearchParams();
1450
- if (typeof mutationTarget.creatorUsername === 'string' && mutationTarget.creatorUsername.trim().length > 0) {
1451
- params.set('creatorUsername', mutationTarget.creatorUsername.trim());
1452
- }
1453
- const query = params.toString();
1454
- const response = await request({
1455
- method: 'PATCH',
1456
- path: `/creator/asset-packs/${encodeURIComponent(packName)}${query ? `?${query}` : ''}`,
1457
- body: requestBody,
1458
- });
1459
- if (response.status !== 200) {
1460
- handleApiError(response, 'update_asset_pack');
1461
- }
1462
- return response.body;
1463
- },
1464
- async updateAssetPackVersion(name, version, requestBody, mutationTarget = {}) {
1465
- const packName = typeof name === 'string' ? name.trim() : '';
1466
- const versionValue = typeof version === 'string' ? version.trim() : '';
1467
- if (!packName) {
1468
- throw new Error('invalid_pack_name');
1469
- }
1470
- if (!versionValue) {
1471
- throw new Error('invalid_pack_version');
1472
- }
1473
- const params = new URLSearchParams();
1474
- if (typeof mutationTarget.creatorUsername === 'string' && mutationTarget.creatorUsername.trim().length > 0) {
1475
- params.set('creatorUsername', mutationTarget.creatorUsername.trim());
1476
- }
1477
- const query = params.toString();
1478
- const response = await request({
1479
- method: 'PATCH',
1480
- path: `/creator/asset-packs/${encodeURIComponent(packName)}/versions/${encodeURIComponent(versionValue)}${query ? `?${query}` : ''}`,
1481
- body: requestBody,
1482
- });
1483
- if (response.status !== 200) {
1484
- handleApiError(response, 'update_asset_pack_version');
1485
- }
1486
- return response.body;
1487
- },
1488
- async deleteAssetPackVersion(name, version, mutationTarget = {}) {
1489
- const packName = typeof name === 'string' ? name.trim() : '';
1490
- const versionValue = typeof version === 'string' ? version.trim() : '';
1491
- if (!packName) {
1492
- throw new Error('invalid_pack_name');
1493
- }
1494
- if (!versionValue) {
1495
- throw new Error('invalid_pack_version');
1496
- }
1497
- const params = new URLSearchParams();
1498
- if (typeof mutationTarget.creatorUsername === 'string' && mutationTarget.creatorUsername.trim().length > 0) {
1499
- params.set('creatorUsername', mutationTarget.creatorUsername.trim());
1500
- }
1501
- const query = params.toString();
1502
- const response = await request({
1503
- method: 'DELETE',
1504
- path: `/creator/asset-packs/${encodeURIComponent(packName)}/versions/${encodeURIComponent(versionValue)}${query ? `?${query}` : ''}`,
1505
- });
1506
- if (response.status !== 200) {
1507
- handleApiError(response, 'delete_asset_pack_version');
1508
- }
1509
- return response.body;
1510
- },
1511
- async deleteAssetPack(name, mutationTarget = {}) {
1512
- const packName = typeof name === 'string' ? name.trim() : '';
1513
- if (!packName) {
1514
- throw new Error('invalid_pack_name');
1515
- }
1516
- const params = new URLSearchParams();
1517
- if (typeof mutationTarget.creatorUsername === 'string' && mutationTarget.creatorUsername.trim().length > 0) {
1518
- params.set('creatorUsername', mutationTarget.creatorUsername.trim());
1519
- }
1520
- const query = params.toString();
1521
- const response = await request({
1522
- method: 'DELETE',
1523
- path: `/creator/asset-packs/${encodeURIComponent(packName)}${query ? `?${query}` : ''}`,
1524
- });
1525
- if (response.status !== 200) {
1526
- handleApiError(response, 'delete_asset_pack');
1527
- }
1528
- return response.body;
1529
- },
1530
- async batchUpsertGraphRelations(body) {
1531
- const response = await request({
1532
- method: 'POST',
1533
- path: '/creator/graph/relations:batchUpsert',
1534
- body,
1535
- });
1536
- if (response.status !== 200) {
1537
- handleApiError(response, 'batch_upsert_graph_relations');
1538
- }
1539
- return response.body;
1540
- },
1541
- async deleteApp(name, options = {}) {
1542
- const params = new URLSearchParams();
1543
- if (typeof options.creatorUsername === 'string' && options.creatorUsername.trim().length > 0) {
1544
- params.set('creatorUsername', options.creatorUsername.trim());
1545
- }
1546
- const query = params.toString();
1547
- const response = await request({
1548
- method: 'DELETE',
1549
- path: `/creator/apps/${encodeURIComponent(name)}${query ? `?${query}` : ''}`,
1550
- });
1551
- if (response.status !== 200) {
1552
- handleApiError(response, 'delete_app');
1553
- }
1554
- return response.body;
1555
- },
1556
- async submitFeedback(feedbackRequest) {
1557
- const response = await request({
1558
- method: 'POST',
1559
- path: '/feedback',
1560
- body: feedbackRequest,
1561
- });
1562
- if (response.status !== 201 && response.status !== 200) {
1563
- handleApiError(response, 'submit_feedback');
1564
- }
1565
- return response.body;
1566
- },
1567
- async listFeedback(options = {}) {
1568
- const params = new URLSearchParams();
1569
- if (options.limit !== undefined) {
1570
- params.set('limit', String(options.limit));
1571
- }
1572
- if (options.offset !== undefined) {
1573
- params.set('offset', String(options.offset));
1574
- }
1575
- if (typeof options.source === 'string' && options.source.trim().length > 0) {
1576
- params.set('source', options.source.trim());
1577
- }
1578
- if (options.userId !== undefined) {
1579
- params.set('userId', String(options.userId));
1580
- }
1581
- const query = params.toString();
1582
- const path = `/feedback${query ? `?${query}` : ''}`;
1583
- const response = await request({
1584
- method: 'GET',
1585
- path,
1586
- });
1587
- if (response.status !== 200) {
1588
- handleApiError(response, 'list_feedback');
1589
- }
1590
- return response.body;
1591
- },
1592
- async deleteFeedback(id) {
1593
- const response = await request({
1594
- method: 'DELETE',
1595
- path: `/feedback/${encodeURIComponent(String(id))}`,
1596
- });
1597
- if (response.status !== 200) {
1598
- handleApiError(response, 'delete_feedback');
1599
- }
1600
- return response.body;
1601
- },
1602
- async setSelectedProfileAsset(profileAssetRequest) {
1603
- const response = await request({
1604
- method: 'POST',
1605
- path: '/me/profile-asset',
1606
- body: profileAssetRequest,
1607
- });
1608
- if (response.status !== 200) {
1609
- handleApiError(response, 'set_profile_asset');
1610
- }
1611
- return response.body;
1612
- },
1613
- async fetchHome(options = {}) {
1614
- const params = new URLSearchParams();
1615
- if (typeof options.section === 'string' && options.section.trim().length > 0) {
1616
- params.set('section', options.section.trim());
1617
- }
1618
- if (typeof options.limit === 'number') {
1619
- params.set('limit', String(options.limit));
1620
- }
1621
- if (typeof options.offset === 'number') {
1622
- params.set('offset', String(options.offset));
1623
- }
1624
- const query = params.toString();
1625
- const response = await request({
1626
- method: 'GET',
1627
- path: `/home${query ? `?${query}` : ''}`,
1628
- });
1629
- if (response.status !== 200) {
1630
- handleApiError(response, 'fetch_home');
1631
- }
1632
- return response.body;
1633
- },
1634
- async fetchUsers() {
1635
- const response = await request({
1636
- method: 'GET',
1637
- path: '/admin/users',
1638
- });
1639
- if (response.status !== 200) {
1640
- handleApiError(response, 'fetch_users');
1641
- }
1642
- return response.body;
1643
- },
1644
- async createUser(userRequest) {
1645
- const response = await request({
1646
- method: 'POST',
1647
- path: '/admin/users',
1648
- body: userRequest,
1649
- });
1650
- if (response.status !== 201 && response.status !== 200) {
1651
- handleApiError(response, 'create_user');
1652
- }
1653
- return response.body;
1654
- },
1655
- async batchCreateUsersFromCsv(formData) {
1656
- const base = resolveBaseUrl();
1657
- const headers = new Headers();
1658
- if (config.clientHeaders) {
1659
- const clientHeaders = config.clientHeaders();
1660
- for (const [key, value] of Object.entries(clientHeaders)) {
1661
- headers.set(key, value);
1662
- }
1663
- }
1664
- const token = await resolveToken();
1665
- if (token) {
1666
- headers.set('authorization', `Bearer ${token}`);
1667
- }
1668
- const path = '/admin/users/batch-create';
1669
- const response = await fetchImpl(resolveUrl(base, path), {
1670
- method: 'POST',
1671
- headers,
1672
- body: formData,
1673
- });
1674
- const parsed = await parseResponseBody(response);
1675
- const apiResponse = { status: response.status, body: parsed, headers: response.headers };
1676
- if (response.status !== 200 && response.status !== 201) {
1677
- handleApiError(apiResponse, 'batch_create_users');
1678
- }
1679
- return parsed;
1680
- },
1681
- async fetchAdminUser(userId) {
1682
- const response = await request({
1683
- method: 'GET',
1684
- path: `/admin/users/${encodeURIComponent(String(userId))}`,
1685
- });
1686
- if (response.status !== 200) {
1687
- handleApiError(response, 'fetch_admin_user');
1688
- }
1689
- return response.body;
1690
- },
1691
- async updateAdminUser(userId, updateRequest) {
1692
- const response = await request({
1693
- method: 'PATCH',
1694
- path: `/admin/users/${encodeURIComponent(String(userId))}`,
1695
- body: updateRequest,
1696
- });
1697
- if (response.status !== 200) {
1698
- handleApiError(response, 'update_admin_user');
1699
- }
1700
- return response.body;
1701
- },
1702
- async deleteAdminUser(userId) {
1703
- const response = await request({
1704
- method: 'DELETE',
1705
- path: `/admin/users/${encodeURIComponent(String(userId))}`,
1706
- });
1707
- if (response.status !== 200) {
1708
- handleApiError(response, 'delete_admin_user');
1709
- }
1710
- return response.body;
1711
- },
1712
- async fetchAdminApps() {
1713
- const response = await request({
1714
- method: 'GET',
1715
- path: '/admin/apps',
1716
- });
1717
- if (response.status !== 200) {
1718
- handleApiError(response, 'fetch_admin_apps');
1719
- }
1720
- return response.body;
1721
- },
1722
- async fetchAdminGames() {
1723
- const response = await this.fetchAdminApps();
1724
- return { ...response, games: response.apps };
1725
- },
1726
- async updateAdminApp(id, updateRequest) {
1727
- const response = await request({
1728
- method: 'PATCH',
1729
- path: `/admin/apps/${encodeURIComponent(String(id))}`,
1730
- body: updateRequest,
1731
- });
1732
- if (response.status !== 200) {
1733
- handleApiError(response, 'update_admin_app');
1734
- }
1735
- return response.body;
1736
- },
1737
- async deleteAdminApp(id) {
1738
- const response = await request({
1739
- method: 'DELETE',
1740
- path: `/admin/apps/${encodeURIComponent(String(id))}`,
1741
- });
1742
- if (response.status !== 200) {
1743
- handleApiError(response, 'delete_admin_app');
1744
- }
1745
- return response.body;
1746
- },
1747
- async fetchAdminCreditPacks() {
1748
- const response = await request({
1749
- method: 'GET',
1750
- path: '/admin/credit-packs',
1751
- });
1752
- if (response.status !== 200) {
1753
- handleApiError(response, 'fetch_admin_credit_packs');
1754
- }
1755
- return response.body;
1756
- },
1757
- async createAdminCreditPack(body) {
1758
- const response = await request({
1759
- method: 'POST',
1760
- path: '/admin/credit-packs',
1761
- body,
1762
- });
1763
- if (response.status !== 201) {
1764
- handleApiError(response, 'create_admin_credit_pack');
1765
- }
1766
- return response.body;
1767
- },
1768
- async updateAdminCreditPack(sku, body) {
1769
- const response = await request({
1770
- method: 'PATCH',
1771
- path: `/admin/credit-packs/${encodeURIComponent(sku)}`,
1772
- body,
1773
- });
1774
- if (response.status !== 200) {
1775
- handleApiError(response, 'update_admin_credit_pack');
1776
- }
1777
- return response.body;
1778
- },
1779
- async deleteAdminCreditPack(sku) {
1780
- const response = await request({
1781
- method: 'DELETE',
1782
- path: `/admin/credit-packs/${encodeURIComponent(sku)}`,
1783
- });
1784
- if (response.status !== 200) {
1785
- handleApiError(response, 'delete_admin_credit_pack');
1786
- }
1787
- return response.body;
1788
- },
1789
- async syncAdminCreditPacksStripe() {
1790
- const response = await request({
1791
- method: 'POST',
1792
- path: '/admin/credit-packs/sync-stripe',
1793
- });
1794
- if (response.status !== 200) {
1795
- handleApiError(response, 'sync_admin_credit_packs_stripe');
1796
- }
1797
- return response.body;
1798
- },
1799
- async fetchAdminPayments(options) {
1800
- const params = new URLSearchParams();
1801
- if (options?.provider) {
1802
- params.set('provider', options.provider);
1803
- }
1804
- if (options?.status) {
1805
- const statuses = Array.isArray(options.status) ? options.status : [options.status];
1806
- params.set('status', statuses.join(','));
1807
- }
1808
- if (typeof options?.userId === 'number') {
1809
- params.set('userId', String(options.userId));
1810
- }
1811
- if (options?.creditPackSku) {
1812
- params.set('creditPackSku', options.creditPackSku);
1813
- }
1814
- if (options?.from) {
1815
- const fromValue = options.from instanceof Date ? options.from.toISOString() : options.from;
1816
- params.set('from', fromValue);
1817
- }
1818
- if (options?.to) {
1819
- const toValue = options.to instanceof Date ? options.to.toISOString() : options.to;
1820
- params.set('to', toValue);
1821
- }
1822
- if (typeof options?.limit === 'number') {
1823
- params.set('limit', String(options.limit));
1824
- }
1825
- if (typeof options?.offset === 'number') {
1826
- params.set('offset', String(options.offset));
1827
- }
1828
- const query = params.toString();
1829
- const path = query ? `/admin/payments?${query}` : '/admin/payments';
1830
- const response = await request({
1831
- method: 'GET',
1832
- path,
1833
- });
1834
- if (response.status !== 200) {
1835
- handleApiError(response, 'fetch_admin_payments');
1836
- }
1837
- return response.body;
1838
- },
1839
- async fetchAdminPayment(paymentId) {
1840
- const response = await request({
1841
- method: 'GET',
1842
- path: `/admin/payments/${encodeURIComponent(String(paymentId))}`,
1843
- });
1844
- if (response.status !== 200) {
1845
- handleApiError(response, 'fetch_admin_payment');
1846
- }
1847
- return response.body;
1848
- },
1849
- async refundAdminPayment(paymentId, body) {
1850
- const response = await request({
1851
- method: 'POST',
1852
- path: `/admin/payments/${encodeURIComponent(String(paymentId))}/refund`,
1853
- body,
1854
- });
1855
- if (response.status !== 200) {
1856
- handleApiError(response, 'refund_admin_payment');
1857
- }
1858
- return response.body;
1859
- },
1860
- async reconcileAdminPayment(paymentId) {
1861
- const response = await request({
1862
- method: 'POST',
1863
- path: `/admin/payments/${encodeURIComponent(String(paymentId))}/reconcile`,
1864
- });
1865
- if (response.status !== 200) {
1866
- handleApiError(response, 'reconcile_admin_payment');
1867
- }
1868
- return response.body;
1869
- },
1870
- async fetchAdminCreditTransactions(options) {
1871
- const params = new URLSearchParams();
1872
- if (options?.limit !== undefined) {
1873
- params.set('limit', String(options.limit));
1874
- }
1875
- if (options?.offset !== undefined) {
1876
- params.set('offset', String(options.offset));
1877
- }
1878
- const query = params.toString();
1879
- const path = query ? `/admin/credit-transactions?${query}` : '/admin/credit-transactions';
1880
- const response = await request({
1881
- method: 'GET',
1882
- path,
1883
- });
1884
- if (response.status !== 200) {
1885
- handleApiError(response, 'fetch_admin_credit_transactions');
1886
- }
1887
- return response.body;
1888
- },
1889
- async fetchAdminAiGenerations(options) {
1890
- const params = new URLSearchParams();
1891
- if (options?.limit !== undefined) {
1892
- params.set('limit', String(options.limit));
1893
- }
1894
- if (options?.offset !== undefined) {
1895
- params.set('offset', String(options.offset));
1896
- }
1897
- const query = params.toString();
1898
- const path = query ? `/admin/ai-generations?${query}` : '/admin/ai-generations';
1899
- const response = await request({
1900
- method: 'GET',
1901
- path,
1902
- });
1903
- if (response.status !== 200) {
1904
- handleApiError(response, 'fetch_admin_ai_generations');
1905
- }
1906
- return response.body;
1907
- },
1908
- async fetchAdminAiGeneration(id) {
1909
- const response = await request({
1910
- method: 'GET',
1911
- path: `/admin/ai-generations/${id}`,
1912
- });
1913
- if (response.status !== 200) {
1914
- handleApiError(response, 'fetch_admin_ai_generation');
1915
- }
1916
- return response.body;
1917
- },
1918
- async fetchCreatorBootstrap() {
1919
- const response = await request({
1920
- method: 'GET',
1921
- path: '/creator/bootstrap',
1922
- });
1923
- if (response.status !== 200) {
1924
- handleApiError(response, 'fetch_creator_bootstrap');
1925
- }
1926
- return response.body;
1927
- },
1928
- async fetchRemixScaffold(creatorUsername, appName) {
1929
- const response = await request({
1930
- method: 'GET',
1931
- path: `/creator/apps/${encodeURIComponent(creatorUsername)}/${encodeURIComponent(appName)}/remix`,
1932
- });
1933
- if (response.status !== 200) {
1934
- handleApiError(response, 'fetch_remix_scaffold');
1935
- }
1936
- return response.body;
1937
- },
1938
- async fetchTemplateScaffold(namespace, slug) {
1939
- const response = await request({
1940
- method: 'GET',
1941
- path: `/creator/templates/${encodeURIComponent(namespace)}/${encodeURIComponent(slug)}`,
1942
- });
1943
- if (response.status !== 200) {
1944
- handleApiError(response, 'fetch_template_scaffold');
1945
- }
1946
- return response.body;
1947
- },
1948
- async fetchCreditShop() {
1949
- const response = await request({
1950
- method: 'GET',
1951
- path: '/shop',
1952
- });
1953
- if (response.status !== 200) {
1954
- handleApiError(response, 'fetch_shop');
1955
- }
1956
- return response.body;
1957
- },
1958
- async createCreditPackCheckoutSession(sku) {
1959
- const normalizedSku = sku.trim();
1960
- if (!normalizedSku) {
1961
- throw new Error('invalid_credit_pack_sku');
1962
- }
1963
- const response = await request({
1964
- method: 'POST',
1965
- path: `/shop/credit-packs/${encodeURIComponent(normalizedSku)}/checkout-session`,
1966
- });
1967
- if (response.status !== 200) {
1968
- handleApiError(response, 'create_credit_pack_checkout_session');
1969
- }
1970
- return response.body;
1971
- },
1972
- async fetchCreditPackCheckoutStatus(sessionId) {
1973
- const normalizedSessionId = sessionId.trim();
1974
- if (!normalizedSessionId) {
1975
- throw new Error('invalid_checkout_session_id');
1976
- }
1977
- const response = await request({
1978
- method: 'GET',
1979
- path: `/shop/credit-packs/checkout-session/${encodeURIComponent(normalizedSessionId)}`,
1980
- });
1981
- if (response.status !== 200) {
1982
- handleApiError(response, 'fetch_credit_pack_checkout_status');
1983
- }
1984
- return response.body;
1985
- },
1986
- async purchaseAsset(body) {
1987
- const response = await request({
1988
- method: 'POST',
1989
- path: '/purchase',
1990
- body,
1991
- });
1992
- if (response.status !== 200) {
1993
- handleApiError(response, 'purchase_asset');
1994
- }
1995
- return response.body;
1996
- },
1997
- async purchaseIap(body) {
1998
- const response = await request({
1999
- method: 'POST',
2000
- path: '/iap/purchase',
2001
- body,
2002
- });
2003
- if (response.status !== 200) {
2004
- handleApiError(response, 'purchase_iap');
2005
- }
2006
- return response.body;
2007
- },
2008
- async fetchIapReceipts(params) {
2009
- const query = buildIapQuery(params);
2010
- const path = query ? `/iap/receipts?${query}` : '/iap/receipts';
2011
- const response = await request({
2012
- method: 'GET',
2013
- path,
2014
- });
2015
- if (response.status !== 200) {
2016
- handleApiError(response, 'fetch_iap_receipts');
2017
- }
2018
- return response.body;
2019
- },
2020
- async cancelIapReceipt(receiptId) {
2021
- const response = await request({
2022
- method: 'POST',
2023
- path: `/iap/receipts/${encodeURIComponent(String(receiptId))}/cancel`,
2024
- });
2025
- if (response.status !== 200) {
2026
- handleApiError(response, 'cancel_iap_receipt');
2027
- }
2028
- return response.body;
2029
- },
2030
- async fetchAppIapReceipts(params) {
2031
- const query = buildIapQuery(params);
2032
- const path = query ? `/app/iap/receipts?${query}` : '/app/iap/receipts';
2033
- const response = await request({
2034
- method: 'GET',
2035
- path,
2036
- });
2037
- if (response.status !== 200) {
2038
- handleApiError(response, 'fetch_app_iap_receipts');
2039
- }
2040
- return response.body;
2041
- },
2042
- async consumeAppIapReceipt(receiptId) {
2043
- const response = await request({
2044
- method: 'POST',
2045
- path: `/app/iap/receipts/${encodeURIComponent(String(receiptId))}/consume`,
2046
- });
2047
- if (response.status !== 200) {
2048
- handleApiError(response, 'consume_app_iap_receipt');
2049
- }
2050
- return response.body;
2051
- },
2052
- async grantAppIapReceipt(receiptId) {
2053
- const response = await request({
2054
- method: 'POST',
2055
- path: `/app/iap/receipts/${encodeURIComponent(String(receiptId))}/grant`,
2056
- });
2057
- if (response.status !== 200) {
2058
- handleApiError(response, 'grant_app_iap_receipt');
2059
- }
2060
- return response.body;
2061
- },
2062
- async cancelAppIapReceipt(receiptId) {
2063
- const response = await request({
2064
- method: 'POST',
2065
- path: `/app/iap/receipts/${encodeURIComponent(String(receiptId))}/cancel`,
2066
- });
2067
- if (response.status !== 200) {
2068
- handleApiError(response, 'cancel_app_iap_receipt');
2069
- }
2070
- return response.body;
2071
- },
2072
- async fetchCreditTransactions(options) {
2073
- const params = new URLSearchParams();
2074
- if (options?.limit !== undefined) {
2075
- params.set('limit', String(options.limit));
2076
- }
2077
- if (options?.offset !== undefined) {
2078
- params.set('offset', String(options.offset));
2079
- }
2080
- const query = params.toString();
2081
- const path = query ? `/transactions?${query}` : '/transactions';
2082
- const response = await request({
2083
- method: 'GET',
2084
- path,
2085
- });
2086
- if (response.status !== 200) {
2087
- handleApiError(response, 'fetch_credit_transactions');
2088
- }
2089
- return response.body;
2090
- },
2091
- async fetchAiGeneration(id) {
2092
- const response = await request({
2093
- method: 'GET',
2094
- path: `/ai-generations/${encodeURIComponent(id)}`,
2095
- });
2096
- if (response.status !== 200) {
2097
- handleApiError(response, 'fetch_ai_generation');
689
+ handleApiError(response, 'fetch_home');
2098
690
  }
2099
691
  return response.body;
2100
692
  },
693
+ ...buildAdminApiClientMethods({
694
+ request,
695
+ handleApiError,
696
+ fetchImpl,
697
+ resolveBaseUrl,
698
+ resolveUrl,
699
+ parseResponseBody,
700
+ resolveToken,
701
+ getClientHeaders: () => config.clientHeaders ? config.clientHeaders() : {},
702
+ }),
703
+ ...buildPaymentsApiClientMethods({
704
+ request,
705
+ handleApiError,
706
+ buildIapQuery,
707
+ }),
708
+ ...buildAiApiClientMethods({
709
+ request,
710
+ handleApiError,
711
+ }),
2101
712
  };
2102
713
  }