@nodaro/sdk 2.54.0 → 2.56.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-P6AM42UB.cjs → chunk-2KX5ZE6M.cjs} +2 -2
- package/dist/chunk-2KX5ZE6M.cjs.map +1 -0
- package/dist/{chunk-JOVJAKBT.cjs → chunk-2LOTDOUV.cjs} +6 -6
- package/dist/chunk-2LOTDOUV.cjs.map +1 -0
- package/dist/{chunk-AN36M6HO.js → chunk-37LL6BPM.js} +5 -5
- package/dist/chunk-37LL6BPM.js.map +1 -0
- package/dist/{chunk-22P4X3N5.cjs → chunk-3CVWTUK5.cjs} +26 -8
- package/dist/chunk-3CVWTUK5.cjs.map +1 -0
- package/dist/{chunk-7CUWAVWB.js → chunk-4FSWJTRS.js} +3 -3
- package/dist/{chunk-7CUWAVWB.js.map → chunk-4FSWJTRS.js.map} +1 -1
- package/dist/{chunk-DV6GTEX5.js → chunk-4SZUSZXK.js} +2 -2
- package/dist/{chunk-DV6GTEX5.js.map → chunk-4SZUSZXK.js.map} +1 -1
- package/dist/{chunk-L6T44A3G.js → chunk-4VP2GFIZ.js} +20 -5
- package/dist/chunk-4VP2GFIZ.js.map +1 -0
- package/dist/{chunk-NKH2UFSD.cjs → chunk-4WOT5OAY.cjs} +5 -5
- package/dist/{chunk-NKH2UFSD.cjs.map → chunk-4WOT5OAY.cjs.map} +1 -1
- package/dist/{chunk-W5RMFTPA.cjs → chunk-57GANTLV.cjs} +2 -2
- package/dist/chunk-57GANTLV.cjs.map +1 -0
- package/dist/{chunk-HK5FSTKG.cjs → chunk-A3XA6UNM.cjs} +2 -2
- package/dist/chunk-A3XA6UNM.cjs.map +1 -0
- package/dist/{chunk-AUKHMT53.js → chunk-BGOZRZHY.js} +3 -3
- package/dist/{chunk-AUKHMT53.js.map → chunk-BGOZRZHY.js.map} +1 -1
- package/dist/{chunk-PBFODIFT.js → chunk-CBDUHYTR.js} +2 -2
- package/dist/chunk-CBDUHYTR.js.map +1 -0
- package/dist/{chunk-OSMKIRKI.cjs → chunk-DFT4LD2H.cjs} +4 -4
- package/dist/{chunk-OSMKIRKI.cjs.map → chunk-DFT4LD2H.cjs.map} +1 -1
- package/dist/{chunk-RBX3QTKB.js → chunk-E6X6BGRO.js} +3 -3
- package/dist/{chunk-RBX3QTKB.js.map → chunk-E6X6BGRO.js.map} +1 -1
- package/dist/{chunk-47ULSVO2.js → chunk-FTCAT2LK.js} +3 -3
- package/dist/chunk-FTCAT2LK.js.map +1 -0
- package/dist/{chunk-QGVOAPUI.js → chunk-GIQDM2MH.js} +2 -2
- package/dist/chunk-GIQDM2MH.js.map +1 -0
- package/dist/{chunk-65VIIZEF.cjs → chunk-GJH73EGF.cjs} +2 -2
- package/dist/{chunk-65VIIZEF.cjs.map → chunk-GJH73EGF.cjs.map} +1 -1
- package/dist/{chunk-HAVIVOLO.js → chunk-HFYNZ4SO.js} +2 -2
- package/dist/chunk-HFYNZ4SO.js.map +1 -0
- package/dist/{chunk-THLTFB6I.js → chunk-HJLSOT5C.js} +2 -2
- package/dist/chunk-HJLSOT5C.js.map +1 -0
- package/dist/{chunk-D2ILCSOQ.js → chunk-HK6XP5EN.js} +3 -3
- package/dist/{chunk-D2ILCSOQ.js.map → chunk-HK6XP5EN.js.map} +1 -1
- package/dist/{chunk-HWSYNUSC.js → chunk-HUYI5G3D.js} +2 -2
- package/dist/chunk-HUYI5G3D.js.map +1 -0
- package/dist/{chunk-JVDUGVLX.cjs → chunk-MIXRL6I2.cjs} +2 -2
- package/dist/chunk-MIXRL6I2.cjs.map +1 -0
- package/dist/{chunk-SF2CMKWA.cjs → chunk-OMJ45CW4.cjs} +9 -9
- package/dist/{chunk-SF2CMKWA.cjs.map → chunk-OMJ45CW4.cjs.map} +1 -1
- package/dist/{chunk-DAONQZPI.cjs → chunk-PDX742CC.cjs} +2 -2
- package/dist/chunk-PDX742CC.cjs.map +1 -0
- package/dist/{chunk-EZXFDCII.js → chunk-PQ6G5EM7.js} +15 -15
- package/dist/{chunk-EZXFDCII.js.map → chunk-PQ6G5EM7.js.map} +1 -1
- package/dist/{chunk-FRQJNGJS.cjs → chunk-Q4MFQC2J.cjs} +5 -5
- package/dist/{chunk-FRQJNGJS.cjs.map → chunk-Q4MFQC2J.cjs.map} +1 -1
- package/dist/{chunk-VHTDOACT.cjs → chunk-Q7W4QNE5.cjs} +22 -22
- package/dist/chunk-Q7W4QNE5.cjs.map +1 -0
- package/dist/{chunk-XZRBRXGJ.cjs → chunk-RIMDKJSQ.cjs} +28 -28
- package/dist/{chunk-XZRBRXGJ.cjs.map → chunk-RIMDKJSQ.cjs.map} +1 -1
- package/dist/{chunk-BQAW4RX2.js → chunk-VEQLP5TA.js} +25 -7
- package/dist/chunk-VEQLP5TA.js.map +1 -0
- package/dist/{chunk-I3MEBVLP.js → chunk-XZPSJG2X.js} +2 -2
- package/dist/chunk-XZPSJG2X.js.map +1 -0
- package/dist/{chunk-O74MSMFH.cjs → chunk-XZQ6Z4T6.cjs} +2 -2
- package/dist/chunk-XZQ6Z4T6.cjs.map +1 -0
- package/dist/{chunk-FM2KM5TY.cjs → chunk-Z4B4SZ33.cjs} +21 -4
- package/dist/chunk-Z4B4SZ33.cjs.map +1 -0
- package/dist/{developer-apps-zSQXWmEG.d.ts → developer-apps-CMUzKpE9.d.cts} +2 -0
- package/dist/{developer-apps-zSQXWmEG.d.cts → developer-apps-CMUzKpE9.d.ts} +2 -0
- package/dist/entries/apps.d.cts +1 -1
- package/dist/entries/apps.d.ts +1 -1
- package/dist/entries/audio.d.cts +1 -1
- package/dist/entries/audio.d.ts +1 -1
- package/dist/entries/billing.d.cts +1 -1
- package/dist/entries/billing.d.ts +1 -1
- package/dist/entries/cast-swap.cjs +2 -2
- package/dist/entries/cast-swap.d.cts +13 -1
- package/dist/entries/cast-swap.d.ts +13 -1
- package/dist/entries/cast-swap.js +1 -1
- package/dist/entries/catalogs.d.cts +1 -1
- package/dist/entries/catalogs.d.ts +1 -1
- package/dist/entries/characters.cjs +10 -10
- package/dist/entries/characters.d.cts +11 -3
- package/dist/entries/characters.d.ts +11 -3
- package/dist/entries/characters.js +1 -1
- package/dist/entries/client.cjs +21 -21
- package/dist/entries/client.d.cts +5 -5
- package/dist/entries/client.d.ts +5 -5
- package/dist/entries/client.js +16 -16
- package/dist/entries/collections.d.cts +1 -1
- package/dist/entries/collections.d.ts +1 -1
- package/dist/entries/community.d.cts +1 -1
- package/dist/entries/community.d.ts +1 -1
- package/dist/entries/competitors.d.cts +1 -1
- package/dist/entries/competitors.d.ts +1 -1
- package/dist/entries/copilot.cjs +4 -4
- package/dist/entries/copilot.d.cts +1 -1
- package/dist/entries/copilot.d.ts +1 -1
- package/dist/entries/copilot.js +3 -3
- package/dist/entries/core.cjs +6 -6
- package/dist/entries/core.d.cts +1 -1
- package/dist/entries/core.d.ts +1 -1
- package/dist/entries/core.js +2 -2
- package/dist/entries/creatures.cjs +6 -6
- package/dist/entries/creatures.d.cts +11 -3
- package/dist/entries/creatures.d.ts +11 -3
- package/dist/entries/creatures.js +1 -1
- package/dist/entries/credits.d.cts +1 -1
- package/dist/entries/credits.d.ts +1 -1
- package/dist/entries/developer-apps.d.cts +1 -1
- package/dist/entries/developer-apps.d.ts +1 -1
- package/dist/entries/edit.cjs +7 -7
- package/dist/entries/edit.d.cts +1 -1
- package/dist/entries/edit.d.ts +1 -1
- package/dist/entries/edit.js +2 -2
- package/dist/entries/errors.cjs +32 -24
- package/dist/entries/errors.d.cts +28 -4
- package/dist/entries/errors.d.ts +28 -4
- package/dist/entries/errors.js +1 -1
- package/dist/entries/executions.d.cts +1 -1
- package/dist/entries/executions.d.ts +1 -1
- package/dist/entries/gallery.d.cts +1 -1
- package/dist/entries/gallery.d.ts +1 -1
- package/dist/entries/jobs.cjs +2 -2
- package/dist/entries/jobs.d.cts +7 -4
- package/dist/entries/jobs.d.ts +7 -4
- package/dist/entries/jobs.js +1 -1
- package/dist/entries/keepers.d.cts +1 -1
- package/dist/entries/keepers.d.ts +1 -1
- package/dist/entries/library.d.cts +1 -1
- package/dist/entries/library.d.ts +1 -1
- package/dist/entries/llm.d.cts +1 -1
- package/dist/entries/llm.d.ts +1 -1
- package/dist/entries/locations.cjs +5 -5
- package/dist/entries/locations.d.cts +11 -3
- package/dist/entries/locations.d.ts +11 -3
- package/dist/entries/locations.js +1 -1
- package/dist/entries/media.cjs +4 -4
- package/dist/entries/media.d.cts +34 -5
- package/dist/entries/media.d.ts +34 -5
- package/dist/entries/media.js +3 -3
- package/dist/entries/models.d.cts +1 -1
- package/dist/entries/models.d.ts +1 -1
- package/dist/entries/moodboards.d.cts +1 -1
- package/dist/entries/moodboards.d.ts +1 -1
- package/dist/entries/node-presets.d.cts +1 -1
- package/dist/entries/node-presets.d.ts +1 -1
- package/dist/entries/nodes.cjs +3 -3
- package/dist/entries/nodes.d.cts +3 -3
- package/dist/entries/nodes.d.ts +3 -3
- package/dist/entries/nodes.js +2 -2
- package/dist/entries/oauth.d.cts +1 -1
- package/dist/entries/oauth.d.ts +1 -1
- package/dist/entries/objects.cjs +6 -6
- package/dist/entries/objects.d.cts +11 -3
- package/dist/entries/objects.d.ts +11 -3
- package/dist/entries/objects.js +1 -1
- package/dist/entries/organizations.d.cts +1 -1
- package/dist/entries/organizations.d.ts +1 -1
- package/dist/entries/palettes.d.cts +1 -1
- package/dist/entries/palettes.d.ts +1 -1
- package/dist/entries/picker-catalogs.d.cts +1 -1
- package/dist/entries/picker-catalogs.d.ts +1 -1
- package/dist/entries/pipelines.d.cts +1 -1
- package/dist/entries/pipelines.d.ts +1 -1
- package/dist/entries/projects.d.cts +1 -1
- package/dist/entries/projects.d.ts +1 -1
- package/dist/entries/prompt-helper.d.cts +1 -1
- package/dist/entries/prompt-helper.d.ts +1 -1
- package/dist/entries/recast.d.cts +1 -1
- package/dist/entries/recast.d.ts +1 -1
- package/dist/entries/reduce.d.cts +1 -1
- package/dist/entries/reduce.d.ts +1 -1
- package/dist/entries/saved-posts.d.cts +1 -1
- package/dist/entries/saved-posts.d.ts +1 -1
- package/dist/entries/scene3d.d.cts +4 -4
- package/dist/entries/scene3d.d.ts +4 -4
- package/dist/entries/sessions.d.cts +1 -1
- package/dist/entries/sessions.d.ts +1 -1
- package/dist/entries/shots.d.cts +1 -1
- package/dist/entries/shots.d.ts +1 -1
- package/dist/entries/studio.cjs +5 -5
- package/dist/entries/studio.d.cts +3 -3
- package/dist/entries/studio.d.ts +3 -3
- package/dist/entries/studio.js +2 -2
- package/dist/entries/templates.d.cts +1 -1
- package/dist/entries/templates.d.ts +1 -1
- package/dist/entries/trash.d.cts +1 -1
- package/dist/entries/trash.d.ts +1 -1
- package/dist/entries/trends.cjs +2 -2
- package/dist/entries/trends.d.cts +37 -17
- package/dist/entries/trends.d.ts +37 -17
- package/dist/entries/trends.js +1 -1
- package/dist/entries/tutorials.d.cts +1 -1
- package/dist/entries/tutorials.d.ts +1 -1
- package/dist/entries/uploads.d.cts +1 -1
- package/dist/entries/uploads.d.ts +1 -1
- package/dist/entries/user-settings.d.cts +1 -1
- package/dist/entries/user-settings.d.ts +1 -1
- package/dist/entries/video-pro.d.cts +1 -1
- package/dist/entries/video-pro.d.ts +1 -1
- package/dist/entries/voices.d.cts +1 -1
- package/dist/entries/voices.d.ts +1 -1
- package/dist/entries/webhooks.d.cts +3 -3
- package/dist/entries/webhooks.d.ts +3 -3
- package/dist/entries/workflows.d.cts +1 -1
- package/dist/entries/workflows.d.ts +1 -1
- package/dist/entries/workspaces.d.cts +1 -1
- package/dist/entries/workspaces.d.ts +1 -1
- package/dist/index.cjs +90 -82
- package/dist/index.d.cts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +16 -16
- package/dist/{nodes-DuXF6XVv.d.ts → nodes-1u7MPrD5.d.ts} +11 -1
- package/dist/{nodes-bY51Z1Os.d.cts → nodes-BZavad1T.d.cts} +11 -1
- package/dist/{studio-productions-r2-VZsKj.d.cts → studio-productions-CMiS827q.d.cts} +1 -1
- package/dist/{studio-productions-DtTE8mdl.d.ts → studio-productions-DkI51Z9M.d.ts} +1 -1
- package/dist/{webhooks-BJawEIz8.d.ts → webhooks-C2DZTK4n.d.ts} +1 -1
- package/dist/{webhooks-Dn_DtNTD.d.cts → webhooks-tg3VN39V.d.cts} +1 -1
- package/package.json +3 -3
- package/dist/chunk-22P4X3N5.cjs.map +0 -1
- package/dist/chunk-47ULSVO2.js.map +0 -1
- package/dist/chunk-AN36M6HO.js.map +0 -1
- package/dist/chunk-BQAW4RX2.js.map +0 -1
- package/dist/chunk-DAONQZPI.cjs.map +0 -1
- package/dist/chunk-FM2KM5TY.cjs.map +0 -1
- package/dist/chunk-HAVIVOLO.js.map +0 -1
- package/dist/chunk-HK5FSTKG.cjs.map +0 -1
- package/dist/chunk-HWSYNUSC.js.map +0 -1
- package/dist/chunk-I3MEBVLP.js.map +0 -1
- package/dist/chunk-JOVJAKBT.cjs.map +0 -1
- package/dist/chunk-JVDUGVLX.cjs.map +0 -1
- package/dist/chunk-L6T44A3G.js.map +0 -1
- package/dist/chunk-O74MSMFH.cjs.map +0 -1
- package/dist/chunk-P6AM42UB.cjs.map +0 -1
- package/dist/chunk-PBFODIFT.js.map +0 -1
- package/dist/chunk-QGVOAPUI.js.map +0 -1
- package/dist/chunk-THLTFB6I.js.map +0 -1
- package/dist/chunk-VHTDOACT.cjs.map +0 -1
- package/dist/chunk-W5RMFTPA.cjs.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/resources/trends.ts"],"names":[],"mappings":"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","file":"chunk-DAONQZPI.cjs","sourcesContent":["import type { NodaroClientCore } from \"../core.js\"\nimport type { CastSwapEngine } from \"./cast-swap.js\"\n\n/**\n * Trends — ready-made Nodaro Motion recipes. A trend is a short clip with slots\n * (the people, pets, products and place you can replace); fill its slots with\n * your own pictures and run it to get the clip back with them in it.\n *\n * Cloud edition only: `/v1/trends` 404s on self-hosted installs. Only\n * published trends exist here: a draft, unpublished or unknown slug is a 404\n * on every route. `\"runs\"` and `\"tags\"` are never slugs (`/v1/trends/runs` is\n * the run list, `/v1/trends/tags` the tag list): the slug methods throw a\n * `TypeError` for them before any request. `run()` answers 202 with a job id; follow it with\n * `client.jobs.get(jobId)` / `client.jobs.getStatus(jobId)` like any other\n * job, or read it back as a trend run with `getRun(jobId)` / `runs()`.\n *\n * Repeats: pass `{ idempotencyKey }` to `run()` and it is sent as the\n * `Idempotency-Key` header. A repeat with the same key answers with the first\n * run's `jobId`; nothing new is started or charged.\n *\n * Refusals (thrown as a `NodaroError` subclass; body `{ error: { code, message } }`):\n * - 400 `validation_error` (the body, a query, or a bad `cursor`);\n * `estimate()` / `run()` only, before anything is charged:\n * `missing_slot` (a required slot without pictures, or an optional one\n * left empty that the chosen example has no pictures for), `unknown_slot`,\n * `invalid_choice` (a chip the slot's kind does not take),\n * `chip_not_offered` (a chip of the kind that the slot's\n * {@link TrendDetailSlot.chips} does not list: the trend fixes it),\n * `example_out_of_range` (`example` names no example of the trend, or is\n * sent at all on a trend with none), `preview_unavailable` (the trend offers no\n * preview), `invalid_slot_mention` (a `{slot:<key>}` in `details` naming no\n * slot), `prompt_too_long` (shorten `details`), `draft_unsupported`\n * (`draft: true` on a trend whose `engine` has no draft: Nodaro Motion Pulse),\n * `resolution_unsupported` (a `resolution` not in the trend's\n * `resolutions`), `too_many_images` (a Nodaro Motion Pulse trend's run would send more\n * than 10 pictures: send fewer per slot). The slot errors carry the\n * slot's key as `slot` (in `NodaroError.details`), and `chip_not_offered`\n * the chip as `chip` too.\n * - 401 `unauthorized`.\n * - 404 `not_found`: the trend is not published (every method), or `run()`'s\n * `sessionId` is not a session you may use.\n * - 409 `trend_unavailable` (`estimate()` / `run()`): the trend's setup is out\n * of date — it cannot run until it is updated, so a retry gets the same answer.\n * - 502 `engine_error` (`estimate()` / `run()`).\n * - 503 `engine_unsupported` (this platform version cannot run trends yet),\n * `trend_unavailable` (`estimate()` / `run()`), `not_available` (this\n * server has no trend catalog yet).\n * - `estimate()` / `run()` answer the video engine's refusals with the trend\n * routes' OWN codes and fixed messages — never the engine's text or\n * `issues`: 400 `trend_run_rejected` (the inputs could not run), or\n * `clip_out_of_range` / `preview_out_of_range` / `video_unreadable` (this\n * trend's clip), `unsafe_url` (a picture is not a public http(s) address),\n * `raw_reference_token` (`details` holds `{image:` / `{video:` /\n * `{audio:`); 402 `insufficient_credits` (or a workspace cap) as given;\n * 413 `storage_limit_exceeded`; 422 `job_blocked` (the job policy\n * blocked it); 429 `rate_limited`; 503 `engine_unsupported`,\n * `estimate_unavailable`; 502 `engine_error` for anything else. `run()`\n * also answers 400 `validation_error` for an `idempotencyKey` outside\n * 8–200 characters.\n */\n\n/** `/v1/trends/runs` is the run list and `/v1/trends/tags` the tag list, so neither can be a trend's slug. */\nconst RESERVED_SLUGS: Readonly<Record<string, string>> = {\n runs: \"the run list; use runs()\",\n tags: \"the tag list; use tags()\",\n}\n\nfunction trendPath(slug: string, rest = \"\"): string {\n if (Object.hasOwn(RESERVED_SLUGS, slug)) {\n throw new TypeError(`\"${slug}\" is not a trend slug (it is reserved for ${RESERVED_SLUGS[slug]})`)\n }\n return `/v1/trends/${encodeURIComponent(slug)}${rest}`\n}\n\n/** What a slot holds. */\nexport type TrendSlotKind = \"person\" | \"location\" | \"product\" | \"pet\"\n\n/** A chip: make this trait anew from your pictures (`\"new\"`), or keep the clip's (`\"original\"`). */\nexport type TrendChoice = \"new\" | \"original\"\n\n/**\n * The chips a slot can take, by its kind: a person `body` / `outfit` / `hair`,\n * a pet `body` / `coat`, a product `shape` / `finish`, a location none.\n */\nexport interface TrendChips {\n body?: TrendChoice\n outfit?: TrendChoice\n hair?: TrendChoice\n coat?: TrendChoice\n shape?: TrendChoice\n finish?: TrendChoice\n}\n\n/** A chip's name: `body`, `outfit`, `hair`, `coat`, `shape` or `finish`. */\nexport type TrendChipKey = keyof TrendChips\n\nexport type TrendResolution = \"480p\" | \"720p\" | \"1080p\"\n\n/**\n * The engine a trend runs on, by its public id ({@link CastSwapEngine}):\n * `\"motion-prism\"` (Nodaro Motion Prism) or `\"motion-pulse\"` (Nodaro Motion Pulse).\n * The trend chooses it, never the person running it.\n */\nexport type TrendEngine = CastSwapEngine\n\n/** A trend in the catalog (`list()`). Text is in the resolved locale. */\nexport interface TrendCard {\n id: string\n slug: string\n name: string\n description?: string\n tags: string[]\n /** e.g. `\"trending\"`, `\"new\"`. */\n badges: string[]\n /**\n * The trend's first example, else (a trend with no example) its original's\n * display copy, as {@link TrendDetail.original}.\n */\n cover: { videoUrl: string; posterUrl?: string; width: number; height: number }\n /**\n * The original's display copy, the same address as {@link TrendDetail.original}\n * (without its length and preview start). Absent on a version without a\n * display copy (and from an older server).\n */\n original?: { videoUrl: string; posterUrl?: string; width: number; height: number }\n /**\n * Every example's video, in the page's order, so a list can show each clip\n * without reading the trend's page. Empty on a trend with only its original;\n * absent from an older server. The pictures each slot used are on the page\n * ({@link TrendDetail.examples}).\n */\n examples?: Array<{ videoUrl: string; posterUrl?: string; width: number; height: number }>\n /** How many slots of each kind the trend has. */\n needs: Record<TrendSlotKind, number>\n /** The length of a full run, in seconds. */\n durationSec: number\n isFavorite: boolean\n}\n\n/** One slot of a trend: what it asks you for. */\nexport interface TrendDetailSlot {\n /** The key to fill in {@link TrendRunRequest.slots}, and to mention in `details` as `{slot:<key>}`. */\n key: string\n label: string\n kind: TrendSlotKind\n /**\n * A required slot needs pictures; an optional one left empty takes the\n * chosen example's, or, on a trend with no example, stays as in the original;\n * except in Full depth trends, where it uses the trend's default image for that role if one is set, otherwise the original's look.\n */\n required: boolean\n hint?: string\n /**\n * A picture showing who or what this slot is in the original (e.g. a frame\n * of that actor), when the trend has one. Show it on an empty slot; a run\n * never sends it.\n */\n hintImageUrl?: string\n /**\n * The chips you may set on this slot, in its kind's order; `[]` = none (show\n * no chips row). A chip of the kind that is not listed is fixed by the\n * trend: sending it is refused with `400 chip_not_offered`.\n */\n chips: TrendChipKey[]\n /** The starting value of the chips in {@link chips} (only those). */\n defaults?: TrendChips\n}\n\n/** A finished run shown on a trend's page, with the pictures it used per slot. */\nexport interface TrendExample {\n videoUrl: string\n posterUrl?: string\n width: number\n height: number\n /** Slot key → the pictures this example used for it. */\n slots: Record<string, string[]>\n}\n\n/**\n * The clip a trend recasts, as you may show it: a browser-safe copy (H.264\n * MP4) of the clip every run starts from. Its fields parallel\n * {@link TrendExample}'s.\n */\nexport interface TrendOriginal {\n videoUrl: string\n posterUrl?: string\n width: number\n height: number\n /** The copy's length, in seconds. */\n durationSec: number\n /**\n * Where the 4-second preview starts in the clip, in seconds (`0` included),\n * when the trend offers one ({@link TrendDetail.previewSec} is `4`); absent\n * otherwise.\n */\n previewStartSec?: number\n}\n\n/** A trend's page (`get()`). */\nexport interface TrendDetail extends TrendCard {\n /** The published version this page shows. */\n version: number\n /** `4` when the trend offers a 4-second preview run, else `null`. */\n previewSec: 4 | null\n /**\n * The original clip every run starts from, to show beside the examples.\n * Absent only on a version without a display copy (and from an older server).\n */\n original?: TrendOriginal\n /** The engine every run of this trend uses. Absent (an older server) = `\"motion-prism\"`. */\n engine?: TrendEngine\n /** Its name to show: \"Nodaro Motion Prism\" or \"Nodaro Motion Pulse\". Absent from an older server. */\n engineName?: string\n /**\n * The resolutions a run may ask for, the default first. Nodaro Motion Prism:\n * `[\"480p\", \"720p\", \"1080p\"]`, where 480p is a draft (show it as one);\n * Nodaro Motion Pulse: `[\"720p\", \"1080p\"]`, no draft. Offer exactly these.\n */\n resolutions: TrendResolution[]\n slots: TrendDetailSlot[]\n /** Finished runs to show beside the original; may be empty (a trend with only its original). */\n examples: TrendExample[]\n}\n\n/** What you put in one slot of a run: 1–3 pictures, and the chips the slot offers ({@link TrendDetailSlot.chips}). */\nexport interface TrendRunSlot extends TrendChips {\n images?: string[]\n}\n\n/** The body of `estimate()` and `run()`. */\nexport interface TrendRunRequest {\n /**\n * Slot key → what you put in it. Every required slot needs pictures; an\n * optional slot left out takes the chosen example's, or, on a trend with no\n * example, stays as in the original; except in Full depth trends, where it uses the trend's default image for that role if one is set, otherwise the original's look.\n * 1–3 pictures per slot.\n */\n slots: Record<string, TrendRunSlot>\n /**\n * 1-based example whose pictures fill the optional slots you leave empty\n * (never in a Full depth trend, which records `example: 0`). Default 1. Leave it out on a trend with no examples: sending one there\n * answers 400 `example_out_of_range` (and `0` is a `validation_error`).\n */\n example?: number\n /** Your own words, at most 1,000 characters. Mention a slot as `{slot:<key>}`. */\n details?: string\n /** `true` runs a 4-second preview (only when the trend's `previewSec` is `4`). */\n preview?: boolean\n /**\n * One of the trend's {@link TrendDetail.resolutions}; default its first\n * (`\"480p\"` on Nodaro Motion Prism, `\"720p\"` on Nodaro Motion Pulse). Another answers 400\n * `resolution_unsupported`.\n */\n resolution?: TrendResolution\n /**\n * A draft run, only at 480p on a Nodaro Motion Prism trend. Default `true` at\n * 480p. `true` on a Nodaro Motion Pulse trend answers 400 `draft_unsupported`.\n */\n draft?: boolean\n /**\n * A generation session of yours. Accepted (and checked: one you may not use\n * is a 404), but not yet applied: trend runs are not filed into sessions yet.\n */\n sessionId?: string\n /** Accepted, but not used by the run today. */\n projectId?: string\n /**\n * A full run's own preview: the `jobId` of a completed preview run of this\n * trend that you started. When that preview needed the trend's retry (the\n * clip refused at first), the full run is made that way from the start (the\n * quote includes it). Any other job is ignored, without an error. Must be a uuid\n * (else 400 `validation_error`).\n */\n previewJobId?: string\n /**\n * `run()`: your client app's slug (e.g. `\"tools\"`: lowercase letters,\n * digits and `-`, 1–40 characters, starting with a letter or digit), as on\n * any job: the run's job carries it as `input_data.origin`, so\n * `client.jobs.list({ origin })` finds it. Not a slug is a 400\n * `validation_error`; without it the run has no origin. `estimate()`\n * ignores it.\n */\n origin?: string\n}\n\n/** What a run would cost, in credits (`estimate()`). */\nexport interface TrendEstimate {\n /** The charge the run is expected to come to. */\n expectedCredits: number\n /** What is reserved when the run starts; the run is charged what it actually costs. */\n holdCredits: number\n /**\n * The parts of the quote, by name, for display only: some are alternatives\n * or sit outside the totals (`privacy`, the retry's, beside\n * `privacyCredits`), so read `expectedCredits` and `holdCredits`, never\n * their sum.\n */\n breakdown: Record<string, number>\n /**\n * Only on a trend that retries a clip the video model refuses: the extra\n * credits charged if that retry runs. Not included in `expectedCredits` or\n * `holdCredits`. 0 (or absent) when there is nothing extra to charge.\n */\n privacyCredits?: number\n /** @deprecated read {@link privacyCredits} (an older server answered this name). */\n maskingCredits?: number\n}\n\n/** Per-call options for {@link TrendsResource.run}. */\nexport interface TrendRunOptions {\n /**\n * Sent as the `Idempotency-Key` header, unchanged (an empty string sends no\n * header). The server takes 8–200 characters and answers 400 for any other\n * length. Reuse it when retrying the same run.\n */\n idempotencyKey?: string\n}\n\n/** One slot of a past run, as it was run. Labels are English. */\nexport interface TrendRunDisplaySlot extends TrendChips {\n key: string\n label: string\n kind: TrendSlotKind\n images: string[]\n /**\n * `true` when the slot was left empty and the example's pictures filled it.\n * `false` with no `images`: left empty on a trend with no example, so it\n * stayed as in the original.\n */\n fromExample: boolean\n /**\n * `true` when the slot was left empty and the trend's own default pictures\n * filled it (`fromExample` is then `false`). Absent otherwise.\n */\n fromDefault?: true\n}\n\n/**\n * One of your trend runs (`runs()`, `getRun()`). Stays readable after the\n * trend moves on or is unpublished.\n *\n * A Full Quality version of a draft is a run of its own, with its own status,\n * result and charge: `fullQualityOf` names the draft it was made from, and it\n * stays listed after that draft is deleted.\n */\nexport interface TrendRun {\n jobId: string\n status: string\n progress: number | null\n /**\n * Why a failed or cancelled run did not finish; `null` otherwise. `code` is\n * `safety-block` or `policy-block` when the job was blocked, `credits` when\n * it ran out of credits partway (it was refunded: ask the person to top up,\n * then run it again), else `cancelled` or `failed`. `message` is the same\n * fixed sentence for every code — branch on `code`, not on the text.\n */\n error: { code?: string; message: string } | null\n createdAt: string\n completedAt: string | null\n /** The trend and version it ran (name in English). */\n trend: { id: string; slug: string; version: number; name: string }\n /**\n * The 1-based example used for empty optional slots; `0` = none was used (the\n * trend had no example, or is a Full depth trend): never show it as \"Example 0\".\n */\n example: number\n slots: TrendRunDisplaySlot[]\n details?: string\n preview: boolean\n resolution: string\n draft: boolean\n /** The engine the run was made on. Absent (an older server) = `\"motion-prism\"`. */\n engine?: TrendEngine\n /** Its name to show: \"Nodaro Motion Prism\" or \"Nodaro Motion Pulse\". Absent from an older server. */\n engineName?: string\n /** The result, once completed. */\n videoUrl: string | null\n posterUrl: string | null\n /**\n * What the run was charged once settled, every step it ran included (its\n * reference preparation, mask and video); `null` until the run's own hold\n * settles. A step adds its charge once it settles.\n */\n creditsCharged: number | null\n /** The run's hold: its own plus its steps'. Absent from an older server. */\n creditsHeld?: number | null\n /** What went back from `creditsHeld` once every hold in the run settled; `null` until then. Absent from an older server. */\n creditsReleased?: number | null\n /** A Full Quality version: the job id of the run (a draft, or a Nodaro Motion Pulse 720p run) it was made from. `null` for any other run. */\n fullQualityOf: string | null\n /**\n * A draft's (or Nodaro Motion Pulse 720p run's) newest Full Quality try, if one was started: a pointer only,\n * to know an upgrade exists and how it is going. Its video and charge are on\n * that run, listed on its own (its `fullQualityOf` is this run's `jobId`) —\n * read it there (`getRun(fullQuality.jobId)`). Older tries of the draft (a\n * failed or cancelled one tried again) are not listed by `runs()`;\n * `getRun()` still reads one by its id.\n */\n fullQuality: { jobId: string; status: string } | null\n /**\n * Until when a completed run can be redone in Full Quality — a Nodaro Motion\n * Prism draft (the same take at 1080p) or a Nodaro Motion Pulse run at 720p (a new take at\n * 1080p); `null` otherwise.\n */\n fullQualityUntil: string | null\n}\n\nexport interface ListTrendsParams {\n /** Search text. */\n q?: string\n tag?: string\n /** `true` lists only your favorites. */\n favorites?: boolean\n /** A platform language for names and descriptions; default your profile's, then English. */\n locale?: string\n /** The previous page's `next`. */\n cursor?: string\n /** Page size, 1–60 (server default 30). */\n limit?: number\n}\n\nexport interface ListTrendRunsParams {\n /** Only runs of this trend (its slug). */\n trend?: string\n /** The previous page's `next`. */\n cursor?: string\n /** Page size, 1–60 (server default 30). */\n limit?: number\n}\n\n/** A tag in use on the published catalog (`tags()`). */\nexport interface TrendTag {\n /** The tag itself: pass it as `list({ tag })`. */\n tag: string\n /** The tag's label in the resolved locale; the tag itself when it has none. */\n label: string\n /** How many published trends carry it. */\n count: number\n}\n\nexport interface TrendPage<T> {\n data: T[]\n /** Pass back as `cursor` for the next page; `null` on the last one. */\n next: string | null\n}\n\nexport class TrendsResource {\n constructor(private client: NodaroClientCore) {}\n\n /** The published catalog in its curated order (`GET /v1/trends`), a page at a time. */\n list(params: ListTrendsParams = {}): Promise<TrendPage<TrendCard>> {\n const query: Record<string, string> = {}\n if (params.q) query.q = params.q\n if (params.tag) query.tag = params.tag\n if (params.favorites) query.favorites = \"1\"\n if (params.locale) query.locale = params.locale\n if (params.cursor) query.cursor = params.cursor\n if (params.limit !== undefined) query.limit = String(params.limit)\n return this.client.request(\"GET\", \"/v1/trends\", { query })\n }\n\n /** A published trend's page (`GET /v1/trends/:slug`). */\n async get(slug: string, params: { locale?: string } = {}): Promise<TrendDetail> {\n const query: Record<string, string> = {}\n if (params.locale) query.locale = params.locale\n const res = await this.client.request<{ data: TrendDetail }>(\"GET\", trendPath(slug), { query })\n return res.data\n }\n\n /** Quote a run before starting it (`POST /v1/trends/:slug/estimate`); spends nothing. */\n async estimate(slug: string, request: TrendRunRequest): Promise<TrendEstimate> {\n const res = await this.client.request<{ data: TrendEstimate }>(\n \"POST\",\n trendPath(slug, \"/estimate\"),\n { body: request },\n )\n return res.data\n }\n\n /**\n * Start a run (`POST /v1/trends/:slug/runs`, 202). Returns the job to follow.\n * With `options.idempotencyKey` (sent as the `Idempotency-Key` header) a\n * repeat with the same key answers with the first run's `jobId`.\n */\n async run(slug: string, request: TrendRunRequest, options?: TrendRunOptions): Promise<{ jobId: string }> {\n const res = await this.client.request<{ data: { jobId: string } }>(\n \"POST\",\n trendPath(slug, \"/runs\"),\n {\n body: request,\n ...(options?.idempotencyKey ? { headers: { \"Idempotency-Key\": options.idempotencyKey } } : {}),\n },\n )\n return res.data\n }\n\n /**\n * Your trend runs, newest first (`GET /v1/trends/runs`). A Full Quality\n * version of a draft is listed as its own run (`fullQualityOf`).\n */\n runs(params: ListTrendRunsParams = {}): Promise<TrendPage<TrendRun>> {\n const query: Record<string, string> = {}\n if (params.trend) query.trend = params.trend\n if (params.cursor) query.cursor = params.cursor\n if (params.limit !== undefined) query.limit = String(params.limit)\n return this.client.request(\"GET\", \"/v1/trends/runs\", { query })\n }\n\n /**\n * One of your trend runs by its job id (`GET /v1/trends/runs/:jobId`), in\n * the same shape as `runs()`. A job that is not your own trend run is a\n * `NotFoundError`.\n */\n async getRun(jobId: string): Promise<TrendRun> {\n const res = await this.client.request<{ data: TrendRun }>(\"GET\", `/v1/trends/runs/${encodeURIComponent(jobId)}`)\n return res.data\n }\n\n /**\n * The tags in use on the published catalog, each with its label in the\n * resolved locale (`GET /v1/trends/tags`), most used first.\n */\n async tags(params: { locale?: string } = {}): Promise<TrendTag[]> {\n const query: Record<string, string> = {}\n if (params.locale) query.locale = params.locale\n const res = await this.client.request<{ data: TrendTag[] }>(\"GET\", \"/v1/trends/tags\", { query })\n return res.data\n }\n\n /** Add a trend to your favorites (`PUT /v1/trends/:slug/favorite`). */\n async favorite(slug: string): Promise<void> {\n await this.client.request<void>(\"PUT\", trendPath(slug, \"/favorite\"))\n }\n\n /** Remove a trend from your favorites (`DELETE /v1/trends/:slug/favorite`). */\n async unfavorite(slug: string): Promise<void> {\n await this.client.request<void>(\"DELETE\", trendPath(slug, \"/favorite\"))\n }\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts"],"names":[],"mappings":"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","file":"chunk-FM2KM5TY.cjs","sourcesContent":["import type { StudioOpsResponse } from \"./resources/studio-productions.js\"\n\nexport class NodaroError extends Error {\n /**\n * Every other field of the server's error envelope (`{ error: { code,\n * message, … } }`), as it was sent: for example a trend refusal's `slot`, a\n * publish refusal's `reasons`, a validation error's `issues`. Empty when the\n * envelope had nothing else, or for an error the SDK made itself. A copy —\n * changing it changes nothing else.\n */\n public readonly details: Readonly<Record<string, unknown>> = {}\n\n constructor(\n message: string,\n public readonly code: string,\n public readonly status: number,\n details?: Readonly<Record<string, unknown>>,\n ) {\n super(message)\n this.name = \"NodaroError\"\n if (details) this.details = { ...details }\n }\n}\n\nexport class UnauthorizedError extends NodaroError {\n constructor(message = \"Authentication required\") {\n super(message, \"unauthorized\", 401)\n this.name = \"UnauthorizedError\"\n }\n}\n\nexport class ForbiddenError extends NodaroError {\n constructor(message = \"Forbidden\", public readonly missingScope?: string) {\n super(message, \"forbidden\", 403)\n this.name = \"ForbiddenError\"\n }\n}\n\nexport class NotFoundError extends NodaroError {\n constructor(message = \"Not found\") {\n super(message, \"not_found\", 404)\n this.name = \"NotFoundError\"\n }\n}\n\nexport class RateLimitedError extends NodaroError {\n constructor(message = \"Rate limited\") {\n super(message, \"rate_limited\", 429)\n this.name = \"RateLimitedError\"\n }\n}\n\n/**\n * HTTP 402: the run costs more than the caller may spend. `code` is the\n * refusal's own code — `insufficient_credits` for the caller's own balance, or\n * another 402 code such as `free_video_limit`. A spending cap someone else set\n * (a workspace budget, a member cap, a per-user allowance) is the subclass\n * {@link CreditCapExceededError}, so `instanceof InsufficientCreditsError`\n * still catches every 402.\n */\nexport class InsufficientCreditsError extends NodaroError {\n constructor(\n message = \"Insufficient credits\",\n public readonly required?: number,\n public readonly available?: number,\n code = \"insufficient_credits\",\n ) {\n super(message, code, 402)\n this.name = \"InsufficientCreditsError\"\n }\n}\n\n/** The 402 codes of a spending cap set by someone other than the caller. */\nexport type CreditCapCode = \"budget_exceeded\" | \"member_cap_exceeded\" | \"user_allowance_exceeded\"\n\n/**\n * The 402 codes {@link CreditCapExceededError} carries: the workspace's budget\n * (`budget_exceeded`), the caller's cap in that workspace\n * (`member_cap_exceeded`), the deployment's per-user allowance\n * (`user_allowance_exceeded`).\n */\nexport const CREDIT_CAP_CODES: ReadonlySet<CreditCapCode> = new Set<CreditCapCode>([\n \"budget_exceeded\",\n \"member_cap_exceeded\",\n \"user_allowance_exceeded\",\n])\n\n/**\n * HTTP 402 from a spending cap, not from the caller's own balance: topping up\n * does not help — whoever set the cap (the workspace's owner, the deployment's\n * operator) has to raise it. An {@link InsufficientCreditsError}, so existing\n * catches keep working; `code` says which cap. `available`, when sent, is what\n * the cap has left.\n */\nexport class CreditCapExceededError extends InsufficientCreditsError {\n declare readonly code: CreditCapCode\n\n constructor(code: CreditCapCode, message = \"A credit cap cannot cover this run\", required?: number, available?: number) {\n super(message, required, available, code)\n this.name = \"CreditCapExceededError\"\n }\n}\n\nexport class StorageExceededError extends NodaroError {\n constructor(message = \"Storage exceeded\", public readonly limitBytes?: number) {\n super(message, \"storage_exceeded\", 413)\n this.name = \"StorageExceededError\"\n }\n}\n\n/**\n * Optimistic-concurrency rejection (HTTP 409 `workflow_conflict`): the workflow\n * was written by another tab/device after the state carried in\n * `expectedUpdatedAt`/`expectedVersion` was read. `currentRecord` — when the\n * server includes it — is the full current workflow: merge your changes onto it\n * and retry with its fresh `updatedAt`, no follow-up GET needed.\n */\nexport class WorkflowConflictError extends NodaroError {\n constructor(\n message = \"Workflow was updated by another writer\",\n public readonly currentUpdatedAt?: string,\n public readonly currentVersion?: number,\n public readonly currentRecord?: Record<string, unknown>,\n /**\n * The wire code this conflict actually arrived with.\n *\n * `production_busy` is the studio production routes' own 409: the row\n * changed under a read-modify-write and the server exhausted its retries.\n * It is the same situation and the same remedy — re-read and apply again —\n * so it is the same ERROR, and a caller catching `WorkflowConflictError`\n * handles both. The code stays truthful because a caller that logs or\n * branches on it should see what the server said, not what the class is\n * usually called.\n */\n code: WorkflowConflictCode = \"workflow_conflict\",\n ) {\n super(message, code, 409)\n this.name = \"WorkflowConflictError\"\n }\n}\n\n/** The 409 codes that mean \"somebody else wrote first; re-read and retry\". */\nexport type WorkflowConflictCode = \"workflow_conflict\" | \"production_busy\"\n\n/**\n * A studio operation batch was refused, and the error names WHICH operation\n * (`opIndex`, zero-based) was wrong. Nothing in the batch was written: a batch\n * applies atomically or not at all, so fix that one operation and send the\n * whole batch again.\n *\n * Selected by SHAPE — any 4xx carrying a numeric `opIndex` — not by a list of\n * codes, so a new refusal reason (`op_invalid`, `op_target_missing`, whatever\n * the server adds next) reaches the caller as this error without an SDK\n * release. `code` is whatever the server sent.\n */\nexport class StudioOpError extends NodaroError {\n constructor(\n message: string,\n code: string,\n status: number,\n /** Zero-based index into the `ops` array that was sent. */\n public readonly opIndex: number,\n ) {\n super(message, code, status)\n this.name = \"StudioOpError\"\n }\n}\n\n/** The 409 codes whose answer names the job to turn to instead (a top-level `jobId`). */\nconst CONTINUATION_REFUSAL_CODES: ReadonlySet<string> = new Set([\n \"already_running\",\n \"continuation_superseded\",\n \"render_final_already_rendered\",\n])\n\n/**\n * A 409 that names the job to turn to instead: continuing a use-case run\n * (`client.edit.continueUseCase`) answers `already_running` (a continuation is\n * under way, or one that already completed — follow `jobId`),\n * `continuation_superseded` (a later continuation failed too — continue\n * `jobId` instead) or `render_final_already_rendered` (a Render final with this\n * very edit already completed — `jobId` holds the result). `code` and `status`\n * are what the server sent. Selected for exactly those three codes when the\n * answer carries a top-level `jobId`; every other 409 stays a plain\n * `NodaroError`.\n */\nexport class ContinuationRefusedError extends NodaroError {\n constructor(\n message: string,\n code: string,\n /** The job the refusal names. */\n public readonly jobId: string,\n ) {\n super(message, code, 409)\n this.name = \"ContinuationRefusedError\"\n }\n}\n\n/**\n * The one run that finishes a continuation held at a Preview review (the\n * `next` of {@link ContinuationPreviewPendingError}): pass these three fields\n * to `client.workflows.run`. It continues that execution, runs each held render\n * at Final and each held Tighten Episode continuing the run that made its\n * Preview, then every node after them.\n */\nexport interface HeldFinalRun {\n continueFromExecutionId: string\n /** The nodes it runs, in canvas order. */\n nodeIds: string[]\n /** For this run only: each held render at Final, each held use-case node's `useCaseContinue`. */\n inputOverrides: Record<string, Record<string, unknown>>\n}\n\n/**\n * HTTP 409 `continuation_preview_pending`: a continue-from-failed\n * (`client.workflows.run` with `continueMode: \"from-failed\"`) whose run's\n * newest later continuation completed by stopping at a Preview review, so\n * continuing again would stop there too. `executionId` is that continuation;\n * `renderNodeIds` the Apply EDL renders and `reviewNodeIds` the Tighten Episode\n * nodes holding it; `next` the run that finishes them — send it first\n * (`client.workflows.run(workflowId, error.next)`), then continue. Absent only\n * when the server could not name it. For a single held render, `next` is that\n * render's `client.workflows.renderFinal`.\n */\nexport class ContinuationPreviewPendingError extends NodaroError {\n constructor(\n message: string,\n public readonly executionId: string,\n public readonly renderNodeIds: readonly string[],\n public readonly reviewNodeIds: readonly string[],\n public readonly next?: HeldFinalRun,\n ) {\n super(message, \"continuation_preview_pending\", 409)\n this.name = \"ContinuationPreviewPendingError\"\n }\n}\n\nconst stringList = (v: unknown): string[] => (Array.isArray(v) ? v.filter((id): id is string => typeof id === \"string\") : [])\n\n/** A `next` as the server sends it, or undefined for anything else. */\nfunction heldFinalRunOf(v: unknown): HeldFinalRun | undefined {\n if (!v || typeof v !== \"object\") return undefined\n const r = v as Record<string, unknown>\n if (typeof r.continueFromExecutionId !== \"string\" || !Array.isArray(r.nodeIds)) return undefined\n if (!r.inputOverrides || typeof r.inputOverrides !== \"object\" || Array.isArray(r.inputOverrides)) return undefined\n return {\n continueFromExecutionId: r.continueFromExecutionId,\n nodeIds: stringList(r.nodeIds),\n inputOverrides: r.inputOverrides as Record<string, Record<string, unknown>>,\n }\n}\n\n/**\n * HTTP 409 `already_running` that names the execution under way (a top-level\n * `executionId`): the run you asked to start or continue is still running —\n * follow `executionId` (`client.executions.get`) instead of starting it again.\n * Sent by the workflow run route and by an app run's Retry\n * (`client.apps.resume`). An `already_running` that names a job instead stays\n * {@link ContinuationRefusedError}; one that names nothing, a plain\n * `NodaroError`.\n */\nexport class AlreadyRunningError extends NodaroError {\n constructor(\n message: string,\n /** The execution under way. */\n public readonly executionId: string,\n ) {\n super(message, \"already_running\", 409)\n this.name = \"AlreadyRunningError\"\n }\n}\n\n/**\n * HTTP 409 `app_run_version_changed`: a Retry of a failed app run\n * (`client.apps.resume`) refused because the app is on another version than\n * the one the run ran — continuing would mix them. `runVersion` is the run's\n * version, `appVersion` the one you are on (the `version` you sent, else the\n * app's latest). Start the run over (`client.apps.run`) to run `appVersion`,\n * or send `{ version: runVersion }` to continue on the run's own version.\n * Nothing was written or billed. Selected by code; the two numbers are\n * `undefined` when the answer does not carry them.\n */\nexport class AppRunVersionChangedError extends NodaroError {\n constructor(\n message: string,\n public readonly runVersion?: number,\n public readonly appVersion?: number,\n ) {\n super(message, \"app_run_version_changed\", 409)\n this.name = \"AppRunVersionChangedError\"\n }\n}\n\n/**\n * HTTP 422 `job_blocked`. A job policy registered by this deployment refused\n * the generation **before it ran** — no job was created, nothing was reserved\n * and nothing was charged. `message` is the policy's user-safe text: show it\n * as-is. Do not retry the identical request; whether the same input would be\n * judged differently is the deployment's policy's business.\n *\n * Only occurs on deployments that register a job policy. Selected by `code`,\n * not by status, the same way `workflow_conflict` narrows a 409 above — any\n * other 422 stays a plain `NodaroError`.\n */\nexport class JobBlockedError extends NodaroError {\n constructor(message = \"Blocked by this deployment's content policy\") {\n super(message, \"job_blocked\", 422)\n this.name = \"JobBlockedError\"\n }\n}\n\n/**\n * A job reached a terminal `failed`/`cancelled` status while being awaited by\n * `nodes.runAndWait` / `nodes.runMany`. Not an HTTP-level error (the polls\n * themselves succeeded), so `status` is 0 — distinguish it by type/`code`.\n * Carries the job's own `error_message` (as the message) and `jobId`.\n */\nexport class JobFailedError extends NodaroError {\n constructor(\n message: string,\n public readonly jobId: string,\n /** The terminal status that triggered the failure (`failed` | `cancelled`). */\n public readonly jobStatus: \"failed\" | \"cancelled\" = \"failed\",\n ) {\n super(message, \"job_failed\", 0)\n this.name = \"JobFailedError\"\n }\n}\n\n/**\n * `nodes.runAndWait` polled past its `maxMs` deadline without the job reaching\n * a terminal status. Not an HTTP error — `status` is 0; catch by type/`code`.\n */\nexport class JobTimeoutError extends NodaroError {\n constructor(\n message: string,\n public readonly jobId: string,\n /** The wall-clock deadline (ms) that was exceeded. */\n public readonly timeoutMs: number,\n ) {\n super(message, \"job_timeout\", 0)\n this.name = \"JobTimeoutError\"\n }\n}\n\n/**\n * The caller's `AbortSignal` fired while `nodes.runAndWait` was polling (or it\n * was already aborted on entry). Polling stops and this rejects. Not an HTTP\n * error — `status` is 0; catch by type/`code`.\n */\nexport class JobAbortedError extends NodaroError {\n constructor(message = \"Aborted\", public readonly jobId?: string) {\n super(message, \"job_aborted\", 0)\n this.name = \"JobAbortedError\"\n }\n}\n\n/**\n * A batch preview was asked for and this deployment cannot give one, so\n * NOTHING was sent: the batch is still unapplied and the production untouched.\n *\n * A preview is two requests because the route's body is parsed in strip mode —\n * a deployment that predates the preview silently DROPS the flag and APPLIES\n * the batch. So the SDK asks with an EMPTY batch first and sends the real one\n * only when that answer carries the `dryRun` marker. This is what it throws\n * when the answer does not: whatever the older deployment made of an empty\n * batch, the caller's batch never left.\n *\n * The remedy is a deployment that serves the preview — there is nothing to\n * retry here. To apply the batch instead, send it without the flag.\n *\n * A deployment that REFUSES the empty batch outright throws its own error\n * instead of this one, which is the right way round: the route's message says\n * more than \"unavailable\" does.\n *\n * Not an HTTP error: the request itself succeeded and answered the older shape.\n * `status` is 0; catch by type/`code`.\n */\nexport class StudioPreviewUnavailable extends NodaroError {\n constructor(\n message = \"This deployment does not preview operation batches; nothing was sent\",\n ) {\n super(message, \"studio_preview_unavailable\", 0)\n this.name = \"StudioPreviewUnavailable\"\n }\n}\n\n/**\n * A batch preview was asked for and the batch was APPLIED instead. The\n * production is written; this is the opposite of {@link\n * StudioPreviewUnavailable}, where nothing was sent.\n *\n * How it happens: the preview's proving ping and the batch are two requests,\n * and a fleet mid-rollout can serve them from different deployments. The ping\n * answers the marker, the batch reaches a deployment that predates the preview,\n * parses in strip mode, drops the flag and writes. The SDK cannot recall that\n * request — by the time the answer comes back the change has landed — so it\n * refuses to call the result a preview, which is the only thing still in its\n * gift. `receipts` and `warnings` are on both shapes, so an unchecked reply\n * would have shown a person what ALREADY happened under the heading of what\n * would.\n *\n * `applied` is what the route answered: the ordinary apply reply, whose\n * `production` and `version` are now the truth. Adopt them the way a plain\n * apply's caller does — do NOT re-send the batch, and do not present it for\n * approval.\n *\n * Not an HTTP error: the request succeeded, at the wrong thing. `status` is 0.\n */\nexport class StudioPreviewAppliedError extends NodaroError {\n constructor(\n /**\n * The apply reply the route sent back, as it sent it. An answer this\n * package does not recognise arrives here unchanged rather than being\n * dressed up: it is what the deployment said about a batch it took.\n *\n * `undefined` when the answer carried no body at all — a 204, an empty\n * envelope. The refusal still fires, because a non-preview answer is never\n * handed back as a preview, but there is nothing to report and the SDK will\n * not invent it: whether the batch was applied is unknown from here, and\n * the caller settles it by re-reading the production.\n */\n public readonly applied: StudioOpsResponse | undefined,\n message = applied\n ? \"Asked for a preview and this deployment APPLIED the batch; the change is written — see `applied`\"\n : \"Asked for a preview and this deployment answered with neither one nor a body to read; the batch may have been applied — re-read the production before deciding anything\",\n ) {\n super(message, \"studio_preview_applied\", 0)\n this.name = \"StudioPreviewAppliedError\"\n }\n}\n\n/**\n * The awaited job entered `pending_review`: a job policy registered by this\n * deployment held its output for a human reviewer. `pending_review` is\n * IN-FLIGHT, not terminal, so `nodes.runAndWait` / `nodes.runMany` end the\n * poll on the first tick they observe it rather than burning `maxMs` on a\n * status that no longer moves on its own.\n *\n * This does NOT cancel the job — the output exists, a human is reviewing it,\n * and the credit reservation stays `reserved` for the whole hold. Do not\n * re-run the request (a duplicate would be held too): re-fetch with\n * `jobs.get(jobId)` later, or surface \"awaiting review\" to your user and poll\n * `jobs.getStatus()` yourself. It resolves to `completed` (approved), `failed`\n * (rejected, with `error_hint.kind === \"policy-block\"`) or `cancelled`.\n *\n * Not an HTTP error — `status` is 0; catch by type/`code`.\n */\nexport class JobHeldError extends NodaroError {\n constructor(\n message: string,\n public readonly jobId: string,\n ) {\n super(message, \"job_held\", 0)\n this.name = \"JobHeldError\"\n }\n}\n\n/** The `{ error: { code, message, … } }` envelope every current route sends. */\ninterface ApiErrorEnvelope {\n code?: string\n message?: string\n missingScope?: string\n required?: number\n available?: number\n limitBytes?: number\n opIndex?: number\n [key: string]: unknown\n}\n\ninterface ApiErrorBody {\n /** The envelope — or, on an older route, a bare string (see {@link readErrorBody}). */\n error?: ApiErrorEnvelope | string\n /** A top-level message: an older route's, a bare validation answer's, or the server framework's own. */\n message?: unknown\n /** OAuth's human text (RFC 6749 §5.2), beside a bare-string `error`. */\n error_description?: unknown\n /** A bare validation answer's per-field issues (`{ message, issues }`). */\n issues?: unknown\n /** A refusal that names another job (see {@link ContinuationRefusedError}). */\n jobId?: unknown\n /** `continuation_preview_pending`: the held continuation, what holds it, and the run that finishes it. */\n executionId?: unknown\n renderNodeIds?: unknown\n reviewNodeIds?: unknown\n next?: unknown\n /** The credit guard's 402 sends its figures beside the envelope: what the run needs… */\n required?: unknown\n /** …and what the caller has (withheld on a deployment-paid instance). */\n balance?: unknown\n /** A per-user allowance's 402: what the allowance has left. */\n remaining?: unknown\n /** `app_run_version_changed`: the version the run ran, and the one the caller is on. */\n runVersion?: unknown\n appVersion?: unknown\n}\n\nconst finite = (v: unknown): number | undefined => (typeof v === \"number\" && Number.isFinite(v) ? v : undefined)\n\n/** A machine code as an older route writes it: lower snake_case, never a sentence or a reason phrase. */\nconst BARE_CODE = /^[a-z][a-z0-9_]*$/\n\nconst nonEmpty = (v: unknown): string | undefined => (typeof v === \"string\" && v.length > 0 ? v : undefined)\n\n/**\n * Where a body keeps its code and its human message. Most routes send the\n * envelope `{ error: { code, message } }`; three other shapes reach the SDK\n * too, and each is read for what it says rather than collapsed into\n * `internal_error` / \"Request failed\":\n *\n * - an older route's bare string, `{ error: \"<code>\", message?, … }` (character\n * training, a few profile and billing routes), and OAuth's\n * `{ error: \"<code>\", error_description }`. A snake_case string is the code;\n * a sentence (`\"Profile not found\"`) is the message.\n * - a bare validation answer, `{ message, issues: [...] }`: `validation_error`.\n * - the server framework's own answer, `{ statusCode, error: \"<reason phrase>\",\n * message }` (a route it does not have): the reason phrase is neither, the\n * message is kept — so \"no such route\" stays distinguishable from \"no such\n * resource\".\n *\n * At HTTP 500 and above only the CODE is read from outside the envelope. Text\n * there can be whatever the server failed with: the framework's own answer to\n * an uncaught throw is `{ statusCode: 500, error: \"Internal Server Error\",\n * message: <the raw error> }`, and the server's sanitizer rewrites only the\n * `internal_error` envelope. The envelope's own message is a route's chosen\n * sentence and is read at every status, as before.\n *\n * `message` is undefined when the body carries no human text it may show, so a\n * typed class keeps its own default (\"Not found\").\n */\nfunction readErrorBody(status: number, body: ApiErrorBody): { code: string | undefined; message: string | undefined; envelope: ApiErrorEnvelope } {\n const raw = body.error\n const envelope: ApiErrorEnvelope = raw && typeof raw === \"object\" ? raw : {}\n const bare = typeof raw === \"string\" ? raw : undefined\n const bareCode = bare !== undefined && BARE_CODE.test(bare) ? bare : undefined\n // Words with a space between them are human text: an older route's sentence,\n // or the framework's reason phrase — which always arrives with a real\n // `message`, read first. A single capitalised word (\"Unauthorized\") is a\n // reason phrase alone and says nothing the status does not.\n const bareSentence = bare !== undefined && bareCode === undefined && /\\s/.test(bare.trim()) ? bare : undefined\n const code =\n nonEmpty(envelope.code) ??\n bareCode ??\n (status === 400 && raw === undefined && Array.isArray(body.issues) ? \"validation_error\" : undefined)\n const outside = status >= 500 ? undefined : (nonEmpty(body.message) ?? nonEmpty(body.error_description) ?? bareSentence)\n const message = nonEmpty(envelope.message) ?? outside\n return { code, message, envelope }\n}\n\n/** The envelope's fields other than `code` and `message` (see {@link NodaroError.details}). */\nfunction envelopeDetails(envelope: ApiErrorEnvelope): Record<string, unknown> {\n const out: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(envelope)) {\n if (key !== \"code\" && key !== \"message\") out[key] = value\n }\n return out\n}\n\nexport function throwFromResponse(status: number, body: ApiErrorBody): never {\n try {\n selectError(status, body)\n } catch (err) {\n // Every class carries the envelope's other fields, whichever was chosen.\n if (err instanceof NodaroError) {\n const raw = body && typeof body === \"object\" ? body.error : undefined\n if (raw && typeof raw === \"object\") Object.defineProperty(err, \"details\", { value: envelopeDetails(raw), enumerable: true })\n }\n throw err\n }\n}\n\nfunction selectError(status: number, body: ApiErrorBody): never {\n // A body that is not an object (an empty answer, `null`, a bare string) still\n // throws by its status.\n const parsed: ApiErrorBody = body && typeof body === \"object\" ? body : {}\n const read = readErrorBody(status, parsed)\n const envelope = read.envelope\n const code = read.code ?? \"internal_error\"\n // A typed class falls back to its own default; a generic error to the code\n // it carries, which says more than \"Request failed\" does.\n const message = read.message ?? (read.code ? read.code : \"Request failed\")\n if (status === 401) throw new UnauthorizedError(read.message)\n if (status === 409 && (code === \"workflow_conflict\" || code === \"production_busy\")) {\n throw new WorkflowConflictError(\n read.message,\n envelope.currentUpdatedAt as string | undefined,\n envelope.currentVersion as number | undefined,\n envelope.currentRecord as Record<string, unknown> | undefined,\n code,\n )\n }\n // By shape, not by code — see StudioOpError. Only the studio operations route\n // sends an op index, so this cannot capture anyone else's 400.\n if (status >= 400 && status < 500 && typeof envelope.opIndex === \"number\") {\n throw new StudioOpError(message, code, status, envelope.opIndex)\n }\n if (status === 409 && CONTINUATION_REFUSAL_CODES.has(code) && typeof parsed.jobId === \"string\") {\n throw new ContinuationRefusedError(message, code, parsed.jobId)\n }\n if (status === 409 && code === \"continuation_preview_pending\" && typeof parsed.executionId === \"string\") {\n throw new ContinuationPreviewPendingError(\n message,\n parsed.executionId,\n stringList(parsed.renderNodeIds),\n stringList(parsed.reviewNodeIds),\n heldFinalRunOf(parsed.next),\n )\n }\n if (status === 409 && code === \"already_running\" && typeof parsed.executionId === \"string\") {\n throw new AlreadyRunningError(message, parsed.executionId)\n }\n if (status === 409 && code === \"app_run_version_changed\") {\n throw new AppRunVersionChangedError(message, finite(parsed.runVersion), finite(parsed.appVersion))\n }\n if (status === 422 && code === \"job_blocked\") throw new JobBlockedError(read.message)\n if (status === 403 && code === \"insufficient_scope\") {\n throw new ForbiddenError(read.message, envelope.missingScope)\n }\n if (status === 403) throw new ForbiddenError(read.message)\n // A 404 the framework answered itself (no route at that path) carries its\n // message at the top level, not under `error`; `readErrorBody` keeps it so\n // callers can tell \"no such route\" from \"no such resource\".\n if (status === 404) throw new NotFoundError(read.message)\n if (status === 429) throw new RateLimitedError(read.message)\n if (status === 402) {\n // The credit guard puts `required` / `balance` (an allowance: `remaining`)\n // beside the envelope; an envelope that carries them (`required` /\n // `available`) is read first.\n const required = finite(envelope.required) ?? finite(parsed.required)\n const available = finite(envelope.available) ?? finite(parsed.balance) ?? finite(parsed.remaining)\n const capCode = read.code as CreditCapCode | undefined\n if (capCode !== undefined && CREDIT_CAP_CODES.has(capCode)) {\n throw new CreditCapExceededError(capCode, read.message, required, available)\n }\n throw new InsufficientCreditsError(read.message, required, available, read.code ?? \"insufficient_credits\")\n }\n if (status === 413) throw new StorageExceededError(read.message, envelope.limitBytes)\n throw new NodaroError(message, code, status)\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/resources/trends.ts"],"names":[],"mappings":"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","file":"chunk-HAVIVOLO.js","sourcesContent":["import type { NodaroClientCore } from \"../core.js\"\nimport type { CastSwapEngine } from \"./cast-swap.js\"\n\n/**\n * Trends — ready-made Nodaro Motion recipes. A trend is a short clip with slots\n * (the people, pets, products and place you can replace); fill its slots with\n * your own pictures and run it to get the clip back with them in it.\n *\n * Cloud edition only: `/v1/trends` 404s on self-hosted installs. Only\n * published trends exist here: a draft, unpublished or unknown slug is a 404\n * on every route. `\"runs\"` and `\"tags\"` are never slugs (`/v1/trends/runs` is\n * the run list, `/v1/trends/tags` the tag list): the slug methods throw a\n * `TypeError` for them before any request. `run()` answers 202 with a job id; follow it with\n * `client.jobs.get(jobId)` / `client.jobs.getStatus(jobId)` like any other\n * job, or read it back as a trend run with `getRun(jobId)` / `runs()`.\n *\n * Repeats: pass `{ idempotencyKey }` to `run()` and it is sent as the\n * `Idempotency-Key` header. A repeat with the same key answers with the first\n * run's `jobId`; nothing new is started or charged.\n *\n * Refusals (thrown as a `NodaroError` subclass; body `{ error: { code, message } }`):\n * - 400 `validation_error` (the body, a query, or a bad `cursor`);\n * `estimate()` / `run()` only, before anything is charged:\n * `missing_slot` (a required slot without pictures, or an optional one\n * left empty that the chosen example has no pictures for), `unknown_slot`,\n * `invalid_choice` (a chip the slot's kind does not take),\n * `chip_not_offered` (a chip of the kind that the slot's\n * {@link TrendDetailSlot.chips} does not list: the trend fixes it),\n * `example_out_of_range` (`example` names no example of the trend, or is\n * sent at all on a trend with none), `preview_unavailable` (the trend offers no\n * preview), `invalid_slot_mention` (a `{slot:<key>}` in `details` naming no\n * slot), `prompt_too_long` (shorten `details`), `draft_unsupported`\n * (`draft: true` on a trend whose `engine` has no draft: Nodaro Motion Pulse),\n * `resolution_unsupported` (a `resolution` not in the trend's\n * `resolutions`), `too_many_images` (a Nodaro Motion Pulse trend's run would send more\n * than 10 pictures: send fewer per slot). The slot errors carry the\n * slot's key as `slot` (in `NodaroError.details`), and `chip_not_offered`\n * the chip as `chip` too.\n * - 401 `unauthorized`.\n * - 404 `not_found`: the trend is not published (every method), or `run()`'s\n * `sessionId` is not a session you may use.\n * - 409 `trend_unavailable` (`estimate()` / `run()`): the trend's setup is out\n * of date — it cannot run until it is updated, so a retry gets the same answer.\n * - 502 `engine_error` (`estimate()` / `run()`).\n * - 503 `engine_unsupported` (this platform version cannot run trends yet),\n * `trend_unavailable` (`estimate()` / `run()`), `not_available` (this\n * server has no trend catalog yet).\n * - `estimate()` / `run()` answer the video engine's refusals with the trend\n * routes' OWN codes and fixed messages — never the engine's text or\n * `issues`: 400 `trend_run_rejected` (the inputs could not run), or\n * `clip_out_of_range` / `preview_out_of_range` / `video_unreadable` (this\n * trend's clip), `unsafe_url` (a picture is not a public http(s) address),\n * `raw_reference_token` (`details` holds `{image:` / `{video:` /\n * `{audio:`); 402 `insufficient_credits` (or a workspace cap) as given;\n * 413 `storage_limit_exceeded`; 422 `job_blocked` (the job policy\n * blocked it); 429 `rate_limited`; 503 `engine_unsupported`,\n * `estimate_unavailable`; 502 `engine_error` for anything else. `run()`\n * also answers 400 `validation_error` for an `idempotencyKey` outside\n * 8–200 characters.\n */\n\n/** `/v1/trends/runs` is the run list and `/v1/trends/tags` the tag list, so neither can be a trend's slug. */\nconst RESERVED_SLUGS: Readonly<Record<string, string>> = {\n runs: \"the run list; use runs()\",\n tags: \"the tag list; use tags()\",\n}\n\nfunction trendPath(slug: string, rest = \"\"): string {\n if (Object.hasOwn(RESERVED_SLUGS, slug)) {\n throw new TypeError(`\"${slug}\" is not a trend slug (it is reserved for ${RESERVED_SLUGS[slug]})`)\n }\n return `/v1/trends/${encodeURIComponent(slug)}${rest}`\n}\n\n/** What a slot holds. */\nexport type TrendSlotKind = \"person\" | \"location\" | \"product\" | \"pet\"\n\n/** A chip: make this trait anew from your pictures (`\"new\"`), or keep the clip's (`\"original\"`). */\nexport type TrendChoice = \"new\" | \"original\"\n\n/**\n * The chips a slot can take, by its kind: a person `body` / `outfit` / `hair`,\n * a pet `body` / `coat`, a product `shape` / `finish`, a location none.\n */\nexport interface TrendChips {\n body?: TrendChoice\n outfit?: TrendChoice\n hair?: TrendChoice\n coat?: TrendChoice\n shape?: TrendChoice\n finish?: TrendChoice\n}\n\n/** A chip's name: `body`, `outfit`, `hair`, `coat`, `shape` or `finish`. */\nexport type TrendChipKey = keyof TrendChips\n\nexport type TrendResolution = \"480p\" | \"720p\" | \"1080p\"\n\n/**\n * The engine a trend runs on, by its public id ({@link CastSwapEngine}):\n * `\"motion-prism\"` (Nodaro Motion Prism) or `\"motion-pulse\"` (Nodaro Motion Pulse).\n * The trend chooses it, never the person running it.\n */\nexport type TrendEngine = CastSwapEngine\n\n/** A trend in the catalog (`list()`). Text is in the resolved locale. */\nexport interface TrendCard {\n id: string\n slug: string\n name: string\n description?: string\n tags: string[]\n /** e.g. `\"trending\"`, `\"new\"`. */\n badges: string[]\n /**\n * The trend's first example, else (a trend with no example) its original's\n * display copy, as {@link TrendDetail.original}.\n */\n cover: { videoUrl: string; posterUrl?: string; width: number; height: number }\n /**\n * The original's display copy, the same address as {@link TrendDetail.original}\n * (without its length and preview start). Absent on a version without a\n * display copy (and from an older server).\n */\n original?: { videoUrl: string; posterUrl?: string; width: number; height: number }\n /**\n * Every example's video, in the page's order, so a list can show each clip\n * without reading the trend's page. Empty on a trend with only its original;\n * absent from an older server. The pictures each slot used are on the page\n * ({@link TrendDetail.examples}).\n */\n examples?: Array<{ videoUrl: string; posterUrl?: string; width: number; height: number }>\n /** How many slots of each kind the trend has. */\n needs: Record<TrendSlotKind, number>\n /** The length of a full run, in seconds. */\n durationSec: number\n isFavorite: boolean\n}\n\n/** One slot of a trend: what it asks you for. */\nexport interface TrendDetailSlot {\n /** The key to fill in {@link TrendRunRequest.slots}, and to mention in `details` as `{slot:<key>}`. */\n key: string\n label: string\n kind: TrendSlotKind\n /**\n * A required slot needs pictures; an optional one left empty takes the\n * chosen example's, or, on a trend with no example, stays as in the original;\n * except in Full depth trends, where it uses the trend's default image for that role if one is set, otherwise the original's look.\n */\n required: boolean\n hint?: string\n /**\n * A picture showing who or what this slot is in the original (e.g. a frame\n * of that actor), when the trend has one. Show it on an empty slot; a run\n * never sends it.\n */\n hintImageUrl?: string\n /**\n * The chips you may set on this slot, in its kind's order; `[]` = none (show\n * no chips row). A chip of the kind that is not listed is fixed by the\n * trend: sending it is refused with `400 chip_not_offered`.\n */\n chips: TrendChipKey[]\n /** The starting value of the chips in {@link chips} (only those). */\n defaults?: TrendChips\n}\n\n/** A finished run shown on a trend's page, with the pictures it used per slot. */\nexport interface TrendExample {\n videoUrl: string\n posterUrl?: string\n width: number\n height: number\n /** Slot key → the pictures this example used for it. */\n slots: Record<string, string[]>\n}\n\n/**\n * The clip a trend recasts, as you may show it: a browser-safe copy (H.264\n * MP4) of the clip every run starts from. Its fields parallel\n * {@link TrendExample}'s.\n */\nexport interface TrendOriginal {\n videoUrl: string\n posterUrl?: string\n width: number\n height: number\n /** The copy's length, in seconds. */\n durationSec: number\n /**\n * Where the 4-second preview starts in the clip, in seconds (`0` included),\n * when the trend offers one ({@link TrendDetail.previewSec} is `4`); absent\n * otherwise.\n */\n previewStartSec?: number\n}\n\n/** A trend's page (`get()`). */\nexport interface TrendDetail extends TrendCard {\n /** The published version this page shows. */\n version: number\n /** `4` when the trend offers a 4-second preview run, else `null`. */\n previewSec: 4 | null\n /**\n * The original clip every run starts from, to show beside the examples.\n * Absent only on a version without a display copy (and from an older server).\n */\n original?: TrendOriginal\n /** The engine every run of this trend uses. Absent (an older server) = `\"motion-prism\"`. */\n engine?: TrendEngine\n /** Its name to show: \"Nodaro Motion Prism\" or \"Nodaro Motion Pulse\". Absent from an older server. */\n engineName?: string\n /**\n * The resolutions a run may ask for, the default first. Nodaro Motion Prism:\n * `[\"480p\", \"720p\", \"1080p\"]`, where 480p is a draft (show it as one);\n * Nodaro Motion Pulse: `[\"720p\", \"1080p\"]`, no draft. Offer exactly these.\n */\n resolutions: TrendResolution[]\n slots: TrendDetailSlot[]\n /** Finished runs to show beside the original; may be empty (a trend with only its original). */\n examples: TrendExample[]\n}\n\n/** What you put in one slot of a run: 1–3 pictures, and the chips the slot offers ({@link TrendDetailSlot.chips}). */\nexport interface TrendRunSlot extends TrendChips {\n images?: string[]\n}\n\n/** The body of `estimate()` and `run()`. */\nexport interface TrendRunRequest {\n /**\n * Slot key → what you put in it. Every required slot needs pictures; an\n * optional slot left out takes the chosen example's, or, on a trend with no\n * example, stays as in the original; except in Full depth trends, where it uses the trend's default image for that role if one is set, otherwise the original's look.\n * 1–3 pictures per slot.\n */\n slots: Record<string, TrendRunSlot>\n /**\n * 1-based example whose pictures fill the optional slots you leave empty\n * (never in a Full depth trend, which records `example: 0`). Default 1. Leave it out on a trend with no examples: sending one there\n * answers 400 `example_out_of_range` (and `0` is a `validation_error`).\n */\n example?: number\n /** Your own words, at most 1,000 characters. Mention a slot as `{slot:<key>}`. */\n details?: string\n /** `true` runs a 4-second preview (only when the trend's `previewSec` is `4`). */\n preview?: boolean\n /**\n * One of the trend's {@link TrendDetail.resolutions}; default its first\n * (`\"480p\"` on Nodaro Motion Prism, `\"720p\"` on Nodaro Motion Pulse). Another answers 400\n * `resolution_unsupported`.\n */\n resolution?: TrendResolution\n /**\n * A draft run, only at 480p on a Nodaro Motion Prism trend. Default `true` at\n * 480p. `true` on a Nodaro Motion Pulse trend answers 400 `draft_unsupported`.\n */\n draft?: boolean\n /**\n * A generation session of yours. Accepted (and checked: one you may not use\n * is a 404), but not yet applied: trend runs are not filed into sessions yet.\n */\n sessionId?: string\n /** Accepted, but not used by the run today. */\n projectId?: string\n /**\n * A full run's own preview: the `jobId` of a completed preview run of this\n * trend that you started. When that preview needed the trend's retry (the\n * clip refused at first), the full run is made that way from the start (the\n * quote includes it). Any other job is ignored, without an error. Must be a uuid\n * (else 400 `validation_error`).\n */\n previewJobId?: string\n /**\n * `run()`: your client app's slug (e.g. `\"tools\"`: lowercase letters,\n * digits and `-`, 1–40 characters, starting with a letter or digit), as on\n * any job: the run's job carries it as `input_data.origin`, so\n * `client.jobs.list({ origin })` finds it. Not a slug is a 400\n * `validation_error`; without it the run has no origin. `estimate()`\n * ignores it.\n */\n origin?: string\n}\n\n/** What a run would cost, in credits (`estimate()`). */\nexport interface TrendEstimate {\n /** The charge the run is expected to come to. */\n expectedCredits: number\n /** What is reserved when the run starts; the run is charged what it actually costs. */\n holdCredits: number\n /**\n * The parts of the quote, by name, for display only: some are alternatives\n * or sit outside the totals (`privacy`, the retry's, beside\n * `privacyCredits`), so read `expectedCredits` and `holdCredits`, never\n * their sum.\n */\n breakdown: Record<string, number>\n /**\n * Only on a trend that retries a clip the video model refuses: the extra\n * credits charged if that retry runs. Not included in `expectedCredits` or\n * `holdCredits`. 0 (or absent) when there is nothing extra to charge.\n */\n privacyCredits?: number\n /** @deprecated read {@link privacyCredits} (an older server answered this name). */\n maskingCredits?: number\n}\n\n/** Per-call options for {@link TrendsResource.run}. */\nexport interface TrendRunOptions {\n /**\n * Sent as the `Idempotency-Key` header, unchanged (an empty string sends no\n * header). The server takes 8–200 characters and answers 400 for any other\n * length. Reuse it when retrying the same run.\n */\n idempotencyKey?: string\n}\n\n/** One slot of a past run, as it was run. Labels are English. */\nexport interface TrendRunDisplaySlot extends TrendChips {\n key: string\n label: string\n kind: TrendSlotKind\n images: string[]\n /**\n * `true` when the slot was left empty and the example's pictures filled it.\n * `false` with no `images`: left empty on a trend with no example, so it\n * stayed as in the original.\n */\n fromExample: boolean\n /**\n * `true` when the slot was left empty and the trend's own default pictures\n * filled it (`fromExample` is then `false`). Absent otherwise.\n */\n fromDefault?: true\n}\n\n/**\n * One of your trend runs (`runs()`, `getRun()`). Stays readable after the\n * trend moves on or is unpublished.\n *\n * A Full Quality version of a draft is a run of its own, with its own status,\n * result and charge: `fullQualityOf` names the draft it was made from, and it\n * stays listed after that draft is deleted.\n */\nexport interface TrendRun {\n jobId: string\n status: string\n progress: number | null\n /**\n * Why a failed or cancelled run did not finish; `null` otherwise. `code` is\n * `safety-block` or `policy-block` when the job was blocked, `credits` when\n * it ran out of credits partway (it was refunded: ask the person to top up,\n * then run it again), else `cancelled` or `failed`. `message` is the same\n * fixed sentence for every code — branch on `code`, not on the text.\n */\n error: { code?: string; message: string } | null\n createdAt: string\n completedAt: string | null\n /** The trend and version it ran (name in English). */\n trend: { id: string; slug: string; version: number; name: string }\n /**\n * The 1-based example used for empty optional slots; `0` = none was used (the\n * trend had no example, or is a Full depth trend): never show it as \"Example 0\".\n */\n example: number\n slots: TrendRunDisplaySlot[]\n details?: string\n preview: boolean\n resolution: string\n draft: boolean\n /** The engine the run was made on. Absent (an older server) = `\"motion-prism\"`. */\n engine?: TrendEngine\n /** Its name to show: \"Nodaro Motion Prism\" or \"Nodaro Motion Pulse\". Absent from an older server. */\n engineName?: string\n /** The result, once completed. */\n videoUrl: string | null\n posterUrl: string | null\n /**\n * What the run was charged once settled, every step it ran included (its\n * reference preparation, mask and video); `null` until the run's own hold\n * settles. A step adds its charge once it settles.\n */\n creditsCharged: number | null\n /** The run's hold: its own plus its steps'. Absent from an older server. */\n creditsHeld?: number | null\n /** What went back from `creditsHeld` once every hold in the run settled; `null` until then. Absent from an older server. */\n creditsReleased?: number | null\n /** A Full Quality version: the job id of the run (a draft, or a Nodaro Motion Pulse 720p run) it was made from. `null` for any other run. */\n fullQualityOf: string | null\n /**\n * A draft's (or Nodaro Motion Pulse 720p run's) newest Full Quality try, if one was started: a pointer only,\n * to know an upgrade exists and how it is going. Its video and charge are on\n * that run, listed on its own (its `fullQualityOf` is this run's `jobId`) —\n * read it there (`getRun(fullQuality.jobId)`). Older tries of the draft (a\n * failed or cancelled one tried again) are not listed by `runs()`;\n * `getRun()` still reads one by its id.\n */\n fullQuality: { jobId: string; status: string } | null\n /**\n * Until when a completed run can be redone in Full Quality — a Nodaro Motion\n * Prism draft (the same take at 1080p) or a Nodaro Motion Pulse run at 720p (a new take at\n * 1080p); `null` otherwise.\n */\n fullQualityUntil: string | null\n}\n\nexport interface ListTrendsParams {\n /** Search text. */\n q?: string\n tag?: string\n /** `true` lists only your favorites. */\n favorites?: boolean\n /** A platform language for names and descriptions; default your profile's, then English. */\n locale?: string\n /** The previous page's `next`. */\n cursor?: string\n /** Page size, 1–60 (server default 30). */\n limit?: number\n}\n\nexport interface ListTrendRunsParams {\n /** Only runs of this trend (its slug). */\n trend?: string\n /** The previous page's `next`. */\n cursor?: string\n /** Page size, 1–60 (server default 30). */\n limit?: number\n}\n\n/** A tag in use on the published catalog (`tags()`). */\nexport interface TrendTag {\n /** The tag itself: pass it as `list({ tag })`. */\n tag: string\n /** The tag's label in the resolved locale; the tag itself when it has none. */\n label: string\n /** How many published trends carry it. */\n count: number\n}\n\nexport interface TrendPage<T> {\n data: T[]\n /** Pass back as `cursor` for the next page; `null` on the last one. */\n next: string | null\n}\n\nexport class TrendsResource {\n constructor(private client: NodaroClientCore) {}\n\n /** The published catalog in its curated order (`GET /v1/trends`), a page at a time. */\n list(params: ListTrendsParams = {}): Promise<TrendPage<TrendCard>> {\n const query: Record<string, string> = {}\n if (params.q) query.q = params.q\n if (params.tag) query.tag = params.tag\n if (params.favorites) query.favorites = \"1\"\n if (params.locale) query.locale = params.locale\n if (params.cursor) query.cursor = params.cursor\n if (params.limit !== undefined) query.limit = String(params.limit)\n return this.client.request(\"GET\", \"/v1/trends\", { query })\n }\n\n /** A published trend's page (`GET /v1/trends/:slug`). */\n async get(slug: string, params: { locale?: string } = {}): Promise<TrendDetail> {\n const query: Record<string, string> = {}\n if (params.locale) query.locale = params.locale\n const res = await this.client.request<{ data: TrendDetail }>(\"GET\", trendPath(slug), { query })\n return res.data\n }\n\n /** Quote a run before starting it (`POST /v1/trends/:slug/estimate`); spends nothing. */\n async estimate(slug: string, request: TrendRunRequest): Promise<TrendEstimate> {\n const res = await this.client.request<{ data: TrendEstimate }>(\n \"POST\",\n trendPath(slug, \"/estimate\"),\n { body: request },\n )\n return res.data\n }\n\n /**\n * Start a run (`POST /v1/trends/:slug/runs`, 202). Returns the job to follow.\n * With `options.idempotencyKey` (sent as the `Idempotency-Key` header) a\n * repeat with the same key answers with the first run's `jobId`.\n */\n async run(slug: string, request: TrendRunRequest, options?: TrendRunOptions): Promise<{ jobId: string }> {\n const res = await this.client.request<{ data: { jobId: string } }>(\n \"POST\",\n trendPath(slug, \"/runs\"),\n {\n body: request,\n ...(options?.idempotencyKey ? { headers: { \"Idempotency-Key\": options.idempotencyKey } } : {}),\n },\n )\n return res.data\n }\n\n /**\n * Your trend runs, newest first (`GET /v1/trends/runs`). A Full Quality\n * version of a draft is listed as its own run (`fullQualityOf`).\n */\n runs(params: ListTrendRunsParams = {}): Promise<TrendPage<TrendRun>> {\n const query: Record<string, string> = {}\n if (params.trend) query.trend = params.trend\n if (params.cursor) query.cursor = params.cursor\n if (params.limit !== undefined) query.limit = String(params.limit)\n return this.client.request(\"GET\", \"/v1/trends/runs\", { query })\n }\n\n /**\n * One of your trend runs by its job id (`GET /v1/trends/runs/:jobId`), in\n * the same shape as `runs()`. A job that is not your own trend run is a\n * `NotFoundError`.\n */\n async getRun(jobId: string): Promise<TrendRun> {\n const res = await this.client.request<{ data: TrendRun }>(\"GET\", `/v1/trends/runs/${encodeURIComponent(jobId)}`)\n return res.data\n }\n\n /**\n * The tags in use on the published catalog, each with its label in the\n * resolved locale (`GET /v1/trends/tags`), most used first.\n */\n async tags(params: { locale?: string } = {}): Promise<TrendTag[]> {\n const query: Record<string, string> = {}\n if (params.locale) query.locale = params.locale\n const res = await this.client.request<{ data: TrendTag[] }>(\"GET\", \"/v1/trends/tags\", { query })\n return res.data\n }\n\n /** Add a trend to your favorites (`PUT /v1/trends/:slug/favorite`). */\n async favorite(slug: string): Promise<void> {\n await this.client.request<void>(\"PUT\", trendPath(slug, \"/favorite\"))\n }\n\n /** Remove a trend from your favorites (`DELETE /v1/trends/:slug/favorite`). */\n async unfavorite(slug: string): Promise<void> {\n await this.client.request<void>(\"DELETE\", trendPath(slug, \"/favorite\"))\n }\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/resources/creatures.ts"],"names":[],"mappings":"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","file":"chunk-HK5FSTKG.cjs","sourcesContent":["import type { ObjectAspectRatio, CreatureAttachColumn } from \"@nodaro/shared/entities\"\nimport type { TtsProvider } from \"@nodaro/shared/models\"\nexport type { CreatureAttachColumn, ObjectAspectRatio as CreatureAspectRatio } from \"@nodaro/shared/entities\"\nexport { CREATURE_ATTACH_COLUMNS, OBJECT_ASPECT_OPTIONS as CREATURE_ASPECT_OPTIONS, OBJECT_ASPECT_DEFAULTS as CREATURE_ASPECT_DEFAULTS } from \"@nodaro/shared/entities\"\nimport type { NodaroClientCore } from \"../core.js\"\nimport type { GenerationSessionParams, Subject } from \"./nodes.js\"\nimport type { SetKeeperCatalogInput, SetKeeperCatalogResult } from \"./keepers.js\"\n\n/**\n * Creature voice — IDENTICAL shape + semantics to `Character[\"voice\"]` (the\n * \"talking creature\" stack reuses the character voice plumbing verbatim).\n * Render speech via `client.nodes.run(\"text-to-speech\", { text, voice:\n * voiceId, provider: ttsProvider, voiceType })`, then feed the audio + the\n * creature's `sourceImageUrl` to `client.nodes.run(\"lip-sync\", …)` (or\n * speech-to-video) for a talking-creature clip.\n */\nexport interface CreatureVoice {\n voiceId: string\n voiceName: string\n traits: string\n voiceType?: \"premade\" | \"library\" | \"custom\"\n /** Playable preview sample (client-played only). */\n previewUrl?: string\n /** Recommended TTS provider — send as `provider` on text-to-speech. */\n ttsProvider?: TtsProvider\n}\n\n/**\n * Re-export the shared `CreatureAttachColumn` union + its runtime tuple so SDK\n * consumers don't have to add `@nodaro/shared` as a second dependency just to\n * typecheck the `attachToColumn` field. Single source of truth lives in\n * `@nodaro/shared/entity-prompts` (`CREATURE_ATTACH_COLUMNS`).\n *\n * `CreatureAspectRatio` is re-exported as an alias of the shared\n * `ObjectAspectRatio` — `generateMotion`'s `aspectRatio` field is the 5-value\n * object enum (1:1 / 3:4 / 16:9 / 9:16 / 4:3). The creature motion route\n * deliberately REUSES `OBJECT_ASPECT_OPTIONS` server-side (a creature reference\n * clip is centered product-showcase framing, not cinematic 16:9), so the SDK\n * surfaces the same enum under a creature-friendly name. The runtime tuple is\n * re-exported as `CREATURE_ASPECT_OPTIONS` / `CREATURE_ASPECT_DEFAULTS` aliases.\n */\n\n/**\n * Creature asset-type enum — the kinds of variant a user can generate off a\n * creature's anchor main image. Mirrors the literal accepted by\n * `POST /v1/generate-creature-asset` (`backend/src/routes/generate-creature-asset.ts`).\n *\n * Delta vs `ObjectAssetType`: object's `materials` becomes `poses` (a creature\n * has poses, not materials), and there is NO `motion` value — creature motion\n * variants flow through the dedicated `/v1/generate-creature-motion` endpoint\n * (worker-side a different BullMQ job type). `custom` is the free-form bucket;\n * callers must supply `attachToColumn` explicitly since the worker can't infer\n * the destination from the asset type.\n *\n * The shared `@nodaro/shared` package does NOT export a `CREATURE_ASSET_TYPES`\n * tuple (the route validates an inline Zod enum), so the SDK defines its own\n * single-source-of-truth tuple here.\n */\nexport const CREATURE_ASSET_TYPES = [\"angles\", \"poses\", \"variations\", \"custom\"] as const\nexport type CreatureAssetType = (typeof CREATURE_ASSET_TYPES)[number]\n\n/**\n * Reference-photo kind discriminator — the mood-board roles a user can attach\n * to a creature. Mirrors the `reference_photos.kind` field accepted by\n * `backend/src/routes/creatures.ts` (the route accepts open strings; this SDK\n * type narrows to the 6 canonical roles surfaced by the Studio). `other` is\n * the free-form bucket.\n */\nexport type CreatureReferencePhotoKind =\n | \"front\"\n | \"side\"\n | \"detail\"\n | \"context\"\n | \"moodBoard\"\n | \"other\"\n\nexport interface CreatureReferencePhoto {\n url: string\n kind: CreatureReferencePhotoKind\n}\n\n/**\n * A creature record returned by Nodaro's REST API. Mirrors the camelCase\n * shape produced by `backend/src/routes/creatures.ts::toCamel()`.\n *\n * Asset buckets (`angles`, `poses`, `variations`, `motionClips`) are\n * independent JSONB arrays keyed by a human-readable variant name (e.g.\n * `\"front\"`, `\"walking\"`, `\"scarred\"`). Each entry's `url` points at an\n * R2-hosted asset.\n *\n * Creature delta vs object:\n * - `species` — free-text creature type (e.g. `\"dragon\"`, `\"wolf\"`). This is\n * the subject of the establishing-shot prompt and the primary creature\n * differentiator (object has no equivalent).\n * - `poses` (where object has `materials`) — the pose-variant asset bucket.\n * - `category` is free-text (NOT object's fixed 10-value enum) — a creature\n * can be any animal/type.\n *\n * Identity-foundation fields:\n * - `referencePhotos` — caller-supplied mood-board refs (cap 20).\n * - `canonicalDescription` — ~80–120-word LLM-authored visual caption,\n * populated by `approveMainImage()` / `recaption()`. The wire still sends\n * `\"\"` on caption sub-failure, but `get()` normalizes `\"\"` → `null` so\n * consumers see the same `string | null` semantics as characters.\n * - `styleLock` — whether asset gens should anchor to the canonical style\n * captured at approval time. Defaults to `true` on new rows.\n */\nexport interface Creature {\n id: string\n userId: string\n nodeId: string\n projectId: string | null\n name: string\n description: string | null\n /** Free-text creature type/species (e.g. \"dragon\", \"wolf\") — the creature\n * delta vs object. `null` when unset. */\n species: string | null\n category: string | null\n style: string | null\n sourceImageUrl: string | null\n /** MODEL_CATALOG image-model id the main image was generated with (or `null`).\n * Set on create + editable via the update route. */\n imageProvider: string | null\n angles: Array<{ name: string; url: string }>\n poses: Array<{ name: string; url: string }>\n variations: Array<{ name: string; url: string }>\n motionClips: Array<{ name: string; url: string }>\n /** Named Creature Boards — dense reference sheets, one per variant/mood\n * (the `generate-image/creature-board` factory preset rendered from the\n * creature's images). A first-class bucket: community publish snapshots it\n * and clone hands the consumer their own copy to extend. Defaults to `[]`.\n * `type` marks an image-collage `\"identity\"` sheet vs a plain `\"looks\"`\n * board; `sourceImages` are the R2 URLs it was collaged from. Both optional\n * + backward-compatible (legacy boards have neither). */\n boards?: Array<{ name: string; url: string; type?: \"looks\" | \"identity\"; sourceImages?: string[] }> | null\n /** The creature's voice (the \"talking creature\" stack) — same shape and\n * flow as `Character[\"voice\"]`. `null` when no voice is selected. */\n voice?: CreatureVoice | null\n referencePhotos: CreatureReferencePhoto[]\n /** `null` when no caption is set (or the LLM caption sub-failed) — the wire\n * sends `\"\"`, normalized to `null` in `get()` to match character semantics. */\n canonicalDescription: string | null\n styleLock: boolean\n /** The user's chosen DEFAULT asset take per variant (Studio version history).\n * OPAQUE map: key `\"<bucket>:<variant>\"` (e.g. `\"angles:front\"`) → the chosen\n * asset URL (one already present in that bucket). Stored verbatim — keys are\n * NOT normalized; soft-capped server-side at 200 keys / 2048-char values\n * (overflow dropped silently). Defaults to `{}`. */\n selectedAssetByVariant?: Record<string, string> | null\n deletedAt: string | null\n createdAt: string\n updatedAt: string\n}\n\n/**\n * GET /v1/creatures/:id may append a `pendingJobs` bucket the studio uses to\n * rehydrate spinners after a reload. Optional on the SDK surface — it doesn't\n * appear on `list()` rows.\n */\nexport interface CreatureDetail extends Creature {\n pendingJobs?: Array<{\n jobId: string\n assetType: string\n name: string\n status: string\n }>\n}\n\n/**\n * Body for `client.creatures.create()`. Mirrors the INSERT branch of\n * `upsertCreatureBody` in `backend/src/routes/creatures.ts`. `name` + `nodeId`\n * are required on create.\n */\nexport interface CreateCreatureInput {\n nodeId: string\n name: string\n description?: string\n /** Free-text creature type/species (the creature delta vs object). */\n species?: string\n /** Free-text category (NOT object's fixed enum — a creature can be anything). */\n category?: string\n style?: string\n workflowId?: string\n projectId?: string\n sourceImageUrl?: string\n /** Persistent image-model id (a MODEL_CATALOG image model). Validated\n * server-side — unknown / non-image / \"\" is stored as `null`. */\n imageProvider?: string | null\n referencePhotos?: CreatureReferencePhoto[]\n canonicalDescription?: string\n styleLock?: boolean\n /** The user's chosen DEFAULT asset take per variant. OPAQUE\n * `\"<bucket>:<variant>\"` → chosen-URL map; a write REPLACES the whole map.\n * Keys stored verbatim; soft-capped server-side at 200 keys / 2048-char values. */\n selectedAssetByVariant?: Record<string, string>\n /** Initial voice selection (see `CreatureVoice`). Omit for a voiceless creature. */\n voice?: CreatureVoice | null\n}\n\n/**\n * Body for `client.creatures.update()`. Mirrors the UPDATE branch of\n * `upsertCreatureBody` in `backend/src/routes/creatures.ts`.\n *\n * Worker-owned asset buckets (`angles` / `poses` / `variations` /\n * `motionClips`) are deliberately omitted — the route drops them on UPDATE\n * so a Studio auto-save with a stale snapshot cannot clobber the worker's\n * atomic `append_creature_asset()` writes.\n *\n * `expectedUpdatedAt` is the optimistic-concurrency token: when present, the\n * UPDATE only succeeds if the row's `updated_at` still matches; on mismatch\n * the route returns 409 so the studio can re-fetch + merge.\n */\nexport interface UpdateCreatureInput {\n name?: string\n description?: string\n /** Free-text creature type/species (the creature delta vs object). */\n species?: string\n category?: string\n style?: string\n sourceImageUrl?: string\n /** Persistent image-model id (a MODEL_CATALOG image model). Validated\n * server-side — unknown / non-image / \"\" is stored as `null`. */\n imageProvider?: string | null\n referencePhotos?: CreatureReferencePhoto[]\n canonicalDescription?: string\n styleLock?: boolean\n /** The user's chosen DEFAULT asset take per variant. OPAQUE\n * `\"<bucket>:<variant>\"` → chosen-URL map; a write REPLACES the whole map\n * (omit to leave untouched). Keys stored verbatim; soft-capped server-side\n * at 200 keys / 2048-char values. */\n selectedAssetByVariant?: Record<string, string>\n /** Named Creature Boards (see `Creature.boards`) — whole-array replace,\n * USER-owned (unlike the worker-owned buckets it flows through UPDATE).\n * Server caps: 24 boards, 200-char names, 30 sourceImages per board. */\n boards?: Array<{ name: string; url: string; type?: \"looks\" | \"identity\"; sourceImages?: string[] }>\n /** Voice selection (see `CreatureVoice`) — whole-object replace; pass\n * `null` to clear the voice, omit to leave untouched. */\n voice?: CreatureVoice | null\n expectedUpdatedAt?: string\n}\n\nexport interface UpdateCreatureResult {\n id: string\n updatedAt: string\n}\n\n/**\n * Combined create + update body (parameter for both branches). Exported for\n * callers that want to drive a single `upsert` flow without picking between\n * `Create*` and `Update*`. Mirrors the `upsertCreatureBody` Zod schema in\n * `backend/src/routes/creatures.ts`. `nodeId` + `name` are required on INSERT;\n * `id` flips the route into UPDATE mode.\n */\nexport interface UpsertCreatureInput extends CreateCreatureInput {\n id?: string\n expectedUpdatedAt?: string\n}\n\nexport type UpsertCreatureResult = { id: string } | UpdateCreatureResult\n\nexport interface ListCreaturesParams {\n /** When true, return archived creatures instead of active ones. */\n archived?: boolean\n /** Optional project filter — server-scoped to the caller's user. */\n projectId?: string\n /**\n * Search words: only the creatures whose name or description contains\n * every word (split on spaces, the first 5), in any order, ignoring case.\n * Each word is matched as written (`%`, `_` and `*` are not wildcards;\n * punctuation is kept); blank means no search; up to 200 characters.\n * Combines with the other filters and with `cursor` paging.\n */\n q?: string\n /**\n * Max rows to return (cap 500). OPT-IN: omitted, the server returns the\n * full legacy listing with no `nextCursor`; supplied, the response is one\n * page plus `nextCursor` — keep passing it back until it is `null`.\n */\n limit?: number\n /** Opaque cursor from a prior page's `nextCursor` (fetches the next page). */\n cursor?: string\n}\n\n/**\n * Input for `client.creatures.generate()` — fires the\n * `POST /v1/generate-creature` route. Produces 1–10 candidate\n * main images; each lands as one `jobs` row in `pending` state and is then\n * enqueued for the worker.\n *\n * When `attachToCreatureId` is set AND `count === 1`, the worker writes the\n * resulting URL directly to `creatures.source_image_url` on completion —\n * caller doesn't need a separate `approveMainImage` call. Multi-candidate\n * batches MUST go through explicit approval so the user picks the winner.\n *\n * `seedPromptHint` flows the parameter-picker's prompt fragment through to the\n * worker so a catalog selection (e.g. \"armored frost dragon\") gets appended to\n * the generated prompt context.\n */\nexport interface GenerateCreatureInput extends GenerationSessionParams {\n name: string\n description?: string\n userPrompt?: string\n /** Free-text creature type/species (the creature delta vs object). */\n species?: string\n category?: string\n style?: \"realistic\" | \"anime\" | \"3d-pixar\" | \"illustration\"\n sourceImageUrl?: string\n provider?: string\n /** Number of candidate images to generate (1–10; server-validated). */\n count?: number\n /** Auto-attach the result to this creature row (single-candidate only). */\n attachToCreatureId?: string\n /** Parameter-picker prompt-fragment pass-through. */\n seedPromptHint?: string\n /**\n * What the creature is, as picker-catalog ids ({@link Subject} — `animal`\n * above all; the same type and bounds as `generateImage`'s). The platform\n * writes the wording and folds it into the prompt after `description`, so\n * send ids rather than phrasing a pick yourself.\n */\n subject?: Subject\n /** Optional name to set on the attached row alongside the main image. */\n attachName?: string\n /** Optimistic-concurrency token for the single-candidate auto-attach path. */\n expectedUpdatedAt?: string\n}\n\n/**\n * `generate()` response — `jobIds` is ALWAYS present (the harmonized contract,\n * matching characters). `jobId` is a deprecated back-compat alias populated only\n * on `count === 1`; prefer `jobIds`. (Will be removed on the next major.)\n */\nexport interface GenerateCreatureResult {\n jobIds: string[]\n /** @deprecated count===1 back-compat alias — use `jobIds`. */\n jobId?: string\n}\n\n/**\n * Input for `client.creatures.generateAsset()` — fires the\n * `POST /v1/generate-creature-asset` route. Produces a single\n * angles / poses / variations / custom variant.\n *\n * When all three studio-path fields are set (`attachToCreatureId` +\n * `attachToColumn` + `attachName`), the worker appends\n * `{ name: attachName, url: <result> }` to the named JSONB array column on\n * the user's creature row on completion. `attachToColumn` is REQUIRED for\n * `assetType === \"custom\"` — the worker can't infer the bucket from the\n * asset type.\n */\nexport interface GenerateCreatureAssetInput extends GenerationSessionParams {\n assetType: CreatureAssetType\n variant: string\n name: string\n description?: string\n userPrompt?: string\n category?: string\n style?: string\n sourceImageUrl?: string\n provider?: string\n attachToCreatureId?: string\n attachToColumn?: CreatureAttachColumn\n attachName?: string\n /** Parameter-picker prompt-fragment pass-through. */\n seedPromptHint?: string\n}\n\nexport interface GenerateCreatureAssetResult {\n jobId: string\n}\n\n/**\n * Input for `client.creatures.generateMotion()` — fires the\n * `POST /v1/generate-creature-motion` route. Produces a single motion clip\n * (idle, prowl, attack, etc.) animated FROM a static creature-shot image.\n *\n * Mirrors `client.objects.generateMotion()` — the creature motion route reuses\n * the entity-agnostic object motion helpers server-side. The route hardcodes\n * the attach column to `motion_clips` — callers supply `attachToCreatureId` +\n * `attachName` only.\n *\n * `sourceImageUrl` is REQUIRED — image-to-video needs a source frame and the\n * route has no fallback (the studio path supplies the canonical creature-shot\n * URL explicitly).\n *\n * Defaults vs location:\n * - `provider` defaults to `\"kling-turbo\"` (not location's `\"kling\"`)\n * - `aspectRatio` defaults to `\"1:1\"` server-side via\n * `resolveObjectAspectRatio({ assetType: \"motion\" })` — creatures use\n * centered reference framing, not cinematic establishing shots.\n *\n * When the studio path is set (`attachToCreatureId` + `attachName`), the\n * worker appends `{ name: attachName, url: <result> }` to the creature row's\n * `motion_clips` JSONB column on completion.\n */\nexport interface GenerateCreatureMotionInput extends GenerationSessionParams {\n motionPrompt: string\n sourceImageUrl: string\n provider?: string\n name: string\n /** Source clip URL — when set, worker routes to video-to-video refine. */\n refineFromVideoUrl?: string\n category?: string\n style?: \"realistic\" | \"anime\" | \"3d-pixar\" | \"illustration\"\n canonicalDescription?: string\n /** Parameter-picker prompt-fragment pass-through. */\n seedPromptHint?: string\n attachToCreatureId?: string\n attachName?: string\n /**\n * Optional aspect ratio override. Defaults to 1:1 server-side. One of the\n * 5-value `CreatureAspectRatio` union (1:1 / 3:4 / 16:9 / 9:16 / 4:3) — the\n * creature route reuses the object aspect enum.\n */\n aspectRatio?: ObjectAspectRatio\n /**\n * Optional clip duration in seconds. Validated server-side against the chosen\n * provider's allowed durations (e.g. kling 5/10, wan-i2v 5/10/15); omitted →\n * the model's own default (no behavior change). Mirrors generate-video's\n * per-model i2v duration lever.\n */\n duration?: number\n}\n\nexport interface GenerateCreatureMotionResult {\n jobId: string\n}\n\nexport interface ApproveCreatureMainImageResult {\n sourceImageUrl: string\n /**\n * LLM-authored caption. `null` when the LLM caption sub-failed — the wire\n * sends `\"\"`, normalized to `null` here so consumers see the same\n * `string | null` semantics as characters. The main image is still set; call\n * `recaption()` to retry.\n */\n canonicalDescription: string | null\n}\n\nexport interface RecaptionCreatureResult {\n canonicalDescription: string\n}\n\nexport class CreaturesResource {\n constructor(private client: NodaroClientCore) {}\n\n /**\n * List the caller's creatures. By default returns active creatures only;\n * pass `archived: true` to fetch soft-deleted rows for an \"archive\" view.\n * Optional `projectId` scopes the result to a single project; `q` keeps the\n * creatures whose name or description contains it.\n */\n list(params: ListCreaturesParams = {}): Promise<{ creatures: Creature[]; nextCursor?: string | null }> {\n const query: Record<string, string | undefined> = {}\n if (params.archived) query.archived = \"true\"\n if (params.projectId) query.projectId = params.projectId\n if (params.q) query.q = params.q\n if (params.limit !== undefined) query.limit = String(params.limit)\n if (params.cursor) query.cursor = params.cursor\n return this.client.request(\"GET\", \"/v1/creatures\", { query })\n }\n\n /**\n * Convenience wrapper for `list({ archived: true })`. Returns soft-deleted\n * rows so callers can drive a UI \"Archived\" tab without re-encoding the\n * query param.\n *\n * `archived` is omitted from the param type — it's always set to `true` here.\n */\n listArchived(params: Omit<ListCreaturesParams, \"archived\"> = {}): Promise<{ creatures: Creature[]; nextCursor?: string | null }> {\n return this.list({ ...params, archived: true })\n }\n\n /**\n * Fetch a single creature including in-flight asset job state. Soft-deleted\n * (archived) rows are NOT returned by id — the route enforces\n * `deleted_at IS NULL` so archived creatures 404 (uniform \"not_found\" — does\n * not leak the deleted vs non-existent distinction).\n */\n async get(id: string): Promise<CreatureDetail> {\n const res = await this.client.request<CreatureDetail>(\n \"GET\",\n `/v1/creatures/${encodeURIComponent(id)}`,\n )\n // Normalize the wire `\"\"` caption (DB null / LLM sub-failure) → null so\n // consumers see the same `string | null` semantics as characters. New\n // object — never mutate the response.\n return { ...res, canonicalDescription: res.canonicalDescription || null }\n }\n\n /**\n * Create a new creature. `name` + `nodeId` are required — the route 400s\n * otherwise. Returns the new row's id.\n *\n * Note: the underlying route is the same `POST /v1/creatures` upsert that\n * powers `update()`. This convenience wrapper enforces the INSERT-required\n * fields at the type level and never sends an `id`.\n */\n create(data: CreateCreatureInput): Promise<{ id: string }> {\n return this.client.request(\"POST\", \"/v1/creatures\", { body: data })\n }\n\n /**\n * Update a creature. Only the fields you pass are written — undefined keys\n * are NOT touched on the row. Worker-owned asset buckets are intentionally\n * not exposed on this surface (see `UpdateCreatureInput` for the rationale).\n *\n * Optimistic-concurrency: pass `expectedUpdatedAt` to require the row's\n * `updated_at` still matches; on mismatch the route returns 409\n * `concurrent_modification` carrying the fresh `updatedAt`. The SDK\n * surfaces that as a generic `NodaroError` with the same code.\n */\n update(id: string, data: UpdateCreatureInput): Promise<UpdateCreatureResult> {\n return this.client.request(\"POST\", \"/v1/creatures\", {\n body: { id, ...data },\n })\n }\n\n /**\n * Soft-delete (archive) a creature. The row is hidden from `list()` by\n * default but recoverable via `restore(id)` or visible under\n * `listArchived()`. Idempotent — repeating a delete on an already-archived\n * row is a no-op.\n */\n delete(id: string): Promise<{ success: true; archived: true }> {\n return this.client.request(\"DELETE\", `/v1/creatures/${encodeURIComponent(id)}`)\n }\n\n /**\n * Hard-delete (permanent) a creature — the row + every R2 asset it\n * references. Archived rows ONLY: active creatures return 400 `not_archived`.\n * Call `delete()` first to archive, then `permanentDelete()` to destroy.\n *\n * Mirrors the `app_runs` permanent-delete pattern (archive-first) so a\n * stray SDK / curl caller cannot bypass the studio's archive-first UI\n * flow.\n */\n permanentDelete(id: string): Promise<{ success: true; permanent: true }> {\n return this.client.request(\"DELETE\", `/v1/creatures/${encodeURIComponent(id)}`, {\n query: { permanent: \"true\" },\n })\n }\n\n /**\n * Un-archive a creature. If the original name now collides (case-\n * insensitive) with an active row, the server auto-suffixes \"(restored)\"\n * and returns the effective name.\n */\n restore(id: string): Promise<{ id: string; name: string }> {\n return this.client.request(\"POST\", `/v1/creatures/${encodeURIComponent(id)}/restore`)\n }\n\n /**\n * Admin only: put one of your own creatures on the shared Nodaro Keepers\n * shelf (`client.keepers.catalog()`), or take it off. A first-party session\n * or your personal token; `forbidden` for anyone who is not a platform\n * admin, `not_found` for a row that is not yours.\n */\n setCatalog(id: string, input: SetKeeperCatalogInput): Promise<SetKeeperCatalogResult> {\n return this.client.request(\"PUT\", `/v1/creatures/${encodeURIComponent(id)}/catalog`, { body: input })\n }\n\n /**\n * Fire `POST /v1/generate-creature` to produce one or more candidate main\n * images. With `count > 1`, all jobs are reserved up-front before any\n * is enqueued — mid-batch failures roll back atomically.\n *\n * When `attachToCreatureId` is set AND `count === 1`, the worker writes\n * the result directly to the row's `source_image_url`; otherwise you must\n * call `approveMainImage()` after picking a candidate.\n */\n async generate(data: GenerateCreatureInput): Promise<GenerateCreatureResult> {\n const res = await this.client.request<{ jobId?: string; jobIds?: string[] }>(\n \"POST\", \"/v1/generate-creature\", { body: data },\n )\n // Tolerate the legacy `{ jobId }`-only shape (older server): synthesize jobIds.\n const jobIds = res.jobIds ?? (res.jobId ? [res.jobId] : [])\n return res.jobId ? { jobIds, jobId: res.jobId } : { jobIds }\n }\n\n /**\n * Fire `POST /v1/generate-creature-asset` to produce a single variant.\n * When the studio path is set (`attachToCreatureId` + `attachToColumn` +\n * `attachName`), the worker appends `{ name: attachName, url: <result> }`\n * to the named JSONB array column on completion.\n *\n * Note: `attachToColumn` is REQUIRED for `assetType === \"custom\"` — the\n * worker can't infer the bucket from the asset type. For canonical asset\n * types (`angles` / `poses` / `variations`), the column is derived\n * automatically by the route.\n */\n generateAsset(\n data: GenerateCreatureAssetInput,\n ): Promise<GenerateCreatureAssetResult> {\n return this.client.request(\"POST\", \"/v1/generate-creature-asset\", { body: data })\n }\n\n /**\n * Fire `POST /v1/generate-creature-motion` to animate the creature's main\n * image into a motion clip. Image-to-video, single clip per call; the\n * attach column is hardcoded to `motion_clips` server-side (creatures have a\n * single motion bucket so the caller doesn't supply `attachToColumn`).\n * When the studio path is set (`attachToCreatureId` + `attachName`), the\n * worker appends `{ name: attachName, url: <result> }` to the row's\n * `motion_clips` column on completion.\n *\n * Defaults: `provider` → `\"kling-turbo\"`, `aspectRatio` → `\"1:1\"` (set\n * server-side via `resolveObjectAspectRatio({ assetType: \"motion\" })`).\n */\n generateMotion(\n data: GenerateCreatureMotionInput,\n ): Promise<GenerateCreatureMotionResult> {\n return this.client.request(\"POST\", \"/v1/generate-creature-motion\", { body: data })\n }\n\n /**\n * Approve a completed `generate-creature` job as the creature's main image.\n * Sets `source_image_url` and fires the LLM caption (Claude Sonnet vision)\n * inline. Returns the new main-image URL plus the caption.\n *\n * Caption-failure semantics: the route still sends `\"\"` on LLM sub-failure,\n * but the SDK normalizes `\"\"` → `null` here so `canonicalDescription` carries\n * the same `string | null` semantics as characters. The main image is still\n * set; call `recaption()` to retry.\n *\n * Optimistic-concurrency: pass `expectedUpdatedAt` to gate the update on\n * the row's current `updated_at`; on mismatch the route returns 409\n * `concurrent_modification` carrying the fresh token.\n */\n async approveMainImage(\n id: string,\n candidateJobId: string,\n expectedUpdatedAt?: string,\n ): Promise<ApproveCreatureMainImageResult> {\n const res = await this.client.request<{ sourceImageUrl: string; canonicalDescription: string | null }>(\n \"POST\",\n `/v1/creatures/${encodeURIComponent(id)}/approve-main-image`,\n { body: { candidateJobId, expectedUpdatedAt } },\n )\n // Normalize the wire `\"\"` (LLM sub-failure) → null; build a new object\n // rather than mutating the response.\n return { sourceImageUrl: res.sourceImageUrl, canonicalDescription: res.canonicalDescription || null }\n }\n\n /**\n * Re-fire the LLM caption against the creature's current main image. 502s\n * on LLM failure (unlike `approveMainImage` which preserves the side-effect\n * and returns \"\"); returns 400 `main_image_required` if no main image is\n * set yet.\n *\n * The route is a pure idempotent retry — it does NOT accept an\n * `expectedUpdatedAt` token (backend route is idempotent retry, not gated on\n * optimistic-concurrency).\n */\n recaption(id: string): Promise<RecaptionCreatureResult> {\n return this.client.request(\n \"POST\",\n `/v1/creatures/${encodeURIComponent(id)}/llm-caption`,\n )\n }\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/resources/creatures.ts"],"names":[],"mappings":"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","file":"chunk-HWSYNUSC.js","sourcesContent":["import type { ObjectAspectRatio, CreatureAttachColumn } from \"@nodaro/shared/entities\"\nimport type { TtsProvider } from \"@nodaro/shared/models\"\nexport type { CreatureAttachColumn, ObjectAspectRatio as CreatureAspectRatio } from \"@nodaro/shared/entities\"\nexport { CREATURE_ATTACH_COLUMNS, OBJECT_ASPECT_OPTIONS as CREATURE_ASPECT_OPTIONS, OBJECT_ASPECT_DEFAULTS as CREATURE_ASPECT_DEFAULTS } from \"@nodaro/shared/entities\"\nimport type { NodaroClientCore } from \"../core.js\"\nimport type { GenerationSessionParams, Subject } from \"./nodes.js\"\nimport type { SetKeeperCatalogInput, SetKeeperCatalogResult } from \"./keepers.js\"\n\n/**\n * Creature voice — IDENTICAL shape + semantics to `Character[\"voice\"]` (the\n * \"talking creature\" stack reuses the character voice plumbing verbatim).\n * Render speech via `client.nodes.run(\"text-to-speech\", { text, voice:\n * voiceId, provider: ttsProvider, voiceType })`, then feed the audio + the\n * creature's `sourceImageUrl` to `client.nodes.run(\"lip-sync\", …)` (or\n * speech-to-video) for a talking-creature clip.\n */\nexport interface CreatureVoice {\n voiceId: string\n voiceName: string\n traits: string\n voiceType?: \"premade\" | \"library\" | \"custom\"\n /** Playable preview sample (client-played only). */\n previewUrl?: string\n /** Recommended TTS provider — send as `provider` on text-to-speech. */\n ttsProvider?: TtsProvider\n}\n\n/**\n * Re-export the shared `CreatureAttachColumn` union + its runtime tuple so SDK\n * consumers don't have to add `@nodaro/shared` as a second dependency just to\n * typecheck the `attachToColumn` field. Single source of truth lives in\n * `@nodaro/shared/entity-prompts` (`CREATURE_ATTACH_COLUMNS`).\n *\n * `CreatureAspectRatio` is re-exported as an alias of the shared\n * `ObjectAspectRatio` — `generateMotion`'s `aspectRatio` field is the 5-value\n * object enum (1:1 / 3:4 / 16:9 / 9:16 / 4:3). The creature motion route\n * deliberately REUSES `OBJECT_ASPECT_OPTIONS` server-side (a creature reference\n * clip is centered product-showcase framing, not cinematic 16:9), so the SDK\n * surfaces the same enum under a creature-friendly name. The runtime tuple is\n * re-exported as `CREATURE_ASPECT_OPTIONS` / `CREATURE_ASPECT_DEFAULTS` aliases.\n */\n\n/**\n * Creature asset-type enum — the kinds of variant a user can generate off a\n * creature's anchor main image. Mirrors the literal accepted by\n * `POST /v1/generate-creature-asset` (`backend/src/routes/generate-creature-asset.ts`).\n *\n * Delta vs `ObjectAssetType`: object's `materials` becomes `poses` (a creature\n * has poses, not materials), and there is NO `motion` value — creature motion\n * variants flow through the dedicated `/v1/generate-creature-motion` endpoint\n * (worker-side a different BullMQ job type). `custom` is the free-form bucket;\n * callers must supply `attachToColumn` explicitly since the worker can't infer\n * the destination from the asset type.\n *\n * The shared `@nodaro/shared` package does NOT export a `CREATURE_ASSET_TYPES`\n * tuple (the route validates an inline Zod enum), so the SDK defines its own\n * single-source-of-truth tuple here.\n */\nexport const CREATURE_ASSET_TYPES = [\"angles\", \"poses\", \"variations\", \"custom\"] as const\nexport type CreatureAssetType = (typeof CREATURE_ASSET_TYPES)[number]\n\n/**\n * Reference-photo kind discriminator — the mood-board roles a user can attach\n * to a creature. Mirrors the `reference_photos.kind` field accepted by\n * `backend/src/routes/creatures.ts` (the route accepts open strings; this SDK\n * type narrows to the 6 canonical roles surfaced by the Studio). `other` is\n * the free-form bucket.\n */\nexport type CreatureReferencePhotoKind =\n | \"front\"\n | \"side\"\n | \"detail\"\n | \"context\"\n | \"moodBoard\"\n | \"other\"\n\nexport interface CreatureReferencePhoto {\n url: string\n kind: CreatureReferencePhotoKind\n}\n\n/**\n * A creature record returned by Nodaro's REST API. Mirrors the camelCase\n * shape produced by `backend/src/routes/creatures.ts::toCamel()`.\n *\n * Asset buckets (`angles`, `poses`, `variations`, `motionClips`) are\n * independent JSONB arrays keyed by a human-readable variant name (e.g.\n * `\"front\"`, `\"walking\"`, `\"scarred\"`). Each entry's `url` points at an\n * R2-hosted asset.\n *\n * Creature delta vs object:\n * - `species` — free-text creature type (e.g. `\"dragon\"`, `\"wolf\"`). This is\n * the subject of the establishing-shot prompt and the primary creature\n * differentiator (object has no equivalent).\n * - `poses` (where object has `materials`) — the pose-variant asset bucket.\n * - `category` is free-text (NOT object's fixed 10-value enum) — a creature\n * can be any animal/type.\n *\n * Identity-foundation fields:\n * - `referencePhotos` — caller-supplied mood-board refs (cap 20).\n * - `canonicalDescription` — ~80–120-word LLM-authored visual caption,\n * populated by `approveMainImage()` / `recaption()`. The wire still sends\n * `\"\"` on caption sub-failure, but `get()` normalizes `\"\"` → `null` so\n * consumers see the same `string | null` semantics as characters.\n * - `styleLock` — whether asset gens should anchor to the canonical style\n * captured at approval time. Defaults to `true` on new rows.\n */\nexport interface Creature {\n id: string\n userId: string\n nodeId: string\n projectId: string | null\n name: string\n description: string | null\n /** Free-text creature type/species (e.g. \"dragon\", \"wolf\") — the creature\n * delta vs object. `null` when unset. */\n species: string | null\n category: string | null\n style: string | null\n sourceImageUrl: string | null\n /** MODEL_CATALOG image-model id the main image was generated with (or `null`).\n * Set on create + editable via the update route. */\n imageProvider: string | null\n angles: Array<{ name: string; url: string }>\n poses: Array<{ name: string; url: string }>\n variations: Array<{ name: string; url: string }>\n motionClips: Array<{ name: string; url: string }>\n /** Named Creature Boards — dense reference sheets, one per variant/mood\n * (the `generate-image/creature-board` factory preset rendered from the\n * creature's images). A first-class bucket: community publish snapshots it\n * and clone hands the consumer their own copy to extend. Defaults to `[]`.\n * `type` marks an image-collage `\"identity\"` sheet vs a plain `\"looks\"`\n * board; `sourceImages` are the R2 URLs it was collaged from. Both optional\n * + backward-compatible (legacy boards have neither). */\n boards?: Array<{ name: string; url: string; type?: \"looks\" | \"identity\"; sourceImages?: string[] }> | null\n /** The creature's voice (the \"talking creature\" stack) — same shape and\n * flow as `Character[\"voice\"]`. `null` when no voice is selected. */\n voice?: CreatureVoice | null\n referencePhotos: CreatureReferencePhoto[]\n /** `null` when no caption is set (or the LLM caption sub-failed) — the wire\n * sends `\"\"`, normalized to `null` in `get()` to match character semantics. */\n canonicalDescription: string | null\n styleLock: boolean\n /** The user's chosen DEFAULT asset take per variant (Studio version history).\n * OPAQUE map: key `\"<bucket>:<variant>\"` (e.g. `\"angles:front\"`) → the chosen\n * asset URL (one already present in that bucket). Stored verbatim — keys are\n * NOT normalized; soft-capped server-side at 200 keys / 2048-char values\n * (overflow dropped silently). Defaults to `{}`. */\n selectedAssetByVariant?: Record<string, string> | null\n deletedAt: string | null\n createdAt: string\n updatedAt: string\n}\n\n/**\n * GET /v1/creatures/:id may append a `pendingJobs` bucket the studio uses to\n * rehydrate spinners after a reload. Optional on the SDK surface — it doesn't\n * appear on `list()` rows.\n */\nexport interface CreatureDetail extends Creature {\n pendingJobs?: Array<{\n jobId: string\n assetType: string\n name: string\n status: string\n }>\n}\n\n/**\n * Body for `client.creatures.create()`. Mirrors the INSERT branch of\n * `upsertCreatureBody` in `backend/src/routes/creatures.ts`. `name` + `nodeId`\n * are required on create.\n */\nexport interface CreateCreatureInput {\n nodeId: string\n name: string\n description?: string\n /** Free-text creature type/species (the creature delta vs object). */\n species?: string\n /** Free-text category (NOT object's fixed enum — a creature can be anything). */\n category?: string\n style?: string\n workflowId?: string\n projectId?: string\n sourceImageUrl?: string\n /** Persistent image-model id (a MODEL_CATALOG image model). Validated\n * server-side — unknown / non-image / \"\" is stored as `null`. */\n imageProvider?: string | null\n referencePhotos?: CreatureReferencePhoto[]\n canonicalDescription?: string\n styleLock?: boolean\n /** The user's chosen DEFAULT asset take per variant. OPAQUE\n * `\"<bucket>:<variant>\"` → chosen-URL map; a write REPLACES the whole map.\n * Keys stored verbatim; soft-capped server-side at 200 keys / 2048-char values. */\n selectedAssetByVariant?: Record<string, string>\n /** Initial voice selection (see `CreatureVoice`). Omit for a voiceless creature. */\n voice?: CreatureVoice | null\n}\n\n/**\n * Body for `client.creatures.update()`. Mirrors the UPDATE branch of\n * `upsertCreatureBody` in `backend/src/routes/creatures.ts`.\n *\n * Worker-owned asset buckets (`angles` / `poses` / `variations` /\n * `motionClips`) are deliberately omitted — the route drops them on UPDATE\n * so a Studio auto-save with a stale snapshot cannot clobber the worker's\n * atomic `append_creature_asset()` writes.\n *\n * `expectedUpdatedAt` is the optimistic-concurrency token: when present, the\n * UPDATE only succeeds if the row's `updated_at` still matches; on mismatch\n * the route returns 409 so the studio can re-fetch + merge.\n */\nexport interface UpdateCreatureInput {\n name?: string\n description?: string\n /** Free-text creature type/species (the creature delta vs object). */\n species?: string\n category?: string\n style?: string\n sourceImageUrl?: string\n /** Persistent image-model id (a MODEL_CATALOG image model). Validated\n * server-side — unknown / non-image / \"\" is stored as `null`. */\n imageProvider?: string | null\n referencePhotos?: CreatureReferencePhoto[]\n canonicalDescription?: string\n styleLock?: boolean\n /** The user's chosen DEFAULT asset take per variant. OPAQUE\n * `\"<bucket>:<variant>\"` → chosen-URL map; a write REPLACES the whole map\n * (omit to leave untouched). Keys stored verbatim; soft-capped server-side\n * at 200 keys / 2048-char values. */\n selectedAssetByVariant?: Record<string, string>\n /** Named Creature Boards (see `Creature.boards`) — whole-array replace,\n * USER-owned (unlike the worker-owned buckets it flows through UPDATE).\n * Server caps: 24 boards, 200-char names, 30 sourceImages per board. */\n boards?: Array<{ name: string; url: string; type?: \"looks\" | \"identity\"; sourceImages?: string[] }>\n /** Voice selection (see `CreatureVoice`) — whole-object replace; pass\n * `null` to clear the voice, omit to leave untouched. */\n voice?: CreatureVoice | null\n expectedUpdatedAt?: string\n}\n\nexport interface UpdateCreatureResult {\n id: string\n updatedAt: string\n}\n\n/**\n * Combined create + update body (parameter for both branches). Exported for\n * callers that want to drive a single `upsert` flow without picking between\n * `Create*` and `Update*`. Mirrors the `upsertCreatureBody` Zod schema in\n * `backend/src/routes/creatures.ts`. `nodeId` + `name` are required on INSERT;\n * `id` flips the route into UPDATE mode.\n */\nexport interface UpsertCreatureInput extends CreateCreatureInput {\n id?: string\n expectedUpdatedAt?: string\n}\n\nexport type UpsertCreatureResult = { id: string } | UpdateCreatureResult\n\nexport interface ListCreaturesParams {\n /** When true, return archived creatures instead of active ones. */\n archived?: boolean\n /** Optional project filter — server-scoped to the caller's user. */\n projectId?: string\n /**\n * Search words: only the creatures whose name or description contains\n * every word (split on spaces, the first 5), in any order, ignoring case.\n * Each word is matched as written (`%`, `_` and `*` are not wildcards;\n * punctuation is kept); blank means no search; up to 200 characters.\n * Combines with the other filters and with `cursor` paging.\n */\n q?: string\n /**\n * Max rows to return (cap 500). OPT-IN: omitted, the server returns the\n * full legacy listing with no `nextCursor`; supplied, the response is one\n * page plus `nextCursor` — keep passing it back until it is `null`.\n */\n limit?: number\n /** Opaque cursor from a prior page's `nextCursor` (fetches the next page). */\n cursor?: string\n}\n\n/**\n * Input for `client.creatures.generate()` — fires the\n * `POST /v1/generate-creature` route. Produces 1–10 candidate\n * main images; each lands as one `jobs` row in `pending` state and is then\n * enqueued for the worker.\n *\n * When `attachToCreatureId` is set AND `count === 1`, the worker writes the\n * resulting URL directly to `creatures.source_image_url` on completion —\n * caller doesn't need a separate `approveMainImage` call. Multi-candidate\n * batches MUST go through explicit approval so the user picks the winner.\n *\n * `seedPromptHint` flows the parameter-picker's prompt fragment through to the\n * worker so a catalog selection (e.g. \"armored frost dragon\") gets appended to\n * the generated prompt context.\n */\nexport interface GenerateCreatureInput extends GenerationSessionParams {\n name: string\n description?: string\n userPrompt?: string\n /** Free-text creature type/species (the creature delta vs object). */\n species?: string\n category?: string\n style?: \"realistic\" | \"anime\" | \"3d-pixar\" | \"illustration\"\n sourceImageUrl?: string\n provider?: string\n /** Number of candidate images to generate (1–10; server-validated). */\n count?: number\n /** Auto-attach the result to this creature row (single-candidate only). */\n attachToCreatureId?: string\n /** Parameter-picker prompt-fragment pass-through. */\n seedPromptHint?: string\n /**\n * What the creature is, as picker-catalog ids ({@link Subject} — `animal`\n * above all; the same type and bounds as `generateImage`'s). The platform\n * writes the wording and folds it into the prompt after `description`, so\n * send ids rather than phrasing a pick yourself.\n */\n subject?: Subject\n /** Optional name to set on the attached row alongside the main image. */\n attachName?: string\n /** Optimistic-concurrency token for the single-candidate auto-attach path. */\n expectedUpdatedAt?: string\n}\n\n/**\n * `generate()` response — `jobIds` is ALWAYS present (the harmonized contract,\n * matching characters). `jobId` is a deprecated back-compat alias populated only\n * on `count === 1`; prefer `jobIds`. (Will be removed on the next major.)\n */\nexport interface GenerateCreatureResult {\n jobIds: string[]\n /** @deprecated count===1 back-compat alias — use `jobIds`. */\n jobId?: string\n}\n\n/**\n * Input for `client.creatures.generateAsset()` — fires the\n * `POST /v1/generate-creature-asset` route. Produces a single\n * angles / poses / variations / custom variant.\n *\n * When all three studio-path fields are set (`attachToCreatureId` +\n * `attachToColumn` + `attachName`), the worker appends\n * `{ name: attachName, url: <result> }` to the named JSONB array column on\n * the user's creature row on completion. `attachToColumn` is REQUIRED for\n * `assetType === \"custom\"` — the worker can't infer the bucket from the\n * asset type.\n */\nexport interface GenerateCreatureAssetInput extends GenerationSessionParams {\n assetType: CreatureAssetType\n variant: string\n name: string\n description?: string\n userPrompt?: string\n category?: string\n style?: string\n sourceImageUrl?: string\n provider?: string\n attachToCreatureId?: string\n attachToColumn?: CreatureAttachColumn\n attachName?: string\n /** Parameter-picker prompt-fragment pass-through. */\n seedPromptHint?: string\n}\n\nexport interface GenerateCreatureAssetResult {\n jobId: string\n}\n\n/**\n * Input for `client.creatures.generateMotion()` — fires the\n * `POST /v1/generate-creature-motion` route. Produces a single motion clip\n * (idle, prowl, attack, etc.) animated FROM a static creature-shot image.\n *\n * Mirrors `client.objects.generateMotion()` — the creature motion route reuses\n * the entity-agnostic object motion helpers server-side. The route hardcodes\n * the attach column to `motion_clips` — callers supply `attachToCreatureId` +\n * `attachName` only.\n *\n * `sourceImageUrl` is REQUIRED — image-to-video needs a source frame and the\n * route has no fallback (the studio path supplies the canonical creature-shot\n * URL explicitly).\n *\n * Defaults vs location:\n * - `provider` defaults to `\"kling-turbo\"` (not location's `\"kling\"`)\n * - `aspectRatio` defaults to `\"1:1\"` server-side via\n * `resolveObjectAspectRatio({ assetType: \"motion\" })` — creatures use\n * centered reference framing, not cinematic establishing shots.\n *\n * When the studio path is set (`attachToCreatureId` + `attachName`), the\n * worker appends `{ name: attachName, url: <result> }` to the creature row's\n * `motion_clips` JSONB column on completion.\n */\nexport interface GenerateCreatureMotionInput extends GenerationSessionParams {\n motionPrompt: string\n sourceImageUrl: string\n provider?: string\n name: string\n /** Source clip URL — when set, worker routes to video-to-video refine. */\n refineFromVideoUrl?: string\n category?: string\n style?: \"realistic\" | \"anime\" | \"3d-pixar\" | \"illustration\"\n canonicalDescription?: string\n /** Parameter-picker prompt-fragment pass-through. */\n seedPromptHint?: string\n attachToCreatureId?: string\n attachName?: string\n /**\n * Optional aspect ratio override. Defaults to 1:1 server-side. One of the\n * 5-value `CreatureAspectRatio` union (1:1 / 3:4 / 16:9 / 9:16 / 4:3) — the\n * creature route reuses the object aspect enum.\n */\n aspectRatio?: ObjectAspectRatio\n /**\n * Optional clip duration in seconds. Validated server-side against the chosen\n * provider's allowed durations (e.g. kling 5/10, wan-i2v 5/10/15); omitted →\n * the model's own default (no behavior change). Mirrors generate-video's\n * per-model i2v duration lever.\n */\n duration?: number\n}\n\nexport interface GenerateCreatureMotionResult {\n jobId: string\n}\n\nexport interface ApproveCreatureMainImageResult {\n sourceImageUrl: string\n /**\n * LLM-authored caption. `null` when the LLM caption sub-failed — the wire\n * sends `\"\"`, normalized to `null` here so consumers see the same\n * `string | null` semantics as characters. The main image is still set; call\n * `recaption()` to retry.\n */\n canonicalDescription: string | null\n}\n\nexport interface RecaptionCreatureResult {\n canonicalDescription: string\n}\n\nexport class CreaturesResource {\n constructor(private client: NodaroClientCore) {}\n\n /**\n * List the caller's creatures. By default returns active creatures only;\n * pass `archived: true` to fetch soft-deleted rows for an \"archive\" view.\n * Optional `projectId` scopes the result to a single project; `q` keeps the\n * creatures whose name or description contains it.\n */\n list(params: ListCreaturesParams = {}): Promise<{ creatures: Creature[]; nextCursor?: string | null }> {\n const query: Record<string, string | undefined> = {}\n if (params.archived) query.archived = \"true\"\n if (params.projectId) query.projectId = params.projectId\n if (params.q) query.q = params.q\n if (params.limit !== undefined) query.limit = String(params.limit)\n if (params.cursor) query.cursor = params.cursor\n return this.client.request(\"GET\", \"/v1/creatures\", { query })\n }\n\n /**\n * Convenience wrapper for `list({ archived: true })`. Returns soft-deleted\n * rows so callers can drive a UI \"Archived\" tab without re-encoding the\n * query param.\n *\n * `archived` is omitted from the param type — it's always set to `true` here.\n */\n listArchived(params: Omit<ListCreaturesParams, \"archived\"> = {}): Promise<{ creatures: Creature[]; nextCursor?: string | null }> {\n return this.list({ ...params, archived: true })\n }\n\n /**\n * Fetch a single creature including in-flight asset job state. Soft-deleted\n * (archived) rows are NOT returned by id — the route enforces\n * `deleted_at IS NULL` so archived creatures 404 (uniform \"not_found\" — does\n * not leak the deleted vs non-existent distinction).\n */\n async get(id: string): Promise<CreatureDetail> {\n const res = await this.client.request<CreatureDetail>(\n \"GET\",\n `/v1/creatures/${encodeURIComponent(id)}`,\n )\n // Normalize the wire `\"\"` caption (DB null / LLM sub-failure) → null so\n // consumers see the same `string | null` semantics as characters. New\n // object — never mutate the response.\n return { ...res, canonicalDescription: res.canonicalDescription || null }\n }\n\n /**\n * Create a new creature. `name` + `nodeId` are required — the route 400s\n * otherwise. Returns the new row's id.\n *\n * Note: the underlying route is the same `POST /v1/creatures` upsert that\n * powers `update()`. This convenience wrapper enforces the INSERT-required\n * fields at the type level and never sends an `id`.\n */\n create(data: CreateCreatureInput): Promise<{ id: string }> {\n return this.client.request(\"POST\", \"/v1/creatures\", { body: data })\n }\n\n /**\n * Update a creature. Only the fields you pass are written — undefined keys\n * are NOT touched on the row. Worker-owned asset buckets are intentionally\n * not exposed on this surface (see `UpdateCreatureInput` for the rationale).\n *\n * Optimistic-concurrency: pass `expectedUpdatedAt` to require the row's\n * `updated_at` still matches; on mismatch the route returns 409\n * `concurrent_modification` carrying the fresh `updatedAt`. The SDK\n * surfaces that as a generic `NodaroError` with the same code.\n */\n update(id: string, data: UpdateCreatureInput): Promise<UpdateCreatureResult> {\n return this.client.request(\"POST\", \"/v1/creatures\", {\n body: { id, ...data },\n })\n }\n\n /**\n * Soft-delete (archive) a creature. The row is hidden from `list()` by\n * default but recoverable via `restore(id)` or visible under\n * `listArchived()`. Idempotent — repeating a delete on an already-archived\n * row is a no-op.\n */\n delete(id: string): Promise<{ success: true; archived: true }> {\n return this.client.request(\"DELETE\", `/v1/creatures/${encodeURIComponent(id)}`)\n }\n\n /**\n * Hard-delete (permanent) a creature — the row + every R2 asset it\n * references. Archived rows ONLY: active creatures return 400 `not_archived`.\n * Call `delete()` first to archive, then `permanentDelete()` to destroy.\n *\n * Mirrors the `app_runs` permanent-delete pattern (archive-first) so a\n * stray SDK / curl caller cannot bypass the studio's archive-first UI\n * flow.\n */\n permanentDelete(id: string): Promise<{ success: true; permanent: true }> {\n return this.client.request(\"DELETE\", `/v1/creatures/${encodeURIComponent(id)}`, {\n query: { permanent: \"true\" },\n })\n }\n\n /**\n * Un-archive a creature. If the original name now collides (case-\n * insensitive) with an active row, the server auto-suffixes \"(restored)\"\n * and returns the effective name.\n */\n restore(id: string): Promise<{ id: string; name: string }> {\n return this.client.request(\"POST\", `/v1/creatures/${encodeURIComponent(id)}/restore`)\n }\n\n /**\n * Admin only: put one of your own creatures on the shared Nodaro Keepers\n * shelf (`client.keepers.catalog()`), or take it off. A first-party session\n * or your personal token; `forbidden` for anyone who is not a platform\n * admin, `not_found` for a row that is not yours.\n */\n setCatalog(id: string, input: SetKeeperCatalogInput): Promise<SetKeeperCatalogResult> {\n return this.client.request(\"PUT\", `/v1/creatures/${encodeURIComponent(id)}/catalog`, { body: input })\n }\n\n /**\n * Fire `POST /v1/generate-creature` to produce one or more candidate main\n * images. With `count > 1`, all jobs are reserved up-front before any\n * is enqueued — mid-batch failures roll back atomically.\n *\n * When `attachToCreatureId` is set AND `count === 1`, the worker writes\n * the result directly to the row's `source_image_url`; otherwise you must\n * call `approveMainImage()` after picking a candidate.\n */\n async generate(data: GenerateCreatureInput): Promise<GenerateCreatureResult> {\n const res = await this.client.request<{ jobId?: string; jobIds?: string[] }>(\n \"POST\", \"/v1/generate-creature\", { body: data },\n )\n // Tolerate the legacy `{ jobId }`-only shape (older server): synthesize jobIds.\n const jobIds = res.jobIds ?? (res.jobId ? [res.jobId] : [])\n return res.jobId ? { jobIds, jobId: res.jobId } : { jobIds }\n }\n\n /**\n * Fire `POST /v1/generate-creature-asset` to produce a single variant.\n * When the studio path is set (`attachToCreatureId` + `attachToColumn` +\n * `attachName`), the worker appends `{ name: attachName, url: <result> }`\n * to the named JSONB array column on completion.\n *\n * Note: `attachToColumn` is REQUIRED for `assetType === \"custom\"` — the\n * worker can't infer the bucket from the asset type. For canonical asset\n * types (`angles` / `poses` / `variations`), the column is derived\n * automatically by the route.\n */\n generateAsset(\n data: GenerateCreatureAssetInput,\n ): Promise<GenerateCreatureAssetResult> {\n return this.client.request(\"POST\", \"/v1/generate-creature-asset\", { body: data })\n }\n\n /**\n * Fire `POST /v1/generate-creature-motion` to animate the creature's main\n * image into a motion clip. Image-to-video, single clip per call; the\n * attach column is hardcoded to `motion_clips` server-side (creatures have a\n * single motion bucket so the caller doesn't supply `attachToColumn`).\n * When the studio path is set (`attachToCreatureId` + `attachName`), the\n * worker appends `{ name: attachName, url: <result> }` to the row's\n * `motion_clips` column on completion.\n *\n * Defaults: `provider` → `\"kling-turbo\"`, `aspectRatio` → `\"1:1\"` (set\n * server-side via `resolveObjectAspectRatio({ assetType: \"motion\" })`).\n */\n generateMotion(\n data: GenerateCreatureMotionInput,\n ): Promise<GenerateCreatureMotionResult> {\n return this.client.request(\"POST\", \"/v1/generate-creature-motion\", { body: data })\n }\n\n /**\n * Approve a completed `generate-creature` job as the creature's main image.\n * Sets `source_image_url` and fires the LLM caption (Claude Sonnet vision)\n * inline. Returns the new main-image URL plus the caption.\n *\n * Caption-failure semantics: the route still sends `\"\"` on LLM sub-failure,\n * but the SDK normalizes `\"\"` → `null` here so `canonicalDescription` carries\n * the same `string | null` semantics as characters. The main image is still\n * set; call `recaption()` to retry.\n *\n * Optimistic-concurrency: pass `expectedUpdatedAt` to gate the update on\n * the row's current `updated_at`; on mismatch the route returns 409\n * `concurrent_modification` carrying the fresh token.\n */\n async approveMainImage(\n id: string,\n candidateJobId: string,\n expectedUpdatedAt?: string,\n ): Promise<ApproveCreatureMainImageResult> {\n const res = await this.client.request<{ sourceImageUrl: string; canonicalDescription: string | null }>(\n \"POST\",\n `/v1/creatures/${encodeURIComponent(id)}/approve-main-image`,\n { body: { candidateJobId, expectedUpdatedAt } },\n )\n // Normalize the wire `\"\"` (LLM sub-failure) → null; build a new object\n // rather than mutating the response.\n return { sourceImageUrl: res.sourceImageUrl, canonicalDescription: res.canonicalDescription || null }\n }\n\n /**\n * Re-fire the LLM caption against the creature's current main image. 502s\n * on LLM failure (unlike `approveMainImage` which preserves the side-effect\n * and returns \"\"); returns 400 `main_image_required` if no main image is\n * set yet.\n *\n * The route is a pure idempotent retry — it does NOT accept an\n * `expectedUpdatedAt` token (backend route is idempotent retry, not gated on\n * optimistic-concurrency).\n */\n recaption(id: string): Promise<RecaptionCreatureResult> {\n return this.client.request(\n \"POST\",\n `/v1/creatures/${encodeURIComponent(id)}/llm-caption`,\n )\n }\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/resources/locations.ts"],"names":[],"mappings":"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","file":"chunk-I3MEBVLP.js","sourcesContent":["import type { CharacterAspectRatio, SurroundDirection, LocationAssetType, LocationAttachColumn } from \"@nodaro/shared/entities\"\nexport type { LocationAssetType, LocationAttachColumn, CharacterAspectRatio, SurroundDirection } from \"@nodaro/shared/entities\"\nexport { LOCATION_ASSET_TYPES, LOCATION_ATTACH_COLUMNS, SURROUND_DIRECTIONS } from \"@nodaro/shared/entities\"\nimport type { NodaroClientCore } from \"../core.js\"\nimport type { SetKeeperCatalogInput, SetKeeperCatalogResult } from \"./keepers.js\"\nimport type { GenerationSessionParams } from \"./nodes.js\"\n\n/**\n * Re-export the shared `LocationAssetType` / `LocationAttachColumn` unions and\n * their runtime tuples so SDK consumers don't have to add `@nodaro/shared` as a\n * second dependency just to typecheck the `assetType` / `attachToColumn`\n * fields. Single source of truth lives in `@nodaro/shared/entity-prompts`.\n *\n * `CharacterAspectRatio` is re-exported alongside them — `generateMotion`'s\n * `aspectRatio` field reuses the same 4-value enum (1:1 / 3:4 / 16:9 / 9:16)\n * as characters; the route enforces this with `z.enum(CHARACTER_ASPECT_OPTIONS)`.\n */\n\n/**\n * Reference-photo kind discriminator — the mood-board roles a user can attach\n * to a location. Mirrors the `reference_photos.kind` Zod enum in\n * `backend/src/routes/locations.ts`. `other` is the free-form bucket.\n */\nexport type LocationReferencePhotoKind =\n | \"wide\"\n | \"interior\"\n | \"exterior\"\n | \"detail\"\n | \"moodBoard\"\n | \"other\"\n\nexport interface LocationReferencePhoto {\n url: string\n kind: LocationReferencePhotoKind\n}\n\n/**\n * A location record returned by Nodaro's REST API. Mirrors the camelCase\n * shape produced by `backend/src/routes/locations.ts::toCamel()`.\n *\n * Asset buckets (`timeOfDay`, `weather`, `angles`, `lighting`, `seasons`,\n * `atmosphereMotions`) are independent JSONB arrays keyed by a human-readable\n * variant name (e.g. `\"dawn\"`, `\"clear\"`, `\"wide\"`). Each entry's `url` points\n * at an R2-hosted asset.\n *\n * Identity-foundation fields:\n * - `referencePhotos` — caller-supplied mood-board refs (cap 20).\n * - `canonicalDescription` — ~80–120-word LLM-authored visual caption,\n * populated by `approveMainImage()` / `recaption()`. The wire still sends\n * `\"\"` on caption sub-failure (the breaking wire change is deferred to a\n * major bump), but `get()` normalizes `\"\"` → `null` so consumers see the\n * same `string | null` semantics as characters.\n * - `styleLock` — whether asset gens should anchor to the canonical style\n * captured at approval time. Defaults to `true` on new rows.\n */\nexport interface Location {\n id: string\n userId: string\n nodeId: string\n projectId: string | null\n name: string\n description: string | null\n category: string | null\n style: string | null\n sourceImageUrl: string | null\n /** MODEL_CATALOG image-model id the main image was generated with (or `null`).\n * Set on create + editable via the update route. */\n imageProvider: string | null\n timeOfDay: Array<{ name: string; url: string }>\n weather: Array<{ name: string; url: string }>\n angles: Array<{ name: string; url: string }>\n lighting: Array<{ name: string; url: string }>\n seasons: Array<{ name: string; url: string }>\n atmosphereMotions: Array<{ name: string; url: string }>\n /** Named Location Boards — dense reference sheets, one per variant/mood\n * (the `generate-image/location-board` factory preset rendered from the\n * location's images). A first-class bucket: community publish snapshots it\n * and clone hands the consumer their own copy to extend. Defaults to `[]`.\n * `type` marks an image-collage `\"identity\"` sheet vs a plain `\"looks\"`\n * board; `sourceImages` are the R2 URLs it was collaged from. Both optional\n * + backward-compatible (legacy boards have neither). */\n boards?: Array<{ name: string; url: string; type?: \"looks\" | \"identity\"; sourceImages?: string[] }> | null\n referencePhotos: LocationReferencePhoto[]\n /** `null` when no caption is set (or the LLM caption sub-failed) — the wire\n * sends `\"\"`, normalized to `null` in `get()` to match character semantics. */\n canonicalDescription: string | null\n styleLock: boolean\n /** The user's chosen DEFAULT asset take per variant (Studio version history).\n * OPAQUE map: key `\"<bucket>:<variant>\"` (e.g. `\"timeOfDay:dawn\"`) → the chosen\n * asset URL (one already present in that bucket). Stored verbatim — keys are\n * NOT normalized; soft-capped server-side at 200 keys / 2048-char values\n * (overflow dropped silently). Defaults to `{}`. */\n selectedAssetByVariant?: Record<string, string> | null\n deletedAt: string | null\n createdAt: string\n updatedAt: string\n}\n\n/**\n * GET /v1/locations/:id appends a `pendingJobs` bucket the studio uses to\n * rehydrate spinners after a reload. Optional on the SDK surface — it doesn't\n * appear on `list()` rows.\n */\nexport interface LocationDetail extends Location {\n pendingJobs?: Array<{\n jobId: string\n assetType: string\n name: string\n status: string\n }>\n /**\n * Completed candidate main images for this location whose URL differs from\n * the current `sourceImageUrl`, newest first (max 5). Surfaced so a\n * \"pick from N\" UI can offer alternatives the user can promote via\n * `approveMainImage(id, jobId)`; until they pick, the current main image is\n * left untouched. Mirrors `CharacterDetail.previousCandidates`. Optional -\n * absent on `list()` rows, present (possibly empty) on `get()`.\n */\n previousCandidates?: Array<{\n jobId: string\n url: string\n createdAt: string\n }>\n}\n\n/**\n * Body for `client.locations.create()`. Mirrors the INSERT branch of\n * `upsertLocationBody` in `backend/src/routes/locations.ts`. `name` + `nodeId`\n * are required on create.\n */\nexport interface CreateLocationInput {\n nodeId: string\n name: string\n description?: string\n category?: string\n style?: string\n workflowId?: string\n projectId?: string\n sourceImageUrl?: string\n /** Persistent image-model id (a MODEL_CATALOG image model). Validated\n * server-side — unknown / non-image / \"\" is stored as `null`. */\n imageProvider?: string | null\n referencePhotos?: LocationReferencePhoto[]\n canonicalDescription?: string\n styleLock?: boolean\n /** The user's chosen DEFAULT asset take per variant. OPAQUE\n * `\"<bucket>:<variant>\"` → chosen-URL map; a write REPLACES the whole map.\n * Keys stored verbatim; soft-capped server-side at 200 keys / 2048-char values. */\n selectedAssetByVariant?: Record<string, string>\n}\n\n/**\n * Body for `client.locations.update()`. Mirrors the UPDATE branch of\n * `upsertLocationBody` in `backend/src/routes/locations.ts`.\n *\n * Worker-owned asset buckets (`timeOfDay`/`weather`/`angles`/`lighting`/\n * `seasons`/`atmosphereMotions`) are deliberately omitted — the route drops\n * them on UPDATE so a Studio auto-save with a stale snapshot cannot clobber\n * the worker's atomic `append_location_asset()` writes.\n *\n * `expectedUpdatedAt` is the optimistic-concurrency token: when present, the\n * UPDATE only succeeds if the row's `updated_at` still matches; on mismatch\n * the route returns 409 so the studio can re-fetch + merge.\n */\nexport interface UpdateLocationInput {\n name?: string\n description?: string\n category?: string\n style?: string\n sourceImageUrl?: string\n /** Persistent image-model id (a MODEL_CATALOG image model). Validated\n * server-side — unknown / non-image / \"\" is stored as `null`. */\n imageProvider?: string | null\n referencePhotos?: LocationReferencePhoto[]\n canonicalDescription?: string\n styleLock?: boolean\n /** The user's chosen DEFAULT asset take per variant. OPAQUE\n * `\"<bucket>:<variant>\"` → chosen-URL map; a write REPLACES the whole map\n * (omit to leave untouched). Keys stored verbatim; soft-capped server-side\n * at 200 keys / 2048-char values. */\n selectedAssetByVariant?: Record<string, string>\n /** Named Location Boards (see `Location.boards`) — whole-array replace,\n * USER-owned (unlike the worker-owned buckets it flows through UPDATE).\n * Server caps: 24 boards, 200-char names, 30 sourceImages per board. */\n boards?: Array<{ name: string; url: string; type?: \"looks\" | \"identity\"; sourceImages?: string[] }>\n /** ISO-8601 timestamp recording when PII consent was captured for this location. */\n piiConsentAt?: string\n expectedUpdatedAt?: string\n}\n\nexport interface UpdateLocationResult {\n id: string\n updatedAt: string\n}\n\nexport interface ListLocationsParams {\n /** When true, return archived locations instead of active ones. */\n archived?: boolean\n /**\n * Search words: only the locations whose name or description contains\n * every word (split on spaces, the first 5), in any order, ignoring case.\n * Each word is matched as written (`%`, `_` and `*` are not wildcards;\n * punctuation is kept); blank means no search; up to 200 characters.\n * Combines with the other filters and with `cursor` paging.\n */\n q?: string\n /**\n * Max rows to return (cap 500). OPT-IN: omitted, the server returns the\n * full legacy listing with no `nextCursor`; supplied, the response is one\n * page plus `nextCursor` — keep passing it back until it is `null`.\n */\n limit?: number\n /** Opaque cursor from a prior page's `nextCursor` (fetches the next page). */\n cursor?: string\n}\n\n/**\n * Input for `client.locations.generate()` — fires the\n * `POST /v1/generate-location` route. Produces 1–10 candidate\n * establishing shots; each lands as one `jobs` row in `pending` state and\n * is then enqueued for the worker.\n *\n * When `attachToLocationId` is set AND `count === 1`, the worker writes the\n * resulting URL directly to `locations.source_image_url` on completion —\n * caller doesn't need a separate `approveMainImage` call. Multi-candidate\n * batches MUST go through explicit approval so the user picks the winner.\n */\nexport interface GenerateLocationInput extends GenerationSessionParams {\n name: string\n description?: string\n userPrompt?: string\n category?: \"indoor\" | \"outdoor\" | \"urban\" | \"nature\" | \"fantasy\" | \"sci-fi\" | \"historical\" | \"futuristic\" | \"other\"\n style?: \"realistic\" | \"anime\" | \"3d-pixar\" | \"illustration\"\n sourceImageUrl?: string\n provider?: string\n /** Number of candidate images to generate (1–10; server-validated). */\n count?: number\n /** Auto-attach the result to this location row (single-candidate only). */\n attachToLocationId?: string\n /**\n * Credit-affecting quality tier (e.g. `\"high\"` for gpt-image). Priced like\n * generate-image (composite ids such as `gpt-image:high`); values the chosen\n * model doesn't support are ignored server-side, never rejected.\n */\n quality?: string\n /**\n * Credit-affecting output resolution (e.g. `\"2K\"` / `\"4K\"` / `\"2 MP\"`).\n * Priced like generate-image (composite ids such as `nano-banana-pro:4K`);\n * values the chosen model doesn't support are ignored server-side, never\n * rejected.\n */\n resolution?: string\n}\n\n/**\n * `generate()` response — `jobIds` is ALWAYS present (the harmonized contract,\n * matching characters). `jobId` is a deprecated back-compat alias populated only\n * on `count === 1`; prefer `jobIds`. (Will be removed on the next major.)\n */\nexport interface GenerateLocationResult {\n jobIds: string[]\n /** @deprecated count===1 back-compat alias — use `jobIds`. */\n jobId?: string\n}\n\n/**\n * Input for `client.locations.generateAsset()` — fires the\n * `POST /v1/generate-location-asset` route. Produces a single\n * timeOfDay / weather / seasons / angles / lighting / custom variant.\n *\n * When all three studio-path fields are set (`attachToLocationId` +\n * `attachToColumn` + `attachName`), the worker appends\n * `{ name: attachName, url: <result> }` to the named JSONB array column on\n * the user's location row on completion. `attachToColumn` is REQUIRED for\n * `assetType === \"custom\"` — the worker can't infer the bucket from the\n * asset type.\n */\nexport interface GenerateLocationAssetInput extends GenerationSessionParams {\n assetType: LocationAssetType\n variant: string\n name: string\n description?: string\n userPrompt?: string\n category?: string\n style?: \"realistic\" | \"anime\" | \"3d-pixar\" | \"illustration\"\n sourceImageUrl?: string\n provider?: string\n /** Optional framing override (the same 4-value enum as `generateMotion`).\n * Absent = the image model's default. The studio's 360° surround path pins\n * `\"16:9\"` so every ring view matches the establishing shot's frame. */\n aspectRatio?: CharacterAspectRatio\n attachToLocationId?: string\n attachToColumn?: LocationAttachColumn\n attachName?: string\n /**\n * Credit-affecting quality tier (e.g. `\"high\"` for gpt-image). Values the\n * chosen model doesn't support are ignored server-side, never rejected.\n */\n quality?: string\n /**\n * Credit-affecting output resolution (e.g. `\"2K\"` / `\"4K\"` / `\"2 MP\"`).\n * Values the chosen model doesn't support are ignored server-side, never\n * rejected.\n */\n resolution?: string\n}\n\n/**\n * Input for `client.locations.generateSurroundContinuation()` — fires the\n * `POST /v1/generate-surround-continuation` route. Generates one seamless 360°\n * ring view as an image-to-image continuation of `referenceImageUrl` (the\n * previous ring view, or the establishing shot for the first ring).\n *\n * The platform owns the whole pipeline: it builds the half-carry composite\n * server-side (carry the reference's trailing half into the new frame's leading\n * half per `direction`, gray the rest), paints the gray region, then\n * color-harmonizes the painted half to the carried half so there is no tonal\n * seam down the frame's center. The carried half stays pixel-exact, so a\n * panorama viewer stitching adjacent ring views stays geometrically seamless.\n *\n * When the studio path is set (`attachToLocationId` + `attachToColumn` +\n * `attachName`), the worker appends `{ name: attachName, url: <result> }` to the\n * location's bucket (studio uses `attachToColumn: \"angles\"`,\n * `attachName: \"Surround 45°\"`).\n */\nexport interface GenerateSurroundContinuationInput extends GenerationSessionParams {\n /** The previous ring view to continue from (i2i anchor). */\n referenceImageUrl: string\n /** Carry/paint axis: turn right, turn left, tilt up, or tilt down. Tilts\n * render the sky/ground (a thin horizon strip), not a horizontal continuation. */\n direction: SurroundDirection\n /** Ring angle (45, 90, …) — stored on the result as metadata. */\n degrees?: number\n /** Fraction of the frame carried from the reference. Omitted ⇒ per-direction\n * default (0.5 for a pan, 0.12 thin strip for a tilt). */\n carriedFraction?: number\n /** Upscale/denoise the result before it's chained as the next reference, to\n * slow cumulative softening down a long ring chain. Default false. */\n refine?: boolean\n /** Refine model when `refine` is set. `recraft-upscale` (1 cr, default) or\n * `topaz-image-upscale` (3 cr). */\n refineProvider?: \"recraft-upscale\" | \"topaz-image-upscale\"\n /** Optional free-form scene hint woven into the fill prompt. */\n userPrompt?: string\n /** Image model. Defaults to the platform's general image model (`gpt-image-2`). */\n provider?: string\n /** Studio pins `\"16:9\"` so every ring view matches the establishing frame. */\n aspectRatio?: CharacterAspectRatio\n attachToLocationId?: string\n attachToColumn?: LocationAttachColumn\n attachName?: string\n}\n\n/**\n * Input for `client.locations.generateMotion()` — fires the\n * `POST /v1/generate-location-motion` route. Produces a single atmospheric\n * motion clip (drifting fog, snowfall, rolling waves, etc.) animated FROM a\n * static establishing-shot image.\n *\n * Mirrors `client.characters.generateMotion()` minus the character-specific\n * fields (gender / baseOutfit / realLifeRefs). The route hardcodes the attach\n * column to `atmosphere_motions` — callers supply `attachToLocationId` +\n * `attachName` only.\n *\n * `sourceImageUrl` is REQUIRED — image-to-video needs a source frame and the\n * route has no fallback (no `source_image_url` column to pull from on the\n * locations row; the studio path supplies the canonical establishing-shot URL\n * explicitly).\n *\n * When the studio path is set (`attachToLocationId` + `attachName`), the\n * worker appends `{ name: attachName, url: <result> }` to the location row's\n * `atmosphere_motions` JSONB column on completion.\n */\nexport interface GenerateLocationMotionInput extends GenerationSessionParams {\n motionPrompt: string\n sourceImageUrl: string\n provider?: string\n name: string\n category?: string\n style?: \"realistic\" | \"anime\" | \"3d-pixar\" | \"illustration\"\n canonicalDescription?: string\n attachToLocationId?: string\n attachName?: string\n /**\n * Optional aspect ratio override. Defaults to 16:9 server-side via\n * `resolveLocationAspectRatio` (locations are cinematic establishing shots).\n * One of the 4-value `CharacterAspectRatio` union — locations reuse the\n * character aspect enum since the supported ratios are identical.\n */\n aspectRatio?: CharacterAspectRatio\n}\n\nexport interface ApproveMainImageResult {\n sourceImageUrl: string\n /**\n * LLM-authored caption. `null` when the LLM caption sub-failed — the wire\n * sends `\"\"`, normalized to `null` here so consumers see the same\n * `string | null` semantics as characters. The main image is still set; call\n * `recaption()` to retry.\n */\n canonicalDescription: string | null\n}\n\nexport interface RecaptionLocationResult {\n canonicalDescription: string\n}\n\nexport class LocationsResource {\n constructor(private client: NodaroClientCore) {}\n\n /**\n * List the caller's locations. By default returns active locations only;\n * pass `archived: true` to fetch soft-deleted rows for an \"archive\" view,\n * and `q` to keep the ones whose name or description contains it.\n */\n list(params: ListLocationsParams = {}): Promise<{ locations: Location[]; nextCursor?: string | null }> {\n const query: Record<string, string | undefined> = {}\n if (params.archived) query.archived = \"true\"\n if (params.q) query.q = params.q\n if (params.limit !== undefined) query.limit = String(params.limit)\n if (params.cursor) query.cursor = params.cursor\n return this.client.request(\"GET\", \"/v1/locations\", { query })\n }\n\n /**\n * Convenience wrapper for `list({ archived: true })`. Returns soft-deleted\n * rows so callers can drive a UI \"Archived\" tab without re-encoding the\n * query param. Mirrors `ObjectsResource.listArchived`.\n *\n * `archived` is omitted from the param type — it's always set to `true` here.\n */\n listArchived(params: Omit<ListLocationsParams, \"archived\"> = {}): Promise<{ locations: Location[]; nextCursor?: string | null }> {\n return this.list({ ...params, archived: true })\n }\n\n /**\n * Fetch a single location including in-flight asset job state. Soft-deleted\n * (archived) rows are returned by id intentionally so canvas nodes that\n * hold a stale `locationDbId` keep loading.\n */\n async get(id: string): Promise<LocationDetail> {\n const res = await this.client.request<LocationDetail>(\n \"GET\",\n `/v1/locations/${encodeURIComponent(id)}`,\n )\n // Normalize the wire `\"\"` caption (DB null / LLM sub-failure) → null so\n // consumers see the same `string | null` semantics as characters. New\n // object — never mutate the response.\n return { ...res, canonicalDescription: res.canonicalDescription || null }\n }\n\n /**\n * Create a new location. `name` + `nodeId` are required — the route 400s\n * otherwise. Returns the new row's id.\n *\n * Note: the underlying route is the same `POST /v1/locations` upsert that\n * powers `update()`. This convenience wrapper enforces the INSERT-required\n * fields at the type level and never sends an `id`.\n */\n create(data: CreateLocationInput): Promise<{ id: string }> {\n return this.client.request(\"POST\", \"/v1/locations\", { body: data })\n }\n\n /**\n * Update a location. Only the fields you pass are written — undefined keys\n * are NOT touched on the row. Worker-owned asset buckets are intentionally\n * not exposed on this surface (see `UpdateLocationInput` for the rationale).\n *\n * Optimistic-concurrency: pass `expectedUpdatedAt` to require the row's\n * `updated_at` still matches; on mismatch the route returns 409\n * `concurrent_modification`. The SDK surfaces that as a generic\n * `NodaroError` with the same code.\n */\n update(id: string, data: UpdateLocationInput): Promise<UpdateLocationResult> {\n return this.client.request(\"POST\", \"/v1/locations\", {\n body: { id, ...data },\n })\n }\n\n /**\n * Soft-delete (archive) a location. The row is hidden from `list()` by\n * default but still loadable via `get(id)` so canvas nodes pointing at it\n * keep working. Restore with `restore(id)`.\n */\n delete(id: string): Promise<{ success: true; archived: true }> {\n return this.client.request(\"DELETE\", `/v1/locations/${encodeURIComponent(id)}`)\n }\n\n /**\n * Un-archive a location. If the original name now collides (case-\n * insensitive) with an active row, the server auto-suffixes \"(restored)\"\n * and returns the effective name.\n */\n restore(id: string): Promise<{ id: string; name: string }> {\n return this.client.request(\"POST\", `/v1/locations/${encodeURIComponent(id)}/restore`)\n }\n\n /**\n * Admin only: put one of your own locations on the shared Nodaro Keepers\n * shelf (`client.keepers.catalog()`), or take it off. A first-party session\n * or your personal token; `forbidden` for anyone who is not a platform\n * admin, `not_found` for a row that is not yours.\n */\n setCatalog(id: string, input: SetKeeperCatalogInput): Promise<SetKeeperCatalogResult> {\n return this.client.request(\"PUT\", `/v1/locations/${encodeURIComponent(id)}/catalog`, { body: input })\n }\n\n /**\n * Fire `POST /v1/generate-location` to produce one or more candidate main\n * images. With `count > 1`, all jobs are reserved up-front before any\n * is enqueued — mid-batch failures roll back atomically.\n *\n * When `attachToLocationId` is set AND `count === 1`, the worker writes\n * the result directly to the row's `source_image_url`; otherwise you must\n * call `approveMainImage()` after picking a candidate.\n */\n async generate(data: GenerateLocationInput): Promise<GenerateLocationResult> {\n const res = await this.client.request<{ jobId?: string; jobIds?: string[] }>(\n \"POST\", \"/v1/generate-location\", { body: data },\n )\n // Tolerate the legacy `{ jobId }`-only shape (older server): synthesize jobIds.\n const jobIds = res.jobIds ?? (res.jobId ? [res.jobId] : [])\n return res.jobId ? { jobIds, jobId: res.jobId } : { jobIds }\n }\n\n /**\n * Fire `POST /v1/generate-location-asset` to produce a single variant.\n * When the studio path is set (`attachToLocationId` + `attachToColumn` +\n * `attachName`), the worker appends `{ name: attachName, url: <result> }`\n * to the named JSONB array column on completion.\n */\n generateAsset(data: GenerateLocationAssetInput): Promise<{ jobId: string }> {\n return this.client.request(\"POST\", \"/v1/generate-location-asset\", { body: data })\n }\n\n /**\n * Fire `POST /v1/generate-surround-continuation` to produce one seamless 360°\n * ring view as an i2i continuation of `referenceImageUrl`. The platform builds\n * the half-carry composite, paints the missing half, and color-harmonizes it\n * to the carried half (no tonal seam; carried half stays pixel-exact). When the\n * studio path is set, the worker appends the result to the location's bucket.\n */\n generateSurroundContinuation(data: GenerateSurroundContinuationInput): Promise<{ jobId: string }> {\n return this.client.request(\"POST\", \"/v1/generate-surround-continuation\", { body: data })\n }\n\n /**\n * Fire `POST /v1/generate-location-motion` to animate the location's\n * establishing shot into an atmospheric motion clip. Image-to-video, single\n * clip per call; the attach column is hardcoded to `atmosphere_motions`\n * server-side (locations have a single motion bucket so the caller doesn't\n * supply `attachToColumn`). When the studio path is set\n * (`attachToLocationId` + `attachName`), the worker appends\n * `{ name: attachName, url: <result> }` to the row's `atmosphere_motions`\n * column on completion.\n */\n generateMotion(data: GenerateLocationMotionInput): Promise<{ jobId: string }> {\n return this.client.request(\"POST\", \"/v1/generate-location-motion\", { body: data })\n }\n\n /**\n * Atomically remove ONE asset take (every entry matching `url`) from a\n * worker-owned bucket column — `POST /v1/locations/:id/remove-asset`. The\n * worker-owned buckets are deliberately not writable through `update()`\n * (a stale snapshot would race concurrent worker appends), so deleting a\n * take — e.g. a 360° surround view being regenerated — goes through this\n * single-statement server-side filter instead. 404s (`NotFoundError`) when\n * the url isn't in that bucket or the location isn't yours.\n */\n removeAsset(\n id: string,\n data: { column: LocationAttachColumn; url: string },\n ): Promise<{ removed: true }> {\n return this.client.request(\n \"POST\",\n `/v1/locations/${encodeURIComponent(id)}/remove-asset`,\n { body: data },\n )\n }\n\n /**\n * Approve a completed `generate-location` job as the location's main image.\n * Sets `source_image_url` and fires the LLM caption (Claude Sonnet vision)\n * inline. Returns the new main-image URL plus the caption.\n *\n * Caption-failure semantics: the route still sends `\"\"` on LLM sub-failure,\n * but the SDK normalizes `\"\"` → `null` here so `canonicalDescription` carries\n * the same `string | null` semantics as characters. The main image is still\n * set; call `recaption()` to retry.\n */\n async approveMainImage(id: string, candidateJobId: string): Promise<ApproveMainImageResult> {\n const res = await this.client.request<{ sourceImageUrl: string; canonicalDescription: string | null }>(\n \"POST\",\n `/v1/locations/${encodeURIComponent(id)}/approve-main-image`,\n { body: { candidateJobId } },\n )\n // Normalize the wire `\"\"` (LLM sub-failure) → null; build a new object\n // rather than mutating the response.\n return { sourceImageUrl: res.sourceImageUrl, canonicalDescription: res.canonicalDescription || null }\n }\n\n /**\n * Re-fire the LLM caption against the location's current main image. 502s\n * on LLM failure (unlike `approveMainImage` which preserves the side-effect\n * and returns \"\"); returns 400 `no_source_image` if no main image is set\n * yet.\n */\n recaption(id: string): Promise<RecaptionLocationResult> {\n return this.client.request(\n \"POST\",\n `/v1/locations/${encodeURIComponent(id)}/llm-caption`,\n )\n }\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/binary-response.ts","../src/core.ts","../src/auth.ts"],"names":["WORKSPACE_HEADER","throwFromResponse"],"mappings":"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","file":"chunk-JOVJAKBT.cjs","sourcesContent":["/** Bound decoded response bytes even when Content-Length is absent or compressed. */\nexport async function readBinaryResponse(response: Response, maxBytes: number): Promise<ArrayBuffer> {\n const advertised = response.headers.get(\"content-length\")\n if (advertised !== null && (!/^\\d+$/.test(advertised) || Number(advertised) > maxBytes)) {\n await response.body?.cancel()\n throw new Error(\"Binary response exceeds its declared size limit\")\n }\n if (!response.body) return new ArrayBuffer(0)\n const reader = response.body.getReader()\n const chunks: Uint8Array[] = []\n let length = 0\n try {\n while (true) {\n const next = await reader.read()\n if (next.done) break\n length += next.value.byteLength\n if (length > maxBytes) {\n await reader.cancel()\n throw new Error(\"Binary response exceeds its declared size limit\")\n }\n chunks.push(next.value)\n }\n } finally { reader.releaseLock() }\n const bytes = new Uint8Array(length)\n let offset = 0\n for (const chunk of chunks) { bytes.set(chunk, offset); offset += chunk.byteLength }\n return bytes.buffer\n}\n","/**\n * The client core: configuration, auth, the request transport and the\n * account-identity calls — everything a resource needs, and none of the\n * resources themselves.\n *\n * {@link NodaroClient} (`createClient`) extends it with every resource. An app\n * that uses only a few resources can extend it with just those, so it loads\n * (and its tests depend on) only the resource modules it actually uses:\n *\n * class AppClient extends NodaroClientCore {\n * readonly jobs = new JobsResource(this)\n * readonly nodes = new NodesResource(this) // needs `jobs` on the same client\n * }\n *\n * A resource that calls another one through the client says so in its\n * constructor type (`NodesResource` takes a core that also has `jobs`), so a\n * client missing it fails to compile rather than at run time.\n */\nimport { readBinaryResponse } from \"./binary-response.js\"\nimport { throwFromResponse } from \"./errors.js\"\nimport type { Auth } from \"./auth.js\"\nimport type { DeveloperAppKind, DeveloperAppScope } from \"./resources/developer-apps.js\"\nimport { WORKSPACE_HEADER, type MeOrganizations } from \"@nodaro/shared/organizations\"\n\n/** Replaced at build time by tsup `define` from package.json. The fallback\n * keeps `tsx`/vitest runs of the source working, where no define applies. */\ndeclare const __SDK_VERSION__: string | undefined\nconst SDK_VERSION = typeof __SDK_VERSION__ === \"string\" ? __SDK_VERSION__ : \"0.0.0-dev\"\n\n/**\n * Identifies the calling package to the backend, which records it as the job's\n * provenance (`jobs.source` / `source_detail`) so an operator can tell a CLI\n * run from an SDK integration from a browser session.\n *\n * Only `sdk/…` and `cli/…` are honoured server-side; anything else is ignored\n * rather than trusted, since this is an unauthenticated header.\n */\nexport const CLIENT_HEADER = \"X-Nodaro-Client\"\n\n/**\n * In a browser the header is redundant AND a liability, so it is not sent.\n *\n * Redundant: the browser already sends `Origin`, which names the actual product\n * (`studio.nodaro.ai`) rather than merely the library it used — and the backend\n * deliberately prefers Origin over this header, so a browser-sent value is\n * discarded on arrival.\n *\n * A liability: `X-Nodaro-Client` is not a CORS-safelisted request header, so a\n * browser sending it requires an exact match in the server's\n * `Access-Control-Allow-Headers`. Any deployment whose backend predates that\n * allowlist entry would fail the PREFLIGHT — breaking every API call from the\n * app, not just its provenance. Self-hosted and lagging deployments make that a\n * real risk, and nothing in a browser app would reveal the cause.\n *\n * An EXPLICIT `clientLabel` is always sent regardless: a caller that names\n * itself has opted in deliberately, and that intent outranks this default.\n */\nconst isBrowser = (): boolean => typeof window !== \"undefined\" && typeof window.document !== \"undefined\"\n\nexport interface ClientOptions {\n /** Backend base URL, e.g. \"https://nodaro.example.com\" or empty string for same-origin. */\n baseUrl: string\n /** Auth provider. Use StaticTokenAuth, supabaseAuth, or CallbackAuth. */\n auth: Auth\n /** Optional fetch override (for tests or custom transports). */\n fetch?: typeof fetch\n /** Default request timeout in ms. Default 60s. */\n timeoutMs?: number\n /**\n * Overrides the `X-Nodaro-Client` label. Defaults to `sdk/<version>`.\n *\n * Exists for `@nodaro/cli`, which is a wrapper AROUND this SDK: without an\n * override every CLI invocation would be recorded as an SDK call and the two\n * surfaces could never be told apart.\n */\n clientLabel?: string\n /**\n * The workspace every request acts in — sent as `X-Nodaro-Workspace`.\n *\n * It selects which workspace a LIST reads from and where a CREATE lands.\n * It never authorizes: reading, updating, deleting or running an\n * identified object is decided by that object's own workspace, so a\n * forgotten header cannot hide work and a forged one cannot reach anyone\n * else's. Omit it to work in the caller's personal space.\n *\n * Prefer {@link NodaroClient.withWorkspace} for anything short-lived — one\n * client per workspace, no shared mutable selection to get wrong.\n */\n workspaceId?: string\n}\n\ninterface RequestOptions {\n body?: unknown\n query?: Record<string, string | number | boolean | undefined>\n headers?: Record<string, string>\n signal?: AbortSignal\n}\n\n/**\n * The authenticated user's canonical identity (`GET /v1/me`). A token-\n * introspection primitive: any valid bearer token (first-party Supabase JWT or\n * a developer-app OAuth token) resolves to its owner's identity. Mirrors the\n * `profiles` identity columns server-side — the route is the source of truth.\n */\nexport interface UserIdentity {\n /** Nodaro user id (= the Supabase auth user id). */\n readonly id: string\n readonly email: string\n /** Human-readable display name (from `profiles.full_name`); `null` if unset. */\n readonly displayName: string | null\n /** Avatar URL; `null` if unset. */\n readonly avatarUrl: string | null\n /** Subscription tier (e.g. \"free\", \"pro\"). */\n readonly tier: string\n /**\n * Whether the user holds an admin role. DESCRIPTIVE only — use it to decide\n * whether to render admin surfaces without capability-probing an admin\n * endpoint; every admin API stays enforced server-side regardless.\n */\n readonly isAdmin: boolean\n}\n\n/**\n * An app the user let into their account through OAuth (`GET\n * /v1/me/connected-apps`): a developer app, an AI assistant's MCP connector, or\n * a self-hosted install. One entry per grant still in force.\n */\nexport interface ConnectedApp {\n /** The grant's id — what {@link NodaroClient.revokeConnectedApp} takes. */\n readonly authorizationId: string\n /** The app's name; `null` if it has none. A `dynamic_mcp` client chose its own. */\n readonly name: string | null\n /**\n * How the app came to exist: `user` (a developer app someone registered),\n * `first_party_mcp`, `dynamic_mcp` (an MCP client that registered itself) or\n * `community_instance` (a self-hosted install).\n */\n readonly kind: DeveloperAppKind | (string & {})\n readonly homepageUrl: string | null\n /** The scopes this grant holds. */\n readonly scopes: readonly DeveloperAppScope[]\n /** When the user granted access (ISO 8601). */\n readonly connectedAt: string\n /** The latest use of any token issued under the grant; `null` if never used. */\n readonly lastUsedAt: string | null\n}\n\nexport class NodaroClientCore {\n readonly baseUrl: string\n readonly auth: Auth\n readonly timeoutMs: number\n /** Value sent as `X-Nodaro-Client`; recorded by the backend as job provenance. */\n readonly clientLabel: string\n /** Whether to actually send it — see the note on {@link CLIENT_HEADER}. */\n private readonly sendClientHeader: boolean\n private readonly fetchOverride: typeof fetch | undefined\n\n /**\n * Resolved lazily so consumers can swap `globalThis.fetch` after the\n * client has been constructed (e.g. test mocks). Always rebound to the\n * global object — native fetch throws \"Illegal invocation\" when its\n * `this` is anything else.\n */\n get fetch(): typeof fetch {\n return this.fetchOverride ?? globalThis.fetch.bind(globalThis)\n }\n\n /** The workspace this client acts in; undefined = the personal space. */\n readonly workspaceId: string | undefined\n\n constructor(opts: ClientOptions) {\n this.baseUrl = opts.baseUrl.replace(/\\/$/, \"\") // strip trailing slash\n this.auth = opts.auth\n this.fetchOverride = opts.fetch\n this.timeoutMs = opts.timeoutMs ?? 60_000\n this.clientLabel = opts.clientLabel ?? `sdk/${SDK_VERSION}`\n this.workspaceId = opts.workspaceId\n // Explicit label = deliberate opt-in, always sent. The default is suppressed\n // in browsers — see the note on CLIENT_HEADER.\n this.sendClientHeader = opts.clientLabel !== undefined || !isBrowser()\n }\n\n /**\n * The transport: build the request, send it, throw the typed error on a\n * non-2xx via {@link throwFromResponse}, then read the body via `read` — all\n * inside the abort timer, so `timeoutMs` bounds the body download too (a\n * stalled CSV stream aborts, it does not hang forever). Both the JSON path\n * ({@link request}) and the text path ({@link requestText}) go through here.\n */\n private async send<T>(\n method: string,\n path: string,\n options: RequestOptions,\n read: (res: Response) => Promise<T>,\n ): Promise<T> {\n const url = this.buildUrl(path, options.query)\n\n const token = await this.auth.getToken()\n // A `FormData` body is a multipart upload: let the runtime set\n // `Content-Type: multipart/form-data; boundary=…` itself (a manual JSON\n // content-type corrupts the boundary), and send the body as-is rather than\n // JSON-stringifying it. Every other body stays JSON, exactly as before.\n const isFormData =\n typeof FormData !== \"undefined\" && options.body instanceof FormData\n const headers: Record<string, string> = {\n ...(isFormData ? {} : { \"Content-Type\": \"application/json\" }),\n ...(this.sendClientHeader ? { [CLIENT_HEADER]: this.clientLabel } : {}),\n // Before per-request headers: a resource that needs to reach outside\n // this client's workspace says so explicitly and wins.\n ...(this.workspaceId ? { [WORKSPACE_HEADER]: this.workspaceId } : {}),\n ...(options.headers ?? {}),\n }\n if (token) headers[\"Authorization\"] = `Bearer ${token}`\n\n const ac = new AbortController()\n const timeoutId = setTimeout(() => ac.abort(), this.timeoutMs)\n const abort = () => ac.abort(options.signal?.reason)\n options.signal?.addEventListener(\"abort\", abort, { once: true })\n if (options.signal?.aborted) abort()\n\n try {\n ac.signal.throwIfAborted()\n const res = await this.fetch(url, {\n method,\n headers,\n body:\n options.body === undefined\n ? undefined\n : isFormData\n ? (options.body as FormData)\n : JSON.stringify(options.body),\n signal: ac.signal,\n })\n\n if (!res.ok) {\n let errBody: Record<string, unknown> = {}\n try {\n errBody = await res.json() as Record<string, unknown>\n } catch {\n // Empty/non-JSON body — fall through with empty errBody\n }\n throwFromResponse(res.status, errBody)\n }\n\n return await read(res)\n } finally {\n clearTimeout(timeoutId)\n options.signal?.removeEventListener(\"abort\", abort)\n }\n }\n\n /** Authenticated, bounded binary reads through the normal timeout/error transport. */\n async requestBytes(method: string, path: string, options: RequestOptions & { maxBytes: number }): Promise<ArrayBuffer> {\n if (!Number.isSafeInteger(options.maxBytes) || options.maxBytes < 1) throw new Error(\"maxBytes must be a positive integer\")\n return this.send(method, path, options, (response) => readBinaryResponse(response, options.maxBytes))\n }\n\n async request<T>(method: string, path: string, options: RequestOptions = {}): Promise<T> {\n return this.send(method, path, options, async (res) =>\n // 204 No Content\n res.status === 204 ? (undefined as T) : ((await res.json()) as T),\n )\n }\n\n /**\n * Like {@link request}, for endpoints that answer text (CSV exports). Errors\n * are still the JSON envelope and throw the same typed errors, and the read is\n * bounded by the same timeout as the request.\n */\n async requestText(method: string, path: string, options: RequestOptions = {}): Promise<string> {\n return this.send(method, path, options, (res) => res.text())\n }\n\n /**\n * `GET /v1/me` → the authenticated user's identity (see {@link UserIdentity}).\n * Unwraps the `{ data }` envelope. Throws `UnauthorizedError` (401) when the\n * token is missing/invalid, and the SDK's other typed errors as usual.\n *\n * On an instance with organizations it also carries what the caller belongs\n * to. THREE states, and collapsing them is wrong in a way users feel: the\n * organization fields ABSENT means this instance has no organizations at\n * all; present and empty means the account belongs to none; and\n * `organizationsUnavailable` means the lookup failed — keep whatever\n * selection you already had rather than concluding the person was removed\n * from everything.\n */\n async me(): Promise<UserIdentity & MeOrganizations> {\n const res = await this.request<{ data: UserIdentity & MeOrganizations }>(\"GET\", \"/v1/me\")\n return res.data\n }\n\n /**\n * `GET /v1/me/connected-apps` → every app with access to the signed-in\n * user's account (see {@link ConnectedApp}), newest grant first.\n *\n * **A signed-in browser session only.** The route answers a Supabase\n * session token (`supabaseAuth(…)`, `createSharedSupabaseClient`, or a\n * `StaticTokenAuth` holding one) and refuses every other credential with\n * `UnauthorizedError` (\"Sign in required\"): an app token or an API key must\n * not list the grants it lives under. Build your \"Connected apps\" settings\n * screen on this; a server-side integration cannot call it.\n */\n async connectedApps(): Promise<ConnectedApp[]> {\n const res = await this.request<{ apps: ConnectedApp[] }>(\"GET\", \"/v1/me/connected-apps\")\n return res.apps\n }\n\n /**\n * `POST /v1/me/connected-apps/:authorizationId/revoke` — ends an app's\n * access: the grant and every token issued under it, at once (the app's next\n * call is a 401). Resolves when done.\n *\n * A signed-in browser session only, like {@link connectedApps}. Throws\n * `NotFoundError` when the grant is not the user's or is already revoked.\n */\n async revokeConnectedApp(authorizationId: string): Promise<void> {\n await this.request(\"POST\", `/v1/me/connected-apps/${encodeURIComponent(authorizationId)}/revoke`)\n }\n\n private buildUrl(path: string, query?: Record<string, string | number | boolean | undefined>): string {\n const base = this.baseUrl || (typeof window !== \"undefined\" ? window.location.origin : \"http://placeholder\")\n const url = new URL(path, base)\n // If baseUrl was empty, strip the placeholder origin\n const fullUrl = this.baseUrl ? url.toString() : url.pathname + url.search\n if (query) {\n const u = new URL(this.baseUrl ? fullUrl : fullUrl, base)\n for (const [k, v] of Object.entries(query)) {\n if (v !== undefined) u.searchParams.set(k, String(v))\n }\n return this.baseUrl ? u.toString() : u.pathname + u.search\n }\n return fullUrl\n }\n}\n","/**\n * Auth provides the token used for `Authorization: Bearer <token>` on each request.\n * Implementations:\n * - StaticTokenAuth — fixed string (server-side, OAuth access token, API token)\n * - CallbackAuth — caller-supplied async function (BYO logic)\n * - supabaseAuth — pulls JWT from a Supabase client live (browser frontends)\n */\nexport interface Auth {\n /** Returns the current Bearer token, or null if not authenticated. */\n getToken(): Promise<string | null>\n}\n\nexport class StaticTokenAuth implements Auth {\n constructor(private token: string) {}\n async getToken() {\n return this.token\n }\n}\n\nexport class CallbackAuth implements Auth {\n constructor(private fn: () => string | null | Promise<string | null>) {}\n async getToken() {\n return this.fn()\n }\n}\n\ninterface SupabaseLikeClient {\n auth: {\n getSession(): Promise<{ data: { session: { access_token: string } | null } }>\n }\n}\n\n/** Pulls a JWT from a Supabase v2 client. Caller supplies their own supabase. */\nexport function supabaseAuth(supabase: SupabaseLikeClient): Auth {\n return {\n async getToken() {\n const { data } = await supabase.auth.getSession()\n return data.session?.access_token ?? null\n },\n }\n}\n"]}
|