@nodaro/sdk 2.56.0 → 2.57.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 (71) hide show
  1. package/dist/{chunk-3CVWTUK5.cjs → chunk-3Y5TDB5K.cjs} +4 -4
  2. package/dist/{chunk-3CVWTUK5.cjs.map → chunk-3Y5TDB5K.cjs.map} +1 -1
  3. package/dist/{chunk-2LOTDOUV.cjs → chunk-7PYZCNLH.cjs} +5 -5
  4. package/dist/{chunk-2LOTDOUV.cjs.map → chunk-7PYZCNLH.cjs.map} +1 -1
  5. package/dist/{chunk-FTCAT2LK.js → chunk-ALDXFMD7.js} +3 -3
  6. package/dist/{chunk-FTCAT2LK.js.map → chunk-ALDXFMD7.js.map} +1 -1
  7. package/dist/{chunk-OMJ45CW4.cjs → chunk-DOMNKVKA.cjs} +9 -9
  8. package/dist/{chunk-OMJ45CW4.cjs.map → chunk-DOMNKVKA.cjs.map} +1 -1
  9. package/dist/{chunk-WY4QRJZW.js → chunk-DTYN7QAZ.js} +25 -2
  10. package/dist/chunk-DTYN7QAZ.js.map +1 -0
  11. package/dist/{chunk-PQ6G5EM7.js → chunk-EDSODRRY.js} +9 -9
  12. package/dist/{chunk-PQ6G5EM7.js.map → chunk-EDSODRRY.js.map} +1 -1
  13. package/dist/{chunk-DFT4LD2H.cjs → chunk-GDUEOKBF.cjs} +4 -4
  14. package/dist/{chunk-DFT4LD2H.cjs.map → chunk-GDUEOKBF.cjs.map} +1 -1
  15. package/dist/{chunk-Z4B4SZ33.cjs → chunk-GSE7SB3I.cjs} +6 -4
  16. package/dist/chunk-GSE7SB3I.cjs.map +1 -0
  17. package/dist/{chunk-Q7W4QNE5.cjs → chunk-GWTKYJJO.cjs} +22 -22
  18. package/dist/{chunk-Q7W4QNE5.cjs.map → chunk-GWTKYJJO.cjs.map} +1 -1
  19. package/dist/{chunk-4VP2GFIZ.js → chunk-JJMQ2EVL.js} +6 -4
  20. package/dist/chunk-JJMQ2EVL.js.map +1 -0
  21. package/dist/{chunk-RIMDKJSQ.cjs → chunk-JX3GYLV3.cjs} +16 -16
  22. package/dist/{chunk-RIMDKJSQ.cjs.map → chunk-JX3GYLV3.cjs.map} +1 -1
  23. package/dist/{chunk-Q4MFQC2J.cjs → chunk-KU3UITCU.cjs} +5 -5
  24. package/dist/{chunk-Q4MFQC2J.cjs.map → chunk-KU3UITCU.cjs.map} +1 -1
  25. package/dist/{chunk-E6X6BGRO.js → chunk-MUHRK4OI.js} +3 -3
  26. package/dist/{chunk-E6X6BGRO.js.map → chunk-MUHRK4OI.js.map} +1 -1
  27. package/dist/{chunk-VEQLP5TA.js → chunk-ND7JMM5H.js} +3 -3
  28. package/dist/{chunk-VEQLP5TA.js.map → chunk-ND7JMM5H.js.map} +1 -1
  29. package/dist/{chunk-JTOEHQQJ.cjs → chunk-NOZWIS7M.cjs} +25 -2
  30. package/dist/chunk-NOZWIS7M.cjs.map +1 -0
  31. package/dist/{chunk-HK6XP5EN.js → chunk-RCD4HDBI.js} +3 -3
  32. package/dist/{chunk-HK6XP5EN.js.map → chunk-RCD4HDBI.js.map} +1 -1
  33. package/dist/{chunk-37LL6BPM.js → chunk-SOR6K3XZ.js} +4 -4
  34. package/dist/{chunk-37LL6BPM.js.map → chunk-SOR6K3XZ.js.map} +1 -1
  35. package/dist/{chunk-4WOT5OAY.cjs → chunk-TSM3S2QS.cjs} +5 -5
  36. package/dist/{chunk-4WOT5OAY.cjs.map → chunk-TSM3S2QS.cjs.map} +1 -1
  37. package/dist/{chunk-BGOZRZHY.js → chunk-VTL4DBX4.js} +3 -3
  38. package/dist/{chunk-BGOZRZHY.js.map → chunk-VTL4DBX4.js.map} +1 -1
  39. package/dist/{chunk-4FSWJTRS.js → chunk-YYMX3VN7.js} +3 -3
  40. package/dist/{chunk-4FSWJTRS.js.map → chunk-YYMX3VN7.js.map} +1 -1
  41. package/dist/entries/client.cjs +15 -15
  42. package/dist/entries/client.js +10 -10
  43. package/dist/entries/copilot.cjs +4 -4
  44. package/dist/entries/copilot.js +3 -3
  45. package/dist/entries/core.cjs +6 -6
  46. package/dist/entries/core.js +2 -2
  47. package/dist/entries/edit.cjs +7 -7
  48. package/dist/entries/edit.js +2 -2
  49. package/dist/entries/errors.cjs +26 -26
  50. package/dist/entries/errors.d.cts +12 -1
  51. package/dist/entries/errors.d.ts +12 -1
  52. package/dist/entries/errors.js +1 -1
  53. package/dist/entries/media.cjs +4 -4
  54. package/dist/entries/media.js +3 -3
  55. package/dist/entries/nodes.cjs +3 -3
  56. package/dist/entries/nodes.js +2 -2
  57. package/dist/entries/studio.cjs +5 -5
  58. package/dist/entries/studio.js +2 -2
  59. package/dist/entries/uploads.cjs +2 -2
  60. package/dist/entries/uploads.d.cts +41 -1
  61. package/dist/entries/uploads.d.ts +41 -1
  62. package/dist/entries/uploads.js +1 -1
  63. package/dist/index.cjs +53 -53
  64. package/dist/index.d.cts +1 -1
  65. package/dist/index.d.ts +1 -1
  66. package/dist/index.js +10 -10
  67. package/package.json +1 -1
  68. package/dist/chunk-4VP2GFIZ.js.map +0 -1
  69. package/dist/chunk-JTOEHQQJ.cjs.map +0 -1
  70. package/dist/chunk-WY4QRJZW.js.map +0 -1
  71. package/dist/chunk-Z4B4SZ33.cjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/resources/edit-use-case-inputs.ts","../src/resources/edit.ts"],"names":["isUseCaseNodeType","NodaroError","USE_CASE_NODE_TYPES","ForbiddenError","resolveEditPlanSources","describeAudioSyncOffsetIssue","transcriptSpeakerLabels","speakerMapResultOf","cameraSwitchSpeakerMap","edl","remapTranscriptThroughEdl"],"mappings":"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","file":"chunk-OMJ45CW4.cjs","sourcesContent":["/**\n * The inputs of the podcast use-case runs on the `edit` resource (Tighten\n * Episode, Chapters, Trailer, Clip Pack, Speaker Layout) and the request body each one sends.\n * Split from `edit.ts`, which holds the methods, the type list and the\n * continue routes; every name here is re-exported from there.\n */\nimport type { EditPlanTier, EdlTargetAspect, SpeakerEmphasisStyle, SpeakerSwitchId } from \"@nodaro/shared/edl\"\nimport type { CaptionStyle } from \"@nodaro/shared/captions\"\n\n/**\n * The recordings of a use-case run: one (`mediaUrl`), or the recordings of one\n * conversation (`mediaUrls`, in order — the cameras; one may be sound only),\n * an optional Master audio and the Cameras settings. Pass `mediaUrl` or\n * `mediaUrls`, not both.\n *\n * Several recordings or a Master audio need Speaker Map, which tells who is on\n * which camera: where it is not available to you (not yet on nodaro.ai) the\n * request is refused `403 node_not_available` — send one recording.\n */\nexport interface UseCaseRecordingsInput {\n /** The recording — a video or audio URL, up to 3 hours. */\n mediaUrl?: string\n /**\n * Instead of `mediaUrl`: the recordings of one conversation, in order — up\n * to six in all with the Master audio; without one, two or more cameras keep\n * a place for the sound, so up to five. With two or more the run lines them\n * up, works out who is on which camera and cuts to whoever is talking.\n */\n mediaUrls?: string[]\n /** The mixer or recorder track: the episode's sound and the clock the recordings are lined up to. */\n masterAudioUrl?: string\n /** With several recordings or a Master audio: the Cameras settings (ignored with one recording and no Master audio). */\n cameras?: {\n /** Which recording (1-based) is the wide shot, shown when a speaker has no camera of their own; `null` for none. */\n wide?: number | null\n /** The recordings already share one clock: skip lining them up. */\n synced?: boolean\n /** Who is on which camera: speaker number (`\"1\"` = the first voice heard) → recording number, 0 = the wide shot. Overrides the automatic map. */\n speakerCameras?: Record<string, number>\n }\n}\n\n/**\n * Input for {@link EditResource.tightenEpisode} and\n * {@link EditResource.estimateTightenEpisode}: the recording (or the\n * recordings of one conversation, see {@link UseCaseRecordingsInput}) in, the\n * tightened episode out. Only the recording is required; every other field\n * left out takes the node's default.\n */\nexport interface TightenEpisodeInput extends UseCaseRecordingsInput {\n /** Optional music bed, ducked under the voice and ending with the episode. */\n musicUrl?: string\n /** `\"video\"` or `\"audio\"`; an audio recording always makes an audio episode. */\n output?: \"video\" | \"audio\"\n /**\n * Frame a video episode with Speaker View: an output aspect and a layout,\n * over automatic boxes on the speakers on screen. A layout the aspect does\n * not draw is snapped to one it does. `null` or absent: no framing.\n */\n framing?: {\n aspect: EdlTargetAspect\n layout: \"auto\" | \"single\" | \"side-by-side\" | \"stacked\" | \"grid\" | \"pip\"\n } | null\n /**\n * With a framing, how it follows the speakers: `\"static\"` (the default)\n * splits the frame evenly by speaker; `\"tracking\"` follows faces with\n * Speaker Frames (charged per started block of 1,000 sampled frames; a\n * camera shared by several speakers keeps the even split until faces are\n * named; refused 403 where Speaker Frames is not available to the caller);\n * `\"auto\"` follows faces while Speaker Frames is available to the caller,\n * else the even split. Ignored without a framing.\n */\n framingSource?: \"auto\" | \"static\" | \"tracking\"\n /** Captions on a video episode (on by default). */\n captions?: boolean\n /** The captions' look. */\n captionStyle?: CaptionStyle\n /**\n * Stop at a quick preview for a person to review; render the full-quality\n * episode afterwards with {@link EditResource.continueUseCase}\n * (`mode: \"render-final\"`).\n */\n reviewBeforeRender?: boolean\n /** The planner's tier. */\n planTier?: EditPlanTier\n /** Editing instructions for the planner (up to 4 000 characters). */\n instructions?: string\n /** A style guide for the planner (up to 4 000 characters). */\n styleGuide?: string\n /** How far the music dips under the voice, 0–100 (default 75). */\n musicDuckAmount?: number\n}\n\n/**\n * Input for {@link EditResource.episodeChapters} and\n * {@link EditResource.estimateEpisodeChapters}: one recording in, its chapters\n * out. Only `mediaUrl` is required; every other field left out takes the\n * node's default.\n */\nexport interface EpisodeChaptersInput {\n /** The recording — a video or audio URL, up to 3 hours. */\n mediaUrl: string\n /** The planner's tier (default `\"economy\"`). */\n planTier?: EditPlanTier\n /** Instructions for the chapters, e.g. \"5 to 8 chapters\" (up to 4 000 characters). */\n instructions?: string\n /** A style guide for the chapter titles (up to 4 000 characters). */\n styleGuide?: string\n}\n\n/** The formats a Trailer is delivered in, in delivery order (16:9 is a 1920×1080 landscape). */\nexport const TRAILER_FORMATS = [\"9:16\", \"1:1\", \"4:5\", \"16:9\"] as const\n/** One Trailer format (see {@link TRAILER_FORMATS}). */\nexport type TrailerFormat = (typeof TRAILER_FORMATS)[number]\n\n/**\n * Input for {@link EditResource.episodeTrailer} and\n * {@link EditResource.estimateEpisodeTrailer}: one video recording (or the\n * recordings of one conversation, see {@link UseCaseRecordingsInput}) in, a\n * 20–40 s trailer out in each chosen format. Only the recording is required.\n */\nexport interface EpisodeTrailerInput extends UseCaseRecordingsInput {\n /** The recording — a video URL, up to 3 hours (a run with no picture is refused). Or `mediaUrls`. */\n mediaUrl?: string\n /** An optional intro card: a short video (15 s at most) played before the trailer. */\n introCardUrl?: string\n /** The formats to deliver, padded, never cropped (default `[\"9:16\", \"1:1\", \"4:5\"]`; an empty list is refused). */\n formats?: TrailerFormat[]\n /** Stop at a preview of the trailer; render every format with {@link EditResource.continueUseCase} (`mode: \"render-final\"`). */\n reviewBeforeRender?: boolean\n /** The planner's tier (default `\"standard\"`). */\n planTier?: EditPlanTier\n /** Instructions for the trailer (up to 4 000 characters). */\n instructions?: string\n /** A style guide for the planner (up to 4 000 characters). */\n styleGuide?: string\n}\n\n/** The shortest and longest clip a Clip Pack asks the plan for, in seconds. */\nexport const CLIP_PACK_MIN_TARGET_SEC = 5\nexport const CLIP_PACK_MAX_TARGET_SEC = 180\n\n/**\n * A Clip Pack emphasis: `\"none\"`, or one or more of `\"scale\"`, `\"border\"` and\n * `\"dim\"` joined with `\"+\"` (each once — the route refuses a repeat).\n */\nexport type ClipPackEmphasis = SpeakerEmphasisStyle | `${Exclude<SpeakerEmphasisStyle, \"none\">}+${string}`\n\n/**\n * Input for {@link EditResource.clipPack} and\n * {@link EditResource.estimateClipPack}: the recording (or the recordings of\n * one conversation, see {@link UseCaseRecordingsInput} — each clip then cuts\n * to whoever is talking) in, a pack of short clips out. An audio recording\n * makes audio clips (no framing, no captions). Only the recording is\n * required; every other field left out takes the node's default.\n */\nexport interface ClipPackInput extends UseCaseRecordingsInput {\n /** How many clips to find, 1–50 (default 8). The plan may find fewer. */\n count?: number\n /** Each clip's target length in seconds, {@link CLIP_PACK_MIN_TARGET_SEC}–{@link CLIP_PACK_MAX_TARGET_SEC} (default 60). */\n targetDurationSec?: number\n /**\n * Frame each video clip with Speaker View on automatic boxes over the\n * episode's speakers: the shape, and optionally the layout (default\n * `\"stacked\"`; one the shape does not draw is snapped), the switch at each\n * speaker change (default `\"pan\"`) and the emphasis (default `\"scale\"`;\n * `\"none\"`, or `\"scale\"`, `\"border\"` and `\"dim\"` joined with `\"+\"`). Left\n * out: 9:16, stacked, pan, scale. `null`: no framing (the recording's shape).\n */\n framing?: {\n aspect: EdlTargetAspect\n layout?: \"auto\" | \"single\" | \"side-by-side\" | \"stacked\" | \"grid\" | \"pip\"\n switchType?: SpeakerSwitchId\n emphasisStyle?: ClipPackEmphasis\n } | null\n /**\n * With a framing, how it follows the speakers: `\"static\"` splits the frame\n * evenly by speaker (what a request that leaves this out gets); `\"tracking\"`\n * runs Speaker Frames once over the whole pack to follow faces (charged per\n * started block of 1,000 sampled frames; refused 403 where Speaker Frames is\n * not available to the caller); `\"auto\"` follows faces while Speaker Frames\n * is available to the caller, else the even split. Ignored without a framing.\n */\n framingSource?: \"auto\" | \"static\" | \"tracking\"\n /** Caption each video clip (on by default). */\n captions?: boolean\n /** The captions' look (default `\"karaoke\"`). */\n captionStyle?: CaptionStyle\n /**\n * Stop at quick previews of the clips for a person to review; render the\n * kept clips at full quality with {@link EditResource.continueUseCase}\n * (`mode: \"render-final\"`, an `editedEdl` that keeps or drops clips).\n */\n reviewBeforeRender?: boolean\n /** The planner's tier (default `\"standard\"`). */\n planTier?: EditPlanTier\n /** Instructions for picking the clips (up to 4 000 characters). */\n instructions?: string\n /** A style guide for the planner (up to 4 000 characters). */\n styleGuide?: string\n}\n\n/**\n * Input for {@link EditResource.speakerLayout} and\n * {@link EditResource.estimateSpeakerLayout}: one video recording (or the\n * recordings of one conversation, see {@link UseCaseRecordingsInput}) in, the\n * whole recording framed by speaker out — the same length, nothing cut. Only\n * the recording is required; every other field left out takes the node's\n * default.\n */\nexport interface SpeakerLayoutInput extends UseCaseRecordingsInput {\n /** The recording — a video URL, up to 3 hours (an audio-only recording is refused). Or `mediaUrls`. */\n mediaUrl?: string\n /** The video's shape (default `\"9:16\"`). With one recording, a video already as narrow as the shape (or narrower) is refused `400 media_shape`. */\n targetAspect?: EdlTargetAspect\n /** How the speakers are laid out (default `\"stacked\"`; one the shape does not draw is snapped to one it does). */\n layout?: \"auto\" | \"single\" | \"side-by-side\" | \"stacked\" | \"grid\" | \"pip\"\n /** The switch at each speaker change (default `\"cut\"`). */\n switchType?: SpeakerSwitchId\n /** How the speaker talking is emphasised (default `\"scale\"`): `\"none\"`, or `\"scale\"`, `\"border\"` and `\"dim\"` joined with `\"+\"`. */\n emphasisStyle?: ClipPackEmphasis\n /**\n * How the speakers are followed: `\"auto\"` (the default) follows faces with\n * Speaker Frames while it is available to the caller, else splits the frame\n * evenly; `\"static\"` splits the frame evenly by speaker; `\"tracking\"`\n * follows faces (charged per started block of 1,000 sampled frames;\n * refused 403 where Speaker Frames is not available to the caller). Faces\n * aren't named after a speaker yet, so a camera shared by several speakers\n * keeps the even split.\n */\n framingSource?: \"auto\" | \"static\" | \"tracking\"\n /**\n * Stop at a quick preview for a person to review; render it at full\n * quality with {@link EditResource.continueUseCase}\n * (`mode: \"render-final\"`, no `editedEdl`: the layout has no cut to change).\n */\n reviewBeforeRender?: boolean\n}\n\n/**\n * The body's recordings (`mediaUrls`, then `masterAudioUrl` and `cameras` when\n * given), and the rest of the input as it came: the one mapper every use-case\n * body goes through. Throws before any request when the input names both\n * `mediaUrl` and `mediaUrls`, or neither.\n */\nfunction withRecordings<T extends UseCaseRecordingsInput>(input: T): Record<string, unknown> {\n const { mediaUrl, mediaUrls, masterAudioUrl, cameras, ...rest } = input\n if (mediaUrl !== undefined && mediaUrls !== undefined) throw new TypeError(\"pass mediaUrl or mediaUrls, not both\")\n const recordings = mediaUrls ?? (mediaUrl !== undefined ? [mediaUrl] : undefined)\n if (!recordings) throw new TypeError(\"pass mediaUrl or mediaUrls\")\n return {\n mediaUrls: [...recordings],\n ...(masterAudioUrl !== undefined ? { masterAudioUrl } : {}),\n ...(cameras !== undefined ? { cameras } : {}),\n ...Object.fromEntries(Object.entries(rest).filter(([, v]) => v !== undefined)),\n }\n}\n\n/**\n * Sends `send` the body `build` makes, or rejects (never throws) with the\n * error of an input the body cannot take — before any request, as every input\n * check of the `edit` resource rejects.\n */\nexport function withUseCaseBody<T>(build: () => Record<string, unknown>, send: (body: Record<string, unknown>) => Promise<T>): Promise<T> {\n let body: Record<string, unknown>\n try {\n body = build()\n } catch (err) {\n return Promise.reject(err)\n }\n return send(body)\n}\n\nexport function tightenBody(input: TightenEpisodeInput): Record<string, unknown> {\n return withRecordings(input)\n}\n\nexport function chaptersBody(input: EpisodeChaptersInput): Record<string, unknown> {\n return withRecordings({\n mediaUrl: input.mediaUrl,\n ...(input.planTier !== undefined ? { planTier: input.planTier } : {}),\n ...(input.instructions !== undefined ? { instructions: input.instructions } : {}),\n ...(input.styleGuide !== undefined ? { styleGuide: input.styleGuide } : {}),\n })\n}\n\nexport function trailerBody(input: EpisodeTrailerInput): Record<string, unknown> {\n return withRecordings({\n mediaUrl: input.mediaUrl,\n mediaUrls: input.mediaUrls,\n masterAudioUrl: input.masterAudioUrl,\n cameras: input.cameras,\n ...(input.introCardUrl !== undefined ? { introCardUrl: input.introCardUrl } : {}),\n // An empty list is sent as is: the route refuses it (at least one format).\n ...(input.formats !== undefined ? { formats: input.formats } : {}),\n ...(input.reviewBeforeRender !== undefined ? { reviewBeforeRender: input.reviewBeforeRender } : {}),\n ...(input.planTier !== undefined ? { planTier: input.planTier } : {}),\n ...(input.instructions !== undefined ? { instructions: input.instructions } : {}),\n ...(input.styleGuide !== undefined ? { styleGuide: input.styleGuide } : {}),\n })\n}\n\n/** Clip Pack's body: what the caller set, `framing: null` included (no framing). */\nexport function clipPackBody(input: ClipPackInput): Record<string, unknown> {\n return withRecordings(input)\n}\n\n/** Speaker Layout's body: the recordings, then what the caller set. */\nexport function speakerLayoutBody(input: SpeakerLayoutInput): Record<string, unknown> {\n return withRecordings(input)\n}\n","import type { NodaroClientCore } from \"../core.js\"\nimport { ForbiddenError, NodaroError } from \"../errors.js\"\nimport {\n remapTranscriptThroughEdl,\n unwrapEditPlanOutput,\n resolveEditPlanSources,\n describeAudioSyncOffsetIssue,\n transcriptSpeakerLabels,\n cameraSwitchSpeakerMap, speakerMapResultOf, type SpeakerMapResult,\n type Edl,\n type Transcript,\n type EditPlanMode,\n type EditPlanTier,\n type EdlClipSet,\n type ChapterSet,\n type EdlTargetAspect\n} from \"@nodaro/shared/edl\"\nimport { USE_CASE_NODE_TYPES, isUseCaseNodeType, type UseCaseNodeType } from \"@nodaro/shared/nodes\"\nimport type { SpeakerMapInput } from \"./speaker-map-inputs.js\"\nimport {\n chaptersBody,\n clipPackBody,\n speakerLayoutBody,\n tightenBody,\n trailerBody,\n withUseCaseBody,\n type ClipPackInput,\n type EpisodeChaptersInput,\n type EpisodeTrailerInput,\n type SpeakerLayoutInput,\n type TightenEpisodeInput,\n} from \"./edit-use-case-inputs.js\"\n\nexport { CLIP_PACK_MAX_TARGET_SEC, CLIP_PACK_MIN_TARGET_SEC, TRAILER_FORMATS } from \"./edit-use-case-inputs.js\"\nexport type { ClipPackEmphasis, ClipPackInput, EpisodeChaptersInput, EpisodeTrailerInput, SpeakerLayoutInput, TightenEpisodeInput, TrailerFormat, UseCaseRecordingsInput } from \"./edit-use-case-inputs.js\"\n\n// Re-export the canonical EDL / transcript vocabulary from `@nodaro/shared`\n// (single source of truth — the shapes live at `packages/shared/src/edl.ts`).\n// `@nodaro/shared` is already a hard dep of this package, so there is no\n// bundle-size cost to importing from it, and an integration builds requests and\n// reads results with one dependency. `EdlClipSet` / `ChapterSet` are the raw\n// `output_data` shapes of the `clips` / `chapters` modes, and\n// `unwrapEditPlanOutput` is the sanctioned way to normalize any edit-plan job's\n// `output_data` (it also strips the relay's `viaNodaroCloud` marker).\nexport type { Edl, Transcript, EditPlanMode, EditPlanTier, EdlClipSet, ChapterSet }\nexport { unwrapEditPlanOutput }\n\n/**\n * A silence-detect job's `output_data.json` — the value to pass as\n * {@link EditPlanInput.silence}. It is NOT what {@link EditResource.silenceDetect}\n * returns (that is `{ jobId }`); fetch the finished job and read its\n * `output_data.json`. The planner reads the `ranges` array — an input without\n * one is silently ignored, so pass this whole object.\n */\nexport interface SilenceRanges {\n /** Wire version of the payload. */\n version?: number\n /** Silence spans on the source clock, in ms. */\n ranges: ReadonlyArray<{ startMs: number; endMs: number }>\n /** Total source duration, in ms. */\n durationMs?: number\n}\n\n/** Every editorial route answers with the queued job to poll. */\nexport interface EditJobResult {\n /** The queued job id — follow it via `client.jobs.getStatus(jobId)`. */\n jobId: string\n}\n\nexport interface SilenceDetectInput {\n /**\n * An audio OR video source. A single ffmpeg `silencedetect` pass runs over the\n * source's audio proxy either way — no provider key required.\n */\n audioUrl: string\n /** dBFS threshold, always ≤ 0. Default -35 (a good podcast default). */\n thresholdDb?: number\n /** Minimum silence length to report, in ms. Default 700. */\n minSilenceMs?: number\n /** Padding kept around speech, in ms — shrinks each reported range inward. Default 120. */\n padMs?: number\n /**\n * Optionally associate this run with a workflow execution (display only — it\n * ties the standalone job back to a workflow for the execution history).\n */\n workflowId?: string\n}\n\n/** One recording for {@link EditResource.audioSync}. */\nexport interface AudioSyncSource {\n /**\n * Your id for this recording (1–200 chars, unique within the request) —\n * echoed back as its offset's `sourceId`. Use the id your EDL gives the same\n * recording (`EdlSource.id`) and the result folds straight into it.\n */\n id: string\n /** An audio OR video URL — the audio track is read either way. */\n url: string\n}\n\nexport interface AudioSyncInput {\n /** The 2–6 recordings of one conversation to line up (camera files and/or a master mic). */\n sources: AudioSyncSource[]\n /**\n * The id of the source every offset is measured against (its own offset is\n * 0). Must be one of `sources`' ids; default: the first source.\n */\n reference?: string\n /** Optionally associate this run with a workflow execution (display only). */\n workflowId?: string\n}\n\n/** One recording's measured clock offset in an {@link AudioSyncResult}. */\nexport interface AudioSyncOffset {\n /** The recording's `id` from the request. */\n sourceId: string\n /**\n * Where this recording sits on the reference's clock, in integer ms:\n * `referenceMs = sourceMs + offsetMs` (the EDL's D19 sign — the value\n * `EdlSource.offsetMs` takes when the reference is the master).\n */\n offsetMs: number\n /** 0–1. Below 0.5 a `notes` line asks for a check by ear. */\n confidence: number\n /**\n * Measured clock drift against the reference, in ms gained per hour; `null`\n * when the shared stretch was too short to measure it. Drift is reported,\n * never corrected — the offset is taken at the middle of the overlap.\n */\n driftMsPerHour: number | null\n}\n\n/**\n * An audio-sync job's `output_data.json`. It is NOT what\n * {@link EditResource.audioSync} returns (that is `{ jobId }`); fetch the\n * finished job and read its `output_data.json`.\n */\nexport interface AudioSyncResult {\n /** Wire version of the payload. */\n version: number\n /** The source every offset is measured against (its own offset is 0). */\n reference: string\n offsets: AudioSyncOffset[]\n /** Human-readable warnings: low confidence, measured drift, no shared sound. */\n notes: string[]\n}\n\nexport interface ApplyEdlInput {\n /** The edit decision list to render. Media resolves from each `edl.sources[i].url`. */\n edl: Edl\n /**\n * Optional media-URL overrides for `edl.sources[i].url`, POSITIONAL in this\n * array's order. Each URL is SSRF-guarded server-side like any media the\n * platform fetches.\n */\n sources?: string[]\n /**\n * Optional transcript to remap through the cut. The rendered job returns the\n * remapped transcript on its `json` output. A word-level multi-hour transcript\n * is several MB — if you only need the re-timed transcript (not a render), use\n * {@link EditResource.remapTranscript} locally instead of sending it here.\n */\n transcript?: Transcript\n /** Render a full video (default) or an audio-only cut. */\n output?: \"video\" | \"audio\"\n /** Fast proxy draft or the final render. Default \"final\". */\n quality?: \"proxy\" | \"final\"\n /**\n * Default crossfade (ms) on boundaries with no explicit transition; 0 = hard\n * cuts. Per-boundary clamped to the ffmpeg-xfade limit server-side. Default 0.\n */\n crossfadeMs?: number\n /**\n * The plan clip this render cuts — `edlSpanKey(clip)` from `@nodaro/shared`\n * (`\"<first inMs>-<last outMs>\"`). The job's result carries it back as\n * `output_data.clipKey`, so renders of a clip set can be matched to their\n * clips. Omit for a render of no plan clip.\n */\n clipKey?: string\n /**\n * The plan value this render cuts — `renderReadBasis(value)` from\n * `@nodaro/shared` (16 lowercase hex digits), where `value` is the Edit\n * Plan's Tighten EDL with any review applied, or the clip this render cuts.\n * The job's result carries it back as `output_data.planBasis`, so a take can\n * be told apart from one cut from an earlier plan. Send it only when the EDL\n * you send IS that value (not one an intermediate step re-cut from an older\n * plan); omit it otherwise. The result's `output_data.renderBasis` (the\n * render's own settings and sources) is stamped by the server.\n */\n planBasis?: string\n /** Optionally associate this run with a workflow execution (display only). */\n workflowId?: string\n}\n\n/**\n * One media source for an edit-plan run. Mirrors the shape the workflow engine\n * sends: a stable `id` (adopted verbatim as the plan's `EdlSource` id), the\n * media `url`, and the `kind`, plus optional per-source annotations the planner\n * honors.\n */\nexport interface EditPlanSource {\n /** Stable id for this source — becomes the `EdlSource` id in the returned plan. */\n id: string\n /** The source's media URL (SSRF-guarded server-side). */\n url: string\n /** This source's medium. */\n kind: \"video\" | \"audio\"\n /** Role annotation. `\"master-audio\"` marks the clock the plan is reserved on. */\n role?: \"master-audio\" | \"camera\" | \"wide\" | \"screen\"\n /** Speaker labels present in this source. */\n speakers?: string[]\n /**\n * This source's origin on the master clock (masterMs = sourceMs + offsetMs).\n * Set by hand, it wins over a measured offset from `offsets`.\n */\n offsetMs?: number\n}\n\nexport interface EditPlanInput {\n /**\n * Planning mode. The finished job's `output_data` carries the plan — read it\n * with {@link unwrapEditPlanOutput}, which also strips the relay's\n * `viaNodaroCloud` marker:\n * - `\"tighten\"` → an `Edl`.\n * - `\"clips\"` → an {@link EdlClipSet} (`{ version, clips: Edl[] }`);\n * `unwrapEditPlanOutput` returns the bare `Edl[]`.\n * - `\"chapters\"` → a {@link ChapterSet} (`{ version, chapters: [...] }`).\n * - `\"trailer\"` → an `Edl` (one short teaser cut from the strongest moments).\n */\n mode: EditPlanMode\n /** Reasoning tier — affects plan quality AND the credit bucket. */\n planTier: EditPlanTier\n /** The timed transcript driving the plan. */\n transcript: Transcript\n /**\n * Optional detected silence ranges. Pass the silence-detect JOB'S RESULT —\n * `getStatus(jobId).data.output_data.json` (a {@link SilenceRanges} object),\n * NOT the `{ jobId }` that {@link EditResource.silenceDetect} returns. The\n * planner reads the `ranges` array; an input without one is silently ignored.\n */\n silence?: SilenceRanges\n /** The recording's media sources (1–6). */\n sources: EditPlanSource[]\n /**\n * Multicam: an {@link AudioSyncResult} (the audio-sync job's\n * `output_data.json`) measured over these same source ids. Each source's\n * measured offset is written onto its `offsetMs` BEFORE the request, on the\n * master's clock (the `master-audio` source, else the first) — a source's\n * own `offsetMs` wins. `editPlan` rejects with a {@link NodaroError}\n * (`code: \"edit_plan_sources\"`), before any request or charge, when a\n * source was not measured or matched weakly (confidence < 0.5 — set its\n * `offsetMs` by hand), or the master was not measured.\n */\n offsets?: AudioSyncResult | string\n /**\n * The id of the source the transcript was made from, when you know it. The\n * plan follows the master's clock, so a transcript made from a source that\n * is off it is rejected the same way.\n */\n transcriptSourceId?: string\n /** Free-text editing steer. */\n instructions?: string\n /** Style-guide text applied to the plan. */\n styleGuide?: string\n /** `\"clips\"` mode only: how many clips to cut. */\n count?: number\n /** `\"clips\"` mode only: target duration per clip, in seconds. */\n targetDurationSec?: number\n /** Target aspect for cut clips (`\"clips\"`) or the teaser (`\"trailer\"`). */\n targetAspect?: \"16:9\" | \"9:16\" | \"1:1\" | \"4:5\"\n /** Target platform hint (e.g. a social platform name). */\n platform?: string\n /** Optionally associate this run with a workflow execution (display only). */\n workflowId?: string\n}\n\n/** Input for {@link EditResource.cameraSwitch} (podcast B5). */\nexport interface CameraSwitchInput {\n /** One EDL — an `editPlan` result (`unwrapEditPlanOutput`), not a clip set. */\n edl: Edl\n /** The word transcript WITH speaker labels (transcribe with speaker detection). */\n transcript: Transcript\n /** Speaker label → the EDL source id of that speaker's camera. A speaker\n * left out shows the source whose `speakers` list names them, else the\n * `wide` camera, else any camera that filmed them. */\n speakerMap?: Record<string, string>\n /** A {@link EditResource.speakerMap} job's `output_data.json`: a label in `speakerMap`\n * wins, then this result, then the n-th speaker heard gets the n-th camera. */\n speakerMapResult?: SpeakerMapResult | string\n /** Speaker label → display name (on the segments and the returned transcript). */\n speakerNames?: Record<string, string>\n /** The shortest shot in ms (default 2 500): a shorter turn holds the shot. */\n minShotMs?: number\n /** Cut this long before the new speaker starts, ms (default 200). */\n leadMs?: number\n /** With a `wide` source: break to it after this long on one camera, ms (default 20 000). */\n maxShotMs?: number\n /** With a `wide` source: every N-th cut goes to the wide (default 0 = off). */\n wideEvery?: number\n /** Overlapping speech → a layout hint (default false; Apply EDL renders cut-only edits). */\n layoutHints?: boolean\n /** Optionally associate this run with a workflow execution (display only). */\n workflowId?: string\n}\n\n/**\n * The podcast use-case node types, each one a route (`POST /v1/<type>`, and\n * `POST /v1/<type>/continue` to continue one of its runs).\n */\nexport { USE_CASE_NODE_TYPES, type UseCaseNodeType }\n\n/** The route that continues a run of `type`. */\nconst continuePathOf = (type: UseCaseNodeType): `/v1/${UseCaseNodeType}/continue` => `/v1/${type}/continue`\n\n/** What a use-case run (`tightenEpisode`, `episodeChapters`, `episodeTrailer`, `clipPack`, `speakerLayout`) and `continueUseCase` answer: the run's job to poll. */\nexport interface UseCaseJobResult extends EditJobResult {\n /** The run's execution (absent on a deduplicated retry). */\n executionId?: string\n /** `true` when an `Idempotency-Key` retry found the run already started: `jobId` is that run. */\n deduped?: boolean\n}\n\n/** What `tightenEpisode` answers (a {@link UseCaseJobResult}). */\nexport type TightenEpisodeJobResult = UseCaseJobResult\n\n/**\n * What a use-case run is estimated at (`data`). Every credit amount is 0\n * on an edition without credits; `durationSec` is `null` when the recording's\n * length could not be read.\n */\nexport interface UseCaseEstimate {\n /** The whole run: its steps plus the fee. */\n totalCredits: number\n /** The steps at their own rates. */\n stepsCredits: number\n /** The per-run fee. */\n feeCredits: number\n /** A step is a metered LLM call's ESTIMATE (charged its actual usage), so the\n * total is one: show it `≈N`. Absent for a fixed figure. */\n estimate?: true\n /** The recording's length, in seconds. */\n durationSec: number | null\n}\n\n/** What a Tighten Episode run is estimated at (a {@link UseCaseEstimate}). */\nexport type TightenEpisodeEstimate = UseCaseEstimate\n\n/** Input for {@link EditResource.continueUseCase}. */\nexport interface UseCaseContinueInput {\n /** The run to continue: the job `tightenEpisode`, `episodeChapters`, `episodeTrailer`, `clipPack` or `speakerLayout` (or an earlier continuation) answered. */\n jobId: string\n /**\n * `\"from-failed\"` re-runs what did not finish of a failed run;\n * `\"render-final\"` renders the full-quality result after a review-on preview\n * (a Chapters run has no preview: it is refused `render_final_not_preview`;\n * a Clip Pack edit that drops every clip is refused `use_case_nothing_kept`).\n */\n mode: \"from-failed\" | \"render-final\"\n /** Render final only: the reviewer's edit of the plan (an EDL). A Speaker Layout run has no plan: an edit is refused `400 use_case_no_plan`. */\n editedEdl?: unknown\n /**\n * The run's node type: its continuation goes to `POST /v1/<nodeType>/continue`.\n * Optional: when absent the job is read first (`GET /v1/jobs/:id`, which\n * needs the `jobs:read` scope on an app token) for the type the run records.\n * Required when that read cannot answer: a key without `jobs:read`, or a job\n * that records no use-case type (the call rejects with `use_case_type_unknown`).\n */\n nodeType?: UseCaseNodeType\n}\n\n/** Per-call options for the use-case requests (Tighten Episode, Chapters, Trailer, Clip Pack, Speaker Layout, and their continuations). */\nexport interface UseCaseRequestOptions {\n /**\n * Sent as the `Idempotency-Key` header. Reuse the same value when retrying\n * the same request and the server answers the run it already started\n * (`deduped: true`) instead of starting a second one.\n */\n idempotencyKey?: string\n}\n\nfunction idempotencyHeaders(options?: UseCaseRequestOptions): { headers?: Record<string, string> } {\n return options?.idempotencyKey ? { headers: { \"Idempotency-Key\": options.idempotencyKey } } : {}\n}\n\n/**\n * Editorial primitives for podcast / long-form video editing, single-camera\n * and multicam: measure the cameras' offsets ({@link audioSync}), plan the cut\n * ({@link editPlan}), put each cut on the speaker's camera\n * ({@link cameraSwitch}), render a Preview to review (`applyEdl` with\n * `quality: \"proxy\"`), then the final (`quality: \"final\"`).\n *\n * - {@link silenceDetect}, {@link audioSync} and {@link applyEdl} are core nodes\n * available on every edition.\n * - {@link editPlan} and {@link cameraSwitch} run on nodaro.ai; a self-hosted\n * install relays them once it is connected (a 503\n * `code: \"nodaro_connection_required\"` otherwise).\n * - {@link tightenEpisode} runs the whole chain (transcribe, plan, render, and\n * optionally captions, music and framing) in one call. It is core, but a\n * self-hosted install needs a nodaro.ai connection for the steps that run\n * there (a 503 `code: \"nodaro_connection_required\"` otherwise).\n * {@link continueUseCase} continues one of its runs.\n * - {@link episodeChapters} lists a recording's chapters (transcribe, then the\n * plan in chapters mode) in one call; nothing renders. Like\n * {@link tightenEpisode}, a self-hosted install needs a nodaro.ai connection.\n * - {@link episodeTrailer} cuts a 20–40 s trailer of a recording and delivers\n * it in each chosen format in one call; the same connection applies.\n * - {@link clipPack} cuts a recording into a pack of short clips (framed and\n * captioned by default) in one call; the same connection applies.\n * - {@link speakerLayout} frames a whole recording by speaker (the same\n * length, nothing cut) in one call; the same connection applies.\n * - {@link remapTranscript} is a PURE local transform (no request) — the same\n * remap `applyEdl` performs on its `transcript`, exposed for callers that hold\n * an EDL and a transcript and only want the re-timed transcript.\n *\n * Every request method except the estimates ({@link estimateTightenEpisode},\n * {@link estimateEpisodeChapters}, {@link estimateEpisodeTrailer},\n * {@link estimateClipPack}, {@link estimateSpeakerLayout}: a quote, `{ data }`) returns\n * {@link EditJobResult} (the use-case runs a {@link UseCaseJobResult}); poll the\n * `jobId` with `client.jobs.getStatus(jobId)`.\n */\nexport class EditResource {\n constructor(private client: NodaroClientCore) {}\n\n /**\n * Detect silence ranges in an audio/video source (`POST /v1/silence-detect`).\n * Keyless — one ffmpeg pass over the source's audio proxy.\n */\n silenceDetect(input: SilenceDetectInput): Promise<EditJobResult> {\n return this.client.request(\"POST\", \"/v1/silence-detect\", {\n body: {\n audioUrl: input.audioUrl,\n ...(input.thresholdDb !== undefined ? { thresholdDb: input.thresholdDb } : {}),\n ...(input.minSilenceMs !== undefined ? { minSilenceMs: input.minSilenceMs } : {}),\n ...(input.padMs !== undefined ? { padMs: input.padMs } : {}),\n ...(input.workflowId !== undefined ? { workflowId: input.workflowId } : {}),\n },\n })\n }\n\n /**\n * Measure how far apart the clocks of 2–6 recordings of one conversation are\n * (`POST /v1/audio-sync`), by cross-correlating their audio — keyless, one\n * ffmpeg decode per source. The finished job's `output_data.json` is an\n * {@link AudioSyncResult}. A malformed request (fewer than 2 or more than 6\n * sources, a repeated id, a `reference` that is not one of the ids) throws a\n * typed `NodaroError` (400, `code: \"validation_error\"`) before any credits\n * are reserved.\n */\n audioSync(input: AudioSyncInput): Promise<EditJobResult> {\n return this.client.request(\"POST\", \"/v1/audio-sync\", {\n body: {\n sources: input.sources.map((s) => ({ id: s.id, url: s.url })),\n ...(input.reference !== undefined ? { reference: input.reference } : {}),\n ...(input.workflowId !== undefined ? { workflowId: input.workflowId } : {}),\n },\n })\n }\n\n /**\n * Which camera each speaker is on, from the cameras' own microphones (`POST\n * /v1/speaker-map`), keyless. `output_data.json` is a `SpeakerMapResult`: pass\n * it to {@link cameraSwitch} as `speakerMapResult`. A malformed request throws\n * a `NodaroError` (400 `validation_error`; 422 `no_speakers` for a transcript\n * with no speaker labels) before any credits are reserved.\n */\n speakerMap(input: SpeakerMapInput): Promise<EditJobResult> {\n return this.client.request(\"POST\", \"/v1/speaker-map\", {\n body: {\n sources: input.sources.map((s) => ({ id: s.id, url: s.url, ...(s.kind ? { kind: s.kind } : {}) })),\n transcript: input.transcript,\n ...(input.offsets !== undefined ? { offsets: input.offsets } : {}),\n ...(input.masterSourceId !== undefined ? { masterSourceId: input.masterSourceId } : {}),\n ...(input.wideSourceId !== undefined ? { wideSourceId: input.wideSourceId } : {}),\n ...(input.marginDb !== undefined ? { marginDb: input.marginDb } : {}),\n ...(input.workflowId !== undefined ? { workflowId: input.workflowId } : {}),\n },\n })\n }\n\n /**\n * Render an edit decision list into a video or audio cut (`POST /v1/apply-edl`).\n * The EDL is validated at ingress — an unresolvable source or a picture-less\n * segment on a video edit throws a typed `NodaroError` (400, `code:\n * \"invalid_edl\"`) before any credits are reserved.\n */\n applyEdl(input: ApplyEdlInput): Promise<EditJobResult> {\n return this.client.request(\"POST\", \"/v1/apply-edl\", {\n body: {\n edl: input.edl,\n ...(input.sources !== undefined ? { sources: input.sources } : {}),\n ...(input.transcript !== undefined ? { transcript: input.transcript } : {}),\n ...(input.output !== undefined ? { output: input.output } : {}),\n ...(input.quality !== undefined ? { quality: input.quality } : {}),\n ...(input.crossfadeMs !== undefined ? { crossfadeMs: input.crossfadeMs } : {}),\n ...(input.clipKey !== undefined ? { clipKey: input.clipKey } : {}),\n ...(input.planBasis !== undefined ? { planBasis: input.planBasis } : {}),\n ...(input.workflowId !== undefined ? { workflowId: input.workflowId } : {}),\n },\n })\n }\n\n /**\n * Tighten Episode (`POST /v1/tighten-episode`): tighten a podcast recording\n * in one call — transcribe, cut the silences and filler, render, with\n * optional captions, music and framing. Answers the run's job to poll; its\n * `output_data` holds the episode. The run is priced as its steps at their own\n * rates plus the listed per-run fee. Quote it first with\n * {@link estimateTightenEpisode}.\n */\n tightenEpisode(input: TightenEpisodeInput, options?: UseCaseRequestOptions): Promise<TightenEpisodeJobResult> {\n return withUseCaseBody(() => tightenBody(input), (body) => this.client.request(\"POST\", \"/v1/tighten-episode\", { body, ...idempotencyHeaders(options) }))\n }\n\n /**\n * What a Tighten Episode run is estimated at (`POST /v1/tighten-episode/estimate`):\n * its steps at their own rates plus its per-run fee. Nothing is created or\n * charged. The estimate leans high: the render is priced at the recording's\n * full length, while the charge follows the minutes actually rendered.\n */\n estimateTightenEpisode(input: TightenEpisodeInput): Promise<{ data: TightenEpisodeEstimate }> {\n return withUseCaseBody(() => tightenBody(input), (body) => this.client.request(\"POST\", \"/v1/tighten-episode/estimate\", { body }))\n }\n\n /**\n * Chapters (`POST /v1/episode-chapters`): transcribe a recording and list its\n * chapters in one call. Answers the run's job to poll; the finished job's\n * `output_data.text` is the list as show notes (one `0:00 Title` line per\n * chapter; once a chapter starts at 1:00:00 or later, every line is\n * `H:MM:SS`), `output_data.json` the list itself (`{ startMs, title }[]`, the\n * same rows; the first starts at 0). A run that finds no chapters fails,\n * and its fee is refunded. Priced as its steps at their own rates plus the\n * listed per-run fee; quote it first with {@link estimateEpisodeChapters}.\n */\n episodeChapters(input: EpisodeChaptersInput, options?: UseCaseRequestOptions): Promise<UseCaseJobResult> {\n return withUseCaseBody(() => chaptersBody(input), (body) => this.client.request(\"POST\", \"/v1/episode-chapters\", { body, ...idempotencyHeaders(options) }))\n }\n\n /**\n * What a Chapters run is estimated at (`POST /v1/episode-chapters/estimate`):\n * its steps at their own rates plus its per-run fee. Nothing is created or\n * charged. A recording whose length cannot be read is estimated at the\n * 180-minute ceiling.\n */\n estimateEpisodeChapters(input: EpisodeChaptersInput): Promise<{ data: UseCaseEstimate }> {\n return withUseCaseBody(() => chaptersBody(input), (body) => this.client.request(\"POST\", \"/v1/episode-chapters/estimate\", { body }))\n }\n\n /**\n * Trailer (`POST /v1/episode-trailer`): cut a 20–40 s trailer of a recording\n * and deliver it in each chosen format (padded, never cropped), optionally\n * after an intro card, in one call. The finished job's `output_data.formats`\n * is `{ format, url }[]` in format order, the first also `output_data.videoUrl`;\n * a format that failed is named in `output_data.failedFormats` (the run keeps\n * the others). With `reviewBeforeRender` the run stops at a preview\n * (`videoUrl`, no formats yet). Priced as its steps at their own rates plus\n * the listed per-run fee; quote it first with {@link estimateEpisodeTrailer}.\n */\n episodeTrailer(input: EpisodeTrailerInput, options?: UseCaseRequestOptions): Promise<UseCaseJobResult> {\n return withUseCaseBody(() => trailerBody(input), (body) => this.client.request(\"POST\", \"/v1/episode-trailer\", { body, ...idempotencyHeaders(options) }))\n }\n\n /**\n * What a Trailer run is estimated at (`POST /v1/episode-trailer/estimate`):\n * its steps at their own rates plus its per-run fee. Nothing is created or\n * charged. The trailer is quoted at 40 seconds, the longest trailer the\n * plan cuts; a Render final is quoted on the trailer the run cut (with the\n * review's edits), plus the intro card.\n */\n estimateEpisodeTrailer(input: EpisodeTrailerInput): Promise<{ data: UseCaseEstimate }> {\n return withUseCaseBody(() => trailerBody(input), (body) => this.client.request(\"POST\", \"/v1/episode-trailer/estimate\", { body }))\n }\n\n /**\n * Clip Pack (`POST /v1/clip-pack`): cut a recording into a pack of short\n * clips in one call — the plan finds the best moments (`count`, default 8,\n * of about `targetDurationSec`, default 60), each is rendered (framed 9:16\n * with the speakers stacked by default; `framing: null` keeps the\n * recording's shape) and captioned. An audio recording makes audio clips.\n * The finished job's `output_data.clips` is `{ url, title?, hook?, clipKey,\n * thumbnailUrl?, captionsFailed? }[]` in plan order, the first also\n * `output_data.videoUrl` (`audioUrl` for audio clips). Every clip is tried:\n * one that cannot be rendered is skipped, not charged and counted on\n * `failedClips` (the pack keeps the others and its fee); a clip whose\n * captions failed comes uncaptioned (`captionsFailed`, counted on\n * `failedCaptions`). When no clip renders the run fails and its fee is\n * refunded. With `reviewBeforeRender` the run stops at previews; Render\n * final ({@link continueUseCase}) renders only the clips the edit keeps.\n * Priced as its steps at their own rates plus the listed per-run fee;\n * quote it first with {@link estimateClipPack}.\n */\n clipPack(input: ClipPackInput, options?: UseCaseRequestOptions): Promise<UseCaseJobResult> {\n return withUseCaseBody(() => clipPackBody(input), (body) => this.client.request(\"POST\", \"/v1/clip-pack\", { body, ...idempotencyHeaders(options) }))\n }\n\n /**\n * What a Clip Pack run is estimated at (`POST /v1/clip-pack/estimate`): its\n * steps at their own rates plus its per-run fee. Nothing is created or\n * charged. Each clip is quoted at twice the target length (the plan may cut\n * a clip longer than asked); the charge follows each clip's real length.\n */\n estimateClipPack(input: ClipPackInput): Promise<{ data: UseCaseEstimate }> {\n return withUseCaseBody(() => clipPackBody(input), (body) => this.client.request(\"POST\", \"/v1/clip-pack/estimate\", { body }))\n }\n\n /**\n * Speaker Layout (`POST /v1/speaker-layout`): frame a whole recording by\n * speaker in one call — the same length, nothing cut. One recording: each\n * speaker framed in turn; several recordings of one conversation: lined up,\n * each speaker shown on their own camera. The finished job's\n * `output_data.videoUrl` is the framed video, `output_data.json` the edit\n * Speaker View drew. With `reviewBeforeRender` the run stops at a preview;\n * {@link continueUseCase} (`mode: \"render-final\"`, no `editedEdl`) renders\n * it at full quality. Priced as its steps at their own rates plus the listed\n * per-run fee; quote it first with {@link estimateSpeakerLayout}.\n */\n speakerLayout(input: SpeakerLayoutInput, options?: UseCaseRequestOptions): Promise<UseCaseJobResult> {\n return withUseCaseBody(() => speakerLayoutBody(input), (body) => this.client.request(\"POST\", \"/v1/speaker-layout\", { body, ...idempotencyHeaders(options) }))\n }\n\n /**\n * What a Speaker Layout run is estimated at (`POST /v1/speaker-layout/estimate`):\n * its steps at their own rates plus its per-run fee. Nothing is created or\n * charged. A recording whose length cannot be read is estimated at the\n * 180-minute ceiling.\n */\n estimateSpeakerLayout(input: SpeakerLayoutInput): Promise<{ data: UseCaseEstimate }> {\n return withUseCaseBody(() => speakerLayoutBody(input), (body) => this.client.request(\"POST\", \"/v1/speaker-layout/estimate\", { body }))\n }\n\n /**\n * Continue a use-case run as a new job (`POST /v1/<type>/continue`, the\n * run's own type: `input.nodeType`, else the type the job records, read with\n * `GET /v1/jobs/:id`; when that read cannot tell, this rejects with a\n * `NodaroError` coded `use_case_type_unknown` — pass `nodeType` then):\n * `\"from-failed\"` keeps the steps that finished and runs the rest (the fee\n * is held again; the failed run's was refunded);\n * `\"render-final\"` renders the full-quality result after a review-on preview,\n * with the preview's settings and no fee. A refusal that names another job\n * (`already_running`, `continuation_superseded`,\n * `render_final_already_rendered`) throws a `ContinuationRefusedError`\n * carrying that `jobId`.\n */\n async continueUseCase(input: UseCaseContinueInput, options?: UseCaseRequestOptions): Promise<UseCaseJobResult> {\n if (input.nodeType !== undefined && !isUseCaseNodeType(input.nodeType)) {\n throw new NodaroError(\n `continueUseCase: nodeType \"${String(input.nodeType)}\" is not a use-case node type (${USE_CASE_NODE_TYPES.join(\", \")})`,\n \"invalid_node_type\",\n 400,\n )\n }\n const type = input.nodeType ?? (await this.runTypeOf(input.jobId))\n return this.client.request(\"POST\", continuePathOf(type), {\n body: { jobId: input.jobId, mode: input.mode, ...(input.editedEdl !== undefined ? { editedEdl: input.editedEdl } : {}) },\n ...idempotencyHeaders(options),\n })\n }\n\n /**\n * The use-case type a run records (`input_data.type`, else its `job_type`).\n * When the key lacks the `jobs:read` scope (403 naming that scope) or the job\n * names no use-case type, the type cannot be read: this rejects with a\n * `NodaroError` (`use_case_type_unknown`, 400) asking for `nodeType`, and\n * nothing is posted (decided 2026-10-18: no route is guessed for the run).\n * Any other failure of the read, any other 403 included, is thrown as is.\n */\n private async runTypeOf(jobId: string): Promise<UseCaseNodeType> {\n const unknown = () =>\n new NodaroError(\"continueUseCase: the run's node type cannot be read — pass nodeType\", \"use_case_type_unknown\", 400)\n let row: { job_type?: unknown; input_data?: unknown } | undefined\n try {\n row = (await this.client.request<{ data?: { job_type?: unknown; input_data?: unknown } }>(\"GET\", `/v1/jobs/${encodeURIComponent(jobId)}`)).data\n } catch (err) {\n if (err instanceof ForbiddenError && err.missingScope === \"jobs:read\") throw unknown()\n throw err\n }\n const input = row?.input_data\n const recorded = input && typeof input === \"object\" && !Array.isArray(input) ? (input as { type?: unknown }).type : undefined\n const type = typeof recorded === \"string\" && recorded.length > 0 ? recorded : row?.job_type\n if (!isUseCaseNodeType(type)) throw unknown()\n return type\n }\n\n /**\n * Plan a transcript-driven cut (`POST /v1/edit-plan`). Reads a timed\n * transcript (plus optional silence ranges) and the media sources, and plans\n * the edit. The finished job's `output_data` holds the plan: an `Edl`\n * (`\"tighten\"` or `\"trailer\"`), an {@link EdlClipSet} (`\"clips\"`), or a\n * {@link ChapterSet} (`\"chapters\"`) — normalize it with {@link unwrapEditPlanOutput}.\n *\n * On a self-hosted install the request relays to nodaro.ai and needs the\n * install connected (a 503 `code: \"nodaro_connection_required\"` otherwise);\n * on nodaro.ai it runs directly.\n */\n editPlan(input: EditPlanInput): Promise<EditJobResult> {\n // The same pre-dispatch check the canvas and MCP run (B4): the server never\n // sees `offsets` — they are written onto the sources here.\n const planned = resolveEditPlanSources(input.sources, {\n offsets: input.offsets,\n transcriptSourceId: input.transcriptSourceId,\n })\n if (!planned.ok) {\n const message = planned.issues.map((issue) => describeAudioSyncOffsetIssue(issue)).join(\"; \")\n return Promise.reject(new NodaroError(`editPlan: ${message}`, \"edit_plan_sources\", 400))\n }\n const transcript = planned.transcriptSourceId\n ? { ...input.transcript, sourceId: planned.transcriptSourceId }\n : input.transcript\n return this.client.request(\"POST\", \"/v1/edit-plan\", {\n body: {\n mode: input.mode,\n planTier: input.planTier,\n transcript,\n sources: planned.sources,\n ...(input.silence !== undefined ? { silence: input.silence } : {}),\n ...(input.instructions !== undefined ? { instructions: input.instructions } : {}),\n ...(input.styleGuide !== undefined ? { styleGuide: input.styleGuide } : {}),\n ...(input.count !== undefined ? { count: input.count } : {}),\n ...(input.targetDurationSec !== undefined ? { targetDurationSec: input.targetDurationSec } : {}),\n ...(input.targetAspect !== undefined ? { targetAspect: input.targetAspect } : {}),\n ...(input.platform !== undefined ? { platform: input.platform } : {}),\n ...(input.workflowId !== undefined ? { workflowId: input.workflowId } : {}),\n },\n })\n }\n\n /**\n * Camera Switch (podcast B5): choose which camera shows each cut of `edl`\n * by who is speaking — the sound never changes. Cloud edition; a flat\n * price. The finished job's `output_data.json` is the switched EDL (feed it\n * to {@link applyEdl}) and `output_data.transcript` the transcript with\n * `speakerNames` applied. A transcript with no speaker labels rejects with\n * a {@link NodaroError} (`code: \"no_speakers\"`) before any request or charge.\n */\n cameraSwitch(input: CameraSwitchInput): Promise<EditJobResult> {\n if (transcriptSpeakerLabels(input.transcript).length === 0) {\n return Promise.reject(new NodaroError(\n \"cameraSwitch: the transcript has no speaker labels — transcribe with speaker detection on\",\n \"no_speakers\",\n 422,\n ))\n }\n const result = input.speakerMapResult\n if (result !== undefined && !speakerMapResultOf(result)) return Promise.reject(new NodaroError(\"cameraSwitch: speakerMapResult is not a Speaker Map result — pass that job's output_data.json\", \"not_a_speaker_map\", 400))\n const speakerMap = result !== undefined ? cameraSwitchSpeakerMap({ speakerMap: input.speakerMap }, input.edl, input.transcript, { speakerMap: result }) : input.speakerMap\n return this.client.request(\"POST\", \"/v1/camera-switch\", {\n body: {\n edl: input.edl,\n transcript: input.transcript,\n ...(speakerMap !== undefined ? { speakerMap } : {}),\n ...(input.speakerNames !== undefined ? { speakerNames: input.speakerNames } : {}),\n ...(input.minShotMs !== undefined ? { minShotMs: input.minShotMs } : {}),\n ...(input.leadMs !== undefined ? { leadMs: input.leadMs } : {}),\n ...(input.maxShotMs !== undefined ? { maxShotMs: input.maxShotMs } : {}),\n ...(input.wideEvery !== undefined ? { wideEvery: input.wideEvery } : {}),\n ...(input.layoutHints !== undefined ? { layoutHints: input.layoutHints } : {}),\n ...(input.workflowId !== undefined ? { workflowId: input.workflowId } : {}),\n },\n })\n }\n\n /**\n * Remap a transcript through an EDL — a PURE client-side transform (NO\n * request). Returns a new transcript whose word (and segment) timings are on\n * the EDL's rendered output clock, dropping words that fall in cut regions and\n * clipping straddlers. Runs `@nodaro/shared`'s canonical\n * `remapTranscriptThroughEdl`, the same remap `applyEdl` performs server-side.\n */\n remapTranscript(edl: Edl, transcript: Transcript): Transcript {\n return remapTranscriptThroughEdl(edl, transcript)\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/resources/edit-use-case-inputs.ts","../src/resources/edit.ts"],"names":["isUseCaseNodeType","NodaroError","USE_CASE_NODE_TYPES","ForbiddenError","resolveEditPlanSources","describeAudioSyncOffsetIssue","transcriptSpeakerLabels","speakerMapResultOf","cameraSwitchSpeakerMap","edl","remapTranscriptThroughEdl"],"mappings":"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","file":"chunk-DOMNKVKA.cjs","sourcesContent":["/**\n * The inputs of the podcast use-case runs on the `edit` resource (Tighten\n * Episode, Chapters, Trailer, Clip Pack, Speaker Layout) and the request body each one sends.\n * Split from `edit.ts`, which holds the methods, the type list and the\n * continue routes; every name here is re-exported from there.\n */\nimport type { EditPlanTier, EdlTargetAspect, SpeakerEmphasisStyle, SpeakerSwitchId } from \"@nodaro/shared/edl\"\nimport type { CaptionStyle } from \"@nodaro/shared/captions\"\n\n/**\n * The recordings of a use-case run: one (`mediaUrl`), or the recordings of one\n * conversation (`mediaUrls`, in order — the cameras; one may be sound only),\n * an optional Master audio and the Cameras settings. Pass `mediaUrl` or\n * `mediaUrls`, not both.\n *\n * Several recordings or a Master audio need Speaker Map, which tells who is on\n * which camera: where it is not available to you (not yet on nodaro.ai) the\n * request is refused `403 node_not_available` — send one recording.\n */\nexport interface UseCaseRecordingsInput {\n /** The recording — a video or audio URL, up to 3 hours. */\n mediaUrl?: string\n /**\n * Instead of `mediaUrl`: the recordings of one conversation, in order — up\n * to six in all with the Master audio; without one, two or more cameras keep\n * a place for the sound, so up to five. With two or more the run lines them\n * up, works out who is on which camera and cuts to whoever is talking.\n */\n mediaUrls?: string[]\n /** The mixer or recorder track: the episode's sound and the clock the recordings are lined up to. */\n masterAudioUrl?: string\n /** With several recordings or a Master audio: the Cameras settings (ignored with one recording and no Master audio). */\n cameras?: {\n /** Which recording (1-based) is the wide shot, shown when a speaker has no camera of their own; `null` for none. */\n wide?: number | null\n /** The recordings already share one clock: skip lining them up. */\n synced?: boolean\n /** Who is on which camera: speaker number (`\"1\"` = the first voice heard) → recording number, 0 = the wide shot. Overrides the automatic map. */\n speakerCameras?: Record<string, number>\n }\n}\n\n/**\n * Input for {@link EditResource.tightenEpisode} and\n * {@link EditResource.estimateTightenEpisode}: the recording (or the\n * recordings of one conversation, see {@link UseCaseRecordingsInput}) in, the\n * tightened episode out. Only the recording is required; every other field\n * left out takes the node's default.\n */\nexport interface TightenEpisodeInput extends UseCaseRecordingsInput {\n /** Optional music bed, ducked under the voice and ending with the episode. */\n musicUrl?: string\n /** `\"video\"` or `\"audio\"`; an audio recording always makes an audio episode. */\n output?: \"video\" | \"audio\"\n /**\n * Frame a video episode with Speaker View: an output aspect and a layout,\n * over automatic boxes on the speakers on screen. A layout the aspect does\n * not draw is snapped to one it does. `null` or absent: no framing.\n */\n framing?: {\n aspect: EdlTargetAspect\n layout: \"auto\" | \"single\" | \"side-by-side\" | \"stacked\" | \"grid\" | \"pip\"\n } | null\n /**\n * With a framing, how it follows the speakers: `\"static\"` (the default)\n * splits the frame evenly by speaker; `\"tracking\"` follows faces with\n * Speaker Frames (charged per started block of 1,000 sampled frames; a\n * camera shared by several speakers keeps the even split until faces are\n * named; refused 403 where Speaker Frames is not available to the caller);\n * `\"auto\"` follows faces while Speaker Frames is available to the caller,\n * else the even split. Ignored without a framing.\n */\n framingSource?: \"auto\" | \"static\" | \"tracking\"\n /** Captions on a video episode (on by default). */\n captions?: boolean\n /** The captions' look. */\n captionStyle?: CaptionStyle\n /**\n * Stop at a quick preview for a person to review; render the full-quality\n * episode afterwards with {@link EditResource.continueUseCase}\n * (`mode: \"render-final\"`).\n */\n reviewBeforeRender?: boolean\n /** The planner's tier. */\n planTier?: EditPlanTier\n /** Editing instructions for the planner (up to 4 000 characters). */\n instructions?: string\n /** A style guide for the planner (up to 4 000 characters). */\n styleGuide?: string\n /** How far the music dips under the voice, 0–100 (default 75). */\n musicDuckAmount?: number\n}\n\n/**\n * Input for {@link EditResource.episodeChapters} and\n * {@link EditResource.estimateEpisodeChapters}: one recording in, its chapters\n * out. Only `mediaUrl` is required; every other field left out takes the\n * node's default.\n */\nexport interface EpisodeChaptersInput {\n /** The recording — a video or audio URL, up to 3 hours. */\n mediaUrl: string\n /** The planner's tier (default `\"economy\"`). */\n planTier?: EditPlanTier\n /** Instructions for the chapters, e.g. \"5 to 8 chapters\" (up to 4 000 characters). */\n instructions?: string\n /** A style guide for the chapter titles (up to 4 000 characters). */\n styleGuide?: string\n}\n\n/** The formats a Trailer is delivered in, in delivery order (16:9 is a 1920×1080 landscape). */\nexport const TRAILER_FORMATS = [\"9:16\", \"1:1\", \"4:5\", \"16:9\"] as const\n/** One Trailer format (see {@link TRAILER_FORMATS}). */\nexport type TrailerFormat = (typeof TRAILER_FORMATS)[number]\n\n/**\n * Input for {@link EditResource.episodeTrailer} and\n * {@link EditResource.estimateEpisodeTrailer}: one video recording (or the\n * recordings of one conversation, see {@link UseCaseRecordingsInput}) in, a\n * 20–40 s trailer out in each chosen format. Only the recording is required.\n */\nexport interface EpisodeTrailerInput extends UseCaseRecordingsInput {\n /** The recording — a video URL, up to 3 hours (a run with no picture is refused). Or `mediaUrls`. */\n mediaUrl?: string\n /** An optional intro card: a short video (15 s at most) played before the trailer. */\n introCardUrl?: string\n /** The formats to deliver, padded, never cropped (default `[\"9:16\", \"1:1\", \"4:5\"]`; an empty list is refused). */\n formats?: TrailerFormat[]\n /** Stop at a preview of the trailer; render every format with {@link EditResource.continueUseCase} (`mode: \"render-final\"`). */\n reviewBeforeRender?: boolean\n /** The planner's tier (default `\"standard\"`). */\n planTier?: EditPlanTier\n /** Instructions for the trailer (up to 4 000 characters). */\n instructions?: string\n /** A style guide for the planner (up to 4 000 characters). */\n styleGuide?: string\n}\n\n/** The shortest and longest clip a Clip Pack asks the plan for, in seconds. */\nexport const CLIP_PACK_MIN_TARGET_SEC = 5\nexport const CLIP_PACK_MAX_TARGET_SEC = 180\n\n/**\n * A Clip Pack emphasis: `\"none\"`, or one or more of `\"scale\"`, `\"border\"` and\n * `\"dim\"` joined with `\"+\"` (each once — the route refuses a repeat).\n */\nexport type ClipPackEmphasis = SpeakerEmphasisStyle | `${Exclude<SpeakerEmphasisStyle, \"none\">}+${string}`\n\n/**\n * Input for {@link EditResource.clipPack} and\n * {@link EditResource.estimateClipPack}: the recording (or the recordings of\n * one conversation, see {@link UseCaseRecordingsInput} — each clip then cuts\n * to whoever is talking) in, a pack of short clips out. An audio recording\n * makes audio clips (no framing, no captions). Only the recording is\n * required; every other field left out takes the node's default.\n */\nexport interface ClipPackInput extends UseCaseRecordingsInput {\n /** How many clips to find, 1–50 (default 8). The plan may find fewer. */\n count?: number\n /** Each clip's target length in seconds, {@link CLIP_PACK_MIN_TARGET_SEC}–{@link CLIP_PACK_MAX_TARGET_SEC} (default 60). */\n targetDurationSec?: number\n /**\n * Frame each video clip with Speaker View on automatic boxes over the\n * episode's speakers: the shape, and optionally the layout (default\n * `\"stacked\"`; one the shape does not draw is snapped), the switch at each\n * speaker change (default `\"pan\"`) and the emphasis (default `\"scale\"`;\n * `\"none\"`, or `\"scale\"`, `\"border\"` and `\"dim\"` joined with `\"+\"`). Left\n * out: 9:16, stacked, pan, scale. `null`: no framing (the recording's shape).\n */\n framing?: {\n aspect: EdlTargetAspect\n layout?: \"auto\" | \"single\" | \"side-by-side\" | \"stacked\" | \"grid\" | \"pip\"\n switchType?: SpeakerSwitchId\n emphasisStyle?: ClipPackEmphasis\n } | null\n /**\n * With a framing, how it follows the speakers: `\"static\"` splits the frame\n * evenly by speaker (what a request that leaves this out gets); `\"tracking\"`\n * runs Speaker Frames once over the whole pack to follow faces (charged per\n * started block of 1,000 sampled frames; refused 403 where Speaker Frames is\n * not available to the caller); `\"auto\"` follows faces while Speaker Frames\n * is available to the caller, else the even split. Ignored without a framing.\n */\n framingSource?: \"auto\" | \"static\" | \"tracking\"\n /** Caption each video clip (on by default). */\n captions?: boolean\n /** The captions' look (default `\"karaoke\"`). */\n captionStyle?: CaptionStyle\n /**\n * Stop at quick previews of the clips for a person to review; render the\n * kept clips at full quality with {@link EditResource.continueUseCase}\n * (`mode: \"render-final\"`, an `editedEdl` that keeps or drops clips).\n */\n reviewBeforeRender?: boolean\n /** The planner's tier (default `\"standard\"`). */\n planTier?: EditPlanTier\n /** Instructions for picking the clips (up to 4 000 characters). */\n instructions?: string\n /** A style guide for the planner (up to 4 000 characters). */\n styleGuide?: string\n}\n\n/**\n * Input for {@link EditResource.speakerLayout} and\n * {@link EditResource.estimateSpeakerLayout}: one video recording (or the\n * recordings of one conversation, see {@link UseCaseRecordingsInput}) in, the\n * whole recording framed by speaker out — the same length, nothing cut. Only\n * the recording is required; every other field left out takes the node's\n * default.\n */\nexport interface SpeakerLayoutInput extends UseCaseRecordingsInput {\n /** The recording — a video URL, up to 3 hours (an audio-only recording is refused). Or `mediaUrls`. */\n mediaUrl?: string\n /** The video's shape (default `\"9:16\"`). With one recording, a video already as narrow as the shape (or narrower) is refused `400 media_shape`. */\n targetAspect?: EdlTargetAspect\n /** How the speakers are laid out (default `\"stacked\"`; one the shape does not draw is snapped to one it does). */\n layout?: \"auto\" | \"single\" | \"side-by-side\" | \"stacked\" | \"grid\" | \"pip\"\n /** The switch at each speaker change (default `\"cut\"`). */\n switchType?: SpeakerSwitchId\n /** How the speaker talking is emphasised (default `\"scale\"`): `\"none\"`, or `\"scale\"`, `\"border\"` and `\"dim\"` joined with `\"+\"`. */\n emphasisStyle?: ClipPackEmphasis\n /**\n * How the speakers are followed: `\"auto\"` (the default) follows faces with\n * Speaker Frames while it is available to the caller, else splits the frame\n * evenly; `\"static\"` splits the frame evenly by speaker; `\"tracking\"`\n * follows faces (charged per started block of 1,000 sampled frames;\n * refused 403 where Speaker Frames is not available to the caller). Faces\n * aren't named after a speaker yet, so a camera shared by several speakers\n * keeps the even split.\n */\n framingSource?: \"auto\" | \"static\" | \"tracking\"\n /**\n * Stop at a quick preview for a person to review; render it at full\n * quality with {@link EditResource.continueUseCase}\n * (`mode: \"render-final\"`, no `editedEdl`: the layout has no cut to change).\n */\n reviewBeforeRender?: boolean\n}\n\n/**\n * The body's recordings (`mediaUrls`, then `masterAudioUrl` and `cameras` when\n * given), and the rest of the input as it came: the one mapper every use-case\n * body goes through. Throws before any request when the input names both\n * `mediaUrl` and `mediaUrls`, or neither.\n */\nfunction withRecordings<T extends UseCaseRecordingsInput>(input: T): Record<string, unknown> {\n const { mediaUrl, mediaUrls, masterAudioUrl, cameras, ...rest } = input\n if (mediaUrl !== undefined && mediaUrls !== undefined) throw new TypeError(\"pass mediaUrl or mediaUrls, not both\")\n const recordings = mediaUrls ?? (mediaUrl !== undefined ? [mediaUrl] : undefined)\n if (!recordings) throw new TypeError(\"pass mediaUrl or mediaUrls\")\n return {\n mediaUrls: [...recordings],\n ...(masterAudioUrl !== undefined ? { masterAudioUrl } : {}),\n ...(cameras !== undefined ? { cameras } : {}),\n ...Object.fromEntries(Object.entries(rest).filter(([, v]) => v !== undefined)),\n }\n}\n\n/**\n * Sends `send` the body `build` makes, or rejects (never throws) with the\n * error of an input the body cannot take — before any request, as every input\n * check of the `edit` resource rejects.\n */\nexport function withUseCaseBody<T>(build: () => Record<string, unknown>, send: (body: Record<string, unknown>) => Promise<T>): Promise<T> {\n let body: Record<string, unknown>\n try {\n body = build()\n } catch (err) {\n return Promise.reject(err)\n }\n return send(body)\n}\n\nexport function tightenBody(input: TightenEpisodeInput): Record<string, unknown> {\n return withRecordings(input)\n}\n\nexport function chaptersBody(input: EpisodeChaptersInput): Record<string, unknown> {\n return withRecordings({\n mediaUrl: input.mediaUrl,\n ...(input.planTier !== undefined ? { planTier: input.planTier } : {}),\n ...(input.instructions !== undefined ? { instructions: input.instructions } : {}),\n ...(input.styleGuide !== undefined ? { styleGuide: input.styleGuide } : {}),\n })\n}\n\nexport function trailerBody(input: EpisodeTrailerInput): Record<string, unknown> {\n return withRecordings({\n mediaUrl: input.mediaUrl,\n mediaUrls: input.mediaUrls,\n masterAudioUrl: input.masterAudioUrl,\n cameras: input.cameras,\n ...(input.introCardUrl !== undefined ? { introCardUrl: input.introCardUrl } : {}),\n // An empty list is sent as is: the route refuses it (at least one format).\n ...(input.formats !== undefined ? { formats: input.formats } : {}),\n ...(input.reviewBeforeRender !== undefined ? { reviewBeforeRender: input.reviewBeforeRender } : {}),\n ...(input.planTier !== undefined ? { planTier: input.planTier } : {}),\n ...(input.instructions !== undefined ? { instructions: input.instructions } : {}),\n ...(input.styleGuide !== undefined ? { styleGuide: input.styleGuide } : {}),\n })\n}\n\n/** Clip Pack's body: what the caller set, `framing: null` included (no framing). */\nexport function clipPackBody(input: ClipPackInput): Record<string, unknown> {\n return withRecordings(input)\n}\n\n/** Speaker Layout's body: the recordings, then what the caller set. */\nexport function speakerLayoutBody(input: SpeakerLayoutInput): Record<string, unknown> {\n return withRecordings(input)\n}\n","import type { NodaroClientCore } from \"../core.js\"\nimport { ForbiddenError, NodaroError } from \"../errors.js\"\nimport {\n remapTranscriptThroughEdl,\n unwrapEditPlanOutput,\n resolveEditPlanSources,\n describeAudioSyncOffsetIssue,\n transcriptSpeakerLabels,\n cameraSwitchSpeakerMap, speakerMapResultOf, type SpeakerMapResult,\n type Edl,\n type Transcript,\n type EditPlanMode,\n type EditPlanTier,\n type EdlClipSet,\n type ChapterSet,\n type EdlTargetAspect\n} from \"@nodaro/shared/edl\"\nimport { USE_CASE_NODE_TYPES, isUseCaseNodeType, type UseCaseNodeType } from \"@nodaro/shared/nodes\"\nimport type { SpeakerMapInput } from \"./speaker-map-inputs.js\"\nimport {\n chaptersBody,\n clipPackBody,\n speakerLayoutBody,\n tightenBody,\n trailerBody,\n withUseCaseBody,\n type ClipPackInput,\n type EpisodeChaptersInput,\n type EpisodeTrailerInput,\n type SpeakerLayoutInput,\n type TightenEpisodeInput,\n} from \"./edit-use-case-inputs.js\"\n\nexport { CLIP_PACK_MAX_TARGET_SEC, CLIP_PACK_MIN_TARGET_SEC, TRAILER_FORMATS } from \"./edit-use-case-inputs.js\"\nexport type { ClipPackEmphasis, ClipPackInput, EpisodeChaptersInput, EpisodeTrailerInput, SpeakerLayoutInput, TightenEpisodeInput, TrailerFormat, UseCaseRecordingsInput } from \"./edit-use-case-inputs.js\"\n\n// Re-export the canonical EDL / transcript vocabulary from `@nodaro/shared`\n// (single source of truth — the shapes live at `packages/shared/src/edl.ts`).\n// `@nodaro/shared` is already a hard dep of this package, so there is no\n// bundle-size cost to importing from it, and an integration builds requests and\n// reads results with one dependency. `EdlClipSet` / `ChapterSet` are the raw\n// `output_data` shapes of the `clips` / `chapters` modes, and\n// `unwrapEditPlanOutput` is the sanctioned way to normalize any edit-plan job's\n// `output_data` (it also strips the relay's `viaNodaroCloud` marker).\nexport type { Edl, Transcript, EditPlanMode, EditPlanTier, EdlClipSet, ChapterSet }\nexport { unwrapEditPlanOutput }\n\n/**\n * A silence-detect job's `output_data.json` — the value to pass as\n * {@link EditPlanInput.silence}. It is NOT what {@link EditResource.silenceDetect}\n * returns (that is `{ jobId }`); fetch the finished job and read its\n * `output_data.json`. The planner reads the `ranges` array — an input without\n * one is silently ignored, so pass this whole object.\n */\nexport interface SilenceRanges {\n /** Wire version of the payload. */\n version?: number\n /** Silence spans on the source clock, in ms. */\n ranges: ReadonlyArray<{ startMs: number; endMs: number }>\n /** Total source duration, in ms. */\n durationMs?: number\n}\n\n/** Every editorial route answers with the queued job to poll. */\nexport interface EditJobResult {\n /** The queued job id — follow it via `client.jobs.getStatus(jobId)`. */\n jobId: string\n}\n\nexport interface SilenceDetectInput {\n /**\n * An audio OR video source. A single ffmpeg `silencedetect` pass runs over the\n * source's audio proxy either way — no provider key required.\n */\n audioUrl: string\n /** dBFS threshold, always ≤ 0. Default -35 (a good podcast default). */\n thresholdDb?: number\n /** Minimum silence length to report, in ms. Default 700. */\n minSilenceMs?: number\n /** Padding kept around speech, in ms — shrinks each reported range inward. Default 120. */\n padMs?: number\n /**\n * Optionally associate this run with a workflow execution (display only — it\n * ties the standalone job back to a workflow for the execution history).\n */\n workflowId?: string\n}\n\n/** One recording for {@link EditResource.audioSync}. */\nexport interface AudioSyncSource {\n /**\n * Your id for this recording (1–200 chars, unique within the request) —\n * echoed back as its offset's `sourceId`. Use the id your EDL gives the same\n * recording (`EdlSource.id`) and the result folds straight into it.\n */\n id: string\n /** An audio OR video URL — the audio track is read either way. */\n url: string\n}\n\nexport interface AudioSyncInput {\n /** The 2–6 recordings of one conversation to line up (camera files and/or a master mic). */\n sources: AudioSyncSource[]\n /**\n * The id of the source every offset is measured against (its own offset is\n * 0). Must be one of `sources`' ids; default: the first source.\n */\n reference?: string\n /** Optionally associate this run with a workflow execution (display only). */\n workflowId?: string\n}\n\n/** One recording's measured clock offset in an {@link AudioSyncResult}. */\nexport interface AudioSyncOffset {\n /** The recording's `id` from the request. */\n sourceId: string\n /**\n * Where this recording sits on the reference's clock, in integer ms:\n * `referenceMs = sourceMs + offsetMs` (the EDL's D19 sign — the value\n * `EdlSource.offsetMs` takes when the reference is the master).\n */\n offsetMs: number\n /** 0–1. Below 0.5 a `notes` line asks for a check by ear. */\n confidence: number\n /**\n * Measured clock drift against the reference, in ms gained per hour; `null`\n * when the shared stretch was too short to measure it. Drift is reported,\n * never corrected — the offset is taken at the middle of the overlap.\n */\n driftMsPerHour: number | null\n}\n\n/**\n * An audio-sync job's `output_data.json`. It is NOT what\n * {@link EditResource.audioSync} returns (that is `{ jobId }`); fetch the\n * finished job and read its `output_data.json`.\n */\nexport interface AudioSyncResult {\n /** Wire version of the payload. */\n version: number\n /** The source every offset is measured against (its own offset is 0). */\n reference: string\n offsets: AudioSyncOffset[]\n /** Human-readable warnings: low confidence, measured drift, no shared sound. */\n notes: string[]\n}\n\nexport interface ApplyEdlInput {\n /** The edit decision list to render. Media resolves from each `edl.sources[i].url`. */\n edl: Edl\n /**\n * Optional media-URL overrides for `edl.sources[i].url`, POSITIONAL in this\n * array's order. Each URL is SSRF-guarded server-side like any media the\n * platform fetches.\n */\n sources?: string[]\n /**\n * Optional transcript to remap through the cut. The rendered job returns the\n * remapped transcript on its `json` output. A word-level multi-hour transcript\n * is several MB — if you only need the re-timed transcript (not a render), use\n * {@link EditResource.remapTranscript} locally instead of sending it here.\n */\n transcript?: Transcript\n /** Render a full video (default) or an audio-only cut. */\n output?: \"video\" | \"audio\"\n /** Fast proxy draft or the final render. Default \"final\". */\n quality?: \"proxy\" | \"final\"\n /**\n * Default crossfade (ms) on boundaries with no explicit transition; 0 = hard\n * cuts. Per-boundary clamped to the ffmpeg-xfade limit server-side. Default 0.\n */\n crossfadeMs?: number\n /**\n * The plan clip this render cuts — `edlSpanKey(clip)` from `@nodaro/shared`\n * (`\"<first inMs>-<last outMs>\"`). The job's result carries it back as\n * `output_data.clipKey`, so renders of a clip set can be matched to their\n * clips. Omit for a render of no plan clip.\n */\n clipKey?: string\n /**\n * The plan value this render cuts — `renderReadBasis(value)` from\n * `@nodaro/shared` (16 lowercase hex digits), where `value` is the Edit\n * Plan's Tighten EDL with any review applied, or the clip this render cuts.\n * The job's result carries it back as `output_data.planBasis`, so a take can\n * be told apart from one cut from an earlier plan. Send it only when the EDL\n * you send IS that value (not one an intermediate step re-cut from an older\n * plan); omit it otherwise. The result's `output_data.renderBasis` (the\n * render's own settings and sources) is stamped by the server.\n */\n planBasis?: string\n /** Optionally associate this run with a workflow execution (display only). */\n workflowId?: string\n}\n\n/**\n * One media source for an edit-plan run. Mirrors the shape the workflow engine\n * sends: a stable `id` (adopted verbatim as the plan's `EdlSource` id), the\n * media `url`, and the `kind`, plus optional per-source annotations the planner\n * honors.\n */\nexport interface EditPlanSource {\n /** Stable id for this source — becomes the `EdlSource` id in the returned plan. */\n id: string\n /** The source's media URL (SSRF-guarded server-side). */\n url: string\n /** This source's medium. */\n kind: \"video\" | \"audio\"\n /** Role annotation. `\"master-audio\"` marks the clock the plan is reserved on. */\n role?: \"master-audio\" | \"camera\" | \"wide\" | \"screen\"\n /** Speaker labels present in this source. */\n speakers?: string[]\n /**\n * This source's origin on the master clock (masterMs = sourceMs + offsetMs).\n * Set by hand, it wins over a measured offset from `offsets`.\n */\n offsetMs?: number\n}\n\nexport interface EditPlanInput {\n /**\n * Planning mode. The finished job's `output_data` carries the plan — read it\n * with {@link unwrapEditPlanOutput}, which also strips the relay's\n * `viaNodaroCloud` marker:\n * - `\"tighten\"` → an `Edl`.\n * - `\"clips\"` → an {@link EdlClipSet} (`{ version, clips: Edl[] }`);\n * `unwrapEditPlanOutput` returns the bare `Edl[]`.\n * - `\"chapters\"` → a {@link ChapterSet} (`{ version, chapters: [...] }`).\n * - `\"trailer\"` → an `Edl` (one short teaser cut from the strongest moments).\n */\n mode: EditPlanMode\n /** Reasoning tier — affects plan quality AND the credit bucket. */\n planTier: EditPlanTier\n /** The timed transcript driving the plan. */\n transcript: Transcript\n /**\n * Optional detected silence ranges. Pass the silence-detect JOB'S RESULT —\n * `getStatus(jobId).data.output_data.json` (a {@link SilenceRanges} object),\n * NOT the `{ jobId }` that {@link EditResource.silenceDetect} returns. The\n * planner reads the `ranges` array; an input without one is silently ignored.\n */\n silence?: SilenceRanges\n /** The recording's media sources (1–6). */\n sources: EditPlanSource[]\n /**\n * Multicam: an {@link AudioSyncResult} (the audio-sync job's\n * `output_data.json`) measured over these same source ids. Each source's\n * measured offset is written onto its `offsetMs` BEFORE the request, on the\n * master's clock (the `master-audio` source, else the first) — a source's\n * own `offsetMs` wins. `editPlan` rejects with a {@link NodaroError}\n * (`code: \"edit_plan_sources\"`), before any request or charge, when a\n * source was not measured or matched weakly (confidence < 0.5 — set its\n * `offsetMs` by hand), or the master was not measured.\n */\n offsets?: AudioSyncResult | string\n /**\n * The id of the source the transcript was made from, when you know it. The\n * plan follows the master's clock, so a transcript made from a source that\n * is off it is rejected the same way.\n */\n transcriptSourceId?: string\n /** Free-text editing steer. */\n instructions?: string\n /** Style-guide text applied to the plan. */\n styleGuide?: string\n /** `\"clips\"` mode only: how many clips to cut. */\n count?: number\n /** `\"clips\"` mode only: target duration per clip, in seconds. */\n targetDurationSec?: number\n /** Target aspect for cut clips (`\"clips\"`) or the teaser (`\"trailer\"`). */\n targetAspect?: \"16:9\" | \"9:16\" | \"1:1\" | \"4:5\"\n /** Target platform hint (e.g. a social platform name). */\n platform?: string\n /** Optionally associate this run with a workflow execution (display only). */\n workflowId?: string\n}\n\n/** Input for {@link EditResource.cameraSwitch} (podcast B5). */\nexport interface CameraSwitchInput {\n /** One EDL — an `editPlan` result (`unwrapEditPlanOutput`), not a clip set. */\n edl: Edl\n /** The word transcript WITH speaker labels (transcribe with speaker detection). */\n transcript: Transcript\n /** Speaker label → the EDL source id of that speaker's camera. A speaker\n * left out shows the source whose `speakers` list names them, else the\n * `wide` camera, else any camera that filmed them. */\n speakerMap?: Record<string, string>\n /** A {@link EditResource.speakerMap} job's `output_data.json`: a label in `speakerMap`\n * wins, then this result, then the n-th speaker heard gets the n-th camera. */\n speakerMapResult?: SpeakerMapResult | string\n /** Speaker label → display name (on the segments and the returned transcript). */\n speakerNames?: Record<string, string>\n /** The shortest shot in ms (default 2 500): a shorter turn holds the shot. */\n minShotMs?: number\n /** Cut this long before the new speaker starts, ms (default 200). */\n leadMs?: number\n /** With a `wide` source: break to it after this long on one camera, ms (default 20 000). */\n maxShotMs?: number\n /** With a `wide` source: every N-th cut goes to the wide (default 0 = off). */\n wideEvery?: number\n /** Overlapping speech → a layout hint (default false; Apply EDL renders cut-only edits). */\n layoutHints?: boolean\n /** Optionally associate this run with a workflow execution (display only). */\n workflowId?: string\n}\n\n/**\n * The podcast use-case node types, each one a route (`POST /v1/<type>`, and\n * `POST /v1/<type>/continue` to continue one of its runs).\n */\nexport { USE_CASE_NODE_TYPES, type UseCaseNodeType }\n\n/** The route that continues a run of `type`. */\nconst continuePathOf = (type: UseCaseNodeType): `/v1/${UseCaseNodeType}/continue` => `/v1/${type}/continue`\n\n/** What a use-case run (`tightenEpisode`, `episodeChapters`, `episodeTrailer`, `clipPack`, `speakerLayout`) and `continueUseCase` answer: the run's job to poll. */\nexport interface UseCaseJobResult extends EditJobResult {\n /** The run's execution (absent on a deduplicated retry). */\n executionId?: string\n /** `true` when an `Idempotency-Key` retry found the run already started: `jobId` is that run. */\n deduped?: boolean\n}\n\n/** What `tightenEpisode` answers (a {@link UseCaseJobResult}). */\nexport type TightenEpisodeJobResult = UseCaseJobResult\n\n/**\n * What a use-case run is estimated at (`data`). Every credit amount is 0\n * on an edition without credits; `durationSec` is `null` when the recording's\n * length could not be read.\n */\nexport interface UseCaseEstimate {\n /** The whole run: its steps plus the fee. */\n totalCredits: number\n /** The steps at their own rates. */\n stepsCredits: number\n /** The per-run fee. */\n feeCredits: number\n /** A step is a metered LLM call's ESTIMATE (charged its actual usage), so the\n * total is one: show it `≈N`. Absent for a fixed figure. */\n estimate?: true\n /** The recording's length, in seconds. */\n durationSec: number | null\n}\n\n/** What a Tighten Episode run is estimated at (a {@link UseCaseEstimate}). */\nexport type TightenEpisodeEstimate = UseCaseEstimate\n\n/** Input for {@link EditResource.continueUseCase}. */\nexport interface UseCaseContinueInput {\n /** The run to continue: the job `tightenEpisode`, `episodeChapters`, `episodeTrailer`, `clipPack` or `speakerLayout` (or an earlier continuation) answered. */\n jobId: string\n /**\n * `\"from-failed\"` re-runs what did not finish of a failed run;\n * `\"render-final\"` renders the full-quality result after a review-on preview\n * (a Chapters run has no preview: it is refused `render_final_not_preview`;\n * a Clip Pack edit that drops every clip is refused `use_case_nothing_kept`).\n */\n mode: \"from-failed\" | \"render-final\"\n /** Render final only: the reviewer's edit of the plan (an EDL). A Speaker Layout run has no plan: an edit is refused `400 use_case_no_plan`. */\n editedEdl?: unknown\n /**\n * The run's node type: its continuation goes to `POST /v1/<nodeType>/continue`.\n * Optional: when absent the job is read first (`GET /v1/jobs/:id`, which\n * needs the `jobs:read` scope on an app token) for the type the run records.\n * Required when that read cannot answer: a key without `jobs:read`, or a job\n * that records no use-case type (the call rejects with `use_case_type_unknown`).\n */\n nodeType?: UseCaseNodeType\n}\n\n/** Per-call options for the use-case requests (Tighten Episode, Chapters, Trailer, Clip Pack, Speaker Layout, and their continuations). */\nexport interface UseCaseRequestOptions {\n /**\n * Sent as the `Idempotency-Key` header. Reuse the same value when retrying\n * the same request and the server answers the run it already started\n * (`deduped: true`) instead of starting a second one.\n */\n idempotencyKey?: string\n}\n\nfunction idempotencyHeaders(options?: UseCaseRequestOptions): { headers?: Record<string, string> } {\n return options?.idempotencyKey ? { headers: { \"Idempotency-Key\": options.idempotencyKey } } : {}\n}\n\n/**\n * Editorial primitives for podcast / long-form video editing, single-camera\n * and multicam: measure the cameras' offsets ({@link audioSync}), plan the cut\n * ({@link editPlan}), put each cut on the speaker's camera\n * ({@link cameraSwitch}), render a Preview to review (`applyEdl` with\n * `quality: \"proxy\"`), then the final (`quality: \"final\"`).\n *\n * - {@link silenceDetect}, {@link audioSync} and {@link applyEdl} are core nodes\n * available on every edition.\n * - {@link editPlan} and {@link cameraSwitch} run on nodaro.ai; a self-hosted\n * install relays them once it is connected (a 503\n * `code: \"nodaro_connection_required\"` otherwise).\n * - {@link tightenEpisode} runs the whole chain (transcribe, plan, render, and\n * optionally captions, music and framing) in one call. It is core, but a\n * self-hosted install needs a nodaro.ai connection for the steps that run\n * there (a 503 `code: \"nodaro_connection_required\"` otherwise).\n * {@link continueUseCase} continues one of its runs.\n * - {@link episodeChapters} lists a recording's chapters (transcribe, then the\n * plan in chapters mode) in one call; nothing renders. Like\n * {@link tightenEpisode}, a self-hosted install needs a nodaro.ai connection.\n * - {@link episodeTrailer} cuts a 20–40 s trailer of a recording and delivers\n * it in each chosen format in one call; the same connection applies.\n * - {@link clipPack} cuts a recording into a pack of short clips (framed and\n * captioned by default) in one call; the same connection applies.\n * - {@link speakerLayout} frames a whole recording by speaker (the same\n * length, nothing cut) in one call; the same connection applies.\n * - {@link remapTranscript} is a PURE local transform (no request) — the same\n * remap `applyEdl` performs on its `transcript`, exposed for callers that hold\n * an EDL and a transcript and only want the re-timed transcript.\n *\n * Every request method except the estimates ({@link estimateTightenEpisode},\n * {@link estimateEpisodeChapters}, {@link estimateEpisodeTrailer},\n * {@link estimateClipPack}, {@link estimateSpeakerLayout}: a quote, `{ data }`) returns\n * {@link EditJobResult} (the use-case runs a {@link UseCaseJobResult}); poll the\n * `jobId` with `client.jobs.getStatus(jobId)`.\n */\nexport class EditResource {\n constructor(private client: NodaroClientCore) {}\n\n /**\n * Detect silence ranges in an audio/video source (`POST /v1/silence-detect`).\n * Keyless — one ffmpeg pass over the source's audio proxy.\n */\n silenceDetect(input: SilenceDetectInput): Promise<EditJobResult> {\n return this.client.request(\"POST\", \"/v1/silence-detect\", {\n body: {\n audioUrl: input.audioUrl,\n ...(input.thresholdDb !== undefined ? { thresholdDb: input.thresholdDb } : {}),\n ...(input.minSilenceMs !== undefined ? { minSilenceMs: input.minSilenceMs } : {}),\n ...(input.padMs !== undefined ? { padMs: input.padMs } : {}),\n ...(input.workflowId !== undefined ? { workflowId: input.workflowId } : {}),\n },\n })\n }\n\n /**\n * Measure how far apart the clocks of 2–6 recordings of one conversation are\n * (`POST /v1/audio-sync`), by cross-correlating their audio — keyless, one\n * ffmpeg decode per source. The finished job's `output_data.json` is an\n * {@link AudioSyncResult}. A malformed request (fewer than 2 or more than 6\n * sources, a repeated id, a `reference` that is not one of the ids) throws a\n * typed `NodaroError` (400, `code: \"validation_error\"`) before any credits\n * are reserved.\n */\n audioSync(input: AudioSyncInput): Promise<EditJobResult> {\n return this.client.request(\"POST\", \"/v1/audio-sync\", {\n body: {\n sources: input.sources.map((s) => ({ id: s.id, url: s.url })),\n ...(input.reference !== undefined ? { reference: input.reference } : {}),\n ...(input.workflowId !== undefined ? { workflowId: input.workflowId } : {}),\n },\n })\n }\n\n /**\n * Which camera each speaker is on, from the cameras' own microphones (`POST\n * /v1/speaker-map`), keyless. `output_data.json` is a `SpeakerMapResult`: pass\n * it to {@link cameraSwitch} as `speakerMapResult`. A malformed request throws\n * a `NodaroError` (400 `validation_error`; 422 `no_speakers` for a transcript\n * with no speaker labels) before any credits are reserved.\n */\n speakerMap(input: SpeakerMapInput): Promise<EditJobResult> {\n return this.client.request(\"POST\", \"/v1/speaker-map\", {\n body: {\n sources: input.sources.map((s) => ({ id: s.id, url: s.url, ...(s.kind ? { kind: s.kind } : {}) })),\n transcript: input.transcript,\n ...(input.offsets !== undefined ? { offsets: input.offsets } : {}),\n ...(input.masterSourceId !== undefined ? { masterSourceId: input.masterSourceId } : {}),\n ...(input.wideSourceId !== undefined ? { wideSourceId: input.wideSourceId } : {}),\n ...(input.marginDb !== undefined ? { marginDb: input.marginDb } : {}),\n ...(input.workflowId !== undefined ? { workflowId: input.workflowId } : {}),\n },\n })\n }\n\n /**\n * Render an edit decision list into a video or audio cut (`POST /v1/apply-edl`).\n * The EDL is validated at ingress — an unresolvable source or a picture-less\n * segment on a video edit throws a typed `NodaroError` (400, `code:\n * \"invalid_edl\"`) before any credits are reserved.\n */\n applyEdl(input: ApplyEdlInput): Promise<EditJobResult> {\n return this.client.request(\"POST\", \"/v1/apply-edl\", {\n body: {\n edl: input.edl,\n ...(input.sources !== undefined ? { sources: input.sources } : {}),\n ...(input.transcript !== undefined ? { transcript: input.transcript } : {}),\n ...(input.output !== undefined ? { output: input.output } : {}),\n ...(input.quality !== undefined ? { quality: input.quality } : {}),\n ...(input.crossfadeMs !== undefined ? { crossfadeMs: input.crossfadeMs } : {}),\n ...(input.clipKey !== undefined ? { clipKey: input.clipKey } : {}),\n ...(input.planBasis !== undefined ? { planBasis: input.planBasis } : {}),\n ...(input.workflowId !== undefined ? { workflowId: input.workflowId } : {}),\n },\n })\n }\n\n /**\n * Tighten Episode (`POST /v1/tighten-episode`): tighten a podcast recording\n * in one call — transcribe, cut the silences and filler, render, with\n * optional captions, music and framing. Answers the run's job to poll; its\n * `output_data` holds the episode. The run is priced as its steps at their own\n * rates plus the listed per-run fee. Quote it first with\n * {@link estimateTightenEpisode}.\n */\n tightenEpisode(input: TightenEpisodeInput, options?: UseCaseRequestOptions): Promise<TightenEpisodeJobResult> {\n return withUseCaseBody(() => tightenBody(input), (body) => this.client.request(\"POST\", \"/v1/tighten-episode\", { body, ...idempotencyHeaders(options) }))\n }\n\n /**\n * What a Tighten Episode run is estimated at (`POST /v1/tighten-episode/estimate`):\n * its steps at their own rates plus its per-run fee. Nothing is created or\n * charged. The estimate leans high: the render is priced at the recording's\n * full length, while the charge follows the minutes actually rendered.\n */\n estimateTightenEpisode(input: TightenEpisodeInput): Promise<{ data: TightenEpisodeEstimate }> {\n return withUseCaseBody(() => tightenBody(input), (body) => this.client.request(\"POST\", \"/v1/tighten-episode/estimate\", { body }))\n }\n\n /**\n * Chapters (`POST /v1/episode-chapters`): transcribe a recording and list its\n * chapters in one call. Answers the run's job to poll; the finished job's\n * `output_data.text` is the list as show notes (one `0:00 Title` line per\n * chapter; once a chapter starts at 1:00:00 or later, every line is\n * `H:MM:SS`), `output_data.json` the list itself (`{ startMs, title }[]`, the\n * same rows; the first starts at 0). A run that finds no chapters fails,\n * and its fee is refunded. Priced as its steps at their own rates plus the\n * listed per-run fee; quote it first with {@link estimateEpisodeChapters}.\n */\n episodeChapters(input: EpisodeChaptersInput, options?: UseCaseRequestOptions): Promise<UseCaseJobResult> {\n return withUseCaseBody(() => chaptersBody(input), (body) => this.client.request(\"POST\", \"/v1/episode-chapters\", { body, ...idempotencyHeaders(options) }))\n }\n\n /**\n * What a Chapters run is estimated at (`POST /v1/episode-chapters/estimate`):\n * its steps at their own rates plus its per-run fee. Nothing is created or\n * charged. A recording whose length cannot be read is estimated at the\n * 180-minute ceiling.\n */\n estimateEpisodeChapters(input: EpisodeChaptersInput): Promise<{ data: UseCaseEstimate }> {\n return withUseCaseBody(() => chaptersBody(input), (body) => this.client.request(\"POST\", \"/v1/episode-chapters/estimate\", { body }))\n }\n\n /**\n * Trailer (`POST /v1/episode-trailer`): cut a 20–40 s trailer of a recording\n * and deliver it in each chosen format (padded, never cropped), optionally\n * after an intro card, in one call. The finished job's `output_data.formats`\n * is `{ format, url }[]` in format order, the first also `output_data.videoUrl`;\n * a format that failed is named in `output_data.failedFormats` (the run keeps\n * the others). With `reviewBeforeRender` the run stops at a preview\n * (`videoUrl`, no formats yet). Priced as its steps at their own rates plus\n * the listed per-run fee; quote it first with {@link estimateEpisodeTrailer}.\n */\n episodeTrailer(input: EpisodeTrailerInput, options?: UseCaseRequestOptions): Promise<UseCaseJobResult> {\n return withUseCaseBody(() => trailerBody(input), (body) => this.client.request(\"POST\", \"/v1/episode-trailer\", { body, ...idempotencyHeaders(options) }))\n }\n\n /**\n * What a Trailer run is estimated at (`POST /v1/episode-trailer/estimate`):\n * its steps at their own rates plus its per-run fee. Nothing is created or\n * charged. The trailer is quoted at 40 seconds, the longest trailer the\n * plan cuts; a Render final is quoted on the trailer the run cut (with the\n * review's edits), plus the intro card.\n */\n estimateEpisodeTrailer(input: EpisodeTrailerInput): Promise<{ data: UseCaseEstimate }> {\n return withUseCaseBody(() => trailerBody(input), (body) => this.client.request(\"POST\", \"/v1/episode-trailer/estimate\", { body }))\n }\n\n /**\n * Clip Pack (`POST /v1/clip-pack`): cut a recording into a pack of short\n * clips in one call — the plan finds the best moments (`count`, default 8,\n * of about `targetDurationSec`, default 60), each is rendered (framed 9:16\n * with the speakers stacked by default; `framing: null` keeps the\n * recording's shape) and captioned. An audio recording makes audio clips.\n * The finished job's `output_data.clips` is `{ url, title?, hook?, clipKey,\n * thumbnailUrl?, captionsFailed? }[]` in plan order, the first also\n * `output_data.videoUrl` (`audioUrl` for audio clips). Every clip is tried:\n * one that cannot be rendered is skipped, not charged and counted on\n * `failedClips` (the pack keeps the others and its fee); a clip whose\n * captions failed comes uncaptioned (`captionsFailed`, counted on\n * `failedCaptions`). When no clip renders the run fails and its fee is\n * refunded. With `reviewBeforeRender` the run stops at previews; Render\n * final ({@link continueUseCase}) renders only the clips the edit keeps.\n * Priced as its steps at their own rates plus the listed per-run fee;\n * quote it first with {@link estimateClipPack}.\n */\n clipPack(input: ClipPackInput, options?: UseCaseRequestOptions): Promise<UseCaseJobResult> {\n return withUseCaseBody(() => clipPackBody(input), (body) => this.client.request(\"POST\", \"/v1/clip-pack\", { body, ...idempotencyHeaders(options) }))\n }\n\n /**\n * What a Clip Pack run is estimated at (`POST /v1/clip-pack/estimate`): its\n * steps at their own rates plus its per-run fee. Nothing is created or\n * charged. Each clip is quoted at twice the target length (the plan may cut\n * a clip longer than asked); the charge follows each clip's real length.\n */\n estimateClipPack(input: ClipPackInput): Promise<{ data: UseCaseEstimate }> {\n return withUseCaseBody(() => clipPackBody(input), (body) => this.client.request(\"POST\", \"/v1/clip-pack/estimate\", { body }))\n }\n\n /**\n * Speaker Layout (`POST /v1/speaker-layout`): frame a whole recording by\n * speaker in one call — the same length, nothing cut. One recording: each\n * speaker framed in turn; several recordings of one conversation: lined up,\n * each speaker shown on their own camera. The finished job's\n * `output_data.videoUrl` is the framed video, `output_data.json` the edit\n * Speaker View drew. With `reviewBeforeRender` the run stops at a preview;\n * {@link continueUseCase} (`mode: \"render-final\"`, no `editedEdl`) renders\n * it at full quality. Priced as its steps at their own rates plus the listed\n * per-run fee; quote it first with {@link estimateSpeakerLayout}.\n */\n speakerLayout(input: SpeakerLayoutInput, options?: UseCaseRequestOptions): Promise<UseCaseJobResult> {\n return withUseCaseBody(() => speakerLayoutBody(input), (body) => this.client.request(\"POST\", \"/v1/speaker-layout\", { body, ...idempotencyHeaders(options) }))\n }\n\n /**\n * What a Speaker Layout run is estimated at (`POST /v1/speaker-layout/estimate`):\n * its steps at their own rates plus its per-run fee. Nothing is created or\n * charged. A recording whose length cannot be read is estimated at the\n * 180-minute ceiling.\n */\n estimateSpeakerLayout(input: SpeakerLayoutInput): Promise<{ data: UseCaseEstimate }> {\n return withUseCaseBody(() => speakerLayoutBody(input), (body) => this.client.request(\"POST\", \"/v1/speaker-layout/estimate\", { body }))\n }\n\n /**\n * Continue a use-case run as a new job (`POST /v1/<type>/continue`, the\n * run's own type: `input.nodeType`, else the type the job records, read with\n * `GET /v1/jobs/:id`; when that read cannot tell, this rejects with a\n * `NodaroError` coded `use_case_type_unknown` — pass `nodeType` then):\n * `\"from-failed\"` keeps the steps that finished and runs the rest (the fee\n * is held again; the failed run's was refunded);\n * `\"render-final\"` renders the full-quality result after a review-on preview,\n * with the preview's settings and no fee. A refusal that names another job\n * (`already_running`, `continuation_superseded`,\n * `render_final_already_rendered`) throws a `ContinuationRefusedError`\n * carrying that `jobId`.\n */\n async continueUseCase(input: UseCaseContinueInput, options?: UseCaseRequestOptions): Promise<UseCaseJobResult> {\n if (input.nodeType !== undefined && !isUseCaseNodeType(input.nodeType)) {\n throw new NodaroError(\n `continueUseCase: nodeType \"${String(input.nodeType)}\" is not a use-case node type (${USE_CASE_NODE_TYPES.join(\", \")})`,\n \"invalid_node_type\",\n 400,\n )\n }\n const type = input.nodeType ?? (await this.runTypeOf(input.jobId))\n return this.client.request(\"POST\", continuePathOf(type), {\n body: { jobId: input.jobId, mode: input.mode, ...(input.editedEdl !== undefined ? { editedEdl: input.editedEdl } : {}) },\n ...idempotencyHeaders(options),\n })\n }\n\n /**\n * The use-case type a run records (`input_data.type`, else its `job_type`).\n * When the key lacks the `jobs:read` scope (403 naming that scope) or the job\n * names no use-case type, the type cannot be read: this rejects with a\n * `NodaroError` (`use_case_type_unknown`, 400) asking for `nodeType`, and\n * nothing is posted (decided 2026-10-18: no route is guessed for the run).\n * Any other failure of the read, any other 403 included, is thrown as is.\n */\n private async runTypeOf(jobId: string): Promise<UseCaseNodeType> {\n const unknown = () =>\n new NodaroError(\"continueUseCase: the run's node type cannot be read — pass nodeType\", \"use_case_type_unknown\", 400)\n let row: { job_type?: unknown; input_data?: unknown } | undefined\n try {\n row = (await this.client.request<{ data?: { job_type?: unknown; input_data?: unknown } }>(\"GET\", `/v1/jobs/${encodeURIComponent(jobId)}`)).data\n } catch (err) {\n if (err instanceof ForbiddenError && err.missingScope === \"jobs:read\") throw unknown()\n throw err\n }\n const input = row?.input_data\n const recorded = input && typeof input === \"object\" && !Array.isArray(input) ? (input as { type?: unknown }).type : undefined\n const type = typeof recorded === \"string\" && recorded.length > 0 ? recorded : row?.job_type\n if (!isUseCaseNodeType(type)) throw unknown()\n return type\n }\n\n /**\n * Plan a transcript-driven cut (`POST /v1/edit-plan`). Reads a timed\n * transcript (plus optional silence ranges) and the media sources, and plans\n * the edit. The finished job's `output_data` holds the plan: an `Edl`\n * (`\"tighten\"` or `\"trailer\"`), an {@link EdlClipSet} (`\"clips\"`), or a\n * {@link ChapterSet} (`\"chapters\"`) — normalize it with {@link unwrapEditPlanOutput}.\n *\n * On a self-hosted install the request relays to nodaro.ai and needs the\n * install connected (a 503 `code: \"nodaro_connection_required\"` otherwise);\n * on nodaro.ai it runs directly.\n */\n editPlan(input: EditPlanInput): Promise<EditJobResult> {\n // The same pre-dispatch check the canvas and MCP run (B4): the server never\n // sees `offsets` — they are written onto the sources here.\n const planned = resolveEditPlanSources(input.sources, {\n offsets: input.offsets,\n transcriptSourceId: input.transcriptSourceId,\n })\n if (!planned.ok) {\n const message = planned.issues.map((issue) => describeAudioSyncOffsetIssue(issue)).join(\"; \")\n return Promise.reject(new NodaroError(`editPlan: ${message}`, \"edit_plan_sources\", 400))\n }\n const transcript = planned.transcriptSourceId\n ? { ...input.transcript, sourceId: planned.transcriptSourceId }\n : input.transcript\n return this.client.request(\"POST\", \"/v1/edit-plan\", {\n body: {\n mode: input.mode,\n planTier: input.planTier,\n transcript,\n sources: planned.sources,\n ...(input.silence !== undefined ? { silence: input.silence } : {}),\n ...(input.instructions !== undefined ? { instructions: input.instructions } : {}),\n ...(input.styleGuide !== undefined ? { styleGuide: input.styleGuide } : {}),\n ...(input.count !== undefined ? { count: input.count } : {}),\n ...(input.targetDurationSec !== undefined ? { targetDurationSec: input.targetDurationSec } : {}),\n ...(input.targetAspect !== undefined ? { targetAspect: input.targetAspect } : {}),\n ...(input.platform !== undefined ? { platform: input.platform } : {}),\n ...(input.workflowId !== undefined ? { workflowId: input.workflowId } : {}),\n },\n })\n }\n\n /**\n * Camera Switch (podcast B5): choose which camera shows each cut of `edl`\n * by who is speaking — the sound never changes. Cloud edition; a flat\n * price. The finished job's `output_data.json` is the switched EDL (feed it\n * to {@link applyEdl}) and `output_data.transcript` the transcript with\n * `speakerNames` applied. A transcript with no speaker labels rejects with\n * a {@link NodaroError} (`code: \"no_speakers\"`) before any request or charge.\n */\n cameraSwitch(input: CameraSwitchInput): Promise<EditJobResult> {\n if (transcriptSpeakerLabels(input.transcript).length === 0) {\n return Promise.reject(new NodaroError(\n \"cameraSwitch: the transcript has no speaker labels — transcribe with speaker detection on\",\n \"no_speakers\",\n 422,\n ))\n }\n const result = input.speakerMapResult\n if (result !== undefined && !speakerMapResultOf(result)) return Promise.reject(new NodaroError(\"cameraSwitch: speakerMapResult is not a Speaker Map result — pass that job's output_data.json\", \"not_a_speaker_map\", 400))\n const speakerMap = result !== undefined ? cameraSwitchSpeakerMap({ speakerMap: input.speakerMap }, input.edl, input.transcript, { speakerMap: result }) : input.speakerMap\n return this.client.request(\"POST\", \"/v1/camera-switch\", {\n body: {\n edl: input.edl,\n transcript: input.transcript,\n ...(speakerMap !== undefined ? { speakerMap } : {}),\n ...(input.speakerNames !== undefined ? { speakerNames: input.speakerNames } : {}),\n ...(input.minShotMs !== undefined ? { minShotMs: input.minShotMs } : {}),\n ...(input.leadMs !== undefined ? { leadMs: input.leadMs } : {}),\n ...(input.maxShotMs !== undefined ? { maxShotMs: input.maxShotMs } : {}),\n ...(input.wideEvery !== undefined ? { wideEvery: input.wideEvery } : {}),\n ...(input.layoutHints !== undefined ? { layoutHints: input.layoutHints } : {}),\n ...(input.workflowId !== undefined ? { workflowId: input.workflowId } : {}),\n },\n })\n }\n\n /**\n * Remap a transcript through an EDL — a PURE client-side transform (NO\n * request). Returns a new transcript whose word (and segment) timings are on\n * the EDL's rendered output clock, dropping words that fall in cut regions and\n * clipping straddlers. Runs `@nodaro/shared`'s canonical\n * `remapTranscriptThroughEdl`, the same remap `applyEdl` performs server-side.\n */\n remapTranscript(edl: Edl, transcript: Transcript): Transcript {\n return remapTranscriptThroughEdl(edl, transcript)\n }\n}\n"]}
