@factoidal/core 0.20.0 → 0.21.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/bin/pack-host.mjs CHANGED
@@ -363,6 +363,11 @@ export async function denoReexec (options) {
363
363
  return null
364
364
  }
365
365
  if (granted.indexOf('run') < 0 || granted.indexOf('read') < 0) return null
366
+ // A `deno compile` executable is not the deno command: given `run ...` it
367
+ // reads `run` as a factoidal command (found 2026-10-28, building the
368
+ // single-file executables of docs/designissues/2026-10-28-single-file-app.md).
369
+ // It packs in process instead.
370
+ if (!/^deno(\.exe)?$/i.test(Deno.execPath().split(/[\\/]/).pop())) return null
366
371
  const main = Deno.mainModule.startsWith('file://')
367
372
  ? fileUrlToPath(Deno.mainModule)
368
373
  : Deno.mainModule
package/bin/serve.mjs CHANGED
@@ -147,6 +147,8 @@ export async function openServedStore (root, options = {}) {
147
147
  const config = {}
148
148
  if (typeof options.queryPath === 'string') config.queryPath = options.queryPath
149
149
  if (typeof options.gspPath === 'string') config.gspPath = options.gspPath
150
+ // The Host and Origin guard (issue 1124): passed unread; the engine decides.
151
+ if (options.localGuard !== undefined && options.localGuard !== null) config.localGuard = options.localGuard
150
152
  const info = engine.callBlobIO('storeServeOpen',
151
153
  [manifestHex, JSON.stringify(artifacts), JSON.stringify(state), JSON.stringify(config)],
152
154
  concatenate(chunks)).envelope
@@ -233,6 +235,8 @@ export async function openServedTdb2 (root, options = {}) {
233
235
  const config = {}
234
236
  if (typeof options.queryPath === 'string') config.queryPath = options.queryPath
235
237
  if (typeof options.gspPath === 'string') config.gspPath = options.gspPath
238
+ // The Host and Origin guard (issue 1124): passed unread; the engine decides.
239
+ if (options.localGuard !== undefined && options.localGuard !== null) config.localGuard = options.localGuard
236
240
  const info = engine.callBlobIO('tdb2ServeOpen',
237
241
  [JSON.stringify(files), JSON.stringify(config)], concatenate(chunks)).envelope
238
242
  const handle = info.handle
@@ -343,9 +347,22 @@ function serveConnection (served, socket, onError) {
343
347
  */
344
348
  export async function listen (root, options = {}) {
345
349
  const net = await import('node:net')
350
+ const host = typeof options.host === 'string' ? options.host : '127.0.0.1'
351
+ // `factoidal serve` has no authentication: the engine answers only the
352
+ // listener's own names and refuses writes from another origin
353
+ // (https://github.com/danbri/factoidal/issues/1124). Data for its check.
354
+ const os = await import('node:os')
355
+ let addresses = []
356
+ try { addresses = Object.values(os.networkInterfaces()).flat().filter(Boolean).map((i) => i.address) } catch (_error) { addresses = [] }
357
+ const localGuard = {
358
+ host,
359
+ addresses,
360
+ ...(Array.isArray(options.allowHosts) ? { allowHosts: options.allowHosts } : {}),
361
+ ...(Array.isArray(options.allowOrigins) ? { allowOrigins: options.allowOrigins } : {})
362
+ }
346
363
  const served = options.tdb2 === true
347
- ? await openServedTdb2(root, options)
348
- : await openServedStore(root, options)
364
+ ? await openServedTdb2(root, { ...options, localGuard })
365
+ : await openServedStore(root, { ...options, localGuard })
349
366
  const onError = typeof options.onError === 'function'
350
367
  ? options.onError
351
368
  : (error) => { console.error(`factoidal serve: ${error && error.message ? error.message : error}`) }
@@ -356,7 +373,6 @@ export async function listen (root, options = {}) {
356
373
  serveConnection(served, socket, onError)
357
374
  })
358
375
  const port = typeof options.port === 'number' ? options.port : 0
359
- const host = typeof options.host === 'string' ? options.host : '127.0.0.1'
360
376
  await new Promise((resolve, reject) => {
361
377
  server.once('error', reject)
362
378
  server.listen(port, host, resolve)
package/browser.d.ts CHANGED
@@ -14,6 +14,7 @@ export type {
14
14
  Sbm11Reader, Sbm11Answer, Sbm11Store, Sbm11ReadEvidence, Sbm11Transport,
15
15
  LiteralValueData, LiteralValueResult,
16
16
  ExplainResult, StageInfo, EvidenceRecord, Wire, FactoidalNode, Pipeline, RunResult, RunOptions,
17
+ NodePort, GraphSource, GraphSpec, GraphIssue, GraphCheck, FactoidalGraph, GraphRunResult,
17
18
  } from './index';
18
19
 
19
20
  export {
@@ -26,6 +27,7 @@ export {
26
27
  canonicalHash,
27
28
  asDefaultGraph,
28
29
  isomorphic,
30
+ datasetMerge,
29
31
  fromQuads,
30
32
  literalValue,
31
33
  isValidLiteral,
@@ -42,6 +44,7 @@ export {
42
44
  memberOrdinal,
43
45
  openDataset,
44
46
  closure,
47
+ sparqlRlInfer,
45
48
  formats,
46
49
  queryRaw,
47
50
  queryHdt,
@@ -74,6 +77,7 @@ export {
74
77
  stages,
75
78
  node,
76
79
  pipe,
80
+ graph,
77
81
  run,
78
82
  rdfsPlusClosure,
79
83
  rhoDfClosure,
@@ -107,12 +111,18 @@ export {
107
111
  vcEd25519SecretToPublic,
108
112
  vcEd25519Sign,
109
113
  vcEd25519Verify,
114
+ xmlDecrypt,
115
+ xmlEncrypt,
116
+ jweDecrypt,
117
+ jweEncrypt,
110
118
  vcEddsaCreateFromCanonical,
111
119
  vcEddsaVerifyFromCanonical,
112
120
  vcCheckCredential,
113
121
  vcCheckCredentialSubject,
114
122
  vcCheckNoDataLoss,
115
123
  vcCheckRelatedResourceDigests,
124
+ cidValidate,
125
+ cidRetrieveVerificationMethod,
116
126
  didKeyResolve,
117
127
  capabilities,
118
128
  Dataset,
package/browser.js CHANGED
@@ -85,6 +85,7 @@ export const graphs = api.graphs;
85
85
  export const canonicalHash = api.canonicalHash;
86
86
  export const asDefaultGraph = api.asDefaultGraph;
87
87
  export const isomorphic = api.isomorphic;
88
+ export const datasetMerge = api.datasetMerge;
88
89
  export const fromQuads = api.fromQuads;
89
90
  // Literal values (https://github.com/danbri/factoidal/issues/1051): synchronous
90
91
  // after the engine is loaded.
@@ -103,6 +104,7 @@ export const memberIri = api.memberIri;
103
104
  export const memberOrdinal = api.memberOrdinal;
104
105
  export const openDataset = api.openDataset;
105
106
  export const closure = api.closure;
107
+ export const sparqlRlInfer = api.sparqlRlInfer;
106
108
  export const formats = api.formats;
107
109
  export const queryRaw = api.queryRaw;
108
110
  export const queryHdt = api.queryHdt;
@@ -136,6 +138,7 @@ export const explain = api.explain;
136
138
  export const stages = api.stages;
137
139
  export const node = api.node;
138
140
  export const pipe = api.pipe;
141
+ export const graph = api.graph;
139
142
  export const run = api.run;
140
143
  export const rdfsPlusClosure = api.rdfsPlusClosure;
141
144
  export const rhoDfClosure = api.rhoDfClosure;
@@ -177,12 +180,21 @@ export const vcSha256Hex = api.vcSha256Hex;
177
180
  export const vcEd25519SecretToPublic = api.vcEd25519SecretToPublic;
178
181
  export const vcEd25519Sign = api.vcEd25519Sign;
179
182
  export const vcEd25519Verify = api.vcEd25519Verify;
183
+
184
+ // XML Encryption 1.1 and JWE; AES through WebCrypto (lib/cipher-host.mjs)
185
+ export const xmlDecrypt = api.xmlDecrypt;
186
+ export const xmlEncrypt = api.xmlEncrypt;
187
+ export const jweDecrypt = api.jweDecrypt;
188
+ export const jweEncrypt = api.jweEncrypt;
180
189
  export const vcEddsaCreateFromCanonical = api.vcEddsaCreateFromCanonical;
181
190
  export const vcEddsaVerifyFromCanonical = api.vcEddsaVerifyFromCanonical;
182
191
  export const vcCheckCredential = api.vcCheckCredential;
183
192
  export const vcCheckCredentialSubject = api.vcCheckCredentialSubject;
184
193
  export const vcCheckNoDataLoss = api.vcCheckNoDataLoss;
185
194
  export const vcCheckRelatedResourceDigests = api.vcCheckRelatedResourceDigests;
195
+ // Controlled Identifiers v1.0 (https://github.com/danbri/factoidal/issues/1100).
196
+ export const cidValidate = api.cidValidate;
197
+ export const cidRetrieveVerificationMethod = api.cidRetrieveVerificationMethod;
186
198
  export const didKeyResolve = api.didKeyResolve;
187
199
 
188
200
  // Types, probes and metadata
package/index.d.ts CHANGED
@@ -530,6 +530,18 @@ export function closure(
530
530
  options?: { format?: DataFormat; baseIRI?: string }
531
531
  ): Promise<Dataset>;
532
532
 
533
+ /**
534
+ * SPARQL 1.2 RL infer (https://w3c.github.io/data-shapes/sparql12-rl/): the
535
+ * inference graph of the rule set `rules` (SPARQL-RL text) over the default
536
+ * graph of `data`, as a new Dataset. Rejects when the rule set has a syntax
537
+ * error, is not well-formed or not stratifiable, or has IMPORTS.
538
+ */
539
+ export function sparqlRlInfer(
540
+ data: DataInput,
541
+ rules: string,
542
+ options?: { format?: DataFormat; baseIRI?: string }
543
+ ): Promise<Dataset>;
544
+
533
545
  /** The syntaxes the engine reads and writes, from the engine (op datasetFormats). */
534
546
  export function formats(): Promise<FormatCapability[]>;
535
547
 
@@ -574,9 +586,16 @@ export function graphs(dataset: Dataset): Array<[name: NamedNode | BlankNode, gr
574
586
  * differ only in their graph names got the same hash. To hash a graph
575
587
  * whatever its name (for example one entry of graphs()), use
576
588
  * canonicalHash(asDefaultGraph(g)). Rejects when the input holds an RDF 1.2
577
- * triple term or the section 4.4 call budget is exceeded.
578
- */
579
- export function canonicalHash(dataset: Dataset): Promise<string>;
589
+ * triple term or the section 4.4 call budget is exceeded. The input is what
590
+ * canonicalize() takes: a Dataset, or text with `format` and `baseIRI`.
591
+ * Text is a JavaScript string (characters, not bytes): decode bytes first;
592
+ * the RDF text syntaxes are UTF-8 (`new TextDecoder('utf-8', { fatal: true })`).
593
+ * A Uint8Array is refused.
594
+ */
595
+ export function canonicalHash(
596
+ data: Dataset | string | { text: string; format?: DataFormat; baseIRI?: string },
597
+ options?: { format?: DataFormat; baseIRI?: string },
598
+ ): Promise<string>;
580
599
 
581
600
  /**
582
601
  * A new Dataset with the triples of every graph of `dataset`, all in the
@@ -593,6 +612,15 @@ export function asDefaultGraph(dataset: Dataset): Dataset;
593
612
  */
594
613
  export function isomorphic(a: DataInput, b: DataInput, options?: { format?: string; baseIRI?: string }): Promise<boolean>;
595
614
 
615
+ /**
616
+ * The RDF merge of two datasets (RDF 1.1 Semantics 5.2): the quads of both,
617
+ * with the blank nodes of each input kept apart (`_:b` in `a` and `_:b` in
618
+ * `b` are two blank nodes). The engine computes it (op datasetMerge, Lean
619
+ * theorem mergeDatasets_isMerge). Prefixes: those of `a`, then those of `b`
620
+ * whose label `a` does not declare. Since 0.21.0.
621
+ */
622
+ export function datasetMerge(a: DataInput, b: DataInput, options?: { format?: string; baseIRI?: string }): Promise<Dataset>;
623
+
596
624
  /** A Dataset holding RDF/JS quads; each term is sent to the engine as its components. */
597
625
  export function fromQuads(quads: Iterable<Quad>): Promise<Dataset>;
598
626
 
@@ -937,17 +965,30 @@ export interface Wire<G = unknown> {
937
965
  evidence: EvidenceRecord[];
938
966
  }
939
967
 
968
+ /** An input port of a node: its name and its wire. */
969
+ export interface NodePort {
970
+ readonly name: string;
971
+ readonly wire: string;
972
+ }
973
+
940
974
  /** A node: a registered stage with its parameters. */
941
975
  export interface FactoidalNode {
942
976
  readonly stage: string;
943
977
  readonly kind: string | null;
944
978
  /** The engine's status of this node with its settings (see NodeStatus). */
945
979
  readonly status: NodeStatus;
946
- /** The registry status of the stage. */
947
- readonly registryStatus: StageInfo['status'];
980
+ /** The registry status of the stage; null for a stage with more than one port (not a registry entry). */
981
+ readonly registryStatus: StageInfo['status'] | null;
948
982
  readonly contract: string | null;
949
983
  readonly assumptions: readonly string[];
950
- readonly wireIn: string;
984
+ /**
985
+ * The input ports: one port 'in' for a registry stage; for a stage with
986
+ * more than one port (datasetMerge: 'left', 'right'), the engine's list
987
+ * (op graphCheckNodes). Such a node runs only in graph().
988
+ */
989
+ readonly ports: readonly NodePort[];
990
+ /** The input wire of a one-port stage; null for a stage with more than one port. */
991
+ readonly wireIn: string | null;
951
992
  /**
952
993
  * The output wire with these settings: for shippedEvaluator, 'Table' for
953
994
  * SELECT, 'Answer' for ASK, 'Dataset' for CONSTRUCT and DESCRIBE (Lean
@@ -1047,9 +1088,74 @@ export function stages(): Promise<StageInfo[]>;
1047
1088
  */
1048
1089
  export function node(name: string, params?: Record<string, unknown>): Promise<FactoidalNode>;
1049
1090
 
1050
- /** Compose nodes and pipelines left to right. */
1091
+ /** Compose nodes and pipelines left to right. A node with more than one input port throws a TypeError (use graph()). */
1051
1092
  export function pipe(...nodes: Array<FactoidalNode | Pipeline>): Pipeline;
1052
1093
 
1094
+ /** Where a port's value comes from: graph input `input`, or the output of node `node` (an earlier node). */
1095
+ export type GraphSource = { readonly input: number } | { readonly node: number };
1096
+
1097
+ /** The request of graph(). */
1098
+ export interface GraphSpec {
1099
+ /** The wire of each graph input: a wire label of stages() (e.g. 'String', 'Dataset'). */
1100
+ inputs?: string[];
1101
+ /** The nodes in order; `from` has one source per input port of the node. */
1102
+ nodes: Array<{ node: FactoidalNode; from: GraphSource[] }>;
1103
+ }
1104
+
1105
+ /** An issue of the engine's static check of a graph (op graphCheckNodes, Lean graphIssues). */
1106
+ export type GraphIssue =
1107
+ | { readonly kind: 'unknownInput'; readonly node: number; readonly port: number; readonly portName: string; readonly input: number }
1108
+ | { readonly kind: 'forwardRef'; readonly node: number; readonly port: number; readonly portName: string; readonly ref: number }
1109
+ | { readonly kind: 'portCount'; readonly node: number; readonly ports: number; readonly sources: number }
1110
+ | { readonly kind: 'wireMismatch'; readonly node: number; readonly port: number; readonly portName: string; readonly source: string; readonly portWire: string };
1111
+
1112
+ /** The engine's check of a graph with no issue (op graphCheckNodes). */
1113
+ export interface GraphCheck {
1114
+ readonly issues: readonly GraphIssue[];
1115
+ /** The output wire of the last node. */
1116
+ readonly wireOut: string | null;
1117
+ /** The union of the nodes' named assumptions: the premises of Graph.guarantee_sound. */
1118
+ readonly assumptions: readonly string[];
1119
+ readonly contract: { readonly theorem: string; readonly staticCheck: string };
1120
+ readonly nodes: readonly {
1121
+ readonly name: string; readonly kind: string | null; readonly status: NodeStatus;
1122
+ /** null for a stage with more than one port (not a registry entry). */
1123
+ readonly registryStatus: StageInfo['status'] | null;
1124
+ readonly checked: boolean; readonly contract: string | null;
1125
+ readonly theorems: readonly string[]; readonly assumptions: readonly string[];
1126
+ readonly ports: readonly NodePort[]; readonly wireOut: string;
1127
+ readonly settings: Record<string, unknown>; readonly settingsDigest: string;
1128
+ readonly roles: Readonly<Record<string, string>>;
1129
+ readonly outside: readonly OutsideSetting[];
1130
+ readonly derived: Readonly<Record<string, string>>;
1131
+ }[];
1132
+ }
1133
+
1134
+ /** A graph from graph(): checked by the engine, with no issue. */
1135
+ export interface FactoidalGraph {
1136
+ readonly inputs: readonly string[];
1137
+ readonly nodes: readonly { readonly node: FactoidalNode; readonly from: readonly GraphSource[] }[];
1138
+ readonly wireOut: string | null;
1139
+ readonly assumptions: readonly string[];
1140
+ readonly check: GraphCheck;
1141
+ }
1142
+
1143
+ /** The result of run() on a graph. */
1144
+ export interface GraphRunResult<G = unknown> extends RunResult<G> {
1145
+ /** The output of each node, in order; `graph` is the last one. */
1146
+ values: unknown[];
1147
+ issues: GraphIssue[];
1148
+ }
1149
+
1150
+ /**
1151
+ * A pipeline that is an acyclic graph of nodes with named input ports
1152
+ * (https://github.com/danbri/factoidal/issues/1130). The engine's op
1153
+ * graphCheckNodes checks it: a graph with an issue throws a FactoidalError
1154
+ * (code 'op.failed') whose `issues` is the engine's list; an engine without
1155
+ * the op throws code 'op.unknown'. Since 0.21.0.
1156
+ */
1157
+ export function graph(spec: GraphSpec): FactoidalGraph;
1158
+
1053
1159
  /**
1054
1160
  * Run a node or pipeline on `input` (a Wire, or the graph: text for a
1055
1161
  * reader, else a Dataset or data input). Rejects before any node runs when
@@ -1061,6 +1167,12 @@ export function pipe(...nodes: Array<FactoidalNode | Pipeline>): Pipeline;
1061
1167
  * `wireOut` (see Wire).
1062
1168
  */
1063
1169
  export function run(pipeline: FactoidalNode | Pipeline, input: unknown, options?: RunOptions): Promise<RunResult>;
1170
+ /**
1171
+ * Run a graph on `inputs`, one value per graph input. Each node runs on the
1172
+ * values of its sources (a node with more than one port gets them in port
1173
+ * order); one evidence record per node, with `node` (its index) and `from`.
1174
+ */
1175
+ export function run(graph: FactoidalGraph, inputs: unknown[], options?: RunOptions): Promise<GraphRunResult>;
1064
1176
 
1065
1177
  /** Literature-name alias for coreRdfsClosure (ρdf). */
1066
1178
  export function rhoDfClosure(
@@ -1374,6 +1486,10 @@ export interface Sbm11Store {
1374
1486
  terms: number;
1375
1487
  /** how the engine checks reads; undefined from a wasm module built before the Merkle check */
1376
1488
  verify: 'merkle' | 'none' | undefined;
1489
+ /** the SHA-256 of the bytes of manifest.sbm11, 64 lowercase hex digits, as
1490
+ * the engine computed it at open (pin it, then give it as
1491
+ * `manifestSha256`); undefined from a wasm module built before issue 1105 */
1492
+ manifestSha256: string | undefined;
1377
1493
  query(sparql: string, options?: { base?: string; sparql12?: boolean; reference?: boolean }): Sbm11Answer;
1378
1494
  /** the resources the reader read, when its reader records them (lwsSbm11Reader) */
1379
1495
  readonly evidence: Sbm11ReadEvidence[] | undefined;
@@ -1384,8 +1500,13 @@ export interface Sbm11Store {
1384
1500
  * Node: `source` is a directory unless a reader is given or registered.
1385
1501
  * `verify` (default 'merkle'): the engine checks every byte it decodes against
1386
1502
  * the manifest's Merkle roots and refuses a changed file with its name;
1387
- * 'none' checks lengths only. */
1388
- export function openSbm11(source: string, options?: { reader?: Sbm11Reader; verify?: 'merkle' | 'none' }): Promise<Sbm11Store>;
1503
+ * 'none' checks lengths only.
1504
+ * `manifestSha256`: the trust anchor, the SHA-256 of the bytes of
1505
+ * manifest.sbm11 as 64 hex digits (https://github.com/danbri/factoidal/issues/1105);
1506
+ * the engine refuses the open when the manifest has another digest. */
1507
+ export function openSbm11(source: string, options?: {
1508
+ reader?: Sbm11Reader; verify?: 'merkle' | 'none'; manifestSha256?: string
1509
+ }): Promise<Sbm11Store>;
1389
1510
 
1390
1511
  /** Serve `source` with `reader`; `null` removes it. */
1391
1512
  export function registerSbm11Source(source: string, reader: Sbm11Reader | null): void;
@@ -1749,6 +1870,45 @@ export function vcEd25519Verify(
1749
1870
  signatureHex: string
1750
1871
  ): Promise<boolean>;
1751
1872
 
1873
+ /**
1874
+ * Decrypt every xenc:EncryptedData of an XML document (XML Encryption 1.1).
1875
+ * RSA-OAEP, ECDH-ES and X25519 run in the wasm (HACL*); AES runs in the
1876
+ * host's WebCrypto. Every failure after the structure check is the one
1877
+ * error "XML decryption failed".
1878
+ */
1879
+ export function xmlDecrypt(
1880
+ document: string,
1881
+ options: { keys: object[]; allowCbc?: boolean }
1882
+ ): Promise<{ document: string; canonical: string }>;
1883
+
1884
+ /** Encrypt an XML document element, or its content, for one recipient. */
1885
+ export function xmlEncrypt(
1886
+ document: string,
1887
+ options: {
1888
+ recipient: object;
1889
+ algorithm?: 'aes128-gcm' | 'aes256-gcm';
1890
+ keyTransport?: 'rsa-oaep-mgf1p' | 'rsa-oaep-sha256';
1891
+ keyWrap?: 'kw-aes128' | 'kw-aes256';
1892
+ content?: boolean;
1893
+ saml?: boolean;
1894
+ }
1895
+ ): Promise<{ document: string; canonical: string }>;
1896
+
1897
+ /**
1898
+ * Decrypt a compact JWE (RFC 7516). Every failure after the allowlist is
1899
+ * the one error "decryption failed".
1900
+ */
1901
+ export function jweDecrypt(
1902
+ token: string,
1903
+ options: { jwk: object }
1904
+ ): Promise<{ header: Record<string, unknown>; plaintext: Uint8Array }>;
1905
+
1906
+ /** Encrypt to a compact JWE (RFC 7516). */
1907
+ export function jweEncrypt(
1908
+ plaintext: Uint8Array | string,
1909
+ options: { alg: string; enc: string; jwk: object; header?: Record<string, unknown> }
1910
+ ): Promise<string>;
1911
+
1752
1912
  /**
1753
1913
  * Create an eddsa-rdfc-2022 Data Integrity proofValue (multibase-z,
1754
1914
  * base58btc) over already-canonicalized inputs — RDFC-1.0 canonical
@@ -1817,6 +1977,70 @@ export function vcCheckRelatedResourceDigests(
1817
1977
  credentialJson: string
1818
1978
  ): Promise<{ valid: boolean; reason?: string }>;
1819
1979
 
1980
+ /** One failed MUST of CID 1.0 §2 (cidValidate). */
1981
+ export interface CidValidationError {
1982
+ /** The engine's name of the failed MUST, e.g. 'idNotUrl', 'jwkPrivateMember'. */
1983
+ code: string;
1984
+ message: string;
1985
+ /** RFC 6901 JSON Pointer to the member, e.g. '/verificationMethod/1/publicKeyJwk/d'; '' is the whole document. */
1986
+ path: string;
1987
+ }
1988
+
1989
+ /**
1990
+ * Controlled Identifiers v1.0 §2 (https://www.w3.org/TR/cid-1.0/): check a
1991
+ * controlled identifier document. `valid` is the engine's answer
1992
+ * (L4Factoidal.CID.parseDocument); `errors` lists every failed MUST it found,
1993
+ * empty when valid. Issue 1100 item 9.
1994
+ */
1995
+ export function cidValidate(doc: string | object): Promise<{ valid: boolean; errors: CidValidationError[] }>;
1996
+
1997
+ /** An RFC 9457 problem details object. */
1998
+ export interface CidProblem {
1999
+ /** https://w3id.org/security#<NAME> for a §3.5 error; a tag: URI for the others. */
2000
+ type: string;
2001
+ title: string;
2002
+ detail: string;
2003
+ }
2004
+
2005
+ export interface CidRetrieveOptions {
2006
+ /**
2007
+ * GET the URL the engine names. Called as fetch(url, init) with
2008
+ * init.headers.accept, init.redirect 'manual' and, when the engine chose
2009
+ * one, init.address (the address to connect to). Answers a Response, or
2010
+ * { status, headers: { get(name) }, text() }. Default: Node and Deno
2011
+ * connect to init.address; a browser uses the page's fetch.
2012
+ */
2013
+ fetch?: (url: string, init: { method: 'GET'; headers: { accept: string }; redirect: 'manual'; address?: string }) =>
2014
+ Promise<{ status: number; headers: { get(name: string): string | null }; text(): Promise<string> }>;
2015
+ /** Every address of a host name. Default: the system resolver (Node, Deno); none in a browser. null: none. */
2016
+ resolve?: ((host: string) => Promise<string[]>) | null;
2017
+ /** Refuse a method that has expired or been revoked at this time (a Date, or seconds since the epoch). */
2018
+ now?: Date | number;
2019
+ /** Allow an http document URL (default: https only). */
2020
+ allowHttp?: boolean;
2021
+ /** Allow loopback, link-local, private and localhost addresses (default: refused). */
2022
+ allowPrivateFetch?: boolean;
2023
+ }
2024
+
2025
+ /**
2026
+ * Controlled Identifiers v1.0 §3.3 Retrieve Verification Method. The engine
2027
+ * names each fetch and decides each answer (the private-address guard of the
2028
+ * authorization server, the status, the Content-Type: application/cid,
2029
+ * application/cid+json, application/ld+json or application/json, then §3.3);
2030
+ * this function does the fetch. Never rejects for a failed retrieval: it
2031
+ * answers `ok: false` with the §3.5 name (or FETCH_REFUSED, FETCH_FAILED,
2032
+ * UNSUPPORTED_MEDIA_TYPE, VERIFICATION_METHOD_NOT_IN_FORCE) and an RFC 9457
2033
+ * object. Issue 1100 items 7 and 9.
2034
+ */
2035
+ export function cidRetrieveVerificationMethod(
2036
+ url: string,
2037
+ relationship: 'authentication' | 'assertionMethod' | 'keyAgreement' | 'capabilityInvocation' | 'capabilityDelegation',
2038
+ options?: CidRetrieveOptions
2039
+ ): Promise<
2040
+ | { ok: true; verificationMethod: Record<string, unknown>; controllerDocument: string }
2041
+ | { ok: false; code: string; problem: CidProblem }
2042
+ >;
2043
+
1820
2044
  /**
1821
2045
  * Feature probe: which ops the loaded wasm module serves. A module older
1822
2046
  * than this package can lack some; an operation whose op is missing
@@ -1831,6 +2055,8 @@ export function capabilities(): Promise<{
1831
2055
  canonicalHash: boolean;
1832
2056
  shacl: boolean;
1833
2057
  shex: boolean;
2058
+ /** the engine has the SPARQL 1.2 RL op (datasetSparqlRlInfer) */
2059
+ sparqlRl: boolean;
1834
2060
  owlClosure: boolean;
1835
2061
  explain: boolean;
1836
2062
  stages: boolean;
@@ -1838,6 +2064,10 @@ export function capabilities(): Promise<{
1838
2064
  pipelineCheck: boolean;
1839
2065
  /** The op pipelineCheckNodes: node settings in evidence, and the evaluator's output wire from the query form. */
1840
2066
  pipelineCheckNodes: boolean;
2067
+ /** The op graphCheckNodes: graph() and run() of a graph, and node('datasetMerge'). */
2068
+ graphCheck: boolean;
2069
+ /** The op datasetMerge: datasetMerge(). */
2070
+ datasetMerge: boolean;
1841
2071
  tableau: boolean;
1842
2072
  rml: boolean;
1843
2073
  csvw: boolean;
@@ -1867,6 +2097,8 @@ export function capabilities(): Promise<{
1867
2097
  deltaLog: boolean;
1868
2098
  /** ops literalValue and literalFromValue (issue 1051). */
1869
2099
  literalValues: boolean;
2100
+ /** ops cidValidate and cidRetrieve (issue 1100). */
2101
+ cid: boolean;
1870
2102
  /** 'full': the whole library is in the wasm module. */
1871
2103
  profile: 'full' | string;
1872
2104
  /** The dispatch ABI version string of the loaded wasm module. */
@@ -1945,6 +2177,7 @@ declare const _default: {
1945
2177
  update: typeof update;
1946
2178
  openDataset: typeof openDataset;
1947
2179
  closure: typeof closure;
2180
+ sparqlRlInfer: typeof sparqlRlInfer;
1948
2181
  formats: typeof formats;
1949
2182
  serialize: typeof serialize;
1950
2183
  canonicalize: typeof canonicalize;
@@ -2005,12 +2238,18 @@ declare const _default: {
2005
2238
  vcEd25519SecretToPublic: typeof vcEd25519SecretToPublic;
2006
2239
  vcEd25519Sign: typeof vcEd25519Sign;
2007
2240
  vcEd25519Verify: typeof vcEd25519Verify;
2241
+ xmlDecrypt: typeof xmlDecrypt;
2242
+ xmlEncrypt: typeof xmlEncrypt;
2243
+ jweDecrypt: typeof jweDecrypt;
2244
+ jweEncrypt: typeof jweEncrypt;
2008
2245
  vcEddsaCreateFromCanonical: typeof vcEddsaCreateFromCanonical;
2009
2246
  vcEddsaVerifyFromCanonical: typeof vcEddsaVerifyFromCanonical;
2010
2247
  vcCheckCredential: typeof vcCheckCredential;
2011
2248
  vcCheckCredentialSubject: typeof vcCheckCredentialSubject;
2012
2249
  vcCheckNoDataLoss: typeof vcCheckNoDataLoss;
2013
2250
  vcCheckRelatedResourceDigests: typeof vcCheckRelatedResourceDigests;
2251
+ cidValidate: typeof cidValidate;
2252
+ cidRetrieveVerificationMethod: typeof cidRetrieveVerificationMethod;
2014
2253
  capabilities: typeof capabilities;
2015
2254
  Dataset: typeof Dataset;
2016
2255
  Store: typeof Store;
package/index.mjs CHANGED
@@ -25,6 +25,7 @@ import { sbm11Api, registerSbm11Source, setDefaultSbm11Reader, mapReader } from
25
25
  import { nodeDefaultReaderFactory } from './lib/sbm11-node.mjs';
26
26
  import { lwsSbm11Reader as lwsSbm11ReaderWith } from './lib/sbm11-lws.mjs';
27
27
  import { nodeSyncTransport } from './lib/sync-http-node.mjs';
28
+ import { nodeCidHost } from './lib/cid-node.mjs';
28
29
 
29
30
  /**
30
31
  * The loaded Lean engine handle: `call(op, args)`, `callBlob`,
@@ -45,6 +46,8 @@ const api = buildApi({
45
46
  engineName: 'lean4-wasm',
46
47
  loadEntry: async () => entryFromEngine(await loadEngine()),
47
48
  storeReaderFor: (root) => (path) => readFileSync(join(root, path)),
49
+ // Name resolution and a GET pinned to one address (issue 1100 item 9).
50
+ cidHost: nodeCidHost,
48
51
  });
49
52
 
50
53
  // RDF and SPARQL
@@ -57,6 +60,7 @@ export const graphs = api.graphs;
57
60
  export const canonicalHash = api.canonicalHash;
58
61
  export const asDefaultGraph = api.asDefaultGraph;
59
62
  export const isomorphic = api.isomorphic;
63
+ export const datasetMerge = api.datasetMerge;
60
64
  export const fromQuads = api.fromQuads;
61
65
  // Literal values (https://github.com/danbri/factoidal/issues/1051): synchronous
62
66
  // after the engine is loaded.
@@ -75,6 +79,7 @@ export const memberIri = api.memberIri;
75
79
  export const memberOrdinal = api.memberOrdinal;
76
80
  export const openDataset = api.openDataset;
77
81
  export const closure = api.closure;
82
+ export const sparqlRlInfer = api.sparqlRlInfer;
78
83
  export const formats = api.formats;
79
84
  export const queryRaw = api.queryRaw;
80
85
  export const queryHdt = api.queryHdt;
@@ -129,6 +134,7 @@ export const explain = api.explain;
129
134
  export const stages = api.stages;
130
135
  export const node = api.node;
131
136
  export const pipe = api.pipe;
137
+ export const graph = api.graph;
132
138
  export const run = api.run;
133
139
  export const rdfsPlusClosure = api.rdfsPlusClosure;
134
140
  export const rhoDfClosure = api.rhoDfClosure;
@@ -170,12 +176,21 @@ export const vcSha256Hex = api.vcSha256Hex;
170
176
  export const vcEd25519SecretToPublic = api.vcEd25519SecretToPublic;
171
177
  export const vcEd25519Sign = api.vcEd25519Sign;
172
178
  export const vcEd25519Verify = api.vcEd25519Verify;
179
+
180
+ // XML Encryption 1.1 and JWE; AES through WebCrypto (lib/cipher-host.mjs)
181
+ export const xmlDecrypt = api.xmlDecrypt;
182
+ export const xmlEncrypt = api.xmlEncrypt;
183
+ export const jweDecrypt = api.jweDecrypt;
184
+ export const jweEncrypt = api.jweEncrypt;
173
185
  export const vcEddsaCreateFromCanonical = api.vcEddsaCreateFromCanonical;
174
186
  export const vcEddsaVerifyFromCanonical = api.vcEddsaVerifyFromCanonical;
175
187
  export const vcCheckCredential = api.vcCheckCredential;
176
188
  export const vcCheckCredentialSubject = api.vcCheckCredentialSubject;
177
189
  export const vcCheckNoDataLoss = api.vcCheckNoDataLoss;
178
190
  export const vcCheckRelatedResourceDigests = api.vcCheckRelatedResourceDigests;
191
+ // Controlled Identifiers v1.0 (https://github.com/danbri/factoidal/issues/1100).
192
+ export const cidValidate = api.cidValidate;
193
+ export const cidRetrieveVerificationMethod = api.cidRetrieveVerificationMethod;
179
194
  export const didKeyResolve = api.didKeyResolve;
180
195
 
181
196
  // Types, probes and metadata
@@ -37,7 +37,7 @@
37
37
  // bytes change.
38
38
 
39
39
  // Stamped by formal/lean4/Wasm/build-wasm.sh step 9 -- do not hand-edit.
40
- const WASM_VERSION = "43c334ec5335";
40
+ const WASM_VERSION = "18074526651e";
41
41
 
42
42
  import createModule from './l4factoidal.mjs';
43
43
 
Binary file
@@ -2,17 +2,17 @@
2
2
  "engine": "lean4",
3
3
  "note": "The Lean 4 (L4Factoidal) engine build provenance and claims: the only engine of @factoidal/core since 0.9.0 (issue 713). This committed file is a placeholder. tools/fetch-builds.sh --set web (through tools/stamp-l4-version.mjs) writes the provenance members from the danbri/factoidal-builds release that built the wasm; formal/lean4/Wasm/build-wasm.sh step 9 writes them for a local build. Do not commit a stamped copy.",
4
4
  "stamped": true,
5
- "release": "danbri/factoidal-builds build-0c9a222bdb25-web",
6
- "releaseRun": "https://github.com/danbri/factoidal-builds/actions/runs/40662145237",
7
- "gitSha": "0c9a222bdb25ff70456611d3fbc87a41902d8324",
8
- "builtAt": "2026-10-28T09:52:07Z",
5
+ "release": "danbri/factoidal-builds build-7ab6936b6710-web",
6
+ "releaseRun": "https://github.com/danbri/factoidal-builds/actions/runs/40733510537",
7
+ "gitSha": "7ab6936b6710f2a68517a1fd3a1bf047e96c3c7c",
8
+ "builtAt": "2026-10-28T17:53:09Z",
9
9
  "leanToolchain": "leanprover/lean4:v4.33.1",
10
10
  "emscripten": "6.0.8",
11
11
  "abiVersion": "1",
12
12
  "engineVersion": "l4factoidal-wasm 0.2.0 (dispatch: RDF parse/serialize, SPARQL query+update, RDFS/OWL-RL closures, RDFC-1.0, CL/IKL)",
13
13
  "version": "l4factoidal-wasm 0.2.0 (dispatch: RDF parse/serialize, SPARQL query+update, RDFS/OWL-RL closures, RDFC-1.0, CL/IKL)",
14
- "wasmSha256": "43c334ec53357cd40339f693d303bda3e422ac92e94ad335cb6b0e83ec4eafbd",
15
- "wasmBytes": 17958911,
14
+ "wasmSha256": "18074526651eb00293b15be5c6d6e117e9d07271f1d104340b9d9ecff3b826c2",
15
+ "wasmBytes": 19211990,
16
16
  "claims": {
17
17
  "source": "formal/lean4 (L4Factoidal): no sorry, no user axioms, no native_decide; W3C behaviour pinned by build-time #guard",
18
18
  "suitesAtBuildSha": "see docs/test-results and formal/lean4/PORT_NOTES.md at gitSha"