@undefineds.co/xpod 0.3.18 → 0.3.23

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 (115) hide show
  1. package/config/bun.json +57 -11
  2. package/config/cloud.json +14 -12
  3. package/config/local.json +16 -14
  4. package/config/xpod.json +47 -9
  5. package/dist/api/matrix/PodMatrixStore.d.ts +4 -7
  6. package/dist/api/matrix/PodMatrixStore.js +116 -148
  7. package/dist/api/matrix/PodMatrixStore.js.map +1 -1
  8. package/dist/api/matrix/types.d.ts +2 -0
  9. package/dist/api/matrix/types.js.map +1 -1
  10. package/dist/api/runs/PiAgentRuntimeDriver.d.ts +1 -0
  11. package/dist/api/runs/PiAgentRuntimeDriver.js +4 -1
  12. package/dist/api/runs/PiAgentRuntimeDriver.js.map +1 -1
  13. package/dist/components/components.jsonld +3 -0
  14. package/dist/components/context.jsonld +71 -32
  15. package/dist/http/SubgraphSparqlHttpHandler.d.ts +1 -0
  16. package/dist/http/SubgraphSparqlHttpHandler.js +27 -4
  17. package/dist/http/SubgraphSparqlHttpHandler.js.map +1 -1
  18. package/dist/http/SubgraphSparqlHttpHandler.jsonld +4 -0
  19. package/dist/http/vector/VectorHttpHandler.d.ts +5 -1
  20. package/dist/http/vector/VectorHttpHandler.js +5 -5
  21. package/dist/http/vector/VectorHttpHandler.js.map +1 -1
  22. package/dist/http/vector/VectorHttpHandler.jsonld +40 -28
  23. package/dist/index.d.ts +5 -2
  24. package/dist/index.js +9 -4
  25. package/dist/index.js.map +1 -1
  26. package/dist/runtime/Proxy.d.ts +3 -0
  27. package/dist/runtime/Proxy.js +31 -7
  28. package/dist/runtime/Proxy.js.map +1 -1
  29. package/dist/solidfs/LocalSolidFS.js +31 -124
  30. package/dist/solidfs/LocalSolidFS.js.map +1 -1
  31. package/dist/solidfs/SolidFsPathUtils.d.ts +13 -0
  32. package/dist/solidfs/SolidFsPathUtils.js +114 -0
  33. package/dist/solidfs/SolidFsPathUtils.js.map +1 -0
  34. package/dist/solidfs/SolidFsSyncJournal.d.ts +117 -0
  35. package/dist/solidfs/SolidFsSyncJournal.js +553 -0
  36. package/dist/solidfs/SolidFsSyncJournal.js.map +1 -0
  37. package/dist/solidfs/index.d.ts +1 -0
  38. package/dist/solidfs/index.js +1 -0
  39. package/dist/solidfs/index.js.map +1 -1
  40. package/dist/solidfs/types.d.ts +1 -0
  41. package/dist/solidfs/types.js.map +1 -1
  42. package/dist/storage/SparqlUpdateResourceStore.js +94 -33
  43. package/dist/storage/SparqlUpdateResourceStore.js.map +1 -1
  44. package/dist/storage/accessors/MixDataAccessor.d.ts +22 -5
  45. package/dist/storage/accessors/MixDataAccessor.js +376 -61
  46. package/dist/storage/accessors/MixDataAccessor.js.map +1 -1
  47. package/dist/storage/accessors/MixDataAccessor.jsonld +73 -5
  48. package/dist/storage/accessors/QuadstoreSparqlDataAccessor.js +32 -10
  49. package/dist/storage/accessors/QuadstoreSparqlDataAccessor.js.map +1 -1
  50. package/dist/storage/accessors/QuintStoreSparqlDataAccessor.js +28 -6
  51. package/dist/storage/accessors/QuintStoreSparqlDataAccessor.js.map +1 -1
  52. package/dist/storage/accessors/SolidRdfDataAccessor.d.ts +45 -0
  53. package/dist/storage/accessors/SolidRdfDataAccessor.js +277 -0
  54. package/dist/storage/accessors/SolidRdfDataAccessor.js.map +1 -0
  55. package/dist/storage/accessors/SolidRdfDataAccessor.jsonld +161 -0
  56. package/dist/storage/rdf/Rdf3xIndex.d.ts +122 -0
  57. package/dist/storage/rdf/Rdf3xIndex.js +2695 -0
  58. package/dist/storage/rdf/Rdf3xIndex.js.map +1 -0
  59. package/dist/storage/rdf/Rdf3xIndex.jsonld +528 -0
  60. package/dist/storage/rdf/Rdf3xSchema.d.ts +20 -0
  61. package/dist/storage/rdf/Rdf3xSchema.js +65 -0
  62. package/dist/storage/rdf/Rdf3xSchema.js.map +1 -0
  63. package/dist/storage/rdf/RdfLocalQueryEngine.d.ts +10 -4
  64. package/dist/storage/rdf/RdfLocalQueryEngine.js +607 -127
  65. package/dist/storage/rdf/RdfLocalQueryEngine.js.map +1 -1
  66. package/dist/storage/rdf/RdfQuadIndex.d.ts +12 -1
  67. package/dist/storage/rdf/RdfQuadIndex.js +152 -22
  68. package/dist/storage/rdf/RdfQuadIndex.js.map +1 -1
  69. package/dist/storage/rdf/RdfQuadIndex.jsonld +36 -4
  70. package/dist/storage/rdf/RdfSparqlAdapter.d.ts +20 -2
  71. package/dist/storage/rdf/RdfSparqlAdapter.js +364 -40
  72. package/dist/storage/rdf/RdfSparqlAdapter.js.map +1 -1
  73. package/dist/storage/rdf/RdfSparqlAdapter.jsonld +60 -0
  74. package/dist/storage/rdf/RdfTermDictionary.d.ts +8 -0
  75. package/dist/storage/rdf/RdfTermDictionary.js +141 -70
  76. package/dist/storage/rdf/RdfTermDictionary.js.map +1 -1
  77. package/dist/storage/rdf/RdfTermDictionary.jsonld +24 -0
  78. package/dist/storage/rdf/RdfTextIndex.js +10 -3
  79. package/dist/storage/rdf/RdfTextIndex.js.map +1 -1
  80. package/dist/storage/rdf/SolidRdfEngine.d.ts +15 -6
  81. package/dist/storage/rdf/SolidRdfEngine.js +218 -25
  82. package/dist/storage/rdf/SolidRdfEngine.js.map +1 -1
  83. package/dist/storage/rdf/SolidRdfEngine.jsonld +70 -7
  84. package/dist/storage/rdf/SolidRdfSparqlEngine.d.ts +11 -7
  85. package/dist/storage/rdf/SolidRdfSparqlEngine.js +60 -47
  86. package/dist/storage/rdf/SolidRdfSparqlEngine.js.map +1 -1
  87. package/dist/storage/rdf/SolidRdfSparqlEngine.jsonld +9 -5
  88. package/dist/storage/rdf/index.d.ts +2 -2
  89. package/dist/storage/rdf/index.js +3 -3
  90. package/dist/storage/rdf/index.js.map +1 -1
  91. package/dist/storage/rdf/models-benchmark.d.ts +12 -1
  92. package/dist/storage/rdf/models-benchmark.js +549 -32
  93. package/dist/storage/rdf/models-benchmark.js.map +1 -1
  94. package/dist/storage/rdf/types.d.ts +81 -7
  95. package/dist/storage/rdf/types.js.map +1 -1
  96. package/dist/storage/sparql/CompatibilitySparqlEngine.d.ts +36 -0
  97. package/dist/storage/sparql/CompatibilitySparqlEngine.js +96 -0
  98. package/dist/storage/sparql/CompatibilitySparqlEngine.js.map +1 -0
  99. package/dist/storage/sparql/CompatibilitySparqlEngine.jsonld +123 -0
  100. package/dist/storage/sparql/CompatibilitySparqlEngineImpl.d.ts +35 -0
  101. package/dist/storage/sparql/CompatibilitySparqlEngineImpl.js +112 -0
  102. package/dist/storage/sparql/CompatibilitySparqlEngineImpl.js.map +1 -0
  103. package/dist/storage/sparql/SubgraphQueryEngine.d.ts +1 -36
  104. package/dist/storage/sparql/SubgraphQueryEngine.js +2 -115
  105. package/dist/storage/sparql/SubgraphQueryEngine.js.map +1 -1
  106. package/dist/storage/sparql/SubgraphQueryEngine.jsonld +1 -124
  107. package/dist/terminal/AclPermissionService.d.ts +2 -1
  108. package/dist/terminal/AclPermissionService.js +26 -3
  109. package/dist/terminal/AclPermissionService.js.map +1 -1
  110. package/dist/terminal/TerminalSessionManager.js +25 -3
  111. package/dist/terminal/TerminalSessionManager.js.map +1 -1
  112. package/package.json +1 -1
  113. package/dist/storage/rdf/Rdf3xTripleIndex.d.ts +0 -55
  114. package/dist/storage/rdf/Rdf3xTripleIndex.js +0 -1235
  115. package/dist/storage/rdf/Rdf3xTripleIndex.js.map +0 -1
