ankka 0.15.0 → 0.16.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.
Files changed (60) hide show
  1. package/dist/_proto/ankka/protocol/v1/client_pb.d.ts +365 -0
  2. package/dist/_proto/ankka/protocol/v1/client_pb.js +61 -5
  3. package/dist/_proto/ankka/protocol/v1/discovery_pb.d.ts +7 -0
  4. package/dist/_proto/ankka/protocol/v1/discovery_pb.js +1 -1
  5. package/dist/_proto/ankka/protocol/v1/erasure_pb.d.ts +72 -0
  6. package/dist/_proto/ankka/protocol/v1/erasure_pb.js +24 -0
  7. package/dist/_proto/ankka/protocol/v1/event_sourced_pb.d.ts +14 -0
  8. package/dist/_proto/ankka/protocol/v1/event_sourced_pb.js +1 -1
  9. package/dist/_proto/ankka/protocol/v1/wasm_pb.d.ts +136 -1
  10. package/dist/_proto/ankka/protocol/v1/wasm_pb.js +21 -1
  11. package/dist/autonomous.d.ts +12 -2
  12. package/dist/autonomous.js +17 -3
  13. package/dist/client.d.ts +21 -3
  14. package/dist/client.js +46 -13
  15. package/dist/codec.d.ts +2 -0
  16. package/dist/codec.js +8 -1
  17. package/dist/consumer.d.ts +5 -0
  18. package/dist/consumer.js +10 -0
  19. package/dist/endpoint.d.ts +5 -0
  20. package/dist/endpoint.js +10 -0
  21. package/dist/erasure.d.ts +35 -0
  22. package/dist/erasure.js +10 -0
  23. package/dist/erasures.d.ts +32 -0
  24. package/dist/erasures.js +65 -0
  25. package/dist/graph.d.ts +5 -0
  26. package/dist/graph.js +10 -0
  27. package/dist/index.d.ts +5 -1
  28. package/dist/index.js +5 -1
  29. package/dist/json.js +110 -0
  30. package/dist/keyring.d.ts +119 -0
  31. package/dist/keyring.js +417 -0
  32. package/dist/personal.d.ts +97 -0
  33. package/dist/personal.js +209 -0
  34. package/dist/schema.d.ts +13 -0
  35. package/dist/schema.js +43 -0
  36. package/dist/server/agent.js +2 -1
  37. package/dist/server/discovery.d.ts +13 -1
  38. package/dist/server/discovery.js +14 -2
  39. package/dist/server/erasure.d.ts +7 -0
  40. package/dist/server/erasure.js +40 -0
  41. package/dist/server/eventSourced.js +25 -8
  42. package/dist/server/keyValue.js +6 -2
  43. package/dist/server/payloads.d.ts +10 -2
  44. package/dist/server/payloads.js +36 -4
  45. package/dist/server/server.d.ts +2 -0
  46. package/dist/server/server.js +59 -2
  47. package/dist/server/stateless.js +10 -1
  48. package/dist/server/workflow.js +8 -2
  49. package/dist/service.d.ts +12 -1
  50. package/dist/service.js +60 -3
  51. package/dist/spec.d.ts +1 -1
  52. package/dist/spec.js +2 -1
  53. package/dist/storage.d.ts +48 -2
  54. package/dist/storage.js +138 -7
  55. package/dist/testkit/index.d.ts +1 -1
  56. package/dist/testkit/integration.d.ts +35 -0
  57. package/dist/testkit/integration.js +106 -1
  58. package/dist/version.d.ts +1 -1
  59. package/dist/version.js +1 -1
  60. package/package.json +1 -1
@@ -0,0 +1,24 @@
1
+ // The service's erasure handler (protocol 1.23, feature 042): what the platform cannot erase for it,
2
+ // such as objects in a bucket. The sidecar calls it on one instance for each erased data subject,
3
+ // and again on each re-run within the window; it must be idempotent. A handler that fails is
4
+ // recorded as failed for that run and run again on the next.
5
+ import { fileDesc, messageDesc, serviceDesc } from "@bufbuild/protobuf/codegenv2";
6
+ import { file_ankka_protocol_v1_payload } from "./payload_pb.js";
7
+ /**
8
+ * Describes the file ankka/protocol/v1/erasure.proto.
9
+ */
10
+ export const file_ankka_protocol_v1_erasure = /*@__PURE__*/ fileDesc("Ch9hbmtrYS9wcm90b2NvbC92MS9lcmFzdXJlLnByb3RvEhFhbmtrYS5wcm90b2NvbC52MSJxCgtFcmFzdXJlQ2FsbBIPCgdzdWJqZWN0GAEgASgJEhMKC2VyYXN1cmVfc2VxGAIgASgDEg0KBXJlcnVuGAMgASgIEi0KCG1ldGFkYXRhGAQgASgLMhsuYW5ra2EucHJvdG9jb2wudjEuTWV0YWRhdGEicAoMRXJhc3VyZVJlcGx5EhYKDm9iamVjdHNfZXJhc2VkGAEgASgDEhAKCGZpbmFsaXR5GAIgASgJEiwKBWVycm9yGAMgASgLMhguYW5ra2EucHJvdG9jb2wudjEuRXJyb3JIAIgBAUIICgZfZXJyb3IyVAoHRXJhc3VyZRJJCgZJbnZva2USHi5hbmtrYS5wcm90b2NvbC52MS5FcmFzdXJlQ2FsbBofLmFua2thLnByb3RvY29sLnYxLkVyYXN1cmVSZXBseWIGcHJvdG8z", [file_ankka_protocol_v1_payload]);
11
+ /**
12
+ * Describes the message ankka.protocol.v1.ErasureCall.
13
+ * Use `create(ErasureCallSchema)` to create a new message.
14
+ */
15
+ export const ErasureCallSchema = /*@__PURE__*/ messageDesc(file_ankka_protocol_v1_erasure, 0);
16
+ /**
17
+ * Describes the message ankka.protocol.v1.ErasureReply.
18
+ * Use `create(ErasureReplySchema)` to create a new message.
19
+ */
20
+ export const ErasureReplySchema = /*@__PURE__*/ messageDesc(file_ankka_protocol_v1_erasure, 1);
21
+ /**
22
+ * @generated from service ankka.protocol.v1.Erasure
23
+ */
24
+ export const Erasure = /*@__PURE__*/ serviceDesc(file_ankka_protocol_v1_erasure, 0);
@@ -64,6 +64,13 @@ export type EventSourcedIn_Init = Message<"ankka.protocol.v1.EventSourcedIn.Init
64
64
  * @generated from field: string installation = 4;
65
65
  */
66
66
  installation: string;
67
+ /**
68
+ * 1.23: the home the snapshot was written under, whose keyring keeps the keys of its personal
69
+ * fields (SubjectKeyRequest.home); empty for an entity not replicated or no snapshot.
70
+ *
71
+ * @generated from field: string home = 5;
72
+ */
73
+ home: string;
67
74
  };
68
75
  /**
69
76
  * Describes the message ankka.protocol.v1.EventSourcedIn.Init.
@@ -180,6 +187,13 @@ export type EventSourcedIn_Command = Message<"ankka.protocol.v1.EventSourcedIn.C
180
187
  * @generated from field: string forwarded_from = 9;
181
188
  */
182
189
  forwardedFrom: string;
190
+ /**
191
+ * 1.23: the entity's home as this copy reads it, whose keyring keeps the keys of the state's
192
+ * personal fields (SubjectKeyRequest.home); empty for an entity not replicated.
193
+ *
194
+ * @generated from field: string home = 10;
195
+ */
196
+ home: string;
183
197
  };
