@spine-event-engine/core 2.0.0-snapshot.2 → 2.0.0-snapshot.20
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/README.md +61 -8
- package/REFERENCE.md +31 -3
- package/dist/codegen/index.d.ts +10 -0
- package/dist/codegen/index.d.ts.map +1 -0
- package/dist/codegen/index.js +20 -0
- package/dist/codegen/index.js.map +1 -0
- package/dist/entity/entity-column.d.ts +158 -0
- package/dist/entity/entity-column.d.ts.map +1 -0
- package/dist/entity/entity-column.js +303 -0
- package/dist/entity/entity-column.js.map +1 -0
- package/dist/index.d.ts +84 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +331 -7
- package/dist/index.js.map +1 -1
- package/dist/internal/subscription-lifecycle.d.ts +0 -1
- package/dist/internal/subscription-lifecycle.d.ts.map +1 -1
- package/dist/internal/subscription-lifecycle.js +0 -1
- package/dist/internal/subscription-lifecycle.js.map +1 -1
- package/dist/query/entity-field-classification.d.ts +20 -0
- package/dist/query/entity-field-classification.d.ts.map +1 -0
- package/dist/query/entity-field-classification.js +62 -0
- package/dist/query/entity-field-classification.js.map +1 -0
- package/dist/query/entity-query.d.ts +405 -0
- package/dist/query/entity-query.d.ts.map +1 -0
- package/dist/query/entity-query.js +841 -0
- package/dist/query/entity-query.js.map +1 -0
- package/dist/query/generated-entity-query.d.ts +197 -0
- package/dist/query/generated-entity-query.d.ts.map +1 -0
- package/dist/query/generated-entity-query.js +202 -0
- package/dist/query/generated-entity-query.js.map +1 -0
- package/dist/spi/entity-query-plan.d.ts +7 -0
- package/dist/spi/entity-query-plan.d.ts.map +1 -0
- package/dist/spi/entity-query-plan.js +15 -0
- package/dist/spi/entity-query-plan.js.map +1 -0
- package/dist/spi/subscription-lifecycle.d.ts +5 -0
- package/dist/spi/subscription-lifecycle.d.ts.map +1 -0
- package/dist/spi/subscription-lifecycle.js +18 -0
- package/dist/spi/subscription-lifecycle.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +14 -7
package/dist/index.js
CHANGED
|
@@ -16,6 +16,8 @@ import { base64Decode, base64Encode } from "@bufbuild/protobuf/wire";
|
|
|
16
16
|
import { AnySchema, Int32ValueSchema, Int64ValueSchema, StringValueSchema, } from "@bufbuild/protobuf/wkt";
|
|
17
17
|
import { validate as validateWithSpine } from "@spine-event-engine/validation";
|
|
18
18
|
import { ActorContextSchema, CommandContextSchema, CommandIdSchema, CommandSchema, CommandContext_ScheduleSchema, Command_SystemPropertiesSchema, ConstraintViolationSchema, EmailAddressSchema, EnrichmentSchema, Enrichment_ContainerSchema, EventContextSchema, EventIdSchema, EventSchema, FieldPathSchema, InternetDomainSchema, LocalDateSchema, LocalDateTimeSchema, LocalTimeSchema, MessageIdSchema, OriginSchema, RejectionEventContextSchema, TemplateStringSchema, TenantIdSchema, UserIdSchema, ValidationErrorSchema, VersionSchema, YearMonthSchema, ZoneIdSchema, ZonedDateTimeSchema, type_url_prefix, } from "@spine-event-engine/proto";
|
|
19
|
+
export { EntityColumn, } from "./entity/entity-column.js";
|
|
20
|
+
export { EntityQuery, EntityQueryBuilder, } from "./query/entity-query.js";
|
|
19
21
|
const EMPTY_VIOLATIONS = Object.freeze([]);
|
|
20
22
|
const REDACTED_VALIDATION_DETAIL = "[redacted]";
|
|
21
23
|
const VALIDATION_RUNTIME_FAILURE_MESSAGE = "Validation runtime failed.";
|
|
@@ -179,13 +181,30 @@ export class ValidationException extends Error {
|
|
|
179
181
|
return this.#messageData;
|
|
180
182
|
}
|
|
181
183
|
}
|
|
184
|
+
/**
|
|
185
|
+
* Constructs a rejection after its generated message has been validated.
|
|
186
|
+
*
|
|
187
|
+
* @typeParam Schema Generated rejection message schema.
|
|
188
|
+
* @param schema Schema used to snapshot the message.
|
|
189
|
+
* @param messageData Validated rejection message.
|
|
190
|
+
* @returns Nominal rejection throwable.
|
|
191
|
+
*/
|
|
182
192
|
let instantiateRejection;
|
|
183
193
|
/**
|
|
184
194
|
* A nominal domain rejection carrying its generated Protobuf message.
|
|
195
|
+
*
|
|
196
|
+
* @typeParam Schema Generated schema of the rejection message.
|
|
185
197
|
*/
|
|
186
198
|
export class RejectionThrowable extends Error {
|
|
187
199
|
#schema;
|
|
188
200
|
#messageData;
|
|
201
|
+
/**
|
|
202
|
+
* Captures a validated rejection through the private factory token.
|
|
203
|
+
*
|
|
204
|
+
* @param schema Generated rejection message schema.
|
|
205
|
+
* @param messageData Validated rejection message to snapshot.
|
|
206
|
+
* @param token Token restricting construction to the factory.
|
|
207
|
+
*/
|
|
189
208
|
constructor(schema, messageData, token) {
|
|
190
209
|
super(`Rejected: ${schema.typeName}`);
|
|
191
210
|
if (token !== REJECTION_CONSTRUCTOR) {
|
|
@@ -199,7 +218,18 @@ export class RejectionThrowable extends Error {
|
|
|
199
218
|
Object.preventExtensions(this);
|
|
200
219
|
}
|
|
201
220
|
static {
|
|
202
|
-
instantiateRejection = (schema, messageData) =>
|
|
221
|
+
instantiateRejection = (schema, messageData) => RejectionThrowable.instantiate(schema, messageData);
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Creates a typed rejection through the private constructor.
|
|
225
|
+
*
|
|
226
|
+
* @typeParam CreatedSchema Generated rejection message schema.
|
|
227
|
+
* @param schema Schema used to snapshot the message.
|
|
228
|
+
* @param messageData Validated rejection message.
|
|
229
|
+
* @returns Nominal rejection throwable.
|
|
230
|
+
*/
|
|
231
|
+
static instantiate(schema, messageData) {
|
|
232
|
+
return new RejectionThrowable(schema, messageData, REJECTION_CONSTRUCTOR);
|
|
203
233
|
}
|
|
204
234
|
/**
|
|
205
235
|
* Returns the generated Protobuf-ES schema for the rejected domain signal.
|
|
@@ -224,6 +254,7 @@ export class RejectionThrowable extends Error {
|
|
|
224
254
|
}
|
|
225
255
|
/**
|
|
226
256
|
* Creates a nominal throwable from a validated generated rejection message.
|
|
257
|
+
* @typeParam Schema Generated rejection message schema.
|
|
227
258
|
* @param schema The generated rejection schema.
|
|
228
259
|
* @param input The rejection message fields.
|
|
229
260
|
* @returns The validated nominal rejection throwable.
|
|
@@ -240,6 +271,11 @@ export class RejectionThrowable extends Error {
|
|
|
240
271
|
static is(value) {
|
|
241
272
|
return typeof value === "object" && value !== null && REJECTION_THROWABLES.has(value);
|
|
242
273
|
}
|
|
274
|
+
/**
|
|
275
|
+
* Validates that a schema is a top-level message from a rejection schema file.
|
|
276
|
+
*
|
|
277
|
+
* @param schema Candidate generated rejection schema.
|
|
278
|
+
*/
|
|
243
279
|
static assertSchema(schema) {
|
|
244
280
|
const basename = schema.file.proto.name.split("/").at(-1);
|
|
245
281
|
const rejectionSource = basename === "rejections.proto" || basename?.endsWith("_rejections.proto") === true;
|
|
@@ -247,6 +283,14 @@ export class RejectionThrowable extends Error {
|
|
|
247
283
|
throw new TypeError(`Rejection schema "${schema.typeName}" must be a top-level message declared in a rejections.proto file.`);
|
|
248
284
|
}
|
|
249
285
|
}
|
|
286
|
+
/**
|
|
287
|
+
* Copies a rejection message through its binary representation.
|
|
288
|
+
*
|
|
289
|
+
* @typeParam Schema Generated rejection message schema.
|
|
290
|
+
* @param schema Schema used to encode and decode the message.
|
|
291
|
+
* @param message Rejection message to copy.
|
|
292
|
+
* @returns Independent message snapshot.
|
|
293
|
+
*/
|
|
250
294
|
static snapshot(schema, message) {
|
|
251
295
|
return fromBinary(schema, toBinary(schema, message));
|
|
252
296
|
}
|
|
@@ -266,6 +310,7 @@ export const Validate = {
|
|
|
266
310
|
},
|
|
267
311
|
/**
|
|
268
312
|
* Validates one Protobuf message through the Spine TS validation facade.
|
|
313
|
+
* @typeParam Schema Generated schema of the message being validated.
|
|
269
314
|
* @param schema The message schema.
|
|
270
315
|
* @param message The message to validate.
|
|
271
316
|
* @returns The sanitized validation result.
|
|
@@ -282,6 +327,7 @@ export const Validate = {
|
|
|
282
327
|
},
|
|
283
328
|
/**
|
|
284
329
|
* Validates one Protobuf message and throws for constraint violations.
|
|
330
|
+
* @typeParam Schema Generated schema of the message being validated.
|
|
285
331
|
* @param schema The message schema.
|
|
286
332
|
* @param message The message to validate.
|
|
287
333
|
* @returns The validated message.
|
|
@@ -294,6 +340,7 @@ export const Validate = {
|
|
|
294
340
|
},
|
|
295
341
|
/**
|
|
296
342
|
* Validates a previous/next state pair with framework-owned transition rules.
|
|
343
|
+
* @typeParam Schema Generated schema shared by both states.
|
|
297
344
|
* @param request The state transition.
|
|
298
345
|
* @param rules The rules to apply.
|
|
299
346
|
* @returns The sanitized transition result.
|
|
@@ -376,6 +423,7 @@ export const AnyMessages = {
|
|
|
376
423
|
// prettier-ignore
|
|
377
424
|
/**
|
|
378
425
|
* Packs a message into `Any`, omitting unknown fields from binary output.
|
|
426
|
+
* @typeParam Schema Generated schema of the enclosed message.
|
|
379
427
|
* @param schema The message schema.
|
|
380
428
|
* @param message The message to pack.
|
|
381
429
|
* @param options The packing options.
|
|
@@ -391,6 +439,7 @@ export const AnyMessages = {
|
|
|
391
439
|
},
|
|
392
440
|
/**
|
|
393
441
|
* Unpacks an `Any` when its type URL exactly matches the requested schema.
|
|
442
|
+
* @typeParam Schema Generated schema expected in the envelope.
|
|
394
443
|
* @param packed The packed message.
|
|
395
444
|
* @param schema The expected schema.
|
|
396
445
|
* @returns The unpacked message, when valid.
|
|
@@ -427,8 +476,23 @@ Object.freeze(AnyMessages);
|
|
|
427
476
|
function isProtobufRegistry(types) {
|
|
428
477
|
return "kind" in types;
|
|
429
478
|
}
|
|
479
|
+
/**
|
|
480
|
+
* Creates reversible compact Proto JSON conversion for a generated message.
|
|
481
|
+
*
|
|
482
|
+
* @typeParam Schema Generated schema used for conversion.
|
|
483
|
+
* @param schema Message schema used for Proto JSON.
|
|
484
|
+
* @param registry Optional registry for expanding packed Any messages.
|
|
485
|
+
* @param typeUrls Canonical URLs restored on parsed Any messages.
|
|
486
|
+
* @returns Schema-bound stringifier.
|
|
487
|
+
*/
|
|
430
488
|
function defaultMessageStringifier(schema, registry, typeUrls) {
|
|
431
489
|
return Object.freeze({
|
|
490
|
+
/**
|
|
491
|
+
* Parses compact Proto JSON and restores canonical Any type URLs.
|
|
492
|
+
*
|
|
493
|
+
* @param value Compact Proto JSON text.
|
|
494
|
+
* @returns Parsed generated message.
|
|
495
|
+
*/
|
|
432
496
|
fromString(value) {
|
|
433
497
|
const message = registry === undefined
|
|
434
498
|
? fromJsonString(schema, value)
|
|
@@ -436,6 +500,12 @@ function defaultMessageStringifier(schema, registry, typeUrls) {
|
|
|
436
500
|
restoreAnyTypeUrls(message, typeUrls);
|
|
437
501
|
return message;
|
|
438
502
|
},
|
|
503
|
+
/**
|
|
504
|
+
* Serializes a generated message as compact Proto JSON.
|
|
505
|
+
*
|
|
506
|
+
* @param value Generated message to serialize.
|
|
507
|
+
* @returns Compact Proto JSON text.
|
|
508
|
+
*/
|
|
439
509
|
toString(value) {
|
|
440
510
|
return registry === undefined
|
|
441
511
|
? toJsonString(schema, value)
|
|
@@ -464,6 +534,13 @@ function restoreAnyTypeUrls(value, typeUrls) {
|
|
|
464
534
|
restoreAnyTypeUrls(item, typeUrls);
|
|
465
535
|
}
|
|
466
536
|
const FieldStringifiers = Object.freeze({
|
|
537
|
+
/**
|
|
538
|
+
* Returns reversible conversion for one singular message, enum, or scalar field.
|
|
539
|
+
*
|
|
540
|
+
* @param field Generated descriptor of the field.
|
|
541
|
+
* @param messageStringifier Resolves conversion for message-valued fields.
|
|
542
|
+
* @returns Stringifier for the field's runtime value.
|
|
543
|
+
*/
|
|
467
544
|
create(field, messageStringifier) {
|
|
468
545
|
switch (field.fieldKind) {
|
|
469
546
|
case "message":
|
|
@@ -477,13 +554,31 @@ const FieldStringifiers = Object.freeze({
|
|
|
477
554
|
throw new Error("Stringifiers support only singular Protobuf fields.");
|
|
478
555
|
}
|
|
479
556
|
},
|
|
557
|
+
/**
|
|
558
|
+
* Creates enum conversion using declared names and valid numeric values.
|
|
559
|
+
*
|
|
560
|
+
* @param field Generated enum field descriptor.
|
|
561
|
+
* @returns Reversible enum stringifier.
|
|
562
|
+
*/
|
|
480
563
|
enum(field) {
|
|
481
564
|
return Object.freeze({
|
|
565
|
+
/**
|
|
566
|
+
* Parses a declared enum name or valid integer text.
|
|
567
|
+
*
|
|
568
|
+
* @param value Enum name or canonical numeric text.
|
|
569
|
+
* @returns Enum numeric value.
|
|
570
|
+
*/
|
|
482
571
|
fromString(value) {
|
|
483
572
|
const named = field.enum.values.find((candidate) => candidate.name === value);
|
|
484
573
|
return (named?.number ??
|
|
485
574
|
Number(FieldStringifiers.integerText(value, -(2n ** 31n), 2n ** 31n - 1n)));
|
|
486
575
|
},
|
|
576
|
+
/**
|
|
577
|
+
* Formats an enum number as its declared name or integer text.
|
|
578
|
+
*
|
|
579
|
+
* @param value Valid enum numeric value.
|
|
580
|
+
* @returns Declared name when available, otherwise numeric text.
|
|
581
|
+
*/
|
|
487
582
|
toString(value) {
|
|
488
583
|
if (typeof value !== "number" || !Number.isInteger(value)) {
|
|
489
584
|
throw new TypeError("Enum field value must be an integer number.");
|
|
@@ -493,6 +588,12 @@ const FieldStringifiers = Object.freeze({
|
|
|
493
588
|
},
|
|
494
589
|
});
|
|
495
590
|
},
|
|
591
|
+
/**
|
|
592
|
+
* Returns conversion and range rules for a Protobuf scalar field.
|
|
593
|
+
*
|
|
594
|
+
* @param field Generated scalar field descriptor.
|
|
595
|
+
* @returns Reversible scalar stringifier.
|
|
596
|
+
*/
|
|
496
597
|
scalar(field) {
|
|
497
598
|
switch (field.scalar) {
|
|
498
599
|
case ScalarType.STRING:
|
|
@@ -522,9 +623,21 @@ const FieldStringifiers = Object.freeze({
|
|
|
522
623
|
}
|
|
523
624
|
},
|
|
524
625
|
string: Object.freeze({
|
|
626
|
+
/**
|
|
627
|
+
* Accepts a string field without changing its text.
|
|
628
|
+
*
|
|
629
|
+
* @param value Stored string text.
|
|
630
|
+
* @returns The same string value.
|
|
631
|
+
*/
|
|
525
632
|
fromString(value) {
|
|
526
633
|
return value;
|
|
527
634
|
},
|
|
635
|
+
/**
|
|
636
|
+
* Checks and returns a string field value.
|
|
637
|
+
*
|
|
638
|
+
* @param value Runtime string field value.
|
|
639
|
+
* @returns The same string text.
|
|
640
|
+
*/
|
|
528
641
|
toString(value) {
|
|
529
642
|
if (typeof value !== "string")
|
|
530
643
|
throw new TypeError("Field value must be a string.");
|
|
@@ -532,6 +645,12 @@ const FieldStringifiers = Object.freeze({
|
|
|
532
645
|
},
|
|
533
646
|
}),
|
|
534
647
|
boolean: Object.freeze({
|
|
648
|
+
/**
|
|
649
|
+
* Parses canonical boolean text.
|
|
650
|
+
*
|
|
651
|
+
* @param value Text required to be `true` or `false`.
|
|
652
|
+
* @returns Decoded boolean value.
|
|
653
|
+
*/
|
|
535
654
|
fromString(value) {
|
|
536
655
|
if (value === "true")
|
|
537
656
|
return true;
|
|
@@ -539,6 +658,12 @@ const FieldStringifiers = Object.freeze({
|
|
|
539
658
|
return false;
|
|
540
659
|
throw new Error("Field value must be a canonical boolean.");
|
|
541
660
|
},
|
|
661
|
+
/**
|
|
662
|
+
* Formats a boolean as canonical text.
|
|
663
|
+
*
|
|
664
|
+
* @param value Runtime boolean field value.
|
|
665
|
+
* @returns `true` or `false`.
|
|
666
|
+
*/
|
|
542
667
|
toString(value) {
|
|
543
668
|
if (typeof value !== "boolean")
|
|
544
669
|
throw new TypeError("Field value must be a boolean.");
|
|
@@ -546,6 +671,12 @@ const FieldStringifiers = Object.freeze({
|
|
|
546
671
|
},
|
|
547
672
|
}),
|
|
548
673
|
bytes: Object.freeze({
|
|
674
|
+
/**
|
|
675
|
+
* Decodes a canonical standard-base64 byte field.
|
|
676
|
+
*
|
|
677
|
+
* @param value Canonical base64 text.
|
|
678
|
+
* @returns Decoded bytes.
|
|
679
|
+
*/
|
|
549
680
|
fromString(value) {
|
|
550
681
|
let decoded;
|
|
551
682
|
try {
|
|
@@ -559,6 +690,12 @@ const FieldStringifiers = Object.freeze({
|
|
|
559
690
|
}
|
|
560
691
|
return decoded;
|
|
561
692
|
},
|
|
693
|
+
/**
|
|
694
|
+
* Encodes a byte field as standard base64.
|
|
695
|
+
*
|
|
696
|
+
* @param value Runtime byte array.
|
|
697
|
+
* @returns Canonical base64 text.
|
|
698
|
+
*/
|
|
562
699
|
toString(value) {
|
|
563
700
|
if (!(value instanceof Uint8Array)) {
|
|
564
701
|
throw new TypeError("Field value must be a byte array.");
|
|
@@ -567,6 +704,12 @@ const FieldStringifiers = Object.freeze({
|
|
|
567
704
|
},
|
|
568
705
|
}),
|
|
569
706
|
number: Object.freeze({
|
|
707
|
+
/**
|
|
708
|
+
* Parses canonical finite numeric text, preserving negative zero.
|
|
709
|
+
*
|
|
710
|
+
* @param value Canonical finite number text.
|
|
711
|
+
* @returns Parsed finite number.
|
|
712
|
+
*/
|
|
570
713
|
fromString(value) {
|
|
571
714
|
const parsed = Number(value);
|
|
572
715
|
if (!Number.isFinite(parsed))
|
|
@@ -576,6 +719,12 @@ const FieldStringifiers = Object.freeze({
|
|
|
576
719
|
throw new Error("Field value must be a canonical number.");
|
|
577
720
|
return parsed;
|
|
578
721
|
},
|
|
722
|
+
/**
|
|
723
|
+
* Formats a finite number canonically, preserving negative zero.
|
|
724
|
+
*
|
|
725
|
+
* @param value Runtime finite number.
|
|
726
|
+
* @returns Canonical numeric text.
|
|
727
|
+
*/
|
|
579
728
|
toString(value) {
|
|
580
729
|
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
581
730
|
throw new TypeError("Field value must be a finite number.");
|
|
@@ -584,6 +733,12 @@ const FieldStringifiers = Object.freeze({
|
|
|
584
733
|
},
|
|
585
734
|
}),
|
|
586
735
|
float: Object.freeze({
|
|
736
|
+
/**
|
|
737
|
+
* Parses canonical binary32 text and rejects values outside its range.
|
|
738
|
+
*
|
|
739
|
+
* @param value Canonical binary32 number text.
|
|
740
|
+
* @returns Rounded binary32 number.
|
|
741
|
+
*/
|
|
587
742
|
fromString(value) {
|
|
588
743
|
const parsed = Number(value);
|
|
589
744
|
if (!Number.isFinite(parsed))
|
|
@@ -597,6 +752,12 @@ const FieldStringifiers = Object.freeze({
|
|
|
597
752
|
}
|
|
598
753
|
return restored;
|
|
599
754
|
},
|
|
755
|
+
/**
|
|
756
|
+
* Converts a finite number to canonical binary32 text.
|
|
757
|
+
*
|
|
758
|
+
* @param value Runtime finite number.
|
|
759
|
+
* @returns Canonical binary32 number text.
|
|
760
|
+
*/
|
|
600
761
|
toString(value) {
|
|
601
762
|
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
602
763
|
throw new TypeError("Field value must be a finite number.");
|
|
@@ -608,6 +769,12 @@ const FieldStringifiers = Object.freeze({
|
|
|
608
769
|
return FieldStringifiers.floatText(normalized);
|
|
609
770
|
},
|
|
610
771
|
}),
|
|
772
|
+
/**
|
|
773
|
+
* Finds the shortest decimal text that round-trips to a binary32 value.
|
|
774
|
+
*
|
|
775
|
+
* @param value Finite binary32 number to format.
|
|
776
|
+
* @returns Canonical short decimal text.
|
|
777
|
+
*/
|
|
611
778
|
floatText(value) {
|
|
612
779
|
if (Object.is(value, -0))
|
|
613
780
|
return "-0";
|
|
@@ -620,8 +787,22 @@ const FieldStringifiers = Object.freeze({
|
|
|
620
787
|
}
|
|
621
788
|
throw new Error("Unable to format the float32 field value.");
|
|
622
789
|
},
|
|
790
|
+
/**
|
|
791
|
+
* Creates range-checked integer conversion for a declared runtime representation.
|
|
792
|
+
*
|
|
793
|
+
* @param min Smallest integer accepted by the field.
|
|
794
|
+
* @param max Largest integer accepted by the field.
|
|
795
|
+
* @param representation Runtime number, bigint, or string representation.
|
|
796
|
+
* @returns Reversible bounded integer stringifier.
|
|
797
|
+
*/
|
|
623
798
|
integer(min, max, representation) {
|
|
624
799
|
return Object.freeze({
|
|
800
|
+
/**
|
|
801
|
+
* Parses bounded canonical integer text into the declared runtime form.
|
|
802
|
+
*
|
|
803
|
+
* @param value Canonical integer text.
|
|
804
|
+
* @returns Number, bigint, or string required by the field.
|
|
805
|
+
*/
|
|
625
806
|
fromString(value) {
|
|
626
807
|
const restored = FieldStringifiers.integerText(value, min, max);
|
|
627
808
|
switch (representation) {
|
|
@@ -633,12 +814,26 @@ const FieldStringifiers = Object.freeze({
|
|
|
633
814
|
return restored.toString();
|
|
634
815
|
}
|
|
635
816
|
},
|
|
817
|
+
/**
|
|
818
|
+
* Checks a runtime integer and formats it as canonical decimal text.
|
|
819
|
+
*
|
|
820
|
+
* @param value Integer in the field's runtime representation.
|
|
821
|
+
* @returns Canonical decimal text.
|
|
822
|
+
*/
|
|
636
823
|
toString(value) {
|
|
637
824
|
const restored = FieldStringifiers.integerValue(value, min, max, representation);
|
|
638
825
|
return restored.toString();
|
|
639
826
|
},
|
|
640
827
|
});
|
|
641
828
|
},
|
|
829
|
+
/**
|
|
830
|
+
* Parses canonical decimal integer text within the field's bounds.
|
|
831
|
+
*
|
|
832
|
+
* @param value Canonical integer text.
|
|
833
|
+
* @param min Smallest allowed integer.
|
|
834
|
+
* @param max Largest allowed integer.
|
|
835
|
+
* @returns Parsed bounded integer.
|
|
836
|
+
*/
|
|
642
837
|
integerText(value, min, max) {
|
|
643
838
|
if (!/^(?:0|-?[1-9]\d*)$/u.test(value)) {
|
|
644
839
|
throw new Error("Field value must be a canonical integer.");
|
|
@@ -650,6 +845,15 @@ const FieldStringifiers = Object.freeze({
|
|
|
650
845
|
}
|
|
651
846
|
return restored;
|
|
652
847
|
},
|
|
848
|
+
/**
|
|
849
|
+
* Converts a runtime integer to bigint after representation and range checks.
|
|
850
|
+
*
|
|
851
|
+
* @param value Integer value to validate.
|
|
852
|
+
* @param min Smallest allowed integer.
|
|
853
|
+
* @param max Largest allowed integer.
|
|
854
|
+
* @param representation Required runtime representation.
|
|
855
|
+
* @returns Bounded bigint value.
|
|
856
|
+
*/
|
|
653
857
|
integerValue(value, min, max, representation) {
|
|
654
858
|
let converted;
|
|
655
859
|
if (representation === "string") {
|
|
@@ -682,6 +886,7 @@ export const Stringifiers = {
|
|
|
682
886
|
// prettier-ignore
|
|
683
887
|
/**
|
|
684
888
|
* Creates the default compact Proto JSON stringifier for a message schema.
|
|
889
|
+
* @typeParam Schema Generated schema used for Proto JSON conversion.
|
|
685
890
|
* @param schema The generated message schema.
|
|
686
891
|
* @param types The optional generated-type registry used to expand `Any` values.
|
|
687
892
|
* @returns A reversible schema-bound stringifier.
|
|
@@ -736,6 +941,7 @@ export class StringifierRegistry {
|
|
|
736
941
|
}
|
|
737
942
|
/**
|
|
738
943
|
* Registers or replaces the stringifier for one generated message type.
|
|
944
|
+
* @typeParam Schema Generated schema of the custom stringifier's message.
|
|
739
945
|
* @param schema The generated message schema.
|
|
740
946
|
* @param stringifier The reversible stringifier.
|
|
741
947
|
*/
|
|
@@ -754,6 +960,7 @@ export class StringifierRegistry {
|
|
|
754
960
|
}
|
|
755
961
|
/**
|
|
756
962
|
* Returns the custom stringifier or the default compact Proto JSON mapping.
|
|
963
|
+
* @typeParam Schema Generated schema of the requested stringifier.
|
|
757
964
|
* @param schema The generated message schema.
|
|
758
965
|
* @returns The schema-bound stringifier.
|
|
759
966
|
*/
|
|
@@ -794,6 +1001,12 @@ export const Identifiers = {
|
|
|
794
1001
|
};
|
|
795
1002
|
Object.freeze(Identifiers);
|
|
796
1003
|
const IdentifierValues = Object.freeze({
|
|
1004
|
+
/**
|
|
1005
|
+
* Validates a signed 32-bit numeric identifier.
|
|
1006
|
+
*
|
|
1007
|
+
* @param value Candidate numeric identifier.
|
|
1008
|
+
* @returns Integer within the signed 32-bit range.
|
|
1009
|
+
*/
|
|
797
1010
|
int32(value) {
|
|
798
1011
|
if (typeof value !== "number" ||
|
|
799
1012
|
!Number.isInteger(value) ||
|
|
@@ -803,6 +1016,12 @@ const IdentifierValues = Object.freeze({
|
|
|
803
1016
|
}
|
|
804
1017
|
return value;
|
|
805
1018
|
},
|
|
1019
|
+
/**
|
|
1020
|
+
* Validates a signed 64-bit bigint identifier.
|
|
1021
|
+
*
|
|
1022
|
+
* @param value Candidate bigint identifier.
|
|
1023
|
+
* @returns Bigint within the signed 64-bit range.
|
|
1024
|
+
*/
|
|
806
1025
|
int64(value) {
|
|
807
1026
|
if (typeof value !== "bigint" || value < -(1n << 63n) || value >= 1n << 63n) {
|
|
808
1027
|
throw new RangeError("Identifier is outside the int64 range.");
|
|
@@ -839,31 +1058,52 @@ function unpackIdentifier(type, value) {
|
|
|
839
1058
|
return AnyMessages.unpack(value, Int64ValueSchema)?.value;
|
|
840
1059
|
}
|
|
841
1060
|
}
|
|
1061
|
+
function freshSignalId() {
|
|
1062
|
+
const crypto = Reflect.get(globalThis, "crypto");
|
|
1063
|
+
if (crypto === undefined)
|
|
1064
|
+
throw new Error("Secure random crypto is unavailable for signal IDs.");
|
|
1065
|
+
if (typeof crypto.randomUUID === "function")
|
|
1066
|
+
return crypto.randomUUID();
|
|
1067
|
+
if (typeof crypto.getRandomValues !== "function")
|
|
1068
|
+
throw new Error("Secure random crypto is unavailable for signal IDs.");
|
|
1069
|
+
const bytes = new Uint8Array(16);
|
|
1070
|
+
crypto.getRandomValues(bytes);
|
|
1071
|
+
const version = bytes.at(6);
|
|
1072
|
+
const variant = bytes.at(8);
|
|
1073
|
+
if (version === undefined || variant === undefined)
|
|
1074
|
+
throw new Error("Secure random crypto is unavailable for signal IDs.");
|
|
1075
|
+
bytes[6] = (version & 0x0f) | 0x40;
|
|
1076
|
+
bytes[8] = (variant & 0x3f) | 0x80;
|
|
1077
|
+
const hex = [...bytes].map((value) => value.toString(16).padStart(2, "0")).join("");
|
|
1078
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
1079
|
+
}
|
|
842
1080
|
/**
|
|
843
1081
|
* Creates generated Spine command and event envelopes.
|
|
844
1082
|
*/
|
|
845
1083
|
export const SignalEnvelopes = {
|
|
846
1084
|
// prettier-ignore
|
|
847
1085
|
/**
|
|
848
|
-
* Packs a generated Spine command envelope
|
|
1086
|
+
* Packs a generated Spine command envelope with a fresh secure ID.
|
|
1087
|
+
* @typeParam Schema Generated schema of the domain command.
|
|
849
1088
|
* @param input The command envelope input.
|
|
850
1089
|
* @returns The packed command.
|
|
851
1090
|
*/
|
|
852
1091
|
command(input) {
|
|
853
1092
|
return create(CommandSchema, {
|
|
854
|
-
id:
|
|
1093
|
+
id: create(CommandIdSchema, { uuid: freshSignalId() }),
|
|
855
1094
|
message: AnyMessages.pack(input.schema, input.message, input),
|
|
856
1095
|
context: clone(CommandContextSchema, input.context),
|
|
857
1096
|
});
|
|
858
1097
|
},
|
|
859
1098
|
/**
|
|
860
|
-
* Packs a generated Spine event envelope
|
|
1099
|
+
* Packs a generated Spine event envelope with a fresh secure ID.
|
|
1100
|
+
* @typeParam Schema Generated schema of the domain event.
|
|
861
1101
|
* @param input The event envelope input.
|
|
862
1102
|
* @returns The packed event.
|
|
863
1103
|
*/
|
|
864
1104
|
event(input) {
|
|
865
1105
|
return create(EventSchema, {
|
|
866
|
-
id:
|
|
1106
|
+
id: create(EventIdSchema, { value: freshSignalId() }),
|
|
867
1107
|
message: AnyMessages.pack(input.schema, input.message, input),
|
|
868
1108
|
context: clone(EventContextSchema, input.context),
|
|
869
1109
|
});
|
|
@@ -941,6 +1181,7 @@ export class TypeRegistry {
|
|
|
941
1181
|
}
|
|
942
1182
|
/**
|
|
943
1183
|
* Registers one schema and returns its immutable metadata.
|
|
1184
|
+
* @typeParam Schema Generated schema to register.
|
|
944
1185
|
* @param schema The generated message schema.
|
|
945
1186
|
* @param options Optional explicit type URL.
|
|
946
1187
|
* @returns The registered schema metadata.
|
|
@@ -992,6 +1233,7 @@ export class TypeRegistry {
|
|
|
992
1233
|
}
|
|
993
1234
|
/**
|
|
994
1235
|
* Finds metadata by generated schema identity.
|
|
1236
|
+
* @typeParam Schema Generated schema used as the lookup key.
|
|
995
1237
|
* @param schema The generated message schema.
|
|
996
1238
|
* @returns Matching metadata, if registered.
|
|
997
1239
|
*/
|
|
@@ -1024,6 +1266,7 @@ export class TypeRegistry {
|
|
|
1024
1266
|
}
|
|
1025
1267
|
/**
|
|
1026
1268
|
* Gets metadata by generated schema identity or throws a descriptive error.
|
|
1269
|
+
* @typeParam Schema Generated schema used as the lookup key.
|
|
1027
1270
|
* @param schema The generated message schema.
|
|
1028
1271
|
* @returns The registered metadata.
|
|
1029
1272
|
*/
|
|
@@ -1046,6 +1289,12 @@ const RegistryLookups = {
|
|
|
1046
1289
|
// prettier-ignore
|
|
1047
1290
|
/**
|
|
1048
1291
|
* Composes modules in deterministic dependency-first order.
|
|
1292
|
+
*
|
|
1293
|
+
* @param root Module whose dependency graph is traversed.
|
|
1294
|
+
* @param definitions Seen module definitions keyed by name.
|
|
1295
|
+
* @param visiting Names on the current dependency path for cycle detection.
|
|
1296
|
+
* @param verified Module objects already checked and appended.
|
|
1297
|
+
* @param schemas Output list of schemas in dependency-first order.
|
|
1049
1298
|
*/
|
|
1050
1299
|
compose(root, definitions, visiting, verified, schemas) {
|
|
1051
1300
|
const frames = [{ module: root, appendSchemas: false }];
|
|
@@ -1088,6 +1337,10 @@ const RegistryLookups = {
|
|
|
1088
1337
|
},
|
|
1089
1338
|
/**
|
|
1090
1339
|
* Compares two module definitions for same-name conflicts.
|
|
1340
|
+
*
|
|
1341
|
+
* @param left Previously seen module definition.
|
|
1342
|
+
* @param right Candidate definition with the same name.
|
|
1343
|
+
* @returns True when names, schemas, and dependency names agree.
|
|
1091
1344
|
*/
|
|
1092
1345
|
sameModule(left, right) {
|
|
1093
1346
|
if (left === right) {
|
|
@@ -1103,6 +1356,11 @@ const RegistryLookups = {
|
|
|
1103
1356
|
},
|
|
1104
1357
|
/**
|
|
1105
1358
|
* Creates immutable descriptor-backed schema metadata.
|
|
1359
|
+
*
|
|
1360
|
+
* @typeParam Schema Generated schema represented by the metadata.
|
|
1361
|
+
* @param schema Generated message schema being registered.
|
|
1362
|
+
* @param typeUrl Canonical URL assigned to the schema.
|
|
1363
|
+
* @returns Frozen descriptor-backed metadata.
|
|
1106
1364
|
*/
|
|
1107
1365
|
metadata(schema, typeUrl) {
|
|
1108
1366
|
const firstField = schema.fields[0];
|
|
@@ -1116,9 +1374,23 @@ const RegistryLookups = {
|
|
|
1116
1374
|
typeUrlPrefix: typeUrl.slice(0, typeUrl.length - schema.typeName.length - 1),
|
|
1117
1375
|
firstField,
|
|
1118
1376
|
firstFieldName: firstField?.name,
|
|
1377
|
+
/**
|
|
1378
|
+
* Checks whether the schema file declares a given option.
|
|
1379
|
+
*
|
|
1380
|
+
* @typeParam Value Value type declared by the extension.
|
|
1381
|
+
* @param option File-option extension to test.
|
|
1382
|
+
* @returns True when the option is present.
|
|
1383
|
+
*/
|
|
1119
1384
|
hasFileOption(option) {
|
|
1120
1385
|
return hasOption(schema.file, option);
|
|
1121
1386
|
},
|
|
1387
|
+
/**
|
|
1388
|
+
* Reads a declared option from the schema file.
|
|
1389
|
+
*
|
|
1390
|
+
* @typeParam Value Value type declared by the extension.
|
|
1391
|
+
* @param option File-option extension to read.
|
|
1392
|
+
* @returns Decoded option value.
|
|
1393
|
+
*/
|
|
1122
1394
|
getFileOption(option) {
|
|
1123
1395
|
return getOption(schema.file, option);
|
|
1124
1396
|
},
|
|
@@ -1126,15 +1398,36 @@ const RegistryLookups = {
|
|
|
1126
1398
|
},
|
|
1127
1399
|
/**
|
|
1128
1400
|
* Creates an immutable registry lookup view.
|
|
1401
|
+
*
|
|
1402
|
+
* @param registry Mutable registry exposed through read-only operations.
|
|
1403
|
+
* @returns Frozen lookup facade.
|
|
1129
1404
|
*/
|
|
1130
1405
|
lookup(registry) {
|
|
1131
1406
|
return Object.freeze({
|
|
1132
1407
|
findByFullName: (fullTypeName) => registry.findByFullName(fullTypeName),
|
|
1133
1408
|
findByTypeUrl: (typeUrl) => registry.findByTypeUrl(typeUrl),
|
|
1134
|
-
|
|
1409
|
+
/**
|
|
1410
|
+
* Finds registered metadata by generated schema identity.
|
|
1411
|
+
*
|
|
1412
|
+
* @typeParam Schema Generated schema used as the lookup key.
|
|
1413
|
+
* @param schema Generated schema to find.
|
|
1414
|
+
* @returns Matching metadata, if registered.
|
|
1415
|
+
*/
|
|
1416
|
+
findBySchema(schema) {
|
|
1417
|
+
return registry.findBySchema(schema);
|
|
1418
|
+
},
|
|
1135
1419
|
getByFullName: (fullTypeName) => registry.getByFullName(fullTypeName),
|
|
1136
1420
|
getByTypeUrl: (typeUrl) => registry.getByTypeUrl(typeUrl),
|
|
1137
|
-
|
|
1421
|
+
/**
|
|
1422
|
+
* Gets registered metadata by generated schema identity.
|
|
1423
|
+
*
|
|
1424
|
+
* @typeParam Schema Generated schema used as the lookup key.
|
|
1425
|
+
* @param schema Generated schema to require.
|
|
1426
|
+
* @returns Registered metadata.
|
|
1427
|
+
*/
|
|
1428
|
+
getBySchema(schema) {
|
|
1429
|
+
return registry.getBySchema(schema);
|
|
1430
|
+
},
|
|
1138
1431
|
list: () => registry.list(),
|
|
1139
1432
|
});
|
|
1140
1433
|
},
|
|
@@ -1147,21 +1440,46 @@ export const spineCoreRegistry = RegistryLookups.lookup(TypeRegistry.spineCore()
|
|
|
1147
1440
|
* Constructs and sanitizes internal message-validation results.
|
|
1148
1441
|
*/
|
|
1149
1442
|
const ValidationResults = {
|
|
1443
|
+
/**
|
|
1444
|
+
* Builds a structured validation result from sanitized violations.
|
|
1445
|
+
*
|
|
1446
|
+
* @param violations Sanitized constraint violations.
|
|
1447
|
+
* @returns Valid result when empty, otherwise an error with violations.
|
|
1448
|
+
*/
|
|
1150
1449
|
from(violations) {
|
|
1151
1450
|
if (violations.length === 0)
|
|
1152
1451
|
return { valid: true, violations: EMPTY_VIOLATIONS, error: undefined };
|
|
1153
1452
|
const nonEmpty = violations;
|
|
1154
1453
|
return { valid: false, violations: nonEmpty, error: ValidationResults.error(nonEmpty) };
|
|
1155
1454
|
},
|
|
1455
|
+
/**
|
|
1456
|
+
* Packs constraint violations into a generated validation error.
|
|
1457
|
+
*
|
|
1458
|
+
* @param violations Violations to include in the error.
|
|
1459
|
+
* @returns Generated validation error message.
|
|
1460
|
+
*/
|
|
1156
1461
|
error(violations) {
|
|
1157
1462
|
return create(ValidationErrorSchema, { constraintViolation: [...violations] });
|
|
1158
1463
|
},
|
|
1464
|
+
/**
|
|
1465
|
+
* Creates a runtime-failure violation without exposing the caught error.
|
|
1466
|
+
*
|
|
1467
|
+
* @param typeName Protobuf type being validated.
|
|
1468
|
+
* @param message Stable public failure text.
|
|
1469
|
+
* @returns Generated constraint violation.
|
|
1470
|
+
*/
|
|
1159
1471
|
failure(typeName, message) {
|
|
1160
1472
|
return create(ConstraintViolationSchema, {
|
|
1161
1473
|
typeName,
|
|
1162
1474
|
message: create(TemplateStringSchema, { withPlaceholders: message }),
|
|
1163
1475
|
});
|
|
1164
1476
|
},
|
|
1477
|
+
/**
|
|
1478
|
+
* Copies a violation while redacting placeholder values.
|
|
1479
|
+
*
|
|
1480
|
+
* @param violation Violation supplied by a validation rule.
|
|
1481
|
+
* @returns Sanitized generated constraint violation.
|
|
1482
|
+
*/
|
|
1165
1483
|
violation(violation) {
|
|
1166
1484
|
return create(ConstraintViolationSchema, {
|
|
1167
1485
|
message: violation.message === undefined
|
|
@@ -1176,6 +1494,12 @@ const ValidationResults = {
|
|
|
1176
1494
|
: create(FieldPathSchema, { fieldName: [...violation.fieldPath.fieldName] }),
|
|
1177
1495
|
});
|
|
1178
1496
|
},
|
|
1497
|
+
/**
|
|
1498
|
+
* Replaces every template placeholder value with stable redaction text.
|
|
1499
|
+
*
|
|
1500
|
+
* @param values Placeholder values to suppress.
|
|
1501
|
+
* @returns Placeholder keys mapped to redaction text.
|
|
1502
|
+
*/
|
|
1179
1503
|
redact(values) {
|
|
1180
1504
|
return Object.fromEntries(Object.keys(values ?? {}).map((key) => [key, REDACTED_VALIDATION_DETAIL]));
|
|
1181
1505
|
},
|