From 369ffafd0e99e6a53402c7703ab6b59ef627fcd7 Mon Sep 17 00:00:00 2001 From: paulwer Date: Mon, 4 Nov 2024 14:17:35 +0100 Subject: [PATCH 01/56] feat: add class-validator support --- packages/framework/package.json | 26 ++- .../framework/src/client.validation.test.ts | 179 ++++++++++++++++++ packages/framework/src/types/schema.types.ts | 19 +- packages/framework/src/types/step.types.ts | 9 +- .../src/validators/base.validator.ts | 6 + .../validators/class-validator.validator.ts | 139 ++++++++++++++ .../src/validators/validator.test.ts | 58 +++++- .../framework/src/validators/zod.validator.ts | 3 +- 8 files changed, 424 insertions(+), 15 deletions(-) create mode 100644 packages/framework/src/validators/class-validator.validator.ts diff --git a/packages/framework/package.json b/packages/framework/package.json index 37845e8fc46..7cd8962a9e5 100644 --- a/packages/framework/package.json +++ b/packages/framework/package.json @@ -25,7 +25,7 @@ "next", "nuxt", "remix", - "sveltekit", + "sveltekit", "README.md" ], "scripts": { @@ -170,9 +170,13 @@ "@sveltejs/kit": ">=1.27.3", "@vercel/node": ">=2.15.9", "aws-lambda": ">=1.0.7", + "class-transformer": ">=0.5.1", + "class-validator": ">=0.14.0", + "class-validator-jsonschema": ">=5.0.0", "express": ">=4.19.2", "h3": ">=1.8.1", "next": ">=12.0.0", + "reflect-metadata": ">=0.2.2", "zod": ">=3.0.0", "zod-to-json-schema": ">=3.0.0" }, @@ -201,6 +205,18 @@ "next": { "optional": true }, + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + }, + "class-validator-jsonschema": { + "optional": true + }, + "reflect-metadata": { + "optional": true + }, "zod": { "optional": true }, @@ -219,11 +235,15 @@ "@types/sanitize-html": "2.11.0", "@vercel/node": "^2.15.9", "aws-lambda": "^1.0.7", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.1", + "class-validator-jsonschema": "^5.0.1", "express": "^4.19.2", "h3": "^1.11.1", "madge": "^8.0.0", "next": "^13.5.4", "prettier": "^3.2.5", + "reflect-metadata": "^0.2.2", "ts-node": "^10.9.2", "tsup": "^8.0.2", "tsx": "4.16.2", @@ -244,6 +264,8 @@ "sanitize-html": "^2.13.0" }, "nx": { - "tags": ["package:public"] + "tags": [ + "package:public" + ] } } diff --git a/packages/framework/src/client.validation.test.ts b/packages/framework/src/client.validation.test.ts index 141e1234a62..d88d628e8ef 100644 --- a/packages/framework/src/client.validation.test.ts +++ b/packages/framework/src/client.validation.test.ts @@ -1,6 +1,7 @@ /* eslint-disable no-param-reassign */ import { expect, it, describe, beforeEach } from 'vitest'; import { z } from 'zod'; +import { IsNumber, IsOptional, IsString } from 'class-validator'; import { Client } from './client'; import { workflow } from './resources/workflow'; import { ExecutionStateControlsInvalidError } from './errors'; @@ -187,6 +188,184 @@ describe('validation', () => { }); }); + describe('class-validator', () => { + class ClassValidatorSchema { + @IsString() + @IsOptional() + foo?: string; + @IsNumber() + @IsOptional() + baz?: number; + } + + it('should infer types in the step controls', async () => { + workflow('class-validator-validation', async ({ step }) => { + await step.email( + 'class-validator-validation', + async (controls) => { + // @ts-expect-error - Type 'number' is not assignable to type 'string'. + controls.foo = 123; + // @ts-expect-error - Type 'string' is not assignable to type 'number'. + controls.baz = '123'; + + return { + subject: 'Test subject', + body: 'Test body', + }; + }, + { + controlSchema: ClassValidatorSchema, + skip: (controls) => { + // @ts-expect-error - Type 'number' is not assignable to type 'string'. + controls.foo = 123; + // @ts-expect-error - Type 'string' is not assignable to type 'number'. + controls.baz = '123'; + + return true; + }, + providers: { + sendgrid: async ({ controls, outputs }) => { + // @ts-expect-error - Type 'number' is not assignable to type 'string'. + controls.foo = 123; + // @ts-expect-error - Type 'string' is not assignable to type 'number'. + controls.baz = '123'; + + // @ts-expect-error - Type 'number' is not assignable to type 'string'. + outputs.body = 123; + // @ts-expect-error - Type 'number' is not assignable to type 'string'. + outputs.subject = 123; + + return { + ipPoolName: 'test', + }; + }, + }, + } + ); + }); + }); + + it('should infer types in the workflow payload', async () => { + workflow( + 'class-validator-validation', + async ({ step, payload }) => { + await step.email('class-validator-validation', async () => { + // @ts-expect-error - Type 'number' is not assignable to type 'string'. + payload.foo = 123; + // @ts-expect-error - Type 'string' is not assignable to type 'number'. + payload.baz = '123'; + + return { + subject: 'Test subject', + body: 'Test body', + }; + }); + }, + { + payloadSchema: ClassValidatorSchema, + } + ); + }); + + it('should infer types in the workflow controls', async () => { + workflow( + 'class-validator-validation', + async ({ step, controls }) => { + await step.email('class-validator-validation', async () => { + // @ts-expect-error - Type 'number' is not assignable to type 'string'. + controls.foo = 123; + // @ts-expect-error - Type 'string' is not assignable to type 'number'. + controls.baz = '123'; + + return { + subject: 'Test subject', + body: 'Test body', + }; + }); + }, + { + controlSchema: ClassValidatorSchema, + } + ); + }); + + it('should transform a class-validator schema to a json schema during discovery', async () => { + client.addWorkflows([ + workflow('class-validator-validation', async ({ step }) => { + await step.email( + 'class-validator-validation', + async () => ({ + subject: 'Test subject', + body: 'Test body', + }), + { + controlSchema: ClassValidatorSchema, + } + ); + }), + ]); + + const discoverResult = client.discover(); + const stepControlSchema = discoverResult.workflows[0].steps[0].controls.schema; + + expect(stepControlSchema).to.deep.include({ + additionalProperties: false, + properties: { + foo: { + type: 'string', + }, + baz: { + type: 'number', + }, + }, + required: ['foo', 'baz'], + type: 'object', + }); + }); + + it('should throw an error if a property is missing', async () => { + client.addWorkflows([ + workflow('class-validator-validation', async ({ step }) => { + await step.email( + 'test-email', + async () => ({ + subject: 'Test subject', + body: 'Test body', + }), + { + controlSchema: ClassValidatorSchema, + } + ); + }), + ]); + + try { + await client.executeWorkflow({ + action: PostActionEnum.EXECUTE, + workflowId: 'class-validator-validation', + controls: { + foo: '341', + }, + payload: {}, + stepId: 'test-email', + state: [], + subscriber: {}, + }); + } catch (error) { + expect(error).to.be.instanceOf(ExecutionStateControlsInvalidError); + expect((error as ExecutionStateControlsInvalidError).message).to.equal( + 'Workflow with id: `class-validator-validation` has an invalid state. Step with id: `test-email` has invalid `controls`. Please provide the correct step controls.' + ); + expect((error as ExecutionStateControlsInvalidError).data).to.deep.equal([ + { + message: 'Required', + path: '/baz', + }, + ]); + } + }); + }); + describe('json-schema', () => { const jsonSchema = { type: 'object', diff --git a/packages/framework/src/types/schema.types.ts b/packages/framework/src/types/schema.types.ts index 2aa817aa8a0..c75e60a7237 100644 --- a/packages/framework/src/types/schema.types.ts +++ b/packages/framework/src/types/schema.types.ts @@ -3,6 +3,9 @@ import zod from 'zod'; export type JsonSchema = JSONSchema; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type ClassType = new (...args: any[]) => T; + /** * A schema used to validate a JSON object. * @@ -10,7 +13,7 @@ export type JsonSchema = JSONSchema; * - JSONSchema * - ZodSchema */ -export type Schema = JsonSchema | zod.ZodSchema; +export type Schema = JsonSchema | zod.ZodSchema | ClassType; /** * Infer the type of a Schema for unvalidated data. @@ -36,8 +39,11 @@ export type FromSchemaUnvalidated = : // ZodSchema T extends zod.ZodSchema ? zod.input - : // All schema types exhausted. - never; + : // ClassValidatorSchema + T extends ClassType + ? U + : // All schema types exhausted. + never; /** * Infer the type of a Schema for validated data. @@ -63,5 +69,8 @@ export type FromSchema = : // ZodSchema T extends zod.ZodSchema ? zod.infer - : // All schema types exhausted. - never; + : // ClassValidatorSchema + T extends ClassType + ? U + : // All schema types exhausted. + never; diff --git a/packages/framework/src/types/step.types.ts b/packages/framework/src/types/step.types.ts index 9bbb423285a..e6f073ee57f 100644 --- a/packages/framework/src/types/step.types.ts +++ b/packages/framework/src/types/step.types.ts @@ -64,7 +64,8 @@ export type ActionStep< /** * The controls for the step. */ - T_Controls extends Record = FromSchema, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + T_Controls extends Record = FromSchema, >( /** * The name of the step. This is used to identify the step in the workflow. @@ -94,7 +95,8 @@ export type CustomStep = < /** * The controls for the step. */ - T_Controls extends Record = FromSchema, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + T_Controls extends Record = FromSchema, /* * These intermediary types are needed to capture the types in a single type instance * to stop Typescript from erroring with: @@ -153,7 +155,8 @@ export type ChannelStep< /** * The controls for the step. */ - T_Controls extends Record = FromSchema, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + T_Controls extends Record = FromSchema, >( /** * The name of the step. This is used to identify the step in the workflow. diff --git a/packages/framework/src/validators/base.validator.ts b/packages/framework/src/validators/base.validator.ts index 4ac5e959e60..50d5e23f9cc 100644 --- a/packages/framework/src/validators/base.validator.ts +++ b/packages/framework/src/validators/base.validator.ts @@ -2,8 +2,10 @@ import type { FromSchema, FromSchemaUnvalidated, JsonSchema, Schema } from '../t import type { ValidateResult } from '../types/validator.types'; import { JsonSchemaValidator } from './json-schema.validator'; import { ZodValidator } from './zod.validator'; +import { ClassValidatorValidator } from './class-validator.validator'; const zodValidator = new ZodValidator(); +const classValidatorValidator = new ClassValidatorValidator(); const jsonSchemaValidator = new JsonSchemaValidator(); export const validateData = async < @@ -16,6 +18,8 @@ export const validateData = async < ): Promise> => { if (zodValidator.canHandle(schema)) { return zodValidator.validate(data, schema); + } else if (classValidatorValidator.canHandle(schema)) { + return classValidatorValidator.validate(data, schema); } else if (jsonSchemaValidator.canHandle(schema)) { return jsonSchemaValidator.validate(data, schema); } @@ -26,6 +30,8 @@ export const validateData = async < export const transformSchema = (schema: Schema): JsonSchema => { if (zodValidator.canHandle(schema)) { return zodValidator.transformToJsonSchema(schema); + } else if (classValidatorValidator.canHandle(schema)) { + return classValidatorValidator.transformToJsonSchema(schema); } else if (jsonSchemaValidator.canHandle(schema)) { return jsonSchemaValidator.transformToJsonSchema(schema); } diff --git a/packages/framework/src/validators/class-validator.validator.ts b/packages/framework/src/validators/class-validator.validator.ts new file mode 100644 index 00000000000..19c85a49208 --- /dev/null +++ b/packages/framework/src/validators/class-validator.validator.ts @@ -0,0 +1,139 @@ +import { ValidationError } from 'class-validator'; +import type { ClassType, FromSchema, FromSchemaUnvalidated, JsonSchema, Schema } from '../types/schema.types'; +import type { ValidateResult, Validator } from '../types/validator.types'; + +// Function to recursively add `additionalProperties: false` to the schema +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function replaceSchemaRefs(schema: any, schemas: any): JsonSchema { + if (schema && typeof schema === 'object' && schema?.$ref) { + // eslint-disable-next-line no-param-reassign + schema = schemas[schema.$ref.split('/').at(-1)]; + } + + if (schema && typeof schema === 'object') + for (const key in schema) { + if (schema.hasOwnProperty(key)) { + // eslint-disable-next-line no-param-reassign + schema[key] = replaceSchemaRefs(schema[key], schemas); + } + } + + return schema; +} +// Function to recursively add `additionalProperties: false` to the schema +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function addAdditionalPropertiesFalse(schema: any): JsonSchema { + if (schema && typeof schema === 'object' && schema?.type === 'object') { + // eslint-disable-next-line no-param-reassign + schema.additionalProperties = false; + } + + if (schema.properties) { + for (const key in schema.properties) { + if (schema.properties.hasOwnProperty(key)) { + addAdditionalPropertiesFalse(schema.properties[key]); + } + } + } + + return schema; +} +function formatErrors(errors: ValidationError[], parentPath = ''): { path: string; message: string }[] { + return errors.flatMap((err) => { + const currentPath = `${parentPath}/${err.property}`.replace(/\/+/g, '/'); + + if (err.children && err.children.length > 0) { + // Recursively format the children + return formatErrors(err.children, currentPath); + } else { + // Base case: no children, return the formatted error + return { + path: currentPath, + message: Object.values(err.constraints || {}).join(', '), + }; + } + }); +} + +export class ClassValidatorValidator implements Validator { + canHandle(schema: Schema): schema is ClassType { + return typeof (schema as ClassType) === 'function'; + } + + async validate< + T_Schema extends ClassType = ClassType, + T_Unvalidated = FromSchemaUnvalidated, + T_Validated = FromSchema, + >(data: T_Unvalidated, schema: T_Schema): Promise> { + try { + // eslint-disable-next-line global-require + require('reflect-metadata') as typeof import('reflect-metadata'); + // eslint-disable-next-line global-require + const { plainToInstance, instanceToPlain } = require('class-transformer') as typeof import('class-transformer'); + // eslint-disable-next-line global-require + const { validate } = require('class-validator') as typeof import('class-validator'); + + // Convert plain data to an instance of the schema class + const instance = plainToInstance(schema, data); + + // Validate the instance + const errors = await validate(instance as object, { whitelist: true }); + + // if undefined, then something went wrong + if (!instance && !!data) throw new Error('Failed to convert data to an instance of the schema class'); + + if (errors.length === 0) { + return { success: true, data: instanceToPlain(instance) as T_Validated }; + } else { + return { + success: false, + errors: formatErrors(errors), + }; + } + } catch (error) { + if ((error as Error)?.message?.includes('Cannot find module')) { + throw new Error( + 'Tried to use a class-validator schema in @novu/framework without `class-validator`, `class-transformer` or `reflect-metadata` installed. ' + + 'Please install it by running `npm install class-validator class-transformer reflect-metadata`.' + ); + } + throw error; + } + } + + transformToJsonSchema(schema: ClassType): JsonSchema { + try { + // eslint-disable-next-line global-require + const { defaultMetadataStorage } = require('class-transformer/cjs/storage'); + // eslint-disable-next-line global-require + const { getMetadataStorage } = require('class-validator') as typeof import('class-validator'); + // eslint-disable-next-line global-require, prettier/prettier + const { targetConstructorToSchema, validationMetadatasToSchemas } = + require('class-validator-jsonschema') as typeof import('class-validator-jsonschema'); + + const schemas = validationMetadatasToSchemas({ + classValidatorMetadataStorage: getMetadataStorage(), + classTransformerMetadataStorage: defaultMetadataStorage, + }); + + return addAdditionalPropertiesFalse( + replaceSchemaRefs( + targetConstructorToSchema(schema, { + classValidatorMetadataStorage: getMetadataStorage(), + classTransformerMetadataStorage: defaultMetadataStorage, + }), + schemas + ) + ); + } catch (error) { + if ((error as Error)?.message?.includes('Cannot find module')) { + // eslint-disable-next-line no-console + console.error( + 'Tried to use a class-validator schema in @novu/framework without `class-validator-jsonschema` installed. ' + + 'Please install it by running `npm install class-validator-jsonschema`.' + ); + } + throw error; + } + } +} diff --git a/packages/framework/src/validators/validator.test.ts b/packages/framework/src/validators/validator.test.ts index 62ae56876e7..95fd6bce491 100644 --- a/packages/framework/src/validators/validator.test.ts +++ b/packages/framework/src/validators/validator.test.ts @@ -1,9 +1,37 @@ import { describe, it, expect } from 'vitest'; import { ZodSchema, z } from 'zod'; +import { IsNumber, IsOptional, IsString, ValidateNested } from 'class-validator'; +import { Type } from 'class-transformer'; import { validateData, transformSchema } from './base.validator'; -import { JsonSchema, Schema } from '../types/schema.types'; +import { ClassType, JsonSchema, Schema } from '../types/schema.types'; +import 'reflect-metadata'; -const schemas = ['zod', 'json'] as const; +const schemas = ['zod', 'class', 'json'] as const; + +// Definitions of class-validator schemas +class SimpleStringSchema { + @IsString() + @IsOptional() + name?: string; +} +class NestedChildrenSchema { + @IsNumber() + age!: number; +} +class NestedSchema { + @IsString() + name!: string; + + @ValidateNested() + @Type(() => NestedChildrenSchema) + nested!: NestedChildrenSchema; +} +class SimpleStringAndNumberSchema { + @IsString() + name!: string; + @IsNumber() + age!: number; +} describe('validators', () => { describe('validateData', () => { @@ -11,6 +39,7 @@ describe('validators', () => { title: string; schemas: { zod: ZodSchema | null; + class: ClassType | null; json: JsonSchema; }; payload: Record; @@ -19,6 +48,7 @@ describe('validators', () => { data?: Record; errors?: { zod: { message: string; path: string }[] | null; + class: { message: string; path: string }[] | null; json: { message: string; path: string }[]; }; }; @@ -28,6 +58,7 @@ describe('validators', () => { title: 'should successfully validate data', schemas: { zod: z.object({ name: z.string() }), + class: SimpleStringSchema, json: { type: 'object', properties: { name: { type: 'string' } } } as const, }, payload: { name: 'John' }, @@ -40,6 +71,7 @@ describe('validators', () => { title: 'should remove additional properties and successfully validate', schemas: { zod: z.object({ name: z.string() }), + class: SimpleStringSchema, json: { type: 'object', properties: { name: { type: 'string' } }, additionalProperties: false } as const, }, payload: { name: 'John', age: 30 }, @@ -52,6 +84,7 @@ describe('validators', () => { title: 'should return errors when given invalid types', schemas: { zod: z.object({ name: z.string() }), + class: SimpleStringSchema, json: { type: 'object', properties: { name: { type: 'string' } } } as const, }, payload: { name: 123 }, @@ -60,6 +93,7 @@ describe('validators', () => { errors: { // TODO: error normalization json: [{ message: 'must be string', path: '/name' }], + class: [{ message: 'name must be a string', path: '/name' }], zod: [{ message: 'Expected string, received number', path: '/name' }], }, }, @@ -68,6 +102,7 @@ describe('validators', () => { title: 'should validate nested properties successfully', schemas: { zod: z.object({ name: z.string(), nested: z.object({ age: z.number() }) }), + class: NestedSchema, json: { type: 'object', properties: { @@ -86,6 +121,7 @@ describe('validators', () => { title: 'should return errors for invalid nested properties', schemas: { zod: z.object({ name: z.string(), nested: z.object({ age: z.number() }) }), + class: NestedSchema, json: { type: 'object', properties: { @@ -99,6 +135,7 @@ describe('validators', () => { success: false, errors: { zod: [{ message: 'Expected number, received string', path: '/nested/age' }], + class: [{ message: 'age must be a number conforming to the specified constraints', path: '/nested/age' }], json: [{ message: 'must be number', path: '/nested/age' }], }, }, @@ -107,6 +144,7 @@ describe('validators', () => { title: 'should successfully validate a polymorphic oneOf schema', schemas: { zod: null, // Zod has no support for `oneOf` + class: null, // ClassValidator has no support for `oneOf` json: { oneOf: [ { type: 'object', properties: { stringType: { type: 'string' } }, required: ['stringType'] }, @@ -129,6 +167,7 @@ describe('validators', () => { title: 'should return errors for invalid polymorphic oneOf schema', schemas: { zod: null, // Zod has no support for `oneOf` + class: null, // ClassValidator has no support for `oneOf` json: { oneOf: [ { type: 'object', properties: { stringType: { type: 'string' } }, required: ['stringType'] }, @@ -146,6 +185,7 @@ describe('validators', () => { errors: { json: [{ message: 'must match exactly one schema in oneOf', path: '' }], zod: null, // Zod has no support for `oneOf` + class: null, // ClassValidator has no support for `oneOf` }, }, }, @@ -153,6 +193,7 @@ describe('validators', () => { title: 'should successfully validate a polymorphic allOf schema', schemas: { zod: null, // Zod has no support for `oneOf` + class: null, // ClassValidator has no support for `oneOf` json: { allOf: [ { type: 'object', properties: { stringType: { type: 'string' } }, required: ['stringType'] }, @@ -179,6 +220,7 @@ describe('validators', () => { title: 'should return errors for invalid polymorphic `allOf` schema', schemas: { zod: null, // Zod has no support for `allOf` + class: null, // ClassValidator has no support for `allOf` json: { allOf: [ { type: 'object', properties: { stringType: { type: 'string' } }, required: ['stringType'] }, @@ -195,6 +237,7 @@ describe('validators', () => { errors: { json: [{ message: "must have required property 'numberType'", path: '' }], zod: null, // Zod has no support for `allOf` + class: null, // ClassValidator has no support for `allOf` }, }, }, @@ -206,6 +249,7 @@ describe('validators', () => { z.object({ type: z.literal('numberType'), numVal: z.number() }), z.object({ type: z.literal('booleanType'), boolVal: z.boolean() }), ]), + class: null, // ClassValidator has no support for `anyOf` json: { anyOf: [ { @@ -243,6 +287,7 @@ describe('validators', () => { z.object({ type: z.literal('numberType'), numVal: z.number() }), z.object({ type: z.literal('booleanType'), boolVal: z.boolean() }), ]), + class: null, // ClassValidator has no support for `anyOf` json: { anyOf: [ { @@ -285,6 +330,7 @@ describe('validators', () => { * * @see https://ajv.js.org/json-schema.html#discriminator */ + class: null, // ClassValidator has no support for `anyOf` json: [ { message: "must have required property 'stringVal'", @@ -338,6 +384,7 @@ describe('validators', () => { title: string; schemas: { zod: ZodSchema | null; + class: ClassType | null; json: JsonSchema; }; result: JsonSchema; @@ -347,6 +394,7 @@ describe('validators', () => { title: 'should transform a simple object schema', schemas: { zod: z.object({ name: z.string(), age: z.number() }), + class: SimpleStringAndNumberSchema, json: { type: 'object', properties: { name: { type: 'string' }, age: { type: 'number' } }, @@ -365,6 +413,7 @@ describe('validators', () => { title: 'should transform a nested object schema', schemas: { zod: z.object({ name: z.string(), nested: z.object({ age: z.number() }) }), + class: NestedSchema, json: { type: 'object', properties: { @@ -399,6 +448,7 @@ describe('validators', () => { title: 'should transform a polymorphic `oneOf` schema', schemas: { zod: null, // Zod has no support for `oneOf` + class: null, // ClassValidator has no support for `oneOf` json: { oneOf: [ { type: 'object', properties: { stringType: { type: 'string' } }, required: ['stringType'] }, @@ -419,6 +469,7 @@ describe('validators', () => { title: 'should transform a polymorphic `allOf` schema', schemas: { zod: null, // Zod has no support for `anyOf` + class: null, // ClassValidator has no support for `anyOf` json: { allOf: [ { type: 'object', properties: { stringType: { type: 'string' } }, required: ['stringType'] }, @@ -447,6 +498,7 @@ describe('validators', () => { ]) ), }), + class: null, // ClassValidator has no support for `anyOf` json: { type: 'object', properties: { @@ -522,7 +574,7 @@ describe('validators', () => { .forEach((testCase) => { it(testCase.title, () => { const result = transformSchema(testCase.schemas[schema] as Schema); - expect(result).deep.contain(testCase.result); + expect(result).deep.contain(testCase.result, JSON.stringify(result)); }); }); }); diff --git a/packages/framework/src/validators/zod.validator.ts b/packages/framework/src/validators/zod.validator.ts index e6eb413a372..7dec9b6d6b2 100644 --- a/packages/framework/src/validators/zod.validator.ts +++ b/packages/framework/src/validators/zod.validator.ts @@ -32,8 +32,7 @@ export class ZodValidator implements Validator { // eslint-disable-next-line global-require const { zodToJsonSchema } = require('zod-to-json-schema') as typeof import('zod-to-json-schema'); - // @ts-expect-error - zod-to-json-schema is not using JSONSchema7 - return zodToJsonSchema(schema); + return zodToJsonSchema(schema) as JsonSchema; } catch (error) { if ((error as Error)?.message?.includes('Cannot find module')) { // eslint-disable-next-line no-console From c2c0512f69669c2826c3150f1ce5a606526e5458 Mon Sep 17 00:00:00 2001 From: Paul Werner <52678724+paulwer@users.noreply.github.com> Date: Fri, 8 Nov 2024 08:48:15 +0100 Subject: [PATCH 02/56] Update packages/framework/src/validators/class-validator.validator.ts Co-authored-by: Richard Fontein <32132657+rifont@users.noreply.github.com> --- .../src/validators/class-validator.validator.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/framework/src/validators/class-validator.validator.ts b/packages/framework/src/validators/class-validator.validator.ts index 19c85a49208..b09c2461424 100644 --- a/packages/framework/src/validators/class-validator.validator.ts +++ b/packages/framework/src/validators/class-validator.validator.ts @@ -66,12 +66,9 @@ export class ClassValidatorValidator implements Validator { T_Validated = FromSchema, >(data: T_Unvalidated, schema: T_Schema): Promise> { try { - // eslint-disable-next-line global-require - require('reflect-metadata') as typeof import('reflect-metadata'); - // eslint-disable-next-line global-require - const { plainToInstance, instanceToPlain } = require('class-transformer') as typeof import('class-transformer'); - // eslint-disable-next-line global-require - const { validate } = require('class-validator') as typeof import('class-validator'); + await import('reflect-metadata'); + const { plainToInstance, instanceToPlain } = await import('class-transformer'); + const { validate } = await import('class-validator'); // Convert plain data to an instance of the schema class const instance = plainToInstance(schema, data); From f343a9dc20af3f34595c8d95b13e9117a12e7e12 Mon Sep 17 00:00:00 2001 From: Paul Werner <52678724+paulwer@users.noreply.github.com> Date: Fri, 8 Nov 2024 08:22:52 +0000 Subject: [PATCH 03/56] fixes --- .../src/validators/class-validator.validator.ts | 9 +++------ packages/framework/src/validators/validator.test.ts | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/packages/framework/src/validators/class-validator.validator.ts b/packages/framework/src/validators/class-validator.validator.ts index b09c2461424..c2beebbbb55 100644 --- a/packages/framework/src/validators/class-validator.validator.ts +++ b/packages/framework/src/validators/class-validator.validator.ts @@ -98,15 +98,12 @@ export class ClassValidatorValidator implements Validator { } } - transformToJsonSchema(schema: ClassType): JsonSchema { + async transformToJsonSchema(schema: ClassType): Promise { try { // eslint-disable-next-line global-require const { defaultMetadataStorage } = require('class-transformer/cjs/storage'); - // eslint-disable-next-line global-require - const { getMetadataStorage } = require('class-validator') as typeof import('class-validator'); - // eslint-disable-next-line global-require, prettier/prettier - const { targetConstructorToSchema, validationMetadatasToSchemas } = - require('class-validator-jsonschema') as typeof import('class-validator-jsonschema'); + const { getMetadataStorage } = await import('class-validator'); + const { targetConstructorToSchema, validationMetadatasToSchemas } = await import('class-validator-jsonschema'); const schemas = validationMetadatasToSchemas({ classValidatorMetadataStorage: getMetadataStorage(), diff --git a/packages/framework/src/validators/validator.test.ts b/packages/framework/src/validators/validator.test.ts index 370a2c489e0..4b5e141452f 100644 --- a/packages/framework/src/validators/validator.test.ts +++ b/packages/framework/src/validators/validator.test.ts @@ -572,7 +572,7 @@ describe('validators', () => { testCases .filter((testCase) => testCase.schemas[schema] !== null) .forEach((testCase) => { - it(testCase.title, () => { + it(testCase.title, async () => { const result = await transformSchema(testCase.schemas[schema] as Schema); expect(result).deep.contain(testCase.result, JSON.stringify(result)); }); From 8662b2b311902b8413d71b153b29eee0abbc9b70 Mon Sep 17 00:00:00 2001 From: Paul Werner <52678724+paulwer@users.noreply.github.com> Date: Fri, 8 Nov 2024 09:00:16 +0000 Subject: [PATCH 04/56] workaround for classValidator defaultStorage --- .../validators/class-validator.validator.ts | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/packages/framework/src/validators/class-validator.validator.ts b/packages/framework/src/validators/class-validator.validator.ts index c2beebbbb55..a9ab53dbed9 100644 --- a/packages/framework/src/validators/class-validator.validator.ts +++ b/packages/framework/src/validators/class-validator.validator.ts @@ -100,8 +100,23 @@ export class ClassValidatorValidator implements Validator { async transformToJsonSchema(schema: ClassType): Promise { try { - // eslint-disable-next-line global-require - const { defaultMetadataStorage } = require('class-transformer/cjs/storage'); + // @ts-ignore + const { defaultMetadataStorage: defaultMetadataStorageCjs } = await import('class-transformer/cjs/storage'); + // @ts-ignore + const { defaultMetadataStorage: defaultMetadataStorageEsm2015 } = await import( + // @ts-ignore + 'class-transformer/esm2015/storage' + ); + // @ts-ignore + const { defaultMetadataStorage: defaultMetadataStorageEsm5 } = await import('class-transformer/esm5/storage'); + // @ts-ignore + const defaultMetadataStorage = defaultMetadataStorageCjs._typeMetadatas.size + ? defaultMetadataStorageCjs + : defaultMetadataStorageEsm2015._typeMetadatas.size + ? defaultMetadataStorageEsm2015 + : defaultMetadataStorageEsm5._typeMetadatas.size + ? defaultMetadataStorageEsm5 + : undefined; const { getMetadataStorage } = await import('class-validator'); const { targetConstructorToSchema, validationMetadatasToSchemas } = await import('class-validator-jsonschema'); From df9128ede96984d809b1ecc17bd66b76d82a2097 Mon Sep 17 00:00:00 2001 From: Paul Werner <52678724+paulwer@users.noreply.github.com> Date: Fri, 8 Nov 2024 10:00:53 +0100 Subject: [PATCH 05/56] Update packages/framework/src/validators/class-validator.validator.ts Co-authored-by: Richard Fontein <32132657+rifont@users.noreply.github.com> --- packages/framework/src/validators/class-validator.validator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/framework/src/validators/class-validator.validator.ts b/packages/framework/src/validators/class-validator.validator.ts index c2beebbbb55..3953def3097 100644 --- a/packages/framework/src/validators/class-validator.validator.ts +++ b/packages/framework/src/validators/class-validator.validator.ts @@ -57,7 +57,7 @@ function formatErrors(errors: ValidationError[], parentPath = ''): { path: strin export class ClassValidatorValidator implements Validator { canHandle(schema: Schema): schema is ClassType { - return typeof (schema as ClassType) === 'function'; + return typeof schema === 'function' && schema.prototype !== undefined && schema.prototype.constructor === schema; } async validate< From 86bd4f9ee872332c863d8be5be69459ab63b5fe9 Mon Sep 17 00:00:00 2001 From: Paul Werner <52678724+paulwer@users.noreply.github.com> Date: Fri, 8 Nov 2024 13:45:06 +0000 Subject: [PATCH 06/56] fixes --- .../framework/src/validators/class-validator.validator.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/framework/src/validators/class-validator.validator.ts b/packages/framework/src/validators/class-validator.validator.ts index a9ab53dbed9..579b05e9b8d 100644 --- a/packages/framework/src/validators/class-validator.validator.ts +++ b/packages/framework/src/validators/class-validator.validator.ts @@ -100,7 +100,10 @@ export class ClassValidatorValidator implements Validator { async transformToJsonSchema(schema: ClassType): Promise { try { - // @ts-ignore + /* + * TODO: replace with direct import, when metadataStorage is exported by default: https://github.com/typestack/class-transformer/issues/563#issuecomment-803262394 + * @ts-ignore + */ const { defaultMetadataStorage: defaultMetadataStorageCjs } = await import('class-transformer/cjs/storage'); // @ts-ignore const { defaultMetadataStorage: defaultMetadataStorageEsm2015 } = await import( From f74470a4ad118ff7cedfca84d522224c767684e8 Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Fri, 8 Nov 2024 17:27:24 +0100 Subject: [PATCH 07/56] refactor(types): replace any with unknown in T_Controls --- packages/framework/src/types/step.types.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/framework/src/types/step.types.ts b/packages/framework/src/types/step.types.ts index e6f073ee57f..9bbb423285a 100644 --- a/packages/framework/src/types/step.types.ts +++ b/packages/framework/src/types/step.types.ts @@ -64,8 +64,7 @@ export type ActionStep< /** * The controls for the step. */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any - T_Controls extends Record = FromSchema, + T_Controls extends Record = FromSchema, >( /** * The name of the step. This is used to identify the step in the workflow. @@ -95,8 +94,7 @@ export type CustomStep = < /** * The controls for the step. */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any - T_Controls extends Record = FromSchema, + T_Controls extends Record = FromSchema, /* * These intermediary types are needed to capture the types in a single type instance * to stop Typescript from erroring with: @@ -155,8 +153,7 @@ export type ChannelStep< /** * The controls for the step. */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any - T_Controls extends Record = FromSchema, + T_Controls extends Record = FromSchema, >( /** * The name of the step. This is used to identify the step in the workflow. From e7f3ef85ff56b65092f80ab6dc01feea3f3560cf Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Fri, 8 Nov 2024 17:27:56 +0100 Subject: [PATCH 08/56] Update packages/framework/src/validators/class-validator.validator.ts --- packages/framework/src/validators/class-validator.validator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/framework/src/validators/class-validator.validator.ts b/packages/framework/src/validators/class-validator.validator.ts index c26cc9cb282..9b88a97a1f5 100644 --- a/packages/framework/src/validators/class-validator.validator.ts +++ b/packages/framework/src/validators/class-validator.validator.ts @@ -102,7 +102,7 @@ export class ClassValidatorValidator implements Validator { try { /* * TODO: replace with direct import, when metadataStorage is exported by default: https://github.com/typestack/class-transformer/issues/563#issuecomment-803262394 - * @ts-ignore + * @ts-expect-error - class-transformer doesn't export `defaultMetadataStorage` from the root module */ const { defaultMetadataStorage: defaultMetadataStorageCjs } = await import('class-transformer/cjs/storage'); // @ts-ignore From c5daec5a2747e1924b964deec4dddd010b0fcba4 Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Fri, 8 Nov 2024 17:33:38 +0100 Subject: [PATCH 09/56] refactor(validator): simplify metadata storage import --- .../validators/class-validator.validator.ts | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/packages/framework/src/validators/class-validator.validator.ts b/packages/framework/src/validators/class-validator.validator.ts index 9b88a97a1f5..c8d9546d341 100644 --- a/packages/framework/src/validators/class-validator.validator.ts +++ b/packages/framework/src/validators/class-validator.validator.ts @@ -102,24 +102,9 @@ export class ClassValidatorValidator implements Validator { try { /* * TODO: replace with direct import, when metadataStorage is exported by default: https://github.com/typestack/class-transformer/issues/563#issuecomment-803262394 - * @ts-expect-error - class-transformer doesn't export `defaultMetadataStorage` from the root module */ - const { defaultMetadataStorage: defaultMetadataStorageCjs } = await import('class-transformer/cjs/storage'); - // @ts-ignore - const { defaultMetadataStorage: defaultMetadataStorageEsm2015 } = await import( - // @ts-ignore - 'class-transformer/esm2015/storage' - ); - // @ts-ignore - const { defaultMetadataStorage: defaultMetadataStorageEsm5 } = await import('class-transformer/esm5/storage'); - // @ts-ignore - const defaultMetadataStorage = defaultMetadataStorageCjs._typeMetadatas.size - ? defaultMetadataStorageCjs - : defaultMetadataStorageEsm2015._typeMetadatas.size - ? defaultMetadataStorageEsm2015 - : defaultMetadataStorageEsm5._typeMetadatas.size - ? defaultMetadataStorageEsm5 - : undefined; + // @ts-expect-error - class-transformer doesn't export `defaultMetadataStorage` from the root module + const { defaultMetadataStorage } = await import('class-transformer/cjs/storage'); const { getMetadataStorage } = await import('class-validator'); const { targetConstructorToSchema, validationMetadatasToSchemas } = await import('class-validator-jsonschema'); From 255115c90ccf37afb6ec350757732ecec0cce225 Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Fri, 8 Nov 2024 17:34:18 +0100 Subject: [PATCH 10/56] docs(validator): update TODO comment with @see link --- packages/framework/src/validators/class-validator.validator.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/framework/src/validators/class-validator.validator.ts b/packages/framework/src/validators/class-validator.validator.ts index c8d9546d341..af36a43292b 100644 --- a/packages/framework/src/validators/class-validator.validator.ts +++ b/packages/framework/src/validators/class-validator.validator.ts @@ -101,7 +101,8 @@ export class ClassValidatorValidator implements Validator { async transformToJsonSchema(schema: ClassType): Promise { try { /* - * TODO: replace with direct import, when metadataStorage is exported by default: https://github.com/typestack/class-transformer/issues/563#issuecomment-803262394 + * TODO: replace with direct import, when defaultMetadataStorage is exported by default + * @see https://github.com/typestack/class-transformer/issues/563#issuecomment-803262394 */ // @ts-expect-error - class-transformer doesn't export `defaultMetadataStorage` from the root module const { defaultMetadataStorage } = await import('class-transformer/cjs/storage'); From 68e5c9cf2d81724c0378817198b2f493e8d05cb9 Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Fri, 8 Nov 2024 17:42:35 +0100 Subject: [PATCH 11/56] test(validation): update tests for validation changes --- packages/framework/src/client.validation.test.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/framework/src/client.validation.test.ts b/packages/framework/src/client.validation.test.ts index 17635629764..0860ba294f7 100644 --- a/packages/framework/src/client.validation.test.ts +++ b/packages/framework/src/client.validation.test.ts @@ -191,8 +191,7 @@ describe('validation', () => { describe('class-validator', () => { class ClassValidatorSchema { @IsString() - @IsOptional() - foo?: string; + foo!: string; @IsNumber() @IsOptional() baz?: number; @@ -290,7 +289,7 @@ describe('validation', () => { }); it('should transform a class-validator schema to a json schema during discovery', async () => { - client.addWorkflows([ + await client.addWorkflows([ workflow('class-validator-validation', async ({ step }) => { await step.email( 'class-validator-validation', @@ -308,7 +307,7 @@ describe('validation', () => { const discoverResult = client.discover(); const stepControlSchema = discoverResult.workflows[0].steps[0].controls.schema; - expect(stepControlSchema).to.deep.include({ + expect(stepControlSchema).to.deep.equal({ additionalProperties: false, properties: { foo: { @@ -318,13 +317,13 @@ describe('validation', () => { type: 'number', }, }, - required: ['foo', 'baz'], + required: ['foo'], type: 'object', }); }); it('should throw an error if a property is missing', async () => { - client.addWorkflows([ + await client.addWorkflows([ workflow('class-validator-validation', async ({ step }) => { await step.email( 'test-email', From ecec05d46d353d3aea0a995eb36a717dd13ef710 Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Fri, 8 Nov 2024 17:54:17 +0100 Subject: [PATCH 12/56] refactor(types): update class type inference logic --- packages/framework/src/types/schema.types.ts | 26 ++++++++++++++------ 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/packages/framework/src/types/schema.types.ts b/packages/framework/src/types/schema.types.ts index c75e60a7237..75556f112d4 100644 --- a/packages/framework/src/types/schema.types.ts +++ b/packages/framework/src/types/schema.types.ts @@ -1,19 +1,31 @@ import type { JSONSchema, FromSchema as JsonSchemaInfer } from 'json-schema-to-ts'; import zod from 'zod'; +import { Prettify } from './util.types'; +/** + * A JSON schema. + */ export type JsonSchema = JSONSchema; -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export type ClassType = new (...args: any[]) => T; +/** + * A class type. + */ +export type ClassType = new (...args: unknown[]) => T; + +/** + * Extract the properties of a class type. + */ +export type ClassPropsInfer = T extends ClassType ? Prettify : never; /** * A schema used to validate a JSON object. * * Supported schemas: * - JSONSchema + * - ClassValidatorSchema * - ZodSchema */ -export type Schema = JsonSchema | zod.ZodSchema | ClassType; +export type Schema = JsonSchema | zod.ZodType | ClassType; /** * Infer the type of a Schema for unvalidated data. @@ -40,8 +52,8 @@ export type FromSchemaUnvalidated = T extends zod.ZodSchema ? zod.input : // ClassValidatorSchema - T extends ClassType - ? U + T extends ClassType + ? ClassPropsInfer : // All schema types exhausted. never; @@ -70,7 +82,7 @@ export type FromSchema = T extends zod.ZodSchema ? zod.infer : // ClassValidatorSchema - T extends ClassType - ? U + T extends ClassType + ? ClassPropsInfer : // All schema types exhausted. never; From 836bde369f709b2f54135ec11ac6738e86f8a708 Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Fri, 8 Nov 2024 17:55:55 +0100 Subject: [PATCH 13/56] test: remove JSON stringify from test assertion --- packages/framework/src/validators/validator.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/framework/src/validators/validator.test.ts b/packages/framework/src/validators/validator.test.ts index 4b5e141452f..a99b4602438 100644 --- a/packages/framework/src/validators/validator.test.ts +++ b/packages/framework/src/validators/validator.test.ts @@ -574,7 +574,7 @@ describe('validators', () => { .forEach((testCase) => { it(testCase.title, async () => { const result = await transformSchema(testCase.schemas[schema] as Schema); - expect(result).deep.contain(testCase.result, JSON.stringify(result)); + expect(result).deep.contain(testCase.result); }); }); }); From f3decf0cc18b0b5264e9bc41d27d22d1cd58d0a1 Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Fri, 8 Nov 2024 18:09:47 +0100 Subject: [PATCH 14/56] docs(schema.types): update ClassType type description --- packages/framework/src/types/schema.types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/framework/src/types/schema.types.ts b/packages/framework/src/types/schema.types.ts index 75556f112d4..6d6f3d2edf9 100644 --- a/packages/framework/src/types/schema.types.ts +++ b/packages/framework/src/types/schema.types.ts @@ -8,7 +8,7 @@ import { Prettify } from './util.types'; export type JsonSchema = JSONSchema; /** - * A class type. + * A type that represents a class. */ export type ClassType = new (...args: unknown[]) => T; From ed7c857fc5fc0979b3ce9eba946c956aee140b66 Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Fri, 8 Nov 2024 18:11:43 +0100 Subject: [PATCH 15/56] refactor(class-validator): improve type checking logic --- .../framework/src/validators/class-validator.validator.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/framework/src/validators/class-validator.validator.ts b/packages/framework/src/validators/class-validator.validator.ts index af36a43292b..7252e47ea45 100644 --- a/packages/framework/src/validators/class-validator.validator.ts +++ b/packages/framework/src/validators/class-validator.validator.ts @@ -57,7 +57,11 @@ function formatErrors(errors: ValidationError[], parentPath = ''): { path: strin export class ClassValidatorValidator implements Validator { canHandle(schema: Schema): schema is ClassType { - return typeof schema === 'function' && schema.prototype !== undefined && schema.prototype.constructor === schema; + return ( + typeof (schema as ClassType) === 'function' && + (schema as ClassType).prototype !== undefined && + (schema as ClassType).prototype.constructor === schema + ); } async validate< From 322d118ee522d7b3a6843e0c00c4da627da31283 Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Fri, 8 Nov 2024 19:13:35 +0100 Subject: [PATCH 16/56] test(validator): extract class-validator fixtures --- .../fixures/class-validator.fixtures.ts | 30 ++++++++++++++++++ .../src/validators/validator.test.ts | 31 ++----------------- 2 files changed, 32 insertions(+), 29 deletions(-) create mode 100644 packages/framework/src/validators/fixures/class-validator.fixtures.ts diff --git a/packages/framework/src/validators/fixures/class-validator.fixtures.ts b/packages/framework/src/validators/fixures/class-validator.fixtures.ts new file mode 100644 index 00000000000..6f158ddc4c7 --- /dev/null +++ b/packages/framework/src/validators/fixures/class-validator.fixtures.ts @@ -0,0 +1,30 @@ +import 'reflect-metadata'; +import { IsNumber, IsOptional, IsString, ValidateNested } from 'class-validator'; +import { Type } from 'class-transformer'; + +export class SimpleStringSchema { + @IsString() + @IsOptional() + name?: string; +} + +class NestedChildrenSchema { + @IsNumber() + age!: number; +} + +export class NestedSchema { + @IsString() + name!: string; + + @ValidateNested() + @Type(() => NestedChildrenSchema) + nested!: NestedChildrenSchema; +} + +export class SimpleStringAndNumberSchema { + @IsString() + name!: string; + @IsNumber() + age!: number; +} diff --git a/packages/framework/src/validators/validator.test.ts b/packages/framework/src/validators/validator.test.ts index a99b4602438..72e3648b264 100644 --- a/packages/framework/src/validators/validator.test.ts +++ b/packages/framework/src/validators/validator.test.ts @@ -1,38 +1,11 @@ import { describe, it, expect } from 'vitest'; import { ZodSchema, z } from 'zod'; -import { IsNumber, IsOptional, IsString, ValidateNested } from 'class-validator'; -import { Type } from 'class-transformer'; import { validateData, transformSchema } from './base.validator'; import { ClassType, JsonSchema, Schema } from '../types/schema.types'; -import 'reflect-metadata'; +import { SimpleStringSchema, NestedSchema, SimpleStringAndNumberSchema } from './fixures/class-validator.fixtures'; const schemas = ['zod', 'class', 'json'] as const; -// Definitions of class-validator schemas -class SimpleStringSchema { - @IsString() - @IsOptional() - name?: string; -} -class NestedChildrenSchema { - @IsNumber() - age!: number; -} -class NestedSchema { - @IsString() - name!: string; - - @ValidateNested() - @Type(() => NestedChildrenSchema) - nested!: NestedChildrenSchema; -} -class SimpleStringAndNumberSchema { - @IsString() - name!: string; - @IsNumber() - age!: number; -} - describe('validators', () => { describe('validateData', () => { type ValidateDataTestCase = { @@ -316,6 +289,7 @@ describe('validators', () => { success: false, errors: { zod: [{ message: 'Expected number, received string', path: '/numVal' }], + class: null, // ClassValidator has no support for `anyOf` /* * TODO: use discriminator to get the correct error message. * @@ -330,7 +304,6 @@ describe('validators', () => { * * @see https://ajv.js.org/json-schema.html#discriminator */ - class: null, // ClassValidator has no support for `anyOf` json: [ { message: "must have required property 'stringVal'", From b432668551c87981af017658aa3701970b24bdbb Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Fri, 8 Nov 2024 21:51:33 +0100 Subject: [PATCH 17/56] refactor: Remove IsOptional from name property --- .../src/validators/fixures/class-validator.fixtures.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/framework/src/validators/fixures/class-validator.fixtures.ts b/packages/framework/src/validators/fixures/class-validator.fixtures.ts index 6f158ddc4c7..073b6ef5113 100644 --- a/packages/framework/src/validators/fixures/class-validator.fixtures.ts +++ b/packages/framework/src/validators/fixures/class-validator.fixtures.ts @@ -1,11 +1,10 @@ import 'reflect-metadata'; -import { IsNumber, IsOptional, IsString, ValidateNested } from 'class-validator'; +import { IsNumber, IsString, ValidateNested } from 'class-validator'; import { Type } from 'class-transformer'; export class SimpleStringSchema { @IsString() - @IsOptional() - name?: string; + name!: string; } class NestedChildrenSchema { From 76de6fa9fbb1bd94607b887ab7ebc76b18f70769 Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Sun, 10 Nov 2024 23:35:16 +0100 Subject: [PATCH 18/56] refactor(schema): remove zod dependency from schemas --- packages/framework/package.json | 2 +- packages/framework/src/client.ts | 2 +- .../framework/src/client.validation.test.ts | 387 +++--------------- .../src/constants/error.constants.ts | 1 + packages/framework/src/errors/base.errors.ts | 2 +- .../framework/src/errors/import.errors.ts | 16 + .../workflow/discover-action-step-factory.ts | 4 +- .../workflow/discover-channel-step-factory.ts | 14 +- .../workflow/discover-custom-step-factory.ts | 13 +- .../resources/workflow/discover-providers.ts | 9 +- .../workflow/workflow.resource.test-d.ts | 281 +++++++++++++ .../resources/workflow/workflow.resource.ts | 2 +- packages/framework/src/types/import.types.ts | 34 ++ packages/framework/src/types/schema.types.ts | 67 --- .../schema.types/base.schema.types.test-d.ts | 59 +++ .../types/schema.types/base.schema.types.ts | 53 +++ .../framework/src/types/schema.types/index.ts | 3 + .../schema.types/json.schema.types.test-d.ts | 42 ++ .../types/schema.types/json.schema.types.ts | 36 ++ .../schema.types/zod.schema.types.test-d.ts | 39 ++ .../types/schema.types/zod.schema.types.ts | 42 ++ packages/framework/src/types/util.types.ts | 5 + .../framework/src/types/validator.types.ts | 12 +- .../framework/src/utils/import.utils.test.ts | 59 +++ packages/framework/src/utils/import.utils.ts | 38 ++ .../src/validators/base.validator.ts | 36 +- .../src/validators/json-schema.validator.ts | 29 +- .../src/validators/validator.test.ts | 4 +- .../framework/src/validators/zod.validator.ts | 56 +-- 29 files changed, 884 insertions(+), 463 deletions(-) create mode 100644 packages/framework/src/errors/import.errors.ts create mode 100644 packages/framework/src/resources/workflow/workflow.resource.test-d.ts create mode 100644 packages/framework/src/types/import.types.ts delete mode 100644 packages/framework/src/types/schema.types.ts create mode 100644 packages/framework/src/types/schema.types/base.schema.types.test-d.ts create mode 100644 packages/framework/src/types/schema.types/base.schema.types.ts create mode 100644 packages/framework/src/types/schema.types/index.ts create mode 100644 packages/framework/src/types/schema.types/json.schema.types.test-d.ts create mode 100644 packages/framework/src/types/schema.types/json.schema.types.ts create mode 100644 packages/framework/src/types/schema.types/zod.schema.types.test-d.ts create mode 100644 packages/framework/src/types/schema.types/zod.schema.types.ts create mode 100644 packages/framework/src/utils/import.utils.test.ts create mode 100644 packages/framework/src/utils/import.utils.ts diff --git a/packages/framework/package.json b/packages/framework/package.json index 37845e8fc46..fae96653dcb 100644 --- a/packages/framework/package.json +++ b/packages/framework/package.json @@ -25,7 +25,7 @@ "next", "nuxt", "remix", - "sveltekit", + "sveltekit", "README.md" ], "scripts": { diff --git a/packages/framework/src/client.ts b/packages/framework/src/client.ts index 3a5db6c9ece..83c423c24d8 100644 --- a/packages/framework/src/client.ts +++ b/packages/framework/src/client.ts @@ -195,7 +195,7 @@ export class Client { throw new Error(`Invalid component: '${component}'`); } } else { - return result.data; + return result.data as T; } } diff --git a/packages/framework/src/client.validation.test.ts b/packages/framework/src/client.validation.test.ts index b3444d0c7c5..7326ed80de6 100644 --- a/packages/framework/src/client.validation.test.ts +++ b/packages/framework/src/client.validation.test.ts @@ -1,6 +1,4 @@ -/* eslint-disable no-param-reassign */ import { expect, it, describe, beforeEach } from 'vitest'; -import { z } from 'zod'; import { Client } from './client'; import { workflow } from './resources/workflow'; import { ExecutionStateControlsInvalidError } from './errors'; @@ -13,356 +11,77 @@ describe('validation', () => { client = new Client({ secretKey: 'some-secret-key' }); }); - describe('zod', () => { - const zodSchema = z.object({ - foo: z.string(), - baz: z.number(), - }); - - it('should infer types in the step controls', async () => { - workflow('zod-validation', async ({ step }) => { + const jsonSchema = { + type: 'object', + properties: { + foo: { type: 'string' }, + baz: { type: 'number' }, + }, + required: ['foo', 'baz'], + additionalProperties: false, + } as const; + + it('should transform a JSON schema to a valid schema during discovery', async () => { + await client.addWorkflows([ + workflow('json-schema-validation', async ({ step }) => { await step.email( - 'zod-validation', - async (controls) => { - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - controls.foo = 123; - // @ts-expect-error - Type 'string' is not assignable to type 'number'. - controls.baz = '123'; - - return { - subject: 'Test subject', - body: 'Test body', - }; - }, + 'json-schema-validation', + async () => ({ + subject: 'Test subject', + body: 'Test body', + }), { - controlSchema: zodSchema, - skip: (controls) => { - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - controls.foo = 123; - // @ts-expect-error - Type 'string' is not assignable to type 'number'. - controls.baz = '123'; - - return true; - }, - providers: { - sendgrid: async ({ controls, outputs }) => { - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - controls.foo = 123; - // @ts-expect-error - Type 'string' is not assignable to type 'number'. - controls.baz = '123'; - - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - outputs.body = 123; - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - outputs.subject = 123; - - return { - ipPoolName: 'test', - }; - }, - }, + controlSchema: jsonSchema, } ); - }); - }); - - it('should infer types in the workflow payload', async () => { - workflow( - 'zod-validation', - async ({ step, payload }) => { - await step.email('zod-validation', async () => { - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - payload.foo = 123; - // @ts-expect-error - Type 'string' is not assignable to type 'number'. - payload.baz = '123'; - - return { - subject: 'Test subject', - body: 'Test body', - }; - }); - }, - { - payloadSchema: zodSchema, - } - ); - }); - - it('should infer types in the workflow controls', async () => { - workflow( - 'zod-validation', - async ({ step, controls }) => { - await step.email('zod-validation', async () => { - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - controls.foo = 123; - // @ts-expect-error - Type 'string' is not assignable to type 'number'. - controls.baz = '123'; + }), + ]); - return { - subject: 'Test subject', - body: 'Test body', - }; - }); - }, - { - controlSchema: zodSchema, - } - ); - }); - - it('should transform a zod schema to a json schema during discovery', async () => { - await client.addWorkflows([ - workflow('zod-validation', async ({ step }) => { - await step.email( - 'zod-validation', - async () => ({ - subject: 'Test subject', - body: 'Test body', - }), - { - controlSchema: zodSchema, - } - ); - }), - ]); - - const discoverResult = client.discover(); - const stepControlSchema = discoverResult.workflows[0].steps[0].controls.schema; - - expect(stepControlSchema).to.deep.include({ - additionalProperties: false, - properties: { - foo: { - type: 'string', - }, - baz: { - type: 'number', - }, - }, - required: ['foo', 'baz'], - type: 'object', - }); - }); - - it('should throw an error if a property is missing', async () => { - await client.addWorkflows([ - workflow('zod-validation', async ({ step }) => { - await step.email( - 'test-email', - async () => ({ - subject: 'Test subject', - body: 'Test body', - }), - { - controlSchema: zodSchema, - } - ); - }), - ]); + const discoverResult = client.discover(); + const stepControlSchema = discoverResult.workflows[0].steps[0].controls.schema; - try { - await client.executeWorkflow({ - action: PostActionEnum.EXECUTE, - workflowId: 'zod-validation', - controls: { - foo: '341', - }, - payload: {}, - stepId: 'test-email', - state: [], - subscriber: {}, - }); - } catch (error) { - expect(error).to.be.instanceOf(ExecutionStateControlsInvalidError); - expect((error as ExecutionStateControlsInvalidError).message).to.equal( - 'Workflow with id: `zod-validation` has an invalid state. Step with id: `test-email` has invalid `controls`. Please provide the correct step controls.' - ); - expect((error as ExecutionStateControlsInvalidError).data).to.deep.equal([ - { - message: 'Required', - path: '/baz', - }, - ]); - } - }); + expect(stepControlSchema).to.deep.include(jsonSchema); }); - describe('json-schema', () => { - const jsonSchema = { - type: 'object', - properties: { - foo: { type: 'string' }, - baz: { type: 'number' }, - }, - required: ['foo', 'baz'], - additionalProperties: false, - } as const; - - it('should infer types in the step controls', async () => { + it('should throw an error if a property is missing', async () => { + await client.addWorkflows([ workflow('json-schema-validation', async ({ step }) => { await step.email( - 'json-schema-validation', - async (controls) => { - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - controls.foo = 123; - // @ts-expect-error - Type 'string' is not assignable to type 'number'. - controls.baz = '123'; - - return { - subject: 'Test subject', - body: 'Test body', - }; - }, + 'test-email', + async () => ({ + subject: 'Test subject', + body: 'Test body', + }), { controlSchema: jsonSchema, - skip: (controls) => { - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - controls.foo = 123; - // @ts-expect-error - Type 'string' is not assignable to type 'number'. - controls.baz = '123'; - - return true; - }, - providers: { - sendgrid: async ({ controls, outputs }) => { - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - controls.foo = 123; - // @ts-expect-error - Type 'string' is not assignable to type 'number'. - controls.baz = '123'; - - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - outputs.body = 123; - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - outputs.subject = 123; - - return { - ipPoolName: 'test', - }; - }, - }, } ); - }); - }); - - it('should infer types in the workflow payload', async () => { - workflow( - 'json-schema-validation', - async ({ step, payload }) => { - await step.email('json-schema-validation', async () => { - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - payload.foo = 123; - // @ts-expect-error - Type 'string' is not assignable to type 'number'. - payload.baz = '123'; - - return { - subject: 'Test subject', - body: 'Test body', - }; - }); + }), + ]); + + try { + await client.executeWorkflow({ + action: PostActionEnum.EXECUTE, + workflowId: 'json-schema-validation', + controls: { + foo: '341', }, - { - payloadSchema: jsonSchema, - } + payload: {}, + stepId: 'test-email', + state: [], + subscriber: {}, + }); + } catch (error) { + expect(error).to.be.instanceOf(ExecutionStateControlsInvalidError); + expect((error as ExecutionStateControlsInvalidError).message).to.equal( + 'Workflow with id: `json-schema-validation` has an invalid state. Step with id: `test-email` has invalid `controls`. Please provide the correct step controls.' ); - }); - - it('should infer types in the workflow controls', async () => { - workflow( - 'json-schema-validation', - async ({ step, controls }) => { - await step.email('json-schema-validation', async () => { - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - controls.foo = 123; - // @ts-expect-error - Type 'string' is not assignable to type 'number'. - controls.baz = '123'; - - return { - subject: 'Test subject', - body: 'Test body', - }; - }); - }, + expect((error as ExecutionStateControlsInvalidError).data).to.deep.equal([ { - controlSchema: jsonSchema, - } - ); - }); - - it('should transform a JSON schema to a valid schema during discovery', async () => { - await client.addWorkflows([ - workflow('json-schema-validation', async ({ step }) => { - await step.email( - 'json-schema-validation', - async () => ({ - subject: 'Test subject', - body: 'Test body', - }), - { - controlSchema: jsonSchema, - } - ); - }), - ]); - - const discoverResult = client.discover(); - const stepControlSchema = discoverResult.workflows[0].steps[0].controls.schema; - - expect(stepControlSchema).to.deep.include({ - additionalProperties: false, - properties: { - foo: { - type: 'string', - }, - baz: { - type: 'number', - }, + message: "must have required property 'baz'", + path: '', }, - required: ['foo', 'baz'], - type: 'object', - }); - }); - - it('should throw an error if a property is missing', async () => { - await client.addWorkflows([ - workflow('json-schema-validation', async ({ step }) => { - await step.email( - 'test-email', - async () => ({ - subject: 'Test subject', - body: 'Test body', - }), - { - controlSchema: jsonSchema, - } - ); - }), ]); - - try { - await client.executeWorkflow({ - action: PostActionEnum.EXECUTE, - workflowId: 'json-schema-validation', - controls: { - foo: '341', - }, - payload: {}, - stepId: 'test-email', - state: [], - subscriber: {}, - }); - } catch (error) { - expect(error).to.be.instanceOf(ExecutionStateControlsInvalidError); - expect((error as ExecutionStateControlsInvalidError).message).to.equal( - 'Workflow with id: `json-schema-validation` has an invalid state. Step with id: `test-email` has invalid `controls`. Please provide the correct step controls.' - ); - expect((error as ExecutionStateControlsInvalidError).data).to.deep.equal([ - { - message: "must have required property 'baz'", - path: '', - }, - ]); - } - }); + } }); }); diff --git a/packages/framework/src/constants/error.constants.ts b/packages/framework/src/constants/error.constants.ts index 03a6dc826db..7c86a63c4e3 100644 --- a/packages/framework/src/constants/error.constants.ts +++ b/packages/framework/src/constants/error.constants.ts @@ -11,6 +11,7 @@ export enum ErrorCodeEnum { EXECUTION_STATE_RESULT_INVALID_ERROR = 'ExecutionStateResultInvalidError', INVALID_ACTION_ERROR = 'InvalidActionError', METHOD_NOT_ALLOWED_ERROR = 'MethodNotAllowedError', + MISSING_DEPENDENCY_ERROR = 'MissingDependencyError', MISSING_SECRET_KEY_ERROR = 'MissingSecretKeyError', PROVIDER_EXECUTION_FAILED_ERROR = 'ProviderExecutionFailedError', PROVIDER_NOT_FOUND_ERROR = 'ProviderNotFoundError', diff --git a/packages/framework/src/errors/base.errors.ts b/packages/framework/src/errors/base.errors.ts index 9f0cb581833..d4318ded1e2 100644 --- a/packages/framework/src/errors/base.errors.ts +++ b/packages/framework/src/errors/base.errors.ts @@ -67,7 +67,7 @@ export abstract class ServerError extends FrameworkError { stack: cause.stack ?? message, }; } else { - super(`${message}: ${JSON.stringify(cause, null, 2)}`); + super(`${message}${cause ? `: ${JSON.stringify(cause, null, 2)}` : ''}`); this.data = { stack: message, }; diff --git a/packages/framework/src/errors/import.errors.ts b/packages/framework/src/errors/import.errors.ts new file mode 100644 index 00000000000..9b03553bddb --- /dev/null +++ b/packages/framework/src/errors/import.errors.ts @@ -0,0 +1,16 @@ +import { ErrorCodeEnum, HttpStatusEnum } from '../constants'; +import { ServerError } from './base.errors'; + +export class MissingDependencyError extends ServerError { + statusCode = HttpStatusEnum.INTERNAL_SERVER_ERROR; + code = ErrorCodeEnum.MISSING_DEPENDENCY_ERROR; + + constructor(usageReason: string, missingDependencies: string[]) { + const pronoun = missingDependencies.length === 1 ? 'it' : 'them'; + super( + `Tried to use a ${usageReason} in @novu/framework without ${missingDependencies.join( + ', ' + )} installed. Please install ${pronoun} by running \`npm install ${missingDependencies.join(' ')}\`.` + ); + } +} diff --git a/packages/framework/src/resources/workflow/discover-action-step-factory.ts b/packages/framework/src/resources/workflow/discover-action-step-factory.ts index 8b7d7d4fcca..1bf676d8614 100644 --- a/packages/framework/src/resources/workflow/discover-action-step-factory.ts +++ b/packages/framework/src/resources/workflow/discover-action-step-factory.ts @@ -1,6 +1,6 @@ import { ActionStepEnum } from '../../constants'; import { emptySchema } from '../../schemas'; -import type { Awaitable, DiscoverWorkflowOutput, Schema, ActionStep } from '../../types'; +import type { Awaitable, DiscoverWorkflowOutput, Schema, ActionStep, StepOptions, FromSchema } from '../../types'; import { transformSchema } from '../../validators'; import { discoverStep } from './discover-step'; @@ -32,7 +32,7 @@ export async function discoverActionStepFactory( }, resolve: resolve as (controls: Record) => Awaitable>, code: resolve.toString(), - options, + options: options as StepOptions, FromSchema>, providers: [], }); diff --git a/packages/framework/src/resources/workflow/discover-channel-step-factory.ts b/packages/framework/src/resources/workflow/discover-channel-step-factory.ts index 6b3fb0e5656..ecabdf530c3 100644 --- a/packages/framework/src/resources/workflow/discover-channel-step-factory.ts +++ b/packages/framework/src/resources/workflow/discover-channel-step-factory.ts @@ -1,6 +1,14 @@ import { ChannelStepEnum } from '../../constants'; import { emptySchema } from '../../schemas'; -import type { Awaitable, DiscoverStepOutput, DiscoverWorkflowOutput, Schema, ChannelStep } from '../../types'; +import type { + Awaitable, + DiscoverStepOutput, + DiscoverWorkflowOutput, + Schema, + ChannelStep, + StepOptions, + FromSchema, +} from '../../types'; import { transformSchema } from '../../validators'; import { discoverProviders } from './discover-providers'; import { discoverStep } from './discover-step'; @@ -32,14 +40,14 @@ export async function discoverChannelStepFactory( }, resolve: resolve as (controls: Record) => Awaitable>, code: resolve.toString(), - options, + options: options as StepOptions, FromSchema>, providers: [], }; await discoverStep(targetWorkflow, stepId, step); if (Object.keys(options.providers || {}).length > 0) { - discoverProviders(step, type as ChannelStepEnum, options.providers || {}); + await discoverProviders(step, type as ChannelStepEnum, options.providers || {}); } return { diff --git a/packages/framework/src/resources/workflow/discover-custom-step-factory.ts b/packages/framework/src/resources/workflow/discover-custom-step-factory.ts index 66a6d5ebf36..ebad260e5f2 100644 --- a/packages/framework/src/resources/workflow/discover-custom-step-factory.ts +++ b/packages/framework/src/resources/workflow/discover-custom-step-factory.ts @@ -1,5 +1,14 @@ import { emptySchema } from '../../schemas'; -import type { Awaitable, CustomStep, DiscoverWorkflowOutput, StepType, StepOutput } from '../../types'; +import type { + Awaitable, + CustomStep, + DiscoverWorkflowOutput, + StepType, + StepOutput, + StepOptions, + FromSchema, + Schema, +} from '../../types'; import { transformSchema } from '../../validators'; import { discoverStep } from './discover-step'; @@ -28,7 +37,7 @@ export async function discoverCustomStepFactory( }, resolve: resolve as (controls: Record) => Awaitable>, code: resolve.toString(), - options, + options: options as StepOptions, FromSchema>, providers: [], }); diff --git a/packages/framework/src/resources/workflow/discover-providers.ts b/packages/framework/src/resources/workflow/discover-providers.ts index 672c0766474..9329a08ce05 100644 --- a/packages/framework/src/resources/workflow/discover-providers.ts +++ b/packages/framework/src/resources/workflow/discover-providers.ts @@ -20,12 +20,13 @@ export async function discoverProviders( ): Promise { const channelSchemas = providerSchemas[channelType]; - Object.entries(providers).forEach(async ([type, resolve]) => { + const providerPromises = Object.entries(providers).map(async ([type, resolve]) => { // eslint-disable-next-line multiline-comment-style // TODO: fix the typing for `type` to use the keyof providerSchema[channelType] // @ts-expect-error - Element implicitly has an 'any' type because expression of type 'string' can't be used to index type const schemas = channelSchemas[type]; - step.providers.push({ + + return { type, code: resolve.toString(), resolve, @@ -33,6 +34,8 @@ export async function discoverProviders( schema: await transformSchema(schemas.output), unknownSchema: schemas.output, }, - }); + }; }); + + step.providers.push(...(await Promise.all(providerPromises))); } diff --git a/packages/framework/src/resources/workflow/workflow.resource.test-d.ts b/packages/framework/src/resources/workflow/workflow.resource.test-d.ts new file mode 100644 index 00000000000..e2a635019c2 --- /dev/null +++ b/packages/framework/src/resources/workflow/workflow.resource.test-d.ts @@ -0,0 +1,281 @@ +import { describe, expectTypeOf } from 'vitest'; +import { workflow } from '.'; +import { Subscriber } from '../../types'; + +describe('workflow function types', () => { + describe('event types', () => { + it('should have the expected subscriber type', () => { + workflow('without-schema', async ({ subscriber }) => { + expectTypeOf(subscriber).toEqualTypeOf(); + }); + }); + + it('should have the expected step functions', () => { + workflow('without-schema', async ({ step }) => { + expectTypeOf(step).toMatchTypeOf<{ + email: unknown; + sms: unknown; + push: unknown; + chat: unknown; + inApp: unknown; + digest: unknown; + delay: unknown; + custom: unknown; + }>(); + }); + }); + }); + + describe('without schema', () => { + it('should infer an unknown record type in the step function step controls', async () => { + workflow('without-schema', async ({ step }) => { + await step.email('without-schema', async (controls) => { + expectTypeOf(controls).toEqualTypeOf>(); + + return { + subject: 'Test subject', + body: 'Test body', + }; + }); + }); + }); + + it('should infer an unknown record type in the skip function step controls', async () => { + workflow('without-schema', async ({ step }) => { + await step.email( + 'without-schema', + async (controls) => { + return { + subject: 'Test subject', + body: 'Test body', + }; + }, + { + skip: (controls) => { + expectTypeOf(controls).toEqualTypeOf>(); + + return true; + }, + } + ); + }); + }); + + it('should infer an unknown record type in the provider function step controls', async () => { + workflow('without-schema', async ({ step }) => { + await step.email( + 'without-schema', + async (controls) => { + return { + subject: 'Test subject', + body: 'Test body', + }; + }, + { + providers: { + sendgrid: async ({ controls }) => { + expectTypeOf(controls).toEqualTypeOf>(); + + return { + ipPoolName: 'test', + }; + }, + }, + } + ); + }); + }); + + it('should infer an unknown record type in the workflow event payload', async () => { + workflow('without-schema', async ({ step, payload }) => { + await step.email('without-schema', async () => { + expectTypeOf(payload).toEqualTypeOf>(); + + return { + subject: 'Test subject', + body: 'Test body', + }; + }); + }); + }); + + it('should infer an unknown record type in the workflow event controls', async () => { + workflow('without-schema', async ({ step, controls }) => { + await step.email('without-schema', async () => { + expectTypeOf(controls).toEqualTypeOf>(); + + return { + subject: 'Test subject', + body: 'Test body', + }; + }); + }); + }); + + it('should infer an unknown record type in the custom step results', async () => { + workflow('without-schema', async ({ step }) => { + const result = await step.custom('without-schema', async () => { + return { + foo: 'bar', + }; + }); + + expectTypeOf(result).toMatchTypeOf>(); + }); + }); + }); + + describe('json-schema', () => { + const jsonSchema = { + type: 'object', + properties: { + foo: { type: 'string' }, + baz: { type: 'number' }, + }, + required: ['foo'], + additionalProperties: false, + } as const; + + it('should infer correct types in the step function step controls', async () => { + workflow('json-schema', async ({ step }) => { + await step.email( + 'json-schema', + async (controls) => { + expectTypeOf(controls).toEqualTypeOf<{ foo: string; baz?: number }>(); + + return { + subject: 'Test subject', + body: 'Test body', + }; + }, + { + controlSchema: jsonSchema, + } + ); + }); + + it('should infer correct types in the skip function step controls', async () => { + workflow('json-schema', async ({ step }) => { + await step.email( + 'json-schema', + async (controls) => { + return { + subject: 'Test subject', + body: 'Test body', + }; + }, + { + controlSchema: jsonSchema, + skip: (controls) => { + expectTypeOf(controls).toEqualTypeOf<{ foo: string; baz?: number }>(); + + return true; + }, + } + ); + }); + }); + + it('should infer correct types in the provider function step controls', async () => { + workflow('json-schema', async ({ step }) => { + await step.email( + 'json-schema', + async (controls) => { + return { + subject: 'Test subject', + body: 'Test body', + }; + }, + { + controlSchema: jsonSchema, + providers: { + sendgrid: async ({ controls }) => { + expectTypeOf(controls).toEqualTypeOf<{ foo: string; baz?: number }>(); + + return { + ipPoolName: 'test', + }; + }, + }, + } + ); + }); + }); + + it('should infer correct types in the workflow event payload', async () => { + workflow( + 'json-schema-validation', + async ({ step, payload }) => { + await step.email('json-schema-validation', async () => { + expectTypeOf(payload).toEqualTypeOf<{ foo: string; baz?: number }>(); + + return { + subject: 'Test subject', + body: 'Test body', + }; + }); + }, + { + payloadSchema: jsonSchema, + } + ); + }); + + it('should infer correct types in the workflow event controls', async () => { + workflow( + 'json-schema-validation', + async ({ step, controls }) => { + await step.email('json-schema-validation', async () => { + expectTypeOf(controls).toEqualTypeOf<{ foo: string; baz?: number }>(); + + return { + subject: 'Test subject', + body: 'Test body', + }; + }); + }, + { + controlSchema: jsonSchema, + } + ); + }); + + it('should infer correct types in the workflow event controls', async () => { + workflow( + 'json-schema-validation', + async ({ step, controls }) => { + await step.email('json-schema-validation', async () => { + expectTypeOf(controls).toEqualTypeOf<{ foo: string; baz?: number }>(); + + return { + subject: 'Test subject', + body: 'Test body', + }; + }); + }, + { + controlSchema: jsonSchema, + } + ); + }); + + it('should infer an unknown record type in the custom step results', async () => { + workflow('without-schema', async ({ step }) => { + const result = await step.custom( + 'without-schema', + async () => { + return { + foo: 'bar', + }; + }, + { + outputSchema: jsonSchema, + } + ); + + expectTypeOf(result).toMatchTypeOf<{ foo: string; baz?: number }>(); + }); + }); + }); + }); +}); diff --git a/packages/framework/src/resources/workflow/workflow.resource.ts b/packages/framework/src/resources/workflow/workflow.resource.ts index c6d868d6558..09bdc9e9453 100644 --- a/packages/framework/src/resources/workflow/workflow.resource.ts +++ b/packages/framework/src/resources/workflow/workflow.resource.ts @@ -45,7 +45,7 @@ export function workflow< if (validationResult.success === false) { throw new WorkflowPayloadInvalidError(workflowId, validationResult.errors); } - validatedData = validationResult.data; + validatedData = validationResult.data as T_PayloadValidated; } else { // This type coercion provides support to trigger Workflows without a payload schema validatedData = event.payload as unknown as T_PayloadValidated; diff --git a/packages/framework/src/types/import.types.ts b/packages/framework/src/types/import.types.ts new file mode 100644 index 00000000000..98c7d6d89e5 --- /dev/null +++ b/packages/framework/src/types/import.types.ts @@ -0,0 +1,34 @@ +export type ImportRequirement = { + /** + * The name of the dependency. + * + * This is a necessary duplicate as ESM does not provide a consistent API for + * reading the name of a dependency that can't be resolved. + * + * @example + * ```typescript + * 'my-dependency' + * ``` + */ + name: string; + /** + * The import of the dependency. This is necessary to ensure that the bundler will make + * the dependency available for usage during tree-shaking. + * + * @example + * ```typescript + * import('my-dependency') + * ``` + */ + import: Promise<{ default: unknown } & Record>; + /** + * The required exports of the dependency. The availability of these exports are + * checked by the import validator to verify the dependency is installed. + * + * @example + * ```typescript + * ['my-export'] + * ``` + */ + exports: readonly string[]; +}; diff --git a/packages/framework/src/types/schema.types.ts b/packages/framework/src/types/schema.types.ts deleted file mode 100644 index 2aa817aa8a0..00000000000 --- a/packages/framework/src/types/schema.types.ts +++ /dev/null @@ -1,67 +0,0 @@ -import type { JSONSchema, FromSchema as JsonSchemaInfer } from 'json-schema-to-ts'; -import zod from 'zod'; - -export type JsonSchema = JSONSchema; - -/** - * A schema used to validate a JSON object. - * - * Supported schemas: - * - JSONSchema - * - ZodSchema - */ -export type Schema = JsonSchema | zod.ZodSchema; - -/** - * Infer the type of a Schema for unvalidated data. - * - * The resulting type has default properties set to optional, - * reflecting the fact that the data is unvalidated and has - * not had default properties set. - * - * @example - * ```ts - * type MySchema = FromSchemaUnvalidated; - * ``` - */ -export type FromSchemaUnvalidated = - /* - * Handle each Schema's type inference individually until - * all Schema types are exhausted. - */ - - // JSONSchema - T extends JSONSchema - ? JsonSchemaInfer - : // ZodSchema - T extends zod.ZodSchema - ? zod.input - : // All schema types exhausted. - never; - -/** - * Infer the type of a Schema for validated data. - * - * The resulting type has default properties set to required, - * reflecting the fact that the data has been validated and - * default properties have been set. - * - * @example - * ```ts - * type MySchema = FromSchema; - * ``` - */ -export type FromSchema = - /* - * Handle each Schema's type inference individually until - * all Schema types are exhausted. - */ - - // JSONSchema - T extends JSONSchema - ? JsonSchemaInfer - : // ZodSchema - T extends zod.ZodSchema - ? zod.infer - : // All schema types exhausted. - never; diff --git a/packages/framework/src/types/schema.types/base.schema.types.test-d.ts b/packages/framework/src/types/schema.types/base.schema.types.test-d.ts new file mode 100644 index 00000000000..cb97f80b6b1 --- /dev/null +++ b/packages/framework/src/types/schema.types/base.schema.types.test-d.ts @@ -0,0 +1,59 @@ +import { describe, expectTypeOf, it } from 'vitest'; +import { z } from 'zod'; +import { FromSchema, FromSchemaUnvalidated } from './base.schema.types'; + +describe('FromSchema', () => { + it('should infer an unknown record type when no schema is provided', () => { + expectTypeOf>().toEqualTypeOf>(); + }); + + it('should infer a Json Schema type', () => { + const testJsonSchema = { + type: 'object', + properties: { + foo: { type: 'string', default: 'bar' }, + bar: { type: 'string' }, + }, + additionalProperties: false, + } as const; + + expectTypeOf>().toEqualTypeOf<{ foo: string; bar?: string }>(); + }); + + it('should infer a Zod Schema type', () => { + const testZodSchema = z.object({ + foo: z.string().default('bar'), + bar: z.string().optional(), + }); + + expectTypeOf>().toEqualTypeOf<{ foo: string; bar?: string }>(); + }); +}); + +describe('FromSchemaUnvalidated', () => { + it('should infer an unknown record type when no schema is provided', () => { + expectTypeOf>().toEqualTypeOf>(); + }); + + it('should infer a Json Schema type', () => { + const testJsonSchema = { + type: 'object', + properties: { + foo: { type: 'string', default: 'bar' }, + bar: { type: 'string' }, + }, + additionalProperties: false, + } as const; + + expectTypeOf>().toEqualTypeOf<{ foo?: string; bar?: string }>(); + }); + + it('should infer a Zod Schema type', () => { + const testZodSchema = z.object({ + foo: z.string().default('bar'), + bar: z.string().optional(), + }); + + expectTypeOf>().toEqualTypeOf<{ foo?: string; bar?: string }>(); + }); +}); diff --git a/packages/framework/src/types/schema.types/base.schema.types.ts b/packages/framework/src/types/schema.types/base.schema.types.ts new file mode 100644 index 00000000000..d61861a5af3 --- /dev/null +++ b/packages/framework/src/types/schema.types/base.schema.types.ts @@ -0,0 +1,53 @@ +import { JsonSchema, InferJsonSchema } from './json.schema.types'; +import { ZodSchemaMinimal, InferZodSchema } from './zod.schema.types'; + +/** + * A schema used to validate a JSON object. + */ +export type Schema = JsonSchema | ZodSchemaMinimal; + +/** + * Main utility type for schema inference + * + * @param T - The Schema to infer the type of. + * @param Options - Configuration options for the type inference. The `validated` flag determines whether the schema has been validated. If `validated` is true, all properties are required unless specified otherwise. If false, properties with default values are optional. + */ +type InferSchema = + | InferJsonSchema + | InferZodSchema + | never extends infer U + ? // If all inferred types are `never`, return an unknown record + [U] extends [never] + ? Record + : U extends Record + ? U + : Record + : Record; + +/** + * Infer the type of a Schema for unvalidated data. + * + * The resulting type has default properties set to optional, + * reflecting the fact that the data is unvalidated and has + * not had default properties set. + * + * @example + * ```ts + * type MySchema = FromSchemaUnvalidated; + * ``` + */ +export type FromSchemaUnvalidated = InferSchema; + +/** + * Infer the type of a Schema for validated data. + * + * The resulting type has default properties set to required, + * reflecting the fact that the data has been validated and + * default properties have been set. + * + * @example + * ```ts + * type MySchema = FromSchema; + * ``` + */ +export type FromSchema> = InferSchema; diff --git a/packages/framework/src/types/schema.types/index.ts b/packages/framework/src/types/schema.types/index.ts new file mode 100644 index 00000000000..b312dd77e4d --- /dev/null +++ b/packages/framework/src/types/schema.types/index.ts @@ -0,0 +1,3 @@ +export type { JsonSchema } from './json.schema.types'; +export type { ZodSchemaMinimal, ZodSchema } from './zod.schema.types'; +export type { Schema, FromSchema, FromSchemaUnvalidated } from './base.schema.types'; diff --git a/packages/framework/src/types/schema.types/json.schema.types.test-d.ts b/packages/framework/src/types/schema.types/json.schema.types.test-d.ts new file mode 100644 index 00000000000..25522ef5f43 --- /dev/null +++ b/packages/framework/src/types/schema.types/json.schema.types.test-d.ts @@ -0,0 +1,42 @@ +import { describe, expectTypeOf, it } from 'vitest'; +import { InferJsonSchema, JsonSchema } from './json.schema.types'; + +describe('JsonSchema types', () => { + const testSchema = { + type: 'object', + properties: { + foo: { type: 'string', default: 'bar' }, + bar: { type: 'string' }, + }, + additionalProperties: false, + } as const satisfies JsonSchema; + + describe('validated data', () => { + it('should compile when the expected properties are provided', () => { + expectTypeOf>().toEqualTypeOf<{ + foo: string; + bar?: string; + }>(); + }); + + it('should not compile when the schema is not a ClassSchema', () => { + expectTypeOf>().toEqualTypeOf(); + }); + + it('should not compile when a property does not match the expected type', () => { + // @ts-expect-error - Type 'number' is not assignable to type 'string'. + expectTypeOf>().toEqualTypeOf<{ + foo: number; + }>(); + }); + }); + + describe('unvalidated data', () => { + it('should keep the defaulted properties optional', () => { + expectTypeOf>().toEqualTypeOf<{ + foo?: string; + bar?: string; + }>(); + }); + }); +}); diff --git a/packages/framework/src/types/schema.types/json.schema.types.ts b/packages/framework/src/types/schema.types/json.schema.types.ts new file mode 100644 index 00000000000..789edf7683e --- /dev/null +++ b/packages/framework/src/types/schema.types/json.schema.types.ts @@ -0,0 +1,36 @@ +import type { JSONSchema, FromSchema as JsonSchemaInfer } from 'json-schema-to-ts'; + +/** + * A JSON schema. + */ +export type JsonSchema = Exclude; + +/** + * Infer the data type of a JsonSchema. + * + * @param T - The `JsonSchema` to infer the data type of. + * @param Options - Configuration options for the type inference. The `validated` flag determines whether the schema has been validated. If `validated` is true, all properties are required unless specified otherwise. If false, properties with default values are optional. + * + * @returns The inferred type. + * + * @example + * ```ts + * const mySchema = { + * type: 'object', + * properties: { + * name: { type: 'string' }, + * email: { type: 'string' }, + * }, + * required: ['name'], + * additionalProperties: false, + * } as const satisfies JsonSchema; + * + * // has type { name: string, email?: string } + * type MySchema = InferJsonSchema; + * ``` + */ +export type InferJsonSchema = T extends JsonSchema + ? Options['validated'] extends true + ? JsonSchemaInfer + : JsonSchemaInfer + : never; diff --git a/packages/framework/src/types/schema.types/zod.schema.types.test-d.ts b/packages/framework/src/types/schema.types/zod.schema.types.test-d.ts new file mode 100644 index 00000000000..dee4a87c08f --- /dev/null +++ b/packages/framework/src/types/schema.types/zod.schema.types.test-d.ts @@ -0,0 +1,39 @@ +import { describe, expectTypeOf, it } from 'vitest'; +import { z } from 'zod'; +import { InferZodSchema } from './zod.schema.types'; + +describe('ZodSchema', () => { + const testSchema = z.object({ + foo: z.string().default('bar'), + bar: z.string().optional(), + }); + + describe('validated data', () => { + it('should compile when the expected properties are provided', () => { + expectTypeOf>().toEqualTypeOf<{ + foo: string; + bar?: string; + }>(); + }); + + it('should not compile when the schema is not a ClassSchema', () => { + expectTypeOf>().toEqualTypeOf(); + }); + + it('should not compile when a property does not match the expected type', () => { + // @ts-expect-error - Type 'number' is not assignable to type 'string'. + expectTypeOf>().toEqualTypeOf<{ + foo: number; + }>(); + }); + }); + + describe('unvalidated data', () => { + it('should keep the defaulted properties optional', () => { + expectTypeOf>().toEqualTypeOf<{ + foo?: string; + bar?: string; + }>(); + }); + }); +}); diff --git a/packages/framework/src/types/schema.types/zod.schema.types.ts b/packages/framework/src/types/schema.types/zod.schema.types.ts new file mode 100644 index 00000000000..67655b8f528 --- /dev/null +++ b/packages/framework/src/types/schema.types/zod.schema.types.ts @@ -0,0 +1,42 @@ +import zod from 'zod'; + +export type ZodSchema = zod.ZodType; + +/** + * A minimal ZodSchema type. + * + * It is necessary to define a minimal ZodSchema type to enable correct inference + * when Zod is not available, as Typescript doesn't support detection of module + * availability via `typeof import('zod')`. + */ +export type ZodSchemaMinimal = { + readonly safeParseAsync: unknown; +}; + +/** + * Infer the data type of a ZodSchema. + * + * @param T - The ZodSchema to infer the data type of. + * @param Options - Configuration options for the type inference. The `validated` flag determines whether the schema has been validated. If `validated` is true, all properties are required unless specified otherwise. If false, properties with default values are optional. + * + * @example + * ```ts + * const mySchema = z.object({ + * name: z.string(), + * email: z.string().optional(), + * }); + * + * // has type { name: string, email?: string } + * type MySchema = InferZodSchema; + * ``` + */ +export type InferZodSchema = + // Firstly, narrow to the minimal schema type without using the `zod` import + T extends ZodSchemaMinimal + ? // Secondly, narrow to the Zod type to provide type-safety to `zod.infer` and `zod.input` + T extends ZodSchema + ? Options['validated'] extends true + ? zod.infer + : zod.input + : never + : never; diff --git a/packages/framework/src/types/util.types.ts b/packages/framework/src/types/util.types.ts index 0246e75632b..0e5fc0a8f9a 100644 --- a/packages/framework/src/types/util.types.ts +++ b/packages/framework/src/types/util.types.ts @@ -1,3 +1,8 @@ +/* + * THIS FILE SHOULD NOT DEPEND ON ANY OTHER FILES. + * IT SHOULD ONLY CONTAIN UTILITY TYPES. + */ + /** * A type that represents either `A` or `B`. Shared properties retain their * types and unique properties are marked as optional. diff --git a/packages/framework/src/types/validator.types.ts b/packages/framework/src/types/validator.types.ts index 36826f8bf2b..933c39f8284 100644 --- a/packages/framework/src/types/validator.types.ts +++ b/packages/framework/src/types/validator.types.ts @@ -1,6 +1,8 @@ import type { ValidateFunction as AjvValidateFunction } from 'ajv'; import type { ParseReturnType } from 'zod'; -import type { Schema, JsonSchema, FromSchema, FromSchemaUnvalidated } from './schema.types'; +import type { Schema, FromSchema, FromSchemaUnvalidated } from './schema.types'; +import type { JsonSchema } from './schema.types/json.schema.types'; +import type { ImportRequirement } from './import.types'; export type ValidateFunction = AjvValidateFunction | ((data: T) => ParseReturnType); @@ -19,8 +21,7 @@ export type ValidateResult = data: T; }; -// eslint-disable-next-line @typescript-eslint/naming-convention -export interface Validator { +export type Validator = { validate: < T_Unvalidated extends Record = FromSchemaUnvalidated, T_Validated extends Record = FromSchema, @@ -28,6 +29,7 @@ export interface Validator { data: T_Unvalidated, schema: T_Schema ) => Promise>; - canHandle: (schema: Schema) => schema is T_Schema; + canHandle: (schema: Schema) => Promise; transformToJsonSchema: (schema: T_Schema) => Promise; -} + requiredImports: readonly ImportRequirement[]; +}; diff --git a/packages/framework/src/utils/import.utils.test.ts b/packages/framework/src/utils/import.utils.test.ts new file mode 100644 index 00000000000..ea08ba73fd2 --- /dev/null +++ b/packages/framework/src/utils/import.utils.test.ts @@ -0,0 +1,59 @@ +import { describe, it, expect } from 'vitest'; +import { checkDependencies } from './import.utils'; + +describe('import utils', () => { + describe('checkDependencies', () => { + it('should not throw an error if all dependencies are installed', async () => { + await expect( + checkDependencies( + [{ name: 'typescript', import: import('typescript'), exports: ['tokenToString'] }], + 'test schema' + ) + ).resolves.not.toThrow(); + }); + + it('should throw an error if a single dependency is not installed', async () => { + await expect( + checkDependencies( + // @ts-expect-error - Cannot find module 'missing-random-dependency' or its corresponding type declarations. + [{ name: 'missing-random-dependency', import: import('missing-random-dependency'), exports: [] }], + 'test schema' + ) + ).rejects.toThrow( + 'Tried to use a test schema in @novu/framework without missing-random-dependency installed. Please install it by running `npm install missing-random-dependency`.' + ); + }); + + it('should throw an error if multiple dependencies are not installed', async () => { + await expect( + checkDependencies( + [ + // @ts-expect-error - Cannot find module 'missing-random-dependency-1' or its corresponding type declarations. + { name: 'missing-random-dependency-1', import: import('missing-random-dependency-1'), exports: [] }, + // @ts-expect-error - Cannot find module 'missing-random-dependency-2' or its corresponding type declarations. + { name: 'missing-random-dependency-2', import: import('missing-random-dependency-2'), exports: [] }, + ], + 'test schema' + ) + ).rejects.toThrow( + 'Tried to use a test schema in @novu/framework without missing-random-dependency-1, missing-random-dependency-2 installed. Please install them by running `npm install missing-random-dependency-1 missing-random-dependency-2`.' + ); + }); + + it('should throw an error listing a single dependency that is not installed when using a root and non-root import', async () => { + await expect( + checkDependencies( + [ + // @ts-expect-error - Cannot find module 'missing-random-dependency' or its corresponding type declarations. + { name: 'missing-random-dependency', import: import('missing-random-dependency'), exports: [] }, + // @ts-expect-error - Cannot find module 'missing-random-dependency/nested' or its corresponding type declarations. + { name: 'missing-random-dependency', import: import('missing-random-dependency/nested'), exports: [] }, + ], + 'test schema' + ) + ).rejects.toThrow( + 'Tried to use a test schema in @novu/framework without missing-random-dependency installed. Please install it by running `npm install missing-random-dependency`.' + ); + }); + }); +}); diff --git a/packages/framework/src/utils/import.utils.ts b/packages/framework/src/utils/import.utils.ts new file mode 100644 index 00000000000..e5684c2575b --- /dev/null +++ b/packages/framework/src/utils/import.utils.ts @@ -0,0 +1,38 @@ +import { MissingDependencyError } from '../errors/import.errors'; +import type { ImportRequirement } from '../types/import.types'; + +/** + * Check if the required dependencies are installed and throw an error if not. + * + * @param dependencies - The list of dependencies to check + * @param usageReason - The usage of the dependencies + */ +export const checkDependencies = async ( + dependencies: readonly ImportRequirement[], + usageReason: string +): Promise => { + const missingDependencies = new Set(); + const results = await Promise.allSettled(dependencies.map((dep) => dep.import)); + + results.forEach((result, index) => { + const dep = dependencies[index]; + if (result.status === 'fulfilled') { + const hasAllExports = dep.exports.every((exportName) => result.value[exportName] !== undefined); + + /* + * First way that a dependency isn't available is if the import succeeds + * but the necessary exports are not available. + */ + if (!hasAllExports) { + missingDependencies.add(dep.name); + } + } else { + // Second way that a dependency isn't available is if the import fails. + missingDependencies.add(dep.name); + } + }); + + if (missingDependencies.size > 0) { + throw new MissingDependencyError(usageReason, Array.from(missingDependencies)); + } +}; diff --git a/packages/framework/src/validators/base.validator.ts b/packages/framework/src/validators/base.validator.ts index 3a7f170a634..96acecdb135 100644 --- a/packages/framework/src/validators/base.validator.ts +++ b/packages/framework/src/validators/base.validator.ts @@ -1,4 +1,4 @@ -import type { FromSchema, FromSchemaUnvalidated, JsonSchema, Schema } from '../types/schema.types'; +import type { FromSchema, FromSchemaUnvalidated, Schema, JsonSchema, ZodSchema } from '../types/schema.types'; import type { ValidateResult } from '../types/validator.types'; import { JsonSchemaValidator } from './json-schema.validator'; import { ZodValidator } from './zod.validator'; @@ -6,6 +6,13 @@ import { ZodValidator } from './zod.validator'; const zodValidator = new ZodValidator(); const jsonSchemaValidator = new JsonSchemaValidator(); +/** + * Validate data against a schema. + * + * @param schema - The schema to validate the data against. + * @param data - The data to validate. + * @returns The validated data. + */ export const validateData = async < T_Schema extends Schema = Schema, T_Unvalidated extends Record = FromSchemaUnvalidated, @@ -14,20 +21,31 @@ export const validateData = async < schema: T_Schema, data: T_Unvalidated ): Promise> => { - if (zodValidator.canHandle(schema)) { - return zodValidator.validate(data, schema); - } else if (jsonSchemaValidator.canHandle(schema)) { - return jsonSchemaValidator.validate(data, schema); + /** + * TODO: Replace type coercion with async type guard when available. + * + * @see https://github.com/microsoft/typescript/issues/37681 + */ + if (await zodValidator.canHandle(schema)) { + return zodValidator.validate(data, schema as ZodSchema); + } else if (await jsonSchemaValidator.canHandle(schema)) { + return jsonSchemaValidator.validate(data, schema as JsonSchema); } throw new Error('Invalid schema'); }; +/** + * Transform a schema to a JSON schema. + * + * @param schema - The schema to transform. + * @returns The transformed JSON schema. + */ export const transformSchema = async (schema: Schema): Promise => { - if (zodValidator.canHandle(schema)) { - return zodValidator.transformToJsonSchema(schema); - } else if (jsonSchemaValidator.canHandle(schema)) { - return jsonSchemaValidator.transformToJsonSchema(schema); + if (await zodValidator.canHandle(schema)) { + return zodValidator.transformToJsonSchema(schema as ZodSchema); + } else if (await jsonSchemaValidator.canHandle(schema)) { + return jsonSchemaValidator.transformToJsonSchema(schema as JsonSchema); } throw new Error('Invalid schema'); diff --git a/packages/framework/src/validators/json-schema.validator.ts b/packages/framework/src/validators/json-schema.validator.ts index 2a5446d7a9a..22e8ede605d 100644 --- a/packages/framework/src/validators/json-schema.validator.ts +++ b/packages/framework/src/validators/json-schema.validator.ts @@ -2,10 +2,18 @@ import Ajv from 'ajv'; import type { ErrorObject, ValidateFunction as AjvValidateFunction } from 'ajv'; import addFormats from 'ajv-formats'; import type { ValidateResult, Validator } from '../types/validator.types'; -import type { FromSchema, FromSchemaUnvalidated, JsonSchema, Schema } from '../types/schema.types'; +import type { FromSchema, FromSchemaUnvalidated, Schema, JsonSchema } from '../types/schema.types'; import { cloneData } from '../utils/clone.utils'; +import { checkDependencies } from '../utils/import.utils'; +import { ImportRequirement } from '../types/import.types'; export class JsonSchemaValidator implements Validator { + /** + * Json schema validation has no required dependencies as they are included in + * the `@novu/framework` package dependencies. + */ + readonly requiredImports: readonly ImportRequirement[] = []; + private readonly ajv: Ajv; /** @@ -27,15 +35,18 @@ export class JsonSchemaValidator implements Validator { this.compiledSchemas = new Map(); } - canHandle(schema: Schema): schema is JsonSchema { - if (typeof schema === 'boolean') return false; + async canHandle(schema: Schema): Promise { + const canHandle = + (schema as JsonSchema).type === 'object' || + !!(schema as JsonSchema).anyOf || + !!(schema as JsonSchema).allOf || + !!(schema as JsonSchema).oneOf; + + if (canHandle) { + await checkDependencies(this.requiredImports, 'json-schema'); + } - return ( - (schema as Exclude).type === 'object' || - !!(schema as Exclude).anyOf || - !!(schema as Exclude).allOf || - !!(schema as Exclude).oneOf - ); + return canHandle; } async validate< diff --git a/packages/framework/src/validators/validator.test.ts b/packages/framework/src/validators/validator.test.ts index c52531a19e1..b43a32c0316 100644 --- a/packages/framework/src/validators/validator.test.ts +++ b/packages/framework/src/validators/validator.test.ts @@ -1,7 +1,7 @@ import { describe, it, expect } from 'vitest'; -import { ZodSchema, z } from 'zod'; +import { z } from 'zod'; import { validateData, transformSchema } from './base.validator'; -import { JsonSchema, Schema } from '../types/schema.types'; +import { Schema, ZodSchema, JsonSchema } from '../types/schema.types'; const schemas = ['zod', 'json'] as const; diff --git a/packages/framework/src/validators/zod.validator.ts b/packages/framework/src/validators/zod.validator.ts index e428b9bf82e..5db48cdc48a 100644 --- a/packages/framework/src/validators/zod.validator.ts +++ b/packages/framework/src/validators/zod.validator.ts @@ -1,19 +1,40 @@ -import { ZodSchema } from 'zod'; +import zod from 'zod'; -import type { FromSchema, FromSchemaUnvalidated, JsonSchema, Schema } from '../types/schema.types'; +import type { FromSchema, FromSchemaUnvalidated, Schema, JsonSchema, ZodSchemaMinimal } from '../types/schema.types'; import type { ValidateResult, Validator } from '../types/validator.types'; +import { checkDependencies } from '../utils/import.utils'; +import { ImportRequirement } from '../types/import.types'; -export class ZodValidator implements Validator { - canHandle(schema: Schema): schema is ZodSchema { - return (schema as ZodSchema).safeParseAsync !== undefined; +export class ZodValidator implements Validator { + readonly requiredImports: readonly ImportRequirement[] = [ + { + name: 'zod', + import: import('zod'), + exports: ['ZodType'], + }, + { + name: 'zod-to-json-schema', + import: import('zod-to-json-schema'), + exports: ['zodToJsonSchema'], + }, + ]; + + async canHandle(schema: Schema): Promise { + const canHandle = (schema as ZodSchemaMinimal).safeParseAsync !== undefined; + + if (canHandle) { + await checkDependencies(this.requiredImports, 'zod schema'); + } + + return canHandle; } async validate< - T_Schema extends ZodSchema = ZodSchema, + T_Schema extends zod.ZodType = zod.ZodType, T_Unvalidated = FromSchemaUnvalidated, T_Validated = FromSchema, >(data: T_Unvalidated, schema: T_Schema): Promise> { - const result = schema.safeParse(data); + const result = await schema.safeParseAsync(data); if (result.success) { return { success: true, data: result.data as T_Validated }; } else { @@ -27,21 +48,10 @@ export class ZodValidator implements Validator { } } - async transformToJsonSchema(schema: ZodSchema): Promise { - try { - const { zodToJsonSchema } = await import('zod-to-json-schema'); - - // TODO: zod-to-json-schema is not using JSONSchema7 - return zodToJsonSchema(schema) as JsonSchema; - } catch (error) { - if ((error as Error)?.message?.includes('Cannot find module')) { - // eslint-disable-next-line no-console - console.error( - 'Tried to use a zod schema in @novu/framework without `zod-to-json-schema` installed. ' + - 'Please install it by running `npm install zod-to-json-schema`.' - ); - } - throw error; - } + async transformToJsonSchema(schema: zod.ZodType): Promise { + const { zodToJsonSchema } = await import('zod-to-json-schema'); + + // TODO: zod-to-json-schema is not using JSONSchema7 + return zodToJsonSchema(schema) as JsonSchema; } } From 3eb118a8681a5fd5c5b698115d04a4683ffe3b24 Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Mon, 11 Nov 2024 00:35:03 +0100 Subject: [PATCH 19/56] docs(import.types): clarify dependency import comment --- packages/framework/src/types/import.types.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/framework/src/types/import.types.ts b/packages/framework/src/types/import.types.ts index 98c7d6d89e5..6cabd1807f0 100644 --- a/packages/framework/src/types/import.types.ts +++ b/packages/framework/src/types/import.types.ts @@ -12,8 +12,8 @@ export type ImportRequirement = { */ name: string; /** - * The import of the dependency. This is necessary to ensure that the bundler will make - * the dependency available for usage during tree-shaking. + * The import of the dependency. An explicit `import()` call is necessary to ensure + * that the bundler will make the dependency available for usage during tree-shaking. * * @example * ```typescript From 8049177a24fee2f2a86504ca2e79d2b22256467b Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Mon, 11 Nov 2024 00:45:29 +0100 Subject: [PATCH 20/56] refactor(validators): update type imports and schema names --- .../src/validators/json-schema.validator.ts | 3 +-- .../framework/src/validators/zod.validator.ts | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/framework/src/validators/json-schema.validator.ts b/packages/framework/src/validators/json-schema.validator.ts index 22e8ede605d..4f1cf969eb6 100644 --- a/packages/framework/src/validators/json-schema.validator.ts +++ b/packages/framework/src/validators/json-schema.validator.ts @@ -43,7 +43,7 @@ export class JsonSchemaValidator implements Validator { !!(schema as JsonSchema).oneOf; if (canHandle) { - await checkDependencies(this.requiredImports, 'json-schema'); + await checkDependencies(this.requiredImports, 'JSON schema'); } return canHandle; @@ -63,7 +63,6 @@ export class JsonSchemaValidator implements Validator { // ajv mutates the data, so we need to clone it to avoid side effects const clonedData = cloneData(data); - // const valid = validateFn(data); const valid = validateFn(clonedData); if (valid) { diff --git a/packages/framework/src/validators/zod.validator.ts b/packages/framework/src/validators/zod.validator.ts index 5db48cdc48a..d6cd31a1880 100644 --- a/packages/framework/src/validators/zod.validator.ts +++ b/packages/framework/src/validators/zod.validator.ts @@ -1,11 +1,16 @@ -import zod from 'zod'; - -import type { FromSchema, FromSchemaUnvalidated, Schema, JsonSchema, ZodSchemaMinimal } from '../types/schema.types'; +import type { + FromSchema, + FromSchemaUnvalidated, + Schema, + JsonSchema, + ZodSchemaMinimal, + ZodSchema, +} from '../types/schema.types'; import type { ValidateResult, Validator } from '../types/validator.types'; import { checkDependencies } from '../utils/import.utils'; import { ImportRequirement } from '../types/import.types'; -export class ZodValidator implements Validator { +export class ZodValidator implements Validator { readonly requiredImports: readonly ImportRequirement[] = [ { name: 'zod', @@ -23,14 +28,14 @@ export class ZodValidator implements Validator { const canHandle = (schema as ZodSchemaMinimal).safeParseAsync !== undefined; if (canHandle) { - await checkDependencies(this.requiredImports, 'zod schema'); + await checkDependencies(this.requiredImports, 'Zod schema'); } return canHandle; } async validate< - T_Schema extends zod.ZodType = zod.ZodType, + T_Schema extends ZodSchema = ZodSchema, T_Unvalidated = FromSchemaUnvalidated, T_Validated = FromSchema, >(data: T_Unvalidated, schema: T_Schema): Promise> { @@ -48,7 +53,7 @@ export class ZodValidator implements Validator { } } - async transformToJsonSchema(schema: zod.ZodType): Promise { + async transformToJsonSchema(schema: ZodSchema): Promise { const { zodToJsonSchema } = await import('zod-to-json-schema'); // TODO: zod-to-json-schema is not using JSONSchema7 From 0d0b31badacac57d3f5e59ad8715036334962956 Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Mon, 11 Nov 2024 00:52:21 +0100 Subject: [PATCH 21/56] refactor(types): update import to use 'type' keyword --- .../framework/src/types/schema.types/base.schema.types.ts | 4 ++-- .../framework/src/types/schema.types/zod.schema.types.ts | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/framework/src/types/schema.types/base.schema.types.ts b/packages/framework/src/types/schema.types/base.schema.types.ts index d61861a5af3..88d6b5a0c3b 100644 --- a/packages/framework/src/types/schema.types/base.schema.types.ts +++ b/packages/framework/src/types/schema.types/base.schema.types.ts @@ -1,5 +1,5 @@ -import { JsonSchema, InferJsonSchema } from './json.schema.types'; -import { ZodSchemaMinimal, InferZodSchema } from './zod.schema.types'; +import type { JsonSchema, InferJsonSchema } from './json.schema.types'; +import type { ZodSchemaMinimal, InferZodSchema } from './zod.schema.types'; /** * A schema used to validate a JSON object. diff --git a/packages/framework/src/types/schema.types/zod.schema.types.ts b/packages/framework/src/types/schema.types/zod.schema.types.ts index 67655b8f528..f506c6a934f 100644 --- a/packages/framework/src/types/schema.types/zod.schema.types.ts +++ b/packages/framework/src/types/schema.types/zod.schema.types.ts @@ -1,6 +1,6 @@ -import zod from 'zod'; +import type { ZodType, infer as ZodInfer, input as ZodInput } from 'zod'; -export type ZodSchema = zod.ZodType; +export type ZodSchema = ZodType; /** * A minimal ZodSchema type. @@ -36,7 +36,7 @@ export type InferZodSchema = ? // Secondly, narrow to the Zod type to provide type-safety to `zod.infer` and `zod.input` T extends ZodSchema ? Options['validated'] extends true - ? zod.infer - : zod.input + ? ZodInfer + : ZodInput : never : never; From 15b9ab4f9cc3ecc49b4501764e12acc0b5d3439f Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Mon, 11 Nov 2024 00:53:29 +0100 Subject: [PATCH 22/56] docs(zod): add comment for ZodSchema type --- packages/framework/src/types/schema.types/zod.schema.types.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/framework/src/types/schema.types/zod.schema.types.ts b/packages/framework/src/types/schema.types/zod.schema.types.ts index f506c6a934f..fd3f0ae9acb 100644 --- a/packages/framework/src/types/schema.types/zod.schema.types.ts +++ b/packages/framework/src/types/schema.types/zod.schema.types.ts @@ -1,5 +1,8 @@ import type { ZodType, infer as ZodInfer, input as ZodInput } from 'zod'; +/** + * A Zod schema. + */ export type ZodSchema = ZodType; /** From ff1577e219f099ea8fa383f449c18adcd714d0a0 Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Mon, 11 Nov 2024 00:56:40 +0100 Subject: [PATCH 23/56] fix(framework): Add dependency check import utilities --- packages/framework/src/client.test.ts | 2 + packages/framework/src/client.ts | 2 +- .../framework/src/client.validation.test.ts | 565 +------ .../src/constants/error.constants.ts | 1 + packages/framework/src/errors/base.errors.ts | 2 +- .../framework/src/errors/import.errors.ts | 16 + .../workflow/discover-action-step-factory.ts | 4 +- .../workflow/discover-channel-step-factory.ts | 14 +- .../workflow/discover-custom-step-factory.ts | 13 +- .../resources/workflow/discover-providers.ts | 9 +- .../workflow/workflow.resource.test-d.ts | 281 ++++ .../resources/workflow/workflow.resource.ts | 2 +- packages/framework/src/types/import.types.ts | 34 + packages/framework/src/types/schema.types.ts | 88 - .../schema.types/base.schema.types.test-d.ts | 77 + .../types/schema.types/base.schema.types.ts | 55 + .../schema.types/class.schema.types.test-d.ts | 42 + .../types/schema.types/class.schema.types.ts | 44 + .../framework/src/types/schema.types/index.ts | 4 + .../schema.types/json.schema.types.test-d.ts | 42 + .../types/schema.types/json.schema.types.ts | 36 + .../schema.types/zod.schema.types.test-d.ts | 39 + .../types/schema.types/zod.schema.types.ts | 42 + packages/framework/src/types/util.types.ts | 5 + .../framework/src/types/validator.types.ts | 12 +- .../framework/src/utils/import.utils.test.ts | 59 + packages/framework/src/utils/import.utils.ts | 37 + .../src/validators/base.validator.ts | 51 +- .../validators/class-validator.validator.ts | 170 +- .../src/validators/json-schema.validator.ts | 29 +- .../src/validators/validator.test.ts | 10 +- .../framework/src/validators/zod.validator.ts | 56 +- pnpm-lock.yaml | 1480 ++++++++--------- 33 files changed, 1814 insertions(+), 1509 deletions(-) create mode 100644 packages/framework/src/errors/import.errors.ts create mode 100644 packages/framework/src/resources/workflow/workflow.resource.test-d.ts create mode 100644 packages/framework/src/types/import.types.ts delete mode 100644 packages/framework/src/types/schema.types.ts create mode 100644 packages/framework/src/types/schema.types/base.schema.types.test-d.ts create mode 100644 packages/framework/src/types/schema.types/base.schema.types.ts create mode 100644 packages/framework/src/types/schema.types/class.schema.types.test-d.ts create mode 100644 packages/framework/src/types/schema.types/class.schema.types.ts create mode 100644 packages/framework/src/types/schema.types/index.ts create mode 100644 packages/framework/src/types/schema.types/json.schema.types.test-d.ts create mode 100644 packages/framework/src/types/schema.types/json.schema.types.ts create mode 100644 packages/framework/src/types/schema.types/zod.schema.types.test-d.ts create mode 100644 packages/framework/src/types/schema.types/zod.schema.types.ts create mode 100644 packages/framework/src/utils/import.utils.test.ts create mode 100644 packages/framework/src/utils/import.utils.ts diff --git a/packages/framework/src/client.test.ts b/packages/framework/src/client.test.ts index a80064e2359..b91915df1e4 100644 --- a/packages/framework/src/client.test.ts +++ b/packages/framework/src/client.test.ts @@ -313,6 +313,8 @@ describe('Novu Client', () => { if (stepChat === undefined) throw new Error('stepEmail is undefined'); expect(stepChat.type).toBe('chat'); expect(stepChat.code).toContain(`body: "Test Body"`); + console.log(stepChat.providers); + // await new Promise((resolve) => setTimeout(resolve, 1000)); expect(stepChat.providers[0].code).toContain(`type: "plain_text"`); expect(stepChat.providers[0].code).toContain(`text: "Pretty Header"`); }); diff --git a/packages/framework/src/client.ts b/packages/framework/src/client.ts index 3a5db6c9ece..83c423c24d8 100644 --- a/packages/framework/src/client.ts +++ b/packages/framework/src/client.ts @@ -195,7 +195,7 @@ export class Client { throw new Error(`Invalid component: '${component}'`); } } else { - return result.data; + return result.data as T; } } diff --git a/packages/framework/src/client.validation.test.ts b/packages/framework/src/client.validation.test.ts index 0860ba294f7..7326ed80de6 100644 --- a/packages/framework/src/client.validation.test.ts +++ b/packages/framework/src/client.validation.test.ts @@ -1,7 +1,4 @@ -/* eslint-disable no-param-reassign */ import { expect, it, describe, beforeEach } from 'vitest'; -import { z } from 'zod'; -import { IsNumber, IsOptional, IsString } from 'class-validator'; import { Client } from './client'; import { workflow } from './resources/workflow'; import { ExecutionStateControlsInvalidError } from './errors'; @@ -14,533 +11,77 @@ describe('validation', () => { client = new Client({ secretKey: 'some-secret-key' }); }); - describe('zod', () => { - const zodSchema = z.object({ - foo: z.string(), - baz: z.number(), - }); - - it('should infer types in the step controls', async () => { - workflow('zod-validation', async ({ step }) => { + const jsonSchema = { + type: 'object', + properties: { + foo: { type: 'string' }, + baz: { type: 'number' }, + }, + required: ['foo', 'baz'], + additionalProperties: false, + } as const; + + it('should transform a JSON schema to a valid schema during discovery', async () => { + await client.addWorkflows([ + workflow('json-schema-validation', async ({ step }) => { await step.email( - 'zod-validation', - async (controls) => { - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - controls.foo = 123; - // @ts-expect-error - Type 'string' is not assignable to type 'number'. - controls.baz = '123'; - - return { - subject: 'Test subject', - body: 'Test body', - }; - }, + 'json-schema-validation', + async () => ({ + subject: 'Test subject', + body: 'Test body', + }), { - controlSchema: zodSchema, - skip: (controls) => { - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - controls.foo = 123; - // @ts-expect-error - Type 'string' is not assignable to type 'number'. - controls.baz = '123'; - - return true; - }, - providers: { - sendgrid: async ({ controls, outputs }) => { - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - controls.foo = 123; - // @ts-expect-error - Type 'string' is not assignable to type 'number'. - controls.baz = '123'; - - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - outputs.body = 123; - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - outputs.subject = 123; - - return { - ipPoolName: 'test', - }; - }, - }, + controlSchema: jsonSchema, } ); - }); - }); - - it('should infer types in the workflow payload', async () => { - workflow( - 'zod-validation', - async ({ step, payload }) => { - await step.email('zod-validation', async () => { - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - payload.foo = 123; - // @ts-expect-error - Type 'string' is not assignable to type 'number'. - payload.baz = '123'; - - return { - subject: 'Test subject', - body: 'Test body', - }; - }); - }, - { - payloadSchema: zodSchema, - } - ); - }); - - it('should infer types in the workflow controls', async () => { - workflow( - 'zod-validation', - async ({ step, controls }) => { - await step.email('zod-validation', async () => { - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - controls.foo = 123; - // @ts-expect-error - Type 'string' is not assignable to type 'number'. - controls.baz = '123'; - - return { - subject: 'Test subject', - body: 'Test body', - }; - }); - }, - { - controlSchema: zodSchema, - } - ); - }); - - it('should transform a zod schema to a json schema during discovery', async () => { - await client.addWorkflows([ - workflow('zod-validation', async ({ step }) => { - await step.email( - 'zod-validation', - async () => ({ - subject: 'Test subject', - body: 'Test body', - }), - { - controlSchema: zodSchema, - } - ); - }), - ]); - - const discoverResult = client.discover(); - const stepControlSchema = discoverResult.workflows[0].steps[0].controls.schema; + }), + ]); - expect(stepControlSchema).to.deep.include({ - additionalProperties: false, - properties: { - foo: { - type: 'string', - }, - baz: { - type: 'number', - }, - }, - required: ['foo', 'baz'], - type: 'object', - }); - }); - - it('should throw an error if a property is missing', async () => { - await client.addWorkflows([ - workflow('zod-validation', async ({ step }) => { - await step.email( - 'test-email', - async () => ({ - subject: 'Test subject', - body: 'Test body', - }), - { - controlSchema: zodSchema, - } - ); - }), - ]); + const discoverResult = client.discover(); + const stepControlSchema = discoverResult.workflows[0].steps[0].controls.schema; - try { - await client.executeWorkflow({ - action: PostActionEnum.EXECUTE, - workflowId: 'zod-validation', - controls: { - foo: '341', - }, - payload: {}, - stepId: 'test-email', - state: [], - subscriber: {}, - }); - } catch (error) { - expect(error).to.be.instanceOf(ExecutionStateControlsInvalidError); - expect((error as ExecutionStateControlsInvalidError).message).to.equal( - 'Workflow with id: `zod-validation` has an invalid state. Step with id: `test-email` has invalid `controls`. Please provide the correct step controls.' - ); - expect((error as ExecutionStateControlsInvalidError).data).to.deep.equal([ - { - message: 'Required', - path: '/baz', - }, - ]); - } - }); + expect(stepControlSchema).to.deep.include(jsonSchema); }); - describe('class-validator', () => { - class ClassValidatorSchema { - @IsString() - foo!: string; - @IsNumber() - @IsOptional() - baz?: number; - } - - it('should infer types in the step controls', async () => { - workflow('class-validator-validation', async ({ step }) => { - await step.email( - 'class-validator-validation', - async (controls) => { - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - controls.foo = 123; - // @ts-expect-error - Type 'string' is not assignable to type 'number'. - controls.baz = '123'; - - return { - subject: 'Test subject', - body: 'Test body', - }; - }, - { - controlSchema: ClassValidatorSchema, - skip: (controls) => { - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - controls.foo = 123; - // @ts-expect-error - Type 'string' is not assignable to type 'number'. - controls.baz = '123'; - - return true; - }, - providers: { - sendgrid: async ({ controls, outputs }) => { - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - controls.foo = 123; - // @ts-expect-error - Type 'string' is not assignable to type 'number'. - controls.baz = '123'; - - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - outputs.body = 123; - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - outputs.subject = 123; - - return { - ipPoolName: 'test', - }; - }, - }, - } - ); - }); - }); - - it('should infer types in the workflow payload', async () => { - workflow( - 'class-validator-validation', - async ({ step, payload }) => { - await step.email('class-validator-validation', async () => { - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - payload.foo = 123; - // @ts-expect-error - Type 'string' is not assignable to type 'number'. - payload.baz = '123'; - - return { - subject: 'Test subject', - body: 'Test body', - }; - }); - }, - { - payloadSchema: ClassValidatorSchema, - } - ); - }); - - it('should infer types in the workflow controls', async () => { - workflow( - 'class-validator-validation', - async ({ step, controls }) => { - await step.email('class-validator-validation', async () => { - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - controls.foo = 123; - // @ts-expect-error - Type 'string' is not assignable to type 'number'. - controls.baz = '123'; - - return { - subject: 'Test subject', - body: 'Test body', - }; - }); - }, - { - controlSchema: ClassValidatorSchema, - } - ); - }); - - it('should transform a class-validator schema to a json schema during discovery', async () => { - await client.addWorkflows([ - workflow('class-validator-validation', async ({ step }) => { - await step.email( - 'class-validator-validation', - async () => ({ - subject: 'Test subject', - body: 'Test body', - }), - { - controlSchema: ClassValidatorSchema, - } - ); - }), - ]); - - const discoverResult = client.discover(); - const stepControlSchema = discoverResult.workflows[0].steps[0].controls.schema; - - expect(stepControlSchema).to.deep.equal({ - additionalProperties: false, - properties: { - foo: { - type: 'string', - }, - baz: { - type: 'number', - }, - }, - required: ['foo'], - type: 'object', - }); - }); - - it('should throw an error if a property is missing', async () => { - await client.addWorkflows([ - workflow('class-validator-validation', async ({ step }) => { - await step.email( - 'test-email', - async () => ({ - subject: 'Test subject', - body: 'Test body', - }), - { - controlSchema: ClassValidatorSchema, - } - ); - }), - ]); - - try { - await client.executeWorkflow({ - action: PostActionEnum.EXECUTE, - workflowId: 'class-validator-validation', - controls: { - foo: '341', - }, - payload: {}, - stepId: 'test-email', - state: [], - subscriber: {}, - }); - } catch (error) { - expect(error).to.be.instanceOf(ExecutionStateControlsInvalidError); - expect((error as ExecutionStateControlsInvalidError).message).to.equal( - 'Workflow with id: `class-validator-validation` has an invalid state. Step with id: `test-email` has invalid `controls`. Please provide the correct step controls.' - ); - expect((error as ExecutionStateControlsInvalidError).data).to.deep.equal([ - { - message: 'Required', - path: '/baz', - }, - ]); - } - }); - }); - - describe('json-schema', () => { - const jsonSchema = { - type: 'object', - properties: { - foo: { type: 'string' }, - baz: { type: 'number' }, - }, - required: ['foo', 'baz'], - additionalProperties: false, - } as const; - - it('should infer types in the step controls', async () => { + it('should throw an error if a property is missing', async () => { + await client.addWorkflows([ workflow('json-schema-validation', async ({ step }) => { await step.email( - 'json-schema-validation', - async (controls) => { - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - controls.foo = 123; - // @ts-expect-error - Type 'string' is not assignable to type 'number'. - controls.baz = '123'; - - return { - subject: 'Test subject', - body: 'Test body', - }; - }, + 'test-email', + async () => ({ + subject: 'Test subject', + body: 'Test body', + }), { controlSchema: jsonSchema, - skip: (controls) => { - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - controls.foo = 123; - // @ts-expect-error - Type 'string' is not assignable to type 'number'. - controls.baz = '123'; - - return true; - }, - providers: { - sendgrid: async ({ controls, outputs }) => { - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - controls.foo = 123; - // @ts-expect-error - Type 'string' is not assignable to type 'number'. - controls.baz = '123'; - - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - outputs.body = 123; - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - outputs.subject = 123; - - return { - ipPoolName: 'test', - }; - }, - }, } ); - }); - }); - - it('should infer types in the workflow payload', async () => { - workflow( - 'json-schema-validation', - async ({ step, payload }) => { - await step.email('json-schema-validation', async () => { - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - payload.foo = 123; - // @ts-expect-error - Type 'string' is not assignable to type 'number'. - payload.baz = '123'; - - return { - subject: 'Test subject', - body: 'Test body', - }; - }); + }), + ]); + + try { + await client.executeWorkflow({ + action: PostActionEnum.EXECUTE, + workflowId: 'json-schema-validation', + controls: { + foo: '341', }, - { - payloadSchema: jsonSchema, - } + payload: {}, + stepId: 'test-email', + state: [], + subscriber: {}, + }); + } catch (error) { + expect(error).to.be.instanceOf(ExecutionStateControlsInvalidError); + expect((error as ExecutionStateControlsInvalidError).message).to.equal( + 'Workflow with id: `json-schema-validation` has an invalid state. Step with id: `test-email` has invalid `controls`. Please provide the correct step controls.' ); - }); - - it('should infer types in the workflow controls', async () => { - workflow( - 'json-schema-validation', - async ({ step, controls }) => { - await step.email('json-schema-validation', async () => { - // @ts-expect-error - Type 'number' is not assignable to type 'string'. - controls.foo = 123; - // @ts-expect-error - Type 'string' is not assignable to type 'number'. - controls.baz = '123'; - - return { - subject: 'Test subject', - body: 'Test body', - }; - }); - }, + expect((error as ExecutionStateControlsInvalidError).data).to.deep.equal([ { - controlSchema: jsonSchema, - } - ); - }); - - it('should transform a JSON schema to a valid schema during discovery', async () => { - await client.addWorkflows([ - workflow('json-schema-validation', async ({ step }) => { - await step.email( - 'json-schema-validation', - async () => ({ - subject: 'Test subject', - body: 'Test body', - }), - { - controlSchema: jsonSchema, - } - ); - }), - ]); - - const discoverResult = client.discover(); - const stepControlSchema = discoverResult.workflows[0].steps[0].controls.schema; - - expect(stepControlSchema).to.deep.include({ - additionalProperties: false, - properties: { - foo: { - type: 'string', - }, - baz: { - type: 'number', - }, + message: "must have required property 'baz'", + path: '', }, - required: ['foo', 'baz'], - type: 'object', - }); - }); - - it('should throw an error if a property is missing', async () => { - await client.addWorkflows([ - workflow('json-schema-validation', async ({ step }) => { - await step.email( - 'test-email', - async () => ({ - subject: 'Test subject', - body: 'Test body', - }), - { - controlSchema: jsonSchema, - } - ); - }), ]); - - try { - await client.executeWorkflow({ - action: PostActionEnum.EXECUTE, - workflowId: 'json-schema-validation', - controls: { - foo: '341', - }, - payload: {}, - stepId: 'test-email', - state: [], - subscriber: {}, - }); - } catch (error) { - expect(error).to.be.instanceOf(ExecutionStateControlsInvalidError); - expect((error as ExecutionStateControlsInvalidError).message).to.equal( - 'Workflow with id: `json-schema-validation` has an invalid state. Step with id: `test-email` has invalid `controls`. Please provide the correct step controls.' - ); - expect((error as ExecutionStateControlsInvalidError).data).to.deep.equal([ - { - message: "must have required property 'baz'", - path: '', - }, - ]); - } - }); + } }); }); diff --git a/packages/framework/src/constants/error.constants.ts b/packages/framework/src/constants/error.constants.ts index 03a6dc826db..7c86a63c4e3 100644 --- a/packages/framework/src/constants/error.constants.ts +++ b/packages/framework/src/constants/error.constants.ts @@ -11,6 +11,7 @@ export enum ErrorCodeEnum { EXECUTION_STATE_RESULT_INVALID_ERROR = 'ExecutionStateResultInvalidError', INVALID_ACTION_ERROR = 'InvalidActionError', METHOD_NOT_ALLOWED_ERROR = 'MethodNotAllowedError', + MISSING_DEPENDENCY_ERROR = 'MissingDependencyError', MISSING_SECRET_KEY_ERROR = 'MissingSecretKeyError', PROVIDER_EXECUTION_FAILED_ERROR = 'ProviderExecutionFailedError', PROVIDER_NOT_FOUND_ERROR = 'ProviderNotFoundError', diff --git a/packages/framework/src/errors/base.errors.ts b/packages/framework/src/errors/base.errors.ts index 9f0cb581833..d4318ded1e2 100644 --- a/packages/framework/src/errors/base.errors.ts +++ b/packages/framework/src/errors/base.errors.ts @@ -67,7 +67,7 @@ export abstract class ServerError extends FrameworkError { stack: cause.stack ?? message, }; } else { - super(`${message}: ${JSON.stringify(cause, null, 2)}`); + super(`${message}${cause ? `: ${JSON.stringify(cause, null, 2)}` : ''}`); this.data = { stack: message, }; diff --git a/packages/framework/src/errors/import.errors.ts b/packages/framework/src/errors/import.errors.ts new file mode 100644 index 00000000000..9b03553bddb --- /dev/null +++ b/packages/framework/src/errors/import.errors.ts @@ -0,0 +1,16 @@ +import { ErrorCodeEnum, HttpStatusEnum } from '../constants'; +import { ServerError } from './base.errors'; + +export class MissingDependencyError extends ServerError { + statusCode = HttpStatusEnum.INTERNAL_SERVER_ERROR; + code = ErrorCodeEnum.MISSING_DEPENDENCY_ERROR; + + constructor(usageReason: string, missingDependencies: string[]) { + const pronoun = missingDependencies.length === 1 ? 'it' : 'them'; + super( + `Tried to use a ${usageReason} in @novu/framework without ${missingDependencies.join( + ', ' + )} installed. Please install ${pronoun} by running \`npm install ${missingDependencies.join(' ')}\`.` + ); + } +} diff --git a/packages/framework/src/resources/workflow/discover-action-step-factory.ts b/packages/framework/src/resources/workflow/discover-action-step-factory.ts index 8b7d7d4fcca..1bf676d8614 100644 --- a/packages/framework/src/resources/workflow/discover-action-step-factory.ts +++ b/packages/framework/src/resources/workflow/discover-action-step-factory.ts @@ -1,6 +1,6 @@ import { ActionStepEnum } from '../../constants'; import { emptySchema } from '../../schemas'; -import type { Awaitable, DiscoverWorkflowOutput, Schema, ActionStep } from '../../types'; +import type { Awaitable, DiscoverWorkflowOutput, Schema, ActionStep, StepOptions, FromSchema } from '../../types'; import { transformSchema } from '../../validators'; import { discoverStep } from './discover-step'; @@ -32,7 +32,7 @@ export async function discoverActionStepFactory( }, resolve: resolve as (controls: Record) => Awaitable>, code: resolve.toString(), - options, + options: options as StepOptions, FromSchema>, providers: [], }); diff --git a/packages/framework/src/resources/workflow/discover-channel-step-factory.ts b/packages/framework/src/resources/workflow/discover-channel-step-factory.ts index 6b3fb0e5656..ecabdf530c3 100644 --- a/packages/framework/src/resources/workflow/discover-channel-step-factory.ts +++ b/packages/framework/src/resources/workflow/discover-channel-step-factory.ts @@ -1,6 +1,14 @@ import { ChannelStepEnum } from '../../constants'; import { emptySchema } from '../../schemas'; -import type { Awaitable, DiscoverStepOutput, DiscoverWorkflowOutput, Schema, ChannelStep } from '../../types'; +import type { + Awaitable, + DiscoverStepOutput, + DiscoverWorkflowOutput, + Schema, + ChannelStep, + StepOptions, + FromSchema, +} from '../../types'; import { transformSchema } from '../../validators'; import { discoverProviders } from './discover-providers'; import { discoverStep } from './discover-step'; @@ -32,14 +40,14 @@ export async function discoverChannelStepFactory( }, resolve: resolve as (controls: Record) => Awaitable>, code: resolve.toString(), - options, + options: options as StepOptions, FromSchema>, providers: [], }; await discoverStep(targetWorkflow, stepId, step); if (Object.keys(options.providers || {}).length > 0) { - discoverProviders(step, type as ChannelStepEnum, options.providers || {}); + await discoverProviders(step, type as ChannelStepEnum, options.providers || {}); } return { diff --git a/packages/framework/src/resources/workflow/discover-custom-step-factory.ts b/packages/framework/src/resources/workflow/discover-custom-step-factory.ts index 66a6d5ebf36..ebad260e5f2 100644 --- a/packages/framework/src/resources/workflow/discover-custom-step-factory.ts +++ b/packages/framework/src/resources/workflow/discover-custom-step-factory.ts @@ -1,5 +1,14 @@ import { emptySchema } from '../../schemas'; -import type { Awaitable, CustomStep, DiscoverWorkflowOutput, StepType, StepOutput } from '../../types'; +import type { + Awaitable, + CustomStep, + DiscoverWorkflowOutput, + StepType, + StepOutput, + StepOptions, + FromSchema, + Schema, +} from '../../types'; import { transformSchema } from '../../validators'; import { discoverStep } from './discover-step'; @@ -28,7 +37,7 @@ export async function discoverCustomStepFactory( }, resolve: resolve as (controls: Record) => Awaitable>, code: resolve.toString(), - options, + options: options as StepOptions, FromSchema>, providers: [], }); diff --git a/packages/framework/src/resources/workflow/discover-providers.ts b/packages/framework/src/resources/workflow/discover-providers.ts index 672c0766474..9329a08ce05 100644 --- a/packages/framework/src/resources/workflow/discover-providers.ts +++ b/packages/framework/src/resources/workflow/discover-providers.ts @@ -20,12 +20,13 @@ export async function discoverProviders( ): Promise { const channelSchemas = providerSchemas[channelType]; - Object.entries(providers).forEach(async ([type, resolve]) => { + const providerPromises = Object.entries(providers).map(async ([type, resolve]) => { // eslint-disable-next-line multiline-comment-style // TODO: fix the typing for `type` to use the keyof providerSchema[channelType] // @ts-expect-error - Element implicitly has an 'any' type because expression of type 'string' can't be used to index type const schemas = channelSchemas[type]; - step.providers.push({ + + return { type, code: resolve.toString(), resolve, @@ -33,6 +34,8 @@ export async function discoverProviders( schema: await transformSchema(schemas.output), unknownSchema: schemas.output, }, - }); + }; }); + + step.providers.push(...(await Promise.all(providerPromises))); } diff --git a/packages/framework/src/resources/workflow/workflow.resource.test-d.ts b/packages/framework/src/resources/workflow/workflow.resource.test-d.ts new file mode 100644 index 00000000000..e2a635019c2 --- /dev/null +++ b/packages/framework/src/resources/workflow/workflow.resource.test-d.ts @@ -0,0 +1,281 @@ +import { describe, expectTypeOf } from 'vitest'; +import { workflow } from '.'; +import { Subscriber } from '../../types'; + +describe('workflow function types', () => { + describe('event types', () => { + it('should have the expected subscriber type', () => { + workflow('without-schema', async ({ subscriber }) => { + expectTypeOf(subscriber).toEqualTypeOf(); + }); + }); + + it('should have the expected step functions', () => { + workflow('without-schema', async ({ step }) => { + expectTypeOf(step).toMatchTypeOf<{ + email: unknown; + sms: unknown; + push: unknown; + chat: unknown; + inApp: unknown; + digest: unknown; + delay: unknown; + custom: unknown; + }>(); + }); + }); + }); + + describe('without schema', () => { + it('should infer an unknown record type in the step function step controls', async () => { + workflow('without-schema', async ({ step }) => { + await step.email('without-schema', async (controls) => { + expectTypeOf(controls).toEqualTypeOf>(); + + return { + subject: 'Test subject', + body: 'Test body', + }; + }); + }); + }); + + it('should infer an unknown record type in the skip function step controls', async () => { + workflow('without-schema', async ({ step }) => { + await step.email( + 'without-schema', + async (controls) => { + return { + subject: 'Test subject', + body: 'Test body', + }; + }, + { + skip: (controls) => { + expectTypeOf(controls).toEqualTypeOf>(); + + return true; + }, + } + ); + }); + }); + + it('should infer an unknown record type in the provider function step controls', async () => { + workflow('without-schema', async ({ step }) => { + await step.email( + 'without-schema', + async (controls) => { + return { + subject: 'Test subject', + body: 'Test body', + }; + }, + { + providers: { + sendgrid: async ({ controls }) => { + expectTypeOf(controls).toEqualTypeOf>(); + + return { + ipPoolName: 'test', + }; + }, + }, + } + ); + }); + }); + + it('should infer an unknown record type in the workflow event payload', async () => { + workflow('without-schema', async ({ step, payload }) => { + await step.email('without-schema', async () => { + expectTypeOf(payload).toEqualTypeOf>(); + + return { + subject: 'Test subject', + body: 'Test body', + }; + }); + }); + }); + + it('should infer an unknown record type in the workflow event controls', async () => { + workflow('without-schema', async ({ step, controls }) => { + await step.email('without-schema', async () => { + expectTypeOf(controls).toEqualTypeOf>(); + + return { + subject: 'Test subject', + body: 'Test body', + }; + }); + }); + }); + + it('should infer an unknown record type in the custom step results', async () => { + workflow('without-schema', async ({ step }) => { + const result = await step.custom('without-schema', async () => { + return { + foo: 'bar', + }; + }); + + expectTypeOf(result).toMatchTypeOf>(); + }); + }); + }); + + describe('json-schema', () => { + const jsonSchema = { + type: 'object', + properties: { + foo: { type: 'string' }, + baz: { type: 'number' }, + }, + required: ['foo'], + additionalProperties: false, + } as const; + + it('should infer correct types in the step function step controls', async () => { + workflow('json-schema', async ({ step }) => { + await step.email( + 'json-schema', + async (controls) => { + expectTypeOf(controls).toEqualTypeOf<{ foo: string; baz?: number }>(); + + return { + subject: 'Test subject', + body: 'Test body', + }; + }, + { + controlSchema: jsonSchema, + } + ); + }); + + it('should infer correct types in the skip function step controls', async () => { + workflow('json-schema', async ({ step }) => { + await step.email( + 'json-schema', + async (controls) => { + return { + subject: 'Test subject', + body: 'Test body', + }; + }, + { + controlSchema: jsonSchema, + skip: (controls) => { + expectTypeOf(controls).toEqualTypeOf<{ foo: string; baz?: number }>(); + + return true; + }, + } + ); + }); + }); + + it('should infer correct types in the provider function step controls', async () => { + workflow('json-schema', async ({ step }) => { + await step.email( + 'json-schema', + async (controls) => { + return { + subject: 'Test subject', + body: 'Test body', + }; + }, + { + controlSchema: jsonSchema, + providers: { + sendgrid: async ({ controls }) => { + expectTypeOf(controls).toEqualTypeOf<{ foo: string; baz?: number }>(); + + return { + ipPoolName: 'test', + }; + }, + }, + } + ); + }); + }); + + it('should infer correct types in the workflow event payload', async () => { + workflow( + 'json-schema-validation', + async ({ step, payload }) => { + await step.email('json-schema-validation', async () => { + expectTypeOf(payload).toEqualTypeOf<{ foo: string; baz?: number }>(); + + return { + subject: 'Test subject', + body: 'Test body', + }; + }); + }, + { + payloadSchema: jsonSchema, + } + ); + }); + + it('should infer correct types in the workflow event controls', async () => { + workflow( + 'json-schema-validation', + async ({ step, controls }) => { + await step.email('json-schema-validation', async () => { + expectTypeOf(controls).toEqualTypeOf<{ foo: string; baz?: number }>(); + + return { + subject: 'Test subject', + body: 'Test body', + }; + }); + }, + { + controlSchema: jsonSchema, + } + ); + }); + + it('should infer correct types in the workflow event controls', async () => { + workflow( + 'json-schema-validation', + async ({ step, controls }) => { + await step.email('json-schema-validation', async () => { + expectTypeOf(controls).toEqualTypeOf<{ foo: string; baz?: number }>(); + + return { + subject: 'Test subject', + body: 'Test body', + }; + }); + }, + { + controlSchema: jsonSchema, + } + ); + }); + + it('should infer an unknown record type in the custom step results', async () => { + workflow('without-schema', async ({ step }) => { + const result = await step.custom( + 'without-schema', + async () => { + return { + foo: 'bar', + }; + }, + { + outputSchema: jsonSchema, + } + ); + + expectTypeOf(result).toMatchTypeOf<{ foo: string; baz?: number }>(); + }); + }); + }); + }); +}); diff --git a/packages/framework/src/resources/workflow/workflow.resource.ts b/packages/framework/src/resources/workflow/workflow.resource.ts index c6d868d6558..09bdc9e9453 100644 --- a/packages/framework/src/resources/workflow/workflow.resource.ts +++ b/packages/framework/src/resources/workflow/workflow.resource.ts @@ -45,7 +45,7 @@ export function workflow< if (validationResult.success === false) { throw new WorkflowPayloadInvalidError(workflowId, validationResult.errors); } - validatedData = validationResult.data; + validatedData = validationResult.data as T_PayloadValidated; } else { // This type coercion provides support to trigger Workflows without a payload schema validatedData = event.payload as unknown as T_PayloadValidated; diff --git a/packages/framework/src/types/import.types.ts b/packages/framework/src/types/import.types.ts new file mode 100644 index 00000000000..98c7d6d89e5 --- /dev/null +++ b/packages/framework/src/types/import.types.ts @@ -0,0 +1,34 @@ +export type ImportRequirement = { + /** + * The name of the dependency. + * + * This is a necessary duplicate as ESM does not provide a consistent API for + * reading the name of a dependency that can't be resolved. + * + * @example + * ```typescript + * 'my-dependency' + * ``` + */ + name: string; + /** + * The import of the dependency. This is necessary to ensure that the bundler will make + * the dependency available for usage during tree-shaking. + * + * @example + * ```typescript + * import('my-dependency') + * ``` + */ + import: Promise<{ default: unknown } & Record>; + /** + * The required exports of the dependency. The availability of these exports are + * checked by the import validator to verify the dependency is installed. + * + * @example + * ```typescript + * ['my-export'] + * ``` + */ + exports: readonly string[]; +}; diff --git a/packages/framework/src/types/schema.types.ts b/packages/framework/src/types/schema.types.ts deleted file mode 100644 index 6d6f3d2edf9..00000000000 --- a/packages/framework/src/types/schema.types.ts +++ /dev/null @@ -1,88 +0,0 @@ -import type { JSONSchema, FromSchema as JsonSchemaInfer } from 'json-schema-to-ts'; -import zod from 'zod'; -import { Prettify } from './util.types'; - -/** - * A JSON schema. - */ -export type JsonSchema = JSONSchema; - -/** - * A type that represents a class. - */ -export type ClassType = new (...args: unknown[]) => T; - -/** - * Extract the properties of a class type. - */ -export type ClassPropsInfer = T extends ClassType ? Prettify : never; - -/** - * A schema used to validate a JSON object. - * - * Supported schemas: - * - JSONSchema - * - ClassValidatorSchema - * - ZodSchema - */ -export type Schema = JsonSchema | zod.ZodType | ClassType; - -/** - * Infer the type of a Schema for unvalidated data. - * - * The resulting type has default properties set to optional, - * reflecting the fact that the data is unvalidated and has - * not had default properties set. - * - * @example - * ```ts - * type MySchema = FromSchemaUnvalidated; - * ``` - */ -export type FromSchemaUnvalidated = - /* - * Handle each Schema's type inference individually until - * all Schema types are exhausted. - */ - - // JSONSchema - T extends JSONSchema - ? JsonSchemaInfer - : // ZodSchema - T extends zod.ZodSchema - ? zod.input - : // ClassValidatorSchema - T extends ClassType - ? ClassPropsInfer - : // All schema types exhausted. - never; - -/** - * Infer the type of a Schema for validated data. - * - * The resulting type has default properties set to required, - * reflecting the fact that the data has been validated and - * default properties have been set. - * - * @example - * ```ts - * type MySchema = FromSchema; - * ``` - */ -export type FromSchema = - /* - * Handle each Schema's type inference individually until - * all Schema types are exhausted. - */ - - // JSONSchema - T extends JSONSchema - ? JsonSchemaInfer - : // ZodSchema - T extends zod.ZodSchema - ? zod.infer - : // ClassValidatorSchema - T extends ClassType - ? ClassPropsInfer - : // All schema types exhausted. - never; diff --git a/packages/framework/src/types/schema.types/base.schema.types.test-d.ts b/packages/framework/src/types/schema.types/base.schema.types.test-d.ts new file mode 100644 index 00000000000..30cd78312e7 --- /dev/null +++ b/packages/framework/src/types/schema.types/base.schema.types.test-d.ts @@ -0,0 +1,77 @@ +import { describe, expectTypeOf, it } from 'vitest'; +import { z } from 'zod'; +import { FromSchema, FromSchemaUnvalidated } from './base.schema.types'; + +describe('FromSchema', () => { + it('should infer an unknown record type when no schema is provided', () => { + expectTypeOf>().toEqualTypeOf>(); + }); + + it('should infer a Json Schema type', () => { + const testJsonSchema = { + type: 'object', + properties: { + foo: { type: 'string', default: 'bar' }, + bar: { type: 'string' }, + }, + additionalProperties: false, + } as const; + + expectTypeOf>().toEqualTypeOf<{ foo: string; bar?: string }>(); + }); + + it('should infer a Zod Schema type', () => { + const testZodSchema = z.object({ + foo: z.string().default('bar'), + bar: z.string().optional(), + }); + + expectTypeOf>().toEqualTypeOf<{ foo: string; bar?: string }>(); + }); + + it('should infer a Class Schema type', () => { + class TestSchema { + foo: string = 'bar'; + bar?: string; + } + + expectTypeOf>().toEqualTypeOf<{ foo: string; bar?: string }>(); + }); +}); + +describe('FromSchemaUnvalidated', () => { + it('should infer an unknown record type when no schema is provided', () => { + expectTypeOf>().toEqualTypeOf>(); + }); + + it('should infer a Json Schema type', () => { + const testJsonSchema = { + type: 'object', + properties: { + foo: { type: 'string', default: 'bar' }, + bar: { type: 'string' }, + }, + additionalProperties: false, + } as const; + + expectTypeOf>().toEqualTypeOf<{ foo?: string; bar?: string }>(); + }); + + it('should infer a Zod Schema type', () => { + const testZodSchema = z.object({ + foo: z.string().default('bar'), + bar: z.string().optional(), + }); + + expectTypeOf>().toEqualTypeOf<{ foo?: string; bar?: string }>(); + }); + + it('should infer a Class Schema type', () => { + class TestClassSchema { + foo?: string = 'bar'; + bar?: string; + } + + expectTypeOf>().toEqualTypeOf<{ foo?: string; bar?: string }>(); + }); +}); diff --git a/packages/framework/src/types/schema.types/base.schema.types.ts b/packages/framework/src/types/schema.types/base.schema.types.ts new file mode 100644 index 00000000000..ddaaae26b87 --- /dev/null +++ b/packages/framework/src/types/schema.types/base.schema.types.ts @@ -0,0 +1,55 @@ +import { ClassValidatorSchema, InferClassValidatorSchema } from './class.schema.types'; +import { JsonSchema, InferJsonSchema } from './json.schema.types'; +import { ZodSchemaMinimal, InferZodSchema } from './zod.schema.types'; + +/** + * A schema used to validate a JSON object. + */ +export type Schema = JsonSchema | ZodSchemaMinimal | ClassValidatorSchema; + +/** + * Main utility type for schema inference + * + * @param T - The Schema to infer the type of. + * @param Options - Configuration options for the type inference. The `validated` flag determines whether the schema has been validated. If `validated` is true, all properties are required unless specified otherwise. If false, properties with default values are optional. + */ +type InferSchema = + | InferJsonSchema + | InferZodSchema + | InferClassValidatorSchema + | never extends infer U + ? // If all inferred types are `never`, return an unknown record + [U] extends [never] + ? Record + : U extends Record + ? U + : Record + : Record; + +/** + * Infer the type of a Schema for unvalidated data. + * + * The resulting type has default properties set to optional, + * reflecting the fact that the data is unvalidated and has + * not had default properties set. + * + * @example + * ```ts + * type MySchema = FromSchemaUnvalidated; + * ``` + */ +export type FromSchemaUnvalidated = InferSchema; + +/** + * Infer the type of a Schema for validated data. + * + * The resulting type has default properties set to required, + * reflecting the fact that the data has been validated and + * default properties have been set. + * + * @example + * ```ts + * type MySchema = FromSchema; + * ``` + */ +export type FromSchema> = InferSchema; diff --git a/packages/framework/src/types/schema.types/class.schema.types.test-d.ts b/packages/framework/src/types/schema.types/class.schema.types.test-d.ts new file mode 100644 index 00000000000..ebdd46cb6c8 --- /dev/null +++ b/packages/framework/src/types/schema.types/class.schema.types.test-d.ts @@ -0,0 +1,42 @@ +import { describe, expectTypeOf, it } from 'vitest'; +import { InferClassValidatorSchema } from './class.schema.types'; + +describe('ClassSchema types', () => { + class TestSchema { + foo: string = 'bar'; + bar?: string; + } + + describe('validated data', () => { + it('should compile when the expected properties are provided', () => { + expectTypeOf>().toEqualTypeOf<{ + foo: string; + bar?: string; + }>(); + }); + + it('should not compile when the schema is not a ClassSchema', () => { + expectTypeOf>().toEqualTypeOf(); + }); + + it('should not compile when a property does not match the expected type', () => { + // @ts-expect-error - Type 'number' is not assignable to type 'string'. + expectTypeOf>().toEqualTypeOf<{ + foo: number; + }>(); + }); + }); + + describe('unvalidated data', () => { + /** + * TODO: Support accessing defaulted properties when Typescript supports it. + */ + it.skip('should keep the defaulted properties optional', () => { + // @ts-expect-error - Type 'undefined' is not assignable to type 'string'. + expectTypeOf>().toEqualTypeOf<{ + foo?: string; + bar?: string; + }>(); + }); + }); +}); diff --git a/packages/framework/src/types/schema.types/class.schema.types.ts b/packages/framework/src/types/schema.types/class.schema.types.ts new file mode 100644 index 00000000000..4c57b30bf92 --- /dev/null +++ b/packages/framework/src/types/schema.types/class.schema.types.ts @@ -0,0 +1,44 @@ +import { Prettify } from '../util.types'; + +/** + * A type that represents a class. + */ +export type ClassValidatorSchema = new (...args: unknown[]) => T; + +/** + * Extract the properties of a class type. + */ +export type ClassPropsInfer = + T extends ClassValidatorSchema ? Prettify : never; + +/** + * Infer the data type of a ClassValidatorSchema. + * + * @param T - The ClassValidatorSchema to infer the data type of. + * @param Options - Configuration options for the type inference. The `validated` flag determines whether the schema has been validated. If `validated` is true, all properties are required unless specified otherwise. If false, properties with default values are optional. + * + * @returns The inferred type. + * + * @example + * ```ts + * class MySchema { + * @IsString() + * @IsNotEmpty() + * name: string; + * + * @IsEmail() + * @IsOptional() + * email?: string; + * } + * + * // has type { name: string, email?: string } + * type MySchema = InferClassValidatorSchema; + * ``` + */ +export type InferClassValidatorSchema = T extends ClassValidatorSchema + ? Options['validated'] extends true + ? ClassPropsInfer + : // ClassSchema doesn't support default properties, so the resulting type + // will not have default properties set to optional. + ClassPropsInfer + : never; diff --git a/packages/framework/src/types/schema.types/index.ts b/packages/framework/src/types/schema.types/index.ts new file mode 100644 index 00000000000..bee70f5c10b --- /dev/null +++ b/packages/framework/src/types/schema.types/index.ts @@ -0,0 +1,4 @@ +export type { JsonSchema } from './json.schema.types'; +export type { ZodSchemaMinimal, ZodSchema } from './zod.schema.types'; +export type { ClassValidatorSchema } from './class.schema.types'; +export type { Schema, FromSchema, FromSchemaUnvalidated } from './base.schema.types'; diff --git a/packages/framework/src/types/schema.types/json.schema.types.test-d.ts b/packages/framework/src/types/schema.types/json.schema.types.test-d.ts new file mode 100644 index 00000000000..25522ef5f43 --- /dev/null +++ b/packages/framework/src/types/schema.types/json.schema.types.test-d.ts @@ -0,0 +1,42 @@ +import { describe, expectTypeOf, it } from 'vitest'; +import { InferJsonSchema, JsonSchema } from './json.schema.types'; + +describe('JsonSchema types', () => { + const testSchema = { + type: 'object', + properties: { + foo: { type: 'string', default: 'bar' }, + bar: { type: 'string' }, + }, + additionalProperties: false, + } as const satisfies JsonSchema; + + describe('validated data', () => { + it('should compile when the expected properties are provided', () => { + expectTypeOf>().toEqualTypeOf<{ + foo: string; + bar?: string; + }>(); + }); + + it('should not compile when the schema is not a ClassSchema', () => { + expectTypeOf>().toEqualTypeOf(); + }); + + it('should not compile when a property does not match the expected type', () => { + // @ts-expect-error - Type 'number' is not assignable to type 'string'. + expectTypeOf>().toEqualTypeOf<{ + foo: number; + }>(); + }); + }); + + describe('unvalidated data', () => { + it('should keep the defaulted properties optional', () => { + expectTypeOf>().toEqualTypeOf<{ + foo?: string; + bar?: string; + }>(); + }); + }); +}); diff --git a/packages/framework/src/types/schema.types/json.schema.types.ts b/packages/framework/src/types/schema.types/json.schema.types.ts new file mode 100644 index 00000000000..789edf7683e --- /dev/null +++ b/packages/framework/src/types/schema.types/json.schema.types.ts @@ -0,0 +1,36 @@ +import type { JSONSchema, FromSchema as JsonSchemaInfer } from 'json-schema-to-ts'; + +/** + * A JSON schema. + */ +export type JsonSchema = Exclude; + +/** + * Infer the data type of a JsonSchema. + * + * @param T - The `JsonSchema` to infer the data type of. + * @param Options - Configuration options for the type inference. The `validated` flag determines whether the schema has been validated. If `validated` is true, all properties are required unless specified otherwise. If false, properties with default values are optional. + * + * @returns The inferred type. + * + * @example + * ```ts + * const mySchema = { + * type: 'object', + * properties: { + * name: { type: 'string' }, + * email: { type: 'string' }, + * }, + * required: ['name'], + * additionalProperties: false, + * } as const satisfies JsonSchema; + * + * // has type { name: string, email?: string } + * type MySchema = InferJsonSchema; + * ``` + */ +export type InferJsonSchema = T extends JsonSchema + ? Options['validated'] extends true + ? JsonSchemaInfer + : JsonSchemaInfer + : never; diff --git a/packages/framework/src/types/schema.types/zod.schema.types.test-d.ts b/packages/framework/src/types/schema.types/zod.schema.types.test-d.ts new file mode 100644 index 00000000000..dee4a87c08f --- /dev/null +++ b/packages/framework/src/types/schema.types/zod.schema.types.test-d.ts @@ -0,0 +1,39 @@ +import { describe, expectTypeOf, it } from 'vitest'; +import { z } from 'zod'; +import { InferZodSchema } from './zod.schema.types'; + +describe('ZodSchema', () => { + const testSchema = z.object({ + foo: z.string().default('bar'), + bar: z.string().optional(), + }); + + describe('validated data', () => { + it('should compile when the expected properties are provided', () => { + expectTypeOf>().toEqualTypeOf<{ + foo: string; + bar?: string; + }>(); + }); + + it('should not compile when the schema is not a ClassSchema', () => { + expectTypeOf>().toEqualTypeOf(); + }); + + it('should not compile when a property does not match the expected type', () => { + // @ts-expect-error - Type 'number' is not assignable to type 'string'. + expectTypeOf>().toEqualTypeOf<{ + foo: number; + }>(); + }); + }); + + describe('unvalidated data', () => { + it('should keep the defaulted properties optional', () => { + expectTypeOf>().toEqualTypeOf<{ + foo?: string; + bar?: string; + }>(); + }); + }); +}); diff --git a/packages/framework/src/types/schema.types/zod.schema.types.ts b/packages/framework/src/types/schema.types/zod.schema.types.ts new file mode 100644 index 00000000000..67655b8f528 --- /dev/null +++ b/packages/framework/src/types/schema.types/zod.schema.types.ts @@ -0,0 +1,42 @@ +import zod from 'zod'; + +export type ZodSchema = zod.ZodType; + +/** + * A minimal ZodSchema type. + * + * It is necessary to define a minimal ZodSchema type to enable correct inference + * when Zod is not available, as Typescript doesn't support detection of module + * availability via `typeof import('zod')`. + */ +export type ZodSchemaMinimal = { + readonly safeParseAsync: unknown; +}; + +/** + * Infer the data type of a ZodSchema. + * + * @param T - The ZodSchema to infer the data type of. + * @param Options - Configuration options for the type inference. The `validated` flag determines whether the schema has been validated. If `validated` is true, all properties are required unless specified otherwise. If false, properties with default values are optional. + * + * @example + * ```ts + * const mySchema = z.object({ + * name: z.string(), + * email: z.string().optional(), + * }); + * + * // has type { name: string, email?: string } + * type MySchema = InferZodSchema; + * ``` + */ +export type InferZodSchema = + // Firstly, narrow to the minimal schema type without using the `zod` import + T extends ZodSchemaMinimal + ? // Secondly, narrow to the Zod type to provide type-safety to `zod.infer` and `zod.input` + T extends ZodSchema + ? Options['validated'] extends true + ? zod.infer + : zod.input + : never + : never; diff --git a/packages/framework/src/types/util.types.ts b/packages/framework/src/types/util.types.ts index 0246e75632b..0e5fc0a8f9a 100644 --- a/packages/framework/src/types/util.types.ts +++ b/packages/framework/src/types/util.types.ts @@ -1,3 +1,8 @@ +/* + * THIS FILE SHOULD NOT DEPEND ON ANY OTHER FILES. + * IT SHOULD ONLY CONTAIN UTILITY TYPES. + */ + /** * A type that represents either `A` or `B`. Shared properties retain their * types and unique properties are marked as optional. diff --git a/packages/framework/src/types/validator.types.ts b/packages/framework/src/types/validator.types.ts index 36826f8bf2b..933c39f8284 100644 --- a/packages/framework/src/types/validator.types.ts +++ b/packages/framework/src/types/validator.types.ts @@ -1,6 +1,8 @@ import type { ValidateFunction as AjvValidateFunction } from 'ajv'; import type { ParseReturnType } from 'zod'; -import type { Schema, JsonSchema, FromSchema, FromSchemaUnvalidated } from './schema.types'; +import type { Schema, FromSchema, FromSchemaUnvalidated } from './schema.types'; +import type { JsonSchema } from './schema.types/json.schema.types'; +import type { ImportRequirement } from './import.types'; export type ValidateFunction = AjvValidateFunction | ((data: T) => ParseReturnType); @@ -19,8 +21,7 @@ export type ValidateResult = data: T; }; -// eslint-disable-next-line @typescript-eslint/naming-convention -export interface Validator { +export type Validator = { validate: < T_Unvalidated extends Record = FromSchemaUnvalidated, T_Validated extends Record = FromSchema, @@ -28,6 +29,7 @@ export interface Validator { data: T_Unvalidated, schema: T_Schema ) => Promise>; - canHandle: (schema: Schema) => schema is T_Schema; + canHandle: (schema: Schema) => Promise; transformToJsonSchema: (schema: T_Schema) => Promise; -} + requiredImports: readonly ImportRequirement[]; +}; diff --git a/packages/framework/src/utils/import.utils.test.ts b/packages/framework/src/utils/import.utils.test.ts new file mode 100644 index 00000000000..ea08ba73fd2 --- /dev/null +++ b/packages/framework/src/utils/import.utils.test.ts @@ -0,0 +1,59 @@ +import { describe, it, expect } from 'vitest'; +import { checkDependencies } from './import.utils'; + +describe('import utils', () => { + describe('checkDependencies', () => { + it('should not throw an error if all dependencies are installed', async () => { + await expect( + checkDependencies( + [{ name: 'typescript', import: import('typescript'), exports: ['tokenToString'] }], + 'test schema' + ) + ).resolves.not.toThrow(); + }); + + it('should throw an error if a single dependency is not installed', async () => { + await expect( + checkDependencies( + // @ts-expect-error - Cannot find module 'missing-random-dependency' or its corresponding type declarations. + [{ name: 'missing-random-dependency', import: import('missing-random-dependency'), exports: [] }], + 'test schema' + ) + ).rejects.toThrow( + 'Tried to use a test schema in @novu/framework without missing-random-dependency installed. Please install it by running `npm install missing-random-dependency`.' + ); + }); + + it('should throw an error if multiple dependencies are not installed', async () => { + await expect( + checkDependencies( + [ + // @ts-expect-error - Cannot find module 'missing-random-dependency-1' or its corresponding type declarations. + { name: 'missing-random-dependency-1', import: import('missing-random-dependency-1'), exports: [] }, + // @ts-expect-error - Cannot find module 'missing-random-dependency-2' or its corresponding type declarations. + { name: 'missing-random-dependency-2', import: import('missing-random-dependency-2'), exports: [] }, + ], + 'test schema' + ) + ).rejects.toThrow( + 'Tried to use a test schema in @novu/framework without missing-random-dependency-1, missing-random-dependency-2 installed. Please install them by running `npm install missing-random-dependency-1 missing-random-dependency-2`.' + ); + }); + + it('should throw an error listing a single dependency that is not installed when using a root and non-root import', async () => { + await expect( + checkDependencies( + [ + // @ts-expect-error - Cannot find module 'missing-random-dependency' or its corresponding type declarations. + { name: 'missing-random-dependency', import: import('missing-random-dependency'), exports: [] }, + // @ts-expect-error - Cannot find module 'missing-random-dependency/nested' or its corresponding type declarations. + { name: 'missing-random-dependency', import: import('missing-random-dependency/nested'), exports: [] }, + ], + 'test schema' + ) + ).rejects.toThrow( + 'Tried to use a test schema in @novu/framework without missing-random-dependency installed. Please install it by running `npm install missing-random-dependency`.' + ); + }); + }); +}); diff --git a/packages/framework/src/utils/import.utils.ts b/packages/framework/src/utils/import.utils.ts new file mode 100644 index 00000000000..3d924c75f3e --- /dev/null +++ b/packages/framework/src/utils/import.utils.ts @@ -0,0 +1,37 @@ +import { MissingDependencyError } from '../errors/import.errors'; +import type { ImportRequirement } from '../types/import.types'; + +/** + * Check if the required dependencies are installed and throw an error if not. + * + * @param dependencies - The list of dependencies to check + * @param usageReason - The usage of the dependencies + */ +export const checkDependencies = async ( + dependencies: readonly ImportRequirement[], + usageReason: string +): Promise => { + const missingDependencies = new Set(); + for (const dep of dependencies) { + try { + const result = await dep.import; + + const hasAllExports = dep.exports.every((exportName) => result[exportName] !== undefined); + + /* + * First way that a dependency isn't available is if the import succeeds + * but the necessary exports are not available. + */ + if (!hasAllExports) { + missingDependencies.add(dep.name); + } + } catch (error) { + // Second way that a dependency isn't available is if the import fails. + missingDependencies.add(dep.name); + } + } + + if (missingDependencies.size > 0) { + throw new MissingDependencyError(usageReason, Array.from(missingDependencies)); + } +}; diff --git a/packages/framework/src/validators/base.validator.ts b/packages/framework/src/validators/base.validator.ts index e276acf453a..52daa76a971 100644 --- a/packages/framework/src/validators/base.validator.ts +++ b/packages/framework/src/validators/base.validator.ts @@ -1,4 +1,11 @@ -import type { FromSchema, FromSchemaUnvalidated, JsonSchema, Schema } from '../types/schema.types'; +import type { + FromSchema, + FromSchemaUnvalidated, + ClassValidatorSchema, + Schema, + JsonSchema, + ZodSchema, +} from '../types/schema.types'; import type { ValidateResult } from '../types/validator.types'; import { JsonSchemaValidator } from './json-schema.validator'; import { ZodValidator } from './zod.validator'; @@ -8,6 +15,13 @@ const zodValidator = new ZodValidator(); const classValidatorValidator = new ClassValidatorValidator(); const jsonSchemaValidator = new JsonSchemaValidator(); +/** + * Validate data against a schema. + * + * @param schema - The schema to validate the data against. + * @param data - The data to validate. + * @returns The validated data. + */ export const validateData = async < T_Schema extends Schema = Schema, T_Unvalidated extends Record = FromSchemaUnvalidated, @@ -16,24 +30,35 @@ export const validateData = async < schema: T_Schema, data: T_Unvalidated ): Promise> => { - if (zodValidator.canHandle(schema)) { - return zodValidator.validate(data, schema); - } else if (classValidatorValidator.canHandle(schema)) { - return classValidatorValidator.validate(data, schema); - } else if (jsonSchemaValidator.canHandle(schema)) { - return jsonSchemaValidator.validate(data, schema); + /** + * TODO: Replace type coercion with async type guard when available. + * + * @see https://github.com/microsoft/typescript/issues/37681 + */ + if (await zodValidator.canHandle(schema)) { + return zodValidator.validate(data, schema as ZodSchema); + } else if (await classValidatorValidator.canHandle(schema)) { + return classValidatorValidator.validate(data, schema as ClassValidatorSchema); + } else if (await jsonSchemaValidator.canHandle(schema)) { + return jsonSchemaValidator.validate(data, schema as JsonSchema); } throw new Error('Invalid schema'); }; +/** + * Transform a schema to a JSON schema. + * + * @param schema - The schema to transform. + * @returns The transformed JSON schema. + */ export const transformSchema = async (schema: Schema): Promise => { - if (zodValidator.canHandle(schema)) { - return zodValidator.transformToJsonSchema(schema); - } else if (classValidatorValidator.canHandle(schema)) { - return classValidatorValidator.transformToJsonSchema(schema); - } else if (jsonSchemaValidator.canHandle(schema)) { - return jsonSchemaValidator.transformToJsonSchema(schema); + if (await zodValidator.canHandle(schema)) { + return zodValidator.transformToJsonSchema(schema as ZodSchema); + } else if (await classValidatorValidator.canHandle(schema)) { + return classValidatorValidator.transformToJsonSchema(schema as ClassValidatorSchema); + } else if (await jsonSchemaValidator.canHandle(schema)) { + return jsonSchemaValidator.transformToJsonSchema(schema as JsonSchema); } throw new Error('Invalid schema'); diff --git a/packages/framework/src/validators/class-validator.validator.ts b/packages/framework/src/validators/class-validator.validator.ts index 7252e47ea45..6770f1554a2 100644 --- a/packages/framework/src/validators/class-validator.validator.ts +++ b/packages/framework/src/validators/class-validator.validator.ts @@ -1,6 +1,14 @@ import { ValidationError } from 'class-validator'; -import type { ClassType, FromSchema, FromSchemaUnvalidated, JsonSchema, Schema } from '../types/schema.types'; +import type { + FromSchema, + FromSchemaUnvalidated, + Schema, + JsonSchema, + ClassValidatorSchema, +} from '../types/schema.types'; import type { ValidateResult, Validator } from '../types/validator.types'; +import { checkDependencies } from '../utils/import.utils'; +import { ImportRequirement } from '../types/import.types'; // Function to recursively add `additionalProperties: false` to the schema // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -55,87 +63,101 @@ function formatErrors(errors: ValidationError[], parentPath = ''): { path: strin }); } -export class ClassValidatorValidator implements Validator { - canHandle(schema: Schema): schema is ClassType { - return ( - typeof (schema as ClassType) === 'function' && - (schema as ClassType).prototype !== undefined && - (schema as ClassType).prototype.constructor === schema - ); +export class ClassValidatorValidator implements Validator { + readonly requiredImports: readonly ImportRequirement[] = [ + { + name: 'class-validator', + import: import('class-validator'), + exports: ['validate', 'getMetadataStorage'], + }, + { + name: 'class-transformer', + import: import('class-transformer'), + exports: ['plainToInstance', 'instanceToPlain'], + }, + { + name: 'class-transformer', + // @ts-expect-error - class-transformer doesn't export `defaultMetadataStorage` from the root module + import: import('class-transformer/cjs/storage'), + exports: ['defaultMetadataStorage'], + }, + { + name: 'reflect-metadata', + import: import('reflect-metadata'), + exports: [], + }, + { + name: 'class-validator-jsonschema', + import: import('class-validator-jsonschema'), + exports: ['validationMetadatasToSchemas', 'targetConstructorToSchema'], + }, + ]; + + async canHandle(schema: Schema): Promise { + const canHandle = + typeof (schema as ClassValidatorSchema) === 'function' && + (schema as ClassValidatorSchema).prototype !== undefined && + (schema as ClassValidatorSchema).prototype.constructor === schema; + + if (canHandle) { + await checkDependencies(this.requiredImports, 'class-validator schema'); + } + + return canHandle; } async validate< - T_Schema extends ClassType = ClassType, + T_Schema extends ClassValidatorSchema = ClassValidatorSchema, T_Unvalidated = FromSchemaUnvalidated, T_Validated = FromSchema, >(data: T_Unvalidated, schema: T_Schema): Promise> { - try { - await import('reflect-metadata'); - const { plainToInstance, instanceToPlain } = await import('class-transformer'); - const { validate } = await import('class-validator'); - - // Convert plain data to an instance of the schema class - const instance = plainToInstance(schema, data); - - // Validate the instance - const errors = await validate(instance as object, { whitelist: true }); - - // if undefined, then something went wrong - if (!instance && !!data) throw new Error('Failed to convert data to an instance of the schema class'); - - if (errors.length === 0) { - return { success: true, data: instanceToPlain(instance) as T_Validated }; - } else { - return { - success: false, - errors: formatErrors(errors), - }; - } - } catch (error) { - if ((error as Error)?.message?.includes('Cannot find module')) { - throw new Error( - 'Tried to use a class-validator schema in @novu/framework without `class-validator`, `class-transformer` or `reflect-metadata` installed. ' + - 'Please install it by running `npm install class-validator class-transformer reflect-metadata`.' - ); - } - throw error; + const { plainToInstance, instanceToPlain } = await import('class-transformer'); + const { validate } = await import('class-validator'); + + // Convert plain data to an instance of the schema class + const instance = plainToInstance(schema, data); + + // Validate the instance + const errors = await validate(instance as object, { whitelist: true }); + + // if undefined, then something went wrong + if (!instance && !!data) throw new Error('Failed to convert data to an instance of the schema class'); + + if (errors.length === 0) { + return { success: true, data: instanceToPlain(instance) as T_Validated }; + } else { + return { + success: false, + errors: formatErrors(errors), + }; } } - async transformToJsonSchema(schema: ClassType): Promise { - try { - /* - * TODO: replace with direct import, when defaultMetadataStorage is exported by default - * @see https://github.com/typestack/class-transformer/issues/563#issuecomment-803262394 - */ - // @ts-expect-error - class-transformer doesn't export `defaultMetadataStorage` from the root module - const { defaultMetadataStorage } = await import('class-transformer/cjs/storage'); - const { getMetadataStorage } = await import('class-validator'); - const { targetConstructorToSchema, validationMetadatasToSchemas } = await import('class-validator-jsonschema'); - - const schemas = validationMetadatasToSchemas({ - classValidatorMetadataStorage: getMetadataStorage(), - classTransformerMetadataStorage: defaultMetadataStorage, - }); - - return addAdditionalPropertiesFalse( - replaceSchemaRefs( - targetConstructorToSchema(schema, { - classValidatorMetadataStorage: getMetadataStorage(), - classTransformerMetadataStorage: defaultMetadataStorage, - }), - schemas - ) - ); - } catch (error) { - if ((error as Error)?.message?.includes('Cannot find module')) { - // eslint-disable-next-line no-console - console.error( - 'Tried to use a class-validator schema in @novu/framework without `class-validator-jsonschema` installed. ' + - 'Please install it by running `npm install class-validator-jsonschema`.' - ); - } - throw error; - } + async transformToJsonSchema(schema: ClassValidatorSchema): Promise { + /* + * TODO: replace with direct import, when defaultMetadataStorage is exported by default + * @see https://github.com/typestack/class-transformer/issues/563#issuecomment-803262394 + */ + // @ts-expect-error - class-transformer doesn't export `defaultMetadataStorage` from the root module + const { defaultMetadataStorage } = await import('class-transformer/cjs/storage'); + const { getMetadataStorage } = await import('class-validator'); + const { validationMetadatasToSchemas, targetConstructorToSchema } = await import('class-validator-jsonschema'); + + const schemas = validationMetadatasToSchemas({ + classValidatorMetadataStorage: getMetadataStorage(), + classTransformerMetadataStorage: defaultMetadataStorage, + }); + + const transformedSchema = addAdditionalPropertiesFalse( + replaceSchemaRefs( + targetConstructorToSchema(schema, { + classValidatorMetadataStorage: getMetadataStorage(), + classTransformerMetadataStorage: defaultMetadataStorage, + }), + schemas + ) + ); + + return transformedSchema; } } diff --git a/packages/framework/src/validators/json-schema.validator.ts b/packages/framework/src/validators/json-schema.validator.ts index 2a5446d7a9a..22e8ede605d 100644 --- a/packages/framework/src/validators/json-schema.validator.ts +++ b/packages/framework/src/validators/json-schema.validator.ts @@ -2,10 +2,18 @@ import Ajv from 'ajv'; import type { ErrorObject, ValidateFunction as AjvValidateFunction } from 'ajv'; import addFormats from 'ajv-formats'; import type { ValidateResult, Validator } from '../types/validator.types'; -import type { FromSchema, FromSchemaUnvalidated, JsonSchema, Schema } from '../types/schema.types'; +import type { FromSchema, FromSchemaUnvalidated, Schema, JsonSchema } from '../types/schema.types'; import { cloneData } from '../utils/clone.utils'; +import { checkDependencies } from '../utils/import.utils'; +import { ImportRequirement } from '../types/import.types'; export class JsonSchemaValidator implements Validator { + /** + * Json schema validation has no required dependencies as they are included in + * the `@novu/framework` package dependencies. + */ + readonly requiredImports: readonly ImportRequirement[] = []; + private readonly ajv: Ajv; /** @@ -27,15 +35,18 @@ export class JsonSchemaValidator implements Validator { this.compiledSchemas = new Map(); } - canHandle(schema: Schema): schema is JsonSchema { - if (typeof schema === 'boolean') return false; + async canHandle(schema: Schema): Promise { + const canHandle = + (schema as JsonSchema).type === 'object' || + !!(schema as JsonSchema).anyOf || + !!(schema as JsonSchema).allOf || + !!(schema as JsonSchema).oneOf; + + if (canHandle) { + await checkDependencies(this.requiredImports, 'json-schema'); + } - return ( - (schema as Exclude).type === 'object' || - !!(schema as Exclude).anyOf || - !!(schema as Exclude).allOf || - !!(schema as Exclude).oneOf - ); + return canHandle; } async validate< diff --git a/packages/framework/src/validators/validator.test.ts b/packages/framework/src/validators/validator.test.ts index 72e3648b264..851b6ac1033 100644 --- a/packages/framework/src/validators/validator.test.ts +++ b/packages/framework/src/validators/validator.test.ts @@ -1,8 +1,10 @@ import { describe, it, expect } from 'vitest'; -import { ZodSchema, z } from 'zod'; +import { z } from 'zod'; import { validateData, transformSchema } from './base.validator'; -import { ClassType, JsonSchema, Schema } from '../types/schema.types'; +import { Schema, ZodSchema } from '../types/schema.types'; import { SimpleStringSchema, NestedSchema, SimpleStringAndNumberSchema } from './fixures/class-validator.fixtures'; +import { ClassValidatorSchema } from '../types/schema.types/class.schema.types'; +import { JsonSchema } from '../types/schema.types/json.schema.types'; const schemas = ['zod', 'class', 'json'] as const; @@ -12,7 +14,7 @@ describe('validators', () => { title: string; schemas: { zod: ZodSchema | null; - class: ClassType | null; + class: ClassValidatorSchema | null; json: JsonSchema; }; payload: Record; @@ -357,7 +359,7 @@ describe('validators', () => { title: string; schemas: { zod: ZodSchema | null; - class: ClassType | null; + class: ClassValidatorSchema | null; json: JsonSchema; }; result: JsonSchema; diff --git a/packages/framework/src/validators/zod.validator.ts b/packages/framework/src/validators/zod.validator.ts index e428b9bf82e..5db48cdc48a 100644 --- a/packages/framework/src/validators/zod.validator.ts +++ b/packages/framework/src/validators/zod.validator.ts @@ -1,19 +1,40 @@ -import { ZodSchema } from 'zod'; +import zod from 'zod'; -import type { FromSchema, FromSchemaUnvalidated, JsonSchema, Schema } from '../types/schema.types'; +import type { FromSchema, FromSchemaUnvalidated, Schema, JsonSchema, ZodSchemaMinimal } from '../types/schema.types'; import type { ValidateResult, Validator } from '../types/validator.types'; +import { checkDependencies } from '../utils/import.utils'; +import { ImportRequirement } from '../types/import.types'; -export class ZodValidator implements Validator { - canHandle(schema: Schema): schema is ZodSchema { - return (schema as ZodSchema).safeParseAsync !== undefined; +export class ZodValidator implements Validator { + readonly requiredImports: readonly ImportRequirement[] = [ + { + name: 'zod', + import: import('zod'), + exports: ['ZodType'], + }, + { + name: 'zod-to-json-schema', + import: import('zod-to-json-schema'), + exports: ['zodToJsonSchema'], + }, + ]; + + async canHandle(schema: Schema): Promise { + const canHandle = (schema as ZodSchemaMinimal).safeParseAsync !== undefined; + + if (canHandle) { + await checkDependencies(this.requiredImports, 'zod schema'); + } + + return canHandle; } async validate< - T_Schema extends ZodSchema = ZodSchema, + T_Schema extends zod.ZodType = zod.ZodType, T_Unvalidated = FromSchemaUnvalidated, T_Validated = FromSchema, >(data: T_Unvalidated, schema: T_Schema): Promise> { - const result = schema.safeParse(data); + const result = await schema.safeParseAsync(data); if (result.success) { return { success: true, data: result.data as T_Validated }; } else { @@ -27,21 +48,10 @@ export class ZodValidator implements Validator { } } - async transformToJsonSchema(schema: ZodSchema): Promise { - try { - const { zodToJsonSchema } = await import('zod-to-json-schema'); - - // TODO: zod-to-json-schema is not using JSONSchema7 - return zodToJsonSchema(schema) as JsonSchema; - } catch (error) { - if ((error as Error)?.message?.includes('Cannot find module')) { - // eslint-disable-next-line no-console - console.error( - 'Tried to use a zod schema in @novu/framework without `zod-to-json-schema` installed. ' + - 'Please install it by running `npm install zod-to-json-schema`.' - ); - } - throw error; - } + async transformToJsonSchema(schema: zod.ZodType): Promise { + const { zodToJsonSchema } = await import('zod-to-json-schema'); + + // TODO: zod-to-json-schema is not using JSONSchema7 + return zodToJsonSchema(schema) as JsonSchema; } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b887430470b..283d301fb69 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -335,7 +335,7 @@ importers: version: 7.1.0 ts-jest: specifier: 27.1.5 - version: 27.1.5(@babel/core@7.25.2)(@types/jest@29.5.13)(babel-jest@27.5.1(@babel/core@7.25.2))(jest@29.7.0(@types/node@18.16.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)))(typescript@5.6.2) + version: 27.1.5(@babel/core@7.24.3)(@types/jest@29.5.13)(babel-jest@27.5.1(@babel/core@7.24.3))(jest@29.7.0(@types/node@18.16.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)))(typescript@5.6.2) ts-node: specifier: ~10.9.1 version: 10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2) @@ -1023,13 +1023,13 @@ importers: dependencies: '@babel/plugin-proposal-optional-chaining': specifier: ^7.20.7 - version: 7.21.0(@babel/core@7.21.4) + version: 7.21.0(@babel/core@7.22.11) '@babel/plugin-transform-react-display-name': specifier: ^7.18.6 - version: 7.18.6(@babel/core@7.21.4) + version: 7.18.6(@babel/core@7.22.11) '@babel/plugin-transform-runtime': specifier: ^7.23.2 - version: 7.23.2(@babel/core@7.21.4) + version: 7.23.2(@babel/core@7.22.11) '@clerk/clerk-react': specifier: ^5.15.1 version: 5.15.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -1215,7 +1215,7 @@ importers: version: 11.9.0 html-webpack-plugin: specifier: 5.5.3 - version: 5.5.3(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) + version: 5.5.3(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) js-cookie: specifier: ^3.0.5 version: 3.0.5 @@ -1251,7 +1251,7 @@ importers: version: 4.3.2 mdx-bundler: specifier: 10.0.2 - version: 10.0.2(esbuild@0.23.1) + version: 10.0.2(esbuild@0.18.20) mixpanel-browser: specifier: ^2.52.0 version: 2.53.0 @@ -1354,13 +1354,13 @@ importers: version: 7.12.1 '@babel/preset-env': specifier: ^7.23.2 - version: 7.23.2(@babel/core@7.21.4) + version: 7.23.2(@babel/core@7.22.11) '@babel/preset-react': specifier: ^7.13.13 - version: 7.18.6(@babel/core@7.21.4) + version: 7.18.6(@babel/core@7.22.11) '@babel/preset-typescript': specifier: ^7.13.0 - version: 7.21.4(@babel/core@7.21.4) + version: 7.21.4(@babel/core@7.22.11) '@babel/runtime': specifier: ^7.20.13 version: 7.21.0 @@ -1405,13 +1405,13 @@ importers: version: 7.4.2 '@storybook/preset-create-react-app': specifier: ^7.4.2 - version: 7.4.2(f7avyblvzm233o6g7idqcb345u) + version: 7.4.2(ucmnrhmq4kewpo24xrp57f5r6y) '@storybook/react': specifier: ^7.4.2 version: 7.4.2(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) '@storybook/react-webpack5': specifier: ^7.4.2 - version: 7.4.2(@babel/core@7.21.4)(@swc/core@1.3.107(@swc/helpers@0.5.12))(@swc/helpers@0.5.12)(@types/react-dom@18.3.0)(@types/react@18.3.3)(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1))(encoding@0.1.13)(esbuild@0.23.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(type-fest@2.19.0)(typescript@5.6.2)(webpack-dev-server@4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)))(webpack-hot-middleware@2.26.1) + version: 7.4.2(@babel/core@7.22.11)(@swc/core@1.3.107(@swc/helpers@0.5.12))(@swc/helpers@0.5.12)(@types/react-dom@18.3.0)(@types/react@18.3.3)(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20))(encoding@0.1.13)(esbuild@0.18.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(type-fest@2.19.0)(typescript@5.6.2)(webpack-dev-server@4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)))(webpack-hot-middleware@2.26.1) '@testing-library/jest-dom': specifier: ^4.2.4 version: 4.2.4 @@ -1438,16 +1438,16 @@ importers: version: 0.13.0 less-loader: specifier: 4.1.0 - version: 4.1.0(less@4.1.3)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) + version: 4.1.0(less@4.1.3)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) react-app-rewired: specifier: ^2.2.1 - version: 2.2.1(react-scripts@5.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.21.4))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.21.4))(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/babel__core@7.20.5)(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1))(esbuild@0.23.1)(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6))(react@18.3.1)(sass@1.77.8)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2))(type-fest@2.19.0)(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack-hot-middleware@2.26.1)) + version: 2.2.1(react-scripts@5.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.22.11))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.22.11))(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/babel__core@7.20.5)(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20))(esbuild@0.18.20)(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6))(react@18.3.1)(sass@1.77.8)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2))(type-fest@2.19.0)(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack-hot-middleware@2.26.1)) react-error-overlay: specifier: 6.0.11 version: 6.0.11 react-scripts: specifier: ^5.0.1 - version: 5.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.21.4))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.21.4))(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/babel__core@7.20.5)(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1))(esbuild@0.23.1)(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6))(react@18.3.1)(sass@1.77.8)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2))(type-fest@2.19.0)(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack-hot-middleware@2.26.1) + version: 5.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.22.11))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.22.11))(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/babel__core@7.20.5)(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20))(esbuild@0.18.20)(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6))(react@18.3.1)(sass@1.77.8)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2))(type-fest@2.19.0)(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack-hot-middleware@2.26.1) sinon: specifier: 9.2.4 version: 9.2.4 @@ -1459,13 +1459,13 @@ importers: version: 5.6.2 webpack: specifier: 5.78.0 - version: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) + version: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20) webpack-bundle-analyzer: specifier: ^4.9.0 version: 4.9.0 webpack-dev-server: specifier: 4.11.1 - version: 4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) + version: 4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) apps/webhook: dependencies: @@ -1764,34 +1764,34 @@ importers: version: 1.14.2 html-webpack-plugin: specifier: 5.5.3 - version: 5.5.3(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))) + version: 5.5.3(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) http-server: specifier: ^0.13.0 version: 0.13.0 jest: specifier: 27.5.1 - version: 27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) + version: 27.5.1(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)) less: specifier: ^4.1.0 version: 4.1.3 less-loader: specifier: 4.1.0 - version: 4.1.0(less@4.1.3)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))) + version: 4.1.0(less@4.1.3)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) react-app-rewired: specifier: ^2.2.1 - version: 2.2.1(react-scripts@5.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.25.2))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2))(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/babel__core@7.20.5)(@types/webpack@5.28.5(@swc/core@1.7.26(@swc/helpers@0.5.12)))(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6))(react@18.3.1)(sass@1.77.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2))(type-fest@2.19.0)(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack-hot-middleware@2.26.1)) + version: 2.2.1(react-scripts@5.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.25.2))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2))(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/babel__core@7.20.5)(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12)))(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6))(react@18.3.1)(sass@1.77.8)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2))(type-fest@2.19.0)(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack-hot-middleware@2.26.1)) react-scripts: specifier: ^5.0.1 - version: 5.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.25.2))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2))(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/babel__core@7.20.5)(@types/webpack@5.28.5(@swc/core@1.7.26(@swc/helpers@0.5.12)))(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6))(react@18.3.1)(sass@1.77.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2))(type-fest@2.19.0)(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack-hot-middleware@2.26.1) + version: 5.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.25.2))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2))(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/babel__core@7.20.5)(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12)))(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6))(react@18.3.1)(sass@1.77.8)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2))(type-fest@2.19.0)(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack-hot-middleware@2.26.1) typescript: specifier: 5.6.2 version: 5.6.2 webpack: specifier: 5.78.0 - version: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12)) + version: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12)) webpack-dev-server: specifier: 4.11.1 - version: 4.11.1(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))) + version: 4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) apps/worker: dependencies: @@ -2786,7 +2786,7 @@ importers: version: 20.16.5 jest: specifier: ^29.4.1 - version: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)) + version: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) jest-environment-jsdom: specifier: ^29.4.1 version: 29.5.0 @@ -2798,7 +2798,7 @@ importers: version: 16.10.0(@swc-node/register@1.8.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.3.107(@swc/helpers@0.5.12)) ts-jest: specifier: ^29.1.0 - version: 29.1.2(@babel/core@7.24.4)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.4))(jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)))(typescript@5.6.2) + version: 29.1.2(@babel/core@7.25.2)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(typescript@5.6.2) typescript: specifier: 5.6.2 version: 5.6.2 @@ -2956,13 +2956,13 @@ importers: version: 7.4.2(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) '@storybook/react-webpack5': specifier: ^7.4.2 - version: 7.4.2(@babel/core@7.22.11)(@swc/core@1.3.107(@swc/helpers@0.5.12))(@swc/helpers@0.5.12)(@types/react-dom@18.3.0)(@types/react@18.3.3)(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20))(encoding@0.1.13)(esbuild@0.18.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(type-fest@2.19.0)(typescript@5.6.2)(webpack-dev-server@4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)))(webpack-hot-middleware@2.26.1) + version: 7.4.2(@babel/core@7.23.2)(@swc/core@1.7.26(@swc/helpers@0.5.12))(@swc/helpers@0.5.12)(@types/react-dom@18.3.0)(@types/react@18.3.3)(@types/webpack@5.28.5(@swc/core@1.7.26(@swc/helpers@0.5.12)))(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(type-fest@2.19.0)(typescript@5.6.2)(webpack-hot-middleware@2.26.1) '@storybook/theming': specifier: ^7.4.2 version: 7.4.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@testing-library/jest-dom': specifier: ^6.4.1 - version: 6.4.2(@jest/globals@29.7.0)(@types/jest@29.5.13)(jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)))(vitest@1.2.1(@edge-runtime/vm@4.0.2)(@types/node@20.16.5)(jsdom@24.0.0)(less@4.2.0)(lightningcss@1.26.0)(sass@1.77.8)(sugarss@4.0.1(postcss@8.4.47))(terser@5.31.6)) + version: 6.4.2(@jest/globals@29.7.0)(@types/jest@29.5.13)(jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(vitest@1.2.1(@edge-runtime/vm@4.0.2)(@types/node@20.16.5)(jsdom@24.0.0)(less@4.2.0)(lightningcss@1.26.0)(sass@1.77.8)(sugarss@4.0.1(postcss@8.4.47))(terser@5.31.6)) '@testing-library/react': specifier: ^12.1.5 version: 12.1.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -3007,13 +3007,13 @@ importers: version: 7.4.2(encoding@0.1.13) ts-loader: specifier: ~9.4.0 - version: 9.4.4(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) + version: 9.4.4(typescript@5.6.2)(webpack@5.94.0(@swc/core@1.7.26(@swc/helpers@0.5.12))) typescript: specifier: 5.6.2 version: 5.6.2 url-loader: specifier: ^4.1.1 - version: 4.1.1(file-loader@6.2.0(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)))(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) + version: 4.1.1(file-loader@6.2.0(webpack@5.94.0(@swc/core@1.7.26(@swc/helpers@0.5.12))))(webpack@5.94.0(@swc/core@1.7.26(@swc/helpers@0.5.12))) vite: specifier: ^4.5.2 version: 4.5.2(@types/node@20.16.5)(less@4.2.0)(lightningcss@1.26.0)(sass@1.77.8)(sugarss@4.0.1(postcss@8.4.47))(terser@5.31.6) @@ -3204,7 +3204,7 @@ importers: version: 8.1.1 '@testing-library/jest-dom': specifier: ^6.4.1 - version: 6.4.2(@jest/globals@29.7.0)(@types/jest@29.5.13)(jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)))(vitest@1.2.1(@edge-runtime/vm@4.0.2)(@types/node@20.16.5)(jsdom@25.0.0)(less@4.2.0)(lightningcss@1.26.0)(sass@1.77.8)(sugarss@4.0.1(postcss@8.4.38))(terser@5.31.6)) + version: 6.4.2(@jest/globals@29.7.0)(@types/jest@29.5.13)(jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(vitest@1.2.1(@edge-runtime/vm@4.0.2)(@types/node@20.16.5)(jsdom@25.0.0)(less@4.2.0)(lightningcss@1.26.0)(sass@1.77.8)(sugarss@4.0.1(postcss@8.4.38))(terser@5.31.6)) '@testing-library/react': specifier: ^12.1.5 version: 12.1.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -3383,7 +3383,7 @@ importers: version: 3.8.3(encoding@0.1.13) jest: specifier: ^27.0.6 - version: 27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) + version: 27.5.1(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)) npm-run-all: specifier: ^4.1.5 version: 4.1.5 @@ -3392,7 +3392,7 @@ importers: version: 3.0.2 ts-jest: specifier: ^27.0.5 - version: 27.1.5(@babel/core@7.25.2)(@types/jest@29.5.2)(babel-jest@27.5.1(@babel/core@7.25.2))(jest@27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(typescript@5.6.2) + version: 27.1.5(@babel/core@7.25.2)(@types/jest@29.5.2)(babel-jest@27.5.1(@babel/core@7.25.2))(jest@27.5.1(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)))(typescript@5.6.2) typedoc: specifier: ^0.24.0 version: 0.24.6(typescript@5.6.2) @@ -3460,6 +3460,15 @@ importers: aws-lambda: specifier: ^1.0.7 version: 1.0.7 + class-transformer: + specifier: ^0.5.1 + version: 0.5.1 + class-validator: + specifier: ^0.14.1 + version: 0.14.1 + class-validator-jsonschema: + specifier: ^5.0.1 + version: 5.0.1(class-transformer@0.5.1)(class-validator@0.14.1) express: specifier: ^4.19.2 version: 4.19.2 @@ -3471,10 +3480,13 @@ importers: version: 8.0.0(typescript@5.6.2) next: specifier: ^13.5.4 - version: 13.5.6(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8) + version: 13.5.6(@babel/core@7.24.3)(@opentelemetry/api@1.9.0)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8) prettier: specifier: ^3.2.5 version: 3.3.2 + reflect-metadata: + specifier: ^0.2.2 + version: 0.2.2 ts-node: specifier: ^10.9.2 version: 10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2) @@ -3532,7 +3544,7 @@ importers: version: 29.5.0 ts-jest: specifier: ^29.0.3 - version: 29.1.0(@babel/core@7.25.2)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(esbuild@0.18.20)(jest@29.5.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(typescript@5.6.2) + version: 29.1.0(@babel/core@7.25.2)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(jest@29.5.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(typescript@5.6.2) typedoc: specifier: ^0.24.0 version: 0.24.6(typescript@5.6.2) @@ -3732,7 +3744,7 @@ importers: version: link:../react next: specifier: '>=13' - version: 13.5.6(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8) + version: 13.5.6(@babel/core@7.24.3)(@opentelemetry/api@1.9.0)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8) react: specifier: '>=17' version: 18.3.1 @@ -3803,7 +3815,7 @@ importers: version: 3.8.3(encoding@0.1.13) jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)) + version: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) nock: specifier: ^13.1.3 version: 13.3.0 @@ -3821,7 +3833,7 @@ importers: version: 0.0.0 ts-jest: specifier: ^29.1.2 - version: 29.1.2(@babel/core@7.25.2)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)))(typescript@5.6.2) + version: 29.1.2(@babel/core@7.25.2)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(esbuild@0.23.1)(jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(typescript@5.6.2) typedoc: specifier: ^0.24.0 version: 0.24.6(typescript@5.6.2) @@ -3912,7 +3924,7 @@ importers: version: 7.4.2(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) '@storybook/react-webpack5': specifier: ^7.4.2 - version: 7.4.2(@babel/core@7.25.2)(@swc/core@1.7.26(@swc/helpers@0.5.12))(@swc/helpers@0.5.12)(@types/react-dom@18.3.0)(@types/react@18.3.3)(@types/webpack@5.28.5(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack-dev-server@4.11.1)(webpack@5.78.0)))(encoding@0.1.13)(esbuild@0.18.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(type-fest@2.19.0)(typescript@5.6.2)(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack-dev-server@4.11.1)(webpack@5.78.0))(webpack-dev-server@4.11.1(webpack-cli@5.1.4)(webpack@5.78.0))(webpack-hot-middleware@2.26.1) + version: 7.4.2(@babel/core@7.25.2)(@swc/core@1.7.26(@swc/helpers@0.5.12))(@swc/helpers@0.5.12)(@types/react-dom@18.3.0)(@types/react@18.3.3)(@types/webpack@5.28.5(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0)))(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(type-fest@2.19.0)(typescript@5.6.2)(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0))(webpack-hot-middleware@2.26.1) '@testing-library/dom': specifier: ^9.3.0 version: 9.3.0 @@ -3945,10 +3957,10 @@ importers: version: 8.8.2 babel-loader: specifier: ^8.2.4 - version: 8.3.0(@babel/core@7.25.2)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)) + version: 8.3.0(@babel/core@7.25.2)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)) compression-webpack-plugin: specifier: ^10.0.0 - version: 10.0.0(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)) + version: 10.0.0(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)) jest: specifier: ^29.3.1 version: 29.5.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) @@ -3972,28 +3984,28 @@ importers: version: 7.4.2(encoding@0.1.13) terser-webpack-plugin: specifier: ^5.3.9 - version: 5.3.10(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)) + version: 5.3.10(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)) ts-jest: specifier: ^29.0.3 - version: 29.1.0(@babel/core@7.25.2)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(esbuild@0.18.20)(jest@29.5.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(typescript@5.6.2) + version: 29.1.0(@babel/core@7.25.2)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(jest@29.5.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(typescript@5.6.2) ts-loader: specifier: ~9.4.0 - version: 9.4.4(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)) + version: 9.4.4(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)) typescript: specifier: 5.6.2 version: 5.6.2 url-loader: specifier: ^4.1.1 - version: 4.1.1(file-loader@6.2.0(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)) + version: 4.1.1(file-loader@6.2.0(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)) webpack: specifier: ^5.74.0 - version: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4) + version: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4) webpack-bundle-analyzer: specifier: ^4.9.0 version: 4.9.0 webpack-cli: specifier: ^5.1.4 - version: 5.1.4(webpack-bundle-analyzer@4.9.0)(webpack-dev-server@4.11.1)(webpack@5.78.0) + version: 5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0) packages/novu: dependencies: @@ -4403,7 +4415,7 @@ importers: version: 3.8.3(encoding@0.1.13) jest: specifier: ^27.0.6 - version: 27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) + version: 27.5.1(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)) npm-run-all: specifier: ^4.1.5 version: 4.1.5 @@ -4418,7 +4430,7 @@ importers: version: 0.0.0 ts-jest: specifier: ^27.0.5 - version: 27.1.5(@babel/core@7.25.2)(@types/jest@29.5.2)(babel-jest@27.5.1(@babel/core@7.25.2))(jest@27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(typescript@5.6.2) + version: 27.1.5(@babel/core@7.25.2)(@types/jest@29.5.2)(babel-jest@27.5.1(@babel/core@7.25.2))(jest@27.5.1(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)))(typescript@5.6.2) typedoc: specifier: ^0.24.0 version: 0.24.6(typescript@5.6.2) @@ -4533,7 +4545,7 @@ importers: version: 0.439.0(react@18.3.1) next: specifier: 14.2.4 - version: 14.2.4(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.46.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8) + version: 14.2.4(@babel/core@7.24.3)(@opentelemetry/api@1.9.0)(@playwright/test@1.46.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8) react: specifier: ^18 version: 18.3.1 @@ -19735,6 +19747,12 @@ packages: resolution: {integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==} engines: {node: '>=0.10.0'} + class-validator-jsonschema@5.0.1: + resolution: {integrity: sha512-9uTdo5jSnJUj7f0dS8YZDqM0Fv1Uky0BWefswnNa2F4nRcKPCiEb5z3nDUaXyEzcERCrizE+0AGDSao1uSNX9g==} + peerDependencies: + class-transformer: ^0.4.0 || ^0.5.0 + class-validator: ^0.14.0 + class-validator@0.14.1: resolution: {integrity: sha512-2VEG9JICxIqTpoK1eMzZqaV+u/EiwEJkMGzTrZf6sU/fwsnOITVgYJ8yojSy6CaXtO9V0Cc6ZQZ8h8m4UBuLwQ==} @@ -25939,6 +25957,9 @@ packages: lodash.get@4.4.2: resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} + lodash.groupby@4.6.0: + resolution: {integrity: sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==} + lodash.includes@4.3.0: resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} @@ -27789,6 +27810,9 @@ packages: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} + openapi3-ts@3.2.0: + resolution: {integrity: sha512-/ykNWRV5Qs0Nwq7Pc0nJ78fgILvOT/60OxEmB3v7yQ8a8Bwcm43D4diaYazG/KBn6czA+52XYy931WFLMCUeSg==} + opener@1.5.2: resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==} hasBin: true @@ -30595,6 +30619,9 @@ packages: resolution: {integrity: sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + reflect-metadata@0.1.14: + resolution: {integrity: sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==} + reflect-metadata@0.2.2: resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} @@ -35289,8 +35316,8 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.575.0(@aws-sdk/client-sts@3.575.0) - '@aws-sdk/client-sts': 3.575.0 + '@aws-sdk/client-sso-oidc': 3.575.0 + '@aws-sdk/client-sts': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) '@aws-sdk/core': 3.575.0 '@aws-sdk/credential-provider-node': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0) '@aws-sdk/middleware-host-header': 3.575.0 @@ -35491,8 +35518,8 @@ snapshots: '@aws-crypto/sha1-browser': 3.0.0 '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.575.0(@aws-sdk/client-sts@3.575.0) - '@aws-sdk/client-sts': 3.575.0 + '@aws-sdk/client-sso-oidc': 3.575.0 + '@aws-sdk/client-sts': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) '@aws-sdk/core': 3.575.0 '@aws-sdk/credential-provider-node': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0) '@aws-sdk/middleware-bucket-endpoint': 3.575.0 @@ -35718,11 +35745,11 @@ snapshots: - aws-crt optional: true - '@aws-sdk/client-sso-oidc@3.575.0(@aws-sdk/client-sts@3.575.0)': + '@aws-sdk/client-sso-oidc@3.575.0': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.575.0 + '@aws-sdk/client-sts': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) '@aws-sdk/core': 3.575.0 '@aws-sdk/credential-provider-node': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0) '@aws-sdk/middleware-host-header': 3.575.0 @@ -35761,7 +35788,6 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.7.0 transitivePeerDependencies: - - '@aws-sdk/client-sts' - aws-crt '@aws-sdk/client-sso-oidc@3.637.0(@aws-sdk/client-sts@3.637.0)': @@ -36146,11 +36172,11 @@ snapshots: - aws-crt optional: true - '@aws-sdk/client-sts@3.575.0': + '@aws-sdk/client-sts@3.575.0(@aws-sdk/client-sso-oidc@3.575.0)': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.575.0(@aws-sdk/client-sts@3.575.0) + '@aws-sdk/client-sso-oidc': 3.575.0 '@aws-sdk/core': 3.575.0 '@aws-sdk/credential-provider-node': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0) '@aws-sdk/middleware-host-header': 3.575.0 @@ -36189,6 +36215,7 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.7.0 transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' - aws-crt '@aws-sdk/client-sts@3.637.0': @@ -36418,7 +36445,7 @@ snapshots: '@aws-sdk/credential-provider-ini@3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0)': dependencies: - '@aws-sdk/client-sts': 3.575.0 + '@aws-sdk/client-sts': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) '@aws-sdk/credential-provider-env': 3.575.0 '@aws-sdk/credential-provider-process': 3.575.0 '@aws-sdk/credential-provider-sso': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) @@ -36729,7 +36756,7 @@ snapshots: '@aws-sdk/credential-provider-web-identity@3.575.0(@aws-sdk/client-sts@3.575.0)': dependencies: - '@aws-sdk/client-sts': 3.575.0 + '@aws-sdk/client-sts': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) '@aws-sdk/types': 3.575.0 '@smithy/property-provider': 3.1.3 '@smithy/types': 3.3.0 @@ -37250,7 +37277,7 @@ snapshots: '@aws-sdk/token-providers@3.575.0(@aws-sdk/client-sso-oidc@3.575.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.575.0(@aws-sdk/client-sts@3.575.0) + '@aws-sdk/client-sso-oidc': 3.575.0 '@aws-sdk/types': 3.575.0 '@smithy/property-provider': 3.1.3 '@smithy/shared-ini-file-loader': 3.1.4 @@ -37259,7 +37286,7 @@ snapshots: '@aws-sdk/token-providers@3.614.0(@aws-sdk/client-sso-oidc@3.575.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.575.0(@aws-sdk/client-sts@3.575.0) + '@aws-sdk/client-sso-oidc': 3.575.0 '@aws-sdk/types': 3.609.0 '@smithy/property-provider': 3.1.3 '@smithy/shared-ini-file-loader': 3.1.4 @@ -38042,6 +38069,17 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-define-polyfill-provider@0.6.2(@babel/core@7.22.11)': + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + debug: 4.3.6(supports-color@8.1.1) + lodash.debounce: 4.0.8 + resolve: 1.22.8 + transitivePeerDependencies: + - supports-color + '@babel/helper-define-polyfill-provider@0.6.2(@babel/core@7.24.3)': dependencies: '@babel/core': 7.24.3 @@ -38136,6 +38174,17 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-module-transforms@7.22.20(@babel/core@7.22.11)': + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-simple-access': 7.24.7 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-validator-identifier': 7.24.7 + transitivePeerDependencies: + - supports-color + '@babel/helper-module-transforms@7.22.20(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -38659,6 +38708,13 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.21.4) + '@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.22.11)': + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.22.11) + '@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -38734,6 +38790,12 @@ snapshots: '@babel/core': 7.21.4 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.24.3)': + dependencies: + '@babel/core': 7.24.3 + '@babel/helper-plugin-utils': 7.24.8 + optional: true + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 @@ -38869,14 +38931,14 @@ snapshots: '@babel/core': 7.21.4 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-flow@7.24.7(@babel/core@7.21.4)': + '@babel/plugin-syntax-flow@7.24.7(@babel/core@7.22.11)': dependencies: - '@babel/core': 7.21.4 + '@babel/core': 7.22.11 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-flow@7.24.7(@babel/core@7.22.11)': + '@babel/plugin-syntax-flow@7.24.7(@babel/core@7.23.2)': dependencies: - '@babel/core': 7.22.11 + '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-flow@7.24.7(@babel/core@7.24.3)': @@ -39009,6 +39071,11 @@ snapshots: '@babel/core': 7.22.11 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-jsx@7.22.5(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-jsx@7.22.5(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 @@ -39019,9 +39086,9 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.21.4)': + '@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.22.11)': dependencies: - '@babel/core': 7.21.4 + '@babel/core': 7.22.11 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.24.3)': @@ -39244,9 +39311,9 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-typescript@7.21.4(@babel/core@7.21.4)': + '@babel/plugin-syntax-typescript@7.21.4(@babel/core@7.22.11)': dependencies: - '@babel/core': 7.21.4 + '@babel/core': 7.22.11 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-typescript@7.21.4(@babel/core@7.25.2)': @@ -39923,18 +39990,18 @@ snapshots: '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-flow': 7.22.5(@babel/core@7.21.4) - '@babel/plugin-transform-flow-strip-types@7.25.2(@babel/core@7.21.4)': - dependencies: - '@babel/core': 7.21.4 - '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-flow': 7.24.7(@babel/core@7.21.4) - '@babel/plugin-transform-flow-strip-types@7.25.2(@babel/core@7.22.11)': dependencies: '@babel/core': 7.22.11 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-flow': 7.24.7(@babel/core@7.22.11) + '@babel/plugin-transform-flow-strip-types@7.25.2(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-flow': 7.24.7(@babel/core@7.23.2) + '@babel/plugin-transform-flow-strip-types@7.25.2(@babel/core@7.24.3)': dependencies: '@babel/core': 7.24.3 @@ -40209,10 +40276,10 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-commonjs@7.22.15(@babel/core@7.21.4)': + '@babel/plugin-transform-modules-commonjs@7.22.15(@babel/core@7.22.11)': dependencies: - '@babel/core': 7.21.4 - '@babel/helper-module-transforms': 7.22.20(@babel/core@7.21.4) + '@babel/core': 7.22.11 + '@babel/helper-module-transforms': 7.22.20(@babel/core@7.22.11) '@babel/helper-plugin-utils': 7.24.8 '@babel/helper-simple-access': 7.22.5 transitivePeerDependencies: @@ -40863,6 +40930,11 @@ snapshots: '@babel/core': 7.21.4 '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-transform-react-display-name@7.18.6(@babel/core@7.22.11)': + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-transform-react-display-name@7.22.5(@babel/core@7.21.4)': dependencies: '@babel/core': 7.21.4 @@ -40873,6 +40945,11 @@ snapshots: '@babel/core': 7.22.11 '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-react-display-name@7.22.5(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-transform-react-display-name@7.22.5(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -40890,10 +40967,10 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-react-jsx-development@7.22.5(@babel/core@7.21.4)': + '@babel/plugin-transform-react-jsx-development@7.18.6(@babel/core@7.22.11)': dependencies: - '@babel/core': 7.21.4 - '@babel/plugin-transform-react-jsx': 7.22.15(@babel/core@7.21.4) + '@babel/core': 7.22.11 + '@babel/plugin-transform-react-jsx': 7.21.0(@babel/core@7.22.11) transitivePeerDependencies: - supports-color @@ -40904,6 +40981,13 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-react-jsx-development@7.22.5(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/plugin-transform-react-jsx': 7.22.15(@babel/core@7.23.2) + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-react-jsx-development@7.22.5(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -40959,14 +41043,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-react-jsx@7.22.15(@babel/core@7.21.4)': + '@babel/plugin-transform-react-jsx@7.21.0(@babel/core@7.22.11)': dependencies: - '@babel/core': 7.21.4 - '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/core': 7.22.11 + '@babel/helper-annotate-as-pure': 7.18.6 '@babel/helper-module-imports': 7.24.7 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-jsx': 7.22.5(@babel/core@7.21.4) - '@babel/types': 7.25.6 + '@babel/plugin-syntax-jsx': 7.22.5(@babel/core@7.22.11) + '@babel/types': 7.22.19 transitivePeerDependencies: - supports-color @@ -40981,6 +41065,17 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-react-jsx@7.22.15(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-jsx': 7.22.5(@babel/core@7.23.2) + '@babel/types': 7.25.6 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-react-jsx@7.22.15(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -41003,13 +41098,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.21.4)': + '@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.22.11)': dependencies: - '@babel/core': 7.21.4 + '@babel/core': 7.22.11 '@babel/helper-annotate-as-pure': 7.24.7 '@babel/helper-module-imports': 7.24.7 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.21.4) + '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.22.11) '@babel/types': 7.25.6 transitivePeerDependencies: - supports-color @@ -41042,10 +41137,10 @@ snapshots: '@babel/helper-annotate-as-pure': 7.18.6 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-react-pure-annotations@7.22.5(@babel/core@7.21.4)': + '@babel/plugin-transform-react-pure-annotations@7.18.6(@babel/core@7.22.11)': dependencies: - '@babel/core': 7.21.4 - '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/core': 7.22.11 + '@babel/helper-annotate-as-pure': 7.18.6 '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-transform-react-pure-annotations@7.22.5(@babel/core@7.22.11)': @@ -41054,6 +41149,12 @@ snapshots: '@babel/helper-annotate-as-pure': 7.22.5 '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-react-pure-annotations@7.22.5(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-transform-react-pure-annotations@7.22.5(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -41144,6 +41245,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-runtime@7.23.2(@babel/core@7.22.11)': + dependencies: + '@babel/core': 7.22.11 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-plugin-utils': 7.24.8 + babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.22.11) + babel-plugin-polyfill-corejs3: 0.8.5(@babel/core@7.22.11) + babel-plugin-polyfill-regenerator: 0.5.3(@babel/core@7.22.11) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-runtime@7.23.2(@babel/core@7.24.4)': dependencies: '@babel/core': 7.24.4 @@ -41328,13 +41441,13 @@ snapshots: '@babel/core': 7.25.2 '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-transform-typescript@7.21.3(@babel/core@7.21.4)': + '@babel/plugin-transform-typescript@7.21.3(@babel/core@7.22.11)': dependencies: - '@babel/core': 7.21.4 + '@babel/core': 7.22.11 '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-create-class-features-plugin': 7.22.15(@babel/core@7.21.4) + '@babel/helper-create-class-features-plugin': 7.22.15(@babel/core@7.22.11) '@babel/helper-plugin-utils': 7.24.8 - '@babel/plugin-syntax-typescript': 7.21.4(@babel/core@7.21.4) + '@babel/plugin-syntax-typescript': 7.21.4(@babel/core@7.22.11) '@babel/plugin-transform-typescript@7.21.3(@babel/core@7.25.2)': dependencies: @@ -42030,19 +42143,19 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/preset-flow@7.22.15(@babel/core@7.21.4)': + '@babel/preset-flow@7.22.15(@babel/core@7.22.11)': dependencies: - '@babel/core': 7.21.4 + '@babel/core': 7.22.11 '@babel/helper-plugin-utils': 7.24.8 '@babel/helper-validator-option': 7.24.8 - '@babel/plugin-transform-flow-strip-types': 7.25.2(@babel/core@7.21.4) + '@babel/plugin-transform-flow-strip-types': 7.25.2(@babel/core@7.22.11) - '@babel/preset-flow@7.22.15(@babel/core@7.22.11)': + '@babel/preset-flow@7.22.15(@babel/core@7.23.2)': dependencies: - '@babel/core': 7.22.11 + '@babel/core': 7.23.2 '@babel/helper-plugin-utils': 7.24.8 '@babel/helper-validator-option': 7.24.8 - '@babel/plugin-transform-flow-strip-types': 7.25.2(@babel/core@7.22.11) + '@babel/plugin-transform-flow-strip-types': 7.25.2(@babel/core@7.23.2) '@babel/preset-flow@7.22.15(@babel/core@7.25.2)': dependencies: @@ -42112,15 +42225,15 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/preset-react@7.22.15(@babel/core@7.21.4)': + '@babel/preset-react@7.18.6(@babel/core@7.22.11)': dependencies: - '@babel/core': 7.21.4 - '@babel/helper-plugin-utils': 7.22.5 - '@babel/helper-validator-option': 7.22.15 - '@babel/plugin-transform-react-display-name': 7.22.5(@babel/core@7.21.4) - '@babel/plugin-transform-react-jsx': 7.22.15(@babel/core@7.21.4) - '@babel/plugin-transform-react-jsx-development': 7.22.5(@babel/core@7.21.4) - '@babel/plugin-transform-react-pure-annotations': 7.22.5(@babel/core@7.21.4) + '@babel/core': 7.22.11 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-validator-option': 7.21.0 + '@babel/plugin-transform-react-display-name': 7.18.6(@babel/core@7.22.11) + '@babel/plugin-transform-react-jsx': 7.21.0(@babel/core@7.22.11) + '@babel/plugin-transform-react-jsx-development': 7.18.6(@babel/core@7.22.11) + '@babel/plugin-transform-react-pure-annotations': 7.18.6(@babel/core@7.22.11) transitivePeerDependencies: - supports-color @@ -42136,6 +42249,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/preset-react@7.22.15(@babel/core@7.23.2)': + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-validator-option': 7.22.15 + '@babel/plugin-transform-react-display-name': 7.22.5(@babel/core@7.23.2) + '@babel/plugin-transform-react-jsx': 7.22.15(@babel/core@7.23.2) + '@babel/plugin-transform-react-jsx-development': 7.22.5(@babel/core@7.23.2) + '@babel/plugin-transform-react-pure-annotations': 7.22.5(@babel/core@7.23.2) + transitivePeerDependencies: + - supports-color + '@babel/preset-react@7.22.15(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 @@ -42160,14 +42285,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/preset-typescript@7.21.4(@babel/core@7.21.4)': + '@babel/preset-typescript@7.21.4(@babel/core@7.22.11)': dependencies: - '@babel/core': 7.21.4 + '@babel/core': 7.22.11 '@babel/helper-plugin-utils': 7.22.5 '@babel/helper-validator-option': 7.22.15 - '@babel/plugin-syntax-jsx': 7.22.5(@babel/core@7.21.4) - '@babel/plugin-transform-modules-commonjs': 7.22.15(@babel/core@7.21.4) - '@babel/plugin-transform-typescript': 7.21.3(@babel/core@7.21.4) + '@babel/plugin-syntax-jsx': 7.22.5(@babel/core@7.22.11) + '@babel/plugin-transform-modules-commonjs': 7.22.15(@babel/core@7.22.11) + '@babel/plugin-transform-typescript': 7.21.3(@babel/core@7.22.11) transitivePeerDependencies: - supports-color @@ -43711,11 +43836,11 @@ snapshots: to-pascal-case: 1.0.0 unescape-js: 1.1.4 - '@esbuild-plugins/node-resolve@0.2.2(esbuild@0.23.1)': + '@esbuild-plugins/node-resolve@0.2.2(esbuild@0.18.20)': dependencies: '@types/resolve': 1.20.2 debug: 4.3.6(supports-color@8.1.1) - esbuild: 0.23.1 + esbuild: 0.18.20 escape-string-regexp: 4.0.0 resolve: 1.22.8 transitivePeerDependencies: @@ -44665,7 +44790,7 @@ snapshots: - ts-node - utf-8-validate - '@jest/core@27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2))': + '@jest/core@27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@22.7.4)(typescript@5.6.2))': dependencies: '@jest/console': 27.5.1 '@jest/reporters': 27.5.1 @@ -44679,7 +44804,7 @@ snapshots: exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 27.5.1 - jest-config: 27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) + jest-config: 27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@22.7.4)(typescript@5.6.2)) jest-haste-map: 27.5.1 jest-message-util: 27.5.1 jest-regex-util: 27.5.1 @@ -44702,44 +44827,42 @@ snapshots: - ts-node - utf-8-validate - '@jest/core@27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@22.7.4)(typescript@5.6.2))': + '@jest/core@29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2))': dependencies: - '@jest/console': 27.5.1 - '@jest/reporters': 27.5.1 - '@jest/test-result': 27.5.1 - '@jest/transform': 27.5.1 - '@jest/types': 27.5.1 + '@jest/console': 29.7.0 + '@jest/reporters': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 '@types/node': 20.16.5 ansi-escapes: 4.3.2 chalk: 4.1.2 - emittery: 0.8.1 + ci-info: 3.9.0 exit: 0.1.2 graceful-fs: 4.2.11 - jest-changed-files: 27.5.1 - jest-config: 27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@22.7.4)(typescript@5.6.2)) - jest-haste-map: 27.5.1 - jest-message-util: 27.5.1 - jest-regex-util: 27.5.1 - jest-resolve: 27.5.1 - jest-resolve-dependencies: 27.5.1 - jest-runner: 27.5.1 - jest-runtime: 27.5.1 - jest-snapshot: 27.5.1 - jest-util: 27.5.1 - jest-validate: 27.5.1 - jest-watcher: 27.5.1 + jest-changed-files: 29.7.0 + jest-config: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 micromatch: 4.0.8 - rimraf: 3.0.2 + pretty-format: 29.7.0 slash: 3.0.0 strip-ansi: 6.0.1 transitivePeerDependencies: - - bufferutil - - canvas + - babel-plugin-macros - supports-color - ts-node - - utf-8-validate - '@jest/core@29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2))': + '@jest/core@29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2))': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0 @@ -44753,7 +44876,7 @@ snapshots: exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)) + jest-config: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -44774,7 +44897,7 @@ snapshots: - supports-color - ts-node - '@jest/core@29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2))': + '@jest/core@29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2))': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0 @@ -44788,7 +44911,7 @@ snapshots: exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) + jest-config: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -46018,11 +46141,11 @@ snapshots: - encoding - supports-color - '@mdx-js/esbuild@3.0.1(esbuild@0.23.1)': + '@mdx-js/esbuild@3.0.1(esbuild@0.18.20)': dependencies: '@mdx-js/mdx': 3.0.1 '@types/unist': 3.0.2 - esbuild: 0.23.1 + esbuild: 0.18.20 vfile: 6.0.1 vfile-message: 4.0.2 transitivePeerDependencies: @@ -49424,7 +49547,7 @@ snapshots: webpack-dev-server: 4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) webpack-hot-middleware: 2.26.1 - '@pmmmwh/react-refresh-webpack-plugin@0.5.10(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1))(react-refresh@0.11.0)(type-fest@2.19.0)(webpack-dev-server@4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)))(webpack-hot-middleware@2.26.1)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1))': + '@pmmmwh/react-refresh-webpack-plugin@0.5.10(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12)))(react-refresh@0.11.0)(type-fest@2.19.0)(webpack-dev-server@4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(webpack-hot-middleware@2.26.1)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12)))': dependencies: ansi-html-community: 0.0.8 common-path-prefix: 3.0.0 @@ -49436,14 +49559,14 @@ snapshots: react-refresh: 0.11.0 schema-utils: 3.3.0 source-map: 0.7.4 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12)) optionalDependencies: - '@types/webpack': 5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) + '@types/webpack': 5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12)) type-fest: 2.19.0 - webpack-dev-server: 4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) + webpack-dev-server: 4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) webpack-hot-middleware: 2.26.1 - '@pmmmwh/react-refresh-webpack-plugin@0.5.10(@types/webpack@5.28.5(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack-dev-server@4.11.1)(webpack@5.78.0)))(react-refresh@0.11.0)(type-fest@2.19.0)(webpack-dev-server@4.11.1(webpack-cli@5.1.4)(webpack@5.78.0))(webpack-hot-middleware@2.26.1)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4))': + '@pmmmwh/react-refresh-webpack-plugin@0.5.10(@types/webpack@5.28.5(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0)))(react-refresh@0.11.0)(type-fest@2.19.0)(webpack-hot-middleware@2.26.1)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4))': dependencies: ansi-html-community: 0.0.8 common-path-prefix: 3.0.0 @@ -49455,14 +49578,13 @@ snapshots: react-refresh: 0.11.0 schema-utils: 3.3.0 source-map: 0.7.4 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4) optionalDependencies: - '@types/webpack': 5.28.5(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack-dev-server@4.11.1)(webpack@5.78.0)) + '@types/webpack': 5.28.5(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0)) type-fest: 2.19.0 - webpack-dev-server: 4.11.1(webpack-cli@5.1.4)(webpack@5.78.0) webpack-hot-middleware: 2.26.1 - '@pmmmwh/react-refresh-webpack-plugin@0.5.10(@types/webpack@5.28.5(@swc/core@1.7.26(@swc/helpers@0.5.12)))(react-refresh@0.11.0)(type-fest@2.19.0)(webpack-dev-server@4.11.1(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))))(webpack-hot-middleware@2.26.1)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12)))': + '@pmmmwh/react-refresh-webpack-plugin@0.5.10(@types/webpack@5.28.5(@swc/core@1.7.26(@swc/helpers@0.5.12)))(react-refresh@0.11.0)(type-fest@2.19.0)(webpack-hot-middleware@2.26.1)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12)))': dependencies: ansi-html-community: 0.0.8 common-path-prefix: 3.0.0 @@ -49478,7 +49600,6 @@ snapshots: optionalDependencies: '@types/webpack': 5.28.5(@swc/core@1.7.26(@swc/helpers@0.5.12)) type-fest: 2.19.0 - webpack-dev-server: 4.11.1(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))) webpack-hot-middleware: 2.26.1 '@pnpm/cli-meta@5.0.0': @@ -54483,7 +54604,7 @@ snapshots: - uglify-js - webpack-cli - '@storybook/builder-webpack5@7.4.2(@swc/helpers@0.5.12)(@types/react-dom@18.3.0)(@types/react@18.3.3)(encoding@0.1.13)(esbuild@0.18.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack-dev-server@4.11.1)(webpack@5.78.0))': + '@storybook/builder-webpack5@7.4.2(@swc/helpers@0.5.12)(@types/react-dom@18.3.0)(@types/react@18.3.3)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)': dependencies: '@babel/core': 7.23.2 '@storybook/addons': 7.4.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -54505,30 +54626,30 @@ snapshots: '@swc/core': 1.3.107(@swc/helpers@0.5.12) '@types/node': 16.11.7 '@types/semver': 7.3.13 - babel-loader: 9.1.2(@babel/core@7.23.2)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)) + babel-loader: 9.1.2(@babel/core@7.23.2)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) babel-plugin-named-exports-order: 0.0.2 browser-assert: 1.2.1 case-sensitive-paths-webpack-plugin: 2.4.0 constants-browserify: 1.0.0 - css-loader: 6.7.3(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)) + css-loader: 6.7.3(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) express: 4.21.0 - fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)) + fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) fs-extra: 11.2.0 - html-webpack-plugin: 5.5.3(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)) + html-webpack-plugin: 5.5.3(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) path-browserify: 1.0.1 process: 0.11.10 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) semver: 7.6.3 - style-loader: 3.3.2(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)) - swc-loader: 0.2.3(@swc/core@1.3.107(@swc/helpers@0.5.12))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)) - terser-webpack-plugin: 5.3.10(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)) + style-loader: 3.3.2(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) + swc-loader: 0.2.3(@swc/core@1.3.107(@swc/helpers@0.5.12))(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) + terser-webpack-plugin: 5.3.10(@swc/core@1.3.107(@swc/helpers@0.5.12))(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) ts-dedent: 2.2.0 url: 0.11.4 util: 0.12.5 util-deprecate: 1.0.2 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack-dev-server@4.11.1)(webpack@5.78.0)) - webpack-dev-middleware: 6.1.1(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12)) + webpack-dev-middleware: 6.1.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) webpack-hot-middleware: 2.25.3 webpack-virtual-modules: 0.5.0 optionalDependencies: @@ -54543,7 +54664,7 @@ snapshots: - uglify-js - webpack-cli - '@storybook/builder-webpack5@7.4.2(@swc/helpers@0.5.12)(@types/react-dom@18.3.0)(@types/react@18.3.3)(encoding@0.1.13)(esbuild@0.23.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)': + '@storybook/builder-webpack5@7.4.2(@swc/helpers@0.5.12)(@types/react-dom@18.3.0)(@types/react@18.3.3)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0))': dependencies: '@babel/core': 7.23.2 '@storybook/addons': 7.4.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -54565,30 +54686,30 @@ snapshots: '@swc/core': 1.3.107(@swc/helpers@0.5.12) '@types/node': 16.11.7 '@types/semver': 7.3.13 - babel-loader: 9.1.2(@babel/core@7.23.2)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) + babel-loader: 9.1.2(@babel/core@7.23.2)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)) babel-plugin-named-exports-order: 0.0.2 browser-assert: 1.2.1 case-sensitive-paths-webpack-plugin: 2.4.0 constants-browserify: 1.0.0 - css-loader: 6.7.3(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) + css-loader: 6.7.3(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)) express: 4.21.0 - fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) + fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)) fs-extra: 11.2.0 - html-webpack-plugin: 5.5.3(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) + html-webpack-plugin: 5.5.3(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)) path-browserify: 1.0.1 process: 0.11.10 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) semver: 7.6.3 - style-loader: 3.3.2(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) - swc-loader: 0.2.3(@swc/core@1.3.107(@swc/helpers@0.5.12))(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) - terser-webpack-plugin: 5.3.10(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) + style-loader: 3.3.2(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)) + swc-loader: 0.2.3(@swc/core@1.3.107(@swc/helpers@0.5.12))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)) + terser-webpack-plugin: 5.3.10(@swc/core@1.3.107(@swc/helpers@0.5.12))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)) ts-dedent: 2.2.0 url: 0.11.4 util: 0.12.5 util-deprecate: 1.0.2 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) - webpack-dev-middleware: 6.1.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0)) + webpack-dev-middleware: 6.1.1(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)) webpack-hot-middleware: 2.25.3 webpack-virtual-modules: 0.5.0 optionalDependencies: @@ -55239,16 +55360,16 @@ snapshots: '@storybook/postinstall@7.4.2': {} - '@storybook/preset-create-react-app@7.4.2(f7avyblvzm233o6g7idqcb345u)': + '@storybook/preset-create-react-app@7.4.2(ucmnrhmq4kewpo24xrp57f5r6y)': dependencies: - '@babel/core': 7.21.4 - '@pmmmwh/react-refresh-webpack-plugin': 0.5.10(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1))(react-refresh@0.11.0)(type-fest@2.19.0)(webpack-dev-server@4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)))(webpack-hot-middleware@2.26.1)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) - '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) + '@babel/core': 7.22.11 + '@pmmmwh/react-refresh-webpack-plugin': 0.5.10(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20))(react-refresh@0.11.0)(type-fest@2.19.0)(webpack-dev-server@4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)))(webpack-hot-middleware@2.26.1)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) + '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) '@storybook/types': 7.4.2 '@types/babel__core': 7.20.0 babel-plugin-react-docgen: 4.2.1 pnp-webpack-plugin: 1.7.0(typescript@5.6.2) - react-scripts: 5.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.21.4))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.21.4))(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/babel__core@7.20.5)(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1))(esbuild@0.23.1)(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6))(react@18.3.1)(sass@1.77.8)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2))(type-fest@2.19.0)(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack-hot-middleware@2.26.1) + react-scripts: 5.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.22.11))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.22.11))(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/babel__core@7.20.5)(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20))(esbuild@0.18.20)(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6))(react@18.3.1)(sass@1.77.8)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2))(type-fest@2.19.0)(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack-hot-middleware@2.26.1) semver: 7.5.4 transitivePeerDependencies: - '@types/webpack' @@ -55262,16 +55383,16 @@ snapshots: - webpack-hot-middleware - webpack-plugin-serve - '@storybook/preset-react-webpack@7.4.2(@babel/core@7.21.4)(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1))(encoding@0.1.13)(esbuild@0.23.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(type-fest@2.19.0)(typescript@5.6.2)(webpack-dev-server@4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)))(webpack-hot-middleware@2.26.1)': + '@storybook/preset-react-webpack@7.4.2(@babel/core@7.22.11)(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20))(encoding@0.1.13)(esbuild@0.18.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(type-fest@2.19.0)(typescript@5.6.2)(webpack-dev-server@4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)))(webpack-hot-middleware@2.26.1)': dependencies: - '@babel/preset-flow': 7.22.15(@babel/core@7.21.4) - '@babel/preset-react': 7.22.15(@babel/core@7.21.4) - '@pmmmwh/react-refresh-webpack-plugin': 0.5.10(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1))(react-refresh@0.11.0)(type-fest@2.19.0)(webpack-dev-server@4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)))(webpack-hot-middleware@2.26.1)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) + '@babel/preset-flow': 7.22.15(@babel/core@7.22.11) + '@babel/preset-react': 7.22.15(@babel/core@7.22.11) + '@pmmmwh/react-refresh-webpack-plugin': 0.5.10(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20))(react-refresh@0.11.0)(type-fest@2.19.0)(webpack-dev-server@4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)))(webpack-hot-middleware@2.26.1)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) '@storybook/core-webpack': 7.4.2(encoding@0.1.13) '@storybook/docs-tools': 7.4.2(encoding@0.1.13) '@storybook/node-logger': 7.4.2 '@storybook/react': 7.4.2(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) + '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) '@types/node': 16.11.7 '@types/semver': 7.5.8 babel-plugin-add-react-displayname: 0.0.5 @@ -55281,9 +55402,9 @@ snapshots: react-dom: 18.3.1(react@18.3.1) react-refresh: 0.11.0 semver: 7.6.3 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20) optionalDependencies: - '@babel/core': 7.21.4 + '@babel/core': 7.22.11 typescript: 5.6.2 transitivePeerDependencies: - '@swc/core' @@ -55299,16 +55420,16 @@ snapshots: - webpack-hot-middleware - webpack-plugin-serve - '@storybook/preset-react-webpack@7.4.2(@babel/core@7.22.11)(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20))(encoding@0.1.13)(esbuild@0.18.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(type-fest@2.19.0)(typescript@5.6.2)(webpack-dev-server@4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)))(webpack-hot-middleware@2.26.1)': + '@storybook/preset-react-webpack@7.4.2(@babel/core@7.23.2)(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/webpack@5.28.5(@swc/core@1.7.26(@swc/helpers@0.5.12)))(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(type-fest@2.19.0)(typescript@5.6.2)(webpack-hot-middleware@2.26.1)': dependencies: - '@babel/preset-flow': 7.22.15(@babel/core@7.22.11) - '@babel/preset-react': 7.22.15(@babel/core@7.22.11) - '@pmmmwh/react-refresh-webpack-plugin': 0.5.10(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20))(react-refresh@0.11.0)(type-fest@2.19.0)(webpack-dev-server@4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)))(webpack-hot-middleware@2.26.1)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) + '@babel/preset-flow': 7.22.15(@babel/core@7.23.2) + '@babel/preset-react': 7.22.15(@babel/core@7.23.2) + '@pmmmwh/react-refresh-webpack-plugin': 0.5.10(@types/webpack@5.28.5(@swc/core@1.7.26(@swc/helpers@0.5.12)))(react-refresh@0.11.0)(type-fest@2.19.0)(webpack-hot-middleware@2.26.1)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))) '@storybook/core-webpack': 7.4.2(encoding@0.1.13) '@storybook/docs-tools': 7.4.2(encoding@0.1.13) '@storybook/node-logger': 7.4.2 '@storybook/react': 7.4.2(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) + '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))) '@types/node': 16.11.7 '@types/semver': 7.5.8 babel-plugin-add-react-displayname: 0.0.5 @@ -55318,9 +55439,9 @@ snapshots: react-dom: 18.3.1(react@18.3.1) react-refresh: 0.11.0 semver: 7.6.3 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12)) optionalDependencies: - '@babel/core': 7.22.11 + '@babel/core': 7.23.2 typescript: 5.6.2 transitivePeerDependencies: - '@swc/core' @@ -55336,16 +55457,16 @@ snapshots: - webpack-hot-middleware - webpack-plugin-serve - '@storybook/preset-react-webpack@7.4.2(@babel/core@7.25.2)(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/webpack@5.28.5(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack-dev-server@4.11.1)(webpack@5.78.0)))(encoding@0.1.13)(esbuild@0.18.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(type-fest@2.19.0)(typescript@5.6.2)(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack-dev-server@4.11.1)(webpack@5.78.0))(webpack-dev-server@4.11.1(webpack-cli@5.1.4)(webpack@5.78.0))(webpack-hot-middleware@2.26.1)': + '@storybook/preset-react-webpack@7.4.2(@babel/core@7.25.2)(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/webpack@5.28.5(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0)))(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(type-fest@2.19.0)(typescript@5.6.2)(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0))(webpack-hot-middleware@2.26.1)': dependencies: '@babel/preset-flow': 7.22.15(@babel/core@7.25.2) '@babel/preset-react': 7.22.15(@babel/core@7.25.2) - '@pmmmwh/react-refresh-webpack-plugin': 0.5.10(@types/webpack@5.28.5(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack-dev-server@4.11.1)(webpack@5.78.0)))(react-refresh@0.11.0)(type-fest@2.19.0)(webpack-dev-server@4.11.1(webpack-cli@5.1.4)(webpack@5.78.0))(webpack-hot-middleware@2.26.1)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)) + '@pmmmwh/react-refresh-webpack-plugin': 0.5.10(@types/webpack@5.28.5(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0)))(react-refresh@0.11.0)(type-fest@2.19.0)(webpack-hot-middleware@2.26.1)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)) '@storybook/core-webpack': 7.4.2(encoding@0.1.13) '@storybook/docs-tools': 7.4.2(encoding@0.1.13) '@storybook/node-logger': 7.4.2 '@storybook/react': 7.4.2(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)) + '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)) '@types/node': 16.11.7 '@types/semver': 7.5.8 babel-plugin-add-react-displayname: 0.0.5 @@ -55355,7 +55476,7 @@ snapshots: react-dom: 18.3.1(react@18.3.1) react-refresh: 0.11.0 semver: 7.6.3 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4) optionalDependencies: '@babel/core': 7.25.2 typescript: 5.6.2 @@ -55459,7 +55580,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1))': + '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4))': dependencies: debug: 4.3.6(supports-color@8.1.1) endent: 2.1.0 @@ -55469,11 +55590,11 @@ snapshots: react-docgen-typescript: 2.2.2(typescript@5.6.2) tslib: 2.7.0 typescript: 5.6.2 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4) transitivePeerDependencies: - supports-color - '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4))': + '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12)))': dependencies: debug: 4.3.6(supports-color@8.1.1) endent: 2.1.0 @@ -55483,7 +55604,7 @@ snapshots: react-docgen-typescript: 2.2.2(typescript@5.6.2) tslib: 2.7.0 typescript: 5.6.2 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12)) transitivePeerDependencies: - supports-color @@ -55523,16 +55644,16 @@ snapshots: - vite-plugin-glimmerx - webpack-sources - '@storybook/react-webpack5@7.4.2(@babel/core@7.21.4)(@swc/core@1.3.107(@swc/helpers@0.5.12))(@swc/helpers@0.5.12)(@types/react-dom@18.3.0)(@types/react@18.3.3)(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1))(encoding@0.1.13)(esbuild@0.23.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(type-fest@2.19.0)(typescript@5.6.2)(webpack-dev-server@4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)))(webpack-hot-middleware@2.26.1)': + '@storybook/react-webpack5@7.4.2(@babel/core@7.22.11)(@swc/core@1.3.107(@swc/helpers@0.5.12))(@swc/helpers@0.5.12)(@types/react-dom@18.3.0)(@types/react@18.3.3)(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20))(encoding@0.1.13)(esbuild@0.18.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(type-fest@2.19.0)(typescript@5.6.2)(webpack-dev-server@4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)))(webpack-hot-middleware@2.26.1)': dependencies: - '@storybook/builder-webpack5': 7.4.2(@swc/helpers@0.5.12)(@types/react-dom@18.3.0)(@types/react@18.3.3)(encoding@0.1.13)(esbuild@0.23.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@storybook/preset-react-webpack': 7.4.2(@babel/core@7.21.4)(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1))(encoding@0.1.13)(esbuild@0.23.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(type-fest@2.19.0)(typescript@5.6.2)(webpack-dev-server@4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)))(webpack-hot-middleware@2.26.1) + '@storybook/builder-webpack5': 7.4.2(@swc/helpers@0.5.12)(@types/react-dom@18.3.0)(@types/react@18.3.3)(encoding@0.1.13)(esbuild@0.18.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@storybook/preset-react-webpack': 7.4.2(@babel/core@7.22.11)(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20))(encoding@0.1.13)(esbuild@0.18.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(type-fest@2.19.0)(typescript@5.6.2)(webpack-dev-server@4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)))(webpack-hot-middleware@2.26.1) '@storybook/react': 7.4.2(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) '@types/node': 16.11.7 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: - '@babel/core': 7.21.4 + '@babel/core': 7.22.11 typescript: 5.6.2 transitivePeerDependencies: - '@swc/core' @@ -55551,16 +55672,16 @@ snapshots: - webpack-hot-middleware - webpack-plugin-serve - '@storybook/react-webpack5@7.4.2(@babel/core@7.22.11)(@swc/core@1.3.107(@swc/helpers@0.5.12))(@swc/helpers@0.5.12)(@types/react-dom@18.3.0)(@types/react@18.3.3)(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20))(encoding@0.1.13)(esbuild@0.18.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(type-fest@2.19.0)(typescript@5.6.2)(webpack-dev-server@4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)))(webpack-hot-middleware@2.26.1)': + '@storybook/react-webpack5@7.4.2(@babel/core@7.23.2)(@swc/core@1.7.26(@swc/helpers@0.5.12))(@swc/helpers@0.5.12)(@types/react-dom@18.3.0)(@types/react@18.3.3)(@types/webpack@5.28.5(@swc/core@1.7.26(@swc/helpers@0.5.12)))(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(type-fest@2.19.0)(typescript@5.6.2)(webpack-hot-middleware@2.26.1)': dependencies: - '@storybook/builder-webpack5': 7.4.2(@swc/helpers@0.5.12)(@types/react-dom@18.3.0)(@types/react@18.3.3)(encoding@0.1.13)(esbuild@0.18.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) - '@storybook/preset-react-webpack': 7.4.2(@babel/core@7.22.11)(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20))(encoding@0.1.13)(esbuild@0.18.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(type-fest@2.19.0)(typescript@5.6.2)(webpack-dev-server@4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)))(webpack-hot-middleware@2.26.1) + '@storybook/builder-webpack5': 7.4.2(@swc/helpers@0.5.12)(@types/react-dom@18.3.0)(@types/react@18.3.3)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@storybook/preset-react-webpack': 7.4.2(@babel/core@7.23.2)(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/webpack@5.28.5(@swc/core@1.7.26(@swc/helpers@0.5.12)))(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(type-fest@2.19.0)(typescript@5.6.2)(webpack-hot-middleware@2.26.1) '@storybook/react': 7.4.2(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) '@types/node': 16.11.7 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: - '@babel/core': 7.22.11 + '@babel/core': 7.23.2 typescript: 5.6.2 transitivePeerDependencies: - '@swc/core' @@ -55579,10 +55700,10 @@ snapshots: - webpack-hot-middleware - webpack-plugin-serve - '@storybook/react-webpack5@7.4.2(@babel/core@7.25.2)(@swc/core@1.7.26(@swc/helpers@0.5.12))(@swc/helpers@0.5.12)(@types/react-dom@18.3.0)(@types/react@18.3.3)(@types/webpack@5.28.5(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack-dev-server@4.11.1)(webpack@5.78.0)))(encoding@0.1.13)(esbuild@0.18.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(type-fest@2.19.0)(typescript@5.6.2)(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack-dev-server@4.11.1)(webpack@5.78.0))(webpack-dev-server@4.11.1(webpack-cli@5.1.4)(webpack@5.78.0))(webpack-hot-middleware@2.26.1)': + '@storybook/react-webpack5@7.4.2(@babel/core@7.25.2)(@swc/core@1.7.26(@swc/helpers@0.5.12))(@swc/helpers@0.5.12)(@types/react-dom@18.3.0)(@types/react@18.3.3)(@types/webpack@5.28.5(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0)))(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(type-fest@2.19.0)(typescript@5.6.2)(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0))(webpack-hot-middleware@2.26.1)': dependencies: - '@storybook/builder-webpack5': 7.4.2(@swc/helpers@0.5.12)(@types/react-dom@18.3.0)(@types/react@18.3.3)(encoding@0.1.13)(esbuild@0.18.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack-dev-server@4.11.1)(webpack@5.78.0)) - '@storybook/preset-react-webpack': 7.4.2(@babel/core@7.25.2)(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/webpack@5.28.5(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack-dev-server@4.11.1)(webpack@5.78.0)))(encoding@0.1.13)(esbuild@0.18.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(type-fest@2.19.0)(typescript@5.6.2)(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack-dev-server@4.11.1)(webpack@5.78.0))(webpack-dev-server@4.11.1(webpack-cli@5.1.4)(webpack@5.78.0))(webpack-hot-middleware@2.26.1) + '@storybook/builder-webpack5': 7.4.2(@swc/helpers@0.5.12)(@types/react-dom@18.3.0)(@types/react@18.3.3)(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2)(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0)) + '@storybook/preset-react-webpack': 7.4.2(@babel/core@7.25.2)(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/webpack@5.28.5(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0)))(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(type-fest@2.19.0)(typescript@5.6.2)(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0))(webpack-hot-middleware@2.26.1) '@storybook/react': 7.4.2(encoding@0.1.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) '@types/node': 16.11.7 react: 18.3.1 @@ -56227,7 +56348,7 @@ snapshots: pretty-format: 24.9.0 redent: 3.0.0 - '@testing-library/jest-dom@6.4.2(@jest/globals@29.7.0)(@types/jest@29.5.13)(jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)))(vitest@1.2.1(@edge-runtime/vm@4.0.2)(@types/node@20.16.5)(jsdom@24.0.0)(less@4.2.0)(lightningcss@1.26.0)(sass@1.77.8)(sugarss@4.0.1(postcss@8.4.47))(terser@5.31.6))': + '@testing-library/jest-dom@6.4.2(@jest/globals@29.7.0)(@types/jest@29.5.13)(jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(vitest@1.2.1(@edge-runtime/vm@4.0.2)(@types/node@20.16.5)(jsdom@24.0.0)(less@4.2.0)(lightningcss@1.26.0)(sass@1.77.8)(sugarss@4.0.1(postcss@8.4.47))(terser@5.31.6))': dependencies: '@adobe/css-tools': 4.3.3 '@babel/runtime': 7.23.2 @@ -56240,10 +56361,10 @@ snapshots: optionalDependencies: '@jest/globals': 29.7.0 '@types/jest': 29.5.13 - jest: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)) + jest: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) vitest: 1.2.1(@edge-runtime/vm@4.0.2)(@types/node@20.16.5)(jsdom@24.0.0)(less@4.2.0)(lightningcss@1.26.0)(sass@1.77.8)(sugarss@4.0.1(postcss@8.4.47))(terser@5.31.6) - '@testing-library/jest-dom@6.4.2(@jest/globals@29.7.0)(@types/jest@29.5.13)(jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)))(vitest@1.2.1(@edge-runtime/vm@4.0.2)(@types/node@20.16.5)(jsdom@25.0.0)(less@4.2.0)(lightningcss@1.26.0)(sass@1.77.8)(sugarss@4.0.1(postcss@8.4.38))(terser@5.31.6))': + '@testing-library/jest-dom@6.4.2(@jest/globals@29.7.0)(@types/jest@29.5.13)(jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(vitest@1.2.1(@edge-runtime/vm@4.0.2)(@types/node@20.16.5)(jsdom@25.0.0)(less@4.2.0)(lightningcss@1.26.0)(sass@1.77.8)(sugarss@4.0.1(postcss@8.4.38))(terser@5.31.6))': dependencies: '@adobe/css-tools': 4.3.3 '@babel/runtime': 7.23.2 @@ -56256,7 +56377,7 @@ snapshots: optionalDependencies: '@jest/globals': 29.7.0 '@types/jest': 29.5.13 - jest: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)) + jest: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) vitest: 1.2.1(@edge-runtime/vm@4.0.2)(@types/node@20.16.5)(jsdom@25.0.0)(less@4.2.0)(lightningcss@1.26.0)(sass@1.77.8)(sugarss@4.0.1(postcss@8.4.38))(terser@5.31.6) '@testing-library/react-hooks@8.0.1(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': @@ -57401,11 +57522,11 @@ snapshots: '@types/webidl-conversions@7.0.3': optional: true - '@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)': + '@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))': dependencies: '@types/node': 20.16.5 tapable: 2.2.1 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12)) transitivePeerDependencies: - '@swc/core' - esbuild @@ -57413,11 +57534,11 @@ snapshots: - webpack-cli optional: true - '@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)': + '@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)': dependencies: '@types/node': 20.16.5 tapable: 2.2.1 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20) transitivePeerDependencies: - '@swc/core' - esbuild @@ -57437,11 +57558,11 @@ snapshots: - webpack-cli optional: true - '@types/webpack@5.28.5(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack-dev-server@4.11.1)(webpack@5.78.0))': + '@types/webpack@5.28.5(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0))': dependencies: '@types/node': 20.16.5 tapable: 2.2.1 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4) transitivePeerDependencies: - '@swc/core' - esbuild @@ -59027,32 +59148,30 @@ snapshots: webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0) - '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack-dev-server@4.11.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4))': + '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4))': dependencies: - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4) - webpack-cli: 5.1.4(webpack-bundle-analyzer@4.9.0)(webpack-dev-server@4.11.1)(webpack@5.78.0) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4) + webpack-cli: 5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0) '@webpack-cli/info@2.0.2(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4))': dependencies: webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0) - '@webpack-cli/info@2.0.2(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack-dev-server@4.11.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4))': + '@webpack-cli/info@2.0.2(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4))': dependencies: - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4) - webpack-cli: 5.1.4(webpack-bundle-analyzer@4.9.0)(webpack-dev-server@4.11.1)(webpack@5.78.0) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4) + webpack-cli: 5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0) '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4))': dependencies: webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0) - '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack-dev-server@4.11.1)(webpack@5.78.0))(webpack-dev-server@4.11.1(webpack-cli@5.1.4)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4))': + '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4))': dependencies: - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4) - webpack-cli: 5.1.4(webpack-bundle-analyzer@4.9.0)(webpack-dev-server@4.11.1)(webpack@5.78.0) - optionalDependencies: - webpack-dev-server: 4.11.1(webpack-cli@5.1.4)(webpack@5.78.0) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4) + webpack-cli: 5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0) '@wry/context@0.4.4': dependencies: @@ -60169,42 +60288,43 @@ snapshots: transitivePeerDependencies: - supports-color - babel-jest@27.5.1(@babel/core@7.24.4): + babel-jest@27.5.1(@babel/core@7.24.3): dependencies: - '@babel/core': 7.24.4 + '@babel/core': 7.24.3 '@jest/transform': 27.5.1 '@jest/types': 27.5.1 '@types/babel__core': 7.20.3 babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 27.5.1(@babel/core@7.24.4) + babel-preset-jest: 27.5.1(@babel/core@7.24.3) chalk: 4.1.2 graceful-fs: 4.2.11 slash: 3.0.0 transitivePeerDependencies: - supports-color + optional: true - babel-jest@27.5.1(@babel/core@7.25.2): + babel-jest@27.5.1(@babel/core@7.24.4): dependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.24.4 '@jest/transform': 27.5.1 '@jest/types': 27.5.1 '@types/babel__core': 7.20.3 babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 27.5.1(@babel/core@7.25.2) + babel-preset-jest: 27.5.1(@babel/core@7.24.4) chalk: 4.1.2 graceful-fs: 4.2.11 slash: 3.0.0 transitivePeerDependencies: - supports-color - optional: true - babel-jest@29.7.0(@babel/core@7.24.4): + babel-jest@27.5.1(@babel/core@7.25.2): dependencies: - '@babel/core': 7.24.4 - '@jest/transform': 29.7.0 - '@types/babel__core': 7.20.5 + '@babel/core': 7.25.2 + '@jest/transform': 27.5.1 + '@jest/types': 27.5.1 + '@types/babel__core': 7.20.3 babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 29.6.3(@babel/core@7.24.4) + babel-preset-jest: 27.5.1(@babel/core@7.25.2) chalk: 4.1.2 graceful-fs: 4.2.11 slash: 3.0.0 @@ -60225,32 +60345,32 @@ snapshots: transitivePeerDependencies: - supports-color - babel-loader@8.3.0(@babel/core@7.21.4)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)): + babel-loader@8.3.0(@babel/core@7.21.4)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)): dependencies: '@babel/core': 7.21.4 find-cache-dir: 3.3.2 loader-utils: 2.0.4 make-dir: 3.1.0 schema-utils: 2.7.1 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20) - babel-loader@8.3.0(@babel/core@7.21.4)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))): + babel-loader@8.3.0(@babel/core@7.21.4)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))): dependencies: '@babel/core': 7.21.4 find-cache-dir: 3.3.2 loader-utils: 2.0.4 make-dir: 3.1.0 schema-utils: 2.7.1 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12)) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12)) - babel-loader@8.3.0(@babel/core@7.25.2)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)): + babel-loader@8.3.0(@babel/core@7.25.2)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)): dependencies: '@babel/core': 7.25.2 find-cache-dir: 3.3.2 loader-utils: 2.0.4 make-dir: 3.1.0 schema-utils: 2.7.1 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4) babel-loader@9.1.2(@babel/core@7.23.2)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)): dependencies: @@ -60259,19 +60379,19 @@ snapshots: schema-utils: 4.0.0 webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20) - babel-loader@9.1.2(@babel/core@7.23.2)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)): + babel-loader@9.1.2(@babel/core@7.23.2)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))): dependencies: '@babel/core': 7.23.2 find-cache-dir: 3.3.2 schema-utils: 4.0.0 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12)) - babel-loader@9.1.2(@babel/core@7.23.2)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)): + babel-loader@9.1.2(@babel/core@7.23.2)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)): dependencies: '@babel/core': 7.23.2 find-cache-dir: 3.3.2 schema-utils: 4.0.0 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4) babel-plugin-add-react-displayname@0.0.5: {} @@ -60366,6 +60486,15 @@ snapshots: transitivePeerDependencies: - supports-color + babel-plugin-polyfill-corejs2@0.4.11(@babel/core@7.22.11): + dependencies: + '@babel/compat-data': 7.25.4 + '@babel/core': 7.22.11 + '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.22.11) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + babel-plugin-polyfill-corejs2@0.4.11(@babel/core@7.24.3): dependencies: '@babel/compat-data': 7.25.4 @@ -60559,6 +60688,23 @@ snapshots: '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.21.4) '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.21.4) + babel-preset-current-node-syntax@1.0.1(@babel/core@7.24.3): + dependencies: + '@babel/core': 7.24.3 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.3) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.3) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.3) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.3) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.3) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.3) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.3) + optional: true + babel-preset-current-node-syntax@1.0.1(@babel/core@7.24.4): dependencies: '@babel/core': 7.24.4 @@ -60597,6 +60743,13 @@ snapshots: babel-plugin-jest-hoist: 27.5.1 babel-preset-current-node-syntax: 1.0.1(@babel/core@7.21.4) + babel-preset-jest@27.5.1(@babel/core@7.24.3): + dependencies: + '@babel/core': 7.24.3 + babel-plugin-jest-hoist: 27.5.1 + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.24.3) + optional: true + babel-preset-jest@27.5.1(@babel/core@7.24.4): dependencies: '@babel/core': 7.24.4 @@ -60610,13 +60763,6 @@ snapshots: babel-preset-current-node-syntax: 1.0.1(@babel/core@7.25.2) optional: true - babel-preset-jest@29.6.3(@babel/core@7.24.4): - dependencies: - '@babel/core': 7.24.4 - babel-plugin-jest-hoist: 29.6.3 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.24.4) - optional: true - babel-preset-jest@29.6.3(@babel/core@7.25.2): dependencies: '@babel/core': 7.25.2 @@ -61507,6 +61653,16 @@ snapshots: isobject: 3.0.1 static-extend: 0.1.2 + class-validator-jsonschema@5.0.1(class-transformer@0.5.1)(class-validator@0.14.1): + dependencies: + class-transformer: 0.5.1 + class-validator: 0.14.1 + lodash.groupby: 4.6.0 + lodash.merge: 4.6.2 + openapi3-ts: 3.2.0 + reflect-metadata: 0.1.14 + tslib: 2.7.0 + class-validator@0.14.1: dependencies: '@types/validator': 13.12.1 @@ -61879,17 +62035,17 @@ snapshots: dependencies: mime-db: 1.52.0 - compression-webpack-plugin@10.0.0(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)): + compression-webpack-plugin@10.0.0(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)): dependencies: schema-utils: 4.0.0 serialize-javascript: 6.0.1 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4) - compression-webpack-plugin@10.0.0(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)): + compression-webpack-plugin@10.0.0(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)): dependencies: schema-utils: 4.0.0 serialize-javascript: 6.0.1 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4) compression@1.7.4: dependencies: @@ -62205,13 +62361,13 @@ snapshots: - supports-color - ts-node - create-jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)): + create-jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)) + jest-config: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -62220,13 +62376,13 @@ snapshots: - supports-color - ts-node - create-jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)): + create-jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) + jest-config: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -62574,7 +62730,7 @@ snapshots: semver: 7.6.3 webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20) - css-loader@6.7.3(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)): + css-loader@6.7.3(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))): dependencies: icss-utils: 5.1.0(postcss@8.4.47) postcss: 8.4.47 @@ -62584,9 +62740,9 @@ snapshots: postcss-modules-values: 4.0.0(postcss@8.4.47) postcss-value-parser: 4.2.0 semver: 7.6.3 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12)) - css-loader@6.7.3(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)): + css-loader@6.7.3(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)): dependencies: icss-utils: 5.1.0(postcss@8.4.47) postcss: 8.4.47 @@ -62596,21 +62752,9 @@ snapshots: postcss-modules-values: 4.0.0(postcss@8.4.47) postcss-value-parser: 4.2.0 semver: 7.6.3 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4) - css-loader@6.7.3(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))): - dependencies: - icss-utils: 5.1.0(postcss@8.4.47) - postcss: 8.4.47 - postcss-modules-extract-imports: 3.0.0(postcss@8.4.47) - postcss-modules-local-by-default: 4.0.0(postcss@8.4.47) - postcss-modules-scope: 3.0.0(postcss@8.4.47) - postcss-modules-values: 4.0.0(postcss@8.4.47) - postcss-value-parser: 4.2.0 - semver: 7.6.3 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12)) - - css-minimizer-webpack-plugin@3.4.1(esbuild@0.23.1)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)): + css-minimizer-webpack-plugin@3.4.1(esbuild@0.18.20)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)): dependencies: cssnano: 5.1.15(postcss@8.4.47) jest-worker: 27.5.1 @@ -62618,11 +62762,11 @@ snapshots: schema-utils: 4.0.0 serialize-javascript: 6.0.2 source-map: 0.6.1 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20) optionalDependencies: - esbuild: 0.23.1 + esbuild: 0.18.20 - css-minimizer-webpack-plugin@3.4.1(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))): + css-minimizer-webpack-plugin@3.4.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))): dependencies: cssnano: 5.1.15(postcss@8.4.47) jest-worker: 27.5.1 @@ -62630,7 +62774,7 @@ snapshots: schema-utils: 4.0.0 serialize-javascript: 6.0.2 source-map: 0.6.1 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12)) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12)) css-prefers-color-scheme@6.0.3(postcss@8.4.47): dependencies: @@ -64228,7 +64372,7 @@ snapshots: dependencies: eslint: 8.57.1 - eslint-config-react-app@7.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.21.4))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.21.4))(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6))(jest@27.5.1(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)))(typescript@5.6.2): + eslint-config-react-app@7.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.22.11))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.22.11))(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6))(jest@27.5.1(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)))(typescript@5.6.2): dependencies: '@babel/core': 7.21.4 '@babel/eslint-parser': 7.25.1(@babel/core@7.21.4)(eslint@9.9.1(jiti@1.21.6)) @@ -64238,7 +64382,7 @@ snapshots: babel-preset-react-app: 10.0.1 confusing-browser-globals: 1.0.11 eslint: 9.9.1(jiti@1.21.6) - eslint-plugin-flowtype: 8.0.3(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.21.4))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.21.4))(eslint@9.9.1(jiti@1.21.6)) + eslint-plugin-flowtype: 8.0.3(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.22.11))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.22.11))(eslint@9.9.1(jiti@1.21.6)) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.62.0(eslint@9.9.1(jiti@1.21.6))(typescript@5.6.2))(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6)) eslint-plugin-jest: 25.7.0(@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@9.9.1(jiti@1.21.6))(typescript@5.6.2))(eslint@9.9.1(jiti@1.21.6))(typescript@5.6.2))(eslint@9.9.1(jiti@1.21.6))(jest@27.5.1(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)))(typescript@5.6.2) eslint-plugin-jsx-a11y: 6.9.0(eslint@9.9.1(jiti@1.21.6)) @@ -64255,7 +64399,7 @@ snapshots: - jest - supports-color - eslint-config-react-app@7.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.25.2))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2))(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6))(jest@27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(typescript@5.6.2): + eslint-config-react-app@7.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.25.2))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2))(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6))(jest@27.5.1(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)))(typescript@5.6.2): dependencies: '@babel/core': 7.21.4 '@babel/eslint-parser': 7.25.1(@babel/core@7.21.4)(eslint@9.9.1(jiti@1.21.6)) @@ -64267,7 +64411,7 @@ snapshots: eslint: 9.9.1(jiti@1.21.6) eslint-plugin-flowtype: 8.0.3(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.25.2))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2))(eslint@9.9.1(jiti@1.21.6)) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.62.0(eslint@9.9.1(jiti@1.21.6))(typescript@5.6.2))(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6)) - eslint-plugin-jest: 25.7.0(@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@9.9.1(jiti@1.21.6))(typescript@5.6.2))(eslint@9.9.1(jiti@1.21.6))(typescript@5.6.2))(eslint@9.9.1(jiti@1.21.6))(jest@27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(typescript@5.6.2) + eslint-plugin-jest: 25.7.0(@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@9.9.1(jiti@1.21.6))(typescript@5.6.2))(eslint@9.9.1(jiti@1.21.6))(typescript@5.6.2))(eslint@9.9.1(jiti@1.21.6))(jest@27.5.1(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)))(typescript@5.6.2) eslint-plugin-jsx-a11y: 6.9.0(eslint@9.9.1(jiti@1.21.6)) eslint-plugin-react: 7.35.0(eslint@9.9.1(jiti@1.21.6)) eslint-plugin-react-hooks: 4.6.2(eslint@9.9.1(jiti@1.21.6)) @@ -64363,10 +64507,10 @@ snapshots: eslint: 8.57.1 ignore: 5.3.2 - eslint-plugin-flowtype@8.0.3(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.21.4))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.21.4))(eslint@9.9.1(jiti@1.21.6)): + eslint-plugin-flowtype@8.0.3(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.22.11))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.22.11))(eslint@9.9.1(jiti@1.21.6)): dependencies: - '@babel/plugin-syntax-flow': 7.24.7(@babel/core@7.21.4) - '@babel/plugin-transform-react-jsx': 7.25.2(@babel/core@7.21.4) + '@babel/plugin-syntax-flow': 7.24.7(@babel/core@7.22.11) + '@babel/plugin-transform-react-jsx': 7.25.2(@babel/core@7.22.11) eslint: 9.9.1(jiti@1.21.6) lodash: 4.17.21 string-natural-compare: 3.0.1 @@ -64474,17 +64618,6 @@ snapshots: - supports-color - typescript - eslint-plugin-jest@25.7.0(@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@9.9.1(jiti@1.21.6))(typescript@5.6.2))(eslint@9.9.1(jiti@1.21.6))(typescript@5.6.2))(eslint@9.9.1(jiti@1.21.6))(jest@27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(typescript@5.6.2): - dependencies: - '@typescript-eslint/experimental-utils': 5.58.0(eslint@9.9.1(jiti@1.21.6))(typescript@5.6.2) - eslint: 9.9.1(jiti@1.21.6) - optionalDependencies: - '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0(eslint@9.9.1(jiti@1.21.6))(typescript@5.6.2))(eslint@9.9.1(jiti@1.21.6))(typescript@5.6.2) - jest: 27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) - transitivePeerDependencies: - - supports-color - - typescript - eslint-plugin-jest@28.8.0(@typescript-eslint/eslint-plugin@8.3.0(@typescript-eslint/parser@8.3.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1)(jest@29.7.0(@types/node@18.16.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)))(typescript@5.6.2): dependencies: '@typescript-eslint/utils': 8.3.0(eslint@8.57.1)(typescript@5.6.2) @@ -64803,7 +64936,7 @@ snapshots: eslint-visitor-keys@4.0.0: {} - eslint-webpack-plugin@3.2.0(eslint@9.9.1(jiti@1.21.6))(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)): + eslint-webpack-plugin@3.2.0(eslint@9.9.1(jiti@1.21.6))(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)): dependencies: '@types/eslint': 8.56.12 eslint: 9.9.1(jiti@1.21.6) @@ -64811,9 +64944,9 @@ snapshots: micromatch: 4.0.8 normalize-path: 3.0.0 schema-utils: 4.0.0 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20) - eslint-webpack-plugin@3.2.0(eslint@9.9.1(jiti@1.21.6))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))): + eslint-webpack-plugin@3.2.0(eslint@9.9.1(jiti@1.21.6))(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))): dependencies: '@types/eslint': 8.56.12 eslint: 9.9.1(jiti@1.21.6) @@ -64821,7 +64954,7 @@ snapshots: micromatch: 4.0.8 normalize-path: 3.0.0 schema-utils: 4.0.0 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12)) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12)) eslint@8.57.1: dependencies: @@ -65548,26 +65681,26 @@ snapshots: loader-utils: 2.0.4 schema-utils: 3.3.0 webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20) - optional: true - file-loader@6.2.0(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)): + file-loader@6.2.0(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))): dependencies: loader-utils: 2.0.4 schema-utils: 3.3.0 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12)) - file-loader@6.2.0(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)): + file-loader@6.2.0(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)): dependencies: loader-utils: 2.0.4 schema-utils: 3.3.0 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4) optional: true - file-loader@6.2.0(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))): + file-loader@6.2.0(webpack@5.94.0(@swc/core@1.7.26(@swc/helpers@0.5.12))): dependencies: loader-utils: 2.0.4 schema-utils: 3.3.0 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12)) + webpack: 5.94.0(@swc/core@1.7.26(@swc/helpers@0.5.12)) + optional: true file-selector@0.6.0: dependencies: @@ -65801,7 +65934,7 @@ snapshots: forever-agent@0.6.1: {} - fork-ts-checker-webpack-plugin@6.5.3(eslint@9.9.1(jiti@1.21.6))(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)): + fork-ts-checker-webpack-plugin@6.5.3(eslint@9.9.1(jiti@1.21.6))(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)): dependencies: '@babel/code-frame': 7.24.7 '@types/json-schema': 7.0.15 @@ -65817,12 +65950,12 @@ snapshots: semver: 7.6.3 tapable: 1.1.3 typescript: 5.6.2 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20) optionalDependencies: eslint: 9.9.1(jiti@1.21.6) vue-template-compiler: 2.7.16 - fork-ts-checker-webpack-plugin@6.5.3(eslint@9.9.1(jiti@1.21.6))(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))): + fork-ts-checker-webpack-plugin@6.5.3(eslint@9.9.1(jiti@1.21.6))(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))): dependencies: '@babel/code-frame': 7.24.7 '@types/json-schema': 7.0.15 @@ -65838,7 +65971,7 @@ snapshots: semver: 7.6.3 tapable: 1.1.3 typescript: 5.6.2 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12)) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12)) optionalDependencies: eslint: 9.9.1(jiti@1.21.6) vue-template-compiler: 2.7.16 @@ -65860,7 +65993,7 @@ snapshots: typescript: 5.6.2 webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20) - fork-ts-checker-webpack-plugin@8.0.0(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)): + fork-ts-checker-webpack-plugin@8.0.0(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))): dependencies: '@babel/code-frame': 7.24.7 chalk: 4.1.2 @@ -65875,9 +66008,9 @@ snapshots: semver: 7.6.3 tapable: 2.2.1 typescript: 5.6.2 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12)) - fork-ts-checker-webpack-plugin@8.0.0(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)): + fork-ts-checker-webpack-plugin@8.0.0(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)): dependencies: '@babel/code-frame': 7.24.7 chalk: 4.1.2 @@ -65892,7 +66025,7 @@ snapshots: semver: 7.6.3 tapable: 2.2.1 typescript: 5.6.2 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4) fork-ts-checker-webpack-plugin@9.0.2(typescript@5.3.3)(webpack@5.94.0(@swc/core@1.7.26(@swc/helpers@0.5.12))): dependencies: @@ -67112,32 +67245,23 @@ snapshots: tapable: 2.2.1 webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20) - html-webpack-plugin@5.5.3(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)): - dependencies: - '@types/html-minifier-terser': 6.1.0 - html-minifier-terser: 6.1.0 - lodash: 4.17.21 - pretty-error: 4.0.0 - tapable: 2.2.1 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) - - html-webpack-plugin@5.5.3(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)): + html-webpack-plugin@5.5.3(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))): dependencies: '@types/html-minifier-terser': 6.1.0 html-minifier-terser: 6.1.0 lodash: 4.17.21 pretty-error: 4.0.0 tapable: 2.2.1 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12)) - html-webpack-plugin@5.5.3(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))): + html-webpack-plugin@5.5.3(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)): dependencies: '@types/html-minifier-terser': 6.1.0 html-minifier-terser: 6.1.0 lodash: 4.17.21 pretty-error: 4.0.0 tapable: 2.2.1 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12)) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4) htmlparser2@6.1.0: dependencies: @@ -68297,27 +68421,6 @@ snapshots: - ts-node - utf-8-validate - jest-cli@27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)): - dependencies: - '@jest/core': 27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) - '@jest/test-result': 27.5.1 - '@jest/types': 27.5.1 - chalk: 4.1.2 - exit: 0.1.2 - graceful-fs: 4.2.11 - import-local: 3.1.0 - jest-config: 27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) - jest-util: 27.5.1 - jest-validate: 27.5.1 - prompts: 2.4.2 - yargs: 16.2.0 - transitivePeerDependencies: - - bufferutil - - canvas - - supports-color - - ts-node - - utf-8-validate - jest-cli@27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@22.7.4)(typescript@5.6.2)): dependencies: '@jest/core': 27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@22.7.4)(typescript@5.6.2)) @@ -68378,16 +68481,16 @@ snapshots: - supports-color - ts-node - jest-cli@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)): + jest-cli@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)): dependencies: - '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)) + '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)) + create-jest: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) exit: 0.1.2 import-local: 3.1.0 - jest-config: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)) + jest-config: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -68397,16 +68500,16 @@ snapshots: - supports-color - ts-node - jest-cli@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)): + jest-cli@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)): dependencies: - '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) + '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) + create-jest: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) exit: 0.1.2 import-local: 3.1.0 - jest-config: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) + jest-config: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -68537,7 +68640,7 @@ snapshots: - supports-color - utf-8-validate - jest-config@27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)): + jest-config@27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@22.7.4)(typescript@5.6.2)): dependencies: '@babel/core': 7.24.4 '@jest/test-sequencer': 27.5.1 @@ -68564,48 +68667,45 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - ts-node: 10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2) + ts-node: 10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@22.7.4)(typescript@5.6.2) transitivePeerDependencies: - bufferutil - canvas - supports-color - utf-8-validate - jest-config@27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@22.7.4)(typescript@5.6.2)): + jest-config@29.7.0(@types/node@18.16.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)): dependencies: - '@babel/core': 7.24.4 - '@jest/test-sequencer': 27.5.1 - '@jest/types': 27.5.1 - babel-jest: 27.5.1(@babel/core@7.24.4) + '@babel/core': 7.25.2 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.25.2) chalk: 4.1.2 - ci-info: 3.8.0 + ci-info: 3.9.0 deepmerge: 4.3.1 glob: 7.2.3 graceful-fs: 4.2.11 - jest-circus: 27.5.1 - jest-environment-jsdom: 27.5.1 - jest-environment-node: 27.5.1 - jest-get-type: 27.5.1 - jest-jasmine2: 27.5.1 - jest-regex-util: 27.5.1 - jest-resolve: 27.5.1 - jest-runner: 27.5.1 - jest-util: 27.5.1 - jest-validate: 27.5.1 - micromatch: 4.0.5 + jest-circus: 29.7.0(babel-plugin-macros@3.1.0) + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.8 parse-json: 5.2.0 - pretty-format: 27.5.1 + pretty-format: 29.7.0 slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - ts-node: 10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@22.7.4)(typescript@5.6.2) + '@types/node': 18.16.9 + ts-node: 10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2) transitivePeerDependencies: - - bufferutil - - canvas + - babel-plugin-macros - supports-color - - utf-8-validate - jest-config@29.7.0(@types/node@18.16.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)): + jest-config@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)): dependencies: '@babel/core': 7.25.2 '@jest/test-sequencer': 29.7.0 @@ -68630,13 +68730,13 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 18.16.9 + '@types/node': 20.16.5 ts-node: 10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2) transitivePeerDependencies: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)): + jest-config@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)): dependencies: '@babel/core': 7.25.2 '@jest/test-sequencer': 29.7.0 @@ -68662,12 +68762,12 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@types/node': 20.16.5 - ts-node: 10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2) + ts-node: 10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2) transitivePeerDependencies: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)): + jest-config@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)): dependencies: '@babel/core': 7.25.2 '@jest/test-sequencer': 29.7.0 @@ -68693,7 +68793,7 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@types/node': 20.16.5 - ts-node: 10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2) + ts-node: 10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -69280,17 +69380,6 @@ snapshots: string-length: 5.0.1 strip-ansi: 7.1.0 - jest-watch-typeahead@1.1.0(jest@27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2))): - dependencies: - ansi-escapes: 4.3.2 - chalk: 4.1.2 - jest: 27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) - jest-regex-util: 28.0.2 - jest-watcher: 28.1.3 - slash: 4.0.0 - string-length: 5.0.1 - strip-ansi: 7.1.0 - jest-watcher@27.5.1: dependencies: '@jest/test-result': 27.5.1 @@ -69384,18 +69473,6 @@ snapshots: - ts-node - utf-8-validate - jest@27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)): - dependencies: - '@jest/core': 27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) - import-local: 3.1.0 - jest-cli: 27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) - transitivePeerDependencies: - - bufferutil - - canvas - - supports-color - - ts-node - - utf-8-validate - jest@27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@22.7.4)(typescript@5.6.2)): dependencies: '@jest/core': 27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@22.7.4)(typescript@5.6.2)) @@ -69432,24 +69509,24 @@ snapshots: - supports-color - ts-node - jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)): + jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)): dependencies: - '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)) + '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) '@jest/types': 29.6.3 import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)) + jest-cli: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros - supports-color - ts-node - jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)): + jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)): dependencies: - '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) + '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) '@jest/types': 29.6.3 import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) + jest-cli: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -70071,21 +70148,21 @@ snapshots: - encoding - supports-color - less-loader@4.1.0(less@4.1.3)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)): + less-loader@4.1.0(less@4.1.3)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)): dependencies: clone: 2.1.2 less: 4.1.3 loader-utils: 1.4.2 pify: 3.0.0 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20) - less-loader@4.1.0(less@4.1.3)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))): + less-loader@4.1.0(less@4.1.3)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))): dependencies: clone: 2.1.2 less: 4.1.3 loader-utils: 1.4.2 pify: 3.0.0 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12)) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12)) less@4.1.3: dependencies: @@ -70493,6 +70570,8 @@ snapshots: lodash.get@4.4.2: {} + lodash.groupby@4.6.0: {} + lodash.includes@4.3.0: {} lodash.isarguments@3.1.0: {} @@ -71213,13 +71292,13 @@ snapshots: mdurl@2.0.0: {} - mdx-bundler@10.0.2(esbuild@0.23.1): + mdx-bundler@10.0.2(esbuild@0.18.20): dependencies: '@babel/runtime': 7.24.7 - '@esbuild-plugins/node-resolve': 0.2.2(esbuild@0.23.1) + '@esbuild-plugins/node-resolve': 0.2.2(esbuild@0.18.20) '@fal-works/esbuild-plugin-global-externals': 2.1.2 - '@mdx-js/esbuild': 3.0.1(esbuild@0.23.1) - esbuild: 0.23.1 + '@mdx-js/esbuild': 3.0.1(esbuild@0.18.20) + esbuild: 0.18.20 gray-matter: 4.0.3 remark-frontmatter: 5.0.0 remark-mdx-frontmatter: 4.0.0 @@ -71879,15 +71958,15 @@ snapshots: min-indent@1.0.1: {} - mini-css-extract-plugin@2.7.5(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)): + mini-css-extract-plugin@2.7.5(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)): dependencies: schema-utils: 4.0.0 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20) - mini-css-extract-plugin@2.7.5(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))): + mini-css-extract-plugin@2.7.5(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))): dependencies: schema-utils: 4.0.0 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12)) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12)) minimalistic-assert@1.0.1: {} @@ -72493,7 +72572,7 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - next@13.5.6(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8): + next@13.5.6(@babel/core@7.24.3)(@opentelemetry/api@1.9.0)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8): dependencies: '@next/env': 13.5.6 '@swc/helpers': 0.5.2 @@ -72502,7 +72581,7 @@ snapshots: postcss: 8.4.31 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - styled-jsx: 5.1.1(@babel/core@7.25.2)(babel-plugin-macros@3.1.0)(react@18.3.1) + styled-jsx: 5.1.1(@babel/core@7.24.3)(babel-plugin-macros@3.1.0)(react@18.3.1) watchpack: 2.4.0 optionalDependencies: '@next/swc-darwin-arm64': 13.5.6 @@ -72520,7 +72599,7 @@ snapshots: - '@babel/core' - babel-plugin-macros - next@14.2.4(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.46.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8): + next@14.2.4(@babel/core@7.24.3)(@opentelemetry/api@1.9.0)(@playwright/test@1.46.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8): dependencies: '@next/env': 14.2.4 '@swc/helpers': 0.5.5 @@ -72530,7 +72609,7 @@ snapshots: postcss: 8.4.31 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - styled-jsx: 5.1.1(@babel/core@7.25.2)(babel-plugin-macros@3.1.0)(react@18.3.1) + styled-jsx: 5.1.1(@babel/core@7.24.3)(babel-plugin-macros@3.1.0)(react@18.3.1) optionalDependencies: '@next/swc-darwin-arm64': 14.2.4 '@next/swc-darwin-x64': 14.2.4 @@ -73369,6 +73448,10 @@ snapshots: is-docker: 2.2.1 is-wsl: 2.2.0 + openapi3-ts@3.2.0: + dependencies: + yaml: 2.5.0 + opener@1.5.2: {} opentracing@0.14.7: {} @@ -74561,21 +74644,21 @@ snapshots: tsx: 4.19.0 yaml: 2.5.0 - postcss-loader@6.2.1(postcss@8.4.47)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)): + postcss-loader@6.2.1(postcss@8.4.47)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)): dependencies: cosmiconfig: 7.1.0 klona: 2.0.6 postcss: 8.4.47 semver: 7.6.3 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20) - postcss-loader@6.2.1(postcss@8.4.47)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))): + postcss-loader@6.2.1(postcss@8.4.47)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))): dependencies: cosmiconfig: 7.1.0 klona: 2.0.6 postcss: 8.4.47 semver: 7.6.3 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12)) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12)) postcss-logical@5.0.4(postcss@8.4.47): dependencies: @@ -76154,14 +76237,14 @@ snapshots: regenerator-runtime: 0.13.11 whatwg-fetch: 3.6.2 - react-app-rewired@2.2.1(react-scripts@5.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.21.4))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.21.4))(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/babel__core@7.20.5)(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1))(esbuild@0.23.1)(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6))(react@18.3.1)(sass@1.77.8)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2))(type-fest@2.19.0)(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack-hot-middleware@2.26.1)): + react-app-rewired@2.2.1(react-scripts@5.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.22.11))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.22.11))(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/babel__core@7.20.5)(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20))(esbuild@0.18.20)(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6))(react@18.3.1)(sass@1.77.8)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2))(type-fest@2.19.0)(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack-hot-middleware@2.26.1)): dependencies: - react-scripts: 5.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.21.4))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.21.4))(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/babel__core@7.20.5)(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1))(esbuild@0.23.1)(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6))(react@18.3.1)(sass@1.77.8)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2))(type-fest@2.19.0)(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack-hot-middleware@2.26.1) + react-scripts: 5.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.22.11))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.22.11))(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/babel__core@7.20.5)(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20))(esbuild@0.18.20)(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6))(react@18.3.1)(sass@1.77.8)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2))(type-fest@2.19.0)(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack-hot-middleware@2.26.1) semver: 5.7.2 - react-app-rewired@2.2.1(react-scripts@5.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.25.2))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2))(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/babel__core@7.20.5)(@types/webpack@5.28.5(@swc/core@1.7.26(@swc/helpers@0.5.12)))(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6))(react@18.3.1)(sass@1.77.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2))(type-fest@2.19.0)(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack-hot-middleware@2.26.1)): + react-app-rewired@2.2.1(react-scripts@5.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.25.2))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2))(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/babel__core@7.20.5)(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12)))(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6))(react@18.3.1)(sass@1.77.8)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2))(type-fest@2.19.0)(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack-hot-middleware@2.26.1)): dependencies: - react-scripts: 5.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.25.2))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2))(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/babel__core@7.20.5)(@types/webpack@5.28.5(@swc/core@1.7.26(@swc/helpers@0.5.12)))(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6))(react@18.3.1)(sass@1.77.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2))(type-fest@2.19.0)(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack-hot-middleware@2.26.1) + react-scripts: 5.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.25.2))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2))(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/babel__core@7.20.5)(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12)))(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6))(react@18.3.1)(sass@1.77.8)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2))(type-fest@2.19.0)(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack-hot-middleware@2.26.1) semver: 5.7.2 react-chartjs-2@4.3.1(chart.js@3.9.1)(react@18.3.1): @@ -76197,7 +76280,7 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-dev-utils@12.0.1(eslint@9.9.1(jiti@1.21.6))(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)): + react-dev-utils@12.0.1(eslint@9.9.1(jiti@1.21.6))(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)): dependencies: '@babel/code-frame': 7.24.2 address: 1.2.2 @@ -76208,7 +76291,7 @@ snapshots: escape-string-regexp: 4.0.0 filesize: 8.0.7 find-up: 5.0.0 - fork-ts-checker-webpack-plugin: 6.5.3(eslint@9.9.1(jiti@1.21.6))(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) + fork-ts-checker-webpack-plugin: 6.5.3(eslint@9.9.1(jiti@1.21.6))(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) global-modules: 2.0.0 globby: 11.1.0 gzip-size: 6.0.0 @@ -76223,7 +76306,7 @@ snapshots: shell-quote: 1.8.1 strip-ansi: 6.0.1 text-table: 0.2.0 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20) optionalDependencies: typescript: 5.6.2 transitivePeerDependencies: @@ -76231,7 +76314,7 @@ snapshots: - supports-color - vue-template-compiler - react-dev-utils@12.0.1(eslint@9.9.1(jiti@1.21.6))(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))): + react-dev-utils@12.0.1(eslint@9.9.1(jiti@1.21.6))(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))): dependencies: '@babel/code-frame': 7.24.2 address: 1.2.2 @@ -76242,7 +76325,7 @@ snapshots: escape-string-regexp: 4.0.0 filesize: 8.0.7 find-up: 5.0.0 - fork-ts-checker-webpack-plugin: 6.5.3(eslint@9.9.1(jiti@1.21.6))(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))) + fork-ts-checker-webpack-plugin: 6.5.3(eslint@9.9.1(jiti@1.21.6))(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) global-modules: 2.0.0 globby: 11.1.0 gzip-size: 6.0.0 @@ -76257,7 +76340,7 @@ snapshots: shell-quote: 1.8.1 strip-ansi: 6.0.1 text-table: 0.2.0 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12)) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12)) optionalDependencies: typescript: 5.6.2 transitivePeerDependencies: @@ -76555,56 +76638,56 @@ snapshots: transitivePeerDependencies: - supports-color - react-scripts@5.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.21.4))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.21.4))(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/babel__core@7.20.5)(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1))(esbuild@0.23.1)(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6))(react@18.3.1)(sass@1.77.8)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2))(type-fest@2.19.0)(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack-hot-middleware@2.26.1): + react-scripts@5.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.22.11))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.22.11))(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/babel__core@7.20.5)(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20))(esbuild@0.18.20)(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6))(react@18.3.1)(sass@1.77.8)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2))(type-fest@2.19.0)(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack-hot-middleware@2.26.1): dependencies: '@babel/core': 7.21.4 - '@pmmmwh/react-refresh-webpack-plugin': 0.5.10(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1))(react-refresh@0.11.0)(type-fest@2.19.0)(webpack-dev-server@4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)))(webpack-hot-middleware@2.26.1)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) + '@pmmmwh/react-refresh-webpack-plugin': 0.5.10(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20))(react-refresh@0.11.0)(type-fest@2.19.0)(webpack-dev-server@4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)))(webpack-hot-middleware@2.26.1)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) '@svgr/webpack': 5.5.0 babel-jest: 27.5.1(@babel/core@7.21.4) - babel-loader: 8.3.0(@babel/core@7.21.4)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) + babel-loader: 8.3.0(@babel/core@7.21.4)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) babel-plugin-named-asset-import: 0.3.8(@babel/core@7.21.4) babel-preset-react-app: 10.0.1 bfj: 7.0.2 browserslist: 4.21.5 camelcase: 6.3.0 case-sensitive-paths-webpack-plugin: 2.4.0 - css-loader: 6.7.3(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) - css-minimizer-webpack-plugin: 3.4.1(esbuild@0.23.1)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) + css-loader: 6.7.3(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) + css-minimizer-webpack-plugin: 3.4.1(esbuild@0.18.20)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) dotenv: 10.0.0 dotenv-expand: 5.1.0 eslint: 9.9.1(jiti@1.21.6) - eslint-config-react-app: 7.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.21.4))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.21.4))(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6))(jest@27.5.1(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)))(typescript@5.6.2) - eslint-webpack-plugin: 3.2.0(eslint@9.9.1(jiti@1.21.6))(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) - file-loader: 6.2.0(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) + eslint-config-react-app: 7.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.22.11))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.22.11))(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6))(jest@27.5.1(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)))(typescript@5.6.2) + eslint-webpack-plugin: 3.2.0(eslint@9.9.1(jiti@1.21.6))(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) + file-loader: 6.2.0(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) fs-extra: 10.1.0 - html-webpack-plugin: 5.5.3(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) + html-webpack-plugin: 5.5.3(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) identity-obj-proxy: 3.0.0 jest: 27.5.1(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)) jest-resolve: 27.5.1 jest-watch-typeahead: 1.1.0(jest@27.5.1(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2))) - mini-css-extract-plugin: 2.7.5(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) + mini-css-extract-plugin: 2.7.5(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) postcss: 8.4.47 postcss-flexbugs-fixes: 5.0.2(postcss@8.4.47) - postcss-loader: 6.2.1(postcss@8.4.47)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) + postcss-loader: 6.2.1(postcss@8.4.47)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) postcss-normalize: 10.0.1(browserslist@4.21.5)(postcss@8.4.47) postcss-preset-env: 7.8.3(postcss@8.4.47) prompts: 2.4.2 react: 18.3.1 react-app-polyfill: 3.0.0 - react-dev-utils: 12.0.1(eslint@9.9.1(jiti@1.21.6))(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) + react-dev-utils: 12.0.1(eslint@9.9.1(jiti@1.21.6))(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) react-refresh: 0.11.0 resolve: 1.22.2 resolve-url-loader: 4.0.0 - sass-loader: 12.6.0(sass@1.77.8)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) + sass-loader: 12.6.0(sass@1.77.8)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) semver: 7.5.4 - source-map-loader: 3.0.2(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) - style-loader: 3.3.2(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) + source-map-loader: 3.0.2(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) + style-loader: 3.3.2(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) tailwindcss: 3.4.13(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)) - terser-webpack-plugin: 5.3.7(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) - webpack-dev-server: 4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) - webpack-manifest-plugin: 4.1.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) - workbox-webpack-plugin: 6.5.4(@types/babel__core@7.20.5)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) + terser-webpack-plugin: 5.3.7(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20) + webpack-dev-server: 4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) + webpack-manifest-plugin: 4.1.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) + workbox-webpack-plugin: 6.5.4(@types/babel__core@7.20.5)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) optionalDependencies: fsevents: 2.3.3 typescript: 5.6.2 @@ -76641,56 +76724,56 @@ snapshots: - webpack-hot-middleware - webpack-plugin-serve - react-scripts@5.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.25.2))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2))(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/babel__core@7.20.5)(@types/webpack@5.28.5(@swc/core@1.7.26(@swc/helpers@0.5.12)))(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6))(react@18.3.1)(sass@1.77.8)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2))(type-fest@2.19.0)(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack-hot-middleware@2.26.1): + react-scripts@5.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.25.2))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2))(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/babel__core@7.20.5)(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12)))(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6))(react@18.3.1)(sass@1.77.8)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2))(type-fest@2.19.0)(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack-hot-middleware@2.26.1): dependencies: '@babel/core': 7.21.4 - '@pmmmwh/react-refresh-webpack-plugin': 0.5.10(@types/webpack@5.28.5(@swc/core@1.7.26(@swc/helpers@0.5.12)))(react-refresh@0.11.0)(type-fest@2.19.0)(webpack-dev-server@4.11.1(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))))(webpack-hot-middleware@2.26.1)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))) + '@pmmmwh/react-refresh-webpack-plugin': 0.5.10(@types/webpack@5.28.5(@swc/core@1.3.107(@swc/helpers@0.5.12)))(react-refresh@0.11.0)(type-fest@2.19.0)(webpack-dev-server@4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(webpack-hot-middleware@2.26.1)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) '@svgr/webpack': 5.5.0 babel-jest: 27.5.1(@babel/core@7.21.4) - babel-loader: 8.3.0(@babel/core@7.21.4)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))) + babel-loader: 8.3.0(@babel/core@7.21.4)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) babel-plugin-named-asset-import: 0.3.8(@babel/core@7.21.4) babel-preset-react-app: 10.0.1 bfj: 7.0.2 browserslist: 4.21.5 camelcase: 6.3.0 case-sensitive-paths-webpack-plugin: 2.4.0 - css-loader: 6.7.3(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))) - css-minimizer-webpack-plugin: 3.4.1(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))) + css-loader: 6.7.3(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) + css-minimizer-webpack-plugin: 3.4.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) dotenv: 10.0.0 dotenv-expand: 5.1.0 eslint: 9.9.1(jiti@1.21.6) - eslint-config-react-app: 7.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.25.2))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2))(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6))(jest@27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(typescript@5.6.2) - eslint-webpack-plugin: 3.2.0(eslint@9.9.1(jiti@1.21.6))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))) - file-loader: 6.2.0(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))) + eslint-config-react-app: 7.0.1(@babel/plugin-syntax-flow@7.24.7(@babel/core@7.25.2))(@babel/plugin-transform-react-jsx@7.25.2(@babel/core@7.25.2))(eslint-import-resolver-webpack@0.13.8(eslint-plugin-import@2.29.1)(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))))(eslint@9.9.1(jiti@1.21.6))(jest@27.5.1(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)))(typescript@5.6.2) + eslint-webpack-plugin: 3.2.0(eslint@9.9.1(jiti@1.21.6))(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) + file-loader: 6.2.0(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) fs-extra: 10.1.0 - html-webpack-plugin: 5.5.3(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))) + html-webpack-plugin: 5.5.3(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) identity-obj-proxy: 3.0.0 - jest: 27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) + jest: 27.5.1(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)) jest-resolve: 27.5.1 - jest-watch-typeahead: 1.1.0(jest@27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2))) - mini-css-extract-plugin: 2.7.5(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))) + jest-watch-typeahead: 1.1.0(jest@27.5.1(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2))) + mini-css-extract-plugin: 2.7.5(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) postcss: 8.4.47 postcss-flexbugs-fixes: 5.0.2(postcss@8.4.47) - postcss-loader: 6.2.1(postcss@8.4.47)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))) + postcss-loader: 6.2.1(postcss@8.4.47)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) postcss-normalize: 10.0.1(browserslist@4.21.5)(postcss@8.4.47) postcss-preset-env: 7.8.3(postcss@8.4.47) prompts: 2.4.2 react: 18.3.1 react-app-polyfill: 3.0.0 - react-dev-utils: 12.0.1(eslint@9.9.1(jiti@1.21.6))(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))) + react-dev-utils: 12.0.1(eslint@9.9.1(jiti@1.21.6))(typescript@5.6.2)(vue-template-compiler@2.7.16)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) react-refresh: 0.11.0 resolve: 1.22.2 resolve-url-loader: 4.0.0 - sass-loader: 12.6.0(sass@1.77.8)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))) + sass-loader: 12.6.0(sass@1.77.8)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) semver: 7.5.4 - source-map-loader: 3.0.2(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))) - style-loader: 3.3.2(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))) - tailwindcss: 3.4.13(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) - terser-webpack-plugin: 5.3.7(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))) - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12)) - webpack-dev-server: 4.11.1(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))) - webpack-manifest-plugin: 4.1.1(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))) - workbox-webpack-plugin: 6.5.4(@types/babel__core@7.20.5)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))) + source-map-loader: 3.0.2(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) + style-loader: 3.3.2(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) + tailwindcss: 3.4.13(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)) + terser-webpack-plugin: 5.3.7(@swc/core@1.3.107(@swc/helpers@0.5.12))(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12)) + webpack-dev-server: 4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) + webpack-manifest-plugin: 4.1.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) + workbox-webpack-plugin: 6.5.4(@types/babel__core@7.20.5)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) optionalDependencies: fsevents: 2.3.3 typescript: 5.6.2 @@ -77006,6 +77089,8 @@ snapshots: dependencies: '@eslint-community/regexpp': 4.11.0 + reflect-metadata@0.1.14: {} + reflect-metadata@0.2.2: {} reflect.getprototypeof@1.0.6: @@ -77704,19 +77789,19 @@ snapshots: sanitize.css@13.0.0: {} - sass-loader@12.6.0(sass@1.77.8)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)): + sass-loader@12.6.0(sass@1.77.8)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)): dependencies: klona: 2.0.6 neo-async: 2.6.2 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20) optionalDependencies: sass: 1.77.8 - sass-loader@12.6.0(sass@1.77.8)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))): + sass-loader@12.6.0(sass@1.77.8)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))): dependencies: klona: 2.0.6 neo-async: 2.6.2 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12)) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12)) optionalDependencies: sass: 1.77.8 @@ -78355,19 +78440,19 @@ snapshots: source-map-js@1.2.1: {} - source-map-loader@3.0.2(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)): + source-map-loader@3.0.2(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)): dependencies: abab: 2.0.6 iconv-lite: 0.6.3 source-map-js: 1.2.1 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20) - source-map-loader@3.0.2(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))): + source-map-loader@3.0.2(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))): dependencies: abab: 2.0.6 iconv-lite: 0.6.3 source-map-js: 1.2.1 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12)) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12)) source-map-resolve@0.5.3: dependencies: @@ -78904,17 +78989,13 @@ snapshots: dependencies: webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20) - style-loader@3.3.2(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)): - dependencies: - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) - - style-loader@3.3.2(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)): + style-loader@3.3.2(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))): dependencies: - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12)) - style-loader@3.3.2(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))): + style-loader@3.3.2(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)): dependencies: - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12)) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4) style-mod@4.1.2: {} @@ -78926,12 +79007,12 @@ snapshots: dependencies: inline-style-parser: 0.2.3 - styled-jsx@5.1.1(@babel/core@7.25.2)(babel-plugin-macros@3.1.0)(react@18.3.1): + styled-jsx@5.1.1(@babel/core@7.24.3)(babel-plugin-macros@3.1.0)(react@18.3.1): dependencies: client-only: 0.0.1 react: 18.3.1 optionalDependencies: - '@babel/core': 7.25.2 + '@babel/core': 7.24.3 babel-plugin-macros: 3.1.0 stylehacks@5.1.1(postcss@8.4.47): @@ -79201,15 +79282,15 @@ snapshots: '@swc/core': 1.3.107(@swc/helpers@0.5.12) webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20) - swc-loader@0.2.3(@swc/core@1.3.107(@swc/helpers@0.5.12))(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)): + swc-loader@0.2.3(@swc/core@1.3.107(@swc/helpers@0.5.12))(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))): dependencies: '@swc/core': 1.3.107(@swc/helpers@0.5.12) - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12)) - swc-loader@0.2.3(@swc/core@1.3.107(@swc/helpers@0.5.12))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)): + swc-loader@0.2.3(@swc/core@1.3.107(@swc/helpers@0.5.12))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)): dependencies: '@swc/core': 1.3.107(@swc/helpers@0.5.12) - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4) swr@2.2.5(react@18.3.1): dependencies: @@ -79287,33 +79368,6 @@ snapshots: transitivePeerDependencies: - ts-node - tailwindcss@3.4.13(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)): - dependencies: - '@alloc/quick-lru': 5.2.0 - arg: 5.0.2 - chokidar: 3.6.0 - didyoumean: 1.2.2 - dlv: 1.1.3 - fast-glob: 3.3.1 - glob-parent: 6.0.2 - is-glob: 4.0.3 - jiti: 1.21.6 - lilconfig: 2.1.0 - micromatch: 4.0.8 - normalize-path: 3.0.0 - object-hash: 3.0.0 - picocolors: 1.1.0 - postcss: 8.4.47 - postcss-import: 15.1.0(postcss@8.4.47) - postcss-js: 4.0.1(postcss@8.4.47) - postcss-load-config: 4.0.2(postcss@8.4.47)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) - postcss-nested: 6.0.1(postcss@8.4.47) - postcss-selector-parser: 6.1.2 - resolve: 1.22.8 - sucrase: 3.35.0 - transitivePeerDependencies: - - ts-node - tailwindcss@3.4.13(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@22.7.4)(typescript@5.6.2)): dependencies: '@alloc/quick-lru': 5.2.0 @@ -79523,29 +79577,27 @@ snapshots: '@swc/core': 1.3.107(@swc/helpers@0.5.12) esbuild: 0.18.20 - terser-webpack-plugin@5.3.10(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)): + terser-webpack-plugin@5.3.10(@swc/core@1.3.107(@swc/helpers@0.5.12))(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.31.6 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12)) optionalDependencies: '@swc/core': 1.3.107(@swc/helpers@0.5.12) - esbuild: 0.18.20 - terser-webpack-plugin@5.3.10(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)): + terser-webpack-plugin@5.3.10(@swc/core@1.3.107(@swc/helpers@0.5.12))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.31.6 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4) optionalDependencies: '@swc/core': 1.3.107(@swc/helpers@0.5.12) - esbuild: 0.23.1 terser-webpack-plugin@5.3.10(@swc/core@1.3.107(@swc/helpers@0.5.12))(webpack@5.94.0(@swc/core@1.3.107(@swc/helpers@0.5.12))): dependencies: @@ -79558,29 +79610,28 @@ snapshots: optionalDependencies: '@swc/core': 1.3.107(@swc/helpers@0.5.12) - terser-webpack-plugin@5.3.10(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)): + terser-webpack-plugin@5.3.10(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.31.6 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4) optionalDependencies: '@swc/core': 1.7.26(@swc/helpers@0.5.12) - esbuild: 0.18.20 + esbuild: 0.23.1 - terser-webpack-plugin@5.3.10(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)): + terser-webpack-plugin@5.3.10(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.31.6 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4) optionalDependencies: '@swc/core': 1.7.26(@swc/helpers@0.5.12) - esbuild: 0.23.1 terser-webpack-plugin@5.3.10(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))): dependencies: @@ -79604,28 +79655,28 @@ snapshots: optionalDependencies: '@swc/core': 1.7.26(@swc/helpers@0.5.12) - terser-webpack-plugin@5.3.7(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)): + terser-webpack-plugin@5.3.7(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.31.6 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20) optionalDependencies: '@swc/core': 1.3.107(@swc/helpers@0.5.12) - esbuild: 0.23.1 + esbuild: 0.18.20 - terser-webpack-plugin@5.3.7(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))): + terser-webpack-plugin@5.3.7(@swc/core@1.3.107(@swc/helpers@0.5.12))(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.31.6 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12)) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12)) optionalDependencies: - '@swc/core': 1.7.26(@swc/helpers@0.5.12) + '@swc/core': 1.3.107(@swc/helpers@0.5.12) terser-webpack-plugin@5.3.9(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)): dependencies: @@ -79965,11 +80016,11 @@ snapshots: dependencies: tslib: 1.14.1 - ts-jest@27.1.5(@babel/core@7.24.4)(@types/jest@29.5.2)(babel-jest@27.5.1(@babel/core@7.24.4))(jest@27.5.1(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(typescript@5.6.2): + ts-jest@27.1.5(@babel/core@7.24.3)(@types/jest@29.5.13)(babel-jest@27.5.1(@babel/core@7.24.3))(jest@29.7.0(@types/node@18.16.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)))(typescript@5.6.2): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 - jest: 27.5.1(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) + jest: 29.7.0(@types/node@18.16.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)) jest-util: 27.5.1 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -79978,11 +80029,11 @@ snapshots: typescript: 5.6.2 yargs-parser: 20.2.9 optionalDependencies: - '@babel/core': 7.24.4 - '@types/jest': 29.5.2 - babel-jest: 27.5.1(@babel/core@7.24.4) + '@babel/core': 7.24.3 + '@types/jest': 29.5.13 + babel-jest: 27.5.1(@babel/core@7.24.3) - ts-jest@27.1.5(@babel/core@7.25.2)(@types/jest@29.5.1)(babel-jest@27.5.1(@babel/core@7.25.2))(jest@27.5.1(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(typescript@5.6.2): + ts-jest@27.1.5(@babel/core@7.24.4)(@types/jest@29.5.2)(babel-jest@27.5.1(@babel/core@7.24.4))(jest@27.5.1(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(typescript@5.6.2): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 @@ -79995,15 +80046,15 @@ snapshots: typescript: 5.6.2 yargs-parser: 20.2.9 optionalDependencies: - '@babel/core': 7.25.2 - '@types/jest': 29.5.1 - babel-jest: 27.5.1(@babel/core@7.25.2) + '@babel/core': 7.24.4 + '@types/jest': 29.5.2 + babel-jest: 27.5.1(@babel/core@7.24.4) - ts-jest@27.1.5(@babel/core@7.25.2)(@types/jest@29.5.13)(babel-jest@27.5.1(@babel/core@7.25.2))(jest@29.7.0(@types/node@18.16.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)))(typescript@5.6.2): + ts-jest@27.1.5(@babel/core@7.25.2)(@types/jest@29.5.1)(babel-jest@27.5.1(@babel/core@7.25.2))(jest@27.5.1(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(typescript@5.6.2): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@18.16.9)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)) + jest: 27.5.1(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) jest-util: 27.5.1 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -80013,7 +80064,7 @@ snapshots: yargs-parser: 20.2.9 optionalDependencies: '@babel/core': 7.25.2 - '@types/jest': 29.5.13 + '@types/jest': 29.5.1 babel-jest: 27.5.1(@babel/core@7.25.2) ts-jest@27.1.5(@babel/core@7.25.2)(@types/jest@29.5.13)(babel-jest@27.5.1(@babel/core@7.25.2))(jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(typescript@5.6.2): @@ -80033,11 +80084,11 @@ snapshots: '@types/jest': 29.5.13 babel-jest: 27.5.1(@babel/core@7.25.2) - ts-jest@27.1.5(@babel/core@7.25.2)(@types/jest@29.5.2)(babel-jest@27.5.1(@babel/core@7.25.2))(jest@27.5.1(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@22.7.4)(typescript@5.6.2)))(typescript@5.6.2): + ts-jest@27.1.5(@babel/core@7.25.2)(@types/jest@29.5.2)(babel-jest@27.5.1(@babel/core@7.25.2))(jest@27.5.1(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)))(typescript@5.6.2): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 - jest: 27.5.1(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@22.7.4)(typescript@5.6.2)) + jest: 27.5.1(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)) jest-util: 27.5.1 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -80050,11 +80101,11 @@ snapshots: '@types/jest': 29.5.2 babel-jest: 27.5.1(@babel/core@7.25.2) - ts-jest@27.1.5(@babel/core@7.25.2)(@types/jest@29.5.2)(babel-jest@27.5.1(@babel/core@7.25.2))(jest@27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(typescript@5.6.2): + ts-jest@27.1.5(@babel/core@7.25.2)(@types/jest@29.5.2)(babel-jest@27.5.1(@babel/core@7.25.2))(jest@27.5.1(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@22.7.4)(typescript@5.6.2)))(typescript@5.6.2): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 - jest: 27.5.1(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) + jest: 27.5.1(ts-node@10.9.1(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@22.7.4)(typescript@5.6.2)) jest-util: 27.5.1 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -80084,7 +80135,7 @@ snapshots: '@types/jest': 29.5.2 babel-jest: 27.5.1(@babel/core@7.25.2) - ts-jest@29.1.0(@babel/core@7.25.2)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(esbuild@0.18.20)(jest@29.5.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(typescript@5.6.2): + ts-jest@29.1.0(@babel/core@7.25.2)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(jest@29.5.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(typescript@5.6.2): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 @@ -80100,24 +80151,6 @@ snapshots: '@babel/core': 7.25.2 '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.25.2) - esbuild: 0.18.20 - - ts-jest@29.1.2(@babel/core@7.24.4)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.4))(jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)))(typescript@5.6.2): - dependencies: - bs-logger: 0.2.6 - fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)) - jest-util: 29.7.0 - json5: 2.2.3 - lodash.memoize: 4.1.2 - make-error: 1.3.6 - semver: 7.6.3 - typescript: 5.6.2 - yargs-parser: 21.1.1 - optionalDependencies: - '@babel/core': 7.24.4 - '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.24.4) ts-jest@29.1.2(@babel/core@7.25.2)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(esbuild@0.23.1)(jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(typescript@5.6.2): dependencies: @@ -80137,11 +80170,11 @@ snapshots: babel-jest: 29.7.0(@babel/core@7.25.2) esbuild: 0.23.1 - ts-jest@29.1.2(@babel/core@7.25.2)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)))(typescript@5.6.2): + ts-jest@29.1.2(@babel/core@7.25.2)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(typescript@5.6.2): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@18.16.9)(typescript@5.6.2)) + jest: 29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -80163,32 +80196,23 @@ snapshots: typescript: 5.6.2 webpack: 5.94.0(@swc/core@1.7.26(@swc/helpers@0.5.12)) - ts-loader@9.4.4(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)): - dependencies: - chalk: 4.1.2 - enhanced-resolve: 5.17.1 - micromatch: 4.0.8 - semver: 7.6.3 - typescript: 5.6.2 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20) - - ts-loader@9.4.4(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)): + ts-loader@9.4.4(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)): dependencies: chalk: 4.1.2 enhanced-resolve: 5.17.1 micromatch: 4.0.8 semver: 7.6.3 typescript: 5.6.2 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4) - ts-loader@9.4.4(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)): + ts-loader@9.4.4(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)): dependencies: chalk: 4.1.2 enhanced-resolve: 5.17.1 micromatch: 4.0.8 semver: 7.6.3 typescript: 5.6.2 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4) ts-loader@9.4.4(typescript@5.6.2)(webpack@5.94.0(@swc/core@1.7.26(@swc/helpers@0.5.12))): dependencies: @@ -80349,6 +80373,27 @@ snapshots: optionalDependencies: '@swc/core': 1.3.107(@swc/helpers@0.5.12) + ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.9 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.3 + '@types/node': 20.16.5 + acorn: 8.12.1 + acorn-walk: 8.3.2 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.6.2 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + optionalDependencies: + '@swc/core': 1.3.107(@swc/helpers@0.5.12) + optional: true + ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.14.10)(typescript@5.6.2): dependencies: '@cspotcode/source-map-support': 0.8.1 @@ -81147,23 +81192,23 @@ snapshots: url-join@5.0.0: {} - url-loader@4.1.1(file-loader@6.2.0(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)))(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)): + url-loader@4.1.1(file-loader@6.2.0(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)): dependencies: loader-utils: 2.0.4 mime-types: 2.1.35 schema-utils: 3.3.0 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4) optionalDependencies: - file-loader: 6.2.0(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) + file-loader: 6.2.0(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)) - url-loader@4.1.1(file-loader@6.2.0(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)): + url-loader@4.1.1(file-loader@6.2.0(webpack@5.94.0(@swc/core@1.7.26(@swc/helpers@0.5.12))))(webpack@5.94.0(@swc/core@1.7.26(@swc/helpers@0.5.12))): dependencies: loader-utils: 2.0.4 mime-types: 2.1.35 schema-utils: 3.3.0 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4) + webpack: 5.94.0(@swc/core@1.7.26(@swc/helpers@0.5.12)) optionalDependencies: - file-loader: 6.2.0(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)) + file-loader: 6.2.0(webpack@5.94.0(@swc/core@1.7.26(@swc/helpers@0.5.12))) url-parse@1.5.10: dependencies: @@ -82257,12 +82302,12 @@ snapshots: optionalDependencies: webpack-bundle-analyzer: 4.10.1 - webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack-dev-server@4.11.1)(webpack@5.78.0): + webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0): dependencies: '@discoveryjs/json-ext': 0.5.7 - '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack-dev-server@4.11.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)) - '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack-dev-server@4.11.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)) - '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack-dev-server@4.11.1)(webpack@5.78.0))(webpack-dev-server@4.11.1(webpack-cli@5.1.4)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)) + '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)) + '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)) + '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)) colorette: 2.0.20 commander: 10.0.1 cross-spawn: 7.0.3 @@ -82271,11 +82316,10 @@ snapshots: import-local: 3.1.0 interpret: 3.1.1 rechoir: 0.8.0 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4) webpack-merge: 5.9.0 optionalDependencies: webpack-bundle-analyzer: 4.9.0 - webpack-dev-server: 4.11.1(webpack-cli@5.1.4)(webpack@5.78.0) webpack-dev-middleware@5.3.3(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)): dependencies: @@ -82285,35 +82329,15 @@ snapshots: range-parser: 1.2.1 schema-utils: 4.0.0 webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20) - optional: true - - webpack-dev-middleware@5.3.3(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)): - dependencies: - colorette: 2.0.19 - memfs: 3.5.0 - mime-types: 2.1.35 - range-parser: 1.2.1 - schema-utils: 4.0.0 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) - - webpack-dev-middleware@5.3.3(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)): - dependencies: - colorette: 2.0.19 - memfs: 3.5.0 - mime-types: 2.1.35 - range-parser: 1.2.1 - schema-utils: 4.0.0 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4) - optional: true - webpack-dev-middleware@5.3.3(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))): + webpack-dev-middleware@5.3.3(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))): dependencies: colorette: 2.0.19 memfs: 3.5.0 mime-types: 2.1.35 range-parser: 1.2.1 schema-utils: 4.0.0 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12)) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12)) webpack-dev-middleware@6.1.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)): dependencies: @@ -82325,7 +82349,7 @@ snapshots: optionalDependencies: webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20) - webpack-dev-middleware@6.1.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)): + webpack-dev-middleware@6.1.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))): dependencies: colorette: 2.0.19 memfs: 3.5.0 @@ -82333,9 +82357,9 @@ snapshots: range-parser: 1.2.1 schema-utils: 4.0.0 optionalDependencies: - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12)) - webpack-dev-middleware@6.1.1(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)): + webpack-dev-middleware@6.1.1(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)): dependencies: colorette: 2.0.19 memfs: 3.5.0 @@ -82343,48 +82367,7 @@ snapshots: range-parser: 1.2.1 schema-utils: 4.0.0 optionalDependencies: - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4) - - webpack-dev-server@4.11.1(webpack-cli@5.1.4)(webpack@5.78.0): - dependencies: - '@types/bonjour': 3.5.10 - '@types/connect-history-api-fallback': 1.3.5 - '@types/express': 4.17.17 - '@types/serve-index': 1.9.1 - '@types/serve-static': 1.15.1 - '@types/sockjs': 0.3.33 - '@types/ws': 8.5.4 - ansi-html-community: 0.0.8 - bonjour-service: 1.1.1 - chokidar: 3.5.3 - colorette: 2.0.19 - compression: 1.7.4 - connect-history-api-fallback: 2.0.0 - default-gateway: 6.0.3 - express: 4.21.0 - graceful-fs: 4.2.11 - html-entities: 2.3.3 - http-proxy-middleware: 2.0.6(@types/express@4.17.17) - ipaddr.js: 2.0.1 - open: 8.4.2 - p-retry: 4.6.2 - rimraf: 3.0.2 - schema-utils: 4.0.0 - selfsigned: 2.1.1 - serve-index: 1.9.1 - sockjs: 0.3.24 - spdy: 4.0.2 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4) - webpack-dev-middleware: 5.3.3(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)) - ws: 8.13.0 - optionalDependencies: - webpack-cli: 5.1.4(webpack-bundle-analyzer@4.9.0)(webpack-dev-server@4.11.1)(webpack@5.78.0) - transitivePeerDependencies: - - bufferutil - - debug - - supports-color - - utf-8-validate - optional: true + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4) webpack-dev-server@4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)): dependencies: @@ -82423,47 +82406,8 @@ snapshots: - debug - supports-color - utf-8-validate - optional: true - - webpack-dev-server@4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)): - dependencies: - '@types/bonjour': 3.5.10 - '@types/connect-history-api-fallback': 1.3.5 - '@types/express': 4.17.17 - '@types/serve-index': 1.9.1 - '@types/serve-static': 1.15.1 - '@types/sockjs': 0.3.33 - '@types/ws': 8.5.4 - ansi-html-community: 0.0.8 - bonjour-service: 1.1.1 - chokidar: 3.5.3 - colorette: 2.0.19 - compression: 1.7.4 - connect-history-api-fallback: 2.0.0 - default-gateway: 6.0.3 - express: 4.21.0 - graceful-fs: 4.2.11 - html-entities: 2.3.3 - http-proxy-middleware: 2.0.6(@types/express@4.17.17) - ipaddr.js: 2.0.1 - open: 8.4.2 - p-retry: 4.6.2 - rimraf: 3.0.2 - schema-utils: 4.0.0 - selfsigned: 2.1.1 - serve-index: 1.9.1 - sockjs: 0.3.24 - spdy: 4.0.2 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) - webpack-dev-middleware: 5.3.3(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) - ws: 8.13.0 - transitivePeerDependencies: - - bufferutil - - debug - - supports-color - - utf-8-validate - webpack-dev-server@4.11.1(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))): + webpack-dev-server@4.11.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))): dependencies: '@types/bonjour': 3.5.10 '@types/connect-history-api-fallback': 1.3.5 @@ -82492,8 +82436,8 @@ snapshots: serve-index: 1.9.1 sockjs: 0.3.24 spdy: 4.0.2 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12)) - webpack-dev-middleware: 5.3.3(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12)) + webpack-dev-middleware: 5.3.3(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) ws: 8.13.0 transitivePeerDependencies: - bufferutil @@ -82514,16 +82458,16 @@ snapshots: strip-ansi: 6.0.1 optional: true - webpack-manifest-plugin@4.1.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)): + webpack-manifest-plugin@4.1.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)): dependencies: tapable: 2.2.1 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20) webpack-sources: 2.3.1 - webpack-manifest-plugin@4.1.1(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))): + webpack-manifest-plugin@4.1.1(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))): dependencies: tapable: 2.2.1 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12)) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12)) webpack-sources: 2.3.1 webpack-merge@5.9.0: @@ -82549,7 +82493,7 @@ snapshots: webpack-virtual-modules@0.6.2: {} - webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20): + webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12)): dependencies: '@types/eslint-scope': 3.7.4 '@types/estree': 0.0.51 @@ -82572,7 +82516,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) + terser-webpack-plugin: 5.3.10(@swc/core@1.3.107(@swc/helpers@0.5.12))(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))) watchpack: 2.4.2 webpack-sources: 3.2.3 transitivePeerDependencies: @@ -82580,7 +82524,7 @@ snapshots: - esbuild - uglify-js - webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack-dev-server@4.11.1)(webpack@5.78.0)): + webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20): dependencies: '@types/eslint-scope': 3.7.4 '@types/estree': 0.0.51 @@ -82603,17 +82547,15 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)) + terser-webpack-plugin: 5.3.10(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)) watchpack: 2.4.2 webpack-sources: 3.2.3 - optionalDependencies: - webpack-cli: 5.1.4(webpack-bundle-analyzer@4.9.0)(webpack-dev-server@4.11.1)(webpack@5.78.0) transitivePeerDependencies: - '@swc/core' - esbuild - uglify-js - webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1): + webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0)): dependencies: '@types/eslint-scope': 3.7.4 '@types/estree': 0.0.51 @@ -82636,9 +82578,11 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)) + terser-webpack-plugin: 5.3.10(@swc/core@1.3.107(@swc/helpers@0.5.12))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)) watchpack: 2.4.2 webpack-sources: 3.2.3 + optionalDependencies: + webpack-cli: 5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0) transitivePeerDependencies: - '@swc/core' - esbuild @@ -82675,7 +82619,7 @@ snapshots: - esbuild - uglify-js - webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4): + webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4): dependencies: '@types/eslint-scope': 3.7.4 '@types/estree': 0.0.51 @@ -82698,17 +82642,17 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.18.20)(webpack-cli@5.1.4)) + terser-webpack-plugin: 5.3.10(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)) watchpack: 2.4.2 webpack-sources: 3.2.3 optionalDependencies: - webpack-cli: 5.1.4(webpack-bundle-analyzer@4.9.0)(webpack-dev-server@4.11.1)(webpack@5.78.0) + webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0) transitivePeerDependencies: - '@swc/core' - esbuild - uglify-js - webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4): + webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4): dependencies: '@types/eslint-scope': 3.7.4 '@types/estree': 0.0.51 @@ -82731,11 +82675,11 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)) + terser-webpack-plugin: 5.3.10(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)) watchpack: 2.4.2 webpack-sources: 3.2.3 optionalDependencies: - webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0) + webpack-cli: 5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0) transitivePeerDependencies: - '@swc/core' - esbuild @@ -83109,24 +83053,24 @@ snapshots: workbox-sw@6.5.4: {} - workbox-webpack-plugin@6.5.4(@types/babel__core@7.20.5)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1)): + workbox-webpack-plugin@6.5.4(@types/babel__core@7.20.5)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20)): dependencies: fast-json-stable-stringify: 2.1.0 pretty-bytes: 5.6.0 upath: 1.2.0 - webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.23.1) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))(esbuild@0.18.20) webpack-sources: 1.4.3 workbox-build: 6.5.4(@types/babel__core@7.20.5) transitivePeerDependencies: - '@types/babel__core' - supports-color - workbox-webpack-plugin@6.5.4(@types/babel__core@7.20.5)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))): + workbox-webpack-plugin@6.5.4(@types/babel__core@7.20.5)(webpack@5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12))): dependencies: fast-json-stable-stringify: 2.1.0 pretty-bytes: 5.6.0 upath: 1.2.0 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12)) + webpack: 5.78.0(@swc/core@1.3.107(@swc/helpers@0.5.12)) webpack-sources: 1.4.3 workbox-build: 6.5.4(@types/babel__core@7.20.5) transitivePeerDependencies: From dac4ef81a7df952c8d6ee9b30a405f6e36e3982b Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Mon, 11 Nov 2024 01:02:06 +0100 Subject: [PATCH 24/56] refactor(zod): simplify import and type usage --- .../src/types/schema.types/zod.schema.types.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/packages/framework/src/types/schema.types/zod.schema.types.ts b/packages/framework/src/types/schema.types/zod.schema.types.ts index fd3f0ae9acb..78d5cf454d8 100644 --- a/packages/framework/src/types/schema.types/zod.schema.types.ts +++ b/packages/framework/src/types/schema.types/zod.schema.types.ts @@ -1,9 +1,6 @@ -import type { ZodType, infer as ZodInfer, input as ZodInput } from 'zod'; +import type zod from 'zod'; -/** - * A Zod schema. - */ -export type ZodSchema = ZodType; +export type ZodSchema = zod.ZodType; /** * A minimal ZodSchema type. @@ -39,7 +36,7 @@ export type InferZodSchema = ? // Secondly, narrow to the Zod type to provide type-safety to `zod.infer` and `zod.input` T extends ZodSchema ? Options['validated'] extends true - ? ZodInfer - : ZodInput + ? zod.infer + : zod.input : never : never; From d5c304b4ae1ab912a0143a014866b7261359d1ee Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Mon, 11 Nov 2024 01:16:25 +0100 Subject: [PATCH 25/56] Update packages/framework/src/types/schema.types/zod.schema.types.ts --- packages/framework/src/types/schema.types/zod.schema.types.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/framework/src/types/schema.types/zod.schema.types.ts b/packages/framework/src/types/schema.types/zod.schema.types.ts index ef33671e3b4..78d5cf454d8 100644 --- a/packages/framework/src/types/schema.types/zod.schema.types.ts +++ b/packages/framework/src/types/schema.types/zod.schema.types.ts @@ -1,4 +1,3 @@ - import type zod from 'zod'; export type ZodSchema = zod.ZodType; From 1281a14200b11c012cd446cdbc334731ebdb1b8a Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Mon, 11 Nov 2024 01:16:51 +0100 Subject: [PATCH 26/56] Update packages/framework/src/client.test.ts --- packages/framework/src/client.test.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/framework/src/client.test.ts b/packages/framework/src/client.test.ts index b91915df1e4..a80064e2359 100644 --- a/packages/framework/src/client.test.ts +++ b/packages/framework/src/client.test.ts @@ -313,8 +313,6 @@ describe('Novu Client', () => { if (stepChat === undefined) throw new Error('stepEmail is undefined'); expect(stepChat.type).toBe('chat'); expect(stepChat.code).toContain(`body: "Test Body"`); - console.log(stepChat.providers); - // await new Promise((resolve) => setTimeout(resolve, 1000)); expect(stepChat.providers[0].code).toContain(`type: "plain_text"`); expect(stepChat.providers[0].code).toContain(`text: "Pretty Header"`); }); From d29556d481bcdaa13ce770c96f7ac7ec95914160 Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Mon, 11 Nov 2024 01:17:18 +0100 Subject: [PATCH 27/56] Update packages/framework/package.json --- packages/framework/package.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/framework/package.json b/packages/framework/package.json index 7cd8962a9e5..f9c074627c7 100644 --- a/packages/framework/package.json +++ b/packages/framework/package.json @@ -264,8 +264,6 @@ "sanitize-html": "^2.13.0" }, "nx": { - "tags": [ - "package:public" - ] + "tags": ["package:public"] } } From 0ab32ecf473e4e38f2049935d7b8f853ef4a4b79 Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Mon, 11 Nov 2024 01:20:33 +0100 Subject: [PATCH 28/56] Update packages/framework/src/validators/class-validator.validator.ts --- packages/framework/src/validators/class-validator.validator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/framework/src/validators/class-validator.validator.ts b/packages/framework/src/validators/class-validator.validator.ts index 6770f1554a2..492f7e5c53d 100644 --- a/packages/framework/src/validators/class-validator.validator.ts +++ b/packages/framework/src/validators/class-validator.validator.ts @@ -100,7 +100,7 @@ export class ClassValidatorValidator implements Validator (schema as ClassValidatorSchema).prototype.constructor === schema; if (canHandle) { - await checkDependencies(this.requiredImports, 'class-validator schema'); + await checkDependencies(this.requiredImports, 'Class Validator schema'); } return canHandle; From 5d76360cba0536585c87e04e9b806da15c059487 Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Mon, 11 Nov 2024 01:55:10 +0100 Subject: [PATCH 29/56] refactor(json-schema): update JSONSchema imports --- packages/shared/package.json | 3 - .../src/dto/workflows/json-schema-dto.ts | 139 +++++++++--------- .../shared/src/dto/workflows/step-data.dto.ts | 6 +- .../dto/workflows/workflow-commons-fields.ts | 4 +- .../workflow-test-data-response-dto.ts | 6 +- .../message-template.interface.ts | 8 +- .../notification-template.interface.ts | 6 +- pnpm-lock.yaml | 14 -- 8 files changed, 79 insertions(+), 107 deletions(-) diff --git a/packages/shared/package.json b/packages/shared/package.json index 5dde98dc13a..0846c48f156 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -38,9 +38,6 @@ } }, "devDependencies": { - "@types/bluebird": "^3.5.24", - "@types/jest": "29.5.2", - "json-schema-to-ts": "^3.0.0", "rimraf": "^3.0.2", "typescript": "5.6.2", "vitest": "^2.0.5" diff --git a/packages/shared/src/dto/workflows/json-schema-dto.ts b/packages/shared/src/dto/workflows/json-schema-dto.ts index b92311149f7..9a81fc4c0fc 100644 --- a/packages/shared/src/dto/workflows/json-schema-dto.ts +++ b/packages/shared/src/dto/workflows/json-schema-dto.ts @@ -1,74 +1,67 @@ -export type JSONSchemaTypeName = 'string' | 'number' | 'integer' | 'boolean' | 'object' | 'array' | 'null'; +/** + * Json Schema version 7. + * + * Copied from import(`json-schema-to-ts`).JSONSchema. + */ +export declare const $JSONSchema: unique symbol; +export type $JSONSchema = typeof $JSONSchema; +export type JSONSchemaType = 'string' | 'number' | 'integer' | 'boolean' | 'object' | 'array' | 'null'; +export type JSONSchema = + | boolean + | Readonly<{ + [$JSONSchema]?: $JSONSchema; + $id?: string | undefined; + $ref?: string | undefined; + $schema?: string | undefined; + $comment?: string | undefined; + type?: JSONSchemaType | readonly JSONSchemaType[]; + const?: unknown; + enum?: unknown; + multipleOf?: number | undefined; + maximum?: number | undefined; + exclusiveMaximum?: number | undefined; + minimum?: number | undefined; + exclusiveMinimum?: number | undefined; + maxLength?: number | undefined; + minLength?: number | undefined; + pattern?: string | undefined; + items?: JSONSchema | readonly JSONSchema[]; + additionalItems?: JSONSchema; + contains?: JSONSchema; + maxItems?: number | undefined; + minItems?: number | undefined; + uniqueItems?: boolean | undefined; + maxProperties?: number | undefined; + minProperties?: number | undefined; + required?: readonly string[]; + properties?: Readonly>; + patternProperties?: Readonly>; + additionalProperties?: JSONSchema; + unevaluatedProperties?: JSONSchema; + dependencies?: Readonly>; + propertyNames?: JSONSchema; + if?: JSONSchema; + then?: JSONSchema; + else?: JSONSchema; + allOf?: readonly JSONSchema[]; + anyOf?: readonly JSONSchema[]; + oneOf?: readonly JSONSchema[]; + not?: JSONSchema; + format?: string | undefined; + contentMediaType?: string | undefined; + contentEncoding?: string | undefined; + definitions?: Readonly>; + title?: string | undefined; + description?: string | undefined; + default?: unknown; + readOnly?: boolean | undefined; + writeOnly?: boolean | undefined; + examples?: readonly unknown[]; + nullable?: boolean; + }>; +export type JSONSchemaReference = JSONSchema & + Readonly<{ + $id: string; + }>; -export type JSONSchemaType = string | number | boolean | JSONSchemaObject | JSONSchemaArray | null; - -// eslint-disable-next-line @typescript-eslint/naming-convention -export interface JSONSchemaObject { - [key: string]: JSONSchemaType; -} - -// eslint-disable-next-line @typescript-eslint/naming-convention -export interface JSONSchemaArray extends Array {} - -export type JSONSchemaVersion = string; - -export type JSONSchemaDefinition = JSONSchemaDto | boolean; - -// eslint-disable-next-line @typescript-eslint/naming-convention -export interface JSONSchemaDto { - type?: JSONSchemaTypeName | JSONSchemaTypeName[] | undefined; - enum?: JSONSchemaType[] | undefined; - const?: JSONSchemaType | undefined; - multipleOf?: number | undefined; - maximum?: number | undefined; - exclusiveMaximum?: number | undefined; - minimum?: number | undefined; - exclusiveMinimum?: number | undefined; - maxLength?: number | undefined; - minLength?: number | undefined; - pattern?: string | undefined; - items?: JSONSchemaDefinition | JSONSchemaDefinition[] | undefined; - additionalItems?: JSONSchemaDefinition | undefined; - maxItems?: number | undefined; - minItems?: number | undefined; - uniqueItems?: boolean | undefined; - contains?: JSONSchemaDefinition | undefined; - maxProperties?: number | undefined; - minProperties?: number | undefined; - required?: string[] | undefined; - properties?: - | { - [key: string]: JSONSchemaDefinition; - } - | undefined; - patternProperties?: - | { - [key: string]: JSONSchemaDefinition; - } - | undefined; - additionalProperties?: JSONSchemaDefinition | undefined; - dependencies?: - | { - [key: string]: JSONSchemaDefinition | string[]; - } - | undefined; - propertyNames?: JSONSchemaDefinition | undefined; - if?: JSONSchemaDefinition | undefined; - then?: JSONSchemaDefinition | undefined; - else?: JSONSchemaDefinition | undefined; - allOf?: JSONSchemaDefinition[] | undefined; - anyOf?: JSONSchemaDefinition[] | undefined; - oneOf?: JSONSchemaDefinition[] | undefined; - not?: JSONSchemaDefinition | undefined; - definitions?: - | { - [key: string]: JSONSchemaDefinition; - } - | undefined; - title?: string | undefined; - description?: string | undefined; - default?: JSONSchemaType | undefined; - readOnly?: boolean | undefined; - writeOnly?: boolean | undefined; - examples?: JSONSchemaType | undefined; -} +export type JSONSchemaDto = Exclude; diff --git a/packages/shared/src/dto/workflows/step-data.dto.ts b/packages/shared/src/dto/workflows/step-data.dto.ts index 73db886681d..a5c1e31a138 100644 --- a/packages/shared/src/dto/workflows/step-data.dto.ts +++ b/packages/shared/src/dto/workflows/step-data.dto.ts @@ -1,8 +1,8 @@ -import type { JSONSchema } from 'json-schema-to-ts'; +import type { JSONSchemaDto } from './json-schema-dto'; export type StepDataDto = { controls: ControlsMetadata; - variables: JSONSchema; + variables: JSONSchemaDto; stepId: string; _id: string; name: string; @@ -35,7 +35,7 @@ export class UiSchema { } export class ControlsMetadata { - dataSchema?: JSONSchema; + dataSchema?: JSONSchemaDto; uiSchema?: UiSchema; values: Record; } diff --git a/packages/shared/src/dto/workflows/workflow-commons-fields.ts b/packages/shared/src/dto/workflows/workflow-commons-fields.ts index 9f410eaa94d..cfc48d10519 100644 --- a/packages/shared/src/dto/workflows/workflow-commons-fields.ts +++ b/packages/shared/src/dto/workflows/workflow-commons-fields.ts @@ -1,10 +1,10 @@ -import type { JSONSchema } from 'json-schema-to-ts'; +import type { JSONSchemaDto } from './json-schema-dto'; import { WorkflowResponseDto } from './workflow-response-dto'; import { Slug, StepTypeEnum, WorkflowPreferences } from '../../types'; import { StepContentIssueEnum, StepIssueEnum } from './step-content-issue.enum'; export class ControlsSchema { - schema: JSONSchema; + schema: JSONSchemaDto; } export type StepCreateAndUpdateKeys = keyof StepCreateDto | keyof StepUpdateDto; diff --git a/packages/shared/src/dto/workflows/workflow-test-data-response-dto.ts b/packages/shared/src/dto/workflows/workflow-test-data-response-dto.ts index 016465501cf..7de54c13316 100644 --- a/packages/shared/src/dto/workflows/workflow-test-data-response-dto.ts +++ b/packages/shared/src/dto/workflows/workflow-test-data-response-dto.ts @@ -1,6 +1,6 @@ -import type { JSONSchema } from 'json-schema-to-ts'; +import type { JSONSchemaDto } from './json-schema-dto'; export type WorkflowTestDataResponseDto = { - to: JSONSchema; - payload: JSONSchema; + to: JSONSchemaDto; + payload: JSONSchemaDto; }; diff --git a/packages/shared/src/entities/message-template/message-template.interface.ts b/packages/shared/src/entities/message-template/message-template.interface.ts index e5052751beb..8b8c412982a 100644 --- a/packages/shared/src/entities/message-template/message-template.interface.ts +++ b/packages/shared/src/entities/message-template/message-template.interface.ts @@ -1,5 +1,3 @@ -import type { JSONSchema } from 'json-schema-to-ts'; - import { ChannelCTATypeEnum, EnvironmentId, @@ -11,7 +9,7 @@ import { } from '../../types'; import { TriggerContextTypeEnum } from '../notification-template'; import { IActor } from '../messages'; -import { UiSchema } from '../../dto'; +import type { JSONSchemaDto, UiSchema } from '../../dto'; export type MessageTemplateContentType = 'editor' | 'customHtml'; @@ -45,14 +43,14 @@ export interface IMessageTemplate { actor?: IActor; controls?: ControlSchemas; output?: { - schema: JSONSchema; + schema: JSONSchemaDto; }; code?: string; createdAt?: string; updatedAt?: string; } export class ControlSchemas { - schema: JSONSchema; + schema: JSONSchemaDto; uiSchema?: UiSchema; } export const TemplateSystemVariables = ['subscriber', 'step', 'branding', 'tenant', 'preheader', 'actor']; diff --git a/packages/shared/src/entities/notification-template/notification-template.interface.ts b/packages/shared/src/entities/notification-template/notification-template.interface.ts index a2c55a093e1..6b74dc24f36 100644 --- a/packages/shared/src/entities/notification-template/notification-template.interface.ts +++ b/packages/shared/src/entities/notification-template/notification-template.interface.ts @@ -1,5 +1,3 @@ -import type { JSONSchema } from 'json-schema-to-ts'; - import type { BuilderFieldType, BuilderGroupValues, @@ -12,7 +10,7 @@ import { ControlSchemas, IMessageTemplate } from '../message-template'; import { IPreferenceChannels } from '../subscriber-preference'; import { IWorkflowStepMetadata } from '../step'; import { INotificationGroup } from '../notification-group'; -import { ContentIssue, ControlsDto, StepIssue } from '../../index'; +import type { ContentIssue, ControlsDto, JSONSchemaDto, StepIssue } from '../../index'; export interface INotificationTemplate { _id?: string; @@ -104,7 +102,7 @@ export interface IStepVariant { }; metadata?: IWorkflowStepMetadata; inputs?: { - schema: JSONSchema; + schema: JSONSchemaDto; }; /** * @deprecated This property is deprecated and will be removed in future versions. diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e423610e4ee..b77baeadfae 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4355,15 +4355,6 @@ importers: packages/shared: devDependencies: - '@types/bluebird': - specifier: ^3.5.24 - version: 3.5.38 - '@types/jest': - specifier: 29.5.2 - version: 29.5.2 - json-schema-to-ts: - specifier: ^3.0.0 - version: 3.1.0 rimraf: specifier: ^3.0.2 version: 3.0.2 @@ -16523,9 +16514,6 @@ packages: '@types/bcryptjs@2.4.6': resolution: {integrity: sha512-9xlo6R2qDs5uixm0bcIqCeMCE6HiQsIyel9KQySStiyqNl2tnj2mP3DX1Nf56MD6KMenNNlBBsy3LJ7gUEQPXQ==} - '@types/bluebird@3.5.38': - resolution: {integrity: sha512-yR/Kxc0dd4FfwtEoLZMoqJbM/VE/W7hXn/MIjb+axcwag0iFmSPK7OBUZq1YWLynJUoWQkfUrI7T0HDqGApNSg==} - '@types/body-parser@1.19.2': resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==} @@ -56599,8 +56587,6 @@ snapshots: '@types/bcryptjs@2.4.6': {} - '@types/bluebird@3.5.38': {} - '@types/body-parser@1.19.2': dependencies: '@types/connect': 3.4.36 From 0c8857d02cd671cb6042e1e7d6e88cd8073ffca3 Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Mon, 11 Nov 2024 01:59:59 +0100 Subject: [PATCH 30/56] docs(json-schema-dto): update comment for clarity --- packages/shared/src/dto/workflows/json-schema-dto.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/shared/src/dto/workflows/json-schema-dto.ts b/packages/shared/src/dto/workflows/json-schema-dto.ts index 9a81fc4c0fc..1963f4d4232 100644 --- a/packages/shared/src/dto/workflows/json-schema-dto.ts +++ b/packages/shared/src/dto/workflows/json-schema-dto.ts @@ -1,8 +1,11 @@ /** * Json Schema version 7. * - * Copied from import(`json-schema-to-ts`).JSONSchema. + * Note: Copied verbatim from import(`json-schema-to-ts`).JSONSchema. + * This is to avoid a dependency on `json-schema-to-ts` in the shared package when + * Framework can't be depended on, to avoid circular dependencies. */ + export declare const $JSONSchema: unique symbol; export type $JSONSchema = typeof $JSONSchema; export type JSONSchemaType = 'string' | 'number' | 'integer' | 'boolean' | 'object' | 'array' | 'null'; From 37bc8bcf0be010011334663afd58e7fbb4547e76 Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Mon, 11 Nov 2024 02:02:45 +0100 Subject: [PATCH 31/56] Update packages/framework/src/validators/validator.test.ts --- packages/framework/src/validators/validator.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/framework/src/validators/validator.test.ts b/packages/framework/src/validators/validator.test.ts index 26729b4d29a..c5c7563d5cb 100644 --- a/packages/framework/src/validators/validator.test.ts +++ b/packages/framework/src/validators/validator.test.ts @@ -1,9 +1,8 @@ import { describe, it, expect } from 'vitest'; import { z } from 'zod'; import { validateData, transformSchema } from './base.validator'; -import type { Schema, ZodSchema, JsonSchema } from '../types/schema.types'; +import type { Schema, ZodSchema, JsonSchema, ClassValidatorSchema } from '../types/schema.types'; import { SimpleStringSchema, NestedSchema, SimpleStringAndNumberSchema } from './fixures/class-validator.fixtures'; -import { ClassValidatorSchema } from '../types/schema.types/class.schema.types'; const schemas = ['zod', 'class', 'json'] as const; From 2b9c81f2050b0391115cd650e02b4c0223f7b16d Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Mon, 11 Nov 2024 04:40:51 +0100 Subject: [PATCH 32/56] refactor(json-schema-dto): simplify JSON schema types --- .../src/dto/workflows/json-schema-dto.ts | 140 +++++++++--------- 1 file changed, 72 insertions(+), 68 deletions(-) diff --git a/packages/shared/src/dto/workflows/json-schema-dto.ts b/packages/shared/src/dto/workflows/json-schema-dto.ts index 1963f4d4232..b92311149f7 100644 --- a/packages/shared/src/dto/workflows/json-schema-dto.ts +++ b/packages/shared/src/dto/workflows/json-schema-dto.ts @@ -1,70 +1,74 @@ -/** - * Json Schema version 7. - * - * Note: Copied verbatim from import(`json-schema-to-ts`).JSONSchema. - * This is to avoid a dependency on `json-schema-to-ts` in the shared package when - * Framework can't be depended on, to avoid circular dependencies. - */ +export type JSONSchemaTypeName = 'string' | 'number' | 'integer' | 'boolean' | 'object' | 'array' | 'null'; -export declare const $JSONSchema: unique symbol; -export type $JSONSchema = typeof $JSONSchema; -export type JSONSchemaType = 'string' | 'number' | 'integer' | 'boolean' | 'object' | 'array' | 'null'; -export type JSONSchema = - | boolean - | Readonly<{ - [$JSONSchema]?: $JSONSchema; - $id?: string | undefined; - $ref?: string | undefined; - $schema?: string | undefined; - $comment?: string | undefined; - type?: JSONSchemaType | readonly JSONSchemaType[]; - const?: unknown; - enum?: unknown; - multipleOf?: number | undefined; - maximum?: number | undefined; - exclusiveMaximum?: number | undefined; - minimum?: number | undefined; - exclusiveMinimum?: number | undefined; - maxLength?: number | undefined; - minLength?: number | undefined; - pattern?: string | undefined; - items?: JSONSchema | readonly JSONSchema[]; - additionalItems?: JSONSchema; - contains?: JSONSchema; - maxItems?: number | undefined; - minItems?: number | undefined; - uniqueItems?: boolean | undefined; - maxProperties?: number | undefined; - minProperties?: number | undefined; - required?: readonly string[]; - properties?: Readonly>; - patternProperties?: Readonly>; - additionalProperties?: JSONSchema; - unevaluatedProperties?: JSONSchema; - dependencies?: Readonly>; - propertyNames?: JSONSchema; - if?: JSONSchema; - then?: JSONSchema; - else?: JSONSchema; - allOf?: readonly JSONSchema[]; - anyOf?: readonly JSONSchema[]; - oneOf?: readonly JSONSchema[]; - not?: JSONSchema; - format?: string | undefined; - contentMediaType?: string | undefined; - contentEncoding?: string | undefined; - definitions?: Readonly>; - title?: string | undefined; - description?: string | undefined; - default?: unknown; - readOnly?: boolean | undefined; - writeOnly?: boolean | undefined; - examples?: readonly unknown[]; - nullable?: boolean; - }>; -export type JSONSchemaReference = JSONSchema & - Readonly<{ - $id: string; - }>; +export type JSONSchemaType = string | number | boolean | JSONSchemaObject | JSONSchemaArray | null; -export type JSONSchemaDto = Exclude; +// eslint-disable-next-line @typescript-eslint/naming-convention +export interface JSONSchemaObject { + [key: string]: JSONSchemaType; +} + +// eslint-disable-next-line @typescript-eslint/naming-convention +export interface JSONSchemaArray extends Array {} + +export type JSONSchemaVersion = string; + +export type JSONSchemaDefinition = JSONSchemaDto | boolean; + +// eslint-disable-next-line @typescript-eslint/naming-convention +export interface JSONSchemaDto { + type?: JSONSchemaTypeName | JSONSchemaTypeName[] | undefined; + enum?: JSONSchemaType[] | undefined; + const?: JSONSchemaType | undefined; + multipleOf?: number | undefined; + maximum?: number | undefined; + exclusiveMaximum?: number | undefined; + minimum?: number | undefined; + exclusiveMinimum?: number | undefined; + maxLength?: number | undefined; + minLength?: number | undefined; + pattern?: string | undefined; + items?: JSONSchemaDefinition | JSONSchemaDefinition[] | undefined; + additionalItems?: JSONSchemaDefinition | undefined; + maxItems?: number | undefined; + minItems?: number | undefined; + uniqueItems?: boolean | undefined; + contains?: JSONSchemaDefinition | undefined; + maxProperties?: number | undefined; + minProperties?: number | undefined; + required?: string[] | undefined; + properties?: + | { + [key: string]: JSONSchemaDefinition; + } + | undefined; + patternProperties?: + | { + [key: string]: JSONSchemaDefinition; + } + | undefined; + additionalProperties?: JSONSchemaDefinition | undefined; + dependencies?: + | { + [key: string]: JSONSchemaDefinition | string[]; + } + | undefined; + propertyNames?: JSONSchemaDefinition | undefined; + if?: JSONSchemaDefinition | undefined; + then?: JSONSchemaDefinition | undefined; + else?: JSONSchemaDefinition | undefined; + allOf?: JSONSchemaDefinition[] | undefined; + anyOf?: JSONSchemaDefinition[] | undefined; + oneOf?: JSONSchemaDefinition[] | undefined; + not?: JSONSchemaDefinition | undefined; + definitions?: + | { + [key: string]: JSONSchemaDefinition; + } + | undefined; + title?: string | undefined; + description?: string | undefined; + default?: JSONSchemaType | undefined; + readOnly?: boolean | undefined; + writeOnly?: boolean | undefined; + examples?: JSONSchemaType | undefined; +} From 522d59acd6d6fee5c5e40b5e6dc1d8d294b44a70 Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Mon, 11 Nov 2024 04:42:12 +0100 Subject: [PATCH 33/56] refactor(api): replace json-schema with JSONSchemaDto --- apps/api/package.json | 1 - .../shared/build-string-schema.ts | 6 ++-- .../shared/schemas/email-control.schema.ts | 5 ++- .../shared/schemas/in-app-control.schema.ts | 9 +++--- .../get-step-schema/get-step-data.usecase.ts | 17 +++++----- .../usecases/test-data/test-data.usecase.ts | 11 +++++-- apps/dashboard/package.json | 1 + .../src/components/workflow-editor/schema.ts | 4 +-- .../parseStepVariablesToLiquidVariables.ts | 4 +-- libs/dal/package.json | 1 - .../message-template.entity.ts | 6 ++-- pnpm-lock.yaml | 32 ++++++++----------- 12 files changed, 44 insertions(+), 53 deletions(-) diff --git a/apps/api/package.json b/apps/api/package.json index f933fcdc655..d8e502b2b86 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -93,7 +93,6 @@ "shortid": "^2.2.16", "swagger-ui-express": "^4.4.0", "twilio": "^4.14.1","zod": "^3.23.8", - "json-schema-to-ts": "^3.0.0", "uuid": "^8.3.2" }, "devDependencies": { diff --git a/apps/api/src/app/workflows-v2/shared/build-string-schema.ts b/apps/api/src/app/workflows-v2/shared/build-string-schema.ts index 92d413018a0..b5947b75483 100644 --- a/apps/api/src/app/workflows-v2/shared/build-string-schema.ts +++ b/apps/api/src/app/workflows-v2/shared/build-string-schema.ts @@ -1,10 +1,10 @@ -import { JSONSchema } from 'json-schema-to-ts'; +import { JSONSchemaDto } from '@novu/shared'; /** * Builds a JSON schema object where each variable becomes a string property. */ -export function buildJSONSchema(variables: Record): JSONSchema { - const properties: Record = {}; +export function buildJSONSchema(variables: Record): JSONSchemaDto { + const properties: Record = {}; for (const [variableKey, variableValue] of Object.entries(variables)) { properties[variableKey] = { diff --git a/apps/api/src/app/workflows-v2/shared/schemas/email-control.schema.ts b/apps/api/src/app/workflows-v2/shared/schemas/email-control.schema.ts index 3d58a156baa..54e3d4af02a 100644 --- a/apps/api/src/app/workflows-v2/shared/schemas/email-control.schema.ts +++ b/apps/api/src/app/workflows-v2/shared/schemas/email-control.schema.ts @@ -1,7 +1,6 @@ -import { JSONSchema } from 'json-schema-to-ts'; -import { UiComponentEnum, UiSchema, UiSchemaGroupEnum } from '@novu/shared'; +import { JSONSchemaDto, UiComponentEnum, UiSchema, UiSchemaGroupEnum } from '@novu/shared'; -export const EmailStepControlSchema: JSONSchema = { +export const EmailStepControlSchema: JSONSchemaDto = { type: 'object', properties: { emailEditor: { diff --git a/apps/api/src/app/workflows-v2/shared/schemas/in-app-control.schema.ts b/apps/api/src/app/workflows-v2/shared/schemas/in-app-control.schema.ts index 587e9c41e86..ee177b15145 100644 --- a/apps/api/src/app/workflows-v2/shared/schemas/in-app-control.schema.ts +++ b/apps/api/src/app/workflows-v2/shared/schemas/in-app-control.schema.ts @@ -1,5 +1,4 @@ -import { JSONSchema } from 'json-schema-to-ts'; -import { UiComponentEnum, UiSchema, UiSchemaGroupEnum, UiSchemaProperty } from '@novu/shared'; +import { JSONSchemaDto, UiComponentEnum, UiSchema, UiSchemaGroupEnum, UiSchemaProperty } from '@novu/shared'; const ABSOLUTE_AND_RELATIVE_URL_REGEX = '^(?!mailto:)(?:(https?):\\/\\/[^\\s/$.?#].[^\\s]*)|^(\\/[^\\s]*)$'; @@ -18,7 +17,7 @@ const redirectSchema = { }, required: ['url'], // url remains required additionalProperties: false, // No additional properties allowed -} as const satisfies JSONSchema; +} as const satisfies JSONSchemaDto; const actionSchema = { type: 'object', @@ -28,7 +27,7 @@ const actionSchema = { }, required: ['label'], additionalProperties: false, -} as const satisfies JSONSchema; +} as const satisfies JSONSchemaDto; export const inAppControlSchema = { type: 'object', @@ -43,7 +42,7 @@ export const inAppControlSchema = { }, required: ['body'], additionalProperties: false, -} as const satisfies JSONSchema; +} as const satisfies JSONSchemaDto; const redirectPlaceholder = { url: { diff --git a/apps/api/src/app/workflows-v2/usecases/get-step-schema/get-step-data.usecase.ts b/apps/api/src/app/workflows-v2/usecases/get-step-schema/get-step-data.usecase.ts index 9d8b67bb501..3470e42dd9a 100644 --- a/apps/api/src/app/workflows-v2/usecases/get-step-schema/get-step-data.usecase.ts +++ b/apps/api/src/app/workflows-v2/usecases/get-step-schema/get-step-data.usecase.ts @@ -1,6 +1,5 @@ import { BadRequestException, Injectable } from '@nestjs/common'; -import { ControlValuesLevelEnum, StepDataDto } from '@novu/shared'; -import { JSONSchema } from 'json-schema-to-ts'; +import { ControlValuesLevelEnum, JSONSchemaDto, StepDataDto } from '@novu/shared'; import { ControlValuesRepository, NotificationStepEntity, NotificationTemplateEntity } from '@novu/dal'; import { GetStepDataCommand } from './get-step-data.command'; import { mapStepTypeToResult } from '../../shared'; @@ -119,12 +118,12 @@ const buildSubscriberSchema = () => }, required: ['firstName', 'lastName', 'email', 'subscriberId'], additionalProperties: false, - }) as const satisfies JSONSchema; + }) as const satisfies JSONSchemaDto; function buildVariablesSchema( previousSteps: NotificationStepEntity[] | undefined, - payloadSchema: JSONSchema -): JSONSchema { + payloadSchema: JSONSchemaDto +): JSONSchemaDto { return { type: 'object', properties: { @@ -133,12 +132,12 @@ function buildVariablesSchema( payload: payloadSchema, }, additionalProperties: false, - } as const satisfies JSONSchema; + } as const satisfies JSONSchemaDto; } function buildPreviousStepsSchema(previousSteps: NotificationStepEntity[] | undefined) { type StepExternalId = string; - let previousStepsProperties: Record = {}; + let previousStepsProperties: Record = {}; previousStepsProperties = (previousSteps || []).reduce( (acc, step) => { @@ -148,7 +147,7 @@ function buildPreviousStepsSchema(previousSteps: NotificationStepEntity[] | unde return acc; }, - {} as Record + {} as Record ); return { @@ -157,5 +156,5 @@ function buildPreviousStepsSchema(previousSteps: NotificationStepEntity[] | unde required: [], additionalProperties: false, description: 'Previous Steps Results', - } as const satisfies JSONSchema; + } as const satisfies JSONSchemaDto; } diff --git a/apps/api/src/app/workflows-v2/usecases/test-data/test-data.usecase.ts b/apps/api/src/app/workflows-v2/usecases/test-data/test-data.usecase.ts index b27bc27a002..2d873c40989 100644 --- a/apps/api/src/app/workflows-v2/usecases/test-data/test-data.usecase.ts +++ b/apps/api/src/app/workflows-v2/usecases/test-data/test-data.usecase.ts @@ -1,7 +1,12 @@ -import { JSONSchema } from 'json-schema-to-ts'; import { Injectable } from '@nestjs/common'; import { ControlValuesRepository, NotificationStepEntity, NotificationTemplateEntity } from '@novu/dal'; -import { ControlValuesLevelEnum, StepTypeEnum, UserSessionData, WorkflowTestDataResponseDto } from '@novu/shared'; +import { + ControlValuesLevelEnum, + JSONSchemaDto, + StepTypeEnum, + UserSessionData, + WorkflowTestDataResponseDto, +} from '@novu/shared'; import { WorkflowTestDataCommand } from './test-data.command'; import { GetWorkflowByIdsUseCase } from '../get-workflow-by-ids/get-workflow-by-ids.usecase'; @@ -81,7 +86,7 @@ const buildToFieldSchema = ({ user, steps }: { user: UserSessionData; steps: Not }, required: ['subscriberId', ...(isEmailExist ? ['email'] : []), ...(isSmsExist ? ['phone'] : [])], additionalProperties: false, - } as const satisfies JSONSchema; + } as const satisfies JSONSchemaDto; }; function isContainsStepType(steps: NotificationStepEntity[], type: StepTypeEnum) { diff --git a/apps/dashboard/package.json b/apps/dashboard/package.json index 1b302ece074..b45f1f74251 100644 --- a/apps/dashboard/package.json +++ b/apps/dashboard/package.json @@ -7,6 +7,7 @@ "start": "vite", "start:static:build": "pm2 start proxy-server.js", "dev": "pnpm start", + "check:types": "tsc --noEmit", "build": "pnpm build:legacy && tsc -b && vite build", "build:legacy": "rimraf legacy/* && pnpm nx build:web:for-dashboard @novu/web", "lint": "eslint .", diff --git a/apps/dashboard/src/components/workflow-editor/schema.ts b/apps/dashboard/src/components/workflow-editor/schema.ts index 0c78ace3da1..ae6dad54c41 100644 --- a/apps/dashboard/src/components/workflow-editor/schema.ts +++ b/apps/dashboard/src/components/workflow-editor/schema.ts @@ -1,5 +1,5 @@ import * as z from 'zod'; -import type { StepResponseDto, WorkflowTestDataResponseDto } from '@novu/shared'; +import type { JSONSchema, StepResponseDto } from '@novu/shared'; import { StepTypeEnum } from '@/utils/enums'; import { capitalize } from '@/utils/string'; @@ -49,8 +49,6 @@ export const workflowSchema = z.object({ }), }); -export type JSONSchema = WorkflowTestDataResponseDto['to']; - export const buildDynamicFormSchema = ({ to, }: { diff --git a/apps/dashboard/src/utils/parseStepVariablesToLiquidVariables.ts b/apps/dashboard/src/utils/parseStepVariablesToLiquidVariables.ts index a52b0cc67cc..3bcb0509363 100644 --- a/apps/dashboard/src/utils/parseStepVariablesToLiquidVariables.ts +++ b/apps/dashboard/src/utils/parseStepVariablesToLiquidVariables.ts @@ -1,4 +1,4 @@ -import { StepDataDto } from '@novu/shared'; +import { JSONSchema } from '@novu/shared'; interface LiquidVariable { type: 'variable'; @@ -6,8 +6,6 @@ interface LiquidVariable { detail: string; } -type JSONSchema = StepDataDto['variables']; - /** * Parse JSON Schema and extract variables for Liquid autocompletion. * @param schema - The JSON Schema to parse. diff --git a/libs/dal/package.json b/libs/dal/package.json index daaa314a401..56118e8a18e 100644 --- a/libs/dal/package.json +++ b/libs/dal/package.json @@ -46,7 +46,6 @@ "@types/node": "^20.15.0", "@typescript-eslint/parser": "^4.14.2", "apollo-boost": "0.4.9", - "json-schema-to-ts": "^3.0.0", "ts-node": "~10.9.1", "tsconfig-paths": "~4.1.0", "typescript": "5.6.2", diff --git a/libs/dal/src/repositories/message-template/message-template.entity.ts b/libs/dal/src/repositories/message-template/message-template.entity.ts index aa86e8139a0..9217eb9b5de 100644 --- a/libs/dal/src/repositories/message-template/message-template.entity.ts +++ b/libs/dal/src/repositories/message-template/message-template.entity.ts @@ -1,14 +1,14 @@ -import { +import type { ControlSchemas, EnvironmentId, IActor, IMessageCTA, IMessageTemplate, + JSONSchemaDto, MessageTemplateContentType, OrganizationId, StepTypeEnum, } from '@novu/shared'; -import { JSONSchema } from 'json-schema-to-ts'; import { IEmailBlock, ITemplateVariable } from './types'; import type { ChangePropsValueType } from '../../types/helpers'; @@ -60,7 +60,7 @@ export class MessageTemplateEntity implements IMessageTemplate { controls?: ControlSchemas; output?: { - schema: JSONSchema; + schema: JSONSchemaDto; }; code?: string; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b77baeadfae..e100974d3f7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -480,9 +480,6 @@ importers: ioredis: specifier: 5.3.2 version: 5.3.2 - json-schema-to-ts: - specifier: ^3.0.0 - version: 3.1.0 jsonwebtoken: specifier: 9.0.0 version: 9.0.0 @@ -2872,9 +2869,6 @@ importers: apollo-boost: specifier: 0.4.9 version: 0.4.9(graphql@16.9.0) - json-schema-to-ts: - specifier: ^3.0.0 - version: 3.1.0 rimraf: specifier: ^3.0.2 version: 3.0.2 @@ -35274,8 +35268,8 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.575.0(@aws-sdk/client-sts@3.575.0) - '@aws-sdk/client-sts': 3.575.0 + '@aws-sdk/client-sso-oidc': 3.575.0 + '@aws-sdk/client-sts': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) '@aws-sdk/core': 3.575.0 '@aws-sdk/credential-provider-node': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0) '@aws-sdk/middleware-host-header': 3.575.0 @@ -35476,8 +35470,8 @@ snapshots: '@aws-crypto/sha1-browser': 3.0.0 '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.575.0(@aws-sdk/client-sts@3.575.0) - '@aws-sdk/client-sts': 3.575.0 + '@aws-sdk/client-sso-oidc': 3.575.0 + '@aws-sdk/client-sts': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) '@aws-sdk/core': 3.575.0 '@aws-sdk/credential-provider-node': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0) '@aws-sdk/middleware-bucket-endpoint': 3.575.0 @@ -35703,11 +35697,11 @@ snapshots: - aws-crt optional: true - '@aws-sdk/client-sso-oidc@3.575.0(@aws-sdk/client-sts@3.575.0)': + '@aws-sdk/client-sso-oidc@3.575.0': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.575.0 + '@aws-sdk/client-sts': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) '@aws-sdk/core': 3.575.0 '@aws-sdk/credential-provider-node': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0) '@aws-sdk/middleware-host-header': 3.575.0 @@ -35746,7 +35740,6 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.7.0 transitivePeerDependencies: - - '@aws-sdk/client-sts' - aws-crt '@aws-sdk/client-sso-oidc@3.637.0(@aws-sdk/client-sts@3.637.0)': @@ -36131,11 +36124,11 @@ snapshots: - aws-crt optional: true - '@aws-sdk/client-sts@3.575.0': + '@aws-sdk/client-sts@3.575.0(@aws-sdk/client-sso-oidc@3.575.0)': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.575.0(@aws-sdk/client-sts@3.575.0) + '@aws-sdk/client-sso-oidc': 3.575.0 '@aws-sdk/core': 3.575.0 '@aws-sdk/credential-provider-node': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0) '@aws-sdk/middleware-host-header': 3.575.0 @@ -36174,6 +36167,7 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.7.0 transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' - aws-crt '@aws-sdk/client-sts@3.637.0': @@ -36403,7 +36397,7 @@ snapshots: '@aws-sdk/credential-provider-ini@3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0)': dependencies: - '@aws-sdk/client-sts': 3.575.0 + '@aws-sdk/client-sts': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) '@aws-sdk/credential-provider-env': 3.575.0 '@aws-sdk/credential-provider-process': 3.575.0 '@aws-sdk/credential-provider-sso': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) @@ -36714,7 +36708,7 @@ snapshots: '@aws-sdk/credential-provider-web-identity@3.575.0(@aws-sdk/client-sts@3.575.0)': dependencies: - '@aws-sdk/client-sts': 3.575.0 + '@aws-sdk/client-sts': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) '@aws-sdk/types': 3.575.0 '@smithy/property-provider': 3.1.3 '@smithy/types': 3.3.0 @@ -37235,7 +37229,7 @@ snapshots: '@aws-sdk/token-providers@3.575.0(@aws-sdk/client-sso-oidc@3.575.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.575.0(@aws-sdk/client-sts@3.575.0) + '@aws-sdk/client-sso-oidc': 3.575.0 '@aws-sdk/types': 3.575.0 '@smithy/property-provider': 3.1.3 '@smithy/shared-ini-file-loader': 3.1.4 @@ -37244,7 +37238,7 @@ snapshots: '@aws-sdk/token-providers@3.614.0(@aws-sdk/client-sso-oidc@3.575.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.575.0(@aws-sdk/client-sts@3.575.0) + '@aws-sdk/client-sso-oidc': 3.575.0 '@aws-sdk/types': 3.609.0 '@smithy/property-provider': 3.1.3 '@smithy/shared-ini-file-loader': 3.1.4 From 8c24423a4098e5210ac2b9d0ecdb5c687ab97a82 Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Mon, 11 Nov 2024 04:58:29 +0100 Subject: [PATCH 34/56] refactor(schema): update JSONSchema to JSONSchemaDefinition --- apps/dashboard/package.json | 1 + .../dashboard/src/components/workflow-editor/schema.ts | 10 +++++++--- .../src/utils/parseStepVariablesToLiquidVariables.ts | 8 ++++---- apps/dashboard/src/utils/schema.ts | 8 +++----- packages/shared/src/dto/workflows/json-schema-dto.ts | 1 + 5 files changed, 16 insertions(+), 12 deletions(-) diff --git a/apps/dashboard/package.json b/apps/dashboard/package.json index b45f1f74251..5cc44bc8acb 100644 --- a/apps/dashboard/package.json +++ b/apps/dashboard/package.json @@ -8,6 +8,7 @@ "start:static:build": "pm2 start proxy-server.js", "dev": "pnpm start", "check:types": "tsc --noEmit", + "build:new": "tsc -b && vite build", "build": "pnpm build:legacy && tsc -b && vite build", "build:legacy": "rimraf legacy/* && pnpm nx build:web:for-dashboard @novu/web", "lint": "eslint .", diff --git a/apps/dashboard/src/components/workflow-editor/schema.ts b/apps/dashboard/src/components/workflow-editor/schema.ts index ae6dad54c41..295065dafb9 100644 --- a/apps/dashboard/src/components/workflow-editor/schema.ts +++ b/apps/dashboard/src/components/workflow-editor/schema.ts @@ -1,5 +1,5 @@ import * as z from 'zod'; -import type { JSONSchema, StepResponseDto } from '@novu/shared'; +import type { JSONSchemaDefinition, StepResponseDto } from '@novu/shared'; import { StepTypeEnum } from '@/utils/enums'; import { capitalize } from '@/utils/string'; @@ -52,7 +52,7 @@ export const workflowSchema = z.object({ export const buildDynamicFormSchema = ({ to, }: { - to: JSONSchema; + to: JSONSchemaDefinition; }): z.ZodObject<{ to: z.ZodObject>; payload: z.ZodEffects; @@ -101,7 +101,11 @@ export const buildDynamicFormSchema = ({ export type TestWorkflowFormType = z.infer>; -export const makeObjectFromSchema = ({ properties }: { properties: Readonly> }) => { +export const makeObjectFromSchema = ({ + properties, +}: { + properties: Readonly>; +}) => { return Object.keys(properties).reduce((acc, key) => { const value = properties[key]; if (typeof value !== 'object') { diff --git a/apps/dashboard/src/utils/parseStepVariablesToLiquidVariables.ts b/apps/dashboard/src/utils/parseStepVariablesToLiquidVariables.ts index 3bcb0509363..42f183872b2 100644 --- a/apps/dashboard/src/utils/parseStepVariablesToLiquidVariables.ts +++ b/apps/dashboard/src/utils/parseStepVariablesToLiquidVariables.ts @@ -1,4 +1,4 @@ -import { JSONSchema } from '@novu/shared'; +import type { JSONSchemaDefinition } from '@novu/shared'; interface LiquidVariable { type: 'variable'; @@ -11,10 +11,10 @@ interface LiquidVariable { * @param schema - The JSON Schema to parse. * @returns An array of variable objects suitable for the Liquid language. */ -export function parseStepVariablesToLiquidVariables(schema: JSONSchema): LiquidVariable[] { +export function parseStepVariablesToLiquidVariables(schema: JSONSchemaDefinition): LiquidVariable[] { const variables: LiquidVariable[] = []; - function extractProperties(obj: JSONSchema, path = ''): void { + function extractProperties(obj: JSONSchemaDefinition, path = ''): void { if (typeof obj === 'boolean') return; // Handle boolean schema if (obj.type === 'object' && obj.properties) { @@ -42,7 +42,7 @@ export function parseStepVariablesToLiquidVariables(schema: JSONSchema): LiquidV // Handle combinators (allOf, anyOf, oneOf) ['allOf', 'anyOf', 'oneOf'].forEach((combiner) => { if (Array.isArray(obj[combiner as keyof typeof obj])) { - for (const subSchema of obj[combiner as keyof typeof obj] as JSONSchema[]) { + for (const subSchema of obj[combiner as keyof typeof obj] as JSONSchemaDefinition[]) { extractProperties(subSchema, path); } } diff --git a/apps/dashboard/src/utils/schema.ts b/apps/dashboard/src/utils/schema.ts index ea32ad1b2a4..082867add55 100644 --- a/apps/dashboard/src/utils/schema.ts +++ b/apps/dashboard/src/utils/schema.ts @@ -1,9 +1,7 @@ import * as z from 'zod'; -import { UiSchema, WorkflowTestDataResponseDto } from '@novu/shared'; +import { JSONSchemaDto, UiSchema } from '@novu/shared'; import { capitalize } from './string'; -type JSONSchema = WorkflowTestDataResponseDto['to']; - type ZodValue = | z.AnyZodObject | z.ZodString @@ -97,7 +95,7 @@ const handleStringType = ({ * The function will recursively build the schema based on the JSONSchema object. * It removes empty strings and objects with empty required fields during the transformation phase after parsing. */ -export const buildDynamicZodSchema = (obj: JSONSchema): z.AnyZodObject => { +export const buildDynamicZodSchema = (obj: JSONSchemaDto): z.AnyZodObject => { const properties = typeof obj === 'object' ? (obj.properties ?? {}) : {}; const requiredFields = typeof obj === 'object' ? (obj.required ?? []) : []; @@ -114,7 +112,7 @@ export const buildDynamicZodSchema = (obj: JSONSchema): z.AnyZodObject => { if (type === 'object') { zodValue = buildDynamicZodSchema(jsonSchemaProp); if (defaultValue) { - zodValue = zodValue.default(defaultValue); + zodValue = zodValue.default(defaultValue as object); } zodValue = zodValue.transform((val) => { const hasAnyRequiredEmpty = required?.some((field) => val[field] === '' || val[field] === undefined); diff --git a/packages/shared/src/dto/workflows/json-schema-dto.ts b/packages/shared/src/dto/workflows/json-schema-dto.ts index b92311149f7..d3b97c179cd 100644 --- a/packages/shared/src/dto/workflows/json-schema-dto.ts +++ b/packages/shared/src/dto/workflows/json-schema-dto.ts @@ -26,6 +26,7 @@ export interface JSONSchemaDto { exclusiveMinimum?: number | undefined; maxLength?: number | undefined; minLength?: number | undefined; + format?: string | undefined; pattern?: string | undefined; items?: JSONSchemaDefinition | JSONSchemaDefinition[] | undefined; additionalItems?: JSONSchemaDefinition | undefined; From d35de47d033a2a9293ba32e4c7b438b419ffed64 Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Mon, 11 Nov 2024 09:52:54 +0100 Subject: [PATCH 35/56] Update apps/dashboard/package.json --- apps/dashboard/package.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/dashboard/package.json b/apps/dashboard/package.json index 5cc44bc8acb..1b302ece074 100644 --- a/apps/dashboard/package.json +++ b/apps/dashboard/package.json @@ -7,8 +7,6 @@ "start": "vite", "start:static:build": "pm2 start proxy-server.js", "dev": "pnpm start", - "check:types": "tsc --noEmit", - "build:new": "tsc -b && vite build", "build": "pnpm build:legacy && tsc -b && vite build", "build:legacy": "rimraf legacy/* && pnpm nx build:web:for-dashboard @novu/web", "lint": "eslint .", From 4aaa2755e8ff6f55ddc9946017e7c4b13abf735c Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Mon, 11 Nov 2024 10:21:23 +0100 Subject: [PATCH 36/56] refactor: replace JsonSchema with JSONSchemaDto --- .../api/src/app/bridge/usecases/sync/sync.command.ts | 5 ++--- .../create-workflow/create-workflow.command.ts | 12 ++++++------ .../create-message-template.command.ts | 6 +++--- .../update-message-template.command.ts | 8 ++++---- .../update-workflow/update-workflow.command.ts | 6 +++--- 5 files changed, 18 insertions(+), 19 deletions(-) diff --git a/apps/api/src/app/bridge/usecases/sync/sync.command.ts b/apps/api/src/app/bridge/usecases/sync/sync.command.ts index d5e3b1c6a5c..de583f1b678 100644 --- a/apps/api/src/app/bridge/usecases/sync/sync.command.ts +++ b/apps/api/src/app/bridge/usecases/sync/sync.command.ts @@ -1,12 +1,11 @@ import { IsDefined, IsOptional, IsString, ValidateNested } from 'class-validator'; import { Type } from 'class-transformer'; -import { JsonSchema } from '@novu/framework/internal'; import { EnvironmentWithUserCommand, IStepControl } from '@novu/application-generic'; -import { StepType } from '@novu/shared'; +import type { JSONSchemaDto, StepType } from '@novu/shared'; interface IStepOutput { - schema: JsonSchema; + schema: JSONSchemaDto; } interface IWorkflowDefineStep { diff --git a/libs/application-generic/src/usecases/create-workflow/create-workflow.command.ts b/libs/application-generic/src/usecases/create-workflow/create-workflow.command.ts index 27003ada6e3..04627d85fb1 100644 --- a/libs/application-generic/src/usecases/create-workflow/create-workflow.command.ts +++ b/libs/application-generic/src/usecases/create-workflow/create-workflow.command.ts @@ -18,12 +18,12 @@ import { INotificationGroup, IPreferenceChannels, IWorkflowStepMetadata, + JSONSchemaDto, NotificationTemplateCustomData, WorkflowOriginEnum, WorkflowTypeEnum, } from '@novu/shared'; -import { JsonSchema } from '@novu/framework/internal'; import { EnvironmentWithUserCommand } from '../../commands'; export class CreateWorkflowCommand extends EnvironmentWithUserCommand { @@ -76,18 +76,18 @@ export class CreateWorkflowCommand extends EnvironmentWithUserCommand { @IsOptional() inputs?: { - schema: JsonSchema; + schema: JSONSchemaDto; }; @IsOptional() controls?: { - schema: JsonSchema; + schema: JSONSchemaDto; }; @IsOptional() rawData?: Record; @IsOptional() - payloadSchema?: JsonSchema; + payloadSchema?: JSONSchemaDto; @IsEnum(WorkflowTypeEnum) @IsDefined() @@ -163,12 +163,12 @@ export class NotificationStepVariantCommand { @IsOptional() controls?: { - schema: JsonSchema; + schema: JSONSchemaDto; }; @IsOptional() output?: { - schema: JsonSchema; + schema: JSONSchemaDto; }; @IsOptional() diff --git a/libs/application-generic/src/usecases/message-template/create-message-template/create-message-template.command.ts b/libs/application-generic/src/usecases/message-template/create-message-template/create-message-template.command.ts index 39c9996993f..f97e38cdebd 100644 --- a/libs/application-generic/src/usecases/message-template/create-message-template/create-message-template.command.ts +++ b/libs/application-generic/src/usecases/message-template/create-message-template/create-message-template.command.ts @@ -15,9 +15,9 @@ import { IActor, MessageTemplateContentType, WorkflowTypeEnum, + JSONSchemaDto, } from '@novu/shared'; -import { JsonSchema } from '@novu/framework/internal'; import { EnvironmentWithUserCommand } from '../../../commands'; export class CreateMessageTemplateCommand extends EnvironmentWithUserCommand { @@ -74,12 +74,12 @@ export class CreateMessageTemplateCommand extends EnvironmentWithUserCommand { @IsOptional() controls?: { - schema: JsonSchema; + schema: JSONSchemaDto; }; @IsOptional() output?: { - schema: JsonSchema; + schema: JSONSchemaDto; }; @IsOptional() diff --git a/libs/application-generic/src/usecases/message-template/update-message-template/update-message-template.command.ts b/libs/application-generic/src/usecases/message-template/update-message-template/update-message-template.command.ts index 7c4b9b70d01..b53c7f1e9a9 100644 --- a/libs/application-generic/src/usecases/message-template/update-message-template/update-message-template.command.ts +++ b/libs/application-generic/src/usecases/message-template/update-message-template/update-message-template.command.ts @@ -14,8 +14,8 @@ import { IActor, MessageTemplateContentType, WorkflowTypeEnum, + JSONSchemaDto, } from '@novu/shared'; -import { JsonSchema } from '@novu/framework/internal'; import { EnvironmentWithUserCommand } from '../../../commands'; export class UpdateMessageTemplateCommand extends EnvironmentWithUserCommand { @@ -75,16 +75,16 @@ export class UpdateMessageTemplateCommand extends EnvironmentWithUserCommand { @IsOptional() inputs?: { - schema: JsonSchema; + schema: JSONSchemaDto; }; @IsOptional() controls?: { - schema: JsonSchema; + schema: JSONSchemaDto; }; @IsOptional() output?: { - schema: JsonSchema; + schema: JSONSchemaDto; }; @IsOptional() diff --git a/libs/application-generic/src/usecases/workflow/update-workflow/update-workflow.command.ts b/libs/application-generic/src/usecases/workflow/update-workflow/update-workflow.command.ts index 12e743088d3..89fdc09c1c9 100644 --- a/libs/application-generic/src/usecases/workflow/update-workflow/update-workflow.command.ts +++ b/libs/application-generic/src/usecases/workflow/update-workflow/update-workflow.command.ts @@ -11,11 +11,11 @@ import { import { IPreferenceChannels, + JSONSchemaDto, NotificationTemplateCustomData, WorkflowTypeEnum, } from '@novu/shared'; -import { JsonSchema } from '@novu/framework/internal'; import { EnvironmentWithUserCommand } from '../../../commands'; import { NotificationStep } from '../..'; @@ -82,7 +82,7 @@ export class UpdateWorkflowCommand extends EnvironmentWithUserCommand { rawData?: any; @IsOptional() - payloadSchema?: JsonSchema; + payloadSchema?: JSONSchemaDto; @IsEnum(WorkflowTypeEnum) @IsDefined() @@ -90,5 +90,5 @@ export class UpdateWorkflowCommand extends EnvironmentWithUserCommand { } export interface IStepControl { - schema: JsonSchema; + schema: JSONSchemaDto; } From 2e5c3b554edec5b264108434a069a6cfeb8827e2 Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Mon, 11 Nov 2024 10:48:37 +0100 Subject: [PATCH 37/56] refactor(json-schema-dto): use readonly types for safety --- .../src/dto/workflows/json-schema-dto.ts | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/packages/shared/src/dto/workflows/json-schema-dto.ts b/packages/shared/src/dto/workflows/json-schema-dto.ts index d3b97c179cd..0f0bdd06910 100644 --- a/packages/shared/src/dto/workflows/json-schema-dto.ts +++ b/packages/shared/src/dto/workflows/json-schema-dto.ts @@ -14,11 +14,10 @@ export type JSONSchemaVersion = string; export type JSONSchemaDefinition = JSONSchemaDto | boolean; -// eslint-disable-next-line @typescript-eslint/naming-convention -export interface JSONSchemaDto { - type?: JSONSchemaTypeName | JSONSchemaTypeName[] | undefined; - enum?: JSONSchemaType[] | undefined; - const?: JSONSchemaType | undefined; +export type JSONSchemaDto = Readonly<{ + type?: JSONSchemaTypeName | readonly JSONSchemaTypeName[] | undefined; + enum?: unknown | undefined; + const?: unknown | undefined; multipleOf?: number | undefined; maximum?: number | undefined; exclusiveMaximum?: number | undefined; @@ -28,7 +27,7 @@ export interface JSONSchemaDto { minLength?: number | undefined; format?: string | undefined; pattern?: string | undefined; - items?: JSONSchemaDefinition | JSONSchemaDefinition[] | undefined; + items?: JSONSchemaDefinition | readonly JSONSchemaDefinition[] | undefined; additionalItems?: JSONSchemaDefinition | undefined; maxItems?: number | undefined; minItems?: number | undefined; @@ -36,40 +35,40 @@ export interface JSONSchemaDto { contains?: JSONSchemaDefinition | undefined; maxProperties?: number | undefined; minProperties?: number | undefined; - required?: string[] | undefined; + required?: readonly string[] | undefined; properties?: - | { + | Readonly<{ [key: string]: JSONSchemaDefinition; - } + }> | undefined; patternProperties?: - | { + | Readonly<{ [key: string]: JSONSchemaDefinition; - } + }> | undefined; additionalProperties?: JSONSchemaDefinition | undefined; dependencies?: - | { - [key: string]: JSONSchemaDefinition | string[]; - } + | Readonly<{ + [key: string]: JSONSchemaDefinition | readonly string[]; + }> | undefined; propertyNames?: JSONSchemaDefinition | undefined; if?: JSONSchemaDefinition | undefined; then?: JSONSchemaDefinition | undefined; else?: JSONSchemaDefinition | undefined; - allOf?: JSONSchemaDefinition[] | undefined; - anyOf?: JSONSchemaDefinition[] | undefined; - oneOf?: JSONSchemaDefinition[] | undefined; + allOf?: readonly JSONSchemaDefinition[] | undefined; + anyOf?: readonly JSONSchemaDefinition[] | undefined; + oneOf?: readonly JSONSchemaDefinition[] | undefined; not?: JSONSchemaDefinition | undefined; definitions?: - | { + | Readonly<{ [key: string]: JSONSchemaDefinition; - } + }> | undefined; title?: string | undefined; description?: string | undefined; - default?: JSONSchemaType | undefined; + default?: unknown | undefined; readOnly?: boolean | undefined; writeOnly?: boolean | undefined; - examples?: JSONSchemaType | undefined; -} + examples?: readonly unknown[] | undefined; +}>; From 7c2736e64145de56da7eefa6f9c061c2e5ae4979 Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Mon, 11 Nov 2024 10:54:43 +0100 Subject: [PATCH 38/56] refactor(api): remove json-schema-to-ts dependency --- apps/api/package.json | 1 - .../app/bridge/usecases/sync/sync.command.ts | 5 +- .../shared/build-string-schema.ts | 6 +-- .../shared/schemas/email-control.schema.ts | 5 +- .../shared/schemas/in-app-control.schema.ts | 9 ++-- .../get-step-schema/get-step-data.usecase.ts | 17 ++++--- .../usecases/test-data/test-data.usecase.ts | 11 +++-- .../src/components/workflow-editor/schema.ts | 12 +++-- .../parseStepVariablesToLiquidVariables.ts | 10 ++-- apps/dashboard/src/utils/schema.ts | 8 ++-- .../create-workflow.command.ts | 12 ++--- .../create-message-template.command.ts | 6 +-- .../update-message-template.command.ts | 8 ++-- .../update-workflow.command.ts | 6 +-- libs/dal/package.json | 1 - .../message-template.entity.ts | 6 +-- packages/shared/package.json | 3 -- .../src/dto/workflows/json-schema-dto.ts | 44 +++++++++--------- .../shared/src/dto/workflows/step-data.dto.ts | 6 +-- .../dto/workflows/workflow-commons-fields.ts | 4 +- .../workflow-test-data-response-dto.ts | 6 +-- .../message-template.interface.ts | 8 ++-- .../notification-template.interface.ts | 6 +-- pnpm-lock.yaml | 46 ++++++------------- 24 files changed, 108 insertions(+), 138 deletions(-) diff --git a/apps/api/package.json b/apps/api/package.json index f933fcdc655..d8e502b2b86 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -93,7 +93,6 @@ "shortid": "^2.2.16", "swagger-ui-express": "^4.4.0", "twilio": "^4.14.1","zod": "^3.23.8", - "json-schema-to-ts": "^3.0.0", "uuid": "^8.3.2" }, "devDependencies": { diff --git a/apps/api/src/app/bridge/usecases/sync/sync.command.ts b/apps/api/src/app/bridge/usecases/sync/sync.command.ts index d5e3b1c6a5c..de583f1b678 100644 --- a/apps/api/src/app/bridge/usecases/sync/sync.command.ts +++ b/apps/api/src/app/bridge/usecases/sync/sync.command.ts @@ -1,12 +1,11 @@ import { IsDefined, IsOptional, IsString, ValidateNested } from 'class-validator'; import { Type } from 'class-transformer'; -import { JsonSchema } from '@novu/framework/internal'; import { EnvironmentWithUserCommand, IStepControl } from '@novu/application-generic'; -import { StepType } from '@novu/shared'; +import type { JSONSchemaDto, StepType } from '@novu/shared'; interface IStepOutput { - schema: JsonSchema; + schema: JSONSchemaDto; } interface IWorkflowDefineStep { diff --git a/apps/api/src/app/workflows-v2/shared/build-string-schema.ts b/apps/api/src/app/workflows-v2/shared/build-string-schema.ts index 92d413018a0..b5947b75483 100644 --- a/apps/api/src/app/workflows-v2/shared/build-string-schema.ts +++ b/apps/api/src/app/workflows-v2/shared/build-string-schema.ts @@ -1,10 +1,10 @@ -import { JSONSchema } from 'json-schema-to-ts'; +import { JSONSchemaDto } from '@novu/shared'; /** * Builds a JSON schema object where each variable becomes a string property. */ -export function buildJSONSchema(variables: Record): JSONSchema { - const properties: Record = {}; +export function buildJSONSchema(variables: Record): JSONSchemaDto { + const properties: Record = {}; for (const [variableKey, variableValue] of Object.entries(variables)) { properties[variableKey] = { diff --git a/apps/api/src/app/workflows-v2/shared/schemas/email-control.schema.ts b/apps/api/src/app/workflows-v2/shared/schemas/email-control.schema.ts index 3d58a156baa..54e3d4af02a 100644 --- a/apps/api/src/app/workflows-v2/shared/schemas/email-control.schema.ts +++ b/apps/api/src/app/workflows-v2/shared/schemas/email-control.schema.ts @@ -1,7 +1,6 @@ -import { JSONSchema } from 'json-schema-to-ts'; -import { UiComponentEnum, UiSchema, UiSchemaGroupEnum } from '@novu/shared'; +import { JSONSchemaDto, UiComponentEnum, UiSchema, UiSchemaGroupEnum } from '@novu/shared'; -export const EmailStepControlSchema: JSONSchema = { +export const EmailStepControlSchema: JSONSchemaDto = { type: 'object', properties: { emailEditor: { diff --git a/apps/api/src/app/workflows-v2/shared/schemas/in-app-control.schema.ts b/apps/api/src/app/workflows-v2/shared/schemas/in-app-control.schema.ts index 587e9c41e86..ee177b15145 100644 --- a/apps/api/src/app/workflows-v2/shared/schemas/in-app-control.schema.ts +++ b/apps/api/src/app/workflows-v2/shared/schemas/in-app-control.schema.ts @@ -1,5 +1,4 @@ -import { JSONSchema } from 'json-schema-to-ts'; -import { UiComponentEnum, UiSchema, UiSchemaGroupEnum, UiSchemaProperty } from '@novu/shared'; +import { JSONSchemaDto, UiComponentEnum, UiSchema, UiSchemaGroupEnum, UiSchemaProperty } from '@novu/shared'; const ABSOLUTE_AND_RELATIVE_URL_REGEX = '^(?!mailto:)(?:(https?):\\/\\/[^\\s/$.?#].[^\\s]*)|^(\\/[^\\s]*)$'; @@ -18,7 +17,7 @@ const redirectSchema = { }, required: ['url'], // url remains required additionalProperties: false, // No additional properties allowed -} as const satisfies JSONSchema; +} as const satisfies JSONSchemaDto; const actionSchema = { type: 'object', @@ -28,7 +27,7 @@ const actionSchema = { }, required: ['label'], additionalProperties: false, -} as const satisfies JSONSchema; +} as const satisfies JSONSchemaDto; export const inAppControlSchema = { type: 'object', @@ -43,7 +42,7 @@ export const inAppControlSchema = { }, required: ['body'], additionalProperties: false, -} as const satisfies JSONSchema; +} as const satisfies JSONSchemaDto; const redirectPlaceholder = { url: { diff --git a/apps/api/src/app/workflows-v2/usecases/get-step-schema/get-step-data.usecase.ts b/apps/api/src/app/workflows-v2/usecases/get-step-schema/get-step-data.usecase.ts index 9d8b67bb501..3470e42dd9a 100644 --- a/apps/api/src/app/workflows-v2/usecases/get-step-schema/get-step-data.usecase.ts +++ b/apps/api/src/app/workflows-v2/usecases/get-step-schema/get-step-data.usecase.ts @@ -1,6 +1,5 @@ import { BadRequestException, Injectable } from '@nestjs/common'; -import { ControlValuesLevelEnum, StepDataDto } from '@novu/shared'; -import { JSONSchema } from 'json-schema-to-ts'; +import { ControlValuesLevelEnum, JSONSchemaDto, StepDataDto } from '@novu/shared'; import { ControlValuesRepository, NotificationStepEntity, NotificationTemplateEntity } from '@novu/dal'; import { GetStepDataCommand } from './get-step-data.command'; import { mapStepTypeToResult } from '../../shared'; @@ -119,12 +118,12 @@ const buildSubscriberSchema = () => }, required: ['firstName', 'lastName', 'email', 'subscriberId'], additionalProperties: false, - }) as const satisfies JSONSchema; + }) as const satisfies JSONSchemaDto; function buildVariablesSchema( previousSteps: NotificationStepEntity[] | undefined, - payloadSchema: JSONSchema -): JSONSchema { + payloadSchema: JSONSchemaDto +): JSONSchemaDto { return { type: 'object', properties: { @@ -133,12 +132,12 @@ function buildVariablesSchema( payload: payloadSchema, }, additionalProperties: false, - } as const satisfies JSONSchema; + } as const satisfies JSONSchemaDto; } function buildPreviousStepsSchema(previousSteps: NotificationStepEntity[] | undefined) { type StepExternalId = string; - let previousStepsProperties: Record = {}; + let previousStepsProperties: Record = {}; previousStepsProperties = (previousSteps || []).reduce( (acc, step) => { @@ -148,7 +147,7 @@ function buildPreviousStepsSchema(previousSteps: NotificationStepEntity[] | unde return acc; }, - {} as Record + {} as Record ); return { @@ -157,5 +156,5 @@ function buildPreviousStepsSchema(previousSteps: NotificationStepEntity[] | unde required: [], additionalProperties: false, description: 'Previous Steps Results', - } as const satisfies JSONSchema; + } as const satisfies JSONSchemaDto; } diff --git a/apps/api/src/app/workflows-v2/usecases/test-data/test-data.usecase.ts b/apps/api/src/app/workflows-v2/usecases/test-data/test-data.usecase.ts index b27bc27a002..2d873c40989 100644 --- a/apps/api/src/app/workflows-v2/usecases/test-data/test-data.usecase.ts +++ b/apps/api/src/app/workflows-v2/usecases/test-data/test-data.usecase.ts @@ -1,7 +1,12 @@ -import { JSONSchema } from 'json-schema-to-ts'; import { Injectable } from '@nestjs/common'; import { ControlValuesRepository, NotificationStepEntity, NotificationTemplateEntity } from '@novu/dal'; -import { ControlValuesLevelEnum, StepTypeEnum, UserSessionData, WorkflowTestDataResponseDto } from '@novu/shared'; +import { + ControlValuesLevelEnum, + JSONSchemaDto, + StepTypeEnum, + UserSessionData, + WorkflowTestDataResponseDto, +} from '@novu/shared'; import { WorkflowTestDataCommand } from './test-data.command'; import { GetWorkflowByIdsUseCase } from '../get-workflow-by-ids/get-workflow-by-ids.usecase'; @@ -81,7 +86,7 @@ const buildToFieldSchema = ({ user, steps }: { user: UserSessionData; steps: Not }, required: ['subscriberId', ...(isEmailExist ? ['email'] : []), ...(isSmsExist ? ['phone'] : [])], additionalProperties: false, - } as const satisfies JSONSchema; + } as const satisfies JSONSchemaDto; }; function isContainsStepType(steps: NotificationStepEntity[], type: StepTypeEnum) { diff --git a/apps/dashboard/src/components/workflow-editor/schema.ts b/apps/dashboard/src/components/workflow-editor/schema.ts index 0c78ace3da1..295065dafb9 100644 --- a/apps/dashboard/src/components/workflow-editor/schema.ts +++ b/apps/dashboard/src/components/workflow-editor/schema.ts @@ -1,5 +1,5 @@ import * as z from 'zod'; -import type { StepResponseDto, WorkflowTestDataResponseDto } from '@novu/shared'; +import type { JSONSchemaDefinition, StepResponseDto } from '@novu/shared'; import { StepTypeEnum } from '@/utils/enums'; import { capitalize } from '@/utils/string'; @@ -49,12 +49,10 @@ export const workflowSchema = z.object({ }), }); -export type JSONSchema = WorkflowTestDataResponseDto['to']; - export const buildDynamicFormSchema = ({ to, }: { - to: JSONSchema; + to: JSONSchemaDefinition; }): z.ZodObject<{ to: z.ZodObject>; payload: z.ZodEffects; @@ -103,7 +101,11 @@ export const buildDynamicFormSchema = ({ export type TestWorkflowFormType = z.infer>; -export const makeObjectFromSchema = ({ properties }: { properties: Readonly> }) => { +export const makeObjectFromSchema = ({ + properties, +}: { + properties: Readonly>; +}) => { return Object.keys(properties).reduce((acc, key) => { const value = properties[key]; if (typeof value !== 'object') { diff --git a/apps/dashboard/src/utils/parseStepVariablesToLiquidVariables.ts b/apps/dashboard/src/utils/parseStepVariablesToLiquidVariables.ts index a52b0cc67cc..42f183872b2 100644 --- a/apps/dashboard/src/utils/parseStepVariablesToLiquidVariables.ts +++ b/apps/dashboard/src/utils/parseStepVariablesToLiquidVariables.ts @@ -1,4 +1,4 @@ -import { StepDataDto } from '@novu/shared'; +import type { JSONSchemaDefinition } from '@novu/shared'; interface LiquidVariable { type: 'variable'; @@ -6,17 +6,15 @@ interface LiquidVariable { detail: string; } -type JSONSchema = StepDataDto['variables']; - /** * Parse JSON Schema and extract variables for Liquid autocompletion. * @param schema - The JSON Schema to parse. * @returns An array of variable objects suitable for the Liquid language. */ -export function parseStepVariablesToLiquidVariables(schema: JSONSchema): LiquidVariable[] { +export function parseStepVariablesToLiquidVariables(schema: JSONSchemaDefinition): LiquidVariable[] { const variables: LiquidVariable[] = []; - function extractProperties(obj: JSONSchema, path = ''): void { + function extractProperties(obj: JSONSchemaDefinition, path = ''): void { if (typeof obj === 'boolean') return; // Handle boolean schema if (obj.type === 'object' && obj.properties) { @@ -44,7 +42,7 @@ export function parseStepVariablesToLiquidVariables(schema: JSONSchema): LiquidV // Handle combinators (allOf, anyOf, oneOf) ['allOf', 'anyOf', 'oneOf'].forEach((combiner) => { if (Array.isArray(obj[combiner as keyof typeof obj])) { - for (const subSchema of obj[combiner as keyof typeof obj] as JSONSchema[]) { + for (const subSchema of obj[combiner as keyof typeof obj] as JSONSchemaDefinition[]) { extractProperties(subSchema, path); } } diff --git a/apps/dashboard/src/utils/schema.ts b/apps/dashboard/src/utils/schema.ts index ea32ad1b2a4..082867add55 100644 --- a/apps/dashboard/src/utils/schema.ts +++ b/apps/dashboard/src/utils/schema.ts @@ -1,9 +1,7 @@ import * as z from 'zod'; -import { UiSchema, WorkflowTestDataResponseDto } from '@novu/shared'; +import { JSONSchemaDto, UiSchema } from '@novu/shared'; import { capitalize } from './string'; -type JSONSchema = WorkflowTestDataResponseDto['to']; - type ZodValue = | z.AnyZodObject | z.ZodString @@ -97,7 +95,7 @@ const handleStringType = ({ * The function will recursively build the schema based on the JSONSchema object. * It removes empty strings and objects with empty required fields during the transformation phase after parsing. */ -export const buildDynamicZodSchema = (obj: JSONSchema): z.AnyZodObject => { +export const buildDynamicZodSchema = (obj: JSONSchemaDto): z.AnyZodObject => { const properties = typeof obj === 'object' ? (obj.properties ?? {}) : {}; const requiredFields = typeof obj === 'object' ? (obj.required ?? []) : []; @@ -114,7 +112,7 @@ export const buildDynamicZodSchema = (obj: JSONSchema): z.AnyZodObject => { if (type === 'object') { zodValue = buildDynamicZodSchema(jsonSchemaProp); if (defaultValue) { - zodValue = zodValue.default(defaultValue); + zodValue = zodValue.default(defaultValue as object); } zodValue = zodValue.transform((val) => { const hasAnyRequiredEmpty = required?.some((field) => val[field] === '' || val[field] === undefined); diff --git a/libs/application-generic/src/usecases/create-workflow/create-workflow.command.ts b/libs/application-generic/src/usecases/create-workflow/create-workflow.command.ts index 27003ada6e3..04627d85fb1 100644 --- a/libs/application-generic/src/usecases/create-workflow/create-workflow.command.ts +++ b/libs/application-generic/src/usecases/create-workflow/create-workflow.command.ts @@ -18,12 +18,12 @@ import { INotificationGroup, IPreferenceChannels, IWorkflowStepMetadata, + JSONSchemaDto, NotificationTemplateCustomData, WorkflowOriginEnum, WorkflowTypeEnum, } from '@novu/shared'; -import { JsonSchema } from '@novu/framework/internal'; import { EnvironmentWithUserCommand } from '../../commands'; export class CreateWorkflowCommand extends EnvironmentWithUserCommand { @@ -76,18 +76,18 @@ export class CreateWorkflowCommand extends EnvironmentWithUserCommand { @IsOptional() inputs?: { - schema: JsonSchema; + schema: JSONSchemaDto; }; @IsOptional() controls?: { - schema: JsonSchema; + schema: JSONSchemaDto; }; @IsOptional() rawData?: Record; @IsOptional() - payloadSchema?: JsonSchema; + payloadSchema?: JSONSchemaDto; @IsEnum(WorkflowTypeEnum) @IsDefined() @@ -163,12 +163,12 @@ export class NotificationStepVariantCommand { @IsOptional() controls?: { - schema: JsonSchema; + schema: JSONSchemaDto; }; @IsOptional() output?: { - schema: JsonSchema; + schema: JSONSchemaDto; }; @IsOptional() diff --git a/libs/application-generic/src/usecases/message-template/create-message-template/create-message-template.command.ts b/libs/application-generic/src/usecases/message-template/create-message-template/create-message-template.command.ts index 39c9996993f..f97e38cdebd 100644 --- a/libs/application-generic/src/usecases/message-template/create-message-template/create-message-template.command.ts +++ b/libs/application-generic/src/usecases/message-template/create-message-template/create-message-template.command.ts @@ -15,9 +15,9 @@ import { IActor, MessageTemplateContentType, WorkflowTypeEnum, + JSONSchemaDto, } from '@novu/shared'; -import { JsonSchema } from '@novu/framework/internal'; import { EnvironmentWithUserCommand } from '../../../commands'; export class CreateMessageTemplateCommand extends EnvironmentWithUserCommand { @@ -74,12 +74,12 @@ export class CreateMessageTemplateCommand extends EnvironmentWithUserCommand { @IsOptional() controls?: { - schema: JsonSchema; + schema: JSONSchemaDto; }; @IsOptional() output?: { - schema: JsonSchema; + schema: JSONSchemaDto; }; @IsOptional() diff --git a/libs/application-generic/src/usecases/message-template/update-message-template/update-message-template.command.ts b/libs/application-generic/src/usecases/message-template/update-message-template/update-message-template.command.ts index 7c4b9b70d01..b53c7f1e9a9 100644 --- a/libs/application-generic/src/usecases/message-template/update-message-template/update-message-template.command.ts +++ b/libs/application-generic/src/usecases/message-template/update-message-template/update-message-template.command.ts @@ -14,8 +14,8 @@ import { IActor, MessageTemplateContentType, WorkflowTypeEnum, + JSONSchemaDto, } from '@novu/shared'; -import { JsonSchema } from '@novu/framework/internal'; import { EnvironmentWithUserCommand } from '../../../commands'; export class UpdateMessageTemplateCommand extends EnvironmentWithUserCommand { @@ -75,16 +75,16 @@ export class UpdateMessageTemplateCommand extends EnvironmentWithUserCommand { @IsOptional() inputs?: { - schema: JsonSchema; + schema: JSONSchemaDto; }; @IsOptional() controls?: { - schema: JsonSchema; + schema: JSONSchemaDto; }; @IsOptional() output?: { - schema: JsonSchema; + schema: JSONSchemaDto; }; @IsOptional() diff --git a/libs/application-generic/src/usecases/workflow/update-workflow/update-workflow.command.ts b/libs/application-generic/src/usecases/workflow/update-workflow/update-workflow.command.ts index 12e743088d3..89fdc09c1c9 100644 --- a/libs/application-generic/src/usecases/workflow/update-workflow/update-workflow.command.ts +++ b/libs/application-generic/src/usecases/workflow/update-workflow/update-workflow.command.ts @@ -11,11 +11,11 @@ import { import { IPreferenceChannels, + JSONSchemaDto, NotificationTemplateCustomData, WorkflowTypeEnum, } from '@novu/shared'; -import { JsonSchema } from '@novu/framework/internal'; import { EnvironmentWithUserCommand } from '../../../commands'; import { NotificationStep } from '../..'; @@ -82,7 +82,7 @@ export class UpdateWorkflowCommand extends EnvironmentWithUserCommand { rawData?: any; @IsOptional() - payloadSchema?: JsonSchema; + payloadSchema?: JSONSchemaDto; @IsEnum(WorkflowTypeEnum) @IsDefined() @@ -90,5 +90,5 @@ export class UpdateWorkflowCommand extends EnvironmentWithUserCommand { } export interface IStepControl { - schema: JsonSchema; + schema: JSONSchemaDto; } diff --git a/libs/dal/package.json b/libs/dal/package.json index daaa314a401..56118e8a18e 100644 --- a/libs/dal/package.json +++ b/libs/dal/package.json @@ -46,7 +46,6 @@ "@types/node": "^20.15.0", "@typescript-eslint/parser": "^4.14.2", "apollo-boost": "0.4.9", - "json-schema-to-ts": "^3.0.0", "ts-node": "~10.9.1", "tsconfig-paths": "~4.1.0", "typescript": "5.6.2", diff --git a/libs/dal/src/repositories/message-template/message-template.entity.ts b/libs/dal/src/repositories/message-template/message-template.entity.ts index aa86e8139a0..9217eb9b5de 100644 --- a/libs/dal/src/repositories/message-template/message-template.entity.ts +++ b/libs/dal/src/repositories/message-template/message-template.entity.ts @@ -1,14 +1,14 @@ -import { +import type { ControlSchemas, EnvironmentId, IActor, IMessageCTA, IMessageTemplate, + JSONSchemaDto, MessageTemplateContentType, OrganizationId, StepTypeEnum, } from '@novu/shared'; -import { JSONSchema } from 'json-schema-to-ts'; import { IEmailBlock, ITemplateVariable } from './types'; import type { ChangePropsValueType } from '../../types/helpers'; @@ -60,7 +60,7 @@ export class MessageTemplateEntity implements IMessageTemplate { controls?: ControlSchemas; output?: { - schema: JSONSchema; + schema: JSONSchemaDto; }; code?: string; diff --git a/packages/shared/package.json b/packages/shared/package.json index 5dde98dc13a..0846c48f156 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -38,9 +38,6 @@ } }, "devDependencies": { - "@types/bluebird": "^3.5.24", - "@types/jest": "29.5.2", - "json-schema-to-ts": "^3.0.0", "rimraf": "^3.0.2", "typescript": "5.6.2", "vitest": "^2.0.5" diff --git a/packages/shared/src/dto/workflows/json-schema-dto.ts b/packages/shared/src/dto/workflows/json-schema-dto.ts index b92311149f7..0f0bdd06910 100644 --- a/packages/shared/src/dto/workflows/json-schema-dto.ts +++ b/packages/shared/src/dto/workflows/json-schema-dto.ts @@ -14,11 +14,10 @@ export type JSONSchemaVersion = string; export type JSONSchemaDefinition = JSONSchemaDto | boolean; -// eslint-disable-next-line @typescript-eslint/naming-convention -export interface JSONSchemaDto { - type?: JSONSchemaTypeName | JSONSchemaTypeName[] | undefined; - enum?: JSONSchemaType[] | undefined; - const?: JSONSchemaType | undefined; +export type JSONSchemaDto = Readonly<{ + type?: JSONSchemaTypeName | readonly JSONSchemaTypeName[] | undefined; + enum?: unknown | undefined; + const?: unknown | undefined; multipleOf?: number | undefined; maximum?: number | undefined; exclusiveMaximum?: number | undefined; @@ -26,8 +25,9 @@ export interface JSONSchemaDto { exclusiveMinimum?: number | undefined; maxLength?: number | undefined; minLength?: number | undefined; + format?: string | undefined; pattern?: string | undefined; - items?: JSONSchemaDefinition | JSONSchemaDefinition[] | undefined; + items?: JSONSchemaDefinition | readonly JSONSchemaDefinition[] | undefined; additionalItems?: JSONSchemaDefinition | undefined; maxItems?: number | undefined; minItems?: number | undefined; @@ -35,40 +35,40 @@ export interface JSONSchemaDto { contains?: JSONSchemaDefinition | undefined; maxProperties?: number | undefined; minProperties?: number | undefined; - required?: string[] | undefined; + required?: readonly string[] | undefined; properties?: - | { + | Readonly<{ [key: string]: JSONSchemaDefinition; - } + }> | undefined; patternProperties?: - | { + | Readonly<{ [key: string]: JSONSchemaDefinition; - } + }> | undefined; additionalProperties?: JSONSchemaDefinition | undefined; dependencies?: - | { - [key: string]: JSONSchemaDefinition | string[]; - } + | Readonly<{ + [key: string]: JSONSchemaDefinition | readonly string[]; + }> | undefined; propertyNames?: JSONSchemaDefinition | undefined; if?: JSONSchemaDefinition | undefined; then?: JSONSchemaDefinition | undefined; else?: JSONSchemaDefinition | undefined; - allOf?: JSONSchemaDefinition[] | undefined; - anyOf?: JSONSchemaDefinition[] | undefined; - oneOf?: JSONSchemaDefinition[] | undefined; + allOf?: readonly JSONSchemaDefinition[] | undefined; + anyOf?: readonly JSONSchemaDefinition[] | undefined; + oneOf?: readonly JSONSchemaDefinition[] | undefined; not?: JSONSchemaDefinition | undefined; definitions?: - | { + | Readonly<{ [key: string]: JSONSchemaDefinition; - } + }> | undefined; title?: string | undefined; description?: string | undefined; - default?: JSONSchemaType | undefined; + default?: unknown | undefined; readOnly?: boolean | undefined; writeOnly?: boolean | undefined; - examples?: JSONSchemaType | undefined; -} + examples?: readonly unknown[] | undefined; +}>; diff --git a/packages/shared/src/dto/workflows/step-data.dto.ts b/packages/shared/src/dto/workflows/step-data.dto.ts index 73db886681d..a5c1e31a138 100644 --- a/packages/shared/src/dto/workflows/step-data.dto.ts +++ b/packages/shared/src/dto/workflows/step-data.dto.ts @@ -1,8 +1,8 @@ -import type { JSONSchema } from 'json-schema-to-ts'; +import type { JSONSchemaDto } from './json-schema-dto'; export type StepDataDto = { controls: ControlsMetadata; - variables: JSONSchema; + variables: JSONSchemaDto; stepId: string; _id: string; name: string; @@ -35,7 +35,7 @@ export class UiSchema { } export class ControlsMetadata { - dataSchema?: JSONSchema; + dataSchema?: JSONSchemaDto; uiSchema?: UiSchema; values: Record; } diff --git a/packages/shared/src/dto/workflows/workflow-commons-fields.ts b/packages/shared/src/dto/workflows/workflow-commons-fields.ts index 9f410eaa94d..cfc48d10519 100644 --- a/packages/shared/src/dto/workflows/workflow-commons-fields.ts +++ b/packages/shared/src/dto/workflows/workflow-commons-fields.ts @@ -1,10 +1,10 @@ -import type { JSONSchema } from 'json-schema-to-ts'; +import type { JSONSchemaDto } from './json-schema-dto'; import { WorkflowResponseDto } from './workflow-response-dto'; import { Slug, StepTypeEnum, WorkflowPreferences } from '../../types'; import { StepContentIssueEnum, StepIssueEnum } from './step-content-issue.enum'; export class ControlsSchema { - schema: JSONSchema; + schema: JSONSchemaDto; } export type StepCreateAndUpdateKeys = keyof StepCreateDto | keyof StepUpdateDto; diff --git a/packages/shared/src/dto/workflows/workflow-test-data-response-dto.ts b/packages/shared/src/dto/workflows/workflow-test-data-response-dto.ts index 016465501cf..7de54c13316 100644 --- a/packages/shared/src/dto/workflows/workflow-test-data-response-dto.ts +++ b/packages/shared/src/dto/workflows/workflow-test-data-response-dto.ts @@ -1,6 +1,6 @@ -import type { JSONSchema } from 'json-schema-to-ts'; +import type { JSONSchemaDto } from './json-schema-dto'; export type WorkflowTestDataResponseDto = { - to: JSONSchema; - payload: JSONSchema; + to: JSONSchemaDto; + payload: JSONSchemaDto; }; diff --git a/packages/shared/src/entities/message-template/message-template.interface.ts b/packages/shared/src/entities/message-template/message-template.interface.ts index e5052751beb..8b8c412982a 100644 --- a/packages/shared/src/entities/message-template/message-template.interface.ts +++ b/packages/shared/src/entities/message-template/message-template.interface.ts @@ -1,5 +1,3 @@ -import type { JSONSchema } from 'json-schema-to-ts'; - import { ChannelCTATypeEnum, EnvironmentId, @@ -11,7 +9,7 @@ import { } from '../../types'; import { TriggerContextTypeEnum } from '../notification-template'; import { IActor } from '../messages'; -import { UiSchema } from '../../dto'; +import type { JSONSchemaDto, UiSchema } from '../../dto'; export type MessageTemplateContentType = 'editor' | 'customHtml'; @@ -45,14 +43,14 @@ export interface IMessageTemplate { actor?: IActor; controls?: ControlSchemas; output?: { - schema: JSONSchema; + schema: JSONSchemaDto; }; code?: string; createdAt?: string; updatedAt?: string; } export class ControlSchemas { - schema: JSONSchema; + schema: JSONSchemaDto; uiSchema?: UiSchema; } export const TemplateSystemVariables = ['subscriber', 'step', 'branding', 'tenant', 'preheader', 'actor']; diff --git a/packages/shared/src/entities/notification-template/notification-template.interface.ts b/packages/shared/src/entities/notification-template/notification-template.interface.ts index a2c55a093e1..6b74dc24f36 100644 --- a/packages/shared/src/entities/notification-template/notification-template.interface.ts +++ b/packages/shared/src/entities/notification-template/notification-template.interface.ts @@ -1,5 +1,3 @@ -import type { JSONSchema } from 'json-schema-to-ts'; - import type { BuilderFieldType, BuilderGroupValues, @@ -12,7 +10,7 @@ import { ControlSchemas, IMessageTemplate } from '../message-template'; import { IPreferenceChannels } from '../subscriber-preference'; import { IWorkflowStepMetadata } from '../step'; import { INotificationGroup } from '../notification-group'; -import { ContentIssue, ControlsDto, StepIssue } from '../../index'; +import type { ContentIssue, ControlsDto, JSONSchemaDto, StepIssue } from '../../index'; export interface INotificationTemplate { _id?: string; @@ -104,7 +102,7 @@ export interface IStepVariant { }; metadata?: IWorkflowStepMetadata; inputs?: { - schema: JSONSchema; + schema: JSONSchemaDto; }; /** * @deprecated This property is deprecated and will be removed in future versions. diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6e86d13a110..3cc312692d5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -480,9 +480,6 @@ importers: ioredis: specifier: 5.3.2 version: 5.3.2 - json-schema-to-ts: - specifier: ^3.0.0 - version: 3.1.0 jsonwebtoken: specifier: 9.0.0 version: 9.0.0 @@ -2875,9 +2872,6 @@ importers: apollo-boost: specifier: 0.4.9 version: 0.4.9(graphql@16.9.0) - json-schema-to-ts: - specifier: ^3.0.0 - version: 3.1.0 rimraf: specifier: ^3.0.2 version: 3.0.2 @@ -4358,15 +4352,6 @@ importers: packages/shared: devDependencies: - '@types/bluebird': - specifier: ^3.5.24 - version: 3.5.38 - '@types/jest': - specifier: 29.5.2 - version: 29.5.2 - json-schema-to-ts: - specifier: ^3.0.0 - version: 3.1.0 rimraf: specifier: ^3.0.2 version: 3.0.2 @@ -16526,9 +16511,6 @@ packages: '@types/bcryptjs@2.4.6': resolution: {integrity: sha512-9xlo6R2qDs5uixm0bcIqCeMCE6HiQsIyel9KQySStiyqNl2tnj2mP3DX1Nf56MD6KMenNNlBBsy3LJ7gUEQPXQ==} - '@types/bluebird@3.5.38': - resolution: {integrity: sha512-yR/Kxc0dd4FfwtEoLZMoqJbM/VE/W7hXn/MIjb+axcwag0iFmSPK7OBUZq1YWLynJUoWQkfUrI7T0HDqGApNSg==} - '@types/body-parser@1.19.2': resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==} @@ -35289,8 +35271,8 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.575.0(@aws-sdk/client-sts@3.575.0) - '@aws-sdk/client-sts': 3.575.0 + '@aws-sdk/client-sso-oidc': 3.575.0 + '@aws-sdk/client-sts': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) '@aws-sdk/core': 3.575.0 '@aws-sdk/credential-provider-node': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0) '@aws-sdk/middleware-host-header': 3.575.0 @@ -35491,8 +35473,8 @@ snapshots: '@aws-crypto/sha1-browser': 3.0.0 '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.575.0(@aws-sdk/client-sts@3.575.0) - '@aws-sdk/client-sts': 3.575.0 + '@aws-sdk/client-sso-oidc': 3.575.0 + '@aws-sdk/client-sts': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) '@aws-sdk/core': 3.575.0 '@aws-sdk/credential-provider-node': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0) '@aws-sdk/middleware-bucket-endpoint': 3.575.0 @@ -35718,11 +35700,11 @@ snapshots: - aws-crt optional: true - '@aws-sdk/client-sso-oidc@3.575.0(@aws-sdk/client-sts@3.575.0)': + '@aws-sdk/client-sso-oidc@3.575.0': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.575.0 + '@aws-sdk/client-sts': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) '@aws-sdk/core': 3.575.0 '@aws-sdk/credential-provider-node': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0) '@aws-sdk/middleware-host-header': 3.575.0 @@ -35761,7 +35743,6 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.7.0 transitivePeerDependencies: - - '@aws-sdk/client-sts' - aws-crt '@aws-sdk/client-sso-oidc@3.637.0(@aws-sdk/client-sts@3.637.0)': @@ -36146,11 +36127,11 @@ snapshots: - aws-crt optional: true - '@aws-sdk/client-sts@3.575.0': + '@aws-sdk/client-sts@3.575.0(@aws-sdk/client-sso-oidc@3.575.0)': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.575.0(@aws-sdk/client-sts@3.575.0) + '@aws-sdk/client-sso-oidc': 3.575.0 '@aws-sdk/core': 3.575.0 '@aws-sdk/credential-provider-node': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0) '@aws-sdk/middleware-host-header': 3.575.0 @@ -36189,6 +36170,7 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.7.0 transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' - aws-crt '@aws-sdk/client-sts@3.637.0': @@ -36418,7 +36400,7 @@ snapshots: '@aws-sdk/credential-provider-ini@3.575.0(@aws-sdk/client-sso-oidc@3.575.0)(@aws-sdk/client-sts@3.575.0)': dependencies: - '@aws-sdk/client-sts': 3.575.0 + '@aws-sdk/client-sts': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) '@aws-sdk/credential-provider-env': 3.575.0 '@aws-sdk/credential-provider-process': 3.575.0 '@aws-sdk/credential-provider-sso': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) @@ -36729,7 +36711,7 @@ snapshots: '@aws-sdk/credential-provider-web-identity@3.575.0(@aws-sdk/client-sts@3.575.0)': dependencies: - '@aws-sdk/client-sts': 3.575.0 + '@aws-sdk/client-sts': 3.575.0(@aws-sdk/client-sso-oidc@3.575.0) '@aws-sdk/types': 3.575.0 '@smithy/property-provider': 3.1.3 '@smithy/types': 3.3.0 @@ -37250,7 +37232,7 @@ snapshots: '@aws-sdk/token-providers@3.575.0(@aws-sdk/client-sso-oidc@3.575.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.575.0(@aws-sdk/client-sts@3.575.0) + '@aws-sdk/client-sso-oidc': 3.575.0 '@aws-sdk/types': 3.575.0 '@smithy/property-provider': 3.1.3 '@smithy/shared-ini-file-loader': 3.1.4 @@ -37259,7 +37241,7 @@ snapshots: '@aws-sdk/token-providers@3.614.0(@aws-sdk/client-sso-oidc@3.575.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.575.0(@aws-sdk/client-sts@3.575.0) + '@aws-sdk/client-sso-oidc': 3.575.0 '@aws-sdk/types': 3.609.0 '@smithy/property-provider': 3.1.3 '@smithy/shared-ini-file-loader': 3.1.4 @@ -56700,8 +56682,6 @@ snapshots: '@types/bcryptjs@2.4.6': {} - '@types/bluebird@3.5.38': {} - '@types/body-parser@1.19.2': dependencies: '@types/connect': 3.4.36 From 0fb4a20778203af427002a234fd9e3d884aec7f6 Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Mon, 11 Nov 2024 11:56:29 +0100 Subject: [PATCH 39/56] refactor(types): refactor JSON schema type definitions --- packages/framework/src/types/schema.types.ts | 2 +- .../src/dto/workflows/json-schema-dto.ts | 28 ++++++++++++++----- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/packages/framework/src/types/schema.types.ts b/packages/framework/src/types/schema.types.ts index 2aa817aa8a0..b7884be33d4 100644 --- a/packages/framework/src/types/schema.types.ts +++ b/packages/framework/src/types/schema.types.ts @@ -1,7 +1,7 @@ import type { JSONSchema, FromSchema as JsonSchemaInfer } from 'json-schema-to-ts'; import zod from 'zod'; -export type JsonSchema = JSONSchema; +export type JsonSchema = Exclude; /** * A schema used to validate a JSON object. diff --git a/packages/shared/src/dto/workflows/json-schema-dto.ts b/packages/shared/src/dto/workflows/json-schema-dto.ts index 0f0bdd06910..eac2e7f5166 100644 --- a/packages/shared/src/dto/workflows/json-schema-dto.ts +++ b/packages/shared/src/dto/workflows/json-schema-dto.ts @@ -1,19 +1,33 @@ +/** + * The primitive types for JSON Schema. + */ export type JSONSchemaTypeName = 'string' | 'number' | 'integer' | 'boolean' | 'object' | 'array' | 'null'; +/** + * All possible types for JSON Schema. + */ export type JSONSchemaType = string | number | boolean | JSONSchemaObject | JSONSchemaArray | null; -// eslint-disable-next-line @typescript-eslint/naming-convention -export interface JSONSchemaObject { +/** + * The object type for JSON Schema. + */ +export type JSONSchemaObject = { [key: string]: JSONSchemaType; -} +}; -// eslint-disable-next-line @typescript-eslint/naming-convention -export interface JSONSchemaArray extends Array {} - -export type JSONSchemaVersion = string; +/** + * The array type for JSON Schema. + */ +export type JSONSchemaArray = Array; +/** + * The definition type for JSON Schema. + */ export type JSONSchemaDefinition = JSONSchemaDto | boolean; +/** + * Json schema version 7. + */ export type JSONSchemaDto = Readonly<{ type?: JSONSchemaTypeName | readonly JSONSchemaTypeName[] | undefined; enum?: unknown | undefined; From c1bf7ff46acd96573414569785617c67ef6cb6b4 Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Mon, 11 Nov 2024 12:40:50 +0100 Subject: [PATCH 40/56] chore: add 'combinators' to cspell.json dictionary --- .cspell.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.cspell.json b/.cspell.json index a0d2d8f211f..673be22b4f9 100644 --- a/.cspell.json +++ b/.cspell.json @@ -103,6 +103,7 @@ "codesee", "codestream", "coep", + "combinators", "commitlint", "compatbility", "cond", From d7ed75fe29f285c0a77edbf1d0689c151f0608e5 Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Tue, 12 Nov 2024 15:12:21 +0100 Subject: [PATCH 41/56] Update packages/framework/src/resources/workflow/discover-custom-step-factory.ts --- .../src/resources/workflow/discover-custom-step-factory.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/framework/src/resources/workflow/discover-custom-step-factory.ts b/packages/framework/src/resources/workflow/discover-custom-step-factory.ts index 7327fa67b48..963d0d37a55 100644 --- a/packages/framework/src/resources/workflow/discover-custom-step-factory.ts +++ b/packages/framework/src/resources/workflow/discover-custom-step-factory.ts @@ -6,7 +6,6 @@ import type { StepType, StepOutput, StepOptions, - FromSchema, Schema, } from '../../types'; import { transformSchema } from '../../validators'; From 229b530c06c28a122b4399c09109efd329148d7f Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Tue, 12 Nov 2024 15:12:51 +0100 Subject: [PATCH 42/56] Update packages/framework/src/types/schema.types/base.schema.types.ts --- packages/framework/src/types/schema.types/base.schema.types.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/framework/src/types/schema.types/base.schema.types.ts b/packages/framework/src/types/schema.types/base.schema.types.ts index 41eb7f833b6..c5e3dbc8605 100644 --- a/packages/framework/src/types/schema.types/base.schema.types.ts +++ b/packages/framework/src/types/schema.types/base.schema.types.ts @@ -15,7 +15,6 @@ export type Schema = JsonSchemaMinimal | ZodSchemaMinimal | ClassValidatorSchema */ type InferSchema = | InferJsonSchema - | InferZodSchema | InferClassValidatorSchema | InferZodSchema; From 41d8ff3e76c2ffb60efb33789f82075462ceaa59 Mon Sep 17 00:00:00 2001 From: paulwer Date: Tue, 12 Nov 2024 17:20:24 +0100 Subject: [PATCH 43/56] feat: add enum tests --- .../src/validators/validator.test.ts | 92 ++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-) diff --git a/packages/framework/src/validators/validator.test.ts b/packages/framework/src/validators/validator.test.ts index 95fd6bce491..a31869bbd3e 100644 --- a/packages/framework/src/validators/validator.test.ts +++ b/packages/framework/src/validators/validator.test.ts @@ -1,6 +1,6 @@ import { describe, it, expect } from 'vitest'; import { ZodSchema, z } from 'zod'; -import { IsNumber, IsOptional, IsString, ValidateNested } from 'class-validator'; +import { IsEnum, IsNumber, IsOptional, IsString, ValidateNested } from 'class-validator'; import { Type } from 'class-transformer'; import { validateData, transformSchema } from './base.validator'; import { ClassType, JsonSchema, Schema } from '../types/schema.types'; @@ -9,6 +9,11 @@ import 'reflect-metadata'; const schemas = ['zod', 'class', 'json'] as const; // Definitions of class-validator schemas +enum EnumSchema { + A = 'A', + B = 'B', + C = 'C', +} class SimpleStringSchema { @IsString() @IsOptional() @@ -32,6 +37,11 @@ class SimpleStringAndNumberSchema { @IsNumber() age!: number; } +class SimpleEnumSchema { + @IsString() + @IsEnum(EnumSchema) + enum?: EnumSchema; +} describe('validators', () => { describe('validateData', () => { @@ -352,6 +362,59 @@ describe('validators', () => { }, }, }, + { + title: 'should successfully validate enum property', + schemas: { + zod: z.object({ enum: z.enum(['A', 'B', 'C']) }), + class: SimpleEnumSchema, + json: { + type: 'object', + properties: { + enum: { + type: 'string', + enum: ['A', 'B', 'C'], + }, + }, + required: ['enum'], + } as const, + }, + payload: { enum: 'A' }, + result: { + success: true, + data: { enum: 'A' }, + }, + }, + { + title: 'should return errors for invalid enum property', + schemas: { + zod: z.object({ enum: z.enum(['A', 'B', 'C']) }), + class: SimpleEnumSchema, + json: { + type: 'object', + properties: { + enum: { + type: 'string', + enum: ['A', 'B', 'C'], + }, + }, + required: ['enum'], + } as const, + }, + payload: { enum: 'Z' }, + result: { + success: false, + errors: { + zod: [{ message: "Invalid enum value. Expected 'A' | 'B' | 'C', received 'Z'", path: '/enum' }], + class: [{ message: 'enum must be one of the following values: A, B, C', path: '/enum' }], + json: [ + { + message: 'must be equal to one of the allowed values', + path: '/enum', + }, + ], + }, + }, + }, ]; schemas.forEach((schema) => { @@ -565,6 +628,33 @@ describe('validators', () => { required: ['elements'], }, }, + { + title: 'should transform a enum schema', + schemas: { + zod: z.object({ enum: z.enum(['A', 'B', 'C']) }), + class: SimpleEnumSchema, // ClassValidator has no support for `anyOf` + json: { + type: 'object', + properties: { + enum: { + type: 'string', + enum: ['A', 'B', 'C'], + }, + }, + required: ['enum'], + } as const, + }, + result: { + type: 'object', + properties: { + enum: { + type: 'string', + enum: ['A', 'B', 'C'], + }, + }, + required: ['enum'], + }, + }, ]; schemas.forEach((schema) => { From f146791d42b1a43d45c06221eea08cd23530a41b Mon Sep 17 00:00:00 2001 From: paulwer Date: Tue, 12 Nov 2024 17:32:50 +0100 Subject: [PATCH 44/56] feat: support nested array structures --- .../validators/class-validator.validator.ts | 26 ++-- .../src/validators/validator.test.ts | 121 ++++++++++++++++++ 2 files changed, 138 insertions(+), 9 deletions(-) diff --git a/packages/framework/src/validators/class-validator.validator.ts b/packages/framework/src/validators/class-validator.validator.ts index 19c85a49208..ec5c53c2e9a 100644 --- a/packages/framework/src/validators/class-validator.validator.ts +++ b/packages/framework/src/validators/class-validator.validator.ts @@ -23,17 +23,25 @@ function replaceSchemaRefs(schema: any, schemas: any): JsonSchema { // Function to recursively add `additionalProperties: false` to the schema // eslint-disable-next-line @typescript-eslint/no-explicit-any function addAdditionalPropertiesFalse(schema: any): JsonSchema { - if (schema && typeof schema === 'object' && schema?.type === 'object') { - // eslint-disable-next-line no-param-reassign - schema.additionalProperties = false; - } + if (schema && typeof schema === 'object') { + if (schema.type === 'object') { + // eslint-disable-next-line no-param-reassign + schema.additionalProperties = false; + } - if (schema.properties) { - for (const key in schema.properties) { - if (schema.properties.hasOwnProperty(key)) { - addAdditionalPropertiesFalse(schema.properties[key]); + // If schema has properties, recursively apply the function to each property + if (schema.properties) { + for (const key in schema.properties) { + if (schema.properties.hasOwnProperty(key)) { + addAdditionalPropertiesFalse(schema.properties[key]); + } } } + + // If schema has items (meaning it's an array), apply recursively to each item schema + if (schema.type === 'array' && schema.items) { + addAdditionalPropertiesFalse(schema.items); + } } return schema; @@ -107,7 +115,7 @@ export class ClassValidatorValidator implements Validator { const { defaultMetadataStorage } = require('class-transformer/cjs/storage'); // eslint-disable-next-line global-require const { getMetadataStorage } = require('class-validator') as typeof import('class-validator'); - // eslint-disable-next-line global-require, prettier/prettier + const { targetConstructorToSchema, validationMetadatasToSchemas } = require('class-validator-jsonschema') as typeof import('class-validator-jsonschema'); diff --git a/packages/framework/src/validators/validator.test.ts b/packages/framework/src/validators/validator.test.ts index a31869bbd3e..fa6d54481d8 100644 --- a/packages/framework/src/validators/validator.test.ts +++ b/packages/framework/src/validators/validator.test.ts @@ -31,6 +31,14 @@ class NestedSchema { @Type(() => NestedChildrenSchema) nested!: NestedChildrenSchema; } +class NestedArraySchema { + @IsString() + name!: string; + + @ValidateNested({ each: true }) + @Type(() => NestedChildrenSchema) + nested!: NestedChildrenSchema[]; +} class SimpleStringAndNumberSchema { @IsString() name!: string; @@ -150,6 +158,70 @@ describe('validators', () => { }, }, }, + { + title: 'should validate nested array objects successfully', + schemas: { + zod: z.object({ name: z.string(), nested: z.array(z.object({ age: z.number() })) }), + class: NestedArraySchema, + json: { + type: 'object', + properties: { + name: { type: 'string' }, + nested: { + type: 'array', + items: { + type: 'object', + properties: { + age: { + type: 'number', + }, + }, + required: ['age'], + }, + }, + }, + } as const, + }, + payload: { name: 'John', nested: [{ age: 30 }] }, + result: { + success: true, + data: { name: 'John', nested: [{ age: 30 }] }, + }, + }, + { + title: 'should return errors for invalid nested array objects', + schemas: { + zod: z.object({ name: z.string(), nested: z.array(z.object({ age: z.number() })) }), + class: NestedArraySchema, + json: { + type: 'object', + properties: { + name: { type: 'string' }, + nested: { + type: 'array', + items: { + type: 'object', + properties: { + age: { + type: 'number', + }, + }, + required: ['age'], + }, + }, + }, + } as const, + }, + payload: { name: 'John', nested: [{ age: '30' }] }, + result: { + success: false, + errors: { + zod: [{ message: 'Expected number, received string', path: '/nested/0/age' }], + class: [{ message: 'age must be a number conforming to the specified constraints', path: '/nested/0/age' }], + json: [{ message: 'must be number', path: '/nested/0/age' }], + }, + }, + }, { title: 'should successfully validate a polymorphic oneOf schema', schemas: { @@ -507,6 +579,55 @@ describe('validators', () => { additionalProperties: false, }, }, + { + title: 'should transform a nested array object schema', + schemas: { + zod: z.object({ name: z.string(), nested: z.array(z.object({ age: z.number() })) }), + class: NestedArraySchema, + json: { + type: 'object', + properties: { + name: { type: 'string' }, + nested: { + type: 'array', + items: { + type: 'object', + properties: { + age: { + type: 'number', + }, + }, + required: ['age'], + additionalProperties: false, + }, + }, + }, + required: ['name', 'nested'], + additionalProperties: false, + } as const, + }, + result: { + type: 'object', + properties: { + name: { type: 'string' }, + nested: { + type: 'array', + items: { + type: 'object', + properties: { + age: { + type: 'number', + }, + }, + required: ['age'], + additionalProperties: false, + }, + }, + }, + required: ['name', 'nested'], + additionalProperties: false, + }, + }, { title: 'should transform a polymorphic `oneOf` schema', schemas: { From c39591fcc8563e26ff3d1d24823bd9b227f7f6d8 Mon Sep 17 00:00:00 2001 From: paulwer Date: Tue, 12 Nov 2024 17:38:32 +0100 Subject: [PATCH 45/56] fixes --- .../fixures/class-validator.fixtures.ts | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/framework/src/validators/fixures/class-validator.fixtures.ts b/packages/framework/src/validators/fixures/class-validator.fixtures.ts index 073b6ef5113..7ca40f8252e 100644 --- a/packages/framework/src/validators/fixures/class-validator.fixtures.ts +++ b/packages/framework/src/validators/fixures/class-validator.fixtures.ts @@ -1,7 +1,13 @@ import 'reflect-metadata'; -import { IsNumber, IsString, ValidateNested } from 'class-validator'; +import { IsEnum, IsNumber, IsString, ValidateNested } from 'class-validator'; import { Type } from 'class-transformer'; +enum TestEnum { + A = 'A', + B = 'B', + C = 'C', +} + export class SimpleStringSchema { @IsString() name!: string; @@ -20,6 +26,14 @@ export class NestedSchema { @Type(() => NestedChildrenSchema) nested!: NestedChildrenSchema; } +export class NestedArraySchema { + @IsString() + name!: string; + + @ValidateNested({ each: true }) + @Type(() => NestedChildrenSchema) + nested!: NestedChildrenSchema[]; +} export class SimpleStringAndNumberSchema { @IsString() @@ -27,3 +41,9 @@ export class SimpleStringAndNumberSchema { @IsNumber() age!: number; } + +export class SimpleTestEnum { + @IsString() + @IsEnum(TestEnum) + enum?: TestEnum; +} From db76adb543a5b42013449bf71878fa24b8ab50d9 Mon Sep 17 00:00:00 2001 From: paulwer Date: Tue, 12 Nov 2024 18:11:56 +0100 Subject: [PATCH 46/56] chore: cleanup namings for fixtures & add tests for simple UnionTypes --- .../fixures/class-validator.fixtures.ts | 25 +++++++++++++--- .../src/validators/validator.test.ts | 30 ++++++++++--------- 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/packages/framework/src/validators/fixures/class-validator.fixtures.ts b/packages/framework/src/validators/fixures/class-validator.fixtures.ts index 7ca40f8252e..c26137fc6ea 100644 --- a/packages/framework/src/validators/fixures/class-validator.fixtures.ts +++ b/packages/framework/src/validators/fixures/class-validator.fixtures.ts @@ -1,5 +1,5 @@ import 'reflect-metadata'; -import { IsEnum, IsNumber, IsString, ValidateNested } from 'class-validator'; +import { IsBoolean, IsEnum, IsIn, IsNumber, IsString, ValidateIf, ValidateNested } from 'class-validator'; import { Type } from 'class-transformer'; enum TestEnum { @@ -8,7 +8,7 @@ enum TestEnum { C = 'C', } -export class SimpleStringSchema { +export class StringSchema { @IsString() name!: string; } @@ -35,15 +35,32 @@ export class NestedArraySchema { nested!: NestedChildrenSchema[]; } -export class SimpleStringAndNumberSchema { +export class StringAndNumberSchema { @IsString() name!: string; @IsNumber() age!: number; } -export class SimpleTestEnum { +export class SimpleTestEnumSchema { @IsString() @IsEnum(TestEnum) enum?: TestEnum; } + +export class UnionSchema { + @IsIn(['stringType', 'numberType', 'booleanType']) + type!: 'stringType' | 'numberType' | 'booleanType'; + + @ValidateIf((obj) => obj.type === 'stringType') + @IsString() + stringVal?: string; + + @ValidateIf((obj) => obj.type === 'numberType') + @IsNumber() + numVal?: number; + + @ValidateIf((obj) => obj.type === 'booleanType') + @IsBoolean() + boolVal?: boolean; +} diff --git a/packages/framework/src/validators/validator.test.ts b/packages/framework/src/validators/validator.test.ts index cbb50bf21f1..22fb0b8fcee 100644 --- a/packages/framework/src/validators/validator.test.ts +++ b/packages/framework/src/validators/validator.test.ts @@ -3,11 +3,13 @@ import { z } from 'zod'; import { validateData, transformSchema } from './base.validator'; import type { Schema, ZodSchema, JsonSchema, ClassValidatorSchema } from '../types/schema.types'; import { - SimpleStringSchema, + StringSchema, NestedSchema, - SimpleStringAndNumberSchema, + StringAndNumberSchema, NestedArraySchema, - SimpleTestEnum, + SimpleTestEnumSchema, + UnionSchema, + OneOfSchema, } from './fixures/class-validator.fixtures'; const schemas = ['zod', 'class', 'json'] as const; @@ -37,7 +39,7 @@ describe('validators', () => { title: 'should successfully validate data', schemas: { zod: z.object({ name: z.string() }), - class: SimpleStringSchema, + class: StringSchema, json: { type: 'object', properties: { name: { type: 'string' } } } as const, }, payload: { name: 'John' }, @@ -50,7 +52,7 @@ describe('validators', () => { title: 'should remove additional properties and successfully validate', schemas: { zod: z.object({ name: z.string() }), - class: SimpleStringSchema, + class: StringSchema, json: { type: 'object', properties: { name: { type: 'string' } }, additionalProperties: false } as const, }, payload: { name: 'John', age: 30 }, @@ -63,7 +65,7 @@ describe('validators', () => { title: 'should return errors when given invalid types', schemas: { zod: z.object({ name: z.string() }), - class: SimpleStringSchema, + class: StringSchema, json: { type: 'object', properties: { name: { type: 'string' } } } as const, }, payload: { name: 123 }, @@ -187,7 +189,7 @@ describe('validators', () => { title: 'should successfully validate a polymorphic oneOf schema', schemas: { zod: null, // Zod has no support for `oneOf` - class: null, // ClassValidator has no support for `oneOf` + class: OneOfSchema, // ClassValidator has no support for `oneOf` json: { oneOf: [ { type: 'object', properties: { stringType: { type: 'string' } }, required: ['stringType'] }, @@ -292,7 +294,7 @@ describe('validators', () => { z.object({ type: z.literal('numberType'), numVal: z.number() }), z.object({ type: z.literal('booleanType'), boolVal: z.boolean() }), ]), - class: null, // ClassValidator has no support for `anyOf` + class: UnionSchema, json: { anyOf: [ { @@ -330,7 +332,7 @@ describe('validators', () => { z.object({ type: z.literal('numberType'), numVal: z.number() }), z.object({ type: z.literal('booleanType'), boolVal: z.boolean() }), ]), - class: null, // ClassValidator has no support for `anyOf` + class: UnionSchema, json: { anyOf: [ { @@ -359,7 +361,7 @@ describe('validators', () => { success: false, errors: { zod: [{ message: 'Expected number, received string', path: '/numVal' }], - class: null, // ClassValidator has no support for `anyOf` + class: [{ message: 'numVal must be a number conforming to the specified constraints', path: '/numVal' }], /* * TODO: use discriminator to get the correct error message. * @@ -399,7 +401,7 @@ describe('validators', () => { title: 'should successfully validate enum property', schemas: { zod: z.object({ enum: z.enum(['A', 'B', 'C']) }), - class: SimpleTestEnum, + class: SimpleTestEnumSchema, json: { type: 'object', properties: { @@ -421,7 +423,7 @@ describe('validators', () => { title: 'should return errors for invalid enum property', schemas: { zod: z.object({ enum: z.enum(['A', 'B', 'C']) }), - class: SimpleTestEnum, + class: SimpleTestEnumSchema, json: { type: 'object', properties: { @@ -490,7 +492,7 @@ describe('validators', () => { title: 'should transform a simple object schema', schemas: { zod: z.object({ name: z.string(), age: z.number() }), - class: SimpleStringAndNumberSchema, + class: StringAndNumberSchema, json: { type: 'object', properties: { name: { type: 'string' }, age: { type: 'number' } }, @@ -714,7 +716,7 @@ describe('validators', () => { title: 'should transform a enum schema', schemas: { zod: z.object({ enum: z.enum(['A', 'B', 'C']) }), - class: SimpleTestEnum, // ClassValidator has no support for `anyOf` + class: SimpleTestEnumSchema, // ClassValidator has no support for `anyOf` json: { type: 'object', properties: { From d9c952cd39587a2301b23cea6787555b6e4c698f Mon Sep 17 00:00:00 2001 From: paulwer Date: Tue, 12 Nov 2024 18:19:52 +0100 Subject: [PATCH 47/56] fixes --- packages/framework/src/validators/validator.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/framework/src/validators/validator.test.ts b/packages/framework/src/validators/validator.test.ts index 22fb0b8fcee..33c48157537 100644 --- a/packages/framework/src/validators/validator.test.ts +++ b/packages/framework/src/validators/validator.test.ts @@ -9,7 +9,6 @@ import { NestedArraySchema, SimpleTestEnumSchema, UnionSchema, - OneOfSchema, } from './fixures/class-validator.fixtures'; const schemas = ['zod', 'class', 'json'] as const; @@ -189,7 +188,7 @@ describe('validators', () => { title: 'should successfully validate a polymorphic oneOf schema', schemas: { zod: null, // Zod has no support for `oneOf` - class: OneOfSchema, // ClassValidator has no support for `oneOf` + class: null, // ClassValidator has no support for `oneOf` json: { oneOf: [ { type: 'object', properties: { stringType: { type: 'string' } }, required: ['stringType'] }, From bb0e949d3749601442ab58a5eeb56332f9abbdc3 Mon Sep 17 00:00:00 2001 From: Dima Grossman Date: Mon, 2 Dec 2024 20:09:32 +0200 Subject: [PATCH 48/56] feat: cspell --- .cspell.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.cspell.json b/.cspell.json index 5b103437191..12c581c0a69 100644 --- a/.cspell.json +++ b/.cspell.json @@ -707,7 +707,8 @@ "rstrip", "truncatewords", "xmlschema", - "jsonify" + "jsonify", + "metadatas" ], "flagWords": [], "patterns": [ From 1c7dc73a7ca6166716f58c6d95c1a1b61ab35c12 Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Tue, 3 Dec 2024 01:53:32 +0200 Subject: [PATCH 49/56] test: Add tests for enhanced type inference system --- .../workflow/workflow.resource.test-d.ts | 48 +++- .../resources/workflow/workflow.resource.ts | 3 +- .../schema.types/base.schema.types.test-d.ts | 92 +++++-- .../types/schema.types/base.schema.types.ts | 27 +- .../schema.types/class.schema.types.test-d.ts | 54 +++- .../types/schema.types/class.schema.types.ts | 14 +- .../schema.types/json.schema.types.test-d.ts | 73 ++++- .../types/schema.types/json.schema.types.ts | 8 +- .../schema.types/zod.schema.types.test-d.ts | 63 ++++- .../types/schema.types/zod.schema.types.ts | 2 +- .../framework/src/types/util.types.test-d.ts | 253 ++++++++++++++---- packages/framework/src/types/util.types.ts | 137 +++++++++- 12 files changed, 653 insertions(+), 121 deletions(-) diff --git a/packages/framework/src/resources/workflow/workflow.resource.test-d.ts b/packages/framework/src/resources/workflow/workflow.resource.test-d.ts index 3ad8e6ed0ee..51d33997332 100644 --- a/packages/framework/src/resources/workflow/workflow.resource.test-d.ts +++ b/packages/framework/src/resources/workflow/workflow.resource.test-d.ts @@ -109,13 +109,15 @@ describe('workflow function types', () => { additionalProperties: false, } as const; - it('should infer an unknown record type when the provided schema is for a primitive type', () => { + it('should infer an error message type when the provided schema is for a primitive type', () => { const primitiveSchema = { type: 'string' } as const; workflow('without-schema', async ({ step }) => { await step.email( 'without-schema', async (controls) => { - expectTypeOf(controls).toEqualTypeOf>(); + expectTypeOf(controls).toEqualTypeOf<{ + SchemaError: "Schema must describe an object data structure. Got data type: 'string'"; + }>(); return { subject: 'Test subject', @@ -123,13 +125,53 @@ describe('workflow function types', () => { }; }, { - // @ts-expect-error - schema is for a primitive type controlSchema: primitiveSchema, } ); }); }); + it('should infer an error message type when the provided schema is for an array type', () => { + const arraySchema = { type: 'array', items: { type: 'string' } } as const; + workflow('without-schema', async ({ step }) => { + await step.email( + 'without-schema', + async (controls) => { + expectTypeOf(controls).toEqualTypeOf<{ + SchemaError: `Schema must describe an object data structure. Got data type: 'string[]'`; + }>(); + + return { + subject: 'Test subject', + body: 'Test body', + }; + }, + { + controlSchema: arraySchema, + } + ); + }); + }); + + it('should infer an unknown record type when the provided schema is undefined', () => { + workflow('without-schema', async ({ step }) => { + await step.email( + 'without-schema', + async (controls) => { + expectTypeOf(controls).toEqualTypeOf>(); + + return { + subject: 'Test subject', + body: 'Test body', + }; + }, + { + controlSchema: undefined, + } + ); + }); + }); + it('should infer correct types in the step controls', async () => { workflow('json-schema', async ({ step }) => { await step.email( diff --git a/packages/framework/src/resources/workflow/workflow.resource.ts b/packages/framework/src/resources/workflow/workflow.resource.ts index 09bdc9e9453..56e70b28f19 100644 --- a/packages/framework/src/resources/workflow/workflow.resource.ts +++ b/packages/framework/src/resources/workflow/workflow.resource.ts @@ -45,7 +45,8 @@ export function workflow< if (validationResult.success === false) { throw new WorkflowPayloadInvalidError(workflowId, validationResult.errors); } - validatedData = validationResult.data as T_PayloadValidated; + // Coerce the validated data to handle unknown matching to SchemaError + validatedData = validationResult.data as unknown as T_PayloadValidated; } else { // This type coercion provides support to trigger Workflows without a payload schema validatedData = event.payload as unknown as T_PayloadValidated; diff --git a/packages/framework/src/types/schema.types/base.schema.types.test-d.ts b/packages/framework/src/types/schema.types/base.schema.types.test-d.ts index e3ab10ed064..cf28e027005 100644 --- a/packages/framework/src/types/schema.types/base.schema.types.test-d.ts +++ b/packages/framework/src/types/schema.types/base.schema.types.test-d.ts @@ -4,16 +4,65 @@ import { FromSchema, FromSchemaUnvalidated, Schema } from './base.schema.types'; describe('FromSchema', () => { it('should infer an unknown record type when a generic schema is provided', () => { - expectTypeOf>().toEqualTypeOf>(); + type Test = FromSchema; + + expectTypeOf().toEqualTypeOf>(); + }); + + it('should not compile and infer an unknown record type when the schema is undefined', () => { + // @ts-expect-error - Type 'undefined' does not satisfy the constraint 'Schema'. + type Test = FromSchema; + + expectTypeOf().toEqualTypeOf>(); }); - it('should not compile when the schema is primitive', () => { + it('not compile when the schema is undefined', () => { + // @ts-expect-error - Type 'undefined' does not satisfy the constraint 'Schema'. + type Test = FromSchemaUnvalidated; + + expectTypeOf().toEqualTypeOf>(); + }); + + it('should infer an error message type when the schema describes a primitive type', () => { const primitiveSchema = { type: 'string' } as const; + type Test = FromSchema; + + expectTypeOf().toEqualTypeOf<{ + SchemaError: `Schema must describe an object data structure. Got data type: 'string'`; + }>(); + }); + + it('should infer an error message type when the schema describes an array of primitive types', () => { + const primitiveSchema = { type: 'array', items: { type: 'string' } } as const; + type Test = FromSchema; + + expectTypeOf().toEqualTypeOf<{ + SchemaError: `Schema must describe an object data structure. Got data type: 'string[]'`; + }>(); + }); + + it('should infer an error message type when the schema describes an array of objects', () => { + const primitiveSchema = { + type: 'array', + items: { type: 'object' }, + } as const; + type Test = FromSchema; + + expectTypeOf().toEqualTypeOf<{ + SchemaError: `Schema must describe an object data structure. Got data type: '{ [x: string]: unknown; }[]'`; + }>(); + }); - // @ts-expect-error - Type '{ type: string; }' is not assignable to type '{ type: "object"; }'. + it('should infer an error message type when the schema describes an array of unknown types', () => { + const primitiveSchema = { + type: 'array', + items: {}, + } as const; type Test = FromSchema; - expectTypeOf().toEqualTypeOf(); + expectTypeOf().toEqualTypeOf<{ + SchemaError: `Schema must describe an object data structure. Got data type: 'unknown[]'`; + }>(); }); it('should infer a Json Schema type', () => { @@ -26,7 +75,9 @@ describe('FromSchema', () => { additionalProperties: false, } as const; - expectTypeOf>().toEqualTypeOf<{ foo: string; bar?: string }>(); + type Test = FromSchema; + + expectTypeOf().toEqualTypeOf<{ foo: string; bar?: string }>(); }); it('should infer a Zod Schema type', () => { @@ -35,7 +86,9 @@ describe('FromSchema', () => { bar: z.string().optional(), }); - expectTypeOf>().toEqualTypeOf<{ foo: string; bar?: string }>(); + type Test = FromSchema; + + expectTypeOf().toEqualTypeOf<{ foo: string; bar?: string }>(); }); it('should infer a Class Schema type', () => { @@ -44,22 +97,17 @@ describe('FromSchema', () => { bar?: string; } - expectTypeOf>().toEqualTypeOf<{ foo: string; bar?: string }>(); + type Test = FromSchema; + + expectTypeOf().toEqualTypeOf<{ foo: string; bar?: string }>(); }); }); describe('FromSchemaUnvalidated', () => { it('should infer an unknown record type when a generic schema is provided', () => { - expectTypeOf>().toEqualTypeOf>(); - }); - - it('should not compile when the schema is primitive', () => { - const primitiveSchema = { type: 'string' } as const; - - // @ts-expect-error - Type '{ type: string; }' is not assignable to type '{ type: "object"; }'. - type Test = FromSchemaUnvalidated; + type Test = FromSchemaUnvalidated; - expectTypeOf().toEqualTypeOf(); + expectTypeOf().toEqualTypeOf>(); }); it('should infer a Json Schema type', () => { @@ -72,7 +120,9 @@ describe('FromSchemaUnvalidated', () => { additionalProperties: false, } as const; - expectTypeOf>().toEqualTypeOf<{ foo?: string; bar?: string }>(); + type Test = FromSchemaUnvalidated; + + expectTypeOf().toEqualTypeOf<{ foo?: string; bar?: string }>(); }); it('should infer a Zod Schema type', () => { @@ -81,7 +131,9 @@ describe('FromSchemaUnvalidated', () => { bar: z.string().optional(), }); - expectTypeOf>().toEqualTypeOf<{ foo?: string; bar?: string }>(); + type Test = FromSchemaUnvalidated; + + expectTypeOf().toEqualTypeOf<{ foo?: string; bar?: string }>(); }); it('should infer a Class Schema type', () => { @@ -90,6 +142,8 @@ describe('FromSchemaUnvalidated', () => { bar?: string; } - expectTypeOf>().toEqualTypeOf<{ foo?: string; bar?: string }>(); + type Test = FromSchemaUnvalidated; + + expectTypeOf().toEqualTypeOf<{ foo?: string; bar?: string }>(); }); }); diff --git a/packages/framework/src/types/schema.types/base.schema.types.ts b/packages/framework/src/types/schema.types/base.schema.types.ts index c5e3dbc8605..39c990c52e6 100644 --- a/packages/framework/src/types/schema.types/base.schema.types.ts +++ b/packages/framework/src/types/schema.types/base.schema.types.ts @@ -1,6 +1,7 @@ import type { InferJsonSchema, JsonSchemaMinimal } from './json.schema.types'; import type { InferZodSchema, ZodSchemaMinimal } from './zod.schema.types'; import type { InferClassValidatorSchema, ClassValidatorSchema } from './class.schema.types'; +import type { Stringify } from '../util.types'; /** * A schema used to validate a JSON object. @@ -16,7 +17,31 @@ export type Schema = JsonSchemaMinimal | ZodSchemaMinimal | ClassValidatorSchema type InferSchema = | InferJsonSchema | InferClassValidatorSchema - | InferZodSchema; + | InferZodSchema + | never extends infer U + ? /* + * Use a distributive conditional type to detect if all inferred types are `never`. + * When all inferred types are `never`, return an unknown record. + * + * Each schema inferrence must return `never` type when: + * - The schema is generic (i.e. not a concrete schema type) + * - The schema is not supported (i.e. tried to specify `string` as the schema type) + * - The schema is undefined + * + * @see - https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types + */ + [U] extends [never] + ? // When all inferred types are `never`, return an unknown record. + Record + : // The type inferrence did not return `never`. Ensure the inferred type is a record type, as only objects are supported. + U extends Record + ? // Got a record type, return it. + U + : // The schema describes a non-record type, return an error message. + { + SchemaError: `Schema must describe an object data structure. Got data type: '${Stringify}'`; + } + : never; /** * Infer the type of a Schema for unvalidated data. diff --git a/packages/framework/src/types/schema.types/class.schema.types.test-d.ts b/packages/framework/src/types/schema.types/class.schema.types.test-d.ts index ebdd46cb6c8..a79c22cd3de 100644 --- a/packages/framework/src/types/schema.types/class.schema.types.test-d.ts +++ b/packages/framework/src/types/schema.types/class.schema.types.test-d.ts @@ -1,5 +1,5 @@ import { describe, expectTypeOf, it } from 'vitest'; -import { InferClassValidatorSchema } from './class.schema.types'; +import { InferClassValidatorSchema, ClassValidatorSchema } from './class.schema.types'; describe('ClassSchema types', () => { class TestSchema { @@ -8,32 +8,70 @@ describe('ClassSchema types', () => { } describe('validated data', () => { - it('should compile when the expected properties are provided', () => { - expectTypeOf>().toEqualTypeOf<{ + it('should infer the expected properties for the schema', () => { + type Test = InferClassValidatorSchema; + + expectTypeOf().toEqualTypeOf<{ foo: string; bar?: string; }>(); }); - it('should not compile when the schema is not a ClassSchema', () => { - expectTypeOf>().toEqualTypeOf(); + it('should infer an empty object type for an empty object schema', () => { + class EmptySchema {} + type Test = InferClassValidatorSchema; + + expectTypeOf().toEqualTypeOf<{}>(); + }); + + it('should infer to never when the schema is not a ClassSchema', () => { + type Test = InferClassValidatorSchema; + + expectTypeOf().toEqualTypeOf(); + }); + + it('should infer to never when the schema is undefined', () => { + type Test = InferClassValidatorSchema; + + expectTypeOf().toEqualTypeOf(); + }); + + it('should infer to never when the schema is generic', () => { + type Test = InferClassValidatorSchema; + + expectTypeOf().toEqualTypeOf(); }); it('should not compile when a property does not match the expected type', () => { + type Test = InferClassValidatorSchema; + // @ts-expect-error - Type 'number' is not assignable to type 'string'. - expectTypeOf>().toEqualTypeOf<{ + expectTypeOf().toEqualTypeOf<{ foo: number; }>(); }); + + it('should infer to never when the schema includes a constructor', () => { + class TestSchemaWithConstructor { + constructor(public foo: string) {} + + bar?: string; + } + type Test = InferClassValidatorSchema; + + expectTypeOf().toEqualTypeOf(); + }); }); describe('unvalidated data', () => { /** - * TODO: Support accessing defaulted properties when Typescript supports it. + * TODO: Support accessing defaulted class properties when Typescript supports it. */ it.skip('should keep the defaulted properties optional', () => { + type Test = InferClassValidatorSchema; + // @ts-expect-error - Type 'undefined' is not assignable to type 'string'. - expectTypeOf>().toEqualTypeOf<{ + expectTypeOf().toEqualTypeOf<{ foo?: string; bar?: string; }>(); diff --git a/packages/framework/src/types/schema.types/class.schema.types.ts b/packages/framework/src/types/schema.types/class.schema.types.ts index 4c57b30bf92..e6154f073d5 100644 --- a/packages/framework/src/types/schema.types/class.schema.types.ts +++ b/packages/framework/src/types/schema.types/class.schema.types.ts @@ -36,9 +36,13 @@ export type ClassPropsInfer = * ``` */ export type InferClassValidatorSchema = T extends ClassValidatorSchema - ? Options['validated'] extends true - ? ClassPropsInfer - : // ClassSchema doesn't support default properties, so the resulting type - // will not have default properties set to optional. - ClassPropsInfer + ? keyof T extends never + ? // Ensure that a generic schema produces never + never + : // Non-generic schema + Options['validated'] extends true + ? ClassPropsInfer + : // ClassSchema doesn't support default properties, so the resulting type + // will not have default properties set to optional. + ClassPropsInfer : never; diff --git a/packages/framework/src/types/schema.types/json.schema.types.test-d.ts b/packages/framework/src/types/schema.types/json.schema.types.test-d.ts index 4a786aad3a7..192baa6a944 100644 --- a/packages/framework/src/types/schema.types/json.schema.types.test-d.ts +++ b/packages/framework/src/types/schema.types/json.schema.types.test-d.ts @@ -1,5 +1,5 @@ import { describe, expectTypeOf, it } from 'vitest'; -import { InferJsonSchema, JsonSchema } from './json.schema.types'; +import { InferJsonSchema, JsonSchema, JsonSchemaMinimal } from './json.schema.types'; describe('JsonSchema types', () => { const testSchema = { @@ -12,30 +12,77 @@ describe('JsonSchema types', () => { } as const satisfies JsonSchema; describe('validated data', () => { - it('should compile when the expected properties are provided', () => { - expectTypeOf>().toEqualTypeOf<{ + it('should infer the expected properties for an object schema with properties', () => { + type Test = InferJsonSchema; + + expectTypeOf().toEqualTypeOf<{ foo: string; bar?: string; }>(); }); - it('should not compile when the schema is not a JsonSchema', () => { - expectTypeOf>().toEqualTypeOf(); + it('should infer the expected properties for a polymorphic schema with properties', () => { + const polymorphicSchema = { + anyOf: [ + { + type: 'object', + properties: { + foo: { type: 'string', default: 'bar' }, + }, + additionalProperties: false, + }, + { + type: 'object', + properties: { + bar: { type: 'number' }, + }, + additionalProperties: false, + }, + ], + } as const satisfies JsonSchema; + + type Test = InferJsonSchema; + + expectTypeOf().toEqualTypeOf< + | { + foo: string; + } + | { + bar?: number; + } + >(); + }); + + it('should infer an empty object type for an empty object schema', () => { + const emptySchema = { type: 'object', properties: {}, additionalProperties: false } as const; + type Test = InferJsonSchema; + + expectTypeOf().toEqualTypeOf<{}>(); + }); + + it('should infer to never when the schema is not a JsonSchema', () => { + type Test = InferJsonSchema; + + expectTypeOf().toEqualTypeOf(); }); - it('should not compile when the schema is generic', () => { - expectTypeOf>().toEqualTypeOf(); + it('should infer to never when the schema is undefined', () => { + type Test = InferJsonSchema; + + expectTypeOf().toEqualTypeOf(); }); - it('should not compile when the schema is a primitive JsonSchema', () => { - const testPrimitiveSchema = { type: 'string' } as const; + it('should infer to never when the schema is generic', () => { + type Test = InferJsonSchema; - expectTypeOf>().toEqualTypeOf(); + expectTypeOf().toEqualTypeOf(); }); it('should not compile when a property does not match the expected type', () => { + type Test = InferJsonSchema; + // @ts-expect-error - Type 'number' is not assignable to type 'string'. - expectTypeOf>().toEqualTypeOf<{ + expectTypeOf().toEqualTypeOf<{ foo: number; }>(); }); @@ -43,7 +90,9 @@ describe('JsonSchema types', () => { describe('unvalidated data', () => { it('should keep the defaulted properties optional', () => { - expectTypeOf>().toEqualTypeOf<{ + type Test = InferJsonSchema; + + expectTypeOf().toEqualTypeOf<{ foo?: string; bar?: string; }>(); diff --git a/packages/framework/src/types/schema.types/json.schema.types.ts b/packages/framework/src/types/schema.types/json.schema.types.ts index 71d378beefb..a684729e330 100644 --- a/packages/framework/src/types/schema.types/json.schema.types.ts +++ b/packages/framework/src/types/schema.types/json.schema.types.ts @@ -6,7 +6,11 @@ import type { JSONSchema, FromSchema as JsonSchemaInfer } from 'json-schema-to-t * This type is used to narrow the type of a JSON schema to a minimal type * that is compatible with the `json-schema-to-ts` library. */ -export type JsonSchemaMinimal = { type: 'object' } | { anyOf: unknown[] } | { allOf: unknown[] } | { oneOf: unknown[] }; +export type JsonSchemaMinimal = + | { type: unknown } + | { anyOf: readonly unknown[] } + | { allOf: readonly unknown[] } + | { oneOf: readonly unknown[] }; /** * A JSON schema @@ -43,7 +47,7 @@ export type InferJsonSchema = ? // Secondly, narrow to the JSON schema type to provide type-safety to `json-schema-to-ts` T extends JSONSchema ? Options['validated'] extends true - ? JsonSchemaInfer + ? JsonSchemaInfer : JsonSchemaInfer : never : never; diff --git a/packages/framework/src/types/schema.types/zod.schema.types.test-d.ts b/packages/framework/src/types/schema.types/zod.schema.types.test-d.ts index a85b603f5a7..e937cb3d074 100644 --- a/packages/framework/src/types/schema.types/zod.schema.types.test-d.ts +++ b/packages/framework/src/types/schema.types/zod.schema.types.test-d.ts @@ -2,37 +2,74 @@ import { describe, expectTypeOf, it } from 'vitest'; import { z } from 'zod'; import { InferZodSchema, ZodSchemaMinimal } from './zod.schema.types'; -describe('ZodSchema', () => { +describe('ZodSchema types', () => { const testSchema = z.object({ foo: z.string().default('bar'), bar: z.string().optional(), }); describe('validated data', () => { - it('should compile when the expected properties are provided', () => { - expectTypeOf>().toEqualTypeOf<{ + it('should infer the expected properties for the schema', () => { + type Test = InferZodSchema; + + expectTypeOf().toEqualTypeOf<{ foo: string; bar?: string; }>(); }); - it('should not compile when the schema is not a ZodSchema', () => { - expectTypeOf>().toEqualTypeOf(); + it('should infer the expected properties for a polymorphic schema with properties', () => { + const polymorphicSchema = z.union([ + z.object({ + foo: z.string().default('bar'), + }), + z.object({ + bar: z.number().optional(), + }), + ]); + + type Test = InferZodSchema; + + expectTypeOf().toEqualTypeOf< + | { + foo: string; + } + | { + bar?: number; + } + >(); + }); + + it('should infer an empty object type for an empty object schema', () => { + const emptySchema = z.object({}); + type Test = InferZodSchema; + + expectTypeOf().toEqualTypeOf<{}>(); + }); + + it('should infer to never when the schema is not a ZodSchema', () => { + type Test = InferZodSchema; + + expectTypeOf().toEqualTypeOf(); }); - it('should not compile when the schema is generic', () => { - expectTypeOf>().toEqualTypeOf(); + it('should infer to never when the schema is undefined', () => { + type Test = InferZodSchema; + + expectTypeOf().toEqualTypeOf(); }); - it('should not compile when the schema is a primitive ZodSchema', () => { - const testPrimitiveSchema = z.string(); + it('should infer to never when the schema is generic', () => { + type Test = InferZodSchema; - expectTypeOf>().toEqualTypeOf(); + expectTypeOf().toEqualTypeOf(); }); it('should not compile when a property does not match the expected type', () => { + type Test = InferZodSchema; + // @ts-expect-error - Type 'number' is not assignable to type 'string'. - expectTypeOf>().toEqualTypeOf<{ + expectTypeOf().toEqualTypeOf<{ foo: number; }>(); }); @@ -40,7 +77,9 @@ describe('ZodSchema', () => { describe('unvalidated data', () => { it('should keep the defaulted properties optional', () => { - expectTypeOf>().toEqualTypeOf<{ + type Test = InferZodSchema; + + expectTypeOf().toEqualTypeOf<{ foo?: string; bar?: string; }>(); diff --git a/packages/framework/src/types/schema.types/zod.schema.types.ts b/packages/framework/src/types/schema.types/zod.schema.types.ts index efbb6d35604..86bbb40dda8 100644 --- a/packages/framework/src/types/schema.types/zod.schema.types.ts +++ b/packages/framework/src/types/schema.types/zod.schema.types.ts @@ -3,7 +3,7 @@ import type zod from 'zod'; /** * A ZodSchema used to validate a JSON object. */ -export type ZodSchema = zod.ZodType, zod.ZodTypeDef, Record>; +export type ZodSchema = zod.ZodType; /** * A minimal ZodSchema type. diff --git a/packages/framework/src/types/util.types.test-d.ts b/packages/framework/src/types/util.types.test-d.ts index d20a988d93d..88d52bc9e40 100644 --- a/packages/framework/src/types/util.types.test-d.ts +++ b/packages/framework/src/types/util.types.test-d.ts @@ -1,5 +1,5 @@ -import { describe, it } from 'vitest'; -import { +import { describe, expectTypeOf, it } from 'vitest'; +import type { ConditionalPartial, Either, Awaitable, @@ -10,6 +10,8 @@ import { Prettify, DeepPartial, DeepRequired, + Stringify, + UnionToTuple, } from './util.types'; describe('Either', () => { @@ -36,188 +38,327 @@ describe('Either', () => { }); describe('Awaitable', () => { - it('should compile when the type is an awaitable', () => { - type TestAwaitable = Awaitable>; - const testAwaitableValid: TestAwaitable = Promise.resolve('bar'); - }); - - it('should compile when the type is not an awaitable', () => { + it('should return a string or a promise of a string', () => { type TestAwaitable = Awaitable; - const testAwaitableValid: TestAwaitable = 'bar'; + expectTypeOf().toEqualTypeOf>(); }); it('should not compile when a non-awaitable type has incorrect properties', () => { type TestAwaitable = Awaitable<{ foo: string }>; // @ts-expect-error - foo should be a string - const testAwaitableInvalid: TestAwaitable = { foo: 123 }; + expectTypeOf().toEqualTypeOf<{ foo: 123 }>(); }); it('should not compile when an awaitable type has incorrect properties', () => { type TestAwaitable = Awaitable<{ foo: string }>; // @ts-expect-error - foo should be a string - const testAwaitableInvalid: TestAwaitable = Promise.resolve({ foo: 123 }); + expectTypeOf().toEqualTypeOf>(); }); }); describe('ConditionalPartial', () => { - it('should compile an empty object when the condition is true', () => { + it('should return an empty object when the condition is true', () => { type TestConditionalPartialTrue = ConditionalPartial<{ foo: string }, true>; - const testConditionalPartialTrueValid: TestConditionalPartialTrue = {}; + expectTypeOf().toEqualTypeOf<{}>(); }); - it('should compile an object with the correct type of properties when the condition is true', () => { + it('should return the object with the optional properties when the condition is true', () => { type TestConditionalPartialTrue = ConditionalPartial<{ foo: string }, true>; - const testConditionalPartialTrueValid: TestConditionalPartialTrue = { foo: 'bar' }; + expectTypeOf().toEqualTypeOf<{ foo?: string }>(); }); it('should not compile an object with the wrong type of properties when the condition is true', () => { type TestConditionalPartialTrue = ConditionalPartial<{ foo: string }, true>; - // @ts-expect-error - foo should be a string - const testConditionalPartialTrueInvalid: TestConditionalPartialTrue = { foo: 123 }; + // @ts-expect-error - foo should be optional + expectTypeOf().toEqualTypeOf<{ foo: 123 }>(); }); - it('should compile an object with the required properties when the condition is false', () => { + it('should return the object with the required properties when the condition is false', () => { type TestConditionalPartialFalse = ConditionalPartial<{ foo: string }, false>; - const testConditionalPartialFalseValid: TestConditionalPartialFalse = { foo: 'bar' }; + expectTypeOf().toEqualTypeOf<{ foo: string }>(); }); it('should not compile an empty object when the condition is false', () => { type TestConditionalPartialFalse = ConditionalPartial<{ foo: string }, false>; // @ts-expect-error: 'foo' is required but missing - const testConditionalPartialFalseInvalid: TestConditionalPartialFalse = {}; + expectTypeOf().toEqualTypeOf<{}>(); }); it('should not compile when the first argument is not an indexable type', () => { // @ts-expect-error - string is not an object type TestConditionalPartialFalse = ConditionalPartial; + expectTypeOf().toEqualTypeOf(); }); }); describe('PickOptional', () => { - it('should compile when the optional property is present', () => { - type TestPickOptional = PickOptional<{ foo?: string }>; - const testPickOptionalValid: TestPickOptional = { foo: 'bar' }; + it('should return the optional property', () => { + type TestPickOptional = PickOptional<{ foo?: string; bar: string }>; + expectTypeOf().toEqualTypeOf<{ foo?: string }>(); }); it('should not compile when the optional property is the wrong type', () => { - type TestPickOptional = PickOptional<{ foo?: string }>; + type TestPickOptional = PickOptional<{ foo?: string; bar: string }>; // @ts-expect-error - foo should be a string - const testPickOptionalInvalid: TestPickOptional = { foo: 123 }; - }); - - it('should compile when the optional property is not present', () => { - type TestPickOptional = PickOptional<{ foo?: string }>; - const testPickOptionalValid: TestPickOptional = {}; + expectTypeOf().toEqualTypeOf<{ foo: 123 }>(); }); it('should not compile when specifying a required property', () => { type TestPickOptional = PickOptional<{ foo?: string; bar: string }>; // @ts-expect-error - bar should not be present - const testPickOptionalInvalid: TestPickOptional = { bar: 'bar' }; + expectTypeOf().toEqualTypeOf<{ foo?: string; bar: string }>(); }); }); describe('PickOptionalKeys', () => { - it('should compile when the optional property is present', () => { + it('should return the optional property', () => { type TestPickOptionalKeys = PickOptionalKeys<{ foo?: string }>; - const testPickOptionalKeysValid: TestPickOptionalKeys = 'foo'; + expectTypeOf().toEqualTypeOf<'foo'>(); }); - it('should not compile when the object has no optional properties', () => { + it('should return never when the object has no optional properties', () => { type TestPickOptionalKeys = PickOptionalKeys<{ foo: string }>; - // @ts-expect-error - no optional property is present - const testPickOptionalKeysInvalid: TestPickOptionalKeys = 'invalid'; + expectTypeOf().toEqualTypeOf(); }); }); describe('PickRequired', () => { - it('should compile when the required property is present', () => { + it('should return the required property', () => { type TestPickRequired = PickRequired<{ foo: string }>; - const testPickRequiredValid: TestPickRequired = { foo: 'bar' }; + expectTypeOf().toEqualTypeOf<{ foo: string }>(); }); it('should not compile when the required property is the wrong type', () => { type TestPickRequired = PickRequired<{ foo: string }>; // @ts-expect-error - foo should be a string - const testPickRequiredInvalid: TestPickRequired = { foo: 123 }; + expectTypeOf().toEqualTypeOf<{ foo: 123 }>(); }); it('should not compile when the required property is not present', () => { type TestPickRequired = PickRequired<{ foo: string }>; // @ts-expect-error - foo should be present - const testPickRequiredInvalid: TestPickRequired = {}; + expectTypeOf().toEqualTypeOf<{}>(); }); it('should not compile when specifying an optional property', () => { type TestPickRequired = PickRequired<{ foo?: string; bar: string }>; // @ts-expect-error - foo should not be present - const testPickRequiredInvalid: TestPickRequired = { foo: 'bar', bar: 'bar' }; + expectTypeOf().toEqualTypeOf<{ foo: string; bar: string }>(); }); }); describe('PickRequiredKeys', () => { - it('should compile when the object is empty', () => { + it('should return the required property', () => { type TestPickRequiredKeys = PickRequiredKeys<{ foo: string }>; - const testPickRequiredKeysValid: TestPickRequiredKeys = 'foo'; + expectTypeOf().toEqualTypeOf<'foo'>(); }); - it('should not compile when the object has no required properties', () => { + it('should return never when the object has no required properties', () => { type TestPickRequiredKeys = PickRequiredKeys<{ foo?: string }>; - // @ts-expect-error - no required property is present - const testPickRequiredKeysInvalid: TestPickRequiredKeys = 'invalid'; + expectTypeOf().toEqualTypeOf(); }); }); describe('Prettify', () => { - it('should compile the prettified type to the identity type', () => { + it('should return the identity type', () => { type TestPrettify = Prettify<{ foo: string }>; - const testPrettifyValid: TestPrettify = { foo: 'bar' }; + expectTypeOf().toEqualTypeOf<{ foo: string }>(); }); it('should not compile when the object has incorrect properties', () => { type TestPrettify = Prettify<{ foo: string }>; // @ts-expect-error - foo should be a string - const testPrettifyInvalid: TestPrettify = { foo: 123 }; + expectTypeOf().toEqualTypeOf<{ foo: 123 }>(); }); }); describe('DeepPartial', () => { it('should make a top-level property optional', () => { type TestDeepPartial = DeepPartial<{ foo: string }>; - const testDeepPartialValid: TestDeepPartial = { foo: undefined }; + expectTypeOf().toEqualTypeOf<{ foo?: string }>(); }); it('should make a nested property optional', () => { type TestDeepPartial = DeepPartial<{ foo: { bar: string } }>; - const testDeepPartialValid: TestDeepPartial = { foo: { bar: undefined } }; + expectTypeOf().toEqualTypeOf<{ foo?: { bar?: string } }>(); }); }); describe('DeepRequired', () => { it('should make a top-level property required', () => { type TestDeepRequired = DeepRequired<{ foo?: string }>; - const testDeepRequiredValid: TestDeepRequired = { foo: 'bar' }; + expectTypeOf().toEqualTypeOf<{ foo: string }>(); }); it('should make a nested object property required', () => { type TestDeepRequired = DeepRequired<{ foo: { bar?: string } }>; - const testDeepRequiredValid: TestDeepRequired = { foo: { bar: 'bar' } }; + expectTypeOf().toEqualTypeOf<{ foo: { bar: string } }>(); }); it('should make a nested array property required', () => { type TestDeepRequired = DeepRequired<{ foo: { bar: (string | undefined)[] } }>; - const testDeepRequiredValid: TestDeepRequired = { foo: { bar: ['bar'] } }; + expectTypeOf().toEqualTypeOf<{ foo: { bar: string[] } }>(); }); it('should not compile when the array has incorrect properties', () => { type TestDeepRequired = DeepRequired<{ foo: { bar: (string | undefined)[] } }>; // @ts-expect-error - bar should be an array of strings - const testDeepRequiredInvalid: TestDeepRequired = { foo: { bar: [undefined] } }; + expectTypeOf().toEqualTypeOf<{ foo: { bar: undefined[] } }>(); }); it('should not compile when the object has incorrect properties', () => { type TestDeepRequired = DeepRequired<{ foo: string }>; // @ts-expect-error - foo should be a string - const testDeepRequiredInvalid: TestDeepRequired = { foo: 123 }; + expectTypeOf().toEqualTypeOf<{ foo: 123 }>(); + }); +}); + +describe('UnionToTuple', () => { + it('should return a tuple of the union types', () => { + type TestUnionToTuple = UnionToTuple<1 | 2 | 3>; + expectTypeOf().toEqualTypeOf<[1, 2, 3]>(); }); }); + +describe('Stringify', () => { + it('should stringify a string type', () => { + type TestStringify = Stringify; + expectTypeOf().toEqualTypeOf<'string'>(); + }); + + it('should stringify a boolean type', () => { + type TestStringify = Stringify; + expectTypeOf().toEqualTypeOf<'boolean'>(); + }); + + it('should stringify a number type', () => { + type TestStringify = Stringify; + expectTypeOf().toEqualTypeOf<'number'>(); + }); + + it('should stringify a bigint type', () => { + type TestStringify = Stringify; + expectTypeOf().toEqualTypeOf<'bigint'>(); + }); + + it('should stringify an unknown type', () => { + type TestStringify = Stringify; + expectTypeOf().toEqualTypeOf<'unknown'>(); + }); + + it('should stringify an undefined type', () => { + type TestStringify = Stringify; + expectTypeOf().toEqualTypeOf<'undefined'>(); + }); + + it('should stringify a null type', () => { + type TestStringify = Stringify; + expectTypeOf().toEqualTypeOf<'null'>(); + }); + + it('should stringify a symbol type', () => { + type TestStringify = Stringify; + expectTypeOf().toEqualTypeOf<'symbol'>(); + }); + + it('should stringify an array type', () => { + type TestStringify = Stringify>; + expectTypeOf().toEqualTypeOf<'string[]'>(); + }); + + it('should stringify an empty object type', () => { + type TestStringify = Stringify<{}>; + expectTypeOf().toEqualTypeOf<'{}'>(); + }); + + it('should stringify an `object` type', () => { + type TestStringify = Stringify; + expectTypeOf().toEqualTypeOf<'{}'>(); + }); + + it('should stringify a `Record` type', () => { + type TestStringify = Stringify>; + expectTypeOf().toEqualTypeOf<'{ [x: string]: never; }'>(); + }); + + it('should stringify a `Record` type', () => { + type TestType = Record; + type TestKey = keyof TestType; + type TestStringify = Stringify; + expectTypeOf().toEqualTypeOf<'{ [x: string]: string; }'>(); + }); + + it('should stringify a `{ [x: string]: string }` type', () => { + type TestType = { + [x: string]: string; + }; + type TestKey = keyof TestType; + type TestStringify = Stringify; + expectTypeOf().toEqualTypeOf<'{ [x: string]: string; }'>(); + }); + + it('should stringify a `{ [x: string]: unknown }` type', () => { + type TestStringify = Stringify<{ + [x: string]: unknown; + }>; + expectTypeOf().toEqualTypeOf<'{ [x: string]: unknown; }'>(); + }); + + it('should stringify a `Record` type', () => { + type TestStringify = Stringify>; + expectTypeOf().toEqualTypeOf<'{ [x: string]: unknown; }'>(); + }); + + it('should stringify an array of empty object types', () => { + type TestStringify = Stringify>; + expectTypeOf().toEqualTypeOf<'{}[]'>(); + }); + + it('should stringify an object type with a single required property', () => { + type TestStringify = Stringify<{ foo: string }>; + expectTypeOf().toEqualTypeOf<'{ foo: string; }'>(); + }); + + it('should stringify an object type with a single optional property', () => { + type TestStringify = Stringify<{ foo?: string }>; + expectTypeOf().toEqualTypeOf<'{ foo?: string; }'>(); + }); + + it('should stringify an object type with multiple properties', () => { + type TestStringify = Stringify<{ foo: string; bar?: number }>; + expectTypeOf().toEqualTypeOf<'{ foo: string; bar?: number; }'>(); + }); + + it('should stringify an object type with a nested object property', () => { + type TestStringify = Stringify<{ foo: { bar: string } }>; + expectTypeOf().toEqualTypeOf<'{ foo: { bar: string; }; }'>(); + }); + + it('should stringify an object type with an array property', () => { + type TestStringify = Stringify<{ foo: { bar: string }[] }>; + expectTypeOf().toEqualTypeOf<'{ foo: { bar: string; }[]; }'>(); + }); + + it('should stringify an array of unknown record types', () => { + type TestStringify = Stringify< + { + [x: string]: unknown; + }[] + >; + expectTypeOf().toEqualTypeOf<'{ [x: string]: unknown; }[]'>(); + }); +}); + +type Test = Prettify>; + +type test3 = keyof Test; + +type test2 = unknown extends unknown ? true : false; + +type test4 = Stringify<{ foo: never }>; + +type RecordString = Stringify>; + +type Test5 = keyof { + [x: string]: unknown; +}; diff --git a/packages/framework/src/types/util.types.ts b/packages/framework/src/types/util.types.ts index 0e5fc0a8f9a..fd8d9a63067 100644 --- a/packages/framework/src/types/util.types.ts +++ b/packages/framework/src/types/util.types.ts @@ -24,7 +24,11 @@ export type Prettify = { [K in keyof T]: T[K] } & {}; /** * Mark properties of T as optional if Condition is true */ -export type ConditionalPartial = Condition extends true ? Partial : T; +export type ConditionalPartial = T extends Obj + ? Condition extends true + ? Partial + : T + : never; /** * Same as Nullable except without `null`. @@ -107,3 +111,134 @@ export type DeepRequired = T extends object [P in keyof T]-?: DeepRequired; } : T; + +// https://github.com/type-challenges/type-challenges/issues/737 +/** + * Convert union type T to an intersection type. + */ +type UnionToIntersection = (T extends unknown ? (x: T) => unknown : never) extends (x: infer U) => unknown + ? U + : never; + +/* + * Get the last union type in a union T. + * + * ((x: A) => unknown) & ((x: B) => unknown) is overloaded function then Conditional types are inferred only from the last overload + * @see https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#type-inference-in-conditional-types + * + * + * @example + * ```ts + * type Test = LastUnion<1 | 2>; // => 2 + * ``` + */ +type LastUnion = + UnionToIntersection unknown : never> extends (x: infer L) => unknown ? L : never; + +/** + * Convert a union type to a tuple. + */ +export type UnionToTuple> = [T] extends [never] ? [] : [...UnionToTuple>, Last]; + +/** + * Stringify type T to a string. Useful for error messages. + * + * Each built-in type is exhaustively handled to produce a string representation. + * + * @example + * ```ts + * type Test = Stringify; + * // => 'string' + * ``` + * + * @example + * ```ts + * type Test = Stringify<{ foo: string; bar?: number }>; + * // => '{ foo: string; bar?: number }' + * ``` + * + * @example + * ```ts + * type Test = Stringify>; + * // => 'unknown[]' + * ``` + */ +export type Stringify = T extends string + ? 'string' + : T extends number + ? 'number' + : T extends boolean + ? 'boolean' + : T extends bigint + ? 'bigint' + : T extends symbol + ? 'symbol' + : T extends null + ? 'null' + : T extends undefined + ? 'undefined' + : T extends Array + ? `${Stringify}[]` + : T extends Obj + ? `{${DeepStringifyObject}}` + : T extends unknown + ? 'unknown' + : // Fallback to `never` for unknown types + 'never'; + +/** + * Known types that can be used to stringify a type. + */ +type KnownTypes = string | number | boolean | bigint | symbol | undefined | null | Array | Obj; + +type UnknownKey = '[x: string]'; + +/** + * Stringify the properties of a record type. + */ +type DeepStringifyObject = + // If T has no keys, return an empty string + keyof T extends never + ? '' + : // Convert the keys of T into a tuple and destructure it into the first key (U) and the rest (Rest) + UnionToTuple extends [infer U, ...infer Rest] + ? ` ${ + // If U is a string, construct the string representation of the key-value pair + U extends keyof T & string + ? `${ + // If the value is a known type, use the key directly. Otherwise, use a "[key: string]" fallback. Never is handled separately because it is omitted in a union of known types + T[U] extends KnownTypes ? (T[U] extends never ? UnknownKey : U) : UnknownKey + }${ + // Check if the value extends undefined + undefined extends T[U] + ? // Check if the value extends a known type + T[U] extends KnownTypes + ? // If the value extends a known type, add a "?" to the end of the key + '?' + : // Otherwise, the value is not a known type, so we can't add a "?" + '' + : // The value didn't extend undefined, so no "?" is needed + '' + }: ${ + // If the value is `never`, return `never` + T[U] extends never + ? 'never' + : // Stringify the value, excluding undefined if necessary + Stringify< + // Check if the value is optional + Exclude extends never + ? // If the value was explicitly undefined, return undefined + undefined + : // Otherwise, remove undefined from the type as it's already handled with the "?" + Exclude + > + };${ + // Add a space if there are no more keys to process in the object + Rest extends [] ? ' ' : '' + }` + : '' + }${ + // Recursively process the rest of the keys, excluding string, number, and symbol to handle cases like `{ [x: string]: unknown }` whose keys are `string | number` + DeepStringifyObject> + }` + : never; From 52886b10a37dc42a5fb67696466addac6edc4b5c Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Tue, 3 Dec 2024 01:56:18 +0200 Subject: [PATCH 50/56] refactor(workflow): improve data type coercion --- packages/framework/src/resources/workflow/workflow.resource.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/framework/src/resources/workflow/workflow.resource.ts b/packages/framework/src/resources/workflow/workflow.resource.ts index 56e70b28f19..62d9c5b3c78 100644 --- a/packages/framework/src/resources/workflow/workflow.resource.ts +++ b/packages/framework/src/resources/workflow/workflow.resource.ts @@ -46,7 +46,7 @@ export function workflow< throw new WorkflowPayloadInvalidError(workflowId, validationResult.errors); } // Coerce the validated data to handle unknown matching to SchemaError - validatedData = validationResult.data as unknown as T_PayloadValidated; + validatedData = validationResult.data as Record as T_PayloadValidated; } else { // This type coercion provides support to trigger Workflows without a payload schema validatedData = event.payload as unknown as T_PayloadValidated; From bb552b8154f33d2ec26bb738877c94e96f1c631a Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Tue, 3 Dec 2024 02:52:50 +0200 Subject: [PATCH 51/56] refactor(utils): relocate checkIsResponseError function --- packages/framework/src/utils/http.utils.ts | 2 +- packages/framework/src/utils/platform.utils.ts | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 packages/framework/src/utils/platform.utils.ts diff --git a/packages/framework/src/utils/http.utils.ts b/packages/framework/src/utils/http.utils.ts index 361e57c5cfa..342c346ea79 100644 --- a/packages/framework/src/utils/http.utils.ts +++ b/packages/framework/src/utils/http.utils.ts @@ -1,4 +1,4 @@ -import { checkIsResponseError } from '@novu/shared'; +import { checkIsResponseError } from './platform.utils'; import { BridgeError, MissingSecretKeyError, PlatformError } from '../errors'; export const initApiClient = (secretKey: string, apiUrl: string) => { diff --git a/packages/framework/src/utils/platform.utils.ts b/packages/framework/src/utils/platform.utils.ts new file mode 100644 index 00000000000..3c7303c21e8 --- /dev/null +++ b/packages/framework/src/utils/platform.utils.ts @@ -0,0 +1,8 @@ +import type { IResponseError } from '@novu/shared'; + +/** + * Validate (type-guard) that an error response matches our IResponseError interface. + */ +export const checkIsResponseError = (err: unknown): err is IResponseError => { + return !!err && typeof err === 'object' && 'error' in err && 'message' in err && 'statusCode' in err; +}; From 52e70840cc7cbb7162665c28623d91c82dca1262 Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Tue, 3 Dec 2024 03:06:32 +0200 Subject: [PATCH 52/56] refactor(types): update test and stringify logic --- .../framework/src/types/util.types.test-d.ts | 44 +++++-------------- packages/framework/src/types/util.types.ts | 32 +++++++++++--- 2 files changed, 36 insertions(+), 40 deletions(-) diff --git a/packages/framework/src/types/util.types.test-d.ts b/packages/framework/src/types/util.types.test-d.ts index 88d52bc9e40..46c5cbbbcdf 100644 --- a/packages/framework/src/types/util.types.test-d.ts +++ b/packages/framework/src/types/util.types.test-d.ts @@ -215,8 +215,10 @@ describe('DeepRequired', () => { describe('UnionToTuple', () => { it('should return a tuple of the union types', () => { - type TestUnionToTuple = UnionToTuple<1 | 2 | 3>; - expectTypeOf().toEqualTypeOf<[1, 2, 3]>(); + type TestUnionToTuple = UnionToTuple<1 | 2>; + // UnionToTuple can return items in any order, so we need to check that the array contains the expected items + type Parts = 1 | 2; + expectTypeOf().toMatchTypeOf<[Parts, Parts]>(); }); }); @@ -282,25 +284,17 @@ describe('Stringify', () => { }); it('should stringify a `Record` type', () => { - type TestType = Record; - type TestKey = keyof TestType; - type TestStringify = Stringify; + type TestStringify = Stringify>; expectTypeOf().toEqualTypeOf<'{ [x: string]: string; }'>(); }); it('should stringify a `{ [x: string]: string }` type', () => { - type TestType = { - [x: string]: string; - }; - type TestKey = keyof TestType; - type TestStringify = Stringify; + type TestStringify = Stringify<{ [x: string]: string }>; expectTypeOf().toEqualTypeOf<'{ [x: string]: string; }'>(); }); it('should stringify a `{ [x: string]: unknown }` type', () => { - type TestStringify = Stringify<{ - [x: string]: unknown; - }>; + type TestStringify = Stringify<{ [x: string]: unknown }>; expectTypeOf().toEqualTypeOf<'{ [x: string]: unknown; }'>(); }); @@ -326,7 +320,9 @@ describe('Stringify', () => { it('should stringify an object type with multiple properties', () => { type TestStringify = Stringify<{ foo: string; bar?: number }>; - expectTypeOf().toEqualTypeOf<'{ foo: string; bar?: number; }'>(); + // The order of the properties is not guaranteed, so we need to check that the string matches the expected pattern + type Parts = `foo: string;` | `bar?: number;`; + expectTypeOf().toMatchTypeOf<`{ ${Parts} ${Parts} }`>(); }); it('should stringify an object type with a nested object property', () => { @@ -340,25 +336,7 @@ describe('Stringify', () => { }); it('should stringify an array of unknown record types', () => { - type TestStringify = Stringify< - { - [x: string]: unknown; - }[] - >; + type TestStringify = Stringify<{ [x: string]: unknown }[]>; expectTypeOf().toEqualTypeOf<'{ [x: string]: unknown; }[]'>(); }); }); - -type Test = Prettify>; - -type test3 = keyof Test; - -type test2 = unknown extends unknown ? true : false; - -type test4 = Stringify<{ foo: never }>; - -type RecordString = Stringify>; - -type Test5 = keyof { - [x: string]: unknown; -}; diff --git a/packages/framework/src/types/util.types.ts b/packages/framework/src/types/util.types.ts index fd8d9a63067..ab770d9d979 100644 --- a/packages/framework/src/types/util.types.ts +++ b/packages/framework/src/types/util.types.ts @@ -191,6 +191,23 @@ export type Stringify = T extends string */ type KnownTypes = string | number | boolean | bigint | symbol | undefined | null | Array | Obj; +/** + * Check if T is a dictionary type. + * + * @example + * ```ts + * type Test1 = IsDictionary>; // true + * type Test2 = IsDictionary>; // true + * type Test3 = IsDictionary<{ [x: string]: string }>; // true + * type Test4 = IsDictionary<{ [x: string]: unknown }>; // true + * type Test5 = IsDictionary<{ foo: string }>; // false + * ``` + */ +type IsDictionary = string extends keyof T ? true : false; + +/** + * The key used when the key is for a dictionary type. + */ type UnknownKey = '[x: string]'; /** @@ -206,24 +223,25 @@ type DeepStringifyObject = // If U is a string, construct the string representation of the key-value pair U extends keyof T & string ? `${ - // If the value is a known type, use the key directly. Otherwise, use a "[key: string]" fallback. Never is handled separately because it is omitted in a union of known types - T[U] extends KnownTypes ? (T[U] extends never ? UnknownKey : U) : UnknownKey + // Build the key. If T is a dictionary, use "[key: string]" as the key. Otherwise, use the key directly. + IsDictionary extends true ? UnknownKey : U }${ - // Check if the value extends undefined + // Build the optional "?" indicator. Check if the value extends undefined undefined extends T[U] ? // Check if the value extends a known type T[U] extends KnownTypes ? // If the value extends a known type, add a "?" to the end of the key '?' - : // Otherwise, the value is not a known type, so we can't add a "?" + : // Otherwise, the value is not a known type (i.e. `unknown`), so we don't add a "?" '' : // The value didn't extend undefined, so no "?" is needed '' }: ${ - // If the value is `never`, return `never` + // Build the value. T[U] extends never - ? 'never' - : // Stringify the value, excluding undefined if necessary + ? // If the value is `never`, return `never` + 'never' + : // Otherwise, stringify the value, excluding undefined if necessary Stringify< // Check if the value is optional Exclude extends never From d14be7509ea0972ca95a06b11cd2bf856a46551f Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Tue, 3 Dec 2024 03:08:30 +0200 Subject: [PATCH 53/56] build: exclude shared from circular check --- packages/framework/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/framework/package.json b/packages/framework/package.json index e168cbf278d..c9de25d2303 100644 --- a/packages/framework/package.json +++ b/packages/framework/package.json @@ -38,7 +38,7 @@ "build:watch": "tsup --watch", "postbuild": "pnpm run check:exports && pnpm check:circulars", "check:exports": "attw --pack .", - "check:circulars": "madge --circular --extensions ts ./src", + "check:circulars": "madge --circular --extensions ts --exclude ../../shared ./src", "$comment:bump:prerelease": "This is a workaround to support `npm version prerelease` with lerna", "bump:prerelease": "npm version prerelease --preid=alpha & PID=$!; (sleep 1 && kill -9 $PID) & wait $PID", "release:alpha": "pnpm bump:prerelease || pnpm build && npm publish", From 53dad235d1cdeba389af9e0a04a77b15b3684b8f Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Tue, 3 Dec 2024 03:28:49 +0200 Subject: [PATCH 54/56] refactor(schema): update SchemaError message wording --- .../src/resources/workflow/workflow.resource.test-d.ts | 4 ++-- .../src/types/schema.types/base.schema.types.test-d.ts | 8 ++++---- .../framework/src/types/schema.types/base.schema.types.ts | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/framework/src/resources/workflow/workflow.resource.test-d.ts b/packages/framework/src/resources/workflow/workflow.resource.test-d.ts index 51d33997332..3d792217f9b 100644 --- a/packages/framework/src/resources/workflow/workflow.resource.test-d.ts +++ b/packages/framework/src/resources/workflow/workflow.resource.test-d.ts @@ -116,7 +116,7 @@ describe('workflow function types', () => { 'without-schema', async (controls) => { expectTypeOf(controls).toEqualTypeOf<{ - SchemaError: "Schema must describe an object data structure. Got data type: 'string'"; + SchemaError: "Schema must describe an object data structure. Received data type: 'string'"; }>(); return { @@ -138,7 +138,7 @@ describe('workflow function types', () => { 'without-schema', async (controls) => { expectTypeOf(controls).toEqualTypeOf<{ - SchemaError: `Schema must describe an object data structure. Got data type: 'string[]'`; + SchemaError: `Schema must describe an object data structure. Received data type: 'string[]'`; }>(); return { diff --git a/packages/framework/src/types/schema.types/base.schema.types.test-d.ts b/packages/framework/src/types/schema.types/base.schema.types.test-d.ts index cf28e027005..24adb460740 100644 --- a/packages/framework/src/types/schema.types/base.schema.types.test-d.ts +++ b/packages/framework/src/types/schema.types/base.schema.types.test-d.ts @@ -28,7 +28,7 @@ describe('FromSchema', () => { type Test = FromSchema; expectTypeOf().toEqualTypeOf<{ - SchemaError: `Schema must describe an object data structure. Got data type: 'string'`; + SchemaError: `Schema must describe an object data structure. Received data type: 'string'`; }>(); }); @@ -37,7 +37,7 @@ describe('FromSchema', () => { type Test = FromSchema; expectTypeOf().toEqualTypeOf<{ - SchemaError: `Schema must describe an object data structure. Got data type: 'string[]'`; + SchemaError: `Schema must describe an object data structure. Received data type: 'string[]'`; }>(); }); @@ -49,7 +49,7 @@ describe('FromSchema', () => { type Test = FromSchema; expectTypeOf().toEqualTypeOf<{ - SchemaError: `Schema must describe an object data structure. Got data type: '{ [x: string]: unknown; }[]'`; + SchemaError: `Schema must describe an object data structure. Received data type: '{ [x: string]: unknown; }[]'`; }>(); }); @@ -61,7 +61,7 @@ describe('FromSchema', () => { type Test = FromSchema; expectTypeOf().toEqualTypeOf<{ - SchemaError: `Schema must describe an object data structure. Got data type: 'unknown[]'`; + SchemaError: `Schema must describe an object data structure. Received data type: 'unknown[]'`; }>(); }); diff --git a/packages/framework/src/types/schema.types/base.schema.types.ts b/packages/framework/src/types/schema.types/base.schema.types.ts index 39c990c52e6..7d7d84b2383 100644 --- a/packages/framework/src/types/schema.types/base.schema.types.ts +++ b/packages/framework/src/types/schema.types/base.schema.types.ts @@ -39,7 +39,7 @@ type InferSchema = U : // The schema describes a non-record type, return an error message. { - SchemaError: `Schema must describe an object data structure. Got data type: '${Stringify}'`; + SchemaError: `Schema must describe an object data structure. Received data type: '${Stringify}'`; } : never; From 905f6a5c9d282e616e8555ce03b9a21c859e1755 Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Tue, 3 Dec 2024 03:36:58 +0200 Subject: [PATCH 55/56] docs: Fix typos in schema inference comments --- .../framework/src/types/schema.types/base.schema.types.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/framework/src/types/schema.types/base.schema.types.ts b/packages/framework/src/types/schema.types/base.schema.types.ts index 7d7d84b2383..f4f1b3c3134 100644 --- a/packages/framework/src/types/schema.types/base.schema.types.ts +++ b/packages/framework/src/types/schema.types/base.schema.types.ts @@ -23,7 +23,7 @@ type InferSchema = * Use a distributive conditional type to detect if all inferred types are `never`. * When all inferred types are `never`, return an unknown record. * - * Each schema inferrence must return `never` type when: + * Each schema inference must return `never` type when: * - The schema is generic (i.e. not a concrete schema type) * - The schema is not supported (i.e. tried to specify `string` as the schema type) * - The schema is undefined @@ -33,7 +33,7 @@ type InferSchema = [U] extends [never] ? // When all inferred types are `never`, return an unknown record. Record - : // The type inferrence did not return `never`. Ensure the inferred type is a record type, as only objects are supported. + : // The type inference did not return `never`. Ensure the inferred type is a record type, as only objects are supported. U extends Record ? // Got a record type, return it. U From 49cc45d434e18970582bb5ca4cd35a2c49113de6 Mon Sep 17 00:00:00 2001 From: Richard Fontein <32132657+rifont@users.noreply.github.com> Date: Tue, 3 Dec 2024 03:49:40 +0200 Subject: [PATCH 56/56] style(validator): fix import extensions warnings --- .../framework/src/validators/class-validator.validator.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/framework/src/validators/class-validator.validator.ts b/packages/framework/src/validators/class-validator.validator.ts index 631fb879b87..f098ca0ce15 100644 --- a/packages/framework/src/validators/class-validator.validator.ts +++ b/packages/framework/src/validators/class-validator.validator.ts @@ -86,7 +86,8 @@ export class ClassValidatorValidator implements Validator { name: 'class-transformer', // @ts-expect-error - class-transformer doesn't export `defaultMetadataStorage` from the root module - import: import('class-transformer/cjs/storage'), + // eslint-disable-next-line import/extensions + import: import('class-transformer/cjs/storage.js'), exports: ['defaultMetadataStorage'], }, { @@ -147,7 +148,8 @@ export class ClassValidatorValidator implements Validator * @see https://github.com/typestack/class-transformer/issues/563#issuecomment-803262394 */ // @ts-expect-error - class-transformer doesn't export `defaultMetadataStorage` from the root module - const { defaultMetadataStorage } = await import('class-transformer/cjs/storage'); + // eslint-disable-next-line import/extensions + const { defaultMetadataStorage } = await import('class-transformer/cjs/storage.js'); const { getMetadataStorage } = await import('class-validator'); const { validationMetadatasToSchemas, targetConstructorToSchema } = await import('class-validator-jsonschema');