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