codai-sdk 0.3.1 → 0.5.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 +47 -2
- package/dist/index.d.ts +9261 -4798
- package/dist/index.js +659 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -669,6 +669,256 @@ var Embeddings = class {
|
|
|
669
669
|
}
|
|
670
670
|
};
|
|
671
671
|
|
|
672
|
+
// src/resources/environments.ts
|
|
673
|
+
var envPath = (id, suffix = "") => `/v1/environments/${encodeURIComponent(id)}${suffix}`;
|
|
674
|
+
var EnvironmentMembers = class {
|
|
675
|
+
constructor(http) {
|
|
676
|
+
this.http = http;
|
|
677
|
+
}
|
|
678
|
+
http;
|
|
679
|
+
/** `GET /v1/environments/{id}/members` — any role. */
|
|
680
|
+
async list(envId, opts = {}) {
|
|
681
|
+
const raw = await this.http.json(envPath(envId, "/members"), {
|
|
682
|
+
ext: opts.ext,
|
|
683
|
+
signal: opts.signal
|
|
684
|
+
});
|
|
685
|
+
return [...raw.members ?? []];
|
|
686
|
+
}
|
|
687
|
+
/** `POST /v1/environments/{id}/members` — exactly one of `user_id` / `email`. */
|
|
688
|
+
async add(envId, body, opts = {}) {
|
|
689
|
+
const raw = await this.http.json(
|
|
690
|
+
envPath(envId, "/members"),
|
|
691
|
+
{ body, ext: opts.ext, signal: opts.signal }
|
|
692
|
+
);
|
|
693
|
+
return raw.member;
|
|
694
|
+
}
|
|
695
|
+
/** `PUT /v1/environments/{id}/members/me/ssh-key` — one `authorized_keys` line. */
|
|
696
|
+
setSshKey(envId, publicKey, opts = {}) {
|
|
697
|
+
const body = { public_key: publicKey };
|
|
698
|
+
return this.http.json(envPath(envId, "/members/me/ssh-key"), {
|
|
699
|
+
method: "PUT",
|
|
700
|
+
body,
|
|
701
|
+
ext: opts.ext,
|
|
702
|
+
signal: opts.signal
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
/** `PATCH /v1/environments/{id}/members/{userId}` — 409 `last_owner` on demoting the last owner. */
|
|
706
|
+
async setRole(envId, userId, role, opts = {}) {
|
|
707
|
+
const raw = await this.http.json(
|
|
708
|
+
envPath(envId, `/members/${encodeURIComponent(userId)}`),
|
|
709
|
+
{ method: "PATCH", body: { role }, ext: opts.ext, signal: opts.signal }
|
|
710
|
+
);
|
|
711
|
+
return raw.member;
|
|
712
|
+
}
|
|
713
|
+
/** `DELETE /v1/environments/{id}/members/{userId}` — pass your own id to leave. */
|
|
714
|
+
remove(envId, userId, opts = {}) {
|
|
715
|
+
return this.http.json(
|
|
716
|
+
envPath(envId, `/members/${encodeURIComponent(userId)}`),
|
|
717
|
+
{ method: "DELETE", ext: opts.ext, signal: opts.signal }
|
|
718
|
+
);
|
|
719
|
+
}
|
|
720
|
+
/** `POST /v1/environments/{id}/members/me/ssh-cert` — 12 h OpenSSH user certificate for your key. */
|
|
721
|
+
sshCert(envId, body, opts = {}) {
|
|
722
|
+
return this.http.json(envPath(envId, "/members/me/ssh-cert"), {
|
|
723
|
+
method: "POST",
|
|
724
|
+
body,
|
|
725
|
+
ext: opts.ext,
|
|
726
|
+
signal: opts.signal,
|
|
727
|
+
noRetry: true
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
};
|
|
731
|
+
var EnvironmentTasks = class {
|
|
732
|
+
constructor(http) {
|
|
733
|
+
this.http = http;
|
|
734
|
+
}
|
|
735
|
+
http;
|
|
736
|
+
/** `GET /v1/environments/{id}/tasks` */
|
|
737
|
+
list(envId, opts = {}) {
|
|
738
|
+
return this.http.json(envPath(envId, "/tasks"), { ext: opts.ext, signal: opts.signal });
|
|
739
|
+
}
|
|
740
|
+
/** `POST /v1/environments/{id}/tasks` — queued; you get a notification when it finishes. */
|
|
741
|
+
create(envId, body, opts = {}) {
|
|
742
|
+
return this.http.json(envPath(envId, "/tasks"), {
|
|
743
|
+
method: "POST",
|
|
744
|
+
body,
|
|
745
|
+
ext: opts.ext,
|
|
746
|
+
signal: opts.signal,
|
|
747
|
+
noRetry: true
|
|
748
|
+
});
|
|
749
|
+
}
|
|
750
|
+
/** `GET /v1/environments/{id}/tasks/{taskId}` */
|
|
751
|
+
get(envId, taskId, opts = {}) {
|
|
752
|
+
return this.http.json(envPath(envId, `/tasks/${encodeURIComponent(taskId)}`), { ext: opts.ext, signal: opts.signal });
|
|
753
|
+
}
|
|
754
|
+
};
|
|
755
|
+
var EnvironmentPorts = class {
|
|
756
|
+
constructor(http) {
|
|
757
|
+
this.http = http;
|
|
758
|
+
}
|
|
759
|
+
http;
|
|
760
|
+
/** `GET /v1/environments/{id}/ports` — published (forwarded) ports. */
|
|
761
|
+
async list(envId, opts = {}) {
|
|
762
|
+
const raw = await this.http.json(envPath(envId, "/ports"), {
|
|
763
|
+
ext: opts.ext,
|
|
764
|
+
signal: opts.signal
|
|
765
|
+
});
|
|
766
|
+
return [...raw.ports ?? []];
|
|
767
|
+
}
|
|
768
|
+
/** `PUT /v1/environments/{id}/ports/{port}` — publish or change visibility (upsert). */
|
|
769
|
+
async set(envId, port, body, opts = {}) {
|
|
770
|
+
const raw = await this.http.json(
|
|
771
|
+
envPath(envId, `/ports/${encodeURIComponent(String(port))}`),
|
|
772
|
+
{ method: "PUT", body, ext: opts.ext, signal: opts.signal }
|
|
773
|
+
);
|
|
774
|
+
return raw.port;
|
|
775
|
+
}
|
|
776
|
+
/** `DELETE /v1/environments/{id}/ports/{port}` — unpublish. */
|
|
777
|
+
remove(envId, port, opts = {}) {
|
|
778
|
+
return this.http.json(
|
|
779
|
+
envPath(envId, `/ports/${encodeURIComponent(String(port))}`),
|
|
780
|
+
{ method: "DELETE", ext: opts.ext, signal: opts.signal }
|
|
781
|
+
);
|
|
782
|
+
}
|
|
783
|
+
};
|
|
784
|
+
var EnvironmentSecrets = class {
|
|
785
|
+
constructor(http) {
|
|
786
|
+
this.http = http;
|
|
787
|
+
}
|
|
788
|
+
http;
|
|
789
|
+
/** `GET /v1/environments/{id}/secrets` — names and timestamps only, never values. */
|
|
790
|
+
async list(envId, opts = {}) {
|
|
791
|
+
const raw = await this.http.json(envPath(envId, "/secrets"), {
|
|
792
|
+
ext: opts.ext,
|
|
793
|
+
signal: opts.signal
|
|
794
|
+
});
|
|
795
|
+
return [...raw.secrets ?? []];
|
|
796
|
+
}
|
|
797
|
+
/** `PUT /v1/environments/{id}/secrets/{name}` — upsert; `name` is `ENV_STYLE`. */
|
|
798
|
+
set(envId, name, value, opts = {}) {
|
|
799
|
+
const body = { value };
|
|
800
|
+
return this.http.json(
|
|
801
|
+
envPath(envId, `/secrets/${encodeURIComponent(name)}`),
|
|
802
|
+
{ method: "PUT", body, ext: opts.ext, signal: opts.signal }
|
|
803
|
+
);
|
|
804
|
+
}
|
|
805
|
+
/** `DELETE /v1/environments/{id}/secrets/{name}` */
|
|
806
|
+
remove(envId, name, opts = {}) {
|
|
807
|
+
return this.http.json(
|
|
808
|
+
envPath(envId, `/secrets/${encodeURIComponent(name)}`),
|
|
809
|
+
{ method: "DELETE", ext: opts.ext, signal: opts.signal }
|
|
810
|
+
);
|
|
811
|
+
}
|
|
812
|
+
};
|
|
813
|
+
var Environments = class {
|
|
814
|
+
constructor(http) {
|
|
815
|
+
this.http = http;
|
|
816
|
+
this.members = new EnvironmentMembers(http);
|
|
817
|
+
this.ports = new EnvironmentPorts(http);
|
|
818
|
+
this.secrets = new EnvironmentSecrets(http);
|
|
819
|
+
this.tasks = new EnvironmentTasks(http);
|
|
820
|
+
}
|
|
821
|
+
http;
|
|
822
|
+
members;
|
|
823
|
+
ports;
|
|
824
|
+
secrets;
|
|
825
|
+
tasks;
|
|
826
|
+
/** `GET /v1/environments/{id}/ssh-ca` — CA public keys to trust (`@cert-authority` lines). */
|
|
827
|
+
sshCa(envId, opts = {}) {
|
|
828
|
+
return this.http.json(envPath(envId, "/ssh-ca"), { ext: opts.ext, signal: opts.signal });
|
|
829
|
+
}
|
|
830
|
+
/** `GET /v1/environments?project_id=&for_user_id=me` — newest first, every state. */
|
|
831
|
+
async list(query = {}, opts = {}) {
|
|
832
|
+
const raw = await this.http.json("/v1/environments", {
|
|
833
|
+
query: { project_id: query.project_id, for_user_id: query.for_user_id },
|
|
834
|
+
ext: opts.ext,
|
|
835
|
+
signal: opts.signal
|
|
836
|
+
});
|
|
837
|
+
return [...raw.environments ?? []];
|
|
838
|
+
}
|
|
839
|
+
/**
|
|
840
|
+
* `POST /v1/environments` — `byo` starts `pending`; managed providers start
|
|
841
|
+
* `creating`. 409 `already_has_env` in a `vm_per_dev` project (the error
|
|
842
|
+
* body carries the `environment_id` to reuse).
|
|
843
|
+
*/
|
|
844
|
+
async create(body, opts = {}) {
|
|
845
|
+
const raw = await this.http.json("/v1/environments", {
|
|
846
|
+
body,
|
|
847
|
+
ext: opts.ext,
|
|
848
|
+
signal: opts.signal,
|
|
849
|
+
noRetry: true
|
|
850
|
+
});
|
|
851
|
+
return raw.environment;
|
|
852
|
+
}
|
|
853
|
+
/**
|
|
854
|
+
* `POST /v1/environments/enroll` — daemon side. The one-time `codai_env_…`
|
|
855
|
+
* token in the body is the only credential; the client's API key header is
|
|
856
|
+
* ignored by this route. Managed environments additionally receive a
|
|
857
|
+
* freshly minted `api_key`, returned exactly once.
|
|
858
|
+
*/
|
|
859
|
+
enroll(body, opts = {}) {
|
|
860
|
+
return this.http.json("/v1/environments/enroll", {
|
|
861
|
+
body,
|
|
862
|
+
ext: opts.ext,
|
|
863
|
+
signal: opts.signal,
|
|
864
|
+
// The token is consumed on success; a retried POST would 401.
|
|
865
|
+
noRetry: true
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
/** `GET /v1/environments/{id}` — environment, your role, members, ports, recent events. */
|
|
869
|
+
get(envId, opts = {}) {
|
|
870
|
+
return this.http.json(envPath(envId), {
|
|
871
|
+
ext: opts.ext,
|
|
872
|
+
signal: opts.signal
|
|
873
|
+
});
|
|
874
|
+
}
|
|
875
|
+
/** `PATCH /v1/environments/{id}` — `name` and/or `idle_timeout_minutes` (5..1440). */
|
|
876
|
+
async update(envId, body, opts = {}) {
|
|
877
|
+
const raw = await this.http.json(envPath(envId), {
|
|
878
|
+
method: "PATCH",
|
|
879
|
+
body,
|
|
880
|
+
ext: opts.ext,
|
|
881
|
+
signal: opts.signal
|
|
882
|
+
});
|
|
883
|
+
return raw.environment;
|
|
884
|
+
}
|
|
885
|
+
/** `POST /v1/environments/{id}/start` — managed providers only (`stopped` → `starting`). */
|
|
886
|
+
start(envId, opts = {}) {
|
|
887
|
+
return this.transition(envId, "start", opts);
|
|
888
|
+
}
|
|
889
|
+
/** `POST /v1/environments/{id}/stop` — managed providers only (`running` → `stopping`). */
|
|
890
|
+
stop(envId, opts = {}) {
|
|
891
|
+
return this.transition(envId, "stop", opts);
|
|
892
|
+
}
|
|
893
|
+
/** `POST /v1/environments/{id}/archive` — keeps history, releases the machine. */
|
|
894
|
+
archive(envId, opts = {}) {
|
|
895
|
+
return this.transition(envId, "archive", opts);
|
|
896
|
+
}
|
|
897
|
+
/** `POST /v1/environments/{id}/destroy` — owner only; terminal. */
|
|
898
|
+
destroy(envId, opts = {}) {
|
|
899
|
+
return this.transition(envId, "destroy", opts);
|
|
900
|
+
}
|
|
901
|
+
/**
|
|
902
|
+
* `POST /v1/environments/{id}/enroll-token` — `byo` only; a 30-minute
|
|
903
|
+
* one-time token for `enroll()`. Minting again replaces the previous one.
|
|
904
|
+
*/
|
|
905
|
+
enrollToken(envId, opts = {}) {
|
|
906
|
+
return this.http.json(envPath(envId, "/enroll-token"), {
|
|
907
|
+
method: "POST",
|
|
908
|
+
ext: opts.ext,
|
|
909
|
+
signal: opts.signal,
|
|
910
|
+
noRetry: true
|
|
911
|
+
});
|
|
912
|
+
}
|
|
913
|
+
transition(envId, action, opts) {
|
|
914
|
+
return this.http.json(envPath(envId, `/${action}`), {
|
|
915
|
+
method: "POST",
|
|
916
|
+
ext: opts.ext,
|
|
917
|
+
signal: opts.signal
|
|
918
|
+
});
|
|
919
|
+
}
|
|
920
|
+
};
|
|
921
|
+
|
|
672
922
|
// src/resources/health.ts
|
|
673
923
|
var Health = class {
|
|
674
924
|
constructor(http) {
|
|
@@ -921,6 +1171,221 @@ var Orgs = class {
|
|
|
921
1171
|
}
|
|
922
1172
|
};
|
|
923
1173
|
|
|
1174
|
+
// src/resources/projects.ts
|
|
1175
|
+
var Projects = class {
|
|
1176
|
+
constructor(http) {
|
|
1177
|
+
this.http = http;
|
|
1178
|
+
}
|
|
1179
|
+
http;
|
|
1180
|
+
/** `GET /v1/projects` — projects you own plus those of your orgs, newest first. */
|
|
1181
|
+
async list(opts = {}) {
|
|
1182
|
+
const raw = await this.http.json("/v1/projects", {
|
|
1183
|
+
ext: opts.ext,
|
|
1184
|
+
signal: opts.signal
|
|
1185
|
+
});
|
|
1186
|
+
return [...raw.projects ?? []];
|
|
1187
|
+
}
|
|
1188
|
+
/** `POST /v1/projects` — 409 `slug_taken` when the slug is already yours. */
|
|
1189
|
+
async create(body, opts = {}) {
|
|
1190
|
+
const raw = await this.http.json("/v1/projects", {
|
|
1191
|
+
body,
|
|
1192
|
+
ext: opts.ext,
|
|
1193
|
+
signal: opts.signal
|
|
1194
|
+
});
|
|
1195
|
+
return raw.project;
|
|
1196
|
+
}
|
|
1197
|
+
/** `GET /v1/projects/{id}` — the project plus every environment in it. */
|
|
1198
|
+
get(projectId, opts = {}) {
|
|
1199
|
+
return this.http.json(`/v1/projects/${encodeURIComponent(projectId)}`, {
|
|
1200
|
+
ext: opts.ext,
|
|
1201
|
+
signal: opts.signal
|
|
1202
|
+
});
|
|
1203
|
+
}
|
|
1204
|
+
/** `PATCH /v1/projects/{id}` — owner or org owner/admin; the slug cannot change. */
|
|
1205
|
+
async update(projectId, body, opts = {}) {
|
|
1206
|
+
const raw = await this.http.json(
|
|
1207
|
+
`/v1/projects/${encodeURIComponent(projectId)}`,
|
|
1208
|
+
{ method: "PATCH", body, ext: opts.ext, signal: opts.signal }
|
|
1209
|
+
);
|
|
1210
|
+
return raw.project;
|
|
1211
|
+
}
|
|
1212
|
+
/** `DELETE /v1/projects/{id}` — 409 `project_has_environments` until all are destroyed. */
|
|
1213
|
+
delete(projectId, opts = {}) {
|
|
1214
|
+
return this.http.json(`/v1/projects/${encodeURIComponent(projectId)}`, {
|
|
1215
|
+
method: "DELETE",
|
|
1216
|
+
ext: opts.ext,
|
|
1217
|
+
signal: opts.signal
|
|
1218
|
+
});
|
|
1219
|
+
}
|
|
1220
|
+
};
|
|
1221
|
+
|
|
1222
|
+
// src/resources/resolve.ts
|
|
1223
|
+
var RESOLVE_TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
1224
|
+
"resolved",
|
|
1225
|
+
"failed",
|
|
1226
|
+
"declined",
|
|
1227
|
+
"error"
|
|
1228
|
+
]);
|
|
1229
|
+
var ResolveError = class extends CodaiError {
|
|
1230
|
+
/** The `error` field of the body: a message, or Zod `flatten()` details on a 400. */
|
|
1231
|
+
detail;
|
|
1232
|
+
constructor(message, status, body, meta = {}) {
|
|
1233
|
+
super(message, status, body, meta);
|
|
1234
|
+
this.name = "ResolveError";
|
|
1235
|
+
this.detail = extractDetail(body);
|
|
1236
|
+
}
|
|
1237
|
+
};
|
|
1238
|
+
var ResolveInsufficientFundsError = class extends ResolveError {
|
|
1239
|
+
/** Wallet balance, in `currency` units (EUR micros). */
|
|
1240
|
+
balance;
|
|
1241
|
+
/** Amount the hold needs, in `currency` units (EUR micros). */
|
|
1242
|
+
required;
|
|
1243
|
+
currency;
|
|
1244
|
+
/** pay.codai.ro checkout link for the shortfall — open it, then retry `accept()`. */
|
|
1245
|
+
topupUrl;
|
|
1246
|
+
constructor(message, body, meta = {}) {
|
|
1247
|
+
super(message, 402, body, meta);
|
|
1248
|
+
this.name = "ResolveInsufficientFundsError";
|
|
1249
|
+
this.balance = body.balance;
|
|
1250
|
+
this.required = body.required;
|
|
1251
|
+
this.currency = body.currency;
|
|
1252
|
+
this.topupUrl = body.topup_url;
|
|
1253
|
+
}
|
|
1254
|
+
};
|
|
1255
|
+
var Resolve = class {
|
|
1256
|
+
constructor(http) {
|
|
1257
|
+
this.http = http;
|
|
1258
|
+
}
|
|
1259
|
+
http;
|
|
1260
|
+
/**
|
|
1261
|
+
* `POST /v1/resolve/jobs` — submit a public GitHub repo + issue for triage.
|
|
1262
|
+
* Returns a quote (`status: 'quoted'`), a free-tier auto-accept
|
|
1263
|
+
* (`status: 'accepted'`) or a decline (`status: 'declined'`). Never retried:
|
|
1264
|
+
* a retry could create a second job.
|
|
1265
|
+
*/
|
|
1266
|
+
submit(body, opts = {}) {
|
|
1267
|
+
if (!body.issue_url && !body.issue_text)
|
|
1268
|
+
throw new TypeError("resolve.submit: one of issue_url or issue_text is required");
|
|
1269
|
+
return this.call("/v1/resolve/jobs", {
|
|
1270
|
+
method: "POST",
|
|
1271
|
+
body,
|
|
1272
|
+
noRetry: true,
|
|
1273
|
+
signal: opts.signal
|
|
1274
|
+
});
|
|
1275
|
+
}
|
|
1276
|
+
/** `GET /v1/resolve/jobs/{id}` — status, quote, reasons, cost and attestation pointer. */
|
|
1277
|
+
get(id, opts = {}) {
|
|
1278
|
+
return this.call(`/v1/resolve/jobs/${encodeURIComponent(id)}`, {
|
|
1279
|
+
signal: opts.signal
|
|
1280
|
+
});
|
|
1281
|
+
}
|
|
1282
|
+
/**
|
|
1283
|
+
* `POST /v1/resolve/jobs/{id}/accept` — accept a paid quote and start the job.
|
|
1284
|
+
* Throws `ResolveInsufficientFundsError` (402, carries `topupUrl`) when the
|
|
1285
|
+
* wallet is short, `ResolveError` 409 when the job is not `quoted`.
|
|
1286
|
+
*/
|
|
1287
|
+
accept(id, opts = {}) {
|
|
1288
|
+
return this.call(`/v1/resolve/jobs/${encodeURIComponent(id)}/accept`, {
|
|
1289
|
+
method: "POST",
|
|
1290
|
+
rawBody: "",
|
|
1291
|
+
// no body — sent with content-length: 0
|
|
1292
|
+
noRetry: true,
|
|
1293
|
+
signal: opts.signal
|
|
1294
|
+
});
|
|
1295
|
+
}
|
|
1296
|
+
/**
|
|
1297
|
+
* `GET /v1/resolve/attestations/{id}` — public execution proof (no auth needed
|
|
1298
|
+
* server-side). Accepts the attestation id or the job's `attestation_url`.
|
|
1299
|
+
*/
|
|
1300
|
+
attestation(idOrUrl, opts = {}) {
|
|
1301
|
+
const id = idOrUrl.replace(/^.*\/v1\/resolve\/attestations\//, "");
|
|
1302
|
+
return this.call(`/v1/resolve/attestations/${encodeURIComponent(id)}`, {
|
|
1303
|
+
signal: opts.signal
|
|
1304
|
+
});
|
|
1305
|
+
}
|
|
1306
|
+
/** `GET /health` — liveness of the Resolve service. */
|
|
1307
|
+
health(opts = {}) {
|
|
1308
|
+
return this.call("/health", { signal: opts.signal });
|
|
1309
|
+
}
|
|
1310
|
+
/**
|
|
1311
|
+
* Poll `get(id)` until the job reaches a terminal status (`resolved`,
|
|
1312
|
+
* `failed`, `declined`, `error`) or one of `opts.until`. A `quoted` job
|
|
1313
|
+
* does not move until you `accept()` it.
|
|
1314
|
+
*/
|
|
1315
|
+
async waitFor(id, opts = {}) {
|
|
1316
|
+
const intervalMs = opts.intervalMs ?? 5e3;
|
|
1317
|
+
const timeoutMs = opts.timeoutMs ?? 18e5;
|
|
1318
|
+
const until = new Set(opts.until ?? RESOLVE_TERMINAL_STATUSES);
|
|
1319
|
+
const deadline = Date.now() + timeoutMs;
|
|
1320
|
+
for (; ; ) {
|
|
1321
|
+
const job = await this.get(id, { signal: opts.signal });
|
|
1322
|
+
opts.onPoll?.(job);
|
|
1323
|
+
if (until.has(job.status)) return job;
|
|
1324
|
+
const left = deadline - Date.now();
|
|
1325
|
+
if (left <= 0)
|
|
1326
|
+
throw new ResolveError(
|
|
1327
|
+
`codai-resolve job ${id} still ${job.status} after ${timeoutMs} ms`,
|
|
1328
|
+
0,
|
|
1329
|
+
job
|
|
1330
|
+
);
|
|
1331
|
+
await abortableSleep(Math.min(intervalMs, left), opts.signal);
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
async call(path, init) {
|
|
1335
|
+
try {
|
|
1336
|
+
return await this.http.json(path, init);
|
|
1337
|
+
} catch (err) {
|
|
1338
|
+
throw toResolveError(path, err);
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
};
|
|
1342
|
+
function extractDetail(body) {
|
|
1343
|
+
if (body && typeof body === "object" && "error" in body) {
|
|
1344
|
+
const e = body.error;
|
|
1345
|
+
if (typeof e === "string") return e;
|
|
1346
|
+
if (e && typeof e === "object") return e;
|
|
1347
|
+
}
|
|
1348
|
+
return null;
|
|
1349
|
+
}
|
|
1350
|
+
function isInsufficientFunds(body) {
|
|
1351
|
+
return !!body && typeof body === "object" && body.error === "insufficient_funds" && typeof body.topup_url === "string";
|
|
1352
|
+
}
|
|
1353
|
+
function toResolveError(path, err) {
|
|
1354
|
+
if (!(err instanceof CodaiError) || err instanceof ResolveError) return err;
|
|
1355
|
+
if (err.status === 0) return err;
|
|
1356
|
+
const meta = { requestId: err.requestId, retryAfter: err.retryAfter };
|
|
1357
|
+
if (err.status === 402 && isInsufficientFunds(err.body)) {
|
|
1358
|
+
const b = err.body;
|
|
1359
|
+
return new ResolveInsufficientFundsError(
|
|
1360
|
+
`codai-resolve ${path} \u2192 402: insufficient funds (balance ${b.balance}, required ${b.required} ${b.currency}); top up at ${b.topup_url}`,
|
|
1361
|
+
b,
|
|
1362
|
+
meta
|
|
1363
|
+
);
|
|
1364
|
+
}
|
|
1365
|
+
const detail = extractDetail(err.body);
|
|
1366
|
+
const text = detail === null ? "" : `: ${typeof detail === "string" ? detail : JSON.stringify(detail)}`;
|
|
1367
|
+
return new ResolveError(
|
|
1368
|
+
`codai-resolve ${path} \u2192 ${err.status}${text}`,
|
|
1369
|
+
err.status,
|
|
1370
|
+
err.body,
|
|
1371
|
+
meta
|
|
1372
|
+
);
|
|
1373
|
+
}
|
|
1374
|
+
function abortableSleep(ms, signal) {
|
|
1375
|
+
return new Promise((resolve, reject) => {
|
|
1376
|
+
if (signal?.aborted) return reject(signal.reason);
|
|
1377
|
+
const onAbort = () => {
|
|
1378
|
+
clearTimeout(t);
|
|
1379
|
+
reject(signal?.reason);
|
|
1380
|
+
};
|
|
1381
|
+
const t = setTimeout(() => {
|
|
1382
|
+
signal?.removeEventListener("abort", onAbort);
|
|
1383
|
+
resolve();
|
|
1384
|
+
}, ms);
|
|
1385
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
1386
|
+
});
|
|
1387
|
+
}
|
|
1388
|
+
|
|
924
1389
|
// src/resources/responses.ts
|
|
925
1390
|
var Responses = class {
|
|
926
1391
|
constructor(http) {
|
|
@@ -1215,6 +1680,26 @@ var Sessions = class {
|
|
|
1215
1680
|
}
|
|
1216
1681
|
};
|
|
1217
1682
|
|
|
1683
|
+
// src/resources/system-one.ts
|
|
1684
|
+
var SystemOne = class {
|
|
1685
|
+
constructor(http) {
|
|
1686
|
+
this.http = http;
|
|
1687
|
+
}
|
|
1688
|
+
http;
|
|
1689
|
+
/**
|
|
1690
|
+
* Ask one or more typed questions about `state`. Throws on 503 `s1_unavailable` like any other
|
|
1691
|
+
* error — keep a local fallback and catch it: the gateway never substitutes a generative model.
|
|
1692
|
+
*/
|
|
1693
|
+
async create(body, opts = {}) {
|
|
1694
|
+
const res = await this.http.request("/v1/systemone", {
|
|
1695
|
+
body,
|
|
1696
|
+
ext: opts.ext,
|
|
1697
|
+
signal: opts.signal
|
|
1698
|
+
});
|
|
1699
|
+
return await res.json();
|
|
1700
|
+
}
|
|
1701
|
+
};
|
|
1702
|
+
|
|
1218
1703
|
// src/resources/tasks.ts
|
|
1219
1704
|
var Tasks = class {
|
|
1220
1705
|
constructor(http) {
|
|
@@ -1262,6 +1747,99 @@ var Tasks = class {
|
|
|
1262
1747
|
}
|
|
1263
1748
|
};
|
|
1264
1749
|
|
|
1750
|
+
// src/resources/triggers.ts
|
|
1751
|
+
var Triggers = class {
|
|
1752
|
+
constructor(http) {
|
|
1753
|
+
this.http = http;
|
|
1754
|
+
}
|
|
1755
|
+
http;
|
|
1756
|
+
/** `GET /v1/triggers` — never includes the signing secret. */
|
|
1757
|
+
list(opts = {}) {
|
|
1758
|
+
return this.http.json("/v1/triggers", { ext: opts.ext, signal: opts.signal });
|
|
1759
|
+
}
|
|
1760
|
+
/** `POST /v1/triggers` — the response carries the signing `secret` ONCE. */
|
|
1761
|
+
create(body, opts = {}) {
|
|
1762
|
+
return this.http.json("/v1/triggers", { method: "POST", body, ext: opts.ext, signal: opts.signal });
|
|
1763
|
+
}
|
|
1764
|
+
/** `PATCH /v1/triggers/{id}` — name / enabled / policy. */
|
|
1765
|
+
update(id, body, opts = {}) {
|
|
1766
|
+
return this.http.json(`/v1/triggers/${encodeURIComponent(id)}`, { method: "PATCH", body, ext: opts.ext, signal: opts.signal });
|
|
1767
|
+
}
|
|
1768
|
+
/** `DELETE /v1/triggers/{id}` — its hook URL stops working immediately. */
|
|
1769
|
+
delete(id, opts = {}) {
|
|
1770
|
+
return this.http.json(`/v1/triggers/${encodeURIComponent(id)}`, { method: "DELETE", ext: opts.ext, signal: opts.signal });
|
|
1771
|
+
}
|
|
1772
|
+
/** `POST /v1/triggers/{id}/rotate-secret` — new secret, shown once. */
|
|
1773
|
+
rotateSecret(id, opts = {}) {
|
|
1774
|
+
return this.http.json(`/v1/triggers/${encodeURIComponent(id)}/rotate-secret`, { method: "POST", body: {}, ext: opts.ext, signal: opts.signal });
|
|
1775
|
+
}
|
|
1776
|
+
/** `POST /v1/triggers/{id}/test` — manual fire through the full pipeline; returns the decision + reason. */
|
|
1777
|
+
/** `PUT /v1/triggers/{id}/secret` — store a secret issued by the source (e.g. a Sentry integration's client secret). */
|
|
1778
|
+
setSecret(id, secret, opts = {}) {
|
|
1779
|
+
return this.http.json(`/v1/triggers/${encodeURIComponent(id)}/secret`, { method: "PUT", body: { secret }, ext: opts.ext, signal: opts.signal, noRetry: true });
|
|
1780
|
+
}
|
|
1781
|
+
/** `POST /v1/triggers/{id}/test` — manual fire through the full pipeline; returns the decision + reason. */
|
|
1782
|
+
test(id, body = {}, opts = {}) {
|
|
1783
|
+
return this.http.json(`/v1/triggers/${encodeURIComponent(id)}/test`, { method: "POST", body, ext: opts.ext, signal: opts.signal });
|
|
1784
|
+
}
|
|
1785
|
+
/** `GET /v1/triggers/{id}/events?limit=` — recent deliveries with decisions. */
|
|
1786
|
+
events(id, limit, opts = {}) {
|
|
1787
|
+
return this.http.json(`/v1/triggers/${encodeURIComponent(id)}/events`, { query: { limit }, ext: opts.ext, signal: opts.signal });
|
|
1788
|
+
}
|
|
1789
|
+
/**
|
|
1790
|
+
* `POST /v1/hooks/{id}` — send an event to a `generic` / `form` trigger from your own code. Signs the body
|
|
1791
|
+
* (`X-Codai-Signature: t=<unix>,v1=HMAC_SHA256(secret, "<t>.<body>")`, WebCrypto — Node 20+, browsers, Deno,
|
|
1792
|
+
* Workers). `deliveryId` makes retries idempotent. The hook needs no API key (the signature is the auth).
|
|
1793
|
+
*/
|
|
1794
|
+
async fireHook(id, secret, event, opts = {}) {
|
|
1795
|
+
const raw = JSON.stringify(event);
|
|
1796
|
+
const t = Math.floor(Date.now() / 1e3);
|
|
1797
|
+
const key = await crypto.subtle.importKey("raw", new TextEncoder().encode(secret), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
1798
|
+
const mac = new Uint8Array(await crypto.subtle.sign("HMAC", key, new TextEncoder().encode(`${t}.${raw}`)));
|
|
1799
|
+
const v1 = Array.from(mac, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
1800
|
+
return this.http.json(`/v1/hooks/${encodeURIComponent(id)}`, {
|
|
1801
|
+
method: "POST",
|
|
1802
|
+
rawBody: raw,
|
|
1803
|
+
ext: {
|
|
1804
|
+
...opts.ext,
|
|
1805
|
+
headers: {
|
|
1806
|
+
...opts.ext?.headers,
|
|
1807
|
+
"Content-Type": "application/json",
|
|
1808
|
+
"x-codai-signature": `t=${t},v1=${v1}`,
|
|
1809
|
+
...opts.deliveryId ? { "x-codai-delivery": opts.deliveryId } : {}
|
|
1810
|
+
}
|
|
1811
|
+
},
|
|
1812
|
+
signal: opts.signal
|
|
1813
|
+
});
|
|
1814
|
+
}
|
|
1815
|
+
};
|
|
1816
|
+
var Notifications = class {
|
|
1817
|
+
constructor(http) {
|
|
1818
|
+
this.http = http;
|
|
1819
|
+
}
|
|
1820
|
+
http;
|
|
1821
|
+
/** `GET /v1/notifications?unread=1&limit=` — newest first. */
|
|
1822
|
+
list(query = {}, opts = {}) {
|
|
1823
|
+
return this.http.json("/v1/notifications", {
|
|
1824
|
+
query: { unread: query.unread ? "1" : void 0, limit: query.limit },
|
|
1825
|
+
ext: opts.ext,
|
|
1826
|
+
signal: opts.signal
|
|
1827
|
+
});
|
|
1828
|
+
}
|
|
1829
|
+
/** `POST /v1/notifications/read` — `ids` omitted = every unread one. */
|
|
1830
|
+
markRead(ids, opts = {}) {
|
|
1831
|
+
return this.http.json("/v1/notifications/read", { method: "POST", body: ids ? { ids } : {}, ext: opts.ext, signal: opts.signal });
|
|
1832
|
+
}
|
|
1833
|
+
/** `DELETE /v1/notifications/:id` — `{ deleted: 0 }` when the id is missing or not yours. */
|
|
1834
|
+
delete(id, opts = {}) {
|
|
1835
|
+
return this.http.json(`/v1/notifications/${encodeURIComponent(String(id))}`, { method: "DELETE", ext: opts.ext, signal: opts.signal });
|
|
1836
|
+
}
|
|
1837
|
+
/** `POST /v1/notifications/delete` — 1..200 ids; ids of other users are skipped. */
|
|
1838
|
+
deleteMany(ids, opts = {}) {
|
|
1839
|
+
return this.http.json("/v1/notifications/delete", { method: "POST", body: { ids }, ext: opts.ext, signal: opts.signal });
|
|
1840
|
+
}
|
|
1841
|
+
};
|
|
1842
|
+
|
|
1265
1843
|
// src/resources/tokens.ts
|
|
1266
1844
|
var Tokens = class {
|
|
1267
1845
|
constructor(http) {
|
|
@@ -1314,6 +1892,7 @@ var OPERATION_METHODS = {
|
|
|
1314
1892
|
createMessage: "messages.create",
|
|
1315
1893
|
// Embeddings & Audio
|
|
1316
1894
|
createEmbeddings: "embeddings.create",
|
|
1895
|
+
createSystemOne: "systemOne.create",
|
|
1317
1896
|
createTranscription: "audio.transcribe",
|
|
1318
1897
|
createSpeech: "audio.speech",
|
|
1319
1898
|
createEphemeralToken: "tokens.create",
|
|
@@ -1340,6 +1919,20 @@ var OPERATION_METHODS = {
|
|
|
1340
1919
|
getTaskStats: "tasks.stats",
|
|
1341
1920
|
getTask: "tasks.get",
|
|
1342
1921
|
confirmTask: "tasks.confirm",
|
|
1922
|
+
// Event triggers + inbox
|
|
1923
|
+
listTriggers: "triggers.list",
|
|
1924
|
+
createTrigger: "triggers.create",
|
|
1925
|
+
updateTrigger: "triggers.update",
|
|
1926
|
+
deleteTrigger: "triggers.delete",
|
|
1927
|
+
rotateTriggerSecret: "triggers.rotateSecret",
|
|
1928
|
+
setTriggerSecret: "triggers.setSecret",
|
|
1929
|
+
testTrigger: "triggers.test",
|
|
1930
|
+
listTriggerEvents: "triggers.events",
|
|
1931
|
+
receiveTriggerHook: "triggers.fireHook",
|
|
1932
|
+
listNotifications: "notifications.list",
|
|
1933
|
+
markNotificationsRead: "notifications.markRead",
|
|
1934
|
+
deleteNotification: "notifications.delete",
|
|
1935
|
+
deleteNotifications: "notifications.deleteMany",
|
|
1343
1936
|
// Sessions
|
|
1344
1937
|
createSession: "sessions.create",
|
|
1345
1938
|
listSessions: "sessions.list",
|
|
@@ -1376,6 +1969,39 @@ var OPERATION_METHODS = {
|
|
|
1376
1969
|
listOrgMembers: "orgs.members.list",
|
|
1377
1970
|
addOrgMember: "orgs.members.add",
|
|
1378
1971
|
removeOrgMember: "orgs.members.remove",
|
|
1972
|
+
// Projects
|
|
1973
|
+
listProjects: "projects.list",
|
|
1974
|
+
createProject: "projects.create",
|
|
1975
|
+
getProject: "projects.get",
|
|
1976
|
+
updateProject: "projects.update",
|
|
1977
|
+
deleteProject: "projects.delete",
|
|
1978
|
+
// Environments
|
|
1979
|
+
listEnvironments: "environments.list",
|
|
1980
|
+
createEnvironment: "environments.create",
|
|
1981
|
+
enrollEnvironment: "environments.enroll",
|
|
1982
|
+
getEnvironment: "environments.get",
|
|
1983
|
+
updateEnvironment: "environments.update",
|
|
1984
|
+
startEnvironment: "environments.start",
|
|
1985
|
+
stopEnvironment: "environments.stop",
|
|
1986
|
+
archiveEnvironment: "environments.archive",
|
|
1987
|
+
destroyEnvironment: "environments.destroy",
|
|
1988
|
+
createEnvironmentEnrollToken: "environments.enrollToken",
|
|
1989
|
+
listEnvironmentMembers: "environments.members.list",
|
|
1990
|
+
addEnvironmentMember: "environments.members.add",
|
|
1991
|
+
setMyEnvironmentSshKey: "environments.members.setSshKey",
|
|
1992
|
+
setEnvironmentMemberRole: "environments.members.setRole",
|
|
1993
|
+
removeEnvironmentMember: "environments.members.remove",
|
|
1994
|
+
issueMyEnvironmentSshCert: "environments.members.sshCert",
|
|
1995
|
+
getEnvironmentSshCa: "environments.sshCa",
|
|
1996
|
+
listEnvironmentTasks: "environments.tasks.list",
|
|
1997
|
+
createEnvironmentTask: "environments.tasks.create",
|
|
1998
|
+
getEnvironmentTask: "environments.tasks.get",
|
|
1999
|
+
listEnvironmentPorts: "environments.ports.list",
|
|
2000
|
+
setEnvironmentPort: "environments.ports.set",
|
|
2001
|
+
removeEnvironmentPort: "environments.ports.remove",
|
|
2002
|
+
listEnvironmentSecrets: "environments.secrets.list",
|
|
2003
|
+
setEnvironmentSecret: "environments.secrets.set",
|
|
2004
|
+
removeEnvironmentSecret: "environments.secrets.remove",
|
|
1379
2005
|
// Account
|
|
1380
2006
|
getAccount: "account.get",
|
|
1381
2007
|
patchAccount: "account.update",
|
|
@@ -1388,6 +2014,13 @@ var STREAMING_OPERATIONS = /* @__PURE__ */ new Set([
|
|
|
1388
2014
|
"streamSession",
|
|
1389
2015
|
"streamHost"
|
|
1390
2016
|
]);
|
|
2017
|
+
var RESOLVE_OPERATION_METHODS = {
|
|
2018
|
+
resolveHealth: "resolve.health",
|
|
2019
|
+
createResolveJob: "resolve.submit",
|
|
2020
|
+
getResolveJob: "resolve.get",
|
|
2021
|
+
acceptResolveJob: "resolve.accept",
|
|
2022
|
+
getResolveAttestation: "resolve.attestation"
|
|
2023
|
+
};
|
|
1391
2024
|
|
|
1392
2025
|
// src/index.ts
|
|
1393
2026
|
var Codai = class {
|
|
@@ -1398,20 +2031,30 @@ var Codai = class {
|
|
|
1398
2031
|
responses;
|
|
1399
2032
|
embeddings;
|
|
1400
2033
|
audio;
|
|
2034
|
+
/** Typed decisions from codai-s1 (`systemOne.create({ state, questions })`). */
|
|
2035
|
+
systemOne;
|
|
1401
2036
|
tokens;
|
|
1402
2037
|
models;
|
|
1403
2038
|
health;
|
|
1404
2039
|
agents;
|
|
1405
2040
|
tools;
|
|
1406
2041
|
tasks;
|
|
2042
|
+
/** Event triggers — webhooks that notify you or start agent sessions. */
|
|
2043
|
+
triggers;
|
|
2044
|
+
/** Inbox of trigger / cloud-task notifications. */
|
|
2045
|
+
notifications;
|
|
1407
2046
|
sessions;
|
|
1408
2047
|
devices;
|
|
1409
2048
|
hosts;
|
|
1410
2049
|
orgs;
|
|
2050
|
+
projects;
|
|
2051
|
+
environments;
|
|
1411
2052
|
account;
|
|
1412
2053
|
receipt;
|
|
1413
2054
|
feedback;
|
|
1414
2055
|
phoneModels;
|
|
2056
|
+
/** codai Resolve — execution-verified bug fixes (separate host, `resolveBaseUrl`). */
|
|
2057
|
+
resolve;
|
|
1415
2058
|
constructor(opts) {
|
|
1416
2059
|
if (!opts.apiKey) throw new Error("Codai: apiKey is required");
|
|
1417
2060
|
this.http = new HttpClient({
|
|
@@ -1433,18 +2076,33 @@ var Codai = class {
|
|
|
1433
2076
|
this.messages = new Messages(http);
|
|
1434
2077
|
this.responses = new Responses(http);
|
|
1435
2078
|
this.audio = new Audio(http);
|
|
2079
|
+
this.systemOne = new SystemOne(http);
|
|
1436
2080
|
this.tokens = new Tokens(http);
|
|
1437
2081
|
this.health = new Health(http);
|
|
1438
2082
|
this.agents = new Agents(http);
|
|
1439
2083
|
this.tools = new Tools(http);
|
|
1440
2084
|
this.tasks = new Tasks(http);
|
|
2085
|
+
this.triggers = new Triggers(http);
|
|
2086
|
+
this.notifications = new Notifications(http);
|
|
1441
2087
|
this.sessions = new Sessions(http);
|
|
1442
2088
|
this.devices = new Devices(http);
|
|
1443
2089
|
this.hosts = new Hosts(http);
|
|
1444
2090
|
this.orgs = new Orgs(http);
|
|
2091
|
+
this.projects = new Projects(http);
|
|
2092
|
+
this.environments = new Environments(http);
|
|
1445
2093
|
this.account = new Account(http);
|
|
1446
2094
|
this.receipt = new Receipts(http);
|
|
1447
2095
|
this.phoneModels = new PhoneModels(http);
|
|
2096
|
+
this.resolve = new Resolve(
|
|
2097
|
+
new HttpClient({
|
|
2098
|
+
apiKey: opts.apiKey,
|
|
2099
|
+
baseUrl: opts.resolveBaseUrl ?? "https://resolve.codai.ro",
|
|
2100
|
+
timeoutMs: opts.timeoutMs ?? 12e4,
|
|
2101
|
+
maxRetries: opts.maxRetries ?? 2,
|
|
2102
|
+
fetch: opts.fetch,
|
|
2103
|
+
defaults: opts.client ? { client: opts.client } : {}
|
|
2104
|
+
})
|
|
2105
|
+
);
|
|
1448
2106
|
this.chat = callable(
|
|
1449
2107
|
new Chat(http),
|
|
1450
2108
|
(o) => this.chat.completions.create(this.legacyBody(o), {
|
|
@@ -1529,6 +2187,6 @@ function allKeys(obj) {
|
|
|
1529
2187
|
}
|
|
1530
2188
|
var index_default = Codai;
|
|
1531
2189
|
|
|
1532
|
-
export { Account, AgentRuns, Agents, Audio, Chat, ChatCompletions, Codai, CodaiError, Devices, Embeddings, Feedback, Health, Hosts, HttpClient, Messages, Models, OPERATION_METHODS, OrgMembers, Orgs, PhoneModels, Receipts, Responses, STREAMING_OPERATIONS, SessionControls, SessionEvents, SessionLease, SessionShares, Sessions, Tasks, Tokens, Tools, index_default as default, extensionHeaders, frameJson, mergeToolCall, readSse };
|
|
2190
|
+
export { Account, AgentRuns, Agents, Audio, Chat, ChatCompletions, Codai, CodaiError, Devices, Embeddings, EnvironmentMembers, EnvironmentPorts, EnvironmentSecrets, EnvironmentTasks, Environments, Feedback, Health, Hosts, HttpClient, Messages, Models, Notifications, OPERATION_METHODS, OrgMembers, Orgs, PhoneModels, Projects, RESOLVE_OPERATION_METHODS, RESOLVE_TERMINAL_STATUSES, Receipts, Resolve, ResolveError, ResolveInsufficientFundsError, Responses, STREAMING_OPERATIONS, SessionControls, SessionEvents, SessionLease, SessionShares, Sessions, Tasks, Tokens, Tools, Triggers, index_default as default, extensionHeaders, frameJson, mergeToolCall, readSse };
|
|
1533
2191
|
//# sourceMappingURL=index.js.map
|
|
1534
2192
|
//# sourceMappingURL=index.js.map
|