@@ -10,6 +10,7 @@ const arrayify_stream_1 = __importDefault(require("arrayify-stream"));
10
10
  const n3_1 = require("n3");
11
11
  const jsonld_1 = __importDefault(require("jsonld"));
12
12
  const rdf_parse_1 = require("rdf-parse");
13
+ const sparqljs_1 = require("sparqljs");
13
14
  const community_server_1 = require("@solid/community-server");
14
15
  const RdfSparqlAdapter_1 = require("../rdf/RdfSparqlAdapter");
15
16
  const RdfContentTypes_1 = require("../rdf/RdfContentTypes");
@@ -20,7 +21,7 @@ const MetadataRequestContext_1 = require("../MetadataRequestContext");
20
21
  /**
21
22
  * MixDataAccessor - Routes data to appropriate storage based on content type
22
23
  *
23
- * - RDF data (internal/quads) -> structuredDataAccessor (Quadstore or QuintStore)
24
+ * - RDF data (internal/quads) -> structuredDataAccessor (Solid RDF engine by default)
24
25
  * - RDF file mirrors (.ttl/.jsonld) -> rdfFileDataAccessor (local FileSystem)
25
26
  * - Other data (binary, text, etc.) -> unstructuredDataAccessor (FileSystem, Minio, etc.)
26
27
  *
@@ -179,16 +180,18 @@ class MixDataAccessor {
179
180
  * Execute SPARQL UPDATE.
180
181
  *
181
182
  * Supported embedded deltas patch the local RDF authority file first and then
182
- * rebuild the structured RDF index. Unsupported shapes keep using the
183
- * compatibility accessor until the embedded engine covers them.
183
+ * rebuild the structured RDF index. The structured accessor decides whether
184
+ * unsupported shapes have an explicitly configured compatibility path.
184
185
  */
