@enbox/dwn-sdk-js 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -301
- package/dist/bundles/dwn.js +19 -21
- package/dist/esm/generated/precompiled-validators.js +2764 -1773
- package/dist/esm/generated/precompiled-validators.js.map +1 -1
- package/dist/esm/src/core/dwn-error.js +27 -3
- package/dist/esm/src/core/dwn-error.js.map +1 -1
- package/dist/esm/src/core/message.js.map +1 -1
- package/dist/esm/src/core/messages-grant-authorization.js +17 -6
- package/dist/esm/src/core/messages-grant-authorization.js.map +1 -1
- package/dist/esm/src/core/protocol-authorization.js +245 -69
- package/dist/esm/src/core/protocol-authorization.js.map +1 -1
- package/dist/esm/src/core/resumable-task-manager.js +4 -4
- package/dist/esm/src/core/resumable-task-manager.js.map +1 -1
- package/dist/esm/src/dwn.js +10 -8
- package/dist/esm/src/dwn.js.map +1 -1
- package/dist/esm/src/enums/dwn-interface-method.js +4 -2
- package/dist/esm/src/enums/dwn-interface-method.js.map +1 -1
- package/dist/esm/src/event-stream/event-emitter-stream.js.map +1 -0
- package/dist/esm/src/handlers/messages-subscribe.js +1 -1
- package/dist/esm/src/handlers/messages-subscribe.js.map +1 -1
- package/dist/esm/src/handlers/messages-sync.js +116 -0
- package/dist/esm/src/handlers/messages-sync.js.map +1 -0
- package/dist/esm/src/handlers/protocols-configure.js +149 -16
- package/dist/esm/src/handlers/protocols-configure.js.map +1 -1
- package/dist/esm/src/handlers/protocols-query.js +2 -2
- package/dist/esm/src/handlers/protocols-query.js.map +1 -1
- package/dist/esm/src/handlers/records-count.js +143 -0
- package/dist/esm/src/handlers/records-count.js.map +1 -0
- package/dist/esm/src/handlers/records-query.js +4 -0
- package/dist/esm/src/handlers/records-query.js.map +1 -1
- package/dist/esm/src/handlers/records-read.js +4 -6
- package/dist/esm/src/handlers/records-read.js.map +1 -1
- package/dist/esm/src/handlers/records-write.js +17 -18
- package/dist/esm/src/handlers/records-write.js.map +1 -1
- package/dist/esm/src/index.js +9 -5
- package/dist/esm/src/index.js.map +1 -1
- package/dist/esm/src/interfaces/messages-read.js +2 -7
- package/dist/esm/src/interfaces/messages-read.js.map +1 -1
- package/dist/esm/src/interfaces/messages-subscribe.js +1 -0
- package/dist/esm/src/interfaces/messages-subscribe.js.map +1 -1
- package/dist/esm/src/interfaces/{messages-query.js → messages-sync.js} +11 -12
- package/dist/esm/src/interfaces/messages-sync.js.map +1 -0
- package/dist/esm/src/interfaces/protocols-configure.js +153 -30
- package/dist/esm/src/interfaces/protocols-configure.js.map +1 -1
- package/dist/esm/src/interfaces/protocols-query.js +1 -0
- package/dist/esm/src/interfaces/protocols-query.js.map +1 -1
- package/dist/esm/src/interfaces/records-count.js +91 -0
- package/dist/esm/src/interfaces/records-count.js.map +1 -0
- package/dist/esm/src/interfaces/records-read.js +15 -1
- package/dist/esm/src/interfaces/records-read.js.map +1 -1
- package/dist/esm/src/interfaces/records-write.js +64 -15
- package/dist/esm/src/interfaces/records-write.js.map +1 -1
- package/dist/esm/src/jose/algorithms/signing/ed25519.js.map +1 -1
- package/dist/esm/src/jose/algorithms/signing/signature-algorithms.js.map +1 -1
- package/dist/esm/src/jose/jws/general/builder.js.map +1 -1
- package/dist/esm/src/jose/jws/general/verifier.js.map +1 -1
- package/dist/esm/src/protocols/permission-grant.js +30 -0
- package/dist/esm/src/protocols/permission-grant.js.map +1 -1
- package/dist/esm/src/protocols/permission-request.js +24 -0
- package/dist/esm/src/protocols/permission-request.js.map +1 -1
- package/dist/esm/src/protocols/permissions.js +1 -1
- package/dist/esm/src/protocols/permissions.js.map +1 -1
- package/dist/esm/src/schema-validator.js +0 -1
- package/dist/esm/src/schema-validator.js.map +1 -1
- package/dist/esm/src/smt/smt-store-level.js +125 -0
- package/dist/esm/src/smt/smt-store-level.js.map +1 -0
- package/dist/esm/src/smt/smt-store-memory.js +67 -0
- package/dist/esm/src/smt/smt-store-memory.js.map +1 -0
- package/dist/esm/src/smt/smt-utils.js +146 -0
- package/dist/esm/src/smt/smt-utils.js.map +1 -0
- package/dist/esm/src/smt/sparse-merkle-tree.js +622 -0
- package/dist/esm/src/smt/sparse-merkle-tree.js.map +1 -0
- package/dist/esm/src/state-index/state-index-level.js +228 -0
- package/dist/esm/src/state-index/state-index-level.js.map +1 -0
- package/dist/esm/src/store/data-store-level.js +6 -6
- package/dist/esm/src/store/data-store-level.js.map +1 -1
- package/dist/esm/src/store/index-level.js +375 -17
- package/dist/esm/src/store/index-level.js.map +1 -1
- package/dist/esm/src/store/message-store-level.js +56 -0
- package/dist/esm/src/store/message-store-level.js.map +1 -1
- package/dist/esm/src/store/storage-controller.js +19 -16
- package/dist/esm/src/store/storage-controller.js.map +1 -1
- package/dist/esm/src/types/encryption-types.js +2 -0
- package/dist/esm/src/types/encryption-types.js.map +1 -0
- package/dist/esm/src/types/message-types.js.map +1 -1
- package/dist/esm/src/types/protocols-types.js +0 -2
- package/dist/esm/src/types/protocols-types.js.map +1 -1
- package/dist/esm/src/types/records-types.js +2 -0
- package/dist/esm/src/types/records-types.js.map +1 -1
- package/dist/esm/src/types/smt-types.js +5 -0
- package/dist/esm/src/types/smt-types.js.map +1 -0
- package/dist/esm/src/types/state-index.js +2 -0
- package/dist/esm/src/types/state-index.js.map +1 -0
- package/dist/esm/src/utils/cid.js +2 -1
- package/dist/esm/src/utils/cid.js.map +1 -1
- package/dist/esm/src/utils/data-stream.js +84 -29
- package/dist/esm/src/utils/data-stream.js.map +1 -1
- package/dist/esm/src/utils/encryption.js +22 -31
- package/dist/esm/src/utils/encryption.js.map +1 -1
- package/dist/esm/src/utils/hd-key.js +3 -3
- package/dist/esm/src/utils/hd-key.js.map +1 -1
- package/dist/esm/src/utils/jws.js +4 -4
- package/dist/esm/src/utils/jws.js.map +1 -1
- package/dist/esm/src/utils/private-key-signer.js +4 -3
- package/dist/esm/src/utils/private-key-signer.js.map +1 -1
- package/dist/esm/src/utils/protocols.js +82 -9
- package/dist/esm/src/utils/protocols.js.map +1 -1
- package/dist/esm/src/utils/records.js +82 -26
- package/dist/esm/src/utils/records.js.map +1 -1
- package/dist/esm/src/utils/secp256k1.js +4 -3
- package/dist/esm/src/utils/secp256k1.js.map +1 -1
- package/dist/esm/src/utils/secp256r1.js +3 -2
- package/dist/esm/src/utils/secp256r1.js.map +1 -1
- package/dist/esm/src/utils/time.js +1 -1
- package/dist/esm/src/utils/url.js +1 -1
- package/dist/esm/src/utils/url.js.map +1 -1
- package/dist/esm/tests/core/auth.spec.js +2 -2
- package/dist/esm/tests/core/auth.spec.js.map +1 -1
- package/dist/esm/tests/core/message-reply.spec.js +3 -3
- package/dist/esm/tests/core/message-reply.spec.js.map +1 -1
- package/dist/esm/tests/core/message.spec.js +13 -13
- package/dist/esm/tests/core/message.spec.js.map +1 -1
- package/dist/esm/tests/core/protocol-authorization.spec.js +3 -3
- package/dist/esm/tests/core/protocol-authorization.spec.js.map +1 -1
- package/dist/esm/tests/dwn.spec.js +27 -37
- package/dist/esm/tests/dwn.spec.js.map +1 -1
- package/dist/esm/tests/{event-log → event-stream}/event-emitter-stream.spec.js +14 -15
- package/dist/esm/tests/event-stream/event-emitter-stream.spec.js.map +1 -0
- package/dist/esm/tests/{event-log → event-stream}/event-stream.spec.js +13 -15
- package/dist/esm/tests/event-stream/event-stream.spec.js.map +1 -0
- package/dist/esm/tests/features/author-delegated-grant.spec.js +281 -135
- package/dist/esm/tests/features/author-delegated-grant.spec.js.map +1 -1
- package/dist/esm/tests/features/owner-delegated-grant.spec.js +57 -59
- package/dist/esm/tests/features/owner-delegated-grant.spec.js.map +1 -1
- package/dist/esm/tests/features/owner-signature.spec.js +32 -34
- package/dist/esm/tests/features/owner-signature.spec.js.map +1 -1
- package/dist/esm/tests/features/permissions.spec.js +73 -95
- package/dist/esm/tests/features/permissions.spec.js.map +1 -1
- package/dist/esm/tests/features/protocol-composition.spec.js +1645 -0
- package/dist/esm/tests/features/protocol-composition.spec.js.map +1 -0
- package/dist/esm/tests/features/protocol-create-action.spec.js +25 -27
- package/dist/esm/tests/features/protocol-create-action.spec.js.map +1 -1
- package/dist/esm/tests/features/protocol-delete-action.spec.js +42 -44
- package/dist/esm/tests/features/protocol-delete-action.spec.js.map +1 -1
- package/dist/esm/tests/features/protocol-update-action.spec.js +53 -55
- package/dist/esm/tests/features/protocol-update-action.spec.js.map +1 -1
- package/dist/esm/tests/features/records-prune.spec.js +126 -100
- package/dist/esm/tests/features/records-prune.spec.js.map +1 -1
- package/dist/esm/tests/features/records-tags.spec.js +272 -272
- package/dist/esm/tests/features/records-tags.spec.js.map +1 -1
- package/dist/esm/tests/features/resumable-tasks.spec.js +35 -37
- package/dist/esm/tests/features/resumable-tasks.spec.js.map +1 -1
- package/dist/esm/tests/handlers/messages-read.spec.js +112 -112
- package/dist/esm/tests/handlers/messages-read.spec.js.map +1 -1
- package/dist/esm/tests/handlers/messages-subscribe.spec.js +78 -76
- package/dist/esm/tests/handlers/messages-subscribe.spec.js.map +1 -1
- package/dist/esm/tests/handlers/messages-sync.spec.js +528 -0
- package/dist/esm/tests/handlers/messages-sync.spec.js.map +1 -0
- package/dist/esm/tests/handlers/protocols-configure.spec.js +545 -152
- package/dist/esm/tests/handlers/protocols-configure.spec.js.map +1 -1
- package/dist/esm/tests/handlers/protocols-query.spec.js +70 -72
- package/dist/esm/tests/handlers/protocols-query.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-count.spec.js +313 -0
- package/dist/esm/tests/handlers/records-count.spec.js.map +1 -0
- package/dist/esm/tests/handlers/records-delete.spec.js +106 -109
- package/dist/esm/tests/handlers/records-delete.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-query.spec.js +863 -463
- package/dist/esm/tests/handlers/records-query.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-read.spec.js +439 -209
- package/dist/esm/tests/handlers/records-read.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-subscribe.spec.js +292 -97
- package/dist/esm/tests/handlers/records-subscribe.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-write.spec.js +481 -483
- package/dist/esm/tests/handlers/records-write.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/messages-get.spec.js +31 -11
- package/dist/esm/tests/interfaces/messages-get.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/messages-subscribe.spec.js +5 -5
- package/dist/esm/tests/interfaces/messages-subscribe.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/protocols-configure.spec.js +64 -134
- package/dist/esm/tests/interfaces/protocols-configure.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/protocols-query.spec.js +4 -6
- package/dist/esm/tests/interfaces/protocols-query.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/records-delete.spec.js +3 -5
- package/dist/esm/tests/interfaces/records-delete.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/records-query.spec.js +9 -11
- package/dist/esm/tests/interfaces/records-query.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/records-read.spec.js +76 -7
- package/dist/esm/tests/interfaces/records-read.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/records-subscribe.spec.js +7 -9
- package/dist/esm/tests/interfaces/records-subscribe.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/records-write.spec.js +244 -48
- package/dist/esm/tests/interfaces/records-write.spec.js.map +1 -1
- package/dist/esm/tests/jose/jws/general.spec.js +15 -18
- package/dist/esm/tests/jose/jws/general.spec.js.map +1 -1
- package/dist/esm/tests/protocols/permission-grant.spec.js +114 -0
- package/dist/esm/tests/protocols/permission-grant.spec.js.map +1 -0
- package/dist/esm/tests/protocols/permission-request.spec.js +43 -7
- package/dist/esm/tests/protocols/permission-request.spec.js.map +1 -1
- package/dist/esm/tests/protocols/permissions.spec.js +9 -11
- package/dist/esm/tests/protocols/permissions.spec.js.map +1 -1
- package/dist/esm/tests/scenarios/aggregator.spec.js +90 -92
- package/dist/esm/tests/scenarios/aggregator.spec.js.map +1 -1
- package/dist/esm/tests/scenarios/deleted-record.spec.js +17 -19
- package/dist/esm/tests/scenarios/deleted-record.spec.js.map +1 -1
- package/dist/esm/tests/scenarios/end-to-end-tests.spec.js +27 -29
- package/dist/esm/tests/scenarios/end-to-end-tests.spec.js.map +1 -1
- package/dist/esm/tests/scenarios/nested-roles.spec.js +37 -39
- package/dist/esm/tests/scenarios/nested-roles.spec.js.map +1 -1
- package/dist/esm/tests/scenarios/subscriptions.spec.js +163 -163
- package/dist/esm/tests/scenarios/subscriptions.spec.js.map +1 -1
- package/dist/esm/tests/smt/smt-store-level.spec.js +143 -0
- package/dist/esm/tests/smt/smt-store-level.spec.js.map +1 -0
- package/dist/esm/tests/smt/sparse-merkle-tree.spec.js +741 -0
- package/dist/esm/tests/smt/sparse-merkle-tree.spec.js.map +1 -0
- package/dist/esm/tests/state-index/state-index-level.spec.js +254 -0
- package/dist/esm/tests/state-index/state-index-level.spec.js.map +1 -0
- package/dist/esm/tests/store/blockstore-level.spec.js +136 -0
- package/dist/esm/tests/store/blockstore-level.spec.js.map +1 -0
- package/dist/esm/tests/store/blockstore-mock.spec.js +29 -28
- package/dist/esm/tests/store/blockstore-mock.spec.js.map +1 -1
- package/dist/esm/tests/store/data-store-level.spec.js +23 -25
- package/dist/esm/tests/store/data-store-level.spec.js.map +1 -1
- package/dist/esm/tests/store/index-level.spec.js +544 -194
- package/dist/esm/tests/store/index-level.spec.js.map +1 -1
- package/dist/esm/tests/store/message-store-level.spec.js +4 -4
- package/dist/esm/tests/store/message-store-level.spec.js.map +1 -1
- package/dist/esm/tests/store/message-store.spec.js +147 -73
- package/dist/esm/tests/store/message-store.spec.js.map +1 -1
- package/dist/esm/tests/store-dependent-tests.spec.js +1 -0
- package/dist/esm/tests/store-dependent-tests.spec.js.map +1 -1
- package/dist/esm/tests/test-stores.js +5 -5
- package/dist/esm/tests/test-stores.js.map +1 -1
- package/dist/esm/tests/test-suite.js +9 -8
- package/dist/esm/tests/test-suite.js.map +1 -1
- package/dist/esm/tests/utils/cid.spec.js +8 -11
- package/dist/esm/tests/utils/cid.spec.js.map +1 -1
- package/dist/esm/tests/utils/data-stream.spec.js +167 -13
- package/dist/esm/tests/utils/data-stream.spec.js.map +1 -1
- package/dist/esm/tests/utils/encryption-callbacks.spec.js +233 -0
- package/dist/esm/tests/utils/encryption-callbacks.spec.js.map +1 -0
- package/dist/esm/tests/utils/encryption.spec.js +34 -85
- package/dist/esm/tests/utils/encryption.spec.js.map +1 -1
- package/dist/esm/tests/utils/filters.spec.js +67 -69
- package/dist/esm/tests/utils/filters.spec.js.map +1 -1
- package/dist/esm/tests/utils/hd-key.spec.js +3 -3
- package/dist/esm/tests/utils/hd-key.spec.js.map +1 -1
- package/dist/esm/tests/utils/jws.spec.js +54 -3
- package/dist/esm/tests/utils/jws.spec.js.map +1 -1
- package/dist/esm/tests/utils/memory-cache.spec.js +6 -9
- package/dist/esm/tests/utils/memory-cache.spec.js.map +1 -1
- package/dist/esm/tests/utils/messages.spec.js +63 -29
- package/dist/esm/tests/utils/messages.spec.js.map +1 -1
- package/dist/esm/tests/utils/object.spec.js +3 -3
- package/dist/esm/tests/utils/object.spec.js.map +1 -1
- package/dist/esm/tests/utils/poller.js +1 -1
- package/dist/esm/tests/utils/poller.js.map +1 -1
- package/dist/esm/tests/utils/private-key-signer.spec.js +6 -6
- package/dist/esm/tests/utils/private-key-signer.spec.js.map +1 -1
- package/dist/esm/tests/utils/records.spec.js +37 -5
- package/dist/esm/tests/utils/records.spec.js.map +1 -1
- package/dist/esm/tests/utils/secp256k1.spec.js +7 -7
- package/dist/esm/tests/utils/secp256k1.spec.js.map +1 -1
- package/dist/esm/tests/utils/secp256r1.spec.js +7 -7
- package/dist/esm/tests/utils/secp256r1.spec.js.map +1 -1
- package/dist/esm/tests/utils/test-data-generator.js +47 -28
- package/dist/esm/tests/utils/test-data-generator.js.map +1 -1
- package/dist/esm/tests/utils/time.spec.js +7 -7
- package/dist/esm/tests/utils/time.spec.js.map +1 -1
- package/dist/esm/tests/utils/url.spec.js +25 -27
- package/dist/esm/tests/utils/url.spec.js.map +1 -1
- package/dist/esm/tests/validation/json-schemas/definitions.spec.js +4 -4
- package/dist/esm/tests/validation/json-schemas/definitions.spec.js.map +1 -1
- package/dist/esm/tests/validation/json-schemas/jwk/general-jwk.spec.js +15 -3
- package/dist/esm/tests/validation/json-schemas/jwk/general-jwk.spec.js.map +1 -1
- package/dist/esm/tests/validation/json-schemas/jwk/public-jwk.spec.js +8 -8
- package/dist/esm/tests/validation/json-schemas/jwk/public-jwk.spec.js.map +1 -1
- package/dist/esm/tests/validation/json-schemas/jwk-verification-method.spec.js +8 -18
- package/dist/esm/tests/validation/json-schemas/jwk-verification-method.spec.js.map +1 -1
- package/dist/esm/tests/validation/json-schemas/protocols/protocols-configure.spec.js +3 -3
- package/dist/esm/tests/validation/json-schemas/protocols/protocols-configure.spec.js.map +1 -1
- package/dist/esm/tests/validation/json-schemas/records/records-query.spec.js +9 -9
- package/dist/esm/tests/validation/json-schemas/records/records-query.spec.js.map +1 -1
- package/dist/esm/tests/validation/json-schemas/records/records-read.spec.js +106 -0
- package/dist/esm/tests/validation/json-schemas/records/records-read.spec.js.map +1 -0
- package/dist/esm/tests/validation/json-schemas/records/records-write.spec.js +18 -18
- package/dist/esm/tests/validation/json-schemas/records/records-write.spec.js.map +1 -1
- package/dist/esm/tests/vectors/protocol-definitions/email.json +1 -1
- package/dist/esm/tests/vectors/protocol-definitions/friend-role.json +2 -4
- package/dist/esm/tests/vectors/protocol-definitions/slack.json +2 -6
- package/dist/esm/tests/vectors/protocol-definitions/thread-role.json +2 -6
- package/dist/types/generated/precompiled-validators.d.ts +82 -64
- package/dist/types/generated/precompiled-validators.d.ts.map +1 -1
- package/dist/types/src/core/dwn-error.d.ts +27 -3
- package/dist/types/src/core/dwn-error.d.ts.map +1 -1
- package/dist/types/src/core/message-reply.d.ts +1 -1
- package/dist/types/src/core/message.d.ts +3 -3
- package/dist/types/src/core/message.d.ts.map +1 -1
- package/dist/types/src/core/messages-grant-authorization.d.ts +4 -4
- package/dist/types/src/core/messages-grant-authorization.d.ts.map +1 -1
- package/dist/types/src/core/protocol-authorization.d.ts +43 -2
- package/dist/types/src/core/protocol-authorization.d.ts.map +1 -1
- package/dist/types/src/core/records-grant-authorization.d.ts +2 -2
- package/dist/types/src/core/records-grant-authorization.d.ts.map +1 -1
- package/dist/types/src/core/resumable-task-manager.d.ts +1 -0
- package/dist/types/src/core/resumable-task-manager.d.ts.map +1 -1
- package/dist/types/src/dwn.d.ts +8 -8
- package/dist/types/src/dwn.d.ts.map +1 -1
- package/dist/types/src/enums/dwn-interface-method.d.ts +5 -3
- package/dist/types/src/enums/dwn-interface-method.d.ts.map +1 -1
- package/dist/types/src/event-stream/event-emitter-stream.d.ts.map +1 -0
- package/dist/types/src/handlers/messages-sync.d.ts +21 -0
- package/dist/types/src/handlers/messages-sync.d.ts.map +1 -0
- package/dist/types/src/handlers/protocols-configure.d.ts +24 -4
- package/dist/types/src/handlers/protocols-configure.d.ts.map +1 -1
- package/dist/types/src/handlers/protocols-query.d.ts.map +1 -1
- package/dist/types/src/handlers/records-count.d.ts +43 -0
- package/dist/types/src/handlers/records-count.d.ts.map +1 -0
- package/dist/types/src/handlers/records-query.d.ts.map +1 -1
- package/dist/types/src/handlers/records-read.d.ts.map +1 -1
- package/dist/types/src/handlers/records-write.d.ts +5 -5
- package/dist/types/src/handlers/records-write.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +72 -37
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/interfaces/messages-read.d.ts +2 -2
- package/dist/types/src/interfaces/messages-read.d.ts.map +1 -1
- package/dist/types/src/interfaces/messages-subscribe.d.ts +2 -2
- package/dist/types/src/interfaces/messages-subscribe.d.ts.map +1 -1
- package/dist/types/src/interfaces/messages-sync.d.ts +16 -0
- package/dist/types/src/interfaces/messages-sync.d.ts.map +1 -0
- package/dist/types/src/interfaces/protocols-configure.d.ts +22 -2
- package/dist/types/src/interfaces/protocols-configure.d.ts.map +1 -1
- package/dist/types/src/interfaces/protocols-query.d.ts +2 -2
- package/dist/types/src/interfaces/protocols-query.d.ts.map +1 -1
- package/dist/types/src/interfaces/records-count.d.ts +27 -0
- package/dist/types/src/interfaces/records-count.d.ts.map +1 -0
- package/dist/types/src/interfaces/records-delete.d.ts +2 -2
- package/dist/types/src/interfaces/records-delete.d.ts.map +1 -1
- package/dist/types/src/interfaces/records-query.d.ts +2 -2
- package/dist/types/src/interfaces/records-query.d.ts.map +1 -1
- package/dist/types/src/interfaces/records-read.d.ts +4 -2
- package/dist/types/src/interfaces/records-read.d.ts.map +1 -1
- package/dist/types/src/interfaces/records-subscribe.d.ts +2 -2
- package/dist/types/src/interfaces/records-subscribe.d.ts.map +1 -1
- package/dist/types/src/interfaces/records-write.d.ts +37 -15
- package/dist/types/src/interfaces/records-write.d.ts.map +1 -1
- package/dist/types/src/jose/algorithms/signing/ed25519.d.ts.map +1 -1
- package/dist/types/src/jose/algorithms/signing/signature-algorithms.d.ts +5 -1
- package/dist/types/src/jose/algorithms/signing/signature-algorithms.d.ts.map +1 -1
- package/dist/types/src/jose/jws/general/builder.d.ts +3 -3
- package/dist/types/src/jose/jws/general/builder.d.ts.map +1 -1
- package/dist/types/src/protocols/permission-grant.d.ts +11 -0
- package/dist/types/src/protocols/permission-grant.d.ts.map +1 -1
- package/dist/types/src/protocols/permission-request.d.ts +11 -0
- package/dist/types/src/protocols/permission-request.d.ts.map +1 -1
- package/dist/types/src/protocols/permissions.d.ts +4 -4
- package/dist/types/src/protocols/permissions.d.ts.map +1 -1
- package/dist/types/src/schema-validator.d.ts +1 -1
- package/dist/types/src/schema-validator.d.ts.map +1 -1
- package/dist/types/src/smt/smt-store-level.d.ts +32 -0
- package/dist/types/src/smt/smt-store-level.d.ts.map +1 -0
- package/dist/types/src/smt/smt-store-memory.d.ts +22 -0
- package/dist/types/src/smt/smt-store-memory.d.ts.map +1 -0
- package/dist/types/src/smt/smt-utils.d.ts +58 -0
- package/dist/types/src/smt/smt-utils.d.ts.map +1 -0
- package/dist/types/src/smt/sparse-merkle-tree.d.ts +124 -0
- package/dist/types/src/smt/sparse-merkle-tree.d.ts.map +1 -0
- package/dist/types/src/state-index/state-index-level.d.ts +83 -0
- package/dist/types/src/state-index/state-index-level.d.ts.map +1 -0
- package/dist/types/src/store/data-store-level.d.ts +1 -2
- package/dist/types/src/store/data-store-level.d.ts.map +1 -1
- package/dist/types/src/store/index-level.d.ts +98 -2
- package/dist/types/src/store/index-level.d.ts.map +1 -1
- package/dist/types/src/store/level-wrapper.d.ts.map +1 -1
- package/dist/types/src/store/message-store-level.d.ts +5 -0
- package/dist/types/src/store/message-store-level.d.ts.map +1 -1
- package/dist/types/src/store/storage-controller.d.ts +7 -7
- package/dist/types/src/store/storage-controller.d.ts.map +1 -1
- package/dist/types/src/types/data-store.d.ts +2 -3
- package/dist/types/src/types/data-store.d.ts.map +1 -1
- package/dist/types/src/types/encryption-types.d.ts +48 -0
- package/dist/types/src/types/encryption-types.d.ts.map +1 -0
- package/dist/types/src/types/jose-types.d.ts +9 -40
- package/dist/types/src/types/jose-types.d.ts.map +1 -1
- package/dist/types/src/types/message-store.d.ts +5 -0
- package/dist/types/src/types/message-store.d.ts.map +1 -1
- package/dist/types/src/types/message-types.d.ts +19 -0
- package/dist/types/src/types/message-types.d.ts.map +1 -1
- package/dist/types/src/types/messages-types.d.ts +16 -11
- package/dist/types/src/types/messages-types.d.ts.map +1 -1
- package/dist/types/src/types/method-handler.d.ts +1 -2
- package/dist/types/src/types/method-handler.d.ts.map +1 -1
- package/dist/types/src/types/permission-types.d.ts +2 -2
- package/dist/types/src/types/permission-types.d.ts.map +1 -1
- package/dist/types/src/types/protocols-types.d.ts +49 -5
- package/dist/types/src/types/protocols-types.d.ts.map +1 -1
- package/dist/types/src/types/records-types.d.ts +23 -7
- package/dist/types/src/types/records-types.d.ts.map +1 -1
- package/dist/types/src/types/signer.d.ts +1 -1
- package/dist/types/src/types/signer.d.ts.map +1 -1
- package/dist/types/src/types/smt-types.d.ts +81 -0
- package/dist/types/src/types/smt-types.d.ts.map +1 -0
- package/dist/types/src/types/state-index.d.ts +90 -0
- package/dist/types/src/types/state-index.d.ts.map +1 -0
- package/dist/types/src/utils/cid.d.ts +1 -2
- package/dist/types/src/utils/cid.d.ts.map +1 -1
- package/dist/types/src/utils/data-stream.d.ts +14 -7
- package/dist/types/src/utils/data-stream.d.ts.map +1 -1
- package/dist/types/src/utils/encryption.d.ts +2 -3
- package/dist/types/src/utils/encryption.d.ts.map +1 -1
- package/dist/types/src/utils/hd-key.d.ts +4 -4
- package/dist/types/src/utils/hd-key.d.ts.map +1 -1
- package/dist/types/src/utils/jws.d.ts +7 -7
- package/dist/types/src/utils/jws.d.ts.map +1 -1
- package/dist/types/src/utils/private-key-signer.d.ts +4 -4
- package/dist/types/src/utils/private-key-signer.d.ts.map +1 -1
- package/dist/types/src/utils/protocols.d.ts +46 -3
- package/dist/types/src/utils/protocols.d.ts.map +1 -1
- package/dist/types/src/utils/records.d.ts +33 -6
- package/dist/types/src/utils/records.d.ts.map +1 -1
- package/dist/types/src/utils/secp256k1.d.ts +11 -11
- package/dist/types/src/utils/secp256k1.d.ts.map +1 -1
- package/dist/types/src/utils/secp256r1.d.ts +8 -8
- package/dist/types/src/utils/secp256r1.d.ts.map +1 -1
- package/dist/types/src/utils/time.d.ts +1 -1
- package/dist/types/tests/dwn.spec.d.ts.map +1 -1
- package/dist/types/tests/event-stream/event-emitter-stream.spec.d.ts.map +1 -0
- package/dist/types/tests/event-stream/event-stream.spec.d.ts.map +1 -0
- package/dist/types/tests/features/author-delegated-grant.spec.d.ts.map +1 -1
- package/dist/types/tests/features/owner-delegated-grant.spec.d.ts.map +1 -1
- package/dist/types/tests/features/owner-signature.spec.d.ts.map +1 -1
- package/dist/types/tests/features/permissions.spec.d.ts.map +1 -1
- package/dist/types/tests/features/protocol-composition.spec.d.ts +5 -0
- package/dist/types/tests/features/protocol-composition.spec.d.ts.map +1 -0
- package/dist/types/tests/features/protocol-create-action.spec.d.ts.map +1 -1
- package/dist/types/tests/features/protocol-delete-action.spec.d.ts.map +1 -1
- package/dist/types/tests/features/protocol-update-action.spec.d.ts.map +1 -1
- package/dist/types/tests/features/records-prune.spec.d.ts.map +1 -1
- package/dist/types/tests/features/records-tags.spec.d.ts.map +1 -1
- package/dist/types/tests/features/resumable-tasks.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/messages-read.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/messages-subscribe.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/messages-sync.spec.d.ts +2 -0
- package/dist/types/tests/handlers/messages-sync.spec.d.ts.map +1 -0
- package/dist/types/tests/handlers/protocols-configure.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/protocols-query.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/records-count.spec.d.ts +2 -0
- package/dist/types/tests/handlers/records-count.spec.d.ts.map +1 -0
- package/dist/types/tests/handlers/records-delete.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/records-query.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/records-read.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/records-subscribe.spec.d.ts.map +1 -1
- package/dist/types/tests/handlers/records-write.spec.d.ts.map +1 -1
- package/dist/types/tests/protocols/permission-grant.spec.d.ts +2 -0
- package/dist/types/tests/protocols/permission-grant.spec.d.ts.map +1 -0
- package/dist/types/tests/scenarios/deleted-record.spec.d.ts.map +1 -1
- package/dist/types/tests/scenarios/end-to-end-tests.spec.d.ts.map +1 -1
- package/dist/types/tests/scenarios/nested-roles.spec.d.ts.map +1 -1
- package/dist/types/tests/smt/smt-store-level.spec.d.ts +2 -0
- package/dist/types/tests/smt/smt-store-level.spec.d.ts.map +1 -0
- package/dist/types/tests/smt/sparse-merkle-tree.spec.d.ts +2 -0
- package/dist/types/tests/smt/sparse-merkle-tree.spec.d.ts.map +1 -0
- package/dist/types/tests/state-index/state-index-level.spec.d.ts +2 -0
- package/dist/types/tests/state-index/state-index-level.spec.d.ts.map +1 -0
- package/dist/types/tests/store/blockstore-level.spec.d.ts +2 -0
- package/dist/types/tests/store/blockstore-level.spec.d.ts.map +1 -0
- package/dist/types/tests/store/message-store.spec.d.ts.map +1 -1
- package/dist/types/tests/test-stores.d.ts +4 -4
- package/dist/types/tests/test-stores.d.ts.map +1 -1
- package/dist/types/tests/test-suite.d.ts +2 -2
- package/dist/types/tests/test-suite.d.ts.map +1 -1
- package/dist/types/tests/utils/encryption-callbacks.spec.d.ts +2 -0
- package/dist/types/tests/utils/encryption-callbacks.spec.d.ts.map +1 -0
- package/dist/types/tests/utils/test-data-generator.d.ts +31 -28
- package/dist/types/tests/utils/test-data-generator.d.ts.map +1 -1
- package/dist/types/tests/validation/json-schemas/records/records-read.spec.d.ts +2 -0
- package/dist/types/tests/validation/json-schemas/records/records-read.spec.d.ts.map +1 -0
- package/package.json +27 -46
- package/src/core/dwn-error.ts +27 -3
- package/src/core/message-reply.ts +1 -1
- package/src/core/message.ts +5 -5
- package/src/core/messages-grant-authorization.ts +22 -8
- package/src/core/protocol-authorization.ts +345 -68
- package/src/core/records-grant-authorization.ts +2 -2
- package/src/core/resumable-task-manager.ts +4 -5
- package/src/dwn.ts +25 -20
- package/src/enums/dwn-interface-method.ts +5 -3
- package/src/handlers/messages-subscribe.ts +1 -1
- package/src/handlers/messages-sync.ts +129 -0
- package/src/handlers/protocols-configure.ts +195 -17
- package/src/handlers/protocols-query.ts +7 -5
- package/src/handlers/records-count.ts +184 -0
- package/src/handlers/records-query.ts +4 -0
- package/src/handlers/records-read.ts +4 -8
- package/src/handlers/records-write.ts +20 -21
- package/src/index.ts +74 -37
- package/src/interfaces/messages-read.ts +6 -5
- package/src/interfaces/messages-subscribe.ts +7 -6
- package/src/interfaces/messages-sync.ts +59 -0
- package/src/interfaces/protocols-configure.ts +211 -33
- package/src/interfaces/protocols-query.ts +7 -6
- package/src/interfaces/records-count.ts +106 -0
- package/src/interfaces/records-delete.ts +2 -2
- package/src/interfaces/records-query.ts +2 -2
- package/src/interfaces/records-read.ts +26 -3
- package/src/interfaces/records-subscribe.ts +2 -2
- package/src/interfaces/records-write.ts +115 -46
- package/src/jose/algorithms/signing/ed25519.ts +13 -12
- package/src/jose/algorithms/signing/signature-algorithms.ts +6 -1
- package/src/jose/jws/general/builder.ts +3 -3
- package/src/jose/jws/general/verifier.ts +3 -3
- package/src/protocols/permission-grant.ts +51 -0
- package/src/protocols/permission-request.ts +37 -0
- package/src/protocols/permissions.ts +5 -5
- package/src/schema-validator.ts +11 -3
- package/src/smt/smt-store-level.ts +143 -0
- package/src/smt/smt-store-memory.ts +53 -0
- package/src/smt/smt-utils.ts +149 -0
- package/src/smt/sparse-merkle-tree.ts +698 -0
- package/src/state-index/state-index-level.ts +241 -0
- package/src/store/data-store-level.ts +8 -7
- package/src/store/index-level.ts +415 -19
- package/src/store/level-wrapper.ts +1 -1
- package/src/store/message-store-level.ts +62 -0
- package/src/store/storage-controller.ts +21 -19
- package/src/types/data-store.ts +2 -4
- package/src/types/encryption-types.ts +52 -0
- package/src/types/jose-types.ts +10 -42
- package/src/types/message-store.ts +11 -0
- package/src/types/message-types.ts +21 -0
- package/src/types/messages-types.ts +21 -15
- package/src/types/method-handler.ts +1 -2
- package/src/types/permission-types.ts +2 -2
- package/src/types/protocols-types.ts +55 -6
- package/src/types/records-types.ts +26 -7
- package/src/types/signer.ts +1 -1
- package/src/types/smt-types.ts +95 -0
- package/src/types/state-index.ts +100 -0
- package/src/utils/cid.ts +3 -4
- package/src/utils/data-stream.ts +75 -38
- package/src/utils/encryption.ts +24 -39
- package/src/utils/hd-key.ts +6 -6
- package/src/utils/jws.ts +9 -9
- package/src/utils/private-key-signer.ts +9 -8
- package/src/utils/protocols.ts +132 -6
- package/src/utils/records.ts +118 -29
- package/src/utils/secp256k1.ts +23 -21
- package/src/utils/secp256r1.ts +17 -15
- package/src/utils/time.ts +1 -1
- package/src/utils/url.ts +1 -1
- package/dist/cjs/index.js +0 -36749
- package/dist/cjs/package.json +0 -1
- package/dist/esm/src/event-log/event-emitter-stream.js.map +0 -1
- package/dist/esm/src/event-log/event-log-level.js +0 -63
- package/dist/esm/src/event-log/event-log-level.js.map +0 -1
- package/dist/esm/src/handlers/messages-query.js +0 -71
- package/dist/esm/src/handlers/messages-query.js.map +0 -1
- package/dist/esm/src/interfaces/messages-query.js.map +0 -1
- package/dist/esm/src/types/event-log.js +0 -2
- package/dist/esm/src/types/event-log.js.map +0 -1
- package/dist/esm/tests/event-log/event-emitter-stream.spec.js.map +0 -1
- package/dist/esm/tests/event-log/event-log-level.spec.js +0 -44
- package/dist/esm/tests/event-log/event-log-level.spec.js.map +0 -1
- package/dist/esm/tests/event-log/event-log.spec.js +0 -236
- package/dist/esm/tests/event-log/event-log.spec.js.map +0 -1
- package/dist/esm/tests/event-log/event-stream.spec.js.map +0 -1
- package/dist/esm/tests/handlers/messages-query.spec.js +0 -349
- package/dist/esm/tests/handlers/messages-query.spec.js.map +0 -1
- package/dist/esm/tests/interfaces/messagess-query.spec.js +0 -127
- package/dist/esm/tests/interfaces/messagess-query.spec.js.map +0 -1
- package/dist/esm/tests/scenarios/messages-query.spec.js +0 -395
- package/dist/esm/tests/scenarios/messages-query.spec.js.map +0 -1
- package/dist/types/src/event-log/event-emitter-stream.d.ts.map +0 -1
- package/dist/types/src/event-log/event-log-level.d.ts +0 -35
- package/dist/types/src/event-log/event-log-level.d.ts.map +0 -1
- package/dist/types/src/handlers/messages-query.d.ts +0 -17
- package/dist/types/src/handlers/messages-query.d.ts.map +0 -1
- package/dist/types/src/interfaces/messages-query.d.ts +0 -16
- package/dist/types/src/interfaces/messages-query.d.ts.map +0 -1
- package/dist/types/src/types/event-log.d.ts +0 -52
- package/dist/types/src/types/event-log.d.ts.map +0 -1
- package/dist/types/tests/event-log/event-emitter-stream.spec.d.ts.map +0 -1
- package/dist/types/tests/event-log/event-log-level.spec.d.ts +0 -2
- package/dist/types/tests/event-log/event-log-level.spec.d.ts.map +0 -1
- package/dist/types/tests/event-log/event-log.spec.d.ts +0 -2
- package/dist/types/tests/event-log/event-log.spec.d.ts.map +0 -1
- package/dist/types/tests/event-log/event-stream.spec.d.ts.map +0 -1
- package/dist/types/tests/handlers/messages-query.spec.d.ts +0 -2
- package/dist/types/tests/handlers/messages-query.spec.d.ts.map +0 -1
- package/dist/types/tests/interfaces/messagess-query.spec.d.ts +0 -2
- package/dist/types/tests/interfaces/messagess-query.spec.d.ts.map +0 -1
- package/dist/types/tests/scenarios/messages-query.spec.d.ts +0 -2
- package/dist/types/tests/scenarios/messages-query.spec.d.ts.map +0 -1
- package/src/event-log/event-log-level.ts +0 -72
- package/src/handlers/messages-query.ts +0 -67
- package/src/interfaces/messages-query.ts +0 -60
- package/src/types/event-log.ts +0 -52
- /package/dist/esm/src/{event-log → event-stream}/event-emitter-stream.js +0 -0
- /package/dist/types/src/{event-log → event-stream}/event-emitter-stream.d.ts +0 -0
- /package/dist/types/tests/{event-log → event-stream}/event-emitter-stream.spec.d.ts +0 -0
- /package/dist/types/tests/{event-log → event-stream}/event-stream.spec.d.ts +0 -0
- /package/src/{event-log → event-stream}/event-emitter-stream.ts +0 -0
|
@@ -0,0 +1,1645 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import sinon from 'sinon';
|
|
11
|
+
import { DataStream } from '../../src/utils/data-stream.js';
|
|
12
|
+
import { Dwn } from '../../src/dwn.js';
|
|
13
|
+
import { Encoder } from '../../src/utils/encoder.js';
|
|
14
|
+
import { Jws } from '../../src/utils/jws.js';
|
|
15
|
+
import { Protocols } from '../../src/utils/protocols.js';
|
|
16
|
+
import { Records } from '../../src/utils/records.js';
|
|
17
|
+
import { Secp256k1 } from '../../src/utils/secp256k1.js';
|
|
18
|
+
import { TestDataGenerator } from '../utils/test-data-generator.js';
|
|
19
|
+
import { TestEventStream } from '../test-event-stream.js';
|
|
20
|
+
import { TestStores } from '../test-stores.js';
|
|
21
|
+
import { TestStubGenerator } from '../utils/test-stub-generator.js';
|
|
22
|
+
import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'bun:test';
|
|
23
|
+
import { DidKey, UniversalResolver } from '@enbox/dids';
|
|
24
|
+
import { DwnErrorCode, Message, ProtocolsConfigure, RecordsDelete, RecordsQuery, RecordsRead, Time } from '../../src/index.js';
|
|
25
|
+
import { HdKey, KeyDerivationScheme } from '../../src/utils/hd-key.js';
|
|
26
|
+
/**
|
|
27
|
+
* Tests for protocol composition using `uses` + `$ref`.
|
|
28
|
+
*/
|
|
29
|
+
export function testProtocolComposition() {
|
|
30
|
+
describe('Protocol composition', () => {
|
|
31
|
+
let didResolver;
|
|
32
|
+
let messageStore;
|
|
33
|
+
let dataStore;
|
|
34
|
+
let resumableTaskStore;
|
|
35
|
+
let stateIndex;
|
|
36
|
+
let eventStream;
|
|
37
|
+
let dwn;
|
|
38
|
+
beforeAll(() => __awaiter(this, void 0, void 0, function* () {
|
|
39
|
+
didResolver = new UniversalResolver({ didResolvers: [DidKey] });
|
|
40
|
+
const stores = TestStores.get();
|
|
41
|
+
messageStore = stores.messageStore;
|
|
42
|
+
dataStore = stores.dataStore;
|
|
43
|
+
resumableTaskStore = stores.resumableTaskStore;
|
|
44
|
+
stateIndex = stores.stateIndex;
|
|
45
|
+
eventStream = TestEventStream.get();
|
|
46
|
+
dwn = yield Dwn.create({ didResolver, messageStore, dataStore, stateIndex, eventStream, resumableTaskStore });
|
|
47
|
+
}));
|
|
48
|
+
beforeEach(() => __awaiter(this, void 0, void 0, function* () {
|
|
49
|
+
sinon.restore();
|
|
50
|
+
yield messageStore.clear();
|
|
51
|
+
yield dataStore.clear();
|
|
52
|
+
yield resumableTaskStore.clear();
|
|
53
|
+
yield stateIndex.clear();
|
|
54
|
+
}));
|
|
55
|
+
afterAll(() => __awaiter(this, void 0, void 0, function* () {
|
|
56
|
+
yield dwn.close();
|
|
57
|
+
}));
|
|
58
|
+
// =========================================================================
|
|
59
|
+
// Protocol definitions for tests
|
|
60
|
+
// =========================================================================
|
|
61
|
+
const threadsProtocol = {
|
|
62
|
+
protocol: 'https://threads.example.com',
|
|
63
|
+
published: true,
|
|
64
|
+
types: {
|
|
65
|
+
thread: { schema: 'https://threads.example.com/schemas/thread', dataFormats: ['application/json'] },
|
|
66
|
+
participant: { schema: 'https://threads.example.com/schemas/participant', dataFormats: ['application/json'] },
|
|
67
|
+
message: { schema: 'https://threads.example.com/schemas/message', dataFormats: ['application/json'] },
|
|
68
|
+
},
|
|
69
|
+
structure: {
|
|
70
|
+
thread: {
|
|
71
|
+
$actions: [
|
|
72
|
+
{ who: 'anyone', can: ['create', 'read'] }
|
|
73
|
+
],
|
|
74
|
+
participant: {
|
|
75
|
+
$role: true,
|
|
76
|
+
$actions: [
|
|
77
|
+
{ who: 'anyone', can: ['read'] },
|
|
78
|
+
{ who: 'author', of: 'thread', can: ['create'] },
|
|
79
|
+
],
|
|
80
|
+
},
|
|
81
|
+
message: {
|
|
82
|
+
$actions: [
|
|
83
|
+
{ role: 'thread/participant', can: ['create', 'read'] },
|
|
84
|
+
],
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
const commentsProtocol = {
|
|
90
|
+
protocol: 'https://comments.example.com',
|
|
91
|
+
published: true,
|
|
92
|
+
uses: {
|
|
93
|
+
threads: 'https://threads.example.com',
|
|
94
|
+
},
|
|
95
|
+
types: {
|
|
96
|
+
comment: { schema: 'https://comments.example.com/schemas/comment', dataFormats: ['application/json'] },
|
|
97
|
+
reaction: { schema: 'https://comments.example.com/schemas/reaction', dataFormats: ['application/json'] },
|
|
98
|
+
},
|
|
99
|
+
structure: {
|
|
100
|
+
thread: {
|
|
101
|
+
$ref: 'threads:thread',
|
|
102
|
+
comment: {
|
|
103
|
+
$actions: [
|
|
104
|
+
{ who: 'anyone', can: ['create', 'read'] },
|
|
105
|
+
{ role: 'threads:thread/participant', can: ['read', 'co-delete'] },
|
|
106
|
+
],
|
|
107
|
+
reaction: {
|
|
108
|
+
$actions: [
|
|
109
|
+
{ who: 'anyone', can: ['create', 'read'] },
|
|
110
|
+
],
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
// =========================================================================
|
|
117
|
+
// Validation tests (ProtocolsConfigure)
|
|
118
|
+
// =========================================================================
|
|
119
|
+
describe('ProtocolsConfigure validation', () => {
|
|
120
|
+
it('should accept a valid protocol definition with `uses` and `$ref`', () => __awaiter(this, void 0, void 0, function* () {
|
|
121
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
122
|
+
const protocolsConfigure = yield ProtocolsConfigure.create({
|
|
123
|
+
definition: commentsProtocol,
|
|
124
|
+
signer: Jws.createSigner(alice),
|
|
125
|
+
});
|
|
126
|
+
expect(protocolsConfigure.message.descriptor.definition.uses).toEqual({
|
|
127
|
+
threads: 'https://threads.example.com',
|
|
128
|
+
});
|
|
129
|
+
}));
|
|
130
|
+
it('should reject `uses` alias that does not match naming pattern (bypassing JSON schema)', () => __awaiter(this, void 0, void 0, function* () {
|
|
131
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
132
|
+
// The JSON schema enforces alias naming via `patternProperties` + `additionalProperties: false`,
|
|
133
|
+
// which means invalid aliases like '123invalid' are caught by JSON schema before the code-level
|
|
134
|
+
// `validateUses()` check. To exercise the code-level `ProtocolsConfigureInvalidUsesAlias` error,
|
|
135
|
+
// we must stub `Message.validateJsonSchema` to bypass JSON schema validation.
|
|
136
|
+
sinon.stub(Message, 'validateJsonSchema');
|
|
137
|
+
const badDefinition = {
|
|
138
|
+
protocol: 'https://bad.example.com',
|
|
139
|
+
published: true,
|
|
140
|
+
uses: { '123invalid': 'https://foo.example.com' },
|
|
141
|
+
types: {},
|
|
142
|
+
structure: {},
|
|
143
|
+
};
|
|
144
|
+
try {
|
|
145
|
+
yield ProtocolsConfigure.create({
|
|
146
|
+
definition: badDefinition,
|
|
147
|
+
signer: Jws.createSigner(alice),
|
|
148
|
+
});
|
|
149
|
+
throw new Error('Expected an error to be thrown');
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
expect(error.message).toContain(DwnErrorCode.ProtocolsConfigureInvalidUsesAlias);
|
|
153
|
+
}
|
|
154
|
+
}));
|
|
155
|
+
it('should reject `$ref` with alias not in `uses`', () => __awaiter(this, void 0, void 0, function* () {
|
|
156
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
157
|
+
const badDefinition = {
|
|
158
|
+
protocol: 'https://bad.example.com',
|
|
159
|
+
published: true,
|
|
160
|
+
uses: {
|
|
161
|
+
foo: 'https://foo.example.com',
|
|
162
|
+
},
|
|
163
|
+
types: { comment: {} },
|
|
164
|
+
structure: {
|
|
165
|
+
thread: {
|
|
166
|
+
$ref: 'nonexistent:thread', // alias 'nonexistent' not in uses
|
|
167
|
+
comment: {
|
|
168
|
+
$actions: [{ who: 'anyone', can: ['create'] }],
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
try {
|
|
174
|
+
yield ProtocolsConfigure.create({
|
|
175
|
+
definition: badDefinition,
|
|
176
|
+
signer: Jws.createSigner(alice),
|
|
177
|
+
});
|
|
178
|
+
throw new Error('Expected an error to be thrown');
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
expect(error.message).toContain(DwnErrorCode.ProtocolsConfigureInvalidRefAlias);
|
|
182
|
+
}
|
|
183
|
+
}));
|
|
184
|
+
it('should reject `$ref` node with `$actions`', () => __awaiter(this, void 0, void 0, function* () {
|
|
185
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
186
|
+
const badDefinition = {
|
|
187
|
+
protocol: 'https://bad.example.com',
|
|
188
|
+
published: true,
|
|
189
|
+
uses: { threads: 'https://threads.example.com' },
|
|
190
|
+
types: { comment: {} },
|
|
191
|
+
structure: {
|
|
192
|
+
thread: {
|
|
193
|
+
$ref: 'threads:thread',
|
|
194
|
+
$actions: [{ who: 'anyone', can: ['read'] }], // not allowed on $ref node
|
|
195
|
+
comment: {
|
|
196
|
+
$actions: [{ who: 'anyone', can: ['create'] }],
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
try {
|
|
202
|
+
yield ProtocolsConfigure.create({
|
|
203
|
+
definition: badDefinition,
|
|
204
|
+
signer: Jws.createSigner(alice),
|
|
205
|
+
});
|
|
206
|
+
throw new Error('Expected an error to be thrown');
|
|
207
|
+
}
|
|
208
|
+
catch (error) {
|
|
209
|
+
expect(error.message).toContain(DwnErrorCode.ProtocolsConfigureInvalidRefNodeHasDirectives);
|
|
210
|
+
}
|
|
211
|
+
}));
|
|
212
|
+
it('should reject `$ref` node with `$role`', () => __awaiter(this, void 0, void 0, function* () {
|
|
213
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
214
|
+
const badDefinition = {
|
|
215
|
+
protocol: 'https://bad.example.com',
|
|
216
|
+
published: true,
|
|
217
|
+
uses: { threads: 'https://threads.example.com' },
|
|
218
|
+
types: {},
|
|
219
|
+
structure: {
|
|
220
|
+
thread: {
|
|
221
|
+
$ref: 'threads:thread',
|
|
222
|
+
$role: true, // not allowed on $ref node
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
};
|
|
226
|
+
try {
|
|
227
|
+
yield ProtocolsConfigure.create({
|
|
228
|
+
definition: badDefinition,
|
|
229
|
+
signer: Jws.createSigner(alice),
|
|
230
|
+
});
|
|
231
|
+
throw new Error('Expected an error to be thrown');
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
expect(error.message).toContain(DwnErrorCode.ProtocolsConfigureInvalidRefNodeHasDirectives);
|
|
235
|
+
}
|
|
236
|
+
}));
|
|
237
|
+
it('should reject cross-protocol `role` with alias not in `uses`', () => __awaiter(this, void 0, void 0, function* () {
|
|
238
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
239
|
+
const badDefinition = {
|
|
240
|
+
protocol: 'https://bad.example.com',
|
|
241
|
+
published: true,
|
|
242
|
+
uses: { threads: 'https://threads.example.com' },
|
|
243
|
+
types: { comment: {} },
|
|
244
|
+
structure: {
|
|
245
|
+
thread: {
|
|
246
|
+
$ref: 'threads:thread',
|
|
247
|
+
comment: {
|
|
248
|
+
$actions: [
|
|
249
|
+
{ role: 'nonexistent:thread/participant', can: ['read'] }, // alias 'nonexistent' not in uses
|
|
250
|
+
],
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
};
|
|
255
|
+
try {
|
|
256
|
+
yield ProtocolsConfigure.create({
|
|
257
|
+
definition: badDefinition,
|
|
258
|
+
signer: Jws.createSigner(alice),
|
|
259
|
+
});
|
|
260
|
+
throw new Error('Expected an error to be thrown');
|
|
261
|
+
}
|
|
262
|
+
catch (error) {
|
|
263
|
+
expect(error.message).toContain(DwnErrorCode.ProtocolsConfigureInvalidCrossProtocolRole);
|
|
264
|
+
}
|
|
265
|
+
}));
|
|
266
|
+
it('should reject `uses` with invalid protocol URL', () => __awaiter(this, void 0, void 0, function* () {
|
|
267
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
268
|
+
const badDefinition = {
|
|
269
|
+
protocol: 'https://bad.example.com',
|
|
270
|
+
published: true,
|
|
271
|
+
uses: { threads: '::invalid::' },
|
|
272
|
+
types: {},
|
|
273
|
+
structure: {},
|
|
274
|
+
};
|
|
275
|
+
try {
|
|
276
|
+
yield ProtocolsConfigure.create({
|
|
277
|
+
definition: badDefinition,
|
|
278
|
+
signer: Jws.createSigner(alice),
|
|
279
|
+
});
|
|
280
|
+
throw new Error('Expected an error to be thrown');
|
|
281
|
+
}
|
|
282
|
+
catch (error) {
|
|
283
|
+
expect(error.message).toContain(DwnErrorCode.ProtocolsConfigureInvalidUsesProtocolUrl);
|
|
284
|
+
}
|
|
285
|
+
}));
|
|
286
|
+
it('should accept `$ref` referencing a multi-segment path in the referenced protocol', () => __awaiter(this, void 0, void 0, function* () {
|
|
287
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
288
|
+
// The root-only constraint means `$ref` must appear at the root of the composing structure,
|
|
289
|
+
// but the REFERENCED path can be multi-segment (e.g., 'thread/participant').
|
|
290
|
+
const definition = {
|
|
291
|
+
protocol: 'https://deep-ref.example.com',
|
|
292
|
+
published: true,
|
|
293
|
+
uses: { threads: 'https://threads.example.com' },
|
|
294
|
+
types: {
|
|
295
|
+
note: { schema: 'https://deep-ref.example.com/schemas/note', dataFormats: ['application/json'] },
|
|
296
|
+
},
|
|
297
|
+
structure: {
|
|
298
|
+
participant: {
|
|
299
|
+
$ref: 'threads:thread/participant', // multi-segment referenced path
|
|
300
|
+
note: {
|
|
301
|
+
$actions: [{ who: 'anyone', can: ['create', 'read'] }],
|
|
302
|
+
},
|
|
303
|
+
},
|
|
304
|
+
},
|
|
305
|
+
};
|
|
306
|
+
// ProtocolsConfigure.create() should succeed — the $ref is at root level
|
|
307
|
+
const protocolsConfigure = yield ProtocolsConfigure.create({
|
|
308
|
+
definition,
|
|
309
|
+
signer: Jws.createSigner(alice),
|
|
310
|
+
});
|
|
311
|
+
expect(protocolsConfigure.message.descriptor.definition.uses).toBeDefined();
|
|
312
|
+
// Install-time validation should also succeed when the referenced protocol is installed
|
|
313
|
+
const threadsConfigure = yield ProtocolsConfigure.create({
|
|
314
|
+
definition: threadsProtocol,
|
|
315
|
+
signer: Jws.createSigner(alice),
|
|
316
|
+
});
|
|
317
|
+
yield dwn.processMessage(alice.did, threadsConfigure.message);
|
|
318
|
+
const installReply = yield dwn.processMessage(alice.did, protocolsConfigure.message);
|
|
319
|
+
expect(installReply.status.code).toBe(202);
|
|
320
|
+
}));
|
|
321
|
+
it('should not require `$ref` types in local types map', () => __awaiter(this, void 0, void 0, function* () {
|
|
322
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
323
|
+
// 'thread' is NOT in the local `types` — it comes from the $ref
|
|
324
|
+
const definition = {
|
|
325
|
+
protocol: 'https://comments.example.com',
|
|
326
|
+
published: true,
|
|
327
|
+
uses: { threads: 'https://threads.example.com' },
|
|
328
|
+
types: { comment: {} }, // no 'thread' type
|
|
329
|
+
structure: {
|
|
330
|
+
thread: {
|
|
331
|
+
$ref: 'threads:thread',
|
|
332
|
+
comment: {
|
|
333
|
+
$actions: [{ who: 'anyone', can: ['create'] }],
|
|
334
|
+
},
|
|
335
|
+
},
|
|
336
|
+
},
|
|
337
|
+
};
|
|
338
|
+
// should succeed without error
|
|
339
|
+
const protocolsConfigure = yield ProtocolsConfigure.create({
|
|
340
|
+
definition,
|
|
341
|
+
signer: Jws.createSigner(alice),
|
|
342
|
+
});
|
|
343
|
+
expect(protocolsConfigure.message.descriptor.definition.uses).toBeDefined();
|
|
344
|
+
}));
|
|
345
|
+
});
|
|
346
|
+
// =========================================================================
|
|
347
|
+
// Install-time validation tests (handler)
|
|
348
|
+
// =========================================================================
|
|
349
|
+
describe('install-time composition dependency validation', () => {
|
|
350
|
+
it('should reject composing protocol if `uses` protocol is not installed', () => __awaiter(this, void 0, void 0, function* () {
|
|
351
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
352
|
+
// Try to install comments protocol WITHOUT installing threads first
|
|
353
|
+
const commentsConfigure = yield ProtocolsConfigure.create({
|
|
354
|
+
definition: commentsProtocol,
|
|
355
|
+
signer: Jws.createSigner(alice),
|
|
356
|
+
});
|
|
357
|
+
const reply = yield dwn.processMessage(alice.did, commentsConfigure.message);
|
|
358
|
+
expect(reply.status.code).toBe(400);
|
|
359
|
+
expect(reply.status.detail).toContain(DwnErrorCode.ProtocolsConfigureComposedProtocolNotInstalled);
|
|
360
|
+
}));
|
|
361
|
+
it('should accept composing protocol when `uses` protocol is already installed', () => __awaiter(this, void 0, void 0, function* () {
|
|
362
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
363
|
+
// Install threads protocol first
|
|
364
|
+
const threadsConfigure = yield ProtocolsConfigure.create({
|
|
365
|
+
definition: threadsProtocol,
|
|
366
|
+
signer: Jws.createSigner(alice),
|
|
367
|
+
});
|
|
368
|
+
const threadsReply = yield dwn.processMessage(alice.did, threadsConfigure.message);
|
|
369
|
+
expect(threadsReply.status.code).toBe(202);
|
|
370
|
+
// Now install comments protocol — should succeed
|
|
371
|
+
const commentsConfigure = yield ProtocolsConfigure.create({
|
|
372
|
+
definition: commentsProtocol,
|
|
373
|
+
signer: Jws.createSigner(alice),
|
|
374
|
+
});
|
|
375
|
+
const commentsReply = yield dwn.processMessage(alice.did, commentsConfigure.message);
|
|
376
|
+
expect(commentsReply.status.code).toBe(202);
|
|
377
|
+
}));
|
|
378
|
+
it('should reject composing protocol if `$ref` path does not exist in referenced protocol', () => __awaiter(this, void 0, void 0, function* () {
|
|
379
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
380
|
+
// Install threads protocol first
|
|
381
|
+
const threadsConfigure = yield ProtocolsConfigure.create({
|
|
382
|
+
definition: threadsProtocol,
|
|
383
|
+
signer: Jws.createSigner(alice),
|
|
384
|
+
});
|
|
385
|
+
yield dwn.processMessage(alice.did, threadsConfigure.message);
|
|
386
|
+
// Install a composing protocol that references a non-existent type path
|
|
387
|
+
const badDefinition = {
|
|
388
|
+
protocol: 'https://bad.example.com',
|
|
389
|
+
published: true,
|
|
390
|
+
uses: { threads: 'https://threads.example.com' },
|
|
391
|
+
types: { comment: {} },
|
|
392
|
+
structure: {
|
|
393
|
+
nonexistent: {
|
|
394
|
+
$ref: 'threads:nonexistent', // 'nonexistent' doesn't exist in threads protocol
|
|
395
|
+
comment: {
|
|
396
|
+
$actions: [{ who: 'anyone', can: ['create'] }],
|
|
397
|
+
},
|
|
398
|
+
},
|
|
399
|
+
},
|
|
400
|
+
};
|
|
401
|
+
const badConfigure = yield ProtocolsConfigure.create({
|
|
402
|
+
definition: badDefinition,
|
|
403
|
+
signer: Jws.createSigner(alice),
|
|
404
|
+
});
|
|
405
|
+
const reply = yield dwn.processMessage(alice.did, badConfigure.message);
|
|
406
|
+
expect(reply.status.code).toBe(400);
|
|
407
|
+
expect(reply.status.detail).toContain(DwnErrorCode.ProtocolsConfigureInvalidRefProtocolPath);
|
|
408
|
+
}));
|
|
409
|
+
it('should reject composing protocol if cross-protocol `of` path does not exist in referenced protocol', () => __awaiter(this, void 0, void 0, function* () {
|
|
410
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
411
|
+
// Install threads protocol first
|
|
412
|
+
const threadsConfigure = yield ProtocolsConfigure.create({
|
|
413
|
+
definition: threadsProtocol,
|
|
414
|
+
signer: Jws.createSigner(alice),
|
|
415
|
+
});
|
|
416
|
+
yield dwn.processMessage(alice.did, threadsConfigure.message);
|
|
417
|
+
// Install a composing protocol with an `of` reference to a non-existent path
|
|
418
|
+
const badDefinition = {
|
|
419
|
+
protocol: 'https://bad.example.com',
|
|
420
|
+
published: true,
|
|
421
|
+
uses: { threads: 'https://threads.example.com' },
|
|
422
|
+
types: { action: {} },
|
|
423
|
+
structure: {
|
|
424
|
+
thread: {
|
|
425
|
+
$ref: 'threads:thread',
|
|
426
|
+
action: {
|
|
427
|
+
$actions: [
|
|
428
|
+
{ who: 'author', of: 'threads:nonexistent', can: ['create'] },
|
|
429
|
+
],
|
|
430
|
+
},
|
|
431
|
+
},
|
|
432
|
+
},
|
|
433
|
+
};
|
|
434
|
+
const badConfigure = yield ProtocolsConfigure.create({
|
|
435
|
+
definition: badDefinition,
|
|
436
|
+
signer: Jws.createSigner(alice),
|
|
437
|
+
});
|
|
438
|
+
const reply = yield dwn.processMessage(alice.did, badConfigure.message);
|
|
439
|
+
expect(reply.status.code).toBe(400);
|
|
440
|
+
expect(reply.status.detail).toContain(DwnErrorCode.ProtocolsConfigureInvalidCrossProtocolOf);
|
|
441
|
+
}));
|
|
442
|
+
it('should reject composing protocol if cross-protocol role does not exist in referenced protocol', () => __awaiter(this, void 0, void 0, function* () {
|
|
443
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
444
|
+
// Install threads protocol first
|
|
445
|
+
const threadsConfigure = yield ProtocolsConfigure.create({
|
|
446
|
+
definition: threadsProtocol,
|
|
447
|
+
signer: Jws.createSigner(alice),
|
|
448
|
+
});
|
|
449
|
+
yield dwn.processMessage(alice.did, threadsConfigure.message);
|
|
450
|
+
// Install a composing protocol with invalid cross-protocol role
|
|
451
|
+
const badDefinition = {
|
|
452
|
+
protocol: 'https://bad.example.com',
|
|
453
|
+
published: true,
|
|
454
|
+
uses: { threads: 'https://threads.example.com' },
|
|
455
|
+
types: { comment: {} },
|
|
456
|
+
structure: {
|
|
457
|
+
thread: {
|
|
458
|
+
$ref: 'threads:thread',
|
|
459
|
+
comment: {
|
|
460
|
+
$actions: [
|
|
461
|
+
{ who: 'anyone', can: ['create'] },
|
|
462
|
+
{ role: 'threads:thread/nonexistent', can: ['read'] }, // path exists but not a role
|
|
463
|
+
],
|
|
464
|
+
},
|
|
465
|
+
},
|
|
466
|
+
},
|
|
467
|
+
};
|
|
468
|
+
const badConfigure = yield ProtocolsConfigure.create({
|
|
469
|
+
definition: badDefinition,
|
|
470
|
+
signer: Jws.createSigner(alice),
|
|
471
|
+
});
|
|
472
|
+
const reply = yield dwn.processMessage(alice.did, badConfigure.message);
|
|
473
|
+
expect(reply.status.code).toBe(400);
|
|
474
|
+
expect(reply.status.detail).toContain(DwnErrorCode.ProtocolsConfigureInvalidCrossProtocolRole);
|
|
475
|
+
}));
|
|
476
|
+
});
|
|
477
|
+
// =========================================================================
|
|
478
|
+
// Runtime cross-protocol record creation tests
|
|
479
|
+
// =========================================================================
|
|
480
|
+
describe('cross-protocol record creation', () => {
|
|
481
|
+
it('should allow creating a child record in a composing protocol under a parent from a different protocol', () => __awaiter(this, void 0, void 0, function* () {
|
|
482
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
483
|
+
// Install both protocols
|
|
484
|
+
const threadsConfigure = yield ProtocolsConfigure.create({
|
|
485
|
+
definition: threadsProtocol,
|
|
486
|
+
signer: Jws.createSigner(alice),
|
|
487
|
+
});
|
|
488
|
+
yield dwn.processMessage(alice.did, threadsConfigure.message);
|
|
489
|
+
const commentsConfigure = yield ProtocolsConfigure.create({
|
|
490
|
+
definition: commentsProtocol,
|
|
491
|
+
signer: Jws.createSigner(alice),
|
|
492
|
+
});
|
|
493
|
+
yield dwn.processMessage(alice.did, commentsConfigure.message);
|
|
494
|
+
// Create a thread record in the threads protocol
|
|
495
|
+
const threadWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
496
|
+
author: alice,
|
|
497
|
+
protocol: threadsProtocol.protocol,
|
|
498
|
+
protocolPath: 'thread',
|
|
499
|
+
schema: 'https://threads.example.com/schemas/thread',
|
|
500
|
+
dataFormat: 'application/json',
|
|
501
|
+
});
|
|
502
|
+
const threadReply = yield dwn.processMessage(alice.did, threadWrite.message, { dataStream: threadWrite.dataStream });
|
|
503
|
+
expect(threadReply.status.code).toBe(202);
|
|
504
|
+
const threadContextId = threadWrite.message.contextId;
|
|
505
|
+
// Create a comment record in the comments protocol, parented under the thread
|
|
506
|
+
const commentWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
507
|
+
author: alice,
|
|
508
|
+
protocol: commentsProtocol.protocol,
|
|
509
|
+
protocolPath: 'thread/comment',
|
|
510
|
+
schema: 'https://comments.example.com/schemas/comment',
|
|
511
|
+
dataFormat: 'application/json',
|
|
512
|
+
parentContextId: threadContextId,
|
|
513
|
+
});
|
|
514
|
+
const commentReply = yield dwn.processMessage(alice.did, commentWrite.message, { dataStream: commentWrite.dataStream });
|
|
515
|
+
expect(commentReply.status.code).toBe(202);
|
|
516
|
+
// The comment's contextId should chain from the thread's contextId
|
|
517
|
+
expect(commentWrite.message.contextId).toBe(`${threadContextId}/${commentWrite.message.recordId}`);
|
|
518
|
+
}));
|
|
519
|
+
it('should allow creating a grandchild in the composing protocol under a cross-protocol child', () => __awaiter(this, void 0, void 0, function* () {
|
|
520
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
521
|
+
// Install both protocols
|
|
522
|
+
const threadsConfigure = yield ProtocolsConfigure.create({
|
|
523
|
+
definition: threadsProtocol,
|
|
524
|
+
signer: Jws.createSigner(alice),
|
|
525
|
+
});
|
|
526
|
+
yield dwn.processMessage(alice.did, threadsConfigure.message);
|
|
527
|
+
const commentsConfigure = yield ProtocolsConfigure.create({
|
|
528
|
+
definition: commentsProtocol,
|
|
529
|
+
signer: Jws.createSigner(alice),
|
|
530
|
+
});
|
|
531
|
+
yield dwn.processMessage(alice.did, commentsConfigure.message);
|
|
532
|
+
// Create thread -> comment -> reaction chain
|
|
533
|
+
const threadWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
534
|
+
author: alice,
|
|
535
|
+
protocol: threadsProtocol.protocol,
|
|
536
|
+
protocolPath: 'thread',
|
|
537
|
+
schema: 'https://threads.example.com/schemas/thread',
|
|
538
|
+
dataFormat: 'application/json',
|
|
539
|
+
});
|
|
540
|
+
yield dwn.processMessage(alice.did, threadWrite.message, { dataStream: threadWrite.dataStream });
|
|
541
|
+
const threadContextId = threadWrite.message.contextId;
|
|
542
|
+
const commentWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
543
|
+
author: alice,
|
|
544
|
+
protocol: commentsProtocol.protocol,
|
|
545
|
+
protocolPath: 'thread/comment',
|
|
546
|
+
schema: 'https://comments.example.com/schemas/comment',
|
|
547
|
+
dataFormat: 'application/json',
|
|
548
|
+
parentContextId: threadContextId,
|
|
549
|
+
});
|
|
550
|
+
yield dwn.processMessage(alice.did, commentWrite.message, { dataStream: commentWrite.dataStream });
|
|
551
|
+
const commentContextId = commentWrite.message.contextId;
|
|
552
|
+
// Create a reaction under the comment (grandchild, same composing protocol)
|
|
553
|
+
const reactionWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
554
|
+
author: alice,
|
|
555
|
+
protocol: commentsProtocol.protocol,
|
|
556
|
+
protocolPath: 'thread/comment/reaction',
|
|
557
|
+
schema: 'https://comments.example.com/schemas/reaction',
|
|
558
|
+
dataFormat: 'application/json',
|
|
559
|
+
parentContextId: commentContextId,
|
|
560
|
+
});
|
|
561
|
+
const reactionReply = yield dwn.processMessage(alice.did, reactionWrite.message, { dataStream: reactionWrite.dataStream });
|
|
562
|
+
expect(reactionReply.status.code).toBe(202);
|
|
563
|
+
}));
|
|
564
|
+
});
|
|
565
|
+
// =========================================================================
|
|
566
|
+
// Writing at the $ref position
|
|
567
|
+
// =========================================================================
|
|
568
|
+
describe('writing at the $ref position', () => {
|
|
569
|
+
it('should reject a non-tenant writing at the `$ref` position because `$ref` nodes have no `$actions`', () => __awaiter(this, void 0, void 0, function* () {
|
|
570
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
571
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
572
|
+
// Install both protocols on Alice's DWN
|
|
573
|
+
const threadsConfigure = yield ProtocolsConfigure.create({
|
|
574
|
+
definition: threadsProtocol,
|
|
575
|
+
signer: Jws.createSigner(alice),
|
|
576
|
+
});
|
|
577
|
+
yield dwn.processMessage(alice.did, threadsConfigure.message);
|
|
578
|
+
const commentsConfigure = yield ProtocolsConfigure.create({
|
|
579
|
+
definition: commentsProtocol,
|
|
580
|
+
signer: Jws.createSigner(alice),
|
|
581
|
+
});
|
|
582
|
+
yield dwn.processMessage(alice.did, commentsConfigure.message);
|
|
583
|
+
// Bob tries to write a record at the `$ref` position (protocolPath: 'thread')
|
|
584
|
+
// through the composing protocol. The `$ref` node has no `$actions`, so this should
|
|
585
|
+
// be rejected for any non-tenant author.
|
|
586
|
+
const threadWriteAtRef = yield TestDataGenerator.generateRecordsWrite({
|
|
587
|
+
author: bob,
|
|
588
|
+
protocol: commentsProtocol.protocol,
|
|
589
|
+
protocolPath: 'thread',
|
|
590
|
+
schema: 'https://threads.example.com/schemas/thread',
|
|
591
|
+
dataFormat: 'application/json',
|
|
592
|
+
});
|
|
593
|
+
const reply = yield dwn.processMessage(alice.did, threadWriteAtRef.message, { dataStream: threadWriteAtRef.dataStream });
|
|
594
|
+
expect(reply.status.code).toBe(401);
|
|
595
|
+
expect(reply.status.detail).toContain(DwnErrorCode.ProtocolAuthorizationActionRulesNotFound);
|
|
596
|
+
}));
|
|
597
|
+
it('should resolve type from the referenced protocol for records at the `$ref` position', () => __awaiter(this, void 0, void 0, function* () {
|
|
598
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
599
|
+
// Install both protocols on Alice's DWN
|
|
600
|
+
const threadsConfigure = yield ProtocolsConfigure.create({
|
|
601
|
+
definition: threadsProtocol,
|
|
602
|
+
signer: Jws.createSigner(alice),
|
|
603
|
+
});
|
|
604
|
+
yield dwn.processMessage(alice.did, threadsConfigure.message);
|
|
605
|
+
const commentsConfigure = yield ProtocolsConfigure.create({
|
|
606
|
+
definition: commentsProtocol,
|
|
607
|
+
signer: Jws.createSigner(alice),
|
|
608
|
+
});
|
|
609
|
+
yield dwn.processMessage(alice.did, commentsConfigure.message);
|
|
610
|
+
// Alice (tenant) writes at the `$ref` position using the WRONG schema.
|
|
611
|
+
// The type at position 'thread' should resolve from the threads protocol, which expects
|
|
612
|
+
// schema 'https://threads.example.com/schemas/thread'. Using a different schema should fail.
|
|
613
|
+
const wrongSchemaWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
614
|
+
author: alice,
|
|
615
|
+
protocol: commentsProtocol.protocol,
|
|
616
|
+
protocolPath: 'thread',
|
|
617
|
+
schema: 'https://comments.example.com/schemas/comment', // wrong schema
|
|
618
|
+
dataFormat: 'application/json',
|
|
619
|
+
});
|
|
620
|
+
const reply = yield dwn.processMessage(alice.did, wrongSchemaWrite.message, { dataStream: wrongSchemaWrite.dataStream });
|
|
621
|
+
expect(reply.status.code).toBe(400);
|
|
622
|
+
// Type verification should fail because the schema doesn't match the referenced protocol's type
|
|
623
|
+
}));
|
|
624
|
+
});
|
|
625
|
+
// =========================================================================
|
|
626
|
+
// Cross-protocol role invocation tests
|
|
627
|
+
// =========================================================================
|
|
628
|
+
describe('cross-protocol role invocation', () => {
|
|
629
|
+
it('should allow a cross-protocol role holder to perform actions in the composing protocol', () => __awaiter(this, void 0, void 0, function* () {
|
|
630
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
631
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
632
|
+
// Install threads protocol on Alice's DWN
|
|
633
|
+
const threadsConfigure = yield ProtocolsConfigure.create({
|
|
634
|
+
definition: threadsProtocol,
|
|
635
|
+
signer: Jws.createSigner(alice),
|
|
636
|
+
});
|
|
637
|
+
const threadsReply = yield dwn.processMessage(alice.did, threadsConfigure.message);
|
|
638
|
+
expect(threadsReply.status.code).toBe(202);
|
|
639
|
+
// Install comments protocol on Alice's DWN
|
|
640
|
+
const commentsConfigure = yield ProtocolsConfigure.create({
|
|
641
|
+
definition: commentsProtocol,
|
|
642
|
+
signer: Jws.createSigner(alice),
|
|
643
|
+
});
|
|
644
|
+
const commentsReply = yield dwn.processMessage(alice.did, commentsConfigure.message);
|
|
645
|
+
expect(commentsReply.status.code).toBe(202);
|
|
646
|
+
// Alice creates a thread
|
|
647
|
+
const threadWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
648
|
+
author: alice,
|
|
649
|
+
protocol: threadsProtocol.protocol,
|
|
650
|
+
protocolPath: 'thread',
|
|
651
|
+
schema: 'https://threads.example.com/schemas/thread',
|
|
652
|
+
dataFormat: 'application/json',
|
|
653
|
+
});
|
|
654
|
+
const threadReply = yield dwn.processMessage(alice.did, threadWrite.message, { dataStream: threadWrite.dataStream });
|
|
655
|
+
expect(threadReply.status.code).toBe(202);
|
|
656
|
+
const threadContextId = threadWrite.message.contextId;
|
|
657
|
+
// Alice assigns Bob as a participant in the thread (role record in threads protocol)
|
|
658
|
+
const participantWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
659
|
+
author: alice,
|
|
660
|
+
recipient: bob.did,
|
|
661
|
+
protocol: threadsProtocol.protocol,
|
|
662
|
+
protocolPath: 'thread/participant',
|
|
663
|
+
schema: 'https://threads.example.com/schemas/participant',
|
|
664
|
+
dataFormat: 'application/json',
|
|
665
|
+
parentContextId: threadContextId,
|
|
666
|
+
});
|
|
667
|
+
const participantReply = yield dwn.processMessage(alice.did, participantWrite.message, { dataStream: participantWrite.dataStream });
|
|
668
|
+
expect(participantReply.status.code).toBe(202);
|
|
669
|
+
// Bob invokes the cross-protocol role to read comments
|
|
670
|
+
const commentWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
671
|
+
author: alice,
|
|
672
|
+
protocol: commentsProtocol.protocol,
|
|
673
|
+
protocolPath: 'thread/comment',
|
|
674
|
+
schema: 'https://comments.example.com/schemas/comment',
|
|
675
|
+
dataFormat: 'application/json',
|
|
676
|
+
parentContextId: threadContextId,
|
|
677
|
+
});
|
|
678
|
+
const commentReply = yield dwn.processMessage(alice.did, commentWrite.message, { dataStream: commentWrite.dataStream });
|
|
679
|
+
expect(commentReply.status.code).toBe(202);
|
|
680
|
+
// Bob reads the comment using the cross-protocol role
|
|
681
|
+
const bobRead = yield RecordsRead.create({
|
|
682
|
+
signer: Jws.createSigner(bob),
|
|
683
|
+
protocolRole: 'threads:thread/participant',
|
|
684
|
+
filter: {
|
|
685
|
+
protocol: commentsProtocol.protocol,
|
|
686
|
+
protocolPath: 'thread/comment',
|
|
687
|
+
contextId: threadContextId,
|
|
688
|
+
},
|
|
689
|
+
});
|
|
690
|
+
const bobReadReply = yield dwn.processMessage(alice.did, bobRead.message);
|
|
691
|
+
expect(bobReadReply.status.code).toBe(200);
|
|
692
|
+
}));
|
|
693
|
+
it('should allow a cross-protocol role holder to query records in the composing protocol', () => __awaiter(this, void 0, void 0, function* () {
|
|
694
|
+
var _a;
|
|
695
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
696
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
697
|
+
// Install both protocols on Alice's DWN
|
|
698
|
+
const threadsConfigure = yield ProtocolsConfigure.create({
|
|
699
|
+
definition: threadsProtocol,
|
|
700
|
+
signer: Jws.createSigner(alice),
|
|
701
|
+
});
|
|
702
|
+
yield dwn.processMessage(alice.did, threadsConfigure.message);
|
|
703
|
+
const commentsConfigure = yield ProtocolsConfigure.create({
|
|
704
|
+
definition: commentsProtocol,
|
|
705
|
+
signer: Jws.createSigner(alice),
|
|
706
|
+
});
|
|
707
|
+
yield dwn.processMessage(alice.did, commentsConfigure.message);
|
|
708
|
+
// Alice creates a thread
|
|
709
|
+
const threadWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
710
|
+
author: alice,
|
|
711
|
+
protocol: threadsProtocol.protocol,
|
|
712
|
+
protocolPath: 'thread',
|
|
713
|
+
schema: 'https://threads.example.com/schemas/thread',
|
|
714
|
+
dataFormat: 'application/json',
|
|
715
|
+
});
|
|
716
|
+
yield dwn.processMessage(alice.did, threadWrite.message, { dataStream: threadWrite.dataStream });
|
|
717
|
+
const threadContextId = threadWrite.message.contextId;
|
|
718
|
+
// Alice assigns Bob as a participant
|
|
719
|
+
const participantWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
720
|
+
author: alice,
|
|
721
|
+
recipient: bob.did,
|
|
722
|
+
protocol: threadsProtocol.protocol,
|
|
723
|
+
protocolPath: 'thread/participant',
|
|
724
|
+
schema: 'https://threads.example.com/schemas/participant',
|
|
725
|
+
dataFormat: 'application/json',
|
|
726
|
+
parentContextId: threadContextId,
|
|
727
|
+
});
|
|
728
|
+
yield dwn.processMessage(alice.did, participantWrite.message, { dataStream: participantWrite.dataStream });
|
|
729
|
+
// Alice creates two comments
|
|
730
|
+
const comment1 = yield TestDataGenerator.generateRecordsWrite({
|
|
731
|
+
author: alice,
|
|
732
|
+
protocol: commentsProtocol.protocol,
|
|
733
|
+
protocolPath: 'thread/comment',
|
|
734
|
+
schema: 'https://comments.example.com/schemas/comment',
|
|
735
|
+
dataFormat: 'application/json',
|
|
736
|
+
parentContextId: threadContextId,
|
|
737
|
+
});
|
|
738
|
+
yield dwn.processMessage(alice.did, comment1.message, { dataStream: comment1.dataStream });
|
|
739
|
+
const comment2 = yield TestDataGenerator.generateRecordsWrite({
|
|
740
|
+
author: alice,
|
|
741
|
+
protocol: commentsProtocol.protocol,
|
|
742
|
+
protocolPath: 'thread/comment',
|
|
743
|
+
schema: 'https://comments.example.com/schemas/comment',
|
|
744
|
+
dataFormat: 'application/json',
|
|
745
|
+
parentContextId: threadContextId,
|
|
746
|
+
});
|
|
747
|
+
yield dwn.processMessage(alice.did, comment2.message, { dataStream: comment2.dataStream });
|
|
748
|
+
// Bob queries comments using the cross-protocol role
|
|
749
|
+
const bobQuery = yield RecordsQuery.create({
|
|
750
|
+
signer: Jws.createSigner(bob),
|
|
751
|
+
protocolRole: 'threads:thread/participant',
|
|
752
|
+
filter: {
|
|
753
|
+
protocol: commentsProtocol.protocol,
|
|
754
|
+
protocolPath: 'thread/comment',
|
|
755
|
+
contextId: threadContextId,
|
|
756
|
+
},
|
|
757
|
+
});
|
|
758
|
+
const bobQueryReply = yield dwn.processMessage(alice.did, bobQuery.message);
|
|
759
|
+
expect(bobQueryReply.status.code).toBe(200);
|
|
760
|
+
expect((_a = bobQueryReply.entries) === null || _a === void 0 ? void 0 : _a.length).toBe(2);
|
|
761
|
+
}));
|
|
762
|
+
it('should allow a cross-protocol role holder to co-delete records in the composing protocol', () => __awaiter(this, void 0, void 0, function* () {
|
|
763
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
764
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
765
|
+
const carol = yield TestDataGenerator.generateDidKeyPersona();
|
|
766
|
+
// Install both protocols on Alice's DWN
|
|
767
|
+
const threadsConfigure = yield ProtocolsConfigure.create({
|
|
768
|
+
definition: threadsProtocol,
|
|
769
|
+
signer: Jws.createSigner(alice),
|
|
770
|
+
});
|
|
771
|
+
yield dwn.processMessage(alice.did, threadsConfigure.message);
|
|
772
|
+
const commentsConfigure = yield ProtocolsConfigure.create({
|
|
773
|
+
definition: commentsProtocol,
|
|
774
|
+
signer: Jws.createSigner(alice),
|
|
775
|
+
});
|
|
776
|
+
yield dwn.processMessage(alice.did, commentsConfigure.message);
|
|
777
|
+
// Alice creates a thread
|
|
778
|
+
const threadWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
779
|
+
author: alice,
|
|
780
|
+
protocol: threadsProtocol.protocol,
|
|
781
|
+
protocolPath: 'thread',
|
|
782
|
+
schema: 'https://threads.example.com/schemas/thread',
|
|
783
|
+
dataFormat: 'application/json',
|
|
784
|
+
});
|
|
785
|
+
yield dwn.processMessage(alice.did, threadWrite.message, { dataStream: threadWrite.dataStream });
|
|
786
|
+
const threadContextId = threadWrite.message.contextId;
|
|
787
|
+
// Alice assigns Bob as a participant (role record)
|
|
788
|
+
const participantWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
789
|
+
author: alice,
|
|
790
|
+
recipient: bob.did,
|
|
791
|
+
protocol: threadsProtocol.protocol,
|
|
792
|
+
protocolPath: 'thread/participant',
|
|
793
|
+
schema: 'https://threads.example.com/schemas/participant',
|
|
794
|
+
dataFormat: 'application/json',
|
|
795
|
+
parentContextId: threadContextId,
|
|
796
|
+
});
|
|
797
|
+
yield dwn.processMessage(alice.did, participantWrite.message, { dataStream: participantWrite.dataStream });
|
|
798
|
+
// Carol creates a comment (via 'anyone' can 'create')
|
|
799
|
+
const carolComment = yield TestDataGenerator.generateRecordsWrite({
|
|
800
|
+
author: carol,
|
|
801
|
+
protocol: commentsProtocol.protocol,
|
|
802
|
+
protocolPath: 'thread/comment',
|
|
803
|
+
schema: 'https://comments.example.com/schemas/comment',
|
|
804
|
+
dataFormat: 'application/json',
|
|
805
|
+
parentContextId: threadContextId,
|
|
806
|
+
});
|
|
807
|
+
yield dwn.processMessage(alice.did, carolComment.message, { dataStream: carolComment.dataStream });
|
|
808
|
+
// Bob (participant) co-deletes Carol's comment using the cross-protocol role
|
|
809
|
+
// The commentsProtocol grants 'threads:thread/participant' the 'co-delete' action on comments
|
|
810
|
+
const bobDelete = yield RecordsDelete.create({
|
|
811
|
+
protocolRole: 'threads:thread/participant',
|
|
812
|
+
recordId: carolComment.message.recordId,
|
|
813
|
+
signer: Jws.createSigner(bob),
|
|
814
|
+
});
|
|
815
|
+
const deleteReply = yield dwn.processMessage(alice.did, bobDelete.message);
|
|
816
|
+
expect(deleteReply.status.code).toBe(202);
|
|
817
|
+
}));
|
|
818
|
+
it('should deny cross-protocol role access when the role record has been deleted (revocation)', () => __awaiter(this, void 0, void 0, function* () {
|
|
819
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
820
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
821
|
+
// Install both protocols on Alice's DWN
|
|
822
|
+
const threadsConfigure = yield ProtocolsConfigure.create({
|
|
823
|
+
definition: threadsProtocol,
|
|
824
|
+
signer: Jws.createSigner(alice),
|
|
825
|
+
});
|
|
826
|
+
yield dwn.processMessage(alice.did, threadsConfigure.message);
|
|
827
|
+
const commentsConfigure = yield ProtocolsConfigure.create({
|
|
828
|
+
definition: commentsProtocol,
|
|
829
|
+
signer: Jws.createSigner(alice),
|
|
830
|
+
});
|
|
831
|
+
yield dwn.processMessage(alice.did, commentsConfigure.message);
|
|
832
|
+
// Alice creates a thread
|
|
833
|
+
const threadWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
834
|
+
author: alice,
|
|
835
|
+
protocol: threadsProtocol.protocol,
|
|
836
|
+
protocolPath: 'thread',
|
|
837
|
+
schema: 'https://threads.example.com/schemas/thread',
|
|
838
|
+
dataFormat: 'application/json',
|
|
839
|
+
});
|
|
840
|
+
yield dwn.processMessage(alice.did, threadWrite.message, { dataStream: threadWrite.dataStream });
|
|
841
|
+
const threadContextId = threadWrite.message.contextId;
|
|
842
|
+
// Alice assigns Bob as a participant
|
|
843
|
+
const participantWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
844
|
+
author: alice,
|
|
845
|
+
recipient: bob.did,
|
|
846
|
+
protocol: threadsProtocol.protocol,
|
|
847
|
+
protocolPath: 'thread/participant',
|
|
848
|
+
schema: 'https://threads.example.com/schemas/participant',
|
|
849
|
+
dataFormat: 'application/json',
|
|
850
|
+
parentContextId: threadContextId,
|
|
851
|
+
});
|
|
852
|
+
yield dwn.processMessage(alice.did, participantWrite.message, { dataStream: participantWrite.dataStream });
|
|
853
|
+
// Alice creates a comment
|
|
854
|
+
const commentWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
855
|
+
author: alice,
|
|
856
|
+
protocol: commentsProtocol.protocol,
|
|
857
|
+
protocolPath: 'thread/comment',
|
|
858
|
+
schema: 'https://comments.example.com/schemas/comment',
|
|
859
|
+
dataFormat: 'application/json',
|
|
860
|
+
parentContextId: threadContextId,
|
|
861
|
+
});
|
|
862
|
+
yield dwn.processMessage(alice.did, commentWrite.message, { dataStream: commentWrite.dataStream });
|
|
863
|
+
// Verify Bob CAN read the comment (role is active)
|
|
864
|
+
const bobRead = yield RecordsRead.create({
|
|
865
|
+
signer: Jws.createSigner(bob),
|
|
866
|
+
protocolRole: 'threads:thread/participant',
|
|
867
|
+
filter: {
|
|
868
|
+
protocol: commentsProtocol.protocol,
|
|
869
|
+
protocolPath: 'thread/comment',
|
|
870
|
+
contextId: threadContextId,
|
|
871
|
+
},
|
|
872
|
+
});
|
|
873
|
+
const bobReadReply = yield dwn.processMessage(alice.did, bobRead.message);
|
|
874
|
+
expect(bobReadReply.status.code).toBe(200);
|
|
875
|
+
// Alice deletes Bob's participant role record (revocation)
|
|
876
|
+
const deleteRole = yield RecordsDelete.create({
|
|
877
|
+
recordId: participantWrite.message.recordId,
|
|
878
|
+
signer: Jws.createSigner(alice),
|
|
879
|
+
});
|
|
880
|
+
const deleteRoleReply = yield dwn.processMessage(alice.did, deleteRole.message);
|
|
881
|
+
expect(deleteRoleReply.status.code).toBe(202);
|
|
882
|
+
// Bob tries to read the comment again — should be denied because role was deleted
|
|
883
|
+
const bobRead2 = yield RecordsRead.create({
|
|
884
|
+
signer: Jws.createSigner(bob),
|
|
885
|
+
protocolRole: 'threads:thread/participant',
|
|
886
|
+
filter: {
|
|
887
|
+
protocol: commentsProtocol.protocol,
|
|
888
|
+
protocolPath: 'thread/comment',
|
|
889
|
+
contextId: threadContextId,
|
|
890
|
+
},
|
|
891
|
+
});
|
|
892
|
+
const bobRead2Reply = yield dwn.processMessage(alice.did, bobRead2.message);
|
|
893
|
+
expect(bobRead2Reply.status.code).toBe(401);
|
|
894
|
+
expect(bobRead2Reply.status.detail).toContain(DwnErrorCode.ProtocolAuthorizationMatchingRoleRecordNotFound);
|
|
895
|
+
}));
|
|
896
|
+
it('should reject a cross-protocol role invocation if the invoker lacks the role record', () => __awaiter(this, void 0, void 0, function* () {
|
|
897
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
898
|
+
const carol = yield TestDataGenerator.generateDidKeyPersona();
|
|
899
|
+
// Install both protocols
|
|
900
|
+
const threadsConfigure = yield ProtocolsConfigure.create({
|
|
901
|
+
definition: threadsProtocol,
|
|
902
|
+
signer: Jws.createSigner(alice),
|
|
903
|
+
});
|
|
904
|
+
yield dwn.processMessage(alice.did, threadsConfigure.message);
|
|
905
|
+
const commentsConfigure = yield ProtocolsConfigure.create({
|
|
906
|
+
definition: commentsProtocol,
|
|
907
|
+
signer: Jws.createSigner(alice),
|
|
908
|
+
});
|
|
909
|
+
yield dwn.processMessage(alice.did, commentsConfigure.message);
|
|
910
|
+
// Alice creates a thread
|
|
911
|
+
const threadWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
912
|
+
author: alice,
|
|
913
|
+
protocol: threadsProtocol.protocol,
|
|
914
|
+
protocolPath: 'thread',
|
|
915
|
+
schema: 'https://threads.example.com/schemas/thread',
|
|
916
|
+
dataFormat: 'application/json',
|
|
917
|
+
});
|
|
918
|
+
yield dwn.processMessage(alice.did, threadWrite.message, { dataStream: threadWrite.dataStream });
|
|
919
|
+
const threadContextId = threadWrite.message.contextId;
|
|
920
|
+
// Alice creates a comment
|
|
921
|
+
const commentWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
922
|
+
author: alice,
|
|
923
|
+
protocol: commentsProtocol.protocol,
|
|
924
|
+
protocolPath: 'thread/comment',
|
|
925
|
+
schema: 'https://comments.example.com/schemas/comment',
|
|
926
|
+
dataFormat: 'application/json',
|
|
927
|
+
parentContextId: threadContextId,
|
|
928
|
+
});
|
|
929
|
+
yield dwn.processMessage(alice.did, commentWrite.message, { dataStream: commentWrite.dataStream });
|
|
930
|
+
// Carol (who has NO participant role) tries to read the comment using the cross-protocol role
|
|
931
|
+
const carolRead = yield RecordsRead.create({
|
|
932
|
+
signer: Jws.createSigner(carol),
|
|
933
|
+
protocolRole: 'threads:thread/participant',
|
|
934
|
+
filter: {
|
|
935
|
+
protocol: commentsProtocol.protocol,
|
|
936
|
+
protocolPath: 'thread/comment',
|
|
937
|
+
contextId: threadContextId,
|
|
938
|
+
},
|
|
939
|
+
});
|
|
940
|
+
const carolReadReply = yield dwn.processMessage(alice.did, carolRead.message);
|
|
941
|
+
expect(carolReadReply.status.code).toBe(401);
|
|
942
|
+
expect(carolReadReply.status.detail).toContain(DwnErrorCode.ProtocolAuthorizationMatchingRoleRecordNotFound);
|
|
943
|
+
}));
|
|
944
|
+
});
|
|
945
|
+
// =========================================================================
|
|
946
|
+
// Cross-protocol `who`/`of` actor checks
|
|
947
|
+
// =========================================================================
|
|
948
|
+
describe('cross-protocol `who`/`of` actor checks', () => {
|
|
949
|
+
it('should allow `author` of a cross-protocol parent to perform actions in the composing protocol', () => __awaiter(this, void 0, void 0, function* () {
|
|
950
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
951
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
952
|
+
// Install both protocols
|
|
953
|
+
const threadsConfigure = yield ProtocolsConfigure.create({
|
|
954
|
+
definition: threadsProtocol,
|
|
955
|
+
signer: Jws.createSigner(alice),
|
|
956
|
+
});
|
|
957
|
+
yield dwn.processMessage(alice.did, threadsConfigure.message);
|
|
958
|
+
const commentsConfigure = yield ProtocolsConfigure.create({
|
|
959
|
+
definition: commentsProtocol,
|
|
960
|
+
signer: Jws.createSigner(alice),
|
|
961
|
+
});
|
|
962
|
+
yield dwn.processMessage(alice.did, commentsConfigure.message);
|
|
963
|
+
// Bob creates a thread (via the 'anyone' can 'create' rule)
|
|
964
|
+
const threadWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
965
|
+
author: bob,
|
|
966
|
+
protocol: threadsProtocol.protocol,
|
|
967
|
+
protocolPath: 'thread',
|
|
968
|
+
schema: 'https://threads.example.com/schemas/thread',
|
|
969
|
+
dataFormat: 'application/json',
|
|
970
|
+
});
|
|
971
|
+
const threadReply = yield dwn.processMessage(alice.did, threadWrite.message, { dataStream: threadWrite.dataStream });
|
|
972
|
+
expect(threadReply.status.code).toBe(202);
|
|
973
|
+
const threadContextId = threadWrite.message.contextId;
|
|
974
|
+
// Anyone can create a comment under the thread (via 'anyone' can 'create' rule)
|
|
975
|
+
const commentWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
976
|
+
author: alice,
|
|
977
|
+
protocol: commentsProtocol.protocol,
|
|
978
|
+
protocolPath: 'thread/comment',
|
|
979
|
+
schema: 'https://comments.example.com/schemas/comment',
|
|
980
|
+
dataFormat: 'application/json',
|
|
981
|
+
parentContextId: threadContextId,
|
|
982
|
+
});
|
|
983
|
+
const commentReply = yield dwn.processMessage(alice.did, commentWrite.message, { dataStream: commentWrite.dataStream });
|
|
984
|
+
expect(commentReply.status.code).toBe(202);
|
|
985
|
+
// Anyone can also read (via 'anyone' can 'read' rule)
|
|
986
|
+
const readComment = yield RecordsRead.create({
|
|
987
|
+
signer: Jws.createSigner(bob),
|
|
988
|
+
filter: {
|
|
989
|
+
protocol: commentsProtocol.protocol,
|
|
990
|
+
protocolPath: 'thread/comment',
|
|
991
|
+
contextId: threadContextId,
|
|
992
|
+
},
|
|
993
|
+
});
|
|
994
|
+
const readReply = yield dwn.processMessage(alice.did, readComment.message);
|
|
995
|
+
expect(readReply.status.code).toBe(200);
|
|
996
|
+
}));
|
|
997
|
+
});
|
|
998
|
+
// =========================================================================
|
|
999
|
+
// Cross-protocol `of` actor check — happy path
|
|
1000
|
+
// =========================================================================
|
|
1001
|
+
describe('cross-protocol `of` actor check — happy path', () => {
|
|
1002
|
+
it('should allow author of cross-protocol parent to create records via `who: author, of: alias:path` rule', () => __awaiter(this, void 0, void 0, function* () {
|
|
1003
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1004
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
1005
|
+
const carol = yield TestDataGenerator.generateDidKeyPersona();
|
|
1006
|
+
// A protocol that grants the author of a thread (from the threads protocol) the ability to create moderation actions
|
|
1007
|
+
const moderationProtocol = {
|
|
1008
|
+
protocol: 'https://moderation.example.com',
|
|
1009
|
+
published: true,
|
|
1010
|
+
uses: { threads: 'https://threads.example.com' },
|
|
1011
|
+
types: {
|
|
1012
|
+
action: { schema: 'https://moderation.example.com/schemas/action', dataFormats: ['application/json'] },
|
|
1013
|
+
},
|
|
1014
|
+
structure: {
|
|
1015
|
+
thread: {
|
|
1016
|
+
$ref: 'threads:thread',
|
|
1017
|
+
action: {
|
|
1018
|
+
$actions: [
|
|
1019
|
+
{ who: 'author', of: 'threads:thread', can: ['create'] },
|
|
1020
|
+
{ who: 'anyone', can: ['read'] },
|
|
1021
|
+
],
|
|
1022
|
+
},
|
|
1023
|
+
},
|
|
1024
|
+
},
|
|
1025
|
+
};
|
|
1026
|
+
// Install both protocols on Alice's DWN
|
|
1027
|
+
const threadsConfigure = yield ProtocolsConfigure.create({
|
|
1028
|
+
definition: threadsProtocol,
|
|
1029
|
+
signer: Jws.createSigner(alice),
|
|
1030
|
+
});
|
|
1031
|
+
yield dwn.processMessage(alice.did, threadsConfigure.message);
|
|
1032
|
+
const moderationConfigure = yield ProtocolsConfigure.create({
|
|
1033
|
+
definition: moderationProtocol,
|
|
1034
|
+
signer: Jws.createSigner(alice),
|
|
1035
|
+
});
|
|
1036
|
+
const modReply = yield dwn.processMessage(alice.did, moderationConfigure.message);
|
|
1037
|
+
expect(modReply.status.code).toBe(202);
|
|
1038
|
+
// Bob creates a thread (via 'anyone' can 'create' in threadsProtocol)
|
|
1039
|
+
const threadWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
1040
|
+
author: bob,
|
|
1041
|
+
protocol: threadsProtocol.protocol,
|
|
1042
|
+
protocolPath: 'thread',
|
|
1043
|
+
schema: 'https://threads.example.com/schemas/thread',
|
|
1044
|
+
dataFormat: 'application/json',
|
|
1045
|
+
});
|
|
1046
|
+
const threadReply = yield dwn.processMessage(alice.did, threadWrite.message, { dataStream: threadWrite.dataStream });
|
|
1047
|
+
expect(threadReply.status.code).toBe(202);
|
|
1048
|
+
const threadContextId = threadWrite.message.contextId;
|
|
1049
|
+
// Bob (as author of the thread) creates a moderation action — should succeed
|
|
1050
|
+
const actionWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
1051
|
+
author: bob,
|
|
1052
|
+
protocol: moderationProtocol.protocol,
|
|
1053
|
+
protocolPath: 'thread/action',
|
|
1054
|
+
schema: 'https://moderation.example.com/schemas/action',
|
|
1055
|
+
dataFormat: 'application/json',
|
|
1056
|
+
parentContextId: threadContextId,
|
|
1057
|
+
});
|
|
1058
|
+
const actionReply = yield dwn.processMessage(alice.did, actionWrite.message, { dataStream: actionWrite.dataStream });
|
|
1059
|
+
expect(actionReply.status.code).toBe(202);
|
|
1060
|
+
// Carol (NOT author of the thread, NOT the tenant) tries to create a moderation action — should fail
|
|
1061
|
+
const carolActionWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
1062
|
+
author: carol,
|
|
1063
|
+
protocol: moderationProtocol.protocol,
|
|
1064
|
+
protocolPath: 'thread/action',
|
|
1065
|
+
schema: 'https://moderation.example.com/schemas/action',
|
|
1066
|
+
dataFormat: 'application/json',
|
|
1067
|
+
parentContextId: threadContextId,
|
|
1068
|
+
});
|
|
1069
|
+
const carolActionReply = yield dwn.processMessage(alice.did, carolActionWrite.message, { dataStream: carolActionWrite.dataStream });
|
|
1070
|
+
expect(carolActionReply.status.code).toBe(401);
|
|
1071
|
+
expect(carolActionReply.status.detail).toContain(DwnErrorCode.ProtocolAuthorizationActionNotAllowed);
|
|
1072
|
+
}));
|
|
1073
|
+
});
|
|
1074
|
+
// =========================================================================
|
|
1075
|
+
// Edge case and error tests
|
|
1076
|
+
// =========================================================================
|
|
1077
|
+
describe('composition error cases', () => {
|
|
1078
|
+
it('should reject `$ref` with malformed format (no colon separator)', () => __awaiter(this, void 0, void 0, function* () {
|
|
1079
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1080
|
+
const badDefinition = {
|
|
1081
|
+
protocol: 'https://bad.example.com',
|
|
1082
|
+
published: true,
|
|
1083
|
+
uses: { threads: 'https://threads.example.com' },
|
|
1084
|
+
types: { comment: {} },
|
|
1085
|
+
structure: {
|
|
1086
|
+
thread: {
|
|
1087
|
+
$ref: 'threadsthread', // missing colon — rejected by JSON schema pattern
|
|
1088
|
+
comment: {
|
|
1089
|
+
$actions: [{ who: 'anyone', can: ['create'] }],
|
|
1090
|
+
},
|
|
1091
|
+
},
|
|
1092
|
+
},
|
|
1093
|
+
};
|
|
1094
|
+
try {
|
|
1095
|
+
yield ProtocolsConfigure.create({
|
|
1096
|
+
definition: badDefinition,
|
|
1097
|
+
signer: Jws.createSigner(alice),
|
|
1098
|
+
});
|
|
1099
|
+
throw new Error('Expected an error to be thrown');
|
|
1100
|
+
}
|
|
1101
|
+
catch (error) {
|
|
1102
|
+
// JSON schema enforces `$ref` must match pattern `^[a-zA-Z][a-zA-Z0-9_-]*:.+$`
|
|
1103
|
+
expect(error.message).toContain('must match pattern');
|
|
1104
|
+
}
|
|
1105
|
+
}));
|
|
1106
|
+
it('should reject `$ref` that references own protocol', () => __awaiter(this, void 0, void 0, function* () {
|
|
1107
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1108
|
+
const badDefinition = {
|
|
1109
|
+
protocol: 'https://self.example.com',
|
|
1110
|
+
published: true,
|
|
1111
|
+
uses: { self: 'https://self.example.com' },
|
|
1112
|
+
types: { comment: {} },
|
|
1113
|
+
structure: {
|
|
1114
|
+
thread: {
|
|
1115
|
+
$ref: 'self:thread',
|
|
1116
|
+
comment: {
|
|
1117
|
+
$actions: [{ who: 'anyone', can: ['create'] }],
|
|
1118
|
+
},
|
|
1119
|
+
},
|
|
1120
|
+
},
|
|
1121
|
+
};
|
|
1122
|
+
try {
|
|
1123
|
+
yield ProtocolsConfigure.create({
|
|
1124
|
+
definition: badDefinition,
|
|
1125
|
+
signer: Jws.createSigner(alice),
|
|
1126
|
+
});
|
|
1127
|
+
throw new Error('Expected an error to be thrown');
|
|
1128
|
+
}
|
|
1129
|
+
catch (error) {
|
|
1130
|
+
expect(error.message).toContain(DwnErrorCode.ProtocolsConfigureInvalidUsesSelfReference);
|
|
1131
|
+
}
|
|
1132
|
+
}));
|
|
1133
|
+
it('should reject `uses` with invalid alias name (starts with a number)', () => __awaiter(this, void 0, void 0, function* () {
|
|
1134
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1135
|
+
const badDefinition = {
|
|
1136
|
+
protocol: 'https://bad.example.com',
|
|
1137
|
+
published: true,
|
|
1138
|
+
uses: { '123invalid': 'https://foo.example.com' },
|
|
1139
|
+
types: {},
|
|
1140
|
+
structure: {},
|
|
1141
|
+
};
|
|
1142
|
+
try {
|
|
1143
|
+
yield ProtocolsConfigure.create({
|
|
1144
|
+
definition: badDefinition,
|
|
1145
|
+
signer: Jws.createSigner(alice),
|
|
1146
|
+
});
|
|
1147
|
+
throw new Error('Expected an error to be thrown');
|
|
1148
|
+
}
|
|
1149
|
+
catch (error) {
|
|
1150
|
+
// JSON schema enforces alias pattern `^[a-zA-Z][a-zA-Z0-9_-]*$` via additionalProperties: false
|
|
1151
|
+
expect(error.message).toContain('must NOT have additional properties');
|
|
1152
|
+
}
|
|
1153
|
+
}));
|
|
1154
|
+
it('should reject cross-protocol `of` with alias not in `uses`', () => __awaiter(this, void 0, void 0, function* () {
|
|
1155
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1156
|
+
const badDefinition = {
|
|
1157
|
+
protocol: 'https://bad.example.com',
|
|
1158
|
+
published: true,
|
|
1159
|
+
uses: { threads: 'https://threads.example.com' },
|
|
1160
|
+
types: { action: {} },
|
|
1161
|
+
structure: {
|
|
1162
|
+
thread: {
|
|
1163
|
+
$ref: 'threads:thread',
|
|
1164
|
+
action: {
|
|
1165
|
+
$actions: [
|
|
1166
|
+
{ who: 'author', of: 'nonexistent:thread', can: ['create'] }, // alias 'nonexistent' not in uses
|
|
1167
|
+
],
|
|
1168
|
+
},
|
|
1169
|
+
},
|
|
1170
|
+
},
|
|
1171
|
+
};
|
|
1172
|
+
try {
|
|
1173
|
+
yield ProtocolsConfigure.create({
|
|
1174
|
+
definition: badDefinition,
|
|
1175
|
+
signer: Jws.createSigner(alice),
|
|
1176
|
+
});
|
|
1177
|
+
throw new Error('Expected an error to be thrown');
|
|
1178
|
+
}
|
|
1179
|
+
catch (error) {
|
|
1180
|
+
expect(error.message).toContain(DwnErrorCode.ProtocolsConfigureInvalidCrossProtocolOf);
|
|
1181
|
+
}
|
|
1182
|
+
}));
|
|
1183
|
+
it('should return 400 when cross-protocol parent record does not exist at runtime', () => __awaiter(this, void 0, void 0, function* () {
|
|
1184
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1185
|
+
// Install both protocols
|
|
1186
|
+
const threadsConfigure = yield ProtocolsConfigure.create({
|
|
1187
|
+
definition: threadsProtocol,
|
|
1188
|
+
signer: Jws.createSigner(alice),
|
|
1189
|
+
});
|
|
1190
|
+
yield dwn.processMessage(alice.did, threadsConfigure.message);
|
|
1191
|
+
const commentsConfigure = yield ProtocolsConfigure.create({
|
|
1192
|
+
definition: commentsProtocol,
|
|
1193
|
+
signer: Jws.createSigner(alice),
|
|
1194
|
+
});
|
|
1195
|
+
yield dwn.processMessage(alice.did, commentsConfigure.message);
|
|
1196
|
+
// Try to create a comment under a non-existent thread (fabricate a contextId)
|
|
1197
|
+
const fakeThreadContextId = 'bafybeifake1234567890';
|
|
1198
|
+
const commentWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
1199
|
+
author: alice,
|
|
1200
|
+
protocol: commentsProtocol.protocol,
|
|
1201
|
+
protocolPath: 'thread/comment',
|
|
1202
|
+
schema: 'https://comments.example.com/schemas/comment',
|
|
1203
|
+
dataFormat: 'application/json',
|
|
1204
|
+
parentContextId: fakeThreadContextId,
|
|
1205
|
+
});
|
|
1206
|
+
const reply = yield dwn.processMessage(alice.did, commentWrite.message, { dataStream: commentWrite.dataStream });
|
|
1207
|
+
expect(reply.status.code).toBe(400);
|
|
1208
|
+
expect(reply.status.detail).toContain(DwnErrorCode.ProtocolAuthorizationCrossProtocolParentNotFound);
|
|
1209
|
+
}));
|
|
1210
|
+
it('should reject `$ref` at non-root protocol path', () => __awaiter(this, void 0, void 0, function* () {
|
|
1211
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1212
|
+
const badDefinition = {
|
|
1213
|
+
protocol: 'https://bad.example.com',
|
|
1214
|
+
published: true,
|
|
1215
|
+
uses: { threads: 'https://threads.example.com' },
|
|
1216
|
+
types: { wrapper: {}, nested: {} },
|
|
1217
|
+
structure: {
|
|
1218
|
+
wrapper: {
|
|
1219
|
+
nested: {
|
|
1220
|
+
$ref: 'threads:thread', // $ref at depth > 1 — not allowed
|
|
1221
|
+
},
|
|
1222
|
+
},
|
|
1223
|
+
},
|
|
1224
|
+
};
|
|
1225
|
+
try {
|
|
1226
|
+
yield ProtocolsConfigure.create({
|
|
1227
|
+
definition: badDefinition,
|
|
1228
|
+
signer: Jws.createSigner(alice),
|
|
1229
|
+
});
|
|
1230
|
+
throw new Error('Expected an error to be thrown');
|
|
1231
|
+
}
|
|
1232
|
+
catch (error) {
|
|
1233
|
+
expect(error.message).toContain(DwnErrorCode.ProtocolsConfigureInvalidRefNotAtRoot);
|
|
1234
|
+
}
|
|
1235
|
+
}));
|
|
1236
|
+
it('should reject `uses` with empty alias map', () => __awaiter(this, void 0, void 0, function* () {
|
|
1237
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1238
|
+
const badDefinition = {
|
|
1239
|
+
protocol: 'https://bad.example.com',
|
|
1240
|
+
published: true,
|
|
1241
|
+
uses: {},
|
|
1242
|
+
types: {},
|
|
1243
|
+
structure: {},
|
|
1244
|
+
};
|
|
1245
|
+
try {
|
|
1246
|
+
yield ProtocolsConfigure.create({
|
|
1247
|
+
definition: badDefinition,
|
|
1248
|
+
signer: Jws.createSigner(alice),
|
|
1249
|
+
});
|
|
1250
|
+
throw new Error('Expected an error to be thrown');
|
|
1251
|
+
}
|
|
1252
|
+
catch (error) {
|
|
1253
|
+
// JSON schema enforces minProperties: 1 on `uses`
|
|
1254
|
+
expect(error.message).toContain('must NOT have fewer than 1 properties');
|
|
1255
|
+
}
|
|
1256
|
+
}));
|
|
1257
|
+
});
|
|
1258
|
+
// =========================================================================
|
|
1259
|
+
// Temporal correctness — governing timestamp for cross-protocol lookups
|
|
1260
|
+
// =========================================================================
|
|
1261
|
+
describe('temporal correctness — governing timestamp', () => {
|
|
1262
|
+
it('should use the governing timestamp when fetching the referenced protocol for role verification', () => __awaiter(this, void 0, void 0, function* () {
|
|
1263
|
+
// Scenario:
|
|
1264
|
+
// 1. Install threads V1 (participant has $role: true)
|
|
1265
|
+
// 2. Install comments protocol (uses threads, references threads:thread/participant role)
|
|
1266
|
+
// 3. Create thread, assign Bob as participant, create comment — all under V1
|
|
1267
|
+
// 4. Update threads to V2 where participant is no longer a role ($role removed)
|
|
1268
|
+
// 5. Bob reads the comment using the cross-protocol role
|
|
1269
|
+
// → should SUCCEED because the comment's governing timestamp pins to threads V1
|
|
1270
|
+
const alice = yield TestDataGenerator.generateDidKeyPersona();
|
|
1271
|
+
const bob = yield TestDataGenerator.generateDidKeyPersona();
|
|
1272
|
+
// threads V1: participant is a role
|
|
1273
|
+
const threadsV1 = {
|
|
1274
|
+
protocol: 'https://threads-versioned.example.com',
|
|
1275
|
+
published: true,
|
|
1276
|
+
types: {
|
|
1277
|
+
thread: { schema: 'https://threads-versioned.example.com/schemas/thread', dataFormats: ['application/json'] },
|
|
1278
|
+
participant: { schema: 'https://threads-versioned.example.com/schemas/participant', dataFormats: ['application/json'] },
|
|
1279
|
+
},
|
|
1280
|
+
structure: {
|
|
1281
|
+
thread: {
|
|
1282
|
+
$actions: [{ who: 'anyone', can: ['create', 'read'] }],
|
|
1283
|
+
participant: {
|
|
1284
|
+
$role: true,
|
|
1285
|
+
$actions: [
|
|
1286
|
+
{ who: 'anyone', can: ['read'] },
|
|
1287
|
+
{ who: 'author', of: 'thread', can: ['create'] },
|
|
1288
|
+
],
|
|
1289
|
+
},
|
|
1290
|
+
},
|
|
1291
|
+
},
|
|
1292
|
+
};
|
|
1293
|
+
// comments protocol: references threads-versioned
|
|
1294
|
+
const commentsVersioned = {
|
|
1295
|
+
protocol: 'https://comments-versioned.example.com',
|
|
1296
|
+
published: true,
|
|
1297
|
+
uses: { threads: 'https://threads-versioned.example.com' },
|
|
1298
|
+
types: {
|
|
1299
|
+
comment: { schema: 'https://comments-versioned.example.com/schemas/comment', dataFormats: ['application/json'] },
|
|
1300
|
+
},
|
|
1301
|
+
structure: {
|
|
1302
|
+
thread: {
|
|
1303
|
+
$ref: 'threads:thread',
|
|
1304
|
+
comment: {
|
|
1305
|
+
$actions: [
|
|
1306
|
+
{ who: 'anyone', can: ['create'] },
|
|
1307
|
+
{ role: 'threads:thread/participant', can: ['read'] },
|
|
1308
|
+
],
|
|
1309
|
+
},
|
|
1310
|
+
},
|
|
1311
|
+
},
|
|
1312
|
+
};
|
|
1313
|
+
// Install threads V1
|
|
1314
|
+
const threadsV1Configure = yield ProtocolsConfigure.create({
|
|
1315
|
+
definition: threadsV1,
|
|
1316
|
+
signer: Jws.createSigner(alice),
|
|
1317
|
+
});
|
|
1318
|
+
const threadsV1Reply = yield dwn.processMessage(alice.did, threadsV1Configure.message);
|
|
1319
|
+
expect(threadsV1Reply.status.code).toBe(202);
|
|
1320
|
+
// Install comments protocol (depends on threads)
|
|
1321
|
+
const commentsConfigure = yield ProtocolsConfigure.create({
|
|
1322
|
+
definition: commentsVersioned,
|
|
1323
|
+
signer: Jws.createSigner(alice),
|
|
1324
|
+
});
|
|
1325
|
+
const commentsReply = yield dwn.processMessage(alice.did, commentsConfigure.message);
|
|
1326
|
+
expect(commentsReply.status.code).toBe(202);
|
|
1327
|
+
// Alice creates a thread
|
|
1328
|
+
const threadWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
1329
|
+
author: alice,
|
|
1330
|
+
protocol: threadsV1.protocol,
|
|
1331
|
+
protocolPath: 'thread',
|
|
1332
|
+
schema: 'https://threads-versioned.example.com/schemas/thread',
|
|
1333
|
+
dataFormat: 'application/json',
|
|
1334
|
+
});
|
|
1335
|
+
yield dwn.processMessage(alice.did, threadWrite.message, { dataStream: threadWrite.dataStream });
|
|
1336
|
+
const threadContextId = threadWrite.message.contextId;
|
|
1337
|
+
// Alice assigns Bob as participant (role record in threads V1)
|
|
1338
|
+
const participantWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
1339
|
+
author: alice,
|
|
1340
|
+
recipient: bob.did,
|
|
1341
|
+
protocol: threadsV1.protocol,
|
|
1342
|
+
protocolPath: 'thread/participant',
|
|
1343
|
+
schema: 'https://threads-versioned.example.com/schemas/participant',
|
|
1344
|
+
dataFormat: 'application/json',
|
|
1345
|
+
parentContextId: threadContextId,
|
|
1346
|
+
});
|
|
1347
|
+
yield dwn.processMessage(alice.did, participantWrite.message, { dataStream: participantWrite.dataStream });
|
|
1348
|
+
// Alice creates a comment (under V1)
|
|
1349
|
+
const commentWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
1350
|
+
author: alice,
|
|
1351
|
+
protocol: commentsVersioned.protocol,
|
|
1352
|
+
protocolPath: 'thread/comment',
|
|
1353
|
+
schema: 'https://comments-versioned.example.com/schemas/comment',
|
|
1354
|
+
dataFormat: 'application/json',
|
|
1355
|
+
parentContextId: threadContextId,
|
|
1356
|
+
});
|
|
1357
|
+
yield dwn.processMessage(alice.did, commentWrite.message, { dataStream: commentWrite.dataStream });
|
|
1358
|
+
// Wait to ensure V2 gets a later timestamp
|
|
1359
|
+
yield Time.minimalSleep();
|
|
1360
|
+
// threads V2: participant is NO LONGER a role ($role removed)
|
|
1361
|
+
const threadsV2 = {
|
|
1362
|
+
protocol: 'https://threads-versioned.example.com',
|
|
1363
|
+
published: true,
|
|
1364
|
+
types: {
|
|
1365
|
+
thread: { schema: 'https://threads-versioned.example.com/schemas/thread', dataFormats: ['application/json'] },
|
|
1366
|
+
participant: { schema: 'https://threads-versioned.example.com/schemas/participant', dataFormats: ['application/json'] },
|
|
1367
|
+
},
|
|
1368
|
+
structure: {
|
|
1369
|
+
thread: {
|
|
1370
|
+
$actions: [{ who: 'anyone', can: ['create', 'read'] }],
|
|
1371
|
+
participant: {
|
|
1372
|
+
// $role is removed — participant is no longer a role in V2
|
|
1373
|
+
$actions: [
|
|
1374
|
+
{ who: 'anyone', can: ['read'] },
|
|
1375
|
+
{ who: 'author', of: 'thread', can: ['create'] },
|
|
1376
|
+
],
|
|
1377
|
+
},
|
|
1378
|
+
},
|
|
1379
|
+
},
|
|
1380
|
+
};
|
|
1381
|
+
const threadsV2Configure = yield ProtocolsConfigure.create({
|
|
1382
|
+
definition: threadsV2,
|
|
1383
|
+
signer: Jws.createSigner(alice),
|
|
1384
|
+
});
|
|
1385
|
+
const threadsV2Reply = yield dwn.processMessage(alice.did, threadsV2Configure.message);
|
|
1386
|
+
expect(threadsV2Reply.status.code).toBe(202);
|
|
1387
|
+
// Bob reads the comment using the cross-protocol role.
|
|
1388
|
+
// The comment was created under V1. The governing timestamp pins the referenced protocol
|
|
1389
|
+
// lookup to V1 where participant IS a valid role. This should SUCCEED.
|
|
1390
|
+
const bobRead = yield RecordsRead.create({
|
|
1391
|
+
signer: Jws.createSigner(bob),
|
|
1392
|
+
protocolRole: 'threads:thread/participant',
|
|
1393
|
+
filter: {
|
|
1394
|
+
protocol: commentsVersioned.protocol,
|
|
1395
|
+
protocolPath: 'thread/comment',
|
|
1396
|
+
contextId: threadContextId,
|
|
1397
|
+
},
|
|
1398
|
+
});
|
|
1399
|
+
const bobReadReply = yield dwn.processMessage(alice.did, bobRead.message);
|
|
1400
|
+
expect(bobReadReply.status.code).toBe(200);
|
|
1401
|
+
}));
|
|
1402
|
+
});
|
|
1403
|
+
// =========================================================================
|
|
1404
|
+
// Encryption + composition tests
|
|
1405
|
+
// =========================================================================
|
|
1406
|
+
describe('encryption with protocol composition', () => {
|
|
1407
|
+
let encryptionPrivateJwk;
|
|
1408
|
+
let encryptionRootKeyId;
|
|
1409
|
+
beforeAll(() => __awaiter(this, void 0, void 0, function* () {
|
|
1410
|
+
const { privateJwk } = yield Secp256k1.generateKeyPair();
|
|
1411
|
+
encryptionPrivateJwk = privateJwk;
|
|
1412
|
+
encryptionRootKeyId = 'did:example:alice#enc';
|
|
1413
|
+
}));
|
|
1414
|
+
it('should skip `$encryption` injection on `$ref` nodes but inject on their children (raw-key path)', () => __awaiter(this, void 0, void 0, function* () {
|
|
1415
|
+
const composingProtocol = {
|
|
1416
|
+
protocol: 'https://comments.example.com',
|
|
1417
|
+
published: true,
|
|
1418
|
+
uses: { threads: 'https://threads.example.com' },
|
|
1419
|
+
types: {
|
|
1420
|
+
comment: { schema: 'https://comments.example.com/schemas/comment', dataFormats: ['application/json'] },
|
|
1421
|
+
reaction: { schema: 'https://comments.example.com/schemas/reaction', dataFormats: ['application/json'] },
|
|
1422
|
+
},
|
|
1423
|
+
structure: {
|
|
1424
|
+
thread: {
|
|
1425
|
+
$ref: 'threads:thread',
|
|
1426
|
+
comment: {
|
|
1427
|
+
$actions: [{ who: 'anyone', can: ['create', 'read'] }],
|
|
1428
|
+
reaction: {
|
|
1429
|
+
$actions: [{ who: 'anyone', can: ['create', 'read'] }],
|
|
1430
|
+
},
|
|
1431
|
+
},
|
|
1432
|
+
},
|
|
1433
|
+
},
|
|
1434
|
+
};
|
|
1435
|
+
const result = yield Protocols.deriveAndInjectPublicEncryptionKeys(composingProtocol, encryptionRootKeyId, encryptionPrivateJwk);
|
|
1436
|
+
// $ref node must NOT have $encryption
|
|
1437
|
+
expect(result.structure.thread.$encryption).toBeUndefined();
|
|
1438
|
+
// Children of $ref node MUST have $encryption
|
|
1439
|
+
expect(result.structure.thread.comment.$encryption).toBeDefined();
|
|
1440
|
+
expect(result.structure.thread.comment.$encryption.rootKeyId).toBe(encryptionRootKeyId);
|
|
1441
|
+
expect(result.structure.thread.comment.$encryption.publicKeyJwk).toBeDefined();
|
|
1442
|
+
// Grandchild of $ref node
|
|
1443
|
+
expect(result.structure.thread.comment.reaction.$encryption).toBeDefined();
|
|
1444
|
+
expect(result.structure.thread.comment.reaction.$encryption.rootKeyId).toBe(encryptionRootKeyId);
|
|
1445
|
+
}));
|
|
1446
|
+
it('should skip `$encryption` injection on `$ref` nodes but inject on their children (callback path)', () => __awaiter(this, void 0, void 0, function* () {
|
|
1447
|
+
const composingProtocol = {
|
|
1448
|
+
protocol: 'https://comments.example.com',
|
|
1449
|
+
published: true,
|
|
1450
|
+
uses: { threads: 'https://threads.example.com' },
|
|
1451
|
+
types: {
|
|
1452
|
+
comment: { schema: 'https://comments.example.com/schemas/comment', dataFormats: ['application/json'] },
|
|
1453
|
+
reaction: { schema: 'https://comments.example.com/schemas/reaction', dataFormats: ['application/json'] },
|
|
1454
|
+
},
|
|
1455
|
+
structure: {
|
|
1456
|
+
thread: {
|
|
1457
|
+
$ref: 'threads:thread',
|
|
1458
|
+
comment: {
|
|
1459
|
+
$actions: [{ who: 'anyone', can: ['create', 'read'] }],
|
|
1460
|
+
reaction: {
|
|
1461
|
+
$actions: [{ who: 'anyone', can: ['create', 'read'] }],
|
|
1462
|
+
},
|
|
1463
|
+
},
|
|
1464
|
+
},
|
|
1465
|
+
},
|
|
1466
|
+
};
|
|
1467
|
+
const calledPaths = [];
|
|
1468
|
+
const keyDeriver = {
|
|
1469
|
+
rootKeyId: encryptionRootKeyId,
|
|
1470
|
+
derivationScheme: KeyDerivationScheme.ProtocolPath,
|
|
1471
|
+
derivePublicKey: (fullDerivationPath) => __awaiter(this, void 0, void 0, function* () {
|
|
1472
|
+
calledPaths.push([...fullDerivationPath]);
|
|
1473
|
+
const privateKeyBytes = Secp256k1.privateJwkToBytes(encryptionPrivateJwk);
|
|
1474
|
+
const derivedPrivateKeyBytes = yield HdKey.derivePrivateKeyBytes(privateKeyBytes, fullDerivationPath);
|
|
1475
|
+
const derivedPublicKeyBytes = yield Secp256k1.getPublicKey(derivedPrivateKeyBytes);
|
|
1476
|
+
return Secp256k1.publicKeyToJwk(derivedPublicKeyBytes);
|
|
1477
|
+
}),
|
|
1478
|
+
};
|
|
1479
|
+
const result = yield Protocols.deriveAndInjectPublicEncryptionKeys(composingProtocol, keyDeriver);
|
|
1480
|
+
// $ref node must NOT have $encryption
|
|
1481
|
+
expect(result.structure.thread.$encryption).toBeUndefined();
|
|
1482
|
+
// Children of $ref node MUST have $encryption
|
|
1483
|
+
expect(result.structure.thread.comment.$encryption).toBeDefined();
|
|
1484
|
+
expect(result.structure.thread.comment.reaction.$encryption).toBeDefined();
|
|
1485
|
+
// derivePublicKey should NOT have been called for the $ref node itself
|
|
1486
|
+
const threadPath = [KeyDerivationScheme.ProtocolPath, 'https://comments.example.com', 'thread'];
|
|
1487
|
+
expect(calledPaths).not.toContainEqual(threadPath);
|
|
1488
|
+
// derivePublicKey SHOULD have been called for children
|
|
1489
|
+
const commentPath = [KeyDerivationScheme.ProtocolPath, 'https://comments.example.com', 'thread', 'comment'];
|
|
1490
|
+
const reactionPath = [KeyDerivationScheme.ProtocolPath, 'https://comments.example.com', 'thread', 'comment', 'reaction'];
|
|
1491
|
+
expect(calledPaths).toContainEqual(commentPath);
|
|
1492
|
+
expect(calledPaths).toContainEqual(reactionPath);
|
|
1493
|
+
}));
|
|
1494
|
+
it('should produce identical $encryption for children across both overloads', () => __awaiter(this, void 0, void 0, function* () {
|
|
1495
|
+
const composingProtocol = {
|
|
1496
|
+
protocol: 'https://comments.example.com',
|
|
1497
|
+
published: true,
|
|
1498
|
+
uses: { threads: 'https://threads.example.com' },
|
|
1499
|
+
types: {
|
|
1500
|
+
comment: { schema: 'https://comments.example.com/schemas/comment', dataFormats: ['application/json'] },
|
|
1501
|
+
},
|
|
1502
|
+
structure: {
|
|
1503
|
+
thread: {
|
|
1504
|
+
$ref: 'threads:thread',
|
|
1505
|
+
comment: {},
|
|
1506
|
+
},
|
|
1507
|
+
},
|
|
1508
|
+
};
|
|
1509
|
+
// Raw-key path
|
|
1510
|
+
const resultA = yield Protocols.deriveAndInjectPublicEncryptionKeys(composingProtocol, encryptionRootKeyId, encryptionPrivateJwk);
|
|
1511
|
+
// Callback path
|
|
1512
|
+
const keyDeriver = {
|
|
1513
|
+
rootKeyId: encryptionRootKeyId,
|
|
1514
|
+
derivationScheme: KeyDerivationScheme.ProtocolPath,
|
|
1515
|
+
derivePublicKey: (fullDerivationPath) => __awaiter(this, void 0, void 0, function* () {
|
|
1516
|
+
const privateKeyBytes = Secp256k1.privateJwkToBytes(encryptionPrivateJwk);
|
|
1517
|
+
const derivedPrivateKeyBytes = yield HdKey.derivePrivateKeyBytes(privateKeyBytes, fullDerivationPath);
|
|
1518
|
+
const derivedPublicKeyBytes = yield Secp256k1.getPublicKey(derivedPrivateKeyBytes);
|
|
1519
|
+
return Secp256k1.publicKeyToJwk(derivedPublicKeyBytes);
|
|
1520
|
+
}),
|
|
1521
|
+
};
|
|
1522
|
+
const resultB = yield Protocols.deriveAndInjectPublicEncryptionKeys(composingProtocol, keyDeriver);
|
|
1523
|
+
// Both paths must skip $ref
|
|
1524
|
+
expect(resultA.structure.thread.$encryption).toBeUndefined();
|
|
1525
|
+
expect(resultB.structure.thread.$encryption).toBeUndefined();
|
|
1526
|
+
// Both paths must produce identical $encryption on children
|
|
1527
|
+
expect(resultA.structure.thread.comment.$encryption.publicKeyJwk).toEqual(resultB.structure.thread.comment.$encryption.publicKeyJwk);
|
|
1528
|
+
expect(resultA.structure.thread.comment.$encryption.rootKeyId).toBe(resultB.structure.thread.comment.$encryption.rootKeyId);
|
|
1529
|
+
}));
|
|
1530
|
+
it('should successfully install a composing protocol with encryption after $ref skip', () => __awaiter(this, void 0, void 0, function* () {
|
|
1531
|
+
// This test verifies the full pipeline: inject encryption keys → ProtocolsConfigure.create()
|
|
1532
|
+
// → validateRefNode() passes because $ref node has no $encryption.
|
|
1533
|
+
const alice = yield TestDataGenerator.generatePersona();
|
|
1534
|
+
TestStubGenerator.stubDidResolver(didResolver, [alice]);
|
|
1535
|
+
// Install the threads protocol first (required dependency)
|
|
1536
|
+
const threadsConfigure = yield ProtocolsConfigure.create({
|
|
1537
|
+
definition: threadsProtocol,
|
|
1538
|
+
signer: Jws.createSigner(alice),
|
|
1539
|
+
});
|
|
1540
|
+
const threadsInstallReply = yield dwn.processMessage(alice.did, threadsConfigure.message);
|
|
1541
|
+
expect(threadsInstallReply.status.code).toBe(202);
|
|
1542
|
+
// Inject encryption keys into the composing protocol
|
|
1543
|
+
const encryptedComments = yield Protocols.deriveAndInjectPublicEncryptionKeys(commentsProtocol, alice.keyId, alice.keyPair.privateJwk);
|
|
1544
|
+
// $ref node should not have $encryption
|
|
1545
|
+
expect(encryptedComments.structure.thread.$encryption).toBeUndefined();
|
|
1546
|
+
// Children should have $encryption
|
|
1547
|
+
expect(encryptedComments.structure.thread.comment.$encryption).toBeDefined();
|
|
1548
|
+
// ProtocolsConfigure.create() should NOT throw — validateRefNode() will pass
|
|
1549
|
+
// because $ref node has no forbidden directives
|
|
1550
|
+
const commentsConfigure = yield ProtocolsConfigure.create({
|
|
1551
|
+
definition: encryptedComments,
|
|
1552
|
+
signer: Jws.createSigner(alice),
|
|
1553
|
+
});
|
|
1554
|
+
// Install should succeed
|
|
1555
|
+
const commentsInstallReply = yield dwn.processMessage(alice.did, commentsConfigure.message);
|
|
1556
|
+
expect(commentsInstallReply.status.code).toBe(202);
|
|
1557
|
+
}));
|
|
1558
|
+
it('should encrypt and decrypt a child record written under a `$ref` parent', () => __awaiter(this, void 0, void 0, function* () {
|
|
1559
|
+
// Full round-trip: install both protocols → write parent → write encrypted child → read and decrypt
|
|
1560
|
+
const alice = yield TestDataGenerator.generatePersona();
|
|
1561
|
+
TestStubGenerator.stubDidResolver(didResolver, [alice]);
|
|
1562
|
+
// 1. Install the threads protocol (parent)
|
|
1563
|
+
const threadsConfigure = yield ProtocolsConfigure.create({
|
|
1564
|
+
definition: threadsProtocol,
|
|
1565
|
+
signer: Jws.createSigner(alice),
|
|
1566
|
+
});
|
|
1567
|
+
const threadsReply = yield dwn.processMessage(alice.did, threadsConfigure.message);
|
|
1568
|
+
expect(threadsReply.status.code).toBe(202);
|
|
1569
|
+
// 2. Install the comments protocol with encryption keys
|
|
1570
|
+
const encryptedComments = yield Protocols.deriveAndInjectPublicEncryptionKeys(commentsProtocol, alice.keyId, alice.keyPair.privateJwk);
|
|
1571
|
+
const commentsConfigure = yield ProtocolsConfigure.create({
|
|
1572
|
+
definition: encryptedComments,
|
|
1573
|
+
signer: Jws.createSigner(alice),
|
|
1574
|
+
});
|
|
1575
|
+
const commentsReply = yield dwn.processMessage(alice.did, commentsConfigure.message);
|
|
1576
|
+
expect(commentsReply.status.code).toBe(202);
|
|
1577
|
+
// 3. Write a thread record (in the threads protocol — the $ref parent)
|
|
1578
|
+
const threadWrite = yield TestDataGenerator.generateRecordsWrite({
|
|
1579
|
+
author: alice,
|
|
1580
|
+
protocol: threadsProtocol.protocol,
|
|
1581
|
+
protocolPath: 'thread',
|
|
1582
|
+
schema: 'https://threads.example.com/schemas/thread',
|
|
1583
|
+
dataFormat: 'application/json',
|
|
1584
|
+
});
|
|
1585
|
+
const threadWriteReply = yield dwn.processMessage(alice.did, threadWrite.message, { dataStream: threadWrite.dataStream });
|
|
1586
|
+
expect(threadWriteReply.status.code).toBe(202);
|
|
1587
|
+
const threadContextId = threadWrite.message.contextId;
|
|
1588
|
+
// 4. Write an encrypted comment (child of $ref parent, in the comments protocol)
|
|
1589
|
+
const plaintext = 'This is a secret comment';
|
|
1590
|
+
const plaintextBytes = Encoder.stringToBytes(plaintext);
|
|
1591
|
+
const encryptedComment = yield TestDataGenerator.generateProtocolEncryptedRecordsWrite({
|
|
1592
|
+
plaintextBytes,
|
|
1593
|
+
author: alice,
|
|
1594
|
+
protocolDefinition: encryptedComments,
|
|
1595
|
+
protocolPath: 'thread/comment',
|
|
1596
|
+
protocolParentContextId: threadContextId,
|
|
1597
|
+
encryptSymmetricKeyWithProtocolPathDerivedKey: true,
|
|
1598
|
+
encryptSymmetricKeyWithProtocolContextDerivedKey: false,
|
|
1599
|
+
});
|
|
1600
|
+
const commentWriteReply = yield dwn.processMessage(alice.did, encryptedComment.message, { dataStream: DataStream.fromBytes(encryptedComment.encryptedDataBytes) });
|
|
1601
|
+
expect(commentWriteReply.status.code).toBe(202);
|
|
1602
|
+
// 5. Read the encrypted comment back
|
|
1603
|
+
const readMessage = yield RecordsRead.create({
|
|
1604
|
+
signer: Jws.createSigner(alice),
|
|
1605
|
+
filter: { recordId: encryptedComment.message.recordId },
|
|
1606
|
+
});
|
|
1607
|
+
const readReply = yield dwn.processMessage(alice.did, readMessage.message);
|
|
1608
|
+
expect(readReply.status.code).toBe(200);
|
|
1609
|
+
// 6. Decrypt using the composing protocol's key hierarchy.
|
|
1610
|
+
// The key derivation path is [protocolPath, commentsProtocol.protocol, 'thread', 'comment']
|
|
1611
|
+
// — note this uses the COMPOSING protocol's URI, not the threads protocol's URI,
|
|
1612
|
+
// because the comment record's descriptor.protocol is the comments protocol.
|
|
1613
|
+
const rootKey = {
|
|
1614
|
+
rootKeyId: alice.keyId,
|
|
1615
|
+
derivationScheme: KeyDerivationScheme.ProtocolPath,
|
|
1616
|
+
derivedPrivateKey: alice.keyPair.privateJwk,
|
|
1617
|
+
};
|
|
1618
|
+
const decryptedStream = yield Records.decrypt(readReply.entry.recordsWrite, rootKey, readReply.entry.data);
|
|
1619
|
+
const decryptedBytes = yield DataStream.toBytes(decryptedStream);
|
|
1620
|
+
expect(Encoder.bytesToString(decryptedBytes)).toBe(plaintext);
|
|
1621
|
+
}));
|
|
1622
|
+
it('should not inject `$encryption` on the original protocol definition (immutability)', () => __awaiter(this, void 0, void 0, function* () {
|
|
1623
|
+
const composingProtocol = {
|
|
1624
|
+
protocol: 'https://comments.example.com',
|
|
1625
|
+
published: true,
|
|
1626
|
+
uses: { threads: 'https://threads.example.com' },
|
|
1627
|
+
types: {
|
|
1628
|
+
comment: { schema: 'https://comments.example.com/schemas/comment', dataFormats: ['application/json'] },
|
|
1629
|
+
},
|
|
1630
|
+
structure: {
|
|
1631
|
+
thread: {
|
|
1632
|
+
$ref: 'threads:thread',
|
|
1633
|
+
comment: {},
|
|
1634
|
+
},
|
|
1635
|
+
},
|
|
1636
|
+
};
|
|
1637
|
+
yield Protocols.deriveAndInjectPublicEncryptionKeys(composingProtocol, encryptionRootKeyId, encryptionPrivateJwk);
|
|
1638
|
+
// Original must be unmodified
|
|
1639
|
+
expect(composingProtocol.structure.thread.$encryption).toBeUndefined();
|
|
1640
|
+
expect(composingProtocol.structure.thread.comment.$encryption).toBeUndefined();
|
|
1641
|
+
}));
|
|
1642
|
+
});
|
|
1643
|
+
});
|
|
1644
|
+
}
|
|
1645
|
+
//# sourceMappingURL=protocol-composition.spec.js.map
|