@fungi.computer/darkroom 0.0.0-stage → 0.0.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 (80) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +315 -2
  3. package/dist/app-media-contracts.d.ts +499 -0
  4. package/dist/app-media-contracts.js +98 -0
  5. package/dist/browser-failure.d.ts +40 -0
  6. package/dist/browser-failure.js +39 -0
  7. package/dist/browser.d.ts +2 -0
  8. package/dist/browser.js +1 -0
  9. package/dist/cloudflare/provider.d.ts +13 -0
  10. package/dist/cloudflare/provider.js +140 -0
  11. package/dist/cloudflare/reference-images.d.ts +42 -0
  12. package/dist/cloudflare/reference-images.js +102 -0
  13. package/dist/cloudflare.d.ts +6 -0
  14. package/dist/cloudflare.js +4 -0
  15. package/dist/cost-estimate.d.ts +22 -0
  16. package/dist/cost-estimate.js +76 -0
  17. package/dist/effect.d.ts +2 -0
  18. package/dist/effect.js +2 -0
  19. package/dist/execution-error.d.ts +54 -0
  20. package/dist/execution-error.js +62 -0
  21. package/dist/failure.d.ts +2 -0
  22. package/dist/failure.js +8 -0
  23. package/dist/gateway-models.d.ts +23 -0
  24. package/dist/gateway-models.js +77 -0
  25. package/dist/gateway-wire.d.ts +16 -0
  26. package/dist/gateway-wire.js +22 -0
  27. package/dist/index.d.ts +361 -0
  28. package/dist/index.js +611 -0
  29. package/dist/media-binding.d.ts +291 -0
  30. package/dist/media-binding.js +146 -0
  31. package/dist/media-generation.d.ts +10 -0
  32. package/dist/media-generation.js +110 -0
  33. package/dist/media-operation-contract.d.ts +104 -0
  34. package/dist/media-operation-contract.js +29 -0
  35. package/dist/media-operation-do.d.ts +55 -0
  36. package/dist/media-operation-do.js +105 -0
  37. package/dist/media-operation-owner.d.ts +301 -0
  38. package/dist/media-operation-owner.js +903 -0
  39. package/dist/media-operation-storage.d.ts +81 -0
  40. package/dist/media-operation-storage.js +1 -0
  41. package/dist/media-operation.d.ts +33 -0
  42. package/dist/media-operation.js +230 -0
  43. package/dist/model-catalog.d.ts +456 -0
  44. package/dist/model-catalog.js +565 -0
  45. package/dist/neurons.d.ts +4 -0
  46. package/dist/neurons.js +4 -0
  47. package/dist/provenance-bytes.d.ts +3 -0
  48. package/dist/provenance-bytes.js +15 -0
  49. package/dist/provenance-export.d.ts +23 -0
  50. package/dist/provenance-export.js +103 -0
  51. package/dist/provenance-jpeg.d.ts +3 -0
  52. package/dist/provenance-jpeg.js +76 -0
  53. package/dist/provenance-png.d.ts +1 -0
  54. package/dist/provenance-png.js +21 -0
  55. package/dist/provenance-xmp.d.ts +2 -0
  56. package/dist/provenance-xmp.js +54 -0
  57. package/dist/provenance.d.ts +20 -0
  58. package/dist/provenance.js +58 -0
  59. package/dist/server.d.ts +158 -0
  60. package/dist/server.js +207 -0
  61. package/dist/video-providers/index.d.ts +14 -0
  62. package/dist/video-providers/index.js +14 -0
  63. package/dist/video-providers/minimax.d.ts +25 -0
  64. package/dist/video-providers/minimax.js +63 -0
  65. package/dist/video-providers/reference-encoding.d.ts +4 -0
  66. package/dist/video-providers/reference-encoding.js +11 -0
  67. package/dist/video-providers/types.d.ts +28 -0
  68. package/dist/video-providers/types.js +1 -0
  69. package/dist/video-providers/unified.d.ts +18 -0
  70. package/dist/video-providers/unified.js +52 -0
  71. package/docs/api/README.md +16 -0
  72. package/docs/api/app-media-contracts.md +507 -0
  73. package/docs/api/browser.md +126 -0
  74. package/docs/api/cloudflare.md +678 -0
  75. package/docs/api/effect.md +39 -0
  76. package/docs/api/index.md +1775 -0
  77. package/docs/api/modules.md +19 -0
  78. package/docs/api/provenance-export.md +114 -0
  79. package/docs/api/server.md +1672 -0
  80. package/package.json +110 -3
