@unrdf/knowledge-engine 5.0.1 → 26.4.3

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 (71) hide show
  1. package/package.json +13 -7
  2. package/src/ai-enhanced-search.mjs +371 -0
  3. package/src/anomaly-detector.mjs +226 -0
  4. package/src/artifact-generator.mjs +251 -0
  5. package/src/browser.mjs +1 -1
  6. package/src/chatman/disruption-arithmetic.mjs +140 -0
  7. package/src/chatman/market-dynamics.mjs +140 -0
  8. package/src/chatman/organizational-dynamics.mjs +140 -0
  9. package/src/chatman/strategic-dynamics.mjs +140 -0
  10. package/src/chatman-config-loader.mjs +282 -0
  11. package/src/chatman-engine.mjs +431 -0
  12. package/src/chatman-operator.mjs +342 -0
  13. package/src/dark-field-detector.mjs +312 -0
  14. package/src/formation-theorems.mjs +345 -0
  15. package/src/index.mjs +20 -2
  16. package/src/knowledge-hook-manager.mjs +1 -1
  17. package/src/lockchain-writer-browser.mjs +2 -2
  18. package/src/observability.mjs +40 -4
  19. package/src/query-optimizer.mjs +1 -1
  20. package/src/resolution-layer.mjs +1 -1
  21. package/src/transaction.mjs +11 -9
  22. package/README.md +0 -84
  23. package/src/browser-shims.mjs +0 -343
  24. package/src/canonicalize.mjs +0 -414
  25. package/src/condition-cache.mjs +0 -109
  26. package/src/condition-evaluator.mjs +0 -722
  27. package/src/dark-matter-core.mjs +0 -742
  28. package/src/define-hook.mjs +0 -213
  29. package/src/effect-sandbox-browser.mjs +0 -283
  30. package/src/effect-sandbox-worker.mjs +0 -170
  31. package/src/effect-sandbox.mjs +0 -517
  32. package/src/engines/index.mjs +0 -11
  33. package/src/engines/rdf-engine.mjs +0 -299
  34. package/src/file-resolver.mjs +0 -387
  35. package/src/hook-executor-batching.mjs +0 -277
  36. package/src/hook-executor.mjs +0 -870
  37. package/src/hook-management.mjs +0 -150
  38. package/src/ken-parliment.mjs +0 -119
  39. package/src/ken.mjs +0 -149
  40. package/src/knowledge-engine/builtin-rules.mjs +0 -190
  41. package/src/knowledge-engine/inference-engine.mjs +0 -418
  42. package/src/knowledge-engine/knowledge-engine.mjs +0 -317
  43. package/src/knowledge-engine/pattern-dsl.mjs +0 -142
  44. package/src/knowledge-engine/pattern-matcher.mjs +0 -215
  45. package/src/knowledge-engine/rules.mjs +0 -184
  46. package/src/knowledge-engine.mjs +0 -319
  47. package/src/knowledge-hook-engine.mjs +0 -360
  48. package/src/knowledge-substrate-core.mjs +0 -927
  49. package/src/lite.mjs +0 -222
  50. package/src/lockchain-writer.mjs +0 -602
  51. package/src/monitoring/andon-signals.mjs +0 -775
  52. package/src/parse.mjs +0 -290
  53. package/src/performance-optimizer.mjs +0 -678
  54. package/src/policy-pack.mjs +0 -572
  55. package/src/query-cache.mjs +0 -116
  56. package/src/query.mjs +0 -306
  57. package/src/reason.mjs +0 -350
  58. package/src/schemas.mjs +0 -1063
  59. package/src/security/error-sanitizer.mjs +0 -257
  60. package/src/security/path-validator.mjs +0 -194
  61. package/src/security/sandbox-restrictions.mjs +0 -331
  62. package/src/security-validator.mjs +0 -389
  63. package/src/store-cache.mjs +0 -137
  64. package/src/telemetry.mjs +0 -167
  65. package/src/utils/adaptive-monitor.mjs +0 -746
  66. package/src/utils/circuit-breaker.mjs +0 -513
  67. package/src/utils/edge-case-handler.mjs +0 -503
  68. package/src/utils/memory-manager.mjs +0 -498
  69. package/src/utils/ring-buffer.mjs +0 -282
  70. package/src/validate.mjs +0 -319
  71. package/src/validators/index.mjs +0 -338
