@cadenza.io/core 3.19.2 → 3.19.4

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.mjs CHANGED
@@ -1272,6 +1272,36 @@ var SignalBroker = class _SignalBroker {
1272
1272
  setVerbose(value) {
1273
1273
  this.verbose = value;
1274
1274
  }
1275
+ // Dor debugging
1276
+ logMemoryFootprint(label = "current") {
1277
+ console.log(`[${label}] SignalBroker state sizes:`);
1278
+ console.log(` \u2022 signalObservers entries: ${this.signalObservers.size}`);
1279
+ console.log(
1280
+ ` \u2022 emittedSignalsRegistry size: ${this.emittedSignalsRegistry.size}`
1281
+ );
1282
+ let totalSquashContexts = 0;
1283
+ let totalSquashGroups = 0;
1284
+ for (const groups of this.strategyData.values()) {
1285
+ totalSquashGroups += groups.size;
1286
+ for (const data of groups.values()) {
1287
+ totalSquashContexts += data.contexts.length;
1288
+ }
1289
+ }
1290
+ console.log(` \u2022 Active squash groups: ${totalSquashGroups}`);
1291
+ console.log(` \u2022 Total queued squash contexts: ${totalSquashContexts}`);
1292
+ let totalDebouncers = this.debouncedEmitters.size;
1293
+ console.log(` \u2022 Active debouncers: ${totalDebouncers}`);
1294
+ let totalThrottleQueues = 0;
1295
+ for (const q of this.throttleQueues.values()) {
1296
+ totalThrottleQueues += q.length;
1297
+ }
1298
+ console.log(` \u2022 Total items in throttle queues: ${totalThrottleQueues}`);
1299
+ let totalScheduled = 0;
1300
+ for (const bucket of this.scheduledBuckets.values()) {
1301
+ totalScheduled += bucket.length;
1302
+ }
1303
+ console.log(` \u2022 Pending scheduled items: ${totalScheduled}`);
1304
+ }
1275
1305
  /**
1276
1306
  * Validates the provided signal name string to ensure it adheres to specific formatting rules.
1277
1307
  * Throws an error if any of the validation checks fail.
@@ -1467,7 +1497,8 @@ var SignalBroker = class _SignalBroker {
1467
1497
  delay = options.exactDateTime.getTime() - Date.now();
1468
1498
  }
1469
1499
  delay = Math.max(0, delay);
1470
- const bucketKey = Math.ceil(delay / 100) * 100;
1500
+ const dueAt = Date.now() + delay;
1501
+ const bucketKey = Math.ceil(dueAt / 100) * 100;
1471
1502
  let bucket = this.scheduledBuckets.get(bucketKey);
1472
1503
  if (!bucket) {
1473
1504
  bucket = [];
@@ -3572,9 +3603,9 @@ var Task = class _Task extends SignalEmitter {
3572
3603
  * @param {boolean} [isSubMeta=false] - Indicates if the task is a sub-meta-task.
3573
3604
  * @param {boolean} [isHidden=false] - Determines if the task is hidden and not exposed publicly.
3574
3605
  * @param {ThrottleTagGetter} [getTagCallback=undefined] - A callback to generate a throttle tag for the task.
3575
- * @param {SchemaDefinition} [inputSchema=undefined] - The input schema for validating the task's input context.
3606
+ * @param {Schema} [inputSchema=undefined] - The input schema for validating the task's input context.
3576
3607
  * @param {boolean} [validateInputContext=false] - Specifies if the input context should be validated against the input schema.
3577
- * @param {SchemaDefinition} [outputSchema=undefined] - The output schema for validating the task's output context.
3608
+ * @param {Schema} [outputSchema=undefined] - The output schema for validating the task's output context.
3578
3609
  * @param {boolean} [validateOutputContext=false] - Specifies if the output context should be validated against the output schema.
3579
3610
  * @param {number} [retryCount=0] - The number of retry attempts allowed for the task in case of failure.
3580
3611
  * @param {number} [retryDelay=0] - The initial delay (in milliseconds) between retry attempts.
@@ -3819,14 +3850,27 @@ var Task = class _Task extends SignalEmitter {
3819
3850
  * Validates a data object against a specified schema definition and returns validation results.
3820
3851
  *
3821
3852
  * @param {any} data - The target object to validate against the schema.
3822
- * @param {SchemaDefinition | undefined} schema - The schema definition describing the expected structure and constraints of the data.
3853
+ * @param {Schema | undefined} schema - The schema definition describing the expected structure and constraints of the data.
3823
3854
  * @param {string} [path="context"] - The base path or context for traversing the data, used in generating error messages.
3824
3855
  * @return {{ valid: boolean, errors: Record<string, string> }} - An object containing a validity flag (`valid`)
3825
3856
  * and a map (`errors`) of validation error messages keyed by property paths.
3826
3857
  */
3827
3858
  validateSchema(data, schema, path = "context") {
3828
3859
  const errors = {};
3829
- if (!schema || typeof schema !== "object") return { valid: true, errors };
3860
+ if (!schema || typeof schema !== "object" && !Array.isArray(schema))
3861
+ return { valid: true, errors };
3862
+ if (Array.isArray(schema)) {
3863
+ for (const s of schema) {
3864
+ const subValidation = this.validateSchema(data, s, path);
3865
+ if (!subValidation.valid) {
3866
+ Object.assign(errors, subValidation.errors);
3867
+ }
3868
+ if (subValidation.valid) {
3869
+ return { valid: true, errors: {} };
3870
+ }
3871
+ }
3872
+ return { valid: false, errors };
3873
+ }
3830
3874
  const required = schema.required || [];
3831
3875
  for (const key of required) {
3832
3876
  if (!(key in data)) {
@@ -3837,84 +3881,12 @@ var Task = class _Task extends SignalEmitter {
3837
3881
  for (const [key, value] of Object.entries(data)) {
3838
3882
  if (key in properties) {
3839
3883
  const prop = properties[key];
3840
- const propType = prop.type;
3841
- if (propType === "any") {
3842
- continue;
3843
- }
3844
- if ((value === void 0 || value === null) && !prop.strict) {
3845
- continue;
3846
- }
3847
- if (propType === "string" && typeof value !== "string") {
3848
- errors[`${path}.${key}`] = `Expected 'string' for '${key}', got '${typeof value}'`;
3849
- } else if (propType === "number" && typeof value !== "number") {
3850
- errors[`${path}.${key}`] = `Expected 'number' for '${key}', got '${typeof value}'`;
3851
- } else if (propType === "boolean" && typeof value !== "boolean") {
3852
- errors[`${path}.${key}`] = `Expected 'boolean' for '${key}', got '${typeof value}'`;
3853
- } else if (propType === "array" && !Array.isArray(value)) {
3854
- errors[`${path}.${key}`] = `Expected 'array' for '${key}', got '${typeof value}'`;
3855
- } else if (propType === "object" && (typeof value !== "object" || value === null || Array.isArray(value))) {
3856
- errors[`${path}.${key}`] = `Expected 'object' for '${key}', got '${typeof value}'`;
3857
- } else if (propType === "array" && prop.items) {
3858
- if (Array.isArray(value)) {
3859
- value.forEach((item, index) => {
3860
- const subValidation = this.validateSchema(
3861
- item,
3862
- prop.items,
3863
- `${path}.${key}[${index}]`
3864
- );
3865
- if (!subValidation.valid) {
3866
- Object.assign(errors, subValidation.errors);
3867
- }
3868
- });
3869
- }
3870
- } else if (propType === "object" && !Array.isArray(value) && value !== null) {
3871
- const subValidation = this.validateSchema(
3872
- value,
3873
- prop,
3874
- `${path}.${key}`
3875
- );
3876
- if (!subValidation.valid) {
3877
- Object.assign(errors, subValidation.errors);
3878
- }
3879
- }
3880
- const constraints = prop.constraints || {};
3881
- if (typeof value === "string") {
3882
- if (constraints.minLength && value.length < constraints.minLength) {
3883
- errors[`${path}.${key}`] = `String '${key}' shorter than minLength ${constraints.minLength}`;
3884
- }
3885
- if (constraints.maxLength && value.length > constraints.maxLength) {
3886
- errors[`${path}.${key}`] = `String '${key}' exceeds maxLength ${constraints.maxLength}`;
3887
- }
3888
- if (constraints.pattern && !new RegExp(constraints.pattern).test(value)) {
3889
- errors[`${path}.${key}`] = `String '${key}' does not match pattern ${constraints.pattern}`;
3890
- }
3891
- } else if (typeof value === "number") {
3892
- if (constraints.min && value < constraints.min) {
3893
- errors[`${path}.${key}`] = `Number '${key}' below min ${constraints.min}`;
3884
+ if (Array.isArray(prop)) {
3885
+ for (const p of prop) {
3886
+ Object.assign(errors, this.validateProp(p, key, value, path));
3894
3887
  }
3895
- if (constraints.max && value > constraints.max) {
3896
- errors[`${path}.${key}`] = `Number '${key}' exceeds max ${constraints.max}`;
3897
- }
3898
- if (constraints.multipleOf && value % constraints.multipleOf !== 0) {
3899
- errors[`${path}.${key}`] = `Number '${key}' not multiple of ${constraints.multipleOf}`;
3900
- }
3901
- } else if (constraints.enum && !constraints.enum.includes(value)) {
3902
- errors[`${path}.${key}`] = `Value '${value}' for '${key}' not in enum ${JSON.stringify(constraints.enum)}`;
3903
- } else if (constraints.format) {
3904
- const formats = {
3905
- email: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
3906
- url: /^(https?|ftp):\/\/[^\s/$.?#].[^\s]*$/,
3907
- "date-time": /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})?$/,
3908
- uuid: /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/,
3909
- custom: /.*/
3910
- // Placeholder; override with prop.constraints.pattern if present
3911
- };
3912
- const regex = formats[constraints.format] || new RegExp(constraints.pattern || ".*");
3913
- if (typeof value === "string" && !regex.test(value)) {
3914
- errors[`${path}.${key}`] = `Value '${value}' for '${key}' does not match format '${constraints.format}'`;
3915
- }
3916
- } else if (constraints.oneOf && !constraints.oneOf.includes(value)) {
3917
- errors[`${path}.${key}`] = `Value '${value}' for '${key}' not in oneOf ${JSON.stringify(constraints.oneOf)}`;
3888
+ } else {
3889
+ Object.assign(errors, this.validateProp(prop, key, value, path));
3918
3890
  }
3919
3891
  } else if (schema.strict) {
3920
3892
  errors[`${path}.${key}`] = `Key '${key}' is not allowed`;
@@ -3925,6 +3897,83 @@ var Task = class _Task extends SignalEmitter {
3925
3897
  }
3926
3898
  return { valid: true, errors: {} };
3927
3899
  }
3900
+ validateProp(prop, key, value, path = "context") {
3901
+ const propType = prop.type;
3902
+ const errors = {};
3903
+ if (propType === "any") {
3904
+ return errors;
3905
+ }
3906
+ if ((value === void 0 || value === null) && !prop.strict) {
3907
+ return errors;
3908
+ }
3909
+ if (propType === "string" && typeof value !== "string") {
3910
+ errors[`${path}.${key}`] = `Expected 'string' for '${key}', got '${typeof value}'`;
3911
+ } else if (propType === "number" && typeof value !== "number") {
3912
+ errors[`${path}.${key}`] = `Expected 'number' for '${key}', got '${typeof value}'`;
3913
+ } else if (propType === "boolean" && typeof value !== "boolean") {
3914
+ errors[`${path}.${key}`] = `Expected 'boolean' for '${key}', got '${typeof value}'`;
3915
+ } else if (propType === "array" && !Array.isArray(value)) {
3916
+ errors[`${path}.${key}`] = `Expected 'array' for '${key}', got '${typeof value}'`;
3917
+ } else if (propType === "object" && (typeof value !== "object" || value === null || Array.isArray(value))) {
3918
+ errors[`${path}.${key}`] = `Expected 'object' for '${key}', got '${typeof value}'`;
3919
+ } else if (propType === "array" && prop.items) {
3920
+ value.forEach((item, index) => {
3921
+ const subValidation = this.validateSchema(
3922
+ item,
3923
+ prop.items,
3924
+ `${path}.${key}[${index}]`
3925
+ );
3926
+ if (!subValidation.valid) {
3927
+ Object.assign(errors, subValidation.errors);
3928
+ }
3929
+ });
3930
+ } else if (propType === "object" && !Array.isArray(value) && value !== null) {
3931
+ const subValidation = this.validateSchema(value, prop, `${path}.${key}`);
3932
+ if (!subValidation.valid) {
3933
+ Object.assign(errors, subValidation.errors);
3934
+ }
3935
+ }
3936
+ const constraints = prop.constraints || {};
3937
+ if (typeof value === "string") {
3938
+ if (constraints.minLength && value.length < constraints.minLength) {
3939
+ errors[`${path}.${key}`] = `String '${key}' shorter than minLength ${constraints.minLength}`;
3940
+ }
3941
+ if (constraints.maxLength && value.length > constraints.maxLength) {
3942
+ errors[`${path}.${key}`] = `String '${key}' exceeds maxLength ${constraints.maxLength}`;
3943
+ }
3944
+ if (constraints.pattern && !new RegExp(constraints.pattern).test(value)) {
3945
+ errors[`${path}.${key}`] = `String '${key}' does not match pattern ${constraints.pattern}`;
3946
+ }
3947
+ } else if (typeof value === "number") {
3948
+ if (constraints.min && value < constraints.min) {
3949
+ errors[`${path}.${key}`] = `Number '${key}' below min ${constraints.min}`;
3950
+ }
3951
+ if (constraints.max && value > constraints.max) {
3952
+ errors[`${path}.${key}`] = `Number '${key}' exceeds max ${constraints.max}`;
3953
+ }
3954
+ if (constraints.multipleOf && value % constraints.multipleOf !== 0) {
3955
+ errors[`${path}.${key}`] = `Number '${key}' not multiple of ${constraints.multipleOf}`;
3956
+ }
3957
+ } else if (constraints.enum && !constraints.enum.includes(value)) {
3958
+ errors[`${path}.${key}`] = `Value '${value}' for '${key}' not in enum ${JSON.stringify(constraints.enum)}`;
3959
+ } else if (constraints.format) {
3960
+ const formats = {
3961
+ email: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
3962
+ url: /^(https?|ftp):\/\/[^\s/$.?#].[^\s]*$/,
3963
+ "date-time": /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})?$/,
3964
+ uuid: /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/,
3965
+ custom: /.*/
3966
+ // Placeholder; override with prop.constraints.pattern if present
3967
+ };
3968
+ const regex = formats[constraints.format] || new RegExp(constraints.pattern || ".*");
3969
+ if (typeof value === "string" && !regex.test(value)) {
3970
+ errors[`${path}.${key}`] = `Value '${value}' for '${key}' does not match format '${constraints.format}'`;
3971
+ }
3972
+ } else if (constraints.oneOf && !constraints.oneOf.includes(value)) {
3973
+ errors[`${path}.${key}`] = `Value '${value}' for '${key}' not in oneOf ${JSON.stringify(constraints.oneOf)}`;
3974
+ }
3975
+ return errors;
3976
+ }
3928
3977
  /**
3929
3978
  * Validates the input context against the predefined schema and emits metadata if validation fails.
3930
3979
  *
@@ -5967,8 +6016,11 @@ var Cadenza = class {
5967
6016
  static emit(event, data = {}, options = {}) {
5968
6017
  this.signalBroker?.emit(event, data, options);
5969
6018
  }
5970
- static schedule(taskName, context, delayMs, exactDateTime) {
5971
- this.signalBroker?.schedule(taskName, context, { delayMs, exactDateTime });
6019
+ static schedule(signalName, context, delayMs, exactDateTime) {
6020
+ this.signalBroker?.schedule(signalName, context, {
6021
+ delayMs,
6022
+ exactDateTime
6023
+ });
5972
6024
  }
5973
6025
  static interval(taskName, context, intervalMs, leading = false, startDateTime) {
5974
6026
  this.signalBroker?.interval(