@@ -0,0 +1,565 @@
1
+ import * as z from "zod";
2
+ /** An explicitly requested image encoding; video is outside this contract. */
3
+ export const mediaRequestedImageFormatSchema = z.enum({
4
+ /** PNG image encoding. */
5
+ png: "png",
6
+ /** JPEG image encoding. */
7
+ jpeg: "jpeg",
8
+ /** WebP image encoding. */
9
+ webp: "webp",
10
+ });
11
+ /**
12
+ * Agent-facing selection tier: cheap/fast draft work, the balanced default,
13
+ * premium for art the user will see, and max for the most expensive models.
14
+ * One value per model; never a price.
15
+ */
16
+ export const mediaModelTierSchema = z.enum({
17
+ /** Cheap, fast draft model. */
18
+ draft: "draft",
19
+ /** Balanced model selection. */
20
+ balanced: "balanced",
21
+ /** Premium model selection. */
22
+ premium: "premium",
23
+ /** Most expensive model selection. */
24
+ max: "max",
25
+ });
26
+ /** Media's provider catalog: Workers AI images plus gateway image and video models. */
27
+ export const mediaModelInputSchema = z
28
+ .strictObject({
29
+ /** Provider input transport. */
30
+ transport: z.enum({
31
+ /** JSON provider input. */
32
+ json: "json",
33
+ /** Multipart provider input. */
34
+ multipart: "multipart",
35
+ }),
36
+ /** Whether this model accepts explicit output dimensions. */
37
+ dimensions: z.enum({
38
+ /** Provider chooses its own dimensions. */
39
+ none: "none",
40
+ /** Provider accepts the requested dimensions. */
41
+ own: "own",
42
+ }),
43
+ /** Maximum accepted dimension in pixels, or null when unbounded by this model. */
44
+ maxDimension: z.number().int().positive().nullable(),
45
+ /** Default output width in pixels. */
46
+ defaultWidth: z.number().int().positive(),
47
+ /** Default output height in pixels. */
48
+ defaultHeight: z.number().int().positive(),
49
+ /** Model-specific inference step count. */
50
+ steps: z.enum({
51
+ /** Provider reads the steps field. */
52
+ steps: "steps",
53
+ /** Provider reads the num_steps field. */
54
+ num_steps: "num_steps",
55
+ /** Provider uses fixed inference steps. */
56
+ fixed: "fixed",
57
+ }),
58
+ /** Maximum model steps, or null when the model has no step ceiling. */
59
+ maxSteps: z.number().int().positive().nullable(),
60
+ /** Default inference step count. */
61
+ defaultSteps: z.number().int().nonnegative().nullable(),
62
+ /** Provider multipart reference-field prefix, or null when unsupported. */
63
+ referenceField: z.string().min(1).max(256).nullable(),
64
+ /** Maximum references accepted by this model. */
65
+ maxReferences: z.number().int().nonnegative(),
66
+ })
67
+ .readonly();
68
+ /** Verified Unified AI video identifiers; no inferred family aliases. */
69
+ export const mediaVideoModelIdSchema = z.enum({
70
+ /** Seedance 2.0. */
71
+ seedance: "bytedance/seedance-2.0",
72
+ /** Seedance 2.0 Fast. */
73
+ seedanceFast: "bytedance/seedance-2.0-fast",
74
+ /** Seedance 2.0 Mini. */
75
+ seedanceMini: "bytedance/seedance-2.0-mini",
76
+ /** Veo 3.1. */
77
+ veo: "google/veo-3.1",
78
+ /** Veo 3.1 Fast. */
79
+ veoFast: "google/veo-3.1-fast",
80
+ /** MiniMax H3 Max. */
81
+ minimaxH3Max: "minimax/h3-max",
82
+ });
83
+ /** Provider resolution selectors, refined against the selected catalog entry. */
84
+ export const mediaVideoResolutionSchema = z.enum({
85
+ /** 480p. */
86
+ p480: "480p",
87
+ /** 720p. */
88
+ p720: "720p",
89
+ /** 768p, admitted only by MiniMax H3 Max. */
90
+ p768: "768p",
91
+ /** 1080p. */
92
+ p1080: "1080p",
93
+ /** 4k, admitted only by Seedance 2.0. */
94
+ p4k: "4k",
95
+ });
96
+ /** Documented video aspect selectors, refined per model. */
97
+ export const mediaVideoAspectRatioSchema = z.enum({
98
+ /** Landscape widescreen. */
99
+ wide: "16:9",
100
+ /** Landscape standard. */
101
+ landscape: "4:3",
102
+ /** Square. */
103
+ square: "1:1",
104
+ /** Portrait standard. */
105
+ portrait: "3:4",
106
+ /** Portrait widescreen. */
107
+ tall: "9:16",
108
+ /** Landscape ultrawide. */
109
+ ultrawide: "21:9",
110
+ /** Portrait ultrawide. */
111
+ ultratall: "9:21",
112
+ });
113
+ /** Explicit reference meaning; frame mode and reference mode are exclusive. */
114
+ export const mediaVideoReferenceRoleSchema = z.enum({
115
+ /** First frame; required when a last frame is supplied. */
116
+ first: "first-frame",
117
+ /** Last frame, supported by Seedance only. */
118
+ last: "last-frame",
119
+ /** One image in Seedance reference-image mode. */
120
+ reference: "reference",
121
+ });
122
+ /** One nominal size used to select provider resolution and aspect. */
123
+ export const mediaVideoFormatSchema = z
124
+ .strictObject({
125
+ /** Provider resolution. */
126
+ resolution: mediaVideoResolutionSchema,
127
+ /** Requested aspect; Seedance may derive actual aspect from its first image. */
128
+ aspectRatio: mediaVideoAspectRatioSchema,
129
+ /** Nominal width; actual MP4 dimensions are not decoded. */
130
+ width: z.number().int().positive(),
131
+ /** Nominal height; actual MP4 dimensions are not decoded. */
132
+ height: z.number().int().positive(),
133
+ })
134
+ .readonly();
135
+ /** Verified video parameters and provider costs, checked 2026-10-11. */
136
+ export const mediaVideoSchema = z
137
+ .strictObject({
138
+ /** Minimum duration, for callers displaying bounds. */
139
+ minSeconds: z.number().int().positive(),
140
+ /** Maximum duration; durations still owns membership. */
141
+ maxSeconds: z.number().int().positive(),
142
+ /** Default duration. */
143
+ defaultSeconds: z.number().int().positive(),
144
+ /** Exact accepted whole-second durations. */
145
+ durations: z.array(z.number().int().positive()).readonly(),
146
+ /** Verified provider input grammar. */
147
+ provider: z.enum({
148
+ /** Seedance integer duration and data-URI image fields. */
149
+ seedance: "seedance",
150
+ /** Veo duration string and base64 image_input. */
151
+ veo: "veo",
152
+ /** MiniMax multimodal `content[]` array and uppercase resolution. */
153
+ minimax: "minimax",
154
+ }),
155
+ /** Supported resolution/aspect combinations and their nominal selectors. */
156
+ formats: z.array(mediaVideoFormatSchema).readonly(),
157
+ /** Resolution selected when omitted. */
158
+ defaultResolution: mediaVideoResolutionSchema,
159
+ /** Aspect selected when omitted. */
160
+ defaultAspectRatio: mediaVideoAspectRatioSchema,
161
+ /** Audio default, or null when not documented and left to the provider. */
162
+ defaultGenerateAudio: z.boolean().nullable(),
163
+ /** Prompt bound: provider bound for Seedance, retained host bound for Veo. */
164
+ maxPromptLength: z.number().int().positive(),
165
+ /** Frame or reference roles this provider accepts. */
166
+ referenceRoles: z.array(mediaVideoReferenceRoleSchema).readonly(),
167
+ /** Reference-image mode count; first/last frame mode has its own grammar. */
168
+ maxReferenceImages: z.number().int().nonnegative(),
169
+ /** Resolutions supporting reference-image mode. */
170
+ referenceResolutions: z.array(mediaVideoResolutionSchema).readonly(),
171
+ /** Non-video-input provider cost; 1 USD = 100,000 milliunits. */
172
+ prices: z
173
+ .array(z
174
+ .strictObject({
175
+ /** Billed output resolution. */
176
+ resolution: mediaVideoResolutionSchema,
177
+ /** Provider milliunits per output second without audio. */
178
+ silentMilliunitsPerSecond: z.number().int().positive(),
179
+ /** Provider milliunits per output second with audio. */
180
+ audioMilliunitsPerSecond: z.number().int().positive(),
181
+ })
182
+ .readonly())
183
+ .readonly(),
184
+ })
185
+ .readonly();
186
+ /** Public wire grammar for a catalog entry returned by the Media owner. */
187
+ export const mediaModelSchema = z
188
+ .strictObject({
189
+ /** Provider model identifier. */
190
+ id: z.string().min(1).max(256),
191
+ /** Customer-visible model label. */
192
+ label: z.string().min(1).max(512),
193
+ /** Outcome or model-kind discriminant. */
194
+ kind: z.enum({
195
+ /** Still-image generation. */
196
+ image: "image",
197
+ /** Video generation. */
198
+ video: "video",
199
+ }),
200
+ /** Model selection tier, independent of price. */
201
+ tier: mediaModelTierSchema,
202
+ /** Verified provider encodings; an empty list refuses pinned formats. */
203
+ outputFormats: z.array(mediaRequestedImageFormatSchema).max(3).readonly(),
204
+ /** Model-native input options and reference limits. */
205
+ input: mediaModelInputSchema,
206
+ /**
207
+ * Image output sizes or nominal video selectors, as `WIDTHxHEIGHT`; null means
208
+ * any size within the input bounds.
209
+ */
210
+ sizes: z
211
+ .array(z.string().regex(/^\d+x\d+$/u))
212
+ .readonly()
213
+ .nullable(),
214
+ /** Video length constraints, or null for a still-image model. */
215
+ video: mediaVideoSchema.nullable(),
216
+ })
217
+ .readonly();
218
+ const freezeModel = (model) => Object.freeze({
219
+ kind: "image",
220
+ sizes: null,
221
+ video: null,
222
+ outputFormats: Object.freeze([]),
223
+ ...model,
224
+ input: Object.freeze(model.input),
225
+ });
226
+ const videoShortEdges = {
227
+ "480p": 480,
228
+ "720p": 720,
229
+ "768p": 768,
230
+ "1080p": 1080,
231
+ "4k": 2160,
232
+ };
233
+ const videoAspects = {
234
+ "16:9": [16, 9],
235
+ "4:3": [4, 3],
236
+ "1:1": [1, 1],
237
+ "3:4": [3, 4],
238
+ "9:16": [9, 16],
239
+ "21:9": [21, 9],
240
+ "9:21": [9, 21],
241
+ };
242
+ function videoModel(id, label, tier, provider, rates) {
243
+ const seedance = provider === "seedance";
244
+ const aspects = seedance
245
+ ? mediaVideoAspectRatioSchema.options
246
+ : [
247
+ mediaVideoAspectRatioSchema.enum.wide,
248
+ mediaVideoAspectRatioSchema.enum.tall,
249
+ mediaVideoAspectRatioSchema.enum.square,
250
+ ];
251
+ // Nominal dimensions select resolution/aspect; upstream does not accept pixels.
252
+ // Round the long edge to even pixels, retaining the existing 854x480 selector.
253
+ const formats = Object.freeze(rates.flatMap(([resolution]) => aspects.map((aspectRatio) => {
254
+ const [w, h] = videoAspects[aspectRatio];
255
+ const edge = videoShortEdges[resolution];
256
+ const shorter = Math.min(w, h);
257
+ return Object.freeze({
258
+ resolution,
259
+ aspectRatio,
260
+ width: Math.ceil((edge * w) / shorter / 2) * 2,
261
+ height: Math.ceil((edge * h) / shorter / 2) * 2,
262
+ });
263
+ })));
264
+ const durations = Object.freeze(seedance ? [4, 5, 6, 7, 8, 9, 10, 11, 12] : [4, 6, 8]);
265
+ const video = Object.freeze({
266
+ minSeconds: 4,
267
+ maxSeconds: seedance ? 12 : 8,
268
+ defaultSeconds: seedance ? 5 : 6,
269
+ durations,
270
+ provider,
271
+ formats,
272
+ defaultResolution: "720p",
273
+ defaultAspectRatio: "16:9",
274
+ defaultGenerateAudio: seedance ? null : true,
275
+ maxPromptLength: seedance ? 2000 : 2048,
276
+ referenceRoles: Object.freeze(seedance
277
+ ? mediaVideoReferenceRoleSchema.options
278
+ : [mediaVideoReferenceRoleSchema.enum.first]),
279
+ maxReferenceImages: seedance ? 4 : 0,
280
+ referenceResolutions: Object.freeze(seedance
281
+ ? rates
282
+ .map(([resolution]) => resolution)
283
+ .filter((resolution) => resolution !== "1080p")
284
+ : []),
285
+ prices: Object.freeze(rates.map(([resolution, silentMilliunitsPerSecond, audioMilliunitsPerSecond]) => Object.freeze({
286
+ resolution,
287
+ silentMilliunitsPerSecond,
288
+ audioMilliunitsPerSecond,
289
+ }))),
290
+ });
291
+ return freezeModel({
292
+ id,
293
+ label,
294
+ tier,
295
+ kind: "video",
296
+ video,
297
+ sizes: Object.freeze(formats.map(({ width, height }) => `${String(width)}x${String(height)}`)),
298
+ input: {
299
+ transport: "json",
300
+ dimensions: "own",
301
+ maxDimension: Math.max(...formats.map(({ width, height }) => Math.max(width, height))),
302
+ defaultWidth: 1280,
303
+ defaultHeight: 720,
304
+ steps: "fixed",
305
+ maxSteps: null,
306
+ defaultSteps: null,
307
+ referenceField: seedance ? "image" : "image_input",
308
+ maxReferences: seedance ? 4 : 1,
309
+ },
310
+ });
311
+ }
312
+ // MiniMax H3 Max diverges too far from `videoModel()`'s shared seedance/veo
313
+ // shape to reuse it: its wire resolution literals are uppercase ("480P"),
314
+ // its ratio grammar admits no "9:21" selector, and its request body is a
315
+ // multimodal `content[]` array dispatched by `media-generation.ts`, not a
316
+ // flat prompt/image body. https://developers.cloudflare.com/ai/models/minimax/h3-max/
317
+ function minimaxVideoModel() {
318
+ const resolutions = [
319
+ "480p",
320
+ "768p",
321
+ ];
322
+ const aspects = [
323
+ mediaVideoAspectRatioSchema.enum.wide,
324
+ mediaVideoAspectRatioSchema.enum.landscape,
325
+ mediaVideoAspectRatioSchema.enum.square,
326
+ mediaVideoAspectRatioSchema.enum.portrait,
327
+ mediaVideoAspectRatioSchema.enum.tall,
328
+ mediaVideoAspectRatioSchema.enum.ultrawide,
329
+ ];
330
+ const formats = Object.freeze(resolutions.flatMap((resolution) => aspects.map((aspectRatio) => {
331
+ const [w, h] = videoAspects[aspectRatio];
332
+ const edge = videoShortEdges[resolution];
333
+ const shorter = Math.min(w, h);
334
+ return Object.freeze({
335
+ resolution,
336
+ aspectRatio,
337
+ width: Math.ceil((edge * w) / shorter / 2) * 2,
338
+ height: Math.ceil((edge * h) / shorter / 2) * 2,
339
+ });
340
+ })));
341
+ const defaultResolution = mediaVideoResolutionSchema.enum.p768;
342
+ const defaultAspectRatio = mediaVideoAspectRatioSchema.enum.wide;
343
+ const defaultFormat = formats.find((format) => format.resolution === defaultResolution &&
344
+ format.aspectRatio === defaultAspectRatio);
345
+ if (defaultFormat === undefined)
346
+ throw new Error("minimax/h3-max is missing its default format");
347
+ // Integers 5 through 15 inclusive; the documented bound has no gaps.
348
+ const durations = Object.freeze(Array.from({ length: 11 }, (_, index) => index + 5));
349
+ const video = Object.freeze({
350
+ minSeconds: 5,
351
+ maxSeconds: 15,
352
+ defaultSeconds: 5,
353
+ durations,
354
+ provider: "minimax",
355
+ formats,
356
+ defaultResolution,
357
+ defaultAspectRatio,
358
+ // Not merely undocumented: the schema has no audio field at all, so the
359
+ // dispatcher refuses an explicit generateAudio choice outright.
360
+ defaultGenerateAudio: null,
361
+ maxPromptLength: 7000,
362
+ referenceRoles: Object.freeze(mediaVideoReferenceRoleSchema.options),
363
+ // The host-wide MAX_REFERENCE_COUNT (4) already governs every call; the
364
+ // vendor page documents up to nine, which this catalog cannot reach.
365
+ maxReferenceImages: 4,
366
+ referenceResolutions: Object.freeze(resolutions),
367
+ prices: Object.freeze([
368
+ {
369
+ resolution: mediaVideoResolutionSchema.enum.p480,
370
+ // No documented audio surcharge; one rate serves both selectors.
371
+ silentMilliunitsPerSecond: 5_000,
372
+ audioMilliunitsPerSecond: 5_000,
373
+ },
374
+ {
375
+ resolution: mediaVideoResolutionSchema.enum.p768,
376
+ silentMilliunitsPerSecond: 8_000,
377
+ audioMilliunitsPerSecond: 8_000,
378
+ },
379
+ ]),
380
+ });
381
+ return freezeModel({
382
+ id: mediaVideoModelIdSchema.enum.minimaxH3Max,
383
+ label: "MiniMax H3 Max",
384
+ tier: "balanced",
385
+ kind: "video",
386
+ video,
387
+ sizes: Object.freeze(formats.map(({ width, height }) => `${String(width)}x${String(height)}`)),
388
+ input: {
389
+ transport: "json",
390
+ dimensions: "own",
391
+ maxDimension: Math.max(...formats.map(({ width, height }) => Math.max(width, height))),
392
+ defaultWidth: defaultFormat.width,
393
+ defaultHeight: defaultFormat.height,
394
+ steps: "fixed",
395
+ maxSteps: null,
396
+ defaultSteps: null,
397
+ // Inert for this gateway model (media-generation.ts builds its body
398
+ // directly); recorded for the same documentation parity as Seedance/Veo.
399
+ referenceField: "image_url",
400
+ maxReferences: 4,
401
+ },
402
+ });
403
+ }
404
+ const models = Object.freeze([
405
+ freezeModel({
406
+ id: "@cf/black-forest-labs/flux-1-schnell",
407
+ outputFormats: Object.freeze(["jpeg"]),
408
+ tier: "draft",
409
+ label: "Flux 1 Schnell — cheap/fast sketches",
410
+ input: {
411
+ transport: "json",
412
+ dimensions: "none",
413
+ maxDimension: null,
414
+ defaultWidth: 1024,
415
+ defaultHeight: 768,
416
+ steps: "steps",
417
+ maxSteps: 8,
418
+ defaultSteps: 4,
419
+ referenceField: null,
420
+ maxReferences: 0,
421
+ },
422
+ }),
423
+ freezeModel({
424
+ id: "@cf/black-forest-labs/flux-2-klein-4b",
425
+ tier: "balanced",
426
+ label: "Flux 2 Klein 4b — balanced default",
427
+ input: {
428
+ transport: "multipart",
429
+ dimensions: "own",
430
+ maxDimension: 1920,
431
+ defaultWidth: 1024,
432
+ defaultHeight: 768,
433
+ steps: "fixed",
434
+ maxSteps: null,
435
+ defaultSteps: 4,
436
+ referenceField: "input_image_",
437
+ maxReferences: 4,
438
+ },
439
+ }),
440
+ freezeModel({
441
+ id: "@cf/black-forest-labs/flux-2-klein-9b",
442
+ tier: "premium",
443
+ label: "Flux 2 Klein 9b — higher quality flux-2",
444
+ input: {
445
+ transport: "multipart",
446
+ dimensions: "own",
447
+ maxDimension: 1920,
448
+ defaultWidth: 1024,
449
+ defaultHeight: 768,
450
+ steps: "fixed",
451
+ maxSteps: null,
452
+ defaultSteps: 4,
453
+ referenceField: "input_image_",
454
+ maxReferences: 4,
455
+ },
456
+ }),
457
+ freezeModel({
458
+ id: "@cf/black-forest-labs/flux-2-dev",
459
+ tier: "max",
460
+ label: "Flux 2 Dev — best detailed quality, expensive",
461
+ input: {
462
+ transport: "multipart",
463
+ dimensions: "own",
464
+ maxDimension: 1920,
465
+ defaultWidth: 1024,
466
+ defaultHeight: 768,
467
+ steps: "steps",
468
+ maxSteps: null,
469
+ defaultSteps: 20,
470
+ referenceField: "input_image_",
471
+ maxReferences: 4,
472
+ },
473
+ }),
474
+ freezeModel({
475
+ id: "@cf/leonardo/lucid-origin",
476
+ tier: "premium",
477
+ label: "Leonardo Lucid Origin — premium prompt adherence",
478
+ input: {
479
+ transport: "json",
480
+ dimensions: "own",
481
+ maxDimension: 2500,
482
+ defaultWidth: 1120,
483
+ defaultHeight: 1120,
484
+ steps: "num_steps",
485
+ maxSteps: 40,
486
+ defaultSteps: null,
487
+ referenceField: null,
488
+ maxReferences: 0,
489
+ },
490
+ }),
491
+ freezeModel({
492
+ id: "@cf/leonardo/phoenix-1.0",
493
+ tier: "balanced",
494
+ label: "Leonardo Phoenix 1.0 — best prompt adherence",
495
+ input: {
496
+ transport: "json",
497
+ dimensions: "own",
498
+ maxDimension: 2048,
499
+ defaultWidth: 1024,
500
+ defaultHeight: 1024,
501
+ steps: "num_steps",
502
+ maxSteps: 50,
503
+ defaultSteps: 25,
504
+ referenceField: null,
505
+ maxReferences: 0,
506
+ },
507
+ }),
508
+ // Third-party models run through the AI Gateway (Unified Billing): OpenAI's
509
+ // image model and ByteDance's video model return a result URL, not bytes.
510
+ freezeModel({
511
+ id: "openai/gpt-image-2",
512
+ outputFormats: Object.freeze(["png", "jpeg", "webp"]),
513
+ tier: "premium",
514
+ label: "GPT Image 2 — strong text and layout, premium",
515
+ sizes: Object.freeze(["1024x1024", "1024x1536", "1536x1024"]),
516
+ input: {
517
+ transport: "json",
518
+ dimensions: "own",
519
+ maxDimension: 1536,
520
+ defaultWidth: 1024,
521
+ defaultHeight: 1024,
522
+ steps: "fixed",
523
+ maxSteps: null,
524
+ defaultSteps: null,
525
+ referenceField: null,
526
+ maxReferences: 0,
527
+ },
528
+ }),
529
+ videoModel(mediaVideoModelIdSchema.enum.seedance, "Seedance 2.0", "balanced", "seedance", [
530
+ ["480p", 7_000, 7_000],
531
+ ["720p", 15_000, 15_000],
532
+ ["1080p", 37_000, 37_000],
533
+ ["4k", 78_000, 78_000],
534
+ ]),
535
+ videoModel(mediaVideoModelIdSchema.enum.seedanceFast, "Seedance 2.0 Fast", "draft", "seedance", [
536
+ ["480p", 6_000, 6_000],
537
+ ["720p", 12_000, 12_000],
538
+ ]),
539
+ videoModel(mediaVideoModelIdSchema.enum.seedanceMini, "Seedance 2.0 Mini", "draft", "seedance", [
540
+ ["480p", 4_000, 4_000],
541
+ ["720p", 9_000, 9_000],
542
+ ]),
543
+ videoModel(mediaVideoModelIdSchema.enum.veo, "Veo 3.1", "premium", "veo", [
544
+ ["720p", 20_000, 40_000],
545
+ ["1080p", 20_000, 40_000],
546
+ ]),
547
+ videoModel(mediaVideoModelIdSchema.enum.veoFast, "Veo 3.1 Fast", "balanced", "veo", [
548
+ ["720p", 8_000, 10_000],
549
+ ["1080p", 10_000, 12_000],
550
+ ]),
551
+ minimaxVideoModel(),
552
+ ]);
553
+ /** The immutable image and video model catalog. */
554
+ export const mediaModels = models;
555
+ /** List all image and video models in catalog order. */
556
+ export const listMediaModels = () => mediaModels;
557
+ /** Find a model by provider identifier, returning undefined when it is absent. */
558
+ export const getMediaModel = (id) => mediaModels.find((model) => model.id === id);
559
+ /** Invalid generation settings or unsupported model parameters. */
560
+ export class MediaSettingsError extends Error {
561
+ constructor(message) {
562
+ super(message);
563
+ this.name = "MediaSettingsError";
564
+ }
565
+ }
@@ -0,0 +1,4 @@
1
+ /** Published Workers AI image rate: $0.011 per 1,000 neurons. */
2
+ export declare const USD_PER_1K_NEURONS = 0.011;
3
+ /** Convert a neuron estimate to milliunits, rounding up to avoid underquoting. */
4
+ export declare const neuronsToMilliunits: (neurons: number) => number;
@@ -0,0 +1,4 @@
1
+ /** Published Workers AI image rate: $0.011 per 1,000 neurons. */
2
+ export const USD_PER_1K_NEURONS = 0.011;
3
+ /** Convert a neuron estimate to milliunits, rounding up to avoid underquoting. */
4
+ export const neuronsToMilliunits = (neurons) => Math.ceil((neurons * 11) / 10);
@@ -0,0 +1,3 @@
1
+ /** Byte composition only; maintained format owners parse and encode containers. */
2
+ export declare function joinBytes(parts: readonly Uint8Array[]): Uint8Array<ArrayBuffer>;
3
+ export declare function startsWithBytes(bytes: Uint8Array, text: string): boolean;
@@ -0,0 +1,15 @@
1
+ /** Byte composition only; maintained format owners parse and encode containers. */
2
+ export function joinBytes(parts) {
3
+ const result = new Uint8Array(parts.reduce((size, part) => size + part.length, 0));
4
+ let offset = 0;
5
+ for (const part of parts) {
6
+ result.set(part, offset);
7
+ offset += part.length;
8
+ }
9
+ return result;
10
+ }
11
+ export function startsWithBytes(bytes, text) {
12
+ const prefix = new TextEncoder().encode(text);
13
+ return (bytes.length >= prefix.length &&
14
+ prefix.every((value, index) => bytes[index] === value));
15
+ }
@@ -0,0 +1,23 @@
1
+ /** The admitted Computer file read and generated output share this launch bound. */
2
+ export declare const maximumPrintDownloadBytes: number;
3
+ /** Why a lossless public image export was refused. */
4
+ export type ProvenanceExportFailure = "too-large" | "signed-image" | "invalid-image" | "unsupported-format";
5
+ /** A refusal to export unsafe, unsupported or oversized image bytes. */
6
+ export declare class ProvenanceExportError extends Error {
7
+ /** Bounded refusal reason. */
8
+ readonly reason: ProvenanceExportFailure;
9
+ /** Stable export refusal name. */
10
+ readonly name = "ProvenanceExportError";
11
+ constructor(
12
+ /** Bounded refusal reason. */
13
+ reason: ProvenanceExportFailure, options?: ErrorOptions);
14
+ }
15
+ /** Lossless browser export. Never mutates the input or falls back to private bytes. */
16
+ export declare function stripPrivateProvenance(bytes: Uint8Array): Promise<{
17
+ /** Image bytes with private provenance removed. */
18
+ bytes: Uint8Array;
19
+ /** Actual output MIME type. */
20
+ type: string;
21
+ /** Filename extension matching the output encoding. */
22
+ extension: string;
23
+ }>;