eyeling 1.28.8 → 1.29.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.
@@ -5990,6 +5990,9 @@ async function main() {
5990
5990
  ` -p, --proof Enable proof explanations.\n` +
5991
5991
  ` -r, --rdf Enable RDF/TriG input/output compatibility.\n` +
5992
5992
  ` --stream-messages Process RDF Message Logs one message at a time under -r.\n` +
5993
+ ` --store <name> Use an optional persistent fact store.\n` +
5994
+ ` --store-clear Clear the named store before this run.\n` +
5995
+ ` --store-path <dir> Node.js persistent store directory.\n` +
5993
5996
  ` -s, --super-restricted Disable all builtins except => and <=.\n` +
5994
5997
  ` -t, --stream Stream derived triples as soon as they are derived.\n` +
5995
5998
  ` -v, --version Print version and exit.\n`;
@@ -6026,6 +6029,35 @@ async function main() {
6026
6029
  builtinModules.push(a.slice('--builtin='.length));
6027
6030
  continue;
6028
6031
  }
6032
+ if (a === '--store') {
6033
+ const next = argv[i + 1];
6034
+ if (!next || next.startsWith('-')) {
6035
+ console.error('Error: --store expects a store name.');
6036
+ process.exit(1);
6037
+ }
6038
+ argv.__storeName = next;
6039
+ i += 1;
6040
+ continue;
6041
+ }
6042
+ if (typeof a === 'string' && a.startsWith('--store=')) {
6043
+ argv.__storeName = a.slice('--store='.length);
6044
+ continue;
6045
+ }
6046
+ if (a === '--store-path') {
6047
+ const next = argv[i + 1];
6048
+ if (!next || next.startsWith('-')) {
6049
+ console.error('Error: --store-path expects a directory path.');
6050
+ process.exit(1);
6051
+ }
6052
+ argv.__storePath = next;
6053
+ i += 1;
6054
+ continue;
6055
+ }
6056
+ if (typeof a === 'string' && a.startsWith('--store-path=')) {
6057
+ argv.__storePath = a.slice('--store-path='.length);
6058
+ continue;
6059
+ }
6060
+ if (a === '--store-clear') continue;
6029
6061
  if (a === '-' || !a.startsWith('-')) positional.push(a);
6030
6062
  }
6031
6063
 
