@hraness/slopcamera 3.2.8 → 3.3.2

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 (153) hide show
  1. package/README.md +29 -9
  2. package/apps/desktop/application/context.ts +6 -0
  3. package/apps/desktop/application/default-registry.ts +26 -0
  4. package/apps/desktop/application/operation.ts +14 -1
  5. package/apps/desktop/application/operations/index.ts +4 -0
  6. package/apps/desktop/application/operations/spatial-behavior.ts +151 -0
  7. package/apps/desktop/application/operations/spatial-direction.ts +222 -0
  8. package/apps/desktop/application/operations/spatial-rendered-audit.ts +174 -0
  9. package/apps/desktop/application/operations/spatial-review.ts +194 -0
  10. package/apps/desktop/application/operations/spatial-scene.ts +25 -1
  11. package/apps/desktop/application/registry.ts +2 -2
  12. package/apps/desktop/application/spatial-asset-admission.ts +201 -0
  13. package/apps/desktop/application/spatial-assets.ts +160 -31
  14. package/apps/desktop/application/spatial-render.ts +217 -20
  15. package/apps/desktop/application/spatial-rendered-audit.ts +273 -0
  16. package/apps/desktop/application/spatial-review.ts +361 -0
  17. package/apps/desktop/application/spatial-spz.ts +48 -3
  18. package/apps/desktop/application/spatial-world-import.ts +26 -5
  19. package/apps/desktop/application/spatial-world-metadata.ts +105 -0
  20. package/apps/desktop/cli/args.ts +514 -11
  21. package/apps/desktop/cli/capability-manifest.ts +374 -0
  22. package/apps/desktop/cli/cinema-renderer.ts +608 -0
  23. package/apps/desktop/cli/command-host-resources.ts +29 -1
  24. package/apps/desktop/cli/commands.ts +1188 -4
  25. package/apps/desktop/cli/gateway-review-provider.ts +334 -0
  26. package/apps/desktop/cli/help.ts +172 -6
  27. package/apps/desktop/cli/main.ts +3 -3
  28. package/apps/desktop/cli/portable-surface.ts +6 -1
  29. package/apps/desktop/cli/spatial-asset-service.ts +124 -0
  30. package/apps/desktop/cli/spatial-design-service.ts +237 -0
  31. package/apps/desktop/cli/spatial-generate-service.ts +370 -0
  32. package/apps/desktop/cli/spatial-scene-service.ts +271 -4
  33. package/apps/desktop/cli/workflow-code.ts +1 -1
  34. package/apps/desktop/code/semantic-builder.ts +24 -0
  35. package/apps/desktop/contracts/cinema.ts +736 -0
  36. package/apps/desktop/contracts/index.ts +1 -0
  37. package/apps/desktop/contracts/spatial-asset.ts +16 -0
  38. package/apps/desktop/contracts/spatial-world.ts +26 -3
  39. package/apps/desktop/core/cinema-plan.ts +1320 -0
  40. package/apps/desktop/core/index.ts +1 -0
  41. package/apps/desktop/core/storage.ts +75 -0
  42. package/apps/desktop/dist/cli/main.js +725 -273
  43. package/apps/desktop/html-overlay/spatial.ts +619 -57
  44. package/apps/desktop/workflows/cinematic-world.ts +127 -0
  45. package/apps/desktop/workflows/index.ts +6 -0
  46. package/dist/cli.js +25 -429
  47. package/dist/code/advanced.js +1 -269
  48. package/dist/code/index.js +16 -2239
  49. package/dist/generate.js +1 -23
  50. package/dist/host-resources.js +1 -25
  51. package/dist/index-0bbesn4m.js +35 -0
  52. package/dist/index-296qhpf2.js +3 -0
  53. package/dist/index-3cxf2c58.js +3 -0
  54. package/dist/index-77fjfg9f.js +3 -0
  55. package/dist/index-80a36bc0.js +3 -0
  56. package/dist/index-a3vvs3rf.js +3 -0
  57. package/dist/index-b3geqczn.js +5 -0
  58. package/dist/index-grk47tgs.js +3 -0
  59. package/dist/index-gs48afpt.js +7 -0
  60. package/dist/index-qry58nj2.js +10 -0
  61. package/dist/index-zhg36tf9.js +3 -0
  62. package/dist/index.js +1 -226
  63. package/dist/operations.js +1 -28
  64. package/dist/skill-install-gx7afxsd.js +2 -0
  65. package/dist/vectorize/worker.js +1 -141
  66. package/dist/workflow.js +1 -15
  67. package/docs/README.md +5 -1
  68. package/docs/studio.md +12 -0
  69. package/package.json +7 -5
  70. package/skills/slopcamera/SKILL.md +7 -1
  71. package/skills/slopcamera/references/directed-scenes.md +48 -2
  72. package/skills/slopcamera/references/gateway-media.md +15 -1
  73. package/skills/slopcamera/references/image-galleries.md +166 -0
  74. package/skills/slopcamera/references/install.md +1 -1
  75. package/skills/slopcamera/references/music-video.md +4 -0
  76. package/skills/slopcamera/references/native-studio.md +19 -0
  77. package/skills/slopcamera/references/parametric-design.md +14 -0
  78. package/skills/slopcamera/references/scene-building.md +172 -0
  79. package/skills/slopcamera/references/social-collage-banners.md +204 -0
  80. package/skills/slopcamera/references/workflows-sdk.md +3 -3
  81. package/skills/slopcamera/scripts/compose-social-collage-banner.ts +728 -0
  82. package/src/capability-manifest.ts +361 -0
  83. package/src/cli.ts +222 -4
  84. package/src/code/canonical-json.ts +9 -0
  85. package/src/generate.ts +2 -2
  86. package/src/icon.ts +1111 -0
  87. package/src/image-gallery.ts +1049 -0
  88. package/src/index.ts +11 -0
  89. package/src/mcp/boundary.ts +11 -11
  90. package/src/mcp/index.ts +3 -0
  91. package/src/mcp/server.ts +2 -1
  92. package/src/mcp/tools.ts +1649 -132
  93. package/src/mcp/types.ts +19 -0
  94. package/src/operations.ts +412 -0
  95. package/src/portable-capability-manifest.ts +67 -0
  96. package/src/scene-gallery.ts +184 -0
  97. package/src/spatial-scene/asset-admission.ts +183 -0
  98. package/src/spatial-scene/audit-rendered.ts +692 -0
  99. package/src/spatial-scene/audit.ts +617 -0
  100. package/src/spatial-scene/behavior-audit.ts +252 -0
  101. package/src/spatial-scene/behavior-bake.ts +232 -0
  102. package/src/spatial-scene/behavior-fns.ts +585 -0
  103. package/src/spatial-scene/behavior-gallery.ts +108 -0
  104. package/src/spatial-scene/behavior-stdlib.ts +323 -0
  105. package/src/spatial-scene/behavior-trace.ts +325 -0
  106. package/src/spatial-scene/behavior.ts +617 -0
  107. package/src/spatial-scene/build.ts +632 -0
  108. package/src/spatial-scene/camera-rig.ts +125 -0
  109. package/src/spatial-scene/camera-track.ts +4 -2
  110. package/src/spatial-scene/character.ts +124 -0
  111. package/src/spatial-scene/contracts.ts +75 -7
  112. package/src/spatial-scene/design-templates.ts +351 -0
  113. package/src/spatial-scene/design.ts +327 -0
  114. package/src/spatial-scene/direction-compile.ts +584 -0
  115. package/src/spatial-scene/direction.ts +122 -0
  116. package/src/spatial-scene/effects.ts +149 -0
  117. package/src/spatial-scene/evaluate.ts +109 -29
  118. package/src/spatial-scene/gallery.ts +277 -0
  119. package/src/spatial-scene/generate.ts +239 -0
  120. package/src/spatial-scene/geometry-native.ts +165 -0
  121. package/src/spatial-scene/geometry.ts +1216 -0
  122. package/src/spatial-scene/gltf.ts +600 -77
  123. package/src/spatial-scene/identity.ts +55 -2
  124. package/src/spatial-scene/index.ts +36 -0
  125. package/src/spatial-scene/inspect.ts +35 -6
  126. package/src/spatial-scene/material-lighting.ts +609 -0
  127. package/src/spatial-scene/math.ts +21 -4
  128. package/src/spatial-scene/motion-evidence.ts +88 -0
  129. package/src/spatial-scene/parametric.ts +765 -0
  130. package/src/spatial-scene/particle-preparation.ts +183 -0
  131. package/src/spatial-scene/particle.ts +195 -0
  132. package/src/spatial-scene/patch.ts +109 -15
  133. package/src/spatial-scene/performance.ts +1613 -0
  134. package/src/spatial-scene/probe.ts +137 -0
  135. package/src/spatial-scene/recipe-pack.ts +86 -0
  136. package/src/spatial-scene/render-effects.ts +240 -0
  137. package/src/spatial-scene/review.ts +639 -0
  138. package/src/spatial-scene/simulation-bake.ts +206 -0
  139. package/src/spatial-scene/simulation.ts +187 -0
  140. package/src/spatial-scene/solve.ts +366 -0
  141. package/src/spatial-scene/temporal-audit.ts +354 -0
  142. package/src/version.ts +1 -1
  143. package/dist/index-42zsesc1.js +0 -2257
  144. package/dist/index-7131pg1c.js +0 -1820
  145. package/dist/index-7308egqr.js +0 -48
  146. package/dist/index-8txs6fkn.js +0 -712
  147. package/dist/index-fava6pge.js +0 -192
  148. package/dist/index-h1k0fnjq.js +0 -2363
  149. package/dist/index-r7gdhmsp.js +0 -424
  150. package/dist/index-sh6xbav6.js +0 -1219
  151. package/dist/index-z1w83f81.js +0 -4
  152. package/dist/index-zfnddgay.js +0 -2029
  153. package/dist/skill-install-dh0ntqba.js +0 -10
