zenstack 1.0.0 → 1.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (264) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +126 -1
  3. package/bin/cli +3 -0
  4. package/bin/post-install.js +24 -0
  5. package/cli/cli-error.d.ts +5 -0
  6. package/cli/cli-error.js +10 -0
  7. package/cli/cli-error.js.map +1 -0
  8. package/cli/cli-util.d.ts +18 -0
  9. package/cli/cli-util.js +143 -0
  10. package/cli/cli-util.js.map +1 -0
  11. package/cli/index.d.ts +15 -0
  12. package/cli/index.js +121 -0
  13. package/cli/index.js.map +1 -0
  14. package/cli/plugin-runner.d.ts +14 -0
  15. package/cli/plugin-runner.js +145 -0
  16. package/cli/plugin-runner.js.map +1 -0
  17. package/constants.d.ts +1 -0
  18. package/constants.js +6 -0
  19. package/constants.js.map +1 -0
  20. package/language-server/constants.d.ts +15 -0
  21. package/language-server/constants.js +20 -0
  22. package/language-server/constants.js.map +1 -0
  23. package/language-server/main.d.ts +1 -0
  24. package/language-server/main.js +13 -0
  25. package/language-server/main.js.map +1 -0
  26. package/language-server/types.d.ts +10 -0
  27. package/language-server/types.js +3 -0
  28. package/language-server/types.js.map +1 -0
  29. package/language-server/utils.d.ts +18 -0
  30. package/language-server/utils.js +58 -0
  31. package/language-server/utils.js.map +1 -0
  32. package/language-server/validator/attribute-validator.d.ts +9 -0
  33. package/language-server/validator/attribute-validator.js +11 -0
  34. package/language-server/validator/attribute-validator.js.map +1 -0
  35. package/language-server/validator/datamodel-validator.d.ts +15 -0
  36. package/language-server/validator/datamodel-validator.js +278 -0
  37. package/language-server/validator/datamodel-validator.js.map +1 -0
  38. package/language-server/validator/datasource-validator.d.ts +12 -0
  39. package/language-server/validator/datasource-validator.js +66 -0
  40. package/language-server/validator/datasource-validator.js.map +1 -0
  41. package/language-server/validator/enum-validator.d.ts +11 -0
  42. package/language-server/validator/enum-validator.js +28 -0
  43. package/language-server/validator/enum-validator.js.map +1 -0
  44. package/language-server/validator/expression-validator.d.ts +10 -0
  45. package/language-server/validator/expression-validator.js +30 -0
  46. package/language-server/validator/expression-validator.js.map +1 -0
  47. package/language-server/validator/schema-validator.d.ts +10 -0
  48. package/language-server/validator/schema-validator.js +28 -0
  49. package/language-server/validator/schema-validator.js.map +1 -0
  50. package/language-server/validator/utils.d.ts +25 -0
  51. package/language-server/validator/utils.js +257 -0
  52. package/language-server/validator/utils.js.map +1 -0
  53. package/language-server/validator/zmodel-validator.d.ts +21 -0
  54. package/language-server/validator/zmodel-validator.js +69 -0
  55. package/language-server/validator/zmodel-validator.js.map +1 -0
  56. package/language-server/zmodel-code-action.d.ts +14 -0
  57. package/language-server/zmodel-code-action.js +93 -0
  58. package/language-server/zmodel-code-action.js.map +1 -0
  59. package/language-server/zmodel-formatter.d.ts +9 -0
  60. package/language-server/zmodel-formatter.js +76 -0
  61. package/language-server/zmodel-formatter.js.map +1 -0
  62. package/language-server/zmodel-linker.d.ts +29 -0
  63. package/language-server/zmodel-linker.js +366 -0
  64. package/language-server/zmodel-linker.js.map +1 -0
  65. package/language-server/zmodel-module.d.ts +41 -0
  66. package/language-server/zmodel-module.js +80 -0
  67. package/language-server/zmodel-module.js.map +1 -0
  68. package/language-server/zmodel-scope.d.ts +10 -0
  69. package/language-server/zmodel-scope.js +44 -0
  70. package/language-server/zmodel-scope.js.map +1 -0
  71. package/language-server/zmodel-workspace-manager.d.ts +8 -0
  72. package/language-server/zmodel-workspace-manager.js +37 -0
  73. package/language-server/zmodel-workspace-manager.js.map +1 -0
  74. package/package.json +133 -8
  75. package/plugins/access-policy/expression-writer.d.ts +39 -0
  76. package/plugins/access-policy/expression-writer.js +361 -0
  77. package/plugins/access-policy/expression-writer.js.map +1 -0
  78. package/plugins/access-policy/index.d.ts +4 -0
  79. package/plugins/access-policy/index.js +24 -0
  80. package/plugins/access-policy/index.js.map +1 -0
  81. package/plugins/access-policy/policy-guard-generator.d.ts +15 -0
  82. package/plugins/access-policy/policy-guard-generator.js +349 -0
  83. package/plugins/access-policy/policy-guard-generator.js.map +1 -0
  84. package/plugins/access-policy/typescript-expression-transformer.d.ts +26 -0
  85. package/plugins/access-policy/typescript-expression-transformer.js +111 -0
  86. package/plugins/access-policy/typescript-expression-transformer.js.map +1 -0
  87. package/plugins/access-policy/utils.d.ts +5 -0
  88. package/plugins/access-policy/utils.js +14 -0
  89. package/plugins/access-policy/utils.js.map +1 -0
  90. package/plugins/access-policy/zod-schema-generator.d.ts +12 -0
  91. package/plugins/access-policy/zod-schema-generator.js +158 -0
  92. package/plugins/access-policy/zod-schema-generator.js.map +1 -0
  93. package/plugins/model-meta/index.d.ts +4 -0
  94. package/plugins/model-meta/index.js +168 -0
  95. package/plugins/model-meta/index.js.map +1 -0
  96. package/plugins/plugin-utils.d.ts +16 -0
  97. package/plugins/plugin-utils.js +54 -0
  98. package/plugins/plugin-utils.js.map +1 -0
  99. package/plugins/prisma/indent-string.d.ts +4 -0
  100. package/plugins/prisma/indent-string.js +12 -0
  101. package/plugins/prisma/indent-string.js.map +1 -0
  102. package/plugins/prisma/index.d.ts +4 -0
  103. package/plugins/prisma/index.js +24 -0
  104. package/plugins/prisma/index.js.map +1 -0
  105. package/plugins/prisma/prisma-builder.d.ts +152 -0
  106. package/plugins/prisma/prisma-builder.js +363 -0
  107. package/plugins/prisma/prisma-builder.js.map +1 -0
  108. package/plugins/prisma/schema-generator.d.ts +25 -0
  109. package/plugins/prisma/schema-generator.js +292 -0
  110. package/plugins/prisma/schema-generator.js.map +1 -0
  111. package/plugins/prisma/zmodel-code-generator.d.ts +28 -0
  112. package/plugins/prisma/zmodel-code-generator.js +114 -0
  113. package/plugins/prisma/zmodel-code-generator.js.map +1 -0
  114. package/res/prism-zmodel.js +20 -0
  115. package/res/starter.zmodel +51 -0
  116. package/res/stdlib.zmodel +346 -0
  117. package/telemetry.d.ts +20 -0
  118. package/telemetry.js +119 -0
  119. package/telemetry.js.map +1 -0
  120. package/types.d.ts +12 -0
  121. package/types.js +3 -0
  122. package/types.js.map +1 -0
  123. package/utils/ast-utils.d.ts +16 -0
  124. package/utils/ast-utils.js +85 -0
  125. package/utils/ast-utils.js.map +1 -0
  126. package/utils/exec-utils.d.ts +6 -0
  127. package/utils/exec-utils.js +13 -0
  128. package/utils/exec-utils.js.map +1 -0
  129. package/utils/pkg-utils.d.ts +3 -0
  130. package/utils/pkg-utils.js +46 -0
  131. package/utils/pkg-utils.js.map +1 -0
  132. package/utils/version-utils.d.ts +1 -0
  133. package/utils/version-utils.js +14 -0
  134. package/utils/version-utils.js.map +1 -0
  135. package/.vscode/extensions.json +0 -7
  136. package/.vscode/launch.json +0 -49
  137. package/.vscode/settings.json +0 -4
  138. package/packages/internal/jest.config.ts +0 -32
  139. package/packages/internal/package.json +0 -42
  140. package/packages/internal/src/constants.ts +0 -1
  141. package/packages/internal/src/handler/data/guard-utils.ts +0 -7
  142. package/packages/internal/src/handler/data/handler.ts +0 -415
  143. package/packages/internal/src/handler/data/query-processor.ts +0 -504
  144. package/packages/internal/src/handler/index.ts +0 -1
  145. package/packages/internal/src/handler/types.ts +0 -20
  146. package/packages/internal/src/index.ts +0 -3
  147. package/packages/internal/src/request-handler.ts +0 -27
  148. package/packages/internal/src/request.ts +0 -101
  149. package/packages/internal/src/types.ts +0 -40
  150. package/packages/internal/tests/query-processor.test.ts +0 -172
  151. package/packages/internal/tsconfig.json +0 -21
  152. package/packages/runtime/auth.d.ts +0 -1
  153. package/packages/runtime/auth.js +0 -3
  154. package/packages/runtime/hooks.d.ts +0 -10
  155. package/packages/runtime/hooks.js +0 -3
  156. package/packages/runtime/index.d.ts +0 -3
  157. package/packages/runtime/index.js +0 -1
  158. package/packages/runtime/package-lock.json +0 -512
  159. package/packages/runtime/package.json +0 -16
  160. package/packages/runtime/server.d.ts +0 -1
  161. package/packages/runtime/server.js +0 -3
  162. package/packages/runtime/types.d.ts +0 -1
  163. package/packages/runtime/types.js +0 -3
  164. package/packages/schema/.eslintrc.json +0 -13
  165. package/packages/schema/.vscodeignore +0 -4
  166. package/packages/schema/asset/logo-dark.png +0 -0
  167. package/packages/schema/asset/logo-light.png +0 -0
  168. package/packages/schema/bin/cli +0 -3
  169. package/packages/schema/jest.config.ts +0 -32
  170. package/packages/schema/langium-config.json +0 -14
  171. package/packages/schema/langium-quickstart.md +0 -41
  172. package/packages/schema/language-configuration.json +0 -30
  173. package/packages/schema/package.json +0 -96
  174. package/packages/schema/src/cli/cli-util.ts +0 -80
  175. package/packages/schema/src/cli/index.ts +0 -64
  176. package/packages/schema/src/extension.ts +0 -76
  177. package/packages/schema/src/generator/constants.ts +0 -5
  178. package/packages/schema/src/generator/index.ts +0 -92
  179. package/packages/schema/src/generator/next-auth/index.ts +0 -197
  180. package/packages/schema/src/generator/package.template.json +0 -9
  181. package/packages/schema/src/generator/prisma/expression-writer.ts +0 -352
  182. package/packages/schema/src/generator/prisma/index.ts +0 -32
  183. package/packages/schema/src/generator/prisma/plain-expression-builder.ts +0 -91
  184. package/packages/schema/src/generator/prisma/prisma-builder.ts +0 -366
  185. package/packages/schema/src/generator/prisma/query-gard-generator.ts +0 -208
  186. package/packages/schema/src/generator/prisma/schema-generator.ts +0 -300
  187. package/packages/schema/src/generator/react-hooks/index.ts +0 -181
  188. package/packages/schema/src/generator/service/index.ts +0 -107
  189. package/packages/schema/src/generator/tsconfig.template.json +0 -17
  190. package/packages/schema/src/generator/types.ts +0 -17
  191. package/packages/schema/src/generator/utils.ts +0 -9
  192. package/packages/schema/src/language-server/generated/ast.ts +0 -603
  193. package/packages/schema/src/language-server/generated/grammar.ts +0 -2190
  194. package/packages/schema/src/language-server/generated/module.ts +0 -24
  195. package/packages/schema/src/language-server/main.ts +0 -12
  196. package/packages/schema/src/language-server/stdlib.zmodel +0 -22
  197. package/packages/schema/src/language-server/types.ts +0 -9
  198. package/packages/schema/src/language-server/zmodel-index.ts +0 -33
  199. package/packages/schema/src/language-server/zmodel-linker.ts +0 -409
  200. package/packages/schema/src/language-server/zmodel-module.ts +0 -90
  201. package/packages/schema/src/language-server/zmodel-scope.ts +0 -21
  202. package/packages/schema/src/language-server/zmodel-validator.ts +0 -35
  203. package/packages/schema/src/language-server/zmodel.langium +0 -186
  204. package/packages/schema/src/utils/exec-utils.ts +0 -5
  205. package/packages/schema/src/utils/indent-string.ts +0 -6
  206. package/packages/schema/syntaxes/zmodel.json +0 -57
  207. package/packages/schema/syntaxes/zmodel.tmLanguage.json +0 -57
  208. package/packages/schema/tests/generator/expression-writer.test.ts +0 -676
  209. package/packages/schema/tests/generator/prisma-builder.test.ts +0 -138
  210. package/packages/schema/tests/schema/parser.test.ts +0 -423
  211. package/packages/schema/tests/schema/sample-todo.test.ts +0 -14
  212. package/packages/schema/tests/utils.ts +0 -38
  213. package/packages/schema/tsconfig.json +0 -23
  214. package/pnpm-workspace.yaml +0 -3
  215. package/samples/todo/.env +0 -2
  216. package/samples/todo/.eslintrc.json +0 -3
  217. package/samples/todo/.vscode/launch.json +0 -11
  218. package/samples/todo/README.md +0 -34
  219. package/samples/todo/components/AuthGuard.tsx +0 -17
  220. package/samples/todo/components/Avatar.tsx +0 -22
  221. package/samples/todo/components/BreadCrumb.tsx +0 -44
  222. package/samples/todo/components/ManageMembers.tsx +0 -134
  223. package/samples/todo/components/NavBar.tsx +0 -57
  224. package/samples/todo/components/SpaceMembers.tsx +0 -76
  225. package/samples/todo/components/Spaces.tsx +0 -28
  226. package/samples/todo/components/TimeInfo.tsx +0 -17
  227. package/samples/todo/components/Todo.tsx +0 -72
  228. package/samples/todo/components/TodoList.tsx +0 -77
  229. package/samples/todo/lib/context.ts +0 -31
  230. package/samples/todo/next.config.js +0 -10
  231. package/samples/todo/package-lock.json +0 -7527
  232. package/samples/todo/package.json +0 -45
  233. package/samples/todo/pages/_app.tsx +0 -50
  234. package/samples/todo/pages/api/auth/[...nextauth].ts +0 -83
  235. package/samples/todo/pages/api/zenstack/[...path].ts +0 -16
  236. package/samples/todo/pages/create-space.tsx +0 -114
  237. package/samples/todo/pages/index.tsx +0 -32
  238. package/samples/todo/pages/space/[slug]/[listId]/index.tsx +0 -88
  239. package/samples/todo/pages/space/[slug]/index.tsx +0 -169
  240. package/samples/todo/postcss.config.js +0 -6
  241. package/samples/todo/public/avatar.jpg +0 -0
  242. package/samples/todo/public/favicon.ico +0 -0
  243. package/samples/todo/public/logo.png +0 -0
  244. package/samples/todo/public/vercel.svg +0 -4
  245. package/samples/todo/styles/globals.css +0 -7
  246. package/samples/todo/tailwind.config.js +0 -11
  247. package/samples/todo/tsconfig.json +0 -28
  248. package/samples/todo/types/next-auth.d.ts +0 -14
  249. package/samples/todo/types/next.d.ts +0 -16
  250. package/samples/todo/zenstack/migrations/20221014084317_init/migration.sql +0 -153
  251. package/samples/todo/zenstack/migrations/20221020094651_upate_cli/migration.sql +0 -23
  252. package/samples/todo/zenstack/migrations/migration_lock.toml +0 -3
  253. package/samples/todo/zenstack/schema.prisma +0 -126
  254. package/samples/todo/zenstack/schema.zmodel +0 -161
  255. package/tests/integration/jest.config.ts +0 -16
  256. package/tests/integration/package-lock.json +0 -1081
  257. package/tests/integration/package.json +0 -27
  258. package/tests/integration/tests/operation-coverate.test.ts +0 -563
  259. package/tests/integration/tests/operations.zmodel +0 -69
  260. package/tests/integration/tests/todo-e2e.test.ts +0 -577
  261. package/tests/integration/tests/todo.zmodel +0 -123
  262. package/tests/integration/tests/tsconfig.template.json +0 -10
  263. package/tests/integration/tests/utils.ts +0 -133
  264. package/tests/integration/tsconfig.json +0 -10
