@lobb-js/lobb-ext-auth 0.11.3 → 0.13.0

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 (43) hide show
  1. package/dist/lib/components/pages/loginPage/index.svelte +1 -1
  2. package/dist/lib/components/pages/settings/pages/activityFeed.svelte +1 -1
  3. package/dist/lib/components/pages/settings/pages/rolesAndPermissions.svelte +1 -1
  4. package/dist/lib/components/pages/settings/pages/users.svelte +1 -1
  5. package/dist/lib/components/pages/userSettings/index.svelte +1 -1
  6. package/extensions/auth/studio/lib/components/pages/loginPage/index.svelte +1 -1
  7. package/extensions/auth/studio/lib/components/pages/settings/pages/activityFeed.svelte +1 -1
  8. package/extensions/auth/studio/lib/components/pages/settings/pages/rolesAndPermissions.svelte +1 -1
  9. package/extensions/auth/studio/lib/components/pages/settings/pages/users.svelte +1 -1
  10. package/extensions/auth/studio/lib/components/pages/userSettings/index.svelte +1 -1
  11. package/package.json +5 -5
  12. package/extensions/auth/tests/collections/extend_users_collection.test.ts +0 -61
  13. package/extensions/auth/tests/collections/shares.test.ts +0 -657
  14. package/extensions/auth/tests/configs/auth.ts +0 -101
  15. package/extensions/auth/tests/configs/auth_no_roles.ts +0 -65
  16. package/extensions/auth/tests/configs/auth_public_full_access.ts +0 -69
  17. package/extensions/auth/tests/configs/auth_with_admin_extra_fields.ts +0 -53
  18. package/extensions/auth/tests/configs/auth_with_different_admin_creds.ts +0 -81
  19. package/extensions/auth/tests/configs/auth_with_extend_users.ts +0 -79
  20. package/extensions/auth/tests/configs/auth_with_refresh_token.ts +0 -86
  21. package/extensions/auth/tests/configs/auth_with_short_access_token_only.ts +0 -95
  22. package/extensions/auth/tests/configs/auth_with_short_time_refresh_token.ts +0 -86
  23. package/extensions/auth/tests/configs/social_blog.ts +0 -146
  24. package/extensions/auth/tests/controllers/change_password.test.ts +0 -113
  25. package/extensions/auth/tests/controllers/dashboardAccessRoles.test.ts +0 -29
  26. package/extensions/auth/tests/controllers/login.test.ts +0 -101
  27. package/extensions/auth/tests/controllers/logout.test.ts +0 -89
  28. package/extensions/auth/tests/controllers/me.test.ts +0 -376
  29. package/extensions/auth/tests/controllers/register.test.ts +0 -45
  30. package/extensions/auth/tests/database/adminExtraFields.test.ts +0 -50
  31. package/extensions/auth/tests/database/db.test.ts +0 -64
  32. package/extensions/auth/tests/database/differentAdminCreds.test.ts +0 -51
  33. package/extensions/auth/tests/middlewares/adminAuthGuard.test.ts +0 -157
  34. package/extensions/auth/tests/middlewares/adminProtection.test.ts +0 -59
  35. package/extensions/auth/tests/middlewares/publicAllowBasic.test.ts +0 -137
  36. package/extensions/auth/tests/middlewares/publicPreventBasic.test.ts +0 -108
  37. package/extensions/auth/tests/permissions.test.ts +0 -127
  38. package/extensions/auth/tests/socialBlog.test.ts +0 -253
  39. package/extensions/auth/tests/utils/addArticles.ts +0 -22
  40. package/extensions/auth/tests/utils/addSocialBlogArticles.ts +0 -52
  41. package/extensions/auth/tests/utils/data/articles.ts +0 -65
  42. package/extensions/auth/tests/utils/data/socialBlogArticles.ts +0 -56
  43. package/extensions/auth/tests/workflows/shareIntersection.test.ts +0 -158
