@nodaro/sdk 2.25.0 → 2.26.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/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { SCENE3D_V2_LIMITS, resolveEditPlanSources, describeAudioSyncOffsetIssue, transcriptSpeakerLabels, remapTranscriptThroughEdl, WORKSPACE_HEADER } from '@nodaro/shared';
1
+ import { nodeRunRoute, NODE_TYPES_WITHOUT_RUN_ROUTE, SOCIAL_POST_NODE_PLATFORM, NODE_RUN_ROUTES, SCENE3D_V2_LIMITS, resolveEditPlanSources, describeAudioSyncOffsetIssue, transcriptSpeakerLabels, remapTranscriptThroughEdl, WORKSPACE_HEADER } from '@nodaro/shared';
2
2
  export { CHARACTER_ASPECT_DEFAULTS, CHARACTER_ASPECT_OPTIONS, CHARACTER_STYLES, OBJECT_ASPECT_DEFAULTS as CREATURE_ASPECT_DEFAULTS, OBJECT_ASPECT_OPTIONS as CREATURE_ASPECT_OPTIONS, CREATURE_ATTACH_COLUMNS, LOCATION_ASSET_TYPES, LOCATION_ATTACH_COLUMNS, OBJECT_ASPECT_DEFAULTS, OBJECT_ASPECT_OPTIONS, OBJECT_ASSET_TYPES, OBJECT_ATTACH_COLUMNS, OUTPUT_BEARING_NODE_STATUSES, PROMPT_PREFIX_KEY, PROMPT_SUFFIX_KEY, RECAST_SEGMENT_PACKS, SURROUND_DIRECTIONS, USAGE_GROUP_BYS, WORKSPACE_HEADER, nodeStateMayCarryOutput, unwrapEditPlanOutput } from '@nodaro/shared';
3
3
  import { buildPersonHints } from '@nodaro/prompts';
4
4
  export { PEOPLE, PERSON_DIMENSION_LABELS, PERSON_DIMENSION_ORDER, buildPersonHints } from '@nodaro/prompts';
@@ -189,7 +189,7 @@ function throwFromResponse(status, body) {
189
189
  throw new ForbiddenError(message, body.error?.missingScope);
190
190
  }
191
191
  if (status === 403) throw new ForbiddenError(message);
192
- if (status === 404) throw new NotFoundError(message);
192
+ if (status === 404) throw new NotFoundError(body.error?.message ?? (typeof body.message === "string" ? body.message : void 0));
193
193
  if (status === 429) throw new RateLimitedError(message);
194
194
  if (status === 402) {
195
195
  throw new InsufficientCreditsError(message, body.error?.required, body.error?.available);
@@ -539,8 +539,6 @@ var ExecutionsResource = class {
539
539
  );
540
540
  }
541
541
  };
542
-
543
- // src/resources/nodes.ts
544
542
  var DEFAULT_POLL_MS = 2e3;
545
543
  var DEFAULT_MAX_MS = 15 * 60 * 1e3;
