tila-sdk 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,10 +1,8 @@
1
1
  'use strict';
2
2
 
3
- var module$1 = require('module');
4
3
  var zod = require('zod');
5
4
 
6
- var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
7
- // src/client.ts
5
+ // ../schemas/dist/entity.js
8
6
  zod.z.object({
9
7
  id: zod.z.string(),
10
8
  type: zod.z.string(),
@@ -13,7 +11,8 @@ zod.z.object({
13
11
  archived: zod.z.number().int().default(0),
14
12
  created_at: zod.z.number().int(),
15
13
  updated_at: zod.z.number().int(),
16
- created_by: zod.z.string()
14
+ created_by: zod.z.string(),
15
+ tags: zod.z.array(zod.z.string()).default([])
17
16
  });
18
17
  var ClaimModeSchema = zod.z.enum(["exclusive", "owner", "presence"]);
19
18
  zod.z.object({
@@ -75,7 +74,8 @@ zod.z.object({
75
74
  produced_at: zod.z.number().int(),
76
75
  produced_by: zod.z.string(),
77
76
  expires_at: zod.z.number().int().nullable(),
78
- tombstoned: zod.z.number().int().default(0)
77
+ tombstoned: zod.z.number().int().default(0),
78
+ tags: zod.z.array(zod.z.string()).default([])
79
79
  });
80
80
  zod.z.object({
81
81
  entity_id: zod.z.string(),
@@ -163,15 +163,15 @@ zod.z.object({
163
163
  payload: zod.z.unknown().optional(),
164
164
  ttl_ms: zod.z.number().int().min(1e3).max(864e5).optional()
165
165
  });
166
- zod.z.object({
166
+ var SendSignalResponseSchema = zod.z.object({
167
167
  ok: zod.z.literal(true),
168
168
  id: zod.z.string()
169
169
  });
170
- zod.z.object({
170
+ var InboxResponseSchema = zod.z.object({
171
171
  ok: zod.z.literal(true),
172
172
  signals: zod.z.array(SignalSchema)
173
173
  });
174
- zod.z.object({
174
+ var AckSignalResponseSchema = zod.z.object({
175
175
  ok: zod.z.literal(true)
176
176
  });
177
177
  zod.z.object({
@@ -335,6 +335,21 @@ zod.z.object({
335
335
  pages_project_name: zod.z.string().optional(),
336
336
  infra_slug: zod.z.string().optional()
337
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
338
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");
339
354
  var RecordKeySchema = zod.z.string().superRefine((val, ctx) => {
340
355
  if (val.length === 0) {
@@ -411,18 +426,7 @@ var RecordKeySchema = zod.z.string().superRefine((val, ctx) => {
411
426
  }
412
427
  }
413
428
  });
414
- var RecordTagSchema = zod.z.array(zod.z.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9_:.-]{0,63}$/, "Invalid tag format")).transform((tags) => {
415
- const seen = /* @__PURE__ */ new Set();
416
- const result = [];
417
- for (const tag of tags) {
418
- const lower = tag.toLowerCase();
419
- if (!seen.has(lower)) {
420
- seen.add(lower);
421
- result.push(lower);
422
- }
423
- }
424
- return result;
425
- }).refine((tags) => tags.length <= 20, "Record may not have more than 20 tags");
429
+ var RecordTagSchema = TagsSchema;
426
430
  function sortKeysDeep(v) {
427
431
  if (Array.isArray(v))
428
432
  return v.map(sortKeysDeep);
@@ -461,7 +465,7 @@ zod.z.object({
461
465
  idempotency_key: zod.z.string().optional(),
462
466
  metadata: zod.z.record(zod.z.unknown()).optional()
463
467
  });
464
- zod.z.object({
468
+ var AcquireSuccessResponseSchema = zod.z.object({
465
469
  ok: zod.z.literal(true),
466
470
  fence: zod.z.number().int(),
467
471
  expires_at: zod.z.number().int()
@@ -471,7 +475,7 @@ zod.z.object({
471
475
  fence: zod.z.number().int(),
472
476
  ttl_ms: zod.z.number().int().positive()
473
477
  });
474
- zod.z.object({
478
+ var RenewSuccessResponseSchema = zod.z.object({
475
479
  ok: zod.z.literal(true),
476
480
  expires_at: zod.z.number().int()
477
481
  });
@@ -479,10 +483,10 @@ zod.z.object({
479
483
  resource: zod.z.string(),
480
484
  fence: zod.z.number().int()
481
485
  });
482
- zod.z.object({
486
+ var ReleaseSuccessResponseSchema = zod.z.object({
483
487
  ok: zod.z.literal(true)
484
488
  });
485
- zod.z.object({
489
+ var StateResponseSchema = zod.z.object({
486
490
  ok: zod.z.literal(true),
487
491
  claim: zod.z.object({
488
492
  resource: zod.z.string(),
@@ -511,16 +515,18 @@ zod.z.object({
511
515
  zod.z.object({
512
516
  id: zod.z.string(),
513
517
  type: zod.z.string(),
514
- data: zod.z.record(zod.z.unknown()).default({})
518
+ data: zod.z.record(zod.z.unknown()).default({}),
519
+ tags: TagsSchema.optional()
515
520
  });
516
521
  zod.z.object({
517
522
  data: zod.z.record(zod.z.unknown()),
518
- fence: zod.z.number().int()
523
+ fence: zod.z.number().int(),
524
+ tags: TagsSchema.optional()
519
525
  });
520
526
  zod.z.object({
521
527
  fence: zod.z.number().int()
522
528
  });
523
- zod.z.object({
529
+ var EntityResponseSchema = zod.z.object({
524
530
  ok: zod.z.literal(true),
525
531
  entity: zod.z.object({
526
532
  id: zod.z.string(),
@@ -530,7 +536,8 @@ zod.z.object({
530
536
  archived: zod.z.number().int(),
531
537
  created_at: zod.z.number().int(),
532
538
  updated_at: zod.z.number().int(),
533
- created_by: zod.z.string()
539
+ created_by: zod.z.string(),
540
+ tags: zod.z.array(zod.z.string())
534
541
  })
535
542
  });
536
543
  zod.z.object({
@@ -543,10 +550,11 @@ zod.z.object({
543
550
  archived: zod.z.number().int(),
544
551
  created_at: zod.z.number().int(),
545
552
  updated_at: zod.z.number().int(),
546
- created_by: zod.z.string()
553
+ created_by: zod.z.string(),
554
+ tags: zod.z.array(zod.z.string())
547
555
  }))
548
556
  });
549
- zod.z.object({
557
+ var PaginatedEntityListResponseSchema = zod.z.object({
550
558
  ok: zod.z.literal(true),
551
559
  entities: zod.z.array(zod.z.object({
552
560
  id: zod.z.string(),
@@ -556,14 +564,15 @@ zod.z.object({
556
564
  archived: zod.z.number().int(),
557
565
  created_at: zod.z.number().int(),
558
566
  updated_at: zod.z.number().int(),
559
- created_by: zod.z.string()
567
+ created_by: zod.z.string(),
568
+ tags: zod.z.array(zod.z.string())
560
569
  })),
561
570
  total: zod.z.number().int(),
562
571
  limit: zod.z.number().int().nullable(),
563
572
  offset: zod.z.number().int(),
564
573
  has_more: zod.z.boolean()
565
574
  });
566
- zod.z.object({
575
+ var ListReadyEntitiesResponseSchema = zod.z.object({
567
576
  ok: zod.z.literal(true),
568
577
  entities: zod.z.array(zod.z.object({
569
578
  id: zod.z.string(),
@@ -593,7 +602,7 @@ zod.z.object({
593
602
  ok: zod.z.literal(true),
594
603
  entity: CompactEntitySchema
595
604
  });
596
- zod.z.object({
605
+ var PaginatedCompactEntityListResponseSchema = zod.z.object({
597
606
  ok: zod.z.literal(true),
598
607
  entities: zod.z.array(CompactEntitySchema),
599
608
  total: zod.z.number().int(),
@@ -601,7 +610,7 @@ zod.z.object({
601
610
  offset: zod.z.number().int(),
602
611
  has_more: zod.z.boolean()
603
612
  });
604
- zod.z.object({
613
+ var SummaryResponseSchema = zod.z.object({
605
614
  ok: zod.z.literal(true),
606
615
  project: zod.z.object({
607
616
  entity_count: zod.z.number().int(),
@@ -620,7 +629,7 @@ zod.z.object({
620
629
  }))
621
630
  })
622
631
  });
623
- zod.z.object({
632
+ var EntityDetailResponseSchema = zod.z.object({
624
633
  ok: zod.z.literal(true),
625
634
  entity: zod.z.object({
626
635
  id: zod.z.string(),
@@ -630,11 +639,12 @@ zod.z.object({
630
639
  archived: zod.z.number().int(),
631
640
  created_at: zod.z.number().int(),
632
641
  updated_at: zod.z.number().int(),
633
- created_by: zod.z.string()
642
+ created_by: zod.z.string(),
643
+ tags: zod.z.array(zod.z.string())
634
644
  }),
635
645
  relationships: zod.z.array(EntityRelationshipSchema).default([])
636
646
  });
637
- zod.z.object({
647
+ var ArchiveSuccessResponseSchema = zod.z.object({
638
648
  ok: zod.z.literal(true)
639
649
  });
640
650
  zod.z.object({
@@ -642,7 +652,7 @@ zod.z.object({
642
652
  to_id: zod.z.string().min(1),
643
653
  type: EntityRelationshipTypeSchema
644
654
  });
645
- zod.z.object({
655
+ var CreateEntityRelationshipResponseSchema = zod.z.object({
646
656
  ok: zod.z.literal(true),
647
657
  created: zod.z.boolean().default(true)
648
658
  });
@@ -651,7 +661,7 @@ zod.z.object({
651
661
  to_id: zod.z.string().min(1).optional(),
652
662
  type: EntityRelationshipTypeSchema.optional()
653
663
  });
654
- zod.z.object({
664
+ var ListEntityRelationshipsResponseSchema = zod.z.object({
655
665
  ok: zod.z.literal(true),
656
666
  relationships: zod.z.array(EntityRelationshipSchema)
657
667
  });
@@ -660,7 +670,7 @@ zod.z.object({
660
670
  to_id: zod.z.string().min(1),
661
671
  type: EntityRelationshipTypeSchema
662
672
  });
663
- zod.z.object({
673
+ var DeleteEntityRelationshipResponseSchema = zod.z.object({
664
674
  ok: zod.z.literal(true),
665
675
  removed: zod.z.boolean()
666
676
  });
@@ -671,7 +681,7 @@ zod.z.object({
671
681
  after_seq: zod.z.number().int().optional(),
672
682
  limit: zod.z.number().int().positive().default(100)
673
683
  });
674
- zod.z.object({
684
+ var JournalResponseSchema = zod.z.object({
675
685
  ok: zod.z.literal(true),
676
686
  events: zod.z.array(zod.z.object({
677
687
  seq: zod.z.number().int(),
@@ -698,7 +708,7 @@ zod.z.object({
698
708
  info: zod.z.record(zod.z.unknown())
699
709
  }))
700
710
  });
701
- zod.z.object({
711
+ var PresenceAllListResponseSchema = zod.z.object({
702
712
  ok: zod.z.literal(true),
703
713
  machines: zod.z.array(zod.z.object({
704
714
  machine: zod.z.string(),
@@ -707,7 +717,7 @@ zod.z.object({
707
717
  active: zod.z.boolean()
708
718
  }))
709
719
  });
710
- zod.z.object({
720
+ var PresenceHeartbeatSuccessResponseSchema = zod.z.object({
711
721
  ok: zod.z.literal(true)
712
722
  });
713
723
  zod.z.object({
@@ -849,7 +859,7 @@ zod.z.object({
849
859
  slot: zod.z.string().min(1),
850
860
  metadata: zod.z.record(zod.z.unknown()).default({})
851
861
  });
852
- zod.z.object({
862
+ var EntityArtifactReferenceListResponseSchema = zod.z.object({
853
863
  ok: zod.z.literal(true),
854
864
  references: zod.z.array(zod.z.object({
855
865
  entity_id: zod.z.string(),
@@ -859,6 +869,46 @@ zod.z.object({
859
869
  created_at: zod.z.number().int()
860
870
  }))
861
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));
862
912
  zod.z.object({
863
913
  ok: zod.z.literal(true),
864
914
  results: zod.z.array(ArtifactSearchResultSchema),
@@ -869,7 +919,8 @@ zod.z.object({
869
919
  kind: zod.z.string().optional(),
870
920
  resource: zod.z.string().optional(),
871
921
  source_only: zod.z.string().optional().transform((v) => v === "true").pipe(zod.z.boolean()),
872
- 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
873
924
  });
874
925
  var ArtifactGrepLineSchema = zod.z.object({
875
926
  line: zod.z.number().int(),
@@ -887,7 +938,7 @@ var ArtifactGrepResultSchema = zod.z.object({
887
938
  truncated: zod.z.boolean().optional()
888
939
  // this blob hit the per-blob byte cap
889
940
  });
890
- zod.z.object({
941
+ var ArtifactGrepResponseSchema = zod.z.object({
891
942
  ok: zod.z.literal(true),
892
943
  results: zod.z.array(ArtifactGrepResultSchema),
893
944
  scanned: zod.z.number().int(),
@@ -923,16 +974,18 @@ zod.z.object({
923
974
  });
924
975
  zod.z.object({
925
976
  q: zod.z.string().min(1).max(200),
926
- 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
927
979
  });
928
980
  zod.z.object({
929
981
  content: zod.z.string().min(1),
930
982
  kind: zod.z.string().min(1),
931
983
  mime_type: zod.z.string().default("text/markdown"),
932
984
  resource: zod.z.string().optional(),
933
- fence: zod.z.number().int().optional()
985
+ fence: zod.z.number().int().optional(),
986
+ tags: TagsSchema.optional()
934
987
  });
935
- zod.z.object({
988
+ var ArtifactPutResponseSchema = zod.z.object({
936
989
  ok: zod.z.literal(true),
937
990
  key: zod.z.string(),
938
991
  bytes: zod.z.number(),
@@ -951,7 +1004,8 @@ zod.z.object({
951
1004
  produced_at: zod.z.number(),
952
1005
  produced_by: zod.z.string(),
953
1006
  expires_at: zod.z.number().nullable(),
954
- tombstoned: zod.z.number()
1007
+ tombstoned: zod.z.number(),
1008
+ tags: zod.z.array(zod.z.string())
955
1009
  }))
956
1010
  });
957
1011
  zod.z.object({
@@ -1038,12 +1092,15 @@ var RecordItemSchema = zod.z.object({
1038
1092
  updated_by: zod.z.string(),
1039
1093
  tags: zod.z.array(zod.z.string())
1040
1094
  });
1041
- zod.z.object({
1095
+ RecordItemSchema.extend({
1096
+ fence: zod.z.number().int()
1097
+ });
1098
+ var RecordGetResponseSchema = zod.z.object({
1042
1099
  ok: zod.z.literal(true),
1043
1100
  record: RecordItemSchema,
1044
1101
  fence: zod.z.number().int()
1045
1102
  });
1046
- zod.z.object({
1103
+ var RecordMutateResponseSchema = zod.z.object({
1047
1104
  ok: zod.z.literal(true),
1048
1105
  record: RecordItemSchema,
1049
1106
  fence: zod.z.number().int(),
@@ -1058,7 +1115,7 @@ var RecordListItemSchema = zod.z.object({
1058
1115
  archived: zod.z.number().int(),
1059
1116
  tags: zod.z.array(zod.z.string())
1060
1117
  });
1061
- zod.z.object({
1118
+ var RecordListResponseSchema = zod.z.object({
1062
1119
  ok: zod.z.literal(true),
1063
1120
  items: zod.z.array(RecordListItemSchema),
1064
1121
  meta: zod.z.object({
@@ -1078,9 +1135,12 @@ var RecordHistoryItemSchema = zod.z.object({
1078
1135
  source_artifact_key: zod.z.string().nullable(),
1079
1136
  actor: zod.z.string(),
1080
1137
  created_at: zod.z.number().int(),
1081
- 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()
1082
1142
  });
1083
- zod.z.object({
1143
+ var RecordHistoryResponseSchema = zod.z.object({
1084
1144
  ok: zod.z.literal(true),
1085
1145
  items: zod.z.array(RecordHistoryItemSchema),
1086
1146
  meta: zod.z.object({
@@ -1190,392 +1250,208 @@ zod.z.object({
1190
1250
  zod.z.object({
1191
1251
  resolution: zod.z.string().optional()
1192
1252
  });
1193
- zod.z.object({
1253
+ var GateResponseSchema = zod.z.object({
1194
1254
  ok: zod.z.literal(true),
1195
1255
  gate: GateSchema
1196
1256
  });
1197
- zod.z.object({
1257
+ var GateListResponseSchema = zod.z.object({
1198
1258
  ok: zod.z.literal(true),
1199
1259
  gates: zod.z.array(GateSchema)
1200
1260
  });
1201
1261
 
1202
- // src/client.ts
1203
- var require2 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
1204
- var SDK_VERSION = require2("../package.json").version;
1205
- var TilaClient = class _TilaClient {
1206
- baseUrl;
1207
- token;
1208
- validate;
1209
- timeoutMs;
1210
- extraHeaders;
1211
- constructor(opts) {
1212
- this.baseUrl = opts.baseUrl.replace(/\/+$/, "");
1213
- this.token = opts.token;
1214
- this.validate = opts.validate ?? false;
1215
- this.timeoutMs = opts.timeoutMs ?? 3e4;
1216
- this.extraHeaders = {
1217
- "X-Tila-Source": `sdk/${SDK_VERSION}`,
1218
- ...opts.extraHeaders
1219
- };
1220
- }
1221
- /**
1222
- * Creates an AbortSignal that fires after this.timeoutMs.
1223
- * Uses AbortSignal.timeout() when available (Node 18.8+, Bun 0.5+, browsers),
1224
- * falls back to manual setTimeout + AbortController for older runtimes.
1225
- *
1226
- * Note: Cloudflare Workers has supported AbortSignal.timeout() since 2023;
1227
- * the fallback branch will never execute there.
1228
- */
1229
- createAbortSignal() {
1230
- if (typeof AbortSignal.timeout === "function") {
1231
- return AbortSignal.timeout(this.timeoutMs);
1232
- }
1233
- const controller = new AbortController();
1234
- setTimeout(
1235
- () => controller.abort(
1236
- new DOMException(
1237
- "The operation was aborted due to timeout",
1238
- "TimeoutError"
1239
- )
1240
- ),
1241
- this.timeoutMs
1242
- );
1243
- return controller.signal;
1244
- }
1245
- static fromConfig(config, token) {
1246
- if (!config.worker_url) {
1247
- throw new Error(
1248
- `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)}`
1249
1315
  );
1250
- }
1251
- return new _TilaClient({ baseUrl: config.worker_url, token });
1252
- }
1253
- async request(method, path, opts) {
1254
- const url = new URL(path, `${this.baseUrl}/`);
1255
- if (opts?.query) {
1256
- for (const [key, value] of Object.entries(opts.query)) {
1257
- if (value !== void 0) {
1258
- 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
1259
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;
1260
1367
  }
1261
- }
1262
- const headers = {
1263
- Authorization: `Bearer ${this.token}`,
1264
- Accept: "application/json",
1265
- ...this.extraHeaders
1266
- };
1267
- const init = {
1268
- method,
1269
- headers,
1270
- signal: this.createAbortSignal()
1271
- };
1272
- if (opts?.body !== void 0) {
1273
- headers["Content-Type"] = "application/json";
1274
- init.body = JSON.stringify(opts.body);
1275
- }
1276
- let res;
1277
- try {
1278
- res = await fetch(url.toString(), init);
1279
- } catch (err) {
1280
- if (err instanceof Error && (err.name === "AbortError" || err.name === "TimeoutError")) {
1281
- throw new Error(
1282
- `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`
1283
1391
  );
1284
1392
  }
1285
- throw new Error(
1286
- `Network error connecting to ${url.origin}: ${err instanceof Error ? err.message : String(err)}`
1287
- );
1288
- }
1289
- if (!res.ok) {
1290
- await this.throwApiError(res);
1291
- }
1292
- const body = await res.json();
1293
- const shouldValidate = opts?.validate ?? this.validate;
1294
- if (shouldValidate && opts?.schema) {
1295
- const result = opts.schema.safeParse(body);
1296
- if (!result.success) {
1297
- const issues = result.error.issues.map((i) => ` - ${i.path.join(".")}: ${i.message}`).join("\n");
1298
- throw new Error(
1299
- `Unexpected response shape from ${method} ${path}:
1300
- ${issues}`
1301
- );
1302
- }
1303
- return result.data;
1304
- }
1305
- return body;
1306
- }
1307
- async get(path, opts) {
1308
- return this.request("GET", path, {
1309
- schema: opts?.schema,
1310
- query: opts?.query,
1311
- validate: opts?.validate
1312
- });
1313
- }
1314
- async post(path, body, opts) {
1315
- return this.request("POST", path, {
1316
- body,
1317
- schema: opts?.schema,
1318
- validate: opts?.validate
1319
- });
1320
- }
1321
- async put(path, body, opts) {
1322
- return this.request("PUT", path, {
1323
- body,
1324
- schema: opts?.schema,
1325
- validate: opts?.validate
1326
- });
1327
- }
1328
- async patch(path, body, opts) {
1329
- return this.request("PATCH", path, {
1330
- body,
1331
- schema: opts?.schema,
1332
- validate: opts?.validate
1333
- });
1334
- }
1335
- async delete(path, opts) {
1336
- return this.request("DELETE", path, {
1337
- schema: opts?.schema,
1338
- validate: opts?.validate
1339
- });
1340
- }
1341
- async requestRaw(method, path, opts) {
1342
- const url = new URL(path, `${this.baseUrl}/`);
1343
- if (opts?.query) {
1344
- for (const [key, value] of Object.entries(opts.query)) {
1345
- if (value !== void 0) {
1346
- url.searchParams.set(key, value);
1347
- }
1348
- }
1393
+ const text = await res.text();
1394
+ return { content: text, mimeType: contentType };
1349
1395
  }
1350
- const headers = {
1351
- Authorization: `Bearer ${this.token}`,
1352
- ...this.extraHeaders
1353
- };
1354
- let res;
1355
- try {
1356
- res = await fetch(url.toString(), {
1357
- method,
1358
- headers,
1359
- 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
1360
1409
  });
1361
- } catch (err) {
1362
- if (err instanceof Error && (err.name === "AbortError" || err.name === "TimeoutError")) {
1363
- throw new Error(
1364
- `Request to ${url.origin} timed out after ${this.timeoutMs}ms`
1365
- );
1366
- }
1367
- throw new Error(
1368
- `Network error connecting to ${url.origin}: ${err instanceof Error ? err.message : String(err)}`
1369
- );
1370
- }
1371
- if (!res.ok) {
1372
- await this.throwApiError(res);
1373
- }
1374
- return res;
1375
- }
1376
- async postFormData(path, formData, opts) {
1377
- const url = new URL(path, `${this.baseUrl}/`);
1378
- const headers = {
1379
- Authorization: `Bearer ${this.token}`,
1380
- Accept: "application/json",
1381
- ...this.extraHeaders
1382
- };
1383
- let res;
1384
- try {
1385
- res = await fetch(url.toString(), {
1386
- method: "POST",
1387
- headers,
1388
- body: formData,
1389
- signal: this.createAbortSignal()
1410
+ },
1411
+ async renew(resource, fence, ttlMs) {
1412
+ return client.post(`${base}/renew`, {
1413
+ resource,
1414
+ fence,
1415
+ ttl_ms: ttlMs
1390
1416
  });
1391
- } catch (err) {
1392
- if (err instanceof Error && (err.name === "AbortError" || err.name === "TimeoutError")) {
1393
- throw new Error(
1394
- `Request to ${url.origin} timed out after ${this.timeoutMs}ms`
1395
- );
1396
- }
1397
- throw new Error(
1398
- `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)}`
1399
1430
  );
1400
1431
  }
1401
- if (!res.ok) {
1402
- await this.throwApiError(res);
1403
- }
1404
- const body = await res.json();
1405
- const shouldValidate = opts?.validate ?? this.validate;
1406
- if (shouldValidate && opts?.schema) {
1407
- const result = opts.schema.safeParse(body);
1408
- if (!result.success) {
1409
- const issues = result.error.issues.map((i) => ` - ${i.path.join(".")}: ${i.message}`).join("\n");
1410
- throw new Error(
1411
- `Unexpected response shape from POST ${path}:
1412
- ${issues}`
1413
- );
1414
- }
1415
- return result.data;
1416
- }
1417
- return body;
1418
- }
1419
- async throwApiError(res) {
1420
- try {
1421
- const body = await res.json();
1422
- const parsed = ErrorEnvelopeSchema.safeParse(body);
1423
- if (parsed.success) {
1424
- const { code, message, retryable } = parsed.data.error;
1425
- throw new TilaApiError(res.status, code, message, retryable);
1426
- }
1427
- } catch (err) {
1428
- if (err instanceof TilaApiError) throw err;
1429
- }
1430
- throw new TilaApiError(
1431
- res.status,
1432
- "UNKNOWN",
1433
- `HTTP ${res.status}: ${res.statusText}`,
1434
- false
1435
- );
1436
- }
1437
- };
1438
- var TilaApiError = class extends Error {
1439
- constructor(status, code, message, retryable) {
1440
- super(message);
1441
- this.status = status;
1442
- this.code = code;
1443
- this.retryable = retryable;
1444
- this.name = "TilaApiError";
1445
- }
1446
- status;
1447
- code;
1448
- retryable;
1449
- };
1450
- function isTilaApiError(err) {
1451
- return err instanceof TilaApiError;
1452
- }
1453
- async function exchangeGitHubToken(baseUrl, projectId, githubToken) {
1454
- const url = `${baseUrl.replace(/\/+$/, "")}/api/auth/github/exchange`;
1455
- let res;
1456
- try {
1457
- res = await fetch(url, {
1458
- method: "POST",
1459
- headers: { "Content-Type": "application/json" },
1460
- body: JSON.stringify({
1461
- project_id: projectId,
1462
- github_token: githubToken
1463
- })
1464
- });
1465
- } catch (err) {
1466
- throw new Error(
1467
- `Network error during GitHub token exchange: ${err instanceof Error ? err.message : String(err)}`
1468
- );
1469
- }
1470
- if (!res.ok) {
1471
- try {
1472
- const body2 = await res.json();
1473
- const parsed = ErrorEnvelopeSchema.safeParse(body2);
1474
- if (parsed.success) {
1475
- const { code, message, retryable } = parsed.data.error;
1476
- throw new TilaApiError(res.status, code, message, retryable);
1477
- }
1478
- } catch (err) {
1479
- if (err instanceof TilaApiError) throw err;
1480
- }
1481
- throw new TilaApiError(
1482
- res.status,
1483
- "UNKNOWN",
1484
- `HTTP ${res.status}: ${res.statusText}`,
1485
- false
1486
- );
1487
- }
1488
- const body = await res.json();
1489
- if (!body.session_token || typeof body.expires_at !== "number") {
1490
- throw new TypeError(
1491
- "Exchange returned unexpected response shape: missing session_token or expires_at"
1492
- );
1493
- }
1494
- return {
1495
- sessionToken: body.session_token,
1496
- expiresAt: body.expires_at,
1497
- permission: body.permission ?? "read"
1498
1432
  };
1499
1433
  }
1500
1434
 
1501
- // src/retry.ts
1502
- async function withRetry(fn, opts) {
1503
- const maxRetries = opts?.maxRetries ?? 3;
1504
- const baseDelayMs = opts?.baseDelayMs ?? 200;
1505
- const maxDelayMs = opts?.maxDelayMs ?? 3e4;
1506
- const jitter = opts?.jitter ?? true;
1507
- for (let attempt = 0; attempt <= maxRetries; attempt++) {
1508
- try {
1509
- return await fn();
1510
- } catch (err) {
1511
- if (isTilaApiError(err) && err.retryable === false) {
1512
- throw err;
1513
- }
1514
- if (attempt === maxRetries) {
1515
- throw err;
1516
- }
1517
- const cap = Math.min(maxDelayMs, baseDelayMs * 2 ** attempt);
1518
- const sleepMs = jitter ? Math.random() * cap : cap;
1519
- await new Promise((resolve) => setTimeout(resolve, sleepMs));
1520
- }
1521
- }
1522
- throw new Error("withRetry: unreachable");
1523
- }
1524
-
1525
- // src/error-codes.ts
1526
- var TILA_ERRORS = {
1527
- // Auth / middleware (worker layer — SCREAMING_SNAKE_CASE wire values)
1528
- UNAUTHORIZED: "UNAUTHORIZED",
1529
- SESSION_EXPIRED: "SESSION_EXPIRED",
1530
- RATE_LIMITED: "RATE_LIMITED",
1531
- PERMISSION_DENIED: "PERMISSION_DENIED",
1532
- PROJECT_MISMATCH: "PROJECT_MISMATCH",
1533
- CSRF_MISSING_ORIGIN: "CSRF_MISSING_ORIGIN",
1534
- CSRF_ORIGIN_MISMATCH: "CSRF_ORIGIN_MISMATCH",
1535
- INTERNAL_ERROR: "INTERNAL_ERROR",
1536
- DO_UNREACHABLE: "do-unreachable",
1537
- // Auth endpoint specific
1538
- REPO_NOT_ALLOWED: "REPO_NOT_ALLOWED",
1539
- GITHUB_AUTH_FAILED: "GITHUB_AUTH_FAILED",
1540
- HMAC_NOT_CONFIGURED: "HMAC_NOT_CONFIGURED",
1541
- // Token endpoint specific
1542
- TOKEN_NAME_CONFLICT: "TOKEN_NAME_CONFLICT",
1543
- TOKEN_AUTHZ_DENIED: "TOKEN_AUTHZ_DENIED",
1544
- TOKEN_NOT_FOUND: "TOKEN_NOT_FOUND",
1545
- // Validation (worker layer uses SCREAMING_SNAKE for this code)
1546
- VALIDATION_ERROR: "VALIDATION_ERROR",
1547
- // DO errors (project-do-router — kebab-case wire values)
1548
- STALE_FENCE: "stale-fence",
1549
- NOT_FOUND: "not-found",
1550
- GATE_ALREADY_SETTLED: "gate-already-settled",
1551
- NO_FENCE: "no-fence",
1552
- INTERNAL: "internal",
1553
- CONSTRAINT_VIOLATION: "constraint-violation",
1554
- IDEMPOTENCY_KEY_CONFLICT: "idempotency-key-conflict",
1555
- // DO-layer validation uses kebab-case (distinct from VALIDATION_ERROR above)
1556
- VALIDATION_ERROR_DO: "validation-error",
1557
- ALREADY_HELD: "already-held",
1558
- RENEW_FAILED: "renew-failed",
1559
- BAD_REQUEST: "bad-request",
1560
- MISSING_QUERY: "missing-query",
1561
- INVALID_QUERY: "invalid-query",
1562
- INVALID_SLOT: "invalid-slot",
1563
- INVALID_RELATIONSHIP_TYPE: "invalid-relationship-type",
1564
- // Fallback (SDK-generated when response is unparseable)
1565
- UNKNOWN: "UNKNOWN"
1566
- };
1567
-
1568
1435
  // src/entities.ts
1569
1436
  function _createMethods(client, base) {
1570
1437
  return {
1571
- async create(id, type, data) {
1572
- 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
+ });
1573
1445
  },
1574
1446
  async get(id) {
1575
1447
  return client.get(`${base}/${id}`);
1576
1448
  },
1577
1449
  async list(query) {
1578
- 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 });
1579
1455
  },
1580
1456
  async update(id, data, fence) {
1581
1457
  return client.patch(`${base}/${id}`, { data, fence });
@@ -1587,13 +1463,34 @@ function _createMethods(client, base) {
1587
1463
  },
1588
1464
  async addRelationship(fromId, toId, type) {
1589
1465
  return client.post(
1590
- `${base}/${fromId}/relationships`,
1466
+ `${base}/relationships`,
1591
1467
  {
1468
+ from_id: fromId,
1592
1469
  to_id: toId,
1593
1470
  type
1594
1471
  }
1595
1472
  );
1596
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
+ },
1597
1494
  async addArtifactRef(entityId, artifactKey, slot, metadata) {
1598
1495
  return client.post(`${base}/${entityId}/artifact-refs`, {
1599
1496
  artifact_key: artifactKey,
@@ -1608,366 +1505,663 @@ function _createMethods(client, base) {
1608
1505
  }
1609
1506
  };
1610
1507
  }
1611
- function createTaskMethods(client, projectId) {
1612
- return _createMethods(client, `/projects/${projectId}/tasks`);
1613
- }
1614
- function createEntityMethods(client, projectId) {
1615
- return _createMethods(client, `/projects/${projectId}/entities`);
1616
- }
1617
- function createWorkUnitMethods(client, projectId) {
1618
- return _createMethods(client, `/projects/${projectId}/work-units`);
1619
- }
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
+ }
1620
1722
 
1621
- // src/claims.ts
1622
- function createClaimMethods(client, projectId) {
1623
- const base = `/projects/${projectId}/claims`;
1723
+ // src/tokens.ts
1724
+ function createTokenMethods(client) {
1725
+ const base = "/api/tokens";
1624
1726
  return {
1625
- async acquire(resource, mode, ttlMs, opts) {
1626
- return client.post(`${base}/acquire`, {
1627
- resource,
1628
- mode,
1629
- ttl_ms: ttlMs,
1630
- ...opts
1631
- });
1632
- },
1633
- async renew(resource, fence, ttlMs) {
1634
- return client.post(`${base}/renew`, {
1635
- resource,
1636
- fence,
1637
- ttl_ms: ttlMs
1638
- });
1727
+ async issue(name, note) {
1728
+ return client.post(base, { name, note });
1639
1729
  },
1640
- async release(resource, fence) {
1641
- return client.post(`${base}/release`, {
1642
- resource,
1643
- fence
1644
- });
1730
+ async revoke(name) {
1731
+ return client.delete(
1732
+ `${base}/${encodeURIComponent(name)}`
1733
+ );
1645
1734
  },
1646
1735
  async list() {
1647
1736
  return client.get(base);
1648
- },
1649
- async get(resource) {
1650
- return client.get(
1651
- `${base}/${encodeURIComponent(resource)}`
1652
- );
1653
1737
  }
1654
1738
  };
1655
1739
  }
1656
1740
 
1657
- // src/artifacts.ts
1658
- function createArtifactMethods(client, projectId) {
1659
- const base = `/projects/${projectId}/artifacts`;
1660
- return {
1661
- upload: Object.assign(
1662
- function upload(input, opts) {
1663
- if (input instanceof ReadableStream) {
1664
- if (!opts.mimeType) {
1665
- throw new TypeError(
1666
- "mimeType is required when uploading a ReadableStream. Pass opts.mimeType explicitly."
1667
- );
1668
- }
1669
- return new Response(input).arrayBuffer().then((bytes) => {
1670
- const uploadFile = new Blob([bytes], {
1671
- type: opts.mimeType
1672
- });
1673
- const formData2 = new FormData();
1674
- formData2.append("file", uploadFile);
1675
- formData2.append("kind", opts.kind);
1676
- formData2.append("mime_type", opts.mimeType);
1677
- if (opts.resource) formData2.append("resource", opts.resource);
1678
- if (opts.fence !== void 0)
1679
- formData2.append("fence", String(opts.fence));
1680
- if (opts.flavor) formData2.append("flavor", opts.flavor);
1681
- return client.postFormData(base, formData2);
1682
- });
1683
- }
1684
- const contentType = opts.mimeType || (input instanceof File ? input.type : "") || "";
1685
- if (!contentType) {
1686
- throw new TypeError(
1687
- "contentType is required for uploads when file.type is absent. Pass opts.mimeType explicitly."
1688
- );
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);
1689
1810
  }
1690
- const formData = new FormData();
1691
- formData.append("file", input);
1692
- formData.append("kind", opts.kind);
1693
- formData.append("mime_type", contentType);
1694
- if (opts.resource) formData.append("resource", opts.resource);
1695
- if (opts.fence !== void 0)
1696
- formData.append("fence", String(opts.fence));
1697
- if (opts.flavor) formData.append("flavor", opts.flavor);
1698
- return client.postFormData(base, formData);
1699
- },
1700
- {}
1701
- ),
1702
- async download(key) {
1703
- const res = await client.requestRaw(
1704
- "GET",
1705
- `${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)}`
1706
1838
  );
1707
- return {
1708
- body: res.body ?? new ReadableStream(),
1709
- contentType: res.headers.get("content-type") || "application/octet-stream",
1710
- contentLength: res.headers.has("content-length") ? Number(res.headers.get("content-length")) : null
1711
- };
1712
- },
1713
- async list(query) {
1714
- return client.get(base, { query });
1715
- },
1716
- async search(q, opts) {
1717
- return client.get(`${base}/search`, {
1718
- query: { q, ...opts }
1719
- });
1720
- },
1721
- async grep(pattern, opts) {
1722
- const query = { pattern };
1723
- if (opts?.kind) query.kind = opts.kind;
1724
- if (opts?.resource) query.resource = opts.resource;
1725
- if (opts?.regex) query.regex = "true";
1726
- if (opts?.limit != null) query.limit = String(opts.limit);
1727
- return client.get(`${base}/grep`, { query });
1728
- },
1729
- async addRelationship(fromKey, toKeyOrUri, type, metadata) {
1730
- const isUri = toKeyOrUri.includes("://");
1731
- return client.post(
1732
- `${base}/${encodeURIComponent(fromKey)}/relationships`,
1733
- {
1734
- [isUri ? "to_uri" : "to_key"]: toKeyOrUri,
1735
- type,
1736
- 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);
1737
1898
  }
1738
- );
1739
- },
1740
- async listRelationships(key) {
1741
- return client.get(
1742
- `${base}/${encodeURIComponent(key)}/relationships`
1743
- );
1744
- },
1745
- async getLatest(kind, resource) {
1746
- const res = await client.requestRaw("GET", `${base}/latest`, {
1747
- 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()
1748
1911
  });
1749
- if (res.status === 404) return null;
1750
- if (!res.ok) {
1751
- const body2 = await res.json().catch(() => ({}));
1912
+ } catch (err) {
1913
+ if (err instanceof Error && (err.name === "AbortError" || err.name === "TimeoutError")) {
1752
1914
  throw new Error(
1753
- `getLatest failed with status ${res.status}: ${JSON.stringify(body2)}`
1915
+ `Request to ${url.origin} timed out after ${this.timeoutMs}ms`
1754
1916
  );
1755
1917
  }
1756
- const body = await res.json();
1757
- return body.pointer;
1758
- },
1759
- async writeText(content, opts) {
1760
- return client.post(`${base}/text`, {
1761
- content,
1762
- kind: opts.kind,
1763
- mime_type: opts.mimeType ?? "text/markdown",
1764
- resource: opts.resource,
1765
- fence: opts.fence
1766
- });
1767
- },
1768
- async readText(key) {
1769
- const res = await client.requestRaw(
1770
- "GET",
1771
- `${base}/${encodeURIComponent(key)}`
1918
+ throw new Error(
1919
+ `Network error connecting to ${url.origin}: ${err instanceof Error ? err.message : String(err)}`
1772
1920
  );
1773
- const contentType = res.headers.get("content-type") || "application/octet-stream";
1774
- if (!contentType.startsWith("text/")) {
1775
- throw new TypeError(
1776
- `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`
1777
1946
  );
1778
1947
  }
1779
- const text = await res.text();
1780
- return { content: text, mimeType: contentType };
1781
- }
1782
- };
1783
- }
1784
-
1785
- // src/tokens.ts
1786
- function createTokenMethods(client) {
1787
- const base = "/api/tokens";
1788
- return {
1789
- async issue(name, note) {
1790
- return client.post(base, { name, note });
1791
- },
1792
- async revoke(name) {
1793
- return client.delete(
1794
- `${base}/${encodeURIComponent(name)}`
1948
+ throw new Error(
1949
+ `Network error connecting to ${url.origin}: ${err instanceof Error ? err.message : String(err)}`
1795
1950
  );
1796
- },
1797
- async list() {
1798
- return client.get(base);
1799
1951
  }
1800
- };
1801
- }
1802
-
1803
- // src/journal.ts
1804
- function createJournalMethods(client, projectId) {
1805
- const base = `/projects/${projectId}/journal`;
1806
- return {
1807
- async query(opts) {
1808
- return client.get(base, { query: opts });
1952
+ if (!res.ok) {
1953
+ await this.throwApiError(res);
1809
1954
  }
1810
- };
1811
- }
1812
-
1813
- // src/presence.ts
1814
- function createPresenceMethods(client, projectId) {
1815
- const base = `/projects/${projectId}/presence`;
1816
- return {
1817
- async heartbeat(machine, ttlMs) {
1818
- return client.post(base, {
1819
- machine,
1820
- ttl_ms: ttlMs
1821
- });
1822
- },
1823
- async list() {
1824
- return client.get(base);
1825
- },
1826
- /**
1827
- * List all presence records across all machines, including whether each is active.
1828
- * Hits GET /projects/:projectId/presence/all
1829
- */
1830
- async listAll() {
1831
- 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;
1832
1967
  }
1833
- };
1834
- }
1835
-
1836
- // src/records.ts
1837
- function encodeKey(key) {
1838
- 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;
1839
2003
  }
1840
- function createRecordMethods(client, projectId) {
1841
- const base = `/projects/${projectId}/records`;
1842
- return {
1843
- async create(type, req) {
1844
- return client.post(`${base}/${type}`, req);
1845
- },
1846
- async set(type, key, req) {
1847
- return client.put(
1848
- `${base}/${type}/${encodeKey(key)}`,
1849
- req
1850
- );
1851
- },
1852
- async get(type, key) {
1853
- return client.get(`${base}/${type}/${encodeKey(key)}`);
1854
- },
1855
- async patch(type, key, req) {
1856
- return client.patch(
1857
- `${base}/${type}/${encodeKey(key)}`,
1858
- req
1859
- );
1860
- },
1861
- async archive(type, key, req) {
1862
- return client.post(
1863
- `${base}/${type}/~/archive/${encodeKey(key)}`,
1864
- req
1865
- );
1866
- },
1867
- async unarchive(type, key, req) {
1868
- return client.post(
1869
- `${base}/${type}/~/unarchive/${encodeKey(key)}`,
1870
- req
1871
- );
1872
- },
1873
- async history(type, key, opts) {
1874
- const query = {};
1875
- if (opts?.limit !== void 0) query.limit = String(opts.limit);
1876
- if (opts?.values !== void 0) query.values = String(opts.values);
1877
- return client.get(
1878
- `${base}/${type}/~/history/${encodeKey(key)}`,
1879
- { query }
1880
- );
1881
- },
1882
- async list(type, query) {
1883
- return client.get(`${base}/${type}`, { query });
1884
- },
1885
- async types() {
1886
- return client.get(`${base}/_types`);
1887
- },
1888
- async typesInUse() {
1889
- const raw = await client.get(`${base}/_types`);
1890
- 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;
1891
2031
  }
1892
- };
1893
- }
1894
-
1895
- // src/schema.ts
1896
- function createSchemaMethods(client, projectId) {
1897
- 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
+ }
1898
2045
  return {
1899
- async get() {
1900
- return client.get(base);
1901
- },
1902
- async apply(schema, strategy) {
1903
- return client.post(`${base}/apply`, { schema, strategy });
1904
- },
1905
- async history(opts) {
1906
- return client.get(`${base}/history`, { query: opts });
1907
- }
2046
+ sessionToken: body.session_token,
2047
+ expiresAt: body.expires_at,
2048
+ permission: body.permission ?? "read"
1908
2049
  };
1909
2050
  }
1910
-
1911
- // src/signals.ts
1912
- function createSignalMethods(client, projectId) {
1913
- const base = `/projects/${projectId}/signals`;
2051
+ function buildHttpFacade(client, projectId) {
1914
2052
  return {
1915
- /** Fetch the signal inbox for the current token. GET /projects/:id/signals */
1916
- async inbox() {
1917
- return client.get(base);
1918
- },
1919
- /** Send a signal to a target. POST /projects/:id/signals/send */
1920
- async send(req) {
1921
- return client.post(`${base}/send`, req);
1922
- },
1923
- /** Acknowledge a signal. POST /projects/:id/signals/:signalId/ack */
1924
- async ack(signalId) {
1925
- 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: () => {
1926
2067
  }
1927
2068
  };
1928
2069
  }
1929
-
1930
- // src/gates.ts
1931
- function createGateMethods(client, projectId) {
1932
- const base = `/projects/${projectId}/gates`;
1933
- return {
1934
- /** List gates with optional filters. GET /projects/:id/gates */
1935
- async list(query) {
1936
- return client.get(base, { query });
1937
- },
1938
- /** Create a new gate. POST /projects/:id/gates */
1939
- async create(req) {
1940
- return client.post(base, req);
1941
- },
1942
- /** Resolve a gate. POST /projects/:id/gates/:gateId/resolve */
1943
- async resolve(gateId, req) {
1944
- return client.post(`${base}/${gateId}/resolve`, req ?? {});
1945
- },
1946
- /** Delete a gate. DELETE /projects/:id/gates/:gateId */
1947
- async remove(gateId) {
1948
- 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
+ );
1949
2076
  }
1950
- };
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);
1951
2096
  }
1952
2097
 
1953
- // src/templates.ts
1954
- function createTemplateMethods(client, projectId) {
1955
- const base = `/projects/${projectId}/templates`;
1956
- return {
1957
- /** Instantiate an entity template. POST /projects/:id/templates/instantiate */
1958
- async instantiate(req) {
1959
- return client.post(
1960
- `${base}/instantiate`,
1961
- req
1962
- );
1963
- },
1964
- /** List available templates from the project schema. GET /projects/:id/templates */
1965
- async list() {
1966
- 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));
1967
2117
  }
1968
- };
2118
+ }
2119
+ throw new Error("withRetry: unreachable");
1969
2120
  }
1970
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
+
1971
2165
  // src/indexes.ts
1972
2166
  function createIndexMethods(client, projectId) {
1973
2167
  const base = `/projects/${projectId}/artifacts`;
@@ -2010,26 +2204,240 @@ function createIndexMethods(client, projectId) {
2010
2204
  }
2011
2205
  };
2012
2206
  }
2013
-
2014
- // src/summary.ts
2015
- 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);
2016
2413
  return {
2017
- /** Get project summary. GET /projects/:id/summary */
2018
- async get() {
2019
- 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
+ };
2020
2431
  }
2021
2432
  };
2022
2433
  }
2023
-
2024
- // src/search.ts
2025
- function createSearchMethods(client, projectId) {
2026
- const base = `/projects/${projectId}`;
2434
+ function createNamespace(client, projectId, ns) {
2435
+ validateNamespace(ns);
2027
2436
  return {
2028
- async search(q, opts) {
2029
- const query = { q };
2030
- if (opts?.limit !== void 0) query.limit = String(opts.limit);
2031
- return client.get(`${base}/search`, { query });
2032
- }
2437
+ tasks: namespacedTaskMethods(client, projectId, ns),
2438
+ records: namespacedRecordMethods(client, projectId, ns),
2439
+ artifacts: namespacedArtifactMethods(client, projectId, ns),
2440
+ templates: namespacedTemplateMethods(client, projectId, ns)
2033
2441
  };
2034
2442
  }
2035
2443
 
@@ -2141,17 +2549,884 @@ async function withClaim(client, projectId, resource, mode, ttlMs, callback) {
2141
2549
  }
2142
2550
  }
2143
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
+ };
2144
3414
 
2145
3415
  exports.ClaimHandle = ClaimHandle;
3416
+ exports.RemoteArtifactBackend = RemoteArtifactBackend;
3417
+ exports.RemoteBackend = RemoteBackend;
3418
+ exports.RemoteRecordBackend = RemoteRecordBackend;
2146
3419
  exports.TILA_ERRORS = TILA_ERRORS;
2147
3420
  exports.TilaApiError = TilaApiError;
2148
3421
  exports.TilaClient = TilaClient;
3422
+ exports.applyPrefix = applyPrefix;
2149
3423
  exports.createArtifactMethods = createArtifactMethods;
2150
3424
  exports.createClaimMethods = createClaimMethods;
2151
3425
  exports.createEntityMethods = createEntityMethods;
2152
3426
  exports.createGateMethods = createGateMethods;
2153
3427
  exports.createIndexMethods = createIndexMethods;
2154
3428
  exports.createJournalMethods = createJournalMethods;
3429
+ exports.createNamespace = createNamespace;
2155
3430
  exports.createPresenceMethods = createPresenceMethods;
2156
3431
  exports.createRecordMethods = createRecordMethods;
2157
3432
  exports.createSchemaMethods = createSchemaMethods;
@@ -2160,9 +3435,12 @@ exports.createSignalMethods = createSignalMethods;
2160
3435
  exports.createSummaryMethods = createSummaryMethods;
2161
3436
  exports.createTaskMethods = createTaskMethods;
2162
3437
  exports.createTemplateMethods = createTemplateMethods;
3438
+ exports.createTila = createTila;
2163
3439
  exports.createTokenMethods = createTokenMethods;
2164
3440
  exports.createWorkUnitMethods = createWorkUnitMethods;
2165
3441
  exports.exchangeGitHubToken = exchangeGitHubToken;
2166
3442
  exports.isTilaApiError = isTilaApiError;
3443
+ exports.stripPrefix = stripPrefix;
3444
+ exports.validateNamespace = validateNamespace;
2167
3445
  exports.withClaim = withClaim;
2168
3446
  exports.withRetry = withRetry;