@enbox/dwn-sdk-js 0.4.0 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/browser.mjs +3 -10
- package/dist/browser.mjs.map +4 -4
- package/dist/esm/generated/precompiled-validators.js +799 -885
- 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 +12 -4
- 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 -45
- 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 +34 -89
- 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 +123 -28
- package/dist/esm/src/core/replication-apply.js.map +1 -1
- 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 +165 -132
- 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 +6 -7
- package/dist/esm/src/index.js.map +1 -1
- package/dist/esm/src/interfaces/{messages-sync.js → messages-query.js} +21 -15
- package/dist/esm/src/interfaces/messages-query.js.map +1 -0
- package/dist/esm/src/interfaces/protocols-configure.js +12 -9
- 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/protocol-tags.js +262 -0
- package/dist/esm/src/utils/protocol-tags.js.map +1 -0
- 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 +55 -1
- package/dist/esm/tests/core/replication-apply.spec.js.map +1 -1
- 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 +504 -35
- 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 +82 -36
- 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 -2
- package/dist/esm/tests/test-suite.js.map +1 -1
- package/dist/esm/tests/utils/protocol-tags.spec.js +96 -0
- package/dist/esm/tests/utils/protocol-tags.spec.js.map +1 -0
- 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 +12 -4
- 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 -14
- 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 +14 -17
- 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 +36 -0
- package/dist/types/src/core/replication-apply.d.ts.map +1 -1
- 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 +33 -20
- 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 +14 -16
- 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 -37
- 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/protocol-tags.d.ts +15 -0
- package/dist/types/src/utils/protocol-tags.d.ts.map +1 -0
- 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-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/protocol-tags.spec.d.ts +2 -0
- package/dist/types/tests/utils/protocol-tags.spec.d.ts.map +1 -0
- 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 +12 -4
- package/src/core/grant-authorization.ts +11 -20
- package/src/core/message-reply.ts +6 -5
- package/src/core/messages-grant-authorization.ts +37 -70
- package/src/core/protocol-authorization-action.ts +29 -38
- package/src/core/protocol-authorization-validation.ts +47 -121
- 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 +172 -32
- package/src/core/resumable-task-manager.ts +10 -8
- package/src/core/validation-state-reader.ts +350 -0
- package/src/dwn.ts +285 -192
- 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 +14 -17
- package/src/interfaces/messages-query.ts +70 -0
- package/src/interfaces/protocols-configure.ts +20 -10
- 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 -45
- 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/protocol-tags.ts +366 -0
- 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 -278
- package/dist/esm/src/handlers/messages-sync.js.map +0 -1
- 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/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 -1088
- 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/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 -39
- package/dist/types/src/handlers/messages-sync.d.ts.map +0 -1
- package/dist/types/src/interfaces/messages-sync.d.ts +0 -20
- 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/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/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 -403
- package/src/interfaces/messages-sync.ts +0 -69
- 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/types/smt-types.ts +0 -95
- package/src/types/state-index.ts +0 -100
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
import type { MessageStore } from '../types/message-store.js';
|
|
2
|
+
import type { ProtocolRecordLimitDefinition } from '../types/protocols-types.js';
|
|
3
|
+
import type { RecordsWriteMessage } from '../types/records-types.js';
|
|
4
|
+
import type { ValidationStateReader } from '../types/validation-state-reader.js';
|
|
5
|
+
import type { Filter, PaginationCursor } from '../types/query-types.js';
|
|
6
|
+
import type { MessageSort, Pagination } from '../types/message-types.js';
|
|
7
|
+
|
|
8
|
+
import { FilterUtility } from './filter.js';
|
|
9
|
+
import { getRuleSetAtPath } from './protocols.js';
|
|
10
|
+
import { lexicographicalCompare } from './string.js';
|
|
11
|
+
import { ProtocolRecordLimitStrategy } from '../types/protocols-types.js';
|
|
12
|
+
import { Records } from './records.js';
|
|
13
|
+
import { SortDirection } from '../types/query-types.js';
|
|
14
|
+
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
|
|
15
|
+
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
|
|
16
|
+
|
|
17
|
+
type RecordLimitOccupancyDependencies = {
|
|
18
|
+
messageStore: MessageStore;
|
|
19
|
+
validationStateReader: ValidationStateReader;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
type RecordLimitOccupancyQueryInput = RecordLimitOccupancyDependencies & {
|
|
23
|
+
tenant: string;
|
|
24
|
+
filters: Filter[];
|
|
25
|
+
messageTimestamp: string;
|
|
26
|
+
messageSort?: MessageSort;
|
|
27
|
+
pagination?: Pagination;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
type RecordLimitScope = {
|
|
31
|
+
protocol: string;
|
|
32
|
+
protocolPath: string;
|
|
33
|
+
parentContextId: string;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
type RecordLimitFilterResolution = {
|
|
37
|
+
projectedFilters: Filter[];
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Queries records with bounded `$recordLimit` occupancy projection when every limited filter targets one concrete scope.
|
|
42
|
+
*
|
|
43
|
+
* Broad filters keep the store's native query path. Projecting those without a store-level grouping primitive would require
|
|
44
|
+
* scanning the full matching set, which is worse than leaving them unprojected until a bounded broad-query strategy exists.
|
|
45
|
+
*/
|
|
46
|
+
export async function queryRecordsWithRecordLimitOccupancy(
|
|
47
|
+
input: RecordLimitOccupancyQueryInput
|
|
48
|
+
): Promise<{ messages: RecordsWriteMessage[]; cursor?: PaginationCursor }> {
|
|
49
|
+
const filterResolution = await resolveRecordLimitFilters(input);
|
|
50
|
+
if (filterResolution === undefined) {
|
|
51
|
+
const { messages, cursor } = await input.messageStore.query(input.tenant, input.filters, input.messageSort, input.pagination);
|
|
52
|
+
return { messages: messages.filter(Records.isRecordsWrite), cursor };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (filterResolution.projectedFilters.length === 0) {
|
|
56
|
+
return { messages: [] };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const { messages, cursor } = await input.messageStore.query(
|
|
60
|
+
input.tenant,
|
|
61
|
+
filterResolution.projectedFilters,
|
|
62
|
+
input.messageSort,
|
|
63
|
+
input.pagination
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
return { messages: messages.filter(Records.isRecordsWrite), cursor };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Counts records with bounded `$recordLimit` occupancy projection when every limited filter targets one concrete scope.
|
|
71
|
+
*/
|
|
72
|
+
export async function countRecordsWithRecordLimitOccupancy(input: Omit<RecordLimitOccupancyQueryInput, 'pagination'>): Promise<number> {
|
|
73
|
+
const filterResolution = await resolveRecordLimitFilters(input);
|
|
74
|
+
if (filterResolution === undefined) {
|
|
75
|
+
return input.messageStore.count(input.tenant, input.filters, input.messageSort);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (filterResolution.projectedFilters.length === 0) {
|
|
79
|
+
return 0;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return input.messageStore.count(input.tenant, filterResolution.projectedFilters, input.messageSort);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Returns true when the latest RecordsWrite is visible under the `$recordLimit` projection.
|
|
87
|
+
*/
|
|
88
|
+
export async function isRecordLimitOccupant(input: RecordLimitOccupancyDependencies & {
|
|
89
|
+
tenant: string;
|
|
90
|
+
message: RecordsWriteMessage;
|
|
91
|
+
messageTimestamp: string;
|
|
92
|
+
}): Promise<boolean> {
|
|
93
|
+
const recordLimit = await getRecordLimitForMessage({
|
|
94
|
+
messageStore : input.messageStore,
|
|
95
|
+
validationStateReader : input.validationStateReader,
|
|
96
|
+
tenant : input.tenant,
|
|
97
|
+
message : input.message,
|
|
98
|
+
messageTimestamp : input.messageTimestamp,
|
|
99
|
+
recordLimitDefinitions : new Map(),
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
if (recordLimit === undefined) {
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const occupantRecordIds = await findOccupantRecordIds({
|
|
107
|
+
messageStore : input.messageStore,
|
|
108
|
+
tenant : input.tenant,
|
|
109
|
+
scope : getRecordLimitScope(input.message),
|
|
110
|
+
recordLimit,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
return occupantRecordIds.has(input.message.recordId);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async function resolveRecordLimitFilters(
|
|
117
|
+
input: Omit<RecordLimitOccupancyQueryInput, 'pagination'>
|
|
118
|
+
): Promise<RecordLimitFilterResolution | undefined> {
|
|
119
|
+
const recordLimitDefinitions = new Map<string, ProtocolRecordLimitDefinition | undefined>();
|
|
120
|
+
const projectedFilters: Filter[] = [];
|
|
121
|
+
let projectionApplied = false;
|
|
122
|
+
|
|
123
|
+
for (const filter of input.filters) {
|
|
124
|
+
const recordLimit = await getRecordLimitForFilter({
|
|
125
|
+
messageStore : input.messageStore,
|
|
126
|
+
validationStateReader : input.validationStateReader,
|
|
127
|
+
tenant : input.tenant,
|
|
128
|
+
filter,
|
|
129
|
+
messageTimestamp : input.messageTimestamp,
|
|
130
|
+
recordLimitDefinitions,
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
if (recordLimit === undefined) {
|
|
134
|
+
projectedFilters.push(filter);
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const scope = getRecordLimitScopeFromFilter(filter);
|
|
139
|
+
if (scope === undefined) {
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const occupantRecordIds = await findOccupantRecordIds({
|
|
144
|
+
messageStore : input.messageStore,
|
|
145
|
+
tenant : input.tenant,
|
|
146
|
+
scope,
|
|
147
|
+
recordLimit,
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const projectedFilter = buildProjectedFilter(filter, occupantRecordIds);
|
|
151
|
+
if (projectedFilter !== undefined) {
|
|
152
|
+
projectedFilters.push(projectedFilter);
|
|
153
|
+
}
|
|
154
|
+
projectionApplied = true;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return projectionApplied ? { projectedFilters } : undefined;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async function getRecordLimitForMessage(input: RecordLimitOccupancyDependencies & {
|
|
161
|
+
tenant: string;
|
|
162
|
+
message: RecordsWriteMessage;
|
|
163
|
+
messageTimestamp: string;
|
|
164
|
+
recordLimitDefinitions: Map<string, ProtocolRecordLimitDefinition | undefined>;
|
|
165
|
+
}): Promise<ProtocolRecordLimitDefinition | undefined> {
|
|
166
|
+
const { protocol, protocolPath } = input.message.descriptor;
|
|
167
|
+
if (protocol === undefined || protocolPath === undefined) {
|
|
168
|
+
return undefined;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return getRecordLimit({
|
|
172
|
+
validationStateReader : input.validationStateReader,
|
|
173
|
+
tenant : input.tenant,
|
|
174
|
+
protocol,
|
|
175
|
+
protocolPath,
|
|
176
|
+
messageTimestamp : input.messageTimestamp,
|
|
177
|
+
recordLimitDefinitions : input.recordLimitDefinitions,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
async function getRecordLimitForFilter(input: RecordLimitOccupancyDependencies & {
|
|
182
|
+
tenant: string;
|
|
183
|
+
filter: Filter;
|
|
184
|
+
messageTimestamp: string;
|
|
185
|
+
recordLimitDefinitions: Map<string, ProtocolRecordLimitDefinition | undefined>;
|
|
186
|
+
}): Promise<ProtocolRecordLimitDefinition | undefined> {
|
|
187
|
+
if (input.filter.interface !== DwnInterfaceName.Records ||
|
|
188
|
+
input.filter.method !== DwnMethodName.Write ||
|
|
189
|
+
input.filter.isLatestBaseState !== true
|
|
190
|
+
) {
|
|
191
|
+
return undefined;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const { protocol, protocolPath } = input.filter;
|
|
195
|
+
if (typeof protocol !== 'string' || typeof protocolPath !== 'string') {
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return getRecordLimit({
|
|
200
|
+
validationStateReader : input.validationStateReader,
|
|
201
|
+
tenant : input.tenant,
|
|
202
|
+
protocol,
|
|
203
|
+
protocolPath,
|
|
204
|
+
messageTimestamp : input.messageTimestamp,
|
|
205
|
+
recordLimitDefinitions : input.recordLimitDefinitions,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
async function getRecordLimit(input: {
|
|
210
|
+
validationStateReader: ValidationStateReader;
|
|
211
|
+
tenant: string;
|
|
212
|
+
protocol: string;
|
|
213
|
+
protocolPath: string;
|
|
214
|
+
messageTimestamp: string;
|
|
215
|
+
recordLimitDefinitions: Map<string, ProtocolRecordLimitDefinition | undefined>;
|
|
216
|
+
}): Promise<ProtocolRecordLimitDefinition | undefined> {
|
|
217
|
+
const key = `${input.protocol}\u0000${input.protocolPath}`;
|
|
218
|
+
if (!input.recordLimitDefinitions.has(key)) {
|
|
219
|
+
let protocolDefinition;
|
|
220
|
+
try {
|
|
221
|
+
protocolDefinition = await input.validationStateReader.fetchProtocolDefinition(
|
|
222
|
+
input.tenant,
|
|
223
|
+
input.protocol,
|
|
224
|
+
input.messageTimestamp,
|
|
225
|
+
);
|
|
226
|
+
} catch (error) {
|
|
227
|
+
if (error instanceof DwnError && error.code === DwnErrorCode.ProtocolAuthorizationProtocolNotFound) {
|
|
228
|
+
input.recordLimitDefinitions.set(key, undefined);
|
|
229
|
+
return undefined;
|
|
230
|
+
}
|
|
231
|
+
throw error;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const ruleSet = getRuleSetAtPath(input.protocolPath, protocolDefinition.structure);
|
|
235
|
+
const recordLimit = ruleSet?.$recordLimit;
|
|
236
|
+
input.recordLimitDefinitions.set(
|
|
237
|
+
key,
|
|
238
|
+
recordLimit?.strategy === ProtocolRecordLimitStrategy.Reject ? recordLimit : undefined
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return input.recordLimitDefinitions.get(key);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
async function findOccupantRecordIds(input: {
|
|
246
|
+
messageStore: MessageStore;
|
|
247
|
+
tenant: string;
|
|
248
|
+
scope: RecordLimitScope;
|
|
249
|
+
recordLimit: ProtocolRecordLimitDefinition;
|
|
250
|
+
}): Promise<Set<string>> {
|
|
251
|
+
const scopeFilter = buildRecordLimitScopeFilter(input.scope);
|
|
252
|
+
const messageSort = { dateCreated: SortDirection.Ascending };
|
|
253
|
+
const { messages: firstPage } = await input.messageStore.query(
|
|
254
|
+
input.tenant,
|
|
255
|
+
[scopeFilter],
|
|
256
|
+
messageSort,
|
|
257
|
+
{ limit: input.recordLimit.max }
|
|
258
|
+
);
|
|
259
|
+
const firstPageCandidates = firstPage.filter(Records.isRecordsWrite);
|
|
260
|
+
if (firstPageCandidates.length === 0) {
|
|
261
|
+
return new Set();
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const boundaryDateCreated = firstPageCandidates.at(-1)!.descriptor.dateCreated;
|
|
265
|
+
const beforeBoundary = firstPageCandidates.filter(
|
|
266
|
+
(message): boolean => message.descriptor.dateCreated < boundaryDateCreated
|
|
267
|
+
);
|
|
268
|
+
let boundaryCandidates = firstPageCandidates.filter(
|
|
269
|
+
(message): boolean => message.descriptor.dateCreated === boundaryDateCreated
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
if (firstPageCandidates.length === input.recordLimit.max) {
|
|
273
|
+
const { messages } = await input.messageStore.query(
|
|
274
|
+
input.tenant,
|
|
275
|
+
[{ ...scopeFilter, dateCreated: boundaryDateCreated }],
|
|
276
|
+
messageSort
|
|
277
|
+
);
|
|
278
|
+
boundaryCandidates = messages.filter(Records.isRecordsWrite);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
boundaryCandidates.sort(compareRecordLimitCandidates);
|
|
282
|
+
|
|
283
|
+
const rankedCandidates = [
|
|
284
|
+
...beforeBoundary,
|
|
285
|
+
...boundaryCandidates,
|
|
286
|
+
];
|
|
287
|
+
|
|
288
|
+
return new Set(
|
|
289
|
+
rankedCandidates
|
|
290
|
+
.slice(0, input.recordLimit.max)
|
|
291
|
+
.map((message): string => message.recordId)
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function buildRecordLimitScopeFilter(scope: RecordLimitScope): Filter {
|
|
296
|
+
const filter: Filter = {
|
|
297
|
+
interface : DwnInterfaceName.Records,
|
|
298
|
+
method : DwnMethodName.Write,
|
|
299
|
+
isLatestBaseState : true,
|
|
300
|
+
protocol : scope.protocol,
|
|
301
|
+
protocolPath : scope.protocolPath,
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
if (scope.parentContextId !== '') {
|
|
305
|
+
filter.contextId = FilterUtility.constructPrefixFilterAsRangeFilter(scope.parentContextId);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return filter;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function getRecordLimitScopeFromFilter(filter: Filter): RecordLimitScope | undefined {
|
|
312
|
+
const { protocol, protocolPath } = filter;
|
|
313
|
+
if (typeof protocol !== 'string' || typeof protocolPath !== 'string') {
|
|
314
|
+
return undefined;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if (!protocolPath.includes('/')) {
|
|
318
|
+
return { protocol, protocolPath, parentContextId: '' };
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const parentContextId = getExactParentContextIdFromFilter(filter);
|
|
322
|
+
if (parentContextId === undefined) {
|
|
323
|
+
return undefined;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return { protocol, protocolPath, parentContextId };
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function getRecordLimitScope(message: RecordsWriteMessage): RecordLimitScope {
|
|
330
|
+
return {
|
|
331
|
+
protocol : message.descriptor.protocol,
|
|
332
|
+
protocolPath : message.descriptor.protocolPath,
|
|
333
|
+
parentContextId : Records.getParentContextFromOfContextId(message.contextId) ?? '',
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function getExactParentContextIdFromFilter(filter: Filter): string | undefined {
|
|
338
|
+
const { contextId } = filter;
|
|
339
|
+
if (contextId === undefined || !FilterUtility.isRangeFilter(contextId)) {
|
|
340
|
+
return undefined;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
if (typeof contextId.gte !== 'string' || contextId.lt !== `${contextId.gte}\uffff`) {
|
|
344
|
+
return undefined;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return contextId.gte;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function buildProjectedFilter(filter: Filter, occupantRecordIds: Set<string>): Filter | undefined {
|
|
351
|
+
let projectedRecordIds = Array.from(occupantRecordIds);
|
|
352
|
+
const existingRecordIdFilter = filter.recordId;
|
|
353
|
+
if (typeof existingRecordIdFilter === 'string') {
|
|
354
|
+
projectedRecordIds = occupantRecordIds.has(existingRecordIdFilter) ? [existingRecordIdFilter] : [];
|
|
355
|
+
} else if (Array.isArray(existingRecordIdFilter)) {
|
|
356
|
+
projectedRecordIds = existingRecordIdFilter
|
|
357
|
+
.filter((recordId): recordId is string => typeof recordId === 'string' && occupantRecordIds.has(recordId));
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if (projectedRecordIds.length === 0) {
|
|
361
|
+
return undefined;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
return {
|
|
365
|
+
...filter,
|
|
366
|
+
recordId: projectedRecordIds,
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
function compareRecordLimitCandidates(left: RecordsWriteMessage, right: RecordsWriteMessage): number {
|
|
371
|
+
const dateComparison = lexicographicalCompare(left.descriptor.dateCreated, right.descriptor.dateCreated);
|
|
372
|
+
if (dateComparison !== 0) {
|
|
373
|
+
return dateComparison;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
return lexicographicalCompare(left.recordId, right.recordId);
|
|
377
|
+
}
|
package/src/utils/records.ts
CHANGED
|
@@ -36,6 +36,26 @@ export class Records {
|
|
|
36
36
|
return isRecordsWrite;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Gets the newest `RecordsWrite` from the given message set.
|
|
41
|
+
*/
|
|
42
|
+
public static async getNewestRecordsWrite(messages: GenericMessage[]): Promise<RecordsWriteMessage | undefined> {
|
|
43
|
+
const recordsWriteMessages = messages.filter(Records.isRecordsWrite);
|
|
44
|
+
const newestRecordsWrite = await Message.getNewestMessage(recordsWriteMessages);
|
|
45
|
+
return newestRecordsWrite as RecordsWriteMessage | undefined;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Gets the newest `RecordsDelete` from the given message set.
|
|
50
|
+
*/
|
|
51
|
+
public static async getNewestRecordsDelete(messages: GenericMessage[]): Promise<RecordsDeleteMessage | undefined> {
|
|
52
|
+
const recordsDeleteMessages = messages.filter((message): message is RecordsDeleteMessage =>
|
|
53
|
+
message.descriptor.interface === DwnInterfaceName.Records && message.descriptor.method === DwnMethodName.Delete
|
|
54
|
+
);
|
|
55
|
+
const newestRecordsDelete = await Message.getNewestMessage(recordsDeleteMessages);
|
|
56
|
+
return newestRecordsDelete as RecordsDeleteMessage | undefined;
|
|
57
|
+
}
|
|
58
|
+
|
|
39
59
|
/**
|
|
40
60
|
* Decrypts the encrypted data in a message reply.
|
|
41
61
|
*
|
|
@@ -285,6 +305,35 @@ export class Records {
|
|
|
285
305
|
return filterCopy;
|
|
286
306
|
}
|
|
287
307
|
|
|
308
|
+
/**
|
|
309
|
+
* Nested protocol-path queries must pin one parent context. Otherwise the same
|
|
310
|
+
* protocol type is read across every parent instance.
|
|
311
|
+
*/
|
|
312
|
+
public static validateNestedProtocolPathQueryScope(
|
|
313
|
+
filter: RecordsFilter,
|
|
314
|
+
errorCode: DwnErrorCode,
|
|
315
|
+
operationName: string,
|
|
316
|
+
): void {
|
|
317
|
+
const { contextId, protocolPath } = filter;
|
|
318
|
+
if (!protocolPath?.includes('/')) {
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const expectedParentDepth = protocolPath.split('/').length - 1;
|
|
323
|
+
const contextIdSegments = contextId?.split('/');
|
|
324
|
+
if (
|
|
325
|
+
contextIdSegments?.length === expectedParentDepth &&
|
|
326
|
+
contextIdSegments.every(segment => segment.length > 0)
|
|
327
|
+
) {
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
throw new DwnError(
|
|
332
|
+
errorCode,
|
|
333
|
+
`${operationName} for nested protocol path '${protocolPath}' must include the direct parent contextId in the filter`
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
|
|
288
337
|
|
|
289
338
|
public static isStartsWithFilter(filter: RecordsWriteTagsFilter): filter is StartsWithFilter {
|
|
290
339
|
return typeof filter === 'object' && ('startsWith' in filter && typeof filter.startsWith === 'string');
|
|
@@ -530,25 +579,32 @@ export class Records {
|
|
|
530
579
|
}
|
|
531
580
|
|
|
532
581
|
/**
|
|
533
|
-
* Checks
|
|
582
|
+
* Checks whether the given `RecordsDelete` is beaten by an existing tombstone for the record,
|
|
583
|
+
* per the tombstone lattice. A tombstone displaces any `RecordsWrite` regardless of timestamp
|
|
584
|
+
* (delete-wins). Among competing tombstones one canonical winner stands on every replica:
|
|
585
|
+
* a prune beats a plain delete regardless of timestamp — the cascade is a side effect, and a
|
|
586
|
+
* plain-newer winner would leave replicas that ran the cascade diverged from those that never
|
|
587
|
+
* would — and within the same class the newest tombstone wins, with `Message.isNewer`'s
|
|
588
|
+
* (messageTimestamp, CID) total order picking the same winner everywhere. Admission and
|
|
589
|
+
* resumable-task replay must share this predicate: state can advance between acceptance and
|
|
590
|
+
* replay, and replay must never admit a delete that admission would now reject.
|
|
534
591
|
*/
|
|
535
|
-
public static
|
|
536
|
-
|
|
592
|
+
public static async isDeleteBeatenByExistingTombstone(
|
|
593
|
+
deleteToBePerformed: RecordsDeleteMessage,
|
|
594
|
+
newestExistingMessage: GenericMessage
|
|
595
|
+
): Promise<boolean> {
|
|
596
|
+
if (newestExistingMessage.descriptor.method !== DwnMethodName.Delete) {
|
|
537
597
|
return false;
|
|
538
598
|
}
|
|
539
599
|
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
if (deleteToBePerformed.descriptor.prune !== true) {
|
|
545
|
-
return false;
|
|
546
|
-
} else if ((newestExistingMessage as RecordsDeleteMessage).descriptor.prune === true) {
|
|
547
|
-
return false;
|
|
548
|
-
}
|
|
600
|
+
const incomingIsPrune = deleteToBePerformed.descriptor.prune === true;
|
|
601
|
+
const existingIsPrune = (newestExistingMessage as RecordsDeleteMessage).descriptor.prune === true;
|
|
602
|
+
if (incomingIsPrune !== existingIsPrune) {
|
|
603
|
+
return existingIsPrune;
|
|
549
604
|
}
|
|
550
605
|
|
|
551
|
-
|
|
606
|
+
const incomingDeleteIsNewest = await Message.isNewer(deleteToBePerformed, newestExistingMessage);
|
|
607
|
+
return !incomingDeleteIsNewest;
|
|
552
608
|
}
|
|
553
609
|
|
|
554
610
|
/**
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import type { GenericMessage } from '../types/message-types.js';
|
|
2
|
+
import type { KeyValues } from '../types/query-types.js';
|
|
3
|
+
|
|
4
|
+
import { PermissionsProtocol } from '../protocols/permissions.js';
|
|
5
|
+
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
|
|
6
|
+
|
|
7
|
+
const POSITION_PAD_WIDTH = 20;
|
|
8
|
+
|
|
9
|
+
type ReplicationMessageDescriptor = GenericMessage['descriptor'] & {
|
|
10
|
+
tags?: Record<string, unknown>;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Shared helpers for the replication log substrate.
|
|
15
|
+
*/
|
|
16
|
+
export class Replication {
|
|
17
|
+
public static readonly globalDomain = '';
|
|
18
|
+
|
|
19
|
+
public static protocolDomain(protocolUri: string): string {
|
|
20
|
+
return `protocol:${protocolUri}`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public static permissionDomain(protocolUri: string): string {
|
|
24
|
+
return `perm:${protocolUri}`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public static async deriveStreamId(tenant: string): Promise<string> {
|
|
28
|
+
const bytes = new TextEncoder().encode(tenant);
|
|
29
|
+
const hashBuffer = await crypto.subtle.digest('SHA-256', bytes);
|
|
30
|
+
const hashArray = new Uint8Array(hashBuffer);
|
|
31
|
+
return Array.from(hashArray.slice(0, 8), (b: number) => b.toString(16).padStart(2, '0')).join('');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public static computeFingerprintScopes(message: GenericMessage, indexes: KeyValues): string[] {
|
|
35
|
+
const scopes = [Replication.globalDomain];
|
|
36
|
+
|
|
37
|
+
const descriptor: ReplicationMessageDescriptor = message.descriptor;
|
|
38
|
+
const protocol = indexes.protocol;
|
|
39
|
+
if (typeof protocol === 'string') {
|
|
40
|
+
scopes.push(Replication.protocolDomain(protocol));
|
|
41
|
+
|
|
42
|
+
if (protocol === PermissionsProtocol.uri) {
|
|
43
|
+
const indexedTaggedProtocol = indexes['tag.protocol'];
|
|
44
|
+
const taggedProtocol = indexedTaggedProtocol ?? descriptor.tags?.protocol;
|
|
45
|
+
if (typeof taggedProtocol === 'string') {
|
|
46
|
+
scopes.push(Replication.permissionDomain(taggedProtocol));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return scopes;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
public static assertFingerprintScopesUntouched(
|
|
55
|
+
persistedScopes: string[],
|
|
56
|
+
message: GenericMessage,
|
|
57
|
+
messageCid: string,
|
|
58
|
+
newIndexes: KeyValues,
|
|
59
|
+
): void {
|
|
60
|
+
const expectedScopes = Replication.computeFingerprintScopes(message, newIndexes);
|
|
61
|
+
if (!Replication.scopeSetsMatch(persistedScopes, expectedScopes)) {
|
|
62
|
+
Replication.throwFingerprintScopeMutation(messageCid);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private static scopeSetsMatch(left: string[], right: string[]): boolean {
|
|
67
|
+
if (left.length !== right.length) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return right.every((scope) => left.includes(scope));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
private static throwFingerprintScopeMutation(messageCid: string): never {
|
|
75
|
+
throw new DwnError(
|
|
76
|
+
DwnErrorCode.MessageStoreFingerprintScopeMutation,
|
|
77
|
+
`index replacement for message ${messageCid} would change its persisted fingerprint scopes`
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public static async hashMessageCid(messageCid: string): Promise<Uint8Array> {
|
|
82
|
+
const bytes = new TextEncoder().encode(messageCid);
|
|
83
|
+
const hashBuffer = await crypto.subtle.digest('SHA-256', bytes);
|
|
84
|
+
return new Uint8Array(hashBuffer);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
public static emptyFingerprint(): Uint8Array {
|
|
88
|
+
return new Uint8Array(32);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
public static xorFingerprint(fingerprint: Uint8Array, contribution: Uint8Array): Uint8Array {
|
|
92
|
+
const result = new Uint8Array(32);
|
|
93
|
+
for (let i = 0; i < 32; i++) {
|
|
94
|
+
result[i] = fingerprint[i] ^ contribution[i];
|
|
95
|
+
}
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
public static fingerprintToHex(fingerprint: Uint8Array): string {
|
|
100
|
+
return Array.from(fingerprint, (b: number) => b.toString(16).padStart(2, '0')).join('');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
public static hexToFingerprint(hex: string): Uint8Array {
|
|
104
|
+
const bytes = new Uint8Array(32);
|
|
105
|
+
for (let i = 0; i < 32; i++) {
|
|
106
|
+
bytes[i] = Number.parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
107
|
+
}
|
|
108
|
+
return bytes;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
public static encodePositionKey(position: bigint): string {
|
|
112
|
+
const decimal = position.toString();
|
|
113
|
+
if (position < 0n || decimal.length > POSITION_PAD_WIDTH) {
|
|
114
|
+
throw new DwnError(
|
|
115
|
+
DwnErrorCode.MessageStoreReplicationPositionOverflow,
|
|
116
|
+
`log position ${decimal} cannot be encoded within ${POSITION_PAD_WIDTH} digits`
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return decimal.padStart(POSITION_PAD_WIDTH, '0');
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { RecordsWrite } from '../interfaces/records-write.js';
|
|
2
|
-
import { DwnError, DwnErrorCode } from './dwn-error.js';
|
|
3
|
-
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
|
|
4
|
-
/**
|
|
5
|
-
* Fetches the initial RecordsWrite message associated with the given (tenant + recordId).
|
|
6
|
-
*/
|
|
7
|
-
export async function fetchInitialWrite(tenant, recordId, messageStore) {
|
|
8
|
-
const query = {
|
|
9
|
-
interface: DwnInterfaceName.Records,
|
|
10
|
-
method: DwnMethodName.Write,
|
|
11
|
-
recordId: recordId
|
|
12
|
-
};
|
|
13
|
-
const { messages } = await messageStore.query(tenant, [query]);
|
|
14
|
-
if (messages.length === 0) {
|
|
15
|
-
return undefined;
|
|
16
|
-
}
|
|
17
|
-
const initialWrite = await RecordsWrite.getInitialWrite(messages);
|
|
18
|
-
return initialWrite;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Constructs the chain of EXISTING records in the datastore where the first record is the root initial `RecordsWrite` of the record chain
|
|
22
|
-
* and last record is the initial `RecordsWrite` of the descendant record specified.
|
|
23
|
-
* @param descendantRecordId The ID of the descendent record to start constructing the record chain from by repeatedly looking up the parent.
|
|
24
|
-
* @returns the record chain where each record is represented by its initial `RecordsWrite`;
|
|
25
|
-
* returns empty array if `descendantRecordId` is `undefined`.
|
|
26
|
-
* @throws {DwnError} if `descendantRecordId` is defined but any initial `RecordsWrite` is not found in the chain of records.
|
|
27
|
-
*/
|
|
28
|
-
export async function constructRecordChain(tenant, descendantRecordId, messageStore) {
|
|
29
|
-
if (descendantRecordId === undefined) {
|
|
30
|
-
return [];
|
|
31
|
-
}
|
|
32
|
-
const recordChain = [];
|
|
33
|
-
// keep walking up the chain from the inbound message's parent, until there is no more parent
|
|
34
|
-
let currentRecordId = descendantRecordId;
|
|
35
|
-
while (currentRecordId !== undefined) {
|
|
36
|
-
const initialWrite = await fetchInitialWrite(tenant, currentRecordId, messageStore);
|
|
37
|
-
// RecordsWrite needed should be available since we perform necessary checks at the time of writes,
|
|
38
|
-
// eg. check the immediate parent in `verifyProtocolPathAndContextId` at the time of writing,
|
|
39
|
-
// so if this condition is triggered, it means there is an unexpected bug that caused an incomplete chain.
|
|
40
|
-
// We add additional defensive check here because returning an unexpected/incorrect record chain could lead to security vulnerabilities.
|
|
41
|
-
if (initialWrite === undefined) {
|
|
42
|
-
throw new DwnError(DwnErrorCode.ProtocolAuthorizationParentNotFoundConstructingRecordChain, `Unexpected error that should never trigger: no parent found with ID ${currentRecordId} when constructing record chain.`);
|
|
43
|
-
}
|
|
44
|
-
recordChain.push(initialWrite);
|
|
45
|
-
currentRecordId = initialWrite.descriptor.parentId;
|
|
46
|
-
}
|
|
47
|
-
return recordChain.reverse(); // root record first
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Determines the timestamp that governs which protocol definition version applies to the given RecordsWrite.
|
|
51
|
-
* For an update, this is the initial write's `messageTimestamp` (the protocol version is locked at creation time).
|
|
52
|
-
* For a new initial write, returns `undefined` — the latest protocol definition should be used because the
|
|
53
|
-
* record is being created now and must conform to the current protocol rules.
|
|
54
|
-
*/
|
|
55
|
-
export async function getGoverningTimestamp(tenant, incomingMessage, messageStore) {
|
|
56
|
-
const existingInitialWrite = await fetchInitialWrite(tenant, incomingMessage.message.recordId, messageStore);
|
|
57
|
-
if (existingInitialWrite !== undefined) {
|
|
58
|
-
// update case: use the initial write's timestamp
|
|
59
|
-
return existingInitialWrite.descriptor.messageTimestamp;
|
|
60
|
-
}
|
|
61
|
-
// initial write case: validate against the latest protocol definition
|
|
62
|
-
return undefined;
|
|
63
|
-
}
|
|
64
|
-
//# sourceMappingURL=record-chain.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"record-chain.js","sourceRoot":"","sources":["../../../../src/core/record-chain.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAEnF;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,MAAc,EACd,QAAgB,EAChB,YAA0B;IAG1B,MAAM,KAAK,GAAW;QACpB,SAAS,EAAG,gBAAgB,CAAC,OAAO;QACpC,MAAM,EAAM,aAAa,CAAC,KAAK;QAC/B,QAAQ,EAAI,QAAQ;KACrB,CAAC;IACF,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAE/D,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,YAAY,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;IAClE,OAAO,YAAY,CAAC;AACtB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,MAAc,EACd,kBAAsC,EACtC,YAA0B;IAG1B,IAAI,kBAAkB,KAAK,SAAS,EAAE,CAAC;QACrC,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,WAAW,GAA0B,EAAE,CAAC;IAE9C,6FAA6F;IAC7F,IAAI,eAAe,GAAuB,kBAAkB,CAAC;IAC7D,OAAO,eAAe,KAAK,SAAS,EAAE,CAAC;QAErC,MAAM,YAAY,GAAG,MAAM,iBAAiB,CAAC,MAAM,EAAE,eAAe,EAAE,YAAY,CAAC,CAAC;QAEpF,mGAAmG;QACnG,6FAA6F;QAC7F,0GAA0G;QAC1G,wIAAwI;QACxI,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;YAC/B,MAAM,IAAI,QAAQ,CAChB,YAAY,CAAC,0DAA0D,EACvE,uEAAuE,eAAe,kCAAkC,CACzH,CAAC;QACJ,CAAC;QAED,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC/B,eAAe,GAAG,YAAY,CAAC,UAAU,CAAC,QAAQ,CAAC;IACrD,CAAC;IAED,OAAO,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC,oBAAoB;AACpD,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,MAAc,EACd,eAA6B,EAC7B,YAA0B;IAE1B,MAAM,oBAAoB,GAAG,MAAM,iBAAiB,CAClD,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,QAAQ,EAAE,YAAY,CACvD,CAAC;IAEF,IAAI,oBAAoB,KAAK,SAAS,EAAE,CAAC;QACvC,iDAAiD;QACjD,OAAO,oBAAoB,CAAC,UAAU,CAAC,gBAAgB,CAAC;IAC1D,CAAC;IAED,sEAAsE;IACtE,OAAO,SAAS,CAAC;AACnB,CAAC"}
|