@nodaro/sdk 2.34.0 → 2.39.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.
Files changed (195) hide show
  1. package/dist/{chunk-JMOKD6ZP.js → chunk-7CUWAVWB.js} +3 -3
  2. package/dist/{chunk-JMOKD6ZP.js.map → chunk-7CUWAVWB.js.map} +1 -1
  3. package/dist/{chunk-E5BM4BLO.js → chunk-7IWVDWSP.js} +20 -3
  4. package/dist/chunk-7IWVDWSP.js.map +1 -0
  5. package/dist/{chunk-RHJRLXKY.cjs → chunk-7XOK277W.cjs} +9 -9
  6. package/dist/{chunk-RHJRLXKY.cjs.map → chunk-7XOK277W.cjs.map} +1 -1
  7. package/dist/{chunk-3QBH2VE2.cjs → chunk-A7QSOD2S.cjs} +20 -3
  8. package/dist/chunk-A7QSOD2S.cjs.map +1 -0
  9. package/dist/chunk-AQHU7EI5.js +54 -0
  10. package/dist/chunk-AQHU7EI5.js.map +1 -0
  11. package/dist/{chunk-VV4TZG5S.js → chunk-AUKHMT53.js} +3 -3
  12. package/dist/chunk-AUKHMT53.js.map +1 -0
  13. package/dist/{chunk-CWH642B2.js → chunk-CIUZMTER.js} +22 -18
  14. package/dist/chunk-CIUZMTER.js.map +1 -0
  15. package/dist/{chunk-I6CXC345.js → chunk-D2ILCSOQ.js} +3 -3
  16. package/dist/{chunk-I6CXC345.js.map → chunk-D2ILCSOQ.js.map} +1 -1
  17. package/dist/{chunk-4NLVBYMW.js → chunk-DQAYIVVS.js} +42 -8
  18. package/dist/chunk-DQAYIVVS.js.map +1 -0
  19. package/dist/{chunk-5ALNFATQ.cjs → chunk-EK672FFM.cjs} +2 -2
  20. package/dist/chunk-EK672FFM.cjs.map +1 -0
  21. package/dist/{chunk-OXQKE5EG.cjs → chunk-ETX3TLNB.cjs} +43 -9
  22. package/dist/{chunk-4NLVBYMW.js.map → chunk-ETX3TLNB.cjs.map} +1 -1
  23. package/dist/{chunk-BRV7Z4GD.cjs → chunk-FHVNTS4E.cjs} +2 -2
  24. package/dist/{chunk-BRV7Z4GD.cjs.map → chunk-FHVNTS4E.cjs.map} +1 -1
  25. package/dist/{chunk-N6GLZOE4.cjs → chunk-FM2KM5TY.cjs} +52 -10
  26. package/dist/chunk-FM2KM5TY.cjs.map +1 -0
  27. package/dist/{chunk-53SXNN3A.js → chunk-FQNCIP6K.js} +2 -2
  28. package/dist/chunk-FQNCIP6K.js.map +1 -0
  29. package/dist/{chunk-KNMW722T.cjs → chunk-FRQJNGJS.cjs} +5 -5
  30. package/dist/{chunk-KNMW722T.cjs.map → chunk-FRQJNGJS.cjs.map} +1 -1
  31. package/dist/{chunk-4CXB7RA6.js → chunk-IGMWFEFB.js} +6 -4
  32. package/dist/chunk-IGMWFEFB.js.map +1 -0
  33. package/dist/{chunk-6OGGJQVA.js → chunk-ILG5DHQQ.js} +2 -2
  34. package/dist/chunk-ILG5DHQQ.js.map +1 -0
  35. package/dist/{chunk-CFY6XXOT.cjs → chunk-IXCJ26F5.cjs} +37 -33
  36. package/dist/chunk-IXCJ26F5.cjs.map +1 -0
  37. package/dist/{chunk-ZQQABQMH.cjs → chunk-JTOEHQQJ.cjs} +12 -2
  38. package/dist/chunk-JTOEHQQJ.cjs.map +1 -0
  39. package/dist/{chunk-ZXJQSFIA.js → chunk-JUON5NXA.js} +2 -2
  40. package/dist/{chunk-ZXJQSFIA.js.map → chunk-JUON5NXA.js.map} +1 -1
  41. package/dist/{chunk-JGS6YBDW.js → chunk-L6T44A3G.js} +51 -11
  42. package/dist/chunk-L6T44A3G.js.map +1 -0
  43. package/dist/{chunk-U4T3Z3K7.cjs → chunk-NKH2UFSD.cjs} +5 -5
  44. package/dist/chunk-NKH2UFSD.cjs.map +1 -0
  45. package/dist/{chunk-VFMWBW2Q.js → chunk-NU4QSOMH.js} +4 -4
  46. package/dist/{chunk-VFMWBW2Q.js.map → chunk-NU4QSOMH.js.map} +1 -1
  47. package/dist/{chunk-E2ZXHS6E.js → chunk-OIPPTBW4.js} +2 -2
  48. package/dist/chunk-OIPPTBW4.js.map +1 -0
  49. package/dist/{chunk-DKEYSJCE.cjs → chunk-OIYMTGYN.cjs} +2 -2
  50. package/dist/chunk-OIYMTGYN.cjs.map +1 -0
  51. package/dist/{chunk-NLQQHJ25.cjs → chunk-OSMKIRKI.cjs} +4 -4
  52. package/dist/{chunk-NLQQHJ25.cjs.map → chunk-OSMKIRKI.cjs.map} +1 -1
  53. package/dist/chunk-PG2GBS3K.cjs +4 -0
  54. package/dist/chunk-PG2GBS3K.cjs.map +1 -0
  55. package/dist/{chunk-GB724HW2.cjs → chunk-PQ7OKM3E.cjs} +6 -4
  56. package/dist/chunk-PQ7OKM3E.cjs.map +1 -0
  57. package/dist/chunk-QGOEQGAE.js +102 -0
  58. package/dist/chunk-QGOEQGAE.js.map +1 -0
  59. package/dist/{chunk-EAGD6NEE.cjs → chunk-QZHRXPN5.cjs} +22 -22
  60. package/dist/chunk-QZHRXPN5.cjs.map +1 -0
  61. package/dist/{chunk-5MTCKWKA.cjs → chunk-QZMI7364.cjs} +5 -5
  62. package/dist/{chunk-5MTCKWKA.cjs.map → chunk-QZMI7364.cjs.map} +1 -1
  63. package/dist/chunk-SRBYCGRC.cjs +56 -0
  64. package/dist/chunk-SRBYCGRC.cjs.map +1 -0
  65. package/dist/{chunk-KGKCAGRD.cjs → chunk-TCLNSVYA.cjs} +2 -2
  66. package/dist/chunk-TCLNSVYA.cjs.map +1 -0
  67. package/dist/chunk-VCEYLJ2Q.cjs +104 -0
  68. package/dist/chunk-VCEYLJ2Q.cjs.map +1 -0
  69. package/dist/{chunk-VGWOIWRQ.cjs → chunk-VHSMOBU7.cjs} +2 -2
  70. package/dist/{chunk-VGWOIWRQ.cjs.map → chunk-VHSMOBU7.cjs.map} +1 -1
  71. package/dist/{chunk-T3SYREY4.js → chunk-WY4QRJZW.js} +12 -2
  72. package/dist/chunk-WY4QRJZW.js.map +1 -0
  73. package/dist/chunk-YCVRQZT3.js +3 -0
  74. package/dist/chunk-YCVRQZT3.js.map +1 -0
  75. package/dist/{chunk-DPSMVOM3.js → chunk-YSZM3N7Q.js} +2 -2
  76. package/dist/chunk-YSZM3N7Q.js.map +1 -0
  77. package/dist/{chunk-5A7J24LN.js → chunk-Z7UZ3FD3.js} +3 -3
  78. package/dist/{chunk-5A7J24LN.js.map → chunk-Z7UZ3FD3.js.map} +1 -1
  79. package/dist/{chunk-4JKI6JRC.js → chunk-ZDSC6KBT.js} +3 -3
  80. package/dist/chunk-ZDSC6KBT.js.map +1 -0
  81. package/dist/entries/apps.cjs +2 -2
  82. package/dist/entries/apps.d.cts +4 -0
  83. package/dist/entries/apps.d.ts +4 -0
  84. package/dist/entries/apps.js +1 -1
  85. package/dist/entries/cast-swap.cjs +2 -2
  86. package/dist/entries/cast-swap.d.cts +278 -18
  87. package/dist/entries/cast-swap.d.ts +278 -18
  88. package/dist/entries/cast-swap.js +1 -1
  89. package/dist/entries/characters.d.cts +2 -2
  90. package/dist/entries/characters.d.ts +2 -2
  91. package/dist/entries/client.cjs +25 -24
  92. package/dist/entries/client.d.cts +5 -2
  93. package/dist/entries/client.d.ts +5 -2
  94. package/dist/entries/client.js +20 -19
  95. package/dist/entries/copilot.cjs +4 -4
  96. package/dist/entries/copilot.js +3 -3
  97. package/dist/entries/core.cjs +6 -6
  98. package/dist/entries/core.js +2 -2
  99. package/dist/entries/creatures.d.cts +2 -2
  100. package/dist/entries/creatures.d.ts +2 -2
  101. package/dist/entries/credits.cjs +2 -2
  102. package/dist/entries/credits.d.cts +37 -2
  103. package/dist/entries/credits.d.ts +37 -2
  104. package/dist/entries/credits.js +1 -1
  105. package/dist/entries/edit.cjs +7 -7
  106. package/dist/entries/edit.d.cts +3 -0
  107. package/dist/entries/edit.d.ts +3 -0
  108. package/dist/entries/edit.js +2 -2
  109. package/dist/entries/errors.cjs +30 -22
  110. package/dist/entries/errors.d.cts +42 -4
  111. package/dist/entries/errors.d.ts +42 -4
  112. package/dist/entries/errors.js +1 -1
  113. package/dist/entries/jobs.cjs +2 -2
  114. package/dist/entries/jobs.d.cts +76 -4
  115. package/dist/entries/jobs.d.ts +76 -4
  116. package/dist/entries/jobs.js +1 -1
  117. package/dist/entries/locations.d.cts +2 -2
  118. package/dist/entries/locations.d.ts +2 -2
  119. package/dist/entries/media.cjs +4 -4
  120. package/dist/entries/media.d.cts +39 -5
  121. package/dist/entries/media.d.ts +39 -5
  122. package/dist/entries/media.js +3 -3
  123. package/dist/entries/nodes.cjs +3 -3
  124. package/dist/entries/nodes.d.cts +2 -2
  125. package/dist/entries/nodes.d.ts +2 -2
  126. package/dist/entries/nodes.js +2 -2
  127. package/dist/entries/objects.d.cts +2 -2
  128. package/dist/entries/objects.d.ts +2 -2
  129. package/dist/entries/prompt-helper.cjs +2 -2
  130. package/dist/entries/prompt-helper.d.cts +3 -1
  131. package/dist/entries/prompt-helper.d.ts +3 -1
  132. package/dist/entries/prompt-helper.js +1 -1
  133. package/dist/entries/scene3d.d.cts +3 -3
  134. package/dist/entries/scene3d.d.ts +3 -3
  135. package/dist/entries/studio.cjs +5 -5
  136. package/dist/entries/studio.d.cts +2 -2
  137. package/dist/entries/studio.d.ts +2 -2
  138. package/dist/entries/studio.js +2 -2
  139. package/dist/entries/templates.cjs +2 -2
  140. package/dist/entries/templates.d.cts +4 -0
  141. package/dist/entries/templates.d.ts +4 -0
  142. package/dist/entries/templates.js +1 -1
  143. package/dist/entries/trends.cjs +13 -0
  144. package/dist/entries/trends.cjs.map +1 -0
  145. package/dist/entries/trends.d.cts +295 -0
  146. package/dist/entries/trends.d.ts +295 -0
  147. package/dist/entries/trends.js +4 -0
  148. package/dist/entries/trends.js.map +1 -0
  149. package/dist/entries/tutorials.cjs +2 -2
  150. package/dist/entries/tutorials.d.cts +4 -0
  151. package/dist/entries/tutorials.d.ts +4 -0
  152. package/dist/entries/tutorials.js +1 -1
  153. package/dist/entries/uploads.cjs +2 -2
  154. package/dist/entries/uploads.d.cts +14 -1
  155. package/dist/entries/uploads.d.ts +14 -1
  156. package/dist/entries/uploads.js +1 -1
  157. package/dist/entries/workflows.cjs +2 -2
  158. package/dist/entries/workflows.d.cts +6 -0
  159. package/dist/entries/workflows.d.ts +6 -0
  160. package/dist/entries/workflows.js +1 -1
  161. package/dist/index.cjs +85 -71
  162. package/dist/index.d.cts +8 -7
  163. package/dist/index.d.ts +8 -7
  164. package/dist/index.js +22 -20
  165. package/dist/{nodes-D2tbtzt7.d.ts → nodes-9WpYNWtS.d.ts} +13 -1
  166. package/dist/{nodes-CTujw6Qd.d.cts → nodes-BDUk5Aej.d.cts} +13 -1
  167. package/dist/{studio-productions-vbCNSbtf.d.ts → studio-productions-DtTE8mdl.d.ts} +35 -1
  168. package/dist/{studio-productions-DUHvdSvk.d.cts → studio-productions-r2-VZsKj.d.cts} +35 -1
  169. package/package.json +7 -2
  170. package/dist/chunk-3QBH2VE2.cjs.map +0 -1
  171. package/dist/chunk-4CXB7RA6.js.map +0 -1
  172. package/dist/chunk-4JKI6JRC.js.map +0 -1
  173. package/dist/chunk-53SXNN3A.js.map +0 -1
  174. package/dist/chunk-5ALNFATQ.cjs.map +0 -1
  175. package/dist/chunk-6OGGJQVA.js.map +0 -1
  176. package/dist/chunk-CFY6XXOT.cjs.map +0 -1
  177. package/dist/chunk-CWH642B2.js.map +0 -1
  178. package/dist/chunk-DKEYSJCE.cjs.map +0 -1
  179. package/dist/chunk-DPSMVOM3.js.map +0 -1
  180. package/dist/chunk-E2ZXHS6E.js.map +0 -1
  181. package/dist/chunk-E5BM4BLO.js.map +0 -1
  182. package/dist/chunk-EAGD6NEE.cjs.map +0 -1
  183. package/dist/chunk-GB724HW2.cjs.map +0 -1
  184. package/dist/chunk-GDXS4EJ5.js +0 -28
  185. package/dist/chunk-GDXS4EJ5.js.map +0 -1
  186. package/dist/chunk-GVBSOZDI.cjs +0 -30
  187. package/dist/chunk-GVBSOZDI.cjs.map +0 -1
  188. package/dist/chunk-JGS6YBDW.js.map +0 -1
  189. package/dist/chunk-KGKCAGRD.cjs.map +0 -1
  190. package/dist/chunk-N6GLZOE4.cjs.map +0 -1
  191. package/dist/chunk-OXQKE5EG.cjs.map +0 -1
  192. package/dist/chunk-T3SYREY4.js.map +0 -1
  193. package/dist/chunk-U4T3Z3K7.cjs.map +0 -1
  194. package/dist/chunk-VV4TZG5S.js.map +0 -1
  195. package/dist/chunk-ZQQABQMH.cjs.map +0 -1
@@ -1,13 +1,22 @@
1
1
  // src/errors.ts