@@ -1,424 +0,0 @@
1
- // @bun
2
- import {
3
- __require
4
- } from "./index-z1w83f81.js";
5
-
6
- // src/generate.ts
7
- import { createHash, randomUUID } from "crypto";
8
- import { link, rm, writeFile } from "fs/promises";
9
- import { dirname, extname, resolve } from "path";
10
-
11
- // src/cloud-errors.ts
12
- class SlopcameraCloudError extends Error {
13
- code;
14
- constructor(code, message, options) {
15
- super(`[${code}] ${message}`, options);
16
- this.name = "SlopcameraCloudError";
17
- this.code = code;
18
- }
19
- }
20
-
21
- // src/generate.ts
22
- var slopcameraGatewayApiBaseUrl = "https://ai-gateway.vercel.sh/v4/ai";
23
- var slopcameraImageModels = Object.freeze([
24
- "openai/gpt-image-1.5",
25
- "recraft/recraft-v4.1-utility"
26
- ]);
27
- var slopcameraResponseMediaTypes = Object.freeze([
28
- "image/png",
29
- "image/jpeg",
30
- "image/webp"
31
- ]);
32
- var slopcameraMaximumPromptBytes = 32 * 1024;
33
- var slopcameraMaximumRawImageBytes = 64 * 1024 * 1024;
34
- var defaultGenerationTimeoutMs = 5 * 60000;
35
- var maximumGenerationTimeoutMs = 30 * 60000;
36
- var defaultMaximumGatewayResponseBytes = 96 * 1024 * 1024;
37
- function invalidArgument(message) {
38
- throw new SlopcameraCloudError("INVALID_ARGUMENT", message);
39
- }
40
- function credentialValue(value) {
41
- if (value.length < 16 || value.length > 16 * 1024 || value.trim() !== value || /[^\x21-\x7e]/u.test(value)) {
42
- throw new SlopcameraCloudError("AUTHENTICATION_REQUIRED", "The selected Vercel AI Gateway credential is invalid.");
43
- }
44
- return value;
45
- }
46
- function environment(injected) {
47
- return injected ?? process.env;
48
- }
49
- function resolveGatewayCredential(injected) {
50
- const values = environment(injected);
51
- if (values.AI_GATEWAY_API_KEY !== undefined) {
52
- return {
53
- source: "AI_GATEWAY_API_KEY",
54
- token: credentialValue(values.AI_GATEWAY_API_KEY)
55
- };
56
- }
57
- if (values.VERCEL_OIDC_TOKEN !== undefined) {
58
- return {
59
- source: "VERCEL_OIDC_TOKEN",
60
- token: credentialValue(values.VERCEL_OIDC_TOKEN)
61
- };
62
- }
63
- throw new SlopcameraCloudError("AUTHENTICATION_REQUIRED", "Set AI_GATEWAY_API_KEY or run Slopcamera through `vercel env run -- \u2026` with VERCEL_OIDC_TOKEN available.");
64
- }
65
- function slopcameraGatewayCredentialStatus(injected) {
66
- const values = environment(injected);
67
- if (values.AI_GATEWAY_API_KEY !== undefined) {
68
- credentialValue(values.AI_GATEWAY_API_KEY);
69
- return { available: true, source: "AI_GATEWAY_API_KEY" };
70
- }
71
- if (values.VERCEL_OIDC_TOKEN !== undefined) {
72
- credentialValue(values.VERCEL_OIDC_TOKEN);
73
- return { available: true, source: "VERCEL_OIDC_TOKEN" };
74
- }
75
- return { available: false, source: null };
76
- }
77
- function validateModel(value) {
78
- if (typeof value !== "string" || value.length < 3 || value.length > 256 || !/^[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._:-]*$/iu.test(value)) {
79
- invalidArgument("Model must be a bounded Vercel AI Gateway provider/model id.");
80
- }
81
- return value;
82
- }
83
- function validatePrompt(value) {
84
- if (typeof value !== "string" || value.trim().length === 0 || /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/u.test(value) || Buffer.byteLength(value, "utf8") > slopcameraMaximumPromptBytes) {
85
- invalidArgument(`Prompt must be non-empty and no more than ${slopcameraMaximumPromptBytes} UTF-8 bytes.`);
86
- }
87
- return value;
88
- }
89
- function validateTimeout(value) {
90
- const timeout = value ?? defaultGenerationTimeoutMs;
91
- if (!Number.isSafeInteger(timeout) || timeout < 1000 || timeout > maximumGenerationTimeoutMs) {
92
- invalidArgument(`timeoutMs must be an integer from 1000 through ${maximumGenerationTimeoutMs}.`);
93
- }
94
- return timeout;
95
- }
96
- function isObject(value) {
97
- return typeof value === "object" && value !== null || typeof value === "function";
98
- }
99
- function parseFunction(value) {
100
- if (typeof value !== "function") {
101
- throw new SlopcameraCloudError("GENERATION_FAILED", "The Vercel AI Gateway runtime is unavailable.");
102
- }
103
- return value;
104
- }
105
- function disableAiSdkWarningLogging() {
106
- globalThis.AI_SDK_LOG_WARNINGS = false;
107
- }
108
- function assertGenerationActive(signal) {
109
- if (signal.aborted) {
110
- throw new SlopcameraCloudError("GENERATION_FAILED", "Vercel AI Gateway image generation was cancelled or exceeded its deadline.");
111
- }
112
- }
113
- async function loadDefaultGatewayRuntime() {
114
- let aiModule;
115
- let gatewayModule;
116
- try {
117
- [aiModule, gatewayModule] = await Promise.all([
118
- import("ai-v7"),
119
- import("@ai-sdk/gateway-v4")
120
- ]);
121
- } catch {
122
- throw new SlopcameraCloudError("GENERATION_FAILED", "The Vercel AI Gateway runtime is unavailable.");
123
- }
124
- if (!isObject(aiModule) || !isObject(gatewayModule)) {
125
- throw new SlopcameraCloudError("GENERATION_FAILED", "The Vercel AI Gateway runtime is unavailable.");
126
- }
127
- const generateImage = parseFunction(aiModule.generateImage);
128
- if (typeof gatewayModule.createGateway !== "function") {
129
- throw new SlopcameraCloudError("GENERATION_FAILED", "The Vercel AI Gateway runtime is unavailable.");
130
- }
131
- const createGateway = gatewayModule.createGateway;
132
- return {
133
- createGateway: (settings) => {
134
- const provider = createGateway(settings);
135
- if (!isObject(provider) || typeof provider.imageModel !== "function") {
136
- throw new SlopcameraCloudError("GENERATION_FAILED", "The Vercel AI Gateway runtime is unavailable.");
137
- }
138
- const imageModel = provider.imageModel;
139
- return { imageModel: (modelId) => imageModel.call(provider, modelId) };
140
- },
141
- generateImage
142
- };
143
- }
144
- function gatewayUrl(input) {
145
- try {
146
- if (input instanceof Request)
147
- return new URL(input.url);
148
- if (input instanceof URL)
149
- return new URL(input.href);
150
- return new URL(input, slopcameraGatewayApiBaseUrl);
151
- } catch {
152
- throw new SlopcameraCloudError("GENERATION_FAILED", "The Vercel AI Gateway request was rejected.");
153
- }
154
- }
155
- function canonicalGatewayInput(input, url) {
156
- if (!(input instanceof Request))
157
- return url;
158
- const snapshot = new Request(input);
159
- const body = snapshot.method === "GET" || snapshot.method === "HEAD" ? undefined : snapshot.body ?? undefined;
160
- const requestInit = {
161
- headers: snapshot.headers,
162
- method: snapshot.method,
163
- signal: snapshot.signal,
164
- ...body === undefined ? {} : { body, duplex: "half" }
165
- };
166
- return new Request(url.href, requestInit);
167
- }
168
- function boundedResponse(response, maximumBytes) {
169
- const declared = response.headers.get("content-length");
170
- if (declared !== null) {
171
- const value = Number(declared);
172
- if (!Number.isSafeInteger(value) || value < 0 || value > maximumBytes) {
173
- response.body?.cancel().catch(() => {
174
- return;
175
- });
176
- throw new SlopcameraCloudError("GENERATION_INVALID_RESPONSE", "Vercel AI Gateway returned an invalid bounded response.");
177
- }
178
- }
179
- if (response.body === null)
180
- return response;
181
- const reader = response.body.getReader();
182
- let bytes = 0;
183
- const body = new ReadableStream({
184
- cancel: async (reason) => await reader.cancel(reason),
185
- pull: async (controller) => {
186
- try {
187
- const next = await reader.read();
188
- if (next.done) {
189
- reader.releaseLock();
190
- controller.close();
191
- return;
192
- }
193
- bytes += next.value.byteLength;
194
- if (bytes > maximumBytes) {
195
- await reader.cancel().catch(() => {
196
- return;
197
- });
198
- controller.error(new SlopcameraCloudError("GENERATION_INVALID_RESPONSE", "Vercel AI Gateway returned an invalid bounded response."));
199
- return;
200
- }
201
- controller.enqueue(next.value);
202
- } catch {
203
- controller.error(new SlopcameraCloudError("GENERATION_INVALID_RESPONSE", "Vercel AI Gateway returned an invalid bounded response."));
204
- }
205
- }
206
- });
207
- return new Response(body, {
208
- headers: response.headers,
209
- status: response.status,
210
- statusText: response.statusText
211
- });
212
- }
213
- function createFixedGatewayFetch(options = {}) {
214
- const fetchImplementation = options.fetch ?? globalThis.fetch;
215
- const maximumResponseBytes = options.maximumResponseBytes ?? defaultMaximumGatewayResponseBytes;
216
- if (!Number.isSafeInteger(maximumResponseBytes) || maximumResponseBytes < 1 || maximumResponseBytes > 1024 * 1024 * 1024) {
217
- invalidArgument("maximumResponseBytes is outside the supported range.");
218
- }
219
- const fixed = new URL(slopcameraGatewayApiBaseUrl);
220
- return async (input, init) => {
221
- const url = gatewayUrl(input);
222
- if (url.origin !== fixed.origin || url.pathname !== fixed.pathname && !url.pathname.startsWith(`${fixed.pathname}/`) || url.username !== "" || url.password !== "") {
223
- throw new SlopcameraCloudError("GENERATION_FAILED", "The Vercel AI Gateway request was rejected.");
224
- }
225
- const canonicalInput = canonicalGatewayInput(input, url);
226
- let response;
227
- try {
228
- response = await fetchImplementation(canonicalInput, {
229
- ...init,
230
- redirect: "error"
231
- });
232
- } catch (error) {
233
- if (error instanceof SlopcameraCloudError)
234
- throw error;
235
- throw new SlopcameraCloudError("GENERATION_FAILED", "Vercel AI Gateway image generation failed; the request was not retried.");
236
- }
237
- if (response.redirected || response.status >= 300 && response.status < 400) {
238
- await response.body?.cancel().catch(() => {
239
- return;
240
- });
241
- throw new SlopcameraCloudError("GENERATION_FAILED", "The Vercel AI Gateway request was rejected.");
242
- }
243
- return boundedResponse(response, maximumResponseBytes);
244
- };
245
- }
246
- function combineSignals(caller, timeoutMs) {
247
- const controller = new AbortController;
248
- const abort = () => controller.abort(caller?.reason);
249
- let rejectInterruption;
250
- const interruption = new Promise((_resolve, reject) => {
251
- rejectInterruption = reject;
252
- });
253
- const rejectOnAbort = () => {
254
- rejectInterruption?.(new SlopcameraCloudError("GENERATION_FAILED", "Vercel AI Gateway image generation was cancelled or exceeded its deadline."));
255
- };
256
- controller.signal.addEventListener("abort", rejectOnAbort, { once: true });
257
- if (caller?.aborted === true)
258
- abort();
259
- caller?.addEventListener("abort", abort, { once: true });
260
- const timer = setTimeout(() => controller.abort(), timeoutMs);
261
- return {
262
- dispose: () => {
263
- clearTimeout(timer);
264
- caller?.removeEventListener("abort", abort);
265
- controller.signal.removeEventListener("abort", rejectOnAbort);
266
- rejectInterruption = undefined;
267
- },
268
- interruption,
269
- signal: controller.signal
270
- };
271
- }
272
- function mediaType(value) {
273
- if (typeof value !== "string" || !slopcameraResponseMediaTypes.includes(value)) {
274
- throw new SlopcameraCloudError("GENERATION_INVALID_RESPONSE", "Vercel AI Gateway returned an unsupported image type.");
275
- }
276
- return value;
277
- }
278
- function validImageBytes(bytes, type) {
279
- if (bytes.byteLength < 12 || bytes.byteLength > slopcameraMaximumRawImageBytes) {
280
- return false;
281
- }
282
- if (type === "image/png") {
283
- return Buffer.from(bytes.subarray(0, 8)).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]));
284
- }
285
- if (type === "image/jpeg") {
286
- return bytes[0] === 255 && bytes[1] === 216 && bytes.at(-2) === 255 && bytes.at(-1) === 217;
287
- }
288
- return bytes.byteLength >= 16 && Buffer.from(bytes.subarray(0, 4)).toString("ascii") === "RIFF" && Buffer.from(bytes).readUInt32LE(4) === bytes.byteLength - 8 && Buffer.from(bytes.subarray(8, 12)).toString("ascii") === "WEBP" && ["VP8 ", "VP8L", "VP8X"].includes(Buffer.from(bytes.subarray(12, 16)).toString("ascii"));
289
- }
290
- function warningReceipt(value) {
291
- let type = "provider-warning";
292
- let detail = "Provider warning";
293
- if (typeof value === "string") {
294
- detail = value;
295
- } else if (isObject(value)) {
296
- if (typeof value.type === "string" && value.type.length <= 64) {
297
- type = value.type.replace(/[^a-z0-9._-]/giu, "-") || type;
298
- }
299
- if (typeof value.message === "string")
300
- detail = value.message;
301
- else if (typeof value.details === "string")
302
- detail = value.details;
303
- }
304
- return `${type} sha256:${createHash("sha256").update(detail).digest("hex")}`;
305
- }
306
- function parseResult(value, model) {
307
- if (!isObject(value) || !Array.isArray(value.images) || value.images.length !== 1) {
308
- throw new SlopcameraCloudError("GENERATION_INVALID_RESPONSE", "Vercel AI Gateway did not return exactly one image.");
309
- }
310
- const image = value.images[0];
311
- if (!isObject(image) || !(image.uint8Array instanceof Uint8Array)) {
312
- throw new SlopcameraCloudError("GENERATION_INVALID_RESPONSE", "Vercel AI Gateway returned an invalid bounded image.");
313
- }
314
- const type = mediaType(image.mediaType);
315
- if (!validImageBytes(image.uint8Array, type)) {
316
- throw new SlopcameraCloudError("GENERATION_INVALID_RESPONSE", "Vercel AI Gateway returned an invalid bounded image.");
317
- }
318
- const gateway = isObject(value.providerMetadata) && isObject(value.providerMetadata.gateway) ? value.providerMetadata.gateway : undefined;
319
- const foreignGenerationId = gateway !== undefined && typeof gateway.generationId === "string" && gateway.generationId.length > 0 && gateway.generationId.length <= 256 && !/[\u0000-\u001f\u007f]/u.test(gateway.generationId) ? gateway.generationId : randomUUID();
320
- const requestId = `sha256:${createHash("sha256").update("slopcamera.gateway-generation-id/v1\x00").update(foreignGenerationId).digest("hex")}`;
321
- const warnings = Array.isArray(value.warnings) ? value.warnings.slice(0, 100).map(warningReceipt) : [];
322
- return {
323
- bytes: image.uint8Array,
324
- response: {
325
- image: {
326
- base64: Buffer.from(image.uint8Array).toString("base64"),
327
- mediaType: type
328
- },
329
- model,
330
- provider: "vercel-ai-gateway",
331
- requestId,
332
- warnings
333
- }
334
- };
335
- }
336
- async function performGeneration(input, dependencies) {
337
- const model = validateModel(input.model);
338
- const prompt = validatePrompt(input.prompt);
339
- const credential = resolveGatewayCredential(dependencies.environment);
340
- const timeout = combineSignals(input.signal, validateTimeout(input.timeoutMs));
341
- try {
342
- const generation = (async () => {
343
- assertGenerationActive(timeout.signal);
344
- disableAiSdkWarningLogging();
345
- const runtime = await (dependencies.loadRuntime ?? loadDefaultGatewayRuntime)();
346
- assertGenerationActive(timeout.signal);
347
- const provider = runtime.createGateway({
348
- apiKey: credential.token,
349
- baseURL: slopcameraGatewayApiBaseUrl,
350
- fetch: createFixedGatewayFetch({
351
- ...dependencies.fetch === undefined ? {} : { fetch: dependencies.fetch },
352
- ...dependencies.maximumResponseBytes === undefined ? {} : { maximumResponseBytes: dependencies.maximumResponseBytes }
353
- })
354
- });
355
- assertGenerationActive(timeout.signal);
356
- const generated = await runtime.generateImage({
357
- abortSignal: timeout.signal,
358
- maxRetries: 0,
359
- model: provider.imageModel(model),
360
- n: 1,
361
- prompt
362
- });
363
- return parseResult(generated, model);
364
- })();
365
- return await Promise.race([generation, timeout.interruption]);
366
- } catch (error) {
367
- if (error instanceof SlopcameraCloudError)
368
- throw error;
369
- throw new SlopcameraCloudError("GENERATION_FAILED", "Vercel AI Gateway image generation failed; the request was not retried.");
370
- } finally {
371
- timeout.dispose();
372
- }
373
- }
374
- async function generateSlopcameraImage(input, dependencies = {}) {
375
- return (await performGeneration(input, dependencies)).response;
376
- }
377
- function expectedMediaType(outputPath) {
378
- const extension = extname(outputPath).toLocaleLowerCase("en-US");
379
- if (extension === ".png")
380
- return "image/png";
381
- if (extension === ".jpg" || extension === ".jpeg")
382
- return "image/jpeg";
383
- if (extension === ".webp")
384
- return "image/webp";
385
- invalidArgument("Output path must end in .png, .jpg, .jpeg, or .webp.");
386
- }
387
- async function atomicImageWrite(outputPath, bytes) {
388
- const absolutePath = resolve(outputPath);
389
- const temporaryPath = resolve(dirname(absolutePath), `.${randomUUID()}.slopcamera-generate.tmp`);
390
- try {
391
- await writeFile(temporaryPath, bytes, { flag: "wx" });
392
- await link(temporaryPath, absolutePath);
393
- return absolutePath;
394
- } catch {
395
- throw new SlopcameraCloudError("OUTPUT_WRITE_FAILED", "Slopcamera could not atomically write the generated image.");
396
- } finally {
397
- await rm(temporaryPath, { force: true }).catch(() => {
398
- return;
399
- });
400
- }
401
- }
402
- async function generateSlopcameraImageFile(input, dependencies = {}) {
403
- if (typeof input.outputPath !== "string" || input.outputPath.length < 1 || input.outputPath.length > 4096 || input.outputPath.includes("\x00")) {
404
- invalidArgument("Output path must be a non-empty local path.");
405
- }
406
- const expected = expectedMediaType(input.outputPath);
407
- const generated = await performGeneration(input, dependencies);
408
- if (generated.response.image.mediaType !== expected) {
409
- throw new SlopcameraCloudError("GENERATION_INVALID_RESPONSE", `Generated ${generated.response.image.mediaType} does not match the requested ${expected} output path.`);
410
- }
411
- const outputPath = await atomicImageWrite(input.outputPath, generated.bytes);
412
- return {
413
- bytes: generated.bytes.byteLength,
414
- mediaType: generated.response.image.mediaType,
415
- model: generated.response.model,
416
- outputPath,
417
- provider: generated.response.provider,
418
- requestId: generated.response.requestId,
419
- sha256: createHash("sha256").update(generated.bytes).digest("hex"),
420
- warnings: generated.response.warnings
421
- };
422
- }
423
-
424
- export { SlopcameraCloudError, slopcameraGatewayApiBaseUrl, slopcameraImageModels, slopcameraResponseMediaTypes, slopcameraMaximumPromptBytes, slopcameraMaximumRawImageBytes, slopcameraGatewayCredentialStatus, createFixedGatewayFetch, generateSlopcameraImage, generateSlopcameraImageFile };