@nodaro/sdk 2.17.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/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { SCENE3D_V2_LIMITS, remapTranscriptThroughEdl, WORKSPACE_HEADER } from '@nodaro/shared';
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, SURROUND_DIRECTIONS, USAGE_GROUP_BYS, WORKSPACE_HEADER, nodeStateMayCarryOutput, unwrapEditPlanOutput } from '@nodaro/shared';
1
+ import { SCENE3D_V2_LIMITS, resolveEditPlanSources, describeAudioSyncOffsetIssue, transcriptSpeakerLabels, remapTranscriptThroughEdl, WORKSPACE_HEADER } from '@nodaro/shared';
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';
5
5
 
@@ -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 pollJob(jobId, label, opts) {
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-7 sub-gate (`dialogue_recheck` / `silent_cut`) so the
1744
- * orchestrator resumes from the next sub-step. Requires `pipelines:approve`.
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) {
@@ -3616,12 +3777,21 @@ var EditResource = class {
3616
3777
  * on nodaro.ai it runs directly.
3617
3778
  */
3618
3779
  editPlan(input) {
3780
+ const planned = resolveEditPlanSources(input.sources, {
3781
+ offsets: input.offsets,
3782
+ transcriptSourceId: input.transcriptSourceId
3783
+ });
3784
+ if (!planned.ok) {
3785
+ const message = planned.issues.map((issue) => 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;
3619
3789
  return this.client.request("POST", "/v1/edit-plan", {
3620
3790
  body: {
3621
3791
  mode: input.mode,
3622
3792
  planTier: input.planTier,
3623
- transcript: input.transcript,
3624
- sources: input.sources,
3793
+ transcript,
3794
+ sources: planned.sources,
3625
3795
  ...input.silence !== void 0 ? { silence: input.silence } : {},
3626
3796
  ...input.instructions !== void 0 ? { instructions: input.instructions } : {},
3627
3797
  ...input.styleGuide !== void 0 ? { styleGuide: input.styleGuide } : {},
@@ -3633,6 +3803,37 @@ var EditResource = class {
3633
3803
  }
3634
3804
  });
3635
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 (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
+ }
3636
3837
  /**
3637
3838
  * Remap a transcript through an EDL — a PURE client-side transform (NO
3638
3839
  * request). Returns a new transcript whose word (and segment) timings are on
@@ -3644,7 +3845,7 @@ var EditResource = class {
3644
3845
  return remapTranscriptThroughEdl(edl, transcript);
3645
3846
  }
3646
3847
  };
3647
- var SDK_VERSION = "2.17.0" ;
3848
+ var SDK_VERSION = "2.18.0" ;
3648
3849
  var CLIENT_HEADER = "X-Nodaro-Client";
3649
3850
  var isBrowser = () => typeof window !== "undefined" && typeof window.document !== "undefined";
3650
3851
  var NodaroClient = class _NodaroClient {
@@ -3690,6 +3891,8 @@ var NodaroClient = class _NodaroClient {
3690
3891
  uploads;
3691
3892
  library;
3692
3893
  presets;
3894
+ savedPosts;
3895
+ competitors;
3693
3896
  pickerCatalogs;
3694
3897
  catalogs;
3695
3898
  models;
@@ -3738,6 +3941,8 @@ var NodaroClient = class _NodaroClient {
3738
3941
  this.uploads = new UploadsResource(this);
3739
3942
  this.library = new LibraryResource(this);
3740
3943
  this.presets = new PresetsResource(this);
3944
+ this.savedPosts = new SavedPostsResource(this);
3945
+ this.competitors = new CompetitorsResource(this);
3741
3946
  this.pickerCatalogs = new PickerCatalogsResource(this);
3742
3947
  this.catalogs = new CatalogsResource(this);
3743
3948
  this.models = new ModelsResource(this);
@@ -3907,6 +4112,6 @@ function supabaseAuth(supabase) {
3907
4112
  };
3908
4113
  }
3909
4114
 
3910
- export { AppsResource, AudioResource, CREATURE_ASSET_TYPES, CallbackAuth, CatalogsResource, CharactersResource, CommunityResource, 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, Scene3DResource, ShotsResource, StaticTokenAuth, StorageExceededError, StudioOpError, StudioPreviewAppliedError, StudioPreviewUnavailable, StudioProductionsResource, StudioResource, TemplatesResource, TutorialsResource, UnauthorizedError, UploadsResource, VideoProResource, VoicesResource, WorkflowConflictError, WorkflowsResource, WorkspacesResource, buildPersonSeedPrompt, createClient, isStudioGenerateEstimate, supabaseAuth, throwFromResponse };
4115
+ export { AppsResource, AudioResource, CREATURE_ASSET_TYPES, CallbackAuth, CatalogsResource, CharactersResource, 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 };
3911
4116
  //# sourceMappingURL=index.js.map
3912
4117
  //# sourceMappingURL=index.js.map