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