@dyrected/core 2.12.0 → 2.13.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.
package/dist/index.cjs CHANGED
@@ -5,9 +5,6 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __esm = (fn, res) => function __init() {
9
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
- };
11
8
  var __commonJS = (cb, mod) => function __require() {
12
9
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
13
10
  };
@@ -33,517 +30,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
33
30
  ));
34
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
35
32
 
36
- // src/observability.ts
37
- var observability_exports = {};
38
- __export(observability_exports, {
39
- attachRequestMetrics: () => attachRequestMetrics,
40
- bindObservabilityRuntime: () => bindObservabilityRuntime,
41
- buildRequestLogger: () => buildRequestLogger,
42
- captureRequestBody: () => captureRequestBody,
43
- createObservabilityRuntime: () => createObservabilityRuntime,
44
- createRequestSpan: () => createRequestSpan,
45
- endRequestSpan: () => endRequestSpan,
46
- getConfigLogger: () => getConfigLogger,
47
- getObservabilityRuntime: () => getObservabilityRuntime,
48
- getRequestLogger: () => getRequestLogger,
49
- redactBody: () => redactBody,
50
- redactHeaders: () => redactHeaders,
51
- renderPrometheusMetrics: () => renderPrometheusMetrics,
52
- resolveObservabilityConfig: () => resolveObservabilityConfig,
53
- shouldSampleRequest: () => shouldSampleRequest
54
- });
55
- function resolveObservabilityConfig(config) {
56
- const requestLogging = config?.requestLogging;
57
- const sampling = config?.sampling;
58
- const tracing = config?.tracing;
59
- const metrics = config?.metrics;
60
- return {
61
- requestLogging: {
62
- enabled: requestLogging?.enabled ?? true,
63
- logBodies: requestLogging?.logBodies ?? false,
64
- maxBodyBytes: requestLogging?.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES,
65
- redactPaths: uniqueValues([
66
- ...DEFAULT_REDACT_PATHS,
67
- ...requestLogging?.redactPaths ?? []
68
- ]),
69
- includeHeaders: normalizeHeaderNames(requestLogging?.includeHeaders ?? []),
70
- redactHeaders: uniqueValues(
71
- normalizeHeaderNames([
72
- ...DEFAULT_REDACT_HEADERS,
73
- ...requestLogging?.redactHeaders ?? []
74
- ])
75
- )
76
- },
77
- sampling: {
78
- successRate: clampRate(sampling?.successRate ?? DEFAULT_SUCCESS_SAMPLE_RATE),
79
- traceSuccessRate: clampRate(
80
- sampling?.traceSuccessRate ?? sampling?.successRate ?? DEFAULT_SUCCESS_SAMPLE_RATE
81
- ),
82
- bodySuccessRate: clampRate(
83
- sampling?.bodySuccessRate ?? Math.min(DEFAULT_BODY_SAMPLE_RATE, sampling?.successRate ?? DEFAULT_SUCCESS_SAMPLE_RATE)
84
- ),
85
- alwaysKeep4xx: sampling?.alwaysKeep4xx ?? true,
86
- alwaysKeep5xx: sampling?.alwaysKeep5xx ?? true
87
- },
88
- tracing: {
89
- enabled: tracing?.enabled ?? false,
90
- serviceName: tracing?.serviceName ?? "dyrected",
91
- exporter: tracing?.exporter ?? "none",
92
- headers: tracing?.headers ?? {},
93
- endpoint: tracing?.endpoint
94
- },
95
- metrics: {
96
- enabled: metrics?.enabled ?? false,
97
- exporter: metrics?.exporter ?? "none",
98
- endpoint: metrics?.endpoint,
99
- path: metrics?.path ?? "/metrics"
100
- },
101
- transports: {
102
- targets: config?.transports?.targets && config.transports.targets.length > 0 ? config.transports.targets : [{ type: "stdout" }]
103
- }
104
- };
105
- }
106
- function createObservabilityRuntime(config) {
107
- const resolved = resolveObservabilityConfig(config.observability);
108
- const logger = createRootLogger(config.logger, resolved);
109
- const shutdownTasks = [];
110
- const meterRuntime = resolved.metrics.enabled || resolved.metrics.exporter === "prometheus" ? createMeterProvider(resolved) : void 0;
111
- const tracerProvider = resolved.tracing.enabled ? createTracerProvider(resolved) : void 0;
112
- const tracer = tracerProvider?.getTracer("dyrected");
113
- const meter = meterRuntime?.provider.getMeter("dyrected");
114
- const metrics = meter ? {
115
- requestCount: meter.createCounter("dyrected_http_requests_total", {
116
- description: "Total HTTP requests served by Dyrected"
117
- }),
118
- authFailureCount: meter.createCounter("dyrected_auth_failures_total", {
119
- description: "Authentication failures"
120
- }),
121
- uncaughtErrorCount: meter.createCounter("dyrected_uncaught_errors_total", {
122
- description: "Uncaught application errors"
123
- }),
124
- auditWriteFailureCount: meter.createCounter("dyrected_audit_write_failures_total", {
125
- description: "Audit log persistence failures"
126
- }),
127
- emailSendFailureCount: meter.createCounter("dyrected_email_send_failures_total", {
128
- description: "Transactional email delivery failures"
129
- }),
130
- workflowHookFailureCount: meter.createCounter("dyrected_workflow_hook_failures_total", {
131
- description: "Workflow hook failures isolated after successful writes"
132
- }),
133
- requestDuration: meter.createHistogram("dyrected_http_request_duration_ms", {
134
- description: "HTTP request duration in milliseconds",
135
- unit: "ms"
136
- })
137
- } : void 0;
138
- if (meterRuntime) {
139
- shutdownTasks.push(() => meterRuntime.provider.shutdown());
140
- }
141
- if (tracerProvider) {
142
- shutdownTasks.push(() => tracerProvider.shutdown());
143
- }
144
- return {
145
- logger,
146
- config: resolved,
147
- tracer,
148
- metrics,
149
- prometheusExporter: meterRuntime?.prometheusExporter,
150
- shutdown: async () => {
151
- for (const task of shutdownTasks) {
152
- await task();
153
- }
154
- },
155
- recordAuthFailure: (attributes) => metrics?.authFailureCount.add(1, attributes),
156
- recordUncaughtError: (attributes) => metrics?.uncaughtErrorCount.add(1, attributes),
157
- recordAuditWriteFailure: (attributes) => metrics?.auditWriteFailureCount.add(1, attributes),
158
- recordEmailSendFailure: (attributes) => metrics?.emailSendFailureCount.add(1, attributes),
159
- recordWorkflowHookFailure: (attributes) => metrics?.workflowHookFailureCount.add(1, attributes)
160
- };
161
- }
162
- function bindObservabilityRuntime(config, runtime) {
163
- runtimeByConfig.set(config, runtime);
164
- }
165
- function getObservabilityRuntime(config) {
166
- if (!config || typeof config !== "object") return void 0;
167
- return runtimeByConfig.get(config);
168
- }
169
- function createRootLogger(loggerConfig, observability) {
170
- if (loggerConfig && !("options" in loggerConfig)) {
171
- return loggerConfig;
172
- }
173
- const options = loggerConfig?.options ?? {};
174
- const enabled = options.enabled ?? process.env.DISABLE_LOGGING !== "true";
175
- const name = options.name ?? "dyrected";
176
- if (loggerConfig?.destination) {
177
- return (0, import_pino.default)(
178
- {
179
- ...options,
180
- enabled,
181
- name,
182
- timestamp: options.timestamp ?? import_pino.stdTimeFunctions.isoTime
183
- },
184
- loggerConfig.destination
185
- );
186
- }
187
- const streams = buildTransportStreams(observability);
188
- const destination = streams.length === 1 ? streams[0] : (0, import_pino.multistream)(streams.map((stream) => ({ stream })));
189
- return (0, import_pino.default)(
190
- {
191
- ...options,
192
- enabled,
193
- name,
194
- timestamp: options.timestamp ?? import_pino.stdTimeFunctions.isoTime
195
- },
196
- destination
197
- );
198
- }
199
- function buildTransportStreams(observability) {
200
- const targets = observability.transports.targets;
201
- if (targets.length === 0) {
202
- return [defaultLoggerDestination()];
203
- }
204
- return targets.map((target) => {
205
- switch (target.type) {
206
- case "stdout":
207
- return defaultLoggerDestination();
208
- case "stderr":
209
- return (0, import_pino.destination)(2);
210
- case "file":
211
- return (0, import_pino.destination)(target.path);
212
- case "otlp":
213
- return new OtlpLogWritable(target.endpoint, target.headers);
214
- }
215
- });
216
- }
217
- function defaultLoggerDestination() {
218
- if (process.env.NODE_ENV !== "production" && typeof window === "undefined") {
219
- try {
220
- const req = globalThis.require;
221
- if (req) {
222
- const pinoPretty = req("pino-pretty");
223
- return pinoPretty({
224
- colorize: true,
225
- ignore: "pid,hostname",
226
- translateTime: "SYS:HH:MM:ss",
227
- destination: 1,
228
- sync: true
229
- });
230
- }
231
- } catch {
232
- }
233
- }
234
- return (0, import_pino.destination)(1);
235
- }
236
- function createTracerProvider(observability) {
237
- const exporter = createTraceExporter(observability);
238
- const provider = new import_sdk_trace_base.BasicTracerProvider({
239
- resource: (0, import_resources.resourceFromAttributes)({
240
- "service.name": observability.tracing.serviceName
241
- }),
242
- spanProcessors: exporter ? [new import_sdk_trace_base.BatchSpanProcessor(exporter)] : []
243
- });
244
- import_api.trace.setGlobalTracerProvider(provider);
245
- return provider;
246
- }
247
- function createTraceExporter(observability) {
248
- switch (observability.tracing.exporter) {
249
- case "console":
250
- return new import_sdk_trace_base.ConsoleSpanExporter();
251
- case "otlp":
252
- return new import_exporter_trace_otlp_http.OTLPTraceExporter({
253
- url: observability.tracing.endpoint,
254
- headers: observability.tracing.headers
255
- });
256
- default:
257
- return void 0;
258
- }
259
- }
260
- function createMeterProvider(observability) {
261
- const readers = [];
262
- let prometheusExporter;
263
- switch (observability.metrics.exporter) {
264
- case "otlp":
265
- readers.push(
266
- new import_sdk_metrics.PeriodicExportingMetricReader({
267
- exporter: new import_exporter_metrics_otlp_http.OTLPMetricExporter({
268
- url: observability.metrics.endpoint
269
- })
270
- })
271
- );
272
- break;
273
- case "prometheus":
274
- prometheusExporter = new import_exporter_prometheus.PrometheusExporter({
275
- endpoint: observability.metrics.path,
276
- preventServerStart: true
277
- });
278
- readers.push(prometheusExporter);
279
- break;
280
- }
281
- const provider = new import_sdk_metrics.MeterProvider({
282
- resource: (0, import_resources.resourceFromAttributes)({
283
- "service.name": observability.tracing.serviceName
284
- }),
285
- readers
286
- });
287
- return { provider, prometheusExporter };
288
- }
289
- function getConfigLogger(config, component) {
290
- const base = config?.logger && !("options" in config.logger) ? config.logger : fallbackLogger;
291
- return base.child({ component });
292
- }
293
- function getRequestLogger(c, component) {
294
- const base = c.get("logger") ?? fallbackLogger;
295
- return component ? base.child({ component }) : base;
296
- }
297
- function buildRequestLogger(runtime, vars, requestId) {
298
- const trace2 = vars.requestTrace;
299
- return runtime.logger.child({
300
- requestId,
301
- siteId: vars.siteId,
302
- workspaceId: vars.workspaceId,
303
- traceId: trace2?.traceId,
304
- spanId: trace2?.spanId
305
- });
306
- }
307
- function shouldSampleRequest(requestId, statusCode, sampling, kind) {
308
- if (statusCode >= 500 && sampling.alwaysKeep5xx) return true;
309
- if (statusCode >= 400 && sampling.alwaysKeep4xx) return true;
310
- const rate = kind === "trace" ? sampling.traceSuccessRate : kind === "body" ? sampling.bodySuccessRate : sampling.successRate;
311
- return deterministicSample(requestId ?? "no-request-id", rate);
312
- }
313
- function redactHeaders(headers, observability) {
314
- const includeHeaders = new Set(observability.requestLogging.includeHeaders);
315
- const redactHeaders2 = new Set(observability.requestLogging.redactHeaders);
316
- const output = {};
317
- for (const [key, value] of Object.entries(headers)) {
318
- const normalizedKey = key.toLowerCase();
319
- if (includeHeaders.size > 0 && !includeHeaders.has(normalizedKey)) continue;
320
- output[normalizedKey] = redactHeaders2.has(normalizedKey) ? REDACTED_VALUE : value;
321
- }
322
- return output;
323
- }
324
- async function captureRequestBody(request, observability) {
325
- const contentType = request.headers.get("content-type") ?? void 0;
326
- const contentLength = toNumber(request.headers.get("content-length"));
327
- const jsonBody = contentType?.includes("application/json");
328
- if (!jsonBody) {
329
- return {
330
- attempted: false,
331
- contentType,
332
- contentLength
333
- };
334
- }
335
- try {
336
- const text = await request.clone().text();
337
- if (!text) {
338
- return { attempted: true, contentType, contentLength };
339
- }
340
- const truncated = text.length > observability.requestLogging.maxBodyBytes;
341
- const raw = truncated ? text.slice(0, observability.requestLogging.maxBodyBytes) : text;
342
- try {
343
- const parsed = JSON.parse(raw);
344
- return {
345
- attempted: true,
346
- contentType,
347
- contentLength: contentLength ?? text.length,
348
- truncated,
349
- body: redactBody(parsed, observability.requestLogging.redactPaths)
350
- };
351
- } catch {
352
- return {
353
- attempted: true,
354
- contentType,
355
- contentLength: contentLength ?? text.length,
356
- truncated,
357
- parseFailed: true
358
- };
359
- }
360
- } catch {
361
- return {
362
- attempted: true,
363
- contentType,
364
- contentLength,
365
- parseFailed: true
366
- };
367
- }
368
- }
369
- function redactBody(value, redactPaths) {
370
- const cloned = deepClone(value);
371
- for (const path of redactPaths) {
372
- applyRedaction(cloned, path.split("."));
373
- }
374
- return cloned;
375
- }
376
- function applyRedaction(target, segments) {
377
- if (!target || segments.length === 0) return;
378
- const [segment, ...rest] = segments;
379
- if (Array.isArray(target)) {
380
- for (const item of target) {
381
- if (segment === "*") {
382
- applyRedaction(item, rest);
383
- } else {
384
- applyRedaction(item, segments);
385
- }
386
- }
387
- return;
388
- }
389
- if (typeof target !== "object") return;
390
- const record = target;
391
- if (segment === "*") {
392
- for (const value of Object.values(record)) {
393
- applyRedaction(value, rest);
394
- }
395
- return;
396
- }
397
- if (!(segment in record)) return;
398
- if (rest.length === 0) {
399
- record[segment] = REDACTED_VALUE;
400
- return;
401
- }
402
- applyRedaction(record[segment], rest);
403
- }
404
- function deepClone(value) {
405
- if (typeof structuredClone === "function") {
406
- return structuredClone(value);
407
- }
408
- return JSON.parse(JSON.stringify(value));
409
- }
410
- function createRequestSpan(runtime, name, attributes) {
411
- if (!runtime.tracer) return void 0;
412
- const span = runtime.tracer.startSpan(name, { attributes }, import_api.context.active());
413
- const spanContext = span.spanContext();
414
- return {
415
- span,
416
- traceId: spanContext.traceId,
417
- spanId: spanContext.spanId,
418
- sampled: spanContext.traceFlags === import_api.TraceFlags.SAMPLED
419
- };
420
- }
421
- function endRequestSpan(requestTrace, statusCode, error) {
422
- if (!requestTrace) return;
423
- requestTrace.span.setAttribute("http.status_code", statusCode);
424
- if (error) {
425
- requestTrace.span.recordException(error instanceof Error ? error : new Error(String(error)));
426
- }
427
- requestTrace.span.end();
428
- }
429
- function attachRequestMetrics(runtime, args) {
430
- runtime.metrics?.requestCount.add(1, {
431
- method: args.method,
432
- route: args.route,
433
- status_class: `${Math.floor(args.statusCode / 100)}xx`
434
- });
435
- runtime.metrics?.requestDuration.record(args.durationMs, {
436
- method: args.method,
437
- route: args.route,
438
- status_class: `${Math.floor(args.statusCode / 100)}xx`
439
- });
440
- }
441
- async function renderPrometheusMetrics(exporter) {
442
- let statusCode = 200;
443
- const headers = {};
444
- let body = "";
445
- await new Promise((resolve) => {
446
- const response = {
447
- statusCode,
448
- setHeader(name, value) {
449
- headers[name.toLowerCase()] = value;
450
- },
451
- end(chunk) {
452
- if (chunk) body += chunk;
453
- statusCode = this.statusCode;
454
- resolve();
455
- }
456
- };
457
- exporter.getMetricsRequestHandler({}, response);
458
- });
459
- return { body, headers, statusCode };
460
- }
461
- function normalizeHeaderNames(headers) {
462
- return headers.map((value) => value.toLowerCase());
463
- }
464
- function uniqueValues(values) {
465
- return [...new Set(values)];
466
- }
467
- function clampRate(value) {
468
- if (Number.isNaN(value)) return 0;
469
- return Math.max(0, Math.min(1, value));
470
- }
471
- function deterministicSample(seed, rate) {
472
- if (rate >= 1) return true;
473
- if (rate <= 0) return false;
474
- let hash = 0;
475
- for (let index = 0; index < seed.length; index += 1) {
476
- hash = hash * 31 + seed.charCodeAt(index) >>> 0;
477
- }
478
- return hash / 4294967295 <= rate;
479
- }
480
- function toNumber(value) {
481
- if (!value) return void 0;
482
- const parsed = Number(value);
483
- return Number.isFinite(parsed) ? parsed : void 0;
484
- }
485
- var import_api, import_exporter_metrics_otlp_http, import_exporter_prometheus, import_exporter_trace_otlp_http, import_resources, import_sdk_metrics, import_sdk_trace_base, import_pino, import_node_stream, DEFAULT_REDACT_HEADERS, DEFAULT_REDACT_PATHS, DEFAULT_MAX_BODY_BYTES, DEFAULT_SUCCESS_SAMPLE_RATE, DEFAULT_BODY_SAMPLE_RATE, REDACTED_VALUE, runtimeByConfig, fallbackLogger, OtlpLogWritable;
486
- var init_observability = __esm({
487
- "src/observability.ts"() {
488
- "use strict";
489
- import_api = require("@opentelemetry/api");
490
- import_exporter_metrics_otlp_http = require("@opentelemetry/exporter-metrics-otlp-http");
491
- import_exporter_prometheus = require("@opentelemetry/exporter-prometheus");
492
- import_exporter_trace_otlp_http = require("@opentelemetry/exporter-trace-otlp-http");
493
- import_resources = require("@opentelemetry/resources");
494
- import_sdk_metrics = require("@opentelemetry/sdk-metrics");
495
- import_sdk_trace_base = require("@opentelemetry/sdk-trace-base");
496
- import_pino = __toESM(require("pino"), 1);
497
- import_node_stream = require("stream");
498
- DEFAULT_REDACT_HEADERS = ["authorization", "cookie", "set-cookie", "x-api-key"];
499
- DEFAULT_REDACT_PATHS = [
500
- "password",
501
- "currentPassword",
502
- "newPassword",
503
- "confirmPassword",
504
- "token",
505
- "refreshToken",
506
- "accessToken",
507
- "secret",
508
- "apiKey",
509
- "inviteToken",
510
- "resetToken"
511
- ];
512
- DEFAULT_MAX_BODY_BYTES = 8192;
513
- DEFAULT_SUCCESS_SAMPLE_RATE = 0.1;
514
- DEFAULT_BODY_SAMPLE_RATE = 0.02;
515
- REDACTED_VALUE = "[REDACTED]";
516
- runtimeByConfig = /* @__PURE__ */ new WeakMap();
517
- fallbackLogger = (0, import_pino.default)({
518
- name: "dyrected",
519
- enabled: process.env.DISABLE_LOGGING !== "true",
520
- timestamp: import_pino.stdTimeFunctions.isoTime
521
- });
522
- OtlpLogWritable = class extends import_node_stream.Writable {
523
- constructor(endpoint, headers = {}) {
524
- super();
525
- this.endpoint = endpoint;
526
- this.headers = headers;
527
- }
528
- endpoint;
529
- headers;
530
- _write(chunk, _encoding, callback) {
531
- const payload = chunk.toString();
532
- void fetch(this.endpoint, {
533
- method: "POST",
534
- headers: {
535
- "content-type": "application/json",
536
- ...this.headers
537
- },
538
- body: JSON.stringify({ logs: payload.trim().split("\n").filter(Boolean) })
539
- }).then(() => callback()).catch(
540
- (error) => callback(error instanceof Error ? error : new Error(String(error)))
541
- );
542
- }
543
- };
544
- }
545
- });
546
-
547
33
  // ../../node_modules/.pnpm/@babel+runtime@7.29.7/node_modules/@babel/runtime/helpers/interopRequireDefault.js
