@byok-sdk/cloud 0.4.1 → 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/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 +343 -16
- 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 +3 -3
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),
|
|
@@ -721,6 +798,75 @@ function eventsHandler(deps) {
|
|
|
721
798
|
return c.json(response, 200);
|
|
722
799
|
};
|
|
723
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
|
+
}
|
|
724
870
|
async function projectTerminalToReview(board, taskId) {
|
|
725
871
|
const item = await board.get(taskId);
|
|
726
872
|
if (item === void 0 || item.status !== "in_progress") return;
|
|
@@ -749,7 +895,16 @@ async function handleInboundEnvelope(stores, deviceId, envelope, activityBounds
|
|
|
749
895
|
if (attempt?.ownerDeviceId !== void 0 && attempt.ownerDeviceId !== deviceId) return "rejected";
|
|
750
896
|
if (envelope.type === "task.progress" && envelope.payload.events.length > 0) {
|
|
751
897
|
try {
|
|
752
|
-
|
|
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
|
+
);
|
|
753
908
|
} catch (caught) {
|
|
754
909
|
if (isCloudError(caught, "activity_batch_too_large") || isCloudError(caught, "coordination_input_invalid")) {
|
|
755
910
|
return "rejected";
|
|
@@ -757,6 +912,15 @@ async function handleInboundEnvelope(stores, deviceId, envelope, activityBounds
|
|
|
757
912
|
throw caught;
|
|
758
913
|
}
|
|
759
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
|
+
}
|
|
760
924
|
if (await stores.dedup.checkAndRecord(deviceId, envelope.id)) return "duplicate";
|
|
761
925
|
await applyLifecycle(stores, deviceId, taskId, envelope, activityBounds);
|
|
762
926
|
return "accepted";
|
|
@@ -776,11 +940,23 @@ async function applyLifecycle(stores, deviceId, taskId, envelope, activityBounds
|
|
|
776
940
|
if (envelope.payload.events.length > 0) {
|
|
777
941
|
await appendActivityEvents(
|
|
778
942
|
stores.activity,
|
|
779
|
-
{
|
|
943
|
+
{
|
|
944
|
+
taskId,
|
|
945
|
+
sourceEnvelopeId: envelope.id,
|
|
946
|
+
batchSeq: envelope.payload.seq,
|
|
947
|
+
events: envelope.payload.events,
|
|
948
|
+
dropped: 0
|
|
949
|
+
},
|
|
780
950
|
activityBounds
|
|
781
951
|
);
|
|
782
952
|
}
|
|
783
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;
|
|
784
960
|
case "task.complete":
|
|
785
961
|
await recordTerminal(stores, taskId, envelope, "complete");
|
|
786
962
|
return;
|
|
@@ -794,6 +970,34 @@ async function applyLifecycle(stores, deviceId, taskId, envelope, activityBounds
|
|
|
794
970
|
return;
|
|
795
971
|
}
|
|
796
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
|
+
}
|
|
797
1001
|
async function recordTerminal(stores, taskId, envelope, status) {
|
|
798
1002
|
const { created } = await stores.receipts.record({
|
|
799
1003
|
key: terminalReceiptKey(taskId),
|
|
@@ -1072,11 +1276,6 @@ var PresenceBodySchema = z.object({
|
|
|
1072
1276
|
detail: z.string().optional(),
|
|
1073
1277
|
configuredToolsets: ConfiguredToolsetsSchema.optional()
|
|
1074
1278
|
});
|
|
1075
|
-
var ActivityBodySchema = z.object({
|
|
1076
|
-
taskId: z.string().min(1).max(200),
|
|
1077
|
-
events: z.array(AgentEventOrUnknownSchema),
|
|
1078
|
-
dropped: z.number().int().nonnegative()
|
|
1079
|
-
});
|
|
1080
1279
|
function presencePublishHandler(deps) {
|
|
1081
1280
|
return async (c) => {
|
|
1082
1281
|
const authenticated = await authenticateDevice(c, deps);
|
|
@@ -1110,7 +1309,7 @@ function activityAppendHandler(deps) {
|
|
|
1110
1309
|
return async (c) => {
|
|
1111
1310
|
const authenticated = await authenticateDevice(c, deps);
|
|
1112
1311
|
if (authenticated === void 0) return c.json({ error: "unauthorized" }, 401);
|
|
1113
|
-
const parsed =
|
|
1312
|
+
const parsed = ActivityAppendRequestSchema.safeParse(await readJsonBody(c));
|
|
1114
1313
|
if (!parsed.success) return c.json({ error: "invalid activity body" }, 400);
|
|
1115
1314
|
try {
|
|
1116
1315
|
return c.json(
|
|
@@ -1882,6 +2081,9 @@ function createByokCloud(options) {
|
|
|
1882
2081
|
},
|
|
1883
2082
|
readActivity(tenant, taskId) {
|
|
1884
2083
|
return tenantStoresFor(controlPlane(tenant), root).activity.read(taskId);
|
|
2084
|
+
},
|
|
2085
|
+
readApprovalTimeline(tenant, taskId) {
|
|
2086
|
+
return tenantStoresFor(controlPlane(tenant), root).approvals.read(taskId);
|
|
1885
2087
|
}
|
|
1886
2088
|
};
|
|
1887
2089
|
}
|
|
@@ -2296,11 +2498,130 @@ var InMemoryTaskAttemptStore = class {
|
|
|
2296
2498
|
}
|
|
2297
2499
|
};
|
|
2298
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
|
+
|
|
2299
2618
|
// src/stores/in-memory/index.ts
|
|
2300
2619
|
function createInMemoryCloudStores(clock, crypto, objects) {
|
|
2301
2620
|
const blobs = createInMemoryBlobs(clock, crypto, objects);
|
|
2302
2621
|
return {
|
|
2303
2622
|
stores: {
|
|
2623
|
+
activity: new InMemoryActivityStore(clock),
|
|
2624
|
+
approvals: new InMemoryApprovalTimelineStore(clock),
|
|
2304
2625
|
devices: new InMemoryDeviceDirectory(),
|
|
2305
2626
|
pairingCodes: new InMemoryPairingCodeStore(clock),
|
|
2306
2627
|
nonces: new InMemoryNonceStore(clock, crypto),
|
|
@@ -2509,6 +2830,8 @@ var TASK_ATTEMPT_STATUSES = [
|
|
|
2509
2830
|
"cancelled"
|
|
2510
2831
|
];
|
|
2511
2832
|
var CLOUD_STORE_NAMES = [
|
|
2833
|
+
"activity",
|
|
2834
|
+
"approvals",
|
|
2512
2835
|
"devices",
|
|
2513
2836
|
"pairingCodes",
|
|
2514
2837
|
"nonces",
|
|
@@ -2522,6 +2845,8 @@ var CLOUD_STORE_NAMES = [
|
|
|
2522
2845
|
|
|
2523
2846
|
// src/stores/ports-contract.ts
|
|
2524
2847
|
var CLOUD_PORT_METHODS = {
|
|
2848
|
+
activity: ["append", "read"],
|
|
2849
|
+
approvals: ["append", "read"],
|
|
2525
2850
|
devices: ["register", "get", "revoke", "list", "resolveByDeviceId"],
|
|
2526
2851
|
pairingCodes: ["issue", "redeem"],
|
|
2527
2852
|
nonces: ["issue", "validate", "markUsed"],
|
|
@@ -2536,6 +2861,8 @@ var CLOUD_PORT_METHODS = {
|
|
|
2536
2861
|
rateLimiter: ["consume"]
|
|
2537
2862
|
};
|
|
2538
2863
|
var CLOUD_PORT_INTERFACES = {
|
|
2864
|
+
activity: "ActivityStore",
|
|
2865
|
+
approvals: "ApprovalTimelineStore",
|
|
2539
2866
|
devices: "DeviceDirectory",
|
|
2540
2867
|
pairingCodes: "PairingCodeStore",
|
|
2541
2868
|
nonces: "NonceStore",
|
|
@@ -2547,6 +2874,6 @@ var CLOUD_PORT_INTERFACES = {
|
|
|
2547
2874
|
rateLimiter: "InboundRateLimiter"
|
|
2548
2875
|
};
|
|
2549
2876
|
|
|
2550
|
-
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 };
|
|
2551
2878
|
//# sourceMappingURL=index.js.map
|
|
2552
2879
|
//# sourceMappingURL=index.js.map
|