From ffdad2713e71071b53ac3fd13b82b38673d7b6f6 Mon Sep 17 00:00:00 2001 From: Yiming Date: Sat, 8 Jul 2023 21:59:20 +0800 Subject: [PATCH 1/5] fix: update rule check for connect with implicit many-to-many relation (#565) --- .../runtime/src/enhancements/model-meta.ts | 7 + .../src/enhancements/policy/policy-utils.ts | 40 ++- .../schema/src/plugins/model-meta/index.ts | 19 +- .../with-policy/connect-disconnect.test.ts | 132 ++++++++ .../relation-many-to-many-filter.test.ts | 296 ++++++++++++++++++ ...ts => relation-one-to-many-filter.test.ts} | 65 +++- ....ts => relation-one-to-one-filter.test.ts} | 2 +- 7 files changed, 553 insertions(+), 8 deletions(-) create mode 100644 tests/integration/tests/with-policy/relation-many-to-many-filter.test.ts rename tests/integration/tests/with-policy/{relation-to-many-filter.test.ts => relation-one-to-many-filter.test.ts} (79%) rename tests/integration/tests/with-policy/{relation-to-one-filter.test.ts => relation-one-to-one-filter.test.ts} (99%) diff --git a/packages/runtime/src/enhancements/model-meta.ts b/packages/runtime/src/enhancements/model-meta.ts index 8109bbacc..ee480db5c 100644 --- a/packages/runtime/src/enhancements/model-meta.ts +++ b/packages/runtime/src/enhancements/model-meta.ts @@ -29,3 +29,10 @@ export function getDefaultModelMeta(): ModelMeta { export function resolveField(modelMeta: ModelMeta, model: string, field: string) { return modelMeta.fields[lowerCaseFirst(model)][field]; } + +/** + * Gets all fields of a model. + */ +export function getFields(modelMeta: ModelMeta, model: string) { + return modelMeta.fields[lowerCaseFirst(model)]; +} diff --git a/packages/runtime/src/enhancements/policy/policy-utils.ts b/packages/runtime/src/enhancements/policy/policy-utils.ts index 08d8034ae..c97fa1537 100644 --- a/packages/runtime/src/enhancements/policy/policy-utils.ts +++ b/packages/runtime/src/enhancements/policy/policy-utils.ts @@ -16,7 +16,7 @@ import { PrismaWriteActionType, } from '../../types'; import { getVersion } from '../../version'; -import { resolveField } from '../model-meta'; +import { getFields, resolveField } from '../model-meta'; import { NestedWriteVisitor, type VisitorContext } from '../nested-write-vistor'; import type { ModelMeta, PolicyDef, PolicyFunc, ZodSchemas } from '../types'; import { @@ -294,6 +294,37 @@ export class PolicyUtil { return; } + if (injectTarget._count !== undefined) { + // _count needs to respect read policies of related models + if (injectTarget._count === true) { + // include count for all relations, expand to all fields + // so that we can inject guard conditions for each of them + injectTarget._count = { select: {} }; + const modelFields = getFields(this.modelMeta, model); + if (modelFields) { + for (const [k, v] of Object.entries(modelFields)) { + if (v.isDataModel && v.isArray) { + // create an entry for to-many relation + injectTarget._count.select[k] = {}; + } + } + } + } + + // inject conditions for each relation + for (const field of Object.keys(injectTarget._count.select)) { + if (typeof injectTarget._count.select[field] !== 'object') { + injectTarget._count.select[field] = {}; + } + const fieldInfo = resolveField(this.modelMeta, model, field); + if (!fieldInfo) { + continue; + } + // inject into the "where" clause inside select + await this.injectAuthGuard(injectTarget._count.select[field], fieldInfo.type, 'read'); + } + } + const idFields = this.getIdFields(model); for (const field of getModelFields(injectTarget)) { const fieldInfo = resolveField(this.modelMeta, model, field); @@ -602,6 +633,9 @@ export class PolicyUtil { // process relation updates: connect, connectOrCreate, and disconnect const processRelationUpdate = async (model: string, args: any, context: VisitorContext) => { + // CHECK ME: equire the entity being connected readable? + // await this.checkPolicyForFilter(model, args, 'read', this.db); + if (context.field?.backLink) { // fetch the backlink field of the model being connected const backLinkField = resolveField(this.modelMeta, model, context.field.backLink); @@ -720,9 +754,9 @@ export class PolicyUtil { } } - private getModelField(model: string, backlinkField: string) { + private getModelField(model: string, field: string) { model = lowerCaseFirst(model); - return this.modelMeta.fields[model]?.[backlinkField]; + return this.modelMeta.fields[model]?.[field]; } private transaction(db: DbClientContract, action: (tx: Record) => Promise) { diff --git a/packages/schema/src/plugins/model-meta/index.ts b/packages/schema/src/plugins/model-meta/index.ts index 2198c4b43..892f57c36 100644 --- a/packages/schema/src/plugins/model-meta/index.ts +++ b/packages/schema/src/plugins/model-meta/index.ts @@ -81,7 +81,7 @@ function generateModelMetadata(dataModels: DataModel[], writer: CodeBlockWriter) isOptional: ${f.type.optional}, attributes: ${JSON.stringify(getFieldAttributes(f))}, backLink: ${backlink ? "'" + backlink.name + "'" : 'undefined'}, - isRelationOwner: ${isRelationOwner(f)}, + isRelationOwner: ${isRelationOwner(f, backlink)}, },`); } }); @@ -177,6 +177,19 @@ function getUniqueConstraints(model: DataModel) { return constraints; } -function isRelationOwner(field: DataModelField) { - return hasAttribute(field, '@relation'); +function isRelationOwner(field: DataModelField, backLink: DataModelField | undefined) { + if (!isDataModel(field.type.reference?.ref)) { + return false; + } + + if (hasAttribute(field, '@relation')) { + // this field has `@relation` attribute + return true; + } else if (!backLink || !hasAttribute(backLink, '@relation')) { + // if the opposite side field doesn't have `@relation` attribute either, + // it's an implicit many-to-many relation, both sides are owners + return true; + } else { + return false; + } } diff --git a/tests/integration/tests/with-policy/connect-disconnect.test.ts b/tests/integration/tests/with-policy/connect-disconnect.test.ts index 613b8ed53..fab86ac58 100644 --- a/tests/integration/tests/with-policy/connect-disconnect.test.ts +++ b/tests/integration/tests/with-policy/connect-disconnect.test.ts @@ -16,7 +16,9 @@ describe('With Policy: connect-disconnect', () => { model M1 { id String @id @default(uuid()) m2 M2[] + value Int @default(0) + @@deny('read', value < 0) @@allow('all', true) } @@ -49,6 +51,7 @@ describe('With Policy: connect-disconnect', () => { const db = withPolicy(); + // m1-1 -> m2-1 await db.m2.create({ data: { id: 'm2-1', value: 1, deleted: false } }); await db.m1.create({ data: { @@ -58,7 +61,9 @@ describe('With Policy: connect-disconnect', () => { }, }, }); + // mark m2-1 deleted await prisma.m2.update({ where: { id: 'm2-1' }, data: { deleted: true } }); + // disconnect denied because of violation of m2's update rule await expect( db.m1.update({ where: { id: 'm1-1' }, @@ -69,7 +74,9 @@ describe('With Policy: connect-disconnect', () => { }, }) ).toBeRejectedByPolicy(); + // reset m2-1 delete await prisma.m2.update({ where: { id: 'm2-1' }, data: { deleted: false } }); + // disconnect allowed await db.m1.update({ where: { id: 'm1-1' }, data: { @@ -79,6 +86,7 @@ describe('With Policy: connect-disconnect', () => { }, }); + // connect during create denied await db.m2.create({ data: { id: 'm2-2', value: 1, deleted: true } }); await expect( db.m1.create({ @@ -138,6 +146,21 @@ describe('With Policy: connect-disconnect', () => { }, }) ).toBeRejectedByPolicy(); + + // // connect from m2 to m1, require m1 to be readable + // await db.m2.create({ data: { id: 'm2-7', value: 1 } }); + // await prisma.m1.create({ data: { id: 'm1-2', value: -1 } }); + // // connect is denied because m1 is not readable + // await expect( + // db.m2.update({ + // where: { id: 'm2-7' }, + // data: { + // m1: { + // connect: { id: 'm1-2' }, + // }, + // }, + // }) + // ).toBeRejectedByPolicy(); }); it('nested to-many', async () => { @@ -267,4 +290,113 @@ describe('With Policy: connect-disconnect', () => { }) ).toBeRejectedByPolicy(); }); + + const modelImplicitManyToMany = ` + model M1 { + id String @id @default(uuid()) + value Int @default(0) + m2 M2[] + + @@deny('read', value < 0) + @@allow('all', true) + } + + model M2 { + id String @id @default(uuid()) + value Int + deleted Boolean @default(false) + m1 M1[] + + @@deny('read', value < 0) + @@allow('read,create', true) + @@allow('update', !deleted) + } + `; + + it('implicit many-to-many', async () => { + const { withPolicy, prisma } = await loadSchema(modelImplicitManyToMany); + + const db = withPolicy(); + + await prisma.m1.create({ data: { id: 'm1-1', value: 1 } }); + await prisma.m2.create({ data: { id: 'm2-1', value: 1 } }); + await expect( + db.m1.update({ + where: { id: 'm1-1' }, + data: { m2: { connect: { id: 'm2-1' } } }, + }) + ).toResolveTruthy(); + + await prisma.m1.create({ data: { id: 'm1-2', value: 1 } }); + await prisma.m2.create({ data: { id: 'm2-2', value: 1, deleted: true } }); + // m2-2 not updatable + await expect( + db.m1.update({ + where: { id: 'm1-2' }, + data: { m2: { connect: { id: 'm2-2' } } }, + }) + ).toBeRejectedByPolicy(); + + // await prisma.m1.create({ data: { id: 'm1-3', value: -1 } }); + // await prisma.m2.create({ data: { id: 'm2-3', value: 1 } }); + // // m1-3 not readable + // await expect( + // db.m2.update({ + // where: { id: 'm2-3' }, + // data: { m1: { connect: { id: 'm1-3' } } }, + // }) + // ).toBeRejectedByPolicy(); + }); + + const modelExplicitManyToMany = ` + model M1 { + id String @id @default(uuid()) + value Int @default(0) + m2 M1OnM2[] + + @@allow('all', true) + } + + model M2 { + id String @id @default(uuid()) + value Int + deleted Boolean @default(false) + m1 M1OnM2[] + + @@allow('read,create', true) + } + + model M1OnM2 { + m1 M1 @relation(fields: [m1Id], references: [id]) + m1Id String + m2 M2 @relation(fields: [m2Id], references: [id]) + m2Id String + + @@id([m1Id, m2Id]) + @@allow('read', true) + @@allow('create', !m2.deleted) + } + `; + + it('explicit many-to-many', async () => { + const { withPolicy, prisma } = await loadSchema(modelExplicitManyToMany); + + const db = withPolicy(); + + await prisma.m1.create({ data: { id: 'm1-1', value: 1 } }); + await prisma.m2.create({ data: { id: 'm2-1', value: 1 } }); + await expect( + db.m1OnM2.create({ + data: { m1: { connect: { id: 'm1-1' } }, m2: { connect: { id: 'm2-1' } } }, + }) + ).toResolveTruthy(); + + await prisma.m1.create({ data: { id: 'm1-2', value: 1 } }); + await prisma.m2.create({ data: { id: 'm2-2', value: 1, deleted: true } }); + await expect( + db.m1OnM2.create({ + data: { m1: { connect: { id: 'm1-2' } }, m2: { connect: { id: 'm2-2' } } }, + }) + ).toBeRejectedByPolicy(); + }); }); diff --git a/tests/integration/tests/with-policy/relation-many-to-many-filter.test.ts b/tests/integration/tests/with-policy/relation-many-to-many-filter.test.ts new file mode 100644 index 000000000..fe0c686db --- /dev/null +++ b/tests/integration/tests/with-policy/relation-many-to-many-filter.test.ts @@ -0,0 +1,296 @@ +import { loadSchema } from '@zenstackhq/testtools'; +import path from 'path'; + +describe('With Policy: relation many-to-many filter', () => { + let origDir: string; + + beforeAll(async () => { + origDir = path.resolve('.'); + }); + + afterEach(() => { + process.chdir(origDir); + }); + + const model = ` + model M1 { + id String @id @default(uuid()) + value Int + deleted Boolean @default(false) + m2 M2[] + + @@allow('read', !deleted) + @@allow('create', true) + } + + model M2 { + id String @id @default(uuid()) + value Int + deleted Boolean @default(false) + m1 M1[] + + @@allow('read', !deleted) + @@allow('create', true) + } + `; + + it('some filter', async () => { + const { withPolicy } = await loadSchema(model); + + const db = withPolicy(); + + await db.m1.create({ + data: { + id: '1', + value: 1, + m2: { + create: [ + { + id: '1', + value: 1, + }, + { + id: '2', + value: 2, + deleted: true, + }, + ], + }, + }, + }); + + // m1 -> m2 lookup + const r = await db.m1.findFirst({ + where: { + id: '1', + m2: { + some: {}, + }, + }, + include: { + _count: { select: { m2: true } }, + }, + }); + expect(r._count.m2).toBe(1); + + // m2 -> m1 lookup + await expect( + db.m2.findFirst({ + where: { + id: '1', + m1: { + some: {}, + }, + }, + }) + ).toResolveTruthy(); + + await expect( + db.m1.findFirst({ + where: { + id: '1', + m2: { + some: { value: { gt: 1 } }, + }, + }, + }) + ).toResolveFalsy(); + + // m1 with empty m2 list + await db.m1.create({ + data: { + id: '2', + value: 1, + }, + }); + + await expect( + db.m1.findFirst({ + where: { + id: '2', + m2: { + some: {}, + }, + }, + }) + ).toResolveFalsy(); + + await expect( + db.m1.findFirst({ + where: { + id: '2', + m2: { + some: { value: { gt: 1 } }, + }, + }, + }) + ).toResolveFalsy(); + }); + + it('none filter', async () => { + const { withPolicy } = await loadSchema(model); + + const db = withPolicy(); + + await db.m1.create({ + data: { + id: '1', + value: 1, + m2: { + create: [ + { id: '1', value: 1 }, + { id: '2', value: 2, deleted: true }, + ], + }, + }, + }); + + // m1 -> m2 lookup + await expect( + db.m1.findFirst({ + where: { + id: '1', + m2: { + none: {}, + }, + }, + }) + ).toResolveFalsy(); + + // m2 -> m1 lookup + await expect( + db.m2.findFirst({ + where: { + m1: { + none: {}, + }, + }, + }) + ).toResolveFalsy(); + + await expect( + db.m1.findFirst({ + where: { + id: '1', + m2: { + none: { value: { gt: 1 } }, + }, + }, + }) + ).toResolveTruthy(); + + // m1 with empty m2 list + await db.m1.create({ + data: { + id: '2', + value: 2, + }, + }); + + await expect( + db.m1.findFirst({ + where: { + id: '2', + m2: { + none: {}, + }, + }, + }) + ).toResolveTruthy(); + + await expect( + db.m1.findFirst({ + where: { + id: '2', + m2: { + none: { value: { gt: 1 } }, + }, + }, + }) + ).toResolveTruthy(); + }); + + it('every filter', async () => { + const { withPolicy } = await loadSchema(model); + + const db = withPolicy(); + + await db.m1.create({ + data: { + id: '1', + value: 1, + m2: { + create: [ + { id: '1', value: 1 }, + { id: '2', value: 2, deleted: true }, + ], + }, + }, + }); + + // m1 -> m2 lookup + await expect( + db.m1.findFirst({ + where: { + id: '1', + m2: { + every: {}, + }, + }, + }) + ).toResolveTruthy(); + + // m2 -> m1 lookup + await expect( + db.m2.findFirst({ + where: { + id: '1', + m1: { + every: {}, + }, + }, + }) + ).toResolveTruthy(); + + await expect( + db.m1.findFirst({ + where: { + id: '1', + m2: { + every: { value: { gt: 1 } }, + }, + }, + }) + ).toResolveFalsy(); + + // m1 with empty m2 list + await db.m1.create({ + data: { + id: '2', + value: 2, + }, + }); + + await expect( + db.m1.findFirst({ + where: { + id: '2', + m2: { + every: {}, + }, + }, + }) + ).toResolveTruthy(); + + await expect( + db.m1.findFirst({ + where: { + id: '2', + m2: { + every: { value: { gt: 1 } }, + }, + }, + }) + ).toResolveTruthy(); + }); +}); diff --git a/tests/integration/tests/with-policy/relation-to-many-filter.test.ts b/tests/integration/tests/with-policy/relation-one-to-many-filter.test.ts similarity index 79% rename from tests/integration/tests/with-policy/relation-to-many-filter.test.ts rename to tests/integration/tests/with-policy/relation-one-to-many-filter.test.ts index e66d35761..6ccaa6b9d 100644 --- a/tests/integration/tests/with-policy/relation-to-many-filter.test.ts +++ b/tests/integration/tests/with-policy/relation-one-to-many-filter.test.ts @@ -1,7 +1,7 @@ import { loadSchema } from '@zenstackhq/testtools'; import path from 'path'; -describe('With Policy: relation to-many filter', () => { +describe('With Policy: relation one-to-many filter', () => { let origDir: string; beforeAll(async () => { @@ -397,4 +397,67 @@ describe('With Policy: relation to-many filter', () => { }) ).toResolveTruthy(); }); + + it('_count filter', async () => { + const { withPolicy } = await loadSchema(model); + + const db = withPolicy(); + + // m1 with m2 and m3 + await db.m1.create({ + data: { + id: '1', + m2: { + create: [ + { + value: 1, + m3: { + create: { + value: 1, + }, + }, + }, + { + value: 2, + deleted: true, + m3: { + create: { + value: 2, + deleted: true, + }, + }, + }, + ], + }, + }, + }); + + await expect(db.m1.findFirst({ include: { _count: true } })).resolves.toEqual( + expect.objectContaining({ _count: { m2: 1 } }) + ); + await expect(db.m1.findFirst({ include: { _count: { select: { m2: true } } } })).resolves.toEqual( + expect.objectContaining({ _count: { m2: 1 } }) + ); + await expect( + db.m1.findFirst({ include: { _count: { select: { m2: { where: { value: { gt: 0 } } } } } } }) + ).resolves.toEqual(expect.objectContaining({ _count: { m2: 1 } })); + await expect( + db.m1.findFirst({ include: { _count: { select: { m2: { where: { value: { gt: 1 } } } } } } }) + ).resolves.toEqual(expect.objectContaining({ _count: { m2: 0 } })); + + const t = await db.m1.findFirst({ include: { m2: { select: { _count: true } } } }); + console.log(t); + + await expect(db.m1.findFirst({ include: { m2: { select: { _count: true } } } })).resolves.toEqual( + expect.objectContaining({ m2: [{ _count: { m3: 1 } }] }) + ); + await expect( + db.m1.findFirst({ include: { m2: { select: { _count: { select: { m3: true } } } } } }) + ).resolves.toEqual(expect.objectContaining({ m2: [{ _count: { m3: 1 } }] })); + await expect( + db.m1.findFirst({ + include: { m2: { select: { _count: { select: { m3: { where: { value: { gt: 1 } } } } } } } }, + }) + ).resolves.toEqual(expect.objectContaining({ m2: [{ _count: { m3: 0 } }] })); + }); }); diff --git a/tests/integration/tests/with-policy/relation-to-one-filter.test.ts b/tests/integration/tests/with-policy/relation-one-to-one-filter.test.ts similarity index 99% rename from tests/integration/tests/with-policy/relation-to-one-filter.test.ts rename to tests/integration/tests/with-policy/relation-one-to-one-filter.test.ts index d305a33d4..e77b27792 100644 --- a/tests/integration/tests/with-policy/relation-to-one-filter.test.ts +++ b/tests/integration/tests/with-policy/relation-one-to-one-filter.test.ts @@ -1,7 +1,7 @@ import { loadSchema } from '@zenstackhq/testtools'; import path from 'path'; -describe('With Policy: relation to-one filter', () => { +describe('With Policy: relation one-to-one filter', () => { let origDir: string; beforeAll(async () => { From 6abf735d287158d462eda3ceb3625a3c7dbb5389 Mon Sep 17 00:00:00 2001 From: Yiming Date: Sat, 8 Jul 2023 22:35:54 +0800 Subject: [PATCH 2/5] chore: bump version (#566) --- package.json | 2 +- packages/language/package.json | 2 +- packages/plugins/openapi/package.json | 2 +- packages/plugins/swr/package.json | 2 +- packages/plugins/tanstack-query/package.json | 2 +- packages/plugins/trpc/package.json | 2 +- packages/runtime/package.json | 2 +- packages/schema/package.json | 2 +- packages/sdk/package.json | 2 +- packages/server/package.json | 2 +- packages/testtools/package.json | 2 +- tests/integration/test-run/package-lock.json | 4 ++-- 12 files changed, 13 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index ba0bec6f5..048c8adcf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "zenstack-monorepo", - "version": "1.0.0-beta.6", + "version": "1.0.0-beta.7", "description": "", "scripts": { "build": "pnpm -r build", diff --git a/packages/language/package.json b/packages/language/package.json index b9c1320e8..a3e00f11f 100644 --- a/packages/language/package.json +++ b/packages/language/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/language", - "version": "1.0.0-beta.6", + "version": "1.0.0-beta.7", "displayName": "ZenStack modeling language compiler", "description": "ZenStack modeling language compiler", "homepage": "https://zenstack.dev", diff --git a/packages/plugins/openapi/package.json b/packages/plugins/openapi/package.json index e55ad76c1..796b74693 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.6", + "version": "1.0.0-beta.7", "description": "ZenStack plugin and runtime supporting OpenAPI", "main": "index.js", "repository": { diff --git a/packages/plugins/swr/package.json b/packages/plugins/swr/package.json index d7d01b4ba..aa7e4c806 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.6", + "version": "1.0.0-beta.7", "description": "ZenStack plugin for generating SWR hooks", "main": "index.js", "repository": { diff --git a/packages/plugins/tanstack-query/package.json b/packages/plugins/tanstack-query/package.json index 9a88355f0..45e20b4cd 100644 --- a/packages/plugins/tanstack-query/package.json +++ b/packages/plugins/tanstack-query/package.json @@ -1,7 +1,7 @@ { "name": "@zenstackhq/tanstack-query", "displayName": "ZenStack plugin for generating tanstack-query hooks", - "version": "1.0.0-beta.6", + "version": "1.0.0-beta.7", "description": "ZenStack plugin for generating tanstack-query hooks", "main": "index.js", "repository": { diff --git a/packages/plugins/trpc/package.json b/packages/plugins/trpc/package.json index ee76052ef..628d92dd6 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.6", + "version": "1.0.0-beta.7", "description": "ZenStack plugin for tRPC", "main": "index.js", "repository": { diff --git a/packages/runtime/package.json b/packages/runtime/package.json index afb5df295..7be271206 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.6", + "version": "1.0.0-beta.7", "description": "Runtime of ZenStack for both client-side and server-side environments.", "repository": { "type": "git", diff --git a/packages/schema/package.json b/packages/schema/package.json index 749c8abd8..6cbe0ce5f 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.6", + "version": "1.0.0-beta.7", "author": { "name": "ZenStack Team" }, diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 9a72cb290..6f10158ec 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/sdk", - "version": "1.0.0-beta.6", + "version": "1.0.0-beta.7", "description": "ZenStack plugin development SDK", "main": "index.js", "scripts": { diff --git a/packages/server/package.json b/packages/server/package.json index 261ce51eb..38e929bb7 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/server", - "version": "1.0.0-beta.6", + "version": "1.0.0-beta.7", "displayName": "ZenStack Server-side Adapters", "description": "ZenStack server-side adapters", "homepage": "https://zenstack.dev", diff --git a/packages/testtools/package.json b/packages/testtools/package.json index 563ee75ff..b74d7c7bd 100644 --- a/packages/testtools/package.json +++ b/packages/testtools/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/testtools", - "version": "1.0.0-beta.6", + "version": "1.0.0-beta.7", "description": "ZenStack Test Tools", "main": "index.js", "publishConfig": { diff --git a/tests/integration/test-run/package-lock.json b/tests/integration/test-run/package-lock.json index d002970f9..d0b7f99b5 100644 --- a/tests/integration/test-run/package-lock.json +++ b/tests/integration/test-run/package-lock.json @@ -126,7 +126,7 @@ }, "../../../packages/runtime/dist": { "name": "@zenstackhq/runtime", - "version": "1.0.0-beta.6", + "version": "1.0.0-beta.7", "license": "MIT", "dependencies": { "@paralleldrive/cuid2": "^2.2.0", @@ -160,7 +160,7 @@ }, "../../../packages/schema/dist": { "name": "zenstack", - "version": "1.0.0-beta.6", + "version": "1.0.0-beta.7", "hasInstallScript": true, "license": "MIT", "dependencies": { From 858b075ca193ae26673aaefc052cc7c029a26c08 Mon Sep 17 00:00:00 2001 From: Yiming Date: Sun, 9 Jul 2023 10:09:41 +0800 Subject: [PATCH 3/5] fix: zod schema compilation errors in pnpm environment due to peer dependencies (#568) --- packages/runtime/package.json | 4 +- packages/schema/package.json | 3 - pnpm-lock.yaml | 270 ++++++++++++++++++++-------------- 3 files changed, 158 insertions(+), 119 deletions(-) diff --git a/packages/runtime/package.json b/packages/runtime/package.json index 7be271206..612e57b5e 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -37,15 +37,13 @@ "zod": "3.21.1", "zod-validation-error": "^0.2.1" }, - "peerDependencies": { - "@prisma/client": "^4.0.0" - }, "author": { "name": "ZenStack Team" }, "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", diff --git a/packages/schema/package.json b/packages/schema/package.json index 6cbe0ce5f..4fdc36d12 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -78,9 +78,6 @@ "publish-dev": "pnpm publish --registry http://localhost:4873", "postinstall": "node bin/post-install.js" }, - "peerDependencies": { - "prisma": "^4.0.0" - }, "dependencies": { "@paralleldrive/cuid2": "^2.2.0", "@prisma/generator-helper": "4.10.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c5d53b1bd..2ab2d41cb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,4 +1,4 @@ -lockfileVersion: '6.1' +lockfileVersion: '6.0' settings: autoInstallPeers: true @@ -103,7 +103,7 @@ importers: version: 8.35.0 jest: specifier: ^29.5.0 - version: 29.5.0(@types/node@14.18.29)(ts-node@10.9.1) + version: 29.5.0 pluralize: specifier: ^8.0.0 version: 8.0.0 @@ -177,7 +177,7 @@ importers: version: 2.4.1 jest: specifier: ^29.5.0 - version: 29.5.0(@types/node@14.18.29)(ts-node@10.9.1) + version: 29.5.0 react: specifier: ^17.0.2 || ^18 version: 17.0.2 @@ -254,7 +254,7 @@ importers: version: 2.4.1 jest: specifier: ^29.5.0 - version: 29.5.0(@types/node@14.18.29)(ts-node@10.9.1) + version: 29.5.0 react: specifier: ^17.0.2 || ^18 version: 17.0.2 @@ -334,7 +334,7 @@ importers: version: 2.4.1 jest: specifier: ^29.5.0 - version: 29.5.0(@types/node@14.18.29)(ts-node@10.9.1) + version: 29.5.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) @@ -354,9 +354,6 @@ importers: '@paralleldrive/cuid2': specifier: ^2.2.0 version: 2.2.0 - '@prisma/client': - specifier: ^4.0.0 - version: 4.0.0 '@types/bcryptjs': specifier: ^2.4.2 version: 2.4.2 @@ -397,6 +394,9 @@ 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 @@ -681,7 +681,7 @@ importers: devDependencies: '@sveltejs/kit': specifier: 1.21.0 - version: 1.21.0(svelte@4.0.0-next.3)(vite@4.3.9) + version: 1.21.0(svelte@3.59.2)(vite@4.3.9) '@types/body-parser': specifier: ^1.19.2 version: 1.19.2 @@ -723,7 +723,7 @@ importers: version: 3.0.0 jest: specifier: ^29.5.0 - version: 29.5.0(@types/node@14.18.29)(ts-node@10.9.1) + version: 29.5.0 next: specifier: ^13.4.5 version: 13.4.5(@babel/core@7.22.5)(react-dom@18.2.0)(react@18.2.0) @@ -847,7 +847,7 @@ importers: version: 8.30.0 eslint-plugin-jest: specifier: ^27.1.7 - version: 27.1.7(@typescript-eslint/eslint-plugin@5.42.0)(eslint@8.27.0)(jest@29.5.0)(typescript@4.8.4) + version: 27.1.7(eslint@8.30.0)(jest@29.5.0)(typescript@4.6.2) fs-extra: specifier: ^11.1.0 version: 11.1.0 @@ -1679,6 +1679,16 @@ packages: eslint-visitor-keys: 3.4.1 dev: true + /@eslint-community/eslint-utils@4.4.0(eslint@8.30.0): + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 8.30.0 + eslint-visitor-keys: 3.4.1 + dev: true + /@eslint/eslintrc@1.4.1: resolution: {integrity: sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2458,7 +2468,7 @@ packages: optional: true dependencies: '@prisma/engines-version': 3.16.0-49.da41d2bb3406da22087b849f0e911199ba4fbf11 - dev: false + dev: true /@prisma/client@4.7.0(prisma@4.7.0): resolution: {integrity: sha512-keXMa0oJWJGOzMEFKp+CEgzJPwnOtGSrnTWw6qMYxnypYrRFdNxqyA06EzELZexBhgM4oLooZ1jDJ3iy46wExA==} @@ -2506,7 +2516,7 @@ packages: /@prisma/engines-version@3.16.0-49.da41d2bb3406da22087b849f0e911199ba4fbf11: resolution: {integrity: sha512-PiZhdD624SrYEjyLboI0X7OugNbxUzDJx9v/6ldTKuqNDVUCmRH/Z00XwDi/dgM4FlqOSO+YiUsSiSKjxxG8cw==} - dev: false + dev: true /@prisma/engines-version@4.7.0-74.39190b250ebc338586e25e6da45e5e783bc8a635: resolution: {integrity: sha512-ImczGEQ8NS1OUApEeyAGxC4uLTtQp0wI1+2wM4MeQLVwIQbyMHk1vOhWWE8Pwbi3rnzLcPvsIrd9sm6oNXhERw==} @@ -2685,7 +2695,7 @@ packages: '@sinonjs/commons': 3.0.0 dev: true - /@sveltejs/kit@1.21.0(svelte@4.0.0-next.3)(vite@4.3.9): + /@sveltejs/kit@1.21.0(svelte@3.59.2)(vite@4.3.9): resolution: {integrity: sha512-CBsYoI34SjtOQp0eG85dmVnvTR3Pjs8VgAQhO0CgQja9BIorKl808F1X8EunPhCcyek5r5lKQE1Mmbi0RuzHqA==} engines: {node: ^16.14 || >=18} hasBin: true @@ -2694,7 +2704,7 @@ packages: svelte: ^3.54.0 || ^4.0.0-next.0 vite: ^4.0.0 dependencies: - '@sveltejs/vite-plugin-svelte': 2.4.2(svelte@4.0.0-next.3)(vite@4.3.9) + '@sveltejs/vite-plugin-svelte': 2.4.2(svelte@3.59.2)(vite@4.3.9) '@types/cookie': 0.5.1 cookie: 0.5.0 devalue: 4.3.2 @@ -2705,14 +2715,14 @@ packages: sade: 1.8.1 set-cookie-parser: 2.6.0 sirv: 2.0.3 - svelte: 4.0.0-next.3 + svelte: 3.59.2 undici: 5.22.1 vite: 4.3.9(@types/node@14.18.32) transitivePeerDependencies: - supports-color dev: true - /@sveltejs/vite-plugin-svelte-inspector@1.0.3(@sveltejs/vite-plugin-svelte@2.4.2)(svelte@4.0.0-next.3)(vite@4.3.9): + /@sveltejs/vite-plugin-svelte-inspector@1.0.3(@sveltejs/vite-plugin-svelte@2.4.2)(svelte@3.59.2)(vite@4.3.9): resolution: {integrity: sha512-Khdl5jmmPN6SUsVuqSXatKpQTMIifoQPDanaxC84m9JxIibWvSABJyHpyys0Z+1yYrxY5TTEQm+6elh0XCMaOA==} engines: {node: ^14.18.0 || >= 16} peerDependencies: @@ -2720,28 +2730,28 @@ packages: svelte: ^3.54.0 || ^4.0.0 vite: ^4.0.0 dependencies: - '@sveltejs/vite-plugin-svelte': 2.4.2(svelte@4.0.0-next.3)(vite@4.3.9) + '@sveltejs/vite-plugin-svelte': 2.4.2(svelte@3.59.2)(vite@4.3.9) debug: 4.3.4 - svelte: 4.0.0-next.3 + svelte: 3.59.2 vite: 4.3.9(@types/node@14.18.32) transitivePeerDependencies: - supports-color dev: true - /@sveltejs/vite-plugin-svelte@2.4.2(svelte@4.0.0-next.3)(vite@4.3.9): + /@sveltejs/vite-plugin-svelte@2.4.2(svelte@3.59.2)(vite@4.3.9): 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@4.0.0-next.3)(vite@4.3.9) + '@sveltejs/vite-plugin-svelte-inspector': 1.0.3(@sveltejs/vite-plugin-svelte@2.4.2)(svelte@3.59.2)(vite@4.3.9) debug: 4.3.4 deepmerge: 4.3.1 kleur: 4.1.5 magic-string: 0.30.0 - svelte: 4.0.0-next.3 - svelte-hmr: 0.15.2(svelte@4.0.0-next.3) + 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) transitivePeerDependencies: @@ -2996,10 +3006,6 @@ packages: dependencies: '@types/ms': 0.7.31 - /@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: @@ -3449,6 +3455,27 @@ packages: - supports-color dev: true + /@typescript-eslint/typescript-estree@5.60.1(typescript@4.6.2): + resolution: {integrity: sha512-hkX70J9+2M2ZT6fhti5Q2FoU9zb+GeZK2SLP1WZlvUDqdMbEKhexZODD1WodNRyO8eS+4nScvT0dts8IdaBzfw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 5.60.1 + '@typescript-eslint/visitor-keys': 5.60.1 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.3.8 + tsutils: 3.21.0(typescript@4.6.2) + typescript: 4.6.2 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/typescript-estree@5.60.1(typescript@4.8.4): resolution: {integrity: sha512-hkX70J9+2M2ZT6fhti5Q2FoU9zb+GeZK2SLP1WZlvUDqdMbEKhexZODD1WodNRyO8eS+4nScvT0dts8IdaBzfw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -3530,6 +3557,26 @@ packages: - typescript dev: true + /@typescript-eslint/utils@5.60.1(eslint@8.30.0)(typescript@4.6.2): + resolution: {integrity: sha512-tiJ7FFdFQOWssFa3gqb94Ilexyw0JVxj6vBzaSpfN/8IhoKkDuSAenUKvsSHw2A/TMpJb26izIszTXaqygkvpQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.30.0) + '@types/json-schema': 7.0.12 + '@types/semver': 7.3.13 + '@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 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + /@typescript-eslint/visitor-keys@5.42.0: resolution: {integrity: sha512-QHbu5Hf/2lOEOwy+IUw0GoSCuAzByTAWWrOTKzTzsotiUnWFpuKnXcAhC9YztAf2EElQ0VvIK+pHJUPkM0q7jg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -3805,12 +3852,6 @@ 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'} @@ -3900,12 +3941,6 @@ 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: @@ -4416,16 +4451,6 @@ 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.9.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 @@ -4659,14 +4684,6 @@ 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'} @@ -4830,11 +4847,6 @@ 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} @@ -5340,6 +5352,27 @@ packages: - typescript dev: true + /eslint-plugin-jest@27.1.7(eslint@8.30.0)(jest@29.5.0)(typescript@4.6.2): + resolution: {integrity: sha512-0QVzf+og4YI1Qr3UoprkqqhezAZjFffdi62b0IurkCXMqPtRW84/UT4CKsYT80h/D82LA9avjO/80Ou1LdgbaQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@typescript-eslint/eslint-plugin': ^5.0.0 + eslint: ^7.0.0 || ^8.0.0 + jest: '*' + peerDependenciesMeta: + '@typescript-eslint/eslint-plugin': + optional: true + jest: + optional: true + 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) + transitivePeerDependencies: + - supports-color + - typescript + dev: true + /eslint-scope@5.1.1: resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} engines: {node: '>=8.0.0'} @@ -5584,12 +5617,6 @@ 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'} @@ -6524,12 +6551,6 @@ 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'} @@ -6711,6 +6732,34 @@ 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): resolution: {integrity: sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -7142,6 +7191,26 @@ packages: 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 + dev: true + /jest@29.5.0(@types/node@14.18.29)(ts-node@10.9.1): resolution: {integrity: sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -7368,10 +7437,6 @@ 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'} @@ -7512,10 +7577,6 @@ 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 @@ -8207,14 +8268,6 @@ 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 @@ -9402,13 +9455,13 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - /svelte-hmr@0.15.2(svelte@4.0.0-next.3): + /svelte-hmr@0.15.2(svelte@3.59.2): 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: 4.0.0-next.3 + svelte: 3.59.2 dev: true /svelte@3.59.2: @@ -9416,25 +9469,6 @@ packages: engines: {node: '>= 8'} dev: true - /svelte@4.0.0-next.3: - resolution: {integrity: sha512-NogP/EuGk+xCzqye8hoj/Wz1OoTCTp1yQpsfAIkATlYct2xqoQADB1UjPLm/plQjhGQrZcODW2MHCiYsDTQWtA==} - engines: {node: '>=16'} - dependencies: - '@ampproject/remapping': 2.2.1 - '@jridgewell/sourcemap-codec': 1.4.15 - '@jridgewell/trace-mapping': 0.3.18 - acorn: 8.9.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.0 - periscopic: 3.1.0 - dev: true - /swr@2.0.3(react@17.0.2): resolution: {integrity: sha512-sGvQDok/AHEWTPfhUWXEHBVEXmgGnuahyhmRQbjl9XBYxT/MSlAzvXEKQpyM++bMPaI52vcWS2HiKNaW7+9OFw==} engines: {pnpm: '7'} @@ -9712,7 +9746,7 @@ packages: '@babel/core': 7.22.5 bs-logger: 0.2.6 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 jest-util: 29.5.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -9746,7 +9780,7 @@ packages: '@babel/core': 7.22.5 bs-logger: 0.2.6 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 jest-util: 29.5.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -9853,6 +9887,16 @@ packages: /tslib@2.6.0: resolution: {integrity: sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==} + /tsutils@3.21.0(typescript@4.6.2): + resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} + engines: {node: '>= 6'} + peerDependencies: + typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + dependencies: + tslib: 1.14.1 + typescript: 4.6.2 + dev: true + /tsutils@3.21.0(typescript@4.8.4): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} From bd5666ae03110392e0fc578e37c6fcddba9cf50d Mon Sep 17 00:00:00 2001 From: Yiming Date: Sun, 9 Jul 2023 11:38:25 +0800 Subject: [PATCH 4/5] fix: add "interactiveTransactions" preview features for lower version of Prisma (#569) --- .../src/plugins/prisma/schema-generator.ts | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/packages/schema/src/plugins/prisma/schema-generator.ts b/packages/schema/src/plugins/prisma/schema-generator.ts index 7130b0a7b..81c01f874 100644 --- a/packages/schema/src/plugins/prisma/schema-generator.ts +++ b/packages/schema/src/plugins/prisma/schema-generator.ts @@ -36,6 +36,7 @@ import { import fs from 'fs'; import { writeFile } from 'fs/promises'; import path from 'path'; +import semver from 'semver'; import stripColor from 'strip-color'; import { name } from '.'; import { getStringLiteral } from '../../language-server/validator/utils'; @@ -236,14 +237,43 @@ 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) { - prisma.addGenerator( + const generator = prisma.addGenerator( decl.name, decl.fields.map((f) => { const value = isArrayExpr(f.value) ? getLiteralArray(f.value) : getLiteral(f.value); return { name: f.name, value }; }) ); + + // 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(); + if (prismaVersion && semver.lt(prismaVersion, '4.7.0')) { + // insert interactiveTransactions preview feature + let previewFeatures = generator.fields.find((f) => f.name === 'previewFeatures'); + if (!previewFeatures) { + previewFeatures = { name: 'previewFeatures', value: [] }; + generator.fields.push(previewFeatures); + } + if (!Array.isArray(previewFeatures.value)) { + throw new PluginError(name, 'option "previewFeatures" must be an array'); + } + if (!previewFeatures.value.includes('interactiveTransactions')) { + previewFeatures.value.push('interactiveTransactions'); + } + } + } } private generateModel(prisma: PrismaModel, decl: DataModel, config?: Record) { From 1e1ad8fe161e834ca5903fc806b67a9b4e5eb0f2 Mon Sep 17 00:00:00 2001 From: Yiming Date: Sun, 9 Jul 2023 11:44:02 +0800 Subject: [PATCH 5/5] chore: unify zod versions in tests (#571) --- .../nextjs/test-project/package-lock.json | 6 ++++-- .../tests/nextjs/test-project/package.json | 2 +- .../tests/trpc/test-project/package-lock.json | 21 +++++++++++++------ 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/tests/integration/tests/nextjs/test-project/package-lock.json b/tests/integration/tests/nextjs/test-project/package-lock.json index a361d4333..d7b1be834 100644 --- a/tests/integration/tests/nextjs/test-project/package-lock.json +++ b/tests/integration/tests/nextjs/test-project/package-lock.json @@ -19,7 +19,7 @@ "react-dom": "18.2.0", "swr": "^2.2.0", "typescript": "4.9.4", - "zod": "^3.21.1" + "zod": "3.21.1" }, "devDependencies": { "prisma": "^4.7.0" @@ -27,7 +27,9 @@ }, "../../../../../../packages/plugins/swr/dist": {}, "../../../../../../packages/runtime/dist": {}, - "../../../../../../packages/server/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", diff --git a/tests/integration/tests/nextjs/test-project/package.json b/tests/integration/tests/nextjs/test-project/package.json index 81332055d..e9fc87b33 100644 --- a/tests/integration/tests/nextjs/test-project/package.json +++ b/tests/integration/tests/nextjs/test-project/package.json @@ -20,7 +20,7 @@ "react-dom": "18.2.0", "swr": "^2.2.0", "typescript": "4.9.4", - "zod": "^3.21.1" + "zod": "3.21.1" }, "devDependencies": { "prisma": "^4.7.0" diff --git a/tests/integration/tests/trpc/test-project/package-lock.json b/tests/integration/tests/trpc/test-project/package-lock.json index 384172430..f3f74a713 100644 --- a/tests/integration/tests/trpc/test-project/package-lock.json +++ b/tests/integration/tests/trpc/test-project/package-lock.json @@ -17,6 +17,7 @@ "@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", @@ -28,6 +29,7 @@ "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", @@ -378,6 +380,10 @@ "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", @@ -657,9 +663,9 @@ } }, "node_modules/zod": { - "version": "3.20.2", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.20.2.tgz", - "integrity": "sha512-1MzNQdAvO+54H+EaK5YpyEy0T+Ejo/7YLHS93G3RnYWh5gaotGHwGeN/ZO687qEDU2y4CdStQYXVHIgrUl5UVQ==", + "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" } @@ -848,6 +854,9 @@ "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", @@ -1012,9 +1021,9 @@ "requires": {} }, "zod": { - "version": "3.20.2", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.20.2.tgz", - "integrity": "sha512-1MzNQdAvO+54H+EaK5YpyEy0T+Ejo/7YLHS93G3RnYWh5gaotGHwGeN/ZO687qEDU2y4CdStQYXVHIgrUl5UVQ==" + "version": "3.21.1", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.1.tgz", + "integrity": "sha512-+dTu2m6gmCbO9Ahm4ZBDapx2O6ZY9QSPXst2WXjcznPMwf2YNpn3RevLx4KkZp1OPW/ouFcoBtBzFz/LeY69oA==" } } }