@backblaze-labs/b2-sdk 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +110 -5
- package/README.md +144 -33
- package/dist/_virtual/_b2-sdk-version-json.cjs +4 -0
- package/dist/_virtual/_b2-sdk-version-json.js +4 -0
- package/dist/auth/account-info.d.cts +32 -0
- package/dist/auth/account-info.d.cts.map +1 -1
- package/dist/auth/account-info.d.ts +32 -0
- package/dist/auth/account-info.d.ts.map +1 -1
- package/dist/auth/file.cjs +408 -207
- package/dist/auth/file.cjs.map +1 -1
- package/dist/auth/file.d.cts +77 -3
- package/dist/auth/file.d.cts.map +1 -1
- package/dist/auth/file.d.ts +77 -3
- package/dist/auth/file.d.ts.map +1 -1
- package/dist/auth/file.js +407 -207
- package/dist/auth/file.js.map +1 -1
- package/dist/auth/in-memory.cjs +212 -183
- package/dist/auth/in-memory.cjs.map +1 -1
- package/dist/auth/in-memory.d.cts +8 -0
- package/dist/auth/in-memory.d.cts.map +1 -1
- package/dist/auth/in-memory.d.ts +8 -0
- package/dist/auth/in-memory.d.ts.map +1 -1
- package/dist/auth/in-memory.js +211 -182
- package/dist/auth/in-memory.js.map +1 -1
- package/dist/auth/index.cjs +7 -9
- package/dist/auth/index.d.cts +3 -2
- package/dist/auth/index.d.cts.map +1 -1
- package/dist/auth/index.d.ts +3 -2
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +2 -8
- package/dist/auth/realms.cjs +80 -7
- package/dist/auth/realms.cjs.map +1 -1
- package/dist/auth/realms.d.cts +27 -4
- package/dist/auth/realms.d.cts.map +1 -1
- package/dist/auth/realms.d.ts +27 -4
- package/dist/auth/realms.d.ts.map +1 -1
- package/dist/auth/realms.js +80 -9
- package/dist/auth/realms.js.map +1 -1
- package/dist/auth/upload-url-pool.cjs +55 -51
- package/dist/auth/upload-url-pool.cjs.map +1 -1
- package/dist/auth/upload-url-pool.js +55 -51
- package/dist/auth/upload-url-pool.js.map +1 -1
- package/dist/bucket.cjs +785 -787
- package/dist/bucket.cjs.map +1 -1
- package/dist/bucket.d.cts +35 -47
- package/dist/bucket.d.cts.map +1 -1
- package/dist/bucket.d.ts +35 -47
- package/dist/bucket.d.ts.map +1 -1
- package/dist/bucket.js +780 -782
- package/dist/bucket.js.map +1 -1
- package/dist/client.cjs +246 -228
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +25 -17
- package/dist/client.d.cts.map +1 -1
- package/dist/client.d.ts +25 -17
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +243 -225
- package/dist/client.js.map +1 -1
- package/dist/copy/large.cjs +114 -71
- package/dist/copy/large.cjs.map +1 -1
- package/dist/copy/large.d.cts +6 -0
- package/dist/copy/large.d.cts.map +1 -1
- package/dist/copy/large.d.ts +6 -0
- package/dist/copy/large.d.ts.map +1 -1
- package/dist/copy/large.js +112 -69
- package/dist/copy/large.js.map +1 -1
- package/dist/download/checksum.cjs +89 -0
- package/dist/download/checksum.cjs.map +1 -0
- package/dist/download/checksum.d.cts +40 -0
- package/dist/download/checksum.d.cts.map +1 -0
- package/dist/download/checksum.d.ts +40 -0
- package/dist/download/checksum.d.ts.map +1 -0
- package/dist/download/checksum.js +87 -0
- package/dist/download/checksum.js.map +1 -0
- package/dist/download/parallel.cjs +214 -118
- package/dist/download/parallel.cjs.map +1 -1
- package/dist/download/parallel.d.cts +5 -1
- package/dist/download/parallel.d.cts.map +1 -1
- package/dist/download/parallel.d.ts +5 -1
- package/dist/download/parallel.d.ts.map +1 -1
- package/dist/download/parallel.js +212 -116
- package/dist/download/parallel.js.map +1 -1
- package/dist/download/single.cjs +188 -97
- package/dist/download/single.cjs.map +1 -1
- package/dist/download/single.d.cts +6 -1
- package/dist/download/single.d.cts.map +1 -1
- package/dist/download/single.d.ts +6 -1
- package/dist/download/single.d.ts.map +1 -1
- package/dist/download/single.js +186 -98
- package/dist/download/single.js.map +1 -1
- package/dist/errors/index.cjs +699 -243
- package/dist/errors/index.cjs.map +1 -1
- package/dist/errors/index.d.cts +285 -82
- package/dist/errors/index.d.cts.map +1 -1
- package/dist/errors/index.d.ts +285 -82
- package/dist/errors/index.d.ts.map +1 -1
- package/dist/errors/index.js +678 -261
- package/dist/errors/index.js.map +1 -1
- package/dist/http/retry.cjs +45 -28
- package/dist/http/retry.cjs.map +1 -1
- package/dist/http/retry.d.cts +15 -2
- package/dist/http/retry.d.cts.map +1 -1
- package/dist/http/retry.d.ts +15 -2
- package/dist/http/retry.d.ts.map +1 -1
- package/dist/http/retry.js +46 -31
- package/dist/http/retry.js.map +1 -1
- package/dist/http/transport.cjs +438 -140
- package/dist/http/transport.cjs.map +1 -1
- package/dist/http/transport.d.cts +21 -2
- package/dist/http/transport.d.cts.map +1 -1
- package/dist/http/transport.d.ts +21 -2
- package/dist/http/transport.d.ts.map +1 -1
- package/dist/http/transport.js +437 -140
- package/dist/http/transport.js.map +1 -1
- package/dist/http/url-guard.cjs +154 -89
- package/dist/http/url-guard.cjs.map +1 -1
- package/dist/http/url-guard.d.cts +25 -3
- package/dist/http/url-guard.d.cts.map +1 -1
- package/dist/http/url-guard.d.ts +25 -3
- package/dist/http/url-guard.d.ts.map +1 -1
- package/dist/http/url-guard.js +152 -90
- package/dist/http/url-guard.js.map +1 -1
- package/dist/http/user-agent.cjs +84 -44
- package/dist/http/user-agent.cjs.map +1 -1
- package/dist/http/user-agent.js +84 -46
- package/dist/http/user-agent.js.map +1 -1
- package/dist/index.cjs +101 -77
- package/dist/index.d.cts +27 -21
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +27 -21
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -71
- package/dist/internal/b2-naming.cjs +66 -0
- package/dist/internal/b2-naming.cjs.map +1 -0
- package/dist/internal/b2-naming.d.cts +43 -0
- package/dist/internal/b2-naming.d.cts.map +1 -0
- package/dist/internal/b2-naming.d.ts +43 -0
- package/dist/internal/b2-naming.d.ts.map +1 -0
- package/dist/internal/b2-naming.js +60 -0
- package/dist/internal/b2-naming.js.map +1 -0
- package/dist/internal/upload-retry-options.cjs +21 -0
- package/dist/internal/upload-retry-options.cjs.map +1 -0
- package/dist/internal/upload-retry-options.d.cts +12 -0
- package/dist/internal/upload-retry-options.d.cts.map +1 -0
- package/dist/internal/upload-retry-options.d.ts +12 -0
- package/dist/internal/upload-retry-options.d.ts.map +1 -0
- package/dist/internal/upload-retry-options.js +21 -0
- package/dist/internal/upload-retry-options.js.map +1 -0
- package/dist/internal/url-redaction.cjs +31 -0
- package/dist/internal/url-redaction.cjs.map +1 -0
- package/dist/internal/url-redaction.d.cts +17 -0
- package/dist/internal/url-redaction.d.cts.map +1 -0
- package/dist/internal/url-redaction.d.ts +17 -0
- package/dist/internal/url-redaction.d.ts.map +1 -0
- package/dist/internal/url-redaction.js +31 -0
- package/dist/internal/url-redaction.js.map +1 -0
- package/dist/notifications/index.cjs +4 -6
- package/dist/notifications/index.d.cts +1 -1
- package/dist/notifications/index.d.cts.map +1 -1
- package/dist/notifications/index.d.ts +1 -1
- package/dist/notifications/index.d.ts.map +1 -1
- package/dist/notifications/index.js +1 -6
- package/dist/notifications/webhook.cjs +195 -85
- package/dist/notifications/webhook.cjs.map +1 -1
- package/dist/notifications/webhook.d.cts.map +1 -1
- package/dist/notifications/webhook.d.ts.map +1 -1
- package/dist/notifications/webhook.js +195 -87
- package/dist/notifications/webhook.js.map +1 -1
- package/dist/object.cjs +253 -210
- package/dist/object.cjs.map +1 -1
- package/dist/object.d.cts +9 -55
- package/dist/object.d.cts.map +1 -1
- package/dist/object.d.ts +9 -55
- package/dist/object.d.ts.map +1 -1
- package/dist/object.js +249 -206
- package/dist/object.js.map +1 -1
- package/dist/raw/encoding.cjs +74 -35
- package/dist/raw/encoding.cjs.map +1 -1
- package/dist/raw/encoding.js +74 -38
- package/dist/raw/encoding.js.map +1 -1
- package/dist/raw/index.cjs +678 -587
- package/dist/raw/index.cjs.map +1 -1
- package/dist/raw/index.d.cts +121 -18
- package/dist/raw/index.d.cts.map +1 -1
- package/dist/raw/index.d.ts +121 -18
- package/dist/raw/index.d.ts.map +1 -1
- package/dist/raw/index.js +674 -589
- package/dist/raw/index.js.map +1 -1
- package/dist/s3/index.cjs +355 -18
- package/dist/s3/index.cjs.map +1 -1
- package/dist/s3/index.d.cts +233 -5
- package/dist/s3/index.d.cts.map +1 -1
- package/dist/s3/index.d.ts +233 -5
- package/dist/s3/index.d.ts.map +1 -1
- package/dist/s3/index.js +351 -22
- package/dist/s3/index.js.map +1 -1
- package/dist/s3/sigv4.cjs +149 -0
- package/dist/s3/sigv4.cjs.map +1 -0
- package/dist/s3/sigv4.d.cts +43 -0
- package/dist/s3/sigv4.d.cts.map +1 -0
- package/dist/s3/sigv4.d.ts +43 -0
- package/dist/s3/sigv4.d.ts.map +1 -0
- package/dist/s3/sigv4.js +148 -0
- package/dist/s3/sigv4.js.map +1 -0
- package/dist/s3/validation.cjs +69 -0
- package/dist/s3/validation.cjs.map +1 -0
- package/dist/s3/validation.d.cts +43 -0
- package/dist/s3/validation.d.cts.map +1 -0
- package/dist/s3/validation.d.ts +43 -0
- package/dist/s3/validation.d.ts.map +1 -0
- package/dist/s3/validation.js +66 -0
- package/dist/s3/validation.js.map +1 -0
- package/dist/simulator/capabilities.cjs +63 -48
- package/dist/simulator/capabilities.cjs.map +1 -1
- package/dist/simulator/capabilities.js +63 -49
- package/dist/simulator/capabilities.js.map +1 -1
- package/dist/simulator/index.cjs +2124 -1548
- package/dist/simulator/index.cjs.map +1 -1
- package/dist/simulator/index.d.cts +79 -11
- package/dist/simulator/index.d.cts.map +1 -1
- package/dist/simulator/index.d.ts +79 -11
- package/dist/simulator/index.d.ts.map +1 -1
- package/dist/simulator/index.js +2112 -1546
- package/dist/simulator/index.js.map +1 -1
- package/dist/simulator/validation.cjs +191 -153
- package/dist/simulator/validation.cjs.map +1 -1
- package/dist/simulator/validation.d.cts +3 -21
- package/dist/simulator/validation.d.cts.map +1 -1
- package/dist/simulator/validation.d.ts +3 -21
- package/dist/simulator/validation.d.ts.map +1 -1
- package/dist/simulator/validation.js +188 -162
- package/dist/simulator/validation.js.map +1 -1
- package/dist/streams/collect.cjs +74 -24
- package/dist/streams/collect.cjs.map +1 -1
- package/dist/streams/collect.d.cts +14 -1
- package/dist/streams/collect.d.cts.map +1 -1
- package/dist/streams/collect.d.ts +14 -1
- package/dist/streams/collect.d.ts.map +1 -1
- package/dist/streams/collect.js +74 -25
- package/dist/streams/collect.js.map +1 -1
- package/dist/streams/file-source.cjs +287 -0
- package/dist/streams/file-source.cjs.map +1 -0
- package/dist/streams/file-source.d.cts +96 -0
- package/dist/streams/file-source.d.cts.map +1 -0
- package/dist/streams/file-source.d.ts +96 -0
- package/dist/streams/file-source.d.ts.map +1 -0
- package/dist/streams/file-source.js +286 -0
- package/dist/streams/file-source.js.map +1 -0
- package/dist/streams/hash.cjs +207 -115
- package/dist/streams/hash.cjs.map +1 -1
- package/dist/streams/hash.d.cts +5 -4
- package/dist/streams/hash.d.cts.map +1 -1
- package/dist/streams/hash.d.ts +5 -4
- package/dist/streams/hash.d.ts.map +1 -1
- package/dist/streams/hash.js +208 -95
- package/dist/streams/hash.js.map +1 -1
- package/dist/streams/index.cjs +12 -12
- package/dist/streams/index.d.cts +3 -3
- package/dist/streams/index.d.cts.map +1 -1
- package/dist/streams/index.d.ts +3 -3
- package/dist/streams/index.d.ts.map +1 -1
- package/dist/streams/index.js +2 -10
- package/dist/streams/progress.cjs +60 -46
- package/dist/streams/progress.cjs.map +1 -1
- package/dist/streams/progress.js +60 -46
- package/dist/streams/progress.js.map +1 -1
- package/dist/streams/source.cjs +316 -146
- package/dist/streams/source.cjs.map +1 -1
- package/dist/streams/source.d.cts +56 -18
- package/dist/streams/source.d.cts.map +1 -1
- package/dist/streams/source.d.ts +56 -18
- package/dist/streams/source.d.ts.map +1 -1
- package/dist/streams/source.js +312 -149
- package/dist/streams/source.js.map +1 -1
- package/dist/sync/actions/index.cjs +236 -184
- package/dist/sync/actions/index.cjs.map +1 -1
- package/dist/sync/actions/index.d.cts +29 -21
- package/dist/sync/actions/index.d.cts.map +1 -1
- package/dist/sync/actions/index.d.ts +29 -21
- package/dist/sync/actions/index.d.ts.map +1 -1
- package/dist/sync/actions/index.js +236 -190
- package/dist/sync/actions/index.js.map +1 -1
- package/dist/sync/b2-sha1-reader.cjs +148 -0
- package/dist/sync/b2-sha1-reader.cjs.map +1 -0
- package/dist/sync/b2-sha1-reader.d.cts +58 -0
- package/dist/sync/b2-sha1-reader.d.cts.map +1 -0
- package/dist/sync/b2-sha1-reader.d.ts +58 -0
- package/dist/sync/b2-sha1-reader.d.ts.map +1 -0
- package/dist/sync/b2-sha1-reader.js +145 -0
- package/dist/sync/b2-sha1-reader.js.map +1 -0
- package/dist/sync/download-staging.cjs +265 -0
- package/dist/sync/download-staging.cjs.map +1 -0
- package/dist/sync/download-staging.d.cts +54 -0
- package/dist/sync/download-staging.d.cts.map +1 -0
- package/dist/sync/download-staging.d.ts +54 -0
- package/dist/sync/download-staging.d.ts.map +1 -0
- package/dist/sync/download-staging.js +259 -0
- package/dist/sync/download-staging.js.map +1 -0
- package/dist/sync/filesystem-errors.cjs +32 -0
- package/dist/sync/filesystem-errors.cjs.map +1 -0
- package/dist/sync/filesystem-errors.d.cts +8 -0
- package/dist/sync/filesystem-errors.d.cts.map +1 -0
- package/dist/sync/filesystem-errors.d.ts +8 -0
- package/dist/sync/filesystem-errors.d.ts.map +1 -0
- package/dist/sync/filesystem-errors.js +32 -0
- package/dist/sync/filesystem-errors.js.map +1 -0
- package/dist/sync/filters.cjs +217 -0
- package/dist/sync/filters.cjs.map +1 -0
- package/dist/sync/filters.d.cts +51 -0
- package/dist/sync/filters.d.cts.map +1 -0
- package/dist/sync/filters.d.ts +51 -0
- package/dist/sync/filters.d.ts.map +1 -0
- package/dist/sync/filters.js +213 -0
- package/dist/sync/filters.js.map +1 -0
- package/dist/sync/index.cjs +39 -22
- package/dist/sync/index.d.cts +14 -9
- package/dist/sync/index.d.cts.map +1 -1
- package/dist/sync/index.d.ts +14 -9
- package/dist/sync/index.d.ts.map +1 -1
- package/dist/sync/index.js +9 -20
- package/dist/sync/local-file-identity.cjs +61 -0
- package/dist/sync/local-file-identity.cjs.map +1 -0
- package/dist/sync/local-file-identity.d.cts +37 -0
- package/dist/sync/local-file-identity.d.cts.map +1 -0
- package/dist/sync/local-file-identity.d.ts +37 -0
- package/dist/sync/local-file-identity.d.ts.map +1 -0
- package/dist/sync/local-file-identity.js +60 -0
- package/dist/sync/local-file-identity.js.map +1 -0
- package/dist/sync/local-file-io.cjs +364 -0
- package/dist/sync/local-file-io.cjs.map +1 -0
- package/dist/sync/local-file-io.d.cts +75 -0
- package/dist/sync/local-file-io.d.cts.map +1 -0
- package/dist/sync/local-file-io.d.ts +75 -0
- package/dist/sync/local-file-io.d.ts.map +1 -0
- package/dist/sync/local-file-io.js +360 -0
- package/dist/sync/local-file-io.js.map +1 -0
- package/dist/sync/local-filesystem-root.cjs +27 -0
- package/dist/sync/local-filesystem-root.cjs.map +1 -0
- package/dist/sync/local-filesystem-root.d.cts +18 -0
- package/dist/sync/local-filesystem-root.d.cts.map +1 -0
- package/dist/sync/local-filesystem-root.d.ts +18 -0
- package/dist/sync/local-filesystem-root.d.ts.map +1 -0
- package/dist/sync/local-filesystem-root.js +26 -0
- package/dist/sync/local-filesystem-root.js.map +1 -0
- package/dist/sync/local-sha1.cjs +119 -0
- package/dist/sync/local-sha1.cjs.map +1 -0
- package/dist/sync/local-sha1.d.cts +39 -0
- package/dist/sync/local-sha1.d.cts.map +1 -0
- package/dist/sync/local-sha1.d.ts +39 -0
- package/dist/sync/local-sha1.d.ts.map +1 -0
- package/dist/sync/local-sha1.js +117 -0
- package/dist/sync/local-sha1.js.map +1 -0
- package/dist/sync/pairing.cjs +118 -29
- package/dist/sync/pairing.cjs.map +1 -1
- package/dist/sync/pairing.d.cts +7 -2
- package/dist/sync/pairing.d.cts.map +1 -1
- package/dist/sync/pairing.d.ts +7 -2
- package/dist/sync/pairing.d.ts.map +1 -1
- package/dist/sync/pairing.js +120 -31
- package/dist/sync/pairing.js.map +1 -1
- package/dist/sync/path-order.cjs +30 -0
- package/dist/sync/path-order.cjs.map +1 -0
- package/dist/sync/path-order.d.cts +28 -0
- package/dist/sync/path-order.d.cts.map +1 -0
- package/dist/sync/path-order.d.ts +28 -0
- package/dist/sync/path-order.d.ts.map +1 -0
- package/dist/sync/path-order.js +29 -0
- package/dist/sync/path-order.js.map +1 -0
- package/dist/sync/path-safety.cjs +111 -0
- package/dist/sync/path-safety.cjs.map +1 -0
- package/dist/sync/path-safety.d.cts +78 -0
- package/dist/sync/path-safety.d.cts.map +1 -0
- package/dist/sync/path-safety.d.ts +78 -0
- package/dist/sync/path-safety.d.ts.map +1 -0
- package/dist/sync/path-safety.js +105 -0
- package/dist/sync/path-safety.js.map +1 -0
- package/dist/sync/paths.d.cts +19 -0
- package/dist/sync/paths.d.cts.map +1 -0
- package/dist/sync/paths.d.ts +19 -0
- package/dist/sync/paths.d.ts.map +1 -0
- package/dist/sync/policies/compare.cjs +389 -11
- package/dist/sync/policies/compare.cjs.map +1 -1
- package/dist/sync/policies/compare.d.cts +100 -2
- package/dist/sync/policies/compare.d.cts.map +1 -1
- package/dist/sync/policies/compare.d.ts +100 -2
- package/dist/sync/policies/compare.d.ts.map +1 -1
- package/dist/sync/policies/compare.js +387 -13
- package/dist/sync/policies/compare.js.map +1 -1
- package/dist/sync/policies/index.cjs +76 -65
- package/dist/sync/policies/index.cjs.map +1 -1
- package/dist/sync/policies/index.d.cts +35 -6
- package/dist/sync/policies/index.d.cts.map +1 -1
- package/dist/sync/policies/index.d.ts +35 -6
- package/dist/sync/policies/index.d.ts.map +1 -1
- package/dist/sync/policies/index.js +76 -65
- package/dist/sync/policies/index.js.map +1 -1
- package/dist/sync/prefix.cjs +96 -0
- package/dist/sync/prefix.cjs.map +1 -0
- package/dist/sync/prefix.d.cts +55 -0
- package/dist/sync/prefix.d.cts.map +1 -0
- package/dist/sync/prefix.d.ts +55 -0
- package/dist/sync/prefix.d.ts.map +1 -0
- package/dist/sync/prefix.js +92 -0
- package/dist/sync/prefix.js.map +1 -0
- package/dist/sync/regexp-safety.cjs +192 -0
- package/dist/sync/regexp-safety.cjs.map +1 -0
- package/dist/sync/regexp-safety.d.cts +29 -0
- package/dist/sync/regexp-safety.d.cts.map +1 -0
- package/dist/sync/regexp-safety.d.ts +29 -0
- package/dist/sync/regexp-safety.d.ts.map +1 -0
- package/dist/sync/regexp-safety.js +190 -0
- package/dist/sync/regexp-safety.js.map +1 -0
- package/dist/sync/scan-events.cjs +33 -0
- package/dist/sync/scan-events.cjs.map +1 -0
- package/dist/sync/scan-events.d.cts +17 -0
- package/dist/sync/scan-events.d.cts.map +1 -0
- package/dist/sync/scan-events.d.ts +17 -0
- package/dist/sync/scan-events.d.ts.map +1 -0
- package/dist/sync/scan-events.js +32 -0
- package/dist/sync/scan-events.js.map +1 -0
- package/dist/sync/scan-limit.cjs +33 -0
- package/dist/sync/scan-limit.cjs.map +1 -0
- package/dist/sync/scan-limit.d.cts +21 -0
- package/dist/sync/scan-limit.d.cts.map +1 -0
- package/dist/sync/scan-limit.d.ts +21 -0
- package/dist/sync/scan-limit.d.ts.map +1 -0
- package/dist/sync/scan-limit.js +31 -0
- package/dist/sync/scan-limit.js.map +1 -0
- package/dist/sync/scanners/b2.cjs +239 -55
- package/dist/sync/scanners/b2.cjs.map +1 -1
- package/dist/sync/scanners/b2.d.cts +26 -7
- package/dist/sync/scanners/b2.d.cts.map +1 -1
- package/dist/sync/scanners/b2.d.ts +26 -7
- package/dist/sync/scanners/b2.d.ts.map +1 -1
- package/dist/sync/scanners/b2.js +239 -55
- package/dist/sync/scanners/b2.js.map +1 -1
- package/dist/sync/scanners/local.cjs +215 -56
- package/dist/sync/scanners/local.cjs.map +1 -1
- package/dist/sync/scanners/local.d.cts +22 -7
- package/dist/sync/scanners/local.d.cts.map +1 -1
- package/dist/sync/scanners/local.d.ts +22 -7
- package/dist/sync/scanners/local.d.ts.map +1 -1
- package/dist/sync/scanners/local.js +216 -57
- package/dist/sync/scanners/local.js.map +1 -1
- package/dist/sync/sha1-metadata.cjs +94 -0
- package/dist/sync/sha1-metadata.cjs.map +1 -0
- package/dist/sync/sha1-metadata.d.cts +82 -0
- package/dist/sync/sha1-metadata.d.cts.map +1 -0
- package/dist/sync/sha1-metadata.d.ts +82 -0
- package/dist/sync/sha1-metadata.d.ts.map +1 -0
- package/dist/sync/sha1-metadata.js +89 -0
- package/dist/sync/sha1-metadata.js.map +1 -0
- package/dist/sync/sha1-options.cjs +23 -0
- package/dist/sync/sha1-options.cjs.map +1 -0
- package/dist/sync/sha1-options.d.cts +14 -0
- package/dist/sync/sha1-options.d.cts.map +1 -0
- package/dist/sync/sha1-options.d.ts +14 -0
- package/dist/sync/sha1-options.d.ts.map +1 -0
- package/dist/sync/sha1-options.js +21 -0
- package/dist/sync/sha1-options.js.map +1 -0
- package/dist/sync/synchronizer.cjs +782 -197
- package/dist/sync/synchronizer.cjs.map +1 -1
- package/dist/sync/synchronizer.d.cts +47 -1
- package/dist/sync/synchronizer.d.cts.map +1 -1
- package/dist/sync/synchronizer.d.ts +47 -1
- package/dist/sync/synchronizer.d.ts.map +1 -1
- package/dist/sync/synchronizer.js +779 -173
- package/dist/sync/synchronizer.js.map +1 -1
- package/dist/sync/types.d.cts +208 -16
- package/dist/sync/types.d.cts.map +1 -1
- package/dist/sync/types.d.ts +208 -16
- package/dist/sync/types.d.ts.map +1 -1
- package/dist/types/auth.cjs +76 -56
- package/dist/types/auth.cjs.map +1 -1
- package/dist/types/auth.d.cts +67 -9
- package/dist/types/auth.d.cts.map +1 -1
- package/dist/types/auth.d.ts +67 -9
- package/dist/types/auth.d.ts.map +1 -1
- package/dist/types/auth.js +77 -57
- package/dist/types/auth.js.map +1 -1
- package/dist/types/bucket.cjs +74 -38
- package/dist/types/bucket.cjs.map +1 -1
- package/dist/types/bucket.js +75 -41
- package/dist/types/bucket.js.map +1 -1
- package/dist/types/encryption.cjs +364 -327
- package/dist/types/encryption.cjs.map +1 -1
- package/dist/types/encryption.d.cts +16 -0
- package/dist/types/encryption.d.cts.map +1 -1
- package/dist/types/encryption.d.ts +16 -0
- package/dist/types/encryption.d.ts.map +1 -1
- package/dist/types/encryption.js +364 -310
- package/dist/types/encryption.js.map +1 -1
- package/dist/types/errors.cjs +47 -0
- package/dist/types/errors.cjs.map +1 -0
- package/dist/types/errors.d.cts +13 -4
- package/dist/types/errors.d.cts.map +1 -1
- package/dist/types/errors.d.ts +13 -4
- package/dist/types/errors.d.ts.map +1 -1
- package/dist/types/errors.js +47 -0
- package/dist/types/errors.js.map +1 -0
- package/dist/types/file.cjs +36 -19
- package/dist/types/file.cjs.map +1 -1
- package/dist/types/file.d.cts +2 -2
- package/dist/types/file.d.cts.map +1 -1
- package/dist/types/file.d.ts +2 -2
- package/dist/types/file.d.ts.map +1 -1
- package/dist/types/file.js +37 -21
- package/dist/types/file.js.map +1 -1
- package/dist/types/ids.cjs +53 -9
- package/dist/types/ids.cjs.map +1 -1
- package/dist/types/ids.js +54 -15
- package/dist/types/ids.js.map +1 -1
- package/dist/types/index.d.cts +12 -11
- package/dist/types/index.d.cts.map +1 -1
- package/dist/types/index.d.ts +12 -11
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/key.d.cts +44 -8
- package/dist/types/key.d.cts.map +1 -1
- package/dist/types/key.d.ts +44 -8
- package/dist/types/key.d.ts.map +1 -1
- package/dist/types/lock.cjs +33 -13
- package/dist/types/lock.cjs.map +1 -1
- package/dist/types/lock.js +34 -15
- package/dist/types/lock.js.map +1 -1
- package/dist/types/notifications.cjs +44 -22
- package/dist/types/notifications.cjs.map +1 -1
- package/dist/types/notifications.js +45 -23
- package/dist/types/notifications.js.map +1 -1
- package/dist/types/upload.d.cts +39 -5
- package/dist/types/upload.d.cts.map +1 -1
- package/dist/types/upload.d.ts +39 -5
- package/dist/types/upload.d.ts.map +1 -1
- package/dist/upload/abort-scope.cjs +91 -0
- package/dist/upload/abort-scope.cjs.map +1 -0
- package/dist/upload/abort-scope.d.cts +48 -0
- package/dist/upload/abort-scope.d.cts.map +1 -0
- package/dist/upload/abort-scope.d.ts +48 -0
- package/dist/upload/abort-scope.d.ts.map +1 -0
- package/dist/upload/abort-scope.js +88 -0
- package/dist/upload/abort-scope.js.map +1 -0
- package/dist/upload/cancel.cjs +183 -8
- package/dist/upload/cancel.cjs.map +1 -1
- package/dist/upload/cancel.d.cts +110 -2
- package/dist/upload/cancel.d.cts.map +1 -1
- package/dist/upload/cancel.d.ts +110 -2
- package/dist/upload/cancel.d.ts.map +1 -1
- package/dist/upload/cancel.js +178 -9
- package/dist/upload/cancel.js.map +1 -1
- package/dist/upload/concurrency.cjs +79 -52
- package/dist/upload/concurrency.cjs.map +1 -1
- package/dist/upload/concurrency.js +79 -53
- package/dist/upload/concurrency.js.map +1 -1
- package/dist/upload/finish.cjs +59 -0
- package/dist/upload/finish.cjs.map +1 -0
- package/dist/upload/finish.d.cts +26 -0
- package/dist/upload/finish.d.cts.map +1 -0
- package/dist/upload/finish.d.ts +26 -0
- package/dist/upload/finish.d.ts.map +1 -0
- package/dist/upload/finish.js +59 -0
- package/dist/upload/finish.js.map +1 -0
- package/dist/upload/large.cjs +301 -218
- package/dist/upload/large.cjs.map +1 -1
- package/dist/upload/large.d.cts +76 -9
- package/dist/upload/large.d.cts.map +1 -1
- package/dist/upload/large.d.ts +76 -9
- package/dist/upload/large.d.ts.map +1 -1
- package/dist/upload/large.js +301 -218
- package/dist/upload/large.js.map +1 -1
- package/dist/upload/options.cjs +28 -0
- package/dist/upload/options.cjs.map +1 -0
- package/dist/upload/options.d.cts +104 -0
- package/dist/upload/options.d.cts.map +1 -0
- package/dist/upload/options.d.ts +104 -0
- package/dist/upload/options.d.ts.map +1 -0
- package/dist/upload/options.js +27 -0
- package/dist/upload/options.js.map +1 -0
- package/dist/upload/resume.cjs +333 -33
- package/dist/upload/resume.cjs.map +1 -1
- package/dist/upload/resume.d.cts +82 -12
- package/dist/upload/resume.d.cts.map +1 -1
- package/dist/upload/resume.d.ts +82 -12
- package/dist/upload/resume.d.ts.map +1 -1
- package/dist/upload/resume.js +330 -33
- package/dist/upload/resume.js.map +1 -1
- package/dist/upload/retry.cjs +186 -0
- package/dist/upload/retry.cjs.map +1 -0
- package/dist/upload/retry.d.cts +127 -0
- package/dist/upload/retry.d.cts.map +1 -0
- package/dist/upload/retry.d.ts +127 -0
- package/dist/upload/retry.d.ts.map +1 -0
- package/dist/upload/retry.js +182 -0
- package/dist/upload/retry.js.map +1 -0
- package/dist/upload/single.cjs +68 -44
- package/dist/upload/single.cjs.map +1 -1
- package/dist/upload/single.d.cts +2 -1
- package/dist/upload/single.d.cts.map +1 -1
- package/dist/upload/single.d.ts +2 -1
- package/dist/upload/single.d.ts.map +1 -1
- package/dist/upload/single.js +68 -44
- package/dist/upload/single.js.map +1 -1
- package/dist/upload/stream.cjs +317 -193
- package/dist/upload/stream.cjs.map +1 -1
- package/dist/upload/stream.d.cts +3 -1
- package/dist/upload/stream.d.cts.map +1 -1
- package/dist/upload/stream.d.ts +3 -1
- package/dist/upload/stream.d.ts.map +1 -1
- package/dist/upload/stream.js +316 -192
- package/dist/upload/stream.js.map +1 -1
- package/dist/util/best-effort.cjs +42 -8
- package/dist/util/best-effort.cjs.map +1 -1
- package/dist/util/best-effort.d.cts +2 -1
- package/dist/util/best-effort.d.cts.map +1 -1
- package/dist/util/best-effort.d.ts +2 -1
- package/dist/util/best-effort.d.ts.map +1 -1
- package/dist/util/best-effort.js +43 -9
- package/dist/util/best-effort.js.map +1 -1
- package/dist/util/bytes.cjs +23 -0
- package/dist/util/bytes.cjs.map +1 -0
- package/dist/util/bytes.d.cts +15 -0
- package/dist/util/bytes.d.cts.map +1 -0
- package/dist/util/bytes.d.ts +15 -0
- package/dist/util/bytes.d.ts.map +1 -0
- package/dist/util/bytes.js +23 -0
- package/dist/util/bytes.js.map +1 -0
- package/dist/util/crypto.cjs +68 -0
- package/dist/util/crypto.cjs.map +1 -0
- package/dist/util/crypto.d.cts +26 -0
- package/dist/util/crypto.d.cts.map +1 -0
- package/dist/util/crypto.d.ts +26 -0
- package/dist/util/crypto.d.ts.map +1 -0
- package/dist/util/crypto.js +66 -0
- package/dist/util/crypto.js.map +1 -0
- package/dist/util/defaults.cjs +25 -9
- package/dist/util/defaults.cjs.map +1 -1
- package/dist/util/defaults.js +26 -11
- package/dist/util/defaults.js.map +1 -1
- package/dist/util/error-reason.cjs +41 -0
- package/dist/util/error-reason.cjs.map +1 -0
- package/dist/util/error-reason.d.cts +9 -0
- package/dist/util/error-reason.d.cts.map +1 -0
- package/dist/util/error-reason.d.ts +9 -0
- package/dist/util/error-reason.d.ts.map +1 -0
- package/dist/util/error-reason.js +41 -0
- package/dist/util/error-reason.js.map +1 -0
- package/dist/util/http.cjs +23 -0
- package/dist/util/http.cjs.map +1 -0
- package/dist/util/http.d.cts +13 -0
- package/dist/util/http.d.cts.map +1 -0
- package/dist/util/http.d.ts +13 -0
- package/dist/util/http.d.ts.map +1 -0
- package/dist/util/http.js +23 -0
- package/dist/util/http.js.map +1 -0
- package/dist/util/normalize.cjs +66 -7
- package/dist/util/normalize.cjs.map +1 -1
- package/dist/util/normalize.js +67 -10
- package/dist/util/normalize.js.map +1 -1
- package/dist/util/paginator.cjs +63 -14
- package/dist/util/paginator.cjs.map +1 -1
- package/dist/util/paginator.js +64 -16
- package/dist/util/paginator.js.map +1 -1
- package/dist/util/plan-ranges.cjs +47 -22
- package/dist/util/plan-ranges.cjs.map +1 -1
- package/dist/util/plan-ranges.js +48 -24
- package/dist/util/plan-ranges.js.map +1 -1
- package/dist/util/sha1.cjs +27 -0
- package/dist/util/sha1.cjs.map +1 -0
- package/dist/util/sha1.d.cts +17 -0
- package/dist/util/sha1.d.cts.map +1 -0
- package/dist/util/sha1.d.ts +17 -0
- package/dist/util/sha1.d.ts.map +1 -0
- package/dist/util/sha1.js +26 -0
- package/dist/util/sha1.js.map +1 -0
- package/dist/util/text-codec.cjs +29 -5
- package/dist/util/text-codec.cjs.map +1 -1
- package/dist/util/text-codec.js +30 -7
- package/dist/util/text-codec.js.map +1 -1
- package/dist/util/to-error.cjs +18 -4
- package/dist/util/to-error.cjs.map +1 -1
- package/dist/util/to-error.js +19 -5
- package/dist/util/to-error.js.map +1 -1
- package/dist/version.cjs +17 -5
- package/dist/version.cjs.map +1 -1
- package/dist/version.d.cts +3 -3
- package/dist/version.d.ts +3 -3
- package/dist/version.js +19 -6
- package/dist/version.js.map +1 -1
- package/package.json +19 -16
- package/dist/auth/index.cjs.map +0 -1
- package/dist/auth/index.js.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/notifications/index.cjs.map +0 -1
- package/dist/notifications/index.js.map +0 -1
- package/dist/package.json.cjs +0 -9
- package/dist/package.json.cjs.map +0 -1
- package/dist/package.json.js +0 -9
- package/dist/package.json.js.map +0 -1
- package/dist/streams/index.cjs.map +0 -1
- package/dist/streams/index.js.map +0 -1
- package/dist/sync/index.cjs.map +0 -1
- package/dist/sync/index.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local.cjs","sources":["../../../src/sync/scanners/local.ts"],"sourcesContent":["import { readdir, stat } from 'node:fs/promises'\nimport { join, relative, sep } from 'node:path'\nimport type { LocalSyncPath, SyncFolder } from '../types.ts'\n\n/**\n * Scans a local directory tree and yields {@link LocalSyncPath} entries\n * sorted by relative path. Unreadable files and directories are silently skipped.\n */\nexport class LocalFolder implements SyncFolder {\n readonly type = 'local' as const\n /** Absolute path to the local root directory. */\n readonly root: string\n\n /**\n * Creates a new LocalFolder for the given root directory.\n * @param root - Absolute path to the local directory to scan.\n */\n constructor(root: string) {\n this.root = root\n }\n\n /** Recursively walks the directory and yields files sorted by relative path. */\n async *scan(): AsyncGenerator<LocalSyncPath> {\n const collected: LocalSyncPath[] = []\n await this.walk(this.root, collected)\n collected.sort((a, b) => a.relativePath.localeCompare(b.relativePath))\n for (const entry of collected) {\n yield entry\n }\n }\n\n /**\n * Recursively collects files from {@link dir} into {@link out}.\n * @param dir - Absolute path of the directory to scan.\n * @param out - Accumulator array that receives discovered file entries.\n */\n private async walk(dir: string, out: LocalSyncPath[]): Promise<void> {\n let entries: import('node:fs').Dirent[]\n try {\n entries = await readdir(dir, { withFileTypes: true })\n } catch {\n return\n }\n\n for (const entry of entries) {\n const fullPath = join(dir, entry.name)\n if (entry.isDirectory()) {\n await this.walk(fullPath, out)\n } else if (entry.isFile()) {\n try {\n const s = await stat(fullPath)\n const rel = relative(this.root, fullPath).split(sep).join('/')\n out.push({\n relativePath: rel,\n absolutePath: fullPath,\n modTimeMillis: Math.floor(s.mtimeMs),\n size: s.size,\n })\n } catch {\n // skip unreadable files\n }\n }\n }\n }\n}\n"],"names":["readdir","join","stat","relative","sep"],"mappings":";;;;AAQO,MAAM,YAAkC;AAAA,EACpC,OAAO;AAAA;AAAA,EAEP;AAAA;AAAA;AAAA;AAAA;AAAA,EAMT,YAAY,MAAc;AACxB,SAAK,OAAO;AAAA,EACd;AAAA;AAAA,EAGA,OAAO,OAAsC;AAC3C,UAAM,YAA6B,CAAA;AACnC,UAAM,KAAK,KAAK,KAAK,MAAM,SAAS;AACpC,cAAU,KAAK,CAAC,GAAG,MAAM,EAAE,aAAa,cAAc,EAAE,YAAY,CAAC;AACrE,eAAW,SAAS,WAAW;AAC7B,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,KAAK,KAAa,KAAqC;AACnE,QAAI;AACJ,QAAI;AACF,gBAAU,MAAMA,SAAAA,QAAQ,KAAK,EAAE,eAAe,MAAM;AAAA,IACtD,QAAQ;AACN;AAAA,IACF;AAEA,eAAW,SAAS,SAAS;AAC3B,YAAM,WAAWC,UAAAA,KAAK,KAAK,MAAM,IAAI;AACrC,UAAI,MAAM,eAAe;AACvB,cAAM,KAAK,KAAK,UAAU,GAAG;AAAA,MAC/B,WAAW,MAAM,UAAU;AACzB,YAAI;AACF,gBAAM,IAAI,MAAMC,SAAAA,KAAK,QAAQ;AAC7B,gBAAM,MAAMC,UAAAA,SAAS,KAAK,MAAM,QAAQ,EAAE,MAAMC,UAAAA,GAAG,EAAE,KAAK,GAAG;AAC7D,cAAI,KAAK;AAAA,YACP,cAAc;AAAA,YACd,cAAc;AAAA,YACd,eAAe,KAAK,MAAM,EAAE,OAAO;AAAA,YACnC,MAAM,EAAE;AAAA,UAAA,CACT;AAAA,QACH,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;"}
|
|
1
|
+
{"version":3,"file":"local.cjs","names":[],"sources":["../../../src/sync/scanners/local.ts"],"sourcesContent":["import {\n isDownloadStagingDirectorySegment,\n isManagedDownloadStagingRoot,\n} from '../download-staging.ts'\nimport { localFilesystemErrorReason } from '../filesystem-errors.ts'\nimport {\n directoryMayContainSyncPaths,\n pathPassesSyncFilters,\n pathSkippedByRegExpInputLimit,\n} from '../filters.ts'\nimport { localFileIdentityFromStats } from '../local-file-identity.ts'\nimport { registerLocalFilesystemRoot } from '../local-filesystem-root.ts'\nimport { compareSyncRelativePaths } from '../path-order.ts'\nimport { isReservedSyncTempFileName } from '../path-safety.ts'\nimport { validateSyncFilters } from '../regexp-safety.ts'\nimport { emitScannerSkip, regexpInputTooLongSkip } from '../scan-events.ts'\nimport { assertScanEntryLimit, scanEntryLimit } from '../scan-limit.ts'\nimport type { LocalSyncPath, SyncErrorEvent, SyncFolder, SyncScanOptions } from '../types.ts'\n\ntype LocalDirent = {\n readonly name: string\n isDirectory(): boolean\n isFile(): boolean\n}\n\ntype LocalStats = {\n readonly dev: number\n readonly ino: number\n readonly mtimeMs: number\n readonly ctimeMs: number\n readonly size: number\n isFile(): boolean\n}\n\ntype LocalNodeDeps = {\n readdir(path: string, options: { readonly withFileTypes: true }): Promise<LocalDirent[]>\n lstat(path: string): Promise<LocalStats>\n join(...paths: string[]): string\n relative(from: string, to: string): string\n resolve(...paths: string[]): string\n sep: string\n}\n\n/**\n * Scans a local directory tree and yields {@link LocalSyncPath} entries sorted by relative path.\n * A root directory read failure aborts the scan with an error diagnostic. Per-entry file or\n * directory failures are reported through `onError` and the scan continues over readable siblings.\n * SDK-managed partial download file names are skipped so unfinished internal\n * temp files are not synchronized.\n * The current implementation collects matching entries before sorting, so memory usage is\n * proportional to the number of matched files.\n */\nexport class LocalFolder implements SyncFolder {\n readonly type = 'local' as const\n readonly appliesScanFilters = true as const\n readonly appliesScanSorting = true as const\n /** Resolved absolute path to the local root directory. */\n readonly root: string\n\n /**\n * Creates a new LocalFolder for the given root directory.\n * @param root - Absolute or relative path to the local directory to scan.\n */\n constructor(root: string) {\n this.root = resolvePathAtConstruction(root)\n registerLocalFilesystemRoot(this)\n }\n\n /**\n * Recursively walks the directory and yields files in sync path order.\n * @param options - Optional scan controls.\n */\n async *scan(options: SyncScanOptions = {}): AsyncGenerator<LocalSyncPath> {\n validateSyncFilters(options)\n const nodeDeps = await loadLocalNodeDeps()\n const root = nodeDeps.resolve(this.root)\n const collected: LocalSyncPath[] = []\n await this.walk(root, root, collected, options, scanEntryLimit(options), nodeDeps)\n collected.sort((a, b) => compareSyncRelativePaths(a.relativePath, b.relativePath))\n for (const entry of collected) {\n throwIfScanAborted(options)\n yield entry\n }\n }\n\n /**\n * Recursively collects files from {@link dir} into {@link out}.\n * @param root - Resolved scan root used for relative path calculation.\n * @param dir - Absolute path of the directory to scan.\n * @param out - Accumulator array that receives discovered file entries.\n * @param options - Optional scan controls.\n * @param maxScanEntries - Maximum number of entries to retain before failing.\n * @param nodeDeps - Lazy-loaded Node filesystem and path helpers.\n */\n private async walk(\n root: string,\n dir: string,\n out: LocalSyncPath[],\n options: SyncScanOptions,\n maxScanEntries: number,\n nodeDeps: LocalNodeDeps,\n ): Promise<void> {\n throwIfScanAborted(options)\n let entries: LocalDirent[]\n try {\n entries = await nodeDeps.readdir(dir, { withFileTypes: true })\n } catch (err) {\n const error = this.emitScanError(\n options,\n relativePathFromRoot(root, dir, nodeDeps),\n 'directory',\n err,\n )\n if (dir === root) throw error\n return\n }\n\n for (const entry of entries) {\n throwIfScanAborted(options)\n const fullPath = nodeDeps.join(dir, entry.name)\n const rel = relativePathFromRoot(root, fullPath, nodeDeps)\n if (\n isDownloadStagingDirectorySegment(rel) &&\n entry.isDirectory() &&\n isDownloadStagingDirectorySegment(entry.name) &&\n (await isManagedDownloadStagingRoot(fullPath))\n ) {\n continue\n }\n if (rel.includes('\\\\')) {\n emitScannerSkip(options, {\n type: 'skip',\n path: rel,\n size: 0,\n reason: 'unsafe-name',\n message: `Skipped local path ${JSON.stringify(rel)}: backslashes are not safe sync path characters`,\n })\n continue\n }\n if (isReservedSyncTempFileName(entry.name)) {\n emitScannerSkip(options, {\n type: 'skip',\n path: rel,\n size: 0,\n reason: 'stale-download-partial',\n message: `Skipped local path ${JSON.stringify(rel)}: reserved SDK partial download file`,\n })\n continue\n }\n // Symlinks, FIFOs, sockets, and device nodes are not syncable files.\n // Ignore them without poisoning delete-mode orphan handling for unrelated paths.\n if (entry.isDirectory()) {\n if (directoryMayContainSyncPaths(rel, options)) {\n await this.walk(root, fullPath, out, options, maxScanEntries, nodeDeps)\n }\n } else if (entry.isFile()) {\n if (!pathPassesSyncFilters(rel, options)) {\n if (pathSkippedByRegExpInputLimit(rel, options)) {\n emitScannerSkip(options, regexpInputTooLongSkip(rel))\n }\n continue\n }\n let s: LocalStats\n try {\n s = await nodeDeps.lstat(fullPath)\n /* v8 ignore start -- lstat race after a Dirent file result is not deterministic */\n if (!s.isFile()) {\n this.emitScanError(options, rel, 'file', new Error('not a regular file'))\n continue\n }\n /* v8 ignore stop */\n } catch (err) {\n /* v8 ignore next -- stat TOCTOU failures are not deterministic to trigger */\n this.emitScanError(options, relativePathFromRoot(root, fullPath, nodeDeps), 'file', err)\n continue\n }\n assertScanEntryLimit(out.length + 1, maxScanEntries)\n out.push({\n relativePath: rel,\n absolutePath: fullPath,\n modTimeMillis: Math.floor(s.mtimeMs),\n size: s.size,\n fileIdentity: localFileIdentityFromStats(s),\n })\n }\n }\n }\n\n private emitScanError(\n options: SyncScanOptions,\n path: string,\n kind: 'directory' | 'file',\n err: unknown,\n ): Error {\n const event: SyncErrorEvent = {\n type: 'error',\n path,\n size: 0,\n message: `failed to scan local ${kind}: ${localFilesystemErrorReason(err)}`,\n }\n options.onError?.(event)\n return new Error(event.message)\n }\n}\n\nasync function loadLocalNodeDeps(): Promise<LocalNodeDeps> {\n const [fsPromises, path] = await Promise.all([import('node:fs/promises'), import('node:path')])\n return {\n readdir: fsPromises.readdir as LocalNodeDeps['readdir'],\n lstat: fsPromises.lstat as LocalNodeDeps['lstat'],\n join: path.join,\n relative: path.relative,\n resolve: path.resolve,\n sep: path.sep,\n }\n}\n\nfunction resolvePathAtConstruction(root: string): string {\n const processLike = (\n globalThis as {\n process?: { cwd?: () => string; platform?: string }\n }\n ).process\n if (typeof processLike?.cwd !== 'function') return root\n\n const cwd = processLike.cwd()\n if (processLike.platform === 'win32') return resolveWindowsPath(cwd, root)\n return resolvePosixPath(cwd, root)\n}\n\nfunction resolvePosixPath(cwd: string, root: string): string {\n const joined = root.startsWith('/') ? root : `${cwd}/${root}`\n const resolved = normalizePathSegments(joined.split('/'), '/')\n return resolved === '' ? '/' : `/${resolved}`\n}\n\nfunction resolveWindowsPath(cwd: string, root: string): string {\n const normalizedRoot = root.replaceAll('/', '\\\\')\n const normalizedCwd = cwd.replaceAll('/', '\\\\')\n const drive = /^[A-Za-z]:/.exec(normalizedCwd)?.[0] ?? ''\n const cwdUnc = splitUncPath(normalizedCwd)\n if (/^\\\\\\\\/.test(normalizedRoot)) return normalizeUncPath(normalizedRoot)\n if (/^[A-Za-z]:\\\\/.test(normalizedRoot)) {\n const prefix = normalizedRoot.slice(0, 2)\n const rest = normalizedRoot.slice(3).split('\\\\')\n return joinWindowsRoot(prefix, normalizePathSegments(rest, '\\\\'))\n }\n if (/^[A-Za-z]:/.test(normalizedRoot)) {\n throw new Error('LocalFolder root must not be a drive-relative Windows path')\n }\n if (normalizedRoot.startsWith('\\\\')) {\n const rest = normalizePathSegments(normalizedRoot.slice(1).split('\\\\'), '\\\\')\n return joinWindowsRoot(cwdUnc?.prefix ?? drive, rest)\n }\n if (cwdUnc !== undefined) {\n const resolved = normalizePathSegments([...cwdUnc.rest, ...normalizedRoot.split('\\\\')], '\\\\')\n return joinWindowsRoot(cwdUnc.prefix, resolved)\n }\n const base = /^[A-Za-z]:\\\\/.test(normalizedCwd) ? normalizedCwd : `${drive}\\\\`\n const prefix = /^[A-Za-z]:/.exec(base)?.[0] ?? drive\n const baseRest = base.slice(prefix.length).replace(/^\\\\/, '').split('\\\\')\n const resolved = normalizePathSegments([...baseRest, ...normalizedRoot.split('\\\\')], '\\\\')\n return joinWindowsRoot(prefix, resolved)\n}\n\nfunction normalizeUncPath(path: string): string {\n const unc = splitUncPath(path)\n if (unc === undefined) return path\n return joinWindowsRoot(unc.prefix, normalizePathSegments(unc.rest, '\\\\'))\n}\n\nfunction splitUncPath(\n path: string,\n): { readonly prefix: string; readonly rest: string[] } | undefined {\n if (!path.startsWith('\\\\\\\\')) return undefined\n const parts = path.split('\\\\').filter((part) => part !== '')\n const [server, share, ...rest] = parts\n if (server === undefined || share === undefined) return undefined\n return { prefix: `\\\\\\\\${server}\\\\${share}`, rest }\n}\n\nfunction joinWindowsRoot(prefix: string, rest: string): string {\n return rest === '' ? `${prefix}\\\\` : `${prefix}\\\\${rest}`\n}\n\nfunction normalizePathSegments(segments: readonly string[], separator: '/' | '\\\\'): string {\n const out: string[] = []\n for (const segment of segments) {\n if (segment === '' || segment === '.') continue\n if (segment === '..') {\n out.pop()\n continue\n }\n out.push(segment)\n }\n return out.join(separator)\n}\n\nfunction relativePathFromRoot(root: string, path: string, nodeDeps: LocalNodeDeps): string {\n return nodeDeps.relative(root, path).split(nodeDeps.sep).join('/')\n}\n\nfunction throwIfScanAborted(options: SyncScanOptions): void {\n if (options.signal?.aborted === true) {\n throw options.signal.reason ?? new DOMException('Aborted', 'AbortError')\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,24 +1,39 @@
|
|
|
1
|
-
import { LocalSyncPath, SyncFolder } from '../types.js';
|
|
1
|
+
import { LocalSyncPath, SyncFolder, SyncScanOptions } from '../types.js';
|
|
2
2
|
/**
|
|
3
|
-
* Scans a local directory tree and yields {@link LocalSyncPath} entries
|
|
4
|
-
*
|
|
3
|
+
* Scans a local directory tree and yields {@link LocalSyncPath} entries sorted by relative path.
|
|
4
|
+
* A root directory read failure aborts the scan with an error diagnostic. Per-entry file or
|
|
5
|
+
* directory failures are reported through `onError` and the scan continues over readable siblings.
|
|
6
|
+
* SDK-managed partial download file names are skipped so unfinished internal
|
|
7
|
+
* temp files are not synchronized.
|
|
8
|
+
* The current implementation collects matching entries before sorting, so memory usage is
|
|
9
|
+
* proportional to the number of matched files.
|
|
5
10
|
*/
|
|
6
11
|
export declare class LocalFolder implements SyncFolder {
|
|
7
12
|
readonly type: "local";
|
|
8
|
-
|
|
13
|
+
readonly appliesScanFilters: true;
|
|
14
|
+
readonly appliesScanSorting: true;
|
|
15
|
+
/** Resolved absolute path to the local root directory. */
|
|
9
16
|
readonly root: string;
|
|
10
17
|
/**
|
|
11
18
|
* Creates a new LocalFolder for the given root directory.
|
|
12
|
-
* @param root - Absolute path to the local directory to scan.
|
|
19
|
+
* @param root - Absolute or relative path to the local directory to scan.
|
|
13
20
|
*/
|
|
14
21
|
constructor(root: string);
|
|
15
|
-
/**
|
|
16
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Recursively walks the directory and yields files in sync path order.
|
|
24
|
+
* @param options - Optional scan controls.
|
|
25
|
+
*/
|
|
26
|
+
scan(options?: SyncScanOptions): AsyncGenerator<LocalSyncPath>;
|
|
17
27
|
/**
|
|
18
28
|
* Recursively collects files from {@link dir} into {@link out}.
|
|
29
|
+
* @param root - Resolved scan root used for relative path calculation.
|
|
19
30
|
* @param dir - Absolute path of the directory to scan.
|
|
20
31
|
* @param out - Accumulator array that receives discovered file entries.
|
|
32
|
+
* @param options - Optional scan controls.
|
|
33
|
+
* @param maxScanEntries - Maximum number of entries to retain before failing.
|
|
34
|
+
* @param nodeDeps - Lazy-loaded Node filesystem and path helpers.
|
|
21
35
|
*/
|
|
22
36
|
private walk;
|
|
37
|
+
private emitScanError;
|
|
23
38
|
}
|
|
24
39
|
//# sourceMappingURL=local.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../../src/sync/scanners/local.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../../src/sync/scanners/local.js"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,aAAa,EAAkB,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AA0B7F;;;;;;;;GAQG;AACH,qBAAa,WAAY,YAAW,UAAU;IAC5C,QAAQ,CAAC,IAAI,EAAG,OAAO,CAAS;IAChC,QAAQ,CAAC,kBAAkB,EAAG,IAAI,CAAS;IAC3C,QAAQ,CAAC,kBAAkB,EAAG,IAAI,CAAS;IAC3C,0DAA0D;IAC1D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IAErB;;;OAGG;gBACS,IAAI,EAAE,MAAM;IAKxB;;;OAGG;IACI,IAAI,CAAC,OAAO,GAAE,eAAoB,GAAG,cAAc,CAAC,aAAa,CAAC;IAazE;;;;;;;;OAQG;YACW,IAAI;IA8FlB,OAAO,CAAC,aAAa;CAetB"}
|
|
@@ -1,24 +1,39 @@
|
|
|
1
|
-
import { LocalSyncPath, SyncFolder } from '../types.js';
|
|
1
|
+
import { LocalSyncPath, SyncFolder, SyncScanOptions } from '../types.js';
|
|
2
2
|
/**
|
|
3
|
-
* Scans a local directory tree and yields {@link LocalSyncPath} entries
|
|
4
|
-
*
|
|
3
|
+
* Scans a local directory tree and yields {@link LocalSyncPath} entries sorted by relative path.
|
|
4
|
+
* A root directory read failure aborts the scan with an error diagnostic. Per-entry file or
|
|
5
|
+
* directory failures are reported through `onError` and the scan continues over readable siblings.
|
|
6
|
+
* SDK-managed partial download file names are skipped so unfinished internal
|
|
7
|
+
* temp files are not synchronized.
|
|
8
|
+
* The current implementation collects matching entries before sorting, so memory usage is
|
|
9
|
+
* proportional to the number of matched files.
|
|
5
10
|
*/
|
|
6
11
|
export declare class LocalFolder implements SyncFolder {
|
|
7
12
|
readonly type: "local";
|
|
8
|
-
|
|
13
|
+
readonly appliesScanFilters: true;
|
|
14
|
+
readonly appliesScanSorting: true;
|
|
15
|
+
/** Resolved absolute path to the local root directory. */
|
|
9
16
|
readonly root: string;
|
|
10
17
|
/**
|
|
11
18
|
* Creates a new LocalFolder for the given root directory.
|
|
12
|
-
* @param root - Absolute path to the local directory to scan.
|
|
19
|
+
* @param root - Absolute or relative path to the local directory to scan.
|
|
13
20
|
*/
|
|
14
21
|
constructor(root: string);
|
|
15
|
-
/**
|
|
16
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Recursively walks the directory and yields files in sync path order.
|
|
24
|
+
* @param options - Optional scan controls.
|
|
25
|
+
*/
|
|
26
|
+
scan(options?: SyncScanOptions): AsyncGenerator<LocalSyncPath>;
|
|
17
27
|
/**
|
|
18
28
|
* Recursively collects files from {@link dir} into {@link out}.
|
|
29
|
+
* @param root - Resolved scan root used for relative path calculation.
|
|
19
30
|
* @param dir - Absolute path of the directory to scan.
|
|
20
31
|
* @param out - Accumulator array that receives discovered file entries.
|
|
32
|
+
* @param options - Optional scan controls.
|
|
33
|
+
* @param maxScanEntries - Maximum number of entries to retain before failing.
|
|
34
|
+
* @param nodeDeps - Lazy-loaded Node filesystem and path helpers.
|
|
21
35
|
*/
|
|
22
36
|
private walk;
|
|
37
|
+
private emitScanError;
|
|
23
38
|
}
|
|
24
39
|
//# sourceMappingURL=local.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../../src/sync/scanners/local.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../../src/sync/scanners/local.js"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,aAAa,EAAkB,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AA0B7F;;;;;;;;GAQG;AACH,qBAAa,WAAY,YAAW,UAAU;IAC5C,QAAQ,CAAC,IAAI,EAAG,OAAO,CAAS;IAChC,QAAQ,CAAC,kBAAkB,EAAG,IAAI,CAAS;IAC3C,QAAQ,CAAC,kBAAkB,EAAG,IAAI,CAAS;IAC3C,0DAA0D;IAC1D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IAErB;;;OAGG;gBACS,IAAI,EAAE,MAAM;IAKxB;;;OAGG;IACI,IAAI,CAAC,OAAO,GAAE,eAAoB,GAAG,cAAc,CAAC,aAAa,CAAC;IAazE;;;;;;;;OAQG;YACW,IAAI;IA8FlB,OAAO,CAAC,aAAa;CAetB"}
|
|
@@ -1,58 +1,217 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
1
|
+
import { validateSyncFilters } from "../regexp-safety.js";
|
|
2
|
+
import { emitScannerSkip, regexpInputTooLongSkip } from "../scan-events.js";
|
|
3
|
+
import { directoryMayContainSyncPaths, pathPassesSyncFilters, pathSkippedByRegExpInputLimit } from "../filters.js";
|
|
4
|
+
import { compareSyncRelativePaths } from "../path-order.js";
|
|
5
|
+
import { assertScanEntryLimit, scanEntryLimit } from "../scan-limit.js";
|
|
6
|
+
import { localFileIdentityFromStats } from "../local-file-identity.js";
|
|
7
|
+
import { isReservedSyncTempFileName } from "../path-safety.js";
|
|
8
|
+
import { isDownloadStagingDirectorySegment, isManagedDownloadStagingRoot } from "../download-staging.js";
|
|
9
|
+
import { localFilesystemErrorReason } from "../filesystem-errors.js";
|
|
10
|
+
import { registerLocalFilesystemRoot } from "../local-filesystem-root.js";
|
|
11
|
+
//#region src/sync/scanners/local.ts
|
|
12
|
+
/**
|
|
13
|
+
* Scans a local directory tree and yields {@link LocalSyncPath} entries sorted by relative path.
|
|
14
|
+
* A root directory read failure aborts the scan with an error diagnostic. Per-entry file or
|
|
15
|
+
* directory failures are reported through `onError` and the scan continues over readable siblings.
|
|
16
|
+
* SDK-managed partial download file names are skipped so unfinished internal
|
|
17
|
+
* temp files are not synchronized.
|
|
18
|
+
* The current implementation collects matching entries before sorting, so memory usage is
|
|
19
|
+
* proportional to the number of matched files.
|
|
20
|
+
*/
|
|
21
|
+
var LocalFolder = class {
|
|
22
|
+
type = "local";
|
|
23
|
+
appliesScanFilters = true;
|
|
24
|
+
appliesScanSorting = true;
|
|
25
|
+
/** Resolved absolute path to the local root directory. */
|
|
26
|
+
root;
|
|
27
|
+
/**
|
|
28
|
+
* Creates a new LocalFolder for the given root directory.
|
|
29
|
+
* @param root - Absolute or relative path to the local directory to scan.
|
|
30
|
+
*/
|
|
31
|
+
constructor(root) {
|
|
32
|
+
this.root = resolvePathAtConstruction(root);
|
|
33
|
+
registerLocalFilesystemRoot(this);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Recursively walks the directory and yields files in sync path order.
|
|
37
|
+
* @param options - Optional scan controls.
|
|
38
|
+
*/
|
|
39
|
+
async *scan(options = {}) {
|
|
40
|
+
validateSyncFilters(options);
|
|
41
|
+
const nodeDeps = await loadLocalNodeDeps();
|
|
42
|
+
const root = nodeDeps.resolve(this.root);
|
|
43
|
+
const collected = [];
|
|
44
|
+
await this.walk(root, root, collected, options, scanEntryLimit(options), nodeDeps);
|
|
45
|
+
collected.sort((a, b) => compareSyncRelativePaths(a.relativePath, b.relativePath));
|
|
46
|
+
for (const entry of collected) {
|
|
47
|
+
throwIfScanAborted(options);
|
|
48
|
+
yield entry;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Recursively collects files from {@link dir} into {@link out}.
|
|
53
|
+
* @param root - Resolved scan root used for relative path calculation.
|
|
54
|
+
* @param dir - Absolute path of the directory to scan.
|
|
55
|
+
* @param out - Accumulator array that receives discovered file entries.
|
|
56
|
+
* @param options - Optional scan controls.
|
|
57
|
+
* @param maxScanEntries - Maximum number of entries to retain before failing.
|
|
58
|
+
* @param nodeDeps - Lazy-loaded Node filesystem and path helpers.
|
|
59
|
+
*/
|
|
60
|
+
async walk(root, dir, out, options, maxScanEntries, nodeDeps) {
|
|
61
|
+
throwIfScanAborted(options);
|
|
62
|
+
let entries;
|
|
63
|
+
try {
|
|
64
|
+
entries = await nodeDeps.readdir(dir, { withFileTypes: true });
|
|
65
|
+
} catch (err) {
|
|
66
|
+
const error = this.emitScanError(options, relativePathFromRoot(root, dir, nodeDeps), "directory", err);
|
|
67
|
+
if (dir === root) throw error;
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
for (const entry of entries) {
|
|
71
|
+
throwIfScanAborted(options);
|
|
72
|
+
const fullPath = nodeDeps.join(dir, entry.name);
|
|
73
|
+
const rel = relativePathFromRoot(root, fullPath, nodeDeps);
|
|
74
|
+
if (isDownloadStagingDirectorySegment(rel) && entry.isDirectory() && isDownloadStagingDirectorySegment(entry.name) && await isManagedDownloadStagingRoot(fullPath)) continue;
|
|
75
|
+
if (rel.includes("\\")) {
|
|
76
|
+
emitScannerSkip(options, {
|
|
77
|
+
type: "skip",
|
|
78
|
+
path: rel,
|
|
79
|
+
size: 0,
|
|
80
|
+
reason: "unsafe-name",
|
|
81
|
+
message: `Skipped local path ${JSON.stringify(rel)}: backslashes are not safe sync path characters`
|
|
82
|
+
});
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (isReservedSyncTempFileName(entry.name)) {
|
|
86
|
+
emitScannerSkip(options, {
|
|
87
|
+
type: "skip",
|
|
88
|
+
path: rel,
|
|
89
|
+
size: 0,
|
|
90
|
+
reason: "stale-download-partial",
|
|
91
|
+
message: `Skipped local path ${JSON.stringify(rel)}: reserved SDK partial download file`
|
|
92
|
+
});
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (entry.isDirectory()) {
|
|
96
|
+
if (directoryMayContainSyncPaths(rel, options)) await this.walk(root, fullPath, out, options, maxScanEntries, nodeDeps);
|
|
97
|
+
} else if (entry.isFile()) {
|
|
98
|
+
if (!pathPassesSyncFilters(rel, options)) {
|
|
99
|
+
if (pathSkippedByRegExpInputLimit(rel, options)) emitScannerSkip(options, regexpInputTooLongSkip(rel));
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
let s;
|
|
103
|
+
try {
|
|
104
|
+
s = await nodeDeps.lstat(fullPath);
|
|
105
|
+
/* v8 ignore start -- lstat race after a Dirent file result is not deterministic */
|
|
106
|
+
if (!s.isFile()) {
|
|
107
|
+
this.emitScanError(options, rel, "file", /* @__PURE__ */ new Error("not a regular file"));
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
} catch (err) {
|
|
111
|
+
/* v8 ignore next -- stat TOCTOU failures are not deterministic to trigger */
|
|
112
|
+
this.emitScanError(options, relativePathFromRoot(root, fullPath, nodeDeps), "file", err);
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
assertScanEntryLimit(out.length + 1, maxScanEntries);
|
|
116
|
+
out.push({
|
|
117
|
+
relativePath: rel,
|
|
118
|
+
absolutePath: fullPath,
|
|
119
|
+
modTimeMillis: Math.floor(s.mtimeMs),
|
|
120
|
+
size: s.size,
|
|
121
|
+
fileIdentity: localFileIdentityFromStats(s)
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
emitScanError(options, path, kind, err) {
|
|
127
|
+
const event = {
|
|
128
|
+
type: "error",
|
|
129
|
+
path,
|
|
130
|
+
size: 0,
|
|
131
|
+
message: `failed to scan local ${kind}: ${localFilesystemErrorReason(err)}`
|
|
132
|
+
};
|
|
133
|
+
options.onError?.(event);
|
|
134
|
+
return new Error(event.message);
|
|
135
|
+
}
|
|
57
136
|
};
|
|
58
|
-
|
|
137
|
+
async function loadLocalNodeDeps() {
|
|
138
|
+
const [fsPromises, path] = await Promise.all([import("node:fs/promises"), import("node:path")]);
|
|
139
|
+
return {
|
|
140
|
+
readdir: fsPromises.readdir,
|
|
141
|
+
lstat: fsPromises.lstat,
|
|
142
|
+
join: path.join,
|
|
143
|
+
relative: path.relative,
|
|
144
|
+
resolve: path.resolve,
|
|
145
|
+
sep: path.sep
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
function resolvePathAtConstruction(root) {
|
|
149
|
+
const processLike = globalThis.process;
|
|
150
|
+
if (typeof processLike?.cwd !== "function") return root;
|
|
151
|
+
const cwd = processLike.cwd();
|
|
152
|
+
if (processLike.platform === "win32") return resolveWindowsPath(cwd, root);
|
|
153
|
+
return resolvePosixPath(cwd, root);
|
|
154
|
+
}
|
|
155
|
+
function resolvePosixPath(cwd, root) {
|
|
156
|
+
const resolved = normalizePathSegments((root.startsWith("/") ? root : `${cwd}/${root}`).split("/"), "/");
|
|
157
|
+
return resolved === "" ? "/" : `/${resolved}`;
|
|
158
|
+
}
|
|
159
|
+
function resolveWindowsPath(cwd, root) {
|
|
160
|
+
const normalizedRoot = root.replaceAll("/", "\\");
|
|
161
|
+
const normalizedCwd = cwd.replaceAll("/", "\\");
|
|
162
|
+
const drive = /^[A-Za-z]:/.exec(normalizedCwd)?.[0] ?? "";
|
|
163
|
+
const cwdUnc = splitUncPath(normalizedCwd);
|
|
164
|
+
if (/^\\\\/.test(normalizedRoot)) return normalizeUncPath(normalizedRoot);
|
|
165
|
+
if (/^[A-Za-z]:\\/.test(normalizedRoot)) return joinWindowsRoot(normalizedRoot.slice(0, 2), normalizePathSegments(normalizedRoot.slice(3).split("\\"), "\\"));
|
|
166
|
+
if (/^[A-Za-z]:/.test(normalizedRoot)) throw new Error("LocalFolder root must not be a drive-relative Windows path");
|
|
167
|
+
if (normalizedRoot.startsWith("\\")) {
|
|
168
|
+
const rest = normalizePathSegments(normalizedRoot.slice(1).split("\\"), "\\");
|
|
169
|
+
return joinWindowsRoot(cwdUnc?.prefix ?? drive, rest);
|
|
170
|
+
}
|
|
171
|
+
if (cwdUnc !== void 0) {
|
|
172
|
+
const resolved = normalizePathSegments([...cwdUnc.rest, ...normalizedRoot.split("\\")], "\\");
|
|
173
|
+
return joinWindowsRoot(cwdUnc.prefix, resolved);
|
|
174
|
+
}
|
|
175
|
+
const base = /^[A-Za-z]:\\/.test(normalizedCwd) ? normalizedCwd : `${drive}\\`;
|
|
176
|
+
const prefix = /^[A-Za-z]:/.exec(base)?.[0] ?? drive;
|
|
177
|
+
return joinWindowsRoot(prefix, normalizePathSegments([...base.slice(prefix.length).replace(/^\\/, "").split("\\"), ...normalizedRoot.split("\\")], "\\"));
|
|
178
|
+
}
|
|
179
|
+
function normalizeUncPath(path) {
|
|
180
|
+
const unc = splitUncPath(path);
|
|
181
|
+
if (unc === void 0) return path;
|
|
182
|
+
return joinWindowsRoot(unc.prefix, normalizePathSegments(unc.rest, "\\"));
|
|
183
|
+
}
|
|
184
|
+
function splitUncPath(path) {
|
|
185
|
+
if (!path.startsWith("\\\\")) return void 0;
|
|
186
|
+
const [server, share, ...rest] = path.split("\\").filter((part) => part !== "");
|
|
187
|
+
if (server === void 0 || share === void 0) return void 0;
|
|
188
|
+
return {
|
|
189
|
+
prefix: `\\\\${server}\\${share}`,
|
|
190
|
+
rest
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
function joinWindowsRoot(prefix, rest) {
|
|
194
|
+
return rest === "" ? `${prefix}\\` : `${prefix}\\${rest}`;
|
|
195
|
+
}
|
|
196
|
+
function normalizePathSegments(segments, separator) {
|
|
197
|
+
const out = [];
|
|
198
|
+
for (const segment of segments) {
|
|
199
|
+
if (segment === "" || segment === ".") continue;
|
|
200
|
+
if (segment === "..") {
|
|
201
|
+
out.pop();
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
out.push(segment);
|
|
205
|
+
}
|
|
206
|
+
return out.join(separator);
|
|
207
|
+
}
|
|
208
|
+
function relativePathFromRoot(root, path, nodeDeps) {
|
|
209
|
+
return nodeDeps.relative(root, path).split(nodeDeps.sep).join("/");
|
|
210
|
+
}
|
|
211
|
+
function throwIfScanAborted(options) {
|
|
212
|
+
if (options.signal?.aborted === true) throw options.signal.reason ?? new DOMException("Aborted", "AbortError");
|
|
213
|
+
}
|
|
214
|
+
//#endregion
|
|
215
|
+
export { LocalFolder };
|
|
216
|
+
|
|
217
|
+
//# sourceMappingURL=local.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local.js","sources":["../../../src/sync/scanners/local.ts"],"sourcesContent":["import { readdir, stat } from 'node:fs/promises'\nimport { join, relative, sep } from 'node:path'\nimport type { LocalSyncPath, SyncFolder } from '../types.ts'\n\n/**\n * Scans a local directory tree and yields {@link LocalSyncPath} entries\n * sorted by relative path. Unreadable files and directories are silently skipped.\n */\nexport class LocalFolder implements SyncFolder {\n readonly type = 'local' as const\n /** Absolute path to the local root directory. */\n readonly root: string\n\n /**\n * Creates a new LocalFolder for the given root directory.\n * @param root - Absolute path to the local directory to scan.\n */\n constructor(root: string) {\n this.root = root\n }\n\n /** Recursively walks the directory and yields files sorted by relative path. */\n async *scan(): AsyncGenerator<LocalSyncPath> {\n const collected: LocalSyncPath[] = []\n await this.walk(this.root, collected)\n collected.sort((a, b) => a.relativePath.localeCompare(b.relativePath))\n for (const entry of collected) {\n yield entry\n }\n }\n\n /**\n * Recursively collects files from {@link dir} into {@link out}.\n * @param dir - Absolute path of the directory to scan.\n * @param out - Accumulator array that receives discovered file entries.\n */\n private async walk(dir: string, out: LocalSyncPath[]): Promise<void> {\n let entries: import('node:fs').Dirent[]\n try {\n entries = await readdir(dir, { withFileTypes: true })\n } catch {\n return\n }\n\n for (const entry of entries) {\n const fullPath = join(dir, entry.name)\n if (entry.isDirectory()) {\n await this.walk(fullPath, out)\n } else if (entry.isFile()) {\n try {\n const s = await stat(fullPath)\n const rel = relative(this.root, fullPath).split(sep).join('/')\n out.push({\n relativePath: rel,\n absolutePath: fullPath,\n modTimeMillis: Math.floor(s.mtimeMs),\n size: s.size,\n })\n } catch {\n // skip unreadable files\n }\n }\n }\n }\n}\n"],"names":[],"mappings":";;AAQO,MAAM,YAAkC;AAAA,EACpC,OAAO;AAAA;AAAA,EAEP;AAAA;AAAA;AAAA;AAAA;AAAA,EAMT,YAAY,MAAc;AACxB,SAAK,OAAO;AAAA,EACd;AAAA;AAAA,EAGA,OAAO,OAAsC;AAC3C,UAAM,YAA6B,CAAA;AACnC,UAAM,KAAK,KAAK,KAAK,MAAM,SAAS;AACpC,cAAU,KAAK,CAAC,GAAG,MAAM,EAAE,aAAa,cAAc,EAAE,YAAY,CAAC;AACrE,eAAW,SAAS,WAAW;AAC7B,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,KAAK,KAAa,KAAqC;AACnE,QAAI;AACJ,QAAI;AACF,gBAAU,MAAM,QAAQ,KAAK,EAAE,eAAe,MAAM;AAAA,IACtD,QAAQ;AACN;AAAA,IACF;AAEA,eAAW,SAAS,SAAS;AAC3B,YAAM,WAAW,KAAK,KAAK,MAAM,IAAI;AACrC,UAAI,MAAM,eAAe;AACvB,cAAM,KAAK,KAAK,UAAU,GAAG;AAAA,MAC/B,WAAW,MAAM,UAAU;AACzB,YAAI;AACF,gBAAM,IAAI,MAAM,KAAK,QAAQ;AAC7B,gBAAM,MAAM,SAAS,KAAK,MAAM,QAAQ,EAAE,MAAM,GAAG,EAAE,KAAK,GAAG;AAC7D,cAAI,KAAK;AAAA,YACP,cAAc;AAAA,YACd,cAAc;AAAA,YACd,eAAe,KAAK,MAAM,EAAE,OAAO;AAAA,YACnC,MAAM,EAAE;AAAA,UAAA,CACT;AAAA,QACH,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;"}
|
|
1
|
+
{"version":3,"file":"local.js","names":[],"sources":["../../../src/sync/scanners/local.ts"],"sourcesContent":["import {\n isDownloadStagingDirectorySegment,\n isManagedDownloadStagingRoot,\n} from '../download-staging.ts'\nimport { localFilesystemErrorReason } from '../filesystem-errors.ts'\nimport {\n directoryMayContainSyncPaths,\n pathPassesSyncFilters,\n pathSkippedByRegExpInputLimit,\n} from '../filters.ts'\nimport { localFileIdentityFromStats } from '../local-file-identity.ts'\nimport { registerLocalFilesystemRoot } from '../local-filesystem-root.ts'\nimport { compareSyncRelativePaths } from '../path-order.ts'\nimport { isReservedSyncTempFileName } from '../path-safety.ts'\nimport { validateSyncFilters } from '../regexp-safety.ts'\nimport { emitScannerSkip, regexpInputTooLongSkip } from '../scan-events.ts'\nimport { assertScanEntryLimit, scanEntryLimit } from '../scan-limit.ts'\nimport type { LocalSyncPath, SyncErrorEvent, SyncFolder, SyncScanOptions } from '../types.ts'\n\ntype LocalDirent = {\n readonly name: string\n isDirectory(): boolean\n isFile(): boolean\n}\n\ntype LocalStats = {\n readonly dev: number\n readonly ino: number\n readonly mtimeMs: number\n readonly ctimeMs: number\n readonly size: number\n isFile(): boolean\n}\n\ntype LocalNodeDeps = {\n readdir(path: string, options: { readonly withFileTypes: true }): Promise<LocalDirent[]>\n lstat(path: string): Promise<LocalStats>\n join(...paths: string[]): string\n relative(from: string, to: string): string\n resolve(...paths: string[]): string\n sep: string\n}\n\n/**\n * Scans a local directory tree and yields {@link LocalSyncPath} entries sorted by relative path.\n * A root directory read failure aborts the scan with an error diagnostic. Per-entry file or\n * directory failures are reported through `onError` and the scan continues over readable siblings.\n * SDK-managed partial download file names are skipped so unfinished internal\n * temp files are not synchronized.\n * The current implementation collects matching entries before sorting, so memory usage is\n * proportional to the number of matched files.\n */\nexport class LocalFolder implements SyncFolder {\n readonly type = 'local' as const\n readonly appliesScanFilters = true as const\n readonly appliesScanSorting = true as const\n /** Resolved absolute path to the local root directory. */\n readonly root: string\n\n /**\n * Creates a new LocalFolder for the given root directory.\n * @param root - Absolute or relative path to the local directory to scan.\n */\n constructor(root: string) {\n this.root = resolvePathAtConstruction(root)\n registerLocalFilesystemRoot(this)\n }\n\n /**\n * Recursively walks the directory and yields files in sync path order.\n * @param options - Optional scan controls.\n */\n async *scan(options: SyncScanOptions = {}): AsyncGenerator<LocalSyncPath> {\n validateSyncFilters(options)\n const nodeDeps = await loadLocalNodeDeps()\n const root = nodeDeps.resolve(this.root)\n const collected: LocalSyncPath[] = []\n await this.walk(root, root, collected, options, scanEntryLimit(options), nodeDeps)\n collected.sort((a, b) => compareSyncRelativePaths(a.relativePath, b.relativePath))\n for (const entry of collected) {\n throwIfScanAborted(options)\n yield entry\n }\n }\n\n /**\n * Recursively collects files from {@link dir} into {@link out}.\n * @param root - Resolved scan root used for relative path calculation.\n * @param dir - Absolute path of the directory to scan.\n * @param out - Accumulator array that receives discovered file entries.\n * @param options - Optional scan controls.\n * @param maxScanEntries - Maximum number of entries to retain before failing.\n * @param nodeDeps - Lazy-loaded Node filesystem and path helpers.\n */\n private async walk(\n root: string,\n dir: string,\n out: LocalSyncPath[],\n options: SyncScanOptions,\n maxScanEntries: number,\n nodeDeps: LocalNodeDeps,\n ): Promise<void> {\n throwIfScanAborted(options)\n let entries: LocalDirent[]\n try {\n entries = await nodeDeps.readdir(dir, { withFileTypes: true })\n } catch (err) {\n const error = this.emitScanError(\n options,\n relativePathFromRoot(root, dir, nodeDeps),\n 'directory',\n err,\n )\n if (dir === root) throw error\n return\n }\n\n for (const entry of entries) {\n throwIfScanAborted(options)\n const fullPath = nodeDeps.join(dir, entry.name)\n const rel = relativePathFromRoot(root, fullPath, nodeDeps)\n if (\n isDownloadStagingDirectorySegment(rel) &&\n entry.isDirectory() &&\n isDownloadStagingDirectorySegment(entry.name) &&\n (await isManagedDownloadStagingRoot(fullPath))\n ) {\n continue\n }\n if (rel.includes('\\\\')) {\n emitScannerSkip(options, {\n type: 'skip',\n path: rel,\n size: 0,\n reason: 'unsafe-name',\n message: `Skipped local path ${JSON.stringify(rel)}: backslashes are not safe sync path characters`,\n })\n continue\n }\n if (isReservedSyncTempFileName(entry.name)) {\n emitScannerSkip(options, {\n type: 'skip',\n path: rel,\n size: 0,\n reason: 'stale-download-partial',\n message: `Skipped local path ${JSON.stringify(rel)}: reserved SDK partial download file`,\n })\n continue\n }\n // Symlinks, FIFOs, sockets, and device nodes are not syncable files.\n // Ignore them without poisoning delete-mode orphan handling for unrelated paths.\n if (entry.isDirectory()) {\n if (directoryMayContainSyncPaths(rel, options)) {\n await this.walk(root, fullPath, out, options, maxScanEntries, nodeDeps)\n }\n } else if (entry.isFile()) {\n if (!pathPassesSyncFilters(rel, options)) {\n if (pathSkippedByRegExpInputLimit(rel, options)) {\n emitScannerSkip(options, regexpInputTooLongSkip(rel))\n }\n continue\n }\n let s: LocalStats\n try {\n s = await nodeDeps.lstat(fullPath)\n /* v8 ignore start -- lstat race after a Dirent file result is not deterministic */\n if (!s.isFile()) {\n this.emitScanError(options, rel, 'file', new Error('not a regular file'))\n continue\n }\n /* v8 ignore stop */\n } catch (err) {\n /* v8 ignore next -- stat TOCTOU failures are not deterministic to trigger */\n this.emitScanError(options, relativePathFromRoot(root, fullPath, nodeDeps), 'file', err)\n continue\n }\n assertScanEntryLimit(out.length + 1, maxScanEntries)\n out.push({\n relativePath: rel,\n absolutePath: fullPath,\n modTimeMillis: Math.floor(s.mtimeMs),\n size: s.size,\n fileIdentity: localFileIdentityFromStats(s),\n })\n }\n }\n }\n\n private emitScanError(\n options: SyncScanOptions,\n path: string,\n kind: 'directory' | 'file',\n err: unknown,\n ): Error {\n const event: SyncErrorEvent = {\n type: 'error',\n path,\n size: 0,\n message: `failed to scan local ${kind}: ${localFilesystemErrorReason(err)}`,\n }\n options.onError?.(event)\n return new Error(event.message)\n }\n}\n\nasync function loadLocalNodeDeps(): Promise<LocalNodeDeps> {\n const [fsPromises, path] = await Promise.all([import('node:fs/promises'), import('node:path')])\n return {\n readdir: fsPromises.readdir as LocalNodeDeps['readdir'],\n lstat: fsPromises.lstat as LocalNodeDeps['lstat'],\n join: path.join,\n relative: path.relative,\n resolve: path.resolve,\n sep: path.sep,\n }\n}\n\nfunction resolvePathAtConstruction(root: string): string {\n const processLike = (\n globalThis as {\n process?: { cwd?: () => string; platform?: string }\n }\n ).process\n if (typeof processLike?.cwd !== 'function') return root\n\n const cwd = processLike.cwd()\n if (processLike.platform === 'win32') return resolveWindowsPath(cwd, root)\n return resolvePosixPath(cwd, root)\n}\n\nfunction resolvePosixPath(cwd: string, root: string): string {\n const joined = root.startsWith('/') ? root : `${cwd}/${root}`\n const resolved = normalizePathSegments(joined.split('/'), '/')\n return resolved === '' ? '/' : `/${resolved}`\n}\n\nfunction resolveWindowsPath(cwd: string, root: string): string {\n const normalizedRoot = root.replaceAll('/', '\\\\')\n const normalizedCwd = cwd.replaceAll('/', '\\\\')\n const drive = /^[A-Za-z]:/.exec(normalizedCwd)?.[0] ?? ''\n const cwdUnc = splitUncPath(normalizedCwd)\n if (/^\\\\\\\\/.test(normalizedRoot)) return normalizeUncPath(normalizedRoot)\n if (/^[A-Za-z]:\\\\/.test(normalizedRoot)) {\n const prefix = normalizedRoot.slice(0, 2)\n const rest = normalizedRoot.slice(3).split('\\\\')\n return joinWindowsRoot(prefix, normalizePathSegments(rest, '\\\\'))\n }\n if (/^[A-Za-z]:/.test(normalizedRoot)) {\n throw new Error('LocalFolder root must not be a drive-relative Windows path')\n }\n if (normalizedRoot.startsWith('\\\\')) {\n const rest = normalizePathSegments(normalizedRoot.slice(1).split('\\\\'), '\\\\')\n return joinWindowsRoot(cwdUnc?.prefix ?? drive, rest)\n }\n if (cwdUnc !== undefined) {\n const resolved = normalizePathSegments([...cwdUnc.rest, ...normalizedRoot.split('\\\\')], '\\\\')\n return joinWindowsRoot(cwdUnc.prefix, resolved)\n }\n const base = /^[A-Za-z]:\\\\/.test(normalizedCwd) ? normalizedCwd : `${drive}\\\\`\n const prefix = /^[A-Za-z]:/.exec(base)?.[0] ?? drive\n const baseRest = base.slice(prefix.length).replace(/^\\\\/, '').split('\\\\')\n const resolved = normalizePathSegments([...baseRest, ...normalizedRoot.split('\\\\')], '\\\\')\n return joinWindowsRoot(prefix, resolved)\n}\n\nfunction normalizeUncPath(path: string): string {\n const unc = splitUncPath(path)\n if (unc === undefined) return path\n return joinWindowsRoot(unc.prefix, normalizePathSegments(unc.rest, '\\\\'))\n}\n\nfunction splitUncPath(\n path: string,\n): { readonly prefix: string; readonly rest: string[] } | undefined {\n if (!path.startsWith('\\\\\\\\')) return undefined\n const parts = path.split('\\\\').filter((part) => part !== '')\n const [server, share, ...rest] = parts\n if (server === undefined || share === undefined) return undefined\n return { prefix: `\\\\\\\\${server}\\\\${share}`, rest }\n}\n\nfunction joinWindowsRoot(prefix: string, rest: string): string {\n return rest === '' ? `${prefix}\\\\` : `${prefix}\\\\${rest}`\n}\n\nfunction normalizePathSegments(segments: readonly string[], separator: '/' | '\\\\'): string {\n const out: string[] = []\n for (const segment of segments) {\n if (segment === '' || segment === '.') continue\n if (segment === '..') {\n out.pop()\n continue\n }\n out.push(segment)\n }\n return out.join(separator)\n}\n\nfunction relativePathFromRoot(root: string, path: string, nodeDeps: LocalNodeDeps): string {\n return nodeDeps.relative(root, path).split(nodeDeps.sep).join('/')\n}\n\nfunction throwIfScanAborted(options: SyncScanOptions): void {\n if (options.signal?.aborted === true) {\n throw options.signal.reason ?? new DOMException('Aborted', 'AbortError')\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
const require_sha1 = require("../util/sha1.cjs");
|
|
2
|
+
//#region src/sync/sha1-metadata.ts
|
|
3
|
+
/** Prefix used to mark SHA-1 metadata that must not prove equality without byte verification. */
|
|
4
|
+
var untrustedSha1Prefix = "unverified:";
|
|
5
|
+
/**
|
|
6
|
+
* Marks a verifiable SHA-1 digest as untrusted provider metadata.
|
|
7
|
+
*
|
|
8
|
+
* @param sha1 - Verifiable 40-character hexadecimal SHA-1 digest.
|
|
9
|
+
*
|
|
10
|
+
* @returns The untrusted SHA-1 sentinel value.
|
|
11
|
+
*
|
|
12
|
+
* @throws When the supplied value is not a verifiable SHA-1 digest.
|
|
13
|
+
*/
|
|
14
|
+
function untrustedSha1(sha1) {
|
|
15
|
+
const normalized = require_sha1.normalizeVerifiableSha1(sha1);
|
|
16
|
+
if (normalized === null) throw new Error("untrusted SHA-1 metadata must be verifiable");
|
|
17
|
+
return `${untrustedSha1Prefix}${normalized}`;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Extracts the best comparable SHA-1 value from a B2 file version.
|
|
21
|
+
*
|
|
22
|
+
* B2's primary `contentSha1` is authoritative for single-part uploads when it is a verifiable
|
|
23
|
+
* digest. Large/multipart B2 files report `contentSha1: null`; `fileInfo.large_file_sha1` is
|
|
24
|
+
* caller-provided metadata, so it is returned as an untrusted hint that cannot prove equality
|
|
25
|
+
* until the high-level synchronizer hashes the selected version's bytes.
|
|
26
|
+
*
|
|
27
|
+
* @param version - B2 file version metadata.
|
|
28
|
+
*
|
|
29
|
+
* @returns A lowercase comparable SHA-1, an untrusted sentinel, or null when unavailable.
|
|
30
|
+
*/
|
|
31
|
+
function selectB2ComparableSha1(version) {
|
|
32
|
+
const originalContentSha1 = version.contentSha1;
|
|
33
|
+
if (typeof originalContentSha1 === "string") {
|
|
34
|
+
if (isUntrustedSha1(originalContentSha1)) return originalContentSha1.toLowerCase();
|
|
35
|
+
return require_sha1.normalizeVerifiableSha1(originalContentSha1) ?? originalContentSha1.toLowerCase();
|
|
36
|
+
}
|
|
37
|
+
const largeFileSha1 = require_sha1.normalizeVerifiableSha1(version.fileInfo["large_file_sha1"]);
|
|
38
|
+
return largeFileSha1 === null ? null : untrustedSha1(largeFileSha1);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Returns whether a SHA-1 value is marked as untrusted metadata.
|
|
42
|
+
*
|
|
43
|
+
* @param sha1 - Candidate SHA-1 metadata.
|
|
44
|
+
*
|
|
45
|
+
* @returns True when the value carries B2's unverified sentinel prefix.
|
|
46
|
+
*/
|
|
47
|
+
function isUntrustedSha1(sha1) {
|
|
48
|
+
return sha1?.toLowerCase().startsWith("unverified:") ?? false;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Parses the public `SyncPath.contentSha1` value into an explicit trust/availability state.
|
|
52
|
+
*
|
|
53
|
+
* @param sha1 - The raw `contentSha1` field from a sync path.
|
|
54
|
+
*
|
|
55
|
+
* @returns A discriminated state so custom scanners do not need to decode sentinels directly.
|
|
56
|
+
*/
|
|
57
|
+
function parseSyncContentSha1(sha1) {
|
|
58
|
+
if (sha1 === void 0) return { kind: "pending" };
|
|
59
|
+
if (sha1 === null) return { kind: "unavailable" };
|
|
60
|
+
if (isUntrustedSha1(sha1)) return {
|
|
61
|
+
kind: "untrusted",
|
|
62
|
+
raw: sha1,
|
|
63
|
+
value: require_sha1.normalizeVerifiableSha1(sha1.slice(11))
|
|
64
|
+
};
|
|
65
|
+
const normalized = require_sha1.normalizeVerifiableSha1(sha1);
|
|
66
|
+
if (normalized === null) return {
|
|
67
|
+
kind: "untrusted",
|
|
68
|
+
raw: sha1,
|
|
69
|
+
value: null
|
|
70
|
+
};
|
|
71
|
+
return {
|
|
72
|
+
kind: "verified",
|
|
73
|
+
value: normalized
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Reads an explicit SHA-1 state when present, otherwise parses the compatibility field.
|
|
78
|
+
*
|
|
79
|
+
* @param path - Object carrying SHA-1 metadata.
|
|
80
|
+
*
|
|
81
|
+
* @returns The explicit or parsed SHA-1 state.
|
|
82
|
+
*/
|
|
83
|
+
function syncSha1StateOf(path) {
|
|
84
|
+
return path.contentSha1State ?? parseSyncContentSha1(path.contentSha1);
|
|
85
|
+
}
|
|
86
|
+
//#endregion
|
|
87
|
+
exports.isUntrustedSha1 = isUntrustedSha1;
|
|
88
|
+
exports.parseSyncContentSha1 = parseSyncContentSha1;
|
|
89
|
+
exports.selectB2ComparableSha1 = selectB2ComparableSha1;
|
|
90
|
+
exports.syncSha1StateOf = syncSha1StateOf;
|
|
91
|
+
exports.untrustedSha1 = untrustedSha1;
|
|
92
|
+
exports.untrustedSha1Prefix = untrustedSha1Prefix;
|
|
93
|
+
|
|
94
|
+
//# sourceMappingURL=sha1-metadata.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sha1-metadata.cjs","names":[],"sources":["../../src/sync/sha1-metadata.ts"],"sourcesContent":["import type { FileVersion } from '../types/file.ts'\nimport { normalizeVerifiableSha1 } from '../util/sha1.ts'\n\n/** Prefix used to mark SHA-1 metadata that must not prove equality without byte verification. */\nexport const untrustedSha1Prefix = 'unverified:'\n\n/** SHA-1 has not been computed or populated yet. */\nexport interface SyncSha1PendingState {\n /** State discriminator. */\n readonly kind: 'pending'\n}\n\n/** SHA-1 is known to be unavailable for this path. */\nexport interface SyncSha1UnavailableState {\n /** State discriminator. */\n readonly kind: 'unavailable'\n}\n\n/** SHA-1 is a normalized 40-character digest that may prove equality. */\nexport interface SyncSha1VerifiedState {\n /** State discriminator. */\n readonly kind: 'verified'\n /** Normalized lowercase 40-character SHA-1 digest. */\n readonly value: string\n}\n\n/** SHA-1 metadata is present but cannot prove equality without verification. */\nexport interface SyncSha1UntrustedState {\n /** State discriminator. */\n readonly kind: 'untrusted'\n /** Normalized digest when one can be extracted from the raw metadata. */\n readonly value: string | null\n /** Original metadata string supplied by the scanner or B2 file version. */\n readonly raw: string\n}\n\n/** Public SHA-1 state used by sync scanners and low-level compare helpers. */\nexport type SyncSha1State =\n | SyncSha1PendingState\n | SyncSha1UnavailableState\n | SyncSha1VerifiedState\n | SyncSha1UntrustedState\n\n/**\n * Marks a verifiable SHA-1 digest as untrusted provider metadata.\n *\n * @param sha1 - Verifiable 40-character hexadecimal SHA-1 digest.\n *\n * @returns The untrusted SHA-1 sentinel value.\n *\n * @throws When the supplied value is not a verifiable SHA-1 digest.\n */\nexport function untrustedSha1(sha1: string): string {\n const normalized = normalizeVerifiableSha1(sha1)\n if (normalized === null) throw new Error('untrusted SHA-1 metadata must be verifiable')\n return `${untrustedSha1Prefix}${normalized}`\n}\n\n/**\n * Extracts the best comparable SHA-1 value from a B2 file version.\n *\n * B2's primary `contentSha1` is authoritative for single-part uploads when it is a verifiable\n * digest. Large/multipart B2 files report `contentSha1: null`; `fileInfo.large_file_sha1` is\n * caller-provided metadata, so it is returned as an untrusted hint that cannot prove equality\n * until the high-level synchronizer hashes the selected version's bytes.\n *\n * @param version - B2 file version metadata.\n *\n * @returns A lowercase comparable SHA-1, an untrusted sentinel, or null when unavailable.\n */\nexport function selectB2ComparableSha1(version: FileVersion): string | null {\n const originalContentSha1 = version.contentSha1\n if (typeof originalContentSha1 === 'string') {\n if (isUntrustedSha1(originalContentSha1)) return originalContentSha1.toLowerCase()\n const contentSha1 = normalizeVerifiableSha1(originalContentSha1)\n return contentSha1 ?? originalContentSha1.toLowerCase()\n }\n\n const largeFileSha1 = normalizeVerifiableSha1(version.fileInfo['large_file_sha1'])\n return largeFileSha1 === null ? null : untrustedSha1(largeFileSha1)\n}\n\n/**\n * Returns whether a SHA-1 value is marked as untrusted metadata.\n *\n * @param sha1 - Candidate SHA-1 metadata.\n *\n * @returns True when the value carries B2's unverified sentinel prefix.\n */\nexport function isUntrustedSha1(sha1: string | null | undefined): boolean {\n return sha1?.toLowerCase().startsWith(untrustedSha1Prefix) ?? false\n}\n\n/**\n * Parses the public `SyncPath.contentSha1` value into an explicit trust/availability state.\n *\n * @param sha1 - The raw `contentSha1` field from a sync path.\n *\n * @returns A discriminated state so custom scanners do not need to decode sentinels directly.\n */\nexport function parseSyncContentSha1(sha1: string | null | undefined): SyncSha1State {\n if (sha1 === undefined) return { kind: 'pending' }\n if (sha1 === null) return { kind: 'unavailable' }\n if (isUntrustedSha1(sha1)) {\n return {\n kind: 'untrusted',\n raw: sha1,\n value: normalizeVerifiableSha1(sha1.slice(untrustedSha1Prefix.length)),\n }\n }\n const normalized = normalizeVerifiableSha1(sha1)\n if (normalized === null) return { kind: 'untrusted', raw: sha1, value: null }\n return { kind: 'verified', value: normalized }\n}\n\n/**\n * Reads an explicit SHA-1 state when present, otherwise parses the compatibility field.\n *\n * @param path - Object carrying SHA-1 metadata.\n *\n * @returns The explicit or parsed SHA-1 state.\n */\nexport function syncSha1StateOf(path: {\n readonly contentSha1?: string | null\n readonly contentSha1State?: SyncSha1State\n}): SyncSha1State {\n return path.contentSha1State ?? parseSyncContentSha1(path.contentSha1)\n}\n"],"mappings":";;;AAIA,IAAa,sBAAsB;;;;;;;;;;AAgDnC,SAAgB,cAAc,MAAsB;CAClD,MAAM,aAAa,aAAA,wBAAwB,IAAI;CAC/C,IAAI,eAAe,MAAM,MAAM,IAAI,MAAM,6CAA6C;CACtF,OAAO,GAAG,sBAAsB;AAClC;;;;;;;;;;;;;AAcA,SAAgB,uBAAuB,SAAqC;CAC1E,MAAM,sBAAsB,QAAQ;CACpC,IAAI,OAAO,wBAAwB,UAAU;EAC3C,IAAI,gBAAgB,mBAAmB,GAAG,OAAO,oBAAoB,YAAY;EAEjF,OADoB,aAAA,wBAAwB,mBACrC,KAAe,oBAAoB,YAAY;CACxD;CAEA,MAAM,gBAAgB,aAAA,wBAAwB,QAAQ,SAAS,kBAAkB;CACjF,OAAO,kBAAkB,OAAO,OAAO,cAAc,aAAa;AACpE;;;;;;;;AASA,SAAgB,gBAAgB,MAA0C;CACxE,OAAO,MAAM,YAAY,CAAC,CAAC,WAAA,aAA8B,KAAK;AAChE;;;;;;;;AASA,SAAgB,qBAAqB,MAAgD;CACnF,IAAI,SAAS,KAAA,GAAW,OAAO,EAAE,MAAM,UAAU;CACjD,IAAI,SAAS,MAAM,OAAO,EAAE,MAAM,cAAc;CAChD,IAAI,gBAAgB,IAAI,GACtB,OAAO;EACL,MAAM;EACN,KAAK;EACL,OAAO,aAAA,wBAAwB,KAAK,MAAM,EAA0B,CAAC;CACvE;CAEF,MAAM,aAAa,aAAA,wBAAwB,IAAI;CAC/C,IAAI,eAAe,MAAM,OAAO;EAAE,MAAM;EAAa,KAAK;EAAM,OAAO;CAAK;CAC5E,OAAO;EAAE,MAAM;EAAY,OAAO;CAAW;AAC/C;;;;;;;;AASA,SAAgB,gBAAgB,MAGd;CAChB,OAAO,KAAK,oBAAoB,qBAAqB,KAAK,WAAW;AACvE"}
|