@nodaro/sdk 1.17.0 → 1.20.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,6 +1,7 @@
1
1
  import { buildPersonHints } from '@nodaro/prompts';
2
2
  export { PEOPLE, PERSON_DIMENSION_LABELS, PERSON_DIMENSION_ORDER, buildPersonHints } from '@nodaro/prompts';
3
- 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';
3
+ import { WORKSPACE_HEADER } from '@nodaro/shared';
4
+ 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, WORKSPACE_HEADER } from '@nodaro/shared';
4
5
 
5
6
  // src/errors.ts
6
7
  var NodaroError = class extends Error {
@@ -123,11 +124,50 @@ function throwFromResponse(status, body) {
123
124
  }
124
125
 
125
126
  // src/resources/workflows.ts
127
+ var WorkflowCollaboratorsResource = class {
128
+ constructor(client) {
129
+ this.client = client;
130
+ }
131
+ client;
132
+ /** List a workflow's collaborators (id, name, avatar, role — never email). */
133
+ list(workflowId) {
134
+ return this.client.request(
135
+ "GET",
136
+ `/v1/workflows/${encodeURIComponent(workflowId)}/collaborators`
137
+ );
138
+ }
139
+ /** Add a collaborator by `userId` OR `email` (exactly one), at the given role. */
140
+ add(workflowId, input) {
141
+ return this.client.request(
142
+ "POST",
143
+ `/v1/workflows/${encodeURIComponent(workflowId)}/collaborators`,
144
+ { body: input }
145
+ );
146
+ }
147
+ /** Change a collaborator's role. */
148
+ update(workflowId, userId, input) {
149
+ return this.client.request(
150
+ "PATCH",
151
+ `/v1/workflows/${encodeURIComponent(workflowId)}/collaborators/${encodeURIComponent(userId)}`,
152
+ { body: input }
153
+ );
154
+ }
155
+ /** Remove a collaborator — or yourself. Returns `{ success: true }`. */
156
+ remove(workflowId, userId) {
157
+ return this.client.request(
158
+ "DELETE",
159
+ `/v1/workflows/${encodeURIComponent(workflowId)}/collaborators/${encodeURIComponent(userId)}`
160
+ );
161
+ }
162
+ };
126
163
  var WorkflowsResource = class {
127
164
  constructor(client) {
128
165
  this.client = client;
166
+ this.collaborators = new WorkflowCollaboratorsResource(client);
129
167
  }
130
168
  client;
169
+ /** The people this workflow is shared with. See {@link WorkflowCollaboratorsResource}. */
170
+ collaborators;
131
171
  /** List workflows for a project. Returns metadata only — `nodes`/`edges` are not included. */
132
172
  list(params) {
133
173
  return this.client.request(
@@ -199,6 +239,9 @@ var WorkflowsResource = class {
199
239
  /**
200
240
  * Import a `WorkflowExport` bundle into the specified project.
201
241
  * Re-creates any bundled assets (characters, objects, locations) under your account.
242
+ * Media the bundle references on other hosts is copied onto this instance's
243
+ * storage where reachable; `importReport` says what was copied, what could
244
+ * not be reached, and what was skipped (and why).
202
245
  */
203
246
  import(input) {
204
247
  const { projectId, ...workflowJson } = input;
@@ -206,6 +249,37 @@ var WorkflowsResource = class {
206
249
  body: { projectId, workflow_json: workflowJson }
207
250
  });
208
251
  }
252
+ /**
253
+ * Set a workflow's visibility — `"private"` (creator + explicit collaborators)
254
+ * or `"workspace"` (everyone in its workspace). Only the creator or a workspace
255
+ * admin may change it; anyone else gets HTTP 403. Thin wrapper over `update()`:
256
+ * the visibility lever lives on `PATCH /v1/workflows/:id`.
257
+ */
258
+ setVisibility(id, visibility) {
259
+ return this.client.request("PATCH", `/v1/workflows/${encodeURIComponent(id)}`, {
260
+ body: { visibility }
261
+ });
262
+ }
263
+ /**
264
+ * Move a workflow to another project (`POST /v1/workflows/:id/move`); its folder
265
+ * is cleared. When the move takes the workflow out of a workspace, collaborator
266
+ * grants that came from that workspace are dropped and returned as
267
+ * `droppedCollaborators`.
268
+ */
269
+ move(id, params) {
270
+ return this.client.request("POST", `/v1/workflows/${encodeURIComponent(id)}/move`, {
271
+ body: params
272
+ });
273
+ }
274
+ /**
275
+ * Workflows other people shared with you (`GET /v1/workflows/shared-with-me`) —
276
+ * grants on work that is NOT in a workspace you belong to (workspace work already
277
+ * shows in that workspace's own lists). Each carries the `grantedRole` you hold.
278
+ * Empty when the organizations feature is off server-side.
279
+ */
280
+ sharedWithMe() {
281
+ return this.client.request("GET", "/v1/workflows/shared-with-me");
282
+ }
209
283
  };
210
284
 
211
285
  // src/resources/projects.ts
@@ -758,6 +832,8 @@ var LocationsResource = class {
758
832
  list(params = {}) {
759
833
  const query = {};
760
834
  if (params.archived) query.archived = "true";
835
+ if (params.limit !== void 0) query.limit = String(params.limit);
836
+ if (params.cursor) query.cursor = params.cursor;
761
837
  return this.client.request("GET", "/v1/locations", { query });
762
838
  }
763
839
  /**
@@ -935,6 +1011,8 @@ var ObjectsResource = class {
935
1011
  const query = {};
936
1012
  if (params.archived) query.archived = "true";
937
1013
  if (params.projectId) query.projectId = params.projectId;
1014
+ if (params.limit !== void 0) query.limit = String(params.limit);
1015
+ if (params.cursor) query.cursor = params.cursor;
938
1016
  return this.client.request("GET", "/v1/objects", { query });
939
1017
  }
940
1018
  /**
@@ -1119,6 +1197,8 @@ var CreaturesResource = class {
1119
1197
  const query = {};
1120
1198
  if (params.archived) query.archived = "true";
1121
1199
  if (params.projectId) query.projectId = params.projectId;
1200
+ if (params.limit !== void 0) query.limit = String(params.limit);
1201
+ if (params.cursor) query.cursor = params.cursor;
1122
1202
  return this.client.request("GET", "/v1/creatures", { query });
1123
1203
  }
1124
1204
  /**
@@ -1803,6 +1883,30 @@ var MediaResource = class {
1803
1883
  trimAudio(input) {
1804
1884
  return this.client.request("POST", "/v1/trim-audio", { body: input });
1805
1885
  }
1886
+ /**
1887
+ * Turn one still image + one audio track into an MP4
1888
+ * (`POST /v1/still-to-video`) — locally rendered (FFmpeg), no AI model,
1889
+ * zero credits. The output duration IS the audio's duration; there is no
1890
+ * duration field. Optional `motion` animates the still (zoom / pan /
1891
+ * ken-burns) at `intensity` 1–10. `fit: "contain"` letterboxes with
1892
+ * `padColor` instead of cropping. Poll `jobs.get(jobId)`.
1893
+ */
1894
+ stillToVideo(input) {
1895
+ return this.client.request("POST", "/v1/still-to-video", { body: input });
1896
+ }
1897
+ /**
1898
+ * Turn 2–100 images + one optional audio track into an MP4 slideshow
1899
+ * (`POST /v1/slideshow`) — locally rendered (FFmpeg), zero credits. With
1900
+ * audio, the output duration IS the audio's duration (equal split unless
1901
+ * `imageDurations` pins rows — null entries = auto; mismatched pinned sums
1902
+ * scale proportionally and the factor is disclosed in the job output).
1903
+ * Without audio: N × `perImageDuration`, silent output. Transitions
1904
+ * consume the outgoing slide, so totals stay exact. For a single image use
1905
+ * `stillToVideo`. Poll `jobs.get(jobId)`.
1906
+ */
1907
+ slideshow(input) {
1908
+ return this.client.request("POST", "/v1/slideshow", { body: input });
1909
+ }
1806
1910
  /**
1807
1911
  * Probe a social video's metadata (`POST /v1/video-metadata`) — duration,
1808
1912
  * dimensions, title, live status — WITHOUT downloading it. A direct read, not a
@@ -2023,6 +2127,20 @@ var PickerCatalogsResource = class {
2023
2127
  }
2024
2128
  };
2025
2129
 
2130
+ // src/resources/catalogs.ts
2131
+ var CatalogsResource = class {
2132
+ constructor(client) {
2133
+ this.client = client;
2134
+ }
2135
+ client;
2136
+ /** Every catalog, projected & pack-composed (honors the deployment's
2137
+ * registered vendored packs). Cached publicly 5 min. */
2138
+ list(opts = {}) {
2139
+ const qs = opts.detail ? `?detail=${opts.detail}` : "";
2140
+ return this.client.request("GET", `/v1/catalogs${qs}`);
2141
+ }
2142
+ };
2143
+
2026
2144
  // src/resources/models.ts
2027
2145
  var ModelsResource = class {
2028
2146
  constructor(client) {
@@ -2114,6 +2232,22 @@ var RecastResource = class {
2114
2232
  get(recastId) {
2115
2233
  return this.client.request("GET", `/v1/recast/${encodeURIComponent(recastId)}`);
2116
2234
  }
2235
+ /** Quote a revisioned Music replacement and/or complete desired mix. Free. */
2236
+ estimateRescore(recastId, input) {
2237
+ return this.client.request(
2238
+ "POST",
2239
+ `/v1/recast/${encodeURIComponent(recastId)}/estimate-rescore`,
2240
+ { body: input }
2241
+ );
2242
+ }
2243
+ /** Apply a quoted audio operation. Reuse its request id only for a transport retry. */
2244
+ rescore(recastId, input) {
2245
+ return this.client.request(
2246
+ "POST",
2247
+ `/v1/recast/${encodeURIComponent(recastId)}/rescore`,
2248
+ { body: input }
2249
+ );
2250
+ }
2117
2251
  /** Start rendering a `planned` run. Idempotent server-side. */
2118
2252
  start(recastId, opts = {}) {
2119
2253
  return this.client.request("POST", `/v1/recast/${encodeURIComponent(recastId)}/start`, {
@@ -2280,11 +2414,204 @@ var TutorialsResource = class {
2280
2414
  }
2281
2415
  };
2282
2416
 
2283
- // src/client.ts
2284
- var SDK_VERSION = "1.17.0" ;
2417
+ // src/resources/organizations.ts
2418
+ var OrganizationsResource = class {
2419
+ constructor(client) {
2420
+ this.client = client;
2421
+ }
2422
+ client;
2423
+ /** The organizations this account belongs to. */
2424
+ list() {
2425
+ return this.client.request("GET", "/v1/orgs");
2426
+ }
2427
+ get(id) {
2428
+ return this.client.request("GET", `/v1/orgs/${encodeURIComponent(id)}`);
2429
+ }
2430
+ /**
2431
+ * Create an organization. On instances that require it, `acceptTerms` must
2432
+ * be true or the server answers `terms_required` — the SDK does not decide
2433
+ * whether terms apply, because only the instance knows.
2434
+ *
2435
+ * A new organization may come back `pending`: some instances hold new
2436
+ * organizations for a platform admin to approve, and a pending one grants
2437
+ * nothing until it is active.
2438
+ */
2439
+ create(input) {
2440
+ return this.client.request("POST", "/v1/orgs", { body: input });
2441
+ }
2442
+ update(id, input) {
2443
+ return this.client.request("PATCH", `/v1/orgs/${encodeURIComponent(id)}`, { body: input });
2444
+ }
2445
+ /** Soft-delete. The organization stops granting context; nothing is destroyed. */
2446
+ delete(id) {
2447
+ return this.client.request("DELETE", `/v1/orgs/${encodeURIComponent(id)}`);
2448
+ }
2449
+ /** Hand the organization to another member. The caller becomes an admin. */
2450
+ transferOwnership(id, userId) {
2451
+ return this.client.request("POST", `/v1/orgs/${encodeURIComponent(id)}/transfer-ownership`, {
2452
+ body: { userId }
2453
+ });
2454
+ }
2455
+ /** Leave. An owner cannot — transfer ownership first (`owner_cannot_leave`). */
2456
+ leave(id) {
2457
+ return this.client.request("POST", `/v1/orgs/${encodeURIComponent(id)}/leave`);
2458
+ }
2459
+ // -- members --------------------------------------------------------------
2460
+ listMembers(orgId, opts = {}) {
2461
+ return this.client.request("GET", `/v1/orgs/${encodeURIComponent(orgId)}/members`, { query: { ...opts } });
2462
+ }
2463
+ updateMember(orgId, userId, input) {
2464
+ return this.client.request(
2465
+ "PATCH",
2466
+ `/v1/orgs/${encodeURIComponent(orgId)}/members/${encodeURIComponent(userId)}`,
2467
+ { body: input }
2468
+ );
2469
+ }
2470
+ removeMember(orgId, userId) {
2471
+ return this.client.request(
2472
+ "DELETE",
2473
+ `/v1/orgs/${encodeURIComponent(orgId)}/members/${encodeURIComponent(userId)}`
2474
+ );
2475
+ }
2476
+ // -- invitations ----------------------------------------------------------
2477
+ /**
2478
+ * Invite by email. Returns ONE ROW PER ADDRESS, and a row whose `status` is
2479
+ * not `sent` carries a `link` instead.
2480
+ *
2481
+ * Surface that link. An install with no mail provider — every fresh
2482
+ * self-host — delivers nothing, and an integration that reports "invited"
2483
+ * without showing the link creates invitations nobody can ever reach.
2484
+ */
2485
+ invite(orgId, input) {
2486
+ return this.client.request("POST", `/v1/orgs/${encodeURIComponent(orgId)}/invitations`, { body: input });
2487
+ }
2488
+ listInvitations(orgId, opts = {}) {
2489
+ return this.client.request("GET", `/v1/orgs/${encodeURIComponent(orgId)}/invitations`, {
2490
+ query: { ...opts }
2491
+ });
2492
+ }
2493
+ revokeInvitation(id) {
2494
+ return this.client.request("DELETE", `/v1/invitations/${encodeURIComponent(id)}`);
2495
+ }
2496
+ resendInvitation(id) {
2497
+ return this.client.request("POST", `/v1/invitations/${encodeURIComponent(id)}/resend`);
2498
+ }
2499
+ /**
2500
+ * What an invitee sees before signing in — the one organization read that
2501
+ * needs no token, so it works while the recipient is still signed out.
2502
+ */
2503
+ previewInvitation(token) {
2504
+ return this.client.request("GET", `/v1/invitations/by-token/${encodeURIComponent(token)}`);
2505
+ }
2506
+ /** Accept. Requires an authenticated caller whose email matches the invite. */
2507
+ acceptInvitation(token) {
2508
+ return this.client.request("POST", `/v1/invitations/${encodeURIComponent(token)}/accept`);
2509
+ }
2510
+ // -- audit ----------------------------------------------------------------
2511
+ /**
2512
+ * The organization's audit log, newest first. Owner and admins only, and
2513
+ * readable while the organization is suspended — the record of what
2514
+ * happened is exactly what someone needs when things have gone wrong.
2515
+ */
2516
+ audit(orgId, opts = {}) {
2517
+ return this.client.request("GET", `/v1/orgs/${encodeURIComponent(orgId)}/audit`, { query: { ...opts } });
2518
+ }
2519
+ };
2520
+
2521
+ // src/resources/workspaces.ts
2522
+ var WorkspacesResource = class {
2523
+ constructor(client) {
2524
+ this.client = client;
2525
+ }
2526
+ client;
2527
+ /**
2528
+ * Every workspace this account belongs to, across all its organizations.
2529
+ *
2530
+ * An identity read: a stale workspace binding cannot lock a caller out of
2531
+ * it, which is what makes it safe to call when a selection has gone bad.
2532
+ *
2533
+ * Byte-for-byte the list `GET /v1/me` carries, so a client reconciles
2534
+ * against one truth rather than two. That is why these are SUMMARIES —
2535
+ * enough to render a switcher, not the full view; use {@link get} for that.
2536
+ */
2537
+ list() {
2538
+ return this.client.request("GET", "/v1/workspaces");
2539
+ }
2540
+ listForOrg(orgId, opts = {}) {
2541
+ return this.client.request("GET", `/v1/orgs/${encodeURIComponent(orgId)}/workspaces`, {
2542
+ query: { includeArchived: opts.includeArchived }
2543
+ });
2544
+ }
2545
+ get(id) {
2546
+ return this.client.request("GET", `/v1/workspaces/${encodeURIComponent(id)}`);
2547
+ }
2548
+ create(orgId, input) {
2549
+ return this.client.request("POST", `/v1/orgs/${encodeURIComponent(orgId)}/workspaces`, { body: input });
2550
+ }
2551
+ update(id, input) {
2552
+ return this.client.request("PATCH", `/v1/workspaces/${encodeURIComponent(id)}`, { body: input });
2553
+ }
2554
+ /**
2555
+ * Archive or restore. Archiving is REVERSIBLE and destroys nothing: the
2556
+ * workspace stops accepting new work and stays fully readable, which is
2557
+ * what a finished class term needs and a delete would not survive.
2558
+ */
2559
+ setArchived(id, archived) {
2560
+ return this.client.request(
2561
+ "POST",
2562
+ `/v1/workspaces/${encodeURIComponent(id)}/${archived ? "archive" : "unarchive"}`
2563
+ );
2564
+ }
2565
+ // -- members --------------------------------------------------------------
2566
+ listMembers(id, opts = {}) {
2567
+ return this.client.request("GET", `/v1/workspaces/${encodeURIComponent(id)}/members`, {
2568
+ query: { ...opts }
2569
+ });
2570
+ }
2571
+ /** Add someone who is ALREADY in the organization. To bring in a new person, invite them. */
2572
+ addMember(id, input) {
2573
+ return this.client.request("POST", `/v1/workspaces/${encodeURIComponent(id)}/members`, { body: input });
2574
+ }
2575
+ updateMember(id, userId, input) {
2576
+ return this.client.request(
2577
+ "PATCH",
2578
+ `/v1/workspaces/${encodeURIComponent(id)}/members/${encodeURIComponent(userId)}`,
2579
+ { body: input }
2580
+ );
2581
+ }
2582
+ removeMember(id, userId) {
2583
+ return this.client.request(
2584
+ "DELETE",
2585
+ `/v1/workspaces/${encodeURIComponent(id)}/members/${encodeURIComponent(userId)}`
2586
+ );
2587
+ }
2588
+ // -- join codes -----------------------------------------------------------
2589
+ /** The workspace's join code, or `null` if none has been created. Admins only. */
2590
+ getJoinCode(id) {
2591
+ return this.client.request("GET", `/v1/workspaces/${encodeURIComponent(id)}/join-code`);
2592
+ }
2593
+ /**
2594
+ * Rotate, enable or disable the code. Rotating invalidates the old one
2595
+ * immediately — that is the point of it, and anyone still holding a link
2596
+ * with the old code will be refused.
2597
+ */
2598
+ actOnJoinCode(id, action) {
2599
+ return this.client.request("POST", `/v1/workspaces/${encodeURIComponent(id)}/join-code`, {
2600
+ body: { action }
2601
+ });
2602
+ }
2603
+ /**
2604
+ * Join by code. Another way IN, so a stale workspace binding must not block
2605
+ * it — the server treats this as an identity route for that reason.
2606
+ */
2607
+ join(code) {
2608
+ return this.client.request("POST", "/v1/workspaces/join", { body: { code } });
2609
+ }
2610
+ };
2611
+ var SDK_VERSION = "1.20.0" ;
2285
2612
  var CLIENT_HEADER = "X-Nodaro-Client";
2286
2613
  var isBrowser = () => typeof window !== "undefined" && typeof window.document !== "undefined";
2287
- var NodaroClient = class {
2614
+ var NodaroClient = class _NodaroClient {
2288
2615
  baseUrl;
2289
2616
  auth;
2290
2617
  timeoutMs;
@@ -2326,18 +2653,24 @@ var NodaroClient = class {
2326
2653
  library;
2327
2654
  presets;
2328
2655
  pickerCatalogs;
2656
+ catalogs;
2329
2657
  models;
2330
2658
  shots;
2331
2659
  recast;
2332
2660
  community;
2333
2661
  templates;
2334
2662
  tutorials;
2663
+ organizations;
2664
+ workspaces;
2665
+ /** The workspace this client acts in; undefined = the personal space. */
2666
+ workspaceId;
2335
2667
  constructor(opts) {
2336
2668
  this.baseUrl = opts.baseUrl.replace(/\/$/, "");
2337
2669
  this.auth = opts.auth;
2338
2670
  this.fetchOverride = opts.fetch;
2339
2671
  this.timeoutMs = opts.timeoutMs ?? 6e4;
2340
2672
  this.clientLabel = opts.clientLabel ?? `sdk/${SDK_VERSION}`;
2673
+ this.workspaceId = opts.workspaceId;
2341
2674
  this.sendClientHeader = opts.clientLabel !== void 0 || !isBrowser();
2342
2675
  this.workflows = new WorkflowsResource(this);
2343
2676
  this.projects = new ProjectsResource(this);
@@ -2363,12 +2696,36 @@ var NodaroClient = class {
2363
2696
  this.library = new LibraryResource(this);
2364
2697
  this.presets = new PresetsResource(this);
2365
2698
  this.pickerCatalogs = new PickerCatalogsResource(this);
2699
+ this.catalogs = new CatalogsResource(this);
2366
2700
  this.models = new ModelsResource(this);
2367
2701
  this.shots = new ShotsResource(this);
2368
2702
  this.recast = new RecastResource(this);
2369
2703
  this.community = new CommunityResource(this);
2370
2704
  this.templates = new TemplatesResource(this);
2371
2705
  this.tutorials = new TutorialsResource(this);
2706
+ this.organizations = new OrganizationsResource(this);
2707
+ this.workspaces = new WorkspacesResource(this);
2708
+ }
2709
+ /**
2710
+ * A client that acts in `workspaceId`, sharing this one's auth and config.
2711
+ *
2712
+ * A NEW client rather than a setter, deliberately. A mutable selection is
2713
+ * the bug this whole axis exists to prevent: two concurrent operations
2714
+ * against one client would race over which workspace they were in, and the
2715
+ * loser would create work in the wrong place with nothing failing. A
2716
+ * per-workspace client cannot be raced.
2717
+ *
2718
+ * Pass `null` for the personal space.
2719
+ */
2720
+ withWorkspace(workspaceId) {
2721
+ return new _NodaroClient({
2722
+ baseUrl: this.baseUrl,
2723
+ auth: this.auth,
2724
+ timeoutMs: this.timeoutMs,
2725
+ ...this.fetchOverride ? { fetch: this.fetchOverride } : {},
2726
+ ...this.sendClientHeader ? { clientLabel: this.clientLabel } : {},
2727
+ ...workspaceId ? { workspaceId } : {}
2728
+ });
2372
2729
  }
2373
2730
  async request(method, path, options = {}) {
2374
2731
  const url = this.buildUrl(path, options.query);
@@ -2377,6 +2734,9 @@ var NodaroClient = class {
2377
2734
  const headers = {
2378
2735
  ...isFormData ? {} : { "Content-Type": "application/json" },
2379
2736
  ...this.sendClientHeader ? { [CLIENT_HEADER]: this.clientLabel } : {},
2737
+ // Before per-request headers: a resource that needs to reach outside
2738
+ // this client's workspace says so explicitly and wins.
2739
+ ...this.workspaceId ? { [WORKSPACE_HEADER]: this.workspaceId } : {},
2380
2740
  ...options.headers ?? {}
2381
2741
  };
2382
2742
  if (token) headers["Authorization"] = `Bearer ${token}`;
@@ -2410,6 +2770,14 @@ var NodaroClient = class {
2410
2770
  * `GET /v1/me` → the authenticated user's identity (see {@link UserIdentity}).
2411
2771
  * Unwraps the `{ data }` envelope. Throws `UnauthorizedError` (401) when the
2412
2772
  * token is missing/invalid, and the SDK's other typed errors as usual.
2773
+ *
2774
+ * On an instance with organizations it also carries what the caller belongs
2775
+ * to. THREE states, and collapsing them is wrong in a way users feel: the
2776
+ * organization fields ABSENT means this instance has no organizations at
2777
+ * all; present and empty means the account belongs to none; and
2778
+ * `organizationsUnavailable` means the lookup failed — keep whatever
2779
+ * selection you already had rather than concluding the person was removed
2780
+ * from everything.
2413
2781
  */
2414
2782
  async me() {
2415
2783
  const res = await this.request("GET", "/v1/me");
@@ -2461,6 +2829,6 @@ function supabaseAuth(supabase) {
2461
2829
  };
2462
2830
  }
2463
2831
 
2464
- export { AppsResource, AudioResource, CREATURE_ASSET_TYPES, CallbackAuth, CharactersResource, CommunityResource, CreaturesResource, CreditsResource, DeveloperAppsResource, ExecutionsResource, ForbiddenError, InsufficientCreditsError, JobAbortedError, JobFailedError, JobTimeoutError, JobsResource, LibraryResource, LocationsResource, MediaResource, ModelsResource, NodaroClient, NodaroError, NodesResource, NotFoundError, OAuthResource, ObjectsResource, PickerCatalogsResource, PipelinesResource, PresetsResource, ProjectsResource, PromptHelperResource, RateLimitedError, RecastResource, ReduceResource, ShotsResource, StaticTokenAuth, StorageExceededError, TemplatesResource, TutorialsResource, UnauthorizedError, UploadsResource, VideoProResource, VoicesResource, WorkflowConflictError, WorkflowsResource, buildPersonSeedPrompt, createClient, supabaseAuth, throwFromResponse };
2832
+ export { AppsResource, AudioResource, CREATURE_ASSET_TYPES, CallbackAuth, CatalogsResource, CharactersResource, CommunityResource, CreaturesResource, CreditsResource, DeveloperAppsResource, ExecutionsResource, ForbiddenError, InsufficientCreditsError, JobAbortedError, JobFailedError, JobTimeoutError, JobsResource, LibraryResource, LocationsResource, MediaResource, ModelsResource, NodaroClient, NodaroError, NodesResource, NotFoundError, OAuthResource, ObjectsResource, OrganizationsResource, PickerCatalogsResource, PipelinesResource, PresetsResource, ProjectsResource, PromptHelperResource, RateLimitedError, RecastResource, ReduceResource, ShotsResource, StaticTokenAuth, StorageExceededError, TemplatesResource, TutorialsResource, UnauthorizedError, UploadsResource, VideoProResource, VoicesResource, WorkflowConflictError, WorkflowsResource, WorkspacesResource, buildPersonSeedPrompt, createClient, supabaseAuth, throwFromResponse };
2465
2833
  //# sourceMappingURL=index.js.map
2466
2834
  //# sourceMappingURL=index.js.map