@@ -22,6 +22,29 @@ var UploadsResource = class {
22
22
  );
23
23
  return res.data;
24
24
  }
25
+ /**
26
+ * Copy a picture from a web address into your storage
27
+ * (`POST /v1/media/import-url`, body `{ url }`). The platform fetches it
28
+ * (http(s) only, never a private address, up to 20 MB), keeps it only if it
29
+ * decodes as an image (JPEG, PNG, WebP, GIF; HEIC/HEIF and AVIF are
30
+ * converted to JPEG or PNG), and stores it as an upload of yours, so its address serves
31
+ * the pixels to the browser (a canvas can read it). Returns the stored
32
+ * picture (unwraps the `{ data }` envelope).
33
+ *
34
+ * Throws `StorageExceededError` on a 413, its `reason` telling the two
35
+ * apart: `storage_limit_exceeded` is a full storage (the quota is in
36
+ * `details` — `usedBytes`, `quotaBytes`, `remainingBytes`, `tier`), and
37
+ * `file_too_large` a picture over 20 MB. Throws a `NodaroError` with `code`
38
+ * `validation_error` (400: not an http(s) address, or not an image) or
39
+ * `fetch_failed` (422: the address could not be reached or answered with an
40
+ * error).
41
+ */
42
+ async importUrl(url) {
43
+ const res = await this.client.request("POST", "/v1/media/import-url", {
44
+ body: { url }
45
+ });
46
+ return res.data;
47
+ }
25
48
  /**
26
49
  * Store a JSON document (`POST /v1/upload-json`, up to 25 MB) and get its
27
50
  * public URL — e.g. an image editor's design state, passed to
@@ -35,5 +58,5 @@ var UploadsResource = class {
35
58
  };
36
59
 
37
60
  export { UploadsResource };
38
- //# sourceMappingURL=chunk-WY4QRJZW.js.map
39
- //# sourceMappingURL=chunk-WY4QRJZW.js.map
61
+ //# sourceMappingURL=chunk-DTYN7QAZ.js.map
62
+ //# sourceMappingURL=chunk-DTYN7QAZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/resources/uploads.ts"],"names":[],"mappings":";AA4BO,IAAM,kBAAN,MAAsB;AAAA,EAC3B,YAAoB,MAAA,EAA0B;AAA1B,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AAAA,EAA2B;AAAA,EAA3B,MAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUpB,MAAM,OAAO,IAAA,EAAmC;AAC9C,IAAA,MAAM,IAAA,GAAO,IAAI,QAAA,EAAS;AAC1B,IAAA,IAAA,CAAK,MAAA,CAAO,QAAQ,IAAI,CAAA;AACxB,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,MAAA,CAAO,OAAA;AAAA,MAC5B,MAAA;AAAA,MACA,YAAA;AAAA,MACA,EAAE,MAAM,IAAA;AAAK,KACf;AACA,IAAA,OAAO,GAAA,CAAI,IAAA;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBA,MAAM,UAAU,GAAA,EAAuC;AACrD,IAAA,MAAM,MAAM,MAAM,IAAA,CAAK,MAAA,CAAO,OAAA,CAAmC,QAAQ,sBAAA,EAAwB;AAAA,MAC/F,IAAA,EAAM,EAAE,GAAA;AAAI,KACb,CAAA;AACD,IAAA,OAAO,GAAA,CAAI,IAAA;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,WAAW,IAAA,EAA+E;AACxF,IAAA,OAAO,IAAA,CAAK,OAAO,OAAA,CAA0B,MAAA,EAAQ,mBAAmB,EAAE,IAAA,EAAM,MAAM,CAAA;AAAA,EACxF;AACF","file":"chunk-DTYN7QAZ.js","sourcesContent":["import type { NodaroClientCore } from \"../core.js\"\n\n/**\n * Result of a successful `POST /v1/upload`. Mirrors the route's `data` envelope\n * (`backend/src/routes/upload.ts`), the source of truth — keep in sync if that\n * response changes. The route also returns loosely-typed extracted `metadata`;\n * it is omitted here until a consumer needs a typed shape (add it shaped to\n * that need rather than inventing `Record<string, unknown>` surface now).\n */\nexport interface UploadResult {\n /** Public R2 URL of the stored asset (always present on success). */\n readonly url: string\n /** Storage row id; `null` when no asset row was written (e.g. unauthenticated). */\n readonly assetId: string | null\n /** Generated thumbnail URL (images/video); `null` for audio or on failure. */\n readonly thumbnailUrl: string | null\n /** Server-classified asset category (e.g. \"image\" | \"video\" | \"audio\"). */\n readonly category: string\n /** Display filename (server override or the original). */\n readonly filename: string\n /** Final MIME type after server normalization. */\n readonly mimeType: string\n /** Stored byte size. */\n readonly sizeBytes: number\n /** R2 object key. */\n readonly r2Key: string\n}\n\nexport class UploadsResource {\n constructor(private client: NodaroClientCore) {}\n\n /**\n * Upload one file (`POST /v1/upload`, multipart — the file rides the `file`\n * field). The SDK's `request` detects the `FormData` body and lets the\n * runtime set the multipart boundary. Returns the persisted asset's public\n * URL + storage metadata (unwraps the `{ data }` envelope). Throws\n * `StorageExceededError` (413) over the storage cap and the SDK's other typed\n * errors on the usual statuses.\n */\n async upload(file: File): Promise<UploadResult> {\n const form = new FormData()\n form.append(\"file\", file)\n const res = await this.client.request<{ data: UploadResult }>(\n \"POST\",\n \"/v1/upload\",\n { body: form },\n )\n return res.data\n }\n\n /**\n * Copy a picture from a web address into your storage\n * (`POST /v1/media/import-url`, body `{ url }`). The platform fetches it\n * (http(s) only, never a private address, up to 20 MB), keeps it only if it\n * decodes as an image (JPEG, PNG, WebP, GIF; HEIC/HEIF and AVIF are\n * converted to JPEG or PNG), and stores it as an upload of yours, so its address serves\n * the pixels to the browser (a canvas can read it). Returns the stored\n * picture (unwraps the `{ data }` envelope).\n *\n * Throws `StorageExceededError` on a 413, its `reason` telling the two\n * apart: `storage_limit_exceeded` is a full storage (the quota is in\n * `details` — `usedBytes`, `quotaBytes`, `remainingBytes`, `tier`), and\n * `file_too_large` a picture over 20 MB. Throws a `NodaroError` with `code`\n * `validation_error` (400: not an http(s) address, or not an image) or\n * `fetch_failed` (422: the address could not be reached or answered with an\n * error).\n */\n async importUrl(url: string): Promise<ImportUrlResult> {\n const res = await this.client.request<{ data: ImportUrlResult }>(\"POST\", \"/v1/media/import-url\", {\n body: { url },\n })\n return res.data\n }\n\n /**\n * Store a JSON document (`POST /v1/upload-json`, up to 25 MB) and get its\n * public URL — e.g. an image editor's design state, passed to\n * `client.jobs.fromUpload` as `editStateUrl` so the edit can be reopened.\n * The URL is unguessable but public: never store a secret in it. Creates no\n * library item.\n */\n uploadJson(json: Record<string, unknown> | readonly unknown[]): Promise<UploadJsonResult> {\n return this.client.request<UploadJsonResult>(\"POST\", \"/v1/upload-json\", { body: json })\n }\n}\n\n/** Result of {@link UploadsResource.uploadJson}. */\nexport interface UploadJsonResult {\n /** Public URL of the stored JSON document. */\n readonly url: string\n}\n\n/**\n * Result of {@link UploadsResource.importUrl}. Mirrors the route's `data`:\n * the fields of {@link UploadResult} it shares, plus the picture's size.\n */\nexport interface ImportUrlResult {\n /** Public URL of the stored picture. */\n readonly url: string\n /** Generated thumbnail URL; `null` when it could not be made. */\n readonly thumbnailUrl: string | null\n /** Storage row id; `null` when no asset row was written. */\n readonly assetId: string | null\n /** Final MIME type (a HEIC/HEIF or AVIF source is stored as JPEG or PNG). */\n readonly mimeType: string\n /** Stored byte size. */\n readonly sizeBytes: number\n /** Display filename: the address's last path segment, else `imported-<id>.<ext>`. */\n readonly filename: string\n /** Width in pixels; 0 when it could not be read. */\n readonly width: number\n /** Height in pixels; 0 when it could not be read. */\n readonly height: number\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { TutorialsResource } from './chunk-HPXE3NZW.js';
2
- import { UploadsResource } from './chunk-WY4QRJZW.js';
2
+ import { UploadsResource } from './chunk-DTYN7QAZ.js';
3
3
  import { UserSettingsResource } from './chunk-LR5TGCJP.js';
4
4
  import { VideoProResource } from './chunk-ERLXU47J.js';
5
5
  import { VoicesResource } from './chunk-T7N7DFQJ.js';
@@ -10,7 +10,7 @@ import { SavedPostsResource } from './chunk-NCCBS6GU.js';
10
10
  import { Scene3DResource } from './chunk-NNHWH7ER.js';
11
11
  import { SessionsResource } from './chunk-WS4ZQ4AA.js';
12
12
  import { ShotsResource } from './chunk-WVFAQBS7.js';
13
- import { StudioResource } from './chunk-BGOZRZHY.js';
13
+ import { StudioResource } from './chunk-VTL4DBX4.js';
14
14
  import { TemplatesResource } from './chunk-M7VSFZMV.js';
15
15
  import { TrashResource } from './chunk-2SQ7V6EX.js';
16
16
  import { TrendsResource } from './chunk-HFYNZ4SO.js';
@@ -23,14 +23,14 @@ import { PromptHelperResource } from './chunk-OIPPTBW4.js';
23
23
  import { RecastResource } from './chunk-AJVSMNPZ.js';
24
24
  import { ReduceResource } from './chunk-IHKIYVZQ.js';
25
25
  import { LocationsResource } from './chunk-XZPSJG2X.js';
26
- import { MediaResource } from './chunk-VEQLP5TA.js';
26
+ import { MediaResource } from './chunk-ND7JMM5H.js';
27
27
  import { ModelsResource } from './chunk-Y6V6CBY5.js';
28
28
  import { MoodboardsResource } from './chunk-YVU2M7MI.js';
29
29
  import { PresetsResource } from './chunk-AEUPH7EE.js';
30
- import { NodesResource } from './chunk-FTCAT2LK.js';
30
+ import { NodesResource } from './chunk-ALDXFMD7.js';
31
31
  import { OAuthResource } from './chunk-Z7LGWNI7.js';
32
32
  import { ObjectsResource } from './chunk-GIQDM2MH.js';
33
- import { EditResource } from './chunk-E6X6BGRO.js';
33
+ import { EditResource } from './chunk-MUHRK4OI.js';
34
34
  import { ExecutionsResource } from './chunk-Z3ZKFI2M.js';
35
35
  import { GalleryResource } from './chunk-JDEZHITT.js';
36
36
  import { JobsResource } from './chunk-HJLSOT5C.js';
@@ -40,8 +40,8 @@ import { LlmResource } from './chunk-E37CVHWW.js';
40
40
  import { CollectionsResource } from './chunk-4WRDR4GN.js';
41
41
  import { CommunityResource } from './chunk-SFB4YLCS.js';
42
42
  import { CompetitorsResource } from './chunk-BU5A6K4C.js';
43
- import { CopilotResource } from './chunk-HK6XP5EN.js';
44
- import { NodaroClientCore } from './chunk-37LL6BPM.js';
43
+ import { CopilotResource } from './chunk-RCD4HDBI.js';
44
+ import { NodaroClientCore } from './chunk-SOR6K3XZ.js';
45
45
  import { CreaturesResource } from './chunk-HUYI5G3D.js';
46
46
  import { CreditsResource } from './chunk-7QK2NXJA.js';
47
47
  import { DeveloperAppsResource } from './chunk-65E3JBFZ.js';
@@ -200,5 +200,5 @@ function createClient(opts) {
200
200
  }
201
201
 
202
202
  export { NodaroClient, createClient };
203
- //# sourceMappingURL=chunk-PQ6G5EM7.js.map
204
- //# sourceMappingURL=chunk-PQ6G5EM7.js.map
203
+ //# sourceMappingURL=chunk-EDSODRRY.js.map
204
+ //# sourceMappingURL=chunk-EDSODRRY.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts"],"names":[],"mappings":"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","file":"chunk-PQ6G5EM7.js","sourcesContent":["import { WorkflowsResource } from \"./resources/workflows.js\"\nimport { ProjectsResource } from \"./resources/projects.js\"\nimport { SessionsResource } from \"./resources/sessions.js\"\nimport { TrashResource } from \"./resources/trash.js\"\nimport { JobsResource } from \"./resources/jobs.js\"\nimport { VideoProResource } from \"./resources/video-pro.js\"\nimport { ExecutionsResource } from \"./resources/executions.js\"\nimport { NodesResource } from \"./resources/nodes.js\"\nimport { Scene3DResource } from \"./resources/scene3d.js\"\nimport { DeveloperAppsResource } from \"./resources/developer-apps.js\"\nimport { OAuthResource } from \"./resources/oauth.js\"\nimport { WebhooksResource } from \"./resources/webhooks.js\"\nimport { AppsResource } from \"./resources/apps.js\"\nimport { CharactersResource } from \"./resources/characters.js\"\nimport { LocationsResource } from \"./resources/locations.js\"\nimport { ObjectsResource } from \"./resources/objects.js\"\nimport { CreaturesResource } from \"./resources/creatures.js\"\nimport { KeepersResource } from \"./resources/keepers.js\"\nimport { PipelinesResource } from \"./resources/pipelines.js\"\nimport { ReduceResource } from \"./resources/reduce.js\"\nimport { PromptHelperResource } from \"./resources/prompt-helper.js\"\nimport { VoicesResource } from \"./resources/voices.js\"\nimport { LlmResource } from \"./resources/llm.js\"\nimport { MediaResource } from \"./resources/media.js\"\nimport { AudioResource } from \"./resources/audio.js\"\nimport { CreditsResource } from \"./resources/credits.js\"\nimport { BillingResource } from \"./resources/billing.js\"\nimport { UserSettingsResource } from \"./resources/user-settings.js\"\nimport { UploadsResource } from \"./resources/uploads.js\"\nimport { LibraryResource } from \"./resources/library.js\"\nimport { GalleryResource } from \"./resources/gallery.js\"\nimport { PresetsResource } from \"./resources/node-presets.js\"\nimport { SavedPostsResource } from \"./resources/saved-posts.js\"\nimport { CollectionsResource } from \"./resources/collections.js\"\nimport { PalettesResource } from \"./resources/palettes.js\"\nimport { MoodboardsResource } from \"./resources/moodboards.js\"\nimport { CompetitorsResource } from \"./resources/competitors.js\"\nimport { PickerCatalogsResource } from \"./resources/picker-catalogs.js\"\nimport { CatalogsResource } from \"./resources/catalogs.js\"\nimport { ModelsResource } from \"./resources/models.js\"\nimport { ShotsResource } from \"./resources/shots.js\"\nimport { RecastResource } from \"./resources/recast.js\"\nimport { CastSwapResource } from \"./resources/cast-swap.js\"\nimport { TrendsResource } from \"./resources/trends.js\"\nimport { StudioResource } from \"./resources/studio.js\"\nimport { CopilotResource } from \"./resources/copilot.js\"\nimport { CommunityResource } from \"./resources/community.js\"\nimport { TemplatesResource } from \"./resources/templates.js\"\nimport { TutorialsResource } from \"./resources/tutorials.js\"\nimport { OrganizationsResource } from \"./resources/organizations.js\"\nimport { WorkspacesResource } from \"./resources/workspaces.js\"\nimport { EditResource } from \"./resources/edit.js\"\nimport { NodaroClientCore, type ClientOptions } from \"./core.js\"\n\nexport { CLIENT_HEADER } from \"./core.js\"\nexport type { ClientOptions, UserIdentity, ConnectedApp } from \"./core.js\"\n\n/**\n * The full client: the core (`./core.ts` — config, transport, identity) and\n * every resource.\n */\nexport class NodaroClient extends NodaroClientCore {\n readonly workflows: WorkflowsResource\n readonly projects: ProjectsResource\n /** Generation sessions inside projects (Create Image / Video / Music). */\n readonly sessions: SessionsResource\n /** Your Trash: items removed from sessions and deleted jobs. */\n readonly trash: TrashResource\n readonly jobs: JobsResource\n readonly videoPro: VideoProResource\n readonly executions: ExecutionsResource\n readonly nodes: NodesResource\n readonly scene3d: Scene3DResource\n readonly developerApps: DeveloperAppsResource\n readonly oauth: OAuthResource\n /** Outbound webhooks: endpoints that receive your job.completed / job.failed. */\n readonly webhooks: WebhooksResource\n readonly apps: AppsResource\n readonly characters: CharactersResource\n readonly locations: LocationsResource\n readonly objects: ObjectsResource\n readonly creatures: CreaturesResource\n /** The shared Nodaro Keepers catalog of characters, creatures, locations and objects. */\n readonly keepers: KeepersResource\n readonly pipelines: PipelinesResource\n readonly reduce: ReduceResource\n readonly promptHelper: PromptHelperResource\n readonly voices: VoicesResource\n readonly llm: LlmResource\n readonly media: MediaResource\n readonly audio: AudioResource\n readonly credits: CreditsResource\n /** The signed-in person's own settings (the interface language, the monthly statement opt-in, …). */\n readonly userSettings: UserSettingsResource\n /** Plans and prices, the subscription, and how this deployment bills. */\n readonly billing: BillingResource\n readonly uploads: UploadsResource\n readonly library: LibraryResource\n /** The public gallery and your favorites. */\n readonly gallery: GalleryResource\n readonly presets: PresetsResource\n readonly savedPosts: SavedPostsResource\n readonly collections: CollectionsResource\n /** Your colour palettes — a generate-image direction (`direction.colorLook: paletteDirectionId(id)`). */\n readonly palettes: PalettesResource\n /** Your moodboards — a generate-image direction (`direction.style: moodboardDirectionId(id)`). */\n readonly moodboards: MoodboardsResource\n readonly competitors: CompetitorsResource\n readonly pickerCatalogs: PickerCatalogsResource\n readonly catalogs: CatalogsResource\n readonly models: ModelsResource\n readonly shots: ShotsResource\n readonly recast: RecastResource\n /** Cast Swap: replace the people and/or location in a short video (Cloud). */\n readonly castSwap: CastSwapResource\n /** Trends: ready-made Cast Swap recipes you fill with your own pictures (Cloud). */\n readonly trends: TrendsResource\n readonly studio: StudioResource\n readonly copilot: CopilotResource\n readonly community: CommunityResource\n readonly templates: TemplatesResource\n readonly tutorials: TutorialsResource\n readonly organizations: OrganizationsResource\n readonly workspaces: WorkspacesResource\n readonly edit: EditResource\n\n constructor(opts: ClientOptions) {\n super(opts)\n\n this.workflows = new WorkflowsResource(this)\n this.projects = new ProjectsResource(this)\n this.sessions = new SessionsResource(this)\n this.trash = new TrashResource(this)\n this.jobs = new JobsResource(this)\n this.videoPro = new VideoProResource(this)\n this.executions = new ExecutionsResource(this)\n this.nodes = new NodesResource(this)\n this.scene3d = new Scene3DResource(this)\n this.developerApps = new DeveloperAppsResource(this)\n this.oauth = new OAuthResource(this)\n this.webhooks = new WebhooksResource(this)\n this.apps = new AppsResource(this)\n this.characters = new CharactersResource(this)\n this.locations = new LocationsResource(this)\n this.objects = new ObjectsResource(this)\n this.creatures = new CreaturesResource(this)\n this.keepers = new KeepersResource(this)\n this.pipelines = new PipelinesResource(this)\n this.reduce = new ReduceResource(this)\n this.promptHelper = new PromptHelperResource(this)\n this.voices = new VoicesResource(this)\n this.llm = new LlmResource(this)\n this.media = new MediaResource(this)\n this.audio = new AudioResource(this)\n this.credits = new CreditsResource(this)\n this.userSettings = new UserSettingsResource(this)\n this.billing = new BillingResource(this)\n this.uploads = new UploadsResource(this)\n this.library = new LibraryResource(this)\n this.gallery = new GalleryResource(this)\n this.presets = new PresetsResource(this)\n this.savedPosts = new SavedPostsResource(this)\n this.collections = new CollectionsResource(this)\n this.palettes = new PalettesResource(this)\n this.moodboards = new MoodboardsResource(this)\n this.competitors = new CompetitorsResource(this)\n this.pickerCatalogs = new PickerCatalogsResource(this)\n this.catalogs = new CatalogsResource(this)\n this.models = new ModelsResource(this)\n this.shots = new ShotsResource(this)\n this.recast = new RecastResource(this)\n this.castSwap = new CastSwapResource(this)\n this.trends = new TrendsResource(this)\n this.studio = new StudioResource(this)\n this.copilot = new CopilotResource(this)\n this.community = new CommunityResource(this)\n this.templates = new TemplatesResource(this)\n this.tutorials = new TutorialsResource(this)\n this.organizations = new OrganizationsResource(this)\n this.workspaces = new WorkspacesResource(this)\n this.edit = new EditResource(this)\n }\n\n /**\n * A client that acts in `workspaceId`, sharing this one's auth and config.\n *\n * A NEW client rather than a setter, deliberately. A mutable selection is\n * the bug this whole axis exists to prevent: two concurrent operations\n * against one client would race over which workspace they were in, and the\n * loser would create work in the wrong place with nothing failing. A\n * per-workspace client cannot be raced.\n *\n * Pass `null` for the personal space.\n */\n withWorkspace(workspaceId: string | null): NodaroClient {\n // The two private settings are read by bracket access, which TypeScript\n // allows on a subclass and which adds no member to the declarations. Read\n // through `this` (not a side table keyed by the instance), so a client\n // wrapped in a Proxy (Vue/Pinia `reactive()`) or reached through\n // `Object.create(client)` still works.\n const fetchOverride = this[\"fetchOverride\"]\n return new NodaroClient({\n baseUrl: this.baseUrl,\n auth: this.auth,\n timeoutMs: this.timeoutMs,\n ...(fetchOverride ? { fetch: fetchOverride } : {}),\n ...(this[\"sendClientHeader\"] ? { clientLabel: this.clientLabel } : {}),\n ...(workspaceId ? { workspaceId } : {}),\n })\n }\n}\n\n/** Factory function — preferred entry point. */\nexport function createClient(opts: ClientOptions): NodaroClient {\n return new NodaroClient(opts)\n}\n"]}
1
+ {"version":3,"sources":["../src/client.ts"],"names":[],"mappings":"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","file":"chunk-EDSODRRY.js","sourcesContent":["import { WorkflowsResource } from \"./resources/workflows.js\"\nimport { ProjectsResource } from \"./resources/projects.js\"\nimport { SessionsResource } from \"./resources/sessions.js\"\nimport { TrashResource } from \"./resources/trash.js\"\nimport { JobsResource } from \"./resources/jobs.js\"\nimport { VideoProResource } from \"./resources/video-pro.js\"\nimport { ExecutionsResource } from \"./resources/executions.js\"\nimport { NodesResource } from \"./resources/nodes.js\"\nimport { Scene3DResource } from \"./resources/scene3d.js\"\nimport { DeveloperAppsResource } from \"./resources/developer-apps.js\"\nimport { OAuthResource } from \"./resources/oauth.js\"\nimport { WebhooksResource } from \"./resources/webhooks.js\"\nimport { AppsResource } from \"./resources/apps.js\"\nimport { CharactersResource } from \"./resources/characters.js\"\nimport { LocationsResource } from \"./resources/locations.js\"\nimport { ObjectsResource } from \"./resources/objects.js\"\nimport { CreaturesResource } from \"./resources/creatures.js\"\nimport { KeepersResource } from \"./resources/keepers.js\"\nimport { PipelinesResource } from \"./resources/pipelines.js\"\nimport { ReduceResource } from \"./resources/reduce.js\"\nimport { PromptHelperResource } from \"./resources/prompt-helper.js\"\nimport { VoicesResource } from \"./resources/voices.js\"\nimport { LlmResource } from \"./resources/llm.js\"\nimport { MediaResource } from \"./resources/media.js\"\nimport { AudioResource } from \"./resources/audio.js\"\nimport { CreditsResource } from \"./resources/credits.js\"\nimport { BillingResource } from \"./resources/billing.js\"\nimport { UserSettingsResource } from \"./resources/user-settings.js\"\nimport { UploadsResource } from \"./resources/uploads.js\"\nimport { LibraryResource } from \"./resources/library.js\"\nimport { GalleryResource } from \"./resources/gallery.js\"\nimport { PresetsResource } from \"./resources/node-presets.js\"\nimport { SavedPostsResource } from \"./resources/saved-posts.js\"\nimport { CollectionsResource } from \"./resources/collections.js\"\nimport { PalettesResource } from \"./resources/palettes.js\"\nimport { MoodboardsResource } from \"./resources/moodboards.js\"\nimport { CompetitorsResource } from \"./resources/competitors.js\"\nimport { PickerCatalogsResource } from \"./resources/picker-catalogs.js\"\nimport { CatalogsResource } from \"./resources/catalogs.js\"\nimport { ModelsResource } from \"./resources/models.js\"\nimport { ShotsResource } from \"./resources/shots.js\"\nimport { RecastResource } from \"./resources/recast.js\"\nimport { CastSwapResource } from \"./resources/cast-swap.js\"\nimport { TrendsResource } from \"./resources/trends.js\"\nimport { StudioResource } from \"./resources/studio.js\"\nimport { CopilotResource } from \"./resources/copilot.js\"\nimport { CommunityResource } from \"./resources/community.js\"\nimport { TemplatesResource } from \"./resources/templates.js\"\nimport { TutorialsResource } from \"./resources/tutorials.js\"\nimport { OrganizationsResource } from \"./resources/organizations.js\"\nimport { WorkspacesResource } from \"./resources/workspaces.js\"\nimport { EditResource } from \"./resources/edit.js\"\nimport { NodaroClientCore, type ClientOptions } from \"./core.js\"\n\nexport { CLIENT_HEADER } from \"./core.js\"\nexport type { ClientOptions, UserIdentity, ConnectedApp } from \"./core.js\"\n\n/**\n * The full client: the core (`./core.ts` — config, transport, identity) and\n * every resource.\n */\nexport class NodaroClient extends NodaroClientCore {\n readonly workflows: WorkflowsResource\n readonly projects: ProjectsResource\n /** Generation sessions inside projects (Create Image / Video / Music). */\n readonly sessions: SessionsResource\n /** Your Trash: items removed from sessions and deleted jobs. */\n readonly trash: TrashResource\n readonly jobs: JobsResource\n readonly videoPro: VideoProResource\n readonly executions: ExecutionsResource\n readonly nodes: NodesResource\n readonly scene3d: Scene3DResource\n readonly developerApps: DeveloperAppsResource\n readonly oauth: OAuthResource\n /** Outbound webhooks: endpoints that receive your job.completed / job.failed. */\n readonly webhooks: WebhooksResource\n readonly apps: AppsResource\n readonly characters: CharactersResource\n readonly locations: LocationsResource\n readonly objects: ObjectsResource\n readonly creatures: CreaturesResource\n /** The shared Nodaro Keepers catalog of characters, creatures, locations and objects. */\n readonly keepers: KeepersResource\n readonly pipelines: PipelinesResource\n readonly reduce: ReduceResource\n readonly promptHelper: PromptHelperResource\n readonly voices: VoicesResource\n readonly llm: LlmResource\n readonly media: MediaResource\n readonly audio: AudioResource\n readonly credits: CreditsResource\n /** The signed-in person's own settings (the interface language, the monthly statement opt-in, …). */\n readonly userSettings: UserSettingsResource\n /** Plans and prices, the subscription, and how this deployment bills. */\n readonly billing: BillingResource\n readonly uploads: UploadsResource\n readonly library: LibraryResource\n /** The public gallery and your favorites. */\n readonly gallery: GalleryResource\n readonly presets: PresetsResource\n readonly savedPosts: SavedPostsResource\n readonly collections: CollectionsResource\n /** Your colour palettes — a generate-image direction (`direction.colorLook: paletteDirectionId(id)`). */\n readonly palettes: PalettesResource\n /** Your moodboards — a generate-image direction (`direction.style: moodboardDirectionId(id)`). */\n readonly moodboards: MoodboardsResource\n readonly competitors: CompetitorsResource\n readonly pickerCatalogs: PickerCatalogsResource\n readonly catalogs: CatalogsResource\n readonly models: ModelsResource\n readonly shots: ShotsResource\n readonly recast: RecastResource\n /** Cast Swap: replace the people and/or location in a short video (Cloud). */\n readonly castSwap: CastSwapResource\n /** Trends: ready-made Cast Swap recipes you fill with your own pictures (Cloud). */\n readonly trends: TrendsResource\n readonly studio: StudioResource\n readonly copilot: CopilotResource\n readonly community: CommunityResource\n readonly templates: TemplatesResource\n readonly tutorials: TutorialsResource\n readonly organizations: OrganizationsResource\n readonly workspaces: WorkspacesResource\n readonly edit: EditResource\n\n constructor(opts: ClientOptions) {\n super(opts)\n\n this.workflows = new WorkflowsResource(this)\n this.projects = new ProjectsResource(this)\n this.sessions = new SessionsResource(this)\n this.trash = new TrashResource(this)\n this.jobs = new JobsResource(this)\n this.videoPro = new VideoProResource(this)\n this.executions = new ExecutionsResource(this)\n this.nodes = new NodesResource(this)\n this.scene3d = new Scene3DResource(this)\n this.developerApps = new DeveloperAppsResource(this)\n this.oauth = new OAuthResource(this)\n this.webhooks = new WebhooksResource(this)\n this.apps = new AppsResource(this)\n this.characters = new CharactersResource(this)\n this.locations = new LocationsResource(this)\n this.objects = new ObjectsResource(this)\n this.creatures = new CreaturesResource(this)\n this.keepers = new KeepersResource(this)\n this.pipelines = new PipelinesResource(this)\n this.reduce = new ReduceResource(this)\n this.promptHelper = new PromptHelperResource(this)\n this.voices = new VoicesResource(this)\n this.llm = new LlmResource(this)\n this.media = new MediaResource(this)\n this.audio = new AudioResource(this)\n this.credits = new CreditsResource(this)\n this.userSettings = new UserSettingsResource(this)\n this.billing = new BillingResource(this)\n this.uploads = new UploadsResource(this)\n this.library = new LibraryResource(this)\n this.gallery = new GalleryResource(this)\n this.presets = new PresetsResource(this)\n this.savedPosts = new SavedPostsResource(this)\n this.collections = new CollectionsResource(this)\n this.palettes = new PalettesResource(this)\n this.moodboards = new MoodboardsResource(this)\n this.competitors = new CompetitorsResource(this)\n this.pickerCatalogs = new PickerCatalogsResource(this)\n this.catalogs = new CatalogsResource(this)\n this.models = new ModelsResource(this)\n this.shots = new ShotsResource(this)\n this.recast = new RecastResource(this)\n this.castSwap = new CastSwapResource(this)\n this.trends = new TrendsResource(this)\n this.studio = new StudioResource(this)\n this.copilot = new CopilotResource(this)\n this.community = new CommunityResource(this)\n this.templates = new TemplatesResource(this)\n this.tutorials = new TutorialsResource(this)\n this.organizations = new OrganizationsResource(this)\n this.workspaces = new WorkspacesResource(this)\n this.edit = new EditResource(this)\n }\n\n /**\n * A client that acts in `workspaceId`, sharing this one's auth and config.\n *\n * A NEW client rather than a setter, deliberately. A mutable selection is\n * the bug this whole axis exists to prevent: two concurrent operations\n * against one client would race over which workspace they were in, and the\n * loser would create work in the wrong place with nothing failing. A\n * per-workspace client cannot be raced.\n *\n * Pass `null` for the personal space.\n */\n withWorkspace(workspaceId: string | null): NodaroClient {\n // The two private settings are read by bracket access, which TypeScript\n // allows on a subclass and which adds no member to the declarations. Read\n // through `this` (not a side table keyed by the instance), so a client\n // wrapped in a Proxy (Vue/Pinia `reactive()`) or reached through\n // `Object.create(client)` still works.\n const fetchOverride = this[\"fetchOverride\"]\n return new NodaroClient({\n baseUrl: this.baseUrl,\n auth: this.auth,\n timeoutMs: this.timeoutMs,\n ...(fetchOverride ? { fetch: fetchOverride } : {}),\n ...(this[\"sendClientHeader\"] ? { clientLabel: this.clientLabel } : {}),\n ...(workspaceId ? { workspaceId } : {}),\n })\n }\n}\n\n/** Factory function — preferred entry point. */\nexport function createClient(opts: ClientOptions): NodaroClient {\n return new NodaroClient(opts)\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkQ4MFQC2J_cjs = require('./chunk-Q4MFQC2J.cjs');
3
+ var chunkKU3UITCU_cjs = require('./chunk-KU3UITCU.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 chunkQ4MFQC2J_cjs.readSseStream(res, { label: "copilot stream" })) {
96
+ for await (const value of chunkKU3UITCU_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-DFT4LD2H.cjs.map
104
- //# sourceMappingURL=chunk-DFT4LD2H.cjs.map
103
+ //# sourceMappingURL=chunk-GDUEOKBF.cjs.map
104
+ //# sourceMappingURL=chunk-GDUEOKBF.cjs.map