546
544
  var sleep = (ms, signal) => new Promise((resolve, reject) => {
@@ -558,6 +556,10 @@ var sleep = (ms, signal) => new Promise((resolve, reject) => {
558
556
  }
559
557
  signal?.addEventListener("abort", onAbort, { once: true });
560
558
  });
559
+ function notRunnable(type, why) {
560
+ return new NodaroError(`Node type "${type}" has no route of its own to run it directly: ${why}.`, "node_not_runnable", 0);
561
+ }
562
+ var isRouteNotFound = (err) => err instanceof NotFoundError && /^Route\b.*\bnot found\b/i.test(err.message);
561
563
  function extractJobId(result, label) {
562
564
  if (result && typeof result === "object" && "jobId" in result) {
563
565
  const jobId = result.jobId;
@@ -579,13 +581,20 @@ var NodesResource = class {
579
581
  return this.client.request("GET", `/v1/nodes/${encodeURIComponent(type)}`);
580
582
  }
581
583
  run(type, params = {}, options = {}) {
582
- const route = type === "generate-3d-scene" ? "/v1/3d-scene/generate" : type === "edit-3d-scene" ? "/v1/3d-scene/edit" : type === "render-video" && typeof params.planType === "string" ? "/v1/render-video/plan" : `/v1/${encodeURIComponent(type)}`;
584
+ const route = type === "render-video" && typeof params.planType === "string" ? "/v1/render-video/plan" : nodeRunRoute(type);
585
+ if (!route) return Promise.reject(notRunnable(type, NODE_TYPES_WITHOUT_RUN_ROUTE[type]));
586
+ const platform = SOCIAL_POST_NODE_PLATFORM[type];
587
+ const body = platform && params.platform === void 0 ? { ...params, platform } : params;
588
+ const conventional = !Object.prototype.hasOwnProperty.call(NODE_RUN_ROUTES, type);
583
589
  return this.client.request("POST", route, {
584
- body: params,
590
+ body,
585
591
  // Transport-level retry safety, opt-in per call. The platform reads the
586
592
  // standard header, so a caller that reuses a key on a retry gets the
587
593
  // same run back instead of a second charge.
588
594
  ...options.idempotencyKey ? { headers: { "Idempotency-Key": options.idempotencyKey } } : {}
595
+ }).catch((err) => {
596
+ if (conventional && isRouteNotFound(err)) throw notRunnable(type, "it runs only inside a workflow (client.workflows.run)");
597
+ throw err;
589
598
  });
590
599
  }
591
600
  async runAndWait(type, params = {}, opts = {}) {
@@ -2386,6 +2395,20 @@ var MediaResource = class {
2386
2395
  trimAudio(input) {
2387
2396
  return this.client.request("POST", "/v1/trim-audio", { body: input });
2388
2397
  }
2398
+ /**
2399
+ * Cut a video and/or an audio file into consecutive parts
2400
+ * (`POST /v1/split-media`). Every part is at most `chunkDuration` seconds and
2401
+ * at least `minPartDuration` (default 4, never above `chunkDuration`) — a
2402
+ * short leftover is evened out with the parts before it. Video is cut on
2403
+ * whole frames with each part's sound matching its picture; audio parts are
2404
+ * sample-exact, in `audioFormat` (`mp3` default / `wav` / `aac`). With both
2405
+ * sources each is split on its own. At most 200 parts per input. Poll
2406
+ * `jobs.get(jobId)`; the parts are on the completed job's `output_data` —
2407
+ * see {@link SplitMediaOutput}.
2408
+ */
2409
+ splitMedia(input) {
2410
+ return this.client.request("POST", "/v1/split-media", { body: input });
2411
+ }
2389
2412
  /**
2390
2413
  * Turn one still image + one audio track into an MP4
2391
2414
  * (`POST /v1/still-to-video`) — locally rendered (FFmpeg), no AI model,
@@ -2601,6 +2624,23 @@ var CreditsResource = class {
2601
2624
  body: { models: ids.slice(0, MODEL_COSTS_LIMIT) }
2602
2625
  });
2603
2626
  }
2627
+ /**
2628
+ * `POST /v1/credits/claim-signup-grant` → claims the account's free signup
2629
+ * grant, once, with the browser signals of the page making the claim.
2630
+ *
2631
+ * Call it once per page load as soon as the session is known, and never
2632
+ * wait on it for rendering: it is idempotent (a decided account answers
2633
+ * with its state and `granted: false`), it costs the user nothing when it
2634
+ * fails (the next load asks again), and the signals are what make the
2635
+ * claim worth sending — collect them with `collectSignupKeys()` from
2636
+ * `@nodaro/sdk/signup-signals` and pass whatever came back, `{}` included.
2637
+ * Cloud-only route: a self-hosted instance answers 404.
2638
+ */
2639
+ claimSignupGrant(keys = {}) {
2640
+ return this.client.request("POST", "/v1/credits/claim-signup-grant", {
2641
+ body: keys
2642
+ });
2643
+ }
2604
2644
  // NOTE: no `estimate(...)` helper. The backend exposes
2605
2645
  // `POST /v1/credits/estimate-workflow` (body `{ nodes }` → `{ data: {
2606
2646
  // totalCredits, nodeCount } }`), but no consumer has a settled shape for it
@@ -4054,7 +4094,7 @@ var EditResource = class {
4054
4094
  return remapTranscriptThroughEdl(edl, transcript);
4055
4095
  }
4056
4096
  };
4057
- var SDK_VERSION = "2.25.0" ;
4097
+ var SDK_VERSION = "2.26.0" ;
4058
4098
  var CLIENT_HEADER = "X-Nodaro-Client";
4059
4099
  var isBrowser = () => typeof window !== "undefined" && typeof window.document !== "undefined";
4060
4100
  var NodaroClient = class _NodaroClient {