From 86a785c70b5010f1004823f3c6110dbe3973790c Mon Sep 17 00:00:00 2001
From: Piotr Roslaniec
Date: Mon, 21 Aug 2023 13:38:26 +0200
Subject: [PATCH 1/3] feat!: add typed conditions api
---
package.json | 6 +-
src/conditions/base/condition.ts | 49 -----
src/conditions/base/contract.ts | 155 ++++++++--------
src/conditions/base/index.ts | 47 ++++-
src/conditions/base/return-value.ts | 29 ---
src/conditions/base/rpc.ts | 57 +++---
src/conditions/base/time.ts | 30 ++-
src/conditions/compound-condition.ts | 47 ++---
src/conditions/condition-expr.ts | 54 +++---
src/conditions/condition.ts | 68 +++++++
src/conditions/const.ts | 9 -
src/conditions/context/context.ts | 2 +-
src/conditions/context/index.ts | 3 +-
src/conditions/index.ts | 16 +-
src/conditions/predefined/erc721.ts | 45 +++--
src/index.ts | 4 +-
src/utils.ts | 4 -
test/docs/cbd.test.ts | 8 +-
test/integration/enrico.test.ts | 2 +-
test/integration/pre.test.ts | 2 +-
test/unit/conditions/base/condition.test.ts | 45 +++--
test/unit/conditions/base/contract.test.ts | 174 +++++++++++-------
test/unit/conditions/base/rpc.test.ts | 28 +--
test/unit/conditions/base/time.test.ts | 49 +++--
.../conditions/compound-condition.test.ts | 124 ++++++++-----
test/unit/conditions/condition-expr.test.ts | 61 +-----
test/unit/conditions/context.test.ts | 6 +-
test/unit/testVariables.ts | 21 ++-
yarn.lock | 125 +++++++++----
29 files changed, 697 insertions(+), 573 deletions(-)
delete mode 100644 src/conditions/base/condition.ts
delete mode 100644 src/conditions/base/return-value.ts
create mode 100644 src/conditions/condition.ts
diff --git a/package.json b/package.json
index 0da9ef763..76fade158 100644
--- a/package.json
+++ b/package.json
@@ -35,7 +35,7 @@
"test:lint": "eslint src test --ext .ts",
"test:exports": "ts-unused-exports tsconfig.json --ignoreFiles src/index.ts",
"test:prettier": "prettier \"src/**/*.ts\" \"test/**/*.ts\" --list-different",
- "test:unit": "jest --detectOpenHandles --forceExit --runInBand",
+ "test:unit": "jest --detectOpenHandles --forceExit",
"watch:build": "tsc -p tsconfig.json -w",
"watch:test": "jest --watch",
"cov": "run-s build test:unit && open-cli coverage/index.html",
@@ -56,9 +56,9 @@
"axios": "^1.5.0",
"deep-equal": "^2.2.1",
"ethers": "^5.7.2",
- "joi": "^17.10.0",
"qs": "^6.10.1",
- "semver": "^7.5.2"
+ "semver": "^7.5.2",
+ "zod": "^3.22.1"
},
"devDependencies": {
"@babel/core": "^7.22.11",
diff --git a/src/conditions/base/condition.ts b/src/conditions/base/condition.ts
deleted file mode 100644
index d77fb587e..000000000
--- a/src/conditions/base/condition.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-import Joi from 'joi';
-
-import { objectEquals } from '../../utils';
-import { USER_ADDRESS_PARAM } from '../const';
-
-type Map = Record;
-
-export class Condition {
- public readonly schema = Joi.object();
- public readonly defaults: Map = {};
-
- constructor(private readonly value: Record = {}) {}
-
- public validate(override: Map = {}) {
- const newValue = {
- ...this.defaults,
- ...this.value,
- ...override,
- };
- return this.schema.validate(newValue);
- }
-
- public requiresSigner(): boolean {
- return JSON.stringify(this.value).includes(USER_ADDRESS_PARAM);
- }
-
- public toObj(): Map {
- const { error, value } = this.validate(this.value);
- if (error) {
- throw `Invalid condition: ${error.message}`;
- }
- return {
- ...value,
- };
- }
-
- public static fromObj(
- // We disable the eslint rule here because we have to pass args to the constructor
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- this: new (...args: any[]) => T,
- obj: Map
- ): T {
- return new this(obj);
- }
-
- public equals(other: Condition) {
- return objectEquals(this, other);
- }
-}
diff --git a/src/conditions/base/contract.ts b/src/conditions/base/contract.ts
index c4221e1da..44f13c9d4 100644
--- a/src/conditions/base/contract.ts
+++ b/src/conditions/base/contract.ts
@@ -1,87 +1,90 @@
import { ethers } from 'ethers';
-import Joi from 'joi';
+import { z } from 'zod';
import { ETH_ADDRESS_REGEXP } from '../const';
-import { RpcCondition, rpcConditionRecord } from './rpc';
+import { rpcConditionSchema } from './rpc';
-export const STANDARD_CONTRACT_TYPES = ['ERC20', 'ERC721'];
+// TODO: Consider replacing with `z.unknown`:
+// Since Solidity types are tied to Solidity version, we may not be able to accurately represent them in Zod.
+// Alternatively, find a TS Solidity type lib.
+const EthBaseTypes: [string, ...string[]] = [
+ 'bool',
+ 'string',
+ 'address',
+ ...Array.from({ length: 32 }, (_v, i) => `bytes${i + 1}`), // bytes1 through bytes32
+ 'bytes',
+ ...Array.from({ length: 32 }, (_v, i) => `uint${8 * (i + 1)}`), // uint8 through uint256
+ ...Array.from({ length: 32 }, (_v, i) => `int${8 * (i + 1)}`), // int8 through int256
+];
-const functionAbiSchema = Joi.object({
- name: Joi.string().required(),
- type: Joi.string().valid('function').required(),
- inputs: Joi.array(),
- outputs: Joi.array(),
- stateMutability: Joi.string().valid('view', 'pure').required(),
-}).custom((functionAbi, helper) => {
- // Is `functionABI` a valid function fragment?
- let asInterface;
- try {
- asInterface = new ethers.utils.Interface([functionAbi]);
- } catch (e: unknown) {
- const { message } = e as Error;
- return helper.message({
- custom: message,
- });
- }
+const functionAbiVariableSchema = z
+ .object({
+ name: z.string(),
+ type: z.enum(EthBaseTypes),
+ internalType: z.enum(EthBaseTypes), // TODO: Do we need to validate this?
+ })
+ .strict();
- if (!asInterface.functions) {
- return helper.message({
- custom: '"functionAbi" is missing a function fragment',
- });
- }
+const functionAbiSchema = z
+ .object({
+ name: z.string(),
+ type: z.literal('function'),
+ inputs: z.array(functionAbiVariableSchema).min(0),
+ outputs: z.array(functionAbiVariableSchema).nonempty(),
+ stateMutability: z.union([z.literal('view'), z.literal('pure')]),
+ })
+ .strict()
+ .refine(
+ (functionAbi) => {
+ let asInterface;
+ try {
+ // `stringify` here because ethers.utils.Interface doesn't accept a Zod schema
+ asInterface = new ethers.utils.Interface(JSON.stringify([functionAbi]));
+ } catch (e) {
+ return false;
+ }
- if (Object.values(asInterface.functions).length !== 1) {
- return helper.message({
- custom: '"functionAbi" must contain exactly one function fragment',
- });
- }
+ const functionsInAbi = Object.values(asInterface.functions || {});
+ return functionsInAbi.length === 1;
+ },
+ {
+ message: '"functionAbi" must contain a single function definition',
+ }
+ )
+ .refine(
+ (functionAbi) => {
+ const asInterface = new ethers.utils.Interface(
+ JSON.stringify([functionAbi])
+ );
+ const nrOfInputs = asInterface.fragments[0].inputs.length;
+ return functionAbi.inputs.length === nrOfInputs;
+ },
+ {
+ message: '"parameters" must have the same length as "functionAbi.inputs"',
+ }
+ );
- // Now we just need to validate against the parent schema
- // Validate method name
- const method = helper.state.ancestors[0].method;
+export type FunctionAbiProps = z.infer;
- let functionFragment;
- try {
- functionFragment = asInterface.getFunction(method);
- } catch (e) {
- return helper.message({
- custom: `"functionAbi" has no matching function for "${method}"`,
- });
- }
+export const contractConditionSchema = rpcConditionSchema
+ .extend({
+ conditionType: z.literal('contract').default('contract'),
+ contractAddress: z.string().regex(ETH_ADDRESS_REGEXP),
+ standardContractType: z.enum(['ERC20', 'ERC721']).optional(),
+ method: z.string(),
+ functionAbi: functionAbiSchema.optional(),
+ parameters: z.array(z.unknown()),
+ })
+ // Adding this custom logic causes the return type to be ZodEffects instead of ZodObject
+ // https://github.com/colinhacks/zod/issues/2474
+ .refine(
+ // A check to see if either 'standardContractType' or 'functionAbi' is set
+ (data) => Boolean(data.standardContractType) !== Boolean(data.functionAbi),
+ {
+ message:
+ "At most one of the fields 'standardContractType' and 'functionAbi' must be defined",
+ }
+ );
- if (!functionFragment) {
- return helper.message({
- custom: `"functionAbi" not valid for method: "${method}"`,
- });
- }
-
- // Validate nr of parameters
- const parameters = helper.state.ancestors[0].parameters;
- if (functionFragment.inputs.length !== parameters.length) {
- return helper.message({
- custom: '"parameters" must have the same length as "functionAbi.inputs"',
- });
- }
-
- return functionAbi;
-});
-
-export const contractConditionRecord = {
- ...rpcConditionRecord,
- contractAddress: Joi.string().pattern(ETH_ADDRESS_REGEXP).required(),
- standardContractType: Joi.string()
- .valid(...STANDARD_CONTRACT_TYPES)
- .optional(),
- method: Joi.string().required(),
- functionAbi: functionAbiSchema.optional(),
- parameters: Joi.array().required(),
-};
-
-export const contractConditionSchema = Joi.object(contractConditionRecord)
- // At most one of these keys needs to be present
- .xor('standardContractType', 'functionAbi');
-
-export class ContractCondition extends RpcCondition {
- public readonly schema = contractConditionSchema;
-}
+export type ContractConditionProps = z.infer;
diff --git a/src/conditions/base/index.ts b/src/conditions/base/index.ts
index 805717e01..a6a0abe36 100644
--- a/src/conditions/base/index.ts
+++ b/src/conditions/base/index.ts
@@ -1,4 +1,43 @@
-export { Condition } from './condition';
-export { ContractCondition } from './contract';
-export { RpcCondition } from './rpc';
-export { TimeCondition } from './time';
+import {
+ CompoundConditionProps,
+ compoundConditionSchema,
+} from '../compound-condition';
+import { Condition } from '../condition';
+
+import { ContractConditionProps, contractConditionSchema } from './contract';
+import { RpcConditionProps, rpcConditionSchema } from './rpc';
+import { TimeConditionProps, timeConditionSchema } from './time';
+
+// Exporting classes here instead of their respective schema files to
+// avoid circular dependency on Condition class.
+
+export class CompoundCondition extends Condition {
+ constructor(value: CompoundConditionProps) {
+ super(compoundConditionSchema, value);
+ }
+}
+
+export class ContractCondition extends Condition {
+ constructor(value: ContractConditionProps) {
+ super(contractConditionSchema, value);
+ }
+}
+
+export class RpcCondition extends Condition {
+ constructor(value: RpcConditionProps) {
+ super(rpcConditionSchema, value);
+ }
+}
+
+export class TimeCondition extends Condition {
+ constructor(value: TimeConditionProps) {
+ super(timeConditionSchema, value);
+ }
+}
+
+export {
+ contractConditionSchema,
+ type ContractConditionProps,
+} from './contract';
+export { rpcConditionSchema, type RpcConditionProps } from './rpc';
+export { timeConditionSchema, type TimeConditionProps } from './time';
diff --git a/src/conditions/base/return-value.ts b/src/conditions/base/return-value.ts
deleted file mode 100644
index 544033cdc..000000000
--- a/src/conditions/base/return-value.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import Joi from 'joi';
-
-import { ETH_ADDRESS_REGEXP, USER_ADDRESS_PARAM } from '../const';
-
-const COMPARATORS = ['==', '>', '<', '>=', '<=', '!='];
-
-export interface ReturnValueTestConfig {
- index?: number;
- comparator: string;
- value: string | number;
-}
-
-export const returnValueTestSchema: Joi.ObjectSchema =
- Joi.object({
- index: Joi.number().optional(),
- comparator: Joi.string()
- .valid(...COMPARATORS)
- .required(),
- value: Joi.alternatives(
- Joi.string(),
- Joi.number(),
- Joi.boolean()
- ).required(),
- });
-
-export const ethAddressOrUserAddressSchema = Joi.alternatives(
- Joi.string().pattern(ETH_ADDRESS_REGEXP),
- USER_ADDRESS_PARAM
-);
diff --git a/src/conditions/base/rpc.ts b/src/conditions/base/rpc.ts
index 27ed5f0b7..2b16d7823 100644
--- a/src/conditions/base/rpc.ts
+++ b/src/conditions/base/rpc.ts
@@ -1,39 +1,30 @@
-import Joi from 'joi';
+import { z } from 'zod';
-import { SUPPORTED_CHAINS } from '../const';
+import { ETH_ADDRESS_REGEXP, USER_ADDRESS_PARAM } from '../const';
-import { Condition } from './condition';
-import {
- ethAddressOrUserAddressSchema,
- returnValueTestSchema,
-} from './return-value';
+export const returnValueTestSchema = z.object({
+ index: z.number().optional(),
+ comparator: z.enum(['==', '>', '<', '>=', '<=', '!=']),
+ value: z.union([z.string(), z.number(), z.boolean()]),
+});
-const rpcMethodSchemas: Record = {
- eth_getBalance: Joi.array().items(ethAddressOrUserAddressSchema).required(),
- balanceOf: Joi.array().items(ethAddressOrUserAddressSchema).required(),
-};
+export type ReturnValueTestProps = z.infer;
-const makeParameters = () =>
- Joi.array().when('method', {
- switch: Object.keys(rpcMethodSchemas).map((method) => ({
- is: method,
- then: rpcMethodSchemas[method],
- })),
- });
+const EthAddressOrUserAddressSchema = z.array(
+ z.union([z.string().regex(ETH_ADDRESS_REGEXP), z.literal(USER_ADDRESS_PARAM)])
+);
-export const rpcConditionRecord = {
- chain: Joi.number()
- .valid(...SUPPORTED_CHAINS)
- .required(),
- method: Joi.string()
- .valid(...Object.keys(rpcMethodSchemas))
- .required(),
- parameters: makeParameters(),
- returnValueTest: returnValueTestSchema.required(),
-};
+export const rpcConditionSchema = z.object({
+ conditionType: z.literal('rpc').default('rpc'),
+ chain: z.union([
+ z.literal(137),
+ z.literal(80001),
+ z.literal(5),
+ z.literal(1),
+ ]),
+ method: z.enum(['eth_getBalance', 'balanceOf']),
+ parameters: EthAddressOrUserAddressSchema,
+ returnValueTest: returnValueTestSchema,
+});
-export const rpcConditionSchema = Joi.object(rpcConditionRecord);
-
-export class RpcCondition extends Condition {
- public readonly schema = rpcConditionSchema;
-}
+export type RpcConditionProps = z.infer;
diff --git a/src/conditions/base/time.ts b/src/conditions/base/time.ts
index 4f4671dd0..0196b728c 100644
--- a/src/conditions/base/time.ts
+++ b/src/conditions/base/time.ts
@@ -1,23 +1,15 @@
-import Joi from 'joi';
+import { z } from 'zod';
-import { omit } from '../../utils';
+import { rpcConditionSchema } from './rpc';
-import { RpcCondition, rpcConditionRecord } from './rpc';
+// TimeCondition is an RpcCondition with the method set to 'blocktime' and no parameters
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+const { parameters: _, ...restShape } = rpcConditionSchema.shape;
-export const BLOCKTIME_METHOD = 'blocktime';
+export const timeConditionSchema = z.object({
+ ...restShape,
+ conditionType: z.literal('time').default('time'),
+ method: z.literal('blocktime').default('blocktime'),
+});
-export const timeConditionRecord: Record = {
- // TimeCondition is an RpcCondition with the method set to 'blocktime' and no parameters
- ...omit(rpcConditionRecord, ['parameters']),
- method: Joi.string().valid(BLOCKTIME_METHOD).required(),
-};
-
-export const timeConditionSchema = Joi.object(timeConditionRecord);
-
-export class TimeCondition extends RpcCondition {
- public readonly defaults: Record = {
- method: BLOCKTIME_METHOD,
- };
-
- public readonly schema = timeConditionSchema;
-}
+export type TimeConditionProps = z.infer;
diff --git a/src/conditions/compound-condition.ts b/src/conditions/compound-condition.ts
index 3b35f675a..33c137a99 100644
--- a/src/conditions/compound-condition.ts
+++ b/src/conditions/compound-condition.ts
@@ -1,31 +1,24 @@
-import Joi from 'joi';
+import { z } from 'zod';
-import { Condition } from './base';
-import { contractConditionSchema } from './base/contract';
-import { rpcConditionSchema } from './base/rpc';
-import { timeConditionSchema } from './base/time';
+import { contractConditionSchema } from './base';
+import { rpcConditionSchema } from './base';
+import { timeConditionSchema } from './base';
-const OR_OPERATOR = 'or';
-const AND_OPERATOR = 'and';
-
-const LOGICAL_OPERATORS = [AND_OPERATOR, OR_OPERATOR];
-
-export const compoundConditionSchema = Joi.object({
- operator: Joi.string()
- .valid(...LOGICAL_OPERATORS)
- .required(),
- operands: Joi.array()
- .min(2)
- .items(
- rpcConditionSchema,
- timeConditionSchema,
- contractConditionSchema,
- Joi.link('#compoundCondition')
+export const compoundConditionSchema: z.ZodSchema = z.object({
+ conditionType: z.literal('compound').default('compound'),
+ operator: z.enum(['and', 'or']),
+ operands: z
+ .array(
+ z.lazy(() =>
+ z.union([
+ rpcConditionSchema,
+ timeConditionSchema,
+ contractConditionSchema,
+ compoundConditionSchema,
+ ])
+ )
)
- .required()
- .valid(),
-}).id('compoundCondition');
+ .min(2),
+});
-export class CompoundCondition extends Condition {
- public readonly schema = compoundConditionSchema;
-}
+export type CompoundConditionProps = z.infer;
diff --git a/src/conditions/condition-expr.ts b/src/conditions/condition-expr.ts
index a8fcb6be8..99358f84c 100644
--- a/src/conditions/condition-expr.ts
+++ b/src/conditions/condition-expr.ts
@@ -2,16 +2,19 @@ import { Conditions as WASMConditions } from '@nucypher/nucypher-core';
import { ethers } from 'ethers';
import { SemVer } from 'semver';
-import { objectEquals, toBytes, toJSON } from '../utils';
+import { toBytes, toJSON } from '../utils';
import {
- Condition,
+ CompoundCondition,
ContractCondition,
+ ContractConditionProps,
RpcCondition,
+ RpcConditionProps,
TimeCondition,
+ TimeConditionProps,
} from './base';
-import { BLOCKTIME_METHOD } from './base/time';
-import { CompoundCondition } from './compound-condition';
+import { CompoundConditionProps } from './compound-condition';
+import { Condition, ConditionProps } from './condition';
import { ConditionContext, CustomContextParam } from './context';
export type ConditionExpressionJSON = {
@@ -28,13 +31,28 @@ export class ConditionExpression {
) {}
public toObj(): ConditionExpressionJSON {
- const conditionData = this.condition.toObj();
+ const condition = this.condition.toObj();
return {
version: this.version,
- condition: conditionData,
+ condition,
};
}
+ private static conditionFromObject(obj: ConditionProps): Condition {
+ switch (obj.conditionType) {
+ case 'rpc':
+ return new RpcCondition(obj as RpcConditionProps);
+ case 'time':
+ return new TimeCondition(obj as TimeConditionProps);
+ case 'contract':
+ return new ContractCondition(obj as ContractConditionProps);
+ case 'compound':
+ return new CompoundCondition(obj as CompoundConditionProps);
+ default:
+ throw new Error(`Invalid conditionType: ${obj.conditionType}`);
+ }
+ }
+
public static fromObj(obj: ConditionExpressionJSON): ConditionExpression {
const receivedVersion = new SemVer(obj.version);
const currentVersion = new SemVer(ConditionExpression.VERSION);
@@ -44,31 +62,15 @@ export class ConditionExpression {
);
}
- const underlyingConditionData = obj.condition;
- let condition: Condition | undefined;
-
- if (underlyingConditionData.operator) {
- condition = new CompoundCondition(underlyingConditionData);
- } else if (underlyingConditionData.method) {
- if (underlyingConditionData.method === BLOCKTIME_METHOD) {
- condition = new TimeCondition(underlyingConditionData);
- } else if (underlyingConditionData.contractAddress) {
- condition = new ContractCondition(underlyingConditionData);
- } else if (
- (underlyingConditionData.method as string).startsWith('eth_')
- ) {
- condition = new RpcCondition(underlyingConditionData);
- }
- }
-
- if (!condition) {
+ if (!obj.condition) {
throw new Error(
`Invalid condition: unrecognized condition data ${JSON.stringify(
- underlyingConditionData
+ obj.condition
)}`
);
}
+ const condition = this.conditionFromObject(obj.condition as ConditionProps);
return new ConditionExpression(condition, obj.version);
}
@@ -108,7 +110,7 @@ export class ConditionExpression {
public equals(other: ConditionExpression): boolean {
return [
this.version === other.version,
- objectEquals(this.condition.toObj(), other.condition.toObj()),
+ this.condition.equals(other.condition),
].every(Boolean);
}
}
diff --git a/src/conditions/condition.ts b/src/conditions/condition.ts
new file mode 100644
index 000000000..fe957bf32
--- /dev/null
+++ b/src/conditions/condition.ts
@@ -0,0 +1,68 @@
+import { z } from 'zod';
+
+import { objectEquals } from '../utils';
+
+import {
+ ContractConditionProps,
+ RpcConditionProps,
+ TimeConditionProps,
+} from './base';
+import { CompoundConditionProps } from './compound-condition';
+import { USER_ADDRESS_PARAM } from './const';
+
+// Not using discriminated union because of inconsistent Zod types
+// Some conditions have ZodEffect types because of .refine() calls
+export type ConditionProps =
+ | RpcConditionProps
+ | TimeConditionProps
+ | ContractConditionProps
+ | CompoundConditionProps;
+
+export class Condition {
+ constructor(
+ public readonly schema: z.ZodSchema,
+ public readonly value:
+ | RpcConditionProps
+ | TimeConditionProps
+ | ContractConditionProps
+ | CompoundConditionProps
+ ) {}
+
+ public validate(override: Partial = {}): {
+ data?: ConditionProps;
+ error?: z.ZodError;
+ } {
+ const newValue = {
+ ...this.value,
+ ...override,
+ };
+ const result = this.schema.safeParse(newValue);
+ if (result.success) {
+ return { data: result.data };
+ }
+ return { error: result.error };
+ }
+
+ public requiresSigner(): boolean {
+ return JSON.stringify(this.value).includes(USER_ADDRESS_PARAM);
+ }
+
+ public toObj() {
+ const { data, error } = this.validate(this.value);
+ if (error) {
+ throw new Error(`Invalid condition: ${JSON.stringify(error.issues)}`);
+ }
+ return data;
+ }
+
+ public static fromObj(
+ this: new (...args: unknown[]) => T,
+ obj: Record
+ ): T {
+ return new this(obj);
+ }
+
+ public equals(other: Condition) {
+ return objectEquals(this, other);
+ }
+}
diff --git a/src/conditions/const.ts b/src/conditions/const.ts
index 19f336649..3a8b941d2 100644
--- a/src/conditions/const.ts
+++ b/src/conditions/const.ts
@@ -1,12 +1,3 @@
-import { ChainId } from '../types';
-
-export const SUPPORTED_CHAINS = [
- ChainId.MAINNET,
- ChainId.GOERLI,
- ChainId.POLYGON,
- ChainId.MUMBAI,
-];
-
export const USER_ADDRESS_PARAM = ':userAddress';
export const ETH_ADDRESS_REGEXP = new RegExp('^0x[a-fA-F0-9]{40}$');
diff --git a/src/conditions/context/context.ts b/src/conditions/context/context.ts
index 0f1f7fc04..b32e5a4e1 100644
--- a/src/conditions/context/context.ts
+++ b/src/conditions/context/context.ts
@@ -2,7 +2,7 @@ import { Conditions as WASMConditions } from '@nucypher/nucypher-core';
import { ethers } from 'ethers';
import { fromJSON, toJSON } from '../../utils';
-import { Condition } from '../base';
+import { Condition } from '../condition';
import { USER_ADDRESS_PARAM } from '../const';
import { TypedSignature, WalletAuthenticationProvider } from './providers';
diff --git a/src/conditions/context/index.ts b/src/conditions/context/index.ts
index 72a893ff3..e18afda2a 100644
--- a/src/conditions/context/index.ts
+++ b/src/conditions/context/index.ts
@@ -1,2 +1 @@
-export { ConditionContext } from './context';
-export type { CustomContextParam } from './context';
+export { ConditionContext, type CustomContextParam } from './context';
diff --git a/src/conditions/index.ts b/src/conditions/index.ts
index 2d5661fdb..365b87a63 100644
--- a/src/conditions/index.ts
+++ b/src/conditions/index.ts
@@ -2,9 +2,13 @@ import * as base from './base';
import * as predefined from './predefined';
export { predefined, base };
-export { Condition } from './base/condition';
-export type { ConditionExpressionJSON } from './condition-expr';
-export { ConditionExpression } from './condition-expr';
-export { CompoundCondition } from './compound-condition';
-export type { CustomContextParam } from './context';
-export { ConditionContext } from './context';
+export {
+ ConditionExpression,
+ type ConditionExpressionJSON,
+} from './condition-expr';
+export { ConditionContext, type CustomContextParam } from './context';
+export { Condition, type ConditionProps } from './condition';
+export {
+ compoundConditionSchema,
+ type CompoundConditionProps,
+} from './compound-condition';
diff --git a/src/conditions/predefined/erc721.ts b/src/conditions/predefined/erc721.ts
index beed9a5ce..9fcfe22d5 100644
--- a/src/conditions/predefined/erc721.ts
+++ b/src/conditions/predefined/erc721.ts
@@ -1,21 +1,35 @@
-import { ContractCondition } from '../base';
+import { ContractCondition, ContractConditionProps } from '../base';
import { USER_ADDRESS_PARAM } from '../const';
+// TODO: Rewrite these using Zod schemas?
+
+type ERC721OwnershipFields = 'contractAddress' | 'chain' | 'parameters';
+
+const ERC721OwnershipDefaults: Omit<
+ ContractConditionProps,
+ ERC721OwnershipFields
+> = {
+ conditionType: 'contract',
+ method: 'ownerOf',
+ standardContractType: 'ERC721',
+ returnValueTest: {
+ index: 0,
+ comparator: '==',
+ value: USER_ADDRESS_PARAM,
+ },
+};
+
export class ERC721Ownership extends ContractCondition {
- public readonly defaults = {
- method: 'ownerOf',
- parameters: [],
- standardContractType: 'ERC721',
- returnValueTest: {
- index: 0,
- comparator: '==',
- value: USER_ADDRESS_PARAM,
- },
- };
+ constructor(value: Pick) {
+ super({ ...ERC721OwnershipDefaults, ...value });
+ }
}
-export class ERC721Balance extends ContractCondition {
- public readonly defaults = {
+type ERC721BalanceFields = 'contractAddress' | 'chain';
+
+const ERC721BalanceDefaults: Omit =
+ {
+ conditionType: 'contract',
method: 'balanceOf',
parameters: [USER_ADDRESS_PARAM],
standardContractType: 'ERC721',
@@ -25,4 +39,9 @@ export class ERC721Balance extends ContractCondition {
value: '0',
},
};
+
+export class ERC721Balance extends ContractCondition {
+ constructor(value: Pick) {
+ super({ ...ERC721BalanceDefaults, ...value });
+ }
}
diff --git a/src/index.ts b/src/index.ts
index 0045b30bc..0382830de 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -22,10 +22,8 @@ export { getPorterUri } from './porter';
export { PolicyMessageKit } from './kits/message';
// Conditions
-import type { CustomContextParam } from './conditions';
import * as conditions from './conditions';
-// TODO: Not sure how to re-export this type from the conditions module
-export { conditions, CustomContextParam };
+export { conditions };
// DKG
export { FerveoVariant } from '@nucypher/nucypher-core';
diff --git a/src/utils.ts b/src/utils.ts
index 3fc45a09a..b74a43a1a 100644
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -65,10 +65,6 @@ export const zip = (
export const toEpoch = (date: Date) => (date.getTime() / 1000) | 0;
-export const bytesEquals = (first: Uint8Array, second: Uint8Array): boolean =>
- first.length === second.length &&
- first.every((value, index) => value === second[index]);
-
export const objectEquals = (a: unknown, b: unknown, strict = true): boolean =>
deepEqual(a, b, { strict });
diff --git a/test/docs/cbd.test.ts b/test/docs/cbd.test.ts
index e0e0c40af..9d863f8c0 100644
--- a/test/docs/cbd.test.ts
+++ b/test/docs/cbd.test.ts
@@ -8,6 +8,10 @@ import {
PreStrategy,
SecretKey,
} from '../../src';
+import {
+ ContractCondition,
+ ContractConditionProps,
+} from '../../src/conditions/base';
import { Ursula } from '../../src/porter';
import { toBytes } from '../../src/utils';
import {
@@ -24,7 +28,6 @@ import {
const {
predefined: { ERC721Ownership },
- base: { ContractCondition },
ConditionExpression,
} = conditions;
@@ -91,7 +94,8 @@ describe('Get Started (CBD PoC)', () => {
const newDeployed = await newStrategy.deploy(provider, signer, 'test');
// 5. Encrypt the plaintext & update conditions
- const NFTBalanceConfig = {
+ const NFTBalanceConfig: ContractConditionProps = {
+ conditionType: 'contract',
contractAddress: '0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D',
standardContractType: 'ERC721',
chain: 5,
diff --git a/test/integration/enrico.test.ts b/test/integration/enrico.test.ts
index d28ea9f77..2dbdfae96 100644
--- a/test/integration/enrico.test.ts
+++ b/test/integration/enrico.test.ts
@@ -99,7 +99,7 @@ describe('enrico', () => {
const policyKey = alice.getPolicyEncryptingKeyFromLabel(label);
- const ownsBufficornNFT = ERC721Ownership.fromObj({
+ const ownsBufficornNFT = new ERC721Ownership({
contractAddress: '0x1e988ba4692e52Bc50b375bcC8585b95c48AaD77',
parameters: [3591],
chain: 5,
diff --git a/test/integration/pre.test.ts b/test/integration/pre.test.ts
index 6546228f5..b14f2bf18 100644
--- a/test/integration/pre.test.ts
+++ b/test/integration/pre.test.ts
@@ -1,7 +1,7 @@
import { CapsuleFrag, reencrypt } from '@nucypher/nucypher-core';
import { conditions, Enrico, MessageKit, PolicyMessageKit } from '../../src';
-import { CompoundCondition } from '../../src/conditions';
+import { CompoundCondition } from '../../src/conditions/base';
import { RetrievalResult } from '../../src/kits/retrieval';
import { toBytes, zip } from '../../src/utils';
import { fakeAlice, fakeBob, fakeUrsulas, reencryptKFrags } from '../utils';
diff --git a/test/unit/conditions/base/condition.test.ts b/test/unit/conditions/base/condition.test.ts
index 2a567434c..baa0882a0 100644
--- a/test/unit/conditions/base/condition.test.ts
+++ b/test/unit/conditions/base/condition.test.ts
@@ -11,37 +11,45 @@ import {
} from '../../testVariables';
describe('validation', () => {
- // TODO: Consider:
- // Use Condition here with returnTestValue schema
- // Refactor returnTestValue to be the part of the Condition
- const condition = new ERC721Balance();
+ const condition = new ERC721Balance({
+ contractAddress: TEST_CONTRACT_ADDR,
+ chain: TEST_CHAIN_ID,
+ });
it('accepts a correct schema', async () => {
- const result = condition.validate({
- contractAddress: TEST_CONTRACT_ADDR,
- chain: TEST_CHAIN_ID,
- });
+ const result = condition.validate();
expect(result.error).toBeUndefined();
- expect(result.value.contractAddress).toEqual(TEST_CONTRACT_ADDR);
+ expect(result.data.contractAddress).toEqual(TEST_CONTRACT_ADDR);
});
- it('updates on a valid schema value', async () => {
- const result = condition.validate({
+ it('accepts on a valid value override', async () => {
+ const validOverride = {
chain: TEST_CHAIN_ID,
contractAddress: TEST_CONTRACT_ADDR_2,
- });
+ };
+ const result = condition.validate(validOverride);
expect(result.error).toBeUndefined();
- expect(result.value.chain).toEqual(TEST_CHAIN_ID);
+ expect(result.data).toMatchObject(validOverride);
});
- it('rejects on an invalid schema value', async () => {
- const result = condition.validate({
+ it('rejects on an invalid value override', async () => {
+ const invalidOverride = {
chain: -1,
contractAddress: TEST_CONTRACT_ADDR,
+ };
+ const result = condition.validate(invalidOverride);
+ expect(result.error).toBeDefined();
+ expect(result.data).toBeUndefined();
+ expect(result.error?.format()).toMatchObject({
+ chain: {
+ _errors: [
+ 'Invalid literal value, expected 137',
+ 'Invalid literal value, expected 80001',
+ 'Invalid literal value, expected 5',
+ 'Invalid literal value, expected 1',
+ ],
+ },
});
- expect(result.error?.message).toEqual(
- '"chain" must be one of [1, 5, 137, 80001]'
- );
});
});
@@ -56,7 +64,6 @@ describe('serialization', () => {
it('serializes predefined conditions', () => {
const contract = new ERC721Ownership(testContractConditionObj);
expect(contract.toObj()).toEqual({
- ...contract.defaults,
...testContractConditionObj,
});
});
diff --git a/test/unit/conditions/base/contract.test.ts b/test/unit/conditions/base/contract.test.ts
index ef926e640..11ff45f29 100644
--- a/test/unit/conditions/base/contract.test.ts
+++ b/test/unit/conditions/base/contract.test.ts
@@ -2,17 +2,21 @@ import {
ConditionExpression,
CustomContextParam,
} from '../../../../src/conditions';
-import { ContractCondition } from '../../../../src/conditions/base';
+import {
+ ContractCondition,
+ ContractConditionProps,
+} from '../../../../src/conditions/base';
+import { FunctionAbiProps } from '../../../../src/conditions/base/contract';
import { USER_ADDRESS_PARAM } from '../../../../src/conditions/const';
import { fakeProvider, fakeSigner } from '../../../utils';
import { testContractConditionObj, testFunctionAbi } from '../../testVariables';
describe('validation', () => {
it('accepts on a valid schema', () => {
- const contract = new ContractCondition(testContractConditionObj);
- expect(contract.toObj()).toEqual({
- ...testContractConditionObj,
- });
+ const result = new ContractCondition(testContractConditionObj).validate();
+
+ expect(result.error).toBeUndefined();
+ expect(result.data).toEqual(testContractConditionObj);
});
it('rejects an invalid schema', () => {
@@ -20,14 +24,16 @@ describe('validation', () => {
...testContractConditionObj,
// Intentionally removing `contractAddress`
contractAddress: undefined,
- };
- const badEvm = new ContractCondition(badContractCondition);
- expect(() => badEvm.toObj()).toThrow(
- 'Invalid condition: "contractAddress" is required'
- );
-
- const { error } = badEvm.validate(badContractCondition);
- expect(error?.message).toEqual('"contractAddress" is required');
+ } as unknown as ContractConditionProps;
+ const result = new ContractCondition(badContractCondition).validate();
+
+ expect(result.error).toBeDefined();
+ expect(result.data).toBeUndefined();
+ expect(result.error?.format()).toMatchObject({
+ contractAddress: {
+ _errors: ['Required'],
+ },
+ });
});
});
@@ -38,6 +44,7 @@ describe('accepts either standardContractType or functionAbi but not both or non
{
name: '_owner',
type: 'address',
+ internalType: 'address',
},
],
name: 'balanceOf',
@@ -45,6 +52,7 @@ describe('accepts either standardContractType or functionAbi but not both or non
{
name: 'balance',
type: 'uint256',
+ internalType: 'uint256',
},
],
stateMutability: 'view',
@@ -56,11 +64,11 @@ describe('accepts either standardContractType or functionAbi but not both or non
...testContractConditionObj,
standardContractType,
functionAbi: undefined,
- };
- const contractCondition = new ContractCondition(conditionObj);
- expect(contractCondition.toObj()).toEqual({
- ...conditionObj,
- });
+ } as typeof testContractConditionObj;
+ const result = new ContractCondition(conditionObj).validate();
+
+ expect(result.error).toBeUndefined();
+ expect(result.data).toEqual(conditionObj);
});
it('accepts functionAbi', () => {
@@ -68,11 +76,11 @@ describe('accepts either standardContractType or functionAbi but not both or non
...testContractConditionObj,
functionAbi,
standardContractType: undefined,
- };
- const contractCondition = new ContractCondition(conditionObj);
- expect(contractCondition.toObj()).toEqual({
- ...conditionObj,
- });
+ } as typeof testContractConditionObj;
+ const result = new ContractCondition(conditionObj).validate();
+
+ expect(result.error).toBeUndefined();
+ expect(result.data).toEqual(conditionObj);
});
it('rejects both', () => {
@@ -80,11 +88,16 @@ describe('accepts either standardContractType or functionAbi but not both or non
...testContractConditionObj,
standardContractType,
functionAbi,
- };
- const contractCondition = new ContractCondition(conditionObj);
- expect(() => contractCondition.toObj()).toThrow(
- '"value" contains a conflict between exclusive peers [standardContractType, functionAbi]'
- );
+ } as typeof testContractConditionObj;
+ const result = new ContractCondition(conditionObj).validate();
+
+ expect(result.error).toBeDefined();
+ expect(result.data).toBeUndefined();
+ expect(result.error?.format()).toMatchObject({
+ _errors: [
+ "At most one of the fields 'standardContractType' and 'functionAbi' must be defined",
+ ],
+ });
});
it('rejects none', () => {
@@ -92,16 +105,21 @@ describe('accepts either standardContractType or functionAbi but not both or non
...testContractConditionObj,
standardContractType: undefined,
functionAbi: undefined,
- };
- const contractCondition = new ContractCondition(conditionObj);
- expect(() => contractCondition.toObj()).toThrow(
- '"value" must contain at least one of [standardContractType, functionAbi]'
- );
+ } as typeof testContractConditionObj;
+ const result = new ContractCondition(conditionObj).validate();
+
+ expect(result.error).toBeDefined();
+ expect(result.data).toBeUndefined();
+ expect(result.error?.format()).toMatchObject({
+ _errors: [
+ "At most one of the fields 'standardContractType' and 'functionAbi' must be defined",
+ ],
+ });
});
});
describe('supports custom function abi', () => {
- const contractConditionObj = {
+ const contractConditionObj: ContractConditionProps = {
...testContractConditionObj,
standardContractType: undefined,
functionAbi: testFunctionAbi,
@@ -126,6 +144,7 @@ describe('supports custom function abi', () => {
const asJson = await conditionContext
.withCustomParams(customParams)
.toJson();
+
expect(asJson).toBeDefined();
expect(asJson).toContain(USER_ADDRESS_PARAM);
expect(asJson).toContain(myCustomParam);
@@ -137,8 +156,10 @@ describe('supports custom function abi', () => {
functionAbi: {
name: 'balanceOf',
type: 'function',
- inputs: [{ name: '_owner', type: 'address' }],
- outputs: [{ name: 'balance', type: 'uint256' }],
+ inputs: [{ name: '_owner', type: 'address', internalType: 'address' }],
+ outputs: [
+ { name: 'balance', type: 'uint256', internalType: 'uint256' },
+ ],
stateMutability: 'view',
},
},
@@ -148,61 +169,72 @@ describe('supports custom function abi', () => {
name: 'get',
type: 'function',
inputs: [],
- outputs: [],
+ outputs: [
+ { name: 'balance', type: 'uint256', internalType: 'uint256' },
+ ],
stateMutability: 'pure',
},
},
])('accepts well-formed functionAbi', ({ method, functionAbi }) => {
- expect(() =>
- new ContractCondition({
- ...contractConditionObj,
- parameters: functionAbi.inputs.map(
- (input) => `fake_parameter_${input}`
- ), //
- functionAbi,
- method,
- }).toObj()
- ).not.toThrow();
+ const result = new ContractCondition({
+ ...contractConditionObj,
+ parameters: functionAbi.inputs.map((input) => `fake_parameter_${input}`), //
+ functionAbi: functionAbi as FunctionAbiProps,
+ method,
+ }).validate();
+
+ expect(result.error).toBeUndefined();
+ expect(result.data).toBeDefined();
+ expect(result.data?.method).toEqual(method);
+ expect(result.data?.functionAbi).toEqual(functionAbi);
});
it.each([
{
method: '1234',
- expectedError: '"functionAbi.name" must be a string',
+ badField: 'name',
+ expectedErrors: ['Expected string, received number'],
functionAbi: {
name: 1234, // invalid value
type: 'function',
- inputs: [{ name: '_owner', type: 'address' }],
- outputs: [{ name: 'balance', type: 'uint256' }],
+ inputs: [{ name: '_owner', type: 'address', internalType: 'address' }],
+ outputs: [
+ { name: 'balance', type: 'uint256', internalType: 'uint256' },
+ ],
stateMutability: 'view',
},
},
{
method: 'transfer',
- expectedError: '"functionAbi.inputs" must be an array',
+ badField: 'inputs',
+ expectedErrors: ['Expected array, received string'],
functionAbi: {
name: 'transfer',
type: 'function',
inputs: 'invalid value', // invalid value
- outputs: [{ name: '_status', type: 'bool' }],
+ outputs: [{ name: '_status', type: 'bool', internalType: 'bool' }],
stateMutability: 'pure',
},
},
{
method: 'get',
- expectedError:
- '"functionAbi.stateMutability" must be one of [view, pure]',
+ badField: 'stateMutability',
+ expectedErrors: [
+ 'Invalid literal value, expected "view"',
+ 'Invalid literal value, expected "pure"',
+ ],
functionAbi: {
name: 'get',
type: 'function',
inputs: [],
- outputs: [],
+ outputs: [{ name: 'result', type: 'uint256', internalType: 'uint256' }],
stateMutability: 'invalid', // invalid value
},
},
{
method: 'test',
- expectedError: '"functionAbi.outputs" must be an array',
+ badField: 'outputs',
+ expectedErrors: ['Expected array, received string'],
functionAbi: {
name: 'test',
type: 'function',
@@ -213,26 +245,34 @@ describe('supports custom function abi', () => {
},
{
method: 'calculatePow',
- expectedError:
- 'Invalid condition: "parameters" must have the same length as "functionAbi.inputs"',
+ badField: 'inputs',
+ expectedErrors: ['Required'],
functionAbi: {
name: 'calculatePow',
type: 'function',
// 'inputs': [] // Missing inputs array
- outputs: [{ name: 'result', type: 'uint256' }],
+ outputs: [{ name: 'result', type: 'uint256', internalType: 'uint256' }],
stateMutability: 'view',
},
},
])(
'rejects malformed functionAbi',
- ({ method, expectedError, functionAbi }) => {
- expect(() =>
- new ContractCondition({
- ...contractConditionObj,
- functionAbi,
- method,
- }).toObj()
- ).toThrow(expectedError);
+ ({ method, badField, expectedErrors, functionAbi }) => {
+ const result = new ContractCondition({
+ ...contractConditionObj,
+ functionAbi: functionAbi as unknown as FunctionAbiProps,
+ method,
+ }).validate();
+
+ expect(result.error).toBeDefined();
+ expect(result.data).toBeUndefined();
+ expect(result.error?.format()).toMatchObject({
+ functionAbi: {
+ [badField]: {
+ _errors: expectedErrors,
+ },
+ },
+ });
}
);
});
diff --git a/test/unit/conditions/base/rpc.test.ts b/test/unit/conditions/base/rpc.test.ts
index ccd65f63a..a830d0f50 100644
--- a/test/unit/conditions/base/rpc.test.ts
+++ b/test/unit/conditions/base/rpc.test.ts
@@ -3,10 +3,10 @@ import { testRpcConditionObj } from '../../testVariables';
describe('validation', () => {
it('accepts on a valid schema', () => {
- const rpc = new RpcCondition(testRpcConditionObj);
- expect(rpc.toObj()).toEqual({
- ...testRpcConditionObj,
- });
+ const result = new RpcCondition(testRpcConditionObj).validate();
+
+ expect(result.error).toBeUndefined();
+ expect(result.data).toEqual(testRpcConditionObj);
});
it('rejects an invalid schema', () => {
@@ -14,16 +14,18 @@ describe('validation', () => {
...testRpcConditionObj,
// Intentionally replacing `method` with an invalid method
method: 'fake_invalid_method',
- };
+ } as unknown as typeof testRpcConditionObj;
- const badRpc = new RpcCondition(badRpcObj);
- expect(() => badRpc.toObj()).toThrow(
- 'Invalid condition: "method" must be one of [eth_getBalance, balanceOf]'
- );
+ const result = new RpcCondition(badRpcObj).validate();
- const { error } = badRpc.validate(badRpcObj);
- expect(error?.message).toEqual(
- '"method" must be one of [eth_getBalance, balanceOf]'
- );
+ expect(result.error).toBeDefined();
+ expect(result.data).toBeUndefined();
+ expect(result.error?.format()).toMatchObject({
+ method: {
+ _errors: [
+ "Invalid enum value. Expected 'eth_getBalance' | 'balanceOf', received 'fake_invalid_method'",
+ ],
+ },
+ });
});
});
diff --git a/test/unit/conditions/base/time.test.ts b/test/unit/conditions/base/time.test.ts
index a043c8eba..e2d30cbed 100644
--- a/test/unit/conditions/base/time.test.ts
+++ b/test/unit/conditions/base/time.test.ts
@@ -1,42 +1,51 @@
-import { TimeCondition } from '../../../../src/conditions/base';
+import {
+ TimeCondition,
+ TimeConditionProps,
+} from '../../../../src/conditions/base';
+import { ReturnValueTestProps } from '../../../../src/conditions/base/rpc';
describe('validation', () => {
- const returnValueTest = {
+ const returnValueTest: ReturnValueTestProps = {
index: 0,
comparator: '>',
value: '100',
};
it('accepts a valid schema', () => {
- const timeCondition = new TimeCondition({
+ const conditionObj: TimeConditionProps = {
returnValueTest,
- chain: 5,
- });
- expect(timeCondition.toObj()).toEqual({
- returnValueTest,
- chain: 5,
+ conditionType: 'time',
method: 'blocktime',
- });
+ chain: 1,
+ };
+ const result = new TimeCondition(conditionObj).validate();
+
+ expect(result.error).toBeUndefined();
+ expect(result.data).toEqual(conditionObj);
});
it('rejects an invalid schema', () => {
- const badTimeObj = {
+ const badObj = {
+ conditionType: 'time',
// Intentionally replacing `returnValueTest` with an invalid test
returnValueTest: {
...returnValueTest,
comparator: 'not-a-comparator',
},
chain: 5,
- };
-
- const badTimeCondition = new TimeCondition(badTimeObj);
- expect(() => badTimeCondition.toObj()).toThrow(
- 'Invalid condition: "returnValueTest.comparator" must be one of [==, >, <, >=, <=, !=]'
- );
+ } as unknown as TimeConditionProps;
+ const result = new TimeCondition(badObj).validate();
- const { error } = badTimeCondition.validate(badTimeObj);
- expect(error?.message).toEqual(
- '"returnValueTest.comparator" must be one of [==, >, <, >=, <=, !=]'
- );
+ expect(result.error).toBeDefined();
+ expect(result.data).toBeUndefined();
+ expect(result.error?.format()).toMatchObject({
+ returnValueTest: {
+ comparator: {
+ _errors: [
+ "Invalid enum value. Expected '==' | '>' | '<' | '>=' | '<=' | '!=', received 'not-a-comparator'",
+ ],
+ },
+ },
+ });
});
});
diff --git a/test/unit/conditions/compound-condition.test.ts b/test/unit/conditions/compound-condition.test.ts
index 396b6fddf..f558fd8c9 100644
--- a/test/unit/conditions/compound-condition.test.ts
+++ b/test/unit/conditions/compound-condition.test.ts
@@ -1,85 +1,113 @@
-import { CompoundCondition } from '../../../src/conditions';
-import { ERC721Ownership } from '../../../src/conditions/predefined/erc721';
+import { CompoundCondition } from '../../../src/conditions/base';
import {
testContractConditionObj,
testRpcConditionObj,
testTimeConditionObj,
} from '../testVariables';
-describe('validate', () => {
- const ownsBufficornNFT = ERC721Ownership.fromObj({
- contractAddress: '0x1e988ba4692e52Bc50b375bcC8585b95c48AaD77',
- parameters: [3591],
- chain: 5,
- }).toObj();
-
+describe('validation', () => {
it('accepts or operator', () => {
- const orCondition = new CompoundCondition({
+ const conditionObj = {
operator: 'or',
- operands: [ownsBufficornNFT, testTimeConditionObj],
- }).toObj();
+ operands: [testContractConditionObj, testTimeConditionObj],
+ };
+ const result = new CompoundCondition(conditionObj).validate();
- expect(orCondition.operator).toEqual('or');
- expect(orCondition.operands).toEqual([
- ownsBufficornNFT,
- testTimeConditionObj,
- ]);
+ expect(result.error).toBeUndefined();
+ expect(result.data).toEqual({
+ ...conditionObj,
+ conditionType: 'compound',
+ });
});
it('accepts and operator', () => {
- const orCondition = new CompoundCondition({
+ const conditionObj = {
operator: 'and',
operands: [testContractConditionObj, testTimeConditionObj],
- }).toObj();
+ };
+ const result = new CompoundCondition(conditionObj).validate();
- expect(orCondition.operator).toEqual('and');
- expect(orCondition.operands).toEqual([
- testContractConditionObj,
- testTimeConditionObj,
- ]);
+ expect(result.error).toBeUndefined();
+ expect(result.data).toEqual({
+ ...conditionObj,
+ conditionType: 'compound',
+ });
});
it('rejects an invalid operator', () => {
- expect(() =>
- new CompoundCondition({
- operator: 'not-an-operator',
- operands: [testRpcConditionObj, testTimeConditionObj],
- }).toObj()
- ).toThrow('"operator" must be one of [and, or]');
+ const result = new CompoundCondition({
+ operator: 'not-an-operator',
+ operands: [testRpcConditionObj, testTimeConditionObj],
+ }).validate();
+
+ expect(result.error).toBeDefined();
+ expect(result.data).toBeUndefined();
+ expect(result.error?.format()).toMatchObject({
+ operator: {
+ _errors: [
+ "Invalid enum value. Expected 'and' | 'or', received 'not-an-operator'",
+ ],
+ },
+ });
});
it('rejects invalid number of operands = 0', () => {
- expect(() =>
- new CompoundCondition({
- operator: 'or',
- operands: [],
- }).toObj()
- ).toThrow('"operands" must contain at least 2 items');
+ const result = new CompoundCondition({
+ operator: 'or',
+ operands: [],
+ }).validate();
+
+ expect(result.error).toBeDefined();
+ expect(result.data).toBeUndefined();
+ expect(result.error?.format()).toMatchObject({
+ operands: {
+ _errors: ['Array must contain at least 2 element(s)'],
+ },
+ });
});
it('rejects invalid number of operands = 1', () => {
- expect(() =>
- new CompoundCondition({
- operator: 'or',
- operands: [testRpcConditionObj],
- }).toObj()
- ).toThrow('"operands" must contain at least 2 items');
+ const result = new CompoundCondition({
+ operator: 'or',
+ operands: [testRpcConditionObj],
+ }).validate();
+ expect(result.error).toBeDefined();
+ expect(result.data).toBeUndefined();
+ expect(result.error?.format()).toMatchObject({
+ operands: {
+ _errors: ['Array must contain at least 2 element(s)'],
+ },
+ });
});
- it('it allows recursive compound conditions', () => {
- const compoundCondition = new CompoundCondition({
+ it('accepts recursive compound conditions', () => {
+ const conditionObj = {
+ operator: 'and',
+ operands: [
+ testContractConditionObj,
+ testTimeConditionObj,
+ testRpcConditionObj,
+ {
+ operator: 'or',
+ operands: [testTimeConditionObj, testContractConditionObj],
+ },
+ ],
+ };
+ const result = new CompoundCondition(conditionObj).validate();
+ expect(result.error).toBeUndefined();
+ expect(result.data).toEqual({
+ conditionType: 'compound',
operator: 'and',
operands: [
testContractConditionObj,
testTimeConditionObj,
testRpcConditionObj,
{
+ conditionType: 'compound',
operator: 'or',
- operands: [ownsBufficornNFT, testContractConditionObj],
+ operands: [testTimeConditionObj, testContractConditionObj],
},
],
- }).toObj();
- expect(compoundCondition.operator).toEqual('and');
- expect(compoundCondition.operands).toHaveLength(4);
+ });
});
});
diff --git a/test/unit/conditions/condition-expr.test.ts b/test/unit/conditions/condition-expr.test.ts
index 806269a7f..bcc78e7a7 100644
--- a/test/unit/conditions/condition-expr.test.ts
+++ b/test/unit/conditions/condition-expr.test.ts
@@ -1,17 +1,16 @@
import { SemVer } from 'semver';
+import { ConditionExpression } from '../../../src/conditions';
import {
CompoundCondition,
- ConditionExpression,
-} from '../../../src/conditions';
-import {
ContractCondition,
+ ContractConditionProps,
RpcCondition,
TimeCondition,
} from '../../../src/conditions/base';
import { USER_ADDRESS_PARAM } from '../../../src/conditions/const';
import { ERC721Balance } from '../../../src/conditions/predefined';
-import { toJSON } from '../../../src/utils';
+import { objectEquals, toJSON } from '../../../src/utils';
import {
TEST_CHAIN_ID,
TEST_CONTRACT_ADDR,
@@ -35,7 +34,7 @@ describe('condition set', () => {
);
const customParamKey = ':customParam';
- const contractConditionWithAbiObj = {
+ const contractConditionWithAbiObj: ContractConditionProps = {
...testContractConditionObj,
standardContractType: undefined,
functionAbi: testFunctionAbi,
@@ -68,12 +67,12 @@ describe('condition set', () => {
const conditionExprCurrentVersion = new ConditionExpression(rpcCondition);
it('same version and condition', async () => {
- const conditionExprSameCurrentVerstion = new ConditionExpression(
+ const conditionExprSameCurrentVersion = new ConditionExpression(
rpcCondition,
ConditionExpression.VERSION
);
expect(
- conditionExprCurrentVersion.equals(conditionExprSameCurrentVerstion)
+ conditionExprCurrentVersion.equals(conditionExprSameCurrentVersion)
).toBeTruthy();
});
@@ -159,7 +158,9 @@ describe('condition set', () => {
const contractConditionExpr = new ConditionExpression(
sameContractCondition
);
- expect(erc721ConditionExpr.equals(contractConditionExpr)).toBeTruthy();
+ expect(
+ objectEquals(erc721ConditionExpr.toObj(), contractConditionExpr.toObj())
+ ).toBeTruthy();
});
});
@@ -211,50 +212,6 @@ describe('condition set', () => {
}
);
- it.each([
- // no "operator" nor "method" value
- {
- version: ConditionExpression.VERSION,
- condition: {
- randoKey: 'randoValue',
- otherKey: 'otherValue',
- },
- },
- // invalid "method" and no "contractAddress"
- {
- version: ConditionExpression.VERSION,
- condition: {
- method: 'doWhatIWant',
- returnValueTest: {
- index: 0,
- comparator: '>',
- value: '100',
- },
- chain: 5,
- },
- },
- // condition with wrong method "method" and no contract address
- {
- version: ConditionExpression.VERSION,
- condition: {
- ...testTimeConditionObj,
- method: 'doWhatIWant',
- },
- },
- // rpc condition (no contract address) with disallowed method
- {
- version: ConditionExpression.VERSION,
- condition: {
- ...testRpcConditionObj,
- method: 'isPolicyActive',
- },
- },
- ])("can't determine condition type", async (invalidCondition) => {
- expect(() => {
- ConditionExpression.fromObj(invalidCondition);
- }).toThrow('unrecognized condition data');
- });
-
it('erc721 condition serialization', async () => {
const conditionExpr = new ConditionExpression(erc721BalanceCondition);
diff --git a/test/unit/conditions/context.test.ts b/test/unit/conditions/context.test.ts
index 126f05df3..3f0f9e501 100644
--- a/test/unit/conditions/context.test.ts
+++ b/test/unit/conditions/context.test.ts
@@ -1,5 +1,7 @@
-import { CustomContextParam } from '../../../src';
-import { ConditionExpression } from '../../../src/conditions';
+import {
+ ConditionExpression,
+ CustomContextParam,
+} from '../../../src/conditions';
import { ContractCondition, RpcCondition } from '../../../src/conditions/base';
import { USER_ADDRESS_PARAM } from '../../../src/conditions/const';
import { RESERVED_CONTEXT_PARAMS } from '../../../src/conditions/context/context';
diff --git a/test/unit/testVariables.ts b/test/unit/testVariables.ts
index 36031e816..c7f85dec8 100644
--- a/test/unit/testVariables.ts
+++ b/test/unit/testVariables.ts
@@ -1,3 +1,11 @@
+import {
+ ContractConditionProps,
+ RpcConditionProps,
+ TimeConditionProps,
+} from '../../src/conditions/base';
+import { FunctionAbiProps } from '../../src/conditions/base/contract';
+import { ReturnValueTestProps } from '../../src/conditions/base/rpc';
+
export const aliceSecretKeyBytes = new Uint8Array([
55, 82, 190, 189, 203, 164, 60, 148, 36, 86, 46, 123, 63, 152, 215, 113, 174,
86, 244, 44, 23, 227, 197, 68, 5, 85, 116, 31, 208, 152, 88, 53,
@@ -13,13 +21,14 @@ export const TEST_CONTRACT_ADDR_2 =
'0x0000000000000000000000000000000000000002';
export const TEST_CHAIN_ID = 5;
-export const testReturnValueTest = {
+export const testReturnValueTest: ReturnValueTestProps = {
index: 0,
comparator: '>',
value: '100',
};
-export const testTimeConditionObj = {
+export const testTimeConditionObj: TimeConditionProps = {
+ conditionType: 'time',
returnValueTest: {
index: 0,
comparator: '>',
@@ -29,14 +38,16 @@ export const testTimeConditionObj = {
chain: 5,
};
-export const testRpcConditionObj = {
+export const testRpcConditionObj: RpcConditionProps = {
+ conditionType: 'rpc',
chain: TEST_CHAIN_ID,
method: 'eth_getBalance',
parameters: ['0x1e988ba4692e52Bc50b375bcC8585b95c48AaD77'],
returnValueTest: testReturnValueTest,
};
-export const testContractConditionObj = {
+export const testContractConditionObj: ContractConditionProps = {
+ conditionType: 'contract',
contractAddress: '0x0000000000000000000000000000000000000000',
chain: 5,
standardContractType: 'ERC20',
@@ -45,7 +56,7 @@ export const testContractConditionObj = {
returnValueTest: testReturnValueTest,
};
-export const testFunctionAbi = {
+export const testFunctionAbi: FunctionAbiProps = {
name: 'myFunction',
type: 'function',
stateMutability: 'view',
diff --git a/yarn.lock b/yarn.lock
index 89631bb51..1176f978f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1487,18 +1487,6 @@
"@ethersproject/properties" "^5.7.0"
"@ethersproject/strings" "^5.7.0"
-"@hapi/hoek@^9.0.0":
- version "9.3.0"
- resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb"
- integrity sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==
-
-"@hapi/topo@^5.0.0":
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-5.1.0.tgz#dc448e332c6c6e37a4dc02fd84ba8d44b9afb012"
- integrity sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==
- dependencies:
- "@hapi/hoek" "^9.0.0"
-
"@humanwhocodes/config-array@^0.11.10":
version "0.11.10"
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.10.tgz#5a3ffe32cc9306365fb3fd572596cd602d5e12d2"
@@ -1595,6 +1583,13 @@
"@types/node" "*"
jest-mock "^29.6.3"
+"@jest/expect-utils@^29.6.2":
+ version "29.6.2"
+ resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.6.2.tgz#1b97f290d0185d264dd9fdec7567a14a38a90534"
+ integrity sha512-6zIhM8go3RV2IG4aIZaZbxwpOzz3ZiM23oxAlkquOIole+G6TrbeXnykxWYlqF7kz2HlBjdKtca20x9atkEQYg==
+ dependencies:
+ jest-get-type "^29.4.3"
+
"@jest/expect-utils@^29.6.4":
version "29.6.4"
resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.6.4.tgz#17c7dfe6cec106441f218b0aff4b295f98346679"
@@ -1662,6 +1657,13 @@
strip-ansi "^6.0.0"
v8-to-istanbul "^9.0.1"
+"@jest/schemas@^29.6.0":
+ version "29.6.0"
+ resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.0.tgz#0f4cb2c8e3dca80c135507ba5635a4fd755b0040"
+ integrity sha512-rxLjXyJBTL4LQeJW3aKo0M/+GkCOXsO+8i9Iu7eDb6KwtP65ayoDsitrdPBtujxQ88k4wI2FNYfa6TOGwSn6cQ==
+ dependencies:
+ "@sinclair/typebox" "^0.27.8"
+
"@jest/schemas@^29.6.3":
version "29.6.3"
resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03"
@@ -1805,22 +1807,10 @@
resolved "https://registry.yarnpkg.com/@nucypher/nucypher-core/-/nucypher-core-0.12.0.tgz#0274026f3996601994e9639c06ab79c62c8f5d7c"
integrity sha512-hEjjnTSLNqHUiIF6U02j+M8jUOBCOt5mGG78lMHoathbak15AmYX4gkdkHTg2Ssvt5o77Cwzsn5YgGM4Haf7AQ==
-"@sideway/address@^4.1.3":
- version "4.1.4"
- resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.4.tgz#03dccebc6ea47fdc226f7d3d1ad512955d4783f0"
- integrity sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==
- dependencies:
- "@hapi/hoek" "^9.0.0"
-
-"@sideway/formula@^3.0.1":
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/@sideway/formula/-/formula-3.0.1.tgz#80fcbcbaf7ce031e0ef2dd29b1bfc7c3f583611f"
- integrity sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==
-
-"@sideway/pinpoint@^2.0.0":
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df"
- integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==
+"@sinclair/typebox@^0.27.8":
+ version "0.27.8"
+ resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e"
+ integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==
"@sinclair/typebox@^0.27.8":
version "0.27.8"
@@ -3702,6 +3692,18 @@ expect@^29.0.0, expect@^29.6.4:
jest-message-util "^29.6.3"
jest-util "^29.6.3"
+expect@^29.0.0:
+ version "29.6.2"
+ resolved "https://registry.yarnpkg.com/expect/-/expect-29.6.2.tgz#7b08e83eba18ddc4a2cf62b5f2d1918f5cd84521"
+ integrity sha512-iAErsLxJ8C+S02QbLAwgSGSezLQK+XXRDt8IuFXFpwCNw2ECmzZSmjKcCaFVp5VRMk+WAvz6h6jokzEzBFZEuA==
+ dependencies:
+ "@jest/expect-utils" "^29.6.2"
+ "@types/node" "*"
+ jest-get-type "^29.4.3"
+ jest-matcher-utils "^29.6.2"
+ jest-message-util "^29.6.2"
+ jest-util "^29.6.2"
+
external-editor@^3.0.3:
version "3.1.0"
resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
@@ -4901,6 +4903,16 @@ jest-matcher-utils@^29.6.4:
jest-get-type "^29.6.3"
pretty-format "^29.6.3"
+jest-matcher-utils@^29.6.2:
+ version "29.6.2"
+ resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.6.2.tgz#39de0be2baca7a64eacb27291f0bd834fea3a535"
+ integrity sha512-4LiAk3hSSobtomeIAzFTe+N8kL6z0JtF3n6I4fg29iIW7tt99R7ZcIFW34QkX+DuVrf+CUe6wuVOpm7ZKFJzZQ==
+ dependencies:
+ chalk "^4.0.0"
+ jest-diff "^29.6.2"
+ jest-get-type "^29.4.3"
+ pretty-format "^29.6.2"
+
jest-message-util@^29.6.3:
version "29.6.3"
resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.6.3.tgz#bce16050d86801b165f20cfde34dc01d3cf85fbf"
@@ -4916,6 +4928,21 @@ jest-message-util@^29.6.3:
slash "^3.0.0"
stack-utils "^2.0.3"
+jest-message-util@^29.6.2:
+ version "29.6.2"
+ resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.6.2.tgz#af7adc2209c552f3f5ae31e77cf0a261f23dc2bb"
+ integrity sha512-vnIGYEjoPSuRqV8W9t+Wow95SDp6KPX2Uf7EoeG9G99J2OVh7OSwpS4B6J0NfpEIpfkBNHlBZpA2rblEuEFhZQ==
+ dependencies:
+ "@babel/code-frame" "^7.12.13"
+ "@jest/types" "^29.6.1"
+ "@types/stack-utils" "^2.0.0"
+ chalk "^4.0.0"
+ graceful-fs "^4.2.9"
+ micromatch "^4.0.4"
+ pretty-format "^29.6.2"
+ slash "^3.0.0"
+ stack-utils "^2.0.3"
+
jest-mock@^29.6.3:
version "29.6.3"
resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.6.3.tgz#433f3fd528c8ec5a76860177484940628bdf5e0a"
@@ -5051,6 +5078,18 @@ jest-util@^29.0.0, jest-util@^29.6.3:
graceful-fs "^4.2.9"
picomatch "^2.2.3"
+jest-util@^29.6.2:
+ version "29.6.2"
+ resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.6.2.tgz#8a052df8fff2eebe446769fd88814521a517664d"
+ integrity sha512-3eX1qb6L88lJNCFlEADKOkjpXJQyZRiavX1INZ4tRnrBVr2COd3RgcTLyUiEXMNBlDU/cgYq6taUS0fExrWW4w==
+ dependencies:
+ "@jest/types" "^29.6.1"
+ "@types/node" "*"
+ chalk "^4.0.0"
+ ci-info "^3.2.0"
+ graceful-fs "^4.2.9"
+ picomatch "^2.2.3"
+
jest-validate@^29.6.3:
version "29.6.3"
resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.6.3.tgz#a75fca774cfb1c5758c70d035d30a1f9c2784b4d"
@@ -5097,17 +5136,6 @@ jest@^29.6.4:
import-local "^3.0.2"
jest-cli "^29.6.4"
-joi@^17.10.0:
- version "17.10.0"
- resolved "https://registry.yarnpkg.com/joi/-/joi-17.10.0.tgz#04e249daa24d48fada2d34046a8262e474b1326f"
- integrity sha512-hrazgRSlhzacZ69LdcKfhi3Vu13z2yFfoAzmEov3yFIJlatTdVGUW6vle1zjH8qkzdCn/qGw8rapjqsObbYXAg==
- dependencies:
- "@hapi/hoek" "^9.0.0"
- "@hapi/topo" "^5.0.0"
- "@sideway/address" "^4.1.3"
- "@sideway/formula" "^3.0.1"
- "@sideway/pinpoint" "^2.0.0"
-
js-sha3@0.8.0, js-sha3@^0.8.0:
version "0.8.0"
resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840"
@@ -6044,6 +6072,15 @@ pretty-format@^29.0.0, pretty-format@^29.6.3:
ansi-styles "^5.0.0"
react-is "^18.0.0"
+pretty-format@^29.0.0, pretty-format@^29.6.2:
+ version "29.6.2"
+ resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.6.2.tgz#3d5829261a8a4d89d8b9769064b29c50ed486a47"
+ integrity sha512-1q0oC8eRveTg5nnBEWMXAU2qpv65Gnuf2eCQzSjxpWFkPaPARwqZZDGuNE0zPAZfTCHzIk3A8dIjwlQKKLphyg==
+ dependencies:
+ "@jest/schemas" "^29.6.0"
+ ansi-styles "^5.0.0"
+ react-is "^18.0.0"
+
process-nextick-args@~2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
@@ -6113,6 +6150,11 @@ react-is@^18.0.0:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
+react-is@^18.0.0:
+ version "18.2.0"
+ resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
+ integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
+
read-pkg-up@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07"
@@ -7420,3 +7462,8 @@ yocto-queue@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.0.0.tgz#7f816433fb2cbc511ec8bf7d263c3b58a1a3c251"
integrity sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==
+
+zod@^3.22.1:
+ version "3.22.1"
+ resolved "https://registry.yarnpkg.com/zod/-/zod-3.22.1.tgz#815f850baf933fef96c1061322dbe579b1a80c27"
+ integrity sha512-+qUhAMl414+Elh+fRNtpU+byrwjDFOS1N7NioLY+tSlcADTx4TkCUua/hxJvxwDXcV4397/nZ420jy4n4+3WUg==
From 8eaf2a7f2cfd08c0de7a8de2034ec27790f6089b Mon Sep 17 00:00:00 2001
From: Piotr Roslaniec
Date: Wed, 30 Aug 2023 18:40:54 +0200
Subject: [PATCH 2/3] apply pr suggestions
---
src/agents/contracts.ts | 3 +-
src/conditions/base/index.ts | 9 +--
src/conditions/base/rpc.ts | 24 ++-----
src/conditions/base/shared.ts | 18 ++++++
src/conditions/compound-condition.ts | 6 +-
src/conditions/condition-expr.ts | 29 +--------
src/conditions/condition.ts | 64 +++++++++++--------
src/conditions/const.ts | 9 +++
src/conditions/index.ts | 5 +-
src/conditions/zod.ts | 31 +++++++++
src/types.ts | 7 --
src/web3.ts | 8 +++
test/unit/conditions/base/condition.test.ts | 34 +---------
test/unit/conditions/base/contract.test.ts | 43 +++++++++----
test/unit/conditions/base/rpc.test.ts | 8 ++-
test/unit/conditions/base/time.test.ts | 7 +-
.../conditions/compound-condition.test.ts | 26 +++++---
test/unit/conditions/condition-expr.test.ts | 58 +++++++++++++----
test/unit/testVariables.ts | 2 +-
19 files changed, 226 insertions(+), 165 deletions(-)
create mode 100644 src/conditions/base/shared.ts
create mode 100644 src/conditions/zod.ts
diff --git a/src/agents/contracts.ts b/src/agents/contracts.ts
index 0ed03352f..a25d89115 100644
--- a/src/agents/contracts.ts
+++ b/src/agents/contracts.ts
@@ -1,4 +1,5 @@
-import { ChainId, ChecksumAddress } from '../types';
+import { ChecksumAddress } from '../types';
+import { ChainId } from '../web3';
type Contracts = {
readonly SUBSCRIPTION_MANAGER: ChecksumAddress | undefined;
diff --git a/src/conditions/base/index.ts b/src/conditions/base/index.ts
index a6a0abe36..b17914f34 100644
--- a/src/conditions/base/index.ts
+++ b/src/conditions/base/index.ts
@@ -35,9 +35,6 @@ export class TimeCondition extends Condition {
}
}
-export {
- contractConditionSchema,
- type ContractConditionProps,
-} from './contract';
-export { rpcConditionSchema, type RpcConditionProps } from './rpc';
-export { timeConditionSchema, type TimeConditionProps } from './time';
+export { type ContractConditionProps } from './contract';
+export { type RpcConditionProps } from './rpc';
+export { type TimeConditionProps } from './time';
diff --git a/src/conditions/base/rpc.ts b/src/conditions/base/rpc.ts
index 2b16d7823..ea232d50f 100644
--- a/src/conditions/base/rpc.ts
+++ b/src/conditions/base/rpc.ts
@@ -1,29 +1,15 @@
import { z } from 'zod';
-import { ETH_ADDRESS_REGEXP, USER_ADDRESS_PARAM } from '../const';
+import { SUPPORTED_CHAIN_IDS } from '../const';
+import createUnionSchema from '../zod';
-export const returnValueTestSchema = z.object({
- index: z.number().optional(),
- comparator: z.enum(['==', '>', '<', '>=', '<=', '!=']),
- value: z.union([z.string(), z.number(), z.boolean()]),
-});
-
-export type ReturnValueTestProps = z.infer;
-
-const EthAddressOrUserAddressSchema = z.array(
- z.union([z.string().regex(ETH_ADDRESS_REGEXP), z.literal(USER_ADDRESS_PARAM)])
-);
+import { EthAddressOrUserAddressSchema, returnValueTestSchema } from './shared';
export const rpcConditionSchema = z.object({
conditionType: z.literal('rpc').default('rpc'),
- chain: z.union([
- z.literal(137),
- z.literal(80001),
- z.literal(5),
- z.literal(1),
- ]),
+ chain: createUnionSchema(SUPPORTED_CHAIN_IDS),
method: z.enum(['eth_getBalance', 'balanceOf']),
- parameters: EthAddressOrUserAddressSchema,
+ parameters: z.array(EthAddressOrUserAddressSchema),
returnValueTest: returnValueTestSchema,
});
diff --git a/src/conditions/base/shared.ts b/src/conditions/base/shared.ts
new file mode 100644
index 000000000..904329521
--- /dev/null
+++ b/src/conditions/base/shared.ts
@@ -0,0 +1,18 @@
+import { z } from 'zod';
+
+import { ETH_ADDRESS_REGEXP, USER_ADDRESS_PARAM } from '../const';
+
+export const returnValueTestSchema = z.object({
+ index: z.number().optional(),
+ comparator: z.enum(['==', '>', '<', '>=', '<=', '!=']),
+ value: z.unknown(),
+});
+
+export type ReturnValueTestProps = z.infer;
+
+const EthAddressSchema = z.string().regex(ETH_ADDRESS_REGEXP);
+const UserAddressSchema = z.literal(USER_ADDRESS_PARAM);
+export const EthAddressOrUserAddressSchema = z.union([
+ EthAddressSchema,
+ UserAddressSchema,
+]);
diff --git a/src/conditions/compound-condition.ts b/src/conditions/compound-condition.ts
index 33c137a99..2c88e0bfe 100644
--- a/src/conditions/compound-condition.ts
+++ b/src/conditions/compound-condition.ts
@@ -1,8 +1,8 @@
import { z } from 'zod';
-import { contractConditionSchema } from './base';
-import { rpcConditionSchema } from './base';
-import { timeConditionSchema } from './base';
+import { contractConditionSchema } from './base/contract';
+import { rpcConditionSchema } from './base/rpc';
+import { timeConditionSchema } from './base/time';
export const compoundConditionSchema: z.ZodSchema = z.object({
conditionType: z.literal('compound').default('compound'),
diff --git a/src/conditions/condition-expr.ts b/src/conditions/condition-expr.ts
index 99358f84c..697687088 100644
--- a/src/conditions/condition-expr.ts
+++ b/src/conditions/condition-expr.ts
@@ -4,17 +4,7 @@ import { SemVer } from 'semver';
import { toBytes, toJSON } from '../utils';
-import {
- CompoundCondition,
- ContractCondition,
- ContractConditionProps,
- RpcCondition,
- RpcConditionProps,
- TimeCondition,
- TimeConditionProps,
-} from './base';
-import { CompoundConditionProps } from './compound-condition';
-import { Condition, ConditionProps } from './condition';
+import { Condition } from './condition';
import { ConditionContext, CustomContextParam } from './context';
export type ConditionExpressionJSON = {
@@ -38,21 +28,6 @@ export class ConditionExpression {
};
}
- private static conditionFromObject(obj: ConditionProps): Condition {
- switch (obj.conditionType) {
- case 'rpc':
- return new RpcCondition(obj as RpcConditionProps);
- case 'time':
- return new TimeCondition(obj as TimeConditionProps);
- case 'contract':
- return new ContractCondition(obj as ContractConditionProps);
- case 'compound':
- return new CompoundCondition(obj as CompoundConditionProps);
- default:
- throw new Error(`Invalid conditionType: ${obj.conditionType}`);
- }
- }
-
public static fromObj(obj: ConditionExpressionJSON): ConditionExpression {
const receivedVersion = new SemVer(obj.version);
const currentVersion = new SemVer(ConditionExpression.VERSION);
@@ -70,7 +45,7 @@ export class ConditionExpression {
);
}
- const condition = this.conditionFromObject(obj.condition as ConditionProps);
+ const condition = Condition.fromObj(obj.condition);
return new ConditionExpression(condition, obj.version);
}
diff --git a/src/conditions/condition.ts b/src/conditions/condition.ts
index fe957bf32..b16444ef1 100644
--- a/src/conditions/condition.ts
+++ b/src/conditions/condition.ts
@@ -3,40 +3,40 @@ import { z } from 'zod';
import { objectEquals } from '../utils';
import {
+ CompoundCondition,
+ ContractCondition,
ContractConditionProps,
+ RpcCondition,
RpcConditionProps,
+ TimeCondition,
TimeConditionProps,
} from './base';
import { CompoundConditionProps } from './compound-condition';
import { USER_ADDRESS_PARAM } from './const';
-// Not using discriminated union because of inconsistent Zod types
-// Some conditions have ZodEffect types because of .refine() calls
-export type ConditionProps =
- | RpcConditionProps
- | TimeConditionProps
- | ContractConditionProps
- | CompoundConditionProps;
+type ConditionSchema = z.ZodSchema;
+export type ConditionProps = z.infer;
export class Condition {
constructor(
- public readonly schema: z.ZodSchema,
- public readonly value:
- | RpcConditionProps
- | TimeConditionProps
- | ContractConditionProps
- | CompoundConditionProps
- ) {}
+ public readonly schema: ConditionSchema,
+ public readonly value: ConditionProps
+ ) {
+ const { data, error } = Condition.validate(schema, value);
+ if (error) {
+ throw new Error(`Invalid condition: ${JSON.stringify(error.issues)}`);
+ }
+ this.value = data;
+ }
- public validate(override: Partial = {}): {
+ public static validate(
+ schema: ConditionSchema,
+ value: ConditionProps
+ ): {
data?: ConditionProps;
error?: z.ZodError;
} {
- const newValue = {
- ...this.value,
- ...override,
- };
- const result = this.schema.safeParse(newValue);
+ const result = schema.safeParse(value);
if (result.success) {
return { data: result.data };
}
@@ -48,18 +48,30 @@ export class Condition {
}
public toObj() {
- const { data, error } = this.validate(this.value);
+ const { data, error } = Condition.validate(this.schema, this.value);
if (error) {
throw new Error(`Invalid condition: ${JSON.stringify(error.issues)}`);
}
return data;
}
- public static fromObj(
- this: new (...args: unknown[]) => T,
- obj: Record
- ): T {
- return new this(obj);
+ private static conditionFromObject(obj: ConditionProps): Condition {
+ switch (obj.conditionType) {
+ case 'rpc':
+ return new RpcCondition(obj as RpcConditionProps);
+ case 'time':
+ return new TimeCondition(obj as TimeConditionProps);
+ case 'contract':
+ return new ContractCondition(obj as ContractConditionProps);
+ case 'compound':
+ return new CompoundCondition(obj as CompoundConditionProps);
+ default:
+ throw new Error(`Invalid conditionType: ${obj.conditionType}`);
+ }
+ }
+
+ public static fromObj(obj: ConditionProps): Condition {
+ return Condition.conditionFromObject(obj);
}
public equals(other: Condition) {
diff --git a/src/conditions/const.ts b/src/conditions/const.ts
index 3a8b941d2..9854c6a13 100644
--- a/src/conditions/const.ts
+++ b/src/conditions/const.ts
@@ -1,3 +1,12 @@
+import { ChainId } from '../web3';
+
export const USER_ADDRESS_PARAM = ':userAddress';
export const ETH_ADDRESS_REGEXP = new RegExp('^0x[a-fA-F0-9]{40}$');
+
+export const SUPPORTED_CHAIN_IDS = [
+ ChainId.POLYGON,
+ ChainId.MUMBAI,
+ ChainId.GOERLI,
+ ChainId.MAINNET,
+];
diff --git a/src/conditions/index.ts b/src/conditions/index.ts
index 365b87a63..ac71ad556 100644
--- a/src/conditions/index.ts
+++ b/src/conditions/index.ts
@@ -8,7 +8,4 @@ export {
} from './condition-expr';
export { ConditionContext, type CustomContextParam } from './context';
export { Condition, type ConditionProps } from './condition';
-export {
- compoundConditionSchema,
- type CompoundConditionProps,
-} from './compound-condition';
+export { type CompoundConditionProps } from './compound-condition';
diff --git a/src/conditions/zod.ts b/src/conditions/zod.ts
new file mode 100644
index 000000000..1829e1201
--- /dev/null
+++ b/src/conditions/zod.ts
@@ -0,0 +1,31 @@
+import { Primitive, z, ZodLiteral } from 'zod';
+
+// Source: https://github.com/colinhacks/zod/issues/831#issuecomment-1063481764
+const createUnion = <
+ T extends Readonly<[Primitive, Primitive, ...Primitive[]]>
+>(
+ values: T
+) => {
+ const zodLiterals = values.map((value) => z.literal(value)) as unknown as [
+ ZodLiteral,
+ ZodLiteral,
+ ...ZodLiteral[]
+ ];
+ return z.union(zodLiterals);
+};
+
+function createUnionSchema(values: T) {
+ if (values.length === 0) {
+ return z.never();
+ }
+
+ if (values.length === 1) {
+ return z.literal(values[0]);
+ }
+
+ return createUnion(
+ values as unknown as Readonly<[Primitive, Primitive, ...Primitive[]]>
+ );
+}
+
+export default createUnionSchema;
diff --git a/src/types.ts b/src/types.ts
index 2440dcc53..9befc497e 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -1,10 +1,3 @@
export type ChecksumAddress = string;
export type HexEncodedBytes = string;
export type Base64EncodedBytes = string;
-
-export enum ChainId {
- POLYGON = 137,
- MUMBAI = 80001,
- GOERLI = 5,
- MAINNET = 1,
-}
diff --git a/src/web3.ts b/src/web3.ts
index 1b5dcd11a..a55508f8f 100644
--- a/src/web3.ts
+++ b/src/web3.ts
@@ -1,4 +1,12 @@
import { fromHexString } from './utils';
+
+export enum ChainId {
+ POLYGON = 137,
+ MUMBAI = 80001,
+ GOERLI = 5,
+ MAINNET = 1,
+}
+
export const toCanonicalAddress = (address: string): Uint8Array => {
const ETH_ADDRESS_STRING_PREFIX = '0x';
const nonPrefixed = address.startsWith(ETH_ADDRESS_STRING_PREFIX)
diff --git a/test/unit/conditions/base/condition.test.ts b/test/unit/conditions/base/condition.test.ts
index baa0882a0..e91322af0 100644
--- a/test/unit/conditions/base/condition.test.ts
+++ b/test/unit/conditions/base/condition.test.ts
@@ -1,3 +1,4 @@
+import { Condition } from '../../../../src/conditions';
import { ContractCondition } from '../../../../src/conditions/base';
import {
ERC721Balance,
@@ -6,7 +7,6 @@ import {
import {
TEST_CHAIN_ID,
TEST_CONTRACT_ADDR,
- TEST_CONTRACT_ADDR_2,
testContractConditionObj,
} from '../../testVariables';
@@ -17,40 +17,10 @@ describe('validation', () => {
});
it('accepts a correct schema', async () => {
- const result = condition.validate();
+ const result = Condition.validate(condition.schema, condition.value);
expect(result.error).toBeUndefined();
expect(result.data.contractAddress).toEqual(TEST_CONTRACT_ADDR);
});
-
- it('accepts on a valid value override', async () => {
- const validOverride = {
- chain: TEST_CHAIN_ID,
- contractAddress: TEST_CONTRACT_ADDR_2,
- };
- const result = condition.validate(validOverride);
- expect(result.error).toBeUndefined();
- expect(result.data).toMatchObject(validOverride);
- });
-
- it('rejects on an invalid value override', async () => {
- const invalidOverride = {
- chain: -1,
- contractAddress: TEST_CONTRACT_ADDR,
- };
- const result = condition.validate(invalidOverride);
- expect(result.error).toBeDefined();
- expect(result.data).toBeUndefined();
- expect(result.error?.format()).toMatchObject({
- chain: {
- _errors: [
- 'Invalid literal value, expected 137',
- 'Invalid literal value, expected 80001',
- 'Invalid literal value, expected 5',
- 'Invalid literal value, expected 1',
- ],
- },
- });
- });
});
describe('serialization', () => {
diff --git a/test/unit/conditions/base/contract.test.ts b/test/unit/conditions/base/contract.test.ts
index 11ff45f29..002467210 100644
--- a/test/unit/conditions/base/contract.test.ts
+++ b/test/unit/conditions/base/contract.test.ts
@@ -6,14 +6,20 @@ import {
ContractCondition,
ContractConditionProps,
} from '../../../../src/conditions/base';
-import { FunctionAbiProps } from '../../../../src/conditions/base/contract';
+import {
+ contractConditionSchema,
+ FunctionAbiProps,
+} from '../../../../src/conditions/base/contract';
import { USER_ADDRESS_PARAM } from '../../../../src/conditions/const';
import { fakeProvider, fakeSigner } from '../../../utils';
import { testContractConditionObj, testFunctionAbi } from '../../testVariables';
describe('validation', () => {
it('accepts on a valid schema', () => {
- const result = new ContractCondition(testContractConditionObj).validate();
+ const result = ContractCondition.validate(
+ contractConditionSchema,
+ testContractConditionObj
+ );
expect(result.error).toBeUndefined();
expect(result.data).toEqual(testContractConditionObj);
@@ -25,7 +31,10 @@ describe('validation', () => {
// Intentionally removing `contractAddress`
contractAddress: undefined,
} as unknown as ContractConditionProps;
- const result = new ContractCondition(badContractCondition).validate();
+ const result = ContractCondition.validate(
+ contractConditionSchema,
+ badContractCondition
+ );
expect(result.error).toBeDefined();
expect(result.data).toBeUndefined();
@@ -65,7 +74,10 @@ describe('accepts either standardContractType or functionAbi but not both or non
standardContractType,
functionAbi: undefined,
} as typeof testContractConditionObj;
- const result = new ContractCondition(conditionObj).validate();
+ const result = ContractCondition.validate(
+ contractConditionSchema,
+ conditionObj
+ );
expect(result.error).toBeUndefined();
expect(result.data).toEqual(conditionObj);
@@ -77,7 +89,10 @@ describe('accepts either standardContractType or functionAbi but not both or non
functionAbi,
standardContractType: undefined,
} as typeof testContractConditionObj;
- const result = new ContractCondition(conditionObj).validate();
+ const result = ContractCondition.validate(
+ contractConditionSchema,
+ conditionObj
+ );
expect(result.error).toBeUndefined();
expect(result.data).toEqual(conditionObj);
@@ -89,7 +104,10 @@ describe('accepts either standardContractType or functionAbi but not both or non
standardContractType,
functionAbi,
} as typeof testContractConditionObj;
- const result = new ContractCondition(conditionObj).validate();
+ const result = ContractCondition.validate(
+ contractConditionSchema,
+ conditionObj
+ );
expect(result.error).toBeDefined();
expect(result.data).toBeUndefined();
@@ -106,7 +124,10 @@ describe('accepts either standardContractType or functionAbi but not both or non
standardContractType: undefined,
functionAbi: undefined,
} as typeof testContractConditionObj;
- const result = new ContractCondition(conditionObj).validate();
+ const result = ContractCondition.validate(
+ contractConditionSchema,
+ conditionObj
+ );
expect(result.error).toBeDefined();
expect(result.data).toBeUndefined();
@@ -176,12 +197,12 @@ describe('supports custom function abi', () => {
},
},
])('accepts well-formed functionAbi', ({ method, functionAbi }) => {
- const result = new ContractCondition({
+ const result = ContractCondition.validate(contractConditionSchema, {
...contractConditionObj,
parameters: functionAbi.inputs.map((input) => `fake_parameter_${input}`), //
functionAbi: functionAbi as FunctionAbiProps,
method,
- }).validate();
+ });
expect(result.error).toBeUndefined();
expect(result.data).toBeDefined();
@@ -258,11 +279,11 @@ describe('supports custom function abi', () => {
])(
'rejects malformed functionAbi',
({ method, badField, expectedErrors, functionAbi }) => {
- const result = new ContractCondition({
+ const result = ContractCondition.validate(contractConditionSchema, {
...contractConditionObj,
functionAbi: functionAbi as unknown as FunctionAbiProps,
method,
- }).validate();
+ });
expect(result.error).toBeDefined();
expect(result.data).toBeUndefined();
diff --git a/test/unit/conditions/base/rpc.test.ts b/test/unit/conditions/base/rpc.test.ts
index a830d0f50..c4f658092 100644
--- a/test/unit/conditions/base/rpc.test.ts
+++ b/test/unit/conditions/base/rpc.test.ts
@@ -1,9 +1,13 @@
import { RpcCondition } from '../../../../src/conditions/base';
+import { rpcConditionSchema } from '../../../../src/conditions/base/rpc';
import { testRpcConditionObj } from '../../testVariables';
describe('validation', () => {
it('accepts on a valid schema', () => {
- const result = new RpcCondition(testRpcConditionObj).validate();
+ const result = RpcCondition.validate(
+ rpcConditionSchema,
+ testRpcConditionObj
+ );
expect(result.error).toBeUndefined();
expect(result.data).toEqual(testRpcConditionObj);
@@ -16,7 +20,7 @@ describe('validation', () => {
method: 'fake_invalid_method',
} as unknown as typeof testRpcConditionObj;
- const result = new RpcCondition(badRpcObj).validate();
+ const result = RpcCondition.validate(rpcConditionSchema, badRpcObj);
expect(result.error).toBeDefined();
expect(result.data).toBeUndefined();
diff --git a/test/unit/conditions/base/time.test.ts b/test/unit/conditions/base/time.test.ts
index e2d30cbed..0ace6466f 100644
--- a/test/unit/conditions/base/time.test.ts
+++ b/test/unit/conditions/base/time.test.ts
@@ -2,7 +2,8 @@ import {
TimeCondition,
TimeConditionProps,
} from '../../../../src/conditions/base';
-import { ReturnValueTestProps } from '../../../../src/conditions/base/rpc';
+import { ReturnValueTestProps } from '../../../../src/conditions/base/shared';
+import { timeConditionSchema } from '../../../../src/conditions/base/time';
describe('validation', () => {
const returnValueTest: ReturnValueTestProps = {
@@ -18,7 +19,7 @@ describe('validation', () => {
method: 'blocktime',
chain: 1,
};
- const result = new TimeCondition(conditionObj).validate();
+ const result = TimeCondition.validate(timeConditionSchema, conditionObj);
expect(result.error).toBeUndefined();
expect(result.data).toEqual(conditionObj);
@@ -34,7 +35,7 @@ describe('validation', () => {
},
chain: 5,
} as unknown as TimeConditionProps;
- const result = new TimeCondition(badObj).validate();
+ const result = TimeCondition.validate(timeConditionSchema, badObj);
expect(result.error).toBeDefined();
expect(result.data).toBeUndefined();
diff --git a/test/unit/conditions/compound-condition.test.ts b/test/unit/conditions/compound-condition.test.ts
index f558fd8c9..2f81a8bc8 100644
--- a/test/unit/conditions/compound-condition.test.ts
+++ b/test/unit/conditions/compound-condition.test.ts
@@ -1,4 +1,6 @@
+import { Condition } from '../../../src/conditions';
import { CompoundCondition } from '../../../src/conditions/base';
+import { compoundConditionSchema } from '../../../src/conditions/compound-condition';
import {
testContractConditionObj,
testRpcConditionObj,
@@ -11,7 +13,7 @@ describe('validation', () => {
operator: 'or',
operands: [testContractConditionObj, testTimeConditionObj],
};
- const result = new CompoundCondition(conditionObj).validate();
+ const result = Condition.validate(compoundConditionSchema, conditionObj);
expect(result.error).toBeUndefined();
expect(result.data).toEqual({
@@ -25,7 +27,10 @@ describe('validation', () => {
operator: 'and',
operands: [testContractConditionObj, testTimeConditionObj],
};
- const result = new CompoundCondition(conditionObj).validate();
+ const result = CompoundCondition.validate(
+ compoundConditionSchema,
+ conditionObj
+ );
expect(result.error).toBeUndefined();
expect(result.data).toEqual({
@@ -35,10 +40,10 @@ describe('validation', () => {
});
it('rejects an invalid operator', () => {
- const result = new CompoundCondition({
+ const result = CompoundCondition.validate(compoundConditionSchema, {
operator: 'not-an-operator',
operands: [testRpcConditionObj, testTimeConditionObj],
- }).validate();
+ });
expect(result.error).toBeDefined();
expect(result.data).toBeUndefined();
@@ -52,10 +57,10 @@ describe('validation', () => {
});
it('rejects invalid number of operands = 0', () => {
- const result = new CompoundCondition({
+ const result = CompoundCondition.validate(compoundConditionSchema, {
operator: 'or',
operands: [],
- }).validate();
+ });
expect(result.error).toBeDefined();
expect(result.data).toBeUndefined();
@@ -67,10 +72,10 @@ describe('validation', () => {
});
it('rejects invalid number of operands = 1', () => {
- const result = new CompoundCondition({
+ const result = CompoundCondition.validate(compoundConditionSchema, {
operator: 'or',
operands: [testRpcConditionObj],
- }).validate();
+ });
expect(result.error).toBeDefined();
expect(result.data).toBeUndefined();
expect(result.error?.format()).toMatchObject({
@@ -93,7 +98,10 @@ describe('validation', () => {
},
],
};
- const result = new CompoundCondition(conditionObj).validate();
+ const result = CompoundCondition.validate(
+ compoundConditionSchema,
+ conditionObj
+ );
expect(result.error).toBeUndefined();
expect(result.data).toEqual({
conditionType: 'compound',
diff --git a/test/unit/conditions/condition-expr.test.ts b/test/unit/conditions/condition-expr.test.ts
index bcc78e7a7..ff53730e1 100644
--- a/test/unit/conditions/condition-expr.test.ts
+++ b/test/unit/conditions/condition-expr.test.ts
@@ -7,6 +7,7 @@ import {
ContractConditionProps,
RpcCondition,
TimeCondition,
+ TimeConditionProps,
} from '../../../src/conditions/base';
import { USER_ADDRESS_PARAM } from '../../../src/conditions/const';
import { ERC721Balance } from '../../../src/conditions/predefined';
@@ -66,7 +67,7 @@ describe('condition set', () => {
describe('equality', () => {
const conditionExprCurrentVersion = new ConditionExpression(rpcCondition);
- it('same version and condition', async () => {
+ it('same version and condition', () => {
const conditionExprSameCurrentVersion = new ConditionExpression(
rpcCondition,
ConditionExpression.VERSION
@@ -76,7 +77,7 @@ describe('condition set', () => {
).toBeTruthy();
});
- it('different minor/patch version but same condition', async () => {
+ it('different minor/patch version but same condition', () => {
const conditionExprOlderMinorVersion = new ConditionExpression(
rpcCondition,
'0.1.0'
@@ -96,7 +97,7 @@ describe('condition set', () => {
).not.toBeTruthy();
});
- it('minor/patch number greater than major; still older', async () => {
+ it('minor/patch number greater than major; still older', () => {
const conditionExprOlderMinorVersion = new ConditionExpression(
rpcCondition,
'0.9.0'
@@ -139,7 +140,7 @@ describe('condition set', () => {
contractConditionWithAbi,
timeCondition,
compoundCondition,
- ])('same version but different condition', async (condition) => {
+ ])('same version but different condition', (condition) => {
const conditionExprSameVersionDifferentCondition =
new ConditionExpression(condition);
expect(
@@ -149,7 +150,7 @@ describe('condition set', () => {
).not.toBeTruthy();
});
- it('same contract condition although using erc721 helper', async () => {
+ it('same contract condition although using erc721 helper', () => {
const erc721ConditionExpr = new ConditionExpression(
erc721BalanceCondition
);
@@ -172,7 +173,7 @@ describe('condition set', () => {
rpcCondition,
timeCondition,
compoundCondition,
- ])('serializes to and from json', async (condition) => {
+ ])('serializes to and from json', (condition) => {
const conditionExpr = new ConditionExpression(condition);
const conditionExprJson = conditionExpr.toJson();
expect(conditionExprJson).toBeDefined();
@@ -187,7 +188,7 @@ describe('condition set', () => {
expect(conditionExprFromJson.equals(conditionExprFromJson)).toBeTruthy();
});
- it('incompatible version', async () => {
+ it('incompatible version', () => {
const currentVersion = new SemVer(ConditionExpression.VERSION);
const invalidVersion = currentVersion.inc('major');
expect(() => {
@@ -202,7 +203,7 @@ describe('condition set', () => {
it.each(['version', 'x.y', 'x.y.z', '-1,0.0', '1.0.0.0.0.0.0'])(
'invalid versions',
- async (invalidVersion) => {
+ (invalidVersion) => {
expect(() => {
ConditionExpression.fromObj({
version: invalidVersion,
@@ -212,7 +213,36 @@ describe('condition set', () => {
}
);
- it('erc721 condition serialization', async () => {
+ it.each(['_invalid_condition_type_', undefined as unknown as string])(
+ 'rejects an invalid condition type',
+ (invalidConditionType) => {
+ const conditionObj = {
+ ...testTimeConditionObj,
+ conditionType: invalidConditionType,
+ } as unknown as TimeConditionProps;
+ expect(() => {
+ ConditionExpression.fromObj({
+ version: ConditionExpression.VERSION,
+ condition: conditionObj,
+ });
+ }).toThrow(`Invalid conditionType: ${invalidConditionType}`);
+ }
+ );
+
+ it('rejects a mismatched condition type', () => {
+ const conditionObj = {
+ ...testTimeConditionObj,
+ conditionType: 'rpc',
+ } as unknown as TimeConditionProps;
+ expect(() => {
+ ConditionExpression.fromObj({
+ version: ConditionExpression.VERSION,
+ condition: conditionObj,
+ });
+ }).toThrow(/^Invalid condition/);
+ });
+
+ it('erc721 condition serialization', () => {
const conditionExpr = new ConditionExpression(erc721BalanceCondition);
const erc721BalanceConditionObj = erc721BalanceCondition.toObj();
@@ -240,7 +270,7 @@ describe('condition set', () => {
expect(conditionExprFromJson.condition).toBeInstanceOf(ContractCondition);
});
- it('contract condition no abi serialization', async () => {
+ it('contract condition no abi serialization', () => {
const conditionExpr = new ConditionExpression(contractConditionNoAbi);
const conditionExprJson = conditionExpr.toJson();
@@ -272,7 +302,7 @@ describe('condition set', () => {
expect(conditionExprFromJson.condition).toBeInstanceOf(ContractCondition);
});
- it('contract condition with abi serialization', async () => {
+ it('contract condition with abi serialization', () => {
const conditionExpr = new ConditionExpression(contractConditionWithAbi);
const conditionExprJson = conditionExpr.toJson();
@@ -305,7 +335,7 @@ describe('condition set', () => {
expect(conditionExprFromJson.condition).toBeInstanceOf(ContractCondition);
});
- it('time condition serialization', async () => {
+ it('time condition serialization', () => {
const conditionExpr = new ConditionExpression(timeCondition);
const conditionExprJson = conditionExpr.toJson();
@@ -328,7 +358,7 @@ describe('condition set', () => {
expect(conditionExprFromJson.condition).toBeInstanceOf(TimeCondition);
});
- it('rpc condition serialization', async () => {
+ it('rpc condition serialization', () => {
const conditionExpr = new ConditionExpression(rpcCondition);
const conditionExprJson = conditionExpr.toJson();
@@ -352,7 +382,7 @@ describe('condition set', () => {
expect(conditionExprFromJson.condition).toBeInstanceOf(RpcCondition);
});
- it('compound condition serialization', async () => {
+ it('compound condition serialization', () => {
const conditionExpr = new ConditionExpression(compoundCondition);
const compoundConditionObj = compoundCondition.toObj();
diff --git a/test/unit/testVariables.ts b/test/unit/testVariables.ts
index c7f85dec8..1acfe86eb 100644
--- a/test/unit/testVariables.ts
+++ b/test/unit/testVariables.ts
@@ -4,7 +4,7 @@ import {
TimeConditionProps,
} from '../../src/conditions/base';
import { FunctionAbiProps } from '../../src/conditions/base/contract';
-import { ReturnValueTestProps } from '../../src/conditions/base/rpc';
+import { ReturnValueTestProps } from '../../src/conditions/base/shared';
export const aliceSecretKeyBytes = new Uint8Array([
55, 82, 190, 189, 203, 164, 60, 148, 36, 86, 46, 123, 63, 152, 215, 113, 174,
From 84c8ef4b63c68a39e727ec856241d4988c8a1672 Mon Sep 17 00:00:00 2001
From: Piotr Roslaniec
Date: Tue, 5 Sep 2023 20:37:24 +0200
Subject: [PATCH 3/3] update after rebase
---
src/conditions/zod.ts | 4 +-
yarn.lock | 301 ++++++++++++++++++------------------------
2 files changed, 132 insertions(+), 173 deletions(-)
diff --git a/src/conditions/zod.ts b/src/conditions/zod.ts
index 1829e1201..3e5ca9e68 100644
--- a/src/conditions/zod.ts
+++ b/src/conditions/zod.ts
@@ -2,14 +2,14 @@ import { Primitive, z, ZodLiteral } from 'zod';
// Source: https://github.com/colinhacks/zod/issues/831#issuecomment-1063481764
const createUnion = <
- T extends Readonly<[Primitive, Primitive, ...Primitive[]]>
+ T extends Readonly<[Primitive, Primitive, ...Primitive[]]>,
>(
values: T
) => {
const zodLiterals = values.map((value) => z.literal(value)) as unknown as [
ZodLiteral,
ZodLiteral,
- ...ZodLiteral[]
+ ...ZodLiteral[],
];
return z.union(zodLiterals);
};
diff --git a/yarn.lock b/yarn.lock
index 1176f978f..7a7ef1720 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -23,12 +23,12 @@
"@babel/highlight" "^7.22.10"
chalk "^2.4.2"
-"@babel/code-frame@^7.22.10":
- version "7.22.10"
- resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.10.tgz#1c20e612b768fefa75f6e90d6ecb86329247f0a3"
- integrity sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==
+"@babel/code-frame@^7.22.13":
+ version "7.22.13"
+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e"
+ integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==
dependencies:
- "@babel/highlight" "^7.22.10"
+ "@babel/highlight" "^7.22.13"
chalk "^2.4.2"
"@babel/compat-data@^7.22.5", "@babel/compat-data@^7.22.6", "@babel/compat-data@^7.22.9":
@@ -78,7 +78,7 @@
json5 "^2.2.2"
semver "^6.3.1"
-"@babel/generator@^7.22.10":
+"@babel/generator@^7.22.10", "@babel/generator@^7.7.2":
version "7.22.10"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.10.tgz#c92254361f398e160645ac58831069707382b722"
integrity sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==
@@ -88,12 +88,12 @@
"@jridgewell/trace-mapping" "^0.3.17"
jsesc "^2.5.1"
-"@babel/generator@^7.22.10", "@babel/generator@^7.7.2":
- version "7.22.10"
- resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.10.tgz#c92254361f398e160645ac58831069707382b722"
- integrity sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==
+"@babel/generator@^7.22.15":
+ version "7.22.15"
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.15.tgz#1564189c7ec94cb8f77b5e8a90c4d200d21b2339"
+ integrity sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA==
dependencies:
- "@babel/types" "^7.22.10"
+ "@babel/types" "^7.22.15"
"@jridgewell/gen-mapping" "^0.3.2"
"@jridgewell/trace-mapping" "^0.3.17"
jsesc "^2.5.1"
@@ -112,17 +112,6 @@
dependencies:
"@babel/types" "^7.22.10"
-"@babel/helper-compilation-targets@^7.22.10":
- version "7.22.10"
- resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.10.tgz#01d648bbc25dd88f513d862ee0df27b7d4e67024"
- integrity sha512-JMSwHD4J7SLod0idLq5PKgI+6g/hLD/iuWBq08ZX49xE14VpVEojJ5rHWptpirV2j020MvypRLAXAO50igCJ5Q==
- dependencies:
- "@babel/compat-data" "^7.22.9"
- "@babel/helper-validator-option" "^7.22.5"
- browserslist "^4.21.9"
- lru-cache "^5.1.1"
- semver "^6.3.1"
-
"@babel/helper-compilation-targets@^7.22.10", "@babel/helper-compilation-targets@^7.22.5", "@babel/helper-compilation-targets@^7.22.6":
version "7.22.10"
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.10.tgz#01d648bbc25dd88f513d862ee0df27b7d4e67024"
@@ -270,6 +259,11 @@
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f"
integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==
+"@babel/helper-validator-identifier@^7.22.15":
+ version "7.22.15"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz#601fa28e4cc06786c18912dca138cec73b882044"
+ integrity sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==
+
"@babel/helper-validator-identifier@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193"
@@ -289,15 +283,6 @@
"@babel/template" "^7.22.5"
"@babel/types" "^7.22.10"
-"@babel/helpers@^7.22.11":
- version "7.22.11"
- resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.22.11.tgz#b02f5d5f2d7abc21ab59eeed80de410ba70b056a"
- integrity sha512-vyOXC8PBWaGc5h7GMsNx68OH33cypkEDJCHvYVVgVbbxJDROYVtexSk0gK5iCF1xNjRIN2s8ai7hwkWDq5szWg==
- dependencies:
- "@babel/template" "^7.22.5"
- "@babel/traverse" "^7.22.11"
- "@babel/types" "^7.22.11"
-
"@babel/helpers@^7.22.10":
version "7.22.10"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.22.10.tgz#ae6005c539dfbcb5cd71fb51bfc8a52ba63bc37a"
@@ -307,6 +292,15 @@
"@babel/traverse" "^7.22.10"
"@babel/types" "^7.22.10"
+"@babel/helpers@^7.22.11":
+ version "7.22.11"
+ resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.22.11.tgz#b02f5d5f2d7abc21ab59eeed80de410ba70b056a"
+ integrity sha512-vyOXC8PBWaGc5h7GMsNx68OH33cypkEDJCHvYVVgVbbxJDROYVtexSk0gK5iCF1xNjRIN2s8ai7hwkWDq5szWg==
+ dependencies:
+ "@babel/template" "^7.22.5"
+ "@babel/traverse" "^7.22.11"
+ "@babel/types" "^7.22.11"
+
"@babel/highlight@^7.22.10":
version "7.22.10"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.10.tgz#02a3f6d8c1cb4521b2fd0ab0da8f4739936137d7"
@@ -316,10 +310,10 @@
chalk "^2.4.2"
js-tokens "^4.0.0"
-"@babel/highlight@^7.22.10":
- version "7.22.10"
- resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.10.tgz#02a3f6d8c1cb4521b2fd0ab0da8f4739936137d7"
- integrity sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==
+"@babel/highlight@^7.22.13":
+ version "7.22.13"
+ resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.13.tgz#9cda839e5d3be9ca9e8c26b6dd69e7548f0cbf16"
+ integrity sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==
dependencies:
"@babel/helper-validator-identifier" "^7.22.5"
chalk "^2.4.2"
@@ -335,6 +329,11 @@
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.11.tgz#becf8ee33aad2a35ed5607f521fe6e72a615f905"
integrity sha512-R5zb8eJIBPJriQtbH/htEQy4k7E2dHWlD2Y2VT07JCzwYZHBxV5ZYtM0UhXSNMT74LyxuM+b1jdL7pSesXbC/g==
+"@babel/parser@^7.22.15":
+ version "7.22.15"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.15.tgz#d34592bfe288a32e741aa0663dbc4829fcd55160"
+ integrity sha512-RWmQ/sklUN9BvGGpCDgSubhHWfAx24XDTDObup4ffvxaYsptOg2P3KG0j+1eWKLxpkX0j0uHxmpq2Z1SP/VhxA==
+
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.5.tgz#87245a21cd69a73b0b81bcda98d443d6df08f05e"
@@ -1015,7 +1014,7 @@
"@babel/parser" "^7.22.5"
"@babel/types" "^7.22.5"
-"@babel/traverse@^7.22.10", "@babel/traverse@^7.7.2":
+"@babel/traverse@^7.22.10":
version "7.22.10"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.10.tgz#20252acb240e746d27c2e82b4484f199cf8141aa"
integrity sha512-Q/urqV4pRByiNNpb/f5OSv28ZlGJiFiiTh+GAHktbIrkPhPbl90+uW6SmpoLyZqutrg9AEaEf3Q/ZBRHBXgxig==
@@ -1031,7 +1030,23 @@
debug "^4.1.0"
globals "^11.1.0"
-"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.10", "@babel/types@^7.22.5", "@babel/types@^7.3.3", "@babel/types@^7.4.4":
+"@babel/traverse@^7.22.11":
+ version "7.22.15"
+ resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.15.tgz#75be4d2d6e216e880e93017f4e2389aeb77ef2d9"
+ integrity sha512-DdHPwvJY0sEeN4xJU5uRLmZjgMMDIvMPniLuYzUVXj/GGzysPl0/fwt44JBkyUIzGJPV8QgHMcQdQ34XFuKTYQ==
+ dependencies:
+ "@babel/code-frame" "^7.22.13"
+ "@babel/generator" "^7.22.15"
+ "@babel/helper-environment-visitor" "^7.22.5"
+ "@babel/helper-function-name" "^7.22.5"
+ "@babel/helper-hoist-variables" "^7.22.5"
+ "@babel/helper-split-export-declaration" "^7.22.6"
+ "@babel/parser" "^7.22.15"
+ "@babel/types" "^7.22.15"
+ debug "^4.1.0"
+ globals "^11.1.0"
+
+"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.5", "@babel/types@^7.3.3", "@babel/types@^7.4.4":
version "7.22.10"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.10.tgz#4a9e76446048f2c66982d1a989dd12b8a2d2dc03"
integrity sha512-obaoigiLrlDZ7TUQln/8m4mSqIW2QFeOrCQc9r+xsaHGNoplVNYlRVpsfE8Vj35GEm2ZH4ZhrNYogs/3fj85kg==
@@ -1049,6 +1064,15 @@
"@babel/helper-validator-identifier" "^7.22.5"
to-fast-properties "^2.0.0"
+"@babel/types@^7.22.15":
+ version "7.22.15"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.15.tgz#266cb21d2c5fd0b3931e7a91b6dd72d2f617d282"
+ integrity sha512-X+NLXr0N8XXmN5ZsaQdm9U2SSC3UbIYq/doL++sueHOTisgZHoKaQtZxGuV2cUPQHMfjKEfg/g6oy7Hm6SKFtA==
+ dependencies:
+ "@babel/helper-string-parser" "^7.22.5"
+ "@babel/helper-validator-identifier" "^7.22.15"
+ to-fast-properties "^2.0.0"
+
"@bcoe/v8-coverage@^0.2.3":
version "0.2.3"
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
@@ -1721,7 +1745,7 @@
slash "^3.0.0"
write-file-atomic "^4.0.2"
-"@jest/types@^29.6.3":
+"@jest/types@^29.6.1", "@jest/types@^29.6.3":
version "29.6.3"
resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59"
integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==
@@ -1742,7 +1766,7 @@
"@jridgewell/sourcemap-codec" "^1.4.10"
"@jridgewell/trace-mapping" "^0.3.9"
-"@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0", "@jridgewell/resolve-uri@^3.1.0":
+"@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0":
version "3.1.1"
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721"
integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==
@@ -1752,7 +1776,7 @@
resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
-"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.14":
+"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14":
version "1.4.15"
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
@@ -1765,15 +1789,7 @@
"@jridgewell/resolve-uri" "^3.0.3"
"@jridgewell/sourcemap-codec" "^1.4.10"
-"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18":
- version "0.3.19"
- resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz#f8a3249862f91be48d3127c3cfe992f79b4b8811"
- integrity sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==
- dependencies:
- "@jridgewell/resolve-uri" "^3.1.0"
- "@jridgewell/sourcemap-codec" "^1.4.14"
-
-"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9":
+"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.9":
version "0.3.19"
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz#f8a3249862f91be48d3127c3cfe992f79b4b8811"
integrity sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==
@@ -1812,11 +1828,6 @@
resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e"
integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==
-"@sinclair/typebox@^0.27.8":
- version "0.27.8"
- resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e"
- integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==
-
"@sinonjs/commons@^3.0.0":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.0.tgz#beb434fe875d965265e04722ccfc21df7f755d72"
@@ -2334,6 +2345,14 @@ available-typed-arrays@^1.0.5:
resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7"
integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==
+axios@^0.27.2:
+ version "0.27.2"
+ resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972"
+ integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==
+ dependencies:
+ follow-redirects "^1.14.9"
+ form-data "^4.0.0"
+
axios@^1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-1.5.0.tgz#f02e4af823e2e46a9768cfc74691fdd0517ea267"
@@ -2343,14 +2362,6 @@ axios@^1.5.0:
form-data "^4.0.0"
proxy-from-env "^1.1.0"
-axios@^0.27.2:
- version "0.27.2"
- resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972"
- integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==
- dependencies:
- follow-redirects "^1.14.9"
- form-data "^4.0.0"
-
babel-jest@^29.6.4:
version "29.6.4"
resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.6.4.tgz#98dbc45d1c93319c82a8ab4a478b670655dd2585"
@@ -2515,11 +2526,6 @@ brotli-size@^4.0.0:
dependencies:
duplexer "0.1.1"
-browser-process-hrtime@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626"
- integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==
-
browserslist@^4.21.10, browserslist@^4.21.9:
version "4.21.10"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.10.tgz#dbbac576628c13d3b2231332cb2ec5a46e015bb0"
@@ -3681,17 +3687,6 @@ expand-tilde@^2.0.0, expand-tilde@^2.0.2:
dependencies:
homedir-polyfill "^1.0.1"
-expect@^29.0.0, expect@^29.6.4:
- version "29.6.4"
- resolved "https://registry.yarnpkg.com/expect/-/expect-29.6.4.tgz#a6e6f66d4613717859b2fe3da98a739437b6f4b8"
- integrity sha512-F2W2UyQ8XYyftHT57dtfg8Ue3X5qLgm2sSug0ivvLRH/VKNRL/pDxg/TH7zVzbQB0tu80clNFy6LU7OS/VSEKA==
- dependencies:
- "@jest/expect-utils" "^29.6.4"
- jest-get-type "^29.6.3"
- jest-matcher-utils "^29.6.4"
- jest-message-util "^29.6.3"
- jest-util "^29.6.3"
-
expect@^29.0.0:
version "29.6.2"
resolved "https://registry.yarnpkg.com/expect/-/expect-29.6.2.tgz#7b08e83eba18ddc4a2cf62b5f2d1918f5cd84521"
@@ -3704,6 +3699,17 @@ expect@^29.0.0:
jest-message-util "^29.6.2"
jest-util "^29.6.2"
+expect@^29.6.4:
+ version "29.6.4"
+ resolved "https://registry.yarnpkg.com/expect/-/expect-29.6.4.tgz#a6e6f66d4613717859b2fe3da98a739437b6f4b8"
+ integrity sha512-F2W2UyQ8XYyftHT57dtfg8Ue3X5qLgm2sSug0ivvLRH/VKNRL/pDxg/TH7zVzbQB0tu80clNFy6LU7OS/VSEKA==
+ dependencies:
+ "@jest/expect-utils" "^29.6.4"
+ jest-get-type "^29.6.3"
+ jest-matcher-utils "^29.6.4"
+ jest-message-util "^29.6.3"
+ jest-util "^29.6.3"
+
external-editor@^3.0.3:
version "3.1.0"
resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
@@ -3887,7 +3893,7 @@ flatted@^3.1.0:
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787"
integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==
-follow-redirects@^1.15.0, follow-redirects@^1.14.9:
+follow-redirects@^1.14.9, follow-redirects@^1.15.0:
version "1.15.2"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
@@ -3908,15 +3914,6 @@ form-data@^4.0.0:
combined-stream "^1.0.8"
mime-types "^2.1.12"
-form-data@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
- integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
- dependencies:
- asynckit "^0.4.0"
- combined-stream "^1.0.8"
- mime-types "^2.1.12"
-
fs-extra@9.1.0:
version "9.1.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d"
@@ -4470,14 +4467,7 @@ is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7:
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055"
integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==
-is-core-module@^2.13.0, is-core-module@^2.5.0:
- version "2.13.0"
- resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db"
- integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==
- dependencies:
- has "^1.0.3"
-
-is-core-module@^2.13.0, is-core-module@^2.8.1:
+is-core-module@^2.13.0, is-core-module@^2.5.0, is-core-module@^2.8.1:
version "2.13.0"
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db"
integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==
@@ -4821,7 +4811,7 @@ jest-config@^29.6.4:
slash "^3.0.0"
strip-json-comments "^3.1.1"
-jest-diff@^29.6.4:
+jest-diff@^29.6.2, jest-diff@^29.6.4:
version "29.6.4"
resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.6.4.tgz#85aaa6c92a79ae8cd9a54ebae8d5b6d9a513314a"
integrity sha512-9F48UxR9e4XOEZvoUXEHSWY4qC4zERJaOfrbBg9JpbJOO43R1vN76REt/aMGZoY6GD5g84nnJiBIVlscegefpw==
@@ -4861,7 +4851,7 @@ jest-environment-node@^29.6.4:
jest-mock "^29.6.3"
jest-util "^29.6.3"
-jest-get-type@^29.6.3:
+jest-get-type@^29.4.3, jest-get-type@^29.6.3:
version "29.6.3"
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1"
integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==
@@ -4893,6 +4883,16 @@ jest-leak-detector@^29.6.3:
jest-get-type "^29.6.3"
pretty-format "^29.6.3"
+jest-matcher-utils@^29.6.2:
+ version "29.6.2"
+ resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.6.2.tgz#39de0be2baca7a64eacb27291f0bd834fea3a535"
+ integrity sha512-4LiAk3hSSobtomeIAzFTe+N8kL6z0JtF3n6I4fg29iIW7tt99R7ZcIFW34QkX+DuVrf+CUe6wuVOpm7ZKFJzZQ==
+ dependencies:
+ chalk "^4.0.0"
+ jest-diff "^29.6.2"
+ jest-get-type "^29.4.3"
+ pretty-format "^29.6.2"
+
jest-matcher-utils@^29.6.4:
version "29.6.4"
resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.6.4.tgz#327db7ababea49455df3b23e5d6109fe0c709d24"
@@ -4903,15 +4903,20 @@ jest-matcher-utils@^29.6.4:
jest-get-type "^29.6.3"
pretty-format "^29.6.3"
-jest-matcher-utils@^29.6.2:
+jest-message-util@^29.6.2:
version "29.6.2"
- resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.6.2.tgz#39de0be2baca7a64eacb27291f0bd834fea3a535"
- integrity sha512-4LiAk3hSSobtomeIAzFTe+N8kL6z0JtF3n6I4fg29iIW7tt99R7ZcIFW34QkX+DuVrf+CUe6wuVOpm7ZKFJzZQ==
+ resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.6.2.tgz#af7adc2209c552f3f5ae31e77cf0a261f23dc2bb"
+ integrity sha512-vnIGYEjoPSuRqV8W9t+Wow95SDp6KPX2Uf7EoeG9G99J2OVh7OSwpS4B6J0NfpEIpfkBNHlBZpA2rblEuEFhZQ==
dependencies:
+ "@babel/code-frame" "^7.12.13"
+ "@jest/types" "^29.6.1"
+ "@types/stack-utils" "^2.0.0"
chalk "^4.0.0"
- jest-diff "^29.6.2"
- jest-get-type "^29.4.3"
+ graceful-fs "^4.2.9"
+ micromatch "^4.0.4"
pretty-format "^29.6.2"
+ slash "^3.0.0"
+ stack-utils "^2.0.3"
jest-message-util@^29.6.3:
version "29.6.3"
@@ -4928,21 +4933,6 @@ jest-message-util@^29.6.3:
slash "^3.0.0"
stack-utils "^2.0.3"
-jest-message-util@^29.6.2:
- version "29.6.2"
- resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.6.2.tgz#af7adc2209c552f3f5ae31e77cf0a261f23dc2bb"
- integrity sha512-vnIGYEjoPSuRqV8W9t+Wow95SDp6KPX2Uf7EoeG9G99J2OVh7OSwpS4B6J0NfpEIpfkBNHlBZpA2rblEuEFhZQ==
- dependencies:
- "@babel/code-frame" "^7.12.13"
- "@jest/types" "^29.6.1"
- "@types/stack-utils" "^2.0.0"
- chalk "^4.0.0"
- graceful-fs "^4.2.9"
- micromatch "^4.0.4"
- pretty-format "^29.6.2"
- slash "^3.0.0"
- stack-utils "^2.0.3"
-
jest-mock@^29.6.3:
version "29.6.3"
resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.6.3.tgz#433f3fd528c8ec5a76860177484940628bdf5e0a"
@@ -6063,15 +6053,6 @@ prettier@^3.0.2:
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.0.2.tgz#78fcecd6d870551aa5547437cdae39d4701dca5b"
integrity sha512-o2YR9qtniXvwEZlOKbveKfDQVyqxbEIWn48Z8m3ZJjBjcCmUy3xZGIv+7AkaeuaTr6yPXJjwv07ZWlsWbEy1rQ==
-pretty-format@^29.0.0, pretty-format@^29.6.3:
- version "29.6.3"
- resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.6.3.tgz#d432bb4f1ca6f9463410c3fb25a0ba88e594ace7"
- integrity sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==
- dependencies:
- "@jest/schemas" "^29.6.3"
- ansi-styles "^5.0.0"
- react-is "^18.0.0"
-
pretty-format@^29.0.0, pretty-format@^29.6.2:
version "29.6.2"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.6.2.tgz#3d5829261a8a4d89d8b9769064b29c50ed486a47"
@@ -6081,6 +6062,15 @@ pretty-format@^29.0.0, pretty-format@^29.6.2:
ansi-styles "^5.0.0"
react-is "^18.0.0"
+pretty-format@^29.6.3:
+ version "29.6.3"
+ resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.6.3.tgz#d432bb4f1ca6f9463410c3fb25a0ba88e594ace7"
+ integrity sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==
+ dependencies:
+ "@jest/schemas" "^29.6.3"
+ ansi-styles "^5.0.0"
+ react-is "^18.0.0"
+
process-nextick-args@~2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
@@ -6094,19 +6084,15 @@ prompts@^2.0.1:
kleur "^3.0.3"
sisteransi "^1.0.5"
-proxy-from-env@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
- integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
property-expr@^2.0.4:
version "2.0.5"
resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.5.tgz#278bdb15308ae16af3e3b9640024524f4dc02cb4"
integrity sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA==
-psl@^1.1.33:
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7"
- integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==
+proxy-from-env@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
+ integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
punycode@^2.1.0:
version "2.3.0"
@@ -6150,11 +6136,6 @@ react-is@^18.0.0:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
-react-is@^18.0.0:
- version "18.2.0"
- resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
- integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
-
read-pkg-up@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07"
@@ -6895,23 +6876,6 @@ toposort@^2.0.2:
resolved "https://registry.yarnpkg.com/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330"
integrity sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==
-tough-cookie@^4.0.0:
- version "4.1.3"
- resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf"
- integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==
- dependencies:
- psl "^1.1.33"
- punycode "^2.1.1"
- universalify "^0.2.0"
- url-parse "^1.5.3"
-
-tr46@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240"
- integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==
- dependencies:
- punycode "^2.1.1"
-
trim-newlines@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144"
@@ -7237,15 +7201,10 @@ v8-compile-cache-lib@^3.0.1:
resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf"
integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==
-v8-compile-cache@^2.0.3:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz#cdada8bec61e15865f05d097c5f4fd30e94dc128"
- integrity sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==
-
-v8-to-istanbul@^8.1.0:
- version "8.1.1"
- resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz#77b752fd3975e31bbcef938f85e9bd1c7a8d60ed"
- integrity sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==
+v8-to-istanbul@^9.0.1:
+ version "9.1.0"
+ resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz#1b83ed4e397f58c85c266a570fc2558b5feb9265"
+ integrity sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==
dependencies:
"@jridgewell/trace-mapping" "^0.3.12"
"@types/istanbul-lib-coverage" "^2.0.1"
@@ -7445,6 +7404,11 @@ yocto-queue@^0.1.0:
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
+yocto-queue@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.0.0.tgz#7f816433fb2cbc511ec8bf7d263c3b58a1a3c251"
+ integrity sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==
+
yup@^0.32.11:
version "0.32.11"
resolved "https://registry.yarnpkg.com/yup/-/yup-0.32.11.tgz#d67fb83eefa4698607982e63f7ca4c5ed3cf18c5"
@@ -7458,11 +7422,6 @@ yup@^0.32.11:
property-expr "^2.0.4"
toposort "^2.0.2"
-yocto-queue@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.0.0.tgz#7f816433fb2cbc511ec8bf7d263c3b58a1a3c251"
- integrity sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==
-
zod@^3.22.1:
version "3.22.1"
resolved "https://registry.yarnpkg.com/zod/-/zod-3.22.1.tgz#815f850baf933fef96c1061322dbe579b1a80c27"