@mdbase-dev/sdk 0.0.0-stage → 0.1.0-beta.149
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/LICENSE +21 -0
- package/README.md +844 -2
- package/dist/account-key.d.ts +176 -0
- package/dist/account-key.js +409 -0
- package/dist/account-key.js.map +1 -0
- package/dist/account.d.ts +11 -0
- package/dist/account.js +9 -0
- package/dist/account.js.map +1 -0
- package/dist/app-grant/client.d.ts +209 -0
- package/dist/app-grant/client.js +930 -0
- package/dist/app-grant/client.js.map +1 -0
- package/dist/app-grant/grant-store.d.ts +77 -0
- package/dist/app-grant/grant-store.js +201 -0
- package/dist/app-grant/grant-store.js.map +1 -0
- package/dist/app-grant/index.d.ts +11 -0
- package/dist/app-grant/index.js +10 -0
- package/dist/app-grant/index.js.map +1 -0
- package/dist/app-grant/native-completion.d.ts +22 -0
- package/dist/app-grant/native-completion.js +63 -0
- package/dist/app-grant/native-completion.js.map +1 -0
- package/dist/app-grant/people.d.ts +10 -0
- package/dist/app-grant/people.js +84 -0
- package/dist/app-grant/people.js.map +1 -0
- package/dist/app-grant/setup-attempt.d.ts +12 -0
- package/dist/app-grant/setup-attempt.js +62 -0
- package/dist/app-grant/setup-attempt.js.map +1 -0
- package/dist/app-grant/setup-producer.d.ts +31 -0
- package/dist/app-grant/setup-producer.js +65 -0
- package/dist/app-grant/setup-producer.js.map +1 -0
- package/dist/app-grant/setup.d.ts +11 -0
- package/dist/app-grant/setup.js +222 -0
- package/dist/app-grant/setup.js.map +1 -0
- package/dist/app-host/app-environment.d.ts +27 -0
- package/dist/app-host/app-environment.js +48 -0
- package/dist/app-host/app-environment.js.map +1 -0
- package/dist/app-host/app-origin.d.ts +7 -0
- package/dist/app-host/app-origin.js +49 -0
- package/dist/app-host/app-origin.js.map +1 -0
- package/dist/app-host/bases-pages.d.ts +29 -0
- package/dist/app-host/bases-pages.js +42 -0
- package/dist/app-host/bases-pages.js.map +1 -0
- package/dist/app-host/bases-wire.d.ts +159 -0
- package/dist/app-host/bases-wire.js +376 -0
- package/dist/app-host/bases-wire.js.map +1 -0
- package/dist/app-host/browser-direct-access.d.ts +18 -0
- package/dist/app-host/browser-direct-access.js +17 -0
- package/dist/app-host/browser-direct-access.js.map +1 -0
- package/dist/app-host/cloud-copy-bootstrap.d.ts +127 -0
- package/dist/app-host/cloud-copy-bootstrap.js +608 -0
- package/dist/app-host/cloud-copy-bootstrap.js.map +1 -0
- package/dist/app-host/cloud-copy-host.d.ts +248 -0
- package/dist/app-host/cloud-copy-host.js +1028 -0
- package/dist/app-host/cloud-copy-host.js.map +1 -0
- package/dist/app-host/cloud-copy-persistence-idb.d.ts +33 -0
- package/dist/app-host/cloud-copy-persistence-idb.js +255 -0
- package/dist/app-host/cloud-copy-persistence-idb.js.map +1 -0
- package/dist/app-host/cloud-copy-persistence.d.ts +57 -0
- package/dist/app-host/cloud-copy-persistence.js +341 -0
- package/dist/app-host/cloud-copy-persistence.js.map +1 -0
- package/dist/app-host/collection-control.d.ts +111 -0
- package/dist/app-host/collection-control.js +604 -0
- package/dist/app-host/collection-control.js.map +1 -0
- package/dist/app-host/collection-delete.d.ts +7 -0
- package/dist/app-host/collection-delete.js +54 -0
- package/dist/app-host/collection-delete.js.map +1 -0
- package/dist/app-host/collection-display-name.d.ts +2 -0
- package/dist/app-host/collection-display-name.js +22 -0
- package/dist/app-host/collection-display-name.js.map +1 -0
- package/dist/app-host/collection-join-ledger.d.ts +52 -0
- package/dist/app-host/collection-join-ledger.js +208 -0
- package/dist/app-host/collection-join-ledger.js.map +1 -0
- package/dist/app-host/collection-people.d.ts +32 -0
- package/dist/app-host/collection-people.js +119 -0
- package/dist/app-host/collection-people.js.map +1 -0
- package/dist/app-host/collection-readiness.d.ts +119 -0
- package/dist/app-host/collection-readiness.js +649 -0
- package/dist/app-host/collection-readiness.js.map +1 -0
- package/dist/app-host/collection-setup-journal.d.ts +59 -0
- package/dist/app-host/collection-setup-journal.js +813 -0
- package/dist/app-host/collection-setup-journal.js.map +1 -0
- package/dist/app-host/collection-setup-types.d.ts +155 -0
- package/dist/app-host/collection-setup-types.js +10 -0
- package/dist/app-host/collection-setup-types.js.map +1 -0
- package/dist/app-host/cp-authority.d.ts +65 -0
- package/dist/app-host/cp-authority.js +243 -0
- package/dist/app-host/cp-authority.js.map +1 -0
- package/dist/app-host/cp-people.d.ts +23 -0
- package/dist/app-host/cp-people.js +145 -0
- package/dist/app-host/cp-people.js.map +1 -0
- package/dist/app-host/cp-problem.d.ts +34 -0
- package/dist/app-host/cp-problem.js +114 -0
- package/dist/app-host/cp-problem.js.map +1 -0
- package/dist/app-host/device-key-custody.d.ts +51 -0
- package/dist/app-host/device-key-custody.js +128 -0
- package/dist/app-host/device-key-custody.js.map +1 -0
- package/dist/app-host/device-key-idb.d.ts +31 -0
- package/dist/app-host/device-key-idb.js +176 -0
- package/dist/app-host/device-key-idb.js.map +1 -0
- package/dist/app-host/device-key-provider.d.ts +33 -0
- package/dist/app-host/device-key-provider.js +181 -0
- package/dist/app-host/device-key-provider.js.map +1 -0
- package/dist/app-host/device-registration.d.ts +51 -0
- package/dist/app-host/device-registration.js +180 -0
- package/dist/app-host/device-registration.js.map +1 -0
- package/dist/app-host/foreground-wake.d.ts +43 -0
- package/dist/app-host/foreground-wake.js +113 -0
- package/dist/app-host/foreground-wake.js.map +1 -0
- package/dist/app-host/handover.d.ts +27 -0
- package/dist/app-host/handover.js +82 -0
- package/dist/app-host/handover.js.map +1 -0
- package/dist/app-host/http-log.d.ts +96 -0
- package/dist/app-host/http-log.js +609 -0
- package/dist/app-host/http-log.js.map +1 -0
- package/dist/app-host/index.d.ts +63 -0
- package/dist/app-host/index.js +33 -0
- package/dist/app-host/index.js.map +1 -0
- package/dist/app-host/initial-sync.d.ts +22 -0
- package/dist/app-host/initial-sync.js +41 -0
- package/dist/app-host/initial-sync.js.map +1 -0
- package/dist/app-host/installation-sign-in.d.ts +319 -0
- package/dist/app-host/installation-sign-in.js +1231 -0
- package/dist/app-host/installation-sign-in.js.map +1 -0
- package/dist/app-host/installation-store.d.ts +56 -0
- package/dist/app-host/installation-store.js +285 -0
- package/dist/app-host/installation-store.js.map +1 -0
- package/dist/app-host/ledger-rows.d.ts +3 -0
- package/dist/app-host/ledger-rows.js +23 -0
- package/dist/app-host/ledger-rows.js.map +1 -0
- package/dist/app-host/local-facade.d.ts +24 -0
- package/dist/app-host/local-facade.js +361 -0
- package/dist/app-host/local-facade.js.map +1 -0
- package/dist/app-host/log-pump.d.ts +124 -0
- package/dist/app-host/log-pump.js +326 -0
- package/dist/app-host/log-pump.js.map +1 -0
- package/dist/app-host/log-push.d.ts +90 -0
- package/dist/app-host/log-push.js +377 -0
- package/dist/app-host/log-push.js.map +1 -0
- package/dist/app-host/log-token-cache.d.ts +28 -0
- package/dist/app-host/log-token-cache.js +104 -0
- package/dist/app-host/log-token-cache.js.map +1 -0
- package/dist/app-host/native-sign-in.d.ts +27 -0
- package/dist/app-host/native-sign-in.js +12 -0
- package/dist/app-host/native-sign-in.js.map +1 -0
- package/dist/app-host/noise-custody.d.ts +62 -0
- package/dist/app-host/noise-custody.js +238 -0
- package/dist/app-host/noise-custody.js.map +1 -0
- package/dist/app-host/noise-idb.d.ts +33 -0
- package/dist/app-host/noise-idb.js +199 -0
- package/dist/app-host/noise-idb.js.map +1 -0
- package/dist/app-host/open-wait.d.ts +3 -0
- package/dist/app-host/open-wait.js +17 -0
- package/dist/app-host/open-wait.js.map +1 -0
- package/dist/app-host/opening-progress.d.ts +3 -0
- package/dist/app-host/opening-progress.js +5 -0
- package/dist/app-host/opening-progress.js.map +1 -0
- package/dist/app-host/owner.d.ts +103 -0
- package/dist/app-host/owner.js +262 -0
- package/dist/app-host/owner.js.map +1 -0
- package/dist/app-host/private-bootstrap.d.ts +78 -0
- package/dist/app-host/private-bootstrap.js +230 -0
- package/dist/app-host/private-bootstrap.js.map +1 -0
- package/dist/app-host/private-persistence-idb.d.ts +32 -0
- package/dist/app-host/private-persistence-idb.js +188 -0
- package/dist/app-host/private-persistence-idb.js.map +1 -0
- package/dist/app-host/private-persistence.d.ts +55 -0
- package/dist/app-host/private-persistence.js +257 -0
- package/dist/app-host/private-persistence.js.map +1 -0
- package/dist/app-host/scoped-sign-in-session.d.ts +49 -0
- package/dist/app-host/scoped-sign-in-session.js +243 -0
- package/dist/app-host/scoped-sign-in-session.js.map +1 -0
- package/dist/app-host/setup-engine.d.ts +14 -0
- package/dist/app-host/setup-engine.js +73 -0
- package/dist/app-host/setup-engine.js.map +1 -0
- package/dist/app-host/sign-out-erase.d.ts +37 -0
- package/dist/app-host/sign-out-erase.js +139 -0
- package/dist/app-host/sign-out-erase.js.map +1 -0
- package/dist/app-host/status.d.ts +62 -0
- package/dist/app-host/status.js +43 -0
- package/dist/app-host/status.js.map +1 -0
- package/dist/app-host/storage-probe.d.ts +46 -0
- package/dist/app-host/storage-probe.js +63 -0
- package/dist/app-host/storage-probe.js.map +1 -0
- package/dist/app-host/timer-port.d.ts +29 -0
- package/dist/app-host/timer-port.js +483 -0
- package/dist/app-host/timer-port.js.map +1 -0
- package/dist/app-host/wasm-runtime.d.ts +302 -0
- package/dist/app-host/wasm-runtime.js +1050 -0
- package/dist/app-host/wasm-runtime.js.map +1 -0
- package/dist/app-host/web-collection.d.ts +78 -0
- package/dist/app-host/web-collection.js +671 -0
- package/dist/app-host/web-collection.js.map +1 -0
- package/dist/app-host/web-sign-in-problem.d.ts +17 -0
- package/dist/app-host/web-sign-in-problem.js +59 -0
- package/dist/app-host/web-sign-in-problem.js.map +1 -0
- package/dist/app-host/web-sign-in-session.d.ts +367 -0
- package/dist/app-host/web-sign-in-session.js +1258 -0
- package/dist/app-host/web-sign-in-session.js.map +1 -0
- package/dist/app-storage/app-binary-index.d.ts +33 -0
- package/dist/app-storage/app-binary-index.js +274 -0
- package/dist/app-storage/app-binary-index.js.map +1 -0
- package/dist/app-storage/app-sqlite-index.d.ts +40 -0
- package/dist/app-storage/app-sqlite-index.js +102 -0
- package/dist/app-storage/app-sqlite-index.js.map +1 -0
- package/dist/app-storage/collection-sql.d.ts +39 -0
- package/dist/app-storage/collection-sql.js +93 -0
- package/dist/app-storage/collection-sql.js.map +1 -0
- package/dist/app-storage/index.d.ts +10 -0
- package/dist/app-storage/index.js +7 -0
- package/dist/app-storage/index.js.map +1 -0
- package/dist/app-storage/sqlite-index.d.ts +95 -0
- package/dist/app-storage/sqlite-index.js +280 -0
- package/dist/app-storage/sqlite-index.js.map +1 -0
- package/dist/application/asset-loader.d.ts +22 -0
- package/dist/application/asset-loader.js +130 -0
- package/dist/application/asset-loader.js.map +1 -0
- package/dist/application/asset-pins.json +24 -0
- package/dist/application/browser-capabilities.d.ts +48 -0
- package/dist/application/browser-capabilities.js +87 -0
- package/dist/application/browser-capabilities.js.map +1 -0
- package/dist/application/browser-selection.d.ts +58 -0
- package/dist/application/browser-selection.js +160 -0
- package/dist/application/browser-selection.js.map +1 -0
- package/dist/application/capabilities.d.ts +20 -0
- package/dist/application/capabilities.js +22 -0
- package/dist/application/capabilities.js.map +1 -0
- package/dist/application/collection-selection.d.ts +147 -0
- package/dist/application/collection-selection.js +351 -0
- package/dist/application/collection-selection.js.map +1 -0
- package/dist/application/configuration.d.ts +52 -0
- package/dist/application/configuration.js +568 -0
- package/dist/application/configuration.js.map +1 -0
- package/dist/application/declaration.d.ts +51 -0
- package/dist/application/declaration.js +100 -0
- package/dist/application/declaration.js.map +1 -0
- package/dist/application/entry.d.ts +343 -0
- package/dist/application/entry.js +945 -0
- package/dist/application/entry.js.map +1 -0
- package/dist/application/file-access.d.ts +55 -0
- package/dist/application/file-access.js +93 -0
- package/dist/application/file-access.js.map +1 -0
- package/dist/application/file-readiness.d.ts +16 -0
- package/dist/application/file-readiness.js +53 -0
- package/dist/application/file-readiness.js.map +1 -0
- package/dist/application/forgotten.d.ts +15 -0
- package/dist/application/forgotten.js +70 -0
- package/dist/application/forgotten.js.map +1 -0
- package/dist/application/front-door.d.ts +68 -0
- package/dist/application/front-door.js +66 -0
- package/dist/application/front-door.js.map +1 -0
- package/dist/application/local-build.d.ts +5 -0
- package/dist/application/local-build.js +22 -0
- package/dist/application/local-build.js.map +1 -0
- package/dist/application/manifest.d.ts +16 -0
- package/dist/application/manifest.js +31 -0
- package/dist/application/manifest.js.map +1 -0
- package/dist/application/native-assets.d.ts +25 -0
- package/dist/application/native-assets.js +29 -0
- package/dist/application/native-assets.js.map +1 -0
- package/dist/application/native-authorization-rpc.d.ts +23 -0
- package/dist/application/native-authorization-rpc.js +54 -0
- package/dist/application/native-authorization-rpc.js.map +1 -0
- package/dist/application/notification-readiness.d.ts +33 -0
- package/dist/application/notification-readiness.js +222 -0
- package/dist/application/notification-readiness.js.map +1 -0
- package/dist/application/packaged-assets.d.ts +5 -0
- package/dist/application/packaged-assets.js +55 -0
- package/dist/application/packaged-assets.js.map +1 -0
- package/dist/application/packaged-trust.d.ts +5 -0
- package/dist/application/packaged-trust.js +10 -0
- package/dist/application/packaged-trust.js.map +1 -0
- package/dist/application/people-readiness.d.ts +23 -0
- package/dist/application/people-readiness.js +213 -0
- package/dist/application/people-readiness.js.map +1 -0
- package/dist/application/phase.d.ts +108 -0
- package/dist/application/phase.js +113 -0
- package/dist/application/phase.js.map +1 -0
- package/dist/application/portal-reservation.d.ts +38 -0
- package/dist/application/portal-reservation.js +183 -0
- package/dist/application/portal-reservation.js.map +1 -0
- package/dist/application/private-collections.d.ts +114 -0
- package/dist/application/private-collections.js +415 -0
- package/dist/application/private-collections.js.map +1 -0
- package/dist/application/readiness.d.ts +59 -0
- package/dist/application/readiness.js +223 -0
- package/dist/application/readiness.js.map +1 -0
- package/dist/application/registration-refusal.d.ts +16 -0
- package/dist/application/registration-refusal.js +41 -0
- package/dist/application/registration-refusal.js.map +1 -0
- package/dist/application/registration.d.ts +26 -0
- package/dist/application/registration.js +372 -0
- package/dist/application/registration.js.map +1 -0
- package/dist/application/return-url.d.ts +1 -0
- package/dist/application/return-url.js +41 -0
- package/dist/application/return-url.js.map +1 -0
- package/dist/application/runtime.d.ts +107 -0
- package/dist/application/runtime.js +379 -0
- package/dist/application/runtime.js.map +1 -0
- package/dist/application/scope.d.ts +34 -0
- package/dist/application/scope.js +164 -0
- package/dist/application/scope.js.map +1 -0
- package/dist/application/session-hint.d.ts +21 -0
- package/dist/application/session-hint.js +87 -0
- package/dist/application/session-hint.js.map +1 -0
- package/dist/application/setup.d.ts +105 -0
- package/dist/application/setup.js +137 -0
- package/dist/application/setup.js.map +1 -0
- package/dist/application/sign-out.d.ts +17 -0
- package/dist/application/sign-out.js +28 -0
- package/dist/application/sign-out.js.map +1 -0
- package/dist/application/storage-scope.d.ts +8 -0
- package/dist/application/storage-scope.js +15 -0
- package/dist/application/storage-scope.js.map +1 -0
- package/dist/application/tabs.d.ts +98 -0
- package/dist/application/tabs.js +407 -0
- package/dist/application/tabs.js.map +1 -0
- package/dist/application/timer-criteria.d.ts +5 -0
- package/dist/application/timer-criteria.js +15 -0
- package/dist/application/timer-criteria.js.map +1 -0
- package/dist/application/ui-connections.d.ts +35 -0
- package/dist/application/ui-connections.js +129 -0
- package/dist/application/ui-connections.js.map +1 -0
- package/dist/application/worker-client.d.ts +59 -0
- package/dist/application/worker-client.js +381 -0
- package/dist/application/worker-client.js.map +1 -0
- package/dist/application/worker-host.d.ts +84 -0
- package/dist/application/worker-host.js +547 -0
- package/dist/application/worker-host.js.map +1 -0
- package/dist/application/worker-protocol.d.ts +40 -0
- package/dist/application/worker-protocol.js +83 -0
- package/dist/application/worker-protocol.js.map +1 -0
- package/dist/application/worker-session.d.ts +45 -0
- package/dist/application/worker-session.js +37 -0
- package/dist/application/worker-session.js.map +1 -0
- package/dist/application/worker.d.ts +1 -0
- package/dist/application/worker.js +34826 -0
- package/dist/application/worker.js.map +1 -0
- package/dist/attachment-wire.d.ts +15 -0
- package/dist/attachment-wire.js +47 -0
- package/dist/attachment-wire.js.map +1 -0
- package/dist/browser/mdbase-sdk.js +49392 -0
- package/dist/browser/mdbase-sdk.min.js +130 -0
- package/dist/browser.d.ts +4 -0
- package/dist/browser.js +5 -0
- package/dist/browser.js.map +1 -0
- package/dist/cbor.d.ts +52 -0
- package/dist/cbor.js +480 -0
- package/dist/cbor.js.map +1 -0
- package/dist/client.d.ts +656 -0
- package/dist/client.js +1962 -0
- package/dist/client.js.map +1 -0
- package/dist/codec.d.ts +82 -0
- package/dist/codec.js +388 -0
- package/dist/codec.js.map +1 -0
- package/dist/collection-availability.d.ts +34 -0
- package/dist/collection-availability.js +63 -0
- package/dist/collection-availability.js.map +1 -0
- package/dist/contract-query.d.ts +31 -0
- package/dist/contract-query.js +13 -0
- package/dist/contract-query.js.map +1 -0
- package/dist/contract-records.d.ts +51 -0
- package/dist/contract-records.js +14 -0
- package/dist/contract-records.js.map +1 -0
- package/dist/describe-error.d.ts +61 -0
- package/dist/describe-error.js +452 -0
- package/dist/describe-error.js.map +1 -0
- package/dist/errors.d.ts +65 -0
- package/dist/errors.js +94 -0
- package/dist/errors.js.map +1 -0
- package/dist/files.d.ts +147 -0
- package/dist/files.js +537 -0
- package/dist/files.js.map +1 -0
- package/dist/holds.d.ts +74 -0
- package/dist/holds.js +118 -0
- package/dist/holds.js.map +1 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/keys.d.ts +40 -0
- package/dist/keys.js +181 -0
- package/dist/keys.js.map +1 -0
- package/dist/live.d.ts +38 -0
- package/dist/live.js +82 -0
- package/dist/live.js.map +1 -0
- package/dist/local-build.d.ts +9 -0
- package/dist/local-build.js +33 -0
- package/dist/local-build.js.map +1 -0
- package/dist/native/provenance.json +23 -0
- package/dist/native/runtime.wasm +0 -0
- package/dist/native/sqlite3.d.ts +5 -0
- package/dist/native/sqlite3.js +17392 -0
- package/dist/native/sqlite3.js.map +1 -0
- package/dist/native/sqlite3.wasm +0 -0
- package/dist/node.d.ts +63 -0
- package/dist/node.js +255 -0
- package/dist/node.js.map +1 -0
- package/dist/notifications.d.ts +95 -0
- package/dist/notifications.js +226 -0
- package/dist/notifications.js.map +1 -0
- package/dist/offline-shell-build.d.ts +25 -0
- package/dist/offline-shell-build.js +78 -0
- package/dist/offline-shell-build.js.map +1 -0
- package/dist/offline-shell-worker.d.ts +46 -0
- package/dist/offline-shell-worker.js +115 -0
- package/dist/offline-shell-worker.js.map +1 -0
- package/dist/people.d.ts +82 -0
- package/dist/people.js +199 -0
- package/dist/people.js.map +1 -0
- package/dist/presence.d.ts +21 -0
- package/dist/presence.js +109 -0
- package/dist/presence.js.map +1 -0
- package/dist/private-account.d.ts +197 -0
- package/dist/private-account.js +510 -0
- package/dist/private-account.js.map +1 -0
- package/dist/private.d.ts +55 -0
- package/dist/private.js +69 -0
- package/dist/private.js.map +1 -0
- package/dist/read-helpers.d.ts +32 -0
- package/dist/read-helpers.js +181 -0
- package/dist/read-helpers.js.map +1 -0
- package/dist/records/session.d.ts +60 -0
- package/dist/records/session.js +534 -0
- package/dist/records/session.js.map +1 -0
- package/dist/records/types.d.ts +76 -0
- package/dist/records/types.js +2 -0
- package/dist/records/types.js.map +1 -0
- package/dist/records/witness.d.ts +19 -0
- package/dist/records/witness.js +64 -0
- package/dist/records/witness.js.map +1 -0
- package/dist/records.d.ts +23 -0
- package/dist/records.js +234 -0
- package/dist/records.js.map +1 -0
- package/dist/runtime/wasm.d.ts +69 -0
- package/dist/runtime/wasm.js +274 -0
- package/dist/runtime/wasm.js.map +1 -0
- package/dist/runtime-wire.d.ts +71 -0
- package/dist/runtime-wire.js +71 -0
- package/dist/runtime-wire.js.map +1 -0
- package/dist/saved-views.d.ts +29 -0
- package/dist/saved-views.js +171 -0
- package/dist/saved-views.js.map +1 -0
- package/dist/semver.d.ts +22 -0
- package/dist/semver.js +63 -0
- package/dist/semver.js.map +1 -0
- package/dist/session.d.ts +65 -0
- package/dist/session.js +332 -0
- package/dist/session.js.map +1 -0
- package/dist/status.d.ts +46 -0
- package/dist/status.js +59 -0
- package/dist/status.js.map +1 -0
- package/dist/strength.d.ts +12 -0
- package/dist/strength.js +194 -0
- package/dist/strength.js.map +1 -0
- package/dist/testing/application.d.ts +59 -0
- package/dist/testing/application.js +230 -0
- package/dist/testing/application.js.map +1 -0
- package/dist/testing/index.d.ts +10 -0
- package/dist/testing/index.js +6 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/memory-contracts.d.ts +40 -0
- package/dist/testing/memory-contracts.js +127 -0
- package/dist/testing/memory-contracts.js.map +1 -0
- package/dist/testing/memory-replica.d.ts +191 -0
- package/dist/testing/memory-replica.js +1465 -0
- package/dist/testing/memory-replica.js.map +1 -0
- package/dist/testing/noise-server.d.ts +11 -0
- package/dist/testing/noise-server.js +65 -0
- package/dist/testing/noise-server.js.map +1 -0
- package/dist/testing/test-app.d.ts +93 -0
- package/dist/testing/test-app.js +140 -0
- package/dist/testing/test-app.js.map +1 -0
- package/dist/thin-client.d.ts +67 -0
- package/dist/thin-client.js +42 -0
- package/dist/thin-client.js.map +1 -0
- package/dist/timers.d.ts +158 -0
- package/dist/timers.js +258 -0
- package/dist/timers.js.map +1 -0
- package/dist/transport/bases-rpc.d.ts +15 -0
- package/dist/transport/bases-rpc.js +61 -0
- package/dist/transport/bases-rpc.js.map +1 -0
- package/dist/transport/control-route.d.ts +34 -0
- package/dist/transport/control-route.js +84 -0
- package/dist/transport/control-route.js.map +1 -0
- package/dist/transport/inprocess.d.ts +13 -0
- package/dist/transport/inprocess.js +37 -0
- package/dist/transport/inprocess.js.map +1 -0
- package/dist/transport/local-link.d.ts +53 -0
- package/dist/transport/local-link.js +66 -0
- package/dist/transport/local-link.js.map +1 -0
- package/dist/transport/next-relay.d.ts +64 -0
- package/dist/transport/next-relay.js +222 -0
- package/dist/transport/next-relay.js.map +1 -0
- package/dist/transport/noise-session.d.ts +88 -0
- package/dist/transport/noise-session.js +264 -0
- package/dist/transport/noise-session.js.map +1 -0
- package/dist/transport/noise.d.ts +102 -0
- package/dist/transport/noise.js +307 -0
- package/dist/transport/noise.js.map +1 -0
- package/dist/transport/original-session.d.ts +6 -0
- package/dist/transport/original-session.js +6 -0
- package/dist/transport/original-session.js.map +1 -0
- package/dist/transport/port.d.ts +67 -0
- package/dist/transport/port.js +184 -0
- package/dist/transport/port.js.map +1 -0
- package/dist/transport/read-fence-policy.d.ts +3 -0
- package/dist/transport/read-fence-policy.js +11 -0
- package/dist/transport/read-fence-policy.js.map +1 -0
- package/dist/transport/relay-close.d.ts +31 -0
- package/dist/transport/relay-close.js +23 -0
- package/dist/transport/relay-close.js.map +1 -0
- package/dist/transport/relay-pipe.d.ts +15 -0
- package/dist/transport/relay-pipe.js +190 -0
- package/dist/transport/relay-pipe.js.map +1 -0
- package/dist/transport/relay.d.ts +36 -0
- package/dist/transport/relay.js +45 -0
- package/dist/transport/relay.js.map +1 -0
- package/dist/type-packs.d.ts +124 -0
- package/dist/type-packs.js +188 -0
- package/dist/type-packs.js.map +1 -0
- package/dist/validation.d.ts +30 -0
- package/dist/validation.js +125 -0
- package/dist/validation.js.map +1 -0
- package/dist/values.d.ts +37 -0
- package/dist/values.js +133 -0
- package/dist/values.js.map +1 -0
- package/dist/view-sources.d.ts +31 -0
- package/dist/view-sources.js +78 -0
- package/dist/view-sources.js.map +1 -0
- package/dist/wire.d.ts +856 -0
- package/dist/wire.js +914 -0
- package/dist/wire.js.map +1 -0
- package/dist/witness.d.ts +7 -0
- package/dist/witness.js +82 -0
- package/dist/witness.js.map +1 -0
- package/dist/write-ledger.d.ts +41 -0
- package/dist/write-ledger.js +184 -0
- package/dist/write-ledger.js.map +1 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/application-authorization.d.ts +32 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/application-authorization.js +207 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/application-contract.d.ts +23 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/application-contract.js +76 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/application-declaration.d.ts +120 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/application-declaration.js +1 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/authorization-errors.d.ts +34 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/authorization-errors.js +52 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/capabilities.d.ts +73 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/capabilities.js +92 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/change-events.generated.d.ts +48 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/change-events.generated.js +18 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/collection-setup.d.ts +93 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/collection-setup.js +7 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/compatibility.d.ts +37 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/compatibility.js +65 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/connect-problems.generated.d.ts +1533 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/connect-problems.generated.js +598 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/files.d.ts +288 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/files.js +426 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/index.d.ts +723 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/index.js +104 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/manifest-validators.generated.d.ts +13 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/manifest-validators.generated.js +7940 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/manifest.d.ts +72 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/manifest.js +643 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/mutation-fingerprint.d.ts +6 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/mutation-fingerprint.js +116 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/next-authorization.d.ts +30 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/next-authorization.js +90 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/operations.d.ts +15 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/operations.js +196 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/people.d.ts +33 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/people.js +26 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/records.d.ts +108 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/records.js +3 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/type-packs.d.ts +154 -0
- package/node_modules/@mdbase-dev/connect-protocol/dist/type-packs.js +30 -0
- package/node_modules/@mdbase-dev/connect-protocol/package.json +49 -0
- package/node_modules/@mdbase-dev/connect-protocol/schemas/application-capability-catalog.v1.json +40 -0
- package/node_modules/@mdbase-dev/connect-protocol/schemas/application-capability-catalog.v2.json +68 -0
- package/node_modules/@mdbase-dev/connect-protocol/schemas/catalog.json +17 -0
- package/node_modules/@mdbase-dev/connect-protocol/schemas/change-events.v1.json +48 -0
- package/node_modules/@mdbase-dev/connect-protocol/schemas/connect-problem.v1.schema.json +5665 -0
- package/node_modules/@mdbase-dev/connect-protocol/schemas/connect-problems.v1.catalog.json +373 -0
- package/node_modules/@mdbase-dev/connect-protocol/schemas/connect-protocol.v1.schema.json +901 -0
- package/node_modules/@mdbase-dev/connect-protocol/schemas/data-contract.schema.json +163 -0
- package/node_modules/@mdbase-dev/connect-protocol/schemas/encrypted-relay.v1.schema.json +63 -0
- package/node_modules/@mdbase-dev/connect-protocol/schemas/encrypted-relay.v2.schema.json +63 -0
- package/node_modules/@mdbase-dev/connect-protocol/schemas/encrypted-relay.v3.schema.json +64 -0
- package/node_modules/@mdbase-dev/connect-protocol/schemas/files.v1.schema.json +551 -0
- package/node_modules/@mdbase-dev/connect-protocol/schemas/interop/v0.1/action-cancellation.schema.json +6 -0
- package/node_modules/@mdbase-dev/connect-protocol/schemas/interop/v0.1/action-invocation.schema.json +6 -0
- package/node_modules/@mdbase-dev/connect-protocol/schemas/interop/v0.1/action-outcome.schema.json +6 -0
- package/node_modules/@mdbase-dev/connect-protocol/schemas/interop/v0.1/action-provider-declaration.schema.json +6 -0
- package/node_modules/@mdbase-dev/connect-protocol/schemas/interop/v0.1/action-request.schema.json +6 -0
- package/node_modules/@mdbase-dev/connect-protocol/schemas/interop/v0.1/conformance-claim.schema.json +6 -0
- package/node_modules/@mdbase-dev/connect-protocol/schemas/interop/v0.1/event-source-declaration.schema.json +6 -0
- package/node_modules/@mdbase-dev/connect-protocol/schemas/interop/v0.1/event.schema.json +6 -0
- package/node_modules/@mdbase-dev/connect-protocol/schemas/interop/v0.1/profile.schema.json +456 -0
- package/node_modules/@mdbase-dev/connect-protocol/schemas/mdbase-app.legacy-v1.schema.json +430 -0
- package/node_modules/@mdbase-dev/connect-protocol/schemas/mdbase-app.schema.json +437 -0
- package/node_modules/@mdbase-dev/connect-protocol/schemas/mdbase-query.v0.3.schema.json +176 -0
- package/node_modules/@mdbase-dev/connect-protocol/schemas/next-trust.v1.schema.json +54 -0
- package/node_modules/@mdbase-dev/connect-protocol/schemas/notification-webhook.v1.schema.json +56 -0
- package/node_modules/@mdbase-dev/connect-protocol/schemas/operation-catalog.v1.json +43 -0
- package/node_modules/@mdbase-dev/connect-protocol/schemas/operation-mutation-classification.v1.json +554 -0
- package/node_modules/@mdbase-dev/connect-protocol/schemas/sync.v1.schema.json +483 -0
- package/node_modules/@noble/hashes/LICENSE +21 -0
- package/node_modules/@noble/hashes/README.md +478 -0
- package/node_modules/@noble/hashes/_blake.d.ts +20 -0
- package/node_modules/@noble/hashes/_blake.js +59 -0
- package/node_modules/@noble/hashes/_md.d.ts +95 -0
- package/node_modules/@noble/hashes/_md.js +209 -0
- package/node_modules/@noble/hashes/_u64.d.ts +36 -0
- package/node_modules/@noble/hashes/_u64.js +77 -0
- package/node_modules/@noble/hashes/argon2.d.ts +148 -0
- package/node_modules/@noble/hashes/argon2.js +577 -0
- package/node_modules/@noble/hashes/blake1.d.ts +162 -0
- package/node_modules/@noble/hashes/blake1.js +630 -0
- package/node_modules/@noble/hashes/blake2.d.ts +203 -0
- package/node_modules/@noble/hashes/blake2.js +573 -0
- package/node_modules/@noble/hashes/blake3.d.ts +68 -0
- package/node_modules/@noble/hashes/blake3.js +310 -0
- package/node_modules/@noble/hashes/eskdf.d.ts +91 -0
- package/node_modules/@noble/hashes/eskdf.js +225 -0
- package/node_modules/@noble/hashes/hkdf.d.ts +70 -0
- package/node_modules/@noble/hashes/hkdf.js +152 -0
- package/node_modules/@noble/hashes/hmac.d.ts +50 -0
- package/node_modules/@noble/hashes/hmac.js +93 -0
- package/node_modules/@noble/hashes/index.d.ts +1 -0
- package/node_modules/@noble/hashes/index.js +34 -0
- package/node_modules/@noble/hashes/legacy.d.ts +107 -0
- package/node_modules/@noble/hashes/legacy.js +348 -0
- package/node_modules/@noble/hashes/package.json +91 -0
- package/node_modules/@noble/hashes/pbkdf2.d.ts +66 -0
- package/node_modules/@noble/hashes/pbkdf2.js +176 -0
- package/node_modules/@noble/hashes/scrypt.d.ts +98 -0
- package/node_modules/@noble/hashes/scrypt.js +304 -0
- package/node_modules/@noble/hashes/sha2.d.ts +176 -0
- package/node_modules/@noble/hashes/sha2.js +446 -0
- package/node_modules/@noble/hashes/sha3-addons.d.ts +533 -0
- package/node_modules/@noble/hashes/sha3-addons.js +973 -0
- package/node_modules/@noble/hashes/sha3.d.ts +208 -0
- package/node_modules/@noble/hashes/sha3.js +475 -0
- package/node_modules/@noble/hashes/src/_blake.ts +67 -0
- package/node_modules/@noble/hashes/src/_md.ts +227 -0
- package/node_modules/@noble/hashes/src/_u64.ts +111 -0
- package/node_modules/@noble/hashes/src/argon2.ts +693 -0
- package/node_modules/@noble/hashes/src/blake1.ts +677 -0
- package/node_modules/@noble/hashes/src/blake2.ts +648 -0
- package/node_modules/@noble/hashes/src/blake3.ts +344 -0
- package/node_modules/@noble/hashes/src/eskdf.ts +265 -0
- package/node_modules/@noble/hashes/src/hkdf.ts +161 -0
- package/node_modules/@noble/hashes/src/hmac.ts +130 -0
- package/node_modules/@noble/hashes/src/index.ts +33 -0
- package/node_modules/@noble/hashes/src/legacy.ts +361 -0
- package/node_modules/@noble/hashes/src/pbkdf2.ts +219 -0
- package/node_modules/@noble/hashes/src/scrypt.ts +375 -0
- package/node_modules/@noble/hashes/src/sha2.ts +486 -0
- package/node_modules/@noble/hashes/src/sha3-addons.ts +1157 -0
- package/node_modules/@noble/hashes/src/sha3.ts +525 -0
- package/node_modules/@noble/hashes/src/utils.ts +978 -0
- package/node_modules/@noble/hashes/src/webcrypto.ts +283 -0
- package/node_modules/@noble/hashes/utils.d.ts +560 -0
- package/node_modules/@noble/hashes/utils.js +687 -0
- package/node_modules/@noble/hashes/webcrypto.d.ts +121 -0
- package/node_modules/@noble/hashes/webcrypto.js +228 -0
- package/node_modules/yaml/LICENSE +13 -0
- package/node_modules/yaml/README.md +172 -0
- package/node_modules/yaml/bin.mjs +11 -0
- package/node_modules/yaml/browser/dist/compose/compose-collection.js +88 -0
- package/node_modules/yaml/browser/dist/compose/compose-doc.js +43 -0
- package/node_modules/yaml/browser/dist/compose/compose-node.js +109 -0
- package/node_modules/yaml/browser/dist/compose/compose-scalar.js +86 -0
- package/node_modules/yaml/browser/dist/compose/composer.js +219 -0
- package/node_modules/yaml/browser/dist/compose/resolve-block-map.js +115 -0
- package/node_modules/yaml/browser/dist/compose/resolve-block-scalar.js +198 -0
- package/node_modules/yaml/browser/dist/compose/resolve-block-seq.js +49 -0
- package/node_modules/yaml/browser/dist/compose/resolve-end.js +37 -0
- package/node_modules/yaml/browser/dist/compose/resolve-flow-collection.js +207 -0
- package/node_modules/yaml/browser/dist/compose/resolve-flow-scalar.js +226 -0
- package/node_modules/yaml/browser/dist/compose/resolve-props.js +146 -0
- package/node_modules/yaml/browser/dist/compose/util-contains-newline.js +34 -0
- package/node_modules/yaml/browser/dist/compose/util-empty-scalar-position.js +26 -0
- package/node_modules/yaml/browser/dist/compose/util-flow-indent-check.js +15 -0
- package/node_modules/yaml/browser/dist/compose/util-map-includes.js +13 -0
- package/node_modules/yaml/browser/dist/doc/Document.js +335 -0
- package/node_modules/yaml/browser/dist/doc/anchors.js +71 -0
- package/node_modules/yaml/browser/dist/doc/applyReviver.js +55 -0
- package/node_modules/yaml/browser/dist/doc/createNode.js +88 -0
- package/node_modules/yaml/browser/dist/doc/directives.js +176 -0
- package/node_modules/yaml/browser/dist/errors.js +57 -0
- package/node_modules/yaml/browser/dist/index.js +17 -0
- package/node_modules/yaml/browser/dist/log.js +11 -0
- package/node_modules/yaml/browser/dist/nodes/Alias.js +118 -0
- package/node_modules/yaml/browser/dist/nodes/Collection.js +147 -0
- package/node_modules/yaml/browser/dist/nodes/Node.js +38 -0
- package/node_modules/yaml/browser/dist/nodes/Pair.js +36 -0
- package/node_modules/yaml/browser/dist/nodes/Scalar.js +24 -0
- package/node_modules/yaml/browser/dist/nodes/YAMLMap.js +144 -0
- package/node_modules/yaml/browser/dist/nodes/YAMLSeq.js +113 -0
- package/node_modules/yaml/browser/dist/nodes/addPairToJSMap.js +63 -0
- package/node_modules/yaml/browser/dist/nodes/identity.js +36 -0
- package/node_modules/yaml/browser/dist/nodes/toJS.js +37 -0
- package/node_modules/yaml/browser/dist/parse/cst-scalar.js +214 -0
- package/node_modules/yaml/browser/dist/parse/cst-stringify.js +61 -0
- package/node_modules/yaml/browser/dist/parse/cst-visit.js +97 -0
- package/node_modules/yaml/browser/dist/parse/cst.js +98 -0
- package/node_modules/yaml/browser/dist/parse/lexer.js +721 -0
- package/node_modules/yaml/browser/dist/parse/line-counter.js +39 -0
- package/node_modules/yaml/browser/dist/parse/parser.js +975 -0
- package/node_modules/yaml/browser/dist/public-api.js +102 -0
- package/node_modules/yaml/browser/dist/schema/Schema.js +37 -0
- package/node_modules/yaml/browser/dist/schema/common/map.js +17 -0
- package/node_modules/yaml/browser/dist/schema/common/null.js +15 -0
- package/node_modules/yaml/browser/dist/schema/common/seq.js +17 -0
- package/node_modules/yaml/browser/dist/schema/common/string.js +14 -0
- package/node_modules/yaml/browser/dist/schema/core/bool.js +19 -0
- package/node_modules/yaml/browser/dist/schema/core/float.js +43 -0
- package/node_modules/yaml/browser/dist/schema/core/int.js +38 -0
- package/node_modules/yaml/browser/dist/schema/core/schema.js +23 -0
- package/node_modules/yaml/browser/dist/schema/json/schema.js +62 -0
- package/node_modules/yaml/browser/dist/schema/tags.js +96 -0
- package/node_modules/yaml/browser/dist/schema/yaml-1.1/binary.js +58 -0
- package/node_modules/yaml/browser/dist/schema/yaml-1.1/bool.js +26 -0
- package/node_modules/yaml/browser/dist/schema/yaml-1.1/float.js +46 -0
- package/node_modules/yaml/browser/dist/schema/yaml-1.1/int.js +71 -0
- package/node_modules/yaml/browser/dist/schema/yaml-1.1/merge.js +67 -0
- package/node_modules/yaml/browser/dist/schema/yaml-1.1/omap.js +74 -0
- package/node_modules/yaml/browser/dist/schema/yaml-1.1/pairs.js +78 -0
- package/node_modules/yaml/browser/dist/schema/yaml-1.1/schema.js +39 -0
- package/node_modules/yaml/browser/dist/schema/yaml-1.1/set.js +93 -0
- package/node_modules/yaml/browser/dist/schema/yaml-1.1/timestamp.js +101 -0
- package/node_modules/yaml/browser/dist/stringify/foldFlowLines.js +146 -0
- package/node_modules/yaml/browser/dist/stringify/stringify.js +129 -0
- package/node_modules/yaml/browser/dist/stringify/stringifyCollection.js +153 -0
- package/node_modules/yaml/browser/dist/stringify/stringifyComment.js +20 -0
- package/node_modules/yaml/browser/dist/stringify/stringifyDocument.js +85 -0
- package/node_modules/yaml/browser/dist/stringify/stringifyNumber.js +25 -0
- package/node_modules/yaml/browser/dist/stringify/stringifyPair.js +150 -0
- package/node_modules/yaml/browser/dist/stringify/stringifyString.js +336 -0
- package/node_modules/yaml/browser/dist/util.js +11 -0
- package/node_modules/yaml/browser/dist/visit.js +233 -0
- package/node_modules/yaml/browser/index.js +5 -0
- package/node_modules/yaml/browser/package.json +3 -0
- package/node_modules/yaml/dist/cli.d.ts +8 -0
- package/node_modules/yaml/dist/cli.mjs +201 -0
- package/node_modules/yaml/dist/compose/compose-collection.d.ts +11 -0
- package/node_modules/yaml/dist/compose/compose-collection.js +90 -0
- package/node_modules/yaml/dist/compose/compose-doc.d.ts +7 -0
- package/node_modules/yaml/dist/compose/compose-doc.js +45 -0
- package/node_modules/yaml/dist/compose/compose-node.d.ts +29 -0
- package/node_modules/yaml/dist/compose/compose-node.js +112 -0
- package/node_modules/yaml/dist/compose/compose-scalar.d.ts +5 -0
- package/node_modules/yaml/dist/compose/compose-scalar.js +88 -0
- package/node_modules/yaml/dist/compose/composer.d.ts +63 -0
- package/node_modules/yaml/dist/compose/composer.js +224 -0
- package/node_modules/yaml/dist/compose/resolve-block-map.d.ts +6 -0
- package/node_modules/yaml/dist/compose/resolve-block-map.js +117 -0
- package/node_modules/yaml/dist/compose/resolve-block-scalar.d.ts +11 -0
- package/node_modules/yaml/dist/compose/resolve-block-scalar.js +200 -0
- package/node_modules/yaml/dist/compose/resolve-block-seq.d.ts +6 -0
- package/node_modules/yaml/dist/compose/resolve-block-seq.js +51 -0
- package/node_modules/yaml/dist/compose/resolve-end.d.ts +6 -0
- package/node_modules/yaml/dist/compose/resolve-end.js +39 -0
- package/node_modules/yaml/dist/compose/resolve-flow-collection.d.ts +7 -0
- package/node_modules/yaml/dist/compose/resolve-flow-collection.js +209 -0
- package/node_modules/yaml/dist/compose/resolve-flow-scalar.d.ts +10 -0
- package/node_modules/yaml/dist/compose/resolve-flow-scalar.js +228 -0
- package/node_modules/yaml/dist/compose/resolve-props.d.ts +23 -0
- package/node_modules/yaml/dist/compose/resolve-props.js +148 -0
- package/node_modules/yaml/dist/compose/util-contains-newline.d.ts +2 -0
- package/node_modules/yaml/dist/compose/util-contains-newline.js +36 -0
- package/node_modules/yaml/dist/compose/util-empty-scalar-position.d.ts +2 -0
- package/node_modules/yaml/dist/compose/util-empty-scalar-position.js +28 -0
- package/node_modules/yaml/dist/compose/util-flow-indent-check.d.ts +3 -0
- package/node_modules/yaml/dist/compose/util-flow-indent-check.js +17 -0
- package/node_modules/yaml/dist/compose/util-map-includes.d.ts +4 -0
- package/node_modules/yaml/dist/compose/util-map-includes.js +15 -0
- package/node_modules/yaml/dist/doc/Document.d.ts +141 -0
- package/node_modules/yaml/dist/doc/Document.js +337 -0
- package/node_modules/yaml/dist/doc/anchors.d.ts +24 -0
- package/node_modules/yaml/dist/doc/anchors.js +76 -0
- package/node_modules/yaml/dist/doc/applyReviver.d.ts +9 -0
- package/node_modules/yaml/dist/doc/applyReviver.js +57 -0
- package/node_modules/yaml/dist/doc/createNode.d.ts +17 -0
- package/node_modules/yaml/dist/doc/createNode.js +90 -0
- package/node_modules/yaml/dist/doc/directives.d.ts +49 -0
- package/node_modules/yaml/dist/doc/directives.js +178 -0
- package/node_modules/yaml/dist/errors.d.ts +21 -0
- package/node_modules/yaml/dist/errors.js +62 -0
- package/node_modules/yaml/dist/index.d.ts +25 -0
- package/node_modules/yaml/dist/index.js +50 -0
- package/node_modules/yaml/dist/log.d.ts +3 -0
- package/node_modules/yaml/dist/log.js +19 -0
- package/node_modules/yaml/dist/nodes/Alias.d.ts +29 -0
- package/node_modules/yaml/dist/nodes/Alias.js +120 -0
- package/node_modules/yaml/dist/nodes/Collection.d.ts +73 -0
- package/node_modules/yaml/dist/nodes/Collection.js +151 -0
- package/node_modules/yaml/dist/nodes/Node.d.ts +53 -0
- package/node_modules/yaml/dist/nodes/Node.js +40 -0
- package/node_modules/yaml/dist/nodes/Pair.d.ts +22 -0
- package/node_modules/yaml/dist/nodes/Pair.js +39 -0
- package/node_modules/yaml/dist/nodes/Scalar.d.ts +47 -0
- package/node_modules/yaml/dist/nodes/Scalar.js +27 -0
- package/node_modules/yaml/dist/nodes/YAMLMap.d.ts +53 -0
- package/node_modules/yaml/dist/nodes/YAMLMap.js +147 -0
- package/node_modules/yaml/dist/nodes/YAMLSeq.d.ts +60 -0
- package/node_modules/yaml/dist/nodes/YAMLSeq.js +115 -0
- package/node_modules/yaml/dist/nodes/addPairToJSMap.d.ts +4 -0
- package/node_modules/yaml/dist/nodes/addPairToJSMap.js +65 -0
- package/node_modules/yaml/dist/nodes/identity.d.ts +23 -0
- package/node_modules/yaml/dist/nodes/identity.js +53 -0
- package/node_modules/yaml/dist/nodes/toJS.d.ts +29 -0
- package/node_modules/yaml/dist/nodes/toJS.js +39 -0
- package/node_modules/yaml/dist/options.d.ts +350 -0
- package/node_modules/yaml/dist/parse/cst-scalar.d.ts +64 -0
- package/node_modules/yaml/dist/parse/cst-scalar.js +218 -0
- package/node_modules/yaml/dist/parse/cst-stringify.d.ts +8 -0
- package/node_modules/yaml/dist/parse/cst-stringify.js +63 -0
- package/node_modules/yaml/dist/parse/cst-visit.d.ts +39 -0
- package/node_modules/yaml/dist/parse/cst-visit.js +99 -0
- package/node_modules/yaml/dist/parse/cst.d.ts +109 -0
- package/node_modules/yaml/dist/parse/cst.js +112 -0
- package/node_modules/yaml/dist/parse/lexer.d.ts +87 -0
- package/node_modules/yaml/dist/parse/lexer.js +723 -0
- package/node_modules/yaml/dist/parse/line-counter.d.ts +22 -0
- package/node_modules/yaml/dist/parse/line-counter.js +41 -0
- package/node_modules/yaml/dist/parse/parser.d.ts +84 -0
- package/node_modules/yaml/dist/parse/parser.js +980 -0
- package/node_modules/yaml/dist/public-api.d.ts +44 -0
- package/node_modules/yaml/dist/public-api.js +107 -0
- package/node_modules/yaml/dist/schema/Schema.d.ts +17 -0
- package/node_modules/yaml/dist/schema/Schema.js +39 -0
- package/node_modules/yaml/dist/schema/common/map.d.ts +2 -0
- package/node_modules/yaml/dist/schema/common/map.js +19 -0
- package/node_modules/yaml/dist/schema/common/null.d.ts +4 -0
- package/node_modules/yaml/dist/schema/common/null.js +17 -0
- package/node_modules/yaml/dist/schema/common/seq.d.ts +2 -0
- package/node_modules/yaml/dist/schema/common/seq.js +19 -0
- package/node_modules/yaml/dist/schema/common/string.d.ts +2 -0
- package/node_modules/yaml/dist/schema/common/string.js +16 -0
- package/node_modules/yaml/dist/schema/core/bool.d.ts +4 -0
- package/node_modules/yaml/dist/schema/core/bool.js +21 -0
- package/node_modules/yaml/dist/schema/core/float.d.ts +4 -0
- package/node_modules/yaml/dist/schema/core/float.js +47 -0
- package/node_modules/yaml/dist/schema/core/int.d.ts +4 -0
- package/node_modules/yaml/dist/schema/core/int.js +42 -0
- package/node_modules/yaml/dist/schema/core/schema.d.ts +1 -0
- package/node_modules/yaml/dist/schema/core/schema.js +25 -0
- package/node_modules/yaml/dist/schema/json/schema.d.ts +2 -0
- package/node_modules/yaml/dist/schema/json/schema.js +64 -0
- package/node_modules/yaml/dist/schema/json-schema.d.ts +69 -0
- package/node_modules/yaml/dist/schema/tags.d.ts +48 -0
- package/node_modules/yaml/dist/schema/tags.js +99 -0
- package/node_modules/yaml/dist/schema/types.d.ts +92 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/binary.d.ts +2 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/binary.js +70 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/bool.d.ts +7 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/bool.js +29 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/float.d.ts +4 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/float.js +50 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/int.d.ts +5 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/int.js +76 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/merge.d.ts +9 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/merge.js +71 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/omap.d.ts +22 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/omap.js +77 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/pairs.d.ts +10 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/pairs.js +82 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/schema.d.ts +1 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/schema.js +41 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/set.d.ts +28 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/set.js +96 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/timestamp.d.ts +6 -0
- package/node_modules/yaml/dist/schema/yaml-1.1/timestamp.js +105 -0
- package/node_modules/yaml/dist/stringify/foldFlowLines.d.ts +34 -0
- package/node_modules/yaml/dist/stringify/foldFlowLines.js +151 -0
- package/node_modules/yaml/dist/stringify/stringify.d.ts +21 -0
- package/node_modules/yaml/dist/stringify/stringify.js +132 -0
- package/node_modules/yaml/dist/stringify/stringifyCollection.d.ts +17 -0
- package/node_modules/yaml/dist/stringify/stringifyCollection.js +155 -0
- package/node_modules/yaml/dist/stringify/stringifyComment.d.ts +10 -0
- package/node_modules/yaml/dist/stringify/stringifyComment.js +24 -0
- package/node_modules/yaml/dist/stringify/stringifyDocument.d.ts +4 -0
- package/node_modules/yaml/dist/stringify/stringifyDocument.js +87 -0
- package/node_modules/yaml/dist/stringify/stringifyNumber.d.ts +2 -0
- package/node_modules/yaml/dist/stringify/stringifyNumber.js +27 -0
- package/node_modules/yaml/dist/stringify/stringifyPair.d.ts +3 -0
- package/node_modules/yaml/dist/stringify/stringifyPair.js +152 -0
- package/node_modules/yaml/dist/stringify/stringifyString.d.ts +9 -0
- package/node_modules/yaml/dist/stringify/stringifyString.js +338 -0
- package/node_modules/yaml/dist/test-events.d.ts +4 -0
- package/node_modules/yaml/dist/test-events.js +134 -0
- package/node_modules/yaml/dist/util.d.ts +16 -0
- package/node_modules/yaml/dist/util.js +28 -0
- package/node_modules/yaml/dist/visit.d.ts +102 -0
- package/node_modules/yaml/dist/visit.js +236 -0
- package/node_modules/yaml/package.json +97 -0
- package/node_modules/yaml/util.js +2 -0
- package/package.json +108 -4
- package/vendor/mdbase-connect-sdk-e6e66bcd172f.json +13 -0
- package/vendor/mdbase-dev-connect-protocol-0.1.0-beta.145-e6e66bcd172f.tgz +0 -0
|
@@ -0,0 +1,1231 @@
|
|
|
1
|
+
/** First-party protected installation sign-in. Internal until SAME original
|
|
2
|
+
* native-owner/cloud-host composition is qualified. No app-grant authority,
|
|
3
|
+
* ambient cookies, automatic polling/renewal or new-actor retry. */
|
|
4
|
+
import { boundNativeCompletion } from "./native-sign-in.js";
|
|
5
|
+
import { parseCollectionAvailability } from "../collection-availability.js";
|
|
6
|
+
import { uuidToBytes } from "../codec.js";
|
|
7
|
+
import { LOCAL_APPLICATION_BUILD, localApplicationEnvironment, localApplicationHttpOrigin } from "../application/local-build.js";
|
|
8
|
+
import { collectionDisplayName } from "./collection-display-name.js";
|
|
9
|
+
import { isAppEnvironmentSelection } from "./app-environment.js";
|
|
10
|
+
import { AppInstallationStore, AppInstallationStorageError } from "./installation-store.js";
|
|
11
|
+
import { isAppInstallationId } from "./owner.js";
|
|
12
|
+
import { appServerOutcome, appServerProblem } from "./cp-problem.js";
|
|
13
|
+
export class AppInstallationSignInError extends Error {
|
|
14
|
+
reason;
|
|
15
|
+
server;
|
|
16
|
+
constructor(reason, server) {
|
|
17
|
+
super(`app installation sign-in: ${reason}`);
|
|
18
|
+
this.reason = reason;
|
|
19
|
+
this.server = server;
|
|
20
|
+
this.name = "AppInstallationSignInError";
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const fail = (reason) => new AppInstallationSignInError(reason);
|
|
24
|
+
// Preserve definite HTTP status provenance even when its body cannot be parsed.
|
|
25
|
+
const nonOkResponses = new WeakSet();
|
|
26
|
+
const hex = (b) => Array.from(b, v => v.toString(16).padStart(2, "0")).join("");
|
|
27
|
+
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
28
|
+
function id(v) { if (typeof v !== "string" || !UUID.test(v) || uuidToBytes(v).every(b => b === 0))
|
|
29
|
+
throw fail("response"); return v; }
|
|
30
|
+
function text(v, pattern) { if (typeof v !== "string" || !pattern.test(v))
|
|
31
|
+
throw fail("response"); return v; }
|
|
32
|
+
function object(v, keys) {
|
|
33
|
+
if (!v || typeof v !== "object" || Array.isArray(v) || Object.keys(v).sort().join() !== keys.split(",").sort().join())
|
|
34
|
+
throw fail("response");
|
|
35
|
+
return v;
|
|
36
|
+
}
|
|
37
|
+
function accountEmail(value) {
|
|
38
|
+
if (typeof value !== "string" || value.length > 320 || !/^[^\s@\u0000-\u001f\u007f]+@[^\s@\u0000-\u001f\u007f]+$/.test(value))
|
|
39
|
+
throw fail("response");
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
42
|
+
function portalKeys(v, stored = false) {
|
|
43
|
+
const [email, marker, provider, login] = stored ? ["accountEmail", "portalConfirmed", "accountProvider", "accountLogin"] : ["account_email", "account_selection_confirmed", "account_provider", "account_login"];
|
|
44
|
+
return [email, marker, provider, login].some(key => Object.hasOwn(v, key))
|
|
45
|
+
? `,${email},${marker}${Object.hasOwn(v, provider) || Object.hasOwn(v, login) ? `,${provider},${login}` : ""}` : "";
|
|
46
|
+
}
|
|
47
|
+
function portalMetadata(v, stored = false) {
|
|
48
|
+
const keys = portalKeys(v, stored);
|
|
49
|
+
if (!keys)
|
|
50
|
+
return {};
|
|
51
|
+
const email = stored ? v.accountEmail : v.account_email;
|
|
52
|
+
const marker = stored ? v.portalConfirmed : v.account_selection_confirmed;
|
|
53
|
+
const provider = stored ? v.accountProvider : v.account_provider;
|
|
54
|
+
const login = stored ? v.accountLogin : v.account_login;
|
|
55
|
+
if (marker !== true)
|
|
56
|
+
throw fail("response");
|
|
57
|
+
if (keys.includes(stored ? "accountProvider" : "account_provider")) {
|
|
58
|
+
if (email !== null || provider !== "github" || typeof login !== "string" || !login.length || new TextEncoder().encode(login).byteLength > 100 || /[\s\u0000-\u001f\u007f]/.test(login))
|
|
59
|
+
throw fail("response");
|
|
60
|
+
return { accountEmail: null, portalConfirmed: true, accountProvider: "github", accountLogin: login };
|
|
61
|
+
}
|
|
62
|
+
return { accountEmail: accountEmail(email), portalConfirmed: true };
|
|
63
|
+
}
|
|
64
|
+
function assertOriginalPortal(before, after) {
|
|
65
|
+
if (before.portalConfirmed && (after.portalConfirmed !== true || before.accountEmail !== after.accountEmail || before.accountProvider !== after.accountProvider || before.accountLogin !== after.accountLogin))
|
|
66
|
+
throw fail("binding");
|
|
67
|
+
}
|
|
68
|
+
function timerKeys(value) {
|
|
69
|
+
return Object.hasOwn(value, "timer_consent") || Object.hasOwn(value, "timer_grants") ? ",timer_consent,timer_grants" : "";
|
|
70
|
+
}
|
|
71
|
+
function timerConsent(value, requestId, approved, confirmed, selected) {
|
|
72
|
+
if (!timerKeys(value))
|
|
73
|
+
return undefined;
|
|
74
|
+
if (![true, false, null].includes(value.timer_consent) || !Array.isArray(value.timer_grants) || value.timer_grants.length > 1000)
|
|
75
|
+
throw fail("response");
|
|
76
|
+
const grants = value.timer_grants.map(item => {
|
|
77
|
+
const row = object(item, "grant_id,collection_id,declaration_digest"), collectionId = id(row.collection_id);
|
|
78
|
+
if (!approved.includes(collectionId))
|
|
79
|
+
throw fail("response");
|
|
80
|
+
return Object.freeze({ grantId: id(row.grant_id), collectionId, declarationDigest: text(row.declaration_digest, /^[0-9a-f]{64}$/) });
|
|
81
|
+
});
|
|
82
|
+
if (new Set(grants.map(grant => grant.grantId)).size !== grants.length || new Set(grants.map(grant => grant.collectionId)).size !== grants.length
|
|
83
|
+
|| (value.timer_consent === true ? !confirmed || !selected || !grants.some(grant => grant.collectionId === selected) : grants.length !== 0)
|
|
84
|
+
|| new Set(grants.map(grant => grant.declarationDigest)).size > 1)
|
|
85
|
+
throw fail("response");
|
|
86
|
+
// Omission is neither approval nor withdrawal: retain ORIGINAL consent,
|
|
87
|
+
// never inherit it into the newly approved collection scope.
|
|
88
|
+
return value.timer_consent === null ? undefined : Object.freeze({ requestId, approved: value.timer_consent === true, grants: Object.freeze(grants.filter(grant => grant.collectionId === selected)) });
|
|
89
|
+
}
|
|
90
|
+
function timerChannel(value) {
|
|
91
|
+
const row = object(value, "grantId,kind,targetDigest,channelId,pending");
|
|
92
|
+
if (!["web_push", "fcm"].includes(row.kind) || ![null, "register", "delete"].includes(row.pending)
|
|
93
|
+
|| (row.channelId === null && row.pending !== "register"))
|
|
94
|
+
throw fail("response");
|
|
95
|
+
return Object.freeze({ grantId: id(row.grantId), kind: row.kind, targetDigest: text(row.targetDigest, /^[0-9a-f]{64}$/),
|
|
96
|
+
channelId: row.channelId === null ? null : id(row.channelId), pending: row.pending });
|
|
97
|
+
}
|
|
98
|
+
/** Strictly parsed CP display/scope metadata, never native readiness. */
|
|
99
|
+
function collectionListing(value) {
|
|
100
|
+
if (!Array.isArray(value) || value.length > 1000)
|
|
101
|
+
throw fail("response");
|
|
102
|
+
const seen = new Set();
|
|
103
|
+
return Object.freeze(value.map(value => {
|
|
104
|
+
const has = (key) => value && typeof value === "object" && key in value ? `,${key}` : "";
|
|
105
|
+
const r = object(value, `collection_id,display_name,role${has("availability")}${has("file_actions")}`), collectionId = id(r.collection_id);
|
|
106
|
+
if (seen.has(collectionId) || typeof r.display_name !== "string" || !r.display_name.length || r.display_name.length > 1024 || (r.role !== "owner" && r.role !== "editor" && r.role !== "viewer"))
|
|
107
|
+
throw fail("response");
|
|
108
|
+
const availability = parseCollectionAvailability(r.availability);
|
|
109
|
+
const allowed = "file_actions" in r ? fileActions(r.file_actions) : null;
|
|
110
|
+
seen.add(collectionId);
|
|
111
|
+
return Object.freeze({ collectionId, displayName: r.display_name, role: r.role, ...(availability ? { availability } : {}), ...(allowed ? { fileActions: allowed } : {}) });
|
|
112
|
+
}));
|
|
113
|
+
}
|
|
114
|
+
const FILE_ACTIONS = ["list", "read", "add", "replace", "move", "delete"];
|
|
115
|
+
function fileActions(v, allowed = FILE_ACTIONS, empty = true) {
|
|
116
|
+
if (!Array.isArray(v) || v.length > FILE_ACTIONS.length || (!empty && !v.length) || new Set(v).size !== v.length || v.some(a => !allowed.includes(a)))
|
|
117
|
+
throw fail("response");
|
|
118
|
+
return Object.freeze(FILE_ACTIONS.filter(a => v.includes(a)));
|
|
119
|
+
}
|
|
120
|
+
function collectionHint(options) {
|
|
121
|
+
const hint = options.collectionHint ?? null;
|
|
122
|
+
if (hint !== null && (typeof hint !== "string" || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(hint) || hint === "00000000-0000-0000-0000-000000000000"))
|
|
123
|
+
throw fail("binding");
|
|
124
|
+
return hint;
|
|
125
|
+
}
|
|
126
|
+
/** The exact returned URI: the plain pairing URI or, from a Connect with hint
|
|
127
|
+
* support, the same URI carrying exactly the requested hint. */
|
|
128
|
+
function verificationUri(value, base, hint) {
|
|
129
|
+
return value === base || (hint !== null && value === `${base}?collection_hint=${hint}`) ? value : null;
|
|
130
|
+
}
|
|
131
|
+
export class AppProtectedInstallationSignIn {
|
|
132
|
+
store;
|
|
133
|
+
state;
|
|
134
|
+
options;
|
|
135
|
+
closed = false;
|
|
136
|
+
busy = false;
|
|
137
|
+
nativeAcknowledged = false;
|
|
138
|
+
expiredRequestId = null;
|
|
139
|
+
/** Definite authenticated pre-proof refusal only, never an HTTP unknown. */
|
|
140
|
+
wrongAccountRequestId = null;
|
|
141
|
+
lifetime = new AbortController();
|
|
142
|
+
request;
|
|
143
|
+
parent;
|
|
144
|
+
onAbort = () => { void this.close(); };
|
|
145
|
+
constructor(store, state, options) {
|
|
146
|
+
this.store = store;
|
|
147
|
+
this.state = state;
|
|
148
|
+
this.options = options;
|
|
149
|
+
this.request = options.fetch ?? ((input, init) => globalThis.fetch(input, init));
|
|
150
|
+
this.parent = options.signal;
|
|
151
|
+
this.parent.addEventListener("abort", this.onAbort, { once: true });
|
|
152
|
+
this.check();
|
|
153
|
+
}
|
|
154
|
+
static async open(options) {
|
|
155
|
+
const p = Object.freeze({ ...options, ...(options.recoveryFor ? { recoveryFor: Object.freeze({ ...options.recoveryFor }) } : {}) });
|
|
156
|
+
let opened = null;
|
|
157
|
+
try {
|
|
158
|
+
if ((LOCAL_APPLICATION_BUILD ? !localApplicationEnvironment(p.environment) : !["lab", "staging", "production"].includes(p.environment)) || !isAppInstallationId(p.appId) ||
|
|
159
|
+
typeof p.appName !== "string" || !p.appName.length || p.appName.length > 100 || p.appName.trim() !== p.appName)
|
|
160
|
+
throw fail("binding");
|
|
161
|
+
// Capacitor ("mobile") keeps custody in the WebView's origin-bound
|
|
162
|
+
// IndexedDB, like a browser app; the CP binds the declared native origin.
|
|
163
|
+
if (p.installationKind !== undefined && p.installationKind !== "app-runtime" && p.installationKind !== "mobile")
|
|
164
|
+
throw fail("binding");
|
|
165
|
+
const selection = p.environmentSelection;
|
|
166
|
+
if (p.requestedCreateCollections !== undefined && typeof p.requestedCreateCollections !== "boolean")
|
|
167
|
+
throw fail("binding");
|
|
168
|
+
if (p.freshRequestedCreateCollections !== undefined && typeof p.freshRequestedCreateCollections !== "boolean")
|
|
169
|
+
throw fail("binding");
|
|
170
|
+
if (p.recoveryFor !== undefined) {
|
|
171
|
+
const binding = object(p.recoveryFor, "accountId,collectionId");
|
|
172
|
+
id(binding.accountId);
|
|
173
|
+
id(binding.collectionId);
|
|
174
|
+
if (!p.owner || p.requestedCreateCollections === true || p.freshRequestedCreateCollections === true)
|
|
175
|
+
throw fail("binding");
|
|
176
|
+
}
|
|
177
|
+
if (selection !== undefined) {
|
|
178
|
+
if (!isAppEnvironmentSelection(selection) || selection.environment !== p.environment ||
|
|
179
|
+
selection.appOrigin !== p.origin || selection.cpOrigin !== p.cpOrigin ||
|
|
180
|
+
(p.allowLoopbackHttp === true && !selection.allowLoopbackHttp) ||
|
|
181
|
+
(p.allowNativeLoopbackHttp === true && !selection.allowNativeLoopbackHttp))
|
|
182
|
+
throw fail("binding");
|
|
183
|
+
}
|
|
184
|
+
// The application supplies its exact origin; the origin-bound store and
|
|
185
|
+
// CP registry authorize it. No brand-specific client allowlist.
|
|
186
|
+
opened = await AppInstallationStore.open({ ...p, allowLoopbackHttp: selection?.allowLoopbackHttp ?? p.allowLoopbackHttp,
|
|
187
|
+
allowNativeLoopbackHttp: selection?.allowNativeLoopbackHttp ?? p.allowNativeLoopbackHttp }, () => {
|
|
188
|
+
const bytes = crypto.getRandomValues(new Uint8Array(32));
|
|
189
|
+
try {
|
|
190
|
+
const secret = `pair_${btoa(String.fromCharCode(...bytes)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "")}`;
|
|
191
|
+
return new TextEncoder().encode(JSON.stringify({ version: 3, renewal: null, requestedCreateCollections: p.requestedCreateCollections ?? p.freshRequestedCreateCollections ?? false, collectionIds: [], createCollections: false, consentRequest: null, requestId: crypto.randomUUID(), installationId: crypto.randomUUID(), deviceId: crypto.randomUUID(), secret, appId: p.appId, ...(p.owner === undefined ? {} : { owner: p.owner }), kind: p.installationKind ?? "app-runtime", origin: p.origin, cpOrigin: p.cpOrigin, environment: p.environment, selection: null, confirmed: false, nativeStarted: false, proof: null, token: null, ...(p.recoveryFor ? { recoveryFor: p.recoveryFor } : {}) }));
|
|
192
|
+
}
|
|
193
|
+
finally {
|
|
194
|
+
bytes.fill(0);
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
const state = this.decode(opened.plaintext, p);
|
|
198
|
+
return new AppProtectedInstallationSignIn(opened.store, state, p);
|
|
199
|
+
}
|
|
200
|
+
catch (e) {
|
|
201
|
+
await opened?.store.close();
|
|
202
|
+
if (e instanceof AppInstallationSignInError)
|
|
203
|
+
throw e;
|
|
204
|
+
if (e instanceof AppInstallationStorageError && e.reason === "busy")
|
|
205
|
+
throw fail("open_in_another_tab");
|
|
206
|
+
throw fail("recovery_required");
|
|
207
|
+
}
|
|
208
|
+
finally {
|
|
209
|
+
opened?.plaintext.fill(0);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
static decode(bytes, p) {
|
|
213
|
+
const parsed = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
214
|
+
const base = "version,requestId,installationId,deviceId,secret,appId,kind,origin,cpOrigin,environment,selection,confirmed,nativeStarted,proof,token";
|
|
215
|
+
const legacy = parsed?.version === 1;
|
|
216
|
+
const fields = `${base},requestedCreateCollections,collectionIds,createCollections,consentRequest`;
|
|
217
|
+
const r = legacy ? { ...object(parsed, base), version: 3, renewal: null, requestedCreateCollections: false, collectionIds: [], createCollections: false, consentRequest: null }
|
|
218
|
+
: parsed?.version === 2 ? { ...object(parsed, fields), version: 3, renewal: null }
|
|
219
|
+
: object(parsed, `${fields},renewal${Object.hasOwn(parsed, "collectionSelection") ? ",collectionSelection" : ""}${Object.hasOwn(parsed, "timerConsent") ? ",timerConsent" : ""}${Object.hasOwn(parsed, "timerChannel") ? ",timerChannel" : ""}${Object.hasOwn(parsed, "owner") ? ",owner" : ""}${Object.hasOwn(parsed, "collectionListing") ? ",collectionListing" : ""}${Object.hasOwn(parsed, "collectionRecoveries") ? ",collectionRecoveries" : ""}${Object.hasOwn(parsed, "recoveryFor") ? ",recoveryFor" : ""}${Object.hasOwn(parsed, "nativeAuthorization") ? ",nativeAuthorization" : ""}${Object.hasOwn(parsed, "nativeSelection") ? ",nativeSelection" : ""}${Object.hasOwn(parsed, "nativeGrants") ? ",nativeGrants" : ""}`);
|
|
220
|
+
if (r.version !== 3 || r.appId !== p.appId || r.owner !== p.owner || r.kind !== (p.installationKind ?? "app-runtime") || r.origin !== p.origin || r.cpOrigin !== p.cpOrigin || r.environment !== p.environment || typeof r.confirmed !== "boolean" || typeof r.nativeStarted !== "boolean")
|
|
221
|
+
throw fail("recovery_required");
|
|
222
|
+
const s = r;
|
|
223
|
+
if (typeof s.requestedCreateCollections !== "boolean" || typeof s.createCollections !== "boolean" ||
|
|
224
|
+
(p.requestedCreateCollections !== undefined && p.requestedCreateCollections !== s.requestedCreateCollections))
|
|
225
|
+
throw fail("binding");
|
|
226
|
+
s.collectionIds = this.collectionIds(s.collectionIds);
|
|
227
|
+
if (s.recoveryFor !== undefined) {
|
|
228
|
+
const binding = object(s.recoveryFor, "accountId,collectionId");
|
|
229
|
+
id(binding.accountId);
|
|
230
|
+
id(binding.collectionId);
|
|
231
|
+
}
|
|
232
|
+
if ((s.recoveryFor === undefined) !== (p.recoveryFor === undefined) || s.recoveryFor?.accountId !== p.recoveryFor?.accountId || s.recoveryFor?.collectionId !== p.recoveryFor?.collectionId || (s.recoveryFor && (s.requestedCreateCollections || s.createCollections ||
|
|
233
|
+
(s.selection && s.selection.accountId !== s.recoveryFor.accountId) || (s.token && (s.nativeSelection ? s.collectionIds.length !== 0 || s.nativeSelection.collectionId !== s.recoveryFor.collectionId : s.collectionIds.length !== 1 || s.collectionIds[0] !== s.recoveryFor.collectionId || s.collectionSelection?.selectedCollectionId !== s.recoveryFor.collectionId)))))
|
|
234
|
+
throw fail("recovery_required");
|
|
235
|
+
if (s.consentRequest !== null) {
|
|
236
|
+
const c = object(s.consentRequest, `requestId,secret,requestedCreateCollections,challenge,completed,addedCollectionIds,approvedCreateCollections${portalKeys(s.consentRequest, true)}`);
|
|
237
|
+
portalMetadata(c, true);
|
|
238
|
+
id(c.requestId);
|
|
239
|
+
text(c.secret, /^pair_[A-Za-z0-9_-]{43}$/);
|
|
240
|
+
if (c.requestId === s.requestId || c.secret === s.secret || typeof c.requestedCreateCollections !== "boolean" || typeof c.completed !== "boolean" || typeof c.approvedCreateCollections !== "boolean" || (c.approvedCreateCollections && !c.requestedCreateCollections))
|
|
241
|
+
throw fail("recovery_required");
|
|
242
|
+
if (c.challenge !== null)
|
|
243
|
+
text(c.challenge, /^[0-9a-f]{64}$/);
|
|
244
|
+
this.collectionIds(c.addedCollectionIds);
|
|
245
|
+
if (!s.token || !s.selection || (c.completed && c.challenge === null))
|
|
246
|
+
throw fail("recovery_required");
|
|
247
|
+
}
|
|
248
|
+
if ((s.createCollections && !s.token) || (s.collectionIds.length && !s.token))
|
|
249
|
+
throw fail("recovery_required");
|
|
250
|
+
if (s.collectionSelection !== undefined) {
|
|
251
|
+
const c = object(s.collectionSelection, "requestId,selectedCollectionId,createdCollectionIds");
|
|
252
|
+
id(c.requestId);
|
|
253
|
+
if (!s.token || !s.collectionIds.includes(id(c.selectedCollectionId)) || this.collectionIds(c.createdCollectionIds).some(v => !s.collectionIds.includes(v)))
|
|
254
|
+
throw fail("recovery_required");
|
|
255
|
+
}
|
|
256
|
+
id(s.requestId);
|
|
257
|
+
id(s.installationId);
|
|
258
|
+
id(s.deviceId);
|
|
259
|
+
text(s.secret, /^pair_[A-Za-z0-9_-]{43}$/);
|
|
260
|
+
if (s.renewal !== null) {
|
|
261
|
+
const r = object(s.renewal, "requestId,secret");
|
|
262
|
+
id(r.requestId);
|
|
263
|
+
text(r.secret, /^pair_[A-Za-z0-9_-]{43}$/);
|
|
264
|
+
if (r.requestId === s.requestId || r.secret === s.secret)
|
|
265
|
+
throw fail("recovery_required");
|
|
266
|
+
}
|
|
267
|
+
if (s.timerChannel !== undefined) {
|
|
268
|
+
if (!s.token || !s.selection)
|
|
269
|
+
throw fail("recovery_required");
|
|
270
|
+
try {
|
|
271
|
+
s.timerChannel = timerChannel(s.timerChannel);
|
|
272
|
+
}
|
|
273
|
+
catch {
|
|
274
|
+
throw fail("recovery_required");
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
if (s.timerConsent !== undefined) {
|
|
278
|
+
const receipt = object(s.timerConsent, "requestId,approved,grants");
|
|
279
|
+
id(receipt.requestId);
|
|
280
|
+
if (!s.token || !s.selection || typeof receipt.approved !== "boolean" || !Array.isArray(receipt.grants) || receipt.grants.length > 1)
|
|
281
|
+
throw fail("recovery_required");
|
|
282
|
+
const grants = receipt.grants.map(grant => {
|
|
283
|
+
const row = object(grant, "grantId,collectionId,declarationDigest");
|
|
284
|
+
return { grant_id: row.grantId, collection_id: row.collectionId, declaration_digest: row.declarationDigest };
|
|
285
|
+
});
|
|
286
|
+
// Original timer approval may precede later omitted reconsent attempts;
|
|
287
|
+
// UUID/scope/protected receipt remain original, never reconstructed.
|
|
288
|
+
const confirmed = s.selection.portalConfirmed === true || s.consentRequest?.portalConfirmed === true;
|
|
289
|
+
s.timerConsent = timerConsent({ timer_consent: receipt.approved, timer_grants: grants }, id(receipt.requestId), s.collectionIds, confirmed, grants[0]?.collection_id);
|
|
290
|
+
}
|
|
291
|
+
if (s.selection !== null) {
|
|
292
|
+
const v = object(s.selection, `accountId,connectorId,challenge,approvalMode${portalKeys(s.selection, true)}`);
|
|
293
|
+
id(v.accountId);
|
|
294
|
+
id(v.connectorId);
|
|
295
|
+
text(v.challenge, /^[0-9a-f]{64}$/);
|
|
296
|
+
if (v.approvalMode !== "password-ak1")
|
|
297
|
+
throw fail("response");
|
|
298
|
+
portalMetadata(v, true);
|
|
299
|
+
}
|
|
300
|
+
if (s.proof !== null)
|
|
301
|
+
this.proof(s.proof);
|
|
302
|
+
if (s.token !== null)
|
|
303
|
+
text(s.token, /^idev_[A-Za-z0-9_-]{43}$/);
|
|
304
|
+
if ((s.confirmed && !s.selection) || (s.nativeStarted && !s.confirmed) || (s.proof && !s.nativeStarted) || (s.token && !s.proof))
|
|
305
|
+
throw fail("recovery_required");
|
|
306
|
+
if (s.collectionListing !== undefined) {
|
|
307
|
+
if (!s.token || !s.confirmed || !s.selection || !s.proof || collectionListing(s.collectionListing).some(c => !s.collectionIds.includes(c.collectionId)))
|
|
308
|
+
throw fail("recovery_required");
|
|
309
|
+
}
|
|
310
|
+
if (s.collectionRecoveries !== undefined) {
|
|
311
|
+
if (!s.token || !s.confirmed || !s.selection || !s.proof || !s.collectionRecoveries || typeof s.collectionRecoveries !== "object" || Array.isArray(s.collectionRecoveries))
|
|
312
|
+
throw fail("recovery_required");
|
|
313
|
+
const entries = Object.entries(s.collectionRecoveries);
|
|
314
|
+
if (entries.length > 1000 || entries.some(([collection, replacement]) => !(s.collectionIds.includes(id(collection)) || s.nativeGrants?.some(c => c.collection_id === collection)) || (replacement !== null && !id(replacement))))
|
|
315
|
+
throw fail("recovery_required");
|
|
316
|
+
}
|
|
317
|
+
if (s.nativeAuthorization) {
|
|
318
|
+
const a = object(s.nativeAuthorization, "requestId,authorizationId,applicationId,manifestDigest");
|
|
319
|
+
id(a.requestId);
|
|
320
|
+
id(a.authorizationId);
|
|
321
|
+
if (a.applicationId !== s.appId || !s.proof || !s.confirmed)
|
|
322
|
+
throw fail("recovery_required");
|
|
323
|
+
text(a.manifestDigest, /^[0-9a-f]{64}$/);
|
|
324
|
+
}
|
|
325
|
+
if (s.nativeSelection) {
|
|
326
|
+
const n = object(s.nativeSelection, "requestId,authorizationRequestId,collectionId");
|
|
327
|
+
id(n.requestId);
|
|
328
|
+
id(n.authorizationRequestId);
|
|
329
|
+
id(n.collectionId);
|
|
330
|
+
if (!s.token || !s.nativeAuthorization || n.requestId !== s.nativeAuthorization.requestId || n.authorizationRequestId !== s.nativeAuthorization.authorizationId)
|
|
331
|
+
throw fail("recovery_required");
|
|
332
|
+
}
|
|
333
|
+
if (s.nativeGrants) {
|
|
334
|
+
if (!s.token || !s.selection || !Array.isArray(s.nativeGrants) || s.nativeGrants.length > 1000)
|
|
335
|
+
throw fail("recovery_required");
|
|
336
|
+
s.nativeGrants = s.nativeGrants.map(c => boundNativeCompletion(c, { requestId: s.requestId, authorizationRequestId: c.authorization_request_id, collectionId: c.collection_id }, s.selection.accountId, s.appId, s.origin, c.application_manifest_digest));
|
|
337
|
+
if (new Set(s.nativeGrants.map(c => c.collection_id)).size !== s.nativeGrants.length)
|
|
338
|
+
throw fail("recovery_required");
|
|
339
|
+
}
|
|
340
|
+
return s;
|
|
341
|
+
}
|
|
342
|
+
static collectionIds(value) {
|
|
343
|
+
if (!Array.isArray(value) || value.length > 1000)
|
|
344
|
+
throw fail("response");
|
|
345
|
+
const ids = value.map(id);
|
|
346
|
+
if (new Set(ids).size !== ids.length)
|
|
347
|
+
throw fail("response");
|
|
348
|
+
return ids;
|
|
349
|
+
}
|
|
350
|
+
static proof(value) {
|
|
351
|
+
const r = object(value, "sign_pk,kem_pk,noise_pk,sig");
|
|
352
|
+
return { sign_pk: text(r.sign_pk, /^[0-9a-f]{64}$/), kem_pk: text(r.kem_pk, /^[0-9a-f]{64}$/), noise_pk: text(r.noise_pk, /^[0-9a-f]{64}$/), sig: text(r.sig, /^[0-9a-f]{128}$/) };
|
|
353
|
+
}
|
|
354
|
+
isCurrent() { return !this.closed && !this.parent.aborted && !this.lifetime.signal.aborted && this.store.isCurrent(); }
|
|
355
|
+
check() { if (!this.isCurrent())
|
|
356
|
+
throw fail("fenced"); }
|
|
357
|
+
view() {
|
|
358
|
+
this.check();
|
|
359
|
+
const s = this.state, identity = s.consentRequest?.portalConfirmed ? s.consentRequest : s.selection;
|
|
360
|
+
return Object.freeze({ requestId: s.requestId, installationId: s.installationId, deviceId: s.deviceId, appId: s.appId, kind: s.kind, verificationUri: `${s.cpOrigin}/pair/${s.requestId}`, state: s.token ? "paired" : s.proof ? "awaiting_approval" : s.confirmed ? "account_confirmed" : s.selection ? "account_selected" : "pending", accountId: s.selection?.accountId ?? null, accountEmail: identity?.accountEmail ?? null, ...(identity?.accountProvider ? { accountProvider: identity.accountProvider, accountLogin: identity.accountLogin } : {}), collectionSelection: s.collectionSelection ? Object.freeze({ ...s.collectionSelection, createdCollectionIds: Object.freeze([...s.collectionSelection.createdCollectionIds]) }) : null, nativeSelection: s.nativeSelection && s.nativeGrants?.some(c => c.authorization_request_id === s.nativeSelection.authorizationRequestId && c.collection_id === s.nativeSelection.collectionId) ? Object.freeze({ ...s.nativeSelection }) : null, nativeGrants: Object.freeze([...(s.nativeGrants ?? [])]), ...(s.timerConsent ? { timerConsent: s.timerConsent } : {}), collectionIds: Object.freeze([...s.collectionIds]), createCollections: s.createCollections, requestedCreateCollections: s.requestedCreateCollections });
|
|
361
|
+
}
|
|
362
|
+
/** Persist before exposing changed selection/proof/credential or native ACK. */
|
|
363
|
+
async save(next) {
|
|
364
|
+
this.check();
|
|
365
|
+
const bytes = new TextEncoder().encode(JSON.stringify(next));
|
|
366
|
+
try {
|
|
367
|
+
await this.store.commit(bytes);
|
|
368
|
+
this.check();
|
|
369
|
+
this.state = next;
|
|
370
|
+
}
|
|
371
|
+
catch {
|
|
372
|
+
await this.close();
|
|
373
|
+
throw fail("recovery_required");
|
|
374
|
+
}
|
|
375
|
+
finally {
|
|
376
|
+
bytes.fill(0);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
async exclusive(work) {
|
|
380
|
+
this.check();
|
|
381
|
+
if (this.busy)
|
|
382
|
+
throw fail("busy");
|
|
383
|
+
this.busy = true;
|
|
384
|
+
try {
|
|
385
|
+
return await work();
|
|
386
|
+
}
|
|
387
|
+
finally {
|
|
388
|
+
this.busy = false;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
/** Single bounded request, no cookie, redirect, ambient auth or automatic retry.
|
|
392
|
+
* A network failure may have committed: only explicit SAME-request reconcile. */
|
|
393
|
+
async json(path, secret, body, auth) {
|
|
394
|
+
this.check();
|
|
395
|
+
this.wrongAccountRequestId = null;
|
|
396
|
+
const ctrl = new AbortController(), abort = () => ctrl.abort(), timer = setTimeout(abort, 15000);
|
|
397
|
+
this.lifetime.signal.addEventListener("abort", abort, { once: true });
|
|
398
|
+
let response = null, reader = null, drained = false, decoding = false;
|
|
399
|
+
// Scoped metadata may contain 1000 UUIDs; discovery additionally contains
|
|
400
|
+
// bounded names. Reject oversize before accumulating/parsing the body.
|
|
401
|
+
const bytes = new Uint8Array(auth?.get || path.endsWith("/exchange") ? 1024 * 1024 : 64 * 1024);
|
|
402
|
+
let count = 0;
|
|
403
|
+
try {
|
|
404
|
+
// Default cache mode, also for the authenticated GETs: Chrome skips its CORS preflight cache
|
|
405
|
+
// for "no-store" requests. The CP answers them with Cache-Control: no-store, so nothing is HTTP-cached.
|
|
406
|
+
response = await this.request(`${this.state.cpOrigin}${path}`, { method: auth?.get ? "GET" : auth?.patch ? "PATCH" : auth?.delete ? "DELETE" : "POST", headers: { ...(auth ? { authorization: `Bearer ${auth.bearer}` } : secret ? { authorization: `Bearer ${this.state.secret}` } : {}), ...(body === undefined ? {} : { "content-type": "application/json" }) }, body: body === undefined ? undefined : JSON.stringify(body), credentials: "omit", redirect: "error", cache: "default", referrerPolicy: "no-referrer", signal: ctrl.signal });
|
|
407
|
+
this.check();
|
|
408
|
+
if (ctrl.signal.aborted)
|
|
409
|
+
throw fail("outcome_unknown");
|
|
410
|
+
const length = response.headers.get("content-length");
|
|
411
|
+
// Fetch decodes content-encoding, which CORS may hide. Wire length is
|
|
412
|
+
// only an early over-cap hint; the decoded stream is the hard bound.
|
|
413
|
+
if (length !== null && /^(0|[1-9][0-9]*)$/.test(length) && Number(length) > bytes.length) {
|
|
414
|
+
ctrl.abort();
|
|
415
|
+
throw fail("response");
|
|
416
|
+
}
|
|
417
|
+
if (!response.body)
|
|
418
|
+
throw fail("response");
|
|
419
|
+
reader = response.body.getReader();
|
|
420
|
+
for (;;) {
|
|
421
|
+
const { done, value } = await reader.read();
|
|
422
|
+
try {
|
|
423
|
+
this.check();
|
|
424
|
+
if (ctrl.signal.aborted)
|
|
425
|
+
throw fail("outcome_unknown");
|
|
426
|
+
if (done) {
|
|
427
|
+
drained = true;
|
|
428
|
+
break;
|
|
429
|
+
}
|
|
430
|
+
if (count + value.length > bytes.length) {
|
|
431
|
+
ctrl.abort();
|
|
432
|
+
throw fail("response");
|
|
433
|
+
}
|
|
434
|
+
bytes.set(value, count);
|
|
435
|
+
count += value.length;
|
|
436
|
+
}
|
|
437
|
+
finally {
|
|
438
|
+
value?.fill(0);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
decoding = true;
|
|
442
|
+
const value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, count)));
|
|
443
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
444
|
+
throw fail("response");
|
|
445
|
+
if (!response.ok) {
|
|
446
|
+
const error = value.error;
|
|
447
|
+
if (!auth && response.status === 404 &&
|
|
448
|
+
(path === "/v1/pairing-requests" || path === `/v1/pairing-requests/${this.state.requestId}/exchange` || path === `/v1/pairing-requests/${this.state.requestId}/attest`) &&
|
|
449
|
+
error && typeof error === "object" && !Array.isArray(error) &&
|
|
450
|
+
(error.code === "installation_pairing_expired" || error.code === "installation_pairing_denied")) {
|
|
451
|
+
// Expired or cancelled in the portal: the SAME actor may renew this
|
|
452
|
+
// window from an explicit user retry. Any other 404 stays terminal.
|
|
453
|
+
this.expiredRequestId = this.state.requestId;
|
|
454
|
+
throw fail(error.code === "installation_pairing_expired" ? "expired" : "refused");
|
|
455
|
+
}
|
|
456
|
+
const server = appServerProblem(response.status, value, response.headers);
|
|
457
|
+
throw new AppInstallationSignInError(appServerOutcome(server) ?? "refused", server);
|
|
458
|
+
}
|
|
459
|
+
return { status: response.status, value: value };
|
|
460
|
+
}
|
|
461
|
+
catch (e) {
|
|
462
|
+
this.check();
|
|
463
|
+
const error = e instanceof AppInstallationSignInError ? e : fail(auth?.get && !ctrl.signal.aborted && !(e instanceof DOMException && e.name === "AbortError") ? decoding ? "response" : !response || response.ok ? "unavailable" : "refused" : "outcome_unknown");
|
|
464
|
+
if (response && !response.ok)
|
|
465
|
+
nonOkResponses.add(error);
|
|
466
|
+
throw error;
|
|
467
|
+
}
|
|
468
|
+
// Cancel only an unfinished body: cancelling a drained one makes the browser
|
|
469
|
+
// record a completed request as aborted.
|
|
470
|
+
finally {
|
|
471
|
+
bytes.fill(0);
|
|
472
|
+
if (!drained)
|
|
473
|
+
void (reader?.cancel() ?? response?.body?.cancel())?.catch(() => { });
|
|
474
|
+
reader?.releaseLock();
|
|
475
|
+
clearTimeout(timer);
|
|
476
|
+
this.lifetime.signal.removeEventListener("abort", abort);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
/** Original operation+secret already committed before this FIRST HTTP. An
|
|
480
|
+
* explicit repeat uses the same request, never a new installation/device. */
|
|
481
|
+
start(options = {}) {
|
|
482
|
+
let hint;
|
|
483
|
+
try {
|
|
484
|
+
hint = collectionHint(options);
|
|
485
|
+
}
|
|
486
|
+
catch (error) {
|
|
487
|
+
return Promise.reject(error);
|
|
488
|
+
}
|
|
489
|
+
return this.exclusive(() => this.startRequest(hint));
|
|
490
|
+
}
|
|
491
|
+
/** Explicit user retry after an exact typed expiry. Renew ONLY the pairing
|
|
492
|
+
* window; installation/device/account/challenge/keys/proof remain original.
|
|
493
|
+
* Persist the new request and its parent capability BEFORE HTTP. Unknown
|
|
494
|
+
* outcomes resume that SAME new request via start(), never renew again. */
|
|
495
|
+
renewExpiredPairing() {
|
|
496
|
+
return this.exclusive(async () => {
|
|
497
|
+
const s = this.state;
|
|
498
|
+
if (s.token || this.expiredRequestId !== s.requestId)
|
|
499
|
+
throw fail("recovery_required");
|
|
500
|
+
const bytes = crypto.getRandomValues(new Uint8Array(32));
|
|
501
|
+
try {
|
|
502
|
+
const requestId = crypto.randomUUID(), secret = `pair_${btoa(String.fromCharCode(...bytes)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "")}`;
|
|
503
|
+
if (requestId === s.requestId || requestId === s.renewal?.requestId || secret === s.secret)
|
|
504
|
+
throw fail("binding");
|
|
505
|
+
await this.save({ ...s, requestId, secret, renewal: { requestId: s.requestId, secret: s.secret } });
|
|
506
|
+
this.expiredRequestId = null;
|
|
507
|
+
return await this.startRequest();
|
|
508
|
+
}
|
|
509
|
+
finally {
|
|
510
|
+
bytes.fill(0);
|
|
511
|
+
}
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
async startRequest(hint = null) {
|
|
515
|
+
if (this.state.token)
|
|
516
|
+
return this.view();
|
|
517
|
+
const s = this.state;
|
|
518
|
+
if (s.recoveryFor && hint !== null && hint !== s.recoveryFor.collectionId)
|
|
519
|
+
throw fail("binding");
|
|
520
|
+
const { status, value: v } = await this.json("/v1/pairing-requests", false, { installation: { app_id: s.appId, request_id: s.requestId, pairing_secret: s.secret, installation_id: s.installationId, device_id: s.deviceId, kind: s.kind, requested_create_collections: s.requestedCreateCollections, ...(s.recoveryFor ? { recovery_collection_id: s.recoveryFor.collectionId } : {}), ...(s.renewal ? { renewal: { request_id: s.renewal.requestId, pairing_secret: s.renewal.secret } } : {}) }, ...(hint ? { collection_hint: hint } : {}) });
|
|
521
|
+
if (status !== 200 && status !== 201)
|
|
522
|
+
throw fail("response");
|
|
523
|
+
object(v, `pairing_id,pairing_secret,verification_uri,expires_in,installation_device,app_id,app_origin,app_name${this.recoveryTargetKeys()}`);
|
|
524
|
+
this.assertRecoveryTarget(v);
|
|
525
|
+
const uri = verificationUri(v.verification_uri, `${s.cpOrigin}/pair/${s.requestId}`, hint);
|
|
526
|
+
if (v.pairing_id !== s.requestId || v.pairing_secret !== s.secret || uri === null || v.installation_device !== true || v.app_id !== s.appId || v.app_origin !== s.origin || v.app_name !== this.options.appName || !Number.isSafeInteger(v.expires_in) || v.expires_in < 0 || v.expires_in > 600)
|
|
527
|
+
throw fail("response");
|
|
528
|
+
this.expiredRequestId = null;
|
|
529
|
+
return Object.freeze({ ...this.view(), verificationUri: uri });
|
|
530
|
+
}
|
|
531
|
+
/** Scoped replies must echo the immutable protected CID. Legacy normal
|
|
532
|
+
* replies omit it; missing support is refusal, never a hint-only fallback. */
|
|
533
|
+
recoveryTargetKeys() { return this.state.recoveryFor ? ",recovery_collection_id" : ""; }
|
|
534
|
+
assertRecoveryTarget(value) {
|
|
535
|
+
if (this.state.recoveryFor && id(value.recovery_collection_id) !== this.state.recoveryFor.collectionId)
|
|
536
|
+
throw fail("binding");
|
|
537
|
+
}
|
|
538
|
+
selected(v) {
|
|
539
|
+
const s = this.state;
|
|
540
|
+
this.assertRecoveryTarget(v);
|
|
541
|
+
if (v.request_id !== s.requestId || v.installation_id !== s.installationId || v.device_id !== s.deviceId || v.kind !== s.kind || v.app_id !== s.appId || v.app_origin !== s.origin || v.approval_mode !== "password-ak1" || !Number.isSafeInteger(v.expires_at) || v.expires_at < 0)
|
|
542
|
+
throw fail("response");
|
|
543
|
+
const next = { accountId: id(v.account_id), connectorId: id(v.connector_id), challenge: text(v.challenge, /^[0-9a-f]{64}$/), approvalMode: "password-ak1" };
|
|
544
|
+
if (s.selection && (next.accountId !== s.selection.accountId || next.connectorId !== s.selection.connectorId || next.challenge !== s.selection.challenge || next.approvalMode !== s.selection.approvalMode))
|
|
545
|
+
throw fail("binding");
|
|
546
|
+
Object.assign(next, portalMetadata(v));
|
|
547
|
+
if (s.selection)
|
|
548
|
+
assertOriginalPortal(s.selection, next);
|
|
549
|
+
if (s.recoveryFor && next.accountId !== s.recoveryFor.accountId) {
|
|
550
|
+
if (v.status === "account_selected" && !s.selection && !s.confirmed && !s.nativeStarted && !s.proof && !s.token) {
|
|
551
|
+
this.wrongAccountRequestId = s.requestId;
|
|
552
|
+
throw fail("recovery_account_mismatch");
|
|
553
|
+
}
|
|
554
|
+
throw fail("binding");
|
|
555
|
+
}
|
|
556
|
+
this.wrongAccountRequestId = null;
|
|
557
|
+
return next;
|
|
558
|
+
}
|
|
559
|
+
/** The owner may offer an explicit NEW browser slot only after this exact
|
|
560
|
+
* fully validated wrong-account response, before any confirmation or keys.
|
|
561
|
+
* A generic binding failure, loss, later refusal or closed actor never permits
|
|
562
|
+
* abandoning a possibly completed original attempt. No CP row is reset. */
|
|
563
|
+
canAbandonWrongAccount() {
|
|
564
|
+
const s = this.state;
|
|
565
|
+
return this.isCurrent() && s.recoveryFor !== undefined && this.wrongAccountRequestId === s.requestId &&
|
|
566
|
+
!s.selection && !s.confirmed && !s.nativeStarted && !s.proof && !s.token && !s.consentRequest;
|
|
567
|
+
}
|
|
568
|
+
/** No account KEK/native opens here. The SDK-owned selection must be explicitly
|
|
569
|
+
* confirmed by guarded portal choice or manual legacy confirmation before
|
|
570
|
+
* confirmedSelection/attestation is permitted. */
|
|
571
|
+
exchange() {
|
|
572
|
+
return this.exclusive(async () => {
|
|
573
|
+
if (this.state.token)
|
|
574
|
+
return this.view();
|
|
575
|
+
const { status, value: v } = await this.json(`/v1/pairing-requests/${this.state.requestId}/exchange`, true);
|
|
576
|
+
if (v.status === "pending") {
|
|
577
|
+
object(v, "status");
|
|
578
|
+
if (status !== 202 || this.state.selection)
|
|
579
|
+
throw fail("response");
|
|
580
|
+
return this.view();
|
|
581
|
+
}
|
|
582
|
+
const keys = `status,request_id,account_id,connector_id,device_id,installation_id,kind,challenge,approval_mode,app_id,app_origin,expires_at${portalKeys(v)}${this.recoveryTargetKeys()}`;
|
|
583
|
+
if (v.status === "account_selected" || v.status === "awaiting_approval") {
|
|
584
|
+
object(v, keys);
|
|
585
|
+
if (status !== 202 || (v.status === "awaiting_approval" && !this.state.proof))
|
|
586
|
+
throw fail("response");
|
|
587
|
+
const selection = this.selected(v);
|
|
588
|
+
if (JSON.stringify(selection) !== JSON.stringify(this.state.selection))
|
|
589
|
+
await this.save({ ...this.state, selection });
|
|
590
|
+
return this.view();
|
|
591
|
+
}
|
|
592
|
+
// Pre-C5 receipts give NO scope; never infer access from old enrollment.
|
|
593
|
+
const scoped = Object.hasOwn(v, "collection_ids") || Object.hasOwn(v, "create_collections");
|
|
594
|
+
const picked = Object.hasOwn(v, "selected_collection_id") || Object.hasOwn(v, "created_collection_ids");
|
|
595
|
+
const native = Object.hasOwn(v, "native_selection");
|
|
596
|
+
object(v, `${keys},connector,token,registration${scoped ? ",collection_ids,create_collections" : ""}${picked ? ",selected_collection_id,created_collection_ids" : ""}${native ? ",native_selection" : ""}${timerKeys(v)}`);
|
|
597
|
+
if (status !== 200 || v.status !== "paired" || !this.state.confirmed || !this.state.proof)
|
|
598
|
+
throw fail("response");
|
|
599
|
+
const selection = this.selected(v), connector = object(v.connector, "id,name"), r = object(v.registration, "device_id,sign_pk,kem_pk,noise_pk");
|
|
600
|
+
if (connector.id !== selection.connectorId || connector.name !== this.options.appName || r.device_id !== this.state.deviceId || r.sign_pk !== this.state.proof.sign_pk || r.kem_pk !== this.state.proof.kem_pk || r.noise_pk !== this.state.proof.noise_pk)
|
|
601
|
+
throw fail("binding");
|
|
602
|
+
const collectionIds = scoped ? AppProtectedInstallationSignIn.collectionIds(v.collection_ids) : [];
|
|
603
|
+
const createCollections = scoped ? v.create_collections : false;
|
|
604
|
+
if (typeof createCollections !== "boolean" || (createCollections && !this.state.requestedCreateCollections))
|
|
605
|
+
throw fail("response");
|
|
606
|
+
const collectionSelection = picked ? this.collectionSelection(v, collectionIds, this.state.requestId) : undefined;
|
|
607
|
+
const nativeSelection = native ? this.parseNativeSelection(v.native_selection, this.state.requestId) : undefined;
|
|
608
|
+
if (native && (!scoped || picked || createCollections || collectionIds.length !== 0 || v.timer_consent === true))
|
|
609
|
+
throw fail("response");
|
|
610
|
+
if (this.state.recoveryFor && nativeSelection && nativeSelection.collectionId !== this.state.recoveryFor.collectionId)
|
|
611
|
+
throw fail("binding");
|
|
612
|
+
if (this.state.recoveryFor && !nativeSelection && (createCollections || collectionIds.length !== 1 || collectionIds[0] !== this.state.recoveryFor.collectionId ||
|
|
613
|
+
collectionSelection?.selectedCollectionId !== this.state.recoveryFor.collectionId || collectionSelection.createdCollectionIds.length !== 0))
|
|
614
|
+
throw fail("binding");
|
|
615
|
+
if (v.timer_consent === true && !collectionSelection)
|
|
616
|
+
throw fail("response");
|
|
617
|
+
const reminder = timerConsent(v, this.state.requestId, collectionIds, selection.portalConfirmed === true, collectionSelection?.selectedCollectionId);
|
|
618
|
+
const token = text(v.token, /^idev_[A-Za-z0-9_-]{43}$/);
|
|
619
|
+
await this.save({ ...this.state, selection, token, collectionIds, createCollections, nativeSelection, ...(nativeSelection ? { collectionSelection: undefined } : collectionSelection ? { collectionSelection } : {}), ...(reminder ? { timerConsent: reminder } : {}) });
|
|
620
|
+
return this.view();
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
parseNativeSelection(value, requestId) {
|
|
624
|
+
const n = object(value, "authorization_request_id,collection_id"), a = this.state.nativeAuthorization;
|
|
625
|
+
if (!a || a.requestId !== requestId || id(n.authorization_request_id) !== a.authorizationId)
|
|
626
|
+
throw fail("binding");
|
|
627
|
+
return Object.freeze({ requestId, authorizationRequestId: a.authorizationId, collectionId: id(n.collection_id) });
|
|
628
|
+
}
|
|
629
|
+
pendingNativeSelection() { this.check(); return this.state.nativeSelection ?? null; }
|
|
630
|
+
nativeAuthorizationContext(installation) {
|
|
631
|
+
this.check();
|
|
632
|
+
this.owned(installation);
|
|
633
|
+
const s = this.state, r = s.consentRequest && !s.consentRequest.completed ? s.consentRequest : null;
|
|
634
|
+
const challenge = r?.challenge ?? s.selection?.challenge, confirmed = r ? r.portalConfirmed : s.selection?.portalConfirmed;
|
|
635
|
+
if (!s.proof || !s.confirmed || !confirmed || !challenge || (s.token && !r))
|
|
636
|
+
return null;
|
|
637
|
+
const requestId = r?.requestId ?? s.requestId, a = s.nativeAuthorization;
|
|
638
|
+
return Object.freeze({ requestId, accountId: s.selection.accountId, appId: s.appId, challenge, ...(a?.requestId === requestId ? { authorizationId: a.authorizationId } : {}) });
|
|
639
|
+
}
|
|
640
|
+
attachNativeAuthorization(installation, context, prepared) {
|
|
641
|
+
const original = Object.freeze({ ...context }), p = Object.freeze({ ...prepared }), callback = installation.isCurrent;
|
|
642
|
+
return this.exclusive(async () => {
|
|
643
|
+
this.owned(installation);
|
|
644
|
+
const current = this.nativeAuthorizationContext(installation);
|
|
645
|
+
if (!current || installation.isCurrent !== callback || current.requestId !== original.requestId || current.challenge !== original.challenge || current.accountId !== original.accountId || p.applicationId !== current.appId || !/^[0-9a-f]{64}$/.test(p.manifestDigest))
|
|
646
|
+
throw fail("binding");
|
|
647
|
+
id(p.authorizationId);
|
|
648
|
+
if (current.authorizationId && current.authorizationId !== p.authorizationId)
|
|
649
|
+
throw fail("binding");
|
|
650
|
+
await this.save({ ...this.state, nativeAuthorization: { ...p, requestId: current.requestId } });
|
|
651
|
+
const bearer = current.requestId === this.state.requestId ? this.state.secret : this.state.consentRequest.secret;
|
|
652
|
+
const { status, value } = await this.json(`/v1/pairing-requests/${current.requestId}/native-authorization`, false, { authorization_request_id: p.authorizationId }, { bearer });
|
|
653
|
+
this.owned(installation);
|
|
654
|
+
if (installation.isCurrent !== callback)
|
|
655
|
+
throw fail("fenced");
|
|
656
|
+
object(value, "request_id,authorization_request_id,account_id");
|
|
657
|
+
if (status !== 200 || value.request_id !== current.requestId || value.authorization_request_id !== p.authorizationId || value.account_id !== current.accountId)
|
|
658
|
+
throw fail("binding");
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
completeNativeAuthorization(installation, completion) {
|
|
662
|
+
const check = this.consentGuard(installation);
|
|
663
|
+
return this.exclusive(async () => {
|
|
664
|
+
check();
|
|
665
|
+
const s = this.state, n = s.nativeSelection, a = s.nativeAuthorization;
|
|
666
|
+
if (!this.nativeAcknowledged || !n || !a)
|
|
667
|
+
throw fail("binding");
|
|
668
|
+
const verified = boundNativeCompletion(completion, n, s.selection.accountId, s.appId, s.origin, a.manifestDigest);
|
|
669
|
+
await this.save({ ...s, nativeGrants: [...(s.nativeGrants ?? []).filter(c => c.collection_id !== n.collectionId), verified] });
|
|
670
|
+
check();
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
collectionSelection(v, approved, requestId) {
|
|
674
|
+
const selectedCollectionId = id(v.selected_collection_id), createdCollectionIds = AppProtectedInstallationSignIn.collectionIds(v.created_collection_ids);
|
|
675
|
+
if (!approved.includes(selectedCollectionId) || createdCollectionIds.some(value => !approved.includes(value)))
|
|
676
|
+
throw fail("response");
|
|
677
|
+
return Object.freeze({ requestId, selectedCollectionId, createdCollectionIds: Object.freeze(createdCollectionIds) });
|
|
678
|
+
}
|
|
679
|
+
collectionConsentView() {
|
|
680
|
+
this.check();
|
|
681
|
+
const r = this.state.consentRequest;
|
|
682
|
+
return r ? Object.freeze({ requestId: r.requestId, verificationUri: `${this.state.cpOrigin}/pair/${r.requestId}`, state: r.completed ? "scope_updated" : "pending", requestedCreateCollections: r.requestedCreateCollections, addedCollectionIds: Object.freeze([...r.addedCollectionIds]), approvedCreateCollections: r.approvedCreateCollections, accountEmail: r.accountEmail ?? null, ...(r.accountProvider ? { accountProvider: r.accountProvider, accountLogin: r.accountLogin } : {}), accountSelectionConfirmed: r.portalConfirmed === true }) : null;
|
|
683
|
+
}
|
|
684
|
+
consentGuard(installation) {
|
|
685
|
+
const callback = installation.isCurrent;
|
|
686
|
+
return () => { this.check(); this.owned(installation); this.receipt(); if (installation.isCurrent !== callback)
|
|
687
|
+
throw fail("fenced"); };
|
|
688
|
+
}
|
|
689
|
+
/** A consent window the CP reports closed (denied in the portal, or expired) can
|
|
690
|
+
* never be reopened, and re-consent windows are not renewable. Forget it, so the
|
|
691
|
+
* next explicit consent starts a new window instead of re-sending the dead one. */
|
|
692
|
+
async consentWindow(requestId, work) {
|
|
693
|
+
try {
|
|
694
|
+
return await work();
|
|
695
|
+
}
|
|
696
|
+
catch (error) {
|
|
697
|
+
const code = error instanceof AppInstallationSignInError ? error.server?.code : null;
|
|
698
|
+
if ((code === "installation_pairing_denied" || code === "installation_pairing_expired") && error instanceof AppInstallationSignInError && error.server?.status === 404) {
|
|
699
|
+
const r = this.state.consentRequest;
|
|
700
|
+
if (r && !r.completed && r.requestId === requestId)
|
|
701
|
+
await this.save({ ...this.state, consentRequest: null });
|
|
702
|
+
throw fail(code === "installation_pairing_expired" ? "expired" : "refused");
|
|
703
|
+
}
|
|
704
|
+
throw error;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
/** Explicit additive consent, not renewal/registration/account selection.
|
|
708
|
+
* A new secret/request is protected BEFORE HTTP; unknown outcomes only permit
|
|
709
|
+
* an explicit repeat of that exact request, never new keys or a new actor. */
|
|
710
|
+
startCollectionConsent(installation, requestedCreateCollections = false, options = {}) {
|
|
711
|
+
const check = this.consentGuard(installation);
|
|
712
|
+
let hint;
|
|
713
|
+
try {
|
|
714
|
+
hint = collectionHint(options);
|
|
715
|
+
}
|
|
716
|
+
catch (error) {
|
|
717
|
+
return Promise.reject(error);
|
|
718
|
+
}
|
|
719
|
+
const attempt = async () => {
|
|
720
|
+
check();
|
|
721
|
+
if (this.state.recoveryFor || typeof requestedCreateCollections !== "boolean")
|
|
722
|
+
throw fail("binding");
|
|
723
|
+
let r = this.state.consentRequest;
|
|
724
|
+
if (!r || r.completed) {
|
|
725
|
+
const bytes = crypto.getRandomValues(new Uint8Array(32));
|
|
726
|
+
try {
|
|
727
|
+
const secret = `pair_${btoa(String.fromCharCode(...bytes)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "")}`;
|
|
728
|
+
r = { requestId: crypto.randomUUID(), secret, requestedCreateCollections, challenge: null, completed: false, addedCollectionIds: [], approvedCreateCollections: false };
|
|
729
|
+
await this.save({ ...this.state, consentRequest: r });
|
|
730
|
+
check();
|
|
731
|
+
}
|
|
732
|
+
finally {
|
|
733
|
+
bytes.fill(0);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
else if (r.requestedCreateCollections !== requestedCreateCollections)
|
|
737
|
+
throw fail("binding");
|
|
738
|
+
const s = this.state, token = s.token, req = r;
|
|
739
|
+
const { status, value: v } = await this.consentWindow(req.requestId, () => this.json("/v1/pairing-requests", false, { installation: { app_id: s.appId, request_id: req.requestId, pairing_secret: req.secret, installation_id: s.installationId, device_id: s.deviceId, kind: s.kind, requested_create_collections: req.requestedCreateCollections, reconsent: true }, ...(hint ? { collection_hint: hint } : {}) }, { bearer: token }));
|
|
740
|
+
check();
|
|
741
|
+
object(v, "pairing_id,pairing_secret,verification_uri,expires_in,installation_device,app_id,app_origin,app_name");
|
|
742
|
+
let uri = null;
|
|
743
|
+
if ((status !== 200 && status !== 201) || v.pairing_id !== r.requestId || v.pairing_secret !== r.secret || (uri = verificationUri(v.verification_uri, `${s.cpOrigin}/pair/${r.requestId}`, hint)) === null || v.installation_device !== true || v.app_id !== s.appId || v.app_origin !== s.origin || v.app_name !== this.options.appName || !Number.isSafeInteger(v.expires_in) || v.expires_in < 0 || v.expires_in > 600 || token !== this.state.token)
|
|
744
|
+
throw fail("response");
|
|
745
|
+
return Object.freeze({ ...this.collectionConsentView(), verificationUri: uri });
|
|
746
|
+
};
|
|
747
|
+
return this.exclusive(async () => {
|
|
748
|
+
const stored = this.state.consentRequest, reused = stored !== null && !stored.completed;
|
|
749
|
+
try {
|
|
750
|
+
return await attempt();
|
|
751
|
+
}
|
|
752
|
+
catch (error) {
|
|
753
|
+
// The stored window was already closed in Connect (and is now forgotten):
|
|
754
|
+
// a definite outcome, same credential, so open the new window for this gesture.
|
|
755
|
+
if (reused && this.state.consentRequest === null && error instanceof AppInstallationSignInError && (error.reason === "refused" || error.reason === "expired"))
|
|
756
|
+
return await attempt();
|
|
757
|
+
throw error;
|
|
758
|
+
}
|
|
759
|
+
});
|
|
760
|
+
}
|
|
761
|
+
/** The ORIGINAL consent-request secret consumes approval. Strict response
|
|
762
|
+
* keys forbid replacement tokens/registrations; original actor/proof remains. */
|
|
763
|
+
exchangeCollectionConsent(installation) {
|
|
764
|
+
const check = this.consentGuard(installation);
|
|
765
|
+
return this.exclusive(async () => {
|
|
766
|
+
check();
|
|
767
|
+
const r = this.state.consentRequest, s = this.state;
|
|
768
|
+
if (!r)
|
|
769
|
+
throw fail("binding");
|
|
770
|
+
if (r.completed)
|
|
771
|
+
return this.collectionConsentView();
|
|
772
|
+
const { status, value: v } = await this.consentWindow(r.requestId, () => this.json(`/v1/pairing-requests/${r.requestId}/exchange`, false, undefined, { bearer: r.secret }));
|
|
773
|
+
check();
|
|
774
|
+
const portal = portalKeys(v);
|
|
775
|
+
const keys = `status,request_id,account_id,connector_id,device_id,installation_id,kind,challenge,approval_mode,app_id,app_origin,expires_at${portal}`;
|
|
776
|
+
const done = v.status === "scope_updated";
|
|
777
|
+
const picked = done && (Object.hasOwn(v, "selected_collection_id") || Object.hasOwn(v, "created_collection_ids"));
|
|
778
|
+
const native = done && Object.hasOwn(v, "native_selection");
|
|
779
|
+
object(v, `${keys}${done ? ",added_collection_ids,approved_create_collections" : ""}${picked ? ",selected_collection_id,created_collection_ids" : ""}${native ? ",native_selection" : ""}${done ? timerKeys(v) : ""}`);
|
|
780
|
+
if ((!done && (status !== 202 || v.status !== "awaiting_approval")) || (done && status !== 200) || v.request_id !== r.requestId || v.account_id !== s.selection.accountId || v.connector_id !== s.selection.connectorId || v.device_id !== s.deviceId || v.installation_id !== s.installationId || v.kind !== s.kind || v.app_id !== s.appId || v.app_origin !== s.origin || v.approval_mode !== s.selection.approvalMode || !Number.isSafeInteger(v.expires_at) || v.expires_at < 0)
|
|
781
|
+
throw fail("binding");
|
|
782
|
+
const confirmation = portalMetadata(v);
|
|
783
|
+
if (r.portalConfirmed && !portal)
|
|
784
|
+
throw fail("response");
|
|
785
|
+
assertOriginalPortal(r, confirmation);
|
|
786
|
+
const challenge = text(v.challenge, /^[0-9a-f]{64}$/);
|
|
787
|
+
if (r.challenge !== null && r.challenge !== challenge)
|
|
788
|
+
throw fail("binding");
|
|
789
|
+
if (!done) {
|
|
790
|
+
if (r.challenge === null || (portal && !r.portalConfirmed))
|
|
791
|
+
await this.save({ ...s, consentRequest: { ...r, ...confirmation, challenge } });
|
|
792
|
+
check();
|
|
793
|
+
return this.collectionConsentView();
|
|
794
|
+
}
|
|
795
|
+
const addedCollectionIds = AppProtectedInstallationSignIn.collectionIds(v.added_collection_ids);
|
|
796
|
+
if (typeof v.approved_create_collections !== "boolean" || (v.approved_create_collections && !r.requestedCreateCollections))
|
|
797
|
+
throw fail("response");
|
|
798
|
+
const collectionIds = AppProtectedInstallationSignIn.collectionIds([...new Set([...s.collectionIds, ...addedCollectionIds])]);
|
|
799
|
+
const collectionSelection = picked ? this.collectionSelection(v, collectionIds, r.requestId) : undefined;
|
|
800
|
+
const nativeSelection = native ? this.parseNativeSelection(v.native_selection, r.requestId) : undefined;
|
|
801
|
+
if (native && (picked || addedCollectionIds.length !== 0 || v.approved_create_collections !== false || v.timer_consent === true))
|
|
802
|
+
throw fail("response");
|
|
803
|
+
if (v.timer_consent === true && !collectionSelection)
|
|
804
|
+
throw fail("response");
|
|
805
|
+
const reminder = timerConsent(v, r.requestId, addedCollectionIds, confirmation.portalConfirmed === true, collectionSelection?.selectedCollectionId);
|
|
806
|
+
await this.save({ ...s, collectionIds, nativeSelection, ...(nativeSelection ? { collectionSelection: undefined } : collectionSelection ? { collectionSelection } : {}), ...(reminder ? { timerConsent: reminder } : {}), createCollections: s.createCollections || v.approved_create_collections, consentRequest: { ...r, ...confirmation, challenge, completed: true, addedCollectionIds, approvedCreateCollections: v.approved_create_collections } });
|
|
807
|
+
check();
|
|
808
|
+
return this.collectionConsentView();
|
|
809
|
+
});
|
|
810
|
+
}
|
|
811
|
+
/** Current approved/member cloud-copy metadata only; never readiness, keying,
|
|
812
|
+
* or permission inferred from this response or retained consent snapshots. */
|
|
813
|
+
listApprovedCollections(installation) {
|
|
814
|
+
const check = this.consentGuard(installation);
|
|
815
|
+
return this.exclusive(async () => {
|
|
816
|
+
check();
|
|
817
|
+
let reply;
|
|
818
|
+
try {
|
|
819
|
+
reply = await this.json("/v1/next/collections?include=file_actions", false, undefined, { bearer: this.state.token, get: true });
|
|
820
|
+
}
|
|
821
|
+
catch (error) {
|
|
822
|
+
check();
|
|
823
|
+
if (error instanceof AppInstallationSignInError && error.reason === "unavailable" && !error.server && !nonOkResponses.has(error) && this.state.collectionListing !== undefined)
|
|
824
|
+
return Object.freeze(collectionListing(this.state.collectionListing).filter(c => this.state.collectionIds.includes(c.collectionId)).map(c => Object.freeze({ ...c, fileActions: Object.freeze([]) })));
|
|
825
|
+
if (error instanceof AppInstallationSignInError && (error.server || nonOkResponses.has(error)) && this.state.collectionListing !== undefined) {
|
|
826
|
+
const state = { ...this.state };
|
|
827
|
+
delete state.collectionListing;
|
|
828
|
+
await this.save(state);
|
|
829
|
+
check();
|
|
830
|
+
}
|
|
831
|
+
throw error;
|
|
832
|
+
}
|
|
833
|
+
check();
|
|
834
|
+
const { status, value: v } = reply;
|
|
835
|
+
object(v, "collections");
|
|
836
|
+
if (status !== 200)
|
|
837
|
+
throw fail("response");
|
|
838
|
+
const collections = collectionListing(v.collections);
|
|
839
|
+
// Receipt references narrow replay; metadata cannot add consent or infer a role.
|
|
840
|
+
const approved = v.collections.filter(c => this.state.collectionIds.includes(c.collection_id)).map(c => { const metadata = { ...c }; delete metadata.file_actions; return metadata; });
|
|
841
|
+
const state = { ...this.state };
|
|
842
|
+
delete state.collectionListing;
|
|
843
|
+
const cached = { ...state, collectionListing: approved };
|
|
844
|
+
// Keep the original 128 KiB protected-ledger ceiling. An oversized listing
|
|
845
|
+
// remains usable online but cannot leave an obsolete offline cache behind.
|
|
846
|
+
await this.save(new TextEncoder().encode(JSON.stringify(cached)).length <= 128 * 1024 ? cached : state);
|
|
847
|
+
check();
|
|
848
|
+
return collections;
|
|
849
|
+
});
|
|
850
|
+
}
|
|
851
|
+
/** Protected references to retired scopes. Each non-null value identifies a
|
|
852
|
+
* separate original installation ledger, never a replacement credential. */
|
|
853
|
+
collectionRecoveries() {
|
|
854
|
+
this.check();
|
|
855
|
+
return Object.freeze({ ...this.state.collectionRecoveries });
|
|
856
|
+
}
|
|
857
|
+
retireCollectionScope(installation, collection, expectedReplacement = null) {
|
|
858
|
+
const check = this.consentGuard(installation);
|
|
859
|
+
return this.exclusive(async () => {
|
|
860
|
+
check();
|
|
861
|
+
id(collection);
|
|
862
|
+
if (!(this.state.collectionIds.includes(collection) || this.state.nativeGrants?.some(c => c.collection_id === collection)))
|
|
863
|
+
throw fail("binding");
|
|
864
|
+
if (expectedReplacement !== null) {
|
|
865
|
+
id(expectedReplacement);
|
|
866
|
+
if (this.state.collectionRecoveries?.[collection] !== expectedReplacement)
|
|
867
|
+
throw fail("fenced");
|
|
868
|
+
}
|
|
869
|
+
else if (Object.hasOwn(this.state.collectionRecoveries ?? {}, collection))
|
|
870
|
+
return;
|
|
871
|
+
await this.saveRecovery(collection, null);
|
|
872
|
+
check();
|
|
873
|
+
});
|
|
874
|
+
}
|
|
875
|
+
/** Only an explicit recovery gesture creates this new slot reference. The
|
|
876
|
+
* new slot performs ordinary account confirmation, attestation and approval. */
|
|
877
|
+
freshCollectionInstallation(installation, collection) {
|
|
878
|
+
const check = this.consentGuard(installation);
|
|
879
|
+
return this.exclusive(async () => {
|
|
880
|
+
check();
|
|
881
|
+
id(collection);
|
|
882
|
+
if (!Object.hasOwn(this.state.collectionRecoveries ?? {}, collection))
|
|
883
|
+
throw fail("binding");
|
|
884
|
+
const existing = this.state.collectionRecoveries[collection];
|
|
885
|
+
if (existing !== null)
|
|
886
|
+
return existing; // pending/unknown retries keep the SAME fresh slot
|
|
887
|
+
const replacement = crypto.randomUUID();
|
|
888
|
+
await this.saveRecovery(collection, replacement);
|
|
889
|
+
check();
|
|
890
|
+
return replacement;
|
|
891
|
+
});
|
|
892
|
+
}
|
|
893
|
+
async saveRecovery(collection, replacement) {
|
|
894
|
+
const state = { ...this.state, collectionRecoveries: { ...this.state.collectionRecoveries, [collection]: replacement } };
|
|
895
|
+
// Recovery metadata shares the original ledger bound; discard only display
|
|
896
|
+
// cache if necessary, never the original receipt or unrelated scope state.
|
|
897
|
+
if (new TextEncoder().encode(JSON.stringify(state)).length > 128 * 1024)
|
|
898
|
+
delete state.collectionListing;
|
|
899
|
+
await this.save(state);
|
|
900
|
+
}
|
|
901
|
+
/** Ask, from a fresh user gesture, for declared optional file actions on one
|
|
902
|
+
* approved collection, with a one-line reason shown by Connect. A scope-only
|
|
903
|
+
* re-consent under a new in-memory secret: nothing is persisted, so a lost
|
|
904
|
+
* Worker simply drops the request. */
|
|
905
|
+
startFileAccess(installation, collectionId, actions, reason) {
|
|
906
|
+
const check = this.consentGuard(installation);
|
|
907
|
+
let requested;
|
|
908
|
+
try {
|
|
909
|
+
id(collectionId);
|
|
910
|
+
requested = fileActions([...actions], FILE_ACTIONS, false);
|
|
911
|
+
if (requested.length !== actions.length)
|
|
912
|
+
throw fail("binding");
|
|
913
|
+
}
|
|
914
|
+
catch {
|
|
915
|
+
return Promise.reject(fail("binding"));
|
|
916
|
+
}
|
|
917
|
+
return this.exclusive(async () => {
|
|
918
|
+
check();
|
|
919
|
+
const bytes = crypto.getRandomValues(new Uint8Array(32));
|
|
920
|
+
try {
|
|
921
|
+
const requestId = crypto.randomUUID(), secret = `pair_${btoa(String.fromCharCode(...bytes)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "")}`;
|
|
922
|
+
const s = this.state, token = s.token;
|
|
923
|
+
const { status, value: v } = await this.json("/v1/pairing-requests", false, { installation: { app_id: s.appId, request_id: requestId, pairing_secret: secret, installation_id: s.installationId, device_id: s.deviceId, kind: s.kind, requested_create_collections: false, reconsent: true, file_access: { collection_id: collectionId, actions: [...requested], reason } } }, { bearer: token });
|
|
924
|
+
check();
|
|
925
|
+
object(v, "pairing_id,pairing_secret,verification_uri,expires_in,installation_device,app_id,app_origin,app_name");
|
|
926
|
+
const uri = `${s.cpOrigin}/pair/${requestId}`;
|
|
927
|
+
if ((status !== 200 && status !== 201) || v.pairing_id !== requestId || v.pairing_secret !== secret || v.verification_uri !== uri || v.installation_device !== true || v.app_id !== s.appId || v.app_origin !== s.origin || v.app_name !== this.options.appName || !Number.isSafeInteger(v.expires_in) || v.expires_in < 0 || v.expires_in > 600 || token !== this.state.token)
|
|
928
|
+
throw fail("response");
|
|
929
|
+
return Object.freeze({ requestId, secret, collectionId, actions: requested, verificationUri: uri, expiresAt: Date.now() + v.expires_in * 1000 });
|
|
930
|
+
}
|
|
931
|
+
finally {
|
|
932
|
+
bytes.fill(0);
|
|
933
|
+
}
|
|
934
|
+
});
|
|
935
|
+
}
|
|
936
|
+
/** One read of that request's outcome. Connect records an approval when the
|
|
937
|
+
* person allows it; this only reports it. */
|
|
938
|
+
exchangeFileAccess(installation, request) {
|
|
939
|
+
const check = this.consentGuard(installation);
|
|
940
|
+
return this.exclusive(async () => {
|
|
941
|
+
check();
|
|
942
|
+
const s = this.state;
|
|
943
|
+
const { status, value: v } = await this.json(`/v1/pairing-requests/${request.requestId}/exchange`, false, undefined, { bearer: request.secret });
|
|
944
|
+
check();
|
|
945
|
+
if (v.status === "pending") {
|
|
946
|
+
object(v, "status");
|
|
947
|
+
if (status !== 202)
|
|
948
|
+
throw fail("response");
|
|
949
|
+
return Object.freeze({ state: "pending" });
|
|
950
|
+
}
|
|
951
|
+
if (v.status === "account_selected" || v.status === "awaiting_approval") {
|
|
952
|
+
object(v, `status,request_id,account_id,connector_id,device_id,installation_id,kind,challenge,approval_mode,app_id,app_origin,expires_at${portalKeys(v)}`);
|
|
953
|
+
if (status !== 202 || v.request_id !== request.requestId || v.account_id !== s.selection?.accountId || v.installation_id !== s.installationId || v.device_id !== s.deviceId || v.app_id !== s.appId)
|
|
954
|
+
throw fail("binding");
|
|
955
|
+
return Object.freeze({ state: "pending" });
|
|
956
|
+
}
|
|
957
|
+
if (v.status === "declined") {
|
|
958
|
+
object(v, "status,request_id");
|
|
959
|
+
if (status !== 200 || v.request_id !== request.requestId)
|
|
960
|
+
throw fail("response");
|
|
961
|
+
return Object.freeze({ state: "declined" });
|
|
962
|
+
}
|
|
963
|
+
object(v, "status,request_id,collection_id,file_actions");
|
|
964
|
+
if (status !== 200 || v.status !== "file_access_updated" || v.request_id !== request.requestId || v.collection_id !== request.collectionId)
|
|
965
|
+
throw fail("response");
|
|
966
|
+
return Object.freeze({ state: "granted", actions: fileActions(v.file_actions, request.actions, false) });
|
|
967
|
+
});
|
|
968
|
+
}
|
|
969
|
+
/** Fresh explicit user intent only. CP owner/approved scope remains authoritative;
|
|
970
|
+
* private installation consent is not widened. Names are cleartext metadata,
|
|
971
|
+
* not paths or native readiness. No CAS/request ledger or automatic retry:
|
|
972
|
+
* a lost response is UNKNOWN; refresh catalog, never infer commit from equality.
|
|
973
|
+
*/
|
|
974
|
+
renameApprovedCollection(installation, collectionId, displayName) {
|
|
975
|
+
// Capture/validate caller input synchronously, before exclusive/HTTP awaits.
|
|
976
|
+
let name;
|
|
977
|
+
try {
|
|
978
|
+
id(collectionId);
|
|
979
|
+
name = collectionDisplayName(displayName);
|
|
980
|
+
}
|
|
981
|
+
catch {
|
|
982
|
+
return Promise.reject(fail("binding"));
|
|
983
|
+
}
|
|
984
|
+
const check = this.consentGuard(installation);
|
|
985
|
+
return this.exclusive(async () => {
|
|
986
|
+
check();
|
|
987
|
+
if (!this.state.collectionIds.includes(collectionId))
|
|
988
|
+
throw fail("refused");
|
|
989
|
+
const { status, value } = await this.json(`/v1/next/collections/${collectionId}/name`, false, { display_name: name }, { bearer: this.state.token, patch: true });
|
|
990
|
+
check();
|
|
991
|
+
const response = object(value, "collection_id,display_name");
|
|
992
|
+
if (status !== 200 || response.collection_id !== collectionId || response.display_name !== name)
|
|
993
|
+
throw fail("response");
|
|
994
|
+
return Object.freeze({ collectionId, displayName: name });
|
|
995
|
+
});
|
|
996
|
+
}
|
|
997
|
+
/** Fresh explicit owner intent only: soft-delete one approved collection for
|
|
998
|
+
* everyone. `confirmName` must equal the current name (the CP checks it).
|
|
999
|
+
* The CP is authoritative for ownership, freeze and scope. No retry: a lost
|
|
1000
|
+
* response is UNKNOWN; refresh the catalog, never infer the outcome. */
|
|
1001
|
+
deleteApprovedCollection(installation, collectionId, confirmName) {
|
|
1002
|
+
let name;
|
|
1003
|
+
try {
|
|
1004
|
+
id(collectionId);
|
|
1005
|
+
name = collectionDisplayName(confirmName);
|
|
1006
|
+
}
|
|
1007
|
+
catch {
|
|
1008
|
+
return Promise.reject(fail("binding"));
|
|
1009
|
+
}
|
|
1010
|
+
const check = this.consentGuard(installation);
|
|
1011
|
+
return this.exclusive(async () => {
|
|
1012
|
+
check();
|
|
1013
|
+
if (!this.state.collectionIds.includes(collectionId))
|
|
1014
|
+
throw fail("refused");
|
|
1015
|
+
const { status, value } = await this.json(`/v1/next/collections/${collectionId}`, false, { confirm_name: name }, { bearer: this.state.token, delete: true });
|
|
1016
|
+
check();
|
|
1017
|
+
const response = object(value, "collection_id,deleted");
|
|
1018
|
+
if (status !== 200 || response.collection_id !== collectionId || response.deleted !== true)
|
|
1019
|
+
throw fail("response");
|
|
1020
|
+
return Object.freeze({ collectionId, deleted: true });
|
|
1021
|
+
});
|
|
1022
|
+
}
|
|
1023
|
+
/** UX-011: end this installation's server session. One DELETE
|
|
1024
|
+
* /v1/next/installation with the installation's own `idev_` credential, no
|
|
1025
|
+
* retry. `revoked`: the CP revoked it now. `already_signed_out`: 401
|
|
1026
|
+
* `invalid_connector`, the CP no longer accepts this credential. Every other
|
|
1027
|
+
* outcome (403 `installation_required`, 5xx, network loss) rejects. */
|
|
1028
|
+
signOutInstallation() {
|
|
1029
|
+
return this.exclusive(async () => {
|
|
1030
|
+
const token = this.state.token;
|
|
1031
|
+
if (!token)
|
|
1032
|
+
throw fail("binding");
|
|
1033
|
+
try {
|
|
1034
|
+
const { status, value } = await this.json("/v1/next/installation", false, undefined, { bearer: token, delete: true });
|
|
1035
|
+
// Required fields only: no authority is derived from this response.
|
|
1036
|
+
if (status !== 200 || value.ok !== true || value.revoked !== true || !Number.isSafeInteger(value.collections) || value.collections < 0
|
|
1037
|
+
|| (value.fence !== "closed" && value.fence !== "committed_with_degraded_fence"))
|
|
1038
|
+
throw fail("response");
|
|
1039
|
+
return "revoked";
|
|
1040
|
+
}
|
|
1041
|
+
catch (error) {
|
|
1042
|
+
if (error instanceof AppInstallationSignInError && error.server?.status === 401 && error.server.code === "invalid_connector")
|
|
1043
|
+
return "already_signed_out";
|
|
1044
|
+
throw error;
|
|
1045
|
+
}
|
|
1046
|
+
});
|
|
1047
|
+
}
|
|
1048
|
+
/** True when this installation registered a Web Push channel (so a browser
|
|
1049
|
+
* push subscription exists for the app). Metadata only. */
|
|
1050
|
+
hasWebPushChannel() { this.check(); return this.state.timerChannel?.kind === "web_push"; }
|
|
1051
|
+
/** Consume only this object's protected current portal-confirmed selection.
|
|
1052
|
+
* The CP marker comes from an explicit authenticated portal account choice,
|
|
1053
|
+
* bound to the original request secret/app/origin/actor/challenge. Identity is
|
|
1054
|
+
* display metadata. This grants no collection scope and bypasses no final CP
|
|
1055
|
+
* approval, original native ownership or attestation requirement. */
|
|
1056
|
+
confirmPortalSelectedAccount() {
|
|
1057
|
+
return this.exclusive(async () => {
|
|
1058
|
+
const selection = this.state.selection;
|
|
1059
|
+
if (!selection?.portalConfirmed)
|
|
1060
|
+
throw fail("account_confirmation_required");
|
|
1061
|
+
if (!this.state.confirmed)
|
|
1062
|
+
await this.save({ ...this.state, confirmed: true });
|
|
1063
|
+
this.check();
|
|
1064
|
+
if (this.state.selection !== selection)
|
|
1065
|
+
throw fail("binding");
|
|
1066
|
+
return this.view();
|
|
1067
|
+
});
|
|
1068
|
+
}
|
|
1069
|
+
confirmSelectedAccount(accountId) {
|
|
1070
|
+
return this.exclusive(async () => { if (!this.state.selection || accountId !== this.state.selection.accountId)
|
|
1071
|
+
throw fail("binding"); if (!this.state.confirmed)
|
|
1072
|
+
await this.save({ ...this.state, confirmed: true }); return this.view(); });
|
|
1073
|
+
}
|
|
1074
|
+
confirmedSelection() {
|
|
1075
|
+
this.check();
|
|
1076
|
+
if (!this.state.confirmed || !this.state.selection)
|
|
1077
|
+
throw fail("account_confirmation_required");
|
|
1078
|
+
const s = this.state, selected = s.selection;
|
|
1079
|
+
return Object.freeze({ accountId: selected.accountId, connectorId: selected.connectorId, installationId: s.installationId, deviceId: s.deviceId, kind: s.kind, cpOrigin: s.cpOrigin, approvalMode: selected.approvalMode, isCurrent: () => this.isCurrent() });
|
|
1080
|
+
}
|
|
1081
|
+
owned(installation) {
|
|
1082
|
+
const s = this.confirmedSelection();
|
|
1083
|
+
if (installation.isCurrent() !== true || installation.scope.account !== s.accountId || installation.scope.installation !== s.installationId)
|
|
1084
|
+
throw fail("fenced");
|
|
1085
|
+
}
|
|
1086
|
+
/** Commit the explicit original native attempt BEFORE KEK/provider/keys/native.
|
|
1087
|
+
* Once attempted, even missing/partial stores require EXISTING restore or visible
|
|
1088
|
+
* recovery; never infer fresh from a null key/Noise record. */
|
|
1089
|
+
prepareOriginalDevice(installation) {
|
|
1090
|
+
const callback = installation.isCurrent;
|
|
1091
|
+
const current = () => { try {
|
|
1092
|
+
this.check();
|
|
1093
|
+
this.owned(installation);
|
|
1094
|
+
return installation.isCurrent === callback;
|
|
1095
|
+
}
|
|
1096
|
+
catch {
|
|
1097
|
+
return false;
|
|
1098
|
+
} };
|
|
1099
|
+
return this.exclusive(async () => {
|
|
1100
|
+
if (!current())
|
|
1101
|
+
throw fail("fenced");
|
|
1102
|
+
const mode = this.state.nativeStarted ? "existing" : "fresh";
|
|
1103
|
+
if (!this.state.nativeStarted)
|
|
1104
|
+
await this.save({ ...this.state, nativeStarted: true });
|
|
1105
|
+
if (!current())
|
|
1106
|
+
throw fail("fenced");
|
|
1107
|
+
return Object.freeze({ mode, pin: Object.freeze({ ...this.confirmedSelection(), isCurrent: current, installationOwned: current }) });
|
|
1108
|
+
});
|
|
1109
|
+
}
|
|
1110
|
+
/** Fixed native cp-enrol transcript only. Original protected keys/native owner
|
|
1111
|
+
* already opened under actual account-install ownership; no generic signer. */
|
|
1112
|
+
attest(options) {
|
|
1113
|
+
const { runtime, custody, persistence, installation } = options;
|
|
1114
|
+
const callback = installation.isCurrent;
|
|
1115
|
+
const check = () => { this.check(); this.owned(installation); if (installation.isCurrent !== callback || !runtime.deviceCustodyCurrent(this.confirmedSelection(), custody))
|
|
1116
|
+
throw fail("fenced"); };
|
|
1117
|
+
return this.exclusive(async () => {
|
|
1118
|
+
check();
|
|
1119
|
+
if (!this.state.nativeStarted)
|
|
1120
|
+
throw fail("recovery_required");
|
|
1121
|
+
if (this.state.token)
|
|
1122
|
+
return this.view();
|
|
1123
|
+
if (!this.state.proof) {
|
|
1124
|
+
await persistence.pending(new Uint8Array(custody.envelope), { signal: this.lifetime.signal });
|
|
1125
|
+
check();
|
|
1126
|
+
const challenge = Uint8Array.from(this.state.selection.challenge.match(/../g), v => parseInt(v, 16));
|
|
1127
|
+
let signature = null;
|
|
1128
|
+
try {
|
|
1129
|
+
const proof = runtime.signCpEnrol(challenge);
|
|
1130
|
+
signature = proof.signature;
|
|
1131
|
+
check();
|
|
1132
|
+
await this.save({ ...this.state, proof: AppProtectedInstallationSignIn.proof({ sign_pk: hex(proof.signPublicKey), kem_pk: hex(proof.kemPublicKey), noise_pk: hex(proof.noisePublicKey), sig: hex(signature) }) });
|
|
1133
|
+
check();
|
|
1134
|
+
}
|
|
1135
|
+
finally {
|
|
1136
|
+
challenge.fill(0);
|
|
1137
|
+
signature?.fill(0);
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
const p = this.state.proof;
|
|
1141
|
+
if (p.sign_pk !== hex(custody.signPublicKey) || p.kem_pk !== hex(custody.kemPublicKey) || p.noise_pk !== hex(custody.noisePublicKey))
|
|
1142
|
+
throw fail("binding");
|
|
1143
|
+
const { status, value } = await this.json(`/v1/pairing-requests/${this.state.requestId}/attest`, true, p);
|
|
1144
|
+
check();
|
|
1145
|
+
object(value, "ok");
|
|
1146
|
+
if (status !== 200 || value.ok !== true)
|
|
1147
|
+
throw fail("response");
|
|
1148
|
+
return this.view();
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1151
|
+
receipt() {
|
|
1152
|
+
const s = this.state, p = s.proof;
|
|
1153
|
+
this.check();
|
|
1154
|
+
if (!s.token || !p || !s.selection)
|
|
1155
|
+
throw fail("binding");
|
|
1156
|
+
const bytes = (v) => Uint8Array.from(v.match(/../g), x => parseInt(x, 16));
|
|
1157
|
+
return Object.freeze({ connectorId: s.selection.connectorId, deviceId: s.deviceId, installationId: s.installationId, signPublicKey: bytes(p.sign_pk), kemPublicKey: bytes(p.kem_pk), noisePublicKey: bytes(p.noise_pk) });
|
|
1158
|
+
}
|
|
1159
|
+
/** Protect receipt in the SAME Noise custody before the SAME native ACK.
|
|
1160
|
+
* Failure preserves the already protected credential for explicit restore. */
|
|
1161
|
+
acknowledge(options) {
|
|
1162
|
+
const { runtime, custody, persistence, installation } = options, callback = installation.isCurrent;
|
|
1163
|
+
const check = () => { this.check(); this.owned(installation); if (installation.isCurrent !== callback || !runtime.deviceCustodyCurrent(this.confirmedSelection(), custody))
|
|
1164
|
+
throw fail("fenced"); };
|
|
1165
|
+
return this.exclusive(async () => {
|
|
1166
|
+
check();
|
|
1167
|
+
const r = this.receipt();
|
|
1168
|
+
if (hex(r.signPublicKey) !== hex(custody.signPublicKey) || hex(r.kemPublicKey) !== hex(custody.kemPublicKey) || hex(r.noisePublicKey) !== hex(custody.noisePublicKey))
|
|
1169
|
+
throw fail("binding");
|
|
1170
|
+
await persistence.registered(r, { signal: this.lifetime.signal });
|
|
1171
|
+
check();
|
|
1172
|
+
runtime.acknowledgeDeviceRegistration(r);
|
|
1173
|
+
check();
|
|
1174
|
+
this.nativeAcknowledged = true;
|
|
1175
|
+
return r;
|
|
1176
|
+
});
|
|
1177
|
+
}
|
|
1178
|
+
/** Trusted SAME-host timer composition only. Metadata is not CP authority. */
|
|
1179
|
+
originalTimerChannel(grantId) {
|
|
1180
|
+
this.check();
|
|
1181
|
+
this.receipt();
|
|
1182
|
+
if (!this.state.timerConsent?.approved || !this.state.timerConsent.grants.some(grant => grant.grantId === grantId))
|
|
1183
|
+
throw fail("fenced");
|
|
1184
|
+
const row = this.state.timerChannel;
|
|
1185
|
+
return row?.grantId === grantId ? row : null;
|
|
1186
|
+
}
|
|
1187
|
+
retainTimerChannel(grantId, value) {
|
|
1188
|
+
return this.exclusive(async () => {
|
|
1189
|
+
this.originalTimerChannel(grantId);
|
|
1190
|
+
if (value !== null && timerChannel(value).grantId !== grantId)
|
|
1191
|
+
throw fail("binding");
|
|
1192
|
+
await this.save({ ...this.state, timerChannel: value === null ? undefined : timerChannel(value) });
|
|
1193
|
+
this.originalTimerChannel(grantId);
|
|
1194
|
+
});
|
|
1195
|
+
}
|
|
1196
|
+
/** Scoped first-party CP credential callback, never cookies or log bearer.
|
|
1197
|
+
* This is installation authority, NOT a keyed/readable/Saved proof. */
|
|
1198
|
+
session(logOrigin) {
|
|
1199
|
+
this.receipt();
|
|
1200
|
+
return this.confirmedHostSession(logOrigin, this.state.environment);
|
|
1201
|
+
}
|
|
1202
|
+
/** Internal SAME-owner composition before pairing completes. This conveys only
|
|
1203
|
+
* explicitly confirmed account scope: the bearer callback refuses until the
|
|
1204
|
+
* exact protected credential exists. No pending scope becomes CP authority. */
|
|
1205
|
+
confirmedHostSession(logOrigin, environment) {
|
|
1206
|
+
const selected = this.confirmedSelection();
|
|
1207
|
+
if (environment !== this.state.environment)
|
|
1208
|
+
throw fail("binding");
|
|
1209
|
+
const u = new URL(logOrigin);
|
|
1210
|
+
if (u.origin !== logOrigin || (u.protocol !== "https:" && !(LOCAL_APPLICATION_BUILD && localApplicationHttpOrigin(logOrigin))) || u.username || u.password)
|
|
1211
|
+
throw fail("binding");
|
|
1212
|
+
return Object.freeze({ ...selected, logOrigin, timerConsent: () => { this.check(); return this.state.timerConsent ?? null; }, connectorBearer: async ({ signal }) => { this.check(); if (signal.aborted || !this.state.token)
|
|
1213
|
+
throw fail("fenced"); return this.state.token; } });
|
|
1214
|
+
}
|
|
1215
|
+
async close() {
|
|
1216
|
+
if (!this.closed) {
|
|
1217
|
+
this.closed = true;
|
|
1218
|
+
this.lifetime.abort();
|
|
1219
|
+
this.parent.removeEventListener("abort", this.onAbort);
|
|
1220
|
+
this.state.secret = "";
|
|
1221
|
+
this.state.token = null;
|
|
1222
|
+
if (this.state.consentRequest)
|
|
1223
|
+
this.state.consentRequest.secret = "";
|
|
1224
|
+
if (this.state.renewal)
|
|
1225
|
+
this.state.renewal.secret = "";
|
|
1226
|
+
this.state.renewal = null;
|
|
1227
|
+
}
|
|
1228
|
+
await this.store.close();
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
//# sourceMappingURL=installation-sign-in.js.map
|