@@ -1,577 +0,0 @@
1
- import path from 'path';
2
- import { makeClient, run, setup } from './utils';
3
-
4
- describe('Todo E2E Tests', () => {
5
- let workDir: string;
6
- let origDir: string;
7
-
8
- beforeAll(async () => {
9
- origDir = path.resolve('.');
10
- workDir = await setup('./tests/todo.zmodel');
11
- });
12
-
13
- afterAll(() => {
14
- process.chdir(origDir);
15
- });
16
-
17
- beforeEach(() => {
18
- run('npx prisma migrate reset --schema ./zenstack/schema.prisma -f');
19
- });
20
-
21
- it('user', async () => {
22
- const userClient = makeClient('/api/data/User');
23
- const user1 = {
24
- id: 'user1',
25
- email: 'user1@zenstack.dev',
26
- name: 'User 1',
27
- };
28
- const user2 = {
29
- id: 'user2',
30
- email: 'user2@zenstack.dev',
31
- name: 'User 2',
32
- };
33
- const user1Client = makeClient('/api/data/User/user1', user1.id);
34
- const user2Client = makeClient('/api/data/User/user2', user1.id);
35
-
36
- // create user1
37
- await userClient
38
- .post('/')
39
- .send({
40
- data: user1,
41
- })
42
- .expect(201)
43
- .expect((resp) => {
44
- expect(resp.body).toEqual(expect.objectContaining(user1));
45
- });
46
-
47
- const credClient = makeClient('/api/data/User', user1.id);
48
-
49
- // find
50
- await credClient
51
- .get('/')
52
- .expect(200)
53
- .expect((resp) => {
54
- expect(resp.body).toEqual([expect.objectContaining(user1)]);
55
- });
56
-
57
- // get
58
- await user1Client
59
- .get('/')
60
- .expect(200)
61
- .expect((resp) =>
62
- expect(resp.body).toEqual(expect.objectContaining(user1))
63
- );
64
- await user2Client.get('/').expect(404);
65
-
66
- // create user2
67
- await userClient.post('/').send({
68
- data: user2,
69
- });
70
-
71
- // find with user1 should only get user1
72
- await credClient
73
- .get('/')
74
- .expect(200)
75
- .expect((resp) => {
76
- expect(resp.body).toHaveLength(1);
77
- expect(resp.body).toEqual([expect.objectContaining(user1)]);
78
- });
79
-
80
- // get user2 as user1
81
- await user2Client.get('/').expect(404);
82
-
83
- // add both users into the same space
84
- const spaceClient = makeClient('/api/data/Space', user1.id);
85
- await spaceClient
86
- .post('/')
87
- .send({
88
- data: {
89
- name: 'Space 1',
90
- slug: 'space1',
91
- owner: { connect: { id: user1.id } },
92
- members: {
93
- create: [
94
- {
95
- user: { connect: { id: user1.id } },
96
- role: 'ADMIN',
97
- },
98
- {
99
- user: { connect: { id: user2.id } },
100
- role: 'USER',
101
- },
102
- ],
103
- },
104
- },
105
- })
106
- .expect(201);
107
-
108
- // now both user1 and user2 should be visible
109
- await credClient
110
- .get('/')
111
- .expect((resp) => expect(resp.body).toHaveLength(2));
112
- await user2Client
113
- .get('/')
114
- .expect(200)
115
- .expect((resp) =>
116
- expect(resp.body).toEqual(expect.objectContaining(user2))
117
- );
118
-
119
- // update user2 as user1
120
- await user2Client
121
- .put('/')
122
- .send({
123
- data: {
124
- name: 'hello',
125
- },
126
- })
127
- .expect(403);
128
-
129
- // update user1 as user1
130
- await user1Client
131
- .put('/')
132
- .send({
133
- data: {
134
- name: 'hello',
135
- },
136
- })
137
- .expect(200)
138
- .expect((resp) => expect(resp.body.name).toBe('hello'));
139
-
140
- // delete user2 as user1
141
- await user2Client.delete('/').expect(403);
142
-
143
- // delete user1 as user1
144
- await user1Client.delete('/').expect(200);
145
- await user1Client.get('/').expect(404);
146
- });
147
-
148
- it('todo list', async () => {
149
- await createSpaceAndUsers();
150
-
151
- const listClient = makeClient('/api/data/List');
152
- await listClient
153
- .post('/')
154
- .send({
155
- data: {
156
- id: 'list1',
157
- title: 'List 1',
158
- owner: { connect: { id: user1.id } },
159
- space: { connect: { id: space1.id } },
160
- },
161
- })
162
- .expect(403);
163
-
164
- const credClient = makeClient('/api/data/List', user1.id);
165
- await credClient
166
- .post('/')
167
- .send({
168
- data: {
169
- id: 'list1',
170
- title: 'List 1',
171
- owner: { connect: { id: user1.id } },
172
- space: { connect: { id: space1.id } },
173
- },
174
- })
175
- .expect(201);
176
-
177
- await credClient
178
- .get('/')
179
- .expect(200)
180
- .expect((resp) => expect(resp.body).toHaveLength(1));
181
-
182
- await listClient
183
- .get('/')
184
- .expect(200)
185
- .expect((resp) => expect(resp.body).toHaveLength(0));
186
-
187
- const list1Client = makeClient('/api/data/List/list1');
188
- await list1Client.get('/').expect(404);
189
-
190
- // accessible to owner
191
- const list1CredClientUser1 = makeClient(
192
- '/api/data/List/list1',
193
- user1.id
194
- );
195
- await list1CredClientUser1
196
- .get('/')
197
- .expect(200)
198
- .expect((resp) =>
199
- expect(resp.body).toEqual(
200
- expect.objectContaining({ id: 'list1', title: 'List 1' })
201
- )
202
- );
203
-
204
- // accessible to user in the space
205
- const list1CredClientUser2 = makeClient(
206
- '/api/data/List/list1',
207
- user2.id
208
- );
209
- await list1CredClientUser2.get('/').expect(200);
210
-
211
- // inaccessible to user not in the space
212
- const list1CredClientUser3 = makeClient(
213
- '/api/data/List/list1',
214
- user3.id
215
- );
216
- await list1CredClientUser3.get('/').expect(404);
217
-
218
- // make a private list
219
- await credClient
220
- .post('/')
221
- .send({
222
- data: {
223
- id: 'list2',
224
- title: 'List 2',
225
- private: true,
226
- owner: { connect: { id: user1.id } },
227
- space: { connect: { id: space1.id } },
228
- },
229
- })
230
- .expect(201);
231
-
232
- // accessible to owner
233
- const list2CredClientUser1 = makeClient(
234
- '/api/data/List/list2',
235
- user1.id
236
- );
237
- await list2CredClientUser1.get('/').expect(200);
238
-
239
- // inaccessible to other user in the space
240
- const list2CredClientUser2 = makeClient(
241
- '/api/data/List/list2',
242
- user2.id
243
- );
244
- await list2CredClientUser2.get('/').expect(404);
245
-
246
- // create a list which doesn't match credential should fail
247
- await credClient
248
- .post('/')
249
- .send({
250
- data: {
251
- id: 'list3',
252
- title: 'List 3',
253
- owner: { connect: { id: user2.id } },
254
- space: { connect: { id: space1.id } },
255
- },
256
- })
257
- .expect(403);
258
-
259
- // create a list which doesn't match credential's space should fail
260
- await credClient
261
- .post('/')
262
- .send({
263
- data: {
264
- id: 'list3',
265
- title: 'List 3',
266
- owner: { connect: { id: user1.id } },
267
- space: { connect: { id: space2.id } },
268
- },
269
- })
270
- .expect(403);
271
-
272
- // update list
273
- await list1CredClientUser1
274
- .put('/')
275
- .send({
276
- data: {
277
- title: 'List 1 updated',
278
- },
279
- })
280
- .expect(200)
281
- .expect((resp) => expect(resp.body.title).toBe('List 1 updated'));
282
-
283
- await list1CredClientUser2
284
- .put('/')
285
- .send({
286
- data: {
287
- title: 'List 1 updated',
288
- },
289
- })
290
- .expect(403);
291
-
292
- // delete list
293
- await list1CredClientUser2.delete('/').expect(403);
294
- await list1CredClientUser1.delete('/').expect(200);
295
- await list1CredClientUser1.get('/').expect(404);
296
- });
297
-
298
- it('todo', async () => {
299
- await createSpaceAndUsers();
300
-
301
- const listClient = makeClient('/api/data/List', user1.id);
302
- await listClient
303
- .post('/')
304
- .send({
305
- data: {
306
- id: 'list1',
307
- title: 'List 1',
308
- owner: { connect: { id: user1.id } },
309
- space: { connect: { id: space1.id } },
310
- },
311
- })
312
- .expect(201);
313
-
314
- const todoClientUser1 = makeClient('/api/data/Todo', user1.id);
315
- const todoClientUser2 = makeClient('/api/data/Todo', user2.id);
316
-
317
- // create
318
- await todoClientUser1
319
- .post('/')
320
- .send({
321
- data: {
322
- id: 'todo1',
323
- title: 'Todo 1',
324
- owner: { connect: { id: user1.id } },
325
- list: {
326
- connect: { id: 'list1' },
327
- },
328
- },
329
- })
330
- .expect(201);
331
- await todoClientUser2
332
- .post('/')
333
- .send({
334
- data: {
335
- id: 'todo2',
336
- title: 'Todo 2',
337
- owner: { connect: { id: user2.id } },
338
- list: {
339
- connect: { id: 'list1' },
340
- },
341
- },
342
- })
343
- .expect(201);
344
-
345
- // read
346
- await todoClientUser1
347
- .get('/')
348
- .expect(200)
349
- .expect((resp) => expect(resp.body).toHaveLength(2));
350
- await todoClientUser2
351
- .get('/')
352
- .expect(200)
353
- .expect((resp) => expect(resp.body).toHaveLength(2));
354
-
355
- const todo1ClientUser1 = makeClient('/api/data/Todo/todo1', user1.id);
356
- const todo2ClientUser1 = makeClient('/api/data/Todo/todo2', user1.id);
357
-
358
- // update, user in the same space can freely update
359
- await todo1ClientUser1
360
- .put('/')
361
- .send({
362
- data: {
363
- title: 'Todo 1 updated',
364
- },
365
- })
366
- .expect(200);
367
- await todo2ClientUser1
368
- .put('/')
369
- .send({
370
- data: {
371
- title: 'Todo 2 updated',
372
- },
373
- })
374
- .expect(200);
375
-
376
- // create a private list
377
- await listClient
378
- .post('/')
379
- .send({
380
- data: {
381
- id: 'list2',
382
- private: true,
383
- title: 'List 2',
384
- owner: { connect: { id: user1.id } },
385
- space: { connect: { id: space1.id } },
386
- },
387
- })
388
- .expect(201);
389
-
390
- // create
391
- await todoClientUser1
392
- .post('/')
393
- .send({
394
- data: {
395
- id: 'todo3',
396
- title: 'Todo 3',
397
- owner: { connect: { id: user1.id } },
398
- list: {
399
- connect: { id: 'list2' },
400
- },
401
- },
402
- })
403
- .expect(201);
404
- await todoClientUser2
405
- .post('/')
406
- .send({
407
- data: {
408
- id: 'todo4',
409
- title: 'Todo 4',
410
- owner: { connect: { id: user2.id } },
411
- list: {
412
- connect: { id: 'list2' },
413
- },
414
- },
415
- })
416
- .expect(403);
417
-
418
- // update, only owner can update todo in a private list
419
- const todo3ClientUser1 = makeClient('/api/data/Todo/todo3', user1.id);
420
- const todo3ClientUser2 = makeClient('/api/data/Todo/todo3', user2.id);
421
- await todo3ClientUser1
422
- .put('/')
423
- .send({
424
- data: {
425
- title: 'Todo 3 updated',
426
- },
427
- })
428
- .expect(200);
429
- await todo3ClientUser2
430
- .put('/')
431
- .send({
432
- data: {
433
- title: 'Todo 3 updated',
434
- },
435
- })
436
- .expect(403);
437
- });
438
-
439
- it('relation query', async () => {
440
- await createSpaceAndUsers();
441
- const listClient = makeClient('/api/data/List', user1.id);
442
- await listClient.post('/').send({
443
- data: {
444
- id: 'list1',
445
- title: 'List 1',
446
- owner: { connect: { id: user1.id } },
447
- space: { connect: { id: space1.id } },
448
- },
449
- });
450
- await listClient.post('/').send({
451
- data: {
452
- id: 'list2',
453
- title: 'List 2',
454
- private: true,
455
- owner: { connect: { id: user1.id } },
456
- space: { connect: { id: space1.id } },
457
- },
458
- });
459
-
460
- const spaceClientUser1 = makeClient(
461
- `/api/data/Space/space1`,
462
- user1.id,
463
- {
464
- include: { lists: true },
465
- }
466
- );
467
- await spaceClientUser1.get('/').expect((resp) => {
468
- expect(resp.body.lists).toHaveLength(2);
469
- });
470
-
471
- const spaceClientUser2 = makeClient(
472
- `/api/data/Space/space1`,
473
- user2.id,
474
- {
475
- include: { lists: true },
476
- }
477
- );
478
- await spaceClientUser2.get('/').expect((resp) => {
479
- expect(resp.body.lists).toHaveLength(1);
480
- });
481
- });
482
- });
483
-
484
- const user1 = {
485
- id: 'user1',
486
- email: 'user1@zenstack.dev',
487
- name: 'User 1',
488
- };
489
-
490
- const user2 = {
491
- id: 'user2',
492
- email: 'user2@zenstack.dev',
493
- name: 'User 2',
494
- };
495
-
496
- const user3 = {
497
- id: 'user3',
498
- email: 'user3@zenstack.dev',
499
- name: 'User 3',
500
- };
501
-
502
- const space1 = {
503
- id: 'space1',
504
- name: 'Space 1',
505
- slug: 'space1',
506
- };
507
-
508
- const space2 = {
509
- id: 'space2',
510
- name: 'Space 2',
511
- slug: 'space2',
512
- };
513
-
514
- async function createSpaceAndUsers() {
515
- const userClient = makeClient('/api/data/User');
516
- // create users
517
- await userClient
518
- .post('/')
519
- .send({
520
- data: user1,
521
- })
522
- .expect(201);
523
- await userClient
524
- .post('/')
525
- .send({
526
- data: user2,
527
- })
528
- .expect(201);
529
- await userClient
530
- .post('/')
531
- .send({
532
- data: user3,
533
- })
534
- .expect(201);
535
-
536
- // add user1 and user2 into space1
537
- const spaceClientUser1 = makeClient('/api/data/Space', user1.id);
538
- await spaceClientUser1
539
- .post('/')
540
- .send({
541
- data: {
542
- ...space1,
543
- members: {
544
- create: [
545
- {
546
- user: { connect: { id: user1.id } },
547
- role: 'ADMIN',
548
- },
549
- {
550
- user: { connect: { id: user2.id } },
551
- role: 'USER',
552
- },
553
- ],
554
- },
555
- },
556
- })
557
- .expect(201);
558
-
559
- // add user3 to space2
560
- const spaceClientUser3 = makeClient('/api/data/Space', user3.id);
561
- await spaceClientUser3
562
- .post('/')
563
- .send({
564
- data: {
565
- ...space2,
566
- members: {
567
- create: [
568
- {
569
- user: { connect: { id: user3.id } },
570
- role: 'ADMIN',
571
- },
572
- ],
573
- },
574
- },
575
- })
576
- .expect(201);
577
- }
@@ -1,123 +0,0 @@
1
- /*
2
- * Sample model for a collaborative Todo app
3
- */
4
-
5
- datasource db {
6
- provider = 'sqlite'
7
- url = 'file:./todo.db'
8
- }
9
-
10
- model Space {
11
- id String @id @default(uuid())
12
- createdAt DateTime @default(now())
13
- updatedAt DateTime @updatedAt
14
- name String @length(1, 100)
15
- slug String @unique @length(1, 20)
16
-
17
- owner User? @relation(fields: [ownerId], references: [id])
18
- ownerId String?
19
-
20
- members SpaceUser[]
21
- lists List[]
22
-
23
- // require login
24
- @@deny('all', auth() == null)
25
-
26
- // everyone can create a space
27
- @@allow('create', true)
28
-
29
- // any user in the space can read the space
30
- @@allow('read', members?[user == auth()])
31
-
32
- // space admin can update and delete
33
- @@allow('update,delete', members?[user == auth() && role == "ADMIN"])
34
- }
35
-
36
- model SpaceUser {
37
- id String @id @default(uuid())
38
- createdAt DateTime @default(now())
39
- updatedAt DateTime @updatedAt
40
- space Space @relation(fields:[spaceId], references: [id], onDelete: Cascade)
41
- spaceId String
42
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
43
- userId String
44
- role String
45
-
46
- @@unique([userId, spaceId])
47
-
48
- // require login
49
- @@deny('all', auth() == null)
50
-
51
- // space admin can create/update/delete
52
- @@allow('create,update,delete', space.owner == auth() || space.members?[user == auth() && role == "ADMIN"])
53
-
54
- // user can read entries for spaces which he's a member of
55
- @@allow('read', space.members?[user == auth()])
56
- }
57
-
58
- model User {
59
- id String @id @default(uuid())
60
- createdAt DateTime @default(now())
61
- updatedAt DateTime @updatedAt
62
- email String @unique @email
63
- emailVerified DateTime?
64
- password String?
65
- name String? @length(1, 100)
66
-
67
- ownedSpaces Space[]
68
-
69
- spaces SpaceUser[]
70
- image String? @url
71
- lists List[]
72
- todos Todo[]
73
-
74
- // can be created by anyone, even not logged in
75
- @@allow('create', true)
76
-
77
- // can be read by users sharing any space
78
- @@allow('read', auth() == this || spaces?[space.members?[user == auth()]])
79
-
80
- // can only be updated and deleted by himeself
81
- @@allow('update,delete', auth() == this)
82
- }
83
-
84
- model List {
85
- id String @id @default(uuid())
86
- createdAt DateTime @default(now())
87
- updatedAt DateTime @updatedAt
88
- space Space @relation(fields: [spaceId], references: [id], onDelete: Cascade)
89
- spaceId String
90
- owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade)
91
- ownerId String
92
- title String @length(1, 20)
93
- private Boolean @default(false)
94
- todos Todo[]
95
-
96
- // require login
97
- @@deny('all', auth() == null)
98
-
99
- // can be read by owner or space members (only if not private)
100
- @@allow('read', owner == auth() || (space.members?[user == auth()] && !private))
101
-
102
- // can be updated/deleted by owner with a valid space
103
- @@allow('create,update,delete', owner == auth() && space.members?[user == auth()])
104
- }
105
-
106
- model Todo {
107
- id String @id @default(uuid())
108
- createdAt DateTime @default(now())
109
- updatedAt DateTime @updatedAt
110
- owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade)
111
- ownerId String
112
- list List @relation(fields: [listId], references: [id], onDelete: Cascade)
113
- listId String
114
- title String
115
- completedAt DateTime?
116
-
117
- // require login
118
- @@deny('all', auth() == null)
119
-
120
- // owner has full access, also space members have full access (if the parent List is not private)
121
- @@allow('all', list.owner == auth())
122
- @@allow('all', list.space.members?[user == auth()] && !list.private)
123
- }
@@ -1,10 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "es2016",
4
- "module": "commonjs",
5
- "esModuleInterop": true,
6
- "forceConsistentCasingInFileNames": true,
7
- "strict": true,
8
- "skipLibCheck": true
9
- }
10
- }