@nodaro/sdk 2.25.0 → 2.27.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/README.md +2 -1
- package/dist/index.cjs +191 -69
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +380 -20
- package/dist/index.d.ts +380 -20
- package/dist/index.js +135 -12
- package/dist/index.js.map +1 -1
- package/dist/signup-signals.cjs +88 -0
- package/dist/signup-signals.cjs.map +1 -0
- package/dist/signup-signals.d.cts +55 -0
- package/dist/signup-signals.d.ts +55 -0
- package/dist/signup-signals.js +82 -0
- package/dist/signup-signals.js.map +1 -0
- package/package.json +14 -3
package/dist/index.js
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
export { OUTPUT_BEARING_NODE_STATUSES, nodeStateMayCarryOutput } from '@nodaro/shared/workflow';
|
|
2
|
+
import { nodeRunRoute, NODE_TYPES_WITHOUT_RUN_ROUTE, NODE_RUN_ROUTES } from '@nodaro/shared/nodes';
|
|
3
|
+
export { PROMPT_PREFIX_KEY, PROMPT_SUFFIX_KEY } from '@nodaro/shared/nodes';
|
|
4
|
+
import { SOCIAL_POST_NODE_PLATFORM } from '@nodaro/shared/social';
|
|
5
|
+
import { SCENE3D_V2_LIMITS } from '@nodaro/shared/scene3d';
|
|
6
|
+
import { buildPersonHints } from '@nodaro/prompts/person';
|
|
7
|
+
export { PEOPLE, PERSON_DIMENSION_LABELS, PERSON_DIMENSION_ORDER, buildPersonHints } from '@nodaro/prompts/person';
|
|
8
|
+
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, SURROUND_DIRECTIONS } from '@nodaro/shared/entities';
|
|
9
|
+
import { resolveEditPlanSources, describeAudioSyncOffsetIssue, transcriptSpeakerLabels, remapTranscriptThroughEdl } from '@nodaro/shared/edl';
|
|
10
|
+
export { unwrapEditPlanOutput } from '@nodaro/shared/edl';
|
|
11
|
+
import { WORKSPACE_HEADER } from '@nodaro/shared/organizations';
|
|
12
|
+
export { USAGE_GROUP_BYS, WORKSPACE_HEADER } from '@nodaro/shared/organizations';
|
|
13
|
+
export { RECAST_SEGMENT_PACKS } from '@nodaro/shared/apps';
|
|
5
14
|
|
|
6
15
|
// src/binary-response.ts
|
|
7
16
|
async function readBinaryResponse(response, maxBytes) {
|
|
@@ -112,6 +121,19 @@ var StudioOpError = class extends NodaroError {
|
|
|
112
121
|
}
|
|
113
122
|
opIndex;
|
|
114
123
|
};
|
|
124
|
+
var CONTINUATION_REFUSAL_CODES = /* @__PURE__ */ new Set([
|
|
125
|
+
"already_running",
|
|
126
|
+
"continuation_superseded",
|
|
127
|
+
"render_final_already_rendered"
|
|
128
|
+
]);
|
|
129
|
+
var ContinuationRefusedError = class extends NodaroError {
|
|
130
|
+
constructor(message, code, jobId) {
|
|
131
|
+
super(message, code, 409);
|
|
132
|
+
this.jobId = jobId;
|
|
133
|
+
this.name = "ContinuationRefusedError";
|
|
134
|
+
}
|
|
135
|
+
jobId;
|
|
136
|
+
};
|
|
115
137
|
var JobBlockedError = class extends NodaroError {
|
|
116
138
|
constructor(message = "Blocked by this deployment's content policy") {
|
|
117
139
|
super(message, "job_blocked", 422);
|
|
@@ -184,12 +206,15 @@ function throwFromResponse(status, body) {
|
|
|
184
206
|
if (status >= 400 && status < 500 && typeof body.error?.opIndex === "number") {
|
|
185
207
|
throw new StudioOpError(message, code, status, body.error.opIndex);
|
|
186
208
|
}
|
|
209
|
+
if (status === 409 && CONTINUATION_REFUSAL_CODES.has(code) && typeof body.jobId === "string") {
|
|
210
|
+
throw new ContinuationRefusedError(message, code, body.jobId);
|
|
211
|
+
}
|
|
187
212
|
if (status === 422 && code === "job_blocked") throw new JobBlockedError(message);
|
|
188
213
|
if (status === 403 && code === "insufficient_scope") {
|
|
189
214
|
throw new ForbiddenError(message, body.error?.missingScope);
|
|
190
215
|
}
|
|
191
216
|
if (status === 403) throw new ForbiddenError(message);
|
|
192
|
-
if (status === 404) throw new NotFoundError(message);
|
|
217
|
+
if (status === 404) throw new NotFoundError(body.error?.message ?? (typeof body.message === "string" ? body.message : void 0));
|
|
193
218
|
if (status === 429) throw new RateLimitedError(message);
|
|
194
219
|
if (status === 402) {
|
|
195
220
|
throw new InsufficientCreditsError(message, body.error?.required, body.error?.available);
|
|
@@ -539,8 +564,6 @@ var ExecutionsResource = class {
|
|
|
539
564
|
);
|
|
540
565
|
}
|
|
541
566
|
};
|
|
542
|
-
|
|
543
|
-
// src/resources/nodes.ts
|
|
544
567
|
var DEFAULT_POLL_MS = 2e3;
|
|
545
568
|
var DEFAULT_MAX_MS = 15 * 60 * 1e3;
|
|
546
569
|
var sleep = (ms, signal) => new Promise((resolve, reject) => {
|
|
@@ -558,6 +581,10 @@ var sleep = (ms, signal) => new Promise((resolve, reject) => {
|
|
|
558
581
|
}
|
|
559
582
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
560
583
|
});
|
|
584
|
+
function notRunnable(type, why) {
|
|
585
|
+
return new NodaroError(`Node type "${type}" has no route of its own to run it directly: ${why}.`, "node_not_runnable", 0);
|
|
586
|
+
}
|
|
587
|
+
var isRouteNotFound = (err) => err instanceof NotFoundError && /^Route\b.*\bnot found\b/i.test(err.message);
|
|
561
588
|
function extractJobId(result, label) {
|
|
562
589
|
if (result && typeof result === "object" && "jobId" in result) {
|
|
563
590
|
const jobId = result.jobId;
|
|
@@ -579,13 +606,20 @@ var NodesResource = class {
|
|
|
579
606
|
return this.client.request("GET", `/v1/nodes/${encodeURIComponent(type)}`);
|
|
580
607
|
}
|
|
581
608
|
run(type, params = {}, options = {}) {
|
|
582
|
-
const route = type === "
|
|
609
|
+
const route = type === "render-video" && typeof params.planType === "string" ? "/v1/render-video/plan" : nodeRunRoute(type);
|
|
610
|
+
if (!route) return Promise.reject(notRunnable(type, NODE_TYPES_WITHOUT_RUN_ROUTE[type]));
|
|
611
|
+
const platform = SOCIAL_POST_NODE_PLATFORM[type];
|
|
612
|
+
const body = platform && params.platform === void 0 ? { ...params, platform } : params;
|
|
613
|
+
const conventional = !Object.prototype.hasOwnProperty.call(NODE_RUN_ROUTES, type);
|
|
583
614
|
return this.client.request("POST", route, {
|
|
584
|
-
body
|
|
615
|
+
body,
|
|
585
616
|
// Transport-level retry safety, opt-in per call. The platform reads the
|
|
586
617
|
// standard header, so a caller that reuses a key on a retry gets the
|
|
587
618
|
// same run back instead of a second charge.
|
|
588
619
|
...options.idempotencyKey ? { headers: { "Idempotency-Key": options.idempotencyKey } } : {}
|
|
620
|
+
}).catch((err) => {
|
|
621
|
+
if (conventional && isRouteNotFound(err)) throw notRunnable(type, "it runs only inside a workflow (client.workflows.run)");
|
|
622
|
+
throw err;
|
|
589
623
|
});
|
|
590
624
|
}
|
|
591
625
|
async runAndWait(type, params = {}, opts = {}) {
|
|
@@ -2386,6 +2420,20 @@ var MediaResource = class {
|
|
|
2386
2420
|
trimAudio(input) {
|
|
2387
2421
|
return this.client.request("POST", "/v1/trim-audio", { body: input });
|
|
2388
2422
|
}
|
|
2423
|
+
/**
|
|
2424
|
+
* Cut a video and/or an audio file into consecutive parts
|
|
2425
|
+
* (`POST /v1/split-media`). Every part is at most `chunkDuration` seconds and
|
|
2426
|
+
* at least `minPartDuration` (default 4, never above `chunkDuration`) — a
|
|
2427
|
+
* short leftover is evened out with the parts before it. Video is cut on
|
|
2428
|
+
* whole frames with each part's sound matching its picture; audio parts are
|
|
2429
|
+
* sample-exact, in `audioFormat` (`mp3` default / `wav` / `aac`). With both
|
|
2430
|
+
* sources each is split on its own. At most 200 parts per input. Poll
|
|
2431
|
+
* `jobs.get(jobId)`; the parts are on the completed job's `output_data` —
|
|
2432
|
+
* see {@link SplitMediaOutput}.
|
|
2433
|
+
*/
|
|
2434
|
+
splitMedia(input) {
|
|
2435
|
+
return this.client.request("POST", "/v1/split-media", { body: input });
|
|
2436
|
+
}
|
|
2389
2437
|
/**
|
|
2390
2438
|
* Turn one still image + one audio track into an MP4
|
|
2391
2439
|
* (`POST /v1/still-to-video`) — locally rendered (FFmpeg), no AI model,
|
|
@@ -2513,7 +2561,10 @@ var AudioResource = class {
|
|
|
2513
2561
|
* `ratio` (1–20, overrides `amount`), `attackMs` (1–2000, default 20) and
|
|
2514
2562
|
* `releaseMs` (10–9000, default 500) are optional fine controls. A ducked mix
|
|
2515
2563
|
* sums its tracks rather than averaging them, so the voice keeps its level;
|
|
2516
|
-
* the price is the same with or without a duck.
|
|
2564
|
+
* the price is the same with or without a duck. `endAt` (`"longest"`, the
|
|
2565
|
+
* default, or `"voice"`) says where the mix ends: `"voice"` ends it when the
|
|
2566
|
+
* voice (the `duck.under` track) ends (needs `duck`). A video URL is a track
|
|
2567
|
+
* too: its audio is mixed, and a video with no sound is a silent track.
|
|
2517
2568
|
*/
|
|
2518
2569
|
mix(input) {
|
|
2519
2570
|
return this.client.request("POST", "/v1/mix-audio", { body: input });
|
|
@@ -2590,6 +2641,18 @@ var CreditsResource = class {
|
|
|
2590
2641
|
);
|
|
2591
2642
|
return res.data;
|
|
2592
2643
|
}
|
|
2644
|
+
/**
|
|
2645
|
+
* `GET /v1/credits/transactions` → one page of the caller's credit
|
|
2646
|
+
* transactions, newest first, with `nextCursor` for the next page (`null`
|
|
2647
|
+
* at the end). Read `credits_charged` for what each run cost — it can be
|
|
2648
|
+
* below the hold (`credits_reserved`) and is `null` while the hold is open.
|
|
2649
|
+
* Cloud-only route: a self-hosted instance answers 404.
|
|
2650
|
+
*/
|
|
2651
|
+
transactions(options = {}) {
|
|
2652
|
+
return this.client.request("GET", "/v1/credits/transactions", {
|
|
2653
|
+
query: { limit: options.limit, cursor: options.cursor }
|
|
2654
|
+
});
|
|
2655
|
+
}
|
|
2593
2656
|
/**
|
|
2594
2657
|
* `POST /v1/credits/model-costs` → per-identifier credit cost, for editor
|
|
2595
2658
|
* cost previews. Capped at the first {@link MODEL_COSTS_LIMIT} identifiers
|
|
@@ -2601,6 +2664,23 @@ var CreditsResource = class {
|
|
|
2601
2664
|
body: { models: ids.slice(0, MODEL_COSTS_LIMIT) }
|
|
2602
2665
|
});
|
|
2603
2666
|
}
|
|
2667
|
+
/**
|
|
2668
|
+
* `POST /v1/credits/claim-signup-grant` → claims the account's free signup
|
|
2669
|
+
* grant, once, with the browser signals of the page making the claim.
|
|
2670
|
+
*
|
|
2671
|
+
* Call it once per page load as soon as the session is known, and never
|
|
2672
|
+
* wait on it for rendering: it is idempotent (a decided account answers
|
|
2673
|
+
* with its state and `granted: false`), it costs the user nothing when it
|
|
2674
|
+
* fails (the next load asks again), and the signals are what make the
|
|
2675
|
+
* claim worth sending — collect them with `collectSignupKeys()` from
|
|
2676
|
+
* `@nodaro/sdk/signup-signals` and pass whatever came back, `{}` included.
|
|
2677
|
+
* Cloud-only route: a self-hosted instance answers 404.
|
|
2678
|
+
*/
|
|
2679
|
+
claimSignupGrant(keys = {}) {
|
|
2680
|
+
return this.client.request("POST", "/v1/credits/claim-signup-grant", {
|
|
2681
|
+
body: keys
|
|
2682
|
+
});
|
|
2683
|
+
}
|
|
2604
2684
|
// NOTE: no `estimate(...)` helper. The backend exposes
|
|
2605
2685
|
// `POST /v1/credits/estimate-workflow` (body `{ nodes }` → `{ data: {
|
|
2606
2686
|
// totalCredits, nodeCount } }`), but no consumer has a settled shape for it
|
|
@@ -3915,6 +3995,13 @@ var WorkspacesResource = class {
|
|
|
3915
3995
|
return this.client.requestText("GET", `/v1/workspaces/${encodeURIComponent(id)}/usage`, { query: { ...opts, format: "csv" } });
|
|
3916
3996
|
}
|
|
3917
3997
|
};
|
|
3998
|
+
function tightenBody(input) {
|
|
3999
|
+
const { mediaUrl, ...rest } = input;
|
|
4000
|
+
return { mediaUrls: [mediaUrl], ...Object.fromEntries(Object.entries(rest).filter(([, v]) => v !== void 0)) };
|
|
4001
|
+
}
|
|
4002
|
+
function idempotencyHeaders(options) {
|
|
4003
|
+
return options?.idempotencyKey ? { headers: { "Idempotency-Key": options.idempotencyKey } } : {};
|
|
4004
|
+
}
|
|
3918
4005
|
var EditResource = class {
|
|
3919
4006
|
constructor(client) {
|
|
3920
4007
|
this.client = client;
|
|
@@ -3974,6 +4061,42 @@ var EditResource = class {
|
|
|
3974
4061
|
}
|
|
3975
4062
|
});
|
|
3976
4063
|
}
|
|
4064
|
+
/**
|
|
4065
|
+
* Tighten Episode (`POST /v1/tighten-episode`): tighten a podcast recording
|
|
4066
|
+
* in one call — transcribe, cut the silences and filler, render, with
|
|
4067
|
+
* optional captions, music and framing. Answers the run's job to poll; its
|
|
4068
|
+
* `output_data` holds the episode. The run is priced as its steps at their own
|
|
4069
|
+
* rates plus the listed per-run fee. Quote it first with
|
|
4070
|
+
* {@link estimateTightenEpisode}.
|
|
4071
|
+
*/
|
|
4072
|
+
tightenEpisode(input, options) {
|
|
4073
|
+
return this.client.request("POST", "/v1/tighten-episode", { body: tightenBody(input), ...idempotencyHeaders(options) });
|
|
4074
|
+
}
|
|
4075
|
+
/**
|
|
4076
|
+
* What a Tighten Episode run is estimated at (`POST /v1/tighten-episode/estimate`):
|
|
4077
|
+
* its steps at their own rates plus its per-run fee. Nothing is created or
|
|
4078
|
+
* charged. The estimate leans high: the render is priced at the recording's
|
|
4079
|
+
* full length, while the charge follows the minutes actually rendered.
|
|
4080
|
+
*/
|
|
4081
|
+
estimateTightenEpisode(input) {
|
|
4082
|
+
return this.client.request("POST", "/v1/tighten-episode/estimate", { body: tightenBody(input) });
|
|
4083
|
+
}
|
|
4084
|
+
/**
|
|
4085
|
+
* Continue a Tighten Episode run as a new job (`POST /v1/tighten-episode/continue`):
|
|
4086
|
+
* `"from-failed"` keeps the steps that finished and runs the rest (the fee is
|
|
4087
|
+
* held again; the failed run's was refunded); `"render-final"` renders the
|
|
4088
|
+
* full-quality episode after a review-on preview, with the preview's
|
|
4089
|
+
* settings and no fee. A refusal that names another job
|
|
4090
|
+
* (`already_running`, `continuation_superseded`,
|
|
4091
|
+
* `render_final_already_rendered`) throws a `ContinuationRefusedError`
|
|
4092
|
+
* carrying that `jobId`.
|
|
4093
|
+
*/
|
|
4094
|
+
continueUseCase(input, options) {
|
|
4095
|
+
return this.client.request("POST", "/v1/tighten-episode/continue", {
|
|
4096
|
+
body: { jobId: input.jobId, mode: input.mode, ...input.editedEdl !== void 0 ? { editedEdl: input.editedEdl } : {} },
|
|
4097
|
+
...idempotencyHeaders(options)
|
|
4098
|
+
});
|
|
4099
|
+
}
|
|
3977
4100
|
/**
|
|
3978
4101
|
* Plan a transcript-driven cut (`POST /v1/edit-plan`). Reads a timed
|
|
3979
4102
|
* transcript (plus optional silence ranges) and the media sources, and plans
|
|
@@ -4054,7 +4177,7 @@ var EditResource = class {
|
|
|
4054
4177
|
return remapTranscriptThroughEdl(edl, transcript);
|
|
4055
4178
|
}
|
|
4056
4179
|
};
|
|
4057
|
-
var SDK_VERSION = "2.
|
|
4180
|
+
var SDK_VERSION = "2.27.0" ;
|
|
4058
4181
|
var CLIENT_HEADER = "X-Nodaro-Client";
|
|
4059
4182
|
var isBrowser = () => typeof window !== "undefined" && typeof window.document !== "undefined";
|
|
4060
4183
|
var NodaroClient = class _NodaroClient {
|
|
@@ -4323,6 +4446,6 @@ function supabaseAuth(supabase) {
|
|
|
4323
4446
|
};
|
|
4324
4447
|
}
|
|
4325
4448
|
|
|
4326
|
-
export { AppsResource, AudioResource, CREATURE_ASSET_TYPES, CallbackAuth, CatalogsResource, CharactersResource, CollectionsResource, CommunityResource, CompetitorsResource, CopilotResource, CreaturesResource, CreditsResource, DeveloperAppsResource, EditResource, ExecutionsResource, ForbiddenError, InsufficientCreditsError, JobAbortedError, JobBlockedError, JobFailedError, JobHeldError, JobTimeoutError, JobsResource, LibraryResource, LlmResource, LocationsResource, MediaResource, ModelsResource, NodaroClient, NodaroError, NodesResource, NotFoundError, OAuthResource, ObjectsResource, OrganizationsResource, PickerCatalogsResource, PipelinesResource, PresetsResource, ProjectsResource, PromptHelperResource, RateLimitedError, RecastResource, ReduceResource, SCENE3D_DELIVERY_ASSET_USAGE, SavedPostsResource, Scene3DResource, ShotsResource, StaticTokenAuth, StorageExceededError, StudioOpError, StudioPreviewAppliedError, StudioPreviewUnavailable, StudioProductionsResource, StudioResource, TemplatesResource, TutorialsResource, UnauthorizedError, UploadsResource, VideoProResource, VoicesResource, WorkflowConflictError, WorkflowsResource, WorkspacesResource, buildPersonSeedPrompt, createClient, isStudioGenerateEstimate, supabaseAuth, throwFromResponse };
|
|
4449
|
+
export { AppsResource, AudioResource, CREATURE_ASSET_TYPES, CallbackAuth, CatalogsResource, CharactersResource, CollectionsResource, CommunityResource, CompetitorsResource, ContinuationRefusedError, CopilotResource, CreaturesResource, CreditsResource, DeveloperAppsResource, EditResource, ExecutionsResource, ForbiddenError, InsufficientCreditsError, JobAbortedError, JobBlockedError, JobFailedError, JobHeldError, JobTimeoutError, JobsResource, LibraryResource, LlmResource, LocationsResource, MediaResource, ModelsResource, NodaroClient, NodaroError, NodesResource, NotFoundError, OAuthResource, ObjectsResource, OrganizationsResource, PickerCatalogsResource, PipelinesResource, PresetsResource, ProjectsResource, PromptHelperResource, RateLimitedError, RecastResource, ReduceResource, SCENE3D_DELIVERY_ASSET_USAGE, SavedPostsResource, Scene3DResource, ShotsResource, StaticTokenAuth, StorageExceededError, StudioOpError, StudioPreviewAppliedError, StudioPreviewUnavailable, StudioProductionsResource, StudioResource, TemplatesResource, TutorialsResource, UnauthorizedError, UploadsResource, VideoProResource, VoicesResource, WorkflowConflictError, WorkflowsResource, WorkspacesResource, buildPersonSeedPrompt, createClient, isStudioGenerateEstimate, supabaseAuth, throwFromResponse };
|
|
4327
4450
|
//# sourceMappingURL=index.js.map
|
|
4328
4451
|
//# sourceMappingURL=index.js.map
|