@nodaro/sdk 2.27.0 → 2.29.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 -2
- package/dist/index.cjs +665 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7042 -5651
- package/dist/index.d.ts +7042 -5651
- package/dist/index.js +654 -29
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -188,36 +188,57 @@ var JobHeldError = class extends NodaroError {
|
|
|
188
188
|
}
|
|
189
189
|
jobId;
|
|
190
190
|
};
|
|
191
|
+
var finite = (v) => typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
192
|
+
var BARE_CODE = /^[a-z][a-z0-9_]*$/;
|
|
193
|
+
var nonEmpty = (v) => typeof v === "string" && v.length > 0 ? v : void 0;
|
|
194
|
+
function readErrorBody(status, body) {
|
|
195
|
+
const raw = body.error;
|
|
196
|
+
const envelope = raw && typeof raw === "object" ? raw : {};
|
|
197
|
+
const bare = typeof raw === "string" ? raw : void 0;
|
|
198
|
+
const bareCode = bare !== void 0 && BARE_CODE.test(bare) ? bare : void 0;
|
|
199
|
+
const bareSentence = bare !== void 0 && bareCode === void 0 && /\s/.test(bare.trim()) ? bare : void 0;
|
|
200
|
+
const code = nonEmpty(envelope.code) ?? bareCode ?? (status === 400 && raw === void 0 && Array.isArray(body.issues) ? "validation_error" : void 0);
|
|
201
|
+
const outside = status >= 500 ? void 0 : nonEmpty(body.message) ?? nonEmpty(body.error_description) ?? bareSentence;
|
|
202
|
+
const message = nonEmpty(envelope.message) ?? outside;
|
|
203
|
+
return { code, message, envelope };
|
|
204
|
+
}
|
|
191
205
|
function throwFromResponse(status, body) {
|
|
192
|
-
const
|
|
193
|
-
const
|
|
194
|
-
|
|
206
|
+
const parsed = body && typeof body === "object" ? body : {};
|
|
207
|
+
const read = readErrorBody(status, parsed);
|
|
208
|
+
const envelope = read.envelope;
|
|
209
|
+
const code = read.code ?? "internal_error";
|
|
210
|
+
const message = read.message ?? (read.code ? read.code : "Request failed");
|
|
211
|
+
if (status === 401) throw new UnauthorizedError(read.message);
|
|
195
212
|
if (status === 409 && (code === "workflow_conflict" || code === "production_busy")) {
|
|
196
213
|
throw new WorkflowConflictError(
|
|
197
|
-
message,
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
214
|
+
read.message,
|
|
215
|
+
envelope.currentUpdatedAt,
|
|
216
|
+
envelope.currentVersion,
|
|
217
|
+
envelope.currentRecord,
|
|
201
218
|
code
|
|
202
219
|
);
|
|
203
220
|
}
|
|
204
|
-
if (status >= 400 && status < 500 && typeof
|
|
205
|
-
throw new StudioOpError(message, code, status,
|
|
221
|
+
if (status >= 400 && status < 500 && typeof envelope.opIndex === "number") {
|
|
222
|
+
throw new StudioOpError(message, code, status, envelope.opIndex);
|
|
206
223
|
}
|
|
207
|
-
if (status === 409 && CONTINUATION_REFUSAL_CODES.has(code) && typeof
|
|
208
|
-
throw new ContinuationRefusedError(message, code,
|
|
224
|
+
if (status === 409 && CONTINUATION_REFUSAL_CODES.has(code) && typeof parsed.jobId === "string") {
|
|
225
|
+
throw new ContinuationRefusedError(message, code, parsed.jobId);
|
|
209
226
|
}
|
|
210
|
-
if (status === 422 && code === "job_blocked") throw new JobBlockedError(message);
|
|
227
|
+
if (status === 422 && code === "job_blocked") throw new JobBlockedError(read.message);
|
|
211
228
|
if (status === 403 && code === "insufficient_scope") {
|
|
212
|
-
throw new ForbiddenError(message,
|
|
229
|
+
throw new ForbiddenError(read.message, envelope.missingScope);
|
|
213
230
|
}
|
|
214
|
-
if (status === 403) throw new ForbiddenError(message);
|
|
215
|
-
if (status === 404) throw new NotFoundError(
|
|
216
|
-
if (status === 429) throw new RateLimitedError(message);
|
|
231
|
+
if (status === 403) throw new ForbiddenError(read.message);
|
|
232
|
+
if (status === 404) throw new NotFoundError(read.message);
|
|
233
|
+
if (status === 429) throw new RateLimitedError(read.message);
|
|
217
234
|
if (status === 402) {
|
|
218
|
-
throw new InsufficientCreditsError(
|
|
235
|
+
throw new InsufficientCreditsError(
|
|
236
|
+
read.message,
|
|
237
|
+
finite(envelope.required) ?? finite(parsed.required),
|
|
238
|
+
finite(envelope.available) ?? finite(parsed.balance)
|
|
239
|
+
);
|
|
219
240
|
}
|
|
220
|
-
if (status === 413) throw new StorageExceededError(message,
|
|
241
|
+
if (status === 413) throw new StorageExceededError(read.message, envelope.limitBytes);
|
|
221
242
|
throw new NodaroError(message, code, status);
|
|
222
243
|
}
|
|
223
244
|
|
|
@@ -447,7 +468,70 @@ var ProjectsResource = class {
|
|
|
447
468
|
}
|
|
448
469
|
};
|
|
449
470
|
|
|
471
|
+
// src/resources/sessions.ts
|
|
472
|
+
var SessionsResource = class {
|
|
473
|
+
constructor(client) {
|
|
474
|
+
this.client = client;
|
|
475
|
+
}
|
|
476
|
+
client;
|
|
477
|
+
/**
|
|
478
|
+
* Create a session. Send its `id` as `sessionId` on a generation request
|
|
479
|
+
* (`nodes.run("generate-image", { sessionId, … })`, video, speech, music) and
|
|
480
|
+
* the job is born in it.
|
|
481
|
+
*/
|
|
482
|
+
create(input) {
|
|
483
|
+
return this.client.request("POST", "/v1/sessions", { body: input });
|
|
484
|
+
}
|
|
485
|
+
/** Your sessions, newest first. */
|
|
486
|
+
list(params = {}) {
|
|
487
|
+
const query = {};
|
|
488
|
+
if (params.projectId) query.projectId = params.projectId;
|
|
489
|
+
if (params.tool) query.tool = params.tool;
|
|
490
|
+
if (params.includeArchived) query.includeArchived = "true";
|
|
491
|
+
if (params.limit !== void 0) query.limit = String(params.limit);
|
|
492
|
+
if (params.cursor) query.cursor = params.cursor;
|
|
493
|
+
return this.client.request("GET", "/v1/sessions", { query });
|
|
494
|
+
}
|
|
495
|
+
get(id) {
|
|
496
|
+
return this.client.request("GET", `/v1/sessions/${encodeURIComponent(id)}`);
|
|
497
|
+
}
|
|
498
|
+
/** Rename or archive a session. Its project cannot change. */
|
|
499
|
+
update(id, input) {
|
|
500
|
+
return this.client.request("PATCH", `/v1/sessions/${encodeURIComponent(id)}`, { body: input });
|
|
501
|
+
}
|
|
502
|
+
/** Delete a session and its links. Its jobs are kept, and stay in every other session holding them. */
|
|
503
|
+
delete(id) {
|
|
504
|
+
return this.client.request("DELETE", `/v1/sessions/${encodeURIComponent(id)}`);
|
|
505
|
+
}
|
|
506
|
+
/** The session's items, born-in and imported, newest first. */
|
|
507
|
+
items(id, params = {}) {
|
|
508
|
+
const query = {};
|
|
509
|
+
if (params.limit !== void 0) query.limit = String(params.limit);
|
|
510
|
+
if (params.cursor) query.cursor = params.cursor;
|
|
511
|
+
return this.client.request("GET", `/v1/sessions/${encodeURIComponent(id)}/items`, { query });
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* Import some of your own jobs into a session — a link, not a copy (up to 100
|
|
515
|
+
* a call). All-or-nothing: if any id is not one of your jobs, nothing is
|
|
516
|
+
* imported and the call fails with 404. Items already there are left as they are.
|
|
517
|
+
*/
|
|
518
|
+
importItems(id, input) {
|
|
519
|
+
return this.client.request("POST", `/v1/sessions/${encodeURIComponent(id)}/items`, { body: input });
|
|
520
|
+
}
|
|
521
|
+
/** Remove one item from a session. Only the link goes: the job, and every other session holding it, stay. */
|
|
522
|
+
removeItem(id, jobId) {
|
|
523
|
+
return this.client.request(
|
|
524
|
+
"DELETE",
|
|
525
|
+
`/v1/sessions/${encodeURIComponent(id)}/items/${encodeURIComponent(jobId)}`
|
|
526
|
+
);
|
|
527
|
+
}
|
|
528
|
+
};
|
|
529
|
+
|
|
450
530
|
// src/resources/jobs.ts
|
|
531
|
+
function listParam(value) {
|
|
532
|
+
if (value === void 0) return void 0;
|
|
533
|
+
return typeof value === "string" ? value : value.join(",");
|
|
534
|
+
}
|
|
451
535
|
var JobsResource = class {
|
|
452
536
|
constructor(client) {
|
|
453
537
|
this.client = client;
|
|
@@ -461,9 +545,26 @@ var JobsResource = class {
|
|
|
461
545
|
* Your jobs, newest first (`GET /v1/jobs`), cursor-paginated. `type` and
|
|
462
546
|
* `origin` filter on the job's own `input_data`, which every job carries —
|
|
463
547
|
* a client app lists its runs with `{ type: "llm-structured", origin: "studio" }`.
|
|
548
|
+
* `status` and `type` take one value or a list; `favorited` and `rating`
|
|
549
|
+
* filter on your own marks. Every filter combines with AND, and each job
|
|
550
|
+
* carries `favorited` and `rating`.
|
|
464
551
|
*/
|
|
465
552
|
list(params = {}) {
|
|
466
|
-
|
|
553
|
+
const { status, type, ...rest } = params;
|
|
554
|
+
return this.client.request("GET", "/v1/jobs", {
|
|
555
|
+
query: { ...rest, status: listParam(status), type: listParam(type) }
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
* Rate one of your jobs `"good"` or `"bad"`, or clear the rating with
|
|
560
|
+
* `null` (`PUT /v1/jobs/:id/rating`). Only the job's owner rates it — anyone
|
|
561
|
+
* else's job is a `NotFoundError`. The rating reads back as `Job.rating`
|
|
562
|
+
* and filters {@link list}. OAuth apps need the `assets:write` scope.
|
|
563
|
+
*/
|
|
564
|
+
rate(id, rating) {
|
|
565
|
+
return this.client.request("PUT", `/v1/jobs/${encodeURIComponent(id)}/rating`, {
|
|
566
|
+
body: { rating }
|
|
567
|
+
});
|
|
467
568
|
}
|
|
468
569
|
/**
|
|
469
570
|
* Get the lean status of a single job (poll-loop friendly).
|
|
@@ -590,6 +691,26 @@ function extractJobId(result, label) {
|
|
|
590
691
|
}
|
|
591
692
|
throw new JobFailedError(`${label} did not return a jobId`, "");
|
|
592
693
|
}
|
|
694
|
+
function isImageBatchRequest(type, params) {
|
|
695
|
+
if (type !== "generate-image") return false;
|
|
696
|
+
return typeof params.count === "number" && params.count > 1 || Array.isArray(params.models);
|
|
697
|
+
}
|
|
698
|
+
function batchJobIds(result) {
|
|
699
|
+
const ids = result?.jobIds;
|
|
700
|
+
return Array.isArray(ids) && ids.every((id) => typeof id === "string") ? ids : null;
|
|
701
|
+
}
|
|
702
|
+
function batchRefusal(detail) {
|
|
703
|
+
return new NodaroError(
|
|
704
|
+
`${detail}: this waits for one job \u2014 use nodes.runBatchAndWait() for a batch (count above 1, or models).`,
|
|
705
|
+
"batch_requires_run_batch_and_wait",
|
|
706
|
+
0
|
|
707
|
+
);
|
|
708
|
+
}
|
|
709
|
+
function batchResultOf(result) {
|
|
710
|
+
const r = result;
|
|
711
|
+
if (!r || typeof r.batchId !== "string" || !batchJobIds(result) || !Array.isArray(r.groups)) return null;
|
|
712
|
+
return r;
|
|
713
|
+
}
|
|
593
714
|
var NodesResource = class {
|
|
594
715
|
constructor(client) {
|
|
595
716
|
this.client = client;
|
|
@@ -622,10 +743,55 @@ var NodesResource = class {
|
|
|
622
743
|
}
|
|
623
744
|
async runAndWait(type, params = {}, opts = {}) {
|
|
624
745
|
if (opts.signal?.aborted) throw new JobAbortedError();
|
|
746
|
+
if (isImageBatchRequest(type, params)) throw batchRefusal(`${type} with count above 1 or models makes several jobs`);
|
|
625
747
|
const result = await this.run(type, params, { idempotencyKey: opts.idempotencyKey });
|
|
748
|
+
const ids = batchJobIds(result);
|
|
749
|
+
if (ids && ids.length > 1) throw batchRefusal(`${type} started ${ids.length} jobs (${ids.join(", ")}), which keep running`);
|
|
626
750
|
const jobId = extractJobId(result, type);
|
|
627
751
|
return this.pollJob(jobId, type, opts);
|
|
628
752
|
}
|
|
753
|
+
/**
|
|
754
|
+
* Run a generate-image BATCH — `count` above 1 and/or `models` — to the end:
|
|
755
|
+
* submit it once ({@link run}, with your `idempotencyKey` if any), then wait
|
|
756
|
+
* for every job at once, each the way {@link runAndWait} waits.
|
|
757
|
+
*
|
|
758
|
+
* Resolves `{ batch, results }`: the submit's answer
|
|
759
|
+
* ({@link GenerateImageBatchResult} — ids, groups by model, credits) and one
|
|
760
|
+
* {@link BatchJobOutcome} per job, in `batch.jobIds` order — its output, or the
|
|
761
|
+
* typed error that ended the wait for it. One image failing never discards the
|
|
762
|
+
* others. Rejects only before any job exists (the submit's own errors, e.g.
|
|
763
|
+
* `InsufficientCreditsError` with the batch total as `required`), and on
|
|
764
|
+
* `signal` ({@link JobAbortedError}; `cancelOnAbort` cancels every job).
|
|
765
|
+
*
|
|
766
|
+
* A request for one image is refused before anything is sent (code
|
|
767
|
+
* `not_a_batch`) — wait for it with {@link runAndWait}.
|
|
768
|
+
*/
|
|
769
|
+
async runBatchAndWait(type, params, opts = {}) {
|
|
770
|
+
if (opts.signal?.aborted) throw new JobAbortedError();
|
|
771
|
+
if (!isImageBatchRequest(type, params)) {
|
|
772
|
+
throw new NodaroError(
|
|
773
|
+
"runBatchAndWait waits for a batch \u2014 count above 1, or models; wait for one image with nodes.runAndWait().",
|
|
774
|
+
"not_a_batch",
|
|
775
|
+
0
|
|
776
|
+
);
|
|
777
|
+
}
|
|
778
|
+
const result = await this.run(type, params, { idempotencyKey: opts.idempotencyKey });
|
|
779
|
+
const batch = batchResultOf(result);
|
|
780
|
+
if (!batch) throw new JobFailedError(`${type} did not answer with a batch`, "");
|
|
781
|
+
const modelOf = new Map(batch.groups.flatMap((group) => group.jobIds.map((id) => [id, group.model])));
|
|
782
|
+
const results = await Promise.all(
|
|
783
|
+
batch.jobIds.map(async (jobId) => {
|
|
784
|
+
const model = modelOf.get(jobId) ?? "";
|
|
785
|
+
try {
|
|
786
|
+
return { jobId, model, status: "completed", output: await this.pollJob(jobId, type, opts) };
|
|
787
|
+
} catch (err) {
|
|
788
|
+
if (err instanceof JobAbortedError || !(err instanceof NodaroError)) throw err;
|
|
789
|
+
return { jobId, model, status: "error", error: err };
|
|
790
|
+
}
|
|
791
|
+
})
|
|
792
|
+
);
|
|
793
|
+
return { batch, results };
|
|
794
|
+
}
|
|
629
795
|
/**
|
|
630
796
|
* Fan out N async runs of the same node `type` to completion concurrently —
|
|
631
797
|
* the candidate-grid path (generate N stills/clips in parallel). Each runs
|
|
@@ -641,6 +807,9 @@ var NodesResource = class {
|
|
|
641
807
|
*/
|
|
642
808
|
async runMany(type, paramsList, opts = {}) {
|
|
643
809
|
if (opts.signal?.aborted) throw new JobAbortedError();
|
|
810
|
+
if (paramsList.some((params) => isImageBatchRequest(type, params))) {
|
|
811
|
+
throw batchRefusal(`a ${type} entry with count above 1 or models makes several jobs`);
|
|
812
|
+
}
|
|
644
813
|
return Promise.all(
|
|
645
814
|
paramsList.map(async (params) => {
|
|
646
815
|
if (opts.signal?.aborted) throw new JobAbortedError();
|
|
@@ -957,6 +1126,66 @@ var OAuthResource = class {
|
|
|
957
1126
|
}
|
|
958
1127
|
};
|
|
959
1128
|
|
|
1129
|
+
// src/resources/webhooks.ts
|
|
1130
|
+
var WebhooksResource = class {
|
|
1131
|
+
constructor(client) {
|
|
1132
|
+
this.client = client;
|
|
1133
|
+
}
|
|
1134
|
+
client;
|
|
1135
|
+
/** `POST /v1/webhook-endpoints` → the endpoint and its signing secret (shown this once). */
|
|
1136
|
+
create(input) {
|
|
1137
|
+
return this.client.request("POST", "/v1/webhook-endpoints", { body: input });
|
|
1138
|
+
}
|
|
1139
|
+
/** `GET /v1/webhook-endpoints` → your endpoints, newest first. Never a secret. */
|
|
1140
|
+
list() {
|
|
1141
|
+
return this.client.request("GET", "/v1/webhook-endpoints");
|
|
1142
|
+
}
|
|
1143
|
+
/** `GET /v1/webhook-endpoints/:id`. */
|
|
1144
|
+
get(id) {
|
|
1145
|
+
return this.client.request("GET", `/v1/webhook-endpoints/${encodeURIComponent(id)}`);
|
|
1146
|
+
}
|
|
1147
|
+
/** `PATCH /v1/webhook-endpoints/:id` → change the address, events, description; switch on or off. */
|
|
1148
|
+
update(id, input) {
|
|
1149
|
+
return this.client.request("PATCH", `/v1/webhook-endpoints/${encodeURIComponent(id)}`, { body: input });
|
|
1150
|
+
}
|
|
1151
|
+
/** `DELETE /v1/webhook-endpoints/:id` → the endpoint and its delivery log. */
|
|
1152
|
+
delete(id) {
|
|
1153
|
+
return this.client.request("DELETE", `/v1/webhook-endpoints/${encodeURIComponent(id)}`);
|
|
1154
|
+
}
|
|
1155
|
+
/**
|
|
1156
|
+
* `POST /v1/webhook-endpoints/:id/rotate-secret` → a new signing secret,
|
|
1157
|
+
* shown this once. It signs every delivery from now on (retries included);
|
|
1158
|
+
* the one it replaces keeps signing beside it for `gracePeriodSeconds` (a
|
|
1159
|
+
* day by default), so update your receiver within that time.
|
|
1160
|
+
*/
|
|
1161
|
+
rotateSecret(id, input = {}) {
|
|
1162
|
+
return this.client.request("POST", `/v1/webhook-endpoints/${encodeURIComponent(id)}/rotate-secret`, {
|
|
1163
|
+
body: input
|
|
1164
|
+
});
|
|
1165
|
+
}
|
|
1166
|
+
/** `GET /v1/webhook-endpoints/:id/deliveries` → the delivery log, newest first (kept 30 days). */
|
|
1167
|
+
deliveries(id, params = {}) {
|
|
1168
|
+
return this.client.request("GET", `/v1/webhook-endpoints/${encodeURIComponent(id)}/deliveries`, {
|
|
1169
|
+
query: { status: params.status, limit: params.limit, cursor: params.cursor }
|
|
1170
|
+
});
|
|
1171
|
+
}
|
|
1172
|
+
/** `GET /v1/webhook-endpoints/:id/deliveries/:deliveryId` → one delivery (`test()` returns its id). */
|
|
1173
|
+
getDelivery(id, deliveryId) {
|
|
1174
|
+
return this.client.request(
|
|
1175
|
+
"GET",
|
|
1176
|
+
`/v1/webhook-endpoints/${encodeURIComponent(id)}/deliveries/${encodeURIComponent(deliveryId)}`
|
|
1177
|
+
);
|
|
1178
|
+
}
|
|
1179
|
+
/**
|
|
1180
|
+
* `POST /v1/webhook-endpoints/:id/test` → queue a `ping` (sent within
|
|
1181
|
+
* seconds, tried once — even to an endpoint that is switched off). Follow
|
|
1182
|
+
* it with `deliveries()`.
|
|
1183
|
+
*/
|
|
1184
|
+
test(id) {
|
|
1185
|
+
return this.client.request("POST", `/v1/webhook-endpoints/${encodeURIComponent(id)}/test`);
|
|
1186
|
+
}
|
|
1187
|
+
};
|
|
1188
|
+
|
|
960
1189
|
// src/resources/apps.ts
|
|
961
1190
|
var AppsResource = class {
|
|
962
1191
|
constructor(client) {
|
|
@@ -1030,7 +1259,7 @@ var CharactersResource = class {
|
|
|
1030
1259
|
* List the caller's characters. By default returns active characters only;
|
|
1031
1260
|
* pass `archived: true` to fetch soft-deleted rows for an "archive" view.
|
|
1032
1261
|
* When `projectId` is set, only characters belonging to that project are
|
|
1033
|
-
* returned.
|
|
1262
|
+
* returned; `q` keeps the ones whose name or description contains it.
|
|
1034
1263
|
*
|
|
1035
1264
|
* Cursor-paginated: a response carrying a non-null `nextCursor` means more
|
|
1036
1265
|
* rows exist. Pass it back as `cursor` to fetch the next page, and keep going
|
|
@@ -1052,6 +1281,7 @@ var CharactersResource = class {
|
|
|
1052
1281
|
const query = {};
|
|
1053
1282
|
if (params.projectId) query.projectId = params.projectId;
|
|
1054
1283
|
if (params.archived) query.archived = "true";
|
|
1284
|
+
if (params.q) query.q = params.q;
|
|
1055
1285
|
if (params.limit !== void 0) query.limit = String(params.limit);
|
|
1056
1286
|
if (params.cursor) query.cursor = params.cursor;
|
|
1057
1287
|
return this.client.request("GET", "/v1/characters", { query });
|
|
@@ -1184,6 +1414,41 @@ var CharactersResource = class {
|
|
|
1184
1414
|
`/v1/characters/${encodeURIComponent(id)}/llm-caption`
|
|
1185
1415
|
);
|
|
1186
1416
|
}
|
|
1417
|
+
/**
|
|
1418
|
+
* Start training a high-fidelity model of the character on its own images
|
|
1419
|
+
* (Nodaro Cloud only — other editions answer `NotFoundError`). Reserves the
|
|
1420
|
+
* training price up front and refunds it if the training fails or is
|
|
1421
|
+
* cancelled. Resolves at once (202); a training takes about 15 minutes —
|
|
1422
|
+
* follow it with {@link trainingStatus}. Once it succeeds, a workflow's
|
|
1423
|
+
* Generate Image node whose prompt @-mentions this one character runs on the
|
|
1424
|
+
* trained model.
|
|
1425
|
+
*
|
|
1426
|
+
* An OAuth app token needs the `assets:write` scope (`ForbiddenError`
|
|
1427
|
+
* otherwise, before anything is reserved); a session or personal API key
|
|
1428
|
+
* needs none. Refusals are `NodaroError`s whose `code` is a
|
|
1429
|
+
* {@link TrainCharacterRefusalCode}; rate-limited to 3 calls a minute.
|
|
1430
|
+
*/
|
|
1431
|
+
train(id, input = {}) {
|
|
1432
|
+
return this.client.request("POST", `/v1/characters/${encodeURIComponent(id)}/train`, { body: input });
|
|
1433
|
+
}
|
|
1434
|
+
/**
|
|
1435
|
+
* The character's training record (Nodaro Cloud only). Poll it while
|
|
1436
|
+
* `status` is `queued` or `training` — every 10 s or so is plenty.
|
|
1437
|
+
*/
|
|
1438
|
+
trainingStatus(id) {
|
|
1439
|
+
return this.client.request("GET", `/v1/characters/${encodeURIComponent(id)}/training`);
|
|
1440
|
+
}
|
|
1441
|
+
/**
|
|
1442
|
+
* Remove the character's trained model (Nodaro Cloud only): cancels a
|
|
1443
|
+
* training in flight and refunds its reservation, deletes the model, and
|
|
1444
|
+
* clears the training record (`trainingStatus` then reads `untrained`).
|
|
1445
|
+
* Generations go back to reference images. Cannot be undone — a new model
|
|
1446
|
+
* means a new, paid training. An OAuth app token needs the `assets:write`
|
|
1447
|
+
* scope (`ForbiddenError` otherwise), like deleting the character.
|
|
1448
|
+
*/
|
|
1449
|
+
async deleteLora(id) {
|
|
1450
|
+
await this.client.request("DELETE", `/v1/characters/${encodeURIComponent(id)}/lora`);
|
|
1451
|
+
}
|
|
1187
1452
|
};
|
|
1188
1453
|
function buildPersonSeedPrompt(value) {
|
|
1189
1454
|
return person.buildPersonHints(value).join(", ");
|
|
@@ -1195,11 +1460,13 @@ var LocationsResource = class {
|
|
|
1195
1460
|
client;
|
|
1196
1461
|
/**
|
|
1197
1462
|
* List the caller's locations. By default returns active locations only;
|
|
1198
|
-
* pass `archived: true` to fetch soft-deleted rows for an "archive" view
|
|
1463
|
+
* pass `archived: true` to fetch soft-deleted rows for an "archive" view,
|
|
1464
|
+
* and `q` to keep the ones whose name or description contains it.
|
|
1199
1465
|
*/
|
|
1200
1466
|
list(params = {}) {
|
|
1201
1467
|
const query = {};
|
|
1202
1468
|
if (params.archived) query.archived = "true";
|
|
1469
|
+
if (params.q) query.q = params.q;
|
|
1203
1470
|
if (params.limit !== void 0) query.limit = String(params.limit);
|
|
1204
1471
|
if (params.cursor) query.cursor = params.cursor;
|
|
1205
1472
|
return this.client.request("GET", "/v1/locations", { query });
|
|
@@ -1373,12 +1640,14 @@ var ObjectsResource = class {
|
|
|
1373
1640
|
/**
|
|
1374
1641
|
* List the caller's objects. By default returns active objects only;
|
|
1375
1642
|
* pass `archived: true` to fetch soft-deleted rows for an "archive" view.
|
|
1376
|
-
* Optional `projectId` scopes the result to a single project
|
|
1643
|
+
* Optional `projectId` scopes the result to a single project; `q` keeps the
|
|
1644
|
+
* objects whose name or description contains it.
|
|
1377
1645
|
*/
|
|
1378
1646
|
list(params = {}) {
|
|
1379
1647
|
const query = {};
|
|
1380
1648
|
if (params.archived) query.archived = "true";
|
|
1381
1649
|
if (params.projectId) query.projectId = params.projectId;
|
|
1650
|
+
if (params.q) query.q = params.q;
|
|
1382
1651
|
if (params.limit !== void 0) query.limit = String(params.limit);
|
|
1383
1652
|
if (params.cursor) query.cursor = params.cursor;
|
|
1384
1653
|
return this.client.request("GET", "/v1/objects", { query });
|
|
@@ -1559,12 +1828,14 @@ var CreaturesResource = class {
|
|
|
1559
1828
|
/**
|
|
1560
1829
|
* List the caller's creatures. By default returns active creatures only;
|
|
1561
1830
|
* pass `archived: true` to fetch soft-deleted rows for an "archive" view.
|
|
1562
|
-
* Optional `projectId` scopes the result to a single project
|
|
1831
|
+
* Optional `projectId` scopes the result to a single project; `q` keeps the
|
|
1832
|
+
* creatures whose name or description contains it.
|
|
1563
1833
|
*/
|
|
1564
1834
|
list(params = {}) {
|
|
1565
1835
|
const query = {};
|
|
1566
1836
|
if (params.archived) query.archived = "true";
|
|
1567
1837
|
if (params.projectId) query.projectId = params.projectId;
|
|
1838
|
+
if (params.q) query.q = params.q;
|
|
1568
1839
|
if (params.limit !== void 0) query.limit = String(params.limit);
|
|
1569
1840
|
if (params.cursor) query.cursor = params.cursor;
|
|
1570
1841
|
return this.client.request("GET", "/v1/creatures", { query });
|
|
@@ -2688,6 +2959,53 @@ var CreditsResource = class {
|
|
|
2688
2959
|
// a consumer needs it, shaped to that need.
|
|
2689
2960
|
};
|
|
2690
2961
|
|
|
2962
|
+
// src/resources/billing.ts
|
|
2963
|
+
var BillingResource = class {
|
|
2964
|
+
constructor(client) {
|
|
2965
|
+
this.client = client;
|
|
2966
|
+
}
|
|
2967
|
+
client;
|
|
2968
|
+
/**
|
|
2969
|
+
* `GET /v1/billing/plans` → the plans and credit packs on sale, with their
|
|
2970
|
+
* prices. Public: works with no credential, the same for every caller.
|
|
2971
|
+
* Nodaro Cloud only — a self-hosted instance answers 404. Throws on `403
|
|
2972
|
+
* self_serve_disabled` (this deployment does not sell to its users) and on
|
|
2973
|
+
* `503` (`stripe_not_configured`, or prices briefly unavailable).
|
|
2974
|
+
*/
|
|
2975
|
+
plans() {
|
|
2976
|
+
return this.client.request("GET", "/v1/billing/plans");
|
|
2977
|
+
}
|
|
2978
|
+
/**
|
|
2979
|
+
* `GET /v1/billing/subscription` → the account's latest subscription
|
|
2980
|
+
* (`null` when it never subscribed) and the tier its entitlements follow.
|
|
2981
|
+
* Match `effectiveTier` to a {@link BillingPlan} `id` to mark the current
|
|
2982
|
+
* plan (no match: pay-as-you-go, or a tier not on sale). Needs a signed-in
|
|
2983
|
+
* session, a personal API token without a workflow limit, or an app's OAuth
|
|
2984
|
+
* token. Nodaro Cloud only — a self-hosted instance answers 404.
|
|
2985
|
+
*/
|
|
2986
|
+
subscription() {
|
|
2987
|
+
return this.client.request("GET", "/v1/billing/subscription");
|
|
2988
|
+
}
|
|
2989
|
+
/**
|
|
2990
|
+
* `GET /v1/billing/surface` → how this deployment bills: whether it meters
|
|
2991
|
+
* at all (`providerId !== "none"`) and in which unit costs display. Public,
|
|
2992
|
+
* every edition.
|
|
2993
|
+
*/
|
|
2994
|
+
async surface() {
|
|
2995
|
+
const res = await this.client.request("GET", "/v1/billing/surface");
|
|
2996
|
+
return res.data;
|
|
2997
|
+
}
|
|
2998
|
+
/**
|
|
2999
|
+
* `GET /v1/billing/account` → the caller's plan and balance as the
|
|
3000
|
+
* deployment's billing provider reports them, in its display unit. `null`
|
|
3001
|
+
* when the provider could not answer — not a zero balance. Every edition.
|
|
3002
|
+
*/
|
|
3003
|
+
async account() {
|
|
3004
|
+
const res = await this.client.request("GET", "/v1/billing/account");
|
|
3005
|
+
return res.data;
|
|
3006
|
+
}
|
|
3007
|
+
};
|
|
3008
|
+
|
|
2691
3009
|
// src/resources/uploads.ts
|
|
2692
3010
|
var UploadsResource = class {
|
|
2693
3011
|
constructor(client) {
|
|
@@ -2723,14 +3041,15 @@ var LibraryResource = class {
|
|
|
2723
3041
|
/**
|
|
2724
3042
|
* `GET /v1/library` → a page of the caller's media assets (newest first) plus
|
|
2725
3043
|
* a `nextCursor`. Pass the returned `nextCursor` back as `cursor` for the next
|
|
2726
|
-
* page. Filter by `type` and
|
|
2727
|
-
* full Storage set (uploads + generations), the default only
|
|
2728
|
-
* shared items.
|
|
3044
|
+
* page. Filter by `type` and search the filename with `q`; `owned: true`
|
|
3045
|
+
* returns the full Storage set (uploads + generations), the default only
|
|
3046
|
+
* library-saved + shared items.
|
|
2729
3047
|
*/
|
|
2730
3048
|
list(params = {}) {
|
|
2731
3049
|
const qs = new URLSearchParams();
|
|
2732
3050
|
if (params.type) qs.set("type", params.type);
|
|
2733
|
-
if (params.
|
|
3051
|
+
if (params.q) qs.set("q", params.q);
|
|
3052
|
+
else if (params.search) qs.set("search", params.search);
|
|
2734
3053
|
if (params.limit !== void 0) qs.set("limit", String(params.limit));
|
|
2735
3054
|
if (params.cursor) qs.set("cursor", params.cursor);
|
|
2736
3055
|
if (params.owned !== void 0) qs.set("owned", String(params.owned));
|
|
@@ -2740,6 +3059,46 @@ var LibraryResource = class {
|
|
|
2740
3059
|
}
|
|
2741
3060
|
};
|
|
2742
3061
|
|
|
3062
|
+
// src/resources/gallery.ts
|
|
3063
|
+
var GalleryResource = class {
|
|
3064
|
+
constructor(client) {
|
|
3065
|
+
this.client = client;
|
|
3066
|
+
}
|
|
3067
|
+
client;
|
|
3068
|
+
/**
|
|
3069
|
+
* `GET /v1/gallery` → a page of the public gallery, newest first (no auth
|
|
3070
|
+
* needed), or one person's work with `userId`.
|
|
3071
|
+
*/
|
|
3072
|
+
browse(params = {}) {
|
|
3073
|
+
return this.client.request("GET", "/v1/gallery", {
|
|
3074
|
+
query: {
|
|
3075
|
+
type: params.type,
|
|
3076
|
+
userId: params.userId,
|
|
3077
|
+
favoritesOnly: params.favoritesOnly,
|
|
3078
|
+
limit: params.limit,
|
|
3079
|
+
cursor: params.cursor
|
|
3080
|
+
}
|
|
3081
|
+
});
|
|
3082
|
+
}
|
|
3083
|
+
/**
|
|
3084
|
+
* Favorite a job, or un-favorite it when it already is
|
|
3085
|
+
* (`POST /v1/gallery/favorite`). You can favorite your own jobs and public
|
|
3086
|
+
* ones; another person's private job is a `NotFoundError`. OAuth apps need
|
|
3087
|
+
* the `assets:write` scope.
|
|
3088
|
+
*/
|
|
3089
|
+
toggleFavorite(jobId) {
|
|
3090
|
+
return this.client.request("POST", "/v1/gallery/favorite", { body: { jobId } });
|
|
3091
|
+
}
|
|
3092
|
+
/**
|
|
3093
|
+
* Your favorited job ids, newest first (`GET /v1/gallery/favorites`). OAuth
|
|
3094
|
+
* apps need the `assets:read` or `jobs:read` scope.
|
|
3095
|
+
*/
|
|
3096
|
+
async favorites() {
|
|
3097
|
+
const res = await this.client.request("GET", "/v1/gallery/favorites");
|
|
3098
|
+
return res.data;
|
|
3099
|
+
}
|
|
3100
|
+
};
|
|
3101
|
+
|
|
2743
3102
|
// src/resources/node-presets.ts
|
|
2744
3103
|
var PresetsResource = class {
|
|
2745
3104
|
constructor(client) {
|
|
@@ -2775,6 +3134,76 @@ var PresetsResource = class {
|
|
|
2775
3134
|
`/v1/node-presets/factory?nodeType=${encodeURIComponent(nodeType)}`
|
|
2776
3135
|
);
|
|
2777
3136
|
}
|
|
3137
|
+
/** `POST /v1/node-presets` → the new preset. */
|
|
3138
|
+
async create(input) {
|
|
3139
|
+
const res = await this.client.request("POST", "/v1/node-presets", { body: input });
|
|
3140
|
+
return res.data;
|
|
3141
|
+
}
|
|
3142
|
+
/**
|
|
3143
|
+
* `PATCH /v1/node-presets/:id` → the updated preset. Pass the `updatedAt` you
|
|
3144
|
+
* read as `expectedUpdatedAt` to refuse (409 `conflict`) a change made
|
|
3145
|
+
* elsewhere since.
|
|
3146
|
+
*/
|
|
3147
|
+
async update(id, patch, opts = {}) {
|
|
3148
|
+
const body = opts.expectedUpdatedAt ? { ...patch, expectedUpdatedAt: opts.expectedUpdatedAt } : patch;
|
|
3149
|
+
const res = await this.client.request("PATCH", `/v1/node-presets/${encodeURIComponent(id)}`, { body });
|
|
3150
|
+
return res.data;
|
|
3151
|
+
}
|
|
3152
|
+
/** `DELETE /v1/node-presets/:id` (404 when it is not yours). `expectedUpdatedAt` as on `update`. */
|
|
3153
|
+
async delete(id, opts = {}) {
|
|
3154
|
+
const res = await this.client.request("DELETE", `/v1/node-presets/${encodeURIComponent(id)}`, {
|
|
3155
|
+
query: { expectedUpdatedAt: opts.expectedUpdatedAt }
|
|
3156
|
+
});
|
|
3157
|
+
return res.data;
|
|
3158
|
+
}
|
|
3159
|
+
/**
|
|
3160
|
+
* `POST /v1/node-presets/import` — up to 500 presets in one call. A name you
|
|
3161
|
+
* already use gets an "(imported N)" suffix; a preset whose data is empty
|
|
3162
|
+
* after stripping runtime keys is skipped.
|
|
3163
|
+
*/
|
|
3164
|
+
async import(presets) {
|
|
3165
|
+
const res = await this.client.request("POST", "/v1/node-presets/import", { body: { presets } });
|
|
3166
|
+
return res.data;
|
|
3167
|
+
}
|
|
3168
|
+
/** `POST /v1/node-presets/reorder` — positions (and group membership) for many presets and groups at once. */
|
|
3169
|
+
async reorder(input) {
|
|
3170
|
+
const res = await this.client.request("POST", "/v1/node-presets/reorder", { body: input });
|
|
3171
|
+
return res.data;
|
|
3172
|
+
}
|
|
3173
|
+
/** `GET /v1/node-presets/favorites` → your favorite preset ids for `nodeType`, newest first. */
|
|
3174
|
+
async favorites(nodeType) {
|
|
3175
|
+
const res = await this.client.request("GET", "/v1/node-presets/favorites", { query: { nodeType } });
|
|
3176
|
+
return res.data;
|
|
3177
|
+
}
|
|
3178
|
+
/** `POST /v1/node-presets/favorites` — idempotent. */
|
|
3179
|
+
async addFavorite(input) {
|
|
3180
|
+
const res = await this.client.request("POST", "/v1/node-presets/favorites", { body: input });
|
|
3181
|
+
return res.data;
|
|
3182
|
+
}
|
|
3183
|
+
/** `DELETE /v1/node-presets/favorites` — idempotent. */
|
|
3184
|
+
async removeFavorite(input) {
|
|
3185
|
+
const res = await this.client.request("DELETE", "/v1/node-presets/favorites", {
|
|
3186
|
+
query: { nodeType: input.nodeType, presetId: input.presetId }
|
|
3187
|
+
});
|
|
3188
|
+
return res.data;
|
|
3189
|
+
}
|
|
3190
|
+
/** `POST /v1/node-preset-groups` → the new folder or section. */
|
|
3191
|
+
async createGroup(input) {
|
|
3192
|
+
const res = await this.client.request("POST", "/v1/node-preset-groups", { body: input });
|
|
3193
|
+
return res.data;
|
|
3194
|
+
}
|
|
3195
|
+
/** `PATCH /v1/node-preset-groups/:id` → the renamed or moved group. */
|
|
3196
|
+
async updateGroup(id, patch) {
|
|
3197
|
+
const res = await this.client.request("PATCH", `/v1/node-preset-groups/${encodeURIComponent(id)}`, {
|
|
3198
|
+
body: patch
|
|
3199
|
+
});
|
|
3200
|
+
return res.data;
|
|
3201
|
+
}
|
|
3202
|
+
/** `DELETE /v1/node-preset-groups/:id` — its presets move out of the group; none are deleted. */
|
|
3203
|
+
async deleteGroup(id) {
|
|
3204
|
+
const res = await this.client.request("DELETE", `/v1/node-preset-groups/${encodeURIComponent(id)}`);
|
|
3205
|
+
return res.data;
|
|
3206
|
+
}
|
|
2778
3207
|
};
|
|
2779
3208
|
|
|
2780
3209
|
// src/resources/saved-posts.ts
|
|
@@ -2915,6 +3344,68 @@ var CollectionsResource = class {
|
|
|
2915
3344
|
}
|
|
2916
3345
|
};
|
|
2917
3346
|
|
|
3347
|
+
// src/resources/palettes.ts
|
|
3348
|
+
var PALETTE_DIRECTION_PREFIX = "palette:";
|
|
3349
|
+
function paletteDirectionId(id) {
|
|
3350
|
+
return `${PALETTE_DIRECTION_PREFIX}${id}`;
|
|
3351
|
+
}
|
|
3352
|
+
var PalettesResource = class {
|
|
3353
|
+
constructor(client) {
|
|
3354
|
+
this.client = client;
|
|
3355
|
+
}
|
|
3356
|
+
client;
|
|
3357
|
+
/** Your palettes, newest first. Page with `nextCursor`. */
|
|
3358
|
+
list(params = {}) {
|
|
3359
|
+
return this.client.request("GET", "/v1/palettes", {
|
|
3360
|
+
query: { limit: params.limit, cursor: params.cursor }
|
|
3361
|
+
});
|
|
3362
|
+
}
|
|
3363
|
+
get(id) {
|
|
3364
|
+
return this.client.request("GET", `/v1/palettes/${encodeURIComponent(id)}`);
|
|
3365
|
+
}
|
|
3366
|
+
create(input) {
|
|
3367
|
+
return this.client.request("POST", "/v1/palettes", { body: input });
|
|
3368
|
+
}
|
|
3369
|
+
update(id, input) {
|
|
3370
|
+
return this.client.request("PATCH", `/v1/palettes/${encodeURIComponent(id)}`, { body: input });
|
|
3371
|
+
}
|
|
3372
|
+
/** A run that still names the palette answers 404 `direction_not_found`. */
|
|
3373
|
+
async delete(id) {
|
|
3374
|
+
await this.client.request("DELETE", `/v1/palettes/${encodeURIComponent(id)}`);
|
|
3375
|
+
}
|
|
3376
|
+
};
|
|
3377
|
+
|
|
3378
|
+
// src/resources/moodboards.ts
|
|
3379
|
+
var MOODBOARD_DIRECTION_PREFIX = "moodboard:";
|
|
3380
|
+
function moodboardDirectionId(id) {
|
|
3381
|
+
return `${MOODBOARD_DIRECTION_PREFIX}${id}`;
|
|
3382
|
+
}
|
|
3383
|
+
var MoodboardsResource = class {
|
|
3384
|
+
constructor(client) {
|
|
3385
|
+
this.client = client;
|
|
3386
|
+
}
|
|
3387
|
+
client;
|
|
3388
|
+
/** Your moodboards, newest first. Page with `nextCursor`. */
|
|
3389
|
+
list(params = {}) {
|
|
3390
|
+
return this.client.request("GET", "/v1/moodboards", {
|
|
3391
|
+
query: { limit: params.limit, cursor: params.cursor }
|
|
3392
|
+
});
|
|
3393
|
+
}
|
|
3394
|
+
get(id) {
|
|
3395
|
+
return this.client.request("GET", `/v1/moodboards/${encodeURIComponent(id)}`);
|
|
3396
|
+
}
|
|
3397
|
+
create(input) {
|
|
3398
|
+
return this.client.request("POST", "/v1/moodboards", { body: input });
|
|
3399
|
+
}
|
|
3400
|
+
update(id, input) {
|
|
3401
|
+
return this.client.request("PATCH", `/v1/moodboards/${encodeURIComponent(id)}`, { body: input });
|
|
3402
|
+
}
|
|
3403
|
+
/** Deletes the moodboard only; the images it links to are untouched. */
|
|
3404
|
+
async delete(id) {
|
|
3405
|
+
await this.client.request("DELETE", `/v1/moodboards/${encodeURIComponent(id)}`);
|
|
3406
|
+
}
|
|
3407
|
+
};
|
|
3408
|
+
|
|
2918
3409
|
// src/resources/competitors.ts
|
|
2919
3410
|
var CompetitorsResource = class {
|
|
2920
3411
|
constructor(client) {
|
|
@@ -4175,7 +4666,7 @@ var EditResource = class {
|
|
|
4175
4666
|
return edl.remapTranscriptThroughEdl(edl$1, transcript);
|
|
4176
4667
|
}
|
|
4177
4668
|
};
|
|
4178
|
-
var SDK_VERSION = "2.
|
|
4669
|
+
var SDK_VERSION = "2.29.0" ;
|
|
4179
4670
|
var CLIENT_HEADER = "X-Nodaro-Client";
|
|
4180
4671
|
var isBrowser = () => typeof window !== "undefined" && typeof window.document !== "undefined";
|
|
4181
4672
|
var NodaroClient = class _NodaroClient {
|
|
@@ -4198,6 +4689,8 @@ var NodaroClient = class _NodaroClient {
|
|
|
4198
4689
|
}
|
|
4199
4690
|
workflows;
|
|
4200
4691
|
projects;
|
|
4692
|
+
/** Generation sessions inside projects (Create Image / Video / Music). */
|
|
4693
|
+
sessions;
|
|
4201
4694
|
jobs;
|
|
4202
4695
|
videoPro;
|
|
4203
4696
|
executions;
|
|
@@ -4205,6 +4698,8 @@ var NodaroClient = class _NodaroClient {
|
|
|
4205
4698
|
scene3d;
|
|
4206
4699
|
developerApps;
|
|
4207
4700
|
oauth;
|
|
4701
|
+
/** Outbound webhooks: endpoints that receive your job.completed / job.failed. */
|
|
4702
|
+
webhooks;
|
|
4208
4703
|
apps;
|
|
4209
4704
|
characters;
|
|
4210
4705
|
locations;
|
|
@@ -4218,11 +4713,19 @@ var NodaroClient = class _NodaroClient {
|
|
|
4218
4713
|
media;
|
|
4219
4714
|
audio;
|
|
4220
4715
|
credits;
|
|
4716
|
+
/** Plans and prices, the subscription, and how this deployment bills. */
|
|
4717
|
+
billing;
|
|
4221
4718
|
uploads;
|
|
4222
4719
|
library;
|
|
4720
|
+
/** The public gallery and your favorites. */
|
|
4721
|
+
gallery;
|
|
4223
4722
|
presets;
|
|
4224
4723
|
savedPosts;
|
|
4225
4724
|
collections;
|
|
4725
|
+
/** Your colour palettes — a generate-image direction (`direction.colorLook: paletteDirectionId(id)`). */
|
|
4726
|
+
palettes;
|
|
4727
|
+
/** Your moodboards — a generate-image direction (`direction.style: moodboardDirectionId(id)`). */
|
|
4728
|
+
moodboards;
|
|
4226
4729
|
competitors;
|
|
4227
4730
|
pickerCatalogs;
|
|
4228
4731
|
catalogs;
|
|
@@ -4249,6 +4752,7 @@ var NodaroClient = class _NodaroClient {
|
|
|
4249
4752
|
this.sendClientHeader = opts.clientLabel !== void 0 || !isBrowser();
|
|
4250
4753
|
this.workflows = new WorkflowsResource(this);
|
|
4251
4754
|
this.projects = new ProjectsResource(this);
|
|
4755
|
+
this.sessions = new SessionsResource(this);
|
|
4252
4756
|
this.jobs = new JobsResource(this);
|
|
4253
4757
|
this.videoPro = new VideoProResource(this);
|
|
4254
4758
|
this.executions = new ExecutionsResource(this);
|
|
@@ -4256,6 +4760,7 @@ var NodaroClient = class _NodaroClient {
|
|
|
4256
4760
|
this.scene3d = new Scene3DResource(this);
|
|
4257
4761
|
this.developerApps = new DeveloperAppsResource(this);
|
|
4258
4762
|
this.oauth = new OAuthResource(this);
|
|
4763
|
+
this.webhooks = new WebhooksResource(this);
|
|
4259
4764
|
this.apps = new AppsResource(this);
|
|
4260
4765
|
this.characters = new CharactersResource(this);
|
|
4261
4766
|
this.locations = new LocationsResource(this);
|
|
@@ -4269,11 +4774,15 @@ var NodaroClient = class _NodaroClient {
|
|
|
4269
4774
|
this.media = new MediaResource(this);
|
|
4270
4775
|
this.audio = new AudioResource(this);
|
|
4271
4776
|
this.credits = new CreditsResource(this);
|
|
4777
|
+
this.billing = new BillingResource(this);
|
|
4272
4778
|
this.uploads = new UploadsResource(this);
|
|
4273
4779
|
this.library = new LibraryResource(this);
|
|
4780
|
+
this.gallery = new GalleryResource(this);
|
|
4274
4781
|
this.presets = new PresetsResource(this);
|
|
4275
4782
|
this.savedPosts = new SavedPostsResource(this);
|
|
4276
4783
|
this.collections = new CollectionsResource(this);
|
|
4784
|
+
this.palettes = new PalettesResource(this);
|
|
4785
|
+
this.moodboards = new MoodboardsResource(this);
|
|
4277
4786
|
this.competitors = new CompetitorsResource(this);
|
|
4278
4787
|
this.pickerCatalogs = new PickerCatalogsResource(this);
|
|
4279
4788
|
this.catalogs = new CatalogsResource(this);
|
|
@@ -4398,6 +4907,32 @@ var NodaroClient = class _NodaroClient {
|
|
|
4398
4907
|
const res = await this.request("GET", "/v1/me");
|
|
4399
4908
|
return res.data;
|
|
4400
4909
|
}
|
|
4910
|
+
/**
|
|
4911
|
+
* `GET /v1/me/connected-apps` → every app with access to the signed-in
|
|
4912
|
+
* user's account (see {@link ConnectedApp}), newest grant first.
|
|
4913
|
+
*
|
|
4914
|
+
* **A signed-in browser session only.** The route answers a Supabase
|
|
4915
|
+
* session token (`supabaseAuth(…)`, `createSharedSupabaseClient`, or a
|
|
4916
|
+
* `StaticTokenAuth` holding one) and refuses every other credential with
|
|
4917
|
+
* `UnauthorizedError` ("Sign in required"): an app token or an API key must
|
|
4918
|
+
* not list the grants it lives under. Build your "Connected apps" settings
|
|
4919
|
+
* screen on this; a server-side integration cannot call it.
|
|
4920
|
+
*/
|
|
4921
|
+
async connectedApps() {
|
|
4922
|
+
const res = await this.request("GET", "/v1/me/connected-apps");
|
|
4923
|
+
return res.apps;
|
|
4924
|
+
}
|
|
4925
|
+
/**
|
|
4926
|
+
* `POST /v1/me/connected-apps/:authorizationId/revoke` — ends an app's
|
|
4927
|
+
* access: the grant and every token issued under it, at once (the app's next
|
|
4928
|
+
* call is a 401). Resolves when done.
|
|
4929
|
+
*
|
|
4930
|
+
* A signed-in browser session only, like {@link connectedApps}. Throws
|
|
4931
|
+
* `NotFoundError` when the grant is not the user's or is already revoked.
|
|
4932
|
+
*/
|
|
4933
|
+
async revokeConnectedApp(authorizationId) {
|
|
4934
|
+
await this.request("POST", `/v1/me/connected-apps/${encodeURIComponent(authorizationId)}/revoke`);
|
|
4935
|
+
}
|
|
4401
4936
|
buildUrl(path2, query) {
|
|
4402
4937
|
const base = this.baseUrl || (typeof window !== "undefined" ? window.location.origin : "http://placeholder");
|
|
4403
4938
|
const url = new URL(path2, base);
|
|
@@ -4444,6 +4979,96 @@ function supabaseAuth(supabase) {
|
|
|
4444
4979
|
};
|
|
4445
4980
|
}
|
|
4446
4981
|
|
|
4982
|
+
// src/webhook-signature.ts
|
|
4983
|
+
var WebhookSignatureError = class extends Error {
|
|
4984
|
+
code;
|
|
4985
|
+
constructor(code, message) {
|
|
4986
|
+
super(message);
|
|
4987
|
+
this.name = "WebhookSignatureError";
|
|
4988
|
+
this.code = code;
|
|
4989
|
+
}
|
|
4990
|
+
};
|
|
4991
|
+
var DEFAULT_TOLERANCE_SECONDS = 300;
|
|
4992
|
+
var HEX_SIGNATURE = /^[0-9a-f]{64}$/;
|
|
4993
|
+
function toBytes(payload) {
|
|
4994
|
+
if (typeof payload === "string") return new TextEncoder().encode(payload);
|
|
4995
|
+
if (payload instanceof Uint8Array) return payload;
|
|
4996
|
+
return new Uint8Array(payload);
|
|
4997
|
+
}
|
|
4998
|
+
function hexToBytes(hex) {
|
|
4999
|
+
const out = new Uint8Array(hex.length / 2);
|
|
5000
|
+
for (let i = 0; i < out.length; i++) out[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
5001
|
+
return out;
|
|
5002
|
+
}
|
|
5003
|
+
function constantTimeEqual(a, b) {
|
|
5004
|
+
if (a.length !== b.length) return false;
|
|
5005
|
+
let diff = 0;
|
|
5006
|
+
for (let i = 0; i < a.length; i++) diff |= a[i] ^ b[i];
|
|
5007
|
+
return diff === 0;
|
|
5008
|
+
}
|
|
5009
|
+
function parseHeader(raw) {
|
|
5010
|
+
let timestamp = null;
|
|
5011
|
+
const signatures = [];
|
|
5012
|
+
for (const part of raw.split(",")) {
|
|
5013
|
+
const eq = part.indexOf("=");
|
|
5014
|
+
if (eq <= 0) continue;
|
|
5015
|
+
const key = part.slice(0, eq).trim();
|
|
5016
|
+
const value = part.slice(eq + 1).trim();
|
|
5017
|
+
if (key === "t") {
|
|
5018
|
+
if (!/^\d{1,15}$/.test(value)) {
|
|
5019
|
+
throw new WebhookSignatureError("malformed_header", "Nodaro-Signature has no valid timestamp (t=)");
|
|
5020
|
+
}
|
|
5021
|
+
timestamp = Number(value);
|
|
5022
|
+
} else if (key === "v1") {
|
|
5023
|
+
signatures.push(value.toLowerCase());
|
|
5024
|
+
}
|
|
5025
|
+
}
|
|
5026
|
+
if (timestamp === null) throw new WebhookSignatureError("malformed_header", "Nodaro-Signature has no timestamp (t=)");
|
|
5027
|
+
if (signatures.length === 0) throw new WebhookSignatureError("malformed_header", "Nodaro-Signature has no v1 signature");
|
|
5028
|
+
return { timestamp, signatures };
|
|
5029
|
+
}
|
|
5030
|
+
async function verifyWebhookSignature(options) {
|
|
5031
|
+
const { payload, secret } = options;
|
|
5032
|
+
const tolerance = options.toleranceSeconds ?? DEFAULT_TOLERANCE_SECONDS;
|
|
5033
|
+
if (typeof tolerance !== "number" || !Number.isFinite(tolerance) || tolerance < 0) {
|
|
5034
|
+
throw new RangeError("toleranceSeconds must be a finite number of seconds, 0 or more");
|
|
5035
|
+
}
|
|
5036
|
+
if (!secret) throw new WebhookSignatureError("missing_secret", "No signing secret was given");
|
|
5037
|
+
const header = typeof options.header === "string" ? options.header : options.header?.[0];
|
|
5038
|
+
if (!header || !header.trim()) throw new WebhookSignatureError("missing_header", "The request has no Nodaro-Signature header");
|
|
5039
|
+
const { timestamp, signatures } = parseHeader(header);
|
|
5040
|
+
const subtle = globalThis.crypto?.subtle;
|
|
5041
|
+
if (!subtle) throw new WebhookSignatureError("crypto_unavailable", "Web Crypto (crypto.subtle) is not available in this runtime");
|
|
5042
|
+
const body = toBytes(payload);
|
|
5043
|
+
const prefix = new TextEncoder().encode(`${timestamp}.`);
|
|
5044
|
+
const message = new Uint8Array(prefix.length + body.length);
|
|
5045
|
+
message.set(prefix, 0);
|
|
5046
|
+
message.set(body, prefix.length);
|
|
5047
|
+
const key = await subtle.importKey("raw", new TextEncoder().encode(secret), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
5048
|
+
const expected = new Uint8Array(await subtle.sign("HMAC", key, message));
|
|
5049
|
+
let matched = false;
|
|
5050
|
+
for (const candidate of signatures) {
|
|
5051
|
+
const wellFormed = HEX_SIGNATURE.test(candidate);
|
|
5052
|
+
const bytes = wellFormed ? hexToBytes(candidate) : new Uint8Array(expected.length);
|
|
5053
|
+
if (constantTimeEqual(bytes, expected) && wellFormed) matched = true;
|
|
5054
|
+
}
|
|
5055
|
+
if (!matched) throw new WebhookSignatureError("signature_mismatch", "The Nodaro-Signature does not match the body");
|
|
5056
|
+
if (tolerance > 0) {
|
|
5057
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
5058
|
+
if (Math.abs(now - timestamp) > tolerance) {
|
|
5059
|
+
throw new WebhookSignatureError(
|
|
5060
|
+
"timestamp_outside_tolerance",
|
|
5061
|
+
`The signature's timestamp is more than ${tolerance} seconds from now`
|
|
5062
|
+
);
|
|
5063
|
+
}
|
|
5064
|
+
}
|
|
5065
|
+
try {
|
|
5066
|
+
return JSON.parse(new TextDecoder().decode(body));
|
|
5067
|
+
} catch {
|
|
5068
|
+
throw new WebhookSignatureError("invalid_payload", "The signed body is not JSON");
|
|
5069
|
+
}
|
|
5070
|
+
}
|
|
5071
|
+
|
|
4447
5072
|
Object.defineProperty(exports, "OUTPUT_BEARING_NODE_STATUSES", {
|
|
4448
5073
|
enumerable: true,
|
|
4449
5074
|
get: function () { return workflow.OUTPUT_BEARING_NODE_STATUSES; }
|
|
@@ -4546,6 +5171,7 @@ Object.defineProperty(exports, "RECAST_SEGMENT_PACKS", {
|
|
|
4546
5171
|
});
|
|
4547
5172
|
exports.AppsResource = AppsResource;
|
|
4548
5173
|
exports.AudioResource = AudioResource;
|
|
5174
|
+
exports.BillingResource = BillingResource;
|
|
4549
5175
|
exports.CREATURE_ASSET_TYPES = CREATURE_ASSET_TYPES;
|
|
4550
5176
|
exports.CallbackAuth = CallbackAuth;
|
|
4551
5177
|
exports.CatalogsResource = CatalogsResource;
|
|
@@ -4561,6 +5187,7 @@ exports.DeveloperAppsResource = DeveloperAppsResource;
|
|
|
4561
5187
|
exports.EditResource = EditResource;
|
|
4562
5188
|
exports.ExecutionsResource = ExecutionsResource;
|
|
4563
5189
|
exports.ForbiddenError = ForbiddenError;
|
|
5190
|
+
exports.GalleryResource = GalleryResource;
|
|
4564
5191
|
exports.InsufficientCreditsError = InsufficientCreditsError;
|
|
4565
5192
|
exports.JobAbortedError = JobAbortedError;
|
|
4566
5193
|
exports.JobBlockedError = JobBlockedError;
|
|
@@ -4571,8 +5198,10 @@ exports.JobsResource = JobsResource;
|
|
|
4571
5198
|
exports.LibraryResource = LibraryResource;
|
|
4572
5199
|
exports.LlmResource = LlmResource;
|
|
4573
5200
|
exports.LocationsResource = LocationsResource;
|
|
5201
|
+
exports.MOODBOARD_DIRECTION_PREFIX = MOODBOARD_DIRECTION_PREFIX;
|
|
4574
5202
|
exports.MediaResource = MediaResource;
|
|
4575
5203
|
exports.ModelsResource = ModelsResource;
|
|
5204
|
+
exports.MoodboardsResource = MoodboardsResource;
|
|
4576
5205
|
exports.NodaroClient = NodaroClient;
|
|
4577
5206
|
exports.NodaroError = NodaroError;
|
|
4578
5207
|
exports.NodesResource = NodesResource;
|
|
@@ -4580,6 +5209,8 @@ exports.NotFoundError = NotFoundError;
|
|
|
4580
5209
|
exports.OAuthResource = OAuthResource;
|
|
4581
5210
|
exports.ObjectsResource = ObjectsResource;
|
|
4582
5211
|
exports.OrganizationsResource = OrganizationsResource;
|
|
5212
|
+
exports.PALETTE_DIRECTION_PREFIX = PALETTE_DIRECTION_PREFIX;
|
|
5213
|
+
exports.PalettesResource = PalettesResource;
|
|
4583
5214
|
exports.PickerCatalogsResource = PickerCatalogsResource;
|
|
4584
5215
|
exports.PipelinesResource = PipelinesResource;
|
|
4585
5216
|
exports.PresetsResource = PresetsResource;
|
|
@@ -4591,6 +5222,7 @@ exports.ReduceResource = ReduceResource;
|
|
|
4591
5222
|
exports.SCENE3D_DELIVERY_ASSET_USAGE = SCENE3D_DELIVERY_ASSET_USAGE;
|
|
4592
5223
|
exports.SavedPostsResource = SavedPostsResource;
|
|
4593
5224
|
exports.Scene3DResource = Scene3DResource;
|
|
5225
|
+
exports.SessionsResource = SessionsResource;
|
|
4594
5226
|
exports.ShotsResource = ShotsResource;
|
|
4595
5227
|
exports.StaticTokenAuth = StaticTokenAuth;
|
|
4596
5228
|
exports.StorageExceededError = StorageExceededError;
|
|
@@ -4605,13 +5237,18 @@ exports.UnauthorizedError = UnauthorizedError;
|
|
|
4605
5237
|
exports.UploadsResource = UploadsResource;
|
|
4606
5238
|
exports.VideoProResource = VideoProResource;
|
|
4607
5239
|
exports.VoicesResource = VoicesResource;
|
|
5240
|
+
exports.WebhookSignatureError = WebhookSignatureError;
|
|
5241
|
+
exports.WebhooksResource = WebhooksResource;
|
|
4608
5242
|
exports.WorkflowConflictError = WorkflowConflictError;
|
|
4609
5243
|
exports.WorkflowsResource = WorkflowsResource;
|
|
4610
5244
|
exports.WorkspacesResource = WorkspacesResource;
|
|
4611
5245
|
exports.buildPersonSeedPrompt = buildPersonSeedPrompt;
|
|
4612
5246
|
exports.createClient = createClient;
|
|
4613
5247
|
exports.isStudioGenerateEstimate = isStudioGenerateEstimate;
|
|
5248
|
+
exports.moodboardDirectionId = moodboardDirectionId;
|
|
5249
|
+
exports.paletteDirectionId = paletteDirectionId;
|
|
4614
5250
|
exports.supabaseAuth = supabaseAuth;
|
|
4615
5251
|
exports.throwFromResponse = throwFromResponse;
|
|
5252
|
+
exports.verifyWebhookSignature = verifyWebhookSignature;
|
|
4616
5253
|
//# sourceMappingURL=index.cjs.map
|
|
4617
5254
|
//# sourceMappingURL=index.cjs.map
|