@factoidal/core 0.7.1 → 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.
Files changed (193) hide show
  1. package/CHANGELOG.md +503 -1
  2. package/NOTICE +2 -21
  3. package/README.md +117 -993
  4. package/api.d.ts +53 -0
  5. package/api.js +5 -0
  6. package/api.mjs +56 -0
  7. package/bin/engine.mjs +38 -19
  8. package/bin/factoidal.mjs +512 -66
  9. package/bin/pack.mjs +37 -0
  10. package/bin/serve-worker.mjs +32 -0
  11. package/bin/serve.mjs +423 -0
  12. package/bin/store-worker-host.mjs +1 -1
  13. package/bin/store.mjs +1 -1
  14. package/browser.d.ts +110 -507
  15. package/browser.js +151 -2257
  16. package/docs/fuseki-replacement.md +108 -0
  17. package/fn.d.ts +24 -95
  18. package/fn.js +104 -150
  19. package/index.d.ts +598 -259
  20. package/index.js +4 -234
  21. package/index.mjs +176 -84
  22. package/l4-assets/l4factoidal.js +47 -7
  23. package/l4-assets/l4factoidal.mjs +1 -1
  24. package/l4-assets/l4factoidal.wasm +0 -0
  25. package/l4-assets/version.json +11 -7
  26. package/lib/api.mjs +2300 -0
  27. package/lib/browser-engine.mjs +69 -0
  28. package/lib/dataset.mjs +377 -0
  29. package/lib/delta-log-hosts.mjs +191 -0
  30. package/lib/lean-entry.mjs +204 -0
  31. package/lib/pure.mjs +98 -0
  32. package/lib/store.mjs +115 -0
  33. package/lib/version.mjs +5 -0
  34. package/lws/README.md +97 -0
  35. package/lws/server.mjs +331 -0
  36. package/package.json +59 -61
  37. package/rdfjs.js +5 -536
  38. package/rdfjs.mjs +594 -0
  39. package/sample-store.d.ts +8 -16
  40. package/sample-store.mjs +39 -29
  41. package/solid/client/README.md +100 -0
  42. package/solid/client/index.mjs +277 -0
  43. package/solid/server/README.md +96 -0
  44. package/solid/server/index.mjs +317 -0
  45. package/store-host/deno.mjs +8 -0
  46. package/store-host/index.mjs +12 -0
  47. package/store-host/node.mjs +8 -0
  48. package/xmpp/README.md +107 -0
  49. package/xmpp/index.mjs +229 -0
  50. package/browser-wasm.js +0 -872
  51. package/factoidal-npm-entry.js +0 -15477
  52. package/factoidal-npm-entry.wasm.assets/code-5a7fc68f2ab1323718b8.wasm +0 -0
  53. package/factoidal-npm-entry.wasm.js +0 -455
  54. package/factoidal.js +0 -13118
  55. package/factoidal.wasm.assets/code-bbe6099bfb5b10c4c3ab.wasm +0 -0
  56. package/factoidal.wasm.js +0 -457
  57. package/hacl-init.js +0 -92
  58. package/hacl-wasm/FStar.wasm +0 -0
  59. package/hacl-wasm/Hacl_Bignum.wasm +0 -0
  60. package/hacl-wasm/Hacl_Bignum25519_51.wasm +0 -0
  61. package/hacl-wasm/Hacl_Bignum_Base.wasm +0 -0
  62. package/hacl-wasm/Hacl_Curve25519_51.wasm +0 -0
  63. package/hacl-wasm/Hacl_Ed25519.wasm +0 -0
  64. package/hacl-wasm/Hacl_Ed25519_PrecompTable.wasm +0 -0
  65. package/hacl-wasm/Hacl_Hash_Base.wasm +0 -0
  66. package/hacl-wasm/Hacl_Hash_SHA2.wasm +0 -0
  67. package/hacl-wasm/Hacl_IntTypes_Intrinsics.wasm +0 -0
  68. package/hacl-wasm/LowStar_Endianness.wasm +0 -0
  69. package/hacl-wasm/WasmSupport.wasm +0 -0
  70. package/hacl-wasm/api.js +0 -775
  71. package/hacl-wasm/api.json +0 -3787
  72. package/hacl-wasm/layouts.json +0 -1
  73. package/hacl-wasm/loader.js +0 -568
  74. package/hacl-wasm/shell.js +0 -12
  75. package/l4-core.d.ts +0 -159
  76. package/l4-core.js +0 -188
  77. package/l4.d.ts +0 -50
  78. package/l4.js +0 -104
  79. package/lib/api.js +0 -2300
  80. package/lib/engine-js.js +0 -165
  81. package/lib/engine-wasm.js +0 -300
  82. package/sample-store/CURRENT +0 -1
  83. package/sample-store/gen-1/manifest.sbm2 +0 -0
  84. package/sample-store/gen-1/manifest.tsv +0 -14
  85. package/sample-store/gen-1/predicate-0.ibk3 +0 -0
  86. package/sample-store/gen-1/predicate-0.ibk3.merkle +0 -1
  87. package/sample-store/gen-1/predicate-0.ibk3.oli2 +0 -0
  88. package/sample-store/gen-1/predicate-0.ibk3.oli2.merkle +0 -1
  89. package/sample-store/gen-1/predicate-0.ibk3.sri2 +0 -0
  90. package/sample-store/gen-1/predicate-0.ibk3.sri2.merkle +0 -1
  91. package/sample-store/gen-1/predicate-0.ibk3.tli1 +0 -0
  92. package/sample-store/gen-1/predicate-0.ibk3.tli1.merkle +0 -0
  93. package/sample-store/gen-1/predicate-1.ibk3 +0 -0
  94. package/sample-store/gen-1/predicate-1.ibk3.merkle +0 -0
  95. package/sample-store/gen-1/predicate-1.ibk3.oli2 +0 -0
  96. package/sample-store/gen-1/predicate-1.ibk3.oli2.merkle +0 -0
  97. package/sample-store/gen-1/predicate-1.ibk3.sri2 +0 -0
  98. package/sample-store/gen-1/predicate-1.ibk3.sri2.merkle +0 -1
  99. package/sample-store/gen-1/predicate-1.ibk3.tli1 +0 -0
  100. package/sample-store/gen-1/predicate-1.ibk3.tli1.merkle +0 -1
  101. package/sample-store/gen-1/predicate-10.ibk3 +0 -0
  102. package/sample-store/gen-1/predicate-10.ibk3.merkle +0 -1
  103. package/sample-store/gen-1/predicate-10.ibk3.oli2 +0 -0
  104. package/sample-store/gen-1/predicate-10.ibk3.oli2.merkle +0 -0
  105. package/sample-store/gen-1/predicate-10.ibk3.sri2 +0 -0
  106. package/sample-store/gen-1/predicate-10.ibk3.sri2.merkle +0 -1
  107. package/sample-store/gen-1/predicate-10.ibk3.tli1 +0 -0
  108. package/sample-store/gen-1/predicate-10.ibk3.tli1.merkle +0 -1
  109. package/sample-store/gen-1/predicate-11.ibk3 +0 -0
  110. package/sample-store/gen-1/predicate-11.ibk3.merkle +0 -0
  111. package/sample-store/gen-1/predicate-11.ibk3.oli2 +0 -0
  112. package/sample-store/gen-1/predicate-11.ibk3.oli2.merkle +0 -1
  113. package/sample-store/gen-1/predicate-11.ibk3.sri2 +0 -0
  114. package/sample-store/gen-1/predicate-11.ibk3.sri2.merkle +0 -1
  115. package/sample-store/gen-1/predicate-11.ibk3.tli1 +0 -0
  116. package/sample-store/gen-1/predicate-11.ibk3.tli1.merkle +0 -1
  117. package/sample-store/gen-1/predicate-12.ibk3 +0 -0
  118. package/sample-store/gen-1/predicate-12.ibk3.merkle +0 -1
  119. package/sample-store/gen-1/predicate-12.ibk3.oli2 +0 -0
  120. package/sample-store/gen-1/predicate-12.ibk3.oli2.merkle +0 -1
  121. package/sample-store/gen-1/predicate-12.ibk3.sri2 +0 -0
  122. package/sample-store/gen-1/predicate-12.ibk3.sri2.merkle +0 -1
  123. package/sample-store/gen-1/predicate-12.ibk3.tli1 +0 -0
  124. package/sample-store/gen-1/predicate-12.ibk3.tli1.merkle +0 -1
  125. package/sample-store/gen-1/predicate-2.ibk3 +0 -0
  126. package/sample-store/gen-1/predicate-2.ibk3.merkle +0 -1
  127. package/sample-store/gen-1/predicate-2.ibk3.oli2 +0 -0
  128. package/sample-store/gen-1/predicate-2.ibk3.oli2.merkle +0 -1
  129. package/sample-store/gen-1/predicate-2.ibk3.sri2 +0 -0
  130. package/sample-store/gen-1/predicate-2.ibk3.sri2.merkle +0 -0
  131. package/sample-store/gen-1/predicate-2.ibk3.tli1 +0 -0
  132. package/sample-store/gen-1/predicate-2.ibk3.tli1.merkle +0 -0
  133. package/sample-store/gen-1/predicate-3.ibk3 +0 -0
  134. package/sample-store/gen-1/predicate-3.ibk3.merkle +0 -1
  135. package/sample-store/gen-1/predicate-3.ibk3.oli2 +0 -0
  136. package/sample-store/gen-1/predicate-3.ibk3.oli2.merkle +0 -1
  137. package/sample-store/gen-1/predicate-3.ibk3.sri2 +0 -0
  138. package/sample-store/gen-1/predicate-3.ibk3.sri2.merkle +0 -1
  139. package/sample-store/gen-1/predicate-3.ibk3.tli1 +0 -0
  140. package/sample-store/gen-1/predicate-3.ibk3.tli1.merkle +0 -1
  141. package/sample-store/gen-1/predicate-4.ibk3 +0 -0
  142. package/sample-store/gen-1/predicate-4.ibk3.merkle +0 -0
  143. package/sample-store/gen-1/predicate-4.ibk3.oli2 +0 -0
  144. package/sample-store/gen-1/predicate-4.ibk3.oli2.merkle +0 -1
  145. package/sample-store/gen-1/predicate-4.ibk3.sri2 +0 -0
  146. package/sample-store/gen-1/predicate-4.ibk3.sri2.merkle +0 -1
  147. package/sample-store/gen-1/predicate-4.ibk3.tli1 +0 -0
  148. package/sample-store/gen-1/predicate-4.ibk3.tli1.merkle +0 -2
  149. package/sample-store/gen-1/predicate-5.ibk3 +0 -0
  150. package/sample-store/gen-1/predicate-5.ibk3.merkle +0 -1
  151. package/sample-store/gen-1/predicate-5.ibk3.oli2 +0 -0
  152. package/sample-store/gen-1/predicate-5.ibk3.oli2.merkle +0 -1
  153. package/sample-store/gen-1/predicate-5.ibk3.sri2 +0 -0
  154. package/sample-store/gen-1/predicate-5.ibk3.sri2.merkle +0 -1
  155. package/sample-store/gen-1/predicate-5.ibk3.tli1 +0 -0
  156. package/sample-store/gen-1/predicate-5.ibk3.tli1.merkle +0 -1
  157. package/sample-store/gen-1/predicate-6.ibk3 +0 -0
  158. package/sample-store/gen-1/predicate-6.ibk3.merkle +0 -1
  159. package/sample-store/gen-1/predicate-6.ibk3.oli2 +0 -0
  160. package/sample-store/gen-1/predicate-6.ibk3.oli2.merkle +0 -1
  161. package/sample-store/gen-1/predicate-6.ibk3.sri2 +0 -0
  162. package/sample-store/gen-1/predicate-6.ibk3.sri2.merkle +0 -1
  163. package/sample-store/gen-1/predicate-6.ibk3.tli1 +0 -0
  164. package/sample-store/gen-1/predicate-6.ibk3.tli1.merkle +0 -0
  165. package/sample-store/gen-1/predicate-7.ibk3 +0 -0
  166. package/sample-store/gen-1/predicate-7.ibk3.merkle +0 -0
  167. package/sample-store/gen-1/predicate-7.ibk3.oli2 +0 -0
  168. package/sample-store/gen-1/predicate-7.ibk3.oli2.merkle +0 -2
  169. package/sample-store/gen-1/predicate-7.ibk3.sri2 +0 -0
  170. package/sample-store/gen-1/predicate-7.ibk3.sri2.merkle +0 -1
  171. package/sample-store/gen-1/predicate-7.ibk3.tli1 +0 -0
  172. package/sample-store/gen-1/predicate-7.ibk3.tli1.merkle +0 -1
  173. package/sample-store/gen-1/predicate-8.ibk3 +0 -0
  174. package/sample-store/gen-1/predicate-8.ibk3.merkle +0 -1
  175. package/sample-store/gen-1/predicate-8.ibk3.oli2 +0 -0
  176. package/sample-store/gen-1/predicate-8.ibk3.oli2.merkle +0 -1
  177. package/sample-store/gen-1/predicate-8.ibk3.sri2 +0 -0
  178. package/sample-store/gen-1/predicate-8.ibk3.sri2.merkle +0 -1
  179. package/sample-store/gen-1/predicate-8.ibk3.tli1 +0 -0
  180. package/sample-store/gen-1/predicate-8.ibk3.tli1.merkle +0 -1
  181. package/sample-store/gen-1/predicate-9.ibk3 +0 -0
  182. package/sample-store/gen-1/predicate-9.ibk3.merkle +0 -1
  183. package/sample-store/gen-1/predicate-9.ibk3.oli2 +0 -0
  184. package/sample-store/gen-1/predicate-9.ibk3.oli2.merkle +0 -1
  185. package/sample-store/gen-1/predicate-9.ibk3.sri2 +0 -0
  186. package/sample-store/gen-1/predicate-9.ibk3.sri2.merkle +0 -3
  187. package/sample-store/gen-1/predicate-9.ibk3.tli1 +0 -0
  188. package/sample-store/gen-1/predicate-9.ibk3.tli1.merkle +0 -2
  189. package/select.d.ts +0 -116
  190. package/select.js +0 -492
  191. package/version.json +0 -102
  192. package/wasm.d.ts +0 -130
  193. package/wasm.js +0 -158
