@kanzo-tech/mosaic 0.8.0 → 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/README.md +16 -0
- package/dist/arrow.js +58 -26
- package/dist/arrow.js.map +1 -1
- package/dist/engine.d.ts +16 -4
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +101 -36
- package/dist/engine.js.map +1 -1
- package/dist/id-set-client.d.ts +3 -3
- package/dist/id-set-client.js +34 -42
- package/dist/id-set-client.js.map +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +35 -31
- package/dist/index.js.map +1 -1
- package/extensions/wasm_eh/httpfs.duckdb_extension.wasm +0 -0
- package/extensions/wasm_mvp/httpfs.duckdb_extension.wasm +0 -0
- package/package.json +9 -3
package/README.md
CHANGED
|
@@ -25,6 +25,22 @@ import { engine } from "@kanzo-tech/mosaic";
|
|
|
25
25
|
DuckDB-WASM's `File already registered` was refusing. `hold(name, bytes)` registers a copy of a
|
|
26
26
|
buffer; `drop(names)` forgets. It is fossil's `Engine` structurally, without depending on fossil.
|
|
27
27
|
|
|
28
|
+
It boots with DuckDB's `httpfs` loaded, so `s3://` is readable once a secret says how:
|
|
29
|
+
`query("CREATE OR REPLACE SECRET job (TYPE s3, …, SCOPE 's3://bucket/prefix/')")`, then name the
|
|
30
|
+
objects by their URLs. A lent name has no scheme: `https://…` and `s3://…` in SQL are `httpfs`'s,
|
|
31
|
+
and it answers before the registry is asked.
|
|
32
|
+
|
|
33
|
+
**Nothing is fetched from a CDN.** DuckDB-WASM's worker and module come from
|
|
34
|
+
`@duckdb/duckdb-wasm`, a dependency at the exact release `httpfs` was built for; `httpfs` ships in
|
|
35
|
+
this package (`extensions/`, fetched and hash-pinned at build by `scripts/extensions.mjs`). All
|
|
36
|
+
three are reached through `new URL(…, import.meta.url)`, so your bundler emits them as assets —
|
|
37
|
+
under Next, `/_next/static/media/duckdb-browser-eh.worker.<hash>.js`, `duckdb-eh.<hash>.wasm` and
|
|
38
|
+
`httpfs.duckdb_extension.<hash>.wasm`, or their `mvp` siblings on a browser without WebAssembly
|
|
39
|
+
exceptions — and there is nothing to copy. Serve `.wasm` as `application/wasm` (Next does), and
|
|
40
|
+
the page needs no origin but yours:
|
|
41
|
+
`script-src 'self' 'wasm-unsafe-eval'; worker-src 'self'; connect-src 'self' <your storage>`. No
|
|
42
|
+
`blob:`: the worker is started from its own URL.
|
|
43
|
+
|
|
28
44
|
- **Re-exports** of the coordinator, the clients, the five clause builders and the loaders — so a
|
|
29
45
|
consumer never needs a direct `@uwdata` import. The DuckDB-WASM connector is not among them:
|
|
30
46
|
`engine()` is the only boot.
|
package/dist/arrow.js
CHANGED
|
@@ -1,29 +1,61 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Reading one column out of whatever a Mosaic query handed back.
|
|
3
|
+
*
|
|
4
|
+
* The coordinator answers with an Arrow table, and Arrow only offers a typed column when the type
|
|
5
|
+
* allows one: `getChild` gives an array for an integer column and nothing usable for a
|
|
6
|
+
* dictionary-encoded string. Both shapes come back from ordinary queries — an `id` is the first, a
|
|
7
|
+
* `label` is the second — so a `queryResult` that assumes the typed path is a crash waiting for the
|
|
8
|
+
* first query that selects a string.
|
|
9
|
+
*
|
|
10
|
+
* This is the half of the client protocol the protocol itself does not give you. Declaring a query
|
|
11
|
+
* and publishing a clause is documented and small; turning the answer into values is where every
|
|
12
|
+
* call site independently writes `as { getChild(name: string): … }`, which is a cast asserting the
|
|
13
|
+
* shape rather than checking it.
|
|
14
|
+
*/
|
|
15
|
+
/** Every value in `field`, in row order. */
|
|
16
|
+
export function column(data, field) {
|
|
17
|
+
const child = data.getChild?.(field);
|
|
18
|
+
if (child)
|
|
19
|
+
return Array.from(child.toArray());
|
|
20
|
+
return Array.from(data, (row) => row[field]);
|
|
5
21
|
}
|
|
6
|
-
|
|
7
|
-
|
|
22
|
+
/** The same, coerced — Arrow hands back `BigInt` for some integer widths. */
|
|
23
|
+
export function numbers(data, field) {
|
|
24
|
+
return column(data, field).map(Number);
|
|
8
25
|
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
26
|
+
/**
|
|
27
|
+
* One numeric column, written straight into a typed array the caller already owns.
|
|
28
|
+
*
|
|
29
|
+
* `numbers()` is the wrong tool once a result is large: `toArray()` already hands back a typed
|
|
30
|
+
* buffer, and `Array.from(...).map(Number)` turns it into two full-length boxed `number[]` on the
|
|
31
|
+
* way to a third array that was the actual destination. Three allocations to move nothing. This is
|
|
32
|
+
* the same pass with none of them — which is what lets a caller size once against its own limit and
|
|
33
|
+
* fill from the Arrow batches as they arrive.
|
|
34
|
+
*
|
|
35
|
+
* `stride` and `offset` are how interleaving is expressed: `x` at `(0, 2)` and `y` at `(1, 2)` fill
|
|
36
|
+
* one `[x0, y0, x1, y1, …]` buffer with no seam between them.
|
|
37
|
+
*
|
|
38
|
+
* Returns how many rows were written, which is `min(rows, capacity)` — a caller that sized against
|
|
39
|
+
* a `LIMIT` uses it to `subarray` down to what actually came back.
|
|
40
|
+
*/
|
|
41
|
+
export function fillColumn(data, field, into, offset = 0, stride = 1) {
|
|
42
|
+
const capacity = Math.max(0, Math.ceil((into.length - offset) / stride));
|
|
43
|
+
const values = data.getChild?.(field)?.toArray();
|
|
44
|
+
if (values) {
|
|
45
|
+
const n = Math.min(values.length, capacity);
|
|
46
|
+
// `Number` is identity on the numeric widths and the conversion on the BigInt ones; either way
|
|
47
|
+
// it reads an element rather than allocating one.
|
|
48
|
+
for (let i = 0; i < n; i++)
|
|
49
|
+
into[offset + i * stride] = Number(values[i]);
|
|
50
|
+
return n;
|
|
51
|
+
}
|
|
52
|
+
let i = 0;
|
|
53
|
+
for (const row of data) {
|
|
54
|
+
if (i >= capacity)
|
|
55
|
+
break;
|
|
56
|
+
into[offset + i * stride] = Number(row[field]);
|
|
57
|
+
i++;
|
|
58
|
+
}
|
|
59
|
+
return i;
|
|
23
60
|
}
|
|
24
|
-
|
|
25
|
-
b as column,
|
|
26
|
-
g as fillColumn,
|
|
27
|
-
y as numbers
|
|
28
|
-
};
|
|
29
|
-
//# sourceMappingURL=arrow.js.map
|
|
61
|
+
//# sourceMappingURL=arrow.js.map
|
package/dist/arrow.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"arrow.js","sources":["../src/arrow.ts"],"
|
|
1
|
+
{"version":3,"file":"arrow.js","sourceRoot":"","sources":["../src/arrow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAMH,4CAA4C;AAC5C,MAAM,UAAU,MAAM,CAAC,IAAa,EAAE,KAAa;IACjD,MAAM,KAAK,GAAI,IAAkB,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAC;IACpD,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IAC9C,OAAO,KAAK,CAAC,IAAI,CAAC,IAAyC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;AACpF,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,OAAO,CAAC,IAAa,EAAE,KAAa;IAClD,OAAO,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AACzC,CAAC;AAKD;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,UAAU,CACxB,IAAa,EACb,KAAa,EACb,IAAkB,EAClB,MAAM,GAAG,CAAC,EACV,MAAM,GAAG,CAAC;IAEV,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;IACzE,MAAM,MAAM,GAAI,IAAkB,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC;IAChE,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC5C,+FAA+F;QAC/F,kDAAkD;QAClD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;YAAE,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1E,OAAO,CAAC,CAAC;IACX,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,KAAK,MAAM,GAAG,IAAI,IAAyC,EAAE,CAAC;QAC5D,IAAI,CAAC,IAAI,QAAQ;YAAE,MAAM;QACzB,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;QAC/C,CAAC,EAAE,CAAC;IACN,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC"}
|
package/dist/engine.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Coordinator } from
|
|
1
|
+
import { Coordinator } from "@uwdata/mosaic-core";
|
|
2
2
|
/**
|
|
3
3
|
* The page's one database: a DuckDB-WASM instance, the Mosaic `Coordinator` over it, and the file
|
|
4
4
|
* registry, owned in one place.
|
|
@@ -15,14 +15,26 @@ import { Coordinator } from '@uwdata/mosaic-core';
|
|
|
15
15
|
* the old lease and registers the new. That indirection is also why the registry is kept rather than
|
|
16
16
|
* reading `https://…` directly — a view names a stable file, and only the lease behind it rotates.
|
|
17
17
|
*
|
|
18
|
-
* It
|
|
19
|
-
*
|
|
18
|
+
* **It reads `s3://` from boot.** DuckDB's `httpfs` is loaded before the engine is handed out, so a
|
|
19
|
+
* reader that holds a credential scoped to a prefix makes it readable with one statement through
|
|
20
|
+
* `query` — `CREATE OR REPLACE SECRET … (TYPE s3, …, SCOPE 's3://bucket/prefix/')` — and names the
|
|
21
|
+
* objects by their own URLs. There is no method for it: the secret is SQL, and `query` is the door.
|
|
22
|
+
*
|
|
23
|
+
* **Nothing is fetched from a CDN.** DuckDB-WASM's worker and module and its `httpfs` are named with
|
|
24
|
+
* `new URL(…, import.meta.url)`, so the host's bundler emits them as assets and the page loads all of
|
|
25
|
+
* it from its own origin: `script-src 'self'`, `worker-src 'self'` and `connect-src 'self' <storage>`.
|
|
26
|
+
*
|
|
27
|
+
* It satisfies fossil's `Engine` structurally; this package does not depend on fossil.
|
|
20
28
|
*/
|
|
21
29
|
export interface Engine {
|
|
22
30
|
readonly coordinator: Coordinator;
|
|
23
31
|
/** Rows as objects, uncached: a read after a `lend` must see the new lease. */
|
|
24
32
|
query(sql: string): Promise<Record<string, unknown>[]>;
|
|
25
|
-
/**
|
|
33
|
+
/**
|
|
34
|
+
* name → URL. The same URL is a no-op; a different one replaces the lease. The name has no scheme:
|
|
35
|
+
* with `httpfs` loaded, `https://…` or `s3://…` in SQL is read by `httpfs` before the registry is
|
|
36
|
+
* asked, so a lease under such a name is never consulted.
|
|
37
|
+
*/
|
|
26
38
|
lend(files: Record<string, string>): Promise<void>;
|
|
27
39
|
/** Registers a copy of `bytes` under `name`, replacing whatever was there. */
|
|
28
40
|
hold(name: string, bytes: Uint8Array): Promise<void>;
|
package/dist/engine.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAiB,MAAM,qBAAqB,CAAC;AAEjE;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,+EAA+E;IAC/E,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;IACvD;;;;OAIG;IACH,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,8EAA8E;IAC9E,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,8EAA8E;IAC9E,IAAI,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/C;AA4GD,kDAAkD;AAClD,wBAAgB,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,CAIxC"}
|
package/dist/engine.js
CHANGED
|
@@ -1,38 +1,103 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
1
|
+
import { AsyncDuckDB, DuckDBDataProtocol, VoidLogger, selectBundle } from "@duckdb/duckdb-wasm";
|
|
2
|
+
import { Coordinator, wasmConnector } from "@uwdata/mosaic-core";
|
|
3
|
+
/**
|
|
4
|
+
* DuckDB-WASM >= 1.30 downloads a lent file whole unless full reads are refused outright: its range
|
|
5
|
+
* probe reads `Content-Length` where it meant `Content-Range` and falls through to a whole-file GET
|
|
6
|
+
* (duckdb/duckdb-wasm#2228). Refused, it reaches its `HEAD` fallback and reads by range. Measured on
|
|
7
|
+
* a 160 MiB Parquet file, a count, a point lookup and a max: 1.3 MiB in eight ranges with this, the
|
|
8
|
+
* whole file in one GET without it.
|
|
9
|
+
*
|
|
10
|
+
* It governs `lend` alone. `s3://` and a URL named in SQL go through `httpfs`, which reads by range
|
|
11
|
+
* either way (the same queries: 1.8 MiB in four requests, flag or not). What still lends is a store
|
|
12
|
+
* DuckDB-WASM has no extension for — Azure, reached by a SAS URL — and that is a URL which answers
|
|
13
|
+
* `HEAD`, which the fallback needs.
|
|
14
|
+
*/
|
|
15
|
+
const RANGE_READS = { filesystem: { forceFullHTTPReads: false } };
|
|
16
|
+
/** Absolute, against the page: webpack under Next hands back a root-relative URL. */
|
|
17
|
+
const served = (asset) => new URL(asset.href, location.href).href;
|
|
18
|
+
/**
|
|
19
|
+
* One build per bundle `selectBundle` chooses between, each with the `httpfs` built for it. The worker
|
|
20
|
+
* and module are `@duckdb/duckdb-wasm`'s own, the release this package pins, named by specifier as
|
|
21
|
+
* DuckDB-WASM documents for webpack: the bundler resolves it to that dependency. `httpfs` is not on npm,
|
|
22
|
+
* so `scripts/extensions.mjs` fetches the pinned builds into `extensions/` and the tarball carries
|
|
23
|
+
* them. It is `LOAD`ed by URL, which DuckDB accepts under a hashed file name as long as the name still
|
|
24
|
+
* starts `httpfs.` — the entrypoint is looked up by that prefix.
|
|
25
|
+
*/
|
|
26
|
+
function builds() {
|
|
27
|
+
return {
|
|
28
|
+
mvp: {
|
|
29
|
+
mainModule: served(new URL("@duckdb/duckdb-wasm/dist/duckdb-mvp.wasm", import.meta.url)),
|
|
30
|
+
mainWorker: served(new URL("@duckdb/duckdb-wasm/dist/duckdb-browser-mvp.worker.js", import.meta.url)),
|
|
31
|
+
httpfs: served(new URL("../extensions/wasm_mvp/httpfs.duckdb_extension.wasm", import.meta.url)),
|
|
32
|
+
},
|
|
33
|
+
eh: {
|
|
34
|
+
mainModule: served(new URL("@duckdb/duckdb-wasm/dist/duckdb-eh.wasm", import.meta.url)),
|
|
35
|
+
mainWorker: served(new URL("@duckdb/duckdb-wasm/dist/duckdb-browser-eh.worker.js", import.meta.url)),
|
|
36
|
+
httpfs: served(new URL("../extensions/wasm_eh/httpfs.duckdb_extension.wasm", import.meta.url)),
|
|
37
|
+
},
|
|
38
|
+
};
|
|
29
39
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
40
|
+
/** A buffer is not a URL, so a held name never compares equal to a lent one. */
|
|
41
|
+
const HELD = Symbol("held");
|
|
42
|
+
async function boot() {
|
|
43
|
+
const all = builds();
|
|
44
|
+
const { mainModule } = await selectBundle(all);
|
|
45
|
+
const build = mainModule === all.eh.mainModule ? all.eh : all.mvp;
|
|
46
|
+
const duckdb = new AsyncDuckDB(new VoidLogger(), new Worker(build.mainWorker));
|
|
47
|
+
await duckdb.instantiate(build.mainModule);
|
|
48
|
+
const connector = wasmConnector({ duckdb, config: RANGE_READS });
|
|
49
|
+
const coordinator = new Coordinator(connector);
|
|
50
|
+
await coordinator.exec(`LOAD '${build.httpfs}'`);
|
|
51
|
+
// Files are read lazily by range; caching their metadata is what keeps a pan from re-probing.
|
|
52
|
+
await coordinator.exec("SET enable_http_metadata_cache = true");
|
|
53
|
+
const behind = new Map();
|
|
54
|
+
// Registry changes run one at a time: two `lend`s of one name racing each other would each see the
|
|
55
|
+
// old entry, and the second register would be refused.
|
|
56
|
+
let tail = Promise.resolve();
|
|
57
|
+
const serial = (step) => {
|
|
58
|
+
const run = tail.then(step);
|
|
59
|
+
tail = run.catch(() => { });
|
|
60
|
+
return run;
|
|
61
|
+
};
|
|
62
|
+
const release = async (name) => {
|
|
63
|
+
if (!behind.has(name))
|
|
64
|
+
return;
|
|
65
|
+
await duckdb.dropFile(name);
|
|
66
|
+
behind.delete(name);
|
|
67
|
+
};
|
|
68
|
+
return {
|
|
69
|
+
coordinator,
|
|
70
|
+
query: (sql) => coordinator.query(sql, { type: "json", cache: false }),
|
|
71
|
+
lend: (files) => serial(async () => {
|
|
72
|
+
for (const [name, url] of Object.entries(files)) {
|
|
73
|
+
if (behind.get(name) === url)
|
|
74
|
+
continue;
|
|
75
|
+
await release(name);
|
|
76
|
+
await duckdb.registerFileURL(name, url, DuckDBDataProtocol.HTTP, false);
|
|
77
|
+
behind.set(name, url);
|
|
78
|
+
}
|
|
79
|
+
}),
|
|
80
|
+
hold: (name, bytes) => serial(async () => {
|
|
81
|
+
await release(name);
|
|
82
|
+
// A copy, because DuckDB-WASM transfers the buffer to its worker and detaches the caller's.
|
|
83
|
+
await duckdb.registerFileBuffer(name, bytes.slice());
|
|
84
|
+
behind.set(name, HELD);
|
|
85
|
+
}),
|
|
86
|
+
drop: (names) => serial(async () => {
|
|
87
|
+
for (const name of names)
|
|
88
|
+
await release(name);
|
|
89
|
+
}),
|
|
90
|
+
};
|
|
34
91
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
92
|
+
/**
|
|
93
|
+
* Keyed on the document's global rather than on this module, so two copies of the package in one
|
|
94
|
+
* bundle still share one database — which is the invariant, not the module identity.
|
|
95
|
+
*/
|
|
96
|
+
const KEY = Symbol.for("@kanzo-tech/mosaic/engine");
|
|
97
|
+
/** The page's one engine, booted on first ask. */
|
|
98
|
+
export function engine() {
|
|
99
|
+
const scope = globalThis;
|
|
100
|
+
scope[KEY] ??= boot();
|
|
101
|
+
return scope[KEY];
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=engine.js.map
|
package/dist/engine.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.js","sources":["../src/engine.ts"],"
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
|
package/dist/id-set-client.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { MosaicClient, Selection } from
|
|
2
|
-
import { FilterExpr } from
|
|
1
|
+
import { MosaicClient, type Selection } from "@uwdata/mosaic-core";
|
|
2
|
+
import { type FilterExpr } from "@uwdata/mosaic-sql";
|
|
3
3
|
/**
|
|
4
4
|
* The crossfilter adapter for a view whose positions are not in the database.
|
|
5
5
|
*
|
|
@@ -34,7 +34,7 @@ export interface IdSetClientOptions {
|
|
|
34
34
|
export declare class IdSetClient extends MosaicClient {
|
|
35
35
|
#private;
|
|
36
36
|
constructor(options: IdSetClientOptions);
|
|
37
|
-
query(filter?: FilterExpr): import(
|
|
37
|
+
query(filter?: FilterExpr): import("@uwdata/mosaic-sql").SelectQuery;
|
|
38
38
|
queryResult(data: unknown): this;
|
|
39
39
|
/** `null` retracts the selection: an empty clause has a null predicate, which the resolver drops. */
|
|
40
40
|
publish(ids: readonly unknown[] | null): void;
|
package/dist/id-set-client.js
CHANGED
|
@@ -1,43 +1,35 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
};
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
clients: /* @__PURE__ */ new Set()
|
|
35
|
-
})
|
|
36
|
-
);
|
|
37
|
-
}
|
|
1
|
+
import { MosaicClient, clausePoints } from "@uwdata/mosaic-core";
|
|
2
|
+
import { Query } from "@uwdata/mosaic-sql";
|
|
3
|
+
import { column } from "./arrow.js";
|
|
4
|
+
export class IdSetClient extends MosaicClient {
|
|
5
|
+
#table;
|
|
6
|
+
#idField;
|
|
7
|
+
#as;
|
|
8
|
+
#emit;
|
|
9
|
+
constructor(options) {
|
|
10
|
+
super(options.filterBy);
|
|
11
|
+
this.#table = options.table;
|
|
12
|
+
this.#idField = options.idField;
|
|
13
|
+
this.#as = options.as;
|
|
14
|
+
this.#emit = options.onSurvivors;
|
|
15
|
+
}
|
|
16
|
+
query(filter = []) {
|
|
17
|
+
return Query.from(this.#table).select({ id: this.#idField }).where(filter);
|
|
18
|
+
}
|
|
19
|
+
queryResult(data) {
|
|
20
|
+
this.#emit(column(data, "id"));
|
|
21
|
+
return this;
|
|
22
|
+
}
|
|
23
|
+
/** `null` retracts the selection: an empty clause has a null predicate, which the resolver drops. */
|
|
24
|
+
publish(ids) {
|
|
25
|
+
this.#as.update(clausePoints([this.#idField], ids?.map((id) => [id]), {
|
|
26
|
+
source: this,
|
|
27
|
+
// A crossfilter normally exempts a client from its own clause, so a brush can be widened
|
|
28
|
+
// after it has collapsed the chart under it. A view that FADES an excluded row instead of
|
|
29
|
+
// removing it does not need the exemption: the row is still on screen and still
|
|
30
|
+
// selectable. Declining it is what makes the selection visible — the fade is the brush.
|
|
31
|
+
clients: new Set(),
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
38
34
|
}
|
|
39
|
-
|
|
40
|
-
export {
|
|
41
|
-
w as IdSetClient
|
|
42
|
-
};
|
|
43
|
-
//# sourceMappingURL=id-set-client.js.map
|
|
35
|
+
//# sourceMappingURL=id-set-client.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"id-set-client.js","sources":["../src/id-set-client.ts"],"
|
|
1
|
+
{"version":3,"file":"id-set-client.js","sourceRoot":"","sources":["../src/id-set-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAkB,MAAM,qBAAqB,CAAC;AACjF,OAAO,EAAE,KAAK,EAAmB,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAmCpC,MAAM,OAAO,WAAY,SAAQ,YAAY;IAC3C,MAAM,CAAS;IACf,QAAQ,CAAS;IACjB,GAAG,CAAY;IACf,KAAK,CAAoC;IAEzC,YAAY,OAA2B;QACrC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACxB,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;QAC5B,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;QAChC,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,EAAE,CAAC;QACtB,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,WAAW,CAAC;IACnC,CAAC;IAEQ,KAAK,CAAC,SAAqB,EAAE;QACpC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC7E,CAAC;IAEQ,WAAW,CAAC,IAAa;QAChC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QAC/B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,qGAAqG;IACrG,OAAO,CAAC,GAA8B;QACpC,IAAI,CAAC,GAAG,CAAC,MAAM,CACb,YAAY,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;YACpD,MAAM,EAAE,IAAI;YACZ,yFAAyF;YACzF,0FAA0F;YAC1F,gFAAgF;YAChF,wFAAwF;YACxF,OAAO,EAAE,IAAI,GAAG,EAAgB;SACjC,CAAC,CACH,CAAC;IACJ,CAAC;CACF"}
|
package/dist/index.d.ts
CHANGED
|
@@ -20,16 +20,16 @@
|
|
|
20
20
|
* `Selection` is what makes one copy of Mosaic the easy outcome, and two copies would be two
|
|
21
21
|
* crossfilters that never hear each other.
|
|
22
22
|
*/
|
|
23
|
-
export { Coordinator, MosaicClient, Selection, makeClient, clausePoint, clausePoints, clauseInterval, clauseIntervals, clauseMatch, type SelectionClause, } from
|
|
24
|
-
export { Query, asc, desc, loadCSV, loadJSON, loadObjects, loadParquet, loadSpatial, loadExtension, type ExprValue, type FilterExpr, } from
|
|
23
|
+
export { Coordinator, MosaicClient, Selection, makeClient, clausePoint, clausePoints, clauseInterval, clauseIntervals, clauseMatch, type SelectionClause, } from "@uwdata/mosaic-core";
|
|
24
|
+
export { Query, asc, desc, loadCSV, loadJSON, loadObjects, loadParquet, loadSpatial, loadExtension, type ExprValue, type FilterExpr, } from "@uwdata/mosaic-sql";
|
|
25
25
|
/** Ours: turning an Arrow answer into values, which the client protocol does not do for you. */
|
|
26
|
-
export { column, fillColumn, numbers, type NumericArray } from
|
|
26
|
+
export { column, fillColumn, numbers, type NumericArray } from "./arrow.js";
|
|
27
27
|
/** Ours: the crossfilter adapter for a view whose positions are not in the database. */
|
|
28
|
-
export { IdSetClient, type IdSetClientOptions } from
|
|
28
|
+
export { IdSetClient, type IdSetClientOptions } from "./id-set-client.js";
|
|
29
29
|
/**
|
|
30
30
|
* Ours: the page's one DuckDB-WASM engine — the coordinator and the file registry beside it. It is
|
|
31
31
|
* the only door to `wasmConnector`, which is why that is no longer re-exported: a second boot is a
|
|
32
32
|
* second database, and every host that wrote its own boot also wrote its own registry policy.
|
|
33
33
|
*/
|
|
34
|
-
export { engine, type Engine } from
|
|
34
|
+
export { engine, type Engine } from "./engine.js";
|
|
35
35
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,31 +1,35 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
1
|
+
/**
|
|
2
|
+
* The Mosaic conversation, as one import.
|
|
3
|
+
*
|
|
4
|
+
* This package exists because of a bug that shipped. `@kanzo-tech/graph/duckdb` reached its
|
|
5
|
+
* coordinator, clients and clauses through `@kanzo-tech/ui/analytics`, whose barrel re-exports the
|
|
6
|
+
* React charts first — and `@uwdata/vgplot` with them. The import is static, so a host that
|
|
7
|
+
* installed the two peers the documentation asked for, `mosaic-core` and `mosaic-sql`, still could
|
|
8
|
+
* not open the subpath: vgplot came along, unasked and unused. `@kanzo-tech/graph` ended up
|
|
9
|
+
* declaring vgplot as an optional peer to paper over a dependency it never names.
|
|
10
|
+
*
|
|
11
|
+
* The cause was a layer in the wrong package rather than a missing entry in a list. Reading a
|
|
12
|
+
* column out of an Arrow answer and publishing a points clause are not user-interface concerns;
|
|
13
|
+
* they were only in a component library because that is where the first chart needed them.
|
|
14
|
+
*
|
|
15
|
+
* So: the data half lives here, with no React anywhere in it, and both consumers depend on this
|
|
16
|
+
* rather than on each other. `@kanzo-tech/ui/analytics` keeps every chart and re-exports these
|
|
17
|
+
* names unchanged, so nothing on that surface moves.
|
|
18
|
+
*
|
|
19
|
+
* The re-exports below are deliberate rather than lazy. A single import site for `Coordinator` and
|
|
20
|
+
* `Selection` is what makes one copy of Mosaic the easy outcome, and two copies would be two
|
|
21
|
+
* crossfilters that never hear each other.
|
|
22
|
+
*/
|
|
23
|
+
export { Coordinator, MosaicClient, Selection, makeClient, clausePoint, clausePoints, clauseInterval, clauseIntervals, clauseMatch, } from "@uwdata/mosaic-core";
|
|
24
|
+
export { Query, asc, desc, loadCSV, loadJSON, loadObjects, loadParquet, loadSpatial, loadExtension, } from "@uwdata/mosaic-sql";
|
|
25
|
+
/** Ours: turning an Arrow answer into values, which the client protocol does not do for you. */
|
|
26
|
+
export { column, fillColumn, numbers } from "./arrow.js";
|
|
27
|
+
/** Ours: the crossfilter adapter for a view whose positions are not in the database. */
|
|
28
|
+
export { IdSetClient } from "./id-set-client.js";
|
|
29
|
+
/**
|
|
30
|
+
* Ours: the page's one DuckDB-WASM engine — the coordinator and the file registry beside it. It is
|
|
31
|
+
* the only door to `wasmConnector`, which is why that is no longer re-exported: a second boot is a
|
|
32
|
+
* second database, and every host that wrote its own boot also wrote its own registry policy.
|
|
33
|
+
*/
|
|
34
|
+
export { engine } from "./engine.js";
|
|
35
|
+
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EACL,WAAW,EACX,YAAY,EACZ,SAAS,EACT,UAAU,EACV,WAAW,EACX,YAAY,EACZ,cAAc,EACd,eAAe,EACf,WAAW,GAEZ,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,KAAK,EACL,GAAG,EACH,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,WAAW,EACX,WAAW,EACX,WAAW,EACX,aAAa,GAGd,MAAM,oBAAoB,CAAC;AAE5B,gGAAgG;AAChG,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAqB,MAAM,YAAY,CAAC;AAE5E,wFAAwF;AACxF,OAAO,EAAE,WAAW,EAA2B,MAAM,oBAAoB,CAAC;AAE1E;;;;GAIG;AACH,OAAO,EAAE,MAAM,EAAe,MAAM,aAAa,CAAC"}
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kanzo-tech/mosaic",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "The Mosaic conversation, without React — coordinator, clients and clauses re-exported as one surface, plus the Arrow column reader and the id-set client that every consumer of them was writing by hand.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"sideEffects": false,
|
|
8
8
|
"files": [
|
|
9
9
|
"dist",
|
|
10
|
+
"extensions",
|
|
10
11
|
"README.md"
|
|
11
12
|
],
|
|
12
13
|
"module": "./dist/index.js",
|
|
@@ -18,7 +19,12 @@
|
|
|
18
19
|
},
|
|
19
20
|
"./package.json": "./package.json"
|
|
20
21
|
},
|
|
21
|
-
"//
|
|
22
|
+
"//dependencies": "@duckdb/duckdb-wasm is a dependency, exact, not a peer. `engine()` names its worker and module as `new URL(\"@duckdb/duckdb-wasm/dist/…\", import.meta.url)` — the spelling DuckDB-WASM documents for webpack — so the host's bundler emits them from this package's own copy, and they must be the release the JavaScript driving them comes from and the one the pinned httpfs was built for. A range, or a peer the host resolves, would let the three drift. It is also the release mosaic-core pins, so the tree holds one copy; `scripts/extensions.test.mjs` fails when either moves.",
|
|
23
|
+
"//peers": "mosaic-core and mosaic-sql are REQUIRED, not optional, and that is the whole point of this package: there is nothing here without them, so a host installs them once and both @kanzo-tech/ui/analytics and @kanzo-tech/graph/duckdb see the same coordinator. Two copies would be two crossfilters. @uwdata/vgplot is deliberately absent — it is a plotting library, it belongs to the charts in @kanzo-tech/ui, and its accidental presence on this path is exactly the bug this package exists to end. The two ranges differ — mosaic-core ^0.29.2, mosaic-sql ^0.29.0 — and that is not drift: mosaic-sql published exactly one release in the 0.29 line, so ^0.29.2 does not resolve. Each range names the newest patch that exists.",
|
|
24
|
+
"//build": "tsc, not Vite, and the reason is the `new URL(…, import.meta.url)` lines of src/engine.ts. Those expressions have to reach the HOST's bundler verbatim, which is what makes DuckDB's worker, module and httpfs assets of the host's page. Vite's library mode inlines every asset it resolves, and it resolved the extension into a 1,088 kB engine.js of base64; `?no-inline` emitted it instead, but under a root-absolute URL and renamed `httpfs2.…`, and DuckDB looks up an extension's entrypoint by the file name's first segment. Nothing here needed Vite: no JSX, no CSS, no directive, and nothing to bundle, since every import is a package the host resolves. `extensions/` sits beside `dist/` rather than inside it for the same line: `../extensions` resolves identically from `src/` and from `dist/`, so the test and the tarball read the same path.",
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@duckdb/duckdb-wasm": "1.33.1-dev57.0"
|
|
27
|
+
},
|
|
22
28
|
"peerDependencies": {
|
|
23
29
|
"@uwdata/mosaic-core": "^0.29.2",
|
|
24
30
|
"@uwdata/mosaic-sql": "^0.29.0"
|
|
@@ -37,7 +43,7 @@
|
|
|
37
43
|
"url": "https://github.com/Kanzo-Tech/ui/issues"
|
|
38
44
|
},
|
|
39
45
|
"scripts": {
|
|
40
|
-
"build": "
|
|
46
|
+
"build": "node scripts/extensions.mjs && rm -rf dist && tsc -p tsconfig.build.json",
|
|
41
47
|
"typecheck": "tsc --noEmit",
|
|
42
48
|
"test": "vitest run"
|
|
43
49
|
}
|