@superbee/core 0.2.0-pre.4 → 0.2.0-pre.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1255 -0
- package/dist/artifact-contract.d.ts +90 -0
- package/dist/artifact-contract.d.ts.map +1 -0
- package/dist/artifact-contract.js +205 -0
- package/dist/artifact-contract.js.map +1 -0
- package/dist/backend.d.ts +22 -2
- package/dist/backend.d.ts.map +1 -1
- package/dist/backend.js +153 -38
- package/dist/backend.js.map +1 -1
- package/dist/blob-contract.d.ts +82 -0
- package/dist/blob-contract.d.ts.map +1 -0
- package/dist/blob-contract.js +134 -0
- package/dist/blob-contract.js.map +1 -0
- package/dist/blob-journal.d.ts +303 -0
- package/dist/blob-journal.d.ts.map +1 -0
- package/dist/blob-journal.js +541 -0
- package/dist/blob-journal.js.map +1 -0
- package/dist/body-replace-guards.d.ts +52 -0
- package/dist/body-replace-guards.d.ts.map +1 -0
- package/dist/body-replace-guards.js +176 -0
- package/dist/body-replace-guards.js.map +1 -0
- package/dist/builtin-recipes/content.d.ts +93 -0
- package/dist/builtin-recipes/content.d.ts.map +1 -0
- package/dist/builtin-recipes/content.js +288 -0
- package/dist/builtin-recipes/content.js.map +1 -0
- package/dist/builtin-recipes.d.ts +10 -0
- package/dist/builtin-recipes.d.ts.map +1 -0
- package/dist/builtin-recipes.js +97 -0
- package/dist/builtin-recipes.js.map +1 -0
- package/dist/bundle-health/index.d.ts +14 -0
- package/dist/bundle-health/index.d.ts.map +1 -0
- package/dist/bundle-health/index.js +12 -0
- package/dist/bundle-health/index.js.map +1 -0
- package/dist/bundle-health/kind-findings.d.ts +44 -0
- package/dist/bundle-health/kind-findings.d.ts.map +1 -0
- package/dist/bundle-health/kind-findings.js +68 -0
- package/dist/bundle-health/kind-findings.js.map +1 -0
- package/dist/bundle-health/legacy-page.d.ts +39 -0
- package/dist/bundle-health/legacy-page.d.ts.map +1 -0
- package/dist/bundle-health/legacy-page.js +50 -0
- package/dist/bundle-health/legacy-page.js.map +1 -0
- package/dist/bundle-health/report.d.ts +207 -0
- package/dist/bundle-health/report.d.ts.map +1 -0
- package/dist/bundle-health/report.js +454 -0
- package/dist/bundle-health/report.js.map +1 -0
- package/dist/bundle-ops.d.ts +3 -2
- package/dist/bundle-ops.d.ts.map +1 -1
- package/dist/bundle-ops.js +4 -4
- package/dist/bundle-ops.js.map +1 -1
- package/dist/bundle.d.ts +3 -4
- package/dist/bundle.d.ts.map +1 -1
- package/dist/bundle.js +5 -14
- package/dist/bundle.js.map +1 -1
- package/dist/code-point-order.d.ts +8 -0
- package/dist/code-point-order.d.ts.map +1 -0
- package/dist/code-point-order.js +20 -0
- package/dist/code-point-order.js.map +1 -0
- package/dist/code-unit-order.d.ts +15 -0
- package/dist/code-unit-order.d.ts.map +1 -0
- package/dist/code-unit-order.js +17 -0
- package/dist/code-unit-order.js.map +1 -0
- package/dist/connector-request.d.ts +112 -0
- package/dist/connector-request.d.ts.map +1 -0
- package/dist/connector-request.js +495 -0
- package/dist/connector-request.js.map +1 -0
- package/dist/connectors.d.ts +297 -0
- package/dist/connectors.d.ts.map +1 -0
- package/dist/connectors.js +1233 -0
- package/dist/connectors.js.map +1 -0
- package/dist/cross-bundle.d.ts +135 -0
- package/dist/cross-bundle.d.ts.map +1 -0
- package/dist/cross-bundle.js +191 -0
- package/dist/cross-bundle.js.map +1 -0
- package/dist/dependencies.d.ts +94 -0
- package/dist/dependencies.d.ts.map +1 -0
- package/dist/dependencies.js +180 -0
- package/dist/dependencies.js.map +1 -0
- package/dist/document-codec.d.ts +7 -2
- package/dist/document-codec.d.ts.map +1 -1
- package/dist/document-codec.js +8 -5
- package/dist/document-codec.js.map +1 -1
- package/dist/document-field-actions.d.ts +31 -1
- package/dist/document-field-actions.d.ts.map +1 -1
- package/dist/document-field-actions.js +137 -34
- package/dist/document-field-actions.js.map +1 -1
- package/dist/document-mutation.d.ts +37 -13
- package/dist/document-mutation.d.ts.map +1 -1
- package/dist/document-mutation.js +129 -60
- package/dist/document-mutation.js.map +1 -1
- package/dist/document-transfer.d.ts +208 -0
- package/dist/document-transfer.d.ts.map +1 -0
- package/dist/document-transfer.js +928 -0
- package/dist/document-transfer.js.map +1 -0
- package/dist/document-write-policy.d.ts.map +1 -1
- package/dist/document-write-policy.js +4 -2
- package/dist/document-write-policy.js.map +1 -1
- package/dist/domain-model.d.ts +73 -0
- package/dist/domain-model.d.ts.map +1 -0
- package/dist/domain-model.js +169 -0
- package/dist/domain-model.js.map +1 -0
- package/dist/engine.d.ts +21 -9
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +72 -14
- package/dist/engine.js.map +1 -1
- package/dist/file-journaled-backend-internal.d.ts +21 -0
- package/dist/file-journaled-backend-internal.d.ts.map +1 -0
- package/dist/file-journaled-backend-internal.js +12 -0
- package/dist/file-journaled-backend-internal.js.map +1 -0
- package/dist/file-journaled-backend.d.ts +160 -0
- package/dist/file-journaled-backend.d.ts.map +1 -0
- package/dist/file-journaled-backend.js +1345 -0
- package/dist/file-journaled-backend.js.map +1 -0
- package/dist/filesystem-host.d.ts +15 -0
- package/dist/filesystem-host.d.ts.map +1 -0
- package/dist/filesystem-host.js +20 -0
- package/dist/filesystem-host.js.map +1 -0
- package/dist/filesystem-identity.d.ts +97 -21
- package/dist/filesystem-identity.d.ts.map +1 -1
- package/dist/filesystem-identity.js +398 -119
- package/dist/filesystem-identity.js.map +1 -1
- package/dist/filesystem-lock.d.ts +16 -3
- package/dist/filesystem-lock.d.ts.map +1 -1
- package/dist/filesystem-lock.js +323 -77
- package/dist/filesystem-lock.js.map +1 -1
- package/dist/filesystem-push-role.d.ts +77 -0
- package/dist/filesystem-push-role.d.ts.map +1 -0
- package/dist/filesystem-push-role.js +165 -0
- package/dist/filesystem-push-role.js.map +1 -0
- package/dist/filesystem.d.ts +17 -0
- package/dist/filesystem.d.ts.map +1 -0
- package/dist/filesystem.js +18 -0
- package/dist/filesystem.js.map +1 -0
- package/dist/frontmatter.d.ts +8 -6
- package/dist/frontmatter.d.ts.map +1 -1
- package/dist/frontmatter.js +5 -4
- package/dist/frontmatter.js.map +1 -1
- package/dist/governed-body-write.d.ts +8 -1
- package/dist/governed-body-write.d.ts.map +1 -1
- package/dist/governed-body-write.js +9 -2
- package/dist/governed-body-write.js.map +1 -1
- package/dist/heads-digest.d.ts.map +1 -1
- package/dist/heads-digest.js +2 -1
- package/dist/heads-digest.js.map +1 -1
- package/dist/host-policy-snapshot.d.ts +9 -0
- package/dist/host-policy-snapshot.d.ts.map +1 -0
- package/dist/host-policy-snapshot.js +33 -0
- package/dist/host-policy-snapshot.js.map +1 -0
- package/dist/host-text.d.ts +31 -0
- package/dist/host-text.d.ts.map +1 -0
- package/dist/host-text.js +77 -0
- package/dist/host-text.js.map +1 -0
- package/dist/hosted-client/binding.d.ts +7 -0
- package/dist/hosted-client/binding.d.ts.map +1 -0
- package/dist/hosted-client/binding.js +10 -0
- package/dist/hosted-client/binding.js.map +1 -0
- package/dist/hosted-client/blob-delivery.d.ts +68 -0
- package/dist/hosted-client/blob-delivery.d.ts.map +1 -0
- package/dist/hosted-client/blob-delivery.js +170 -0
- package/dist/hosted-client/blob-delivery.js.map +1 -0
- package/dist/hosted-client/blob-write.d.ts +387 -0
- package/dist/hosted-client/blob-write.d.ts.map +1 -0
- package/dist/hosted-client/blob-write.js +770 -0
- package/dist/hosted-client/blob-write.js.map +1 -0
- package/dist/hosted-client/bundle-listing.d.ts +46 -0
- package/dist/hosted-client/bundle-listing.d.ts.map +1 -0
- package/dist/hosted-client/bundle-listing.js +36 -0
- package/dist/hosted-client/bundle-listing.js.map +1 -0
- package/dist/hosted-client/client.d.ts +219 -0
- package/dist/hosted-client/client.d.ts.map +1 -0
- package/dist/hosted-client/client.js +309 -0
- package/dist/hosted-client/client.js.map +1 -0
- package/dist/hosted-client/directory.d.ts +46 -0
- package/dist/hosted-client/directory.d.ts.map +1 -0
- package/dist/hosted-client/directory.js +74 -0
- package/dist/hosted-client/directory.js.map +1 -0
- package/dist/hosted-client/errors.d.ts +26 -0
- package/dist/hosted-client/errors.d.ts.map +1 -0
- package/dist/hosted-client/errors.js +35 -0
- package/dist/hosted-client/errors.js.map +1 -0
- package/dist/hosted-client/inbox.d.ts +320 -0
- package/dist/hosted-client/inbox.d.ts.map +1 -0
- package/dist/hosted-client/inbox.js +379 -0
- package/dist/hosted-client/inbox.js.map +1 -0
- package/dist/hosted-client/index.d.ts +30 -0
- package/dist/hosted-client/index.d.ts.map +1 -0
- package/dist/hosted-client/index.js +32 -0
- package/dist/hosted-client/index.js.map +1 -0
- package/dist/hosted-client/journal.d.ts +103 -0
- package/dist/hosted-client/journal.d.ts.map +1 -0
- package/dist/hosted-client/journal.js +464 -0
- package/dist/hosted-client/journal.js.map +1 -0
- package/dist/hosted-client/node.d.ts +74 -0
- package/dist/hosted-client/node.d.ts.map +1 -0
- package/dist/hosted-client/node.js +219 -0
- package/dist/hosted-client/node.js.map +1 -0
- package/dist/hosted-client/reference.d.ts +12 -0
- package/dist/hosted-client/reference.d.ts.map +1 -0
- package/dist/hosted-client/reference.js +29 -0
- package/dist/hosted-client/reference.js.map +1 -0
- package/dist/hosted-client/write.d.ts +217 -0
- package/dist/hosted-client/write.d.ts.map +1 -0
- package/dist/hosted-client/write.js +418 -0
- package/dist/hosted-client/write.js.map +1 -0
- package/dist/hosted-transport/answer-rows.d.ts +243 -0
- package/dist/hosted-transport/answer-rows.d.ts.map +1 -0
- package/dist/hosted-transport/answer-rows.js +457 -0
- package/dist/hosted-transport/answer-rows.js.map +1 -0
- package/dist/hosted-transport/blob-reads.d.ts +35 -0
- package/dist/hosted-transport/blob-reads.d.ts.map +1 -0
- package/dist/hosted-transport/blob-reads.js +179 -0
- package/dist/hosted-transport/blob-reads.js.map +1 -0
- package/dist/hosted-transport/blob-write.d.ts +34 -0
- package/dist/hosted-transport/blob-write.d.ts.map +1 -0
- package/dist/hosted-transport/blob-write.js +115 -0
- package/dist/hosted-transport/blob-write.js.map +1 -0
- package/dist/hosted-transport/carrier.d.ts +151 -0
- package/dist/hosted-transport/carrier.d.ts.map +1 -0
- package/dist/hosted-transport/carrier.js +260 -0
- package/dist/hosted-transport/carrier.js.map +1 -0
- package/dist/hosted-transport/document-backend.d.ts +74 -0
- package/dist/hosted-transport/document-backend.d.ts.map +1 -0
- package/dist/hosted-transport/document-backend.js +160 -0
- package/dist/hosted-transport/document-backend.js.map +1 -0
- package/dist/hosted-transport/history-pages.d.ts +55 -0
- package/dist/hosted-transport/history-pages.d.ts.map +1 -0
- package/dist/hosted-transport/history-pages.js +69 -0
- package/dist/hosted-transport/history-pages.js.map +1 -0
- package/dist/hosted-transport/index.d.ts +19 -0
- package/dist/hosted-transport/index.d.ts.map +1 -0
- package/dist/hosted-transport/index.js +19 -0
- package/dist/hosted-transport/index.js.map +1 -0
- package/dist/hosted-transport/operations.d.ts +85 -0
- package/dist/hosted-transport/operations.d.ts.map +1 -0
- package/dist/hosted-transport/operations.js +128 -0
- package/dist/hosted-transport/operations.js.map +1 -0
- package/dist/hosted-transport/paged-reads.d.ts +87 -0
- package/dist/hosted-transport/paged-reads.d.ts.map +1 -0
- package/dist/hosted-transport/paged-reads.js +238 -0
- package/dist/hosted-transport/paged-reads.js.map +1 -0
- package/dist/hosted-transport/read-adapter.d.ts +256 -0
- package/dist/hosted-transport/read-adapter.d.ts.map +1 -0
- package/dist/hosted-transport/read-adapter.js +568 -0
- package/dist/hosted-transport/read-adapter.js.map +1 -0
- package/dist/hosted-transport/root-write.d.ts +114 -0
- package/dist/hosted-transport/root-write.d.ts.map +1 -0
- package/dist/hosted-transport/root-write.js +171 -0
- package/dist/hosted-transport/root-write.js.map +1 -0
- package/dist/hosted-transport/whole-document-transport.d.ts +204 -0
- package/dist/hosted-transport/whole-document-transport.d.ts.map +1 -0
- package/dist/hosted-transport/whole-document-transport.js +447 -0
- package/dist/hosted-transport/whole-document-transport.js.map +1 -0
- package/dist/identity-fold.d.ts +18 -0
- package/dist/identity-fold.d.ts.map +1 -0
- package/dist/identity-fold.js +22 -0
- package/dist/identity-fold.js.map +1 -0
- package/dist/index.d.ts +41 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +31 -9
- package/dist/index.js.map +1 -1
- package/dist/indexeddb-backend.d.ts +25 -33
- package/dist/indexeddb-backend.d.ts.map +1 -1
- package/dist/indexeddb-backend.js +264 -8
- package/dist/indexeddb-backend.js.map +1 -1
- package/dist/inventory-guard.d.ts +58 -0
- package/dist/inventory-guard.d.ts.map +1 -0
- package/dist/inventory-guard.js +169 -0
- package/dist/inventory-guard.js.map +1 -0
- package/dist/journaled-backend.d.ts +149 -9
- package/dist/journaled-backend.d.ts.map +1 -1
- package/dist/journaled-backend.js +64 -58
- package/dist/journaled-backend.js.map +1 -1
- package/dist/kind-authoring.d.ts +170 -0
- package/dist/kind-authoring.d.ts.map +1 -0
- package/dist/kind-authoring.js +452 -0
- package/dist/kind-authoring.js.map +1 -0
- package/dist/kind-changes.d.ts +45 -0
- package/dist/kind-changes.d.ts.map +1 -0
- package/dist/kind-changes.js +96 -0
- package/dist/kind-changes.js.map +1 -0
- package/dist/kind-conformance-error.d.ts +15 -0
- package/dist/kind-conformance-error.d.ts.map +1 -0
- package/dist/kind-conformance-error.js +20 -0
- package/dist/kind-conformance-error.js.map +1 -0
- package/dist/kind-coverage.d.ts +99 -0
- package/dist/kind-coverage.d.ts.map +1 -0
- package/dist/kind-coverage.js +186 -0
- package/dist/kind-coverage.js.map +1 -0
- package/dist/kind-deprecation.d.ts +32 -0
- package/dist/kind-deprecation.d.ts.map +1 -0
- package/dist/kind-deprecation.js +141 -0
- package/dist/kind-deprecation.js.map +1 -0
- package/dist/kind-field-mutation.d.ts +4 -0
- package/dist/kind-field-mutation.d.ts.map +1 -1
- package/dist/kind-field-mutation.js +28 -3
- package/dist/kind-field-mutation.js.map +1 -1
- package/dist/kinds-load.js +4 -4
- package/dist/kinds-load.js.map +1 -1
- package/dist/kinds.d.ts +111 -2
- package/dist/kinds.d.ts.map +1 -1
- package/dist/kinds.js +386 -20
- package/dist/kinds.js.map +1 -1
- package/dist/link-emit.d.ts +29 -0
- package/dist/link-emit.d.ts.map +1 -0
- package/dist/link-emit.js +39 -0
- package/dist/link-emit.js.map +1 -0
- package/dist/link-types.d.ts +27 -0
- package/dist/link-types.d.ts.map +1 -0
- package/dist/link-types.js +60 -0
- package/dist/link-types.js.map +1 -0
- package/dist/links.d.ts +52 -3
- package/dist/links.d.ts.map +1 -1
- package/dist/links.js +259 -18
- package/dist/links.js.map +1 -1
- package/dist/managed-document-metadata.d.ts +2 -0
- package/dist/managed-document-metadata.d.ts.map +1 -0
- package/dist/managed-document-metadata.js +9 -0
- package/dist/managed-document-metadata.js.map +1 -0
- package/dist/memory-backend.d.ts +3 -0
- package/dist/memory-backend.d.ts.map +1 -1
- package/dist/memory-backend.js +44 -2
- package/dist/memory-backend.js.map +1 -1
- package/dist/okf-actor.d.ts +1 -0
- package/dist/okf-actor.d.ts.map +1 -1
- package/dist/okf-actor.js +1 -0
- package/dist/okf-actor.js.map +1 -1
- package/dist/okf-authoring.d.ts +4 -0
- package/dist/okf-authoring.d.ts.map +1 -0
- package/dist/okf-authoring.js +12 -0
- package/dist/okf-authoring.js.map +1 -0
- package/dist/okf-standard-fields.d.ts +3 -0
- package/dist/okf-standard-fields.d.ts.map +1 -1
- package/dist/okf-standard-fields.js +3 -0
- package/dist/okf-standard-fields.js.map +1 -1
- package/dist/path-fold.d.ts +39 -0
- package/dist/path-fold.d.ts.map +1 -0
- package/dist/path-fold.js +41 -0
- package/dist/path-fold.js.map +1 -0
- package/dist/paths.d.ts +18 -0
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +32 -0
- package/dist/paths.js.map +1 -1
- package/dist/platform.d.ts +13 -2
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +16 -0
- package/dist/platform.js.map +1 -1
- package/dist/portable-export.d.ts +119 -0
- package/dist/portable-export.d.ts.map +1 -0
- package/dist/portable-export.js +501 -0
- package/dist/portable-export.js.map +1 -0
- package/dist/publication-filesystem.d.ts +1 -1
- package/dist/publication-filesystem.d.ts.map +1 -1
- package/dist/publication-filesystem.js +1 -1
- package/dist/publication-filesystem.js.map +1 -1
- package/dist/qualified-links.d.ts +67 -0
- package/dist/qualified-links.d.ts.map +1 -0
- package/dist/qualified-links.js +117 -0
- package/dist/qualified-links.js.map +1 -0
- package/dist/query-filter.d.ts +16 -2
- package/dist/query-filter.d.ts.map +1 -1
- package/dist/query-filter.js +40 -1
- package/dist/query-filter.js.map +1 -1
- package/dist/query-order.d.ts +22 -0
- package/dist/query-order.d.ts.map +1 -0
- package/dist/query-order.js +43 -0
- package/dist/query-order.js.map +1 -0
- package/dist/recipe-lifecycle/errors.d.ts +96 -0
- package/dist/recipe-lifecycle/errors.d.ts.map +1 -0
- package/dist/recipe-lifecycle/errors.js +122 -0
- package/dist/recipe-lifecycle/errors.js.map +1 -0
- package/dist/recipe-lifecycle/evolution.d.ts +124 -0
- package/dist/recipe-lifecycle/evolution.d.ts.map +1 -0
- package/dist/recipe-lifecycle/evolution.js +993 -0
- package/dist/recipe-lifecycle/evolution.js.map +1 -0
- package/dist/recipe-lifecycle/index.d.ts +34 -0
- package/dist/recipe-lifecycle/index.d.ts.map +1 -0
- package/dist/recipe-lifecycle/index.js +28 -0
- package/dist/recipe-lifecycle/index.js.map +1 -0
- package/dist/recipe-lifecycle/install.d.ts +155 -0
- package/dist/recipe-lifecycle/install.d.ts.map +1 -0
- package/dist/recipe-lifecycle/install.js +604 -0
- package/dist/recipe-lifecycle/install.js.map +1 -0
- package/dist/recipe-lifecycle/legacy-aliases.d.ts +16 -0
- package/dist/recipe-lifecycle/legacy-aliases.d.ts.map +1 -0
- package/dist/recipe-lifecycle/legacy-aliases.js +51 -0
- package/dist/recipe-lifecycle/legacy-aliases.js.map +1 -0
- package/dist/recipe-lifecycle/retirement-apply.d.ts +59 -0
- package/dist/recipe-lifecycle/retirement-apply.d.ts.map +1 -0
- package/dist/recipe-lifecycle/retirement-apply.js +165 -0
- package/dist/recipe-lifecycle/retirement-apply.js.map +1 -0
- package/dist/recipe-lifecycle/retirement.d.ts +89 -0
- package/dist/recipe-lifecycle/retirement.d.ts.map +1 -0
- package/dist/recipe-lifecycle/retirement.js +347 -0
- package/dist/recipe-lifecycle/retirement.js.map +1 -0
- package/dist/recipe-lifecycle/stamp.d.ts +151 -0
- package/dist/recipe-lifecycle/stamp.d.ts.map +1 -0
- package/dist/recipe-lifecycle/stamp.js +364 -0
- package/dist/recipe-lifecycle/stamp.js.map +1 -0
- package/dist/recipe-set-preflight.d.ts +139 -0
- package/dist/recipe-set-preflight.d.ts.map +1 -0
- package/dist/recipe-set-preflight.js +536 -0
- package/dist/recipe-set-preflight.js.map +1 -0
- package/dist/recipes.d.ts +29 -1
- package/dist/recipes.d.ts.map +1 -1
- package/dist/recipes.js +137 -1
- package/dist/recipes.js.map +1 -1
- package/dist/record-overlay/apply.d.ts +43 -0
- package/dist/record-overlay/apply.d.ts.map +1 -0
- package/dist/record-overlay/apply.js +527 -0
- package/dist/record-overlay/apply.js.map +1 -0
- package/dist/record-overlay/canonical.d.ts +22 -0
- package/dist/record-overlay/canonical.d.ts.map +1 -0
- package/dist/record-overlay/canonical.js +47 -0
- package/dist/record-overlay/canonical.js.map +1 -0
- package/dist/record-overlay/digest.d.ts +4 -0
- package/dist/record-overlay/digest.d.ts.map +1 -0
- package/dist/record-overlay/digest.js +11 -0
- package/dist/record-overlay/digest.js.map +1 -0
- package/dist/record-overlay/errors.d.ts +44 -0
- package/dist/record-overlay/errors.d.ts.map +1 -0
- package/dist/record-overlay/errors.js +55 -0
- package/dist/record-overlay/errors.js.map +1 -0
- package/dist/record-overlay/findings.d.ts +5 -0
- package/dist/record-overlay/findings.d.ts.map +1 -0
- package/dist/record-overlay/findings.js +83 -0
- package/dist/record-overlay/findings.js.map +1 -0
- package/dist/record-overlay/index.d.ts +23 -0
- package/dist/record-overlay/index.d.ts.map +1 -0
- package/dist/record-overlay/index.js +21 -0
- package/dist/record-overlay/index.js.map +1 -0
- package/dist/record-overlay/plan.d.ts +12 -0
- package/dist/record-overlay/plan.d.ts.map +1 -0
- package/dist/record-overlay/plan.js +285 -0
- package/dist/record-overlay/plan.js.map +1 -0
- package/dist/record-overlay/policy.d.ts +74 -0
- package/dist/record-overlay/policy.d.ts.map +1 -0
- package/dist/record-overlay/policy.js +235 -0
- package/dist/record-overlay/policy.js.map +1 -0
- package/dist/record-overlay/redact.d.ts +3 -0
- package/dist/record-overlay/redact.d.ts.map +1 -0
- package/dist/record-overlay/redact.js +27 -0
- package/dist/record-overlay/redact.js.map +1 -0
- package/dist/record-overlay/signal-kind.d.ts +30 -0
- package/dist/record-overlay/signal-kind.d.ts.map +1 -0
- package/dist/record-overlay/signal-kind.js +38 -0
- package/dist/record-overlay/signal-kind.js.map +1 -0
- package/dist/record-overlay/signal-text.d.ts +45 -0
- package/dist/record-overlay/signal-text.d.ts.map +1 -0
- package/dist/record-overlay/signal-text.js +116 -0
- package/dist/record-overlay/signal-text.js.map +1 -0
- package/dist/record-overlay/source-index.d.ts +19 -0
- package/dist/record-overlay/source-index.d.ts.map +1 -0
- package/dist/record-overlay/source-index.js +102 -0
- package/dist/record-overlay/source-index.js.map +1 -0
- package/dist/record-overlay/types.d.ts +291 -0
- package/dist/record-overlay/types.d.ts.map +1 -0
- package/dist/record-overlay/types.js +2 -0
- package/dist/record-overlay/types.js.map +1 -0
- package/dist/remote-backend.d.ts +58 -13
- package/dist/remote-backend.d.ts.map +1 -1
- package/dist/remote-backend.js +156 -36
- package/dist/remote-backend.js.map +1 -1
- package/dist/remote-document-codec.d.ts +2 -1
- package/dist/remote-document-codec.d.ts.map +1 -1
- package/dist/remote-document-codec.js +3 -2
- package/dist/remote-document-codec.js.map +1 -1
- package/dist/remote-error.d.ts +17 -1
- package/dist/remote-error.d.ts.map +1 -1
- package/dist/remote-error.js +32 -2
- package/dist/remote-error.js.map +1 -1
- package/dist/remote-operations.d.ts +0 -40
- package/dist/remote-operations.d.ts.map +1 -1
- package/dist/remote-operations.js +26 -6
- package/dist/remote-operations.js.map +1 -1
- package/dist/remote-parsers.d.ts +1 -1
- package/dist/remote-parsers.js +1 -1
- package/dist/search/backend-source.d.ts +6 -0
- package/dist/search/backend-source.d.ts.map +1 -0
- package/dist/search/backend-source.js +33 -0
- package/dist/search/backend-source.js.map +1 -0
- package/dist/search/contract.d.ts +151 -0
- package/dist/search/contract.d.ts.map +1 -0
- package/dist/search/contract.js +78 -0
- package/dist/search/contract.js.map +1 -0
- package/dist/search/errors.d.ts +30 -0
- package/dist/search/errors.d.ts.map +1 -0
- package/dist/search/errors.js +50 -0
- package/dist/search/errors.js.map +1 -0
- package/dist/search/identity.d.ts +12 -0
- package/dist/search/identity.d.ts.map +1 -0
- package/dist/search/identity.js +90 -0
- package/dist/search/identity.js.map +1 -0
- package/dist/search/index.d.ts +16 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +15 -0
- package/dist/search/index.js.map +1 -0
- package/dist/search/memory-source.d.ts +36 -0
- package/dist/search/memory-source.d.ts.map +1 -0
- package/dist/search/memory-source.js +235 -0
- package/dist/search/memory-source.js.map +1 -0
- package/dist/search/rank.d.ts +34 -0
- package/dist/search/rank.d.ts.map +1 -0
- package/dist/search/rank.js +129 -0
- package/dist/search/rank.js.map +1 -0
- package/dist/search/row-text.d.ts +38 -0
- package/dist/search/row-text.d.ts.map +1 -0
- package/dist/search/row-text.js +88 -0
- package/dist/search/row-text.js.map +1 -0
- package/dist/search/search.d.ts +28 -0
- package/dist/search/search.d.ts.map +1 -0
- package/dist/search/search.js +257 -0
- package/dist/search/search.js.map +1 -0
- package/dist/search/source.d.ts +67 -0
- package/dist/search/source.d.ts.map +1 -0
- package/dist/search/source.js +2 -0
- package/dist/search/source.js.map +1 -0
- package/dist/search/text.d.ts +47 -0
- package/dist/search/text.d.ts.map +1 -0
- package/dist/search/text.js +150 -0
- package/dist/search/text.js.map +1 -0
- package/dist/site-capabilities.d.ts +345 -0
- package/dist/site-capabilities.d.ts.map +1 -0
- package/dist/site-capabilities.js +724 -0
- package/dist/site-capabilities.js.map +1 -0
- package/dist/source-engine/driver.d.ts +42 -0
- package/dist/source-engine/driver.d.ts.map +1 -0
- package/dist/source-engine/driver.js +529 -0
- package/dist/source-engine/driver.js.map +1 -0
- package/dist/source-engine/evidence.d.ts +39 -0
- package/dist/source-engine/evidence.d.ts.map +1 -0
- package/dist/source-engine/evidence.js +54 -0
- package/dist/source-engine/evidence.js.map +1 -0
- package/dist/source-engine/guard.d.ts +87 -0
- package/dist/source-engine/guard.d.ts.map +1 -0
- package/dist/source-engine/guard.js +427 -0
- package/dist/source-engine/guard.js.map +1 -0
- package/dist/source-engine/index.d.ts +35 -0
- package/dist/source-engine/index.d.ts.map +1 -0
- package/dist/source-engine/index.js +27 -0
- package/dist/source-engine/index.js.map +1 -0
- package/dist/source-engine/machine-state.d.ts +87 -0
- package/dist/source-engine/machine-state.d.ts.map +1 -0
- package/dist/source-engine/machine-state.js +94 -0
- package/dist/source-engine/machine-state.js.map +1 -0
- package/dist/source-engine/observe.d.ts +10 -0
- package/dist/source-engine/observe.d.ts.map +1 -0
- package/dist/source-engine/observe.js +276 -0
- package/dist/source-engine/observe.js.map +1 -0
- package/dist/source-engine/overlay.d.ts +50 -0
- package/dist/source-engine/overlay.d.ts.map +1 -0
- package/dist/source-engine/overlay.js +114 -0
- package/dist/source-engine/overlay.js.map +1 -0
- package/dist/source-engine/robots.d.ts +53 -0
- package/dist/source-engine/robots.d.ts.map +1 -0
- package/dist/source-engine/robots.js +158 -0
- package/dist/source-engine/robots.js.map +1 -0
- package/dist/source-engine/snapshot.d.ts +104 -0
- package/dist/source-engine/snapshot.d.ts.map +1 -0
- package/dist/source-engine/snapshot.js +240 -0
- package/dist/source-engine/snapshot.js.map +1 -0
- package/dist/source-engine/target-consumer.d.ts +12 -0
- package/dist/source-engine/target-consumer.d.ts.map +1 -0
- package/dist/source-engine/target-consumer.js +15 -0
- package/dist/source-engine/target-consumer.js.map +1 -0
- package/dist/source-engine/target-descriptor.d.ts +3 -0
- package/dist/source-engine/target-descriptor.d.ts.map +1 -0
- package/dist/source-engine/target-descriptor.js +26 -0
- package/dist/source-engine/target-descriptor.js.map +1 -0
- package/dist/source-engine/target.d.ts +82 -0
- package/dist/source-engine/target.d.ts.map +1 -0
- package/dist/source-engine/target.js +213 -0
- package/dist/source-engine/target.js.map +1 -0
- package/dist/source-engine/types.d.ts +296 -0
- package/dist/source-engine/types.d.ts.map +1 -0
- package/dist/source-engine/types.js +2 -0
- package/dist/source-engine/types.js.map +1 -0
- package/dist/source-harness/conformance.d.ts +16 -0
- package/dist/source-harness/conformance.d.ts.map +1 -0
- package/dist/source-harness/conformance.js +266 -0
- package/dist/source-harness/conformance.js.map +1 -0
- package/dist/source-harness/fixture.d.ts +97 -0
- package/dist/source-harness/fixture.d.ts.map +1 -0
- package/dist/source-harness/fixture.js +276 -0
- package/dist/source-harness/fixture.js.map +1 -0
- package/dist/source-harness/index.d.ts +22 -0
- package/dist/source-harness/index.d.ts.map +1 -0
- package/dist/source-harness/index.js +19 -0
- package/dist/source-harness/index.js.map +1 -0
- package/dist/source-harness/peer.d.ts +74 -0
- package/dist/source-harness/peer.d.ts.map +1 -0
- package/dist/source-harness/peer.js +106 -0
- package/dist/source-harness/peer.js.map +1 -0
- package/dist/source-profiles/index.d.ts +31 -0
- package/dist/source-profiles/index.d.ts.map +1 -0
- package/dist/source-profiles/index.js +206 -0
- package/dist/source-profiles/index.js.map +1 -0
- package/dist/source-profiles/link-header.d.ts +6 -0
- package/dist/source-profiles/link-header.d.ts.map +1 -0
- package/dist/source-profiles/link-header.js +131 -0
- package/dist/source-profiles/link-header.js.map +1 -0
- package/dist/storage.d.ts +9 -2
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +6 -1
- package/dist/storage.js.map +1 -1
- package/dist/string-identity-agreement.d.ts +35 -0
- package/dist/string-identity-agreement.d.ts.map +1 -0
- package/dist/string-identity-agreement.js +72 -0
- package/dist/string-identity-agreement.js.map +1 -0
- package/dist/types.d.ts +41 -6
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +0 -10
- package/dist/types.js.map +1 -1
- package/dist/uncertain-write.d.ts +157 -17
- package/dist/uncertain-write.d.ts.map +1 -1
- package/dist/uncertain-write.js +86 -30
- package/dist/uncertain-write.js.map +1 -1
- package/dist/versioning.d.ts +9 -4
- package/dist/versioning.d.ts.map +1 -1
- package/dist/versioning.js +9 -4
- package/dist/versioning.js.map +1 -1
- package/dist/view-launch-contract.d.ts +14 -0
- package/dist/view-launch-contract.d.ts.map +1 -0
- package/dist/view-launch-contract.js +23 -0
- package/dist/view-launch-contract.js.map +1 -0
- package/dist/write-identity.d.ts +5 -0
- package/dist/write-identity.d.ts.map +1 -0
- package/dist/write-identity.js +9 -0
- package/dist/write-identity.js.map +1 -0
- package/package.json +140 -3
|
@@ -15,6 +15,15 @@
|
|
|
15
15
|
* entirely between two probes of one observation can be traversed by the operating system
|
|
16
16
|
* during a listing or open, but its bytes can never be returned as EXACT, because the leaf
|
|
17
17
|
* witness at the post-walk must match the entry the requested path reaches.
|
|
18
|
+
* - A bulk read runs its observations inside one {@link ObservationPass}: the same protocol per
|
|
19
|
+
* path, but a directory's listing is taken once and reused while the directory's change
|
|
20
|
+
* witness proves its entry set unchanged, and every EXACT verdict that used a reused listing has
|
|
21
|
+
* its post-walk repeated at the end of the pass without trusting timestamps. Listing the parent
|
|
22
|
+
* per observation would make a pass over a directory of N documents read O(N²) directory
|
|
23
|
+
* entries. The speedup assumes local disks, whose directory times advance on every entry change;
|
|
24
|
+
* on Linux any other filesystem type lists per use, and elsewhere a mount whose times can lie
|
|
25
|
+
* (network or FUSE attribute caches, settable Windows directory times) is covered by the
|
|
26
|
+
* end-of-pass re-verification, short of an inode number reused within the pass.
|
|
18
27
|
* - Mutations hold one cross-process lock keyed by a pure fold of the root and `rel`, decide
|
|
19
28
|
* inside it, create directories one segment at a time with a spelling check, and publish a
|
|
20
29
|
* first-created leaf with `link` so the host's own equivalence refuses a second spelling the
|
|
@@ -37,8 +46,8 @@
|
|
|
37
46
|
* and the root's spelling is folded into the lock key rather than verified.
|
|
38
47
|
*
|
|
39
48
|
* Every filesystem call goes through a {@link FilesystemIdentityPort} passed to the protocol
|
|
40
|
-
* functions. Production
|
|
41
|
-
*
|
|
49
|
+
* functions. Production constructs a Node binding with the backend's captured host policy;
|
|
50
|
+
* the policy supplies classifications, never a replacement identity protocol. Normalizing stores that rewrite names on
|
|
42
51
|
* write (legacy HFS+) are unsupported: an id whose NFD form differs from its own form is written
|
|
43
52
|
* and then refused as an alias on every later observation, never silently aliased.
|
|
44
53
|
*/
|
|
@@ -46,13 +55,15 @@ import { promises as fs } from "node:fs";
|
|
|
46
55
|
import path from "node:path";
|
|
47
56
|
import { createHash, randomUUID } from "node:crypto";
|
|
48
57
|
import { ConcurrentReplacementError, FilesystemIdentityAliasError, InvalidInputError } from "./errors.js";
|
|
49
|
-
import { acquireFilesystemIdentityLock } from "./filesystem-lock.js";
|
|
50
|
-
|
|
58
|
+
import { acquireFilesystemIdentityLock, filesystemMutationLockRoot } from "./filesystem-lock.js";
|
|
59
|
+
import { captureFilesystemHostPolicy } from "./filesystem-host.js";
|
|
60
|
+
import { foldSegment } from "./identity-fold.js";
|
|
61
|
+
export { foldSegment };
|
|
51
62
|
/**
|
|
52
|
-
*
|
|
63
|
+
* A host can transiently deny replacement while another process is closing a read handle or a
|
|
53
64
|
* scanner holds the destination. An in-place rename retry cannot remain bound to the complete
|
|
54
65
|
* parent-and-leaf observation: either can change after any final check. Abort this attempt instead,
|
|
55
|
-
* mapping only
|
|
66
|
+
* mapping only a host-classified replacement conflict to the typed
|
|
56
67
|
* contention signal owned by the higher-level fresh read/decide/CAS loop. Every other platform and
|
|
57
68
|
* errno remains the original immediate failure.
|
|
58
69
|
*/
|
|
@@ -61,8 +72,7 @@ async function replaceExistingLeaf(port, tmp, target, rel) {
|
|
|
61
72
|
await port.rename(tmp, target);
|
|
62
73
|
}
|
|
63
74
|
catch (err) {
|
|
64
|
-
|
|
65
|
-
if ((port.platform ?? process.platform) === "win32" && WINDOWS_REPLACE_CONFLICT_CODES.has(code)) {
|
|
75
|
+
if (port.isReplacementConflict?.(err)) {
|
|
66
76
|
throw new ConcurrentReplacementError(rel, 1, 10);
|
|
67
77
|
}
|
|
68
78
|
throw err;
|
|
@@ -117,18 +127,6 @@ function relSegments(rel) {
|
|
|
117
127
|
return segments;
|
|
118
128
|
}
|
|
119
129
|
// ── identity key ──────────────────────────────────────────────────────────────
|
|
120
|
-
/**
|
|
121
|
-
* NFKD, then Unicode FULL case folding applied as lower-upper-lower (locale-independent). A plain
|
|
122
|
-
* lower-case fold misses the pairs a case-insensitive host equates through full case mapping
|
|
123
|
-
* (ß/ss, ẞ/SS, final sigma ς/σ, iota-subscript ᾈ/ἀι and its family): two such spellings would get
|
|
124
|
-
* different keys, both first-creation writers would realize ABSENT, and the second rename would
|
|
125
|
-
* silently replace the first document. The round trip through upper case expands every such
|
|
126
|
-
* pair to a common form, so the fold is a superset of every supported host's equivalence;
|
|
127
|
-
* over-folding (dotless ı with i) only adds serialization, never removes exclusion.
|
|
128
|
-
*/
|
|
129
|
-
export function foldSegment(segment) {
|
|
130
|
-
return segment.normalize("NFKD").toLowerCase().toUpperCase().toLowerCase();
|
|
131
|
-
}
|
|
132
130
|
/** The physical path of the longest existing ancestor of `resolved`, plus the absent remainder. */
|
|
133
131
|
async function existingAnchor(resolved) {
|
|
134
132
|
const tail = [];
|
|
@@ -155,12 +153,65 @@ async function existingAnchor(resolved) {
|
|
|
155
153
|
* and identical for every case or normalization spelling of any segment. It depends on nothing
|
|
156
154
|
* else: not the environment, the clock, the process, or the host name.
|
|
157
155
|
*/
|
|
158
|
-
|
|
159
|
-
const foldedRel = relSegments(rel).map(foldSegment).join("/");
|
|
156
|
+
async function foldedPhysicalRoot(root) {
|
|
160
157
|
const { anchor, tail } = await existingAnchor(path.resolve(root));
|
|
161
158
|
const anchorSegments = anchor.split(path.sep).filter((segment, index) => index === 0 || segment !== "");
|
|
162
|
-
|
|
163
|
-
|
|
159
|
+
return [...anchorSegments, ...tail].map(foldSegment).join("/");
|
|
160
|
+
}
|
|
161
|
+
export async function identityKey(root, rel) {
|
|
162
|
+
const foldedRel = relSegments(rel).map(foldSegment).join("/");
|
|
163
|
+
return createHash("sha256").update(`superbee-identity/v1\0${await foldedPhysicalRoot(root)}\0${foldedRel}`).digest("hex");
|
|
164
|
+
}
|
|
165
|
+
/** Same root key before/after directory creation; physical replacement is a separate witness. */
|
|
166
|
+
export async function filesystemRootMutationKey(root) {
|
|
167
|
+
return createHash("sha256").update(`superbee-root-mutation/v1\0${await foldedPhysicalRoot(root)}`).digest("hex");
|
|
168
|
+
}
|
|
169
|
+
/** Existing physical-root/ancestor witnesses supplement the stable coordination pathname. */
|
|
170
|
+
export async function filesystemRootWitness(port, root) {
|
|
171
|
+
const physical = await fs.realpath(root);
|
|
172
|
+
const witnesses = [];
|
|
173
|
+
let current = physical;
|
|
174
|
+
for (;;) {
|
|
175
|
+
const witness = await port.probe(current);
|
|
176
|
+
if (!witness || witness.kind !== "directory")
|
|
177
|
+
throw new InvalidInputError("Inventory guard root identity is unavailable.");
|
|
178
|
+
witnesses.push([current, witness.dev, witness.ino]);
|
|
179
|
+
const parent = path.dirname(current);
|
|
180
|
+
if (parent === current)
|
|
181
|
+
break;
|
|
182
|
+
current = parent;
|
|
183
|
+
}
|
|
184
|
+
return createHash("sha256").update(JSON.stringify(witnesses)).digest("hex");
|
|
185
|
+
}
|
|
186
|
+
const rootMutationQueues = new Map();
|
|
187
|
+
/** Internal per-backend root coordinator; never re-exported by a public entrypoint. */
|
|
188
|
+
export function createFilesystemMutationCoordinator(_port, root, hostPolicy) {
|
|
189
|
+
const policy = captureFilesystemHostPolicy(hostPolicy);
|
|
190
|
+
let lockRoot;
|
|
191
|
+
const namespace = () => lockRoot ??= filesystemMutationLockRoot(root, policy);
|
|
192
|
+
return Object.freeze({
|
|
193
|
+
namespace,
|
|
194
|
+
async run(body) {
|
|
195
|
+
const key = await filesystemRootMutationKey(root);
|
|
196
|
+
const lockRoot = namespace();
|
|
197
|
+
const queueKey = `${lockRoot}:${key}`;
|
|
198
|
+
const previous = rootMutationQueues.get(queueKey) ?? Promise.resolve();
|
|
199
|
+
const run = previous.then(async () => {
|
|
200
|
+
const release = await acquireFilesystemIdentityLock(key, root, { portableRoot: root, lockRoot, hostPolicy: policy });
|
|
201
|
+
try {
|
|
202
|
+
return await body();
|
|
203
|
+
}
|
|
204
|
+
finally {
|
|
205
|
+
await release();
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
const settled = run.then(() => { }, () => { });
|
|
209
|
+
rootMutationQueues.set(queueKey, settled);
|
|
210
|
+
void settled.then(() => { if (rootMutationQueues.get(queueKey) === settled)
|
|
211
|
+
rootMutationQueues.delete(queueKey); });
|
|
212
|
+
return run;
|
|
213
|
+
},
|
|
214
|
+
});
|
|
164
215
|
}
|
|
165
216
|
// ── pure decisions ────────────────────────────────────────────────────────────
|
|
166
217
|
function sameWitness(a, b) {
|
|
@@ -219,6 +270,13 @@ async function probeSegment(port, candidate, rel, segment) {
|
|
|
219
270
|
function hasExact(listing, segment) {
|
|
220
271
|
return listing.some((entry) => entry.name === segment);
|
|
221
272
|
}
|
|
273
|
+
/** One fresh `entries` call per use: the single-read protocol. */
|
|
274
|
+
function freshListings(port) {
|
|
275
|
+
return async (dir) => {
|
|
276
|
+
const listing = await port.entries(dir);
|
|
277
|
+
return listing === null ? null : { has: (name) => hasExact(listing, name) };
|
|
278
|
+
};
|
|
279
|
+
}
|
|
222
280
|
/**
|
|
223
281
|
* M-REALIZE: per segment, root to leaf, it must exist and the parent listing must carry its exact
|
|
224
282
|
* spelling. A listing-only alias decision is sound here because the identity lock is held: no
|
|
@@ -277,15 +335,15 @@ async function recordWalk(port, rootResolved, segments, rel) {
|
|
|
277
335
|
* (`handle` given) applies that leaf table against the handle's inode, probing the leaf
|
|
278
336
|
* unconditionally.
|
|
279
337
|
*/
|
|
280
|
-
async function confirmedWalk(port, rootResolved, segments, rel, recorded, handle) {
|
|
338
|
+
async function confirmedWalk(port, rootResolved, segments, rel, recorded, handle, listings = freshListings(port)) {
|
|
281
339
|
let parent = rootResolved;
|
|
282
340
|
for (let index = 0; index < segments.length; index++) {
|
|
283
341
|
const segment = segments[index];
|
|
284
342
|
const candidate = path.join(parent, segment);
|
|
285
|
-
const listing = await
|
|
343
|
+
const listing = await listings(parent);
|
|
286
344
|
if (listing === null)
|
|
287
345
|
return "absent";
|
|
288
|
-
const listed =
|
|
346
|
+
const listed = listing.has(segment);
|
|
289
347
|
if (handle !== null && index === segments.length - 1) {
|
|
290
348
|
const verdict = classifyLeaf({ listed, probe: await probeSegment(port, candidate, rel, segment), handle });
|
|
291
349
|
if (verdict === "aliased")
|
|
@@ -316,14 +374,17 @@ function countRestart(restarts, rel) {
|
|
|
316
374
|
* from O-PROBE, bounded; the handle is closed before any restart opens another.
|
|
317
375
|
*/
|
|
318
376
|
export async function observeExact(port, root, rel, read) {
|
|
377
|
+
return observeWith(port, path.resolve(root), rel, read, freshListings(port));
|
|
378
|
+
}
|
|
379
|
+
/** The observation protocol of {@link observeExact}, with the parent listings drawn from `listings`. */
|
|
380
|
+
async function observeWith(port, rootResolved, rel, read, listings, onExact) {
|
|
319
381
|
const segments = relSegments(rel);
|
|
320
|
-
const rootResolved = path.resolve(root);
|
|
321
382
|
const target = path.join(rootResolved, ...segments);
|
|
322
383
|
for (let restarts = 0;;) {
|
|
323
384
|
const recorded = await recordWalk(port, rootResolved, segments, rel);
|
|
324
385
|
if (recorded === null)
|
|
325
386
|
return { state: "absent" };
|
|
326
|
-
const verified = await confirmedWalk(port, rootResolved, segments, rel, recorded, null);
|
|
387
|
+
const verified = await confirmedWalk(port, rootResolved, segments, rel, recorded, null, listings);
|
|
327
388
|
if (verified === "absent")
|
|
328
389
|
return { state: "absent" };
|
|
329
390
|
if (verified === "restart") {
|
|
@@ -337,10 +398,9 @@ export async function observeExact(port, root, rel, read) {
|
|
|
337
398
|
catch (err) {
|
|
338
399
|
if (isAbsentPathError(err))
|
|
339
400
|
return { state: "absent" };
|
|
340
|
-
//
|
|
341
|
-
// an uncertain generation, not a durable permission verdict; re-run the witnessed walk and
|
|
401
|
+
// A host-classified transient open failure reports an uncertain generation; re-run the witnessed walk and
|
|
342
402
|
// let the existing bound turn persistent contention into ConcurrentReplacementError.
|
|
343
|
-
if (
|
|
403
|
+
if (port.isTransientOpenError?.(err)) {
|
|
344
404
|
restarts = countRestart(restarts, rel);
|
|
345
405
|
continue;
|
|
346
406
|
}
|
|
@@ -352,13 +412,15 @@ export async function observeExact(port, root, rel, read) {
|
|
|
352
412
|
value = await read(opened.handle, target);
|
|
353
413
|
if (value === null)
|
|
354
414
|
return { state: "absent" };
|
|
355
|
-
verdict = await confirmedWalk(port, rootResolved, segments, rel, recorded, opened);
|
|
415
|
+
verdict = await confirmedWalk(port, rootResolved, segments, rel, recorded, opened, listings);
|
|
356
416
|
}
|
|
357
417
|
finally {
|
|
358
418
|
await port.close(opened.handle);
|
|
359
419
|
}
|
|
360
|
-
if (verdict === "exact")
|
|
420
|
+
if (verdict === "exact") {
|
|
421
|
+
onExact?.(recorded, { dev: opened.dev, ino: opened.ino });
|
|
361
422
|
return { state: "exact", value };
|
|
423
|
+
}
|
|
362
424
|
if (verdict === "absent")
|
|
363
425
|
return { state: "absent" };
|
|
364
426
|
restarts = countRestart(restarts, rel);
|
|
@@ -385,6 +447,154 @@ export async function probeExact(port, root, rel) {
|
|
|
385
447
|
restarts = countRestart(restarts, rel);
|
|
386
448
|
}
|
|
387
449
|
}
|
|
450
|
+
// ── observation pass ──────────────────────────────────────────────────────────
|
|
451
|
+
/**
|
|
452
|
+
* How long a directory's modification and status-change times must have been still before a
|
|
453
|
+
* listing of it may be reused. A change that lands in the same timestamp tick as the directory's
|
|
454
|
+
* previous change leaves both times unchanged, so a witness is only a change detector once the
|
|
455
|
+
* clock has moved past that tick. Three seconds covers the coarsest supported granularity (FAT's
|
|
456
|
+
* two-second mtime) plus margin; finer clocks (APFS, ext4, NTFS) are covered with room to spare.
|
|
457
|
+
* A time in the future (clock skew) is never settled.
|
|
458
|
+
*/
|
|
459
|
+
const SETTLED_AFTER_NS = 3000000000n;
|
|
460
|
+
function witnessKey(witness) {
|
|
461
|
+
return `${witness.dev}:${witness.ino}:${witness.mtimeNs}:${witness.ctimeNs}`;
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Open an {@link ObservationPass} over `(port, root)`.
|
|
465
|
+
*
|
|
466
|
+
* Every observation runs the exact single-read protocol of {@link observeExact} — recorded walk,
|
|
467
|
+
* confirmed pre-walk, open, read, confirmed post-walk with the handle still open, bounded
|
|
468
|
+
* restarts — and differs only in where a walk's parent listing comes from. The first time a
|
|
469
|
+
* directory is needed the pass takes `witness, entries, witness`; when the two witnesses agree and
|
|
470
|
+
* the directory's times have settled, that listing is kept. Each later use re-takes the witness
|
|
471
|
+
* (one `stat`, constant cost) and reuses the kept listing only if the witness is unchanged;
|
|
472
|
+
* otherwise it lists afresh exactly as a single read would.
|
|
473
|
+
*
|
|
474
|
+
* Two independent arguments make a reused listing safe:
|
|
475
|
+
*
|
|
476
|
+
* 1. Timestamps (the fast path is right in the moment). Where a directory's times advance on every
|
|
477
|
+
* entry change — local APFS, HFS+, ext4, XFS, btrfs, NTFS, FAT — an unchanged settled witness
|
|
478
|
+
* means the entry set is the kept listing at the moment of use, so every verdict is the one a
|
|
479
|
+
* single read reaches against the same state.
|
|
480
|
+
* 2. Re-verification (no timestamps trusted). Where the witness can lie — attribute caches on
|
|
481
|
+
* network and FUSE mounts, settable directory times on Windows, a clock stepped backwards — an
|
|
482
|
+
* observation that used a reused listing may be wrong in the moment, so its verdict is not
|
|
483
|
+
* trusted: a refusal or absence reached through a reused listing is re-taken at once by
|
|
484
|
+
* {@link observeExact}, and `finish` repeats the post-walk of every EXACT verdict that used one
|
|
485
|
+
* against fresh listings (one per directory) and fresh probes. Each segment must still be
|
|
486
|
+
* listed under its exact spelling and reach the inode recorded for it, the leaf the inode the
|
|
487
|
+
* bytes were read from; anything else is returned for a fresh single read. Since published
|
|
488
|
+
* bytes are immutable per inode, a verdict that passes is a state of this identity at `finish`.
|
|
489
|
+
* What this cannot see is the read file being deleted and its inode NUMBER reused by a new file
|
|
490
|
+
* under the same spelling within the pass, because the handle is closed by then.
|
|
491
|
+
*
|
|
492
|
+
* On Linux, a mount whose filesystem type is not a known local one (NFS, SMB, FUSE, 9p, ...) gets
|
|
493
|
+
* no directory witness at all, so it lists exactly as single reads do.
|
|
494
|
+
*/
|
|
495
|
+
export function openObservationPass(port, root, now = Date.now) {
|
|
496
|
+
const rootResolved = path.resolve(root);
|
|
497
|
+
const kept = new Map();
|
|
498
|
+
const reusedVerdicts = [];
|
|
499
|
+
const fresh = freshListings(port);
|
|
500
|
+
const witnessOf = port.directoryWitness?.bind(port);
|
|
501
|
+
const settled = (witness) => {
|
|
502
|
+
const nowNs = BigInt(Math.floor(now())) * 1000000n;
|
|
503
|
+
const latest = witness.mtimeNs > witness.ctimeNs ? witness.mtimeNs : witness.ctimeNs;
|
|
504
|
+
return nowNs - latest >= SETTLED_AFTER_NS;
|
|
505
|
+
};
|
|
506
|
+
/** Listings for one observation; `reused()` says whether any came from the kept set. */
|
|
507
|
+
const listingsFor = () => {
|
|
508
|
+
let reused = false;
|
|
509
|
+
if (witnessOf === undefined)
|
|
510
|
+
return { source: fresh, reused: () => false };
|
|
511
|
+
const source = async (dir) => {
|
|
512
|
+
const keep = kept.get(dir);
|
|
513
|
+
if (keep !== undefined) {
|
|
514
|
+
const current = await witnessOf(dir);
|
|
515
|
+
if (current !== null && witnessKey(current) === keep.witness) {
|
|
516
|
+
reused = true;
|
|
517
|
+
return keep.names;
|
|
518
|
+
}
|
|
519
|
+
kept.delete(dir);
|
|
520
|
+
}
|
|
521
|
+
const before = await witnessOf(dir);
|
|
522
|
+
const listing = await port.entries(dir);
|
|
523
|
+
if (listing === null)
|
|
524
|
+
return null;
|
|
525
|
+
const names = new Set(listing.map((entry) => entry.name));
|
|
526
|
+
const after = await witnessOf(dir);
|
|
527
|
+
if (before !== null && after !== null && witnessKey(before) === witnessKey(after) && settled(after)) {
|
|
528
|
+
kept.set(dir, { witness: witnessKey(after), names });
|
|
529
|
+
}
|
|
530
|
+
return names;
|
|
531
|
+
};
|
|
532
|
+
return { source, reused: () => reused };
|
|
533
|
+
};
|
|
534
|
+
return {
|
|
535
|
+
async observe(rel, read) {
|
|
536
|
+
const listings = listingsFor();
|
|
537
|
+
let exact;
|
|
538
|
+
let observed;
|
|
539
|
+
try {
|
|
540
|
+
observed = await observeWith(port, rootResolved, rel, read, listings.source, (recorded, handle) => {
|
|
541
|
+
exact = { rel, segments: relSegments(rel), recorded, handle };
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
catch (error) {
|
|
545
|
+
if (!listings.reused())
|
|
546
|
+
throw error;
|
|
547
|
+
return observeExact(port, rootResolved, rel, read);
|
|
548
|
+
}
|
|
549
|
+
if (!listings.reused())
|
|
550
|
+
return observed;
|
|
551
|
+
if (observed.state === "absent")
|
|
552
|
+
return observeExact(port, rootResolved, rel, read);
|
|
553
|
+
if (exact !== undefined)
|
|
554
|
+
reusedVerdicts.push(exact);
|
|
555
|
+
return observed;
|
|
556
|
+
},
|
|
557
|
+
async finish() {
|
|
558
|
+
const retry = new Set();
|
|
559
|
+
const endListings = new Map();
|
|
560
|
+
const listedAtEnd = async (dir) => {
|
|
561
|
+
if (!endListings.has(dir)) {
|
|
562
|
+
const listing = await port.entries(dir);
|
|
563
|
+
endListings.set(dir, listing === null ? null : new Set(listing.map((entry) => entry.name)));
|
|
564
|
+
}
|
|
565
|
+
return endListings.get(dir);
|
|
566
|
+
};
|
|
567
|
+
try {
|
|
568
|
+
for (const verdict of reusedVerdicts) {
|
|
569
|
+
if (!(await holdsAtEnd(port, rootResolved, verdict, listedAtEnd)))
|
|
570
|
+
retry.add(verdict.rel);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
finally {
|
|
574
|
+
kept.clear();
|
|
575
|
+
reusedVerdicts.length = 0;
|
|
576
|
+
}
|
|
577
|
+
return [...retry];
|
|
578
|
+
},
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
/** The post-walk of one EXACT verdict, repeated against end-of-pass listings and fresh probes. */
|
|
582
|
+
async function holdsAtEnd(port, rootResolved, verdict, listedAtEnd) {
|
|
583
|
+
let parent = rootResolved;
|
|
584
|
+
for (let index = 0; index < verdict.segments.length; index++) {
|
|
585
|
+
const segment = verdict.segments[index];
|
|
586
|
+
const listing = await listedAtEnd(parent);
|
|
587
|
+
if (listing === null || !listing.has(segment))
|
|
588
|
+
return false;
|
|
589
|
+
const candidate = path.join(parent, segment);
|
|
590
|
+
const probed = await port.probe(candidate);
|
|
591
|
+
const expected = index === verdict.segments.length - 1 ? verdict.handle : verdict.recorded[index];
|
|
592
|
+
if (probed === null || probed.kind === "symlink" || !sameWitness(probed, expected))
|
|
593
|
+
return false;
|
|
594
|
+
parent = candidate;
|
|
595
|
+
}
|
|
596
|
+
return true;
|
|
597
|
+
}
|
|
388
598
|
// ── mutation ──────────────────────────────────────────────────────────────────
|
|
389
599
|
/**
|
|
390
600
|
* Roots (resolved) whose filesystem refused a hard link. Learned lazily on the first creation
|
|
@@ -394,7 +604,15 @@ export async function probeExact(port, root, rel) {
|
|
|
394
604
|
* first-creation writers of a host-equated pair the fold misses are not excluded" applies there
|
|
395
605
|
* and only there.
|
|
396
606
|
*/
|
|
397
|
-
const linkUnsupportedRoots = new
|
|
607
|
+
const linkUnsupportedRoots = new WeakMap();
|
|
608
|
+
function unsupportedLinkRoots(port) {
|
|
609
|
+
let roots = linkUnsupportedRoots.get(port);
|
|
610
|
+
if (!roots) {
|
|
611
|
+
roots = new Set();
|
|
612
|
+
linkUnsupportedRoots.set(port, roots);
|
|
613
|
+
}
|
|
614
|
+
return roots;
|
|
615
|
+
}
|
|
398
616
|
/**
|
|
399
617
|
* Process-local queue per identity key, shared by every `FilesystemBackend` instance: the
|
|
400
618
|
* engine constructs a fresh adapter per bundle operation, so an instance-level map would
|
|
@@ -508,7 +726,7 @@ async function createExactLeaf(port, tmp, target, rel, leaf, rootResolved) {
|
|
|
508
726
|
return;
|
|
509
727
|
}
|
|
510
728
|
if (outcome === "unsupported") {
|
|
511
|
-
|
|
729
|
+
unsupportedLinkRoots(port).add(rootResolved);
|
|
512
730
|
await port.rename(tmp, target);
|
|
513
731
|
return;
|
|
514
732
|
}
|
|
@@ -556,7 +774,7 @@ export async function mutateExact(port, root, rel, body) {
|
|
|
556
774
|
await replaceExistingLeaf(port, tmp, target, rel);
|
|
557
775
|
return;
|
|
558
776
|
}
|
|
559
|
-
if (
|
|
777
|
+
if (unsupportedLinkRoots(port).has(rootResolved)) {
|
|
560
778
|
await port.rename(tmp, target);
|
|
561
779
|
return;
|
|
562
780
|
}
|
|
@@ -588,88 +806,149 @@ function kindOf(stats) {
|
|
|
588
806
|
return "file";
|
|
589
807
|
return "other";
|
|
590
808
|
}
|
|
591
|
-
/**
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
809
|
+
/**
|
|
810
|
+
* Linux filesystem types (`statfs` magic numbers) whose directory times are kept by the local
|
|
811
|
+
* kernel and advance on every entry change. Anything else on Linux — NFS, SMB/CIFS, FUSE, 9p,
|
|
812
|
+
* Ceph, and every type not named here — gets no directory witness, so an observation pass lists it
|
|
813
|
+
* exactly as single reads do. Other platforms expose no stable type through Node, so their
|
|
814
|
+
* witnesses are offered and the pass's end-of-pass re-verification is what covers a remote mount.
|
|
815
|
+
*/
|
|
816
|
+
const LOCAL_LINUX_FILESYSTEMS = new Set([
|
|
817
|
+
0xef53, // ext2/3/4
|
|
818
|
+
0x58465342, // xfs
|
|
819
|
+
0x9123683e, // btrfs
|
|
820
|
+
0x01021994, // tmpfs
|
|
821
|
+
0x858458f6, // ramfs
|
|
822
|
+
0x794c7630, // overlayfs
|
|
823
|
+
0x2fc12fc1, // zfs
|
|
824
|
+
0xf2f52010, // f2fs
|
|
825
|
+
0xca451a4e, // bcachefs
|
|
826
|
+
0x4d44, // vfat
|
|
827
|
+
0x2011bab0, // exfat
|
|
828
|
+
0x7366746e, // ntfs3
|
|
829
|
+
0x482b, // hfsplus
|
|
830
|
+
]);
|
|
831
|
+
/** Whether a directory witness may be offered on `platform` for a filesystem of `filesystemType`. */
|
|
832
|
+
export function directoryWitnessTrusted(platform, filesystemType) {
|
|
833
|
+
if (platform !== "linux")
|
|
834
|
+
return true;
|
|
835
|
+
return filesystemType !== null && LOCAL_LINUX_FILESYSTEMS.has(filesystemType);
|
|
836
|
+
}
|
|
837
|
+
/** Whether `dir`'s filesystem may offer directory witnesses, asked once per device per port. */
|
|
838
|
+
function witnessTrust() {
|
|
839
|
+
const devices = new Map();
|
|
840
|
+
return (dev, dir) => {
|
|
841
|
+
if (process.platform !== "linux")
|
|
842
|
+
return Promise.resolve(true);
|
|
843
|
+
let trusted = devices.get(dev);
|
|
844
|
+
if (trusted === undefined) {
|
|
845
|
+
trusted = fs.statfs(dir).then((info) => directoryWitnessTrusted("linux", Number(info.type)), () => false);
|
|
846
|
+
devices.set(dev, trusted);
|
|
610
847
|
}
|
|
611
|
-
|
|
612
|
-
|
|
848
|
+
return trusted;
|
|
849
|
+
};
|
|
850
|
+
}
|
|
851
|
+
/** The one production binding: `node:fs`, the temp-file convention, and the identity lock. */
|
|
852
|
+
export function createNodeFilesystemIdentityPort(hostPolicy) {
|
|
853
|
+
const policy = captureFilesystemHostPolicy(hostPolicy);
|
|
854
|
+
const witnessTrustedOn = witnessTrust();
|
|
855
|
+
return Object.freeze({
|
|
856
|
+
isTransientOpenError: policy.isTransientOpenError,
|
|
857
|
+
isReplacementConflict: policy.isReplacementConflict,
|
|
858
|
+
async probe(target) {
|
|
859
|
+
let lstats;
|
|
860
|
+
try {
|
|
861
|
+
lstats = await fs.lstat(target);
|
|
862
|
+
}
|
|
863
|
+
catch (err) {
|
|
864
|
+
if (isAbsentPathError(err))
|
|
865
|
+
return null;
|
|
866
|
+
throw err;
|
|
867
|
+
}
|
|
868
|
+
return { kind: kindOf(lstats), dev: lstats.dev, ino: lstats.ino };
|
|
869
|
+
},
|
|
870
|
+
async entries(dir) {
|
|
871
|
+
try {
|
|
872
|
+
const dirents = await fs.readdir(dir, { withFileTypes: true });
|
|
873
|
+
return dirents.map((dirent) => ({ name: dirent.name, kind: kindOf(dirent) }));
|
|
874
|
+
}
|
|
875
|
+
catch (err) {
|
|
876
|
+
if (isAbsentPathError(err))
|
|
877
|
+
return null;
|
|
878
|
+
throw err;
|
|
879
|
+
}
|
|
880
|
+
},
|
|
881
|
+
async directoryWitness(dir) {
|
|
882
|
+
let stats;
|
|
883
|
+
try {
|
|
884
|
+
stats = await fs.stat(dir, { bigint: true });
|
|
885
|
+
}
|
|
886
|
+
catch (err) {
|
|
887
|
+
if (isAbsentPathError(err))
|
|
888
|
+
return null;
|
|
889
|
+
throw err;
|
|
890
|
+
}
|
|
891
|
+
if (!(await witnessTrustedOn(stats.dev, dir)))
|
|
613
892
|
return null;
|
|
614
|
-
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
}
|
|
674
|
-
}
|
|
893
|
+
return { dev: stats.dev, ino: stats.ino, mtimeNs: stats.mtimeNs, ctimeNs: stats.ctimeNs };
|
|
894
|
+
},
|
|
895
|
+
async open(target) {
|
|
896
|
+
const handle = await fs.open(target, "r");
|
|
897
|
+
try {
|
|
898
|
+
const stats = await handle.stat();
|
|
899
|
+
return { handle, dev: stats.dev, ino: stats.ino };
|
|
900
|
+
}
|
|
901
|
+
catch (err) {
|
|
902
|
+
await handle.close().catch(() => { });
|
|
903
|
+
throw err;
|
|
904
|
+
}
|
|
905
|
+
},
|
|
906
|
+
readAll(handle) {
|
|
907
|
+
return handle.readFile();
|
|
908
|
+
},
|
|
909
|
+
close(handle) {
|
|
910
|
+
return handle.close();
|
|
911
|
+
},
|
|
912
|
+
async stat(target) {
|
|
913
|
+
return { mtime: (await fs.stat(target)).mtime };
|
|
914
|
+
},
|
|
915
|
+
async mkdir(dir) {
|
|
916
|
+
try {
|
|
917
|
+
await fs.mkdir(dir);
|
|
918
|
+
return "created";
|
|
919
|
+
}
|
|
920
|
+
catch (err) {
|
|
921
|
+
if (err.code === "EEXIST")
|
|
922
|
+
return "exists";
|
|
923
|
+
throw err;
|
|
924
|
+
}
|
|
925
|
+
},
|
|
926
|
+
async writeTemp(dir, name, bytes) {
|
|
927
|
+
await fs.writeFile(path.join(dir, name), bytes);
|
|
928
|
+
},
|
|
929
|
+
async link(from, to) {
|
|
930
|
+
try {
|
|
931
|
+
await fs.link(from, to);
|
|
932
|
+
return "linked";
|
|
933
|
+
}
|
|
934
|
+
catch (err) {
|
|
935
|
+
const code = err.code;
|
|
936
|
+
if (code === "EEXIST")
|
|
937
|
+
return "exists";
|
|
938
|
+
if (code === "EPERM" || code === "ENOTSUP" || code === "EOPNOTSUPP" || code === "EXDEV")
|
|
939
|
+
return "unsupported";
|
|
940
|
+
throw err;
|
|
941
|
+
}
|
|
942
|
+
},
|
|
943
|
+
async rename(from, to) {
|
|
944
|
+
await fs.rename(from, to);
|
|
945
|
+
},
|
|
946
|
+
async unlink(target) {
|
|
947
|
+
await fs.unlink(target);
|
|
948
|
+
},
|
|
949
|
+
claim(key, identity) {
|
|
950
|
+
return acquireFilesystemIdentityLock(key, `${identity.root}:${identity.rel}`, { portableRoot: identity.root, hostPolicy: policy });
|
|
951
|
+
},
|
|
952
|
+
});
|
|
953
|
+
}
|
|
675
954
|
//# sourceMappingURL=filesystem-identity.js.map
|