@origingame/origin-asset 0.12.0
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 +225 -0
- package/dist/index.d.ts +912 -0
- package/dist/index.js +1449 -0
- package/package.json +48 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1449 @@
|
|
|
1
|
+
// src/generate.ts
|
|
2
|
+
function copyParams(params) {
|
|
3
|
+
if (!params) {
|
|
4
|
+
return void 0;
|
|
5
|
+
}
|
|
6
|
+
return { ...params };
|
|
7
|
+
}
|
|
8
|
+
function mergeParams(base, extra) {
|
|
9
|
+
const merged = {
|
|
10
|
+
...base ?? {},
|
|
11
|
+
...extra ?? {}
|
|
12
|
+
};
|
|
13
|
+
return Object.keys(merged).length > 0 ? merged : void 0;
|
|
14
|
+
}
|
|
15
|
+
function resolveAssetUrl(baseUrl, value) {
|
|
16
|
+
if (!value) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
return new URL(value, ensureTrailingSlash(baseUrl)).toString();
|
|
21
|
+
} catch {
|
|
22
|
+
return value;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function normalizeGenerateResponse(baseUrl, response) {
|
|
26
|
+
const outputUrl = resolveAssetUrl(baseUrl, response.output_url);
|
|
27
|
+
return {
|
|
28
|
+
...response,
|
|
29
|
+
output_url: outputUrl,
|
|
30
|
+
output_files: response.output_files?.map((file) => ({
|
|
31
|
+
...file,
|
|
32
|
+
url: resolveAssetUrl(baseUrl, file.url) ?? file.url
|
|
33
|
+
})),
|
|
34
|
+
url: outputUrl
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function normalizeBatchResponse(baseUrl, response) {
|
|
38
|
+
return {
|
|
39
|
+
...response,
|
|
40
|
+
frames: response.frames.map((frame) => normalizeBatchFrame(baseUrl, frame))
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function normalizeBatchFrame(baseUrl, frame) {
|
|
44
|
+
const outputUrl = resolveAssetUrl(baseUrl, frame.output_url);
|
|
45
|
+
return {
|
|
46
|
+
...frame,
|
|
47
|
+
output_url: outputUrl,
|
|
48
|
+
url: outputUrl
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function normalizeUploadResult(baseUrl, response) {
|
|
52
|
+
return {
|
|
53
|
+
...response,
|
|
54
|
+
url: resolveAssetUrl(baseUrl, response.url) ?? response.url
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function normalizeAssetFile(baseUrl, file) {
|
|
58
|
+
return {
|
|
59
|
+
...file,
|
|
60
|
+
url: resolveAssetUrl(baseUrl, file.url) ?? file.url
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function normalizeMaybeGenerateResponse(baseUrl, value) {
|
|
64
|
+
if (!isRecord(value)) {
|
|
65
|
+
return value;
|
|
66
|
+
}
|
|
67
|
+
const outputUrl = typeof value.output_url === "string" ? resolveAssetUrl(baseUrl, value.output_url) : null;
|
|
68
|
+
if (!outputUrl) {
|
|
69
|
+
return value;
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
...value,
|
|
73
|
+
output_url: outputUrl,
|
|
74
|
+
output_files: Array.isArray(value.output_files) ? value.output_files.map((file) => {
|
|
75
|
+
if (!isRecord(file) || typeof file.url !== "string") {
|
|
76
|
+
return file;
|
|
77
|
+
}
|
|
78
|
+
return { ...file, url: resolveAssetUrl(baseUrl, file.url) ?? file.url };
|
|
79
|
+
}) : value.output_files,
|
|
80
|
+
url: outputUrl
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function buildImageRequest(prompt, options = {}) {
|
|
84
|
+
const request = {
|
|
85
|
+
asset_type: "image",
|
|
86
|
+
prompt
|
|
87
|
+
};
|
|
88
|
+
if (options.provider) request.provider = options.provider;
|
|
89
|
+
if (options.model) request.model = options.model;
|
|
90
|
+
if (options.size) request.size = options.size;
|
|
91
|
+
if (options.transparent !== void 0) request.transparent = options.transparent;
|
|
92
|
+
if (options.input) request.input_file = options.input;
|
|
93
|
+
if (options.reference_images?.length) request.reference_images = options.reference_images;
|
|
94
|
+
if (options.edit_mode) request.edit_mode = options.edit_mode;
|
|
95
|
+
if (options.session_id) request.session_id = options.session_id;
|
|
96
|
+
const params = mergeParams(options.params, {
|
|
97
|
+
...options.quality ? { quality: options.quality } : {},
|
|
98
|
+
...options.background ? { background: options.background } : {},
|
|
99
|
+
...options.output_format ? { output_format: options.output_format } : {},
|
|
100
|
+
...options.n !== void 0 ? { n: options.n } : {},
|
|
101
|
+
...options.preset ? { preset: options.preset } : {},
|
|
102
|
+
...options.mask ? { mask: options.mask } : {},
|
|
103
|
+
...options.mask_url ? { mask_url: options.mask_url } : {}
|
|
104
|
+
});
|
|
105
|
+
if (params) request.params = params;
|
|
106
|
+
return request;
|
|
107
|
+
}
|
|
108
|
+
function buildGeneratedAssetRequest(assetType, prompt, options = {}) {
|
|
109
|
+
const params = mergeParams(options.params, {
|
|
110
|
+
...assetType === "skybox" ? { preset_hint: "skybox_equirect" } : {},
|
|
111
|
+
...assetType === "decal" ? { preset_hint: "decal_transparent" } : {},
|
|
112
|
+
...assetType === "heightmap" ? { preset_hint: "heightmap_grayscale" } : {},
|
|
113
|
+
...options.quality ? { quality: options.quality } : {},
|
|
114
|
+
...options.background ? { background: options.background } : {},
|
|
115
|
+
...options.output_format ? { output_format: options.output_format } : {},
|
|
116
|
+
...options.n !== void 0 ? { n: options.n } : {},
|
|
117
|
+
...options.preset ? { preset: options.preset } : {}
|
|
118
|
+
});
|
|
119
|
+
return {
|
|
120
|
+
asset_type: assetType,
|
|
121
|
+
prompt,
|
|
122
|
+
provider: options.provider,
|
|
123
|
+
model: options.model,
|
|
124
|
+
input_file: options.input,
|
|
125
|
+
size: options.size,
|
|
126
|
+
transparent: options.transparent,
|
|
127
|
+
params
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function buildVideoRequest(prompt, options = {}) {
|
|
131
|
+
const request = {
|
|
132
|
+
asset_type: "video",
|
|
133
|
+
prompt
|
|
134
|
+
};
|
|
135
|
+
if (options.provider) request.provider = options.provider;
|
|
136
|
+
if (options.model) request.model = options.model;
|
|
137
|
+
if (options.size) request.size = options.size;
|
|
138
|
+
if (options.reference_images?.length) request.reference_images = options.reference_images;
|
|
139
|
+
const params = copyParams(options.params);
|
|
140
|
+
if (options.ratio) {
|
|
141
|
+
request.params = { ...params, ratio: options.ratio };
|
|
142
|
+
} else if (params) {
|
|
143
|
+
request.params = params;
|
|
144
|
+
}
|
|
145
|
+
return request;
|
|
146
|
+
}
|
|
147
|
+
function buildAudioRequest(prompt, options = {}) {
|
|
148
|
+
return {
|
|
149
|
+
asset_type: "audio",
|
|
150
|
+
prompt,
|
|
151
|
+
provider: options.provider,
|
|
152
|
+
model: options.model,
|
|
153
|
+
params: mergeParams(options.params, {
|
|
154
|
+
...options.type ? { audio_type: options.type } : {},
|
|
155
|
+
...options.duration !== void 0 ? { duration_seconds: options.duration } : {}
|
|
156
|
+
})
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
function buildMusicRequest(prompt, options = {}) {
|
|
160
|
+
return {
|
|
161
|
+
asset_type: "music",
|
|
162
|
+
prompt,
|
|
163
|
+
provider: options.provider,
|
|
164
|
+
model: options.model,
|
|
165
|
+
params: mergeParams(options.params, {
|
|
166
|
+
...options.duration !== void 0 ? { duration_seconds: options.duration } : {},
|
|
167
|
+
...options.force_instrumental ? { force_instrumental: true } : {},
|
|
168
|
+
...options.output_format ? { output_format: options.output_format } : {}
|
|
169
|
+
})
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
function buildTtsRequest(prompt, options = {}) {
|
|
173
|
+
const context = options.context ?? options.instructions;
|
|
174
|
+
return {
|
|
175
|
+
asset_type: "tts",
|
|
176
|
+
prompt,
|
|
177
|
+
provider: options.provider,
|
|
178
|
+
model: options.model,
|
|
179
|
+
params: mergeParams(options.params, {
|
|
180
|
+
...options.voice ? { voice: options.voice } : {},
|
|
181
|
+
...options.voice_id ? { voice_id: options.voice_id } : {},
|
|
182
|
+
...context ? { context } : {},
|
|
183
|
+
...options.style ? { style: options.style } : {},
|
|
184
|
+
...options.language ? { language_type: options.language } : {},
|
|
185
|
+
...options.instructions ? { instructions: options.instructions } : {}
|
|
186
|
+
})
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
function buildModel3dRequest(prompt, options = {}) {
|
|
190
|
+
return {
|
|
191
|
+
asset_type: "model3d",
|
|
192
|
+
prompt,
|
|
193
|
+
provider: options.provider,
|
|
194
|
+
model: options.model,
|
|
195
|
+
input_file: options.input,
|
|
196
|
+
params: mergeParams(options.params, {
|
|
197
|
+
...options.ai_model ? { ai_model: options.ai_model } : {},
|
|
198
|
+
...options.polycount !== void 0 ? { target_polycount: options.polycount } : {},
|
|
199
|
+
...options.pbr ? { pbr: true } : {},
|
|
200
|
+
...options.hd_texture ? { hd_texture: true } : {},
|
|
201
|
+
...options.auto_size ? { auto_size: true } : {},
|
|
202
|
+
...options.pose_mode ? { pose_mode: options.pose_mode } : {},
|
|
203
|
+
...options.texture_prompt ? { texture_prompt: options.texture_prompt } : {},
|
|
204
|
+
...options.format ? { format: options.format } : {},
|
|
205
|
+
...options.images?.length ? { images: options.images } : {}
|
|
206
|
+
})
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
function buildCharacterRequest(prompt, options = {}) {
|
|
210
|
+
return {
|
|
211
|
+
asset_type: "character",
|
|
212
|
+
prompt,
|
|
213
|
+
provider: options.provider,
|
|
214
|
+
model: options.model,
|
|
215
|
+
input_file: options.input,
|
|
216
|
+
params: mergeParams(options.params, {
|
|
217
|
+
...options.format ? { format: options.format } : {},
|
|
218
|
+
...options.polycount !== void 0 ? { target_polycount: options.polycount } : {},
|
|
219
|
+
...options.pbr ? { pbr: true } : {},
|
|
220
|
+
...options.hd_texture ? { hd_texture: true } : {},
|
|
221
|
+
...options.pose_mode ? { pose_mode: options.pose_mode } : {},
|
|
222
|
+
...options.ai_model ? { ai_model: options.ai_model } : {},
|
|
223
|
+
...options.auto_size ? { auto_size: true } : {},
|
|
224
|
+
...options.texture_prompt ? { texture_prompt: options.texture_prompt } : {},
|
|
225
|
+
...options.images?.length ? { images: options.images } : {}
|
|
226
|
+
})
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
function buildPropRequest(prompt, options = {}) {
|
|
230
|
+
return {
|
|
231
|
+
asset_type: "prop",
|
|
232
|
+
prompt,
|
|
233
|
+
provider: options.provider,
|
|
234
|
+
model: options.model,
|
|
235
|
+
input_file: options.input,
|
|
236
|
+
params: mergeParams(options.params, {
|
|
237
|
+
...options.format ? { format: options.format } : {},
|
|
238
|
+
...options.polycount !== void 0 ? { target_polycount: options.polycount } : {},
|
|
239
|
+
...options.pbr ? { pbr: true } : {},
|
|
240
|
+
...options.hd_texture ? { hd_texture: true } : {},
|
|
241
|
+
...options.ai_model ? { ai_model: options.ai_model } : {},
|
|
242
|
+
...options.auto_size ? { auto_size: true } : {},
|
|
243
|
+
...options.texture_prompt ? { texture_prompt: options.texture_prompt } : {},
|
|
244
|
+
...options.symmetry_mode ? { symmetry_mode: options.symmetry_mode } : {},
|
|
245
|
+
...options.images?.length ? { images: options.images } : {}
|
|
246
|
+
})
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
function buildSpriteRequest(prompt, options = {}) {
|
|
250
|
+
return {
|
|
251
|
+
asset_type: "sprite",
|
|
252
|
+
prompt,
|
|
253
|
+
provider: options.provider,
|
|
254
|
+
model: options.model,
|
|
255
|
+
input_file: options.input,
|
|
256
|
+
params: mergeParams(options.params, {
|
|
257
|
+
animation_type: options.animation_type ?? "walk",
|
|
258
|
+
direction: options.direction ?? "right",
|
|
259
|
+
duration: options.duration ?? 2,
|
|
260
|
+
output_format: options.output_format ?? "spritesheet",
|
|
261
|
+
...options.fps !== void 0 ? { fps: options.fps } : {},
|
|
262
|
+
...options.style ? { style: options.style } : {}
|
|
263
|
+
})
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
function buildWorldRequest(prompt, options = {}) {
|
|
267
|
+
return {
|
|
268
|
+
asset_type: "world",
|
|
269
|
+
prompt,
|
|
270
|
+
provider: options.provider,
|
|
271
|
+
model: options.model,
|
|
272
|
+
input_file: options.input ?? options.image_url,
|
|
273
|
+
params: mergeParams(options.params, {
|
|
274
|
+
...options.display_name ? { display_name: options.display_name } : {},
|
|
275
|
+
...options.image_url ? { image_url: options.image_url } : {},
|
|
276
|
+
...options.panorama_url ? { panorama_url: options.panorama_url } : {},
|
|
277
|
+
...options.video_url ? { video_url: options.video_url } : {},
|
|
278
|
+
...options.multi_image_url?.length ? { multi_image_url: options.multi_image_url } : {},
|
|
279
|
+
...options.quality ? { quality: options.quality } : {}
|
|
280
|
+
})
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
function buildTextRequest(prompt, options = {}) {
|
|
284
|
+
return {
|
|
285
|
+
asset_type: "text",
|
|
286
|
+
prompt,
|
|
287
|
+
provider: options.provider,
|
|
288
|
+
model: options.model,
|
|
289
|
+
params: mergeParams(options.params, {
|
|
290
|
+
...options.max_tokens !== void 0 ? { max_tokens: options.max_tokens } : {}
|
|
291
|
+
})
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
function ensureTrailingSlash(value) {
|
|
295
|
+
return value.endsWith("/") ? value : `${value}/`;
|
|
296
|
+
}
|
|
297
|
+
function isRecord(value) {
|
|
298
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// src/types.ts
|
|
302
|
+
var AssetForgeError = class extends Error {
|
|
303
|
+
code;
|
|
304
|
+
status;
|
|
305
|
+
command;
|
|
306
|
+
details;
|
|
307
|
+
constructor(message, options = {}) {
|
|
308
|
+
super(message, options.cause !== void 0 ? { cause: options.cause } : void 0);
|
|
309
|
+
this.name = "AssetForgeError";
|
|
310
|
+
this.code = options.code ?? "ASSETFORGE_ERROR";
|
|
311
|
+
this.status = options.status;
|
|
312
|
+
this.command = options.command;
|
|
313
|
+
this.details = options.details;
|
|
314
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
315
|
+
}
|
|
316
|
+
};
|
|
317
|
+
function toAssetForgeError(error) {
|
|
318
|
+
if (error instanceof AssetForgeError) {
|
|
319
|
+
return error;
|
|
320
|
+
}
|
|
321
|
+
if (error instanceof Error) {
|
|
322
|
+
return new AssetForgeError(error.message, {
|
|
323
|
+
code: "INTERNAL_ERROR",
|
|
324
|
+
cause: error
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
return new AssetForgeError(String(error), { code: "INTERNAL_ERROR" });
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// src/stream.ts
|
|
331
|
+
function subscribeJob(jobId, handler, options = {}) {
|
|
332
|
+
return subscribeSse(`/api/jobs/${encodeURIComponent(jobId)}/events`, handler, options);
|
|
333
|
+
}
|
|
334
|
+
function subscribeAllJobs(handler, options = {}) {
|
|
335
|
+
return subscribeSse("/api/jobs/events", handler, options);
|
|
336
|
+
}
|
|
337
|
+
var AssetForgeStreamNamespace = class {
|
|
338
|
+
constructor(forge) {
|
|
339
|
+
this.forge = forge;
|
|
340
|
+
}
|
|
341
|
+
forge;
|
|
342
|
+
job(jobId, handler, options = {}) {
|
|
343
|
+
return subscribeJob(jobId, handler, this.options(options));
|
|
344
|
+
}
|
|
345
|
+
all(handler, options = {}) {
|
|
346
|
+
return subscribeAllJobs(handler, this.options(options));
|
|
347
|
+
}
|
|
348
|
+
options(options) {
|
|
349
|
+
return {
|
|
350
|
+
...options,
|
|
351
|
+
baseUrl: this.forge.baseUrl,
|
|
352
|
+
apiKey: this.forge.apiKey
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
function subscribeSse(path, handler, options) {
|
|
357
|
+
const controller = new AbortController();
|
|
358
|
+
linkAbortSignals(options.signal, controller);
|
|
359
|
+
const result = runSse(path, handler, options, controller.signal);
|
|
360
|
+
void result.catch(() => void 0);
|
|
361
|
+
return {
|
|
362
|
+
signal: controller.signal,
|
|
363
|
+
result,
|
|
364
|
+
close: (reason = "closed") => controller.abort(reason)
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
async function runSse(path, handler, options, signal) {
|
|
368
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
369
|
+
if (typeof fetchImpl !== "function") {
|
|
370
|
+
throw new AssetForgeError("Global fetch is unavailable in this runtime", {
|
|
371
|
+
code: "FETCH_UNAVAILABLE"
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
const headers = new Headers(options.headers);
|
|
375
|
+
headers.set("accept", "text/event-stream");
|
|
376
|
+
if (options.apiKey) {
|
|
377
|
+
headers.set("authorization", `Bearer ${options.apiKey}`);
|
|
378
|
+
}
|
|
379
|
+
const response = await fetchImpl(new URL(path, ensureTrailingSlash2(options.baseUrl ?? DEFAULT_BASE_URL)), {
|
|
380
|
+
method: "GET",
|
|
381
|
+
headers,
|
|
382
|
+
signal
|
|
383
|
+
});
|
|
384
|
+
if (!response.ok) {
|
|
385
|
+
throw new AssetForgeError(`SSE subscription failed (${response.status})`, {
|
|
386
|
+
code: defaultErrorCode(response.status),
|
|
387
|
+
status: response.status
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
if (!response.body) {
|
|
391
|
+
throw new AssetForgeError("SSE response body is unavailable", { code: "STREAM_UNAVAILABLE" });
|
|
392
|
+
}
|
|
393
|
+
const reader = response.body.getReader();
|
|
394
|
+
const decoder = new TextDecoder();
|
|
395
|
+
let buffer = "";
|
|
396
|
+
while (!signal.aborted) {
|
|
397
|
+
const { done, value } = await reader.read();
|
|
398
|
+
if (done) {
|
|
399
|
+
break;
|
|
400
|
+
}
|
|
401
|
+
buffer += decoder.decode(value, { stream: true });
|
|
402
|
+
buffer = drainFrames(buffer, handler);
|
|
403
|
+
}
|
|
404
|
+
const finalText = decoder.decode();
|
|
405
|
+
if (finalText) {
|
|
406
|
+
buffer += finalText;
|
|
407
|
+
}
|
|
408
|
+
drainFrames(`${buffer}
|
|
409
|
+
|
|
410
|
+
`, handler);
|
|
411
|
+
}
|
|
412
|
+
function drainFrames(buffer, handler) {
|
|
413
|
+
let normalized = buffer.replace(/\r\n/g, "\n");
|
|
414
|
+
let boundary = normalized.indexOf("\n\n");
|
|
415
|
+
while (boundary !== -1) {
|
|
416
|
+
const frame = normalized.slice(0, boundary);
|
|
417
|
+
normalized = normalized.slice(boundary + 2);
|
|
418
|
+
const parsed = parseFrame(frame);
|
|
419
|
+
if (parsed) {
|
|
420
|
+
handler(normalizeJobEvent(parsed.event, parsed.data));
|
|
421
|
+
}
|
|
422
|
+
boundary = normalized.indexOf("\n\n");
|
|
423
|
+
}
|
|
424
|
+
return normalized;
|
|
425
|
+
}
|
|
426
|
+
function parseFrame(frame) {
|
|
427
|
+
let event = "message";
|
|
428
|
+
const data = [];
|
|
429
|
+
for (const line of frame.split("\n")) {
|
|
430
|
+
if (!line || line.startsWith(":")) {
|
|
431
|
+
continue;
|
|
432
|
+
}
|
|
433
|
+
const separator = line.indexOf(":");
|
|
434
|
+
const field = separator === -1 ? line : line.slice(0, separator);
|
|
435
|
+
const value = separator === -1 ? "" : line.slice(separator + 1).replace(/^ /, "");
|
|
436
|
+
if (field === "event") {
|
|
437
|
+
event = value;
|
|
438
|
+
} else if (field === "data") {
|
|
439
|
+
data.push(value);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
return data.length ? { event, data: data.join("\n") } : null;
|
|
443
|
+
}
|
|
444
|
+
function normalizeJobEvent(eventName, data) {
|
|
445
|
+
const raw = parseJson(data);
|
|
446
|
+
const record = isRecord2(raw) ? raw : {};
|
|
447
|
+
const kind = eventName === "snapshot" || eventName === "progress" || eventName === "update" ? eventName : "update";
|
|
448
|
+
return {
|
|
449
|
+
kind,
|
|
450
|
+
job_id: stringField(record.job_id) ?? stringField(record.id) ?? "",
|
|
451
|
+
status: stringField(record.status) ?? "unknown",
|
|
452
|
+
progress: extractProgress(record),
|
|
453
|
+
output_url: stringField(record.output_url),
|
|
454
|
+
error_message: stringField(record.error_message),
|
|
455
|
+
timestamp: stringField(record.timestamp) ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
456
|
+
raw
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
function extractProgress(record) {
|
|
460
|
+
const nested = isRecord2(record.progress) ? record.progress : void 0;
|
|
461
|
+
const progress = {
|
|
462
|
+
...nested ?? {}
|
|
463
|
+
};
|
|
464
|
+
if (typeof record.progress === "number") progress.progress = record.progress;
|
|
465
|
+
if (typeof record.current_step === "string") progress.current_step = record.current_step;
|
|
466
|
+
if (typeof record.step_index === "number") progress.step_index = record.step_index;
|
|
467
|
+
if (typeof record.step_count === "number") progress.step_count = record.step_count;
|
|
468
|
+
if (typeof record.message === "string") progress.message = record.message;
|
|
469
|
+
if (record.details !== void 0) progress.details = record.details;
|
|
470
|
+
return Object.keys(progress).length > 0 ? progress : void 0;
|
|
471
|
+
}
|
|
472
|
+
function parseJson(value) {
|
|
473
|
+
try {
|
|
474
|
+
return JSON.parse(value);
|
|
475
|
+
} catch {
|
|
476
|
+
return value;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
function stringField(value) {
|
|
480
|
+
return typeof value === "string" ? value : void 0;
|
|
481
|
+
}
|
|
482
|
+
function isRecord2(value) {
|
|
483
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
484
|
+
}
|
|
485
|
+
function linkAbortSignals(source, controller) {
|
|
486
|
+
if (!source) {
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
if (source.aborted) {
|
|
490
|
+
controller.abort(source.reason);
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
const onAbort = () => {
|
|
494
|
+
controller.abort(source.reason);
|
|
495
|
+
source.removeEventListener("abort", onAbort);
|
|
496
|
+
};
|
|
497
|
+
source.addEventListener("abort", onAbort, { once: true });
|
|
498
|
+
}
|
|
499
|
+
function ensureTrailingSlash2(value) {
|
|
500
|
+
return value.endsWith("/") ? value : `${value}/`;
|
|
501
|
+
}
|
|
502
|
+
function defaultErrorCode(status) {
|
|
503
|
+
if (status === 401) return "UNAUTHORIZED";
|
|
504
|
+
if (status === 403) return "FORBIDDEN";
|
|
505
|
+
if (status === 404) return "NOT_FOUND";
|
|
506
|
+
if (status === 409) return "CONFLICT";
|
|
507
|
+
return "API_ERROR";
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// src/jobs.ts
|
|
511
|
+
var AssetForgeJobs = class {
|
|
512
|
+
constructor(transport) {
|
|
513
|
+
this.transport = transport;
|
|
514
|
+
}
|
|
515
|
+
transport;
|
|
516
|
+
async list(query = {}, options = {}) {
|
|
517
|
+
return this.transport.request("GET", "/api/jobs", {
|
|
518
|
+
query: {
|
|
519
|
+
job_kind: query.job_kind,
|
|
520
|
+
status: query.status,
|
|
521
|
+
asset_type: query.asset_type,
|
|
522
|
+
provider_id: query.provider_id,
|
|
523
|
+
since: query.since,
|
|
524
|
+
provider_task_id: query.provider_task_id,
|
|
525
|
+
limit: query.limit,
|
|
526
|
+
offset: query.offset
|
|
527
|
+
},
|
|
528
|
+
signal: options.signal,
|
|
529
|
+
headers: options.headers
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
async status(id, options = {}) {
|
|
533
|
+
const job = await this.transport.request(
|
|
534
|
+
"GET",
|
|
535
|
+
`/api/jobs/${encodeURIComponent(id)}`,
|
|
536
|
+
{
|
|
537
|
+
signal: options.signal,
|
|
538
|
+
headers: options.headers
|
|
539
|
+
}
|
|
540
|
+
);
|
|
541
|
+
return {
|
|
542
|
+
...job,
|
|
543
|
+
response: job.response !== void 0 && job.response !== null ? normalizeMaybeGenerateResponse(this.transport.baseUrl, job.response) : job.response
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
async cancel(id, options = {}) {
|
|
547
|
+
return this.transport.request(
|
|
548
|
+
"POST",
|
|
549
|
+
`/api/jobs/${encodeURIComponent(id)}/cancel`,
|
|
550
|
+
{
|
|
551
|
+
signal: options.signal,
|
|
552
|
+
headers: options.headers
|
|
553
|
+
}
|
|
554
|
+
);
|
|
555
|
+
}
|
|
556
|
+
async wait(id, options = {}) {
|
|
557
|
+
const intervalMs = Math.max(250, options.intervalMs ?? options.interval_ms ?? 1e3);
|
|
558
|
+
const deadline = options.timeoutMs !== void 0 ? Date.now() + options.timeoutMs : void 0;
|
|
559
|
+
try {
|
|
560
|
+
return await this.waitWithSse(id, options);
|
|
561
|
+
} catch (error) {
|
|
562
|
+
if (error instanceof AssetForgeError && error.code === "JOB_WAIT_TIMEOUT") {
|
|
563
|
+
throw error;
|
|
564
|
+
}
|
|
565
|
+
if (options.signal?.aborted) {
|
|
566
|
+
throw new AssetForgeError("Job wait aborted", { code: "ABORTED", cause: error });
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
while (true) {
|
|
570
|
+
if (options.signal?.aborted) {
|
|
571
|
+
throw new AssetForgeError("Job wait aborted", { code: "ABORTED" });
|
|
572
|
+
}
|
|
573
|
+
if (deadline !== void 0 && Date.now() >= deadline) {
|
|
574
|
+
throw new AssetForgeError(`Timed out waiting for job ${id}`, { code: "JOB_WAIT_TIMEOUT" });
|
|
575
|
+
}
|
|
576
|
+
const job = await this.status(id, options);
|
|
577
|
+
if (isTerminalStatus(job.status)) {
|
|
578
|
+
return assertSuccessfulJob(job);
|
|
579
|
+
}
|
|
580
|
+
const sleepMs = deadline === void 0 ? intervalMs : Math.min(intervalMs, Math.max(0, deadline - Date.now()));
|
|
581
|
+
await sleep(sleepMs, options.signal);
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
waitWithSse(id, options) {
|
|
585
|
+
return new Promise((resolve, reject) => {
|
|
586
|
+
let settled = false;
|
|
587
|
+
let timeout;
|
|
588
|
+
const subscription = subscribeJob(
|
|
589
|
+
id,
|
|
590
|
+
(event) => {
|
|
591
|
+
if (!isTerminalStatus(event.status) || settled) {
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
settled = true;
|
|
595
|
+
if (timeout) clearTimeout(timeout);
|
|
596
|
+
subscription.close("terminal");
|
|
597
|
+
void this.status(id, options).then(
|
|
598
|
+
(job) => {
|
|
599
|
+
try {
|
|
600
|
+
resolve(assertSuccessfulJob(job));
|
|
601
|
+
} catch (error) {
|
|
602
|
+
reject(error);
|
|
603
|
+
}
|
|
604
|
+
},
|
|
605
|
+
() => reject(errorFromEvent(event))
|
|
606
|
+
);
|
|
607
|
+
},
|
|
608
|
+
{
|
|
609
|
+
baseUrl: this.transport.baseUrl,
|
|
610
|
+
apiKey: this.transport.apiKey,
|
|
611
|
+
signal: options.signal,
|
|
612
|
+
headers: options.headers
|
|
613
|
+
}
|
|
614
|
+
);
|
|
615
|
+
if (options.timeoutMs !== void 0) {
|
|
616
|
+
timeout = setTimeout(() => {
|
|
617
|
+
if (!settled) {
|
|
618
|
+
settled = true;
|
|
619
|
+
subscription.close("timeout");
|
|
620
|
+
reject(new AssetForgeError(`Timed out waiting for job ${id}`, { code: "JOB_WAIT_TIMEOUT" }));
|
|
621
|
+
}
|
|
622
|
+
}, options.timeoutMs);
|
|
623
|
+
}
|
|
624
|
+
void subscription.result.then(
|
|
625
|
+
() => {
|
|
626
|
+
if (!settled) {
|
|
627
|
+
if (timeout) clearTimeout(timeout);
|
|
628
|
+
reject(new AssetForgeError("SSE stream ended before job completed", { code: "STREAM_ENDED" }));
|
|
629
|
+
}
|
|
630
|
+
},
|
|
631
|
+
(error) => {
|
|
632
|
+
if (!settled) {
|
|
633
|
+
if (timeout) clearTimeout(timeout);
|
|
634
|
+
reject(error);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
);
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
};
|
|
641
|
+
function isTerminalStatus(status) {
|
|
642
|
+
return status === "completed" || status === "failed" || status === "cancelled";
|
|
643
|
+
}
|
|
644
|
+
function assertSuccessfulJob(job) {
|
|
645
|
+
if (job.status === "cancelled") {
|
|
646
|
+
throw new AssetForgeError(job.error_message ?? "Job cancelled", {
|
|
647
|
+
code: "JOB_CANCELLED",
|
|
648
|
+
details: job
|
|
649
|
+
});
|
|
650
|
+
}
|
|
651
|
+
if (job.status === "failed") {
|
|
652
|
+
throw new AssetForgeError(job.error_message ?? "Job failed", {
|
|
653
|
+
code: "JOB_FAILED",
|
|
654
|
+
details: job
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
return job;
|
|
658
|
+
}
|
|
659
|
+
function errorFromEvent(event) {
|
|
660
|
+
if (event.status === "cancelled") {
|
|
661
|
+
return new AssetForgeError(event.error_message ?? "Job cancelled", {
|
|
662
|
+
code: "JOB_CANCELLED",
|
|
663
|
+
details: event.raw
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
return new AssetForgeError(event.error_message ?? `Job ${event.status}`, {
|
|
667
|
+
code: event.status === "failed" ? "JOB_FAILED" : "API_ERROR",
|
|
668
|
+
details: event.raw
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
function sleep(ms, signal) {
|
|
672
|
+
return new Promise((resolve, reject) => {
|
|
673
|
+
if (signal?.aborted) {
|
|
674
|
+
reject(new AssetForgeError("Operation aborted", { code: "ABORTED" }));
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
const timeout = setTimeout(() => {
|
|
678
|
+
cleanup();
|
|
679
|
+
resolve();
|
|
680
|
+
}, ms);
|
|
681
|
+
const onAbort = () => {
|
|
682
|
+
clearTimeout(timeout);
|
|
683
|
+
cleanup();
|
|
684
|
+
reject(new AssetForgeError("Operation aborted", { code: "ABORTED" }));
|
|
685
|
+
};
|
|
686
|
+
const cleanup = () => signal?.removeEventListener("abort", onAbort);
|
|
687
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// src/library.ts
|
|
692
|
+
var AssetForgeLibrary = class {
|
|
693
|
+
constructor(transport) {
|
|
694
|
+
this.transport = transport;
|
|
695
|
+
}
|
|
696
|
+
transport;
|
|
697
|
+
async search(query = {}, options = {}) {
|
|
698
|
+
return this.transport.request("GET", "/api/library/search", {
|
|
699
|
+
query: {
|
|
700
|
+
q: query.q ?? query.query,
|
|
701
|
+
type: query.type,
|
|
702
|
+
tags: query.tags,
|
|
703
|
+
source: query.source,
|
|
704
|
+
pack_id: query.pack_id,
|
|
705
|
+
mode: query.mode,
|
|
706
|
+
style: query.style,
|
|
707
|
+
composition: query.composition,
|
|
708
|
+
lighting: query.lighting,
|
|
709
|
+
color_tone: query.color_tone,
|
|
710
|
+
mood: query.mood,
|
|
711
|
+
theme: query.theme,
|
|
712
|
+
era: query.era,
|
|
713
|
+
gameplay_role: query.gameplay_role,
|
|
714
|
+
ui_element: query.ui_element,
|
|
715
|
+
ui_state: query.ui_state,
|
|
716
|
+
ui_theme_pack: query.ui_theme_pack,
|
|
717
|
+
nine_slice: query.nine_slice,
|
|
718
|
+
size_class: query.size_class,
|
|
719
|
+
rig_name: query.rig_name,
|
|
720
|
+
compatible_rig: query.compatible_rig,
|
|
721
|
+
enrichment_status: query.enrichment_status,
|
|
722
|
+
min_long_edge_px: query.min_long_edge_px,
|
|
723
|
+
min_width_px: query.min_width_px,
|
|
724
|
+
min_height_px: query.min_height_px,
|
|
725
|
+
max_file_size_bytes: query.max_file_size_bytes,
|
|
726
|
+
license: query.license,
|
|
727
|
+
rerank: query.rerank,
|
|
728
|
+
limit: query.limit,
|
|
729
|
+
offset: query.offset
|
|
730
|
+
},
|
|
731
|
+
signal: options.signal,
|
|
732
|
+
headers: options.headers
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
async related(id, query = {}, options = {}) {
|
|
736
|
+
return this.transport.request(
|
|
737
|
+
"GET",
|
|
738
|
+
`/api/library/${encodeURIComponent(id)}/related`,
|
|
739
|
+
{
|
|
740
|
+
query: {
|
|
741
|
+
type: query.type,
|
|
742
|
+
limit: query.limit
|
|
743
|
+
},
|
|
744
|
+
signal: options.signal,
|
|
745
|
+
headers: options.headers
|
|
746
|
+
}
|
|
747
|
+
);
|
|
748
|
+
}
|
|
749
|
+
async bundle(request, options = {}) {
|
|
750
|
+
const url = new URL("/api/library/bundle", ensureTrailingSlash3(this.transport.baseUrl));
|
|
751
|
+
const headers = new Headers(options.headers);
|
|
752
|
+
if (this.transport.apiKey) {
|
|
753
|
+
headers.set("authorization", `Bearer ${this.transport.apiKey}`);
|
|
754
|
+
}
|
|
755
|
+
headers.set("content-type", "application/json");
|
|
756
|
+
const response = await fetch(url.toString(), {
|
|
757
|
+
method: "POST",
|
|
758
|
+
headers,
|
|
759
|
+
body: JSON.stringify(request),
|
|
760
|
+
signal: options.signal
|
|
761
|
+
});
|
|
762
|
+
if (!response.ok) {
|
|
763
|
+
throw await bundleError(response);
|
|
764
|
+
}
|
|
765
|
+
return response.blob();
|
|
766
|
+
}
|
|
767
|
+
async ingest(request, options = {}) {
|
|
768
|
+
return this.transport.request("POST", "/api/library/ingest", {
|
|
769
|
+
body: request,
|
|
770
|
+
signal: options.signal,
|
|
771
|
+
headers: options.headers
|
|
772
|
+
});
|
|
773
|
+
}
|
|
774
|
+
async ingestSync(request, options = {}) {
|
|
775
|
+
return this.transport.request("POST", "/api/library/ingest/sync", {
|
|
776
|
+
body: request,
|
|
777
|
+
signal: options.signal,
|
|
778
|
+
headers: options.headers
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
async ingestStatus(jobId, options = {}) {
|
|
782
|
+
return this.transport.request(
|
|
783
|
+
"GET",
|
|
784
|
+
`/api/library/ingest/${encodeURIComponent(jobId)}`,
|
|
785
|
+
{
|
|
786
|
+
signal: options.signal,
|
|
787
|
+
headers: options.headers
|
|
788
|
+
}
|
|
789
|
+
);
|
|
790
|
+
}
|
|
791
|
+
async ingestWait(jobId, opts = {}) {
|
|
792
|
+
const intervalMs = Math.max(opts.intervalMs ?? 1e3, 250);
|
|
793
|
+
for (; ; ) {
|
|
794
|
+
const job = await this.ingestStatus(jobId, opts);
|
|
795
|
+
if (job.status === "completed") {
|
|
796
|
+
return ingestResultFromJob(job);
|
|
797
|
+
}
|
|
798
|
+
if (job.status === "failed" || job.status === "cancelled") {
|
|
799
|
+
throw new AssetForgeError(job.error_message ?? `Library ingest job ${jobId} ${job.status}`, {
|
|
800
|
+
code: job.status === "cancelled" ? "JOB_CANCELLED" : "API_ERROR",
|
|
801
|
+
details: job
|
|
802
|
+
});
|
|
803
|
+
}
|
|
804
|
+
await sleep2(intervalMs, opts.signal);
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
async packs(options = {}) {
|
|
808
|
+
return this.transport.request("GET", "/api/library/packs", {
|
|
809
|
+
signal: options.signal,
|
|
810
|
+
headers: options.headers
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
async packsInstall(request, options = {}) {
|
|
814
|
+
return this.transport.request("POST", "/api/library/packs/install", {
|
|
815
|
+
body: request,
|
|
816
|
+
signal: options.signal,
|
|
817
|
+
headers: options.headers
|
|
818
|
+
});
|
|
819
|
+
}
|
|
820
|
+
async packsDelete(id, options = {}) {
|
|
821
|
+
return this.transport.request(
|
|
822
|
+
"DELETE",
|
|
823
|
+
`/api/library/packs/${encodeURIComponent(id)}`,
|
|
824
|
+
{
|
|
825
|
+
signal: options.signal,
|
|
826
|
+
headers: options.headers
|
|
827
|
+
}
|
|
828
|
+
);
|
|
829
|
+
}
|
|
830
|
+
async packsRefresh(id, options = {}) {
|
|
831
|
+
return this.transport.request(
|
|
832
|
+
"POST",
|
|
833
|
+
`/api/library/packs/${encodeURIComponent(id)}/refresh`,
|
|
834
|
+
{
|
|
835
|
+
body: {},
|
|
836
|
+
signal: options.signal,
|
|
837
|
+
headers: options.headers
|
|
838
|
+
}
|
|
839
|
+
);
|
|
840
|
+
}
|
|
841
|
+
async add(request, options = {}) {
|
|
842
|
+
return this.transport.request(
|
|
843
|
+
"POST",
|
|
844
|
+
"/api/library",
|
|
845
|
+
{
|
|
846
|
+
body: request,
|
|
847
|
+
signal: options.signal,
|
|
848
|
+
headers: options.headers
|
|
849
|
+
}
|
|
850
|
+
);
|
|
851
|
+
}
|
|
852
|
+
async get(id, options = {}) {
|
|
853
|
+
return this.transport.request(
|
|
854
|
+
"GET",
|
|
855
|
+
`/api/library/${encodeURIComponent(id)}`,
|
|
856
|
+
{
|
|
857
|
+
signal: options.signal,
|
|
858
|
+
headers: options.headers
|
|
859
|
+
}
|
|
860
|
+
);
|
|
861
|
+
}
|
|
862
|
+
async delete(id, options = {}) {
|
|
863
|
+
return this.transport.request(
|
|
864
|
+
"DELETE",
|
|
865
|
+
`/api/library/${encodeURIComponent(id)}`,
|
|
866
|
+
{
|
|
867
|
+
signal: options.signal,
|
|
868
|
+
headers: options.headers
|
|
869
|
+
}
|
|
870
|
+
);
|
|
871
|
+
}
|
|
872
|
+
async catalogJobs(request = {}, options = {}) {
|
|
873
|
+
return this.transport.request("POST", "/api/library/catalog-jobs", {
|
|
874
|
+
body: request,
|
|
875
|
+
signal: options.signal,
|
|
876
|
+
headers: options.headers
|
|
877
|
+
});
|
|
878
|
+
}
|
|
879
|
+
async backfill(request = {}, options = {}) {
|
|
880
|
+
return this.transport.request("POST", "/api/library/admin/backfill", {
|
|
881
|
+
body: request,
|
|
882
|
+
signal: options.signal,
|
|
883
|
+
headers: options.headers
|
|
884
|
+
});
|
|
885
|
+
}
|
|
886
|
+
async reenrich(request = {}, options = {}) {
|
|
887
|
+
return this.transport.request("POST", "/api/library/admin/reenrich", {
|
|
888
|
+
body: request,
|
|
889
|
+
signal: options.signal,
|
|
890
|
+
headers: options.headers
|
|
891
|
+
});
|
|
892
|
+
}
|
|
893
|
+
};
|
|
894
|
+
function ingestResultFromJob(job) {
|
|
895
|
+
const response = job.response;
|
|
896
|
+
if (isIngestResult(response)) {
|
|
897
|
+
return response;
|
|
898
|
+
}
|
|
899
|
+
throw new AssetForgeError(`Library ingest job ${job.id} completed without an ingest result`, {
|
|
900
|
+
code: "API_ERROR",
|
|
901
|
+
details: job
|
|
902
|
+
});
|
|
903
|
+
}
|
|
904
|
+
function isIngestResult(value) {
|
|
905
|
+
return typeof value === "object" && value !== null && typeof value.library_id === "string" && typeof value.skipped === "boolean" && typeof value.embedding_dim === "number";
|
|
906
|
+
}
|
|
907
|
+
function ensureTrailingSlash3(value) {
|
|
908
|
+
return value.endsWith("/") ? value : `${value}/`;
|
|
909
|
+
}
|
|
910
|
+
async function bundleError(response) {
|
|
911
|
+
const text = await response.text();
|
|
912
|
+
let payload = text;
|
|
913
|
+
try {
|
|
914
|
+
payload = JSON.parse(text);
|
|
915
|
+
} catch {
|
|
916
|
+
}
|
|
917
|
+
const message = extractErrorMessage(payload) ?? `AssetForge API error (${response.status})`;
|
|
918
|
+
return new AssetForgeError(message, {
|
|
919
|
+
code: response.status === 404 ? "NOT_FOUND" : "API_ERROR",
|
|
920
|
+
status: response.status,
|
|
921
|
+
details: payload
|
|
922
|
+
});
|
|
923
|
+
}
|
|
924
|
+
function extractErrorMessage(payload) {
|
|
925
|
+
if (typeof payload === "string") {
|
|
926
|
+
return payload || void 0;
|
|
927
|
+
}
|
|
928
|
+
if (typeof payload !== "object" || payload === null) {
|
|
929
|
+
return void 0;
|
|
930
|
+
}
|
|
931
|
+
const error = payload.error;
|
|
932
|
+
if (typeof error === "string") {
|
|
933
|
+
return error;
|
|
934
|
+
}
|
|
935
|
+
if (typeof error === "object" && error !== null) {
|
|
936
|
+
const message = error.message;
|
|
937
|
+
return typeof message === "string" ? message : void 0;
|
|
938
|
+
}
|
|
939
|
+
return void 0;
|
|
940
|
+
}
|
|
941
|
+
function sleep2(ms, signal) {
|
|
942
|
+
if (signal?.aborted) {
|
|
943
|
+
return Promise.reject(new AssetForgeError("The operation was aborted", { code: "ABORTED" }));
|
|
944
|
+
}
|
|
945
|
+
return new Promise((resolve, reject) => {
|
|
946
|
+
const timer = setTimeout(resolve, ms);
|
|
947
|
+
signal?.addEventListener(
|
|
948
|
+
"abort",
|
|
949
|
+
() => {
|
|
950
|
+
clearTimeout(timer);
|
|
951
|
+
reject(new AssetForgeError("The operation was aborted", { code: "ABORTED" }));
|
|
952
|
+
},
|
|
953
|
+
{ once: true }
|
|
954
|
+
);
|
|
955
|
+
});
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
// src/providers.ts
|
|
959
|
+
var AssetForgeProviders = class {
|
|
960
|
+
constructor(transport) {
|
|
961
|
+
this.transport = transport;
|
|
962
|
+
}
|
|
963
|
+
transport;
|
|
964
|
+
async list(options = {}) {
|
|
965
|
+
return this.transport.request("GET", "/api/providers", {
|
|
966
|
+
signal: options.signal,
|
|
967
|
+
headers: options.headers
|
|
968
|
+
});
|
|
969
|
+
}
|
|
970
|
+
async health(idOrOptions, maybeOptions = {}) {
|
|
971
|
+
if (typeof idOrOptions === "string") {
|
|
972
|
+
return this.transport.request(
|
|
973
|
+
"GET",
|
|
974
|
+
`/api/providers/${encodeURIComponent(idOrOptions)}/health`,
|
|
975
|
+
{
|
|
976
|
+
signal: maybeOptions.signal,
|
|
977
|
+
headers: maybeOptions.headers
|
|
978
|
+
}
|
|
979
|
+
);
|
|
980
|
+
}
|
|
981
|
+
const options = idOrOptions ?? {};
|
|
982
|
+
return this.transport.request("GET", "/api/providers/health", {
|
|
983
|
+
signal: options.signal,
|
|
984
|
+
headers: options.headers
|
|
985
|
+
});
|
|
986
|
+
}
|
|
987
|
+
};
|
|
988
|
+
|
|
989
|
+
// src/upload.ts
|
|
990
|
+
var AssetForgeAssets = class {
|
|
991
|
+
constructor(transport) {
|
|
992
|
+
this.transport = transport;
|
|
993
|
+
}
|
|
994
|
+
transport;
|
|
995
|
+
async upload(input, options = {}) {
|
|
996
|
+
const form = new FormData();
|
|
997
|
+
const { blob, filename } = normalizeUploadInput(input, options);
|
|
998
|
+
form.append("file", blob, filename);
|
|
999
|
+
const result = await this.transport.request("POST", "/api/assets/upload", {
|
|
1000
|
+
form,
|
|
1001
|
+
signal: options.signal,
|
|
1002
|
+
headers: options.headers
|
|
1003
|
+
});
|
|
1004
|
+
return normalizeUploadResult(this.transport.baseUrl, result);
|
|
1005
|
+
}
|
|
1006
|
+
async list(options = {}) {
|
|
1007
|
+
const result = await this.transport.request("GET", "/api/assets", {
|
|
1008
|
+
signal: options.signal,
|
|
1009
|
+
headers: options.headers
|
|
1010
|
+
});
|
|
1011
|
+
return {
|
|
1012
|
+
...result,
|
|
1013
|
+
files: result.files.map((file) => normalizeAssetFile(this.transport.baseUrl, file))
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
async delete(filename, options = {}) {
|
|
1017
|
+
return this.transport.request(
|
|
1018
|
+
"DELETE",
|
|
1019
|
+
`/api/assets/${encodeURIComponent(filename)}`,
|
|
1020
|
+
{
|
|
1021
|
+
signal: options.signal,
|
|
1022
|
+
headers: options.headers
|
|
1023
|
+
}
|
|
1024
|
+
);
|
|
1025
|
+
}
|
|
1026
|
+
};
|
|
1027
|
+
function normalizeUploadInput(input, options) {
|
|
1028
|
+
if (typeof File !== "undefined" && input instanceof File) {
|
|
1029
|
+
return {
|
|
1030
|
+
blob: input,
|
|
1031
|
+
filename: options.filename ?? input.name
|
|
1032
|
+
};
|
|
1033
|
+
}
|
|
1034
|
+
if (input instanceof Blob) {
|
|
1035
|
+
return {
|
|
1036
|
+
blob: input,
|
|
1037
|
+
filename: options.filename ?? inferFilename(input.type, "upload")
|
|
1038
|
+
};
|
|
1039
|
+
}
|
|
1040
|
+
if (input instanceof ArrayBuffer) {
|
|
1041
|
+
return {
|
|
1042
|
+
blob: new Blob([input], { type: options.type ?? "application/octet-stream" }),
|
|
1043
|
+
filename: options.filename ?? inferFilename(options.type, "upload")
|
|
1044
|
+
};
|
|
1045
|
+
}
|
|
1046
|
+
if (input instanceof Uint8Array) {
|
|
1047
|
+
const arrayBuffer = new Uint8Array(input).buffer;
|
|
1048
|
+
return {
|
|
1049
|
+
blob: new Blob([arrayBuffer], { type: options.type ?? "application/octet-stream" }),
|
|
1050
|
+
filename: options.filename ?? inferFilename(options.type, "upload")
|
|
1051
|
+
};
|
|
1052
|
+
}
|
|
1053
|
+
if (typeof input === "object" && input !== null && "data" in input) {
|
|
1054
|
+
if (!input.filename.trim()) {
|
|
1055
|
+
throw new AssetForgeError("Upload filename cannot be empty", {
|
|
1056
|
+
code: "INVALID_UPLOAD_INPUT"
|
|
1057
|
+
});
|
|
1058
|
+
}
|
|
1059
|
+
return {
|
|
1060
|
+
blob: new Blob(Array.isArray(input.data) ? input.data : [input.data], {
|
|
1061
|
+
type: input.type ?? options.type ?? "application/octet-stream"
|
|
1062
|
+
}),
|
|
1063
|
+
filename: options.filename ?? input.filename
|
|
1064
|
+
};
|
|
1065
|
+
}
|
|
1066
|
+
throw new AssetForgeError("Unsupported upload input", {
|
|
1067
|
+
code: "INVALID_UPLOAD_INPUT"
|
|
1068
|
+
});
|
|
1069
|
+
}
|
|
1070
|
+
function inferFilename(contentType, basename) {
|
|
1071
|
+
const extension = mimeToExtension(contentType);
|
|
1072
|
+
return extension ? `${basename}.${extension}` : `${basename}.bin`;
|
|
1073
|
+
}
|
|
1074
|
+
function mimeToExtension(contentType) {
|
|
1075
|
+
switch (contentType) {
|
|
1076
|
+
case "image/png":
|
|
1077
|
+
return "png";
|
|
1078
|
+
case "image/jpeg":
|
|
1079
|
+
return "jpg";
|
|
1080
|
+
case "image/webp":
|
|
1081
|
+
return "webp";
|
|
1082
|
+
case "video/mp4":
|
|
1083
|
+
return "mp4";
|
|
1084
|
+
case "audio/mpeg":
|
|
1085
|
+
return "mp3";
|
|
1086
|
+
case "audio/wav":
|
|
1087
|
+
return "wav";
|
|
1088
|
+
case "model/gltf-binary":
|
|
1089
|
+
return "glb";
|
|
1090
|
+
default:
|
|
1091
|
+
return null;
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
// src/client.ts
|
|
1096
|
+
var DEFAULT_BASE_URL = "https://asset.origingame.dev";
|
|
1097
|
+
var AssetForge = class {
|
|
1098
|
+
baseUrl;
|
|
1099
|
+
job;
|
|
1100
|
+
library;
|
|
1101
|
+
providers;
|
|
1102
|
+
assets;
|
|
1103
|
+
stream;
|
|
1104
|
+
voice;
|
|
1105
|
+
apiKey;
|
|
1106
|
+
fetchImpl;
|
|
1107
|
+
defaultHeaders;
|
|
1108
|
+
constructor(options) {
|
|
1109
|
+
if (!options.apiKey.trim()) {
|
|
1110
|
+
throw new AssetForgeError("AssetForge apiKey cannot be empty", {
|
|
1111
|
+
code: "CONFIG_ERROR"
|
|
1112
|
+
});
|
|
1113
|
+
}
|
|
1114
|
+
if (typeof fetch !== "function" && !options.fetch) {
|
|
1115
|
+
throw new AssetForgeError("Global fetch is unavailable in this runtime", {
|
|
1116
|
+
code: "FETCH_UNAVAILABLE"
|
|
1117
|
+
});
|
|
1118
|
+
}
|
|
1119
|
+
this.apiKey = options.apiKey.trim();
|
|
1120
|
+
this.baseUrl = options.baseUrl?.trim() || DEFAULT_BASE_URL;
|
|
1121
|
+
this.fetchImpl = options.fetch ?? fetch;
|
|
1122
|
+
this.defaultHeaders = options.headers ?? {};
|
|
1123
|
+
this.job = new AssetForgeJobs(this);
|
|
1124
|
+
this.library = new AssetForgeLibrary(this);
|
|
1125
|
+
this.providers = new AssetForgeProviders(this);
|
|
1126
|
+
this.assets = new AssetForgeAssets(this);
|
|
1127
|
+
this.stream = new AssetForgeStreamNamespace(this);
|
|
1128
|
+
const cloneVoice = ((request, reqOptions = {}) => this.submitAndMaybeWait(
|
|
1129
|
+
"/api/voice/clone",
|
|
1130
|
+
request,
|
|
1131
|
+
reqOptions
|
|
1132
|
+
));
|
|
1133
|
+
this.voice = {
|
|
1134
|
+
clone: cloneVoice,
|
|
1135
|
+
design: (request, reqOptions = {}) => this.request("POST", "/api/voice/design", {
|
|
1136
|
+
body: request,
|
|
1137
|
+
signal: reqOptions.signal,
|
|
1138
|
+
headers: reqOptions.headers
|
|
1139
|
+
}),
|
|
1140
|
+
list: (query = {}) => this.request("GET", "/api/voice/list", {
|
|
1141
|
+
query: {
|
|
1142
|
+
type: query.type,
|
|
1143
|
+
page: query.page,
|
|
1144
|
+
page_size: query.page_size
|
|
1145
|
+
},
|
|
1146
|
+
signal: query.signal,
|
|
1147
|
+
headers: query.headers
|
|
1148
|
+
}),
|
|
1149
|
+
delete: (voiceId, query = {}) => this.request("DELETE", `/api/voice/${encodeURIComponent(voiceId)}`, {
|
|
1150
|
+
query: { type: query.type },
|
|
1151
|
+
signal: query.signal,
|
|
1152
|
+
headers: query.headers
|
|
1153
|
+
})
|
|
1154
|
+
};
|
|
1155
|
+
}
|
|
1156
|
+
async login(token = this.apiKey, options = {}) {
|
|
1157
|
+
return this.request("POST", "/auth/login", {
|
|
1158
|
+
body: { token },
|
|
1159
|
+
signal: options.signal,
|
|
1160
|
+
headers: options.headers
|
|
1161
|
+
});
|
|
1162
|
+
}
|
|
1163
|
+
async generate(request, options = {}) {
|
|
1164
|
+
return this.submitAndMaybeWait(
|
|
1165
|
+
"/api/generate",
|
|
1166
|
+
request,
|
|
1167
|
+
options,
|
|
1168
|
+
(response) => normalizeGenerateResponse(this.baseUrl, response)
|
|
1169
|
+
);
|
|
1170
|
+
}
|
|
1171
|
+
async batch(request, options = {}) {
|
|
1172
|
+
return this.submitAndMaybeWait(
|
|
1173
|
+
"/api/generate/batch",
|
|
1174
|
+
request,
|
|
1175
|
+
options,
|
|
1176
|
+
(response) => normalizeBatchResponse(this.baseUrl, response)
|
|
1177
|
+
);
|
|
1178
|
+
}
|
|
1179
|
+
async process(request, options = {}) {
|
|
1180
|
+
return this.submitAndMaybeWait("/api/process", request, options);
|
|
1181
|
+
}
|
|
1182
|
+
async process3d(request, options = {}) {
|
|
1183
|
+
return this.submitAndMaybeWait("/api/process3d", request, options);
|
|
1184
|
+
}
|
|
1185
|
+
async upload(input, options = {}) {
|
|
1186
|
+
return this.assets.upload(input, options);
|
|
1187
|
+
}
|
|
1188
|
+
image(prompt, options = {}) {
|
|
1189
|
+
const { signal, headers, async: asyncMode, idempotencyKey, ...rest } = options;
|
|
1190
|
+
return this.generate(buildImageRequest(prompt, rest), { signal, headers, async: asyncMode, idempotencyKey });
|
|
1191
|
+
}
|
|
1192
|
+
animation(prompt, options = {}) {
|
|
1193
|
+
const { signal, headers, async: asyncMode, idempotencyKey, ...rest } = options;
|
|
1194
|
+
return this.generate(buildGeneratedAssetRequest("animation", prompt, rest), { signal, headers, async: asyncMode, idempotencyKey });
|
|
1195
|
+
}
|
|
1196
|
+
material(_prompt, _options = {}) {
|
|
1197
|
+
return Promise.resolve(packOnlyResponse("material"));
|
|
1198
|
+
}
|
|
1199
|
+
hdri(_prompt, _options = {}) {
|
|
1200
|
+
return Promise.resolve(packOnlyResponse("hdri"));
|
|
1201
|
+
}
|
|
1202
|
+
vfx(_prompt, _options = {}) {
|
|
1203
|
+
return Promise.resolve(packOnlyResponse("vfx"));
|
|
1204
|
+
}
|
|
1205
|
+
lut(_prompt, _options = {}) {
|
|
1206
|
+
return Promise.resolve(packOnlyResponse("lut"));
|
|
1207
|
+
}
|
|
1208
|
+
shader(_prompt, _options = {}) {
|
|
1209
|
+
return Promise.resolve(packOnlyResponse("shader"));
|
|
1210
|
+
}
|
|
1211
|
+
fontTypeface(_prompt, _options = {}) {
|
|
1212
|
+
return Promise.resolve(packOnlyResponse("font_typeface"));
|
|
1213
|
+
}
|
|
1214
|
+
skybox(prompt, options = {}) {
|
|
1215
|
+
const { signal, headers, async: asyncMode, idempotencyKey, ...rest } = options;
|
|
1216
|
+
return this.generate(buildGeneratedAssetRequest("skybox", prompt, rest), { signal, headers, async: asyncMode, idempotencyKey });
|
|
1217
|
+
}
|
|
1218
|
+
decal(prompt, options = {}) {
|
|
1219
|
+
const { signal, headers, async: asyncMode, idempotencyKey, ...rest } = options;
|
|
1220
|
+
return this.generate(buildGeneratedAssetRequest("decal", prompt, rest), { signal, headers, async: asyncMode, idempotencyKey });
|
|
1221
|
+
}
|
|
1222
|
+
heightmap(prompt, options = {}) {
|
|
1223
|
+
const { signal, headers, async: asyncMode, idempotencyKey, ...rest } = options;
|
|
1224
|
+
return this.generate(buildGeneratedAssetRequest("heightmap", prompt, rest), { signal, headers, async: asyncMode, idempotencyKey });
|
|
1225
|
+
}
|
|
1226
|
+
video(promptOrRequest, options = {}) {
|
|
1227
|
+
if (typeof promptOrRequest === "string") {
|
|
1228
|
+
const { signal: signal2, headers: headers2, async: asyncMode2, idempotencyKey: idempotencyKey2, ...rest2 } = options;
|
|
1229
|
+
return this.generate(buildVideoRequest(promptOrRequest, rest2), { signal: signal2, headers: headers2, async: asyncMode2, idempotencyKey: idempotencyKey2 });
|
|
1230
|
+
}
|
|
1231
|
+
const { prompt, signal, headers, async: asyncMode, idempotencyKey, ...rest } = promptOrRequest;
|
|
1232
|
+
return this.generate(buildVideoRequest(prompt, rest), { signal, headers, async: asyncMode, idempotencyKey });
|
|
1233
|
+
}
|
|
1234
|
+
audio(prompt, options = {}) {
|
|
1235
|
+
const { signal, headers, async: asyncMode, idempotencyKey, ...rest } = options;
|
|
1236
|
+
return this.generate(buildAudioRequest(prompt, rest), { signal, headers, async: asyncMode, idempotencyKey });
|
|
1237
|
+
}
|
|
1238
|
+
music(prompt, options = {}) {
|
|
1239
|
+
const { signal, headers, async: asyncMode, idempotencyKey, ...rest } = options;
|
|
1240
|
+
return this.generate(buildMusicRequest(prompt, rest), { signal, headers, async: asyncMode, idempotencyKey });
|
|
1241
|
+
}
|
|
1242
|
+
tts(prompt, options = {}) {
|
|
1243
|
+
const { signal, headers, async: asyncMode, idempotencyKey, ...rest } = options;
|
|
1244
|
+
return this.generate(buildTtsRequest(prompt, rest), { signal, headers, async: asyncMode, idempotencyKey });
|
|
1245
|
+
}
|
|
1246
|
+
model3d(prompt, options = {}) {
|
|
1247
|
+
const { signal, headers, async: asyncMode, idempotencyKey, ...rest } = options;
|
|
1248
|
+
return this.generate(buildModel3dRequest(prompt, rest), { signal, headers, async: asyncMode, idempotencyKey });
|
|
1249
|
+
}
|
|
1250
|
+
character(prompt, options = {}) {
|
|
1251
|
+
const { signal, headers, async: asyncMode, idempotencyKey, ...rest } = options;
|
|
1252
|
+
return this.generate(buildCharacterRequest(prompt, rest), { signal, headers, async: asyncMode, idempotencyKey });
|
|
1253
|
+
}
|
|
1254
|
+
prop(prompt, options = {}) {
|
|
1255
|
+
const { signal, headers, async: asyncMode, idempotencyKey, ...rest } = options;
|
|
1256
|
+
return this.generate(buildPropRequest(prompt, rest), { signal, headers, async: asyncMode, idempotencyKey });
|
|
1257
|
+
}
|
|
1258
|
+
sprite(prompt, options = {}) {
|
|
1259
|
+
const { signal, headers, async: asyncMode, idempotencyKey, ...rest } = options;
|
|
1260
|
+
return this.generate(buildSpriteRequest(prompt, rest), { signal, headers, async: asyncMode, idempotencyKey });
|
|
1261
|
+
}
|
|
1262
|
+
world(prompt, options = {}) {
|
|
1263
|
+
const { signal, headers, async: asyncMode, idempotencyKey, ...rest } = options;
|
|
1264
|
+
return this.generate(buildWorldRequest(prompt, rest), { signal, headers, async: asyncMode, idempotencyKey });
|
|
1265
|
+
}
|
|
1266
|
+
text(prompt, options = {}) {
|
|
1267
|
+
const { signal, headers, async: asyncMode, idempotencyKey, ...rest } = options;
|
|
1268
|
+
return this.generate(buildTextRequest(prompt, rest), { signal, headers, async: asyncMode, idempotencyKey });
|
|
1269
|
+
}
|
|
1270
|
+
async request(method, path, options = {}) {
|
|
1271
|
+
const url = new URL(path, ensureTrailingSlash4(this.baseUrl));
|
|
1272
|
+
appendQuery(url, options.query);
|
|
1273
|
+
const headers = new Headers(this.defaultHeaders);
|
|
1274
|
+
headers.set("authorization", `Bearer ${this.apiKey}`);
|
|
1275
|
+
applyHeaders(headers, options.headers);
|
|
1276
|
+
let body;
|
|
1277
|
+
if (options.form) {
|
|
1278
|
+
body = options.form;
|
|
1279
|
+
} else if (options.body !== void 0) {
|
|
1280
|
+
headers.set("content-type", "application/json");
|
|
1281
|
+
body = JSON.stringify(options.body);
|
|
1282
|
+
}
|
|
1283
|
+
let response;
|
|
1284
|
+
try {
|
|
1285
|
+
response = await this.fetchImpl(url.toString(), {
|
|
1286
|
+
method,
|
|
1287
|
+
headers,
|
|
1288
|
+
body,
|
|
1289
|
+
signal: options.signal
|
|
1290
|
+
});
|
|
1291
|
+
} catch (error) {
|
|
1292
|
+
throw new AssetForgeError(
|
|
1293
|
+
error instanceof Error ? error.message : String(error),
|
|
1294
|
+
{
|
|
1295
|
+
code: options.signal?.aborted ? "ABORTED" : "NETWORK_ERROR",
|
|
1296
|
+
cause: error
|
|
1297
|
+
}
|
|
1298
|
+
);
|
|
1299
|
+
}
|
|
1300
|
+
const text = await response.text();
|
|
1301
|
+
const payload = parseJson2(text);
|
|
1302
|
+
const envelope = isEnvelope(payload) ? payload : null;
|
|
1303
|
+
if (envelope?.ok) {
|
|
1304
|
+
return envelope.data;
|
|
1305
|
+
}
|
|
1306
|
+
if (!response.ok || envelope?.ok === false) {
|
|
1307
|
+
throw createApiError(response.status, envelope?.command, envelope?.ok === false ? envelope.error : payload);
|
|
1308
|
+
}
|
|
1309
|
+
return payload;
|
|
1310
|
+
}
|
|
1311
|
+
async submitAndMaybeWait(path, body, options, normalize) {
|
|
1312
|
+
const ack = await this.request("POST", path, {
|
|
1313
|
+
body,
|
|
1314
|
+
signal: options.signal,
|
|
1315
|
+
headers: submitHeaders({ ...options, async: true })
|
|
1316
|
+
});
|
|
1317
|
+
if (options.async) {
|
|
1318
|
+
return ack;
|
|
1319
|
+
}
|
|
1320
|
+
const job = await this.job.wait(ack.job_id, {
|
|
1321
|
+
signal: options.signal,
|
|
1322
|
+
headers: options.headers
|
|
1323
|
+
});
|
|
1324
|
+
if (job.response === void 0 || job.response === null) {
|
|
1325
|
+
throw new AssetForgeError(`Completed job ${ack.job_id} is missing response payload`, {
|
|
1326
|
+
code: "JOB_RESPONSE_MISSING",
|
|
1327
|
+
details: job
|
|
1328
|
+
});
|
|
1329
|
+
}
|
|
1330
|
+
const response = job.response;
|
|
1331
|
+
return normalize ? normalize(response) : response;
|
|
1332
|
+
}
|
|
1333
|
+
};
|
|
1334
|
+
function createApiError(status, command, error) {
|
|
1335
|
+
if (typeof error === "string") {
|
|
1336
|
+
return new AssetForgeError(error, {
|
|
1337
|
+
code: defaultErrorCode2(status),
|
|
1338
|
+
status,
|
|
1339
|
+
command,
|
|
1340
|
+
details: error
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
1343
|
+
if (isApiErrorPayload(error)) {
|
|
1344
|
+
return new AssetForgeError(error.message ?? `AssetForge API error (${status})`, {
|
|
1345
|
+
code: error.code ?? defaultErrorCode2(status),
|
|
1346
|
+
status,
|
|
1347
|
+
command,
|
|
1348
|
+
details: error
|
|
1349
|
+
});
|
|
1350
|
+
}
|
|
1351
|
+
return new AssetForgeError(
|
|
1352
|
+
typeof error === "object" && error !== null ? JSON.stringify(error) : `AssetForge API error (${status})`,
|
|
1353
|
+
{
|
|
1354
|
+
code: defaultErrorCode2(status),
|
|
1355
|
+
status,
|
|
1356
|
+
command,
|
|
1357
|
+
details: error
|
|
1358
|
+
}
|
|
1359
|
+
);
|
|
1360
|
+
}
|
|
1361
|
+
function defaultErrorCode2(status) {
|
|
1362
|
+
if (status === 401) return "UNAUTHORIZED";
|
|
1363
|
+
if (status === 403) return "FORBIDDEN";
|
|
1364
|
+
if (status === 404) return "NOT_FOUND";
|
|
1365
|
+
if (status === 409) return "CONFLICT";
|
|
1366
|
+
return "API_ERROR";
|
|
1367
|
+
}
|
|
1368
|
+
function appendQuery(url, query) {
|
|
1369
|
+
if (!query) {
|
|
1370
|
+
return;
|
|
1371
|
+
}
|
|
1372
|
+
for (const [key, value] of Object.entries(query)) {
|
|
1373
|
+
if (value === void 0 || value === null) {
|
|
1374
|
+
continue;
|
|
1375
|
+
}
|
|
1376
|
+
url.searchParams.set(key, String(value));
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
function applyHeaders(target, source) {
|
|
1380
|
+
if (!source) {
|
|
1381
|
+
return;
|
|
1382
|
+
}
|
|
1383
|
+
const extra = new Headers(source);
|
|
1384
|
+
extra.forEach((value, key) => {
|
|
1385
|
+
target.set(key, value);
|
|
1386
|
+
});
|
|
1387
|
+
}
|
|
1388
|
+
function submitHeaders(options) {
|
|
1389
|
+
const headers = new Headers(options.headers);
|
|
1390
|
+
if (options.async) {
|
|
1391
|
+
headers.set("prefer", "respond-async");
|
|
1392
|
+
}
|
|
1393
|
+
if (options.idempotencyKey) {
|
|
1394
|
+
headers.set("idempotency-key", options.idempotencyKey);
|
|
1395
|
+
}
|
|
1396
|
+
return headers;
|
|
1397
|
+
}
|
|
1398
|
+
function ensureTrailingSlash4(value) {
|
|
1399
|
+
return value.endsWith("/") ? value : `${value}/`;
|
|
1400
|
+
}
|
|
1401
|
+
function parseJson2(text) {
|
|
1402
|
+
if (!text) {
|
|
1403
|
+
return null;
|
|
1404
|
+
}
|
|
1405
|
+
try {
|
|
1406
|
+
return JSON.parse(text);
|
|
1407
|
+
} catch {
|
|
1408
|
+
return text;
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
function isEnvelope(value) {
|
|
1412
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && "ok" in value;
|
|
1413
|
+
}
|
|
1414
|
+
function isApiErrorPayload(value) {
|
|
1415
|
+
return typeof value === "object" && value !== null && ("message" in value || "code" in value);
|
|
1416
|
+
}
|
|
1417
|
+
function packOnlyResponse(assetType) {
|
|
1418
|
+
return {
|
|
1419
|
+
ok: false,
|
|
1420
|
+
pack_only: true,
|
|
1421
|
+
asset_type: assetType,
|
|
1422
|
+
message: "use library packs"
|
|
1423
|
+
};
|
|
1424
|
+
}
|
|
1425
|
+
export {
|
|
1426
|
+
AssetForge,
|
|
1427
|
+
AssetForgeAssets,
|
|
1428
|
+
AssetForgeError,
|
|
1429
|
+
AssetForgeJobs,
|
|
1430
|
+
AssetForgeLibrary,
|
|
1431
|
+
AssetForgeProviders,
|
|
1432
|
+
AssetForgeStreamNamespace,
|
|
1433
|
+
DEFAULT_BASE_URL,
|
|
1434
|
+
buildAudioRequest,
|
|
1435
|
+
buildCharacterRequest,
|
|
1436
|
+
buildImageRequest,
|
|
1437
|
+
buildModel3dRequest,
|
|
1438
|
+
buildMusicRequest,
|
|
1439
|
+
buildPropRequest,
|
|
1440
|
+
buildSpriteRequest,
|
|
1441
|
+
buildTextRequest,
|
|
1442
|
+
buildTtsRequest,
|
|
1443
|
+
buildVideoRequest,
|
|
1444
|
+
buildWorldRequest,
|
|
1445
|
+
normalizeGenerateResponse,
|
|
1446
|
+
subscribeAllJobs,
|
|
1447
|
+
subscribeJob,
|
|
1448
|
+
toAssetForgeError
|
|
1449
|
+
};
|