@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/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 { ConfiguredToolsetsSchema, AgentEventOrUnknownSchema, 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';
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 activityDetails(events, dropped, bounds) {
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
- return events.map((event) => JSON.stringify(event));
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
- details: activityDetails(input.events, input.dropped, bounds),
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) => core.activity.append(tenant, input),
445
- read: (taskId) => core.activity.read(tenant, 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
- activityDetails(envelope.payload.events, 0, activityBounds);
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
- { taskId, events: envelope.payload.events, dropped: 0 },
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 = ActivityBodySchema.safeParse(await readJsonBody(c));
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