diff --git a/packages/action-menu/package.json b/packages/action-menu/package.json index dcdcf82172..210b84232d 100644 --- a/packages/action-menu/package.json +++ b/packages/action-menu/package.json @@ -3,9 +3,7 @@ "main": "build/index", "types": "build/index", "version": "0.4.2", - "files": [ - "build" - ], + "files": ["build"], "license": "Apache-2.0", "publishConfig": { "access": "public" @@ -25,12 +23,10 @@ }, "dependencies": { "@credo-ts/core": "0.4.2", - "class-transformer": "0.5.1", - "class-validator": "0.14.1", - "rxjs": "^7.2.0" + "zod": "^3.22.4" }, "devDependencies": { - "reflect-metadata": "^0.1.13", + "rxjs": "^7.2.0", "rimraf": "^4.4.0", "typescript": "~4.9.5" } diff --git a/packages/action-menu/src/ActionMenuEvents.ts b/packages/action-menu/src/ActionMenuEvents.ts index 31ae0c1774..ec791f132e 100644 --- a/packages/action-menu/src/ActionMenuEvents.ts +++ b/packages/action-menu/src/ActionMenuEvents.ts @@ -1,5 +1,5 @@ import type { ActionMenuState } from './ActionMenuState' -import type { ActionMenuRecord } from './repository' +import type ActionMenuRecord from './repository' import type { BaseEvent } from '@credo-ts/core' /** diff --git a/packages/action-menu/src/messages/MenuMessage.ts b/packages/action-menu/src/messages/MenuMessage.ts index 808b6ba465..61f5ed9a9f 100644 --- a/packages/action-menu/src/messages/MenuMessage.ts +++ b/packages/action-menu/src/messages/MenuMessage.ts @@ -1,60 +1,43 @@ -import type { ActionMenuOptionOptions } from '../models' - -import { AgentMessage, IsValidMessageType, parseMessageType } from '@credo-ts/core' -import { Expose, Type } from 'class-transformer' -import { IsInstance, IsOptional, IsString } from 'class-validator' +import { AgentMessage, parseMessageType, utils } from '@credo-ts/core' +import { z } from 'zod' import { ActionMenuOption } from '../models' +import { actionMenuOptionSchema } from '../models/ActionMenuOption' +import { arrIntoCls } from '../models/ActionMenuOptionForm' + +const menuMessageSchema = z + .object({ + id: z.string().default(utils.uuid()), + title: z.string(), + description: z.string(), + errormsg: z.string().optional(), + options: z.array(actionMenuOptionSchema).transform(arrIntoCls(ActionMenuOption)), + threadId: z.string().optional(), + }) + .transform((o) => ({ + ...o, + errorMessage: o.errormsg, + })) + +export type MenuMessageOptions = z.input -/** - * @internal - */ -export interface MenuMessageOptions { - id?: string - title: string - description: string - errorMessage?: string - options: ActionMenuOptionOptions[] - threadId?: string -} - -/** - * @internal - */ export class MenuMessage extends AgentMessage { - public constructor(options: MenuMessageOptions) { - super() - - if (options) { - this.id = options.id ?? this.generateId() - this.title = options.title - this.description = options.description - this.errorMessage = options.errorMessage - this.options = options.options.map((p) => new ActionMenuOption(p)) - if (options.threadId) { - this.setThread({ - threadId: options.threadId, - }) - } - } - } - - @IsValidMessageType(MenuMessage.type) public readonly type = MenuMessage.type.messageTypeUri public static readonly type = parseMessageType('https://didcomm.org/action-menu/1.0/menu') - @IsString() - public title!: string - - @IsString() - public description!: string - - @Expose({ name: 'errormsg' }) - @IsString() - @IsOptional() + public title: string + public description: string public errorMessage?: string + public options: Array - @IsInstance(ActionMenuOption, { each: true }) - @Type(() => ActionMenuOption) - public options!: ActionMenuOption[] + public constructor(options: MenuMessageOptions) { + super() + + const parsedOptions = menuMessageSchema.parse(options) + this.id = parsedOptions.id + this.title = parsedOptions.title + this.description = parsedOptions.description + this.errorMessage = parsedOptions.errorMessage + this.options = parsedOptions.options + } } diff --git a/packages/action-menu/src/messages/PerformMessage.ts b/packages/action-menu/src/messages/PerformMessage.ts index a62331aa15..ca995da8c8 100644 --- a/packages/action-menu/src/messages/PerformMessage.ts +++ b/packages/action-menu/src/messages/PerformMessage.ts @@ -1,41 +1,33 @@ -import { AgentMessage, IsValidMessageType, parseMessageType } from '@credo-ts/core' -import { IsOptional, IsString } from 'class-validator' +import { AgentMessage, parseMessageType, utils } from '@credo-ts/core' +import { z } from 'zod' -/** - * @internal - */ -export interface PerformMessageOptions { - id?: string - name: string - params?: Record - threadId: string -} +const performMessageSchema = z.object({ + id: z.string().default(utils.uuid()), -/** - * @internal - */ -export class PerformMessage extends AgentMessage { - public constructor(options: PerformMessageOptions) { - super() + // TODO(zod): validate the name like is done in `@IsValidMessageType(PerformMessage.type)` + name: z.string(), + params: z.record(z.string()).optional(), + threadId: z.string(), +}) - if (options) { - this.id = options.id ?? this.generateId() - this.name = options.name - this.params = options.params - this.setThread({ - threadId: options.threadId, - }) - } - } +export type PerformMessageOptions = z.input - @IsValidMessageType(PerformMessage.type) +export class PerformMessage extends AgentMessage { public readonly type = PerformMessage.type.messageTypeUri public static readonly type = parseMessageType('https://didcomm.org/action-menu/1.0/perform') - @IsString() - public name!: string - - @IsString({ each: true }) - @IsOptional() + public name: string public params?: Record + + public constructor(options: PerformMessageOptions) { + super() + + const parsedOptions = performMessageSchema.parse(options) + this.id = parsedOptions.id + this.name = parsedOptions.name + this.params = parsedOptions.params + this.setThread({ + threadId: parsedOptions.threadId, + }) + } } diff --git a/packages/action-menu/src/models/ActionMenu.ts b/packages/action-menu/src/models/ActionMenu.ts index 9e241693e3..bdb30e3269 100644 --- a/packages/action-menu/src/models/ActionMenu.ts +++ b/packages/action-menu/src/models/ActionMenu.ts @@ -1,38 +1,25 @@ -import type { ActionMenuOptionOptions } from './ActionMenuOption' +import { z } from 'zod' -import { Type } from 'class-transformer' -import { IsInstance, IsString } from 'class-validator' +import { ActionMenuOption, actionMenuOptionSchema } from './ActionMenuOption' +import { arrIntoCls } from './ActionMenuOptionForm' -import { ActionMenuOption } from './ActionMenuOption' +export const actionMenuSchema = z.object({ + title: z.string(), + description: z.string(), + options: z.array(actionMenuOptionSchema).transform(arrIntoCls(ActionMenuOption)), +}) -/** - * @public - */ -export interface ActionMenuOptions { - title: string - description: string - options: ActionMenuOptionOptions[] -} +export type ActionMenuOptions = z.input -/** - * @public - */ export class ActionMenu { + public title: string + public description: string + public options: Array + public constructor(options: ActionMenuOptions) { - if (options) { - this.title = options.title - this.description = options.description - this.options = options.options.map((p) => new ActionMenuOption(p)) - } + const parsedOptions = actionMenuSchema.parse(options) + this.title = parsedOptions.title + this.description = parsedOptions.description + this.options = parsedOptions.options } - - @IsString() - public title!: string - - @IsString() - public description!: string - - @IsInstance(ActionMenuOption, { each: true }) - @Type(() => ActionMenuOption) - public options!: ActionMenuOption[] } diff --git a/packages/action-menu/src/models/ActionMenuOption.ts b/packages/action-menu/src/models/ActionMenuOption.ts index ce283c9473..4786d41102 100644 --- a/packages/action-menu/src/models/ActionMenuOption.ts +++ b/packages/action-menu/src/models/ActionMenuOption.ts @@ -1,52 +1,30 @@ -import type { ActionMenuFormOptions } from './ActionMenuOptionForm' +import { z } from 'zod' -import { Type } from 'class-transformer' -import { IsBoolean, IsInstance, IsOptional, IsString } from 'class-validator' +import { ActionMenuForm, actionMenuFormSchema, intoOptCls } from './ActionMenuOptionForm' -import { ActionMenuForm } from './ActionMenuOptionForm' +export const actionMenuOptionSchema = z.object({ + name: z.string(), + title: z.string(), + description: z.string(), + disabled: z.boolean().optional(), + form: actionMenuFormSchema.optional().transform(intoOptCls(ActionMenuForm)), +}) -/** - * @public - */ -export interface ActionMenuOptionOptions { - name: string - title: string - description: string - disabled?: boolean - form?: ActionMenuFormOptions -} +export type ActionMenuOptionOptions = z.input -/** - * @public - */ export class ActionMenuOption { - public constructor(options: ActionMenuOptionOptions) { - if (options) { - this.name = options.name - this.title = options.title - this.description = options.description - this.disabled = options.disabled - if (options.form) { - this.form = new ActionMenuForm(options.form) - } - } - } - - @IsString() - public name!: string - - @IsString() - public title!: string - - @IsString() - public description!: string - - @IsBoolean() - @IsOptional() + public name: string + public title: string + public description: string public disabled?: boolean - - @IsInstance(ActionMenuForm) - @Type(() => ActionMenuForm) - @IsOptional() public form?: ActionMenuForm + + public constructor(options: ActionMenuOptionOptions) { + const parsedOptions = actionMenuOptionSchema.parse(options) + this.name = parsedOptions.name + this.title = parsedOptions.title + this.description = parsedOptions.description + this.disabled = parsedOptions.disabled + this.form = parsedOptions.form + } } diff --git a/packages/action-menu/src/models/ActionMenuOptionForm.ts b/packages/action-menu/src/models/ActionMenuOptionForm.ts index 3c9f4e1e08..ef8b07bc13 100644 --- a/packages/action-menu/src/models/ActionMenuOptionForm.ts +++ b/packages/action-menu/src/models/ActionMenuOptionForm.ts @@ -1,39 +1,39 @@ -import type { ActionMenuFormParameterOptions } from './ActionMenuOptionFormParameter' +import { z } from 'zod' -import { Expose, Type } from 'class-transformer' -import { IsInstance, IsString } from 'class-validator' +import { ActionMenuFormParameter, actionMenuFormParameterSchema } from './ActionMenuOptionFormParameter' -import { ActionMenuFormParameter } from './ActionMenuOptionFormParameter' +// TODO(zod): these should not have any ts-expect-error and should return the type based on `Cls` input, not the generic +export const intoCls = + (Cls: unknown) => + (i: unknown): T => + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error + new Cls(i) +export const arrIntoCls = + (Cls: unknown) => + (o: Array): Array => + o.map(intoCls(Cls)) +export const intoOptCls = + (Cls: unknown) => + (i?: unknown): undefined | T => + i ? intoCls(Cls)(i) : undefined -/** - * @public - */ -export interface ActionMenuFormOptions { - description: string - params: ActionMenuFormParameterOptions[] - submitLabel: string -} +export const actionMenuFormSchema = z.object({ + description: z.string(), + params: z + .array(actionMenuFormParameterSchema) + .transform(arrIntoCls(ActionMenuFormParameter)), +}) + +export type ActionMenuFormOptions = z.input -/** - * @public - */ export class ActionMenuForm { + public description: string + public params: Array + public constructor(options: ActionMenuFormOptions) { - if (options) { - this.description = options.description - this.params = options.params.map((p) => new ActionMenuFormParameter(p)) - this.submitLabel = options.submitLabel - } + const parsedOptions = actionMenuFormSchema.parse(options) + this.description = parsedOptions.description + this.params = parsedOptions.params } - - @IsString() - public description!: string - - @Expose({ name: 'submit-label' }) - @IsString() - public submitLabel!: string - - @IsInstance(ActionMenuFormParameter, { each: true }) - @Type(() => ActionMenuFormParameter) - public params!: ActionMenuFormParameter[] } diff --git a/packages/action-menu/src/models/ActionMenuOptionFormParameter.ts b/packages/action-menu/src/models/ActionMenuOptionFormParameter.ts index dfcce82848..d0d8c43c6e 100644 --- a/packages/action-menu/src/models/ActionMenuOptionFormParameter.ts +++ b/packages/action-menu/src/models/ActionMenuOptionFormParameter.ts @@ -1,57 +1,35 @@ -import { IsBoolean, IsEnum, IsOptional, IsString } from 'class-validator' +import { z } from 'zod' -/** - * @public - */ export enum ActionMenuFormInputType { Text = 'text', } -/** - * @public - */ -export interface ActionMenuFormParameterOptions { - name: string - title: string - default?: string - description: string - required?: boolean - type?: ActionMenuFormInputType -} - -/** - * @public - */ -export class ActionMenuFormParameter { - public constructor(options: ActionMenuFormParameterOptions) { - if (options) { - this.name = options.name - this.title = options.title - this.default = options.default - this.description = options.description - this.required = options.required - this.type = options.type - } - } - - @IsString() - public name!: string +export const actionMenuFormParameterSchema = z.object({ + name: z.string(), + title: z.string(), + description: z.string(), + default: z.string().optional(), + required: z.boolean().optional(), + type: z.nativeEnum(ActionMenuFormInputType), +}) - @IsString() - public title!: string +export type ActionMenuFormParameterOptions = z.input - @IsString() - @IsOptional() +export class ActionMenuFormParameter { + public name: string + public title: string + public description: string public default?: string - - @IsString() - public description!: string - - @IsBoolean() - @IsOptional() public required?: boolean + public type: ActionMenuFormInputType - @IsEnum(ActionMenuFormInputType) - @IsOptional() - public type?: ActionMenuFormInputType + public constructor(options: ActionMenuFormParameterOptions) { + const parsedOptions = actionMenuFormParameterSchema.parse(options) + this.name = parsedOptions.name + this.title = parsedOptions.title + this.description = parsedOptions.description + this.default = parsedOptions.default + this.required = parsedOptions.required + this.type = parsedOptions.type + } } diff --git a/packages/action-menu/src/models/ActionMenuSelection.ts b/packages/action-menu/src/models/ActionMenuSelection.ts index f25c361b41..ac3a2c8986 100644 --- a/packages/action-menu/src/models/ActionMenuSelection.ts +++ b/packages/action-menu/src/models/ActionMenuSelection.ts @@ -1,28 +1,19 @@ -import { IsOptional, IsString } from 'class-validator' +import { z } from 'zod' -/** - * @public - */ -export interface ActionMenuSelectionOptions { - name: string - params?: Record -} +export const actionMenuSelectionSchema = z.object({ + name: z.string(), + params: z.record(z.string()).optional(), +}) + +export type ActionMenuSelectionOptions = z.input -/** - * @public - */ export class ActionMenuSelection { + public name: string + public params?: Record + public constructor(options: ActionMenuSelectionOptions) { - if (options) { - this.name = options.name - this.params = options.params - } + const parsedOptions = actionMenuSelectionSchema.parse(options) + this.name = parsedOptions.name + this.params = parsedOptions.params } - - @IsString() - public name!: string - - @IsString({ each: true }) - @IsOptional() - public params?: Record } diff --git a/packages/action-menu/src/models/index.ts b/packages/action-menu/src/models/index.ts index 15c8673f52..fb61c41ef5 100644 --- a/packages/action-menu/src/models/index.ts +++ b/packages/action-menu/src/models/index.ts @@ -1,5 +1,9 @@ -export * from './ActionMenu' -export * from './ActionMenuOption' -export * from './ActionMenuOptionForm' -export * from './ActionMenuOptionFormParameter' -export * from './ActionMenuSelection' +export { ActionMenu, ActionMenuOptions } from './ActionMenu' +export { ActionMenuOption, ActionMenuOptionOptions } from './ActionMenuOption' +export { ActionMenuForm, ActionMenuFormOptions } from './ActionMenuOptionForm' +export { + ActionMenuFormParameter, + ActionMenuFormParameterOptions, + ActionMenuFormInputType, +} from './ActionMenuOptionFormParameter' +export { ActionMenuSelection, ActionMenuSelectionOptions } from './ActionMenuSelection' diff --git a/packages/action-menu/src/repository/ActionMenuRecord.ts b/packages/action-menu/src/repository/ActionMenuRecord.ts index dec713d894..d92a7fe5ff 100644 --- a/packages/action-menu/src/repository/ActionMenuRecord.ts +++ b/packages/action-menu/src/repository/ActionMenuRecord.ts @@ -1,31 +1,37 @@ -import type { ActionMenuRole } from '../ActionMenuRole' -import type { ActionMenuState } from '../ActionMenuState' -import type { TagsBase } from '@credo-ts/core' - import { CredoError, BaseRecord, utils } from '@credo-ts/core' -import { Type } from 'class-transformer' +import { z } from 'zod' -import { ActionMenuSelection, ActionMenu } from '../models' +import { ActionMenuRole } from '../ActionMenuRole' +import { ActionMenuState } from '../ActionMenuState' +import { ActionMenu, ActionMenuSelection } from '../models' +import { actionMenuSchema } from '../models/ActionMenu' +import { intoOptCls } from '../models/ActionMenuOptionForm' +import { actionMenuSelectionSchema } from '../models/ActionMenuSelection' -/** - * @public - */ -export interface ActionMenuRecordProps { - id?: string - state: ActionMenuState - role: ActionMenuRole - createdAt?: Date - connectionId: string - threadId: string - menu?: ActionMenu - performedAction?: ActionMenuSelection - tags?: CustomActionMenuTags -} +// TODO(zod): figure out how we can set the key type on a `z.record()` +const tagsBaseSchema = z.record( + z.string(), + z.union([z.string(), z.boolean(), z.undefined(), z.array(z.string()), z.null()]) +) +const customActionMenuTagsSchema = tagsBaseSchema -/** - * @public - */ -export type CustomActionMenuTags = TagsBase +const recordSchema = z.object({ + id: z.string().default(utils.uuid()), + createdAt: z.date().default(new Date()), +}) + +const actionMenuRecordSchema = recordSchema.extend({ + state: z.nativeEnum(ActionMenuState), + role: z.nativeEnum(ActionMenuRole), + connectionId: z.string(), + threadId: z.string(), + menu: actionMenuSchema.optional().transform(intoOptCls(ActionMenu)), + performedAction: actionMenuSelectionSchema.optional().transform(intoOptCls(ActionMenuSelection)), + tags: customActionMenuTagsSchema.optional(), +}) + +export type ActionMenuRecordOptions = z.input +export type CustomActionMenuTags = z.input /** * @public @@ -36,41 +42,30 @@ export type DefaultActionMenuTags = { threadId: string } -/** - * @public - */ -export class ActionMenuRecord - extends BaseRecord - implements ActionMenuRecordProps -{ - public state!: ActionMenuState - public role!: ActionMenuRole - public connectionId!: string - public threadId!: string +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-expect-error +export class ActionMenuRecord extends BaseRecord { + public static readonly type = 'ActionMenuRecord' + public readonly type = ActionMenuRecord.type - @Type(() => ActionMenu) + public state: ActionMenuState + public role: ActionMenuRole + public connectionId: string + public threadId: string public menu?: ActionMenu - - @Type(() => ActionMenuSelection) public performedAction?: ActionMenuSelection - public static readonly type = 'ActionMenuRecord' - public readonly type = ActionMenuRecord.type - - public constructor(props: ActionMenuRecordProps) { + public constructor(options: ActionMenuRecordOptions) { super() - if (props) { - this.id = props.id ?? utils.uuid() - this.createdAt = props.createdAt ?? new Date() - this.connectionId = props.connectionId - this.threadId = props.threadId - this.state = props.state - this.role = props.role - this.menu = props.menu - this.performedAction = props.performedAction - this._tags = props.tags ?? {} - } + const parsedOptions = actionMenuRecordSchema.parse(options) + this.id = parsedOptions.id + this.state = parsedOptions.state + this.role = parsedOptions.role + this.connectionId = parsedOptions.connectionId + this.threadId = parsedOptions.threadId + this.menu = parsedOptions.menu + this.performedAction = parsedOptions.performedAction } public getTags() { diff --git a/packages/action-menu/src/services/ActionMenuService.ts b/packages/action-menu/src/services/ActionMenuService.ts index d3810a9d90..91d747b6bf 100644 --- a/packages/action-menu/src/services/ActionMenuService.ts +++ b/packages/action-menu/src/services/ActionMenuService.ts @@ -18,7 +18,7 @@ import { ActionMenuProblemReportError } from '../errors/ActionMenuProblemReportE import { ActionMenuProblemReportReason } from '../errors/ActionMenuProblemReportReason' import { PerformMessage, MenuMessage, MenuRequestMessage } from '../messages' import { ActionMenuSelection, ActionMenu } from '../models' -import { ActionMenuRepository, ActionMenuRecord } from '../repository' +import { ActionMenuRecord, ActionMenuRepository } from '../repository' /** * @internal diff --git a/packages/action-menu/src/services/ActionMenuServiceOptions.ts b/packages/action-menu/src/services/ActionMenuServiceOptions.ts index dc2d85c0ad..0f341d3bf4 100644 --- a/packages/action-menu/src/services/ActionMenuServiceOptions.ts +++ b/packages/action-menu/src/services/ActionMenuServiceOptions.ts @@ -1,7 +1,7 @@ import type { ActionMenuRole } from '../ActionMenuRole' import type { ActionMenuSelection } from '../models' import type { ActionMenu } from '../models/ActionMenu' -import type { ActionMenuRecord } from '../repository' +import type ActionMenuRecord from '../repository' import type { ConnectionRecord } from '@credo-ts/core' /** diff --git a/packages/action-menu/tests/action-menu.test.ts b/packages/action-menu/tests/action-menu.test.ts index 134887830c..5e9414f0fe 100644 --- a/packages/action-menu/tests/action-menu.test.ts +++ b/packages/action-menu/tests/action-menu.test.ts @@ -6,7 +6,7 @@ import { makeConnection, testLogger, setupSubjectTransports, getInMemoryAgentOpt import { waitForActionMenuRecord } from './helpers' -import { ActionMenu, ActionMenuModule, ActionMenuRecord, ActionMenuRole, ActionMenuState } from '@credo-ts/action-menu' +import ActionMenuRecord, { ActionMenu, ActionMenuModule, ActionMenuRole, ActionMenuState } from '@credo-ts/action-menu' const modules = { actionMenu: new ActionMenuModule(), diff --git a/packages/action-menu/tests/setup.ts b/packages/action-menu/tests/setup.ts index 78143033f2..34e38c9705 100644 --- a/packages/action-menu/tests/setup.ts +++ b/packages/action-menu/tests/setup.ts @@ -1,3 +1 @@ -import 'reflect-metadata' - jest.setTimeout(120000) diff --git a/packages/core/src/storage/BaseRecord.ts b/packages/core/src/storage/BaseRecord.ts index 7f26952200..5e1a97e9e7 100644 --- a/packages/core/src/storage/BaseRecord.ts +++ b/packages/core/src/storage/BaseRecord.ts @@ -28,7 +28,7 @@ export abstract class BaseRecord< // We want an empty object, as Record will make typescript // not infer the types correctly // eslint-disable-next-line @typescript-eslint/ban-types - MetadataValues = {} + MetadataValues = {}, > { protected _tags: CustomTags = {} as CustomTags @@ -95,13 +95,15 @@ export abstract class BaseRecord< } public toJSON(): Record { - return JsonTransformer.toJSON(this) + // TODO: convert to JSON with zod, should be quite easy + return { ...this } as Record } /** * Clones the record. */ public clone() { - return JsonTransformer.clone(this) + // TODO: clone with zod, should be quite easy + return { ...this } } } diff --git a/tests/InMemoryStorageService.ts b/tests/InMemoryStorageService.ts index 2fb57419c3..1e3dc876e1 100644 --- a/tests/InMemoryStorageService.ts +++ b/tests/InMemoryStorageService.ts @@ -32,6 +32,10 @@ export class InMemoryStorageService = BaseRe public contextCorrelationIdToRecords: ContextCorrelationIdToRecords = {} private recordToInstance(record: StorageRecord, recordClass: BaseRecordConstructor): T { + // TODO(zod): temporary transformation as the rest still uses class-transformer + if (recordClass.name === 'ActionMenuRecord') { + return new recordClass(record.value) + } const instance = JsonTransformer.fromJSON(record.value, recordClass) instance.id = record.id instance.replaceTags(record.tags as TagsBase) diff --git a/yarn.lock b/yarn.lock index bed0f87ff1..54cfadf719 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12213,3 +12213,8 @@ yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +zod@^3.22.4: + version "3.22.4" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.22.4.tgz#f31c3a9386f61b1f228af56faa9255e845cf3fff" + integrity sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==