@kanzo-tech/mosaic 0.8.0 → 0.9.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/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +18 -18
- package/dist/engine.js.map +1 -1
- package/package.json +1 -1
package/dist/engine.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAiB,MAAM,qBAAqB,CAAC;AAEjE;;;;;;;;;;;;;;;;;;GAkBG;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,+EAA+E;IAC/E,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;
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAiB,MAAM,qBAAqB,CAAC;AAEjE;;;;;;;;;;;;;;;;;;GAkBG;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,+EAA+E;IAC/E,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;AAiFD,kDAAkD;AAClD,wBAAgB,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,CAIxC"}
|
package/dist/engine.js
CHANGED
|
@@ -1,38 +1,38 @@
|
|
|
1
1
|
import { wasmConnector as u, Coordinator as d } from "@uwdata/mosaic-core";
|
|
2
|
-
const h = 4, w = Symbol("held");
|
|
3
|
-
async function
|
|
4
|
-
const
|
|
5
|
-
await
|
|
6
|
-
const
|
|
2
|
+
const h = 4, w = { filesystem: { forceFullHTTPReads: !1 } }, y = Symbol("held");
|
|
3
|
+
async function b() {
|
|
4
|
+
const o = u({ config: w }), c = new d(o), s = await o.getDuckDB();
|
|
5
|
+
await c.exec("SET enable_http_metadata_cache = true");
|
|
6
|
+
const n = /* @__PURE__ */ new Map();
|
|
7
7
|
let f = Promise.resolve();
|
|
8
|
-
const
|
|
8
|
+
const r = (e) => {
|
|
9
9
|
const t = f.then(e);
|
|
10
10
|
return f = t.catch(() => {
|
|
11
11
|
}), t;
|
|
12
12
|
}, i = async (e) => {
|
|
13
|
-
|
|
13
|
+
n.has(e) && (await s.dropFile(e), n.delete(e));
|
|
14
14
|
};
|
|
15
15
|
return {
|
|
16
|
-
coordinator:
|
|
17
|
-
query: (e) =>
|
|
18
|
-
lend: (e) =>
|
|
16
|
+
coordinator: c,
|
|
17
|
+
query: (e) => c.query(e, { type: "json", cache: !1 }),
|
|
18
|
+
lend: (e) => r(async () => {
|
|
19
19
|
for (const [t, l] of Object.entries(e))
|
|
20
|
-
|
|
20
|
+
n.get(t) !== l && (await i(t), await s.registerFileURL(t, l, h, !1), n.set(t, l));
|
|
21
21
|
}),
|
|
22
|
-
hold: (e, t) =>
|
|
23
|
-
await i(e), await
|
|
22
|
+
hold: (e, t) => r(async () => {
|
|
23
|
+
await i(e), await s.registerFileBuffer(e, t.slice()), n.set(e, y);
|
|
24
24
|
}),
|
|
25
|
-
drop: (e) =>
|
|
25
|
+
drop: (e) => r(async () => {
|
|
26
26
|
for (const t of e) await i(t);
|
|
27
27
|
})
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
30
|
const a = Symbol.for("@kanzo-tech/mosaic/engine");
|
|
31
|
-
function
|
|
32
|
-
const
|
|
33
|
-
return
|
|
31
|
+
function m() {
|
|
32
|
+
const o = globalThis;
|
|
33
|
+
return o[a] ?? (o[a] = b()), o[a];
|
|
34
34
|
}
|
|
35
35
|
export {
|
|
36
|
-
|
|
36
|
+
m as engine
|
|
37
37
|
};
|
|
38
38
|
//# sourceMappingURL=engine.js.map
|
package/dist/engine.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.js","sources":["../src/engine.ts"],"sourcesContent":["import { Coordinator, wasmConnector } from \"@uwdata/mosaic-core\";\n\n/**\n * The page's one database: a DuckDB-WASM instance, the Mosaic `Coordinator` over it, and the file\n * registry, owned in one place.\n *\n * **One per document, because vgplot has one.** `MosaicProvider` registers its coordinator as\n * vgplot's process-wide active one, so a second coordinator on the page is a second database the\n * last-mounted chart wins. Every host wrote the same memoised boot to avoid it — three in these\n * docs, one in keasy, one in fossil's playground — and none of them owned the registry beside it.\n *\n * **The registry is the part that was missing.** DuckDB-WASM refuses to register a name a second\n * time under a different URL (`File already registered`), and answers only when the URL is\n * identical. A signed URL is different on every signing, so the second visit to the same data threw.\n * `lend` is the one place that knows what is behind a name: the same URL is a no-op, a new one drops\n * the old lease and registers the new. That indirection is also why the registry is kept rather than\n * reading `https://…` directly — a view names a stable file, and only the lease behind it rotates.\n *\n * It satisfies fossil's `Engine` structurally; this package does not depend on fossil, and does not\n * name `@duckdb/duckdb-wasm` either — the connector hands the database over untyped.\n */\nexport interface Engine {\n readonly coordinator: Coordinator;\n /** Rows as objects, uncached: a read after a `lend` must see the new lease. */\n query(sql: string): Promise<Record<string, unknown>[]>;\n /** name → URL. The same URL is a no-op; a different one replaces the lease. */\n lend(files: Record<string, string>): Promise<void>;\n /** Registers a copy of `bytes` under `name`, replacing whatever was there. */\n hold(name: string, bytes: Uint8Array): Promise<void>;\n /** Unregisters the names. A name the engine does not hold is not an error. */\n drop(names: readonly string[]): Promise<void>;\n}\n\n/** The slice of DuckDB-WASM's `AsyncDuckDB` the registry uses. */\ninterface Registry {\n registerFileURL(name: string, url: string, protocol: number, directIO: boolean): Promise<void>;\n registerFileBuffer(name: string, buffer: Uint8Array): Promise<void>;\n dropFile(name: string): Promise<void>;\n}\n\n/** `DuckDBDataProtocol.HTTP` — a numeric enum, spelled here so the type never has to be imported. */\nconst HTTP = 4;\n\n/** A buffer is not a URL, so a held name never compares equal to a lent one. */\nconst HELD = Symbol(\"held\");\n\nasync function boot(): Promise<Engine> {\n const connector = wasmConnector();\n const coordinator = new Coordinator(connector);\n const db = (await connector.getDuckDB()) as unknown as Registry;\n // Lent files are read lazily by range; caching their metadata is what keeps a pan from re-probing.\n await coordinator.exec(\"SET enable_http_metadata_cache = true\");\n\n const behind = new Map<string, string | typeof HELD>();\n\n // Registry changes run one at a time: two `lend`s of one name racing each other would each see the\n // old entry, and the second register would be refused.\n let tail: Promise<unknown> = Promise.resolve();\n const serial = (step: () => Promise<void>): Promise<void> => {\n const run = tail.then(step);\n tail = run.catch(() => {});\n return run;\n };\n\n const release = async (name: string) => {\n if (!behind.has(name)) return;\n await db.dropFile(name);\n behind.delete(name);\n };\n\n return {\n coordinator,\n query: (sql) =>\n coordinator.query(sql, { type: \"json\", cache: false }) as Promise<Record<string, unknown>[]>,\n lend: (files) =>\n serial(async () => {\n for (const [name, url] of Object.entries(files)) {\n if (behind.get(name) === url) continue;\n await release(name);\n await db.registerFileURL(name, url, HTTP, false);\n behind.set(name, url);\n }\n }),\n hold: (name, bytes) =>\n serial(async () => {\n await release(name);\n // A copy, because DuckDB-WASM transfers the buffer to its worker and detaches the caller's.\n await db.registerFileBuffer(name, bytes.slice());\n behind.set(name, HELD);\n }),\n drop: (names) =>\n serial(async () => {\n for (const name of names) await release(name);\n }),\n };\n}\n\n/**\n * Keyed on the document's global rather than on this module, so two copies of the package in one\n * bundle still share one database — which is the invariant, not the module identity.\n */\nconst KEY = Symbol.for(\"@kanzo-tech/mosaic/engine\");\n\n/** The page's one engine, booted on first ask. */\nexport function engine(): Promise<Engine> {\n const scope = globalThis as { [KEY]?: Promise<Engine> };\n scope[KEY] ??= boot();\n return scope[KEY];\n}\n"],"names":["HTTP","HELD","boot","connector","wasmConnector","coordinator","Coordinator","db","behind","tail","serial","step","run","release","name","sql","files","url","bytes","names","KEY","engine","scope"],"mappings":";AAyCA,MAAMA,IAAO,
|
|
1
|
+
{"version":3,"file":"engine.js","sources":["../src/engine.ts"],"sourcesContent":["import { Coordinator, wasmConnector } from \"@uwdata/mosaic-core\";\n\n/**\n * The page's one database: a DuckDB-WASM instance, the Mosaic `Coordinator` over it, and the file\n * registry, owned in one place.\n *\n * **One per document, because vgplot has one.** `MosaicProvider` registers its coordinator as\n * vgplot's process-wide active one, so a second coordinator on the page is a second database the\n * last-mounted chart wins. Every host wrote the same memoised boot to avoid it — three in these\n * docs, one in keasy, one in fossil's playground — and none of them owned the registry beside it.\n *\n * **The registry is the part that was missing.** DuckDB-WASM refuses to register a name a second\n * time under a different URL (`File already registered`), and answers only when the URL is\n * identical. A signed URL is different on every signing, so the second visit to the same data threw.\n * `lend` is the one place that knows what is behind a name: the same URL is a no-op, a new one drops\n * the old lease and registers the new. That indirection is also why the registry is kept rather than\n * reading `https://…` directly — a view names a stable file, and only the lease behind it rotates.\n *\n * It satisfies fossil's `Engine` structurally; this package does not depend on fossil, and does not\n * name `@duckdb/duckdb-wasm` either — the connector hands the database over untyped.\n */\nexport interface Engine {\n readonly coordinator: Coordinator;\n /** Rows as objects, uncached: a read after a `lend` must see the new lease. */\n query(sql: string): Promise<Record<string, unknown>[]>;\n /** name → URL. The same URL is a no-op; a different one replaces the lease. */\n lend(files: Record<string, string>): Promise<void>;\n /** Registers a copy of `bytes` under `name`, replacing whatever was there. */\n hold(name: string, bytes: Uint8Array): Promise<void>;\n /** Unregisters the names. A name the engine does not hold is not an error. */\n drop(names: readonly string[]): Promise<void>;\n}\n\n/** The slice of DuckDB-WASM's `AsyncDuckDB` the registry uses. */\ninterface Registry {\n registerFileURL(name: string, url: string, protocol: number, directIO: boolean): Promise<void>;\n registerFileBuffer(name: string, buffer: Uint8Array): Promise<void>;\n dropFile(name: string): Promise<void>;\n}\n\n/** `DuckDBDataProtocol.HTTP` — a numeric enum, spelled here so the type never has to be imported. */\nconst HTTP = 4;\n\n/**\n * DuckDB-WASM >= 1.30 downloads a lent file whole unless full reads are refused outright: its range\n * probe reads `Content-Length` where it meant `Content-Range` and falls through to a whole-file GET\n * (duckdb/duckdb-wasm#2228). Refused, it reaches its `HEAD` fallback and reads by range, which is the\n * whole reason a file is lent rather than fetched. The fallback needs a URL that answers `HEAD` — a\n * presigned GET does not; the host's redirect that signs per method does.\n */\nconst RANGE_READS = { filesystem: { forceFullHTTPReads: false } };\n\n/** A buffer is not a URL, so a held name never compares equal to a lent one. */\nconst HELD = Symbol(\"held\");\n\nasync function boot(): Promise<Engine> {\n const connector = wasmConnector({ config: RANGE_READS });\n const coordinator = new Coordinator(connector);\n const db = (await connector.getDuckDB()) as unknown as Registry;\n // Lent files are read lazily by range; caching their metadata is what keeps a pan from re-probing.\n await coordinator.exec(\"SET enable_http_metadata_cache = true\");\n\n const behind = new Map<string, string | typeof HELD>();\n\n // Registry changes run one at a time: two `lend`s of one name racing each other would each see the\n // old entry, and the second register would be refused.\n let tail: Promise<unknown> = Promise.resolve();\n const serial = (step: () => Promise<void>): Promise<void> => {\n const run = tail.then(step);\n tail = run.catch(() => {});\n return run;\n };\n\n const release = async (name: string) => {\n if (!behind.has(name)) return;\n await db.dropFile(name);\n behind.delete(name);\n };\n\n return {\n coordinator,\n query: (sql) =>\n coordinator.query(sql, { type: \"json\", cache: false }) as Promise<Record<string, unknown>[]>,\n lend: (files) =>\n serial(async () => {\n for (const [name, url] of Object.entries(files)) {\n if (behind.get(name) === url) continue;\n await release(name);\n await db.registerFileURL(name, url, HTTP, false);\n behind.set(name, url);\n }\n }),\n hold: (name, bytes) =>\n serial(async () => {\n await release(name);\n // A copy, because DuckDB-WASM transfers the buffer to its worker and detaches the caller's.\n await db.registerFileBuffer(name, bytes.slice());\n behind.set(name, HELD);\n }),\n drop: (names) =>\n serial(async () => {\n for (const name of names) await release(name);\n }),\n };\n}\n\n/**\n * Keyed on the document's global rather than on this module, so two copies of the package in one\n * bundle still share one database — which is the invariant, not the module identity.\n */\nconst KEY = Symbol.for(\"@kanzo-tech/mosaic/engine\");\n\n/** The page's one engine, booted on first ask. */\nexport function engine(): Promise<Engine> {\n const scope = globalThis as { [KEY]?: Promise<Engine> };\n scope[KEY] ??= boot();\n return scope[KEY];\n}\n"],"names":["HTTP","RANGE_READS","HELD","boot","connector","wasmConnector","coordinator","Coordinator","db","behind","tail","serial","step","run","release","name","sql","files","url","bytes","names","KEY","engine","scope"],"mappings":";AAyCA,MAAMA,IAAO,GASPC,IAAc,EAAE,YAAY,EAAE,oBAAoB,KAAM,GAGxDC,IAAO,OAAO,MAAM;AAE1B,eAAeC,IAAwB;AACrC,QAAMC,IAAYC,EAAc,EAAE,QAAQJ,GAAa,GACjDK,IAAc,IAAIC,EAAYH,CAAS,GACvCI,IAAM,MAAMJ,EAAU,UAAA;AAE5B,QAAME,EAAY,KAAK,uCAAuC;AAE9D,QAAMG,wBAAa,IAAA;AAInB,MAAIC,IAAyB,QAAQ,QAAA;AACrC,QAAMC,IAAS,CAACC,MAA6C;AAC3D,UAAMC,IAAMH,EAAK,KAAKE,CAAI;AAC1B,WAAAF,IAAOG,EAAI,MAAM,MAAM;AAAA,IAAC,CAAC,GAClBA;AAAA,EACT,GAEMC,IAAU,OAAOC,MAAiB;AACtC,IAAKN,EAAO,IAAIM,CAAI,MACpB,MAAMP,EAAG,SAASO,CAAI,GACtBN,EAAO,OAAOM,CAAI;AAAA,EACpB;AAEA,SAAO;AAAA,IACL,aAAAT;AAAA,IACA,OAAO,CAACU,MACNV,EAAY,MAAMU,GAAK,EAAE,MAAM,QAAQ,OAAO,IAAO;AAAA,IACvD,MAAM,CAACC,MACLN,EAAO,YAAY;AACjB,iBAAW,CAACI,GAAMG,CAAG,KAAK,OAAO,QAAQD,CAAK;AAC5C,QAAIR,EAAO,IAAIM,CAAI,MAAMG,MACzB,MAAMJ,EAAQC,CAAI,GAClB,MAAMP,EAAG,gBAAgBO,GAAMG,GAAKlB,GAAM,EAAK,GAC/CS,EAAO,IAAIM,GAAMG,CAAG;AAAA,IAExB,CAAC;AAAA,IACH,MAAM,CAACH,GAAMI,MACXR,EAAO,YAAY;AACjB,YAAMG,EAAQC,CAAI,GAElB,MAAMP,EAAG,mBAAmBO,GAAMI,EAAM,OAAO,GAC/CV,EAAO,IAAIM,GAAMb,CAAI;AAAA,IACvB,CAAC;AAAA,IACH,MAAM,CAACkB,MACLT,EAAO,YAAY;AACjB,iBAAWI,KAAQK,EAAO,OAAMN,EAAQC,CAAI;AAAA,IAC9C,CAAC;AAAA,EAAA;AAEP;AAMA,MAAMM,IAAM,OAAO,IAAI,2BAA2B;AAG3C,SAASC,IAA0B;AACxC,QAAMC,IAAQ;AACd,SAAAA,EAAAF,OAAAE,EAAAF,KAAelB,EAAA,IACRoB,EAAMF,CAAG;AAClB;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kanzo-tech/mosaic",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.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",
|