package/fn.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // factoidal/fn — a strictly functional dataset API.
2
2
  //
3
- // Every extracted engine operation is a value-to-value function (F*
4
- // has no mutation to expose); RDF/JS DatasetCore's add/delete is
3
+ // Every engine operation is a value-to-value function (the Lean
4
+ // library has no mutation to expose); RDF/JS DatasetCore's add/delete is
5
5
  // wrapper-side skeuomorphism on top of that. This module makes the JS
6
6
  // contract match the verified one: FnDataset is a frozen snapshot, all
7
7
  // operations are free functions that return new values, and content
@@ -25,7 +25,7 @@ const crypto = require('node:crypto');
25
25
 
26
26
  const engineApi = require('./index.js');
27
27
  const {
28
- Dataset,
28
+ DatasetCore,
29
29
  dataFactory,
30
30
  quadToNQuads,
31
31
  quadsToNQuads,
@@ -92,10 +92,34 @@ function arrayBackend(quads) {
92
92
  kind: 'array',
93
93
  size: quads.length,
94
94
  quads: () => quads,
95
+ engine: null,
95
96
  precomputedHash: null,
96
97
  };
97
98
  }
98
99
 
100
+ // The engine backend (0.10.0, issue 882 of danbri/factoidal): the quads are
101
+ // an engine Dataset (lib/dataset.mjs) that this module never changes. Every
102
+ // engine operation takes that Dataset itself, so no N-Quads text crosses
103
+ // between steps. The JS quad array is read once, on demand.
104
+ function engineBackend(eds) {
105
+ let quads = null;
106
+ return {
107
+ kind: 'engine',
108
+ size: eds.size,
109
+ quads: () => (quads ||= Object.freeze(eds.toArray())),
110
+ engine: eds,
111
+ precomputedHash: null,
112
+ };
113
+ }
114
+
115
+ // An FnDataset over an engine Dataset this module made and never shares.
116
+ function wrapEngine(eds) {
117
+ return new FnDataset(engineBackend(eds));
118
+ }
119
+
120
+ // ds (array-backed FnDataset) -> engine Dataset, opened once from its quads.
121
+ const ENGINE_CACHE = new WeakMap();
122
+
99
123
  // Build a de-duplicated FnDataset from any iterable of RDF/JS quads.