184
198
  /**
185
199
  * Describes the message ankka.protocol.v1.EventSourcedIn.Command.
@@ -5,7 +5,7 @@ import { file_ankka_protocol_v1_payload } from "./payload_pb.js";
5
5
  /**
6
6
  * Describes the file ankka/protocol/v1/event_sourced.proto.
7
7
  */
8
- export const file_ankka_protocol_v1_event_sourced = /*@__PURE__*/ fileDesc("CiVhbmtrYS9wcm90b2NvbC92MS9ldmVudF9zb3VyY2VkLnByb3RvEhFhbmtrYS5wcm90b2NvbC52MSKsBgoORXZlbnRTb3VyY2VkSW4SNgoEaW5pdBgBIAEoCzImLmFua2thLnByb3RvY29sLnYxLkV2ZW50U291cmNlZEluLkluaXRIABI4CgVldmVudBgCIAEoCzInLmFua2thLnByb3RvY29sLnYxLkV2ZW50U291cmNlZEluLkV2ZW50SAASPAoHY29tbWFuZBgDIAEoCzIpLmFua2thLnByb3RvY29sLnYxLkV2ZW50U291cmNlZEluLkNvbW1hbmRIABqVAQoESW5pdBIUCgxjb21wb25lbnRfaWQYASABKAkSEQoJZW50aXR5X2lkGAIgASgJEkEKCHNuYXBzaG90GAMgASgLMiouYW5ra2EucHJvdG9jb2wudjEuRXZlbnRTb3VyY2VkSW4uU25hcHNob3RIAIgBARIUCgxpbnN0YWxsYXRpb24YBCABKAlCCwoJX3NuYXBzaG90GkkKCFNuYXBzaG90EhAKCHNlcXVlbmNlGAEgASgDEisKB3BheWxvYWQYAiABKAsyGi5hbmtrYS5wcm90b2NvbC52MS5QYXlsb2FkGokBCgVFdmVudBIQCghzZXF1ZW5jZRgBIAEoAxIrCgdwYXlsb2FkGAIgASgLMhouYW5ra2EucHJvdG9jb2wudjEuUGF5bG9hZBIUCgxpbnN0YWxsYXRpb24YAyABKAkSEwoLYXR0cmlidXRpb24YBCABKAkSFgoOZm9yd2FyZGVkX2Zyb20YBSABKAka7wEKB0NvbW1hbmQSCgoCaWQYASABKAMSDAoEbmFtZRgCIAEoCRIrCgdwYXlsb2FkGAMgASgLMhouYW5ra2EucHJvdG9jb2wudjEuUGF5bG9hZBItCghtZXRhZGF0YRgEIAEoCzIbLmFua2thLnByb3RvY29sLnYxLk1ldGFkYXRhEhoKEnNuYXBzaG90X3JlcXVlc3RlZBgFIAEoCBIUCgxpbnN0YWxsYXRpb24YBiABKAkSDwoHYXRfaG9tZRgHIAEoCBITCgthdHRyaWJ1dGlvbhgIIAEoCRIWCg5mb3J3YXJkZWRfZnJvbRgJIAEoCUIJCgdtZXNzYWdlItEDCg9FdmVudFNvdXJjZWRPdXQSOQoFcmVwbHkYASABKAsyKC5hbmtrYS5wcm90b2NvbC52MS5FdmVudFNvdXJjZWRPdXQuUmVwbHlIABItCgdmYWlsdXJlGAIgASgLMhouYW5ra2EucHJvdG9jb2wudjEuRmFpbHVyZUgAGsgCCgVSZXBseRISCgpjb21tYW5kX2lkGAEgASgDEioKBmV2ZW50cxgCIAMoCzIaLmFua2thLnByb3RvY29sLnYxLlBheWxvYWQSNAoJcmV0ZW50aW9uGAMgASgLMhwuYW5ra2EucHJvdG9jb2wudjEuUmV0ZW50aW9uSACIAQESKwoHb3V0Y29tZRgEIAEoCzIaLmFua2thLnByb3RvY29sLnYxLk91dGNvbWUSMQoIc25hcHNob3QYBSABKAsyGi5hbmtrYS5wcm90b2NvbC52MS5QYXlsb2FkSAGIAQESPgoLcmVwbGljYXRpb24YBiABKAsyJC5hbmtrYS5wcm90b2NvbC52MS5SZXBsaWNhdGlvbkNoYW5nZUgCiAEBQgwKCl9yZXRlbnRpb25CCwoJX3NuYXBzaG90Qg4KDF9yZXBsaWNhdGlvbkIJCgdtZXNzYWdlIp4BChFSZXBsaWNhdGlvbkNoYW5nZRIWCgxoYW5kX292ZXJfdG8YASABKAlIABI9CgNzZXQYAiABKAsyLi5hbmtrYS5wcm90b2NvbC52MS5SZXBsaWNhdGlvbkNoYW5nZS5TZXRDaGFuZ2VIABooCglTZXRDaGFuZ2USCwoDYWRkGAEgAygJEg4KBnJlbW92ZRgCIAMoCUIICgZjaGFuZ2UyYwoMRXZlbnRTb3VyY2VkElMKBkhhbmRsZRIhLmFua2thLnByb3RvY29sLnYxLkV2ZW50U291cmNlZEluGiIuYW5ra2EucHJvdG9jb2wudjEuRXZlbnRTb3VyY2VkT3V0KAEwAWIGcHJvdG8z", [file_ankka_protocol_v1_payload]);
8
+ export const file_ankka_protocol_v1_event_sourced = /*@__PURE__*/ fileDesc("CiVhbmtrYS9wcm90b2NvbC92MS9ldmVudF9zb3VyY2VkLnByb3RvEhFhbmtrYS5wcm90b2NvbC52MSLIBgoORXZlbnRTb3VyY2VkSW4SNgoEaW5pdBgBIAEoCzImLmFua2thLnByb3RvY29sLnYxLkV2ZW50U291cmNlZEluLkluaXRIABI4CgVldmVudBgCIAEoCzInLmFua2thLnByb3RvY29sLnYxLkV2ZW50U291cmNlZEluLkV2ZW50SAASPAoHY29tbWFuZBgDIAEoCzIpLmFua2thLnByb3RvY29sLnYxLkV2ZW50U291cmNlZEluLkNvbW1hbmRIABqjAQoESW5pdBIUCgxjb21wb25lbnRfaWQYASABKAkSEQoJZW50aXR5X2lkGAIgASgJEkEKCHNuYXBzaG90GAMgASgLMiouYW5ra2EucHJvdG9jb2wudjEuRXZlbnRTb3VyY2VkSW4uU25hcHNob3RIAIgBARIUCgxpbnN0YWxsYXRpb24YBCABKAkSDAoEaG9tZRgFIAEoCUILCglfc25hcHNob3QaSQoIU25hcHNob3QSEAoIc2VxdWVuY2UYASABKAMSKwoHcGF5bG9hZBgCIAEoCzIaLmFua2thLnByb3RvY29sLnYxLlBheWxvYWQaiQEKBUV2ZW50EhAKCHNlcXVlbmNlGAEgASgDEisKB3BheWxvYWQYAiABKAsyGi5hbmtrYS5wcm90b2NvbC52MS5QYXlsb2FkEhQKDGluc3RhbGxhdGlvbhgDIAEoCRITCgthdHRyaWJ1dGlvbhgEIAEoCRIWCg5mb3J3YXJkZWRfZnJvbRgFIAEoCRr9AQoHQ29tbWFuZBIKCgJpZBgBIAEoAxIMCgRuYW1lGAIgASgJEisKB3BheWxvYWQYAyABKAsyGi5hbmtrYS5wcm90b2NvbC52MS5QYXlsb2FkEi0KCG1ldGFkYXRhGAQgASgLMhsuYW5ra2EucHJvdG9jb2wudjEuTWV0YWRhdGESGgoSc25hcHNob3RfcmVxdWVzdGVkGAUgASgIEhQKDGluc3RhbGxhdGlvbhgGIAEoCRIPCgdhdF9ob21lGAcgASgIEhMKC2F0dHJpYnV0aW9uGAggASgJEhYKDmZvcndhcmRlZF9mcm9tGAkgASgJEgwKBGhvbWUYCiABKAlCCQoHbWVzc2FnZSLRAwoPRXZlbnRTb3VyY2VkT3V0EjkKBXJlcGx5GAEgASgLMiguYW5ra2EucHJvdG9jb2wudjEuRXZlbnRTb3VyY2VkT3V0LlJlcGx5SAASLQoHZmFpbHVyZRgCIAEoCzIaLmFua2thLnByb3RvY29sLnYxLkZhaWx1cmVIABrIAgoFUmVwbHkSEgoKY29tbWFuZF9pZBgBIAEoAxIqCgZldmVudHMYAiADKAsyGi5hbmtrYS5wcm90b2NvbC52MS5QYXlsb2FkEjQKCXJldGVudGlvbhgDIAEoCzIcLmFua2thLnByb3RvY29sLnYxLlJldGVudGlvbkgAiAEBEisKB291dGNvbWUYBCABKAsyGi5hbmtrYS5wcm90b2NvbC52MS5PdXRjb21lEjEKCHNuYXBzaG90GAUgASgLMhouYW5ra2EucHJvdG9jb2wudjEuUGF5bG9hZEgBiAEBEj4KC3JlcGxpY2F0aW9uGAYgASgLMiQuYW5ra2EucHJvdG9jb2wudjEuUmVwbGljYXRpb25DaGFuZ2VIAogBAUIMCgpfcmV0ZW50aW9uQgsKCV9zbmFwc2hvdEIOCgxfcmVwbGljYXRpb25CCQoHbWVzc2FnZSKeAQoRUmVwbGljYXRpb25DaGFuZ2USFgoMaGFuZF9vdmVyX3RvGAEgASgJSAASPQoDc2V0GAIgASgLMi4uYW5ra2EucHJvdG9jb2wudjEuUmVwbGljYXRpb25DaGFuZ2UuU2V0Q2hhbmdlSAAaKAoJU2V0Q2hhbmdlEgsKA2FkZBgBIAMoCRIOCgZyZW1vdmUYAiADKAlCCAoGY2hhbmdlMmMKDEV2ZW50U291cmNlZBJTCgZIYW5kbGUSIS5hbmtrYS5wcm90b2NvbC52MS5FdmVudFNvdXJjZWRJbhoiLmFua2thLnByb3RvY29sLnYxLkV2ZW50U291cmNlZE91dCgBMAFiBnByb3RvMw", [file_ankka_protocol_v1_payload]);
9
9
  /**
10
10
  * Describes the message ankka.protocol.v1.EventSourcedIn.
11
11
  * Use `create(EventSourcedInSchema)` to create a new message.
@@ -1,5 +1,5 @@
1
1
  import type { GenFile, GenMessage } from "@bufbuild/protobuf/codegenv2";
2
- import type { Failure, Payload } from "./payload_pb.ts";
2
+ import type { Error, Failure, Payload } from "./payload_pb.ts";
3
3
  import type { Kind, Spec } from "./discovery_pb.ts";
4
4
  import type { EventSourcedIn_Command, EventSourcedOut_Reply } from "./event_sourced_pb.ts";
5
5
  import type { KeyValueIn_Command, KeyValueOut_Reply } from "./key_value_pb.ts";
@@ -329,3 +329,138 @@ export type StreamTokens = Message<"ankka.protocol.v1.StreamTokens"> & {
329
329
  * Use `create(StreamTokensSchema)` to create a new message.
330
330
  */
