diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 67c0ac867..941a3684f 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -18,9 +18,17 @@ jobs: strategy: matrix: node-version: [18.x] + prisma-version: [v4, v5] steps: - - uses: actions/checkout@v3 + - name: Checkout + uses: actions/checkout@v3 + + - name: Set Prisma Version + if: ${{ matrix.prisma-version == 'v5' }} + shell: bash + run: | + bash ./script/test-prisma-v5.sh - name: Install pnpm uses: pnpm/action-setup@v2 diff --git a/package.json b/package.json index e3e1c318f..08a617323 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "zenstack-monorepo", - "version": "1.0.0-beta.8", + "version": "1.0.0-beta.9", "description": "", "scripts": { "build": "pnpm -r build", @@ -14,6 +14,9 @@ "author": "", "license": "MIT", "devDependencies": { - "@changesets/cli": "^2.26.0" + "@changesets/cli": "^2.26.0", + "concurrently": "^7.4.0", + "replace-in-file": "^7.0.1", + "tsup": "^7.1.0" } } diff --git a/packages/language/package.json b/packages/language/package.json index 698c32def..de3f4ac13 100644 --- a/packages/language/package.json +++ b/packages/language/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/language", - "version": "1.0.0-beta.8", + "version": "1.0.0-beta.9", "displayName": "ZenStack modeling language compiler", "description": "ZenStack modeling language compiler", "homepage": "https://zenstack.dev", diff --git a/packages/language/src/generated/ast.ts b/packages/language/src/generated/ast.ts index e086b82e5..e8737b257 100644 --- a/packages/language/src/generated/ast.ts +++ b/packages/language/src/generated/ast.ts @@ -194,6 +194,7 @@ export interface DataModel extends AstNode { comments: Array fields: Array isAbstract: boolean + isView: boolean name: RegularID superTypes: Array> } @@ -748,6 +749,7 @@ export class ZModelAstReflection extends AbstractAstReflection { { name: 'comments', type: 'array' }, { name: 'fields', type: 'array' }, { name: 'isAbstract', type: 'boolean' }, + { name: 'isView', type: 'boolean' }, { name: 'superTypes', type: 'array' } ] }; diff --git a/packages/language/src/generated/grammar.ts b/packages/language/src/generated/grammar.ts index 7561db187..a0b1c972b 100644 --- a/packages/language/src/generated/grammar.ts +++ b/packages/language/src/generated/grammar.ts @@ -1681,74 +1681,110 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "cardinality": "*" }, { - "$type": "Assignment", - "feature": "isAbstract", - "operator": "?=", - "terminal": { - "$type": "Keyword", - "value": "abstract" - }, - "cardinality": "?" - }, - { - "$type": "Keyword", - "value": "model" - }, - { - "$type": "Assignment", - "feature": "name", - "operator": "=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$ref": "#/rules@40" - }, - "arguments": [] - } - }, - { - "$type": "Group", + "$type": "Alternatives", "elements": [ { - "$type": "Keyword", - "value": "extends" - }, - { - "$type": "Assignment", - "feature": "superTypes", - "operator": "+=", - "terminal": { - "$type": "CrossReference", - "type": { - "$ref": "#/rules@30" + "$type": "Group", + "elements": [ + { + "$type": "Assignment", + "feature": "isAbstract", + "operator": "?=", + "terminal": { + "$type": "Keyword", + "value": "abstract" + }, + "cardinality": "?" }, - "deprecatedSyntax": false - } + { + "$type": "Keyword", + "value": "model" + }, + { + "$type": "Assignment", + "feature": "name", + "operator": "=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$ref": "#/rules@40" + }, + "arguments": [] + } + }, + { + "$type": "Group", + "elements": [ + { + "$type": "Keyword", + "value": "extends" + }, + { + "$type": "Assignment", + "feature": "superTypes", + "operator": "+=", + "terminal": { + "$type": "CrossReference", + "type": { + "$ref": "#/rules@30" + }, + "deprecatedSyntax": false + } + }, + { + "$type": "Group", + "elements": [ + { + "$type": "Keyword", + "value": "," + }, + { + "$type": "Assignment", + "feature": "superTypes", + "operator": "+=", + "terminal": { + "$type": "CrossReference", + "type": { + "$ref": "#/rules@30" + }, + "deprecatedSyntax": false + } + } + ], + "cardinality": "*" + } + ], + "cardinality": "?" + } + ] }, { "$type": "Group", "elements": [ { - "$type": "Keyword", - "value": "," + "$type": "Assignment", + "feature": "isView", + "operator": "?=", + "terminal": { + "$type": "Keyword", + "value": "view" + } }, { "$type": "Assignment", - "feature": "superTypes", - "operator": "+=", + "feature": "name", + "operator": "=", "terminal": { - "$type": "CrossReference", - "type": { - "$ref": "#/rules@30" + "$type": "RuleCall", + "rule": { + "$ref": "#/rules@40" }, - "deprecatedSyntax": false + "arguments": [] } } - ], - "cardinality": "*" + ] } - ], - "cardinality": "?" + ] }, { "$type": "Keyword", diff --git a/packages/language/src/zmodel.langium b/packages/language/src/zmodel.langium index 89cdfa8ee..6a4b993ab 100644 --- a/packages/language/src/zmodel.langium +++ b/packages/language/src/zmodel.langium @@ -156,8 +156,12 @@ Argument: // model DataModel: (comments+=TRIPLE_SLASH_COMMENT)* - (isAbstract?='abstract')? 'model' name=RegularID - ('extends' superTypes+=[DataModel] (',' superTypes+=[DataModel])*)? '{' ( + ( + ((isAbstract?='abstract')? 'model' name=RegularID + ('extends' superTypes+=[DataModel] (',' superTypes+=[DataModel])*)?) | + ((isView?='view') name=RegularID) + ) + '{' ( fields+=DataModelField | attributes+=DataModelAttribute )+ diff --git a/packages/language/syntaxes/zmodel.tmLanguage.json b/packages/language/syntaxes/zmodel.tmLanguage.json index 2db106523..d886d9b61 100644 --- a/packages/language/syntaxes/zmodel.tmLanguage.json +++ b/packages/language/syntaxes/zmodel.tmLanguage.json @@ -10,7 +10,7 @@ }, { "name": "keyword.control.zmodel", - "match": "\\b(Any|Asc|BigInt|Boolean|Bytes|ContextType|DateTime|Decimal|Desc|FieldReference|Float|Int|Json|Null|Object|String|TransitiveFieldReference|Unsupported|abstract|attribute|datasource|enum|extends|false|function|generator|import|in|model|plugin|sort|true)\\b" + "match": "\\b(Any|Asc|BigInt|Boolean|Bytes|ContextType|DateTime|Decimal|Desc|FieldReference|Float|Int|Json|Null|Object|String|TransitiveFieldReference|Unsupported|abstract|attribute|datasource|enum|extends|false|function|generator|import|in|model|plugin|sort|true|view)\\b" }, { "name": "string.quoted.double.zmodel", diff --git a/packages/plugins/openapi/package.json b/packages/plugins/openapi/package.json index 140969c8b..246e727c4 100644 --- a/packages/plugins/openapi/package.json +++ b/packages/plugins/openapi/package.json @@ -1,7 +1,7 @@ { "name": "@zenstackhq/openapi", "displayName": "ZenStack Plugin and Runtime for OpenAPI", - "version": "1.0.0-beta.8", + "version": "1.0.0-beta.9", "description": "ZenStack plugin and runtime supporting OpenAPI", "main": "index.js", "repository": { @@ -24,7 +24,7 @@ "author": "ZenStack Team", "license": "MIT", "dependencies": { - "@prisma/generator-helper": "4.10.0", + "@prisma/generator-helper": "^5.0.0", "@zenstackhq/runtime": "workspace:*", "@zenstackhq/sdk": "workspace:*", "change-case": "^4.1.2", @@ -36,10 +36,9 @@ "zod-validation-error": "^0.2.1" }, "devDependencies": { - "@prisma/internals": "4.10.0", "@readme/openapi-parser": "^2.4.0", "@types/jest": "^29.5.0", - "@types/lower-case-first": "^1.0.1", + "@types/node": "^18.0.0", "@types/pluralize": "^0.0.29", "@types/tmp": "^0.2.3", "@typescript-eslint/eslint-plugin": "^5.54.0", diff --git a/packages/plugins/openapi/src/generator-base.ts b/packages/plugins/openapi/src/generator-base.ts index ee507f2f4..5f3e5d933 100644 --- a/packages/plugins/openapi/src/generator-base.ts +++ b/packages/plugins/openapi/src/generator-base.ts @@ -1,4 +1,4 @@ -import { DMMF } from '@prisma/generator-helper'; +import type { DMMF } from '@prisma/generator-helper'; import { PluginError, PluginOptions, getDataModels, hasAttribute } from '@zenstackhq/sdk'; import { Model } from '@zenstackhq/sdk/ast'; import type { OpenAPIV3_1 as OAPI } from 'openapi-types'; diff --git a/packages/plugins/openapi/src/index.ts b/packages/plugins/openapi/src/index.ts index ee1f42543..ddc752d8c 100644 --- a/packages/plugins/openapi/src/index.ts +++ b/packages/plugins/openapi/src/index.ts @@ -1,4 +1,4 @@ -import { DMMF } from '@prisma/generator-helper'; +import type { DMMF } from '@prisma/generator-helper'; import { PluginError, PluginOptions } from '@zenstackhq/sdk'; import { Model } from '@zenstackhq/sdk/ast'; import { RESTfulOpenAPIGenerator } from './rest-generator'; diff --git a/packages/plugins/openapi/src/rest-generator.ts b/packages/plugins/openapi/src/rest-generator.ts index 5a15f5681..6e50126d8 100644 --- a/packages/plugins/openapi/src/rest-generator.ts +++ b/packages/plugins/openapi/src/rest-generator.ts @@ -1,6 +1,6 @@ // Inspired by: https://github.com/omar-dulaimi/prisma-trpc-generator -import { DMMF } from '@prisma/generator-helper'; +import type { DMMF } from '@prisma/generator-helper'; import { AUXILIARY_FIELDS, analyzePolicies, @@ -536,12 +536,16 @@ export class RESTfulOpenAPIGenerator extends OpenAPIGeneratorBase { required: ['version'], properties: { version: { type: 'string' }, - meta: this.ref('_meta'), }, }, _meta: { type: 'object', - description: 'Meta information about the response', + description: 'Meta information about the request or response', + properties: { + serialization: { + description: 'Superjson serialization metadata', + }, + }, additionalProperties: true, }, _resourceIdentifier: { @@ -759,6 +763,7 @@ export class RESTfulOpenAPIGenerator extends OpenAPIGeneratorBase { required: ['data'], properties: { data: this.generateModelEntity(model, 'create'), + meta: this.ref('_meta'), }, }; @@ -766,7 +771,7 @@ export class RESTfulOpenAPIGenerator extends OpenAPIGeneratorBase { type: 'object', description: `Input for updating a "${model.name}"`, required: ['data'], - properties: { data: this.generateModelEntity(model, 'update') }, + properties: { data: this.generateModelEntity(model, 'update'), meta: this.ref('_meta') }, }; const relationships: Record = {}; @@ -790,7 +795,7 @@ export class RESTfulOpenAPIGenerator extends OpenAPIGeneratorBase { type: 'object', properties: { relationships: { type: 'object', properties: relationships } }, }), - + meta: this.ref('_meta'), included: { type: 'array', items: this.ref('_resource'), @@ -811,6 +816,7 @@ export class RESTfulOpenAPIGenerator extends OpenAPIGeneratorBase { properties: { relationships: { type: 'object', properties: relationships } }, }) ), + meta: this.ref('_meta'), included: { type: 'array', items: this.ref('_resource'), @@ -895,14 +901,17 @@ export class RESTfulOpenAPIGenerator extends OpenAPIGeneratorBase { case 'BigInt': return { type: 'integer' }; case 'Float': - case 'Decimal': return { type: 'number' }; + case 'Decimal': + return this.oneOf({ type: 'number' }, { type: 'string' }); case 'Boolean': return { type: 'boolean' }; case 'DateTime': return { type: 'string', format: 'date-time' }; + case 'Bytes': + return { type: 'string', format: 'byte', description: 'Base64 encoded byte array' }; case 'Json': - return { type: 'object' }; + return {}; default: { const fieldDecl = type.reference?.ref; invariant(fieldDecl); diff --git a/packages/plugins/openapi/src/rpc-generator.ts b/packages/plugins/openapi/src/rpc-generator.ts index 303ac3f83..f3476d031 100644 --- a/packages/plugins/openapi/src/rpc-generator.ts +++ b/packages/plugins/openapi/src/rpc-generator.ts @@ -144,15 +144,17 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase { `${model.name}CreateArgs`, { type: 'object', + required: ['data'], properties: { select: this.ref(`${model.name}Select`), include: hasRelation ? this.ref(`${model.name}Include`) : undefined, data: this.ref(`${model.name}CreateInput`), + meta: this.ref('_Meta'), }, }, components ), - outputType: this.ref(model.name), + outputType: this.response(this.ref(model.name)), description: `Create a new ${model.name}`, successCode: 201, security: create === true ? [] : undefined, @@ -167,13 +169,15 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase { `${model.name}CreateManyArgs`, { type: 'object', + required: ['data'], properties: { data: this.ref(`${model.name}CreateManyInput`), + meta: this.ref('_Meta'), }, }, components ), - outputType: this.ref('BatchPayload'), + outputType: this.response(this.ref('BatchPayload')), description: `Create several ${model.name}`, successCode: 201, security: create === true ? [] : undefined, @@ -188,15 +192,17 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase { `${model.name}FindUniqueArgs`, { type: 'object', + required: ['where'], properties: { select: this.ref(`${model.name}Select`), include: hasRelation ? this.ref(`${model.name}Include`) : undefined, where: this.ref(`${model.name}WhereUniqueInput`), + meta: this.ref('_Meta'), }, }, components ), - outputType: this.ref(model.name), + outputType: this.response(this.ref(model.name)), description: `Find one unique ${model.name}`, security: read === true ? [] : undefined, }); @@ -214,11 +220,12 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase { select: this.ref(`${model.name}Select`), include: hasRelation ? this.ref(`${model.name}Include`) : undefined, where: this.ref(`${model.name}WhereInput`), + meta: this.ref('_Meta'), }, }, components ), - outputType: this.ref(model.name), + outputType: this.response(this.ref(model.name)), description: `Find the first ${model.name} matching the given condition`, security: read === true ? [] : undefined, }); @@ -236,11 +243,12 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase { select: this.ref(`${model.name}Select`), include: hasRelation ? this.ref(`${model.name}Include`) : undefined, where: this.ref(`${model.name}WhereInput`), + meta: this.ref('_Meta'), }, }, components ), - outputType: this.array(this.ref(model.name)), + outputType: this.response(this.array(this.ref(model.name))), description: `Find a list of ${model.name}`, security: read === true ? [] : undefined, }); @@ -254,16 +262,18 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase { `${model.name}UpdateArgs`, { type: 'object', + required: ['where', 'data'], properties: { select: this.ref(`${model.name}Select`), include: hasRelation ? this.ref(`${model.name}Include`) : undefined, where: this.ref(`${model.name}WhereUniqueInput`), data: this.ref(`${model.name}UpdateInput`), + meta: this.ref('_Meta'), }, }, components ), - outputType: this.ref(model.name), + outputType: this.response(this.ref(model.name)), description: `Update a ${model.name}`, security: update === true ? [] : undefined, }); @@ -277,14 +287,16 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase { `${model.name}UpdateManyArgs`, { type: 'object', + required: ['data'], properties: { where: this.ref(`${model.name}WhereInput`), data: this.ref(`${model.name}UpdateManyMutationInput`), + meta: this.ref('_Meta'), }, }, components ), - outputType: this.ref('BatchPayload'), + outputType: this.response(this.ref('BatchPayload')), description: `Update ${model.name}s matching the given condition`, security: update === true ? [] : undefined, }); @@ -298,17 +310,19 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase { `${model.name}UpsertArgs`, { type: 'object', + required: ['create', 'update', 'where'], properties: { select: this.ref(`${model.name}Select`), include: hasRelation ? this.ref(`${model.name}Include`) : undefined, where: this.ref(`${model.name}WhereUniqueInput`), create: this.ref(`${model.name}CreateInput`), update: this.ref(`${model.name}UpdateInput`), + meta: this.ref('_Meta'), }, }, components ), - outputType: this.ref(model.name), + outputType: this.response(this.ref(model.name)), description: `Upsert a ${model.name}`, security: create === true && update == true ? [] : undefined, }); @@ -322,15 +336,17 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase { `${model.name}DeleteUniqueArgs`, { type: 'object', + required: ['where'], properties: { select: this.ref(`${model.name}Select`), include: hasRelation ? this.ref(`${model.name}Include`) : undefined, where: this.ref(`${model.name}WhereUniqueInput`), + meta: this.ref('_Meta'), }, }, components ), - outputType: this.ref(model.name), + outputType: this.response(this.ref(model.name)), description: `Delete one unique ${model.name}`, security: del === true ? [] : undefined, }); @@ -346,11 +362,12 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase { type: 'object', properties: { where: this.ref(`${model.name}WhereInput`), + meta: this.ref('_Meta'), }, }, components ), - outputType: this.ref('BatchPayload'), + outputType: this.response(this.ref('BatchPayload')), description: `Delete ${model.name}s matching the given condition`, security: del === true ? [] : undefined, }); @@ -367,11 +384,14 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase { properties: { select: this.ref(`${model.name}Select`), where: this.ref(`${model.name}WhereInput`), + meta: this.ref('_Meta'), }, }, components ), - outputType: this.oneOf({ type: 'integer' }, this.ref(`${model.name}CountAggregateOutputType`)), + outputType: this.response( + this.oneOf({ type: 'integer' }, this.ref(`${model.name}CountAggregateOutputType`)) + ), description: `Find a list of ${model.name}`, security: read === true ? [] : undefined, }); @@ -391,11 +411,12 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase { take: { type: 'integer' }, skip: { type: 'integer' }, ...this.aggregateFields(model), + meta: this.ref('_Meta'), }, }, components ), - outputType: this.ref(`Aggregate${model.name}`), + outputType: this.response(this.ref(`Aggregate${model.name}`)), description: `Aggregate ${model.name}s`, security: read === true ? [] : undefined, }); @@ -417,11 +438,12 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase { take: { type: 'integer' }, skip: { type: 'integer' }, ...this.aggregateFields(model), + meta: this.ref('_Meta'), }, }, components ), - outputType: this.array(this.ref(`${model.name}GroupByOutputType`)), + outputType: this.response(this.array(this.ref(`${model.name}GroupByOutputType`))), description: `Group ${model.name}s by fields`, security: read === true ? [] : undefined, }); @@ -467,9 +489,19 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase { }, }, '400': { + content: { + 'application/json': { + schema: this.ref('_Error'), + }, + }, description: 'Invalid request', }, '403': { + content: { + 'application/json': { + schema: this.ref('_Error'), + }, + }, description: 'Request is forbidden', }, }, @@ -490,12 +522,23 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase { name: 'q', in: 'query', required: true, + description: 'Superjson-serialized Prisma query object', content: { 'application/json': { schema: inputType, }, }, }, + { + name: 'meta', + in: 'query', + description: 'Superjson serialization metadata for parameter "q"', + content: { + 'application/json': { + schema: {}, + }, + }, + }, ] satisfies OAPI.ParameterObject[]; } } @@ -563,6 +606,56 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase { schemas[output.name] = this.generateOutputComponent(output); } + schemas['_Meta'] = { + type: 'object', + properties: { + meta: { + type: 'object', + description: 'Meta information about the request or response', + properties: { + serialization: { + description: 'Serialization metadata', + }, + }, + additionalProperties: true, + }, + }, + }; + + schemas['_Error'] = { + type: 'object', + required: ['error'], + properties: { + error: { + type: 'object', + required: ['message'], + properties: { + prisma: { + type: 'boolean', + description: 'Indicates if the error occurred during a Prisma call', + }, + rejectedByPolicy: { + type: 'boolean', + description: 'Indicates if the error was due to rejection by a policy', + }, + code: { + type: 'string', + description: 'Prisma error code. Only available when "prisma" field is true.', + }, + message: { + type: 'string', + description: 'Error message', + }, + reason: { + type: 'string', + description: 'Detailed error reason', + }, + }, + additionalProperties: true, + }, + }, + }; + // misc types schemas['BatchPayload'] = { type: 'object', @@ -620,7 +713,12 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase { const fields = input.fields.filter((f) => !AUXILIARY_FIELDS.includes(f.name)); for (const field of fields) { const options = field.inputTypes - .filter((f) => f.type !== 'Null') + .filter( + (f) => + f.type !== 'Null' && + // fieldRefTypes refer to other fields in the model and don't need to be generated as part of schema + f.location !== 'fieldRefTypes' + ) .map((f) => { return this.wrapArray(this.prismaTypeToOpenAPIType(f.type), f.isList); }); @@ -682,13 +780,16 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase { case 'BigInt': return { type: 'integer' }; case 'Float': - case 'Decimal': return { type: 'number' }; + case 'Decimal': + return this.oneOf({ type: 'string' }, { type: 'number' }); case 'Boolean': case 'True': return { type: 'boolean' }; case 'DateTime': return { type: 'string', format: 'date-time' }; + case 'Bytes': + return { type: 'string', format: 'byte' }; case 'JSON': case 'Json': return {}; @@ -697,10 +798,21 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase { } } - private ref(type: string, rooted = true) { + private ref(type: string, rooted = true, description?: string): OAPI.ReferenceObject { if (rooted) { this.usedComponents.add(type); } - return { $ref: `#/components/schemas/${type}` }; + return { $ref: `#/components/schemas/${type}`, description }; + } + + private response(schema: OAPI.SchemaObject): OAPI.SchemaObject { + return { + type: 'object', + required: ['data'], + properties: { + data: { ...schema, description: 'The Prisma response data serialized with superjson' }, + meta: this.ref('_Meta', true, 'The superjson serialization metadata for the "data" field'), + }, + }; } } diff --git a/packages/plugins/openapi/tests/baseline/rest-type-coverage.baseline.yaml b/packages/plugins/openapi/tests/baseline/rest-type-coverage.baseline.yaml new file mode 100644 index 000000000..72f43187f --- /dev/null +++ b/packages/plugins/openapi/tests/baseline/rest-type-coverage.baseline.yaml @@ -0,0 +1,802 @@ +openapi: 3.1.0 +info: + title: ZenStack Generated API + version: 1.0.0 +tags: + - name: foo + description: Foo operations +paths: + /foo: + get: + operationId: list-Foo + description: List "Foo" resources + tags: + - foo + parameters: + - $ref: '#/components/parameters/include' + - $ref: '#/components/parameters/sort' + - $ref: '#/components/parameters/page-offset' + - $ref: '#/components/parameters/page-limit' + - name: filter[id] + required: false + description: Id filter + in: query + style: form + explode: false + schema: + type: string + - name: filter[string] + required: false + description: Equality filter for "string" + in: query + style: form + explode: false + schema: + type: string + - name: filter[string$contains] + required: false + description: String contains filter for "string" + in: query + style: form + explode: false + schema: + type: string + - name: filter[string$icontains] + required: false + description: String case-insensitive contains filter for "string" + in: query + style: form + explode: false + schema: + type: string + - name: filter[string$search] + required: false + description: String full-text search filter for "string" + in: query + style: form + explode: false + schema: + type: string + - name: filter[string$startsWith] + required: false + description: String startsWith filter for "string" + in: query + style: form + explode: false + schema: + type: string + - name: filter[string$endsWith] + required: false + description: String endsWith filter for "string" + in: query + style: form + explode: false + schema: + type: string + - name: filter[int] + required: false + description: Equality filter for "int" + in: query + style: form + explode: false + schema: + type: integer + - name: filter[int$lt] + required: false + description: Less-than filter for "int" + in: query + style: form + explode: false + schema: + type: integer + - name: filter[int$lte] + required: false + description: Less-than or equal filter for "int" + in: query + style: form + explode: false + schema: + type: integer + - name: filter[int$gt] + required: false + description: Greater-than filter for "int" + in: query + style: form + explode: false + schema: + type: integer + - name: filter[int$gte] + required: false + description: Greater-than or equal filter for "int" + in: query + style: form + explode: false + schema: + type: integer + - name: filter[bigInt] + required: false + description: Equality filter for "bigInt" + in: query + style: form + explode: false + schema: + type: integer + - name: filter[bigInt$lt] + required: false + description: Less-than filter for "bigInt" + in: query + style: form + explode: false + schema: + type: integer + - name: filter[bigInt$lte] + required: false + description: Less-than or equal filter for "bigInt" + in: query + style: form + explode: false + schema: + type: integer + - name: filter[bigInt$gt] + required: false + description: Greater-than filter for "bigInt" + in: query + style: form + explode: false + schema: + type: integer + - name: filter[bigInt$gte] + required: false + description: Greater-than or equal filter for "bigInt" + in: query + style: form + explode: false + schema: + type: integer + - name: filter[date] + required: false + description: Equality filter for "date" + in: query + style: form + explode: false + schema: + type: string + format: date-time + - name: filter[date$lt] + required: false + description: Less-than filter for "date" + in: query + style: form + explode: false + schema: + type: string + format: date-time + - name: filter[date$lte] + required: false + description: Less-than or equal filter for "date" + in: query + style: form + explode: false + schema: + type: string + format: date-time + - name: filter[date$gt] + required: false + description: Greater-than filter for "date" + in: query + style: form + explode: false + schema: + type: string + format: date-time + - name: filter[date$gte] + required: false + description: Greater-than or equal filter for "date" + in: query + style: form + explode: false + schema: + type: string + format: date-time + - name: filter[float] + required: false + description: Equality filter for "float" + in: query + style: form + explode: false + schema: + type: number + - name: filter[float$lt] + required: false + description: Less-than filter for "float" + in: query + style: form + explode: false + schema: + type: number + - name: filter[float$lte] + required: false + description: Less-than or equal filter for "float" + in: query + style: form + explode: false + schema: + type: number + - name: filter[float$gt] + required: false + description: Greater-than filter for "float" + in: query + style: form + explode: false + schema: + type: number + - name: filter[float$gte] + required: false + description: Greater-than or equal filter for "float" + in: query + style: form + explode: false + schema: + type: number + - name: filter[decimal] + required: false + description: Equality filter for "decimal" + in: query + style: form + explode: false + schema: + oneOf: + - type: number + - type: string + - name: filter[decimal$lt] + required: false + description: Less-than filter for "decimal" + in: query + style: form + explode: false + schema: + oneOf: + - type: number + - type: string + - name: filter[decimal$lte] + required: false + description: Less-than or equal filter for "decimal" + in: query + style: form + explode: false + schema: + oneOf: + - type: number + - type: string + - name: filter[decimal$gt] + required: false + description: Greater-than filter for "decimal" + in: query + style: form + explode: false + schema: + oneOf: + - type: number + - type: string + - name: filter[decimal$gte] + required: false + description: Greater-than or equal filter for "decimal" + in: query + style: form + explode: false + schema: + oneOf: + - type: number + - type: string + - name: filter[boolean] + required: false + description: Equality filter for "boolean" + in: query + style: form + explode: false + schema: + type: boolean + - name: filter[bytes] + required: false + description: Equality filter for "bytes" + in: query + style: form + explode: false + schema: + type: string + format: byte + description: Base64 encoded byte array + responses: + '200': + description: Successful operation + content: + application/vnd.api+json: + schema: + $ref: '#/components/schemas/FooListResponse' + '403': + description: Request is forbidden + content: + application/vnd.api+json: + schema: + $ref: '#/components/schemas/_errorResponse' + security: [] + post: + operationId: create-Foo + description: Create a "Foo" resource + tags: + - foo + requestBody: + content: + application/vnd.api+json: + schema: + $ref: '#/components/schemas/FooCreateRequest' + responses: + '201': + description: Successful operation + content: + application/vnd.api+json: + schema: + $ref: '#/components/schemas/FooResponse' + '403': + description: Request is forbidden + content: + application/vnd.api+json: + schema: + $ref: '#/components/schemas/_errorResponse' + security: [] + '/foo/{id}': + get: + operationId: fetch-Foo + description: Fetch a "Foo" resource + tags: + - foo + parameters: + - $ref: '#/components/parameters/id' + - $ref: '#/components/parameters/include' + responses: + '200': + description: Successful operation + content: + application/vnd.api+json: + schema: + $ref: '#/components/schemas/FooResponse' + '403': + description: Request is forbidden + content: + application/vnd.api+json: + schema: + $ref: '#/components/schemas/_errorResponse' + '404': + description: Resource is not found + content: + application/vnd.api+json: + schema: + $ref: '#/components/schemas/_errorResponse' + security: [] + put: + operationId: update-Foo-put + description: Update a "Foo" resource + tags: + - foo + parameters: + - $ref: '#/components/parameters/id' + requestBody: + content: + application/vnd.api+json: + schema: + $ref: '#/components/schemas/FooUpdateRequest' + responses: + '200': + description: Successful operation + content: + application/vnd.api+json: + schema: + $ref: '#/components/schemas/FooResponse' + '403': + description: Request is forbidden + content: + application/vnd.api+json: + schema: + $ref: '#/components/schemas/_errorResponse' + '404': + description: Resource is not found + content: + application/vnd.api+json: + schema: + $ref: '#/components/schemas/_errorResponse' + security: [] + patch: + operationId: update-Foo-patch + description: Update a "Foo" resource + tags: + - foo + parameters: + - $ref: '#/components/parameters/id' + requestBody: + content: + application/vnd.api+json: + schema: + $ref: '#/components/schemas/FooUpdateRequest' + responses: + '200': + description: Successful operation + content: + application/vnd.api+json: + schema: + $ref: '#/components/schemas/FooResponse' + '403': + description: Request is forbidden + content: + application/vnd.api+json: + schema: + $ref: '#/components/schemas/_errorResponse' + '404': + description: Resource is not found + content: + application/vnd.api+json: + schema: + $ref: '#/components/schemas/_errorResponse' + security: [] + delete: + operationId: delete-Foo + description: Delete a "Foo" resource + tags: + - foo + parameters: + - $ref: '#/components/parameters/id' + responses: + '200': + description: Successful operation + '403': + description: Request is forbidden + content: + application/vnd.api+json: + schema: + $ref: '#/components/schemas/_errorResponse' + '404': + description: Resource is not found + content: + application/vnd.api+json: + schema: + $ref: '#/components/schemas/_errorResponse' + security: [] +components: + schemas: + _jsonapi: + type: object + description: An object describing the server’s implementation + required: + - version + properties: + version: + type: string + _meta: + type: object + description: Meta information about the request or response + properties: + serialization: + description: Superjson serialization metadata + additionalProperties: true + _resourceIdentifier: + type: object + description: Identifier for a resource + required: + - type + - id + properties: + type: + type: string + description: Resource type + id: + type: string + description: Resource id + _resource: + allOf: + - $ref: '#/components/schemas/_resourceIdentifier' + - type: object + description: A resource with attributes and relationships + properties: + attributes: + type: object + description: Resource attributes + relationships: + type: object + description: Resource relationships + _links: + type: object + required: + - self + description: Links related to the resource + properties: + self: + type: string + description: Link for refetching the curent results + _pagination: + type: object + description: Pagination information + required: + - first + - last + - prev + - next + properties: + first: + oneOf: + - type: string + description: Link to the first page + - type: 'null' + last: + oneOf: + - type: string + description: Link to the last page + - type: 'null' + prev: + oneOf: + - type: string + description: Link to the previous page + - type: 'null' + next: + oneOf: + - type: string + description: Link to the next page + - type: 'null' + _errors: + type: array + description: An array of error objects + items: + type: object + required: + - status + - code + properties: + status: + type: string + description: HTTP status + code: + type: string + description: Error code + prismaCode: + type: string + description: Prisma error code if the error is thrown by Prisma + title: + type: string + description: Error title + detail: + type: string + description: Error detail + _errorResponse: + type: object + required: + - errors + description: An error response + properties: + jsonapi: + $ref: '#/components/schemas/_jsonapi' + errors: + $ref: '#/components/schemas/_errors' + Foo: + type: object + description: The "Foo" model + required: + - id + - type + - attributes + properties: + type: + type: string + id: + type: string + attributes: + type: object + properties: + string: + type: string + int: + type: integer + bigInt: + type: integer + date: + type: string + format: date-time + float: + type: number + decimal: + oneOf: + - type: number + - type: string + boolean: + type: boolean + bytes: + type: string + format: byte + description: Base64 encoded byte array + FooCreateRequest: + type: object + description: Input for creating a "Foo" + required: + - data + properties: + data: + type: object + description: The "Foo" model + required: + - id + - type + - attributes + properties: + type: + type: string + id: + type: string + attributes: + type: object + required: + - string + - int + - bigInt + - date + - float + - decimal + - boolean + - bytes + properties: + string: + type: string + int: + type: integer + bigInt: + type: integer + date: + type: string + format: date-time + float: + type: number + decimal: + oneOf: + - type: number + - type: string + boolean: + type: boolean + bytes: + type: string + format: byte + description: Base64 encoded byte array + meta: + $ref: '#/components/schemas/_meta' + FooUpdateRequest: + type: object + description: Input for updating a "Foo" + required: + - data + properties: + data: + type: object + description: The "Foo" model + required: + - id + - type + - attributes + properties: + type: + type: string + id: + type: string + attributes: + type: object + properties: + string: + type: string + int: + type: integer + bigInt: + type: integer + date: + type: string + format: date-time + float: + type: number + decimal: + oneOf: + - type: number + - type: string + boolean: + type: boolean + bytes: + type: string + format: byte + description: Base64 encoded byte array + meta: + $ref: '#/components/schemas/_meta' + FooResponse: + type: object + description: Response for a "Foo" + required: + - data + properties: + jsonapi: + $ref: '#/components/schemas/_jsonapi' + data: + allOf: + - $ref: '#/components/schemas/Foo' + - type: object + properties: + relationships: + type: object + properties: &a1 {} + meta: + $ref: '#/components/schemas/_meta' + included: + type: array + items: + $ref: '#/components/schemas/_resource' + links: + $ref: '#/components/schemas/_links' + FooListResponse: + type: object + description: Response for a list of "Foo" + required: + - data + - links + properties: + jsonapi: + $ref: '#/components/schemas/_jsonapi' + data: + type: array + items: + allOf: + - $ref: '#/components/schemas/Foo' + - type: object + properties: + relationships: + type: object + properties: *a1 + meta: + $ref: '#/components/schemas/_meta' + included: + type: array + items: + $ref: '#/components/schemas/_resource' + links: + allOf: + - $ref: '#/components/schemas/_links' + - $ref: '#/components/schemas/_pagination' + parameters: + id: + name: id + in: path + description: The resource id + required: true + schema: + type: string + include: + name: include + in: query + description: Relationships to include + required: false + style: form + schema: + type: string + sort: + name: sort + in: query + description: Fields to sort by + required: false + style: form + schema: + type: string + page-offset: + name: page[offset] + in: query + description: Offset for pagination + required: false + style: form + schema: + type: integer + page-limit: + name: page[limit] + in: query + description: Limit for pagination + required: false + style: form + schema: + type: integer diff --git a/packages/plugins/openapi/tests/baseline/rest.baseline.yaml b/packages/plugins/openapi/tests/baseline/rest.baseline.yaml index 1c5542024..466556993 100644 --- a/packages/plugins/openapi/tests/baseline/rest.baseline.yaml +++ b/packages/plugins/openapi/tests/baseline/rest.baseline.yaml @@ -1301,11 +1301,12 @@ components: properties: version: type: string - meta: - $ref: '#/components/schemas/_meta' _meta: type: object - description: Meta information about the response + description: Meta information about the request or response + properties: + serialization: + description: Superjson serialization metadata additionalProperties: true _resourceIdentifier: type: object @@ -1577,6 +1578,8 @@ components: properties: posts: $ref: '#/components/schemas/_toManyRelationship' + meta: + $ref: '#/components/schemas/_meta' UserUpdateRequest: type: object description: Input for updating a "User" @@ -1613,6 +1616,8 @@ components: properties: posts: $ref: '#/components/schemas/_toManyRelationship' + meta: + $ref: '#/components/schemas/_meta' UserResponse: type: object description: Response for a "User" @@ -1631,6 +1636,8 @@ components: properties: &a1 posts: $ref: '#/components/schemas/_toManyRelationship' + meta: + $ref: '#/components/schemas/_meta' included: type: array items: @@ -1656,6 +1663,8 @@ components: relationships: type: object properties: *a1 + meta: + $ref: '#/components/schemas/_meta' included: type: array items: @@ -1741,6 +1750,8 @@ components: properties: author: $ref: '#/components/schemas/_toOneRelationship' + meta: + $ref: '#/components/schemas/_meta' PostUpdateRequest: type: object description: Input for updating a "Post" @@ -1781,6 +1792,8 @@ components: properties: author: $ref: '#/components/schemas/_toOneRelationship' + meta: + $ref: '#/components/schemas/_meta' PostResponse: type: object description: Response for a "Post" @@ -1799,6 +1812,8 @@ components: properties: &a2 author: $ref: '#/components/schemas/_toOneRelationship' + meta: + $ref: '#/components/schemas/_meta' included: type: array items: @@ -1824,6 +1839,8 @@ components: relationships: type: object properties: *a2 + meta: + $ref: '#/components/schemas/_meta' included: type: array items: diff --git a/packages/plugins/openapi/tests/baseline/rpc-type-coverage.baseline.yaml b/packages/plugins/openapi/tests/baseline/rpc-type-coverage.baseline.yaml new file mode 100644 index 000000000..a5cc407bc --- /dev/null +++ b/packages/plugins/openapi/tests/baseline/rpc-type-coverage.baseline.yaml @@ -0,0 +1,2518 @@ +openapi: 3.1.0 +info: + title: ZenStack Generated API + version: 1.0.0 +tags: + - name: foo + description: Foo operations +components: + schemas: + FooScalarFieldEnum: + type: string + enum: + - id + - string + - int + - bigInt + - date + - float + - decimal + - boolean + - bytes + QueryMode: + type: string + enum: + - default + - insensitive + SortOrder: + type: string + enum: + - asc + - desc + Foo: + type: object + properties: + id: + type: string + string: + type: string + int: + type: integer + bigInt: + type: integer + date: + type: string + format: date-time + float: + type: number + decimal: + oneOf: + - type: string + - type: number + boolean: + type: boolean + bytes: + type: string + format: byte + required: + - id + - string + - int + - bigInt + - date + - float + - decimal + - boolean + - bytes + FooWhereInput: + type: object + properties: + AND: + oneOf: + - $ref: '#/components/schemas/FooWhereInput' + - type: array + items: + $ref: '#/components/schemas/FooWhereInput' + OR: + type: array + items: + $ref: '#/components/schemas/FooWhereInput' + NOT: + oneOf: + - $ref: '#/components/schemas/FooWhereInput' + - type: array + items: + $ref: '#/components/schemas/FooWhereInput' + id: + oneOf: + - $ref: '#/components/schemas/StringFilter' + - type: string + string: + oneOf: + - $ref: '#/components/schemas/StringFilter' + - type: string + int: + oneOf: + - $ref: '#/components/schemas/IntFilter' + - type: integer + bigInt: + oneOf: + - $ref: '#/components/schemas/BigIntFilter' + - type: integer + date: + oneOf: + - $ref: '#/components/schemas/DateTimeFilter' + - type: string + format: date-time + float: + oneOf: + - $ref: '#/components/schemas/FloatFilter' + - type: number + decimal: + oneOf: + - $ref: '#/components/schemas/DecimalFilter' + - oneOf: + - type: string + - type: number + boolean: + oneOf: + - $ref: '#/components/schemas/BoolFilter' + - type: boolean + bytes: + oneOf: + - $ref: '#/components/schemas/BytesFilter' + - type: string + format: byte + FooOrderByWithRelationInput: + type: object + properties: + id: + $ref: '#/components/schemas/SortOrder' + string: + $ref: '#/components/schemas/SortOrder' + int: + $ref: '#/components/schemas/SortOrder' + bigInt: + $ref: '#/components/schemas/SortOrder' + date: + $ref: '#/components/schemas/SortOrder' + float: + $ref: '#/components/schemas/SortOrder' + decimal: + $ref: '#/components/schemas/SortOrder' + boolean: + $ref: '#/components/schemas/SortOrder' + bytes: + $ref: '#/components/schemas/SortOrder' + FooWhereUniqueInput: + type: object + properties: + id: + type: string + FooScalarWhereWithAggregatesInput: + type: object + properties: + AND: + oneOf: + - $ref: '#/components/schemas/FooScalarWhereWithAggregatesInput' + - type: array + items: + $ref: '#/components/schemas/FooScalarWhereWithAggregatesInput' + OR: + type: array + items: + $ref: '#/components/schemas/FooScalarWhereWithAggregatesInput' + NOT: + oneOf: + - $ref: '#/components/schemas/FooScalarWhereWithAggregatesInput' + - type: array + items: + $ref: '#/components/schemas/FooScalarWhereWithAggregatesInput' + id: + oneOf: + - $ref: '#/components/schemas/StringWithAggregatesFilter' + - type: string + string: + oneOf: + - $ref: '#/components/schemas/StringWithAggregatesFilter' + - type: string + int: + oneOf: + - $ref: '#/components/schemas/IntWithAggregatesFilter' + - type: integer + bigInt: + oneOf: + - $ref: '#/components/schemas/BigIntWithAggregatesFilter' + - type: integer + date: + oneOf: + - $ref: '#/components/schemas/DateTimeWithAggregatesFilter' + - type: string + format: date-time + float: + oneOf: + - $ref: '#/components/schemas/FloatWithAggregatesFilter' + - type: number + decimal: + oneOf: + - $ref: '#/components/schemas/DecimalWithAggregatesFilter' + - oneOf: + - type: string + - type: number + boolean: + oneOf: + - $ref: '#/components/schemas/BoolWithAggregatesFilter' + - type: boolean + bytes: + oneOf: + - $ref: '#/components/schemas/BytesWithAggregatesFilter' + - type: string + format: byte + FooCreateInput: + type: object + properties: + id: + type: string + string: + type: string + int: + type: integer + bigInt: + type: integer + date: + type: string + format: date-time + float: + type: number + decimal: + oneOf: + - type: string + - type: number + boolean: + type: boolean + bytes: + type: string + format: byte + required: + - string + - int + - bigInt + - date + - float + - decimal + - boolean + - bytes + FooUpdateInput: + type: object + properties: + id: + oneOf: + - type: string + - $ref: '#/components/schemas/StringFieldUpdateOperationsInput' + string: + oneOf: + - type: string + - $ref: '#/components/schemas/StringFieldUpdateOperationsInput' + int: + oneOf: + - type: integer + - $ref: '#/components/schemas/IntFieldUpdateOperationsInput' + bigInt: + oneOf: + - type: integer + - $ref: '#/components/schemas/BigIntFieldUpdateOperationsInput' + date: + oneOf: + - type: string + format: date-time + - $ref: '#/components/schemas/DateTimeFieldUpdateOperationsInput' + float: + oneOf: + - type: number + - $ref: '#/components/schemas/FloatFieldUpdateOperationsInput' + decimal: + oneOf: + - oneOf: + - type: string + - type: number + - $ref: '#/components/schemas/DecimalFieldUpdateOperationsInput' + boolean: + oneOf: + - type: boolean + - $ref: '#/components/schemas/BoolFieldUpdateOperationsInput' + bytes: + oneOf: + - type: string + format: byte + - $ref: '#/components/schemas/BytesFieldUpdateOperationsInput' + FooCreateManyInput: + type: object + properties: + id: + type: string + string: + type: string + int: + type: integer + bigInt: + type: integer + date: + type: string + format: date-time + float: + type: number + decimal: + oneOf: + - type: string + - type: number + boolean: + type: boolean + bytes: + type: string + format: byte + required: + - string + - int + - bigInt + - date + - float + - decimal + - boolean + - bytes + FooUpdateManyMutationInput: + type: object + properties: + id: + oneOf: + - type: string + - $ref: '#/components/schemas/StringFieldUpdateOperationsInput' + string: + oneOf: + - type: string + - $ref: '#/components/schemas/StringFieldUpdateOperationsInput' + int: + oneOf: + - type: integer + - $ref: '#/components/schemas/IntFieldUpdateOperationsInput' + bigInt: + oneOf: + - type: integer + - $ref: '#/components/schemas/BigIntFieldUpdateOperationsInput' + date: + oneOf: + - type: string + format: date-time + - $ref: '#/components/schemas/DateTimeFieldUpdateOperationsInput' + float: + oneOf: + - type: number + - $ref: '#/components/schemas/FloatFieldUpdateOperationsInput' + decimal: + oneOf: + - oneOf: + - type: string + - type: number + - $ref: '#/components/schemas/DecimalFieldUpdateOperationsInput' + boolean: + oneOf: + - type: boolean + - $ref: '#/components/schemas/BoolFieldUpdateOperationsInput' + bytes: + oneOf: + - type: string + format: byte + - $ref: '#/components/schemas/BytesFieldUpdateOperationsInput' + StringFilter: + type: object + properties: + equals: + type: string + in: + type: array + items: + type: string + notIn: + type: array + items: + type: string + lt: + type: string + lte: + type: string + gt: + type: string + gte: + type: string + contains: + type: string + startsWith: + type: string + endsWith: + type: string + mode: + $ref: '#/components/schemas/QueryMode' + not: + oneOf: + - type: string + - $ref: '#/components/schemas/NestedStringFilter' + IntFilter: + type: object + properties: + equals: + type: integer + in: + type: array + items: + type: integer + notIn: + type: array + items: + type: integer + lt: + type: integer + lte: + type: integer + gt: + type: integer + gte: + type: integer + not: + oneOf: + - type: integer + - $ref: '#/components/schemas/NestedIntFilter' + BigIntFilter: + type: object + properties: + equals: + type: integer + in: + type: array + items: + type: integer + notIn: + type: array + items: + type: integer + lt: + type: integer + lte: + type: integer + gt: + type: integer + gte: + type: integer + not: + oneOf: + - type: integer + - $ref: '#/components/schemas/NestedBigIntFilter' + DateTimeFilter: + type: object + properties: + equals: + type: string + format: date-time + in: + type: array + items: + type: string + format: date-time + notIn: + type: array + items: + type: string + format: date-time + lt: + type: string + format: date-time + lte: + type: string + format: date-time + gt: + type: string + format: date-time + gte: + type: string + format: date-time + not: + oneOf: + - type: string + format: date-time + - $ref: '#/components/schemas/NestedDateTimeFilter' + FloatFilter: + type: object + properties: + equals: + type: number + in: + type: array + items: + type: number + notIn: + type: array + items: + type: number + lt: + type: number + lte: + type: number + gt: + type: number + gte: + type: number + not: + oneOf: + - type: number + - $ref: '#/components/schemas/NestedFloatFilter' + DecimalFilter: + type: object + properties: + equals: + oneOf: + - type: string + - type: number + in: + type: array + items: + oneOf: + - type: string + - type: number + notIn: + type: array + items: + oneOf: + - type: string + - type: number + lt: + oneOf: + - type: string + - type: number + lte: + oneOf: + - type: string + - type: number + gt: + oneOf: + - type: string + - type: number + gte: + oneOf: + - type: string + - type: number + not: + oneOf: + - oneOf: + - type: string + - type: number + - $ref: '#/components/schemas/NestedDecimalFilter' + BoolFilter: + type: object + properties: + equals: + type: boolean + not: + oneOf: + - type: boolean + - $ref: '#/components/schemas/NestedBoolFilter' + BytesFilter: + type: object + properties: + equals: + type: string + format: byte + in: + type: array + items: + type: string + format: byte + notIn: + type: array + items: + type: string + format: byte + not: + oneOf: + - type: string + format: byte + - $ref: '#/components/schemas/NestedBytesFilter' + StringWithAggregatesFilter: + type: object + properties: + equals: + type: string + in: + type: array + items: + type: string + notIn: + type: array + items: + type: string + lt: + type: string + lte: + type: string + gt: + type: string + gte: + type: string + contains: + type: string + startsWith: + type: string + endsWith: + type: string + mode: + $ref: '#/components/schemas/QueryMode' + not: + oneOf: + - type: string + - $ref: '#/components/schemas/NestedStringWithAggregatesFilter' + _count: + $ref: '#/components/schemas/NestedIntFilter' + _min: + $ref: '#/components/schemas/NestedStringFilter' + _max: + $ref: '#/components/schemas/NestedStringFilter' + IntWithAggregatesFilter: + type: object + properties: + equals: + type: integer + in: + type: array + items: + type: integer + notIn: + type: array + items: + type: integer + lt: + type: integer + lte: + type: integer + gt: + type: integer + gte: + type: integer + not: + oneOf: + - type: integer + - $ref: '#/components/schemas/NestedIntWithAggregatesFilter' + _count: + $ref: '#/components/schemas/NestedIntFilter' + _avg: + $ref: '#/components/schemas/NestedFloatFilter' + _sum: + $ref: '#/components/schemas/NestedIntFilter' + _min: + $ref: '#/components/schemas/NestedIntFilter' + _max: + $ref: '#/components/schemas/NestedIntFilter' + BigIntWithAggregatesFilter: + type: object + properties: + equals: + type: integer + in: + type: array + items: + type: integer + notIn: + type: array + items: + type: integer + lt: + type: integer + lte: + type: integer + gt: + type: integer + gte: + type: integer + not: + oneOf: + - type: integer + - $ref: '#/components/schemas/NestedBigIntWithAggregatesFilter' + _count: + $ref: '#/components/schemas/NestedIntFilter' + _avg: + $ref: '#/components/schemas/NestedFloatFilter' + _sum: + $ref: '#/components/schemas/NestedBigIntFilter' + _min: + $ref: '#/components/schemas/NestedBigIntFilter' + _max: + $ref: '#/components/schemas/NestedBigIntFilter' + DateTimeWithAggregatesFilter: + type: object + properties: + equals: + type: string + format: date-time + in: + type: array + items: + type: string + format: date-time + notIn: + type: array + items: + type: string + format: date-time + lt: + type: string + format: date-time + lte: + type: string + format: date-time + gt: + type: string + format: date-time + gte: + type: string + format: date-time + not: + oneOf: + - type: string + format: date-time + - $ref: '#/components/schemas/NestedDateTimeWithAggregatesFilter' + _count: + $ref: '#/components/schemas/NestedIntFilter' + _min: + $ref: '#/components/schemas/NestedDateTimeFilter' + _max: + $ref: '#/components/schemas/NestedDateTimeFilter' + FloatWithAggregatesFilter: + type: object + properties: + equals: + type: number + in: + type: array + items: + type: number + notIn: + type: array + items: + type: number + lt: + type: number + lte: + type: number + gt: + type: number + gte: + type: number + not: + oneOf: + - type: number + - $ref: '#/components/schemas/NestedFloatWithAggregatesFilter' + _count: + $ref: '#/components/schemas/NestedIntFilter' + _avg: + $ref: '#/components/schemas/NestedFloatFilter' + _sum: + $ref: '#/components/schemas/NestedFloatFilter' + _min: + $ref: '#/components/schemas/NestedFloatFilter' + _max: + $ref: '#/components/schemas/NestedFloatFilter' + DecimalWithAggregatesFilter: + type: object + properties: + equals: + oneOf: + - type: string + - type: number + in: + type: array + items: + oneOf: + - type: string + - type: number + notIn: + type: array + items: + oneOf: + - type: string + - type: number + lt: + oneOf: + - type: string + - type: number + lte: + oneOf: + - type: string + - type: number + gt: + oneOf: + - type: string + - type: number + gte: + oneOf: + - type: string + - type: number + not: + oneOf: + - oneOf: + - type: string + - type: number + - $ref: '#/components/schemas/NestedDecimalWithAggregatesFilter' + _count: + $ref: '#/components/schemas/NestedIntFilter' + _avg: + $ref: '#/components/schemas/NestedDecimalFilter' + _sum: + $ref: '#/components/schemas/NestedDecimalFilter' + _min: + $ref: '#/components/schemas/NestedDecimalFilter' + _max: + $ref: '#/components/schemas/NestedDecimalFilter' + BoolWithAggregatesFilter: + type: object + properties: + equals: + type: boolean + not: + oneOf: + - type: boolean + - $ref: '#/components/schemas/NestedBoolWithAggregatesFilter' + _count: + $ref: '#/components/schemas/NestedIntFilter' + _min: + $ref: '#/components/schemas/NestedBoolFilter' + _max: + $ref: '#/components/schemas/NestedBoolFilter' + BytesWithAggregatesFilter: + type: object + properties: + equals: + type: string + format: byte + in: + type: array + items: + type: string + format: byte + notIn: + type: array + items: + type: string + format: byte + not: + oneOf: + - type: string + format: byte + - $ref: '#/components/schemas/NestedBytesWithAggregatesFilter' + _count: + $ref: '#/components/schemas/NestedIntFilter' + _min: + $ref: '#/components/schemas/NestedBytesFilter' + _max: + $ref: '#/components/schemas/NestedBytesFilter' + StringFieldUpdateOperationsInput: + type: object + properties: + set: + type: string + IntFieldUpdateOperationsInput: + type: object + properties: + set: + type: integer + increment: + type: integer + decrement: + type: integer + multiply: + type: integer + divide: + type: integer + BigIntFieldUpdateOperationsInput: + type: object + properties: + set: + type: integer + increment: + type: integer + decrement: + type: integer + multiply: + type: integer + divide: + type: integer + DateTimeFieldUpdateOperationsInput: + type: object + properties: + set: + type: string + format: date-time + FloatFieldUpdateOperationsInput: + type: object + properties: + set: + type: number + increment: + type: number + decrement: + type: number + multiply: + type: number + divide: + type: number + DecimalFieldUpdateOperationsInput: + type: object + properties: + set: + oneOf: + - type: string + - type: number + increment: + oneOf: + - type: string + - type: number + decrement: + oneOf: + - type: string + - type: number + multiply: + oneOf: + - type: string + - type: number + divide: + oneOf: + - type: string + - type: number + BoolFieldUpdateOperationsInput: + type: object + properties: + set: + type: boolean + BytesFieldUpdateOperationsInput: + type: object + properties: + set: + type: string + format: byte + NestedStringFilter: + type: object + properties: + equals: + type: string + in: + type: array + items: + type: string + notIn: + type: array + items: + type: string + lt: + type: string + lte: + type: string + gt: + type: string + gte: + type: string + contains: + type: string + startsWith: + type: string + endsWith: + type: string + not: + oneOf: + - type: string + - $ref: '#/components/schemas/NestedStringFilter' + NestedIntFilter: + type: object + properties: + equals: + type: integer + in: + type: array + items: + type: integer + notIn: + type: array + items: + type: integer + lt: + type: integer + lte: + type: integer + gt: + type: integer + gte: + type: integer + not: + oneOf: + - type: integer + - $ref: '#/components/schemas/NestedIntFilter' + NestedBigIntFilter: + type: object + properties: + equals: + type: integer + in: + type: array + items: + type: integer + notIn: + type: array + items: + type: integer + lt: + type: integer + lte: + type: integer + gt: + type: integer + gte: + type: integer + not: + oneOf: + - type: integer + - $ref: '#/components/schemas/NestedBigIntFilter' + NestedDateTimeFilter: + type: object + properties: + equals: + type: string + format: date-time + in: + type: array + items: + type: string + format: date-time + notIn: + type: array + items: + type: string + format: date-time + lt: + type: string + format: date-time + lte: + type: string + format: date-time + gt: + type: string + format: date-time + gte: + type: string + format: date-time + not: + oneOf: + - type: string + format: date-time + - $ref: '#/components/schemas/NestedDateTimeFilter' + NestedFloatFilter: + type: object + properties: + equals: + type: number + in: + type: array + items: + type: number + notIn: + type: array + items: + type: number + lt: + type: number + lte: + type: number + gt: + type: number + gte: + type: number + not: + oneOf: + - type: number + - $ref: '#/components/schemas/NestedFloatFilter' + NestedDecimalFilter: + type: object + properties: + equals: + oneOf: + - type: string + - type: number + in: + type: array + items: + oneOf: + - type: string + - type: number + notIn: + type: array + items: + oneOf: + - type: string + - type: number + lt: + oneOf: + - type: string + - type: number + lte: + oneOf: + - type: string + - type: number + gt: + oneOf: + - type: string + - type: number + gte: + oneOf: + - type: string + - type: number + not: + oneOf: + - oneOf: + - type: string + - type: number + - $ref: '#/components/schemas/NestedDecimalFilter' + NestedBoolFilter: + type: object + properties: + equals: + type: boolean + not: + oneOf: + - type: boolean + - $ref: '#/components/schemas/NestedBoolFilter' + NestedBytesFilter: + type: object + properties: + equals: + type: string + format: byte + in: + type: array + items: + type: string + format: byte + notIn: + type: array + items: + type: string + format: byte + not: + oneOf: + - type: string + format: byte + - $ref: '#/components/schemas/NestedBytesFilter' + NestedStringWithAggregatesFilter: + type: object + properties: + equals: + type: string + in: + type: array + items: + type: string + notIn: + type: array + items: + type: string + lt: + type: string + lte: + type: string + gt: + type: string + gte: + type: string + contains: + type: string + startsWith: + type: string + endsWith: + type: string + not: + oneOf: + - type: string + - $ref: '#/components/schemas/NestedStringWithAggregatesFilter' + _count: + $ref: '#/components/schemas/NestedIntFilter' + _min: + $ref: '#/components/schemas/NestedStringFilter' + _max: + $ref: '#/components/schemas/NestedStringFilter' + NestedIntWithAggregatesFilter: + type: object + properties: + equals: + type: integer + in: + type: array + items: + type: integer + notIn: + type: array + items: + type: integer + lt: + type: integer + lte: + type: integer + gt: + type: integer + gte: + type: integer + not: + oneOf: + - type: integer + - $ref: '#/components/schemas/NestedIntWithAggregatesFilter' + _count: + $ref: '#/components/schemas/NestedIntFilter' + _avg: + $ref: '#/components/schemas/NestedFloatFilter' + _sum: + $ref: '#/components/schemas/NestedIntFilter' + _min: + $ref: '#/components/schemas/NestedIntFilter' + _max: + $ref: '#/components/schemas/NestedIntFilter' + NestedBigIntWithAggregatesFilter: + type: object + properties: + equals: + type: integer + in: + type: array + items: + type: integer + notIn: + type: array + items: + type: integer + lt: + type: integer + lte: + type: integer + gt: + type: integer + gte: + type: integer + not: + oneOf: + - type: integer + - $ref: '#/components/schemas/NestedBigIntWithAggregatesFilter' + _count: + $ref: '#/components/schemas/NestedIntFilter' + _avg: + $ref: '#/components/schemas/NestedFloatFilter' + _sum: + $ref: '#/components/schemas/NestedBigIntFilter' + _min: + $ref: '#/components/schemas/NestedBigIntFilter' + _max: + $ref: '#/components/schemas/NestedBigIntFilter' + NestedDateTimeWithAggregatesFilter: + type: object + properties: + equals: + type: string + format: date-time + in: + type: array + items: + type: string + format: date-time + notIn: + type: array + items: + type: string + format: date-time + lt: + type: string + format: date-time + lte: + type: string + format: date-time + gt: + type: string + format: date-time + gte: + type: string + format: date-time + not: + oneOf: + - type: string + format: date-time + - $ref: '#/components/schemas/NestedDateTimeWithAggregatesFilter' + _count: + $ref: '#/components/schemas/NestedIntFilter' + _min: + $ref: '#/components/schemas/NestedDateTimeFilter' + _max: + $ref: '#/components/schemas/NestedDateTimeFilter' + NestedFloatWithAggregatesFilter: + type: object + properties: + equals: + type: number + in: + type: array + items: + type: number + notIn: + type: array + items: + type: number + lt: + type: number + lte: + type: number + gt: + type: number + gte: + type: number + not: + oneOf: + - type: number + - $ref: '#/components/schemas/NestedFloatWithAggregatesFilter' + _count: + $ref: '#/components/schemas/NestedIntFilter' + _avg: + $ref: '#/components/schemas/NestedFloatFilter' + _sum: + $ref: '#/components/schemas/NestedFloatFilter' + _min: + $ref: '#/components/schemas/NestedFloatFilter' + _max: + $ref: '#/components/schemas/NestedFloatFilter' + NestedDecimalWithAggregatesFilter: + type: object + properties: + equals: + oneOf: + - type: string + - type: number + in: + type: array + items: + oneOf: + - type: string + - type: number + notIn: + type: array + items: + oneOf: + - type: string + - type: number + lt: + oneOf: + - type: string + - type: number + lte: + oneOf: + - type: string + - type: number + gt: + oneOf: + - type: string + - type: number + gte: + oneOf: + - type: string + - type: number + not: + oneOf: + - oneOf: + - type: string + - type: number + - $ref: '#/components/schemas/NestedDecimalWithAggregatesFilter' + _count: + $ref: '#/components/schemas/NestedIntFilter' + _avg: + $ref: '#/components/schemas/NestedDecimalFilter' + _sum: + $ref: '#/components/schemas/NestedDecimalFilter' + _min: + $ref: '#/components/schemas/NestedDecimalFilter' + _max: + $ref: '#/components/schemas/NestedDecimalFilter' + NestedBoolWithAggregatesFilter: + type: object + properties: + equals: + type: boolean + not: + oneOf: + - type: boolean + - $ref: '#/components/schemas/NestedBoolWithAggregatesFilter' + _count: + $ref: '#/components/schemas/NestedIntFilter' + _min: + $ref: '#/components/schemas/NestedBoolFilter' + _max: + $ref: '#/components/schemas/NestedBoolFilter' + NestedBytesWithAggregatesFilter: + type: object + properties: + equals: + type: string + format: byte + in: + type: array + items: + type: string + format: byte + notIn: + type: array + items: + type: string + format: byte + not: + oneOf: + - type: string + format: byte + - $ref: '#/components/schemas/NestedBytesWithAggregatesFilter' + _count: + $ref: '#/components/schemas/NestedIntFilter' + _min: + $ref: '#/components/schemas/NestedBytesFilter' + _max: + $ref: '#/components/schemas/NestedBytesFilter' + FooSelect: + type: object + properties: + id: + type: boolean + string: + type: boolean + int: + type: boolean + bigInt: + type: boolean + date: + type: boolean + float: + type: boolean + decimal: + type: boolean + boolean: + type: boolean + bytes: + type: boolean + FooCountAggregateInput: + type: object + properties: + id: + type: boolean + string: + type: boolean + int: + type: boolean + bigInt: + type: boolean + date: + type: boolean + float: + type: boolean + decimal: + type: boolean + boolean: + type: boolean + bytes: + type: boolean + _all: + type: boolean + FooAvgAggregateInput: + type: object + properties: + int: + type: boolean + bigInt: + type: boolean + float: + type: boolean + decimal: + type: boolean + FooSumAggregateInput: + type: object + properties: + int: + type: boolean + bigInt: + type: boolean + float: + type: boolean + decimal: + type: boolean + FooMinAggregateInput: + type: object + properties: + id: + type: boolean + string: + type: boolean + int: + type: boolean + bigInt: + type: boolean + date: + type: boolean + float: + type: boolean + decimal: + type: boolean + boolean: + type: boolean + bytes: + type: boolean + FooMaxAggregateInput: + type: object + properties: + id: + type: boolean + string: + type: boolean + int: + type: boolean + bigInt: + type: boolean + date: + type: boolean + float: + type: boolean + decimal: + type: boolean + boolean: + type: boolean + bytes: + type: boolean + AggregateFoo: + type: object + properties: + _count: + $ref: '#/components/schemas/FooCountAggregateOutputType' + _avg: + $ref: '#/components/schemas/FooAvgAggregateOutputType' + _sum: + $ref: '#/components/schemas/FooSumAggregateOutputType' + _min: + $ref: '#/components/schemas/FooMinAggregateOutputType' + _max: + $ref: '#/components/schemas/FooMaxAggregateOutputType' + FooGroupByOutputType: + type: object + properties: + id: + type: string + string: + type: string + int: + type: integer + bigInt: + type: integer + date: + type: string + format: date-time + float: + type: number + decimal: + oneOf: + - type: string + - type: number + boolean: + type: boolean + bytes: + type: string + format: byte + _count: + $ref: '#/components/schemas/FooCountAggregateOutputType' + _avg: + $ref: '#/components/schemas/FooAvgAggregateOutputType' + _sum: + $ref: '#/components/schemas/FooSumAggregateOutputType' + _min: + $ref: '#/components/schemas/FooMinAggregateOutputType' + _max: + $ref: '#/components/schemas/FooMaxAggregateOutputType' + required: + - id + - string + - int + - bigInt + - date + - float + - decimal + - boolean + - bytes + FooCountAggregateOutputType: + type: object + properties: + id: + type: integer + string: + type: integer + int: + type: integer + bigInt: + type: integer + date: + type: integer + float: + type: integer + decimal: + type: integer + boolean: + type: integer + bytes: + type: integer + _all: + type: integer + required: + - id + - string + - int + - bigInt + - date + - float + - decimal + - boolean + - bytes + - _all + FooAvgAggregateOutputType: + type: object + properties: + int: + type: number + bigInt: + type: number + float: + type: number + decimal: + oneOf: + - type: string + - type: number + FooSumAggregateOutputType: + type: object + properties: + int: + type: integer + bigInt: + type: integer + float: + type: number + decimal: + oneOf: + - type: string + - type: number + FooMinAggregateOutputType: + type: object + properties: + id: + type: string + string: + type: string + int: + type: integer + bigInt: + type: integer + date: + type: string + format: date-time + float: + type: number + decimal: + oneOf: + - type: string + - type: number + boolean: + type: boolean + bytes: + type: string + format: byte + FooMaxAggregateOutputType: + type: object + properties: + id: + type: string + string: + type: string + int: + type: integer + bigInt: + type: integer + date: + type: string + format: date-time + float: + type: number + decimal: + oneOf: + - type: string + - type: number + boolean: + type: boolean + bytes: + type: string + format: byte + _Meta: + type: object + properties: + meta: + type: object + description: Meta information about the request or response + properties: + serialization: + description: Serialization metadata + additionalProperties: true + _Error: + type: object + required: + - error + properties: + error: + type: object + required: + - message + properties: + prisma: + type: boolean + description: Indicates if the error occurred during a Prisma call + rejectedByPolicy: + type: boolean + description: Indicates if the error was due to rejection by a policy + code: + type: string + description: Prisma error code. Only available when "prisma" field is true. + message: + type: string + description: Error message + reason: + type: string + description: Detailed error reason + additionalProperties: true + BatchPayload: + type: object + properties: + count: + type: integer + FooCreateArgs: + type: object + required: + - data + properties: + select: + $ref: '#/components/schemas/FooSelect' + data: + $ref: '#/components/schemas/FooCreateInput' + meta: + $ref: '#/components/schemas/_Meta' + FooCreateManyArgs: + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/FooCreateManyInput' + meta: + $ref: '#/components/schemas/_Meta' + FooFindUniqueArgs: + type: object + required: + - where + properties: + select: + $ref: '#/components/schemas/FooSelect' + where: + $ref: '#/components/schemas/FooWhereUniqueInput' + meta: + $ref: '#/components/schemas/_Meta' + FooFindFirstArgs: + type: object + properties: + select: + $ref: '#/components/schemas/FooSelect' + where: + $ref: '#/components/schemas/FooWhereInput' + meta: + $ref: '#/components/schemas/_Meta' + FooFindManyArgs: + type: object + properties: + select: + $ref: '#/components/schemas/FooSelect' + where: + $ref: '#/components/schemas/FooWhereInput' + meta: + $ref: '#/components/schemas/_Meta' + FooUpdateArgs: + type: object + required: + - where + - data + properties: + select: + $ref: '#/components/schemas/FooSelect' + where: + $ref: '#/components/schemas/FooWhereUniqueInput' + data: + $ref: '#/components/schemas/FooUpdateInput' + meta: + $ref: '#/components/schemas/_Meta' + FooUpdateManyArgs: + type: object + required: + - data + properties: + where: + $ref: '#/components/schemas/FooWhereInput' + data: + $ref: '#/components/schemas/FooUpdateManyMutationInput' + meta: + $ref: '#/components/schemas/_Meta' + FooUpsertArgs: + type: object + required: + - create + - update + - where + properties: + select: + $ref: '#/components/schemas/FooSelect' + where: + $ref: '#/components/schemas/FooWhereUniqueInput' + create: + $ref: '#/components/schemas/FooCreateInput' + update: + $ref: '#/components/schemas/FooUpdateInput' + meta: + $ref: '#/components/schemas/_Meta' + FooDeleteUniqueArgs: + type: object + required: + - where + properties: + select: + $ref: '#/components/schemas/FooSelect' + where: + $ref: '#/components/schemas/FooWhereUniqueInput' + meta: + $ref: '#/components/schemas/_Meta' + FooDeleteManyArgs: + type: object + properties: + where: + $ref: '#/components/schemas/FooWhereInput' + meta: + $ref: '#/components/schemas/_Meta' + FooCountArgs: + type: object + properties: + select: + $ref: '#/components/schemas/FooSelect' + where: + $ref: '#/components/schemas/FooWhereInput' + meta: + $ref: '#/components/schemas/_Meta' + FooAggregateArgs: + type: object + properties: + where: + $ref: '#/components/schemas/FooWhereInput' + orderBy: + $ref: '#/components/schemas/FooOrderByWithRelationInput' + cursor: + $ref: '#/components/schemas/FooWhereUniqueInput' + take: + type: integer + skip: + type: integer + _count: + oneOf: + - type: boolean + - $ref: '#/components/schemas/FooCountAggregateInput' + _min: + $ref: '#/components/schemas/FooMinAggregateInput' + _max: + $ref: '#/components/schemas/FooMaxAggregateInput' + _sum: + $ref: '#/components/schemas/FooSumAggregateInput' + _avg: + $ref: '#/components/schemas/FooAvgAggregateInput' + meta: + $ref: '#/components/schemas/_Meta' + FooGroupByArgs: + type: object + properties: + where: + $ref: '#/components/schemas/FooWhereInput' + orderBy: + $ref: '#/components/schemas/FooOrderByWithRelationInput' + by: + $ref: '#/components/schemas/FooScalarFieldEnum' + having: + $ref: '#/components/schemas/FooScalarWhereWithAggregatesInput' + take: + type: integer + skip: + type: integer + _count: + oneOf: + - type: boolean + - $ref: '#/components/schemas/FooCountAggregateInput' + _min: + $ref: '#/components/schemas/FooMinAggregateInput' + _max: + $ref: '#/components/schemas/FooMaxAggregateInput' + _sum: + $ref: '#/components/schemas/FooSumAggregateInput' + _avg: + $ref: '#/components/schemas/FooAvgAggregateInput' + meta: + $ref: '#/components/schemas/_Meta' +paths: + /foo/create: + post: + operationId: createFoo + description: Create a new Foo + tags: + - foo + security: [] + responses: + '201': + description: Successful operation + content: + application/json: + schema: + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/Foo' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' + description: Invalid request + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' + description: Request is forbidden + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/FooCreateArgs' + /foo/createMany: + post: + operationId: createManyFoo + description: Create several Foo + tags: + - foo + security: [] + responses: + '201': + description: Successful operation + content: + application/json: + schema: + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/BatchPayload' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' + description: Invalid request + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' + description: Request is forbidden + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/FooCreateManyArgs' + /foo/findUnique: + get: + operationId: findUniqueFoo + description: Find one unique Foo + tags: + - foo + security: [] + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/Foo' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' + description: Invalid request + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' + description: Request is forbidden + parameters: + - name: q + in: query + required: true + description: Superjson-serialized Prisma query object + content: + application/json: + schema: + $ref: '#/components/schemas/FooFindUniqueArgs' + - name: meta + in: query + description: Superjson serialization metadata for parameter "q" + content: + application/json: + schema: {} + /foo/findFirst: + get: + operationId: findFirstFoo + description: Find the first Foo matching the given condition + tags: + - foo + security: [] + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/Foo' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' + description: Invalid request + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' + description: Request is forbidden + parameters: + - name: q + in: query + required: true + description: Superjson-serialized Prisma query object + content: + application/json: + schema: + $ref: '#/components/schemas/FooFindFirstArgs' + - name: meta + in: query + description: Superjson serialization metadata for parameter "q" + content: + application/json: + schema: {} + /foo/findMany: + get: + operationId: findManyFoo + description: Find a list of Foo + tags: + - foo + security: [] + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: object + required: + - data + properties: + data: + type: array + items: + $ref: '#/components/schemas/Foo' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' + description: Invalid request + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' + description: Request is forbidden + parameters: + - name: q + in: query + required: true + description: Superjson-serialized Prisma query object + content: + application/json: + schema: + $ref: '#/components/schemas/FooFindManyArgs' + - name: meta + in: query + description: Superjson serialization metadata for parameter "q" + content: + application/json: + schema: {} + /foo/update: + patch: + operationId: updateFoo + description: Update a Foo + tags: + - foo + security: [] + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/Foo' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' + description: Invalid request + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' + description: Request is forbidden + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/FooUpdateArgs' + /foo/updateMany: + patch: + operationId: updateManyFoo + description: Update Foos matching the given condition + tags: + - foo + security: [] + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/BatchPayload' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' + description: Invalid request + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' + description: Request is forbidden + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/FooUpdateManyArgs' + /foo/upsert: + post: + operationId: upsertFoo + description: Upsert a Foo + tags: + - foo + security: [] + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/Foo' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' + description: Invalid request + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' + description: Request is forbidden + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/FooUpsertArgs' + /foo/delete: + delete: + operationId: deleteFoo + description: Delete one unique Foo + tags: + - foo + security: [] + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/Foo' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' + description: Invalid request + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' + description: Request is forbidden + parameters: + - name: q + in: query + required: true + description: Superjson-serialized Prisma query object + content: + application/json: + schema: + $ref: '#/components/schemas/FooDeleteUniqueArgs' + - name: meta + in: query + description: Superjson serialization metadata for parameter "q" + content: + application/json: + schema: {} + /foo/deleteMany: + delete: + operationId: deleteManyFoo + description: Delete Foos matching the given condition + tags: + - foo + security: [] + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/BatchPayload' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' + description: Invalid request + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' + description: Request is forbidden + parameters: + - name: q + in: query + required: true + description: Superjson-serialized Prisma query object + content: + application/json: + schema: + $ref: '#/components/schemas/FooDeleteManyArgs' + - name: meta + in: query + description: Superjson serialization metadata for parameter "q" + content: + application/json: + schema: {} + /foo/count: + get: + operationId: countFoo + description: Find a list of Foo + tags: + - foo + security: [] + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: object + required: + - data + properties: + data: + oneOf: + - type: integer + - $ref: '#/components/schemas/FooCountAggregateOutputType' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' + description: Invalid request + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' + description: Request is forbidden + parameters: + - name: q + in: query + required: true + description: Superjson-serialized Prisma query object + content: + application/json: + schema: + $ref: '#/components/schemas/FooCountArgs' + - name: meta + in: query + description: Superjson serialization metadata for parameter "q" + content: + application/json: + schema: {} + /foo/aggregate: + get: + operationId: aggregateFoo + description: Aggregate Foos + tags: + - foo + security: [] + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/AggregateFoo' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' + description: Invalid request + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' + description: Request is forbidden + parameters: + - name: q + in: query + required: true + description: Superjson-serialized Prisma query object + content: + application/json: + schema: + $ref: '#/components/schemas/FooAggregateArgs' + - name: meta + in: query + description: Superjson serialization metadata for parameter "q" + content: + application/json: + schema: {} + /foo/groupBy: + get: + operationId: groupByFoo + description: Group Foos by fields + tags: + - foo + security: [] + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: object + required: + - data + properties: + data: + type: array + items: + $ref: '#/components/schemas/FooGroupByOutputType' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' + description: Invalid request + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' + description: Request is forbidden + parameters: + - name: q + in: query + required: true + description: Superjson-serialized Prisma query object + content: + application/json: + schema: + $ref: '#/components/schemas/FooGroupByArgs' + - name: meta + in: query + description: Superjson serialization metadata for parameter "q" + content: + application/json: + schema: {} diff --git a/packages/plugins/openapi/tests/baseline/rpc.baseline.yaml b/packages/plugins/openapi/tests/baseline/rpc.baseline.yaml index 17f8fa8d4..bc013f02b 100644 --- a/packages/plugins/openapi/tests/baseline/rpc.baseline.yaml +++ b/packages/plugins/openapi/tests/baseline/rpc.baseline.yaml @@ -613,15 +613,6 @@ components: $ref: '#/components/schemas/PostWhereInput' none: $ref: '#/components/schemas/PostWhereInput' - BoolFilter: - type: object - properties: - equals: - type: boolean - not: - oneOf: - - type: boolean - - $ref: '#/components/schemas/NestedBoolFilter' PostOrderByRelationAggregateInput: type: object properties: @@ -728,21 +719,6 @@ components: $ref: '#/components/schemas/NestedEnumRoleFilter' _max: $ref: '#/components/schemas/NestedEnumRoleFilter' - BoolWithAggregatesFilter: - type: object - properties: - equals: - type: boolean - not: - oneOf: - - type: boolean - - $ref: '#/components/schemas/NestedBoolWithAggregatesFilter' - _count: - $ref: '#/components/schemas/NestedIntFilter' - _min: - $ref: '#/components/schemas/NestedBoolFilter' - _max: - $ref: '#/components/schemas/NestedBoolFilter' UserRelationFilter: type: object properties: @@ -783,6 +759,15 @@ components: oneOf: - type: string - $ref: '#/components/schemas/NestedStringNullableFilter' + BoolFilter: + type: object + properties: + equals: + type: boolean + not: + oneOf: + - type: boolean + - $ref: '#/components/schemas/NestedBoolFilter' IntFilter: type: object properties: @@ -847,6 +832,21 @@ components: $ref: '#/components/schemas/NestedStringNullableFilter' _max: $ref: '#/components/schemas/NestedStringNullableFilter' + BoolWithAggregatesFilter: + type: object + properties: + equals: + type: boolean + not: + oneOf: + - type: boolean + - $ref: '#/components/schemas/NestedBoolWithAggregatesFilter' + _count: + $ref: '#/components/schemas/NestedIntFilter' + _min: + $ref: '#/components/schemas/NestedBoolFilter' + _max: + $ref: '#/components/schemas/NestedBoolFilter' IntWithAggregatesFilter: type: object properties: @@ -994,11 +994,6 @@ components: - type: array items: $ref: '#/components/schemas/PostScalarWhereInput' - BoolFieldUpdateOperationsInput: - type: object - properties: - set: - type: boolean UserCreateNestedOneWithoutPostsInput: type: object properties: @@ -1031,6 +1026,11 @@ components: oneOf: - $ref: '#/components/schemas/UserUpdateWithoutPostsInput' - $ref: '#/components/schemas/UserUncheckedUpdateWithoutPostsInput' + BoolFieldUpdateOperationsInput: + type: object + properties: + set: + type: boolean IntFieldUpdateOperationsInput: type: object properties: @@ -1125,15 +1125,6 @@ components: oneOf: - $ref: '#/components/schemas/Role' - $ref: '#/components/schemas/NestedEnumRoleFilter' - NestedBoolFilter: - type: object - properties: - equals: - type: boolean - not: - oneOf: - - type: boolean - - $ref: '#/components/schemas/NestedBoolFilter' NestedStringWithAggregatesFilter: type: object properties: @@ -1258,21 +1249,6 @@ components: $ref: '#/components/schemas/NestedEnumRoleFilter' _max: $ref: '#/components/schemas/NestedEnumRoleFilter' - NestedBoolWithAggregatesFilter: - type: object - properties: - equals: - type: boolean - not: - oneOf: - - type: boolean - - $ref: '#/components/schemas/NestedBoolWithAggregatesFilter' - _count: - $ref: '#/components/schemas/NestedIntFilter' - _min: - $ref: '#/components/schemas/NestedBoolFilter' - _max: - $ref: '#/components/schemas/NestedBoolFilter' NestedStringNullableFilter: type: object properties: @@ -1304,6 +1280,15 @@ components: oneOf: - type: string - $ref: '#/components/schemas/NestedStringNullableFilter' + NestedBoolFilter: + type: object + properties: + equals: + type: boolean + not: + oneOf: + - type: boolean + - $ref: '#/components/schemas/NestedBoolFilter' NestedStringNullableWithAggregatesFilter: type: object properties: @@ -1366,6 +1351,21 @@ components: oneOf: - type: integer - $ref: '#/components/schemas/NestedIntNullableFilter' + NestedBoolWithAggregatesFilter: + type: object + properties: + equals: + type: boolean + not: + oneOf: + - type: boolean + - $ref: '#/components/schemas/NestedBoolWithAggregatesFilter' + _count: + $ref: '#/components/schemas/NestedIntFilter' + _min: + $ref: '#/components/schemas/NestedBoolFilter' + _max: + $ref: '#/components/schemas/NestedBoolFilter' NestedIntWithAggregatesFilter: type: object properties: @@ -2192,6 +2192,42 @@ components: type: boolean viewCount: type: integer + _Meta: + type: object + properties: + meta: + type: object + description: Meta information about the request or response + properties: + serialization: + description: Serialization metadata + additionalProperties: true + _Error: + type: object + required: + - error + properties: + error: + type: object + required: + - message + properties: + prisma: + type: boolean + description: Indicates if the error occurred during a Prisma call + rejectedByPolicy: + type: boolean + description: Indicates if the error was due to rejection by a policy + code: + type: string + description: Prisma error code. Only available when "prisma" field is true. + message: + type: string + description: Error message + reason: + type: string + description: Detailed error reason + additionalProperties: true BatchPayload: type: object properties: @@ -2199,6 +2235,8 @@ components: type: integer UserCreateArgs: type: object + required: + - data properties: select: $ref: '#/components/schemas/UserSelect' @@ -2206,13 +2244,21 @@ components: $ref: '#/components/schemas/UserInclude' data: $ref: '#/components/schemas/UserCreateInput' + meta: + $ref: '#/components/schemas/_Meta' UserCreateManyArgs: type: object + required: + - data properties: data: $ref: '#/components/schemas/UserCreateManyInput' + meta: + $ref: '#/components/schemas/_Meta' UserFindUniqueArgs: type: object + required: + - where properties: select: $ref: '#/components/schemas/UserSelect' @@ -2220,6 +2266,8 @@ components: $ref: '#/components/schemas/UserInclude' where: $ref: '#/components/schemas/UserWhereUniqueInput' + meta: + $ref: '#/components/schemas/_Meta' UserFindFirstArgs: type: object properties: @@ -2229,6 +2277,8 @@ components: $ref: '#/components/schemas/UserInclude' where: $ref: '#/components/schemas/UserWhereInput' + meta: + $ref: '#/components/schemas/_Meta' UserFindManyArgs: type: object properties: @@ -2238,8 +2288,13 @@ components: $ref: '#/components/schemas/UserInclude' where: $ref: '#/components/schemas/UserWhereInput' + meta: + $ref: '#/components/schemas/_Meta' UserUpdateArgs: type: object + required: + - where + - data properties: select: $ref: '#/components/schemas/UserSelect' @@ -2249,15 +2304,25 @@ components: $ref: '#/components/schemas/UserWhereUniqueInput' data: $ref: '#/components/schemas/UserUpdateInput' + meta: + $ref: '#/components/schemas/_Meta' UserUpdateManyArgs: type: object + required: + - data properties: where: $ref: '#/components/schemas/UserWhereInput' data: $ref: '#/components/schemas/UserUpdateManyMutationInput' + meta: + $ref: '#/components/schemas/_Meta' UserUpsertArgs: type: object + required: + - create + - update + - where properties: select: $ref: '#/components/schemas/UserSelect' @@ -2269,8 +2334,12 @@ components: $ref: '#/components/schemas/UserCreateInput' update: $ref: '#/components/schemas/UserUpdateInput' + meta: + $ref: '#/components/schemas/_Meta' UserDeleteUniqueArgs: type: object + required: + - where properties: select: $ref: '#/components/schemas/UserSelect' @@ -2278,11 +2347,15 @@ components: $ref: '#/components/schemas/UserInclude' where: $ref: '#/components/schemas/UserWhereUniqueInput' + meta: + $ref: '#/components/schemas/_Meta' UserDeleteManyArgs: type: object properties: where: $ref: '#/components/schemas/UserWhereInput' + meta: + $ref: '#/components/schemas/_Meta' UserCountArgs: type: object properties: @@ -2290,6 +2363,8 @@ components: $ref: '#/components/schemas/UserSelect' where: $ref: '#/components/schemas/UserWhereInput' + meta: + $ref: '#/components/schemas/_Meta' UserAggregateArgs: type: object properties: @@ -2311,6 +2386,8 @@ components: $ref: '#/components/schemas/UserMinAggregateInput' _max: $ref: '#/components/schemas/UserMaxAggregateInput' + meta: + $ref: '#/components/schemas/_Meta' UserGroupByArgs: type: object properties: @@ -2334,8 +2411,12 @@ components: $ref: '#/components/schemas/UserMinAggregateInput' _max: $ref: '#/components/schemas/UserMaxAggregateInput' + meta: + $ref: '#/components/schemas/_Meta' PostCreateArgs: type: object + required: + - data properties: select: $ref: '#/components/schemas/PostSelect' @@ -2343,13 +2424,21 @@ components: $ref: '#/components/schemas/PostInclude' data: $ref: '#/components/schemas/PostCreateInput' + meta: + $ref: '#/components/schemas/_Meta' PostCreateManyArgs: type: object + required: + - data properties: data: $ref: '#/components/schemas/PostCreateManyInput' + meta: + $ref: '#/components/schemas/_Meta' PostFindUniqueArgs: type: object + required: + - where properties: select: $ref: '#/components/schemas/PostSelect' @@ -2357,6 +2446,8 @@ components: $ref: '#/components/schemas/PostInclude' where: $ref: '#/components/schemas/PostWhereUniqueInput' + meta: + $ref: '#/components/schemas/_Meta' PostFindFirstArgs: type: object properties: @@ -2366,6 +2457,8 @@ components: $ref: '#/components/schemas/PostInclude' where: $ref: '#/components/schemas/PostWhereInput' + meta: + $ref: '#/components/schemas/_Meta' PostFindManyArgs: type: object properties: @@ -2375,8 +2468,13 @@ components: $ref: '#/components/schemas/PostInclude' where: $ref: '#/components/schemas/PostWhereInput' + meta: + $ref: '#/components/schemas/_Meta' PostUpdateArgs: type: object + required: + - where + - data properties: select: $ref: '#/components/schemas/PostSelect' @@ -2386,15 +2484,25 @@ components: $ref: '#/components/schemas/PostWhereUniqueInput' data: $ref: '#/components/schemas/PostUpdateInput' + meta: + $ref: '#/components/schemas/_Meta' PostUpdateManyArgs: type: object + required: + - data properties: where: $ref: '#/components/schemas/PostWhereInput' data: $ref: '#/components/schemas/PostUpdateManyMutationInput' + meta: + $ref: '#/components/schemas/_Meta' PostUpsertArgs: type: object + required: + - create + - update + - where properties: select: $ref: '#/components/schemas/PostSelect' @@ -2406,8 +2514,12 @@ components: $ref: '#/components/schemas/PostCreateInput' update: $ref: '#/components/schemas/PostUpdateInput' + meta: + $ref: '#/components/schemas/_Meta' PostDeleteUniqueArgs: type: object + required: + - where properties: select: $ref: '#/components/schemas/PostSelect' @@ -2415,11 +2527,15 @@ components: $ref: '#/components/schemas/PostInclude' where: $ref: '#/components/schemas/PostWhereUniqueInput' + meta: + $ref: '#/components/schemas/_Meta' PostDeleteManyArgs: type: object properties: where: $ref: '#/components/schemas/PostWhereInput' + meta: + $ref: '#/components/schemas/_Meta' PostCountArgs: type: object properties: @@ -2427,6 +2543,8 @@ components: $ref: '#/components/schemas/PostSelect' where: $ref: '#/components/schemas/PostWhereInput' + meta: + $ref: '#/components/schemas/_Meta' PostAggregateArgs: type: object properties: @@ -2452,6 +2570,8 @@ components: $ref: '#/components/schemas/PostSumAggregateInput' _avg: $ref: '#/components/schemas/PostAvgAggregateInput' + meta: + $ref: '#/components/schemas/_Meta' PostGroupByArgs: type: object properties: @@ -2479,6 +2599,8 @@ components: $ref: '#/components/schemas/PostSumAggregateInput' _avg: $ref: '#/components/schemas/PostAvgAggregateInput' + meta: + $ref: '#/components/schemas/_Meta' paths: /user/create: post: @@ -2492,10 +2614,27 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/User' + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/User' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Invalid request '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Request is forbidden requestBody: content: @@ -2514,10 +2653,27 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/BatchPayload' + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/BatchPayload' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Invalid request '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Request is forbidden requestBody: content: @@ -2536,19 +2692,43 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/User' + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/User' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Invalid request '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Request is forbidden parameters: - name: q in: query required: true + description: Superjson-serialized Prisma query object content: application/json: schema: $ref: '#/components/schemas/UserFindUniqueArgs' + - name: meta + in: query + description: Superjson serialization metadata for parameter "q" + content: + application/json: + schema: {} /user/findFirst: get: operationId: findFirstUser @@ -2561,19 +2741,43 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/User' + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/User' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Invalid request '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Request is forbidden parameters: - name: q in: query required: true + description: Superjson-serialized Prisma query object content: application/json: schema: $ref: '#/components/schemas/UserFindFirstArgs' + - name: meta + in: query + description: Superjson serialization metadata for parameter "q" + content: + application/json: + schema: {} /user/findMany: get: operationId: findManyUser @@ -2586,21 +2790,45 @@ paths: content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/User' + type: object + required: + - data + properties: + data: + type: array + items: + $ref: '#/components/schemas/User' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Invalid request '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Request is forbidden parameters: - name: q in: query required: true + description: Superjson-serialized Prisma query object content: application/json: schema: $ref: '#/components/schemas/UserFindManyArgs' + - name: meta + in: query + description: Superjson serialization metadata for parameter "q" + content: + application/json: + schema: {} /user/update: patch: operationId: updateUser @@ -2613,10 +2841,27 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/User' + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/User' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Invalid request '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Request is forbidden requestBody: content: @@ -2635,10 +2880,27 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/BatchPayload' + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/BatchPayload' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Invalid request '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Request is forbidden requestBody: content: @@ -2657,10 +2919,27 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/User' + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/User' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Invalid request '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Request is forbidden requestBody: content: @@ -2682,10 +2961,27 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/User' + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/User' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Invalid request '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Request is forbidden requestBody: content: @@ -2704,19 +3000,43 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/BatchPayload' + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/BatchPayload' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Invalid request '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Request is forbidden parameters: - name: q in: query required: true + description: Superjson-serialized Prisma query object content: application/json: schema: $ref: '#/components/schemas/UserDeleteManyArgs' + - name: meta + in: query + description: Superjson serialization metadata for parameter "q" + content: + application/json: + schema: {} /user/count: get: operationId: countUser @@ -2729,21 +3049,45 @@ paths: content: application/json: schema: - oneOf: - - type: integer - - $ref: '#/components/schemas/UserCountAggregateOutputType' + type: object + required: + - data + properties: + data: + oneOf: + - type: integer + - $ref: '#/components/schemas/UserCountAggregateOutputType' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Invalid request '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Request is forbidden parameters: - name: q in: query required: true + description: Superjson-serialized Prisma query object content: application/json: schema: $ref: '#/components/schemas/UserCountArgs' + - name: meta + in: query + description: Superjson serialization metadata for parameter "q" + content: + application/json: + schema: {} /user/aggregate: get: operationId: aggregateUser @@ -2756,19 +3100,43 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/AggregateUser' + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/AggregateUser' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Invalid request '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Request is forbidden parameters: - name: q in: query required: true + description: Superjson-serialized Prisma query object content: application/json: schema: $ref: '#/components/schemas/UserAggregateArgs' + - name: meta + in: query + description: Superjson serialization metadata for parameter "q" + content: + application/json: + schema: {} /user/groupBy: get: operationId: groupByUser @@ -2781,21 +3149,45 @@ paths: content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/UserGroupByOutputType' + type: object + required: + - data + properties: + data: + type: array + items: + $ref: '#/components/schemas/UserGroupByOutputType' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Invalid request '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Request is forbidden parameters: - name: q in: query required: true + description: Superjson-serialized Prisma query object content: application/json: schema: $ref: '#/components/schemas/UserGroupByArgs' + - name: meta + in: query + description: Superjson serialization metadata for parameter "q" + content: + application/json: + schema: {} /post/create: post: operationId: createPost @@ -2808,10 +3200,27 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Post' + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/Post' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Invalid request '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Request is forbidden requestBody: content: @@ -2830,10 +3239,27 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/BatchPayload' + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/BatchPayload' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Invalid request '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Request is forbidden requestBody: content: @@ -2852,19 +3278,43 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Post' + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/Post' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Invalid request '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Request is forbidden parameters: - name: q in: query required: true + description: Superjson-serialized Prisma query object content: application/json: schema: $ref: '#/components/schemas/PostFindUniqueArgs' + - name: meta + in: query + description: Superjson serialization metadata for parameter "q" + content: + application/json: + schema: {} /post/findFirst: get: operationId: findFirstPost @@ -2877,19 +3327,43 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Post' + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/Post' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Invalid request '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Request is forbidden parameters: - name: q in: query required: true + description: Superjson-serialized Prisma query object content: application/json: schema: $ref: '#/components/schemas/PostFindFirstArgs' + - name: meta + in: query + description: Superjson serialization metadata for parameter "q" + content: + application/json: + schema: {} /post/update: patch: operationId: updatePost @@ -2902,10 +3376,27 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Post' + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/Post' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Invalid request '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Request is forbidden requestBody: content: @@ -2924,10 +3415,27 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/BatchPayload' + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/BatchPayload' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Invalid request '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Request is forbidden requestBody: content: @@ -2946,10 +3454,27 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Post' + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/Post' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Invalid request '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Request is forbidden requestBody: content: @@ -2968,19 +3493,43 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Post' + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/Post' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Invalid request '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Request is forbidden parameters: - name: q in: query required: true + description: Superjson-serialized Prisma query object content: application/json: schema: $ref: '#/components/schemas/PostDeleteUniqueArgs' + - name: meta + in: query + description: Superjson serialization metadata for parameter "q" + content: + application/json: + schema: {} /post/deleteMany: delete: operationId: deleteManyPost @@ -2993,19 +3542,43 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/BatchPayload' + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/BatchPayload' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Invalid request '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Request is forbidden parameters: - name: q in: query required: true + description: Superjson-serialized Prisma query object content: application/json: schema: $ref: '#/components/schemas/PostDeleteManyArgs' + - name: meta + in: query + description: Superjson serialization metadata for parameter "q" + content: + application/json: + schema: {} /post/count: get: operationId: countPost @@ -3018,21 +3591,45 @@ paths: content: application/json: schema: - oneOf: - - type: integer - - $ref: '#/components/schemas/PostCountAggregateOutputType' + type: object + required: + - data + properties: + data: + oneOf: + - type: integer + - $ref: '#/components/schemas/PostCountAggregateOutputType' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Invalid request '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Request is forbidden parameters: - name: q in: query required: true + description: Superjson-serialized Prisma query object content: application/json: schema: $ref: '#/components/schemas/PostCountArgs' + - name: meta + in: query + description: Superjson serialization metadata for parameter "q" + content: + application/json: + schema: {} /post/aggregate: get: operationId: aggregatePost @@ -3045,19 +3642,43 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/AggregatePost' + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/AggregatePost' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Invalid request '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Request is forbidden parameters: - name: q in: query required: true + description: Superjson-serialized Prisma query object content: application/json: schema: $ref: '#/components/schemas/PostAggregateArgs' + - name: meta + in: query + description: Superjson serialization metadata for parameter "q" + content: + application/json: + schema: {} /post/groupBy: get: operationId: groupByPost @@ -3070,18 +3691,42 @@ paths: content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/PostGroupByOutputType' + type: object + required: + - data + properties: + data: + type: array + items: + $ref: '#/components/schemas/PostGroupByOutputType' + description: The Prisma response data serialized with superjson + meta: + $ref: '#/components/schemas/_Meta' + description: The superjson serialization metadata for the "data" field '400': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Invalid request '403': + content: + application/json: + schema: + $ref: '#/components/schemas/_Error' description: Request is forbidden parameters: - name: q in: query required: true + description: Superjson-serialized Prisma query object content: application/json: schema: $ref: '#/components/schemas/PostGroupByArgs' + - name: meta + in: query + description: Superjson serialization metadata for parameter "q" + content: + application/json: + schema: {} diff --git a/packages/plugins/openapi/tests/openapi-restful.test.ts b/packages/plugins/openapi/tests/openapi-restful.test.ts index 50b736bf9..6dc0649d0 100644 --- a/packages/plugins/openapi/tests/openapi-restful.test.ts +++ b/packages/plugins/openapi/tests/openapi-restful.test.ts @@ -263,6 +263,43 @@ model Post { await OpenAPIParser.validate(output); }); + + it('field type coverage', async () => { + const { model, dmmf, modelFile } = await loadZModelAndDmmf(` +plugin openapi { + provider = '${process.cwd()}/dist' +} + +model Foo { + id String @id @default(cuid()) + + string String + int Int + bigInt BigInt + date DateTime + float Float + decimal Decimal + boolean Boolean + bytes Bytes + + @@allow('all', true) +} + `); + + const { name: output } = tmp.fileSync({ postfix: '.yaml' }); + + const options = buildOptions(model, modelFile, output, '3.1.0'); + await generate(model, options, dmmf); + + console.log('OpenAPI specification generated:', output); + + await OpenAPIParser.validate(output); + + const parsed = YAML.parse(fs.readFileSync(output, 'utf-8')); + expect(parsed.openapi).toBe('3.1.0'); + const baseline = YAML.parse(fs.readFileSync(`${__dirname}/baseline/rest-type-coverage.baseline.yaml`, 'utf-8')); + expect(parsed).toMatchObject(baseline); + }); }); function buildOptions(model: Model, modelFile: string, output: string, specVersion = '3.0.0') { diff --git a/packages/plugins/openapi/tests/openapi-rpc.test.ts b/packages/plugins/openapi/tests/openapi-rpc.test.ts index feac55778..8af6bc086 100644 --- a/packages/plugins/openapi/tests/openapi-rpc.test.ts +++ b/packages/plugins/openapi/tests/openapi-rpc.test.ts @@ -339,6 +339,43 @@ model Post { console.log('OpenAPI specification generated:', output); await OpenAPIParser.validate(output); }); + + it('field type coverage', async () => { + const { model, dmmf, modelFile } = await loadZModelAndDmmf(` +plugin openapi { + provider = '${process.cwd()}/dist' +} + +model Foo { + id String @id @default(cuid()) + + string String + int Int + bigInt BigInt + date DateTime + float Float + decimal Decimal + boolean Boolean + bytes Bytes + + @@allow('all', true) +} + `); + + const { name: output } = tmp.fileSync({ postfix: '.yaml' }); + + const options = buildOptions(model, modelFile, output); + await generate(model, options, dmmf); + + console.log('OpenAPI specification generated:', output); + + await OpenAPIParser.validate(output); + + const parsed = YAML.parse(fs.readFileSync(output, 'utf-8')); + expect(parsed.openapi).toBe('3.1.0'); + const baseline = YAML.parse(fs.readFileSync(`${__dirname}/baseline/rpc-type-coverage.baseline.yaml`, 'utf-8')); + expect(parsed).toMatchObject(baseline); + }); }); function buildOptions(model: Model, modelFile: string, output: string) { diff --git a/packages/plugins/prisma-types.ts b/packages/plugins/prisma-types.ts new file mode 100644 index 000000000..49c38667c --- /dev/null +++ b/packages/plugins/prisma-types.ts @@ -0,0 +1,12 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/// Types copied over from Prisma's generated code to avoid being broken due to Prisma upgrades + +export type Enumerable = T | Array; + +type _TupleToUnion = T extends (infer E)[] ? E : never; + +export type TupleToUnion = _TupleToUnion; + +export type MaybeTupleToUnion = T extends any[] ? TupleToUnion : T; + +export type PickEnumerable | keyof T> = Pick>; diff --git a/packages/plugins/swr/package.json b/packages/plugins/swr/package.json index 711ecb694..9a82acc77 100644 --- a/packages/plugins/swr/package.json +++ b/packages/plugins/swr/package.json @@ -1,7 +1,7 @@ { "name": "@zenstackhq/swr", "displayName": "ZenStack plugin for generating SWR hooks", - "version": "1.0.0-beta.8", + "version": "1.0.0-beta.9", "description": "ZenStack plugin for generating SWR hooks", "main": "index.js", "repository": { @@ -10,10 +10,10 @@ }, "scripts": { "clean": "rimraf dist", - "build": "pnpm lint && pnpm clean && tsc && copyfiles ./package.json ./README.md ./LICENSE 'res/**/*' dist && pnpm pack dist --pack-destination '../../../../.build'", + "build": "pnpm lint && pnpm clean && tsc && copyfiles ./package.json ./README.md ./LICENSE dist && pnpm pack dist --pack-destination '../../../../.build'", "watch": "tsc --watch", "lint": "eslint src --ext ts", - "test": "jest", + "test": "ZENSTACK_TEST=1 jest", "prepublishOnly": "pnpm build", "publish-dev": "pnpm publish --tag dev" }, @@ -25,27 +25,25 @@ "author": "ZenStack Team", "license": "MIT", "dependencies": { - "@prisma/generator-helper": "4.10.0", + "@prisma/generator-helper": "^5.0.0", + "@zenstackhq/runtime": "workspace:*", "@zenstackhq/sdk": "workspace:*", "change-case": "^4.1.2", "decimal.js": "^10.4.2", "lower-case-first": "^2.0.2", - "superjson": "^1.11.0", "ts-morph": "^16.0.0", "upper-case-first": "^2.0.2" }, "devDependencies": { "@tanstack/react-query": "^4.28.0", "@types/jest": "^29.5.0", - "@types/lower-case-first": "^1.0.1", - "@types/react": "^18.0.26", + "@types/node": "^18.0.0", + "@types/react": "18.2.0", "@types/tmp": "^0.2.3", - "@types/upper-case-first": "^1.1.2", "@zenstackhq/testtools": "workspace:*", "copyfiles": "^2.4.1", "jest": "^29.5.0", - "react": "^17.0.2 || ^18", - "react-dom": "^17.0.2 || ^18", + "react": "18.2.0", "rimraf": "^3.0.2", "swr": "^2.0.3", "ts-jest": "^29.0.5", diff --git a/packages/plugins/swr/res/marshal-json.ts b/packages/plugins/swr/res/marshal-json.ts deleted file mode 100644 index 1f00abc79..000000000 --- a/packages/plugins/swr/res/marshal-json.ts +++ /dev/null @@ -1,12 +0,0 @@ -function marshal(value: unknown) { - return JSON.stringify(value); -} - -function unmarshal(value: string) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return JSON.parse(value) as any; -} - -function makeUrl(url: string, args: unknown) { - return args ? url + `?q=${encodeURIComponent(JSON.stringify(args))}` : url; -} diff --git a/packages/plugins/swr/res/marshal-superjson.ts b/packages/plugins/swr/res/marshal-superjson.ts deleted file mode 100644 index 559b11b4e..000000000 --- a/packages/plugins/swr/res/marshal-superjson.ts +++ /dev/null @@ -1,20 +0,0 @@ -import superjson from 'superjson'; - -function marshal(value: unknown) { - return superjson.stringify(value); -} - -function unmarshal(value: string) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const j = JSON.parse(value) as any; - if (j?.json) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return superjson.parse(value); - } else { - return j; - } -} - -function makeUrl(url: string, args: unknown) { - return args ? url + `?q=${encodeURIComponent(superjson.stringify(args))}` : url; -} diff --git a/packages/plugins/swr/src/generator.ts b/packages/plugins/swr/src/generator.ts index f9b9f1da2..e363c188d 100644 --- a/packages/plugins/swr/src/generator.ts +++ b/packages/plugins/swr/src/generator.ts @@ -1,6 +1,5 @@ -import { DMMF } from '@prisma/generator-helper'; +import type { DMMF } from '@prisma/generator-helper'; import { - CrudFailureReason, PluginOptions, createProject, getDataModels, @@ -11,7 +10,6 @@ import { } from '@zenstackhq/sdk'; import { DataModel, Model } from '@zenstackhq/sdk/ast'; import { paramCase } from 'change-case'; -import fs from 'fs'; import { lowerCaseFirst } from 'lower-case-first'; import path from 'path'; import { FunctionDeclaration, Project, SourceFile } from 'ts-morph'; @@ -23,10 +21,16 @@ export async function generate(model: Model, options: PluginOptions, dmmf: DMMF. const project = createProject(); const warnings: string[] = []; + + if (options.useSuperJson !== undefined) { + warnings.push( + 'The option "useSuperJson" is deprecated. The generated hooks always use superjson for serialization.' + ); + } + const models = getDataModels(model); generateIndex(project, outDir, models); - generateHelper(project, outDir, options.useSuperJson === true); models.forEach((dataModel) => { const mapping = dmmf.mappings.modelOperations.find((op) => op.model === dataModel.name); @@ -41,19 +45,6 @@ export async function generate(model: Model, options: PluginOptions, dmmf: DMMF. return warnings; } -function wrapReadbackErrorCheck(code: string) { - return `try { - ${code} - } catch (err: any) { - if (err.info?.prisma && err.info?.code === 'P2004' && err.info?.reason === '${CrudFailureReason.RESULT_NOT_READABLE}') { - // unable to readback data - return undefined; - } else { - throw err; - } - }`; -} - function generateModelHooks(project: Project, outDir: string, model: DataModel, mapping: DMMF.ModelMapping) { const fileName = paramCase(model.name); const sf = project.createSourceFile(path.join(outDir, `${fileName}.ts`), undefined, { overwrite: true }); @@ -68,8 +59,8 @@ function generateModelHooks(project: Project, outDir: string, model: DataModel, }); sf.addStatements([ `import { useContext } from 'react';`, - `import { RequestHandlerContext, type RequestOptions } from './_helper';`, - `import * as request from './_helper';`, + `import { RequestHandlerContext, type RequestOptions, type PickEnumerable } from '@zenstackhq/swr/runtime';`, + `import * as request from '@zenstackhq/swr/runtime';`, ]); const prefixesToMutate = ['find', 'aggregate', 'count', 'groupBy']; @@ -92,7 +83,9 @@ function generateModelHooks(project: Project, outDir: string, model: DataModel, const argsType = `Prisma.${model.name}CreateArgs`; const inputType = `Prisma.SelectSubset`; const returnType = `Prisma.CheckSelect>`; - mutationFuncs.push(generateMutation(useMutation, model, 'post', 'create', argsType, inputType, returnType)); + mutationFuncs.push( + generateMutation(useMutation, model, 'post', 'create', argsType, inputType, returnType, true) + ); } // createMany @@ -100,7 +93,9 @@ function generateModelHooks(project: Project, outDir: string, model: DataModel, const argsType = `Prisma.${model.name}CreateManyArgs`; const inputType = `Prisma.SelectSubset`; const returnType = `Prisma.BatchPayload`; - mutationFuncs.push(generateMutation(useMutation, model, 'post', 'createMany', argsType, inputType, returnType)); + mutationFuncs.push( + generateMutation(useMutation, model, 'post', 'createMany', argsType, inputType, returnType, false) + ); } // findMany @@ -134,7 +129,9 @@ function generateModelHooks(project: Project, outDir: string, model: DataModel, const argsType = `Prisma.${model.name}UpdateArgs`; const inputType = `Prisma.SelectSubset`; const returnType = `Prisma.${model.name}GetPayload`; - mutationFuncs.push(generateMutation(useMutation, model, 'put', 'update', argsType, inputType, returnType)); + mutationFuncs.push( + generateMutation(useMutation, model, 'put', 'update', argsType, inputType, returnType, true) + ); } // updateMany @@ -142,7 +139,9 @@ function generateModelHooks(project: Project, outDir: string, model: DataModel, const argsType = `Prisma.${model.name}UpdateManyArgs`; const inputType = `Prisma.SelectSubset`; const returnType = `Prisma.BatchPayload`; - mutationFuncs.push(generateMutation(useMutation, model, 'put', 'updateMany', argsType, inputType, returnType)); + mutationFuncs.push( + generateMutation(useMutation, model, 'put', 'updateMany', argsType, inputType, returnType, false) + ); } // upsert @@ -152,7 +151,9 @@ function generateModelHooks(project: Project, outDir: string, model: DataModel, const argsType = `Prisma.${model.name}UpsertArgs`; const inputType = `Prisma.SelectSubset`; const returnType = `Prisma.${model.name}GetPayload`; - mutationFuncs.push(generateMutation(useMutation, model, 'post', 'upsert', argsType, inputType, returnType)); + mutationFuncs.push( + generateMutation(useMutation, model, 'post', 'upsert', argsType, inputType, returnType, true) + ); } // del @@ -162,7 +163,9 @@ function generateModelHooks(project: Project, outDir: string, model: DataModel, const argsType = `Prisma.${model.name}DeleteArgs`; const inputType = `Prisma.SelectSubset`; const returnType = `Prisma.${model.name}GetPayload`; - mutationFuncs.push(generateMutation(useMutation, model, 'delete', 'delete', argsType, inputType, returnType)); + mutationFuncs.push( + generateMutation(useMutation, model, 'delete', 'delete', argsType, inputType, returnType, true) + ); } // deleteMany @@ -171,7 +174,7 @@ function generateModelHooks(project: Project, outDir: string, model: DataModel, const inputType = `Prisma.SelectSubset`; const returnType = `Prisma.BatchPayload`; mutationFuncs.push( - generateMutation(useMutation, model, 'delete', 'deleteMany', argsType, inputType, returnType) + generateMutation(useMutation, model, 'delete', 'deleteMany', argsType, inputType, returnType, false) ); } @@ -190,7 +193,7 @@ function generateModelHooks(project: Project, outDir: string, model: DataModel, `HasSelectOrTake extends Prisma.Or>, Prisma.Extends<'take', Prisma.Keys>>`, `OrderByArg extends Prisma.True extends HasSelectOrTake ? { orderBy: Prisma.${model.name}GroupByArgs['orderBy'] }: { orderBy?: Prisma.${model.name}GroupByArgs['orderBy'] },`, `OrderFields extends Prisma.ExcludeUnderscoreKeys>>`, - `ByFields extends Prisma.TupleToUnion`, + `ByFields extends Prisma.MaybeTupleToUnion`, `ByValid extends Prisma.Has`, `HavingFields extends Prisma.GetHavingFields`, `HavingValid extends Prisma.Has`, @@ -240,7 +243,7 @@ function generateModelHooks(project: Project, outDir: string, model: DataModel, ]; const inputType = `Prisma.SubsetIntersection & InputErrors`; const returnType = `{} extends InputErrors ? - Array & + Array & { [P in ((keyof T) & (keyof Prisma.${model.name}GroupByOutputType))]: P extends '_count' ? T[P] extends boolean @@ -266,7 +269,6 @@ function generateModelHooks(project: Project, outDir: string, model: DataModel, function generateIndex(project: Project, outDir: string, models: DataModel[]) { const sf = project.createSourceFile(path.join(outDir, 'index.ts'), undefined, { overwrite: true }); sf.addStatements(models.map((d) => `export * from './${paramCase(d.name)}';`)); - sf.addStatements(`export * from './_helper';`); } function generateQueryHook( @@ -308,7 +310,8 @@ function generateMutation( operation: string, argsType: string, inputType: string, - returnType: string + returnType: string, + checkReadBack: boolean ) { const modelRouteName = lowerCaseFirst(model.name); const funcName = `${operation}${model.name}`; @@ -326,20 +329,7 @@ function generateMutation( }) .addBody() .addStatements([ - wrapReadbackErrorCheck( - `return await request.${fetcherFunc}<${returnType}>(\`\${endpoint}/${modelRouteName}/${operation}\`, args, mutate, fetch);` - ), + `return await request.${fetcherFunc}<${returnType}, ${checkReadBack}>(\`\${endpoint}/${modelRouteName}/${operation}\`, args, mutate, fetch, ${checkReadBack});`, ]); return funcName; } - -function generateHelper(project: Project, outDir: string, useSuperJson: boolean) { - const helperContent = fs.readFileSync(path.join(__dirname, './res/helper.ts'), 'utf-8'); - const marshalContent = fs.readFileSync( - path.join(__dirname, useSuperJson ? './res/marshal-superjson.ts' : './res/marshal-json.ts'), - 'utf-8' - ); - project.createSourceFile(path.join(outDir, '_helper.ts'), `${helperContent}\n${marshalContent}`, { - overwrite: true, - }); -} diff --git a/packages/plugins/swr/res/helper.ts b/packages/plugins/swr/src/runtime/index.ts similarity index 59% rename from packages/plugins/swr/res/helper.ts rename to packages/plugins/swr/src/runtime/index.ts index 8161c85e0..78b17242f 100644 --- a/packages/plugins/swr/res/helper.ts +++ b/packages/plugins/swr/src/runtime/index.ts @@ -1,8 +1,9 @@ -/* eslint-disable */ - +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { deserialize, serialize } from '@zenstackhq/runtime/browser'; import { createContext } from 'react'; import type { MutatorCallback, MutatorOptions, SWRResponse } from 'swr'; import useSWR, { useSWRConfig } from 'swr'; +export * from './prisma-types'; /** * Function signature for `fetch`. @@ -61,7 +62,7 @@ export function get( fetch?: FetchFn ): SWRResponse { const reqUrl = options?.disabled ? null : url ? makeUrl(url, args) : null; - return useSWR(reqUrl, (url) => fetcher(url, undefined, fetch), { + return useSWR(reqUrl, (url) => fetcher(url, undefined, fetch, false), { fallbackData: options?.initialData, }); } @@ -73,8 +74,14 @@ export function get( * @param data The request data. * @param mutate Mutator for invalidating cache. */ -export async function post(url: string, data: unknown, mutate: Mutator, fetch?: FetchFn): Promise { - const r: Result = await fetcher( +export async function post( + url: string, + data: unknown, + mutate: Mutator, + fetch?: FetchFn, + checkReadBack?: C +): Promise { + const r = await fetcher( url, { method: 'POST', @@ -83,7 +90,8 @@ export async function post(url: string, data: unknown, mutate: Mutator, }, body: marshal(data), }, - fetch + fetch, + checkReadBack ); mutate(); return r; @@ -96,8 +104,14 @@ export async function post(url: string, data: unknown, mutate: Mutator, * @param data The request data. * @param mutate Mutator for invalidating cache. */ -export async function put(url: string, data: unknown, mutate: Mutator, fetch?: FetchFn): Promise { - const r: Result = await fetcher( +export async function put( + url: string, + data: unknown, + mutate: Mutator, + fetch?: FetchFn, + checkReadBack?: C +): Promise { + const r = await fetcher( url, { method: 'PUT', @@ -106,7 +120,8 @@ export async function put(url: string, data: unknown, mutate: Mutator, f }, body: marshal(data), }, - fetch + fetch, + checkReadBack ); mutate(); return r; @@ -119,14 +134,21 @@ export async function put(url: string, data: unknown, mutate: Mutator, f * @param args The request args object, which will be superjson-stringified and appended as "?q=" parameter * @param mutate Mutator for invalidating cache. */ -export async function del(url: string, args: unknown, mutate: Mutator, fetch?: FetchFn): Promise { +export async function del( + url: string, + args: unknown, + mutate: Mutator, + fetch?: FetchFn, + checkReadBack?: C +): Promise { const reqUrl = makeUrl(url, args); - const r: Result = await fetcher( + const r = await fetcher( reqUrl, { method: 'DELETE', }, - fetch + fetch, + checkReadBack ); const path = url.split('/'); path.pop(); @@ -155,23 +177,70 @@ export function getMutate(prefixes: string[]): Mutator { }; } -export async function fetcher(url: string, options?: RequestInit, fetch?: FetchFn) { +export async function fetcher( + url: string, + options?: RequestInit, + fetch?: FetchFn, + checkReadBack?: C +): Promise { const _fetch = fetch ?? window.fetch; const res = await _fetch(url, options); if (!res.ok) { + const errData = unmarshal(await res.text()); + if ( + checkReadBack !== false && + errData.error?.prisma && + errData.error?.code === 'P2004' && + errData.error?.reason === 'RESULT_NOT_READABLE' + ) { + // policy doesn't allow mutation result to be read back, just return undefined + return undefined as any; + } const error: Error & { info?: unknown; status?: number } = new Error( 'An error occurred while fetching the data.' ); - error.info = unmarshal(await res.text()); + error.info = errData.error; error.status = res.status; throw error; } const textResult = await res.text(); try { - return unmarshal(textResult) as R; + return unmarshal(textResult).data as R; } catch (err) { console.error(`Unable to deserialize data:`, textResult); throw err; } } + +function marshal(value: unknown) { + const { data, meta } = serialize(value); + if (meta) { + return JSON.stringify({ ...(data as any), meta: { serialization: meta } }); + } else { + return JSON.stringify(data); + } +} + +function unmarshal(value: string) { + const parsed = JSON.parse(value); + if (parsed.data && parsed.meta?.serialization) { + const deserializedData = deserialize(parsed.data, parsed.meta.serialization); + return { ...parsed, data: deserializedData }; + } else { + return parsed; + } +} + +function makeUrl(url: string, args: unknown) { + if (!args) { + return url; + } + + const { data, meta } = serialize(args); + let result = `${url}?q=${encodeURIComponent(JSON.stringify(data))}`; + if (meta) { + result += `&meta=${encodeURIComponent(JSON.stringify({ serialization: meta }))}`; + } + return result; +} diff --git a/packages/plugins/swr/src/runtime/prisma-types.ts b/packages/plugins/swr/src/runtime/prisma-types.ts new file mode 120000 index 000000000..277b4b133 --- /dev/null +++ b/packages/plugins/swr/src/runtime/prisma-types.ts @@ -0,0 +1 @@ +../../../prisma-types.ts \ No newline at end of file diff --git a/packages/plugins/swr/tests/swr.test.ts b/packages/plugins/swr/tests/swr.test.ts index 9b68dedfe..95e0aecfb 100644 --- a/packages/plugins/swr/tests/swr.test.ts +++ b/packages/plugins/swr/tests/swr.test.ts @@ -40,7 +40,7 @@ model Foo { } `; - it('swr generator regular json', async () => { + it('run plugin', async () => { await loadSchema( ` plugin swr { @@ -50,28 +50,11 @@ plugin swr { ${sharedModel} `, - true, - false, - [`${origDir}/dist`, 'react', '@types/react', 'swr'], - true - ); - }); - - it('swr generator superjson', async () => { - await loadSchema( - ` -plugin swr { - provider = '${process.cwd()}/dist' - output = '$projectRoot/hooks' - useSuperJson = true -} - -${sharedModel} - `, - true, - false, - [`${origDir}/dist`, 'react', '@types/react', 'swr', 'superjson'], - true + { + pushDb: false, + extraDependencies: [`${origDir}/dist`, 'react', '@types/react', 'swr'], + compile: true, + } ); }); }); diff --git a/packages/plugins/tanstack-query/package.json b/packages/plugins/tanstack-query/package.json index 84ab46573..f3ba5fd8c 100644 --- a/packages/plugins/tanstack-query/package.json +++ b/packages/plugins/tanstack-query/package.json @@ -1,19 +1,36 @@ { "name": "@zenstackhq/tanstack-query", "displayName": "ZenStack plugin for generating tanstack-query hooks", - "version": "1.0.0-beta.8", + "version": "1.0.0-beta.9", "description": "ZenStack plugin for generating tanstack-query hooks", "main": "index.js", + "exports": { + ".": { + "default": "./index.js" + }, + "./runtime/react": { + "import": "./runtime/react.mjs", + "require": "./runtime/react.js", + "default": "./runtime/react.js", + "types": "./runtime/react.d.ts" + }, + "./runtime/svelte": { + "import": "./runtime/svelte.mjs", + "require": "./runtime/svelte.js", + "default": "./runtime/svelte.js", + "types": "./runtime/svelte.d.ts" + } + }, "repository": { "type": "git", "url": "https://github.com/zenstackhq/zenstack" }, "scripts": { "clean": "rimraf dist", - "build": "pnpm lint && pnpm clean && tsc && copyfiles ./package.json ./README.md ./LICENSE 'res/**/*' dist && pnpm pack dist --pack-destination '../../../../.build'", - "watch": "tsc --watch", + "build": "pnpm lint && pnpm clean && tsc && tsup-node && copyfiles ./package.json ./README.md ./LICENSE dist && pnpm pack dist --pack-destination '../../../../.build'", + "watch": "concurrently \"tsc --watch\" \"tsup-node --watch\"", "lint": "eslint src --ext ts", - "test": "jest", + "test": "ZENSTACK_TEST=1 jest", "prepublishOnly": "pnpm build", "publish-dev": "pnpm publish --tag dev" }, @@ -25,7 +42,8 @@ "author": "ZenStack Team", "license": "MIT", "dependencies": { - "@prisma/generator-helper": "4.10.0", + "@prisma/generator-helper": "^5.0.0", + "@zenstackhq/runtime": "workspace:*", "@zenstackhq/sdk": "workspace:*", "change-case": "^4.1.2", "decimal.js": "^10.4.2", @@ -35,18 +53,16 @@ "upper-case-first": "^2.0.2" }, "devDependencies": { - "@tanstack/react-query": "^4.29.7", - "@tanstack/svelte-query": "^4.29.7", + "@tanstack/react-query": "4.29.7", + "@tanstack/svelte-query": "4.29.7", "@types/jest": "^29.5.0", - "@types/lower-case-first": "^1.0.1", - "@types/react": "^18.0.26", + "@types/node": "^18.0.0", + "@types/react": "18.2.0", "@types/tmp": "^0.2.3", - "@types/upper-case-first": "^1.1.2", "@zenstackhq/testtools": "workspace:*", "copyfiles": "^2.4.1", "jest": "^29.5.0", - "react": "^17.0.2 || ^18", - "react-dom": "^17.0.2 || ^18", + "react": "18.2.0", "rimraf": "^3.0.2", "swr": "^2.0.3", "ts-jest": "^29.0.5", diff --git a/packages/plugins/tanstack-query/res/marshal-json.ts b/packages/plugins/tanstack-query/res/marshal-json.ts deleted file mode 100644 index 1f00abc79..000000000 --- a/packages/plugins/tanstack-query/res/marshal-json.ts +++ /dev/null @@ -1,12 +0,0 @@ -function marshal(value: unknown) { - return JSON.stringify(value); -} - -function unmarshal(value: string) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return JSON.parse(value) as any; -} - -function makeUrl(url: string, args: unknown) { - return args ? url + `?q=${encodeURIComponent(JSON.stringify(args))}` : url; -} diff --git a/packages/plugins/tanstack-query/res/marshal-superjson.ts b/packages/plugins/tanstack-query/res/marshal-superjson.ts deleted file mode 100644 index 559b11b4e..000000000 --- a/packages/plugins/tanstack-query/res/marshal-superjson.ts +++ /dev/null @@ -1,20 +0,0 @@ -import superjson from 'superjson'; - -function marshal(value: unknown) { - return superjson.stringify(value); -} - -function unmarshal(value: string) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const j = JSON.parse(value) as any; - if (j?.json) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return superjson.parse(value); - } else { - return j; - } -} - -function makeUrl(url: string, args: unknown) { - return args ? url + `?q=${encodeURIComponent(superjson.stringify(args))}` : url; -} diff --git a/packages/plugins/tanstack-query/res/shared.ts b/packages/plugins/tanstack-query/res/shared.ts deleted file mode 100644 index 24caff7cb..000000000 --- a/packages/plugins/tanstack-query/res/shared.ts +++ /dev/null @@ -1,50 +0,0 @@ -/** - * The default query endpoint. - */ -export const DEFAULT_QUERY_ENDPOINT = '/api/model'; - -/** - * Prefix for react-query keys. - */ -export const QUERY_KEY_PREFIX = 'zenstack:'; - -/** - * Function signature for `fetch`. - */ -export type FetchFn = (url: string, options?: RequestInit) => Promise; - -/** - * Context type for configuring the hooks. - */ -export type RequestHandlerContext = { - /** - * The endpoint to use for the queries. - */ - endpoint: string; - - /** - * A custom fetch function for sending the HTTP requests. - */ - fetch?: FetchFn; -}; - -async function fetcher(url: string, options?: RequestInit, fetch?: FetchFn) { - const _fetch = fetch ?? window.fetch; - const res = await _fetch(url, options); - if (!res.ok) { - const error: Error & { info?: unknown; status?: number } = new Error( - 'An error occurred while fetching the data.' - ); - error.info = unmarshal(await res.text()); - error.status = res.status; - throw error; - } - - const textResult = await res.text(); - try { - return unmarshal(textResult) as R; - } catch (err) { - console.error(`Unable to deserialize data:`, textResult); - throw err; - } -} diff --git a/packages/plugins/tanstack-query/src/generator.ts b/packages/plugins/tanstack-query/src/generator.ts index 53ebf0942..b2e5226e3 100644 --- a/packages/plugins/tanstack-query/src/generator.ts +++ b/packages/plugins/tanstack-query/src/generator.ts @@ -1,4 +1,4 @@ -import { DMMF } from '@prisma/generator-helper'; +import type { DMMF } from '@prisma/generator-helper'; import { PluginError, PluginOptions, @@ -11,7 +11,6 @@ import { } from '@zenstackhq/sdk'; import { DataModel, Model } from '@zenstackhq/sdk/ast'; import { paramCase } from 'change-case'; -import fs from 'fs'; import { lowerCaseFirst } from 'lower-case-first'; import path from 'path'; import { Project, SourceFile, VariableDeclarationKind } from 'ts-morph'; @@ -38,7 +37,6 @@ export async function generate(model: Model, options: PluginOptions, dmmf: DMMF. } generateIndex(project, outDir, models); - generateHelper(target, project, outDir, options.useSuperJson === true); models.forEach((dataModel) => { const mapping = dmmf.mappings.modelOperations.find((op) => op.model === dataModel.name); @@ -102,16 +100,20 @@ function generateMutationHook( model: string, operation: string, httpVerb: 'post' | 'put' | 'delete', + checkReadBack: boolean, overrideReturnType?: string ) { const capOperation = upperCaseFirst(operation); const argsType = `Prisma.${model}${capOperation}Args`; const inputType = `Prisma.SelectSubset`; - const returnType = overrideReturnType ?? `Prisma.CheckSelect>`; + let returnType = overrideReturnType ?? `Prisma.CheckSelect>`; + if (checkReadBack) { + returnType = `(${returnType} | undefined )`; + } const nonGenericOptionsType = `Omit<${makeMutationOptions( target, - overrideReturnType ?? model, + checkReadBack ? `(${overrideReturnType ?? model} | undefined)` : overrideReturnType ?? model, argsType )}, 'mutationFn'>`; const optionsType = `Omit<${makeMutationOptions(target, returnType, inputType)}, 'mutationFn'>`; @@ -143,9 +145,9 @@ function generateMutationHook( initializer: ` ${httpVerb}Mutation<${argsType}, ${ overrideReturnType ?? model - }>('${model}', \`\${endpoint}/${lowerCaseFirst( + }, ${checkReadBack}>('${model}', \`\${endpoint}/${lowerCaseFirst( model - )}/${operation}\`, options, fetch, invalidateQueries) + )}/${operation}\`, options, fetch, invalidateQueries, ${checkReadBack}) `, }, ], @@ -232,12 +234,12 @@ function generateModelHooks( // create is somehow named "createOne" in the DMMF // eslint-disable-next-line @typescript-eslint/no-explicit-any if (mapping.create || (mapping as any).createOne) { - generateMutationHook(target, sf, model.name, 'create', 'post'); + generateMutationHook(target, sf, model.name, 'create', 'post', true); } // createMany if (mapping.createMany) { - generateMutationHook(target, sf, model.name, 'createMany', 'post', 'Prisma.BatchPayload'); + generateMutationHook(target, sf, model.name, 'createMany', 'post', false, 'Prisma.BatchPayload'); } // findMany @@ -259,31 +261,31 @@ function generateModelHooks( // update is somehow named "updateOne" in the DMMF // eslint-disable-next-line @typescript-eslint/no-explicit-any if (mapping.update || (mapping as any).updateOne) { - generateMutationHook(target, sf, model.name, 'update', 'put'); + generateMutationHook(target, sf, model.name, 'update', 'put', true); } // updateMany if (mapping.updateMany) { - generateMutationHook(target, sf, model.name, 'updateMany', 'put', 'Prisma.BatchPayload'); + generateMutationHook(target, sf, model.name, 'updateMany', 'put', false, 'Prisma.BatchPayload'); } // upsert // upsert is somehow named "upsertOne" in the DMMF // eslint-disable-next-line @typescript-eslint/no-explicit-any if (mapping.upsert || (mapping as any).upsertOne) { - generateMutationHook(target, sf, model.name, 'upsert', 'post'); + generateMutationHook(target, sf, model.name, 'upsert', 'post', true); } // del // delete is somehow named "deleteOne" in the DMMF // eslint-disable-next-line @typescript-eslint/no-explicit-any if (mapping.delete || (mapping as any).deleteOne) { - generateMutationHook(target, sf, model.name, 'delete', 'delete'); + generateMutationHook(target, sf, model.name, 'delete', 'delete', true); } // deleteMany if (mapping.deleteMany) { - generateMutationHook(target, sf, model.name, 'deleteMany', 'delete', 'Prisma.BatchPayload'); + generateMutationHook(target, sf, model.name, 'deleteMany', 'delete', false, 'Prisma.BatchPayload'); } // aggregate @@ -298,7 +300,7 @@ function generateModelHooks( `HasSelectOrTake extends Prisma.Or>, Prisma.Extends<'take', Prisma.Keys>>`, `OrderByArg extends Prisma.True extends HasSelectOrTake ? { orderBy: Prisma.${model.name}GroupByArgs['orderBy'] }: { orderBy?: Prisma.${model.name}GroupByArgs['orderBy'] },`, `OrderFields extends Prisma.ExcludeUnderscoreKeys>>`, - `ByFields extends Prisma.TupleToUnion`, + `ByFields extends Prisma.MaybeTupleToUnion`, `ByValid extends Prisma.Has`, `HavingFields extends Prisma.GetHavingFields`, `HavingValid extends Prisma.Has`, @@ -348,7 +350,7 @@ function generateModelHooks( ]; const returnType = `{} extends InputErrors ? - Array & + Array & { [P in ((keyof T) & (keyof Prisma.${model.name}GroupByOutputType))]: P extends '_count' ? T[P] extends boolean @@ -388,33 +390,6 @@ function generateModelHooks( function generateIndex(project: Project, outDir: string, models: DataModel[]) { const sf = project.createSourceFile(path.join(outDir, 'index.ts'), undefined, { overwrite: true }); sf.addStatements(models.map((d) => `export * from './${paramCase(d.name)}';`)); - sf.addStatements(`export * from './_helper';`); -} - -function generateHelper(target: TargetFramework, project: Project, outDir: string, useSuperJson: boolean) { - let srcFile: string; - switch (target) { - case 'react': - srcFile = path.join(__dirname, './res/react/helper.ts'); - break; - case 'svelte': - srcFile = path.join(__dirname, './res/svelte/helper.ts'); - break; - default: - throw new PluginError(name, `Unsupported target: ${target}`); - } - - // merge content of `shared.ts`, `helper.ts` and `marshal-?.ts` - const sharedContent = fs.readFileSync(path.join(__dirname, './res/shared.ts'), 'utf-8'); - const helperContent = fs.readFileSync(srcFile, 'utf-8'); - const marshalContent = fs.readFileSync( - path.join(__dirname, useSuperJson ? './res/marshal-superjson.ts' : './res/marshal-json.ts'), - 'utf-8' - ); - - project.createSourceFile(path.join(outDir, '_helper.ts'), `${sharedContent}\n${helperContent}\n${marshalContent}`, { - overwrite: true, - }); } function makeGetContext(target: TargetFramework) { @@ -429,13 +404,16 @@ function makeGetContext(target: TargetFramework) { } function makeBaseImports(target: TargetFramework) { - const shared = [`import { query, postMutation, putMutation, deleteMutation } from './_helper';`]; + const shared = [ + `import { query, postMutation, putMutation, deleteMutation } from '@zenstackhq/tanstack-query/runtime/${target}';`, + `import type { PickEnumerable } from '@zenstackhq/tanstack-query/runtime';`, + ]; switch (target) { case 'react': return [ `import { useContext } from 'react';`, `import type { UseMutationOptions, UseQueryOptions } from '@tanstack/react-query';`, - `import { RequestHandlerContext } from './_helper';`, + `import { RequestHandlerContext } from '@zenstackhq/tanstack-query/runtime/${target}';`, ...shared, ]; case 'svelte': @@ -443,7 +421,7 @@ function makeBaseImports(target: TargetFramework) { `import { getContext } from 'svelte';`, `import { derived } from 'svelte/store';`, `import type { MutationOptions, QueryOptions } from '@tanstack/svelte-query';`, - `import { SvelteQueryContextKey, type RequestHandlerContext } from './_helper';`, + `import { SvelteQueryContextKey, type RequestHandlerContext } from '@zenstackhq/tanstack-query/runtime/${target}';`, ...shared, ]; default: diff --git a/packages/plugins/tanstack-query/src/runtime/common.ts b/packages/plugins/tanstack-query/src/runtime/common.ts new file mode 100644 index 000000000..f341883a2 --- /dev/null +++ b/packages/plugins/tanstack-query/src/runtime/common.ts @@ -0,0 +1,100 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { serialize, deserialize } from '@zenstackhq/runtime/browser'; + +/** + * The default query endpoint. + */ +export const DEFAULT_QUERY_ENDPOINT = '/api/model'; + +/** + * Prefix for react-query keys. + */ +export const QUERY_KEY_PREFIX = 'zenstack:'; + +/** + * Function signature for `fetch`. + */ +export type FetchFn = (url: string, options?: RequestInit) => Promise; + +/** + * Context type for configuring the hooks. + */ +export type APIContext = { + /** + * The endpoint to use for the queries. + */ + endpoint: string; + + /** + * A custom fetch function for sending the HTTP requests. + */ + fetch?: FetchFn; +}; + +export async function fetcher( + url: string, + options?: RequestInit, + fetch?: FetchFn, + checkReadBack?: C +): Promise { + const _fetch = fetch ?? window.fetch; + const res = await _fetch(url, options); + if (!res.ok) { + const errData = unmarshal(await res.text()); + if ( + checkReadBack !== false && + errData.error?.prisma && + errData.error?.code === 'P2004' && + errData.error?.reason === 'RESULT_NOT_READABLE' + ) { + // policy doesn't allow mutation result to be read back, just return undefined + return undefined as any; + } + const error: Error & { info?: unknown; status?: number } = new Error( + 'An error occurred while fetching the data.' + ); + error.info = errData.error; + error.status = res.status; + throw error; + } + + const textResult = await res.text(); + try { + return unmarshal(textResult).data as R; + } catch (err) { + console.error(`Unable to deserialize data:`, textResult); + throw err; + } +} + +export function marshal(value: unknown) { + const { data, meta } = serialize(value); + if (meta) { + return JSON.stringify({ ...(data as any), meta: { serialization: meta } }); + } else { + return JSON.stringify(data); + } +} + +export function unmarshal(value: string) { + const parsed = JSON.parse(value); + if (parsed.data && parsed.meta?.serialization) { + const deserializedData = deserialize(parsed.data, parsed.meta.serialization); + return { ...parsed, data: deserializedData }; + } else { + return parsed; + } +} + +export function makeUrl(url: string, args: unknown) { + if (!args) { + return url; + } + + const { data, meta } = serialize(args); + let result = `${url}?q=${encodeURIComponent(JSON.stringify(data))}`; + if (meta) { + result += `&meta=${encodeURIComponent(JSON.stringify({ serialization: meta }))}`; + } + return result; +} diff --git a/packages/plugins/tanstack-query/src/runtime/index.ts b/packages/plugins/tanstack-query/src/runtime/index.ts new file mode 100644 index 000000000..e4853b9b7 --- /dev/null +++ b/packages/plugins/tanstack-query/src/runtime/index.ts @@ -0,0 +1 @@ +export * from './prisma-types'; diff --git a/packages/plugins/tanstack-query/src/runtime/prisma-types.ts b/packages/plugins/tanstack-query/src/runtime/prisma-types.ts new file mode 120000 index 000000000..277b4b133 --- /dev/null +++ b/packages/plugins/tanstack-query/src/runtime/prisma-types.ts @@ -0,0 +1 @@ +../../../prisma-types.ts \ No newline at end of file diff --git a/packages/plugins/tanstack-query/res/react/helper.ts b/packages/plugins/tanstack-query/src/runtime/react.ts similarity index 65% rename from packages/plugins/tanstack-query/res/react/helper.ts rename to packages/plugins/tanstack-query/src/runtime/react.ts index 5ead00257..cdbbe1b68 100644 --- a/packages/plugins/tanstack-query/res/react/helper.ts +++ b/packages/plugins/tanstack-query/src/runtime/react.ts @@ -1,5 +1,4 @@ -/* eslint-disable */ - +/* eslint-disable @typescript-eslint/no-explicit-any */ import { useMutation, useQuery, @@ -10,11 +9,20 @@ import { type UseQueryOptions, } from '@tanstack/react-query'; import { createContext } from 'react'; +import { + DEFAULT_QUERY_ENDPOINT, + FetchFn, + QUERY_KEY_PREFIX, + fetcher, + makeUrl, + marshal, + type APIContext, +} from './common'; /** * Context for configuring react hooks. */ -export const RequestHandlerContext = createContext({ +export const RequestHandlerContext = createContext({ endpoint: DEFAULT_QUERY_ENDPOINT, fetch: undefined, }); @@ -38,7 +46,7 @@ export function query(model: string, url: string, args?: unknown, options?: U const reqUrl = makeUrl(url, args); return useQuery({ queryKey: [QUERY_KEY_PREFIX + model, url, args], - queryFn: () => fetcher(reqUrl, undefined, fetch), + queryFn: () => fetcher(reqUrl, undefined, fetch, false), ...options, }); } @@ -52,16 +60,17 @@ export function query(model: string, url: string, args?: unknown, options?: U * @param invalidateQueries Whether to invalidate queries after mutation. * @returns useMutation hooks */ -export function postMutation( +export function postMutation( model: string, url: string, - options?: Omit, 'mutationFn'>, + options?: Omit, 'mutationFn'>, fetch?: FetchFn, - invalidateQueries = true + invalidateQueries = true, + checkReadBack?: C ) { const queryClient = useQueryClient(); const mutationFn = (data: any) => - fetcher( + fetcher( url, { method: 'POST', @@ -70,11 +79,12 @@ export function postMutation( }, body: marshal(data), }, - fetch - ); + fetch, + checkReadBack + ) as Promise; - const finalOptions = mergeOptions(model, options, invalidateQueries, mutationFn, queryClient); - const mutation = useMutation(finalOptions); + const finalOptions = mergeOptions(model, options, invalidateQueries, mutationFn, queryClient); + const mutation = useMutation(finalOptions); return mutation; } @@ -87,16 +97,17 @@ export function postMutation( * @param invalidateQueries Whether to invalidate queries after mutation. * @returns useMutation hooks */ -export function putMutation( +export function putMutation( model: string, url: string, - options?: Omit, 'mutationFn'>, + options?: Omit, 'mutationFn'>, fetch?: FetchFn, - invalidateQueries = true + invalidateQueries = true, + checkReadBack?: C ) { const queryClient = useQueryClient(); const mutationFn = (data: any) => - fetcher( + fetcher( url, { method: 'PUT', @@ -105,11 +116,12 @@ export function putMutation( }, body: marshal(data), }, - fetch - ); + fetch, + checkReadBack + ) as Promise; - const finalOptions = mergeOptions(model, options, invalidateQueries, mutationFn, queryClient); - const mutation = useMutation(finalOptions); + const finalOptions = mergeOptions(model, options, invalidateQueries, mutationFn, queryClient); + const mutation = useMutation(finalOptions); return mutation; } @@ -122,25 +134,27 @@ export function putMutation( * @param invalidateQueries Whether to invalidate queries after mutation. * @returns useMutation hooks */ -export function deleteMutation( +export function deleteMutation( model: string, url: string, - options?: Omit, 'mutationFn'>, + options?: Omit, 'mutationFn'>, fetch?: FetchFn, - invalidateQueries = true + invalidateQueries = true, + checkReadBack?: C ) { const queryClient = useQueryClient(); const mutationFn = (data: any) => - fetcher( + fetcher( makeUrl(url, data), { method: 'DELETE', }, - fetch - ); + fetch, + checkReadBack + ) as Promise; - const finalOptions = mergeOptions(model, options, invalidateQueries, mutationFn, queryClient); - const mutation = useMutation(finalOptions); + const finalOptions = mergeOptions(model, options, invalidateQueries, mutationFn, queryClient); + const mutation = useMutation(finalOptions); return mutation; } diff --git a/packages/plugins/tanstack-query/res/svelte/helper.ts b/packages/plugins/tanstack-query/src/runtime/svelte.ts similarity index 65% rename from packages/plugins/tanstack-query/res/svelte/helper.ts rename to packages/plugins/tanstack-query/src/runtime/svelte.ts index d40d8cee5..7edab8edc 100644 --- a/packages/plugins/tanstack-query/res/svelte/helper.ts +++ b/packages/plugins/tanstack-query/src/runtime/svelte.ts @@ -1,5 +1,4 @@ -/* eslint-disable */ - +/* eslint-disable @typescript-eslint/no-explicit-any */ import { createMutation, createQuery, @@ -9,6 +8,9 @@ import { type QueryClient, type QueryOptions, } from '@tanstack/svelte-query'; +import { FetchFn, QUERY_KEY_PREFIX, fetcher, makeUrl, marshal } from './common'; + +export { APIContext as RequestHandlerContext } from './common'; /** * Key for setting and getting the global query context. @@ -29,7 +31,7 @@ export function query(model: string, url: string, args?: unknown, options?: Q const reqUrl = makeUrl(url, args); return createQuery({ queryKey: [QUERY_KEY_PREFIX + model, url, args], - queryFn: () => fetcher(reqUrl, undefined, fetch), + queryFn: () => fetcher(reqUrl, undefined, fetch, false), ...options, }); } @@ -43,16 +45,17 @@ export function query(model: string, url: string, args?: unknown, options?: Q * @param invalidateQueries Whether to invalidate queries after mutation. * @returns useMutation hooks */ -export function postMutation( +export function postMutation( model: string, url: string, - options?: Omit, 'mutationFn'>, + options?: Omit, 'mutationFn'>, fetch?: FetchFn, - invalidateQueries = true + invalidateQueries = true, + checkReadBack?: C ) { const queryClient = useQueryClient(); const mutationFn = (data: any) => - fetcher( + fetcher( url, { method: 'POST', @@ -61,11 +64,12 @@ export function postMutation( }, body: marshal(data), }, - fetch - ); + fetch, + checkReadBack + ) as Promise; - const finalOptions = mergeOptions(model, options, invalidateQueries, mutationFn, queryClient); - const mutation = createMutation(finalOptions); + const finalOptions = mergeOptions(model, options, invalidateQueries, mutationFn, queryClient); + const mutation = createMutation(finalOptions); return mutation; } @@ -78,16 +82,17 @@ export function postMutation( * @param invalidateQueries Whether to invalidate queries after mutation. * @returns useMutation hooks */ -export function putMutation( +export function putMutation( model: string, url: string, - options?: Omit, 'mutationFn'>, + options?: Omit, 'mutationFn'>, fetch?: FetchFn, - invalidateQueries = true + invalidateQueries = true, + checkReadBack?: C ) { const queryClient = useQueryClient(); const mutationFn = (data: any) => - fetcher( + fetcher( url, { method: 'PUT', @@ -96,11 +101,12 @@ export function putMutation( }, body: marshal(data), }, - fetch - ); + fetch, + checkReadBack + ) as Promise; - const finalOptions = mergeOptions(model, options, invalidateQueries, mutationFn, queryClient); - const mutation = createMutation(finalOptions); + const finalOptions = mergeOptions(model, options, invalidateQueries, mutationFn, queryClient); + const mutation = createMutation(finalOptions); return mutation; } @@ -113,25 +119,27 @@ export function putMutation( * @param invalidateQueries Whether to invalidate queries after mutation. * @returns useMutation hooks */ -export function deleteMutation( +export function deleteMutation( model: string, url: string, - options?: Omit, 'mutationFn'>, + options?: Omit, 'mutationFn'>, fetch?: FetchFn, - invalidateQueries = true + invalidateQueries = true, + checkReadBack?: C ) { const queryClient = useQueryClient(); const mutationFn = (data: any) => - fetcher( + fetcher( makeUrl(url, data), { method: 'DELETE', }, - fetch - ); + fetch, + checkReadBack + ) as Promise; - const finalOptions = mergeOptions(model, options, invalidateQueries, mutationFn, queryClient); - const mutation = createMutation(finalOptions); + const finalOptions = mergeOptions(model, options, invalidateQueries, mutationFn, queryClient); + const mutation = createMutation(finalOptions); return mutation; } diff --git a/packages/plugins/tanstack-query/tests/plugin.test.ts b/packages/plugins/tanstack-query/tests/plugin.test.ts index fd2f300fa..62d605f74 100644 --- a/packages/plugins/tanstack-query/tests/plugin.test.ts +++ b/packages/plugins/tanstack-query/tests/plugin.test.ts @@ -40,7 +40,7 @@ model Foo { } `; - it('react-query generator regular json', async () => { + it('react-query run plugin', async () => { await loadSchema( ` plugin tanstack { @@ -51,66 +51,35 @@ plugin tanstack { ${sharedModel} `, - true, - false, - [`${origDir}/dist`, 'react', '@types/react', '@tanstack/react-query'], - true + { + pushDb: false, + extraDependencies: [ + `${origDir}/dist`, + 'react@18.2.0', + '@types/react@18.2.0', + '@tanstack/react-query@4.29.7', + ], + compile: true, + } ); }); - it('react-query generator superjson', async () => { - await loadSchema( - ` -plugin tanstack { - provider = '${process.cwd()}/dist' - output = '$projectRoot/hooks' - target = 'react' - useSuperJson = true -} - -${sharedModel} - `, - true, - false, - [`${origDir}/dist`, 'react', '@types/react', '@tanstack/react-query', 'superjson'], - true - ); - }); - - it('svelte-query generator regular json', async () => { - await loadSchema( - ` -plugin tanstack { - provider = '${process.cwd()}/dist' - output = '$projectRoot/hooks' - target = 'svelte' -} - -${sharedModel} - `, - true, - false, - [`${origDir}/dist`, 'svelte@^3.0.0', '@types/react', '@tanstack/svelte-query'], - true - ); - }); - - it('svelte-query generator superjson', async () => { + it('svelte-query run plugin', async () => { await loadSchema( ` plugin tanstack { provider = '${process.cwd()}/dist' output = '$projectRoot/hooks' target = 'svelte' - useSuperJson = true } ${sharedModel} `, - true, - false, - [`${origDir}/dist`, 'svelte@^3.0.0', '@types/react', '@tanstack/svelte-query', 'superjson'], - true + { + pushDb: false, + extraDependencies: [`${origDir}/dist`, 'svelte@^3.0.0', '@tanstack/svelte-query@4.29.7'], + compile: true, + } ); }); }); diff --git a/packages/plugins/tanstack-query/tsconfig.json b/packages/plugins/tanstack-query/tsconfig.json index e2c5bd0f3..d27927629 100644 --- a/packages/plugins/tanstack-query/tsconfig.json +++ b/packages/plugins/tanstack-query/tsconfig.json @@ -17,5 +17,6 @@ "strictPropertyInitialization": false, "paths": {} }, - "include": ["src/**/*.ts"] + "include": ["src/**/*.ts"], + "exclude": ["src/runtime"] } diff --git a/packages/plugins/tanstack-query/tsup.config.ts b/packages/plugins/tanstack-query/tsup.config.ts new file mode 100644 index 000000000..63646db51 --- /dev/null +++ b/packages/plugins/tanstack-query/tsup.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from 'tsup'; + +export default defineConfig({ + entry: ['src/runtime/index.ts', 'src/runtime/react.ts', 'src/runtime/svelte.ts'], + outDir: 'dist/runtime', + splitting: false, + sourcemap: true, + clean: true, + dts: true, + format: ['cjs', 'esm'], +}); diff --git a/packages/plugins/trpc/package.json b/packages/plugins/trpc/package.json index 7cf24d0da..663db158c 100644 --- a/packages/plugins/trpc/package.json +++ b/packages/plugins/trpc/package.json @@ -1,7 +1,7 @@ { "name": "@zenstackhq/trpc", "displayName": "ZenStack plugin for tRPC", - "version": "1.0.0-beta.8", + "version": "1.0.0-beta.9", "description": "ZenStack plugin for tRPC", "main": "index.js", "repository": { @@ -24,8 +24,7 @@ "author": "ZenStack Team", "license": "MIT", "dependencies": { - "@prisma/generator-helper": "4.10.0", - "@prisma/internals": "4.10.0", + "@prisma/generator-helper": "^5.0.0", "@zenstackhq/sdk": "workspace:*", "change-case": "^4.1.2", "lower-case-first": "^2.0.2", @@ -40,7 +39,7 @@ "@trpc/react-query": "^10.32.0", "@trpc/server": "^10.32.0", "@types/jest": "^29.5.0", - "@types/lower-case-first": "^1.0.1", + "@types/node": "^18.0.0", "@types/prettier": "^2.7.2", "@zenstackhq/testtools": "workspace:*", "copyfiles": "^2.4.1", diff --git a/packages/plugins/trpc/src/generator.ts b/packages/plugins/trpc/src/generator.ts index 8f21b2700..caebd785c 100644 --- a/packages/plugins/trpc/src/generator.ts +++ b/packages/plugins/trpc/src/generator.ts @@ -1,4 +1,4 @@ -import { DMMF } from '@prisma/generator-helper'; +import type { DMMF } from '@prisma/generator-helper'; import { CrudFailureReason, PluginError, diff --git a/packages/plugins/trpc/src/helpers.ts b/packages/plugins/trpc/src/helpers.ts index c09640278..d56e42c9b 100644 --- a/packages/plugins/trpc/src/helpers.ts +++ b/packages/plugins/trpc/src/helpers.ts @@ -1,4 +1,4 @@ -import { DMMF } from '@prisma/generator-helper'; +import type { DMMF } from '@prisma/generator-helper'; import { PluginError, getPrismaClientImportSpec } from '@zenstackhq/sdk'; import { Model } from '@zenstackhq/sdk/ast'; import { lowerCaseFirst } from 'lower-case-first'; @@ -123,7 +123,7 @@ function getPrismaOperationTypes(model: string, operation: string) { ? { orderBy: Prisma.${capModel}GroupByArgs['orderBy'] } : { orderBy?: Prisma.${capModel}GroupByArgs['orderBy'] }, OrderFields extends Prisma.ExcludeUnderscoreKeys>>, - ByFields extends Prisma.TupleToUnion, + ByFields extends Prisma.MaybeTupleToUnion, ByValid extends Prisma.Has, HavingFields extends Prisma.GetHavingFields, HavingValid extends Prisma.Has, diff --git a/packages/plugins/trpc/src/index.ts b/packages/plugins/trpc/src/index.ts index 9be85b19d..85d2a61d8 100644 --- a/packages/plugins/trpc/src/index.ts +++ b/packages/plugins/trpc/src/index.ts @@ -1,4 +1,4 @@ -import { DMMF } from '@prisma/generator-helper'; +import type { DMMF } from '@prisma/generator-helper'; import { PluginOptions } from '@zenstackhq/sdk'; import { Model } from '@zenstackhq/sdk/ast'; import { generate } from './generator'; diff --git a/packages/plugins/trpc/tests/trpc.test.ts b/packages/plugins/trpc/tests/trpc.test.ts index 16e907ee7..617bbe66c 100644 --- a/packages/plugins/trpc/tests/trpc.test.ts +++ b/packages/plugins/trpc/tests/trpc.test.ts @@ -48,10 +48,12 @@ model Foo { @@ignore } `, - true, - false, - [`${origDir}/dist`, '@trpc/client', '@trpc/server'], - true + { + pushDb: false, + extraDependencies: [`${origDir}/dist`, '@trpc/client', '@trpc/server'], + compile: true, + fullZod: true, + } ); }); @@ -88,10 +90,12 @@ model Foo { @@ignore } `, - true, - false, - [`${origDir}/dist`, '@trpc/client', '@trpc/server'], - true + { + pushDb: false, + extraDependencies: [`${origDir}/dist`, '@trpc/client', '@trpc/server'], + compile: true, + fullZod: true, + } ); expect(fs.existsSync(path.join(projectDir, 'trpc'))).toBe(true); }); @@ -116,11 +120,13 @@ model Post { authorId String? } `, - true, - false, - [`${origDir}/dist`, '@trpc/client', '@trpc/server'], - true, - 'zenstack/schema.zmodel' + { + pushDb: false, + extraDependencies: [`${origDir}/dist`, '@trpc/client', '@trpc/server'], + compile: true, + fullZod: true, + customSchemaFilePath: 'zenstack/schema.zmodel', + } ); expect(fs.existsSync(path.join(projectDir, 'zenstack/trpc'))).toBe(true); }); @@ -139,11 +145,13 @@ model Post { title String } `, - true, - false, - [`${origDir}/dist`, '@trpc/client', '@trpc/server'], - true, - 'zenstack/schema.zmodel' + { + pushDb: false, + extraDependencies: [`${origDir}/dist`, '@trpc/client', '@trpc/server'], + compile: true, + fullZod: true, + customSchemaFilePath: 'zenstack/schema.zmodel', + } ); const content = fs.readFileSync(path.join(projectDir, 'zenstack/trpc/routers/Post.router.ts'), 'utf-8'); expect(content).toContain('findMany:'); @@ -167,11 +175,13 @@ model Post { title String } `, - true, - false, - [`${origDir}/dist`, '@trpc/client', '@trpc/server'], - true, - 'zenstack/schema.zmodel' + { + pushDb: false, + extraDependencies: [`${origDir}/dist`, '@trpc/client', '@trpc/server'], + compile: true, + fullZod: true, + customSchemaFilePath: 'zenstack/schema.zmodel', + } ); const content = fs.readFileSync(path.join(projectDir, 'zenstack/trpc/routers/Post.router.ts'), 'utf-8'); expect(content).toContain('findMany:'); @@ -211,10 +221,12 @@ model Post { ${BLOG_BASE_SCHEMA} `, - true, - false, - [`${origDir}/dist`, '@trpc/client', '@trpc/server', '@trpc/react-query'], - true + { + pushDb: false, + extraDependencies: [`${origDir}/dist`, '@trpc/client', '@trpc/server', '@trpc/react-query'], + compile: true, + fullZod: true, + } ); }); @@ -229,10 +241,12 @@ model Post { ${BLOG_BASE_SCHEMA} `, - true, - false, - [`${origDir}/dist`, '@trpc/client', '@trpc/server', '@trpc/next'], - true + { + pushDb: false, + extraDependencies: [`${origDir}/dist`, '@trpc/client', '@trpc/server', '@trpc/next'], + compile: true, + fullZod: true, + } ); }); }); diff --git a/packages/runtime/package.json b/packages/runtime/package.json index 85e5bb5ea..694614ca3 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -1,7 +1,7 @@ { "name": "@zenstackhq/runtime", "displayName": "ZenStack Runtime Library", - "version": "1.0.0-beta.8", + "version": "1.0.0-beta.9", "description": "Runtime of ZenStack for both client-side and server-side environments.", "repository": { "type": "git", @@ -9,14 +9,34 @@ }, "scripts": { "clean": "rimraf dist", - "build": "pnpm lint && pnpm clean && tsc && copyfiles ./package.json ./README.md ../../LICENSE dist && copyfiles -u1 'res/**/*' dist && pnpm pack dist --pack-destination '../../../.build'", - "watch": "tsc --watch", + "build": "pnpm lint && pnpm clean && tsc && tsup-node && copyfiles ./package.json ./README.md ../../LICENSE dist && copyfiles -u1 'res/**/*' dist && pnpm pack dist --pack-destination '../../../.build'", + "watch": "concurrently \"tsc --watch\" \"tsup-node --watch\"", "lint": "eslint src --ext ts", "prepublishOnly": "pnpm build", "publish-dev": "pnpm publish --tag dev" }, "main": "index.js", "types": "index.d.ts", + "exports": { + ".": { + "default": "./index.js" + }, + "./zod": { + "default": "./zod/index.js" + }, + "./zod/input": { + "default": "./zod/input.js" + }, + "./zod/models": { + "default": "./zod/models.js" + }, + "./browser": { + "import": "./browser/index.mjs", + "require": "./browser/index.js", + "default": "./browser/index.js", + "types": "./browser/index.d.ts" + } + }, "publishConfig": { "directory": "dist", "linkDirectory": true @@ -25,6 +45,7 @@ "@paralleldrive/cuid2": "^2.2.0", "@types/bcryptjs": "^2.4.2", "bcryptjs": "^2.4.3", + "buffer": "^6.0.3", "change-case": "^4.1.2", "colors": "1.4.0", "decimal.js": "^10.4.2", @@ -43,11 +64,9 @@ "homepage": "https://zenstack.dev", "license": "MIT", "devDependencies": { - "@prisma/client": "^4.0.0", "@types/bcryptjs": "^2.4.2", "@types/jest": "^29.5.0", - "@types/lower-case-first": "^1.0.1", - "@types/node": "^14.18.29", + "@types/node": "^18.0.0", "@types/pluralize": "^0.0.29", "copyfiles": "^2.4.1", "rimraf": "^3.0.2", diff --git a/packages/runtime/src/browser/index.ts b/packages/runtime/src/browser/index.ts new file mode 100644 index 000000000..90e875c0a --- /dev/null +++ b/packages/runtime/src/browser/index.ts @@ -0,0 +1 @@ +export * from './serialization'; diff --git a/packages/runtime/src/browser/serialization.ts b/packages/runtime/src/browser/serialization.ts new file mode 100644 index 000000000..a0184e0a2 --- /dev/null +++ b/packages/runtime/src/browser/serialization.ts @@ -0,0 +1,36 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import Decimal from 'decimal.js'; +import SuperJSON from 'superjson'; + +SuperJSON.registerCustom( + { + isApplicable: (v): v is Decimal => Decimal.isDecimal(v), + serialize: (v) => v.toJSON(), + deserialize: (v) => new Decimal(v), + }, + 'Decimal' +); + +SuperJSON.registerCustom( + { + isApplicable: (v): v is Buffer => Buffer.isBuffer(v), + serialize: (v) => v.toString('base64'), + deserialize: (v) => Buffer.from(v, 'base64'), + }, + 'Bytes' +); + +/** + * Serialize the given value with superjson + */ +export function serialize(value: unknown): { data: unknown; meta: unknown } { + const { json, meta } = SuperJSON.serialize(value); + return { data: json, meta }; +} + +/** + * Deserialize the given value with superjson using the given metadata + */ +export function deserialize(value: unknown, meta: any): unknown { + return SuperJSON.deserialize({ json: value as any, meta }); +} diff --git a/packages/runtime/src/constants.ts b/packages/runtime/src/constants.ts index 1a09ac31b..d1263255f 100644 --- a/packages/runtime/src/constants.ts +++ b/packages/runtime/src/constants.ts @@ -19,11 +19,23 @@ export const GUARD_FIELD_NAME = 'zenstack_guard'; export const AUXILIARY_FIELDS = [TRANSACTION_FIELD_NAME, GUARD_FIELD_NAME]; /** - * Reasons for a CRUD operation to fail. + * Reasons for a CRUD operation to fail */ export enum CrudFailureReason { /** * CRUD suceeded but the result was not readable. */ RESULT_NOT_READABLE = 'RESULT_NOT_READABLE', + + /** + * CRUD failed because of a data validation rule violation. + */ + DATA_VALIDATION_VIOLATION = 'DATA_VALIDATION_VIOLATION', +} + +/** + * Prisma error codes used + */ +export enum PrismaErrorCode { + CONSTRAINED_FAILED = 'P2004', } diff --git a/packages/runtime/src/enhancements/index.ts b/packages/runtime/src/enhancements/index.ts index 4f223bc63..c1ae7c70e 100644 --- a/packages/runtime/src/enhancements/index.ts +++ b/packages/runtime/src/enhancements/index.ts @@ -1,5 +1,9 @@ +export * from './model-meta'; +export * from './nested-write-vistor'; export * from './omit'; export * from './password'; export * from './policy'; export * from './preset'; +export * from './types'; export * from './utils'; +export * from './where-visitor'; diff --git a/packages/runtime/src/enhancements/nested-write-vistor.ts b/packages/runtime/src/enhancements/nested-write-vistor.ts index 5dd13c0a3..5b696bbd0 100644 --- a/packages/runtime/src/enhancements/nested-write-vistor.ts +++ b/packages/runtime/src/enhancements/nested-write-vistor.ts @@ -11,7 +11,7 @@ type NestingPathItem = { field?: FieldInfo; model: string; where: any; unique: b /** * Context for visiting */ -export type VisitorContext = { +export type NestedWriteVisitorContext = { /** * Parent data, can be used to replace fields */ @@ -32,29 +32,42 @@ export type VisitorContext = { * NestedWriteVisitor's callback actions */ export type NestedWriterVisitorCallback = { - create?: (model: string, args: any[], context: VisitorContext) => Promise; + create?: (model: string, args: any[], context: NestedWriteVisitorContext) => Promise; - connectOrCreate?: (model: string, args: { where: object; create: any }, context: VisitorContext) => Promise; + connectOrCreate?: ( + model: string, + args: { where: object; create: any }, + context: NestedWriteVisitorContext + ) => Promise; - connect?: (model: string, args: object, context: VisitorContext) => Promise; + connect?: (model: string, args: object, context: NestedWriteVisitorContext) => Promise; - disconnect?: (model: string, args: object, context: VisitorContext) => Promise; + disconnect?: (model: string, args: object, context: NestedWriteVisitorContext) => Promise; - update?: (model: string, args: { where: object; data: any }, context: VisitorContext) => Promise; + update?: (model: string, args: { where: object; data: any }, context: NestedWriteVisitorContext) => Promise; - updateMany?: (model: string, args: { where?: object; data: any }, context: VisitorContext) => Promise; + updateMany?: ( + model: string, + args: { where?: object; data: any }, + context: NestedWriteVisitorContext + ) => Promise; upsert?: ( model: string, args: { where: object; create: any; update: any }, - context: VisitorContext + context: NestedWriteVisitorContext ) => Promise; - delete?: (model: string, args: object | boolean, context: VisitorContext) => Promise; + delete?: (model: string, args: object | boolean, context: NestedWriteVisitorContext) => Promise; - deleteMany?: (model: string, args: any | object, context: VisitorContext) => Promise; + deleteMany?: (model: string, args: any | object, context: NestedWriteVisitorContext) => Promise; - field?: (field: FieldInfo, action: PrismaWriteActionType, data: any, context: VisitorContext) => Promise; + field?: ( + field: FieldInfo, + action: PrismaWriteActionType, + data: any, + context: NestedWriteVisitorContext + ) => Promise; }; /** diff --git a/packages/runtime/src/enhancements/policy/policy-utils.ts b/packages/runtime/src/enhancements/policy/policy-utils.ts index c97fa1537..5dadf1590 100644 --- a/packages/runtime/src/enhancements/policy/policy-utils.ts +++ b/packages/runtime/src/enhancements/policy/policy-utils.ts @@ -6,7 +6,14 @@ import { lowerCaseFirst } from 'lower-case-first'; import pluralize from 'pluralize'; import { upperCaseFirst } from 'upper-case-first'; import { fromZodError } from 'zod-validation-error'; -import { AUXILIARY_FIELDS, CrudFailureReason, GUARD_FIELD_NAME, TRANSACTION_FIELD_NAME } from '../../constants'; +import { + AUXILIARY_FIELDS, + CrudFailureReason, + GUARD_FIELD_NAME, + PrismaErrorCode, + TRANSACTION_FIELD_NAME, +} from '../../constants'; +import { isPrismaClientKnownRequestError } from '../../error'; import { AuthUser, DbClientContract, @@ -17,7 +24,7 @@ import { } from '../../types'; import { getVersion } from '../../version'; import { getFields, resolveField } from '../model-meta'; -import { NestedWriteVisitor, type VisitorContext } from '../nested-write-vistor'; +import { NestedWriteVisitor, type NestedWriteVisitorContext } from '../nested-write-vistor'; import type { ModelMeta, PolicyDef, PolicyFunc, ZodSchemas } from '../types'; import { enumerate, @@ -402,7 +409,26 @@ export class PolicyUtil { // `Validating read of to-one relation: ${fieldInfo.type}#${formatObject(ids)}` // ); // } - await this.checkPolicyForFilter(fieldInfo.type, ids, operation, this.db); + try { + await this.checkPolicyForFilter(fieldInfo.type, ids, operation, this.db); + } catch (err) { + if ( + isPrismaClientKnownRequestError(err) && + err.code === PrismaErrorCode.CONSTRAINED_FAILED + ) { + // denied by policy + if (fieldInfo.isOptional) { + // if the relation is optional, just nullify it + entityData[field] = null; + } else { + // otherwise reject + throw err; + } + } else { + // unknown error + throw err; + } + } } } @@ -469,7 +495,7 @@ export class PolicyUtil { }; // build a reversed query for fetching entities affected by nested updates - const buildReversedQuery = async (context: VisitorContext) => { + const buildReversedQuery = async (context: NestedWriteVisitorContext) => { let result, currQuery: any; let currField: FieldInfo | undefined; @@ -514,7 +540,7 @@ export class PolicyUtil { }; // args processor for update/upsert - const processUpdate = async (model: string, where: any, context: VisitorContext) => { + const processUpdate = async (model: string, where: any, context: NestedWriteVisitorContext) => { const preGuard = this.getAuthGuard(model, 'update'); if (preGuard === false) { throw this.deniedByPolicy(model, 'update'); @@ -566,7 +592,7 @@ export class PolicyUtil { }; // args processor for updateMany - const processUpdateMany = async (model: string, args: any, context: VisitorContext) => { + const processUpdateMany = async (model: string, args: any, context: NestedWriteVisitorContext) => { const guard = this.getAuthGuard(model, 'update'); if (guard === false) { throw this.deniedByPolicy(model, 'update'); @@ -580,7 +606,7 @@ export class PolicyUtil { // for models with post-update rules, we need to read and store // entity values before the update for post-update check - const preparePostUpdateCheck = async (model: string, context: VisitorContext) => { + const preparePostUpdateCheck = async (model: string, context: NestedWriteVisitorContext) => { const postGuard = this.getAuthGuard(model, 'postUpdate'); const schema = this.getModelSchema(model); @@ -616,7 +642,7 @@ export class PolicyUtil { }; // args processor for delete - const processDelete = async (model: string, args: any, context: VisitorContext) => { + const processDelete = async (model: string, args: any, context: NestedWriteVisitorContext) => { const guard = this.getAuthGuard(model, 'delete'); if (guard === false) { throw this.deniedByPolicy(model, 'delete'); @@ -632,7 +658,7 @@ export class PolicyUtil { }; // process relation updates: connect, connectOrCreate, and disconnect - const processRelationUpdate = async (model: string, args: any, context: VisitorContext) => { + const processRelationUpdate = async (model: string, args: any, context: NestedWriteVisitorContext) => { // CHECK ME: equire the entity being connected readable? // await this.checkPolicyForFilter(model, args, 'read', this.db); @@ -772,7 +798,7 @@ export class PolicyUtil { return prismaClientKnownRequestError( this.db, `denied by policy: ${model} entities failed '${operation}' check${extra ? ', ' + extra : ''}`, - { clientVersion: getVersion(), code: 'P2004', meta: { reason } } + { clientVersion: getVersion(), code: PrismaErrorCode.CONSTRAINED_FAILED, meta: { reason } } ); } @@ -864,7 +890,12 @@ export class PolicyUtil { if (this.logger.enabled('info')) { this.logger.info(`entity ${model} failed schema check for operation ${operation}: ${error}`); } - throw this.deniedByPolicy(model, operation, `entities failed schema check: [${error}]`); + throw this.deniedByPolicy( + model, + operation, + `entities failed schema check: [${error}]`, + CrudFailureReason.DATA_VALIDATION_VIOLATION + ); } } else { // count entities with policy injected and see if any of them are filtered out diff --git a/packages/runtime/src/enhancements/utils.ts b/packages/runtime/src/enhancements/utils.ts index 0b7f5921e..bbe85a5ce 100644 --- a/packages/runtime/src/enhancements/utils.ts +++ b/packages/runtime/src/enhancements/utils.ts @@ -60,16 +60,37 @@ let _PrismaClientUnknownRequestError: new (...args: unknown[]) => Error; function loadPrismaModule(prisma: any) { // https://github.com/prisma/prisma/discussions/17832 if (prisma._engineConfig?.datamodelPath) { + // try engine path first const loadPath = path.dirname(prisma._engineConfig.datamodelPath); try { const _prisma = require(loadPath).Prisma; - if (typeof _prisma !== 'undefined') return _prisma; - return require('@prisma/client/runtime'); + if (typeof _prisma !== 'undefined') { + return _prisma; + } } catch { - return require('@prisma/client/runtime'); + // noop } - } else { + } + + try { + // Prisma v4 return require('@prisma/client/runtime'); + } catch { + try { + // Prisma v5 + return require('@prisma/client'); + } catch (err) { + if (process.env.ZENSTACK_TEST === '1') { + // running in test, try cwd + try { + return require(path.join(process.cwd(), 'node_modules/@prisma/client/runtime')); + } catch { + return require(path.join(process.cwd(), 'node_modules/@prisma/client')); + } + } else { + throw err; + } + } } } diff --git a/packages/runtime/src/enhancements/where-visitor.ts b/packages/runtime/src/enhancements/where-visitor.ts new file mode 100644 index 000000000..bb806c29d --- /dev/null +++ b/packages/runtime/src/enhancements/where-visitor.ts @@ -0,0 +1,102 @@ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import { FieldInfo } from '../types'; +import { resolveField } from './model-meta'; +import { ModelMeta } from './types'; +import { enumerate } from './utils'; + +/** + * Context for visiting + */ +export type WhereVisitorContext = { + /** + * Parent data, can be used to replace fields + */ + parent: any; + + /** + * Current field, undefined if toplevel + */ + field?: FieldInfo; +}; + +/** + * WhereVisitor's callback actions + */ +export type WhereVisitorCallback = { + field?: (field: FieldInfo, data: any) => Promise; +}; + +const FILTER_OPERATORS = [ + 'equals', + 'not', + 'in', + 'notIn', + 'lt', + 'lte', + 'gt', + 'gte', + 'contains', + 'search', + 'startsWith', + 'endsWith', +]; + +const RELATION_FILTER_OPERATORS = ['is', 'isNot', 'some', 'every', 'none']; + +/** + * Recursive visitor for where payload + */ +export class WhereVisitor { + constructor(private readonly modelMeta: ModelMeta, private readonly callback: WhereVisitorCallback) {} + + /** + * Start visiting + */ + async visit(model: string, where: any): Promise { + if (!where) { + return; + } + + for (const [k, v] of Object.entries(where)) { + if (['AND', 'OR', 'NOT'].includes(k)) { + for (const item of enumerate(v)) { + await this.visit(model, item); + } + continue; + } + + if (RELATION_FILTER_OPERATORS.includes(k)) { + // visit into filter body + await this.visit(model, v); + continue; + } + + const field = resolveField(this.modelMeta, model, k); + if (!field) { + continue; + } + + if (typeof v === 'object') { + const filterOp = Object.keys(v).find((f) => FILTER_OPERATORS.includes(f)); + if (filterOp) { + // reach into filter value + const newValue = await this.callback.field?.(field, v[filterOp]); + v[filterOp] = newValue; + continue; + } + + if (Object.keys(v).some((f) => RELATION_FILTER_OPERATORS.includes(f))) { + // filter payload + await this.visit(field.type, v); + continue; + } + } + + // scalar field + const newValue = await this.callback.field?.(field, v); + where[k] = newValue; + } + } +} diff --git a/packages/runtime/src/index.ts b/packages/runtime/src/index.ts index a3554d2d5..080d229a4 100644 --- a/packages/runtime/src/index.ts +++ b/packages/runtime/src/index.ts @@ -1,5 +1,5 @@ +export * from './constants'; export * from './enhancements'; -export * from './enhancements/policy'; +export * from './error'; export * from './types'; export * from './validation'; -export * from './error'; diff --git a/packages/runtime/src/utils/serialization-utils.ts b/packages/runtime/src/utils/serialization-utils.ts deleted file mode 100644 index 15442900b..000000000 --- a/packages/runtime/src/utils/serialization-utils.ts +++ /dev/null @@ -1,21 +0,0 @@ -import Decimal from 'decimal.js'; -import superjson from 'superjson'; - -export function registerSerializers() { - superjson.registerCustom( - { - isApplicable: (v): v is Buffer => Buffer.isBuffer(v), - serialize: (v) => JSON.stringify(v.toJSON().data), - deserialize: (v) => Buffer.from(JSON.parse(v)), - }, - 'Buffer' - ); - superjson.registerCustom( - { - isApplicable: (v): v is Decimal => Decimal.isDecimal(v), - serialize: (v) => v.toJSON(), - deserialize: (v) => new Decimal(v), - }, - 'decimal.js' - ); -} diff --git a/packages/runtime/tsconfig.json b/packages/runtime/tsconfig.json index f6dff1942..acc4bc58e 100644 --- a/packages/runtime/tsconfig.json +++ b/packages/runtime/tsconfig.json @@ -18,5 +18,5 @@ "paths": {} }, "include": ["src/**/*.ts"], - "exclude": ["dist", "node_modules"] + "exclude": ["src/browser"] } diff --git a/packages/runtime/tsup.config.ts b/packages/runtime/tsup.config.ts new file mode 100644 index 000000000..9689884ca --- /dev/null +++ b/packages/runtime/tsup.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from 'tsup'; + +export default defineConfig({ + entry: ['src/browser/index.ts'], + outDir: 'dist/browser', + splitting: false, + sourcemap: true, + clean: true, + dts: true, + format: ['cjs', 'esm'], +}); diff --git a/packages/schema/package.json b/packages/schema/package.json index 65fa06d80..4e36c4399 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -3,7 +3,7 @@ "publisher": "zenstack", "displayName": "ZenStack Language Tools", "description": "A toolkit for building secure CRUD apps with Next.js + Typescript", - "version": "1.0.0-beta.8", + "version": "1.0.0-beta.9", "author": { "name": "ZenStack Team" }, @@ -80,8 +80,7 @@ }, "dependencies": { "@paralleldrive/cuid2": "^2.2.0", - "@prisma/generator-helper": "4.10.0", - "@prisma/internals": "4.10.0", + "@prisma/generator-helper": "^5.0.0", "@zenstackhq/language": "workspace:*", "@zenstackhq/sdk": "workspace:*", "async-exit-hook": "^2.0.1", @@ -114,13 +113,11 @@ "devDependencies": { "@types/async-exit-hook": "^2.0.0", "@types/jest": "^29.5.0", - "@types/lower-case-first": "^1.0.1", - "@types/node": "^14.18.32", + "@types/node": "^18.0.0", "@types/pluralize": "^0.0.29", "@types/semver": "^7.3.13", "@types/strip-color": "^0.1.0", "@types/tmp": "^0.2.3", - "@types/upper-case-first": "^1.1.2", "@types/uuid": "^8.3.4", "@types/vscode": "^1.56.0", "@typescript-eslint/eslint-plugin": "^5.42.0", @@ -134,7 +131,6 @@ "eslint": "^8.27.0", "eslint-plugin-jest": "^27.1.7", "jest": "^29.5.0", - "prisma": "^4.0.0", "renamer": "^4.0.0", "rimraf": "^3.0.2", "tmp": "^0.2.1", diff --git a/packages/schema/src/cli/plugin-runner.ts b/packages/schema/src/cli/plugin-runner.ts index 59559e0f7..96819cdfb 100644 --- a/packages/schema/src/cli/plugin-runner.ts +++ b/packages/schema/src/cli/plugin-runner.ts @@ -1,10 +1,10 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-var-requires */ import type { DMMF } from '@prisma/generator-helper'; -import { getDMMF } from '@prisma/internals'; import { isPlugin, Plugin } from '@zenstackhq/language/ast'; import { getDataModels, + getDMMF, getLiteral, getLiteralArray, hasValidationAttributes, @@ -99,24 +99,35 @@ export class PluginRunner { } // make sure prerequisites are included - const corePlugins = ['@core/prisma', '@core/model-meta', '@core/access-policy']; + const corePlugins: Array<{ provider: string; options?: Record }> = [ + { provider: '@core/prisma' }, + { provider: '@core/model-meta' }, + { provider: '@core/access-policy' }, + ]; if (getDataModels(context.schema).some((model) => hasValidationAttributes(model))) { // '@core/zod' plugin is auto-enabled if there're validation rules - corePlugins.push('@core/zod'); + corePlugins.push({ provider: '@core/zod', options: { modelOnly: true } }); } - // core dependencies introduced by dependencies + // core plugins introduced by dependencies plugins .flatMap((p) => p.dependencies) .forEach((dep) => { - if (dep.startsWith('@core/') && !corePlugins.includes(dep)) { - corePlugins.push(dep); + if (dep.startsWith('@core/')) { + const existing = corePlugins.find((p) => p.provider === dep); + if (existing) { + // reset options to default + existing.options = undefined; + } else { + // add core dependency + corePlugins.push({ provider: dep }); + } } }); for (const corePlugin of corePlugins.reverse()) { - const existingIdx = plugins.findIndex((p) => p.provider === corePlugin); + const existingIdx = plugins.findIndex((p) => p.provider === corePlugin.provider); if (existingIdx >= 0) { // shift the plugin to the front const existing = plugins[existingIdx]; @@ -124,13 +135,13 @@ export class PluginRunner { plugins.unshift(existing); } else { // synthesize a plugin and insert front - const pluginModule = require(this.getPluginModulePath(corePlugin)); - const pluginName = this.getPluginName(pluginModule, corePlugin); + const pluginModule = require(this.getPluginModulePath(corePlugin.provider)); + const pluginName = this.getPluginName(pluginModule, corePlugin.provider); plugins.unshift({ name: pluginName, - provider: corePlugin, + provider: corePlugin.provider, dependencies: [], - options: { schemaPath: context.schemaPath, name: pluginName }, + options: { schemaPath: context.schemaPath, name: pluginName, ...corePlugin.options }, run: pluginModule.default, module: pluginModule, }); @@ -154,7 +165,9 @@ export class PluginRunner { let dmmf: DMMF.Document | undefined = undefined; for (const { name, provider, run, options } of plugins) { + // const start = Date.now(); await this.runPlugin(name, run, context, options, dmmf, warnings); + // console.log(`✅ Plugin ${colors.bold(name)} (${provider}) completed in ${Date.now() - start}ms`); if (provider === '@core/prisma') { // load prisma DMMF dmmf = await getDMMF({ diff --git a/packages/schema/src/language-server/validator/datamodel-validator.ts b/packages/schema/src/language-server/validator/datamodel-validator.ts index 65804a31c..a4329e44d 100644 --- a/packages/schema/src/language-server/validator/datamodel-validator.ts +++ b/packages/schema/src/language-server/validator/datamodel-validator.ts @@ -6,7 +6,7 @@ import { isLiteralExpr, ReferenceExpr, } from '@zenstackhq/language/ast'; -import { analyzePolicies, getIdFields, getLiteral } from '@zenstackhq/sdk'; +import { analyzePolicies, getModelIdFields, getModelUniqueFields, getLiteral } from '@zenstackhq/sdk'; import { AstNode, DiagnosticInfo, getDocument, ValidationAcceptor } from 'langium'; import { IssueCodes, SCALAR_TYPES } from '../constants'; import { AstValidator } from '../types'; @@ -26,16 +26,29 @@ export default class DataModelValidator implements AstValidator { private validateFields(dm: DataModel, accept: ValidationAcceptor) { const idFields = dm.$resolvedFields.filter((f) => f.attributes.find((attr) => attr.decl.ref?.name === '@id')); - const modelLevelIds = getIdFields(dm); - - if (idFields.length === 0 && modelLevelIds.length === 0) { + const uniqueFields = dm.$resolvedFields.filter((f) => + f.attributes.find((attr) => attr.decl.ref?.name === '@unique') + ); + const modelLevelIds = getModelIdFields(dm); + const modelUniqueFields = getModelUniqueFields(dm); + + if ( + idFields.length === 0 && + modelLevelIds.length === 0 && + uniqueFields.length === 0 && + modelUniqueFields.length === 0 + ) { const { allows, denies, hasFieldValidation } = analyzePolicies(dm); if (allows.length > 0 || denies.length > 0 || hasFieldValidation) { // TODO: relax this requirement to require only @unique fields // when access policies or field valdaition is used, require an @id field - accept('error', 'Model must include a field with @id attribute or a model-level @@id attribute', { - node: dm, - }); + accept( + 'error', + 'Model must include a field with @id or @unique attribute, or a model-level @@id or @@unique attribute to use access policies', + { + node: dm, + } + ); } } else if (idFields.length > 0 && modelLevelIds.length > 0) { accept('error', 'Model cannot have both field-level @id and model-level @@id attributes', { diff --git a/packages/schema/src/language-server/validator/expression-validator.ts b/packages/schema/src/language-server/validator/expression-validator.ts index 18c826158..63960996d 100644 --- a/packages/schema/src/language-server/validator/expression-validator.ts +++ b/packages/schema/src/language-server/validator/expression-validator.ts @@ -1,4 +1,4 @@ -import { BinaryExpr, Expression, isBinaryExpr, isEnum } from '@zenstackhq/language/ast'; +import { BinaryExpr, Expression, ExpressionType, isBinaryExpr, isEnum } from '@zenstackhq/language/ast'; import { ValidationAcceptor } from 'langium'; import { isAuthInvocation } from '../../utils/ast-utils'; import { AstValidator } from '../types'; @@ -48,6 +48,51 @@ export default class ExpressionValidator implements AstValidator { } break; } + + case '>': + case '>=': + case '<': + case '<=': + case '&&': + case '||': { + let supportedShapes: ExpressionType[]; + if (['>', '>=', '<', '<='].includes(expr.operator)) { + supportedShapes = ['Int', 'Float', 'DateTime', 'Any']; + } else { + supportedShapes = ['Boolean', 'Any']; + } + + if ( + typeof expr.left.$resolvedType?.decl !== 'string' || + !supportedShapes.includes(expr.left.$resolvedType.decl) + ) { + accept('error', `invalid operand type for "${expr.operator}" operator`, { + node: expr.left, + }); + return; + } + if ( + typeof expr.right.$resolvedType?.decl !== 'string' || + !supportedShapes.includes(expr.right.$resolvedType.decl) + ) { + accept('error', `invalid operand type for "${expr.operator}" operator`, { + node: expr.right, + }); + return; + } + + // DateTime comparison is only allowed between two DateTime values + if (expr.left.$resolvedType.decl === 'DateTime' && expr.right.$resolvedType.decl !== 'DateTime') { + accept('error', 'incompatible operand types', { node: expr }); + } else if ( + expr.right.$resolvedType.decl === 'DateTime' && + expr.left.$resolvedType.decl !== 'DateTime' + ) { + accept('error', 'incompatible operand types', { node: expr }); + } + + break; + } } } diff --git a/packages/schema/src/language-server/zmodel-linker.ts b/packages/schema/src/language-server/zmodel-linker.ts index 5326ff6cc..4a8557bdd 100644 --- a/packages/schema/src/language-server/zmodel-linker.ts +++ b/packages/schema/src/language-server/zmodel-linker.ts @@ -215,7 +215,13 @@ export class ZModelLinker extends DefaultLinker { private resolveUnary(node: UnaryExpr, document: LangiumDocument, extraScopes: ScopeProvider[]) { this.resolve(node.operand, document, extraScopes); - node.$resolvedType = node.operand.$resolvedType; + switch (node.operator) { + case '!': + this.resolveToBuiltinTypeOrDecl(node, 'Boolean'); + break; + default: + throw Error(`Unsupported unary operator: ${node.operator}`); + } } private resolveObject(node: ObjectExpr, document: LangiumDocument, extraScopes: ScopeProvider[]) { diff --git a/packages/schema/src/plugins/prisma/prisma-builder.ts b/packages/schema/src/plugins/prisma/prisma-builder.ts index 4b8665d51..92ecb377a 100644 --- a/packages/schema/src/plugins/prisma/prisma-builder.ts +++ b/packages/schema/src/plugins/prisma/prisma-builder.ts @@ -35,7 +35,13 @@ export class PrismaModel { } addModel(name: string): Model { - const model = new Model(name); + const model = new Model(name, false); + this.models.push(model); + return model; + } + + addView(name: string): Model { + const model = new Model(name, true); this.models.push(model); return model; } @@ -127,7 +133,7 @@ export class FieldDeclaration extends DeclarationBase { export class Model extends ContainerDeclaration { public fields: ModelField[] = []; - constructor(public name: string, documentations: string[] = []) { + constructor(public name: string, public isView: boolean, documentations: string[] = []) { super(documentations); } @@ -164,7 +170,7 @@ export class Model extends ContainerDeclaration { result.push(...this.attributes); return ( super.toString() + - `model ${this.name} {\n` + + `${this.isView ? 'view' : 'model'} ${this.name} {\n` + indentString(result.map((d) => d.toString()).join('\n')) + `\n}` ); diff --git a/packages/schema/src/plugins/prisma/schema-generator.ts b/packages/schema/src/plugins/prisma/schema-generator.ts index 81c01f874..c3f899219 100644 --- a/packages/schema/src/plugins/prisma/schema-generator.ts +++ b/packages/schema/src/plugins/prisma/schema-generator.ts @@ -1,4 +1,3 @@ -import { getDMMF } from '@prisma/internals'; import { ArrayExpr, AstNode, @@ -24,8 +23,10 @@ import { import { analyzePolicies, getDataModels, + getDMMF, getLiteral, getLiteralArray, + getPrismaVersion, GUARD_FIELD_NAME, PluginError, PluginOptions, @@ -237,15 +238,6 @@ export default class PrismaSchemaGenerator { } } - private getPrismaVersion() { - try { - // eslint-disable-next-line @typescript-eslint/no-var-requires - return require('@prisma/client/package.json').version; - } catch { - return undefined; - } - } - private generateGenerator(prisma: PrismaModel, decl: GeneratorDecl) { const generator = prisma.addGenerator( decl.name, @@ -258,7 +250,7 @@ export default class PrismaSchemaGenerator { // deal with configuring PrismaClient preview features const provider = generator.fields.find((f) => f.name === 'provider'); if (provider?.value === 'prisma-client-js') { - const prismaVersion = this.getPrismaVersion(); + const prismaVersion = getPrismaVersion(); if (prismaVersion && semver.lt(prismaVersion, '4.7.0')) { // insert interactiveTransactions preview feature let previewFeatures = generator.fields.find((f) => f.name === 'previewFeatures'); @@ -277,7 +269,7 @@ export default class PrismaSchemaGenerator { } private generateModel(prisma: PrismaModel, decl: DataModel, config?: Record) { - const model = prisma.addModel(decl.name); + const model = decl.isView ? prisma.addView(decl.name) : prisma.addModel(decl.name); for (const field of decl.fields) { this.generateModelField(model, field); } @@ -336,6 +328,10 @@ export default class PrismaSchemaGenerator { } private shouldGenerateAuxFields(decl: DataModel) { + if (decl.isView) { + return false; + } + const { allowAll, denyAll, hasFieldValidation } = analyzePolicies(decl); if (!allowAll && !denyAll) { diff --git a/packages/schema/src/plugins/zod/generator.ts b/packages/schema/src/plugins/zod/generator.ts index 08734dc0c..5b9838b52 100644 --- a/packages/schema/src/plugins/zod/generator.ts +++ b/packages/schema/src/plugins/zod/generator.ts @@ -1,5 +1,4 @@ import { ConnectorType, DMMF } from '@prisma/generator-helper'; -import { Dictionary } from '@prisma/internals'; import { AUXILIARY_FIELDS, PluginOptions, @@ -15,11 +14,7 @@ import { saveProject, } from '@zenstackhq/sdk'; import { DataModel, DataSource, EnumField, Model, isDataModel, isDataSource, isEnum } from '@zenstackhq/sdk/ast'; -import { - AggregateOperationSupport, - addMissingInputObjectTypes, - resolveAggregateOperationSupport, -} from '@zenstackhq/sdk/dmmf-helpers'; +import { addMissingInputObjectTypes, resolveAggregateOperationSupport } from '@zenstackhq/sdk/dmmf-helpers'; import { promises as fs } from 'fs'; import { streamAllContents } from 'langium'; import path from 'path'; @@ -53,6 +48,10 @@ export async function generate(model: Model, options: PluginOptions, dmmf: DMMF. const project = createProject(); + // common schemas + await generateCommonSchemas(project, output); + + // enums await generateEnumSchemas( prismaClientDmmf.schema.enumTypes.prisma, prismaClientDmmf.schema.enumTypes.model ?? [], @@ -66,18 +65,34 @@ export async function generate(model: Model, options: PluginOptions, dmmf: DMMF. dataSource?.fields.find((f) => f.name === 'provider')?.value ) as ConnectorType; - Transformer.provider = dataSourceProvider; - - const generatorConfigOptions: Dictionary = {}; - Object.entries(options).forEach(([k, v]) => (generatorConfigOptions[k] = v as string)); - - addMissingInputObjectTypes(inputObjectTypes, outputObjectTypes, models); - - const aggregateOperationSupport = resolveAggregateOperationSupport(inputObjectTypes); + await generateModelSchemas(project, model, output); + + if (options.modelOnly !== true) { + // detailed object schemas referenced from input schemas + Transformer.provider = dataSourceProvider; + addMissingInputObjectTypes(inputObjectTypes, outputObjectTypes, models); + const aggregateOperationSupport = resolveAggregateOperationSupport(inputObjectTypes); + await generateObjectSchemas(inputObjectTypes, project, output, model); + + // input schemas + const transformer = new Transformer({ + models, + modelOperations, + aggregateOperationSupport, + project, + zmodel: model, + }); + await transformer.generateInputSchemas(); + } - await generateObjectSchemas(inputObjectTypes, project, output, model); - await generateModelSchemas(models, modelOperations, aggregateOperationSupport, project, model, output); + // create barrel file + const exports = [`export * as models from './models'`, `export * as enums from './enums'`]; + if (options.modelOnly !== true) { + exports.push(`export * as input from './input'`, `export * as objects from './objects'`); + } + project.createSourceFile(path.join(output, 'index.ts'), exports.join(';\n'), { overwrite: true }); + // emit const shouldCompile = options.compile !== false; if (!shouldCompile || options.preserveTsFiles === true) { // save ts files @@ -97,6 +112,30 @@ async function handleGeneratorOutputValue(output: string) { Transformer.setOutputPath(output); } +async function generateCommonSchemas(project: Project, output: string) { + // Decimal + project.createSourceFile( + path.join(output, 'common', 'index.ts'), + ` +import { z } from 'zod'; +export const DecimalSchema = z.union([z.number(), z.string(), z.object({d: z.number().array(), e: z.number(), s: z.number()})]); + +// https://stackoverflow.com/a/54487392/20415796 +type OmitDistributive = T extends any ? (T extends object ? OmitRecursively : T) : never; +type OmitRecursively = Omit< + { [P in keyof T]: OmitDistributive }, + K +>; + +/** + * Strips auxiliary fields recursively + */ +export type Purge = OmitRecursively "'" + f + "'").join('|')}>; +`, + { overwrite: true } + ); +} + async function generateEnumSchemas( prismaSchemaEnum: DMMF.SchemaEnum[], modelSchemaEnum: DMMF.SchemaEnum[], @@ -135,23 +174,7 @@ async function generateObjectSchemas( ); } -async function generateModelSchemas( - models: DMMF.Model[], - modelOperations: DMMF.ModelMapping[], - aggregateOperationSupport: AggregateOperationSupport, - project: Project, - zmodel: Model, - output: string -) { - const transformer = new Transformer({ - models, - modelOperations, - aggregateOperationSupport, - project, - zmodel, - }); - await transformer.generateInputSchemas(); - +async function generateModelSchemas(project: Project, zmodel: Model, output: string) { const schemaNames: string[] = []; for (const dm of getDataModels(zmodel)) { schemaNames.push(await generateModelSchema(dm, project, output)); @@ -162,16 +185,6 @@ async function generateModelSchemas( schemaNames.map((name) => `export * from './${name}';`).join('\n'), { overwrite: true } ); - - project.createSourceFile( - path.join(output, 'index.ts'), - `export * as input from './input'; - export * as models from './models'; - export * as objects from './objects'; - export * as enums from './enums'; - `, - { overwrite: true } - ); } async function generateModelSchema(model: DataModel, project: Project, output: string) { @@ -214,6 +227,11 @@ async function generateModelSchema(model: DataModel, project: Project, output: s } } + // import Decimal + if (fields.some((field) => field.type.type === 'Decimal')) { + writer.writeLine(`import { DecimalSchema } from '../common';`); + } + // create base schema writer.write(`const baseSchema = z.object(`); writer.inlineBlock(() => { diff --git a/packages/schema/src/plugins/zod/index.ts b/packages/schema/src/plugins/zod/index.ts index aee2371d4..80d454533 100644 --- a/packages/schema/src/plugins/zod/index.ts +++ b/packages/schema/src/plugins/zod/index.ts @@ -1,4 +1,4 @@ -import { DMMF } from '@prisma/generator-helper'; +import type { DMMF } from '@prisma/generator-helper'; import { PluginOptions } from '@zenstackhq/sdk'; import { Model } from '@zenstackhq/sdk/ast'; import { generate } from './generator'; diff --git a/packages/schema/src/plugins/zod/transformer.ts b/packages/schema/src/plugins/zod/transformer.ts index 5017adbb6..5471a843a 100644 --- a/packages/schema/src/plugins/zod/transformer.ts +++ b/packages/schema/src/plugins/zod/transformer.ts @@ -1,13 +1,14 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ import type { DMMF as PrismaDMMF } from '@prisma/generator-helper'; import { Model } from '@zenstackhq/language/ast'; -import { AUXILIARY_FIELDS, getPrismaClientImportSpec } from '@zenstackhq/sdk'; +import { AUXILIARY_FIELDS, getPrismaClientImportSpec, getPrismaVersion } from '@zenstackhq/sdk'; import { checkModelHasModelRelation, findModelByName, isAggregateInputType } from '@zenstackhq/sdk/dmmf-helpers'; import indentString from '@zenstackhq/sdk/utils'; import path from 'path'; import { Project } from 'ts-morph'; import { upperCaseFirst } from 'upper-case-first'; import { AggregateOperationSupport, TransformerParams } from './types'; +import * as semver from 'semver'; export default class Transformer { name: string; @@ -23,6 +24,7 @@ export default class Transformer { static provider: string; private static outputPath = './generated'; private hasJson = false; + private hasDecimal = false; private project: Project; private zmodel: Model; @@ -110,8 +112,11 @@ export default class Transformer { let alternatives = lines.reduce((result, inputType) => { if (inputType.type === 'String') { result.push(this.wrapWithZodValidators('z.string()', field, inputType)); - } else if (inputType.type === 'Int' || inputType.type === 'Float' || inputType.type === 'Decimal') { + } else if (inputType.type === 'Int' || inputType.type === 'Float') { result.push(this.wrapWithZodValidators('z.number()', field, inputType)); + } else if (inputType.type === 'Decimal') { + this.hasDecimal = true; + result.push(this.wrapWithZodValidators('DecimalSchema', field, inputType)); } else if (inputType.type === 'BigInt') { result.push(this.wrapWithZodValidators('z.bigint()', field, inputType)); } else if (inputType.type === 'Boolean') { @@ -119,16 +124,23 @@ export default class Transformer { } else if (inputType.type === 'DateTime') { result.push(this.wrapWithZodValidators(['z.date()', 'z.string().datetime()'], field, inputType)); } else if (inputType.type === 'Bytes') { - result.push(this.wrapWithZodValidators('z.number().array()', field, inputType)); + result.push(this.wrapWithZodValidators(`z.instanceof(Uint8Array)`, field, inputType)); } else if (inputType.type === 'Json') { this.hasJson = true; result.push(this.wrapWithZodValidators('jsonSchema', field, inputType)); } else if (inputType.type === 'True') { result.push(this.wrapWithZodValidators('z.literal(true)', field, inputType)); + } else if (inputType.type === 'Null') { + result.push(this.wrapWithZodValidators('z.null()', field, inputType)); } else { const isEnum = inputType.location === 'enumTypes'; + const isFieldRef = inputType.location === 'fieldRefTypes'; - if (inputType.namespace === 'prisma' || isEnum) { + if ( + // fieldRefTypes refer to other fields in the model and don't need to be generated as part of schema + !isFieldRef && + ('prisma' || isEnum) + ) { if (inputType.type !== this.name && typeof inputType.type === 'string') { this.addSchemaImport(inputType.type); } @@ -253,9 +265,9 @@ export default class Transformer { if (isAggregateInputType(name)) { name = `${name}Type`; } - return `export const ${this.name}ObjectSchema: z.ZodType "'" + f + "'" - ).join('|')}>> = ${schema};`; + const outType = `z.ZodType>`; + return `type SchemaType = ${outType}; +export const ${this.name}ObjectSchema: SchemaType = ${schema} as SchemaType;`; } addFinalWrappers({ zodStringFields }: { zodStringFields: string[] }) { @@ -289,6 +301,7 @@ export default class Transformer { generateObjectSchemaImportStatements() { let generatedImports = this.generateImportZodStatement(); generatedImports += this.generateSchemaImports(); + generatedImports += this.generateCommonImport(); generatedImports += '\n\n'; return generatedImports; } @@ -298,14 +311,23 @@ export default class Transformer { .map((name) => { const { isModelQueryType, modelName } = this.checkIsModelQueryType(name); if (isModelQueryType) { - return `import { ${modelName}InputSchema } from '../input/${modelName}Input.schema'`; + return `import { ${modelName}InputSchema } from '../input/${modelName}Input.schema';`; } else if (Transformer.enumNames.includes(name)) { - return `import { ${name}Schema } from '../enums/${name}.schema'`; + return `import { ${name}Schema } from '../enums/${name}.schema';`; } else { - return `import { ${name}ObjectSchema } from './${name}.schema'`; + return `import { ${name}ObjectSchema } from './${name}.schema';`; } }) - .join(';\r\n'); + .join('\n'); + } + + private generateCommonImport() { + let r = `import type { Purge } from '../common';\n`; + if (this.hasDecimal) { + r += `import { DecimalSchema } from '../common';\n`; + } + r += '\n'; + return r; } checkIsModelQueryType(type: string) { @@ -326,7 +348,7 @@ export default class Transformer { } resolveModelQuerySchemaName(modelName: string, queryName: string) { - const modelNameCapitalized = modelName.charAt(0).toUpperCase() + modelName.slice(1); + const modelNameCapitalized = upperCaseFirst(modelName); return `${modelNameCapitalized}InputSchema.${queryName}`; } @@ -502,39 +524,43 @@ export default class Transformer { } const aggregateOperations = []; + // DMMF messed up the model name casing used in the aggregate operations, - const modelNameVar = upperCaseFirst(modelName); - if (this.aggregateOperationSupport[modelNameVar]?.count) { + // AND the casing behavior varies from version to version -_-|| + const modelNameCap = upperCaseFirst(modelName); + const prismaVersion = getPrismaVersion(); + + if (this.aggregateOperationSupport[modelNameCap]?.count) { imports.push( - `import { ${modelNameVar}CountAggregateInputObjectSchema } from '../objects/${modelNameVar}CountAggregateInput.schema'` + `import { ${modelNameCap}CountAggregateInputObjectSchema } from '../objects/${modelNameCap}CountAggregateInput.schema'` ); aggregateOperations.push( - `_count: z.union([ z.literal(true), ${modelNameVar}CountAggregateInputObjectSchema ]).optional()` + `_count: z.union([ z.literal(true), ${modelNameCap}CountAggregateInputObjectSchema ]).optional()` ); } - if (this.aggregateOperationSupport[modelNameVar]?.min) { + if (this.aggregateOperationSupport[modelNameCap]?.min) { imports.push( - `import { ${modelNameVar}MinAggregateInputObjectSchema } from '../objects/${modelNameVar}MinAggregateInput.schema'` + `import { ${modelNameCap}MinAggregateInputObjectSchema } from '../objects/${modelNameCap}MinAggregateInput.schema'` ); - aggregateOperations.push(`_min: ${modelNameVar}MinAggregateInputObjectSchema.optional()`); + aggregateOperations.push(`_min: ${modelNameCap}MinAggregateInputObjectSchema.optional()`); } - if (this.aggregateOperationSupport[modelNameVar]?.max) { + if (this.aggregateOperationSupport[modelNameCap]?.max) { imports.push( - `import { ${modelNameVar}MaxAggregateInputObjectSchema } from '../objects/${modelNameVar}MaxAggregateInput.schema'` + `import { ${modelNameCap}MaxAggregateInputObjectSchema } from '../objects/${modelNameCap}MaxAggregateInput.schema'` ); - aggregateOperations.push(`_max: ${modelNameVar}MaxAggregateInputObjectSchema.optional()`); + aggregateOperations.push(`_max: ${modelNameCap}MaxAggregateInputObjectSchema.optional()`); } - if (this.aggregateOperationSupport[modelNameVar]?.avg) { + if (this.aggregateOperationSupport[modelNameCap]?.avg) { imports.push( - `import { ${modelNameVar}AvgAggregateInputObjectSchema } from '../objects/${modelNameVar}AvgAggregateInput.schema'` + `import { ${modelNameCap}AvgAggregateInputObjectSchema } from '../objects/${modelNameCap}AvgAggregateInput.schema'` ); - aggregateOperations.push(`_avg: ${modelNameVar}AvgAggregateInputObjectSchema.optional()`); + aggregateOperations.push(`_avg: ${modelNameCap}AvgAggregateInputObjectSchema.optional()`); } - if (this.aggregateOperationSupport[modelNameVar]?.sum) { + if (this.aggregateOperationSupport[modelNameCap]?.sum) { imports.push( - `import { ${modelNameVar}SumAggregateInputObjectSchema } from '../objects/${modelNameVar}SumAggregateInput.schema'` + `import { ${modelNameCap}SumAggregateInputObjectSchema } from '../objects/${modelNameCap}SumAggregateInput.schema'` ); - aggregateOperations.push(`_sum: ${modelNameVar}SumAggregateInputObjectSchema.optional()`); + aggregateOperations.push(`_sum: ${modelNameCap}SumAggregateInputObjectSchema.optional()`); } if (aggregate) { @@ -547,7 +573,7 @@ export default class Transformer { codeBody += `aggregate: z.object({ where: ${modelName}WhereInputObjectSchema.optional(), orderBy: z.union([${modelName}OrderByWithRelationInputObjectSchema, ${modelName}OrderByWithRelationInputObjectSchema.array()]).optional(), cursor: ${modelName}WhereUniqueInputObjectSchema.optional(), take: z.number().optional(), skip: z.number().optional(), ${aggregateOperations.join( ', ' )} }),`; - operations.push(['aggregate', modelNameVar]); + operations.push(['aggregate', modelNameCap]); } if (groupBy) { @@ -555,14 +581,18 @@ export default class Transformer { `import { ${modelName}WhereInputObjectSchema } from '../objects/${modelName}WhereInput.schema'`, `import { ${modelName}OrderByWithAggregationInputObjectSchema } from '../objects/${modelName}OrderByWithAggregationInput.schema'`, `import { ${modelName}ScalarWhereWithAggregatesInputObjectSchema } from '../objects/${modelName}ScalarWhereWithAggregatesInput.schema'`, - `import { ${upperCaseFirst(modelName)}ScalarFieldEnumSchema } from '../enums/${upperCaseFirst( - modelName - )}ScalarFieldEnum.schema'` + `import { ${modelNameCap}ScalarFieldEnumSchema } from '../enums/${modelNameCap}ScalarFieldEnum.schema'` ); codeBody += `groupBy: z.object({ where: ${modelName}WhereInputObjectSchema.optional(), orderBy: z.union([${modelName}OrderByWithAggregationInputObjectSchema, ${modelName}OrderByWithAggregationInputObjectSchema.array()]).optional(), having: ${modelName}ScalarWhereWithAggregatesInputObjectSchema.optional(), take: z.number().optional(), skip: z.number().optional(), by: z.array(${upperCaseFirst( modelName )}ScalarFieldEnumSchema), ${aggregateOperations.join(', ')} }),`; - operations.push(['groupBy', modelNameVar]); + + if (prismaVersion && semver.gte(prismaVersion, '5.0.0')) { + // Prisma V5 has a different casing for this guy ... + operations.push(['groupBy', modelName]); + } else { + operations.push(['groupBy', modelNameCap]); + } } imports = [...new Set(imports)]; @@ -578,9 +608,9 @@ ${operations .join(',\n')} } - export const ${modelName}InputSchema: ${modelName}InputSchemaType = { + export const ${modelName}InputSchema = { ${indentString(codeBody, 4)} - }; + } as ${modelName}InputSchemaType; `; this.project.createSourceFile(filePath, content, { overwrite: true }); diff --git a/packages/schema/src/plugins/zod/utils/schema-gen.ts b/packages/schema/src/plugins/zod/utils/schema-gen.ts index 78a720549..34f53083d 100644 --- a/packages/schema/src/plugins/zod/utils/schema-gen.ts +++ b/packages/schema/src/plugins/zod/utils/schema-gen.ts @@ -114,9 +114,11 @@ function makeZodSchema(field: DataModelField) { switch (field.type.type) { case 'Int': case 'Float': - case 'Decimal': schema = 'z.number()'; break; + case 'Decimal': + schema = 'DecimalSchema'; + break; case 'BigInt': schema = 'z.bigint()'; break; @@ -130,7 +132,7 @@ function makeZodSchema(field: DataModelField) { schema = 'z.date()'; break; case 'Bytes': - schema = 'z.number().array()'; + schema = 'z.union([z.string(), z.instanceof(Uint8Array)])'; break; default: schema = 'z.any()'; diff --git a/packages/schema/src/telemetry.ts b/packages/schema/src/telemetry.ts index 2db8eb3ae..b07484629 100644 --- a/packages/schema/src/telemetry.ts +++ b/packages/schema/src/telemetry.ts @@ -8,6 +8,7 @@ import sleep from 'sleep-promise'; import { CliError } from './cli/cli-error'; import { TELEMETRY_TRACKING_TOKEN } from './constants'; import { getVersion } from './utils/version-utils'; +import { getPrismaVersion } from '@zenstackhq/sdk'; /** * Telemetry events @@ -34,6 +35,7 @@ export class Telemetry { private readonly sessionid = createId(); private readonly _os = os.platform(); private readonly version = getVersion(); + private readonly prismaVersion = getPrismaVersion(); private exitWait = 200; constructor() { @@ -90,6 +92,7 @@ export class Telemetry { $os: this._os, nodeVersion: process.version, version: this.version, + prismaVersion: this.prismaVersion, ...properties, }; this.mixpanel.track(event, payload); diff --git a/packages/schema/tests/generator/prisma-builder.test.ts b/packages/schema/tests/generator/prisma-builder.test.ts index 56f9d090b..c3badf6f1 100644 --- a/packages/schema/tests/generator/prisma-builder.test.ts +++ b/packages/schema/tests/generator/prisma-builder.test.ts @@ -1,4 +1,4 @@ -import { getDMMF } from '@prisma/internals'; +import { getDMMF } from '@zenstackhq/sdk'; import { AttributeArg, AttributeArgValue, diff --git a/packages/schema/tests/generator/prisma-generator.test.ts b/packages/schema/tests/generator/prisma-generator.test.ts index 9ed524fa7..80c67567e 100644 --- a/packages/schema/tests/generator/prisma-generator.test.ts +++ b/packages/schema/tests/generator/prisma-generator.test.ts @@ -1,9 +1,9 @@ /// -import { getDMMF } from '@prisma/internals'; +import { getDMMF } from '@zenstackhq/sdk'; import fs from 'fs'; -import tmp from 'tmp'; import path from 'path'; +import tmp from 'tmp'; import { loadDocument } from '../../src/cli/cli-util'; import PrismaSchemaGenerator from '../../src/plugins/prisma/schema-generator'; import { loadModel } from '../utils'; @@ -523,4 +523,38 @@ describe('Prisma generator test', () => { expect(post?.fields.map((f) => f.name)).toContain('zenstack_guard'); expect(post?.fields.map((f) => f.name)).toContain('zenstack_transaction'); }); + + it('view support', async () => { + const model = await loadModel(` + datasource db { + provider = 'postgresql' + url = env('URL') + } + + generator client { + provider = "prisma-client-js" + previewFeatures = ["views"] + } + + view UserInfo { + id Int @unique + email String + name String + bio String + } + `); + + const { name } = tmp.fileSync({ postfix: '.prisma' }); + await new PrismaSchemaGenerator().generate(model, { + name: 'Prisma', + provider: '@core/prisma', + schemaPath: 'schema.zmodel', + output: name, + format: false, + generateClient: false, + }); + + const content = fs.readFileSync(name, 'utf-8'); + await getDMMF({ datamodel: content }); + }); }); diff --git a/packages/schema/tests/schema/parser.test.ts b/packages/schema/tests/schema/parser.test.ts index c9230ae1f..49dd5b2ff 100644 --- a/packages/schema/tests/schema/parser.test.ts +++ b/packages/schema/tests/schema/parser.test.ts @@ -1,4 +1,6 @@ /* eslint-disable @typescript-eslint/ban-types */ +/// + import { ArrayExpr, AttributeArg, @@ -509,4 +511,17 @@ describe('Parsing Tests', () => { `; await loadModel(content, false); }); + + it('view support', async () => { + const content = ` + view UserInfo { + id Int @unique + email String + name String + bio String + } + `; + const doc = await loadModel(content, false); + expect((doc.declarations[0] as DataModel).isView).toBeTruthy(); + }); }); diff --git a/packages/schema/tests/schema/trigger-dev.test.ts b/packages/schema/tests/schema/trigger-dev.test.ts new file mode 100644 index 000000000..c712ad25d --- /dev/null +++ b/packages/schema/tests/schema/trigger-dev.test.ts @@ -0,0 +1,12 @@ +import * as fs from 'fs'; +import path from 'path'; +import { loadModel } from '../utils'; + +describe('Trigger.dev Schema Tests', () => { + it('model loading', async () => { + const content = fs.readFileSync(path.join(__dirname, './trigger-dev.zmodel'), { + encoding: 'utf-8', + }); + await loadModel(content); + }); +}); diff --git a/packages/schema/tests/schema/trigger-dev.zmodel b/packages/schema/tests/schema/trigger-dev.zmodel new file mode 100644 index 000000000..67be17825 --- /dev/null +++ b/packages/schema/tests/schema/trigger-dev.zmodel @@ -0,0 +1,1039 @@ +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} + +generator client { + provider = "prisma-client-js" + binaryTargets = ["native", "debian-openssl-1.1.x"] +} + +model User { + id String @id @default(cuid()) + email String @unique + + authenticationMethod AuthenticationMethod + accessToken String? + authenticationProfile Json? + authenticationExtraParams Json? + authIdentifier String? @unique + + displayName String? + name String? + avatarUrl String? + + admin Boolean @default(false) + isOnCloudWaitlist Boolean @default(false) + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + featureCloud Boolean @default(false) + isOnHostedRepoWaitlist Boolean @default(false) + + marketingEmails Boolean @default(true) + confirmedBasicDetails Boolean @default(false) + + orgMemberships OrgMember[] + sentInvites OrgMemberInvite[] + apiVotes ApiIntegrationVote[] + + invitationCode InvitationCode? @relation(fields: [invitationCodeId], references: [id]) + invitationCodeId String? +} + +model InvitationCode { + id String @id @default(cuid()) + code String @unique + + users User[] + + createdAt DateTime @default(now()) +} + +enum AuthenticationMethod { + GITHUB + MAGIC_LINK +} + +model Organization { + id String @id @default(cuid()) + slug String @unique + title String + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + environments RuntimeEnvironment[] + connections IntegrationConnection[] + endpoints Endpoint[] + jobs Job[] + jobVersions JobVersion[] + events EventRecord[] + jobRuns JobRun[] + + projects Project[] + members OrgMember[] + invites OrgMemberInvite[] + externalAccounts ExternalAccount[] + integrations Integration[] + sources TriggerSource[] +} + +model ExternalAccount { + id String @id @default(cuid()) + identifier String + metadata Json? + + organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade, onUpdate: Cascade) + organizationId String + + environment RuntimeEnvironment @relation(fields: [environmentId], references: [id], onDelete: Cascade, onUpdate: Cascade) + environmentId String + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + connections IntegrationConnection[] + events EventRecord[] + runs JobRun[] + schedules ScheduleSource[] + triggerSources TriggerSource[] + missingConnections MissingConnection[] + + @@unique([environmentId, identifier]) +} + +// This is a "global" table that store all the integration methods for all the integrations across all orgs +model IntegrationAuthMethod { + id String @id @default(cuid()) + key String + + name String + description String + type String + + client Json? + config Json? + scopes Json? + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + integrations Integration[] + + definition IntegrationDefinition @relation(fields: [definitionId], references: [id], onDelete: Cascade, onUpdate: Cascade) + definitionId String + + help Json? + + @@unique([definitionId, key]) +} + +model IntegrationDefinition { + id String @id + name String + instructions String? + description String? + packageName String @default("") + + authMethods IntegrationAuthMethod[] + Integration Integration[] +} + +model Integration { + id String @id @default(cuid()) + + slug String + + title String? + description String? + + setupStatus IntegrationSetupStatus @default(COMPLETE) + authSource IntegrationAuthSource @default(HOSTED) + + definition IntegrationDefinition @relation(fields: [definitionId], references: [id], onDelete: Cascade, onUpdate: Cascade) + definitionId String + + authMethod IntegrationAuthMethod? @relation(fields: [authMethodId], references: [id], onDelete: Cascade, onUpdate: Cascade) + authMethodId String? + + connectionType ConnectionType @default(DEVELOPER) + + scopes String[] + + customClientReference SecretReference? @relation(fields: [customClientReferenceId], references: [id], onDelete: Cascade, onUpdate: Cascade) + customClientReferenceId String? + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade, onUpdate: Cascade) + organizationId String + + attempts ConnectionAttempt[] + connections IntegrationConnection[] + jobIntegrations JobIntegration[] + sources TriggerSource[] + missingConnections MissingConnection[] + RunConnection RunConnection[] + + @@unique([organizationId, slug]) +} + +enum IntegrationAuthSource { + HOSTED + LOCAL +} + +enum IntegrationSetupStatus { + MISSING_FIELDS + COMPLETE +} + +model IntegrationConnection { + id String @id @default(cuid()) + + connectionType ConnectionType @default(DEVELOPER) + + expiresAt DateTime? + metadata Json + scopes String[] + + dataReference SecretReference @relation(fields: [dataReferenceId], references: [id], onDelete: Cascade, onUpdate: Cascade) + dataReferenceId String + + integration Integration @relation(fields: [integrationId], references: [id], onDelete: Cascade, onUpdate: Cascade) + integrationId String + + organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade, onUpdate: Cascade) + organizationId String + + externalAccount ExternalAccount? @relation(fields: [externalAccountId], references: [id], onDelete: Cascade, onUpdate: Cascade) + externalAccountId String? + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + runConnections RunConnection[] +} + +enum ConnectionType { + EXTERNAL + DEVELOPER +} + +model ConnectionAttempt { + id String @id @default(cuid()) + + securityCode String? + + redirectTo String @default("/") + + createdAt DateTime @default(now()) + updatedAt DateTime @default(now()) @updatedAt + + integration Integration @relation(fields: [integrationId], references: [id]) + integrationId String +} + +model OrgMember { + id String @id @default(cuid()) + + organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade, onUpdate: Cascade) + organizationId String + + user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade) + userId String + + role OrgMemberRole @default(MEMBER) + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + environments RuntimeEnvironment[] + + @@unique([organizationId, userId]) +} + +enum OrgMemberRole { + ADMIN + MEMBER +} + +model OrgMemberInvite { + id String @id @default(cuid()) + token String @unique @default(cuid()) + email String + role OrgMemberRole @default(MEMBER) + + organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade, onUpdate: Cascade) + organizationId String + + inviter User @relation(fields: [inviterId], references: [id], onDelete: Cascade, onUpdate: Cascade) + inviterId String + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@unique([organizationId, email]) +} + +model RuntimeEnvironment { + id String @id @default(cuid()) + slug String + apiKey String @unique + pkApiKey String? + + type RuntimeEnvironmentType @default(DEVELOPMENT) + + autoEnableInternalSources Boolean @default(true) + + organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade, onUpdate: Cascade) + organizationId String + + project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade) + projectId String + + //when the org member is deleted, it will keep the environment but set it to null + orgMember OrgMember? @relation(fields: [orgMemberId], references: [id], onDelete: SetNull, onUpdate: Cascade) + orgMemberId String? + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + endpoints Endpoint[] + jobVersions JobVersion[] + events EventRecord[] + jobRuns JobRun[] + requestDeliveries HttpSourceRequestDelivery[] + jobAliases JobAlias[] + JobQueue JobQueue[] + sources TriggerSource[] + eventDispatchers EventDispatcher[] + scheduleSources ScheduleSource[] + ExternalAccount ExternalAccount[] + + @@unique([projectId, slug, orgMemberId]) +} + +enum RuntimeEnvironmentType { + PRODUCTION + STAGING + DEVELOPMENT + PREVIEW +} + +model Project { + id String @id @default(cuid()) + slug String @unique + name String + + organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade, onUpdate: Cascade) + organizationId String + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + environments RuntimeEnvironment[] + endpoints Endpoint[] + jobs Job[] + jobVersion JobVersion[] + events EventRecord[] + runs JobRun[] + sources TriggerSource[] +} + +model Endpoint { + id String @id @default(cuid()) + slug String + url String + + environment RuntimeEnvironment @relation(fields: [environmentId], references: [id], onDelete: Cascade, onUpdate: Cascade) + environmentId String + + organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade, onUpdate: Cascade) + organizationId String + + project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade) + projectId String + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + indexingHookIdentifier String? + + jobVersions JobVersion[] + jobRuns JobRun[] + httpRequestDeliveries HttpSourceRequestDelivery[] + dynamictriggers DynamicTrigger[] + sources TriggerSource[] + indexings EndpointIndex[] + + @@unique([environmentId, slug]) +} + +model EndpointIndex { + id String @id @default(cuid()) + + endpoint Endpoint @relation(fields: [endpointId], references: [id], onDelete: Cascade, onUpdate: Cascade) + endpointId String + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + source EndpointIndexSource @default(MANUAL) + sourceData Json? + reason String? + + data Json + stats Json +} + +enum EndpointIndexSource { + MANUAL + API + INTERNAL + HOOK +} + +model Job { + id String @id @default(cuid()) + slug String + title String + internal Boolean @default(false) + + organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade, onUpdate: Cascade) + organizationId String + + project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade) + projectId String + + versions JobVersion[] + runs JobRun[] + integrations JobIntegration[] + aliases JobAlias[] + dynamicTriggers DynamicTrigger[] + + createdAt DateTime @default(now()) + updatedAt DateTime @default(now()) @updatedAt + + @@unique([projectId, slug]) +} + +model JobVersion { + id String @id @default(cuid()) + version String + eventSpecification Json + + properties Json? + + job Job @relation(fields: [jobId], references: [id], onDelete: Cascade, onUpdate: Cascade) + jobId String + + endpoint Endpoint @relation(fields: [endpointId], references: [id], onDelete: Cascade, onUpdate: Cascade) + endpointId String + + environment RuntimeEnvironment @relation(fields: [environmentId], references: [id], onDelete: Cascade, onUpdate: Cascade) + environmentId String + + organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade, onUpdate: Cascade) + organizationId String + + project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade) + projectId String + + queue JobQueue @relation(fields: [queueId], references: [id]) + queueId String + + startPosition JobStartPosition @default(INITIAL) + preprocessRuns Boolean @default(false) + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + runs JobRun[] + integrations JobIntegration[] + aliases JobAlias[] + examples EventExample[] + dynamicTriggers DynamicTrigger[] + triggerSources TriggerSource[] + + @@unique([jobId, version, environmentId]) +} + +model EventExample { + id String @id @default(cuid()) + + slug String + name String + icon String? + + payload Json? + + jobVersion JobVersion @relation(fields: [jobVersionId], references: [id], onDelete: Cascade, onUpdate: Cascade) + jobVersionId String + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@unique([slug, jobVersionId]) +} + +model JobQueue { + id String @id @default(cuid()) + name String + + environment RuntimeEnvironment @relation(fields: [environmentId], references: [id], onDelete: Cascade, onUpdate: Cascade) + environmentId String + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + jobCount Int @default(0) + maxJobs Int @default(100) + + runs JobRun[] + jobVersion JobVersion[] + + @@unique([environmentId, name]) +} + +model JobAlias { + id String @id @default(cuid()) + name String @default("latest") + value String + + version JobVersion @relation(fields: [versionId], references: [id], onDelete: Cascade, onUpdate: Cascade) + versionId String + + job Job @relation(fields: [jobId], references: [id], onDelete: Cascade, onUpdate: Cascade) + jobId String + + environment RuntimeEnvironment @relation(fields: [environmentId], references: [id], onDelete: Cascade, onUpdate: Cascade) + environmentId String + + @@unique([jobId, environmentId, name]) +} + +model JobIntegration { + id String @id @default(cuid()) + key String + + version JobVersion @relation(fields: [versionId], references: [id], onDelete: Cascade, onUpdate: Cascade) + versionId String + + job Job @relation(fields: [jobId], references: [id], onDelete: Cascade, onUpdate: Cascade) + jobId String + + integration Integration @relation(fields: [integrationId], references: [id], onDelete: Cascade, onUpdate: Cascade) + integrationId String + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@unique([versionId, key]) +} + +model RunConnection { + id String @id @default(cuid()) + key String + + authSource IntegrationAuthSource @default(HOSTED) + + run JobRun @relation(fields: [runId], references: [id], onDelete: Cascade, onUpdate: Cascade) + runId String + + connection IntegrationConnection? @relation(fields: [connectionId], references: [id], onDelete: Cascade, onUpdate: Cascade) + connectionId String? + + integration Integration @relation(fields: [integrationId], references: [id], onDelete: Cascade, onUpdate: Cascade) + integrationId String + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + tasks Task[] + + @@unique([runId, key]) +} + +model DynamicTrigger { + id String @id @default(cuid()) + type DynamicTriggerType @default(EVENT) + slug String + + endpoint Endpoint @relation(fields: [endpointId], references: [id], onDelete: Cascade, onUpdate: Cascade) + endpointId String + + jobs Job[] + sources TriggerSource[] + registrations DynamicTriggerRegistration[] + + sourceRegistrationJob JobVersion? @relation(fields: [sourceRegistrationJobId], references: [id], onDelete: Cascade, onUpdate: Cascade) + sourceRegistrationJobId String? + + @@unique([endpointId, slug, type]) +} + +enum DynamicTriggerType { + EVENT + SCHEDULE +} + +model EventDispatcher { + id String @id @default(cuid()) + event String + source String + payloadFilter Json? + contextFilter Json? + manual Boolean @default(false) + + dispatchableId String + dispatchable Json + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + enabled Boolean @default(true) + + environment RuntimeEnvironment @relation(fields: [environmentId], references: [id], onDelete: Cascade, onUpdate: Cascade) + environmentId String + + registrations DynamicTriggerRegistration[] + scheduleSources ScheduleSource[] + + @@unique([dispatchableId, environmentId]) +} + +enum JobStartPosition { + INITIAL + LATEST +} + +model EventRecord { + id String @id @default(cuid()) + eventId String + name String + timestamp DateTime @default(now()) + payload Json + context Json? + sourceContext Json? + + source String @default("trigger.dev") + + organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade, onUpdate: Cascade) + organizationId String + + environment RuntimeEnvironment @relation(fields: [environmentId], references: [id], onDelete: Cascade, onUpdate: Cascade) + environmentId String + + project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade) + projectId String + + externalAccount ExternalAccount? @relation(fields: [externalAccountId], references: [id], onDelete: Cascade, onUpdate: Cascade) + externalAccountId String? + + deliverAt DateTime @default(now()) + deliveredAt DateTime? + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + isTest Boolean @default(false) + runs JobRun[] + + @@unique([eventId, environmentId]) +} + +model JobRun { + id String @id @default(cuid()) + number Int + + job Job @relation(fields: [jobId], references: [id], onDelete: Cascade, onUpdate: Cascade) + jobId String + + version JobVersion @relation(fields: [versionId], references: [id], onDelete: Cascade, onUpdate: Cascade) + versionId String + + event EventRecord @relation(fields: [eventId], references: [id], onDelete: Cascade, onUpdate: Cascade) + eventId String + + organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade, onUpdate: Cascade) + organizationId String + + endpoint Endpoint @relation(fields: [endpointId], references: [id], onDelete: Cascade, onUpdate: Cascade) + endpointId String + + environment RuntimeEnvironment @relation(fields: [environmentId], references: [id], onDelete: Cascade, onUpdate: Cascade) + environmentId String + + project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade) + projectId String + + queue JobQueue @relation(fields: [queueId], references: [id]) + queueId String + + externalAccount ExternalAccount? @relation(fields: [externalAccountId], references: [id], onDelete: Cascade, onUpdate: Cascade) + externalAccountId String? + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + queuedAt DateTime? + startedAt DateTime? + completedAt DateTime? + + properties Json? + + status JobRunStatus @default(PENDING) + output Json? + + timedOutAt DateTime? + timedOutReason String? + + isTest Boolean @default(false) + preprocess Boolean @default(false) + + tasks Task[] + runConnections RunConnection[] + missingConnections MissingConnection[] + executions JobRunExecution[] +} + +enum JobRunStatus { + PENDING + QUEUED + WAITING_ON_CONNECTIONS + PREPROCESSING + STARTED + SUCCESS + FAILURE + TIMED_OUT + ABORTED +} + +model JobRunExecution { + id String @id @default(cuid()) + + run JobRun @relation(fields: [runId], references: [id], onDelete: Cascade, onUpdate: Cascade) + runId String + + retryCount Int @default(0) + retryLimit Int @default(0) + retryDelayInMs Int @default(0) + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + startedAt DateTime? + completedAt DateTime? + + error String? + + reason JobRunExecutionReason @default(EXECUTE_JOB) + status JobRunExecutionStatus @default(PENDING) + + resumeTask Task? @relation(fields: [resumeTaskId], references: [id], onDelete: Cascade, onUpdate: Cascade) + resumeTaskId String? + + graphileJobId String? +} + +enum JobRunExecutionReason { + PREPROCESS + EXECUTE_JOB +} + +enum JobRunExecutionStatus { + PENDING + STARTED + SUCCESS + FAILURE +} + +model Task { + id String @id + idempotencyKey String + displayKey String? + name String + icon String? + + status TaskStatus @default(PENDING) + delayUntil DateTime? + noop Boolean @default(false) + + description String? + properties Json? + outputProperties Json? + params Json? + output Json? + error String? + redact Json? + style Json? + operation String? + + startedAt DateTime? + completedAt DateTime? + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + run JobRun @relation(fields: [runId], references: [id], onDelete: Cascade, onUpdate: Cascade) + runId String + + parent Task? @relation("TaskParent", fields: [parentId], references: [id], onDelete: Cascade, onUpdate: Cascade) + parentId String? + + runConnection RunConnection? @relation(fields: [runConnectionId], references: [id], onDelete: Cascade, onUpdate: Cascade) + runConnectionId String? + + children Task[] @relation("TaskParent") + executions JobRunExecution[] + attempts TaskAttempt[] + + @@unique([runId, idempotencyKey]) +} + +enum TaskStatus { + PENDING + WAITING + RUNNING + COMPLETED + ERRORED +} + +model TaskAttempt { + id String @id @default(cuid()) + + number Int + + task Task @relation(fields: [taskId], references: [id], onDelete: Cascade, onUpdate: Cascade) + taskId String + + status TaskAttemptStatus @default(PENDING) + + error String? + + runAt DateTime? + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@unique([taskId, number]) +} + +enum TaskAttemptStatus { + PENDING + STARTED + COMPLETED + ERRORED +} + +model SecretReference { + id String @id @default(cuid()) + key String @unique + provider SecretStoreProvider @default(DATABASE) + + connections IntegrationConnection[] + integrations Integration[] + triggerSources TriggerSource[] + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} + +enum SecretStoreProvider { + DATABASE + AWS_PARAM_STORE +} + +/// Used when the provider = "database". Not recommended outside of local development. +model SecretStore { + key String @unique + value Json + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} + +model TriggerSource { + id String @id @default(cuid()) + + key String + params Json? + + channel TriggerChannel @default(HTTP) + channelData Json? + + events TriggerSourceEvent[] + + secretReference SecretReference @relation(fields: [secretReferenceId], references: [id], onDelete: Cascade, onUpdate: Cascade) + secretReferenceId String + + organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade, onUpdate: Cascade) + organizationId String + + environment RuntimeEnvironment @relation(fields: [environmentId], references: [id], onDelete: Cascade, onUpdate: Cascade) + environmentId String + + endpoint Endpoint @relation(fields: [endpointId], references: [id], onDelete: Cascade, onUpdate: Cascade) + endpointId String + + project Project @relation(fields: [projectId], references: [id], onDelete: Cascade, onUpdate: Cascade) + projectId String + + integration Integration @relation(fields: [integrationId], references: [id], onDelete: Cascade, onUpdate: Cascade) + integrationId String + + dynamicTrigger DynamicTrigger? @relation(fields: [dynamicTriggerId], references: [id], onDelete: Cascade, onUpdate: Cascade) + dynamicTriggerId String? + + externalAccount ExternalAccount? @relation(fields: [externalAccountId], references: [id], onDelete: Cascade, onUpdate: Cascade) + externalAccountId String? + + sourceRegistrationJob JobVersion? @relation(fields: [sourceRegistrationJobId], references: [id], onDelete: Cascade, onUpdate: Cascade) + sourceRegistrationJobId String? + + dynamicSourceId String? + dynamicSourceMetadata Json? + + active Boolean @default(false) + interactive Boolean @default(false) + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + httpDeliveries HttpSourceRequestDelivery[] + registrations DynamicTriggerRegistration[] + + @@unique([key, environmentId]) +} + +enum TriggerChannel { + HTTP + SQS + SMTP +} + +model TriggerSourceEvent { + id String @id @default(cuid()) + name String + + source TriggerSource @relation(fields: [sourceId], references: [id], onDelete: Cascade, onUpdate: Cascade) + sourceId String + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + registered Boolean @default(false) + + @@unique([name, sourceId]) +} + +model DynamicTriggerRegistration { + id String @id @default(cuid()) + + key String + + dynamicTrigger DynamicTrigger @relation(fields: [dynamicTriggerId], references: [id], onDelete: Cascade, onUpdate: Cascade) + dynamicTriggerId String + + eventDispatcher EventDispatcher @relation(fields: [eventDispatcherId], references: [id], onDelete: Cascade, onUpdate: Cascade) + eventDispatcherId String + + source TriggerSource @relation(fields: [sourceId], references: [id], onDelete: Cascade, onUpdate: Cascade) + sourceId String + + metadata Json? + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@unique([key, dynamicTriggerId]) +} + +model HttpSourceRequestDelivery { + id String @id @default(cuid()) + url String + method String + headers Json + body Bytes? + + source TriggerSource @relation(fields: [sourceId], references: [id], onDelete: Cascade, onUpdate: Cascade) + sourceId String + + endpoint Endpoint @relation(fields: [endpointId], references: [id], onDelete: Cascade, onUpdate: Cascade) + endpointId String + + environment RuntimeEnvironment @relation(fields: [environmentId], references: [id], onDelete: Cascade, onUpdate: Cascade) + environmentId String + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + deliveredAt DateTime? +} + +model ScheduleSource { + id String @id @default(cuid()) + + key String + schedule Json + + environment RuntimeEnvironment @relation(fields: [environmentId], references: [id], onDelete: Cascade, onUpdate: Cascade) + environmentId String + + dispatcher EventDispatcher @relation(fields: [dispatcherId], references: [id], onDelete: Cascade, onUpdate: Cascade) + dispatcherId String + + lastEventTimestamp DateTime? + + workerJobId String? + + active Boolean @default(false) + + metadata Json? + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + externalAccount ExternalAccount? @relation(fields: [externalAccountId], references: [id], onDelete: Cascade, onUpdate: Cascade) + externalAccountId String? + + @@unique([key, environmentId]) +} + +model MissingConnection { + id String @id @default(cuid()) + + resolved Boolean @default(false) + + runs JobRun[] + + integration Integration @relation(fields: [integrationId], references: [id], onDelete: Cascade, onUpdate: Cascade) + integrationId String + + connectionType ConnectionType @default(DEVELOPER) + + externalAccount ExternalAccount? @relation(fields: [externalAccountId], references: [id], onDelete: Cascade, onUpdate: Cascade) + externalAccountId String? + + accountIdentifier String? + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@unique([integrationId, connectionType, externalAccountId]) + @@unique([integrationId, connectionType, accountIdentifier]) +} + +model ApiIntegrationVote { + id String @id @default(cuid()) + + apiIdentifier String + + user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade) + userId String + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@unique([apiIdentifier, userId]) +} \ No newline at end of file diff --git a/packages/schema/tests/schema/validation/attribute-validation.test.ts b/packages/schema/tests/schema/validation/attribute-validation.test.ts index d5c5f488c..448331fd7 100644 --- a/packages/schema/tests/schema/validation/attribute-validation.test.ts +++ b/packages/schema/tests/schema/validation/attribute-validation.test.ts @@ -388,6 +388,116 @@ describe('Attribute tests', () => { ).toContain(`Value is not assignable to parameter`); }); + it('policy expressions', async () => { + await loadModel(` + ${prelude} + model A { + id String @id + x Int + x1 Int + y DateTime + y1 DateTime + z Float + z1 Decimal + foo Boolean + bar Boolean + + @@allow('all', x > 0) + @@allow('all', x > x1) + @@allow('all', y >= y1) + @@allow('all', z < z1) + @@allow('all', z1 < z) + @@allow('all', x < z) + @@allow('all', x < z1) + @@allow('all', foo && bar) + @@allow('all', foo || bar) + @@allow('all', !foo) + } + `); + + expect( + await loadModelWithError(` + ${prelude} + model A { + id String @id + x String + @@allow('all', x > 0) + } + `) + ).toContain('invalid operand type for ">" operator'); + + expect( + await loadModelWithError(` + ${prelude} + model A { + id String @id + x String + @@allow('all', x < 0) + } + `) + ).toContain('invalid operand type for "<" operator'); + + expect( + await loadModelWithError(` + ${prelude} + model A { + id String @id + x String + y String + @@allow('all', x < y) + } + `) + ).toContain('invalid operand type for "<" operator'); + + expect( + await loadModelWithError(` + ${prelude} + model A { + id String @id + x String + y String + @@allow('all', x <= y) + } + `) + ).toContain('invalid operand type for "<=" operator'); + + expect( + await loadModelWithError(` + ${prelude} + model A { + id String @id + x Int + y DateTime + @@allow('all', x <= y) + } + `) + ).toContain('incompatible operand types'); + + expect( + await loadModelWithError(` + ${prelude} + model A { + id String @id + x String + y String + @@allow('all', x && y) + } + `) + ).toContain('invalid operand type for "&&" operator'); + + expect( + await loadModelWithError(` + ${prelude} + model A { + id String @id + x String + y String + @@allow('all', x || y) + } + `) + ).toContain('invalid operand type for "||" operator'); + }); + it('policy filter function check', async () => { await loadModel(` ${prelude} diff --git a/packages/schema/tests/schema/validation/datamodel-validation.test.ts b/packages/schema/tests/schema/validation/datamodel-validation.test.ts index daa7c381e..a2d68f2c0 100644 --- a/packages/schema/tests/schema/validation/datamodel-validation.test.ts +++ b/packages/schema/tests/schema/validation/datamodel-validation.test.ts @@ -128,6 +128,9 @@ describe('Data Model Validation Tests', () => { } `); + const err = + 'Model must include a field with @id or @unique attribute, or a model-level @@id or @@unique attribute to use access policies'; + expect( await loadModelWithError(` ${prelude} @@ -136,7 +139,27 @@ describe('Data Model Validation Tests', () => { @@allow('all', x > 0) } `) - ).toContain(`Model must include a field with @id attribute or a model-level @@id attribute`); + ).toContain(err); + + // @unique used as id + await loadModel(` + ${prelude} + model M { + id Int @unique + x Int + @@allow('all', x > 0) + } + `); + + // @@unique used as id + await loadModel(` + ${prelude} + model M { + x Int + @@unique([x]) + @@allow('all', x > 0) + } + `); expect( await loadModelWithError(` @@ -146,7 +169,7 @@ describe('Data Model Validation Tests', () => { @@deny('all', x <= 0) } `) - ).toContain(`Model must include a field with @id attribute or a model-level @@id attribute`); + ).toContain(err); expect( await loadModelWithError(` @@ -155,7 +178,7 @@ describe('Data Model Validation Tests', () => { x Int @gt(0) } `) - ).toContain(`Model must include a field with @id attribute or a model-level @@id attribute`); + ).toContain(err); expect( await loadModelWithError(` diff --git a/packages/sdk/package.json b/packages/sdk/package.json index ae76e2eab..f920d76b5 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/sdk", - "version": "1.0.0-beta.8", + "version": "1.0.0-beta.9", "description": "ZenStack plugin development SDK", "main": "index.js", "scripts": { @@ -19,13 +19,17 @@ "author": "", "license": "MIT", "dependencies": { - "@prisma/generator-helper": "4.10.0", + "@prisma/generator-helper": "^5.0.0", + "@prisma/internals": "4.10.0", + "@prisma/internals-v5": "npm:@prisma/internals@^5.0.0", "@zenstackhq/language": "workspace:*", "@zenstackhq/runtime": "workspace:*", "prettier": "^2.8.3", + "semver": "^7.3.8", "ts-morph": "^16.0.0" }, "devDependencies": { + "@types/semver": "^7.3.13", "copyfiles": "^2.4.1", "rimraf": "^3.0.2", "typescript": "^4.9.4" diff --git a/packages/sdk/src/constants.ts b/packages/sdk/src/constants.ts index b1d8d7693..bba0ab93b 100644 --- a/packages/sdk/src/constants.ts +++ b/packages/sdk/src/constants.ts @@ -3,12 +3,7 @@ */ export const RUNTIME_PACKAGE = '@zenstackhq/runtime'; -export { - AUXILIARY_FIELDS, - GUARD_FIELD_NAME, - TRANSACTION_FIELD_NAME, - CrudFailureReason, -} from '@zenstackhq/runtime/constants'; +export { AUXILIARY_FIELDS, GUARD_FIELD_NAME, TRANSACTION_FIELD_NAME, CrudFailureReason } from '@zenstackhq/runtime'; /** * Expression context diff --git a/packages/sdk/src/dmmf-helpers/aggregate-helpers.ts b/packages/sdk/src/dmmf-helpers/aggregate-helpers.ts index cdc1973e6..e2a2c05fa 100644 --- a/packages/sdk/src/dmmf-helpers/aggregate-helpers.ts +++ b/packages/sdk/src/dmmf-helpers/aggregate-helpers.ts @@ -1,4 +1,4 @@ -import { DMMF } from '@prisma/generator-helper'; +import type { DMMF } from '@prisma/generator-helper'; import { AggregateOperationSupport } from './types'; const isAggregateOutputType = (name: string) => /(?:Count|Avg|Sum|Min|Max)AggregateOutputType$/.test(name); diff --git a/packages/sdk/src/dmmf-helpers/include-helpers.ts b/packages/sdk/src/dmmf-helpers/include-helpers.ts index ddb5047d0..2f9bbf478 100644 --- a/packages/sdk/src/dmmf-helpers/include-helpers.ts +++ b/packages/sdk/src/dmmf-helpers/include-helpers.ts @@ -1,4 +1,4 @@ -import { DMMF } from '@prisma/generator-helper'; +import type { DMMF } from '@prisma/generator-helper'; import { checkIsModelRelationField, checkModelHasModelRelation, checkModelHasManyModelRelation } from './model-helpers'; export function addMissingInputObjectTypesForInclude(inputObjectTypes: DMMF.InputType[], models: DMMF.Model[]) { diff --git a/packages/sdk/src/dmmf-helpers/missing-types-helper.ts b/packages/sdk/src/dmmf-helpers/missing-types-helper.ts index 8a6b553e4..e88f56db4 100644 --- a/packages/sdk/src/dmmf-helpers/missing-types-helper.ts +++ b/packages/sdk/src/dmmf-helpers/missing-types-helper.ts @@ -1,4 +1,4 @@ -import { DMMF } from '@prisma/generator-helper'; +import type { DMMF } from '@prisma/generator-helper'; import { addMissingInputObjectTypesForAggregate } from './aggregate-helpers'; import { addMissingInputObjectTypesForInclude } from './include-helpers'; import { addMissingInputObjectTypesForModelArgs } from './modelArgs-helpers'; diff --git a/packages/sdk/src/dmmf-helpers/model-helpers.ts b/packages/sdk/src/dmmf-helpers/model-helpers.ts index 255638bd8..902bd5401 100644 --- a/packages/sdk/src/dmmf-helpers/model-helpers.ts +++ b/packages/sdk/src/dmmf-helpers/model-helpers.ts @@ -1,4 +1,4 @@ -import { DMMF } from '@prisma/generator-helper'; +import type { DMMF } from '@prisma/generator-helper'; export function checkModelHasModelRelation(model: DMMF.Model) { const { fields: modelFields } = model; diff --git a/packages/sdk/src/dmmf-helpers/modelArgs-helpers.ts b/packages/sdk/src/dmmf-helpers/modelArgs-helpers.ts index 9b90fbaf9..549dec3ab 100644 --- a/packages/sdk/src/dmmf-helpers/modelArgs-helpers.ts +++ b/packages/sdk/src/dmmf-helpers/modelArgs-helpers.ts @@ -1,4 +1,4 @@ -import { DMMF } from '@prisma/generator-helper'; +import type { DMMF } from '@prisma/generator-helper'; import { checkModelHasModelRelation } from './model-helpers'; export function addMissingInputObjectTypesForModelArgs(inputObjectTypes: DMMF.InputType[], models: DMMF.Model[]) { diff --git a/packages/sdk/src/dmmf-helpers/select-helpers.ts b/packages/sdk/src/dmmf-helpers/select-helpers.ts index 691bf0269..36403e61a 100644 --- a/packages/sdk/src/dmmf-helpers/select-helpers.ts +++ b/packages/sdk/src/dmmf-helpers/select-helpers.ts @@ -1,4 +1,4 @@ -import { DMMF } from '@prisma/generator-helper'; +import type { DMMF } from '@prisma/generator-helper'; import { checkIsModelRelationField, checkModelHasManyModelRelation } from './model-helpers'; export function addMissingInputObjectTypesForSelect( diff --git a/packages/sdk/src/prisma.ts b/packages/sdk/src/prisma.ts index 8558facdd..7130eafd7 100644 --- a/packages/sdk/src/prisma.ts +++ b/packages/sdk/src/prisma.ts @@ -1,6 +1,10 @@ +import type { DMMF } from '@prisma/generator-helper'; +import { getDMMF as getDMMF4 } from '@prisma/internals'; +import { getDMMF as getDMMF5 } from '@prisma/internals-v5'; +import path from 'path'; +import * as semver from 'semver'; import { GeneratorDecl, Model, Plugin, isGeneratorDecl, isPlugin } from './ast'; import { getLiteral } from './utils'; -import path from 'path'; /** * Given a ZModel and an import context directory, compute the import spec for the Prisma Client. @@ -54,5 +58,48 @@ export function getPrismaClientImportSpec(model: Model, importingFromDir: string // console.log('IMPORTING PATH:', importingFromDir); // compute prisma client absolute output dir relative to the importing file - return path.relative(importingFromDir, resolvedPrismaClientOutput); + return normalizePath(path.relative(importingFromDir, resolvedPrismaClientOutput)); +} + +function normalizePath(p: string) { + return p ? p.split(path.sep).join(path.posix.sep) : p; +} + +/** + * Gets installed Prisma version by first checking "@prisma/client" and if not available, + * "prisma". + */ +export function getPrismaVersion(): string | undefined { + try { + // eslint-disable-next-line @typescript-eslint/no-var-requires + return require('@prisma/client/package.json').version; + } catch { + try { + // eslint-disable-next-line @typescript-eslint/no-var-requires + return require('prisma/package.json').version; + } catch { + return undefined; + } + } +} + +export type GetDMMFOptions = { + datamodel?: string; + cwd?: string; + prismaPath?: string; + datamodelPath?: string; + retry?: number; + previewFeatures?: string[]; +}; + +/** + * Loads Prisma DMMF with appropriate version + */ +export function getDMMF(options: GetDMMFOptions): Promise { + const prismaVersion = getPrismaVersion(); + if (prismaVersion && semver.gte(prismaVersion, '5.0.0')) { + return getDMMF5(options); + } else { + return getDMMF4(options); + } } diff --git a/packages/sdk/src/types.ts b/packages/sdk/src/types.ts index b050d2023..b79829900 100644 --- a/packages/sdk/src/types.ts +++ b/packages/sdk/src/types.ts @@ -1,4 +1,4 @@ -import { DMMF } from '@prisma/generator-helper'; +import type { DMMF } from '@prisma/generator-helper'; import { Model } from '@zenstackhq/language/ast'; /** diff --git a/packages/sdk/src/utils.ts b/packages/sdk/src/utils.ts index edd0fa84e..fb2e7e6cf 100644 --- a/packages/sdk/src/utils.ts +++ b/packages/sdk/src/utils.ts @@ -138,9 +138,9 @@ export function isEnumFieldReference(node: AstNode): node is ReferenceExpr { } /** - * Gets id fields declared at the data model level + * Gets `@@id` fields declared at the data model level */ -export function getIdFields(model: DataModel) { +export function getModelIdFields(model: DataModel) { const idAttr = model.attributes.find((attr) => attr.decl.ref?.name === '@@id'); if (!idAttr) { return []; @@ -155,21 +155,58 @@ export function getIdFields(model: DataModel) { .map((item) => resolved(item.target) as DataModelField); } +/** + * Gets `@@unique` fields declared at the data model level + */ +export function getModelUniqueFields(model: DataModel) { + const uniqueAttr = model.attributes.find((attr) => attr.decl.ref?.name === '@@unique'); + if (!uniqueAttr) { + return []; + } + const fieldsArg = uniqueAttr.args.find((a) => a.$resolvedParam?.name === 'fields'); + if (!fieldsArg || !isArrayExpr(fieldsArg.value)) { + return []; + } + + return fieldsArg.value.items + .filter((item): item is ReferenceExpr => isReferenceExpr(item)) + .map((item) => resolved(item.target) as DataModelField); +} + /** * Returns if the given field is declared as an id field. */ export function isIdField(field: DataModelField) { // field-level @id attribute - if (field.attributes.some((attr) => attr.decl.ref?.name === '@id')) { + if (hasAttribute(field, '@id')) { return true; } - // model-level @@id attribute with a list of fields const model = field.$container as DataModel; - const modelLevelIds = getIdFields(model); + + // model-level @@id attribute with a list of fields + const modelLevelIds = getModelIdFields(model); if (modelLevelIds.includes(field)) { return true; } + + if (model.fields.some((f) => hasAttribute(f, '@id')) || modelLevelIds.length > 0) { + // the model already has id field, don't check @unique and @@unique + return false; + } + + // then, the first field with @unique can be used as id + const firstUniqueField = model.fields.find((f) => hasAttribute(f, '@unique')); + if (firstUniqueField) { + return firstUniqueField === field; + } + + // last, the first model level @@unique can be used as id + const modelLevelUnique = getModelUniqueFields(model); + if (modelLevelUnique.includes(field)) { + return true; + } + return false; } diff --git a/packages/server/package.json b/packages/server/package.json index 27c0c7939..040d6312c 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/server", - "version": "1.0.0-beta.8", + "version": "1.0.0-beta.9", "displayName": "ZenStack Server-side Adapters", "description": "ZenStack server-side adapters", "homepage": "https://zenstack.dev", @@ -9,7 +9,7 @@ "build": "pnpm lint && pnpm clean && tsc && copyfiles ./package.json ./README.md ./LICENSE dist && pnpm pack dist --pack-destination '../../../.build'", "watch": "tsc --watch", "lint": "eslint src --ext ts", - "test": "jest", + "test": "ZENSTACK_TEST=1 jest", "prepublishOnly": "pnpm build", "publish-dev": "pnpm publish --tag dev" }, @@ -40,12 +40,11 @@ "@types/body-parser": "^1.19.2", "@types/express": "^4.17.17", "@types/jest": "^29.5.0", - "@types/lower-case-first": "^1.0.1", "@types/supertest": "^2.0.12", - "@types/upper-case-first": "^1.1.2", "@zenstackhq/testtools": "workspace:*", "body-parser": "^1.20.2", "copyfiles": "^2.4.1", + "decimal.js": "^10.4.2", "express": "^4.18.2", "fastify": "^4.14.1", "fastify-plugin": "^4.5.0", diff --git a/packages/server/src/api/base.ts b/packages/server/src/api/base.ts new file mode 100644 index 000000000..d7e986b3d --- /dev/null +++ b/packages/server/src/api/base.ts @@ -0,0 +1,17 @@ +import { ModelMeta, getDefaultModelMeta } from '@zenstackhq/runtime'; + +/** + * Base class for API handlers + */ +export abstract class APIHandlerBase { + // model meta loaded from default location + protected readonly defaultModelMeta: ModelMeta | undefined; + + constructor() { + try { + this.defaultModelMeta = getDefaultModelMeta(); + } catch { + // noop + } + } +} diff --git a/packages/server/src/api/rest/index.ts b/packages/server/src/api/rest/index.ts index c800fc093..4297cc6dd 100644 --- a/packages/server/src/api/rest/index.ts +++ b/packages/server/src/api/rest/index.ts @@ -1,21 +1,24 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ +import type { ModelMeta, ZodSchemas } from '@zenstackhq/runtime'; import { DbClientContract, FieldInfo, + PrismaErrorCode, enumerate, getIdFields, isPrismaClientKnownRequestError, } from '@zenstackhq/runtime'; -import { getDefaultModelMeta } from '@zenstackhq/runtime/enhancements/model-meta'; -import type { ModelMeta } from '@zenstackhq/runtime/enhancements/types'; import { paramCase } from 'change-case'; import { lowerCaseFirst } from 'lower-case-first'; -import { DataDocument, Linker, Paginator, Relator, Serializer, SerializerOptions } from 'ts-japi'; +import SuperJSON from 'superjson'; +import { Linker, Paginator, Relator, Serializer, SerializerOptions } from 'ts-japi'; +import { upperCaseFirst } from 'upper-case-first'; import UrlPattern from 'url-pattern'; import z from 'zod'; import { fromZodError } from 'zod-validation-error'; import { LoggerConfig, RequestContext, Response } from '../../types'; -import { logWarning, stripAuxFields } from '../utils'; +import { APIHandlerBase } from '../base'; +import { logWarning, processEntityData, registerCustomSerializers } from '../utils'; const urlPatterns = { // collection operations @@ -88,10 +91,12 @@ const FilterOperations = [ type FilterOperationType = (typeof FilterOperations)[number] | undefined; +registerCustomSerializers(); + /** * RESTful-style API request handler (compliant with JSON:API) */ -class RequestHandler { +class RequestHandler extends APIHandlerBase { // resource serializers private serializers: Map; @@ -186,6 +191,7 @@ class RequestHandler { ) .optional(), }), + meta: z.object({}).passthrough().optional(), }) .strict(); @@ -202,15 +208,8 @@ class RequestHandler { // all known types and their metadata private typeMap: Record; - // model meta loaded from default location - private readonly defaultModelMeta: ModelMeta; - constructor(private readonly options: Options) { - try { - this.defaultModelMeta = getDefaultModelMeta(); - } catch { - // noop - } + super(); } async handleRequest({ @@ -221,14 +220,19 @@ class RequestHandler { requestBody, logger, modelMeta, - }: /* zodSchemas, */ - RequestContext): Promise { + zodSchemas, + }: RequestContext): Promise { + modelMeta = modelMeta ?? this.defaultModelMeta; + if (!modelMeta) { + throw new Error('Model meta is not provided or loaded from default location'); + } + if (!this.serializers) { - this.buildSerializers(modelMeta ?? this.defaultModelMeta); + this.buildSerializers(modelMeta); } if (!this.typeMap) { - this.buildTypeMap(logger, modelMeta ?? this.defaultModelMeta); + this.buildTypeMap(logger, modelMeta); } method = method.toUpperCase(); @@ -260,7 +264,7 @@ class RequestHandler { match.id, match.relationship, query, - modelMeta ?? this.defaultModelMeta + modelMeta ); } @@ -274,10 +278,14 @@ class RequestHandler { } case 'POST': { + if (!requestBody) { + return this.makeError('invalidPayload'); + } + let match = urlPatterns.collection.match(path); if (match) { // resource creation - return await this.processCreate(prisma, match.type, query, requestBody /*, zodSchemas */); + return await this.processCreate(prisma, match.type, query, requestBody, zodSchemas); } match = urlPatterns.relationship.match(path); @@ -300,16 +308,14 @@ class RequestHandler { // TODO: PUT for full update case 'PUT': case 'PATCH': { + if (!requestBody) { + return this.makeError('invalidPayload'); + } + let match = urlPatterns.single.match(path); if (match) { // resource update - return await this.processUpdate( - prisma, - match.type, - match.id, - query, - requestBody /*, zodSchemas */ - ); + return await this.processUpdate(prisma, match.type, match.id, query, requestBody, zodSchemas); } match = urlPatterns.relationship.match(path); @@ -666,41 +672,56 @@ class RequestHandler { })); } + private processRequestBody( + type: string, + requestBody: unknown, + zodSchemas: ZodSchemas | undefined, + mode: 'create' | 'update' + ) { + let body: any = requestBody; + if (body.meta?.serialization) { + // superjson deserialize body if a serialization meta is provided + body = SuperJSON.deserialize({ json: body, meta: body.meta.serialization }); + } + + const parsed = this.createUpdatePayloadSchema.parse(body); + const attributes: any = parsed.data.attributes; + + if (attributes) { + const schemaName = `${upperCaseFirst(type)}${upperCaseFirst(mode)}Schema`; + // zod-parse attributes if a schema is provided + const payloadSchema = zodSchemas?.models?.[schemaName]; + if (payloadSchema) { + const parsed = payloadSchema.safeParse(attributes); + if (!parsed.success) { + return { error: this.makeError('invalidPayload', fromZodError(parsed.error).message) }; + } + } + } + + return { attributes, relationships: parsed.data.relationships }; + } + private async processCreate( prisma: DbClientContract, type: string, _query: Record | undefined, - requestBody: unknown - // zodSchemas?: ModelZodSchema + requestBody: unknown, + zodSchemas?: ZodSchemas ): Promise { const typeInfo = this.typeMap[type]; if (!typeInfo) { return this.makeUnsupportedModelError(type); } - // zod-parse payload - const parsed = this.createUpdatePayloadSchema.safeParse(requestBody); - if (!parsed.success) { - return this.makeError('invalidPayload', fromZodError(parsed.error).message); + const { error, attributes, relationships } = this.processRequestBody(type, requestBody, zodSchemas, 'create'); + if (error) { + return error; } - const parsedPayload = parsed.data; - const createPayload: any = { data: { ...parsedPayload.data?.attributes } }; - - // TODO: we need to somehow exclude relation fields from the zod schema because relations are - // not part of "data" in the payload - // - // // zod-parse attributes if a schema is provided - // const dataSchema = zodSchemas ? getZodSchema(zodSchemas, type, 'create') : undefined; - // if (dataSchema) { - // const dataParsed = dataSchema.safeParse(createPayload); - // if (!dataParsed.success) { - // return this.makeError('invalidPayload', fromZodError(dataParsed.error).message); - // } - // } + const createPayload: any = { data: { ...attributes } }; // turn relashionship payload into Prisma connect objects - const relationships = parsedPayload.data?.relationships; if (relationships) { for (const [key, data] of Object.entries(relationships)) { if (!data?.data) { @@ -836,26 +857,18 @@ class RequestHandler { prisma: DbClientContract, type: any, resourceId: string, - query: Record | undefined, - requestBody: unknown - // zodSchemas?: ModelZodSchema + _query: Record | undefined, + requestBody: unknown, + zodSchemas?: ZodSchemas ): Promise { const typeInfo = this.typeMap[type]; if (!typeInfo) { return this.makeUnsupportedModelError(type); } - // zod-parse payload - const parsed = this.createUpdatePayloadSchema.safeParse(requestBody); - if (!parsed.success) { - return this.makeError('invalidPayload', fromZodError(parsed.error).message); - } - - const parsedPayload = parsed.data; - - const attributes = parsedPayload.data?.attributes; - if (!attributes) { - return this.makeError('invalidPayload'); + const { error, attributes, relationships } = this.processRequestBody(type, requestBody, zodSchemas, 'update'); + if (error) { + return error; } const updatePayload: any = { @@ -863,20 +876,7 @@ class RequestHandler { data: { ...attributes }, }; - // TODO: we need to somehow exclude relation fields from the zod schema because relations are - // not part of "data" in the payload - // - // // zod-parse attributes if a schema is provided - // const dataSchema = zodSchemas ? getZodSchema(zodSchemas, type, 'update') : undefined; - // if (dataSchema) { - // const dataParsed = dataSchema.safeParse(updatePayload); - // if (!dataParsed.success) { - // return this.makeError('invalidPayload', fromZodError(dataParsed.error).message); - // } - // } - // turn relationships into prisma payload - const relationships = parsedPayload.data?.relationships; if (relationships) { for (const [key, data] of Object.entries(relationships)) { if (!data?.data) { @@ -1089,20 +1089,62 @@ class RequestHandler { } } - private async serializeItems( - model: string, - items: unknown, - options?: Partial> - ): Promise>> { + private async serializeItems(model: string, items: unknown, options?: Partial>) { model = lowerCaseFirst(model); const serializer = this.serializers.get(model); if (!serializer) { throw new Error(`serializer not found for model ${model}`); } - stripAuxFields(items); + processEntityData(items); + + // serialize to JSON:API strcuture + const serialized = await serializer.serialize(items, options); + + // convert the serialization result to plain object otherwise SuperJSON won't work + const plainResult = this.toPlainObject(serialized); + + // superjson serialize the result + const { json, meta } = SuperJSON.serialize(plainResult); + + const result: any = json; + if (meta) { + result.meta = { ...result.meta, serialization: meta }; + } + + return result; + } + + private toPlainObject(data: any): any { + if (data === undefined || data === null) { + return data; + } + + if (Array.isArray(data)) { + return data.map((item: any) => this.toPlainObject(item)); + } + + if (typeof data === 'object') { + if (typeof data.toJSON === 'function') { + // custom toJSON function + return data.toJSON(); + } + const result: any = {}; + for (const [field, value] of Object.entries(data)) { + if (value === undefined || typeof value === 'function') { + // trim undefined and functions + continue; + } else if (field === 'attributes') { + // don't visit into entity data + result[field] = value; + } else { + result[field] = this.toPlainObject(value); + } + } + return result; + } - return JSON.parse(JSON.stringify(await serializer.serialize(items, options))); + return data; } private replaceURLSearchParams(url: string, params: Record) { @@ -1515,7 +1557,7 @@ class RequestHandler { private handlePrismaError(err: unknown) { if (isPrismaClientKnownRequestError(err)) { - if (err.code === 'P2004') { + if (err.code === PrismaErrorCode.CONSTRAINED_FAILED) { return this.makeError('forbidden', undefined, 403, err.meta?.reason as string); } else if (err.code === 'P2025' || err.code === 'P2018') { return this.makeError('notFound'); diff --git a/packages/server/src/api/rpc/index.ts b/packages/server/src/api/rpc/index.ts index 06050ceb6..57a9437ef 100644 --- a/packages/server/src/api/rpc/index.ts +++ b/packages/server/src/api/rpc/index.ts @@ -1,31 +1,45 @@ import { DbOperations, + PrismaErrorCode, + ZodSchemas, isPrismaClientKnownRequestError, isPrismaClientUnknownRequestError, isPrismaClientValidationError, } from '@zenstackhq/runtime'; +import SuperJSON from 'superjson'; +import { upperCaseFirst } from 'upper-case-first'; +import { fromZodError } from 'zod-validation-error'; import { RequestContext, Response } from '../../types'; -import { logError, stripAuxFields, zodValidate } from '../utils'; +import { APIHandlerBase } from '../base'; +import { logError, processEntityData, registerCustomSerializers } from '../utils'; + +registerCustomSerializers(); /** * Prisma RPC style API request handler that mirrors the Prisma Client API */ -class RequestHandler { +class RequestHandler extends APIHandlerBase { async handleRequest({ prisma, method, path, query, requestBody, + modelMeta, zodSchemas, logger, }: RequestContext): Promise { + modelMeta = modelMeta ?? this.defaultModelMeta; + if (!modelMeta) { + throw new Error('Model meta is not provided or loaded from default location'); + } + const parts = path.split('/').filter((p) => !!p); const op = parts.pop(); const model = parts.pop(); if (parts.length !== 0 || !op || !model) { - return { status: 400, body: { message: 'invalid request path' } }; + return { status: 400, body: this.makeError('invalid request path') }; } method = method.toUpperCase(); @@ -38,10 +52,13 @@ class RequestHandler { case 'createMany': case 'upsert': if (method !== 'POST') { - return { status: 400, body: { message: 'invalid request method, only POST is supported' } }; + return { + status: 400, + body: this.makeError('invalid request method, only POST is supported'), + }; } if (!requestBody) { - return { status: 400, body: { message: 'missing request body' } }; + return { status: 400, body: this.makeError('missing request body') }; } args = requestBody; @@ -57,12 +74,15 @@ class RequestHandler { case 'groupBy': case 'count': if (method !== 'GET') { - return { status: 400, body: { message: 'invalid request method, only GET is supported' } }; + return { + status: 400, + body: this.makeError('invalid request method, only GET is supported'), + }; } try { - args = query?.q ? this.unmarshal(query.q as string) : {}; + args = query?.q ? this.unmarshalQ(query.q as string, query.meta as string | undefined) : {}; } catch { - return { status: 400, body: { message: 'query param must contain valid JSON' } }; + return { status: 400, body: this.makeError('invalid "q" query parameter') }; } break; @@ -71,11 +91,11 @@ class RequestHandler { if (method !== 'PUT' && method !== 'PATCH') { return { status: 400, - body: { message: 'invalid request method, only PUT AND PATCH are supported' }, + body: this.makeError('invalid request method, only PUT AND PATCH are supported'), }; } if (!requestBody) { - return { status: 400, body: { message: 'missing request body' } }; + return { status: 400, body: this.makeError('missing request body') }; } args = requestBody; @@ -84,58 +104,75 @@ class RequestHandler { case 'delete': case 'deleteMany': if (method !== 'DELETE') { - return { status: 400, body: { message: 'invalid request method, only DELETE is supported' } }; + return { + status: 400, + body: this.makeError('invalid request method, only DELETE is supported'), + }; } try { - args = query?.q ? this.unmarshal(query.q as string) : {}; + args = query?.q ? this.unmarshalQ(query.q as string, query.meta as string | undefined) : {}; } catch { - return { status: 400, body: { message: 'query param must contain valid JSON' } }; + return { status: 400, body: this.makeError('invalid "q" query parameter') }; } break; default: - return { status: 400, body: { message: 'invalid operation: ' + op } }; + return { status: 400, body: this.makeError('invalid operation: ' + op) }; } - if (zodSchemas) { - const { data, error } = zodValidate(zodSchemas, model, dbOp, args); - if (error) { - return { status: 400, body: { message: error } }; - } else { - args = data; - } + const { error, data: parsedArgs } = await this.processRequestPayload(args, model, dbOp, zodSchemas); + if (error) { + return { status: 400, body: this.makeError(error) }; } try { if (!prisma[model]) { - return { status: 400, body: { message: `unknown model name: ${model}` } }; + return { status: 400, body: this.makeError(`unknown model name: ${model}`) }; + } + + const result = await prisma[model][dbOp](parsedArgs); + processEntityData(result); + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let response: any = { data: result }; + + // superjson serialize response + if (result) { + const { json, meta } = SuperJSON.serialize(result); + response = { data: json }; + if (meta) { + response.meta = { serialization: meta }; + } } - const result = await prisma[model][dbOp](args); - stripAuxFields(result); - return { status: resCode, body: result }; + + return { status: resCode, body: response }; } catch (err) { if (isPrismaClientKnownRequestError(err)) { logError(logger, err.code, err.message); - if (err.code === 'P2004') { + if (err.code === PrismaErrorCode.CONSTRAINED_FAILED) { // rejected by policy return { status: 403, body: { - prisma: true, - rejectedByPolicy: true, - code: err.code, - message: err.message, - reason: err.meta?.reason, + error: { + prisma: true, + rejectedByPolicy: true, + code: err.code, + message: err.message, + reason: err.meta?.reason, + }, }, }; } else { return { status: 400, body: { - prisma: true, - code: err.code, - message: err.message, - reason: err.meta?.reason, + error: { + prisma: true, + code: err.code, + message: err.message, + reason: err.meta?.reason, + }, }, }; } @@ -144,8 +181,10 @@ class RequestHandler { return { status: 400, body: { - prisma: true, - message: err.message, + error: { + prisma: true, + message: err.message, + }, }, }; } else { @@ -153,16 +192,79 @@ class RequestHandler { logError(logger, _err.message + (_err.stack ? '\n' + _err.stack : '')); return { status: 400, - body: { - message: (err as Error).message, - }, + body: this.makeError((err as Error).message), }; } } } - private unmarshal(value: string) { - return JSON.parse(value); + private makeError(message: string) { + return { error: { message: message } }; + } + + private async processRequestPayload( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + args: any, + model: string, + dbOp: string, + zodSchemas: ZodSchemas | undefined + ) { + const { meta, ...rest } = args; + if (meta?.serialization) { + // superjson deserialization + args = SuperJSON.deserialize({ json: rest, meta: meta.serialization }); + } + return this.zodValidate(zodSchemas, model, dbOp as keyof DbOperations, args); + } + + private getZodSchema(zodSchemas: ZodSchemas, model: string, operation: keyof DbOperations) { + // e.g.: UserInputSchema { findUnique: [schema] } + return zodSchemas.input?.[`${upperCaseFirst(model)}InputSchema`]?.[operation]; + } + + private zodValidate( + zodSchemas: ZodSchemas | undefined, + model: string, + operation: keyof DbOperations, + args: unknown + ) { + const zodSchema = zodSchemas && this.getZodSchema(zodSchemas, model, operation); + if (zodSchema) { + const parseResult = zodSchema.safeParse(args); + if (parseResult.success) { + return { data: args, error: undefined }; + } else { + return { data: undefined, error: fromZodError(parseResult.error).message }; + } + } else { + return { data: args, error: undefined }; + } + } + + private unmarshalQ(value: string, meta: string | undefined) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let parsedValue: any; + try { + parsedValue = JSON.parse(value); + } catch { + throw new Error('invalid "q" query parameter'); + } + + if (meta) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let parsedMeta: any; + try { + parsedMeta = JSON.parse(meta); + } catch { + throw new Error('invalid "meta" query parameter'); + } + + if (parsedMeta.serialization) { + return SuperJSON.deserialize({ json: parsedValue, meta: parsedMeta.serialization }); + } + } + + return parsedValue; } } diff --git a/packages/server/src/api/utils.ts b/packages/server/src/api/utils.ts index b3cd138f8..ba74dd2d3 100644 --- a/packages/server/src/api/utils.ts +++ b/packages/server/src/api/utils.ts @@ -1,34 +1,9 @@ -import { DbOperations } from '@zenstackhq/runtime'; -import { AUXILIARY_FIELDS } from '@zenstackhq/runtime/constants'; -import type { ZodSchemas } from '@zenstackhq/runtime/enhancements/types'; -import { upperCaseFirst } from 'upper-case-first'; -import { fromZodError } from 'zod-validation-error'; +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { AUXILIARY_FIELDS } from '@zenstackhq/runtime'; +import { Decimal } from 'decimal.js'; +import SuperJSON from 'superjson'; import { LoggerConfig } from '../types'; -export function getZodSchema(zodSchemas: ZodSchemas, model: string, operation: keyof DbOperations) { - // e.g.: UserInputSchema { findUnique: [schema] } - return zodSchemas.input?.[`${upperCaseFirst(model)}InputSchema`]?.[operation]; -} - -export function zodValidate( - zodSchemas: ZodSchemas | undefined, - model: string, - operation: keyof DbOperations, - args: unknown -) { - const zodSchema = zodSchemas && getZodSchema(zodSchemas, model, operation); - if (zodSchema) { - const parseResult = zodSchema.safeParse(args); - if (parseResult.success) { - return { data: parseResult.data, error: undefined }; - } else { - return { data: undefined, error: fromZodError(parseResult.error).message }; - } - } else { - return { data: args, error: undefined }; - } -} - export function logError(logger: LoggerConfig | undefined | null, message: string, code?: string) { if (logger === undefined) { console.error(`@zenstackhq/server: error ${code ? '[' + code + ']' : ''}, ${message}`); @@ -53,10 +28,7 @@ export function logInfo(logger: LoggerConfig | undefined | null, message: string } } -/** - * Recursively strip auxiliary fields from the given data. - */ -export function stripAuxFields(data: unknown) { +function stripAuxFields(data: unknown) { if (Array.isArray(data)) { return data.forEach(stripAuxFields); } else if (data && typeof data === 'object') { @@ -70,3 +42,35 @@ export function stripAuxFields(data: unknown) { } } } + +/** + * Processes entity data returned from Prisma call. + */ +export function processEntityData(data: any) { + if (data) { + stripAuxFields(data); + } +} + +/** + * Registers custom superjson serializers. + */ +export function registerCustomSerializers() { + SuperJSON.registerCustom( + { + isApplicable: (v): v is Decimal => Decimal.isDecimal(v), + serialize: (v) => v.toJSON(), + deserialize: (v) => new Decimal(v), + }, + 'Decimal' + ); + + SuperJSON.registerCustom( + { + isApplicable: (v): v is Buffer => Buffer.isBuffer(v), + serialize: (v) => v.toString('base64'), + deserialize: (v) => Buffer.from(v, 'base64'), + }, + 'Bytes' + ); +} diff --git a/packages/server/src/express/middleware.ts b/packages/server/src/express/middleware.ts index 492004a66..b17d3f030 100644 --- a/packages/server/src/express/middleware.ts +++ b/packages/server/src/express/middleware.ts @@ -1,10 +1,9 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ +import type { ZodSchemas } from '@zenstackhq/runtime'; import { DbClientContract } from '@zenstackhq/runtime'; import type { Handler, Request, Response } from 'express'; import RPCAPIHandler from '../api/rpc'; import { AdapterBaseOptions } from '../types'; -import { buildUrlQuery, marshalToObject, unmarshalFromObject } from '../utils'; -import type { ZodSchemas } from '@zenstackhq/runtime/enhancements/types'; /** * Express middleware options @@ -35,14 +34,19 @@ const factory = (options: MiddlewareOptions): Handler => { if (typeof options.zodSchemas === 'object') { zodSchemas = options.zodSchemas; } else if (options.zodSchemas === true) { - zodSchemas = require('@zenstackhq/runtime/zod'); - if (!zodSchemas) { + try { + zodSchemas = require('@zenstackhq/runtime/zod'); + } catch { throw new Error('Unable to load zod schemas from default location'); } } const requestHandler = options.handler || RPCAPIHandler(); - const useSuperJson = options.useSuperJson === true; + if (options.useSuperJson !== undefined) { + console.warn( + 'The option "useSuperJson" is deprecated. The server APIs automatically use superjson for serialization.' + ); + } return async (request, response, next) => { const prisma = (await options.getPrisma(request, response)) as DbClientContract; @@ -53,37 +57,22 @@ const factory = (options: MiddlewareOptions): Handler => { } if (!prisma) { - return response - .status(500) - .json(marshalToObject({ message: 'unable to get prisma from request context' }, useSuperJson)); + return response.status(500).json({ message: 'unable to get prisma from request context' }); } - let query: Record = {}; - try { - // express converts query parameters with square brackets into object - // e.g.: filter[foo]=bar is parsed to { filter: { foo: 'bar' } } - // we need to revert this behavior and reconstruct params from original URL - const url = request.protocol + '://' + request.get('host') + request.originalUrl; - const searchParams = new URL(url).searchParams; - const rawQuery: Record = {}; - for (const key of searchParams.keys()) { - const values = searchParams.getAll(key); - rawQuery[key] = values.length === 1 ? values[0] : values; - } - query = buildUrlQuery(rawQuery, useSuperJson); - } catch { - if (sendResponse === false) { - throw new Error('invalid query parameters'); - } - return response.status(400).json(marshalToObject({ message: 'invalid query parameters' }, useSuperJson)); - } + // express converts query parameters with square brackets into object + // e.g.: filter[foo]=bar is parsed to { filter: { foo: 'bar' } } + // we need to revert this behavior and reconstruct params from original URL + const url = request.protocol + '://' + request.get('host') + request.originalUrl; + const searchParams = new URL(url).searchParams; + const query = Object.fromEntries(searchParams); try { const r = await requestHandler({ method: request.method, path: request.path, query, - requestBody: unmarshalFromObject(request.body, useSuperJson), + requestBody: request.body, prisma, modelMeta: options.modelMeta, zodSchemas, @@ -97,14 +86,12 @@ const factory = (options: MiddlewareOptions): Handler => { }; return next(); } - return response.status(r.status).json(marshalToObject(r.body, useSuperJson)); + return response.status(r.status).json(r.body); } catch (err) { if (sendResponse === false) { throw err; } - return response - .status(500) - .json(marshalToObject({ message: `An unhandled error occurred: ${err}` }, useSuperJson)); + return response.status(500).json({ message: `An unhandled error occurred: ${err}` }); } }; }; diff --git a/packages/server/src/fastify/plugin.ts b/packages/server/src/fastify/plugin.ts index 7406bf944..4b86eec4b 100644 --- a/packages/server/src/fastify/plugin.ts +++ b/packages/server/src/fastify/plugin.ts @@ -1,12 +1,11 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ +import type { ZodSchemas } from '@zenstackhq/runtime'; import { DbClientContract } from '@zenstackhq/runtime'; import { FastifyPluginCallback, FastifyReply, FastifyRequest } from 'fastify'; import fp from 'fastify-plugin'; import RPCApiHandler from '../api/rpc'; import { logInfo } from '../api/utils'; import { AdapterBaseOptions } from '../types'; -import { buildUrlQuery, marshalToObject, unmarshalFromObject } from '../utils'; -import type { ZodSchemas } from '@zenstackhq/runtime/enhancements/types'; /** * Fastify plugin options @@ -41,22 +40,16 @@ const pluginHandler: FastifyPluginCallback = (fastify, options, d } const requestHanler = options.handler ?? RPCApiHandler(); - const useSuperJson = options.useSuperJson === true; + if (options.useSuperJson !== undefined) { + console.warn( + 'The option "useSuperJson" is deprecated. The server APIs automatically use superjson for serialization.' + ); + } fastify.all(`${prefix}/*`, async (request, reply) => { const prisma = (await options.getPrisma(request, reply)) as DbClientContract; if (!prisma) { - reply - .status(500) - .send(marshalToObject({ message: 'unable to get prisma from request context' }, useSuperJson)); - return; - } - - let query: Record = {}; - try { - query = buildUrlQuery(request.query, useSuperJson); - } catch { - reply.status(400).send(marshalToObject({ message: 'invalid query parameters' }, useSuperJson)); + reply.status(500).send({ message: 'unable to get prisma from request context' }); return; } @@ -64,16 +57,16 @@ const pluginHandler: FastifyPluginCallback = (fastify, options, d const response = await requestHanler({ method: request.method, path: (request.params as any)['*'], - query, - requestBody: unmarshalFromObject(request.body, useSuperJson), + query: request.query as Record, + requestBody: request.body, prisma, modelMeta: options.modelMeta, zodSchemas, logger: options.logger, }); - reply.status(response.status).send(marshalToObject(response.body, useSuperJson)); + reply.status(response.status).send(response.body); } catch (err) { - reply.status(500).send(marshalToObject({ message: `An unhandled error occurred: ${err}` }, useSuperJson)); + reply.status(500).send({ message: `An unhandled error occurred: ${err}` }); } }); diff --git a/packages/server/src/next/app-route-handler.ts b/packages/server/src/next/app-route-handler.ts index f40cae80e..58f78244f 100644 --- a/packages/server/src/next/app-route-handler.ts +++ b/packages/server/src/next/app-route-handler.ts @@ -1,11 +1,10 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ +import type { ZodSchemas } from '@zenstackhq/runtime'; import { DbClientContract } from '@zenstackhq/runtime'; -import type { ZodSchemas } from '@zenstackhq/runtime/enhancements/types'; import { NextRequest, NextResponse } from 'next/server'; import { AppRouteRequestHandlerOptions } from '.'; import RPCAPIHandler from '../api/rpc'; -import { buildUrlQuery, marshalToObject, unmarshalFromObject } from '../utils'; type Context = { params: { path: string[] } }; @@ -29,31 +28,28 @@ export default function factory( } const requestHandler = options.handler || RPCAPIHandler(); - const useSuperJson = options.useSuperJson === true; + if (options.useSuperJson !== undefined) { + console.warn( + 'The option "useSuperJson" is deprecated. The server APIs automatically use superjson for serialization.' + ); + } return async (req: NextRequest, context: Context) => { const prisma = (await options.getPrisma(req)) as DbClientContract; if (!prisma) { - return NextResponse.json( - marshalToObject({ message: 'unable to get prisma from request context' }, useSuperJson), - { status: 500 } - ); + return NextResponse.json({ message: 'unable to get prisma from request context' }, { status: 500 }); } const url = new URL(req.url); - let query: Record = Object.fromEntries(url.searchParams); - try { - query = buildUrlQuery(query, useSuperJson); - } catch { - return NextResponse.json(marshalToObject({ message: 'invalid query parameters' }, useSuperJson), { - status: 400, - }); - } + const query = Object.fromEntries(url.searchParams); if (!context.params.path) { - return NextResponse.json(marshalToObject({ message: 'missing path parameter' }, useSuperJson), { - status: 400, - }); + return NextResponse.json( + { message: 'missing path parameter' }, + { + status: 400, + } + ); } const path = context.params.path.join('/'); @@ -71,18 +67,15 @@ export default function factory( method: req.method!, path, query, - requestBody: unmarshalFromObject(requestBody, useSuperJson), + requestBody, prisma, modelMeta: options.modelMeta, zodSchemas, logger: options.logger, }); - return NextResponse.json(marshalToObject(r.body, useSuperJson), { status: r.status }); + return NextResponse.json(r.body, { status: r.status }); } catch (err) { - return NextResponse.json( - marshalToObject({ message: `An unhandled error occurred: ${err}` }, useSuperJson), - { status: 500 } - ); + return NextResponse.json({ message: `An unhandled error occurred: ${err}` }, { status: 500 }); } }; } diff --git a/packages/server/src/next/pages-route-handler.ts b/packages/server/src/next/pages-route-handler.ts index 4b980ff72..2baf0f1a4 100644 --- a/packages/server/src/next/pages-route-handler.ts +++ b/packages/server/src/next/pages-route-handler.ts @@ -1,11 +1,10 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ +import type { ZodSchemas } from '@zenstackhq/runtime'; import { DbClientContract } from '@zenstackhq/runtime'; -import type { ZodSchemas } from '@zenstackhq/runtime/enhancements/types'; import { NextApiRequest, NextApiResponse } from 'next'; import { PagesRouteRequestHandlerOptions } from '.'; import RPCAPIHandler from '../api/rpc'; -import { buildUrlQuery, marshalToObject, unmarshalFromObject } from '../utils'; /** * Creates a Next.js API endpoint (traditional "pages" route) request handler which encapsulates Prisma CRUD operations. @@ -27,27 +26,21 @@ export default function factory( } const requestHandler = options.handler || RPCAPIHandler(); - const useSuperJson = options.useSuperJson === true; + if (options.useSuperJson !== undefined) { + console.warn( + 'The option "useSuperJson" is deprecated. The server APIs automatically use superjson for serialization.' + ); + } return async (req: NextApiRequest, res: NextApiResponse) => { const prisma = (await options.getPrisma(req, res)) as DbClientContract; if (!prisma) { - res.status(500).json( - marshalToObject({ message: 'unable to get prisma from request context' }, useSuperJson) - ); - return; - } - - let query: Record = {}; - try { - query = buildUrlQuery(req.query, useSuperJson); - } catch { - res.status(400).json(marshalToObject({ message: 'invalid query parameters' }, useSuperJson)); + res.status(500).json({ message: 'unable to get prisma from request context' }); return; } if (!req.query.path) { - res.status(400).json(marshalToObject({ message: 'missing path parameter' }, useSuperJson)); + res.status(400).json({ message: 'missing path parameter' }); return; } const path = (req.query.path as string[]).join('/'); @@ -56,16 +49,16 @@ export default function factory( const r = await requestHandler({ method: req.method!, path, - query, - requestBody: unmarshalFromObject(req.body, useSuperJson), + query: req.query as Record, + requestBody: req.body, prisma, modelMeta: options.modelMeta, zodSchemas, logger: options.logger, }); - res.status(r.status).send(marshalToObject(r.body, useSuperJson)); + res.status(r.status).send(r.body); } catch (err) { - res.status(500).send(marshalToObject({ message: `An unhandled error occurred: ${err}` }, useSuperJson)); + res.status(500).send({ message: `An unhandled error occurred: ${err}` }); } }; } diff --git a/packages/server/src/sveltekit/handler.ts b/packages/server/src/sveltekit/handler.ts index b4224c46a..2dbdf7e1d 100644 --- a/packages/server/src/sveltekit/handler.ts +++ b/packages/server/src/sveltekit/handler.ts @@ -1,10 +1,9 @@ import type { Handle, RequestEvent } from '@sveltejs/kit'; +import type { ZodSchemas } from '@zenstackhq/runtime'; import { DbClientContract } from '@zenstackhq/runtime'; import RPCApiHandler from '../api/rpc'; import { logInfo } from '../api/utils'; import { AdapterBaseOptions } from '../types'; -import { buildUrlQuery, marshalToString, unmarshalFromString } from '../utils'; -import type { ZodSchemas } from '@zenstackhq/runtime/enhancements/types'; /** * SvelteKit request handler options @@ -38,34 +37,17 @@ export default function createHandler(options: HandlerOptions): Handle { } const requestHanler = options.handler ?? RPCApiHandler(); - const useSuperJson = options.useSuperJson === true; + if (options.useSuperJson !== undefined) { + console.warn( + 'The option "useSuperJson" is deprecated. The server APIs automatically use superjson for serialization.' + ); + } return async ({ event, resolve }) => { if (event.url.pathname.startsWith(options.prefix)) { const prisma = (await options.getPrisma(event)) as DbClientContract; if (!prisma) { - return new Response( - marshalToString({ message: 'unable to get prisma from request context' }, useSuperJson), - { - status: 400, - headers: { - 'content-type': 'application/json', - }, - } - ); - } - - const queryObj: Record = {}; - for (const key of event.url.searchParams.keys()) { - const values = event.url.searchParams.getAll(key); - queryObj[key] = values; - } - - let query: Record = {}; - try { - query = buildUrlQuery(queryObj, useSuperJson); - } catch { - return new Response(marshalToString({ message: 'invalid query parameters' }, useSuperJson), { + return new Response(JSON.stringify({ message: 'unable to get prisma from request context' }), { status: 400, headers: { 'content-type': 'application/json', @@ -73,11 +55,12 @@ export default function createHandler(options: HandlerOptions): Handle { }); } + const query = Object.fromEntries(event.url.searchParams); let requestBody: unknown; if (event.request.body) { const text = await event.request.text(); if (text) { - requestBody = unmarshalFromString(text, useSuperJson); + requestBody = JSON.parse(text); } } @@ -94,14 +77,14 @@ export default function createHandler(options: HandlerOptions): Handle { modelMeta: options.modelMeta, }); - return new Response(marshalToString(r.body, useSuperJson), { + return new Response(JSON.stringify(r.body), { status: r.status, headers: { 'content-type': 'application/json', }, }); } catch (err) { - return new Response(marshalToString({ message: `An unhandled error occurred: ${err}` }, useSuperJson), { + return new Response(JSON.stringify({ message: `An unhandled error occurred: ${err}` }), { status: 500, headers: { 'content-type': 'application/json', diff --git a/packages/server/src/types.ts b/packages/server/src/types.ts index 58de799a9..ed307ab2e 100644 --- a/packages/server/src/types.ts +++ b/packages/server/src/types.ts @@ -1,5 +1,5 @@ +import type { ModelMeta, ZodSchemas } from '@zenstackhq/runtime'; import { DbClientContract } from '@zenstackhq/runtime'; -import type { ModelMeta, ZodSchemas } from '@zenstackhq/runtime/enhancements/types'; type LoggerMethod = (message: string, code?: string) => void; diff --git a/packages/server/src/utils.ts b/packages/server/src/utils.ts deleted file mode 100644 index c68d161d3..000000000 --- a/packages/server/src/utils.ts +++ /dev/null @@ -1,87 +0,0 @@ -import superjson from 'superjson'; - -/** - * Marshal an object to string - */ -export function marshalToString(value: unknown, useSuperJson = false) { - return useSuperJson ? superjson.stringify(value) : JSON.stringify(value); -} - -/** - * Marshals an object - */ -export function marshalToObject(value: unknown, useSuperJson = false) { - return useSuperJson ? JSON.parse(superjson.stringify(value)) : value; -} - -/** - * Unmarshal a string to object - */ -export function unmarshalFromString(value: string, useSuperJson = false) { - if (value === undefined || value === null) { - return value; - } - - const j = JSON.parse(value); - if (useSuperJson) { - if (j?.json) { - // parse with superjson - return superjson.parse(value); - } else { - // parse as regular json - return j; - } - } else { - return j; - } -} - -/** - * Unmarshal an object - */ -export function unmarshalFromObject(value: unknown, useSuperJson = false) { - if (value === undefined || value === null) { - return value; - } - - if (useSuperJson) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - if ((value as any).json) { - // parse with superjson - return superjson.parse(JSON.stringify(value)); - } else { - // parse as regular json - return value; - } - } else { - return value; - } -} - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export function buildUrlQuery(query: unknown, useSuperJson: boolean) { - const result: Record = {}; - - if (typeof query !== 'object' || query === null) { - return result; - } - - for (const [key, v] of Object.entries(query)) { - if (typeof v !== 'string' && !Array.isArray(v)) { - continue; - } - - let value = v as string | string[]; - - if (key === 'q') { - // handle parameter marshalling (potentially using superjson) - if (Array.isArray(value)) { - value = value.map((v) => JSON.stringify(unmarshalFromString(v as string, useSuperJson))); - } else { - value = JSON.stringify(unmarshalFromString(value as string, useSuperJson)); - } - } - result[key] = value; - } - return result; -} diff --git a/packages/server/tests/adapter/express.test.ts b/packages/server/tests/adapter/express.test.ts index 7121edcf9..e7c908326 100644 --- a/packages/server/tests/adapter/express.test.ts +++ b/packages/server/tests/adapter/express.test.ts @@ -4,7 +4,6 @@ import { loadSchema } from '@zenstackhq/testtools'; import bodyParser from 'body-parser'; import express from 'express'; -import superjson from 'superjson'; import request from 'supertest'; import RESTAPIHandler from '../../src/api/rest'; import { ZenStackMiddleware } from '../../src/express'; @@ -20,7 +19,7 @@ describe('Express adapter tests - rpc handler', () => { let r = await request(app).get(makeUrl('/api/post/findMany', { where: { id: { equals: '1' } } })); expect(r.status).toBe(200); - expect(r.body).toHaveLength(0); + expect(r.body.data).toHaveLength(0); r = await request(app) .post('/api/user/create') @@ -39,7 +38,8 @@ describe('Express adapter tests - rpc handler', () => { }); expect(r.status).toBe(201); - expect(r.body).toEqual( + const data = r.body.data; + expect(data).toEqual( expect.objectContaining({ email: 'user1@abc.com', posts: expect.arrayContaining([ @@ -49,7 +49,6 @@ describe('Express adapter tests - rpc handler', () => { }) ); // aux fields should have been removed - const data = r.body; expect(data.zenstack_guard).toBeUndefined(); expect(data.zenstack_transaction).toBeUndefined(); expect(data.posts[0].zenstack_guard).toBeUndefined(); @@ -57,29 +56,29 @@ describe('Express adapter tests - rpc handler', () => { r = await request(app).get(makeUrl('/api/post/findMany')); expect(r.status).toBe(200); - expect(r.body).toHaveLength(2); + expect(r.body.data).toHaveLength(2); r = await request(app).get(makeUrl('/api/post/findMany', { where: { viewCount: { gt: 1 } } })); expect(r.status).toBe(200); - expect(r.body).toHaveLength(1); + expect(r.body.data).toHaveLength(1); r = await request(app) .put('/api/user/update') .send({ where: { id: 'user1' }, data: { email: 'user1@def.com' } }); expect(r.status).toBe(200); - expect(r.body.email).toBe('user1@def.com'); + expect(r.body.data.email).toBe('user1@def.com'); r = await request(app).get(makeUrl('/api/post/count', { where: { viewCount: { gt: 1 } } })); expect(r.status).toBe(200); - expect(r.body).toBe(1); + expect(r.body.data).toBe(1); r = await request(app).get(makeUrl('/api/post/aggregate', { _sum: { viewCount: true } })); expect(r.status).toBe(200); - expect(r.body._sum.viewCount).toBe(3); + expect(r.body.data._sum.viewCount).toBe(3); r = await request(app).get(makeUrl('/api/post/groupBy', { by: ['published'], _sum: { viewCount: true } })); expect(r.status).toBe(200); - expect(r.body).toEqual( + expect(r.body.data).toEqual( expect.arrayContaining([ expect.objectContaining({ published: true, _sum: { viewCount: 1 } }), expect.objectContaining({ published: false, _sum: { viewCount: 2 } }), @@ -88,7 +87,7 @@ describe('Express adapter tests - rpc handler', () => { r = await request(app).delete(makeUrl('/api/user/deleteMany', { where: { id: 'user1' } })); expect(r.status).toBe(200); - expect(r.body.count).toBe(1); + expect(r.body.data.count).toBe(1); }); it('invalid path or args', async () => { @@ -107,94 +106,8 @@ describe('Express adapter tests - rpc handler', () => { r = await request(app).get('/api/post/findMany?q=abc'); expect(r.status).toBe(400); }); - - it('run plugin superjson', async () => { - const { prisma, zodSchemas } = await loadSchema(schema); - - const app = express(); - app.use(bodyParser.json()); - app.use('/api', ZenStackMiddleware({ getPrisma: () => prisma, zodSchemas, useSuperJson: true })); - - let r = await request(app).get(makeUrl('/api/post/findMany', { where: { id: { equals: '1' } } }, true)); - expect(r.status).toBe(200); - expect(unmarshal(r.body)).toHaveLength(0); - - r = await request(app) - .post('/api/user/create') - .send({ - include: { posts: true }, - data: { - id: 'user1', - email: 'user1@abc.com', - posts: { - create: [ - { title: 'post1', published: true, viewCount: 1 }, - { title: 'post2', published: false, viewCount: 2 }, - ], - }, - }, - }); - - expect(r.status).toBe(201); - expect(unmarshal(r.body)).toEqual( - expect.objectContaining({ - email: 'user1@abc.com', - posts: expect.arrayContaining([ - expect.objectContaining({ title: 'post1' }), - expect.objectContaining({ title: 'post2' }), - ]), - }) - ); - // aux fields should have been removed - const data = unmarshal(r.body); - expect(data.zenstack_guard).toBeUndefined(); - expect(data.zenstack_transaction).toBeUndefined(); - expect(data.posts[0].zenstack_guard).toBeUndefined(); - expect(data.posts[0].zenstack_transaction).toBeUndefined(); - - r = await request(app).get(makeUrl('/api/post/findMany')); - expect(r.status).toBe(200); - expect(unmarshal(r.body)).toHaveLength(2); - - r = await request(app).get(makeUrl('/api/post/findMany', { where: { viewCount: { gt: 1 } } }, true)); - expect(r.status).toBe(200); - expect(unmarshal(r.body)).toHaveLength(1); - - r = await request(app) - .put('/api/user/update') - .send({ where: { id: 'user1' }, data: { email: 'user1@def.com' } }); - expect(r.status).toBe(200); - expect(unmarshal(r.body).email).toBe('user1@def.com'); - - r = await request(app).get(makeUrl('/api/post/count', { where: { viewCount: { gt: 1 } } }, true)); - expect(r.status).toBe(200); - expect(unmarshal(r.body)).toBe(1); - - r = await request(app).get(makeUrl('/api/post/aggregate', { _sum: { viewCount: true } }, true)); - expect(r.status).toBe(200); - expect(unmarshal(r.body)._sum.viewCount).toBe(3); - - r = await request(app).get( - makeUrl('/api/post/groupBy', { by: ['published'], _sum: { viewCount: true } }, true) - ); - expect(r.status).toBe(200); - expect(unmarshal(r.body)).toEqual( - expect.arrayContaining([ - expect.objectContaining({ published: true, _sum: { viewCount: 1 } }), - expect.objectContaining({ published: false, _sum: { viewCount: 2 } }), - ]) - ); - - r = await request(app).delete(makeUrl('/api/user/deleteMany', { where: { id: 'user1' } }, true)); - expect(r.status).toBe(200); - expect(unmarshal(r.body).count).toBe(1); - }); }); -function unmarshal(value: any) { - return superjson.parse(JSON.stringify(value)) as any; -} - describe('Express adapter tests - rest handler', () => { it('run middleware', async () => { const { prisma, zodSchemas, modelMeta } = await loadSchema(schema); @@ -252,7 +165,7 @@ describe('Express adapter tests - rest handler', () => { }); }); -describe('Express adapter tests - rest handler with customMiddleware', () => { +describe('Express adapter tests - rest handler with custom middleware', () => { it('run middleware', async () => { const { prisma, zodSchemas, modelMeta } = await loadSchema(schema); diff --git a/packages/server/tests/adapter/fastify.test.ts b/packages/server/tests/adapter/fastify.test.ts index 3e0c12a6a..89aee54cf 100644 --- a/packages/server/tests/adapter/fastify.test.ts +++ b/packages/server/tests/adapter/fastify.test.ts @@ -3,7 +3,6 @@ import { loadSchema } from '@zenstackhq/testtools'; import fastify from 'fastify'; -import superjson from 'superjson'; import Rest from '../../src/api/rest'; import RPC from '../../src/api/rpc'; import { ZenStackFastifyPlugin } from '../../src/fastify'; @@ -26,7 +25,7 @@ describe('Fastify adapter tests - rpc handler', () => { url: makeUrl('/api/post/findMany', { where: { id: { equals: '1' } } }), }); expect(r.statusCode).toBe(200); - expect(r.json()).toHaveLength(0); + expect(r.json().data).toHaveLength(0); r = await app.inject({ method: 'POST', @@ -46,7 +45,8 @@ describe('Fastify adapter tests - rpc handler', () => { }, }); expect(r.statusCode).toBe(201); - expect(r.json()).toEqual( + const data = r.json().data; + expect(data).toEqual( expect.objectContaining({ email: 'user1@abc.com', posts: expect.arrayContaining([ @@ -56,7 +56,6 @@ describe('Fastify adapter tests - rpc handler', () => { }) ); // aux fields should have been removed - const data = r.json(); expect(data.zenstack_guard).toBeUndefined(); expect(data.zenstack_transaction).toBeUndefined(); expect(data.posts[0].zenstack_guard).toBeUndefined(); @@ -67,14 +66,14 @@ describe('Fastify adapter tests - rpc handler', () => { url: makeUrl('/api/post/findMany'), }); expect(r.statusCode).toBe(200); - expect(r.json()).toHaveLength(2); + expect(r.json().data).toHaveLength(2); r = await app.inject({ method: 'GET', url: makeUrl('/api/post/findMany', { where: { viewCount: { gt: 1 } } }), }); expect(r.statusCode).toBe(200); - expect(r.json()).toHaveLength(1); + expect(r.json().data).toHaveLength(1); r = await app.inject({ method: 'PUT', @@ -82,28 +81,28 @@ describe('Fastify adapter tests - rpc handler', () => { payload: { where: { id: 'user1' }, data: { email: 'user1@def.com' } }, }); expect(r.statusCode).toBe(200); - expect(r.json().email).toBe('user1@def.com'); + expect(r.json().data.email).toBe('user1@def.com'); r = await app.inject({ method: 'GET', url: makeUrl('/api/post/count', { where: { viewCount: { gt: 1 } } }), }); expect(r.statusCode).toBe(200); - expect(r.json()).toBe(1); + expect(r.json().data).toBe(1); r = await app.inject({ method: 'GET', url: makeUrl('/api/post/aggregate', { _sum: { viewCount: true } }), }); expect(r.statusCode).toBe(200); - expect(r.json()._sum.viewCount).toBe(3); + expect(r.json().data._sum.viewCount).toBe(3); r = await app.inject({ method: 'GET', url: makeUrl('/api/post/groupBy', { by: ['published'], _sum: { viewCount: true } }), }); expect(r.statusCode).toBe(200); - expect(r.json()).toEqual( + expect(r.json().data).toEqual( expect.arrayContaining([ expect.objectContaining({ published: true, _sum: { viewCount: 1 } }), expect.objectContaining({ published: false, _sum: { viewCount: 2 } }), @@ -115,7 +114,7 @@ describe('Fastify adapter tests - rpc handler', () => { url: makeUrl('/api/user/deleteMany', { where: { id: 'user1' } }), }); expect(r.statusCode).toBe(200); - expect(r.json().count).toBe(1); + expect(r.json().data.count).toBe(1); }); it('invalid path or args', async () => { @@ -147,121 +146,8 @@ describe('Fastify adapter tests - rpc handler', () => { }); expect(r.statusCode).toBe(400); }); - - it('run plugin superjson', async () => { - const { prisma, zodSchemas } = await loadSchema(schema); - - const app = fastify(); - app.register(ZenStackFastifyPlugin, { - prefix: '/api', - getPrisma: () => prisma, - zodSchemas, - handler: RPC(), - useSuperJson: true, - }); - - let r = await app.inject({ - method: 'GET', - url: makeUrl('/api/post/findMany', { where: { id: { equals: '1' } } }, true), - }); - expect(r.statusCode).toBe(200); - expect(unmarshal(r.json())).toHaveLength(0); - - r = await app.inject({ - method: 'POST', - url: '/api/user/create', - payload: { - include: { posts: true }, - data: { - id: 'user1', - email: 'user1@abc.com', - posts: { - create: [ - { title: 'post1', published: true, viewCount: 1 }, - { title: 'post2', published: false, viewCount: 2 }, - ], - }, - }, - }, - }); - expect(r.statusCode).toBe(201); - expect(unmarshal(r.json())).toEqual( - expect.objectContaining({ - email: 'user1@abc.com', - posts: expect.arrayContaining([ - expect.objectContaining({ title: 'post1' }), - expect.objectContaining({ title: 'post2' }), - ]), - }) - ); - // aux fields should have been removed - const data = unmarshal(r.json()); - expect(data.zenstack_guard).toBeUndefined(); - expect(data.zenstack_transaction).toBeUndefined(); - expect(data.posts[0].zenstack_guard).toBeUndefined(); - expect(data.posts[0].zenstack_transaction).toBeUndefined(); - - r = await app.inject({ - method: 'GET', - url: makeUrl('/api/post/findMany'), - }); - expect(r.statusCode).toBe(200); - expect(unmarshal(r.json())).toHaveLength(2); - - r = await app.inject({ - method: 'GET', - url: makeUrl('/api/post/findMany', { where: { viewCount: { gt: 1 } } }, true), - }); - expect(r.statusCode).toBe(200); - expect(unmarshal(r.json())).toHaveLength(1); - - r = await app.inject({ - method: 'PUT', - url: '/api/user/update', - payload: { where: { id: 'user1' }, data: { email: 'user1@def.com' } }, - }); - expect(r.statusCode).toBe(200); - expect(unmarshal(r.json()).email).toBe('user1@def.com'); - - r = await app.inject({ - method: 'GET', - url: makeUrl('/api/post/count', { where: { viewCount: { gt: 1 } } }, true), - }); - expect(r.statusCode).toBe(200); - expect(unmarshal(r.json())).toBe(1); - - r = await app.inject({ - method: 'GET', - url: makeUrl('/api/post/aggregate', { _sum: { viewCount: true } }, true), - }); - expect(r.statusCode).toBe(200); - expect(unmarshal(r.json())._sum.viewCount).toBe(3); - - r = await app.inject({ - method: 'GET', - url: makeUrl('/api/post/groupBy', { by: ['published'], _sum: { viewCount: true } }, true), - }); - expect(r.statusCode).toBe(200); - expect(unmarshal(r.json())).toEqual( - expect.arrayContaining([ - expect.objectContaining({ published: true, _sum: { viewCount: 1 } }), - expect.objectContaining({ published: false, _sum: { viewCount: 2 } }), - ]) - ); - - r = await app.inject({ - method: 'DELETE', - url: makeUrl('/api/user/deleteMany', { where: { id: 'user1' } }, true), - }); - expect(r.statusCode).toBe(200); - expect(unmarshal(r.json()).count).toBe(1); - }); }); -function unmarshal(value: any) { - return superjson.parse(JSON.stringify(value)) as any; -} - describe('Fastify adapter tests - rest handler', () => { it('run plugin regular json', async () => { const { prisma, zodSchemas, modelMeta } = await loadSchema(schema); diff --git a/packages/server/tests/adapter/next.test.ts b/packages/server/tests/adapter/next.test.ts index 013468403..46db1de78 100644 --- a/packages/server/tests/adapter/next.test.ts +++ b/packages/server/tests/adapter/next.test.ts @@ -2,7 +2,6 @@ import { loadSchema } from '@zenstackhq/testtools'; import { createServer, RequestListener } from 'http'; import { apiResolver } from 'next/dist/server/api-utils/node'; -import superjson from 'superjson'; import request from 'supertest'; import { NextRequestHandler, RequestHandlerOptions } from '../../src/next'; import Rest from '../../src/api/rest'; @@ -12,7 +11,7 @@ function makeTestClient(apiPath: string, options: RequestHandlerOptions, qArg?: const query = { path: pathParts, - ...(qArg ? { q: superjson.stringify(qArg) } : {}), + ...(qArg ? { q: JSON.stringify(qArg) } : {}), ...otherArgs, }; @@ -47,7 +46,7 @@ describe('Next.js adapter tests - rpc handler', () => { process.chdir(origDir); }); - it('simple crud regular json', async () => { + it('simple crud', async () => { const model = ` model M { id String @id @default(cuid()) @@ -57,157 +56,112 @@ model M { const { prisma } = await loadSchema(model); - await makeTestClient('/m/create', { getPrisma: () => prisma, useSuperJson: true }) + await makeTestClient('/m/create', { getPrisma: () => prisma }) .post('/') .send({ data: { id: '1', value: 1 } }) .expect(201) .expect((resp) => { - expect(resp.body.json.value).toBe(1); + expect(resp.body.data.value).toBe(1); }); - await makeTestClient('/m/findUnique', { getPrisma: () => prisma, useSuperJson: true }, { where: { id: '1' } }) + await makeTestClient('/m/findUnique', { getPrisma: () => prisma }, { where: { id: '1' } }) .get('/') .expect(200) .expect((resp) => { - expect(resp.body.json.value).toBe(1); + expect(resp.body.data.value).toBe(1); }); - await makeTestClient('/m/findFirst', { getPrisma: () => prisma, useSuperJson: true }, { where: { id: '1' } }) + await makeTestClient('/m/findFirst', { getPrisma: () => prisma }, { where: { id: '1' } }) .get('/') .expect(200) .expect((resp) => { - expect(resp.body.json.value).toBe(1); + expect(resp.body.data.value).toBe(1); }); - await makeTestClient('/m/findMany', { getPrisma: () => prisma, useSuperJson: true }, {}) + await makeTestClient('/m/findMany', { getPrisma: () => prisma }, {}) .get('/') .expect(200) .expect((resp) => { - expect(resp.body.json).toHaveLength(1); + expect(resp.body.data).toHaveLength(1); }); - await makeTestClient('/m/update', { getPrisma: () => prisma, useSuperJson: true }) + await makeTestClient('/m/update', { getPrisma: () => prisma }) .put('/') .send({ where: { id: '1' }, data: { value: 2 } }) .expect(200) .expect((resp) => { - expect(resp.body.json.value).toBe(2); + expect(resp.body.data.value).toBe(2); }); - await makeTestClient('/m/updateMany', { getPrisma: () => prisma, useSuperJson: true }) + await makeTestClient('/m/updateMany', { getPrisma: () => prisma }) .put('/') .send({ data: { value: 4 } }) .expect(200) .expect((resp) => { - expect(resp.body.json.count).toBe(1); + expect(resp.body.data.count).toBe(1); }); - await makeTestClient('/m/upsert', { getPrisma: () => prisma, useSuperJson: true }) + await makeTestClient('/m/upsert', { getPrisma: () => prisma }) .post('/') .send({ where: { id: '2' }, create: { id: '2', value: 2 }, update: { value: 3 } }) .expect(201) .expect((resp) => { - expect(resp.body.json.value).toBe(2); + expect(resp.body.data.value).toBe(2); }); - await makeTestClient('/m/upsert', { getPrisma: () => prisma, useSuperJson: true }) + await makeTestClient('/m/upsert', { getPrisma: () => prisma }) .post('/') .send({ where: { id: '2' }, create: { id: '2', value: 2 }, update: { value: 3 } }) .expect(201) .expect((resp) => { - expect(resp.body.json.value).toBe(3); + expect(resp.body.data.value).toBe(3); }); - await makeTestClient('/m/count', { getPrisma: () => prisma, useSuperJson: true }, { where: { id: '1' } }) + await makeTestClient('/m/count', { getPrisma: () => prisma }, { where: { id: '1' } }) .get('/') .expect(200) .expect((resp) => { - expect(resp.body.json).toBe(1); + expect(resp.body.data).toBe(1); }); - await makeTestClient('/m/count', { getPrisma: () => prisma, useSuperJson: true }, {}) + await makeTestClient('/m/count', { getPrisma: () => prisma }, {}) .get('/') .expect(200) .expect((resp) => { - expect(resp.body.json).toBe(2); + expect(resp.body.data).toBe(2); }); - await makeTestClient('/m/aggregate', { getPrisma: () => prisma, useSuperJson: true }, { _sum: { value: true } }) + await makeTestClient('/m/aggregate', { getPrisma: () => prisma }, { _sum: { value: true } }) .get('/') .expect(200) .expect((resp) => { - expect(resp.body.json._sum.value).toBe(7); + expect(resp.body.data._sum.value).toBe(7); }); - await makeTestClient( - '/m/groupBy', - { getPrisma: () => prisma, useSuperJson: true }, - { by: ['id'], _sum: { value: true } } - ) + await makeTestClient('/m/groupBy', { getPrisma: () => prisma }, { by: ['id'], _sum: { value: true } }) .get('/') .expect(200) .expect((resp) => { - const data = resp.body.json; + const data = resp.body.data; expect(data).toHaveLength(2); expect(data.find((item: any) => item.id === '1')._sum.value).toBe(4); expect(data.find((item: any) => item.id === '2')._sum.value).toBe(3); }); - await makeTestClient('/m/delete', { getPrisma: () => prisma, useSuperJson: true }, { where: { id: '1' } }) + await makeTestClient('/m/delete', { getPrisma: () => prisma }, { where: { id: '1' } }) .del('/') .expect(200); expect(await prisma.m.count()).toBe(1); - await makeTestClient('/m/deleteMany', { getPrisma: () => prisma, useSuperJson: true }, {}) + await makeTestClient('/m/deleteMany', { getPrisma: () => prisma }, {}) .del('/') .expect(200) .expect((resp) => { - expect(resp.body.json.count).toBe(1); + expect(resp.body.data.count).toBe(1); }); expect(await prisma.m.count()).toBe(0); }); - it('simple crud superjson', async () => { - const model = ` -model M { - id String @id @default(cuid()) - value Int -} - `; - - const { prisma } = await loadSchema(model); - - await makeTestClient('/m/create', { getPrisma: () => prisma, useSuperJson: true }) - .post('/') - .send(marshal({ data: { id: '1', value: 1 } })) - .expect(201) - .expect((resp) => { - expect(resp.body.json.value).toBe(1); - }); - - await makeTestClient('/m/findUnique', { getPrisma: () => prisma, useSuperJson: true }, { where: { id: '1' } }) - .get('/') - .expect(200) - .expect((resp) => { - expect(resp.body.json.value).toBe(1); - }); - - await makeTestClient('/m/findMany', { getPrisma: () => prisma, useSuperJson: true }, {}) - .get('/') - .expect(200) - .expect((resp) => { - expect(resp.body.json).toHaveLength(1); - }); - - await makeTestClient('/m/update', { getPrisma: () => prisma, useSuperJson: true }) - .put('/') - .send(marshal({ where: { id: '1' }, data: { value: 2 } })) - .expect(200) - .expect((resp) => { - expect(resp.body.json.value).toBe(2); - }); - }); - it('access policy crud', async () => { const model = ` model M { @@ -223,54 +177,46 @@ model M { const { withPresets } = await loadSchema(model); - await makeTestClient('/m/create', { getPrisma: () => withPresets(), useSuperJson: true }) + await makeTestClient('/m/create', { getPrisma: () => withPresets() }) .post('/m/create') .send({ data: { value: 0 } }) .expect(403) .expect((resp) => { - expect(resp.body.json.reason).toBe('RESULT_NOT_READABLE'); + expect(resp.body.error.reason).toBe('RESULT_NOT_READABLE'); }); - await makeTestClient('/m/create', { getPrisma: () => withPresets(), useSuperJson: true }) + await makeTestClient('/m/create', { getPrisma: () => withPresets() }) .post('/') .send({ data: { id: '1', value: 1 } }) .expect(201); - await makeTestClient('/m/findMany', { getPrisma: () => withPresets(), useSuperJson: true }) + await makeTestClient('/m/findMany', { getPrisma: () => withPresets() }) .get('/') .expect(200) .expect((resp) => { - expect(resp.body.json).toHaveLength(1); + expect(resp.body.data).toHaveLength(1); }); - await makeTestClient('/m/update', { getPrisma: () => withPresets(), useSuperJson: true }) + await makeTestClient('/m/update', { getPrisma: () => withPresets() }) .put('/') .send({ where: { id: '1' }, data: { value: 0 } }) .expect(403); - await makeTestClient('/m/update', { getPrisma: () => withPresets(), useSuperJson: true }) + await makeTestClient('/m/update', { getPrisma: () => withPresets() }) .put('/') .send({ where: { id: '1' }, data: { value: 2 } }) .expect(200); - await makeTestClient( - '/m/delete', - { getPrisma: () => withPresets(), useSuperJson: true }, - { where: { id: '1' } } - ) + await makeTestClient('/m/delete', { getPrisma: () => withPresets() }, { where: { id: '1' } }) .del('/') .expect(403); - await makeTestClient('/m/update', { getPrisma: () => withPresets(), useSuperJson: true }) + await makeTestClient('/m/update', { getPrisma: () => withPresets() }) .put('/') .send({ where: { id: '1' }, data: { value: 3 } }) .expect(200); - await makeTestClient( - '/m/delete', - { getPrisma: () => withPresets(), useSuperJson: true }, - { where: { id: '1' } } - ) + await makeTestClient('/m/delete', { getPrisma: () => withPresets() }, { where: { id: '1' } }) .del('/') .expect(200); }); @@ -340,7 +286,3 @@ model M { expect(await prisma.m.count()).toBe(0); }); }); - -function marshal(data: unknown) { - return JSON.parse(superjson.stringify(data)); -} diff --git a/packages/server/tests/adapter/sveltekit.test.ts b/packages/server/tests/adapter/sveltekit.test.ts index ae7a9e20b..c56128498 100644 --- a/packages/server/tests/adapter/sveltekit.test.ts +++ b/packages/server/tests/adapter/sveltekit.test.ts @@ -15,7 +15,7 @@ describe('SvelteKit adapter tests - rpc handler', () => { let r = await handler(makeRequest('GET', makeUrl('/api/post/findMany', { where: { id: { equals: '1' } } }))); expect(r.status).toBe(200); - expect(await unmarshal(r)).toHaveLength(0); + expect((await unmarshal(r)).data).toHaveLength(0); r = await handler( makeRequest('POST', '/api/user/create', { @@ -33,7 +33,7 @@ describe('SvelteKit adapter tests - rpc handler', () => { }) ); expect(r.status).toBe(201); - expect(await unmarshal(r)).toMatchObject({ + expect((await unmarshal(r)).data).toMatchObject({ email: 'user1@abc.com', posts: expect.arrayContaining([ expect.objectContaining({ title: 'post1' }), @@ -43,31 +43,31 @@ describe('SvelteKit adapter tests - rpc handler', () => { r = await handler(makeRequest('GET', makeUrl('/api/post/findMany'))); expect(r.status).toBe(200); - expect(await unmarshal(r)).toHaveLength(2); + expect((await unmarshal(r)).data).toHaveLength(2); r = await handler(makeRequest('GET', makeUrl('/api/post/findMany', { where: { viewCount: { gt: 1 } } }))); expect(r.status).toBe(200); - expect(await unmarshal(r)).toHaveLength(1); + expect((await unmarshal(r)).data).toHaveLength(1); r = await handler( makeRequest('PUT', '/api/user/update', { where: { id: 'user1' }, data: { email: 'user1@def.com' } }) ); expect(r.status).toBe(200); - expect((await unmarshal(r)).email).toBe('user1@def.com'); + expect((await unmarshal(r)).data.email).toBe('user1@def.com'); r = await handler(makeRequest('GET', makeUrl('/api/post/count', { where: { viewCount: { gt: 1 } } }))); expect(r.status).toBe(200); - expect(await unmarshal(r)).toBe(1); + expect((await unmarshal(r)).data).toBe(1); r = await handler(makeRequest('GET', makeUrl('/api/post/aggregate', { _sum: { viewCount: true } }))); expect(r.status).toBe(200); - expect((await unmarshal(r))._sum.viewCount).toBe(3); + expect((await unmarshal(r)).data._sum.viewCount).toBe(3); r = await handler( makeRequest('GET', makeUrl('/api/post/groupBy', { by: ['published'], _sum: { viewCount: true } })) ); expect(r.status).toBe(200); - expect(await unmarshal(r)).toEqual( + expect((await unmarshal(r)).data).toEqual( expect.arrayContaining([ expect.objectContaining({ published: true, _sum: { viewCount: 1 } }), expect.objectContaining({ published: false, _sum: { viewCount: 2 } }), @@ -76,80 +76,7 @@ describe('SvelteKit adapter tests - rpc handler', () => { r = await handler(makeRequest('DELETE', makeUrl('/api/user/deleteMany', { where: { id: 'user1' } }))); expect(r.status).toBe(200); - expect((await unmarshal(r)).count).toBe(1); - }); - - it('run hooks superjson', async () => { - const { prisma, zodSchemas } = await loadSchema(schema); - - const handler = SvelteKitHandler({ prefix: '/api', getPrisma: () => prisma, zodSchemas, useSuperJson: true }); - - let r = await handler( - makeRequest('GET', makeUrl('/api/post/findMany', { where: { id: { equals: '1' } } }, true)) - ); - expect(r.status).toBe(200); - expect(await unmarshal(r, true)).toHaveLength(0); - - r = await handler( - makeRequest('POST', '/api/user/create', { - include: { posts: true }, - data: { - id: 'user1', - email: 'user1@abc.com', - posts: { - create: [ - { title: 'post1', published: true, viewCount: 1 }, - { title: 'post2', published: false, viewCount: 2 }, - ], - }, - }, - }) - ); - expect(r.status).toBe(201); - expect(await unmarshal(r, true)).toMatchObject({ - email: 'user1@abc.com', - posts: expect.arrayContaining([ - expect.objectContaining({ title: 'post1' }), - expect.objectContaining({ title: 'post2' }), - ]), - }); - - r = await handler(makeRequest('GET', makeUrl('/api/post/findMany', undefined))); - expect(r.status).toBe(200); - expect(await unmarshal(r, true)).toHaveLength(2); - - r = await handler(makeRequest('GET', makeUrl('/api/post/findMany', { where: { viewCount: { gt: 1 } } }, true))); - expect(r.status).toBe(200); - expect(await unmarshal(r, true)).toHaveLength(1); - - r = await handler( - makeRequest('PUT', '/api/user/update', { where: { id: 'user1' }, data: { email: 'user1@def.com' } }) - ); - expect(r.status).toBe(200); - expect((await unmarshal(r, true)).email).toBe('user1@def.com'); - - r = await handler(makeRequest('GET', makeUrl('/api/post/count', { where: { viewCount: { gt: 1 } } }, true))); - expect(r.status).toBe(200); - expect(await unmarshal(r, true)).toBe(1); - - r = await handler(makeRequest('GET', makeUrl('/api/post/aggregate', { _sum: { viewCount: true } }, true))); - expect(r.status).toBe(200); - expect((await unmarshal(r, true))._sum.viewCount).toBe(3); - - r = await handler( - makeRequest('GET', makeUrl('/api/post/groupBy', { by: ['published'], _sum: { viewCount: true } }, true)) - ); - expect(r.status).toBe(200); - expect(await unmarshal(r, true)).toEqual( - expect.arrayContaining([ - expect.objectContaining({ published: true, _sum: { viewCount: 1 } }), - expect.objectContaining({ published: false, _sum: { viewCount: 2 } }), - ]) - ); - - r = await handler(makeRequest('DELETE', makeUrl('/api/user/deleteMany', { where: { id: 'user1' } }, true))); - expect(r.status).toBe(200); - expect((await unmarshal(r, true)).count).toBe(1); + expect((await unmarshal(r)).data.count).toBe(1); }); }); diff --git a/packages/server/tests/api/rest-petstore.test.ts b/packages/server/tests/api/rest-petstore.test.ts index 69c9075df..4c4d477a0 100644 --- a/packages/server/tests/api/rest-petstore.test.ts +++ b/packages/server/tests/api/rest-petstore.test.ts @@ -1,8 +1,8 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /// +import { ModelMeta } from '@zenstackhq/runtime'; import { loadSchema, run } from '@zenstackhq/testtools'; -import { ModelMeta } from '@zenstackhq/runtime/enhancements/types'; import makeHandler from '../../src/api/rest'; import { Response } from '../../src/types'; diff --git a/packages/server/tests/api/rest.test.ts b/packages/server/tests/api/rest.test.ts index 1f8e12e59..277a5d35e 100644 --- a/packages/server/tests/api/rest.test.ts +++ b/packages/server/tests/api/rest.test.ts @@ -1,17 +1,16 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /// -import { withPolicy } from '@zenstackhq/runtime'; -import { CrudFailureReason } from '@zenstackhq/runtime/constants'; -import { ModelMeta } from '@zenstackhq/runtime/enhancements/types'; +import { CrudFailureReason, ModelMeta, withPolicy } from '@zenstackhq/runtime'; import { loadSchema, run } from '@zenstackhq/testtools'; +import { Decimal } from 'decimal.js'; +import SuperJSON from 'superjson'; import makeHandler from '../../src/api/rest'; -import { Response } from '../../src/types'; let prisma: any; let zodSchemas: any; let modelMeta: ModelMeta; -let handler: (any: any) => Promise; +let handler: (any: any) => Promise<{ status: number; body: any }>; describe('REST server tests - regular prisma', () => { const schema = ` @@ -363,8 +362,8 @@ describe('REST server tests - regular prisma', () => { prisma, }); expect(r.status).toBe(200); - expect((r.body as any).data).toHaveLength(1); - expect((r.body as any).data[0]).toMatchObject({ id: 'user2' }); + expect(r.body.data).toHaveLength(1); + expect(r.body.data[0]).toMatchObject({ id: 'user2' }); // String filter r = await handler({ @@ -373,8 +372,8 @@ describe('REST server tests - regular prisma', () => { query: { ['filter[email]']: 'user1@abc.com' }, prisma, }); - expect((r.body as any).data).toHaveLength(1); - expect((r.body as any).data[0]).toMatchObject({ id: 'user1' }); + expect(r.body.data).toHaveLength(1); + expect(r.body.data[0]).toMatchObject({ id: 'user1' }); r = await handler({ method: 'get', @@ -382,8 +381,8 @@ describe('REST server tests - regular prisma', () => { query: { ['filter[email$contains]']: '1@abc' }, prisma, }); - expect((r.body as any).data).toHaveLength(1); - expect((r.body as any).data[0]).toMatchObject({ id: 'user1' }); + expect(r.body.data).toHaveLength(1); + expect(r.body.data[0]).toMatchObject({ id: 'user1' }); r = await handler({ method: 'get', @@ -391,7 +390,7 @@ describe('REST server tests - regular prisma', () => { query: { ['filter[email$contains]']: '1@bc' }, prisma, }); - expect((r.body as any).data).toHaveLength(0); + expect(r.body.data).toHaveLength(0); r = await handler({ method: 'get', @@ -399,8 +398,8 @@ describe('REST server tests - regular prisma', () => { query: { ['filter[email$startsWith]']: 'user1' }, prisma, }); - expect((r.body as any).data).toHaveLength(1); - expect((r.body as any).data[0]).toMatchObject({ id: 'user1' }); + expect(r.body.data).toHaveLength(1); + expect(r.body.data[0]).toMatchObject({ id: 'user1' }); r = await handler({ method: 'get', @@ -408,7 +407,7 @@ describe('REST server tests - regular prisma', () => { query: { ['filter[email$startsWith]']: 'ser1' }, prisma, }); - expect((r.body as any).data).toHaveLength(0); + expect(r.body.data).toHaveLength(0); r = await handler({ method: 'get', @@ -416,8 +415,8 @@ describe('REST server tests - regular prisma', () => { query: { ['filter[email$endsWith]']: '1@abc.com' }, prisma, }); - expect((r.body as any).data).toHaveLength(1); - expect((r.body as any).data[0]).toMatchObject({ id: 'user1' }); + expect(r.body.data).toHaveLength(1); + expect(r.body.data[0]).toMatchObject({ id: 'user1' }); r = await handler({ method: 'get', @@ -425,7 +424,7 @@ describe('REST server tests - regular prisma', () => { query: { ['filter[email$endsWith]']: '1@abc' }, prisma, }); - expect((r.body as any).data).toHaveLength(0); + expect(r.body.data).toHaveLength(0); // Int filter r = await handler({ @@ -434,8 +433,8 @@ describe('REST server tests - regular prisma', () => { query: { ['filter[viewCount]']: '1' }, prisma, }); - expect((r.body as any).data).toHaveLength(1); - expect((r.body as any).data[0]).toMatchObject({ id: 2 }); + expect(r.body.data).toHaveLength(1); + expect(r.body.data[0]).toMatchObject({ id: 2 }); r = await handler({ method: 'get', @@ -443,8 +442,8 @@ describe('REST server tests - regular prisma', () => { query: { ['filter[viewCount$gt]']: '0' }, prisma, }); - expect((r.body as any).data).toHaveLength(1); - expect((r.body as any).data[0]).toMatchObject({ id: 2 }); + expect(r.body.data).toHaveLength(1); + expect(r.body.data[0]).toMatchObject({ id: 2 }); r = await handler({ method: 'get', @@ -452,8 +451,8 @@ describe('REST server tests - regular prisma', () => { query: { ['filter[viewCount$gte]']: '1' }, prisma, }); - expect((r.body as any).data).toHaveLength(1); - expect((r.body as any).data[0]).toMatchObject({ id: 2 }); + expect(r.body.data).toHaveLength(1); + expect(r.body.data[0]).toMatchObject({ id: 2 }); r = await handler({ method: 'get', @@ -461,7 +460,7 @@ describe('REST server tests - regular prisma', () => { query: { ['filter[viewCount$lt]']: '0' }, prisma, }); - expect((r.body as any).data).toHaveLength(0); + expect(r.body.data).toHaveLength(0); r = await handler({ method: 'get', @@ -469,8 +468,8 @@ describe('REST server tests - regular prisma', () => { query: { ['filter[viewCount$lte]']: '0' }, prisma, }); - expect((r.body as any).data).toHaveLength(1); - expect((r.body as any).data[0]).toMatchObject({ id: 1 }); + expect(r.body.data).toHaveLength(1); + expect(r.body.data[0]).toMatchObject({ id: 1 }); // Boolean filter r = await handler({ @@ -479,8 +478,8 @@ describe('REST server tests - regular prisma', () => { query: { ['filter[published]']: 'true' }, prisma, }); - expect((r.body as any).data).toHaveLength(1); - expect((r.body as any).data[0]).toMatchObject({ id: 2 }); + expect(r.body.data).toHaveLength(1); + expect(r.body.data[0]).toMatchObject({ id: 2 }); // deep to-one filter r = await handler({ @@ -489,7 +488,7 @@ describe('REST server tests - regular prisma', () => { query: { ['filter[author][email]']: 'user1@abc.com' }, prisma, }); - expect((r.body as any).data).toHaveLength(1); + expect(r.body.data).toHaveLength(1); // deep to-many filter r = await handler({ @@ -498,7 +497,7 @@ describe('REST server tests - regular prisma', () => { query: { ['filter[posts][published]']: 'true' }, prisma, }); - expect((r.body as any).data).toHaveLength(1); + expect(r.body.data).toHaveLength(1); // filter to empty r = await handler({ @@ -507,7 +506,7 @@ describe('REST server tests - regular prisma', () => { query: { ['filter[id]']: 'user3' }, prisma, }); - expect((r.body as any).data).toHaveLength(0); + expect(r.body.data).toHaveLength(0); // to-many relation collection filter r = await handler({ @@ -516,8 +515,8 @@ describe('REST server tests - regular prisma', () => { query: { ['filter[posts]']: '2' }, prisma, }); - expect((r.body as any).data).toHaveLength(1); - expect((r.body as any).data[0]).toMatchObject({ id: 'user2' }); + expect(r.body.data).toHaveLength(1); + expect(r.body.data[0]).toMatchObject({ id: 'user2' }); r = await handler({ method: 'get', @@ -525,7 +524,7 @@ describe('REST server tests - regular prisma', () => { query: { ['filter[posts]']: '1,2,3' }, prisma, }); - expect((r.body as any).data).toHaveLength(2); + expect(r.body.data).toHaveLength(2); // multi filter r = await handler({ @@ -534,7 +533,7 @@ describe('REST server tests - regular prisma', () => { query: { ['filter[id]']: 'user1', ['filter[posts]']: '2' }, prisma, }); - expect((r.body as any).data).toHaveLength(0); + expect(r.body.data).toHaveLength(0); // to-one relation filter r = await handler({ @@ -543,8 +542,8 @@ describe('REST server tests - regular prisma', () => { query: { ['filter[author]']: 'user1' }, prisma, }); - expect((r.body as any).data).toHaveLength(1); - expect((r.body as any).data[0]).toMatchObject({ id: 1 }); + expect(r.body.data).toHaveLength(1); + expect(r.body.data[0]).toMatchObject({ id: 1 }); // invalid filter field r = await handler({ @@ -624,7 +623,7 @@ describe('REST server tests - regular prisma', () => { query: { ['filter[viewCount]']: '1' }, prisma, }); - expect((r.body as any).data).toHaveLength(0); + expect(r.body.data).toHaveLength(0); r = await handler({ method: 'get', @@ -632,7 +631,7 @@ describe('REST server tests - regular prisma', () => { query: { ['filter[viewCount]']: '1' }, prisma, }); - expect((r.body as any).data).toHaveLength(1); + expect(r.body.data).toHaveLength(1); }); it('relationship filtering', async () => { @@ -661,7 +660,7 @@ describe('REST server tests - regular prisma', () => { query: { ['filter[viewCount]']: '1' }, prisma, }); - expect((r.body as any).data).toHaveLength(0); + expect(r.body.data).toHaveLength(0); r = await handler({ method: 'get', @@ -669,7 +668,7 @@ describe('REST server tests - regular prisma', () => { query: { ['filter[viewCount]']: '1' }, prisma, }); - expect((r.body as any).data).toHaveLength(1); + expect(r.body.data).toHaveLength(1); }); it('toplevel sorting', async () => { @@ -700,7 +699,7 @@ describe('REST server tests - regular prisma', () => { prisma, }); expect(r.status).toBe(200); - expect((r.body as any).data[0]).toMatchObject({ id: 1 }); + expect(r.body.data[0]).toMatchObject({ id: 1 }); // basic sorting desc r = await handler({ @@ -710,7 +709,7 @@ describe('REST server tests - regular prisma', () => { prisma, }); expect(r.status).toBe(200); - expect((r.body as any).data[0]).toMatchObject({ id: 2 }); + expect(r.body.data[0]).toMatchObject({ id: 2 }); // by relation id r = await handler({ @@ -720,7 +719,7 @@ describe('REST server tests - regular prisma', () => { prisma, }); expect(r.status).toBe(200); - expect((r.body as any).data[0]).toMatchObject({ id: 2 }); + expect(r.body.data[0]).toMatchObject({ id: 2 }); // by relation field r = await handler({ @@ -730,7 +729,7 @@ describe('REST server tests - regular prisma', () => { prisma, }); expect(r.status).toBe(200); - expect((r.body as any).data[0]).toMatchObject({ id: 2 }); + expect(r.body.data[0]).toMatchObject({ id: 2 }); // multi-field sorting r = await handler({ @@ -740,7 +739,7 @@ describe('REST server tests - regular prisma', () => { prisma, }); expect(r.status).toBe(200); - expect((r.body as any).data[0]).toMatchObject({ id: 2 }); + expect(r.body.data[0]).toMatchObject({ id: 2 }); r = await handler({ method: 'get', @@ -749,7 +748,7 @@ describe('REST server tests - regular prisma', () => { prisma, }); expect(r.status).toBe(200); - expect((r.body as any).data[0]).toMatchObject({ id: 1 }); + expect(r.body.data[0]).toMatchObject({ id: 1 }); r = await handler({ method: 'get', @@ -758,7 +757,7 @@ describe('REST server tests - regular prisma', () => { prisma, }); expect(r.status).toBe(200); - expect((r.body as any).data[0]).toMatchObject({ id: 2 }); + expect(r.body.data[0]).toMatchObject({ id: 2 }); // invalid field r = await handler({ @@ -846,7 +845,7 @@ describe('REST server tests - regular prisma', () => { prisma, }); expect(r.status).toBe(200); - expect((r.body as any).data[0]).toMatchObject({ id: 1 }); + expect(r.body.data[0]).toMatchObject({ id: 1 }); // desc r = await handler({ @@ -856,7 +855,7 @@ describe('REST server tests - regular prisma', () => { prisma, }); expect(r.status).toBe(200); - expect((r.body as any).data[0]).toMatchObject({ id: 2 }); + expect(r.body.data[0]).toMatchObject({ id: 2 }); // relation field r = await handler({ @@ -866,7 +865,7 @@ describe('REST server tests - regular prisma', () => { prisma, }); expect(r.status).toBe(200); - expect((r.body as any).data[0]).toMatchObject({ id: 2 }); + expect(r.body.data[0]).toMatchObject({ id: 2 }); }); it('relationship sorting', async () => { @@ -903,7 +902,7 @@ describe('REST server tests - regular prisma', () => { prisma, }); expect(r.status).toBe(200); - expect((r.body as any).data[0]).toMatchObject({ id: 1 }); + expect(r.body.data[0]).toMatchObject({ id: 1 }); // desc r = await handler({ @@ -913,7 +912,7 @@ describe('REST server tests - regular prisma', () => { prisma, }); expect(r.status).toBe(200); - expect((r.body as any).data[0]).toMatchObject({ id: 2 }); + expect(r.body.data[0]).toMatchObject({ id: 2 }); // relation field r = await handler({ @@ -923,7 +922,7 @@ describe('REST server tests - regular prisma', () => { prisma, }); expect(r.status).toBe(200); - expect((r.body as any).data[0]).toMatchObject({ id: 2 }); + expect(r.body.data[0]).toMatchObject({ id: 2 }); }); it('including', async () => { @@ -962,8 +961,8 @@ describe('REST server tests - regular prisma', () => { query: { include: 'posts' }, prisma, }); - expect((r.body as any).included).toHaveLength(2); - expect((r.body as any).included[0]).toMatchObject({ + expect(r.body.included).toHaveLength(2); + expect(r.body.included[0]).toMatchObject({ type: 'post', id: 1, attributes: { title: 'Post1' }, @@ -976,8 +975,8 @@ describe('REST server tests - regular prisma', () => { query: { include: 'posts' }, prisma, }); - expect((r.body as any).included).toHaveLength(1); - expect((r.body as any).included[0]).toMatchObject({ + expect(r.body.included).toHaveLength(1); + expect(r.body.included[0]).toMatchObject({ type: 'post', id: 1, attributes: { title: 'Post1' }, @@ -990,8 +989,8 @@ describe('REST server tests - regular prisma', () => { query: { include: 'posts.comments' }, prisma, }); - expect((r.body as any).included).toHaveLength(1); - expect((r.body as any).included[0]).toMatchObject({ + expect(r.body.included).toHaveLength(1); + expect(r.body.included[0]).toMatchObject({ type: 'comment', attributes: { content: 'Comment1' }, }); @@ -1003,7 +1002,7 @@ describe('REST server tests - regular prisma', () => { query: { include: 'posts.comments', ['filter[published]']: 'true' }, prisma, }); - expect((r.body as any).data).toHaveLength(0); + expect(r.body.data).toHaveLength(0); // deep include r = await handler({ @@ -1012,8 +1011,8 @@ describe('REST server tests - regular prisma', () => { query: { include: 'posts.comments' }, prisma, }); - expect((r.body as any).included).toHaveLength(3); - expect((r.body as any).included[2]).toMatchObject({ + expect(r.body.included).toHaveLength(3); + expect(r.body.included[2]).toMatchObject({ type: 'comment', attributes: { content: 'Comment1' }, }); @@ -1025,8 +1024,8 @@ describe('REST server tests - regular prisma', () => { query: { include: 'posts.comments,profile' }, prisma, }); - expect((r.body as any).included).toHaveLength(4); - const profile = (r.body as any).included.find((item: any) => item.type === 'profile'); + expect(r.body.included).toHaveLength(4); + const profile = r.body.included.find((item: any) => item.type === 'profile'); expect(profile).toMatchObject({ type: 'profile', attributes: { gender: 'male' }, @@ -1062,9 +1061,9 @@ describe('REST server tests - regular prisma', () => { query: { ['page[limit]']: '3' }, prisma, }); - expect((r.body as any).data).toHaveLength(3); - expect((r.body as any).meta.total).toBe(5); - expect((r.body as any).links).toMatchObject({ + expect(r.body.data).toHaveLength(3); + expect(r.body.meta.total).toBe(5); + expect(r.body.links).toMatchObject({ first: 'http://localhost/api/user?page%5Blimit%5D=3', last: 'http://localhost/api/user?page%5Boffset%5D=3', prev: null, @@ -1078,9 +1077,9 @@ describe('REST server tests - regular prisma', () => { query: { ['page[limit]']: '3', ['page[offset]']: '3' }, prisma, }); - expect((r.body as any).data).toHaveLength(2); - expect((r.body as any).meta.total).toBe(5); - expect((r.body as any).links).toMatchObject({ + expect(r.body.data).toHaveLength(2); + expect(r.body.meta.total).toBe(5); + expect(r.body.links).toMatchObject({ first: 'http://localhost/api/user?page%5Blimit%5D=3', last: 'http://localhost/api/user?page%5Boffset%5D=3', prev: 'http://localhost/api/user?page%5Boffset%5D=0&page%5Blimit%5D=3', @@ -1094,8 +1093,8 @@ describe('REST server tests - regular prisma', () => { query: { ['page[limit]']: '10' }, prisma, }); - expect((r.body as any).data).toHaveLength(5); - expect((r.body as any).links).toMatchObject({ + expect(r.body.data).toHaveLength(5); + expect(r.body.links).toMatchObject({ first: 'http://localhost/api/user?page%5Blimit%5D=5', last: 'http://localhost/api/user?page%5Boffset%5D=0', prev: null, @@ -1109,8 +1108,8 @@ describe('REST server tests - regular prisma', () => { query: { ['page[offset]']: '10' }, prisma, }); - expect((r.body as any).data).toHaveLength(0); - expect((r.body as any).links).toMatchObject({ + expect(r.body.data).toHaveLength(0); + expect(r.body.links).toMatchObject({ first: 'http://localhost/api/user?page%5Blimit%5D=5', last: 'http://localhost/api/user?page%5Boffset%5D=0', prev: null, @@ -1124,8 +1123,8 @@ describe('REST server tests - regular prisma', () => { query: { ['page[offset]']: '-1' }, prisma, }); - expect((r.body as any).data).toHaveLength(5); - expect((r.body as any).links).toMatchObject({ + expect(r.body.data).toHaveLength(5); + expect(r.body.links).toMatchObject({ first: 'http://localhost/api/user?page%5Blimit%5D=5', last: 'http://localhost/api/user?page%5Boffset%5D=0', prev: null, @@ -1139,8 +1138,8 @@ describe('REST server tests - regular prisma', () => { query: { ['page[limit]']: '0' }, prisma, }); - expect((r.body as any).data).toHaveLength(5); - expect((r.body as any).links).toMatchObject({ + expect(r.body.data).toHaveLength(5); + expect(r.body.links).toMatchObject({ first: 'http://localhost/api/user?page%5Blimit%5D=5', last: 'http://localhost/api/user?page%5Boffset%5D=0', prev: null, @@ -1168,8 +1167,8 @@ describe('REST server tests - regular prisma', () => { path: '/user/user1/posts', prisma, }); - expect((r.body as any).data).toHaveLength(5); - expect((r.body as any).links).toMatchObject({ + expect(r.body.data).toHaveLength(5); + expect(r.body.links).toMatchObject({ self: 'http://localhost/api/user/user1/posts', first: 'http://localhost/api/user/user1/posts?page%5Blimit%5D=5', last: 'http://localhost/api/user/user1/posts?page%5Boffset%5D=5', @@ -1184,8 +1183,8 @@ describe('REST server tests - regular prisma', () => { query: { ['page[limit]']: '3' }, prisma, }); - expect((r.body as any).data).toHaveLength(3); - expect((r.body as any).links).toMatchObject({ + expect(r.body.data).toHaveLength(3); + expect(r.body.links).toMatchObject({ self: 'http://localhost/api/user/user1/posts', first: 'http://localhost/api/user/user1/posts?page%5Blimit%5D=3', last: 'http://localhost/api/user/user1/posts?page%5Boffset%5D=9', @@ -1200,8 +1199,8 @@ describe('REST server tests - regular prisma', () => { query: { ['page[limit]']: '3', ['page[offset]']: '8' }, prisma, }); - expect((r.body as any).data).toHaveLength(2); - expect((r.body as any).links).toMatchObject({ + expect(r.body.data).toHaveLength(2); + expect(r.body.links).toMatchObject({ self: 'http://localhost/api/user/user1/posts', first: 'http://localhost/api/user/user1/posts?page%5Blimit%5D=3', last: 'http://localhost/api/user/user1/posts?page%5Boffset%5D=9', @@ -1230,8 +1229,8 @@ describe('REST server tests - regular prisma', () => { path: '/user/user1/relationships/posts', prisma, }); - expect((r.body as any).data).toHaveLength(5); - expect((r.body as any).links).toMatchObject({ + expect(r.body.data).toHaveLength(5); + expect(r.body.links).toMatchObject({ self: 'http://localhost/api/user/user1/relationships/posts', first: 'http://localhost/api/user/user1/relationships/posts?page%5Blimit%5D=5', last: 'http://localhost/api/user/user1/relationships/posts?page%5Boffset%5D=5', @@ -1246,8 +1245,8 @@ describe('REST server tests - regular prisma', () => { query: { ['page[limit]']: '3' }, prisma, }); - expect((r.body as any).data).toHaveLength(3); - expect((r.body as any).links).toMatchObject({ + expect(r.body.data).toHaveLength(3); + expect(r.body.links).toMatchObject({ self: 'http://localhost/api/user/user1/relationships/posts', first: 'http://localhost/api/user/user1/relationships/posts?page%5Blimit%5D=3', last: 'http://localhost/api/user/user1/relationships/posts?page%5Boffset%5D=9', @@ -1262,8 +1261,8 @@ describe('REST server tests - regular prisma', () => { query: { ['page[limit]']: '3', ['page[offset]']: '8' }, prisma, }); - expect((r.body as any).data).toHaveLength(2); - expect((r.body as any).links).toMatchObject({ + expect(r.body.data).toHaveLength(2); + expect(r.body.links).toMatchObject({ self: 'http://localhost/api/user/user1/relationships/posts', first: 'http://localhost/api/user/user1/relationships/posts?page%5Blimit%5D=3', last: 'http://localhost/api/user/user1/relationships/posts?page%5Boffset%5D=9', @@ -1910,7 +1909,7 @@ describe('REST server tests - enhanced prisma', () => { prisma, }); expect(r.status).toBe(403); - expect((r.body as any).errors[0].reason).toBe(CrudFailureReason.RESULT_NOT_READABLE); + expect(r.body.errors[0].reason).toBe(CrudFailureReason.RESULT_NOT_READABLE); }); }); @@ -1997,7 +1996,7 @@ describe('REST server tests - NextAuth project regression', () => { prisma, }); expect(r.status).toBe(200); - expect((r.body as any).data).toHaveLength(0); + expect(r.body.data).toHaveLength(0); r = await handler({ method: 'post', @@ -2016,7 +2015,7 @@ describe('REST server tests - NextAuth project regression', () => { prisma, }); expect(r.status).toBe(200); - expect((r.body as any).data).toHaveLength(1); + expect(r.body.data).toHaveLength(1); r = await handler({ method: 'post', @@ -2028,6 +2027,158 @@ describe('REST server tests - NextAuth project regression', () => { prisma, }); expect(r.status).toBe(400); - expect((r.body as any).errors[0].prismaCode).toBe('P2002'); + expect(r.body.errors[0].prismaCode).toBe('P2002'); + }); +}); + +describe('REST server tests - field type coverage', () => { + const schema = ` + model Foo { + id Int @id + string String + int Int + bigInt BigInt + date DateTime + float Float + decimal Decimal + boolean Boolean + bytes Bytes + bars Bar[] + } + + model Bar { + id Int @id + bytes Bytes + foo Foo? @relation(fields: [fooId], references: [id]) + fooId Int? @unique + } + `; + + it('field types', async () => { + const { prisma, zodSchemas, modelMeta } = await loadSchema(schema); + + const _handler = makeHandler({ endpoint: 'http://localhost/api', pageSize: 5 }); + handler = (args) => _handler({ ...args, zodSchemas, modelMeta, url: new URL(`http://localhost/${args.path}`) }); + + await prisma.bar.create({ data: { id: 1, bytes: Buffer.from([7, 8, 9]) } }); + + const decimalValue1 = new Decimal('0.046875'); + const decimalValue2 = new Decimal('0.0146875'); + + const createAttrs = { + string: 'string', + int: 123, + bigInt: BigInt(534543543534), + date: new Date(), + float: 1.23, + decimal: decimalValue1, + boolean: true, + bytes: Buffer.from([1, 2, 3, 4]), + }; + + const { json: createPayload, meta: createMeta } = SuperJSON.serialize({ + data: { + type: 'foo', + attributes: { id: 1, ...createAttrs }, + relationships: { + bars: { + data: [{ type: 'bar', id: 1 }], + }, + }, + }, + }); + + let r = await handler({ + method: 'post', + path: '/foo', + query: {}, + requestBody: { + ...(createPayload as any), + meta: { + serialization: createMeta, + }, + }, + prisma, + }); + expect(r.status).toBe(201); + // result is serializable + expect(JSON.stringify(r.body)).toBeTruthy(); + let serializationMeta = r.body.meta.serialization; + expect(serializationMeta).toBeTruthy(); + let deserialized: any = SuperJSON.deserialize({ json: r.body, meta: serializationMeta }); + let data = deserialized.data.attributes; + expect(typeof data.bigInt).toBe('bigint'); + expect(Buffer.isBuffer(data.bytes)).toBeTruthy(); + expect(data.date instanceof Date).toBeTruthy(); + expect(Decimal.isDecimal(data.decimal)).toBeTruthy(); + + const updateAttrs = { + bigInt: BigInt(1534543543534), + date: new Date(), + decimal: decimalValue2, + bytes: Buffer.from([5, 2, 3, 4]), + }; + const { json: updatePayload, meta: updateMeta } = SuperJSON.serialize({ + data: { + type: 'foo', + attributes: updateAttrs, + }, + }); + + r = await handler({ + method: 'put', + path: '/foo/1', + query: {}, + requestBody: { + ...(updatePayload as any), + meta: { + serialization: updateMeta, + }, + }, + prisma, + }); + expect(r.status).toBe(200); + // result is serializable + expect(JSON.stringify(r.body)).toBeTruthy(); + + serializationMeta = r.body.meta.serialization; + expect(serializationMeta).toBeTruthy(); + deserialized = SuperJSON.deserialize({ json: r.body, meta: serializationMeta }); + data = deserialized.data.attributes; + expect(data.bigInt).toEqual(updateAttrs.bigInt); + expect(data.date).toEqual(updateAttrs.date); + expect(data.decimal.equals(updateAttrs.decimal)).toBeTruthy(); + expect(data.bytes.toString('base64')).toEqual(updateAttrs.bytes.toString('base64')); + + r = await handler({ + method: 'get', + path: '/foo/1', + query: {}, + prisma, + }); + // result is serializable + expect(JSON.stringify(r.body)).toBeTruthy(); + serializationMeta = r.body.meta.serialization; + expect(serializationMeta).toBeTruthy(); + deserialized = SuperJSON.deserialize({ json: r.body, meta: serializationMeta }); + data = deserialized.data.attributes; + expect(typeof data.bigInt).toBe('bigint'); + expect(Buffer.isBuffer(data.bytes)).toBeTruthy(); + expect(data.date instanceof Date).toBeTruthy(); + expect(Decimal.isDecimal(data.decimal)).toBeTruthy(); + + r = await handler({ + method: 'get', + path: '/foo', + query: { include: 'bars' }, + prisma, + }); + // result is serializable + expect(JSON.stringify(r.body)).toBeTruthy(); + serializationMeta = r.body.meta.serialization; + expect(serializationMeta).toBeTruthy(); + deserialized = SuperJSON.deserialize({ json: r.body, meta: serializationMeta }); + const included = deserialized.included[0]; + expect(Buffer.isBuffer(included.attributes.bytes)).toBeTruthy(); }); }); diff --git a/packages/server/tests/api/rpc.test.ts b/packages/server/tests/api/rpc.test.ts index dfdc98f4f..f9ff2155a 100644 --- a/packages/server/tests/api/rpc.test.ts +++ b/packages/server/tests/api/rpc.test.ts @@ -1,17 +1,19 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /// -import type { ZodSchemas } from '@zenstackhq/runtime/enhancements/types'; +import type { ZodSchemas } from '@zenstackhq/runtime'; import { loadSchema } from '@zenstackhq/testtools'; +import { Decimal } from 'decimal.js'; +import SuperJSON from 'superjson'; import RPCAPIHandler from '../../src/api/rpc'; import { schema } from '../utils'; -describe('OpenAPI server tests', () => { +describe('RPC API Handler Tests', () => { let prisma: any; let zodSchemas: any; beforeAll(async () => { - const params = await loadSchema(schema); + const params = await loadSchema(schema, { fullZod: true }); prisma = params.prisma; zodSchemas = params.zodSchemas; }); @@ -25,7 +27,7 @@ describe('OpenAPI server tests', () => { prisma, }); expect(r.status).toBe(200); - expect(r.body).toHaveLength(0); + expect(r.data).toHaveLength(0); r = await handleRequest({ method: 'post', @@ -47,7 +49,7 @@ describe('OpenAPI server tests', () => { prisma, }); expect(r.status).toBe(201); - expect(r.body).toEqual( + expect(r.data).toEqual( expect.objectContaining({ email: 'user1@abc.com', posts: expect.arrayContaining([ @@ -56,11 +58,10 @@ describe('OpenAPI server tests', () => { ]), }) ); - const data: any = r.body; - expect(data.zenstack_guard).toBeUndefined(); - expect(data.zenstack_transaction).toBeUndefined(); - expect(data.posts[0].zenstack_guard).toBeUndefined(); - expect(data.posts[0].zenstack_transaction).toBeUndefined(); + expect(r.data.zenstack_guard).toBeUndefined(); + expect(r.data.zenstack_transaction).toBeUndefined(); + expect(r.data.posts[0].zenstack_guard).toBeUndefined(); + expect(r.data.posts[0].zenstack_transaction).toBeUndefined(); r = await handleRequest({ method: 'get', @@ -68,7 +69,7 @@ describe('OpenAPI server tests', () => { prisma, }); expect(r.status).toBe(200); - expect(r.body).toHaveLength(2); + expect(r.data).toHaveLength(2); r = await handleRequest({ method: 'get', @@ -77,7 +78,7 @@ describe('OpenAPI server tests', () => { prisma, }); expect(r.status).toBe(200); - expect(r.body).toHaveLength(1); + expect(r.data).toHaveLength(1); r = await handleRequest({ method: 'put', @@ -86,7 +87,7 @@ describe('OpenAPI server tests', () => { prisma, }); expect(r.status).toBe(200); - expect((r.body as any).email).toBe('user1@def.com'); + expect(r.data.email).toBe('user1@def.com'); r = await handleRequest({ method: 'get', @@ -95,7 +96,7 @@ describe('OpenAPI server tests', () => { prisma, }); expect(r.status).toBe(200); - expect(r.body).toBe(1); + expect(r.data).toBe(1); r = await handleRequest({ method: 'get', @@ -104,7 +105,7 @@ describe('OpenAPI server tests', () => { prisma, }); expect(r.status).toBe(200); - expect((r.body as any)._sum.viewCount).toBe(3); + expect(r.data._sum.viewCount).toBe(3); r = await handleRequest({ method: 'get', @@ -113,7 +114,7 @@ describe('OpenAPI server tests', () => { prisma, }); expect(r.status).toBe(200); - expect(r.body).toEqual( + expect(r.data).toEqual( expect.arrayContaining([ expect.objectContaining({ published: true, _sum: { viewCount: 1 } }), expect.objectContaining({ published: false, _sum: { viewCount: 2 } }), @@ -127,7 +128,7 @@ describe('OpenAPI server tests', () => { prisma, }); expect(r.status).toBe(200); - expect((r.body as any).count).toBe(1); + expect(r.data.count).toBe(1); }); it('validation error', async () => { @@ -140,7 +141,7 @@ describe('OpenAPI server tests', () => { prisma, }); expect(r.status).toBe(400); - expect((r.body as any).message).toContain('Argument where is missing'); + expect(r.error.message).toMatch(/Argument.+missing/); handleRequest = makeHandler(zodSchemas); @@ -151,8 +152,8 @@ describe('OpenAPI server tests', () => { prisma, }); expect(r.status).toBe(400); - expect((r.body as any).message).toContain('Validation error'); - expect((r.body as any).message).toContain('where'); + expect(r.error.message).toContain('Validation error'); + expect(r.error.message).toContain('where'); r = await handleRequest({ method: 'post', @@ -162,8 +163,8 @@ describe('OpenAPI server tests', () => { zodSchemas, }); expect(r.status).toBe(400); - expect((r.body as any).message).toContain('Validation error'); - expect((r.body as any).message).toContain('data'); + expect(r.error.message).toContain('Validation error'); + expect(r.error.message).toContain('data'); }); it('invalid path or args', async () => { @@ -174,7 +175,7 @@ describe('OpenAPI server tests', () => { prisma, }); expect(r.status).toBe(400); - expect((r.body as any).message).toContain('invalid request path'); + expect(r.error.message).toContain('invalid request path'); r = await handleRequest({ method: 'get', @@ -182,7 +183,7 @@ describe('OpenAPI server tests', () => { prisma, }); expect(r.status).toBe(400); - expect((r.body as any).message).toContain('invalid request path'); + expect(r.error.message).toContain('invalid request path'); r = await handleRequest({ method: 'get', @@ -191,7 +192,7 @@ describe('OpenAPI server tests', () => { prisma, }); expect(r.status).toBe(400); - expect((r.body as any).message).toContain('query param must contain valid JSON'); + expect(r.error.message).toContain('invalid "q" query parameter'); r = await handleRequest({ method: 'delete', @@ -200,13 +201,187 @@ describe('OpenAPI server tests', () => { prisma, }); expect(r.status).toBe(400); - expect((r.body as any).message).toContain('query param must contain valid JSON'); + expect(r.error.message).toContain('invalid "q" query parameter'); + }); + + it('field types', async () => { + const schema = ` + model Foo { + id Int @id + + string String + int Int + bigInt BigInt + date DateTime + float Float + decimal Decimal + boolean Boolean + bytes Bytes + bars Bar[] + + @@allow('all', true) + } + + + model Bar { + id Int @id @default(autoincrement()) + bytes Bytes + foo Foo @relation(fields: [fooId], references: [id]) + fooId Int @unique + } + `; + + const handleRequest = makeHandler(); + const { prisma, zodSchemas, modelMeta } = await loadSchema(schema); + + const decimalValue = new Decimal('0.046875'); + const bigIntValue = BigInt(534543543534); + const dateValue = new Date(); + const bufferValue = Buffer.from([1, 2, 3, 4]); + const barBufferValue = Buffer.from([7, 8, 9]); + + const createData = { + string: 'string', + int: 123, + bigInt: bigIntValue, + date: dateValue, + float: 1.23, + decimal: decimalValue, + boolean: true, + bytes: bufferValue, + bars: { + create: { bytes: barBufferValue }, + }, + }; + + const serialized = SuperJSON.serialize({ + include: { bars: true }, + data: { id: 1, ...createData }, + }); + + let r = await handleRequest({ + method: 'post', + path: '/foo/create', + query: {}, + prisma, + zodSchemas, + modelMeta, + requestBody: { + ...(serialized.json as any), + meta: { serialization: serialized.meta }, + }, + }); + expect(r.status).toBe(201); + expect(r.meta).toBeTruthy(); + const data: any = SuperJSON.deserialize({ json: r.data, meta: r.meta.serialization }); + expect(typeof data.bigInt).toBe('bigint'); + expect(Buffer.isBuffer(data.bytes)).toBeTruthy(); + expect(data.date instanceof Date).toBeTruthy(); + expect(Decimal.isDecimal(data.decimal)).toBeTruthy(); + expect(Buffer.isBuffer(data.bars[0].bytes)).toBeTruthy(); + + // find with filter not found + const serializedQ = SuperJSON.serialize({ + where: { + bigInt: { + gt: bigIntValue, + }, + }, + }); + r = await handleRequest({ + method: 'get', + path: '/foo/findFirst', + query: { + q: JSON.stringify(serializedQ.json), + meta: JSON.stringify({ serialization: serializedQ.meta }), + }, + prisma, + zodSchemas, + modelMeta, + }); + expect(r.status).toBe(200); + expect(r.data).toBeNull(); + + // find with filter found + const serializedQ1 = SuperJSON.serialize({ + where: { + bigInt: bigIntValue, + }, + }); + r = await handleRequest({ + method: 'get', + path: '/foo/findFirst', + query: { + q: JSON.stringify(serializedQ1.json), + meta: JSON.stringify({ serialization: serializedQ1.meta }), + }, + prisma, + zodSchemas, + modelMeta, + }); + expect(r.status).toBe(200); + expect(r.data).toBeTruthy(); + + // find with filter found + const serializedQ2 = SuperJSON.serialize({ + where: { + bars: { + some: { + bytes: barBufferValue, + }, + }, + }, + }); + r = await handleRequest({ + method: 'get', + path: '/foo/findFirst', + query: { + q: JSON.stringify(serializedQ2.json), + meta: JSON.stringify({ serialization: serializedQ2.meta }), + }, + prisma, + zodSchemas, + modelMeta, + }); + expect(r.status).toBe(200); + expect(r.data).toBeTruthy(); + + // find with filter not found + const serializedQ3 = SuperJSON.serialize({ + where: { + bars: { + none: { + bytes: barBufferValue, + }, + }, + }, + }); + r = await handleRequest({ + method: 'get', + path: '/foo/findFirst', + query: { + q: JSON.stringify(serializedQ3.json), + meta: JSON.stringify({ serialization: serializedQ3.meta }), + }, + prisma, + zodSchemas, + modelMeta, + }); + expect(r.status).toBe(200); + expect(r.data).toBeNull(); }); }); function makeHandler(zodSchemas?: ZodSchemas) { const _handler = RPCAPIHandler(); return async (args: any) => { - return _handler({ ...args, url: new URL(`http://localhost/${args.path}`), zodSchemas }); + const r = await _handler({ ...args, url: new URL(`http://localhost/${args.path}`), zodSchemas }); + return { + status: r.status, + body: r.body as any, + data: (r.body as any).data, + error: (r.body as any).error, + meta: (r.body as any).meta, + }; }; } diff --git a/packages/testtools/package.json b/packages/testtools/package.json index de0edccf6..672fd171c 100644 --- a/packages/testtools/package.json +++ b/packages/testtools/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/testtools", - "version": "1.0.0-beta.8", + "version": "1.0.0-beta.9", "description": "ZenStack Test Tools", "main": "index.js", "publishConfig": { @@ -18,18 +18,16 @@ "author": "", "license": "MIT", "dependencies": { - "@prisma/client": "^4.7.0", - "@prisma/generator-helper": "4.10.0", - "@prisma/internals": "4.10.0", + "@prisma/generator-helper": "^5.0.0", "@zenstackhq/language": "workspace:*", "@zenstackhq/runtime": "workspace:*", + "@zenstackhq/sdk": "workspace:*", "json5": "^2.2.3", - "prisma": "~4.7.0", "tmp": "^0.2.1", "zenstack": "workspace:*" }, "devDependencies": { - "@types/node": "^18.14.2", + "@types/node": "^18.0.0", "@types/tmp": "^0.2.3", "copyfiles": "^2.4.1", "rimraf": "^3.0.2", diff --git a/packages/testtools/src/schema.ts b/packages/testtools/src/schema.ts index 1dbf52434..49a53bb5e 100644 --- a/packages/testtools/src/schema.ts +++ b/packages/testtools/src/schema.ts @@ -1,16 +1,16 @@ /* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable @typescript-eslint/no-explicit-any */ import type { DMMF } from '@prisma/generator-helper'; -import { getDMMF } from '@prisma/internals'; import type { Model } from '@zenstackhq/language/ast'; import { withOmit, withPassword, withPolicy, withPresets, type AuthUser, type DbOperations } from '@zenstackhq/runtime'; +import { getDMMF } from '@zenstackhq/sdk'; import { execSync } from 'child_process'; import * as fs from 'fs'; +import json from 'json5'; import * as path from 'path'; import tmp from 'tmp'; import { loadDocument } from 'zenstack/cli/cli-util'; import prismaPlugin from 'zenstack/plugins/prisma'; -import json from 'json5'; /** * Use it to represent multiple files in a single string like this @@ -39,12 +39,14 @@ export type WeakDbClientContract = Record & { }; export function run(cmd: string, env?: Record, cwd?: string) { + const start = Date.now(); execSync(cmd, { stdio: 'pipe', encoding: 'utf-8', env: { ...process.env, DO_NOT_TRACK: '1', ...env }, cwd, }); + console.log('Execution took', Date.now() - start, 'ms', '-', cmd); } function normalizePath(p: string) { @@ -81,23 +83,54 @@ generator js { plugin zod { provider = '@core/zod' + modelOnly = true +} +`; + +const MODEL_PRELUDE_FULL_ZOD = ` +datasource db { + provider = 'sqlite' + url = 'file:./test.db' +} + +generator js { + provider = 'prisma-client-js' + previewFeatures = ['clientExtensions'] +} + +plugin zod { + provider = '@core/zod' + modelOnly = false } `; -export async function loadSchemaFromFile(schemaFile: string, addPrelude = true, pushDb = true, logPrismaQuery = false) { +export type SchemaLoadOptions = { + addPrelude?: boolean; + pushDb?: boolean; + fullZod?: boolean; + extraDependencies?: string[]; + compile?: boolean; + customSchemaFilePath?: string; + logPrismaQuery?: boolean; +}; + +const defaultOptions: SchemaLoadOptions = { + addPrelude: true, + pushDb: true, + fullZod: false, + extraDependencies: [], + compile: false, + logPrismaQuery: false, +}; + +export async function loadSchemaFromFile(schemaFile: string, options?: SchemaLoadOptions) { const content = fs.readFileSync(schemaFile, { encoding: 'utf-8' }); - return loadSchema(content, addPrelude, pushDb, [], false, undefined, logPrismaQuery); + return loadSchema(content, options); } -export async function loadSchema( - schema: string, - addPrelude = true, - pushDb = true, - extraDependencies: string[] = [], - compile = false, - customSchemaFilePath?: string, - logPrismaQuery = false -) { +export async function loadSchema(schema: string, options?: SchemaLoadOptions) { + const opt = { ...defaultOptions, ...options }; + const { name: projectRoot } = tmp.dirSync({ unsafeCleanup: true }); const root = getWorkspaceRoot(__dirname); @@ -129,9 +162,9 @@ export async function loadSchema( if (index === 0) { // The first file is the main schema file zmodelPath = path.join(projectRoot, fileName); - if (addPrelude) { + if (opt.addPrelude) { // plugin need to be added after import statement - fileContent = `${fileContent}\n${MODEL_PRELUDE}`; + fileContent = `${fileContent}\n${opt.fullZod ? MODEL_PRELUDE_FULL_ZOD : MODEL_PRELUDE}`; } } @@ -141,9 +174,9 @@ export async function loadSchema( }); } else { schema = schema.replaceAll('$projectRoot', projectRoot); - const content = addPrelude ? `${MODEL_PRELUDE}\n${schema}` : schema; - if (customSchemaFilePath) { - zmodelPath = path.join(projectRoot, customSchemaFilePath); + const content = opt.addPrelude ? `${opt.fullZod ? MODEL_PRELUDE_FULL_ZOD : MODEL_PRELUDE}\n${schema}` : schema; + if (opt.customSchemaFilePath) { + zmodelPath = path.join(projectRoot, opt.customSchemaFilePath); fs.mkdirSync(path.dirname(zmodelPath), { recursive: true }); fs.writeFileSync(zmodelPath, content); } else { @@ -153,7 +186,7 @@ export async function loadSchema( run('npm install'); - if (customSchemaFilePath) { + if (opt.customSchemaFilePath) { run(`npx zenstack generate --schema ${zmodelPath} --no-dependency-check`, { NODE_PATH: './node_modules', }); @@ -161,19 +194,19 @@ export async function loadSchema( run('npx zenstack generate --no-dependency-check', { NODE_PATH: './node_modules' }); } - if (pushDb) { + if (opt.pushDb) { run('npx prisma db push'); } const PrismaClient = require(path.join(projectRoot, 'node_modules/.prisma/client')).PrismaClient; const prisma = new PrismaClient({ log: ['info', 'warn', 'error'] }); - extraDependencies.forEach((dep) => { + opt.extraDependencies?.forEach((dep) => { console.log(`Installing dependency ${dep}`); run(`npm install ${dep}`); }); - if (compile) { + if (opt.compile) { console.log('Compiling...'); run('npx tsc --init'); @@ -213,11 +246,19 @@ export async function loadSchema( projectDir: projectRoot, prisma, withPolicy: (user?: AuthUser) => - withPolicy(prisma, { user }, { policy, modelMeta, zodSchemas, logPrismaQuery }), + withPolicy( + prisma, + { user }, + { policy, modelMeta, zodSchemas, logPrismaQuery: opt.logPrismaQuery } + ), withOmit: () => withOmit(prisma, { modelMeta }), withPassword: () => withPassword(prisma, { modelMeta }), withPresets: (user?: AuthUser) => - withPresets(prisma, { user }, { policy, modelMeta, zodSchemas, logPrismaQuery }), + withPresets( + prisma, + { user }, + { policy, modelMeta, zodSchemas, logPrismaQuery: opt.logPrismaQuery } + ), policy, modelMeta, zodSchemas, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1d9fde4de..058d0f821 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,15 @@ importers: '@changesets/cli': specifier: ^2.26.0 version: 2.26.0 + concurrently: + specifier: ^7.4.0 + version: 7.4.0 + replace-in-file: + specifier: ^7.0.1 + version: 7.0.1 + tsup: + specifier: ^7.1.0 + version: 7.1.0 packages/language: dependencies: @@ -38,8 +47,8 @@ importers: packages/plugins/openapi: dependencies: '@prisma/generator-helper': - specifier: 4.10.0 - version: 4.10.0 + specifier: ^5.0.0 + version: 5.0.0 '@zenstackhq/runtime': specifier: workspace:* version: link:../../runtime/dist @@ -68,18 +77,15 @@ importers: specifier: ^0.2.1 version: 0.2.1(zod@3.21.1) devDependencies: - '@prisma/internals': - specifier: 4.10.0 - version: 4.10.0 '@readme/openapi-parser': specifier: ^2.4.0 version: 2.4.0(openapi-types@12.1.0) '@types/jest': specifier: ^29.5.0 version: 29.5.0 - '@types/lower-case-first': - specifier: ^1.0.1 - version: 1.0.1 + '@types/node': + specifier: ^18.0.0 + version: 18.0.0 '@types/pluralize': specifier: ^0.0.29 version: 0.0.29 @@ -103,7 +109,7 @@ importers: version: 8.35.0 jest: specifier: ^29.5.0 - version: 29.5.0 + version: 29.5.0(@types/node@18.0.0) pluralize: specifier: ^8.0.0 version: 8.0.0 @@ -115,7 +121,7 @@ importers: version: 0.2.1 ts-jest: specifier: ^29.0.5 - version: 29.0.5(@babel/core@7.22.5)(jest@29.5.0)(typescript@4.9.5) + version: 29.0.5(@babel/core@7.22.5)(esbuild@0.18.13)(jest@29.5.0)(typescript@4.9.5) typescript: specifier: ^4.9.5 version: 4.9.5 @@ -127,8 +133,11 @@ importers: packages/plugins/swr: dependencies: '@prisma/generator-helper': - specifier: 4.10.0 - version: 4.10.0 + specifier: ^5.0.0 + version: 5.0.0 + '@zenstackhq/runtime': + specifier: workspace:* + version: link:../../runtime/dist '@zenstackhq/sdk': specifier: workspace:* version: link:../../sdk/dist @@ -141,9 +150,6 @@ importers: lower-case-first: specifier: ^2.0.2 version: 2.0.2 - superjson: - specifier: ^1.11.0 - version: 1.11.0 ts-morph: specifier: ^16.0.0 version: 16.0.0 @@ -153,22 +159,19 @@ importers: devDependencies: '@tanstack/react-query': specifier: ^4.28.0 - version: 4.28.0(react-dom@17.0.2)(react@17.0.2) + version: 4.28.0(react@18.2.0) '@types/jest': specifier: ^29.5.0 version: 29.5.0 - '@types/lower-case-first': - specifier: ^1.0.1 - version: 1.0.1 + '@types/node': + specifier: ^18.0.0 + version: 18.0.0 '@types/react': - specifier: ^18.0.26 - version: 18.0.26 + specifier: 18.2.0 + version: 18.2.0 '@types/tmp': specifier: ^0.2.3 version: 0.2.3 - '@types/upper-case-first': - specifier: ^1.1.2 - version: 1.1.2 '@zenstackhq/testtools': specifier: workspace:* version: link:../../testtools/dist @@ -177,22 +180,19 @@ importers: version: 2.4.1 jest: specifier: ^29.5.0 - version: 29.5.0 + version: 29.5.0(@types/node@18.0.0) react: - specifier: ^17.0.2 || ^18 - version: 17.0.2 - react-dom: - specifier: ^17.0.2 || ^18 - version: 17.0.2(react@17.0.2) + specifier: 18.2.0 + version: 18.2.0 rimraf: specifier: ^3.0.2 version: 3.0.2 swr: specifier: ^2.0.3 - version: 2.0.3(react@17.0.2) + version: 2.0.3(react@18.2.0) ts-jest: specifier: ^29.0.5 - version: 29.0.5(@babel/core@7.22.5)(jest@29.5.0)(typescript@4.9.4) + version: 29.0.5(@babel/core@7.22.9)(esbuild@0.18.13)(jest@29.5.0)(typescript@4.9.4) typescript: specifier: ^4.9.4 version: 4.9.4 @@ -201,8 +201,11 @@ importers: packages/plugins/tanstack-query: dependencies: '@prisma/generator-helper': - specifier: 4.10.0 - version: 4.10.0 + specifier: ^5.0.0 + version: 5.0.0 + '@zenstackhq/runtime': + specifier: workspace:* + version: link:../../runtime/dist '@zenstackhq/sdk': specifier: workspace:* version: link:../../sdk/dist @@ -226,26 +229,23 @@ importers: version: 2.0.2 devDependencies: '@tanstack/react-query': - specifier: ^4.29.7 - version: 4.29.7(react-dom@17.0.2)(react@17.0.2) + specifier: 4.29.7 + version: 4.29.7(react-dom@18.2.0)(react@18.2.0) '@tanstack/svelte-query': - specifier: ^4.29.7 + specifier: 4.29.7 version: 4.29.7(svelte@3.59.2) '@types/jest': specifier: ^29.5.0 version: 29.5.0 - '@types/lower-case-first': - specifier: ^1.0.1 - version: 1.0.1 + '@types/node': + specifier: ^18.0.0 + version: 18.0.0 '@types/react': - specifier: ^18.0.26 - version: 18.0.26 + specifier: 18.2.0 + version: 18.2.0 '@types/tmp': specifier: ^0.2.3 version: 0.2.3 - '@types/upper-case-first': - specifier: ^1.1.2 - version: 1.1.2 '@zenstackhq/testtools': specifier: workspace:* version: link:../../testtools/dist @@ -254,22 +254,19 @@ importers: version: 2.4.1 jest: specifier: ^29.5.0 - version: 29.5.0 + version: 29.5.0(@types/node@18.0.0) react: - specifier: ^17.0.2 || ^18 - version: 17.0.2 - react-dom: - specifier: ^17.0.2 || ^18 - version: 17.0.2(react@17.0.2) + specifier: 18.2.0 + version: 18.2.0 rimraf: specifier: ^3.0.2 version: 3.0.2 swr: specifier: ^2.0.3 - version: 2.0.3(react@17.0.2) + version: 2.0.3(react@18.2.0) ts-jest: specifier: ^29.0.5 - version: 29.0.5(@babel/core@7.22.5)(jest@29.5.0)(typescript@4.9.4) + version: 29.0.5(@babel/core@7.22.9)(esbuild@0.18.13)(jest@29.5.0)(typescript@4.9.4) typescript: specifier: ^4.9.4 version: 4.9.4 @@ -278,11 +275,8 @@ importers: packages/plugins/trpc: dependencies: '@prisma/generator-helper': - specifier: 4.10.0 - version: 4.10.0 - '@prisma/internals': - specifier: 4.10.0 - version: 4.10.0 + specifier: ^5.0.0 + version: 5.0.0 '@zenstackhq/sdk': specifier: workspace:* version: link:../../sdk/dist @@ -310,19 +304,19 @@ importers: devDependencies: '@trpc/next': specifier: ^10.32.0 - version: 10.32.0(@tanstack/react-query@4.29.19)(@trpc/client@10.32.0)(@trpc/react-query@10.32.0)(@trpc/server@10.32.0)(next@13.4.7)(react-dom@18.2.0)(react@18.2.0) + version: 10.32.0(@tanstack/react-query@4.29.7)(@trpc/client@10.32.0)(@trpc/react-query@10.32.0)(@trpc/server@10.32.0)(next@13.4.7)(react-dom@18.2.0)(react@18.2.0) '@trpc/react-query': specifier: ^10.32.0 - version: 10.32.0(@tanstack/react-query@4.29.19)(@trpc/client@10.32.0)(@trpc/server@10.32.0)(react-dom@18.2.0)(react@18.2.0) + version: 10.32.0(@tanstack/react-query@4.29.7)(@trpc/client@10.32.0)(@trpc/server@10.32.0)(react-dom@18.2.0)(react@18.2.0) '@trpc/server': specifier: ^10.32.0 version: 10.32.0 '@types/jest': specifier: ^29.5.0 version: 29.5.0 - '@types/lower-case-first': - specifier: ^1.0.1 - version: 1.0.1 + '@types/node': + specifier: ^18.0.0 + version: 18.0.0 '@types/prettier': specifier: ^2.7.2 version: 2.7.2 @@ -334,16 +328,16 @@ importers: version: 2.4.1 jest: specifier: ^29.5.0 - version: 29.5.0 + version: 29.5.0(@types/node@18.0.0) next: specifier: ^13.4.7 - version: 13.4.7(@babel/core@7.22.5)(@opentelemetry/api@1.4.1)(react-dom@18.2.0)(react@18.2.0) + version: 13.4.7(@babel/core@7.22.9)(react-dom@18.2.0)(react@18.2.0) rimraf: specifier: ^3.0.2 version: 3.0.2 ts-jest: specifier: ^29.0.5 - version: 29.0.5(@babel/core@7.22.5)(jest@29.5.0)(typescript@4.9.4) + version: 29.0.5(@babel/core@7.22.9)(esbuild@0.18.13)(jest@29.5.0)(typescript@4.9.4) typescript: specifier: ^4.9.4 version: 4.9.4 @@ -360,6 +354,9 @@ importers: bcryptjs: specifier: ^2.4.3 version: 2.4.3 + buffer: + specifier: ^6.0.3 + version: 6.0.3 change-case: specifier: ^4.1.2 version: 4.1.2 @@ -394,18 +391,12 @@ importers: specifier: ^0.2.1 version: 0.2.1(zod@3.21.1) devDependencies: - '@prisma/client': - specifier: ^4.0.0 - version: 4.0.0 '@types/jest': specifier: ^29.5.0 version: 29.5.0 - '@types/lower-case-first': - specifier: ^1.0.1 - version: 1.0.1 '@types/node': - specifier: ^14.18.29 - version: 14.18.29 + specifier: ^18.0.0 + version: 18.0.0 '@types/pluralize': specifier: ^0.0.29 version: 0.0.29 @@ -426,11 +417,8 @@ importers: specifier: ^2.2.0 version: 2.2.0 '@prisma/generator-helper': - specifier: 4.10.0 - version: 4.10.0 - '@prisma/internals': - specifier: 4.10.0 - version: 4.10.0 + specifier: ^5.0.0 + version: 5.0.0 '@zenstackhq/language': specifier: workspace:* version: link:../language/dist @@ -522,12 +510,9 @@ importers: '@types/jest': specifier: ^29.5.0 version: 29.5.0 - '@types/lower-case-first': - specifier: ^1.0.1 - version: 1.0.1 '@types/node': - specifier: ^14.18.32 - version: 14.18.32 + specifier: ^18.0.0 + version: 18.0.0 '@types/pluralize': specifier: ^0.0.29 version: 0.0.29 @@ -540,9 +525,6 @@ importers: '@types/tmp': specifier: ^0.2.3 version: 0.2.3 - '@types/upper-case-first': - specifier: ^1.1.2 - version: 1.1.2 '@types/uuid': specifier: ^8.3.4 version: 8.3.4 @@ -581,10 +563,7 @@ importers: version: 27.1.7(@typescript-eslint/eslint-plugin@5.42.0)(eslint@8.27.0)(jest@29.5.0)(typescript@4.8.4) jest: specifier: ^29.5.0 - version: 29.5.0(@types/node@14.18.32)(ts-node@10.9.1) - prisma: - specifier: ^4.0.0 - version: 4.0.0 + version: 29.5.0(@types/node@18.0.0)(ts-node@10.9.1) renamer: specifier: ^4.0.0 version: 4.0.0 @@ -596,10 +575,10 @@ importers: version: 0.2.1 ts-jest: specifier: ^29.0.3 - version: 29.0.3(@babel/core@7.22.5)(esbuild@0.15.12)(jest@29.5.0)(typescript@4.8.4) + version: 29.0.3(@babel/core@7.22.9)(esbuild@0.15.12)(jest@29.5.0)(typescript@4.8.4) ts-node: specifier: ^10.9.1 - version: 10.9.1(@types/node@14.18.32)(typescript@4.8.4) + version: 10.9.1(@types/node@18.0.0)(typescript@4.8.4) tsc-alias: specifier: ^1.7.0 version: 1.7.0 @@ -614,8 +593,14 @@ importers: packages/sdk: dependencies: '@prisma/generator-helper': + specifier: ^5.0.0 + version: 5.0.0 + '@prisma/internals': specifier: 4.10.0 version: 4.10.0 + '@prisma/internals-v5': + specifier: npm:@prisma/internals@^5.0.0 + version: /@prisma/internals@5.0.0 '@zenstackhq/language': specifier: workspace:* version: link:../language/dist @@ -625,10 +610,16 @@ importers: prettier: specifier: ^2.8.3 version: 2.8.3 + semver: + specifier: ^7.3.8 + version: 7.5.3 ts-morph: specifier: ^16.0.0 version: 16.0.0 devDependencies: + '@types/semver': + specifier: ^7.3.13 + version: 7.5.0 copyfiles: specifier: ^2.4.1 version: 2.4.1 @@ -678,7 +669,7 @@ importers: devDependencies: '@sveltejs/kit': specifier: 1.21.0 - version: 1.21.0(svelte@3.59.2)(vite@4.3.9) + version: 1.21.0(svelte@4.0.5)(vite@4.4.4) '@types/body-parser': specifier: ^1.19.2 version: 1.19.2 @@ -688,15 +679,9 @@ importers: '@types/jest': specifier: ^29.5.0 version: 29.5.0 - '@types/lower-case-first': - specifier: ^1.0.1 - version: 1.0.1 '@types/supertest': specifier: ^2.0.12 version: 2.0.12 - '@types/upper-case-first': - specifier: ^1.1.2 - version: 1.1.2 '@zenstackhq/testtools': specifier: workspace:* version: link:../testtools/dist @@ -706,6 +691,9 @@ importers: copyfiles: specifier: ^2.4.1 version: 2.4.1 + decimal.js: + specifier: ^10.4.2 + version: 10.4.2 express: specifier: ^4.18.2 version: 4.18.2 @@ -720,10 +708,10 @@ importers: version: 3.0.0 jest: specifier: ^29.5.0 - version: 29.5.0 + version: 29.5.0(@types/node@18.0.0) next: specifier: ^13.4.5 - version: 13.4.5(@babel/core@7.22.5)(react-dom@18.2.0)(react@18.2.0) + version: 13.4.5(@babel/core@7.22.9)(react-dom@18.2.0)(react@18.2.0) rimraf: specifier: ^3.0.2 version: 3.0.2 @@ -732,7 +720,7 @@ importers: version: 6.3.3 ts-jest: specifier: ^29.0.5 - version: 29.0.5(@babel/core@7.22.5)(jest@29.5.0)(typescript@4.9.4) + version: 29.0.5(@babel/core@7.22.9)(esbuild@0.18.13)(jest@29.5.0)(typescript@4.9.4) typescript: specifier: ^4.9.4 version: 4.9.4 @@ -740,27 +728,21 @@ importers: packages/testtools: dependencies: - '@prisma/client': - specifier: ^4.7.0 - version: 4.7.0(prisma@4.7.0) '@prisma/generator-helper': - specifier: 4.10.0 - version: 4.10.0 - '@prisma/internals': - specifier: 4.10.0 - version: 4.10.0 + specifier: ^5.0.0 + version: 5.0.0 '@zenstackhq/language': specifier: workspace:* version: link:../language/dist '@zenstackhq/runtime': specifier: workspace:* version: link:../runtime/dist + '@zenstackhq/sdk': + specifier: workspace:* + version: link:../sdk/dist json5: specifier: ^2.2.3 version: 2.2.3 - prisma: - specifier: ~4.7.0 - version: 4.7.0 tmp: specifier: ^0.2.1 version: 0.2.1 @@ -769,8 +751,8 @@ importers: version: link:../schema/dist devDependencies: '@types/node': - specifier: ^18.14.2 - version: 18.14.2 + specifier: ^18.0.0 + version: 18.0.0 '@types/tmp': specifier: ^0.2.3 version: 0.2.3 @@ -787,12 +769,9 @@ importers: tests/integration: dependencies: - '@prisma/client': - specifier: ^4.7.0 - version: 4.7.0(prisma@4.7.0) '@types/node': - specifier: ^14.18.29 - version: 14.18.29 + specifier: ^18.0.0 + version: 18.0.0 '@zenstackhq/sdk': specifier: workspace:* version: link:../../packages/sdk/dist @@ -853,25 +832,22 @@ importers: version: 11.1.0 jest: specifier: ^29.5.0 - version: 29.5.0(@types/node@14.18.29)(ts-node@10.9.1) + version: 29.5.0(@types/node@18.0.0)(ts-node@10.9.1) jest-fetch-mock: specifier: ^3.0.3 version: 3.0.3 next: specifier: ^12.3.1 - version: 12.3.1(@babel/core@7.22.5)(react-dom@18.2.0)(react@18.2.0) - prisma: - specifier: ~4.7.0 - version: 4.7.0 + version: 12.3.1(@babel/core@7.22.9)(react-dom@18.2.0)(react@18.2.0) tmp: specifier: ^0.2.1 version: 0.2.1 ts-jest: specifier: ^29.0.1 - version: 29.0.1(@babel/core@7.22.5)(jest@29.5.0)(typescript@4.6.2) + version: 29.0.1(@babel/core@7.22.9)(esbuild@0.18.13)(jest@29.5.0)(typescript@4.6.2) ts-node: specifier: ^10.9.1 - version: 10.9.1(@types/node@14.18.29)(typescript@4.6.2) + version: 10.9.1(@types/node@18.0.0)(typescript@4.6.2) typescript: specifier: ^4.6.2 version: 4.6.2 @@ -897,6 +873,11 @@ packages: '@jridgewell/trace-mapping': 0.3.18 dev: true + /@antfu/ni@0.21.4: + resolution: {integrity: sha512-O0Uv9LbLDSoEg26fnMDdDRiPwFJnQSoD4WnrflDwKCJm8Cx/0mV4cGxwBLXan5mGIrpK4Dd7vizf4rQm0QCEAA==} + hasBin: true + dev: false + /@apidevtools/openapi-schemas@2.1.0: resolution: {integrity: sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==} engines: {node: '>=10'} @@ -917,6 +898,11 @@ packages: engines: {node: '>=6.9.0'} dev: true + /@babel/compat-data@7.22.9: + resolution: {integrity: sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==} + engines: {node: '>=6.9.0'} + dev: true + /@babel/core@7.22.5: resolution: {integrity: sha512-SBuTAjg91A3eKOvD+bPEz3LlhHZRNu1nFOVts9lzDJTXshHTjII0BAtDS3Y2DAkdZdDKWVZGVwkDfc4Clxn1dg==} engines: {node: '>=6.9.0'} @@ -935,7 +921,30 @@ packages: debug: 4.3.4 gensync: 1.0.0-beta.2 json5: 2.2.3 - semver: 6.3.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/core@7.22.9: + resolution: {integrity: sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w==} + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.2.1 + '@babel/code-frame': 7.22.5 + '@babel/generator': 7.22.9 + '@babel/helper-compilation-targets': 7.22.9(@babel/core@7.22.9) + '@babel/helper-module-transforms': 7.22.9(@babel/core@7.22.9) + '@babel/helpers': 7.22.6 + '@babel/parser': 7.22.7 + '@babel/template': 7.22.5 + '@babel/traverse': 7.22.8 + '@babel/types': 7.22.5 + convert-source-map: 1.9.0 + debug: 4.3.4 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 transitivePeerDependencies: - supports-color dev: true @@ -950,6 +959,16 @@ packages: jsesc: 2.5.2 dev: true + /@babel/generator@7.22.9: + resolution: {integrity: sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.22.5 + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.18 + jsesc: 2.5.2 + dev: true + /@babel/helper-compilation-targets@7.22.5(@babel/core@7.22.5): resolution: {integrity: sha512-Ji+ywpHeuqxB8WDxraCiqR0xfhYjiDE/e6k7FuIaANnoOFxAHskHChz4vA1mJC9Lbm01s1PVAGhQY4FUKSkGZw==} engines: {node: '>=6.9.0'} @@ -961,7 +980,21 @@ packages: '@babel/helper-validator-option': 7.22.5 browserslist: 4.21.9 lru-cache: 5.1.1 - semver: 6.3.0 + semver: 6.3.1 + dev: true + + /@babel/helper-compilation-targets@7.22.9(@babel/core@7.22.9): + resolution: {integrity: sha512-7qYrNM6HjpnPHJbopxmb8hSPoZ0gsX8IvUS32JGVoy+pU9e5N0nLr1VjJoR6kA4d9dmGLxNYOjeB8sUDal2WMw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/compat-data': 7.22.9 + '@babel/core': 7.22.9 + '@babel/helper-validator-option': 7.22.5 + browserslist: 4.21.9 + lru-cache: 5.1.1 + semver: 6.3.1 dev: true /@babel/helper-environment-visitor@7.22.5: @@ -1007,6 +1040,20 @@ packages: - supports-color dev: true + /@babel/helper-module-transforms@7.22.9(@babel/core@7.22.9): + resolution: {integrity: sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.9 + '@babel/helper-environment-visitor': 7.22.5 + '@babel/helper-module-imports': 7.22.5 + '@babel/helper-simple-access': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-validator-identifier': 7.22.5 + dev: true + /@babel/helper-plugin-utils@7.22.5: resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} engines: {node: '>=6.9.0'} @@ -1026,6 +1073,13 @@ packages: '@babel/types': 7.22.5 dev: true + /@babel/helper-split-export-declaration@7.22.6: + resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.22.5 + dev: true + /@babel/helper-string-parser@7.22.5: resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==} engines: {node: '>=6.9.0'} @@ -1051,6 +1105,17 @@ packages: - supports-color dev: true + /@babel/helpers@7.22.6: + resolution: {integrity: sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.22.5 + '@babel/traverse': 7.22.8 + '@babel/types': 7.22.5 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/highlight@7.22.5: resolution: {integrity: sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==} engines: {node: '>=6.9.0'} @@ -1067,6 +1132,14 @@ packages: '@babel/types': 7.22.5 dev: true + /@babel/parser@7.22.7: + resolution: {integrity: sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.22.5 + dev: true + /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.22.5): resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} peerDependencies: @@ -1230,6 +1303,24 @@ packages: - supports-color dev: true + /@babel/traverse@7.22.8: + resolution: {integrity: sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.22.5 + '@babel/generator': 7.22.9 + '@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.7 + '@babel/types': 7.22.5 + debug: 4.3.4 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/types@7.22.5: resolution: {integrity: sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==} engines: {node: '>=6.9.0'} @@ -1462,6 +1553,24 @@ packages: dev: true optional: true + /@esbuild/android-arm64@0.18.13: + resolution: {integrity: sha512-j7NhycJUoUAG5kAzGf4fPWfd17N6SM3o1X6MlXVqfHvs2buFraCJzos9vbeWjLxOyBKHyPOnuCuipbhvbYtTAg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm64@0.18.14: + resolution: {integrity: sha512-rZ2v+Luba5/3D6l8kofWgTnqE+qsC/L5MleKIKFyllHTKHrNBMqeRCnZI1BtRx8B24xMYxeU32iIddRQqMsOsg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/android-arm@0.15.12: resolution: {integrity: sha512-IC7TqIqiyE0MmvAhWkl/8AEzpOtbhRNDo7aph47We1NbE5w2bt/Q+giAhe0YYeVpYnIhGMcuZY92qDK6dQauvA==} engines: {node: '>=12'} @@ -1480,162 +1589,486 @@ packages: dev: true optional: true - /@esbuild/android-x64@0.17.19: - resolution: {integrity: sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==} + /@esbuild/android-arm@0.18.13: + resolution: {integrity: sha512-KwqFhxRFMKZINHzCqf8eKxE0XqWlAVPRxwy6rc7CbVFxzUWB2sA/s3hbMZeemPdhN3fKBkqOaFhTbS8xJXYIWQ==} engines: {node: '>=12'} - cpu: [x64] + cpu: [arm] os: [android] requiresBuild: true dev: true optional: true - /@esbuild/darwin-arm64@0.17.19: - resolution: {integrity: sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==} + /@esbuild/android-arm@0.18.14: + resolution: {integrity: sha512-blODaaL+lngG5bdK/t4qZcQvq2BBqrABmYwqPPcS5VRxrCSGHb9R/rA3fqxh7R18I7WU4KKv+NYkt22FDfalcg==} engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] + cpu: [arm] + os: [android] requiresBuild: true dev: true optional: true - /@esbuild/darwin-x64@0.17.19: - resolution: {integrity: sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==} + /@esbuild/android-x64@0.17.19: + resolution: {integrity: sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==} engines: {node: '>=12'} cpu: [x64] - os: [darwin] + os: [android] requiresBuild: true dev: true optional: true - /@esbuild/freebsd-arm64@0.17.19: - resolution: {integrity: sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==} + /@esbuild/android-x64@0.18.13: + resolution: {integrity: sha512-M2eZkRxR6WnWfVELHmv6MUoHbOqnzoTVSIxgtsyhm/NsgmL+uTmag/VVzdXvmahak1I6sOb1K/2movco5ikDJg==} engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] + cpu: [x64] + os: [android] requiresBuild: true dev: true optional: true - /@esbuild/freebsd-x64@0.17.19: - resolution: {integrity: sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==} + /@esbuild/android-x64@0.18.14: + resolution: {integrity: sha512-qSwh8y38QKl+1Iqg+YhvCVYlSk3dVLk9N88VO71U4FUjtiSFylMWK3Ugr8GC6eTkkP4Tc83dVppt2n8vIdlSGg==} engines: {node: '>=12'} cpu: [x64] - os: [freebsd] + os: [android] requiresBuild: true dev: true optional: true - /@esbuild/linux-arm64@0.17.19: - resolution: {integrity: sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==} + /@esbuild/darwin-arm64@0.17.19: + resolution: {integrity: sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==} engines: {node: '>=12'} cpu: [arm64] - os: [linux] + os: [darwin] requiresBuild: true dev: true optional: true - /@esbuild/linux-arm@0.17.19: - resolution: {integrity: sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==} + /@esbuild/darwin-arm64@0.18.13: + resolution: {integrity: sha512-f5goG30YgR1GU+fxtaBRdSW3SBG9pZW834Mmhxa6terzcboz7P2R0k4lDxlkP7NYRIIdBbWp+VgwQbmMH4yV7w==} engines: {node: '>=12'} - cpu: [arm] - os: [linux] + cpu: [arm64] + os: [darwin] requiresBuild: true dev: true optional: true - /@esbuild/linux-ia32@0.17.19: - resolution: {integrity: sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==} + /@esbuild/darwin-arm64@0.18.14: + resolution: {integrity: sha512-9Hl2D2PBeDYZiNbnRKRWuxwHa9v5ssWBBjisXFkVcSP5cZqzZRFBUWEQuqBHO4+PKx4q4wgHoWtfQ1S7rUqJ2Q==} engines: {node: '>=12'} - cpu: [ia32] - os: [linux] + cpu: [arm64] + os: [darwin] requiresBuild: true dev: true optional: true - /@esbuild/linux-loong64@0.15.12: - resolution: {integrity: sha512-tZEowDjvU7O7I04GYvWQOS4yyP9E/7YlsB0jjw1Ycukgr2ycEzKyIk5tms5WnLBymaewc6VmRKnn5IJWgK4eFw==} + /@esbuild/darwin-x64@0.17.19: + resolution: {integrity: sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==} engines: {node: '>=12'} - cpu: [loong64] - os: [linux] + cpu: [x64] + os: [darwin] requiresBuild: true dev: true optional: true - /@esbuild/linux-loong64@0.17.19: - resolution: {integrity: sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==} + /@esbuild/darwin-x64@0.18.13: + resolution: {integrity: sha512-RIrxoKH5Eo+yE5BtaAIMZaiKutPhZjw+j0OCh8WdvKEKJQteacq0myZvBDLU+hOzQOZWJeDnuQ2xgSScKf1Ovw==} engines: {node: '>=12'} - cpu: [loong64] - os: [linux] + cpu: [x64] + os: [darwin] requiresBuild: true dev: true optional: true - /@esbuild/linux-mips64el@0.17.19: - resolution: {integrity: sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==} + /@esbuild/darwin-x64@0.18.14: + resolution: {integrity: sha512-ZnI3Dg4ElQ6tlv82qLc/UNHtFsgZSKZ7KjsUNAo1BF1SoYDjkGKHJyCrYyWjFecmXpvvG/KJ9A/oe0H12odPLQ==} engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] + cpu: [x64] + os: [darwin] requiresBuild: true dev: true optional: true - /@esbuild/linux-ppc64@0.17.19: - resolution: {integrity: sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==} + /@esbuild/freebsd-arm64@0.17.19: + resolution: {integrity: sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==} engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] + cpu: [arm64] + os: [freebsd] requiresBuild: true dev: true optional: true - /@esbuild/linux-riscv64@0.17.19: - resolution: {integrity: sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==} + /@esbuild/freebsd-arm64@0.18.13: + resolution: {integrity: sha512-AfRPhHWmj9jGyLgW/2FkYERKmYR+IjYxf2rtSLmhOrPGFh0KCETFzSjx/JX/HJnvIqHt/DRQD/KAaVsUKoI3Xg==} engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] + cpu: [arm64] + os: [freebsd] requiresBuild: true dev: true optional: true - /@esbuild/linux-s390x@0.17.19: - resolution: {integrity: sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==} + /@esbuild/freebsd-arm64@0.18.14: + resolution: {integrity: sha512-h3OqR80Da4oQCIa37zl8tU5MwHQ7qgPV0oVScPfKJK21fSRZEhLE4IIVpmcOxfAVmqjU6NDxcxhYaM8aDIGRLw==} engines: {node: '>=12'} - cpu: [s390x] - os: [linux] + cpu: [arm64] + os: [freebsd] requiresBuild: true dev: true optional: true - /@esbuild/linux-x64@0.17.19: - resolution: {integrity: sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==} + /@esbuild/freebsd-x64@0.17.19: + resolution: {integrity: sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==} engines: {node: '>=12'} cpu: [x64] - os: [linux] + os: [freebsd] requiresBuild: true dev: true optional: true - /@esbuild/netbsd-x64@0.17.19: - resolution: {integrity: sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==} + /@esbuild/freebsd-x64@0.18.13: + resolution: {integrity: sha512-pGzWWZJBInhIgdEwzn8VHUBang8UvFKsvjDkeJ2oyY5gZtAM6BaxK0QLCuZY+qoj/nx/lIaItH425rm/hloETA==} engines: {node: '>=12'} cpu: [x64] - os: [netbsd] + os: [freebsd] requiresBuild: true dev: true optional: true - /@esbuild/openbsd-x64@0.17.19: - resolution: {integrity: sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==} + /@esbuild/freebsd-x64@0.18.14: + resolution: {integrity: sha512-ha4BX+S6CZG4BoH9tOZTrFIYC1DH13UTCRHzFc3GWX74nz3h/N6MPF3tuR3XlsNjMFUazGgm35MPW5tHkn2lzQ==} engines: {node: '>=12'} cpu: [x64] - os: [openbsd] + os: [freebsd] requiresBuild: true dev: true optional: true - /@esbuild/sunos-x64@0.17.19: - resolution: {integrity: sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==} - engines: {node: '>=12'} + /@esbuild/linux-arm64@0.17.19: + resolution: {integrity: sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64@0.18.13: + resolution: {integrity: sha512-hCzZbVJEHV7QM77fHPv2qgBcWxgglGFGCxk6KfQx6PsVIdi1u09X7IvgE9QKqm38OpkzaAkPnnPqwRsltvLkIQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64@0.18.14: + resolution: {integrity: sha512-IXORRe22In7U65NZCzjwAUc03nn8SDIzWCnfzJ6t/8AvGx5zBkcLfknI+0P+hhuftufJBmIXxdSTbzWc8X/V4w==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm@0.17.19: + resolution: {integrity: sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm@0.18.13: + resolution: {integrity: sha512-4iMxLRMCxGyk7lEvkkvrxw4aJeC93YIIrfbBlUJ062kilUUnAiMb81eEkVvCVoh3ON283ans7+OQkuy1uHW+Hw==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm@0.18.14: + resolution: {integrity: sha512-5+7vehI1iqru5WRtJyU2XvTOvTGURw3OZxe3YTdE9muNNIdmKAVmSHpB3Vw2LazJk2ifEdIMt/wTWnVe5V98Kg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32@0.17.19: + resolution: {integrity: sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32@0.18.13: + resolution: {integrity: sha512-I3OKGbynl3AAIO6onXNrup/ttToE6Rv2XYfFgLK/wnr2J+1g+7k4asLrE+n7VMhaqX+BUnyWkCu27rl+62Adug==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32@0.18.14: + resolution: {integrity: sha512-BfHlMa0nibwpjG+VXbOoqJDmFde4UK2gnW351SQ2Zd4t1N3zNdmUEqRkw/srC1Sa1DRBE88Dbwg4JgWCbNz/FQ==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.15.12: + resolution: {integrity: sha512-tZEowDjvU7O7I04GYvWQOS4yyP9E/7YlsB0jjw1Ycukgr2ycEzKyIk5tms5WnLBymaewc6VmRKnn5IJWgK4eFw==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.17.19: + resolution: {integrity: sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.18.13: + resolution: {integrity: sha512-8pcKDApAsKc6WW51ZEVidSGwGbebYw2qKnO1VyD8xd6JN0RN6EUXfhXmDk9Vc4/U3Y4AoFTexQewQDJGsBXBpg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.18.14: + resolution: {integrity: sha512-j2/Ex++DRUWIAaUDprXd3JevzGtZ4/d7VKz+AYDoHZ3HjJzCyYBub9CU1wwIXN+viOP0b4VR3RhGClsvyt/xSw==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el@0.17.19: + resolution: {integrity: sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el@0.18.13: + resolution: {integrity: sha512-6GU+J1PLiVqWx8yoCK4Z0GnfKyCGIH5L2KQipxOtbNPBs+qNDcMJr9euxnyJ6FkRPyMwaSkjejzPSISD9hb+gg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el@0.18.14: + resolution: {integrity: sha512-qn2+nc+ZCrJmiicoAnJXJJkZWt8Nwswgu1crY7N+PBR8ChBHh89XRxj38UU6Dkthl2yCVO9jWuafZ24muzDC/A==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64@0.17.19: + resolution: {integrity: sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64@0.18.13: + resolution: {integrity: sha512-pfn/OGZ8tyR8YCV7MlLl5hAit2cmS+j/ZZg9DdH0uxdCoJpV7+5DbuXrR+es4ayRVKIcfS9TTMCs60vqQDmh+w==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64@0.18.14: + resolution: {integrity: sha512-aGzXzd+djqeEC5IRkDKt3kWzvXoXC6K6GyYKxd+wsFJ2VQYnOWE954qV2tvy5/aaNrmgPTb52cSCHFE+Z7Z0yg==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64@0.17.19: + resolution: {integrity: sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64@0.18.13: + resolution: {integrity: sha512-aIbhU3LPg0lOSCfVeGHbmGYIqOtW6+yzO+Nfv57YblEK01oj0mFMtvDJlOaeAZ6z0FZ9D13oahi5aIl9JFphGg==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64@0.18.14: + resolution: {integrity: sha512-8C6vWbfr0ygbAiMFLS6OPz0BHvApkT2gCboOGV76YrYw+sD/MQJzyITNsjZWDXJwPu9tjrFQOVG7zijRzBCnLw==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x@0.17.19: + resolution: {integrity: sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x@0.18.13: + resolution: {integrity: sha512-Pct1QwF2sp+5LVi4Iu5Y+6JsGaV2Z2vm4O9Dd7XZ5tKYxEHjFtb140fiMcl5HM1iuv6xXO8O1Vrb1iJxHlv8UA==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x@0.18.14: + resolution: {integrity: sha512-G/Lf9iu8sRMM60OVGOh94ZW2nIStksEcITkXdkD09/T6QFD/o+g0+9WVyR/jajIb3A0LvBJ670tBnGe1GgXMgw==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64@0.17.19: + resolution: {integrity: sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64@0.18.13: + resolution: {integrity: sha512-zTrIP0KzYP7O0+3ZnmzvUKgGtUvf4+piY8PIO3V8/GfmVd3ZyHJGz7Ht0np3P1wz+I8qJ4rjwJKqqEAbIEPngA==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64@0.18.14: + resolution: {integrity: sha512-TBgStYBQaa3EGhgqIDM+ECnkreb0wkcKqL7H6m+XPcGUoU4dO7dqewfbm0mWEQYH3kzFHrzjOFNpSAVzDZRSJw==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64@0.17.19: + resolution: {integrity: sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64@0.18.13: + resolution: {integrity: sha512-I6zs10TZeaHDYoGxENuksxE1sxqZpCp+agYeW039yqFwh3MgVvdmXL5NMveImOC6AtpLvE4xG5ujVic4NWFIDQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64@0.18.14: + resolution: {integrity: sha512-stvCcjyCQR2lMTroqNhAbvROqRjxPEq0oQ380YdXxA81TaRJEucH/PzJ/qsEtsHgXlWFW6Ryr/X15vxQiyRXVg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64@0.17.19: + resolution: {integrity: sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64@0.18.13: + resolution: {integrity: sha512-W5C5nczhrt1y1xPG5bV+0M12p2vetOGlvs43LH8SopQ3z2AseIROu09VgRqydx5qFN7y9qCbpgHLx0kb0TcW7g==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64@0.18.14: + resolution: {integrity: sha512-apAOJF14CIsN5ht1PA57PboEMsNV70j3FUdxLmA2liZ20gEQnfTG5QU0FhENo5nwbTqCB2O3WDsXAihfODjHYw==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.17.19: + resolution: {integrity: sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.18.13: + resolution: {integrity: sha512-X/xzuw4Hzpo/yq3YsfBbIsipNgmsm8mE/QeWbdGdTTeZ77fjxI2K0KP3AlhZ6gU3zKTw1bKoZTuKLnqcJ537qw==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.18.14: + resolution: {integrity: sha512-fYRaaS8mDgZcGybPn2MQbn1ZNZx+UXFSUoS5Hd2oEnlsyUcr/l3c6RnXf1bLDRKKdLRSabTmyCy7VLQ7VhGdOQ==} + engines: {node: '>=12'} cpu: [x64] os: [sunos] requiresBuild: true @@ -1651,6 +2084,24 @@ packages: dev: true optional: true + /@esbuild/win32-arm64@0.18.13: + resolution: {integrity: sha512-4CGYdRQT/ILd+yLLE5i4VApMPfGE0RPc/wFQhlluDQCK09+b4JDbxzzjpgQqTPrdnP7r5KUtGVGZYclYiPuHrw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64@0.18.14: + resolution: {integrity: sha512-1c44RcxKEJPrVj62XdmYhxXaU/V7auELCmnD+Ri+UCt+AGxTvzxl9uauQhrFso8gj6ZV1DaORV0sT9XSHOAk8Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-ia32@0.17.19: resolution: {integrity: sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==} engines: {node: '>=12'} @@ -1660,6 +2111,24 @@ packages: dev: true optional: true + /@esbuild/win32-ia32@0.18.13: + resolution: {integrity: sha512-D+wKZaRhQI+MUGMH+DbEr4owC2D7XnF+uyGiZk38QbgzLcofFqIOwFs7ELmIeU45CQgfHNy9Q+LKW3cE8g37Kg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32@0.18.14: + resolution: {integrity: sha512-EXAFttrdAxZkFQmpvcAQ2bywlWUsONp/9c2lcfvPUhu8vXBBenCXpoq9YkUvVP639ld3YGiYx0YUQ6/VQz3Maw==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-x64@0.17.19: resolution: {integrity: sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==} engines: {node: '>=12'} @@ -1669,6 +2138,24 @@ packages: dev: true optional: true + /@esbuild/win32-x64@0.18.13: + resolution: {integrity: sha512-iVl6lehAfJS+VmpF3exKpNQ8b0eucf5VWfzR8S7xFve64NBNz2jPUgx1X93/kfnkfgP737O+i1k54SVQS7uVZA==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64@0.18.14: + resolution: {integrity: sha512-K0QjGbcskx+gY+qp3v4/940qg8JitpXbdxFhRDA1aYoNaPff88+aEwoq45aqJ+ogpxQxmU0ZTjgnrQD/w8iiUg==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@eslint-community/eslint-utils@4.4.0(eslint@8.27.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1796,7 +2283,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.5.0 - '@types/node': 14.18.32 + '@types/node': 18.0.0 chalk: 4.1.2 jest-message-util: 29.5.0 jest-util: 29.5.0 @@ -1817,14 +2304,14 @@ packages: '@jest/test-result': 29.5.0 '@jest/transform': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 14.18.29 + '@types/node': 18.0.0 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.8.0 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.5.0 - jest-config: 29.5.0(@types/node@14.18.29)(ts-node@10.9.1) + jest-config: 29.5.0(@types/node@18.0.0)(ts-node@10.9.1) jest-haste-map: 29.5.0 jest-message-util: 29.5.0 jest-regex-util: 29.4.3 @@ -1851,7 +2338,7 @@ packages: dependencies: '@jest/fake-timers': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 14.18.32 + '@types/node': 18.0.0 jest-mock: 29.5.0 dev: true @@ -1878,7 +2365,7 @@ packages: dependencies: '@jest/types': 29.5.0 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 14.18.32 + '@types/node': 18.0.0 jest-message-util: 29.5.0 jest-mock: 29.5.0 jest-util: 29.5.0 @@ -1911,7 +2398,7 @@ packages: '@jest/transform': 29.5.0 '@jest/types': 29.5.0 '@jridgewell/trace-mapping': 0.3.18 - '@types/node': 14.18.32 + '@types/node': 18.0.0 chalk: 4.1.2 collect-v8-coverage: 1.0.1 exit: 0.1.2 @@ -1999,7 +2486,7 @@ packages: '@jest/schemas': 29.4.3 '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 20.3.2 + '@types/node': 18.0.0 '@types/yargs': 17.0.24 chalk: 4.1.2 dev: true @@ -2391,6 +2878,7 @@ packages: /@opentelemetry/api@1.4.1: resolution: {integrity: sha512-O2yRJce1GOc6PAy3QxFM4NzFiWzvScDC1/5ihYBL6BUEVdq0XMWN01sppE+H6bBXbaFYipjwFLEWLg5PaSOThA==} engines: {node: '>=8.0.0'} + dev: false /@opentelemetry/core@1.14.0(@opentelemetry/api@1.4.1): resolution: {integrity: sha512-MnMZ+sxsnlzloeuXL2nm5QcNczt/iO82UOeQQDHhV83F2fP3sgntW2evvtoxJki0MBLxEsh5ADD7PR/Hn5uzjw==} @@ -2400,6 +2888,7 @@ packages: dependencies: '@opentelemetry/api': 1.4.1 '@opentelemetry/semantic-conventions': 1.14.0 + dev: false /@opentelemetry/resources@1.14.0(@opentelemetry/api@1.4.1): resolution: {integrity: sha512-qRfWIgBxxl3z47E036Aey0Lj2ZjlFb27Q7Xnj1y1z/P293RXJZGLtcfn/w8JF7v1Q2hs3SDGxz7Wb9Dko1YUQA==} @@ -2410,6 +2899,7 @@ packages: '@opentelemetry/api': 1.4.1 '@opentelemetry/core': 1.14.0(@opentelemetry/api@1.4.1) '@opentelemetry/semantic-conventions': 1.14.0 + dev: false /@opentelemetry/sdk-trace-base@1.14.0(@opentelemetry/api@1.4.1): resolution: {integrity: sha512-NzRGt3PS+HPKfQYMb6Iy8YYc5OKA73qDwci/6ujOIvyW9vcqBJSWbjZ8FeLEAmuatUB5WrRhEKu9b0sIiIYTrQ==} @@ -2421,10 +2911,12 @@ packages: '@opentelemetry/core': 1.14.0(@opentelemetry/api@1.4.1) '@opentelemetry/resources': 1.14.0(@opentelemetry/api@1.4.1) '@opentelemetry/semantic-conventions': 1.14.0 + dev: false /@opentelemetry/semantic-conventions@1.14.0: resolution: {integrity: sha512-rJfCY8rCWz3cb4KI6pEofnytvMPuj3YLQwoscCCYZ5DkdiPjo15IQ0US7+mjcWy9H3fcZIzf2pbJZ7ck/h4tug==} engines: {node: '>=14'} + dev: false /@paralleldrive/cuid2@2.2.0: resolution: {integrity: sha512-CVQDpPIUHrUGGLdrMGz1NmqZvqmsB2j2rCIQEu1EvxWjlFh4fhvEGmgR409cY20/67/WlJsggenq0no3p3kYsw==} @@ -2457,33 +2949,6 @@ packages: resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==} dev: true - /@prisma/client@4.0.0: - resolution: {integrity: sha512-g1h2OGoRo7anBVQ9Cw3gsbjwPtvf7i0pkGxKeZICtwkvE5CZXW+xZF4FZdmrViYkKaAShbISL0teNpu9ecpf4g==} - engines: {node: '>=14.17'} - requiresBuild: true - peerDependencies: - prisma: '*' - peerDependenciesMeta: - prisma: - optional: true - dependencies: - '@prisma/engines-version': 3.16.0-49.da41d2bb3406da22087b849f0e911199ba4fbf11 - dev: true - - /@prisma/client@4.7.0(prisma@4.7.0): - resolution: {integrity: sha512-keXMa0oJWJGOzMEFKp+CEgzJPwnOtGSrnTWw6qMYxnypYrRFdNxqyA06EzELZexBhgM4oLooZ1jDJ3iy46wExA==} - engines: {node: '>=14.17'} - requiresBuild: true - peerDependencies: - prisma: '*' - peerDependenciesMeta: - prisma: - optional: true - dependencies: - '@prisma/engines-version': 4.7.0-74.39190b250ebc338586e25e6da45e5e783bc8a635 - prisma: 4.7.0 - dev: false - /@prisma/debug@4.10.0: resolution: {integrity: sha512-rxVOZKsEyjlQCwN/pkkJO7wEdARt1yRyukSjLa+BF2QTvy2+VgtBmrfys4WDQSnj3jVWeHMpi5GeAoJjKkSKyA==} dependencies: @@ -2492,6 +2957,17 @@ packages: strip-ansi: 6.0.1 transitivePeerDependencies: - supports-color + dev: false + + /@prisma/debug@5.0.0: + resolution: {integrity: sha512-3q/M/KqlQ01/HJXifU/zCNOHkoTWu24kGelMF/IBrRxm7njPqTTbwfnT1dh4JK+nuWM5/Dg1Lv00u2c0l7AHxg==} + dependencies: + '@types/debug': 4.1.8 + debug: 4.3.4 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - supports-color + dev: false /@prisma/engine-core@4.10.0: resolution: {integrity: sha512-uKkUXcpqGX4LbTwnvLsEBhl0gfcfSE5jYWQqastFqoO+lVIEiVZ9aoDrDDy7ZUhjtCLmejsgVb7mXmCzA3nhMg==} @@ -2513,27 +2989,17 @@ packages: undici: 5.16.0 transitivePeerDependencies: - supports-color - - /@prisma/engines-version@3.16.0-49.da41d2bb3406da22087b849f0e911199ba4fbf11: - resolution: {integrity: sha512-PiZhdD624SrYEjyLboI0X7OugNbxUzDJx9v/6ldTKuqNDVUCmRH/Z00XwDi/dgM4FlqOSO+YiUsSiSKjxxG8cw==} - dev: true - - /@prisma/engines-version@4.7.0-74.39190b250ebc338586e25e6da45e5e783bc8a635: - resolution: {integrity: sha512-ImczGEQ8NS1OUApEeyAGxC4uLTtQp0wI1+2wM4MeQLVwIQbyMHk1vOhWWE8Pwbi3rnzLcPvsIrd9sm6oNXhERw==} dev: false - /@prisma/engines@3.16.0-49.da41d2bb3406da22087b849f0e911199ba4fbf11: - resolution: {integrity: sha512-u/rG4lDHALolWBLr3yebZ+N2qImp3SDMcu7bHNJuRDaYvYEXy/MqfNRNEgd9GoPsXL3gofYf0VzJf2AmCG3YVw==} - requiresBuild: true - dev: true - /@prisma/engines@4.10.0: resolution: {integrity: sha512-ZPPo7q+nQZdTlPFedS7mFXPE3oZ2kWtTh3GO4sku0XQ8ikLqEyinuTPJbQCw/8qel2xglIEQicsK6yI4Jgh20A==} requiresBuild: true + dev: false - /@prisma/engines@4.7.0: - resolution: {integrity: sha512-afKrVFktaZ1pOK12/uFl2hRsBWIJZuC5FdDtacuKk5x/mR+rC5AbA+PlN3ZCZbmYTaeiBMHjcU5wbT5z2N3nSQ==} + /@prisma/engines@5.0.0: + resolution: {integrity: sha512-kyT/8fd0OpWmhAU5YnY7eP31brW1q1YrTGoblWrhQJDiN/1K+Z8S1kylcmtjqx5wsUGcP1HBWutayA/jtyt+sg==} requiresBuild: true + dev: false /@prisma/fetch-engine@4.10.0: resolution: {integrity: sha512-DZaBIstNiubIuZHX3ul2piltE98MkPHelsCKub9NWqprdgTAd/1TBJQT2CVuVP1V5d+0JT0Nd+FmQY+oCWb5rw==} @@ -2558,6 +3024,32 @@ packages: transitivePeerDependencies: - encoding - supports-color + dev: false + + /@prisma/fetch-engine@5.0.0: + resolution: {integrity: sha512-eSzHTE0KcMvM5+O1++eaMuVf4D1zwWHdqjWr6D70skCg37q7RYsuty4GFnlWBuqC4aXwVf06EvIxiJ0SQIIeRw==} + dependencies: + '@prisma/debug': 5.0.0 + '@prisma/get-platform': 5.0.0 + execa: 5.1.1 + find-cache-dir: 3.3.2 + fs-extra: 11.1.1 + hasha: 5.2.2 + http-proxy-agent: 7.0.0 + https-proxy-agent: 7.0.0 + kleur: 4.1.5 + node-fetch: 2.6.12 + p-filter: 2.1.0 + p-map: 4.0.0 + p-retry: 4.6.2 + progress: 2.0.3 + rimraf: 3.0.2 + temp-dir: 2.0.0 + tempy: 1.0.1 + transitivePeerDependencies: + - encoding + - supports-color + dev: false /@prisma/generator-helper@4.10.0: resolution: {integrity: sha512-NkQOfZpHUjVjqJ7NN2FymHSLkGd/E0fz5c3RkyESKvQqBy2sFBxt+aFxGsUbUy3FfwvkckC04HdQOXpisAko0A==} @@ -2568,6 +3060,18 @@ packages: cross-spawn: 7.0.3 transitivePeerDependencies: - supports-color + dev: false + + /@prisma/generator-helper@5.0.0: + resolution: {integrity: sha512-pufQ1mhoH6WzKNtzL79HZDoW4Ql3Lf8QEKVmBoW8e3Tdb50bxpYBYue5LBqp9vNW1xd1pgZO53cNiRfLX2d4Zg==} + dependencies: + '@prisma/debug': 5.0.0 + '@types/cross-spawn': 6.0.2 + cross-spawn: 7.0.3 + kleur: 4.1.5 + transitivePeerDependencies: + - supports-color + dev: false /@prisma/get-platform@4.10.0: resolution: {integrity: sha512-QBgHnMe1CtFoioyH9C9cniC4TENFlhQuxWWxJQwWw8fkxvz/WgDwxJ+Xu3Jk8JrfP5iUVzqv+7VbZVKfMObakg==} @@ -2584,6 +3088,24 @@ packages: ts-pattern: 4.1.3 transitivePeerDependencies: - supports-color + dev: false + + /@prisma/get-platform@5.0.0: + resolution: {integrity: sha512-JT/rz/jaMTggDkd9OIma50si9rPLzSFe7XSrV3mKXwtv9t+rdwx5ZhmKJd+Rz6S1vhn/291k21JLfaxOW6u8KQ==} + dependencies: + '@prisma/debug': 5.0.0 + escape-string-regexp: 4.0.0 + execa: 5.1.1 + fs-jetpack: 5.1.0 + kleur: 4.1.5 + replace-string: 3.1.0 + strip-ansi: 6.0.1 + tempy: 1.0.1 + terminal-link: 2.1.1 + ts-pattern: 4.3.0 + transitivePeerDependencies: + - supports-color + dev: false /@prisma/internals@4.10.0: resolution: {integrity: sha512-Inex2YHZ0oaIxoGGjBX0N2w3TAVx7m7SXF0ru1kbvB05wqum1yyquBnsyca5A4DBANf3uSa3ZyQvx+Ksl4gIgw==} @@ -2633,9 +3155,66 @@ packages: transitivePeerDependencies: - encoding - supports-color + dev: false + + /@prisma/internals@5.0.0: + resolution: {integrity: sha512-VGWyFk6QlSBXT8z65Alq5F3o9E8IiTtaBoa3rmKkGpZjUk85kJy3jZz4xkRv53TaeghGE5rWfwkfak26KtY5yQ==} + dependencies: + '@antfu/ni': 0.21.4 + '@opentelemetry/api': 1.4.1 + '@prisma/debug': 5.0.0 + '@prisma/engines': 5.0.0 + '@prisma/fetch-engine': 5.0.0 + '@prisma/generator-helper': 5.0.0 + '@prisma/get-platform': 5.0.0 + '@prisma/prisma-schema-wasm': 4.17.0-26.6b0aef69b7cdfc787f822ecd7cdc76d5f1991584 + archiver: 5.3.1 + arg: 5.0.2 + checkpoint-client: 1.1.24 + cli-truncate: 2.1.0 + dotenv: 16.0.3 + escape-string-regexp: 4.0.0 + execa: 5.1.1 + find-up: 5.0.0 + fp-ts: 2.16.0 + fs-extra: 11.1.1 + fs-jetpack: 5.1.0 + global-dirs: 3.0.1 + globby: 11.1.0 + indent-string: 4.0.0 + is-windows: 1.0.2 + is-wsl: 2.2.0 + kleur: 4.1.5 + new-github-issue-url: 0.2.1 + node-fetch: 2.6.12 + npm-packlist: 5.1.3 + open: 7.4.2 + p-map: 4.0.0 + prompts: 2.4.2 + read-pkg-up: 7.0.1 + replace-string: 3.1.0 + resolve: 1.22.2 + string-width: 4.2.3 + strip-ansi: 6.0.1 + strip-indent: 3.0.0 + temp-dir: 2.0.0 + temp-write: 4.0.0 + tempy: 1.0.1 + terminal-link: 2.1.1 + tmp: 0.2.1 + ts-pattern: 4.3.0 + transitivePeerDependencies: + - encoding + - supports-color + dev: false /@prisma/prisma-fmt-wasm@4.10.0-84.ca7fcef713137fa11029d519a9780db130cca91d: resolution: {integrity: sha512-AkNNfsOnbfmGYFWAk6mFckuznyi4FvQDrK8NKQKC2DV068K//eAdr149upmypS90uOM3y74KS+b32ZyQwThzyA==} + dev: false + + /@prisma/prisma-schema-wasm@4.17.0-26.6b0aef69b7cdfc787f822ecd7cdc76d5f1991584: + resolution: {integrity: sha512-JFdsnSgBPN8reDTLOI9Vh/6ccCb2aD1LbY/LWQnkcIgNo6IdpzvuM+qRVbBuA6IZP2SdqQI8Lu6RL2P8EFBQUA==} + dev: false /@readme/better-ajv-errors@1.6.0(ajv@8.12.0): resolution: {integrity: sha512-9gO9rld84Jgu13kcbKRU+WHseNhaVt76wYMeRDGsUGYxwJtI3RmEJ9LY9dZCYQGI8eUZLuxb5qDja0nqklpFjQ==} @@ -2695,7 +3274,7 @@ packages: '@sinonjs/commons': 3.0.0 dev: true - /@sveltejs/kit@1.21.0(svelte@3.59.2)(vite@4.3.9): + /@sveltejs/kit@1.21.0(svelte@4.0.5)(vite@4.4.4): resolution: {integrity: sha512-CBsYoI34SjtOQp0eG85dmVnvTR3Pjs8VgAQhO0CgQja9BIorKl808F1X8EunPhCcyek5r5lKQE1Mmbi0RuzHqA==} engines: {node: ^16.14 || >=18} hasBin: true @@ -2704,7 +3283,7 @@ packages: svelte: ^3.54.0 || ^4.0.0-next.0 vite: ^4.0.0 dependencies: - '@sveltejs/vite-plugin-svelte': 2.4.2(svelte@3.59.2)(vite@4.3.9) + '@sveltejs/vite-plugin-svelte': 2.4.2(svelte@4.0.5)(vite@4.4.4) '@types/cookie': 0.5.1 cookie: 0.5.0 devalue: 4.3.2 @@ -2715,14 +3294,14 @@ packages: sade: 1.8.1 set-cookie-parser: 2.6.0 sirv: 2.0.3 - svelte: 3.59.2 + svelte: 4.0.5 undici: 5.22.1 - vite: 4.3.9(@types/node@14.18.32) + vite: 4.4.4 transitivePeerDependencies: - supports-color dev: true - /@sveltejs/vite-plugin-svelte-inspector@1.0.3(@sveltejs/vite-plugin-svelte@2.4.2)(svelte@3.59.2)(vite@4.3.9): + /@sveltejs/vite-plugin-svelte-inspector@1.0.3(@sveltejs/vite-plugin-svelte@2.4.2)(svelte@4.0.5)(vite@4.4.4): resolution: {integrity: sha512-Khdl5jmmPN6SUsVuqSXatKpQTMIifoQPDanaxC84m9JxIibWvSABJyHpyys0Z+1yYrxY5TTEQm+6elh0XCMaOA==} engines: {node: ^14.18.0 || >= 16} peerDependencies: @@ -2730,30 +3309,30 @@ packages: svelte: ^3.54.0 || ^4.0.0 vite: ^4.0.0 dependencies: - '@sveltejs/vite-plugin-svelte': 2.4.2(svelte@3.59.2)(vite@4.3.9) + '@sveltejs/vite-plugin-svelte': 2.4.2(svelte@4.0.5)(vite@4.4.4) debug: 4.3.4 - svelte: 3.59.2 - vite: 4.3.9(@types/node@14.18.32) + svelte: 4.0.5 + vite: 4.4.4 transitivePeerDependencies: - supports-color dev: true - /@sveltejs/vite-plugin-svelte@2.4.2(svelte@3.59.2)(vite@4.3.9): + /@sveltejs/vite-plugin-svelte@2.4.2(svelte@4.0.5)(vite@4.4.4): resolution: {integrity: sha512-ePfcC48ftMKhkT0OFGdOyycYKnnkT6i/buzey+vHRTR/JpQvuPzzhf1PtKqCDQfJRgoPSN2vscXs6gLigx/zGw==} engines: {node: ^14.18.0 || >= 16} peerDependencies: svelte: ^3.54.0 || ^4.0.0 vite: ^4.0.0 dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 1.0.3(@sveltejs/vite-plugin-svelte@2.4.2)(svelte@3.59.2)(vite@4.3.9) + '@sveltejs/vite-plugin-svelte-inspector': 1.0.3(@sveltejs/vite-plugin-svelte@2.4.2)(svelte@4.0.5)(vite@4.4.4) debug: 4.3.4 deepmerge: 4.3.1 kleur: 4.1.5 magic-string: 0.30.0 - svelte: 3.59.2 - svelte-hmr: 0.15.2(svelte@3.59.2) - vite: 4.3.9(@types/node@14.18.32) - vitefu: 0.2.4(vite@4.3.9) + svelte: 4.0.5 + svelte-hmr: 0.15.2(svelte@4.0.5) + vite: 4.4.4 + vitefu: 0.2.4(vite@4.4.4) transitivePeerDependencies: - supports-color dev: true @@ -2780,15 +3359,11 @@ packages: resolution: {integrity: sha512-sm+QncWaPmM73IPwFlmWSKPqjdTXZeFf/7aEmWh00z7yl2FjqophPt0dE1EHW9P1giMC5rMviv7OUbSDmWzXXA==} dev: true - /@tanstack/query-core@4.29.19: - resolution: {integrity: sha512-uPe1DukeIpIHpQi6UzIgBcXsjjsDaLnc7hF+zLBKnaUlh7jFE/A+P8t4cU4VzKPMFB/C970n/9SxtpO5hmIRgw==} - dev: true - /@tanstack/query-core@4.29.7: resolution: {integrity: sha512-GXG4b5hV2Loir+h2G+RXhJdoZhJLnrBWsuLB2r0qBRyhWuXq9w/dWxzvpP89H0UARlH6Mr9DiVj4SMtpkF/aUA==} dev: true - /@tanstack/react-query@4.28.0(react-dom@17.0.2)(react@17.0.2): + /@tanstack/react-query@4.28.0(react@18.2.0): resolution: {integrity: sha512-8cGBV5300RHlvYdS4ea+G1JcZIt5CIuprXYFnsWggkmGoC0b5JaqG0fIX3qwDL9PTNkKvG76NGThIWbpXivMrQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -2801,30 +3376,11 @@ packages: optional: true dependencies: '@tanstack/query-core': 4.27.0 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - use-sync-external-store: 1.2.0(react@17.0.2) - dev: true - - /@tanstack/react-query@4.29.19(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-XiTIOHHQ5Cw1WUlHaD4fmVUMhoWjuNJlAeJGq7eM4BraI5z7y8WkZO+NR8PSuRnQGblpuVdjClQbDFtwxTtTUw==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-native: '*' - peerDependenciesMeta: - react-dom: - optional: true - react-native: - optional: true - dependencies: - '@tanstack/query-core': 4.29.19 react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) use-sync-external-store: 1.2.0(react@18.2.0) dev: true - /@tanstack/react-query@4.29.7(react-dom@17.0.2)(react@17.0.2): + /@tanstack/react-query@4.29.7(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-ijBWEzAIo09fB1yd22slRZzprrZ5zMdWYzBnCg5qiXuFbH78uGN1qtGz8+Ed4MuhaPaYSD+hykn+QEKtQviEtg==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -2837,9 +3393,9 @@ packages: optional: true dependencies: '@tanstack/query-core': 4.29.7 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - use-sync-external-store: 1.2.0(react@17.0.2) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + use-sync-external-store: 1.2.0(react@18.2.0) dev: true /@tanstack/svelte-query@4.29.7(svelte@3.59.2): @@ -2854,6 +3410,7 @@ packages: /@tootallnate/once@2.0.0: resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} engines: {node: '>= 10'} + dev: false /@trpc/client@10.32.0(@trpc/server@10.32.0): resolution: {integrity: sha512-hrj6XV84nE6DH5AmsPJ0JzIRcx3f6zU0tvS705DnZtNBOoMk7Lx+wX+KCDxj4DxLsTXC+roAxZxWwAB6/LGsXA==} @@ -2863,7 +3420,7 @@ packages: '@trpc/server': 10.32.0 dev: true - /@trpc/next@10.32.0(@tanstack/react-query@4.29.19)(@trpc/client@10.32.0)(@trpc/react-query@10.32.0)(@trpc/server@10.32.0)(next@13.4.7)(react-dom@18.2.0)(react@18.2.0): + /@trpc/next@10.32.0(@tanstack/react-query@4.29.7)(@trpc/client@10.32.0)(@trpc/react-query@10.32.0)(@trpc/server@10.32.0)(next@13.4.7)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-qJ3yvJDTVmiOOPW1x/FCpmOvtcMJXnP2t3EbcUFrqwgH+D1KdbU2Kk1iSa89Gwy/BBEmXUxaKkWoM3e4Id80gw==} peerDependencies: '@tanstack/react-query': ^4.18.0 @@ -2874,17 +3431,17 @@ packages: react: '>=16.8.0' react-dom: '>=16.8.0' dependencies: - '@tanstack/react-query': 4.29.19(react-dom@18.2.0)(react@18.2.0) + '@tanstack/react-query': 4.29.7(react-dom@18.2.0)(react@18.2.0) '@trpc/client': 10.32.0(@trpc/server@10.32.0) - '@trpc/react-query': 10.32.0(@tanstack/react-query@4.29.19)(@trpc/client@10.32.0)(@trpc/server@10.32.0)(react-dom@18.2.0)(react@18.2.0) + '@trpc/react-query': 10.32.0(@tanstack/react-query@4.29.7)(@trpc/client@10.32.0)(@trpc/server@10.32.0)(react-dom@18.2.0)(react@18.2.0) '@trpc/server': 10.32.0 - next: 13.4.7(@babel/core@7.22.5)(@opentelemetry/api@1.4.1)(react-dom@18.2.0)(react@18.2.0) + next: 13.4.7(@babel/core@7.22.9)(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) react-ssr-prepass: 1.5.0(react@18.2.0) dev: true - /@trpc/react-query@10.32.0(@tanstack/react-query@4.29.19)(@trpc/client@10.32.0)(@trpc/server@10.32.0)(react-dom@18.2.0)(react@18.2.0): + /@trpc/react-query@10.32.0(@tanstack/react-query@4.29.7)(@trpc/client@10.32.0)(@trpc/server@10.32.0)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-M4W1aGm3VAfQ9u4FJyK8M+pkcAV4lp32ZHxKnkRydxcsladhsqveZC9oqZqwklprEcYHtWU8v3R+jRGUjfCxpw==} peerDependencies: '@tanstack/react-query': ^4.18.0 @@ -2893,7 +3450,7 @@ packages: react: '>=16.8.0' react-dom: '>=16.8.0' dependencies: - '@tanstack/react-query': 4.29.19(react-dom@18.2.0)(react@18.2.0) + '@tanstack/react-query': 4.29.7(react-dom@18.2.0)(react@18.2.0) '@trpc/client': 10.32.0(@trpc/server@10.32.0) '@trpc/server': 10.32.0 react: 18.2.0 @@ -2969,7 +3526,7 @@ packages: resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==} dependencies: '@types/connect': 3.4.35 - '@types/node': 20.3.2 + '@types/node': 18.0.0 dev: true /@types/chai-subset@1.3.3: @@ -2985,7 +3542,7 @@ packages: /@types/connect@3.4.35: resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==} dependencies: - '@types/node': 20.3.2 + '@types/node': 18.0.0 dev: true /@types/cookie@0.5.1: @@ -2999,17 +3556,29 @@ packages: /@types/cross-spawn@6.0.2: resolution: {integrity: sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw==} dependencies: - '@types/node': 14.18.32 + '@types/node': 18.0.0 + dev: false /@types/debug@4.1.7: resolution: {integrity: sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==} dependencies: '@types/ms': 0.7.31 + dev: false + + /@types/debug@4.1.8: + resolution: {integrity: sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==} + dependencies: + '@types/ms': 0.7.31 + dev: false + + /@types/estree@1.0.1: + resolution: {integrity: sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==} + dev: true /@types/express-serve-static-core@4.17.35: resolution: {integrity: sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==} dependencies: - '@types/node': 20.3.2 + '@types/node': 18.0.0 '@types/qs': 6.9.7 '@types/range-parser': 1.2.4 '@types/send': 0.17.1 @@ -3028,13 +3597,13 @@ packages: resolution: {integrity: sha512-MxObHvNl4A69ofaTRU8DFqvgzzv8s9yRtaPPm5gud9HDNvpB3GPQFvNuTWAI59B9huVGV5jXYJwbCsmBsOGYWA==} dependencies: '@types/jsonfile': 6.1.1 - '@types/node': 14.18.29 + '@types/node': 18.0.0 dev: true /@types/graceful-fs@4.1.6: resolution: {integrity: sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==} dependencies: - '@types/node': 14.18.32 + '@types/node': 18.0.0 dev: true /@types/http-errors@2.0.1: @@ -3077,14 +3646,7 @@ packages: /@types/jsonfile@6.1.1: resolution: {integrity: sha512-GSgiRCVeapDN+3pqA35IkQwasaCh/0YFH5dEF6S88iDvEn901DjOeH3/QPY+XYP1DFzDZPvIvfeEgk+7br5png==} dependencies: - '@types/node': 14.18.29 - dev: true - - /@types/lower-case-first@1.0.1: - resolution: {integrity: sha512-Sko9LlGuUr1oqpqD2dTznreWYDWpt0OsgQxPEGudt41Rbp0iFTd3gkbo5j0MpeJCgp/Q2WRTd6MTjjZ9ax0USg==} - deprecated: This is a stub types definition for lower-case-first (https://github.com/blakeembrey/lower-case-first). lower-case-first provides its own type definitions, so you don't need @types/lower-case-first installed! - dependencies: - lower-case-first: 2.0.2 + '@types/node': 18.0.0 dev: true /@types/mime@1.3.2: @@ -3101,24 +3663,14 @@ packages: /@types/ms@0.7.31: resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==} + dev: false /@types/node@12.20.55: resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} dev: true - /@types/node@14.18.29: - resolution: {integrity: sha512-LhF+9fbIX4iPzhsRLpK5H7iPdvW8L4IwGciXQIOEcuF62+9nw/VQVsOViAOOGxY3OlOKGLFv0sWwJXdwQeTn6A==} - - /@types/node@14.18.32: - resolution: {integrity: sha512-Y6S38pFr04yb13qqHf8uk1nHE3lXgQ30WZbv1mLliV9pt0NjvqdWttLcrOYLnXbOafknVYRHZGoMSpR9UwfYow==} - - /@types/node@18.14.2: - resolution: {integrity: sha512-1uEQxww3DaghA0RxqHx0O0ppVlo43pJhepY51OxuQIKHpjbnYLA7vcdwioNPzIqmC2u3I/dmylcqjlh0e7AyUA==} - dev: true - - /@types/node@20.3.2: - resolution: {integrity: sha512-vOBLVQeCQfIcF/2Y7eKFTqrMnizK5lRNQ7ykML/5RuwVXVWxYkgwS7xbt4B6fKCUPgbSL5FSsjHQpaGQP/dQmw==} - dev: true + /@types/node@18.0.0: + resolution: {integrity: sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA==} /@types/normalize-package-data@2.4.1: resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} @@ -3147,8 +3699,8 @@ packages: resolution: {integrity: sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==} dev: true - /@types/react@18.0.26: - resolution: {integrity: sha512-hCR3PJQsAIXyxhTNSiDFY//LhnMZWpNNr5etoCqx/iUfGc5gXWtQR2Phl908jVR6uPXacojQWTg4qRpkxTuGug==} + /@types/react@18.2.0: + resolution: {integrity: sha512-0FLj93y5USLHdnhIhABk83rm8XEGA7kH3cr+YUlvxoUGp1xNt/DINUMvqPxLyOQMzLmZe8i4RTHbvb8MC7NmrA==} dependencies: '@types/prop-types': 15.7.5 '@types/scheduler': 0.16.3 @@ -3157,6 +3709,7 @@ packages: /@types/retry@0.12.0: resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} + dev: false /@types/scheduler@0.16.3: resolution: {integrity: sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==} @@ -3178,7 +3731,7 @@ packages: resolution: {integrity: sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==} dependencies: '@types/mime': 1.3.2 - '@types/node': 20.3.2 + '@types/node': 18.0.0 dev: true /@types/serve-static@1.15.2: @@ -3186,7 +3739,7 @@ packages: dependencies: '@types/http-errors': 2.0.1 '@types/mime': 3.0.1 - '@types/node': 20.3.2 + '@types/node': 18.0.0 dev: true /@types/stack-utils@2.0.1: @@ -3201,7 +3754,7 @@ packages: resolution: {integrity: sha512-LOWgpacIV8GHhrsQU+QMZuomfqXiqzz3ILLkCtKx3Us6AmomFViuzKT9D693QTKgyut2oCytMG8/efOop+DB+w==} dependencies: '@types/cookiejar': 2.1.2 - '@types/node': 20.3.2 + '@types/node': 18.0.0 dev: true /@types/supertest@2.0.12: @@ -3214,13 +3767,6 @@ packages: resolution: {integrity: sha512-dDZH/tXzwjutnuk4UacGgFRwV+JSLaXL1ikvidfJprkb7L9Nx1njcRHHmi3Dsvt7pgqqTEeucQuOrWHPFgzVHA==} dev: true - /@types/upper-case-first@1.1.2: - resolution: {integrity: sha512-YOy6ArS6hUf7d/vzYcL78OBH7+l5t98Kpn0AHrgUnetgChU2r7ku1je12Ysqh0leOHbkz+y+6R8v5hzSDE9U7g==} - deprecated: This is a stub types definition for upper-case-first (https://github.com/blakeembrey/upper-case-first). upper-case-first provides its own type definitions, so you don't need @types/upper-case-first installed! - dependencies: - upper-case-first: 2.0.2 - dev: true - /@types/uuid@8.3.4: resolution: {integrity: sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==} dev: true @@ -3259,7 +3805,7 @@ packages: ignore: 5.2.4 natural-compare-lite: 1.4.0 regexpp: 3.2.0 - semver: 7.3.8 + semver: 7.5.3 tsutils: 3.21.0(typescript@4.8.4) typescript: 4.8.4 transitivePeerDependencies: @@ -3427,7 +3973,7 @@ packages: debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 - semver: 7.3.8 + semver: 7.5.3 tsutils: 3.21.0(typescript@4.8.4) typescript: 4.8.4 transitivePeerDependencies: @@ -3469,7 +4015,7 @@ packages: debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 - semver: 7.3.8 + semver: 7.5.3 tsutils: 3.21.0(typescript@4.6.2) typescript: 4.6.2 transitivePeerDependencies: @@ -3490,7 +4036,7 @@ packages: debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 - semver: 7.3.8 + semver: 7.5.3 tsutils: 3.21.0(typescript@4.8.4) typescript: 4.8.4 transitivePeerDependencies: @@ -3504,14 +4050,14 @@ packages: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: '@types/json-schema': 7.0.12 - '@types/semver': 7.3.13 + '@types/semver': 7.5.0 '@typescript-eslint/scope-manager': 5.42.0 '@typescript-eslint/types': 5.42.0 '@typescript-eslint/typescript-estree': 5.42.0(typescript@4.8.4) eslint: 8.27.0 eslint-scope: 5.1.1 eslint-utils: 3.0.0(eslint@8.27.0) - semver: 7.3.8 + semver: 7.5.3 transitivePeerDependencies: - supports-color - typescript @@ -3545,13 +4091,13 @@ packages: dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.27.0) '@types/json-schema': 7.0.12 - '@types/semver': 7.3.13 + '@types/semver': 7.5.0 '@typescript-eslint/scope-manager': 5.60.1 '@typescript-eslint/types': 5.60.1 '@typescript-eslint/typescript-estree': 5.60.1(typescript@4.8.4) eslint: 8.27.0 eslint-scope: 5.1.1 - semver: 7.3.8 + semver: 7.5.3 transitivePeerDependencies: - supports-color - typescript @@ -3565,13 +4111,13 @@ packages: dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.30.0) '@types/json-schema': 7.0.12 - '@types/semver': 7.3.13 + '@types/semver': 7.5.0 '@typescript-eslint/scope-manager': 5.60.1 '@typescript-eslint/types': 5.60.1 '@typescript-eslint/typescript-estree': 5.60.1(typescript@4.6.2) eslint: 8.30.0 eslint-scope: 5.1.1 - semver: 7.3.8 + semver: 7.5.3 transitivePeerDependencies: - supports-color - typescript @@ -3693,6 +4239,12 @@ packages: engines: {node: '>=0.4.0'} dev: true + /acorn@8.10.0: + resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + /acorn@8.9.0: resolution: {integrity: sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==} engines: {node: '>=0.4.0'} @@ -3706,6 +4258,16 @@ packages: debug: 4.3.4 transitivePeerDependencies: - supports-color + dev: false + + /agent-base@7.1.0: + resolution: {integrity: sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==} + engines: {node: '>= 14'} + dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false /aggregate-error@3.1.0: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} @@ -3713,6 +4275,7 @@ packages: dependencies: clean-stack: 2.2.0 indent-string: 4.0.0 + dev: false /ajv-draft-04@1.0.0(ajv@8.12.0): resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} @@ -3796,6 +4359,10 @@ packages: engines: {node: '>=12'} dev: true + /any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + dev: true + /anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} @@ -3818,6 +4385,7 @@ packages: lodash.union: 4.6.0 normalize-path: 3.0.0 readable-stream: 2.3.8 + dev: false /archiver@5.3.1: resolution: {integrity: sha512-8KyabkmbYrH+9ibcTScQ1xCJC/CGcugdVIwB+53f5sZziXgwUh3iXlAlANMxcZyDEfTHMe6+Z5FofV8nopXP7w==} @@ -3830,6 +4398,7 @@ packages: readdir-glob: 1.1.3 tar-stream: 2.2.0 zip-stream: 4.1.0 + dev: false /archy@1.0.0: resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==} @@ -3841,6 +4410,7 @@ packages: /arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + dev: false /argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} @@ -3852,6 +4422,12 @@ packages: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} dev: true + /aria-query@5.3.0: + resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} + dependencies: + dequal: 2.0.3 + dev: true + /array-back@3.1.0: resolution: {integrity: sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==} engines: {node: '>=6'} @@ -3908,6 +4484,7 @@ packages: /astral-regex@2.0.0: resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} engines: {node: '>=8'} + dev: false /async-exit-hook@2.0.1: resolution: {integrity: sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==} @@ -3916,6 +4493,7 @@ packages: /async@3.2.4: resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==} + dev: false /asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -3941,6 +4519,12 @@ packages: - supports-color dev: true + /axobject-query@3.2.1: + resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==} + dependencies: + dequal: 2.0.3 + dev: true + /azure-devops-node-api@11.2.0: resolution: {integrity: sha512-XdiGPhrpaT5J8wdERRKs5g8E0Zy1pvOYTli7z9E8nmOn3YGp4FhtjhrOyFmX/8veWCwdI69mCHKJw6l+4J/bHA==} dependencies: @@ -4158,6 +4742,15 @@ packages: dependencies: base64-js: 1.5.1 ieee754: 1.2.1 + + /bundle-require@4.0.1(esbuild@0.18.13): + resolution: {integrity: sha512-9NQkRHlNdNpDBGmLpngF3EFDcwodhMUuLz9PaWYciVcQF9SE4LFjM2DB/xV1Li5JiuDMv7ZUWuC3rGbqR0MAXQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + peerDependencies: + esbuild: '>=0.17' + dependencies: + esbuild: 0.18.13 + load-tsconfig: 0.2.5 dev: true /busboy@1.6.0: @@ -4300,6 +4893,21 @@ packages: uuid: 8.3.2 transitivePeerDependencies: - encoding + dev: false + + /checkpoint-client@1.1.24: + resolution: {integrity: sha512-nIOlLhDS7MKs4tUzS3LCm+sE1NgTCVnVrXlD0RRxaoEkkLu8LIWSUNiNWai6a+LK5unLzTyZeTCYX1Smqy0YoA==} + dependencies: + ci-info: 3.8.0 + env-paths: 2.2.1 + fast-write-atomic: 0.2.1 + make-dir: 3.1.0 + ms: 2.1.3 + node-fetch: 2.6.11 + uuid: 9.0.0 + transitivePeerDependencies: + - encoding + dev: false /cheerio-select@2.1.0: resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} @@ -4365,11 +4973,11 @@ packages: /ci-info@3.3.0: resolution: {integrity: sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==} + dev: false /ci-info@3.8.0: resolution: {integrity: sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==} engines: {node: '>=8'} - dev: true /cjs-module-lexer@1.2.3: resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==} @@ -4378,16 +4986,19 @@ packages: /clean-stack@2.2.0: resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} engines: {node: '>=6'} + dev: false /cli-cursor@3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} dependencies: restore-cursor: 3.1.0 + dev: false /cli-spinners@2.9.0: resolution: {integrity: sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g==} engines: {node: '>=6'} + dev: false /cli-truncate@2.1.0: resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==} @@ -4395,6 +5006,7 @@ packages: dependencies: slice-ansi: 3.0.0 string-width: 4.2.3 + dev: false /cli-truncate@3.1.0: resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} @@ -4451,6 +5063,16 @@ packages: engines: {node: '>= 4'} dev: true + /code-red@1.0.3: + resolution: {integrity: sha512-kVwJELqiILQyG5aeuyKFbdsI1fmQy1Cmf7dQ8eGmVuJoaRVdwey7WaMknr2ZFeVSYSKT0rExsa8EGw0aoI/1QQ==} + dependencies: + '@jridgewell/sourcemap-codec': 1.4.15 + '@types/estree': 1.0.1 + acorn: 8.10.0 + estree-walker: 3.0.3 + periscopic: 3.1.0 + dev: true + /collect-v8-coverage@1.0.1: resolution: {integrity: sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==} dev: true @@ -4509,6 +5131,11 @@ packages: engines: {node: '>=14'} dev: true + /commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + dev: true + /commander@6.2.1: resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==} engines: {node: '>= 6'} @@ -4526,6 +5153,7 @@ packages: /commondir@1.0.1: resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} + dev: false /component-emitter@1.3.0: resolution: {integrity: sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==} @@ -4539,6 +5167,7 @@ packages: crc32-stream: 4.0.2 normalize-path: 3.0.0 readable-stream: 3.6.2 + dev: false /concat-map@0.0.1: resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} @@ -4634,6 +5263,7 @@ packages: resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} engines: {node: '>=0.8'} hasBin: true + dev: false /crc32-stream@4.0.2: resolution: {integrity: sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w==} @@ -4641,6 +5271,7 @@ packages: dependencies: crc-32: 1.2.2 readable-stream: 3.6.2 + dev: false /create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} @@ -4649,7 +5280,7 @@ packages: /cross-fetch@3.1.6: resolution: {integrity: sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==} dependencies: - node-fetch: 2.6.11 + node-fetch: 2.6.12 transitivePeerDependencies: - encoding dev: true @@ -4673,6 +5304,7 @@ packages: /crypto-random-string@2.0.0: resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} engines: {node: '>=8'} + dev: false /css-select@5.1.0: resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} @@ -4684,6 +5316,14 @@ packages: nth-check: 2.1.1 dev: true + /css-tree@2.3.1: + resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + dependencies: + mdn-data: 2.0.30 + source-map-js: 1.0.2 + dev: true + /css-what@6.1.0: resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} engines: {node: '>= 6'} @@ -4764,7 +5404,6 @@ packages: /decimal.js@10.4.2: resolution: {integrity: sha512-ic1yEvwT6GuvaYwBLLY6/aFFgjZdySKTE8en/fkU3QICTmRtgtSlFn0u0BXN06InZwtfCelR7j8LRiDI/02iGA==} - dev: false /decompress-response@6.0.0: resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} @@ -4836,6 +5475,7 @@ packages: p-map: 4.0.0 rimraf: 3.0.2 slash: 3.0.0 + dev: false /delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} @@ -4847,6 +5487,11 @@ packages: engines: {node: '>= 0.8'} dev: true + /dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + dev: true + /destroy@1.2.0: resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} @@ -4998,6 +5643,7 @@ packages: /env-paths@2.2.1: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} + dev: false /error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} @@ -5308,6 +5954,66 @@ packages: '@esbuild/win32-x64': 0.17.19 dev: true + /esbuild@0.18.13: + resolution: {integrity: sha512-vhg/WR/Oiu4oUIkVhmfcc23G6/zWuEQKFS+yiosSHe4aN6+DQRXIfeloYGibIfVhkr4wyfuVsGNLr+sQU1rWWw==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.18.13 + '@esbuild/android-arm64': 0.18.13 + '@esbuild/android-x64': 0.18.13 + '@esbuild/darwin-arm64': 0.18.13 + '@esbuild/darwin-x64': 0.18.13 + '@esbuild/freebsd-arm64': 0.18.13 + '@esbuild/freebsd-x64': 0.18.13 + '@esbuild/linux-arm': 0.18.13 + '@esbuild/linux-arm64': 0.18.13 + '@esbuild/linux-ia32': 0.18.13 + '@esbuild/linux-loong64': 0.18.13 + '@esbuild/linux-mips64el': 0.18.13 + '@esbuild/linux-ppc64': 0.18.13 + '@esbuild/linux-riscv64': 0.18.13 + '@esbuild/linux-s390x': 0.18.13 + '@esbuild/linux-x64': 0.18.13 + '@esbuild/netbsd-x64': 0.18.13 + '@esbuild/openbsd-x64': 0.18.13 + '@esbuild/sunos-x64': 0.18.13 + '@esbuild/win32-arm64': 0.18.13 + '@esbuild/win32-ia32': 0.18.13 + '@esbuild/win32-x64': 0.18.13 + dev: true + + /esbuild@0.18.14: + resolution: {integrity: sha512-uNPj5oHPYmj+ZhSQeYQVFZ+hAlJZbAGOmmILWIqrGvPVlNLbyOvU5Bu6Woi8G8nskcx0vwY0iFoMPrzT86Ko+w==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.18.14 + '@esbuild/android-arm64': 0.18.14 + '@esbuild/android-x64': 0.18.14 + '@esbuild/darwin-arm64': 0.18.14 + '@esbuild/darwin-x64': 0.18.14 + '@esbuild/freebsd-arm64': 0.18.14 + '@esbuild/freebsd-x64': 0.18.14 + '@esbuild/linux-arm': 0.18.14 + '@esbuild/linux-arm64': 0.18.14 + '@esbuild/linux-ia32': 0.18.14 + '@esbuild/linux-loong64': 0.18.14 + '@esbuild/linux-mips64el': 0.18.14 + '@esbuild/linux-ppc64': 0.18.14 + '@esbuild/linux-riscv64': 0.18.14 + '@esbuild/linux-s390x': 0.18.14 + '@esbuild/linux-x64': 0.18.14 + '@esbuild/netbsd-x64': 0.18.14 + '@esbuild/openbsd-x64': 0.18.14 + '@esbuild/sunos-x64': 0.18.14 + '@esbuild/win32-arm64': 0.18.14 + '@esbuild/win32-ia32': 0.18.14 + '@esbuild/win32-x64': 0.18.14 + dev: true + /escalade@3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} @@ -5346,7 +6052,7 @@ packages: '@typescript-eslint/eslint-plugin': 5.42.0(@typescript-eslint/parser@5.42.0)(eslint@8.27.0)(typescript@4.8.4) '@typescript-eslint/utils': 5.60.1(eslint@8.27.0)(typescript@4.8.4) eslint: 8.27.0 - jest: 29.5.0(@types/node@14.18.32)(ts-node@10.9.1) + jest: 29.5.0(@types/node@18.0.0)(ts-node@10.9.1) transitivePeerDependencies: - supports-color - typescript @@ -5367,7 +6073,7 @@ packages: dependencies: '@typescript-eslint/utils': 5.60.1(eslint@8.30.0)(typescript@4.6.2) eslint: 8.30.0 - jest: 29.5.0(@types/node@14.18.29)(ts-node@10.9.1) + jest: 29.5.0(@types/node@18.0.0)(ts-node@10.9.1) transitivePeerDependencies: - supports-color - typescript @@ -5617,6 +6323,12 @@ packages: engines: {node: '>=4.0'} dev: true + /estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + dependencies: + '@types/estree': 1.0.1 + dev: true + /esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} @@ -5750,6 +6462,17 @@ packages: glob-parent: 5.1.2 merge2: 1.4.1 micromatch: 4.0.5 + dev: false + + /fast-glob@3.3.0: + resolution: {integrity: sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 /fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} @@ -5791,6 +6514,7 @@ packages: /fast-write-atomic@0.2.1: resolution: {integrity: sha512-WvJe06IfNYlr+6cO3uQkdKdy3Cb1LlCJSF8zRs2eT8yuhdbSlR9nIt+TgQ92RUxiRrQm+/S7RARnMfCs5iuAjw==} + dev: false /fastify-plugin@4.5.0: resolution: {integrity: sha512-79ak0JxddO0utAXAQ5ccKhvs6vX2MGyHHMMsmZkBANrq3hXc1CHzvNPHOcvTsVMEPl5I+NT+RO4YKMGehOfSIg==} @@ -5878,6 +6602,7 @@ packages: commondir: 1.0.1 make-dir: 3.1.0 pkg-dir: 4.2.0 + dev: false /find-my-way@7.6.2: resolution: {integrity: sha512-0OjHn1b1nCX3eVbm9ByeEHiscPYiHLfhei1wOUU9qffQkk98wE0Lo8VrVYfSGMgnSnDh86DxedduAnBf4nwUEw==} @@ -5971,6 +6696,11 @@ packages: /fp-ts@2.13.1: resolution: {integrity: sha512-0eu5ULPS2c/jsa1lGFneEFFEdTbembJv8e4QKXeVJ3lm/5hyve06dlKZrpxmMwJt6rYen7sxmHHK2CLaXvWuWQ==} + dev: false + + /fp-ts@2.16.0: + resolution: {integrity: sha512-bLq+KgbiXdTEoT1zcARrWEpa5z6A/8b7PcDW7Gef3NSisQ+VS7ll2Xbf1E+xsgik0rWub/8u0qP/iTTjj+PhxQ==} + dev: false /fresh@0.5.2: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} @@ -6002,7 +6732,6 @@ packages: graceful-fs: 4.2.11 jsonfile: 6.1.0 universalify: 2.0.0 - dev: true /fs-extra@7.0.1: resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} @@ -6026,6 +6755,7 @@ packages: resolution: {integrity: sha512-Xn4fDhLydXkuzepZVsr02jakLlmoARPy+YWIclo4kh0GyNGUHnTqeH/w/qIsVn50dFxtp8otPL2t/HcPJBbxUA==} dependencies: minimatch: 5.1.6 + dev: false /fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -6103,7 +6833,7 @@ packages: get-it: 8.1.4 registry-auth-token: 5.0.2 registry-url: 5.1.0 - semver: 7.3.8 + semver: 7.5.3 transitivePeerDependencies: - supports-color dev: false @@ -6147,6 +6877,17 @@ packages: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} dev: true + /glob@7.1.6: + resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + /glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} dependencies: @@ -6157,6 +6898,16 @@ packages: once: 1.4.0 path-is-absolute: 1.0.1 + /glob@8.1.0: + resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} + engines: {node: '>=12'} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 5.1.6 + once: 1.4.0 + /global-dirs@3.0.1: resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==} engines: {node: '>=10'} @@ -6188,7 +6939,7 @@ packages: dependencies: array-union: 2.1.0 dir-glob: 3.0.1 - fast-glob: 3.2.12 + fast-glob: 3.3.0 ignore: 5.2.4 merge2: 1.4.1 slash: 3.0.0 @@ -6253,6 +7004,7 @@ packages: /has-yarn@2.1.0: resolution: {integrity: sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==} engines: {node: '>=8'} + dev: false /has@1.0.3: resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} @@ -6266,6 +7018,7 @@ packages: dependencies: is-stream: 2.0.1 type-fest: 0.8.1 + dev: false /header-case@2.0.4: resolution: {integrity: sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==} @@ -6322,6 +7075,17 @@ packages: debug: 4.3.4 transitivePeerDependencies: - supports-color + dev: false + + /http-proxy-agent@7.0.0: + resolution: {integrity: sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==} + engines: {node: '>= 14'} + dependencies: + agent-base: 7.1.0 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false /https-proxy-agent@5.0.0: resolution: {integrity: sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==} @@ -6341,6 +7105,17 @@ packages: debug: 4.3.4 transitivePeerDependencies: - supports-color + dev: false + + /https-proxy-agent@7.0.0: + resolution: {integrity: sha512-0euwPCRyAPSgGdzD1IVN9nJYHtBhJwb6XPfbpQcYbPCwrBidX6GzxmchnaF4sfF/jPb74Ojx5g4yTg3sixlyPw==} + engines: {node: '>= 14'} + dependencies: + agent-base: 7.1.0 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false /human-id@1.0.2: resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==} @@ -6360,6 +7135,13 @@ packages: /ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + /ignore-walk@5.0.1: + resolution: {integrity: sha512-yemi4pMf51WKT7khInJqAvsIGzoqYXblnsz0ql8tM+yi1EKYTY1evX4NAbJrLL/Aanr2HyZeluqU+Oi7MGHokw==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dependencies: + minimatch: 5.1.6 + dev: false + /ignore@5.2.4: resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} engines: {node: '>= 4'} @@ -6488,6 +7270,7 @@ packages: resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} engines: {node: '>=8'} hasBin: true + dev: false /is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} @@ -6516,6 +7299,7 @@ packages: /is-interactive@1.0.0: resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} engines: {node: '>=8'} + dev: false /is-negative-zero@2.0.2: resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} @@ -6536,6 +7320,7 @@ packages: /is-path-cwd@2.2.0: resolution: {integrity: sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==} engines: {node: '>=6'} + dev: false /is-path-inside@3.0.3: resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} @@ -6551,6 +7336,12 @@ packages: engines: {node: '>=0.10.0'} dev: false + /is-reference@3.0.1: + resolution: {integrity: sha512-baJJdQLiYaJdvFbJqXrcGv3WU3QCzBlUcI5QhbesIm6/xPsvmO+2CDoi/GMOFBQEQm+PXkwOPrp9KK5ozZsp2w==} + dependencies: + '@types/estree': 1.0.1 + dev: true + /is-regex@1.1.4: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} engines: {node: '>= 0.4'} @@ -6609,6 +7400,7 @@ packages: /is-unicode-supported@0.1.0: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} + dev: false /is-weakref@1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} @@ -6630,6 +7422,7 @@ packages: engines: {node: '>=8'} dependencies: is-docker: 2.2.1 + dev: false /isarray@0.0.1: resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==} @@ -6663,7 +7456,7 @@ packages: '@babel/parser': 7.22.5 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.0 - semver: 6.3.0 + semver: 6.3.1 transitivePeerDependencies: - supports-color dev: true @@ -6712,7 +7505,7 @@ packages: '@jest/expect': 29.5.0 '@jest/test-result': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 14.18.32 + '@types/node': 18.0.0 chalk: 4.1.2 co: 4.6.0 dedent: 0.7.0 @@ -6732,35 +7525,7 @@ packages: - supports-color dev: true - /jest-cli@29.5.0: - resolution: {integrity: sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - dependencies: - '@jest/core': 29.5.0(ts-node@10.9.1) - '@jest/test-result': 29.5.0 - '@jest/types': 29.5.0 - chalk: 4.1.2 - exit: 0.1.2 - graceful-fs: 4.2.11 - import-local: 3.1.0 - jest-config: 29.5.0(@types/node@14.18.32)(ts-node@10.9.1) - jest-util: 29.5.0 - jest-validate: 29.5.0 - prompts: 2.4.2 - yargs: 17.7.2 - transitivePeerDependencies: - - '@types/node' - - supports-color - - ts-node - dev: true - - /jest-cli@29.5.0(@types/node@14.18.29)(ts-node@10.9.1): + /jest-cli@29.5.0(@types/node@18.0.0): resolution: {integrity: sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -6777,7 +7542,7 @@ packages: exit: 0.1.2 graceful-fs: 4.2.11 import-local: 3.1.0 - jest-config: 29.5.0(@types/node@14.18.29)(ts-node@10.9.1) + jest-config: 29.5.0(@types/node@18.0.0)(ts-node@10.9.1) jest-util: 29.5.0 jest-validate: 29.5.0 prompts: 2.4.2 @@ -6788,7 +7553,7 @@ packages: - ts-node dev: true - /jest-cli@29.5.0(@types/node@14.18.32)(ts-node@10.9.1): + /jest-cli@29.5.0(@types/node@18.0.0)(ts-node@10.9.1): resolution: {integrity: sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -6805,7 +7570,7 @@ packages: exit: 0.1.2 graceful-fs: 4.2.11 import-local: 3.1.0 - jest-config: 29.5.0(@types/node@14.18.32)(ts-node@10.9.1) + jest-config: 29.5.0(@types/node@18.0.0)(ts-node@10.9.1) jest-util: 29.5.0 jest-validate: 29.5.0 prompts: 2.4.2 @@ -6816,47 +7581,7 @@ packages: - ts-node dev: true - /jest-config@29.5.0(@types/node@14.18.29)(ts-node@10.9.1): - resolution: {integrity: sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@types/node': '*' - ts-node: '>=9.0.0' - peerDependenciesMeta: - '@types/node': - optional: true - ts-node: - optional: true - dependencies: - '@babel/core': 7.22.5 - '@jest/test-sequencer': 29.5.0 - '@jest/types': 29.5.0 - '@types/node': 14.18.29 - babel-jest: 29.5.0(@babel/core@7.22.5) - chalk: 4.1.2 - ci-info: 3.8.0 - deepmerge: 4.3.1 - glob: 7.2.3 - graceful-fs: 4.2.11 - jest-circus: 29.5.0 - jest-environment-node: 29.5.0 - jest-get-type: 29.4.3 - jest-regex-util: 29.4.3 - jest-resolve: 29.5.0 - jest-runner: 29.5.0 - jest-util: 29.5.0 - jest-validate: 29.5.0 - micromatch: 4.0.5 - parse-json: 5.2.0 - pretty-format: 29.5.0 - slash: 3.0.0 - strip-json-comments: 3.1.1 - ts-node: 10.9.1(@types/node@14.18.32)(typescript@4.8.4) - transitivePeerDependencies: - - supports-color - dev: true - - /jest-config@29.5.0(@types/node@14.18.32)(ts-node@10.9.1): + /jest-config@29.5.0(@types/node@18.0.0)(ts-node@10.9.1): resolution: {integrity: sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: @@ -6871,7 +7596,7 @@ packages: '@babel/core': 7.22.5 '@jest/test-sequencer': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 14.18.32 + '@types/node': 18.0.0 babel-jest: 29.5.0(@babel/core@7.22.5) chalk: 4.1.2 ci-info: 3.8.0 @@ -6891,7 +7616,7 @@ packages: pretty-format: 29.5.0 slash: 3.0.0 strip-json-comments: 3.1.1 - ts-node: 10.9.1(@types/node@14.18.32)(typescript@4.8.4) + ts-node: 10.9.1(@types/node@18.0.0)(typescript@4.8.4) transitivePeerDependencies: - supports-color dev: true @@ -6931,7 +7656,7 @@ packages: '@jest/environment': 29.5.0 '@jest/fake-timers': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 14.18.32 + '@types/node': 18.0.0 jest-mock: 29.5.0 jest-util: 29.5.0 dev: true @@ -6956,7 +7681,7 @@ packages: dependencies: '@jest/types': 29.5.0 '@types/graceful-fs': 4.1.6 - '@types/node': 14.18.32 + '@types/node': 18.0.0 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -7007,7 +7732,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.5.0 - '@types/node': 14.18.32 + '@types/node': 18.0.0 jest-util: 29.5.0 dev: true @@ -7062,7 +7787,7 @@ packages: '@jest/test-result': 29.5.0 '@jest/transform': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 14.18.32 + '@types/node': 18.0.0 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -7093,7 +7818,7 @@ packages: '@jest/test-result': 29.5.0 '@jest/transform': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 14.18.32 + '@types/node': 18.0.0 chalk: 4.1.2 cjs-module-lexer: 1.2.3 collect-v8-coverage: 1.0.1 @@ -7148,7 +7873,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.5.0 - '@types/node': 20.3.2 + '@types/node': 18.0.0 chalk: 4.1.2 ci-info: 3.8.0 graceful-fs: 4.2.11 @@ -7173,7 +7898,7 @@ packages: dependencies: '@jest/test-result': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 14.18.32 + '@types/node': 18.0.0 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -7184,34 +7909,14 @@ packages: /jest-worker@29.5.0: resolution: {integrity: sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@types/node': 14.18.32 - jest-util: 29.5.0 - merge-stream: 2.0.0 - supports-color: 8.1.1 - dev: true - - /jest@29.5.0: - resolution: {integrity: sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - dependencies: - '@jest/core': 29.5.0(ts-node@10.9.1) - '@jest/types': 29.5.0 - import-local: 3.1.0 - jest-cli: 29.5.0 - transitivePeerDependencies: - - '@types/node' - - supports-color - - ts-node + dependencies: + '@types/node': 18.0.0 + jest-util: 29.5.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 dev: true - /jest@29.5.0(@types/node@14.18.29)(ts-node@10.9.1): + /jest@29.5.0(@types/node@18.0.0): resolution: {integrity: sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -7224,14 +7929,14 @@ packages: '@jest/core': 29.5.0(ts-node@10.9.1) '@jest/types': 29.5.0 import-local: 3.1.0 - jest-cli: 29.5.0(@types/node@14.18.29)(ts-node@10.9.1) + jest-cli: 29.5.0(@types/node@18.0.0) transitivePeerDependencies: - '@types/node' - supports-color - ts-node dev: true - /jest@29.5.0(@types/node@14.18.32)(ts-node@10.9.1): + /jest@29.5.0(@types/node@18.0.0)(ts-node@10.9.1): resolution: {integrity: sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -7244,13 +7949,18 @@ packages: '@jest/core': 29.5.0(ts-node@10.9.1) '@jest/types': 29.5.0 import-local: 3.1.0 - jest-cli: 29.5.0(@types/node@14.18.32)(ts-node@10.9.1) + jest-cli: 29.5.0(@types/node@18.0.0)(ts-node@10.9.1) transitivePeerDependencies: - '@types/node' - supports-color - ts-node dev: true + /joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + dev: true + /js-sdsl@4.4.1: resolution: {integrity: sha512-6Gsx8R0RucyePbWqPssR8DyfuXmLBooYN5cZFZKjHGnQuaf7pEzhtpceagJxVu4LqhYY5EYA7nko3FmeHZ1KbA==} dev: true @@ -7354,7 +8064,6 @@ packages: /kleur@4.1.5: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} - dev: true /langium-cli@1.2.0: resolution: {integrity: sha512-DPyJUd4Hj8+OBNEcAQyJtW6e38+UPd758gTI7Ep0r/sDogrwJ/GJHx5nGA+r0ygpNcDPG+mS9Hw8Y05uCNNcoQ==} @@ -7384,6 +8093,7 @@ packages: engines: {node: '>= 0.6.3'} dependencies: readable-stream: 2.3.8 + dev: false /leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} @@ -7406,6 +8116,11 @@ packages: set-cookie-parser: 2.6.0 dev: true + /lilconfig@2.1.0: + resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} + engines: {node: '>=10'} + dev: true + /lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} @@ -7422,6 +8137,11 @@ packages: array-back: 6.2.2 dev: true + /load-tsconfig@0.2.5: + resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + /load-yaml-file@0.2.0: resolution: {integrity: sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==} engines: {node: '>=6'} @@ -7437,6 +8157,10 @@ packages: engines: {node: '>=14'} dev: true + /locate-character@3.0.0: + resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} + dev: true + /locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} @@ -7455,15 +8179,19 @@ packages: /lodash.defaults@4.2.0: resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} + dev: false /lodash.difference@4.5.0: resolution: {integrity: sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==} + dev: false /lodash.flatten@4.4.0: resolution: {integrity: sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==} + dev: false /lodash.isplainobject@4.0.6: resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + dev: false /lodash.memoize@4.1.2: resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} @@ -7473,12 +8201,17 @@ packages: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true + /lodash.sortby@4.7.0: + resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} + dev: true + /lodash.startcase@4.4.0: resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} dev: true /lodash.union@4.6.0: resolution: {integrity: sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==} + dev: false /lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} @@ -7489,6 +8222,7 @@ packages: dependencies: chalk: 4.1.2 is-unicode-supported: 0.1.0 + dev: false /loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} @@ -7507,6 +8241,7 @@ packages: resolution: {integrity: sha512-EVm/rR94FJTZi3zefZ82fLWab+GX14LJN4HrWBcuo6Evmsl9hEfnqxgcHCKb9q+mNf6EVdsjx/qucYFIIB84pg==} dependencies: tslib: 2.6.0 + dev: false /lower-case@2.0.2: resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} @@ -7540,11 +8275,18 @@ packages: '@jridgewell/sourcemap-codec': 1.4.15 dev: true + /magic-string@0.30.1: + resolution: {integrity: sha512-mbVKXPmS0z0G4XqFDCTllmDQ6coZzn94aMlb0o/A4HEHJCKcanlDZwYJgwnkmgD3jyWhUgj9VsPrfd972yPffA==} + engines: {node: '>=12'} + dependencies: + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + /make-dir@3.1.0: resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} engines: {node: '>=8'} dependencies: - semver: 6.3.0 + semver: 6.3.1 /make-error@1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} @@ -7577,6 +8319,10 @@ packages: uc.micro: 1.0.6 dev: true + /mdn-data@2.0.30: + resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} + dev: true + /mdurl@1.0.1: resolution: {integrity: sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==} dev: true @@ -7753,6 +8499,14 @@ packages: engines: {node: '>=12.0.0'} dev: true + /mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + dev: true + /nanoid@3.3.6: resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -7780,8 +8534,9 @@ packages: /new-github-issue-url@0.2.1: resolution: {integrity: sha512-md4cGoxuT4T4d/HDOXbrUHkTKrp/vp+m3aOA7XXVYwNsUNMK49g3SQicTSeV5GIz/5QVGAeYRAOlyp9OvlgsYA==} engines: {node: '>=10'} + dev: false - /next@12.3.1(@babel/core@7.22.5)(react-dom@18.2.0)(react@18.2.0): + /next@12.3.1(@babel/core@7.22.9)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-l7bvmSeIwX5lp07WtIiP9u2ytZMv7jIeB8iacR28PuUEFG5j0HGAPnMqyG5kbZNBG2H7tRsrQ4HCjuMOPnANZw==} engines: {node: '>=12.22.0'} hasBin: true @@ -7805,7 +8560,7 @@ packages: postcss: 8.4.14 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - styled-jsx: 5.0.7(@babel/core@7.22.5)(react@18.2.0) + styled-jsx: 5.0.7(@babel/core@7.22.9)(react@18.2.0) use-sync-external-store: 1.2.0(react@18.2.0) optionalDependencies: '@next/swc-android-arm-eabi': 12.3.1 @@ -7826,7 +8581,7 @@ packages: - babel-plugin-macros dev: true - /next@13.4.5(@babel/core@7.22.5)(react-dom@18.2.0)(react@18.2.0): + /next@13.4.5(@babel/core@7.22.9)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-pfNsRLVM9e5Y1/z02VakJRfD6hMQkr24FaN2xc9GbcZDBxoOgiNAViSg5cXwlWCoMhtm4U315D7XYhgOr96Q3Q==} engines: {node: '>=16.8.0'} hasBin: true @@ -7851,7 +8606,7 @@ packages: postcss: 8.4.14 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - styled-jsx: 5.1.1(@babel/core@7.22.5)(react@18.2.0) + styled-jsx: 5.1.1(@babel/core@7.22.9)(react@18.2.0) watchpack: 2.4.0 zod: 3.21.4 optionalDependencies: @@ -7869,7 +8624,7 @@ packages: - babel-plugin-macros dev: true - /next@13.4.7(@babel/core@7.22.5)(@opentelemetry/api@1.4.1)(react-dom@18.2.0)(react@18.2.0): + /next@13.4.7(@babel/core@7.22.9)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-M8z3k9VmG51SRT6v5uDKdJXcAqLzP3C+vaKfLIAM0Mhx1um1G7MDnO63+m52qPdZfrTFzMZNzfsgvm3ghuVHIQ==} engines: {node: '>=16.8.0'} hasBin: true @@ -7888,14 +8643,13 @@ packages: optional: true dependencies: '@next/env': 13.4.7 - '@opentelemetry/api': 1.4.1 '@swc/helpers': 0.5.1 busboy: 1.6.0 caniuse-lite: 1.0.30001509 postcss: 8.4.14 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - styled-jsx: 5.1.1(@babel/core@7.22.5)(react@18.2.0) + styled-jsx: 5.1.1(@babel/core@7.22.9)(react@18.2.0) watchpack: 2.4.0 zod: 3.21.4 optionalDependencies: @@ -7924,7 +8678,7 @@ packages: resolution: {integrity: sha512-iwXuFrMAcFVi/ZoZiqq8BzAdsLw9kxDfTC0HMyjXfSL/6CSDAGD5UmR7azrAgWV1zKYq7dUUMj4owusBWKLsiQ==} engines: {node: '>=10'} dependencies: - semver: 7.3.8 + semver: 7.5.3 dev: true optional: true @@ -7943,7 +8697,17 @@ packages: optional: true dependencies: whatwg-url: 5.0.0 - dev: true + + /node-fetch@2.6.12: + resolution: {integrity: sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + dependencies: + whatwg-url: 5.0.0 /node-fetch@2.6.7: resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} @@ -7955,6 +8719,7 @@ packages: optional: true dependencies: whatwg-url: 5.0.0 + dev: false /node-fetch@2.6.9: resolution: {integrity: sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==} @@ -7966,6 +8731,7 @@ packages: optional: true dependencies: whatwg-url: 5.0.0 + dev: false /node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} @@ -7998,6 +8764,29 @@ packages: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} + /npm-bundled@2.0.1: + resolution: {integrity: sha512-gZLxXdjEzE/+mOstGDqR6b0EkhJ+kM6fxM6vUuckuctuVPh80Q6pw/rSZj9s4Gex9GxWtIicO1pc8DB9KZWudw==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dependencies: + npm-normalize-package-bin: 2.0.0 + dev: false + + /npm-normalize-package-bin@2.0.0: + resolution: {integrity: sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + dev: false + + /npm-packlist@5.1.3: + resolution: {integrity: sha512-263/0NGrn32YFYi4J533qzrQ/krmmrWwhKkzwTuM4f/07ug51odoaNjUexxO4vxlzURHcmYMH1QjvHjsNDKLVg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + hasBin: true + dependencies: + glob: 8.1.0 + ignore-walk: 5.0.1 + npm-bundled: 2.0.1 + npm-normalize-package-bin: 2.0.0 + dev: false + /npm-run-path@4.0.1: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} @@ -8062,6 +8851,7 @@ packages: dependencies: is-docker: 2.2.1 is-wsl: 2.2.0 + dev: false /openapi-types@12.1.0: resolution: {integrity: sha512-XpeCy01X6L5EpP+6Hc3jWN7rMZJ+/k1lwki/kTmWzbVhdPie3jd5O2ZtedEx8Yp58icJ0osVldLMrTB/zslQXA==} @@ -8091,6 +8881,7 @@ packages: log-symbols: 4.1.0 strip-ansi: 6.0.1 wcwidth: 1.0.1 + dev: false /os-tmpdir@1.0.2: resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} @@ -8152,6 +8943,7 @@ packages: engines: {node: '>=10'} dependencies: aggregate-error: 3.1.0 + dev: false /p-retry@4.6.2: resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==} @@ -8159,6 +8951,7 @@ packages: dependencies: '@types/retry': 0.12.0 retry: 0.13.1 + dev: false /p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} @@ -8268,6 +9061,14 @@ packages: resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} dev: true + /periscopic@3.1.0: + resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==} + dependencies: + '@types/estree': 1.0.1 + estree-walker: 3.0.3 + is-reference: 3.0.1 + dev: true + /picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} dev: true @@ -8338,6 +9139,22 @@ packages: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} + /postcss-load-config@4.0.1: + resolution: {integrity: sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==} + engines: {node: '>= 14'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + dependencies: + lilconfig: 2.1.0 + yaml: 2.2.1 + dev: true + /postcss@8.4.14: resolution: {integrity: sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==} engines: {node: ^10 || ^12 || >=14} @@ -8356,6 +9173,15 @@ packages: source-map-js: 1.0.2 dev: true + /postcss@8.4.26: + resolution: {integrity: sha512-jrXHFF8iTloAenySjM/ob3gSj7pCu0Ji49hnjqzsgSRa50hkWCKD0HQ+gMNJkW38jBI68MpAAg7ZWwHwX8NMMw==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.6 + picocolors: 1.0.0 + source-map-js: 1.0.2 + dev: true + /prebuild-install@7.1.1: resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==} engines: {node: '>=10'} @@ -8427,23 +9253,6 @@ packages: hasBin: true dev: true - /prisma@4.0.0: - resolution: {integrity: sha512-Dtsar03XpCBkcEb2ooGWO/WcgblDTLzGhPcustbehwlFXuTMliMDRzXsfygsgYwQoZnAUKRd1rhpvBNEUziOVw==} - engines: {node: '>=14.17'} - hasBin: true - requiresBuild: true - dependencies: - '@prisma/engines': 3.16.0-49.da41d2bb3406da22087b849f0e911199ba4fbf11 - dev: true - - /prisma@4.7.0: - resolution: {integrity: sha512-VsecNo0Ca3+bDTzSpJqIpdupKVhhQ8aOYeWc09JlUM89knqvhSrlMrg0U8BiOD4tFrY1OPaCcraK8leDBxKMBg==} - engines: {node: '>=14.17'} - hasBin: true - requiresBuild: true - dependencies: - '@prisma/engines': 4.7.0 - /process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} @@ -8466,6 +9275,7 @@ packages: /progress@2.0.3: resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} engines: {node: '>=0.4.0'} + dev: false /promise-polyfill@8.3.0: resolution: {integrity: sha512-H5oELycFml5yto/atYqmjyigJoAo3+OXwolYiH7OfQuYlAqhxNvTfiNMbV9hsC6Yp83yE5r2KTVmtrG6R9i6Pg==} @@ -8581,17 +9391,6 @@ packages: minimist: 1.2.8 strip-json-comments: 2.0.1 - /react-dom@17.0.2(react@17.0.2): - resolution: {integrity: sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==} - peerDependencies: - react: 17.0.2 - dependencies: - loose-envify: 1.4.0 - object-assign: 4.1.1 - react: 17.0.2 - scheduler: 0.20.2 - dev: true - /react-dom@18.2.0(react@18.2.0): resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} peerDependencies: @@ -8618,14 +9417,6 @@ packages: react: 18.2.0 dev: true - /react@17.0.2: - resolution: {integrity: sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==} - engines: {node: '>=0.10.0'} - dependencies: - loose-envify: 1.4.0 - object-assign: 4.1.1 - dev: true - /react@18.2.0: resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} engines: {node: '>=0.10.0'} @@ -8709,6 +9500,7 @@ packages: resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} dependencies: minimatch: 5.1.6 + dev: false /readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} @@ -8789,9 +9581,20 @@ packages: typical: 7.1.1 dev: true + /replace-in-file@7.0.1: + resolution: {integrity: sha512-KbhgPq04eA+TxXuUxpgWIH9k/TjF+28ofon2PXP7vq6izAILhxOtksCVcLuuQLtyjouBaPdlH6RJYYcSPVxCOA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + chalk: 4.1.2 + glob: 8.1.0 + yargs: 17.7.2 + dev: true + /replace-string@3.1.0: resolution: {integrity: sha512-yPpxc4ZR2makceA9hy/jHNqc7QVkd4Je/N0WRHm6bs3PtivPuPynxE5ejU/mp5EhnCv8+uZL7vhz8rkluSlx+Q==} engines: {node: '>=8'} + dev: false /require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} @@ -8836,6 +9639,7 @@ packages: is-core-module: 2.12.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + dev: false /resolve@1.22.2: resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==} @@ -8851,6 +9655,7 @@ packages: dependencies: onetime: 5.1.2 signal-exit: 3.0.7 + dev: false /ret@0.2.2: resolution: {integrity: sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==} @@ -8860,6 +9665,7 @@ packages: /retry@0.13.1: resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} engines: {node: '>= 4'} + dev: false /reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} @@ -8883,6 +9689,14 @@ packages: fsevents: 2.3.2 dev: true + /rollup@3.26.3: + resolution: {integrity: sha512-7Tin0C8l86TkpcMtXvQu6saWH93nhG3dGQ1/+l5V2TDMceTxO7kDiK6GzbfLWNNxqJXm591PcEZUozZm51ogwQ==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} + hasBin: true + optionalDependencies: + fsevents: 2.3.2 + dev: true + /run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} dependencies: @@ -8934,13 +9748,6 @@ packages: resolution: {integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==} dev: true - /scheduler@0.20.2: - resolution: {integrity: sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==} - dependencies: - loose-envify: 1.4.0 - object-assign: 4.1.1 - dev: true - /scheduler@0.23.0: resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} dependencies: @@ -8955,8 +9762,8 @@ packages: resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==} hasBin: true - /semver@6.3.0: - resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} + /semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true /semver@7.3.8: @@ -8965,6 +9772,7 @@ packages: hasBin: true dependencies: lru-cache: 6.0.0 + dev: false /semver@7.5.3: resolution: {integrity: sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==} @@ -8972,7 +9780,6 @@ packages: hasBin: true dependencies: lru-cache: 6.0.0 - dev: true /send@0.18.0: resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} @@ -9109,6 +9916,7 @@ packages: ansi-styles: 4.3.0 astral-regex: 2.0.0 is-fullwidth-code-point: 3.0.0 + dev: false /slice-ansi@5.0.0: resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} @@ -9161,6 +9969,13 @@ packages: engines: {node: '>=0.10.0'} dev: true + /source-map@0.8.0-beta.0: + resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} + engines: {node: '>= 8'} + dependencies: + whatwg-url: 7.1.0 + dev: true + /spawn-command@0.0.2-1: resolution: {integrity: sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==} dev: true @@ -9355,7 +10170,7 @@ packages: acorn: 8.9.0 dev: true - /styled-jsx@5.0.7(@babel/core@7.22.5)(react@18.2.0): + /styled-jsx@5.0.7(@babel/core@7.22.9)(react@18.2.0): resolution: {integrity: sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA==} engines: {node: '>= 12.0.0'} peerDependencies: @@ -9368,11 +10183,11 @@ packages: babel-plugin-macros: optional: true dependencies: - '@babel/core': 7.22.5 + '@babel/core': 7.22.9 react: 18.2.0 dev: true - /styled-jsx@5.1.1(@babel/core@7.22.5)(react@18.2.0): + /styled-jsx@5.1.1(@babel/core@7.22.9)(react@18.2.0): resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} engines: {node: '>= 12.0.0'} peerDependencies: @@ -9385,11 +10200,25 @@ packages: babel-plugin-macros: optional: true dependencies: - '@babel/core': 7.22.5 + '@babel/core': 7.22.9 client-only: 0.0.1 react: 18.2.0 dev: true + /sucrase@3.33.0: + resolution: {integrity: sha512-ARGC7vbufOHfpvyGcZZXFaXCMZ9A4fffOGC5ucOW7+WHDGlAe8LJdf3Jts1sWhDeiI1RSWrKy5Hodl+JWGdW2A==} + engines: {node: '>=8'} + hasBin: true + dependencies: + '@jridgewell/gen-mapping': 0.3.3 + commander: 4.1.1 + glob: 7.1.6 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.6 + ts-interface-checker: 0.1.13 + dev: true + /superagent@8.0.9: resolution: {integrity: sha512-4C7Bh5pyHTvU33KpZgwrNKh/VQnvgtCSqPRfJAUdmrtSYePVzVg4E4OzsrbkhJj9O7SO6Bnv75K/F8XVZT8YHA==} engines: {node: '>=6.4.0 <13 || >=14'} @@ -9450,18 +10279,19 @@ packages: dependencies: has-flag: 4.0.0 supports-color: 7.2.0 + dev: false /supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - /svelte-hmr@0.15.2(svelte@3.59.2): + /svelte-hmr@0.15.2(svelte@4.0.5): resolution: {integrity: sha512-q/bAruCvFLwvNbeE1x3n37TYFb3mTBJ6TrCq6p2CoFbSTNhDE9oAtEfpy+wmc9So8AG0Tja+X0/mJzX9tSfvIg==} engines: {node: ^12.20 || ^14.13.1 || >= 16} peerDependencies: svelte: ^3.19.0 || ^4.0.0-next.0 dependencies: - svelte: 3.59.2 + svelte: 4.0.5 dev: true /svelte@3.59.2: @@ -9469,14 +10299,33 @@ packages: engines: {node: '>= 8'} dev: true - /swr@2.0.3(react@17.0.2): + /svelte@4.0.5: + resolution: {integrity: sha512-PHKPWP1wiWHBtsE57nCb8xiWB3Ht7/3Kvi3jac0XIxUM2rep8alO7YoAtgWeGD7++tFy46krilOrPW0mG3Dx+A==} + engines: {node: '>=16'} + dependencies: + '@ampproject/remapping': 2.2.1 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.18 + acorn: 8.10.0 + aria-query: 5.3.0 + axobject-query: 3.2.1 + code-red: 1.0.3 + css-tree: 2.3.1 + estree-walker: 3.0.3 + is-reference: 3.0.1 + locate-character: 3.0.0 + magic-string: 0.30.1 + periscopic: 3.1.0 + dev: true + + /swr@2.0.3(react@18.2.0): resolution: {integrity: sha512-sGvQDok/AHEWTPfhUWXEHBVEXmgGnuahyhmRQbjl9XBYxT/MSlAzvXEKQpyM++bMPaI52vcWS2HiKNaW7+9OFw==} engines: {pnpm: '7'} peerDependencies: react: ^16.11.0 || ^17.0.0 || ^18.0.0 dependencies: - react: 17.0.2 - use-sync-external-store: 1.2.0(react@17.0.2) + react: 18.2.0 + use-sync-external-store: 1.2.0(react@18.2.0) dev: true /table-layout@1.0.2: @@ -9512,10 +10361,12 @@ packages: /temp-dir@1.0.0: resolution: {integrity: sha512-xZFXEGbG7SNC3itwBzI3RYjq/cEhBkx2hJuKGIUOcEULmkQExXiHat2z/qkISYsuR+IKumhEfKKbV5qXmhICFQ==} engines: {node: '>=4'} + dev: false /temp-dir@2.0.0: resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==} engines: {node: '>=8'} + dev: false /temp-write@4.0.0: resolution: {integrity: sha512-HIeWmj77uOOHb0QX7siN3OtwV3CTntquin6TNVg6SHOqCP3hYKmox90eeFOGaY1MqJ9WYDDjkyZrW6qS5AWpbw==} @@ -9526,6 +10377,7 @@ packages: make-dir: 3.1.0 temp-dir: 1.0.0 uuid: 3.4.0 + dev: false /tempy@1.0.1: resolution: {integrity: sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w==} @@ -9536,6 +10388,7 @@ packages: temp-dir: 2.0.0 type-fest: 0.16.0 unique-string: 2.0.0 + dev: false /term-size@2.2.1: resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} @@ -9548,6 +10401,7 @@ packages: dependencies: ansi-escapes: 4.3.2 supports-hyperlinks: 2.3.0 + dev: false /test-exclude@6.0.0: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} @@ -9562,6 +10416,19 @@ packages: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true + /thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + dependencies: + thenify: 3.3.1 + dev: true + + /thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + dependencies: + any-promise: 1.3.0 + dev: true + /thread-stream@2.3.0: resolution: {integrity: sha512-kaDqm1DET9pp3NXwR8382WHbnpXnRkN9xGN9dQt3B2+dmXiW8X1SOwmFOxAErEQ47ObhZ96J6yhZNXuyCOL7KA==} dependencies: @@ -9638,6 +10505,12 @@ packages: /tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + /tr46@1.0.1: + resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} + dependencies: + punycode: 2.3.0 + dev: true + /tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -9648,12 +10521,16 @@ packages: engines: {node: '>=8'} dev: true + /ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + dev: true + /ts-japi@1.8.0: resolution: {integrity: sha512-77cNpz1CMJsImcikE7gnihMKOME4c/prCaruBmr7yMRHGnmEt1llFyJbuokXCaEmm0hERPv2VlzTyZ+pb43leg==} engines: {node: '>=10'} dev: false - /ts-jest@29.0.1(@babel/core@7.22.5)(jest@29.5.0)(typescript@4.6.2): + /ts-jest@29.0.1(@babel/core@7.22.9)(esbuild@0.18.13)(jest@29.5.0)(typescript@4.6.2): resolution: {integrity: sha512-htQOHshgvhn93QLxrmxpiQPk69+M1g7govO1g6kf6GsjCv4uvRV0znVmDrrvjUrVCnTYeY4FBxTYYYD4airyJA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -9674,10 +10551,11 @@ packages: esbuild: optional: true dependencies: - '@babel/core': 7.22.5 + '@babel/core': 7.22.9 bs-logger: 0.2.6 + esbuild: 0.18.13 fast-json-stable-stringify: 2.1.0 - jest: 29.5.0(@types/node@14.18.29)(ts-node@10.9.1) + jest: 29.5.0(@types/node@18.0.0)(ts-node@10.9.1) jest-util: 29.5.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -9687,7 +10565,7 @@ packages: yargs-parser: 21.1.1 dev: true - /ts-jest@29.0.3(@babel/core@7.22.5)(esbuild@0.15.12)(jest@29.5.0)(typescript@4.8.4): + /ts-jest@29.0.3(@babel/core@7.22.9)(esbuild@0.15.12)(jest@29.5.0)(typescript@4.8.4): resolution: {integrity: sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -9708,21 +10586,21 @@ packages: esbuild: optional: true dependencies: - '@babel/core': 7.22.5 + '@babel/core': 7.22.9 bs-logger: 0.2.6 esbuild: 0.15.12 fast-json-stable-stringify: 2.1.0 - jest: 29.5.0(@types/node@14.18.32)(ts-node@10.9.1) + jest: 29.5.0(@types/node@18.0.0)(ts-node@10.9.1) jest-util: 29.5.0 json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 - semver: 7.3.8 + semver: 7.5.3 typescript: 4.8.4 yargs-parser: 21.1.1 dev: true - /ts-jest@29.0.5(@babel/core@7.22.5)(jest@29.5.0)(typescript@4.9.4): + /ts-jest@29.0.5(@babel/core@7.22.5)(esbuild@0.18.13)(jest@29.5.0)(typescript@4.9.5): resolution: {integrity: sha512-PL3UciSgIpQ7f6XjVOmbi96vmDHUqAyqDr8YxzopDqX3kfgYtX1cuNeBjP+L9sFXi6nzsGGA6R3fP3DDDJyrxA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -9745,18 +10623,19 @@ packages: dependencies: '@babel/core': 7.22.5 bs-logger: 0.2.6 + esbuild: 0.18.13 fast-json-stable-stringify: 2.1.0 - jest: 29.5.0 + jest: 29.5.0(@types/node@18.0.0) jest-util: 29.5.0 json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 semver: 7.5.3 - typescript: 4.9.4 + typescript: 4.9.5 yargs-parser: 21.1.1 dev: true - /ts-jest@29.0.5(@babel/core@7.22.5)(jest@29.5.0)(typescript@4.9.5): + /ts-jest@29.0.5(@babel/core@7.22.9)(esbuild@0.18.13)(jest@29.5.0)(typescript@4.9.4): resolution: {integrity: sha512-PL3UciSgIpQ7f6XjVOmbi96vmDHUqAyqDr8YxzopDqX3kfgYtX1cuNeBjP+L9sFXi6nzsGGA6R3fP3DDDJyrxA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -9777,16 +10656,17 @@ packages: esbuild: optional: true dependencies: - '@babel/core': 7.22.5 + '@babel/core': 7.22.9 bs-logger: 0.2.6 + esbuild: 0.18.13 fast-json-stable-stringify: 2.1.0 - jest: 29.5.0 + jest: 29.5.0(@types/node@18.0.0) jest-util: 29.5.0 json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 semver: 7.5.3 - typescript: 4.9.5 + typescript: 4.9.4 yargs-parser: 21.1.1 dev: true @@ -9797,7 +10677,7 @@ packages: code-block-writer: 11.0.3 dev: false - /ts-node@10.9.1(@types/node@14.18.29)(typescript@4.6.2): + /ts-node@10.9.1(@types/node@18.0.0)(typescript@4.6.2): resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} hasBin: true peerDependencies: @@ -9816,7 +10696,7 @@ packages: '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 14.18.29 + '@types/node': 18.0.0 acorn: 8.9.0 acorn-walk: 8.2.0 arg: 4.1.3 @@ -9828,7 +10708,7 @@ packages: yn: 3.1.1 dev: true - /ts-node@10.9.1(@types/node@14.18.32)(typescript@4.8.4): + /ts-node@10.9.1(@types/node@18.0.0)(typescript@4.8.4): resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} hasBin: true peerDependencies: @@ -9847,7 +10727,7 @@ packages: '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 14.18.32 + '@types/node': 18.0.0 acorn: 8.9.0 acorn-walk: 8.2.0 arg: 4.1.3 @@ -9861,9 +10741,11 @@ packages: /ts-pattern@4.1.3: resolution: {integrity: sha512-8beXMWTGEv1JfDjSxfNhe4uT5jKYdhmEUKzt4gZW9dmHlquq3b+IbEyA7vX9LjBfzHmvKnM4HiomAUCyaW2Pew==} + dev: false /ts-pattern@4.3.0: resolution: {integrity: sha512-pefrkcd4lmIVR0LA49Imjf9DYLK8vtWhqBPA3Ya1ir8xCW0O2yjL9dsCVvI7pCodLC5q7smNpEtDR2yVulQxOg==} + dev: false /tsc-alias@1.7.0: resolution: {integrity: sha512-n/K6g8S7Ec7Y/A2Z77Ikp2Uv1S1ERtT63ni69XV4W1YPT4rnNmz8ItgIiJYvKfFnKfqcZQ81UPjoKpMTxaC/rg==} @@ -9887,6 +10769,41 @@ packages: /tslib@2.6.0: resolution: {integrity: sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==} + /tsup@7.1.0: + resolution: {integrity: sha512-mazl/GRAk70j8S43/AbSYXGgvRP54oQeX8Un4iZxzATHt0roW0t6HYDVZIXMw0ZQIpvr1nFMniIVnN5186lW7w==} + engines: {node: '>=16.14'} + hasBin: true + peerDependencies: + '@swc/core': ^1 + postcss: ^8.4.12 + typescript: '>=4.1.0' + peerDependenciesMeta: + '@swc/core': + optional: true + postcss: + optional: true + typescript: + optional: true + dependencies: + bundle-require: 4.0.1(esbuild@0.18.13) + cac: 6.7.14 + chokidar: 3.5.3 + debug: 4.3.4 + esbuild: 0.18.13 + execa: 5.1.1 + globby: 11.1.0 + joycon: 3.1.1 + postcss-load-config: 4.0.1 + resolve-from: 5.0.0 + rollup: 3.25.3 + source-map: 0.8.0-beta.0 + sucrase: 3.33.0 + tree-kill: 1.2.2 + transitivePeerDependencies: + - supports-color + - ts-node + dev: true + /tsutils@3.21.0(typescript@4.6.2): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} @@ -9960,6 +10877,7 @@ packages: /type-fest@0.16.0: resolution: {integrity: sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==} engines: {node: '>=10'} + dev: false /type-fest@0.20.2: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} @@ -10073,6 +10991,7 @@ packages: engines: {node: '>=12.18'} dependencies: busboy: 1.6.0 + dev: false /undici@5.22.1: resolution: {integrity: sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==} @@ -10086,6 +11005,7 @@ packages: engines: {node: '>=8'} dependencies: crypto-random-string: 2.0.0 + dev: false /universalify@0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} @@ -10121,6 +11041,7 @@ packages: resolution: {integrity: sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==} dependencies: tslib: 2.6.0 + dev: false /upper-case@2.0.2: resolution: {integrity: sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==} @@ -10143,14 +11064,6 @@ packages: engines: {node: '>=0.12.0'} dev: false - /use-sync-external-store@1.2.0(react@17.0.2): - resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - dependencies: - react: 17.0.2 - dev: true - /use-sync-external-store@1.2.0(react@18.2.0): resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} peerDependencies: @@ -10171,10 +11084,12 @@ packages: resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. hasBin: true + dev: false /uuid@8.3.2: resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} hasBin: true + dev: false /uuid@9.0.0: resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==} @@ -10204,7 +11119,7 @@ packages: engines: {node: '>= 0.8'} dev: true - /vite-node@0.29.7(@types/node@14.18.32): + /vite-node@0.29.7(@types/node@18.0.0): resolution: {integrity: sha512-PakCZLvz37yFfUPWBnLa1OYHPCGm5v4pmRrTcFN4V/N/T3I6tyP3z07S//9w+DdeL7vVd0VSeyMZuAh+449ZWw==} engines: {node: '>=v14.16.0'} hasBin: true @@ -10214,7 +11129,7 @@ packages: mlly: 1.4.0 pathe: 1.1.1 picocolors: 1.0.0 - vite: 4.3.9(@types/node@14.18.32) + vite: 4.3.9(@types/node@18.0.0) transitivePeerDependencies: - '@types/node' - less @@ -10225,7 +11140,7 @@ packages: - terser dev: true - /vite@4.3.9(@types/node@14.18.32): + /vite@4.3.9(@types/node@18.0.0): resolution: {integrity: sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==} engines: {node: ^14.18.0 || >=16.0.0} hasBin: true @@ -10250,7 +11165,7 @@ packages: terser: optional: true dependencies: - '@types/node': 14.18.32 + '@types/node': 18.0.0 esbuild: 0.17.19 postcss: 8.4.24 rollup: 3.25.3 @@ -10258,7 +11173,42 @@ packages: fsevents: 2.3.2 dev: true - /vitefu@0.2.4(vite@4.3.9): + /vite@4.4.4: + resolution: {integrity: sha512-4mvsTxjkveWrKDJI70QmelfVqTm+ihFAb6+xf4sjEU2TmUCTlVX87tmg/QooPEMQb/lM9qGHT99ebqPziEd3wg==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + '@types/node': '>= 14' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + esbuild: 0.18.14 + postcss: 8.4.26 + rollup: 3.26.3 + optionalDependencies: + fsevents: 2.3.2 + dev: true + + /vitefu@0.2.4(vite@4.4.4): resolution: {integrity: sha512-fanAXjSaf9xXtOOeno8wZXIhgia+CZury481LsDaV++lSvcU2R9Ch2bPh3PYFyoHW+w9LqAeYRISVQjUIew14g==} peerDependencies: vite: ^3.0.0 || ^4.0.0 @@ -10266,7 +11216,7 @@ packages: vite: optional: true dependencies: - vite: 4.3.9(@types/node@14.18.32) + vite: 4.4.4 dev: true /vitest@0.29.7: @@ -10299,7 +11249,7 @@ packages: dependencies: '@types/chai': 4.3.5 '@types/chai-subset': 1.3.3 - '@types/node': 14.18.32 + '@types/node': 18.0.0 '@vitest/expect': 0.29.7 '@vitest/runner': 0.29.7 '@vitest/spy': 0.29.7 @@ -10318,8 +11268,8 @@ packages: tinybench: 2.5.0 tinypool: 0.4.0 tinyspy: 1.1.1 - vite: 4.3.9(@types/node@14.18.32) - vite-node: 0.29.7(@types/node@14.18.32) + vite: 4.3.9(@types/node@18.0.0) + vite-node: 0.29.7(@types/node@18.0.0) why-is-node-running: 2.2.2 transitivePeerDependencies: - less @@ -10339,7 +11289,7 @@ packages: engines: {vscode: ^1.67.0} dependencies: minimatch: 3.1.2 - semver: 7.3.8 + semver: 7.5.3 vscode-languageserver-protocol: 3.17.2 dev: false @@ -10394,6 +11344,10 @@ packages: /webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + /webidl-conversions@4.0.2: + resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} + dev: true + /whatwg-fetch@3.6.2: resolution: {integrity: sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==} dev: true @@ -10404,6 +11358,14 @@ packages: tr46: 0.0.3 webidl-conversions: 3.0.1 + /whatwg-url@7.1.0: + resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} + dependencies: + lodash.sortby: 4.7.0 + tr46: 1.0.1 + webidl-conversions: 4.0.2 + dev: true + /when@3.7.8: resolution: {integrity: sha512-5cZ7mecD3eYcMiCH4wtRPA5iFJZ50BJYDfckI5RRpQiktMiYTcn0ccLTZOvcbBume+1304fQztxeNzNS9Gvrnw==} dev: false @@ -10542,7 +11504,6 @@ packages: /yaml@2.2.1: resolution: {integrity: sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==} engines: {node: '>= 14'} - dev: false /yargs-parser@18.1.3: resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} @@ -10639,6 +11600,7 @@ packages: archiver-utils: 2.1.0 compress-commons: 4.1.1 readable-stream: 3.6.2 + dev: false /zod-validation-error@0.2.1(zod@3.21.1): resolution: {integrity: sha512-zGg6P5EHi5V0dvyEeC8HBZd2pzp7QDKTngkSWgWunljrY+0SHkHyjI519D+u8/37BHkGHAFseWgnZ2Uq8LNFKg==} diff --git a/script/test-prisma-v5.sh b/script/test-prisma-v5.sh new file mode 100755 index 000000000..853c75b02 --- /dev/null +++ b/script/test-prisma-v5.sh @@ -0,0 +1,3 @@ +echo Setting Prisma Versions to V5 +npx replace-in-file '/"prisma":\s*"\^4.0.0"/g' '"prisma": "^5.0.0"' 'packages/testtools/**/package*.json' 'tests/integration/**/package*.json' --isRegex +npx replace-in-file '/"@prisma/client":\s*"\^4.0.0"/g' '"@prisma/client": "^5.0.0"' 'packages/testtools/**/package*.json' 'tests/integration/**/package*.json' --isRegex diff --git a/tests/integration/package.json b/tests/integration/package.json index 333edde81..7c2c9d096 100644 --- a/tests/integration/package.json +++ b/tests/integration/package.json @@ -17,9 +17,9 @@ "@types/supertest": "^2.0.12", "@types/tmp": "^0.2.3", "@types/uuid": "^8.3.4", + "@zenstackhq/runtime": "workspace:*", "@zenstackhq/server": "workspace:*", "@zenstackhq/swr": "workspace:*", - "@zenstackhq/runtime": "workspace:*", "@zenstackhq/trpc": "workspace:*", "eslint": "^8.30.0", "eslint-plugin-jest": "^27.1.7", @@ -27,7 +27,6 @@ "jest": "^29.5.0", "jest-fetch-mock": "^3.0.3", "next": "^12.3.1", - "prisma": "~4.7.0", "tmp": "^0.2.1", "ts-jest": "^29.0.1", "ts-node": "^10.9.1", @@ -36,8 +35,7 @@ "zenstack": "workspace: *" }, "dependencies": { - "@prisma/client": "^4.7.0", - "@types/node": "^14.18.29", + "@types/node": "^18.0.0", "@zenstackhq/sdk": "workspace:*", "@zenstackhq/testtools": "workspace:*", "bcryptjs": "^2.4.3", diff --git a/tests/integration/test-run/.gitignore b/tests/integration/test-run/.gitignore new file mode 100644 index 000000000..483a9c42c --- /dev/null +++ b/tests/integration/test-run/.gitignore @@ -0,0 +1 @@ +package-lock.json \ No newline at end of file diff --git a/tests/integration/test-run/package-lock.json b/tests/integration/test-run/package-lock.json deleted file mode 100644 index 2bdb83310..000000000 --- a/tests/integration/test-run/package-lock.json +++ /dev/null @@ -1,492 +0,0 @@ -{ - "name": "test-run", - "version": "1.0.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "test-run", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "@prisma/client": "^4.16.2", - "@zenstackhq/runtime": "file:../../../packages/runtime/dist", - "prisma": "^4.16.2", - "react": "^18.2.0", - "swr": "^1.3.0", - "typescript": "^4.9.3", - "zenstack": "file:../../../packages/schema/dist", - "zod": "3.21.1" - } - }, - "../../../../packages/runtime/dist": { - "name": "@zenstackhq/runtime", - "version": "0.6.0-pre.11", - "extraneous": true, - "license": "MIT", - "dependencies": { - "@types/bcryptjs": "^2.4.2", - "bcryptjs": "^2.4.3", - "change-case": "^4.1.2", - "colors": "1.4.0", - "cuid": "^2.1.8", - "decimal.js": "^10.4.2", - "deepcopy": "^2.1.0", - "superjson": "^1.11.0", - "swr": "^1.3.0", - "tslib": "^2.4.1", - "zod": "3.21.1", - "zod-validation-error": "^0.2.1" - }, - "devDependencies": { - "@types/bcryptjs": "^2.4.2", - "@types/jest": "^29.0.3", - "@types/node": "^14.18.29", - "rimraf": "^3.0.2", - "typescript": "^4.9.3" - }, - "peerDependencies": { - "@prisma/client": "^4.7.1", - "next": "^12.3.1 || ^13", - "react": "^17.0.2 || ^18", - "react-dom": "^17.0.2 || ^18" - } - }, - "../../../../packages/schema/dist": { - "name": "zenstack", - "version": "0.6.0-pre.11", - "extraneous": true, - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "@prisma/generator-helper": "^4.7.1", - "@prisma/internals": "^4.7.1", - "@zenstackhq/language": "workspace:*", - "@zenstackhq/runtime": "workspace:*", - "@zenstackhq/sdk": "workspace:*", - "async-exit-hook": "^2.0.1", - "change-case": "^4.1.2", - "chevrotain": "^9.1.0", - "colors": "1.4.0", - "commander": "^8.3.0", - "cuid": "^2.1.8", - "langium": "^0.5.0", - "mixpanel": "^0.17.0", - "node-machine-id": "^1.1.12", - "ora": "^5.4.1", - "pluralize": "^8.0.0", - "prisma": "~4.7.0", - "promisify": "^0.0.3", - "sleep-promise": "^9.1.0", - "ts-morph": "^16.0.0", - "uuid": "^9.0.0", - "vscode-jsonrpc": "^8.0.2", - "vscode-languageclient": "^8.0.2", - "vscode-languageserver": "^8.0.2", - "vscode-languageserver-textdocument": "^1.0.7", - "vscode-uri": "^3.0.6", - "zod": "3.21.1" - }, - "bin": { - "zenstack": "bin/cli" - }, - "devDependencies": { - "@babel/cli": "^7.19.3", - "@babel/core": "^7.20.5", - "@babel/preset-env": "^7.20.2", - "@babel/preset-typescript": "^7.18.6", - "@types/async-exit-hook": "^2.0.0", - "@types/jest": "^29.2.0", - "@types/node": "^14.18.32", - "@types/pluralize": "^0.0.29", - "@types/tmp": "^0.2.3", - "@types/uuid": "^8.3.4", - "@types/vscode": "^1.56.0", - "@typescript-eslint/eslint-plugin": "^5.42.0", - "@typescript-eslint/parser": "^5.42.0", - "babel-plugin-inline-dotenv": "^1.7.0", - "concurrently": "^7.4.0", - "dotenv": "^16.0.3", - "esbuild": "^0.15.12", - "eslint": "^8.27.0", - "jest": "^29.2.1", - "langium-cli": "^0.5.0", - "rimraf": "^3.0.2", - "tmp": "^0.2.1", - "ts-jest": "^29.0.3", - "ts-node": "^10.9.1", - "tsc-alias": "^1.7.0", - "tsconfig-paths-jest": "^0.0.1", - "typescript": "^4.8.4", - "vsce": "^2.13.0" - }, - "engines": { - "vscode": "^1.56.0" - } - }, - "../../../packages/runtime/dist": { - "name": "@zenstackhq/runtime", - "version": "1.0.0-beta.8", - "license": "MIT", - "dependencies": { - "@paralleldrive/cuid2": "^2.2.0", - "@types/bcryptjs": "^2.4.2", - "bcryptjs": "^2.4.3", - "change-case": "^4.1.2", - "colors": "1.4.0", - "decimal.js": "^10.4.2", - "deepcopy": "^2.1.0", - "lower-case-first": "^2.0.2", - "pluralize": "^8.0.0", - "superjson": "^1.11.0", - "tslib": "^2.4.1", - "upper-case-first": "^2.0.2", - "zod": "3.21.1", - "zod-validation-error": "^0.2.1" - }, - "devDependencies": { - "@prisma/client": "^4.0.0", - "@types/bcryptjs": "^2.4.2", - "@types/jest": "^29.5.0", - "@types/lower-case-first": "^1.0.1", - "@types/node": "^14.18.29", - "@types/pluralize": "^0.0.29", - "copyfiles": "^2.4.1", - "rimraf": "^3.0.2", - "typescript": "^4.9.3" - } - }, - "../../../packages/schema/dist": { - "name": "zenstack", - "version": "1.0.0-beta.8", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "@paralleldrive/cuid2": "^2.2.0", - "@prisma/generator-helper": "4.10.0", - "@prisma/internals": "4.10.0", - "@zenstackhq/language": "workspace:*", - "@zenstackhq/sdk": "workspace:*", - "async-exit-hook": "^2.0.1", - "change-case": "^4.1.2", - "colors": "1.4.0", - "commander": "^8.3.0", - "get-latest-version": "^5.0.1", - "langium": "1.2.0", - "lower-case-first": "^2.0.2", - "mixpanel": "^0.17.0", - "node-machine-id": "^1.1.12", - "ora": "^5.4.1", - "pluralize": "^8.0.0", - "promisify": "^0.0.3", - "semver": "^7.3.8", - "sleep-promise": "^9.1.0", - "strip-color": "^0.1.0", - "ts-morph": "^16.0.0", - "ts-pattern": "^4.3.0", - "upper-case-first": "^2.0.2", - "uuid": "^9.0.0", - "vscode-jsonrpc": "^8.0.2", - "vscode-languageclient": "^8.0.2", - "vscode-languageserver": "^8.0.2", - "vscode-languageserver-textdocument": "^1.0.7", - "vscode-uri": "^3.0.6", - "zod": "3.21.1", - "zod-validation-error": "^0.2.1" - }, - "bin": { - "zenstack": "bin/cli" - }, - "devDependencies": { - "@types/async-exit-hook": "^2.0.0", - "@types/jest": "^29.5.0", - "@types/lower-case-first": "^1.0.1", - "@types/node": "^14.18.32", - "@types/pluralize": "^0.0.29", - "@types/semver": "^7.3.13", - "@types/strip-color": "^0.1.0", - "@types/tmp": "^0.2.3", - "@types/upper-case-first": "^1.1.2", - "@types/uuid": "^8.3.4", - "@types/vscode": "^1.56.0", - "@typescript-eslint/eslint-plugin": "^5.42.0", - "@typescript-eslint/parser": "^5.42.0", - "@vscode/vsce": "^2.19.0", - "@zenstackhq/runtime": "workspace:*", - "concurrently": "^7.4.0", - "copyfiles": "^2.4.1", - "dotenv": "^16.0.3", - "esbuild": "^0.15.12", - "eslint": "^8.27.0", - "eslint-plugin-jest": "^27.1.7", - "jest": "^29.5.0", - "prisma": "^4.0.0", - "renamer": "^4.0.0", - "rimraf": "^3.0.2", - "tmp": "^0.2.1", - "ts-jest": "^29.0.3", - "ts-node": "^10.9.1", - "tsc-alias": "^1.7.0", - "typescript": "^4.8.4", - "vitest": "^0.29.7" - }, - "engines": { - "vscode": "^1.56.0" - } - }, - "node_modules/@prisma/client": { - "version": "4.16.2", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.16.2.tgz", - "integrity": "sha512-qCoEyxv1ZrQ4bKy39GnylE8Zq31IRmm8bNhNbZx7bF2cU5aiCCnSa93J2imF88MBjn7J9eUQneNxUQVJdl/rPQ==", - "hasInstallScript": true, - "dependencies": { - "@prisma/engines-version": "4.16.1-1.4bc8b6e1b66cb932731fb1bdbbc550d1e010de81" - }, - "engines": { - "node": ">=14.17" - }, - "peerDependencies": { - "prisma": "*" - }, - "peerDependenciesMeta": { - "prisma": { - "optional": true - } - } - }, - "node_modules/@prisma/engines": { - "version": "4.16.2", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.16.2.tgz", - "integrity": "sha512-vx1nxVvN4QeT/cepQce68deh/Turxy5Mr+4L4zClFuK1GlxN3+ivxfuv+ej/gvidWn1cE1uAhW7ALLNlYbRUAw==", - "hasInstallScript": true - }, - "node_modules/@prisma/engines-version": { - "version": "4.16.1-1.4bc8b6e1b66cb932731fb1bdbbc550d1e010de81", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.16.1-1.4bc8b6e1b66cb932731fb1bdbbc550d1e010de81.tgz", - "integrity": "sha512-q617EUWfRIDTriWADZ4YiWRZXCa/WuhNgLTVd+HqWLffjMSPzyM5uOWoauX91wvQClSKZU4pzI4JJLQ9Kl62Qg==" - }, - "node_modules/@zenstackhq/runtime": { - "resolved": "../../../packages/runtime/dist", - "link": true - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "license": "MIT" - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "license": "MIT", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/prisma": { - "version": "4.16.2", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.16.2.tgz", - "integrity": "sha512-SYCsBvDf0/7XSJyf2cHTLjLeTLVXYfqp7pG5eEVafFLeT0u/hLFz/9W196nDRGUOo1JfPatAEb+uEnTQImQC1g==", - "hasInstallScript": true, - "dependencies": { - "@prisma/engines": "4.16.2" - }, - "bin": { - "prisma": "build/index.js", - "prisma2": "build/index.js" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/react": { - "version": "18.2.0", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/swr": { - "version": "1.3.0", - "license": "MIT", - "peerDependencies": { - "react": "^16.11.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/typescript": { - "version": "4.9.3", - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/zenstack": { - "resolved": "../../../packages/schema/dist", - "link": true - }, - "node_modules/zod": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.1.tgz", - "integrity": "sha512-+dTu2m6gmCbO9Ahm4ZBDapx2O6ZY9QSPXst2WXjcznPMwf2YNpn3RevLx4KkZp1OPW/ouFcoBtBzFz/LeY69oA==", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - } - }, - "dependencies": { - "@prisma/client": { - "version": "4.16.2", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.16.2.tgz", - "integrity": "sha512-qCoEyxv1ZrQ4bKy39GnylE8Zq31IRmm8bNhNbZx7bF2cU5aiCCnSa93J2imF88MBjn7J9eUQneNxUQVJdl/rPQ==", - "requires": { - "@prisma/engines-version": "4.16.1-1.4bc8b6e1b66cb932731fb1bdbbc550d1e010de81" - } - }, - "@prisma/engines": { - "version": "4.16.2", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.16.2.tgz", - "integrity": "sha512-vx1nxVvN4QeT/cepQce68deh/Turxy5Mr+4L4zClFuK1GlxN3+ivxfuv+ej/gvidWn1cE1uAhW7ALLNlYbRUAw==" - }, - "@prisma/engines-version": { - "version": "4.16.1-1.4bc8b6e1b66cb932731fb1bdbbc550d1e010de81", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.16.1-1.4bc8b6e1b66cb932731fb1bdbbc550d1e010de81.tgz", - "integrity": "sha512-q617EUWfRIDTriWADZ4YiWRZXCa/WuhNgLTVd+HqWLffjMSPzyM5uOWoauX91wvQClSKZU4pzI4JJLQ9Kl62Qg==" - }, - "@zenstackhq/runtime": { - "version": "file:../../../packages/runtime/dist", - "requires": { - "@paralleldrive/cuid2": "^2.2.0", - "@prisma/client": "^4.0.0", - "@types/bcryptjs": "^2.4.2", - "@types/jest": "^29.5.0", - "@types/lower-case-first": "^1.0.1", - "@types/node": "^14.18.29", - "@types/pluralize": "^0.0.29", - "bcryptjs": "^2.4.3", - "change-case": "^4.1.2", - "colors": "1.4.0", - "copyfiles": "^2.4.1", - "decimal.js": "^10.4.2", - "deepcopy": "^2.1.0", - "lower-case-first": "^2.0.2", - "pluralize": "^8.0.0", - "rimraf": "^3.0.2", - "superjson": "^1.11.0", - "tslib": "^2.4.1", - "typescript": "^4.9.3", - "upper-case-first": "^2.0.2", - "zod": "3.21.1", - "zod-validation-error": "^0.2.1" - } - }, - "js-tokens": { - "version": "4.0.0" - }, - "loose-envify": { - "version": "1.4.0", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "prisma": { - "version": "4.16.2", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.16.2.tgz", - "integrity": "sha512-SYCsBvDf0/7XSJyf2cHTLjLeTLVXYfqp7pG5eEVafFLeT0u/hLFz/9W196nDRGUOo1JfPatAEb+uEnTQImQC1g==", - "requires": { - "@prisma/engines": "4.16.2" - } - }, - "react": { - "version": "18.2.0", - "requires": { - "loose-envify": "^1.1.0" - } - }, - "swr": { - "version": "1.3.0", - "requires": {} - }, - "typescript": { - "version": "4.9.3" - }, - "zenstack": { - "version": "file:../../../packages/schema/dist", - "requires": { - "@paralleldrive/cuid2": "^2.2.0", - "@prisma/generator-helper": "4.10.0", - "@prisma/internals": "4.10.0", - "@types/async-exit-hook": "^2.0.0", - "@types/jest": "^29.5.0", - "@types/lower-case-first": "^1.0.1", - "@types/node": "^14.18.32", - "@types/pluralize": "^0.0.29", - "@types/semver": "^7.3.13", - "@types/strip-color": "^0.1.0", - "@types/tmp": "^0.2.3", - "@types/upper-case-first": "^1.1.2", - "@types/uuid": "^8.3.4", - "@types/vscode": "^1.56.0", - "@typescript-eslint/eslint-plugin": "^5.42.0", - "@typescript-eslint/parser": "^5.42.0", - "@vscode/vsce": "^2.19.0", - "@zenstackhq/language": "workspace:*", - "@zenstackhq/runtime": "workspace:*", - "@zenstackhq/sdk": "workspace:*", - "async-exit-hook": "^2.0.1", - "change-case": "^4.1.2", - "colors": "1.4.0", - "commander": "^8.3.0", - "concurrently": "^7.4.0", - "copyfiles": "^2.4.1", - "dotenv": "^16.0.3", - "esbuild": "^0.15.12", - "eslint": "^8.27.0", - "eslint-plugin-jest": "^27.1.7", - "get-latest-version": "^5.0.1", - "jest": "^29.5.0", - "langium": "1.2.0", - "lower-case-first": "^2.0.2", - "mixpanel": "^0.17.0", - "node-machine-id": "^1.1.12", - "ora": "^5.4.1", - "pluralize": "^8.0.0", - "prisma": "^4.0.0", - "promisify": "^0.0.3", - "renamer": "^4.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.8", - "sleep-promise": "^9.1.0", - "strip-color": "^0.1.0", - "tmp": "^0.2.1", - "ts-jest": "^29.0.3", - "ts-morph": "^16.0.0", - "ts-node": "^10.9.1", - "ts-pattern": "^4.3.0", - "tsc-alias": "^1.7.0", - "typescript": "^4.8.4", - "upper-case-first": "^2.0.2", - "uuid": "^9.0.0", - "vitest": "^0.29.7", - "vscode-jsonrpc": "^8.0.2", - "vscode-languageclient": "^8.0.2", - "vscode-languageserver": "^8.0.2", - "vscode-languageserver-textdocument": "^1.0.7", - "vscode-uri": "^3.0.6", - "zod": "3.21.1", - "zod-validation-error": "^0.2.1" - } - }, - "zod": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.1.tgz", - "integrity": "sha512-+dTu2m6gmCbO9Ahm4ZBDapx2O6ZY9QSPXst2WXjcznPMwf2YNpn3RevLx4KkZp1OPW/ouFcoBtBzFz/LeY69oA==" - } - } -} diff --git a/tests/integration/test-run/package.json b/tests/integration/test-run/package.json index 44210853d..b4f3b0810 100644 --- a/tests/integration/test-run/package.json +++ b/tests/integration/test-run/package.json @@ -10,9 +10,9 @@ "author": "", "license": "ISC", "dependencies": { - "@prisma/client": "^4.16.2", + "@prisma/client": "^4.0.0", "@zenstackhq/runtime": "file:../../../packages/runtime/dist", - "prisma": "^4.16.2", + "prisma": "^4.0.0", "react": "^18.2.0", "swr": "^1.3.0", "typescript": "^4.9.3", diff --git a/tests/integration/tests/cli/plugins.test.ts b/tests/integration/tests/cli/plugins.test.ts index 51c7403ad..cff7d30d8 100644 --- a/tests/integration/tests/cli/plugins.test.ts +++ b/tests/integration/tests/cli/plugins.test.ts @@ -73,7 +73,7 @@ describe('CLI Plugins Tests', () => { 'swr', '@tanstack/react-query', '@trpc/server', - '@prisma/client', + '@prisma/client@^4.0.0', `${path.join(__dirname, '../../../../.build/zenstackhq-language-' + ver + '.tgz')}`, `${path.join(__dirname, '../../../../.build/zenstackhq-sdk-' + ver + '.tgz')}`, `${path.join(__dirname, '../../../../.build/zenstackhq-runtime-' + ver + '.tgz')}`, @@ -83,7 +83,7 @@ describe('CLI Plugins Tests', () => { const devDepPkgs = [ 'typescript', '@types/react', - 'prisma', + 'prisma@^4.0.0', `${path.join(__dirname, '../../../../.build/zenstack-' + ver + '.tgz')}`, `${path.join(__dirname, '../../../../.build/zenstackhq-tanstack-query-' + ver + '.tgz')}`, `${path.join(__dirname, '../../../../.build/zenstackhq-swr-' + ver + '.tgz')}`, diff --git a/tests/integration/tests/e2e/todo-presets.test.ts b/tests/integration/tests/e2e/todo-presets.test.ts index 26b9afb73..28f8bd4e6 100644 --- a/tests/integration/tests/e2e/todo-presets.test.ts +++ b/tests/integration/tests/e2e/todo-presets.test.ts @@ -10,7 +10,7 @@ describe('Todo Presets Tests', () => { beforeAll(async () => { const { withPresets, prisma: _prisma } = await loadSchemaFromFile( path.join(__dirname, '../schema/todo.zmodel'), - false + { addPrelude: false } ); getDb = withPresets; prisma = _prisma; diff --git a/tests/integration/tests/with-omit/with-omit.test.ts b/tests/integration/tests/enhancements/with-omit/with-omit.test.ts similarity index 100% rename from tests/integration/tests/with-omit/with-omit.test.ts rename to tests/integration/tests/enhancements/with-omit/with-omit.test.ts diff --git a/tests/integration/tests/with-password/with-password.test.ts b/tests/integration/tests/enhancements/with-password/with-password.test.ts similarity index 100% rename from tests/integration/tests/with-password/with-password.test.ts rename to tests/integration/tests/enhancements/with-password/with-password.test.ts diff --git a/tests/integration/tests/with-policy/auth.test.ts b/tests/integration/tests/enhancements/with-policy/auth.test.ts similarity index 100% rename from tests/integration/tests/with-policy/auth.test.ts rename to tests/integration/tests/enhancements/with-policy/auth.test.ts diff --git a/tests/integration/tests/with-policy/cal-com-sample.test.ts b/tests/integration/tests/enhancements/with-policy/cal-com-sample.test.ts similarity index 54% rename from tests/integration/tests/with-policy/cal-com-sample.test.ts rename to tests/integration/tests/enhancements/with-policy/cal-com-sample.test.ts index 2aa94e4c9..4ebc7f448 100644 --- a/tests/integration/tests/with-policy/cal-com-sample.test.ts +++ b/tests/integration/tests/enhancements/with-policy/cal-com-sample.test.ts @@ -3,6 +3,9 @@ import path from 'path'; describe('Cal.com Sample Integration Tests', () => { it('model loading', async () => { - await loadSchemaFromFile(path.join(__dirname, '../schema/cal-com.zmodel'), false, false); + await loadSchemaFromFile(path.join(__dirname, '../../schema/cal-com.zmodel'), { + addPrelude: false, + pushDb: false, + }); }); }); diff --git a/tests/integration/tests/with-policy/connect-disconnect.test.ts b/tests/integration/tests/enhancements/with-policy/connect-disconnect.test.ts similarity index 100% rename from tests/integration/tests/with-policy/connect-disconnect.test.ts rename to tests/integration/tests/enhancements/with-policy/connect-disconnect.test.ts diff --git a/tests/integration/tests/with-policy/deep-nested.test.ts b/tests/integration/tests/enhancements/with-policy/deep-nested.test.ts similarity index 93% rename from tests/integration/tests/with-policy/deep-nested.test.ts rename to tests/integration/tests/enhancements/with-policy/deep-nested.test.ts index 86ac0b5a2..4b8013ecb 100644 --- a/tests/integration/tests/with-policy/deep-nested.test.ts +++ b/tests/integration/tests/enhancements/with-policy/deep-nested.test.ts @@ -204,22 +204,21 @@ describe('With Policy:deep nested', () => { }); expect(r1.m2.m4).toHaveLength(1); - // create read-back rejection: M3 @@deny('read', value == 200) - await expect( - db.m1.create({ - include: { m2: { include: { m3: true } } }, - data: { - m2: { - create: { - value: 1, - m3: { - create: { value: 200 }, - }, + // create read-back filtering: M3 @@deny('read', value == 200) + const r2 = await db.m1.create({ + include: { m2: { include: { m3: true } } }, + data: { + m2: { + create: { + value: 1, + m3: { + create: { value: 200 }, }, }, }, - }) - ).toBeRejectedByPolicy(); + }, + }); + expect(r2.m2.m3).toBeNull(); }); it('update', async () => { @@ -364,21 +363,20 @@ describe('With Policy:deep nested', () => { expect(r1.m2.m4).not.toContain(expect.objectContaining({ id: 'm4-1' })); // update read-back rejection: M3 @@deny('read', value == 200) - await expect( - db.m1.update({ - where: { myId: '1' }, - include: { m2: { include: { m3: true } } }, - data: { - m2: { - update: { - m3: { - update: { value: 200 }, - }, + const r2 = await db.m1.update({ + where: { myId: '1' }, + include: { m2: { include: { m3: true } } }, + data: { + m2: { + update: { + m3: { + update: { value: 200 }, }, }, }, - }) - ).toBeRejectedByPolicy(); + }, + }); + expect(r2.m2.m3).toBeNull(); }); it('delete', async () => { diff --git a/tests/integration/tests/with-policy/empty-policy.test.ts b/tests/integration/tests/enhancements/with-policy/empty-policy.test.ts similarity index 100% rename from tests/integration/tests/with-policy/empty-policy.test.ts rename to tests/integration/tests/enhancements/with-policy/empty-policy.test.ts diff --git a/tests/integration/tests/with-policy/field-validation.test.ts b/tests/integration/tests/enhancements/with-policy/field-validation.test.ts similarity index 100% rename from tests/integration/tests/with-policy/field-validation.test.ts rename to tests/integration/tests/enhancements/with-policy/field-validation.test.ts diff --git a/tests/integration/tests/with-policy/multi-field-unique.test.ts b/tests/integration/tests/enhancements/with-policy/multi-field-unique.test.ts similarity index 100% rename from tests/integration/tests/with-policy/multi-field-unique.test.ts rename to tests/integration/tests/enhancements/with-policy/multi-field-unique.test.ts diff --git a/tests/integration/tests/with-policy/multi-file.test.ts b/tests/integration/tests/enhancements/with-policy/multi-file.test.ts similarity index 100% rename from tests/integration/tests/with-policy/multi-file.test.ts rename to tests/integration/tests/enhancements/with-policy/multi-file.test.ts diff --git a/tests/integration/tests/with-policy/multi-id-fields.test.ts b/tests/integration/tests/enhancements/with-policy/multi-id-fields.test.ts similarity index 95% rename from tests/integration/tests/with-policy/multi-id-fields.test.ts rename to tests/integration/tests/enhancements/with-policy/multi-id-fields.test.ts index 5d9a37eaf..7dd62364a 100644 --- a/tests/integration/tests/with-policy/multi-id-fields.test.ts +++ b/tests/integration/tests/enhancements/with-policy/multi-id-fields.test.ts @@ -52,14 +52,14 @@ describe('With Policy: multiple id fields', () => { db.a.create({ data: { x: '2', y: 1, value: 1, b: { create: { b1: '1', b2: '2', value: 1 } } } }) ).toBeRejectedByPolicy(); - await expect( - db.a.create({ - include: { b: true }, - data: { x: '2', y: 1, value: 1, b: { create: { b1: '1', b2: '2', value: 2 } } }, - }) - ).toBeRejectedByPolicy(); - const r = await prisma.b.findUnique({ where: { b1_b2: { b1: '1', b2: '2' } } }); - expect(r.value).toBe(2); + const r = await db.a.create({ + include: { b: true }, + data: { x: '2', y: 1, value: 1, b: { create: { b1: '1', b2: '2', value: 2 } } }, + }); + expect(r.b).toBeNull(); + + const r1 = await prisma.b.findUnique({ where: { b1_b2: { b1: '1', b2: '2' } } }); + expect(r1.value).toBe(2); await expect( db.a.create({ diff --git a/tests/integration/tests/with-policy/nested-to-many.test.ts b/tests/integration/tests/enhancements/with-policy/nested-to-many.test.ts similarity index 86% rename from tests/integration/tests/with-policy/nested-to-many.test.ts rename to tests/integration/tests/enhancements/with-policy/nested-to-many.test.ts index c213065ed..75a8d0278 100644 --- a/tests/integration/tests/with-policy/nested-to-many.test.ts +++ b/tests/integration/tests/enhancements/with-policy/nested-to-many.test.ts @@ -12,6 +12,55 @@ describe('With Policy:nested to-many', () => { process.chdir(origDir); }); + it('read filtering', async () => { + const { withPolicy } = await loadSchema( + ` + model M1 { + id String @id @default(uuid()) + m2 M2[] + + @@allow('all', true) + } + + model M2 { + id String @id @default(uuid()) + value Int + m1 M1 @relation(fields: [m1Id], references:[id]) + m1Id String + + @@allow('create', true) + @@allow('read', value > 0) + } + ` + ); + + const db = withPolicy(); + + let read = await db.m1.create({ + include: { m2: true }, + data: { + id: '1', + m2: { + create: [{ value: 0 }], + }, + }, + }); + expect(read.m2).toHaveLength(0); + read = await db.m1.findFirst({ where: { id: '1' }, include: { m2: true } }); + expect(read.m2).toHaveLength(0); + + await db.m1.create({ + data: { + id: '2', + m2: { + create: [{ value: 0 }, { value: 1 }, { value: 2 }], + }, + }, + }); + read = await db.m1.findFirst({ where: { id: '2' }, include: { m2: true } }); + expect(read.m2).toHaveLength(2); + }); + it('create simple', async () => { const { withPolicy } = await loadSchema( ` @@ -397,15 +446,14 @@ describe('With Policy:nested to-many', () => { expect(r.m2).toHaveLength(1); // read-back for to-one relation rejected - await expect( - db.m1.create({ - include: { m3: true }, - data: { - value: 2, - m3: { create: { value: 0 } }, - }, - }) - ).toBeRejectedByPolicy(); + const r1 = await db.m1.create({ + include: { m3: true }, + data: { + value: 2, + m3: { create: { value: 0 } }, + }, + }); + expect(r1.m3).toBeNull(); }); it('update with nested read', async () => { @@ -457,21 +505,20 @@ describe('With Policy:nested to-many', () => { }, }); - await expect( - db.m1.update({ - where: { id: '1' }, - include: { m3: true }, - data: { - m3: { - update: { - value: 1, - }, + const r = await db.m1.update({ + where: { id: '1' }, + include: { m3: true }, + data: { + m3: { + update: { + value: 1, }, }, - }) - ).toBeRejectedByPolicy(); + }, + }); + expect(r.m3).toBeNull(); - const r = await db.m1.update({ + const r1 = await db.m1.update({ where: { id: '1' }, include: { m3: true, m2: true }, data: { @@ -483,11 +530,11 @@ describe('With Policy:nested to-many', () => { }, }); // m3 is ok now - expect(r.m3.value).toBe(2); + expect(r1.m3.value).toBe(2); // m2 got filtered - expect(r.m2).toHaveLength(0); + expect(r1.m2).toHaveLength(0); - const r1 = await db.m1.update({ + const r2 = await db.m1.update({ where: { id: '1' }, select: { m2: true }, data: { @@ -500,6 +547,6 @@ describe('With Policy:nested to-many', () => { }, }); // one of m2 matches policy now - expect(r1.m2).toHaveLength(1); + expect(r2.m2).toHaveLength(1); }); }); diff --git a/tests/integration/tests/with-policy/nested-to-one.test.ts b/tests/integration/tests/enhancements/with-policy/nested-to-one.test.ts similarity index 71% rename from tests/integration/tests/with-policy/nested-to-one.test.ts rename to tests/integration/tests/enhancements/with-policy/nested-to-one.test.ts index b1f3b7a50..45a0e765d 100644 --- a/tests/integration/tests/with-policy/nested-to-one.test.ts +++ b/tests/integration/tests/enhancements/with-policy/nested-to-one.test.ts @@ -12,6 +12,93 @@ describe('With Policy:nested to-one', () => { process.chdir(origDir); }); + it('read fitering for optional relation', async () => { + const { prisma, withPolicy } = await loadSchema( + ` + model M1 { + id String @id @default(uuid()) + m2 M2? + + @@allow('all', true) + } + + model M2 { + id String @id @default(uuid()) + m1 M1 @relation(fields: [m1Id], references:[id]) + m1Id String @unique + value Int + + @@allow('create', true) + @@allow('read', value > 0) + } + ` + ); + + const db = withPolicy(); + + let read = await db.m1.create({ + include: { m2: true }, + data: { + id: '1', + m2: { + create: { id: '1', value: 0 }, + }, + }, + }); + expect(read.m2).toBeNull(); + + await expect(db.m1.findUnique({ where: { id: '1' }, include: { m2: true } })).resolves.toEqual( + expect.objectContaining({ m2: null }) + ); + await expect(db.m1.findMany({ include: { m2: true } })).resolves.toEqual( + expect.arrayContaining([expect.objectContaining({ m2: null })]) + ); + + await prisma.m2.update({ where: { id: '1' }, data: { value: 1 } }); + read = await db.m1.findUnique({ where: { id: '1' }, include: { m2: true } }); + expect(read.m2).toEqual(expect.objectContaining({ id: '1', value: 1 })); + }); + + it('read rejection for non-optional relation', async () => { + const { prisma, withPolicy } = await loadSchema( + ` + model M1 { + id String @id @default(uuid()) + m2 M2? + value Int + + @@allow('create', true) + @@allow('read', value > 0) + } + + model M2 { + id String @id @default(uuid()) + m1 M1 @relation(fields: [m1Id], references:[id]) + m1Id String @unique + + @@allow('all', true) + } + ` + ); + + await prisma.m1.create({ + data: { + id: '1', + value: 0, + m2: { + create: { id: '1' }, + }, + }, + }); + + const db = withPolicy(); + await expect(db.m2.findUnique({ where: { id: '1' }, include: { m1: true } })).toBeRejectedByPolicy(); + await expect(db.m2.findMany({ include: { m1: true } })).toBeRejectedByPolicy(); + + await prisma.m1.update({ where: { id: '1' }, data: { value: 1 } }); + await expect(db.m2.findMany({ include: { m1: true } })).toResolveTruthy(); + }); + it('create and update tests', async () => { const { withPolicy } = await loadSchema( ` diff --git a/tests/integration/tests/with-policy/petstore-sample.test.ts b/tests/integration/tests/enhancements/with-policy/petstore-sample.test.ts similarity index 94% rename from tests/integration/tests/with-policy/petstore-sample.test.ts rename to tests/integration/tests/enhancements/with-policy/petstore-sample.test.ts index c04615ffa..88b0b1f7d 100644 --- a/tests/integration/tests/with-policy/petstore-sample.test.ts +++ b/tests/integration/tests/enhancements/with-policy/petstore-sample.test.ts @@ -8,8 +8,8 @@ describe('Pet Store Policy Tests', () => { beforeAll(async () => { const { withPolicy, prisma: _prisma } = await loadSchemaFromFile( - path.join(__dirname, '../schema/petstore.zmodel'), - false + path.join(__dirname, '../../schema/petstore.zmodel'), + { addPrelude: false } ); getDb = withPolicy; prisma = _prisma; diff --git a/tests/integration/tests/with-policy/post-update.test.ts b/tests/integration/tests/enhancements/with-policy/post-update.test.ts similarity index 100% rename from tests/integration/tests/with-policy/post-update.test.ts rename to tests/integration/tests/enhancements/with-policy/post-update.test.ts diff --git a/tests/integration/tests/with-policy/relation-many-to-many-filter.test.ts b/tests/integration/tests/enhancements/with-policy/relation-many-to-many-filter.test.ts similarity index 100% rename from tests/integration/tests/with-policy/relation-many-to-many-filter.test.ts rename to tests/integration/tests/enhancements/with-policy/relation-many-to-many-filter.test.ts diff --git a/tests/integration/tests/with-policy/relation-one-to-many-filter.test.ts b/tests/integration/tests/enhancements/with-policy/relation-one-to-many-filter.test.ts similarity index 100% rename from tests/integration/tests/with-policy/relation-one-to-many-filter.test.ts rename to tests/integration/tests/enhancements/with-policy/relation-one-to-many-filter.test.ts diff --git a/tests/integration/tests/with-policy/relation-one-to-one-filter.test.ts b/tests/integration/tests/enhancements/with-policy/relation-one-to-one-filter.test.ts similarity index 100% rename from tests/integration/tests/with-policy/relation-one-to-one-filter.test.ts rename to tests/integration/tests/enhancements/with-policy/relation-one-to-one-filter.test.ts diff --git a/tests/integration/tests/with-policy/self-relation.test.ts b/tests/integration/tests/enhancements/with-policy/self-relation.test.ts similarity index 100% rename from tests/integration/tests/with-policy/self-relation.test.ts rename to tests/integration/tests/enhancements/with-policy/self-relation.test.ts diff --git a/tests/integration/tests/with-policy/todo-sample.test.ts b/tests/integration/tests/enhancements/with-policy/todo-sample.test.ts similarity index 99% rename from tests/integration/tests/with-policy/todo-sample.test.ts rename to tests/integration/tests/enhancements/with-policy/todo-sample.test.ts index 4b61e20a8..0f3305e0e 100644 --- a/tests/integration/tests/with-policy/todo-sample.test.ts +++ b/tests/integration/tests/enhancements/with-policy/todo-sample.test.ts @@ -8,8 +8,8 @@ describe('Todo Policy Tests', () => { beforeAll(async () => { const { withPolicy, prisma: _prisma } = await loadSchemaFromFile( - path.join(__dirname, '../schema/todo.zmodel'), - false + path.join(__dirname, '../../schema/todo.zmodel'), + { addPrelude: false } ); getDb = withPolicy; prisma = _prisma; diff --git a/tests/integration/tests/with-policy/toplevel-operations.test.ts b/tests/integration/tests/enhancements/with-policy/toplevel-operations.test.ts similarity index 100% rename from tests/integration/tests/with-policy/toplevel-operations.test.ts rename to tests/integration/tests/enhancements/with-policy/toplevel-operations.test.ts diff --git a/tests/integration/tests/enhancements/with-policy/unique-as-id.test.ts b/tests/integration/tests/enhancements/with-policy/unique-as-id.test.ts new file mode 100644 index 000000000..e4d399204 --- /dev/null +++ b/tests/integration/tests/enhancements/with-policy/unique-as-id.test.ts @@ -0,0 +1,174 @@ +import { loadSchema } from '@zenstackhq/testtools'; +import path from 'path'; + +describe('With Policy: unique as id', () => { + let origDir: string; + + beforeAll(async () => { + origDir = path.resolve('.'); + }); + + afterEach(() => { + process.chdir(origDir); + }); + + it('unique fields', async () => { + const { prisma, withPolicy } = await loadSchema( + ` + model A { + x String @unique + y Int @unique + value Int + b B? + + @@allow('read', true) + @@allow('create', value > 0) + } + + model B { + b1 String @unique + b2 String @unique + value Int + a A @relation(fields: [ax], references: [x]) + ax String @unique + + @@allow('read', value > 2) + @@allow('create', value > 1) + } + ` + ); + + const db = withPolicy(); + + await expect(db.a.create({ data: { x: '1', y: 1, value: 0 } })).toBeRejectedByPolicy(); + await expect(db.a.create({ data: { x: '1', y: 2, value: 1 } })).toResolveTruthy(); + + await expect( + db.a.create({ data: { x: '2', y: 3, value: 1, b: { create: { b1: '1', b2: '2', value: 1 } } } }) + ).toBeRejectedByPolicy(); + + const r = await db.a.create({ + include: { b: true }, + data: { x: '2', y: 3, value: 1, b: { create: { b1: '1', b2: '2', value: 2 } } }, + }); + expect(r.b).toBeNull(); + const r1 = await prisma.b.findUnique({ where: { b1: '1' } }); + expect(r1.value).toBe(2); + + await expect( + db.a.create({ + include: { b: true }, + data: { x: '3', y: 4, value: 1, b: { create: { b1: '2', b2: '3', value: 3 } } }, + }) + ).toResolveTruthy(); + }); + + it('unique fields mixed with id', async () => { + const { prisma, withPolicy } = await loadSchema( + ` + model A { + id Int @id @default(autoincrement()) + x String @unique + y Int @unique + value Int + b B? + + @@allow('read', true) + @@allow('create', value > 0) + } + + model B { + id Int @id @default(autoincrement()) + b1 String @unique + b2 String @unique + value Int + a A @relation(fields: [ax], references: [x]) + ax String @unique + + @@allow('read', value > 2) + @@allow('create', value > 1) + } + ` + ); + + const db = withPolicy(); + + await expect(db.a.create({ data: { x: '1', y: 1, value: 0 } })).toBeRejectedByPolicy(); + await expect(db.a.create({ data: { x: '1', y: 2, value: 1 } })).toResolveTruthy(); + + await expect( + db.a.create({ data: { x: '2', y: 3, value: 1, b: { create: { b1: '1', b2: '2', value: 1 } } } }) + ).toBeRejectedByPolicy(); + + const r = await db.a.create({ + include: { b: true }, + data: { x: '2', y: 3, value: 1, b: { create: { b1: '1', b2: '2', value: 2 } } }, + }); + expect(r.b).toBeNull(); + const r1 = await prisma.b.findUnique({ where: { b1: '1' } }); + expect(r1.value).toBe(2); + + await expect( + db.a.create({ + include: { b: true }, + data: { x: '3', y: 4, value: 1, b: { create: { b1: '2', b2: '3', value: 3 } } }, + }) + ).toResolveTruthy(); + }); + + it('model-level unique fields', async () => { + const { prisma, withPolicy } = await loadSchema( + ` + model A { + x String + y Int + value Int + b B? + @@unique([x, y]) + + @@allow('read', true) + @@allow('create', value > 0) + } + + model B { + b1 String + b2 String + value Int + a A @relation(fields: [ax, ay], references: [x, y]) + ax String + ay Int + + @@allow('read', value > 2) + @@allow('create', value > 1) + + @@unique([ax, ay]) + @@unique([b1, b2]) + } + ` + ); + + const db = withPolicy(); + + await expect(db.a.create({ data: { x: '1', y: 1, value: 0 } })).toBeRejectedByPolicy(); + await expect(db.a.create({ data: { x: '1', y: 2, value: 1 } })).toResolveTruthy(); + + await expect( + db.a.create({ data: { x: '2', y: 1, value: 1, b: { create: { b1: '1', b2: '2', value: 1 } } } }) + ).toBeRejectedByPolicy(); + + const r = await db.a.create({ + include: { b: true }, + data: { x: '2', y: 1, value: 1, b: { create: { b1: '1', b2: '2', value: 2 } } }, + }); + expect(r.b).toBeNull(); + const r1 = await prisma.b.findUnique({ where: { b1_b2: { b1: '1', b2: '2' } } }); + expect(r1.value).toBe(2); + + await expect( + db.a.create({ + include: { b: true }, + data: { x: '3', y: 1, value: 1, b: { create: { b1: '2', b2: '2', value: 3 } } }, + }) + ).toResolveTruthy(); + }); +}); diff --git a/tests/integration/tests/enhancements/with-policy/view.test.ts b/tests/integration/tests/enhancements/with-policy/view.test.ts new file mode 100644 index 000000000..1af13a65c --- /dev/null +++ b/tests/integration/tests/enhancements/with-policy/view.test.ts @@ -0,0 +1,105 @@ +import { loadSchema } from '@zenstackhq/testtools'; +import path from 'path'; + +describe('View Policy Test', () => { + let origDir: string; + + beforeAll(async () => { + origDir = path.resolve('.'); + }); + + afterEach(() => { + process.chdir(origDir); + }); + + it('view policy', async () => { + const { prisma, withPolicy } = await loadSchema( + ` + datasource db { + provider = "sqlite" + url = "file:./dev.db" + } + + generator client { + provider = "prisma-client-js" + previewFeatures = ["views"] + } + + model User { + id Int @id @default(autoincrement()) + email String @unique + name String? + posts Post[] + userInfo UserInfo? + } + + model Post { + id Int @id @default(autoincrement()) + title String + content String? + published Boolean @default(false) + author User? @relation(fields: [authorId], references: [id]) + authorId Int? + } + + view UserInfo { + id Int @unique + name String + email String + postCount Int + user User @relation(fields: [id], references: [id]) + + @@allow('read', postCount > 1) + } + `, + { addPrelude: false } + ); + + await prisma.$executeRaw`CREATE VIEW UserInfo as select user.id, user.name, user.email, user.id as userId, count(post.id) as postCount from user left join post on user.id = post.authorId group by user.id;`; + + await prisma.user.create({ + data: { + email: 'alice@prisma.io', + name: 'Alice', + posts: { + create: { + title: 'Check out Prisma with Next.js', + content: 'https://www.prisma.io/nextjs', + published: true, + }, + }, + }, + }); + await prisma.user.create({ + data: { + email: 'bob@prisma.io', + name: 'Bob', + posts: { + create: [ + { + title: 'Follow Prisma on Twitter', + content: 'https://twitter.com/prisma', + published: true, + }, + { + title: 'Follow Nexus on Twitter', + content: 'https://twitter.com/nexusgql', + published: false, + }, + ], + }, + }, + }); + + const db = withPolicy(); + + await expect(prisma.userInfo.findMany()).resolves.toHaveLength(2); + await expect(db.userInfo.findMany()).resolves.toHaveLength(1); + + const r1 = await prisma.userInfo.findFirst({ include: { user: true } }); + expect(r1.user).toBeTruthy(); + + // user not readable + await expect(db.userInfo.findFirst({ include: { user: true } })).toBeRejectedByPolicy(); + }); +}); diff --git a/tests/integration/tests/nextjs/generation.test.ts b/tests/integration/tests/frameworks/nextjs/generation.test.ts similarity index 100% rename from tests/integration/tests/nextjs/generation.test.ts rename to tests/integration/tests/frameworks/nextjs/generation.test.ts diff --git a/tests/integration/tests/nextjs/test-project/.gitignore b/tests/integration/tests/frameworks/nextjs/test-project/.gitignore similarity index 100% rename from tests/integration/tests/nextjs/test-project/.gitignore rename to tests/integration/tests/frameworks/nextjs/test-project/.gitignore diff --git a/tests/integration/tests/nextjs/test-project/.npmrc b/tests/integration/tests/frameworks/nextjs/test-project/.npmrc similarity index 100% rename from tests/integration/tests/nextjs/test-project/.npmrc rename to tests/integration/tests/frameworks/nextjs/test-project/.npmrc diff --git a/tests/integration/tests/nextjs/test-project/README.md b/tests/integration/tests/frameworks/nextjs/test-project/README.md similarity index 100% rename from tests/integration/tests/nextjs/test-project/README.md rename to tests/integration/tests/frameworks/nextjs/test-project/README.md diff --git a/tests/integration/tests/nextjs/test-project/next.config.js b/tests/integration/tests/frameworks/nextjs/test-project/next.config.js similarity index 100% rename from tests/integration/tests/nextjs/test-project/next.config.js rename to tests/integration/tests/frameworks/nextjs/test-project/next.config.js diff --git a/tests/integration/tests/nextjs/test-project/package.json b/tests/integration/tests/frameworks/nextjs/test-project/package.json similarity index 67% rename from tests/integration/tests/nextjs/test-project/package.json rename to tests/integration/tests/frameworks/nextjs/test-project/package.json index e9fc87b33..e8c006202 100644 --- a/tests/integration/tests/nextjs/test-project/package.json +++ b/tests/integration/tests/frameworks/nextjs/test-project/package.json @@ -9,20 +9,21 @@ "lint": "next lint" }, "dependencies": { - "@prisma/client": "^4.7.0", + "@prisma/client": "^4.0.0", "@types/node": "18.11.18", "@types/react": "18.0.27", "@types/react-dom": "18.0.10", - "@zenstackhq/runtime": "../../../../../../packages/runtime/dist", - "@zenstackhq/swr": "../../../../../../packages/plugins/swr/dist", + "@zenstackhq/runtime": "../../../../../../../packages/runtime/dist", + "@zenstackhq/swr": "../../../../../../../packages/plugins/swr/dist", "next": "13.1.4", "react": "18.2.0", "react-dom": "18.2.0", + "superjson": "^1.12.4", "swr": "^2.2.0", "typescript": "4.9.4", "zod": "3.21.1" }, "devDependencies": { - "prisma": "^4.7.0" + "prisma": "^4.0.0" } } diff --git a/tests/integration/tests/nextjs/test-project/pages/_app.tsx b/tests/integration/tests/frameworks/nextjs/test-project/pages/_app.tsx similarity index 100% rename from tests/integration/tests/nextjs/test-project/pages/_app.tsx rename to tests/integration/tests/frameworks/nextjs/test-project/pages/_app.tsx diff --git a/tests/integration/tests/nextjs/test-project/pages/api/model/[...path].ts b/tests/integration/tests/frameworks/nextjs/test-project/pages/api/model/[...path].ts similarity index 100% rename from tests/integration/tests/nextjs/test-project/pages/api/model/[...path].ts rename to tests/integration/tests/frameworks/nextjs/test-project/pages/api/model/[...path].ts diff --git a/tests/integration/tests/nextjs/test-project/pages/index.tsx b/tests/integration/tests/frameworks/nextjs/test-project/pages/index.tsx similarity index 100% rename from tests/integration/tests/nextjs/test-project/pages/index.tsx rename to tests/integration/tests/frameworks/nextjs/test-project/pages/index.tsx diff --git a/tests/integration/tests/nextjs/test-project/postgres.zmodel b/tests/integration/tests/frameworks/nextjs/test-project/postgres.zmodel similarity index 100% rename from tests/integration/tests/nextjs/test-project/postgres.zmodel rename to tests/integration/tests/frameworks/nextjs/test-project/postgres.zmodel diff --git a/tests/integration/tests/nextjs/test-project/server/db.ts b/tests/integration/tests/frameworks/nextjs/test-project/server/db.ts similarity index 100% rename from tests/integration/tests/nextjs/test-project/server/db.ts rename to tests/integration/tests/frameworks/nextjs/test-project/server/db.ts diff --git a/tests/integration/tests/nextjs/test-project/sqlite.zmodel b/tests/integration/tests/frameworks/nextjs/test-project/sqlite.zmodel similarity index 100% rename from tests/integration/tests/nextjs/test-project/sqlite.zmodel rename to tests/integration/tests/frameworks/nextjs/test-project/sqlite.zmodel diff --git a/tests/integration/tests/nextjs/test-project/tsconfig.json b/tests/integration/tests/frameworks/nextjs/test-project/tsconfig.json similarity index 100% rename from tests/integration/tests/nextjs/test-project/tsconfig.json rename to tests/integration/tests/frameworks/nextjs/test-project/tsconfig.json diff --git a/tests/integration/tests/trpc/generation.test.ts b/tests/integration/tests/frameworks/trpc/generation.test.ts similarity index 76% rename from tests/integration/tests/trpc/generation.test.ts rename to tests/integration/tests/frameworks/trpc/generation.test.ts index ae2098d28..3b0dd0610 100644 --- a/tests/integration/tests/trpc/generation.test.ts +++ b/tests/integration/tests/frameworks/trpc/generation.test.ts @@ -22,11 +22,9 @@ describe('tRPC Routers Generation Tests', () => { fs.mkdirSync(testDir, { recursive: true }); fse.copySync(path.join(__dirname, './test-project'), testDir); - const nodePath = path.resolve(path.join(__dirname, '../../node_modules')); - process.chdir(testDir); run('npm install'); - run('npx zenstack generate --schema ./todo.zmodel', { NODE_PATH: nodePath }); - run('npm run build', { NODE_PATH: nodePath }); + run('npx zenstack generate --no-dependency-check --schema ./todo.zmodel', { NODE_PATH: 'node_modules' }); + run('npm run build', { NODE_PATH: 'node_modules' }); }); }); diff --git a/tests/integration/tests/trpc/test-project/.gitignore b/tests/integration/tests/frameworks/trpc/test-project/.gitignore similarity index 100% rename from tests/integration/tests/trpc/test-project/.gitignore rename to tests/integration/tests/frameworks/trpc/test-project/.gitignore diff --git a/tests/integration/tests/trpc/test-project/.npmrc b/tests/integration/tests/frameworks/trpc/test-project/.npmrc similarity index 100% rename from tests/integration/tests/trpc/test-project/.npmrc rename to tests/integration/tests/frameworks/trpc/test-project/.npmrc diff --git a/tests/integration/tests/trpc/test-project/README.md b/tests/integration/tests/frameworks/trpc/test-project/README.md similarity index 100% rename from tests/integration/tests/trpc/test-project/README.md rename to tests/integration/tests/frameworks/trpc/test-project/README.md diff --git a/tests/integration/tests/trpc/test-project/lib/trpc.ts b/tests/integration/tests/frameworks/trpc/test-project/lib/trpc.ts similarity index 100% rename from tests/integration/tests/trpc/test-project/lib/trpc.ts rename to tests/integration/tests/frameworks/trpc/test-project/lib/trpc.ts diff --git a/tests/integration/tests/trpc/test-project/next.config.js b/tests/integration/tests/frameworks/trpc/test-project/next.config.js similarity index 100% rename from tests/integration/tests/trpc/test-project/next.config.js rename to tests/integration/tests/frameworks/trpc/test-project/next.config.js diff --git a/tests/integration/tests/trpc/test-project/package.json b/tests/integration/tests/frameworks/trpc/test-project/package.json similarity index 57% rename from tests/integration/tests/trpc/test-project/package.json rename to tests/integration/tests/frameworks/trpc/test-project/package.json index 097b1cb86..7bb67cbff 100644 --- a/tests/integration/tests/trpc/test-project/package.json +++ b/tests/integration/tests/frameworks/trpc/test-project/package.json @@ -9,12 +9,12 @@ "lint": "next lint" }, "dependencies": { - "@prisma/client": "^4.7.0", + "@prisma/client": "^4.0.0", "@tanstack/react-query": "^4.22.4", - "@trpc/client": "^10.9.0", - "@trpc/next": "^10.9.0", - "@trpc/react-query": "^10.9.0", - "@trpc/server": "^10.9.0", + "@trpc/client": "^10.34.0", + "@trpc/next": "^10.34.0", + "@trpc/react-query": "^10.34.0", + "@trpc/server": "^10.34.0", "@types/node": "18.11.18", "@types/react": "18.0.27", "@types/react-dom": "18.0.10", @@ -24,9 +24,11 @@ "superjson": "^1.12.2", "typescript": "4.9.4", "zod": "3.21.1", - "@zenstackhq/runtime": "../../../../../../packages/runtime/dist" + "@zenstackhq/runtime": "../../../../../../../packages/runtime/dist" }, "devDependencies": { - "prisma": "^4.7.0" + "prisma": "^4.0.0", + "zenstack": "../../../../../../../packages/schema/dist", + "@zenstackhq/trpc": "../../../../../../../packages/plugins/trpc/dist" } } diff --git a/tests/integration/tests/trpc/test-project/pages/_app.tsx b/tests/integration/tests/frameworks/trpc/test-project/pages/_app.tsx similarity index 100% rename from tests/integration/tests/trpc/test-project/pages/_app.tsx rename to tests/integration/tests/frameworks/trpc/test-project/pages/_app.tsx diff --git a/tests/integration/tests/trpc/test-project/pages/api/model/[...path].ts b/tests/integration/tests/frameworks/trpc/test-project/pages/api/model/[...path].ts similarity index 100% rename from tests/integration/tests/trpc/test-project/pages/api/model/[...path].ts rename to tests/integration/tests/frameworks/trpc/test-project/pages/api/model/[...path].ts diff --git a/tests/integration/tests/trpc/test-project/pages/index.tsx b/tests/integration/tests/frameworks/trpc/test-project/pages/index.tsx similarity index 100% rename from tests/integration/tests/trpc/test-project/pages/index.tsx rename to tests/integration/tests/frameworks/trpc/test-project/pages/index.tsx diff --git a/tests/integration/tests/trpc/test-project/server/context.ts b/tests/integration/tests/frameworks/trpc/test-project/server/context.ts similarity index 100% rename from tests/integration/tests/trpc/test-project/server/context.ts rename to tests/integration/tests/frameworks/trpc/test-project/server/context.ts diff --git a/tests/integration/tests/trpc/test-project/server/db.ts b/tests/integration/tests/frameworks/trpc/test-project/server/db.ts similarity index 100% rename from tests/integration/tests/trpc/test-project/server/db.ts rename to tests/integration/tests/frameworks/trpc/test-project/server/db.ts diff --git a/tests/integration/tests/trpc/test-project/server/routers/_app.ts b/tests/integration/tests/frameworks/trpc/test-project/server/routers/_app.ts similarity index 100% rename from tests/integration/tests/trpc/test-project/server/routers/_app.ts rename to tests/integration/tests/frameworks/trpc/test-project/server/routers/_app.ts diff --git a/tests/integration/tests/trpc/test-project/todo.zmodel b/tests/integration/tests/frameworks/trpc/test-project/todo.zmodel similarity index 100% rename from tests/integration/tests/trpc/test-project/todo.zmodel rename to tests/integration/tests/frameworks/trpc/test-project/todo.zmodel diff --git a/tests/integration/tests/trpc/test-project/tsconfig.json b/tests/integration/tests/frameworks/trpc/test-project/tsconfig.json similarity index 100% rename from tests/integration/tests/trpc/test-project/tsconfig.json rename to tests/integration/tests/frameworks/trpc/test-project/tsconfig.json diff --git a/tests/integration/tests/nextjs/test-project/package-lock.json b/tests/integration/tests/nextjs/test-project/package-lock.json deleted file mode 100644 index d7b1be834..000000000 --- a/tests/integration/tests/nextjs/test-project/package-lock.json +++ /dev/null @@ -1,868 +0,0 @@ -{ - "name": "test-project", - "version": "0.1.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "test-project", - "version": "0.1.0", - "dependencies": { - "@prisma/client": "^4.7.0", - "@types/node": "18.11.18", - "@types/react": "18.0.27", - "@types/react-dom": "18.0.10", - "@zenstackhq/runtime": "../../../../../../packages/runtime/dist", - "@zenstackhq/swr": "../../../../../../packages/plugins/swr/dist", - "next": "13.1.4", - "react": "18.2.0", - "react-dom": "18.2.0", - "swr": "^2.2.0", - "typescript": "4.9.4", - "zod": "3.21.1" - }, - "devDependencies": { - "prisma": "^4.7.0" - } - }, - "../../../../../../packages/plugins/swr/dist": {}, - "../../../../../../packages/runtime/dist": {}, - "../../../../../../packages/server/dist": { - "extraneous": true - }, - "node_modules/@next/env": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.1.4.tgz", - "integrity": "sha512-x7ydhMpi9/xX7yVK+Fw33OuwwQWVZUFRxenK3z89fmPzQZyUk35Ynb+b7JkrhfRhDIFFvvqpzVSXeseSlBAw7A==" - }, - "node_modules/@next/swc-android-arm-eabi": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-13.1.4.tgz", - "integrity": "sha512-5PAchzFst3In6Ml+9APvBj89H29lcPXcUqEYBVv09fWK/V4IuViKc2qOqM9pyPyw7KsqaZPmuqaG595E6jdZLA==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-android-arm64": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-13.1.4.tgz", - "integrity": "sha512-LCLjjRhsQ5fR9ExzR2fqxuyJe/D4Ct/YkdonVfJfqOfkEpFwUTQDOVo5GrQec4LZDk3zY+o6vZYjXbB0nD9VLA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-darwin-arm64": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.1.4.tgz", - "integrity": "sha512-LSc/tF1FQ1y1SwKiCdGg8IIl7+Csk6nuLcLIyQXs24UNYjXg5+7vUQXqE8y66v/Dq8qFDC9rM61QhpM9ZDftbg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-darwin-x64": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.1.4.tgz", - "integrity": "sha512-WoApDo8xfafrNc9+Mz5MwGFKUwbDHsGqLleTGZ8upegwVqDyHsYzqJQudf+loqhV58oGTOqP1eWaHn2J7dijXA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-freebsd-x64": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-13.1.4.tgz", - "integrity": "sha512-fqNyeT8G4guN8AHPIoBRhGY2GJg89FyWpuwX4o0Y3vUy/84IGZpNst3paCzaYkQSqQE/AuCpkB7hKxkN7ittXw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm-gnueabihf": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-13.1.4.tgz", - "integrity": "sha512-MEfm8OC1YR9/tYHUzlQsxcSmiuf8XdO7bqh5VtG4pilScjc5I5t+tQgIDgoDGePfh5W99W23hb3s6oCFrt99rw==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-gnu": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.1.4.tgz", - "integrity": "sha512-2wgth/KsuODzW/E7jsRoWdhKmE5oZzXcBPvf9RW+ZpBNvYQkEDlzfLA7n8DtxTU8I4oMas0mdEPdCWXrSNnVZw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-musl": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.1.4.tgz", - "integrity": "sha512-GdWhCRljsT7rNEElEsdu4RRppd+XaQOX1IJslsh/+HU6LsJGUE8tXpa68yJjCsHZHifkbdZNeCr5SYdsN6CbAA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-gnu": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.1.4.tgz", - "integrity": "sha512-Rsk/ojwYqMskN2eo5hUSVe7UuMV/aSjmrmJ0BCFGFPfBY9sPgmYj/oXlDDN0y5lJD9acPuiBjknLWgnOnx5JIA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-musl": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.1.4.tgz", - "integrity": "sha512-gKSVPozedA2gpA+vggYnAqpDuzWFed2oxFeXxHw0aW2ALdAZswAinn1ZwXEQ5fHnVguxjZhH0+2nBxpMdF8p5Q==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-arm64-msvc": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.1.4.tgz", - "integrity": "sha512-+kAXIIVb7Q4LCKmi7dn9qVlG1XUf3Chgj5Rwl0rAP4WBV2TnJIgsOEC24G1Mm3jjif+qXm7SJS9YZ9Yg3Y8sSQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-ia32-msvc": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.1.4.tgz", - "integrity": "sha512-EsfzAFBVaw1zg1FzlLMgRaTX/DKY+EnAvJ6mCIJMGeSOPIj4Oy6xF2yEQ3VaRkwFpAafHJH6JNB/CGrdKFCMXw==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-x64-msvc": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.1.4.tgz", - "integrity": "sha512-bygNjmnq+F9NqJXh7OfhJgqu6LGU29GNKQYVyZkxY/h5K0WWUvAE/VL+TdyMwbvQr9KByx5XLwORwetLxXCo4g==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@prisma/client": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.16.1.tgz", - "integrity": "sha512-CoDHu7Bt+NuDo40ijoeHP79EHtECsPBTy3yte5Yo3op8TqXt/kV0OT5OrsWewKvQGKFMHhYQ+ePed3zzjYdGAw==", - "hasInstallScript": true, - "dependencies": { - "@prisma/engines-version": "4.16.0-66.b20ead4d3ab9e78ac112966e242ded703f4a052c" - }, - "engines": { - "node": ">=14.17" - }, - "peerDependencies": { - "prisma": "*" - }, - "peerDependenciesMeta": { - "prisma": { - "optional": true - } - } - }, - "node_modules/@prisma/engines": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.16.1.tgz", - "integrity": "sha512-gpZG0kGGxfemgvK/LghHdBIz+crHkZjzszja94xp4oytpsXrgt/Ice82MvPsWMleVIniKuARrowtsIsim0PFJQ==", - "devOptional": true, - "hasInstallScript": true - }, - "node_modules/@prisma/engines-version": { - "version": "4.16.0-66.b20ead4d3ab9e78ac112966e242ded703f4a052c", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.16.0-66.b20ead4d3ab9e78ac112966e242ded703f4a052c.tgz", - "integrity": "sha512-tMWAF/qF00fbUH1HB4Yjmz6bjh7fzkb7Y3NRoUfMlHu6V+O45MGvqwYxqwBjn1BIUXkl3r04W351D4qdJjrgvA==" - }, - "node_modules/@swc/helpers": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz", - "integrity": "sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==", - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@types/node": { - "version": "18.11.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", - "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==" - }, - "node_modules/@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" - }, - "node_modules/@types/react": { - "version": "18.0.27", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.27.tgz", - "integrity": "sha512-3vtRKHgVxu3Jp9t718R9BuzoD4NcQ8YJ5XRzsSKxNDiDonD2MXIT1TmSkenxuCycZJoQT5d2vE8LwWJxBC1gmA==", - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-dom": { - "version": "18.0.10", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.10.tgz", - "integrity": "sha512-E42GW/JA4Qv15wQdqJq8DL4JhNpB3prJgjgapN3qJT9K2zO5IIAQh4VXvCEDupoqAwnz0cY4RlXeC/ajX5SFHg==", - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/scheduler": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" - }, - "node_modules/@zenstackhq/runtime": { - "resolved": "../../../../../../packages/runtime/dist", - "link": true - }, - "node_modules/@zenstackhq/swr": { - "resolved": "../../../../../../packages/plugins/swr/dist", - "link": true - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001446", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001446.tgz", - "integrity": "sha512-fEoga4PrImGcwUUGEol/PoFCSBnSkA9drgdkxXkJLsUBOnJ8rs3zDv6ApqYXGQFOyMPsjh79naWhF4DAxbF8rw==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - } - ] - }, - "node_modules/client-only": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", - "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" - }, - "node_modules/csstype": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", - "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/next": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/next/-/next-13.1.4.tgz", - "integrity": "sha512-g0oBUU+tcOPKbXTVdsDO2adc6wd/ggqauHHysPQJxuIKqZ+fwICGJht0C5D5V0A/77eQDF5EFwNdAHkFvBDsog==", - "dependencies": { - "@next/env": "13.1.4", - "@swc/helpers": "0.4.14", - "caniuse-lite": "^1.0.30001406", - "postcss": "8.4.14", - "styled-jsx": "5.1.1" - }, - "bin": { - "next": "dist/bin/next" - }, - "engines": { - "node": ">=14.6.0" - }, - "optionalDependencies": { - "@next/swc-android-arm-eabi": "13.1.4", - "@next/swc-android-arm64": "13.1.4", - "@next/swc-darwin-arm64": "13.1.4", - "@next/swc-darwin-x64": "13.1.4", - "@next/swc-freebsd-x64": "13.1.4", - "@next/swc-linux-arm-gnueabihf": "13.1.4", - "@next/swc-linux-arm64-gnu": "13.1.4", - "@next/swc-linux-arm64-musl": "13.1.4", - "@next/swc-linux-x64-gnu": "13.1.4", - "@next/swc-linux-x64-musl": "13.1.4", - "@next/swc-win32-arm64-msvc": "13.1.4", - "@next/swc-win32-ia32-msvc": "13.1.4", - "@next/swc-win32-x64-msvc": "13.1.4" - }, - "peerDependencies": { - "fibers": ">= 3.1.0", - "node-sass": "^6.0.0 || ^7.0.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "sass": "^1.3.0" - }, - "peerDependenciesMeta": { - "fibers": { - "optional": true - }, - "node-sass": { - "optional": true - }, - "sass": { - "optional": true - } - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "node_modules/postcss": { - "version": "8.4.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", - "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - } - ], - "dependencies": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/prisma": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.16.1.tgz", - "integrity": "sha512-C2Xm7yxHxjFjjscBEW4tmoraPHH/Vyu/A0XABdbaFtoiOZARsxvOM7rwc2iZ0qVxbh0bGBGBWZUSXO/52/nHBQ==", - "devOptional": true, - "hasInstallScript": true, - "dependencies": { - "@prisma/engines": "4.16.1" - }, - "bin": { - "prisma": "build/index.js", - "prisma2": "build/index.js" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" - }, - "peerDependencies": { - "react": "^18.2.0" - } - }, - "node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/styled-jsx": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", - "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", - "dependencies": { - "client-only": "0.0.1" - }, - "engines": { - "node": ">= 12.0.0" - }, - "peerDependencies": { - "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "babel-plugin-macros": { - "optional": true - } - } - }, - "node_modules/swr": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/swr/-/swr-2.2.0.tgz", - "integrity": "sha512-AjqHOv2lAhkuUdIiBu9xbuettzAzWXmCEcLONNKJRba87WAefz8Ca9d6ds/SzrPc235n1IxWYdhJ2zF3MNUaoQ==", - "dependencies": { - "use-sync-external-store": "^1.2.0" - }, - "peerDependencies": { - "react": "^16.11.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/tslib": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", - "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" - }, - "node_modules/typescript": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", - "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/use-sync-external-store": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/zod": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.1.tgz", - "integrity": "sha512-+dTu2m6gmCbO9Ahm4ZBDapx2O6ZY9QSPXst2WXjcznPMwf2YNpn3RevLx4KkZp1OPW/ouFcoBtBzFz/LeY69oA==", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - } - }, - "dependencies": { - "@next/env": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.1.4.tgz", - "integrity": "sha512-x7ydhMpi9/xX7yVK+Fw33OuwwQWVZUFRxenK3z89fmPzQZyUk35Ynb+b7JkrhfRhDIFFvvqpzVSXeseSlBAw7A==" - }, - "@next/swc-android-arm-eabi": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-13.1.4.tgz", - "integrity": "sha512-5PAchzFst3In6Ml+9APvBj89H29lcPXcUqEYBVv09fWK/V4IuViKc2qOqM9pyPyw7KsqaZPmuqaG595E6jdZLA==", - "optional": true - }, - "@next/swc-android-arm64": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-13.1.4.tgz", - "integrity": "sha512-LCLjjRhsQ5fR9ExzR2fqxuyJe/D4Ct/YkdonVfJfqOfkEpFwUTQDOVo5GrQec4LZDk3zY+o6vZYjXbB0nD9VLA==", - "optional": true - }, - "@next/swc-darwin-arm64": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.1.4.tgz", - "integrity": "sha512-LSc/tF1FQ1y1SwKiCdGg8IIl7+Csk6nuLcLIyQXs24UNYjXg5+7vUQXqE8y66v/Dq8qFDC9rM61QhpM9ZDftbg==", - "optional": true - }, - "@next/swc-darwin-x64": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.1.4.tgz", - "integrity": "sha512-WoApDo8xfafrNc9+Mz5MwGFKUwbDHsGqLleTGZ8upegwVqDyHsYzqJQudf+loqhV58oGTOqP1eWaHn2J7dijXA==", - "optional": true - }, - "@next/swc-freebsd-x64": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-13.1.4.tgz", - "integrity": "sha512-fqNyeT8G4guN8AHPIoBRhGY2GJg89FyWpuwX4o0Y3vUy/84IGZpNst3paCzaYkQSqQE/AuCpkB7hKxkN7ittXw==", - "optional": true - }, - "@next/swc-linux-arm-gnueabihf": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-13.1.4.tgz", - "integrity": "sha512-MEfm8OC1YR9/tYHUzlQsxcSmiuf8XdO7bqh5VtG4pilScjc5I5t+tQgIDgoDGePfh5W99W23hb3s6oCFrt99rw==", - "optional": true - }, - "@next/swc-linux-arm64-gnu": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.1.4.tgz", - "integrity": "sha512-2wgth/KsuODzW/E7jsRoWdhKmE5oZzXcBPvf9RW+ZpBNvYQkEDlzfLA7n8DtxTU8I4oMas0mdEPdCWXrSNnVZw==", - "optional": true - }, - "@next/swc-linux-arm64-musl": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.1.4.tgz", - "integrity": "sha512-GdWhCRljsT7rNEElEsdu4RRppd+XaQOX1IJslsh/+HU6LsJGUE8tXpa68yJjCsHZHifkbdZNeCr5SYdsN6CbAA==", - "optional": true - }, - "@next/swc-linux-x64-gnu": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.1.4.tgz", - "integrity": "sha512-Rsk/ojwYqMskN2eo5hUSVe7UuMV/aSjmrmJ0BCFGFPfBY9sPgmYj/oXlDDN0y5lJD9acPuiBjknLWgnOnx5JIA==", - "optional": true - }, - "@next/swc-linux-x64-musl": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.1.4.tgz", - "integrity": "sha512-gKSVPozedA2gpA+vggYnAqpDuzWFed2oxFeXxHw0aW2ALdAZswAinn1ZwXEQ5fHnVguxjZhH0+2nBxpMdF8p5Q==", - "optional": true - }, - "@next/swc-win32-arm64-msvc": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.1.4.tgz", - "integrity": "sha512-+kAXIIVb7Q4LCKmi7dn9qVlG1XUf3Chgj5Rwl0rAP4WBV2TnJIgsOEC24G1Mm3jjif+qXm7SJS9YZ9Yg3Y8sSQ==", - "optional": true - }, - "@next/swc-win32-ia32-msvc": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.1.4.tgz", - "integrity": "sha512-EsfzAFBVaw1zg1FzlLMgRaTX/DKY+EnAvJ6mCIJMGeSOPIj4Oy6xF2yEQ3VaRkwFpAafHJH6JNB/CGrdKFCMXw==", - "optional": true - }, - "@next/swc-win32-x64-msvc": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.1.4.tgz", - "integrity": "sha512-bygNjmnq+F9NqJXh7OfhJgqu6LGU29GNKQYVyZkxY/h5K0WWUvAE/VL+TdyMwbvQr9KByx5XLwORwetLxXCo4g==", - "optional": true - }, - "@prisma/client": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.16.1.tgz", - "integrity": "sha512-CoDHu7Bt+NuDo40ijoeHP79EHtECsPBTy3yte5Yo3op8TqXt/kV0OT5OrsWewKvQGKFMHhYQ+ePed3zzjYdGAw==", - "requires": { - "@prisma/engines-version": "4.16.0-66.b20ead4d3ab9e78ac112966e242ded703f4a052c" - } - }, - "@prisma/engines": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.16.1.tgz", - "integrity": "sha512-gpZG0kGGxfemgvK/LghHdBIz+crHkZjzszja94xp4oytpsXrgt/Ice82MvPsWMleVIniKuARrowtsIsim0PFJQ==", - "devOptional": true - }, - "@prisma/engines-version": { - "version": "4.16.0-66.b20ead4d3ab9e78ac112966e242ded703f4a052c", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.16.0-66.b20ead4d3ab9e78ac112966e242ded703f4a052c.tgz", - "integrity": "sha512-tMWAF/qF00fbUH1HB4Yjmz6bjh7fzkb7Y3NRoUfMlHu6V+O45MGvqwYxqwBjn1BIUXkl3r04W351D4qdJjrgvA==" - }, - "@swc/helpers": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz", - "integrity": "sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==", - "requires": { - "tslib": "^2.4.0" - } - }, - "@types/node": { - "version": "18.11.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", - "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==" - }, - "@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" - }, - "@types/react": { - "version": "18.0.27", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.27.tgz", - "integrity": "sha512-3vtRKHgVxu3Jp9t718R9BuzoD4NcQ8YJ5XRzsSKxNDiDonD2MXIT1TmSkenxuCycZJoQT5d2vE8LwWJxBC1gmA==", - "requires": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "@types/react-dom": { - "version": "18.0.10", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.10.tgz", - "integrity": "sha512-E42GW/JA4Qv15wQdqJq8DL4JhNpB3prJgjgapN3qJT9K2zO5IIAQh4VXvCEDupoqAwnz0cY4RlXeC/ajX5SFHg==", - "requires": { - "@types/react": "*" - } - }, - "@types/scheduler": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" - }, - "@zenstackhq/runtime": { - "version": "file:../../../../../../packages/runtime/dist" - }, - "@zenstackhq/swr": { - "version": "file:../../../../../../packages/plugins/swr/dist" - }, - "caniuse-lite": { - "version": "1.0.30001446", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001446.tgz", - "integrity": "sha512-fEoga4PrImGcwUUGEol/PoFCSBnSkA9drgdkxXkJLsUBOnJ8rs3zDv6ApqYXGQFOyMPsjh79naWhF4DAxbF8rw==" - }, - "client-only": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", - "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" - }, - "csstype": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", - "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" - }, - "next": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/next/-/next-13.1.4.tgz", - "integrity": "sha512-g0oBUU+tcOPKbXTVdsDO2adc6wd/ggqauHHysPQJxuIKqZ+fwICGJht0C5D5V0A/77eQDF5EFwNdAHkFvBDsog==", - "requires": { - "@next/env": "13.1.4", - "@next/swc-android-arm-eabi": "13.1.4", - "@next/swc-android-arm64": "13.1.4", - "@next/swc-darwin-arm64": "13.1.4", - "@next/swc-darwin-x64": "13.1.4", - "@next/swc-freebsd-x64": "13.1.4", - "@next/swc-linux-arm-gnueabihf": "13.1.4", - "@next/swc-linux-arm64-gnu": "13.1.4", - "@next/swc-linux-arm64-musl": "13.1.4", - "@next/swc-linux-x64-gnu": "13.1.4", - "@next/swc-linux-x64-musl": "13.1.4", - "@next/swc-win32-arm64-msvc": "13.1.4", - "@next/swc-win32-ia32-msvc": "13.1.4", - "@next/swc-win32-x64-msvc": "13.1.4", - "@swc/helpers": "0.4.14", - "caniuse-lite": "^1.0.30001406", - "postcss": "8.4.14", - "styled-jsx": "5.1.1" - } - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "postcss": { - "version": "8.4.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", - "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", - "requires": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - } - }, - "prisma": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.16.1.tgz", - "integrity": "sha512-C2Xm7yxHxjFjjscBEW4tmoraPHH/Vyu/A0XABdbaFtoiOZARsxvOM7rwc2iZ0qVxbh0bGBGBWZUSXO/52/nHBQ==", - "devOptional": true, - "requires": { - "@prisma/engines": "4.16.1" - } - }, - "react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "requires": { - "loose-envify": "^1.1.0" - } - }, - "react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", - "requires": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" - } - }, - "scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "requires": { - "loose-envify": "^1.1.0" - } - }, - "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" - }, - "styled-jsx": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", - "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", - "requires": { - "client-only": "0.0.1" - } - }, - "swr": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/swr/-/swr-2.2.0.tgz", - "integrity": "sha512-AjqHOv2lAhkuUdIiBu9xbuettzAzWXmCEcLONNKJRba87WAefz8Ca9d6ds/SzrPc235n1IxWYdhJ2zF3MNUaoQ==", - "requires": { - "use-sync-external-store": "^1.2.0" - } - }, - "tslib": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", - "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" - }, - "typescript": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", - "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==" - }, - "use-sync-external-store": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", - "requires": {} - }, - "zod": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.1.tgz", - "integrity": "sha512-+dTu2m6gmCbO9Ahm4ZBDapx2O6ZY9QSPXst2WXjcznPMwf2YNpn3RevLx4KkZp1OPW/ouFcoBtBzFz/LeY69oA==" - } - } -} diff --git a/tests/integration/tests/plugins/prisma.test.ts b/tests/integration/tests/plugins/prisma.test.ts index c3c8478fc..9e462f578 100644 --- a/tests/integration/tests/plugins/prisma.test.ts +++ b/tests/integration/tests/plugins/prisma.test.ts @@ -35,11 +35,13 @@ plugin prisma { output = './db/schema.prisma' } `; - const { projectDir } = await loadSchema(model, true, false); + const { projectDir } = await loadSchema(model, { pushDb: false }); expect(fs.existsSync(path.join(projectDir, './db/schema.prisma'))).toEqual(true); }); - it('relative absolute location', async () => { + // eslint-disable-next-line jest/no-disabled-tests + it.skip('relative absolute location', async () => { + // disabling due to a possible bug in Prisma V5 const { name: outDir } = tmp.dirSync({ unsafeCleanup: true }); const model = ` model User { @@ -51,7 +53,7 @@ plugin prisma { output = '${outDir}/db/schema.prisma' } `; - await loadSchema(model, true, false); + await loadSchema(model, { pushDb: false }); expect(fs.existsSync(path.join(outDir, './db/schema.prisma'))).toEqual(true); }); }); diff --git a/tests/integration/tests/plugins/zod.test.ts b/tests/integration/tests/plugins/zod.test.ts index 5fb335143..136155aaf 100644 --- a/tests/integration/tests/plugins/zod.test.ts +++ b/tests/integration/tests/plugins/zod.test.ts @@ -52,7 +52,7 @@ describe('Zod plugin tests', () => { } `; - const { zodSchemas } = await loadSchema(model, false, false); + const { zodSchemas } = await loadSchema(model, { addPrelude: false, pushDb: false }); const schemas = zodSchemas.models; expect(schemas.UserSchema).toBeTruthy(); expect(schemas.UserCreateSchema).toBeTruthy(); @@ -141,7 +141,7 @@ describe('Zod plugin tests', () => { } `; - const { zodSchemas } = await loadSchema(model, false, false); + const { zodSchemas } = await loadSchema(model, { addPrelude: false, pushDb: false }); const schema = zodSchemas.models.MCreateSchema; @@ -234,7 +234,7 @@ describe('Zod plugin tests', () => { } `; - const { zodSchemas } = await loadSchema(model, false, false); + const { zodSchemas } = await loadSchema(model, { addPrelude: false, pushDb: false }); const schema = zodSchemas.models.MCreateSchema; expect(schema.safeParse({ email: 'abd@x.com', x: 0 }).error.toString()).toMatch(/condition1/); @@ -285,7 +285,7 @@ describe('Zod plugin tests', () => { } `; - const { zodSchemas } = await loadSchema(model, false, false); + const { zodSchemas } = await loadSchema(model, { addPrelude: false, pushDb: false }); const schema = zodSchemas.models.MCreateSchema; expect(schema.safeParse({}).error.toString()).toMatch(/condition1/); diff --git a/tests/integration/tests/trpc/test-project/package-lock.json b/tests/integration/tests/trpc/test-project/package-lock.json deleted file mode 100644 index f3f74a713..000000000 --- a/tests/integration/tests/trpc/test-project/package-lock.json +++ /dev/null @@ -1,1029 +0,0 @@ -{ - "name": "test-project", - "version": "0.1.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "test-project", - "version": "0.1.0", - "dependencies": { - "@prisma/client": "^4.7.0", - "@tanstack/react-query": "^4.22.4", - "@trpc/client": "^10.9.0", - "@trpc/next": "^10.9.0", - "@trpc/react-query": "^10.9.0", - "@trpc/server": "^10.9.0", - "@types/node": "18.11.18", - "@types/react": "18.0.27", - "@types/react-dom": "18.0.10", - "@zenstackhq/runtime": "../../../../../../packages/runtime/dist", - "next": "13.1.4", - "react": "18.2.0", - "react-dom": "18.2.0", - "superjson": "^1.12.2", - "typescript": "4.9.4", - "zod": "3.21.1" - }, - "devDependencies": { - "prisma": "^4.7.0" - } - }, - "../../../../../../packages/runtime/dist": {}, - "node_modules/@next/env": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.1.4.tgz", - "integrity": "sha512-x7ydhMpi9/xX7yVK+Fw33OuwwQWVZUFRxenK3z89fmPzQZyUk35Ynb+b7JkrhfRhDIFFvvqpzVSXeseSlBAw7A==" - }, - "node_modules/@next/swc-android-arm-eabi": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-13.1.4.tgz", - "integrity": "sha512-5PAchzFst3In6Ml+9APvBj89H29lcPXcUqEYBVv09fWK/V4IuViKc2qOqM9pyPyw7KsqaZPmuqaG595E6jdZLA==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-android-arm64": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-13.1.4.tgz", - "integrity": "sha512-LCLjjRhsQ5fR9ExzR2fqxuyJe/D4Ct/YkdonVfJfqOfkEpFwUTQDOVo5GrQec4LZDk3zY+o6vZYjXbB0nD9VLA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-darwin-arm64": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.1.4.tgz", - "integrity": "sha512-LSc/tF1FQ1y1SwKiCdGg8IIl7+Csk6nuLcLIyQXs24UNYjXg5+7vUQXqE8y66v/Dq8qFDC9rM61QhpM9ZDftbg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-darwin-x64": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.1.4.tgz", - "integrity": "sha512-WoApDo8xfafrNc9+Mz5MwGFKUwbDHsGqLleTGZ8upegwVqDyHsYzqJQudf+loqhV58oGTOqP1eWaHn2J7dijXA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-freebsd-x64": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-13.1.4.tgz", - "integrity": "sha512-fqNyeT8G4guN8AHPIoBRhGY2GJg89FyWpuwX4o0Y3vUy/84IGZpNst3paCzaYkQSqQE/AuCpkB7hKxkN7ittXw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm-gnueabihf": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-13.1.4.tgz", - "integrity": "sha512-MEfm8OC1YR9/tYHUzlQsxcSmiuf8XdO7bqh5VtG4pilScjc5I5t+tQgIDgoDGePfh5W99W23hb3s6oCFrt99rw==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-gnu": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.1.4.tgz", - "integrity": "sha512-2wgth/KsuODzW/E7jsRoWdhKmE5oZzXcBPvf9RW+ZpBNvYQkEDlzfLA7n8DtxTU8I4oMas0mdEPdCWXrSNnVZw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-musl": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.1.4.tgz", - "integrity": "sha512-GdWhCRljsT7rNEElEsdu4RRppd+XaQOX1IJslsh/+HU6LsJGUE8tXpa68yJjCsHZHifkbdZNeCr5SYdsN6CbAA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-gnu": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.1.4.tgz", - "integrity": "sha512-Rsk/ojwYqMskN2eo5hUSVe7UuMV/aSjmrmJ0BCFGFPfBY9sPgmYj/oXlDDN0y5lJD9acPuiBjknLWgnOnx5JIA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-musl": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.1.4.tgz", - "integrity": "sha512-gKSVPozedA2gpA+vggYnAqpDuzWFed2oxFeXxHw0aW2ALdAZswAinn1ZwXEQ5fHnVguxjZhH0+2nBxpMdF8p5Q==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-arm64-msvc": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.1.4.tgz", - "integrity": "sha512-+kAXIIVb7Q4LCKmi7dn9qVlG1XUf3Chgj5Rwl0rAP4WBV2TnJIgsOEC24G1Mm3jjif+qXm7SJS9YZ9Yg3Y8sSQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-ia32-msvc": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.1.4.tgz", - "integrity": "sha512-EsfzAFBVaw1zg1FzlLMgRaTX/DKY+EnAvJ6mCIJMGeSOPIj4Oy6xF2yEQ3VaRkwFpAafHJH6JNB/CGrdKFCMXw==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-x64-msvc": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.1.4.tgz", - "integrity": "sha512-bygNjmnq+F9NqJXh7OfhJgqu6LGU29GNKQYVyZkxY/h5K0WWUvAE/VL+TdyMwbvQr9KByx5XLwORwetLxXCo4g==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@prisma/client": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.9.0.tgz", - "integrity": "sha512-bz6QARw54sWcbyR1lLnF2QHvRW5R/Jxnbbmwh3u+969vUKXtBkXgSgjDA85nji31ZBlf7+FrHDy5x+5ydGyQDg==", - "hasInstallScript": true, - "dependencies": { - "@prisma/engines-version": "4.9.0-42.ceb5c99003b99c9ee2c1d2e618e359c14aef2ea5" - }, - "engines": { - "node": ">=14.17" - }, - "peerDependencies": { - "prisma": "*" - }, - "peerDependenciesMeta": { - "prisma": { - "optional": true - } - } - }, - "node_modules/@prisma/engines": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.9.0.tgz", - "integrity": "sha512-t1pt0Gsp+HcgPJrHFc+d/ZSAaKKWar2G/iakrE07yeKPNavDP3iVKPpfXP22OTCHZUWf7OelwKJxQgKAm5hkgw==", - "devOptional": true, - "hasInstallScript": true - }, - "node_modules/@prisma/engines-version": { - "version": "4.9.0-42.ceb5c99003b99c9ee2c1d2e618e359c14aef2ea5", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.9.0-42.ceb5c99003b99c9ee2c1d2e618e359c14aef2ea5.tgz", - "integrity": "sha512-M16aibbxi/FhW7z1sJCX8u+0DriyQYY5AyeTH7plQm9MLnURoiyn3CZBqAyIoQ+Z1pS77usCIibYJWSgleBMBA==" - }, - "node_modules/@swc/helpers": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz", - "integrity": "sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==", - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@tanstack/query-core": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.22.4.tgz", - "integrity": "sha512-t79CMwlbBnj+yL82tEcmRN93bL4U3pae2ota4t5NN2z3cIeWw74pzdWrKRwOfTvLcd+b30tC+ciDlfYOKFPGUw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@tanstack/react-query": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.22.4.tgz", - "integrity": "sha512-e5j5Z88XUQGeEPMyz5XF1V0mMf6Da+6URXiTpZfUb9nuHs2nlNoA+EoIvnhccE5b9YT6Yg7kARhn2L7u94M/4A==", - "dependencies": { - "@tanstack/query-core": "4.22.4", - "use-sync-external-store": "^1.2.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-native": "*" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true - } - } - }, - "node_modules/@trpc/client": { - "version": "10.9.0", - "resolved": "https://registry.npmjs.org/@trpc/client/-/client-10.9.0.tgz", - "integrity": "sha512-id6318qpgqllNOuBp7nuciXFPXCe+zae5d4r1hze6Eyp5fFFNO58TqA+4Q44KIcHgpfWyW2egs6iPeql3PrdKA==", - "peerDependencies": { - "@trpc/server": "10.9.0" - } - }, - "node_modules/@trpc/next": { - "version": "10.9.0", - "resolved": "https://registry.npmjs.org/@trpc/next/-/next-10.9.0.tgz", - "integrity": "sha512-h/W8VHMki/fw7vHNMs1Ku7bLqccjpiKCE1wkqbvHfBOO1ARDmarRbuK6dLqJilip/f7jkFXcrxwB+eNgK4+6Wg==", - "dependencies": { - "react-ssr-prepass": "^1.5.0" - }, - "peerDependencies": { - "@tanstack/react-query": "^4.3.8", - "@trpc/client": "10.9.0", - "@trpc/react-query": "^10.8.0", - "@trpc/server": "10.9.0", - "next": "*", - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/@trpc/react-query": { - "version": "10.9.0", - "resolved": "https://registry.npmjs.org/@trpc/react-query/-/react-query-10.9.0.tgz", - "integrity": "sha512-I7xtdFj/AETwc9HfY2bGxKINij39r26LvfIiTBfz2pBj1ELrcgucWmPeI2eS6pon/uI1E9Nqa6fQCg/zkg764Q==", - "peerDependencies": { - "@tanstack/react-query": "^4.3.8", - "@trpc/client": "10.9.0", - "@trpc/server": "10.9.0", - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/@trpc/server": { - "version": "10.9.0", - "resolved": "https://registry.npmjs.org/@trpc/server/-/server-10.9.0.tgz", - "integrity": "sha512-5psyZgbvy29pJND32hwkWTMbv6s86IbsPOeDopsgNF0VegZT6Dsijmb7Ub/TDhuJVQVq5u4u5briMXi3SxmBkw==" - }, - "node_modules/@types/node": { - "version": "18.11.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", - "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==" - }, - "node_modules/@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" - }, - "node_modules/@types/react": { - "version": "18.0.27", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.27.tgz", - "integrity": "sha512-3vtRKHgVxu3Jp9t718R9BuzoD4NcQ8YJ5XRzsSKxNDiDonD2MXIT1TmSkenxuCycZJoQT5d2vE8LwWJxBC1gmA==", - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-dom": { - "version": "18.0.10", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.10.tgz", - "integrity": "sha512-E42GW/JA4Qv15wQdqJq8DL4JhNpB3prJgjgapN3qJT9K2zO5IIAQh4VXvCEDupoqAwnz0cY4RlXeC/ajX5SFHg==", - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/scheduler": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" - }, - "node_modules/@zenstackhq/runtime": { - "resolved": "../../../../../../packages/runtime/dist", - "link": true - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001446", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001446.tgz", - "integrity": "sha512-fEoga4PrImGcwUUGEol/PoFCSBnSkA9drgdkxXkJLsUBOnJ8rs3zDv6ApqYXGQFOyMPsjh79naWhF4DAxbF8rw==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - } - ] - }, - "node_modules/client-only": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", - "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" - }, - "node_modules/copy-anything": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.3.tgz", - "integrity": "sha512-fpW2W/BqEzqPp29QS+MwwfisHCQZtiduTe/m8idFo0xbti9fIZ2WVhAsCv4ggFVH3AgCkVdpoOCtQC6gBrdhjw==", - "dependencies": { - "is-what": "^4.1.8" - }, - "engines": { - "node": ">=12.13" - }, - "funding": { - "url": "https://github.com/sponsors/mesqueeb" - } - }, - "node_modules/csstype": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", - "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" - }, - "node_modules/is-what": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.8.tgz", - "integrity": "sha512-yq8gMao5upkPoGEU9LsB2P+K3Kt8Q3fQFCGyNCWOAnJAMzEXVV9drYb0TXr42TTliLLhKIBvulgAXgtLLnwzGA==", - "engines": { - "node": ">=12.13" - }, - "funding": { - "url": "https://github.com/sponsors/mesqueeb" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/next": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/next/-/next-13.1.4.tgz", - "integrity": "sha512-g0oBUU+tcOPKbXTVdsDO2adc6wd/ggqauHHysPQJxuIKqZ+fwICGJht0C5D5V0A/77eQDF5EFwNdAHkFvBDsog==", - "dependencies": { - "@next/env": "13.1.4", - "@swc/helpers": "0.4.14", - "caniuse-lite": "^1.0.30001406", - "postcss": "8.4.14", - "styled-jsx": "5.1.1" - }, - "bin": { - "next": "dist/bin/next" - }, - "engines": { - "node": ">=14.6.0" - }, - "optionalDependencies": { - "@next/swc-android-arm-eabi": "13.1.4", - "@next/swc-android-arm64": "13.1.4", - "@next/swc-darwin-arm64": "13.1.4", - "@next/swc-darwin-x64": "13.1.4", - "@next/swc-freebsd-x64": "13.1.4", - "@next/swc-linux-arm-gnueabihf": "13.1.4", - "@next/swc-linux-arm64-gnu": "13.1.4", - "@next/swc-linux-arm64-musl": "13.1.4", - "@next/swc-linux-x64-gnu": "13.1.4", - "@next/swc-linux-x64-musl": "13.1.4", - "@next/swc-win32-arm64-msvc": "13.1.4", - "@next/swc-win32-ia32-msvc": "13.1.4", - "@next/swc-win32-x64-msvc": "13.1.4" - }, - "peerDependencies": { - "fibers": ">= 3.1.0", - "node-sass": "^6.0.0 || ^7.0.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "sass": "^1.3.0" - }, - "peerDependenciesMeta": { - "fibers": { - "optional": true - }, - "node-sass": { - "optional": true - }, - "sass": { - "optional": true - } - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "node_modules/postcss": { - "version": "8.4.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", - "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - } - ], - "dependencies": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/prisma": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.9.0.tgz", - "integrity": "sha512-bS96oZ5oDFXYgoF2l7PJ3Mp1wWWfLOo8B/jAfbA2Pn0Wm5Z/owBHzaMQKS3i1CzVBDWWPVnOohmbJmjvkcHS5w==", - "devOptional": true, - "hasInstallScript": true, - "dependencies": { - "@prisma/engines": "4.9.0" - }, - "bin": { - "prisma": "build/index.js", - "prisma2": "build/index.js" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" - }, - "peerDependencies": { - "react": "^18.2.0" - } - }, - "node_modules/react-ssr-prepass": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/react-ssr-prepass/-/react-ssr-prepass-1.5.0.tgz", - "integrity": "sha512-yFNHrlVEReVYKsLI5lF05tZoHveA5pGzjFbFJY/3pOqqjGOmMmqx83N4hIjN2n6E1AOa+eQEUxs3CgRnPmT0RQ==", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/styled-jsx": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", - "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", - "dependencies": { - "client-only": "0.0.1" - }, - "engines": { - "node": ">= 12.0.0" - }, - "peerDependencies": { - "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "babel-plugin-macros": { - "optional": true - } - } - }, - "node_modules/superjson": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/superjson/-/superjson-1.12.2.tgz", - "integrity": "sha512-ugvUo9/WmvWOjstornQhsN/sR9mnGtWGYeTxFuqLb4AiT4QdUavjGFRALCPKWWnAiUJ4HTpytj5e0t5HoMRkXg==", - "dependencies": { - "copy-anything": "^3.0.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/tslib": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", - "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" - }, - "node_modules/typescript": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", - "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/use-sync-external-store": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/zod": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.1.tgz", - "integrity": "sha512-+dTu2m6gmCbO9Ahm4ZBDapx2O6ZY9QSPXst2WXjcznPMwf2YNpn3RevLx4KkZp1OPW/ouFcoBtBzFz/LeY69oA==", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - } - }, - "dependencies": { - "@next/env": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.1.4.tgz", - "integrity": "sha512-x7ydhMpi9/xX7yVK+Fw33OuwwQWVZUFRxenK3z89fmPzQZyUk35Ynb+b7JkrhfRhDIFFvvqpzVSXeseSlBAw7A==" - }, - "@next/swc-android-arm-eabi": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-13.1.4.tgz", - "integrity": "sha512-5PAchzFst3In6Ml+9APvBj89H29lcPXcUqEYBVv09fWK/V4IuViKc2qOqM9pyPyw7KsqaZPmuqaG595E6jdZLA==", - "optional": true - }, - "@next/swc-android-arm64": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-13.1.4.tgz", - "integrity": "sha512-LCLjjRhsQ5fR9ExzR2fqxuyJe/D4Ct/YkdonVfJfqOfkEpFwUTQDOVo5GrQec4LZDk3zY+o6vZYjXbB0nD9VLA==", - "optional": true - }, - "@next/swc-darwin-arm64": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.1.4.tgz", - "integrity": "sha512-LSc/tF1FQ1y1SwKiCdGg8IIl7+Csk6nuLcLIyQXs24UNYjXg5+7vUQXqE8y66v/Dq8qFDC9rM61QhpM9ZDftbg==", - "optional": true - }, - "@next/swc-darwin-x64": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.1.4.tgz", - "integrity": "sha512-WoApDo8xfafrNc9+Mz5MwGFKUwbDHsGqLleTGZ8upegwVqDyHsYzqJQudf+loqhV58oGTOqP1eWaHn2J7dijXA==", - "optional": true - }, - "@next/swc-freebsd-x64": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-13.1.4.tgz", - "integrity": "sha512-fqNyeT8G4guN8AHPIoBRhGY2GJg89FyWpuwX4o0Y3vUy/84IGZpNst3paCzaYkQSqQE/AuCpkB7hKxkN7ittXw==", - "optional": true - }, - "@next/swc-linux-arm-gnueabihf": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-13.1.4.tgz", - "integrity": "sha512-MEfm8OC1YR9/tYHUzlQsxcSmiuf8XdO7bqh5VtG4pilScjc5I5t+tQgIDgoDGePfh5W99W23hb3s6oCFrt99rw==", - "optional": true - }, - "@next/swc-linux-arm64-gnu": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.1.4.tgz", - "integrity": "sha512-2wgth/KsuODzW/E7jsRoWdhKmE5oZzXcBPvf9RW+ZpBNvYQkEDlzfLA7n8DtxTU8I4oMas0mdEPdCWXrSNnVZw==", - "optional": true - }, - "@next/swc-linux-arm64-musl": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.1.4.tgz", - "integrity": "sha512-GdWhCRljsT7rNEElEsdu4RRppd+XaQOX1IJslsh/+HU6LsJGUE8tXpa68yJjCsHZHifkbdZNeCr5SYdsN6CbAA==", - "optional": true - }, - "@next/swc-linux-x64-gnu": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.1.4.tgz", - "integrity": "sha512-Rsk/ojwYqMskN2eo5hUSVe7UuMV/aSjmrmJ0BCFGFPfBY9sPgmYj/oXlDDN0y5lJD9acPuiBjknLWgnOnx5JIA==", - "optional": true - }, - "@next/swc-linux-x64-musl": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.1.4.tgz", - "integrity": "sha512-gKSVPozedA2gpA+vggYnAqpDuzWFed2oxFeXxHw0aW2ALdAZswAinn1ZwXEQ5fHnVguxjZhH0+2nBxpMdF8p5Q==", - "optional": true - }, - "@next/swc-win32-arm64-msvc": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.1.4.tgz", - "integrity": "sha512-+kAXIIVb7Q4LCKmi7dn9qVlG1XUf3Chgj5Rwl0rAP4WBV2TnJIgsOEC24G1Mm3jjif+qXm7SJS9YZ9Yg3Y8sSQ==", - "optional": true - }, - "@next/swc-win32-ia32-msvc": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.1.4.tgz", - "integrity": "sha512-EsfzAFBVaw1zg1FzlLMgRaTX/DKY+EnAvJ6mCIJMGeSOPIj4Oy6xF2yEQ3VaRkwFpAafHJH6JNB/CGrdKFCMXw==", - "optional": true - }, - "@next/swc-win32-x64-msvc": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.1.4.tgz", - "integrity": "sha512-bygNjmnq+F9NqJXh7OfhJgqu6LGU29GNKQYVyZkxY/h5K0WWUvAE/VL+TdyMwbvQr9KByx5XLwORwetLxXCo4g==", - "optional": true - }, - "@prisma/client": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.9.0.tgz", - "integrity": "sha512-bz6QARw54sWcbyR1lLnF2QHvRW5R/Jxnbbmwh3u+969vUKXtBkXgSgjDA85nji31ZBlf7+FrHDy5x+5ydGyQDg==", - "requires": { - "@prisma/engines-version": "4.9.0-42.ceb5c99003b99c9ee2c1d2e618e359c14aef2ea5" - } - }, - "@prisma/engines": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.9.0.tgz", - "integrity": "sha512-t1pt0Gsp+HcgPJrHFc+d/ZSAaKKWar2G/iakrE07yeKPNavDP3iVKPpfXP22OTCHZUWf7OelwKJxQgKAm5hkgw==", - "devOptional": true - }, - "@prisma/engines-version": { - "version": "4.9.0-42.ceb5c99003b99c9ee2c1d2e618e359c14aef2ea5", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.9.0-42.ceb5c99003b99c9ee2c1d2e618e359c14aef2ea5.tgz", - "integrity": "sha512-M16aibbxi/FhW7z1sJCX8u+0DriyQYY5AyeTH7plQm9MLnURoiyn3CZBqAyIoQ+Z1pS77usCIibYJWSgleBMBA==" - }, - "@swc/helpers": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz", - "integrity": "sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==", - "requires": { - "tslib": "^2.4.0" - } - }, - "@tanstack/query-core": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.22.4.tgz", - "integrity": "sha512-t79CMwlbBnj+yL82tEcmRN93bL4U3pae2ota4t5NN2z3cIeWw74pzdWrKRwOfTvLcd+b30tC+ciDlfYOKFPGUw==" - }, - "@tanstack/react-query": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.22.4.tgz", - "integrity": "sha512-e5j5Z88XUQGeEPMyz5XF1V0mMf6Da+6URXiTpZfUb9nuHs2nlNoA+EoIvnhccE5b9YT6Yg7kARhn2L7u94M/4A==", - "requires": { - "@tanstack/query-core": "4.22.4", - "use-sync-external-store": "^1.2.0" - } - }, - "@trpc/client": { - "version": "10.9.0", - "resolved": "https://registry.npmjs.org/@trpc/client/-/client-10.9.0.tgz", - "integrity": "sha512-id6318qpgqllNOuBp7nuciXFPXCe+zae5d4r1hze6Eyp5fFFNO58TqA+4Q44KIcHgpfWyW2egs6iPeql3PrdKA==", - "requires": {} - }, - "@trpc/next": { - "version": "10.9.0", - "resolved": "https://registry.npmjs.org/@trpc/next/-/next-10.9.0.tgz", - "integrity": "sha512-h/W8VHMki/fw7vHNMs1Ku7bLqccjpiKCE1wkqbvHfBOO1ARDmarRbuK6dLqJilip/f7jkFXcrxwB+eNgK4+6Wg==", - "requires": { - "react-ssr-prepass": "^1.5.0" - } - }, - "@trpc/react-query": { - "version": "10.9.0", - "resolved": "https://registry.npmjs.org/@trpc/react-query/-/react-query-10.9.0.tgz", - "integrity": "sha512-I7xtdFj/AETwc9HfY2bGxKINij39r26LvfIiTBfz2pBj1ELrcgucWmPeI2eS6pon/uI1E9Nqa6fQCg/zkg764Q==", - "requires": {} - }, - "@trpc/server": { - "version": "10.9.0", - "resolved": "https://registry.npmjs.org/@trpc/server/-/server-10.9.0.tgz", - "integrity": "sha512-5psyZgbvy29pJND32hwkWTMbv6s86IbsPOeDopsgNF0VegZT6Dsijmb7Ub/TDhuJVQVq5u4u5briMXi3SxmBkw==" - }, - "@types/node": { - "version": "18.11.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", - "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==" - }, - "@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" - }, - "@types/react": { - "version": "18.0.27", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.27.tgz", - "integrity": "sha512-3vtRKHgVxu3Jp9t718R9BuzoD4NcQ8YJ5XRzsSKxNDiDonD2MXIT1TmSkenxuCycZJoQT5d2vE8LwWJxBC1gmA==", - "requires": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "@types/react-dom": { - "version": "18.0.10", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.10.tgz", - "integrity": "sha512-E42GW/JA4Qv15wQdqJq8DL4JhNpB3prJgjgapN3qJT9K2zO5IIAQh4VXvCEDupoqAwnz0cY4RlXeC/ajX5SFHg==", - "requires": { - "@types/react": "*" - } - }, - "@types/scheduler": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" - }, - "@zenstackhq/runtime": { - "version": "file:../../../../../../packages/runtime/dist" - }, - "caniuse-lite": { - "version": "1.0.30001446", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001446.tgz", - "integrity": "sha512-fEoga4PrImGcwUUGEol/PoFCSBnSkA9drgdkxXkJLsUBOnJ8rs3zDv6ApqYXGQFOyMPsjh79naWhF4DAxbF8rw==" - }, - "client-only": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", - "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" - }, - "copy-anything": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.3.tgz", - "integrity": "sha512-fpW2W/BqEzqPp29QS+MwwfisHCQZtiduTe/m8idFo0xbti9fIZ2WVhAsCv4ggFVH3AgCkVdpoOCtQC6gBrdhjw==", - "requires": { - "is-what": "^4.1.8" - } - }, - "csstype": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", - "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" - }, - "is-what": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.8.tgz", - "integrity": "sha512-yq8gMao5upkPoGEU9LsB2P+K3Kt8Q3fQFCGyNCWOAnJAMzEXVV9drYb0TXr42TTliLLhKIBvulgAXgtLLnwzGA==" - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" - }, - "next": { - "version": "13.1.4", - "resolved": "https://registry.npmjs.org/next/-/next-13.1.4.tgz", - "integrity": "sha512-g0oBUU+tcOPKbXTVdsDO2adc6wd/ggqauHHysPQJxuIKqZ+fwICGJht0C5D5V0A/77eQDF5EFwNdAHkFvBDsog==", - "requires": { - "@next/env": "13.1.4", - "@next/swc-android-arm-eabi": "13.1.4", - "@next/swc-android-arm64": "13.1.4", - "@next/swc-darwin-arm64": "13.1.4", - "@next/swc-darwin-x64": "13.1.4", - "@next/swc-freebsd-x64": "13.1.4", - "@next/swc-linux-arm-gnueabihf": "13.1.4", - "@next/swc-linux-arm64-gnu": "13.1.4", - "@next/swc-linux-arm64-musl": "13.1.4", - "@next/swc-linux-x64-gnu": "13.1.4", - "@next/swc-linux-x64-musl": "13.1.4", - "@next/swc-win32-arm64-msvc": "13.1.4", - "@next/swc-win32-ia32-msvc": "13.1.4", - "@next/swc-win32-x64-msvc": "13.1.4", - "@swc/helpers": "0.4.14", - "caniuse-lite": "^1.0.30001406", - "postcss": "8.4.14", - "styled-jsx": "5.1.1" - } - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "postcss": { - "version": "8.4.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", - "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", - "requires": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - } - }, - "prisma": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.9.0.tgz", - "integrity": "sha512-bS96oZ5oDFXYgoF2l7PJ3Mp1wWWfLOo8B/jAfbA2Pn0Wm5Z/owBHzaMQKS3i1CzVBDWWPVnOohmbJmjvkcHS5w==", - "devOptional": true, - "requires": { - "@prisma/engines": "4.9.0" - } - }, - "react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "requires": { - "loose-envify": "^1.1.0" - } - }, - "react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", - "requires": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" - } - }, - "react-ssr-prepass": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/react-ssr-prepass/-/react-ssr-prepass-1.5.0.tgz", - "integrity": "sha512-yFNHrlVEReVYKsLI5lF05tZoHveA5pGzjFbFJY/3pOqqjGOmMmqx83N4hIjN2n6E1AOa+eQEUxs3CgRnPmT0RQ==", - "requires": {} - }, - "scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "requires": { - "loose-envify": "^1.1.0" - } - }, - "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" - }, - "styled-jsx": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", - "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", - "requires": { - "client-only": "0.0.1" - } - }, - "superjson": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/superjson/-/superjson-1.12.2.tgz", - "integrity": "sha512-ugvUo9/WmvWOjstornQhsN/sR9mnGtWGYeTxFuqLb4AiT4QdUavjGFRALCPKWWnAiUJ4HTpytj5e0t5HoMRkXg==", - "requires": { - "copy-anything": "^3.0.2" - } - }, - "tslib": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", - "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" - }, - "typescript": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", - "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==" - }, - "use-sync-external-store": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", - "requires": {} - }, - "zod": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.1.tgz", - "integrity": "sha512-+dTu2m6gmCbO9Ahm4ZBDapx2O6ZY9QSPXst2WXjcznPMwf2YNpn3RevLx4KkZp1OPW/ouFcoBtBzFz/LeY69oA==" - } - } -} diff --git a/tests/integration/utils/jest-ext.ts b/tests/integration/utils/jest-ext.ts index 9d49d82ca..649ba104c 100644 --- a/tests/integration/utils/jest-ext.ts +++ b/tests/integration/utils/jest-ext.ts @@ -1,5 +1,5 @@ import { format } from 'util'; -import { isPrismaClientKnownRequestError } from '@zenstackhq/runtime/error'; +import { isPrismaClientKnownRequestError } from '@zenstackhq/runtime'; export const toBeRejectedByPolicy = async function (received: Promise, expectedMessages?: string[]) { if (!(received instanceof Promise)) {