@@ -1,213 +0,0 @@
1
- /**
2
- * @file 80/20 Knowledge Hook definition contract for autonomic systems.
3
- * @module newco/defineHook
4
- *
5
- * @description
6
- * This module provides the `defineHook` function, the sole entry point for
7
- * defining a Knowledge Hook. The contract enforces critical principles for
8
- * autonomic, deterministic, and provable systems:
9
- *
10
- * 1. **Conditions are Addressed, Not Embedded**: The `when` clause MUST
11
- * reference an external, content-addressed SPARQL or SHACL file.
12
- * This forbids inline query strings, ensuring that governance logic is
13
- * a verifiable, standalone artifact.
14
- *
15
- * 2. **Reflex Arc Lifecycle**: The `before`, `run`, and `after` functions
16
- * provide a minimal, complete lifecycle for autonomic reflexes:
17
- * - `before`: A pre-condition gate for payload normalization or cancellation.
18
- * - `run`: The core effect or analysis.
19
- * - `after`: A post-execution step for auditing and cleanup.
20
- *
21
- * 3. **Declarative Configuration**: Determinism and receipting strategies
22
- * are declared as metadata, not implemented imperatively within the hook.
23
- *
24
- * 4. **Comprehensive Validation**: Uses Zod schemas for complete type safety
25
- * and validation of all hook components.
26
- *
27
- * This API is designed to feel familiar to users of Nitro's `defineTask`
28
- * while being fundamentally adapted for a knowledge-native, policy-first runtime.
29
- */
30
-
31
- /**
32
- * A content-addressed file reference. This is the only way to specify a
33
- * condition, ensuring that governance logic is a verifiable artifact and
34
- * not an inline string.
35
- *
36
- * @typedef {Object} Ref
37
- * @property {string} uri - The URI of the resource, typically a file path like "file://hooks/compliance/largeTx.ask.rq".
38
- * @property {string} sha256 - The SHA-256 hash of the file's content, for integrity and provenance.
39
- * @property {'application/sparql-query'|'text/shacl'|'text/turtle'} mediaType - The MIME type of the resource.
40
- */
41
-
42
- /**
43
- * Descriptive metadata for cataloging, discovery, and tooling.
44
- *
45
- * @typedef {Object} HookMeta
46
- * @property {string} name - A unique, human-readable name for the hook (e.g., "compliance:largeTx").
47
- * @property {string} [description] - A brief explanation of the hook's purpose.
48
- * @property {string[]} [ontology] - A list of ontology prefixes this hook relates to (e.g., ["fibo", "prov"]).
49
- */
50
-
51
- /**
52
- * Defines the knowledge surface the hook observes during its condition evaluation.
53
- *
54
- * @typedef {Object} HookChannel
55
- * @property {string[]} [graphs] - An array of named graph IRIs or labels to scope the query.
56
- * @property {'before'|'after'|'delta'} [view] - The state of the graph to evaluate against. 'before' is the state before the delta is applied, 'after' is the state after, and 'delta' is a graph containing only the additions and removals.
57
- */
58
-
59
- /**
60
- * The declarative trigger condition for the hook, based on a content-addressed reference.
61
- *
62
- * @typedef {Object} HookCondition
63
- * @property {'sparql-ask'|'sparql-select'|'shacl'} kind - The type of evaluation to perform.
64
- * @property {Ref} ref - The content-addressed reference to the SPARQL or SHACL file.
65
- */
66
-
67
- /**
68
- * The execution context passed to all lifecycle functions, providing access
69
- * to the graph and environment.
70
- *
71
- * @typedef {Object} HookContext
72
- * @property {any} [graph] - The active RDF/JS Store or Dataset instance.
73
- * @property {Object.<string, unknown>} [env] - Environment variables or runtime configuration.
74
- */
75
-
76
- /**
77
- * The data payload for a hook event.
78
- *
79
- * @typedef {Object.<string, unknown>} HookPayload
80
- */
81
-
82
- /**
83
- * The event object passed to each lifecycle function of a hook.
84
- *
85
- * @typedef {Object} HookEvent
86
- * @property {string} name - The name of the hook being executed.
87
- * @property {HookPayload} payload - The input data for the event.
88
- * @property {HookContext} context - The execution context.
89
- */
90
-
91
- /**
92
- * The standardized result of a hook's `run` or `after` function.
93
- *
94
- * @typedef {Object} HookResult
95
- * @property {any} [result] - The primary output or return value of the hook.
96
- * @property {any} [assertions] - Optional RDF quads to be added to the graph as a result of the hook's execution.
97
- * @property {any} [deltas] - An optional, more complex delta (additions/removals) to be applied.
98
- * @property {boolean} [cancelled] - Indicates if the hook was cancelled during the `before` phase.
99
- * @property {string} [reason] - The reason for cancellation.
100
- */
101
-
102
- /**
103
- * The complete, 80/20 contract for a Knowledge Hook. This object defines
104
- * the hook's identity, its trigger condition, its autonomic behavior, and
105
- * its operational guarantees.
106
- *
107
- * @typedef {Object} KnowledgeHook
108
- * @property {HookMeta} meta - Essential metadata for the hook.
109
- * @property {HookChannel} [channel] - The observation channel for the condition.
110
- * @property {HookCondition} when - The declarative, file-based trigger condition.
111
- * @property {{ seed?: number }} [determinism] - Configuration for deterministic operations. Defaults to a fixed seed of 42.
112
- * @property {{ anchor?: ('git-notes'|'none') }} [receipt] - Strategy for anchoring the transaction receipt. Defaults to 'none'.
113
- * @property {(e: HookEvent) => Promise<Partial<HookPayload>|{cancel:true,reason?:string}> | Partial<HookPayload>|{cancel:true,reason?:string}} [before] - A function that runs before the condition is checked. It can modify the payload or cancel the execution.
114
- * @property {(e: HookEvent) => Promise<HookResult> | HookResult} run - The main execution body of the hook.
115
- * @property {(e: HookEvent & { result?: any, cancelled?: boolean, reason?: string }) => Promise<HookResult> | HookResult} [after] - A function that runs after the `run` phase, for cleanup or auditing.
116
- */
117
-
118
- /**
119
- * Defines a Knowledge Hook, validating its structure and enforcing the
120
- * 80/20 contract for autonomic systems using comprehensive Zod validation.
121
- *
122
- * @template T
123
- * @param {KnowledgeHook} def - The hook definition object.
124
- * @returns {KnowledgeHook} The validated and normalized hook definition.
125
- */
126
- import { createKnowledgeHook } from './schemas.mjs';
127
- import { defaultSecurityValidator } from './security-validator.mjs';
128
-
129
- /**
130
- *
131
- */
132
- export function defineHook(def) {
133
- // Use comprehensive Zod validation
134
- const validatedHook = createKnowledgeHook(def);
135
-
136
- // Apply security validation (warn only, don't block)
137
- // Security will be enforced at execution time via sandbox
138
- const securityValidation = defaultSecurityValidator.validateKnowledgeHook(validatedHook);
139
- if (!securityValidation.valid) {
140
- // Log warning in development (can't modify frozen object, so just log)
141
- if (process.env.NODE_ENV !== 'production') {
142
- console.warn(
143
- `[Security Warning] Hook "${validatedHook.meta.name}": ${securityValidation.blockReason}`
144
- );
145
- }
146
- }
147
-
148
- return validatedHook;
149
- }
150
-
151
- /* ------------------------- Example (Happy Path) ------------------------- */
152
-
153
- /**
154
- * This is an example of how to use `defineHook` to create a compliance gate.
155
- * It demonstrates all the core features of the 80/20 contract.
156
- */
157
- export const exampleComplianceHook = defineHook({
158
- meta: {
159
- name: 'compliance:largeTx',
160
- description:
161
- 'Alerts and creates an audit trail when a financial transaction exceeds a certain threshold.',
162
- ontology: ['fibo'],
163
- },
164
- channel: {
165
- graphs: ['urn:graph:fibo:prod'],
166
- view: 'delta',
167
- },
168
- when: {
169
- kind: 'sparql-ask',
170
- ref: {
171
- uri: 'file://hooks/compliance/largeTx.ask.rq',
172
- sha256: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', // Example hash
173
- mediaType: 'application/sparql-query',
174
- },
175
- },
176
- determinism: { seed: 42 },
177
- receipt: { anchor: 'git-notes' },
178
-
179
- async before({ payload }) {
180
- if (!payload || typeof payload.amount !== 'number' || payload.amount <= 0) {
181
- return {
182
- cancel: true,
183
- reason: 'Invalid or non-positive transaction amount.',
184
- };
185
- }
186
- // Normalize payload for the `run` step
187
- return { ...payload, validatedAt: new Date().toISOString() };
188
- },
189
-
190
- async run({ payload }) {
191
- console.log(
192
- `[RUN] Processing large transaction of ${payload.amount} validated at ${payload.validatedAt}`
193
- );
194
- // The main result could be an alert object, an event to be emitted, etc.
195
- return {
196
- result: { status: 'alert-dispatched', amount: payload.amount },
197
- // This hook also generates a new piece of knowledge (an audit triple).
198
- assertions: [
199
- /* an RDF quad like: [ a:tx, prov:wasGeneratedBy, this:hook ] */
200
- ],
201
- };
202
- },
203
-
204
- async after({ result, cancelled, reason }) {
205
- if (cancelled) {
206
- console.log(`[AFTER] Hook execution was cancelled. Reason: ${reason}`);
207
- } else {
208
- console.log(`[AFTER] Hook successfully completed with status: ${result?.result?.status}`);
209
- }
210
- // The 'after' hook always returns a result for logging/receipt purposes.
211
- return { result: { finalStatus: cancelled ? 'cancelled' : 'completed' } };
212
- },
213
- });
@@ -1,283 +0,0 @@
1
- /**
2
- * @file Browser-compatible Effect Sandbox
3
- * @module effect-sandbox-browser
4
- *
5
- * @description
6
- * Browser-compatible version of the effect sandbox that uses Web Workers
7
- * instead of Node.js worker threads for secure hook execution.
8
- */
9
-
10
- import { randomUUID, Worker } from './browser-shims.mjs';
11
- import { z } from 'zod';
12
-
13
- /**
14
- * Schema for sandbox configuration
15
- */
16
- const SandboxConfigSchema = z.object({
17
- type: z.enum(['worker', 'global']).default('worker'), // Only worker mode in browser
18
- timeout: z.number().int().positive().max(30000).default(5000), // Shorter timeout for browser
19
- memoryLimit: z
20
- .number()
21
- .int()
22
- .positive()
23
- .max(100 * 1024 * 1024)
24
- .default(10 * 1024 * 1024), // 10MB default
25
- allowedGlobals: z
26
- .array(z.string())
27
- .default(['console', 'Date', 'Math', 'JSON', 'Array', 'Object']),
28
- enableNetwork: z.boolean().default(false),
29
- enableFileSystem: z.boolean().default(false),
30
- strictMode: z.boolean().default(true),
31
- });
32
-
33
- /**
34
- * Schema for sandbox execution context
35
- */
36
- const SandboxContextSchema = z.object({
37
- event: z.any(),
38
- store: z.any(),
39
- delta: z.any(),
40
- metadata: z.record(z.any()).optional(),
41
- });
42
-
43
- /**
44
- * Schema for sandbox execution result
45
- */
46
- const SandboxResultSchema = z.object({
47
- success: z.boolean(),
48
- result: z.any().optional(),
49
- error: z.string().optional(),
50
- duration: z.number().nonnegative(),
51
- });
52
-
53
- /**
54
- * Browser-compatible Effect Sandbox
55
- */
56
- export class EffectSandbox {
57
- /**
58
- *
59
- */
60
- constructor(config = {}) {
61
- this.config = SandboxConfigSchema.parse(config);
62
- this.workers = new Map();
63
- this.executionCount = 0;
64
- this.totalExecutions = 0;
65
- this.totalDuration = 0;
66
- }
67
-
68
- /**
69
- * Execute a hook effect in the sandbox
70
- * @param {Function} effect - The effect function to execute
71
- * @param {Object} context - Execution context
72
- * @param {Object} [options] - Execution options
73
- * @returns {Promise<Object>} Execution result
74
- */
75
- async executeEffect(effect, context, options = {}) {
76
- const executionId = randomUUID();
77
- const startTime = Date.now();
78
-
79
- try {
80
- // Validate context
81
- const validatedContext = SandboxContextSchema.parse(context);
82
-
83
- let result;
84
- switch (this.config.type) {
85
- case 'worker':
86
- result = await this._executeInWorker(effect, validatedContext, executionId, options);
87
- break;
88
- case 'global':
89
- // Not recommended for browser, but allowed for testing
90
- result = await this._executeInGlobal(effect, validatedContext, executionId, options);
91
- break;
92
- default:
93
- throw new Error(`Unsupported sandbox type: ${this.config.type}`);
94
- }
95
-
96
- const duration = Date.now() - startTime;
97
- this.totalExecutions++;
98
- this.totalDuration += duration;
99
-
100
- const validatedResult = SandboxResultSchema.parse({
101
- ...result,
102
- duration,
103
- });
104
-
105
- return validatedResult;
106
- } catch (error) {
107
- const duration = Date.now() - startTime;
108
- this.totalExecutions++;
109
-
110
- return {
111
- success: false,
112
- error: error.message,
113
- duration,
114
- };
115
- }
116
- }
117
-
118
- /**
119
- * Execute effect in Web Worker
120
- * @private
121
- */
122
- async _executeInWorker(effect, context, executionId, _options) {
123
- const workerScript = this._createWorkerScript(effect);
124
-
125
- const worker = new Worker(workerScript, {
126
- name: `effect-sandbox-${executionId}`,
127
- });
128
-
129
- return new Promise((resolve, reject) => {
130
- const timeout = setTimeout(() => {
131
- worker.terminate();
132
- reject(new Error(`Worker execution timeout after ${this.config.timeout}ms`));
133
- }, this.config.timeout);
134
-
135
- worker.onmessage = event => {
136
- clearTimeout(timeout);
137
- worker.terminate();
138
-
139
- if (event.data.error) {
140
- reject(new Error(event.data.error));
141
- } else {
142
- resolve(event.data);
143
- }
144
- };
145
-
146
- worker.onerror = error => {
147
- clearTimeout(timeout);
148
- worker.terminate();
149
- reject(new Error(`Worker error: ${error.message}`));
150
- };
151
-
152
- worker.postMessage({ context, config: this.config });
153
- });
154
- }
155
-
156
- /**
157
- * Execute effect in global scope (not recommended for production)
158
- * @private
159
- */
160
- async _executeInGlobal(effect, context, _executionId, _options) {
161
- return new Promise((resolve, reject) => {
162
- try {
163
- const result = effect(context, {
164
- emitEvent: event => console.log('Event:', event),
165
- log: message => console.log(message),
166
- assert: (condition, message) => {
167
- if (!condition) throw new Error(message || 'Assertion failed');
168
- },
169
- });
170
-
171
- if (result instanceof Promise) {
172
- result.then(resolve).catch(reject);
173
- } else {
174
- resolve({ success: true, result });
175
- }
176
- } catch (error) {
177
- resolve({ success: false, error: error.message });
178
- }
179
- });
180
- }
181
-
182
- /**
183
- * Create worker script from effect function
184
- * @private
185
- */
186
- _createWorkerScript(effect) {
187
- const _allowedGlobals = this.config._allowedGlobals.join(', ');
188
-
189
- return `
190
- // Worker script for effect sandbox
191
- const effect = ${effect.toString()};
192
-
193
- // Sandbox globals
194
- ${this.config.allowedGlobals.map(global => `const ${global} = self.${global};`).join('\n')}
195
-
196
- // Safe console
197
- const console = {
198
- log: (...args) => self.postMessage({ type: 'console', level: 'log', args }),
199
- warn: (...args) => self.postMessage({ type: 'console', level: 'warn', args }),
200
- error: (...args) => self.postMessage({ type: 'console', level: 'error', args }),
201
- info: (...args) => self.postMessage({ type: 'console', level: 'info', args })
202
- };
203
-
204
- // Safe API implementations
205
- const emitEvent = (event) => {
206
- self.postMessage({ type: 'event', event });
207
- };
208
-
209
- const log = (message) => {
210
- self.postMessage({ type: 'log', message });
211
- };
212
-
213
- const assert = (condition, message) => {
214
- throw new Error(message || 'Assertion failed');
215
- };
216
-
217
- // Message handler
218
- self.onmessage = async (event) => {
219
- try {
220
- const { context, config } = event.data;
221
-
222
- const result = await effect(context, {
223
- emitEvent,
224
- log,
225
- assert
226
- });
227
-
228
- self.postMessage({
229
- success: true,
230
- result,
231
- type: 'result'
232
- });
233
- } catch (error) {
234
- self.postMessage({
235
- success: false,
236
- error: error.message,
237
- type: 'error'
238
- });
239
- }
240
- };
241
- `;
242
- }
243
-
244
- /**
245
- * Get sandbox statistics
246
- * @returns {Object} Statistics
247
- */
248
- getStats() {
249
- return {
250
- type: this.config.type,
251
- activeWorkers: this.workers.size,
252
- totalExecutions: this.totalExecutions,
253
- averageDuration: this.totalExecutions > 0 ? this.totalDuration / this.totalExecutions : 0,
254
- config: this.config,
255
- };
256
- }
257
-
258
- /**
259
- * Clear sandbox state
260
- */
261
- clear() {
262
- // Terminate all workers
263
- for (const worker of this.workers.values()) {
264
- worker.terminate();
265
- }
266
- this.workers.clear();
267
-
268
- this.executionCount = 0;
269
- this.totalExecutions = 0;
270
- this.totalDuration = 0;
271
- }
272
- }
273
-
274
- /**
275
- * Create a new effect sandbox
276
- * @param {Object} [config] - Sandbox configuration
277
- * @returns {EffectSandbox} New sandbox instance
278
- */
279
- export function createEffectSandbox(config = {}) {
280
- return new EffectSandbox(config);
281
- }
282
-
283
- export default EffectSandbox;
@@ -1,170 +0,0 @@
1
- /**
2
- * @file Worker thread implementation for effect sandbox
3
- * @module effect-sandbox-worker
4
- *
5
- * @description
6
- * Worker thread implementation for secure hook effect execution.
7
- * This file runs in a separate worker thread to isolate hook execution.
8
- */
9
-
10
- import { parentPort, workerData, isMainThread } from 'worker_threads';
11
-
12
- /**
13
- * Worker thread entry point
14
- */
15
- if (!isMainThread) {
16
- const { effect, context, executionId, config, _options } = workerData;
17
-
18
- try {
19
- // Create safe execution environment
20
- const safeGlobals = createSafeGlobals(context, config);
21
-
22
- // Create safe effect function
23
- const safeEffect = createSafeEffect(effect, safeGlobals);
24
-
25
- // Execute effect with timeout
26
- const result = await executeWithTimeout(safeEffect, context, config.timeout);
27
-
28
- // Send result back to main thread
29
- parentPort.postMessage({
30
- success: true,
31
- result: result.result,
32
- assertions: result.assertions || [],
33
- events: result.events || [],
34
- executionId,
35
- });
36
- } catch (error) {
37
- // Send error back to main thread
38
- parentPort.postMessage({
39
- success: false,
40
- error: error.message,
41
- executionId,
42
- });
43
- }
44
- }
45
-
46
- /**
47
- * Create safe globals for worker execution
48
- * @param {Object} context - Execution context
49
- * @param {Object} config - Sandbox configuration
50
- * @returns {Object} Safe globals
51
- */
52
- function createSafeGlobals(context, config) {
53
- const globals = {};
54
-
55
- // Add context data
56
- globals.event = context.event;
57
- globals.store = context.store;
58
- globals.delta = context.delta;
59
- globals.metadata = context.metadata || {};
60
-
61
- // Add safe console
62
- globals.console = {
63
- log: message => console.log(`[Worker] ${message}`),
64
- warn: message => console.warn(`[Worker] ${message}`),
65
- error: message => console.error(`[Worker] ${message}`),
66
- info: message => console.info(`[Worker] ${message}`),
67
- };
68
-
69
- // Add safe functions
70
- globals.emitEvent = eventData => {
71
- if (!context.events) context.events = [];
72
- context.events.push(eventData);
73
- };
74
-
75
- globals.log = (message, level = 'info') => {
76
- console.log(`[Sandbox ${level.toUpperCase()}] ${message}`);
77
- };
78
-
79
- globals.assert = (subject, predicate, object, graph) => {
80
- if (!context.assertions) context.assertions = [];
81
- context.assertions.push({ subject, predicate, object, graph });
82
- };
83
-
84
- // Add allowed globals
85
- for (const globalName of config.allowedGlobals || []) {
86
- if (globalName === 'Date') globals.Date = Date;
87
- if (globalName === 'Math') globals.Math = Math;
88
- if (globalName === 'JSON') globals.JSON = JSON;
89
- }
90
-
91
- return globals;
92
- }
93
-
94
- /**
95
- * Create safe effect function
96
- * @param {string} effectCode - Effect function code
97
- * @param {Object} safeGlobals - Safe globals
98
- * @returns {Function} Safe effect function
99
- */
100
- function createSafeEffect(effectCode, safeGlobals) {
101
- // Create function with safe globals
102
- const safeFunction = new Function(
103
- ...Object.keys(safeGlobals),
104
- `
105
- "use strict";
106
-
107
- // Override dangerous globals
108
- const process = undefined;
109
- const require = undefined;
110
- const module = undefined;
111
- const exports = undefined;
112
- const __dirname = undefined;
113
- const __filename = undefined;
114
-
115
- // Create effect function
116
- const effect = ${effectCode};
117
-
118
- // Return wrapper that captures assertions and events
119
- return function(context) {
120
- const result = effect(context);
121
-
122
- return {
123
- result,
124
- assertions: context.assertions || [],
125
- events: context.events || []
126
- };
127
- };
128
- `
129
- );
130
-
131
- return safeFunction(...Object.values(safeGlobals));
132
- }
133
-
134
- /**
135
- * Execute function with timeout
136
- * @param {Function} fn - Function to execute
137
- * @param {Object} context - Execution context
138
- * @param {number} timeout - Timeout in milliseconds
139
- * @returns {Promise<Object>} Execution result
140
- */
141
- async function executeWithTimeout(fn, context, timeout) {
142
- return new Promise((resolve, reject) => {
143
- const timeoutId = setTimeout(() => {
144
- reject(new Error(`Execution timeout after ${timeout}ms`));
145
- }, timeout);
146
-
147
- try {
148
- const result = fn(context);
149
-
150
- // Handle both sync and async results
151
- if (result && typeof result.then === 'function') {
152
- result
153
- .then(res => {
154
- clearTimeout(timeoutId);
155
- resolve(res);
156
- })
157
- .catch(err => {
158
- clearTimeout(timeoutId);
159
- reject(err);
160
- });
161
- } else {
162
- clearTimeout(timeoutId);
163
- resolve(result);
164
- }
165
- } catch (error) {
166
- clearTimeout(timeoutId);
167
- reject(error);
168
- }
169
- });
170
- }