331
331
  export declare const StreamTokensSchema: GenMessage<StreamTokens>;
332
+ /**
333
+ * keyring_seal (1.23, feature 042): a personal field sealed into its envelope by the runtime, with
334
+ * the keyring the runtime holds and the same code a Scala field is sealed with. `value` is the
335
+ * field's own JSON; `manifest` the manifest of the record the field is in, which the envelope is
336
+ * bound to. A write for an erased data subject is the reply's Error (CONFLICT), never a trap.
337
+ *
338
+ * @generated from message ankka.protocol.v1.KeyringSealRequest
339
+ */
340
+ export type KeyringSealRequest = Message<"ankka.protocol.v1.KeyringSealRequest"> & {
341
+ /**
342
+ * @generated from field: string subject = 1;
343
+ */
344
+ subject: string;
345
+ /**
346
+ * @generated from field: string manifest = 2;
347
+ */
348
+ manifest: string;
349
+ /**
350
+ * @generated from field: bytes value = 3;
351
+ */
352
+ value: Uint8Array;
353
+ /**
354
+ * the field written erased: the envelope without
355
+ *
356
+ * @generated from field: bool erased = 4;
357
+ */
358
+ erased: boolean;
359
+ /**
360
+ * `c`, under the project the runtime holds; `value`
361
+ * is not read
362
+ * 1.23: the project of the envelope the field was read from, when another project's (FR-027):
363
+ * the field is sealed again under that project's key, never made here, and written erased when
364
+ * that key is no longer given. Empty: the runtime's own project.
365
+ *
366
+ * @generated from field: string project = 5;
367
+ */
368
+ project: string;
369
+ };
370
+ /**
371
+ * Describes the message ankka.protocol.v1.KeyringSealRequest.
372
+ * Use `create(KeyringSealRequestSchema)` to create a new message.
373
+ */
374
+ export declare const KeyringSealRequestSchema: GenMessage<KeyringSealRequest>;
375
+ /**
376
+ * @generated from message ankka.protocol.v1.KeyringSealReply
377
+ */
378
+ export type KeyringSealReply = Message<"ankka.protocol.v1.KeyringSealReply"> & {
379
+ /**
380
+ * @generated from oneof ankka.protocol.v1.KeyringSealReply.reply
381
+ */
382
+ reply: {
383
+ /**
384
+ * the field as it is written: the envelope's JSON
385
+ *
386
+ * @generated from field: bytes envelope = 1;
387
+ */
388
+ value: Uint8Array;
389
+ case: "envelope";
390
+ } | {
391
+ /**
392
+ * @generated from field: ankka.protocol.v1.Error error = 2;
393
+ */
394
+ value: Error;
395
+ case: "error";
396
+ } | {
397
+ case: undefined;
398
+ value?: undefined;
399
+ };
400
+ };
401
+ /**
402
+ * Describes the message ankka.protocol.v1.KeyringSealReply.
403
+ * Use `create(KeyringSealReplySchema)` to create a new message.
404
+ */
405
+ export declare const KeyringSealReplySchema: GenMessage<KeyringSealReply>;
406
+ /**
407
+ * keyring_open (1.23): an envelope read back. Erased when the subject's key is destroyed; an
408
+ * envelope whose authentication fails is the reply's Error (INTERNAL, details `personal` =
409
+ * `corrupt`).
410
+ *
411
+ * @generated from message ankka.protocol.v1.KeyringOpenRequest
412
+ */
413
+ export type KeyringOpenRequest = Message<"ankka.protocol.v1.KeyringOpenRequest"> & {
414
+ /**
415
+ * the field as it was written
416
+ *
417
+ * @generated from field: bytes envelope = 1;
418
+ */
419
+ envelope: Uint8Array;
420
+ /**
421
+ * @generated from field: string manifest = 2;
422
+ */
423
+ manifest: string;
424
+ };
425
+ /**
426
+ * Describes the message ankka.protocol.v1.KeyringOpenRequest.
427
+ * Use `create(KeyringOpenRequestSchema)` to create a new message.
428
+ */
429
+ export declare const KeyringOpenRequestSchema: GenMessage<KeyringOpenRequest>;
430
+ /**
431
+ * @generated from message ankka.protocol.v1.KeyringOpenReply
432
+ */
433
+ export type KeyringOpenReply = Message<"ankka.protocol.v1.KeyringOpenReply"> & {
434
+ /**
435
+ * @generated from oneof ankka.protocol.v1.KeyringOpenReply.reply
436
+ */
437
+ reply: {
438
+ /**
439
+ * the field's own JSON
440
+ *
441
+ * @generated from field: bytes value = 1;
442
+ */
443
+ value: Uint8Array;
444
+ case: "value";
445
+ } | {
446
+ /**
447
+ * @generated from field: bool erased = 2;
448
+ */
449
+ value: boolean;
450
+ case: "erased";
451
+ } | {
452
+ /**
453
+ * @generated from field: ankka.protocol.v1.Error error = 3;
454
+ */
455
+ value: Error;
456
+ case: "error";
457
+ } | {
458
+ case: undefined;
459
+ value?: undefined;
460
+ };
461
+ };
462
+ /**
463
+ * Describes the message ankka.protocol.v1.KeyringOpenReply.
464
+ * Use `create(KeyringOpenReplySchema)` to create a new message.
465
+ */
466
+ export declare const KeyringOpenReplySchema: GenMessage<KeyringOpenReply>;
@@ -14,7 +14,7 @@ import { file_ankka_protocol_v1_client } from "./client_pb.js";
14
14
  /**
15
15
  * Describes the file ankka/protocol/v1/wasm.proto.
16
16
  */
