tila-sdk 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +127 -0
- package/dist/index.cjs +2028 -750
- package/dist/index.d.cts +941 -249
- package/dist/index.d.ts +941 -249
- package/dist/index.js +2021 -750
- 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 +29 -4
package/dist/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { createRequire } from 'module';
|
|
2
1
|
import { z } from 'zod';
|
|
3
2
|
|
|
4
|
-
//
|
|
3
|
+
// ../schemas/dist/entity.js
|
|
5
4
|
z.object({
|
|
6
5
|
id: z.string(),
|
|
7
6
|
type: z.string(),
|
|
@@ -10,7 +9,8 @@ z.object({
|
|
|
10
9
|
archived: z.number().int().default(0),
|
|
11
10
|
created_at: z.number().int(),
|
|
12
11
|
updated_at: z.number().int(),
|
|
13
|
-
created_by: z.string()
|
|
12
|
+
created_by: z.string(),
|
|
13
|
+
tags: z.array(z.string()).default([])
|
|
14
14
|
});
|
|
15
15
|
var ClaimModeSchema = z.enum(["exclusive", "owner", "presence"]);
|
|
16
16
|
z.object({
|
|
@@ -72,7 +72,8 @@ z.object({
|
|
|
72
72
|
produced_at: z.number().int(),
|
|
73
73
|
produced_by: z.string(),
|
|
74
74
|
expires_at: z.number().int().nullable(),
|
|
75
|
-
tombstoned: z.number().int().default(0)
|
|
75
|
+
tombstoned: z.number().int().default(0),
|
|
76
|
+
tags: z.array(z.string()).default([])
|
|
76
77
|
});
|
|
77
78
|
z.object({
|
|
78
79
|
entity_id: z.string(),
|
|
@@ -160,15 +161,15 @@ z.object({
|
|
|
160
161
|
payload: z.unknown().optional(),
|
|
161
162
|
ttl_ms: z.number().int().min(1e3).max(864e5).optional()
|
|
162
163
|
});
|
|
163
|
-
z.object({
|
|
164
|
+
var SendSignalResponseSchema = z.object({
|
|
164
165
|
ok: z.literal(true),
|
|
165
166
|
id: z.string()
|
|
166
167
|
});
|
|
167
|
-
z.object({
|
|
168
|
+
var InboxResponseSchema = z.object({
|
|
168
169
|
ok: z.literal(true),
|
|
169
170
|
signals: z.array(SignalSchema)
|
|
170
171
|
});
|
|
171
|
-
z.object({
|
|
172
|
+
var AckSignalResponseSchema = z.object({
|
|
172
173
|
ok: z.literal(true)
|
|
173
174
|
});
|
|
174
175
|
z.object({
|
|
@@ -332,6 +333,21 @@ z.object({
|
|
|
332
333
|
pages_project_name: z.string().optional(),
|
|
333
334
|
infra_slug: z.string().optional()
|
|
334
335
|
});
|
|
336
|
+
var TagSchema = z.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9_:.-]{0,63}$/, "Invalid tag format");
|
|
337
|
+
var TagsSchema = z.array(TagSchema).transform((tags) => {
|
|
338
|
+
const seen = /* @__PURE__ */ new Set();
|
|
339
|
+
const result = [];
|
|
340
|
+
for (const tag of tags) {
|
|
341
|
+
const lower = tag.toLowerCase();
|
|
342
|
+
if (!seen.has(lower)) {
|
|
343
|
+
seen.add(lower);
|
|
344
|
+
result.push(lower);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return result;
|
|
348
|
+
}).refine((tags) => tags.length <= 20, "may not have more than 20 tags");
|
|
349
|
+
|
|
350
|
+
// ../schemas/dist/record.js
|
|
335
351
|
var RecordTypeSchema = z.string().regex(/^[a-z][a-z0-9_-]*$/, "Record type must start with lowercase letter and contain only lowercase letters, digits, underscores, and hyphens");
|
|
336
352
|
var RecordKeySchema = z.string().superRefine((val, ctx) => {
|
|
337
353
|
if (val.length === 0) {
|
|
@@ -408,18 +424,7 @@ var RecordKeySchema = z.string().superRefine((val, ctx) => {
|
|
|
408
424
|
}
|
|
409
425
|
}
|
|
410
426
|
});
|
|
411
|
-
var RecordTagSchema =
|
|
412
|
-
const seen = /* @__PURE__ */ new Set();
|
|
413
|
-
const result = [];
|
|
414
|
-
for (const tag of tags) {
|
|
415
|
-
const lower = tag.toLowerCase();
|
|
416
|
-
if (!seen.has(lower)) {
|
|
417
|
-
seen.add(lower);
|
|
418
|
-
result.push(lower);
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
return result;
|
|
422
|
-
}).refine((tags) => tags.length <= 20, "Record may not have more than 20 tags");
|
|
427
|
+
var RecordTagSchema = TagsSchema;
|
|
423
428
|
function sortKeysDeep(v) {
|
|
424
429
|
if (Array.isArray(v))
|
|
425
430
|
return v.map(sortKeysDeep);
|
|
@@ -458,7 +463,7 @@ z.object({
|
|
|
458
463
|
idempotency_key: z.string().optional(),
|
|
459
464
|
metadata: z.record(z.unknown()).optional()
|
|
460
465
|
});
|
|
461
|
-
z.object({
|
|
466
|
+
var AcquireSuccessResponseSchema = z.object({
|
|
462
467
|
ok: z.literal(true),
|
|
463
468
|
fence: z.number().int(),
|
|
464
469
|
expires_at: z.number().int()
|
|
@@ -468,7 +473,7 @@ z.object({
|
|
|
468
473
|
fence: z.number().int(),
|
|
469
474
|
ttl_ms: z.number().int().positive()
|
|
470
475
|
});
|
|
471
|
-
z.object({
|
|
476
|
+
var RenewSuccessResponseSchema = z.object({
|
|
472
477
|
ok: z.literal(true),
|
|
473
478
|
expires_at: z.number().int()
|
|
474
479
|
});
|
|
@@ -476,10 +481,10 @@ z.object({
|
|
|
476
481
|
resource: z.string(),
|
|
477
482
|
fence: z.number().int()
|
|
478
483
|
});
|
|
479
|
-
z.object({
|
|
484
|
+
var ReleaseSuccessResponseSchema = z.object({
|
|
480
485
|
ok: z.literal(true)
|
|
481
486
|
});
|
|
482
|
-
z.object({
|
|
487
|
+
var StateResponseSchema = z.object({
|
|
483
488
|
ok: z.literal(true),
|
|
484
489
|
claim: z.object({
|
|
485
490
|
resource: z.string(),
|
|
@@ -508,16 +513,18 @@ z.object({
|
|
|
508
513
|
z.object({
|
|
509
514
|
id: z.string(),
|
|
510
515
|
type: z.string(),
|
|
511
|
-
data: z.record(z.unknown()).default({})
|
|
516
|
+
data: z.record(z.unknown()).default({}),
|
|
517
|
+
tags: TagsSchema.optional()
|
|
512
518
|
});
|
|
513
519
|
z.object({
|
|
514
520
|
data: z.record(z.unknown()),
|
|
515
|
-
fence: z.number().int()
|
|
521
|
+
fence: z.number().int(),
|
|
522
|
+
tags: TagsSchema.optional()
|
|
516
523
|
});
|
|
517
524
|
z.object({
|
|
518
525
|
fence: z.number().int()
|
|
519
526
|
});
|
|
520
|
-
z.object({
|
|
527
|
+
var EntityResponseSchema = z.object({
|
|
521
528
|
ok: z.literal(true),
|
|
522
529
|
entity: z.object({
|
|
523
530
|
id: z.string(),
|
|
@@ -527,7 +534,8 @@ z.object({
|
|
|
527
534
|
archived: z.number().int(),
|
|
528
535
|
created_at: z.number().int(),
|
|
529
536
|
updated_at: z.number().int(),
|
|
530
|
-
created_by: z.string()
|
|
537
|
+
created_by: z.string(),
|
|
538
|
+
tags: z.array(z.string())
|
|
531
539
|
})
|
|
532
540
|
});
|
|
533
541
|
z.object({
|
|
@@ -540,10 +548,11 @@ z.object({
|
|
|
540
548
|
archived: z.number().int(),
|
|
541
549
|
created_at: z.number().int(),
|
|
542
550
|
updated_at: z.number().int(),
|
|
543
|
-
created_by: z.string()
|
|
551
|
+
created_by: z.string(),
|
|
552
|
+
tags: z.array(z.string())
|
|
544
553
|
}))
|
|
545
554
|
});
|
|
546
|
-
z.object({
|
|
555
|
+
var PaginatedEntityListResponseSchema = z.object({
|
|
547
556
|
ok: z.literal(true),
|
|
548
557
|
entities: z.array(z.object({
|
|
549
558
|
id: z.string(),
|
|
@@ -553,14 +562,15 @@ z.object({
|
|
|
553
562
|
archived: z.number().int(),
|
|
554
563
|
created_at: z.number().int(),
|
|
555
564
|
updated_at: z.number().int(),
|
|
556
|
-
created_by: z.string()
|
|
565
|
+
created_by: z.string(),
|
|
566
|
+
tags: z.array(z.string())
|
|
557
567
|
})),
|
|
558
568
|
total: z.number().int(),
|
|
559
569
|
limit: z.number().int().nullable(),
|
|
560
570
|
offset: z.number().int(),
|
|
561
571
|
has_more: z.boolean()
|
|
562
572
|
});
|
|
563
|
-
z.object({
|
|
573
|
+
var ListReadyEntitiesResponseSchema = z.object({
|
|
564
574
|
ok: z.literal(true),
|
|
565
575
|
entities: z.array(z.object({
|
|
566
576
|
id: z.string(),
|
|
@@ -590,7 +600,7 @@ z.object({
|
|
|
590
600
|
ok: z.literal(true),
|
|
591
601
|
entity: CompactEntitySchema
|
|
592
602
|
});
|
|
593
|
-
z.object({
|
|
603
|
+
var PaginatedCompactEntityListResponseSchema = z.object({
|
|
594
604
|
ok: z.literal(true),
|
|
595
605
|
entities: z.array(CompactEntitySchema),
|
|
596
606
|
total: z.number().int(),
|
|
@@ -598,7 +608,7 @@ z.object({
|
|
|
598
608
|
offset: z.number().int(),
|
|
599
609
|
has_more: z.boolean()
|
|
600
610
|
});
|
|
601
|
-
z.object({
|
|
611
|
+
var SummaryResponseSchema = z.object({
|
|
602
612
|
ok: z.literal(true),
|
|
603
613
|
project: z.object({
|
|
604
614
|
entity_count: z.number().int(),
|
|
@@ -617,7 +627,7 @@ z.object({
|
|
|
617
627
|
}))
|
|
618
628
|
})
|
|
619
629
|
});
|
|
620
|
-
z.object({
|
|
630
|
+
var EntityDetailResponseSchema = z.object({
|
|
621
631
|
ok: z.literal(true),
|
|
622
632
|
entity: z.object({
|
|
623
633
|
id: z.string(),
|
|
@@ -627,11 +637,12 @@ z.object({
|
|
|
627
637
|
archived: z.number().int(),
|
|
628
638
|
created_at: z.number().int(),
|
|
629
639
|
updated_at: z.number().int(),
|
|
630
|
-
created_by: z.string()
|
|
640
|
+
created_by: z.string(),
|
|
641
|
+
tags: z.array(z.string())
|
|
631
642
|
}),
|
|
632
643
|
relationships: z.array(EntityRelationshipSchema).default([])
|
|
633
644
|
});
|
|
634
|
-
z.object({
|
|
645
|
+
var ArchiveSuccessResponseSchema = z.object({
|
|
635
646
|
ok: z.literal(true)
|
|
636
647
|
});
|
|
637
648
|
z.object({
|
|
@@ -639,7 +650,7 @@ z.object({
|
|
|
639
650
|
to_id: z.string().min(1),
|
|
640
651
|
type: EntityRelationshipTypeSchema
|
|
641
652
|
});
|
|
642
|
-
z.object({
|
|
653
|
+
var CreateEntityRelationshipResponseSchema = z.object({
|
|
643
654
|
ok: z.literal(true),
|
|
644
655
|
created: z.boolean().default(true)
|
|
645
656
|
});
|
|
@@ -648,7 +659,7 @@ z.object({
|
|
|
648
659
|
to_id: z.string().min(1).optional(),
|
|
649
660
|
type: EntityRelationshipTypeSchema.optional()
|
|
650
661
|
});
|
|
651
|
-
z.object({
|
|
662
|
+
var ListEntityRelationshipsResponseSchema = z.object({
|
|
652
663
|
ok: z.literal(true),
|
|
653
664
|
relationships: z.array(EntityRelationshipSchema)
|
|
654
665
|
});
|
|
@@ -657,7 +668,7 @@ z.object({
|
|
|
657
668
|
to_id: z.string().min(1),
|
|
658
669
|
type: EntityRelationshipTypeSchema
|
|
659
670
|
});
|
|
660
|
-
z.object({
|
|
671
|
+
var DeleteEntityRelationshipResponseSchema = z.object({
|
|
661
672
|
ok: z.literal(true),
|
|
662
673
|
removed: z.boolean()
|
|
663
674
|
});
|
|
@@ -668,7 +679,7 @@ z.object({
|
|
|
668
679
|
after_seq: z.number().int().optional(),
|
|
669
680
|
limit: z.number().int().positive().default(100)
|
|
670
681
|
});
|
|
671
|
-
z.object({
|
|
682
|
+
var JournalResponseSchema = z.object({
|
|
672
683
|
ok: z.literal(true),
|
|
673
684
|
events: z.array(z.object({
|
|
674
685
|
seq: z.number().int(),
|
|
@@ -695,7 +706,7 @@ z.object({
|
|
|
695
706
|
info: z.record(z.unknown())
|
|
696
707
|
}))
|
|
697
708
|
});
|
|
698
|
-
z.object({
|
|
709
|
+
var PresenceAllListResponseSchema = z.object({
|
|
699
710
|
ok: z.literal(true),
|
|
700
711
|
machines: z.array(z.object({
|
|
701
712
|
machine: z.string(),
|
|
@@ -704,7 +715,7 @@ z.object({
|
|
|
704
715
|
active: z.boolean()
|
|
705
716
|
}))
|
|
706
717
|
});
|
|
707
|
-
z.object({
|
|
718
|
+
var PresenceHeartbeatSuccessResponseSchema = z.object({
|
|
708
719
|
ok: z.literal(true)
|
|
709
720
|
});
|
|
710
721
|
z.object({
|
|
@@ -846,7 +857,7 @@ z.object({
|
|
|
846
857
|
slot: z.string().min(1),
|
|
847
858
|
metadata: z.record(z.unknown()).default({})
|
|
848
859
|
});
|
|
849
|
-
z.object({
|
|
860
|
+
var EntityArtifactReferenceListResponseSchema = z.object({
|
|
850
861
|
ok: z.literal(true),
|
|
851
862
|
references: z.array(z.object({
|
|
852
863
|
entity_id: z.string(),
|
|
@@ -856,6 +867,46 @@ z.object({
|
|
|
856
867
|
created_at: z.number().int()
|
|
857
868
|
}))
|
|
858
869
|
});
|
|
870
|
+
function parseTagFilter(raw) {
|
|
871
|
+
if (!raw)
|
|
872
|
+
return void 0;
|
|
873
|
+
const parts = raw.split(",").map((s) => s.trim().toLowerCase()).filter((s) => s.length > 0);
|
|
874
|
+
if (parts.length === 0)
|
|
875
|
+
return void 0;
|
|
876
|
+
for (const part of parts) {
|
|
877
|
+
TagSchema.parse(part);
|
|
878
|
+
}
|
|
879
|
+
const unique = [...new Set(parts)];
|
|
880
|
+
if (unique.length > 20) {
|
|
881
|
+
throw new z.ZodError([
|
|
882
|
+
{
|
|
883
|
+
code: z.ZodIssueCode.too_big,
|
|
884
|
+
maximum: 20,
|
|
885
|
+
type: "array",
|
|
886
|
+
inclusive: true,
|
|
887
|
+
exact: false,
|
|
888
|
+
message: "tag_filter may not have more than 20 tags",
|
|
889
|
+
path: ["tag_filter"]
|
|
890
|
+
}
|
|
891
|
+
]);
|
|
892
|
+
}
|
|
893
|
+
return unique;
|
|
894
|
+
}
|
|
895
|
+
var tagFilterQueryParam = z.string().optional().superRefine((v, ctx) => {
|
|
896
|
+
if (!v)
|
|
897
|
+
return;
|
|
898
|
+
try {
|
|
899
|
+
parseTagFilter(v);
|
|
900
|
+
} catch (err) {
|
|
901
|
+
if (err instanceof z.ZodError) {
|
|
902
|
+
for (const issue of err.issues) {
|
|
903
|
+
ctx.addIssue(issue);
|
|
904
|
+
}
|
|
905
|
+
} else {
|
|
906
|
+
throw err;
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
}).transform((v) => parseTagFilter(v));
|
|
859
910
|
z.object({
|
|
860
911
|
ok: z.literal(true),
|
|
861
912
|
results: z.array(ArtifactSearchResultSchema),
|
|
@@ -866,7 +917,8 @@ z.object({
|
|
|
866
917
|
kind: z.string().optional(),
|
|
867
918
|
resource: z.string().optional(),
|
|
868
919
|
source_only: z.string().optional().transform((v) => v === "true").pipe(z.boolean()),
|
|
869
|
-
limit: z.string().optional().default("20").transform((v) => Number.parseInt(v, 10)).pipe(z.number().int().min(1).max(100))
|
|
920
|
+
limit: z.string().optional().default("20").transform((v) => Number.parseInt(v, 10)).pipe(z.number().int().min(1).max(100)),
|
|
921
|
+
tag_filter: tagFilterQueryParam
|
|
870
922
|
});
|
|
871
923
|
var ArtifactGrepLineSchema = z.object({
|
|
872
924
|
line: z.number().int(),
|
|
@@ -884,7 +936,7 @@ var ArtifactGrepResultSchema = z.object({
|
|
|
884
936
|
truncated: z.boolean().optional()
|
|
885
937
|
// this blob hit the per-blob byte cap
|
|
886
938
|
});
|
|
887
|
-
z.object({
|
|
939
|
+
var ArtifactGrepResponseSchema = z.object({
|
|
888
940
|
ok: z.literal(true),
|
|
889
941
|
results: z.array(ArtifactGrepResultSchema),
|
|
890
942
|
scanned: z.number().int(),
|
|
@@ -920,16 +972,18 @@ z.object({
|
|
|
920
972
|
});
|
|
921
973
|
z.object({
|
|
922
974
|
q: z.string().min(1).max(200),
|
|
923
|
-
limit: z.string().optional().default("20").transform((v) => Number.parseInt(v, 10)).pipe(z.number().int().min(1).max(100))
|
|
975
|
+
limit: z.string().optional().default("20").transform((v) => Number.parseInt(v, 10)).pipe(z.number().int().min(1).max(100)),
|
|
976
|
+
tag_filter: tagFilterQueryParam
|
|
924
977
|
});
|
|
925
978
|
z.object({
|
|
926
979
|
content: z.string().min(1),
|
|
927
980
|
kind: z.string().min(1),
|
|
928
981
|
mime_type: z.string().default("text/markdown"),
|
|
929
982
|
resource: z.string().optional(),
|
|
930
|
-
fence: z.number().int().optional()
|
|
983
|
+
fence: z.number().int().optional(),
|
|
984
|
+
tags: TagsSchema.optional()
|
|
931
985
|
});
|
|
932
|
-
z.object({
|
|
986
|
+
var ArtifactPutResponseSchema = z.object({
|
|
933
987
|
ok: z.literal(true),
|
|
934
988
|
key: z.string(),
|
|
935
989
|
bytes: z.number(),
|
|
@@ -948,7 +1002,8 @@ z.object({
|
|
|
948
1002
|
produced_at: z.number(),
|
|
949
1003
|
produced_by: z.string(),
|
|
950
1004
|
expires_at: z.number().nullable(),
|
|
951
|
-
tombstoned: z.number()
|
|
1005
|
+
tombstoned: z.number(),
|
|
1006
|
+
tags: z.array(z.string())
|
|
952
1007
|
}))
|
|
953
1008
|
});
|
|
954
1009
|
z.object({
|
|
@@ -1035,12 +1090,15 @@ var RecordItemSchema = z.object({
|
|
|
1035
1090
|
updated_by: z.string(),
|
|
1036
1091
|
tags: z.array(z.string())
|
|
1037
1092
|
});
|
|
1038
|
-
|
|
1093
|
+
RecordItemSchema.extend({
|
|
1094
|
+
fence: z.number().int()
|
|
1095
|
+
});
|
|
1096
|
+
var RecordGetResponseSchema = z.object({
|
|
1039
1097
|
ok: z.literal(true),
|
|
1040
1098
|
record: RecordItemSchema,
|
|
1041
1099
|
fence: z.number().int()
|
|
1042
1100
|
});
|
|
1043
|
-
z.object({
|
|
1101
|
+
var RecordMutateResponseSchema = z.object({
|
|
1044
1102
|
ok: z.literal(true),
|
|
1045
1103
|
record: RecordItemSchema,
|
|
1046
1104
|
fence: z.number().int(),
|
|
@@ -1055,7 +1113,7 @@ var RecordListItemSchema = z.object({
|
|
|
1055
1113
|
archived: z.number().int(),
|
|
1056
1114
|
tags: z.array(z.string())
|
|
1057
1115
|
});
|
|
1058
|
-
z.object({
|
|
1116
|
+
var RecordListResponseSchema = z.object({
|
|
1059
1117
|
ok: z.literal(true),
|
|
1060
1118
|
items: z.array(RecordListItemSchema),
|
|
1061
1119
|
meta: z.object({
|
|
@@ -1075,9 +1133,12 @@ var RecordHistoryItemSchema = z.object({
|
|
|
1075
1133
|
source_artifact_key: z.string().nullable(),
|
|
1076
1134
|
actor: z.string(),
|
|
1077
1135
|
created_at: z.number().int(),
|
|
1078
|
-
message: z.string().nullable()
|
|
1136
|
+
message: z.string().nullable(),
|
|
1137
|
+
// Populated only when the history is requested with `includeValues=true`
|
|
1138
|
+
// (wire: `?values=true`). Optional so existing parsers stay compatible.
|
|
1139
|
+
value: z.record(z.unknown()).optional()
|
|
1079
1140
|
});
|
|
1080
|
-
z.object({
|
|
1141
|
+
var RecordHistoryResponseSchema = z.object({
|
|
1081
1142
|
ok: z.literal(true),
|
|
1082
1143
|
items: z.array(RecordHistoryItemSchema),
|
|
1083
1144
|
meta: z.object({
|
|
@@ -1187,392 +1248,208 @@ z.object({
|
|
|
1187
1248
|
z.object({
|
|
1188
1249
|
resolution: z.string().optional()
|
|
1189
1250
|
});
|
|
1190
|
-
z.object({
|
|
1251
|
+
var GateResponseSchema = z.object({
|
|
1191
1252
|
ok: z.literal(true),
|
|
1192
1253
|
gate: GateSchema
|
|
1193
1254
|
});
|
|
1194
|
-
z.object({
|
|
1255
|
+
var GateListResponseSchema = z.object({
|
|
1195
1256
|
ok: z.literal(true),
|
|
1196
1257
|
gates: z.array(GateSchema)
|
|
1197
1258
|
});
|
|
1198
1259
|
|
|
1199
|
-
// src/
|
|
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
|
-
|
|
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 };
|