@kanzo-tech/mosaic 0.1.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 ADDED
@@ -0,0 +1,42 @@
1
+ # @kanzo-tech/mosaic
2
+
3
+ The Mosaic conversation, without React.
4
+
5
+ ```bash
6
+ npm install @kanzo-tech/mosaic @uwdata/mosaic-core @uwdata/mosaic-sql
7
+ ```
8
+
9
+ `mosaic-core` and `mosaic-sql` are **required** peers, not optional ones. There is nothing here
10
+ without them — that is what this package is. Installing them once is also the point: two copies of
11
+ Mosaic are two coordinators, and two coordinators are two crossfilters that never hear each other.
12
+
13
+ ## What it holds
14
+
15
+ ```ts
16
+ import { Coordinator, Selection, MosaicClient, clausePoints } from "@kanzo-tech/mosaic";
17
+ import { column, fillColumn, numbers, IdSetClient } from "@kanzo-tech/mosaic";
18
+ ```
19
+
20
+ - **Re-exports** of the coordinator, the clients, the five clause builders, the loaders and the
21
+ connector — so a consumer boots a coordinator without a direct `@uwdata` import.
22
+ - **`column` / `fillColumn` / `numbers`** — the half of the client protocol the protocol does not
23
+ give you. The coordinator answers with an Arrow table, and Arrow offers a typed column only when
24
+ the type allows one: an integer id gives an array, a dictionary-encoded label gives nothing
25
+ usable. Every call site was writing `as { getChild(name: string): … }`, which asserts Arrow's
26
+ shape rather than checking it, and is wrong on the first query that selects a string.
27
+ - **`IdSetClient`** — the crossfilter adapter for a view whose positions are not in the database.
28
+ A GPU canvas or a map cannot publish `weight BETWEEN …`; there is no column to write the
29
+ predicate over. It can only enumerate what was hit.
30
+
31
+ ## Why it is not part of `@kanzo-tech/ui`
32
+
33
+ It was, and the cost landed somewhere else. `@kanzo-tech/graph/duckdb` reached its coordinator
34
+ through `@kanzo-tech/ui/analytics`, whose barrel re-exports the React charts first — and calls
35
+ `@uwdata/vgplot` doing it. The import is static, so a host that installed the two peers the docs
36
+ asked for still could not open that subpath: vgplot came along, unasked and unused.
37
+
38
+ Reading a column out of an answer and publishing a clause are not user-interface concerns. They
39
+ lived in a component library only because that is where the first chart needed them.
40
+
41
+ The charts did not move. [`@kanzo-tech/ui/analytics`](https://kanzo-tech.github.io/ui) exports
42
+ every name it exported before, these among them.
@@ -0,0 +1,37 @@
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 declare function column(data: unknown, field: string): unknown[];
17
+ /** The same, coerced — Arrow hands back `BigInt` for some integer widths. */
18
+ export declare function numbers(data: unknown, field: string): number[];
19
+ /** A pre-sized destination `fillColumn` can write into. */
20
+ export type NumericArray = Float32Array | Float64Array | Uint32Array | Uint16Array | Int32Array;
21
+ /**
22
+ * One numeric column, written straight into a typed array the caller already owns.
23
+ *
24
+ * `numbers()` is the wrong tool once a result is large: `toArray()` already hands back a typed
25
+ * buffer, and `Array.from(...).map(Number)` turns it into two full-length boxed `number[]` on the
26
+ * way to a third array that was the actual destination. Three allocations to move nothing. This is
27
+ * the same pass with none of them — which is what lets a caller size once against its own limit and
28
+ * fill from the Arrow batches as they arrive.
29
+ *
30
+ * `stride` and `offset` are how interleaving is expressed: `x` at `(0, 2)` and `y` at `(1, 2)` fill
31
+ * one `[x0, y0, x1, y1, …]` buffer with no seam between them.
32
+ *
33
+ * Returns how many rows were written, which is `min(rows, capacity)` — a caller that sized against
34
+ * a `LIMIT` uses it to `subarray` down to what actually came back.
35
+ */
36
+ export declare function fillColumn(data: unknown, field: string, into: NumericArray, offset?: number, stride?: number): number;
37
+ //# sourceMappingURL=arrow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arrow.d.ts","sourceRoot":"","sources":["../src/arrow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAMH,4CAA4C;AAC5C,wBAAgB,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE,CAI9D;AAED,6EAA6E;AAC7E,wBAAgB,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAE9D;AAED,2DAA2D;AAC3D,MAAM,MAAM,YAAY,GAAG,YAAY,GAAG,YAAY,GAAG,WAAW,GAAG,WAAW,GAAG,UAAU,CAAC;AAEhG;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,YAAY,EAClB,MAAM,SAAI,EACV,MAAM,SAAI,GACT,MAAM,CAiBR"}
package/dist/arrow.js ADDED
@@ -0,0 +1,29 @@
1
+ function b(r, n) {
2
+ var u;
3
+ const o = (u = r.getChild) == null ? void 0 : u.call(r, n);
4
+ return o ? Array.from(o.toArray()) : Array.from(r, (c) => c[n]);
5
+ }
6
+ function y(r, n) {
7
+ return b(r, n).map(Number);
8
+ }
9
+ function g(r, n, o, u = 0, c = 1) {
10
+ var h, f;
11
+ const i = Math.max(0, Math.ceil((o.length - u) / c)), t = (f = (h = r.getChild) == null ? void 0 : h.call(r, n)) == null ? void 0 : f.toArray();
12
+ if (t) {
13
+ const l = Math.min(t.length, i);
14
+ for (let m = 0; m < l; m++) o[u + m * c] = Number(t[m]);
15
+ return l;
16
+ }
17
+ let e = 0;
18
+ for (const l of r) {
19
+ if (e >= i) break;
20
+ o[u + e * c] = Number(l[n]), e++;
21
+ }
22
+ return e;
23
+ }
24
+ export {
25
+ b as column,
26
+ g as fillColumn,
27
+ y as numbers
28
+ };
29
+ //# sourceMappingURL=arrow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arrow.js","sources":["../src/arrow.ts"],"sourcesContent":["/**\n * Reading one column out of whatever a Mosaic query handed back.\n *\n * The coordinator answers with an Arrow table, and Arrow only offers a typed column when the type\n * allows one: `getChild` gives an array for an integer column and nothing usable for a\n * dictionary-encoded string. Both shapes come back from ordinary queries — an `id` is the first, a\n * `label` is the second — so a `queryResult` that assumes the typed path is a crash waiting for the\n * first query that selects a string.\n *\n * This is the half of the client protocol the protocol itself does not give you. Declaring a query\n * and publishing a clause is documented and small; turning the answer into values is where every\n * call site independently writes `as { getChild(name: string): … }`, which is a cast asserting the\n * shape rather than checking it.\n */\n\ninterface ArrowLike {\n getChild?: (name: string) => { toArray(): ArrayLike<unknown> } | null;\n}\n\n/** Every value in `field`, in row order. */\nexport function column(data: unknown, field: string): unknown[] {\n const child = (data as ArrowLike).getChild?.(field);\n if (child) return Array.from(child.toArray());\n return Array.from(data as Iterable<Record<string, unknown>>, (row) => row[field]);\n}\n\n/** The same, coerced — Arrow hands back `BigInt` for some integer widths. */\nexport function numbers(data: unknown, field: string): number[] {\n return column(data, field).map(Number);\n}\n\n/** A pre-sized destination `fillColumn` can write into. */\nexport type NumericArray = Float32Array | Float64Array | Uint32Array | Uint16Array | Int32Array;\n\n/**\n * One numeric column, written straight into a typed array the caller already owns.\n *\n * `numbers()` is the wrong tool once a result is large: `toArray()` already hands back a typed\n * buffer, and `Array.from(...).map(Number)` turns it into two full-length boxed `number[]` on the\n * way to a third array that was the actual destination. Three allocations to move nothing. This is\n * the same pass with none of them — which is what lets a caller size once against its own limit and\n * fill from the Arrow batches as they arrive.\n *\n * `stride` and `offset` are how interleaving is expressed: `x` at `(0, 2)` and `y` at `(1, 2)` fill\n * one `[x0, y0, x1, y1, …]` buffer with no seam between them.\n *\n * Returns how many rows were written, which is `min(rows, capacity)` — a caller that sized against\n * a `LIMIT` uses it to `subarray` down to what actually came back.\n */\nexport function fillColumn(\n data: unknown,\n field: string,\n into: NumericArray,\n offset = 0,\n stride = 1,\n): number {\n const capacity = Math.max(0, Math.ceil((into.length - offset) / stride));\n const values = (data as ArrowLike).getChild?.(field)?.toArray();\n if (values) {\n const n = Math.min(values.length, capacity);\n // `Number` is identity on the numeric widths and the conversion on the BigInt ones; either way\n // it reads an element rather than allocating one.\n for (let i = 0; i < n; i++) into[offset + i * stride] = Number(values[i]);\n return n;\n }\n let i = 0;\n for (const row of data as Iterable<Record<string, unknown>>) {\n if (i >= capacity) break;\n into[offset + i * stride] = Number(row[field]);\n i++;\n }\n return i;\n}\n"],"names":["column","data","field","_a","child","row","numbers","fillColumn","into","offset","stride","_b","capacity","values","n","i"],"mappings":"AAoBO,SAASA,EAAOC,GAAeC,GAA0B;AAAzD,MAAAC;AACL,QAAMC,KAASD,IAAAF,EAAmB,aAAnB,gBAAAE,EAAA,KAAAF,GAA8BC;AAC7C,SAAIE,IAAc,MAAM,KAAKA,EAAM,SAAS,IACrC,MAAM,KAAKH,GAA2C,CAACI,MAAQA,EAAIH,CAAK,CAAC;AAClF;AAGO,SAASI,EAAQL,GAAeC,GAAyB;AAC9D,SAAOF,EAAOC,GAAMC,CAAK,EAAE,IAAI,MAAM;AACvC;AAoBO,SAASK,EACdN,GACAC,GACAM,GACAC,IAAS,GACTC,IAAS,GACD;AAnCH,MAAAP,GAAAQ;AAoCL,QAAMC,IAAW,KAAK,IAAI,GAAG,KAAK,MAAMJ,EAAK,SAASC,KAAUC,CAAM,CAAC,GACjEG,KAAUF,KAAAR,IAAAF,EAAmB,aAAnB,gBAAAE,EAAA,KAAAF,GAA8BC,OAA9B,gBAAAS,EAAsC;AACtD,MAAIE,GAAQ;AACV,UAAMC,IAAI,KAAK,IAAID,EAAO,QAAQD,CAAQ;AAG1C,aAASG,IAAI,GAAGA,IAAID,GAAGC,IAAK,CAAAP,EAAKC,IAASM,IAAIL,CAAM,IAAI,OAAOG,EAAOE,CAAC,CAAC;AACxE,WAAOD;AAAA,EACT;AACA,MAAIC,IAAI;AACR,aAAWV,KAAOJ,GAA2C;AAC3D,QAAIc,KAAKH,EAAU;AACnB,IAAAJ,EAAKC,IAASM,IAAIL,CAAM,IAAI,OAAOL,EAAIH,CAAK,CAAC,GAC7Ca;AAAA,EACF;AACA,SAAOA;AACT;"}
@@ -0,0 +1,42 @@
1
+ import { MosaicClient, Selection } from '@uwdata/mosaic-core';
2
+ import { FilterExpr } from '@uwdata/mosaic-sql';
3
+ /**
4
+ * The crossfilter adapter for a view whose positions are not in the database.
5
+ *
6
+ * A `MosaicClient` asks for two things, and this is both:
7
+ *
8
+ * `query(filter)` — which rows survive the page's filters? The coordinator answers with a column
9
+ * of ids, and the view fades everything else. The **observable** half.
10
+ * `publish(ids)` — the user selected these. A points clause, `id IN (…)`, which every other chart
11
+ * on the page filters by. The **controllable** half.
12
+ *
13
+ * The id list is not a shortcut, it is the only thing such a view can say. A Plot brush publishes
14
+ * `weight BETWEEN …`, an interval in data space, because Plot's `x` IS a column. A GPU simulation's
15
+ * `x` exists nowhere in the database, so no predicate over columns can describe the loop the user
16
+ * drew. Enumerating what was hit is the honest translation — and its cost is the length of the `IN`
17
+ * list, which is the real ceiling on the whole approach.
18
+ *
19
+ * Nothing here knows what draws. It is named for what it exchanges rather than for the renderer it
20
+ * was first written against, because a canvas, a map and an imperative widget all reach the
21
+ * crossfilter through exactly this shape.
22
+ */
23
+ export interface IdSetClientOptions {
24
+ /** The relation. Its `idField` column is what gets published and matched. */
25
+ table: string;
26
+ idField: string;
27
+ /** What the view fades by. */
28
+ filterBy: Selection;
29
+ /** Where the selection publishes. */
30
+ as: Selection;
31
+ /** The surviving ids, in relation order, on every filter change. */
32
+ onSurvivors: (ids: readonly unknown[]) => void;
33
+ }
34
+ export declare class IdSetClient extends MosaicClient {
35
+ #private;
36
+ constructor(options: IdSetClientOptions);
37
+ query(filter?: FilterExpr): import('@uwdata/mosaic-sql').SelectQuery;
38
+ queryResult(data: unknown): this;
39
+ /** `null` retracts the selection: an empty clause has a null predicate, which the resolver drops. */
40
+ publish(ids: readonly unknown[] | null): void;
41
+ }
42
+ //# sourceMappingURL=id-set-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"id-set-client.d.ts","sourceRoot":"","sources":["../src/id-set-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAgB,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACjF,OAAO,EAAS,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAG5D;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,WAAW,kBAAkB;IACjC,6EAA6E;IAC7E,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,8BAA8B;IAC9B,QAAQ,EAAE,SAAS,CAAC;IACpB,qCAAqC;IACrC,EAAE,EAAE,SAAS,CAAC;IACd,oEAAoE;IACpE,WAAW,EAAE,CAAC,GAAG,EAAE,SAAS,OAAO,EAAE,KAAK,IAAI,CAAC;CAChD;AAED,qBAAa,WAAY,SAAQ,YAAY;;gBAM/B,OAAO,EAAE,kBAAkB;IAQ9B,KAAK,CAAC,MAAM,GAAE,UAAe;IAI7B,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;IAKzC,qGAAqG;IACrG,OAAO,CAAC,GAAG,EAAE,SAAS,OAAO,EAAE,GAAG,IAAI,GAAG,IAAI;CAY9C"}
@@ -0,0 +1,43 @@
1
+ var o = (t) => {
2
+ throw TypeError(t);
3
+ };
4
+ var n = (t, r, e) => r.has(t) || o("Cannot " + e);
5
+ var i = (t, r, e) => (n(t, r, "read from private field"), e ? e.call(t) : r.get(t)), l = (t, r, e) => r.has(t) ? o("Cannot add the same private member more than once") : r instanceof WeakSet ? r.add(t) : r.set(t, e), u = (t, r, e, c) => (n(t, r, "write to private field"), c ? c.call(t, e) : r.set(t, e), e);
6
+ import { MosaicClient as d, clausePoints as f } from "@uwdata/mosaic-core";
7
+ import { Query as p } from "@uwdata/mosaic-sql";
8
+ import { column as y } from "./arrow.js";
9
+ var h, s, m, a;
10
+ class w extends d {
11
+ constructor(e) {
12
+ super(e.filterBy);
13
+ l(this, h);
14
+ l(this, s);
15
+ l(this, m);
16
+ l(this, a);
17
+ u(this, h, e.table), u(this, s, e.idField), u(this, m, e.as), u(this, a, e.onSurvivors);
18
+ }
19
+ query(e = []) {
20
+ return p.from(i(this, h)).select({ id: i(this, s) }).where(e);
21
+ }
22
+ queryResult(e) {
23
+ return i(this, a).call(this, y(e, "id")), this;
24
+ }
25
+ /** `null` retracts the selection: an empty clause has a null predicate, which the resolver drops. */
26
+ publish(e) {
27
+ i(this, m).update(
28
+ f([i(this, s)], e == null ? void 0 : e.map((c) => [c]), {
29
+ source: this,
30
+ // A crossfilter normally exempts a client from its own clause, so a brush can be widened
31
+ // after it has collapsed the chart under it. A view that FADES an excluded row instead of
32
+ // removing it does not need the exemption: the row is still on screen and still
33
+ // selectable. Declining it is what makes the selection visible — the fade is the brush.
34
+ clients: /* @__PURE__ */ new Set()
35
+ })
36
+ );
37
+ }
38
+ }
39
+ h = new WeakMap(), s = new WeakMap(), m = new WeakMap(), a = new WeakMap();
40
+ export {
41
+ w as IdSetClient
42
+ };
43
+ //# sourceMappingURL=id-set-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"id-set-client.js","sources":["../src/id-set-client.ts"],"sourcesContent":["import { MosaicClient, clausePoints, type Selection } from \"@uwdata/mosaic-core\";\nimport { Query, type FilterExpr } from \"@uwdata/mosaic-sql\";\nimport { column } from \"./arrow.js\";\n\n/**\n * The crossfilter adapter for a view whose positions are not in the database.\n *\n * A `MosaicClient` asks for two things, and this is both:\n *\n * `query(filter)` — which rows survive the page's filters? The coordinator answers with a column\n * of ids, and the view fades everything else. The **observable** half.\n * `publish(ids)` — the user selected these. A points clause, `id IN (…)`, which every other chart\n * on the page filters by. The **controllable** half.\n *\n * The id list is not a shortcut, it is the only thing such a view can say. A Plot brush publishes\n * `weight BETWEEN …`, an interval in data space, because Plot's `x` IS a column. A GPU simulation's\n * `x` exists nowhere in the database, so no predicate over columns can describe the loop the user\n * drew. Enumerating what was hit is the honest translation — and its cost is the length of the `IN`\n * list, which is the real ceiling on the whole approach.\n *\n * Nothing here knows what draws. It is named for what it exchanges rather than for the renderer it\n * was first written against, because a canvas, a map and an imperative widget all reach the\n * crossfilter through exactly this shape.\n */\n\nexport interface IdSetClientOptions {\n /** The relation. Its `idField` column is what gets published and matched. */\n table: string;\n idField: string;\n /** What the view fades by. */\n filterBy: Selection;\n /** Where the selection publishes. */\n as: Selection;\n /** The surviving ids, in relation order, on every filter change. */\n onSurvivors: (ids: readonly unknown[]) => void;\n}\n\nexport class IdSetClient extends MosaicClient {\n #table: string;\n #idField: string;\n #as: Selection;\n #emit: (ids: readonly unknown[]) => void;\n\n constructor(options: IdSetClientOptions) {\n super(options.filterBy);\n this.#table = options.table;\n this.#idField = options.idField;\n this.#as = options.as;\n this.#emit = options.onSurvivors;\n }\n\n override query(filter: FilterExpr = []) {\n return Query.from(this.#table).select({ id: this.#idField }).where(filter);\n }\n\n override queryResult(data: unknown): this {\n this.#emit(column(data, \"id\"));\n return this;\n }\n\n /** `null` retracts the selection: an empty clause has a null predicate, which the resolver drops. */\n publish(ids: readonly unknown[] | null): void {\n this.#as.update(\n clausePoints([this.#idField], ids?.map((id) => [id]), {\n source: this,\n // A crossfilter normally exempts a client from its own clause, so a brush can be widened\n // after it has collapsed the chart under it. A view that FADES an excluded row instead of\n // removing it does not need the exemption: the row is still on screen and still\n // selectable. Declining it is what makes the selection visible — the fade is the brush.\n clients: new Set<MosaicClient>(),\n }),\n );\n }\n}\n"],"names":["IdSetClient","MosaicClient","options","__privateAdd","_table","_idField","_as","_emit","__privateSet","filter","Query","__privateGet","data","column","ids","clausePoints","id"],"mappings":";;;;;;;;;AAqCO,MAAMA,UAAoBC,EAAa;AAAA,EAM5C,YAAYC,GAA6B;AACvC,UAAMA,EAAQ,QAAQ;AANxB,IAAAC,EAAA,MAAAC;AACA,IAAAD,EAAA,MAAAE;AACA,IAAAF,EAAA,MAAAG;AACA,IAAAH,EAAA,MAAAI;AAIE,IAAAC,EAAA,MAAKJ,GAASF,EAAQ,QACtBM,EAAA,MAAKH,GAAWH,EAAQ,UACxBM,EAAA,MAAKF,GAAMJ,EAAQ,KACnBM,EAAA,MAAKD,GAAQL,EAAQ;AAAA,EACvB;AAAA,EAES,MAAMO,IAAqB,IAAI;AACtC,WAAOC,EAAM,KAAKC,EAAA,MAAKP,EAAM,EAAE,OAAO,EAAE,IAAIO,EAAA,MAAKN,GAAA,CAAU,EAAE,MAAMI,CAAM;AAAA,EAC3E;AAAA,EAES,YAAYG,GAAqB;AACxC,WAAAD,EAAA,MAAKJ,GAAL,WAAWM,EAAOD,GAAM,IAAI,IACrB;AAAA,EACT;AAAA;AAAA,EAGA,QAAQE,GAAsC;AAC5C,IAAAH,EAAA,MAAKL,GAAI;AAAA,MACPS,EAAa,CAACJ,EAAA,MAAKN,EAAQ,GAAGS,KAAA,gBAAAA,EAAK,IAAI,CAACE,MAAO,CAACA,CAAE,IAAI;AAAA,QACpD,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,QAKR,6BAAa,IAAA;AAAA,MAAkB,CAChC;AAAA,IAAA;AAAA,EAEL;AACF;AAnCEZ,IAAA,eACAC,IAAA,eACAC,IAAA,eACAC,IAAA;"}
@@ -0,0 +1,29 @@
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, wasmConnector, type SelectionClause, } from '@uwdata/mosaic-core';
24
+ export { Query, loadCSV, loadJSON, loadObjects, loadParquet, loadSpatial, loadExtension, type ExprValue, type FilterExpr, } 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, type NumericArray } from './arrow.js';
27
+ /** Ours: the crossfilter adapter for a view whose positions are not in the database. */
28
+ export { IdSetClient, type IdSetClientOptions } from './id-set-client.js';
29
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","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,EACX,aAAa,EACb,KAAK,eAAe,GACrB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,KAAK,EACL,OAAO,EACP,QAAQ,EACR,WAAW,EACX,WAAW,EACX,WAAW,EACX,aAAa,EACb,KAAK,SAAS,EACd,KAAK,UAAU,GAChB,MAAM,oBAAoB,CAAC;AAE5B,gGAAgG;AAChG,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAE5E,wFAAwF;AACxF,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,28 @@
1
+ import { Coordinator as l, MosaicClient as a, Selection as t, clauseInterval as n, clauseIntervals as r, clauseMatch as s, clausePoint as c, clausePoints as i, makeClient as u, wasmConnector as m } from "@uwdata/mosaic-core";
2
+ import { Query as C, loadCSV as f, loadExtension as p, loadJSON as x, loadObjects as S, loadParquet as I, loadSpatial as P } from "@uwdata/mosaic-sql";
3
+ import { column as v, fillColumn as M, numbers as O } from "./arrow.js";
4
+ import { IdSetClient as j } from "./id-set-client.js";
5
+ export {
6
+ l as Coordinator,
7
+ j as IdSetClient,
8
+ a as MosaicClient,
9
+ C as Query,
10
+ t as Selection,
11
+ n as clauseInterval,
12
+ r as clauseIntervals,
13
+ s as clauseMatch,
14
+ c as clausePoint,
15
+ i as clausePoints,
16
+ v as column,
17
+ M as fillColumn,
18
+ f as loadCSV,
19
+ p as loadExtension,
20
+ x as loadJSON,
21
+ S as loadObjects,
22
+ I as loadParquet,
23
+ P as loadSpatial,
24
+ u as makeClient,
25
+ O as numbers,
26
+ m as wasmConnector
27
+ };
28
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@kanzo-tech/mosaic",
3
+ "version": "0.1.0",
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
+ "type": "module",
6
+ "license": "MIT",
7
+ "sideEffects": false,
8
+ "files": [
9
+ "dist",
10
+ "README.md"
11
+ ],
12
+ "module": "./dist/index.js",
13
+ "types": "./dist/index.d.ts",
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "import": "./dist/index.js"
18
+ },
19
+ "./package.json": "./package.json"
20
+ },
21
+ "//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. @duckdb/duckdb-wasm is absent for the same reason it is absent from @kanzo-tech/graph: nothing here names it, and a host that boots its own DuckDB depends on it directly. 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.",
22
+ "peerDependencies": {
23
+ "@uwdata/mosaic-core": "^0.29.2",
24
+ "@uwdata/mosaic-sql": "^0.29.0"
25
+ },
26
+ "devDependencies": {
27
+ "@uwdata/mosaic-core": "^0.29.2",
28
+ "@uwdata/mosaic-sql": "^0.29.0"
29
+ },
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/Kanzo-Tech/ui.git",
33
+ "directory": "packages/mosaic"
34
+ },
35
+ "homepage": "https://kanzo-tech.github.io/ui",
36
+ "bugs": {
37
+ "url": "https://github.com/Kanzo-Tech/ui/issues"
38
+ },
39
+ "scripts": {
40
+ "build": "vite build",
41
+ "typecheck": "tsc --noEmit",
42
+ "test": "vitest run"
43
+ }
44
+ }