185
186
  async executeSparqlUpdate(query, baseIri) {
186
187
  if (baseIri) {
187
188
  const identifier = { path: baseIri };
188
189
  if (this.isByLineRdfIdentifier(identifier)) {
189
190
  try {
190
- await this.executeLocalRdfSparqlUpdate(query, identifier);
191
- this.invalidateMetadataCache(identifier);
191
+ const writtenIdentifiers = await this.executeLocalRdfSparqlUpdate(query, identifier);
192
+ for (const writtenIdentifier of writtenIdentifiers) {
193
+ this.invalidateMetadataCache(writtenIdentifier);
194
+ }
192
195
  return;
193
196
  }
194
197
  catch (error) {
@@ -210,62 +213,104 @@ class MixDataAccessor {
210
213
  }
211
214
  }
212
215
  async executeLocalRdfSparqlUpdate(query, identifier) {
213
- const delta = this.rdfSparqlAdapter.compileUpdateDelta(query, identifier.path);
214
- this.assertLocalRdfDeltaTargetsGraph(delta.operations, identifier.path);
215
- const existingText = await this.readLocalRdfTextOrEmpty(identifier);
216
- const graph = n3_1.DataFactory.namedNode(identifier.path);
217
- const existingQuads = existingText.length > 0
218
- ? await this.parseLocalRdf(identifier, existingText, this.localRdfContentType(identifier))
219
- .then((quads) => quads.map((quad) => this.toGraphQuad(quad, graph)))
220
- : [];
221
- const nextQuads = this.applyLocalRdfDelta(existingQuads, delta.operations);
222
- const authorityQuads = nextQuads.map((quad) => this.toDefaultGraphQuad(quad));
223
- await this.writeLocalRdfAuthority(identifier, authorityQuads);
224
- await this.writeStructuredRdfIndex(identifier, authorityQuads, new community_server_1.RepresentationMetadata(identifier));
225
- }
226
- applyLocalRdfDelta(quads, operations) {
227
- const byKey = new Map(quads.map((quad) => [this.quadKey(quad), quad]));
216
+ const parsed = new sparqljs_1.Parser({ baseIRI: identifier.path }).parse(query);
217
+ const delta = this.rdfSparqlAdapter.compileUpdateDelta(parsed, this.parentContainer(identifier).path, {
218
+ defaultGraph: identifier.path,
219
+ });
220
+ const writableGraphIris = this.localRdfDeltaWriteGraphIris(delta.operations);
221
+ const graphStates = await this.loadLocalRdfDeltaGraphs(delta.operations, writableGraphIris);
222
+ const graphQuads = new Map([...graphStates].map(([graphIri, state]) => [graphIri, state.quads]));
223
+ const nextQuadsByGraph = this.applyLocalRdfDelta(graphQuads, delta.operations, writableGraphIris);
224
+ const patches = writableGraphIris.map((graphIri) => {
225
+ const previous = graphStates.get(graphIri);
226
+ return {
227
+ identifier: { path: graphIri },
228
+ previousQuads: previous?.quads ?? [],
229
+ previousExists: previous?.existed ?? false,
230
+ nextQuads: nextQuadsByGraph.get(graphIri) ?? [],
231
+ };
232
+ });
233
+ await this.writeLocalRdfAuthorityPatches(patches);
234
+ return patches.map((patch) => patch.identifier);
235
+ }
236
+ applyLocalRdfDelta(graphQuads, operations, writableGraphIris) {
237
+ const writableGraphs = new Set(writableGraphIris);
238
+ const byGraph = new Map();
239
+ for (const [graphIri, quads] of graphQuads) {
240
+ byGraph.set(graphIri, new Map(quads.map((quad) => [this.quadKey(quad), quad])));
241
+ }
242
+ const currentQuads = () => [...byGraph.values()].flatMap((quads) => [...quads.values()]);
243
+ const writableQuads = (graphIri) => {
244
+ let quads = byGraph.get(graphIri);
245
+ if (!quads) {
246
+ quads = new Map();
247
+ byGraph.set(graphIri, quads);
248
+ }
249
+ return quads;
250
+ };
251
+ const deleteQuads = (quads) => {
252
+ for (const quad of quads) {
253
+ const target = writableQuads(this.localRdfWriteGraphIri(quad.graph, writableGraphs));
254
+ target.delete(this.quadKey(quad));
255
+ }
256
+ };
257
+ const insertQuads = (quads) => {
258
+ for (const quad of quads) {
259
+ const target = writableQuads(this.localRdfWriteGraphIri(quad.graph, writableGraphs));
260
+ target.set(this.quadKey(quad), quad);
261
+ }
262
+ };
228
263
  for (const operation of operations) {
229
264
  if (operation.type === 'insert') {
230
- for (const quad of operation.quads) {
231
- byKey.set(this.quadKey(quad), quad);
232
- }
265
+ insertQuads(operation.quads);
233
266
  continue;
234
267
  }
235
268
  if (operation.type === 'delete') {
236
- for (const quad of operation.quads) {
237
- byKey.delete(this.quadKey(quad));
238
- }
269
+ deleteQuads(operation.quads);
239
270
  continue;
240
271
  }
241
272
  if (operation.type === 'insertDeleteWhere') {
242
- const rows = this.queryLocalUpdateBindings([...byKey.values()], operation.query);
243
- for (const quad of this.rdfSparqlAdapter.materializeDeleteWhere(operation.deletes, rows)) {
244
- byKey.delete(this.quadKey(quad));
245
- }
246
- for (const quad of this.rdfSparqlAdapter.materializeDeleteWhere(operation.inserts, rows)) {
247
- byKey.set(this.quadKey(quad), quad);
248
- }
273
+ const rows = this.queryLocalUpdateBindings(currentQuads(), operation.query);
274
+ deleteQuads(this.rdfSparqlAdapter.materializeDeleteWhere(operation.deletes, rows));
275
+ insertQuads(this.rdfSparqlAdapter.materializeDeleteWhere(operation.inserts, rows));
249
276
  continue;
250
277
  }
251
278
  if (operation.type === 'insertWhere') {
252
- const rows = this.queryLocalUpdateBindings([...byKey.values()], operation.query);
253
- for (const quad of this.rdfSparqlAdapter.materializeDeleteWhere(operation.inserts, rows)) {
254
- byKey.set(this.quadKey(quad), quad);
255
- }
279
+ const rows = this.queryLocalUpdateBindings(currentQuads(), operation.query);
280
+ insertQuads(this.rdfSparqlAdapter.materializeDeleteWhere(operation.inserts, rows));
256
281
  continue;
257
282
  }
258
- const rows = this.queryLocalUpdateBindings([...byKey.values()], operation.query);
259
- for (const quad of this.rdfSparqlAdapter.materializeDeleteWhere(operation.template, rows)) {
260
- byKey.delete(this.quadKey(quad));
283
+ const rows = this.queryLocalUpdateBindings(currentQuads(), operation.query);
284
+ deleteQuads(this.rdfSparqlAdapter.materializeDeleteWhere(operation.template, rows));
285
+ }
286
+ return new Map(writableGraphIris.map((graphIri) => [graphIri, [...(byGraph.get(graphIri)?.values() ?? [])]]));
287
+ }
288
+ async loadLocalRdfDeltaGraphs(operations, writableGraphIris) {
289
+ const graphIris = this.localRdfDeltaGraphIris(operations, writableGraphIris);
290
+ const graphStates = new Map();
291
+ for (const graphIri of graphIris) {
292
+ const graphIdentifier = { path: graphIri };
293
+ if (!this.isByLineRdfIdentifier(graphIdentifier)) {
294
+ throw new RdfSparqlAdapter_1.UnsupportedSparqlQueryError('Embedded local RDF update only supports by-line local RDF graph documents');
261
295
  }
262
- }
263
- return [...byKey.values()];
264
- }
265
- assertLocalRdfDeltaTargetsGraph(operations, graphIri) {
296
+ const existing = await this.readLocalRdfState(graphIdentifier);
297
+ const graph = n3_1.DataFactory.namedNode(graphIri);
298
+ const quads = existing.text.length > 0
299
+ ? await this.parseLocalRdf(graphIdentifier, existing.text, this.localRdfContentType(graphIdentifier))
300
+ .then((items) => items.map((quad) => this.toGraphQuad(quad, graph)))
301
+ : [];
302
+ graphStates.set(graphIri, { quads, existed: existing.existed });
303
+ }
304
+ return graphStates;
305
+ }
306
+ localRdfDeltaGraphIris(operations, writableGraphIris) {
307
+ const graphIris = new Set(writableGraphIris);
266
308
  for (const operation of operations) {
267
309
  const graphTerms = operation.type === 'deleteWhere'
268
- ? operation.template.map((item) => item.graph)
310
+ ? [
311
+ ...operation.template.map((item) => item.graph),
312
+ ...this.queryGraphTerms(operation.query),
313
+ ]
269
314
  : operation.type === 'insertDeleteWhere'
270
315
  ? [
271
316
  ...operation.deletes.map((item) => item.graph),
@@ -279,12 +324,64 @@ class MixDataAccessor {
279
324
  ]
280
325
  : operation.quads.map((quad) => quad.graph);
281
326
  for (const graph of graphTerms) {
282
- if (!('termType' in graph) || graph.termType !== 'NamedNode' || graph.value !== graphIri) {
283
- throw new RdfSparqlAdapter_1.UnsupportedSparqlQueryError('Embedded local RDF update only supports the target document graph');
284
- }
327
+ this.addNamedGraphIris(graph, graphIris);
328
+ }
329
+ }
330
+ return [...graphIris];
331
+ }
332
+ localRdfDeltaWriteGraphIris(operations) {
333
+ const graphIris = new Set();
334
+ for (const operation of operations) {
335
+ if (operation.type === 'deleteWhere') {
336
+ this.addWritableTemplateGraphIris(operation.template.map((item) => item.graph), operation.query, graphIris);
337
+ continue;
338
+ }
339
+ if (operation.type === 'insertDeleteWhere') {
340
+ this.addWritableTemplateGraphIris([
341
+ ...operation.deletes.map((item) => item.graph),
342
+ ...operation.inserts.map((item) => item.graph),
343
+ ], operation.query, graphIris);
344
+ continue;
345
+ }
346
+ if (operation.type === 'insertWhere') {
347
+ this.addWritableTemplateGraphIris(operation.inserts.map((item) => item.graph), operation.query, graphIris);
348
+ continue;
349
+ }
350
+ const graphTerms = operation.quads.map((quad) => quad.graph);
351
+ for (const graph of graphTerms) {
352
+ this.addWritableNamedGraphIri(graph, graphIris);
353
+ }
354
+ }
355
+ if (graphIris.size === 0) {
356
+ throw new RdfSparqlAdapter_1.UnsupportedSparqlQueryError('Embedded local RDF update requires explicit local RDF graph write targets');
357
+ }
358
+ return [...graphIris];
359
+ }
360
+ addWritableTemplateGraphIris(graphs, query, graphIris) {
361
+ for (const graph of graphs) {
362
+ if (this.isQueryVariable(graph)) {
363
+ this.addWritableGraphVariableIris(query, graph.variable, graphIris);
364
+ continue;
285
365
  }
366
+ this.addWritableNamedGraphIri(graph, graphIris);
367
+ }
368
+ }
369
+ addWritableGraphVariableIris(query, variable, graphIris) {
370
+ const values = new Set();
371
+ this.collectGraphVariableFilterIris(query, variable, values);
372
+ if (values.size === 0) {
373
+ throw new RdfSparqlAdapter_1.UnsupportedSparqlQueryError('Embedded local RDF update only supports finite GRAPH variable write targets');
374
+ }
375
+ for (const value of values) {
376
+ this.addWritableNamedGraphIri(n3_1.DataFactory.namedNode(value), graphIris);
286
377
  }
287
378
  }
379
+ localRdfWriteGraphIri(graph, writableGraphs) {
380
+ if (graph.termType !== 'NamedNode' || !writableGraphs.has(graph.value)) {
381
+ throw new RdfSparqlAdapter_1.UnsupportedSparqlQueryError('Embedded local RDF update can only write declared local RDF graph documents');
382
+ }
383
+ return graph.value;
384
+ }
288
385
  queryLocalUpdateBindings(quads, query) {
289
386
  const index = new RdfQuadIndex_1.RdfQuadIndex({ path: ':memory:' });
290
387
  index.open();
@@ -298,33 +395,194 @@ class MixDataAccessor {
298
395
  }
299
396
  }
300
397
  queryGraphTerms(query) {
301
- const patterns = [...query.patterns];
398
+ const graphTerms = [];
399
+ const graphVariables = new Set();
400
+ this.collectQueryGraphTerms(query, graphTerms, graphVariables);
401
+ this.collectGraphVariableFilterTerms(query, graphVariables, graphTerms);
402
+ return graphTerms;
403
+ }
404
+ collectQueryGraphTerms(query, graphTerms, graphVariables) {
405
+ for (const pattern of query.patterns) {
406
+ if (!pattern.graph) {
407
+ continue;
408
+ }
409
+ graphTerms.push(pattern.graph);
410
+ if (this.isQueryVariable(pattern.graph)) {
411
+ graphVariables.add(pattern.graph.variable);
412
+ }
413
+ }
414
+ for (const optional of query.optional ?? []) {
415
+ this.collectQueryGraphTerms(Array.isArray(optional) ? { patterns: optional } : optional, graphTerms, graphVariables);
416
+ }
417
+ for (const union of query.unions ?? []) {
418
+ for (const branch of union.branches) {
419
+ this.collectQueryGraphTerms(branch, graphTerms, graphVariables);
420
+ }
421
+ }
422
+ for (const minus of query.minus ?? []) {
423
+ this.collectQueryGraphTerms(minus, graphTerms, graphVariables);
424
+ }
425
+ for (const exists of query.exists ?? []) {
426
+ this.collectQueryGraphTerms(exists, graphTerms, graphVariables);
427
+ }
428
+ }
429
+ collectGraphVariableFilterTerms(query, graphVariables, graphTerms) {
430
+ for (const filter of query.filters ?? []) {
431
+ if (!graphVariables.has(filter.variable)) {
432
+ continue;
433
+ }
434
+ if (filter.value && this.isRdfTerm(filter.value)) {
435
+ graphTerms.push(filter.value);
436
+ }
437
+ for (const value of filter.values ?? []) {
438
+ if (this.isRdfTerm(value)) {
439
+ graphTerms.push(value);
440
+ }
441
+ }
442
+ }
443
+ this.collectGraphVariableValueTerms(query.values ?? [], graphVariables, graphTerms);
444
+ for (const optional of query.optional ?? []) {
445
+ if (!Array.isArray(optional)) {
446
+ this.collectGraphVariableFilterTerms(optional, graphVariables, graphTerms);
447
+ }
448
+ }
449
+ for (const union of query.unions ?? []) {
450
+ for (const branch of union.branches) {
451
+ this.collectGraphVariableFilterTerms(branch, graphVariables, graphTerms);
452
+ }
453
+ }
454
+ for (const minus of query.minus ?? []) {
455
+ this.collectGraphVariableFilterTerms(minus, graphVariables, graphTerms);
456
+ }
457
+ for (const exists of query.exists ?? []) {
458
+ this.collectGraphVariableFilterTerms(exists, graphVariables, graphTerms);
459
+ }
460
+ }
461
+ collectGraphVariableFilterIris(query, variable, values) {
462
+ for (const filter of query.filters ?? []) {
463
+ if (filter.variable !== variable) {
464
+ continue;
465
+ }
466
+ if ((filter.operator === '$eq' || filter.operator === '$sameTerm') && filter.value && this.isRdfTerm(filter.value)) {
467
+ this.addGraphFilterValueIri(filter.value, values);
468
+ }
469
+ if (filter.operator === '$in') {
470
+ for (const value of filter.values ?? []) {
471
+ if (this.isRdfTerm(value)) {
472
+ this.addGraphFilterValueIri(value, values);
473
+ }
474
+ }
475
+ }
476
+ }
477
+ this.collectGraphVariableValueIris(query.values ?? [], variable, values);
302
478
  for (const optional of query.optional ?? []) {
303
- patterns.push(...(Array.isArray(optional) ? optional : optional.patterns));
479
+ if (!Array.isArray(optional)) {
480
+ this.collectGraphVariableFilterIris(optional, variable, values);
481
+ }
304
482
  }
305
483
  for (const union of query.unions ?? []) {
306
484
  for (const branch of union.branches) {
307
- patterns.push(...branch.patterns);
308
- for (const optional of branch.optional ?? []) {
309
- patterns.push(...(Array.isArray(optional) ? optional : optional.patterns));
485
+ this.collectGraphVariableFilterIris(branch, variable, values);
486
+ }
487
+ }
488
+ for (const minus of query.minus ?? []) {
489
+ this.collectGraphVariableFilterIris(minus, variable, values);
490
+ }
491
+ for (const exists of query.exists ?? []) {
492
+ this.collectGraphVariableFilterIris(exists, variable, values);
493
+ }
494
+ }
495
+ collectGraphVariableValueTerms(sources, graphVariables, graphTerms) {
496
+ for (const source of sources) {
497
+ for (const variable of source.variables) {
498
+ if (!graphVariables.has(variable)) {
499
+ continue;
500
+ }
501
+ for (const row of source.rows) {
502
+ const value = row[variable];
503
+ if (value) {
504
+ graphTerms.push(value);
505
+ }
310
506
  }
311
507
  }
312
508
  }
313
- return patterns.flatMap((pattern) => pattern.graph ? [pattern.graph] : []);
314
509
  }
315
- async readLocalRdfTextOrEmpty(identifier) {
510
+ collectGraphVariableValueIris(sources, variable, values) {
511
+ for (const source of sources) {
512
+ if (!source.variables.includes(variable)) {
513
+ continue;
514
+ }
515
+ for (const row of source.rows) {
516
+ const value = row[variable];
517
+ if (value) {
518
+ this.addGraphFilterValueIri(value, values);
519
+ }
520
+ }
521
+ }
522
+ }
523
+ addGraphFilterValueIri(value, values) {
524
+ if (value.termType !== 'NamedNode') {
525
+ throw new RdfSparqlAdapter_1.UnsupportedSparqlQueryError('Embedded local RDF update GRAPH variable write targets must be named graph documents');
526
+ }
527
+ values.add(value.value);
528
+ }
529
+ addNamedGraphIris(graph, graphIris) {
530
+ if (this.isRdfTerm(graph)) {
531
+ if (graph.termType !== 'NamedNode') {
532
+ throw new RdfSparqlAdapter_1.UnsupportedSparqlQueryError('Embedded local RDF update only supports named graph documents');
533
+ }
534
+ graphIris.add(graph.value);
535
+ return;
536
+ }
537
+ const values = graph.$in;
538
+ if (Array.isArray(values) && values.every((value) => this.isRdfTerm(value))) {
539
+ for (const value of values) {
540
+ if (value.termType !== 'NamedNode') {
541
+ throw new RdfSparqlAdapter_1.UnsupportedSparqlQueryError('Embedded local RDF update only supports named graph documents');
542
+ }
543
+ graphIris.add(value.value);
544
+ }
545
+ return;
546
+ }
547
+ if (this.isQueryVariable(graph)) {
548
+ return;
549
+ }
550
+ throw new RdfSparqlAdapter_1.UnsupportedSparqlQueryError('Embedded local RDF update only supports explicit local RDF graph documents');
551
+ }
552
+ addWritableNamedGraphIri(graph, graphIris) {
553
+ if (!this.isRdfTerm(graph) || graph.termType !== 'NamedNode') {
554
+ throw new RdfSparqlAdapter_1.UnsupportedSparqlQueryError('Embedded local RDF update only supports explicit local RDF graph write targets');
555
+ }
556
+ if (!this.isByLineRdfIdentifier({ path: graph.value })) {
557
+ throw new RdfSparqlAdapter_1.UnsupportedSparqlQueryError('Embedded local RDF update only supports by-line local RDF graph write targets');
558
+ }
559
+ graphIris.add(graph.value);
560
+ }
561
+ isQueryVariable(value) {
562
+ return Boolean(value && typeof value === 'object' && 'variable' in value);
563
+ }
564
+ isRdfTerm(value) {
565
+ return Boolean(value && typeof value === 'object' && 'termType' in value);
566
+ }
567
+ async readLocalRdfState(identifier) {
316
568
  try {
317
- return await this.readStreamText(await this.rdfFileDataAccessor.getData(identifier));
569
+ return {
570
+ text: await this.readStreamText(await this.rdfFileDataAccessor.getData(identifier)),
571
+ existed: true,
572
+ };
318
573
  }
319
574
  catch (error) {
320
575
  if (community_server_1.NotFoundHttpError.isInstance(error)) {
321
576
  await this.refreshLocalRdfMirror(identifier);
322
577
  try {
323
- return await this.readStreamText(await this.rdfFileDataAccessor.getData(identifier));
578
+ return {
579
+ text: await this.readStreamText(await this.rdfFileDataAccessor.getData(identifier)),
580
+ existed: true,
581
+ };
324
582
  }
325
583
  catch (retryError) {
326
584
  if (community_server_1.NotFoundHttpError.isInstance(retryError)) {
327
- return '';
585
+ return { text: '', existed: false };
328
586
  }
329
587
  throw retryError;
330
588
  }
@@ -336,6 +594,54 @@ class MixDataAccessor {
336
594
  await this.ensureRdfFileParentContainers(identifier);
337
595
  await this.rdfFileDataAccessor.writeDocument(identifier, (0, community_server_1.guardStream)(stream_1.Readable.from([await this.serializeQuadsForLocalFile(identifier, quads)])), this.createLocalRdfMetadata(identifier, new community_server_1.RepresentationMetadata(identifier)));
338
596
  }
597
+ async writeLocalRdfAuthorityPatches(patches) {
598
+ const applied = [];
599
+ try {
600
+ for (const patch of patches) {
601
+ let localAuthorityWritten = false;
602
+ try {
603
+ const authorityQuads = patch.nextQuads.map((quad) => this.toDefaultGraphQuad(quad));
604
+ await this.writeLocalRdfAuthority(patch.identifier, authorityQuads);
605
+ localAuthorityWritten = true;
606
+ await this.writeStructuredRdfIndex(patch.identifier, authorityQuads, new community_server_1.RepresentationMetadata(patch.identifier));
607
+ applied.push(patch);
608
+ }
609
+ catch (error) {
610
+ if (localAuthorityWritten) {
611
+ applied.push(patch);
612
+ }
613
+ throw error;
614
+ }
615
+ }
616
+ }
617
+ catch (error) {
618
+ await this.rollbackLocalRdfAuthorityPatches(applied);
619
+ throw error;
620
+ }
621
+ }
622
+ async rollbackLocalRdfAuthorityPatches(patches) {
623
+ const failures = [];
624
+ for (const patch of patches.slice().reverse()) {
625
+ try {
626
+ if (patch.previousExists) {
627
+ const authorityQuads = patch.previousQuads.map((quad) => this.toDefaultGraphQuad(quad));
628
+ await this.writeLocalRdfAuthority(patch.identifier, authorityQuads);
629
+ await this.writeStructuredRdfIndex(patch.identifier, authorityQuads, new community_server_1.RepresentationMetadata(patch.identifier));
630
+ }
631
+ else {
632
+ await this.deleteRdfFileResourceIfPresent(patch.identifier);
633
+ await this.deleteLocalRdfIndex(patch.identifier);
634
+ }
635
+ this.invalidateMetadataCache(patch.identifier);
636
+ }
637
+ catch (rollbackError) {
638
+ failures.push(`${patch.identifier.path}: ${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)}`);
639
+ }
640
+ }
641
+ if (failures.length > 0) {
642
+ this.logger.warn(`Failed to fully roll back local RDF authority patch: ${failures.join('; ')}`);
643
+ }
644
+ }
339
645
  toDefaultGraphQuad(quad) {
340
646
  return n3_1.DataFactory.quad(quad.subject, quad.predicate, quad.object);
341
647
  }
@@ -447,9 +753,18 @@ class MixDataAccessor {
447
753
  }
448
754
  }
449
755
  async getExistingLocalRdfMetadata(identifier) {
450
- const metadata = await this.rdfFileDataAccessor.getMetadata(identifier);
451
- metadata.contentType = this.localRdfContentType(identifier);
452
- return metadata;
756
+ try {
757
+ const metadata = await this.rdfFileDataAccessor.getMetadata(identifier);
758
+ metadata.contentType = this.localRdfContentType(identifier);
759
+ return metadata;
760
+ }
761
+ catch (error) {
762
+ if (community_server_1.NotFoundHttpError.isInstance(error)) {
763
+ throw error;
764
+ }
765
+ this.logger.warn(`Ignoring unreadable local RDF metadata for ${identifier.path}: ${error instanceof Error ? error.message : String(error)}`);
766
+ return this.createLocalRdfMetadata(identifier, new community_server_1.RepresentationMetadata(identifier));
767
+ }
453
768
  }
454
769
  createLocalRdfMetadata(identifier, metadata) {
455
770
  const localMetadata = new community_server_1.RepresentationMetadata(metadata);