@enbox/dwn-sdk-js 0.3.9 → 0.4.1
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 +4 -4
- package/dist/browser.mjs +11 -11
- package/dist/browser.mjs.map +4 -4
- package/dist/esm/generated/precompiled-validators.js +783 -1206
- package/dist/esm/generated/precompiled-validators.js.map +1 -1
- package/dist/esm/src/core/dwn-constant.js +5 -0
- package/dist/esm/src/core/dwn-constant.js.map +1 -1
- package/dist/esm/src/core/dwn-error.js +13 -7
- package/dist/esm/src/core/dwn-error.js.map +1 -1
- package/dist/esm/src/core/grant-authorization.js +9 -18
- package/dist/esm/src/core/grant-authorization.js.map +1 -1
- package/dist/esm/src/core/message-reply.js.map +1 -1
- package/dist/esm/src/core/messages-grant-authorization.js +28 -61
- package/dist/esm/src/core/messages-grant-authorization.js.map +1 -1
- package/dist/esm/src/core/protocol-authorization-action.js +25 -27
- package/dist/esm/src/core/protocol-authorization-action.js.map +1 -1
- package/dist/esm/src/core/protocol-authorization-validation.js +31 -69
- package/dist/esm/src/core/protocol-authorization-validation.js.map +1 -1
- package/dist/esm/src/core/protocol-authorization.js +44 -118
- package/dist/esm/src/core/protocol-authorization.js.map +1 -1
- package/dist/esm/src/core/protocols-grant-authorization.js +5 -5
- package/dist/esm/src/core/protocols-grant-authorization.js.map +1 -1
- package/dist/esm/src/core/recording-validation-state-reader.js +84 -0
- package/dist/esm/src/core/recording-validation-state-reader.js.map +1 -0
- package/dist/esm/src/core/records-grant-authorization.js +11 -11
- package/dist/esm/src/core/records-grant-authorization.js.map +1 -1
- package/dist/esm/src/core/replication-apply.js +295 -0
- package/dist/esm/src/core/replication-apply.js.map +1 -0
- package/dist/esm/src/core/resumable-task-manager.js +5 -4
- package/dist/esm/src/core/resumable-task-manager.js.map +1 -1
- package/dist/esm/src/core/validation-state-reader.js +237 -0
- package/dist/esm/src/core/validation-state-reader.js.map +1 -0
- package/dist/esm/src/dwn.js +261 -16
- package/dist/esm/src/dwn.js.map +1 -1
- package/dist/esm/src/enums/dwn-interface-method.js +0 -1
- package/dist/esm/src/enums/dwn-interface-method.js.map +1 -1
- package/dist/esm/src/event-stream/durable-event-log.js +365 -0
- package/dist/esm/src/event-stream/durable-event-log.js.map +1 -0
- package/dist/esm/src/event-stream/event-emitter-wake-publisher.js +25 -0
- package/dist/esm/src/event-stream/event-emitter-wake-publisher.js.map +1 -0
- package/dist/esm/src/handlers/messages-query.js +159 -0
- package/dist/esm/src/handlers/messages-query.js.map +1 -0
- package/dist/esm/src/handlers/messages-read.js +5 -5
- package/dist/esm/src/handlers/messages-read.js.map +1 -1
- package/dist/esm/src/handlers/messages-subscribe.js +8 -8
- package/dist/esm/src/handlers/messages-subscribe.js.map +1 -1
- package/dist/esm/src/handlers/protocols-configure.js +30 -49
- package/dist/esm/src/handlers/protocols-configure.js.map +1 -1
- package/dist/esm/src/handlers/protocols-query.js +1 -1
- package/dist/esm/src/handlers/protocols-query.js.map +1 -1
- package/dist/esm/src/handlers/records-count.js +20 -11
- package/dist/esm/src/handlers/records-count.js.map +1 -1
- package/dist/esm/src/handlers/records-delete.js +20 -16
- package/dist/esm/src/handlers/records-delete.js.map +1 -1
- package/dist/esm/src/handlers/records-query.js +35 -11
- package/dist/esm/src/handlers/records-query.js.map +1 -1
- package/dist/esm/src/handlers/records-read.js +52 -42
- package/dist/esm/src/handlers/records-read.js.map +1 -1
- package/dist/esm/src/handlers/records-subscribe.js +107 -11
- package/dist/esm/src/handlers/records-subscribe.js.map +1 -1
- package/dist/esm/src/handlers/records-write.js +62 -116
- package/dist/esm/src/handlers/records-write.js.map +1 -1
- package/dist/esm/src/index.js +7 -8
- package/dist/esm/src/index.js.map +1 -1
- package/dist/esm/src/interfaces/messages-query.js +49 -0
- package/dist/esm/src/interfaces/messages-query.js.map +1 -0
- package/dist/esm/src/interfaces/protocols-configure.js +7 -3
- package/dist/esm/src/interfaces/protocols-configure.js.map +1 -1
- package/dist/esm/src/interfaces/protocols-query.js +3 -4
- package/dist/esm/src/interfaces/protocols-query.js.map +1 -1
- package/dist/esm/src/interfaces/records-count.js +4 -3
- package/dist/esm/src/interfaces/records-count.js.map +1 -1
- package/dist/esm/src/interfaces/records-delete.js +21 -4
- package/dist/esm/src/interfaces/records-delete.js.map +1 -1
- package/dist/esm/src/interfaces/records-query.js +4 -3
- package/dist/esm/src/interfaces/records-query.js.map +1 -1
- package/dist/esm/src/interfaces/records-read.js +3 -3
- package/dist/esm/src/interfaces/records-read.js.map +1 -1
- package/dist/esm/src/interfaces/records-subscribe.js +4 -3
- package/dist/esm/src/interfaces/records-subscribe.js.map +1 -1
- package/dist/esm/src/interfaces/records-write.js +27 -13
- package/dist/esm/src/interfaces/records-write.js.map +1 -1
- package/dist/esm/src/protocols/permissions.js +27 -34
- package/dist/esm/src/protocols/permissions.js.map +1 -1
- package/dist/esm/src/store/index-level.js +24 -9
- package/dist/esm/src/store/index-level.js.map +1 -1
- package/dist/esm/src/store/level-wrapper.js +7 -0
- package/dist/esm/src/store/level-wrapper.js.map +1 -1
- package/dist/esm/src/store/message-store-level.js +536 -42
- package/dist/esm/src/store/message-store-level.js.map +1 -1
- package/dist/esm/src/store/storage-controller.js +58 -49
- package/dist/esm/src/store/storage-controller.js.map +1 -1
- package/dist/esm/src/types/message-types.js.map +1 -1
- package/dist/esm/src/types/validation-state-reader.js +2 -0
- package/dist/esm/src/types/validation-state-reader.js.map +1 -0
- package/dist/esm/src/utils/messages.js +17 -0
- package/dist/esm/src/utils/messages.js.map +1 -1
- package/dist/esm/src/utils/record-limit-occupancy.js +244 -0
- package/dist/esm/src/utils/record-limit-occupancy.js.map +1 -0
- package/dist/esm/src/utils/records.js +50 -14
- package/dist/esm/src/utils/records.js.map +1 -1
- package/dist/esm/src/utils/replication.js +85 -0
- package/dist/esm/src/utils/replication.js.map +1 -0
- package/dist/esm/tests/core/grant-authorization.spec.js +4 -4
- package/dist/esm/tests/core/grant-authorization.spec.js.map +1 -1
- package/dist/esm/tests/core/process-message-parity.spec.js +222 -0
- package/dist/esm/tests/core/process-message-parity.spec.js.map +1 -0
- package/dist/esm/tests/core/protocol-authorization.spec.js +5 -2
- package/dist/esm/tests/core/protocol-authorization.spec.js.map +1 -1
- package/dist/esm/tests/core/records-grant-authorization.spec.js +5 -5
- package/dist/esm/tests/core/records-grant-authorization.spec.js.map +1 -1
- package/dist/esm/tests/core/replication-apply.spec.js +274 -0
- package/dist/esm/tests/core/replication-apply.spec.js.map +1 -0
- package/dist/esm/tests/core/replication-replay-property.spec.js +350 -0
- package/dist/esm/tests/core/replication-replay-property.spec.js.map +1 -0
- package/dist/esm/tests/core/validation-read-closure.spec.js +469 -0
- package/dist/esm/tests/core/validation-read-closure.spec.js.map +1 -0
- package/dist/esm/tests/core/validation-state-reader.spec.js +716 -0
- package/dist/esm/tests/core/validation-state-reader.spec.js.map +1 -0
- package/dist/esm/tests/durable-event-log.spec.js +373 -0
- package/dist/esm/tests/durable-event-log.spec.js.map +1 -0
- package/dist/esm/tests/dwn.spec.js +620 -14
- package/dist/esm/tests/dwn.spec.js.map +1 -1
- package/dist/esm/tests/features/author-delegated-grant.spec.js +9 -6
- package/dist/esm/tests/features/author-delegated-grant.spec.js.map +1 -1
- package/dist/esm/tests/features/owner-delegated-grant.spec.js +1 -4
- package/dist/esm/tests/features/owner-delegated-grant.spec.js.map +1 -1
- package/dist/esm/tests/features/owner-signature.spec.js +1 -4
- package/dist/esm/tests/features/owner-signature.spec.js.map +1 -1
- package/dist/esm/tests/features/permissions.spec.js +165 -4
- package/dist/esm/tests/features/permissions.spec.js.map +1 -1
- package/dist/esm/tests/features/protocol-composition.spec.js +8 -11
- package/dist/esm/tests/features/protocol-composition.spec.js.map +1 -1
- package/dist/esm/tests/features/protocol-create-action.spec.js +1 -4
- package/dist/esm/tests/features/protocol-create-action.spec.js.map +1 -1
- package/dist/esm/tests/features/protocol-delete-action.spec.js +3 -5
- package/dist/esm/tests/features/protocol-delete-action.spec.js.map +1 -1
- package/dist/esm/tests/features/protocol-update-action.spec.js +3 -6
- package/dist/esm/tests/features/protocol-update-action.spec.js.map +1 -1
- package/dist/esm/tests/features/records-delivery.spec.js +1 -4
- package/dist/esm/tests/features/records-delivery.spec.js.map +1 -1
- package/dist/esm/tests/features/records-immutable.spec.js +1 -4
- package/dist/esm/tests/features/records-immutable.spec.js.map +1 -1
- package/dist/esm/tests/features/records-nested-query-scope.spec.js +281 -0
- package/dist/esm/tests/features/records-nested-query-scope.spec.js.map +1 -0
- package/dist/esm/tests/features/records-prune-cross-protocol.spec.js +3 -7
- package/dist/esm/tests/features/records-prune-cross-protocol.spec.js.map +1 -1
- package/dist/esm/tests/features/records-prune.spec.js +11 -22
- package/dist/esm/tests/features/records-prune.spec.js.map +1 -1
- package/dist/esm/tests/features/records-record-limit.spec.js +441 -231
- package/dist/esm/tests/features/records-record-limit.spec.js.map +1 -1
- package/dist/esm/tests/features/records-squash.spec.js +6 -4
- package/dist/esm/tests/features/records-squash.spec.js.map +1 -1
- package/dist/esm/tests/features/records-tags.spec.js +1 -4
- package/dist/esm/tests/features/records-tags.spec.js.map +1 -1
- package/dist/esm/tests/features/resumable-tasks.spec.js +3 -5
- package/dist/esm/tests/features/resumable-tasks.spec.js.map +1 -1
- package/dist/esm/tests/fuzz/message-store.fuzz.spec.js +1 -2
- package/dist/esm/tests/fuzz/message-store.fuzz.spec.js.map +1 -1
- package/dist/esm/tests/fuzz/process-message.fuzz.spec.js +2 -4
- package/dist/esm/tests/fuzz/process-message.fuzz.spec.js.map +1 -1
- package/dist/esm/tests/fuzz/schema-validation.fuzz.spec.js +1 -1
- package/dist/esm/tests/fuzz/schema-validation.fuzz.spec.js.map +1 -1
- package/dist/esm/tests/handlers/messages-query.spec.js +246 -0
- package/dist/esm/tests/handlers/messages-query.spec.js.map +1 -0
- package/dist/esm/tests/handlers/messages-read.spec.js +2 -5
- package/dist/esm/tests/handlers/messages-read.spec.js.map +1 -1
- package/dist/esm/tests/handlers/messages-subscribe.spec.js +3 -14
- package/dist/esm/tests/handlers/messages-subscribe.spec.js.map +1 -1
- package/dist/esm/tests/handlers/protocols-configure.spec.js +27 -26
- package/dist/esm/tests/handlers/protocols-configure.spec.js.map +1 -1
- package/dist/esm/tests/handlers/protocols-query.spec.js +1 -4
- package/dist/esm/tests/handlers/protocols-query.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-count.spec.js +1 -4
- package/dist/esm/tests/handlers/records-count.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-delete.spec.js +312 -30
- package/dist/esm/tests/handlers/records-delete.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-query.spec.js +32 -9
- package/dist/esm/tests/handlers/records-query.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-read.spec.js +4 -4
- package/dist/esm/tests/handlers/records-read.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-subscribe.spec.js +33 -14
- package/dist/esm/tests/handlers/records-subscribe.spec.js.map +1 -1
- package/dist/esm/tests/handlers/records-write.spec.js +84 -38
- package/dist/esm/tests/handlers/records-write.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/records-delete.spec.js +69 -2
- package/dist/esm/tests/interfaces/records-delete.spec.js.map +1 -1
- package/dist/esm/tests/interfaces/records-write.spec.js +4 -3
- package/dist/esm/tests/interfaces/records-write.spec.js.map +1 -1
- package/dist/esm/tests/protocols/permissions.spec.js +55 -6
- package/dist/esm/tests/protocols/permissions.spec.js.map +1 -1
- package/dist/esm/tests/scenarios/aggregator.spec.js +1 -4
- package/dist/esm/tests/scenarios/aggregator.spec.js.map +1 -1
- package/dist/esm/tests/scenarios/deleted-record.spec.js +1 -4
- package/dist/esm/tests/scenarios/deleted-record.spec.js.map +1 -1
- package/dist/esm/tests/scenarios/end-to-end-tests.spec.js +1 -4
- package/dist/esm/tests/scenarios/end-to-end-tests.spec.js.map +1 -1
- package/dist/esm/tests/scenarios/nested-roles.spec.js +1 -4
- package/dist/esm/tests/scenarios/nested-roles.spec.js.map +1 -1
- package/dist/esm/tests/scenarios/subscriptions.spec.js +1 -4
- package/dist/esm/tests/scenarios/subscriptions.spec.js.map +1 -1
- package/dist/esm/tests/store/message-store-level.spec.js +361 -5
- package/dist/esm/tests/store/message-store-level.spec.js.map +1 -1
- package/dist/esm/tests/store/message-store.spec.js +60 -0
- package/dist/esm/tests/store/message-store.spec.js.map +1 -1
- package/dist/esm/tests/test-event-stream.js +7 -3
- package/dist/esm/tests/test-event-stream.js.map +1 -1
- package/dist/esm/tests/test-stores.js +19 -9
- package/dist/esm/tests/test-stores.js.map +1 -1
- package/dist/esm/tests/test-suite.js +4 -4
- package/dist/esm/tests/test-suite.js.map +1 -1
- package/dist/esm/tests/utils/test-data-generator.js +25 -0
- package/dist/esm/tests/utils/test-data-generator.js.map +1 -1
- package/dist/esm/tests/utils/test-stub-generator.js.map +1 -1
- package/dist/esm/tests/utils/test-validation-state-reader.js +16 -0
- package/dist/esm/tests/utils/test-validation-state-reader.js.map +1 -0
- package/dist/types/generated/precompiled-validators.d.ts +6 -6
- package/dist/types/generated/precompiled-validators.d.ts.map +1 -1
- package/dist/types/src/core/core-protocol.d.ts +3 -3
- package/dist/types/src/core/core-protocol.d.ts.map +1 -1
- package/dist/types/src/core/dwn-constant.d.ts +5 -0
- package/dist/types/src/core/dwn-constant.d.ts.map +1 -1
- package/dist/types/src/core/dwn-error.d.ts +13 -7
- package/dist/types/src/core/dwn-error.d.ts.map +1 -1
- package/dist/types/src/core/grant-authorization.d.ts +5 -5
- package/dist/types/src/core/grant-authorization.d.ts.map +1 -1
- package/dist/types/src/core/message-reply.d.ts +5 -4
- package/dist/types/src/core/message-reply.d.ts.map +1 -1
- package/dist/types/src/core/messages-grant-authorization.d.ts +12 -15
- package/dist/types/src/core/messages-grant-authorization.d.ts.map +1 -1
- package/dist/types/src/core/protocol-authorization-action.d.ts +4 -5
- package/dist/types/src/core/protocol-authorization-action.d.ts.map +1 -1
- package/dist/types/src/core/protocol-authorization-validation.d.ts +13 -16
- package/dist/types/src/core/protocol-authorization-validation.d.ts.map +1 -1
- package/dist/types/src/core/protocol-authorization.d.ts +8 -33
- package/dist/types/src/core/protocol-authorization.d.ts.map +1 -1
- package/dist/types/src/core/protocols-grant-authorization.d.ts +4 -4
- package/dist/types/src/core/protocols-grant-authorization.d.ts.map +1 -1
- package/dist/types/src/core/recording-validation-state-reader.d.ts +75 -0
- package/dist/types/src/core/recording-validation-state-reader.d.ts.map +1 -0
- package/dist/types/src/core/records-grant-authorization.d.ts +8 -8
- package/dist/types/src/core/records-grant-authorization.d.ts.map +1 -1
- package/dist/types/src/core/replication-apply.d.ts +129 -0
- package/dist/types/src/core/replication-apply.d.ts.map +1 -0
- package/dist/types/src/core/resumable-task-manager.d.ts +1 -1
- package/dist/types/src/core/resumable-task-manager.d.ts.map +1 -1
- package/dist/types/src/core/validation-state-reader.d.ts +79 -0
- package/dist/types/src/core/validation-state-reader.d.ts.map +1 -0
- package/dist/types/src/dwn.d.ts +47 -13
- package/dist/types/src/dwn.d.ts.map +1 -1
- package/dist/types/src/enums/dwn-interface-method.d.ts +0 -1
- package/dist/types/src/enums/dwn-interface-method.d.ts.map +1 -1
- package/dist/types/src/event-stream/durable-event-log.d.ts +69 -0
- package/dist/types/src/event-stream/durable-event-log.d.ts.map +1 -0
- package/dist/types/src/event-stream/event-emitter-wake-publisher.d.ts +13 -0
- package/dist/types/src/event-stream/event-emitter-wake-publisher.d.ts.map +1 -0
- package/dist/types/src/handlers/messages-query.d.ts +20 -0
- package/dist/types/src/handlers/messages-query.d.ts.map +1 -0
- package/dist/types/src/handlers/messages-read.d.ts +1 -1
- package/dist/types/src/handlers/messages-read.d.ts.map +1 -1
- package/dist/types/src/handlers/messages-subscribe.d.ts.map +1 -1
- package/dist/types/src/handlers/protocols-configure.d.ts +0 -5
- package/dist/types/src/handlers/protocols-configure.d.ts.map +1 -1
- package/dist/types/src/handlers/records-count.d.ts +2 -1
- package/dist/types/src/handlers/records-count.d.ts.map +1 -1
- package/dist/types/src/handlers/records-delete.d.ts +2 -2
- package/dist/types/src/handlers/records-delete.d.ts.map +1 -1
- package/dist/types/src/handlers/records-query.d.ts +1 -1
- package/dist/types/src/handlers/records-query.d.ts.map +1 -1
- package/dist/types/src/handlers/records-read.d.ts +2 -1
- package/dist/types/src/handlers/records-read.d.ts.map +1 -1
- package/dist/types/src/handlers/records-subscribe.d.ts +4 -5
- package/dist/types/src/handlers/records-subscribe.d.ts.map +1 -1
- package/dist/types/src/handlers/records-write.d.ts +3 -11
- package/dist/types/src/handlers/records-write.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +16 -18
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/interfaces/messages-query.d.ts +23 -0
- package/dist/types/src/interfaces/messages-query.d.ts.map +1 -0
- package/dist/types/src/interfaces/protocols-configure.d.ts +3 -3
- 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 +3 -3
- package/dist/types/src/interfaces/records-count.d.ts.map +1 -1
- package/dist/types/src/interfaces/records-delete.d.ts +11 -3
- package/dist/types/src/interfaces/records-delete.d.ts.map +1 -1
- package/dist/types/src/interfaces/records-query.d.ts +3 -3
- package/dist/types/src/interfaces/records-query.d.ts.map +1 -1
- package/dist/types/src/interfaces/records-read.d.ts +3 -3
- package/dist/types/src/interfaces/records-read.d.ts.map +1 -1
- package/dist/types/src/interfaces/records-subscribe.d.ts +3 -3
- package/dist/types/src/interfaces/records-subscribe.d.ts.map +1 -1
- package/dist/types/src/interfaces/records-write.d.ts +15 -7
- package/dist/types/src/interfaces/records-write.d.ts.map +1 -1
- package/dist/types/src/protocols/permissions.d.ts +9 -12
- package/dist/types/src/protocols/permissions.d.ts.map +1 -1
- package/dist/types/src/store/index-level.d.ts +10 -1
- package/dist/types/src/store/index-level.d.ts.map +1 -1
- package/dist/types/src/store/level-wrapper.d.ts +5 -0
- package/dist/types/src/store/level-wrapper.d.ts.map +1 -1
- package/dist/types/src/store/message-store-level.d.ts +94 -14
- package/dist/types/src/store/message-store-level.d.ts.map +1 -1
- package/dist/types/src/store/storage-controller.d.ts +17 -14
- package/dist/types/src/store/storage-controller.d.ts.map +1 -1
- package/dist/types/src/types/message-store.d.ts +29 -1
- package/dist/types/src/types/message-store.d.ts.map +1 -1
- package/dist/types/src/types/message-types.d.ts +2 -0
- package/dist/types/src/types/message-types.d.ts.map +1 -1
- package/dist/types/src/types/messages-types.d.ts +21 -55
- package/dist/types/src/types/messages-types.d.ts.map +1 -1
- package/dist/types/src/types/method-handler.d.ts +2 -2
- package/dist/types/src/types/method-handler.d.ts.map +1 -1
- package/dist/types/src/types/permission-types.d.ts +1 -1
- package/dist/types/src/types/subscriptions.d.ts +50 -39
- package/dist/types/src/types/subscriptions.d.ts.map +1 -1
- package/dist/types/src/types/validation-state-reader.d.ts +116 -0
- package/dist/types/src/types/validation-state-reader.d.ts.map +1 -0
- package/dist/types/src/utils/messages.d.ts +10 -0
- package/dist/types/src/utils/messages.d.ts.map +1 -1
- package/dist/types/src/utils/record-limit-occupancy.d.ts +40 -0
- package/dist/types/src/utils/record-limit-occupancy.d.ts.map +1 -0
- package/dist/types/src/utils/records.d.ts +25 -3
- package/dist/types/src/utils/records.d.ts.map +1 -1
- package/dist/types/src/utils/replication.d.ts +22 -0
- package/dist/types/src/utils/replication.d.ts.map +1 -0
- package/dist/types/tests/core/process-message-parity.spec.d.ts +2 -0
- package/dist/types/tests/core/process-message-parity.spec.d.ts.map +1 -0
- package/dist/types/tests/core/replication-apply.spec.d.ts +2 -0
- package/dist/types/tests/core/replication-apply.spec.d.ts.map +1 -0
- package/dist/types/tests/core/replication-replay-property.spec.d.ts +2 -0
- package/dist/types/tests/core/replication-replay-property.spec.d.ts.map +1 -0
- package/dist/types/tests/core/validation-read-closure.spec.d.ts +2 -0
- package/dist/types/tests/core/validation-read-closure.spec.d.ts.map +1 -0
- package/dist/types/tests/core/validation-state-reader.spec.d.ts +2 -0
- package/dist/types/tests/core/validation-state-reader.spec.d.ts.map +1 -0
- package/dist/types/tests/durable-event-log.spec.d.ts +2 -0
- package/dist/types/tests/durable-event-log.spec.d.ts.map +1 -0
- package/dist/types/tests/dwn.spec.d.ts.map +1 -1
- 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.map +1 -1
- 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-delivery.spec.d.ts.map +1 -1
- package/dist/types/tests/features/records-immutable.spec.d.ts.map +1 -1
- package/dist/types/tests/features/records-nested-query-scope.spec.d.ts +2 -0
- package/dist/types/tests/features/records-nested-query-scope.spec.d.ts.map +1 -0
- package/dist/types/tests/features/records-prune-cross-protocol.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-record-limit.spec.d.ts.map +1 -1
- package/dist/types/tests/features/records-squash.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-query.spec.d.ts +2 -0
- package/dist/types/tests/handlers/messages-query.spec.d.ts.map +1 -0
- 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/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.map +1 -1
- 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/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/scenarios/subscriptions.spec.d.ts.map +1 -1
- package/dist/types/tests/store/message-store.spec.d.ts.map +1 -1
- package/dist/types/tests/test-event-stream.d.ts +1 -1
- package/dist/types/tests/test-event-stream.d.ts.map +1 -1
- package/dist/types/tests/test-stores.d.ts +5 -4
- package/dist/types/tests/test-stores.d.ts.map +1 -1
- package/dist/types/tests/test-suite.d.ts +1 -2
- package/dist/types/tests/test-suite.d.ts.map +1 -1
- package/dist/types/tests/utils/test-data-generator.d.ts +20 -1
- package/dist/types/tests/utils/test-data-generator.d.ts.map +1 -1
- package/dist/types/tests/utils/test-validation-state-reader.d.ts +15 -0
- package/dist/types/tests/utils/test-validation-state-reader.d.ts.map +1 -0
- package/package.json +2 -2
- package/src/core/core-protocol.ts +3 -3
- package/src/core/dwn-constant.ts +7 -1
- package/src/core/dwn-error.ts +13 -7
- package/src/core/grant-authorization.ts +11 -20
- package/src/core/message-reply.ts +6 -5
- package/src/core/messages-grant-authorization.ts +37 -100
- package/src/core/protocol-authorization-action.ts +29 -38
- package/src/core/protocol-authorization-validation.ts +41 -98
- package/src/core/protocol-authorization.ts +56 -202
- package/src/core/protocols-grant-authorization.ts +9 -9
- package/src/core/recording-validation-state-reader.ts +130 -0
- package/src/core/records-grant-authorization.ts +16 -16
- package/src/core/replication-apply.ts +412 -0
- package/src/core/resumable-task-manager.ts +10 -8
- package/src/core/validation-state-reader.ts +350 -0
- package/src/dwn.ts +417 -30
- package/src/enums/dwn-interface-method.ts +0 -1
- package/src/event-stream/durable-event-log.ts +509 -0
- package/src/event-stream/event-emitter-wake-publisher.ts +34 -0
- package/src/handlers/messages-query.ts +203 -0
- package/src/handlers/messages-read.ts +9 -10
- package/src/handlers/messages-subscribe.ts +12 -13
- package/src/handlers/protocols-configure.ts +37 -58
- package/src/handlers/protocols-query.ts +1 -1
- package/src/handlers/records-count.ts +24 -17
- package/src/handlers/records-delete.ts +29 -27
- package/src/handlers/records-query.ts +38 -17
- package/src/handlers/records-read.ts +63 -50
- package/src/handlers/records-subscribe.ts +132 -19
- package/src/handlers/records-write.ts +77 -168
- package/src/index.ts +16 -20
- package/src/interfaces/messages-query.ts +70 -0
- package/src/interfaces/protocols-configure.ts +12 -4
- package/src/interfaces/protocols-query.ts +4 -5
- package/src/interfaces/records-count.ts +9 -4
- package/src/interfaces/records-delete.ts +25 -5
- package/src/interfaces/records-query.ts +9 -4
- package/src/interfaces/records-read.ts +4 -4
- package/src/interfaces/records-subscribe.ts +9 -4
- package/src/interfaces/records-write.ts +41 -13
- package/src/protocols/permissions.ts +32 -52
- package/src/store/index-level.ts +30 -9
- package/src/store/level-wrapper.ts +9 -1
- package/src/store/message-store-level.ts +757 -47
- package/src/store/storage-controller.ts +74 -63
- package/src/types/message-store.ts +45 -2
- package/src/types/message-types.ts +3 -1
- package/src/types/messages-types.ts +26 -65
- package/src/types/method-handler.ts +3 -3
- package/src/types/permission-types.ts +1 -1
- package/src/types/subscriptions.ts +53 -42
- package/src/types/validation-state-reader.ts +127 -0
- package/src/utils/messages.ts +25 -1
- package/src/utils/record-limit-occupancy.ts +377 -0
- package/src/utils/records.ts +69 -13
- package/src/utils/replication.ts +122 -0
- package/dist/esm/src/core/record-chain.js +0 -64
- package/dist/esm/src/core/record-chain.js.map +0 -1
- package/dist/esm/src/event-stream/event-emitter-event-log.js +0 -334
- package/dist/esm/src/event-stream/event-emitter-event-log.js.map +0 -1
- package/dist/esm/src/handlers/messages-sync.js +0 -581
- package/dist/esm/src/handlers/messages-sync.js.map +0 -1
- package/dist/esm/src/interfaces/messages-sync.js +0 -54
- package/dist/esm/src/interfaces/messages-sync.js.map +0 -1
- package/dist/esm/src/smt/smt-store-level.js +0 -103
- package/dist/esm/src/smt/smt-store-level.js.map +0 -1
- package/dist/esm/src/smt/smt-store-memory.js +0 -41
- package/dist/esm/src/smt/smt-store-memory.js.map +0 -1
- package/dist/esm/src/smt/smt-utils.js +0 -129
- package/dist/esm/src/smt/smt-utils.js.map +0 -1
- package/dist/esm/src/smt/sparse-merkle-tree.js +0 -577
- package/dist/esm/src/smt/sparse-merkle-tree.js.map +0 -1
- package/dist/esm/src/state-index/state-index-level.js +0 -191
- package/dist/esm/src/state-index/state-index-level.js.map +0 -1
- package/dist/esm/src/sync/records-projection.js +0 -228
- package/dist/esm/src/sync/records-projection.js.map +0 -1
- package/dist/esm/src/types/smt-types.js +0 -5
- package/dist/esm/src/types/smt-types.js.map +0 -1
- package/dist/esm/src/types/state-index.js +0 -2
- package/dist/esm/src/types/state-index.js.map +0 -1
- package/dist/esm/tests/event-emitter-event-log.spec.js +0 -499
- package/dist/esm/tests/event-emitter-event-log.spec.js.map +0 -1
- package/dist/esm/tests/handlers/messages-sync.spec.js +0 -1771
- package/dist/esm/tests/handlers/messages-sync.spec.js.map +0 -1
- package/dist/esm/tests/smt/smt-store-level.spec.js +0 -132
- package/dist/esm/tests/smt/smt-store-level.spec.js.map +0 -1
- package/dist/esm/tests/smt/sparse-merkle-tree.spec.js +0 -732
- package/dist/esm/tests/smt/sparse-merkle-tree.spec.js.map +0 -1
- package/dist/esm/tests/state-index/state-index-level.spec.js +0 -245
- package/dist/esm/tests/state-index/state-index-level.spec.js.map +0 -1
- package/dist/esm/tests/sync/records-projection.spec.js +0 -245
- package/dist/esm/tests/sync/records-projection.spec.js.map +0 -1
- package/dist/types/src/core/record-chain.d.ts +0 -24
- package/dist/types/src/core/record-chain.d.ts.map +0 -1
- package/dist/types/src/event-stream/event-emitter-event-log.d.ts +0 -80
- package/dist/types/src/event-stream/event-emitter-event-log.d.ts.map +0 -1
- package/dist/types/src/handlers/messages-sync.d.ts +0 -83
- package/dist/types/src/handlers/messages-sync.d.ts.map +0 -1
- package/dist/types/src/interfaces/messages-sync.d.ts +0 -23
- package/dist/types/src/interfaces/messages-sync.d.ts.map +0 -1
- package/dist/types/src/smt/smt-store-level.d.ts +0 -32
- package/dist/types/src/smt/smt-store-level.d.ts.map +0 -1
- package/dist/types/src/smt/smt-store-memory.d.ts +0 -22
- package/dist/types/src/smt/smt-store-memory.d.ts.map +0 -1
- package/dist/types/src/smt/smt-utils.d.ts +0 -58
- package/dist/types/src/smt/smt-utils.d.ts.map +0 -1
- package/dist/types/src/smt/sparse-merkle-tree.d.ts +0 -124
- package/dist/types/src/smt/sparse-merkle-tree.d.ts.map +0 -1
- package/dist/types/src/state-index/state-index-level.d.ts +0 -83
- package/dist/types/src/state-index/state-index-level.d.ts.map +0 -1
- package/dist/types/src/sync/records-projection.d.ts +0 -98
- package/dist/types/src/sync/records-projection.d.ts.map +0 -1
- package/dist/types/src/types/smt-types.d.ts +0 -81
- package/dist/types/src/types/smt-types.d.ts.map +0 -1
- package/dist/types/src/types/state-index.d.ts +0 -90
- package/dist/types/src/types/state-index.d.ts.map +0 -1
- package/dist/types/tests/event-emitter-event-log.spec.d.ts +0 -2
- package/dist/types/tests/event-emitter-event-log.spec.d.ts.map +0 -1
- package/dist/types/tests/handlers/messages-sync.spec.d.ts +0 -2
- package/dist/types/tests/handlers/messages-sync.spec.d.ts.map +0 -1
- package/dist/types/tests/smt/smt-store-level.spec.d.ts +0 -2
- package/dist/types/tests/smt/smt-store-level.spec.d.ts.map +0 -1
- package/dist/types/tests/smt/sparse-merkle-tree.spec.d.ts +0 -2
- package/dist/types/tests/smt/sparse-merkle-tree.spec.d.ts.map +0 -1
- package/dist/types/tests/state-index/state-index-level.spec.d.ts +0 -2
- package/dist/types/tests/state-index/state-index-level.spec.d.ts.map +0 -1
- package/dist/types/tests/sync/records-projection.spec.d.ts +0 -2
- package/dist/types/tests/sync/records-projection.spec.d.ts.map +0 -1
- package/src/core/record-chain.ts +0 -99
- package/src/event-stream/event-emitter-event-log.ts +0 -430
- package/src/handlers/messages-sync.ts +0 -896
- package/src/interfaces/messages-sync.ts +0 -86
- package/src/smt/smt-store-level.ts +0 -143
- package/src/smt/smt-store-memory.ts +0 -53
- package/src/smt/smt-utils.ts +0 -149
- package/src/smt/sparse-merkle-tree.ts +0 -698
- package/src/state-index/state-index-level.ts +0 -239
- package/src/sync/records-projection.ts +0 -328
- package/src/types/smt-types.ts +0 -95
- package/src/types/state-index.ts +0 -100
|
@@ -2,21 +2,24 @@ import sinon from 'sinon';
|
|
|
2
2
|
import { DataStream } from '../../src/utils/data-stream.js';
|
|
3
3
|
import { DidKey } from '@enbox/dids';
|
|
4
4
|
import { Dwn } from '../../src/dwn.js';
|
|
5
|
+
import { DwnConstant } from '../../src/core/dwn-constant.js';
|
|
5
6
|
import { DwnErrorCode } from '../../src/core/dwn-error.js';
|
|
6
7
|
import { Jws } from '../../src/utils/jws.js';
|
|
7
8
|
import { ProtocolsConfigure } from '../../src/interfaces/protocols-configure.js';
|
|
9
|
+
import { RecordsRead } from '../../src/interfaces/records-read.js';
|
|
10
|
+
import { sleep } from '@enbox/common';
|
|
8
11
|
import { TestDataGenerator } from '../utils/test-data-generator.js';
|
|
9
12
|
import { TestEventLog } from '../test-event-stream.js';
|
|
10
13
|
import { TestStores } from '../test-stores.js';
|
|
11
14
|
import { UniversalResolver } from '@enbox/dids';
|
|
12
15
|
import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'bun:test';
|
|
16
|
+
import { DataStoreLevel, MessageStoreLevel, ResumableTaskStoreLevel } from '../../src/index.js';
|
|
13
17
|
export function testRecordsRecordLimit() {
|
|
14
18
|
describe('Records $recordLimit', () => {
|
|
15
19
|
let didResolver;
|
|
16
20
|
let messageStore;
|
|
17
21
|
let dataStore;
|
|
18
22
|
let resumableTaskStore;
|
|
19
|
-
let stateIndex;
|
|
20
23
|
let eventLog;
|
|
21
24
|
let dwn;
|
|
22
25
|
// important to follow the `before` and `after` pattern to initialize and clean the stores in tests
|
|
@@ -27,20 +30,99 @@ export function testRecordsRecordLimit() {
|
|
|
27
30
|
messageStore = stores.messageStore;
|
|
28
31
|
dataStore = stores.dataStore;
|
|
29
32
|
resumableTaskStore = stores.resumableTaskStore;
|
|
30
|
-
stateIndex = stores.stateIndex;
|
|
31
33
|
eventLog = TestEventLog.get();
|
|
32
|
-
dwn = await Dwn.create({ didResolver, messageStore, dataStore,
|
|
34
|
+
dwn = await Dwn.create({ didResolver, messageStore, dataStore, eventLog, resumableTaskStore });
|
|
33
35
|
});
|
|
34
36
|
beforeEach(async () => {
|
|
35
37
|
sinon.restore();
|
|
36
38
|
await messageStore.clear();
|
|
37
39
|
await dataStore.clear();
|
|
38
40
|
await resumableTaskStore.clear();
|
|
39
|
-
await stateIndex.clear();
|
|
40
41
|
});
|
|
41
42
|
afterAll(async () => {
|
|
42
43
|
await dwn.close();
|
|
43
44
|
});
|
|
45
|
+
async function installProtocol(input) {
|
|
46
|
+
const protocolConfig = await TestDataGenerator.generateProtocolsConfigure({
|
|
47
|
+
author: input.author,
|
|
48
|
+
protocolDefinition: input.definition,
|
|
49
|
+
messageTimestamp: '2024-01-01T00:00:00.000000Z',
|
|
50
|
+
});
|
|
51
|
+
const reply = await (input.targetDwn ?? dwn).processMessage(input.author.did, protocolConfig.message);
|
|
52
|
+
expect(reply.status.code).toBe(202);
|
|
53
|
+
}
|
|
54
|
+
async function writeProtocolRecord(input) {
|
|
55
|
+
const record = await TestDataGenerator.generateRecordsWrite({
|
|
56
|
+
author: input.author,
|
|
57
|
+
recipient: input.author.did,
|
|
58
|
+
protocol: input.protocol,
|
|
59
|
+
protocolPath: input.protocolPath,
|
|
60
|
+
parentContextId: input.parentContextId,
|
|
61
|
+
dateCreated: input.dateCreated,
|
|
62
|
+
messageTimestamp: input.dateCreated,
|
|
63
|
+
});
|
|
64
|
+
const reply = await (input.targetDwn ?? dwn).processMessage(input.author.did, record.message, { dataStream: record.dataStream });
|
|
65
|
+
expect(reply.status.code).toBe(202);
|
|
66
|
+
return record;
|
|
67
|
+
}
|
|
68
|
+
async function queryProtocolRecordIds(input) {
|
|
69
|
+
const recordsQuery = await TestDataGenerator.generateRecordsQuery({
|
|
70
|
+
author: input.author,
|
|
71
|
+
filter: {
|
|
72
|
+
protocol: input.protocol,
|
|
73
|
+
protocolPath: input.protocolPath,
|
|
74
|
+
...(input.contextId === undefined ? {} : { contextId: input.contextId }),
|
|
75
|
+
},
|
|
76
|
+
pagination: input.pagination,
|
|
77
|
+
});
|
|
78
|
+
const reply = await (input.targetDwn ?? dwn).processMessage(input.author.did, recordsQuery.message);
|
|
79
|
+
expect(reply.status.code).toBe(200);
|
|
80
|
+
return {
|
|
81
|
+
recordIds: reply.entries?.map((entry) => entry.recordId) ?? [],
|
|
82
|
+
cursor: reply.cursor,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
async function countProtocolRecords(input) {
|
|
86
|
+
const recordsCount = await TestDataGenerator.generateRecordsCount({
|
|
87
|
+
author: input.author,
|
|
88
|
+
filter: {
|
|
89
|
+
protocol: input.protocol,
|
|
90
|
+
protocolPath: input.protocolPath,
|
|
91
|
+
...(input.contextId === undefined ? {} : { contextId: input.contextId }),
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
const reply = await (input.targetDwn ?? dwn).processMessage(input.author.did, recordsCount.message);
|
|
95
|
+
expect(reply.status.code).toBe(200);
|
|
96
|
+
return reply.count;
|
|
97
|
+
}
|
|
98
|
+
async function readRecord(input) {
|
|
99
|
+
const recordsRead = await RecordsRead.create({
|
|
100
|
+
signer: Jws.createSigner(input.author),
|
|
101
|
+
filter: { recordId: input.recordId },
|
|
102
|
+
});
|
|
103
|
+
return await (input.targetDwn ?? dwn).processMessage(input.author.did, recordsRead.message);
|
|
104
|
+
}
|
|
105
|
+
async function subscribeSnapshotRecordIds(input) {
|
|
106
|
+
const recordsSubscribe = await TestDataGenerator.generateRecordsSubscribe({
|
|
107
|
+
author: input.author,
|
|
108
|
+
filter: {
|
|
109
|
+
protocol: input.protocol,
|
|
110
|
+
protocolPath: input.protocolPath,
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
const reply = await (input.targetDwn ?? dwn).processMessage(input.author.did, recordsSubscribe.message, { subscriptionHandler: () => { } });
|
|
114
|
+
expect(reply.status.code).toBe(200);
|
|
115
|
+
await reply.subscription?.close();
|
|
116
|
+
return reply.entries?.map((entry) => entry.recordId) ?? [];
|
|
117
|
+
}
|
|
118
|
+
async function applyReplicatedWrite(input) {
|
|
119
|
+
const result = await input.targetDwn.applyReplicatedMessage(input.tenant, input.record.message, {
|
|
120
|
+
dataStream: DataStream.fromBytes(input.record.dataBytes),
|
|
121
|
+
});
|
|
122
|
+
if (result.kind !== 'Applied' && result.kind !== 'Duplicate' && result.kind !== 'Superseded') {
|
|
123
|
+
throw new Error(`unexpected replicated write result ${result.kind}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
44
126
|
describe('ProtocolsConfigure validation', () => {
|
|
45
127
|
it('should allow $recordLimit with valid max and strategy', async () => {
|
|
46
128
|
const alice = await TestDataGenerator.generateDidKeyPersona();
|
|
@@ -85,6 +167,24 @@ export function testRecordsRecordLimit() {
|
|
|
85
167
|
strategy: 'reject',
|
|
86
168
|
});
|
|
87
169
|
});
|
|
170
|
+
it('should reject $recordLimit above the supported max', async () => {
|
|
171
|
+
const alice = await TestDataGenerator.generateDidKeyPersona();
|
|
172
|
+
const definition = {
|
|
173
|
+
protocol: 'http://example.com/record-limit',
|
|
174
|
+
published: true,
|
|
175
|
+
types: { message: {} },
|
|
176
|
+
structure: {
|
|
177
|
+
message: {
|
|
178
|
+
$recordLimit: { max: DwnConstant.maxRecordLimit + 1, strategy: 'reject' },
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
const promise = ProtocolsConfigure.create({
|
|
183
|
+
signer: Jws.createSigner(alice),
|
|
184
|
+
definition,
|
|
185
|
+
});
|
|
186
|
+
await expect(promise).rejects.toThrow(DwnErrorCode.ProtocolsConfigureInvalidRecordLimit);
|
|
187
|
+
});
|
|
88
188
|
it('should allow $recordLimit with purgeOldest strategy (schema validation only)', async () => {
|
|
89
189
|
const alice = await TestDataGenerator.generateDidKeyPersona();
|
|
90
190
|
const definition = {
|
|
@@ -206,42 +306,11 @@ export function testRecordsRecordLimit() {
|
|
|
206
306
|
});
|
|
207
307
|
});
|
|
208
308
|
});
|
|
209
|
-
describe('
|
|
210
|
-
it('should
|
|
309
|
+
describe('read-time occupancy projection — reject strategy', () => {
|
|
310
|
+
it('should admit candidates and project Query, Read, and Count to top-ranked occupants', async () => {
|
|
211
311
|
const alice = await TestDataGenerator.generateDidKeyPersona();
|
|
212
312
|
const protocolDefinition = {
|
|
213
|
-
protocol:
|
|
214
|
-
published: true,
|
|
215
|
-
types: { blob: {} },
|
|
216
|
-
structure: {
|
|
217
|
-
blob: {
|
|
218
|
-
$recordLimit: { max: 3, strategy: 'reject' },
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
};
|
|
222
|
-
const protocol = protocolDefinition.protocol;
|
|
223
|
-
const protocolConfig = await TestDataGenerator.generateProtocolsConfigure({
|
|
224
|
-
author: alice,
|
|
225
|
-
protocolDefinition,
|
|
226
|
-
});
|
|
227
|
-
const configReply = await dwn.processMessage(alice.did, protocolConfig.message);
|
|
228
|
-
expect(configReply.status.code).toBe(202);
|
|
229
|
-
// write 3 records — all should succeed
|
|
230
|
-
for (let i = 0; i < 3; i++) {
|
|
231
|
-
const record = await TestDataGenerator.generateRecordsWrite({
|
|
232
|
-
author: alice,
|
|
233
|
-
recipient: alice.did,
|
|
234
|
-
protocol,
|
|
235
|
-
protocolPath: 'blob',
|
|
236
|
-
});
|
|
237
|
-
const reply = await dwn.processMessage(alice.did, record.message, { dataStream: record.dataStream });
|
|
238
|
-
expect(reply.status.code).toBe(202);
|
|
239
|
-
}
|
|
240
|
-
});
|
|
241
|
-
it('should reject writes that exceed the record limit', async () => {
|
|
242
|
-
const alice = await TestDataGenerator.generateDidKeyPersona();
|
|
243
|
-
const protocolDefinition = {
|
|
244
|
-
protocol: 'http://record-limit-test.xyz',
|
|
313
|
+
protocol: `http://record-limit-${TestDataGenerator.randomString(12)}.xyz`,
|
|
245
314
|
published: true,
|
|
246
315
|
types: { blob: {} },
|
|
247
316
|
structure: {
|
|
@@ -251,38 +320,44 @@ export function testRecordsRecordLimit() {
|
|
|
251
320
|
}
|
|
252
321
|
};
|
|
253
322
|
const protocol = protocolDefinition.protocol;
|
|
254
|
-
|
|
323
|
+
await installProtocol({ author: alice, definition: protocolDefinition });
|
|
324
|
+
const record1 = await writeProtocolRecord({
|
|
255
325
|
author: alice,
|
|
256
|
-
|
|
326
|
+
protocol,
|
|
327
|
+
protocolPath: 'blob',
|
|
328
|
+
dateCreated: '2025-01-01T00:00:00.000000Z',
|
|
257
329
|
});
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
author: alice,
|
|
264
|
-
recipient: alice.did,
|
|
265
|
-
protocol,
|
|
266
|
-
protocolPath: 'blob',
|
|
267
|
-
});
|
|
268
|
-
const reply = await dwn.processMessage(alice.did, record.message, { dataStream: record.dataStream });
|
|
269
|
-
expect(reply.status.code).toBe(202);
|
|
270
|
-
}
|
|
271
|
-
// 3rd record should be rejected
|
|
272
|
-
const record3 = await TestDataGenerator.generateRecordsWrite({
|
|
330
|
+
const duplicateReply = await dwn.processMessage(alice.did, record1.message, {
|
|
331
|
+
dataStream: DataStream.fromBytes(record1.dataBytes),
|
|
332
|
+
});
|
|
333
|
+
expect(duplicateReply.status.code).toBe(409);
|
|
334
|
+
const record2 = await writeProtocolRecord({
|
|
273
335
|
author: alice,
|
|
274
|
-
recipient: alice.did,
|
|
275
336
|
protocol,
|
|
276
337
|
protocolPath: 'blob',
|
|
338
|
+
dateCreated: '2025-01-02T00:00:00.000000Z',
|
|
277
339
|
});
|
|
278
|
-
const
|
|
279
|
-
|
|
280
|
-
|
|
340
|
+
const record3 = await writeProtocolRecord({
|
|
341
|
+
author: alice,
|
|
342
|
+
protocol,
|
|
343
|
+
protocolPath: 'blob',
|
|
344
|
+
dateCreated: '2025-01-03T00:00:00.000000Z',
|
|
345
|
+
});
|
|
346
|
+
expect((await queryProtocolRecordIds({ author: alice, protocol, protocolPath: 'blob' })).recordIds).toEqual([
|
|
347
|
+
record1.message.recordId,
|
|
348
|
+
record2.message.recordId,
|
|
349
|
+
]);
|
|
350
|
+
expect(await countProtocolRecords({ author: alice, protocol, protocolPath: 'blob' })).toBe(2);
|
|
351
|
+
const visibleRead = await readRecord({ author: alice, recordId: record1.message.recordId });
|
|
352
|
+
expect(visibleRead.status.code).toBe(200);
|
|
353
|
+
expect(visibleRead.entry?.recordsWrite?.recordId).toBe(record1.message.recordId);
|
|
354
|
+
const hiddenRead = await readRecord({ author: alice, recordId: record3.message.recordId });
|
|
355
|
+
expect(hiddenRead.status.code).toBe(404);
|
|
281
356
|
});
|
|
282
|
-
it('should
|
|
357
|
+
it('should promote the next candidate at read time when the current occupant is deleted', async () => {
|
|
283
358
|
const alice = await TestDataGenerator.generateDidKeyPersona();
|
|
284
359
|
const protocolDefinition = {
|
|
285
|
-
protocol:
|
|
360
|
+
protocol: `http://record-limit-${TestDataGenerator.randomString(12)}.xyz`,
|
|
286
361
|
published: true,
|
|
287
362
|
types: { profile: {} },
|
|
288
363
|
structure: {
|
|
@@ -292,227 +367,377 @@ export function testRecordsRecordLimit() {
|
|
|
292
367
|
}
|
|
293
368
|
};
|
|
294
369
|
const protocol = protocolDefinition.protocol;
|
|
295
|
-
|
|
370
|
+
await installProtocol({ author: alice, definition: protocolDefinition });
|
|
371
|
+
const record1 = await writeProtocolRecord({
|
|
296
372
|
author: alice,
|
|
297
|
-
protocolDefinition,
|
|
298
|
-
});
|
|
299
|
-
const configReply = await dwn.processMessage(alice.did, protocolConfig.message);
|
|
300
|
-
expect(configReply.status.code).toBe(202);
|
|
301
|
-
// first record should succeed
|
|
302
|
-
const record1 = await TestDataGenerator.generateRecordsWrite({
|
|
303
|
-
author: alice,
|
|
304
|
-
recipient: alice.did,
|
|
305
373
|
protocol,
|
|
306
374
|
protocolPath: 'profile',
|
|
375
|
+
dateCreated: '2025-01-01T00:00:00.000000Z',
|
|
307
376
|
});
|
|
308
|
-
const
|
|
309
|
-
expect(reply1.status.code).toBe(202);
|
|
310
|
-
// exact duplicate delivery is idempotent and should not count the
|
|
311
|
-
// same recordId against its own singleton limit
|
|
312
|
-
const duplicateReply = await dwn.processMessage(alice.did, record1.message, {
|
|
313
|
-
dataStream: DataStream.fromBytes(record1.dataBytes),
|
|
314
|
-
});
|
|
315
|
-
expect(duplicateReply.status.code).toBe(409);
|
|
316
|
-
// second record should be rejected
|
|
317
|
-
const record2 = await TestDataGenerator.generateRecordsWrite({
|
|
377
|
+
const record2 = await writeProtocolRecord({
|
|
318
378
|
author: alice,
|
|
319
|
-
recipient: alice.did,
|
|
320
379
|
protocol,
|
|
321
380
|
protocolPath: 'profile',
|
|
381
|
+
dateCreated: '2025-01-02T00:00:00.000000Z',
|
|
322
382
|
});
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
383
|
+
expect((await queryProtocolRecordIds({ author: alice, protocol, protocolPath: 'profile' })).recordIds).toEqual([
|
|
384
|
+
record1.message.recordId,
|
|
385
|
+
]);
|
|
386
|
+
const deleteRecord = await TestDataGenerator.generateRecordsDelete({
|
|
387
|
+
author: alice,
|
|
388
|
+
recordId: record1.message.recordId,
|
|
389
|
+
});
|
|
390
|
+
const deleteReply = await dwn.processMessage(alice.did, deleteRecord.message);
|
|
391
|
+
expect(deleteReply.status.code).toBe(202);
|
|
392
|
+
expect((await queryProtocolRecordIds({ author: alice, protocol, protocolPath: 'profile' })).recordIds).toEqual([
|
|
393
|
+
record2.message.recordId,
|
|
394
|
+
]);
|
|
395
|
+
expect((await readRecord({ author: alice, recordId: record2.message.recordId })).status.code).toBe(200);
|
|
326
396
|
});
|
|
327
|
-
it('should
|
|
397
|
+
it('should project occupancy independently per exact parent context and reject broad cross-context queries', async () => {
|
|
328
398
|
const alice = await TestDataGenerator.generateDidKeyPersona();
|
|
329
399
|
const protocolDefinition = {
|
|
330
|
-
protocol:
|
|
400
|
+
protocol: `http://record-limit-${TestDataGenerator.randomString(12)}.xyz`,
|
|
331
401
|
published: true,
|
|
332
|
-
types: {
|
|
402
|
+
types: {
|
|
403
|
+
room: {},
|
|
404
|
+
message: {},
|
|
405
|
+
},
|
|
333
406
|
structure: {
|
|
334
|
-
|
|
335
|
-
|
|
407
|
+
room: {
|
|
408
|
+
message: {
|
|
409
|
+
$recordLimit: { max: 2, strategy: 'reject' },
|
|
410
|
+
}
|
|
336
411
|
}
|
|
337
412
|
}
|
|
338
413
|
};
|
|
339
414
|
const protocol = protocolDefinition.protocol;
|
|
340
|
-
|
|
415
|
+
await installProtocol({ author: alice, definition: protocolDefinition });
|
|
416
|
+
const room1 = await writeProtocolRecord({
|
|
341
417
|
author: alice,
|
|
342
|
-
protocolDefinition,
|
|
343
|
-
});
|
|
344
|
-
const configReply = await dwn.processMessage(alice.did, protocolConfig.message);
|
|
345
|
-
expect(configReply.status.code).toBe(202);
|
|
346
|
-
// write first record
|
|
347
|
-
const record1 = await TestDataGenerator.generateRecordsWrite({
|
|
348
|
-
author: alice,
|
|
349
|
-
recipient: alice.did,
|
|
350
418
|
protocol,
|
|
351
|
-
protocolPath: '
|
|
419
|
+
protocolPath: 'room',
|
|
420
|
+
dateCreated: '2025-01-01T00:00:00.000000Z',
|
|
352
421
|
});
|
|
353
|
-
const
|
|
354
|
-
expect(reply1.status.code).toBe(202);
|
|
355
|
-
// second write should be rejected
|
|
356
|
-
const record2 = await TestDataGenerator.generateRecordsWrite({
|
|
422
|
+
const room2 = await writeProtocolRecord({
|
|
357
423
|
author: alice,
|
|
358
|
-
recipient: alice.did,
|
|
359
424
|
protocol,
|
|
360
|
-
protocolPath: '
|
|
425
|
+
protocolPath: 'room',
|
|
426
|
+
dateCreated: '2025-01-02T00:00:00.000000Z',
|
|
361
427
|
});
|
|
362
|
-
const
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
428
|
+
const room1Messages = [
|
|
429
|
+
await writeProtocolRecord({
|
|
430
|
+
author: alice,
|
|
431
|
+
protocol,
|
|
432
|
+
protocolPath: 'room/message',
|
|
433
|
+
parentContextId: room1.message.contextId,
|
|
434
|
+
dateCreated: '2025-02-01T00:00:00.000000Z',
|
|
435
|
+
}),
|
|
436
|
+
await writeProtocolRecord({
|
|
437
|
+
author: alice,
|
|
438
|
+
protocol,
|
|
439
|
+
protocolPath: 'room/message',
|
|
440
|
+
parentContextId: room1.message.contextId,
|
|
441
|
+
dateCreated: '2025-02-02T00:00:00.000000Z',
|
|
442
|
+
}),
|
|
443
|
+
await writeProtocolRecord({
|
|
444
|
+
author: alice,
|
|
445
|
+
protocol,
|
|
446
|
+
protocolPath: 'room/message',
|
|
447
|
+
parentContextId: room1.message.contextId,
|
|
448
|
+
dateCreated: '2025-02-03T00:00:00.000000Z',
|
|
449
|
+
}),
|
|
450
|
+
];
|
|
451
|
+
const room2Messages = [
|
|
452
|
+
await writeProtocolRecord({
|
|
453
|
+
author: alice,
|
|
454
|
+
protocol,
|
|
455
|
+
protocolPath: 'room/message',
|
|
456
|
+
parentContextId: room2.message.contextId,
|
|
457
|
+
dateCreated: '2025-03-01T00:00:00.000000Z',
|
|
458
|
+
}),
|
|
459
|
+
await writeProtocolRecord({
|
|
460
|
+
author: alice,
|
|
461
|
+
protocol,
|
|
462
|
+
protocolPath: 'room/message',
|
|
463
|
+
parentContextId: room2.message.contextId,
|
|
464
|
+
dateCreated: '2025-03-02T00:00:00.000000Z',
|
|
465
|
+
}),
|
|
466
|
+
await writeProtocolRecord({
|
|
467
|
+
author: alice,
|
|
468
|
+
protocol,
|
|
469
|
+
protocolPath: 'room/message',
|
|
470
|
+
parentContextId: room2.message.contextId,
|
|
471
|
+
dateCreated: '2025-03-03T00:00:00.000000Z',
|
|
472
|
+
}),
|
|
473
|
+
];
|
|
474
|
+
expect((await queryProtocolRecordIds({
|
|
366
475
|
author: alice,
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
476
|
+
protocol,
|
|
477
|
+
protocolPath: 'room/message',
|
|
478
|
+
contextId: room1.message.contextId,
|
|
479
|
+
})).recordIds).toEqual([
|
|
480
|
+
room1Messages[0].message.recordId,
|
|
481
|
+
room1Messages[1].message.recordId,
|
|
482
|
+
]);
|
|
483
|
+
expect((await queryProtocolRecordIds({
|
|
373
484
|
author: alice,
|
|
374
|
-
recipient: alice.did,
|
|
375
485
|
protocol,
|
|
376
|
-
protocolPath: '
|
|
486
|
+
protocolPath: 'room/message',
|
|
487
|
+
contextId: room2.message.contextId,
|
|
488
|
+
})).recordIds).toEqual([
|
|
489
|
+
room2Messages[0].message.recordId,
|
|
490
|
+
room2Messages[1].message.recordId,
|
|
491
|
+
]);
|
|
492
|
+
const broadQuery = await TestDataGenerator.generateRecordsQuery({
|
|
493
|
+
author: alice,
|
|
494
|
+
filter: {
|
|
495
|
+
protocol,
|
|
496
|
+
protocolPath: 'room/message',
|
|
497
|
+
},
|
|
377
498
|
});
|
|
378
|
-
const
|
|
379
|
-
expect(
|
|
499
|
+
const broadReply = await dwn.processMessage(alice.did, broadQuery.message);
|
|
500
|
+
expect(broadReply.status.code).toBe(400);
|
|
501
|
+
expect(broadReply.status.detail).toContain(DwnErrorCode.RecordsQueryNestedProtocolPathContextIdInvalid);
|
|
380
502
|
});
|
|
381
|
-
it('should
|
|
503
|
+
it('should paginate over the projected occupant set for max:N scopes', async () => {
|
|
382
504
|
const alice = await TestDataGenerator.generateDidKeyPersona();
|
|
383
505
|
const protocolDefinition = {
|
|
384
|
-
protocol:
|
|
506
|
+
protocol: `http://record-limit-${TestDataGenerator.randomString(12)}.xyz`,
|
|
385
507
|
published: true,
|
|
386
|
-
types: {
|
|
508
|
+
types: { item: {} },
|
|
387
509
|
structure: {
|
|
388
|
-
|
|
389
|
-
$recordLimit: { max:
|
|
510
|
+
item: {
|
|
511
|
+
$recordLimit: { max: 3, strategy: 'reject' },
|
|
390
512
|
}
|
|
391
513
|
}
|
|
392
514
|
};
|
|
393
515
|
const protocol = protocolDefinition.protocol;
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
516
|
+
await installProtocol({ author: alice, definition: protocolDefinition });
|
|
517
|
+
const records = [];
|
|
518
|
+
for (let i = 1; i <= 5; i++) {
|
|
519
|
+
records.push(await writeProtocolRecord({
|
|
520
|
+
author: alice,
|
|
521
|
+
protocol,
|
|
522
|
+
protocolPath: 'item',
|
|
523
|
+
dateCreated: `2025-01-0${i}T00:00:00.000000Z`,
|
|
524
|
+
}));
|
|
525
|
+
}
|
|
526
|
+
const page1 = await queryProtocolRecordIds({
|
|
402
527
|
author: alice,
|
|
403
|
-
recipient: alice.did,
|
|
404
528
|
protocol,
|
|
405
|
-
protocolPath: '
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
expect(
|
|
409
|
-
|
|
410
|
-
|
|
529
|
+
protocolPath: 'item',
|
|
530
|
+
pagination: { limit: 2 },
|
|
531
|
+
});
|
|
532
|
+
expect(page1.recordIds).toEqual([
|
|
533
|
+
records[0].message.recordId,
|
|
534
|
+
records[1].message.recordId,
|
|
535
|
+
]);
|
|
536
|
+
expect(page1.cursor).toBeDefined();
|
|
537
|
+
const page2 = await queryProtocolRecordIds({
|
|
411
538
|
author: alice,
|
|
412
|
-
|
|
539
|
+
protocol,
|
|
540
|
+
protocolPath: 'item',
|
|
541
|
+
pagination: { limit: 2, cursor: page1.cursor },
|
|
413
542
|
});
|
|
414
|
-
|
|
415
|
-
expect(
|
|
543
|
+
expect(page2.recordIds).toEqual([records[2].message.recordId]);
|
|
544
|
+
expect(page2.cursor).toBeUndefined();
|
|
416
545
|
});
|
|
417
|
-
it('should
|
|
546
|
+
it('should project RecordsSubscribe snapshots and suppress hidden live writes', async () => {
|
|
418
547
|
const alice = await TestDataGenerator.generateDidKeyPersona();
|
|
419
548
|
const protocolDefinition = {
|
|
420
|
-
protocol:
|
|
549
|
+
protocol: `http://record-limit-${TestDataGenerator.randomString(12)}.xyz`,
|
|
421
550
|
published: true,
|
|
422
|
-
types: {
|
|
423
|
-
room: {},
|
|
424
|
-
message: {},
|
|
425
|
-
},
|
|
551
|
+
types: { status: {} },
|
|
426
552
|
structure: {
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
$recordLimit: { max: 2, strategy: 'reject' },
|
|
430
|
-
}
|
|
553
|
+
status: {
|
|
554
|
+
$recordLimit: { max: 1, strategy: 'reject' },
|
|
431
555
|
}
|
|
432
556
|
}
|
|
433
557
|
};
|
|
434
558
|
const protocol = protocolDefinition.protocol;
|
|
435
|
-
|
|
559
|
+
await installProtocol({ author: alice, definition: protocolDefinition });
|
|
560
|
+
const visibleRecord = await writeProtocolRecord({
|
|
436
561
|
author: alice,
|
|
437
|
-
|
|
562
|
+
protocol,
|
|
563
|
+
protocolPath: 'status',
|
|
564
|
+
dateCreated: '2025-01-01T00:00:00.000000Z',
|
|
438
565
|
});
|
|
439
|
-
const
|
|
440
|
-
expect(configReply.status.code).toBe(202);
|
|
441
|
-
// create two rooms
|
|
442
|
-
const room1 = await TestDataGenerator.generateRecordsWrite({
|
|
566
|
+
const hiddenRecord = await writeProtocolRecord({
|
|
443
567
|
author: alice,
|
|
444
|
-
recipient: alice.did,
|
|
445
568
|
protocol,
|
|
446
|
-
protocolPath: '
|
|
569
|
+
protocolPath: 'status',
|
|
570
|
+
dateCreated: '2025-01-02T00:00:00.000000Z',
|
|
571
|
+
});
|
|
572
|
+
expect(await subscribeSnapshotRecordIds({ author: alice, protocol, protocolPath: 'status' })).toEqual([
|
|
573
|
+
visibleRecord.message.recordId,
|
|
574
|
+
]);
|
|
575
|
+
const liveRecordIds = [];
|
|
576
|
+
const recordsSubscribe = await TestDataGenerator.generateRecordsSubscribe({
|
|
577
|
+
author: alice,
|
|
578
|
+
filter: {
|
|
579
|
+
protocol,
|
|
580
|
+
protocolPath: 'status',
|
|
581
|
+
},
|
|
582
|
+
});
|
|
583
|
+
const subscribeReply = await dwn.processMessage(alice.did, recordsSubscribe.message, {
|
|
584
|
+
subscriptionHandler: (subscriptionMessage) => {
|
|
585
|
+
if (subscriptionMessage.type === 'event') {
|
|
586
|
+
const eventMessage = subscriptionMessage.event.message;
|
|
587
|
+
if (eventMessage.descriptor.method === 'Write' && 'recordId' in eventMessage && typeof eventMessage.recordId === 'string') {
|
|
588
|
+
liveRecordIds.push(eventMessage.recordId);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
},
|
|
447
592
|
});
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
const room2 = await TestDataGenerator.generateRecordsWrite({
|
|
593
|
+
expect(subscribeReply.status.code).toBe(200);
|
|
594
|
+
const laterHiddenRecord = await writeProtocolRecord({
|
|
451
595
|
author: alice,
|
|
452
|
-
recipient: alice.did,
|
|
453
596
|
protocol,
|
|
454
|
-
protocolPath: '
|
|
597
|
+
protocolPath: 'status',
|
|
598
|
+
dateCreated: '2025-01-03T00:00:00.000000Z',
|
|
455
599
|
});
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
600
|
+
expect(hiddenRecord.message.recordId).not.toBe(laterHiddenRecord.message.recordId);
|
|
601
|
+
await sleep(100);
|
|
602
|
+
expect(liveRecordIds).toEqual([]);
|
|
603
|
+
await subscribeReply.subscription?.close();
|
|
604
|
+
});
|
|
605
|
+
it('should converge projected query results when replicas create max:1 and max:N occupants offline', async () => {
|
|
606
|
+
const alice = await TestDataGenerator.generateDidKeyPersona();
|
|
607
|
+
const testId = TestDataGenerator.randomString(12);
|
|
608
|
+
const replicaAStore = new MessageStoreLevel({ location: `__TESTDATA__/record-limit-${testId}/message-a` });
|
|
609
|
+
const replicaADataStore = new DataStoreLevel({ blockstoreLocation: `__TESTDATA__/record-limit-${testId}/data-a` });
|
|
610
|
+
const replicaATaskStore = new ResumableTaskStoreLevel({ location: `__TESTDATA__/record-limit-${testId}/task-a` });
|
|
611
|
+
const replicaBStore = new MessageStoreLevel({ location: `__TESTDATA__/record-limit-${testId}/message-b` });
|
|
612
|
+
const replicaBDataStore = new DataStoreLevel({ blockstoreLocation: `__TESTDATA__/record-limit-${testId}/data-b` });
|
|
613
|
+
const replicaBTaskStore = new ResumableTaskStoreLevel({ location: `__TESTDATA__/record-limit-${testId}/task-b` });
|
|
614
|
+
const replicaA = await Dwn.create({
|
|
615
|
+
didResolver: didResolver,
|
|
616
|
+
messageStore: replicaAStore,
|
|
617
|
+
dataStore: replicaADataStore,
|
|
618
|
+
resumableTaskStore: replicaATaskStore,
|
|
619
|
+
});
|
|
620
|
+
const replicaB = await Dwn.create({
|
|
621
|
+
didResolver: didResolver,
|
|
622
|
+
messageStore: replicaBStore,
|
|
623
|
+
dataStore: replicaBDataStore,
|
|
624
|
+
resumableTaskStore: replicaBTaskStore,
|
|
625
|
+
});
|
|
626
|
+
try {
|
|
627
|
+
const protocolDefinition = {
|
|
628
|
+
protocol: `http://record-limit-offline-${testId}.xyz`,
|
|
629
|
+
published: true,
|
|
630
|
+
types: {
|
|
631
|
+
note: {},
|
|
632
|
+
profile: {},
|
|
633
|
+
},
|
|
634
|
+
structure: {
|
|
635
|
+
note: {
|
|
636
|
+
$recordLimit: { max: 2, strategy: 'reject' },
|
|
637
|
+
},
|
|
638
|
+
profile: {
|
|
639
|
+
$recordLimit: { max: 1, strategy: 'reject' },
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
};
|
|
643
|
+
const protocol = protocolDefinition.protocol;
|
|
644
|
+
await installProtocol({ author: alice, definition: protocolDefinition, targetDwn: replicaA });
|
|
645
|
+
await installProtocol({ author: alice, definition: protocolDefinition, targetDwn: replicaB });
|
|
646
|
+
const profileA = await writeProtocolRecord({
|
|
462
647
|
author: alice,
|
|
463
|
-
recipient: alice.did,
|
|
464
648
|
protocol,
|
|
465
|
-
protocolPath: '
|
|
466
|
-
|
|
649
|
+
protocolPath: 'profile',
|
|
650
|
+
dateCreated: '2025-01-01T00:00:00.000000Z',
|
|
651
|
+
targetDwn: replicaA,
|
|
467
652
|
});
|
|
468
|
-
const
|
|
469
|
-
expect(msgReply.status.code).toBe(202);
|
|
470
|
-
firstRoom1Message ??= msg;
|
|
471
|
-
}
|
|
472
|
-
// exact duplicate nested delivery is idempotent within the parent context
|
|
473
|
-
const duplicateNestedReply = await dwn.processMessage(alice.did, firstRoom1Message.message, {
|
|
474
|
-
dataStream: DataStream.fromBytes(firstRoom1Message.dataBytes),
|
|
475
|
-
});
|
|
476
|
-
expect(duplicateNestedReply.status.code).toBe(409);
|
|
477
|
-
// 3rd message in room1 should be rejected
|
|
478
|
-
const msg3 = await TestDataGenerator.generateRecordsWrite({
|
|
479
|
-
author: alice,
|
|
480
|
-
recipient: alice.did,
|
|
481
|
-
protocol,
|
|
482
|
-
protocolPath: 'room/message',
|
|
483
|
-
parentContextId: room1.message.contextId,
|
|
484
|
-
});
|
|
485
|
-
const msg3Reply = await dwn.processMessage(alice.did, msg3.message, { dataStream: msg3.dataStream });
|
|
486
|
-
expect(msg3Reply.status.code).toBe(400);
|
|
487
|
-
expect(msg3Reply.status.detail).toContain(DwnErrorCode.ProtocolAuthorizationRecordLimitExceeded);
|
|
488
|
-
// but room2 still has capacity — write 2 messages
|
|
489
|
-
for (let i = 0; i < 2; i++) {
|
|
490
|
-
const msg = await TestDataGenerator.generateRecordsWrite({
|
|
653
|
+
const profileB = await writeProtocolRecord({
|
|
491
654
|
author: alice,
|
|
492
|
-
recipient: alice.did,
|
|
493
655
|
protocol,
|
|
494
|
-
protocolPath: '
|
|
495
|
-
|
|
656
|
+
protocolPath: 'profile',
|
|
657
|
+
dateCreated: '2025-01-02T00:00:00.000000Z',
|
|
658
|
+
targetDwn: replicaB,
|
|
496
659
|
});
|
|
497
|
-
const
|
|
498
|
-
|
|
660
|
+
const noteA1 = await writeProtocolRecord({
|
|
661
|
+
author: alice,
|
|
662
|
+
protocol,
|
|
663
|
+
protocolPath: 'note',
|
|
664
|
+
dateCreated: '2025-02-01T00:00:00.000000Z',
|
|
665
|
+
targetDwn: replicaA,
|
|
666
|
+
});
|
|
667
|
+
const noteB = await writeProtocolRecord({
|
|
668
|
+
author: alice,
|
|
669
|
+
protocol,
|
|
670
|
+
protocolPath: 'note',
|
|
671
|
+
dateCreated: '2025-02-02T00:00:00.000000Z',
|
|
672
|
+
targetDwn: replicaB,
|
|
673
|
+
});
|
|
674
|
+
const noteA2 = await writeProtocolRecord({
|
|
675
|
+
author: alice,
|
|
676
|
+
protocol,
|
|
677
|
+
protocolPath: 'note',
|
|
678
|
+
dateCreated: '2025-02-03T00:00:00.000000Z',
|
|
679
|
+
targetDwn: replicaA,
|
|
680
|
+
});
|
|
681
|
+
await applyReplicatedWrite({ targetDwn: replicaA, tenant: alice.did, record: profileB });
|
|
682
|
+
await applyReplicatedWrite({ targetDwn: replicaB, tenant: alice.did, record: profileA });
|
|
683
|
+
await applyReplicatedWrite({ targetDwn: replicaA, tenant: alice.did, record: noteB });
|
|
684
|
+
await applyReplicatedWrite({ targetDwn: replicaB, tenant: alice.did, record: noteA1 });
|
|
685
|
+
await applyReplicatedWrite({ targetDwn: replicaB, tenant: alice.did, record: noteA2 });
|
|
686
|
+
const expectedProfileIds = [profileA.message.recordId];
|
|
687
|
+
const expectedNoteIds = [
|
|
688
|
+
noteA1.message.recordId,
|
|
689
|
+
noteB.message.recordId,
|
|
690
|
+
];
|
|
691
|
+
expect((await queryProtocolRecordIds({ author: alice, protocol, protocolPath: 'profile', targetDwn: replicaA })).recordIds).toEqual(expectedProfileIds);
|
|
692
|
+
expect((await queryProtocolRecordIds({ author: alice, protocol, protocolPath: 'profile', targetDwn: replicaB })).recordIds).toEqual(expectedProfileIds);
|
|
693
|
+
expect((await queryProtocolRecordIds({ author: alice, protocol, protocolPath: 'note', targetDwn: replicaA })).recordIds).toEqual(expectedNoteIds);
|
|
694
|
+
expect((await queryProtocolRecordIds({ author: alice, protocol, protocolPath: 'note', targetDwn: replicaB })).recordIds).toEqual(expectedNoteIds);
|
|
695
|
+
}
|
|
696
|
+
finally {
|
|
697
|
+
await replicaAStore.clear();
|
|
698
|
+
await replicaADataStore.clear();
|
|
699
|
+
await replicaATaskStore.clear();
|
|
700
|
+
await replicaBStore.clear();
|
|
701
|
+
await replicaBDataStore.clear();
|
|
702
|
+
await replicaBTaskStore.clear();
|
|
703
|
+
await replicaA.close();
|
|
704
|
+
await replicaB.close();
|
|
499
705
|
}
|
|
500
|
-
|
|
501
|
-
|
|
706
|
+
});
|
|
707
|
+
it('should not count updates toward the record limit', async () => {
|
|
708
|
+
const alice = await TestDataGenerator.generateDidKeyPersona();
|
|
709
|
+
const protocolDefinition = {
|
|
710
|
+
protocol: `http://record-limit-${TestDataGenerator.randomString(12)}.xyz`,
|
|
711
|
+
published: true,
|
|
712
|
+
types: { blob: {} },
|
|
713
|
+
structure: {
|
|
714
|
+
blob: {
|
|
715
|
+
$recordLimit: { max: 1, strategy: 'reject' },
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
};
|
|
719
|
+
const protocol = protocolDefinition.protocol;
|
|
720
|
+
await installProtocol({ author: alice, definition: protocolDefinition });
|
|
721
|
+
const record = await writeProtocolRecord({
|
|
502
722
|
author: alice,
|
|
503
|
-
recipient: alice.did,
|
|
504
723
|
protocol,
|
|
505
|
-
protocolPath: '
|
|
506
|
-
|
|
724
|
+
protocolPath: 'blob',
|
|
725
|
+
dateCreated: '2025-01-01T00:00:00.000000Z',
|
|
726
|
+
});
|
|
727
|
+
const updatedRecord = await TestDataGenerator.generateFromRecordsWrite({
|
|
728
|
+
author: alice,
|
|
729
|
+
existingWrite: record.recordsWrite,
|
|
507
730
|
});
|
|
508
|
-
const
|
|
509
|
-
expect(
|
|
510
|
-
expect(
|
|
731
|
+
const updateReply = await dwn.processMessage(alice.did, updatedRecord.message, { dataStream: updatedRecord.dataStream });
|
|
732
|
+
expect(updateReply.status.code).toBe(202);
|
|
733
|
+
expect((await queryProtocolRecordIds({ author: alice, protocol, protocolPath: 'blob' })).recordIds).toEqual([
|
|
734
|
+
record.message.recordId,
|
|
735
|
+
]);
|
|
511
736
|
});
|
|
512
737
|
it('should reject purgeOldest strategy at write time with not-implemented error', async () => {
|
|
513
738
|
const alice = await TestDataGenerator.generateDidKeyPersona();
|
|
514
739
|
const protocolDefinition = {
|
|
515
|
-
protocol:
|
|
740
|
+
protocol: `http://record-limit-${TestDataGenerator.randomString(12)}.xyz`,
|
|
516
741
|
published: true,
|
|
517
742
|
types: { blob: {} },
|
|
518
743
|
structure: {
|
|
@@ -522,31 +747,16 @@ export function testRecordsRecordLimit() {
|
|
|
522
747
|
}
|
|
523
748
|
};
|
|
524
749
|
const protocol = protocolDefinition.protocol;
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
protocolDefinition,
|
|
528
|
-
});
|
|
529
|
-
const configReply = await dwn.processMessage(alice.did, protocolConfig.message);
|
|
530
|
-
expect(configReply.status.code).toBe(202);
|
|
531
|
-
// first record should succeed
|
|
532
|
-
const record1 = await TestDataGenerator.generateRecordsWrite({
|
|
533
|
-
author: alice,
|
|
534
|
-
recipient: alice.did,
|
|
535
|
-
protocol,
|
|
536
|
-
protocolPath: 'blob',
|
|
537
|
-
});
|
|
538
|
-
const reply1 = await dwn.processMessage(alice.did, record1.message, { dataStream: record1.dataStream });
|
|
539
|
-
expect(reply1.status.code).toBe(202);
|
|
540
|
-
// second record should fail because purgeOldest is not yet implemented
|
|
541
|
-
const record2 = await TestDataGenerator.generateRecordsWrite({
|
|
750
|
+
await installProtocol({ author: alice, definition: protocolDefinition });
|
|
751
|
+
const record = await TestDataGenerator.generateRecordsWrite({
|
|
542
752
|
author: alice,
|
|
543
753
|
recipient: alice.did,
|
|
544
754
|
protocol,
|
|
545
755
|
protocolPath: 'blob',
|
|
546
756
|
});
|
|
547
|
-
const
|
|
548
|
-
expect(
|
|
549
|
-
expect(
|
|
757
|
+
const reply = await dwn.processMessage(alice.did, record.message, { dataStream: record.dataStream });
|
|
758
|
+
expect(reply.status.code).toBe(400);
|
|
759
|
+
expect(reply.status.detail).toContain(DwnErrorCode.ProtocolAuthorizationRecordLimitStrategyNotImplemented);
|
|
550
760
|
});
|
|
551
761
|
});
|
|
552
762
|
});
|