@openclaw/signal 2026.9.6 → 2026.9.7
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/assets/icon.png +0 -0
- package/dist/.setup/{accounts-BV6tDOTc.mjs → accounts-DMtj2E-4.mjs} +6 -35
- package/dist/.setup/api-DEB0Obj8.mjs +16 -0
- package/dist/.setup/{api-CGh4eWR8.mjs → api-DmCb6e7E.mjs} +10 -10
- package/dist/.setup/{approval-auth-BBI9BTRm.mjs → approval-auth-CszS7gwf.mjs} +7 -13
- package/dist/.setup/{approval-handler.runtime-C3vN5OWd.mjs → approval-handler.runtime-D9ofZcZW.mjs} +10 -29
- package/dist/.setup/{approval-reactions-DDQvPP_z.mjs → approval-reactions-BKkjIAoi.mjs} +25 -36
- package/dist/.setup/{channel-DhzTcFsK.mjs → channel-DrUxv5cf.mjs} +567 -136
- package/dist/.setup/{client-BseAt7F7.mjs → client-AXcDteBZ.mjs} +63 -152
- package/dist/.setup/client-adapter-c_O1ouxZ.mjs +30 -0
- package/dist/.setup/{config-schema-aQwwMGUj.mjs → config-schema-DvxZ18SD.mjs} +3 -13
- package/dist/.setup/{doctor-contract-api-Rbq_sRTI.mjs → doctor-contract-api-Db9V9gsY.mjs} +212 -91
- package/dist/.setup/{identity-YXPmgFMu.mjs → identity-B3JyPqGO.mjs} +2 -6
- package/dist/.setup/{install-signal-cli-BDbzFcU2.mjs → install-signal-cli-ChvjzM6X.mjs} +0 -4
- package/dist/.setup/legacy-transport-QIpaMNST.mjs +18 -0
- package/dist/.setup/{monitor-Dnz6Ygz5.mjs → monitor-BfwQr78f.mjs} +95 -124
- package/dist/.setup/{probe-DXT2eLnw.mjs → probe-BYLzra6D.mjs} +9 -9
- package/dist/.setup/{reaction-runtime-api-BnQGHcrB.mjs → reaction-runtime-api-DDi5x2wC.mjs} +3 -17
- package/dist/.setup/{question-reactions-C8cSEjVf.mjs → reaction-targets-CEdyjtrC.mjs} +11 -8
- package/dist/.setup/{rpc-context-CwwADZ1b.mjs → rpc-context-D26RxFIm.mjs} +1 -1
- package/dist/.setup/runtime-8sxUF217.mjs +8 -0
- package/dist/.setup/{send-B78M_eFp.mjs → send-DEjrbpIC.mjs} +25 -55
- package/dist/.setup/{channel.runtime-CG79z_Vy.mjs → setup-surface-Drt-4t3R.mjs} +4 -6
- package/dist/.setup/transport-detection-BVUDE42e.mjs +25 -0
- package/dist/.setup/{transport-policy-5VSnj5ma.mjs → transport-policy-B6C_LogW.mjs} +19 -1
- package/dist/.setup/transport-probes.runtime-DwXEHnXr.mjs +2 -0
- package/dist/api.js +10 -10
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/contract-api.js +2 -2
- package/dist/doctor-contract-api.js +1 -1
- package/dist/reaction-runtime-api.js +1 -1
- package/dist/runtime-api.js +2 -19
- package/dist/setup-entry.js +1 -1
- package/node_modules/@openclaw/fs-safe/CHANGELOG.md +102 -0
- package/node_modules/@openclaw/fs-safe/README.md +24 -6
- package/node_modules/@openclaw/fs-safe/dist/advanced.d.ts +6 -1
- package/node_modules/@openclaw/fs-safe/dist/advanced.js +3 -1
- package/node_modules/@openclaw/fs-safe/dist/archive-durability.js +1 -1
- package/node_modules/@openclaw/fs-safe/dist/archive-merge.js +1 -2
- package/node_modules/@openclaw/fs-safe/dist/archive-plan.d.ts +2 -7
- package/node_modules/@openclaw/fs-safe/dist/archive-read.js +9 -18
- package/node_modules/@openclaw/fs-safe/dist/archive-staging.d.ts +1 -2
- package/node_modules/@openclaw/fs-safe/dist/archive-staging.js +3 -3
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-directory.js +4 -0
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-entry.d.ts +11 -11
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-entry.js +3 -35
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-integrity.d.ts +2 -2
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-integrity.js +2 -12
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-loader.d.ts +7 -3
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-loader.js +13 -10
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-manifest.js +3 -1
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-preflight.d.ts +2 -3
- package/node_modules/@openclaw/fs-safe/dist/archive-zip-preflight.js +16 -8
- package/node_modules/@openclaw/fs-safe/dist/archive.d.ts +6 -3
- package/node_modules/@openclaw/fs-safe/dist/archive.js +22 -19
- package/node_modules/@openclaw/fs-safe/dist/atomic.d.ts +1 -1
- package/node_modules/@openclaw/fs-safe/dist/copy-publication.d.ts +1 -3
- package/node_modules/@openclaw/fs-safe/dist/copy-publication.js +2 -6
- package/node_modules/@openclaw/fs-safe/dist/deny-mutation-match.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/deny-mutation-match.js +71 -0
- package/node_modules/@openclaw/fs-safe/dist/deny-mutations.js +4 -3
- package/node_modules/@openclaw/fs-safe/dist/directory-guard.d.ts +0 -1
- package/node_modules/@openclaw/fs-safe/dist/directory-guard.js +0 -3
- package/node_modules/@openclaw/fs-safe/dist/directory-mode-node.d.ts +20 -2
- package/node_modules/@openclaw/fs-safe/dist/directory-mode-node.js +77 -1
- package/node_modules/@openclaw/fs-safe/dist/directory-receipt.js +5 -7
- package/node_modules/@openclaw/fs-safe/dist/effective-uid.js +1 -4
- package/node_modules/@openclaw/fs-safe/dist/errors.d.ts +3 -1
- package/node_modules/@openclaw/fs-safe/dist/errors.js +3 -2
- package/node_modules/@openclaw/fs-safe/dist/file-identity.js +10 -2
- package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-acquisition.js +1 -1
- package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-admission.js +5 -1
- package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-root-held.d.ts +4 -11
- package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-root-held.js +1 -4
- package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-root-io.d.ts +3 -6
- package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-root-io.js +1 -1
- package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-root-options.d.ts +2 -10
- package/node_modules/@openclaw/fs-safe/dist/file-lock-sync-root.d.ts +2 -4
- package/node_modules/@openclaw/fs-safe/dist/file-lock-sync.js +2 -2
- package/node_modules/@openclaw/fs-safe/dist/file-store-boundary.d.ts +3 -7
- package/node_modules/@openclaw/fs-safe/dist/file-store-boundary.js +7 -10
- package/node_modules/@openclaw/fs-safe/dist/file-store-prune.js +7 -6
- package/node_modules/@openclaw/fs-safe/dist/file-store.d.ts +4 -7
- package/node_modules/@openclaw/fs-safe/dist/file-store.js +19 -21
- package/node_modules/@openclaw/fs-safe/dist/guest-native-python.js +23 -31
- package/node_modules/@openclaw/fs-safe/dist/guest.js +21 -12
- package/node_modules/@openclaw/fs-safe/dist/json-document-store.d.ts +4 -9
- package/node_modules/@openclaw/fs-safe/dist/json-durable-queue-ownership.d.ts +1 -5
- package/node_modules/@openclaw/fs-safe/dist/json-durable-queue.d.ts +0 -1
- package/node_modules/@openclaw/fs-safe/dist/json-durable-queue.js +2 -7
- package/node_modules/@openclaw/fs-safe/dist/local-file-access.js +2 -5
- package/node_modules/@openclaw/fs-safe/dist/local-file-descriptor.d.ts +2 -5
- package/node_modules/@openclaw/fs-safe/dist/local-roots.d.ts +2 -7
- package/node_modules/@openclaw/fs-safe/dist/move-path-cleanup.js +4 -4
- package/node_modules/@openclaw/fs-safe/dist/mutation-authority.js +5 -0
- package/node_modules/@openclaw/fs-safe/dist/native-binding.d.ts +51 -14
- package/node_modules/@openclaw/fs-safe/dist/native-pinned-write.js +8 -2
- package/node_modules/@openclaw/fs-safe/dist/native-staged-symlink.d.ts +13 -0
- package/node_modules/@openclaw/fs-safe/dist/native-staged-symlink.js +303 -0
- package/node_modules/@openclaw/fs-safe/dist/owner-dacl-batch-worker.d.ts +1 -0
- package/node_modules/@openclaw/fs-safe/dist/owner-dacl-batch-worker.js +54 -0
- package/node_modules/@openclaw/fs-safe/dist/owner-dacl-batch.d.ts +5 -0
- package/node_modules/@openclaw/fs-safe/dist/owner-dacl-batch.js +64 -0
- package/node_modules/@openclaw/fs-safe/dist/owner-dacl.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/owner-dacl.js +3 -0
- package/node_modules/@openclaw/fs-safe/dist/path.js +17 -1
- package/node_modules/@openclaw/fs-safe/dist/permission-exec.d.ts +6 -0
- package/node_modules/@openclaw/fs-safe/dist/permission-exec.js +3 -6
- package/node_modules/@openclaw/fs-safe/dist/permissions-public.d.ts +3 -1
- package/node_modules/@openclaw/fs-safe/dist/permissions-public.js +1 -0
- package/node_modules/@openclaw/fs-safe/dist/permissions-windows.d.ts +3 -6
- package/node_modules/@openclaw/fs-safe/dist/permissions.d.ts +3 -10
- package/node_modules/@openclaw/fs-safe/dist/permissions.js +0 -1
- package/node_modules/@openclaw/fs-safe/dist/pinned-mutation-admission.d.ts +0 -1
- package/node_modules/@openclaw/fs-safe/dist/pinned-mutation-admission.js +4 -2
- package/node_modules/@openclaw/fs-safe/dist/pinned-mutation-shared-route.d.ts +2 -8
- package/node_modules/@openclaw/fs-safe/dist/pinned-open.d.ts +1 -1
- package/node_modules/@openclaw/fs-safe/dist/pinned-open.js +2 -3
- package/node_modules/@openclaw/fs-safe/dist/publish-copy-stage.js +4 -0
- package/node_modules/@openclaw/fs-safe/dist/read-opened-file.d.ts +2 -5
- package/node_modules/@openclaw/fs-safe/dist/regular-file.js +3 -3
- package/node_modules/@openclaw/fs-safe/dist/replace-directory.js +5 -17
- package/node_modules/@openclaw/fs-safe/dist/replace-file-buffer.d.ts +4 -0
- package/node_modules/@openclaw/fs-safe/dist/replace-file-buffer.js +36 -0
- package/node_modules/@openclaw/fs-safe/dist/replace-file-copy-fallback.d.ts +4 -10
- package/node_modules/@openclaw/fs-safe/dist/replace-file-copy-fallback.js +66 -38
- package/node_modules/@openclaw/fs-safe/dist/replace-file-descriptor.d.ts +7 -11
- package/node_modules/@openclaw/fs-safe/dist/replace-file-descriptor.js +10 -2
- package/node_modules/@openclaw/fs-safe/dist/replace-file-destination.d.ts +21 -0
- package/node_modules/@openclaw/fs-safe/dist/replace-file-destination.js +123 -0
- package/node_modules/@openclaw/fs-safe/dist/replace-file-mutation.d.ts +26 -0
- package/node_modules/@openclaw/fs-safe/dist/replace-file-mutation.js +47 -0
- package/node_modules/@openclaw/fs-safe/dist/replace-file-temp-owner.d.ts +2 -2
- package/node_modules/@openclaw/fs-safe/dist/replace-file-temp-owner.js +16 -4
- package/node_modules/@openclaw/fs-safe/dist/replace-file-types.d.ts +55 -0
- package/node_modules/@openclaw/fs-safe/dist/replace-file-types.js +1 -0
- package/node_modules/@openclaw/fs-safe/dist/replace-file.d.ts +3 -55
- package/node_modules/@openclaw/fs-safe/dist/replace-file.js +31 -11
- package/node_modules/@openclaw/fs-safe/dist/retained-directory-replacement.d.ts +1 -0
- package/node_modules/@openclaw/fs-safe/dist/retained-directory-replacement.js +1 -1
- package/node_modules/@openclaw/fs-safe/dist/retained-file-types.d.ts +50 -0
- package/node_modules/@openclaw/fs-safe/dist/retained-file-types.js +1 -0
- package/node_modules/@openclaw/fs-safe/dist/retained-file.d.ts +3 -0
- package/node_modules/@openclaw/fs-safe/dist/retained-file.js +121 -0
- package/node_modules/@openclaw/fs-safe/dist/root-context.js +3 -2
- package/node_modules/@openclaw/fs-safe/dist/root-directory-entry.d.ts +9 -0
- package/node_modules/@openclaw/fs-safe/dist/root-directory-entry.js +28 -0
- package/node_modules/@openclaw/fs-safe/dist/root-directory-list.d.ts +9 -1
- package/node_modules/@openclaw/fs-safe/dist/root-directory-list.js +88 -37
- package/node_modules/@openclaw/fs-safe/dist/root-file-final-admission.d.ts +1 -1
- package/node_modules/@openclaw/fs-safe/dist/root-file-final-admission.js +1 -6
- package/node_modules/@openclaw/fs-safe/dist/root-file.js +2 -5
- package/node_modules/@openclaw/fs-safe/dist/root-handle-context.d.ts +4 -0
- package/node_modules/@openclaw/fs-safe/dist/root-handle-context.js +12 -0
- package/node_modules/@openclaw/fs-safe/dist/root-impl.d.ts +3 -3
- package/node_modules/@openclaw/fs-safe/dist/root-impl.js +8 -5
- package/node_modules/@openclaw/fs-safe/dist/root-move-noreplace.d.ts +2 -7
- package/node_modules/@openclaw/fs-safe/dist/root-move-noreplace.js +3 -3
- package/node_modules/@openclaw/fs-safe/dist/root-observed-path.d.ts +0 -1
- package/node_modules/@openclaw/fs-safe/dist/root-observed-path.js +0 -3
- package/node_modules/@openclaw/fs-safe/dist/root-path-observation.d.ts +4 -11
- package/node_modules/@openclaw/fs-safe/dist/root-path.js +7 -10
- package/node_modules/@openclaw/fs-safe/dist/root-paths.d.ts +2 -6
- package/node_modules/@openclaw/fs-safe/dist/root-remove-identity.d.ts +1 -3
- package/node_modules/@openclaw/fs-safe/dist/root-walk.d.ts +19 -12
- package/node_modules/@openclaw/fs-safe/dist/root-walk.js +56 -20
- package/node_modules/@openclaw/fs-safe/dist/root-write-admission.js +1 -6
- package/node_modules/@openclaw/fs-safe/dist/root-write-complete-parent.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/root-write-complete-parent.js +1 -1
- package/node_modules/@openclaw/fs-safe/dist/safe-path-segment.d.ts +1 -0
- package/node_modules/@openclaw/fs-safe/dist/safe-path-segment.js +8 -2
- package/node_modules/@openclaw/fs-safe/dist/secret-file.d.ts +6 -2
- package/node_modules/@openclaw/fs-safe/dist/secret-file.js +12 -16
- package/node_modules/@openclaw/fs-safe/dist/secret-read-policy.js +1 -1
- package/node_modules/@openclaw/fs-safe/dist/secure-file-windows.js +5 -14
- package/node_modules/@openclaw/fs-safe/dist/secure-file.js +3 -2
- package/node_modules/@openclaw/fs-safe/dist/secure-temp-dir.js +2 -7
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-acquire.js +4 -4
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-admission-parser.d.ts +1 -2
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-handle.d.ts +2 -8
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-policy.d.ts +2 -7
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-reclaim.d.ts +2 -2
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-reclaim.js +11 -12
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock-stale-admission.d.ts +1 -5
- package/node_modules/@openclaw/fs-safe/dist/sidecar-lock.js +9 -7
- package/node_modules/@openclaw/fs-safe/dist/staged-symlink-types.d.ts +39 -0
- package/node_modules/@openclaw/fs-safe/dist/staged-symlink-types.js +1 -0
- package/node_modules/@openclaw/fs-safe/dist/stat-observation.js +3 -10
- package/node_modules/@openclaw/fs-safe/dist/strict-file-identity.d.ts +2 -0
- package/node_modules/@openclaw/fs-safe/dist/strict-file-identity.js +6 -6
- package/node_modules/@openclaw/fs-safe/dist/symlink-parents.js +58 -7
- package/node_modules/@openclaw/fs-safe/dist/temp-target.js +8 -10
- package/node_modules/@openclaw/fs-safe/dist/temp-workspace-admission.js +28 -33
- package/node_modules/@openclaw/fs-safe/dist/temp-workspace-child-admission.d.ts +1 -1
- package/node_modules/@openclaw/fs-safe/dist/temp-workspace-child-admission.js +16 -17
- package/node_modules/@openclaw/fs-safe/dist/temp-workspace-descriptor.js +1 -2
- package/node_modules/@openclaw/fs-safe/dist/temp-workspace-owner.js +4 -9
- package/node_modules/@openclaw/fs-safe/dist/temp-workspace-ownership.d.ts +8 -0
- package/node_modules/@openclaw/fs-safe/dist/temp-workspace-ownership.js +52 -0
- package/node_modules/@openclaw/fs-safe/dist/test-hooks.d.ts +5 -1
- package/node_modules/@openclaw/fs-safe/dist/text-atomic.d.ts +2 -1
- package/node_modules/@openclaw/fs-safe/dist/text-atomic.js +2 -0
- package/node_modules/@openclaw/fs-safe/dist/trash.js +27 -1
- package/node_modules/@openclaw/fs-safe/dist/walk.d.ts +2 -5
- package/node_modules/@openclaw/fs-safe/dist/watch-alias.d.ts +6 -0
- package/node_modules/@openclaw/fs-safe/dist/watch-alias.js +88 -0
- package/node_modules/@openclaw/fs-safe/dist/watch-hints.d.ts +9 -0
- package/node_modules/@openclaw/fs-safe/dist/watch-hints.js +93 -0
- package/node_modules/@openclaw/fs-safe/dist/watch-native.d.ts +36 -0
- package/node_modules/@openclaw/fs-safe/dist/watch-native.js +73 -0
- package/node_modules/@openclaw/fs-safe/dist/watch-scan.d.ts +28 -0
- package/node_modules/@openclaw/fs-safe/dist/watch-scan.js +300 -0
- package/node_modules/@openclaw/fs-safe/dist/watch-stream.d.ts +8 -0
- package/node_modules/@openclaw/fs-safe/dist/watch-stream.js +32 -0
- package/node_modules/@openclaw/fs-safe/dist/watch-types.d.ts +60 -0
- package/node_modules/@openclaw/fs-safe/dist/watch-types.js +1 -0
- package/node_modules/@openclaw/fs-safe/dist/watch.d.ts +5 -0
- package/node_modules/@openclaw/fs-safe/dist/watch.js +530 -0
- package/node_modules/@openclaw/fs-safe/dist/windows-owner.d.ts +3 -7
- package/node_modules/@openclaw/fs-safe/dist/windows-owner.js +0 -1
- package/node_modules/@openclaw/fs-safe/dist/windows-security-bridge.cs +6 -6
- package/node_modules/@openclaw/fs-safe/dist/windows-security-bridge.ps1 +78 -3
- package/node_modules/@openclaw/fs-safe/dist/windows-security-command.d.ts +8 -0
- package/node_modules/@openclaw/fs-safe/dist/windows-security-command.js +66 -15
- package/node_modules/@openclaw/fs-safe/dist/windows-security-facts.d.ts +4 -0
- package/node_modules/@openclaw/fs-safe/dist/windows-security-facts.js +6 -2
- package/node_modules/@openclaw/fs-safe/docs/advanced.md +4 -2
- package/node_modules/@openclaw/fs-safe/docs/archive.md +16 -0
- package/node_modules/@openclaw/fs-safe/docs/atomic.md +93 -3
- package/node_modules/@openclaw/fs-safe/docs/contributing.md +102 -4
- package/node_modules/@openclaw/fs-safe/docs/copy.md +2 -0
- package/node_modules/@openclaw/fs-safe/docs/durability.md +7 -0
- package/node_modules/@openclaw/fs-safe/docs/file-store.md +5 -0
- package/node_modules/@openclaw/fs-safe/docs/guest.md +7 -1
- package/node_modules/@openclaw/fs-safe/docs/index.md +1 -0
- package/node_modules/@openclaw/fs-safe/docs/install.md +30 -0
- package/node_modules/@openclaw/fs-safe/docs/native-helper.md +20 -4
- package/node_modules/@openclaw/fs-safe/docs/native.md +63 -1
- package/node_modules/@openclaw/fs-safe/docs/permissions.md +66 -0
- package/node_modules/@openclaw/fs-safe/docs/public-api.md +30 -3
- package/node_modules/@openclaw/fs-safe/docs/retained-file.md +115 -0
- package/node_modules/@openclaw/fs-safe/docs/root.md +35 -9
- package/node_modules/@openclaw/fs-safe/docs/secret-file.md +19 -0
- package/node_modules/@openclaw/fs-safe/docs/security-model.md +4 -1
- package/node_modules/@openclaw/fs-safe/docs/sidecar-lock.md +5 -1
- package/node_modules/@openclaw/fs-safe/docs/staged-symlink.md +124 -0
- package/node_modules/@openclaw/fs-safe/docs/store.md +3 -1
- package/node_modules/@openclaw/fs-safe/docs/temp.md +24 -4
- package/node_modules/@openclaw/fs-safe/docs/testing.md +210 -0
- package/node_modules/@openclaw/fs-safe/docs/types.md +6 -0
- package/node_modules/@openclaw/fs-safe/docs/walk.md +34 -1
- package/node_modules/@openclaw/fs-safe/docs/watch.md +251 -0
- package/node_modules/@openclaw/fs-safe/docs/writing.md +21 -0
- package/node_modules/@openclaw/fs-safe/package.json +13 -9
- package/node_modules/@openclaw/fs-safe-darwin-arm64/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-darwin-arm64/package.json +1 -1
- package/node_modules/@openclaw/fs-safe-darwin-x64/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-darwin-x64/package.json +1 -1
- package/node_modules/@openclaw/fs-safe-linux-arm64-gnu/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-linux-arm64-gnu/package.json +1 -1
- package/node_modules/@openclaw/fs-safe-linux-arm64-musl/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-linux-arm64-musl/package.json +1 -1
- package/node_modules/@openclaw/fs-safe-linux-x64-gnu/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-linux-x64-gnu/package.json +1 -1
- package/node_modules/@openclaw/fs-safe-linux-x64-musl/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-linux-x64-musl/package.json +1 -1
- package/node_modules/@openclaw/fs-safe-win32-x64-msvc/fs-safe-native.node +0 -0
- package/node_modules/@openclaw/fs-safe-win32-x64-msvc/package.json +1 -1
- package/package.json +5 -5
- package/dist/.setup/api-B9-B1L7Q.mjs +0 -17
- package/dist/.setup/client-adapter-dvFa47YL.mjs +0 -63
- package/dist/.setup/rolldown-runtime-8H4AJuhK.mjs +0 -14
- package/dist/.setup/send.runtime-CLnCWvrM.mjs +0 -2
- package/dist/.setup/transport-detection-CoiRl7Gx.mjs +0 -576
- package/dist/.setup/transport-detection.runtime-Tlhuv3T_.mjs +0 -2
- package/dist/.setup/transport-probes.runtime-WprAyBbL.mjs +0 -2
- package/node_modules/@openclaw/fs-safe/dist/directory-mode-owner.d.ts +0 -20
- package/node_modules/@openclaw/fs-safe/dist/directory-mode-owner.js +0 -78
|
@@ -1,42 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
/** Internal: register only after the complete decoder/admission association. */
|
|
4
|
-
export function registerAdmittedZipEntry(entry, physical) {
|
|
1
|
+
/** Internal: create only after the complete decoder/admission association. */
|
|
2
|
+
export function createAdmittedZipEntry(entry, name, physical) {
|
|
5
3
|
const mode = physical.creatorSystem === 3 ? physical.externalAttributes >>> 16 : undefined;
|
|
6
|
-
admittedMetadata.set(entry, { kind: physical.kind, mode, size: physical.size });
|
|
7
4
|
entry.dir = physical.kind === "directory";
|
|
8
5
|
// Previously unsupported non-UNIX symlinks must also be recognizable to
|
|
9
6
|
// public preflight consumers using JSZip's conventional type inspection.
|
|
10
7
|
entry.unixPermissions = mode ?? (physical.kind === "symlink" ? 0o120000 : null);
|
|
11
8
|
entry.dosPermissions = physical.creatorSystem === 0 ? physical.externalAttributes & 0x3f : null;
|
|
12
|
-
}
|
|
13
|
-
export function zipEntryIntegrityMetadata(entry) {
|
|
14
|
-
const data = entry._data;
|
|
15
|
-
if (!data || "then" in data)
|
|
16
|
-
return undefined;
|
|
17
|
-
return data;
|
|
18
|
-
}
|
|
19
|
-
const ZIP_UNIX_FILE_TYPE_MASK = 0o170000;
|
|
20
|
-
const ZIP_UNIX_SYMLINK_TYPE = 0o120000;
|
|
21
|
-
export function isZipSymlinkEntry(entry) {
|
|
22
|
-
return zipEntryKind(entry) === "symlink";
|
|
23
|
-
}
|
|
24
|
-
export function zipEntryKind(entry) {
|
|
25
|
-
const metadata = admittedMetadata.get(entry);
|
|
26
|
-
if (metadata)
|
|
27
|
-
return metadata.kind;
|
|
28
|
-
return typeof entry.unixPermissions === "number" &&
|
|
29
|
-
(entry.unixPermissions & ZIP_UNIX_FILE_TYPE_MASK) === ZIP_UNIX_SYMLINK_TYPE
|
|
30
|
-
? "symlink" : entry.dir ? "directory" : "file";
|
|
31
|
-
}
|
|
32
|
-
export function zipEntryMode(entry, policy) {
|
|
33
|
-
const metadata = admittedMetadata.get(entry);
|
|
34
|
-
return resolveArchiveEntryMode({
|
|
35
|
-
kind: entry.dir ? "directory" : "file",
|
|
36
|
-
archivedMode: metadata ? metadata.mode : entry.unixPermissions,
|
|
37
|
-
policy,
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
export function zipEntryDeclaredSize(entry) {
|
|
41
|
-
return admittedMetadata.get(entry)?.size ?? Math.max(0, Math.floor(zipEntryIntegrityMetadata(entry)?.uncompressedSize ?? 0));
|
|
9
|
+
return { entry, name, kind: physical.kind, mode, size: physical.size, crc32: physical.crc32 };
|
|
42
10
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Transform } from "node:stream";
|
|
2
|
-
import {
|
|
2
|
+
import type { AdmittedZipEntry } from "./archive-zip-entry.js";
|
|
3
3
|
export declare function normalizeZipIntegrityError(error: unknown): Error;
|
|
4
|
-
export declare function createZipIntegrityTransform(
|
|
4
|
+
export declare function createZipIntegrityTransform(record: AdmittedZipEntry): Transform;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Transform } from "node:stream";
|
|
2
2
|
import { ArchiveFormatError } from "./archive-errors.js";
|
|
3
|
-
import { zipEntryIntegrityMetadata, } from "./archive-zip-entry.js";
|
|
4
3
|
import { updateCrc32 } from "./archive-crc32.js";
|
|
5
4
|
export function normalizeZipIntegrityError(error) {
|
|
6
5
|
if (error instanceof Error &&
|
|
@@ -9,17 +8,8 @@ export function normalizeZipIntegrityError(error) {
|
|
|
9
8
|
}
|
|
10
9
|
return error instanceof Error ? error : new Error(String(error));
|
|
11
10
|
}
|
|
12
|
-
export function createZipIntegrityTransform(
|
|
13
|
-
const
|
|
14
|
-
const expectedCrc32 = metadata?.crc32;
|
|
15
|
-
const expectedSize = metadata?.uncompressedSize;
|
|
16
|
-
if (typeof expectedCrc32 !== "number" ||
|
|
17
|
-
!Number.isInteger(expectedCrc32) ||
|
|
18
|
-
typeof expectedSize !== "number" ||
|
|
19
|
-
!Number.isSafeInteger(expectedSize) ||
|
|
20
|
-
expectedSize < 0) {
|
|
21
|
-
throw new ArchiveFormatError(`zip entry has invalid integrity metadata: ${entry.name}`);
|
|
22
|
-
}
|
|
11
|
+
export function createZipIntegrityTransform(record) {
|
|
12
|
+
const { entry, crc32: expectedCrc32, size: expectedSize } = record;
|
|
23
13
|
let actualCrc32 = 0;
|
|
24
14
|
let actualSize = 0;
|
|
25
15
|
return new Transform({
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import type { ZipDirectoryEntry } from "./archive-zip-directory.js";
|
|
2
|
-
import { type
|
|
2
|
+
import { type AdmittedZipEntry } from "./archive-zip-entry.js";
|
|
3
3
|
export type ZipArchiveWithFiles = {
|
|
4
4
|
files: Record<string, unknown>;
|
|
5
5
|
};
|
|
6
|
-
export
|
|
6
|
+
export type ZipArchiveAdmission = {
|
|
7
|
+
archive: ZipArchiveWithFiles;
|
|
8
|
+
entries: ReadonlyMap<string, AdmittedZipEntry>;
|
|
9
|
+
};
|
|
10
|
+
export declare function assertZipEntryBinding(archive: ZipArchiveWithFiles, record: AdmittedZipEntry, path: string): void;
|
|
7
11
|
/** Internal: the caller has admitted these unchanged bytes and their metadata. */
|
|
8
|
-
export declare function loadAdmittedZipArchive(buffer: Buffer | Uint8Array, admitted: ZipDirectoryEntry[]): Promise<
|
|
12
|
+
export declare function loadAdmittedZipArchive(buffer: Buffer | Uint8Array, admitted: ZipDirectoryEntry[]): Promise<ZipArchiveAdmission>;
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { ArchiveFormatError, ArchiveSecurityError } from "./archive-errors.js";
|
|
2
|
-
import { validateArchiveEntryPath } from "./archive-entry.js";
|
|
3
|
-
import {
|
|
2
|
+
import { createArchiveOutputPathTracker, validateArchiveEntryPath } from "./archive-entry.js";
|
|
3
|
+
import { createAdmittedZipEntry } from "./archive-zip-entry.js";
|
|
4
4
|
import { zipPathKey } from "./archive-zip-names.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
export function assertZipEntryBinding(archive, record, path) {
|
|
6
|
+
const { entry } = record;
|
|
7
|
+
const name = entry.name;
|
|
8
|
+
validateArchiveEntryPath(name, { escapeLabel: "archive root" });
|
|
9
|
+
if (archive.files[record.name] !== entry || zipPathKey(name) !== path)
|
|
10
|
+
disagreement();
|
|
8
11
|
}
|
|
9
12
|
function disagreement() {
|
|
10
13
|
throw new ArchiveFormatError("ZIP decoder disagrees with admitted directory metadata");
|
|
@@ -24,7 +27,9 @@ function matchesData(value, physical) {
|
|
|
24
27
|
/** Internal: the caller has admitted these unchanged bytes and their metadata. */
|
|
25
28
|
export async function loadAdmittedZipArchive(buffer, admitted) {
|
|
26
29
|
const physicalByPath = new Map();
|
|
30
|
+
const trackOutputPath = createArchiveOutputPathTracker();
|
|
27
31
|
for (const entry of admitted) {
|
|
32
|
+
trackOutputPath(entry.portableKey, entry.portableKey);
|
|
28
33
|
if (physicalByPath.has(entry.portableKey))
|
|
29
34
|
collision();
|
|
30
35
|
physicalByPath.set(entry.portableKey, entry);
|
|
@@ -110,7 +115,7 @@ export async function loadAdmittedZipArchive(buffer, admitted) {
|
|
|
110
115
|
if (remaining.size || inserted.size)
|
|
111
116
|
disagreement();
|
|
112
117
|
const files = Object.create(null);
|
|
113
|
-
const entries =
|
|
118
|
+
const entries = new Map();
|
|
114
119
|
for (const [name, entry, physical] of normalized) {
|
|
115
120
|
const appendSlash = physical.kind === "directory" && !name.endsWith("/");
|
|
116
121
|
const normalizedName = appendSlash ? `${name}/` : name;
|
|
@@ -120,12 +125,10 @@ export async function loadAdmittedZipArchive(buffer, admitted) {
|
|
|
120
125
|
entry.name = `${entry.name}/`;
|
|
121
126
|
}
|
|
122
127
|
files[normalizedName] = entry;
|
|
123
|
-
|
|
124
|
-
entries.push(entry);
|
|
128
|
+
entries.set(physical.portableKey, createAdmittedZipEntry(entry, normalizedName, physical));
|
|
125
129
|
}
|
|
126
130
|
archive.files = files;
|
|
127
|
-
|
|
128
|
-
return archive;
|
|
131
|
+
return { archive, entries };
|
|
129
132
|
}
|
|
130
133
|
async function importOptionalJsZip() {
|
|
131
134
|
try {
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { ArchiveFormatError, ArchiveSecurityError } from "./archive-errors.js";
|
|
2
|
-
import { stripArchivePath } from "./archive-entry.js";
|
|
2
|
+
import { createArchiveOutputPathTracker, stripArchivePath } from "./archive-entry.js";
|
|
3
3
|
/** Associate all native entries with physical admission before exposing any. */
|
|
4
4
|
export function validateNativeZipManifest(manifest, admitted) {
|
|
5
5
|
if (manifest.length !== admitted.length) {
|
|
6
6
|
throw new ArchiveSecurityError("entry-path", "zip decoder collapsed entry names");
|
|
7
7
|
}
|
|
8
|
+
const trackOutputPath = createArchiveOutputPathTracker();
|
|
8
9
|
for (const [ordinal, entry] of manifest.entries()) {
|
|
9
10
|
const physical = admitted[ordinal];
|
|
10
11
|
const physicalPath = physical?.path;
|
|
@@ -18,5 +19,6 @@ export function validateNativeZipManifest(manifest, admitted) {
|
|
|
18
19
|
(physical.creatorSystem === 3 && entry.mode !== physical.externalAttributes >>> 16)) {
|
|
19
20
|
throw new ArchiveFormatError("ZIP decoder disagrees with admitted directory metadata");
|
|
20
21
|
}
|
|
22
|
+
trackOutputPath(entry.path, entry.path);
|
|
21
23
|
}
|
|
22
24
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { type ArchiveExtractLimits } from "./archive-limits.js";
|
|
2
|
-
import { type ZipArchiveWithFiles } from "./archive-zip-loader.js";
|
|
3
|
-
export
|
|
4
|
-
export type { ZipArchiveWithFiles } from "./archive-zip-loader.js";
|
|
2
|
+
import { type ZipArchiveAdmission, type ZipArchiveWithFiles } from "./archive-zip-loader.js";
|
|
3
|
+
export declare function loadZipArchiveWithAdmission(buffer: Buffer | Uint8Array, limits?: ArchiveExtractLimits): Promise<ZipArchiveAdmission>;
|
|
5
4
|
export declare function loadZipArchiveWithPreflight(buffer: Buffer | Uint8Array, limits?: ArchiveExtractLimits): Promise<ZipArchiveWithFiles>;
|
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
import { ARCHIVE_LIMIT_ERROR_CODE, ArchiveLimitError, resolveExtractLimits, } from "./archive-limits.js";
|
|
2
2
|
import { admitZipBuffer } from "./archive-zip-admission.js";
|
|
3
3
|
import { loadAdmittedZipArchive } from "./archive-zip-loader.js";
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
export function loadZipArchiveWithAdmission(buffer, limits) {
|
|
5
|
+
try {
|
|
6
|
+
const resolvedLimits = resolveExtractLimits(limits);
|
|
7
|
+
if (buffer.byteLength > resolvedLimits.maxArchiveBytes) {
|
|
8
|
+
throw new ArchiveLimitError(ARCHIVE_LIMIT_ERROR_CODE.ARCHIVE_SIZE_EXCEEDS_LIMIT);
|
|
9
|
+
}
|
|
10
|
+
const entries = [];
|
|
11
|
+
admitZipBuffer(buffer, resolvedLimits, entry => { entries.push(entry); });
|
|
12
|
+
return loadAdmittedZipArchive(buffer, entries);
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
// Keep validation failures in the promise handed to the extraction deadline.
|
|
16
|
+
return Promise.reject(error);
|
|
9
17
|
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
return await
|
|
18
|
+
}
|
|
19
|
+
export async function loadZipArchiveWithPreflight(buffer, limits) {
|
|
20
|
+
return (await loadZipArchiveWithAdmission(buffer, limits)).archive;
|
|
13
21
|
}
|
|
@@ -6,10 +6,13 @@ export { resolveArchiveKind, resolvePackedRootDir, type ArchiveKind } from "./ar
|
|
|
6
6
|
export { readArchiveEntry } from "./archive-read.js";
|
|
7
7
|
export { ARCHIVE_LIMIT_ERROR_CODE, ArchiveLimitError, DEFAULT_MAX_ARCHIVE_BYTES_ZIP, DEFAULT_MAX_ENTRIES, DEFAULT_MAX_EXTRACTED_BYTES, DEFAULT_MAX_ENTRY_BYTES, DEFAULT_MAX_META_ENTRY_BYTES, DEFAULT_MAX_ENTRY_PATH_COMPONENTS, type ArchiveExtractLimits, type ArchiveLimitErrorCode, } from "./archive-limits.js";
|
|
8
8
|
export { ArchiveFormatError, type ArchiveFormatErrorCode } from "./archive-errors.js";
|
|
9
|
-
export { ArchiveSecurityError, type ArchiveSecurityErrorCode } from "./archive-
|
|
10
|
-
export { createArchiveSymlinkTraversalError,
|
|
9
|
+
export { ArchiveSecurityError, type ArchiveSecurityErrorCode } from "./archive-errors.js";
|
|
10
|
+
export { createArchiveSymlinkTraversalError, prepareArchiveDestinationDir, prepareArchiveOutputPath, withStagedArchiveDestination, } from "./archive-staging.js";
|
|
11
|
+
export { mergeExtractedTreeIntoDestination } from "./archive-merge.js";
|
|
11
12
|
export { createTarEntryPreflightChecker, type TarEntryInfo } from "./archive-plan.js";
|
|
12
|
-
export { loadZipArchiveWithPreflight
|
|
13
|
+
export { loadZipArchiveWithPreflight } from "./archive-zip-preflight.js";
|
|
14
|
+
export { readZipCentralDirectoryEntryCount } from "./archive-zip-count.js";
|
|
15
|
+
export type { ZipArchiveWithFiles } from "./archive-zip-loader.js";
|
|
13
16
|
export declare function extractArchive(params: ExtractArchiveOptions): Promise<void>;
|
|
14
17
|
export type InspectTarArchiveOptions = Pick<ExtractArchiveOptions, "archivePath" | "timeoutMs" | "limits" | "entryFilter" | "onFiltered">;
|
|
15
18
|
export type InspectedTarEntry = Readonly<Pick<ArchivePlanEntry, "path" | "kind" | "size">>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createTarEntryPlanner, createArchiveEntrySelector, resolveArchiveFilteredEntryPolicy, createArchiveEntryPlanner, } from "./archive-plan.js";
|
|
1
|
+
import { createTarEntryPlanner, createArchiveEntrySelector, resolveArchiveFilteredEntryPolicy, resolveArchiveEntryMode, createArchiveEntryPlanner, } from "./archive-plan.js";
|
|
2
2
|
import { inspectTar, replayTar } from "./archive-tar-stream.js";
|
|
3
3
|
import { runPinnedWriteHelper } from "./pinned-write.js";
|
|
4
4
|
import { constants as fsConstants } from "node:fs";
|
|
@@ -11,9 +11,7 @@ import { assertArchiveEntryCountWithinLimit, createByteBudgetTracker, createExtr
|
|
|
11
11
|
import { resolveArchiveKind } from "./archive-kind.js";
|
|
12
12
|
import { prepareArchiveDestinationGuard, preparePrivateArchiveOutputPath, } from "./archive-staging.js";
|
|
13
13
|
import { withStagedArchivePublication } from "./archive-merge.js";
|
|
14
|
-
import {
|
|
15
|
-
import { admittedZipEntries } from "./archive-zip-loader.js";
|
|
16
|
-
import { zipEntryKind, zipEntryDeclaredSize, zipEntryMode, } from "./archive-zip-entry.js";
|
|
14
|
+
import { loadZipArchiveWithAdmission } from "./archive-zip-preflight.js";
|
|
17
15
|
import { createZipIntegrityTransform, normalizeZipIntegrityError, } from "./archive-zip-integrity.js";
|
|
18
16
|
import { ArchiveSecurityError, ArchiveFormatError, isArchiveFormatErrorMessage, } from "./archive-errors.js";
|
|
19
17
|
import { stageArchiveFileForExtraction } from "./archive-input.js";
|
|
@@ -29,10 +27,12 @@ export { resolveArchiveKind, resolvePackedRootDir } from "./archive-kind.js";
|
|
|
29
27
|
export { readArchiveEntry } from "./archive-read.js";
|
|
30
28
|
export { ARCHIVE_LIMIT_ERROR_CODE, ArchiveLimitError, DEFAULT_MAX_ARCHIVE_BYTES_ZIP, DEFAULT_MAX_ENTRIES, DEFAULT_MAX_EXTRACTED_BYTES, DEFAULT_MAX_ENTRY_BYTES, DEFAULT_MAX_META_ENTRY_BYTES, DEFAULT_MAX_ENTRY_PATH_COMPONENTS, } from "./archive-limits.js";
|
|
31
29
|
export { ArchiveFormatError } from "./archive-errors.js";
|
|
32
|
-
export { ArchiveSecurityError } from "./archive-
|
|
33
|
-
export { createArchiveSymlinkTraversalError,
|
|
30
|
+
export { ArchiveSecurityError } from "./archive-errors.js";
|
|
31
|
+
export { createArchiveSymlinkTraversalError, prepareArchiveDestinationDir, prepareArchiveOutputPath, withStagedArchiveDestination, } from "./archive-staging.js";
|
|
32
|
+
export { mergeExtractedTreeIntoDestination } from "./archive-merge.js";
|
|
34
33
|
export { createTarEntryPreflightChecker } from "./archive-plan.js";
|
|
35
|
-
export { loadZipArchiveWithPreflight
|
|
34
|
+
export { loadZipArchiveWithPreflight } from "./archive-zip-preflight.js";
|
|
35
|
+
export { readZipCentralDirectoryEntryCount } from "./archive-zip-count.js";
|
|
36
36
|
const SUPPORTS_NOFOLLOW = process.platform !== "win32" && "O_NOFOLLOW" in fsConstants;
|
|
37
37
|
const OPEN_WRITE_CREATE_FLAGS = fsConstants.O_WRONLY |
|
|
38
38
|
fsConstants.O_CREAT |
|
|
@@ -49,7 +49,7 @@ async function readZipEntryStream(entry) {
|
|
|
49
49
|
async function writeZipFileEntry(params) {
|
|
50
50
|
params.deadline.check();
|
|
51
51
|
params.budget.startEntry();
|
|
52
|
-
const readable = await readZipEntryStream(params.entry);
|
|
52
|
+
const readable = await readZipEntryStream(params.record.entry);
|
|
53
53
|
const destinationPath = params.outPath;
|
|
54
54
|
let tempHandle = null;
|
|
55
55
|
let handleClosedByStream = false;
|
|
@@ -67,7 +67,7 @@ async function writeZipFileEntry(params) {
|
|
|
67
67
|
handleClosedByStream = true;
|
|
68
68
|
});
|
|
69
69
|
try {
|
|
70
|
-
await pipeline(readable, createExtractBudgetTransform({ onChunkBytes: params.budget.addBytes }), createZipIntegrityTransform(params.
|
|
70
|
+
await pipeline(readable, createExtractBudgetTransform({ onChunkBytes: params.budget.addBytes }), createZipIntegrityTransform(params.record), writable, { signal: params.deadline.signal });
|
|
71
71
|
}
|
|
72
72
|
catch (err) {
|
|
73
73
|
throw normalizeZipIntegrityError(createPipelineTimeoutError(err, params.deadline));
|
|
@@ -101,26 +101,29 @@ async function extractZip(params) {
|
|
|
101
101
|
deadline.check();
|
|
102
102
|
const buffer = await fs.readFile(params.archivePath, { signal: deadline.signal });
|
|
103
103
|
deadline.check();
|
|
104
|
-
const
|
|
104
|
+
const { entries } = await waitForDeadline(loadZipArchiveWithAdmission(buffer, limits), deadline);
|
|
105
105
|
deadline.check();
|
|
106
|
-
|
|
107
|
-
assertArchiveEntryCountWithinLimit(entries.length, limits);
|
|
106
|
+
assertArchiveEntryCountWithinLimit(entries.size, limits);
|
|
108
107
|
const budget = createByteBudgetTracker(limits);
|
|
109
108
|
await withStagedArchivePublication({ ...params, destinationGuard }, async (stagingDir) => {
|
|
110
109
|
const { select } = createArchiveEntrySelector({ ...params, rootDir: stagingDir });
|
|
111
110
|
const acceptedEntries = [];
|
|
112
|
-
for (const
|
|
111
|
+
for (const record of entries.values()) {
|
|
113
112
|
deadline.check();
|
|
114
|
-
const entryKind =
|
|
115
|
-
const relPath = select({ path:
|
|
113
|
+
const { entry, kind: entryKind, size, mode: archivedMode } = record;
|
|
114
|
+
const relPath = select({ path: record.name, kind: entryKind, size });
|
|
116
115
|
if (relPath === null)
|
|
117
116
|
continue;
|
|
118
117
|
if (entryKind === "symlink") {
|
|
119
|
-
throw new ArchiveSecurityError("entry-link", `zip entry is a link: ${
|
|
118
|
+
throw new ArchiveSecurityError("entry-link", `zip entry is a link: ${record.name}`);
|
|
120
119
|
}
|
|
121
120
|
if (entryKind === "other")
|
|
122
121
|
continue;
|
|
123
|
-
const mode =
|
|
122
|
+
const mode = resolveArchiveEntryMode({
|
|
123
|
+
kind: entry.dir ? "directory" : "file",
|
|
124
|
+
archivedMode,
|
|
125
|
+
policy: params.entryModes,
|
|
126
|
+
});
|
|
124
127
|
acceptedEntries.push({ path: relPath, kind: entry.dir ? "directory" : "file", mode });
|
|
125
128
|
const outPath = path.join(stagingDir, relPath);
|
|
126
129
|
await preparePrivateArchiveOutputPath({
|
|
@@ -128,12 +131,12 @@ async function extractZip(params) {
|
|
|
128
131
|
destinationRealDir: stagingDir,
|
|
129
132
|
relPath,
|
|
130
133
|
outPath,
|
|
131
|
-
originalPath:
|
|
134
|
+
originalPath: record.name,
|
|
132
135
|
isDirectory: entry.dir,
|
|
133
136
|
deadline,
|
|
134
137
|
});
|
|
135
138
|
if (!entry.dir) {
|
|
136
|
-
await writeZipFileEntry({
|
|
139
|
+
await writeZipFileEntry({ record, outPath, budget, deadline });
|
|
137
140
|
}
|
|
138
141
|
}
|
|
139
142
|
return acceptedEntries;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { replaceFileAtomic, replaceFileAtomicSync, type ReplaceFileAtomicFileSystem, type ReplaceFileAtomicOptions, type ReplaceFileAtomicResult, type ReplaceFileAtomicSyncFileSystem, type ReplaceFileAtomicSyncOptions, } from "./replace-file.js";
|
|
1
|
+
export { replaceFileAtomic, replaceFileAtomicSync, type ReplaceFileAtomicFileSystem, type ReplaceFileAtomicOptions, type ReplaceFileAtomicResult, type ReplaceFileAtomicDestinationState, type ReplaceFileAtomicSyncFileSystem, type ReplaceFileAtomicSyncOptions, } from "./replace-file.js";
|
|
2
2
|
export type { RenameIdentityPolicy } from "./pinned-write-types.js";
|
|
3
3
|
export type { ReplaceFileAtomicRestoreCleanup, ReplaceFileAtomicRestoreFailureDetails, ReplaceFileCopyFallbackRestorePolicy, ReplaceFileDestinationHardlinkPolicy, } from "./replace-file-copy-fallback.js";
|
|
4
4
|
export { writeTextAtomic, type WriteTextAtomicOptions } from "./text-atomic.js";
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import type { BigIntStats } from "node:fs";
|
|
2
2
|
import type { PinnedWriteParams, PublishedWriteIdentity } from "./pinned-write-types.js";
|
|
3
|
-
export type RootCopyPublicationReceipt = Readonly<{
|
|
3
|
+
export type RootCopyPublicationReceipt = Readonly<PublishedWriteIdentity & {
|
|
4
4
|
path: string;
|
|
5
|
-
dev: bigint;
|
|
6
|
-
ino: bigint;
|
|
7
5
|
}>;
|
|
8
6
|
export declare function createCopyPublicationObserver(path: string, notify?: (receipt: RootCopyPublicationReceipt) => void): {
|
|
9
7
|
onPublished(identity: PublishedWriteIdentity): void;
|
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
import { FsSafeError } from "./errors.js";
|
|
2
|
+
import { assertSynchronousCallbackResult } from "./mutation-authority.js";
|
|
2
3
|
export function createCopyPublicationObserver(path, notify) {
|
|
3
4
|
let rejected;
|
|
4
5
|
return {
|
|
5
6
|
onPublished(identity) {
|
|
6
7
|
const receipt = Object.freeze({ path, dev: identity.dev, ino: identity.ino });
|
|
7
8
|
try {
|
|
8
|
-
|
|
9
|
-
if (result !== null && (typeof result === "object" || typeof result === "function") &&
|
|
10
|
-
"then" in result && typeof result.then === "function") {
|
|
11
|
-
void Promise.resolve(result).catch(() => undefined);
|
|
12
|
-
throw new TypeError("onDestinationPublished must be synchronous");
|
|
13
|
-
}
|
|
9
|
+
assertSynchronousCallbackResult(notify?.(receipt), "onDestinationPublished");
|
|
14
10
|
}
|
|
15
11
|
catch (error) {
|
|
16
12
|
rejected = { error };
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { isPathInside } from "./path.js";
|
|
3
|
+
import { probePathCaseInsensitiveSync } from "./path-case.js";
|
|
4
|
+
import { observeMutationPath } from "./pinned-mutation-observation.js";
|
|
5
|
+
function foldedName(name) {
|
|
6
|
+
// Decompose before folding so combining marks precede an expanded Greek subscript.
|
|
7
|
+
// Default folding preserves dotless i even though its uppercase mapping is I.
|
|
8
|
+
return name.normalize("NFD").replace(/[^\u0131]+/gu, part => part.toLowerCase().toUpperCase().toLowerCase()).normalize("NFC");
|
|
9
|
+
}
|
|
10
|
+
function asciiCasePair(left, right) {
|
|
11
|
+
return /^[\x00-\x7f]*$/.test(left) && /^[\x00-\x7f]*$/.test(right) &&
|
|
12
|
+
left.toLowerCase() === right.toLowerCase();
|
|
13
|
+
}
|
|
14
|
+
/** Cache observations only within one synchronous policy check, never across mutations or callbacks. */
|
|
15
|
+
export function createMutationDenyMatcher() {
|
|
16
|
+
const observations = new Map();
|
|
17
|
+
const caseObservations = new Map();
|
|
18
|
+
const observe = (pathname) => {
|
|
19
|
+
if (!observations.has(pathname))
|
|
20
|
+
observations.set(pathname, observeMutationPath(pathname));
|
|
21
|
+
return observations.get(pathname);
|
|
22
|
+
};
|
|
23
|
+
const prospectiveInside = (parent, child) => {
|
|
24
|
+
const root = path.parse(parent).root;
|
|
25
|
+
if (root !== path.parse(child).root)
|
|
26
|
+
return false;
|
|
27
|
+
const left = parent.slice(root.length).split(path.sep);
|
|
28
|
+
const right = child.slice(root.length).split(path.sep).slice(0, left.length);
|
|
29
|
+
if (left.length !== right.length || !left.every((name, i) => foldedName(name) === foldedName(right[i]))) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
// Byte-identical relations were already handled without any observations.
|
|
33
|
+
if (left.every((name, i) => name === right[i]))
|
|
34
|
+
return false;
|
|
35
|
+
const alignedChild = path.join(root, ...right);
|
|
36
|
+
const a = observe(parent);
|
|
37
|
+
const b = observe(alignedChild);
|
|
38
|
+
if (!a || !b)
|
|
39
|
+
return true;
|
|
40
|
+
// Distinct existing ancestors are real objects, not prospective aliases.
|
|
41
|
+
if (a.canonicalAncestor !== b.canonicalAncestor ||
|
|
42
|
+
a.missingSegments.length === 0 || a.missingSegments.length !== b.missingSegments.length)
|
|
43
|
+
return false;
|
|
44
|
+
const missingLeft = a.missingSegments;
|
|
45
|
+
const missingRight = b.missingSegments;
|
|
46
|
+
if (!missingLeft.every((name, i) => foldedName(name) === foldedName(missingRight[i])))
|
|
47
|
+
return false;
|
|
48
|
+
const difference = missingLeft.findIndex((name, i) => name !== missingRight[i]);
|
|
49
|
+
if (difference === -1)
|
|
50
|
+
return true;
|
|
51
|
+
// A read-only ASCII observation can disprove aliasing at this existing parent.
|
|
52
|
+
// It cannot prove Unicode sensitivity or the behavior of a future directory.
|
|
53
|
+
if (difference === 0 && asciiCasePair(missingLeft[0], missingRight[0])) {
|
|
54
|
+
if (!caseObservations.has(a.canonicalAncestor)) {
|
|
55
|
+
caseObservations.set(a.canonicalAncestor, probePathCaseInsensitiveSync(path.join(a.canonicalAncestor, missingLeft[0]), { allowTemporaryProbe: false }));
|
|
56
|
+
}
|
|
57
|
+
if (caseObservations.get(a.canonicalAncestor) === false)
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
// Suffix probing writes directories. Policy admission has no authority for
|
|
61
|
+
// those side effects, so unproven case/normalization equivalence fails closed.
|
|
62
|
+
return true;
|
|
63
|
+
};
|
|
64
|
+
return (target, denied, prefix, protectAncestors = false) => {
|
|
65
|
+
if ((isPathInside(denied, target) && (prefix || isPathInside(target, denied))) ||
|
|
66
|
+
(protectAncestors && isPathInside(target, denied)))
|
|
67
|
+
return true;
|
|
68
|
+
return ((prefix || target.split(path.sep).length === denied.split(path.sep).length) &&
|
|
69
|
+
prospectiveInside(denied, target)) || (protectAncestors && prospectiveInside(target, denied));
|
|
70
|
+
};
|
|
71
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { createMutationDenyMatcher } from "./deny-mutation-match.js";
|
|
3
4
|
import { FsSafeError } from "./errors.js";
|
|
4
|
-
import { assertNoNulPathInput, isNotFoundPathError
|
|
5
|
+
import { assertNoNulPathInput, isNotFoundPathError } from "./path.js";
|
|
5
6
|
import { realpathSync } from "./realpath.js";
|
|
6
7
|
import { resolveExistingAncestor } from "./root-path-existing.js";
|
|
7
8
|
import { assertNoWindowsPathAlias, pathForWindowsFilesystem, resolvePathPreservingWindowsRoot, } from "./windows-path-alias.js";
|
|
@@ -65,6 +66,7 @@ export function assertMutationNotDenied(filePath, policy, options = {}, mode = "
|
|
|
65
66
|
const strict = mode === "sync-root-lock";
|
|
66
67
|
const comparablePaths = strict ? strictMutationComparablePaths : resolveMutationComparablePaths;
|
|
67
68
|
const targets = comparablePaths(filePath);
|
|
69
|
+
const matches = createMutationDenyMatcher();
|
|
68
70
|
// Validate one complete phase at a time. A paths denial must not read or
|
|
69
71
|
// canonicalize prefixes, and invalid later paths retain validation precedence.
|
|
70
72
|
for (const kind of ["paths", "prefixes"]) {
|
|
@@ -72,8 +74,7 @@ export function assertMutationNotDenied(filePath, policy, options = {}, mode = "
|
|
|
72
74
|
const deniedPaths = comparablePaths(entry);
|
|
73
75
|
for (const target of targets) {
|
|
74
76
|
for (const denied of deniedPaths) {
|
|
75
|
-
if ((
|
|
76
|
-
(options.protectAncestors === true && isPathInside(target, denied))) {
|
|
77
|
+
if (matches(target, denied, kind === "prefixes", options.protectAncestors)) {
|
|
77
78
|
throw new FsSafeError("denied-path", "path is denied by denyMutations policy");
|
|
78
79
|
}
|
|
79
80
|
}
|
|
@@ -36,7 +36,6 @@ export declare function createNearestExistingDirectoryGuard(rootReal: string, ta
|
|
|
36
36
|
export declare function createNearestExistingDirectoryGuard(rootReal: string, targetPath: string, options: {
|
|
37
37
|
bigint: boolean;
|
|
38
38
|
}): Promise<AnyAsyncDirectoryGuard>;
|
|
39
|
-
export declare function createNearestExistingSyncDirectoryGuard(rootReal: string, targetPath: string): SyncDirectoryGuard;
|
|
40
39
|
export declare function inspectDirectoryIdentity(dir: string, expected?: Pick<BigIntStats, "dev" | "ino">): Promise<BigIntStats>;
|
|
41
40
|
export declare function observeDirectoryIdentitySync(dir: string, options: {
|
|
42
41
|
bigint: true;
|
|
@@ -84,9 +84,6 @@ function assertDirectoryGuard(guard, mode) {
|
|
|
84
84
|
export async function createNearestExistingDirectoryGuard(rootReal, targetPath, options = { bigint: false }) {
|
|
85
85
|
return nearestExistingDirectoryGuard(rootReal, targetPath, "native", options);
|
|
86
86
|
}
|
|
87
|
-
export function createNearestExistingSyncDirectoryGuard(rootReal, targetPath) {
|
|
88
|
-
return nearestExistingDirectoryGuard(rootReal, targetPath, "normalized");
|
|
89
|
-
}
|
|
90
87
|
function nearestExistingDirectoryGuard(rootReal, targetPath, mode, options) {
|
|
91
88
|
assertNoWindowsPathAlias(rootReal, "filesystem");
|
|
92
89
|
assertNoWindowsPathAlias(targetPath, "filesystem");
|
|
@@ -1,5 +1,23 @@
|
|
|
1
|
-
import { type BigIntStats } from "node:fs";
|
|
2
|
-
|
|
1
|
+
import { type BigIntStats, type Stats } from "node:fs";
|
|
2
|
+
export type DirectoryModeChecks = {
|
|
3
|
+
check?: () => void;
|
|
4
|
+
beforeChmod?: () => Promise<void>;
|
|
5
|
+
};
|
|
6
|
+
export type DirectoryModeOwner = {
|
|
7
|
+
verify(check?: () => void): Promise<void>;
|
|
8
|
+
apply(mode: number, checks?: DirectoryModeChecks): Promise<void>;
|
|
9
|
+
close(): Promise<void>;
|
|
10
|
+
};
|
|
11
|
+
export declare function assertOwnedDirectory(expected: Stats | BigIntStats, actual: Stats | BigIntStats): void;
|
|
12
|
+
/** Serializes use and close: even a queued path-based fd operation retains its descriptor. */
|
|
13
|
+
export declare function ownDirectoryMode(params: {
|
|
14
|
+
inspect: () => Promise<number>;
|
|
15
|
+
chmod: (mode: number) => Promise<void>;
|
|
16
|
+
prepareChmod?: () => Promise<void>;
|
|
17
|
+
verifyChmod?: () => Promise<void>;
|
|
18
|
+
close: () => Promise<void>;
|
|
19
|
+
ignoreChmodError?: boolean;
|
|
20
|
+
}): DirectoryModeOwner;
|
|
3
21
|
/** Darwin descriptor inspection avoids requesting directory-content reads. */
|
|
4
22
|
export declare function nodeDarwinDirectoryMetadataFlags(): number;
|
|
5
23
|
export declare function nodeDirectorySearchOnlyFlags(): {
|
|
@@ -3,7 +3,83 @@ import fs from "node:fs/promises";
|
|
|
3
3
|
import { FsSafeError } from "./errors.js";
|
|
4
4
|
import { inspectDirectoryIdentity, inspectDirectoryIdentitySync } from "./directory-guard.js";
|
|
5
5
|
import { inspectFileIdentity, inspectFileIdentitySync } from "./strict-file-identity.js";
|
|
6
|
-
import {
|
|
6
|
+
import { sameFileIdentityForCleanup } from "./file-identity.js";
|
|
7
|
+
export function assertOwnedDirectory(expected, actual) {
|
|
8
|
+
if (actual.isSymbolicLink() || !actual.isDirectory()) {
|
|
9
|
+
throw new FsSafeError("not-file", "directory mode target must be a real directory");
|
|
10
|
+
}
|
|
11
|
+
if (!sameFileIdentityForCleanup(expected, actual)) {
|
|
12
|
+
throw new FsSafeError("path-mismatch", "directory changed before its mode could be applied");
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/** Serializes use and close: even a queued path-based fd operation retains its descriptor. */
|
|
16
|
+
export function ownDirectoryMode(params) {
|
|
17
|
+
let pending = Promise.resolve();
|
|
18
|
+
let closing;
|
|
19
|
+
const enqueue = (run) => {
|
|
20
|
+
if (closing)
|
|
21
|
+
return Promise.reject(new FsSafeError("path-mismatch", "directory mode owner is closed"));
|
|
22
|
+
const operation = pending.then(run);
|
|
23
|
+
pending = operation.catch(() => undefined);
|
|
24
|
+
return operation;
|
|
25
|
+
};
|
|
26
|
+
return {
|
|
27
|
+
verify: (check) => enqueue(async () => {
|
|
28
|
+
check?.();
|
|
29
|
+
await params.inspect();
|
|
30
|
+
check?.();
|
|
31
|
+
}),
|
|
32
|
+
apply: (mode, checks = {}) => enqueue(async () => {
|
|
33
|
+
// inspect() reports permission bits only; chmod ignores file-type bits,
|
|
34
|
+
// so tolerate raw stat modes (e.g. S_IFDIR | 0o755) by masking up front.
|
|
35
|
+
mode &= 0o7777;
|
|
36
|
+
checks.check?.();
|
|
37
|
+
const currentMode = await params.inspect();
|
|
38
|
+
checks.check?.();
|
|
39
|
+
if (currentMode === mode && !checks.beforeChmod && !checks.check)
|
|
40
|
+
return;
|
|
41
|
+
if (currentMode !== mode) {
|
|
42
|
+
await params.prepareChmod?.();
|
|
43
|
+
checks.check?.();
|
|
44
|
+
}
|
|
45
|
+
await checks.beforeChmod?.();
|
|
46
|
+
checks.check?.();
|
|
47
|
+
// Hooks/ancestor checks can yield; recheck the original named association.
|
|
48
|
+
await params.inspect();
|
|
49
|
+
checks.check?.();
|
|
50
|
+
let dispatchDeadlineFailure;
|
|
51
|
+
if (currentMode !== mode) {
|
|
52
|
+
checks.check?.();
|
|
53
|
+
try {
|
|
54
|
+
await params.chmod(mode);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
if (!params.ignoreChmodError)
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
// Expiry cannot release the fd while post-dispatch verification is pending.
|
|
61
|
+
try {
|
|
62
|
+
checks.check?.();
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
dispatchDeadlineFailure = { error };
|
|
66
|
+
}
|
|
67
|
+
await params.verifyChmod?.();
|
|
68
|
+
}
|
|
69
|
+
const finalMode = await params.inspect();
|
|
70
|
+
if (dispatchDeadlineFailure)
|
|
71
|
+
throw dispatchDeadlineFailure.error;
|
|
72
|
+
checks.check?.();
|
|
73
|
+
if (!params.ignoreChmodError && finalMode !== mode) {
|
|
74
|
+
throw new FsSafeError("path-mismatch", "directory final mode could not be verified");
|
|
75
|
+
}
|
|
76
|
+
}),
|
|
77
|
+
close() {
|
|
78
|
+
closing ??= pending.then(params.close);
|
|
79
|
+
return closing;
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
7
83
|
/** Darwin descriptor inspection avoids requesting directory-content reads. */
|
|
8
84
|
export function nodeDarwinDirectoryMetadataFlags() {
|
|
9
85
|
if (process.platform !== "darwin" || (process.arch !== "x64" && process.arch !== "arm64")) {
|