@unrdf/knowledge-engine 5.0.1

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 (60) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +84 -0
  3. package/package.json +64 -0
  4. package/src/browser-shims.mjs +343 -0
  5. package/src/browser.mjs +910 -0
  6. package/src/canonicalize.mjs +414 -0
  7. package/src/condition-cache.mjs +109 -0
  8. package/src/condition-evaluator.mjs +722 -0
  9. package/src/dark-matter-core.mjs +742 -0
  10. package/src/define-hook.mjs +213 -0
  11. package/src/effect-sandbox-browser.mjs +283 -0
  12. package/src/effect-sandbox-worker.mjs +170 -0
  13. package/src/effect-sandbox.mjs +517 -0
  14. package/src/engines/index.mjs +11 -0
  15. package/src/engines/rdf-engine.mjs +299 -0
  16. package/src/file-resolver.mjs +387 -0
  17. package/src/hook-executor-batching.mjs +277 -0
  18. package/src/hook-executor.mjs +870 -0
  19. package/src/hook-management.mjs +150 -0
  20. package/src/index.mjs +93 -0
  21. package/src/ken-parliment.mjs +119 -0
  22. package/src/ken.mjs +149 -0
  23. package/src/knowledge-engine/builtin-rules.mjs +190 -0
  24. package/src/knowledge-engine/inference-engine.mjs +418 -0
  25. package/src/knowledge-engine/knowledge-engine.mjs +317 -0
  26. package/src/knowledge-engine/pattern-dsl.mjs +142 -0
  27. package/src/knowledge-engine/pattern-matcher.mjs +215 -0
  28. package/src/knowledge-engine/rules.mjs +184 -0
  29. package/src/knowledge-engine.mjs +319 -0
  30. package/src/knowledge-hook-engine.mjs +360 -0
  31. package/src/knowledge-hook-manager.mjs +469 -0
  32. package/src/knowledge-substrate-core.mjs +927 -0
  33. package/src/lite.mjs +222 -0
  34. package/src/lockchain-writer-browser.mjs +414 -0
  35. package/src/lockchain-writer.mjs +602 -0
  36. package/src/monitoring/andon-signals.mjs +775 -0
  37. package/src/observability.mjs +531 -0
  38. package/src/parse.mjs +290 -0
  39. package/src/performance-optimizer.mjs +678 -0
  40. package/src/policy-pack.mjs +572 -0
  41. package/src/query-cache.mjs +116 -0
  42. package/src/query-optimizer.mjs +1051 -0
  43. package/src/query.mjs +306 -0
  44. package/src/reason.mjs +350 -0
  45. package/src/resolution-layer.mjs +506 -0
  46. package/src/schemas.mjs +1063 -0
  47. package/src/security/error-sanitizer.mjs +257 -0
  48. package/src/security/path-validator.mjs +194 -0
  49. package/src/security/sandbox-restrictions.mjs +331 -0
  50. package/src/security-validator.mjs +389 -0
  51. package/src/store-cache.mjs +137 -0
  52. package/src/telemetry.mjs +167 -0
  53. package/src/transaction.mjs +810 -0
  54. package/src/utils/adaptive-monitor.mjs +746 -0
  55. package/src/utils/circuit-breaker.mjs +513 -0
  56. package/src/utils/edge-case-handler.mjs +503 -0
  57. package/src/utils/memory-manager.mjs +498 -0
  58. package/src/utils/ring-buffer.mjs +282 -0
  59. package/src/validate.mjs +319 -0
  60. package/src/validators/index.mjs +338 -0