@@ -1,253 +0,0 @@
1
- import { Lobb } from "@lobb-js/core";
2
- import { afterAll, beforeAll, describe, it, expect } from "bun:test";
3
- import {
4
- createArticles,
5
- removeArticles,
6
- } from "./utils/addSocialBlogArticles.ts";
7
- import { socialBlogConfig } from "./configs/social_blog.ts";
8
-
9
- describe("Social Blog auth", () => {
10
- let lobb: Lobb;
11
- let baseUrl: string;
12
- let articlesIds: string[];
13
- let newUserId: string;
14
-
15
- beforeAll(async () => {
16
- lobb = await Lobb.init(socialBlogConfig);
17
- baseUrl = `http://127.0.0.1:${lobb.webServer.port}`;
18
- articlesIds = await createArticles(lobb);
19
- });
20
-
21
- afterAll(async () => {
22
- await removeArticles(lobb);
23
- await lobb.close();
24
- });
25
-
26
- it("should return only public status articles for public users", async () => {
27
- const response = await fetch(
28
- `${baseUrl}/api/collections/articles?sort=id`,
29
- {
30
- method: "GET",
31
- },
32
- );
33
-
34
- const result = await response.json();
35
- const titles = result.data.map((article: any) => article.title);
36
-
37
- expect(
38
- titles,
39
- ).toEqual([
40
- "The Future of AI: Trends Shaping Tomorrow's Technology",
41
- "Mental Health in the Digital Age: Navigating the New Challenges",
42
- "The Role of 5G in Revolutionizing Smart Cities",
43
- ]);
44
- expect(response.status).toEqual(200);
45
- });
46
-
47
- it("returns only public articles or the private and public articles that the user owns", async () => {
48
- // login with the doe user
49
- const headers = new Headers();
50
-
51
- const loginResponse = await fetch(
52
- `${baseUrl}/api/collections/auth_sessions`,
53
- {
54
- method: "POST",
55
- headers: {
56
- "Content-Type": "application/json",
57
- },
58
- body: JSON.stringify({
59
- data: {
60
- email: "doe@gmail.com",
61
- password: "123456",
62
- },
63
- }),
64
- },
65
- );
66
- const loginData = await loginResponse.json();
67
-
68
- headers.append(
69
- "Authorization",
70
- `Bearer ${loginData.data.access_token.token}`,
71
- );
72
-
73
- // get articles with the doe user
74
- const response = await fetch(
75
- `${baseUrl}/api/collections/articles?sort=id`,
76
- {
77
- method: "GET",
78
- headers: headers,
79
- },
80
- );
81
- const result = await response.json();
82
-
83
- const titles = result.data.map((article: any) => article.title);
84
-
85
- expect(
86
- titles,
87
- ).toEqual([
88
- "The Future of AI: Trends Shaping Tomorrow's Technology",
89
- "Mental Health in the Digital Age: Navigating the New Challenges",
90
- "Sustainable Fashion: How the Industry is Going Green",
91
- "The Role of 5G in Revolutionizing Smart Cities",
92
- "Digital Marketing in 2024: Emerging Strategies for Success",
93
- "The Future of Renewable Energy: Innovations Driving a Clean Energy Revolution",
94
- ]);
95
- expect(response.status).toEqual(200);
96
- });
97
-
98
- it("should prevent public users from creating users with a role other than the author role", async () => {
99
- // get articles with the doe user
100
- const response = await fetch(
101
- `${baseUrl}/api/collections/auth_users`,
102
- {
103
- method: "POST",
104
- body: JSON.stringify({
105
- data: {
106
- email: "new_user@gmail.com",
107
- password: "123456",
108
- role: "admin",
109
- },
110
- }),
111
- },
112
- );
113
-
114
- const result = await response.json();
115
-
116
- expect(response.status).toEqual(403);
117
- expect(
118
- result,
119
- ).toEqual({
120
- status: 403,
121
- code: "FORBIDDEN",
122
- message: "You do not have permission to perform this action.",
123
- });
124
- });
125
-
126
- it("should allow public users to create users with the author role", async () => {
127
- // get articles with the doe user
128
- const response = await fetch(
129
- `${baseUrl}/api/collections/auth_users`,
130
- {
131
- method: "POST",
132
- body: JSON.stringify({
133
- data: {
134
- email: "new_user@gmail.com",
135
- password: "123456",
136
- role: "author",
137
- },
138
- }),
139
- },
140
- );
141
-
142
- const result = await response.json();
143
-
144
- expect(response.status).toEqual(201);
145
- expect(
146
- result.data,
147
- ).toMatchObject({
148
- email: "new_user@gmail.com",
149
- });
150
- });
151
-
152
- it("should fill the author_id of the article automatically with the logged in user_id", async () => {
153
- const headers = new Headers();
154
- const loginResponse = await fetch(
155
- `${baseUrl}/api/collections/auth_sessions`,
156
- {
157
- method: "POST",
158
- body: JSON.stringify({
159
- data: {
160
- email: "new_user@gmail.com",
161
- password: "123456",
162
- },
163
- }),
164
- },
165
- );
166
- const loginData = await loginResponse.json();
167
- newUserId = loginData.data.user.id;
168
- headers.append(
169
- "Authorization",
170
- `Bearer ${loginData.data.access_token.token}`,
171
- );
172
-
173
- // create an article
174
- const response = await fetch(
175
- `${baseUrl}/api/collections/articles`,
176
- {
177
- headers: headers,
178
- method: "POST",
179
- body: JSON.stringify({
180
- data: {
181
- title: "new article created by the new user",
182
- body: "test the new body",
183
- },
184
- }),
185
- },
186
- );
187
-
188
- const result = await response.json();
189
-
190
- expect(response.status).toEqual(201);
191
- expect(
192
- result.data,
193
- ).toMatchObject({
194
- author_id: newUserId,
195
- title: "new article created by the new user",
196
- body: "test the new body",
197
- description: null,
198
- image: null,
199
- status: "private",
200
- });
201
- });
202
-
203
- it("should hide the password of the users from the returned responses of findOne operations", async () => {
204
- // create an article
205
- const response = await fetch(
206
- `${baseUrl}/api/collections/auth_users/` + newUserId,
207
- {
208
- method: "Get",
209
- },
210
- );
211
-
212
- const result = await response.json();
213
-
214
- expect(response.status).toEqual(200);
215
- expect(
216
- Object.keys(result.data).includes("password"),
217
- ).toEqual(false);
218
- });
219
-
220
- it("should hide the password of the users from the returned responses of findAll operations", async () => {
221
- const response = await fetch(
222
- `${baseUrl}/api/collections/auth_users`,
223
- {
224
- method: "Get",
225
- },
226
- );
227
-
228
- const result = await response.json();
229
-
230
- expect(
231
- Object.keys(result.data).includes("password"),
232
- ).toEqual(false);
233
- expect(response.status).toEqual(200);
234
- });
235
-
236
- it("should prevent public users from getting admin role users", async () => {
237
- const response = await fetch(
238
- `${baseUrl}/api/collections/auth_users`,
239
- {
240
- method: "Get",
241
- },
242
- );
243
-
244
- const result = await response.json();
245
-
246
- const adminUsers = result.data.filter((user: any) => user.role === "admin");
247
-
248
- expect(
249
- adminUsers.length,
250
- ).toEqual(0);
251
- expect(response.status).toEqual(200);
252
- });
253
- });
@@ -1,22 +0,0 @@
1
- import type { Lobb } from "@lobb-js/core";
2
- import { articles } from "../utils/data/articles.ts";
3
-
4
- export async function createArticles(lobb: Lobb) {
5
- const createdArticles: any[] = [];
6
- for (let index = 0; index < articles.length; index++) {
7
- const article = articles[index];
8
- const createdArticle = (await lobb.collectionService.createOne({
9
- collectionName: "articles",
10
- data: article,
11
- })).data;
12
- createdArticles.push(createdArticle);
13
- }
14
-
15
- return createdArticles.map((article) => article.id);
16
- }
17
-
18
- export async function removeArticles(lobb: Lobb) {
19
- await lobb.collectionService.deleteMany({
20
- collectionName: "articles",
21
- });
22
- }
@@ -1,52 +0,0 @@
1
- import type { Lobb } from "@lobb-js/core";
2
- import { articles } from "./data/socialBlogArticles.ts";
3
-
4
- export async function createArticles(lobb: Lobb) {
5
- // clean collections
6
- await removeArticles(lobb);
7
-
8
- // create the owner user
9
- const user = (await lobb.collectionService.createOne({
10
- collectionName: "auth_users",
11
- data: {
12
- email: "john@gmail.com",
13
- password: "123456",
14
- role: "author",
15
- },
16
- })).data;
17
- const user2 = (await lobb.collectionService.createOne({
18
- collectionName: "auth_users",
19
- data: {
20
- email: "doe@gmail.com",
21
- password: "123456",
22
- role: "author",
23
- },
24
- })).data;
25
-
26
- // create the articles
27
- const createdArticles: any[] = [];
28
- for (let index = 0; index < articles.length; index++) {
29
- const article: any = articles[index];
30
- article["author_id"] = index > (articles.length / 2) ? user2.id : user.id;
31
- const createdArticle = (await lobb.collectionService.createOne({
32
- collectionName: "articles",
33
- data: article,
34
- })).data;
35
- createdArticles.push(createdArticle);
36
- }
37
-
38
- return createdArticles.map((article) => article.id);
39
- }
40
-
41
- export async function removeArticles(lobb: Lobb) {
42
- await lobb.collectionService.deleteMany({
43
- collectionName: "articles",
44
- filter: {},
45
- force: true,
46
- });
47
- await lobb.collectionService.deleteMany({
48
- collectionName: "auth_users",
49
- filter: {},
50
- force: true,
51
- });
52
- }
@@ -1,65 +0,0 @@
1
- export const articles = [
2
- {
3
- title: "The Future of AI: Trends Shaping Tomorrow's Technology",
4
- body:
5
- "Explore how artificial intelligence is evolving, from machine learning innovations to ethical challenges in AI governance. This article delves into the transformative potential AI holds for industries like healthcare, finance, and automation.",
6
- number_of_likes: 454,
7
- published: null,
8
- },
9
- {
10
- title: "Climate Change and Its Impact on Global Food Security",
11
- body:
12
- "This article examines the effect of climate change on agriculture and global food production. It covers rising temperatures, changing weather patterns, and their implications for food supply chains, emphasizing the need for sustainable farming practices Wow.",
13
- number_of_likes: 1212,
14
- },
15
- {
16
- title: "The Rise of Remote Work: Is the Office Dead?",
17
- body:
18
- "A comprehensive analysis of How remote work has redefined the modern workplace post-pandemic. It discusses benefits and challenges for both employers and employees, and whether traditional office spaces will continue to exist in the future.",
19
- number_of_likes: 9848,
20
- published: true,
21
- },
22
- {
23
- title: "Blockchain Beyond Cryptocurrency: Practical Applications in 2024",
24
- body:
25
- "Blockchain technology extends far beyond Bitcoin and digital currencies. This article explains its real-world uses in supply chain management, healthcare, and secure voting systems, highlighting successful implementations and ongoing experiments.",
26
- number_of_likes: 10,
27
- },
28
- {
29
- title: "Mental Health in the Digital Age: Navigating the New Challenges",
30
- body:
31
- "With increasing screen time and social media usage, mental health issues have taken new forms. This article addresses the growing concerns around digital addiction, online anxiety, and the role of tech companies in promoting well-being wow.",
32
- number_of_likes: 5,
33
- },
34
- {
35
- title: "Understanding Quantum Computing: The Next Tech Revolution",
36
- body:
37
- "Quantum computing promises to solve problems too complex for classical computers. This article breaks down the fundamentals of quantum technology, its current state, and its future potential across industries like pharmaceuticals, logistics, and cybersecurity.",
38
- number_of_likes: 156,
39
- },
40
- {
41
- title: "Sustainable Fashion: How the Industry is Going Green",
42
- body:
43
- "With environmental consciousness on the rise, the fashion industry is pivoting toward sustainability. This article looks at eco-friendly materials, ethical manufacturing processes, and how major brands are embracing the green movement wow.",
44
- number_of_likes: 89,
45
- },
46
- {
47
- title: "The Role of 5G in Revolutionizing Smart Cities",
48
- body:
49
- "As 5G networks roll out globally, smart cities are becoming a reality. This wow article covers how 5G technology wow will enable real-time data sharing, improve urban infrastructure, wow and enhance public services through IoT devices and smart sensors.",
50
- number_of_likes: 15,
51
- },
52
- {
53
- title: "Digital Marketing in 2024: Emerging Strategies for Success",
54
- body:
55
- "The landscape of digital marketing is rapidly changing with the rise of AI, personalized experiences, and social commerce. This article outlines the most promising strategies to stay ahead in 2024, from leveraging data analytics to mastering content creation wow.",
56
- number_of_likes: 87,
57
- },
58
- {
59
- title:
60
- "The Future of Renewable Energy: Innovations Driving a Clean Energy Revolution",
61
- body:
62
- "As the world shifts toward green energy, this article highlights wow the latest innovations in solar, wind, and hydropower technologies. It also discusses policy trends, wow global investment in renewables, wow and the challenges in achieving net-zero emissions by 2050 wow.",
63
- number_of_likes: 48,
64
- },
65
- ];
@@ -1,56 +0,0 @@
1
- export const articles = [
2
- {
3
- title: "The Future of AI: Trends Shaping Tomorrow's Technology",
4
- body:
5
- "Explore how artificial intelligence is evolving, from machine learning innovations to ethical challenges in AI governance. This article delves into the transformative potential AI holds for industries like healthcare, finance, and automation.",
6
- status: "public",
7
- },
8
- {
9
- title: "Climate Change and Its Impact on Global Food Security",
10
- body:
11
- "This article examines the effect of climate change on agriculture and global food production. It covers rising temperatures, changing weather patterns, and their implications for food supply chains, emphasizing the need for sustainable farming practices Wow.",
12
- },
13
- {
14
- title: "The Rise of Remote Work: Is the Office Dead?",
15
- body:
16
- "A comprehensive analysis of How remote work has redefined the modern workplace post-pandemic. It discusses benefits and challenges for both employers and employees, and whether traditional office spaces will continue to exist in the future.",
17
- },
18
- {
19
- title: "Blockchain Beyond Cryptocurrency: Practical Applications in 2024",
20
- body:
21
- "Blockchain technology extends far beyond Bitcoin and digital currencies. This article explains its real-world uses in supply chain management, healthcare, and secure voting systems, highlighting successful implementations and ongoing experiments.",
22
- },
23
- {
24
- title: "Mental Health in the Digital Age: Navigating the New Challenges",
25
- body:
26
- "With increasing screen time and social media usage, mental health issues have taken new forms. This article addresses the growing concerns around digital addiction, online anxiety, and the role of tech companies in promoting well-being wow.",
27
- status: "public",
28
- },
29
- {
30
- title: "Understanding Quantum Computing: The Next Tech Revolution",
31
- body:
32
- "Quantum computing promises to solve problems too complex for classical computers. This article breaks down the fundamentals of quantum technology, its current state, and its future potential across industries like pharmaceuticals, logistics, and cybersecurity.",
33
- },
34
- {
35
- title: "Sustainable Fashion: How the Industry is Going Green",
36
- body:
37
- "With environmental consciousness on the rise, the fashion industry is pivoting toward sustainability. This article looks at eco-friendly materials, ethical manufacturing processes, and how major brands are embracing the green movement wow.",
38
- },
39
- {
40
- title: "The Role of 5G in Revolutionizing Smart Cities",
41
- body:
42
- "As 5G networks roll out globally, smart cities are becoming a reality. This wow article covers how 5G technology wow will enable real-time data sharing, improve urban infrastructure, wow and enhance public services through IoT devices and smart sensors.",
43
- status: "public",
44
- },
45
- {
46
- title: "Digital Marketing in 2024: Emerging Strategies for Success",
47
- body:
48
- "The landscape of digital marketing is rapidly changing with the rise of AI, personalized experiences, and social commerce. This article outlines the most promising strategies to stay ahead in 2024, from leveraging data analytics to mastering content creation wow.",
49
- },
50
- {
51
- title:
52
- "The Future of Renewable Energy: Innovations Driving a Clean Energy Revolution",
53
- body:
54
- "As the world shifts toward green energy, this article highlights wow the latest innovations in solar, wind, and hydropower technologies. It also discusses policy trends, wow global investment in renewables, wow and the challenges in achieving net-zero emissions by 2050 wow.",
55
- },
56
- ];
@@ -1,158 +0,0 @@
1
- import { describe, it, expect } from "bun:test";
2
- import { isShareSubsetOfCreator } from "../../workflows/shareIntersection.ts";
3
-
4
- describe("isShareSubsetOfCreator", () => {
5
- describe("creator: true (admin)", () => {
6
- it("allows any share, including true", () => {
7
- expect(isShareSubsetOfCreator(true, true)).toBe(true);
8
- expect(isShareSubsetOfCreator({ articles: { read: true } }, true)).toBe(true);
9
- expect(
10
- isShareSubsetOfCreator(
11
- { auth_users: { read: true, update: true } },
12
- true,
13
- ),
14
- ).toBe(true);
15
- });
16
- });
17
-
18
- describe("share: true (unconditional)", () => {
19
- it("requires creator: true — anything else is broader", () => {
20
- expect(isShareSubsetOfCreator(true, { articles: { read: true } })).toBe(false);
21
- expect(isShareSubsetOfCreator(true, undefined)).toBe(false);
22
- expect(isShareSubsetOfCreator(true, {})).toBe(false);
23
- });
24
- });
25
-
26
- describe("empty / missing share", () => {
27
- it("an empty share is trivially a subset", () => {
28
- expect(isShareSubsetOfCreator(undefined, undefined)).toBe(true);
29
- expect(isShareSubsetOfCreator({}, undefined)).toBe(true);
30
- expect(isShareSubsetOfCreator({}, { articles: { read: true } })).toBe(true);
31
- });
32
- });
33
-
34
- describe("missing creator collection", () => {
35
- it("rejects when share names a collection the creator has no perm for", () => {
36
- expect(
37
- isShareSubsetOfCreator(
38
- { auth_users: { read: true } },
39
- { articles: { read: true } },
40
- ),
41
- ).toBe(false);
42
- });
43
- });
44
-
45
- describe("creator: true on collection", () => {
46
- it("allows any action grant on that collection", () => {
47
- expect(
48
- isShareSubsetOfCreator(
49
- { articles: { read: true, create: true } },
50
- { articles: true },
51
- ),
52
- ).toBe(true);
53
- expect(
54
- isShareSubsetOfCreator(
55
- { articles: { read: { filter: { id: 1 } } } },
56
- { articles: true },
57
- ),
58
- ).toBe(true);
59
- });
60
- });
61
-
62
- describe("share: true on a collection where creator is conditional", () => {
63
- it("rejects — share unconditional > creator conditional", () => {
64
- expect(
65
- isShareSubsetOfCreator(
66
- { articles: true },
67
- { articles: { read: true } },
68
- ),
69
- ).toBe(false);
70
- });
71
- });
72
-
73
- describe("share: true on an action where creator is conditional", () => {
74
- it("rejects — unconditional action > conditional action", () => {
75
- expect(
76
- isShareSubsetOfCreator(
77
- { articles: { read: true } },
78
- { articles: { read: { filter: { user_id: 1 } } } },
79
- ),
80
- ).toBe(false);
81
- });
82
-
83
- it("accepts when creator is also true on that action", () => {
84
- expect(
85
- isShareSubsetOfCreator(
86
- { articles: { read: true } },
87
- { articles: { read: true } },
88
- ),
89
- ).toBe(true);
90
- });
91
- });
92
-
93
- describe("missing creator action", () => {
94
- it("rejects when share has an action the creator doesn't", () => {
95
- expect(
96
- isShareSubsetOfCreator(
97
- { articles: { create: true } },
98
- { articles: { read: true } },
99
- ),
100
- ).toBe(false);
101
- });
102
- });
103
-
104
- describe("fields allowlist subsetting", () => {
105
- it("accepts when share's fields are a subset of creator's", () => {
106
- expect(
107
- isShareSubsetOfCreator(
108
- { articles: { create: { fields: { title: true } } } },
109
- { articles: { create: { fields: { title: true, body: true } } } },
110
- ),
111
- ).toBe(true);
112
- });
113
-
114
- it("rejects when share's fields include one the creator doesn't allow", () => {
115
- expect(
116
- isShareSubsetOfCreator(
117
- {
118
- articles: {
119
- create: { fields: { title: true, published: true } },
120
- },
121
- },
122
- { articles: { create: { fields: { title: true, body: true } } } },
123
- ),
124
- ).toBe(false);
125
- });
126
-
127
- it("rejects share that omits fields restriction when creator has one", () => {
128
- // No fields key = no restriction = broader than the creator.
129
- expect(
130
- isShareSubsetOfCreator(
131
- { articles: { create: {} } },
132
- { articles: { create: { fields: { title: true } } } },
133
- ),
134
- ).toBe(false);
135
- });
136
-
137
- it("allows omitting fields when creator has no fields restriction either", () => {
138
- expect(
139
- isShareSubsetOfCreator(
140
- { articles: { create: {} } },
141
- { articles: { create: {} as any } },
142
- ),
143
- ).toBe(true);
144
- });
145
- });
146
-
147
- describe("filter subsetting (intentionally not enforced)", () => {
148
- it("accepts any share filter when creator has a conditional read", () => {
149
- // Documented limitation — we don't try to prove filter subsets.
150
- expect(
151
- isShareSubsetOfCreator(
152
- { articles: { read: { filter: { id: 42 } } } },
153
- { articles: { read: { filter: { user_id: 1 } } } },
154
- ),
155
- ).toBe(true);
156
- });
157
- });
158
- });