monora-ai 2.1.0 → 2.1.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 (184) hide show
  1. package/README.md +333 -159
  2. package/dist/aims_governance.d.ts +238 -0
  3. package/dist/aims_governance.d.ts.map +1 -0
  4. package/dist/aims_governance.js +922 -0
  5. package/dist/alerts.d.ts +16 -0
  6. package/dist/alerts.d.ts.map +1 -1
  7. package/dist/alerts.js +16 -0
  8. package/dist/api.d.ts +6 -0
  9. package/dist/api.d.ts.map +1 -1
  10. package/dist/api.js +6 -0
  11. package/dist/assessment.d.ts +85 -0
  12. package/dist/assessment.d.ts.map +1 -1
  13. package/dist/assessment.js +506 -13
  14. package/dist/attribution.d.ts +44 -3
  15. package/dist/attribution.d.ts.map +1 -1
  16. package/dist/attribution.js +197 -10
  17. package/dist/autodetect.d.ts +68 -0
  18. package/dist/autodetect.d.ts.map +1 -1
  19. package/dist/autodetect.js +639 -0
  20. package/dist/bias.d.ts +130 -0
  21. package/dist/bias.d.ts.map +1 -0
  22. package/dist/bias.js +223 -0
  23. package/dist/cli/diagnostics.d.ts +5 -1
  24. package/dist/cli/diagnostics.d.ts.map +1 -1
  25. package/dist/cli/diagnostics.js +23 -6
  26. package/dist/cli/doctor.d.ts +25 -0
  27. package/dist/cli/doctor.d.ts.map +1 -0
  28. package/dist/cli/doctor.js +381 -0
  29. package/dist/cli/fix.d.ts +16 -0
  30. package/dist/cli/fix.d.ts.map +1 -0
  31. package/dist/cli/fix.js +284 -0
  32. package/dist/cli/init.d.ts +57 -0
  33. package/dist/cli/init.d.ts.map +1 -0
  34. package/dist/cli/init.js +205 -0
  35. package/dist/cli.js +1550 -176
  36. package/dist/complianceTargets.d.ts +111 -0
  37. package/dist/complianceTargets.d.ts.map +1 -0
  38. package/dist/complianceTargets.js +521 -0
  39. package/dist/config.d.ts +261 -16
  40. package/dist/config.d.ts.map +1 -1
  41. package/dist/config.js +381 -32
  42. package/dist/config_migrations.d.ts.map +1 -1
  43. package/dist/config_migrations.js +38 -1
  44. package/dist/config_schema.d.ts +2490 -1035
  45. package/dist/config_schema.d.ts.map +1 -1
  46. package/dist/config_schema.js +233 -64
  47. package/dist/context.d.ts +34 -0
  48. package/dist/context.d.ts.map +1 -1
  49. package/dist/context.js +118 -7
  50. package/dist/control_backbone.d.ts +122 -0
  51. package/dist/control_backbone.d.ts.map +1 -0
  52. package/dist/control_backbone.js +698 -0
  53. package/dist/data-governance.d.ts +187 -0
  54. package/dist/data-governance.d.ts.map +1 -0
  55. package/dist/data-governance.js +424 -0
  56. package/dist/dataResidency.d.ts +44 -0
  57. package/dist/dataResidency.d.ts.map +1 -0
  58. package/dist/dataResidency.js +203 -0
  59. package/dist/dispatcher.d.ts.map +1 -1
  60. package/dist/dispatcher.js +17 -5
  61. package/dist/evidence_store.d.ts +103 -0
  62. package/dist/evidence_store.d.ts.map +1 -0
  63. package/dist/evidence_store.js +459 -0
  64. package/dist/executiveSummary.d.ts +15 -0
  65. package/dist/executiveSummary.d.ts.map +1 -1
  66. package/dist/executiveSummary.js +135 -22
  67. package/dist/identity.d.ts +143 -0
  68. package/dist/identity.d.ts.map +1 -0
  69. package/dist/identity.js +231 -0
  70. package/dist/impact-assessment.d.ts +350 -0
  71. package/dist/impact-assessment.d.ts.map +1 -0
  72. package/dist/impact-assessment.js +580 -0
  73. package/dist/index.d.ts +20 -4
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +247 -5
  76. package/dist/instrumentation.d.ts +1 -1
  77. package/dist/instrumentation.d.ts.map +1 -1
  78. package/dist/instrumentation.js +123 -22
  79. package/dist/integrations/anthropic.d.ts +3 -0
  80. package/dist/integrations/anthropic.d.ts.map +1 -1
  81. package/dist/integrations/anthropic.js +282 -80
  82. package/dist/integrations/governance.d.ts +33 -0
  83. package/dist/integrations/governance.d.ts.map +1 -0
  84. package/dist/integrations/governance.js +208 -0
  85. package/dist/integrations/langchain.d.ts +4 -0
  86. package/dist/integrations/langchain.d.ts.map +1 -1
  87. package/dist/integrations/langchain.js +362 -142
  88. package/dist/integrations/openai.d.ts +9 -0
  89. package/dist/integrations/openai.d.ts.map +1 -1
  90. package/dist/integrations/openai.js +673 -73
  91. package/dist/iso42001_consolidation.d.ts +16 -0
  92. package/dist/iso42001_consolidation.d.ts.map +1 -0
  93. package/dist/iso42001_consolidation.js +413 -0
  94. package/dist/iso42001_workflows.d.ts +263 -0
  95. package/dist/iso42001_workflows.d.ts.map +1 -0
  96. package/dist/iso42001_workflows.js +781 -0
  97. package/dist/lifecycle.d.ts +299 -0
  98. package/dist/lifecycle.d.ts.map +1 -0
  99. package/dist/lifecycle.js +624 -0
  100. package/dist/lineage.d.ts +2 -2
  101. package/dist/lineage.d.ts.map +1 -1
  102. package/dist/lineage.js +9 -16
  103. package/dist/middleware/express.d.ts.map +1 -1
  104. package/dist/middleware/express.js +18 -3
  105. package/dist/middleware/nextjs.js +2 -2
  106. package/dist/model.d.ts +143 -0
  107. package/dist/model.d.ts.map +1 -0
  108. package/dist/model.js +371 -0
  109. package/dist/onboarding.d.ts +42 -0
  110. package/dist/onboarding.d.ts.map +1 -0
  111. package/dist/onboarding.js +1022 -0
  112. package/dist/oversight.d.ts +264 -0
  113. package/dist/oversight.d.ts.map +1 -0
  114. package/dist/oversight.js +497 -0
  115. package/dist/presets.js +7 -7
  116. package/dist/quotas.d.ts +171 -0
  117. package/dist/quotas.d.ts.map +1 -0
  118. package/dist/quotas.js +259 -0
  119. package/dist/register.d.ts +13 -0
  120. package/dist/register.d.ts.map +1 -0
  121. package/dist/register.js +99 -0
  122. package/dist/registry.d.ts +1 -0
  123. package/dist/registry.d.ts.map +1 -1
  124. package/dist/registry.js +7 -0
  125. package/dist/registryData.json +43 -6
  126. package/dist/report.d.ts +2 -1
  127. package/dist/report.d.ts.map +1 -1
  128. package/dist/report.js +189 -2
  129. package/dist/reporting.d.ts +125 -0
  130. package/dist/reporting.d.ts.map +1 -1
  131. package/dist/reporting.js +192 -2
  132. package/dist/resources.d.ts +285 -0
  133. package/dist/resources.d.ts.map +1 -0
  134. package/dist/resources.js +643 -0
  135. package/dist/risk.d.ts +120 -0
  136. package/dist/risk.d.ts.map +1 -0
  137. package/dist/risk.js +220 -0
  138. package/dist/runtime.d.ts +73 -0
  139. package/dist/runtime.d.ts.map +1 -1
  140. package/dist/runtime.js +415 -18
  141. package/dist/schemaInference.d.ts +92 -0
  142. package/dist/schemaInference.d.ts.map +1 -0
  143. package/dist/schemaInference.js +466 -0
  144. package/dist/schema_validation.js +2 -2
  145. package/dist/schemas/config.schema.json +118 -4
  146. package/dist/security_report.js +4 -4
  147. package/dist/signing.d.ts +1 -1
  148. package/dist/signing.d.ts.map +1 -1
  149. package/dist/signing.js +4 -0
  150. package/dist/sinks/file.d.ts +19 -1
  151. package/dist/sinks/file.d.ts.map +1 -1
  152. package/dist/sinks/file.js +82 -13
  153. package/dist/sinks/https.d.ts +10 -0
  154. package/dist/sinks/https.d.ts.map +1 -1
  155. package/dist/sinks/https.js +76 -16
  156. package/dist/sinks/stdout.d.ts +1 -0
  157. package/dist/sinks/stdout.d.ts.map +1 -1
  158. package/dist/sinks/stdout.js +12 -1
  159. package/dist/spec.d.ts +159 -0
  160. package/dist/spec.d.ts.map +1 -0
  161. package/dist/spec.js +391 -0
  162. package/dist/stakeholders.d.ts +199 -0
  163. package/dist/stakeholders.d.ts.map +1 -0
  164. package/dist/stakeholders.js +398 -0
  165. package/dist/standards.d.ts.map +1 -1
  166. package/dist/standards.js +160 -2
  167. package/dist/standards_ingest.d.ts.map +1 -1
  168. package/dist/standards_ingest.js +1 -4
  169. package/dist/telemetry.d.ts +16 -2
  170. package/dist/telemetry.d.ts.map +1 -1
  171. package/dist/telemetry.js +77 -14
  172. package/dist/templates/controls/iso42001_control_catalog.json +1443 -0
  173. package/dist/traced_emitter.d.ts.map +1 -1
  174. package/dist/traced_emitter.js +19 -9
  175. package/dist/trust_package.d.ts +19 -1
  176. package/dist/trust_package.d.ts.map +1 -1
  177. package/dist/trust_package.js +89 -2
  178. package/dist/verify.d.ts.map +1 -1
  179. package/dist/verify.js +9 -2
  180. package/dist/wal.d.ts.map +1 -1
  181. package/dist/wal.js +2 -1
  182. package/package.json +14 -1
  183. package/scripts/postinstall.js +105 -210
  184. package/templates/controls/iso42001_control_catalog.json +1443 -0