package/src/parse.mjs ADDED
@@ -0,0 +1,290 @@
1
+ /**
2
+ * @file Parsing and serialization utilities for RDF data.
3
+ * @module parse
4
+ */
5
+
6
+ import { createStore, dataFactory } from '@unrdf/oxigraph';
7
+ import { trace, SpanStatusCode } from '@opentelemetry/api';
8
+
9
+ const tracer = trace.getTracer('unrdf');
10
+
11
+ /**
12
+ * Parse a Turtle string into a Store.
13
+ * @param {string} ttl - The Turtle string to parse
14
+ * @param {string} [baseIRI] - Base IRI for resolving relative URIs
15
+ * @returns {Promise<Store>} Promise resolving to a Store containing the parsed quads
16
+ *
17
+ * @throws {Error} If parsing fails
18
+ *
19
+ * @example
20
+ * const ttl = `
21
+ * @prefix ex: <http://example.org/> .
22
+ * ex:alice ex:knows ex:bob .
23
+ * `;
24
+ * const store = await parseTurtle(ttl, 'http://example.org/');
25
+ */
26
+ export async function parseTurtle(ttl, baseIRI = 'http://example.org/') {
27
+ if (typeof ttl !== 'string') {
28
+ throw new TypeError('parseTurtle: ttl must be a string');
29
+ }
30
+ if (typeof baseIRI !== 'string') {
31
+ throw new TypeError('parseTurtle: baseIRI must be a string');
32
+ }
33
+
34
+ return tracer.startActiveSpan('parse.turtle', async span => {
35
+ try {
36
+ span.setAttributes({
37
+ 'parse.format': 'turtle',
38
+ 'parse.base_iri': baseIRI,
39
+ 'parse.input_length': ttl.length,
40
+ });
41
+
42
+ // Use Oxigraph for parsing Turtle
43
+ const store = createStore();
44
+ store.load(ttl, { format: 'text/turtle', base: baseIRI });
45
+
46
+ span.setAttribute('parse.quads_count', store.size);
47
+ span.setStatus({ code: SpanStatusCode.OK });
48
+
49
+ return store;
50
+ } catch (error) {
51
+ span.recordException(error);
52
+ span.setStatus({
53
+ code: SpanStatusCode.ERROR,
54
+ message: error.message,
55
+ });
56
+ throw new Error(`Failed to parse Turtle: ${error.message}`);
57
+ } finally {
58
+ span.end();
59
+ }
60
+ });
61
+ }
62
+
63
+ /**
64
+ * Serialize a store to Turtle.
65
+ * @param {Store} store - The store to serialize
66
+ * @param {Object} [options] - Serialization options
67
+ * @param {Object} [options.prefixes] - Prefix mappings
68
+ * @param {string} [options.baseIRI] - Base IRI for the output
69
+ * @returns {Promise<string>} Promise resolving to the Turtle string
70
+ *
71
+ * @throws {Error} If serialization fails
72
+ *
73
+ * @example
74
+ * const turtle = await toTurtle(store, {
75
+ * prefixes: { ex: 'http://example.org/' },
76
+ * baseIRI: 'http://example.org/'
77
+ * });
78
+ */
79
+ export async function toTurtle(store, options = {}) {
80
+ if (!store || typeof store.getQuads !== 'function') {
81
+ throw new TypeError('toTurtle: store must be a valid Store instance');
82
+ }
83
+
84
+ try {
85
+ // Use Oxigraph dump for serialization
86
+ let result = store.dump({ format: 'text/turtle' });
87
+
88
+ // Add @base directive if baseIRI is provided
89
+ if (options.baseIRI) {
90
+ result = `@base <${options.baseIRI}> .\n\n${result}`;
91
+ }
92
+
93
+ // Add prefixes if provided (prepend to output)
94
+ if (options.prefixes && Object.keys(options.prefixes).length > 0) {
95
+ const prefixLines = Object.entries(options.prefixes)
96
+ .map(([prefix, iri]) => `@prefix ${prefix}: <${iri}> .`)
97
+ .join('\n');
98
+ result = `${prefixLines}\n\n${result}`;
99
+ }
100
+
101
+ return result;
102
+ } catch (error) {
103
+ throw new Error(`Failed to serialize to Turtle: ${error.message}`);
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Serialize a store to canonical N-Quads.
109
+ * @param {Store} store - The store to serialize
110
+ * @param {Object} [options] - Serialization options
111
+ * @returns {Promise<string>} Promise resolving to the N-Quads string
112
+ *
113
+ * @throws {Error} If serialization fails
114
+ *
115
+ * @example
116
+ * const nquads = await toNQuads(store);
117
+ */
118
+ export async function toNQuads(store, options = {}) {
119
+ if (!store || typeof store.getQuads !== 'function') {
120
+ throw new TypeError('toNQuads: store must be a valid Store instance');
121
+ }
122
+
123
+ try {
124
+ // Use Oxigraph dump for N-Quads serialization
125
+ const result = store.dump({ format: 'application/n-quads', ...options });
126
+ return result;
127
+ } catch (error) {
128
+ throw new Error(`Failed to serialize to N-Quads: ${error.message}`);
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Parse a JSON-LD string into a Store.
134
+ * @param {string} jsonld - The JSON-LD string to parse
135
+ * @param {Object} [options] - Parsing options
136
+ * @param {string} [options.baseIRI] - Base IRI for resolving relative URIs
137
+ * @returns {Promise<Store>} Promise resolving to a Store containing the parsed quads
138
+ *
139
+ * @throws {Error} If parsing fails
140
+ *
141
+ * @example
142
+ * const jsonld = `{
143
+ * "@context": {"ex": "http://example.org/"},
144
+ * "@id": "ex:alice",
145
+ * "ex:knows": {"@id": "ex:bob"}
146
+ * }`;
147
+ * const store = await parseJsonLd(jsonld);
148
+ */
149
+ export async function parseJsonLd(jsonld, _options = {}) {
150
+ if (typeof jsonld !== 'string' && typeof jsonld !== 'object') {
151
+ throw new TypeError('parseJsonLd: jsonld must be a string or object');
152
+ }
153
+
154
+ try {
155
+ // Parse JSON string if needed
156
+ const jsonldData = typeof jsonld === 'string' ? JSON.parse(jsonld) : jsonld;
157
+
158
+ if (!jsonldData || (!Array.isArray(jsonldData) && typeof jsonldData !== 'object')) {
159
+ throw new TypeError('parseJsonLd: jsonld must be an object or array');
160
+ }
161
+
162
+ // Convert JSON-LD to RDF quads
163
+ // This is a simplified implementation - in production you would use a proper JSON-LD to RDF converter
164
+ const store = createStore();
165
+
166
+ // Handle @graph array or single object
167
+ const items = jsonldData['@graph'] || (Array.isArray(jsonldData) ? jsonldData : [jsonldData]);
168
+
169
+ // Validate that we have valid JSON-LD structure
170
+ if (
171
+ items.length === 0 ||
172
+ !items.some(item => item && typeof item === 'object' && item['@id'])
173
+ ) {
174
+ throw new Error('Invalid JSON-LD structure: no valid items with @id found');
175
+ }
176
+
177
+ for (const item of items) {
178
+ if (item && item['@id']) {
179
+ const subject = item['@id'];
180
+
181
+ // Process each property
182
+ for (const [key, value] of Object.entries(item)) {
183
+ if (key === '@id' || key === '@context') continue;
184
+
185
+ if (Array.isArray(value)) {
186
+ for (const val of value) {
187
+ if (typeof val === 'object' && val['@id']) {
188
+ store.add(
189
+ dataFactory.quad(
190
+ dataFactory.namedNode(subject),
191
+ dataFactory.namedNode(key),
192
+ dataFactory.namedNode(val['@id'])
193
+ )
194
+ );
195
+ } else if (typeof val === 'string' || typeof val === 'number') {
196
+ store.add(
197
+ dataFactory.quad(
198
+ dataFactory.namedNode(subject),
199
+ dataFactory.namedNode(key),
200
+ dataFactory.literal(String(val))
201
+ )
202
+ );
203
+ }
204
+ }
205
+ } else if (typeof value === 'object' && value['@id']) {
206
+ store.add(
207
+ dataFactory.quad(
208
+ dataFactory.namedNode(subject),
209
+ dataFactory.namedNode(key),
210
+ dataFactory.namedNode(value['@id'])
211
+ )
212
+ );
213
+ } else if (typeof value === 'string' || typeof value === 'number') {
214
+ store.add(
215
+ dataFactory.quad(
216
+ dataFactory.namedNode(subject),
217
+ dataFactory.namedNode(key),
218
+ dataFactory.literal(String(value))
219
+ )
220
+ );
221
+ }
222
+ }
223
+ }
224
+ }
225
+
226
+ return store;
227
+ } catch (error) {
228
+ throw new Error(`Failed to parse JSON-LD: ${error.message}`);
229
+ }
230
+ }
231
+
232
+ /**
233
+ * Serialize a store to JSON-LD.
234
+ * @param {Store} store - The store to serialize
235
+ * @param {Object} [options] - Serialization options
236
+ * @param {Object} [options.context] - JSON-LD context
237
+ * @returns {Promise<Object>} Promise resolving to the JSON-LD object
238
+ *
239
+ * @throws {Error} If serialization fails
240
+ *
241
+ * @example
242
+ * const jsonld = await toJsonLd(store, {
243
+ * context: { ex: 'http://example.org/' }
244
+ * });
245
+ */
246
+ export async function toJsonLd(store, options = {}) {
247
+ if (!store || typeof store.getQuads !== 'function') {
248
+ throw new TypeError('toJsonLd: store must be a valid Store instance');
249
+ }
250
+
251
+ try {
252
+ // This is a simplified implementation
253
+ // In production, you would use a proper RDF to JSON-LD converter
254
+ const quads = store.getQuads();
255
+ const result = {
256
+ '@context': options.context || {},
257
+ '@graph': [],
258
+ };
259
+
260
+ // Add @base to context if baseIRI is provided
261
+ if (options.baseIRI) {
262
+ result['@context']['@base'] = options.baseIRI;
263
+ }
264
+
265
+ // Convert quads to JSON-LD format
266
+ for (const quad of quads) {
267
+ const subject = quad.subject.value;
268
+ const predicate = quad.predicate.value;
269
+ const object = quad.object.value;
270
+
271
+ // Find existing subject in graph or create new one
272
+ let subjectNode = result['@graph'].find(node => node['@id'] === subject);
273
+ if (!subjectNode) {
274
+ subjectNode = { '@id': subject };
275
+ result['@graph'].push(subjectNode);
276
+ }
277
+
278
+ // Add predicate-object pair
279
+ if (!subjectNode[predicate]) {
280
+ subjectNode[predicate] = [];
281
+ }
282
+ subjectNode[predicate].push({ '@id': object });
283
+ }
284
+
285
+ // Return as object (users can call JSON.stringify if they need a string)
286
+ return result;
287
+ } catch (error) {
288
+ throw new Error(`Failed to serialize to JSON-LD: ${error.message}`);
289
+ }
290
+ }