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/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