@unrdf/hooks 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.
- package/LICENSE +21 -0
- package/README.md +86 -0
- package/package.json +70 -0
- package/src/hooks/builtin-hooks.mjs +296 -0
- package/src/hooks/condition-cache.mjs +109 -0
- package/src/hooks/condition-evaluator.mjs +722 -0
- package/src/hooks/define-hook.mjs +211 -0
- package/src/hooks/effect-sandbox-worker.mjs +170 -0
- package/src/hooks/effect-sandbox.mjs +517 -0
- package/src/hooks/file-resolver.mjs +387 -0
- package/src/hooks/hook-chain-compiler.mjs +236 -0
- package/src/hooks/hook-executor-batching.mjs +277 -0
- package/src/hooks/hook-executor.mjs +465 -0
- package/src/hooks/hook-management.mjs +202 -0
- package/src/hooks/hook-scheduler.mjs +413 -0
- package/src/hooks/knowledge-hook-engine.mjs +358 -0
- package/src/hooks/knowledge-hook-manager.mjs +269 -0
- package/src/hooks/observability.mjs +531 -0
- package/src/hooks/policy-pack.mjs +572 -0
- package/src/hooks/quad-pool.mjs +249 -0
- package/src/hooks/quality-metrics.mjs +544 -0
- package/src/hooks/security/error-sanitizer.mjs +257 -0
- package/src/hooks/security/path-validator.mjs +194 -0
- package/src/hooks/security/sandbox-restrictions.mjs +331 -0
- package/src/hooks/telemetry.mjs +167 -0
- package/src/index.mjs +101 -0
- package/src/security/sandbox/browser-executor.mjs +220 -0
- package/src/security/sandbox/detector.mjs +342 -0
- package/src/security/sandbox/isolated-vm-executor.mjs +373 -0
- package/src/security/sandbox/vm2-executor.mjs +217 -0
- package/src/security/sandbox/worker-executor-runtime.mjs +74 -0
- package/src/security/sandbox/worker-executor.mjs +212 -0
- package/src/security/sandbox-adapter.mjs +141 -0
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Sandbox Restrictions for Hook Execution
|
|
3
|
+
* @module sandbox-restrictions
|
|
4
|
+
*
|
|
5
|
+
* @description
|
|
6
|
+
* Defines and enforces security restrictions for sandboxed hook execution.
|
|
7
|
+
* Prevents privilege escalation and unauthorized system access.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Schema for sandbox configuration
|
|
14
|
+
*/
|
|
15
|
+
const SandboxConfigSchema = z
|
|
16
|
+
.object({
|
|
17
|
+
allowFileSystem: z.boolean().default(false),
|
|
18
|
+
allowNetwork: z.boolean().default(false),
|
|
19
|
+
allowProcessAccess: z.boolean().default(false),
|
|
20
|
+
allowEval: z.boolean().default(false),
|
|
21
|
+
timeoutMs: z.number().default(5000),
|
|
22
|
+
memoryLimitMB: z.number().default(50),
|
|
23
|
+
maxIterations: z.number().default(100000),
|
|
24
|
+
})
|
|
25
|
+
.strict();
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Dangerous Node.js modules that should be blocked
|
|
29
|
+
*/
|
|
30
|
+
const BLOCKED_MODULES = new Set([
|
|
31
|
+
'fs',
|
|
32
|
+
'fs/promises',
|
|
33
|
+
'child_process',
|
|
34
|
+
'cluster',
|
|
35
|
+
'crypto',
|
|
36
|
+
'dgram',
|
|
37
|
+
'dns',
|
|
38
|
+
'http',
|
|
39
|
+
'https',
|
|
40
|
+
'http2',
|
|
41
|
+
'inspector',
|
|
42
|
+
'net',
|
|
43
|
+
'os',
|
|
44
|
+
'perf_hooks',
|
|
45
|
+
'process',
|
|
46
|
+
'repl',
|
|
47
|
+
'tls',
|
|
48
|
+
'tty',
|
|
49
|
+
'v8',
|
|
50
|
+
'vm',
|
|
51
|
+
'worker_threads',
|
|
52
|
+
'zlib',
|
|
53
|
+
]);
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Dangerous global objects/functions
|
|
57
|
+
*/
|
|
58
|
+
const BLOCKED_GLOBALS = new Set([
|
|
59
|
+
'eval',
|
|
60
|
+
'Function',
|
|
61
|
+
'require',
|
|
62
|
+
'import',
|
|
63
|
+
'process',
|
|
64
|
+
'global',
|
|
65
|
+
'__dirname',
|
|
66
|
+
'__filename',
|
|
67
|
+
'Buffer',
|
|
68
|
+
'clearImmediate',
|
|
69
|
+
'setImmediate',
|
|
70
|
+
'clearInterval',
|
|
71
|
+
'clearTimeout',
|
|
72
|
+
'setInterval',
|
|
73
|
+
'setTimeout',
|
|
74
|
+
]);
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Sandbox Restrictions Manager
|
|
78
|
+
*/
|
|
79
|
+
export class SandboxRestrictions {
|
|
80
|
+
/**
|
|
81
|
+
* @param {Object} [config] - Sandbox configuration
|
|
82
|
+
*/
|
|
83
|
+
constructor(config = {}) {
|
|
84
|
+
this.config = SandboxConfigSchema.parse(config);
|
|
85
|
+
this.iterationCount = 0;
|
|
86
|
+
this.startTime = null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Create a restricted context for hook execution
|
|
91
|
+
* @returns {Object} Restricted context object
|
|
92
|
+
*/
|
|
93
|
+
createRestrictedContext() {
|
|
94
|
+
const context = {
|
|
95
|
+
// Allow safe Math operations
|
|
96
|
+
Math: Math,
|
|
97
|
+
|
|
98
|
+
// Allow safe JSON operations
|
|
99
|
+
JSON: JSON,
|
|
100
|
+
|
|
101
|
+
// Allow safe Date operations (read-only)
|
|
102
|
+
Date: Date,
|
|
103
|
+
|
|
104
|
+
// Allow safe String/Number/Boolean/Array operations
|
|
105
|
+
String: String,
|
|
106
|
+
Number: Number,
|
|
107
|
+
Boolean: Boolean,
|
|
108
|
+
Array: Array,
|
|
109
|
+
Object: Object,
|
|
110
|
+
|
|
111
|
+
// Logging (safe, write-only)
|
|
112
|
+
console: {
|
|
113
|
+
log: (...args) => console.log('[Sandboxed]', ...args),
|
|
114
|
+
error: (...args) => console.error('[Sandboxed]', ...args),
|
|
115
|
+
warn: (...args) => console.warn('[Sandboxed]', ...args),
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
// Block dangerous functions
|
|
119
|
+
eval: undefined,
|
|
120
|
+
Function: undefined,
|
|
121
|
+
require: undefined,
|
|
122
|
+
import: undefined,
|
|
123
|
+
process: undefined,
|
|
124
|
+
global: undefined,
|
|
125
|
+
__dirname: undefined,
|
|
126
|
+
__filename: undefined,
|
|
127
|
+
Buffer: undefined,
|
|
128
|
+
|
|
129
|
+
// Block timers (DoS prevention)
|
|
130
|
+
setTimeout: undefined,
|
|
131
|
+
setInterval: undefined,
|
|
132
|
+
setImmediate: undefined,
|
|
133
|
+
clearTimeout: undefined,
|
|
134
|
+
clearInterval: undefined,
|
|
135
|
+
clearImmediate: undefined,
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
// Freeze context to prevent modification
|
|
139
|
+
return Object.freeze(context);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Validate hook function code for dangerous patterns
|
|
144
|
+
* @param {Function} hookFn - Hook function to validate
|
|
145
|
+
* @returns {Object} Validation result { valid, violations }
|
|
146
|
+
*/
|
|
147
|
+
validateHookCode(hookFn) {
|
|
148
|
+
if (typeof hookFn !== 'function') {
|
|
149
|
+
return {
|
|
150
|
+
valid: false,
|
|
151
|
+
violations: ['Hook must be a function'],
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const codeString = hookFn.toString();
|
|
156
|
+
const violations = [];
|
|
157
|
+
|
|
158
|
+
// Check for blocked module requires
|
|
159
|
+
for (const moduleName of BLOCKED_MODULES) {
|
|
160
|
+
if (codeString.includes(`require('${moduleName}')`)) {
|
|
161
|
+
violations.push(`Blocked module access: ${moduleName}`);
|
|
162
|
+
}
|
|
163
|
+
if (codeString.includes(`require("${moduleName}")`)) {
|
|
164
|
+
violations.push(`Blocked module access: ${moduleName}`);
|
|
165
|
+
}
|
|
166
|
+
if (codeString.includes(`from '${moduleName}'`)) {
|
|
167
|
+
violations.push(`Blocked module import: ${moduleName}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Check for blocked globals
|
|
172
|
+
for (const globalName of BLOCKED_GLOBALS) {
|
|
173
|
+
// Use word boundaries to avoid false positives
|
|
174
|
+
const pattern = new RegExp(`\\b${globalName}\\b`, 'g');
|
|
175
|
+
if (pattern.test(codeString)) {
|
|
176
|
+
violations.push(`Blocked global access: ${globalName}`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Check for file system access patterns
|
|
181
|
+
if (!this.config.allowFileSystem) {
|
|
182
|
+
if (/\bfs\./g.test(codeString) || /readFileSync|writeFileSync/g.test(codeString)) {
|
|
183
|
+
violations.push('File system access not allowed');
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Check for network access patterns
|
|
188
|
+
if (!this.config.allowNetwork) {
|
|
189
|
+
if (/\bfetch\(|XMLHttpRequest|WebSocket/g.test(codeString)) {
|
|
190
|
+
violations.push('Network access not allowed');
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Check for process access
|
|
195
|
+
if (!this.config.allowProcessAccess) {
|
|
196
|
+
if (/\bprocess\./g.test(codeString)) {
|
|
197
|
+
violations.push('Process access not allowed');
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Check for eval usage
|
|
202
|
+
if (!this.config.allowEval) {
|
|
203
|
+
if (/\beval\(|new Function\(/g.test(codeString)) {
|
|
204
|
+
violations.push('Dynamic code evaluation not allowed');
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
valid: violations.length === 0,
|
|
210
|
+
violations,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Execute a hook function with restrictions
|
|
216
|
+
* @param {Function} hookFn - Hook function to execute
|
|
217
|
+
* @param {Object} event - Event object
|
|
218
|
+
* @returns {Promise<Object>} Execution result
|
|
219
|
+
*/
|
|
220
|
+
async executeRestricted(hookFn, event) {
|
|
221
|
+
// Validate code before execution
|
|
222
|
+
const validation = this.validateHookCode(hookFn);
|
|
223
|
+
if (!validation.valid) {
|
|
224
|
+
return {
|
|
225
|
+
success: false,
|
|
226
|
+
error: `Security validation failed: ${validation.violations.join(', ')}`,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
this.startTime = Date.now();
|
|
231
|
+
this.iterationCount = 0;
|
|
232
|
+
|
|
233
|
+
try {
|
|
234
|
+
// Create restricted context
|
|
235
|
+
const restrictedContext = this.createRestrictedContext();
|
|
236
|
+
|
|
237
|
+
// Execute with timeout
|
|
238
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
239
|
+
setTimeout(() => {
|
|
240
|
+
reject(new Error(`Execution timeout after ${this.config.timeoutMs}ms`));
|
|
241
|
+
}, this.config.timeoutMs);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// Wrap hook function to prevent context mutation
|
|
245
|
+
const wrappedFn = async () => {
|
|
246
|
+
try {
|
|
247
|
+
// Prevent event mutation by freezing
|
|
248
|
+
const frozenEvent = this._deepFreeze({ ...event });
|
|
249
|
+
|
|
250
|
+
// Execute in restricted context
|
|
251
|
+
const result = await hookFn.call(restrictedContext, frozenEvent);
|
|
252
|
+
|
|
253
|
+
// Check iteration limit
|
|
254
|
+
if (this.iterationCount > this.config.maxIterations) {
|
|
255
|
+
throw new Error('Maximum iteration count exceeded');
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return result;
|
|
259
|
+
} catch (error) {
|
|
260
|
+
// Block system access errors
|
|
261
|
+
if (error.code === 'EACCES' || error.code === 'EPERM') {
|
|
262
|
+
return {
|
|
263
|
+
success: false,
|
|
264
|
+
error: 'System access denied',
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
throw error;
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
const result = await Promise.race([wrappedFn(), timeoutPromise]);
|
|
272
|
+
|
|
273
|
+
return result || { success: true };
|
|
274
|
+
} catch (error) {
|
|
275
|
+
if (error.message.includes('timeout')) {
|
|
276
|
+
return {
|
|
277
|
+
success: false,
|
|
278
|
+
error: 'Execution timeout exceeded',
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (error.message.includes('iteration')) {
|
|
283
|
+
return {
|
|
284
|
+
success: false,
|
|
285
|
+
error: 'Maximum iteration count exceeded',
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return {
|
|
290
|
+
success: false,
|
|
291
|
+
error: error.message || 'Hook execution failed',
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Deep freeze an object to prevent mutation
|
|
298
|
+
* @param {Object} obj - Object to freeze
|
|
299
|
+
* @returns {Object} Frozen object
|
|
300
|
+
* @private
|
|
301
|
+
*/
|
|
302
|
+
_deepFreeze(obj) {
|
|
303
|
+
if (obj === null || typeof obj !== 'object') {
|
|
304
|
+
return obj;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
Object.freeze(obj);
|
|
308
|
+
|
|
309
|
+
Object.getOwnPropertyNames(obj).forEach(prop => {
|
|
310
|
+
if (obj[prop] !== null && typeof obj[prop] === 'object') {
|
|
311
|
+
this._deepFreeze(obj[prop]);
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
return obj;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Create sandbox restrictions instance
|
|
321
|
+
* @param {Object} [config] - Sandbox configuration
|
|
322
|
+
* @returns {SandboxRestrictions} Restrictions instance
|
|
323
|
+
*/
|
|
324
|
+
export function createSandboxRestrictions(config = {}) {
|
|
325
|
+
return new SandboxRestrictions(config);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Default sandbox restrictions (strict mode)
|
|
330
|
+
*/
|
|
331
|
+
export const defaultSandboxRestrictions = new SandboxRestrictions();
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Batched OTEL Telemetry - Reduces span overhead
|
|
3
|
+
*
|
|
4
|
+
* @description
|
|
5
|
+
* Optimizes OpenTelemetry instrumentation to reduce span creation overhead:
|
|
6
|
+
* - Single parent span per transaction (not per hook)
|
|
7
|
+
* - Async attribute setting (non-blocking)
|
|
8
|
+
* - Conditional instrumentation (disable in production)
|
|
9
|
+
* - Batch flush for pending attributes
|
|
10
|
+
*
|
|
11
|
+
* Expected Impact: 10-15% latency reduction
|
|
12
|
+
*
|
|
13
|
+
* @module knowledge-engine/telemetry
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Batched OTEL Telemetry for Knowledge Hooks
|
|
18
|
+
*
|
|
19
|
+
* @class BatchedTelemetry
|
|
20
|
+
*/
|
|
21
|
+
export class BatchedTelemetry {
|
|
22
|
+
/**
|
|
23
|
+
* Create a new batched telemetry instance
|
|
24
|
+
* @param {object} tracer - OpenTelemetry tracer instance
|
|
25
|
+
* @param {object} options - Configuration options
|
|
26
|
+
* @param {boolean} options.enabled - Enable telemetry (default: true if not in production)
|
|
27
|
+
* @param {number} options.flushInterval - Batch flush interval in ms (default: 10ms)
|
|
28
|
+
*/
|
|
29
|
+
constructor(tracer, options = {}) {
|
|
30
|
+
this.tracer = tracer;
|
|
31
|
+
this.enabled = options.enabled ?? process.env.NODE_ENV !== 'production';
|
|
32
|
+
this.flushInterval = options.flushInterval ?? 10;
|
|
33
|
+
this.pendingAttributes = [];
|
|
34
|
+
this.flushTimeout = null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Start parent span for entire transaction (not per hook)
|
|
39
|
+
*
|
|
40
|
+
* @param {string} name - Span name
|
|
41
|
+
* @param {object} attributes - Initial attributes
|
|
42
|
+
* @returns {object|null} Span instance or null if disabled
|
|
43
|
+
*/
|
|
44
|
+
startTransactionSpan(name, attributes = {}) {
|
|
45
|
+
if (!this.enabled || !this.tracer) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
return this.tracer.startSpan(name, {
|
|
51
|
+
attributes: {
|
|
52
|
+
'hook.transaction': true,
|
|
53
|
+
...attributes,
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
} catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Queue attribute update for batch flush (async, non-blocking)
|
|
63
|
+
*
|
|
64
|
+
* Attributes are queued and flushed in batch after flushInterval
|
|
65
|
+
* to avoid blocking the hot path with span attribute mutations.
|
|
66
|
+
*
|
|
67
|
+
* @param {object} span - Span instance
|
|
68
|
+
* @param {string} key - Attribute key
|
|
69
|
+
* @param {*} value - Attribute value
|
|
70
|
+
*/
|
|
71
|
+
setAttribute(span, key, value) {
|
|
72
|
+
if (!this.enabled || !span) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Queue attribute update
|
|
77
|
+
this.pendingAttributes.push({ span, key, value });
|
|
78
|
+
|
|
79
|
+
// Schedule batch flush if not already scheduled
|
|
80
|
+
if (!this.flushTimeout) {
|
|
81
|
+
this.flushTimeout = setTimeout(() => this.flush(), this.flushInterval);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Flush pending attributes in batch
|
|
87
|
+
*
|
|
88
|
+
* This reduces the number of span attribute mutations
|
|
89
|
+
* by batching them together rather than setting each individually.
|
|
90
|
+
*/
|
|
91
|
+
flush() {
|
|
92
|
+
try {
|
|
93
|
+
for (const { span, key, value } of this.pendingAttributes) {
|
|
94
|
+
try {
|
|
95
|
+
span.setAttribute(key, value);
|
|
96
|
+
} catch {
|
|
97
|
+
// Ignore individual attribute errors
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
} finally {
|
|
101
|
+
this.pendingAttributes = [];
|
|
102
|
+
this.flushTimeout = null;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Record span event (batched)
|
|
108
|
+
*
|
|
109
|
+
* @param {object} span - Span instance
|
|
110
|
+
* @param {string} name - Event name
|
|
111
|
+
* @param {object} attributes - Event attributes
|
|
112
|
+
*/
|
|
113
|
+
recordEvent(span, name, attributes = {}) {
|
|
114
|
+
if (!this.enabled || !span) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
span.recordEvent(name, attributes);
|
|
120
|
+
} catch {
|
|
121
|
+
// Ignore recording errors
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* End span with status
|
|
127
|
+
*
|
|
128
|
+
* @param {object} span - Span instance
|
|
129
|
+
* @param {string} status - Status code ('ok', 'error', 'unset')
|
|
130
|
+
* @param {string} message - Status message (optional)
|
|
131
|
+
*/
|
|
132
|
+
endSpan(span, status = 'ok', message = '') {
|
|
133
|
+
if (!this.enabled || !span) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
// Flush any pending attributes first
|
|
139
|
+
if (this.pendingAttributes.length > 0) {
|
|
140
|
+
this.flush();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// End span with status
|
|
144
|
+
span.setStatus({ code: status, message });
|
|
145
|
+
span.end();
|
|
146
|
+
} catch {
|
|
147
|
+
// Ignore end errors
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Disable telemetry (for production or testing)
|
|
153
|
+
*/
|
|
154
|
+
disable() {
|
|
155
|
+
this.enabled = false;
|
|
156
|
+
this.flush();
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Enable telemetry
|
|
161
|
+
*/
|
|
162
|
+
enable() {
|
|
163
|
+
this.enabled = true;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export default BatchedTelemetry;
|
package/src/index.mjs
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @unrdf/hooks
|
|
3
|
+
*
|
|
4
|
+
* Knowledge Hooks - Policy Definition and Execution Framework
|
|
5
|
+
*
|
|
6
|
+
* @module @unrdf/hooks
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// Hook definition
|
|
10
|
+
export {
|
|
11
|
+
defineHook,
|
|
12
|
+
isValidHook,
|
|
13
|
+
getHookMetadata,
|
|
14
|
+
hasValidation,
|
|
15
|
+
hasTransformation,
|
|
16
|
+
HookTriggerSchema,
|
|
17
|
+
HookConfigSchema,
|
|
18
|
+
HookSchema,
|
|
19
|
+
} from './hooks/define-hook.mjs';
|
|
20
|
+
|
|
21
|
+
// Hook execution
|
|
22
|
+
export {
|
|
23
|
+
executeHook,
|
|
24
|
+
executeHookChain,
|
|
25
|
+
executeHooksByTrigger,
|
|
26
|
+
wouldPassHooks,
|
|
27
|
+
HookResultSchema,
|
|
28
|
+
ChainResultSchema,
|
|
29
|
+
// Validation-only execution
|
|
30
|
+
validateOnly,
|
|
31
|
+
// Cache management
|
|
32
|
+
clearHookCaches,
|
|
33
|
+
prewarmHookCache,
|
|
34
|
+
// Batch API (high-performance bulk operations)
|
|
35
|
+
executeBatch,
|
|
36
|
+
validateBatch,
|
|
37
|
+
transformBatch,
|
|
38
|
+
} from './hooks/hook-executor.mjs';
|
|
39
|
+
|
|
40
|
+
// Hook chain compiler (JIT optimization)
|
|
41
|
+
export {
|
|
42
|
+
compileHookChain,
|
|
43
|
+
compileValidationOnlyChain,
|
|
44
|
+
clearCompiledChainCache,
|
|
45
|
+
getCompilerStats,
|
|
46
|
+
isJitAvailable,
|
|
47
|
+
getChainKey,
|
|
48
|
+
} from './hooks/hook-chain-compiler.mjs';
|
|
49
|
+
|
|
50
|
+
// Quad pool (object pooling optimization)
|
|
51
|
+
export { QuadPool, quadPool, createPooledTransform, isPooledQuad } from './hooks/quad-pool.mjs';
|
|
52
|
+
|
|
53
|
+
// Hook management
|
|
54
|
+
export {
|
|
55
|
+
createHookRegistry,
|
|
56
|
+
registerHook,
|
|
57
|
+
unregisterHook,
|
|
58
|
+
getHook,
|
|
59
|
+
listHooks,
|
|
60
|
+
getHooksByTrigger,
|
|
61
|
+
hasHook,
|
|
62
|
+
clearHooks,
|
|
63
|
+
getRegistryStats,
|
|
64
|
+
HookRegistrySchema,
|
|
65
|
+
} from './hooks/hook-management.mjs';
|
|
66
|
+
|
|
67
|
+
// Built-in hooks
|
|
68
|
+
export {
|
|
69
|
+
builtinHooks,
|
|
70
|
+
validateSubjectIRI,
|
|
71
|
+
validatePredicateIRI,
|
|
72
|
+
validateObjectLiteral,
|
|
73
|
+
validateIRIFormat,
|
|
74
|
+
validateLanguageTag,
|
|
75
|
+
rejectBlankNodes,
|
|
76
|
+
normalizeNamespace,
|
|
77
|
+
normalizeLanguageTag,
|
|
78
|
+
trimLiterals,
|
|
79
|
+
// Pooled variants (zero-allocation transforms)
|
|
80
|
+
normalizeLanguageTagPooled,
|
|
81
|
+
trimLiteralsPooled,
|
|
82
|
+
standardValidation,
|
|
83
|
+
} from './hooks/builtin-hooks.mjs';
|
|
84
|
+
|
|
85
|
+
// Hook manager (class-based interface)
|
|
86
|
+
export { KnowledgeHookManager } from './hooks/knowledge-hook-manager.mjs';
|
|
87
|
+
|
|
88
|
+
// Hook scheduler (cron/interval triggers)
|
|
89
|
+
export {
|
|
90
|
+
HookScheduler,
|
|
91
|
+
createHookScheduler,
|
|
92
|
+
ScheduleConfigSchema,
|
|
93
|
+
} from './hooks/hook-scheduler.mjs';
|
|
94
|
+
|
|
95
|
+
// Quality metrics (Lean Six Sigma hooks)
|
|
96
|
+
export {
|
|
97
|
+
QualityMetricsCollector,
|
|
98
|
+
createQualityHooks,
|
|
99
|
+
QualityGateSchema,
|
|
100
|
+
SPCDataPointSchema,
|
|
101
|
+
} from './hooks/quality-metrics.mjs';
|