package/dist/lineage.js CHANGED
@@ -6,6 +6,7 @@
6
6
  * automatic capture of parent events and input events in the trace graph.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.createLineageContext = createLineageContext;
9
10
  exports.setCurrentEvent = setCurrentEvent;
10
11
  exports.getParentEventId = getParentEventId;
11
12
  exports.addInputEvent = addInputEvent;
@@ -29,14 +30,18 @@ const lineageStorage = new async_hooks_1.AsyncLocalStorage();
29
30
  /**
30
31
  * Get the current lineage context or a default one.
31
32
  *
32
- * Note: This does not persist the default context.
33
+ * Note: This persists a default context when none is present.
33
34
  */
34
35
  function getContextOrDefault() {
35
36
  const existing = lineageStorage.getStore();
36
37
  if (existing) {
37
38
  return existing;
38
39
  }
39
- // Return a default context if none exists
40
+ const defaultContext = createLineageContext();
41
+ lineageStorage.enterWith(defaultContext);
42
+ return defaultContext;
43
+ }
44
+ function createLineageContext() {
40
45
  return {
41
46
  currentEventId: null,
42
47
  inputEventIds: [],
@@ -208,13 +213,7 @@ function clearLineageContext() {
208
213
  * @returns The result of the function.
209
214
  */
210
215
  function runWithLineage(fn) {
211
- const ctx = {
212
- currentEventId: null,
213
- inputEventIds: [],
214
- promptId: null,
215
- templateId: null,
216
- dataSourceIds: [],
217
- };
216
+ const ctx = createLineageContext();
218
217
  return lineageStorage.run(ctx, fn);
219
218
  }
220
219
  /**
@@ -224,13 +223,7 @@ function runWithLineage(fn) {
224
223
  * @returns Promise resolving to the function result.
225
224
  */
226
225
  async function runWithLineageAsync(fn) {
227
- const ctx = {
228
- currentEventId: null,
229
- inputEventIds: [],
230
- promptId: null,
231
- templateId: null,
232
- dataSourceIds: [],
233
- };
226
+ const ctx = createLineageContext();
234
227
  return lineageStorage.run(ctx, fn);
235
228
  }
236
229
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../src/middleware/express.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,MAAM,CAAC;IAElC;;OAEG;IACH,SAAS,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAExB;;;OAGG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,wBAA6B,IAO7D,KAAK,GAAG,EAAE,KAAK,GAAG,EAAE,MAAM,GAAG,SA0DtC;AAWD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,KACxB,KAAK,GAAG,EAAE,KAAK,GAAG,EAAE,KAAK,GAAG,EAAE,MAAM,GAAG,UAoBhD;AAED,eAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../src/middleware/express.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,MAAM,CAAC;IAElC;;OAEG;IACH,SAAS,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAExB;;;OAGG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,wBAA6B,IAO7D,KAAK,GAAG,EAAE,KAAK,GAAG,EAAE,MAAM,GAAG,SAwEtC;AAWD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,KACxB,KAAK,GAAG,EAAE,KAAK,GAAG,EAAE,KAAK,GAAG,EAAE,MAAM,GAAG,UAoBhD;AAED,eAAe,gBAAgB,CAAC"}
@@ -67,21 +67,36 @@ function monoraMiddleware(options = {}) {
67
67
  req.monoraSpan = span;
68
68
  req.monoraTraceId = span.traceId;
69
69
  req.monoraSpanId = span.spanId;
70
- return new Promise((resolve) => {
70
+ return new Promise((resolve, reject) => {
71
71
  let finished = false;
72
- const finish = () => {
72
+ const cleanup = () => {
73
73
  if (finished)
74
74
  return;
75
75
  finished = true;
76
76
  res.off('finish', finish);
77
77
  res.off('close', finish);
78
78
  res.off('error', finish);
79
+ };
80
+ const finish = () => {
81
+ cleanup();
79
82
  resolve();
80
83
  };
81
84
  res.on('finish', finish);
82
85
  res.on('close', finish);
83
86
  res.on('error', finish);
84
- next();
87
+ try {
88
+ const result = next();
89
+ if (result && typeof result.then === 'function') {
90
+ result.catch((error) => {
91
+ cleanup();
92
+ reject(error);
93
+ });
94
+ }
95
+ }
96
+ catch (error) {
97
+ cleanup();
98
+ reject(error);
99
+ }
85
100
  });
86
101
  }, traceOptions).catch(next);
87
102
  };
@@ -169,7 +169,7 @@ function defaultSpanName(req) {
169
169
  */
170
170
  function withMonoraApi(handler, options = {}) {
171
171
  const { spanNameFn = (req) => `API ${req.method || 'GET'} ${req.url || '/'}`, injectResponseHeaders = true, } = options;
172
- const wrapped = (async (req, res) => {
172
+ const wrapped = ((req, res) => {
173
173
  // Extract headers
174
174
  const headers = {};
175
175
  if (req.headers) {
@@ -200,7 +200,7 @@ function withMonoraApi(handler, options = {}) {
200
200
  // Determine span name
201
201
  const spanName = spanNameFn(req);
202
202
  // Run handler within trace
203
- const result = await (0, context_1.trace)(spanName, async (span) => {
203
+ const result = (0, context_1.trace)(spanName, (span) => {
204
204
  // Store span on request for access in handler
205
205
  req.monoraSpan = span;
206
206
  req.monoraTraceId = span.traceId;
@@ -0,0 +1,143 @@
1
+ /**
2
+ * MonoraModel - Registered AI model/application with its specification.
3
+ *
4
+ * Provides the MonoraModel class for registering and managing AI models/applications
5
+ * being monitored by Monora.
6
+ */
7
+ import { MonoraSpec } from './spec';
8
+ import { InferSchemaOptions } from './schemaInference';
9
+ /** Risk category per EU AI Act classification */
10
+ export type RiskCategory = 'minimal' | 'limited' | 'high' | 'unacceptable';
11
+ /**
12
+ * A single validation error.
13
+ */
14
+ export interface ValidationError {
15
+ field: string;
16
+ message: string;
17
+ expected?: string;
18
+ actual?: string;
19
+ }
20
+ /**
21
+ * Result of validating an event against a model spec.
22
+ */
23
+ export interface ValidationResult {
24
+ valid: boolean;
25
+ errors: ValidationError[];
26
+ warnings: string[];
27
+ }
28
+ /**
29
+ * Create a ValidationResult.
30
+ */
31
+ export declare function createValidationResult(valid: boolean, errors?: ValidationError[], warnings?: string[]): ValidationResult;
32
+ /**
33
+ * Convert ValidationResult to dictionary.
34
+ */
35
+ export declare function validationResultToDict(result: ValidationResult): Record<string, any>;
36
+ /**
37
+ * MonoraModel - A registered AI model/application with its specification.
38
+ */
39
+ export interface MonoraModel {
40
+ /** Unique identifier for the model */
41
+ modelId: string;
42
+ /** MonoraSpec containing schema and enrichment configuration */
43
+ spec: MonoraSpec;
44
+ /** EU AI Act risk classification */
45
+ riskCategory: RiskCategory;
46
+ /** Description of the model's intended use */
47
+ intendedUse?: string;
48
+ /** ISO timestamp of model creation */
49
+ createdAt: string;
50
+ /** ISO timestamp of last update */
51
+ updatedAt?: string;
52
+ /** List of tags for categorization */
53
+ tags: string[];
54
+ /** Owner/team responsible for the model */
55
+ owner?: string;
56
+ }
57
+ export interface CreateModelOptions {
58
+ modelId: string;
59
+ spec: MonoraSpec;
60
+ riskCategory?: RiskCategory;
61
+ intendedUse?: string;
62
+ tags?: string[];
63
+ owner?: string;
64
+ }
65
+ /**
66
+ * Create a MonoraModel instance.
67
+ */
68
+ export declare function createMonoraModel(options: CreateModelOptions): MonoraModel;
69
+ export interface FromDataOptions extends InferSchemaOptions {
70
+ /** Source: file path or list of event dictionaries */
71
+ source: string | Array<Record<string, any>>;
72
+ /** EU AI Act risk classification */
73
+ riskCategory?: RiskCategory;
74
+ /** Description of model's intended use */
75
+ intendedUse?: string;
76
+ /** Tags for categorization */
77
+ tags?: string[];
78
+ /** Owner/team responsible */
79
+ owner?: string;
80
+ }
81
+ /**
82
+ * Create a MonoraModel from sample data using schema inference.
83
+ *
84
+ * This is the primary way to create a model when you have sample events.
85
+ * It analyzes the events to infer the schema, detect PII, and configure
86
+ * appropriate enrichments.
87
+ */
88
+ export declare function modelFromData(options: FromDataOptions): MonoraModel;
89
+ /**
90
+ * Create a MonoraModel from an existing MonoraSpec.
91
+ */
92
+ export declare function modelFromSpec(spec: MonoraSpec, options?: {
93
+ modelId?: string;
94
+ riskCategory?: RiskCategory;
95
+ intendedUse?: string;
96
+ tags?: string[];
97
+ owner?: string;
98
+ }): MonoraModel;
99
+ /**
100
+ * Validate an event against a model's specification.
101
+ */
102
+ export declare function validateEvent(model: MonoraModel, event: Record<string, any>): ValidationResult;
103
+ /**
104
+ * Generate a complete Monora configuration from a model.
105
+ */
106
+ export declare function generateConfig(model: MonoraModel): Record<string, any>;
107
+ /**
108
+ * Convert MonoraModel to dictionary representation.
109
+ */
110
+ export declare function modelToDict(model: MonoraModel): Record<string, any>;
111
+ /**
112
+ * Convert MonoraModel to JSON string.
113
+ */
114
+ export declare function modelToJson(model: MonoraModel, indent?: number): string;
115
+ /**
116
+ * Create MonoraModel from dictionary representation.
117
+ */
118
+ export declare function modelFromDict(data: Record<string, any>): MonoraModel;
119
+ /**
120
+ * Create MonoraModel from JSON string.
121
+ */
122
+ export declare function modelFromJson(jsonStr: string): MonoraModel;
123
+ /**
124
+ * Save MonoraModel to a JSON file.
125
+ */
126
+ export declare function saveModel(model: MonoraModel, filePath: string): void;
127
+ /**
128
+ * Load MonoraModel from a JSON file.
129
+ */
130
+ export declare function loadModel(filePath: string): MonoraModel;
131
+ /**
132
+ * Save just the schema contract for use with onboarding validation.
133
+ */
134
+ export declare function saveSchemaContract(model: MonoraModel, filePath: string): void;
135
+ /**
136
+ * Save the generated Monora configuration.
137
+ */
138
+ export declare function saveConfig(model: MonoraModel, filePath: string, format?: 'json' | 'yaml'): void;
139
+ /**
140
+ * Get a string representation of a MonoraModel.
141
+ */
142
+ export declare function modelToString(model: MonoraModel): string;
143
+ //# sourceMappingURL=model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"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"}
package/dist/model.js ADDED
@@ -0,0 +1,371 @@
1
+ "use strict";
2
+ /**
3
+ * MonoraModel - Registered AI model/application with its specification.
4
+ *
5
+ * Provides the MonoraModel class for registering and managing AI models/applications
6
+ * being monitored by Monora.
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.createValidationResult = createValidationResult;
43
+ exports.validationResultToDict = validationResultToDict;
44
+ exports.createMonoraModel = createMonoraModel;
45
+ exports.modelFromData = modelFromData;
46
+ exports.modelFromSpec = modelFromSpec;
47
+ exports.validateEvent = validateEvent;
48
+ exports.generateConfig = generateConfig;
49
+ exports.modelToDict = modelToDict;
50
+ exports.modelToJson = modelToJson;
51
+ exports.modelFromDict = modelFromDict;
52
+ exports.modelFromJson = modelFromJson;
53
+ exports.saveModel = saveModel;
54
+ exports.loadModel = loadModel;
55
+ exports.saveSchemaContract = saveSchemaContract;
56
+ exports.saveConfig = saveConfig;
57
+ exports.modelToString = modelToString;
58
+ const fs = __importStar(require("fs"));
59
+ const path = __importStar(require("path"));
60
+ const spec_1 = require("./spec");
61
+ const schemaInference_1 = require("./schemaInference");
62
+ /**
63
+ * Create a ValidationResult.
64
+ */
65
+ function createValidationResult(valid, errors = [], warnings = []) {
66
+ return { valid, errors, warnings };
67
+ }
68
+ /**
69
+ * Convert ValidationResult to dictionary.
70
+ */
71
+ function validationResultToDict(result) {
72
+ return {
73
+ valid: result.valid,
74
+ errors: result.errors.map((e) => ({
75
+ field: e.field,
76
+ message: e.message,
77
+ expected: e.expected,
78
+ actual: e.actual,
79
+ })),
80
+ warnings: result.warnings,
81
+ };
82
+ }
83
+ /**
84
+ * Create a MonoraModel instance.
85
+ */
86
+ function createMonoraModel(options) {
87
+ return {
88
+ modelId: options.modelId,
89
+ spec: options.spec,
90
+ riskCategory: options.riskCategory ?? 'limited',
91
+ intendedUse: options.intendedUse,
92
+ createdAt: new Date().toISOString(),
93
+ updatedAt: undefined,
94
+ tags: options.tags ?? [],
95
+ owner: options.owner,
96
+ };
97
+ }
98
+ /**
99
+ * Create a MonoraModel from sample data using schema inference.
100
+ *
101
+ * This is the primary way to create a model when you have sample events.
102
+ * It analyzes the events to infer the schema, detect PII, and configure
103
+ * appropriate enrichments.
104
+ */
105
+ function modelFromData(options) {
106
+ const { source, modelName = 'unnamed-model', modelVersion = '1.0.0', complianceTargets, riskCategory = 'limited', intendedUse, detectPii = true, sampleSize = 100, tags = [], owner, } = options;
107
+ // Load events if source is a path
108
+ let events;
109
+ if (typeof source === 'string') {
110
+ events = (0, schemaInference_1.loadEventsFromFile)(source);
111
+ }
112
+ else {
113
+ events = source;
114
+ }
115
+ // Infer schema
116
+ const spec = (0, schemaInference_1.inferSchemaFromEvents)(events, {
117
+ modelName,
118
+ modelVersion,
119
+ complianceTargets,
120
+ detectPii,
121
+ sampleSize,
122
+ });
123
+ return createMonoraModel({
124
+ modelId: modelName,
125
+ spec,
126
+ riskCategory,
127
+ intendedUse,
128
+ tags,
129
+ owner,
130
+ });
131
+ }
132
+ /**
133
+ * Create a MonoraModel from an existing MonoraSpec.
134
+ */
135
+ function modelFromSpec(spec, options = {}) {
136
+ return createMonoraModel({
137
+ modelId: options.modelId || spec.modelName || 'unnamed-model',
138
+ spec,
139
+ riskCategory: options.riskCategory ?? 'limited',
140
+ intendedUse: options.intendedUse,
141
+ tags: options.tags ?? [],
142
+ owner: options.owner,
143
+ });
144
+ }
145
+ /**
146
+ * Flatten nested dictionary to dot-notation keys.
147
+ */
148
+ function flattenDict(obj, parentKey = '', sep = '.') {
149
+ const items = [];
150
+ for (const [k, v] of Object.entries(obj)) {
151
+ const newKey = parentKey ? `${parentKey}${sep}${k}` : k;
152
+ if (v && typeof v === 'object' && !Array.isArray(v)) {
153
+ const nested = flattenDict(v, newKey, sep);
154
+ items.push(...Object.entries(nested));
155
+ }
156
+ else {
157
+ items.push([newKey, v]);
158
+ }
159
+ }
160
+ return Object.fromEntries(items);
161
+ }
162
+ /**
163
+ * Get Python type(s) for a FieldType.
164
+ */
165
+ function getExpectedTypes(fieldType) {
166
+ const typeMapping = {
167
+ string: ['string'],
168
+ number: ['number'],
169
+ integer: ['number'],
170
+ boolean: ['boolean'],
171
+ array: ['array'],
172
+ object: ['object'],
173
+ };
174
+ return typeMapping[fieldType] || ['string'];
175
+ }
176
+ /**
177
+ * Check if a value matches the expected field type.
178
+ */
179
+ function matchesType(value, fieldType) {
180
+ const expectedTypes = getExpectedTypes(fieldType);
181
+ if (expectedTypes.includes('string') && typeof value === 'string')
182
+ return true;
183
+ if (expectedTypes.includes('number') && typeof value === 'number')
184
+ return true;
185
+ if (expectedTypes.includes('boolean') && typeof value === 'boolean')
186
+ return true;
187
+ if (expectedTypes.includes('array') && Array.isArray(value))
188
+ return true;
189
+ if (expectedTypes.includes('object') && typeof value === 'object' && !Array.isArray(value))
190
+ return true;
191
+ return false;
192
+ }
193
+ /**
194
+ * Validate an event against a model's specification.
195
+ */
196
+ function validateEvent(model, event) {
197
+ const errors = [];
198
+ const warnings = [];
199
+ // Flatten the event for field checking
200
+ const flatEvent = flattenDict(event);
201
+ const allFields = (0, spec_1.getAllFields)(model.spec);
202
+ // Check all required fields
203
+ for (const fieldSpec of allFields) {
204
+ if (fieldSpec.required) {
205
+ if (!(fieldSpec.name in flatEvent)) {
206
+ errors.push({
207
+ field: fieldSpec.name,
208
+ message: `Required field '${fieldSpec.name}' is missing`,
209
+ });
210
+ }
211
+ else if (flatEvent[fieldSpec.name] === null && !fieldSpec.nullable) {
212
+ errors.push({
213
+ field: fieldSpec.name,
214
+ message: `Field '${fieldSpec.name}' cannot be null`,
215
+ });
216
+ }
217
+ }
218
+ }
219
+ // Check field types
220
+ for (const fieldSpec of allFields) {
221
+ if (fieldSpec.name in flatEvent) {
222
+ const value = flatEvent[fieldSpec.name];
223
+ if (value !== null && value !== undefined) {
224
+ if (!matchesType(value, fieldSpec.dataType)) {
225
+ errors.push({
226
+ field: fieldSpec.name,
227
+ message: `Field '${fieldSpec.name}' has wrong type`,
228
+ expected: fieldSpec.dataType,
229
+ actual: typeof value,
230
+ });
231
+ }
232
+ }
233
+ }
234
+ }
235
+ // Check identifiers
236
+ for (const fieldSpec of model.spec.identifiers || []) {
237
+ if (!(fieldSpec.name in flatEvent)) {
238
+ warnings.push(`Identifier field '${fieldSpec.name}' is missing`);
239
+ }
240
+ }
241
+ return createValidationResult(errors.length === 0, errors, warnings);
242
+ }
243
+ /**
244
+ * Generate a complete Monora configuration from a model.
245
+ */
246
+ function generateConfig(model) {
247
+ const config = (0, spec_1.specToConfig)(model.spec);
248
+ // Add model-specific configuration
249
+ config.defaults = config.defaults || {};
250
+ config.defaults.service_name = model.modelId;
251
+ // Add risk category for AI Act compliance
252
+ config.ai_act = config.ai_act || { enabled: true };
253
+ config.ai_act.default_risk_category = model.riskCategory;
254
+ // Add model metadata to onboarding section
255
+ config.onboarding = config.onboarding || { enabled: true };
256
+ config.onboarding.model_spec = {
257
+ name: model.modelId,
258
+ version: model.spec.modelVersion,
259
+ event_ts_field: model.spec.eventTimestampField,
260
+ risk_category: model.riskCategory,
261
+ intended_use: model.intendedUse,
262
+ roles: {
263
+ inputs: model.spec.inputs.map((f) => f.name),
264
+ outputs: model.spec.outputs.map((f) => f.name),
265
+ metadata: (model.spec.metadata || []).map((f) => f.name),
266
+ identifiers: (model.spec.identifiers || []).map((f) => f.name),
267
+ },
268
+ };
269
+ return config;
270
+ }
271
+ /**
272
+ * Convert MonoraModel to dictionary representation.
273
+ */
274
+ function modelToDict(model) {
275
+ return {
276
+ model_id: model.modelId,
277
+ spec: (0, spec_1.specToDict)(model.spec),
278
+ risk_category: model.riskCategory,
279
+ intended_use: model.intendedUse,
280
+ created_at: model.createdAt,
281
+ updated_at: model.updatedAt,
282
+ tags: model.tags,
283
+ owner: model.owner,
284
+ };
285
+ }
286
+ /**
287
+ * Convert MonoraModel to JSON string.
288
+ */
289
+ function modelToJson(model, indent = 2) {
290
+ return JSON.stringify(modelToDict(model), null, indent);
291
+ }
292
+ /**
293
+ * Create MonoraModel from dictionary representation.
294
+ */
295
+ function modelFromDict(data) {
296
+ return {
297
+ modelId: data.model_id || data.modelId,
298
+ spec: (0, spec_1.specFromDict)(data.spec),
299
+ riskCategory: data.risk_category || data.riskCategory || 'limited',
300
+ intendedUse: data.intended_use || data.intendedUse,
301
+ createdAt: data.created_at || data.createdAt || new Date().toISOString(),
302
+ updatedAt: data.updated_at || data.updatedAt,
303
+ tags: data.tags || [],
304
+ owner: data.owner,
305
+ };
306
+ }
307
+ /**
308
+ * Create MonoraModel from JSON string.
309
+ */
310
+ function modelFromJson(jsonStr) {
311
+ return modelFromDict(JSON.parse(jsonStr));
312
+ }
313
+ /**
314
+ * Save MonoraModel to a JSON file.
315
+ */
316
+ function saveModel(model, filePath) {
317
+ const resolvedPath = path.resolve(filePath);
318
+ const dir = path.dirname(resolvedPath);
319
+ // Create directory if it doesn't exist
320
+ fs.mkdirSync(dir, { recursive: true });
321
+ // Update timestamp
322
+ model.updatedAt = new Date().toISOString();
323
+ fs.writeFileSync(resolvedPath, modelToJson(model), 'utf-8');
324
+ }
325
+ /**
326
+ * Load MonoraModel from a JSON file.
327
+ */
328
+ function loadModel(filePath) {
329
+ const resolvedPath = path.resolve(filePath);
330
+ const content = fs.readFileSync(resolvedPath, 'utf-8');
331
+ return modelFromJson(content);
332
+ }
333
+ /**
334
+ * Save just the schema contract for use with onboarding validation.
335
+ */
336
+ function saveSchemaContract(model, filePath) {
337
+ const contract = (0, spec_1.specToSchemaContract)(model.spec);
338
+ const resolvedPath = path.resolve(filePath);
339
+ const dir = path.dirname(resolvedPath);
340
+ fs.mkdirSync(dir, { recursive: true });
341
+ fs.writeFileSync(resolvedPath, JSON.stringify(contract, null, 2), 'utf-8');
342
+ }
343
+ /**
344
+ * Save the generated Monora configuration.
345
+ */
346
+ function saveConfig(model, filePath, format = 'yaml') {
347
+ const config = generateConfig(model);
348
+ const resolvedPath = path.resolve(filePath);
349
+ const dir = path.dirname(resolvedPath);
350
+ fs.mkdirSync(dir, { recursive: true });
351
+ if (format === 'yaml') {
352
+ try {
353
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
354
+ const yaml = require('js-yaml');
355
+ fs.writeFileSync(resolvedPath, yaml.dump(config, { sortKeys: false }), 'utf-8');
356
+ }
357
+ catch {
358
+ // Fall back to JSON if js-yaml not available
359
+ fs.writeFileSync(resolvedPath, JSON.stringify(config, null, 2), 'utf-8');
360
+ }
361
+ }
362
+ else {
363
+ fs.writeFileSync(resolvedPath, JSON.stringify(config, null, 2), 'utf-8');
364
+ }
365
+ }
366
+ /**
367
+ * Get a string representation of a MonoraModel.
368
+ */
369
+ function modelToString(model) {
370
+ return `MonoraModel(modelId='${model.modelId}', riskCategory='${model.riskCategory}', inputs=${model.spec.inputs.length}, outputs=${model.spec.outputs.length})`;
371
+ }
@@ -0,0 +1,42 @@
1
+ import { MonoraConfig } from './config';
2
+ export interface BuildModelSpecOptions {
3
+ name?: string;
4
+ version?: string;
5
+ eventTsField?: string;
6
+ schemaRef?: string;
7
+ roles?: {
8
+ inputs?: string[];
9
+ outputs?: string[];
10
+ metadata?: string[];
11
+ identifiers?: string[];
12
+ };
13
+ }
14
+ export interface OnboardingResult {
15
+ status: string;
16
+ errors: string[];
17
+ warnings: string[];
18
+ coverage: Record<string, any>;
19
+ artifacts: Record<string, any>;
20
+ }
21
+ export interface ValidateOnboardingOptions {
22
+ configPath?: string;
23
+ configDict?: MonoraConfig;
24
+ inputPathOverride?: string;
25
+ persist?: boolean;
26
+ }
27
+ export interface CompleteOnboardingOptions {
28
+ configPath?: string;
29
+ configDict?: MonoraConfig;
30
+ completedBy?: string;
31
+ }
32
+ export declare function buildModelSpec(options?: BuildModelSpecOptions): Record<string, any>;
33
+ export declare function validateOnboarding(options?: ValidateOnboardingOptions): OnboardingResult;
34
+ export declare function completeOnboarding(options?: CompleteOnboardingOptions): OnboardingResult;
35
+ export declare function getOnboardingStatus(options?: {
36
+ configPath?: string;
37
+ configDict?: MonoraConfig;
38
+ }): Record<string, any>;
39
+ export declare function resolveEnrichmentPlan(config: MonoraConfig, options?: {
40
+ apply?: boolean;
41
+ }): Record<string, any>;
42
+ //# sourceMappingURL=onboarding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onboarding.d.ts","sourceRoot":"","sources":["../src/onboarding.ts"],"names":[],"mappings":"AAIA,OAAO,EAA8B,YAAY,EAAE,MAAM,UAAU,CAAC;AAKpE,MAAM,WAAW,qBAAqB;IACpC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE;QACN,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAClB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;KACxB,CAAC;CACH;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,yBAAyB;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,YAAY,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,yBAAyB;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,YAAY,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AA+CD,wBAAgB,cAAc,CAAC,OAAO,GAAE,qBAA0B,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAcvF;AAED,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,yBAA8B,GAAG,gBAAgB,CA8I5F;AAED,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,yBAA8B,GAAG,gBAAgB,CAgH5F;AAED,wBAAgB,mBAAmB,CAAC,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,YAAY,CAAA;CAAO,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAsEzH;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,YAAY,EACpB,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAC5B,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAkErB"}