@cloudbitmaps/roaring 0.8.2 → 0.10.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/NOTICE +3 -3
- package/PRIVACY.md +198 -72
- package/README.md +148 -50
- package/dist/bin/export-segments.d.ts +21 -0
- package/dist/bin/export-segments.js +1508 -30
- package/dist/bin/export-segments.js.map +7 -1
- package/dist/codec-bound.d.ts +38 -0
- package/dist/index.d.ts +875 -425
- package/dist/index.js +997 -306
- package/dist/index.js.map +7 -1
- package/dist/moved-options.d.ts +14 -0
- package/dist/portable/decode.d.ts +54 -0
- package/dist/roaring-codec.d.ts +61 -0
- package/dist/system-clock.d.ts +40 -0
- package/dist/testing/conformance.d.ts +34 -0
- package/dist/testing/fuzz-codec.d.ts +9 -0
- package/package.json +11 -116
- package/dist/azure/index.cjs +0 -14
- package/dist/azure/index.cjs.map +0 -1
- package/dist/azure/index.d.cts +0 -9
- package/dist/azure/index.d.ts +0 -9
- package/dist/azure/index.js +0 -3
- package/dist/azure/index.js.map +0 -1
- package/dist/bin/compact-segments.js +0 -134
- package/dist/bin/compact-segments.js.map +0 -1
- package/dist/cassandra/index.cjs +0 -14
- package/dist/cassandra/index.cjs.map +0 -1
- package/dist/cassandra/index.d.cts +0 -1
- package/dist/cassandra/index.d.ts +0 -1
- package/dist/cassandra/index.js +0 -3
- package/dist/cassandra/index.js.map +0 -1
- package/dist/chunk-4NVOQJGJ.js +0 -801
- package/dist/chunk-4NVOQJGJ.js.map +0 -1
- package/dist/dynamodb/index.cjs +0 -14
- package/dist/dynamodb/index.cjs.map +0 -1
- package/dist/dynamodb/index.d.cts +0 -1
- package/dist/dynamodb/index.d.ts +0 -1
- package/dist/dynamodb/index.js +0 -3
- package/dist/dynamodb/index.js.map +0 -1
- package/dist/gcs/index.cjs +0 -14
- package/dist/gcs/index.cjs.map +0 -1
- package/dist/gcs/index.d.cts +0 -1
- package/dist/gcs/index.d.ts +0 -1
- package/dist/gcs/index.js +0 -3
- package/dist/gcs/index.js.map +0 -1
- package/dist/index.cjs +0 -789
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -642
- package/dist/mongodb/index.cjs +0 -14
- package/dist/mongodb/index.cjs.map +0 -1
- package/dist/mongodb/index.d.cts +0 -1
- package/dist/mongodb/index.d.ts +0 -1
- package/dist/mongodb/index.js +0 -3
- package/dist/mongodb/index.js.map +0 -1
- package/dist/mysql/index.cjs +0 -14
- package/dist/mysql/index.cjs.map +0 -1
- package/dist/mysql/index.d.cts +0 -1
- package/dist/mysql/index.d.ts +0 -1
- package/dist/mysql/index.js +0 -3
- package/dist/mysql/index.js.map +0 -1
- package/dist/postgres/index.cjs +0 -14
- package/dist/postgres/index.cjs.map +0 -1
- package/dist/postgres/index.d.cts +0 -1
- package/dist/postgres/index.d.ts +0 -1
- package/dist/postgres/index.js +0 -3
- package/dist/postgres/index.js.map +0 -1
- package/dist/redis/index.cjs +0 -14
- package/dist/redis/index.cjs.map +0 -1
- package/dist/redis/index.d.cts +0 -1
- package/dist/redis/index.d.ts +0 -1
- package/dist/redis/index.js +0 -3
- package/dist/redis/index.js.map +0 -1
- package/dist/s3/index.cjs +0 -14
- package/dist/s3/index.cjs.map +0 -1
- package/dist/s3/index.d.cts +0 -1
- package/dist/s3/index.d.ts +0 -1
- package/dist/s3/index.js +0 -3
- package/dist/s3/index.js.map +0 -1
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The 0.9.x option spellings this release no longer accepts, and what to tell someone who passes one.
|
|
3
|
+
*
|
|
4
|
+
* NOT part of the public API. It lives in its own module — rather than as an `export` from the barrel — so
|
|
5
|
+
* that the gates which must agree with it (the doc-fence scan, the harness scan, and the test that diffs this
|
|
6
|
+
* table against `CloudRoaringOptions` at the previous tag) can all read ONE copy, without the migration
|
|
7
|
+
* table becoming a permanent public export in the same release whose point was to shrink that surface.
|
|
8
|
+
*
|
|
9
|
+
* Retyping it was tried and is what this replaces: the hand-maintained copies had drifted to naming three
|
|
10
|
+
* spellings no release ever shipped while omitting the five that actually went away with the live tier.
|
|
11
|
+
*/
|
|
12
|
+
export type MovedOptionKind = 'group' | 'renamed' | 'gone';
|
|
13
|
+
/** `[the 0.9.x key, what to do instead, which kind of answer that is]`. */
|
|
14
|
+
export declare const MOVED_OPTIONS: ReadonlyArray<readonly [string, string, MovedOptionKind]>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A decoded portable-roaring bitmap that can be queried but not modified.
|
|
3
|
+
*
|
|
4
|
+
* Construction parses only the headers — container payloads are read on demand, so a membership test against a
|
|
5
|
+
* large bitmap touches one container rather than materializing the set.
|
|
6
|
+
*/
|
|
7
|
+
export declare class PortableRoaringReader {
|
|
8
|
+
private readonly bytes;
|
|
9
|
+
private readonly view;
|
|
10
|
+
private readonly containers;
|
|
11
|
+
private constructor();
|
|
12
|
+
/**
|
|
13
|
+
* Parse the headers of a portable-format bitmap.
|
|
14
|
+
*
|
|
15
|
+
* @throws {IntegrityError} if the cookie is unrecognized, or any header field runs past the buffer.
|
|
16
|
+
*/
|
|
17
|
+
static decode(bytes: Uint8Array): PortableRoaringReader;
|
|
18
|
+
/**
|
|
19
|
+
* Total cardinality.
|
|
20
|
+
*
|
|
21
|
+
* Served entirely from the descriptive header — no container payload is read, so this is O(containers) and
|
|
22
|
+
* independent of how many values the bitmap holds.
|
|
23
|
+
*/
|
|
24
|
+
count(): number;
|
|
25
|
+
/** Is `value` (a `u32`) in the set? */
|
|
26
|
+
has(value: number): boolean;
|
|
27
|
+
/** Binary search the descriptive header for the container owning `key`. */
|
|
28
|
+
private findContainer;
|
|
29
|
+
/**
|
|
30
|
+
* 1,024 little-endian `u64` words. Read as `u32` at `(low >> 5) * 4`: a LE `u64` is two LE `u32`s with the
|
|
31
|
+
* low word first, so the 32-bit view lands on the right half without any 64-bit arithmetic.
|
|
32
|
+
*/
|
|
33
|
+
private bitmapHas;
|
|
34
|
+
/**
|
|
35
|
+
* Sorted `u16` values — binary search.
|
|
36
|
+
*
|
|
37
|
+
* The `at === low` early return means the `at < low` below is only ever evaluated when `at !== low`, so
|
|
38
|
+
* writing it `at <= low` would behave identically. That is recorded because mutation testing surfaced it as
|
|
39
|
+
* a surviving mutant: it is an *equivalent* one, unkillable by any test rather than a coverage gap — three
|
|
40
|
+
* non-equivalent mutations of these same lines (inverting the branches, never reporting a hit, dropping the
|
|
41
|
+
* last element) are all caught. Do not "fix" the survivor, and do not add a test chasing it.
|
|
42
|
+
*/
|
|
43
|
+
private arrayHas;
|
|
44
|
+
/**
|
|
45
|
+
* `u16` run count, then that many `(start, length)` `u16` pairs sorted by start.
|
|
46
|
+
*
|
|
47
|
+
* `length` is the number of values **after** `start`, so a run covers the inclusive range
|
|
48
|
+
* `[start, start + length]` and a single-value run is stored with length 0. Getting this off by one is the
|
|
49
|
+
* easiest mistake in the format and is why the differential test drives runs specifically.
|
|
50
|
+
*/
|
|
51
|
+
private runHas;
|
|
52
|
+
}
|
|
53
|
+
/** Convenience wrapper over {@link PortableRoaringReader.decode}. */
|
|
54
|
+
export declare function decodePortableRoaring(bytes: Uint8Array): PortableRoaringReader;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { CodecBitmap, CodecInterface } from '@cloudbitmaps/core';
|
|
2
|
+
export declare class SafeBitmap implements CodecBitmap {
|
|
3
|
+
private readonly bitmap;
|
|
4
|
+
private constructor();
|
|
5
|
+
static empty(): SafeBitmap;
|
|
6
|
+
static fromValues(values: Iterable<number>): SafeBitmap;
|
|
7
|
+
/**
|
|
8
|
+
* Validate size, then deserialize with the **portable** (validated) format.
|
|
9
|
+
* Throws `IntegrityError` if the input exceeds `maxBytes` or fails to decode — the
|
|
10
|
+
* native addon is never handed unbounded or unsafe-format input.
|
|
11
|
+
*/
|
|
12
|
+
static safeDeserialize(bytes: Uint8Array, maxBytes: number): SafeBitmap;
|
|
13
|
+
serialize(): Uint8Array;
|
|
14
|
+
/**
|
|
15
|
+
* Convert containers to run-encoding where that is smaller. Representation only — membership is untouched, and
|
|
16
|
+
* the portable format still round-trips through {@link RoaringCodec.safeDeserialize}.
|
|
17
|
+
*
|
|
18
|
+
* Roaring's third container type is a RUN, and no implementation selects it on its own: it takes an explicit
|
|
19
|
+
* `runOptimize()` pass. Nothing here made that call, so run-shaped ids paid array or bitset prices — measured
|
|
20
|
+
* at **570×** for a contiguous 1M-id range (128.1 KiB → 0.2 KiB) and **63×** for a 2,000-run shape
|
|
21
|
+
* (536.5 KiB → 8.5 KiB). Sparse ids come out byte-identical, so this is never a losing trade; roaring keeps
|
|
22
|
+
* whichever encoding is smaller per container.
|
|
23
|
+
*
|
|
24
|
+
* Those two factors are THIS CALL's own before/after on the same ids. They are not the ones the site quotes
|
|
25
|
+
* (543× and 63×) — those compare the optimized encoding against the best *fixed* representation at its floor,
|
|
26
|
+
* a different baseline that happens to land near 63× on the run shape too. `pnpm bench:encoding` prints both
|
|
27
|
+
* columns; don't carry a figure between them without checking which denominator it had.
|
|
28
|
+
*
|
|
29
|
+
* Called only when writing an immutable objects generation — see {@link CodecBitmap.optimize} for why the read
|
|
30
|
+
* path deliberately does not.
|
|
31
|
+
*/
|
|
32
|
+
optimize(): void;
|
|
33
|
+
/**
|
|
34
|
+
* Largest value, or `undefined` when empty. O(1) — roaring reads it off the container index, so the engine's
|
|
35
|
+
* per-chunk range assertion costs one call per chunk rather than a walk per id.
|
|
36
|
+
*/
|
|
37
|
+
maximum(): number | undefined;
|
|
38
|
+
add(value: number): void;
|
|
39
|
+
addMany(values: Iterable<number>): void;
|
|
40
|
+
remove(value: number): void;
|
|
41
|
+
removeMany(values: Iterable<number>): void;
|
|
42
|
+
has(value: number): boolean;
|
|
43
|
+
get size(): number;
|
|
44
|
+
get isEmpty(): boolean;
|
|
45
|
+
clone(): SafeBitmap;
|
|
46
|
+
/** In-place union: `this = this ∪ other`. */
|
|
47
|
+
orInPlace(other: CodecBitmap): void;
|
|
48
|
+
/** In-place difference: `this = this \ other`. */
|
|
49
|
+
andNotInPlace(other: CodecBitmap): void;
|
|
50
|
+
/** In-place intersection: `this = this ∩ other`. */
|
|
51
|
+
andInPlace(other: CodecBitmap): void;
|
|
52
|
+
/** Ascending iterator over the set values. */
|
|
53
|
+
[Symbol.iterator](): IterableIterator<number>;
|
|
54
|
+
toArray(): number[];
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The roaring {@link CodecInterface} — the flagship codec, delegating to {@link SafeBitmap}'s statics. This is
|
|
58
|
+
* the default the `CloudRoaring` facade injects into the engine; `core/` itself never hard-references it once a
|
|
59
|
+
* caller supplies a codec. Moves to `@cloudbitmaps/roaring` when the package split lands.
|
|
60
|
+
*/
|
|
61
|
+
export declare const roaringCodec: CodecInterface;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The default real-time {@link Clock} — the production half of the determinism seam.
|
|
3
|
+
*
|
|
4
|
+
* It lives outside `core/`, so `Date.now()`, `setTimeout` and `setImmediate` are allowed here; that separation is
|
|
5
|
+
* the whole point of the seam, and it is lint-enforced on the other side.
|
|
6
|
+
*
|
|
7
|
+
* It sits in its own module rather than in `index.ts` because two places need it — the facade, and
|
|
8
|
+
* `codec-bound.ts`, which pre-binds it into `bulkLoadCrbmGeneration`. Importing it from `index.ts` would put a
|
|
9
|
+
* cycle between the barrel and a module the barrel re-exports.
|
|
10
|
+
*/
|
|
11
|
+
import type { Clock } from '@cloudbitmaps/core';
|
|
12
|
+
/** Default real-time clock — lives outside `core/`, so `Date.now()` + timers are allowed here. */
|
|
13
|
+
export declare class SystemClock implements Clock {
|
|
14
|
+
now(): number;
|
|
15
|
+
sleep(ms: number): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* `setImmediate`, and it has to be — this is the one place where the choice of primitive is the whole feature.
|
|
18
|
+
*
|
|
19
|
+
* A long CPU-bound loop in `core/` (bulk-load is the one that matters) periodically hands the loop back so a
|
|
20
|
+
* co-resident HTTP server keeps answering. Measured on the **synthetic yield-primitive benchmark** — a
|
|
21
|
+
* 61,035-iteration loop yielding every 1,024, isolating the primitive rather than timing a real load (the
|
|
22
|
+
* end-to-end figures are 450 ms → 19 ms; see `cooperative.ts`, which lists all three experiments):
|
|
23
|
+
*
|
|
24
|
+
* ```text
|
|
25
|
+
* no yield 568 ms wall 568.0 ms worst event-loop gap
|
|
26
|
+
* sleep(0) 555 ms wall 555.2 ms ← a microtask. Yields NOTHING.
|
|
27
|
+
* setImmediate 569 ms wall 13.8 ms ← free, and 41x less starvation
|
|
28
|
+
* setTimeout(1) 625 ms wall 15.0 ms ← +10% wall for no extra relief
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* `sleep(0)` resolving on a microtask is correct for its own contract and useless for this: microtasks drain
|
|
32
|
+
* before the loop ever advances a phase, so `await sleep(0)` in a tight loop never lets a single pending I/O
|
|
33
|
+
* callback run. `setImmediate` fires in the check phase *after* pending I/O, which is exactly the ordering a
|
|
34
|
+
* server wants — inbound requests are serviced before the loop resumes chewing.
|
|
35
|
+
*
|
|
36
|
+
* A timer is not ref'd here (unlike {@link sleep}): a yield expresses "someone else may go first", never
|
|
37
|
+
* "there is outstanding work" — and `setImmediate` cannot outlive the turn that scheduled it anyway.
|
|
38
|
+
*/
|
|
39
|
+
yieldNow(): Promise<void>;
|
|
40
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { SafeBitmap } from '../roaring-codec.js';
|
|
2
|
+
import type { StorageChunkSource, IRegistryDriver } from '@cloudbitmaps/core';
|
|
3
|
+
/**
|
|
4
|
+
* The segment every conformance seeder must write. Exported so a driver's own test file derives the name
|
|
5
|
+
* instead of restating it — a second copy that drifts makes the suite query a segment nobody seeded, which
|
|
6
|
+
* fails as an empty result rather than as the mismatch it actually is.
|
|
7
|
+
*/
|
|
8
|
+
export declare const CONFORMANCE_SEGMENT = "s:v1";
|
|
9
|
+
/**
|
|
10
|
+
* Contract tests for a {@link StorageChunkSource}. `makeSource` MUST build a fresh source seeded with the
|
|
11
|
+
* given chunks (each an immutable Storage bitmap) and nothing else.
|
|
12
|
+
*/
|
|
13
|
+
export declare function storageChunkSourceConformance(label: string, makeSource: (chunks: Array<{
|
|
14
|
+
chunkKey: number;
|
|
15
|
+
bitmap: SafeBitmap;
|
|
16
|
+
}>) => Promise<StorageChunkSource>): void;
|
|
17
|
+
/**
|
|
18
|
+
* Contract tests for an {@link IRegistryDriver}. `makeDriver` MUST return a fresh, empty, isolated driver on
|
|
19
|
+
* each call. The OCC contract (create / token-fenced CAS / ABA) plus the registry's record semantics (forward
|
|
20
|
+
* currentGen, status, clearable keyId, discovery).
|
|
21
|
+
*/
|
|
22
|
+
export declare function registryConformance(label: string, makeDriver: () => IRegistryDriver): void;
|
|
23
|
+
/**
|
|
24
|
+
* Contract tests for an {@link IRegistryDriver} under **concurrent writers** — `makeDrivers` MUST return two
|
|
25
|
+
* independent driver instances over the **same** backing store, as two processes would see it.
|
|
26
|
+
*
|
|
27
|
+
* This exists because {@link registryConformance} drives one driver sequentially, and `ObjectStoreRegistry`
|
|
28
|
+
* checks the OCC token in memory before it ever issues a conditional write. That in-process check answers
|
|
29
|
+
* every sequential case, so the store-level precondition — the only thing that fences writers *across*
|
|
30
|
+
* processes, and the entire reason these drivers are built on conditional writes — is never load-bearing
|
|
31
|
+
* there. A backend that accepted `If-Match` and ignored it passed the full suite; so did a GCS driver whose
|
|
32
|
+
* writes were not fenced at all. These cases are what make the fence testable.
|
|
33
|
+
*/
|
|
34
|
+
export declare function registryConcurrency(label: string, makeDrivers: () => readonly [IRegistryDriver, IRegistryDriver]): void;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal surface for the coverage-guided fuzz harness, CODEC half.
|
|
3
|
+
*
|
|
4
|
+
* Only the concrete bitmap codec lives here — the core half (`CrbmReader`, the non-public `parseIndex`,
|
|
5
|
+
* `BufferReader`, `CloudRoaringError`, `DEFAULT_MAX_PAYLOAD_BYTES`) is built from `@cloudbitmaps/core`'s own
|
|
6
|
+
* `src/testing/fuzz-core.ts` to `fuzz/build/fuzz-core.js`. Splitting it this way keeps the published entries
|
|
7
|
+
* of both packages free of test-only exports: neither widened its public API to feed the fuzzer.
|
|
8
|
+
*/
|
|
9
|
+
export { SafeBitmap } from '../roaring-codec.js';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudbitmaps/roaring",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Distributed, cloud-native Roaring Bitmaps — query and intersect billion-scale integer sets
|
|
3
|
+
"version": "0.10.0",
|
|
4
|
+
"description": "Distributed, cloud-native Roaring Bitmaps — query and intersect billion-scale integer sets straight out of object storage, from a bounded RAM cache over immutable objects in your own bucket, at a fraction of an always-on cache.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"roaring",
|
|
7
7
|
"bitmap",
|
|
@@ -16,17 +16,10 @@
|
|
|
16
16
|
"set",
|
|
17
17
|
"set-intersection",
|
|
18
18
|
"s3",
|
|
19
|
-
"dynamodb",
|
|
20
19
|
"gcs",
|
|
21
20
|
"azure",
|
|
22
|
-
"postgres",
|
|
23
|
-
"redis",
|
|
24
|
-
"mongodb",
|
|
25
|
-
"cassandra",
|
|
26
|
-
"mysql",
|
|
27
|
-
"mariadb",
|
|
28
21
|
"serverless",
|
|
29
|
-
"
|
|
22
|
+
"object-storage",
|
|
30
23
|
"scale-to-zero",
|
|
31
24
|
"segmentation",
|
|
32
25
|
"audience",
|
|
@@ -38,7 +31,8 @@
|
|
|
38
31
|
"author": "Sharvil Kadam",
|
|
39
32
|
"repository": {
|
|
40
33
|
"type": "git",
|
|
41
|
-
"url": "git+https://github.com/cloudbitmaps/cloudbitmaps.git"
|
|
34
|
+
"url": "git+https://github.com/cloudbitmaps/cloudbitmaps.git",
|
|
35
|
+
"directory": "packages/roaring"
|
|
42
36
|
},
|
|
43
37
|
"homepage": "https://github.com/cloudbitmaps/cloudbitmaps#readme",
|
|
44
38
|
"bugs": {
|
|
@@ -46,62 +40,15 @@
|
|
|
46
40
|
},
|
|
47
41
|
"type": "module",
|
|
48
42
|
"engines": {
|
|
49
|
-
"node": ">=22"
|
|
43
|
+
"node": ">=22.12"
|
|
50
44
|
},
|
|
51
45
|
"sideEffects": false,
|
|
52
|
-
"main": "./dist/index.
|
|
53
|
-
"module": "./dist/index.js",
|
|
46
|
+
"main": "./dist/index.js",
|
|
54
47
|
"types": "./dist/index.d.ts",
|
|
55
48
|
"exports": {
|
|
56
49
|
".": {
|
|
57
50
|
"types": "./dist/index.d.ts",
|
|
58
|
-
"
|
|
59
|
-
"require": "./dist/index.cjs"
|
|
60
|
-
},
|
|
61
|
-
"./s3": {
|
|
62
|
-
"types": "./dist/s3/index.d.ts",
|
|
63
|
-
"import": "./dist/s3/index.js",
|
|
64
|
-
"require": "./dist/s3/index.cjs"
|
|
65
|
-
},
|
|
66
|
-
"./dynamodb": {
|
|
67
|
-
"types": "./dist/dynamodb/index.d.ts",
|
|
68
|
-
"import": "./dist/dynamodb/index.js",
|
|
69
|
-
"require": "./dist/dynamodb/index.cjs"
|
|
70
|
-
},
|
|
71
|
-
"./gcs": {
|
|
72
|
-
"types": "./dist/gcs/index.d.ts",
|
|
73
|
-
"import": "./dist/gcs/index.js",
|
|
74
|
-
"require": "./dist/gcs/index.cjs"
|
|
75
|
-
},
|
|
76
|
-
"./azure": {
|
|
77
|
-
"types": "./dist/azure/index.d.ts",
|
|
78
|
-
"import": "./dist/azure/index.js",
|
|
79
|
-
"require": "./dist/azure/index.cjs"
|
|
80
|
-
},
|
|
81
|
-
"./postgres": {
|
|
82
|
-
"types": "./dist/postgres/index.d.ts",
|
|
83
|
-
"import": "./dist/postgres/index.js",
|
|
84
|
-
"require": "./dist/postgres/index.cjs"
|
|
85
|
-
},
|
|
86
|
-
"./redis": {
|
|
87
|
-
"types": "./dist/redis/index.d.ts",
|
|
88
|
-
"import": "./dist/redis/index.js",
|
|
89
|
-
"require": "./dist/redis/index.cjs"
|
|
90
|
-
},
|
|
91
|
-
"./mongodb": {
|
|
92
|
-
"types": "./dist/mongodb/index.d.ts",
|
|
93
|
-
"import": "./dist/mongodb/index.js",
|
|
94
|
-
"require": "./dist/mongodb/index.cjs"
|
|
95
|
-
},
|
|
96
|
-
"./cassandra": {
|
|
97
|
-
"types": "./dist/cassandra/index.d.ts",
|
|
98
|
-
"import": "./dist/cassandra/index.js",
|
|
99
|
-
"require": "./dist/cassandra/index.cjs"
|
|
100
|
-
},
|
|
101
|
-
"./mysql": {
|
|
102
|
-
"types": "./dist/mysql/index.d.ts",
|
|
103
|
-
"import": "./dist/mysql/index.js",
|
|
104
|
-
"require": "./dist/mysql/index.cjs"
|
|
51
|
+
"default": "./dist/index.js"
|
|
105
52
|
}
|
|
106
53
|
},
|
|
107
54
|
"files": [
|
|
@@ -115,69 +62,17 @@
|
|
|
115
62
|
"access": "public"
|
|
116
63
|
},
|
|
117
64
|
"bin": {
|
|
118
|
-
"compact-segments": "./dist/bin/compact-segments.js",
|
|
119
65
|
"export-segments": "./dist/bin/export-segments.js"
|
|
120
66
|
},
|
|
121
67
|
"dependencies": {
|
|
122
|
-
"roaring": "
|
|
123
|
-
"@cloudbitmaps/core": "0.
|
|
124
|
-
},
|
|
125
|
-
"peerDependencies": {
|
|
126
|
-
"@aws-sdk/client-dynamodb": "^3",
|
|
127
|
-
"@aws-sdk/client-s3": "^3",
|
|
128
|
-
"@azure/storage-blob": "^12",
|
|
129
|
-
"@google-cloud/storage": "^7",
|
|
130
|
-
"cassandra-driver": "^4",
|
|
131
|
-
"ioredis": "^5",
|
|
132
|
-
"mongodb": "^6",
|
|
133
|
-
"mysql2": "^3",
|
|
134
|
-
"pg": "^8"
|
|
135
|
-
},
|
|
136
|
-
"peerDependenciesMeta": {
|
|
137
|
-
"@aws-sdk/client-dynamodb": {
|
|
138
|
-
"optional": true
|
|
139
|
-
},
|
|
140
|
-
"@aws-sdk/client-s3": {
|
|
141
|
-
"optional": true
|
|
142
|
-
},
|
|
143
|
-
"@azure/storage-blob": {
|
|
144
|
-
"optional": true
|
|
145
|
-
},
|
|
146
|
-
"@google-cloud/storage": {
|
|
147
|
-
"optional": true
|
|
148
|
-
},
|
|
149
|
-
"cassandra-driver": {
|
|
150
|
-
"optional": true
|
|
151
|
-
},
|
|
152
|
-
"ioredis": {
|
|
153
|
-
"optional": true
|
|
154
|
-
},
|
|
155
|
-
"mongodb": {
|
|
156
|
-
"optional": true
|
|
157
|
-
},
|
|
158
|
-
"mysql2": {
|
|
159
|
-
"optional": true
|
|
160
|
-
},
|
|
161
|
-
"pg": {
|
|
162
|
-
"optional": true
|
|
163
|
-
}
|
|
68
|
+
"roaring": "2.7.0",
|
|
69
|
+
"@cloudbitmaps/core": "^0.10.0"
|
|
164
70
|
},
|
|
165
71
|
"devDependencies": {
|
|
166
|
-
"@aws-sdk/client-dynamodb": "^3.1075.0",
|
|
167
|
-
"@aws-sdk/client-s3": "^3.1075.0",
|
|
168
|
-
"@azure/storage-blob": "^12",
|
|
169
|
-
"@google-cloud/storage": "^7.0.0",
|
|
170
|
-
"cassandra-driver": "^4",
|
|
171
|
-
"ioredis": "^5",
|
|
172
|
-
"mongodb": "^6",
|
|
173
|
-
"mysql2": "^3.23.1",
|
|
174
|
-
"pg": "^8",
|
|
175
|
-
"@types/pg": "^8",
|
|
176
72
|
"@types/node": "^22.0.0",
|
|
177
|
-
"tsup": "^8.0.0",
|
|
178
73
|
"typescript": "^5.5.0"
|
|
179
74
|
},
|
|
180
75
|
"scripts": {
|
|
181
|
-
"build": "
|
|
76
|
+
"build": "node ../../scripts/build.mjs"
|
|
182
77
|
}
|
|
183
78
|
}
|
package/dist/azure/index.cjs
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var azure = require('@cloudbitmaps/core/azure');
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Object.keys(azure).forEach(function (k) {
|
|
8
|
-
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
9
|
-
enumerable: true,
|
|
10
|
-
get: function () { return azure[k]; }
|
|
11
|
-
});
|
|
12
|
-
});
|
|
13
|
-
//# sourceMappingURL=index.cjs.map
|
|
14
|
-
//# sourceMappingURL=index.cjs.map
|
package/dist/azure/index.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.cjs","sourcesContent":[]}
|
package/dist/azure/index.d.cts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export * from '@cloudbitmaps/core/azure';
|
|
2
|
-
import '@cloudbitmaps/core/cassandra';
|
|
3
|
-
import '@cloudbitmaps/core/dynamodb';
|
|
4
|
-
import '@cloudbitmaps/core/gcs';
|
|
5
|
-
import '@cloudbitmaps/core/mongodb';
|
|
6
|
-
import '@cloudbitmaps/core/mysql';
|
|
7
|
-
import '@cloudbitmaps/core/postgres';
|
|
8
|
-
import '@cloudbitmaps/core/redis';
|
|
9
|
-
import '@cloudbitmaps/core/s3';
|
package/dist/azure/index.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export * from '@cloudbitmaps/core/azure';
|
|
2
|
-
import '@cloudbitmaps/core/cassandra';
|
|
3
|
-
import '@cloudbitmaps/core/dynamodb';
|
|
4
|
-
import '@cloudbitmaps/core/gcs';
|
|
5
|
-
import '@cloudbitmaps/core/mongodb';
|
|
6
|
-
import '@cloudbitmaps/core/mysql';
|
|
7
|
-
import '@cloudbitmaps/core/postgres';
|
|
8
|
-
import '@cloudbitmaps/core/redis';
|
|
9
|
-
import '@cloudbitmaps/core/s3';
|
package/dist/azure/index.js
DELETED
package/dist/azure/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js","sourcesContent":[]}
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { SystemClock, src_exports, runCompactionCycle } from '../chunk-4NVOQJGJ.js';
|
|
3
|
-
import { hostname } from 'os';
|
|
4
|
-
import { join } from 'path';
|
|
5
|
-
import { pathToFileURL } from 'url';
|
|
6
|
-
|
|
7
|
-
function parseConfig(env) {
|
|
8
|
-
const root = env.CR_COMPACT_ROOT;
|
|
9
|
-
if (root === void 0 || root === "") {
|
|
10
|
-
throw new Error("CR_COMPACT_ROOT is required (the local-filesystem storage root)");
|
|
11
|
-
}
|
|
12
|
-
const mode = env.CR_COMPACT_MODE ?? "once";
|
|
13
|
-
if (mode !== "once" && mode !== "loop") {
|
|
14
|
-
throw new Error(`CR_COMPACT_MODE must be "once" or "loop"; got ${mode}`);
|
|
15
|
-
}
|
|
16
|
-
const num = (name, def) => {
|
|
17
|
-
const raw = env[name];
|
|
18
|
-
if (raw === void 0 || raw === "") return def;
|
|
19
|
-
const v = Number(raw);
|
|
20
|
-
if (!Number.isFinite(v) || v < 0)
|
|
21
|
-
throw new Error(`${name} must be a non-negative number; got ${raw}`);
|
|
22
|
-
return v;
|
|
23
|
-
};
|
|
24
|
-
const intOpt = (name, min = 0) => {
|
|
25
|
-
const raw = env[name];
|
|
26
|
-
if (raw === void 0 || raw === "") return void 0;
|
|
27
|
-
const v = Number(raw);
|
|
28
|
-
if (!Number.isInteger(v) || v < min)
|
|
29
|
-
throw new Error(`${name} must be an integer >= ${min}; got ${raw}`);
|
|
30
|
-
return v;
|
|
31
|
-
};
|
|
32
|
-
const shard = intOpt("CR_COMPACT_SHARD");
|
|
33
|
-
const totalShards = intOpt("CR_COMPACT_TOTAL_SHARDS");
|
|
34
|
-
if (shard === void 0 !== (totalShards === void 0)) {
|
|
35
|
-
throw new Error("set both CR_COMPACT_SHARD and CR_COMPACT_TOTAL_SHARDS, or neither");
|
|
36
|
-
}
|
|
37
|
-
return {
|
|
38
|
-
root,
|
|
39
|
-
mode,
|
|
40
|
-
intervalMs: num("CR_COMPACT_INTERVAL_MS", 3e4),
|
|
41
|
-
namespace: env.CR_COMPACT_NAMESPACE,
|
|
42
|
-
threshold: num("CR_COMPACT_THRESHOLD", 1),
|
|
43
|
-
keep: num("CR_COMPACT_KEEP", 1),
|
|
44
|
-
owner: env.CR_COMPACT_OWNER ?? `${hostname()}:${process.pid}`,
|
|
45
|
-
shard,
|
|
46
|
-
totalShards,
|
|
47
|
-
maxSegments: intOpt("CR_COMPACT_MAX_SEGMENTS", 1)
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
function localFsDeps(root, metrics) {
|
|
51
|
-
return {
|
|
52
|
-
cold: new src_exports.LocalFsColdDriver(join(root, "cold")),
|
|
53
|
-
warm: new src_exports.LocalFsWarmDriver(join(root, "warm")),
|
|
54
|
-
registry: new src_exports.LocalFsRegistryDriver(join(root, "registry")),
|
|
55
|
-
// A real clock, not `{ now }`: outside `core/` ambient time is allowed, and a full clock is what lets
|
|
56
|
-
// the generation write hand the event loop back instead of blocking the daemon for its whole duration.
|
|
57
|
-
clock: new SystemClock(),
|
|
58
|
-
...metrics ? { metrics } : {}
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
async function runOnce(deps, config) {
|
|
62
|
-
return runCompactionCycle(deps, {
|
|
63
|
-
owner: config.owner,
|
|
64
|
-
namespace: config.namespace,
|
|
65
|
-
threshold: config.threshold,
|
|
66
|
-
keep: config.keep,
|
|
67
|
-
shard: config.shard,
|
|
68
|
-
totalShards: config.totalShards,
|
|
69
|
-
maxSegments: config.maxSegments
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
73
|
-
var log = (obj) => {
|
|
74
|
-
process.stdout.write(`${JSON.stringify(obj)}
|
|
75
|
-
`);
|
|
76
|
-
};
|
|
77
|
-
function stdoutMetricsSink() {
|
|
78
|
-
return {
|
|
79
|
-
onEvent: (event) => log({ event: "metric", ...event })
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
async function main(env = process.env) {
|
|
83
|
-
const config = parseConfig(env);
|
|
84
|
-
const deps = localFsDeps(
|
|
85
|
-
config.root,
|
|
86
|
-
env.CR_COMPACT_METRICS === "1" ? stdoutMetricsSink() : void 0
|
|
87
|
-
);
|
|
88
|
-
if (config.mode === "once") {
|
|
89
|
-
const cycle = await runOnce(deps, config);
|
|
90
|
-
log({
|
|
91
|
-
event: "cycle",
|
|
92
|
-
mode: "once",
|
|
93
|
-
candidates: cycle.candidates,
|
|
94
|
-
compacted: cycle.compacted,
|
|
95
|
-
deferred: cycle.deferred,
|
|
96
|
-
results: cycle.results
|
|
97
|
-
});
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
let stop = false;
|
|
101
|
-
const onSignal = () => {
|
|
102
|
-
stop = true;
|
|
103
|
-
};
|
|
104
|
-
process.on("SIGINT", onSignal);
|
|
105
|
-
process.on("SIGTERM", onSignal);
|
|
106
|
-
log({ event: "start", mode: "loop", intervalMs: config.intervalMs, owner: config.owner });
|
|
107
|
-
while (!stop) {
|
|
108
|
-
try {
|
|
109
|
-
const cycle = await runOnce(deps, config);
|
|
110
|
-
log({
|
|
111
|
-
event: "cycle",
|
|
112
|
-
candidates: cycle.candidates,
|
|
113
|
-
compacted: cycle.compacted,
|
|
114
|
-
deferred: cycle.deferred,
|
|
115
|
-
results: cycle.results
|
|
116
|
-
});
|
|
117
|
-
} catch (err) {
|
|
118
|
-
log({ event: "error", message: err.message });
|
|
119
|
-
}
|
|
120
|
-
if (!stop) await sleep(config.intervalMs);
|
|
121
|
-
}
|
|
122
|
-
log({ event: "stopped" });
|
|
123
|
-
}
|
|
124
|
-
if (process.argv[1] !== void 0 && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
125
|
-
main().catch((err) => {
|
|
126
|
-
process.stderr.write(`${err.message}
|
|
127
|
-
`);
|
|
128
|
-
process.exit(1);
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
export { localFsDeps, main, parseConfig, runOnce };
|
|
133
|
-
//# sourceMappingURL=compact-segments.js.map
|
|
134
|
-
//# sourceMappingURL=compact-segments.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/bin/compact-segments.ts"],"names":[],"mappings":"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","file":"compact-segments.js","sourcesContent":["#!/usr/bin/env node\n/**\n * `compact-segments` — the standalone compaction daemon CLI (Phase 4d).\n *\n * A thin wrapper over {@link runCompactionCycle}: discover dirty segments → 2-phase-commit compact → GC. It\n * ships the **local-filesystem** backend (zero-dependency, the dev/reference target) and two **deploy modes**:\n *\n * - `once` — run a single cycle and exit (the **Lambda / one-shot / cron** shape).\n * - `loop` — run a cycle every `intervalMs`, until SIGINT/SIGTERM (the **K8s Deployment / ECS service** shape).\n *\n * **Cloud backends:** rather than have the CLI guess your AWS config, production wires its own ~10-line\n * handler that constructs an `S3ColdDriver` + `DynamoDb{Warm,Registry}Driver` and calls `runCompactionCycle`\n * directly (same two modes — call once, or on a `setInterval`). The library exports everything needed; this\n * binary stays SDK-free (so the core install never pulls a cloud SDK). See the getting-started guide.\n *\n * Config is read from the environment (so it's identical across `once`/`loop` and 12-factor-friendly):\n * CR_COMPACT_ROOT (required) — the local-filesystem root holding cold/ warm/ registry/\n * CR_COMPACT_MODE once | loop (default: once)\n * CR_COMPACT_INTERVAL_MS (default: 30000, loop mode)\n * CR_COMPACT_NAMESPACE scope discovery to one namespace\n * CR_COMPACT_THRESHOLD min dirty chunks to compact (default: 1)\n * CR_COMPACT_KEEP superseded generations to retain as a reader grace window (default: 1)\n * CR_COMPACT_OWNER lease owner id (default: `<hostname>:<pid>`)\n * CR_COMPACT_SHARD / CR_COMPACT_TOTAL_SHARDS run this worker as shard i of N (set both) — partition the\n * fleet across N daemons so each drains only ~1/N of Warm per cycle (gap #3)\n * CR_COMPACT_MAX_SEGMENTS cap segments compacted per cycle (a time budget for a Lambda window); the rest\n * are deferred to the next cycle, most-dirty first\n * CR_COMPACT_METRICS 1 to emit each per-attempt compaction `MetricEvent` (retries, bytes, ms, faults) as a\n * JSON line on stdout — pipe to your metrics pipeline. Off by default (cycle summaries\n * still print regardless); the library's `IMetricsSink` seam is what this wires.\n */\nimport { SystemClock } from '../system-clock';\nimport { hostname } from 'node:os';\nimport { join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport {\n LocalFsColdDriver,\n LocalFsRegistryDriver,\n LocalFsWarmDriver,\n runCompactionCycle,\n} from '../index';\nimport type { CompactionCycleResult, CompactionDeps, IMetricsSink } from '../index';\n\nexport interface CompactConfig {\n readonly root: string;\n readonly mode: 'once' | 'loop';\n readonly intervalMs: number;\n readonly namespace?: string;\n readonly threshold: number;\n readonly keep: number;\n readonly owner: string;\n readonly shard?: number;\n readonly totalShards?: number;\n readonly maxSegments?: number;\n}\n\n/** Parse + validate config from an environment map. Throws a clear `Error` on misconfiguration. */\nexport function parseConfig(env: Record<string, string | undefined>): CompactConfig {\n const root = env.CR_COMPACT_ROOT;\n if (root === undefined || root === '') {\n throw new Error('CR_COMPACT_ROOT is required (the local-filesystem storage root)');\n }\n const mode = env.CR_COMPACT_MODE ?? 'once';\n if (mode !== 'once' && mode !== 'loop') {\n throw new Error(`CR_COMPACT_MODE must be \"once\" or \"loop\"; got ${mode}`);\n }\n const num = (name: string, def: number): number => {\n const raw = env[name];\n if (raw === undefined || raw === '') return def; // unset OR empty (a common unset-var expansion) → default\n const v = Number(raw);\n if (!Number.isFinite(v) || v < 0)\n throw new Error(`${name} must be a non-negative number; got ${raw}`);\n return v;\n };\n const intOpt = (name: string, min = 0): number | undefined => {\n const raw = env[name];\n if (raw === undefined || raw === '') return undefined;\n const v = Number(raw);\n if (!Number.isInteger(v) || v < min)\n throw new Error(`${name} must be an integer >= ${min}; got ${raw}`);\n return v;\n };\n const shard = intOpt('CR_COMPACT_SHARD');\n const totalShards = intOpt('CR_COMPACT_TOTAL_SHARDS');\n if ((shard === undefined) !== (totalShards === undefined)) {\n throw new Error('set both CR_COMPACT_SHARD and CR_COMPACT_TOTAL_SHARDS, or neither');\n }\n return {\n root,\n mode,\n intervalMs: num('CR_COMPACT_INTERVAL_MS', 30_000),\n namespace: env.CR_COMPACT_NAMESPACE,\n threshold: num('CR_COMPACT_THRESHOLD', 1),\n keep: num('CR_COMPACT_KEEP', 1),\n owner: env.CR_COMPACT_OWNER ?? `${hostname()}:${process.pid}`,\n shard,\n totalShards,\n maxSegments: intOpt('CR_COMPACT_MAX_SEGMENTS', 1),\n };\n}\n\n/** Build LocalFs compaction deps rooted at `<root>/{cold,warm,registry}`, optionally with a metrics sink. */\nexport function localFsDeps(root: string, metrics?: IMetricsSink): CompactionDeps {\n return {\n cold: new LocalFsColdDriver(join(root, 'cold')),\n warm: new LocalFsWarmDriver(join(root, 'warm')),\n registry: new LocalFsRegistryDriver(join(root, 'registry')),\n // A real clock, not `{ now }`: outside `core/` ambient time is allowed, and a full clock is what lets\n // the generation write hand the event loop back instead of blocking the daemon for its whole duration.\n clock: new SystemClock(),\n ...(metrics ? { metrics } : {}),\n };\n}\n\n/** Run a single compaction cycle and return the full result (the unit of work for both deploy modes). */\nexport async function runOnce(\n deps: CompactionDeps,\n config: CompactConfig,\n): Promise<CompactionCycleResult> {\n return runCompactionCycle(deps, {\n owner: config.owner,\n namespace: config.namespace,\n threshold: config.threshold,\n keep: config.keep,\n shard: config.shard,\n totalShards: config.totalShards,\n maxSegments: config.maxSegments,\n });\n}\n\nconst sleep = (ms: number): Promise<void> => new Promise((r) => setTimeout(r, ms));\nconst log = (obj: unknown): void => {\n process.stdout.write(`${JSON.stringify(obj)}\\n`);\n};\n\n/** A stdout `IMetricsSink` (opt-in via CR_COMPACT_METRICS) — one JSON line per compaction `MetricEvent`. */\nfunction stdoutMetricsSink(): IMetricsSink {\n return {\n onEvent: (event) => log({ event: 'metric', ...event }),\n };\n}\n\n/** CLI entry: parse env, then run one cycle (`once`) or loop until a termination signal (`loop`). */\nexport async function main(env: Record<string, string | undefined> = process.env): Promise<void> {\n const config = parseConfig(env);\n const deps = localFsDeps(\n config.root,\n env.CR_COMPACT_METRICS === '1' ? stdoutMetricsSink() : undefined,\n );\n\n if (config.mode === 'once') {\n const cycle = await runOnce(deps, config);\n log({\n event: 'cycle',\n mode: 'once',\n candidates: cycle.candidates,\n compacted: cycle.compacted,\n deferred: cycle.deferred,\n results: cycle.results,\n });\n return;\n }\n\n // loop mode: run forever, one cycle per interval, until SIGINT/SIGTERM.\n let stop = false;\n const onSignal = (): void => {\n stop = true;\n };\n process.on('SIGINT', onSignal);\n process.on('SIGTERM', onSignal);\n log({ event: 'start', mode: 'loop', intervalMs: config.intervalMs, owner: config.owner });\n while (!stop) {\n try {\n const cycle = await runOnce(deps, config);\n log({\n event: 'cycle',\n candidates: cycle.candidates,\n compacted: cycle.compacted,\n deferred: cycle.deferred,\n results: cycle.results,\n });\n } catch (err) {\n log({ event: 'error', message: (err as Error).message }); // a cycle error must not kill the daemon\n }\n if (!stop) await sleep(config.intervalMs);\n }\n log({ event: 'stopped' });\n}\n\n// Run only when invoked directly (not when imported by tests). `process.argv[1]` is this file when run as a bin;\n// `pathToFileURL` builds a spec-correct file:// URL (drive letters, spaces, UNC paths) for a robust compare.\nif (process.argv[1] !== undefined && import.meta.url === pathToFileURL(process.argv[1]).href) {\n main().catch((err: unknown) => {\n process.stderr.write(`${(err as Error).message}\\n`);\n process.exit(1);\n });\n}\n"]}
|
package/dist/cassandra/index.cjs
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var cassandra = require('@cloudbitmaps/core/cassandra');
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Object.keys(cassandra).forEach(function (k) {
|
|
8
|
-
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
9
|
-
enumerable: true,
|
|
10
|
-
get: function () { return cassandra[k]; }
|
|
11
|
-
});
|
|
12
|
-
});
|
|
13
|
-
//# sourceMappingURL=index.cjs.map
|
|
14
|
-
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.cjs","sourcesContent":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from '@cloudbitmaps/core/cassandra';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from '@cloudbitmaps/core/cassandra';
|
package/dist/cassandra/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js","sourcesContent":[]}
|