548
34
  var require_interopRequireDefault = __commonJS({
549
35
  "../../node_modules/.pnpm/@babel+runtime@7.29.7/node_modules/@babel/runtime/helpers/interopRequireDefault.js"(exports2, module2) {
@@ -2298,12 +1784,20 @@ var require_Jexl = __commonJS({
2298
1784
  // src/index.ts
2299
1785
  var index_exports = {};
2300
1786
  __export(index_exports, {
1787
+ AI_ACTIONS_COLLECTION: () => AI_ACTIONS_COLLECTION,
1788
+ AI_AUDIT_COLLECTION: () => AI_AUDIT_COLLECTION,
1789
+ AI_CHUNKS_COLLECTION: () => AI_CHUNKS_COLLECTION,
1790
+ AI_MESSAGES_COLLECTION: () => AI_MESSAGES_COLLECTION,
1791
+ AI_THREADS_COLLECTION: () => AI_THREADS_COLLECTION,
2301
1792
  BUILTIN_JEXL_HELPERS: () => BUILTIN_JEXL_HELPERS,
2302
1793
  ConfigValidationError: () => ConfigValidationError,
1794
+ DyrectedAIError: () => DyrectedAIError,
2303
1795
  FieldConditionBuilder: () => FieldConditionBuilder,
2304
1796
  LIFECYCLE_EVENTS_COLLECTION: () => LIFECYCLE_EVENTS_COLLECTION,
2305
1797
  LIFECYCLE_EVENT_NAMES: () => LIFECYCLE_EVENT_NAMES,
2306
1798
  MatchBuilder: () => MatchBuilder,
1799
+ NON_NEGOTIABLE_CREDENTIAL_FIELDS: () => NON_NEGOTIABLE_CREDENTIAL_FIELDS,
1800
+ PII_REGEX_PATTERNS: () => PII_REGEX_PATTERNS,
2307
1801
  WORKFLOW_HISTORY_COLLECTION: () => WORKFLOW_HISTORY_COLLECTION,
2308
1802
  abs: () => abs,
2309
1803
  addDays: () => addDays,
@@ -2391,18 +1885,24 @@ __export(index_exports, {
2391
1885
  generateOpenApi: () => generateOpenApi,
2392
1886
  get: () => get,
2393
1887
  getAdminAuthCollection: () => getAdminAuthCollection,
1888
+ getAllowedSitesForUser: () => getAllowedSitesForUser,
2394
1889
  getPublicAdminAuthConfig: () => getPublicAdminAuthConfig,
2395
1890
  includes: () => includes,
2396
1891
  initializeWorkflowDocument: () => initializeWorkflowDocument,
1892
+ isAICollection: () => isAICollection,
2397
1893
  isConfigValidationError: () => isConfigValidationError,
2398
1894
  isDetailItemVisible: () => isDetailItemVisible,
2399
1895
  isEmpty: () => isEmpty,
2400
1896
  isFuture: () => isFuture,
2401
1897
  isPast: () => isPast,
1898
+ isSiteAuthorized: () => isSiteAuthorized,
2402
1899
  join: () => join,
2403
1900
  last: () => last,
2404
1901
  length: () => length,
2405
1902
  lower: () => lower,
1903
+ maskEmail: () => maskEmail,
1904
+ maskPhone: () => maskPhone,
1905
+ maskTextPII: () => maskTextPII,
2406
1906
  materializeWorkflowDocument: () => materializeWorkflowDocument,
2407
1907
  max: () => max,
2408
1908
  min: () => min,
@@ -2420,8 +1920,10 @@ __export(index_exports, {
2420
1920
  registerJexlHelpers: () => registerJexlHelpers,
2421
1921
  replace: () => replace,
2422
1922
  resolveAdminAuthCollection: () => resolveAdminAuthCollection,
1923
+ resolveAuthorizedSiteId: () => resolveAuthorizedSiteId,
2423
1924
  round: () => round,
2424
1925
  runCollectionHooks: () => runCollectionHooks,
1926
+ sanitizeDocForAI: () => sanitizeDocForAI,
2425
1927
  saveWorkflowDraft: () => saveWorkflowDraft,
2426
1928
  simplePublishingWorkflow: () => simplePublishingWorkflow,
2427
1929
  slugify: () => slugify,
@@ -2440,7 +1942,8 @@ __export(index_exports, {
2440
1942
  validatePreviewUrlExpression: () => validatePreviewUrlExpression,
2441
1943
  when: () => when,
2442
1944
  wordCount: () => wordCount,
2443
- workflowCapabilities: () => workflowCapabilities
1945
+ workflowCapabilities: () => workflowCapabilities,
1946
+ z: () => import_zod.z
2444
1947
  });
2445
1948
  module.exports = __toCommonJS(index_exports);
2446
1949
 
@@ -2460,6 +1963,40 @@ function defineAction(config) {
2460
1963
  return config;
2461
1964
  }
2462
1965
 
1966
+ // src/types/ai.ts
1967
+ var AI_THREADS_COLLECTION = "_dyrected_ai_threads";
1968
+ var AI_MESSAGES_COLLECTION = "_dyrected_ai_messages";
1969
+ var AI_CHUNKS_COLLECTION = "_dyrected_ai_chunks";
1970
+ var AI_ACTIONS_COLLECTION = "_dyrected_ai_actions";
1971
+ var AI_AUDIT_COLLECTION = "_dyrected_ai_audit";
1972
+ function isAICollection(slug) {
1973
+ return slug === AI_THREADS_COLLECTION || slug === AI_MESSAGES_COLLECTION || slug === AI_CHUNKS_COLLECTION || slug === AI_ACTIONS_COLLECTION || slug === AI_AUDIT_COLLECTION;
1974
+ }
1975
+
1976
+ // src/types/ai-errors.ts
1977
+ var DyrectedAIError = class _DyrectedAIError extends Error {
1978
+ code;
1979
+ status;
1980
+ details;
1981
+ constructor(code, message, status = 500, details) {
1982
+ super(message);
1983
+ this.name = "DyrectedAIError";
1984
+ this.code = code;
1985
+ this.status = status;
1986
+ this.details = details;
1987
+ Object.setPrototypeOf(this, _DyrectedAIError.prototype);
1988
+ }
1989
+ toJSON() {
1990
+ return {
1991
+ error: true,
1992
+ code: this.code,
1993
+ message: this.message,
1994
+ status: this.status,
1995
+ details: this.details
1996
+ };
1997
+ }
1998
+ };
1999
+
2463
2000
  // src/auth/token.ts
2464
2001
  var import_jose = require("jose");
2465
2002
 
@@ -2862,18 +2399,31 @@ async function transitionWorkflow(args) {
2862
2399
  await hook({ ...hookContext, doc: updated, event: events[0] });
2863
2400
  } catch (error) {
2864
2401
  try {
2865
- const { getConfigLogger: getConfigLogger2, getObservabilityRuntime: getObservabilityRuntime2 } = await Promise.resolve().then(() => (init_observability(), observability_exports));
2866
- getObservabilityRuntime2(config)?.recordWorkflowHookFailure({
2402
+ const obs = config?.__observability;
2403
+ obs?.recordWorkflowHookFailure?.({
2867
2404
  collection: collection.slug,
2868
2405
  transition: transition.name
2869
2406
  });
2870
- getConfigLogger2(config, "workflow").error({
2871
- err: error,
2872
- msg: "afterTransition hook failed",
2873
- collection: collection.slug,
2874
- transition: transition.name,
2875
- documentId: id
2876
- });
2407
+ const logger = config?.logger;
2408
+ if (logger && typeof logger.child === "function") {
2409
+ logger.child({ component: "workflow" }).error({
2410
+ err: error,
2411
+ msg: "afterTransition hook failed",
2412
+ collection: collection.slug,
2413
+ transition: transition.name,
2414
+ documentId: id
2415
+ });
2416
+ } else if (logger && typeof logger.error === "function") {
2417
+ logger.error({
2418
+ err: error,
2419
+ msg: "afterTransition hook failed",
2420
+ collection: collection.slug,
2421
+ transition: transition.name,
2422
+ documentId: id
2423
+ });
2424
+ } else {
2425
+ console.error("afterTransition hook failed:", error);
2426
+ }
2877
2427
  } catch {
2878
2428
  console.error("afterTransition hook failed:", error);
2879
2429
  }
@@ -5023,6 +4573,182 @@ function generateOpenApi(config) {
5023
4573
  }
5024
4574
  }
5025
4575
  };
4576
+ spec.paths["/api/ai/chat"] = {
4577
+ post: {
4578
+ tags: ["AI"],
4579
+ summary: "Send prompt and stream AI assistant response",
4580
+ requestBody: {
4581
+ required: true,
4582
+ content: {
4583
+ "application/json": {
4584
+ schema: {
4585
+ type: "object",
4586
+ properties: {
4587
+ content: { type: "string", description: "User prompt message" },
4588
+ prompt: { type: "string", description: "Alias for content" },
4589
+ threadId: { type: "string", description: "Existing conversation thread ID" },
4590
+ messages: { type: "array", items: { type: "object" }, description: "Conversation history" }
4591
+ },
4592
+ required: []
4593
+ }
4594
+ }
4595
+ }
4596
+ },
4597
+ responses: {
4598
+ 200: {
4599
+ description: "Server-Sent Events (SSE) AI message stream",
4600
+ content: { "text/event-stream": { schema: { type: "string" } } }
4601
+ }
4602
+ }
4603
+ }
4604
+ };
4605
+ spec.paths["/api/ai/threads"] = {
4606
+ get: {
4607
+ tags: ["AI"],
4608
+ summary: "List conversation threads",
4609
+ parameters: [
4610
+ { name: "limit", in: "query", schema: { type: "integer", default: 20 } }
4611
+ ],
4612
+ responses: { 200: { description: "Array of conversation threads" } }
4613
+ },
4614
+ post: {
4615
+ tags: ["AI"],
4616
+ summary: "Create a new conversation thread",
4617
+ requestBody: {
4618
+ content: {
4619
+ "application/json": {
4620
+ schema: {
4621
+ type: "object",
4622
+ properties: { title: { type: "string" } }
4623
+ }
4624
+ }
4625
+ }
4626
+ },
4627
+ responses: { 201: { description: "Created conversation thread" } }
4628
+ },
4629
+ delete: {
4630
+ tags: ["AI"],
4631
+ summary: "Clear all conversation threads",
4632
+ responses: { 200: { description: "Count of deleted threads" } }
4633
+ }
4634
+ };
4635
+ spec.paths["/api/ai/threads/{threadId}"] = {
4636
+ get: {
4637
+ tags: ["AI"],
4638
+ summary: "Get conversation thread and historical messages",
4639
+ parameters: [
4640
+ { name: "threadId", in: "path", required: true, schema: { type: "string" } }
4641
+ ],
4642
+ responses: { 200: { description: "Thread details and messages" } }
4643
+ },
4644
+ delete: {
4645
+ tags: ["AI"],
4646
+ summary: "Delete a specific conversation thread",
4647
+ parameters: [
4648
+ { name: "threadId", in: "path", required: true, schema: { type: "string" } }
4649
+ ],
4650
+ responses: { 200: { description: "Deletion success status" } }
4651
+ }
4652
+ };
4653
+ spec.paths["/api/ai/threads/{threadId}/messages"] = {
4654
+ post: {
4655
+ tags: ["AI"],
4656
+ summary: "Post a message to an existing thread and stream reply",
4657
+ parameters: [
4658
+ { name: "threadId", in: "path", required: true, schema: { type: "string" } }
4659
+ ],
4660
+ requestBody: {
4661
+ required: true,
4662
+ content: {
4663
+ "application/json": {
4664
+ schema: {
4665
+ type: "object",
4666
+ properties: { content: { type: "string" } },
4667
+ required: ["content"]
4668
+ }
4669
+ }
4670
+ }
4671
+ },
4672
+ responses: {
4673
+ 200: {
4674
+ description: "Server-Sent Events (SSE) AI message stream",
4675
+ content: { "text/event-stream": { schema: { type: "string" } } }
4676
+ }
4677
+ }
4678
+ }
4679
+ };
4680
+ spec.paths["/api/ai/actions/{actionId}"] = {
4681
+ get: {
4682
+ tags: ["AI"],
4683
+ summary: "Get an AI mutation action proposal",
4684
+ parameters: [
4685
+ { name: "actionId", in: "path", required: true, schema: { type: "string" } }
4686
+ ],
4687
+ responses: { 200: { description: "AI Action details and diff payload" } }
4688
+ }
4689
+ };
4690
+ spec.paths["/api/ai/actions/{actionId}/execute"] = {
4691
+ post: {
4692
+ tags: ["AI"],
4693
+ summary: "Approve and execute an AI mutation proposal",
4694
+ parameters: [
4695
+ { name: "actionId", in: "path", required: true, schema: { type: "string" } }
4696
+ ],
4697
+ responses: { 200: { description: "Execution result" } }
4698
+ }
4699
+ };
4700
+ spec.paths["/api/ai/actions/{actionId}/reject"] = {
4701
+ post: {
4702
+ tags: ["AI"],
4703
+ summary: "Reject an AI mutation proposal",
4704
+ parameters: [
4705
+ { name: "actionId", in: "path", required: true, schema: { type: "string" } }
4706
+ ],
4707
+ responses: { 200: { description: "Rejection result" } }
4708
+ }
4709
+ };
4710
+ spec.paths["/api/ai/rag/reindex"] = {
4711
+ post: {
4712
+ tags: ["AI"],
4713
+ summary: "Trigger vector reindexing for semantic search",
4714
+ requestBody: {
4715
+ content: {
4716
+ "application/json": {
4717
+ schema: {
4718
+ type: "object",
4719
+ properties: {
4720
+ collection: { type: "string" },
4721
+ force: { type: "boolean" }
4722
+ }
4723
+ }
4724
+ }
4725
+ }
4726
+ },
4727
+ responses: { 200: { description: "Reindexing results and chunk counts" } }
4728
+ }
4729
+ };
4730
+ spec.paths["/api/ai/rag/search"] = {
4731
+ post: {
4732
+ tags: ["AI"],
4733
+ summary: "Perform semantic vector search against indexed content",
4734
+ requestBody: {
4735
+ required: true,
4736
+ content: {
4737
+ "application/json": {
4738
+ schema: {
4739
+ type: "object",
4740
+ properties: {
4741
+ query: { type: "string" },
4742
+ limit: { type: "integer", default: 5 }
4743
+ },
4744
+ required: ["query"]
4745
+ }
4746
+ }
4747
+ }
4748
+ },
4749
+ responses: { 200: { description: "Semantic search results" } }
4750
+ }
4751
+ };
5026
4752
  for (const collection of config.collections) {
5027
4753
  spec.components.schemas[collection.slug] = collectionToSchema(collection);
5028
4754
  }
@@ -6496,7 +6222,240 @@ function createExpr() {
6496
6222
  var expr = createExpr();
6497
6223
  var when = expr;
6498
6224
 
6225
+ // src/utils/tenant.ts
6226
+ var import_http_exception = require("hono/http-exception");
6227
+ function getAllowedSitesForUser(user, payload) {
6228
+ const raw = user?.allowedSites ?? user?.siteIds ?? user?.siteAccess ?? (user?.siteId ? [user.siteId] : void 0) ?? payload?.allowedSites ?? payload?.siteIds ?? payload?.siteAccess ?? (payload?.siteId ? [payload.siteId] : void 0);
6229
+ if (Array.isArray(raw)) {
6230
+ return raw.filter((s) => typeof s === "string" && s.trim().length > 0);
6231
+ }
6232
+ return void 0;
6233
+ }
6234
+ function isSiteAuthorized(user, payload, requestedSiteId) {
6235
+ const allowedSites = getAllowedSitesForUser(user, payload);
6236
+ if (!allowedSites || allowedSites.length === 0) {
6237
+ return true;
6238
+ }
6239
+ if (!requestedSiteId) {
6240
+ return false;
6241
+ }
6242
+ return allowedSites.includes(requestedSiteId);
6243
+ }
6244
+ function resolveAuthorizedSiteId(c) {
6245
+ const user = typeof c.get === "function" ? c.get("user") : void 0;
6246
+ const tokenPayload = typeof c.get === "function" ? c.get("authTokenPayload") : void 0;
6247
+ const requestedSiteId = (typeof c.req?.header === "function" ? c.req.header("X-Site-Id") : void 0) || (typeof c.get === "function" ? c.get("siteId") : void 0);
6248
+ const allowedSites = getAllowedSitesForUser(user, tokenPayload);
6249
+ if (Array.isArray(allowedSites) && allowedSites.length > 0) {
6250
+ if (!requestedSiteId) {
6251
+ return allowedSites[0];
6252
+ }
6253
+ if (!allowedSites.includes(requestedSiteId)) {
6254
+ throw new import_http_exception.HTTPException(403, {
6255
+ message: `Forbidden: User is not authorized to access site "${requestedSiteId}".`
6256
+ });
6257
+ }
6258
+ return requestedSiteId;
6259
+ }
6260
+ return requestedSiteId || "default";
6261
+ }
6262
+
6263
+ // src/utils/ai-pii.ts
6264
+ var NON_NEGOTIABLE_CREDENTIAL_FIELDS = /* @__PURE__ */ new Set([
6265
+ "password",
6266
+ "salt",
6267
+ "hash",
6268
+ "resetPasswordToken",
6269
+ "apiKey",
6270
+ "token",
6271
+ "secret",
6272
+ "accessToken",
6273
+ "refreshToken",
6274
+ "privateKey",
6275
+ "private_key",
6276
+ "webhookSecret",
6277
+ "webhook_secret",
6278
+ "authSecret",
6279
+ "auth_secret",
6280
+ "cvv",
6281
+ "cvc",
6282
+ "pin"
6283
+ ]);
6284
+ function maskEmail(email, strategy = "mask") {
6285
+ if (!email || typeof email !== "string") return email;
6286
+ if (strategy === "token") return "[REDACTED_EMAIL]";
6287
+ const atIdx = email.indexOf("@");
6288
+ if (atIdx <= 1) {
6289
+ return "***@" + (email.slice(atIdx + 1) || "example.com");
6290
+ }
6291
+ const prefix = email[0];
6292
+ const domain = email.slice(atIdx);
6293
+ return `${prefix}***${domain}`;
6294
+ }
6295
+ function maskPhone(phone, strategy = "mask") {
6296
+ if (!phone || typeof phone !== "string") return phone;
6297
+ if (strategy === "token") return "[REDACTED_PHONE]";
6298
+ const digits = phone.replace(/\D/g, "");
6299
+ if (digits.length < 4) return "***-***-****";
6300
+ const lastFour = digits.slice(-4);
6301
+ return `***-***-${lastFour}`;
6302
+ }
6303
+ var PII_REGEX_PATTERNS = {
6304
+ email: /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g,
6305
+ phone_number: /(?:\+?\d{1,3}[-\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-\s]?\d{4}\b/g,
6306
+ phoneNumber: /(?:\+?\d{1,3}[-\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-\s]?\d{4}\b/g,
6307
+ phone: /(?:\+?\d{1,3}[-\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-\s]?\d{4}\b/g,
6308
+ credit_card: /\b(?:\d{4}[-\s]?){3}\d{4}\b/g,
6309
+ ssn: /\b\d{3}-\d{2}-\d{4}\b/g,
6310
+ ipv4: /\b(?:\d{1,3}\.){3}\d{1,3}\b/g,
6311
+ ipv6: /(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,7}:|(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}/g,
6312
+ iban: /\b[A-Z]{2}\d{2}[A-Z0-9]{4}\d{7}([A-Z0-9]?){0,16}\b/g,
6313
+ api_key: /\b(?:sk_(?:live|test)_[0-9a-zA-Z_]{16,}|ghp_[0-9a-zA-Z_]{20,}|AKIA[0-9A-Z]{16})\b/g,
6314
+ jwt: /\beyJ[a-zA-Z0-9_-]+\.eyJ[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+\b/g,
6315
+ passport: /\b[A-Z]{1,2}[0-9]{6,9}\b/g
6316
+ };
6317
+ var PII_PATTERN_PRIORITY = {
6318
+ api_key: 1,
6319
+ jwt: 2,
6320
+ iban: 3,
6321
+ credit_card: 4,
6322
+ ipv6: 5,
6323
+ ipv4: 6,
6324
+ email: 7,
6325
+ passport: 8,
6326
+ ssn: 9,
6327
+ phone: 10,
6328
+ phone_number: 10,
6329
+ phoneNumber: 10
6330
+ };
6331
+ function maskTextPII(text, piiConfig) {
6332
+ if (!text || typeof text !== "string") return text;
6333
+ if (!piiConfig || piiConfig.enabled === false) return text;
6334
+ let result = text;
6335
+ const strategy = piiConfig.strategy || "mask";
6336
+ const rawPatterns = piiConfig.patterns || [
6337
+ "email",
6338
+ "phone",
6339
+ "phone_number",
6340
+ "phoneNumber",
6341
+ "ssn",
6342
+ "credit_card",
6343
+ "ipv4"
6344
+ ];
6345
+ const patterns = [...rawPatterns].sort(
6346
+ (a, b) => (PII_PATTERN_PRIORITY[a] ?? 99) - (PII_PATTERN_PRIORITY[b] ?? 99)
6347
+ );
6348
+ for (const patternName of patterns) {
6349
+ const regex = PII_REGEX_PATTERNS[patternName];
6350
+ if (!regex) continue;
6351
+ result = result.replace(regex, (match) => {
6352
+ switch (patternName) {
6353
+ case "email":
6354
+ return maskEmail(match, strategy);
6355
+ case "phone":
6356
+ case "phone_number":
6357
+ case "phoneNumber":
6358
+ return maskPhone(match, strategy);
6359
+ case "credit_card":
6360
+ return strategy === "token" ? "[REDACTED_CREDIT_CARD]" : "****-****-****-" + match.replace(/\D/g, "").slice(-4);
6361
+ case "ssn":
6362
+ return strategy === "token" ? "[REDACTED_SSN]" : "***-**-" + match.replace(/\D/g, "").slice(-4);
6363
+ case "ipv4":
6364
+ return "[REDACTED_IP]";
6365
+ case "ipv6":
6366
+ return "[REDACTED_IPV6]";
6367
+ case "iban":
6368
+ return strategy === "token" ? "[REDACTED_IBAN]" : "****-****-" + match.replace(/\s/g, "").slice(-4);
6369
+ case "api_key":
6370
+ return "[REDACTED_API_KEY]";
6371
+ case "jwt":
6372
+ return "[REDACTED_JWT]";
6373
+ case "passport":
6374
+ return strategy === "token" ? "[REDACTED_PASSPORT]" : "***" + match.slice(-3);
6375
+ default:
6376
+ return "[REDACTED]";
6377
+ }
6378
+ });
6379
+ }
6380
+ if (typeof piiConfig.customScrubber === "function") {
6381
+ result = piiConfig.customScrubber(result);
6382
+ }
6383
+ return result;
6384
+ }
6385
+ function sanitizeDocForAI(options) {
6386
+ const { doc, collectionConfig, globalAIConfig } = options;
6387
+ if (!doc || typeof doc !== "object") return doc;
6388
+ const copy = { ...doc };
6389
+ for (const cred of NON_NEGOTIABLE_CREDENTIAL_FIELDS) {
6390
+ delete copy[cred];
6391
+ }
6392
+ if (collectionConfig?.ai?.excludeFields) {
6393
+ for (const field of collectionConfig.ai.excludeFields) {
6394
+ delete copy[field];
6395
+ }
6396
+ }
6397
+ const fields = collectionConfig?.fields || [];
6398
+ for (const field of fields) {
6399
+ const fieldName = field.name;
6400
+ if (!fieldName || copy[fieldName] === void 0) continue;
6401
+ if (field.ai?.exclude === true) {
6402
+ delete copy[fieldName];
6403
+ continue;
6404
+ }
6405
+ const val = copy[fieldName];
6406
+ const normalizedName = fieldName.toLowerCase().replace(/[_\s-]/g, "");
6407
+ const isEmail = field.type === "email" || normalizedName.includes("email");
6408
+ const isPhone = field.type === "phone" || normalizedName.includes("phone") || normalizedName === "tel" || normalizedName === "telephone" || normalizedName === "mobile" || normalizedName === "cell";
6409
+ if (isEmail) {
6410
+ if (globalAIConfig?.pii?.enabled !== false && field.ai?.allowRaw !== true && typeof val === "string") {
6411
+ copy[fieldName] = maskEmail(val, globalAIConfig?.pii?.strategy);
6412
+ }
6413
+ continue;
6414
+ }
6415
+ if (isPhone) {
6416
+ if (globalAIConfig?.pii?.enabled !== false && field.ai?.allowRaw !== true && typeof val === "string") {
6417
+ copy[fieldName] = maskPhone(val, globalAIConfig?.pii?.strategy);
6418
+ }
6419
+ continue;
6420
+ }
6421
+ if (field.ai?.redact === true || field.ai?.redact === "mask") {
6422
+ if (typeof val === "string") {
6423
+ copy[fieldName] = "[REDACTED]";
6424
+ }
6425
+ }
6426
+ }
6427
+ if (collectionConfig?.ai?.redactFields) {
6428
+ for (const field of collectionConfig.ai.redactFields) {
6429
+ if (copy[field] !== void 0) {
6430
+ const val = copy[field];
6431
+ if (typeof val === "string") {
6432
+ if (field.toLowerCase().includes("email")) {
6433
+ copy[field] = maskEmail(val, globalAIConfig?.pii?.strategy);
6434
+ } else if (field.toLowerCase().includes("phone")) {
6435
+ copy[field] = maskPhone(val, globalAIConfig?.pii?.strategy);
6436
+ } else {
6437
+ copy[field] = "[REDACTED]";
6438
+ }
6439
+ }
6440
+ }
6441
+ }
6442
+ }
6443
+ let result = copy;
6444
+ if (typeof collectionConfig?.ai?.sanitizeDoc === "function") {
6445
+ result = collectionConfig.ai.sanitizeDoc(copy);
6446
+ }
6447
+ if (globalAIConfig?.pii?.enabled === true) {
6448
+ for (const [k, v] of Object.entries(result)) {
6449
+ if (typeof v === "string") {
6450
+ result[k] = maskTextPII(v, globalAIConfig.pii);
6451
+ }
6452
+ }
6453
+ }
6454
+ return result;
6455
+ }
6456
+
6499
6457
  // src/index.ts
6458
+ var import_zod = require("zod");
6500
6459
  function defineCollection(config) {
6501
6460
  return config;
6502
6461
  }
@@ -6545,12 +6504,20 @@ function defineTab(args) {
6545
6504
  }
6546
6505
  // Annotate the CommonJS export names for ESM import in node:
6547
6506
  0 && (module.exports = {
6507
+ AI_ACTIONS_COLLECTION,
6508
+ AI_AUDIT_COLLECTION,
6509
+ AI_CHUNKS_COLLECTION,
6510
+ AI_MESSAGES_COLLECTION,
6511
+ AI_THREADS_COLLECTION,
6548
6512
  BUILTIN_JEXL_HELPERS,
6549
6513
  ConfigValidationError,
6514
+ DyrectedAIError,
6550
6515
  FieldConditionBuilder,
6551
6516
  LIFECYCLE_EVENTS_COLLECTION,
6552
6517
  LIFECYCLE_EVENT_NAMES,
6553
6518
  MatchBuilder,
6519
+ NON_NEGOTIABLE_CREDENTIAL_FIELDS,
6520
+ PII_REGEX_PATTERNS,
6554
6521
  WORKFLOW_HISTORY_COLLECTION,
6555
6522
  abs,
6556
6523
  addDays,
@@ -6638,18 +6605,24 @@ function defineTab(args) {
6638
6605
  generateOpenApi,
6639
6606
  get,
6640
6607
  getAdminAuthCollection,
6608
+ getAllowedSitesForUser,
6641
6609
  getPublicAdminAuthConfig,
6642
6610
  includes,
6643
6611
  initializeWorkflowDocument,
6612
+ isAICollection,
6644
6613
  isConfigValidationError,
6645
6614
  isDetailItemVisible,
6646
6615
  isEmpty,
6647
6616
  isFuture,
6648
6617
  isPast,
6618
+ isSiteAuthorized,
6649
6619
  join,
6650
6620
  last,
6651
6621
  length,
6652
6622
  lower,
6623
+ maskEmail,
6624
+ maskPhone,
6625
+ maskTextPII,
6653
6626
  materializeWorkflowDocument,
6654
6627
  max,
6655
6628
  min,
@@ -6667,8 +6640,10 @@ function defineTab(args) {
6667
6640
  registerJexlHelpers,
6668
6641
  replace,
6669
6642
  resolveAdminAuthCollection,
6643
+ resolveAuthorizedSiteId,
6670
6644
  round,
6671
6645
  runCollectionHooks,
6646
+ sanitizeDocForAI,
6672
6647
  saveWorkflowDraft,
6673
6648
  simplePublishingWorkflow,
6674
6649
  slugify,
@@ -6687,5 +6662,6 @@ function defineTab(args) {
6687
6662
  validatePreviewUrlExpression,
6688
6663
  when,
6689
6664
  wordCount,
6690
- workflowCapabilities
6665
+ workflowCapabilities,
6666
+ z
6691
6667
  });