@byok-sdk/cloud 0.4.0 → 0.4.2
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 +1 -1
- package/dist/activity.d.ts +122 -0
- package/dist/approval-timeline.d.ts +74 -0
- package/dist/cloud.d.ts +4 -1
- package/dist/coordination.d.ts +6 -3
- package/dist/index.d.ts +6 -2
- package/dist/index.js +354 -18
- package/dist/index.js.map +1 -1
- package/dist/stores/in-memory/activity.d.ts +9 -0
- package/dist/stores/in-memory/approval-timeline.d.ts +9 -0
- package/dist/stores/in-memory/index.d.ts +2 -0
- package/dist/stores/ports.d.ts +6 -2
- package/dist/tenant-stores.d.ts +8 -1
- package/package.json +9 -9
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BOARD_STATUSES, PRESENCE_LEVELS, CapabilityDeclarationSchema, NONCE_SIGNING_DOMAIN, hasCapability, isTenantId, tenantId, principalTenant, parseDeviceProofEnvelope, deviceProofSigningInput, parseCapabilityDeclaration, ByokCoreError, tenantKey, createInMemoryCoreStores, assertCapability, contentHash, isCoreConflictError, isCoreError, DEVICE_PROOF_HEADER, TRUTH_RECORD_KINDS, STORAGE_ERROR_CODES, STORAGE_ERROR_HTTP_STATUS } from '@byok-sdk/core';
|
|
2
2
|
export { DEVICE_PROOF_HEADER, NONCE_SIGNING_DOMAIN, isTenantId, tenantId } from '@byok-sdk/core';
|
|
3
|
-
import {
|
|
3
|
+
import { AgentEventOrUnknownSchema, ConfiguredToolsetsSchema, DAEMON_TO_SERVER_TYPES, encodeEnvelope, decodeEnvelope, BYOK_PAIR_PATH, BYOK_CHALLENGE_PATH, BYOK_TOKEN_PATH, BYOK_CAPABILITIES_PATH, BYOK_EVENTS_PATH, BYOK_MESSAGES_PATH, BYOK_BOARD_PATH, BYOK_BOARD_CLAIM_ROUTE, BYOK_BOARD_UNCLAIM_ROUTE, BYOK_BOARD_STATUS_ROUTE, BYOK_BOARD_STREAM_PATH, BYOK_PRESENCE_PATH, BYOK_ACTIVITY_PATH, BYOK_RECORDS_PATH, BYOK_RECORD_ROUTE, BYOK_SKILL_PACKS_PATH, BYOK_SKILL_PACK_FILE_ROUTE, BYOK_BLOBS_PATH, BYOK_BLOB_FINALIZE_ROUTE, BYOK_BLOB_URL_ROUTE, BYOK_BLOB_CONTENT_ROUTE, createEnvelope, PairRequestSchema, ChallengeRequestSchema, TokenRequestSchema, MessagesSendRequestSchema, CreateBlobRequestSchema, byokBlobContentPath } from '@byok-sdk/protocol';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { Hono } from 'hono';
|
|
6
6
|
|
|
@@ -332,12 +332,79 @@ function isCloudError(value, code) {
|
|
|
332
332
|
return code === void 0 || value.code === code;
|
|
333
333
|
}
|
|
334
334
|
|
|
335
|
+
// src/activity.ts
|
|
336
|
+
var DEFAULT_ACTIVITY_CAPACITY = 50;
|
|
337
|
+
var ActivityTaskIdSchema = z.string().min(1).max(200);
|
|
338
|
+
var SourceEnvelopeIdSchema = z.string().max(200).regex(/\S/, "sourceEnvelopeId must not be blank");
|
|
339
|
+
var ActivityAppendRequestSchema = z.object({
|
|
340
|
+
taskId: ActivityTaskIdSchema,
|
|
341
|
+
sourceEnvelopeId: SourceEnvelopeIdSchema,
|
|
342
|
+
batchSeq: z.number().int().nonnegative(),
|
|
343
|
+
events: z.array(AgentEventOrUnknownSchema).min(1),
|
|
344
|
+
dropped: z.number().int().nonnegative()
|
|
345
|
+
});
|
|
346
|
+
var TimelineEventSchema = z.object({
|
|
347
|
+
taskId: ActivityTaskIdSchema,
|
|
348
|
+
sourceEnvelopeId: SourceEnvelopeIdSchema,
|
|
349
|
+
batchSeq: z.number().int().nonnegative(),
|
|
350
|
+
eventIndex: z.number().int().nonnegative(),
|
|
351
|
+
receivedAt: z.iso.datetime(),
|
|
352
|
+
event: AgentEventOrUnknownSchema
|
|
353
|
+
});
|
|
354
|
+
function validateActivityAppend(input) {
|
|
355
|
+
if (!Number.isFinite(input.ttlMs) || input.ttlMs <= 0) {
|
|
356
|
+
throw new ByokCloudError(
|
|
357
|
+
"coordination_input_invalid",
|
|
358
|
+
`Activity ttl must be a positive number of milliseconds, received ${String(input.ttlMs)}.`
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
const capacity = input.capacity ?? DEFAULT_ACTIVITY_CAPACITY;
|
|
362
|
+
if (!Number.isSafeInteger(capacity) || capacity <= 0) {
|
|
363
|
+
throw new ByokCloudError(
|
|
364
|
+
"coordination_input_invalid",
|
|
365
|
+
`Activity capacity must be a positive integer, received ${String(capacity)}.`
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
const parsed = ActivityAppendRequestSchema.safeParse(input);
|
|
369
|
+
if (!parsed.success) {
|
|
370
|
+
throw new ByokCloudError(
|
|
371
|
+
"coordination_input_invalid",
|
|
372
|
+
"Activity batches require stable source identity, order, at least one valid event, and a non-negative dropped count."
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
return capacity;
|
|
376
|
+
}
|
|
377
|
+
function projectTimelineEvents(input, receivedAt) {
|
|
378
|
+
return input.events.map(
|
|
379
|
+
(event, eventIndex) => TimelineEventSchema.parse({
|
|
380
|
+
taskId: input.taskId,
|
|
381
|
+
sourceEnvelopeId: input.sourceEnvelopeId,
|
|
382
|
+
batchSeq: input.batchSeq,
|
|
383
|
+
eventIndex,
|
|
384
|
+
receivedAt,
|
|
385
|
+
event
|
|
386
|
+
})
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
function parseTimelineEvents(value) {
|
|
390
|
+
return z.array(TimelineEventSchema).parse(value);
|
|
391
|
+
}
|
|
392
|
+
function compareTimelineEvents(left, right) {
|
|
393
|
+
return left.batchSeq - right.batchSeq || left.eventIndex - right.eventIndex;
|
|
394
|
+
}
|
|
395
|
+
function activityCursor(entries) {
|
|
396
|
+
const last = entries.at(-1);
|
|
397
|
+
return last === void 0 ? void 0 : { batchSeq: last.batchSeq, eventIndex: last.eventIndex };
|
|
398
|
+
}
|
|
399
|
+
function activityTailKey(tenant, taskId) {
|
|
400
|
+
return tenantKey(tenant, taskId);
|
|
401
|
+
}
|
|
402
|
+
|
|
335
403
|
// src/coordination.ts
|
|
336
404
|
var DEFAULT_BOARD_CHANNEL_MAX_BYTES = 128;
|
|
337
405
|
var DEFAULT_BOARD_TITLE_MAX_BYTES = 512;
|
|
338
406
|
var DEFAULT_ACTIVITY_MAX_EVENTS = 50;
|
|
339
407
|
var DEFAULT_ACTIVITY_MAX_BYTES = 64 * 1024;
|
|
340
|
-
var DEFAULT_ACTIVITY_CAPACITY = 50;
|
|
341
408
|
var DEFAULT_ACTIVITY_TTL_MS = 10 * 6e4;
|
|
342
409
|
var DEFAULT_PRESENCE_TTL_MS = 9e4;
|
|
343
410
|
var DEFAULT_PRESENCE_MINIMUM_INTERVAL_MS = 5e3;
|
|
@@ -363,7 +430,7 @@ function assertBoardLabels(channel, title, limits) {
|
|
|
363
430
|
);
|
|
364
431
|
}
|
|
365
432
|
}
|
|
366
|
-
function
|
|
433
|
+
function validateActivityEvents(events, dropped, bounds) {
|
|
367
434
|
if (!Number.isSafeInteger(dropped) || dropped < 0) {
|
|
368
435
|
throw new ByokCloudError(
|
|
369
436
|
"coordination_input_invalid",
|
|
@@ -383,12 +450,18 @@ function activityDetails(events, dropped, bounds) {
|
|
|
383
450
|
`Activity batch exceeds ${bounds.maxBytes} UTF-8 bytes.`
|
|
384
451
|
);
|
|
385
452
|
}
|
|
386
|
-
|
|
453
|
+
}
|
|
454
|
+
function validateActivityBatch(input, bounds) {
|
|
455
|
+
validateActivityEvents(input.events, input.dropped, bounds);
|
|
456
|
+
validateActivityAppend({ ...input, ttlMs: bounds.ttlMs, capacity: bounds.capacity });
|
|
387
457
|
}
|
|
388
458
|
async function appendActivityEvents(activity, input, bounds) {
|
|
459
|
+
validateActivityBatch(input, bounds);
|
|
389
460
|
return activity.append({
|
|
390
461
|
taskId: input.taskId,
|
|
391
|
-
|
|
462
|
+
sourceEnvelopeId: input.sourceEnvelopeId,
|
|
463
|
+
batchSeq: input.batchSeq,
|
|
464
|
+
events: input.events,
|
|
392
465
|
dropped: input.dropped,
|
|
393
466
|
ttlMs: bounds.ttlMs,
|
|
394
467
|
capacity: bounds.capacity
|
|
@@ -441,8 +514,12 @@ function tenantStoresFor(principal, root) {
|
|
|
441
514
|
list: () => core.presence.list(tenant)
|
|
442
515
|
},
|
|
443
516
|
activity: {
|
|
444
|
-
append: (input) =>
|
|
445
|
-
read: (taskId) =>
|
|
517
|
+
append: (input) => cloud.activity.append(tenant, input),
|
|
518
|
+
read: (taskId) => cloud.activity.read(tenant, taskId)
|
|
519
|
+
},
|
|
520
|
+
approvals: {
|
|
521
|
+
append: (input) => cloud.approvals.append(tenant, input),
|
|
522
|
+
read: (taskId) => cloud.approvals.read(tenant, taskId)
|
|
446
523
|
},
|
|
447
524
|
devices: {
|
|
448
525
|
get: (deviceId) => cloud.devices.get(tenant, deviceId),
|
|
@@ -675,6 +752,7 @@ function tokenHandler(deps) {
|
|
|
675
752
|
return c.json(response, 200);
|
|
676
753
|
};
|
|
677
754
|
}
|
|
755
|
+
var CLOUD_PROTOCOL_CAPABILITIES = ["result-document"];
|
|
678
756
|
function sleep(ms) {
|
|
679
757
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
680
758
|
}
|
|
@@ -703,15 +781,92 @@ function eventsHandler(deps) {
|
|
|
703
781
|
});
|
|
704
782
|
if (page.messages.length > 0) {
|
|
705
783
|
const events = page.messages.map((message) => decodeEnvelope(message.body));
|
|
706
|
-
const response2 = {
|
|
784
|
+
const response2 = {
|
|
785
|
+
events,
|
|
786
|
+
cursor: page.nextSeq,
|
|
787
|
+
capabilities: CLOUD_PROTOCOL_CAPABILITIES
|
|
788
|
+
};
|
|
707
789
|
return c.json(response2, 200);
|
|
708
790
|
}
|
|
709
791
|
if (attempt < attempts - 1) await sleep(deps.longPollIntervalMs);
|
|
710
792
|
}
|
|
711
|
-
const response = {
|
|
793
|
+
const response = {
|
|
794
|
+
events: [],
|
|
795
|
+
cursor,
|
|
796
|
+
capabilities: CLOUD_PROTOCOL_CAPABILITIES
|
|
797
|
+
};
|
|
712
798
|
return c.json(response, 200);
|
|
713
799
|
};
|
|
714
800
|
}
|
|
801
|
+
var DEFAULT_APPROVAL_TIMELINE_CAPACITY = 50;
|
|
802
|
+
var DEFAULT_APPROVAL_TIMELINE_TTL_MS = 10 * 60 * 1e3;
|
|
803
|
+
var APPROVAL_SUMMARY_MAX_BYTES = 16 * 1024;
|
|
804
|
+
var NonBlankIdSchema = z.string().max(200).regex(/\S/, "value must not be blank");
|
|
805
|
+
var TaskIdSchema = z.string().min(1).max(200);
|
|
806
|
+
var ApprovalTimelineEventSchema = z.discriminatedUnion("type", [
|
|
807
|
+
z.object({
|
|
808
|
+
type: z.literal("approval_requested"),
|
|
809
|
+
summary: z.string(),
|
|
810
|
+
approvalId: NonBlankIdSchema.optional()
|
|
811
|
+
}),
|
|
812
|
+
z.object({
|
|
813
|
+
type: z.literal("approval_resolved"),
|
|
814
|
+
approvalId: NonBlankIdSchema,
|
|
815
|
+
decision: z.enum(["approve", "reject"]),
|
|
816
|
+
resolvedBy: z.enum(["local"]),
|
|
817
|
+
at: z.iso.datetime({ offset: true })
|
|
818
|
+
})
|
|
819
|
+
]);
|
|
820
|
+
var ApprovalObservationSchema = z.object({
|
|
821
|
+
taskId: TaskIdSchema,
|
|
822
|
+
sourceEnvelopeId: NonBlankIdSchema,
|
|
823
|
+
revision: z.number().int().positive(),
|
|
824
|
+
receivedAt: z.iso.datetime(),
|
|
825
|
+
event: ApprovalTimelineEventSchema
|
|
826
|
+
});
|
|
827
|
+
function validateApprovalTimelineAppend(input) {
|
|
828
|
+
const capacity = input.capacity ?? DEFAULT_APPROVAL_TIMELINE_CAPACITY;
|
|
829
|
+
const ttlMs = input.ttlMs ?? DEFAULT_APPROVAL_TIMELINE_TTL_MS;
|
|
830
|
+
if (!Number.isSafeInteger(capacity) || capacity <= 0) {
|
|
831
|
+
throw new ByokCloudError(
|
|
832
|
+
"coordination_input_invalid",
|
|
833
|
+
`Approval timeline capacity must be a positive integer, received ${String(capacity)}.`
|
|
834
|
+
);
|
|
835
|
+
}
|
|
836
|
+
if (!Number.isFinite(ttlMs) || ttlMs <= 0) {
|
|
837
|
+
throw new ByokCloudError(
|
|
838
|
+
"coordination_input_invalid",
|
|
839
|
+
`Approval timeline ttl must be a positive number of milliseconds, received ${String(ttlMs)}.`
|
|
840
|
+
);
|
|
841
|
+
}
|
|
842
|
+
const parsed = z.object({
|
|
843
|
+
taskId: TaskIdSchema,
|
|
844
|
+
sourceEnvelopeId: NonBlankIdSchema,
|
|
845
|
+
event: ApprovalTimelineEventSchema
|
|
846
|
+
}).safeParse(input);
|
|
847
|
+
if (!parsed.success) {
|
|
848
|
+
throw new ByokCloudError(
|
|
849
|
+
"coordination_input_invalid",
|
|
850
|
+
"Approval observations require stable source identity and a valid native lifecycle event."
|
|
851
|
+
);
|
|
852
|
+
}
|
|
853
|
+
if (parsed.data.event.type === "approval_requested" && new TextEncoder().encode(parsed.data.event.summary).byteLength > APPROVAL_SUMMARY_MAX_BYTES) {
|
|
854
|
+
throw new ByokCloudError(
|
|
855
|
+
"coordination_input_invalid",
|
|
856
|
+
`Approval summary exceeds ${APPROVAL_SUMMARY_MAX_BYTES} UTF-8 bytes.`
|
|
857
|
+
);
|
|
858
|
+
}
|
|
859
|
+
return { capacity, ttlMs, event: parsed.data.event };
|
|
860
|
+
}
|
|
861
|
+
function approvalTimelineKey(tenant, taskId) {
|
|
862
|
+
return tenantKey(tenant, taskId);
|
|
863
|
+
}
|
|
864
|
+
function parseApprovalObservations(value) {
|
|
865
|
+
return z.array(ApprovalObservationSchema).parse(value);
|
|
866
|
+
}
|
|
867
|
+
function approvalTimelineCursor(entries) {
|
|
868
|
+
return entries.at(-1)?.revision;
|
|
869
|
+
}
|
|
715
870
|
async function projectTerminalToReview(board, taskId) {
|
|
716
871
|
const item = await board.get(taskId);
|
|
717
872
|
if (item === void 0 || item.status !== "in_progress") return;
|
|
@@ -740,7 +895,16 @@ async function handleInboundEnvelope(stores, deviceId, envelope, activityBounds
|
|
|
740
895
|
if (attempt?.ownerDeviceId !== void 0 && attempt.ownerDeviceId !== deviceId) return "rejected";
|
|
741
896
|
if (envelope.type === "task.progress" && envelope.payload.events.length > 0) {
|
|
742
897
|
try {
|
|
743
|
-
|
|
898
|
+
validateActivityBatch(
|
|
899
|
+
{
|
|
900
|
+
taskId,
|
|
901
|
+
sourceEnvelopeId: envelope.id,
|
|
902
|
+
batchSeq: envelope.payload.seq,
|
|
903
|
+
events: envelope.payload.events,
|
|
904
|
+
dropped: 0
|
|
905
|
+
},
|
|
906
|
+
activityBounds
|
|
907
|
+
);
|
|
744
908
|
} catch (caught) {
|
|
745
909
|
if (isCloudError(caught, "activity_batch_too_large") || isCloudError(caught, "coordination_input_invalid")) {
|
|
746
910
|
return "rejected";
|
|
@@ -748,6 +912,15 @@ async function handleInboundEnvelope(stores, deviceId, envelope, activityBounds
|
|
|
748
912
|
throw caught;
|
|
749
913
|
}
|
|
750
914
|
}
|
|
915
|
+
const approvalInput = approvalTimelineAppendInput(taskId, envelope);
|
|
916
|
+
if (approvalInput !== void 0) {
|
|
917
|
+
try {
|
|
918
|
+
validateApprovalTimelineAppend(approvalInput);
|
|
919
|
+
} catch (caught) {
|
|
920
|
+
if (isCloudError(caught, "coordination_input_invalid")) return "rejected";
|
|
921
|
+
throw caught;
|
|
922
|
+
}
|
|
923
|
+
}
|
|
751
924
|
if (await stores.dedup.checkAndRecord(deviceId, envelope.id)) return "duplicate";
|
|
752
925
|
await applyLifecycle(stores, deviceId, taskId, envelope, activityBounds);
|
|
753
926
|
return "accepted";
|
|
@@ -767,11 +940,23 @@ async function applyLifecycle(stores, deviceId, taskId, envelope, activityBounds
|
|
|
767
940
|
if (envelope.payload.events.length > 0) {
|
|
768
941
|
await appendActivityEvents(
|
|
769
942
|
stores.activity,
|
|
770
|
-
{
|
|
943
|
+
{
|
|
944
|
+
taskId,
|
|
945
|
+
sourceEnvelopeId: envelope.id,
|
|
946
|
+
batchSeq: envelope.payload.seq,
|
|
947
|
+
events: envelope.payload.events,
|
|
948
|
+
dropped: 0
|
|
949
|
+
},
|
|
771
950
|
activityBounds
|
|
772
951
|
);
|
|
773
952
|
}
|
|
774
953
|
return;
|
|
954
|
+
case "task.await_approval":
|
|
955
|
+
await stores.approvals.append(approvalTimelineAppendInput(taskId, envelope));
|
|
956
|
+
return;
|
|
957
|
+
case "task.approval_resolved":
|
|
958
|
+
await stores.approvals.append(approvalTimelineAppendInput(taskId, envelope));
|
|
959
|
+
return;
|
|
775
960
|
case "task.complete":
|
|
776
961
|
await recordTerminal(stores, taskId, envelope, "complete");
|
|
777
962
|
return;
|
|
@@ -785,6 +970,34 @@ async function applyLifecycle(stores, deviceId, taskId, envelope, activityBounds
|
|
|
785
970
|
return;
|
|
786
971
|
}
|
|
787
972
|
}
|
|
973
|
+
function approvalTimelineAppendInput(taskId, envelope) {
|
|
974
|
+
switch (envelope.type) {
|
|
975
|
+
case "task.await_approval":
|
|
976
|
+
return {
|
|
977
|
+
taskId,
|
|
978
|
+
sourceEnvelopeId: envelope.id,
|
|
979
|
+
event: {
|
|
980
|
+
type: "approval_requested",
|
|
981
|
+
summary: envelope.payload.summary,
|
|
982
|
+
...envelope.payload.approvalId === void 0 ? {} : { approvalId: envelope.payload.approvalId }
|
|
983
|
+
}
|
|
984
|
+
};
|
|
985
|
+
case "task.approval_resolved":
|
|
986
|
+
return {
|
|
987
|
+
taskId,
|
|
988
|
+
sourceEnvelopeId: envelope.id,
|
|
989
|
+
event: {
|
|
990
|
+
type: "approval_resolved",
|
|
991
|
+
approvalId: envelope.payload.approvalId,
|
|
992
|
+
decision: envelope.payload.decision,
|
|
993
|
+
resolvedBy: envelope.payload.resolvedBy,
|
|
994
|
+
at: envelope.payload.at
|
|
995
|
+
}
|
|
996
|
+
};
|
|
997
|
+
default:
|
|
998
|
+
return void 0;
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
788
1001
|
async function recordTerminal(stores, taskId, envelope, status) {
|
|
789
1002
|
const { created } = await stores.receipts.record({
|
|
790
1003
|
key: terminalReceiptKey(taskId),
|
|
@@ -1063,11 +1276,6 @@ var PresenceBodySchema = z.object({
|
|
|
1063
1276
|
detail: z.string().optional(),
|
|
1064
1277
|
configuredToolsets: ConfiguredToolsetsSchema.optional()
|
|
1065
1278
|
});
|
|
1066
|
-
var ActivityBodySchema = z.object({
|
|
1067
|
-
taskId: z.string().min(1).max(200),
|
|
1068
|
-
events: z.array(AgentEventOrUnknownSchema),
|
|
1069
|
-
dropped: z.number().int().nonnegative()
|
|
1070
|
-
});
|
|
1071
1279
|
function presencePublishHandler(deps) {
|
|
1072
1280
|
return async (c) => {
|
|
1073
1281
|
const authenticated = await authenticateDevice(c, deps);
|
|
@@ -1101,7 +1309,7 @@ function activityAppendHandler(deps) {
|
|
|
1101
1309
|
return async (c) => {
|
|
1102
1310
|
const authenticated = await authenticateDevice(c, deps);
|
|
1103
1311
|
if (authenticated === void 0) return c.json({ error: "unauthorized" }, 401);
|
|
1104
|
-
const parsed =
|
|
1312
|
+
const parsed = ActivityAppendRequestSchema.safeParse(await readJsonBody(c));
|
|
1105
1313
|
if (!parsed.success) return c.json({ error: "invalid activity body" }, 400);
|
|
1106
1314
|
try {
|
|
1107
1315
|
return c.json(
|
|
@@ -1873,6 +2081,9 @@ function createByokCloud(options) {
|
|
|
1873
2081
|
},
|
|
1874
2082
|
readActivity(tenant, taskId) {
|
|
1875
2083
|
return tenantStoresFor(controlPlane(tenant), root).activity.read(taskId);
|
|
2084
|
+
},
|
|
2085
|
+
readApprovalTimeline(tenant, taskId) {
|
|
2086
|
+
return tenantStoresFor(controlPlane(tenant), root).approvals.read(taskId);
|
|
1876
2087
|
}
|
|
1877
2088
|
};
|
|
1878
2089
|
}
|
|
@@ -2287,11 +2498,130 @@ var InMemoryTaskAttemptStore = class {
|
|
|
2287
2498
|
}
|
|
2288
2499
|
};
|
|
2289
2500
|
|
|
2501
|
+
// src/stores/in-memory/activity.ts
|
|
2502
|
+
var InMemoryActivityStore = class {
|
|
2503
|
+
constructor(clock) {
|
|
2504
|
+
this.clock = clock;
|
|
2505
|
+
}
|
|
2506
|
+
clock;
|
|
2507
|
+
#tails = /* @__PURE__ */ new Map();
|
|
2508
|
+
async append(tenant, input) {
|
|
2509
|
+
const capacity = validateActivityAppend(input);
|
|
2510
|
+
const now = this.clock.now();
|
|
2511
|
+
const receivedAt = now.toISOString();
|
|
2512
|
+
const key = activityTailKey(tenant, input.taskId);
|
|
2513
|
+
const existing = this.#tails.get(key);
|
|
2514
|
+
const live = existing !== void 0 && receivedAt < existing.expiresAt ? existing : void 0;
|
|
2515
|
+
const incoming = projectTimelineEvents(input, receivedAt);
|
|
2516
|
+
for (const next of incoming) {
|
|
2517
|
+
const collision = live?.entries.find(
|
|
2518
|
+
(entry) => entry.batchSeq === next.batchSeq && entry.eventIndex === next.eventIndex && entry.sourceEnvelopeId !== next.sourceEnvelopeId
|
|
2519
|
+
);
|
|
2520
|
+
if (collision !== void 0) {
|
|
2521
|
+
throw new ByokCloudError(
|
|
2522
|
+
"coordination_input_invalid",
|
|
2523
|
+
`Activity order key (${next.batchSeq}, ${next.eventIndex}) already belongs to another source envelope.`
|
|
2524
|
+
);
|
|
2525
|
+
}
|
|
2526
|
+
}
|
|
2527
|
+
const allEntries = [...live?.entries ?? [], ...incoming].sort(compareTimelineEvents);
|
|
2528
|
+
const evicted = Math.max(allEntries.length - capacity, 0);
|
|
2529
|
+
const entries = allEntries.slice(evicted);
|
|
2530
|
+
const cursor = activityCursor(entries);
|
|
2531
|
+
const tail = {
|
|
2532
|
+
tenantId: tenant,
|
|
2533
|
+
taskId: input.taskId,
|
|
2534
|
+
entries,
|
|
2535
|
+
...cursor === void 0 ? {} : { cursor },
|
|
2536
|
+
dropped: (live?.dropped ?? 0) + input.dropped + evicted,
|
|
2537
|
+
capacity,
|
|
2538
|
+
expiresAt: new Date(now.getTime() + input.ttlMs).toISOString()
|
|
2539
|
+
};
|
|
2540
|
+
this.#tails.set(key, tail);
|
|
2541
|
+
return tail;
|
|
2542
|
+
}
|
|
2543
|
+
async read(tenant, taskId) {
|
|
2544
|
+
const key = activityTailKey(tenant, taskId);
|
|
2545
|
+
const tail = this.#tails.get(key);
|
|
2546
|
+
if (tail === void 0) return void 0;
|
|
2547
|
+
if (this.clock.now().toISOString() >= tail.expiresAt) {
|
|
2548
|
+
this.#tails.delete(key);
|
|
2549
|
+
return void 0;
|
|
2550
|
+
}
|
|
2551
|
+
return tail;
|
|
2552
|
+
}
|
|
2553
|
+
};
|
|
2554
|
+
|
|
2555
|
+
// src/stores/in-memory/approval-timeline.ts
|
|
2556
|
+
var InMemoryApprovalTimelineStore = class {
|
|
2557
|
+
constructor(clock) {
|
|
2558
|
+
this.clock = clock;
|
|
2559
|
+
}
|
|
2560
|
+
clock;
|
|
2561
|
+
#tails = /* @__PURE__ */ new Map();
|
|
2562
|
+
async append(tenant, input) {
|
|
2563
|
+
const { capacity, ttlMs, event } = validateApprovalTimelineAppend(input);
|
|
2564
|
+
const now = this.clock.now();
|
|
2565
|
+
const receivedAt = now.toISOString();
|
|
2566
|
+
const key = approvalTimelineKey(tenant, input.taskId);
|
|
2567
|
+
const existing = this.#tails.get(key);
|
|
2568
|
+
const live = existing !== void 0 && receivedAt < existing.expiresAt ? existing : void 0;
|
|
2569
|
+
if (live !== void 0) {
|
|
2570
|
+
const duplicate = live.entries.find(
|
|
2571
|
+
(entry) => entry.sourceEnvelopeId === input.sourceEnvelopeId
|
|
2572
|
+
);
|
|
2573
|
+
if (duplicate !== void 0) {
|
|
2574
|
+
if (JSON.stringify(duplicate.event) !== JSON.stringify(event)) {
|
|
2575
|
+
throw new ByokCloudError(
|
|
2576
|
+
"coordination_input_invalid",
|
|
2577
|
+
"Approval source envelope identity already belongs to another lifecycle event."
|
|
2578
|
+
);
|
|
2579
|
+
}
|
|
2580
|
+
return live;
|
|
2581
|
+
}
|
|
2582
|
+
}
|
|
2583
|
+
const revision = (live?.cursor ?? 0) + 1;
|
|
2584
|
+
const observation = ApprovalObservationSchema.parse({
|
|
2585
|
+
taskId: input.taskId,
|
|
2586
|
+
sourceEnvelopeId: input.sourceEnvelopeId,
|
|
2587
|
+
revision,
|
|
2588
|
+
receivedAt,
|
|
2589
|
+
event
|
|
2590
|
+
});
|
|
2591
|
+
const allEntries = [...live?.entries ?? [], observation];
|
|
2592
|
+
const evicted = Math.max(allEntries.length - capacity, 0);
|
|
2593
|
+
const entries = allEntries.slice(evicted);
|
|
2594
|
+
const tail = {
|
|
2595
|
+
tenantId: tenant,
|
|
2596
|
+
taskId: input.taskId,
|
|
2597
|
+
entries,
|
|
2598
|
+
cursor: approvalTimelineCursor(entries),
|
|
2599
|
+
dropped: (live?.dropped ?? 0) + evicted,
|
|
2600
|
+
capacity,
|
|
2601
|
+
expiresAt: new Date(now.getTime() + ttlMs).toISOString()
|
|
2602
|
+
};
|
|
2603
|
+
this.#tails.set(key, tail);
|
|
2604
|
+
return tail;
|
|
2605
|
+
}
|
|
2606
|
+
async read(tenant, taskId) {
|
|
2607
|
+
const key = approvalTimelineKey(tenant, taskId);
|
|
2608
|
+
const tail = this.#tails.get(key);
|
|
2609
|
+
if (tail === void 0) return void 0;
|
|
2610
|
+
if (this.clock.now().toISOString() >= tail.expiresAt) {
|
|
2611
|
+
this.#tails.delete(key);
|
|
2612
|
+
return void 0;
|
|
2613
|
+
}
|
|
2614
|
+
return tail;
|
|
2615
|
+
}
|
|
2616
|
+
};
|
|
2617
|
+
|
|
2290
2618
|
// src/stores/in-memory/index.ts
|
|
2291
2619
|
function createInMemoryCloudStores(clock, crypto, objects) {
|
|
2292
2620
|
const blobs = createInMemoryBlobs(clock, crypto, objects);
|
|
2293
2621
|
return {
|
|
2294
2622
|
stores: {
|
|
2623
|
+
activity: new InMemoryActivityStore(clock),
|
|
2624
|
+
approvals: new InMemoryApprovalTimelineStore(clock),
|
|
2295
2625
|
devices: new InMemoryDeviceDirectory(),
|
|
2296
2626
|
pairingCodes: new InMemoryPairingCodeStore(clock),
|
|
2297
2627
|
nonces: new InMemoryNonceStore(clock, crypto),
|
|
@@ -2500,6 +2830,8 @@ var TASK_ATTEMPT_STATUSES = [
|
|
|
2500
2830
|
"cancelled"
|
|
2501
2831
|
];
|
|
2502
2832
|
var CLOUD_STORE_NAMES = [
|
|
2833
|
+
"activity",
|
|
2834
|
+
"approvals",
|
|
2503
2835
|
"devices",
|
|
2504
2836
|
"pairingCodes",
|
|
2505
2837
|
"nonces",
|
|
@@ -2513,6 +2845,8 @@ var CLOUD_STORE_NAMES = [
|
|
|
2513
2845
|
|
|
2514
2846
|
// src/stores/ports-contract.ts
|
|
2515
2847
|
var CLOUD_PORT_METHODS = {
|
|
2848
|
+
activity: ["append", "read"],
|
|
2849
|
+
approvals: ["append", "read"],
|
|
2516
2850
|
devices: ["register", "get", "revoke", "list", "resolveByDeviceId"],
|
|
2517
2851
|
pairingCodes: ["issue", "redeem"],
|
|
2518
2852
|
nonces: ["issue", "validate", "markUsed"],
|
|
@@ -2527,6 +2861,8 @@ var CLOUD_PORT_METHODS = {
|
|
|
2527
2861
|
rateLimiter: ["consume"]
|
|
2528
2862
|
};
|
|
2529
2863
|
var CLOUD_PORT_INTERFACES = {
|
|
2864
|
+
activity: "ActivityStore",
|
|
2865
|
+
approvals: "ApprovalTimelineStore",
|
|
2530
2866
|
devices: "DeviceDirectory",
|
|
2531
2867
|
pairingCodes: "PairingCodeStore",
|
|
2532
2868
|
nonces: "NonceStore",
|
|
@@ -2538,6 +2874,6 @@ var CLOUD_PORT_INTERFACES = {
|
|
|
2538
2874
|
rateLimiter: "InboundRateLimiter"
|
|
2539
2875
|
};
|
|
2540
2876
|
|
|
2541
|
-
export { ACCESS_TOKEN_TTL_SECONDS, AllowAllRateLimiter, BLOB_URL_TTL_MS, BoardFeedClient, BoardFeedRetryableError, BoardFeedStoppedError, ByokCloudError, CLOUD_CAPABILITIES, CLOUD_ERROR_CODES, CLOUD_PORT_INTERFACES, CLOUD_PORT_METHODS, CLOUD_STORE_NAMES, CapabilitiesResponseSchema, CloudRouteRegistry, DEDUP_RING_CAPACITY, DEFAULT_ACTIVITY_BOUNDS, DEFAULT_ACTIVITY_CAPACITY, DEFAULT_ACTIVITY_MAX_BYTES, DEFAULT_ACTIVITY_MAX_EVENTS, DEFAULT_ACTIVITY_TTL_MS, DEFAULT_BOARD_CHANNEL_MAX_BYTES, DEFAULT_BOARD_PAGE_LIMIT, DEFAULT_BOARD_STREAM_HEARTBEAT_INTERVAL_MS, DEFAULT_BOARD_STREAM_QUERY_INTERVAL_MS, DEFAULT_BOARD_STREAM_RECONCILIATION_INTERVAL_MS, DEFAULT_BOARD_TITLE_MAX_BYTES, DEFAULT_DEVICE_PROOF_CLOCK_SKEW_MS, DEFAULT_DEVICE_PROOF_MAX_LIFETIME_MS, DEFAULT_EVENTS_PAGE_LIMIT, DEFAULT_LONG_POLL_HOLD_MS, DEFAULT_LONG_POLL_INTERVAL_MS, DEFAULT_MAX_BLOB_SIZE_BYTES, DEFAULT_MAX_TRUTH_REQUEST_BYTES, DEFAULT_PRESENCE_DETAIL_MAX_BYTES, DEFAULT_PRESENCE_MINIMUM_INTERVAL_MS, DEFAULT_PRESENCE_TTL_MS, DEFAULT_SKILL_PACK_PAGE_LIMIT, DEVICE_IDENTITY_PROOF_KEY_EPOCH, DEVICE_IDENTITY_PROOF_KEY_ID, InMemoryBlobContentProxy, InMemoryCloudBlobStore, InMemoryDeviceDirectory, InMemoryInboundDedupStore, InMemoryNonceStore, InMemoryPairingCodeStore, InMemoryProofRequestReceiptStore, InMemoryRequestReceiptStore, InMemoryTaskAttemptStore, MAX_DEVICE_PROOF_CLOCK_SKEW_MS, MAX_DEVICE_PROOF_HEADER_BYTES, MAX_DEVICE_PROOF_MAX_LIFETIME_MS, NONCE_TTL_MS, PAIRING_CODE_TTL_MS, ROUTE_CLASSES, ROUTE_METHODS, TASK_ATTEMPT_STATUSES, TRUTH_BATCH_MAX_RECORDS, TRUTH_INLINE_CONTENT_TYPE, TRUTH_LABEL_MAX_LENGTH, TRUTH_MANIFEST_MAX_LIMIT, TRUTH_RECORD_CAPABILITY, TRUTH_RECORD_KEY_MAX_LENGTH, TRUTH_REQUEST_ID_MAX_LENGTH, TruthBodyInputSchema, TruthCommitError, TruthCommitResponseSchema, TruthRecordKeySchema, TruthRecordMetadataSchema, TruthWriteRequestSchema, authenticateBearer, authenticateDeviceProof, createAuthPlane, createByokCloud, createHmacTokenSigner, createInMemoryBlobs, createInMemoryByokCloud, createInMemoryCloudStores, createWebCrypto, declares, extractBearerToken, fullCapabilityDeclaration, handleInboundEnvelope, isCloudError, isTruthCommitError, projectTerminalResult, routeKey, tenantStoresFor, terminalReceiptKey, truthManifestMetadata, truthRecordMetadata, verifyNonceSignature };
|
|
2877
|
+
export { ACCESS_TOKEN_TTL_SECONDS, APPROVAL_SUMMARY_MAX_BYTES, ActivityAppendRequestSchema, AllowAllRateLimiter, ApprovalObservationSchema, ApprovalTimelineEventSchema, BLOB_URL_TTL_MS, BoardFeedClient, BoardFeedRetryableError, BoardFeedStoppedError, ByokCloudError, CLOUD_CAPABILITIES, CLOUD_ERROR_CODES, CLOUD_PORT_INTERFACES, CLOUD_PORT_METHODS, CLOUD_STORE_NAMES, CapabilitiesResponseSchema, CloudRouteRegistry, DEDUP_RING_CAPACITY, DEFAULT_ACTIVITY_BOUNDS, DEFAULT_ACTIVITY_CAPACITY, DEFAULT_ACTIVITY_MAX_BYTES, DEFAULT_ACTIVITY_MAX_EVENTS, DEFAULT_ACTIVITY_TTL_MS, DEFAULT_APPROVAL_TIMELINE_CAPACITY, DEFAULT_APPROVAL_TIMELINE_TTL_MS, DEFAULT_BOARD_CHANNEL_MAX_BYTES, DEFAULT_BOARD_PAGE_LIMIT, DEFAULT_BOARD_STREAM_HEARTBEAT_INTERVAL_MS, DEFAULT_BOARD_STREAM_QUERY_INTERVAL_MS, DEFAULT_BOARD_STREAM_RECONCILIATION_INTERVAL_MS, DEFAULT_BOARD_TITLE_MAX_BYTES, DEFAULT_DEVICE_PROOF_CLOCK_SKEW_MS, DEFAULT_DEVICE_PROOF_MAX_LIFETIME_MS, DEFAULT_EVENTS_PAGE_LIMIT, DEFAULT_LONG_POLL_HOLD_MS, DEFAULT_LONG_POLL_INTERVAL_MS, DEFAULT_MAX_BLOB_SIZE_BYTES, DEFAULT_MAX_TRUTH_REQUEST_BYTES, DEFAULT_PRESENCE_DETAIL_MAX_BYTES, DEFAULT_PRESENCE_MINIMUM_INTERVAL_MS, DEFAULT_PRESENCE_TTL_MS, DEFAULT_SKILL_PACK_PAGE_LIMIT, DEVICE_IDENTITY_PROOF_KEY_EPOCH, DEVICE_IDENTITY_PROOF_KEY_ID, InMemoryActivityStore, InMemoryBlobContentProxy, InMemoryCloudBlobStore, InMemoryDeviceDirectory, InMemoryInboundDedupStore, InMemoryNonceStore, InMemoryPairingCodeStore, InMemoryProofRequestReceiptStore, InMemoryRequestReceiptStore, InMemoryTaskAttemptStore, MAX_DEVICE_PROOF_CLOCK_SKEW_MS, MAX_DEVICE_PROOF_HEADER_BYTES, MAX_DEVICE_PROOF_MAX_LIFETIME_MS, NONCE_TTL_MS, PAIRING_CODE_TTL_MS, ROUTE_CLASSES, ROUTE_METHODS, TASK_ATTEMPT_STATUSES, TRUTH_BATCH_MAX_RECORDS, TRUTH_INLINE_CONTENT_TYPE, TRUTH_LABEL_MAX_LENGTH, TRUTH_MANIFEST_MAX_LIMIT, TRUTH_RECORD_CAPABILITY, TRUTH_RECORD_KEY_MAX_LENGTH, TRUTH_REQUEST_ID_MAX_LENGTH, TimelineEventSchema, TruthBodyInputSchema, TruthCommitError, TruthCommitResponseSchema, TruthRecordKeySchema, TruthRecordMetadataSchema, TruthWriteRequestSchema, activityCursor, approvalTimelineCursor, authenticateBearer, authenticateDeviceProof, createAuthPlane, createByokCloud, createHmacTokenSigner, createInMemoryBlobs, createInMemoryByokCloud, createInMemoryCloudStores, createWebCrypto, declares, extractBearerToken, fullCapabilityDeclaration, handleInboundEnvelope, isCloudError, isTruthCommitError, parseApprovalObservations, parseTimelineEvents, projectTerminalResult, projectTimelineEvents, routeKey, tenantStoresFor, terminalReceiptKey, truthManifestMetadata, truthRecordMetadata, validateActivityAppend, validateApprovalTimelineAppend, verifyNonceSignature };
|
|
2542
2878
|
//# sourceMappingURL=index.js.map
|
|
2543
2879
|
//# sourceMappingURL=index.js.map
|