17
- export const file_ankka_protocol_v1_wasm = /*@__PURE__*/ fileDesc("ChxhbmtrYS9wcm90b2NvbC92MS93YXNtLnByb3RvEhFhbmtrYS5wcm90b2NvbC52MSJYCghXYXNtU3BlYxIlCgRzcGVjGAEgASgLMhcuYW5ra2EucHJvdG9jb2wudjEuU3BlYxIQCghzdGF0ZWZ1bBgCIAMoCRITCgthYmlfdmVyc2lvbhgDIAEoCSLfAgoNSGFuZGxlUmVxdWVzdBIlCgRraW5kGAEgASgOMhcuYW5ra2EucHJvdG9jb2wudjEuS2luZBIUCgxjb21wb25lbnRfaWQYAiABKAkSEQoJZW50aXR5X2lkGAMgASgJEi4KBXN0YXRlGAQgASgLMhouYW5ra2EucHJvdG9jb2wudjEuUGF5bG9hZEgBiAEBEkIKDWV2ZW50X3NvdXJjZWQYCiABKAsyKS5hbmtrYS5wcm90b2NvbC52MS5FdmVudFNvdXJjZWRJbi5Db21tYW5kSAASOgoJa2V5X3ZhbHVlGAsgASgLMiUuYW5ra2EucHJvdG9jb2wudjEuS2V5VmFsdWVJbi5Db21tYW5kSAASOQoId29ya2Zsb3cYDCABKAsyJS5hbmtrYS5wcm90b2NvbC52MS5Xb3JrZmxvd0luLkNvbW1hbmRIAEIJCgdjb21tYW5kQggKBl9zdGF0ZSLGAgoLSGFuZGxlUmVwbHkSQQoNZXZlbnRfc291cmNlZBgKIAEoCzIoLmFua2thLnByb3RvY29sLnYxLkV2ZW50U291cmNlZE91dC5SZXBseUgAEjkKCWtleV92YWx1ZRgLIAEoCzIkLmFua2thLnByb3RvY29sLnYxLktleVZhbHVlT3V0LlJlcGx5SAASOAoId29ya2Zsb3cYDCABKAsyJC5hbmtrYS5wcm90b2NvbC52MS5Xb3JrZmxvd091dC5SZXBseUgAEi4KBXN0YXRlGAIgASgLMhouYW5ra2EucHJvdG9jb2wudjEuUGF5bG9hZEgBiAEBEjAKB2ZhaWx1cmUYAyABKAsyGi5hbmtrYS5wcm90b2NvbC52MS5GYWlsdXJlSAKIAQFCBwoFcmVwbHlCCAoGX3N0YXRlQgoKCF9mYWlsdXJlIoICCgtGb2xkUmVxdWVzdBIUCgxjb21wb25lbnRfaWQYASABKAkSEQoJZW50aXR5X2lkGAIgASgJEi4KBXN0YXRlGAMgASgLMhouYW5ra2EucHJvdG9jb2wudjEuUGF5bG9hZEgAiAEBEikKBWV2ZW50GAQgASgLMhouYW5ra2EucHJvdG9jb2wudjEuUGF5bG9hZBIQCghzZXF1ZW5jZRgFIAEoAxIUCgxpbnN0YWxsYXRpb24YBiABKAkSEAoIbWlycm9yZWQYByABKAgSEwoLYXR0cmlidXRpb24YCCABKAkSFgoOZm9yd2FyZGVkX2Zyb20YCSABKAlCCAoGX3N0YXRlInQKCUZvbGRSZXBseRIpCgVzdGF0ZRgBIAEoCzIaLmFua2thLnByb3RvY29sLnYxLlBheWxvYWQSMAoHZmFpbHVyZRgCIAEoCzIaLmFua2thLnByb3RvY29sLnYxLkZhaWx1cmVIAIgBAUIKCghfZmFpbHVyZSKpAQoLU3RlcFJlcXVlc3QSFAoMY29tcG9uZW50X2lkGAEgASgJEhEKCWVudGl0eV9pZBgCIAEoCRIuCgVzdGF0ZRgDIAEoCzIaLmFua2thLnByb3RvY29sLnYxLlBheWxvYWRIAIgBARI3CghydW5fc3RlcBgEIAEoCzIlLmFua2thLnByb3RvY29sLnYxLldvcmtmbG93SW4uUnVuU3RlcEIICgZfc3RhdGUivAEKCVN0ZXBSZXBseRI3CgVyZXBseRgBIAEoCzIoLmFua2thLnByb3RvY29sLnYxLldvcmtmbG93T3V0LlN0ZXBSZXBseRIuCgVzdGF0ZRgCIAEoCzIaLmFua2thLnByb3RvY29sLnYxLlBheWxvYWRIAIgBARIwCgdmYWlsdXJlGAMgASgLMhouYW5ra2EucHJvdG9jb2wudjEuRmFpbHVyZUgBiAEBQggKBl9zdGF0ZUIKCghfZmFpbHVyZSI0CglQYXNzaXZhdGUSFAoMY29tcG9uZW50X2lkGAEgASgJEhEKCWVudGl0eV9pZBgCIAEoCSIdCg1Db25maWdSZXF1ZXN0EgwKBG5hbWUYASABKAkiKwoLQ29uZmlnUmVwbHkSEgoFdmFsdWUYASABKAlIAIgBAUIICgZfdmFsdWUiPgoMU3RyZWFtVG9rZW5zEi4KBnRva2VucxgBIAMoCzIeLmFua2thLnByb3RvY29sLnYxLlN0cmVhbVRva2VuYgZwcm90bzM", [file_ankka_protocol_v1_payload, file_ankka_protocol_v1_discovery, file_ankka_protocol_v1_event_sourced, file_ankka_protocol_v1_key_value, file_ankka_protocol_v1_workflow, file_ankka_protocol_v1_client]);
17
+ export const file_ankka_protocol_v1_wasm = /*@__PURE__*/ fileDesc("ChxhbmtrYS9wcm90b2NvbC92MS93YXNtLnByb3RvEhFhbmtrYS5wcm90b2NvbC52MSJYCghXYXNtU3BlYxIlCgRzcGVjGAEgASgLMhcuYW5ra2EucHJvdG9jb2wudjEuU3BlYxIQCghzdGF0ZWZ1bBgCIAMoCRITCgthYmlfdmVyc2lvbhgDIAEoCSLfAgoNSGFuZGxlUmVxdWVzdBIlCgRraW5kGAEgASgOMhcuYW5ra2EucHJvdG9jb2wudjEuS2luZBIUCgxjb21wb25lbnRfaWQYAiABKAkSEQoJZW50aXR5X2lkGAMgASgJEi4KBXN0YXRlGAQgASgLMhouYW5ra2EucHJvdG9jb2wudjEuUGF5bG9hZEgBiAEBEkIKDWV2ZW50X3NvdXJjZWQYCiABKAsyKS5hbmtrYS5wcm90b2NvbC52MS5FdmVudFNvdXJjZWRJbi5Db21tYW5kSAASOgoJa2V5X3ZhbHVlGAsgASgLMiUuYW5ra2EucHJvdG9jb2wudjEuS2V5VmFsdWVJbi5Db21tYW5kSAASOQoId29ya2Zsb3cYDCABKAsyJS5hbmtrYS5wcm90b2NvbC52MS5Xb3JrZmxvd0luLkNvbW1hbmRIAEIJCgdjb21tYW5kQggKBl9zdGF0ZSLGAgoLSGFuZGxlUmVwbHkSQQoNZXZlbnRfc291cmNlZBgKIAEoCzIoLmFua2thLnByb3RvY29sLnYxLkV2ZW50U291cmNlZE91dC5SZXBseUgAEjkKCWtleV92YWx1ZRgLIAEoCzIkLmFua2thLnByb3RvY29sLnYxLktleVZhbHVlT3V0LlJlcGx5SAASOAoId29ya2Zsb3cYDCABKAsyJC5hbmtrYS5wcm90b2NvbC52MS5Xb3JrZmxvd091dC5SZXBseUgAEi4KBXN0YXRlGAIgASgLMhouYW5ra2EucHJvdG9jb2wudjEuUGF5bG9hZEgBiAEBEjAKB2ZhaWx1cmUYAyABKAsyGi5hbmtrYS5wcm90b2NvbC52MS5GYWlsdXJlSAKIAQFCBwoFcmVwbHlCCAoGX3N0YXRlQgoKCF9mYWlsdXJlIoICCgtGb2xkUmVxdWVzdBIUCgxjb21wb25lbnRfaWQYASABKAkSEQoJZW50aXR5X2lkGAIgASgJEi4KBXN0YXRlGAMgASgLMhouYW5ra2EucHJvdG9jb2wudjEuUGF5bG9hZEgAiAEBEikKBWV2ZW50GAQgASgLMhouYW5ra2EucHJvdG9jb2wudjEuUGF5bG9hZBIQCghzZXF1ZW5jZRgFIAEoAxIUCgxpbnN0YWxsYXRpb24YBiABKAkSEAoIbWlycm9yZWQYByABKAgSEwoLYXR0cmlidXRpb24YCCABKAkSFgoOZm9yd2FyZGVkX2Zyb20YCSABKAlCCAoGX3N0YXRlInQKCUZvbGRSZXBseRIpCgVzdGF0ZRgBIAEoCzIaLmFua2thLnByb3RvY29sLnYxLlBheWxvYWQSMAoHZmFpbHVyZRgCIAEoCzIaLmFua2thLnByb3RvY29sLnYxLkZhaWx1cmVIAIgBAUIKCghfZmFpbHVyZSKpAQoLU3RlcFJlcXVlc3QSFAoMY29tcG9uZW50X2lkGAEgASgJEhEKCWVudGl0eV9pZBgCIAEoCRIuCgVzdGF0ZRgDIAEoCzIaLmFua2thLnByb3RvY29sLnYxLlBheWxvYWRIAIgBARI3CghydW5fc3RlcBgEIAEoCzIlLmFua2thLnByb3RvY29sLnYxLldvcmtmbG93SW4uUnVuU3RlcEIICgZfc3RhdGUivAEKCVN0ZXBSZXBseRI3CgVyZXBseRgBIAEoCzIoLmFua2thLnByb3RvY29sLnYxLldvcmtmbG93T3V0LlN0ZXBSZXBseRIuCgVzdGF0ZRgCIAEoCzIaLmFua2thLnByb3RvY29sLnYxLlBheWxvYWRIAIgBARIwCgdmYWlsdXJlGAMgASgLMhouYW5ra2EucHJvdG9jb2wudjEuRmFpbHVyZUgBiAEBQggKBl9zdGF0ZUIKCghfZmFpbHVyZSI0CglQYXNzaXZhdGUSFAoMY29tcG9uZW50X2lkGAEgASgJEhEKCWVudGl0eV9pZBgCIAEoCSIdCg1Db25maWdSZXF1ZXN0EgwKBG5hbWUYASABKAkiKwoLQ29uZmlnUmVwbHkSEgoFdmFsdWUYASABKAlIAIgBAUIICgZfdmFsdWUiPgoMU3RyZWFtVG9rZW5zEi4KBnRva2VucxgBIAMoCzIeLmFua2thLnByb3RvY29sLnYxLlN0cmVhbVRva2VuImcKEktleXJpbmdTZWFsUmVxdWVzdBIPCgdzdWJqZWN0GAEgASgJEhAKCG1hbmlmZXN0GAIgASgJEg0KBXZhbHVlGAMgASgMEg4KBmVyYXNlZBgEIAEoCBIPCgdwcm9qZWN0GAUgASgJIloKEEtleXJpbmdTZWFsUmVwbHkSEgoIZW52ZWxvcGUYASABKAxIABIpCgVlcnJvchgCIAEoCzIYLmFua2thLnByb3RvY29sLnYxLkVycm9ySABCBwoFcmVwbHkiOAoSS2V5cmluZ09wZW5SZXF1ZXN0EhAKCGVudmVsb3BlGAEgASgMEhAKCG1hbmlmZXN0GAIgASgJImkKEEtleXJpbmdPcGVuUmVwbHkSDwoFdmFsdWUYASABKAxIABIQCgZlcmFzZWQYAiABKAhIABIpCgVlcnJvchgDIAEoCzIYLmFua2thLnByb3RvY29sLnYxLkVycm9ySABCBwoFcmVwbHliBnByb3RvMw", [file_ankka_protocol_v1_payload, file_ankka_protocol_v1_discovery, file_ankka_protocol_v1_event_sourced, file_ankka_protocol_v1_key_value, file_ankka_protocol_v1_workflow, file_ankka_protocol_v1_client]);
18
18
  /**
19
19
  * Describes the message ankka.protocol.v1.WasmSpec.
20
20
  * Use `create(WasmSpecSchema)` to create a new message.
@@ -70,3 +70,23 @@ export const ConfigReplySchema = /*@__PURE__*/ messageDesc(file_ankka_protocol_v
70
70
  * Use `create(StreamTokensSchema)` to create a new message.
71
71
  */
72
72
  export const StreamTokensSchema = /*@__PURE__*/ messageDesc(file_ankka_protocol_v1_wasm, 10);
73
+ /**
74
+ * Describes the message ankka.protocol.v1.KeyringSealRequest.
75
+ * Use `create(KeyringSealRequestSchema)` to create a new message.
76
+ */
77
+ export const KeyringSealRequestSchema = /*@__PURE__*/ messageDesc(file_ankka_protocol_v1_wasm, 11);
78
+ /**
79
+ * Describes the message ankka.protocol.v1.KeyringSealReply.
80
+ * Use `create(KeyringSealReplySchema)` to create a new message.
81
+ */
82
+ export const KeyringSealReplySchema = /*@__PURE__*/ messageDesc(file_ankka_protocol_v1_wasm, 12);
83
+ /**
84
+ * Describes the message ankka.protocol.v1.KeyringOpenRequest.
85
+ * Use `create(KeyringOpenRequestSchema)` to create a new message.
86
+ */
87
+ export const KeyringOpenRequestSchema = /*@__PURE__*/ messageDesc(file_ankka_protocol_v1_wasm, 13);
88
+ /**
89
+ * Describes the message ankka.protocol.v1.KeyringOpenReply.
90
+ * Use `create(KeyringOpenReplySchema)` to create a new message.
91
+ */
92
+ export const KeyringOpenReplySchema = /*@__PURE__*/ messageDesc(file_ankka_protocol_v1_wasm, 14);
@@ -5,6 +5,7 @@ import { type Buckets } from "./storage.ts";
5
5
  import type { GuardrailRef, ToolRef } from "./handlers.ts";
6
6
  import type { Schema } from "./schema.ts";
7
7
  import { type Services } from "./services.ts";
8
+ import { type DataSubject } from "./personal.ts";
8
9
  type MaybePromise<T> = T | Promise<T>;
9
10
  export declare const COMPLETE_TASK = "complete_task";
10
11
  export declare const FAIL_TASK = "fail_task";
@@ -130,11 +131,18 @@ export interface Notification {
130
131
  export declare class Tasks {
131
132
  #private;
132
133
  constructor(client: ComponentClient);
133
- /** A dependency that does not exist is refused before anything is written; one that has already ended cancels the new task. */
134
+ /**
135
+ * A dependency that does not exist is refused before anything is written; one that has already ended
136
+ * cancels the new task. With `subject` (feature 042) the task's instructions, attachments, result and
137
+ * the conversation an agent has working on it are kept sealed under that data subject's key, and read
138
+ * as erased once it is erased; an instance made for the task alone takes it too. An id that breaks the
139
+ * data subject rule throws a `TypeError` before anything is sent.
140
+ */
134
141
  create(type: TaskType<any>, instructions: string, options?: {
135
142
  id?: string;
136
143
  attachments?: readonly Attachment[];
137
144
  dependsOn?: readonly string[];
145
+ subject?: DataSubject | string;
138
146
  }): Promise<string>;
139
147
  }
140
148
  /** Calls about one task. */
@@ -155,7 +163,9 @@ export declare class AutonomousAgentCalls {
155
163
  #private;
156
164
  readonly componentId: string;
157
165
  readonly instanceId: string | undefined;
158
- constructor(client: ComponentClient, componentId: string, instanceId: string | undefined);
166
+ /** The data subject the instance is started with, named by its first assignment (feature 042). */
167
+ readonly subject: DataSubject | undefined;
168
+ constructor(client: ComponentClient, componentId: string, instanceId: string | undefined, about?: DataSubject | string);
159
169
  /** Creates the task, starts an instance on it, and answers the task's id at once. */
160
170
  runSingleTask(type: TaskType<any>, instructions: string, options?: Parameters<Tasks["create"]>[2]): Promise<string>;
161
171
  assign(...taskIds: string[]): Promise<{
@@ -20,6 +20,7 @@ import { processStorage } from "./storage.js";
20
20
  import { decodeJsonValue, reviver } from "./json.js";
21
21
  import { toJsonSchema } from "./schema.js";
22
22
  import { servicesFor } from "./services.js";
23
+ import { subject } from "./personal.js";
23
24
  export const COMPLETE_TASK = "complete_task";
24
25
  export const FAIL_TASK = "fail_task";
25
26
  export const accepted = () => Object.freeze({ verdict: "accepted" });
@@ -110,8 +111,15 @@ export class Tasks {
110
111
  constructor(client) {
111
112
  this.#client = client;
112
113
  }
113
- /** A dependency that does not exist is refused before anything is written; one that has already ended cancels the new task. */
114
+ /**
115
+ * A dependency that does not exist is refused before anything is written; one that has already ended
116
+ * cancels the new task. With `subject` (feature 042) the task's instructions, attachments, result and
117
+ * the conversation an agent has working on it are kept sealed under that data subject's key, and read
118
+ * as erased once it is erased; an instance made for the task alone takes it too. An id that breaks the
119
+ * data subject rule throws a `TypeError` before anything is sent.
120
+ */
114
121
  async create(type, instructions, options = {}) {
122
+ const about = options.subject === undefined ? undefined : subject(options.subject);
115
123
  const id = options.id ?? crypto.randomUUID();
116
124
  const dependencies = [...new Set(options.dependsOn ?? [])];
117
125
  for (const dep of dependencies)
@@ -125,6 +133,7 @@ export class Tasks {
125
133
  content: a.uri !== undefined ? { type: "Reference", uri: a.uri } : { type: "Inline", text: a.content ?? "" },
126
134
  })),
127
135
  dependencies,
136
+ ...(about === undefined ? {} : { subject: about }),
128
137
  });
129
138
  for (const dep of dependencies) {
130
139
  const answer = (await this.#client._raw("event-sourced", TASK, dep, "add-dependent", { taskId: id }));
@@ -186,10 +195,13 @@ export class AutonomousAgentCalls {
186
195
  #client;
187
196
  componentId;
188
197
  instanceId;
189
- constructor(client, componentId, instanceId) {
198
+ /** The data subject the instance is started with, named by its first assignment (feature 042). */
199
+ subject;
200
+ constructor(client, componentId, instanceId, about) {
190
201
  this.#client = client;
191
202
  this.componentId = componentId;
192
203
  this.instanceId = instanceId;
204
+ this.subject = about === undefined ? undefined : subject(about);
193
205
  }
194
206
  #instance() {
195
207
  if (!this.instanceId)
@@ -203,7 +215,9 @@ export class AutonomousAgentCalls {
203
215
  return taskId;
204
216
  }
205
217
  assign(...taskIds) {
206
- return this.#client._raw("autonomous-agent", this.componentId, this.#instance(), "assign", { taskIds });
218
+ // The instance's data subject travels in the assignment, which is what its host reads.
219
+ const body = this.subject === undefined ? { taskIds } : { taskIds, subject: this.subject };
220
+ return this.#client._raw("autonomous-agent", this.componentId, this.#instance(), "assign", body);
207
221
  }
208
222
  async suspend() {
209
223
  await this.#client._raw("autonomous-agent", this.componentId, this.#instance(), "suspend");
package/dist/client.d.ts CHANGED
@@ -4,6 +4,7 @@ import { jsonCodec, type Shape } from "./codec.ts";
4
4
  import { CommandError, type Metadata } from "./effects/common.ts";
5
5
  import type { HandlerRef } from "./handlers.ts";
6
6
  import { type ComponentKind } from "./kinds.ts";
7
+ import { type DataSubject } from "./personal.ts";
7
8
  import { Duration } from "./time.ts";
8
9
  import { AutonomousAgentCalls, TaskCalls, Tasks } from "./autonomous.ts";
9
10
  import { type AgentOutcome, type DecisionInput } from "./approvals.ts";
@@ -74,6 +75,8 @@ export declare class AwaitingInvocation<I, S> {
74
75
  invoke(input?: I): Promise<S>;
75
76
  }
76
77
  /** Calls on one component instance, by wire name. */
78
+ /** The metadata key a call to an agent names its data subject under (feature 042). */
79
+ export declare const DATA_SUBJECT_KEY = "ankka-data-subject";
77
80
  export declare class Calls {
78
81
  #private;
79
82
  constructor(connection: Connection, metadata: Metadata, kind: ComponentKind, componentId: string, entityId: string, state?: Shape<unknown>);
@@ -261,15 +264,30 @@ export declare class ComponentClient {
261
264
  forEventSourcedEntity(componentId: string, entityId: string): Calls;
262
265
  forKeyValueEntity(componentId: string, entityId: string): Calls;
263
266
  forWorkflow(componentId: string, workflowId: string): Calls;
264
- forAgent(componentId: string, sessionId: string): Calls;
267
+ /**
268
+ * Calls to one session of an agent. A session started with `subject` (feature 042) keeps its
269
+ * conversation sealed under that data subject's key, and reads as erased once the subject is erased.
270
+ * The subject is fixed at the session's first call: a later call naming another is refused. An id that
271
+ * breaks the data subject rule throws a `TypeError` before anything is sent.
272
+ */
273
+ forAgent(componentId: string, sessionId: string, options?: {
274
+ subject?: DataSubject | string;
275
+ }): Calls;
265
276
  /** Creates tasks for autonomous agents. */
266
277
  get tasks(): Tasks;
267
278
  /** Calls about one task. */
268
279
  forTask(taskId: string): TaskCalls;
269
- /** One instance of an autonomous agent, by the id the caller chose; without one, only `runSingleTask`, on an instance the platform names. */
280
+ /**
281
+ * One instance of an autonomous agent, by the id the caller chose; without one, only `runSingleTask`,
282
+ * on an instance the platform names. An instance started with `subject` (feature 042), by its first
283
+ * assignment, keeps what it records of its work sealed under that data subject's key and is terminated
284
+ * once the subject is erased; a later call naming another data subject is refused.
285
+ */
270
286
  forAutonomousAgent(agent: {
271
287
  readonly componentId: string;
272
- } | string, instanceId?: string): AutonomousAgentCalls;
288
+ } | string, instanceId?: string, options?: {
289
+ subject?: DataSubject | string;
290
+ }): AutonomousAgentCalls;
273
291
  /** @internal A call with a JSON body and a JSON reply, as the platform's own components take them. */
274
292
  _raw(kind: ComponentKind, componentId: string, entityId: string, name: string, body?: unknown): Promise<unknown>;
275
293
  /** @internal A decision on an approval request; a refusal rejects with `CommandError`. */
package/dist/client.js CHANGED
@@ -11,7 +11,8 @@ import { CommandError } from "./effects/common.js";
11
11
  import { decodeJsonValue, reviver } from "./json.js";
12
12
  import { errorCodeFromProto, kindToProto } from "./kinds.js";
13
13
  import { metadataToProto } from "./context.js";
14
- import { encodePayload, decodePayload, EMPTY_PAYLOAD } from "./server/payloads.js";
14
+ import { encodePayload, decodePayload, EMPTY_PAYLOAD, prefetchPayload, prefetchValue } from "./server/payloads.js";
15
+ import { subject as checkedSubject, withinScope } from "./personal.js";
15
16
  import { Duration } from "./time.js";
16
17
  import { PROTOCOL_VERSION } from "./spec.js";
17
18
  import { AutonomousAgentCalls, TaskCalls, Tasks } from "./autonomous.js";
@@ -62,6 +63,12 @@ function decodeReply(shape, payload) {
62
63
  const codec = payload ? codecForManifest(payload.manifest) : undefined;
63
64
  return (codec ?? binaryCodecs.done).decode(payload?.data ?? new Uint8Array());
64
65
  }
66
+ /** Fetches the keys a reply's personal fields need before it is decoded (feature 042). */
67
+ async function prefetched(answer) {
68
+ if (answer.result.case === "reply")
69
+ await prefetchPayload(answer.result.value.payload);
70
+ return answer;
71
+ }
65
72
  function outcomeOf(reply, answer) {
66
73
  switch (answer.result.case) {
67
74
  case "reply":
@@ -153,7 +160,8 @@ export class Invocation {
153
160
  }
154
161
  /** Calls an agent's handler for its outcome: the model's answer, or the approval requests the turn waits on. */
155
162
  async ask(input) {
156
- return outcomeOf(this.#reply, await stubOf(this.#connection).invoke(this.#request(input)));
163
+ await prefetchValue(input);
164
+ return outcomeOf(this.#reply, await prefetched(await stubOf(this.#connection).invoke(this.#request(input))));
157
165
  }
158
166
  /**
159
167
  * Decides one of the session's approval requests; this invocation names the handler whose turn waits.
@@ -161,7 +169,7 @@ export class Invocation {
161
169
  * and this answers as `ask` would have. A request already decided is a conflict.
162
170
  */
163
171
  async decide(approvalId, decision) {
164
- return outcomeOf(this.#reply, await decideOn(this.#connection, this.#metadata, this.#kind, this.#componentId, this.#entityId, this.#name, approvalId, decision));
172
+ return outcomeOf(this.#reply, await prefetched(await decideOn(this.#connection, this.#metadata, this.#kind, this.#componentId, this.#entityId, this.#name, approvalId, decision)));
165
173
  }
166
174
  /** Invokes a streaming handler; yields tokens in order; a failure rejects with `CommandError`, a turn that waits with `ApprovalAwaited`. */
167
175
  async *stream(input) {
@@ -173,6 +181,7 @@ export class Invocation {
173
181
  }
174
182
  /** As `stream`, ending with one awaiting part when the turn waits for a person. */
175
183
  async *streamParts(input) {
184
+ await prefetchValue(input);
176
185
  for await (const token of stubOf(this.#connection).invokeStream(this.#request(input))) {
177
186
  switch (token.token.case) {
178
187
  case "text":
@@ -216,6 +225,12 @@ const awaitTooOld = (failure) => {
216
225
  throw failure;
217
226
  };
218
227
  /** Calls on one component instance, by wire name. */
228
+ /** The metadata key a call to an agent names its data subject under (feature 042). */
229
+ export const DATA_SUBJECT_KEY = "ankka-data-subject";
230
+ /** `metadata` naming `subject` under `ankka-data-subject`, or unchanged without one; a `TypeError` when it breaks the rule. */
231
+ function withSubject(metadata, subject) {
232
+ return subject === undefined ? metadata : { ...metadata, [DATA_SUBJECT_KEY]: checkedSubject(subject) };
233
+ }
219
234
  export class Calls {
220
235
  #connection;
221
236
  #metadata;
@@ -251,7 +266,7 @@ export class Calls {
251
266
  */
252
267
  async awaitEnd(timeoutMillis, state) {
253
268
  const shape = (state ?? this.#state);
254
- const answer = await stubOf(this.#connection).awaitEnd(this.#awaitRequest(timeoutMillis)).catch(awaitTooOld);
269
+ const answer = await prefetched(await stubOf(this.#connection).awaitEnd(this.#awaitRequest(timeoutMillis)).catch(awaitTooOld));
255
270
  const outcome = outcomeOf(shape, answer);
256
271
  if (outcome.kind !== "answered")
257
272
  throw new CommandError({ message: "a workflow answered a wait as an agent", code: "INTERNAL" });
@@ -270,6 +285,7 @@ export class Calls {
270
285
  yield { kind: "heartbeat" };
271
286
  break;
272
287
  case "ended":
288
+ await prefetchPayload(token.token.value);
273
289
  yield { kind: "ended", state: decodeReply(shape, token.token.value) };
274
290
  return;
275
291
  case "failed": {
@@ -412,7 +428,8 @@ export class Views {
412
428
  for await (const frame of frames) {
413
429
  switch (frame.frame.case) {
414
430
  case "row":
415
- yield { kind: "row", key: frame.frame.value.key, row: codec.decode(frame.frame.value.payload?.data ?? new Uint8Array()) };
431
+ await prefetchPayload(frame.frame.value.payload);
432
+ yield { kind: "row", key: frame.frame.value.key, row: decodePayload(codec, frame.frame.value.payload) };
416
433
  break;
417
434
  case "removed":
418
435
  yield { kind: "removed", key: frame.frame.value.key };
@@ -439,18 +456,21 @@ export class Views {
439
456
  throw failure;
440
457
  }
441
458
  }
442
- static #rows(answer, row) {
459
+ static async #rows(answer, row) {
443
460
  switch (answer.result.case) {
444
461
  case "rows": {
462
+ // A row's personal fields are envelopes under the row's manifest (feature 042).
463
+ await prefetchPayload(answer.result.value);
464
+ const manifest = codecFor(row).manifest;
445
465
  const text = new TextDecoder().decode(answer.result.value.data);
446
466
  const documents = JSON.parse(text, reviver);
447
467
  if (!Array.isArray(documents))
448
468
  throw new CommandError({ message: "the view answered something other than a JSON array", code: "INTERNAL" });
449
469
  if (isCodec(row)) {
450
470
  const utf8 = new TextEncoder();
451
- return documents.map((d) => row.decode(utf8.encode(JSON.stringify(d, (_k, v) => (typeof v === "bigint" ? JSON.rawJSON(v.toString()) : v)))));
471
+ return withinScope(manifest, () => documents.map((d) => row.decode(utf8.encode(JSON.stringify(d, (_k, v) => (typeof v === "bigint" ? JSON.rawJSON(v.toString()) : v))))));
452
472
  }
453
- return documents.map((d) => decodeJsonValue(row, d));
473
+ return withinScope(manifest, () => documents.map((d) => decodeJsonValue(row, d)));
454
474
  }
455
475
  case "error":
456
476
  throw new CommandError(errorOf(answer.result.value));
@@ -479,6 +499,7 @@ export class Timers {
479
499
  const t = "component" in target
480
500
  ? { kind: target.component.prototype._kind, componentId: target.component.componentId, name: target.handler.name, input: target.handler.input, entityId: target.entityId }
481
501
  : target;
502
+ await prefetchValue(input);
482
503
  await stubOf(this.#connection).schedule({
483
504
  timerId,
484
505
  delayMillis: BigInt(delay.toMillis()),
@@ -500,6 +521,7 @@ export class Timers {
500
521
  if (problem !== undefined)
501
522
  throw new CommandError({ message: problem, code: "BAD_REQUEST" });
502
523
  const t = "component" in target ? { componentId: target.component.componentId, name: target.handler.name, input: target.handler.input } : target;
524
+ await prefetchValue(input);
503
525
  const reply = await stubOf(this.#connection)
504
526
  .scheduleRecurring({
505
527
  timerId,
@@ -680,8 +702,14 @@ export class ComponentClient {
680
702
  forWorkflow(componentId, workflowId) {
681
703
  return new Calls(this.#connection, this.#metadata, "workflow", componentId, workflowId);
682
704
  }
683
- forAgent(componentId, sessionId) {
684
- return new Calls(this.#connection, this.#metadata, "agent", componentId, sessionId);
705
+ /**
706
+ * Calls to one session of an agent. A session started with `subject` (feature 042) keeps its
707
+ * conversation sealed under that data subject's key, and reads as erased once the subject is erased.
708
+ * The subject is fixed at the session's first call: a later call naming another is refused. An id that
709
+ * breaks the data subject rule throws a `TypeError` before anything is sent.
710
+ */
711
+ forAgent(componentId, sessionId, options = {}) {
712
+ return new Calls(this.#connection, withSubject(this.#metadata, options.subject), "agent", componentId, sessionId);
685
713
  }
686
714
  /** Creates tasks for autonomous agents. */
687
715
  get tasks() {
@@ -691,9 +719,14 @@ export class ComponentClient {
691
719
  forTask(taskId) {
692
720
  return new TaskCalls(this, taskId);
693
721
  }
694
- /** One instance of an autonomous agent, by the id the caller chose; without one, only `runSingleTask`, on an instance the platform names. */
695
- forAutonomousAgent(agent, instanceId) {
696
- return new AutonomousAgentCalls(this, typeof agent === "string" ? agent : agent.componentId, instanceId);
722
+ /**
723
+ * One instance of an autonomous agent, by the id the caller chose; without one, only `runSingleTask`,
724
+ * on an instance the platform names. An instance started with `subject` (feature 042), by its first
725
+ * assignment, keeps what it records of its work sealed under that data subject's key and is terminated
726
+ * once the subject is erased; a later call naming another data subject is refused.
727
+ */
728
+ forAutonomousAgent(agent, instanceId, options = {}) {
729
+ return new AutonomousAgentCalls(this, typeof agent === "string" ? agent : agent.componentId, instanceId, options.subject);
697
730
  }
698
731
  /** @internal A call with a JSON body and a JSON reply, as the platform's own components take them. */
699
732
  async _raw(kind, componentId, entityId, name, body) {
package/dist/codec.d.ts CHANGED
@@ -15,6 +15,8 @@ export type Shape<T> = Schema<T> | Codec<T>;
15
15
  export declare function isCodec<T>(shape: Shape<T>): shape is Codec<T>;
16
16
  /** The codec for a shape: the codec itself, or the schema's default. */
17
17
  export declare function codecFor<T>(shape: Shape<T>): Codec<T>;
18
+ /** @internal The schema a default JSON codec was derived from, if `codec` is one. */
19
+ export declare function schemaOf(codec: Codec<unknown>): Schema | undefined;
18
20
  /** The default JSON codec for a schema, under `manifest` (the schema's name when omitted). */
19
21
  export declare function jsonCodec<T>(schema: Schema<T>, manifest?: string): Codec<T>;
20
22
  /** The `text/plain` codecs for top-level primitives. */
package/dist/codec.js CHANGED
@@ -24,16 +24,23 @@ function text(bytes) {
24
24
  function frozen(codec) {
25
25
  return Object.freeze(codec);
26
26
  }
27
+ const schemaOfCodec = new WeakMap();
28
+ /** @internal The schema a default JSON codec was derived from, if `codec` is one. */
29
+ export function schemaOf(codec) {
30
+ return schemaOfCodec.get(codec);
31
+ }
27
32
  /** The default JSON codec for a schema, under `manifest` (the schema's name when omitted). */
28
33
  export function jsonCodec(schema, manifest = defaultManifest(schema)) {
29
34
  if (typeof manifest !== "string" || manifest.trim() === "")
30
35
  throw new TypeError(`jsonCodec(${describe(schema)}): a manifest is required`);
31
- return frozen({
36
+ const codec = frozen({
32
37
  manifest,
33
38
  contentType: JSON_CONTENT,
34
39
  encode: (value) => utf8.encode(writeJson(schema, value)),
35
40
  decode: (bytes) => readJson(schema, text(bytes)),
36
41
  });
42
+ schemaOfCodec.set(codec, schema);
43
+ return codec;
37
44
  }
38
45
  function textCodec(manifest, parse, render) {
39
46
  return frozen({
@@ -6,6 +6,7 @@ import { type ComponentClient, type ComponentRef, type Secrets } from "./client.
6
6
  import { type Buckets } from "./storage.ts";
7
7
  import { ConsumerEffects, type ConsumerEffect } from "./effects/stateless.ts";
8
8
  import { type Services } from "./services.ts";
9
+ import { type Erasures } from "./erasures.ts";
9
10
  import type { Standing } from "./standing.ts";
10
11
  type MaybePromise<T> = T | Promise<T>;
11
12
  /** The metadata entry a runtime sets on a consumer's request to say what it speaks: its protocol version. */
@@ -49,6 +50,10 @@ export declare abstract class Consumer<M, Out = never> {
49
50
  get services(): Services;
50
51
  /** A unit test's in place of the runtime's: `component.services = new ScriptedServices()`. */
51
52
  set services(services: Services);
53
+ /** Asks for erasure requests as this service (1.23), which needs the project's `erasure` grant. */
54
+ get erasures(): Erasures;
55
+ /** A unit test's in place of the runtime's: `component.erasures = new Erasures(client)`. */
56
+ set erasures(erasures: Erasures);
52
57
  /** @internal */
53
58
  get _kind(): "consumer";
54
59
  abstract onMessage(message: M): MaybePromise<ConsumerEffect<Out>>;