@nodaro/sdk 2.16.0 → 2.18.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 +39 -21
- package/dist/index.cjs +221 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +283 -27
- package/dist/index.d.ts +283 -27
- package/dist/index.js +218 -12
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Typed REST client for the [Nodaro](https://app.nodaro.ai) AI video workflow plat
|
|
|
6
6
|
npm install @nodaro/sdk
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
Docs: [Documentation](https://
|
|
9
|
+
Docs: [Documentation](https://nodaro.ai/docs) · [SDK Quickstart](https://nodaro.ai/docs/developers/sdk#install) · [SDK Reference](https://nodaro.ai/docs/developers/sdk/client) · [llms.txt](https://nodaro.ai/llms.txt)
|
|
10
10
|
|
|
11
11
|
## Getting credentials
|
|
12
12
|
|
|
@@ -21,7 +21,7 @@ app.nodaro.ai — third parties use a personal token or the OAuth flow.
|
|
|
21
21
|
|
|
22
22
|
**Not using TypeScript?** Everything here is plain REST — generate a Go /
|
|
23
23
|
Rust / Python client from the live [OpenAPI spec](https://app.nodaro.ai/v1/openapi.json)
|
|
24
|
-
([how-to](https://
|
|
24
|
+
([how-to](https://nodaro.ai/docs/developers/api/openapi)).
|
|
25
25
|
|
|
26
26
|
## Quick start (server-side, personal API token)
|
|
27
27
|
|
|
@@ -45,19 +45,20 @@ const exec = await client.workflows.run(workflowId, {
|
|
|
45
45
|
Building with Claude, Cursor, or another coding agent? Two pieces:
|
|
46
46
|
**the primer** (reusable context for *any* Nodaro project) and an
|
|
47
47
|
**example project brief** (a concrete first app). Paste the primer, then a
|
|
48
|
-
brief — yours or ours.
|
|
48
|
+
brief — yours or ours. How both work, plus ready-made agent skills:
|
|
49
|
+
[Agent skills](https://nodaro.ai/docs/developers/agent-skills#paste-the-sdk-agent-primer).
|
|
49
50
|
|
|
50
51
|
Primer straight to your clipboard
|
|
51
|
-
([raw file](https://
|
|
52
|
+
([raw file](https://raw.githubusercontent.com/nodaroai/app.nodaro.ai/main/docs/sdk-agent-primer.txt)):
|
|
52
53
|
|
|
53
54
|
```bash
|
|
54
|
-
curl -s https://
|
|
55
|
-
curl -s https://
|
|
55
|
+
curl -s https://raw.githubusercontent.com/nodaroai/app.nodaro.ai/main/docs/sdk-agent-primer.txt | pbcopy # macOS
|
|
56
|
+
curl -s https://raw.githubusercontent.com/nodaroai/app.nodaro.ai/main/docs/sdk-agent-primer.txt | xclip -sel clip # Linux
|
|
56
57
|
```
|
|
57
58
|
|
|
58
59
|
### The primer — paste into any project
|
|
59
60
|
|
|
60
|
-
<!--
|
|
61
|
+
<!-- Must match docs/sdk-agent-primer.txt (the raw copy above) line for line: src/__tests__/developer-docs.test.ts fails otherwise. -->
|
|
61
62
|
|
|
62
63
|
````text
|
|
63
64
|
You are building against @nodaro/sdk (npm), the typed client for the Nodaro
|
|
@@ -84,8 +85,8 @@ Core pattern (all generation is async; runAndWait submits + polls + resolves):
|
|
|
84
85
|
// outputs: .imageUrl / .videoUrl / .audioUrl on the resolved object
|
|
85
86
|
|
|
86
87
|
Models available (full lists with credit costs, as raw markdown):
|
|
87
|
-
image: https://
|
|
88
|
-
video: https://
|
|
88
|
+
image: https://nodaro.ai/docs/nodes/image/generate-image.md
|
|
89
|
+
video: https://nodaro.ai/docs/nodes/video/generate-video.md
|
|
89
90
|
(or at runtime: client.nodes.get(type) → data.providers + credits.modelCosts)
|
|
90
91
|
|
|
91
92
|
Model choice:
|
|
@@ -106,15 +107,28 @@ UX rules (generation takes seconds-to-minutes — never block silently):
|
|
|
106
107
|
For manual loops use client.jobs.getStatus(jobId) (id/status/progress).
|
|
107
108
|
- Let the user cancel: pass { signal } (AbortSignal) in the same options.
|
|
108
109
|
|
|
110
|
+
Voice / audio surface (client.voices, client.media, client.audio):
|
|
111
|
+
- Multi-speaker recast (Voice Changer Pro, Cloud-hosted instances):
|
|
112
|
+
await client.voices.recast({ videoUrl, orderedVoices: ["Rachel", null, "Aria"] })
|
|
113
|
+
null = that speaker keeps their original voice (positional mapping).
|
|
114
|
+
- Interactive flow: voices.analyze (detect speakers first) →
|
|
115
|
+
voices.recast({ output: "stems", analysis }) → voices.exportMix(tracks) —
|
|
116
|
+
inspect speakers before paying, mix stems before rendering.
|
|
117
|
+
- Also: voices.change (single-voice), design / remix / dub;
|
|
118
|
+
client.media.downloadVideo (+downloadVideoProgress SSE) / trimVideo /
|
|
119
|
+
trimAudio / videoMetadata; client.audio.separate / isolate / applyFx / mix.
|
|
120
|
+
|
|
109
121
|
Rules:
|
|
110
122
|
- Generations cost credits; catch InsufficientCreditsError (has .required /
|
|
111
123
|
.available). All errors are typed classes exported from @nodaro/sdk.
|
|
112
124
|
- Prefer client.nodes.runAndWait over hand-rolled polling; for manual loops
|
|
113
125
|
use client.jobs.getStatus(id) (lean poll endpoint).
|
|
114
|
-
-
|
|
115
|
-
|
|
126
|
+
- One resource per area on the client (workflows, characters, voices,
|
|
127
|
+
media, audio, pipelines, …), each listed at
|
|
128
|
+
https://nodaro.ai/docs/developers/sdk/client.md
|
|
129
|
+
full reference https://nodaro.ai/docs/developers/sdk.md
|
|
116
130
|
- Node catalog + per-node params:
|
|
117
|
-
https://
|
|
131
|
+
https://nodaro.ai/docs/nodes.md (every docs page has a .md twin)
|
|
118
132
|
````
|
|
119
133
|
|
|
120
134
|
### Example project brief — "animated postcard"
|
|
@@ -142,11 +156,15 @@ server exposes generation, workflow, and app tools:
|
|
|
142
156
|
https://mcp.nodaro.ai/mcp
|
|
143
157
|
```
|
|
144
158
|
|
|
145
|
-
[](https://
|
|
146
|
-
[](https://nodaro.ai/docs/mcp/connect/claude)
|
|
160
|
+
[](https://nodaro.ai/docs/mcp/connect/chatgpt)
|
|
161
|
+
[](https://nodaro.ai/docs/mcp/connect/cursor)
|
|
162
|
+
[](https://nodaro.ai/docs/mcp/connect/vs-code)
|
|
163
|
+
[](https://nodaro.ai/docs/mcp/connect/cline)
|
|
164
|
+
[](https://nodaro.ai/docs/mcp/connect/continue)
|
|
165
|
+
[](https://nodaro.ai/docs/mcp/connect/goose)
|
|
166
|
+
|
|
167
|
+
Any other client: [connect your own](https://nodaro.ai/docs/mcp/connect/custom-client).
|
|
150
168
|
|
|
151
169
|
Claude Code, one line:
|
|
152
170
|
|
|
@@ -154,11 +172,11 @@ Claude Code, one line:
|
|
|
154
172
|
claude mcp add --transport http nodaro https://mcp.nodaro.ai/mcp
|
|
155
173
|
```
|
|
156
174
|
|
|
157
|
-
MCP also ships **[Skills](https://
|
|
175
|
+
MCP also ships **[Skills](https://nodaro.ai/docs/mcp#what-an-assistant-can-do)** —
|
|
158
176
|
zero-install agent playbooks that come with the connection:
|
|
159
|
-
[Film Director](https://
|
|
177
|
+
[Film Director](https://nodaro.ai/docs/mcp/film-director)
|
|
160
178
|
(10-stage script → final-cut workflow, assembled live on your canvas) and
|
|
161
|
-
[Video Director](https://
|
|
179
|
+
[Video Director](https://nodaro.ai/docs/mcp/video-director)
|
|
162
180
|
(one-shot narrated motion-graphics videos).
|
|
163
181
|
|
|
164
182
|
## Run AI nodes directly
|
|
@@ -226,7 +244,7 @@ const userClient = createClient({
|
|
|
226
244
|
})
|
|
227
245
|
```
|
|
228
246
|
|
|
229
|
-
Full walkthrough: [OAuth
|
|
247
|
+
Full walkthrough: [OAuth apps](https://nodaro.ai/docs/developers/oauth).
|
|
230
248
|
|
|
231
249
|
## Errors
|
|
232
250
|
|
package/dist/index.cjs
CHANGED
|
@@ -577,7 +577,7 @@ var NodesResource = class {
|
|
|
577
577
|
*
|
|
578
578
|
* @param type Node type slug, applied to every entry.
|
|
579
579
|
* @param paramsList One request body per candidate.
|
|
580
|
-
* @param opts Shared `signal` / `onProgress` / `pollMs` / `maxMs`.
|
|
580
|
+
* @param opts Shared `signal` / `cancelOnAbort` / `onProgress` / `pollMs` / `maxMs`.
|
|
581
581
|
*/
|
|
582
582
|
async runMany(type, paramsList, opts = {}) {
|
|
583
583
|
if (opts.signal?.aborted) throw new JobAbortedError();
|
|
@@ -591,11 +591,23 @@ var NodesResource = class {
|
|
|
591
591
|
})
|
|
592
592
|
);
|
|
593
593
|
}
|
|
594
|
+
/** {@link pollUntilSettled}, plus what an abort does to the job: it keeps
|
|
595
|
+
* running unless `cancelOnAbort` asks to cancel it too, and the rejection
|
|
596
|
+
* always names it (an abort landing mid-sleep carries no id of its own). */
|
|
597
|
+
async pollJob(jobId, label, opts) {
|
|
598
|
+
try {
|
|
599
|
+
return await this.pollUntilSettled(jobId, label, opts);
|
|
600
|
+
} catch (err) {
|
|
601
|
+
if (!(err instanceof JobAbortedError)) throw err;
|
|
602
|
+
if (opts.cancelOnAbort) await this.client.jobs.cancel(jobId).catch(() => void 0);
|
|
603
|
+
throw err.jobId ? err : new JobAbortedError(err.message, jobId);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
594
606
|
/** Poll an already-kicked job id until it stops moving; resolve output_data
|
|
595
607
|
* or throw. Two non-terminal statuses end the loop: an abort, and
|
|
596
608
|
* `pending_review` (a job policy held the output for a human — see
|
|
597
609
|
* {@link JobHeldError}). */
|
|
598
|
-
async
|
|
610
|
+
async pollUntilSettled(jobId, label, opts) {
|
|
599
611
|
const pollMs = opts.pollMs ?? DEFAULT_POLL_MS;
|
|
600
612
|
const maxMs = opts.maxMs ?? DEFAULT_MAX_MS;
|
|
601
613
|
const deadline = Date.now() + maxMs;
|
|
@@ -1672,7 +1684,7 @@ var PipelinesResource = class {
|
|
|
1672
1684
|
* self-advances to completion; poll {@link get} for status and
|
|
1673
1685
|
* {@link getTimeline} for the assembled output. In manual/guided mode, drive
|
|
1674
1686
|
* it with {@link pendingApprovals} + {@link approveStage} /
|
|
1675
|
-
* {@link approveSubGate}.
|
|
1687
|
+
* {@link approveSubGate} / {@link acceptMatchCutBreak}.
|
|
1676
1688
|
*
|
|
1677
1689
|
* Requires `pipelines:execute` scope. Returns the new pipeline id.
|
|
1678
1690
|
*/
|
|
@@ -1740,8 +1752,10 @@ var PipelinesResource = class {
|
|
|
1740
1752
|
);
|
|
1741
1753
|
}
|
|
1742
1754
|
/**
|
|
1743
|
-
* Approve a Stage
|
|
1744
|
-
* orchestrator resumes from the next
|
|
1755
|
+
* Approve a Stage 7 (`animate_audio_edit`) sub-gate — `silent_cut_preview`
|
|
1756
|
+
* or `dialogue_recheck` — so the orchestrator resumes from the next
|
|
1757
|
+
* sub-step. Stage 6's `match_cut_break_pending` is not approved here: accept
|
|
1758
|
+
* each break with {@link acceptMatchCutBreak}. Requires `pipelines:approve`.
|
|
1745
1759
|
*/
|
|
1746
1760
|
approveSubGate(id, gate) {
|
|
1747
1761
|
return this.client.request(
|
|
@@ -1750,6 +1764,20 @@ var PipelinesResource = class {
|
|
|
1750
1764
|
{ body: {} }
|
|
1751
1765
|
);
|
|
1752
1766
|
}
|
|
1767
|
+
/**
|
|
1768
|
+
* Accept one match-cut break Stage 6 (`scene_images`) flagged. While any
|
|
1769
|
+
* break is pending, the stage pauses at the `match_cut_break_pending`
|
|
1770
|
+
* sub-gate, and its output lists the pending shot ids; accepting the last
|
|
1771
|
+
* one resumes the stage. `sceneId` is the scene entity that holds the shot.
|
|
1772
|
+
* Requires `pipelines:approve`.
|
|
1773
|
+
*/
|
|
1774
|
+
acceptMatchCutBreak(id, sceneId, shotId) {
|
|
1775
|
+
return this.client.request(
|
|
1776
|
+
"POST",
|
|
1777
|
+
`/v1/pipelines/${encodeURIComponent(id)}/entities/${encodeURIComponent(sceneId)}/helpers/accept_match_cut_break`,
|
|
1778
|
+
{ body: { shotId } }
|
|
1779
|
+
);
|
|
1780
|
+
}
|
|
1753
1781
|
/**
|
|
1754
1782
|
* Read a single stage's `status`, `output`, and `critic_feedback`. Useful for
|
|
1755
1783
|
* inspecting the script/plan before approving. Requires `pipelines:read`.
|
|
@@ -2588,6 +2616,139 @@ var PresetsResource = class {
|
|
|
2588
2616
|
}
|
|
2589
2617
|
};
|
|
2590
2618
|
|
|
2619
|
+
// src/resources/saved-posts.ts
|
|
2620
|
+
var SavedPostsResource = class {
|
|
2621
|
+
constructor(client) {
|
|
2622
|
+
this.client = client;
|
|
2623
|
+
}
|
|
2624
|
+
client;
|
|
2625
|
+
/** `GET /v1/saved-posts` → your saves, newest first. Page with `nextCursor`. */
|
|
2626
|
+
list(params = {}) {
|
|
2627
|
+
return this.client.request("GET", "/v1/saved-posts", {
|
|
2628
|
+
query: {
|
|
2629
|
+
platform: params.platform,
|
|
2630
|
+
tag: params.tag,
|
|
2631
|
+
q: params.q,
|
|
2632
|
+
cursor: params.cursor,
|
|
2633
|
+
limit: params.limit
|
|
2634
|
+
}
|
|
2635
|
+
});
|
|
2636
|
+
}
|
|
2637
|
+
/**
|
|
2638
|
+
* `POST /v1/saved-posts` → save a post. Saving a post that is already saved
|
|
2639
|
+
* updates its note and tags (when given) and returns the existing save.
|
|
2640
|
+
*/
|
|
2641
|
+
save(input) {
|
|
2642
|
+
return this.client.request("POST", "/v1/saved-posts", { body: input });
|
|
2643
|
+
}
|
|
2644
|
+
/** `POST /v1/saved-posts/lookup` → which of these post ids (`SocialPost.id`) you saved. */
|
|
2645
|
+
lookup(postIds) {
|
|
2646
|
+
return this.client.request("POST", "/v1/saved-posts/lookup", { body: { postIds } });
|
|
2647
|
+
}
|
|
2648
|
+
/** `PATCH /v1/saved-posts/:id` → change a save's note or tags. */
|
|
2649
|
+
update(id, input) {
|
|
2650
|
+
return this.client.request("PATCH", `/v1/saved-posts/${encodeURIComponent(id)}`, { body: input });
|
|
2651
|
+
}
|
|
2652
|
+
/** `DELETE /v1/saved-posts/:id` → remove a save and its copied still. */
|
|
2653
|
+
async delete(id) {
|
|
2654
|
+
await this.client.request("DELETE", `/v1/saved-posts/${encodeURIComponent(id)}`);
|
|
2655
|
+
}
|
|
2656
|
+
};
|
|
2657
|
+
|
|
2658
|
+
// src/resources/competitors.ts
|
|
2659
|
+
var CompetitorsResource = class {
|
|
2660
|
+
constructor(client) {
|
|
2661
|
+
this.client = client;
|
|
2662
|
+
}
|
|
2663
|
+
client;
|
|
2664
|
+
/** `GET /v1/competitors` → every tracked brand. */
|
|
2665
|
+
async list() {
|
|
2666
|
+
const res = await this.client.request("GET", "/v1/competitors");
|
|
2667
|
+
return res.data;
|
|
2668
|
+
}
|
|
2669
|
+
/** `GET /v1/competitors/:id` → one brand with its latest scan (posts and cards) and its scan history. */
|
|
2670
|
+
get(id) {
|
|
2671
|
+
return this.client.request("GET", `/v1/competitors/${encodeURIComponent(id)}`);
|
|
2672
|
+
}
|
|
2673
|
+
/** `POST /v1/competitors` → track a brand. Accounts take handles or links. */
|
|
2674
|
+
create(input) {
|
|
2675
|
+
return this.client.request("POST", "/v1/competitors", { body: input });
|
|
2676
|
+
}
|
|
2677
|
+
/**
|
|
2678
|
+
* `PATCH /v1/competitors/:id` → change its accounts, platforms, name or schedule.
|
|
2679
|
+
* `accounts` replaces the whole set: pass every account to keep. Send
|
|
2680
|
+
* `schedule` only to change it (it restarts the brand's schedule). While a
|
|
2681
|
+
* scan of the brand runs, a change to its name, accounts, platforms or
|
|
2682
|
+
* `isOwn` is refused with `409 scan_running`.
|
|
2683
|
+
*/
|
|
2684
|
+
update(id, input) {
|
|
2685
|
+
return this.client.request("PATCH", `/v1/competitors/${encodeURIComponent(id)}`, { body: input });
|
|
2686
|
+
}
|
|
2687
|
+
/** `DELETE /v1/competitors/:id` → stop tracking it (its scans go too). */
|
|
2688
|
+
async delete(id) {
|
|
2689
|
+
await this.client.request("DELETE", `/v1/competitors/${encodeURIComponent(id)}`);
|
|
2690
|
+
}
|
|
2691
|
+
/** `GET /v1/competitors/cards` → every action card, most urgent first, with the posts they rest on. */
|
|
2692
|
+
cards() {
|
|
2693
|
+
return this.client.request("GET", "/v1/competitors/cards");
|
|
2694
|
+
}
|
|
2695
|
+
/**
|
|
2696
|
+
* `GET /v1/competitors/:id/lessons` → what works for a brand: per platform,
|
|
2697
|
+
* what its best posts share, measured on its own posts across every stored
|
|
2698
|
+
* scan, with the posts each lesson rests on (free). "What works for you" on
|
|
2699
|
+
* the brand marked as yours.
|
|
2700
|
+
*/
|
|
2701
|
+
lessons(id) {
|
|
2702
|
+
return this.client.request("GET", `/v1/competitors/${encodeURIComponent(id)}/lessons`);
|
|
2703
|
+
}
|
|
2704
|
+
/**
|
|
2705
|
+
* `GET /v1/competitors/actions` → the cards you marked "I did this", newest
|
|
2706
|
+
* first, each with how it went (`outcome`), and your track record per
|
|
2707
|
+
* family of advice (free). Each scan of your own brand judges the post that
|
|
2708
|
+
* came of a card once it is a few days old; the first verdict stays.
|
|
2709
|
+
*/
|
|
2710
|
+
tried() {
|
|
2711
|
+
return this.client.request("GET", "/v1/competitors/actions");
|
|
2712
|
+
}
|
|
2713
|
+
/**
|
|
2714
|
+
* `POST /v1/competitors/actions` → "I did this" on a card on your wall (its
|
|
2715
|
+
* `id` from `cards()`), optionally with the link to your post that came of
|
|
2716
|
+
* it. Only cards whose advice ends in a post of yours can be marked
|
|
2717
|
+
* (`400 not_measurable`). Marking a marked card returns its mark
|
|
2718
|
+
* (`created: false`).
|
|
2719
|
+
*/
|
|
2720
|
+
markDone(cardId, options = {}) {
|
|
2721
|
+
return this.client.request("POST", "/v1/competitors/actions", { body: { cardId, ...options.postUrl ? { postUrl: options.postUrl } : {} } });
|
|
2722
|
+
}
|
|
2723
|
+
/**
|
|
2724
|
+
* `PATCH /v1/competitors/actions/:id` → link the post that came of a marked
|
|
2725
|
+
* card (the post's full link; a short link is refused with `400
|
|
2726
|
+
* short_link`), or `null` to remove the link. Another post is judged afresh.
|
|
2727
|
+
*/
|
|
2728
|
+
linkPost(markId, postUrl) {
|
|
2729
|
+
return this.client.request("PATCH", `/v1/competitors/actions/${encodeURIComponent(markId)}`, { body: { postUrl } });
|
|
2730
|
+
}
|
|
2731
|
+
/** `PATCH /v1/competitors/actions/:id` with `seen: true` → you have seen its verdict (the app stops announcing it). */
|
|
2732
|
+
markSeen(markId) {
|
|
2733
|
+
return this.client.request("PATCH", `/v1/competitors/actions/${encodeURIComponent(markId)}`, { body: { seen: true } });
|
|
2734
|
+
}
|
|
2735
|
+
/** `DELETE /v1/competitors/actions/:id` → undo "I did this" (its verdict leaves your track record). */
|
|
2736
|
+
async unmark(markId) {
|
|
2737
|
+
await this.client.request("DELETE", `/v1/competitors/actions/${encodeURIComponent(markId)}`);
|
|
2738
|
+
}
|
|
2739
|
+
/** `POST /v1/competitor-discover` → a brand's accounts found from its website (free; guesses are marked). */
|
|
2740
|
+
discover(website) {
|
|
2741
|
+
return this.client.request("POST", "/v1/competitor-discover", { body: { website } });
|
|
2742
|
+
}
|
|
2743
|
+
/**
|
|
2744
|
+
* `POST /v1/competitor-scan` → scan a brand now. Answers with a job id;
|
|
2745
|
+
* poll `client.jobs.getStatus(jobId)`, then read `get(id)` or `cards()`.
|
|
2746
|
+
*/
|
|
2747
|
+
scan(id) {
|
|
2748
|
+
return this.client.request("POST", "/v1/competitor-scan", { body: { competitorId: id } });
|
|
2749
|
+
}
|
|
2750
|
+
};
|
|
2751
|
+
|
|
2591
2752
|
// src/resources/picker-catalogs.ts
|
|
2592
2753
|
var PickerCatalogsResource = class {
|
|
2593
2754
|
constructor(client) {
|
|
@@ -2624,7 +2785,8 @@ var CatalogsResource = class {
|
|
|
2624
2785
|
}
|
|
2625
2786
|
client;
|
|
2626
2787
|
/** Every catalog, projected & pack-composed (honors the deployment's
|
|
2627
|
-
* registered vendored packs). Cached publicly 5 min.
|
|
2788
|
+
* registered vendored packs). Cached publicly 5 min. `data` is absent
|
|
2789
|
+
* when the deployment registered no packs (`curated: false`). */
|
|
2628
2790
|
list(opts = {}) {
|
|
2629
2791
|
const qs = opts.detail ? `?detail=${opts.detail}` : "";
|
|
2630
2792
|
return this.client.request("GET", `/v1/catalogs${qs}`);
|
|
@@ -3615,12 +3777,21 @@ var EditResource = class {
|
|
|
3615
3777
|
* on nodaro.ai it runs directly.
|
|
3616
3778
|
*/
|
|
3617
3779
|
editPlan(input) {
|
|
3780
|
+
const planned = shared.resolveEditPlanSources(input.sources, {
|
|
3781
|
+
offsets: input.offsets,
|
|
3782
|
+
transcriptSourceId: input.transcriptSourceId
|
|
3783
|
+
});
|
|
3784
|
+
if (!planned.ok) {
|
|
3785
|
+
const message = planned.issues.map((issue) => shared.describeAudioSyncOffsetIssue(issue)).join("; ");
|
|
3786
|
+
return Promise.reject(new NodaroError(`editPlan: ${message}`, "edit_plan_sources", 400));
|
|
3787
|
+
}
|
|
3788
|
+
const transcript = planned.transcriptSourceId ? { ...input.transcript, sourceId: planned.transcriptSourceId } : input.transcript;
|
|
3618
3789
|
return this.client.request("POST", "/v1/edit-plan", {
|
|
3619
3790
|
body: {
|
|
3620
3791
|
mode: input.mode,
|
|
3621
3792
|
planTier: input.planTier,
|
|
3622
|
-
transcript
|
|
3623
|
-
sources:
|
|
3793
|
+
transcript,
|
|
3794
|
+
sources: planned.sources,
|
|
3624
3795
|
...input.silence !== void 0 ? { silence: input.silence } : {},
|
|
3625
3796
|
...input.instructions !== void 0 ? { instructions: input.instructions } : {},
|
|
3626
3797
|
...input.styleGuide !== void 0 ? { styleGuide: input.styleGuide } : {},
|
|
@@ -3632,6 +3803,37 @@ var EditResource = class {
|
|
|
3632
3803
|
}
|
|
3633
3804
|
});
|
|
3634
3805
|
}
|
|
3806
|
+
/**
|
|
3807
|
+
* Camera Switch (podcast B5): choose which camera shows each cut of `edl`
|
|
3808
|
+
* by who is speaking — the sound never changes. Cloud edition; a flat
|
|
3809
|
+
* price. The finished job's `output_data.json` is the switched EDL (feed it
|
|
3810
|
+
* to {@link applyEdl}) and `output_data.transcript` the transcript with
|
|
3811
|
+
* `speakerNames` applied. A transcript with no speaker labels rejects with
|
|
3812
|
+
* a {@link NodaroError} (`code: "no_speakers"`) before any request or charge.
|
|
3813
|
+
*/
|
|
3814
|
+
cameraSwitch(input) {
|
|
3815
|
+
if (shared.transcriptSpeakerLabels(input.transcript).length === 0) {
|
|
3816
|
+
return Promise.reject(new NodaroError(
|
|
3817
|
+
"cameraSwitch: the transcript has no speaker labels \u2014 transcribe with speaker detection on",
|
|
3818
|
+
"no_speakers",
|
|
3819
|
+
422
|
|
3820
|
+
));
|
|
3821
|
+
}
|
|
3822
|
+
return this.client.request("POST", "/v1/camera-switch", {
|
|
3823
|
+
body: {
|
|
3824
|
+
edl: input.edl,
|
|
3825
|
+
transcript: input.transcript,
|
|
3826
|
+
...input.speakerMap !== void 0 ? { speakerMap: input.speakerMap } : {},
|
|
3827
|
+
...input.speakerNames !== void 0 ? { speakerNames: input.speakerNames } : {},
|
|
3828
|
+
...input.minShotMs !== void 0 ? { minShotMs: input.minShotMs } : {},
|
|
3829
|
+
...input.leadMs !== void 0 ? { leadMs: input.leadMs } : {},
|
|
3830
|
+
...input.maxShotMs !== void 0 ? { maxShotMs: input.maxShotMs } : {},
|
|
3831
|
+
...input.wideEvery !== void 0 ? { wideEvery: input.wideEvery } : {},
|
|
3832
|
+
...input.layoutHints !== void 0 ? { layoutHints: input.layoutHints } : {},
|
|
3833
|
+
...input.workflowId !== void 0 ? { workflowId: input.workflowId } : {}
|
|
3834
|
+
}
|
|
3835
|
+
});
|
|
3836
|
+
}
|
|
3635
3837
|
/**
|
|
3636
3838
|
* Remap a transcript through an EDL — a PURE client-side transform (NO
|
|
3637
3839
|
* request). Returns a new transcript whose word (and segment) timings are on
|
|
@@ -3643,7 +3845,7 @@ var EditResource = class {
|
|
|
3643
3845
|
return shared.remapTranscriptThroughEdl(edl, transcript);
|
|
3644
3846
|
}
|
|
3645
3847
|
};
|
|
3646
|
-
var SDK_VERSION = "2.
|
|
3848
|
+
var SDK_VERSION = "2.18.0" ;
|
|
3647
3849
|
var CLIENT_HEADER = "X-Nodaro-Client";
|
|
3648
3850
|
var isBrowser = () => typeof window !== "undefined" && typeof window.document !== "undefined";
|
|
3649
3851
|
var NodaroClient = class _NodaroClient {
|
|
@@ -3689,6 +3891,8 @@ var NodaroClient = class _NodaroClient {
|
|
|
3689
3891
|
uploads;
|
|
3690
3892
|
library;
|
|
3691
3893
|
presets;
|
|
3894
|
+
savedPosts;
|
|
3895
|
+
competitors;
|
|
3692
3896
|
pickerCatalogs;
|
|
3693
3897
|
catalogs;
|
|
3694
3898
|
models;
|
|
@@ -3737,6 +3941,8 @@ var NodaroClient = class _NodaroClient {
|
|
|
3737
3941
|
this.uploads = new UploadsResource(this);
|
|
3738
3942
|
this.library = new LibraryResource(this);
|
|
3739
3943
|
this.presets = new PresetsResource(this);
|
|
3944
|
+
this.savedPosts = new SavedPostsResource(this);
|
|
3945
|
+
this.competitors = new CompetitorsResource(this);
|
|
3740
3946
|
this.pickerCatalogs = new PickerCatalogsResource(this);
|
|
3741
3947
|
this.catalogs = new CatalogsResource(this);
|
|
3742
3948
|
this.models = new ModelsResource(this);
|
|
@@ -3966,6 +4172,10 @@ Object.defineProperty(exports, "PROMPT_SUFFIX_KEY", {
|
|
|
3966
4172
|
enumerable: true,
|
|
3967
4173
|
get: function () { return shared.PROMPT_SUFFIX_KEY; }
|
|
3968
4174
|
});
|
|
4175
|
+
Object.defineProperty(exports, "RECAST_SEGMENT_PACKS", {
|
|
4176
|
+
enumerable: true,
|
|
4177
|
+
get: function () { return shared.RECAST_SEGMENT_PACKS; }
|
|
4178
|
+
});
|
|
3969
4179
|
Object.defineProperty(exports, "SURROUND_DIRECTIONS", {
|
|
3970
4180
|
enumerable: true,
|
|
3971
4181
|
get: function () { return shared.SURROUND_DIRECTIONS; }
|
|
@@ -4009,6 +4219,7 @@ exports.CallbackAuth = CallbackAuth;
|
|
|
4009
4219
|
exports.CatalogsResource = CatalogsResource;
|
|
4010
4220
|
exports.CharactersResource = CharactersResource;
|
|
4011
4221
|
exports.CommunityResource = CommunityResource;
|
|
4222
|
+
exports.CompetitorsResource = CompetitorsResource;
|
|
4012
4223
|
exports.CopilotResource = CopilotResource;
|
|
4013
4224
|
exports.CreaturesResource = CreaturesResource;
|
|
4014
4225
|
exports.CreditsResource = CreditsResource;
|
|
@@ -4044,6 +4255,7 @@ exports.RateLimitedError = RateLimitedError;
|
|
|
4044
4255
|
exports.RecastResource = RecastResource;
|
|
4045
4256
|
exports.ReduceResource = ReduceResource;
|
|
4046
4257
|
exports.SCENE3D_DELIVERY_ASSET_USAGE = SCENE3D_DELIVERY_ASSET_USAGE;
|
|
4258
|
+
exports.SavedPostsResource = SavedPostsResource;
|
|
4047
4259
|
exports.Scene3DResource = Scene3DResource;
|
|
4048
4260
|
exports.ShotsResource = ShotsResource;
|
|
4049
4261
|
exports.StaticTokenAuth = StaticTokenAuth;
|