100
124
  // Every public constructor path (fromDataset, union, difference,
101
125
  // filter, mapQuads, query's CONSTRUCT wrapping, builder().finish())
@@ -147,14 +171,15 @@ class FnDataset {
147
171
  toNQuads() {
148
172
  let cached = NQUADS_CACHE.get(this);
149
173
  if (cached === undefined) {
150
- cached = quadsToNQuads(this.toArray());
174
+ cached = this._backend.engine ? this._backend.engine.toNQuads() : quadsToNQuads(this.toArray());
151
175
  NQUADS_CACHE.set(this, cached);
152
176
  }
153
177
  return cached;
154
178
  }
155
179
 
156
- /** Read-only quad-pattern match (RDF/JS DatasetCore shape), no engine call. */
180
+ /** Read-only quad-pattern match (RDF/JS DatasetCore shape); the engine's indexes for an engine-backed dataset. */
157
181
  match(subject, predicate, object, graph) {
182
+ if (this._backend.engine) return wrapEngine(this._backend.engine.match(subject, predicate, object, graph));
158
183
  return makeFnDataset(this.toArray().filter((q) =>
159
184
  (!subject || subject.equals(q.subject)) &&
160
185
  (!predicate || predicate.equals(q.predicate)) &&
@@ -170,18 +195,31 @@ const EMPTY = new FnDataset(arrayBackend(Object.freeze([])));
170
195
  // Interop with the mutable RDF/JS layer.
171
196
  // ---------------------------------------------------------------------
172
197
 
173
- /** Snapshot a (possibly mutable) RDF/JS Dataset into an FnDataset. */
198
+ /** Snapshot a Dataset (the engine's, or an RDF/JS DatasetCore) into an FnDataset. */
174
199
  function fromDataset(dataset) {
175
- if (!(dataset instanceof Dataset)) {
176
- throw new TypeError('fromDataset: expected an RDF/JS Dataset');
200
+ if (dataset instanceof engineApi.Dataset) return wrapEngine(dataset.clone());
201
+ if (!(dataset instanceof DatasetCore)) {
202
+ throw new TypeError('fromDataset: expected a Dataset or an RDF/JS DatasetCore');
177
203
  }
178
204
  return makeFnDataset(dataset);
179
205
  }
180
206
 
181
- /** Materialize an FnDataset into a fresh, independently-mutable Dataset. */
207
+ // The engine Dataset of an FnDataset: its own, or (for one built from JS
208
+ // quads) one opened from its quads once and kept.
209
+ async function engineOf(ds) {
210
+ if (ds._backend.engine) return ds._backend.engine;
211
+ let eds = ENGINE_CACHE.get(ds);
212
+ if (!eds) {
213
+ eds = await engineApi.openDataset({ text: quadsToNQuads(ds.toArray()), format: 'nquads' });
214
+ ENGINE_CACHE.set(ds, eds);
215
+ }
216
+ return eds;
217
+ }
218
+
219
+ /** Materialize an FnDataset into a fresh, independently-mutable RDF/JS DatasetCore. */
182
220
  function toDataset(ds) {
183
221
  assertFnDataset(ds, 'toDataset');
184
- return new Dataset(ds.toArray());
222
+ return new DatasetCore(ds.toArray());
185
223
  }
186
224
 
187
225
  // ---------------------------------------------------------------------
@@ -247,7 +285,7 @@ async function fromChunks(chunks) {
247
285
 
248
286
  /** Parse one RDF document into an FnDataset. Mirrors index.js's parse(). */
249
287
  async function parse(text, options) {
250
- return fromDataset(await engineApi.parse(text, options));
288
+ return wrapEngine(await engineApi.parse(text, options));
251
289
  }
252
290
 
253
291
  /** Set union, first-seen order (a's quads, then b's not already present). */
@@ -291,31 +329,22 @@ function mapQuads(ds, f) {
291
329
 
292
330
  /**
293
331
  * Run a SPARQL 1.1 query. SELECT -> Bindings[]; ASK -> boolean;
294
- * CONSTRUCT -> FnDataset. Delegates entirely to index.js's query() —
295
- * same capability gating (CONSTRUCT needs the npm-entry bundle; its
296
- * absence throws the existing "pending npm-entry build" Error).
332
+ * CONSTRUCT and DESCRIBE -> FnDataset. Delegates entirely to index.js's
333
+ * query().
297
334
  */
298
335
  async function query(ds, sparql, options) {
299
336
  assertFnDataset(ds, 'query');
300
- const result = await engineApi.query(toDataset(ds), sparql, options);
301
- return result instanceof Dataset ? fromDataset(result) : result;
337
+ const result = await engineApi.query((await engineOf(ds)), sparql, options);
338
+ return result instanceof engineApi.Dataset ? wrapEngine(result) : result;
302
339
  }
303
340
 
304
341
  /**
305
342
  * Materialize an entailment closure as a new FnDataset.
306
343
  *
307
- * Reuses query()'s existing entailment support rather than adding new
308
- * engine plumbing — but *not* via CONSTRUCT: the npm-entry ABI's
309
- * queryDataset has no entailment parameter (entailment closure stays
310
- * on the CLI path, per lib/api.js), and the CLI path does not support
311
- * CONSTRUCT at all, so "CONSTRUCT ... WHERE ... { entail }" is not
312
- * reachable through the existing API today. Instead this runs
313
- * `SELECT ?s ?p ?o WHERE { ?s ?p ?o }` with the entailment option
314
- * (exactly the combination test/api.test.js's "query: entail RDFS
315
- * infers subclass instances" already exercises) and repackages each
316
- * solution row as a quad — pure JS reshaping of already-materialized
317
- * bindings, not new RDF/SPARQL semantics, so it works with the CLI
318
- * bundle alone (no npm-entry bundle required).
344
+ * Reuses query()'s entailment support: it runs
345
+ * `SELECT ?s ?p ?o WHERE { ?s ?p ?o }` with the entailment option (the
346
+ * engine closes the default graph under the regime, then answers the
347
+ * query; op queryRaw) and repackages each solution row as a quad.
319
348
  *
320
349
  * Scope limitation (documented, not silent): like a bare
321
350
  * `WHERE { ?s ?p ?o }` in SPARQL generally, this closes over the
@@ -326,10 +355,10 @@ async function query(ds, sparql, options) {
326
355
  */
327
356
  // Case-insensitive regime aliases ('rdfs', 'owl-rl', 'owlrl', 'owl_rl')
328
357
  // normalized to the engine's exact-case ENTAIL_VALUES spelling ('RDFS',
329
- // 'OWL-RL'); anything else (including already-correct casing, or a
330
- // genuinely invalid value) passes through unchanged so engineApi.query's
331
- // own validation reports the honest error rather than this function
332
- // guessing at what the caller meant.
358
+ // 'OWL-RL'); anything else (including already-correct casing, or a value
359
+ // that names no regime) passes through unchanged, so engineApi.query's own
360
+ // validation reports the error and this function does not guess what the
361
+ // caller meant.
333
362
  const ENTAIL_REGIME_ALIASES = {
334
363
  none: 'none', rdfs: 'RDFS', 'owl-rl': 'OWL-RL', owlrl: 'OWL-RL', owl_rl: 'OWL-RL',
335
364
  };
@@ -380,15 +409,14 @@ function rejectIklRegime(regime, who) {
380
409
  async function entail(ds, regime) {
381
410
  assertFnDataset(ds, 'entail');
382
411
  rejectIklRegime(regime, 'entail');
383
- const rows = await engineApi.query(
384
- toDataset(ds), 'SELECT ?s ?p ?o WHERE { ?s ?p ?o }',
412
+ const rows = await engineApi.query((await engineOf(ds)), 'SELECT ?s ?p ?o WHERE { ?s ?p ?o }',
385
413
  { entail: normalizeEntailRegime(regime) });
386
414
  return makeFnDataset(
387
415
  rows.map((row) => dataFactory.quad(row.get('s'), row.get('p'), row.get('o'))));
388
416
  }
389
417
 
390
418
  /**
391
- * SHACL Core validation. Needs the npm-entry engine bundle. Neither
419
+ * SHACL Core validation. Neither
392
420
  * argument is mutated or consumed -- both stay valid FnDatasets after
393
421
  * the call, same as every other op in this module.
394
422
  *
@@ -401,13 +429,13 @@ async function entail(ds, regime) {
401
429
  async function validate(ds, shapes) {
402
430
  assertFnDataset(ds, 'validate');
403
431
  assertFnDataset(shapes, 'validate');
404
- const r = await engineApi.shaclValidate(toDataset(ds), toDataset(shapes));
405
- return { conforms: r.conforms, report: fromDataset(r.report) };
432
+ const r = await engineApi.shaclValidate((await engineOf(ds)), (await engineOf(shapes)));
433
+ return { conforms: r.conforms, report: wrapEngine(r.report) };
406
434
  }
407
435
 
408
436
  /**
409
437
  * ShEx (Shape Expressions) validation of one focus node against one
410
- * shape. Needs the npm-entry engine bundle.
438
+ * shape.
411
439
  *
412
440
  * @param {FnDataset} ds the data graph
413
441
  * @param {string} schema ShExJ (JSON Schema form), as text
@@ -420,14 +448,13 @@ async function validate(ds, shapes) {
420
448
  */
421
449
  async function shex(ds, schema, focus, shape) {
422
450
  assertFnDataset(ds, 'shex');
423
- return engineApi.shexValidate(toDataset(ds), schema, focus, shape);
451
+ return engineApi.shexValidate((await engineOf(ds)), schema, focus, shape);
424
452
  }
425
453
 
426
454
  /**
427
455
  * Evaluate an RML mapping graph against one logical source's raw
428
- * data, materializing the generated triples as a new FnDataset. Needs
429
- * the npm-entry engine bundle. Scope cut (documented, not silent):
430
- * every triples map in `mapping` reads the SAME `source` -- joins
456
+ * data, materializing the generated triples as a new FnDataset. Every
457
+ * triples map in `mapping` reads the SAME `source` -- joins
431
458
  * across two different logical sources are not reachable through this
432
459
  * one-source entry point (see engineApi.rmlMap's doc comment).
433
460
  *
@@ -438,13 +465,13 @@ async function shex(ds, schema, focus, shape) {
438
465
  */
439
466
  async function fromMapping(mapping, source, kind) {
440
467
  assertFnDataset(mapping, 'fromMapping');
441
- return fromDataset(await engineApi.rmlMap(toDataset(mapping), source, kind));
468
+ return wrapEngine(await engineApi.rmlMap((await engineOf(mapping)), source, kind));
442
469
  }
443
470
 
444
471
  /**
445
472
  * CSVW csv2rdf conversion (w3.org/TR/csv2rdf): convert raw tabular
446
473
  * data plus an optional CSVW metadata document into a new FnDataset.
447
- * Needs the npm-entry engine bundle. Unlike fromMapping there is no
474
+ * Unlike fromMapping there is no
448
475
  * FnDataset input -- both arguments are raw text (CSVW's metadata
449
476
  * format is JSON, not RDF). Scope cut (documented, not silent --
450
477
  * mirrors fromMapping's one-source cut): every table in a multi-table
@@ -461,14 +488,13 @@ async function fromMapping(mapping, source, kind) {
461
488
  * @returns {Promise<FnDataset>}
462
489
  */
463
490
  async function fromCsvw(csv, metadata, options) {
464
- return fromDataset(await engineApi.csvwToRdf(csv, metadata, options));
491
+ return wrapEngine(await engineApi.csvwToRdf(csv, metadata, options));
465
492
  }
466
493
 
467
494
  /**
468
495
  * RIF Core forward-chaining saturation, materialized as a new
469
496
  * FnDataset (input triples + derived triples, default graph only --
470
- * RIF Core has no named-graph notion). Needs the npm-entry engine
471
- * bundle.
497
+ * RIF Core has no named-graph notion).
472
498
  *
473
499
  * @param {FnDataset} ds the premise graph
474
500
  * @param {string} rules a RIF Core XML rule document
@@ -476,7 +502,7 @@ async function fromCsvw(csv, metadata, options) {
476
502
  */
477
503
  async function rif(ds, rules) {
478
504
  assertFnDataset(ds, 'rif');
479
- return fromDataset(await engineApi.rifEval(toDataset(ds), rules));
505
+ return wrapEngine(await engineApi.rifEval((await engineOf(ds)), rules));
480
506
  }
481
507
 
482
508
  /**
@@ -489,8 +515,7 @@ async function rif(ds, rules) {
489
515
  * Gutierrez, "Simple and Efficient Minimal RDFS", J. Web Semantics
490
516
  * 7(3), 2009). Mirrors engineApi.coreRdfsClosure's `{ok, ntriples}`
491
517
  * result, with `ntriples` parsed into an FnDataset via
492
- * Dataset.fromNQuads — pure JS, no extra engine round-trip. Needs the
493
- * npm-entry engine bundle. `rhoDfClosure` is kept below as a
518
+ * the engine Dataset of the closure. `rhoDfClosure` is kept below as a
494
519
  * literature-name alias.
495
520
  * @param {FnDataset} ds
496
521
  * @param {{format?: string}} [options]
@@ -498,17 +523,15 @@ async function rif(ds, rules) {
498
523
  */
499
524
  async function coreRdfsClosure(ds, options) {
500
525
  assertFnDataset(ds, 'coreRdfsClosure');
501
- const r = await engineApi.coreRdfsClosure(toDataset(ds), options);
502
- return { ok: r.ok, dataset: fromDataset(Dataset.fromNQuads(r.ntriples)) };
526
+ const r = await engineApi.coreRdfsClosure((await engineOf(ds)), options);
527
+ return { ok: true, dataset: wrapEngine(r) };
503
528
  }
504
529
  /** Literature-name alias for coreRdfsClosure (ρdf; see above). */
505
530
  const rhoDfClosure = coreRdfsClosure;
506
531
 
507
532
  /**
508
- * Decidable core-RDFS fragment check (`is_rho_df_frag`, tied by an F*
509
- * lemma to the prop the regime theorems quantify over): does the
510
- * certified coreRdfsClosure guarantee apply to `ds`? Needs the
511
- * npm-entry engine bundle. `rhoDfFragmentCheck` is kept below as a
533
+ * Decidable core-RDFS fragment check (L4Factoidal/RDFS, `isRhoDfFrag`):
534
+ * is `ds` in the core-RDFS fragment coreRdfsClosure is defined for? `rhoDfFragmentCheck` is kept below as a
512
535
  * literature-name alias.
513
536
  * @param {FnDataset} ds
514
537
  * @param {{format?: string}} [options]
@@ -516,7 +539,7 @@ const rhoDfClosure = coreRdfsClosure;
516
539
  */
517
540
  async function coreRdfsCheck(ds, options) {
518
541
  assertFnDataset(ds, 'coreRdfsCheck');
519
- return engineApi.coreRdfsCheck(toDataset(ds), options);
542
+ return engineApi.coreRdfsCheck((await engineOf(ds)), options);
520
543
  }
521
544
  /** Literature-name alias for coreRdfsCheck (ρdf; see above). */
522
545
  const rhoDfFragmentCheck = coreRdfsCheck;
@@ -529,19 +552,17 @@ const rhoDfFragmentCheck = coreRdfsCheck;
529
552
  * Allemang & Hendler 2008; "RDFS++", AllegroGraph). Every OWL row
530
553
  * carries a proved licensing + truth lemma; no chain-level
531
554
  * completeness claim (theorem registry) — weaker than
532
- * coreRdfsClosure's decides-iff guarantee. Needs the npm-entry engine
533
- * bundle.
555
+ * coreRdfsClosure's decides-iff guarantee.
534
556
  * @param {FnDataset} ds
535
557
  * @param {{format?: string}} [options]
536
- * @returns {Promise<{ok: boolean, dataset: FnDataset, rounds: number}>}
558
+ * @returns {Promise<{ok: boolean, dataset: FnDataset}>}
537
559
  */
538
560
  async function rdfsPlusClosure(ds, options) {
539
561
  assertFnDataset(ds, 'rdfsPlusClosure');
540
- const r = await engineApi.rdfsPlusClosure(toDataset(ds), options);
562
+ const r = await engineApi.rdfsPlusClosure((await engineOf(ds)), options);
541
563
  return {
542
- ok: r.ok,
543
- dataset: fromDataset(Dataset.fromNQuads(r.ntriples)),
544
- rounds: r.rounds,
564
+ ok: true,
565
+ dataset: wrapEngine(r),
545
566
  };
546
567
  }
547
568
 
@@ -551,7 +572,7 @@ async function rdfsPlusClosure(ds, options) {
551
572
  * individual the model-construction reasoner proves is a member of an
552
573
  * OWL class expression (someValuesFrom / hasValue / unionOf /
553
574
  * intersectionOf, and the named class an equivalentClass restriction
554
- * defines). Needs the npm-entry engine bundle. Default graph only.
575
+ * defines). Default graph only.
555
576
  *
556
577
  * @param {FnDataset} ds the ontology + ABox graph
557
578
  * @returns {Promise<{dataset: FnDataset, addedCount: number}>} dataset
@@ -560,31 +581,29 @@ async function rdfsPlusClosure(ds, options) {
560
581
  */
561
582
  async function tableauMaterialise(ds) {
562
583
  assertFnDataset(ds, 'tableauMaterialise');
563
- const r = await engineApi.tableauMaterialise(toDataset(ds));
564
- return { dataset: fromDataset(r.dataset), addedCount: r.addedCount };
584
+ const r = await engineApi.tableauMaterialise((await engineOf(ds)));
585
+ return { dataset: wrapEngine(r.dataset), addedCount: r.addedCount };
565
586
  }
566
587
 
567
588
  /**
568
589
  * OWL DL inconsistency verdict (bin/owl-runner's DL pipeline: OWL-RL
569
590
  * closure -> tableau materialise -> OWL-RL closure -> is_inconsistent).
570
591
  * `rlAlone` is the plain OWL-RL verdict on the same input, so a caller
571
- * can see the cases the tableau adds. Needs the npm-entry engine
572
- * bundle. Default graph only.
592
+ * can see the cases the tableau adds. Default graph only.
573
593
  *
574
594
  * @param {FnDataset} ds the ontology + ABox graph
575
595
  * @returns {Promise<{inconsistent: boolean, rlAlone: boolean}>}
576
596
  */
577
597
  async function tableauDlInconsistent(ds) {
578
598
  assertFnDataset(ds, 'tableauDlInconsistent');
579
- return engineApi.tableauDlInconsistent(toDataset(ds));
599
+ return engineApi.tableauDlInconsistent((await engineOf(ds)));
580
600
  }
581
601
 
582
602
  /**
583
603
  * OWL DL consistency verdict via the verified clash-detecting tableau
584
604
  * (formal/fstar/Tableau.Refute.fst's `tableau_consistent` over the
585
605
  * OWL-RL closure -- the pure verified chain bin/owl-runner runs under
586
- * `--regime dl`, minus its native-only z3 oracle). Needs the npm-entry
587
- * bundle. Default graph only.
606
+ * `--regime dl`, minus its native-only z3 oracle). Default graph only.
588
607
  *
589
608
  * `consistent` is three-valued: `false` (a clash on every tableau
590
609
  * branch), `true` (a model was constructed), or `null` -- the refuter
@@ -597,7 +616,7 @@ async function tableauDlInconsistent(ds) {
597
616
  * @returns {Promise<{consistent: boolean|null, reason?: string}>}
598
617
  */
599
618
  async function owlIsConsistent(ontology, options) {
600
- const data = ontology instanceof FnDataset ? toDataset(ontology) : ontology;
619
+ const data = ontology instanceof FnDataset ? (await engineOf(ontology)) : ontology;
601
620
  return engineApi.owlIsConsistent(data, options);
602
621
  }
603
622
 
@@ -605,7 +624,7 @@ async function owlIsConsistent(ontology, options) {
605
624
  * OWL entailment check: does `premise` entail `conclusion`? Verified
606
625
  * two-path dispatch (`via: "closure"` for the OWL-RL closure path,
607
626
  * `via: "refutation"` for negate-and-refute), mirroring bin/owl-runner.
608
- * Needs the npm-entry bundle. Default graph only. `entailed` is
627
+ * Default graph only. `entailed` is
609
628
  * three-valued (`true` / `false` / `null` budget-out, `reason` names the
610
629
  * cap).
611
630
  *
@@ -615,20 +634,20 @@ async function owlIsConsistent(ontology, options) {
615
634
  * @returns {Promise<{entailed: boolean|null, via: 'closure'|'refutation', reason?: string}>}
616
635
  */
617
636
  async function owlEntails(premise, conclusion, options) {
618
- const p = premise instanceof FnDataset ? toDataset(premise) : premise;
619
- const c = conclusion instanceof FnDataset ? toDataset(conclusion) : conclusion;
637
+ const p = premise instanceof FnDataset ? (await engineOf(premise)) : premise;
638
+ const c = conclusion instanceof FnDataset ? (await engineOf(conclusion)) : conclusion;
620
639
  return engineApi.owlEntails(p, c, options);
621
640
  }
622
641
 
623
642
  /**
624
- * RDFC-1.0 canonicalization: canonical N-Quads text. Needs the
625
- * npm-entry bundle (same gating as index.js's canonicalize()).
643
+ * RDFC-1.0 canonicalization: canonical N-Quads text (index.js's
644
+ * canonicalize()).
626
645
  */
627
646
  async function canonicalize(ds) {
628
647
  assertFnDataset(ds, 'canonicalize');
629
648
  let cached = CANON_CACHE.get(ds);
630
649
  if (cached === undefined) {
631
- const p = engineApi.canonicalize(toDataset(ds)).then((text) => {
650
+ const p = engineApi.canonicalize((await engineOf(ds))).then((text) => {
632
651
  CANON_CACHE.set(ds, text); // replace the in-flight promise
633
652
  return text;
634
653
  });
@@ -719,60 +738,6 @@ async function equals(a, b) {
719
738
  return h1 === h2;
720
739
  }
721
740
 
722
- /**
723
- * Open a COTTAS/Parquet artifact's raw bytes as a queryable, read-only
724
- * store (docs/designissues/2026-07-06-inmemory-bytes-store.md, browser
725
- * call site). Needs the npm-entry engine bundle. Unlike every other
726
- * constructor in this module, the returned object is NOT an FnDataset:
727
- * the whole point of the design is that rows decode lazily as a query
728
- * touches them, never materializing the corpus into heap FnDataset
729
- * quads (measured 64-161 B/quad vs. an FnDataset/heap Dataset's
730
- * ~877 B/quad for the same data, in the design doc's native numbers).
731
- *
732
- * @param {string|Uint8Array|ArrayBuffer} bytes whole `.cottas` file contents
733
- * @returns {Promise<{handle: string,
734
- * query: (sparql: string) => Promise<Array<Map<string,object>>|boolean|FnDataset>,
735
- * close: () => Promise<void>}>}
736
- * query() divergences from fn.query() (documented, not silent): no
737
- * entail option, no write/--delta-log overlay (read-only), and a
738
- * query shape the backend executor can't push down rejects instead
739
- * of silently falling back to a full materialize (see
740
- * engineApi.queryCottas's doc comment). CONSTRUCT still returns an
741
- * FnDataset (materialized once for that query only).
742
- */
743
- async function openCottas(bytes) {
744
- const handle = await engineApi.openCottas(bytes);
745
- let closed = false;
746
- return {
747
- handle,
748
- async query(sparql) {
749
- if (closed) throw new Error('openCottas store: query() called after close()');
750
- const result = await engineApi.queryCottas(handle, sparql);
751
- return result instanceof Dataset ? fromDataset(result) : result;
752
- },
753
- async close() {
754
- if (closed) return;
755
- closed = true;
756
- await engineApi.closeCottas(handle);
757
- },
758
- };
759
- }
760
-
761
- /**
762
- * Serialize an FnDataset to COTTAS/Parquet bytes via the native writer
763
- * (the same pure `Tot` F* function `factoidal compact --native-writer`
764
- * uses). Needs the npm-entry engine bundle. Round-trips through
765
- * openCottas(): feeding the result straight back into openCottas()
766
- * reproduces the same queryable store.
767
- *
768
- * @param {FnDataset} ds
769
- * @returns {Promise<Uint8Array>}
770
- */
771
- async function toCottas(ds) {
772
- assertFnDataset(ds, 'toCottas');
773
- return engineApi.toCottas(toDataset(ds));
774
- }
775
-
776
741
  /**
777
742
  * Enumerate named graphs (default graph excluded), first-seen order.
778
743
  * Reuses index.js's graphs() enumeration; wraps each per-graph
@@ -780,8 +745,11 @@ async function toCottas(ds) {
780
745
  */
781
746
  function graphs(ds) {
782
747
  assertFnDataset(ds, 'graphs');
783
- return engineApi.graphs(toDataset(ds))
784
- .map(([iri, graphDataset]) => [iri, fromDataset(graphDataset)]);
748
+ const seen = new Map();
749
+ for (const q of ds) {
750
+ if (q.graph.termType !== 'DefaultGraph' && !seen.has(q.graph.value)) seen.set(q.graph.value, q.graph);
751
+ }
752
+ return [...seen].map(([iri, g]) => [iri, ds.match(null, null, null, g)]);
785
753
  }
786
754
 
787
755
  // ---------------------------------------------------------------------
@@ -860,7 +828,7 @@ function pipe(...fns) {
860
828
  // -----------------------------------------------------------------
861
829
  // Typed engine functions (#74). Re-exported unchanged from the JS
862
830
  // engine api — each is already a pure, value-in / value-out function
863
- // over one F*-extracted engine (XSLT, MathML, XForms, JSON Schema,
831
+ // over one engine op (XSLT, MathML, XForms, JSON Schema,
864
832
  // Schematron, TOAN CAS, matrix algebra), so they belong in the
865
833
  // functional surface as-is. See index.d.ts / fn.d.ts for signatures.
866
834
  // -----------------------------------------------------------------
@@ -875,12 +843,6 @@ const {
875
843
  toanSimplify,
876
844
  toanDiff,
877
845
  toanSubst,
878
- matrixDeterminant,
879
- matrixScalarProduct,
880
- matrixVectorProduct,
881
- matrixOuterProduct,
882
- sigmoidPoints,
883
- sigmoidFormulaMathml,
884
846
  vcSha256Hex,
885
847
  vcEd25519SecretToPublic,
886
848
  vcEd25519Sign,
@@ -921,8 +883,6 @@ module.exports = {
921
883
  canonicalize,
922
884
  hash,
923
885
  equals,
924
- openCottas,
925
- toCottas,
926
886
  graphs,
927
887
  cell,
928
888
  derive,
@@ -938,12 +898,6 @@ module.exports = {
938
898
  toanSimplify,
939
899
  toanDiff,
940
900
  toanSubst,
941
- matrixDeterminant,
942
- matrixScalarProduct,
943
- matrixVectorProduct,
944
- matrixOuterProduct,
945
- sigmoidPoints,
946
- sigmoidFormulaMathml,
947
901
  vcSha256Hex,
948
902
  vcEd25519SecretToPublic,
949
903
  vcEd25519Sign,