zeed 1.3.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_experiments/bitcask.cjs +243 -1
- package/dist/_experiments/bitcask.cjs.map +1 -1
- package/dist/_experiments/bitcask.mjs +230 -1
- package/dist/_experiments/bitcask.mjs.map +1 -1
- package/dist/bin-BAoS4qtm.mjs +593 -0
- package/dist/{bin-SPdenYkw.mjs.map → bin-BAoS4qtm.mjs.map} +1 -1
- package/dist/bin-Ddaz2lxM.cjs +862 -0
- package/dist/{bin-Ce3i6ABn.cjs.map → bin-Ddaz2lxM.cjs.map} +1 -1
- package/dist/browser/base64.cjs +14 -1
- package/dist/browser/base64.cjs.map +1 -1
- package/dist/browser/base64.mjs +12 -1
- package/dist/browser/base64.mjs.map +1 -1
- package/dist/browser/gravatar.cjs +186 -1
- package/dist/browser/gravatar.cjs.map +1 -1
- package/dist/browser/gravatar.mjs +184 -1
- package/dist/browser/gravatar.mjs.map +1 -1
- package/dist/browser/index.cjs +14 -1
- package/dist/browser/index.mjs +8 -1
- package/dist/browser/localstorage.cjs +46 -1
- package/dist/browser/localstorage.cjs.map +1 -1
- package/dist/browser/localstorage.mjs +45 -1
- package/dist/browser/localstorage.mjs.map +1 -1
- package/dist/browser/log/index.cjs +8 -1
- package/dist/browser/log/index.mjs +5 -1
- package/dist/browser/log/log-browser-factory.cjs +65 -1
- package/dist/browser/log/log-browser-factory.cjs.map +1 -1
- package/dist/browser/log/log-browser-factory.mjs +64 -1
- package/dist/browser/log/log-browser-factory.mjs.map +1 -1
- package/dist/browser/log/log-browser.cjs +72 -1
- package/dist/browser/log/log-browser.cjs.map +1 -1
- package/dist/browser/log/log-browser.mjs +71 -1
- package/dist/browser/log/log-browser.mjs.map +1 -1
- package/dist/browser/log/log-colors.cjs +11 -1
- package/dist/browser/log/log-colors.cjs.map +1 -1
- package/dist/browser/log/log-colors.mjs +9 -1
- package/dist/browser/log/log-colors.mjs.map +1 -1
- package/dist/browser/log/log-context-browser.cjs +25 -1
- package/dist/browser/log/log-context-browser.cjs.map +1 -1
- package/dist/browser/log/log-context-browser.mjs +23 -1
- package/dist/browser/log/log-context-browser.mjs.map +1 -1
- package/dist/chunk-DQk6qfdC.mjs +18 -0
- package/dist/chunk-uaV2rQ02.cjs +53 -0
- package/dist/common/assert.cjs +22 -1
- package/dist/common/assert.cjs.map +1 -1
- package/dist/common/assert.mjs +19 -1
- package/dist/common/assert.mjs.map +1 -1
- package/dist/common/bin/index.cjs +106 -1
- package/dist/common/bin/index.cjs.map +1 -1
- package/dist/common/bin/index.mjs +98 -1
- package/dist/common/bin/index.mjs.map +1 -1
- package/dist/common/bin/lib0/binary.cjs +146 -1
- package/dist/common/bin/lib0/binary.cjs.map +1 -1
- package/dist/common/bin/lib0/binary.mjs +80 -1
- package/dist/common/bin/lib0/binary.mjs.map +1 -1
- package/dist/common/bin/lib0/buffer.cjs +42 -1
- package/dist/common/bin/lib0/buffer.cjs.map +1 -1
- package/dist/common/bin/lib0/buffer.mjs +38 -1
- package/dist/common/bin/lib0/buffer.mjs.map +1 -1
- package/dist/common/bin/lib0/create.cjs +24 -1
- package/dist/common/bin/lib0/create.cjs.map +1 -1
- package/dist/common/bin/lib0/create.mjs +21 -1
- package/dist/common/bin/lib0/create.mjs.map +1 -1
- package/dist/common/bin/lib0/decoding.cjs +325 -1
- package/dist/common/bin/lib0/decoding.cjs.map +1 -1
- package/dist/common/bin/lib0/decoding.mjs +298 -1
- package/dist/common/bin/lib0/decoding.mjs.map +1 -1
- package/dist/common/bin/lib0/encoding.cjs +404 -1
- package/dist/common/bin/lib0/encoding.cjs.map +1 -1
- package/dist/common/bin/lib0/encoding.mjs +377 -1
- package/dist/common/bin/lib0/encoding.mjs.map +1 -1
- package/dist/common/bin/lib0/string.cjs +81 -1
- package/dist/common/bin/lib0/string.cjs.map +1 -1
- package/dist/common/bin/lib0/string.mjs +71 -1
- package/dist/common/bin/lib0/string.mjs.map +1 -1
- package/dist/common/crypto/aes-sealed.cjs +34 -1
- package/dist/common/crypto/aes-sealed.cjs.map +1 -1
- package/dist/common/crypto/aes-sealed.mjs +32 -1
- package/dist/common/crypto/aes-sealed.mjs.map +1 -1
- package/dist/common/crypto/crypto.cjs +91 -1
- package/dist/common/crypto/crypto.cjs.map +1 -1
- package/dist/common/crypto/crypto.mjs +80 -1
- package/dist/common/crypto/crypto.mjs.map +1 -1
- package/dist/common/crypto/index.cjs +23 -1
- package/dist/common/crypto/index.mjs +5 -1
- package/dist/common/crypto/xaes.cjs +128 -1
- package/dist/common/crypto/xaes.cjs.map +1 -1
- package/dist/common/crypto/xaes.mjs +123 -1
- package/dist/common/crypto/xaes.mjs.map +1 -1
- package/dist/common/csv.cjs +49 -4
- package/dist/common/csv.cjs.map +1 -1
- package/dist/common/csv.mjs +46 -4
- package/dist/common/csv.mjs.map +1 -1
- package/dist/common/data/array.cjs +299 -1
- package/dist/common/data/array.cjs.map +1 -1
- package/dist/common/data/array.mjs +274 -1
- package/dist/common/data/array.mjs.map +1 -1
- package/dist/common/data/basex-secure.cjs +30 -1
- package/dist/common/data/basex-secure.mjs +3 -1
- package/dist/common/data/basex.cjs +163 -1
- package/dist/common/data/basex.cjs.map +1 -1
- package/dist/common/data/basex.mjs +152 -1
- package/dist/common/data/basex.mjs.map +1 -1
- package/dist/common/data/bin-types.mjs +1 -1
- package/dist/common/data/bin.cjs +21 -1
- package/dist/common/data/bin.mjs +3 -1
- package/dist/common/data/camelcase.cjs +27 -1
- package/dist/common/data/camelcase.cjs.map +1 -1
- package/dist/common/data/camelcase.mjs +22 -1
- package/dist/common/data/camelcase.mjs.map +1 -1
- package/dist/common/data/convert.cjs +104 -1
- package/dist/common/data/convert.cjs.map +1 -1
- package/dist/common/data/convert.mjs +88 -1
- package/dist/common/data/convert.mjs.map +1 -1
- package/dist/common/data/datauri.cjs +32 -1
- package/dist/common/data/datauri.cjs.map +1 -1
- package/dist/common/data/datauri.mjs +27 -1
- package/dist/common/data/datauri.mjs.map +1 -1
- package/dist/common/data/day-legacy.cjs +148 -1
- package/dist/common/data/day-legacy.cjs.map +1 -1
- package/dist/common/data/day-legacy.mjs +143 -1
- package/dist/common/data/day-legacy.mjs.map +1 -1
- package/dist/common/data/day.cjs +335 -1
- package/dist/common/data/day.cjs.map +1 -1
- package/dist/common/data/day.mjs +305 -1
- package/dist/common/data/day.mjs.map +1 -1
- package/dist/common/data/decimal.cjs +28 -1
- package/dist/common/data/decimal.cjs.map +1 -1
- package/dist/common/data/decimal.mjs +23 -1
- package/dist/common/data/decimal.mjs.map +1 -1
- package/dist/common/data/deep.cjs +57 -1
- package/dist/common/data/deep.cjs.map +1 -1
- package/dist/common/data/deep.mjs +54 -1
- package/dist/common/data/deep.mjs.map +1 -1
- package/dist/common/data/diff.cjs +62 -1
- package/dist/common/data/diff.cjs.map +1 -1
- package/dist/common/data/diff.mjs +60 -1
- package/dist/common/data/diff.mjs.map +1 -1
- package/dist/common/data/distributed.cjs +24 -1
- package/dist/common/data/distributed.cjs.map +1 -1
- package/dist/common/data/distributed.mjs +22 -1
- package/dist/common/data/distributed.mjs.map +1 -1
- package/dist/common/data/format.cjs +63 -1
- package/dist/common/data/format.cjs.map +1 -1
- package/dist/common/data/format.mjs +59 -1
- package/dist/common/data/format.mjs.map +1 -1
- package/dist/common/data/html.cjs +13 -1
- package/dist/common/data/html.cjs.map +1 -1
- package/dist/common/data/html.mjs +10 -1
- package/dist/common/data/html.mjs.map +1 -1
- package/dist/common/data/index.cjs +296 -1
- package/dist/common/data/index.mjs +37 -1
- package/dist/common/data/is.cjs +106 -1
- package/dist/common/data/is.cjs.map +1 -1
- package/dist/common/data/is.mjs +85 -1
- package/dist/common/data/is.mjs.map +1 -1
- package/dist/common/data/json.cjs +70 -1
- package/dist/common/data/json.cjs.map +1 -1
- package/dist/common/data/json.mjs +65 -1
- package/dist/common/data/json.mjs.map +1 -1
- package/dist/common/data/list.cjs +32 -1
- package/dist/common/data/list.cjs.map +1 -1
- package/dist/common/data/list.mjs +27 -1
- package/dist/common/data/list.mjs.map +1 -1
- package/dist/common/data/lru.mjs +1 -1
- package/dist/common/data/math.cjs +79 -1
- package/dist/common/data/math.cjs.map +1 -1
- package/dist/common/data/math.mjs +65 -1
- package/dist/common/data/math.mjs.map +1 -1
- package/dist/common/data/message.cjs +30 -1
- package/dist/common/data/message.cjs.map +1 -1
- package/dist/common/data/message.mjs +28 -1
- package/dist/common/data/message.mjs.map +1 -1
- package/dist/common/data/object-changes.cjs +66 -1
- package/dist/common/data/object-changes.cjs.map +1 -1
- package/dist/common/data/object-changes.mjs +63 -1
- package/dist/common/data/object-changes.mjs.map +1 -1
- package/dist/common/data/object.cjs +112 -1
- package/dist/common/data/object.cjs.map +1 -1
- package/dist/common/data/object.mjs +104 -1
- package/dist/common/data/object.mjs.map +1 -1
- package/dist/common/data/orderby.cjs +42 -1
- package/dist/common/data/orderby.cjs.map +1 -1
- package/dist/common/data/orderby.mjs +37 -1
- package/dist/common/data/orderby.mjs.map +1 -1
- package/dist/common/data/path.cjs +26 -1
- package/dist/common/data/path.cjs.map +1 -1
- package/dist/common/data/path.mjs +25 -1
- package/dist/common/data/path.mjs.map +1 -1
- package/dist/common/data/regexp.cjs +12 -1
- package/dist/common/data/regexp.cjs.map +1 -1
- package/dist/common/data/regexp.mjs +10 -1
- package/dist/common/data/regexp.mjs.map +1 -1
- package/dist/common/data/rounding.cjs +107 -1
- package/dist/common/data/rounding.cjs.map +1 -1
- package/dist/common/data/rounding.mjs +95 -1
- package/dist/common/data/rounding.mjs.map +1 -1
- package/dist/common/data/signal.cjs +39 -1
- package/dist/common/data/signal.cjs.map +1 -1
- package/dist/common/data/signal.mjs +38 -1
- package/dist/common/data/signal.mjs.map +1 -1
- package/dist/common/data/sortable.cjs +35 -1
- package/dist/common/data/sortable.cjs.map +1 -1
- package/dist/common/data/sortable.mjs +31 -1
- package/dist/common/data/sortable.mjs.map +1 -1
- package/dist/common/data/sorted.cjs +54 -1
- package/dist/common/data/sorted.cjs.map +1 -1
- package/dist/common/data/sorted.mjs +53 -1
- package/dist/common/data/sorted.mjs.map +1 -1
- package/dist/common/data/string-deburr.cjs +240 -1
- package/dist/common/data/string-deburr.cjs.map +1 -1
- package/dist/common/data/string-deburr.mjs +238 -1
- package/dist/common/data/string-deburr.mjs.map +1 -1
- package/dist/common/data/string-hash-fnv.cjs +69 -1
- package/dist/common/data/string-hash-fnv.cjs.map +1 -1
- package/dist/common/data/string-hash-fnv.mjs +67 -1
- package/dist/common/data/string-hash-fnv.mjs.map +1 -1
- package/dist/common/data/string-hash-pool.cjs +28 -1
- package/dist/common/data/string-hash-pool.cjs.map +1 -1
- package/dist/common/data/string-hash-pool.mjs +27 -1
- package/dist/common/data/string-hash-pool.mjs.map +1 -1
- package/dist/common/data/url.cjs +98 -2
- package/dist/common/data/url.cjs.map +1 -1
- package/dist/common/data/url.mjs +91 -2
- package/dist/common/data/url.mjs.map +1 -1
- package/dist/common/data/utils.cjs +118 -1
- package/dist/common/data/utils.cjs.map +1 -1
- package/dist/common/data/utils.mjs +107 -1
- package/dist/common/data/utils.mjs.map +1 -1
- package/dist/common/data/wordlist.cjs +531 -1
- package/dist/common/data/wordlist.cjs.map +1 -1
- package/dist/common/data/wordlist.mjs +529 -1
- package/dist/common/data/wordlist.mjs.map +1 -1
- package/dist/common/data/xrx.cjs +96 -1
- package/dist/common/data/xrx.cjs.map +1 -1
- package/dist/common/data/xrx.mjs +92 -1
- package/dist/common/data/xrx.mjs.map +1 -1
- package/dist/common/dispose-defer.cjs +133 -1
- package/dist/common/dispose-defer.cjs.map +1 -1
- package/dist/common/dispose-defer.mjs +130 -1
- package/dist/common/dispose-defer.mjs.map +1 -1
- package/dist/common/dispose-types.mjs +1 -1
- package/dist/common/dispose-utils.cjs +113 -1
- package/dist/common/dispose-utils.cjs.map +1 -1
- package/dist/common/dispose-utils.mjs +106 -1
- package/dist/common/dispose-utils.mjs.map +1 -1
- package/dist/common/exec/index.cjs +24 -1
- package/dist/common/exec/index.mjs +8 -1
- package/dist/common/exec/mutex.cjs +44 -1
- package/dist/common/exec/mutex.cjs.map +1 -1
- package/dist/common/exec/mutex.mjs +42 -1
- package/dist/common/exec/mutex.mjs.map +1 -1
- package/dist/common/exec/pool.cjs +181 -1
- package/dist/common/exec/pool.cjs.map +1 -1
- package/dist/common/exec/pool.mjs +180 -1
- package/dist/common/exec/pool.mjs.map +1 -1
- package/dist/common/exec/progress.cjs +149 -1
- package/dist/common/exec/progress.cjs.map +1 -1
- package/dist/common/exec/progress.mjs +148 -1
- package/dist/common/exec/progress.mjs.map +1 -1
- package/dist/common/exec/promise.cjs +113 -1
- package/dist/common/exec/promise.cjs.map +1 -1
- package/dist/common/exec/promise.mjs +103 -1
- package/dist/common/exec/promise.mjs.map +1 -1
- package/dist/common/exec/queue.cjs +125 -1
- package/dist/common/exec/queue.cjs.map +1 -1
- package/dist/common/exec/queue.mjs +124 -1
- package/dist/common/exec/queue.mjs.map +1 -1
- package/dist/common/exec/throttle-debounce.cjs +114 -1
- package/dist/common/exec/throttle-debounce.cjs.map +1 -1
- package/dist/common/exec/throttle-debounce.mjs +112 -1
- package/dist/common/exec/throttle-debounce.mjs.map +1 -1
- package/dist/common/global.cjs +22 -1
- package/dist/common/global.cjs.map +1 -1
- package/dist/common/global.mjs +19 -1
- package/dist/common/global.mjs.map +1 -1
- package/dist/common/index.cjs +559 -1
- package/dist/common/index.mjs +89 -1
- package/dist/common/localhost.cjs +16 -1
- package/dist/common/localhost.cjs.map +1 -1
- package/dist/common/localhost.mjs +14 -1
- package/dist/common/localhost.mjs.map +1 -1
- package/dist/common/log/index.cjs +34 -1
- package/dist/common/log/index.mjs +11 -1
- package/dist/common/log/log-base.cjs +40 -1
- package/dist/common/log/log-base.cjs.map +1 -1
- package/dist/common/log/log-base.mjs +31 -1
- package/dist/common/log/log-base.mjs.map +1 -1
- package/dist/common/log/log-colors.cjs +92 -1
- package/dist/common/log/log-colors.cjs.map +1 -1
- package/dist/common/log/log-colors.mjs +90 -1
- package/dist/common/log/log-colors.mjs.map +1 -1
- package/dist/common/log/log-config.cjs +15 -1
- package/dist/common/log/log-config.cjs.map +1 -1
- package/dist/common/log/log-config.mjs +14 -1
- package/dist/common/log/log-config.mjs.map +1 -1
- package/dist/common/log/log-console-capture.cjs +33 -1
- package/dist/common/log/log-console-capture.cjs.map +1 -1
- package/dist/common/log/log-console-capture.mjs +32 -1
- package/dist/common/log/log-console-capture.mjs.map +1 -1
- package/dist/common/log/log-console-original.cjs +27 -1
- package/dist/common/log/log-console-original.cjs.map +1 -1
- package/dist/common/log/log-console-original.mjs +26 -1
- package/dist/common/log/log-console-original.mjs.map +1 -1
- package/dist/common/log/log-console.cjs +39 -1
- package/dist/common/log/log-console.cjs.map +1 -1
- package/dist/common/log/log-console.mjs +38 -1
- package/dist/common/log/log-console.mjs.map +1 -1
- package/dist/common/log/log-context.cjs +109 -1
- package/dist/common/log/log-context.cjs.map +1 -1
- package/dist/common/log/log-context.mjs +108 -1
- package/dist/common/log/log-context.mjs.map +1 -1
- package/dist/common/log/log-filter.cjs +80 -1
- package/dist/common/log/log-filter.cjs.map +1 -1
- package/dist/common/log/log-filter.mjs +75 -1
- package/dist/common/log/log-filter.mjs.map +1 -1
- package/dist/common/log/log-memory.cjs +45 -1
- package/dist/common/log/log-memory.cjs.map +1 -1
- package/dist/common/log/log-memory.mjs +43 -1
- package/dist/common/log/log-memory.mjs.map +1 -1
- package/dist/common/log/log-noop.cjs +17 -1
- package/dist/common/log/log-noop.cjs.map +1 -1
- package/dist/common/log/log-noop.mjs +15 -1
- package/dist/common/log/log-noop.mjs.map +1 -1
- package/dist/common/log/log.cjs +46 -1
- package/dist/common/log/log.cjs.map +1 -1
- package/dist/common/log/log.mjs +43 -1
- package/dist/common/log/log.mjs.map +1 -1
- package/dist/common/msg/channel-debug.cjs +17 -1
- package/dist/common/msg/channel-debug.cjs.map +1 -1
- package/dist/common/msg/channel-debug.mjs +16 -1
- package/dist/common/msg/channel-debug.mjs.map +1 -1
- package/dist/common/msg/channel-local.cjs +28 -1
- package/dist/common/msg/channel-local.cjs.map +1 -1
- package/dist/common/msg/channel-local.mjs +26 -1
- package/dist/common/msg/channel-local.mjs.map +1 -1
- package/dist/common/msg/channel-resilient.cjs +63 -1
- package/dist/common/msg/channel-resilient.cjs.map +1 -1
- package/dist/common/msg/channel-resilient.mjs +62 -1
- package/dist/common/msg/channel-resilient.mjs.map +1 -1
- package/dist/common/msg/channel-wkwebview.cjs +35 -1
- package/dist/common/msg/channel-wkwebview.cjs.map +1 -1
- package/dist/common/msg/channel-wkwebview.mjs +34 -1
- package/dist/common/msg/channel-wkwebview.mjs.map +1 -1
- package/dist/common/msg/channel.cjs +23 -1
- package/dist/common/msg/channel.cjs.map +1 -1
- package/dist/common/msg/channel.mjs +22 -1
- package/dist/common/msg/channel.mjs.map +1 -1
- package/dist/common/msg/emitter.cjs +141 -1
- package/dist/common/msg/emitter.cjs.map +1 -1
- package/dist/common/msg/emitter.mjs +139 -1
- package/dist/common/msg/emitter.mjs.map +1 -1
- package/dist/common/msg/encoder.cjs +38 -1
- package/dist/common/msg/encoder.cjs.map +1 -1
- package/dist/common/msg/encoder.mjs +35 -1
- package/dist/common/msg/encoder.mjs.map +1 -1
- package/dist/common/msg/index.cjs +28 -1
- package/dist/common/msg/index.mjs +11 -1
- package/dist/common/msg/messages.cjs +135 -1
- package/dist/common/msg/messages.cjs.map +1 -1
- package/dist/common/msg/messages.mjs +133 -1
- package/dist/common/msg/messages.mjs.map +1 -1
- package/dist/common/msg/pipe.mjs +1 -1
- package/dist/common/msg/pubsub.cjs +78 -1
- package/dist/common/msg/pubsub.cjs.map +1 -1
- package/dist/common/msg/pubsub.mjs +76 -1
- package/dist/common/msg/pubsub.mjs.map +1 -1
- package/dist/common/msg/rpc.cjs +142 -1
- package/dist/common/msg/rpc.cjs.map +1 -1
- package/dist/common/msg/rpc.mjs +139 -1
- package/dist/common/msg/rpc.mjs.map +1 -1
- package/dist/common/network.cjs +129 -1
- package/dist/common/network.cjs.map +1 -1
- package/dist/common/network.mjs +122 -1
- package/dist/common/network.mjs.map +1 -1
- package/dist/common/platform.cjs +92 -1
- package/dist/common/platform.cjs.map +1 -1
- package/dist/common/platform.mjs +84 -1
- package/dist/common/platform.mjs.map +1 -1
- package/dist/common/schema/_sandbox/sandbox-inherit.mjs +1 -1
- package/dist/common/schema/_sandbox/sandbox.mjs +1 -1
- package/dist/common/schema/_sandbox/sandbox.xspec.mjs +1 -1
- package/dist/common/schema/export-json-schema.cjs +54 -1
- package/dist/common/schema/export-json-schema.cjs.map +1 -1
- package/dist/common/schema/export-json-schema.mjs +52 -1
- package/dist/common/schema/export-json-schema.mjs.map +1 -1
- package/dist/common/schema/export-swift.cjs +30 -2
- package/dist/common/schema/export-swift.cjs.map +1 -1
- package/dist/common/schema/export-swift.mjs +29 -2
- package/dist/common/schema/export-swift.mjs.map +1 -1
- package/dist/common/schema/export-typescript.cjs +20 -2
- package/dist/common/schema/export-typescript.cjs.map +1 -1
- package/dist/common/schema/export-typescript.mjs +19 -2
- package/dist/common/schema/export-typescript.mjs.map +1 -1
- package/dist/common/schema/index.cjs +55 -1
- package/dist/common/schema/index.mjs +12 -1
- package/dist/common/schema/parse-args.cjs +62 -2
- package/dist/common/schema/parse-args.cjs.map +1 -1
- package/dist/common/schema/parse-args.mjs +60 -2
- package/dist/common/schema/parse-args.mjs.map +1 -1
- package/dist/common/schema/parse-env.cjs +48 -3
- package/dist/common/schema/parse-env.cjs.map +1 -1
- package/dist/common/schema/parse-env.mjs +46 -3
- package/dist/common/schema/parse-env.mjs.map +1 -1
- package/dist/common/schema/parse-object.cjs +122 -1
- package/dist/common/schema/parse-object.cjs.map +1 -1
- package/dist/common/schema/parse-object.mjs +119 -1
- package/dist/common/schema/parse-object.mjs.map +1 -1
- package/dist/common/schema/schema-standard.mjs +1 -1
- package/dist/common/schema/schema.cjs +423 -1
- package/dist/common/schema/schema.cjs.map +1 -1
- package/dist/common/schema/schema.mjs +404 -1
- package/dist/common/schema/schema.mjs.map +1 -1
- package/dist/common/schema/serialize.cjs +109 -1
- package/dist/common/schema/serialize.cjs.map +1 -1
- package/dist/common/schema/serialize.mjs +107 -1
- package/dist/common/schema/serialize.mjs.map +1 -1
- package/dist/common/schema/type-test.mjs +1 -1
- package/dist/common/schema/utils.cjs +25 -1
- package/dist/common/schema/utils.cjs.map +1 -1
- package/dist/common/schema/utils.mjs +19 -1
- package/dist/common/schema/utils.mjs.map +1 -1
- package/dist/common/schema/z-collection.cjs +51 -1
- package/dist/common/schema/z-collection.mjs +27 -1
- package/dist/common/schema/z.cjs +9 -1
- package/dist/common/schema/z.mjs +3 -1
- package/dist/common/storage/index.cjs +4 -1
- package/dist/common/storage/index.mjs +3 -1
- package/dist/common/storage/memstorage.cjs +26 -1
- package/dist/common/storage/memstorage.cjs.map +1 -1
- package/dist/common/storage/memstorage.mjs +25 -1
- package/dist/common/storage/memstorage.mjs.map +1 -1
- package/dist/common/test.cjs +14 -1
- package/dist/common/test.cjs.map +1 -1
- package/dist/common/test.mjs +13 -1
- package/dist/common/test.mjs.map +1 -1
- package/dist/common/time.cjs +220 -1
- package/dist/common/time.cjs.map +1 -1
- package/dist/common/time.mjs +194 -1
- package/dist/common/time.mjs.map +1 -1
- package/dist/common/timeout.cjs +27 -1
- package/dist/common/timeout.cjs.map +1 -1
- package/dist/common/timeout.mjs +25 -1
- package/dist/common/timeout.mjs.map +1 -1
- package/dist/common/types.mjs +1 -1
- package/dist/common/utils.cjs +7 -1
- package/dist/common/utils.cjs.map +1 -1
- package/dist/common/utils.mjs +5 -1
- package/dist/common/utils.mjs.map +1 -1
- package/dist/common/uuid.cjs +307 -1
- package/dist/common/uuid.cjs.map +1 -1
- package/dist/common/uuid.mjs +284 -1
- package/dist/common/uuid.mjs.map +1 -1
- package/dist/index.all.cjs +641 -1
- package/dist/index.all.mjs +113 -1
- package/dist/index.browser.cjs +576 -1
- package/dist/index.browser.mjs +98 -1
- package/dist/index.jsr.cjs +57 -1
- package/dist/index.jsr.mjs +6 -1
- package/dist/index.node.cjs +628 -1
- package/dist/index.node.mjs +106 -1
- package/dist/node/args.cjs +56 -1
- package/dist/node/args.cjs.map +1 -1
- package/dist/node/args.mjs +53 -1
- package/dist/node/args.mjs.map +1 -1
- package/dist/node/clipboard.cjs +18 -1
- package/dist/node/clipboard.cjs.map +1 -1
- package/dist/node/clipboard.mjs +16 -1
- package/dist/node/clipboard.mjs.map +1 -1
- package/dist/node/crypto.cjs +28 -1
- package/dist/node/crypto.cjs.map +1 -1
- package/dist/node/crypto.mjs +24 -1
- package/dist/node/crypto.mjs.map +1 -1
- package/dist/node/env.cjs +100 -4
- package/dist/node/env.cjs.map +1 -1
- package/dist/node/env.mjs +90 -4
- package/dist/node/env.mjs.map +1 -1
- package/dist/node/files-async.cjs +66 -1
- package/dist/node/files-async.cjs.map +1 -1
- package/dist/node/files-async.mjs +60 -1
- package/dist/node/files-async.mjs.map +1 -1
- package/dist/node/files.cjs +52 -1
- package/dist/node/files.cjs.map +1 -1
- package/dist/node/files.mjs +46 -1
- package/dist/node/files.mjs.map +1 -1
- package/dist/node/filestorage.cjs +100 -1
- package/dist/node/filestorage.cjs.map +1 -1
- package/dist/node/filestorage.mjs +97 -1
- package/dist/node/filestorage.mjs.map +1 -1
- package/dist/node/fs.cjs +119 -1
- package/dist/node/fs.cjs.map +1 -1
- package/dist/node/fs.mjs +101 -1
- package/dist/node/fs.mjs.map +1 -1
- package/dist/node/glob.cjs +75 -1
- package/dist/node/glob.cjs.map +1 -1
- package/dist/node/glob.mjs +73 -1
- package/dist/node/glob.mjs.map +1 -1
- package/dist/node/index.cjs +66 -1
- package/dist/node/index.mjs +16 -1
- package/dist/node/log/index.cjs +20 -1
- package/dist/node/log/index.mjs +7 -1
- package/dist/node/log/log-context-node.cjs +39 -1
- package/dist/node/log/log-context-node.cjs.map +1 -1
- package/dist/node/log/log-context-node.mjs +35 -1
- package/dist/node/log/log-context-node.mjs.map +1 -1
- package/dist/node/log/log-file-rotation.cjs +71 -1
- package/dist/node/log/log-file-rotation.cjs.map +1 -1
- package/dist/node/log/log-file-rotation.mjs +68 -1
- package/dist/node/log/log-file-rotation.mjs.map +1 -1
- package/dist/node/log/log-file.cjs +57 -1
- package/dist/node/log/log-file.cjs.map +1 -1
- package/dist/node/log/log-file.mjs +54 -1
- package/dist/node/log/log-file.mjs.map +1 -1
- package/dist/node/log/log-node.cjs +162 -1
- package/dist/node/log/log-node.cjs.map +1 -1
- package/dist/node/log/log-node.mjs +155 -1
- package/dist/node/log/log-node.mjs.map +1 -1
- package/dist/node/log/log-rotation.cjs +543 -3
- package/dist/node/log/log-rotation.cjs.map +1 -1
- package/dist/node/log/log-rotation.mjs +538 -3
- package/dist/node/log/log-rotation.mjs.map +1 -1
- package/dist/node/log/log-util.cjs +69 -3
- package/dist/node/log/log-util.cjs.map +1 -1
- package/dist/node/log/log-util.mjs +63 -3
- package/dist/node/log/log-util.mjs.map +1 -1
- package/dist/node/open-browser.cjs +20 -1
- package/dist/node/open-browser.cjs.map +1 -1
- package/dist/node/open-browser.mjs +18 -1
- package/dist/node/open-browser.mjs.map +1 -1
- package/package.json +6 -6
- package/src/eslint-defaults.js +4 -0
- package/src/index.spec.ts +6 -6
- package/dist/bin-Ce3i6ABn.cjs +0 -3
- package/dist/bin-SPdenYkw.mjs +0 -3
- package/dist/chunk-0Lt9GpW0.mjs +0 -1
- package/dist/chunk-D-qHiVGv.cjs +0 -1
|
@@ -1,2 +1,244 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
const require_chunk = require('../chunk-uaV2rQ02.cjs');
|
|
3
|
+
let fs = require("fs");
|
|
4
|
+
fs = require_chunk.__toESM(fs);
|
|
5
|
+
let path = require("path");
|
|
6
|
+
path = require_chunk.__toESM(path);
|
|
7
|
+
let fs_promises = require("fs/promises");
|
|
8
|
+
|
|
9
|
+
//#region src/_experiments/bitcask.ts
|
|
10
|
+
const ENTRY_HEADER_SIZE = 17;
|
|
11
|
+
var Bitcask = class {
|
|
12
|
+
dirname;
|
|
13
|
+
readWrite;
|
|
14
|
+
syncOnPut;
|
|
15
|
+
keydir = /* @__PURE__ */ new Map();
|
|
16
|
+
activeFile = null;
|
|
17
|
+
activeFileId = 0;
|
|
18
|
+
activeOffset = 0;
|
|
19
|
+
openFiles = /* @__PURE__ */ new Map();
|
|
20
|
+
constructor(dirname, opts = {}) {
|
|
21
|
+
this.dirname = dirname;
|
|
22
|
+
this.readWrite = opts.readWrite !== false;
|
|
23
|
+
this.syncOnPut = opts.syncOnPut === true;
|
|
24
|
+
if (!fs.existsSync(dirname)) fs.mkdirSync(dirname, { recursive: true });
|
|
25
|
+
this.loadFiles();
|
|
26
|
+
if (this.readWrite) this.rollover();
|
|
27
|
+
}
|
|
28
|
+
listDataFiles() {
|
|
29
|
+
return fs.readdirSync(this.dirname).filter((f) => f.endsWith(".data")).sort();
|
|
30
|
+
}
|
|
31
|
+
loadFiles() {
|
|
32
|
+
for (const fname of this.listDataFiles()) {
|
|
33
|
+
const fileId = parseInt(fname.split(".")[0], 10);
|
|
34
|
+
const filePath = path.join(this.dirname, fname);
|
|
35
|
+
const fd = fs.openSync(filePath, "r");
|
|
36
|
+
let offset = 0;
|
|
37
|
+
while (true) {
|
|
38
|
+
const header = Buffer.alloc(ENTRY_HEADER_SIZE);
|
|
39
|
+
if (fs.readSync(fd, header, 0, ENTRY_HEADER_SIZE, offset) < ENTRY_HEADER_SIZE) break;
|
|
40
|
+
const keySize = header.readUInt32BE(0);
|
|
41
|
+
const valueSize = header.readUInt32BE(4);
|
|
42
|
+
const tombstone = header.readUInt8(8) === 1;
|
|
43
|
+
const timestamp = header.readBigUInt64BE(9);
|
|
44
|
+
const key = Buffer.alloc(keySize);
|
|
45
|
+
fs.readSync(fd, key, 0, keySize, offset + ENTRY_HEADER_SIZE);
|
|
46
|
+
const entrySize = ENTRY_HEADER_SIZE + keySize + valueSize;
|
|
47
|
+
this.keydir.set(key.toString("binary"), {
|
|
48
|
+
fileId,
|
|
49
|
+
offset,
|
|
50
|
+
size: entrySize,
|
|
51
|
+
timestamp,
|
|
52
|
+
tombstone
|
|
53
|
+
});
|
|
54
|
+
offset += entrySize;
|
|
55
|
+
}
|
|
56
|
+
fs.closeSync(fd);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
rollover() {
|
|
60
|
+
const fileIds = this.listDataFiles().map((f) => parseInt(f.split(".")[0], 10));
|
|
61
|
+
const nextId = fileIds.length ? Math.max(...fileIds) + 1 : 1;
|
|
62
|
+
const fname = `${nextId.toString().padStart(8, "0")}.data`;
|
|
63
|
+
const filePath = path.join(this.dirname, fname);
|
|
64
|
+
this.activeFile = fs.createWriteStream(filePath, { flags: "a" });
|
|
65
|
+
this.activeFileId = nextId;
|
|
66
|
+
this.activeOffset = fs.existsSync(filePath) ? fs.statSync(filePath).size : 0;
|
|
67
|
+
}
|
|
68
|
+
async put(key, value) {
|
|
69
|
+
if (!this.readWrite) throw new Error("Read-only mode");
|
|
70
|
+
const keyBuf = Buffer.isBuffer(key) ? key : Buffer.from(key);
|
|
71
|
+
const valueBuf = Buffer.isBuffer(value) ? value : Buffer.from(value);
|
|
72
|
+
const timestamp = BigInt(Date.now());
|
|
73
|
+
const tombstone = 0;
|
|
74
|
+
const header = Buffer.alloc(ENTRY_HEADER_SIZE);
|
|
75
|
+
header.writeUInt32BE(keyBuf.length, 0);
|
|
76
|
+
header.writeUInt32BE(valueBuf.length, 4);
|
|
77
|
+
header.writeUInt8(tombstone, 8);
|
|
78
|
+
header.writeBigUInt64BE(timestamp, 9);
|
|
79
|
+
const entry = Buffer.concat([
|
|
80
|
+
header,
|
|
81
|
+
keyBuf,
|
|
82
|
+
valueBuf
|
|
83
|
+
]);
|
|
84
|
+
const offset = this.activeOffset;
|
|
85
|
+
await new Promise((resolve, reject) => {
|
|
86
|
+
this.activeFile.write(entry, (err) => err ? reject(err) : resolve());
|
|
87
|
+
});
|
|
88
|
+
if (this.syncOnPut && this.activeFile) fs.fsyncSync(this.activeFile.fd);
|
|
89
|
+
this.keydir.set(keyBuf.toString("binary"), {
|
|
90
|
+
fileId: this.activeFileId,
|
|
91
|
+
offset,
|
|
92
|
+
size: entry.length,
|
|
93
|
+
timestamp,
|
|
94
|
+
tombstone: false
|
|
95
|
+
});
|
|
96
|
+
this.activeOffset += entry.length;
|
|
97
|
+
if (this.activeOffset > 32 * 1024 * 1024) {
|
|
98
|
+
this.activeFile.close();
|
|
99
|
+
this.rollover();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async get(key) {
|
|
103
|
+
const keyBuf = Buffer.isBuffer(key) ? key : Buffer.from(key);
|
|
104
|
+
const meta = this.keydir.get(keyBuf.toString("binary"));
|
|
105
|
+
if (!meta || meta.tombstone) return null;
|
|
106
|
+
let fh = this.openFiles.get(meta.fileId);
|
|
107
|
+
if (!fh) {
|
|
108
|
+
fh = await (0, fs_promises.open)(path.join(this.dirname, `${meta.fileId.toString().padStart(8, "0")}.data`), "r");
|
|
109
|
+
this.openFiles.set(meta.fileId, fh);
|
|
110
|
+
}
|
|
111
|
+
const header = Buffer.alloc(ENTRY_HEADER_SIZE);
|
|
112
|
+
await fh.read(header, 0, ENTRY_HEADER_SIZE, meta.offset);
|
|
113
|
+
const keySize = header.readUInt32BE(0);
|
|
114
|
+
const valueSize = header.readUInt32BE(4);
|
|
115
|
+
const keyRead = Buffer.alloc(keySize);
|
|
116
|
+
await fh.read(keyRead, 0, keySize, meta.offset + ENTRY_HEADER_SIZE);
|
|
117
|
+
const value = Buffer.alloc(valueSize);
|
|
118
|
+
await fh.read(value, 0, valueSize, meta.offset + ENTRY_HEADER_SIZE + keySize);
|
|
119
|
+
return value;
|
|
120
|
+
}
|
|
121
|
+
async delete(key) {
|
|
122
|
+
if (!this.readWrite) throw new Error("Read-only mode");
|
|
123
|
+
const keyBuf = Buffer.isBuffer(key) ? key : Buffer.from(key);
|
|
124
|
+
const timestamp = BigInt(Date.now());
|
|
125
|
+
const tombstone = 1;
|
|
126
|
+
const header = Buffer.alloc(ENTRY_HEADER_SIZE);
|
|
127
|
+
header.writeUInt32BE(keyBuf.length, 0);
|
|
128
|
+
header.writeUInt32BE(0, 4);
|
|
129
|
+
header.writeUInt8(tombstone, 8);
|
|
130
|
+
header.writeBigUInt64BE(timestamp, 9);
|
|
131
|
+
const entry = Buffer.concat([header, keyBuf]);
|
|
132
|
+
const offset = this.activeOffset;
|
|
133
|
+
await new Promise((resolve, reject) => {
|
|
134
|
+
this.activeFile.write(entry, (err) => err ? reject(err) : resolve());
|
|
135
|
+
});
|
|
136
|
+
if (this.syncOnPut && this.activeFile) fs.fsyncSync(this.activeFile.fd);
|
|
137
|
+
this.keydir.set(keyBuf.toString("binary"), {
|
|
138
|
+
fileId: this.activeFileId,
|
|
139
|
+
offset,
|
|
140
|
+
size: entry.length,
|
|
141
|
+
timestamp,
|
|
142
|
+
tombstone: true
|
|
143
|
+
});
|
|
144
|
+
this.activeOffset += entry.length;
|
|
145
|
+
if (this.activeOffset > 32 * 1024 * 1024) {
|
|
146
|
+
this.activeFile.close();
|
|
147
|
+
this.rollover();
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
listKeys() {
|
|
151
|
+
return Array.from(this.keydir.entries()).filter(([_, v]) => !v.tombstone).map(([k, _]) => k);
|
|
152
|
+
}
|
|
153
|
+
async fold(fn, acc0) {
|
|
154
|
+
for (const [k, meta] of this.keydir.entries()) if (!meta.tombstone) acc0 = fn(k, await this.get(k), acc0);
|
|
155
|
+
return acc0;
|
|
156
|
+
}
|
|
157
|
+
async merge() {
|
|
158
|
+
const live = /* @__PURE__ */ new Map();
|
|
159
|
+
for (const [k, meta] of this.keydir.entries()) if (!meta.tombstone) live.set(k, meta);
|
|
160
|
+
const fileIds = this.listDataFiles().map((f) => parseInt(f.split(".")[0], 10));
|
|
161
|
+
const nextId = fileIds.length ? Math.max(...fileIds) + 1 : 1;
|
|
162
|
+
const fname = `${nextId.toString().padStart(8, "0")}.data`;
|
|
163
|
+
const filePath = path.join(this.dirname, fname);
|
|
164
|
+
const f = fs.createWriteStream(filePath, { flags: "a" });
|
|
165
|
+
for (const [k, meta] of live.entries()) {
|
|
166
|
+
const v = await this.get(k);
|
|
167
|
+
const keyBuf = Buffer.from(k, "binary");
|
|
168
|
+
const header = Buffer.alloc(ENTRY_HEADER_SIZE);
|
|
169
|
+
header.writeUInt32BE(keyBuf.length, 0);
|
|
170
|
+
header.writeUInt32BE(v.length, 4);
|
|
171
|
+
header.writeUInt8(0, 8);
|
|
172
|
+
header.writeBigUInt64BE(meta.timestamp, 9);
|
|
173
|
+
const entry = Buffer.concat([
|
|
174
|
+
header,
|
|
175
|
+
keyBuf,
|
|
176
|
+
v
|
|
177
|
+
]);
|
|
178
|
+
await new Promise((resolve, reject) => {
|
|
179
|
+
f.write(entry, (err) => err ? reject(err) : resolve());
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
f.close();
|
|
183
|
+
for (const fid of fileIds) if (fid !== this.activeFileId && fid !== nextId) try {
|
|
184
|
+
fs.unlinkSync(path.join(this.dirname, `${fid.toString().padStart(8, "0")}.data`));
|
|
185
|
+
} catch {}
|
|
186
|
+
this.loadFiles();
|
|
187
|
+
}
|
|
188
|
+
sync() {
|
|
189
|
+
if (this.activeFile) fs.fsyncSync(this.activeFile.fd);
|
|
190
|
+
}
|
|
191
|
+
async close() {
|
|
192
|
+
if (this.activeFile) this.activeFile.end();
|
|
193
|
+
for (const fh of this.openFiles.values()) await fh.close();
|
|
194
|
+
this.openFiles.clear();
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
function open(dirname, opts) {
|
|
198
|
+
return new Bitcask(dirname, opts);
|
|
199
|
+
}
|
|
200
|
+
async function get(handle, key) {
|
|
201
|
+
const v = await handle.get(key);
|
|
202
|
+
return v === null ? "not found" : v;
|
|
203
|
+
}
|
|
204
|
+
async function put(handle, key, value) {
|
|
205
|
+
await handle.put(key, value);
|
|
206
|
+
return "ok";
|
|
207
|
+
}
|
|
208
|
+
async function del(handle, key) {
|
|
209
|
+
await handle.delete(key);
|
|
210
|
+
return "ok";
|
|
211
|
+
}
|
|
212
|
+
function listKeys(handle) {
|
|
213
|
+
return handle.listKeys();
|
|
214
|
+
}
|
|
215
|
+
async function fold(handle, fn, acc0) {
|
|
216
|
+
return await handle.fold(fn, acc0);
|
|
217
|
+
}
|
|
218
|
+
async function merge(dirname) {
|
|
219
|
+
const h = new Bitcask(dirname, { readWrite: true });
|
|
220
|
+
await h.merge();
|
|
221
|
+
h.close();
|
|
222
|
+
return "ok";
|
|
223
|
+
}
|
|
224
|
+
function sync(handle) {
|
|
225
|
+
handle.sync();
|
|
226
|
+
return "ok";
|
|
227
|
+
}
|
|
228
|
+
async function close(handle) {
|
|
229
|
+
await handle.close();
|
|
230
|
+
return "ok";
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
//#endregion
|
|
234
|
+
exports.Bitcask = Bitcask;
|
|
235
|
+
exports.close = close;
|
|
236
|
+
exports.del = del;
|
|
237
|
+
exports.fold = fold;
|
|
238
|
+
exports.get = get;
|
|
239
|
+
exports.listKeys = listKeys;
|
|
240
|
+
exports.merge = merge;
|
|
241
|
+
exports.open = open;
|
|
242
|
+
exports.put = put;
|
|
243
|
+
exports.sync = sync;
|
|
2
244
|
//# sourceMappingURL=bitcask.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bitcask.cjs","names":[],"sources":["../../src/_experiments/bitcask.ts"],"sourcesContent":["// Bitcask-inspired key-value store (minimal, single-process, single-writer)\n// Copyright 2024\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport { FileHandle, open as openFile } from 'fs/promises'\n\nconst ENTRY_HEADER_SIZE = 17 // 4 (key) + 4 (value) + 1 (tombstone) + 8 (timestamp)\n\ninterface KeyDirEntry {\n fileId: number\n offset: number\n size: number\n timestamp: bigint\n tombstone: boolean\n}\n\nexport class Bitcask {\n private dirname: string\n private readWrite: boolean\n private syncOnPut: boolean\n private keydir: Map<string, KeyDirEntry> = new Map();\n private activeFile: fs.WriteStream | null = null;\n private activeFileId: number = 0;\n private activeOffset: number = 0;\n private openFiles: Map<number, FileHandle> = new Map();\n\n constructor(dirname: string, opts: { readWrite?: boolean; syncOnPut?: boolean } = {}) {\n this.dirname = dirname\n this.readWrite = opts.readWrite !== false\n this.syncOnPut = opts.syncOnPut === true\n if (!fs.existsSync(dirname)) fs.mkdirSync(dirname, { recursive: true })\n this.loadFiles()\n if (this.readWrite) this.rollover()\n }\n\n private listDataFiles(): string[] {\n return fs.readdirSync(this.dirname).filter(f => f.endsWith('.data')).sort()\n }\n\n private loadFiles() {\n for (const fname of this.listDataFiles()) {\n const fileId = parseInt(fname.split('.')[0], 10)\n const filePath = path.join(this.dirname, fname)\n const fd = fs.openSync(filePath, 'r')\n let offset = 0\n while (true) {\n const header = Buffer.alloc(ENTRY_HEADER_SIZE)\n const bytesRead = fs.readSync(fd, header, 0, ENTRY_HEADER_SIZE, offset)\n if (bytesRead < ENTRY_HEADER_SIZE) break\n const keySize = header.readUInt32BE(0)\n const valueSize = header.readUInt32BE(4)\n const tombstone = header.readUInt8(8) === 1\n const timestamp = header.readBigUInt64BE(9)\n const key = Buffer.alloc(keySize)\n fs.readSync(fd, key, 0, keySize, offset + ENTRY_HEADER_SIZE)\n // skip value\n const entrySize = ENTRY_HEADER_SIZE + keySize + valueSize\n this.keydir.set(key.toString('binary'), {\n fileId,\n offset,\n size: entrySize,\n timestamp,\n tombstone,\n })\n offset += entrySize\n }\n fs.closeSync(fd)\n }\n }\n\n private rollover() {\n const fileIds = this.listDataFiles().map(f => parseInt(f.split('.')[0], 10))\n const nextId = fileIds.length ? Math.max(...fileIds) + 1 : 1\n const fname = `${nextId.toString().padStart(8, '0')}.data`\n const filePath = path.join(this.dirname, fname)\n this.activeFile = fs.createWriteStream(filePath, { flags: 'a' })\n this.activeFileId = nextId\n this.activeOffset = fs.existsSync(filePath) ? fs.statSync(filePath).size : 0\n }\n\n async put(key: string | Buffer, value: string | Buffer) {\n if (!this.readWrite) throw new Error('Read-only mode')\n const keyBuf = Buffer.isBuffer(key) ? key : Buffer.from(key)\n const valueBuf = Buffer.isBuffer(value) ? value : Buffer.from(value)\n const timestamp = BigInt(Date.now())\n const tombstone = 0\n const header = Buffer.alloc(ENTRY_HEADER_SIZE)\n header.writeUInt32BE(keyBuf.length, 0)\n header.writeUInt32BE(valueBuf.length, 4)\n header.writeUInt8(tombstone, 8)\n header.writeBigUInt64BE(timestamp, 9)\n const entry = Buffer.concat([header, keyBuf, valueBuf])\n const offset = this.activeOffset\n await new Promise<void>((resolve, reject) => {\n this.activeFile!.write(entry, err => (err ? reject(err) : resolve()))\n })\n if (this.syncOnPut && this.activeFile) {\n fs.fsyncSync((this.activeFile as any).fd)\n }\n this.keydir.set(keyBuf.toString('binary'), {\n fileId: this.activeFileId,\n offset,\n size: entry.length,\n timestamp,\n tombstone: false,\n })\n this.activeOffset += entry.length\n if (this.activeOffset > 32 * 1024 * 1024) {\n this.activeFile!.close()\n this.rollover()\n }\n }\n\n async get(key: string | Buffer): Promise<Buffer | null> {\n const keyBuf = Buffer.isBuffer(key) ? key : Buffer.from(key)\n const meta = this.keydir.get(keyBuf.toString('binary'))\n if (!meta || meta.tombstone) return null\n let fh = this.openFiles.get(meta.fileId)\n if (!fh) {\n const fname = path.join(this.dirname, `${meta.fileId.toString().padStart(8, '0')}.data`)\n fh = await openFile(fname, 'r')\n this.openFiles.set(meta.fileId, fh)\n }\n const header = Buffer.alloc(ENTRY_HEADER_SIZE)\n await fh.read(header, 0, ENTRY_HEADER_SIZE, meta.offset)\n const keySize = header.readUInt32BE(0)\n const valueSize = header.readUInt32BE(4)\n const keyRead = Buffer.alloc(keySize)\n await fh.read(keyRead, 0, keySize, meta.offset + ENTRY_HEADER_SIZE)\n const value = Buffer.alloc(valueSize)\n await fh.read(value, 0, valueSize, meta.offset + ENTRY_HEADER_SIZE + keySize)\n return value\n }\n\n async delete(key: string | Buffer) {\n if (!this.readWrite) throw new Error('Read-only mode')\n const keyBuf = Buffer.isBuffer(key) ? key : Buffer.from(key)\n const timestamp = BigInt(Date.now())\n const tombstone = 1\n const header = Buffer.alloc(ENTRY_HEADER_SIZE)\n header.writeUInt32BE(keyBuf.length, 0)\n header.writeUInt32BE(0, 4)\n header.writeUInt8(tombstone, 8)\n header.writeBigUInt64BE(timestamp, 9)\n const entry = Buffer.concat([header, keyBuf])\n const offset = this.activeOffset\n await new Promise<void>((resolve, reject) => {\n this.activeFile!.write(entry, err => (err ? reject(err) : resolve()))\n })\n if (this.syncOnPut && this.activeFile) {\n fs.fsyncSync((this.activeFile as any).fd)\n }\n this.keydir.set(keyBuf.toString('binary'), {\n fileId: this.activeFileId,\n offset,\n size: entry.length,\n timestamp,\n tombstone: true,\n })\n this.activeOffset += entry.length\n if (this.activeOffset > 32 * 1024 * 1024) {\n this.activeFile!.close()\n this.rollover()\n }\n }\n\n listKeys(): string[] {\n return Array.from(this.keydir.entries()).filter(([_, v]) => !v.tombstone).map(([k, _]) => k)\n }\n\n async fold<T>(fn: (k: string, v: Buffer, acc: T) => T, acc0: T): Promise<T> {\n for (const [k, meta] of this.keydir.entries()) {\n if (!meta.tombstone) {\n const v = await this.get(k)\n acc0 = fn(k, v!, acc0)\n }\n }\n return acc0\n }\n\n async merge() {\n // Compact all but active file\n const live: Map<string, KeyDirEntry> = new Map()\n for (const [k, meta] of this.keydir.entries()) {\n if (!meta.tombstone) live.set(k, meta)\n }\n const fileIds = this.listDataFiles().map(f => parseInt(f.split('.')[0], 10))\n const nextId = fileIds.length ? Math.max(...fileIds) + 1 : 1\n const fname = `${nextId.toString().padStart(8, '0')}.data`\n const filePath = path.join(this.dirname, fname)\n const f = fs.createWriteStream(filePath, { flags: 'a' })\n for (const [k, meta] of live.entries()) {\n const v = await this.get(k)\n const keyBuf = Buffer.from(k, 'binary')\n const header = Buffer.alloc(ENTRY_HEADER_SIZE)\n header.writeUInt32BE(keyBuf.length, 0)\n header.writeUInt32BE(v!.length, 4)\n header.writeUInt8(0, 8)\n header.writeBigUInt64BE(meta.timestamp, 9)\n const entry = Buffer.concat([header, keyBuf, v!])\n await new Promise<void>((resolve, reject) => {\n f.write(entry, err => (err ? reject(err) : resolve()))\n })\n }\n f.close()\n for (const fid of fileIds) {\n if (fid !== this.activeFileId && fid !== nextId) {\n try {\n fs.unlinkSync(path.join(this.dirname, `${fid.toString().padStart(8, '0')}.data`))\n } catch { }\n }\n }\n this.loadFiles()\n }\n\n sync() {\n if (this.activeFile) fs.fsyncSync((this.activeFile as any).fd)\n }\n\n async close() {\n if (this.activeFile) this.activeFile.end()\n for (const fh of this.openFiles.values()) await fh.close()\n this.openFiles.clear()\n }\n}\n\n// API functions\nexport function open(dirname: string, opts?: { readWrite?: boolean; syncOnPut?: boolean }) {\n return new Bitcask(dirname, opts)\n}\nexport async function get(handle: Bitcask, key: string | Buffer) {\n const v = await handle.get(key)\n return v === null ? 'not found' : v\n}\nexport async function put(handle: Bitcask, key: string | Buffer, value: string | Buffer) {\n await handle.put(key, value)\n return 'ok'\n}\nexport async function del(handle: Bitcask, key: string | Buffer) {\n await handle.delete(key)\n return 'ok'\n}\nexport function listKeys(handle: Bitcask) {\n return handle.listKeys()\n}\nexport async function fold<T>(handle: Bitcask, fn: (k: string, v: Buffer, acc: T) => T, acc0: T) {\n return await handle.fold(fn, acc0)\n}\nexport async function merge(dirname: string) {\n const h = new Bitcask(dirname, { readWrite: true })\n await h.merge()\n h.close()\n return 'ok'\n}\nexport function sync(handle: Bitcask) {\n handle.sync()\n return 'ok'\n}\nexport async function close(handle: Bitcask) {\n await handle.close()\n return 'ok'\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"bitcask.cjs","names":[],"sources":["../../src/_experiments/bitcask.ts"],"sourcesContent":["// Bitcask-inspired key-value store (minimal, single-process, single-writer)\n// Copyright 2024\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport { FileHandle, open as openFile } from 'fs/promises'\n\nconst ENTRY_HEADER_SIZE = 17 // 4 (key) + 4 (value) + 1 (tombstone) + 8 (timestamp)\n\ninterface KeyDirEntry {\n fileId: number\n offset: number\n size: number\n timestamp: bigint\n tombstone: boolean\n}\n\nexport class Bitcask {\n private dirname: string\n private readWrite: boolean\n private syncOnPut: boolean\n private keydir: Map<string, KeyDirEntry> = new Map();\n private activeFile: fs.WriteStream | null = null;\n private activeFileId: number = 0;\n private activeOffset: number = 0;\n private openFiles: Map<number, FileHandle> = new Map();\n\n constructor(dirname: string, opts: { readWrite?: boolean; syncOnPut?: boolean } = {}) {\n this.dirname = dirname\n this.readWrite = opts.readWrite !== false\n this.syncOnPut = opts.syncOnPut === true\n if (!fs.existsSync(dirname)) fs.mkdirSync(dirname, { recursive: true })\n this.loadFiles()\n if (this.readWrite) this.rollover()\n }\n\n private listDataFiles(): string[] {\n return fs.readdirSync(this.dirname).filter(f => f.endsWith('.data')).sort()\n }\n\n private loadFiles() {\n for (const fname of this.listDataFiles()) {\n const fileId = parseInt(fname.split('.')[0], 10)\n const filePath = path.join(this.dirname, fname)\n const fd = fs.openSync(filePath, 'r')\n let offset = 0\n while (true) {\n const header = Buffer.alloc(ENTRY_HEADER_SIZE)\n const bytesRead = fs.readSync(fd, header, 0, ENTRY_HEADER_SIZE, offset)\n if (bytesRead < ENTRY_HEADER_SIZE) break\n const keySize = header.readUInt32BE(0)\n const valueSize = header.readUInt32BE(4)\n const tombstone = header.readUInt8(8) === 1\n const timestamp = header.readBigUInt64BE(9)\n const key = Buffer.alloc(keySize)\n fs.readSync(fd, key, 0, keySize, offset + ENTRY_HEADER_SIZE)\n // skip value\n const entrySize = ENTRY_HEADER_SIZE + keySize + valueSize\n this.keydir.set(key.toString('binary'), {\n fileId,\n offset,\n size: entrySize,\n timestamp,\n tombstone,\n })\n offset += entrySize\n }\n fs.closeSync(fd)\n }\n }\n\n private rollover() {\n const fileIds = this.listDataFiles().map(f => parseInt(f.split('.')[0], 10))\n const nextId = fileIds.length ? Math.max(...fileIds) + 1 : 1\n const fname = `${nextId.toString().padStart(8, '0')}.data`\n const filePath = path.join(this.dirname, fname)\n this.activeFile = fs.createWriteStream(filePath, { flags: 'a' })\n this.activeFileId = nextId\n this.activeOffset = fs.existsSync(filePath) ? fs.statSync(filePath).size : 0\n }\n\n async put(key: string | Buffer, value: string | Buffer) {\n if (!this.readWrite) throw new Error('Read-only mode')\n const keyBuf = Buffer.isBuffer(key) ? key : Buffer.from(key)\n const valueBuf = Buffer.isBuffer(value) ? value : Buffer.from(value)\n const timestamp = BigInt(Date.now())\n const tombstone = 0\n const header = Buffer.alloc(ENTRY_HEADER_SIZE)\n header.writeUInt32BE(keyBuf.length, 0)\n header.writeUInt32BE(valueBuf.length, 4)\n header.writeUInt8(tombstone, 8)\n header.writeBigUInt64BE(timestamp, 9)\n const entry = Buffer.concat([header, keyBuf, valueBuf])\n const offset = this.activeOffset\n await new Promise<void>((resolve, reject) => {\n this.activeFile!.write(entry, err => (err ? reject(err) : resolve()))\n })\n if (this.syncOnPut && this.activeFile) {\n fs.fsyncSync((this.activeFile as any).fd)\n }\n this.keydir.set(keyBuf.toString('binary'), {\n fileId: this.activeFileId,\n offset,\n size: entry.length,\n timestamp,\n tombstone: false,\n })\n this.activeOffset += entry.length\n if (this.activeOffset > 32 * 1024 * 1024) {\n this.activeFile!.close()\n this.rollover()\n }\n }\n\n async get(key: string | Buffer): Promise<Buffer | null> {\n const keyBuf = Buffer.isBuffer(key) ? key : Buffer.from(key)\n const meta = this.keydir.get(keyBuf.toString('binary'))\n if (!meta || meta.tombstone) return null\n let fh = this.openFiles.get(meta.fileId)\n if (!fh) {\n const fname = path.join(this.dirname, `${meta.fileId.toString().padStart(8, '0')}.data`)\n fh = await openFile(fname, 'r')\n this.openFiles.set(meta.fileId, fh)\n }\n const header = Buffer.alloc(ENTRY_HEADER_SIZE)\n await fh.read(header, 0, ENTRY_HEADER_SIZE, meta.offset)\n const keySize = header.readUInt32BE(0)\n const valueSize = header.readUInt32BE(4)\n const keyRead = Buffer.alloc(keySize)\n await fh.read(keyRead, 0, keySize, meta.offset + ENTRY_HEADER_SIZE)\n const value = Buffer.alloc(valueSize)\n await fh.read(value, 0, valueSize, meta.offset + ENTRY_HEADER_SIZE + keySize)\n return value\n }\n\n async delete(key: string | Buffer) {\n if (!this.readWrite) throw new Error('Read-only mode')\n const keyBuf = Buffer.isBuffer(key) ? key : Buffer.from(key)\n const timestamp = BigInt(Date.now())\n const tombstone = 1\n const header = Buffer.alloc(ENTRY_HEADER_SIZE)\n header.writeUInt32BE(keyBuf.length, 0)\n header.writeUInt32BE(0, 4)\n header.writeUInt8(tombstone, 8)\n header.writeBigUInt64BE(timestamp, 9)\n const entry = Buffer.concat([header, keyBuf])\n const offset = this.activeOffset\n await new Promise<void>((resolve, reject) => {\n this.activeFile!.write(entry, err => (err ? reject(err) : resolve()))\n })\n if (this.syncOnPut && this.activeFile) {\n fs.fsyncSync((this.activeFile as any).fd)\n }\n this.keydir.set(keyBuf.toString('binary'), {\n fileId: this.activeFileId,\n offset,\n size: entry.length,\n timestamp,\n tombstone: true,\n })\n this.activeOffset += entry.length\n if (this.activeOffset > 32 * 1024 * 1024) {\n this.activeFile!.close()\n this.rollover()\n }\n }\n\n listKeys(): string[] {\n return Array.from(this.keydir.entries()).filter(([_, v]) => !v.tombstone).map(([k, _]) => k)\n }\n\n async fold<T>(fn: (k: string, v: Buffer, acc: T) => T, acc0: T): Promise<T> {\n for (const [k, meta] of this.keydir.entries()) {\n if (!meta.tombstone) {\n const v = await this.get(k)\n acc0 = fn(k, v!, acc0)\n }\n }\n return acc0\n }\n\n async merge() {\n // Compact all but active file\n const live: Map<string, KeyDirEntry> = new Map()\n for (const [k, meta] of this.keydir.entries()) {\n if (!meta.tombstone) live.set(k, meta)\n }\n const fileIds = this.listDataFiles().map(f => parseInt(f.split('.')[0], 10))\n const nextId = fileIds.length ? Math.max(...fileIds) + 1 : 1\n const fname = `${nextId.toString().padStart(8, '0')}.data`\n const filePath = path.join(this.dirname, fname)\n const f = fs.createWriteStream(filePath, { flags: 'a' })\n for (const [k, meta] of live.entries()) {\n const v = await this.get(k)\n const keyBuf = Buffer.from(k, 'binary')\n const header = Buffer.alloc(ENTRY_HEADER_SIZE)\n header.writeUInt32BE(keyBuf.length, 0)\n header.writeUInt32BE(v!.length, 4)\n header.writeUInt8(0, 8)\n header.writeBigUInt64BE(meta.timestamp, 9)\n const entry = Buffer.concat([header, keyBuf, v!])\n await new Promise<void>((resolve, reject) => {\n f.write(entry, err => (err ? reject(err) : resolve()))\n })\n }\n f.close()\n for (const fid of fileIds) {\n if (fid !== this.activeFileId && fid !== nextId) {\n try {\n fs.unlinkSync(path.join(this.dirname, `${fid.toString().padStart(8, '0')}.data`))\n } catch { }\n }\n }\n this.loadFiles()\n }\n\n sync() {\n if (this.activeFile) fs.fsyncSync((this.activeFile as any).fd)\n }\n\n async close() {\n if (this.activeFile) this.activeFile.end()\n for (const fh of this.openFiles.values()) await fh.close()\n this.openFiles.clear()\n }\n}\n\n// API functions\nexport function open(dirname: string, opts?: { readWrite?: boolean; syncOnPut?: boolean }) {\n return new Bitcask(dirname, opts)\n}\nexport async function get(handle: Bitcask, key: string | Buffer) {\n const v = await handle.get(key)\n return v === null ? 'not found' : v\n}\nexport async function put(handle: Bitcask, key: string | Buffer, value: string | Buffer) {\n await handle.put(key, value)\n return 'ok'\n}\nexport async function del(handle: Bitcask, key: string | Buffer) {\n await handle.delete(key)\n return 'ok'\n}\nexport function listKeys(handle: Bitcask) {\n return handle.listKeys()\n}\nexport async function fold<T>(handle: Bitcask, fn: (k: string, v: Buffer, acc: T) => T, acc0: T) {\n return await handle.fold(fn, acc0)\n}\nexport async function merge(dirname: string) {\n const h = new Bitcask(dirname, { readWrite: true })\n await h.merge()\n h.close()\n return 'ok'\n}\nexport function sync(handle: Bitcask) {\n handle.sync()\n return 'ok'\n}\nexport async function close(handle: Bitcask) {\n await handle.close()\n return 'ok'\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,231 @@
|
|
|
1
|
-
import*as
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import { open as open$1 } from "fs/promises";
|
|
4
|
+
|
|
5
|
+
//#region src/_experiments/bitcask.ts
|
|
6
|
+
const ENTRY_HEADER_SIZE = 17;
|
|
7
|
+
var Bitcask = class {
|
|
8
|
+
dirname;
|
|
9
|
+
readWrite;
|
|
10
|
+
syncOnPut;
|
|
11
|
+
keydir = /* @__PURE__ */ new Map();
|
|
12
|
+
activeFile = null;
|
|
13
|
+
activeFileId = 0;
|
|
14
|
+
activeOffset = 0;
|
|
15
|
+
openFiles = /* @__PURE__ */ new Map();
|
|
16
|
+
constructor(dirname, opts = {}) {
|
|
17
|
+
this.dirname = dirname;
|
|
18
|
+
this.readWrite = opts.readWrite !== false;
|
|
19
|
+
this.syncOnPut = opts.syncOnPut === true;
|
|
20
|
+
if (!fs.existsSync(dirname)) fs.mkdirSync(dirname, { recursive: true });
|
|
21
|
+
this.loadFiles();
|
|
22
|
+
if (this.readWrite) this.rollover();
|
|
23
|
+
}
|
|
24
|
+
listDataFiles() {
|
|
25
|
+
return fs.readdirSync(this.dirname).filter((f) => f.endsWith(".data")).sort();
|
|
26
|
+
}
|
|
27
|
+
loadFiles() {
|
|
28
|
+
for (const fname of this.listDataFiles()) {
|
|
29
|
+
const fileId = parseInt(fname.split(".")[0], 10);
|
|
30
|
+
const filePath = path.join(this.dirname, fname);
|
|
31
|
+
const fd = fs.openSync(filePath, "r");
|
|
32
|
+
let offset = 0;
|
|
33
|
+
while (true) {
|
|
34
|
+
const header = Buffer.alloc(ENTRY_HEADER_SIZE);
|
|
35
|
+
if (fs.readSync(fd, header, 0, ENTRY_HEADER_SIZE, offset) < ENTRY_HEADER_SIZE) break;
|
|
36
|
+
const keySize = header.readUInt32BE(0);
|
|
37
|
+
const valueSize = header.readUInt32BE(4);
|
|
38
|
+
const tombstone = header.readUInt8(8) === 1;
|
|
39
|
+
const timestamp = header.readBigUInt64BE(9);
|
|
40
|
+
const key = Buffer.alloc(keySize);
|
|
41
|
+
fs.readSync(fd, key, 0, keySize, offset + ENTRY_HEADER_SIZE);
|
|
42
|
+
const entrySize = ENTRY_HEADER_SIZE + keySize + valueSize;
|
|
43
|
+
this.keydir.set(key.toString("binary"), {
|
|
44
|
+
fileId,
|
|
45
|
+
offset,
|
|
46
|
+
size: entrySize,
|
|
47
|
+
timestamp,
|
|
48
|
+
tombstone
|
|
49
|
+
});
|
|
50
|
+
offset += entrySize;
|
|
51
|
+
}
|
|
52
|
+
fs.closeSync(fd);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
rollover() {
|
|
56
|
+
const fileIds = this.listDataFiles().map((f) => parseInt(f.split(".")[0], 10));
|
|
57
|
+
const nextId = fileIds.length ? Math.max(...fileIds) + 1 : 1;
|
|
58
|
+
const fname = `${nextId.toString().padStart(8, "0")}.data`;
|
|
59
|
+
const filePath = path.join(this.dirname, fname);
|
|
60
|
+
this.activeFile = fs.createWriteStream(filePath, { flags: "a" });
|
|
61
|
+
this.activeFileId = nextId;
|
|
62
|
+
this.activeOffset = fs.existsSync(filePath) ? fs.statSync(filePath).size : 0;
|
|
63
|
+
}
|
|
64
|
+
async put(key, value) {
|
|
65
|
+
if (!this.readWrite) throw new Error("Read-only mode");
|
|
66
|
+
const keyBuf = Buffer.isBuffer(key) ? key : Buffer.from(key);
|
|
67
|
+
const valueBuf = Buffer.isBuffer(value) ? value : Buffer.from(value);
|
|
68
|
+
const timestamp = BigInt(Date.now());
|
|
69
|
+
const tombstone = 0;
|
|
70
|
+
const header = Buffer.alloc(ENTRY_HEADER_SIZE);
|
|
71
|
+
header.writeUInt32BE(keyBuf.length, 0);
|
|
72
|
+
header.writeUInt32BE(valueBuf.length, 4);
|
|
73
|
+
header.writeUInt8(tombstone, 8);
|
|
74
|
+
header.writeBigUInt64BE(timestamp, 9);
|
|
75
|
+
const entry = Buffer.concat([
|
|
76
|
+
header,
|
|
77
|
+
keyBuf,
|
|
78
|
+
valueBuf
|
|
79
|
+
]);
|
|
80
|
+
const offset = this.activeOffset;
|
|
81
|
+
await new Promise((resolve, reject) => {
|
|
82
|
+
this.activeFile.write(entry, (err) => err ? reject(err) : resolve());
|
|
83
|
+
});
|
|
84
|
+
if (this.syncOnPut && this.activeFile) fs.fsyncSync(this.activeFile.fd);
|
|
85
|
+
this.keydir.set(keyBuf.toString("binary"), {
|
|
86
|
+
fileId: this.activeFileId,
|
|
87
|
+
offset,
|
|
88
|
+
size: entry.length,
|
|
89
|
+
timestamp,
|
|
90
|
+
tombstone: false
|
|
91
|
+
});
|
|
92
|
+
this.activeOffset += entry.length;
|
|
93
|
+
if (this.activeOffset > 32 * 1024 * 1024) {
|
|
94
|
+
this.activeFile.close();
|
|
95
|
+
this.rollover();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
async get(key) {
|
|
99
|
+
const keyBuf = Buffer.isBuffer(key) ? key : Buffer.from(key);
|
|
100
|
+
const meta = this.keydir.get(keyBuf.toString("binary"));
|
|
101
|
+
if (!meta || meta.tombstone) return null;
|
|
102
|
+
let fh = this.openFiles.get(meta.fileId);
|
|
103
|
+
if (!fh) {
|
|
104
|
+
fh = await open$1(path.join(this.dirname, `${meta.fileId.toString().padStart(8, "0")}.data`), "r");
|
|
105
|
+
this.openFiles.set(meta.fileId, fh);
|
|
106
|
+
}
|
|
107
|
+
const header = Buffer.alloc(ENTRY_HEADER_SIZE);
|
|
108
|
+
await fh.read(header, 0, ENTRY_HEADER_SIZE, meta.offset);
|
|
109
|
+
const keySize = header.readUInt32BE(0);
|
|
110
|
+
const valueSize = header.readUInt32BE(4);
|
|
111
|
+
const keyRead = Buffer.alloc(keySize);
|
|
112
|
+
await fh.read(keyRead, 0, keySize, meta.offset + ENTRY_HEADER_SIZE);
|
|
113
|
+
const value = Buffer.alloc(valueSize);
|
|
114
|
+
await fh.read(value, 0, valueSize, meta.offset + ENTRY_HEADER_SIZE + keySize);
|
|
115
|
+
return value;
|
|
116
|
+
}
|
|
117
|
+
async delete(key) {
|
|
118
|
+
if (!this.readWrite) throw new Error("Read-only mode");
|
|
119
|
+
const keyBuf = Buffer.isBuffer(key) ? key : Buffer.from(key);
|
|
120
|
+
const timestamp = BigInt(Date.now());
|
|
121
|
+
const tombstone = 1;
|
|
122
|
+
const header = Buffer.alloc(ENTRY_HEADER_SIZE);
|
|
123
|
+
header.writeUInt32BE(keyBuf.length, 0);
|
|
124
|
+
header.writeUInt32BE(0, 4);
|
|
125
|
+
header.writeUInt8(tombstone, 8);
|
|
126
|
+
header.writeBigUInt64BE(timestamp, 9);
|
|
127
|
+
const entry = Buffer.concat([header, keyBuf]);
|
|
128
|
+
const offset = this.activeOffset;
|
|
129
|
+
await new Promise((resolve, reject) => {
|
|
130
|
+
this.activeFile.write(entry, (err) => err ? reject(err) : resolve());
|
|
131
|
+
});
|
|
132
|
+
if (this.syncOnPut && this.activeFile) fs.fsyncSync(this.activeFile.fd);
|
|
133
|
+
this.keydir.set(keyBuf.toString("binary"), {
|
|
134
|
+
fileId: this.activeFileId,
|
|
135
|
+
offset,
|
|
136
|
+
size: entry.length,
|
|
137
|
+
timestamp,
|
|
138
|
+
tombstone: true
|
|
139
|
+
});
|
|
140
|
+
this.activeOffset += entry.length;
|
|
141
|
+
if (this.activeOffset > 32 * 1024 * 1024) {
|
|
142
|
+
this.activeFile.close();
|
|
143
|
+
this.rollover();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
listKeys() {
|
|
147
|
+
return Array.from(this.keydir.entries()).filter(([_, v]) => !v.tombstone).map(([k, _]) => k);
|
|
148
|
+
}
|
|
149
|
+
async fold(fn, acc0) {
|
|
150
|
+
for (const [k, meta] of this.keydir.entries()) if (!meta.tombstone) acc0 = fn(k, await this.get(k), acc0);
|
|
151
|
+
return acc0;
|
|
152
|
+
}
|
|
153
|
+
async merge() {
|
|
154
|
+
const live = /* @__PURE__ */ new Map();
|
|
155
|
+
for (const [k, meta] of this.keydir.entries()) if (!meta.tombstone) live.set(k, meta);
|
|
156
|
+
const fileIds = this.listDataFiles().map((f) => parseInt(f.split(".")[0], 10));
|
|
157
|
+
const nextId = fileIds.length ? Math.max(...fileIds) + 1 : 1;
|
|
158
|
+
const fname = `${nextId.toString().padStart(8, "0")}.data`;
|
|
159
|
+
const filePath = path.join(this.dirname, fname);
|
|
160
|
+
const f = fs.createWriteStream(filePath, { flags: "a" });
|
|
161
|
+
for (const [k, meta] of live.entries()) {
|
|
162
|
+
const v = await this.get(k);
|
|
163
|
+
const keyBuf = Buffer.from(k, "binary");
|
|
164
|
+
const header = Buffer.alloc(ENTRY_HEADER_SIZE);
|
|
165
|
+
header.writeUInt32BE(keyBuf.length, 0);
|
|
166
|
+
header.writeUInt32BE(v.length, 4);
|
|
167
|
+
header.writeUInt8(0, 8);
|
|
168
|
+
header.writeBigUInt64BE(meta.timestamp, 9);
|
|
169
|
+
const entry = Buffer.concat([
|
|
170
|
+
header,
|
|
171
|
+
keyBuf,
|
|
172
|
+
v
|
|
173
|
+
]);
|
|
174
|
+
await new Promise((resolve, reject) => {
|
|
175
|
+
f.write(entry, (err) => err ? reject(err) : resolve());
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
f.close();
|
|
179
|
+
for (const fid of fileIds) if (fid !== this.activeFileId && fid !== nextId) try {
|
|
180
|
+
fs.unlinkSync(path.join(this.dirname, `${fid.toString().padStart(8, "0")}.data`));
|
|
181
|
+
} catch {}
|
|
182
|
+
this.loadFiles();
|
|
183
|
+
}
|
|
184
|
+
sync() {
|
|
185
|
+
if (this.activeFile) fs.fsyncSync(this.activeFile.fd);
|
|
186
|
+
}
|
|
187
|
+
async close() {
|
|
188
|
+
if (this.activeFile) this.activeFile.end();
|
|
189
|
+
for (const fh of this.openFiles.values()) await fh.close();
|
|
190
|
+
this.openFiles.clear();
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
function open(dirname, opts) {
|
|
194
|
+
return new Bitcask(dirname, opts);
|
|
195
|
+
}
|
|
196
|
+
async function get(handle, key) {
|
|
197
|
+
const v = await handle.get(key);
|
|
198
|
+
return v === null ? "not found" : v;
|
|
199
|
+
}
|
|
200
|
+
async function put(handle, key, value) {
|
|
201
|
+
await handle.put(key, value);
|
|
202
|
+
return "ok";
|
|
203
|
+
}
|
|
204
|
+
async function del(handle, key) {
|
|
205
|
+
await handle.delete(key);
|
|
206
|
+
return "ok";
|
|
207
|
+
}
|
|
208
|
+
function listKeys(handle) {
|
|
209
|
+
return handle.listKeys();
|
|
210
|
+
}
|
|
211
|
+
async function fold(handle, fn, acc0) {
|
|
212
|
+
return await handle.fold(fn, acc0);
|
|
213
|
+
}
|
|
214
|
+
async function merge(dirname) {
|
|
215
|
+
const h = new Bitcask(dirname, { readWrite: true });
|
|
216
|
+
await h.merge();
|
|
217
|
+
h.close();
|
|
218
|
+
return "ok";
|
|
219
|
+
}
|
|
220
|
+
function sync(handle) {
|
|
221
|
+
handle.sync();
|
|
222
|
+
return "ok";
|
|
223
|
+
}
|
|
224
|
+
async function close(handle) {
|
|
225
|
+
await handle.close();
|
|
226
|
+
return "ok";
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
//#endregion
|
|
230
|
+
export { Bitcask, close, del, fold, get, listKeys, merge, open, put, sync };
|
|
2
231
|
//# sourceMappingURL=bitcask.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bitcask.mjs","names":["openFile"],"sources":["../../src/_experiments/bitcask.ts"],"sourcesContent":["// Bitcask-inspired key-value store (minimal, single-process, single-writer)\n// Copyright 2024\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport { FileHandle, open as openFile } from 'fs/promises'\n\nconst ENTRY_HEADER_SIZE = 17 // 4 (key) + 4 (value) + 1 (tombstone) + 8 (timestamp)\n\ninterface KeyDirEntry {\n fileId: number\n offset: number\n size: number\n timestamp: bigint\n tombstone: boolean\n}\n\nexport class Bitcask {\n private dirname: string\n private readWrite: boolean\n private syncOnPut: boolean\n private keydir: Map<string, KeyDirEntry> = new Map();\n private activeFile: fs.WriteStream | null = null;\n private activeFileId: number = 0;\n private activeOffset: number = 0;\n private openFiles: Map<number, FileHandle> = new Map();\n\n constructor(dirname: string, opts: { readWrite?: boolean; syncOnPut?: boolean } = {}) {\n this.dirname = dirname\n this.readWrite = opts.readWrite !== false\n this.syncOnPut = opts.syncOnPut === true\n if (!fs.existsSync(dirname)) fs.mkdirSync(dirname, { recursive: true })\n this.loadFiles()\n if (this.readWrite) this.rollover()\n }\n\n private listDataFiles(): string[] {\n return fs.readdirSync(this.dirname).filter(f => f.endsWith('.data')).sort()\n }\n\n private loadFiles() {\n for (const fname of this.listDataFiles()) {\n const fileId = parseInt(fname.split('.')[0], 10)\n const filePath = path.join(this.dirname, fname)\n const fd = fs.openSync(filePath, 'r')\n let offset = 0\n while (true) {\n const header = Buffer.alloc(ENTRY_HEADER_SIZE)\n const bytesRead = fs.readSync(fd, header, 0, ENTRY_HEADER_SIZE, offset)\n if (bytesRead < ENTRY_HEADER_SIZE) break\n const keySize = header.readUInt32BE(0)\n const valueSize = header.readUInt32BE(4)\n const tombstone = header.readUInt8(8) === 1\n const timestamp = header.readBigUInt64BE(9)\n const key = Buffer.alloc(keySize)\n fs.readSync(fd, key, 0, keySize, offset + ENTRY_HEADER_SIZE)\n // skip value\n const entrySize = ENTRY_HEADER_SIZE + keySize + valueSize\n this.keydir.set(key.toString('binary'), {\n fileId,\n offset,\n size: entrySize,\n timestamp,\n tombstone,\n })\n offset += entrySize\n }\n fs.closeSync(fd)\n }\n }\n\n private rollover() {\n const fileIds = this.listDataFiles().map(f => parseInt(f.split('.')[0], 10))\n const nextId = fileIds.length ? Math.max(...fileIds) + 1 : 1\n const fname = `${nextId.toString().padStart(8, '0')}.data`\n const filePath = path.join(this.dirname, fname)\n this.activeFile = fs.createWriteStream(filePath, { flags: 'a' })\n this.activeFileId = nextId\n this.activeOffset = fs.existsSync(filePath) ? fs.statSync(filePath).size : 0\n }\n\n async put(key: string | Buffer, value: string | Buffer) {\n if (!this.readWrite) throw new Error('Read-only mode')\n const keyBuf = Buffer.isBuffer(key) ? key : Buffer.from(key)\n const valueBuf = Buffer.isBuffer(value) ? value : Buffer.from(value)\n const timestamp = BigInt(Date.now())\n const tombstone = 0\n const header = Buffer.alloc(ENTRY_HEADER_SIZE)\n header.writeUInt32BE(keyBuf.length, 0)\n header.writeUInt32BE(valueBuf.length, 4)\n header.writeUInt8(tombstone, 8)\n header.writeBigUInt64BE(timestamp, 9)\n const entry = Buffer.concat([header, keyBuf, valueBuf])\n const offset = this.activeOffset\n await new Promise<void>((resolve, reject) => {\n this.activeFile!.write(entry, err => (err ? reject(err) : resolve()))\n })\n if (this.syncOnPut && this.activeFile) {\n fs.fsyncSync((this.activeFile as any).fd)\n }\n this.keydir.set(keyBuf.toString('binary'), {\n fileId: this.activeFileId,\n offset,\n size: entry.length,\n timestamp,\n tombstone: false,\n })\n this.activeOffset += entry.length\n if (this.activeOffset > 32 * 1024 * 1024) {\n this.activeFile!.close()\n this.rollover()\n }\n }\n\n async get(key: string | Buffer): Promise<Buffer | null> {\n const keyBuf = Buffer.isBuffer(key) ? key : Buffer.from(key)\n const meta = this.keydir.get(keyBuf.toString('binary'))\n if (!meta || meta.tombstone) return null\n let fh = this.openFiles.get(meta.fileId)\n if (!fh) {\n const fname = path.join(this.dirname, `${meta.fileId.toString().padStart(8, '0')}.data`)\n fh = await openFile(fname, 'r')\n this.openFiles.set(meta.fileId, fh)\n }\n const header = Buffer.alloc(ENTRY_HEADER_SIZE)\n await fh.read(header, 0, ENTRY_HEADER_SIZE, meta.offset)\n const keySize = header.readUInt32BE(0)\n const valueSize = header.readUInt32BE(4)\n const keyRead = Buffer.alloc(keySize)\n await fh.read(keyRead, 0, keySize, meta.offset + ENTRY_HEADER_SIZE)\n const value = Buffer.alloc(valueSize)\n await fh.read(value, 0, valueSize, meta.offset + ENTRY_HEADER_SIZE + keySize)\n return value\n }\n\n async delete(key: string | Buffer) {\n if (!this.readWrite) throw new Error('Read-only mode')\n const keyBuf = Buffer.isBuffer(key) ? key : Buffer.from(key)\n const timestamp = BigInt(Date.now())\n const tombstone = 1\n const header = Buffer.alloc(ENTRY_HEADER_SIZE)\n header.writeUInt32BE(keyBuf.length, 0)\n header.writeUInt32BE(0, 4)\n header.writeUInt8(tombstone, 8)\n header.writeBigUInt64BE(timestamp, 9)\n const entry = Buffer.concat([header, keyBuf])\n const offset = this.activeOffset\n await new Promise<void>((resolve, reject) => {\n this.activeFile!.write(entry, err => (err ? reject(err) : resolve()))\n })\n if (this.syncOnPut && this.activeFile) {\n fs.fsyncSync((this.activeFile as any).fd)\n }\n this.keydir.set(keyBuf.toString('binary'), {\n fileId: this.activeFileId,\n offset,\n size: entry.length,\n timestamp,\n tombstone: true,\n })\n this.activeOffset += entry.length\n if (this.activeOffset > 32 * 1024 * 1024) {\n this.activeFile!.close()\n this.rollover()\n }\n }\n\n listKeys(): string[] {\n return Array.from(this.keydir.entries()).filter(([_, v]) => !v.tombstone).map(([k, _]) => k)\n }\n\n async fold<T>(fn: (k: string, v: Buffer, acc: T) => T, acc0: T): Promise<T> {\n for (const [k, meta] of this.keydir.entries()) {\n if (!meta.tombstone) {\n const v = await this.get(k)\n acc0 = fn(k, v!, acc0)\n }\n }\n return acc0\n }\n\n async merge() {\n // Compact all but active file\n const live: Map<string, KeyDirEntry> = new Map()\n for (const [k, meta] of this.keydir.entries()) {\n if (!meta.tombstone) live.set(k, meta)\n }\n const fileIds = this.listDataFiles().map(f => parseInt(f.split('.')[0], 10))\n const nextId = fileIds.length ? Math.max(...fileIds) + 1 : 1\n const fname = `${nextId.toString().padStart(8, '0')}.data`\n const filePath = path.join(this.dirname, fname)\n const f = fs.createWriteStream(filePath, { flags: 'a' })\n for (const [k, meta] of live.entries()) {\n const v = await this.get(k)\n const keyBuf = Buffer.from(k, 'binary')\n const header = Buffer.alloc(ENTRY_HEADER_SIZE)\n header.writeUInt32BE(keyBuf.length, 0)\n header.writeUInt32BE(v!.length, 4)\n header.writeUInt8(0, 8)\n header.writeBigUInt64BE(meta.timestamp, 9)\n const entry = Buffer.concat([header, keyBuf, v!])\n await new Promise<void>((resolve, reject) => {\n f.write(entry, err => (err ? reject(err) : resolve()))\n })\n }\n f.close()\n for (const fid of fileIds) {\n if (fid !== this.activeFileId && fid !== nextId) {\n try {\n fs.unlinkSync(path.join(this.dirname, `${fid.toString().padStart(8, '0')}.data`))\n } catch { }\n }\n }\n this.loadFiles()\n }\n\n sync() {\n if (this.activeFile) fs.fsyncSync((this.activeFile as any).fd)\n }\n\n async close() {\n if (this.activeFile) this.activeFile.end()\n for (const fh of this.openFiles.values()) await fh.close()\n this.openFiles.clear()\n }\n}\n\n// API functions\nexport function open(dirname: string, opts?: { readWrite?: boolean; syncOnPut?: boolean }) {\n return new Bitcask(dirname, opts)\n}\nexport async function get(handle: Bitcask, key: string | Buffer) {\n const v = await handle.get(key)\n return v === null ? 'not found' : v\n}\nexport async function put(handle: Bitcask, key: string | Buffer, value: string | Buffer) {\n await handle.put(key, value)\n return 'ok'\n}\nexport async function del(handle: Bitcask, key: string | Buffer) {\n await handle.delete(key)\n return 'ok'\n}\nexport function listKeys(handle: Bitcask) {\n return handle.listKeys()\n}\nexport async function fold<T>(handle: Bitcask, fn: (k: string, v: Buffer, acc: T) => T, acc0: T) {\n return await handle.fold(fn, acc0)\n}\nexport async function merge(dirname: string) {\n const h = new Bitcask(dirname, { readWrite: true })\n await h.merge()\n h.close()\n return 'ok'\n}\nexport function sync(handle: Bitcask) {\n handle.sync()\n return 'ok'\n}\nexport async function close(handle: Bitcask) {\n await handle.close()\n return 'ok'\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"bitcask.mjs","names":["openFile"],"sources":["../../src/_experiments/bitcask.ts"],"sourcesContent":["// Bitcask-inspired key-value store (minimal, single-process, single-writer)\n// Copyright 2024\nimport * as fs from 'fs'\nimport * as path from 'path'\nimport { FileHandle, open as openFile } from 'fs/promises'\n\nconst ENTRY_HEADER_SIZE = 17 // 4 (key) + 4 (value) + 1 (tombstone) + 8 (timestamp)\n\ninterface KeyDirEntry {\n fileId: number\n offset: number\n size: number\n timestamp: bigint\n tombstone: boolean\n}\n\nexport class Bitcask {\n private dirname: string\n private readWrite: boolean\n private syncOnPut: boolean\n private keydir: Map<string, KeyDirEntry> = new Map();\n private activeFile: fs.WriteStream | null = null;\n private activeFileId: number = 0;\n private activeOffset: number = 0;\n private openFiles: Map<number, FileHandle> = new Map();\n\n constructor(dirname: string, opts: { readWrite?: boolean; syncOnPut?: boolean } = {}) {\n this.dirname = dirname\n this.readWrite = opts.readWrite !== false\n this.syncOnPut = opts.syncOnPut === true\n if (!fs.existsSync(dirname)) fs.mkdirSync(dirname, { recursive: true })\n this.loadFiles()\n if (this.readWrite) this.rollover()\n }\n\n private listDataFiles(): string[] {\n return fs.readdirSync(this.dirname).filter(f => f.endsWith('.data')).sort()\n }\n\n private loadFiles() {\n for (const fname of this.listDataFiles()) {\n const fileId = parseInt(fname.split('.')[0], 10)\n const filePath = path.join(this.dirname, fname)\n const fd = fs.openSync(filePath, 'r')\n let offset = 0\n while (true) {\n const header = Buffer.alloc(ENTRY_HEADER_SIZE)\n const bytesRead = fs.readSync(fd, header, 0, ENTRY_HEADER_SIZE, offset)\n if (bytesRead < ENTRY_HEADER_SIZE) break\n const keySize = header.readUInt32BE(0)\n const valueSize = header.readUInt32BE(4)\n const tombstone = header.readUInt8(8) === 1\n const timestamp = header.readBigUInt64BE(9)\n const key = Buffer.alloc(keySize)\n fs.readSync(fd, key, 0, keySize, offset + ENTRY_HEADER_SIZE)\n // skip value\n const entrySize = ENTRY_HEADER_SIZE + keySize + valueSize\n this.keydir.set(key.toString('binary'), {\n fileId,\n offset,\n size: entrySize,\n timestamp,\n tombstone,\n })\n offset += entrySize\n }\n fs.closeSync(fd)\n }\n }\n\n private rollover() {\n const fileIds = this.listDataFiles().map(f => parseInt(f.split('.')[0], 10))\n const nextId = fileIds.length ? Math.max(...fileIds) + 1 : 1\n const fname = `${nextId.toString().padStart(8, '0')}.data`\n const filePath = path.join(this.dirname, fname)\n this.activeFile = fs.createWriteStream(filePath, { flags: 'a' })\n this.activeFileId = nextId\n this.activeOffset = fs.existsSync(filePath) ? fs.statSync(filePath).size : 0\n }\n\n async put(key: string | Buffer, value: string | Buffer) {\n if (!this.readWrite) throw new Error('Read-only mode')\n const keyBuf = Buffer.isBuffer(key) ? key : Buffer.from(key)\n const valueBuf = Buffer.isBuffer(value) ? value : Buffer.from(value)\n const timestamp = BigInt(Date.now())\n const tombstone = 0\n const header = Buffer.alloc(ENTRY_HEADER_SIZE)\n header.writeUInt32BE(keyBuf.length, 0)\n header.writeUInt32BE(valueBuf.length, 4)\n header.writeUInt8(tombstone, 8)\n header.writeBigUInt64BE(timestamp, 9)\n const entry = Buffer.concat([header, keyBuf, valueBuf])\n const offset = this.activeOffset\n await new Promise<void>((resolve, reject) => {\n this.activeFile!.write(entry, err => (err ? reject(err) : resolve()))\n })\n if (this.syncOnPut && this.activeFile) {\n fs.fsyncSync((this.activeFile as any).fd)\n }\n this.keydir.set(keyBuf.toString('binary'), {\n fileId: this.activeFileId,\n offset,\n size: entry.length,\n timestamp,\n tombstone: false,\n })\n this.activeOffset += entry.length\n if (this.activeOffset > 32 * 1024 * 1024) {\n this.activeFile!.close()\n this.rollover()\n }\n }\n\n async get(key: string | Buffer): Promise<Buffer | null> {\n const keyBuf = Buffer.isBuffer(key) ? key : Buffer.from(key)\n const meta = this.keydir.get(keyBuf.toString('binary'))\n if (!meta || meta.tombstone) return null\n let fh = this.openFiles.get(meta.fileId)\n if (!fh) {\n const fname = path.join(this.dirname, `${meta.fileId.toString().padStart(8, '0')}.data`)\n fh = await openFile(fname, 'r')\n this.openFiles.set(meta.fileId, fh)\n }\n const header = Buffer.alloc(ENTRY_HEADER_SIZE)\n await fh.read(header, 0, ENTRY_HEADER_SIZE, meta.offset)\n const keySize = header.readUInt32BE(0)\n const valueSize = header.readUInt32BE(4)\n const keyRead = Buffer.alloc(keySize)\n await fh.read(keyRead, 0, keySize, meta.offset + ENTRY_HEADER_SIZE)\n const value = Buffer.alloc(valueSize)\n await fh.read(value, 0, valueSize, meta.offset + ENTRY_HEADER_SIZE + keySize)\n return value\n }\n\n async delete(key: string | Buffer) {\n if (!this.readWrite) throw new Error('Read-only mode')\n const keyBuf = Buffer.isBuffer(key) ? key : Buffer.from(key)\n const timestamp = BigInt(Date.now())\n const tombstone = 1\n const header = Buffer.alloc(ENTRY_HEADER_SIZE)\n header.writeUInt32BE(keyBuf.length, 0)\n header.writeUInt32BE(0, 4)\n header.writeUInt8(tombstone, 8)\n header.writeBigUInt64BE(timestamp, 9)\n const entry = Buffer.concat([header, keyBuf])\n const offset = this.activeOffset\n await new Promise<void>((resolve, reject) => {\n this.activeFile!.write(entry, err => (err ? reject(err) : resolve()))\n })\n if (this.syncOnPut && this.activeFile) {\n fs.fsyncSync((this.activeFile as any).fd)\n }\n this.keydir.set(keyBuf.toString('binary'), {\n fileId: this.activeFileId,\n offset,\n size: entry.length,\n timestamp,\n tombstone: true,\n })\n this.activeOffset += entry.length\n if (this.activeOffset > 32 * 1024 * 1024) {\n this.activeFile!.close()\n this.rollover()\n }\n }\n\n listKeys(): string[] {\n return Array.from(this.keydir.entries()).filter(([_, v]) => !v.tombstone).map(([k, _]) => k)\n }\n\n async fold<T>(fn: (k: string, v: Buffer, acc: T) => T, acc0: T): Promise<T> {\n for (const [k, meta] of this.keydir.entries()) {\n if (!meta.tombstone) {\n const v = await this.get(k)\n acc0 = fn(k, v!, acc0)\n }\n }\n return acc0\n }\n\n async merge() {\n // Compact all but active file\n const live: Map<string, KeyDirEntry> = new Map()\n for (const [k, meta] of this.keydir.entries()) {\n if (!meta.tombstone) live.set(k, meta)\n }\n const fileIds = this.listDataFiles().map(f => parseInt(f.split('.')[0], 10))\n const nextId = fileIds.length ? Math.max(...fileIds) + 1 : 1\n const fname = `${nextId.toString().padStart(8, '0')}.data`\n const filePath = path.join(this.dirname, fname)\n const f = fs.createWriteStream(filePath, { flags: 'a' })\n for (const [k, meta] of live.entries()) {\n const v = await this.get(k)\n const keyBuf = Buffer.from(k, 'binary')\n const header = Buffer.alloc(ENTRY_HEADER_SIZE)\n header.writeUInt32BE(keyBuf.length, 0)\n header.writeUInt32BE(v!.length, 4)\n header.writeUInt8(0, 8)\n header.writeBigUInt64BE(meta.timestamp, 9)\n const entry = Buffer.concat([header, keyBuf, v!])\n await new Promise<void>((resolve, reject) => {\n f.write(entry, err => (err ? reject(err) : resolve()))\n })\n }\n f.close()\n for (const fid of fileIds) {\n if (fid !== this.activeFileId && fid !== nextId) {\n try {\n fs.unlinkSync(path.join(this.dirname, `${fid.toString().padStart(8, '0')}.data`))\n } catch { }\n }\n }\n this.loadFiles()\n }\n\n sync() {\n if (this.activeFile) fs.fsyncSync((this.activeFile as any).fd)\n }\n\n async close() {\n if (this.activeFile) this.activeFile.end()\n for (const fh of this.openFiles.values()) await fh.close()\n this.openFiles.clear()\n }\n}\n\n// API functions\nexport function open(dirname: string, opts?: { readWrite?: boolean; syncOnPut?: boolean }) {\n return new Bitcask(dirname, opts)\n}\nexport async function get(handle: Bitcask, key: string | Buffer) {\n const v = await handle.get(key)\n return v === null ? 'not found' : v\n}\nexport async function put(handle: Bitcask, key: string | Buffer, value: string | Buffer) {\n await handle.put(key, value)\n return 'ok'\n}\nexport async function del(handle: Bitcask, key: string | Buffer) {\n await handle.delete(key)\n return 'ok'\n}\nexport function listKeys(handle: Bitcask) {\n return handle.listKeys()\n}\nexport async function fold<T>(handle: Bitcask, fn: (k: string, v: Buffer, acc: T) => T, acc0: T) {\n return await handle.fold(fn, acc0)\n}\nexport async function merge(dirname: string) {\n const h = new Bitcask(dirname, { readWrite: true })\n await h.merge()\n h.close()\n return 'ok'\n}\nexport function sync(handle: Bitcask) {\n handle.sync()\n return 'ok'\n}\nexport async function close(handle: Bitcask) {\n await handle.close()\n return 'ok'\n}\n"],"mappings":"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"}
|