@c7-digital/ledger 0.0.6 → 0.0.7

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.
@@ -1,5 +1,5 @@
1
1
  // Auto-generated file - do not edit manually
2
- // Generated from /Users/stefanpla/Development/c7/sandbox/stream_interfaces/c7_ledger/ledger/specs/asyncapi_3.4.7.yaml
2
+ // Generated from /Users/stefanpla/Development/c7/c7_ledger/c7_ledger/ledger/specs/asyncapi_3.4.7.yaml
3
3
  export const ASYNCAPI_SCHEMA = `asyncapi: 2.6.0
4
4
  info:
5
5
  title: JSON Ledger API WebSocket endpoints
@@ -1,5 +1,5 @@
1
1
  // Auto-generated file - do not edit manually
2
- // Generated from /Users/stefanpla/Development/c7/sandbox/stream_interfaces/c7_ledger/ledger/specs/openapi_3.4.7.yaml
2
+ // Generated from /Users/stefanpla/Development/c7/c7_ledger/c7_ledger/ledger/specs/openapi_3.4.7.yaml
3
3
  export const OPENAPI_SCHEMA = `openapi: 3.0.3
4
4
  info:
5
5
  title: JSON Ledger API HTTP endpoints
@@ -15,6 +15,11 @@ export declare class SchemaValidator {
15
15
  * Helper function to handle errors based on the validation mode
16
16
  */
17
17
  private handleError;
18
+ /**
19
+ * Transform schema to allow null values for non-required fields
20
+ * This handles the common OpenAPI pattern where optional fields can be null
21
+ */
22
+ private makeOptionalFieldsNullable;
18
23
  private loadSchemasFromContent;
19
24
  /**
20
25
  * Validate an array of items against a schema
@@ -95,6 +95,61 @@ export class SchemaValidator {
95
95
  throw error instanceof Error ? error : new Error(message);
96
96
  }
97
97
  }
98
+ /**
99
+ * Transform schema to allow null values for non-required fields
100
+ * This handles the common OpenAPI pattern where optional fields can be null
101
+ */
102
+ makeOptionalFieldsNullable(schema) {
103
+ if (!schema || typeof schema !== "object")
104
+ return schema;
105
+ // Handle arrays - recursively transform each element
106
+ if (Array.isArray(schema)) {
107
+ return schema.map((item) => this.makeOptionalFieldsNullable(item));
108
+ }
109
+ const transformed = { ...schema };
110
+ // If this is an object schema with properties
111
+ if (transformed.type === "object" && transformed.properties) {
112
+ const required = new Set(transformed.required || []);
113
+ // For each property that's not required, allow null values
114
+ for (const [propName, propSchema] of Object.entries(transformed.properties)) {
115
+ if (!required.has(propName) && typeof propSchema === "object" && !Array.isArray(propSchema)) {
116
+ // If it has a simple type and isn't already allowing null
117
+ if (propSchema.type && typeof propSchema.type === "string" && propSchema.type !== "null") {
118
+ // Make it accept both the original type and null
119
+ transformed.properties[propName] = {
120
+ ...propSchema,
121
+ anyOf: [
122
+ { ...propSchema, type: propSchema.type },
123
+ { type: "null" }
124
+ ]
125
+ };
126
+ // Remove the type field as it's now in anyOf
127
+ delete transformed.properties[propName].type;
128
+ }
129
+ }
130
+ // Recursively transform nested schemas
131
+ const nestedSchema = transformed.properties[propName];
132
+ if (nestedSchema) {
133
+ transformed.properties[propName] = this.makeOptionalFieldsNullable(nestedSchema);
134
+ }
135
+ }
136
+ }
137
+ // Handle $ref - don't transform, let AJV resolve it
138
+ if (transformed.$ref) {
139
+ return transformed;
140
+ }
141
+ // Recursively handle nested schemas in allOf, anyOf, oneOf
142
+ if (transformed.allOf) {
143
+ transformed.allOf = transformed.allOf.map((s) => this.makeOptionalFieldsNullable(s));
144
+ }
145
+ if (transformed.anyOf) {
146
+ transformed.anyOf = transformed.anyOf.map((s) => this.makeOptionalFieldsNullable(s));
147
+ }
148
+ if (transformed.oneOf) {
149
+ transformed.oneOf = transformed.oneOf.map((s) => this.makeOptionalFieldsNullable(s));
150
+ }
151
+ return transformed;
152
+ }
98
153
  async loadSchemasFromContent(yamlContent) {
99
154
  if (!this.ajv)
100
155
  return;
@@ -104,6 +159,23 @@ export class SchemaValidator {
104
159
  const spec = yaml.parse(yamlContent);
105
160
  // Load the complete schema document first to enable reference resolution
106
161
  if (spec?.components?.schemas) {
162
+ // Transform schemas to allow null for optional fields
163
+ for (const [schemaName, schemaDefinition] of Object.entries(spec.components.schemas)) {
164
+ const transformed = this.makeOptionalFieldsNullable(schemaDefinition);
165
+ // Schemas in the components should always be objects, not arrays
166
+ if (transformed) {
167
+ if (Array.isArray(transformed)) {
168
+ // Arrays shouldn't appear at the schema root level, but handle gracefully
169
+ const firstItem = transformed[0];
170
+ if (firstItem) {
171
+ spec.components.schemas[schemaName] = firstItem;
172
+ }
173
+ }
174
+ else {
175
+ spec.components.schemas[schemaName] = transformed;
176
+ }
177
+ }
178
+ }
107
179
  // Add the full schema document with an ID so references can be resolved
108
180
  this.ajv.addSchema(spec, "#");
109
181
  logger.debug(`Added full schema document with ID "#"`);
@@ -168,7 +240,10 @@ export class SchemaValidator {
168
240
  }
169
241
  const isValid = this.ajv.validate(schemaName, data);
170
242
  if (!isValid) {
171
- this.handleError(`Schema validation failed for ${schemaName}:`, new Error(`Schema validation failed for ${schemaName}: ${this.ajv.errorsText()}`));
243
+ const errorDetails = this.ajv.errorsText();
244
+ logger.warn(`Validation errors: ${errorDetails}`);
245
+ logger.debug(`Full validation errors:`, this.ajv.errors);
246
+ this.handleError(`Schema validation failed for ${schemaName}: ${errorDetails}`, new Error(`Schema validation failed for ${schemaName}: ${errorDetails}`));
172
247
  }
173
248
  else {
174
249
  logger.debug(`Validation successful for "${schemaName}"`);