@@ -6033,6 +6065,9 @@ async function main() {
6033
6065
  const streamMode = argv.includes('--stream') || argv.includes('-t');
6034
6066
  const streamMessagesMode = argv.includes('--stream-messages');
6035
6067
  const rdfMode = argv.includes('--rdf') || argv.includes('-r');
6068
+ const storeName = argv.__storeName || null;
6069
+ const storePath = argv.__storePath || null;
6070
+ const storeClear = argv.includes('--store-clear');
6036
6071
 
6037
6072
  // --enforce-https: rewrite http:// -> https:// for log dereferencing builtins
6038
6073
  if (argv.includes('--enforce-https') || argv.includes('-e')) {
@@ -6056,6 +6091,10 @@ async function main() {
6056
6091
 
6057
6092
 
6058
6093
  if (streamMessagesMode) {
6094
+ if (storeName) {
6095
+ console.error('Error: --store cannot be combined with --stream-messages yet.');
6096
+ process.exit(1);
6097
+ }
6059
6098
  if (!rdfMode) {
6060
6099
  console.error('Error: --stream-messages requires -r/--rdf.');
6061
6100
  process.exit(1);
@@ -6211,6 +6250,69 @@ function factsContainOutputStrings(triplesForOutput) {
6211
6250
  const hasQueries = Array.isArray(qrules) && qrules.length;
6212
6251
  const mayAutoRenderOutputStrings = programMayProduceOutputStrings(triples, frules, qrules);
6213
6252
 
6253
+ if (storeName) {
6254
+ if (streamMode) {
6255
+ console.error('Error: --store cannot be combined with --stream yet.');
6256
+ process.exit(1);
6257
+ }
6258
+
6259
+ const storeResult = await engine.runAsync(
6260
+ { prefixes, triples, frules, brules, logQueryRules: qrules },
6261
+ {
6262
+ proof: engine.getProofCommentsEnabled(),
6263
+ rdf: rdfMode,
6264
+ store: { name: storeName, clear: storeClear, path: storePath || undefined },
6265
+ },
6266
+ );
6267
+
6268
+ const storeFacts = storeResult.facts || [];
6269
+ const storeDerived = storeResult.derived || [];
6270
+ const storeHasQueries = !!storeResult.queryMode;
6271
+ const storeOutTriples = storeHasQueries ? (storeResult.queryTriples || []) : (mayAutoRenderOutputStrings && !engine.getProofCommentsEnabled() ? [] : storeDerived.map((df) => df.fact));
6272
+ const storeOutDerived = storeHasQueries ? (storeResult.queryDerived || []) : storeDerived;
6273
+ const renderedOutputTriples = storeHasQueries ? storeOutTriples : storeFacts;
6274
+
6275
+ if (factsContainOutputStrings(renderedOutputTriples)) {
6276
+ process.stdout.write(engine.collectOutputStringsFromFacts(renderedOutputTriples, prefixes));
6277
+ if (storeResult.store && typeof storeResult.store.close === 'function') await storeResult.store.close();
6278
+ return;
6279
+ }
6280
+
6281
+ if (engine.getProofCommentsEnabled()) {
6282
+ process.stdout.write(engine.renderProofDocument(storeOutDerived, storeDerived.concat(storeOutDerived || []), triples, prefixes, brules));
6283
+ if (storeResult.store && typeof storeResult.store.close === 'function') await storeResult.store.close();
6284
+ return;
6285
+ }
6286
+
6287
+ let bodyText = '';
6288
+ if (rdfMode) bodyText = storeOutTriples.map((tr) => engine.tripleToRdfCompatible(tr, prefixes)).join('\n');
6289
+ else if (storeHasQueries) bodyText = engine.prettyPrintQueryTriples(storeOutTriples, prefixes);
6290
+
6291
+ let usedPrefixes = prefixes.prefixesUsedForOutput(storeOutTriples);
6292
+ if (rdfMode && bodyText) usedPrefixes = usedPrefixes.filter(([pfx]) => pfx === '' || bodyText.includes(pfx + ':'));
6293
+
6294
+ if (rdfMode && bodyText.includes('<<(')) {
6295
+ console.log('VERSION "1.2"');
6296
+ console.log();
6297
+ }
6298
+
6299
+ for (const [pfx, base] of usedPrefixes) {
6300
+ if (pfx === '') console.log(`@prefix : <${base}> .`);
6301
+ else console.log(`@prefix ${pfx}: <${base}> .`);
6302
+ }
6303
+ if (storeOutTriples.length && usedPrefixes.length) console.log();
6304
+
6305
+ if (bodyText) process.stdout.write(String(bodyText).replace(/\s*$/g, '') + '\n');
6306
+ else {
6307
+ for (const df of storeOutDerived) {
6308
+ console.log(rdfMode ? engine.tripleToRdfCompatible(df.fact, prefixes) : engine.tripleToN3(df.fact, prefixes));
6309
+ }
6310
+ }
6311
+
6312
+ if (storeResult.store && typeof storeResult.store.close === 'function') await storeResult.store.close();
6313
+ return;
6314
+ }
6315
+
6214
6316
  if (streamMode && !hasQueries && !mayAutoRenderOutputStrings && !engine.getProofCommentsEnabled()) {
6215
6317
  const usedInInput = mergedDocument.usedPrefixes instanceof Set ? new Set(mergedDocument.usedPrefixes) : new Set();
6216
6318
  const outPrefixes = restrictPrefixEnv(prefixes, usedInInput);
@@ -6886,6 +6988,7 @@ const {
6886
6988
  getDataFactory,
6887
6989
  internalTripleToRdfJsQuads,
6888
6990
  normalizeParsedReasonerInputSync,
6991
+ normalizeParsedReasonerInputAsync,
6889
6992
  normalizeReasonerInputSync,
6890
6993
  normalizeReasonerInputAsync,
6891
6994
  } = require('./rdfjs');
@@ -6894,6 +6997,7 @@ const trace = require('./trace');
6894
6997
  const { deterministicSkolemIdFromKey } = require('./skolem');
6895
6998
 
6896
6999
  const deref = require('./deref');
7000
+ const { createFactStore, collectStore, MemoryFactStore, PersistentFactStore } = require('./store');
6897
7001
 
6898
7002
  const hasOwn = Object.prototype.hasOwnProperty;
6899
7003
 
@@ -10572,6 +10676,120 @@ function reasonStream(input, opts = {}) {
10572
10676
  return __out;
10573
10677
  }
10574
10678
 
10679
+
10680
+ async function __parseRunAsyncInput(input, opts) {
10681
+ const {
10682
+ baseIri = null,
10683
+ proof = false,
10684
+ rdf = false,
10685
+ sourceLabel = '<input>',
10686
+ } = opts || {};
10687
+
10688
+ const parsedSourceList = parseN3SourceList(input, { baseIri, rdf: !!rdf, sourceLocations: !!proof });
10689
+ if (parsedSourceList) return parsedSourceList;
10690
+
10691
+ const parsedObject = await normalizeParsedReasonerInputAsync(input);
10692
+ if (parsedObject) {
10693
+ if (baseIri && parsedObject.prefixes && typeof parsedObject.prefixes.setBase === 'function') parsedObject.prefixes.setBase(baseIri);
10694
+ return parsedObject;
10695
+ }
10696
+
10697
+ const n3Text = await normalizeReasonerInputAsync(input);
10698
+ return parseN3Text(n3Text, {
10699
+ baseIri: baseIri || '',
10700
+ label: sourceLabel || '<input>',
10701
+ keepSourceArtifacts: false,
10702
+ sourceLocations: !!proof,
10703
+ rdf: !!rdf,
10704
+ });
10705
+ }
10706
+
10707
+ function __withoutStoreOptions(opts) {
10708
+ const out = { ...(opts || {}) };
10709
+ delete out.store;
10710
+ delete out.storePath;
10711
+ delete out.storeClear;
10712
+ return out;
10713
+ }
10714
+
10715
+ function __normalizeStoreOption(opts) {
10716
+ const cfg = opts && opts.store;
10717
+ if (!cfg) return null;
10718
+ if (typeof cfg === 'string') return { name: cfg, path: opts.storePath || undefined, clear: !!opts.storeClear };
10719
+ if (typeof cfg === 'object') {
10720
+ return {
10721
+ ...cfg,
10722
+ path: cfg.path || opts.storePath || undefined,
10723
+ clear: !!(cfg.clear || opts.storeClear),
10724
+ };
10725
+ }
10726
+ throw new TypeError('runAsync option "store" must be a store name string or a store options object');
10727
+ }
10728
+
10729
+ async function runAsync(input, opts = {}) {
10730
+ const storeConfig = __normalizeStoreOption(opts);
10731
+ const runOpts = __withoutStoreOptions(opts);
10732
+
10733
+ // No store configured: keep ordinary in-memory behavior, but accept async RDF/JS
10734
+ // iterables by normalizing the input before calling the synchronous engine.
10735
+ if (!storeConfig) {
10736
+ const normalizedInput = parseN3SourceList(input, {
10737
+ baseIri: runOpts.baseIri || null,
10738
+ rdf: !!runOpts.rdf,
10739
+ sourceLocations: !!runOpts.proof,
10740
+ }) || (await normalizeReasonerInputAsync(input));
10741
+ return reasonStream(normalizedInput, runOpts);
10742
+ }
10743
+
10744
+ const store = await createFactStore(storeConfig);
10745
+ let closeStore = true;
10746
+ try {
10747
+ const parsed = await __parseRunAsyncInput(input, runOpts);
10748
+
10749
+ // Persist the newly supplied explicit facts first, then include all stored
10750
+ // facts as the starting closure for this run. This lets --store reuse facts
10751
+ // across runs while keeping the current in-memory prover semantics intact.
10752
+ await store.batchAdd(parsed.triples || [], 'explicit');
10753
+ const storedTriples = await collectStore(store);
10754
+
10755
+ const storedKeys = new Set();
10756
+ for (const tr of storedTriples) storedKeys.add(require('./store').tripleToStoreKey(tr));
10757
+ const mergedTriples = storedTriples.slice();
10758
+ for (const tr of parsed.triples || []) {
10759
+ const key = require('./store').tripleToStoreKey(tr);
10760
+ if (!storedKeys.has(key)) {
10761
+ storedKeys.add(key);
10762
+ mergedTriples.push(tr);
10763
+ }
10764
+ }
10765
+
10766
+ const result = reasonStream(
10767
+ {
10768
+ prefixes: parsed.prefixes,
10769
+ triples: mergedTriples,
10770
+ frules: parsed.frules,
10771
+ brules: parsed.brules,
10772
+ logQueryRules: parsed.logQueryRules,
10773
+ },
10774
+ runOpts,
10775
+ );
10776
+
10777
+ await store.batchAdd((result.derived || []).map((df) => df.fact), 'inferred');
10778
+ result.store = store;
10779
+ closeStore = false;
10780
+ return result;
10781
+ } catch (e) {
10782
+ await store.close();
10783
+ throw e;
10784
+ } finally {
10785
+ // Keep result.store usable for callers. On exceptional paths it is closed
10786
+ // above; on success callers may close it when they are done.
10787
+ if (closeStore) {
10788
+ try { await store.close(); } catch {}
10789
+ }
10790
+ }
10791
+ }
10792
+
10575
10793
  function reasonRdfJs(input, opts = {}) {
10576
10794
  const { dataFactory = null, skipUnsupportedRdfJs = false, ...restOpts } = opts || {};
10577
10795
  const rdfFactory = getDataFactory(dataFactory);
@@ -10679,6 +10897,7 @@ function setTracePrefixes(v) {
10679
10897
 
10680
10898
  module.exports = {
10681
10899
  reasonStream,
10900
+ runAsync,
10682
10901
  reasonRdfJs,
10683
10902
  collectLogQueryConclusions,
10684
10903
  forwardChainAndCollectLogQueryConclusions,
@@ -10715,6 +10934,9 @@ module.exports = {
10715
10934
  loadBuiltinModule,
10716
10935
  listBuiltinIris,
10717
10936
  INFERENCE_FUSE_EXIT_CODE,
10937
+ createFactStore,
10938
+ MemoryFactStore,
10939
+ PersistentFactStore,
10718
10940
  };
10719
10941
 
10720
10942
  };
@@ -10738,6 +10960,7 @@ const { dataFactory } = require('./rdfjs');
10738
10960
  module.exports = {
10739
10961
  // public
10740
10962
  reasonStream: engine.reasonStream,
10963
+ runAsync: engine.runAsync,
10741
10964
  reasonRdfJs: engine.reasonRdfJs,
10742
10965
  rdfjs: dataFactory,
10743
10966
  main: engine.main,
@@ -10762,6 +10985,9 @@ module.exports = {
10762
10985
  registerBuiltinModule: engine.registerBuiltinModule,
10763
10986
  loadBuiltinModule: engine.loadBuiltinModule,
10764
10987
  listBuiltinIris: engine.listBuiltinIris,
10988
+ createFactStore: engine.createFactStore,
10989
+ MemoryFactStore: engine.MemoryFactStore,
10990
+ PersistentFactStore: engine.PersistentFactStore,
10765
10991
  getEnforceHttpsEnabled: engine.getEnforceHttpsEnabled,
10766
10992
  setEnforceHttpsEnabled: engine.setEnforceHttpsEnabled,
10767
10993
  getProofCommentsEnabled: engine.getProofCommentsEnabled,
@@ -13298,7 +13524,76 @@ function lex(inputText, opts = {}) {
13298
13524
  continue;
13299
13525
  }
13300
13526
 
13301
- // 5) Single-character punctuation. Use a switch rather than allocating a
13527
+ // 5) Numeric literal (integer, decimal, or double). Turtle/N3 numeric
13528
+ // literals may have a leading sign and decimals may start with '.', e.g.
13529
+ // '+42' and '.5'. Reject repeated decimal points so '1.2.3'
13530
+ // cannot be misread as one impossible numeric-like token.
13531
+ if (
13532
+ isAsciiDigit(c) ||
13533
+ ((c === '+' || c === '-') && (isAsciiDigit(peek(1)) || (peek(1) === '.' && isAsciiDigit(peek(2))))) ||
13534
+ (c === '.' && isAsciiDigit(peek(1)) && !isAsciiDigit(peek(-1)))
13535
+ ) {
13536
+ const start = i;
13537
+ const numChars = [];
13538
+
13539
+ if (chars[i] === '+' || chars[i] === '-') {
13540
+ numChars.push(chars[i]);
13541
+ i++;
13542
+ }
13543
+
13544
+ if (chars[i] === '.') {
13545
+ numChars.push('.');
13546
+ i++;
13547
+ while (i < n && isAsciiDigit(chars[i])) {
13548
+ numChars.push(chars[i]);
13549
+ i++;
13550
+ }
13551
+ } else {
13552
+ while (i < n && isAsciiDigit(chars[i])) {
13553
+ numChars.push(chars[i]);
13554
+ i++;
13555
+ }
13556
+ if (i < n && chars[i] === '.' && i + 1 < n && isAsciiDigit(chars[i + 1])) {
13557
+ numChars.push('.');
13558
+ i++;
13559
+ while (i < n && isAsciiDigit(chars[i])) {
13560
+ numChars.push(chars[i]);
13561
+ i++;
13562
+ }
13563
+ }
13564
+ }
13565
+
13566
+ if (i < n && chars[i] === '.' && i + 1 < n && isAsciiDigit(chars[i + 1])) {
13567
+ throw new N3SyntaxError('Malformed numeric literal: multiple decimal points', start);
13568
+ }
13569
+
13570
+ // Optional exponent part: e.g., 1e0, 1.1e-3, .5E+0.
13571
+ if (i < n && (chars[i] === 'e' || chars[i] === 'E')) {
13572
+ let j = i + 1;
13573
+ if (j < n && (chars[j] === '+' || chars[j] === '-')) j++;
13574
+ if (j < n && isAsciiDigit(chars[j])) {
13575
+ numChars.push(chars[i]); // e/E
13576
+ i++;
13577
+ if (i < n && (chars[i] === '+' || chars[i] === '-')) {
13578
+ numChars.push(chars[i]);
13579
+ i++;
13580
+ }
13581
+ while (i < n && isAsciiDigit(chars[i])) {
13582
+ numChars.push(chars[i]);
13583
+ i++;
13584
+ }
13585
+ }
13586
+ }
13587
+
13588
+ if (i < n && chars[i] === '.' && i + 1 < n && isAsciiDigit(chars[i + 1])) {
13589
+ throw new N3SyntaxError('Malformed numeric literal: multiple decimal points', start);
13590
+ }
13591
+
13592
+ tokens.push(new Token('Literal', numChars.join(''), start));
13593
+ continue;
13594
+ }
13595
+
13596
+ // 6) Single-character punctuation. Use a switch rather than allocating a
13302
13597
  // mapping object for every punctuation token in large inputs.
13303
13598
  switch (c) {
13304
13599
  case '{':
@@ -13419,13 +13714,17 @@ function lex(inputText, opts = {}) {
13419
13714
  }
13420
13715
  continue;
13421
13716
  }
13717
+ if (cc === '\n' || cc === '\r') {
13718
+ throw new N3SyntaxError('Unescaped newline in short string literal', start);
13719
+ }
13422
13720
  if (cc === '"') {
13423
13721
  closed = true;
13424
13722
  break;
13425
13723
  }
13426
13724
  if (sChars !== null) sChars.push(cc);
13427
13725
  }
13428
- const rawContent = sChars === null ? sliceChars(contentStart, closed ? i - 1 : i) : sChars.join('');
13726
+ if (!closed) throw new N3SyntaxError('Unterminated short string literal "..."', start);
13727
+ const rawContent = sChars === null ? sliceChars(contentStart, i - 1) : sChars.join('');
13429
13728
  const decoded = sChars === null ? rawContent : decodeN3StringEscapes(rawContent, start);
13430
13729
  if (sChars !== null || inputMayContainInvalidStringChar) assertValidStringLiteralValue(decoded, start);
13431
13730
  const s = JSON.stringify(decoded); // canonical short quoted form
@@ -13509,13 +13808,17 @@ function lex(inputText, opts = {}) {
13509
13808
  }
13510
13809
  continue;
13511
13810
  }
13811
+ if (cc === '\n' || cc === '\r') {
13812
+ throw new N3SyntaxError('Unescaped newline in short string literal', start);
13813
+ }
13512
13814
  if (cc === "'") {
13513
13815
  closed = true;
13514
13816
  break;
13515
13817
  }
13516
13818
  if (sChars !== null) sChars.push(cc);
13517
13819
  }
13518
- const rawContent = sChars === null ? sliceChars(contentStart, closed ? i - 1 : i) : sChars.join('');
13820
+ if (!closed) throw new N3SyntaxError("Unterminated short string literal '...'", start);
13821
+ const rawContent = sChars === null ? sliceChars(contentStart, i - 1) : sChars.join('');
13519
13822
  const decoded = sChars === null ? rawContent : decodeN3StringEscapes(rawContent, start);
13520
13823
  if (sChars !== null || inputMayContainInvalidStringChar) assertValidStringLiteralValue(decoded, start);
13521
13824
  const s = JSON.stringify(decoded); // canonical short quoted form
@@ -13598,52 +13901,6 @@ function lex(inputText, opts = {}) {
13598
13901
  continue;
13599
13902
  }
13600
13903
 
13601
- // 6) Numeric literal (integer or float)
13602
- if (isAsciiDigit(c) || (c === '-' && peek(1) !== null && isAsciiDigit(peek(1)))) {
13603
- const start = i;
13604
- const numChars = [c];
13605
- i++;
13606
- while (i < n) {
13607
- const cc = chars[i];
13608
- if (isAsciiDigit(cc)) {
13609
- numChars.push(cc);
13610
- i++;
13611
- continue;
13612
- }
13613
- if (cc === '.') {
13614
- if (i + 1 < n && isAsciiDigit(chars[i + 1])) {
13615
- numChars.push('.');
13616
- i++;
13617
- continue;
13618
- } else {
13619
- break;
13620
- }
13621
- }
13622
- break;
13623
- }
13624
-
13625
- // Optional exponent part: e.g., 1e0, 1.1e-3, 1.1E+0
13626
- if (i < n && (chars[i] === 'e' || chars[i] === 'E')) {
13627
- let j = i + 1;
13628
- if (j < n && (chars[j] === '+' || chars[j] === '-')) j++;
13629
- if (j < n && isAsciiDigit(chars[j])) {
13630
- numChars.push(chars[i]); // e/E
13631
- i++;
13632
- if (i < n && (chars[i] === '+' || chars[i] === '-')) {
13633
- numChars.push(chars[i]);
13634
- i++;
13635
- }
13636
- while (i < n && isAsciiDigit(chars[i])) {
13637
- numChars.push(chars[i]);
13638
- i++;
13639
- }
13640
- }
13641
- }
13642
-
13643
- tokens.push(new Token('Literal', numChars.join(''), start));
13644
- continue;
13645
- }
13646
-
13647
13904
  // 7) Identifiers / keywords / QNames
13648
13905
  const start = i;
13649
13906
  const word = readIdentText(start);
@@ -17019,6 +17276,7 @@ module.exports = {
17019
17276
  internalTripleToRdfJsQuads,
17020
17277
  internalTripleToRdfJsQuadInGraph,
17021
17278
  normalizeParsedReasonerInputSync,
17279
+ normalizeParsedReasonerInputAsync,
17022
17280
  normalizeReasonerInputSync,
17023
17281
  normalizeReasonerInputAsync,
17024
17282
  hasEyelingObjectInput,
@@ -17184,6 +17442,694 @@ module.exports = {
17184
17442
  deterministicSkolemIdFromKey,
17185
17443
  };
17186
17444
 
17445
+ };
17446
+ __modules["lib/store.js"] = function(require, module, exports){
17447
+ /**
17448
+ * Eyeling Reasoner — fact stores
17449
+ *
17450
+ * Optional async fact-store abstraction used by runAsync() and by tests. The
17451
+ * in-memory reasoner remains the default; persistent stores are opt-in.
17452
+ */
17453
+
17454
+ 'use strict';
17455
+
17456
+ const {
17457
+ Iri,
17458
+ Literal,
17459
+ Var,
17460
+ Blank,
17461
+ ListTerm,
17462
+ OpenListTerm,
17463
+ GraphTerm,
17464
+ Triple,
17465
+ } = require('./prelude');
17466
+
17467
+ const KIND_EXPLICIT = 1;
17468
+ const KIND_INFERRED = 2;
17469
+
17470
+ function __dynamicRequire(name) {
17471
+ try {
17472
+ // Keep this indirect so the browser bundle can include this module without
17473
+ // eagerly trying to bundle Node-only or optional Level dependencies.
17474
+ const req = typeof require === 'function' ? require : null;
17475
+ return req ? req(name) : null;
17476
+ } catch {
17477
+ return null;
17478
+ }
17479
+ }
17480
+
17481
+ function base64url(s) {
17482
+ const text = String(s);
17483
+ if (typeof Buffer !== 'undefined') return Buffer.from(text, 'utf8').toString('base64url');
17484
+ const encoder = globalThis.TextEncoder ? new globalThis.TextEncoder() : null;
17485
+ if (!encoder || typeof globalThis.btoa !== 'function') {
17486
+ throw new Error('No UTF-8/base64 encoder available for persistent store keys');
17487
+ }
17488
+ const bytes = encoder.encode(text);
17489
+ let bin = '';
17490
+ for (const b of bytes) bin += String.fromCharCode(b);
17491
+ return globalThis.btoa(bin).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
17492
+ }
17493
+
17494
+ function idPart(id) {
17495
+ return String(id).padStart(16, '0');
17496
+ }
17497
+
17498
+ function safeStoreName(name) {
17499
+ const text = String(name || 'default');
17500
+ return encodeURIComponent(text).replace(/%/g, '_');
17501
+ }
17502
+
17503
+ function termToJson(term) {
17504
+ if (term instanceof Iri) return ['Iri', term.value];
17505
+ if (term instanceof Literal) return ['Literal', term.value];
17506
+ if (term instanceof Var) return ['Var', term.name];
17507
+ if (term instanceof Blank) return ['Blank', term.label];
17508
+ if (term instanceof ListTerm) return ['ListTerm', term.elems.map(termToJson)];
17509
+ if (term instanceof OpenListTerm) return ['OpenListTerm', term.prefix.map(termToJson), term.tailVar];
17510
+ if (term instanceof GraphTerm) return ['GraphTerm', term.triples.map(tripleToJson)];
17511
+
17512
+ // RDF/JS terms, for callers that use the store abstraction directly.
17513
+ if (term && typeof term === 'object' && typeof term.termType === 'string') {
17514
+ switch (term.termType) {
17515
+ case 'NamedNode':
17516
+ return ['Iri', term.value];
17517
+ case 'BlankNode':
17518
+ return ['Blank', term.value && term.value.startsWith('_:') ? term.value : `_:${term.value}`];
17519
+ case 'Variable':
17520
+ return ['Var', term.value];
17521
+ case 'Literal': {
17522
+ const dt = term.datatype && term.datatype.termType === 'NamedNode' ? term.datatype.value : '';
17523
+ const lang = typeof term.language === 'string' ? term.language : '';
17524
+ const q = JSON.stringify(String(term.value));
17525
+ if (lang) return ['Literal', `${q}@${lang}`];
17526
+ if (!dt || dt === 'http://www.w3.org/2001/XMLSchema#string') return ['Literal', q];
17527
+ return ['Literal', `${q}^^<${dt}>`];
17528
+ }
17529
+ case 'Quad':
17530
+ return ['GraphTerm', [tripleToJson({ s: term.subject, p: term.predicate, o: term.object })]];
17531
+ case 'DefaultGraph':
17532
+ return ['DefaultGraph'];
17533
+ default:
17534
+ break;
17535
+ }
17536
+ }
17537
+
17538
+ throw new TypeError(`Unsupported fact-store term: ${term && term.constructor ? term.constructor.name : String(term)}`);
17539
+ }
17540
+
17541
+ function termFromJson(json) {
17542
+ if (!Array.isArray(json)) throw new TypeError('Invalid serialized term');
17543
+ switch (json[0]) {
17544
+ case 'Iri':
17545
+ return new Iri(json[1]);
17546
+ case 'Literal':
17547
+ return new Literal(json[1]);
17548
+ case 'Var':
17549
+ return new Var(json[1]);
17550
+ case 'Blank':
17551
+ return new Blank(json[1]);
17552
+ case 'ListTerm':
17553
+ return new ListTerm((json[1] || []).map(termFromJson));
17554
+ case 'OpenListTerm':
17555
+ return new OpenListTerm((json[1] || []).map(termFromJson), json[2]);
17556
+ case 'GraphTerm':
17557
+ return new GraphTerm((json[1] || []).map(tripleFromJson));
17558
+ case 'DefaultGraph':
17559
+ return new Iri('urn:eyeling:default-graph');
17560
+ default:
17561
+ throw new TypeError(`Unsupported serialized term type: ${json[0]}`);
17562
+ }
17563
+ }
17564
+
17565
+ function tripleToJson(triple) {
17566
+ return [termToJson(triple.s || triple.subject), termToJson(triple.p || triple.predicate), termToJson(triple.o || triple.object)];
17567
+ }
17568
+
17569
+ function tripleFromJson(json) {
17570
+ return new Triple(termFromJson(json[0]), termFromJson(json[1]), termFromJson(json[2]));
17571
+ }
17572
+
17573
+ function termToStoreKey(term) {
17574
+ return JSON.stringify(termToJson(term));
17575
+ }
17576
+
17577
+ function tripleToStoreKey(triple) {
17578
+ return JSON.stringify(tripleToJson(triple));
17579
+ }
17580
+
17581
+ function kindMask(kind) {
17582
+ if (kind === 'explicit') return KIND_EXPLICIT;
17583
+ if (kind === 'inferred') return KIND_INFERRED;
17584
+ if (typeof kind === 'number') return kind & (KIND_EXPLICIT | KIND_INFERRED);
17585
+ return KIND_EXPLICIT;
17586
+ }
17587
+
17588
+ class MemoryKv {
17589
+ constructor() {
17590
+ this.map = new Map();
17591
+ }
17592
+
17593
+ async get(key) {
17594
+ return this.map.get(key);
17595
+ }
17596
+
17597
+ async put(key, value) {
17598
+ this.map.set(key, value);
17599
+ }
17600
+
17601
+ async del(key) {
17602
+ this.map.delete(key);
17603
+ }
17604
+
17605
+ async clear() {
17606
+ this.map.clear();
17607
+ }
17608
+
17609
+ async batch(ops) {
17610
+ for (const op of ops || []) {
17611
+ if (!op) continue;
17612
+ if (op.type === 'del') this.map.delete(op.key);
17613
+ else this.map.set(op.key, op.value);
17614
+ }
17615
+ }
17616
+
17617
+ async *entries(prefix = '') {
17618
+ const keys = Array.from(this.map.keys())
17619
+ .filter((key) => key.startsWith(prefix))
17620
+ .sort();
17621
+ for (const key of keys) yield [key, this.map.get(key)];
17622
+ }
17623
+
17624
+ async close() {}
17625
+ }
17626
+
17627
+ class JsonFileKv extends MemoryKv {
17628
+ constructor(filePath) {
17629
+ super();
17630
+ this.filePath = filePath;
17631
+ this.loaded = false;
17632
+ this.dirty = false;
17633
+ }
17634
+
17635
+ async open() {
17636
+ if (this.loaded) return;
17637
+ this.loaded = true;
17638
+ const fs = __dynamicRequire('node:fs');
17639
+ const path = __dynamicRequire('node:path');
17640
+ if (!fs || !path) throw new Error('Persistent stores need node:fs in this runtime');
17641
+ fs.mkdirSync(path.dirname(this.filePath), { recursive: true });
17642
+ if (!fs.existsSync(this.filePath)) return;
17643
+ const text = fs.readFileSync(this.filePath, 'utf8');
17644
+ if (!text.trim()) return;
17645
+ const data = JSON.parse(text);
17646
+ this.map = new Map(Array.isArray(data.entries) ? data.entries : []);
17647
+ }
17648
+
17649
+ async flush() {
17650
+ if (!this.loaded || !this.dirty) return;
17651
+ const fs = __dynamicRequire('node:fs');
17652
+ const path = __dynamicRequire('node:path');
17653
+ fs.mkdirSync(path.dirname(this.filePath), { recursive: true });
17654
+ const tmp = `${this.filePath}.tmp`;
17655
+ fs.writeFileSync(tmp, JSON.stringify({ entries: Array.from(this.map.entries()) }), 'utf8');
17656
+ fs.renameSync(tmp, this.filePath);
17657
+ this.dirty = false;
17658
+ }
17659
+
17660
+ async get(key) {
17661
+ await this.open();
17662
+ return super.get(key);
17663
+ }
17664
+
17665
+ async put(key, value) {
17666
+ await this.open();
17667
+ await super.put(key, value);
17668
+ this.dirty = true;
17669
+ await this.flush();
17670
+ }
17671
+
17672
+ async del(key) {
17673
+ await this.open();
17674
+ await super.del(key);
17675
+ this.dirty = true;
17676
+ await this.flush();
17677
+ }
17678
+
17679
+ async clear() {
17680
+ await this.open();
17681
+ await super.clear();
17682
+ this.dirty = true;
17683
+ await this.flush();
17684
+ }
17685
+
17686
+ async batch(ops) {
17687
+ await this.open();
17688
+ await super.batch(ops);
17689
+ this.dirty = true;
17690
+ await this.flush();
17691
+ }
17692
+
17693
+ async *entries(prefix = '') {
17694
+ await this.open();
17695
+ yield* super.entries(prefix);
17696
+ }
17697
+
17698
+ async close() {
17699
+ await this.flush();
17700
+ }
17701
+ }
17702
+
17703
+ class ClassicLevelKv {
17704
+ constructor(location) {
17705
+ const classic = __dynamicRequire('classic-level');
17706
+ const ClassicLevel = classic && (classic.ClassicLevel || classic.Level || classic.default);
17707
+ if (!ClassicLevel) throw new Error('classic-level is not installed');
17708
+ this.db = new ClassicLevel(location, { valueEncoding: 'json' });
17709
+ this.opened = false;
17710
+ }
17711
+
17712
+ async open() {
17713
+ if (this.opened) return;
17714
+ if (typeof this.db.open === 'function') await this.db.open();
17715
+ this.opened = true;
17716
+ }
17717
+
17718
+ async get(key) {
17719
+ await this.open();
17720
+ try {
17721
+ return await this.db.get(key);
17722
+ } catch (e) {
17723
+ if (e && (e.notFound || e.code === 'LEVEL_NOT_FOUND' || e.code === 'NOT_FOUND')) return undefined;
17724
+ throw e;
17725
+ }
17726
+ }
17727
+
17728
+ async put(key, value) {
17729
+ await this.open();
17730
+ await this.db.put(key, value);
17731
+ }
17732
+
17733
+ async del(key) {
17734
+ await this.open();
17735
+ await this.db.del(key);
17736
+ }
17737
+
17738
+ async clear() {
17739
+ await this.open();
17740
+ if (typeof this.db.clear === 'function') await this.db.clear();
17741
+ else {
17742
+ const ops = [];
17743
+ for await (const [key] of this.entries('')) ops.push({ type: 'del', key });
17744
+ if (ops.length) await this.batch(ops);
17745
+ }
17746
+ }
17747
+
17748
+ async batch(ops) {
17749
+ await this.open();
17750
+ if (!ops || !ops.length) return;
17751
+ await this.db.batch(ops);
17752
+ }
17753
+
17754
+ async *entries(prefix = '') {
17755
+ await this.open();
17756
+ const gte = prefix;
17757
+ const lt = prefix + '\uffff';
17758
+ const iterator = this.db.iterator({ gte, lt });
17759
+ for await (const item of iterator) {
17760
+ if (Array.isArray(item)) yield item;
17761
+ else if (item && Array.isArray(item.key)) yield item.key;
17762
+ }
17763
+ }
17764
+
17765
+ async close() {
17766
+ if (this.db && typeof this.db.close === 'function') await this.db.close();
17767
+ }
17768
+ }
17769
+
17770
+ class IndexedDbKv {
17771
+ constructor(name) {
17772
+ this.name = name;
17773
+ this.dbPromise = null;
17774
+ }
17775
+
17776
+ open() {
17777
+ if (this.dbPromise) return this.dbPromise;
17778
+ const idb = typeof globalThis !== 'undefined' ? globalThis.indexedDB : null;
17779
+ if (!idb) throw new Error('IndexedDB is not available in this runtime');
17780
+ this.dbPromise = new Promise((resolve, reject) => {
17781
+ const req = idb.open(`eyeling:${this.name}`, 1);
17782
+ req.onupgradeneeded = () => {
17783
+ const db = req.result;
17784
+ if (!db.objectStoreNames.contains('kv')) db.createObjectStore('kv');
17785
+ };
17786
+ req.onerror = () => reject(req.error || new Error('Failed to open IndexedDB store'));
17787
+ req.onsuccess = () => resolve(req.result);
17788
+ });
17789
+ return this.dbPromise;
17790
+ }
17791
+
17792
+ async __tx(mode, fn) {
17793
+ const db = await this.open();
17794
+ return new Promise((resolve, reject) => {
17795
+ const tx = db.transaction('kv', mode);
17796
+ const store = tx.objectStore('kv');
17797
+ let value;
17798
+ tx.oncomplete = () => resolve(value);
17799
+ tx.onerror = () => reject(tx.error || new Error('IndexedDB transaction failed'));
17800
+ tx.onabort = () => reject(tx.error || new Error('IndexedDB transaction aborted'));
17801
+ try {
17802
+ value = fn(store, resolve, reject);
17803
+ } catch (e) {
17804
+ try { tx.abort(); } catch {}
17805
+ reject(e);
17806
+ }
17807
+ });
17808
+ }
17809
+
17810
+ async get(key) {
17811
+ return this.__tx('readonly', (store, resolve, reject) => {
17812
+ const req = store.get(key);
17813
+ req.onerror = () => reject(req.error);
17814
+ req.onsuccess = () => resolve(req.result);
17815
+ });
17816
+ }
17817
+
17818
+ async put(key, value) {
17819
+ return this.__tx('readwrite', (store) => {
17820
+ store.put(value, key);
17821
+ });
17822
+ }
17823
+
17824
+ async del(key) {
17825
+ return this.__tx('readwrite', (store) => {
17826
+ store.delete(key);
17827
+ });
17828
+ }
17829
+
17830
+ async clear() {
17831
+ return this.__tx('readwrite', (store) => {
17832
+ store.clear();
17833
+ });
17834
+ }
17835
+
17836
+ async batch(ops) {
17837
+ return this.__tx('readwrite', (store) => {
17838
+ for (const op of ops || []) {
17839
+ if (op.type === 'del') store.delete(op.key);
17840
+ else store.put(op.value, op.key);
17841
+ }
17842
+ });
17843
+ }
17844
+
17845
+ async *entries(prefix = '') {
17846
+ const db = await this.open();
17847
+ const rows = await new Promise((resolve, reject) => {
17848
+ const tx = db.transaction('kv', 'readonly');
17849
+ const store = tx.objectStore('kv');
17850
+ const out = [];
17851
+ const range = globalThis.IDBKeyRange.bound(prefix, prefix + '\uffff', false, true);
17852
+ const req = store.openCursor(range);
17853
+ req.onerror = () => reject(req.error);
17854
+ req.onsuccess = () => {
17855
+ const cursor = req.result;
17856
+ if (!cursor) return;
17857
+ out.push([cursor.key, cursor.value]);
17858
+ cursor.continue();
17859
+ };
17860
+ tx.oncomplete = () => resolve(out);
17861
+ tx.onerror = () => reject(tx.error || new Error('IndexedDB transaction failed'));
17862
+ });
17863
+ for (const row of rows) yield row;
17864
+ }
17865
+
17866
+ async close() {
17867
+ if (!this.dbPromise) return;
17868
+ const db = await this.dbPromise;
17869
+ if (db && typeof db.close === 'function') db.close();
17870
+ }
17871
+ }
17872
+
17873
+ class MemoryFactStore {
17874
+ constructor() {
17875
+ this.map = new Map();
17876
+ }
17877
+
17878
+ async add(triple, kind = 'explicit') {
17879
+ const key = tripleToStoreKey(triple);
17880
+ const prev = this.map.get(key);
17881
+ const mask = kindMask(kind);
17882
+ if (prev) {
17883
+ const nextKind = prev.kind | mask;
17884
+ if (nextKind !== prev.kind) prev.kind = nextKind;
17885
+ return false;
17886
+ }
17887
+ this.map.set(key, { triple, kind: mask });
17888
+ return true;
17889
+ }
17890
+
17891
+ async batchAdd(triples, kind = 'explicit') {
17892
+ let n = 0;
17893
+ for (const triple of triples || []) if (await this.add(triple, kind)) n += 1;
17894
+ return n;
17895
+ }
17896
+
17897
+ async has(triple) {
17898
+ return this.map.has(tripleToStoreKey(triple));
17899
+ }
17900
+
17901
+ async kindOf(triple) {
17902
+ const row = this.map.get(tripleToStoreKey(triple));
17903
+ return row ? row.kind : 0;
17904
+ }
17905
+
17906
+ async *match(s, p, o) {
17907
+ const sk = s == null ? null : termToStoreKey(s);
17908
+ const pk = p == null ? null : termToStoreKey(p);
17909
+ const ok = o == null ? null : termToStoreKey(o);
17910
+ for (const { triple } of this.map.values()) {
17911
+ if (sk !== null && termToStoreKey(triple.s) !== sk) continue;
17912
+ if (pk !== null && termToStoreKey(triple.p) !== pk) continue;
17913
+ if (ok !== null && termToStoreKey(triple.o) !== ok) continue;
17914
+ yield triple;
17915
+ }
17916
+ }
17917
+
17918
+ async clear() {
17919
+ this.map.clear();
17920
+ }
17921
+
17922
+ async close() {}
17923
+ }
17924
+
17925
+ class PersistentFactStore {
17926
+ constructor(kv, options = {}) {
17927
+ this.kv = kv;
17928
+ this.termCacheByKey = new Map();
17929
+ this.termCacheById = new Map();
17930
+ this.name = options.name || 'default';
17931
+ }
17932
+
17933
+ async clear() {
17934
+ await this.kv.clear();
17935
+ this.termCacheByKey.clear();
17936
+ this.termCacheById.clear();
17937
+ }
17938
+
17939
+ async __nextTermId() {
17940
+ const key = 'meta/nextTermId';
17941
+ const current = Number((await this.kv.get(key)) || 1);
17942
+ await this.kv.put(key, current + 1);
17943
+ return idPart(current);
17944
+ }
17945
+
17946
+ async __idForTerm(term, create) {
17947
+ const canonical = termToStoreKey(term);
17948
+ if (this.termCacheByKey.has(canonical)) return this.termCacheByKey.get(canonical);
17949
+ const byLexKey = `term/byLex/${base64url(canonical)}`;
17950
+ const found = await this.kv.get(byLexKey);
17951
+ if (found !== undefined) {
17952
+ this.termCacheByKey.set(canonical, found);
17953
+ return found;
17954
+ }
17955
+ if (!create) return null;
17956
+ const id = await this.__nextTermId();
17957
+ const json = termToJson(term);
17958
+ await this.kv.batch([
17959
+ { type: 'put', key: byLexKey, value: id },
17960
+ { type: 'put', key: `term/byId/${id}`, value: json },
17961
+ ]);
17962
+ this.termCacheByKey.set(canonical, id);
17963
+ this.termCacheById.set(id, term);
17964
+ return id;
17965
+ }
17966
+
17967
+ async __termById(id) {
17968
+ if (this.termCacheById.has(id)) return this.termCacheById.get(id);
17969
+ const json = await this.kv.get(`term/byId/${id}`);
17970
+ if (json === undefined) throw new Error(`Corrupt fact store: missing term ${id}`);
17971
+ const term = termFromJson(json);
17972
+ this.termCacheById.set(id, term);
17973
+ return term;
17974
+ }
17975
+
17976
+ async __tripleFromIds(sid, pid, oid) {
17977
+ return new Triple(await this.__termById(sid), await this.__termById(pid), await this.__termById(oid));
17978
+ }
17979
+
17980
+ async add(triple, kind = 'explicit') {
17981
+ const sid = await this.__idForTerm(triple.s, true);
17982
+ const pid = await this.__idForTerm(triple.p, true);
17983
+ const oid = await this.__idForTerm(triple.o, true);
17984
+ const mask = kindMask(kind);
17985
+ const primary = `triple/${sid}/${pid}/${oid}`;
17986
+ const prev = await this.kv.get(primary);
17987
+ if (prev !== undefined) {
17988
+ const nextKind = (typeof prev === 'number' ? prev : prev.kind || 0) | mask;
17989
+ if (nextKind !== prev) await this.kv.put(primary, nextKind);
17990
+ return false;
17991
+ }
17992
+ await this.kv.batch([
17993
+ { type: 'put', key: primary, value: mask },
17994
+ { type: 'put', key: `i/spo/${sid}/${pid}/${oid}`, value: mask },
17995
+ { type: 'put', key: `i/pos/${pid}/${oid}/${sid}`, value: mask },
17996
+ { type: 'put', key: `i/osp/${oid}/${sid}/${pid}`, value: mask },
17997
+ ]);
17998
+ return true;
17999
+ }
18000
+
18001
+ async batchAdd(triples, kind = 'explicit') {
18002
+ let n = 0;
18003
+ for (const triple of triples || []) if (await this.add(triple, kind)) n += 1;
18004
+ return n;
18005
+ }
18006
+
18007
+ async has(triple) {
18008
+ return (await this.kindOf(triple)) !== 0;
18009
+ }
18010
+
18011
+ async kindOf(triple) {
18012
+ const sid = await this.__idForTerm(triple.s, false);
18013
+ if (sid === null) return 0;
18014
+ const pid = await this.__idForTerm(triple.p, false);
18015
+ if (pid === null) return 0;
18016
+ const oid = await this.__idForTerm(triple.o, false);
18017
+ if (oid === null) return 0;
18018
+ const value = await this.kv.get(`triple/${sid}/${pid}/${oid}`);
18019
+ return typeof value === 'number' ? value : value && typeof value.kind === 'number' ? value.kind : 0;
18020
+ }
18021
+
18022
+ async __idsForPattern(s, p, o) {
18023
+ const sid = s == null ? null : await this.__idForTerm(s, false);
18024
+ const pid = p == null ? null : await this.__idForTerm(p, false);
18025
+ const oid = o == null ? null : await this.__idForTerm(o, false);
18026
+ if ((s != null && sid === null) || (p != null && pid === null) || (o != null && oid === null)) return null;
18027
+ return { sid, pid, oid };
18028
+ }
18029
+
18030
+ __scanPlan(sid, pid, oid) {
18031
+ if (sid && pid && oid) return { index: 'triple', prefix: `triple/${sid}/${pid}/${oid}`, order: 'spo' };
18032
+ if (sid && pid) return { index: 'spo', prefix: `i/spo/${sid}/${pid}/`, order: 'spo' };
18033
+ if (pid && oid) return { index: 'pos', prefix: `i/pos/${pid}/${oid}/`, order: 'pos' };
18034
+ if (sid && oid) return { index: 'osp', prefix: `i/osp/${oid}/${sid}/`, order: 'osp' };
18035
+ if (pid) return { index: 'pos', prefix: `i/pos/${pid}/`, order: 'pos' };
18036
+ if (sid) return { index: 'spo', prefix: `i/spo/${sid}/`, order: 'spo' };
18037
+ if (oid) return { index: 'osp', prefix: `i/osp/${oid}/`, order: 'osp' };
18038
+ return { index: 'spo', prefix: 'i/spo/', order: 'spo' };
18039
+ }
18040
+
18041
+ __decodeIndexKey(key, plan) {
18042
+ if (plan.index === 'triple') {
18043
+ const parts = key.split('/');
18044
+ return { sid: parts[1], pid: parts[2], oid: parts[3] };
18045
+ }
18046
+ const rest = key.slice(`i/${plan.index}/`.length).split('/');
18047
+ if (plan.order === 'spo') return { sid: rest[0], pid: rest[1], oid: rest[2] };
18048
+ if (plan.order === 'pos') return { pid: rest[0], oid: rest[1], sid: rest[2] };
18049
+ return { oid: rest[0], sid: rest[1], pid: rest[2] };
18050
+ }
18051
+
18052
+ async *match(s, p, o) {
18053
+ const ids = await this.__idsForPattern(s, p, o);
18054
+ if (!ids) return;
18055
+ const plan = this.__scanPlan(ids.sid, ids.pid, ids.oid);
18056
+ const seen = new Set();
18057
+ for await (const [key] of this.kv.entries(plan.prefix)) {
18058
+ const row = this.__decodeIndexKey(key, plan);
18059
+ if (ids.sid && row.sid !== ids.sid) continue;
18060
+ if (ids.pid && row.pid !== ids.pid) continue;
18061
+ if (ids.oid && row.oid !== ids.oid) continue;
18062
+ const primary = `${row.sid}/${row.pid}/${row.oid}`;
18063
+ if (seen.has(primary)) continue;
18064
+ seen.add(primary);
18065
+ yield this.__tripleFromIds(row.sid, row.pid, row.oid);
18066
+ }
18067
+ }
18068
+
18069
+ async close() {
18070
+ if (this.kv && typeof this.kv.close === 'function') await this.kv.close();
18071
+ }
18072
+ }
18073
+
18074
+ function nodeStoreLocation(name, storePath) {
18075
+ const path = __dynamicRequire('node:path');
18076
+ const os = __dynamicRequire('node:os');
18077
+ if (!path || !os) return null;
18078
+ const base = storePath || path.join(os.homedir ? os.homedir() : '.', '.eyeling-store');
18079
+ return path.join(base, safeStoreName(name));
18080
+ }
18081
+
18082
+ async function createPersistentFactStore(options = {}) {
18083
+ const name = typeof options === 'string' ? options : options.name || 'default';
18084
+ const clear = !!(options && options.clear);
18085
+ let kv;
18086
+
18087
+ if (typeof globalThis !== 'undefined' && globalThis.indexedDB && !__dynamicRequire('node:fs')) {
18088
+ kv = new IndexedDbKv(name);
18089
+ } else {
18090
+ const location = nodeStoreLocation(name, options && options.path);
18091
+ try {
18092
+ kv = new ClassicLevelKv(location);
18093
+ } catch {
18094
+ kv = new JsonFileKv(`${location}.json`);
18095
+ }
18096
+ }
18097
+
18098
+ const store = new PersistentFactStore(kv, { name });
18099
+ if (clear) await store.clear();
18100
+ return store;
18101
+ }
18102
+
18103
+ async function createFactStore(options = null) {
18104
+ if (!options) return new MemoryFactStore();
18105
+ if (typeof options === 'string') return createPersistentFactStore({ name: options });
18106
+ if (options.type === 'memory') return new MemoryFactStore();
18107
+ if (options.backend === 'memory') return new MemoryFactStore();
18108
+ return createPersistentFactStore(options);
18109
+ }
18110
+
18111
+ async function collectStore(store) {
18112
+ const out = [];
18113
+ for await (const tr of store.match(null, null, null)) out.push(tr);
18114
+ return out;
18115
+ }
18116
+
18117
+ module.exports = {
18118
+ KIND_EXPLICIT,
18119
+ KIND_INFERRED,
18120
+ MemoryFactStore,
18121
+ PersistentFactStore,
18122
+ createFactStore,
18123
+ createPersistentFactStore,
18124
+ collectStore,
18125
+ termToStoreKey,
18126
+ tripleToStoreKey,
18127
+ termToJson,
18128
+ termFromJson,
18129
+ tripleToJson,
18130
+ tripleFromJson,
18131
+ };
18132
+
17187
18133
  };
17188
18134
  __modules["lib/time.js"] = function(require, module, exports){
17189
18135
  /**