2
2
  var NodaroError = class extends Error {
3
- constructor(message, code, status) {
3
+ constructor(message, code, status, details) {
4
4
  super(message);
5
5
  this.code = code;
6
6
  this.status = status;
7
7
  this.name = "NodaroError";
8
+ if (details) this.details = { ...details };
8
9
  }
9
10
  code;
10
11
  status;
12
+ /**
13
+ * Every other field of the server's error envelope (`{ error: { code,
14
+ * message, … } }`), as it was sent: for example a trend refusal's `slot`, a
15
+ * publish refusal's `reasons`, a validation error's `issues`. Empty when the
16
+ * envelope had nothing else, or for an error the SDK made itself. A copy —
17
+ * changing it changes nothing else.
18
+ */
19
+ details = {};
11
20
  };
12
21
  var UnauthorizedError = class extends NodaroError {
13
22
  constructor(message = "Authentication required") {
@@ -36,8 +45,8 @@ var RateLimitedError = class extends NodaroError {
36
45
  }
37
46
  };
38
47
  var InsufficientCreditsError = class extends NodaroError {
39
- constructor(message = "Insufficient credits", required, available) {
40
- super(message, "insufficient_credits", 402);
48
+ constructor(message = "Insufficient credits", required, available, code = "insufficient_credits") {
49
+ super(message, code, 402);
41
50
  this.required = required;
42
51
  this.available = available;
43
52
  this.name = "InsufficientCreditsError";
@@ -45,6 +54,17 @@ var InsufficientCreditsError = class extends NodaroError {
45
54
  required;
46
55
  available;
47
56
  };
57
+ var CREDIT_CAP_CODES = /* @__PURE__ */ new Set([
58
+ "budget_exceeded",
59
+ "member_cap_exceeded",
60
+ "user_allowance_exceeded"
61
+ ]);
62
+ var CreditCapExceededError = class extends InsufficientCreditsError {
63
+ constructor(code, message = "A credit cap cannot cover this run", required, available) {
64
+ super(message, required, available, code);
65
+ this.name = "CreditCapExceededError";
66
+ }
67
+ };
48
68
  var StorageExceededError = class extends NodaroError {
49
69
  constructor(message = "Storage exceeded", limitBytes) {
50
70
  super(message, "storage_exceeded", 413);
@@ -200,7 +220,25 @@ function readErrorBody(status, body) {
200
220
  const message = nonEmpty(envelope.message) ?? outside;
201
221
  return { code, message, envelope };
202
222
  }
223
+ function envelopeDetails(envelope) {
224
+ const out = {};
225
+ for (const [key, value] of Object.entries(envelope)) {
226
+ if (key !== "code" && key !== "message") out[key] = value;
227
+ }
228
+ return out;
229
+ }
203
230
  function throwFromResponse(status, body) {
231
+ try {
232
+ selectError(status, body);
233
+ } catch (err) {
234
+ if (err instanceof NodaroError) {
235
+ const raw = body && typeof body === "object" ? body.error : void 0;
236
+ if (raw && typeof raw === "object") Object.defineProperty(err, "details", { value: envelopeDetails(raw), enumerable: true });
237
+ }
238
+ throw err;
239
+ }
240
+ }
241
+ function selectError(status, body) {
204
242
  const parsed = body && typeof body === "object" ? body : {};
205
243
  const read = readErrorBody(status, parsed);
206
244
  const envelope = read.envelope;
@@ -245,16 +283,18 @@ function throwFromResponse(status, body) {
245
283
  if (status === 404) throw new NotFoundError(read.message);
246
284
  if (status === 429) throw new RateLimitedError(read.message);
247
285
  if (status === 402) {
248
- throw new InsufficientCreditsError(
249
- read.message,
250
- finite(envelope.required) ?? finite(parsed.required),
251
- finite(envelope.available) ?? finite(parsed.balance)
252
- );
286
+ const required = finite(envelope.required) ?? finite(parsed.required);
287
+ const available = finite(envelope.available) ?? finite(parsed.balance) ?? finite(parsed.remaining);
288
+ const capCode = read.code;
289
+ if (capCode !== void 0 && CREDIT_CAP_CODES.has(capCode)) {
290
+ throw new CreditCapExceededError(capCode, read.message, required, available);
291
+ }
292
+ throw new InsufficientCreditsError(read.message, required, available, read.code ?? "insufficient_credits");
253
293
  }
254
294
  if (status === 413) throw new StorageExceededError(read.message, envelope.limitBytes);
255
295
  throw new NodaroError(message, code, status);
256
296
  }
257
297
 
258
- export { AlreadyRunningError, AppRunVersionChangedError, ContinuationPreviewPendingError, ContinuationRefusedError, ForbiddenError, InsufficientCreditsError, JobAbortedError, JobBlockedError, JobFailedError, JobHeldError, JobTimeoutError, NodaroError, NotFoundError, RateLimitedError, StorageExceededError, StudioOpError, StudioPreviewAppliedError, StudioPreviewUnavailable, UnauthorizedError, WorkflowConflictError, throwFromResponse };
259
- //# sourceMappingURL=chunk-JGS6YBDW.js.map
260
- //# sourceMappingURL=chunk-JGS6YBDW.js.map
298
+ export { AlreadyRunningError, AppRunVersionChangedError, CREDIT_CAP_CODES, ContinuationPreviewPendingError, ContinuationRefusedError, CreditCapExceededError, ForbiddenError, InsufficientCreditsError, JobAbortedError, JobBlockedError, JobFailedError, JobHeldError, JobTimeoutError, NodaroError, NotFoundError, RateLimitedError, StorageExceededError, StudioOpError, StudioPreviewAppliedError, StudioPreviewUnavailable, UnauthorizedError, WorkflowConflictError, throwFromResponse };
299
+ //# sourceMappingURL=chunk-L6T44A3G.js.map
300
+ //# sourceMappingURL=chunk-L6T44A3G.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts"],"names":[],"mappings":"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","file":"chunk-L6T44A3G.js","sourcesContent":["import type { StudioOpsResponse } from \"./resources/studio-productions.js\"\n\nexport class NodaroError extends Error {\n /**\n * Every other field of the server's error envelope (`{ error: { code,\n * message, … } }`), as it was sent: for example a trend refusal's `slot`, a\n * publish refusal's `reasons`, a validation error's `issues`. Empty when the\n * envelope had nothing else, or for an error the SDK made itself. A copy —\n * changing it changes nothing else.\n */\n public readonly details: Readonly<Record<string, unknown>> = {}\n\n constructor(\n message: string,\n public readonly code: string,\n public readonly status: number,\n details?: Readonly<Record<string, unknown>>,\n ) {\n super(message)\n this.name = \"NodaroError\"\n if (details) this.details = { ...details }\n }\n}\n\nexport class UnauthorizedError extends NodaroError {\n constructor(message = \"Authentication required\") {\n super(message, \"unauthorized\", 401)\n this.name = \"UnauthorizedError\"\n }\n}\n\nexport class ForbiddenError extends NodaroError {\n constructor(message = \"Forbidden\", public readonly missingScope?: string) {\n super(message, \"forbidden\", 403)\n this.name = \"ForbiddenError\"\n }\n}\n\nexport class NotFoundError extends NodaroError {\n constructor(message = \"Not found\") {\n super(message, \"not_found\", 404)\n this.name = \"NotFoundError\"\n }\n}\n\nexport class RateLimitedError extends NodaroError {\n constructor(message = \"Rate limited\") {\n super(message, \"rate_limited\", 429)\n this.name = \"RateLimitedError\"\n }\n}\n\n/**\n * HTTP 402: the run costs more than the caller may spend. `code` is the\n * refusal's own code — `insufficient_credits` for the caller's own balance, or\n * another 402 code such as `free_video_limit`. A spending cap someone else set\n * (a workspace budget, a member cap, a per-user allowance) is the subclass\n * {@link CreditCapExceededError}, so `instanceof InsufficientCreditsError`\n * still catches every 402.\n */\nexport class InsufficientCreditsError extends NodaroError {\n constructor(\n message = \"Insufficient credits\",\n public readonly required?: number,\n public readonly available?: number,\n code = \"insufficient_credits\",\n ) {\n super(message, code, 402)\n this.name = \"InsufficientCreditsError\"\n }\n}\n\n/** The 402 codes of a spending cap set by someone other than the caller. */\nexport type CreditCapCode = \"budget_exceeded\" | \"member_cap_exceeded\" | \"user_allowance_exceeded\"\n\n/**\n * The 402 codes {@link CreditCapExceededError} carries: the workspace's budget\n * (`budget_exceeded`), the caller's cap in that workspace\n * (`member_cap_exceeded`), the deployment's per-user allowance\n * (`user_allowance_exceeded`).\n */\nexport const CREDIT_CAP_CODES: ReadonlySet<CreditCapCode> = new Set<CreditCapCode>([\n \"budget_exceeded\",\n \"member_cap_exceeded\",\n \"user_allowance_exceeded\",\n])\n\n/**\n * HTTP 402 from a spending cap, not from the caller's own balance: topping up\n * does not help — whoever set the cap (the workspace's owner, the deployment's\n * operator) has to raise it. An {@link InsufficientCreditsError}, so existing\n * catches keep working; `code` says which cap. `available`, when sent, is what\n * the cap has left.\n */\nexport class CreditCapExceededError extends InsufficientCreditsError {\n declare readonly code: CreditCapCode\n\n constructor(code: CreditCapCode, message = \"A credit cap cannot cover this run\", required?: number, available?: number) {\n super(message, required, available, code)\n this.name = \"CreditCapExceededError\"\n }\n}\n\nexport class StorageExceededError extends NodaroError {\n constructor(message = \"Storage exceeded\", public readonly limitBytes?: number) {\n super(message, \"storage_exceeded\", 413)\n this.name = \"StorageExceededError\"\n }\n}\n\n/**\n * Optimistic-concurrency rejection (HTTP 409 `workflow_conflict`): the workflow\n * was written by another tab/device after the state carried in\n * `expectedUpdatedAt`/`expectedVersion` was read. `currentRecord` — when the\n * server includes it — is the full current workflow: merge your changes onto it\n * and retry with its fresh `updatedAt`, no follow-up GET needed.\n */\nexport class WorkflowConflictError extends NodaroError {\n constructor(\n message = \"Workflow was updated by another writer\",\n public readonly currentUpdatedAt?: string,\n public readonly currentVersion?: number,\n public readonly currentRecord?: Record<string, unknown>,\n /**\n * The wire code this conflict actually arrived with.\n *\n * `production_busy` is the studio production routes' own 409: the row\n * changed under a read-modify-write and the server exhausted its retries.\n * It is the same situation and the same remedy — re-read and apply again —\n * so it is the same ERROR, and a caller catching `WorkflowConflictError`\n * handles both. The code stays truthful because a caller that logs or\n * branches on it should see what the server said, not what the class is\n * usually called.\n */\n code: WorkflowConflictCode = \"workflow_conflict\",\n ) {\n super(message, code, 409)\n this.name = \"WorkflowConflictError\"\n }\n}\n\n/** The 409 codes that mean \"somebody else wrote first; re-read and retry\". */\nexport type WorkflowConflictCode = \"workflow_conflict\" | \"production_busy\"\n\n/**\n * A studio operation batch was refused, and the error names WHICH operation\n * (`opIndex`, zero-based) was wrong. Nothing in the batch was written: a batch\n * applies atomically or not at all, so fix that one operation and send the\n * whole batch again.\n *\n * Selected by SHAPE — any 4xx carrying a numeric `opIndex` — not by a list of\n * codes, so a new refusal reason (`op_invalid`, `op_target_missing`, whatever\n * the server adds next) reaches the caller as this error without an SDK\n * release. `code` is whatever the server sent.\n */\nexport class StudioOpError extends NodaroError {\n constructor(\n message: string,\n code: string,\n status: number,\n /** Zero-based index into the `ops` array that was sent. */\n public readonly opIndex: number,\n ) {\n super(message, code, status)\n this.name = \"StudioOpError\"\n }\n}\n\n/** The 409 codes whose answer names the job to turn to instead (a top-level `jobId`). */\nconst CONTINUATION_REFUSAL_CODES: ReadonlySet<string> = new Set([\n \"already_running\",\n \"continuation_superseded\",\n \"render_final_already_rendered\",\n])\n\n/**\n * A 409 that names the job to turn to instead: continuing a use-case run\n * (`client.edit.continueUseCase`) answers `already_running` (a continuation is\n * under way, or one that already completed — follow `jobId`),\n * `continuation_superseded` (a later continuation failed too — continue\n * `jobId` instead) or `render_final_already_rendered` (a Render final with this\n * very edit already completed — `jobId` holds the result). `code` and `status`\n * are what the server sent. Selected for exactly those three codes when the\n * answer carries a top-level `jobId`; every other 409 stays a plain\n * `NodaroError`.\n */\nexport class ContinuationRefusedError extends NodaroError {\n constructor(\n message: string,\n code: string,\n /** The job the refusal names. */\n public readonly jobId: string,\n ) {\n super(message, code, 409)\n this.name = \"ContinuationRefusedError\"\n }\n}\n\n/**\n * The one run that finishes a continuation held at a Preview review (the\n * `next` of {@link ContinuationPreviewPendingError}): pass these three fields\n * to `client.workflows.run`. It continues that execution, runs each held render\n * at Final and each held Tighten Episode continuing the run that made its\n * Preview, then every node after them.\n */\nexport interface HeldFinalRun {\n continueFromExecutionId: string\n /** The nodes it runs, in canvas order. */\n nodeIds: string[]\n /** For this run only: each held render at Final, each held use-case node's `useCaseContinue`. */\n inputOverrides: Record<string, Record<string, unknown>>\n}\n\n/**\n * HTTP 409 `continuation_preview_pending`: a continue-from-failed\n * (`client.workflows.run` with `continueMode: \"from-failed\"`) whose run's\n * newest later continuation completed by stopping at a Preview review, so\n * continuing again would stop there too. `executionId` is that continuation;\n * `renderNodeIds` the Apply EDL renders and `reviewNodeIds` the Tighten Episode\n * nodes holding it; `next` the run that finishes them — send it first\n * (`client.workflows.run(workflowId, error.next)`), then continue. Absent only\n * when the server could not name it. For a single held render, `next` is that\n * render's `client.workflows.renderFinal`.\n */\nexport class ContinuationPreviewPendingError extends NodaroError {\n constructor(\n message: string,\n public readonly executionId: string,\n public readonly renderNodeIds: readonly string[],\n public readonly reviewNodeIds: readonly string[],\n public readonly next?: HeldFinalRun,\n ) {\n super(message, \"continuation_preview_pending\", 409)\n this.name = \"ContinuationPreviewPendingError\"\n }\n}\n\nconst stringList = (v: unknown): string[] => (Array.isArray(v) ? v.filter((id): id is string => typeof id === \"string\") : [])\n\n/** A `next` as the server sends it, or undefined for anything else. */\nfunction heldFinalRunOf(v: unknown): HeldFinalRun | undefined {\n if (!v || typeof v !== \"object\") return undefined\n const r = v as Record<string, unknown>\n if (typeof r.continueFromExecutionId !== \"string\" || !Array.isArray(r.nodeIds)) return undefined\n if (!r.inputOverrides || typeof r.inputOverrides !== \"object\" || Array.isArray(r.inputOverrides)) return undefined\n return {\n continueFromExecutionId: r.continueFromExecutionId,\n nodeIds: stringList(r.nodeIds),\n inputOverrides: r.inputOverrides as Record<string, Record<string, unknown>>,\n }\n}\n\n/**\n * HTTP 409 `already_running` that names the execution under way (a top-level\n * `executionId`): the run you asked to start or continue is still running —\n * follow `executionId` (`client.executions.get`) instead of starting it again.\n * Sent by the workflow run route and by an app run's Retry\n * (`client.apps.resume`). An `already_running` that names a job instead stays\n * {@link ContinuationRefusedError}; one that names nothing, a plain\n * `NodaroError`.\n */\nexport class AlreadyRunningError extends NodaroError {\n constructor(\n message: string,\n /** The execution under way. */\n public readonly executionId: string,\n ) {\n super(message, \"already_running\", 409)\n this.name = \"AlreadyRunningError\"\n }\n}\n\n/**\n * HTTP 409 `app_run_version_changed`: a Retry of a failed app run\n * (`client.apps.resume`) refused because the app is on another version than\n * the one the run ran — continuing would mix them. `runVersion` is the run's\n * version, `appVersion` the one you are on (the `version` you sent, else the\n * app's latest). Start the run over (`client.apps.run`) to run `appVersion`,\n * or send `{ version: runVersion }` to continue on the run's own version.\n * Nothing was written or billed. Selected by code; the two numbers are\n * `undefined` when the answer does not carry them.\n */\nexport class AppRunVersionChangedError extends NodaroError {\n constructor(\n message: string,\n public readonly runVersion?: number,\n public readonly appVersion?: number,\n ) {\n super(message, \"app_run_version_changed\", 409)\n this.name = \"AppRunVersionChangedError\"\n }\n}\n\n/**\n * HTTP 422 `job_blocked`. A job policy registered by this deployment refused\n * the generation **before it ran** — no job was created, nothing was reserved\n * and nothing was charged. `message` is the policy's user-safe text: show it\n * as-is. Do not retry the identical request; whether the same input would be\n * judged differently is the deployment's policy's business.\n *\n * Only occurs on deployments that register a job policy. Selected by `code`,\n * not by status, the same way `workflow_conflict` narrows a 409 above — any\n * other 422 stays a plain `NodaroError`.\n */\nexport class JobBlockedError extends NodaroError {\n constructor(message = \"Blocked by this deployment's content policy\") {\n super(message, \"job_blocked\", 422)\n this.name = \"JobBlockedError\"\n }\n}\n\n/**\n * A job reached a terminal `failed`/`cancelled` status while being awaited by\n * `nodes.runAndWait` / `nodes.runMany`. Not an HTTP-level error (the polls\n * themselves succeeded), so `status` is 0 — distinguish it by type/`code`.\n * Carries the job's own `error_message` (as the message) and `jobId`.\n */\nexport class JobFailedError extends NodaroError {\n constructor(\n message: string,\n public readonly jobId: string,\n /** The terminal status that triggered the failure (`failed` | `cancelled`). */\n public readonly jobStatus: \"failed\" | \"cancelled\" = \"failed\",\n ) {\n super(message, \"job_failed\", 0)\n this.name = \"JobFailedError\"\n }\n}\n\n/**\n * `nodes.runAndWait` polled past its `maxMs` deadline without the job reaching\n * a terminal status. Not an HTTP error — `status` is 0; catch by type/`code`.\n */\nexport class JobTimeoutError extends NodaroError {\n constructor(\n message: string,\n public readonly jobId: string,\n /** The wall-clock deadline (ms) that was exceeded. */\n public readonly timeoutMs: number,\n ) {\n super(message, \"job_timeout\", 0)\n this.name = \"JobTimeoutError\"\n }\n}\n\n/**\n * The caller's `AbortSignal` fired while `nodes.runAndWait` was polling (or it\n * was already aborted on entry). Polling stops and this rejects. Not an HTTP\n * error — `status` is 0; catch by type/`code`.\n */\nexport class JobAbortedError extends NodaroError {\n constructor(message = \"Aborted\", public readonly jobId?: string) {\n super(message, \"job_aborted\", 0)\n this.name = \"JobAbortedError\"\n }\n}\n\n/**\n * A batch preview was asked for and this deployment cannot give one, so\n * NOTHING was sent: the batch is still unapplied and the production untouched.\n *\n * A preview is two requests because the route's body is parsed in strip mode —\n * a deployment that predates the preview silently DROPS the flag and APPLIES\n * the batch. So the SDK asks with an EMPTY batch first and sends the real one\n * only when that answer carries the `dryRun` marker. This is what it throws\n * when the answer does not: whatever the older deployment made of an empty\n * batch, the caller's batch never left.\n *\n * The remedy is a deployment that serves the preview — there is nothing to\n * retry here. To apply the batch instead, send it without the flag.\n *\n * A deployment that REFUSES the empty batch outright throws its own error\n * instead of this one, which is the right way round: the route's message says\n * more than \"unavailable\" does.\n *\n * Not an HTTP error: the request itself succeeded and answered the older shape.\n * `status` is 0; catch by type/`code`.\n */\nexport class StudioPreviewUnavailable extends NodaroError {\n constructor(\n message = \"This deployment does not preview operation batches; nothing was sent\",\n ) {\n super(message, \"studio_preview_unavailable\", 0)\n this.name = \"StudioPreviewUnavailable\"\n }\n}\n\n/**\n * A batch preview was asked for and the batch was APPLIED instead. The\n * production is written; this is the opposite of {@link\n * StudioPreviewUnavailable}, where nothing was sent.\n *\n * How it happens: the preview's proving ping and the batch are two requests,\n * and a fleet mid-rollout can serve them from different deployments. The ping\n * answers the marker, the batch reaches a deployment that predates the preview,\n * parses in strip mode, drops the flag and writes. The SDK cannot recall that\n * request — by the time the answer comes back the change has landed — so it\n * refuses to call the result a preview, which is the only thing still in its\n * gift. `receipts` and `warnings` are on both shapes, so an unchecked reply\n * would have shown a person what ALREADY happened under the heading of what\n * would.\n *\n * `applied` is what the route answered: the ordinary apply reply, whose\n * `production` and `version` are now the truth. Adopt them the way a plain\n * apply's caller does — do NOT re-send the batch, and do not present it for\n * approval.\n *\n * Not an HTTP error: the request succeeded, at the wrong thing. `status` is 0.\n */\nexport class StudioPreviewAppliedError extends NodaroError {\n constructor(\n /**\n * The apply reply the route sent back, as it sent it. An answer this\n * package does not recognise arrives here unchanged rather than being\n * dressed up: it is what the deployment said about a batch it took.\n *\n * `undefined` when the answer carried no body at all — a 204, an empty\n * envelope. The refusal still fires, because a non-preview answer is never\n * handed back as a preview, but there is nothing to report and the SDK will\n * not invent it: whether the batch was applied is unknown from here, and\n * the caller settles it by re-reading the production.\n */\n public readonly applied: StudioOpsResponse | undefined,\n message = applied\n ? \"Asked for a preview and this deployment APPLIED the batch; the change is written — see `applied`\"\n : \"Asked for a preview and this deployment answered with neither one nor a body to read; the batch may have been applied — re-read the production before deciding anything\",\n ) {\n super(message, \"studio_preview_applied\", 0)\n this.name = \"StudioPreviewAppliedError\"\n }\n}\n\n/**\n * The awaited job entered `pending_review`: a job policy registered by this\n * deployment held its output for a human reviewer. `pending_review` is\n * IN-FLIGHT, not terminal, so `nodes.runAndWait` / `nodes.runMany` end the\n * poll on the first tick they observe it rather than burning `maxMs` on a\n * status that no longer moves on its own.\n *\n * This does NOT cancel the job — the output exists, a human is reviewing it,\n * and the credit reservation stays `reserved` for the whole hold. Do not\n * re-run the request (a duplicate would be held too): re-fetch with\n * `jobs.get(jobId)` later, or surface \"awaiting review\" to your user and poll\n * `jobs.getStatus()` yourself. It resolves to `completed` (approved), `failed`\n * (rejected, with `error_hint.kind === \"policy-block\"`) or `cancelled`.\n *\n * Not an HTTP error — `status` is 0; catch by type/`code`.\n */\nexport class JobHeldError extends NodaroError {\n constructor(\n message: string,\n public readonly jobId: string,\n ) {\n super(message, \"job_held\", 0)\n this.name = \"JobHeldError\"\n }\n}\n\n/** The `{ error: { code, message, … } }` envelope every current route sends. */\ninterface ApiErrorEnvelope {\n code?: string\n message?: string\n missingScope?: string\n required?: number\n available?: number\n limitBytes?: number\n opIndex?: number\n [key: string]: unknown\n}\n\ninterface ApiErrorBody {\n /** The envelope — or, on an older route, a bare string (see {@link readErrorBody}). */\n error?: ApiErrorEnvelope | string\n /** A top-level message: an older route's, a bare validation answer's, or the server framework's own. */\n message?: unknown\n /** OAuth's human text (RFC 6749 §5.2), beside a bare-string `error`. */\n error_description?: unknown\n /** A bare validation answer's per-field issues (`{ message, issues }`). */\n issues?: unknown\n /** A refusal that names another job (see {@link ContinuationRefusedError}). */\n jobId?: unknown\n /** `continuation_preview_pending`: the held continuation, what holds it, and the run that finishes it. */\n executionId?: unknown\n renderNodeIds?: unknown\n reviewNodeIds?: unknown\n next?: unknown\n /** The credit guard's 402 sends its figures beside the envelope: what the run needs… */\n required?: unknown\n /** …and what the caller has (withheld on a deployment-paid instance). */\n balance?: unknown\n /** A per-user allowance's 402: what the allowance has left. */\n remaining?: unknown\n /** `app_run_version_changed`: the version the run ran, and the one the caller is on. */\n runVersion?: unknown\n appVersion?: unknown\n}\n\nconst finite = (v: unknown): number | undefined => (typeof v === \"number\" && Number.isFinite(v) ? v : undefined)\n\n/** A machine code as an older route writes it: lower snake_case, never a sentence or a reason phrase. */\nconst BARE_CODE = /^[a-z][a-z0-9_]*$/\n\nconst nonEmpty = (v: unknown): string | undefined => (typeof v === \"string\" && v.length > 0 ? v : undefined)\n\n/**\n * Where a body keeps its code and its human message. Most routes send the\n * envelope `{ error: { code, message } }`; three other shapes reach the SDK\n * too, and each is read for what it says rather than collapsed into\n * `internal_error` / \"Request failed\":\n *\n * - an older route's bare string, `{ error: \"<code>\", message?, … }` (character\n * training, a few profile and billing routes), and OAuth's\n * `{ error: \"<code>\", error_description }`. A snake_case string is the code;\n * a sentence (`\"Profile not found\"`) is the message.\n * - a bare validation answer, `{ message, issues: [...] }`: `validation_error`.\n * - the server framework's own answer, `{ statusCode, error: \"<reason phrase>\",\n * message }` (a route it does not have): the reason phrase is neither, the\n * message is kept — so \"no such route\" stays distinguishable from \"no such\n * resource\".\n *\n * At HTTP 500 and above only the CODE is read from outside the envelope. Text\n * there can be whatever the server failed with: the framework's own answer to\n * an uncaught throw is `{ statusCode: 500, error: \"Internal Server Error\",\n * message: <the raw error> }`, and the server's sanitizer rewrites only the\n * `internal_error` envelope. The envelope's own message is a route's chosen\n * sentence and is read at every status, as before.\n *\n * `message` is undefined when the body carries no human text it may show, so a\n * typed class keeps its own default (\"Not found\").\n */\nfunction readErrorBody(status: number, body: ApiErrorBody): { code: string | undefined; message: string | undefined; envelope: ApiErrorEnvelope } {\n const raw = body.error\n const envelope: ApiErrorEnvelope = raw && typeof raw === \"object\" ? raw : {}\n const bare = typeof raw === \"string\" ? raw : undefined\n const bareCode = bare !== undefined && BARE_CODE.test(bare) ? bare : undefined\n // Words with a space between them are human text: an older route's sentence,\n // or the framework's reason phrase — which always arrives with a real\n // `message`, read first. A single capitalised word (\"Unauthorized\") is a\n // reason phrase alone and says nothing the status does not.\n const bareSentence = bare !== undefined && bareCode === undefined && /\\s/.test(bare.trim()) ? bare : undefined\n const code =\n nonEmpty(envelope.code) ??\n bareCode ??\n (status === 400 && raw === undefined && Array.isArray(body.issues) ? \"validation_error\" : undefined)\n const outside = status >= 500 ? undefined : (nonEmpty(body.message) ?? nonEmpty(body.error_description) ?? bareSentence)\n const message = nonEmpty(envelope.message) ?? outside\n return { code, message, envelope }\n}\n\n/** The envelope's fields other than `code` and `message` (see {@link NodaroError.details}). */\nfunction envelopeDetails(envelope: ApiErrorEnvelope): Record<string, unknown> {\n const out: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(envelope)) {\n if (key !== \"code\" && key !== \"message\") out[key] = value\n }\n return out\n}\n\nexport function throwFromResponse(status: number, body: ApiErrorBody): never {\n try {\n selectError(status, body)\n } catch (err) {\n // Every class carries the envelope's other fields, whichever was chosen.\n if (err instanceof NodaroError) {\n const raw = body && typeof body === \"object\" ? body.error : undefined\n if (raw && typeof raw === \"object\") Object.defineProperty(err, \"details\", { value: envelopeDetails(raw), enumerable: true })\n }\n throw err\n }\n}\n\nfunction selectError(status: number, body: ApiErrorBody): never {\n // A body that is not an object (an empty answer, `null`, a bare string) still\n // throws by its status.\n const parsed: ApiErrorBody = body && typeof body === \"object\" ? body : {}\n const read = readErrorBody(status, parsed)\n const envelope = read.envelope\n const code = read.code ?? \"internal_error\"\n // A typed class falls back to its own default; a generic error to the code\n // it carries, which says more than \"Request failed\" does.\n const message = read.message ?? (read.code ? read.code : \"Request failed\")\n if (status === 401) throw new UnauthorizedError(read.message)\n if (status === 409 && (code === \"workflow_conflict\" || code === \"production_busy\")) {\n throw new WorkflowConflictError(\n read.message,\n envelope.currentUpdatedAt as string | undefined,\n envelope.currentVersion as number | undefined,\n envelope.currentRecord as Record<string, unknown> | undefined,\n code,\n )\n }\n // By shape, not by code — see StudioOpError. Only the studio operations route\n // sends an op index, so this cannot capture anyone else's 400.\n if (status >= 400 && status < 500 && typeof envelope.opIndex === \"number\") {\n throw new StudioOpError(message, code, status, envelope.opIndex)\n }\n if (status === 409 && CONTINUATION_REFUSAL_CODES.has(code) && typeof parsed.jobId === \"string\") {\n throw new ContinuationRefusedError(message, code, parsed.jobId)\n }\n if (status === 409 && code === \"continuation_preview_pending\" && typeof parsed.executionId === \"string\") {\n throw new ContinuationPreviewPendingError(\n message,\n parsed.executionId,\n stringList(parsed.renderNodeIds),\n stringList(parsed.reviewNodeIds),\n heldFinalRunOf(parsed.next),\n )\n }\n if (status === 409 && code === \"already_running\" && typeof parsed.executionId === \"string\") {\n throw new AlreadyRunningError(message, parsed.executionId)\n }\n if (status === 409 && code === \"app_run_version_changed\") {\n throw new AppRunVersionChangedError(message, finite(parsed.runVersion), finite(parsed.appVersion))\n }\n if (status === 422 && code === \"job_blocked\") throw new JobBlockedError(read.message)\n if (status === 403 && code === \"insufficient_scope\") {\n throw new ForbiddenError(read.message, envelope.missingScope)\n }\n if (status === 403) throw new ForbiddenError(read.message)\n // A 404 the framework answered itself (no route at that path) carries its\n // message at the top level, not under `error`; `readErrorBody` keeps it so\n // callers can tell \"no such route\" from \"no such resource\".\n if (status === 404) throw new NotFoundError(read.message)\n if (status === 429) throw new RateLimitedError(read.message)\n if (status === 402) {\n // The credit guard puts `required` / `balance` (an allowance: `remaining`)\n // beside the envelope; an envelope that carries them (`required` /\n // `available`) is read first.\n const required = finite(envelope.required) ?? finite(parsed.required)\n const available = finite(envelope.available) ?? finite(parsed.balance) ?? finite(parsed.remaining)\n const capCode = read.code as CreditCapCode | undefined\n if (capCode !== undefined && CREDIT_CAP_CODES.has(capCode)) {\n throw new CreditCapExceededError(capCode, read.message, required, available)\n }\n throw new InsufficientCreditsError(read.message, required, available, read.code ?? \"insufficient_credits\")\n }\n if (status === 413) throw new StorageExceededError(read.message, envelope.limitBytes)\n throw new NodaroError(message, code, status)\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkN6GLZOE4_cjs = require('./chunk-N6GLZOE4.cjs');
3
+ var chunkFM2KM5TY_cjs = require('./chunk-FM2KM5TY.cjs');
4
4
 
5
5
  // src/resources/studio-productions.ts
6
6
  function isStudioGenerateEstimate(result) {
@@ -104,11 +104,11 @@ var StudioProductionsResource = class {
104
104
  this.path(productionId, "/ops"),
105
105
  { body: { ops: [], dryRun: true } }
106
106
  );
107
- if (ping?.data?.dryRun !== true) throw new chunkN6GLZOE4_cjs.StudioPreviewUnavailable();
107
+ if (ping?.data?.dryRun !== true) throw new chunkFM2KM5TY_cjs.StudioPreviewUnavailable();
108
108
  const res = await this.client.request("POST", this.path(productionId, "/ops"), { body: input });
109
109
  const data = res?.data;
110
110
  if (data?.dryRun !== true) {
111
- throw new chunkN6GLZOE4_cjs.StudioPreviewAppliedError(data);
111
+ throw new chunkFM2KM5TY_cjs.StudioPreviewAppliedError(data);
112
112
  }
113
113
  return data;
114
114
  }
@@ -321,5 +321,5 @@ var StudioResource = class {
321
321
  exports.StudioProductionsResource = StudioProductionsResource;
322
322
  exports.StudioResource = StudioResource;
323
323
  exports.isStudioGenerateEstimate = isStudioGenerateEstimate;
324
- //# sourceMappingURL=chunk-U4T3Z3K7.cjs.map
325
- //# sourceMappingURL=chunk-U4T3Z3K7.cjs.map
324
+ //# sourceMappingURL=chunk-NKH2UFSD.cjs.map
325
+ //# sourceMappingURL=chunk-NKH2UFSD.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/resources/studio-productions.ts","../src/resources/studio.ts"],"names":["res","StudioPreviewUnavailable","StudioPreviewAppliedError"],"mappings":";;;;;AAwcO,SAAS,yBACd,MAAA,EACkC;AAClC,EAAA,OAAQ,OAAkC,MAAA,KAAW,IAAA;AACvD;AAmCO,IAAM,4BAAN,MAAgC;AAAA,EACrC,YAAoB,MAAA,EAA0B;AAA1B,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AAAA,EAA2B;AAAA,EAA3B,MAAA;AAAA,EAEZ,IAAA,CAAK,YAAA,EAAsB,MAAA,GAAS,EAAA,EAAY;AACtD,IAAA,OAAO,CAAA,uBAAA,EAA0B,kBAAA,CAAmB,YAAY,CAAC,GAAG,MAAM,CAAA,CAAA;AAAA,EAC5E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,KAAA,GAAsC;AAC1C,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,MAAA,CAAO,OAAA;AAAA,MAC5B,KAAA;AAAA,MACA;AAAA,KACF;AACA,IAAA,OAAO,GAAA,CAAI,IAAA;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,aAAa,IAAA,EAAoE;AACrF,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,MAAA,CAAO,OAAA;AAAA,MAC5B,MAAA;AAAA,MACA,iCAAA;AAAA,MACA,EAAE,IAAA,EAAM,EAAE,IAAA,EAAK;AAAE,KACnB;AACA,IAAA,OAAO,GAAA,CAAI,IAAA;AAAA,EACb;AAAA;AAAA,EAGA,MAAM,IAAA,CAAK,IAAA,GAAqC,EAAC,EAA2C;AAC1F,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,MAAA,CAAO,OAAA;AAAA,MAC5B,KAAA;AAAA,MACA,wBAAA;AAAA,MACA;AAAA,QACE,KAAA,EAAO;AAAA,UACL,OAAO,IAAA,CAAK,KAAA;AAAA,UACZ,QAAQ,IAAA,CAAK,MAAA;AAAA,UACb,iBAAiB,IAAA,CAAK;AAAA;AACxB;AACF,KACF;AACA,IAAA,OAAO,GAAA,CAAI,IAAA;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,GAAA,CACJ,YAAA,EACA,IAAA,GAA6B,EAAC,EACH;AAC3B,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,MAAA,CAAO,OAAA;AAAA,MAC5B,KAAA;AAAA,MACA,IAAA,CAAK,KAAK,YAAY,CAAA;AAAA,MACtB,EAAE,OAAO,EAAE,MAAA,EAAQ,KAAK,MAAA,EAAQ,OAAA,EAAS,IAAA,CAAK,MAAA,EAAO;AAAE,KACzD;AACA,IAAA,OAAO,IAAI,IAAA,CAAK,UAAA;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,UAAA,CACJ,YAAA,EACA,IAAA,GAAgC,EAAC,EACE;AACnC,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,MAAA,CAAO,OAAA;AAAA,MAC5B,KAAA;AAAA,MACA,IAAA,CAAK,IAAA,CAAK,YAAA,EAAc,cAAc,CAAA;AAAA,MACtC,EAAE,KAAA,EAAO,EAAE,OAAA,EAAS,IAAA,CAAK,SAAQ;AAAE,KACrC;AACA,IAAA,OAAO,GAAA,CAAI,IAAA;AAAA,EACb;AAAA;AAAA;AAAA,EAKA,MAAM,MAAA,CAAO,KAAA,GAAuC,EAAC,EAAsC;AACzF,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,MAAA,CAAO,OAAA;AAAA,MAC5B,MAAA;AAAA,MACA,wBAAA;AAAA,MACA,EAAE,MAAM,KAAA;AAAM,KAChB;AACA,IAAA,OAAO,GAAA,CAAI,IAAA;AAAA,EACb;AAAA,EAoCA,MAAM,GAAA,CACJ,YAAA,EACA,KAAA,EACsD;AACtD,IAAA,IAAI,KAAA,CAAM,WAAW,IAAA,EAAM;AACzB,MAAA,MAAMA,IAAAA,GAAM,MAAM,IAAA,CAAK,MAAA,CAAO,OAAA;AAAA,QAC5B,MAAA;AAAA,QACA,IAAA,CAAK,IAAA,CAAK,YAAA,EAAc,MAAM,CAAA;AAAA,QAC9B,EAAE,MAAM,KAAA;AAAM,OAChB;AACA,MAAA,OAAOA,IAAAA,CAAI,IAAA;AAAA,IACb;AAMA,IAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,MAAA,CAAO,OAAA;AAAA,MAC7B,MAAA;AAAA,MACA,IAAA,CAAK,IAAA,CAAK,YAAA,EAAc,MAAM,CAAA;AAAA,MAC9B,EAAE,MAAM,EAAE,GAAA,EAAK,EAAC,EAAG,MAAA,EAAQ,MAAK;AAAE,KACpC;AAIA,IAAA,IAAI,MAAM,IAAA,EAAM,MAAA,KAAW,IAAA,EAAM,MAAM,IAAIC,0CAAA,EAAyB;AAEpE,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,MAAA,CAAO,QAE5B,MAAA,EAAQ,IAAA,CAAK,IAAA,CAAK,YAAA,EAAc,MAAM,CAAA,EAAG,EAAE,IAAA,EAAM,OAAO,CAAA;AAG1D,IAAA,MAAM,OAAO,GAAA,EAAK,IAAA;AAClB,IAAA,IAAK,IAAA,EAA2C,WAAW,IAAA,EAAM;AAC/D,MAAA,MAAM,IAAIC,4CAA0B,IAAyB,CAAA;AAAA,IAC/D;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,UAAU,YAAA,EAAwD;AACtE,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,MAAA,CAAO,OAAA;AAAA,MAC5B,MAAA;AAAA,MACA,IAAA,CAAK,IAAA,CAAK,YAAA,EAAc,YAAY;AAAA,KACtC;AACA,IAAA,OAAO,GAAA,CAAI,IAAA;AAAA,EACb;AAAA;AAAA,EAGA,MAAM,UAAA,CACJ,YAAA,EACA,IAAA,EACA,IAAA,GAA4B,EAAC,EACM;AACnC,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,MAAA,CAAO,OAAA;AAAA,MAC5B,MAAA;AAAA,MACA,IAAA,CAAK,IAAA,CAAK,YAAA,EAAc,SAAS,CAAA;AAAA,MACjC,EAAE,MAAM,EAAE,IAAA,EAAM,MAAM,IAAA,CAAK,IAAA,IAAQ,UAAS;AAAE,KAChD;AACA,IAAA,OAAO,GAAA,CAAI,IAAA;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,QAAA,CACJ,YAAA,EACA,KAAA,EACmC;AACnC,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,MAAA,CAAO,OAAA;AAAA,MAC5B,MAAA;AAAA,MACA,IAAA,CAAK,IAAA,CAAK,YAAA,EAAc,WAAW,CAAA;AAAA,MACnC,EAAE,MAAM,KAAA;AAAM,KAChB;AACA,IAAA,OAAO,GAAA,CAAI,IAAA;AAAA,EACb;AAAA,EAwBA,MAAM,QAAA,CACJ,YAAA,EACA,KAAA,EAC+B;AAC/B,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,MAAA,CAAO,OAAA;AAAA,MAC5B,MAAA;AAAA,MACA,IAAA,CAAK,IAAA,CAAK,YAAA,EAAc,WAAW,CAAA;AAAA,MACnC,EAAE,MAAM,KAAA;AAAM,KAChB;AACA,IAAA,OAAO,GAAA,CAAI,IAAA;AAAA,EACb;AAAA,EAoBA,aAAA,CACE,YAAA,EACA,MAAA,EACA,IAAA,GAA8B,EAAC,EACA;AAC/B,IAAA,OAAO,IAAA,CAAK,SAAS,YAAA,EAAc,EAAE,GAAG,IAAA,EAAM,IAAA,EAAM,OAAA,EAAS,MAAA,EAAQ,CAAA;AAAA,EACvE;AAAA,EAgBA,YAAA,CACE,YAAA,EACA,MAAA,EACA,IAAA,GAA8B,EAAC,EACA;AAC/B,IAAA,OAAO,IAAA,CAAK,SAAS,YAAA,EAAc,EAAE,GAAG,IAAA,EAAM,IAAA,EAAM,MAAA,EAAQ,MAAA,EAAQ,CAAA;AAAA,EACtE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,KAAA,CACJ,YAAA,EACA,KAAA,EAC8B;AAC9B,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,MAAA,CAAO,OAAA;AAAA,MAC5B,MAAA;AAAA,MACA,IAAA,CAAK,IAAA,CAAK,YAAA,EAAc,QAAQ,CAAA;AAAA,MAChC,EAAE,MAAM,KAAA;AAAM,KAChB;AACA,IAAA,OAAO,GAAA,CAAI,IAAA;AAAA,EACb;AAAA;AAAA,EAGA,MAAM,KAAA,CACJ,YAAA,EACA,KAAA,EAC8B;AAC9B,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,MAAA,CAAO,OAAA;AAAA,MAC5B,MAAA;AAAA,MACA,IAAA,CAAK,IAAA,CAAK,YAAA,EAAc,QAAQ,CAAA;AAAA,MAChC,EAAE,MAAM,KAAA;AAAM,KAChB;AACA,IAAA,OAAO,GAAA,CAAI,IAAA;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OAAA,CACJ,YAAA,EACA,KAAA,EACmC;AACnC,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,MAAA,CAAO,OAAA;AAAA,MAC5B,MAAA;AAAA,MACA,IAAA,CAAK,IAAA,CAAK,YAAA,EAAc,UAAU,CAAA;AAAA,MAClC,EAAE,MAAM,KAAA;AAAM,KAChB;AACA,IAAA,OAAO,GAAA,CAAI,IAAA;AAAA,EACb;AAAA;AAAA,EAGA,MAAM,KAAA,CACJ,YAAA,EACA,KAAA,EACmC;AACnC,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,MAAA,CAAO,OAAA;AAAA,MAC5B,MAAA;AAAA,MACA,IAAA,CAAK,IAAA,CAAK,YAAA,EAAc,QAAQ,CAAA;AAAA,MAChC,EAAE,MAAM,KAAA;AAAM,KAChB;AACA,IAAA,OAAO,GAAA,CAAI,IAAA;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,MAAM,YAAA,EAAiD;AAC3D,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,MAAA,CAAO,OAAA;AAAA,MAC5B,MAAA;AAAA,MACA,IAAA,CAAK,IAAA,CAAK,YAAA,EAAc,QAAQ,CAAA;AAAA,MAChC,EAAE,IAAA,EAAM,EAAE,MAAA,EAAQ,MAAK;AAAE,KAC3B;AACA,IAAA,OAAO,IAAI,IAAA,CAAK,UAAA;AAAA,EAClB;AAAA;AAAA,EAGA,MAAM,QAAQ,YAAA,EAAiD;AAC7D,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,MAAA,CAAO,OAAA;AAAA,MAC5B,MAAA;AAAA,MACA,IAAA,CAAK,IAAA,CAAK,YAAA,EAAc,UAAU;AAAA,KACpC;AACA,IAAA,OAAO,IAAI,IAAA,CAAK,UAAA;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,KAAA,CACJ,YAAA,EACA,KAAA,GAA4B,EAAC,EACF;AAC3B,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,MAAA,CAAO,OAAA;AAAA,MAC5B,MAAA;AAAA,MACA,IAAA,CAAK,IAAA,CAAK,YAAA,EAAc,QAAQ,CAAA;AAAA,MAChC,EAAE,MAAM,KAAA;AAAM,KAChB;AACA,IAAA,OAAO,IAAI,IAAA,CAAK,UAAA;AAAA,EAClB;AACF;;;AC1vBA,IAAM,IAAA,GAAO,wBAAA;AACb,IAAM,IAAA,GAAO,CAAC,EAAA,KAAe,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,kBAAA,CAAmB,EAAE,CAAC,CAAA,CAAA;AAIvD,IAAM,iBAAN,MAAqB;AAAA,EAG1B,YAA6B,MAAA,EAA0B;AAA1B,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AAC3B,IAAA,IAAA,CAAK,WAAA,GAAc,IAAI,yBAAA,CAA0B,MAAM,CAAA;AAAA,EACzD;AAAA,EAF6B,MAAA;AAAA,EAFpB,WAAA;AAAA,EAMT,YAAA,GAAgE;AAC9D,IAAA,OAAO,KAAK,MAAA,CAAO,OAAA,CAAQ,KAAA,EAAO,CAAA,EAAG,IAAI,CAAA,aAAA,CAAe,CAAA;AAAA,EAC1D;AAAA,EAEA,KAAA,GAA+C;AAC7C,IAAA,OAAO,KAAK,MAAA,CAAO,OAAA,CAAQ,KAAA,EAAO,CAAA,EAAG,IAAI,CAAA,MAAA,CAAQ,CAAA;AAAA,EACnD;AAAA,EAEA,IAAA,CAAK,OAAA,GAA0E,EAAC,EAG3E;AACH,IAAA,OAAO,IAAA,CAAK,OAAO,OAAA,CAAQ,KAAA,EAAO,MAAM,EAAE,KAAA,EAAO,SAAS,CAAA;AAAA,EAC5D;AAAA,EAEA,GAAA,CAAI,EAAA,EAAY,OAAA,GAA4D,EAAC,EAA6C;AACxH,IAAA,OAAO,KAAK,MAAA,CAAO,OAAA,CAAQ,KAAA,EAAO,IAAA,CAAK,EAAE,CAAA,EAAG,EAAE,KAAA,EAAO,EAAE,QAAQ,OAAA,CAAQ,MAAA,EAAQ,SAAS,OAAA,CAAQ,MAAA,IAAU,CAAA;AAAA,EAC5G;AAAA,EAEA,aAAa,IAAA,EAA6J;AACxK,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQ,MAAA,EAAQ,CAAA,EAAG,IAAI,CAAA,SAAA,CAAA,EAAa,EAAE,IAAA,EAAM,EAAE,IAAA,EAAK,EAAG,CAAA;AAAA,EAC3E;AAAA,EAEA,OAAO,KAAA,EAA+F;AACpG,IAAA,OAAO,IAAA,CAAK,OAAO,OAAA,CAAQ,MAAA,EAAQ,MAAM,EAAE,IAAA,EAAM,OAAO,CAAA;AAAA,EAC1D;AAAA;AAAA;AAAA,EAIA,aAAa,KAAA,EAAqG;AAChH,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQ,MAAA,EAAQ,CAAA,EAAG,IAAI,CAAA,cAAA,CAAA,EAAkB,EAAE,IAAA,EAAM,KAAA,EAAO,CAAA;AAAA,EAC7E;AAAA;AAAA,EAGA,YAAA,CAAa,IAAY,KAAA,EAGlB;AACL,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQ,MAAA,EAAQ,CAAA,EAAG,IAAA,CAAK,EAAE,CAAC,CAAA,cAAA,CAAA,EAAkB,EAAE,IAAA,EAAM,KAAA,EAAO,CAAA;AAAA,EACjF;AAAA;AAAA;AAAA,EAIA,KAAA,CAAM,EAAA,EAAY,KAAA,GAAyE,EAAC,EAA6C;AACvI,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQ,MAAA,EAAQ,CAAA,EAAG,IAAA,CAAK,EAAE,CAAC,CAAA,MAAA,CAAA,EAAU,EAAE,IAAA,EAAM,KAAA,EAAO,CAAA;AAAA,EACzE;AAAA,EAEA,IAAA,CAAK,IAAY,KAAA,EAA0I;AACzJ,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQ,MAAA,EAAQ,CAAA,EAAG,IAAA,CAAK,EAAE,CAAC,CAAA,IAAA,CAAA,EAAQ,EAAE,IAAA,EAAM,KAAA,EAAO,CAAA;AAAA,EACvE;AAAA;AAAA;AAAA,EAIA,SAAA,CAAU,IAAY,KAAA,EAA6H;AACjJ,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQ,MAAA,EAAQ,CAAA,EAAG,IAAA,CAAK,EAAE,CAAC,CAAA,MAAA,CAAA,EAAU,EAAE,IAAA,EAAM,KAAA,EAAO,CAAA;AAAA,EACzE;AAAA;AAAA;AAAA,EAIA,eAAA,CAAgB,IAAY,KAAA,EAA6E;AACvG,IAAA,OAAO,IAAA,CAAK,KAAK,EAAA,EAAI;AAAA,MACnB,aAAa,KAAA,CAAM,eAAA;AAAA,MAAiB,MAAA,EAAQ,IAAA;AAAA,MAC5C,GAAI,MAAM,eAAA,GAAkB,EAAE,iBAAiB,KAAA,CAAM,eAAA,KAAoB,EAAC;AAAA,MAC1E,GAAA,EAAK,CAAC,EAAE,EAAA,EAAI,mBAAA,EAAqB,eAAA,EAAiB,KAAA,CAAM,eAAA,EAAiB,KAAA,EAAO,KAAA,CAAM,KAAA,EAAO;AAAA,KAC9F,CAAA;AAAA,EACH;AAAA,EAEA,gBAAA,CAAiB,IAAY,KAAA,EAA2G;AACtI,IAAA,OAAO,KAAK,MAAA,CAAO,OAAA,CAAQ,MAAA,EAAQ,CAAA,EAAG,KAAK,EAAE,CAAC,CAAA,SAAA,CAAA,EAAa,EAAE,MAAM,EAAE,GAAG,OAAO,IAAA,EAAM,UAAA,IAAc,CAAA;AAAA,EACrG;AAAA,EAEA,YAAA,CAAa,IAAY,KAAA,EAA4E;AACnG,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQ,MAAA,EAAQ,CAAA,EAAG,IAAA,CAAK,EAAE,CAAC,CAAA,SAAA,CAAA,EAAa,EAAE,IAAA,EAAM,KAAA,EAAO,CAAA;AAAA,EAC5E;AAAA;AAAA,EAGA,cAAA,CAAe,EAAA,EAAY,KAAA,EACzB,WAAA,GAAmF,EAAC,EAAG;AACvF,IAAA,OAAO,IAAA,CAAK,IAAA,CAAK,EAAA,EAAI,EAAE,GAAG,WAAA,EAAa,GAAA,EAAK,CAAC,EAAE,GAAG,KAAA,EAAO,EAAA,EAAI,wBAAA,EAA0B,GAAG,CAAA;AAAA,EAC5F;AAAA,EAEA,UAAU,EAAA,EAAmI;AAC3I,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQ,MAAA,EAAQ,CAAA,EAAG,IAAA,CAAK,EAAE,CAAC,CAAA,UAAA,CAAA,EAAc,EAAE,IAAA,EAAM,IAAI,CAAA;AAAA,EAC1E;AACF","file":"chunk-NKH2UFSD.cjs","sourcesContent":["import type { NodaroClientCore } from \"../core.js\"\nimport { StudioPreviewAppliedError, StudioPreviewUnavailable } from \"../errors.js\"\n\n/**\n * Studio productions — `/v1/studio/productions`.\n *\n * A production is a Nodaro workflow whose `settings.studio` holds the shots:\n * each shot a framed still, an optional animated clip, and the plan, looks,\n * cast bindings and voice that made them. These routes are the platform's own\n * reader and writer of that document, so an agent, a script and the studio app\n * are looking at ONE production rather than three opinions about one row.\n *\n * Two rules run through the whole surface:\n *\n * - **Every change is an OPERATION** ({@link StudioProductionsResource.ops}),\n * addressed by stable key — a shot id, a role slug, a result's job id or url\n * — and never by position. That is what lets two writers hold the same\n * production open: a batch composed against a slightly older version still\n * applies correctly to the newest one, and the response says whether it was\n * rebased.\n * - **Generation is run-then-poll.** A still or clip run returns job ids and\n * records a marker on the production; the results land when anyone — your\n * poll, the app, a later {@link StudioProductionsResource.reconcile} —\n * reports the finished job. Nothing waits minutes inside a request.\n *\n * Reads are `detail: \"summary\"` by default (counts and the active urls);\n * `detail: \"full\"` adds every result with the context that regenerates it.\n *\n * **The ENVELOPES are typed here; the production DOCUMENT is not.** A view, a\n * summary, a shot and an operation are open JSON on this surface\n * ({@link StudioProduction}, `ops: unknown[]`) — their field-level types ship\n * with the studio app, which is the one consumer that narrows them, and a\n * second spelling of that vocabulary in the SDK would drift from it the first\n * time either grew. Everything a caller branches on — `version`, `rebased`,\n * `receipts`, `warnings`, a quote's `credits`, a run's `jobIds` — is typed.\n *\n * Cloud edition only: these routes 404 on deployments that do not serve them.\n * Feature-detect once with `list()` — a deployment without them 404s that too,\n * where a deployment with them answers an empty page.\n */\n\n/**\n * A production, a summary, a shot, a receipt's target: open JSON.\n *\n * Deliberately not narrowed here — see the note at the top of this module.\n */\nexport type StudioProduction = Record<string, unknown>\n\n/** How much of a production a read returns. */\nexport type StudioProductionDetail = \"summary\" | \"full\"\n\n/** One thing wrong with a plan, addressed at the field that is wrong. */\nexport interface StudioPlanIssue {\n path: string\n message: string\n hint?: string\n}\n\n/** `GET …/skill` — the authoring skill, rendered at request time from what is live. */\nexport interface StudioSkillResponse {\n /** The authoring guide. */\n skill: string\n /** Every picker, model and enum, in full. */\n catalog: string\n /** The strict JSON Schema a plan is validated against. */\n schema: Record<string, unknown>\n /** The operating guide: the tool map, the loops, the rules. */\n operating: string\n /** The versions the three were rendered from — bare semver, no package names. */\n generatedFrom: { prompts: string; shared: string; codec: string }\n}\n\nexport interface StudioValidatePlanResponse {\n valid: boolean\n errors: StudioPlanIssue[]\n warnings: StudioPlanIssue[]\n summary?: {\n name?: string\n scenes: number\n shots: number\n cast: number\n /** Cast entries that matched a row in the caller's library. */\n bound: number\n }\n}\n\nexport interface StudioListProductionsResponse {\n data: StudioProduction[]\n nextCursor?: string\n}\n\n/** What a create or an import did, in the words a receipt would use. */\nexport interface StudioImportSummary {\n shotsAdded: number\n castEnrolled: number\n /** Cast entries that resolved to a row in the caller's library. */\n castBound: number\n}\n\nexport interface StudioProductionResponse {\n production: StudioProduction\n warnings?: StudioPlanIssue[]\n summary?: StudioImportSummary\n}\n\nexport interface StudioCreateProductionRequest {\n name?: string\n plan?: Record<string, unknown>\n}\n\n/** The caller's own retry token — 8–128 chars of `A-Za-z0-9_.:-`, never derived. */\nexport type StudioClientRequestId = string\n\n/**\n * A batch of operations, applied atomically.\n *\n * `ops` is `unknown[]`: the operation union is the studio app's vocabulary and\n * the route validates it, refusing the whole batch with the offending index.\n * The served operating guide is the runtime reference for what an operation\n * looks like.\n */\nexport interface StudioOpsRequest {\n /** Applied in order. At most 100 per request. */\n ops: unknown[]\n /**\n * The version the batch was composed against. INFORMATIONAL by default: the\n * operations address by stable KEY, so a batch built on a slightly older\n * document still applies exactly to the newest one, and the response says\n * `rebased: true`. Omitting it means \"apply to whatever is there\".\n */\n baseVersion?: number\n /**\n * Refuse to rebase. With `strict: true` a `baseVersion` older than the stored\n * one is a 409 `workflow_conflict` carrying the current production, instead\n * of a rebased apply — for the rare \"replace exactly what I read\" intent.\n */\n strict?: boolean\n /** Your own token for this batch, so a transport retry is not applied twice. */\n clientRequestId?: StudioClientRequestId\n}\n\n/**\n * What else an operation touched — the work that now has to follow it.\n *\n * Reported by the operations whose effect reaches past the thing they name: a\n * frame review re-opens every frame derived from it and every shot bound to\n * those, a sequence fork mints a whole parallel set. Both lists are always\n * present and either may be empty; ids, never counts, because the caller's job\n * is to go and refresh THOSE.\n */\nexport interface StudioOpsImpact {\n /** Planned frames the operation reaches, the named one first. */\n keyframeIds: string[]\n /** Shots bound to any of those frames. */\n shotIds: string[]\n}\n\n/**\n * A sentence as data: the id of the template a client words it from, and the\n * values that fill the template's slots.\n *\n * It travels beside the English wording, never instead of it. A client that\n * words the sentence in the person's language builds it from `template` and\n * `vars`, and shows the English wording whenever it has no wording for\n * `template` or `vars` does not fill it — so a template id it has never heard of\n * costs nothing. A template id is permanent: a change to its slots or its\n * meaning ships as a new id.\n */\nexport interface StudioOpsText {\n /** The template's id. */\n template: string\n /** What fills the template's slots, by slot name. */\n vars: Record<string, string | number>\n}\n\n/**\n * One line of what an operation did, in the words a change log would use.\n *\n * Past tense, the target named the way the user sees it, the side effect in a\n * trailing parenthetical: `Deleted take 2 of Shot 1 (in the bin).`\n */\nexport interface StudioOpsReceipt {\n /** The operation this line reports, by name. */\n op: string\n /** Past tense, naming the target the way a person would. */\n summary: string\n /**\n * `summary` as data, for a client that words receipts in the person's\n * language. `summary` is always present and always English; read `detail`\n * only when you have wording for its template, and show `summary` when you do\n * not. Absent when the studio service that answered predates it.\n */\n detail?: StudioOpsText\n /** Ids the operation MINTED — never ids the caller supplied. */\n ids?: string[]\n /**\n * The dependency scope, where the operation reports one — absent for the\n * many that touch only what they name. The route projects a receipt ONCE for\n * both answers, so this reads the same on an apply and on a preview.\n */\n impact?: StudioOpsImpact\n}\n\n/** What a batch produced. Adopt `production` whole; do not merge into it. */\nexport interface StudioOpsResponse {\n /** The canonical production AFTER the batch. */\n production: StudioProduction\n /** The version the batch produced. Carry it as the next `baseVersion`. */\n version: number\n /** True when the batch was applied to a newer document than it named. */\n rebased: boolean\n /** One per operation, in order. */\n receipts: StudioOpsReceipt[]\n /**\n * Things worth saying that are not failures — an operation that changed\n * nothing, a rename that rewrote four prompts. A warning never rejects a\n * batch; a refusal does.\n */\n warnings: string[]\n /**\n * `warnings` as data, by position: entry `i` words `warnings[i]`, and `null`\n * means that warning has no wording but the English one. The service sends it\n * only when it is exactly as long as `warnings`, so treat a list of any other\n * length as absent. Absent too when the studio service that answered predates\n * it.\n */\n warningDetails?: Array<StudioOpsText | null>\n}\n\n/**\n * An operation's confirmation class — the vocabulary's own four letters.\n *\n * `S` safe · `D` delete · `P` changes who can reach the work · `$` spends\n * credits. The table that assigns them ships with the production codec and is\n * pinned complete over the operation union there; this is the wire's spelling\n * of its values, not a second table.\n */\nexport type StudioOpClass = \"S\" | \"D\" | \"P\" | \"$\"\n\n/**\n * One line of what an operation WOULD do, for a person deciding whether to let\n * it. Everything {@link StudioOpsReceipt} says — the same summary, the same ids\n * and the same {@link StudioOpsImpact}, read in the conditional — plus the two\n * things the decision turns on and only a preview needs: which kind of change\n * it is, and whether it can be taken back.\n */\nexport interface StudioOpsDryRunReceipt extends StudioOpsReceipt {\n /**\n * The confirmation class, read out of the operation vocabulary's own table:\n * `S` safe, `D` deletes, `P` changes who can reach the work, `$` spends\n * credits. Narrow rather than open, because it is what a caller branches on\n * — a rule like \"never a `D` without asking\" is only writable if the\n * compiler knows the letters.\n */\n class: StudioOpClass\n /**\n * Present, and always `true`, when this operation put something in the bin\n * that can be brought back. ABSENT is the honest answer for everything else,\n * including a delete that destroys: there is no entry to name, so there is no\n * promise to make. Read it as `restorable ?? false`, never as `!restorable`\n * meaning \"kept\".\n */\n restorable?: true\n}\n\n/**\n * What a batch WOULD do. Nothing was written: there is no production here and\n * no new version, because none was produced.\n */\nexport interface StudioOpsDryRunResponse {\n /** Always present, and the marker the two-request protocol reads. */\n dryRun: true\n /** The version the preview was computed against. */\n version: number\n /** One per operation, in order. */\n receipts: StudioOpsDryRunReceipt[]\n /** The same things an apply would have said. */\n warnings: string[]\n /** The same data behind them an apply would have sent: see {@link StudioOpsResponse.warningDetails}. */\n warningDetails?: Array<StudioOpsText | null>\n}\n\n/** What landing the finished jobs did. */\nexport interface StudioReconcileResponse {\n /** Job ids whose media is now on the production. */\n landed: string[]\n /** Job ids still running — their markers stay; call again later. */\n pending: string[]\n /** Job ids that failed or were cancelled; their markers are cleared. */\n failed: string[]\n /** One line per landing that had something to say. */\n warnings: string[]\n /** The production after the landings. */\n production: StudioProduction\n /** Its version — unchanged when nothing landed. */\n version: number\n}\n\n/** `POST …/:id/describe` — a Director run that will land as scenes. */\nexport interface StudioDescribeRequest {\n brief: string\n llmModel: string\n /** `\"append\"` adds the drafted scenes; `\"replace\"` rewrites the film. */\n mode?: \"append\" | \"replace\"\n label?: string\n clientRequestId?: StudioClientRequestId\n}\n\n/**\n * `POST …/:id/generate` — one framing or directing run for one shot.\n *\n * `overrides` is what the CALL owns over what the shot's plan says: the model,\n * the prose, the aspect, the direction ids. Open JSON, because the request\n * builders' own option types are the contract and they ship with the studio.\n */\nexport interface StudioGenerateRequest {\n kind: \"still\" | \"clip\"\n shotId: string\n /** Candidates to fan out (stills); the builder clamps it to the catalog's range. */\n count?: number\n /**\n * The directing input mode for a clip; absent ⇒ derived from the scene's saved\n * inputs (a pinned end frame included). `start` sends ONLY the start frame;\n * `start-end` sends the start and the end frame.\n */\n mode?: \"start\" | \"start-end\" | \"references\"\n /** Price the run and return; nothing is submitted and nothing is written. */\n dryRun?: boolean\n clientRequestId?: StudioClientRequestId\n overrides?: Record<string, unknown>\n}\n\n/** Which video route a directing run went to — chosen from the inputs, never asked for. */\nexport type StudioVideoLane = \"generate-video\" | \"text-to-video\"\n\n/** `dryRun: true` — what this run would cost, and nothing else. */\nexport interface StudioGenerateEstimate {\n dryRun: true\n provider: string\n count: number\n /** `null` when the model is unpriced or the instance runs without credits. */\n credits: number | null\n lane?: StudioVideoLane\n}\n\n/**\n * A started (or already-started) run.\n *\n * `deduped` means the same `clientRequestId` came back and the job ids were\n * answered from the production's own markers — nothing was submitted and\n * nothing was charged, so `production` is absent.\n */\nexport interface StudioGenerateResponse {\n jobIds: string[]\n lane?: StudioVideoLane\n deduped?: true\n production?: StudioProduction\n receipts?: StudioOpsReceipt[]\n warnings?: string[]\n}\n\n/** `POST …/:id/frame` — a still pulled out of the shot's clip. */\nexport interface StudioFrameRequest {\n shotId: string\n mode?: \"first\" | \"last\" | \"timestamp\"\n /** Seconds, when `mode` is `\"timestamp\"`. */\n timestamp?: number\n /** Where the grabbed image lands. `\"new-shot\"` inserts a shot after this one. */\n target?: \"new-shot\" | \"start-frame\" | \"end-frame\" | \"still\"\n clientRequestId?: StudioClientRequestId\n}\n\n/** `POST …/:id/voice` — synthesize a shot's spoken line and record it. */\nexport interface StudioVoiceRequest {\n shotId: string\n text: string\n voiceId?: string\n voiceType?: \"premade\" | \"custom\" | \"library\"\n ttsProvider?: string\n /** The delivery levers; the text-to-speech route owns their bounds. */\n delivery?: Record<string, number>\n clientRequestId?: StudioClientRequestId\n}\n\n/** `POST …/:id/revoice` — recast the voices of the shot's active clip. */\nexport interface StudioRevoiceRequest {\n shotId: string\n /** The speaker-ordered recast plan, forwarded to the voice route verbatim. */\n plan: Record<string, unknown>\n clientRequestId?: StudioClientRequestId\n}\n\n/** `POST …/:id/music` — the film's soundtrack. */\nexport interface StudioMusicRequest {\n prompt: string\n duration?: number\n instrumental?: boolean\n vocalGender?: string\n model?: string\n clientRequestId?: StudioClientRequestId\n}\n\n/**\n * What a route that finished its work answers with: the production as it now\n * stands, plus whatever that route produced.\n *\n * `jobId` is present on the routes that only STARTED something (a revoice, a\n * soundtrack, a draft) — the result lands through its marker.\n */\nexport interface StudioMediaResponse {\n production: StudioProduction\n /** The grabbed frame's url, on the frame route. */\n url?: string\n jobId?: string\n receipts?: StudioOpsReceipt[]\n warnings?: string[]\n}\n\n/**\n * `GET …/:id/export-plan` — the ordered steps an export would run.\n *\n * The caller runs them with the verbs that already exist; a route that chained\n * three minutes-long jobs is the long-lived request every client times out on.\n */\nexport interface StudioExportPlanResponse {\n /** False when the production has fewer than two clips — nothing to stitch. */\n canExport: boolean\n steps: StudioExportStep[]\n /** The step whose output IS the film, or `null` when nothing can run. */\n resultStepId: string | null\n /** Total credits, or `null` when ANY step is unpriced (a partial sum understates). */\n estimate: number | null\n /** The credit models with no price, each named once, in step order. */\n unpriced: string[]\n}\n\nexport interface StudioExportStep {\n /** Stable within one plan and derived from the production, never minted. */\n id: string\n label: string\n /** The node this step runs — `merge-video-audio`, `combine-videos`, `video-upscale`. */\n node: string\n creditModel: string\n credits: number | null\n params: Record<string, unknown>\n}\n\n/** `POST …/:id/clone` — a copy, which always starts private and visible. */\nexport interface StudioCloneRequest {\n name?: string\n}\n\n/** Either arm of a generation reply: the quote, or the run that started. */\nexport type StudioGenerateResult = StudioGenerateEstimate | StudioGenerateResponse\n\n/** True when a generation reply is the `dryRun` QUOTE rather than a started run. */\nexport function isStudioGenerateEstimate(\n result: StudioGenerateResult,\n): result is StudioGenerateEstimate {\n return (result as StudioGenerateEstimate).dryRun === true\n}\n\n/** What a `generateStill` / `generateClip` call decides, beyond `kind` and the shot. */\nexport type StudioGenerateOptions = Omit<StudioGenerateRequest, \"kind\" | \"shotId\">\n\n/**\n * A route that only STARTED something — a draft, a revoice, a soundtrack. Its\n * `jobId` is always there, which is what makes `const { jobId } = await …` and\n * a poll the honest next line.\n *\n * `StudioMediaResponse` leaves `jobId` optional because the routes that FINISH\n * their work (a frame, a voiceover) share the shape and have no job to name.\n */\nexport type StudioJobStartedResponse = StudioMediaResponse & { jobId: string }\n\nexport interface ListStudioProductionsOptions {\n limit?: number\n /** From a previous page's `nextCursor`. */\n cursor?: string\n /** Include the rows the dashboard hides. Off by default. */\n includeArchived?: boolean\n}\n\nexport interface GetProductionOptions {\n detail?: StudioProductionDetail\n /** Read ONE shot — the cheap way to re-read after a generation. */\n shotId?: string\n}\n\nexport interface StudioExportPlanOptions {\n /** Plan the 4K finish too. Expensive, so it is always explicit. */\n upscale?: boolean\n}\n\n/** `client.studio.productions` — see the note at the top of this module. */\nexport class StudioProductionsResource {\n constructor(private client: NodaroClientCore) {}\n\n private path(productionId: string, suffix = \"\"): string {\n return `/v1/studio/productions/${encodeURIComponent(productionId)}${suffix}`\n }\n\n // ── reads ────────────────────────────────────────────────────────────────\n\n /**\n * The authoring guide, the full catalog, the plan's JSON Schema and the\n * operating guide — rendered server-side from the version that is live, so\n * they describe the platform you are actually talking to. Free.\n */\n async skill(): Promise<StudioSkillResponse> {\n const res = await this.client.request<{ data: StudioSkillResponse }>(\n \"GET\",\n \"/v1/studio/productions/skill\",\n )\n return res.data\n }\n\n /**\n * Check a plan before it becomes anything. Free, persists nothing, and\n * resolves cast names against YOUR library — loop on `errors` until\n * `valid: true`, then `create({ plan })`.\n */\n async validatePlan(plan: Record<string, unknown>): Promise<StudioValidatePlanResponse> {\n const res = await this.client.request<{ data: StudioValidatePlanResponse }>(\n \"POST\",\n \"/v1/studio/productions/validate\",\n { body: { plan } },\n )\n return res.data\n }\n\n /** Your productions, newest first. Archived rows are hidden unless asked for. */\n async list(opts: ListStudioProductionsOptions = {}): Promise<StudioListProductionsResponse> {\n const res = await this.client.request<{ data: StudioListProductionsResponse }>(\n \"GET\",\n \"/v1/studio/productions\",\n {\n query: {\n limit: opts.limit,\n cursor: opts.cursor,\n includeArchived: opts.includeArchived,\n },\n },\n )\n return res.data\n }\n\n /**\n * One production. A pure read — it never lands a finished job, so call\n * {@link reconcile} first if you are waiting on one.\n */\n async get(\n productionId: string,\n opts: GetProductionOptions = {},\n ): Promise<StudioProduction> {\n const res = await this.client.request<{ data: { production: StudioProduction } }>(\n \"GET\",\n this.path(productionId),\n { query: { detail: opts.detail, shot_id: opts.shotId } },\n )\n return res.data.production\n }\n\n /**\n * The ordered steps that assemble the film, with what they will cost. Run\n * them yourself with the ordinary verbs — nothing here blocks for minutes,\n * and nothing here spends.\n */\n async exportPlan(\n productionId: string,\n opts: StudioExportPlanOptions = {},\n ): Promise<StudioExportPlanResponse> {\n const res = await this.client.request<{ data: StudioExportPlanResponse }>(\n \"GET\",\n this.path(productionId, \"/export-plan\"),\n { query: { upscale: opts.upscale } },\n )\n return res.data\n }\n\n // ── writes ───────────────────────────────────────────────────────────────\n\n /** A new production, optionally landed from a plan in the same call. */\n async create(input: StudioCreateProductionRequest = {}): Promise<StudioProductionResponse> {\n const res = await this.client.request<{ data: StudioProductionResponse }>(\n \"POST\",\n \"/v1/studio/productions\",\n { body: input },\n )\n return res.data\n }\n\n /**\n * Apply a batch of operations. Atomic: one bad operation refuses the whole\n * batch with a `StudioOpError` naming its index, and nothing is written. On\n * success adopt `production` wholesale and carry `version` forward as the\n * next `baseVersion`.\n *\n * `dryRun: true` — the LITERAL, which is what selects the preview reply —\n * asks what the batch would do, so a person can approve an assistant's edits\n * before they land. Spell it in THIS call's own object literal: a flag passed\n * through a variable widens `true` to `boolean`, which selects the apply\n * overload while the runtime still takes the preview path.\n *\n * A preview is TWO requests, deliberately. The route's body is parsed in\n * strip mode, so a deployment that predates the preview drops the flag and\n * APPLIES the batch: a caller that sent its batch and read the answer\n * afterwards would already have written it. So the flag is proved on an EMPTY\n * batch first and the real batch goes only when that answer carries the\n * marker. An older deployment either answers the apply shape — this throws\n * `StudioPreviewUnavailable`, and the batch never leaves — or refuses the\n * empty batch with its own error, which is passed through as it stands.\n *\n * The ping proves the deployment that answered IT, and a fleet mid-rollout\n * can serve the second request from another one. So the second answer is\n * checked too: when the batch came back APPLIED, this throws\n * `StudioPreviewAppliedError`, which carries that write. The SDK cannot\n * un-send a request; what it can do is refuse to call the result a preview.\n *\n * An apply stays exactly one request.\n */\n ops(\n productionId: string,\n input: StudioOpsRequest & { dryRun: true },\n ): Promise<StudioOpsDryRunResponse>\n ops(productionId: string, input: StudioOpsRequest): Promise<StudioOpsResponse>\n async ops(\n productionId: string,\n input: StudioOpsRequest & { dryRun?: true },\n ): Promise<StudioOpsResponse | StudioOpsDryRunResponse> {\n if (input.dryRun !== true) {\n const res = await this.client.request<{ data: StudioOpsResponse }>(\n \"POST\",\n this.path(productionId, \"/ops\"),\n { body: input },\n )\n return res.data\n }\n\n // The ping carries nothing of the caller's batch, because an old deployment\n // takes whatever it is sent at face value; an empty batch with no\n // `clientRequestId` spends neither the caller's operations nor the retry\n // token that would make a real batch unrepeatable.\n const ping = await this.client.request<{ data?: { dryRun?: unknown } } | undefined>(\n \"POST\",\n this.path(productionId, \"/ops\"),\n { body: { ops: [], dryRun: true } },\n )\n // Read through: an older deployment can answer no envelope at all, or a 204\n // that `request` reads as `undefined`. Absent is a \"no\" like any other, and\n // the caller who catches `NodaroError` should not get a `TypeError`.\n if (ping?.data?.dryRun !== true) throw new StudioPreviewUnavailable()\n\n const res = await this.client.request<\n { data?: StudioOpsDryRunResponse | StudioOpsResponse } | undefined\n >(\"POST\", this.path(productionId, \"/ops\"), { body: input })\n // The answer that matters most: this request may have landed on a different\n // deployment from the ping, and an applied batch is not a preview.\n const data = res?.data\n if ((data as { dryRun?: unknown } | undefined)?.dryRun !== true) {\n throw new StudioPreviewAppliedError(data as StudioOpsResponse)\n }\n return data as StudioOpsDryRunResponse\n }\n\n /**\n * Land every generation that has finished since you last looked, and report\n * what is still running. The one call that turns finished jobs into results\n * without a browser open. It writes only when something actually landed.\n */\n async reconcile(productionId: string): Promise<StudioReconcileResponse> {\n const res = await this.client.request<{ data: StudioReconcileResponse }>(\n \"POST\",\n this.path(productionId, \"/reconcile\"),\n )\n return res.data\n }\n\n /** Add a plan's scenes to a production that already exists. */\n async importPlan(\n productionId: string,\n plan: Record<string, unknown>,\n opts: { mode?: \"append\" } = {},\n ): Promise<StudioProductionResponse> {\n const res = await this.client.request<{ data: StudioProductionResponse }>(\n \"POST\",\n this.path(productionId, \"/import\"),\n { body: { plan, mode: opts.mode ?? \"append\" } },\n )\n return res.data\n }\n\n /**\n * Turn a brief into scenes. The run is a platform job: poll it, and its\n * scenes land through {@link reconcile}. The production comes back with the\n * run recorded on it as a pending draft.\n */\n async describe(\n productionId: string,\n input: StudioDescribeRequest,\n ): Promise<StudioJobStartedResponse> {\n const res = await this.client.request<{ data: StudioJobStartedResponse }>(\n \"POST\",\n this.path(productionId, \"/describe\"),\n { body: input },\n )\n return res.data\n }\n\n // ── generation ───────────────────────────────────────────────────────────\n\n /**\n * Frame or animate one shot.\n *\n * The request is assembled server-side from the shot's own plan, looks and\n * bound references, so a scripted run and a press of the button in the app\n * produce the same media; `overrides` changes THIS run without changing the\n * shot. Prefer {@link generateStill} / {@link generateClip}, which say which\n * kind they mean.\n *\n * `dryRun: true` returns the quote and writes nothing — narrow the reply with\n * {@link isStudioGenerateEstimate}.\n */\n generate(\n productionId: string,\n input: StudioGenerateRequest & { dryRun: true },\n ): Promise<StudioGenerateEstimate>\n generate(\n productionId: string,\n input: StudioGenerateRequest,\n ): Promise<StudioGenerateResult>\n async generate(\n productionId: string,\n input: StudioGenerateRequest,\n ): Promise<StudioGenerateResult> {\n const res = await this.client.request<{ data: StudioGenerateResult }>(\n \"POST\",\n this.path(productionId, \"/generate\"),\n { body: input },\n )\n return res.data\n }\n\n /**\n * Frame a shot: submit `count` candidates and record a pending marker for\n * each. Results ACCUMULATE — a generate never replaces what is there.\n *\n * `clientRequestId` makes a retry safe: the same token answers with the jobs\n * the first call started (`deduped: true`) and submits nothing. Never retry a\n * spend without it.\n */\n generateStill(\n productionId: string,\n shotId: string,\n opts: StudioGenerateOptions & { dryRun: true },\n ): Promise<StudioGenerateEstimate>\n generateStill(\n productionId: string,\n shotId: string,\n opts?: StudioGenerateOptions,\n ): Promise<StudioGenerateResult>\n generateStill(\n productionId: string,\n shotId: string,\n opts: StudioGenerateOptions = {},\n ): Promise<StudioGenerateResult> {\n return this.generate(productionId, { ...opts, kind: \"still\", shotId })\n }\n\n /**\n * Animate a shot. The LANE is chosen from the shot's inputs (a start frame,\n * references, a prompt) — never passed in — and reported back as `lane`.\n */\n generateClip(\n productionId: string,\n shotId: string,\n opts: StudioGenerateOptions & { dryRun: true },\n ): Promise<StudioGenerateEstimate>\n generateClip(\n productionId: string,\n shotId: string,\n opts?: StudioGenerateOptions,\n ): Promise<StudioGenerateResult>\n generateClip(\n productionId: string,\n shotId: string,\n opts: StudioGenerateOptions = {},\n ): Promise<StudioGenerateResult> {\n return this.generate(productionId, { ...opts, kind: \"clip\", shotId })\n }\n\n // ── media on one shot ────────────────────────────────────────────────────\n\n /**\n * Extract a frame from a shot's active clip and put it where `target` says —\n * a new shot after this one (the default), this shot's sticky start or end\n * frame, or another still of the same shot. Seconds, not minutes: this one\n * waits for the job and answers with the changed production.\n */\n async frame(\n productionId: string,\n input: StudioFrameRequest,\n ): Promise<StudioMediaResponse> {\n const res = await this.client.request<{ data: StudioMediaResponse }>(\n \"POST\",\n this.path(productionId, \"/frame\"),\n { body: input },\n )\n return res.data\n }\n\n /** Synthesize a shot's spoken line and record it. Waits for the job. */\n async voice(\n productionId: string,\n input: StudioVoiceRequest,\n ): Promise<StudioMediaResponse> {\n const res = await this.client.request<{ data: StudioMediaResponse }>(\n \"POST\",\n this.path(productionId, \"/voice\"),\n { body: input },\n )\n return res.data\n }\n\n /**\n * Recast the voices of a shot's active clip. Minutes of work, so it answers\n * `jobId` and the new clip lands as a result through its own marker.\n */\n async revoice(\n productionId: string,\n input: StudioRevoiceRequest,\n ): Promise<StudioJobStartedResponse> {\n const res = await this.client.request<{ data: StudioJobStartedResponse }>(\n \"POST\",\n this.path(productionId, \"/revoice\"),\n { body: input },\n )\n return res.data\n }\n\n /** Score the film. The finished track lands through its pending marker. */\n async music(\n productionId: string,\n input: StudioMusicRequest,\n ): Promise<StudioJobStartedResponse> {\n const res = await this.client.request<{ data: StudioJobStartedResponse }>(\n \"POST\",\n this.path(productionId, \"/music\"),\n { body: input },\n )\n return res.data\n }\n\n // ── audience and copies ──────────────────────────────────────────────────\n\n /**\n * Open the share-by-link read. Deliberately its own route rather than an\n * operation: who may see the work is decided by the owner, never as a side\n * effect of a batch that was editing something else.\n */\n async share(productionId: string): Promise<StudioProduction> {\n const res = await this.client.request<{ data: StudioMediaResponse }>(\n \"POST\",\n this.path(productionId, \"/share\"),\n { body: { shared: true } },\n )\n return res.data.production\n }\n\n /** Close it again. Sharing is opt-in AND reversible. */\n async unshare(productionId: string): Promise<StudioProduction> {\n const res = await this.client.request<{ data: StudioMediaResponse }>(\n \"POST\",\n this.path(productionId, \"/unshare\"),\n )\n return res.data.production\n }\n\n /**\n * Copy a production you own or can see into your own Studio project. The\n * copy starts PRIVATE and visible — sharing and archiving never travel — and\n * it is copied through YOUR view of the source, so somebody else's bin does\n * not come with it.\n */\n async clone(\n productionId: string,\n input: StudioCloneRequest = {},\n ): Promise<StudioProduction> {\n const res = await this.client.request<{ data: { production: StudioProduction } }>(\n \"POST\",\n this.path(productionId, \"/clone\"),\n { body: input },\n )\n return res.data.production\n }\n}\n\n","import type { NodaroClientCore } from \"../core.js\"\nimport { StudioProductionsResource } from \"./studio-productions.js\"\nexport * from \"./studio-productions.js\"\n\n/** Public response/transport contracts only; document validation and planning\n * remain in the private Studio codec on the server. */\nexport type StudioDocumentJson = Record<string, unknown>\n\nexport interface StudioProductionCapabilities {\n planVersions: number[]\n operations: {\n readKeyframes: boolean\n saveEditorState?: boolean\n editableSharedCopies?: boolean\n revisionedSharing?: boolean\n cloneLinkedProductions?: boolean\n importPlannedBundles?: boolean\n importLinkedBundles?: boolean\n appendPlannedBundles?: boolean\n appendLinkedBundles?: boolean\n editKeyframes: boolean\n generateKeyframes: boolean\n acceptKeyframes: boolean\n rejectKeyframes?: boolean\n editSequencePlans?: boolean\n generateLinkedClips: boolean\n retakeLinkedClips?: boolean\n /** The host keeps a scene's empty media slots. */\n mediaSlots?: boolean\n /** The host keeps a clip's inputs on its clip slot. */\n clipSlotInputs?: boolean\n }\n sourceFrameReferences: boolean\n automaticAcceptance: false\n unattendedGeneration: false\n}\n\nexport interface StudioKeyframeRecord {\n id: string\n label: string\n revision: number\n nodeId: string\n parentKeyframeId?: string\n previewResultKey: string | null\n previewUrl: string | null\n acceptedResultKey: string | null\n acceptedUrl: string | null\n count: number\n pending: Array<{ jobId: string; startedAt: string }>\n /** Owner-only working state. Recorded acceptance is not an execution grant. */\n plan?: StudioDocumentJson\n acceptance?: StudioDocumentJson\n results?: StudioDocumentJson[]\n}\n\nexport interface StudioProductionRecord {\n id: string\n name: string\n version: number\n updatedAt: string\n thumbnailUrl: string | null\n shared: boolean\n archived: boolean\n requiredCapabilities?: string[]\n keyframes?: StudioKeyframeRecord[]\n sequences?: StudioDocumentJson[]\n shots: StudioDocumentJson[]\n pending: { stills: number; clips: number; keyframes?: number; music: boolean; draft: StudioDocumentJson | null }\n [field: string]: unknown\n}\n\nexport interface StudioProductionReply {\n production: StudioProductionRecord\n capabilities?: StudioProductionCapabilities\n warnings?: unknown[]\n [field: string]: unknown\n}\n\nexport interface StudioEditInput {\n ops: ReadonlyArray<{ op: string; [field: string]: unknown }>\n baseVersion?: number\n strict?: boolean\n clientRequestId?: string\n}\n\nexport interface StudioKeyframeGenerationInput {\n keyframeId: string\n expectedRevision: number\n clientRequestId?: string\n overrides?: StudioDocumentJson\n}\n\nexport interface StudioKeyframeAcceptanceInput {\n keyframeId: string\n expectedRevision: number\n resultKey: string\n expectedAcceptedResultKey: string | null\n requirementChecks: Array<{ requirementId: string; outcome: \"pass\" | \"waived\" }>\n waivedReason?: string\n}\n\nexport interface StudioShotGenerationInput {\n kind: \"still\" | \"clip\"\n shotId: string\n clientRequestId?: string\n count?: number\n mode?: \"start\" | \"start-end\" | \"references\"\n dryRun?: boolean\n /** Linked clips only: require the exact inputs returned by a reviewed quote. */\n expectedInputHash?: string\n /** Retake a native linked take using its original request and retained endpoints. */\n retakeResultKey?: string\n overrides?: StudioDocumentJson\n}\n\nexport type StudioGenerationReply = {\n jobIds: string[]\n production?: StudioProductionRecord\n deduped?: true\n lane?: string\n [field: string]: unknown\n} | {\n dryRun: true; provider: string; count: number; credits: number | null; lane?: string\n /** Linked-clip quotes include normalized settings and accepted endpoint pins. */\n inputHash?: string\n endpointPins?: StudioDocumentJson\n creditIdentifier?: string\n duration?: number\n resolution?: string\n aspectRatio?: string\n sound?: boolean\n}\n\nconst root = \"/v1/studio/productions\"\nconst path = (id: string) => `${root}/${encodeURIComponent(id)}`\n\n/** Cloud plugin routes. Check capabilities before exposing dependency controls.\n * Reads do not reconcile jobs, submit media or accept generated candidates. */\nexport class StudioResource {\n readonly productions: StudioProductionsResource\n\n constructor(private readonly client: NodaroClientCore) {\n this.productions = new StudioProductionsResource(client)\n }\n\n capabilities(): Promise<{ data: StudioProductionCapabilities }> {\n return this.client.request(\"GET\", `${root}/capabilities`)\n }\n\n skill(): Promise<{ data: StudioDocumentJson }> {\n return this.client.request(\"GET\", `${root}/skill`)\n }\n\n list(options: { limit?: number; cursor?: string; includeArchived?: boolean } = {}): Promise<{ data: {\n data: Array<{ id: string; name: string; version: number; updatedAt: string; thumbnailUrl: string | null; shared: boolean; archived: boolean; shotCount: number }>\n nextCursor?: string\n } }> {\n return this.client.request(\"GET\", root, { query: options })\n }\n\n get(id: string, options: { detail?: \"summary\" | \"full\"; shotId?: string } = {}): Promise<{ data: StudioProductionReply }> {\n return this.client.request(\"GET\", path(id), { query: { detail: options.detail, shot_id: options.shotId } })\n }\n\n validatePlan(plan: StudioDocumentJson): Promise<{ data: { valid: boolean; errors: StudioDocumentJson[]; warnings: StudioDocumentJson[]; summary?: StudioDocumentJson } }> {\n return this.client.request(\"POST\", `${root}/validate`, { body: { plan } })\n }\n\n create(input: { name?: string; plan?: StudioDocumentJson }): Promise<{ data: StudioProductionReply }> {\n return this.client.request(\"POST\", root, { body: input })\n }\n\n /** Import a portable document through the compatible server writer.\n * Retained frame media requires an authorized source; acceptance never transfers. */\n importBundle(input: { bundle: StudioDocumentJson; projectId?: string }): Promise<{ data: StudioProductionReply }> {\n return this.client.request(\"POST\", `${root}/import-bundle`, { body: input })\n }\n\n /** Append a bundle's scenes and frame closure under an exact destination revision. */\n appendBundle(id: string, input: { bundle: StudioDocumentJson; expectedVersion: number;\n afterShotId?: string; applyFilm?: boolean }): Promise<{ data: {\n production: StudioProductionRecord; importedShotIds: string[]; importedKeyframeIds: string[];\n } }> {\n return this.client.request(\"POST\", `${path(id)}/import-bundle`, { body: input })\n }\n\n /** Copy a saved production. Linked copies retain verified inputs, remap\n * dependencies and require fresh frame acceptance; they start no media jobs. */\n clone(id: string, input: { name?: string; projectId?: string; expectedVersion?: number } = {}): Promise<{ data: StudioProductionReply }> {\n return this.client.request(\"POST\", `${path(id)}/clone`, { body: input })\n }\n\n edit(id: string, input: StudioEditInput): Promise<{ data: StudioProductionReply & { version: number; rebased: boolean; receipts: StudioDocumentJson[] } }> {\n return this.client.request(\"POST\", `${path(id)}/ops`, { body: input })\n }\n\n /** Audience-authorized sharing; an expected revision prevents publication\n * of concurrent edits the caller has not reviewed. */\n setShared(id: string, input: { shared: boolean; allowEditableCopy?: boolean; expectedVersion?: number }): Promise<{ data: StudioProductionReply }> {\n return this.client.request(\"POST\", `${path(id)}/share`, { body: input })\n }\n\n /** Save ordinary editor fields against the loaded revision. Protected frame\n * and job state can only change through their dedicated semantic actions. */\n saveEditorState(id: string, input: { expectedVersion: number; graph: object; clientRequestId?: string }) {\n return this.edit(id, {\n baseVersion: input.expectedVersion, strict: true,\n ...(input.clientRequestId ? { clientRequestId: input.clientRequestId } : {}),\n ops: [{ op: \"save_editor_state\", expectedVersion: input.expectedVersion, graph: input.graph }],\n })\n }\n\n generateKeyframe(id: string, input: StudioKeyframeGenerationInput): Promise<{ data: Exclude<StudioGenerationReply, { dryRun: true }> }> {\n return this.client.request(\"POST\", `${path(id)}/generate`, { body: { ...input, kind: \"keyframe\" } })\n }\n\n generateShot(id: string, input: StudioShotGenerationInput): Promise<{ data: StudioGenerationReply }> {\n return this.client.request(\"POST\", `${path(id)}/generate`, { body: input })\n }\n\n /** A separate explicit review action; generation never calls this method. */\n acceptKeyframe(id: string, input: StudioKeyframeAcceptanceInput,\n concurrency: Pick<StudioEditInput, \"baseVersion\" | \"strict\" | \"clientRequestId\"> = {}) {\n return this.edit(id, { ...concurrency, ops: [{ ...input, op: \"accept_keyframe_result\" }] })\n }\n\n reconcile(id: string): Promise<{ data: StudioProductionReply & { landed: string[]; pending: string[]; failed: string[]; version: number } }> {\n return this.client.request(\"POST\", `${path(id)}/reconcile`, { body: {} })\n }\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { throwFromResponse } from './chunk-JGS6YBDW.js';
1
+ import { throwFromResponse } from './chunk-L6T44A3G.js';
2
2
  import { WORKSPACE_HEADER } from '@nodaro/shared/organizations';
3
3
 
4
4
  // src/binary-response.ts
@@ -34,7 +34,7 @@ async function readBinaryResponse(response, maxBytes) {
34
34
  }
35
35
  return bytes.buffer;
36
36
  }
37
- var SDK_VERSION = "2.34.0" ;
37
+ var SDK_VERSION = "2.39.0" ;
38
38
  var CLIENT_HEADER = "X-Nodaro-Client";
39
39
  var isBrowser = () => typeof window !== "undefined" && typeof window.document !== "undefined";
40
40
  var NodaroClientCore = class {
@@ -224,5 +224,5 @@ function supabaseAuth(supabase) {
224
224
  }
225
225
 
226
226
  export { CallbackAuth, NodaroClientCore, StaticTokenAuth, supabaseAuth };
227
- //# sourceMappingURL=chunk-VFMWBW2Q.js.map
228
- //# sourceMappingURL=chunk-VFMWBW2Q.js.map
227
+ //# sourceMappingURL=chunk-NU4QSOMH.js.map
228
+ //# sourceMappingURL=chunk-NU4QSOMH.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/binary-response.ts","../src/core.ts","../src/auth.ts"],"names":[],"mappings":";;;;AACA,eAAsB,kBAAA,CAAmB,UAAoB,QAAA,EAAwC;AACnG,EAAA,MAAM,UAAA,GAAa,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,gBAAgB,CAAA;AACxD,EAAA,IAAI,UAAA,KAAe,IAAA,KAAS,CAAC,OAAA,CAAQ,IAAA,CAAK,UAAU,CAAA,IAAK,MAAA,CAAO,UAAU,CAAA,GAAI,QAAA,CAAA,EAAW;AACvF,IAAA,MAAM,QAAA,CAAS,MAAM,MAAA,EAAO;AAC5B,IAAA,MAAM,IAAI,MAAM,iDAAiD,CAAA;AAAA,EACnE;AACA,EAAA,IAAI,CAAC,QAAA,CAAS,IAAA,EAAM,OAAO,IAAI,YAAY,CAAC,CAAA;AAC5C,EAAA,MAAM,MAAA,GAAS,QAAA,CAAS,IAAA,CAAK,SAAA,EAAU;AACvC,EAAA,MAAM,SAAuB,EAAC;AAC9B,EAAA,IAAI,MAAA,GAAS,CAAA;AACb,EAAA,IAAI;AACF,IAAA,OAAO,IAAA,EAAM;AACX,MAAA,MAAM,IAAA,GAAO,MAAM,MAAA,CAAO,IAAA,EAAK;AAC/B,MAAA,IAAI,KAAK,IAAA,EAAM;AACf,MAAA,MAAA,IAAU,KAAK,KAAA,CAAM,UAAA;AACrB,MAAA,IAAI,SAAS,QAAA,EAAU;AACrB,QAAA,MAAM,OAAO,MAAA,EAAO;AACpB,QAAA,MAAM,IAAI,MAAM,iDAAiD,CAAA;AAAA,MACnE;AACA,MAAA,MAAA,CAAO,IAAA,CAAK,KAAK,KAAK,CAAA;AAAA,IACxB;AAAA,EACF,CAAA,SAAE;AAAU,IAAA,MAAA,CAAO,WAAA,EAAY;AAAA,EAAE;AACjC,EAAA,MAAM,KAAA,GAAQ,IAAI,UAAA,CAAW,MAAM,CAAA;AACnC,EAAA,IAAI,MAAA,GAAS,CAAA;AACb,EAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAAE,IAAA,KAAA,CAAM,GAAA,CAAI,OAAO,MAAM,CAAA;AAAG,IAAA,MAAA,IAAU,KAAA,CAAM,UAAA;AAAA,EAAW;AACnF,EAAA,OAAO,KAAA,CAAM,MAAA;AACf;ACAA,IAAM,WAAA,GAAoD,QAAA,CAAkB;AAUrE,IAAM,aAAA,GAAgB,iBAAA;AAoB7B,IAAM,YAAY,MAAe,OAAO,WAAW,WAAA,IAAe,OAAO,OAAO,QAAA,KAAa,WAAA;AA0FtF,IAAM,mBAAN,MAAuB;AAAA,EACnB,OAAA;AAAA,EACA,IAAA;AAAA,EACA,SAAA;AAAA;AAAA,EAEA,WAAA;AAAA;AAAA,EAEQ,gBAAA;AAAA,EACA,aAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQjB,IAAI,KAAA,GAAsB;AACxB,IAAA,OAAO,IAAA,CAAK,aAAA,IAAiB,UAAA,CAAW,KAAA,CAAM,KAAK,UAAU,CAAA;AAAA,EAC/D;AAAA;AAAA,EAGS,WAAA;AAAA,EAET,YAAY,IAAA,EAAqB;AAC/B,IAAA,IAAA,CAAK,OAAA,GAAU,IAAA,CAAK,OAAA,CAAQ,OAAA,CAAQ,OAAO,EAAE,CAAA;AAC7C,IAAA,IAAA,CAAK,OAAO,IAAA,CAAK,IAAA;AACjB,IAAA,IAAA,CAAK,gBAAgB,IAAA,CAAK,KAAA;AAC1B,IAAA,IAAA,CAAK,SAAA,GAAY,KAAK,SAAA,IAAa,GAAA;AACnC,IAAA,IAAA,CAAK,WAAA,GAAc,IAAA,CAAK,WAAA,IAAe,CAAA,IAAA,EAAO,WAAW,CAAA,CAAA;AACzD,IAAA,IAAA,CAAK,cAAc,IAAA,CAAK,WAAA;AAGxB,IAAA,IAAA,CAAK,gBAAA,GAAmB,IAAA,CAAK,WAAA,KAAgB,MAAA,IAAa,CAAC,SAAA,EAAU;AAAA,EACvE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAc,IAAA,CACZ,MAAA,EACA,IAAA,EACA,SACA,IAAA,EACY;AACZ,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,QAAA,CAAS,IAAA,EAAM,QAAQ,KAAK,CAAA;AAE7C,IAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,CAAK,IAAA,CAAK,QAAA,EAAS;AAKvC,IAAA,MAAM,UAAA,GACJ,OAAO,QAAA,KAAa,WAAA,IAAe,QAAQ,IAAA,YAAgB,QAAA;AAC7D,IAAA,MAAM,OAAA,GAAkC;AAAA,MACtC,GAAI,UAAA,GAAa,EAAC,GAAI,EAAE,gBAAgB,kBAAA,EAAmB;AAAA,MAC3D,GAAI,IAAA,CAAK,gBAAA,GAAmB,EAAE,CAAC,aAAa,GAAG,IAAA,CAAK,WAAA,EAAY,GAAI,EAAC;AAAA;AAAA;AAAA,MAGrE,GAAI,IAAA,CAAK,WAAA,GAAc,EAAE,CAAC,gBAAgB,GAAG,IAAA,CAAK,WAAA,EAAY,GAAI,EAAC;AAAA,MACnE,GAAI,OAAA,CAAQ,OAAA,IAAW;AAAC,KAC1B;AACA,IAAA,IAAI,KAAA,EAAO,OAAA,CAAQ,eAAe,CAAA,GAAI,UAAU,KAAK,CAAA,CAAA;AAErD,IAAA,MAAM,EAAA,GAAK,IAAI,eAAA,EAAgB;AAC/B,IAAA,MAAM,YAAY,UAAA,CAAW,MAAM,GAAG,KAAA,EAAM,EAAG,KAAK,SAAS,CAAA;AAC7D,IAAA,MAAM,QAAQ,MAAM,EAAA,CAAG,KAAA,CAAM,OAAA,CAAQ,QAAQ,MAAM,CAAA;AACnD,IAAA,OAAA,CAAQ,QAAQ,gBAAA,CAAiB,OAAA,EAAS,OAAO,EAAE,IAAA,EAAM,MAAM,CAAA;AAC/D,IAAA,IAAI,OAAA,CAAQ,MAAA,EAAQ,OAAA,EAAS,KAAA,EAAM;AAEnC,IAAA,IAAI;AACF,MAAA,EAAA,CAAG,OAAO,cAAA,EAAe;AACzB,MAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,KAAA,CAAM,GAAA,EAAK;AAAA,QAChC,MAAA;AAAA,QACA,OAAA;AAAA,QACA,IAAA,EACE,OAAA,CAAQ,IAAA,KAAS,KAAA,CAAA,GACb,KAAA,CAAA,GACA,UAAA,GACG,OAAA,CAAQ,IAAA,GACT,IAAA,CAAK,SAAA,CAAU,OAAA,CAAQ,IAAI,CAAA;AAAA,QACnC,QAAQ,EAAA,CAAG;AAAA,OACZ,CAAA;AAED,MAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,QAAA,IAAI,UAAmC,EAAC;AACxC,QAAA,IAAI;AACF,UAAA,OAAA,GAAU,MAAM,IAAI,IAAA,EAAK;AAAA,QAC3B,CAAA,CAAA,MAAQ;AAAA,QAER;AACA,QAAA,iBAAA,CAAkB,GAAA,CAAI,QAAQ,OAAO,CAAA;AAAA,MACvC;AAEA,MAAA,OAAO,MAAM,KAAK,GAAG,CAAA;AAAA,IACvB,CAAA,SAAE;AACA,MAAA,YAAA,CAAa,SAAS,CAAA;AACtB,MAAA,OAAA,CAAQ,MAAA,EAAQ,mBAAA,CAAoB,OAAA,EAAS,KAAK,CAAA;AAAA,IACpD;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,YAAA,CAAa,MAAA,EAAgB,IAAA,EAAc,OAAA,EAAsE;AACrH,IAAA,IAAI,CAAC,MAAA,CAAO,aAAA,CAAc,OAAA,CAAQ,QAAQ,CAAA,IAAK,OAAA,CAAQ,QAAA,GAAW,CAAA,EAAG,MAAM,IAAI,KAAA,CAAM,qCAAqC,CAAA;AAC1H,IAAA,OAAO,IAAA,CAAK,IAAA,CAAK,MAAA,EAAQ,IAAA,EAAM,OAAA,EAAS,CAAC,QAAA,KAAa,kBAAA,CAAmB,QAAA,EAAU,OAAA,CAAQ,QAAQ,CAAC,CAAA;AAAA,EACtG;AAAA,EAEA,MAAM,OAAA,CAAW,MAAA,EAAgB,IAAA,EAAc,OAAA,GAA0B,EAAC,EAAe;AACvF,IAAA,OAAO,IAAA,CAAK,IAAA;AAAA,MAAK,MAAA;AAAA,MAAQ,IAAA;AAAA,MAAM,OAAA;AAAA,MAAS,OAAO,GAAA;AAAA;AAAA,QAE7C,IAAI,MAAA,KAAW,GAAA,GAAO,MAAA,GAAoB,MAAM,IAAI,IAAA;AAAK;AAAA,KAC3D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,WAAA,CAAY,MAAA,EAAgB,IAAA,EAAc,OAAA,GAA0B,EAAC,EAAoB;AAC7F,IAAA,OAAO,IAAA,CAAK,KAAK,MAAA,EAAQ,IAAA,EAAM,SAAS,CAAC,GAAA,KAAQ,GAAA,CAAI,IAAA,EAAM,CAAA;AAAA,EAC7D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,MAAM,EAAA,GAA8C;AAClD,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,OAAA,CAAkD,OAAO,QAAQ,CAAA;AACxF,IAAA,OAAO,GAAA,CAAI,IAAA;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAM,aAAA,GAAyC;AAC7C,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,OAAA,CAAkC,OAAO,uBAAuB,CAAA;AACvF,IAAA,OAAO,GAAA,CAAI,IAAA;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,mBAAmB,eAAA,EAAwC;AAC/D,IAAA,MAAM,KAAK,OAAA,CAAQ,MAAA,EAAQ,yBAAyB,kBAAA,CAAmB,eAAe,CAAC,CAAA,OAAA,CAAS,CAAA;AAAA,EAClG;AAAA,EAEQ,QAAA,CAAS,MAAc,KAAA,EAAuE;AACpG,IAAA,MAAM,IAAA,GAAO,KAAK,OAAA,KAAY,OAAO,WAAW,WAAA,GAAc,MAAA,CAAO,SAAS,MAAA,GAAS,oBAAA,CAAA;AACvF,IAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,IAAA,EAAM,IAAI,CAAA;AAE9B,IAAA,MAAM,OAAA,GAAU,KAAK,OAAA,GAAU,GAAA,CAAI,UAAS,GAAI,GAAA,CAAI,WAAW,GAAA,CAAI,MAAA;AACnE,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,MAAM,IAAI,IAAI,GAAA,CAAI,KAAK,OAAA,GAAU,OAAA,GAAU,SAAS,IAAI,CAAA;AACxD,MAAA,KAAA,MAAW,CAAC,CAAA,EAAG,CAAC,KAAK,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,EAAG;AAC1C,QAAA,IAAI,CAAA,KAAM,QAAW,CAAA,CAAE,YAAA,CAAa,IAAI,CAAA,EAAG,MAAA,CAAO,CAAC,CAAC,CAAA;AAAA,MACtD;AACA,MAAA,OAAO,KAAK,OAAA,GAAU,CAAA,CAAE,UAAS,GAAI,CAAA,CAAE,WAAW,CAAA,CAAE,MAAA;AAAA,IACtD;AACA,IAAA,OAAO,OAAA;AAAA,EACT;AACF;;;ACjUO,IAAM,kBAAN,MAAsC;AAAA,EAC3C,YAAoB,KAAA,EAAe;AAAf,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA;AAAA,EAAgB;AAAA,EAAhB,KAAA;AAAA,EACpB,MAAM,QAAA,GAAW;AACf,IAAA,OAAO,IAAA,CAAK,KAAA;AAAA,EACd;AACF;AAEO,IAAM,eAAN,MAAmC;AAAA,EACxC,YAAoB,EAAA,EAAkD;AAAlD,IAAA,IAAA,CAAA,EAAA,GAAA,EAAA;AAAA,EAAmD;AAAA,EAAnD,EAAA;AAAA,EACpB,MAAM,QAAA,GAAW;AACf,IAAA,OAAO,KAAK,EAAA,EAAG;AAAA,EACjB;AACF;AASO,SAAS,aAAa,QAAA,EAAoC;AAC/D,EAAA,OAAO;AAAA,IACL,MAAM,QAAA,GAAW;AACf,MAAA,MAAM,EAAE,IAAA,EAAK,GAAI,MAAM,QAAA,CAAS,KAAK,UAAA,EAAW;AAChD,MAAA,OAAO,IAAA,CAAK,SAAS,YAAA,IAAgB,IAAA;AAAA,IACvC;AAAA,GACF;AACF","file":"chunk-VFMWBW2Q.js","sourcesContent":["/** Bound decoded response bytes even when Content-Length is absent or compressed. */\nexport async function readBinaryResponse(response: Response, maxBytes: number): Promise<ArrayBuffer> {\n const advertised = response.headers.get(\"content-length\")\n if (advertised !== null && (!/^\\d+$/.test(advertised) || Number(advertised) > maxBytes)) {\n await response.body?.cancel()\n throw new Error(\"Binary response exceeds its declared size limit\")\n }\n if (!response.body) return new ArrayBuffer(0)\n const reader = response.body.getReader()\n const chunks: Uint8Array[] = []\n let length = 0\n try {\n while (true) {\n const next = await reader.read()\n if (next.done) break\n length += next.value.byteLength\n if (length > maxBytes) {\n await reader.cancel()\n throw new Error(\"Binary response exceeds its declared size limit\")\n }\n chunks.push(next.value)\n }\n } finally { reader.releaseLock() }\n const bytes = new Uint8Array(length)\n let offset = 0\n for (const chunk of chunks) { bytes.set(chunk, offset); offset += chunk.byteLength }\n return bytes.buffer\n}\n","/**\n * The client core: configuration, auth, the request transport and the\n * account-identity calls — everything a resource needs, and none of the\n * resources themselves.\n *\n * {@link NodaroClient} (`createClient`) extends it with every resource. An app\n * that uses only a few resources can extend it with just those, so it loads\n * (and its tests depend on) only the resource modules it actually uses:\n *\n * class AppClient extends NodaroClientCore {\n * readonly jobs = new JobsResource(this)\n * readonly nodes = new NodesResource(this) // needs `jobs` on the same client\n * }\n *\n * A resource that calls another one through the client says so in its\n * constructor type (`NodesResource` takes a core that also has `jobs`), so a\n * client missing it fails to compile rather than at run time.\n */\nimport { readBinaryResponse } from \"./binary-response.js\"\nimport { throwFromResponse } from \"./errors.js\"\nimport type { Auth } from \"./auth.js\"\nimport type { DeveloperAppKind, DeveloperAppScope } from \"./resources/developer-apps.js\"\nimport { WORKSPACE_HEADER, type MeOrganizations } from \"@nodaro/shared/organizations\"\n\n/** Replaced at build time by tsup `define` from package.json. The fallback\n * keeps `tsx`/vitest runs of the source working, where no define applies. */\ndeclare const __SDK_VERSION__: string | undefined\nconst SDK_VERSION = typeof __SDK_VERSION__ === \"string\" ? __SDK_VERSION__ : \"0.0.0-dev\"\n\n/**\n * Identifies the calling package to the backend, which records it as the job's\n * provenance (`jobs.source` / `source_detail`) so an operator can tell a CLI\n * run from an SDK integration from a browser session.\n *\n * Only `sdk/…` and `cli/…` are honoured server-side; anything else is ignored\n * rather than trusted, since this is an unauthenticated header.\n */\nexport const CLIENT_HEADER = \"X-Nodaro-Client\"\n\n/**\n * In a browser the header is redundant AND a liability, so it is not sent.\n *\n * Redundant: the browser already sends `Origin`, which names the actual product\n * (`studio.nodaro.ai`) rather than merely the library it used — and the backend\n * deliberately prefers Origin over this header, so a browser-sent value is\n * discarded on arrival.\n *\n * A liability: `X-Nodaro-Client` is not a CORS-safelisted request header, so a\n * browser sending it requires an exact match in the server's\n * `Access-Control-Allow-Headers`. Any deployment whose backend predates that\n * allowlist entry would fail the PREFLIGHT — breaking every API call from the\n * app, not just its provenance. Self-hosted and lagging deployments make that a\n * real risk, and nothing in a browser app would reveal the cause.\n *\n * An EXPLICIT `clientLabel` is always sent regardless: a caller that names\n * itself has opted in deliberately, and that intent outranks this default.\n */\nconst isBrowser = (): boolean => typeof window !== \"undefined\" && typeof window.document !== \"undefined\"\n\nexport interface ClientOptions {\n /** Backend base URL, e.g. \"https://nodaro.example.com\" or empty string for same-origin. */\n baseUrl: string\n /** Auth provider. Use StaticTokenAuth, supabaseAuth, or CallbackAuth. */\n auth: Auth\n /** Optional fetch override (for tests or custom transports). */\n fetch?: typeof fetch\n /** Default request timeout in ms. Default 60s. */\n timeoutMs?: number\n /**\n * Overrides the `X-Nodaro-Client` label. Defaults to `sdk/<version>`.\n *\n * Exists for `@nodaro/cli`, which is a wrapper AROUND this SDK: without an\n * override every CLI invocation would be recorded as an SDK call and the two\n * surfaces could never be told apart.\n */\n clientLabel?: string\n /**\n * The workspace every request acts in — sent as `X-Nodaro-Workspace`.\n *\n * It selects which workspace a LIST reads from and where a CREATE lands.\n * It never authorizes: reading, updating, deleting or running an\n * identified object is decided by that object's own workspace, so a\n * forgotten header cannot hide work and a forged one cannot reach anyone\n * else's. Omit it to work in the caller's personal space.\n *\n * Prefer {@link NodaroClient.withWorkspace} for anything short-lived — one\n * client per workspace, no shared mutable selection to get wrong.\n */\n workspaceId?: string\n}\n\ninterface RequestOptions {\n body?: unknown\n query?: Record<string, string | number | boolean | undefined>\n headers?: Record<string, string>\n signal?: AbortSignal\n}\n\n/**\n * The authenticated user's canonical identity (`GET /v1/me`). A token-\n * introspection primitive: any valid bearer token (first-party Supabase JWT or\n * a developer-app OAuth token) resolves to its owner's identity. Mirrors the\n * `profiles` identity columns server-side — the route is the source of truth.\n */\nexport interface UserIdentity {\n /** Nodaro user id (= the Supabase auth user id). */\n readonly id: string\n readonly email: string\n /** Human-readable display name (from `profiles.full_name`); `null` if unset. */\n readonly displayName: string | null\n /** Avatar URL; `null` if unset. */\n readonly avatarUrl: string | null\n /** Subscription tier (e.g. \"free\", \"pro\"). */\n readonly tier: string\n /**\n * Whether the user holds an admin role. DESCRIPTIVE only — use it to decide\n * whether to render admin surfaces without capability-probing an admin\n * endpoint; every admin API stays enforced server-side regardless.\n */\n readonly isAdmin: boolean\n}\n\n/**\n * An app the user let into their account through OAuth (`GET\n * /v1/me/connected-apps`): a developer app, an AI assistant's MCP connector, or\n * a self-hosted install. One entry per grant still in force.\n */\nexport interface ConnectedApp {\n /** The grant's id — what {@link NodaroClient.revokeConnectedApp} takes. */\n readonly authorizationId: string\n /** The app's name; `null` if it has none. A `dynamic_mcp` client chose its own. */\n readonly name: string | null\n /**\n * How the app came to exist: `user` (a developer app someone registered),\n * `first_party_mcp`, `dynamic_mcp` (an MCP client that registered itself) or\n * `community_instance` (a self-hosted install).\n */\n readonly kind: DeveloperAppKind | (string & {})\n readonly homepageUrl: string | null\n /** The scopes this grant holds. */\n readonly scopes: readonly DeveloperAppScope[]\n /** When the user granted access (ISO 8601). */\n readonly connectedAt: string\n /** The latest use of any token issued under the grant; `null` if never used. */\n readonly lastUsedAt: string | null\n}\n\nexport class NodaroClientCore {\n readonly baseUrl: string\n readonly auth: Auth\n readonly timeoutMs: number\n /** Value sent as `X-Nodaro-Client`; recorded by the backend as job provenance. */\n readonly clientLabel: string\n /** Whether to actually send it — see the note on {@link CLIENT_HEADER}. */\n private readonly sendClientHeader: boolean\n private readonly fetchOverride: typeof fetch | undefined\n\n /**\n * Resolved lazily so consumers can swap `globalThis.fetch` after the\n * client has been constructed (e.g. test mocks). Always rebound to the\n * global object — native fetch throws \"Illegal invocation\" when its\n * `this` is anything else.\n */\n get fetch(): typeof fetch {\n return this.fetchOverride ?? globalThis.fetch.bind(globalThis)\n }\n\n /** The workspace this client acts in; undefined = the personal space. */\n readonly workspaceId: string | undefined\n\n constructor(opts: ClientOptions) {\n this.baseUrl = opts.baseUrl.replace(/\\/$/, \"\") // strip trailing slash\n this.auth = opts.auth\n this.fetchOverride = opts.fetch\n this.timeoutMs = opts.timeoutMs ?? 60_000\n this.clientLabel = opts.clientLabel ?? `sdk/${SDK_VERSION}`\n this.workspaceId = opts.workspaceId\n // Explicit label = deliberate opt-in, always sent. The default is suppressed\n // in browsers — see the note on CLIENT_HEADER.\n this.sendClientHeader = opts.clientLabel !== undefined || !isBrowser()\n }\n\n /**\n * The transport: build the request, send it, throw the typed error on a\n * non-2xx via {@link throwFromResponse}, then read the body via `read` — all\n * inside the abort timer, so `timeoutMs` bounds the body download too (a\n * stalled CSV stream aborts, it does not hang forever). Both the JSON path\n * ({@link request}) and the text path ({@link requestText}) go through here.\n */\n private async send<T>(\n method: string,\n path: string,\n options: RequestOptions,\n read: (res: Response) => Promise<T>,\n ): Promise<T> {\n const url = this.buildUrl(path, options.query)\n\n const token = await this.auth.getToken()\n // A `FormData` body is a multipart upload: let the runtime set\n // `Content-Type: multipart/form-data; boundary=…` itself (a manual JSON\n // content-type corrupts the boundary), and send the body as-is rather than\n // JSON-stringifying it. Every other body stays JSON, exactly as before.\n const isFormData =\n typeof FormData !== \"undefined\" && options.body instanceof FormData\n const headers: Record<string, string> = {\n ...(isFormData ? {} : { \"Content-Type\": \"application/json\" }),\n ...(this.sendClientHeader ? { [CLIENT_HEADER]: this.clientLabel } : {}),\n // Before per-request headers: a resource that needs to reach outside\n // this client's workspace says so explicitly and wins.\n ...(this.workspaceId ? { [WORKSPACE_HEADER]: this.workspaceId } : {}),\n ...(options.headers ?? {}),\n }\n if (token) headers[\"Authorization\"] = `Bearer ${token}`\n\n const ac = new AbortController()\n const timeoutId = setTimeout(() => ac.abort(), this.timeoutMs)\n const abort = () => ac.abort(options.signal?.reason)\n options.signal?.addEventListener(\"abort\", abort, { once: true })\n if (options.signal?.aborted) abort()\n\n try {\n ac.signal.throwIfAborted()\n const res = await this.fetch(url, {\n method,\n headers,\n body:\n options.body === undefined\n ? undefined\n : isFormData\n ? (options.body as FormData)\n : JSON.stringify(options.body),\n signal: ac.signal,\n })\n\n if (!res.ok) {\n let errBody: Record<string, unknown> = {}\n try {\n errBody = await res.json() as Record<string, unknown>\n } catch {\n // Empty/non-JSON body — fall through with empty errBody\n }\n throwFromResponse(res.status, errBody)\n }\n\n return await read(res)\n } finally {\n clearTimeout(timeoutId)\n options.signal?.removeEventListener(\"abort\", abort)\n }\n }\n\n /** Authenticated, bounded binary reads through the normal timeout/error transport. */\n async requestBytes(method: string, path: string, options: RequestOptions & { maxBytes: number }): Promise<ArrayBuffer> {\n if (!Number.isSafeInteger(options.maxBytes) || options.maxBytes < 1) throw new Error(\"maxBytes must be a positive integer\")\n return this.send(method, path, options, (response) => readBinaryResponse(response, options.maxBytes))\n }\n\n async request<T>(method: string, path: string, options: RequestOptions = {}): Promise<T> {\n return this.send(method, path, options, async (res) =>\n // 204 No Content\n res.status === 204 ? (undefined as T) : ((await res.json()) as T),\n )\n }\n\n /**\n * Like {@link request}, for endpoints that answer text (CSV exports). Errors\n * are still the JSON envelope and throw the same typed errors, and the read is\n * bounded by the same timeout as the request.\n */\n async requestText(method: string, path: string, options: RequestOptions = {}): Promise<string> {\n return this.send(method, path, options, (res) => res.text())\n }\n\n /**\n * `GET /v1/me` → the authenticated user's identity (see {@link UserIdentity}).\n * Unwraps the `{ data }` envelope. Throws `UnauthorizedError` (401) when the\n * token is missing/invalid, and the SDK's other typed errors as usual.\n *\n * On an instance with organizations it also carries what the caller belongs\n * to. THREE states, and collapsing them is wrong in a way users feel: the\n * organization fields ABSENT means this instance has no organizations at\n * all; present and empty means the account belongs to none; and\n * `organizationsUnavailable` means the lookup failed — keep whatever\n * selection you already had rather than concluding the person was removed\n * from everything.\n */\n async me(): Promise<UserIdentity & MeOrganizations> {\n const res = await this.request<{ data: UserIdentity & MeOrganizations }>(\"GET\", \"/v1/me\")\n return res.data\n }\n\n /**\n * `GET /v1/me/connected-apps` → every app with access to the signed-in\n * user's account (see {@link ConnectedApp}), newest grant first.\n *\n * **A signed-in browser session only.** The route answers a Supabase\n * session token (`supabaseAuth(…)`, `createSharedSupabaseClient`, or a\n * `StaticTokenAuth` holding one) and refuses every other credential with\n * `UnauthorizedError` (\"Sign in required\"): an app token or an API key must\n * not list the grants it lives under. Build your \"Connected apps\" settings\n * screen on this; a server-side integration cannot call it.\n */\n async connectedApps(): Promise<ConnectedApp[]> {\n const res = await this.request<{ apps: ConnectedApp[] }>(\"GET\", \"/v1/me/connected-apps\")\n return res.apps\n }\n\n /**\n * `POST /v1/me/connected-apps/:authorizationId/revoke` — ends an app's\n * access: the grant and every token issued under it, at once (the app's next\n * call is a 401). Resolves when done.\n *\n * A signed-in browser session only, like {@link connectedApps}. Throws\n * `NotFoundError` when the grant is not the user's or is already revoked.\n */\n async revokeConnectedApp(authorizationId: string): Promise<void> {\n await this.request(\"POST\", `/v1/me/connected-apps/${encodeURIComponent(authorizationId)}/revoke`)\n }\n\n private buildUrl(path: string, query?: Record<string, string | number | boolean | undefined>): string {\n const base = this.baseUrl || (typeof window !== \"undefined\" ? window.location.origin : \"http://placeholder\")\n const url = new URL(path, base)\n // If baseUrl was empty, strip the placeholder origin\n const fullUrl = this.baseUrl ? url.toString() : url.pathname + url.search\n if (query) {\n const u = new URL(this.baseUrl ? fullUrl : fullUrl, base)\n for (const [k, v] of Object.entries(query)) {\n if (v !== undefined) u.searchParams.set(k, String(v))\n }\n return this.baseUrl ? u.toString() : u.pathname + u.search\n }\n return fullUrl\n }\n}\n","/**\n * Auth provides the token used for `Authorization: Bearer <token>` on each request.\n * Implementations:\n * - StaticTokenAuth — fixed string (server-side, OAuth access token, API token)\n * - CallbackAuth — caller-supplied async function (BYO logic)\n * - supabaseAuth — pulls JWT from a Supabase client live (browser frontends)\n */\nexport interface Auth {\n /** Returns the current Bearer token, or null if not authenticated. */\n getToken(): Promise<string | null>\n}\n\nexport class StaticTokenAuth implements Auth {\n constructor(private token: string) {}\n async getToken() {\n return this.token\n }\n}\n\nexport class CallbackAuth implements Auth {\n constructor(private fn: () => string | null | Promise<string | null>) {}\n async getToken() {\n return this.fn()\n }\n}\n\ninterface SupabaseLikeClient {\n auth: {\n getSession(): Promise<{ data: { session: { access_token: string } | null } }>\n }\n}\n\n/** Pulls a JWT from a Supabase v2 client. Caller supplies their own supabase. */\nexport function supabaseAuth(supabase: SupabaseLikeClient): Auth {\n return {\n async getToken() {\n const { data } = await supabase.auth.getSession()\n return data.session?.access_token ?? null\n },\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/binary-response.ts","../src/core.ts","../src/auth.ts"],"names":[],"mappings":"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","file":"chunk-NU4QSOMH.js","sourcesContent":["/** Bound decoded response bytes even when Content-Length is absent or compressed. */\nexport async function readBinaryResponse(response: Response, maxBytes: number): Promise<ArrayBuffer> {\n const advertised = response.headers.get(\"content-length\")\n if (advertised !== null && (!/^\\d+$/.test(advertised) || Number(advertised) > maxBytes)) {\n await response.body?.cancel()\n throw new Error(\"Binary response exceeds its declared size limit\")\n }\n if (!response.body) return new ArrayBuffer(0)\n const reader = response.body.getReader()\n const chunks: Uint8Array[] = []\n let length = 0\n try {\n while (true) {\n const next = await reader.read()\n if (next.done) break\n length += next.value.byteLength\n if (length > maxBytes) {\n await reader.cancel()\n throw new Error(\"Binary response exceeds its declared size limit\")\n }\n chunks.push(next.value)\n }\n } finally { reader.releaseLock() }\n const bytes = new Uint8Array(length)\n let offset = 0\n for (const chunk of chunks) { bytes.set(chunk, offset); offset += chunk.byteLength }\n return bytes.buffer\n}\n","/**\n * The client core: configuration, auth, the request transport and the\n * account-identity calls — everything a resource needs, and none of the\n * resources themselves.\n *\n * {@link NodaroClient} (`createClient`) extends it with every resource. An app\n * that uses only a few resources can extend it with just those, so it loads\n * (and its tests depend on) only the resource modules it actually uses:\n *\n * class AppClient extends NodaroClientCore {\n * readonly jobs = new JobsResource(this)\n * readonly nodes = new NodesResource(this) // needs `jobs` on the same client\n * }\n *\n * A resource that calls another one through the client says so in its\n * constructor type (`NodesResource` takes a core that also has `jobs`), so a\n * client missing it fails to compile rather than at run time.\n */\nimport { readBinaryResponse } from \"./binary-response.js\"\nimport { throwFromResponse } from \"./errors.js\"\nimport type { Auth } from \"./auth.js\"\nimport type { DeveloperAppKind, DeveloperAppScope } from \"./resources/developer-apps.js\"\nimport { WORKSPACE_HEADER, type MeOrganizations } from \"@nodaro/shared/organizations\"\n\n/** Replaced at build time by tsup `define` from package.json. The fallback\n * keeps `tsx`/vitest runs of the source working, where no define applies. */\ndeclare const __SDK_VERSION__: string | undefined\nconst SDK_VERSION = typeof __SDK_VERSION__ === \"string\" ? __SDK_VERSION__ : \"0.0.0-dev\"\n\n/**\n * Identifies the calling package to the backend, which records it as the job's\n * provenance (`jobs.source` / `source_detail`) so an operator can tell a CLI\n * run from an SDK integration from a browser session.\n *\n * Only `sdk/…` and `cli/…` are honoured server-side; anything else is ignored\n * rather than trusted, since this is an unauthenticated header.\n */\nexport const CLIENT_HEADER = \"X-Nodaro-Client\"\n\n/**\n * In a browser the header is redundant AND a liability, so it is not sent.\n *\n * Redundant: the browser already sends `Origin`, which names the actual product\n * (`studio.nodaro.ai`) rather than merely the library it used — and the backend\n * deliberately prefers Origin over this header, so a browser-sent value is\n * discarded on arrival.\n *\n * A liability: `X-Nodaro-Client` is not a CORS-safelisted request header, so a\n * browser sending it requires an exact match in the server's\n * `Access-Control-Allow-Headers`. Any deployment whose backend predates that\n * allowlist entry would fail the PREFLIGHT — breaking every API call from the\n * app, not just its provenance. Self-hosted and lagging deployments make that a\n * real risk, and nothing in a browser app would reveal the cause.\n *\n * An EXPLICIT `clientLabel` is always sent regardless: a caller that names\n * itself has opted in deliberately, and that intent outranks this default.\n */\nconst isBrowser = (): boolean => typeof window !== \"undefined\" && typeof window.document !== \"undefined\"\n\nexport interface ClientOptions {\n /** Backend base URL, e.g. \"https://nodaro.example.com\" or empty string for same-origin. */\n baseUrl: string\n /** Auth provider. Use StaticTokenAuth, supabaseAuth, or CallbackAuth. */\n auth: Auth\n /** Optional fetch override (for tests or custom transports). */\n fetch?: typeof fetch\n /** Default request timeout in ms. Default 60s. */\n timeoutMs?: number\n /**\n * Overrides the `X-Nodaro-Client` label. Defaults to `sdk/<version>`.\n *\n * Exists for `@nodaro/cli`, which is a wrapper AROUND this SDK: without an\n * override every CLI invocation would be recorded as an SDK call and the two\n * surfaces could never be told apart.\n */\n clientLabel?: string\n /**\n * The workspace every request acts in — sent as `X-Nodaro-Workspace`.\n *\n * It selects which workspace a LIST reads from and where a CREATE lands.\n * It never authorizes: reading, updating, deleting or running an\n * identified object is decided by that object's own workspace, so a\n * forgotten header cannot hide work and a forged one cannot reach anyone\n * else's. Omit it to work in the caller's personal space.\n *\n * Prefer {@link NodaroClient.withWorkspace} for anything short-lived — one\n * client per workspace, no shared mutable selection to get wrong.\n */\n workspaceId?: string\n}\n\ninterface RequestOptions {\n body?: unknown\n query?: Record<string, string | number | boolean | undefined>\n headers?: Record<string, string>\n signal?: AbortSignal\n}\n\n/**\n * The authenticated user's canonical identity (`GET /v1/me`). A token-\n * introspection primitive: any valid bearer token (first-party Supabase JWT or\n * a developer-app OAuth token) resolves to its owner's identity. Mirrors the\n * `profiles` identity columns server-side — the route is the source of truth.\n */\nexport interface UserIdentity {\n /** Nodaro user id (= the Supabase auth user id). */\n readonly id: string\n readonly email: string\n /** Human-readable display name (from `profiles.full_name`); `null` if unset. */\n readonly displayName: string | null\n /** Avatar URL; `null` if unset. */\n readonly avatarUrl: string | null\n /** Subscription tier (e.g. \"free\", \"pro\"). */\n readonly tier: string\n /**\n * Whether the user holds an admin role. DESCRIPTIVE only — use it to decide\n * whether to render admin surfaces without capability-probing an admin\n * endpoint; every admin API stays enforced server-side regardless.\n */\n readonly isAdmin: boolean\n}\n\n/**\n * An app the user let into their account through OAuth (`GET\n * /v1/me/connected-apps`): a developer app, an AI assistant's MCP connector, or\n * a self-hosted install. One entry per grant still in force.\n */\nexport interface ConnectedApp {\n /** The grant's id — what {@link NodaroClient.revokeConnectedApp} takes. */\n readonly authorizationId: string\n /** The app's name; `null` if it has none. A `dynamic_mcp` client chose its own. */\n readonly name: string | null\n /**\n * How the app came to exist: `user` (a developer app someone registered),\n * `first_party_mcp`, `dynamic_mcp` (an MCP client that registered itself) or\n * `community_instance` (a self-hosted install).\n */\n readonly kind: DeveloperAppKind | (string & {})\n readonly homepageUrl: string | null\n /** The scopes this grant holds. */\n readonly scopes: readonly DeveloperAppScope[]\n /** When the user granted access (ISO 8601). */\n readonly connectedAt: string\n /** The latest use of any token issued under the grant; `null` if never used. */\n readonly lastUsedAt: string | null\n}\n\nexport class NodaroClientCore {\n readonly baseUrl: string\n readonly auth: Auth\n readonly timeoutMs: number\n /** Value sent as `X-Nodaro-Client`; recorded by the backend as job provenance. */\n readonly clientLabel: string\n /** Whether to actually send it — see the note on {@link CLIENT_HEADER}. */\n private readonly sendClientHeader: boolean\n private readonly fetchOverride: typeof fetch | undefined\n\n /**\n * Resolved lazily so consumers can swap `globalThis.fetch` after the\n * client has been constructed (e.g. test mocks). Always rebound to the\n * global object — native fetch throws \"Illegal invocation\" when its\n * `this` is anything else.\n */\n get fetch(): typeof fetch {\n return this.fetchOverride ?? globalThis.fetch.bind(globalThis)\n }\n\n /** The workspace this client acts in; undefined = the personal space. */\n readonly workspaceId: string | undefined\n\n constructor(opts: ClientOptions) {\n this.baseUrl = opts.baseUrl.replace(/\\/$/, \"\") // strip trailing slash\n this.auth = opts.auth\n this.fetchOverride = opts.fetch\n this.timeoutMs = opts.timeoutMs ?? 60_000\n this.clientLabel = opts.clientLabel ?? `sdk/${SDK_VERSION}`\n this.workspaceId = opts.workspaceId\n // Explicit label = deliberate opt-in, always sent. The default is suppressed\n // in browsers — see the note on CLIENT_HEADER.\n this.sendClientHeader = opts.clientLabel !== undefined || !isBrowser()\n }\n\n /**\n * The transport: build the request, send it, throw the typed error on a\n * non-2xx via {@link throwFromResponse}, then read the body via `read` — all\n * inside the abort timer, so `timeoutMs` bounds the body download too (a\n * stalled CSV stream aborts, it does not hang forever). Both the JSON path\n * ({@link request}) and the text path ({@link requestText}) go through here.\n */\n private async send<T>(\n method: string,\n path: string,\n options: RequestOptions,\n read: (res: Response) => Promise<T>,\n ): Promise<T> {\n const url = this.buildUrl(path, options.query)\n\n const token = await this.auth.getToken()\n // A `FormData` body is a multipart upload: let the runtime set\n // `Content-Type: multipart/form-data; boundary=…` itself (a manual JSON\n // content-type corrupts the boundary), and send the body as-is rather than\n // JSON-stringifying it. Every other body stays JSON, exactly as before.\n const isFormData =\n typeof FormData !== \"undefined\" && options.body instanceof FormData\n const headers: Record<string, string> = {\n ...(isFormData ? {} : { \"Content-Type\": \"application/json\" }),\n ...(this.sendClientHeader ? { [CLIENT_HEADER]: this.clientLabel } : {}),\n // Before per-request headers: a resource that needs to reach outside\n // this client's workspace says so explicitly and wins.\n ...(this.workspaceId ? { [WORKSPACE_HEADER]: this.workspaceId } : {}),\n ...(options.headers ?? {}),\n }\n if (token) headers[\"Authorization\"] = `Bearer ${token}`\n\n const ac = new AbortController()\n const timeoutId = setTimeout(() => ac.abort(), this.timeoutMs)\n const abort = () => ac.abort(options.signal?.reason)\n options.signal?.addEventListener(\"abort\", abort, { once: true })\n if (options.signal?.aborted) abort()\n\n try {\n ac.signal.throwIfAborted()\n const res = await this.fetch(url, {\n method,\n headers,\n body:\n options.body === undefined\n ? undefined\n : isFormData\n ? (options.body as FormData)\n : JSON.stringify(options.body),\n signal: ac.signal,\n })\n\n if (!res.ok) {\n let errBody: Record<string, unknown> = {}\n try {\n errBody = await res.json() as Record<string, unknown>\n } catch {\n // Empty/non-JSON body — fall through with empty errBody\n }\n throwFromResponse(res.status, errBody)\n }\n\n return await read(res)\n } finally {\n clearTimeout(timeoutId)\n options.signal?.removeEventListener(\"abort\", abort)\n }\n }\n\n /** Authenticated, bounded binary reads through the normal timeout/error transport. */\n async requestBytes(method: string, path: string, options: RequestOptions & { maxBytes: number }): Promise<ArrayBuffer> {\n if (!Number.isSafeInteger(options.maxBytes) || options.maxBytes < 1) throw new Error(\"maxBytes must be a positive integer\")\n return this.send(method, path, options, (response) => readBinaryResponse(response, options.maxBytes))\n }\n\n async request<T>(method: string, path: string, options: RequestOptions = {}): Promise<T> {\n return this.send(method, path, options, async (res) =>\n // 204 No Content\n res.status === 204 ? (undefined as T) : ((await res.json()) as T),\n )\n }\n\n /**\n * Like {@link request}, for endpoints that answer text (CSV exports). Errors\n * are still the JSON envelope and throw the same typed errors, and the read is\n * bounded by the same timeout as the request.\n */\n async requestText(method: string, path: string, options: RequestOptions = {}): Promise<string> {\n return this.send(method, path, options, (res) => res.text())\n }\n\n /**\n * `GET /v1/me` → the authenticated user's identity (see {@link UserIdentity}).\n * Unwraps the `{ data }` envelope. Throws `UnauthorizedError` (401) when the\n * token is missing/invalid, and the SDK's other typed errors as usual.\n *\n * On an instance with organizations it also carries what the caller belongs\n * to. THREE states, and collapsing them is wrong in a way users feel: the\n * organization fields ABSENT means this instance has no organizations at\n * all; present and empty means the account belongs to none; and\n * `organizationsUnavailable` means the lookup failed — keep whatever\n * selection you already had rather than concluding the person was removed\n * from everything.\n */\n async me(): Promise<UserIdentity & MeOrganizations> {\n const res = await this.request<{ data: UserIdentity & MeOrganizations }>(\"GET\", \"/v1/me\")\n return res.data\n }\n\n /**\n * `GET /v1/me/connected-apps` → every app with access to the signed-in\n * user's account (see {@link ConnectedApp}), newest grant first.\n *\n * **A signed-in browser session only.** The route answers a Supabase\n * session token (`supabaseAuth(…)`, `createSharedSupabaseClient`, or a\n * `StaticTokenAuth` holding one) and refuses every other credential with\n * `UnauthorizedError` (\"Sign in required\"): an app token or an API key must\n * not list the grants it lives under. Build your \"Connected apps\" settings\n * screen on this; a server-side integration cannot call it.\n */\n async connectedApps(): Promise<ConnectedApp[]> {\n const res = await this.request<{ apps: ConnectedApp[] }>(\"GET\", \"/v1/me/connected-apps\")\n return res.apps\n }\n\n /**\n * `POST /v1/me/connected-apps/:authorizationId/revoke` — ends an app's\n * access: the grant and every token issued under it, at once (the app's next\n * call is a 401). Resolves when done.\n *\n * A signed-in browser session only, like {@link connectedApps}. Throws\n * `NotFoundError` when the grant is not the user's or is already revoked.\n */\n async revokeConnectedApp(authorizationId: string): Promise<void> {\n await this.request(\"POST\", `/v1/me/connected-apps/${encodeURIComponent(authorizationId)}/revoke`)\n }\n\n private buildUrl(path: string, query?: Record<string, string | number | boolean | undefined>): string {\n const base = this.baseUrl || (typeof window !== \"undefined\" ? window.location.origin : \"http://placeholder\")\n const url = new URL(path, base)\n // If baseUrl was empty, strip the placeholder origin\n const fullUrl = this.baseUrl ? url.toString() : url.pathname + url.search\n if (query) {\n const u = new URL(this.baseUrl ? fullUrl : fullUrl, base)\n for (const [k, v] of Object.entries(query)) {\n if (v !== undefined) u.searchParams.set(k, String(v))\n }\n return this.baseUrl ? u.toString() : u.pathname + u.search\n }\n return fullUrl\n }\n}\n","/**\n * Auth provides the token used for `Authorization: Bearer <token>` on each request.\n * Implementations:\n * - StaticTokenAuth — fixed string (server-side, OAuth access token, API token)\n * - CallbackAuth — caller-supplied async function (BYO logic)\n * - supabaseAuth — pulls JWT from a Supabase client live (browser frontends)\n */\nexport interface Auth {\n /** Returns the current Bearer token, or null if not authenticated. */\n getToken(): Promise<string | null>\n}\n\nexport class StaticTokenAuth implements Auth {\n constructor(private token: string) {}\n async getToken() {\n return this.token\n }\n}\n\nexport class CallbackAuth implements Auth {\n constructor(private fn: () => string | null | Promise<string | null>) {}\n async getToken() {\n return this.fn()\n }\n}\n\ninterface SupabaseLikeClient {\n auth: {\n getSession(): Promise<{ data: { session: { access_token: string } | null } }>\n }\n}\n\n/** Pulls a JWT from a Supabase v2 client. Caller supplies their own supabase. */\nexport function supabaseAuth(supabase: SupabaseLikeClient): Auth {\n return {\n async getToken() {\n const { data } = await supabase.auth.getSession()\n return data.session?.access_token ?? null\n },\n }\n}\n"]}
@@ -16,5 +16,5 @@ var PromptHelperResource = class {
16
16
  };
17
17
 
18
18
  export { PromptHelperResource };
19
- //# sourceMappingURL=chunk-E2ZXHS6E.js.map
20
- //# sourceMappingURL=chunk-E2ZXHS6E.js.map
19
+ //# sourceMappingURL=chunk-OIPPTBW4.js.map
20
+ //# sourceMappingURL=chunk-OIPPTBW4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/resources/prompt-helper.ts"],"names":[],"mappings":";AAuEO,IAAM,uBAAN,MAA2B;AAAA,EAChC,YAAoB,MAAA,EAA0B;AAA1B,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AAAA,EAA2B;AAAA,EAA3B,MAAA;AAAA,EAEpB,QAAQ,KAAA,EAA6C;AACnD,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQ,MAAA,EAAQ,0BAAA,EAA4B,EAAE,IAAA,EAAM,EAAE,MAAA,EAAQ,SAAA,EAAW,GAAG,KAAA,IAAS,CAAA;AAAA,EAC1G;AAAA,EAEA,SAAS,KAAA,EAA6C;AACpD,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQ,MAAA,EAAQ,0BAAA,EAA4B,EAAE,IAAA,EAAM,EAAE,MAAA,EAAQ,UAAA,EAAY,GAAG,KAAA,IAAS,CAAA;AAAA,EAC3G;AAAA,EAEA,QAAQ,KAAA,EAA4C;AAClD,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQ,MAAA,EAAQ,0BAAA,EAA4B,EAAE,IAAA,EAAM,EAAE,MAAA,EAAQ,SAAA,EAAW,GAAG,KAAA,IAAS,CAAA;AAAA,EAC1G;AACF","file":"chunk-OIPPTBW4.js","sourcesContent":["import type { NodaroClientCore } from \"../core.js\"\nimport type { WizardQuestion, WizardSelection, RecommendedModel, WizardNodeContext } from \"@nodaro/prompts/doctrine\"\nexport type { WizardQuestion, WizardOption, WizardSelection, RecommendedModel, WizardNodeContext } from \"@nodaro/prompts/doctrine\"\n\n// Re-export the canonical wizard types (SSOT in @nodaro/shared).\n\ninterface CommonInput {\n nodeType: string\n provider?: string\n style?: string\n aspectRatio?: string\n duration?: number\n llmModel?: string\n /** Reasoning effort level (model-dependent). */\n reasoningEffort?: string\n /**\n * Gemini and Claude models. Runs the request on the provider's own API so\n * `temperature`, `maxTokens` and the full reasoning range actually take\n * effect — on the default lane those levers are not reliably honoured.\n * The call is charged its actual usage at the vendor's direct rate (the price key ends `:direct`), so\n * it usually costs more than the default lane; where the server prices LLM calls by tier instead, it\n * bills one credit rung up (a premium model moves to premium-direct). A model without a direct lane returns\n * `400 advanced_mode_unsupported`.\n */\n advancedMode?: boolean\n /** Sampling temperature. Only honoured when `advancedMode` is true. */\n temperature?: number\n /** Output token cap. Only honoured when `advancedMode` is true. */\n maxTokens?: number\n nodeContext?: WizardNodeContext\n userPreference?: string\n /** Associates this call with a workflow execution. Read server-side before Zod. */\n workflowId?: string\n}\n\nexport interface AnalyzeInput extends CommonInput {\n /** The user's rough idea. Omit to build questions from scratch. */\n prompt?: string\n}\nexport interface AnalyzeResult {\n jobId: string\n questions: WizardQuestion[]\n}\n\nexport interface GenerateInput extends CommonInput {\n /** The chosen answers from analyze. */\n selections: WizardSelection[]\n /** The user's original rough idea, woven into the generated prompt. */\n originalPrompt?: string\n}\n\nexport interface EnhanceInput extends CommonInput {\n /** The rough idea to improve one-shot. Omit to build from scratch. */\n prompt?: string\n}\n\nexport interface PromptResult {\n jobId: string\n prompt: string\n recommendedModel?: RecommendedModel\n}\n\n/**\n * AI Prompt Wizard — help write/improve prompts for generation nodes.\n *\n * - `analyze` -> guided questions, `generate` -> prompt from selections (the\n * 2-step human flow), or `enhance` -> one-shot \"improve this prompt\".\n *\n * All three delegate to `POST /v1/prompt-helper/wizard`. Throws `NodaroError`\n * on 4xx/5xx (e.g. `validation_error`, `malformed_response`).\n */\nexport class PromptHelperResource {\n constructor(private client: NodaroClientCore) {}\n\n analyze(input: AnalyzeInput): Promise<AnalyzeResult> {\n return this.client.request(\"POST\", \"/v1/prompt-helper/wizard\", { body: { action: \"analyze\", ...input } })\n }\n\n generate(input: GenerateInput): Promise<PromptResult> {\n return this.client.request(\"POST\", \"/v1/prompt-helper/wizard\", { body: { action: \"generate\", ...input } })\n }\n\n enhance(input: EnhanceInput): Promise<PromptResult> {\n return this.client.request(\"POST\", \"/v1/prompt-helper/wizard\", { body: { action: \"enhance\", ...input } })\n }\n}\n"]}
@@ -78,5 +78,5 @@ var AppsResource = class {
78
78
  };
79
79
 
80
80
  exports.AppsResource = AppsResource;
81
- //# sourceMappingURL=chunk-DKEYSJCE.cjs.map
82
- //# sourceMappingURL=chunk-DKEYSJCE.cjs.map
81
+ //# sourceMappingURL=chunk-OIYMTGYN.cjs.map
82
+ //# sourceMappingURL=chunk-OIYMTGYN.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/resources/apps.ts"],"names":[],"mappings":";;;AAoPO,IAAM,eAAN,MAAmB;AAAA,EACxB,YAAoB,MAAA,EAA0B;AAA1B,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AAAA,EAA2B;AAAA,EAA3B,MAAA;AAAA;AAAA,EAGpB,IAAA,CAAK,MAAA,GAAyB,EAAC,EAA4B;AACzD,IAAA,MAAM,EAAA,GAAK,IAAI,eAAA,EAAgB;AAC/B,IAAA,IAAI,OAAO,MAAA,EAAQ,EAAA,CAAG,GAAA,CAAI,QAAA,EAAU,OAAO,MAAM,CAAA;AACjD,IAAA,IAAI,MAAA,CAAO,UAAU,MAAA,EAAW,EAAA,CAAG,IAAI,OAAA,EAAS,MAAA,CAAO,MAAA,CAAO,KAAK,CAAC,CAAA;AACpE,IAAA,IAAI,OAAO,MAAA,EAAQ,EAAA,CAAG,GAAA,CAAI,QAAA,EAAU,OAAO,MAAM,CAAA;AACjD,IAAA,IAAI,OAAO,QAAA,EAAU,EAAA,CAAG,GAAA,CAAI,UAAA,EAAY,OAAO,QAAQ,CAAA;AACvD,IAAA,MAAM,KAAA,GAAQ,GAAG,QAAA,EAAS;AAC1B,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQ,KAAA,EAAO,CAAA,eAAA,EAAkB,QAAQ,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,GAAK,EAAE,CAAA,CAAE,CAAA;AAAA,EAChF;AAAA;AAAA,EAGA,IAAI,IAAA,EAAqD;AACvD,IAAA,OAAO,IAAA,CAAK,OAAO,OAAA,CAAQ,KAAA,EAAO,WAAW,kBAAA,CAAmB,IAAI,CAAC,CAAA,CAAE,CAAA;AAAA,EACzE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IACE,IAAA,EACA,MAAA,GAAkC,EAAC,EACnC,IAAA,GAAsB,EAAC,EACA;AACvB,IAAA,OAAO,IAAA,CAAK,OAAO,OAAA,CAAQ,MAAA,EAAQ,WAAW,kBAAA,CAAmB,IAAI,CAAC,CAAA,IAAA,CAAA,EAAQ;AAAA,MAC5E,IAAA,EAAM,EAAE,MAAA,EAAQ,GAAI,IAAA,CAAK,cAAA,GAAiB,EAAE,cAAA,EAAgB,IAAA,CAAK,cAAA,EAAe,GAAI,EAAC;AAAG,KACzF,CAAA;AAAA,EACH;AAAA;AAAA,EAGA,QAAA,CAAS,IAAA,EAAc,MAAA,GAA4B,EAAC,EAA4D;AAC9G,IAAA,MAAM,EAAA,GAAK,IAAI,eAAA,EAAgB;AAC/B,IAAA,IAAI,MAAA,CAAO,UAAU,MAAA,EAAW,EAAA,CAAG,IAAI,OAAA,EAAS,MAAA,CAAO,MAAA,CAAO,KAAK,CAAC,CAAA;AACpE,IAAA,IAAI,OAAO,MAAA,EAAQ,EAAA,CAAG,GAAA,CAAI,QAAA,EAAU,OAAO,MAAM,CAAA;AACjD,IAAA,MAAM,KAAA,GAAQ,GAAG,QAAA,EAAS;AAC1B,IAAA,OAAO,KAAK,MAAA,CAAO,OAAA;AAAA,MACjB,KAAA;AAAA,MACA,CAAA,QAAA,EAAW,mBAAmB,IAAI,CAAC,QAAQ,KAAA,GAAQ,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,GAAK,EAAE,CAAA;AAAA,KACrE;AAAA,EACF;AAAA;AAAA,EAGA,MAAA,CAAO,MAAc,KAAA,EAA0C;AAC7D,IAAA,OAAO,KAAK,MAAA,CAAO,OAAA;AAAA,MACjB,KAAA;AAAA,MACA,WAAW,kBAAA,CAAmB,IAAI,CAAC,CAAA,MAAA,EAAS,kBAAA,CAAmB,KAAK,CAAC,CAAA;AAAA,KACvE;AAAA,EACF;AAAA,EAqBA,MAAA,CAAO,IAAA,EAAc,KAAA,EAAe,IAAA,GAA4B,EAAC,EAA6D;AAC5H,IAAA,OAAO,KAAK,MAAA,CAAO,OAAA;AAAA,MACjB,MAAA;AAAA,MACA,WAAW,kBAAA,CAAmB,IAAI,CAAC,CAAA,MAAA,EAAS,kBAAA,CAAmB,KAAK,CAAC,CAAA,OAAA,CAAA;AAAA,MACrE;AAAA,QACE,IAAA,EAAM;AAAA,UACJ,GAAI,IAAA,CAAK,MAAA,GAAS,EAAE,MAAA,EAAQ,IAAA,KAAS,EAAC;AAAA,UACtC,GAAI,KAAK,OAAA,KAAY,MAAA,GAAY,EAAE,OAAA,EAAS,IAAA,CAAK,OAAA,EAAQ,GAAI;AAAC;AAChE;AACF,KACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,SAAA,CAAU,MAAc,KAAA,EAA4C;AAClE,IAAA,OAAO,KAAK,MAAA,CAAO,OAAA;AAAA,MACjB,QAAA;AAAA,MACA,WAAW,kBAAA,CAAmB,IAAI,CAAC,CAAA,MAAA,EAAS,kBAAA,CAAmB,KAAK,CAAC,CAAA;AAAA,KACvE;AAAA,EACF;AACF","file":"chunk-OIYMTGYN.cjs","sourcesContent":["import type { NodaroClientCore } from \"../core.js\"\n\n/**\n * A published app — a workflow wrapped in a curated input/output presentation.\n * Returned by the public `/v1/apps/browse` endpoint.\n */\nexport interface PublishedApp {\n id: string\n slug: string\n name: string\n description?: string | null\n creatorId: string\n creatorName?: string | null\n thumbnailUrl?: string | null\n category?: string | null\n isFeatured?: boolean\n runCount?: number\n /** The listed price per run; when `perMinuteCredits` is above 0, its fixed part. */\n estimatedCredits?: number | null\n /** The listed price holds a metered LLM call's ESTIMATE (its model's typical\n * call, charged its actual usage per token): show it `~N`. Absent for a\n * fixed price, and on a deployment running the tier-pricing rollback. */\n estimatedCreditsIsEstimate?: true\n /**\n * Credits per minute of the recording the app is given, when its price\n * follows that recording's length: the price is `estimatedCredits` plus\n * this per minute. 0 or absent when the price does not depend on a\n * recording's length.\n */\n perMinuteCredits?: number\n /**\n * Credits for each item beyond the creator's saved items of a list input\n * the app's user fills: the price is the listed one plus this per further\n * item. 0 or absent when the app has no such input.\n */\n perItemCredits?: number\n /**\n * The listed price is a range: `estimatedCredits` (with `perMinuteCredits` /\n * `perItemCredits`) is \"from\" — the app's saved settings — and these are\n * \"up to\": the most a run can cost over the choices the app's user has (every\n * exposed field, at the creator's restricted values where set). Present only\n * when they differ from \"from\"; absent on an app published before the range\n * existed until its next publish.\n */\n maxEstimatedCredits?: number\n maxPerMinuteCredits?: number\n maxPerItemCredits?: number\n createdAt: string\n updatedAt: string\n}\n\nexport interface ListAppsParams {\n /** Substring search across app name + description. */\n search?: string\n /** Page size; backend caps at 50. */\n limit?: number\n /** Cursor token returned by the previous page. */\n cursor?: string\n /** Filter to a single category slug. */\n category?: string\n}\n\nexport interface ListAppsResult {\n data: PublishedApp[]\n nextCursor?: string | null\n}\n\n/**\n * App detail — includes the input schema (required + optional fields end users\n * fill in) and the output mapping (which workflow nodes produce which display\n * cards).\n */\nexport interface PublishedAppDetail extends PublishedApp {\n inputSchema: Record<string, unknown>\n outputs: Array<{ nodeId: string; label: string; type: string }>\n /**\n * The app run alone: the listed price less its Render final part (run and\n * charged separately) — fixed, per minute of the recording and per further\n * list item. Absent from a server that predates them; read the listed\n * `estimatedCredits` / `perMinuteCredits` / `perItemCredits` instead.\n */\n runEstimatedCredits?: number\n runPerMinuteCredits?: number\n runPerItemCredits?: number\n /**\n * Whether this server charges Edit Plan per started minute of the recording\n * (otherwise in 15/30/60/90/120/180-minute steps). Absent from a server that\n * predates it: read it as the steps.\n */\n editPlanPerMinute?: boolean\n}\n\nexport interface AppRunResult {\n /** The execution-id that was started — poll via client.executions.get(). */\n executionId: string\n status: \"pending\" | \"running\"\n /** App-run id (distinct from executionId — used by listRuns/getRun). */\n runId?: string\n}\n\nexport interface AppRun {\n id: string\n appSlug: string\n executionId: string\n status: \"pending\" | \"running\" | \"completed\" | \"failed\" | \"cancelled\"\n inputs: Record<string, unknown>\n outputs?: Array<{ nodeId: string; type: string; url?: string; text?: string }>\n startedAt: string\n finishedAt?: string | null\n}\n\nexport interface ListAppRunsParams {\n limit?: number\n cursor?: string\n}\n\n/**\n * Result of a soft-delete (archive) operation. The run is moved to the user's\n * archive in the Nodaro UI; restoration and permanent deletion are UI-only by\n * design — SDK / MCP / API delete callers can't accidentally destroy data.\n */\nexport interface DeleteAppRunResult {\n success: true\n archived: true\n}\n\n/** Advanced per-run options for `apps.run`. */\nexport interface RunAppOptions {\n /**\n * Raw node-data overrides keyed by node id → field → value, merged onto the\n * app's workflow for THIS run only. Reaches fields that are NOT exposed as app\n * inputs — e.g. `{ [nodeId]: { promptPrefix: \"…\", promptSuffix: \"…\" } }` to\n * wrap the end user's prompt with text they never see.\n */\n inputOverrides?: Record<string, Record<string, unknown>>\n}\n\n/** Options for `apps.resume` — the Retry of a failed app run. */\nexport interface ResumeAppRunOptions {\n /** Answer what the Retry would run and charge, and start nothing. */\n dryRun?: boolean\n /**\n * The app version you expect the Retry to run — the one starting over would\n * run. Absent: the app's latest. A run of another version is refused with\n * `app_run_version_changed`; send the run's own version (the refusal's\n * `runVersion`) to continue on it anyway.\n */\n version?: number\n}\n\n/** One step a Retry runs again. */\nexport interface AppRunResumeStep {\n nodeId: string\n type: string\n /** The node's label, or `null` when it has none. */\n label: string | null\n}\n\n/** What a Retry would do (`apps.resume(…, { dryRun: true })`); nothing is started. */\nexport interface AppRunResumePlan {\n runId: string\n /** The failed execution the Retry continues. */\n continuesExecutionId: string\n /** The app version the Retry runs (the run's own). */\n appVersion: number | null\n /** Every node the Retry runs, in graph order. */\n nodeIds: string[]\n /** The steps that run again. */\n steps: AppRunResumeStep[]\n /** What the Retry is expected to charge, the creator's fee included; `null` without credits. */\n estimatedCredits: number | null\n /** Clips handed back at no cost. */\n reusedClips: number\n /** Whether your balance and your app credits cover what the Retry holds while it runs; `null` without credits. */\n sufficient: boolean | null\n /** Your spendable balance; `null` without credits. */\n available: number | null\n /** Your app credits, present only when they are what stops the Retry (it would be refused `insufficient_app_credits`). */\n appCreditsAllowance?: number\n}\n\n/**\n * A Retry that started. `deduped: true` when a concurrent double press reached\n * the same Retry; a second call made while the first is pending is refused\n * with `already_running` (`AlreadyRunningError`) instead.\n */\nexport interface AppRunResumeResult {\n /** The Retry's execution — the run now points at it. Poll via client.executions.get(). */\n executionId: string\n runId: string\n status: \"pending\"\n /** Every node the Retry runs. */\n nodeIds: string[]\n /** `true` when a concurrent press had already started this Retry. */\n deduped?: true\n}\n\n/**\n * The `code` the server gives an `apps.resume` refusal. Nothing is written or\n * billed when a Retry is refused. How each arrives:\n * - `app_run_version_changed` as `AppRunVersionChangedError`;\n * - `already_running` as `AlreadyRunningError` (with the live `executionId`);\n * - `not_found` and `continuation_not_found` as `NotFoundError`, whose `code`\n * is always `not_found` (the server's message is kept);\n * - `insufficient_credits` and `insufficient_app_credits` as\n * `InsufficientCreditsError`, whose `code` is always `insufficient_credits`\n * (the server's message says which);\n * - the rest as `NodaroError` carrying this code.\n */\nexport type AppRunResumeRefusalCode =\n /** No such run of yours under this app. */\n | \"not_found\"\n /** The run's execution is not yours. */\n | \"continuation_not_found\"\n /** A malformed run id or body, or a component's run (continued by the run that called it). */\n | \"validation_error\"\n /** The app version the run ran is gone: start the run over. */\n | \"app_run_version_unavailable\"\n /** The app is on another version than the run ran: start over, or send `version` = the run's. */\n | \"app_run_version_changed\"\n /** The run's execution ran another workflow, or another version of it (rare). */\n | \"continuation_workflow_mismatch\"\n | \"continuation_version_mismatch\"\n /** The run did not fail (it completed or was stopped): start it over. */\n | \"continuation_not_failed\"\n /** The run is still running, a Retry of it is pending, or it was started again elsewhere. */\n | \"already_running\"\n /** Nothing is left to retry: every step completed (409), or the app runs no step (400). */\n | \"continuation_subset_required\"\n /** An input the run applied sets a field the app does not let a runner set. */\n | \"locked_field\"\n /**\n * The Retry would stop at a Preview with nobody to review it: retry it from the app page.\n * (The same refusal arrives under the other preview refusal codes when a review-on use-case\n * node holds the run; `isPreviewRefusalCode` in `@nodaro/shared/nodes` asks for all of them.)\n */\n | \"preview_review_required\"\n /** Your app credits cannot cover it. */\n | \"insufficient_app_credits\"\n /** Your balance cannot cover it. */\n | \"insufficient_credits\"\n /** Billing is briefly unavailable for a workspace run (503): try again shortly. */\n | \"billing_unavailable\"\n\nexport class AppsResource {\n constructor(private client: NodaroClientCore) {}\n\n /** List published apps. Public — no auth required for community apps. */\n list(params: ListAppsParams = {}): Promise<ListAppsResult> {\n const qs = new URLSearchParams()\n if (params.search) qs.set(\"search\", params.search)\n if (params.limit !== undefined) qs.set(\"limit\", String(params.limit))\n if (params.cursor) qs.set(\"cursor\", params.cursor)\n if (params.category) qs.set(\"category\", params.category)\n const query = qs.toString()\n return this.client.request(\"GET\", `/v1/apps/browse${query ? `?${query}` : \"\"}`)\n }\n\n /** Get one app's metadata + input schema by slug. */\n get(slug: string): Promise<{ data: PublishedAppDetail }> {\n return this.client.request(\"GET\", `/v1/app/${encodeURIComponent(slug)}`)\n }\n\n /**\n * Trigger an app run with the given input values. The keys in `inputs` must\n * match the app's input-schema field names (see `get(slug).inputSchema`).\n * `opts.inputOverrides` adds raw per-node overrides (see {@link RunAppOptions}).\n * Returns the execution-id for status polling via client.executions.get().\n */\n run(\n slug: string,\n inputs: Record<string, unknown> = {},\n opts: RunAppOptions = {},\n ): Promise<AppRunResult> {\n return this.client.request(\"POST\", `/v1/app/${encodeURIComponent(slug)}/run`, {\n body: { inputs, ...(opts.inputOverrides ? { inputOverrides: opts.inputOverrides } : {}) },\n })\n }\n\n /** List past runs for an app (the caller must own the app or the runs). */\n listRuns(slug: string, params: ListAppRunsParams = {}): Promise<{ data: AppRun[]; nextCursor?: string | null }> {\n const qs = new URLSearchParams()\n if (params.limit !== undefined) qs.set(\"limit\", String(params.limit))\n if (params.cursor) qs.set(\"cursor\", params.cursor)\n const query = qs.toString()\n return this.client.request(\n \"GET\",\n `/v1/app/${encodeURIComponent(slug)}/runs${query ? `?${query}` : \"\"}`,\n )\n }\n\n /** Get one app-run by id. */\n getRun(slug: string, runId: string): Promise<{ data: AppRun }> {\n return this.client.request(\n \"GET\",\n `/v1/app/${encodeURIComponent(slug)}/runs/${encodeURIComponent(runId)}`,\n )\n }\n\n /**\n * Retry a FAILED app run from where it stopped: only the steps it did not\n * complete run, and only those are charged; every step it completed hands\n * on its result. It runs the version the run ran, with the inputs the run\n * applied (it takes none of its own). The run's execution moves to the\n * Retry's.\n *\n * `{ dryRun: true }` answers what the Retry would run and charge\n * ({@link AppRunResumePlan}) and starts nothing — show it before a Retry.\n * Refusals are listed in {@link AppRunResumeRefusalCode}; to run with other\n * inputs or on the app's current version, start over with\n * `run(slug, inputs)` instead.\n *\n * @param slug The published app's slug.\n * @param runId The run's UUID (`AppRunResult.runId`, `AppRun.id`).\n */\n resume(slug: string, runId: string, opts: ResumeAppRunOptions & { dryRun: true }): Promise<{ data: AppRunResumePlan }>\n resume(slug: string, runId: string, opts?: ResumeAppRunOptions & { dryRun?: false }): Promise<AppRunResumeResult>\n resume(slug: string, runId: string, opts?: ResumeAppRunOptions): Promise<{ data: AppRunResumePlan } | AppRunResumeResult>\n resume(slug: string, runId: string, opts: ResumeAppRunOptions = {}): Promise<{ data: AppRunResumePlan } | AppRunResumeResult> {\n return this.client.request(\n \"POST\",\n `/v1/app/${encodeURIComponent(slug)}/runs/${encodeURIComponent(runId)}/resume`,\n {\n body: {\n ...(opts.dryRun ? { dryRun: true } : {}),\n ...(opts.version !== undefined ? { version: opts.version } : {}),\n },\n },\n )\n }\n\n /**\n * Archive (soft-delete) a published-app run. The run is hidden from the\n * default run list and can be restored or permanently deleted from the\n * archive view at https://app.nodaro.ai/archived-runs.\n *\n * @param slug The published app's slug (the last path segment of its URL).\n * @param runId The run's UUID.\n */\n deleteRun(slug: string, runId: string): Promise<DeleteAppRunResult> {\n return this.client.request(\n \"DELETE\",\n `/v1/app/${encodeURIComponent(slug)}/runs/${encodeURIComponent(runId)}`,\n )\n }\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkKNMW722T_cjs = require('./chunk-KNMW722T.cjs');
3
+ var chunkFRQJNGJS_cjs = require('./chunk-FRQJNGJS.cjs');
4
4
 
5
5
  // src/resources/copilot.ts
6
6
  var COPILOT_FRAME_TYPES = /* @__PURE__ */ new Set([
@@ -93,12 +93,12 @@ var CopilotResource = class {
93
93
  }),
94
94
  signal: opts.signal
95
95
  });
96
- for await (const value of chunkKNMW722T_cjs.readSseStream(res, { label: "copilot stream" })) {
96
+ for await (const value of chunkFRQJNGJS_cjs.readSseStream(res, { label: "copilot stream" })) {
97
97
  if (isCopilotFrame(value)) yield value;
98
98
  }
99
99
  }
100
100
  };
101
101
 
102
102
  exports.CopilotResource = CopilotResource;
103
- //# sourceMappingURL=chunk-NLQQHJ25.cjs.map
104
- //# sourceMappingURL=chunk-NLQQHJ25.cjs.map
103
+ //# sourceMappingURL=chunk-OSMKIRKI.cjs.map
104
+ //# sourceMappingURL=chunk-OSMKIRKI.cjs.map