@enbox/dwn-sdk-js 0.0.8 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.mjs +5 -5
- package/dist/browser.mjs.map +3 -3
- package/dist/esm/generated/precompiled-validators.js +219 -165
- package/dist/esm/generated/precompiled-validators.js.map +1 -1
- package/dist/esm/src/core/dwn-error.js +3 -0
- package/dist/esm/src/core/dwn-error.js.map +1 -1
- package/dist/esm/src/core/protocol-authorization-action.js +5 -0
- package/dist/esm/src/core/protocol-authorization-action.js.map +1 -1
- package/dist/esm/src/core/protocol-authorization-validation.js +24 -0
- package/dist/esm/src/core/protocol-authorization-validation.js.map +1 -1
- package/dist/esm/src/core/protocol-authorization.js +3 -1
- package/dist/esm/src/core/protocol-authorization.js.map +1 -1
- package/dist/esm/src/core/resumable-task-manager.js +2 -0
- package/dist/esm/src/core/resumable-task-manager.js.map +1 -1
- package/dist/esm/src/handlers/records-write.js +81 -0
- package/dist/esm/src/handlers/records-write.js.map +1 -1
- package/dist/esm/src/interfaces/protocols-configure.js +9 -1
- package/dist/esm/src/interfaces/protocols-configure.js.map +1 -1
- package/dist/esm/src/interfaces/records-write.js +3 -0
- package/dist/esm/src/interfaces/records-write.js.map +1 -1
- package/dist/esm/src/store/storage-controller.js +64 -0
- package/dist/esm/src/store/storage-controller.js.map +1 -1
- package/dist/esm/src/types/protocols-types.js +1 -0
- package/dist/esm/src/types/protocols-types.js.map +1 -1
- package/dist/esm/tests/features/records-delivery.spec.js +236 -0
- package/dist/esm/tests/features/records-delivery.spec.js.map +1 -0
- package/dist/esm/tests/features/records-squash.spec.js +1055 -0
- package/dist/esm/tests/features/records-squash.spec.js.map +1 -0
- package/dist/esm/tests/handlers/records-write.spec.js +3 -0
- package/dist/esm/tests/handlers/records-write.spec.js.map +1 -1
- package/dist/esm/tests/test-suite.js +4 -0
- package/dist/esm/tests/test-suite.js.map +1 -1
- package/dist/esm/tests/utils/test-data-generator.js +1 -0
- package/dist/esm/tests/utils/test-data-generator.js.map +1 -1
- package/dist/types/generated/precompiled-validators.d.ts.map +1 -1
- package/dist/types/src/core/dwn-error.d.ts +3 -0
- package/dist/types/src/core/dwn-error.d.ts.map +1 -1
- package/dist/types/src/core/protocol-authorization-action.d.ts.map +1 -1
- package/dist/types/src/core/protocol-authorization-validation.d.ts +9 -0
- package/dist/types/src/core/protocol-authorization-validation.d.ts.map +1 -1
- package/dist/types/src/core/protocol-authorization.d.ts.map +1 -1
- package/dist/types/src/core/resumable-task-manager.d.ts +2 -1
- package/dist/types/src/core/resumable-task-manager.d.ts.map +1 -1
- package/dist/types/src/handlers/records-write.d.ts +8 -0
- package/dist/types/src/handlers/records-write.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/interfaces/protocols-configure.d.ts.map +1 -1
- package/dist/types/src/interfaces/records-write.d.ts +6 -0
- package/dist/types/src/interfaces/records-write.d.ts.map +1 -1
- package/dist/types/src/store/storage-controller.d.ts +16 -2
- package/dist/types/src/store/storage-controller.d.ts.map +1 -1
- package/dist/types/src/types/protocols-types.d.ts +29 -2
- package/dist/types/src/types/protocols-types.d.ts.map +1 -1
- package/dist/types/src/types/records-types.d.ts +7 -0
- package/dist/types/src/types/records-types.d.ts.map +1 -1
- package/dist/types/tests/features/records-delivery.spec.d.ts +2 -0
- package/dist/types/tests/features/records-delivery.spec.d.ts.map +1 -0
- package/dist/types/tests/features/records-squash.spec.d.ts +2 -0
- package/dist/types/tests/features/records-squash.spec.d.ts.map +1 -0
- package/dist/types/tests/handlers/records-write.spec.d.ts.map +1 -1
- package/dist/types/tests/test-suite.d.ts.map +1 -1
- package/dist/types/tests/utils/test-data-generator.d.ts +1 -0
- package/dist/types/tests/utils/test-data-generator.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/core/dwn-error.ts +3 -0
- package/src/core/protocol-authorization-action.ts +5 -0
- package/src/core/protocol-authorization-validation.ts +37 -0
- package/src/core/protocol-authorization.ts +4 -0
- package/src/core/resumable-task-manager.ts +3 -1
- package/src/handlers/records-write.ts +106 -0
- package/src/index.ts +1 -1
- package/src/interfaces/protocols-configure.ts +12 -1
- package/src/interfaces/records-write.ts +10 -0
- package/src/store/storage-controller.ts +78 -1
- package/src/types/protocols-types.ts +32 -1
- package/src/types/records-types.ts +8 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-data-generator.d.ts","sourceRoot":"","sources":["../../../../tests/utils/test-data-generator.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"test-data-generator.d.ts","sourceRoot":"","sources":["../../../../tests/utils/test-data-generator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAU/D,OAAO,KAAK,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AACvF,OAAO,KAAK,EAAqB,eAAe,EAA2C,MAAM,uCAAuC,CAAC;AACzI,OAAO,KAAK,EAAE,8BAA8B,EAAE,QAAQ,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,aAAa,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAClM,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AACvH,OAAO,KAAK,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,qCAAqC,CAAC;AACjG,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AACjF,OAAO,KAAK,EAAE,kBAAkB,EAAmB,yBAAyB,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAChJ,OAAO,KAAK,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AASrG,OAAO,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,4CAA4C,CAAC;AAG/E,OAAO,EAAE,kBAAkB,EAAE,MAAM,6CAA6C,CAAC;AACjF,OAAO,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AAGzE,OAAO,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAC;AAGvE,OAAO,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AAUrE;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE;QAAE,SAAS,EAAE,YAAY,CAAC;QAAC,UAAU,EAAE,aAAa,CAAA;KAAE,CAAC;IAChE,0FAA0F;IAC1F,iBAAiB,EAAE;QAAE,SAAS,EAAE,YAAY,CAAC;QAAC,UAAU,EAAE,aAAa,CAAA;KAAE,CAAC;IAC1E,MAAM,EAAE,aAAa,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,+BAA+B,GAAG;IAC5C;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,8BAA8B,CAAC;CACjD,CAAC;AAEF,MAAM,MAAM,gCAAgC,GAAG;IAC7C,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,yBAAyB,CAAC;IACnC,kBAAkB,EAAE,kBAAkB,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE;QACP,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAA;CACF,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG;IACzC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,qBAAqB,CAAC;IAC/B,cAAc,EAAE,cAAc,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,UAAU,CAAC,EAAE,oBAAoB,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,OAAO,EAAE,mBAAmB,CAAC;IAC7B,SAAS,EAAE,UAAU,CAAC;IACtB,UAAU,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACvC,YAAY,EAAE,YAAY,CAAC;IAC3B,kBAAkB,EAAE,8BAA8B,CAAC;CACpD,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IAEtC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE,IAAI,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG;IAC1C,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,YAAY,CAAC;IAC5B,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,OAAO,EAAE,mBAAmB,CAAC;IAC7B,SAAS,EAAE,UAAU,CAAC;IACtB,UAAU,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACvC,YAAY,EAAE,YAAY,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,mBAAmB,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,UAAU,CAAC;IACvB,UAAU,CAAC,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACxC,YAAY,EAAE,YAAY,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,MAAM,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B,OAAO,EAAE,mBAAmB,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG;IACxC;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,4DAA4D;IAC5D,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,8BAA8B,GAAG;IAC3C,MAAM,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B,OAAO,EAAE,uBAAuB,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,MAAM,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B,OAAO,EAAE,mBAAmB,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,aAAa,CAAC;IAC7B,OAAO,EAAE,oBAAoB,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,8BAA8B,GAAG;IAC3C,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC;IAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,4DAA4D;IAC5D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,+BAA+B,GAAG;IAC5C,MAAM,EAAE,OAAO,CAAC;IAChB,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,OAAO,EAAE,wBAAwB,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,mBAAmB,CAAC;IAC7B,YAAY,EAAE,YAAY,CAAC;CAC5B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,EAAE,kBAS3C,CAAC;AAEF;;GAEG;AACH,qBAAa,iBAAiB;IAC5B;;OAEG;WACiB,eAAe,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;IAyC/E;;;;OAIG;WACiB,0BAA0B,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAWzF;;;;OAIG;WACiB,0BAA0B,CAC5C,KAAK,CAAC,EAAE,+BAA+B,GACtC,OAAO,CAAC,gCAAgC,CAAC;IAwC5C;;OAEG;WACiB,sBAAsB,CAAC,KAAK,CAAC,EAAE,2BAA2B,GAAG,OAAO,CAAC,4BAA4B,CAAC;WAuBlG,mBAAmB,CAAC,KAAK,CAAC,EAAE,wBAAwB,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAmC7G;;;;;;;;;OASG;WACiB,oBAAoB,CAAC,KAAK,CAAC,EAAE,yBAAyB,GAAG,OAAO,CAAC,0BAA0B,CAAC;IAqDhH;;;;;;;;;;;;OAYG;WACiB,qCAAqC,CAAC,KAAK,EAAE;QAC/D,cAAc,EAAE,UAAU,CAAC;QAC3B,MAAM,EAAE,OAAO,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,kBAAkB,EAAE,kBAAkB,CAAC;QACvC,YAAY,EAAE,MAAM,CAAC;QACrB,uBAAuB,CAAC,EAAE,MAAM,CAAC;QACjC,gCAAgC,CAAC,EAAE,MAAM,CAAC;QAC1C,kCAAkC,CAAC,EAAE,YAAY,CAAC;QAClD,6CAA6C,EAAE,OAAO,CAAC;QACvD,gDAAgD,EAAE,OAAO,CAAC;KAC3D,GAAG,OAAO,CAAC;QACV,OAAO,EAAE,mBAAmB,CAAC;QAC7B,UAAU,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;QACvC,YAAY,EAAE,YAAY,CAAC;QAC3B,eAAe,EAAE,eAAe,CAAC;QACjC,kBAAkB,EAAE,UAAU,CAAC;KAChC,CAAC;IAuGF;;;;OAIG;WACiB,wBAAwB,CAAC,KAAK,EAAE,6BAA6B,GAAG,OAAO,CAAC,2BAA2B,CAAC;IA8BxH;;OAEG;WACiB,oBAAoB,CAAC,KAAK,CAAC,EAAE,yBAAyB,GAAG,OAAO,CAAC,0BAA0B,CAAC;IAqChH;;OAEG;WACiB,wBAAwB,CAAC,KAAK,CAAC,EAAE,6BAA6B,GAAG,OAAO,CAAC,8BAA8B,CAAC;IAsC5H;;OAEG;WACiB,oBAAoB,CAAC,KAAK,CAAC,EAAE,yBAAyB,GAAG,OAAO,CAAC,0BAA0B,CAAC;IAmChH;;OAEG;WACiB,qBAAqB,CAAC,KAAK,CAAC,EAAE,0BAA0B,GAAG,OAAO,CAAC,2BAA2B,CAAC;IAgBnH;;OAEG;WACiB,yBAAyB,CAAC,KAAK,CAAC,EAAE,8BAA8B,GAAG,OAAO,CAAC,+BAA+B,CAAC;WAuB3G,oBAAoB,CAAC,KAAK,EAAE,yBAAyB,GAAG,OAAO,CAAC,0BAA0B,CAAC;IAmB/G;;OAEG;WACW,qBAAqB,IAAI,kBAAkB;IAMzD;;OAEG;WACW,8BAA8B,IAAI,UAAU;IAU1D;;OAEG;WACiB,qBAAqB,IAAI,OAAO,CAAC,MAAM,CAAC;IAQ5D;;OAEG;WACW,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAYlD;;OAEG;WACW,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU;IASrD;;OAEG;WACiB,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC;IAO1D;;;;OAIG;WACW,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM;IAIzD;;;;OAIG;WACW,eAAe,CAAC,OAAO,CAAC,EAAE;QACtC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KACzI,GAAG,MAAM;IAcV;;OAEG;WACW,yBAAyB,CAAC,OAAO,EAAE,OAAO,GAAG,mBAAmB;IAiB9E;;OAEG;WACiB,qBAAqB,IAAI,OAAO,CAAC,OAAO,CAAC;CAgC9D"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@enbox/dwn-sdk-js",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "A reference implementation of https://identity.foundation/decentralized-web-node/spec/",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -64,8 +64,8 @@
|
|
|
64
64
|
},
|
|
65
65
|
"react-native": "./dist/esm/src/index.js",
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"@enbox/crypto": "0.0.
|
|
68
|
-
"@enbox/dids": "0.0.
|
|
67
|
+
"@enbox/crypto": "0.0.6",
|
|
68
|
+
"@enbox/dids": "0.0.7",
|
|
69
69
|
"@ipld/dag-cbor": "9.0.3",
|
|
70
70
|
"@js-temporal/polyfill": "0.4.4",
|
|
71
71
|
"@noble/ciphers": "0.5.3",
|
package/src/core/dwn-error.ts
CHANGED
|
@@ -86,6 +86,9 @@ export enum DwnErrorCode {
|
|
|
86
86
|
ProtocolAuthorizationMinSizeInvalid = 'ProtocolAuthorizationMinSizeInvalid',
|
|
87
87
|
ProtocolAuthorizationRecordLimitExceeded = 'ProtocolAuthorizationRecordLimitExceeded',
|
|
88
88
|
ProtocolAuthorizationRecordLimitStrategyNotImplemented = 'ProtocolAuthorizationRecordLimitStrategyNotImplemented',
|
|
89
|
+
ProtocolAuthorizationSquashNotEnabled = 'ProtocolAuthorizationSquashNotEnabled',
|
|
90
|
+
ProtocolAuthorizationSquashNotInitialWrite = 'ProtocolAuthorizationSquashNotInitialWrite',
|
|
91
|
+
ProtocolAuthorizationSquashBackstop = 'ProtocolAuthorizationSquashBackstop',
|
|
89
92
|
ProtocolAuthorizationMissingContextId = 'ProtocolAuthorizationMissingContextId',
|
|
90
93
|
ProtocolAuthorizationMissingRuleSet = 'ProtocolAuthorizationMissingRuleSet',
|
|
91
94
|
ProtocolAuthorizationParentlessIncorrectProtocolPath = 'ProtocolAuthorizationParentlessIncorrectProtocolPath',
|
|
@@ -191,6 +191,11 @@ export async function getActionsSeekingARuleMatch(
|
|
|
191
191
|
const incomingRecordsWrite = incomingMessage as RecordsWrite;
|
|
192
192
|
|
|
193
193
|
if (await incomingRecordsWrite.isInitialWrite()) {
|
|
194
|
+
// A squash write seeks the `squash` action first, with fallback to `create`.
|
|
195
|
+
// This means any DID authorized to `create` can also squash when no explicit `squash` rule exists.
|
|
196
|
+
if (incomingRecordsWrite.message.descriptor.squash === true) {
|
|
197
|
+
return [ProtocolAction.Squash, ProtocolAction.Create];
|
|
198
|
+
}
|
|
194
199
|
return [ProtocolAction.Create];
|
|
195
200
|
} else {
|
|
196
201
|
// else incoming RecordsWrite not an initial write
|
|
@@ -459,6 +459,43 @@ export async function verifyRecordLimit(
|
|
|
459
459
|
}
|
|
460
460
|
}
|
|
461
461
|
|
|
462
|
+
/**
|
|
463
|
+
* Verifies that a `RecordsWrite` with `squash: true` is eligible:
|
|
464
|
+
* 1. The protocol rule set at the record's `protocolPath` must have `$squash: true`.
|
|
465
|
+
* 2. The squash write must be an initial write (a new record, not an update).
|
|
466
|
+
*
|
|
467
|
+
* @throws {DwnError} with `ProtocolAuthorizationSquashNotEnabled` if `$squash` is not enabled.
|
|
468
|
+
* @throws {DwnError} with `ProtocolAuthorizationSquashNotInitialWrite` if the squash write is not an initial write.
|
|
469
|
+
*/
|
|
470
|
+
export async function verifySquashEligibility(
|
|
471
|
+
incomingMessage: RecordsWrite,
|
|
472
|
+
ruleSet: ProtocolRuleSet,
|
|
473
|
+
): Promise<void> {
|
|
474
|
+
const squash = incomingMessage.message.descriptor.squash;
|
|
475
|
+
|
|
476
|
+
if (squash !== true) {
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// squash write must be at a protocol path with $squash: true
|
|
481
|
+
if (ruleSet.$squash !== true) {
|
|
482
|
+
throw new DwnError(
|
|
483
|
+
DwnErrorCode.ProtocolAuthorizationSquashNotEnabled,
|
|
484
|
+
`squash writes are not enabled at protocol path '${incomingMessage.message.descriptor.protocolPath}': ` +
|
|
485
|
+
`rule set must have $squash: true.`
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// squash write must be an initial write (a new record, not an update)
|
|
490
|
+
const isInitialWrite = await incomingMessage.isInitialWrite();
|
|
491
|
+
if (!isInitialWrite) {
|
|
492
|
+
throw new DwnError(
|
|
493
|
+
DwnErrorCode.ProtocolAuthorizationSquashNotInitialWrite,
|
|
494
|
+
`squash write must be an initial write (a new record): updates cannot be squash writes.`
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
462
499
|
/**
|
|
463
500
|
* Verifies that an update is not attempted on a record whose protocol path has `$immutable: true`.
|
|
464
501
|
*
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
verifyProtocolPathAndContextId,
|
|
24
24
|
verifyRecordLimit,
|
|
25
25
|
verifySizeLimit,
|
|
26
|
+
verifySquashEligibility,
|
|
26
27
|
verifyTagsIfNeeded,
|
|
27
28
|
verifyTypeWithComposition,
|
|
28
29
|
} from './protocol-authorization-validation.js';
|
|
@@ -105,6 +106,9 @@ export class ProtocolAuthorization {
|
|
|
105
106
|
// Verify immutability — reject updates to write-once records
|
|
106
107
|
await verifyImmutability(incomingMessage, ruleSet);
|
|
107
108
|
|
|
109
|
+
// Verify squash eligibility — ensure squash writes are at $squash: true paths and are initial writes
|
|
110
|
+
await verifySquashEligibility(incomingMessage, ruleSet);
|
|
111
|
+
|
|
108
112
|
// Verify record count limit
|
|
109
113
|
await verifyRecordLimit(tenant, incomingMessage, ruleSet, messageStore);
|
|
110
114
|
}
|
|
@@ -3,6 +3,7 @@ import type { ManagedResumableTask, ResumableTaskStore } from '../types/resumabl
|
|
|
3
3
|
|
|
4
4
|
export enum ResumableTaskName {
|
|
5
5
|
RecordsDelete = 'RecordsDelete',
|
|
6
|
+
RecordsSquash = 'RecordsSquash',
|
|
6
7
|
}
|
|
7
8
|
|
|
8
9
|
export type ResumableTask = {
|
|
@@ -26,7 +27,8 @@ export class ResumableTaskManager {
|
|
|
26
27
|
this.resumableTaskHandlers = {
|
|
27
28
|
// NOTE: The arrow function is IMPORTANT here, else the `this` context will be lost within the invoked method.
|
|
28
29
|
// e.g. code within performRecordsDelete() won't know `this` refers to the `storageController` instance.
|
|
29
|
-
[ResumableTaskName.RecordsDelete]: async (task): Promise<void> => await storageController.performRecordsDelete(task),
|
|
30
|
+
[ResumableTaskName.RecordsDelete] : async (task): Promise<void> => await storageController.performRecordsDelete(task),
|
|
31
|
+
[ResumableTaskName.RecordsSquash] : async (task): Promise<void> => await storageController.performRecordsSquash(task),
|
|
30
32
|
};
|
|
31
33
|
}
|
|
32
34
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Filter } from '../types/query-types.js';
|
|
1
2
|
import type { GenericMessageReply } from '../types/message-types.js';
|
|
2
3
|
import type { MessageStore } from '../types/message-store.js';
|
|
3
4
|
import type { HandlerDependencies, MethodHandler } from '../types/method-handler.js';
|
|
@@ -8,12 +9,16 @@ import { Cid } from '../utils/cid.js';
|
|
|
8
9
|
import { DataStream } from '../utils/data-stream.js';
|
|
9
10
|
import { DwnConstant } from '../core/dwn-constant.js';
|
|
10
11
|
import { Encoder } from '../utils/encoder.js';
|
|
12
|
+
import { FilterUtility } from '../utils/filter.js';
|
|
11
13
|
import { Message } from '../core/message.js';
|
|
12
14
|
import { messageReplyFromError } from '../core/message-reply.js';
|
|
13
15
|
import { PermissionsProtocol } from '../protocols/permissions.js';
|
|
14
16
|
import { ProtocolAuthorization } from '../core/protocol-authorization.js';
|
|
17
|
+
import { Records } from '../utils/records.js';
|
|
15
18
|
import { RecordsGrantAuthorization } from '../core/records-grant-authorization.js';
|
|
16
19
|
import { RecordsWrite } from '../interfaces/records-write.js';
|
|
20
|
+
import { ResumableTaskName } from '../core/resumable-task-manager.js';
|
|
21
|
+
import { SortDirection } from '../types/query-types.js';
|
|
17
22
|
import { StorageController } from '../store/storage-controller.js';
|
|
18
23
|
import { DwnError, DwnErrorCode } from '../core/dwn-error.js';
|
|
19
24
|
import { DwnInterfaceName, DwnMethodName } from '../enums/dwn-interface-method.js';
|
|
@@ -65,6 +70,15 @@ export class RecordsWriteHandler implements MethodHandler {
|
|
|
65
70
|
}
|
|
66
71
|
}
|
|
67
72
|
|
|
73
|
+
// Squash backstop: if the protocol path has $squash: true, reject any write whose
|
|
74
|
+
// messageTimestamp is <= the most recent squash record at the same path and parent context.
|
|
75
|
+
// The squash record acts as a temporal floor — no record older than the latest squash can exist.
|
|
76
|
+
try {
|
|
77
|
+
await this.enforceSquashBackstop(tenant, message);
|
|
78
|
+
} catch (e) {
|
|
79
|
+
return messageReplyFromError(e, 409);
|
|
80
|
+
}
|
|
81
|
+
|
|
68
82
|
const newestExistingMessage = await Message.getNewestMessage(existingMessages);
|
|
69
83
|
|
|
70
84
|
let incomingMessageIsNewest = false;
|
|
@@ -167,6 +181,15 @@ export class RecordsWriteHandler implements MethodHandler {
|
|
|
167
181
|
tenant, existingMessages, newestMessage, this.deps.messageStore, this.deps.dataStore!, this.deps.stateIndex!
|
|
168
182
|
);
|
|
169
183
|
|
|
184
|
+
// Squash processing: if the incoming write is a squash, delete all older sibling records
|
|
185
|
+
// at the same protocol path and parent context. Uses the resumable task system for crash safety.
|
|
186
|
+
if (message.descriptor.squash === true) {
|
|
187
|
+
await this.deps.resumableTaskManager!.run({
|
|
188
|
+
name : ResumableTaskName.RecordsSquash,
|
|
189
|
+
data : { tenant, message }
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
170
193
|
// Dispatch post-processing hooks to the core protocol, if applicable.
|
|
171
194
|
// This allows core protocols to perform cascading side effects after a successful write
|
|
172
195
|
// (e.g. deleting messages authorized by a revoked grant).
|
|
@@ -306,6 +329,89 @@ export class RecordsWriteHandler implements MethodHandler {
|
|
|
306
329
|
}
|
|
307
330
|
}
|
|
308
331
|
|
|
332
|
+
/**
|
|
333
|
+
* Enforces the squash backstop: if the incoming message is at a protocol path with `$squash: true`,
|
|
334
|
+
* and there exists a squash record at the same protocol path and parent context whose
|
|
335
|
+
* `messageTimestamp` is >= the incoming message's `messageTimestamp`, reject with 409.
|
|
336
|
+
*
|
|
337
|
+
* This check only applies to protocol-based records at `$squash: true` paths.
|
|
338
|
+
*/
|
|
339
|
+
private async enforceSquashBackstop(tenant: string, message: RecordsWriteMessage): Promise<void> {
|
|
340
|
+
// Only applies to protocol-based records
|
|
341
|
+
if (message.descriptor.protocol === undefined || message.descriptor.protocolPath === undefined) {
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Fetch the protocol definition to check if $squash is enabled at this path.
|
|
346
|
+
// Pass coreProtocols so that core protocols (e.g. permissions) are resolved from the registry.
|
|
347
|
+
let protocolDefinition;
|
|
348
|
+
try {
|
|
349
|
+
protocolDefinition = await ProtocolAuthorization.fetchProtocolDefinition(
|
|
350
|
+
tenant,
|
|
351
|
+
message.descriptor.protocol,
|
|
352
|
+
this.deps.messageStore,
|
|
353
|
+
undefined,
|
|
354
|
+
this.deps.coreProtocols,
|
|
355
|
+
);
|
|
356
|
+
} catch (error) {
|
|
357
|
+
// If the protocol definition can't be found, skip the backstop check.
|
|
358
|
+
// Authorization will handle the missing protocol error later.
|
|
359
|
+
console.warn(`enforceSquashBackstop: failed to fetch protocol definition for '${message.descriptor.protocol}':`, error);
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// Walk the structure to find the rule set for this protocol path
|
|
364
|
+
const pathSegments = message.descriptor.protocolPath.split('/');
|
|
365
|
+
let ruleSet = protocolDefinition.structure[pathSegments[0]];
|
|
366
|
+
for (let i = 1; i < pathSegments.length && ruleSet !== undefined; i++) {
|
|
367
|
+
ruleSet = ruleSet[pathSegments[i]] as typeof ruleSet;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
if (ruleSet === undefined || ruleSet.$squash !== true) {
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Find the most recent squash record at the same protocol path and parent context
|
|
375
|
+
const filter: Filter = {
|
|
376
|
+
interface : DwnInterfaceName.Records,
|
|
377
|
+
method : DwnMethodName.Write,
|
|
378
|
+
isLatestBaseState : true,
|
|
379
|
+
protocol : message.descriptor.protocol,
|
|
380
|
+
protocolPath : message.descriptor.protocolPath,
|
|
381
|
+
squash : true,
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
// Scope by parent context for nested records
|
|
385
|
+
const parentContextId = Records.getParentContextFromOfContextId(message.contextId);
|
|
386
|
+
if (parentContextId !== undefined && parentContextId !== '') {
|
|
387
|
+
const prefixFilter = FilterUtility.constructPrefixFilterAsRangeFilter(parentContextId);
|
|
388
|
+
filter.contextId = prefixFilter;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const { messages: squashMessages } = await this.deps.messageStore.query(
|
|
392
|
+
tenant,
|
|
393
|
+
[filter],
|
|
394
|
+
{ messageTimestamp: SortDirection.Descending },
|
|
395
|
+
{ limit: 1 },
|
|
396
|
+
);
|
|
397
|
+
|
|
398
|
+
if (squashMessages.length === 0) {
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const newestSquash = squashMessages[0] as RecordsWriteMessage;
|
|
403
|
+
|
|
404
|
+
// Reject if the incoming message's timestamp is <= the squash record's timestamp
|
|
405
|
+
if (message.descriptor.messageTimestamp <= newestSquash.descriptor.messageTimestamp) {
|
|
406
|
+
throw new DwnError(
|
|
407
|
+
DwnErrorCode.ProtocolAuthorizationSquashBackstop,
|
|
408
|
+
`incoming message timestamp '${message.descriptor.messageTimestamp}' is not newer than ` +
|
|
409
|
+
`the most recent squash record timestamp '${newestSquash.descriptor.messageTimestamp}' ` +
|
|
410
|
+
`at protocol path '${message.descriptor.protocolPath}'.`
|
|
411
|
+
);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
309
415
|
private async authorizeRecordsWrite(tenant: string, recordsWrite: RecordsWrite, messageStore: MessageStore): Promise<void> {
|
|
310
416
|
// if owner signature is given (`owner` is not `undefined`), it must be the same as the tenant DID
|
|
311
417
|
if (recordsWrite.owner !== undefined && recordsWrite.owner !== tenant) {
|
package/src/index.ts
CHANGED
|
@@ -4,7 +4,7 @@ export type { EventListener, EventLog, EventLogEntry, EventLogReadOptions, Event
|
|
|
4
4
|
export type { AuthorizationModel, Descriptor, DelegatedGrantRecordsWriteMessage, GenericMessage, GenericMessageReply, GenericSignaturePayload, MessageSort, MessageSubscription, Pagination, QueryResultEntry, Status } from './types/message-types.js';
|
|
5
5
|
export type { MessagesFilter, MessagesReadMessage as MessagesReadMessage, MessagesReadReply as MessagesReadReply, MessagesReadReplyEntry as MessagesReadReplyEntry, MessagesReadDescriptor, MessagesSubscribeDescriptor, MessagesSubscribeMessage, MessagesSubscribeReply, MessageSubscriptionHandler, MessagesSubscribeMessageOptions, MessagesSyncAction, MessagesSyncDescriptor, MessagesSyncMessage, MessagesSyncReply } from './types/messages-types.js';
|
|
6
6
|
export type { GT, LT, Filter, FilterValue, KeyValues, EqualFilter, OneOfFilter, RangeFilter, RangeCriterion, PaginationCursor, QueryOptions, RangeValue, StartsWithFilter } from './types/query-types.js';
|
|
7
|
-
export type { ProtocolsConfigureDescriptor, ProtocolDefinition, ProtocolTypes, ProtocolRuleSet, ProtocolsQueryFilter, ProtocolsConfigureMessage, ProtocolsQueryMessage, ProtocolsQueryReply, ProtocolActionRule, ProtocolPathEncryption, ProtocolsQueryDescriptor, ProtocolRecordLimitDefinition, ProtocolSizeDefinition, ProtocolTagsDefinition, ProtocolTagSchema, ProtocolType, ProtocolUses } from './types/protocols-types.js';
|
|
7
|
+
export type { ProtocolsConfigureDescriptor, ProtocolDefinition, ProtocolTypes, ProtocolRuleSet, ProtocolsQueryFilter, ProtocolsConfigureMessage, ProtocolsQueryMessage, ProtocolsQueryReply, ProtocolActionRule, ProtocolDeliveryStrategy, ProtocolPathEncryption, ProtocolsQueryDescriptor, ProtocolRecordLimitDefinition, ProtocolSizeDefinition, ProtocolTagsDefinition, ProtocolTagSchema, ProtocolType, ProtocolUses } from './types/protocols-types.js';
|
|
8
8
|
export { ProtocolRecordLimitStrategy } from './types/protocols-types.js';
|
|
9
9
|
export type { DataEncodedRecordsWriteMessage, RecordsCountDescriptor, RecordsCountMessage, RecordsCountReply, RecordsDeleteMessage, RecordsFilter, RecordsQueryMessage, RecordsQueryReply, RecordsQueryReplyEntry, RecordsReadMessage, RecordsReadReply, RecordsSubscribeDescriptor, RecordsSubscribeMessage, RecordsSubscribeReply, RecordSubscriptionHandler, RecordsWriteDescriptor, RecordsWriteTags, RecordsWriteTagValue, RecordsWriteMessage, RecordsWriteSignaturePayload, RecordsDeleteDescriptor, RecordsQueryDescriptor, RecordsReadDescriptor, RecordsSubscribeMessageOptions, RecordsWriteMessageOptions, InternalRecordsWriteMessage, RecordEvent, RecordsWriteTagsFilter } from './types/records-types.js';
|
|
10
10
|
export type { GeneralJws, SignatureEntry } from './types/jws-types.js';
|
|
@@ -418,6 +418,17 @@ export class ProtocolsConfigure extends AbstractMessage<ProtocolsConfigureMessag
|
|
|
418
418
|
}
|
|
419
419
|
}
|
|
420
420
|
|
|
421
|
+
// Warn when `$delivery` is set without `$actions`.
|
|
422
|
+
// Delivery targets are determined from `$actions` role records and actor rules.
|
|
423
|
+
// Without `$actions`, the server cannot determine who to deliver records to.
|
|
424
|
+
if (ruleSet.$delivery !== undefined && (ruleSet.$actions === undefined || ruleSet.$actions.length === 0)) {
|
|
425
|
+
console.warn(
|
|
426
|
+
`ProtocolsConfigure: protocol path '${ruleSetProtocolPath}' has $delivery: '${ruleSet.$delivery}' ` +
|
|
427
|
+
`but no $actions rules. The server uses $actions to determine delivery targets — ` +
|
|
428
|
+
`without $actions, no participants can be resolved for delivery.`
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
|
|
421
432
|
// Warn when `$immutable: true` is combined with `$actions` that include `update` or `co-update`.
|
|
422
433
|
// The `$immutable` directive overrides any update permission — updates are always rejected.
|
|
423
434
|
if (ruleSet.$immutable === true && actionRules.length > 0) {
|
|
@@ -494,7 +505,7 @@ export class ProtocolsConfigure extends AbstractMessage<ProtocolsConfigureMessag
|
|
|
494
505
|
}
|
|
495
506
|
|
|
496
507
|
// validate that `$ref` nodes do not have other directives
|
|
497
|
-
const forbiddenDirectives = ['$actions', '$role', '$size', '$tags', '$encryption', '$recordLimit', '$immutable'] as const;
|
|
508
|
+
const forbiddenDirectives = ['$actions', '$role', '$size', '$tags', '$encryption', '$recordLimit', '$immutable', '$delivery', '$squash'] as const;
|
|
498
509
|
for (const directive of forbiddenDirectives) {
|
|
499
510
|
if (ruleSet[directive] !== undefined) {
|
|
500
511
|
throw new DwnError(
|
|
@@ -79,6 +79,13 @@ export type RecordsWriteOptions = {
|
|
|
79
79
|
encryptionInput?: EncryptionInput;
|
|
80
80
|
permissionGrantId?: string;
|
|
81
81
|
|
|
82
|
+
/**
|
|
83
|
+
* When `true`, this record is a squash (snapshot) write that atomically creates a snapshot
|
|
84
|
+
* and deletes all older sibling records at the same protocol path within the same parent context.
|
|
85
|
+
* Only valid at protocol paths with `$squash: true`. Must be an initial write (new record).
|
|
86
|
+
*/
|
|
87
|
+
squash?: true;
|
|
88
|
+
|
|
82
89
|
/**
|
|
83
90
|
* The author's ProtocolPath-derived public key for key delivery.
|
|
84
91
|
* When set, this is attached to the authorization model so the DWN owner
|
|
@@ -325,6 +332,7 @@ export class RecordsWrite implements MessageInterface<RecordsWriteMessage> {
|
|
|
325
332
|
datePublished : options.datePublished,
|
|
326
333
|
dataFormat : options.dataFormat,
|
|
327
334
|
permissionGrantId : options.permissionGrantId,
|
|
335
|
+
squash : options.squash,
|
|
328
336
|
};
|
|
329
337
|
|
|
330
338
|
// generate `datePublished` if the message is to be published but `datePublished` is not given
|
|
@@ -742,11 +750,13 @@ export class RecordsWrite implements MessageInterface<RecordsWriteMessage> {
|
|
|
742
750
|
// we want to process tags separately from the rest of descriptors as it is an object and not a primitive KeyValue type.
|
|
743
751
|
const { tags, ...descriptor } = message.descriptor;
|
|
744
752
|
delete descriptor.published; // handle `published` specifically further down
|
|
753
|
+
delete descriptor.squash; // handle `squash` specifically further down
|
|
745
754
|
|
|
746
755
|
let indexes: KeyValues = {
|
|
747
756
|
...descriptor,
|
|
748
757
|
isLatestBaseState,
|
|
749
758
|
published : !!message.descriptor.published,
|
|
759
|
+
squash : !!message.descriptor.squash,
|
|
750
760
|
author : this.author!, //author will not be undefined when indexes are constructed as it's been authorized
|
|
751
761
|
recordId : message.recordId,
|
|
752
762
|
entryId : await RecordsWrite.getEntryId(this.author, this.message.descriptor)
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type { DataStore } from '../types/data-store.js';
|
|
2
2
|
import type { EventLog } from '../types/subscriptions.js';
|
|
3
|
+
import type { Filter } from '../types/query-types.js';
|
|
3
4
|
import type { GenericMessage } from '../types/message-types.js';
|
|
4
5
|
import type { MessageStore } from '../types/message-store.js';
|
|
5
6
|
import type { StateIndex } from '../types/state-index.js';
|
|
6
7
|
import type { RecordsDeleteMessage, RecordsQueryReplyEntry, RecordsWriteMessage } from '../types/records-types.js';
|
|
7
8
|
|
|
8
9
|
import { DwnConstant } from '../core/dwn-constant.js';
|
|
10
|
+
import { FilterUtility } from '../utils/filter.js';
|
|
9
11
|
import { Message } from '../core/message.js';
|
|
10
12
|
import { Records } from '../utils/records.js';
|
|
11
13
|
import { RecordsDelete } from '../interfaces/records-delete.js';
|
|
@@ -18,6 +20,11 @@ export type ResumableRecordsDeleteData = {
|
|
|
18
20
|
message: RecordsDeleteMessage;
|
|
19
21
|
};
|
|
20
22
|
|
|
23
|
+
export type ResumableRecordsSquashData = {
|
|
24
|
+
tenant: string;
|
|
25
|
+
message: RecordsWriteMessage;
|
|
26
|
+
};
|
|
27
|
+
|
|
21
28
|
/**
|
|
22
29
|
* A class that provides an abstraction for the usage of MessageStore, DataStore, and StateIndex.
|
|
23
30
|
*/
|
|
@@ -82,6 +89,76 @@ export class StorageController {
|
|
|
82
89
|
);
|
|
83
90
|
}
|
|
84
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Performs the squash processing for a `RecordsWrite` with `squash: true`.
|
|
94
|
+
* Deletes all sibling records at the same protocol path and parent context whose
|
|
95
|
+
* `messageTimestamp` is strictly older than the squash record's `messageTimestamp`.
|
|
96
|
+
* Unlike normal `RecordsDelete` tombstones, squash targets are fully purged — no initial writes
|
|
97
|
+
* are retained.
|
|
98
|
+
*
|
|
99
|
+
* This method is idempotent — it can be safely re-run on resume after a crash.
|
|
100
|
+
*/
|
|
101
|
+
public async performRecordsSquash({ tenant, message }: ResumableRecordsSquashData): Promise<void> {
|
|
102
|
+
const { protocol, protocolPath, messageTimestamp } = message.descriptor;
|
|
103
|
+
|
|
104
|
+
// Build a filter to find all sibling records at the same protocol path and parent context.
|
|
105
|
+
// We query by interface only (not method) so that both RecordsWrite and RecordsDelete messages are found.
|
|
106
|
+
const filter: Filter = {
|
|
107
|
+
interface : DwnInterfaceName.Records,
|
|
108
|
+
protocol,
|
|
109
|
+
protocolPath : protocolPath,
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// Scope by parent context for nested records
|
|
113
|
+
const parentContextId = Records.getParentContextFromOfContextId(message.contextId);
|
|
114
|
+
if (parentContextId !== undefined && parentContextId !== '') {
|
|
115
|
+
const prefixFilter = FilterUtility.constructPrefixFilterAsRangeFilter(parentContextId);
|
|
116
|
+
filter.contextId = prefixFilter;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Query for all records at this path and context
|
|
120
|
+
const { messages: siblingMessages } = await this.messageStore.query(tenant, [filter]);
|
|
121
|
+
|
|
122
|
+
// Group messages by recordId — RecordsWrite messages use `message.recordId`,
|
|
123
|
+
// RecordsDelete messages use `message.descriptor.recordId`.
|
|
124
|
+
const recordIdToMessages = new Map<string, GenericMessage[]>();
|
|
125
|
+
for (const msg of siblingMessages) {
|
|
126
|
+
let recordId: string;
|
|
127
|
+
if (Records.isRecordsWrite(msg)) {
|
|
128
|
+
recordId = msg.recordId;
|
|
129
|
+
} else {
|
|
130
|
+
recordId = (msg as RecordsDeleteMessage).descriptor.recordId;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const existing = recordIdToMessages.get(recordId);
|
|
134
|
+
if (existing !== undefined) {
|
|
135
|
+
existing.push(msg);
|
|
136
|
+
} else {
|
|
137
|
+
recordIdToMessages.set(recordId, [msg]);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Delete all records whose newest message timestamp is strictly older than the squash timestamp.
|
|
142
|
+
// Skip the squash record itself.
|
|
143
|
+
for (const [recordId, messages] of recordIdToMessages) {
|
|
144
|
+
if (recordId === message.recordId) {
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Use the newest message's timestamp to determine if the record predates the squash.
|
|
149
|
+
const newestMessage = await Message.getNewestMessage(messages);
|
|
150
|
+
if (newestMessage === undefined) {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const newestTimestamp = newestMessage.descriptor.messageTimestamp;
|
|
155
|
+
if (newestTimestamp < messageTimestamp) {
|
|
156
|
+
// Fully purge this record — all messages (including initial write) and their data
|
|
157
|
+
await StorageController.purgeRecordMessages(tenant, messages, this.messageStore, this.dataStore, this.stateIndex);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
85
162
|
/**
|
|
86
163
|
* Deletes the data referenced by the given message if needed.
|
|
87
164
|
* @param message The message to check if the data it references should be deleted.
|
|
@@ -164,7 +241,7 @@ export class StorageController {
|
|
|
164
241
|
* Purges (permanent hard-delete) all messages of the SAME `recordId` given and their associated data and events.
|
|
165
242
|
* Assumes that the given `recordMessages` are all of the same `recordId`.
|
|
166
243
|
*/
|
|
167
|
-
|
|
244
|
+
public static async purgeRecordMessages(
|
|
168
245
|
tenant: string,
|
|
169
246
|
recordMessages: GenericMessage[],
|
|
170
247
|
messageStore: MessageStore,
|
|
@@ -75,6 +75,7 @@ export enum ProtocolAction {
|
|
|
75
75
|
Delete = 'delete',
|
|
76
76
|
Prune = 'prune',
|
|
77
77
|
Read = 'read',
|
|
78
|
+
Squash = 'squash',
|
|
78
79
|
Update = 'update'
|
|
79
80
|
}
|
|
80
81
|
|
|
@@ -184,6 +185,17 @@ export type ProtocolRecordLimitDefinition = {
|
|
|
184
185
|
strategy: ProtocolRecordLimitStrategy | `${ProtocolRecordLimitStrategy}` | (string & {});
|
|
185
186
|
};
|
|
186
187
|
|
|
188
|
+
/**
|
|
189
|
+
* Delivery strategy for records at a given protocol path.
|
|
190
|
+
* Controls how a DWN server proactively distributes records to participants' DWN endpoints.
|
|
191
|
+
*
|
|
192
|
+
* - `'direct'` — The origin DWN pushes new records to all participants' DWN endpoints.
|
|
193
|
+
* Best for small participant sets (2–50).
|
|
194
|
+
* - `'subscribe'` — Participant providers establish `RecordsSubscribe` connections to the
|
|
195
|
+
* origin DWN. Best for asymmetric fan-out or unbounded audiences.
|
|
196
|
+
*/
|
|
197
|
+
export type ProtocolDeliveryStrategy = 'direct' | 'subscribe';
|
|
198
|
+
|
|
187
199
|
/**
|
|
188
200
|
* Tag rules for records at a given protocol path. Each non-`$`-prefixed property
|
|
189
201
|
* is a JSON Schema object constraining that tag's value.
|
|
@@ -222,7 +234,7 @@ export type ProtocolTagSchema = {
|
|
|
222
234
|
/**
|
|
223
235
|
* Union of all value types that can appear as properties of a `ProtocolRuleSet`.
|
|
224
236
|
* This includes:
|
|
225
|
-
* - `$`-prefixed directive values (`$encryption`, `$actions`, `$role`, `$ref`, `$size`, `$tags`)
|
|
237
|
+
* - `$`-prefixed directive values (`$encryption`, `$actions`, `$role`, `$ref`, `$size`, `$tags`, `$delivery`)
|
|
226
238
|
* - Child `ProtocolRuleSet` entries (non-`$` keys)
|
|
227
239
|
*/
|
|
228
240
|
type ProtocolRuleSetValue =
|
|
@@ -232,6 +244,7 @@ type ProtocolRuleSetValue =
|
|
|
232
244
|
| ProtocolTagsDefinition
|
|
233
245
|
| ProtocolSizeDefinition
|
|
234
246
|
| ProtocolRecordLimitDefinition
|
|
247
|
+
| ProtocolDeliveryStrategy
|
|
235
248
|
| boolean
|
|
236
249
|
| string
|
|
237
250
|
| undefined;
|
|
@@ -293,6 +306,24 @@ export type ProtocolRuleSet = {
|
|
|
293
306
|
*/
|
|
294
307
|
$immutable?: boolean;
|
|
295
308
|
|
|
309
|
+
/**
|
|
310
|
+
* Delivery strategy hint for records at this protocol path.
|
|
311
|
+
* When set, the DWN server SHOULD proactively deliver records to participants' DWN endpoints.
|
|
312
|
+
*
|
|
313
|
+
* - `'direct'` — Origin DWN pushes to all participant DWN endpoints upon receipt.
|
|
314
|
+
* - `'subscribe'` — Participant providers subscribe to the origin DWN via `RecordsSubscribe`.
|
|
315
|
+
*/
|
|
316
|
+
$delivery?: ProtocolDeliveryStrategy;
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* If `$squash` is `true`, enables squash writes at this protocol path.
|
|
320
|
+
* A squash write is a `RecordsWrite` with `squash: true` in the descriptor that
|
|
321
|
+
* atomically creates a new record (the snapshot) and deletes all sibling records
|
|
322
|
+
* at the same protocol path within the same parent context that have a
|
|
323
|
+
* `messageTimestamp` strictly older than the squash record's `messageTimestamp`.
|
|
324
|
+
*/
|
|
325
|
+
$squash?: boolean;
|
|
326
|
+
|
|
296
327
|
/**
|
|
297
328
|
* Non-`$`-prefixed keys are nested child `ProtocolRuleSet` entries.
|
|
298
329
|
* At runtime, JSON Schema validation ensures only valid child rule sets appear here.
|
|
@@ -38,6 +38,14 @@ export type RecordsWriteDescriptor = {
|
|
|
38
38
|
datePublished?: string;
|
|
39
39
|
dataFormat: string;
|
|
40
40
|
permissionGrantId?: string;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* When `true`, this record is a squash (snapshot) write. The protocol rule set at this record's
|
|
44
|
+
* `protocolPath` must have `$squash: true`; otherwise the message is rejected.
|
|
45
|
+
* A squash write must be an initial write (a new record, not an update).
|
|
46
|
+
* This is an immutable property.
|
|
47
|
+
*/
|
|
48
|
+
squash?: true;
|
|
41
49
|
};
|
|
42
50
|
|
|
43
51
|
export type RecordsWriteMessageOptions = {
|