tila-sdk 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,7 +1,6 @@
1
- import { createRequire } from 'module';
2
1
  import { z } from 'zod';
3
2
 
4
- // src/client.ts
3
+ // ../schemas/dist/entity.js
5
4
  z.object({
6
5
  id: z.string(),
7
6
  type: z.string(),
@@ -10,7 +9,8 @@ z.object({
10
9
  archived: z.number().int().default(0),
11
10
  created_at: z.number().int(),
12
11
  updated_at: z.number().int(),
13
- created_by: z.string()
12
+ created_by: z.string(),
13
+ tags: z.array(z.string()).default([])
14
14
  });
15
15
  var ClaimModeSchema = z.enum(["exclusive", "owner", "presence"]);
16
16
  z.object({
@@ -72,7 +72,8 @@ z.object({
72
72
  produced_at: z.number().int(),
73
73
  produced_by: z.string(),
74
74
  expires_at: z.number().int().nullable(),
75
- tombstoned: z.number().int().default(0)
75
+ tombstoned: z.number().int().default(0),
76
+ tags: z.array(z.string()).default([])
76
77
  });
77
78
  z.object({
78
79
  entity_id: z.string(),
@@ -160,15 +161,15 @@ z.object({
160
161
  payload: z.unknown().optional(),
161
162
  ttl_ms: z.number().int().min(1e3).max(864e5).optional()
162
163
  });
163
- z.object({
164
+ var SendSignalResponseSchema = z.object({
164
165
  ok: z.literal(true),
165
166
  id: z.string()
166
167
  });
167
- z.object({
168
+ var InboxResponseSchema = z.object({
168
169
  ok: z.literal(true),
169
170
  signals: z.array(SignalSchema)
170
171
  });
171
- z.object({
172
+ var AckSignalResponseSchema = z.object({
172
173
  ok: z.literal(true)
173
174
  });
174
175
  z.object({
@@ -332,6 +333,21 @@ z.object({
332
333
  pages_project_name: z.string().optional(),
333
334
  infra_slug: z.string().optional()
334
335
  });
336
+ var TagSchema = z.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9_:.-]{0,63}$/, "Invalid tag format");
337
+ var TagsSchema = z.array(TagSchema).transform((tags) => {
338
+ const seen = /* @__PURE__ */ new Set();
339
+ const result = [];
340
+ for (const tag of tags) {
341
+ const lower = tag.toLowerCase();
342
+ if (!seen.has(lower)) {
343
+ seen.add(lower);
344
+ result.push(lower);
345
+ }
346
+ }
347
+ return result;
348
+ }).refine((tags) => tags.length <= 20, "may not have more than 20 tags");
349
+
350
+ // ../schemas/dist/record.js
335
351
  var RecordTypeSchema = z.string().regex(/^[a-z][a-z0-9_-]*$/, "Record type must start with lowercase letter and contain only lowercase letters, digits, underscores, and hyphens");
336
352
  var RecordKeySchema = z.string().superRefine((val, ctx) => {
337
353
  if (val.length === 0) {
@@ -408,18 +424,7 @@ var RecordKeySchema = z.string().superRefine((val, ctx) => {
408
424
  }
409
425
  }
410
426
  });
411
- var RecordTagSchema = z.array(z.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9_:.-]{0,63}$/, "Invalid tag format")).transform((tags) => {
412
- const seen = /* @__PURE__ */ new Set();
413
- const result = [];
414
- for (const tag of tags) {
415
- const lower = tag.toLowerCase();
416
- if (!seen.has(lower)) {
417
- seen.add(lower);
418
- result.push(lower);
419
- }
420
- }
421
- return result;
422
- }).refine((tags) => tags.length <= 20, "Record may not have more than 20 tags");
427
+ var RecordTagSchema = TagsSchema;
423
428
  function sortKeysDeep(v) {
424
429
  if (Array.isArray(v))
425
430
  return v.map(sortKeysDeep);
@@ -458,7 +463,7 @@ z.object({
458
463
  idempotency_key: z.string().optional(),
459
464
  metadata: z.record(z.unknown()).optional()
460
465
  });
461
- z.object({
466
+ var AcquireSuccessResponseSchema = z.object({
462
467
  ok: z.literal(true),
463
468
  fence: z.number().int(),
464
469
  expires_at: z.number().int()
@@ -468,7 +473,7 @@ z.object({
468
473
  fence: z.number().int(),
469
474
  ttl_ms: z.number().int().positive()
470
475
  });
471
- z.object({
476
+ var RenewSuccessResponseSchema = z.object({
472
477
  ok: z.literal(true),
473
478
  expires_at: z.number().int()
474
479
  });
@@ -476,10 +481,10 @@ z.object({
476
481
  resource: z.string(),
477
482
  fence: z.number().int()
478
483
  });
479
- z.object({
484
+ var ReleaseSuccessResponseSchema = z.object({
480
485
  ok: z.literal(true)
481
486
  });
482
- z.object({
487
+ var StateResponseSchema = z.object({
483
488
  ok: z.literal(true),
484
489
  claim: z.object({
485
490
  resource: z.string(),
@@ -508,16 +513,18 @@ z.object({
508
513
  z.object({
509
514
  id: z.string(),
510
515
  type: z.string(),
511
- data: z.record(z.unknown()).default({})
516
+ data: z.record(z.unknown()).default({}),
517
+ tags: TagsSchema.optional()
512
518
  });
513
519
  z.object({
514
520
  data: z.record(z.unknown()),
515
- fence: z.number().int()
521
+ fence: z.number().int(),
522
+ tags: TagsSchema.optional()
516
523
  });
517
524
  z.object({
518
525
  fence: z.number().int()
519
526
  });
520
- z.object({
527
+ var EntityResponseSchema = z.object({
521
528
  ok: z.literal(true),
522
529
  entity: z.object({
523
530
  id: z.string(),
@@ -527,7 +534,8 @@ z.object({
527
534
  archived: z.number().int(),
528
535
  created_at: z.number().int(),
529
536
  updated_at: z.number().int(),
530
- created_by: z.string()
537
+ created_by: z.string(),
538
+ tags: z.array(z.string())
531
539
  })
532
540
  });
533
541
  z.object({
@@ -540,10 +548,11 @@ z.object({
540
548
  archived: z.number().int(),
541
549
  created_at: z.number().int(),
542
550
  updated_at: z.number().int(),
543
- created_by: z.string()
551
+ created_by: z.string(),
552
+ tags: z.array(z.string())
544
553
  }))
545
554
  });
546
- z.object({
555
+ var PaginatedEntityListResponseSchema = z.object({
547
556
  ok: z.literal(true),
548
557
  entities: z.array(z.object({
549
558
  id: z.string(),
@@ -553,14 +562,15 @@ z.object({
553
562
  archived: z.number().int(),
554
563
  created_at: z.number().int(),
555
564
  updated_at: z.number().int(),
556
- created_by: z.string()
565
+ created_by: z.string(),
566
+ tags: z.array(z.string())
557
567
  })),
558
568
  total: z.number().int(),
559
569
  limit: z.number().int().nullable(),
560
570
  offset: z.number().int(),
561
571
  has_more: z.boolean()
562
572
  });
563
- z.object({
573
+ var ListReadyEntitiesResponseSchema = z.object({
564
574
  ok: z.literal(true),
565
575
  entities: z.array(z.object({
566
576
  id: z.string(),
@@ -590,7 +600,7 @@ z.object({
590
600
  ok: z.literal(true),
591
601
  entity: CompactEntitySchema
592
602
  });
593
- z.object({
603
+ var PaginatedCompactEntityListResponseSchema = z.object({
594
604
  ok: z.literal(true),
595
605
  entities: z.array(CompactEntitySchema),
596
606
  total: z.number().int(),
@@ -598,7 +608,7 @@ z.object({
598
608
  offset: z.number().int(),
599
609
  has_more: z.boolean()
600
610
  });
601
- z.object({
611
+ var SummaryResponseSchema = z.object({
602
612
  ok: z.literal(true),
603
613
  project: z.object({
604
614
  entity_count: z.number().int(),
@@ -617,7 +627,7 @@ z.object({
617
627
  }))
618
628
  })
619
629
  });
620
- z.object({
630
+ var EntityDetailResponseSchema = z.object({
621
631
  ok: z.literal(true),
622
632
  entity: z.object({
623
633
  id: z.string(),
@@ -627,11 +637,12 @@ z.object({
627
637
  archived: z.number().int(),
628
638
  created_at: z.number().int(),
629
639
  updated_at: z.number().int(),
630
- created_by: z.string()
640
+ created_by: z.string(),
641
+ tags: z.array(z.string())
631
642
  }),
632
643
  relationships: z.array(EntityRelationshipSchema).default([])
633
644
  });
634
- z.object({
645
+ var ArchiveSuccessResponseSchema = z.object({
635
646
  ok: z.literal(true)
636
647
  });
637
648
  z.object({
@@ -639,7 +650,7 @@ z.object({
639
650
  to_id: z.string().min(1),
640
651
  type: EntityRelationshipTypeSchema
641
652
  });
642
- z.object({
653
+ var CreateEntityRelationshipResponseSchema = z.object({
643
654
  ok: z.literal(true),
644
655
  created: z.boolean().default(true)
645
656
  });
@@ -648,7 +659,7 @@ z.object({
648
659
  to_id: z.string().min(1).optional(),
649
660
  type: EntityRelationshipTypeSchema.optional()
650
661
  });
651
- z.object({
662
+ var ListEntityRelationshipsResponseSchema = z.object({
652
663
  ok: z.literal(true),
653
664
  relationships: z.array(EntityRelationshipSchema)
654
665
  });
@@ -657,7 +668,7 @@ z.object({
657
668
  to_id: z.string().min(1),
658
669
  type: EntityRelationshipTypeSchema
659
670
  });
660
- z.object({
671
+ var DeleteEntityRelationshipResponseSchema = z.object({
661
672
  ok: z.literal(true),
662
673
  removed: z.boolean()
663
674
  });
@@ -668,7 +679,7 @@ z.object({
668
679
  after_seq: z.number().int().optional(),
669
680
  limit: z.number().int().positive().default(100)
670
681
  });
671
- z.object({
682
+ var JournalResponseSchema = z.object({
672
683
  ok: z.literal(true),
673
684
  events: z.array(z.object({
674
685
  seq: z.number().int(),
@@ -695,7 +706,7 @@ z.object({
695
706
  info: z.record(z.unknown())
696
707
  }))
697
708
  });
698
- z.object({
709
+ var PresenceAllListResponseSchema = z.object({
699
710
  ok: z.literal(true),
700
711
  machines: z.array(z.object({
701
712
  machine: z.string(),
@@ -704,7 +715,7 @@ z.object({
704
715
  active: z.boolean()
705
716
  }))
706
717
  });
707
- z.object({
718
+ var PresenceHeartbeatSuccessResponseSchema = z.object({
708
719
  ok: z.literal(true)
709
720
  });
710
721
  z.object({
@@ -846,7 +857,7 @@ z.object({
846
857
  slot: z.string().min(1),
847
858
  metadata: z.record(z.unknown()).default({})
848
859
  });
849
- z.object({
860
+ var EntityArtifactReferenceListResponseSchema = z.object({
850
861
  ok: z.literal(true),
851
862
  references: z.array(z.object({
852
863
  entity_id: z.string(),
@@ -856,6 +867,46 @@ z.object({
856
867
  created_at: z.number().int()
857
868
  }))
858
869
  });
870
+ function parseTagFilter(raw) {
871
+ if (!raw)
872
+ return void 0;
873
+ const parts = raw.split(",").map((s) => s.trim().toLowerCase()).filter((s) => s.length > 0);
874
+ if (parts.length === 0)
875
+ return void 0;
876
+ for (const part of parts) {
877
+ TagSchema.parse(part);
878
+ }
879
+ const unique = [...new Set(parts)];
880
+ if (unique.length > 20) {
881
+ throw new z.ZodError([
882
+ {
883
+ code: z.ZodIssueCode.too_big,
884
+ maximum: 20,
885
+ type: "array",
886
+ inclusive: true,
887
+ exact: false,
888
+ message: "tag_filter may not have more than 20 tags",
889
+ path: ["tag_filter"]
890
+ }
891
+ ]);
892
+ }
893
+ return unique;
894
+ }
895
+ var tagFilterQueryParam = z.string().optional().superRefine((v, ctx) => {
896
+ if (!v)
897
+ return;
898
+ try {
899
+ parseTagFilter(v);
900
+ } catch (err) {
901
+ if (err instanceof z.ZodError) {
902
+ for (const issue of err.issues) {
903
+ ctx.addIssue(issue);
904
+ }
905
+ } else {
906
+ throw err;
907
+ }
908
+ }
909
+ }).transform((v) => parseTagFilter(v));
859
910
  z.object({
860
911
  ok: z.literal(true),
861
912
  results: z.array(ArtifactSearchResultSchema),
@@ -866,7 +917,8 @@ z.object({
866
917
  kind: z.string().optional(),
867
918
  resource: z.string().optional(),
868
919
  source_only: z.string().optional().transform((v) => v === "true").pipe(z.boolean()),
869
- limit: z.string().optional().default("20").transform((v) => Number.parseInt(v, 10)).pipe(z.number().int().min(1).max(100))
920
+ limit: z.string().optional().default("20").transform((v) => Number.parseInt(v, 10)).pipe(z.number().int().min(1).max(100)),
921
+ tag_filter: tagFilterQueryParam
870
922
  });
871
923
  var ArtifactGrepLineSchema = z.object({
872
924
  line: z.number().int(),
@@ -884,7 +936,7 @@ var ArtifactGrepResultSchema = z.object({
884
936
  truncated: z.boolean().optional()
885
937
  // this blob hit the per-blob byte cap
886
938
  });
887
- z.object({
939
+ var ArtifactGrepResponseSchema = z.object({
888
940
  ok: z.literal(true),
889
941
  results: z.array(ArtifactGrepResultSchema),
890
942
  scanned: z.number().int(),
@@ -920,16 +972,18 @@ z.object({
920
972
  });
921
973
  z.object({
922
974
  q: z.string().min(1).max(200),
923
- limit: z.string().optional().default("20").transform((v) => Number.parseInt(v, 10)).pipe(z.number().int().min(1).max(100))
975
+ limit: z.string().optional().default("20").transform((v) => Number.parseInt(v, 10)).pipe(z.number().int().min(1).max(100)),
976
+ tag_filter: tagFilterQueryParam
924
977
  });
925
978
  z.object({
926
979
  content: z.string().min(1),
927
980
  kind: z.string().min(1),
928
981
  mime_type: z.string().default("text/markdown"),
929
982
  resource: z.string().optional(),
930
- fence: z.number().int().optional()
983
+ fence: z.number().int().optional(),
984
+ tags: TagsSchema.optional()
931
985
  });
932
- z.object({
986
+ var ArtifactPutResponseSchema = z.object({
933
987
  ok: z.literal(true),
934
988
  key: z.string(),
935
989
  bytes: z.number(),
@@ -948,7 +1002,8 @@ z.object({
948
1002
  produced_at: z.number(),
949
1003
  produced_by: z.string(),
950
1004
  expires_at: z.number().nullable(),
951
- tombstoned: z.number()
1005
+ tombstoned: z.number(),
1006
+ tags: z.array(z.string())
952
1007
  }))
953
1008
  });
954
1009
  z.object({
@@ -1035,12 +1090,15 @@ var RecordItemSchema = z.object({
1035
1090
  updated_by: z.string(),
1036
1091
  tags: z.array(z.string())
1037
1092
  });
1038
- z.object({
1093
+ RecordItemSchema.extend({
1094
+ fence: z.number().int()
1095
+ });
1096
+ var RecordGetResponseSchema = z.object({
1039
1097
  ok: z.literal(true),
1040
1098
  record: RecordItemSchema,
1041
1099
  fence: z.number().int()
1042
1100
  });
1043
- z.object({
1101
+ var RecordMutateResponseSchema = z.object({
1044
1102
  ok: z.literal(true),
1045
1103
  record: RecordItemSchema,
1046
1104
  fence: z.number().int(),
@@ -1055,7 +1113,7 @@ var RecordListItemSchema = z.object({
1055
1113
  archived: z.number().int(),
1056
1114
  tags: z.array(z.string())
1057
1115
  });
1058
- z.object({
1116
+ var RecordListResponseSchema = z.object({
1059
1117
  ok: z.literal(true),
1060
1118
  items: z.array(RecordListItemSchema),
1061
1119
  meta: z.object({
@@ -1075,9 +1133,12 @@ var RecordHistoryItemSchema = z.object({
1075
1133
  source_artifact_key: z.string().nullable(),
1076
1134
  actor: z.string(),
1077
1135
  created_at: z.number().int(),
1078
- message: z.string().nullable()
1136
+ message: z.string().nullable(),
1137
+ // Populated only when the history is requested with `includeValues=true`
1138
+ // (wire: `?values=true`). Optional so existing parsers stay compatible.
1139
+ value: z.record(z.unknown()).optional()
1079
1140
  });
1080
- z.object({
1141
+ var RecordHistoryResponseSchema = z.object({
1081
1142
  ok: z.literal(true),
1082
1143
  items: z.array(RecordHistoryItemSchema),
1083
1144
  meta: z.object({
@@ -1187,392 +1248,208 @@ z.object({
1187
1248
  z.object({
1188
1249
  resolution: z.string().optional()
1189
1250
  });
1190
- z.object({
1251
+ var GateResponseSchema = z.object({
1191
1252
  ok: z.literal(true),
1192
1253
  gate: GateSchema
1193
1254
  });
1194
- z.object({
1255
+ var GateListResponseSchema = z.object({
1195
1256
  ok: z.literal(true),
1196
1257
  gates: z.array(GateSchema)
1197
1258
  });
1198
1259
 
1199
- // src/client.ts
1200
- var require2 = createRequire(import.meta.url);
1201
- var SDK_VERSION = require2("../package.json").version;
1202
- var TilaClient = class _TilaClient {
1203
- baseUrl;
1204
- token;
1205
- validate;
1206
- timeoutMs;
1207
- extraHeaders;
1208
- constructor(opts) {
1209
- this.baseUrl = opts.baseUrl.replace(/\/+$/, "");
1210
- this.token = opts.token;
1211
- this.validate = opts.validate ?? false;
1212
- this.timeoutMs = opts.timeoutMs ?? 3e4;
1213
- this.extraHeaders = {
1214
- "X-Tila-Source": `sdk/${SDK_VERSION}`,
1215
- ...opts.extraHeaders
1216
- };
1217
- }
1218
- /**
1219
- * Creates an AbortSignal that fires after this.timeoutMs.
1220
- * Uses AbortSignal.timeout() when available (Node 18.8+, Bun 0.5+, browsers),
1221
- * falls back to manual setTimeout + AbortController for older runtimes.
1222
- *
1223
- * Note: Cloudflare Workers has supported AbortSignal.timeout() since 2023;
1224
- * the fallback branch will never execute there.
1225
- */
1226
- createAbortSignal() {
1227
- if (typeof AbortSignal.timeout === "function") {
1228
- return AbortSignal.timeout(this.timeoutMs);
1229
- }
1230
- const controller = new AbortController();
1231
- setTimeout(
1232
- () => controller.abort(
1233
- new DOMException(
1234
- "The operation was aborted due to timeout",
1235
- "TimeoutError"
1236
- )
1237
- ),
1238
- this.timeoutMs
1239
- );
1240
- return controller.signal;
1241
- }
1242
- static fromConfig(config, token) {
1243
- if (!config.worker_url) {
1244
- throw new Error(
1245
- `Cannot create TilaClient: config has no worker_url. Use 'tila project create' or set backend = "cloudflare" in .tila/config.toml.`
1260
+ // src/artifacts.ts
1261
+ function createArtifactMethods(client, projectId) {
1262
+ const base = `/projects/${projectId}/artifacts`;
1263
+ return {
1264
+ upload: Object.assign(
1265
+ function upload(input, opts) {
1266
+ if (input instanceof ReadableStream) {
1267
+ if (!opts.mimeType) {
1268
+ throw new TypeError(
1269
+ "mimeType is required when uploading a ReadableStream. Pass opts.mimeType explicitly."
1270
+ );
1271
+ }
1272
+ return new Response(input).arrayBuffer().then((bytes) => {
1273
+ const uploadFile = new Blob([bytes], {
1274
+ type: opts.mimeType
1275
+ });
1276
+ const formData2 = new FormData();
1277
+ formData2.append("file", uploadFile);
1278
+ formData2.append("kind", opts.kind);
1279
+ formData2.append("mime_type", opts.mimeType);
1280
+ if (opts.resource) formData2.append("resource", opts.resource);
1281
+ if (opts.fence !== void 0)
1282
+ formData2.append("fence", String(opts.fence));
1283
+ if (opts.flavor) formData2.append("flavor", opts.flavor);
1284
+ if (opts.tags !== void 0)
1285
+ formData2.append("tags", JSON.stringify(opts.tags));
1286
+ return client.postFormData(base, formData2);
1287
+ });
1288
+ }
1289
+ const contentType = opts.mimeType || (input instanceof File ? input.type : "") || "";
1290
+ if (!contentType) {
1291
+ throw new TypeError(
1292
+ "contentType is required for uploads when file.type is absent. Pass opts.mimeType explicitly."
1293
+ );
1294
+ }
1295
+ const formData = new FormData();
1296
+ formData.append("file", input);
1297
+ formData.append("kind", opts.kind);
1298
+ formData.append("mime_type", contentType);
1299
+ if (opts.resource) formData.append("resource", opts.resource);
1300
+ if (opts.fence !== void 0)
1301
+ formData.append("fence", String(opts.fence));
1302
+ if (opts.flavor) formData.append("flavor", opts.flavor);
1303
+ if (opts.tags !== void 0)
1304
+ formData.append("tags", JSON.stringify(opts.tags));
1305
+ return client.postFormData(base, formData);
1306
+ },
1307
+ {}
1308
+ ),
1309
+ async download(key) {
1310
+ const res = await client.requestRaw(
1311
+ "GET",
1312
+ `${base}/${encodeURIComponent(key)}`
1246
1313
  );
1247
- }
1248
- return new _TilaClient({ baseUrl: config.worker_url, token });
1249
- }
1250
- async request(method, path, opts) {
1251
- const url = new URL(path, `${this.baseUrl}/`);
1252
- if (opts?.query) {
1253
- for (const [key, value] of Object.entries(opts.query)) {
1254
- if (value !== void 0) {
1255
- url.searchParams.set(key, value);
1314
+ return {
1315
+ body: res.body ?? new ReadableStream(),
1316
+ contentType: res.headers.get("content-type") || "application/octet-stream",
1317
+ contentLength: res.headers.has("content-length") ? Number(res.headers.get("content-length")) : null
1318
+ };
1319
+ },
1320
+ async list(query) {
1321
+ const { tagFilter, ...rest } = query ?? {};
1322
+ const q = { ...rest };
1323
+ if (tagFilter?.length) q.tag_filter = tagFilter.join(",");
1324
+ return client.get(base, { query: q });
1325
+ },
1326
+ async search(q, opts) {
1327
+ const { tagFilter, ...rest } = opts ?? {};
1328
+ const query = { q, ...rest };
1329
+ if (tagFilter?.length) query.tag_filter = tagFilter.join(",");
1330
+ return client.get(`${base}/search`, { query });
1331
+ },
1332
+ async grep(pattern, opts) {
1333
+ const query = { pattern };
1334
+ if (opts?.kind) query.kind = opts.kind;
1335
+ if (opts?.resource) query.resource = opts.resource;
1336
+ if (opts?.regex) query.regex = "true";
1337
+ if (opts?.limit != null) query.limit = String(opts.limit);
1338
+ return client.get(`${base}/grep`, { query });
1339
+ },
1340
+ async addRelationship(fromKey, toKeyOrUri, type, metadata) {
1341
+ const isUri = toKeyOrUri.includes("://");
1342
+ return client.post(
1343
+ `${base}/${encodeURIComponent(fromKey)}/relationships`,
1344
+ {
1345
+ [isUri ? "to_uri" : "to_key"]: toKeyOrUri,
1346
+ type,
1347
+ metadata
1256
1348
  }
1349
+ );
1350
+ },
1351
+ async listRelationships(key) {
1352
+ return client.get(
1353
+ `${base}/${encodeURIComponent(key)}/relationships`
1354
+ );
1355
+ },
1356
+ async getLatest(kind, resource) {
1357
+ let res;
1358
+ try {
1359
+ res = await client.requestRaw("GET", `${base}/latest`, {
1360
+ query: { kind, resource }
1361
+ });
1362
+ } catch (err) {
1363
+ if (err instanceof TilaApiError && err.status === 404) return null;
1364
+ throw err;
1257
1365
  }
1258
- }
1259
- const headers = {
1260
- Authorization: `Bearer ${this.token}`,
1261
- Accept: "application/json",
1262
- ...this.extraHeaders
1263
- };
1264
- const init = {
1265
- method,
1266
- headers,
1267
- signal: this.createAbortSignal()
1268
- };
1269
- if (opts?.body !== void 0) {
1270
- headers["Content-Type"] = "application/json";
1271
- init.body = JSON.stringify(opts.body);
1272
- }
1273
- let res;
1274
- try {
1275
- res = await fetch(url.toString(), init);
1276
- } catch (err) {
1277
- if (err instanceof Error && (err.name === "AbortError" || err.name === "TimeoutError")) {
1278
- throw new Error(
1279
- `Request to ${url.origin} timed out after ${this.timeoutMs}ms`
1366
+ const body = await res.json();
1367
+ return body.pointer;
1368
+ },
1369
+ async writeText(content, opts) {
1370
+ const body = {
1371
+ content,
1372
+ kind: opts.kind,
1373
+ mime_type: opts.mimeType ?? "text/markdown",
1374
+ resource: opts.resource,
1375
+ fence: opts.fence
1376
+ };
1377
+ if (opts.tags !== void 0) body.tags = opts.tags;
1378
+ return client.post(`${base}/text`, body);
1379
+ },
1380
+ async readText(key) {
1381
+ const res = await client.requestRaw(
1382
+ "GET",
1383
+ `${base}/${encodeURIComponent(key)}`
1384
+ );
1385
+ const contentType = res.headers.get("content-type") || "application/octet-stream";
1386
+ if (!contentType.startsWith("text/")) {
1387
+ throw new TypeError(
1388
+ `Artifact ${key} has MIME type ${contentType} \u2014 readText only supports text/* artifacts`
1280
1389
  );
1281
1390
  }
1282
- throw new Error(
1283
- `Network error connecting to ${url.origin}: ${err instanceof Error ? err.message : String(err)}`
1284
- );
1285
- }
1286
- if (!res.ok) {
1287
- await this.throwApiError(res);
1288
- }
1289
- const body = await res.json();
1290
- const shouldValidate = opts?.validate ?? this.validate;
1291
- if (shouldValidate && opts?.schema) {
1292
- const result = opts.schema.safeParse(body);
1293
- if (!result.success) {
1294
- const issues = result.error.issues.map((i) => ` - ${i.path.join(".")}: ${i.message}`).join("\n");
1295
- throw new Error(
1296
- `Unexpected response shape from ${method} ${path}:
1297
- ${issues}`
1298
- );
1299
- }
1300
- return result.data;
1301
- }
1302
- return body;
1303
- }
1304
- async get(path, opts) {
1305
- return this.request("GET", path, {
1306
- schema: opts?.schema,
1307
- query: opts?.query,
1308
- validate: opts?.validate
1309
- });
1310
- }
1311
- async post(path, body, opts) {
1312
- return this.request("POST", path, {
1313
- body,
1314
- schema: opts?.schema,
1315
- validate: opts?.validate
1316
- });
1317
- }
1318
- async put(path, body, opts) {
1319
- return this.request("PUT", path, {
1320
- body,
1321
- schema: opts?.schema,
1322
- validate: opts?.validate
1323
- });
1324
- }
1325
- async patch(path, body, opts) {
1326
- return this.request("PATCH", path, {
1327
- body,
1328
- schema: opts?.schema,
1329
- validate: opts?.validate
1330
- });
1331
- }
1332
- async delete(path, opts) {
1333
- return this.request("DELETE", path, {
1334
- schema: opts?.schema,
1335
- validate: opts?.validate
1336
- });
1337
- }
1338
- async requestRaw(method, path, opts) {
1339
- const url = new URL(path, `${this.baseUrl}/`);
1340
- if (opts?.query) {
1341
- for (const [key, value] of Object.entries(opts.query)) {
1342
- if (value !== void 0) {
1343
- url.searchParams.set(key, value);
1344
- }
1345
- }
1391
+ const text = await res.text();
1392
+ return { content: text, mimeType: contentType };
1346
1393
  }
1347
- const headers = {
1348
- Authorization: `Bearer ${this.token}`,
1349
- ...this.extraHeaders
1350
- };
1351
- let res;
1352
- try {
1353
- res = await fetch(url.toString(), {
1354
- method,
1355
- headers,
1356
- signal: this.createAbortSignal()
1394
+ };
1395
+ }
1396
+
1397
+ // src/claims.ts
1398
+ function createClaimMethods(client, projectId) {
1399
+ const base = `/projects/${projectId}/claims`;
1400
+ return {
1401
+ async acquire(resource, mode, ttlMs, opts) {
1402
+ return client.post(`${base}/acquire`, {
1403
+ resource,
1404
+ mode,
1405
+ ttl_ms: ttlMs,
1406
+ ...opts
1357
1407
  });
1358
- } catch (err) {
1359
- if (err instanceof Error && (err.name === "AbortError" || err.name === "TimeoutError")) {
1360
- throw new Error(
1361
- `Request to ${url.origin} timed out after ${this.timeoutMs}ms`
1362
- );
1363
- }
1364
- throw new Error(
1365
- `Network error connecting to ${url.origin}: ${err instanceof Error ? err.message : String(err)}`
1366
- );
1367
- }
1368
- if (!res.ok) {
1369
- await this.throwApiError(res);
1370
- }
1371
- return res;
1372
- }
1373
- async postFormData(path, formData, opts) {
1374
- const url = new URL(path, `${this.baseUrl}/`);
1375
- const headers = {
1376
- Authorization: `Bearer ${this.token}`,
1377
- Accept: "application/json",
1378
- ...this.extraHeaders
1379
- };
1380
- let res;
1381
- try {
1382
- res = await fetch(url.toString(), {
1383
- method: "POST",
1384
- headers,
1385
- body: formData,
1386
- signal: this.createAbortSignal()
1408
+ },
1409
+ async renew(resource, fence, ttlMs) {
1410
+ return client.post(`${base}/renew`, {
1411
+ resource,
1412
+ fence,
1413
+ ttl_ms: ttlMs
1387
1414
  });
1388
- } catch (err) {
1389
- if (err instanceof Error && (err.name === "AbortError" || err.name === "TimeoutError")) {
1390
- throw new Error(
1391
- `Request to ${url.origin} timed out after ${this.timeoutMs}ms`
1392
- );
1393
- }
1394
- throw new Error(
1395
- `Network error connecting to ${url.origin}: ${err instanceof Error ? err.message : String(err)}`
1415
+ },
1416
+ async release(resource, fence) {
1417
+ return client.post(`${base}/release`, {
1418
+ resource,
1419
+ fence
1420
+ });
1421
+ },
1422
+ async list() {
1423
+ return client.get(base);
1424
+ },
1425
+ async get(resource) {
1426
+ return client.get(
1427
+ `${base}/${encodeURIComponent(resource)}`
1396
1428
  );
1397
1429
  }
1398
- if (!res.ok) {
1399
- await this.throwApiError(res);
1400
- }
1401
- const body = await res.json();
1402
- const shouldValidate = opts?.validate ?? this.validate;
1403
- if (shouldValidate && opts?.schema) {
1404
- const result = opts.schema.safeParse(body);
1405
- if (!result.success) {
1406
- const issues = result.error.issues.map((i) => ` - ${i.path.join(".")}: ${i.message}`).join("\n");
1407
- throw new Error(
1408
- `Unexpected response shape from POST ${path}:
1409
- ${issues}`
1410
- );
1411
- }
1412
- return result.data;
1413
- }
1414
- return body;
1415
- }
1416
- async throwApiError(res) {
1417
- try {
1418
- const body = await res.json();
1419
- const parsed = ErrorEnvelopeSchema.safeParse(body);
1420
- if (parsed.success) {
1421
- const { code, message, retryable } = parsed.data.error;
1422
- throw new TilaApiError(res.status, code, message, retryable);
1423
- }
1424
- } catch (err) {
1425
- if (err instanceof TilaApiError) throw err;
1426
- }
1427
- throw new TilaApiError(
1428
- res.status,
1429
- "UNKNOWN",
1430
- `HTTP ${res.status}: ${res.statusText}`,
1431
- false
1432
- );
1433
- }
1434
- };
1435
- var TilaApiError = class extends Error {
1436
- constructor(status, code, message, retryable) {
1437
- super(message);
1438
- this.status = status;
1439
- this.code = code;
1440
- this.retryable = retryable;
1441
- this.name = "TilaApiError";
1442
- }
1443
- status;
1444
- code;
1445
- retryable;
1446
- };
1447
- function isTilaApiError(err) {
1448
- return err instanceof TilaApiError;
1449
- }
1450
- async function exchangeGitHubToken(baseUrl, projectId, githubToken) {
1451
- const url = `${baseUrl.replace(/\/+$/, "")}/api/auth/github/exchange`;
1452
- let res;
1453
- try {
1454
- res = await fetch(url, {
1455
- method: "POST",
1456
- headers: { "Content-Type": "application/json" },
1457
- body: JSON.stringify({
1458
- project_id: projectId,
1459
- github_token: githubToken
1460
- })
1461
- });
1462
- } catch (err) {
1463
- throw new Error(
1464
- `Network error during GitHub token exchange: ${err instanceof Error ? err.message : String(err)}`
1465
- );
1466
- }
1467
- if (!res.ok) {
1468
- try {
1469
- const body2 = await res.json();
1470
- const parsed = ErrorEnvelopeSchema.safeParse(body2);
1471
- if (parsed.success) {
1472
- const { code, message, retryable } = parsed.data.error;
1473
- throw new TilaApiError(res.status, code, message, retryable);
1474
- }
1475
- } catch (err) {
1476
- if (err instanceof TilaApiError) throw err;
1477
- }
1478
- throw new TilaApiError(
1479
- res.status,
1480
- "UNKNOWN",
1481
- `HTTP ${res.status}: ${res.statusText}`,
1482
- false
1483
- );
1484
- }
1485
- const body = await res.json();
1486
- if (!body.session_token || typeof body.expires_at !== "number") {
1487
- throw new TypeError(
1488
- "Exchange returned unexpected response shape: missing session_token or expires_at"
1489
- );
1490
- }
1491
- return {
1492
- sessionToken: body.session_token,
1493
- expiresAt: body.expires_at,
1494
- permission: body.permission ?? "read"
1495
1430
  };
1496
1431
  }
1497
1432
 
1498
- // src/retry.ts
1499
- async function withRetry(fn, opts) {
1500
- const maxRetries = opts?.maxRetries ?? 3;
1501
- const baseDelayMs = opts?.baseDelayMs ?? 200;
1502
- const maxDelayMs = opts?.maxDelayMs ?? 3e4;
1503
- const jitter = opts?.jitter ?? true;
1504
- for (let attempt = 0; attempt <= maxRetries; attempt++) {
1505
- try {
1506
- return await fn();
1507
- } catch (err) {
1508
- if (isTilaApiError(err) && err.retryable === false) {
1509
- throw err;
1510
- }
1511
- if (attempt === maxRetries) {
1512
- throw err;
1513
- }
1514
- const cap = Math.min(maxDelayMs, baseDelayMs * 2 ** attempt);
1515
- const sleepMs = jitter ? Math.random() * cap : cap;
1516
- await new Promise((resolve) => setTimeout(resolve, sleepMs));
1517
- }
1518
- }
1519
- throw new Error("withRetry: unreachable");
1520
- }
1521
-
1522
- // src/error-codes.ts
1523
- var TILA_ERRORS = {
1524
- // Auth / middleware (worker layer — SCREAMING_SNAKE_CASE wire values)
1525
- UNAUTHORIZED: "UNAUTHORIZED",
1526
- SESSION_EXPIRED: "SESSION_EXPIRED",
1527
- RATE_LIMITED: "RATE_LIMITED",
1528
- PERMISSION_DENIED: "PERMISSION_DENIED",
1529
- PROJECT_MISMATCH: "PROJECT_MISMATCH",
1530
- CSRF_MISSING_ORIGIN: "CSRF_MISSING_ORIGIN",
1531
- CSRF_ORIGIN_MISMATCH: "CSRF_ORIGIN_MISMATCH",
1532
- INTERNAL_ERROR: "INTERNAL_ERROR",
1533
- DO_UNREACHABLE: "do-unreachable",
1534
- // Auth endpoint specific
1535
- REPO_NOT_ALLOWED: "REPO_NOT_ALLOWED",
1536
- GITHUB_AUTH_FAILED: "GITHUB_AUTH_FAILED",
1537
- HMAC_NOT_CONFIGURED: "HMAC_NOT_CONFIGURED",
1538
- // Token endpoint specific
1539
- TOKEN_NAME_CONFLICT: "TOKEN_NAME_CONFLICT",
1540
- TOKEN_AUTHZ_DENIED: "TOKEN_AUTHZ_DENIED",
1541
- TOKEN_NOT_FOUND: "TOKEN_NOT_FOUND",
1542
- // Validation (worker layer uses SCREAMING_SNAKE for this code)
1543
- VALIDATION_ERROR: "VALIDATION_ERROR",
1544
- // DO errors (project-do-router — kebab-case wire values)
1545
- STALE_FENCE: "stale-fence",
1546
- NOT_FOUND: "not-found",
1547
- GATE_ALREADY_SETTLED: "gate-already-settled",
1548
- NO_FENCE: "no-fence",
1549
- INTERNAL: "internal",
1550
- CONSTRAINT_VIOLATION: "constraint-violation",
1551
- IDEMPOTENCY_KEY_CONFLICT: "idempotency-key-conflict",
1552
- // DO-layer validation uses kebab-case (distinct from VALIDATION_ERROR above)
1553
- VALIDATION_ERROR_DO: "validation-error",
1554
- ALREADY_HELD: "already-held",
1555
- RENEW_FAILED: "renew-failed",
1556
- BAD_REQUEST: "bad-request",
1557
- MISSING_QUERY: "missing-query",
1558
- INVALID_QUERY: "invalid-query",
1559
- INVALID_SLOT: "invalid-slot",
1560
- INVALID_RELATIONSHIP_TYPE: "invalid-relationship-type",
1561
- // Fallback (SDK-generated when response is unparseable)
1562
- UNKNOWN: "UNKNOWN"
1563
- };
1564
-
1565
1433
  // src/entities.ts
1566
1434
  function _createMethods(client, base) {
1567
1435
  return {
1568
- async create(id, type, data) {
1569
- return client.post(base, { id, type, data });
1436
+ async create(id, type, data, tags) {
1437
+ return client.post(base, {
1438
+ id,
1439
+ type,
1440
+ data,
1441
+ ...tags !== void 0 ? { tags } : {}
1442
+ });
1570
1443
  },
1571
1444
  async get(id) {
1572
1445
  return client.get(`${base}/${id}`);
1573
1446
  },
1574
1447
  async list(query) {
1575
- return client.get(base, { query });
1448
+ const { tagFilter, compact, ...rest } = query ?? {};
1449
+ const q = { ...rest };
1450
+ if (tagFilter?.length) q.tag_filter = tagFilter.join(",");
1451
+ if (compact) q.compact = "true";
1452
+ return client.get(base, { query: q });
1576
1453
  },
1577
1454
  async update(id, data, fence) {
1578
1455
  return client.patch(`${base}/${id}`, { data, fence });
@@ -1584,13 +1461,34 @@ function _createMethods(client, base) {
1584
1461
  },
1585
1462
  async addRelationship(fromId, toId, type) {
1586
1463
  return client.post(
1587
- `${base}/${fromId}/relationships`,
1464
+ `${base}/relationships`,
1588
1465
  {
1466
+ from_id: fromId,
1589
1467
  to_id: toId,
1590
1468
  type
1591
1469
  }
1592
1470
  );
1593
1471
  },
1472
+ async listRelationships(filter) {
1473
+ const query = {
1474
+ from_id: filter?.fromId,
1475
+ to_id: filter?.toId,
1476
+ type: filter?.type
1477
+ };
1478
+ return client.get(
1479
+ `${base}/relationships`,
1480
+ { query }
1481
+ );
1482
+ },
1483
+ async ready(query) {
1484
+ const q = {
1485
+ type: query?.type,
1486
+ parent: query?.parent,
1487
+ limit: query?.limit !== void 0 ? String(query.limit) : void 0
1488
+ };
1489
+ if (query?.includeSoftBlocked) q["include-soft-blocked"] = "true";
1490
+ return client.get(`${base}/ready`, { query: q });
1491
+ },
1594
1492
  async addArtifactRef(entityId, artifactKey, slot, metadata) {
1595
1493
  return client.post(`${base}/${entityId}/artifact-refs`, {
1596
1494
  artifact_key: artifactKey,
@@ -1605,366 +1503,663 @@ function _createMethods(client, base) {
1605
1503
  }
1606
1504
  };
1607
1505
  }
1608
- function createTaskMethods(client, projectId) {
1609
- return _createMethods(client, `/projects/${projectId}/tasks`);
1610
- }
1611
- function createEntityMethods(client, projectId) {
1612
- return _createMethods(client, `/projects/${projectId}/entities`);
1613
- }
1614
- function createWorkUnitMethods(client, projectId) {
1615
- return _createMethods(client, `/projects/${projectId}/work-units`);
1616
- }
1506
+ function createTaskMethods(client, projectId) {
1507
+ return _createMethods(client, `/projects/${projectId}/tasks`);
1508
+ }
1509
+ function createEntityMethods(client, projectId) {
1510
+ return _createMethods(client, `/projects/${projectId}/entities`);
1511
+ }
1512
+ function createWorkUnitMethods(client, projectId) {
1513
+ return _createMethods(client, `/projects/${projectId}/work-units`);
1514
+ }
1515
+
1516
+ // src/gates.ts
1517
+ function createGateMethods(client, projectId) {
1518
+ const base = `/projects/${projectId}/gates`;
1519
+ return {
1520
+ /** List gates with optional filters. GET /projects/:id/gates */
1521
+ async list(query) {
1522
+ return client.get(base, { query });
1523
+ },
1524
+ /** Create a new gate. POST /projects/:id/gates */
1525
+ async create(req) {
1526
+ return client.post(base, req);
1527
+ },
1528
+ /** Resolve a gate. POST /projects/:id/gates/:gateId/resolve */
1529
+ async resolve(gateId, req) {
1530
+ return client.post(`${base}/${gateId}/resolve`, req ?? {});
1531
+ },
1532
+ /** Delete a gate. DELETE /projects/:id/gates/:gateId */
1533
+ async remove(gateId) {
1534
+ return client.delete(`${base}/${gateId}`);
1535
+ }
1536
+ };
1537
+ }
1538
+
1539
+ // src/journal.ts
1540
+ function createJournalMethods(client, projectId) {
1541
+ const base = `/projects/${projectId}/journal`;
1542
+ return {
1543
+ async query(opts) {
1544
+ return client.get(base, {
1545
+ query: {
1546
+ resource: opts?.resource,
1547
+ kind: opts?.kind,
1548
+ after_seq: opts?.after_seq,
1549
+ limit: opts?.limit
1550
+ }
1551
+ });
1552
+ }
1553
+ };
1554
+ }
1555
+
1556
+ // src/presence.ts
1557
+ function createPresenceMethods(client, projectId) {
1558
+ const base = `/projects/${projectId}/presence`;
1559
+ return {
1560
+ async heartbeat(machine, info) {
1561
+ return client.post(
1562
+ `${base}/heartbeat`,
1563
+ {
1564
+ machine,
1565
+ info: info ?? {}
1566
+ }
1567
+ );
1568
+ },
1569
+ async list() {
1570
+ return client.get(base);
1571
+ },
1572
+ /**
1573
+ * List all presence records across all machines, including whether each is active.
1574
+ * Hits GET /projects/:projectId/presence/all
1575
+ */
1576
+ async listAll() {
1577
+ return client.get(`${base}/all`);
1578
+ }
1579
+ };
1580
+ }
1581
+
1582
+ // src/records.ts
1583
+ function encodeKey(key) {
1584
+ return key.split("/").map(encodeURIComponent).join("/");
1585
+ }
1586
+ function createRecordMethods(client, projectId) {
1587
+ const base = `/projects/${projectId}/records`;
1588
+ return {
1589
+ async create(type, req) {
1590
+ return client.post(`${base}/${type}`, req);
1591
+ },
1592
+ async set(type, key, req) {
1593
+ return client.put(
1594
+ `${base}/${type}/${encodeKey(key)}`,
1595
+ req
1596
+ );
1597
+ },
1598
+ async get(type, key) {
1599
+ return client.get(`${base}/${type}/${encodeKey(key)}`);
1600
+ },
1601
+ async patch(type, key, req) {
1602
+ return client.patch(
1603
+ `${base}/${type}/${encodeKey(key)}`,
1604
+ req
1605
+ );
1606
+ },
1607
+ async archive(type, key, req) {
1608
+ return client.post(
1609
+ `${base}/${type}/~/archive/${encodeKey(key)}`,
1610
+ req
1611
+ );
1612
+ },
1613
+ async unarchive(type, key, req) {
1614
+ return client.post(
1615
+ `${base}/${type}/~/unarchive/${encodeKey(key)}`,
1616
+ req
1617
+ );
1618
+ },
1619
+ async history(type, key, opts) {
1620
+ const query = {};
1621
+ if (opts?.limit !== void 0) query.limit = String(opts.limit);
1622
+ if (opts?.values !== void 0) query.values = String(opts.values);
1623
+ return client.get(
1624
+ `${base}/${type}/~/history/${encodeKey(key)}`,
1625
+ { query }
1626
+ );
1627
+ },
1628
+ async list(type, query) {
1629
+ const { tagFilter, ...rest } = query ?? {};
1630
+ const q = { ...rest };
1631
+ if (tagFilter?.length) q.tag_filter = tagFilter.join(",");
1632
+ return client.get(`${base}/${type}`, { query: q });
1633
+ },
1634
+ async types() {
1635
+ return client.get(`${base}/_types`);
1636
+ },
1637
+ async typesInUse() {
1638
+ const raw = await client.get(`${base}/_types`);
1639
+ return { ok: true, types: raw.in_use_types ?? [] };
1640
+ }
1641
+ };
1642
+ }
1643
+
1644
+ // src/schema.ts
1645
+ function createSchemaMethods(client, projectId) {
1646
+ const base = `/projects/${projectId}/schema`;
1647
+ return {
1648
+ async get() {
1649
+ return client.get(base);
1650
+ },
1651
+ async apply(schema, strategy) {
1652
+ const definition = typeof schema === "string" ? schema : JSON.stringify(schema);
1653
+ return client.post(base, { definition, strategy });
1654
+ },
1655
+ async history(opts) {
1656
+ return client.get(`${base}/history`, { query: opts });
1657
+ }
1658
+ };
1659
+ }
1660
+
1661
+ // src/search.ts
1662
+ function createSearchMethods(client, projectId) {
1663
+ const base = `/projects/${projectId}`;
1664
+ return {
1665
+ async search(q, opts) {
1666
+ const query = { q };
1667
+ if (opts?.limit !== void 0) query.limit = String(opts.limit);
1668
+ if (opts?.tagFilter?.length) query.tag_filter = opts.tagFilter.join(",");
1669
+ return client.get(`${base}/search`, { query });
1670
+ }
1671
+ };
1672
+ }
1673
+
1674
+ // src/signals.ts
1675
+ function createSignalMethods(client, projectId) {
1676
+ const base = `/projects/${projectId}/signals`;
1677
+ return {
1678
+ /** Fetch the signal inbox for the current token. GET /projects/:id/signals */
1679
+ async inbox() {
1680
+ return client.get(base);
1681
+ },
1682
+ /** Send a signal to a target. POST /projects/:id/signals/send */
1683
+ async send(req) {
1684
+ return client.post(`${base}/send`, req);
1685
+ },
1686
+ /** Acknowledge a signal. POST /projects/:id/signals/:signalId/ack */
1687
+ async ack(signalId) {
1688
+ return client.post(`${base}/${signalId}/ack`, {});
1689
+ }
1690
+ };
1691
+ }
1692
+
1693
+ // src/summary.ts
1694
+ function createSummaryMethods(client, projectId) {
1695
+ return {
1696
+ /** Get project summary. GET /projects/:id/summary */
1697
+ async get() {
1698
+ return client.get(`/projects/${projectId}/summary`);
1699
+ }
1700
+ };
1701
+ }
1702
+
1703
+ // src/templates.ts
1704
+ function createTemplateMethods(client, projectId) {
1705
+ const base = `/projects/${projectId}/templates`;
1706
+ return {
1707
+ /** Instantiate an entity template. POST /projects/:id/templates/instantiate */
1708
+ async instantiate(req) {
1709
+ return client.post(
1710
+ `${base}/instantiate`,
1711
+ req
1712
+ );
1713
+ },
1714
+ /** List available templates from the project schema. GET /projects/:id/templates */
1715
+ async list() {
1716
+ return client.get(base);
1717
+ }
1718
+ };
1719
+ }
1617
1720
 
1618
- // src/claims.ts
1619
- function createClaimMethods(client, projectId) {
1620
- const base = `/projects/${projectId}/claims`;
1721
+ // src/tokens.ts
1722
+ function createTokenMethods(client) {
1723
+ const base = "/api/tokens";
1621
1724
  return {
1622
- async acquire(resource, mode, ttlMs, opts) {
1623
- return client.post(`${base}/acquire`, {
1624
- resource,
1625
- mode,
1626
- ttl_ms: ttlMs,
1627
- ...opts
1628
- });
1629
- },
1630
- async renew(resource, fence, ttlMs) {
1631
- return client.post(`${base}/renew`, {
1632
- resource,
1633
- fence,
1634
- ttl_ms: ttlMs
1635
- });
1725
+ async issue(name, note) {
1726
+ return client.post(base, { name, note });
1636
1727
  },
1637
- async release(resource, fence) {
1638
- return client.post(`${base}/release`, {
1639
- resource,
1640
- fence
1641
- });
1728
+ async revoke(name) {
1729
+ return client.delete(
1730
+ `${base}/${encodeURIComponent(name)}`
1731
+ );
1642
1732
  },
1643
1733
  async list() {
1644
1734
  return client.get(base);
1645
- },
1646
- async get(resource) {
1647
- return client.get(
1648
- `${base}/${encodeURIComponent(resource)}`
1649
- );
1650
1735
  }
1651
1736
  };
1652
1737
  }
1653
1738
 
1654
- // src/artifacts.ts
1655
- function createArtifactMethods(client, projectId) {
1656
- const base = `/projects/${projectId}/artifacts`;
1657
- return {
1658
- upload: Object.assign(
1659
- function upload(input, opts) {
1660
- if (input instanceof ReadableStream) {
1661
- if (!opts.mimeType) {
1662
- throw new TypeError(
1663
- "mimeType is required when uploading a ReadableStream. Pass opts.mimeType explicitly."
1664
- );
1665
- }
1666
- return new Response(input).arrayBuffer().then((bytes) => {
1667
- const uploadFile = new Blob([bytes], {
1668
- type: opts.mimeType
1669
- });
1670
- const formData2 = new FormData();
1671
- formData2.append("file", uploadFile);
1672
- formData2.append("kind", opts.kind);
1673
- formData2.append("mime_type", opts.mimeType);
1674
- if (opts.resource) formData2.append("resource", opts.resource);
1675
- if (opts.fence !== void 0)
1676
- formData2.append("fence", String(opts.fence));
1677
- if (opts.flavor) formData2.append("flavor", opts.flavor);
1678
- return client.postFormData(base, formData2);
1679
- });
1680
- }
1681
- const contentType = opts.mimeType || (input instanceof File ? input.type : "") || "";
1682
- if (!contentType) {
1683
- throw new TypeError(
1684
- "contentType is required for uploads when file.type is absent. Pass opts.mimeType explicitly."
1685
- );
1739
+ // src/version.ts
1740
+ var SDK_VERSION = "0.2.0";
1741
+
1742
+ // src/client.ts
1743
+ var TilaClient = class _TilaClient {
1744
+ baseUrl;
1745
+ token;
1746
+ validate;
1747
+ timeoutMs;
1748
+ extraHeaders;
1749
+ constructor(opts) {
1750
+ this.baseUrl = opts.baseUrl.replace(/\/+$/, "");
1751
+ this.token = opts.token;
1752
+ this.validate = opts.validate ?? false;
1753
+ this.timeoutMs = opts.timeoutMs ?? 3e4;
1754
+ this.extraHeaders = {
1755
+ "X-Tila-Source": `sdk/${SDK_VERSION}`,
1756
+ ...opts.extraHeaders
1757
+ };
1758
+ }
1759
+ /**
1760
+ * Creates an AbortSignal that fires after this.timeoutMs.
1761
+ * Uses AbortSignal.timeout() when available (Node 18.8+, Bun 0.5+, browsers),
1762
+ * falls back to manual setTimeout + AbortController for older runtimes.
1763
+ *
1764
+ * Note: Cloudflare Workers has supported AbortSignal.timeout() since 2023;
1765
+ * the fallback branch will never execute there.
1766
+ */
1767
+ createAbortSignal() {
1768
+ if (typeof AbortSignal.timeout === "function") {
1769
+ return AbortSignal.timeout(this.timeoutMs);
1770
+ }
1771
+ const controller = new AbortController();
1772
+ setTimeout(
1773
+ () => controller.abort(
1774
+ new DOMException(
1775
+ "The operation was aborted due to timeout",
1776
+ "TimeoutError"
1777
+ )
1778
+ ),
1779
+ this.timeoutMs
1780
+ );
1781
+ return controller.signal;
1782
+ }
1783
+ static fromConfig(config, token, opts) {
1784
+ if (config.backend === "local") {
1785
+ throw new Error(
1786
+ `Cannot create an HTTP TilaClient for a local backend (backend = "local"). The local backend runs in-process on SQLite \u2014 use createTila(config) (which routes to the in-process backend) or import createTilaLocal from 'tila-sdk/local' directly.`
1787
+ );
1788
+ }
1789
+ if (!config.worker_url) {
1790
+ throw new Error(
1791
+ `Cannot create TilaClient: config has no worker_url. Use 'tila project create' or set backend = "cloudflare" in .tila/config.toml.`
1792
+ );
1793
+ }
1794
+ return new _TilaClient({
1795
+ baseUrl: config.worker_url,
1796
+ token,
1797
+ // Optional caller attribution (e.g. mcp-server/<version>). When omitted,
1798
+ // the constructor's default X-Tila-Source (sdk/<version>) applies.
1799
+ ...opts?.extraHeaders ? { extraHeaders: opts.extraHeaders } : {}
1800
+ });
1801
+ }
1802
+ async request(method, path, opts) {
1803
+ const url = new URL(path, `${this.baseUrl}/`);
1804
+ if (opts?.query) {
1805
+ for (const [key, value] of Object.entries(opts.query)) {
1806
+ if (value !== void 0) {
1807
+ url.searchParams.set(key, value);
1686
1808
  }
1687
- const formData = new FormData();
1688
- formData.append("file", input);
1689
- formData.append("kind", opts.kind);
1690
- formData.append("mime_type", contentType);
1691
- if (opts.resource) formData.append("resource", opts.resource);
1692
- if (opts.fence !== void 0)
1693
- formData.append("fence", String(opts.fence));
1694
- if (opts.flavor) formData.append("flavor", opts.flavor);
1695
- return client.postFormData(base, formData);
1696
- },
1697
- {}
1698
- ),
1699
- async download(key) {
1700
- const res = await client.requestRaw(
1701
- "GET",
1702
- `${base}/${encodeURIComponent(key)}`
1809
+ }
1810
+ }
1811
+ const headers = {
1812
+ Authorization: `Bearer ${this.token}`,
1813
+ Accept: "application/json",
1814
+ ...this.extraHeaders
1815
+ };
1816
+ const init = {
1817
+ method,
1818
+ headers,
1819
+ signal: this.createAbortSignal()
1820
+ };
1821
+ if (opts?.body !== void 0) {
1822
+ headers["Content-Type"] = "application/json";
1823
+ init.body = JSON.stringify(opts.body);
1824
+ }
1825
+ let res;
1826
+ try {
1827
+ res = await fetch(url.toString(), init);
1828
+ } catch (err) {
1829
+ if (err instanceof Error && (err.name === "AbortError" || err.name === "TimeoutError")) {
1830
+ throw new Error(
1831
+ `Request to ${url.origin} timed out after ${this.timeoutMs}ms`
1832
+ );
1833
+ }
1834
+ throw new Error(
1835
+ `Network error connecting to ${url.origin}: ${err instanceof Error ? err.message : String(err)}`
1703
1836
  );
1704
- return {
1705
- body: res.body ?? new ReadableStream(),
1706
- contentType: res.headers.get("content-type") || "application/octet-stream",
1707
- contentLength: res.headers.has("content-length") ? Number(res.headers.get("content-length")) : null
1708
- };
1709
- },
1710
- async list(query) {
1711
- return client.get(base, { query });
1712
- },
1713
- async search(q, opts) {
1714
- return client.get(`${base}/search`, {
1715
- query: { q, ...opts }
1716
- });
1717
- },
1718
- async grep(pattern, opts) {
1719
- const query = { pattern };
1720
- if (opts?.kind) query.kind = opts.kind;
1721
- if (opts?.resource) query.resource = opts.resource;
1722
- if (opts?.regex) query.regex = "true";
1723
- if (opts?.limit != null) query.limit = String(opts.limit);
1724
- return client.get(`${base}/grep`, { query });
1725
- },
1726
- async addRelationship(fromKey, toKeyOrUri, type, metadata) {
1727
- const isUri = toKeyOrUri.includes("://");
1728
- return client.post(
1729
- `${base}/${encodeURIComponent(fromKey)}/relationships`,
1730
- {
1731
- [isUri ? "to_uri" : "to_key"]: toKeyOrUri,
1732
- type,
1733
- metadata
1837
+ }
1838
+ if (!res.ok) {
1839
+ await this.throwApiError(res);
1840
+ }
1841
+ const body = await res.json();
1842
+ const shouldValidate = opts?.validate ?? this.validate;
1843
+ if (shouldValidate && opts?.schema) {
1844
+ const result = opts.schema.safeParse(body);
1845
+ if (!result.success) {
1846
+ const issues = result.error.issues.map((i) => ` - ${i.path.join(".")}: ${i.message}`).join("\n");
1847
+ throw new Error(
1848
+ `Unexpected response shape from ${method} ${path}:
1849
+ ${issues}`
1850
+ );
1851
+ }
1852
+ return result.data;
1853
+ }
1854
+ return body;
1855
+ }
1856
+ async get(path, opts) {
1857
+ return this.request("GET", path, {
1858
+ schema: opts?.schema,
1859
+ query: opts?.query,
1860
+ validate: opts?.validate
1861
+ });
1862
+ }
1863
+ async post(path, body, opts) {
1864
+ return this.request("POST", path, {
1865
+ body,
1866
+ schema: opts?.schema,
1867
+ validate: opts?.validate
1868
+ });
1869
+ }
1870
+ async put(path, body, opts) {
1871
+ return this.request("PUT", path, {
1872
+ body,
1873
+ schema: opts?.schema,
1874
+ validate: opts?.validate
1875
+ });
1876
+ }
1877
+ async patch(path, body, opts) {
1878
+ return this.request("PATCH", path, {
1879
+ body,
1880
+ schema: opts?.schema,
1881
+ validate: opts?.validate
1882
+ });
1883
+ }
1884
+ async delete(path, opts) {
1885
+ return this.request("DELETE", path, {
1886
+ schema: opts?.schema,
1887
+ validate: opts?.validate
1888
+ });
1889
+ }
1890
+ async requestRaw(method, path, opts) {
1891
+ const url = new URL(path, `${this.baseUrl}/`);
1892
+ if (opts?.query) {
1893
+ for (const [key, value] of Object.entries(opts.query)) {
1894
+ if (value !== void 0) {
1895
+ url.searchParams.set(key, value);
1734
1896
  }
1735
- );
1736
- },
1737
- async listRelationships(key) {
1738
- return client.get(
1739
- `${base}/${encodeURIComponent(key)}/relationships`
1740
- );
1741
- },
1742
- async getLatest(kind, resource) {
1743
- const res = await client.requestRaw("GET", `${base}/latest`, {
1744
- query: { kind, resource }
1897
+ }
1898
+ }
1899
+ const headers = {
1900
+ Authorization: `Bearer ${this.token}`,
1901
+ ...this.extraHeaders
1902
+ };
1903
+ let res;
1904
+ try {
1905
+ res = await fetch(url.toString(), {
1906
+ method,
1907
+ headers,
1908
+ signal: this.createAbortSignal()
1745
1909
  });
1746
- if (res.status === 404) return null;
1747
- if (!res.ok) {
1748
- const body2 = await res.json().catch(() => ({}));
1910
+ } catch (err) {
1911
+ if (err instanceof Error && (err.name === "AbortError" || err.name === "TimeoutError")) {
1749
1912
  throw new Error(
1750
- `getLatest failed with status ${res.status}: ${JSON.stringify(body2)}`
1913
+ `Request to ${url.origin} timed out after ${this.timeoutMs}ms`
1751
1914
  );
1752
1915
  }
1753
- const body = await res.json();
1754
- return body.pointer;
1755
- },
1756
- async writeText(content, opts) {
1757
- return client.post(`${base}/text`, {
1758
- content,
1759
- kind: opts.kind,
1760
- mime_type: opts.mimeType ?? "text/markdown",
1761
- resource: opts.resource,
1762
- fence: opts.fence
1763
- });
1764
- },
1765
- async readText(key) {
1766
- const res = await client.requestRaw(
1767
- "GET",
1768
- `${base}/${encodeURIComponent(key)}`
1916
+ throw new Error(
1917
+ `Network error connecting to ${url.origin}: ${err instanceof Error ? err.message : String(err)}`
1769
1918
  );
1770
- const contentType = res.headers.get("content-type") || "application/octet-stream";
1771
- if (!contentType.startsWith("text/")) {
1772
- throw new TypeError(
1773
- `Artifact ${key} has MIME type ${contentType} \u2014 readText only supports text/* artifacts`
1919
+ }
1920
+ if (!res.ok) {
1921
+ await this.throwApiError(res);
1922
+ }
1923
+ return res;
1924
+ }
1925
+ async postFormData(path, formData, opts) {
1926
+ const url = new URL(path, `${this.baseUrl}/`);
1927
+ const headers = {
1928
+ Authorization: `Bearer ${this.token}`,
1929
+ Accept: "application/json",
1930
+ ...this.extraHeaders
1931
+ };
1932
+ let res;
1933
+ try {
1934
+ res = await fetch(url.toString(), {
1935
+ method: "POST",
1936
+ headers,
1937
+ body: formData,
1938
+ signal: this.createAbortSignal()
1939
+ });
1940
+ } catch (err) {
1941
+ if (err instanceof Error && (err.name === "AbortError" || err.name === "TimeoutError")) {
1942
+ throw new Error(
1943
+ `Request to ${url.origin} timed out after ${this.timeoutMs}ms`
1774
1944
  );
1775
1945
  }
1776
- const text = await res.text();
1777
- return { content: text, mimeType: contentType };
1778
- }
1779
- };
1780
- }
1781
-
1782
- // src/tokens.ts
1783
- function createTokenMethods(client) {
1784
- const base = "/api/tokens";
1785
- return {
1786
- async issue(name, note) {
1787
- return client.post(base, { name, note });
1788
- },
1789
- async revoke(name) {
1790
- return client.delete(
1791
- `${base}/${encodeURIComponent(name)}`
1946
+ throw new Error(
1947
+ `Network error connecting to ${url.origin}: ${err instanceof Error ? err.message : String(err)}`
1792
1948
  );
1793
- },
1794
- async list() {
1795
- return client.get(base);
1796
1949
  }
1797
- };
1798
- }
1799
-
1800
- // src/journal.ts
1801
- function createJournalMethods(client, projectId) {
1802
- const base = `/projects/${projectId}/journal`;
1803
- return {
1804
- async query(opts) {
1805
- return client.get(base, { query: opts });
1950
+ if (!res.ok) {
1951
+ await this.throwApiError(res);
1806
1952
  }
1807
- };
1808
- }
1809
-
1810
- // src/presence.ts
1811
- function createPresenceMethods(client, projectId) {
1812
- const base = `/projects/${projectId}/presence`;
1813
- return {
1814
- async heartbeat(machine, ttlMs) {
1815
- return client.post(base, {
1816
- machine,
1817
- ttl_ms: ttlMs
1818
- });
1819
- },
1820
- async list() {
1821
- return client.get(base);
1822
- },
1823
- /**
1824
- * List all presence records across all machines, including whether each is active.
1825
- * Hits GET /projects/:projectId/presence/all
1826
- */
1827
- async listAll() {
1828
- return client.get(`${base}/all`);
1953
+ const body = await res.json();
1954
+ const shouldValidate = opts?.validate ?? this.validate;
1955
+ if (shouldValidate && opts?.schema) {
1956
+ const result = opts.schema.safeParse(body);
1957
+ if (!result.success) {
1958
+ const issues = result.error.issues.map((i) => ` - ${i.path.join(".")}: ${i.message}`).join("\n");
1959
+ throw new Error(
1960
+ `Unexpected response shape from POST ${path}:
1961
+ ${issues}`
1962
+ );
1963
+ }
1964
+ return result.data;
1829
1965
  }
1830
- };
1831
- }
1832
-
1833
- // src/records.ts
1834
- function encodeKey(key) {
1835
- return key.split("/").map(encodeURIComponent).join("/");
1966
+ return body;
1967
+ }
1968
+ async throwApiError(res) {
1969
+ try {
1970
+ const body = await res.json();
1971
+ const parsed = ErrorEnvelopeSchema.safeParse(body);
1972
+ if (parsed.success) {
1973
+ const { code, message, retryable } = parsed.data.error;
1974
+ throw new TilaApiError(res.status, code, message, retryable);
1975
+ }
1976
+ } catch (err) {
1977
+ if (err instanceof TilaApiError) throw err;
1978
+ }
1979
+ throw new TilaApiError(
1980
+ res.status,
1981
+ "UNKNOWN",
1982
+ `HTTP ${res.status}: ${res.statusText}`,
1983
+ false
1984
+ );
1985
+ }
1986
+ };
1987
+ var TilaApiError = class extends Error {
1988
+ constructor(status, code, message, retryable) {
1989
+ super(message);
1990
+ this.status = status;
1991
+ this.code = code;
1992
+ this.retryable = retryable;
1993
+ this.name = "TilaApiError";
1994
+ }
1995
+ status;
1996
+ code;
1997
+ retryable;
1998
+ };
1999
+ function isTilaApiError(err) {
2000
+ return err instanceof TilaApiError;
1836
2001
  }
1837
- function createRecordMethods(client, projectId) {
1838
- const base = `/projects/${projectId}/records`;
1839
- return {
1840
- async create(type, req) {
1841
- return client.post(`${base}/${type}`, req);
1842
- },
1843
- async set(type, key, req) {
1844
- return client.put(
1845
- `${base}/${type}/${encodeKey(key)}`,
1846
- req
1847
- );
1848
- },
1849
- async get(type, key) {
1850
- return client.get(`${base}/${type}/${encodeKey(key)}`);
1851
- },
1852
- async patch(type, key, req) {
1853
- return client.patch(
1854
- `${base}/${type}/${encodeKey(key)}`,
1855
- req
1856
- );
1857
- },
1858
- async archive(type, key, req) {
1859
- return client.post(
1860
- `${base}/${type}/~/archive/${encodeKey(key)}`,
1861
- req
1862
- );
1863
- },
1864
- async unarchive(type, key, req) {
1865
- return client.post(
1866
- `${base}/${type}/~/unarchive/${encodeKey(key)}`,
1867
- req
1868
- );
1869
- },
1870
- async history(type, key, opts) {
1871
- const query = {};
1872
- if (opts?.limit !== void 0) query.limit = String(opts.limit);
1873
- if (opts?.values !== void 0) query.values = String(opts.values);
1874
- return client.get(
1875
- `${base}/${type}/~/history/${encodeKey(key)}`,
1876
- { query }
1877
- );
1878
- },
1879
- async list(type, query) {
1880
- return client.get(`${base}/${type}`, { query });
1881
- },
1882
- async types() {
1883
- return client.get(`${base}/_types`);
1884
- },
1885
- async typesInUse() {
1886
- const raw = await client.get(`${base}/_types`);
1887
- return { ok: true, types: raw.in_use_types ?? [] };
2002
+ async function exchangeGitHubToken(baseUrl, projectId, githubToken) {
2003
+ const url = `${baseUrl.replace(/\/+$/, "")}/api/auth/github/exchange`;
2004
+ let res;
2005
+ try {
2006
+ res = await fetch(url, {
2007
+ method: "POST",
2008
+ headers: { "Content-Type": "application/json" },
2009
+ body: JSON.stringify({
2010
+ project_id: projectId,
2011
+ github_token: githubToken
2012
+ })
2013
+ });
2014
+ } catch (err) {
2015
+ throw new Error(
2016
+ `Network error during GitHub token exchange: ${err instanceof Error ? err.message : String(err)}`
2017
+ );
2018
+ }
2019
+ if (!res.ok) {
2020
+ try {
2021
+ const body2 = await res.json();
2022
+ const parsed = ErrorEnvelopeSchema.safeParse(body2);
2023
+ if (parsed.success) {
2024
+ const { code, message, retryable } = parsed.data.error;
2025
+ throw new TilaApiError(res.status, code, message, retryable);
2026
+ }
2027
+ } catch (err) {
2028
+ if (err instanceof TilaApiError) throw err;
1888
2029
  }
1889
- };
1890
- }
1891
-
1892
- // src/schema.ts
1893
- function createSchemaMethods(client, projectId) {
1894
- const base = `/projects/${projectId}/schema`;
2030
+ throw new TilaApiError(
2031
+ res.status,
2032
+ "UNKNOWN",
2033
+ `HTTP ${res.status}: ${res.statusText}`,
2034
+ false
2035
+ );
2036
+ }
2037
+ const body = await res.json();
2038
+ if (!body.session_token || typeof body.expires_at !== "number") {
2039
+ throw new TypeError(
2040
+ "Exchange returned unexpected response shape: missing session_token or expires_at"
2041
+ );
2042
+ }
1895
2043
  return {
1896
- async get() {
1897
- return client.get(base);
1898
- },
1899
- async apply(schema, strategy) {
1900
- return client.post(`${base}/apply`, { schema, strategy });
1901
- },
1902
- async history(opts) {
1903
- return client.get(`${base}/history`, { query: opts });
1904
- }
2044
+ sessionToken: body.session_token,
2045
+ expiresAt: body.expires_at,
2046
+ permission: body.permission ?? "read"
1905
2047
  };
1906
2048
  }
1907
-
1908
- // src/signals.ts
1909
- function createSignalMethods(client, projectId) {
1910
- const base = `/projects/${projectId}/signals`;
2049
+ function buildHttpFacade(client, projectId) {
1911
2050
  return {
1912
- /** Fetch the signal inbox for the current token. GET /projects/:id/signals */
1913
- async inbox() {
1914
- return client.get(base);
1915
- },
1916
- /** Send a signal to a target. POST /projects/:id/signals/send */
1917
- async send(req) {
1918
- return client.post(`${base}/send`, req);
1919
- },
1920
- /** Acknowledge a signal. POST /projects/:id/signals/:signalId/ack */
1921
- async ack(signalId) {
1922
- return client.post(`${base}/${signalId}/ack`, {});
2051
+ tasks: createTaskMethods(client, projectId),
2052
+ records: createRecordMethods(client, projectId),
2053
+ claims: createClaimMethods(client, projectId),
2054
+ artifacts: createArtifactMethods(client, projectId),
2055
+ gates: createGateMethods(client, projectId),
2056
+ signals: createSignalMethods(client, projectId),
2057
+ journal: createJournalMethods(client, projectId),
2058
+ presence: createPresenceMethods(client, projectId),
2059
+ schema: createSchemaMethods(client, projectId),
2060
+ summary: createSummaryMethods(client, projectId),
2061
+ search: createSearchMethods(client, projectId),
2062
+ templates: createTemplateMethods(client, projectId),
2063
+ tokens: createTokenMethods(client),
2064
+ close: () => {
1923
2065
  }
1924
2066
  };
1925
2067
  }
1926
-
1927
- // src/gates.ts
1928
- function createGateMethods(client, projectId) {
1929
- const base = `/projects/${projectId}/gates`;
1930
- return {
1931
- /** List gates with optional filters. GET /projects/:id/gates */
1932
- async list(query) {
1933
- return client.get(base, { query });
1934
- },
1935
- /** Create a new gate. POST /projects/:id/gates */
1936
- async create(req) {
1937
- return client.post(base, req);
1938
- },
1939
- /** Resolve a gate. POST /projects/:id/gates/:gateId/resolve */
1940
- async resolve(gateId, req) {
1941
- return client.post(`${base}/${gateId}/resolve`, req ?? {});
1942
- },
1943
- /** Delete a gate. DELETE /projects/:id/gates/:gateId */
1944
- async remove(gateId) {
1945
- return client.delete(`${base}/${gateId}`);
2068
+ async function createTila(config, token, opts) {
2069
+ if (config.backend === "local") {
2070
+ if (!config.local) {
2071
+ throw new Error(
2072
+ 'createTila: backend = "local" requires a [local] config section with db_path and artifacts_path.'
2073
+ );
1946
2074
  }
1947
- };
2075
+ const { createTilaLocal, buildLocalResources } = await import('./local.js');
2076
+ const { project, artifacts, close } = await createTilaLocal({
2077
+ dbPath: config.local.db_path,
2078
+ artifactsPath: config.local.artifacts_path,
2079
+ org: config.local.org,
2080
+ project: config.project_id
2081
+ });
2082
+ const resources = buildLocalResources(project, artifacts);
2083
+ return { ...resources, close };
2084
+ }
2085
+ if (token === void 0) {
2086
+ throw new Error(
2087
+ 'createTila: the Cloudflare backend requires a token. Pass createTila(config, token), or set backend = "local".'
2088
+ );
2089
+ }
2090
+ const client = TilaClient.fromConfig(config, token, {
2091
+ extraHeaders: opts?.extraHeaders
2092
+ });
2093
+ return buildHttpFacade(client, config.project_id);
1948
2094
  }
1949
2095
 
1950
- // src/templates.ts
1951
- function createTemplateMethods(client, projectId) {
1952
- const base = `/projects/${projectId}/templates`;
1953
- return {
1954
- /** Instantiate an entity template. POST /projects/:id/templates/instantiate */
1955
- async instantiate(req) {
1956
- return client.post(
1957
- `${base}/instantiate`,
1958
- req
1959
- );
1960
- },
1961
- /** List available templates from the project schema. GET /projects/:id/templates */
1962
- async list() {
1963
- return client.get(base);
2096
+ // src/retry.ts
2097
+ async function withRetry(fn, opts) {
2098
+ const maxRetries = opts?.maxRetries ?? 3;
2099
+ const baseDelayMs = opts?.baseDelayMs ?? 200;
2100
+ const maxDelayMs = opts?.maxDelayMs ?? 3e4;
2101
+ const jitter = opts?.jitter ?? true;
2102
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
2103
+ try {
2104
+ return await fn();
2105
+ } catch (err) {
2106
+ if (isTilaApiError(err) && err.retryable === false) {
2107
+ throw err;
2108
+ }
2109
+ if (attempt === maxRetries) {
2110
+ throw err;
2111
+ }
2112
+ const cap = Math.min(maxDelayMs, baseDelayMs * 2 ** attempt);
2113
+ const sleepMs = jitter ? Math.random() * cap : cap;
2114
+ await new Promise((resolve) => setTimeout(resolve, sleepMs));
1964
2115
  }
1965
- };
2116
+ }
2117
+ throw new Error("withRetry: unreachable");
1966
2118
  }
1967
2119
 
2120
+ // src/error-codes.ts
2121
+ var TILA_ERRORS = {
2122
+ // Auth / middleware (worker layer — SCREAMING_SNAKE_CASE wire values)
2123
+ UNAUTHORIZED: "UNAUTHORIZED",
2124
+ SESSION_EXPIRED: "SESSION_EXPIRED",
2125
+ RATE_LIMITED: "RATE_LIMITED",
2126
+ PERMISSION_DENIED: "PERMISSION_DENIED",
2127
+ PROJECT_MISMATCH: "PROJECT_MISMATCH",
2128
+ CSRF_MISSING_ORIGIN: "CSRF_MISSING_ORIGIN",
2129
+ CSRF_ORIGIN_MISMATCH: "CSRF_ORIGIN_MISMATCH",
2130
+ INTERNAL_ERROR: "INTERNAL_ERROR",
2131
+ DO_UNREACHABLE: "do-unreachable",
2132
+ // Auth endpoint specific
2133
+ REPO_NOT_ALLOWED: "REPO_NOT_ALLOWED",
2134
+ GITHUB_AUTH_FAILED: "GITHUB_AUTH_FAILED",
2135
+ HMAC_NOT_CONFIGURED: "HMAC_NOT_CONFIGURED",
2136
+ // Token endpoint specific
2137
+ TOKEN_NAME_CONFLICT: "TOKEN_NAME_CONFLICT",
2138
+ TOKEN_AUTHZ_DENIED: "TOKEN_AUTHZ_DENIED",
2139
+ TOKEN_NOT_FOUND: "TOKEN_NOT_FOUND",
2140
+ // Validation (worker layer uses SCREAMING_SNAKE for this code)
2141
+ VALIDATION_ERROR: "VALIDATION_ERROR",
2142
+ // DO errors (project-do-router — kebab-case wire values)
2143
+ STALE_FENCE: "stale-fence",
2144
+ NOT_FOUND: "not-found",
2145
+ GATE_ALREADY_SETTLED: "gate-already-settled",
2146
+ NO_FENCE: "no-fence",
2147
+ INTERNAL: "internal",
2148
+ CONSTRAINT_VIOLATION: "constraint-violation",
2149
+ IDEMPOTENCY_KEY_CONFLICT: "idempotency-key-conflict",
2150
+ // DO-layer validation uses kebab-case (distinct from VALIDATION_ERROR above)
2151
+ VALIDATION_ERROR_DO: "validation-error",
2152
+ ALREADY_HELD: "already-held",
2153
+ RENEW_FAILED: "renew-failed",
2154
+ BAD_REQUEST: "bad-request",
2155
+ MISSING_QUERY: "missing-query",
2156
+ INVALID_QUERY: "invalid-query",
2157
+ INVALID_SLOT: "invalid-slot",
2158
+ INVALID_RELATIONSHIP_TYPE: "invalid-relationship-type",
2159
+ // Fallback (SDK-generated when response is unparseable)
2160
+ UNKNOWN: "UNKNOWN"
2161
+ };
2162
+
1968
2163
  // src/indexes.ts
1969
2164
  function createIndexMethods(client, projectId) {
1970
2165
  const base = `/projects/${projectId}/artifacts`;
@@ -2007,26 +2202,240 @@ function createIndexMethods(client, projectId) {
2007
2202
  }
2008
2203
  };
2009
2204
  }
2010
-
2011
- // src/summary.ts
2012
- function createSummaryMethods(client, projectId) {
2205
+
2206
+ // src/namespace-prefix.ts
2207
+ function validateNamespace(ns) {
2208
+ if (!/^[a-z][a-z0-9_-]*$/.test(ns)) {
2209
+ throw new TypeError(
2210
+ `Invalid namespace "${ns}": must match /^[a-z][a-z0-9_-]*$/ (lowercase letter start, then lowercase letters, digits, underscores, or hyphens).`
2211
+ );
2212
+ }
2213
+ }
2214
+ function applyPrefix(ns, name) {
2215
+ if (name.startsWith(`${ns}_`)) {
2216
+ throw new Error(
2217
+ `Namespace collision: "${name}" already starts with prefix "${ns}_". Call the raw factory if this name is intentional.`
2218
+ );
2219
+ }
2220
+ return `${ns}_${name}`;
2221
+ }
2222
+ function stripPrefix(ns, name) {
2223
+ const prefix = `${ns}_`;
2224
+ if (name.startsWith(prefix)) {
2225
+ return name.slice(prefix.length);
2226
+ }
2227
+ return name;
2228
+ }
2229
+
2230
+ // src/namespace.ts
2231
+ function namespacedTaskMethods(client, projectId, ns) {
2232
+ const inner = createTaskMethods(client, projectId);
2233
+ return {
2234
+ ...inner,
2235
+ async create(id, type, data) {
2236
+ const result = await inner.create(id, applyPrefix(ns, type), data);
2237
+ return {
2238
+ ...result,
2239
+ entity: { ...result.entity, type: stripPrefix(ns, result.entity.type) }
2240
+ };
2241
+ },
2242
+ async get(id) {
2243
+ const result = await inner.get(id);
2244
+ return {
2245
+ ...result,
2246
+ entity: { ...result.entity, type: stripPrefix(ns, result.entity.type) }
2247
+ };
2248
+ },
2249
+ async update(id, data, fence) {
2250
+ const result = await inner.update(id, data, fence);
2251
+ return {
2252
+ ...result,
2253
+ entity: { ...result.entity, type: stripPrefix(ns, result.entity.type) }
2254
+ };
2255
+ },
2256
+ async list(query) {
2257
+ const prefixedQuery = query ? {
2258
+ ...query,
2259
+ type: query.type !== void 0 ? applyPrefix(ns, query.type) : void 0
2260
+ } : void 0;
2261
+ const result = await inner.list(prefixedQuery);
2262
+ return {
2263
+ ...result,
2264
+ entities: result.entities.map((e) => ({
2265
+ ...e,
2266
+ type: stripPrefix(ns, e.type)
2267
+ }))
2268
+ };
2269
+ }
2270
+ };
2271
+ }
2272
+ function namespacedRecordMethods(client, projectId, ns) {
2273
+ const inner = createRecordMethods(client, projectId);
2274
+ function stripRecordType(result) {
2275
+ return {
2276
+ ...result,
2277
+ record: { ...result.record, type: stripPrefix(ns, result.record.type) }
2278
+ };
2279
+ }
2280
+ return {
2281
+ async create(type, req) {
2282
+ return stripRecordType(await inner.create(applyPrefix(ns, type), req));
2283
+ },
2284
+ async set(type, key, req) {
2285
+ return stripRecordType(await inner.set(applyPrefix(ns, type), key, req));
2286
+ },
2287
+ async get(type, key) {
2288
+ return stripRecordType(await inner.get(applyPrefix(ns, type), key));
2289
+ },
2290
+ async patch(type, key, req) {
2291
+ return stripRecordType(
2292
+ await inner.patch(applyPrefix(ns, type), key, req)
2293
+ );
2294
+ },
2295
+ async archive(type, key, req) {
2296
+ return stripRecordType(
2297
+ await inner.archive(applyPrefix(ns, type), key, req)
2298
+ );
2299
+ },
2300
+ async unarchive(type, key, req) {
2301
+ return stripRecordType(
2302
+ await inner.unarchive(applyPrefix(ns, type), key, req)
2303
+ );
2304
+ },
2305
+ async history(type, key, opts) {
2306
+ const result = await inner.history(applyPrefix(ns, type), key, opts);
2307
+ return {
2308
+ ...result,
2309
+ items: result.items.map((item) => ({
2310
+ ...item,
2311
+ type: stripPrefix(ns, item.type)
2312
+ }))
2313
+ };
2314
+ },
2315
+ async list(type, query) {
2316
+ const result = await inner.list(applyPrefix(ns, type), query);
2317
+ return {
2318
+ ...result,
2319
+ items: result.items.map((item) => ({
2320
+ ...item,
2321
+ type: stripPrefix(ns, item.type)
2322
+ }))
2323
+ };
2324
+ },
2325
+ async types() {
2326
+ const result = await inner.types();
2327
+ return {
2328
+ ...result,
2329
+ types: result.types.map((t) => stripPrefix(ns, t))
2330
+ };
2331
+ },
2332
+ async typesInUse() {
2333
+ const result = await inner.typesInUse();
2334
+ return {
2335
+ ...result,
2336
+ types: result.types.map((t) => stripPrefix(ns, t))
2337
+ };
2338
+ }
2339
+ };
2340
+ }
2341
+ function namespacedArtifactMethods(client, projectId, ns) {
2342
+ const inner = createArtifactMethods(client, projectId);
2343
+ return {
2344
+ ...inner,
2345
+ upload(input, opts) {
2346
+ return inner.upload(input, { ...opts, kind: applyPrefix(ns, opts.kind) });
2347
+ },
2348
+ async writeText(content, opts) {
2349
+ return inner.writeText(content, {
2350
+ ...opts,
2351
+ kind: applyPrefix(ns, opts.kind)
2352
+ });
2353
+ },
2354
+ async list(query) {
2355
+ const prefixedQuery = query ? {
2356
+ ...query,
2357
+ kind: query.kind !== void 0 ? applyPrefix(ns, query.kind) : void 0
2358
+ } : void 0;
2359
+ const result = await inner.list(prefixedQuery);
2360
+ return {
2361
+ ...result,
2362
+ pointers: result.pointers.map((p) => ({
2363
+ ...p,
2364
+ kind: stripPrefix(ns, p.kind)
2365
+ }))
2366
+ };
2367
+ },
2368
+ async search(q, opts) {
2369
+ const prefixedOpts = opts ? {
2370
+ ...opts,
2371
+ kind: opts.kind !== void 0 ? applyPrefix(ns, opts.kind) : void 0
2372
+ } : void 0;
2373
+ const result = await inner.search(q, prefixedOpts);
2374
+ return {
2375
+ ...result,
2376
+ results: result.results.map((r) => ({
2377
+ ...r,
2378
+ kind: stripPrefix(ns, r.kind)
2379
+ }))
2380
+ };
2381
+ },
2382
+ async grep(pattern, opts) {
2383
+ const prefixedOpts = opts ? {
2384
+ ...opts,
2385
+ kind: opts.kind !== void 0 ? applyPrefix(ns, opts.kind) : void 0
2386
+ } : void 0;
2387
+ const result = await inner.grep(pattern, prefixedOpts);
2388
+ return {
2389
+ ...result,
2390
+ results: result.results.map((r) => ({
2391
+ ...r,
2392
+ kind: stripPrefix(ns, r.kind)
2393
+ }))
2394
+ };
2395
+ },
2396
+ async getLatest(kind, resource) {
2397
+ let pointer;
2398
+ try {
2399
+ pointer = await inner.getLatest(applyPrefix(ns, kind), resource);
2400
+ } catch (err) {
2401
+ if (err instanceof TilaApiError && err.status === 404) return null;
2402
+ throw err;
2403
+ }
2404
+ if (pointer === null) return null;
2405
+ return { ...pointer, kind: stripPrefix(ns, pointer.kind) };
2406
+ }
2407
+ };
2408
+ }
2409
+ function namespacedTemplateMethods(client, projectId, ns) {
2410
+ const inner = createTemplateMethods(client, projectId);
2013
2411
  return {
2014
- /** Get project summary. GET /projects/:id/summary */
2015
- async get() {
2016
- return client.get(`/projects/${projectId}/summary`);
2412
+ ...inner,
2413
+ async instantiate(req) {
2414
+ return inner.instantiate({
2415
+ ...req,
2416
+ template_name: applyPrefix(ns, req.template_name)
2417
+ });
2418
+ },
2419
+ async list() {
2420
+ const result = await inner.list();
2421
+ return {
2422
+ ...result,
2423
+ templates: result.templates.map((t) => ({
2424
+ ...t,
2425
+ name: stripPrefix(ns, t.name),
2426
+ type: stripPrefix(ns, t.type)
2427
+ }))
2428
+ };
2017
2429
  }
2018
2430
  };
2019
2431
  }
2020
-
2021
- // src/search.ts
2022
- function createSearchMethods(client, projectId) {
2023
- const base = `/projects/${projectId}`;
2432
+ function createNamespace(client, projectId, ns) {
2433
+ validateNamespace(ns);
2024
2434
  return {
2025
- async search(q, opts) {
2026
- const query = { q };
2027
- if (opts?.limit !== void 0) query.limit = String(opts.limit);
2028
- return client.get(`${base}/search`, { query });
2029
- }
2435
+ tasks: namespacedTaskMethods(client, projectId, ns),
2436
+ records: namespacedRecordMethods(client, projectId, ns),
2437
+ artifacts: namespacedArtifactMethods(client, projectId, ns),
2438
+ templates: namespacedTemplateMethods(client, projectId, ns)
2030
2439
  };
2031
2440
  }
2032
2441
 
@@ -2138,5 +2547,867 @@ async function withClaim(client, projectId, resource, mode, ttlMs, callback) {
2138
2547
  }
2139
2548
  }
2140
2549
  }
2550
+ var ArtifactPointerInternalSchema = z.object({
2551
+ r2_key: z.string(),
2552
+ resource: z.string().nullable(),
2553
+ kind: z.string(),
2554
+ sha256: z.string(),
2555
+ bytes: z.number(),
2556
+ mime_type: z.string(),
2557
+ produced_at: z.number(),
2558
+ produced_by: z.string(),
2559
+ expires_at: z.number().nullable(),
2560
+ tombstoned: z.number()
2561
+ }).passthrough();
2562
+ var ArtifactListInternalSchema = z.object({
2563
+ ok: z.literal(true),
2564
+ pointers: z.array(ArtifactPointerInternalSchema)
2565
+ });
2566
+ var OkSchema = z.object({ ok: z.literal(true) }).passthrough();
2567
+ var RecordTypesInternalSchema = z.object({
2568
+ ok: z.literal(true),
2569
+ types: z.array(z.string()),
2570
+ in_use_types: z.array(z.string()).optional()
2571
+ });
2572
+ var SchemaShowResponseSchema = z.object({
2573
+ ok: z.literal(true),
2574
+ schema: z.record(z.unknown()).nullable(),
2575
+ version: z.number().int().nullable()
2576
+ });
2577
+ var SchemaApplyLenientSchema = z.object({
2578
+ ok: z.literal(true),
2579
+ version: z.number().int().nullable().optional(),
2580
+ changes: z.array(z.string()).optional(),
2581
+ noChange: z.boolean().optional()
2582
+ });
2583
+ var StateListInternalSchema = z.object({
2584
+ ok: z.literal(true),
2585
+ claims: z.array(
2586
+ z.object({
2587
+ resource: z.string(),
2588
+ machine: z.string(),
2589
+ user: z.string(),
2590
+ mode: z.enum(["exclusive", "owner", "presence"]),
2591
+ fence: z.number(),
2592
+ acquired_at: z.number(),
2593
+ expires_at: z.number(),
2594
+ metadata: z.record(z.unknown()).optional()
2595
+ })
2596
+ )
2597
+ });
2598
+ var ArtifactSearchResponseSchema2 = z.object({
2599
+ ok: z.literal(true),
2600
+ results: z.array(
2601
+ z.object({
2602
+ r2_key: z.string(),
2603
+ kind: z.string(),
2604
+ title: z.string().nullable(),
2605
+ snippet: z.string().nullable()
2606
+ }).passthrough()
2607
+ )
2608
+ });
2609
+ var RelListResponseSchema = z.object({
2610
+ ok: z.literal(true),
2611
+ relationships: z.array(
2612
+ z.object({
2613
+ from_key: z.string(),
2614
+ to_key: z.string().nullable(),
2615
+ to_uri: z.string().nullable(),
2616
+ type: z.string(),
2617
+ created_at: z.number()
2618
+ }).passthrough()
2619
+ )
2620
+ });
2621
+ var IndexEntriesResponseSchema = z.object({
2622
+ ok: z.literal(true),
2623
+ entries: z.array(
2624
+ z.object({
2625
+ r2_key: z.string(),
2626
+ resource: z.string().nullable(),
2627
+ kind: z.string(),
2628
+ sha256: z.string(),
2629
+ bytes: z.number(),
2630
+ mime_type: z.string(),
2631
+ produced_at: z.number(),
2632
+ produced_by: z.string(),
2633
+ expires_at: z.number().nullable(),
2634
+ tombstoned: z.number(),
2635
+ exists: z.boolean()
2636
+ })
2637
+ )
2638
+ });
2639
+ var RemoteBackend = class {
2640
+ constructor(client, projectId) {
2641
+ this.client = client;
2642
+ this.projectId = projectId;
2643
+ }
2644
+ client;
2645
+ projectId;
2646
+ // --- EntityBackend ---
2647
+ async create(input) {
2648
+ const body = {
2649
+ id: input.id,
2650
+ type: input.type,
2651
+ data: input.data,
2652
+ created_by: input.created_by
2653
+ };
2654
+ if (input.tags !== void 0) body.tags = input.tags;
2655
+ const result = await this.client.post(
2656
+ `/projects/${this.projectId}/tasks`,
2657
+ body,
2658
+ { schema: EntityResponseSchema, validate: true }
2659
+ );
2660
+ return result.entity;
2661
+ }
2662
+ async get(id) {
2663
+ try {
2664
+ const result = await this.client.get(
2665
+ `/projects/${this.projectId}/tasks/${encodeURIComponent(id)}`,
2666
+ { schema: EntityDetailResponseSchema, validate: true }
2667
+ );
2668
+ return result.entity;
2669
+ } catch (err) {
2670
+ if (err instanceof TilaApiError && err.status === 404) {
2671
+ return null;
2672
+ }
2673
+ throw err;
2674
+ }
2675
+ }
2676
+ async list(filter) {
2677
+ const query = {};
2678
+ if (filter?.type) query.type = filter.type;
2679
+ if (filter?.archived !== void 0)
2680
+ query.archived = String(filter.archived);
2681
+ const DATA_FIELD_TO_QUERY_PARAM = {
2682
+ parent_id: "parent"
2683
+ };
2684
+ if (filter?.dataFilter) {
2685
+ for (const [key, value] of Object.entries(filter.dataFilter)) {
2686
+ if (value !== void 0 && value !== null) {
2687
+ const param = DATA_FIELD_TO_QUERY_PARAM[key] ?? key;
2688
+ query[param] = String(value);
2689
+ }
2690
+ }
2691
+ }
2692
+ if (filter?.tagFilter?.length)
2693
+ query.tag_filter = filter.tagFilter.join(",");
2694
+ if (filter?.sort) query.sort = filter.sort;
2695
+ if (filter?.order) query.order = filter.order;
2696
+ if (filter?.limit !== void 0) query.limit = String(filter.limit);
2697
+ if (filter?.offset !== void 0) query.offset = String(filter.offset);
2698
+ const result = await this.client.get(`/projects/${this.projectId}/tasks`, {
2699
+ schema: PaginatedEntityListResponseSchema,
2700
+ validate: true,
2701
+ query
2702
+ });
2703
+ return result.entities;
2704
+ }
2705
+ async update(id, data) {
2706
+ const acquired = await this.acquire(id, "cli", "cli", "exclusive", 3e4);
2707
+ try {
2708
+ const result = await this.client.patch(
2709
+ `/projects/${this.projectId}/tasks/${encodeURIComponent(id)}`,
2710
+ { data, fence: acquired.fence },
2711
+ { schema: EntityResponseSchema, validate: true }
2712
+ );
2713
+ return result.entity;
2714
+ } finally {
2715
+ try {
2716
+ await this.release(id, acquired.fence);
2717
+ } catch {
2718
+ }
2719
+ }
2720
+ }
2721
+ async archive(id) {
2722
+ const acquired = await this.acquire(id, "cli", "cli", "exclusive", 3e4);
2723
+ await this.client.post(
2724
+ `/projects/${this.projectId}/tasks/${encodeURIComponent(id)}/archive`,
2725
+ { fence: acquired.fence },
2726
+ { schema: ArchiveSuccessResponseSchema, validate: true }
2727
+ );
2728
+ }
2729
+ async addRelationship(input) {
2730
+ const result = await this.client.post(
2731
+ `/projects/${this.projectId}/tasks/relationships`,
2732
+ { from_id: input.from_id, to_id: input.to_id, type: input.type },
2733
+ { schema: CreateEntityRelationshipResponseSchema, validate: true }
2734
+ );
2735
+ return { created: result.created ?? true };
2736
+ }
2737
+ async listRelationships(filter) {
2738
+ const query = {};
2739
+ if (filter?.from_id) query.from_id = filter.from_id;
2740
+ if (filter?.to_id) query.to_id = filter.to_id;
2741
+ if (filter?.type) query.type = filter.type;
2742
+ const result = await this.client.get(
2743
+ `/projects/${this.projectId}/tasks/relationships`,
2744
+ { schema: ListEntityRelationshipsResponseSchema, validate: true, query }
2745
+ );
2746
+ return result.relationships;
2747
+ }
2748
+ async removeRelationship(input) {
2749
+ const params = new URLSearchParams({
2750
+ from_id: input.from_id,
2751
+ to_id: input.to_id,
2752
+ type: input.type
2753
+ });
2754
+ const result = await this.client.delete(
2755
+ `/projects/${this.projectId}/tasks/relationships?${params.toString()}`,
2756
+ { schema: DeleteEntityRelationshipResponseSchema, validate: true }
2757
+ );
2758
+ return { removed: result.removed };
2759
+ }
2760
+ // GET /projects/:projectId/tasks/ready (worker entities.ts ~129 -> DO /entity/ready)
2761
+ async listReady(filter) {
2762
+ const query = {};
2763
+ if (filter?.type) query.type = filter.type;
2764
+ if (filter?.parent) query.parent = filter.parent;
2765
+ if (filter?.limit !== void 0) query.limit = String(filter.limit);
2766
+ if (filter?.includeSoftBlocked) query["include-soft-blocked"] = "true";
2767
+ const result = await this.client.get(
2768
+ `/projects/${this.projectId}/tasks/ready`,
2769
+ { schema: ListReadyEntitiesResponseSchema, validate: true, query }
2770
+ );
2771
+ return result.entities.map((e) => ({ ...e, tags: [] }));
2772
+ }
2773
+ // Tree = compact list (GET /tasks?compact=true) + parent-child edges
2774
+ // (GET /tasks/relationships?type=parent-child). The Worker has no dedicated
2775
+ // tree endpoint; these are the two routes the DO/worker already expose.
2776
+ async tree(_rootId) {
2777
+ const listResult = await this.client.get(
2778
+ `/projects/${this.projectId}/tasks`,
2779
+ {
2780
+ schema: PaginatedCompactEntityListResponseSchema,
2781
+ validate: true,
2782
+ query: { compact: "true" }
2783
+ }
2784
+ );
2785
+ const relResult = await this.client.get(
2786
+ `/projects/${this.projectId}/tasks/relationships`,
2787
+ {
2788
+ schema: ListEntityRelationshipsResponseSchema,
2789
+ validate: true,
2790
+ query: { type: "parent-child" }
2791
+ }
2792
+ );
2793
+ return { nodes: listResult.entities, edges: relResult.relationships };
2794
+ }
2795
+ // PATCH /projects/:projectId/tasks/:id with a caller-supplied fence.
2796
+ // Unlike update() (which auto-acquires), the caller owns the fence here, so a
2797
+ // stale fence surfaces the Worker's fence-conflict error verbatim.
2798
+ async updateWithFence(id, data, fence) {
2799
+ const result = await this.client.patch(
2800
+ `/projects/${this.projectId}/tasks/${encodeURIComponent(id)}`,
2801
+ { data, fence },
2802
+ { schema: EntityResponseSchema, validate: true }
2803
+ );
2804
+ return result.entity;
2805
+ }
2806
+ // POST /projects/:projectId/tasks/:entityId/artifact-refs (worker entities.ts ~264)
2807
+ async addArtifactRef(input) {
2808
+ const body = {
2809
+ artifact_key: input.artifact_key,
2810
+ slot: input.slot
2811
+ };
2812
+ if (input.metadata !== void 0) body.metadata = input.metadata;
2813
+ await this.client.post(
2814
+ `/projects/${this.projectId}/tasks/${encodeURIComponent(input.entity_id)}/artifact-refs`,
2815
+ body,
2816
+ { schema: OkSchema, validate: true }
2817
+ );
2818
+ }
2819
+ // GET /projects/:projectId/tasks/:entityId/artifact-refs (worker entities.ts ~340)
2820
+ async listArtifactRefs(entityId) {
2821
+ const result = await this.client.get(
2822
+ `/projects/${this.projectId}/tasks/${encodeURIComponent(entityId)}/artifact-refs`,
2823
+ { schema: EntityArtifactReferenceListResponseSchema, validate: true }
2824
+ );
2825
+ return result.references;
2826
+ }
2827
+ // --- CoordinationBackend ---
2828
+ async acquire(resource, machine, user, mode, ttlMs) {
2829
+ const result = await this.client.post(
2830
+ `/projects/${this.projectId}/claims/acquire`,
2831
+ { resource, mode, ttl_ms: ttlMs },
2832
+ { schema: AcquireSuccessResponseSchema, validate: true }
2833
+ );
2834
+ return {
2835
+ acquired: true,
2836
+ fence: result.fence,
2837
+ expires_at: result.expires_at
2838
+ };
2839
+ }
2840
+ async renew(resource, _machine, _user, fence, ttlMs) {
2841
+ const result = await this.client.post(
2842
+ `/projects/${this.projectId}/claims/renew`,
2843
+ { resource, fence, ttl_ms: ttlMs },
2844
+ { schema: RenewSuccessResponseSchema, validate: true }
2845
+ );
2846
+ return { renewed: true, expires_at: result.expires_at };
2847
+ }
2848
+ async release(resource, fence) {
2849
+ await this.client.post(
2850
+ `/projects/${this.projectId}/claims/release`,
2851
+ { resource, fence },
2852
+ { schema: ReleaseSuccessResponseSchema, validate: true }
2853
+ );
2854
+ }
2855
+ async state(resource) {
2856
+ const result = await this.client.get(
2857
+ `/projects/${this.projectId}/claims/state/${encodeURIComponent(resource)}`,
2858
+ { schema: StateResponseSchema, validate: true }
2859
+ );
2860
+ return result.claim ?? null;
2861
+ }
2862
+ async heartbeat(machine, info) {
2863
+ await this.client.post(
2864
+ `/projects/${this.projectId}/presence/heartbeat`,
2865
+ { machine, info: info ?? {} },
2866
+ { schema: PresenceHeartbeatSuccessResponseSchema, validate: true }
2867
+ );
2868
+ }
2869
+ async listPresence() {
2870
+ const result = await this.client.get(
2871
+ `/projects/${this.projectId}/presence/all`,
2872
+ { schema: PresenceAllListResponseSchema, validate: true }
2873
+ );
2874
+ return result.machines.map(({ machine, last_seen, info }) => ({
2875
+ machine,
2876
+ last_seen,
2877
+ info
2878
+ }));
2879
+ }
2880
+ async listClaims() {
2881
+ const result = await this.client.get(`/projects/${this.projectId}/claims`, {
2882
+ schema: StateListInternalSchema,
2883
+ validate: true
2884
+ });
2885
+ return result.claims.map((c) => ({
2886
+ resource: c.resource,
2887
+ machine: c.machine,
2888
+ user: c.user,
2889
+ mode: c.mode,
2890
+ fence: c.fence,
2891
+ acquired_at: c.acquired_at,
2892
+ expires_at: c.expires_at,
2893
+ metadata: c.metadata ?? {}
2894
+ }));
2895
+ }
2896
+ // --- JournalBackend ---
2897
+ async listJournal(query) {
2898
+ const result = await this.client.get(
2899
+ `/projects/${this.projectId}/journal`,
2900
+ {
2901
+ schema: JournalResponseSchema,
2902
+ validate: true,
2903
+ query: {
2904
+ resource: query.resource,
2905
+ kind: query.kind,
2906
+ limit: query.limit !== void 0 ? String(query.limit) : void 0
2907
+ }
2908
+ }
2909
+ );
2910
+ return result.events.map((ev) => ({
2911
+ seq: ev.seq,
2912
+ t: ev.t,
2913
+ kind: ev.kind,
2914
+ resource: ev.resource,
2915
+ actor: ev.actor,
2916
+ fence: ev.fence
2917
+ }));
2918
+ }
2919
+ // --- GateBackend ---
2920
+ async createGate(resource, awaitType, fence, timeoutAt) {
2921
+ const body = {
2922
+ resource,
2923
+ await_type: awaitType,
2924
+ fence
2925
+ };
2926
+ if (timeoutAt !== void 0) body.timeout_at = timeoutAt;
2927
+ const result = await this.client.post(
2928
+ `/projects/${this.projectId}/gates`,
2929
+ body,
2930
+ { schema: GateResponseSchema, validate: true }
2931
+ );
2932
+ return {
2933
+ id: result.gate.id,
2934
+ resource: result.gate.resource,
2935
+ await_type: result.gate.await_type,
2936
+ status: result.gate.status,
2937
+ fence: result.gate.fence,
2938
+ timeout_at: result.gate.timeout_at,
2939
+ resolved_at: result.gate.resolved_at,
2940
+ resolution: result.gate.resolution,
2941
+ created_at: result.gate.created_at,
2942
+ created_by: result.gate.created_by
2943
+ };
2944
+ }
2945
+ async listGates(filter) {
2946
+ const params = new URLSearchParams();
2947
+ if (filter?.resource) params.set("resource", filter.resource);
2948
+ if (filter?.status) params.set("status", filter.status);
2949
+ const qs = params.toString();
2950
+ const url = `/projects/${this.projectId}/gates${qs ? `?${qs}` : ""}`;
2951
+ const result = await this.client.get(url, {
2952
+ schema: GateListResponseSchema,
2953
+ validate: true
2954
+ });
2955
+ return result.gates.map((g) => ({
2956
+ id: g.id,
2957
+ resource: g.resource,
2958
+ await_type: g.await_type,
2959
+ status: g.status,
2960
+ fence: g.fence,
2961
+ timeout_at: g.timeout_at,
2962
+ resolved_at: g.resolved_at,
2963
+ resolution: g.resolution,
2964
+ created_at: g.created_at,
2965
+ created_by: g.created_by
2966
+ }));
2967
+ }
2968
+ async resolveGate(gateId, resolution) {
2969
+ const body = {};
2970
+ if (resolution) body.resolution = resolution;
2971
+ await this.client.post(
2972
+ `/projects/${this.projectId}/gates/${gateId}/resolve`,
2973
+ body,
2974
+ { schema: OkSchema, validate: true }
2975
+ );
2976
+ }
2977
+ async cancelGate(gateId) {
2978
+ await this.client.delete(`/projects/${this.projectId}/gates/${gateId}`, {
2979
+ schema: OkSchema,
2980
+ validate: true
2981
+ });
2982
+ }
2983
+ // --- SignalBackend ---
2984
+ async sendSignal(input, _createdBy) {
2985
+ const body = {
2986
+ target: input.target,
2987
+ kind: input.kind
2988
+ };
2989
+ if (input.resource) body.resource = input.resource;
2990
+ if (input.payload !== void 0) body.payload = input.payload;
2991
+ if (input.ttl_ms !== void 0) body.ttl_ms = input.ttl_ms;
2992
+ const result = await this.client.post(
2993
+ `/projects/${this.projectId}/signals/send`,
2994
+ body,
2995
+ { schema: SendSignalResponseSchema, validate: true }
2996
+ );
2997
+ return { id: result.id };
2998
+ }
2999
+ async listSignals(_tokenName) {
3000
+ const result = await this.client.get(
3001
+ `/projects/${this.projectId}/signals`,
3002
+ { schema: InboxResponseSchema, validate: true }
3003
+ );
3004
+ return result.signals.map((s) => ({
3005
+ id: s.id,
3006
+ target: s.target,
3007
+ kind: s.kind,
3008
+ resource: s.resource ?? null,
3009
+ payload: s.payload,
3010
+ created_by: s.created_by,
3011
+ created_at: s.created_at,
3012
+ expires_at: s.expires_at,
3013
+ acked_at: s.acked_at
3014
+ }));
3015
+ }
3016
+ async ackSignal(signalId) {
3017
+ await this.client.post(
3018
+ `/projects/${this.projectId}/signals/${signalId}/ack`,
3019
+ {},
3020
+ { schema: AckSignalResponseSchema, validate: true }
3021
+ );
3022
+ return { found: true };
3023
+ }
3024
+ // --- SchemaBackend ---
3025
+ async getCurrentSchema() {
3026
+ const result = await this.client.get(`/projects/${this.projectId}/schema`, {
3027
+ schema: SchemaShowResponseSchema,
3028
+ validate: true
3029
+ });
3030
+ return {
3031
+ version: result.version,
3032
+ definition: result.schema ? JSON.stringify(result.schema) : null
3033
+ };
3034
+ }
3035
+ async applySchema(input) {
3036
+ const body = {
3037
+ definition: input.definition
3038
+ };
3039
+ if (input.strategy) body.strategy = input.strategy;
3040
+ const result = await this.client.post(
3041
+ `/projects/${this.projectId}/schema`,
3042
+ body,
3043
+ { schema: SchemaApplyLenientSchema, validate: true }
3044
+ );
3045
+ return {
3046
+ ok: true,
3047
+ version: result.version ?? null,
3048
+ changes: result.changes ?? [],
3049
+ noChange: result.noChange ?? false
3050
+ };
3051
+ }
3052
+ // --- SummaryBackend ---
3053
+ async getSummary() {
3054
+ const result = await this.client.get(
3055
+ `/projects/${this.projectId}/summary`,
3056
+ { schema: SummaryResponseSchema, validate: true }
3057
+ );
3058
+ return result.project;
3059
+ }
3060
+ };
3061
+ var RemoteArtifactBackend = class {
3062
+ constructor(client, projectId) {
3063
+ this.client = client;
3064
+ this.projectId = projectId;
3065
+ }
3066
+ client;
3067
+ projectId;
3068
+ // --- ArtifactBackend ---
3069
+ async put(options) {
3070
+ let bodyBlob;
3071
+ if (typeof options.body === "string") {
3072
+ bodyBlob = new Blob([options.body], { type: options.contentType });
3073
+ } else if (options.body instanceof ArrayBuffer) {
3074
+ bodyBlob = new Blob([options.body], { type: options.contentType });
3075
+ } else {
3076
+ const arrayBuf = await new Response(options.body).arrayBuffer();
3077
+ bodyBlob = new Blob([arrayBuf], { type: options.contentType });
3078
+ }
3079
+ const formData = new FormData();
3080
+ formData.append("file", bodyBlob, options.key.split("/").pop() ?? "file");
3081
+ if (options.kind) formData.append("kind", options.kind);
3082
+ if (options.resource) formData.append("resource", options.resource);
3083
+ if (options.fence !== void 0)
3084
+ formData.append("fence", String(options.fence));
3085
+ if (options.flavor) formData.append("flavor", options.flavor);
3086
+ const result = await this.client.postFormData(
3087
+ `/projects/${this.projectId}/artifacts`,
3088
+ formData,
3089
+ { schema: ArtifactPutResponseSchema, validate: true }
3090
+ );
3091
+ return { key: result.key, bytes: result.bytes };
3092
+ }
3093
+ async get(key) {
3094
+ let response;
3095
+ try {
3096
+ response = await this.client.requestRaw(
3097
+ "GET",
3098
+ `/projects/${this.projectId}/artifacts/${encodeURIComponent(key)}`
3099
+ );
3100
+ } catch (err) {
3101
+ if (err instanceof TilaApiError && err.status === 404) {
3102
+ return null;
3103
+ }
3104
+ throw err;
3105
+ }
3106
+ if (response.status === 404) return null;
3107
+ if (!response.ok) {
3108
+ throw new TilaApiError(
3109
+ response.status,
3110
+ "artifact-get-failed",
3111
+ `GET artifact ${key} failed: ${response.statusText}`,
3112
+ false
3113
+ );
3114
+ }
3115
+ return {
3116
+ body: response.body,
3117
+ contentType: response.headers.get("Content-Type") ?? "application/octet-stream",
3118
+ metadata: {}
3119
+ };
3120
+ }
3121
+ async list(prefix) {
3122
+ const result = await this.client.get(
3123
+ `/projects/${this.projectId}/artifacts`,
3124
+ {
3125
+ schema: ArtifactListInternalSchema,
3126
+ validate: true,
3127
+ query: { resource: prefix }
3128
+ }
3129
+ );
3130
+ return result.pointers.map((p) => ({
3131
+ key: p.r2_key,
3132
+ size: p.bytes
3133
+ }));
3134
+ }
3135
+ async delete(key) {
3136
+ await this.client.delete(
3137
+ `/projects/${this.projectId}/artifacts/${encodeURIComponent(key)}`,
3138
+ {
3139
+ schema: OkSchema,
3140
+ validate: true
3141
+ }
3142
+ );
3143
+ }
3144
+ async listPointers(query) {
3145
+ const q = {};
3146
+ if (query.resource) q.resource = query.resource;
3147
+ if (query.kind) q.kind = query.kind;
3148
+ const result = await this.client.get(
3149
+ `/projects/${this.projectId}/artifacts`,
3150
+ {
3151
+ schema: ArtifactListInternalSchema,
3152
+ validate: true,
3153
+ query: q
3154
+ }
3155
+ );
3156
+ return result.pointers;
3157
+ }
3158
+ async addRelationship(fromKey, toKeyOrUri, type) {
3159
+ const body = {
3160
+ from_key: fromKey,
3161
+ type
3162
+ };
3163
+ if (toKeyOrUri.to_key) body.to_key = toKeyOrUri.to_key;
3164
+ if (toKeyOrUri.to_uri) body.to_uri = toKeyOrUri.to_uri;
3165
+ await this.client.post(
3166
+ `/projects/${this.projectId}/artifacts/relationship`,
3167
+ body,
3168
+ { schema: OkSchema, validate: true }
3169
+ );
3170
+ }
3171
+ async listRelationships(key) {
3172
+ const result = await this.client.get(
3173
+ `/projects/${this.projectId}/artifacts/${encodeURIComponent(key)}/relationships`,
3174
+ { schema: RelListResponseSchema, validate: true }
3175
+ );
3176
+ return result.relationships;
3177
+ }
3178
+ async searchArtifacts(query) {
3179
+ const q = {
3180
+ q: query.q
3181
+ };
3182
+ if (query.kind) q.kind = query.kind;
3183
+ if (query.resource) q.resource = query.resource;
3184
+ if (query.limit !== void 0) q.limit = String(query.limit);
3185
+ const result = await this.client.get(
3186
+ `/projects/${this.projectId}/artifacts/search`,
3187
+ { schema: ArtifactSearchResponseSchema2, validate: true, query: q }
3188
+ );
3189
+ return result.results;
3190
+ }
3191
+ async grepArtifacts(query) {
3192
+ const q = { pattern: query.pattern };
3193
+ if (query.kind) q.kind = query.kind;
3194
+ if (query.resource) q.resource = query.resource;
3195
+ if (query.regex) q.regex = "true";
3196
+ if (query.limit != null) q.limit = String(query.limit);
3197
+ const result = await this.client.get(
3198
+ `/projects/${this.projectId}/artifacts/grep`,
3199
+ { schema: ArtifactGrepResponseSchema, validate: true, query: q }
3200
+ );
3201
+ return result;
3202
+ }
3203
+ async listIndexEntries(indexKey) {
3204
+ const result = await this.client.get(
3205
+ `/projects/${this.projectId}/artifacts/index/entries`,
3206
+ {
3207
+ schema: IndexEntriesResponseSchema,
3208
+ validate: true,
3209
+ query: { index_key: indexKey }
3210
+ }
3211
+ );
3212
+ return result.entries;
3213
+ }
3214
+ async getLatest(kind, resource) {
3215
+ let response;
3216
+ try {
3217
+ response = await this.client.requestRaw(
3218
+ "GET",
3219
+ `/projects/${this.projectId}/artifacts/latest`,
3220
+ { query: { kind, resource } }
3221
+ );
3222
+ } catch (err) {
3223
+ if (err instanceof TilaApiError && err.status === 404) {
3224
+ return null;
3225
+ }
3226
+ throw err;
3227
+ }
3228
+ if (response.status === 404) return null;
3229
+ if (!response.ok) {
3230
+ throw new TilaApiError(
3231
+ response.status,
3232
+ "artifact-get-latest-failed",
3233
+ `GET artifact latest failed: ${response.statusText}`,
3234
+ false
3235
+ );
3236
+ }
3237
+ const body = await response.json();
3238
+ return body.pointer;
3239
+ }
3240
+ async writeText(content, opts) {
3241
+ const result = await this.client.post(
3242
+ `/projects/${this.projectId}/artifacts/text`,
3243
+ {
3244
+ content,
3245
+ kind: opts.kind,
3246
+ mime_type: opts.mimeType ?? "text/markdown",
3247
+ resource: opts.resource,
3248
+ fence: opts.fence
3249
+ },
3250
+ { schema: ArtifactPutResponseSchema, validate: true }
3251
+ );
3252
+ return { key: result.key, bytes: result.bytes };
3253
+ }
3254
+ async readText(key) {
3255
+ let response;
3256
+ try {
3257
+ response = await this.client.requestRaw(
3258
+ "GET",
3259
+ `/projects/${this.projectId}/artifacts/${encodeURIComponent(key)}`
3260
+ );
3261
+ } catch (err) {
3262
+ if (err instanceof TilaApiError && err.status === 404) {
3263
+ return null;
3264
+ }
3265
+ throw err;
3266
+ }
3267
+ if (response.status === 404) return null;
3268
+ const contentType = response.headers.get("content-type") || "application/octet-stream";
3269
+ if (!contentType.startsWith("text/")) {
3270
+ throw new TypeError(
3271
+ `Artifact ${key} has MIME type ${contentType} \u2014 readText only supports text/* artifacts`
3272
+ );
3273
+ }
3274
+ const text = await response.text();
3275
+ return { content: text, mimeType: contentType };
3276
+ }
3277
+ };
3278
+ var RemoteRecordBackend = class {
3279
+ constructor(client, projectId) {
3280
+ this.client = client;
3281
+ this.projectId = projectId;
3282
+ }
3283
+ client;
3284
+ projectId;
3285
+ base() {
3286
+ return `/projects/${this.projectId}/records`;
3287
+ }
3288
+ /** Encode a record key per-segment so embedded `/` separators are preserved. */
3289
+ encodeKey(key) {
3290
+ return key.split("/").map(encodeURIComponent).join("/");
3291
+ }
3292
+ async createRecord(input) {
3293
+ const body = {
3294
+ key: input.key,
3295
+ value: input.value
3296
+ };
3297
+ if (input.tags) body.tags = input.tags;
3298
+ if (input.message != null) body.message = input.message;
3299
+ if (input.sourceArtifactKey != null)
3300
+ body.source_artifact_key = input.sourceArtifactKey;
3301
+ const result = await this.client.post(
3302
+ `${this.base()}/${input.type}`,
3303
+ body,
3304
+ { schema: RecordMutateResponseSchema, validate: true }
3305
+ );
3306
+ return { ...result.record, fence: result.fence };
3307
+ }
3308
+ async setRecord(input) {
3309
+ const body = {
3310
+ value: input.value,
3311
+ fence: input.fence
3312
+ };
3313
+ if (input.tags) body.tags = input.tags;
3314
+ if (input.message != null) body.message = input.message;
3315
+ if (input.sourceArtifactKey != null)
3316
+ body.source_artifact_key = input.sourceArtifactKey;
3317
+ const result = await this.client.put(
3318
+ `${this.base()}/${input.type}/${this.encodeKey(input.key)}`,
3319
+ body,
3320
+ { schema: RecordMutateResponseSchema, validate: true }
3321
+ );
3322
+ return { ...result.record, fence: result.fence };
3323
+ }
3324
+ async getRecord(type, key) {
3325
+ try {
3326
+ const result = await this.client.get(
3327
+ `${this.base()}/${type}/${this.encodeKey(key)}`,
3328
+ { schema: RecordGetResponseSchema, validate: true }
3329
+ );
3330
+ return { ...result.record, fence: result.fence };
3331
+ } catch (err) {
3332
+ if (err instanceof TilaApiError && err.status === 404) {
3333
+ return null;
3334
+ }
3335
+ throw err;
3336
+ }
3337
+ }
3338
+ async patchRecord(input) {
3339
+ const body = {
3340
+ patch: input.patch,
3341
+ fence: input.fence
3342
+ };
3343
+ if (input.message != null) body.message = input.message;
3344
+ const result = await this.client.patch(
3345
+ `${this.base()}/${input.type}/${this.encodeKey(input.key)}`,
3346
+ body,
3347
+ { schema: RecordMutateResponseSchema, validate: true }
3348
+ );
3349
+ return { ...result.record, fence: result.fence };
3350
+ }
3351
+ async archiveRecord(input) {
3352
+ const body = { fence: input.fence };
3353
+ if (input.message != null) body.message = input.message;
3354
+ const result = await this.client.post(
3355
+ `${this.base()}/${input.type}/~/archive/${this.encodeKey(input.key)}`,
3356
+ body,
3357
+ { schema: RecordMutateResponseSchema, validate: true }
3358
+ );
3359
+ return { ...result.record, fence: result.fence };
3360
+ }
3361
+ async unarchiveRecord(input) {
3362
+ const body = { fence: input.fence };
3363
+ if (input.message != null) body.message = input.message;
3364
+ const result = await this.client.post(
3365
+ `${this.base()}/${input.type}/~/unarchive/${this.encodeKey(input.key)}`,
3366
+ body,
3367
+ { schema: RecordMutateResponseSchema, validate: true }
3368
+ );
3369
+ return { ...result.record, fence: result.fence };
3370
+ }
3371
+ async listRecords(filter) {
3372
+ const query = {};
3373
+ if (filter.tag) query.tag = filter.tag;
3374
+ if (filter.includeArchived) query["include-archived"] = "true";
3375
+ if (filter.tagFilter?.length) query.tag_filter = filter.tagFilter.join(",");
3376
+ if (filter.dataFilter) query.filter = JSON.stringify(filter.dataFilter);
3377
+ if (filter.limit !== void 0) query.limit = String(filter.limit);
3378
+ const result = await this.client.get(`${this.base()}/${filter.type}`, {
3379
+ schema: RecordListResponseSchema,
3380
+ validate: true,
3381
+ query
3382
+ });
3383
+ return {
3384
+ items: result.items,
3385
+ total: result.meta.total,
3386
+ next_cursor: result.meta.next_cursor
3387
+ };
3388
+ }
3389
+ async listRecordHistory(type, key, opts) {
3390
+ const query = {};
3391
+ if (opts?.limit !== void 0) query.limit = String(opts.limit);
3392
+ if (opts?.includeValues !== void 0)
3393
+ query.values = String(opts.includeValues);
3394
+ const result = await this.client.get(
3395
+ `${this.base()}/${type}/~/history/${this.encodeKey(key)}`,
3396
+ { schema: RecordHistoryResponseSchema, validate: true, query }
3397
+ );
3398
+ return {
3399
+ items: result.items,
3400
+ total: result.meta.total,
3401
+ next_cursor: result.meta.next_cursor
3402
+ };
3403
+ }
3404
+ async listRecordTypesInUse() {
3405
+ const result = await this.client.get(`${this.base()}/_types`, {
3406
+ schema: RecordTypesInternalSchema,
3407
+ validate: true
3408
+ });
3409
+ return result.in_use_types ?? [];
3410
+ }
3411
+ };
2141
3412
 
2142
- export { ClaimHandle, TILA_ERRORS, TilaApiError, TilaClient, createArtifactMethods, createClaimMethods, createEntityMethods, createGateMethods, createIndexMethods, createJournalMethods, createPresenceMethods, createRecordMethods, createSchemaMethods, createSearchMethods, createSignalMethods, createSummaryMethods, createTaskMethods, createTemplateMethods, createTokenMethods, createWorkUnitMethods, exchangeGitHubToken, isTilaApiError, withClaim, withRetry };
3413
+ export { ClaimHandle, RemoteArtifactBackend, RemoteBackend, RemoteRecordBackend, TILA_ERRORS, TilaApiError, TilaClient, applyPrefix, createArtifactMethods, createClaimMethods, createEntityMethods, createGateMethods, createIndexMethods, createJournalMethods, createNamespace, createPresenceMethods, createRecordMethods, createSchemaMethods, createSearchMethods, createSignalMethods, createSummaryMethods, createTaskMethods, createTemplateMethods, createTila, createTokenMethods, createWorkUnitMethods, exchangeGitHubToken, isTilaApiError, stripPrefix, validateNamespace, withClaim, withRetry };