@lobb-js/lobb-ext-auth 0.1.67 → 0.2.2

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 (86) hide show
  1. package/.vscode/settings.json +5 -0
  2. package/CHANGELOG.md +90 -31
  3. package/README.md +1 -1
  4. package/extensions/auth/collections/activityFeed.ts +53 -0
  5. package/extensions/auth/collections/collections.ts +43 -0
  6. package/extensions/auth/collections/sessions.ts +34 -0
  7. package/extensions/auth/collections/users.ts +44 -0
  8. package/extensions/auth/config/extensionConfigSchema.ts +47 -0
  9. package/extensions/auth/config/permissionsAction/create.ts +20 -0
  10. package/extensions/auth/config/permissionsAction/delete.ts +3 -0
  11. package/extensions/auth/config/permissionsAction/read.ts +10 -0
  12. package/extensions/auth/config/permissionsAction/update.ts +20 -0
  13. package/extensions/auth/database/init.ts +51 -0
  14. package/extensions/auth/database/migrations.ts +3 -0
  15. package/extensions/auth/database/utils.ts +36 -0
  16. package/extensions/auth/index.ts +19 -0
  17. package/extensions/auth/meta/meta.ts +11 -0
  18. package/extensions/auth/openapi.ts +469 -0
  19. package/extensions/auth/studio/tests/login.spec.ts +34 -0
  20. package/extensions/auth/studio/tests/package.json +1 -0
  21. package/extensions/auth/studio/tests/playwright.config.cjs +27 -0
  22. package/extensions/auth/tests/collections/extend_users_collection.test.ts +61 -0
  23. package/extensions/auth/tests/configs/auth.ts +73 -0
  24. package/extensions/auth/tests/configs/auth_no_roles.ts +65 -0
  25. package/extensions/auth/tests/configs/auth_public_full_access.ts +69 -0
  26. package/extensions/auth/tests/configs/auth_with_different_admin_creds.ts +81 -0
  27. package/extensions/auth/tests/configs/auth_with_extend_users.ts +81 -0
  28. package/extensions/auth/tests/configs/auth_with_refresh_token.ts +86 -0
  29. package/extensions/auth/tests/configs/auth_with_short_access_token_only.ts +95 -0
  30. package/extensions/auth/tests/configs/auth_with_short_time_refresh_token.ts +86 -0
  31. package/extensions/auth/tests/configs/social_blog.ts +156 -0
  32. package/extensions/auth/tests/controllers/change_password.test.ts +113 -0
  33. package/extensions/auth/tests/controllers/dashboardAccessRoles.test.ts +29 -0
  34. package/extensions/auth/tests/controllers/login.test.ts +101 -0
  35. package/extensions/auth/tests/controllers/logout.test.ts +89 -0
  36. package/extensions/auth/tests/controllers/me.test.ts +272 -0
  37. package/extensions/auth/tests/controllers/register.test.ts +45 -0
  38. package/extensions/auth/tests/database/db.test.ts +64 -0
  39. package/extensions/auth/tests/database/differentAdminCreds.test.ts +51 -0
  40. package/extensions/auth/tests/middlewares/adminAuthGuard.test.ts +157 -0
  41. package/extensions/auth/tests/middlewares/publicAllowBasic.test.ts +137 -0
  42. package/extensions/auth/tests/middlewares/publicPreventBasic.test.ts +108 -0
  43. package/extensions/auth/tests/socialBlog.test.ts +253 -0
  44. package/extensions/auth/tests/utils/addArticles.ts +22 -0
  45. package/extensions/auth/tests/utils/addSocialBlogArticles.ts +52 -0
  46. package/extensions/auth/tests/utils/data/articles.ts +65 -0
  47. package/extensions/auth/tests/utils/data/socialBlogArticles.ts +56 -0
  48. package/extensions/auth/utils.ts +17 -0
  49. package/extensions/auth/workflows/baseWorkflow.ts +159 -0
  50. package/extensions/auth/workflows/hashHandlerWorkflows.ts +29 -0
  51. package/extensions/auth/workflows/index.ts +29 -0
  52. package/extensions/auth/workflows/meAliasWorkflows.ts +48 -0
  53. package/extensions/auth/workflows/policiesWorkflows.ts +240 -0
  54. package/extensions/auth/workflows/utils.ts +306 -0
  55. package/lobb.ts +108 -0
  56. package/package.json +33 -6
  57. package/public/public/vite.svg +1 -0
  58. package/scripts/postpublish.sh +12 -0
  59. package/scripts/prepublish.sh +17 -0
  60. package/studio/app.html +12 -0
  61. package/studio/routes/+layout.svelte +7 -0
  62. package/studio/routes/+layout.ts +1 -0
  63. package/studio/routes/[...path]/+page.svelte +6 -0
  64. package/svelte.config.js +23 -7
  65. package/todo.md +37 -0
  66. package/tsconfig.app.json +3 -3
  67. package/tsconfig.json +9 -10
  68. package/vite.config.ts +4 -8
  69. package/.env +0 -1
  70. package/components.json +0 -16
  71. package/index.html +0 -13
  72. package/src/app.css +0 -124
  73. package/src/main.ts +0 -14
  74. /package/{src → extensions/auth/studio}/auth.ts +0 -0
  75. /package/{src → extensions/auth/studio}/index.ts +0 -0
  76. /package/{src → extensions/auth/studio}/lib/components/pages/loginPage/index.svelte +0 -0
  77. /package/{src → extensions/auth/studio}/lib/components/pages/settings/index.svelte +0 -0
  78. /package/{src → extensions/auth/studio}/lib/components/pages/settings/pages/activityFeed.svelte +0 -0
  79. /package/{src → extensions/auth/studio}/lib/components/pages/settings/pages/rolesAndPermissions.svelte +0 -0
  80. /package/{src → extensions/auth/studio}/lib/components/pages/settings/pages/users.svelte +0 -0
  81. /package/{src → extensions/auth/studio}/lib/components/pages/userSettings/components/account.svelte +0 -0
  82. /package/{src → extensions/auth/studio}/lib/components/pages/userSettings/components/profile.svelte +0 -0
  83. /package/{src → extensions/auth/studio}/lib/components/pages/userSettings/index.svelte +0 -0
  84. /package/{src → extensions/auth/studio}/lib/index.ts +0 -0
  85. /package/{src → extensions/auth/studio}/lib/utils.ts +0 -0
  86. /package/{src → extensions/auth/studio}/onStartup.ts +0 -0
@@ -0,0 +1,240 @@
1
+ import type { Lobb, Workflow } from "@lobb-js/core";
2
+ import type { Context } from "hono";
3
+ import type { ExtensionConfig, User } from "../config/extensionConfigSchema.ts";
4
+ import { handlePolicy, handleReadFields } from "./utils.ts";
5
+
6
+ export function getPoliciesWorkflows(extensionConfig: ExtensionConfig): Workflow[] {
7
+ return [
8
+ {
9
+ name: "auth_policyPreCreate",
10
+ eventName: "core.store.preCreateOne",
11
+ handler: async (input, ctx) => {
12
+ if (input.triggeredBy === "API") {
13
+ const context = input.context as Context;
14
+ const lobb = context.get("lobb") as Lobb;
15
+ const user = context.get("auth_user") as User | undefined;
16
+
17
+ const output = handlePolicy({
18
+ action: "create",
19
+ collectionName: input.collectionName,
20
+ role: user?.role,
21
+ user,
22
+ input,
23
+ lobb,
24
+ ctx,
25
+ extensionConfig,
26
+ });
27
+
28
+ if (output && output.payload) {
29
+ input.data = output.payload;
30
+ }
31
+ }
32
+ return input;
33
+ },
34
+ },
35
+ {
36
+ name: "auth_policyPreFindAll",
37
+ eventName: "core.store.preFindAll",
38
+ handler: async (input, ctx) => {
39
+ if (input.triggeredBy === "API") {
40
+ const context = input.context as Context;
41
+ const lobb = context.get("lobb") as Lobb;
42
+ const user = context.get("auth_user") as User | undefined;
43
+
44
+ const output = handlePolicy({
45
+ action: "read",
46
+ collectionName: input.collectionName,
47
+ role: user?.role,
48
+ user,
49
+ input,
50
+ lobb,
51
+ ctx,
52
+ extensionConfig,
53
+ });
54
+
55
+ if (output && output.filter) {
56
+ input.filter = output.filter;
57
+ }
58
+ }
59
+ return input;
60
+ },
61
+ },
62
+ {
63
+ name: "auth_policyPreFindOne",
64
+ eventName: "core.store.preFindOne",
65
+ handler: async (input, ctx) => {
66
+ if (input.triggeredBy === "API") {
67
+ const context = input.context as Context;
68
+ const lobb = context.get("lobb") as Lobb;
69
+ const user = context.get("auth_user") as User | undefined;
70
+
71
+ // pass if the user is effecting himself
72
+ const currentUser = input.id === user?.id;
73
+ if (input.collectionName === "auth_users" && currentUser) {
74
+ return input;
75
+ }
76
+
77
+ const output = handlePolicy({
78
+ action: "read",
79
+ collectionName: input.collectionName,
80
+ role: user?.role,
81
+ user,
82
+ input,
83
+ lobb,
84
+ ctx,
85
+ extensionConfig,
86
+ });
87
+
88
+ if (output && output.filter) {
89
+ input.filter = output.filter;
90
+ }
91
+ }
92
+ return input;
93
+ },
94
+ },
95
+ {
96
+ name: "auth_policyPreUpdate",
97
+ eventName: "core.store.preUpdateOne",
98
+ handler: async (input, ctx) => {
99
+ if (input.triggeredBy === "API") {
100
+ const context = input.context as Context;
101
+ const lobb = context.get("lobb") as Lobb;
102
+ const user = context.get("auth_user") as User | undefined;
103
+
104
+ // pass if the user is effecting himself
105
+ const currentUser = input.id === user?.id;
106
+ if (input.collectionName === "auth_users" && currentUser) {
107
+ return input;
108
+ }
109
+
110
+ handlePolicy({
111
+ action: "update",
112
+ collectionName: input.collectionName,
113
+ role: user?.role,
114
+ user,
115
+ input,
116
+ lobb,
117
+ ctx,
118
+ extensionConfig,
119
+ });
120
+ }
121
+ return input;
122
+ },
123
+ },
124
+ {
125
+ name: "auth_policyPreDelete",
126
+ eventName: "core.store.preDeleteOne",
127
+ handler: async (input, ctx) => {
128
+ if (input.triggeredBy === "API") {
129
+ const context = input.context as Context;
130
+ const lobb = context.get("lobb") as Lobb;
131
+ const user = context.get("auth_user") as User | undefined;
132
+
133
+ // pass if the user is effecting himself
134
+ const currentUser = input.id === user?.id;
135
+ if (input.collectionName === "auth_users" && currentUser) {
136
+ return input;
137
+ }
138
+
139
+ handlePolicy({
140
+ action: "delete",
141
+ collectionName: input.collectionName,
142
+ role: user?.role,
143
+ user,
144
+ input,
145
+ lobb,
146
+ ctx,
147
+ extensionConfig,
148
+ });
149
+ }
150
+ return input;
151
+ },
152
+ },
153
+ // handling read fields property
154
+ {
155
+ name: "auth_policyPostQuery",
156
+ eventName: "core.store.findAll",
157
+ handler: async (input, ctx) => {
158
+ if (input.triggeredBy === "API") {
159
+ const context = input.context as Context;
160
+ const user = context.get("auth_user") as User | undefined;
161
+ input.data = handleReadFields(
162
+ user?.role,
163
+ input.collectionName,
164
+ input.data,
165
+ extensionConfig,
166
+ );
167
+ }
168
+ return input;
169
+ },
170
+ },
171
+ {
172
+ name: "auth_policyPostRead",
173
+ eventName: "core.store.findOne",
174
+ handler: async (input, ctx) => {
175
+ if (input.triggeredBy === "API") {
176
+ const context = input.context as Context;
177
+ const user = context.get("auth_user") as User | undefined;
178
+ input.data = handleReadFields(
179
+ user?.role,
180
+ input.collectionName,
181
+ input.data,
182
+ extensionConfig,
183
+ );
184
+ }
185
+ return input;
186
+ },
187
+ },
188
+ {
189
+ name: "auth_policyPostReadForCreate",
190
+ eventName: "core.store.createOne",
191
+ handler: async (input, ctx) => {
192
+ if (input.triggeredBy === "API") {
193
+ const context = input.context as Context;
194
+ const user = context.get("auth_user") as User | undefined;
195
+ input.data = handleReadFields(
196
+ user?.role,
197
+ input.collectionName,
198
+ input.data,
199
+ extensionConfig,
200
+ );
201
+ }
202
+ return input;
203
+ },
204
+ },
205
+ {
206
+ name: "auth_policyPostReadForUpdate",
207
+ eventName: "core.store.updateOne",
208
+ handler: async (input, ctx) => {
209
+ if (input.triggeredBy === "API") {
210
+ const context = input.context as Context;
211
+ const user = context.get("auth_user") as User | undefined;
212
+ input.data = handleReadFields(
213
+ user?.role,
214
+ input.collectionName,
215
+ input.data,
216
+ extensionConfig,
217
+ );
218
+ }
219
+ return input;
220
+ },
221
+ },
222
+ {
223
+ name: "auth_policyPostReadForDelete",
224
+ eventName: "core.store.updateOne",
225
+ handler: async (input, ctx) => {
226
+ if (input.triggeredBy === "API") {
227
+ const context = input.context as Context;
228
+ const user = context.get("auth_user") as User | undefined;
229
+ input.data = handleReadFields(
230
+ user?.role,
231
+ input.collectionName,
232
+ input.data,
233
+ extensionConfig,
234
+ );
235
+ }
236
+ return input;
237
+ },
238
+ },
239
+ ];
240
+ }
@@ -0,0 +1,306 @@
1
+ import type { EventContext, Filter, Lobb } from "@lobb-js/core";
2
+ import type {
3
+ CollectionPermissionActionsKeys,
4
+ ExtensionConfig,
5
+ User,
6
+ } from "../config/extensionConfigSchema.ts";
7
+ import { LobbError } from "@lobb-js/core";
8
+
9
+ interface HandlePolicyProps {
10
+ ctx: EventContext;
11
+ collectionName: string;
12
+ action: CollectionPermissionActionsKeys;
13
+ user: User | undefined;
14
+ input: any | undefined;
15
+ role?: string;
16
+ lobb: Lobb;
17
+ extensionConfig: ExtensionConfig;
18
+ }
19
+
20
+ interface HandlePolicyOutput {
21
+ payload?: Record<string, unknown>;
22
+ filter?: Filter;
23
+ }
24
+
25
+ export function handlePolicy({
26
+ ctx,
27
+ collectionName,
28
+ action,
29
+ user,
30
+ input,
31
+ lobb,
32
+ role = "public",
33
+ extensionConfig,
34
+ }: HandlePolicyProps): HandlePolicyOutput | void {
35
+ if (role === "admin") {
36
+ return;
37
+ }
38
+
39
+ const config = extensionConfig;
40
+ const currentRole = config.roles[role];
41
+
42
+ if (typeof currentRole === "undefined") {
43
+ throw new ctx.LobbError({
44
+ code: "FORBIDDEN",
45
+ message: "Your role is not recognized by the system.",
46
+ });
47
+ }
48
+
49
+ const currentRolePermission = currentRole.permissions;
50
+
51
+ if (currentRolePermission === true) {
52
+ return;
53
+ }
54
+
55
+ const collectionPermission = currentRolePermission[collectionName];
56
+
57
+ if (typeof collectionPermission === "undefined") {
58
+ throw new ctx.LobbError({
59
+ code: "FORBIDDEN",
60
+ message: "You do not have permission to perform this action.",
61
+ });
62
+ }
63
+
64
+ if (collectionPermission === true) {
65
+ return;
66
+ }
67
+
68
+ const permissionAction = collectionPermission[action];
69
+
70
+ if (typeof permissionAction === "undefined") {
71
+ throw new ctx.LobbError({
72
+ code: "FORBIDDEN",
73
+ message: "You do not have permission to perform this action.",
74
+ });
75
+ }
76
+
77
+ if (typeof permissionAction === "boolean") {
78
+ if (permissionAction === false) {
79
+ throw new ctx.LobbError({
80
+ code: "FORBIDDEN",
81
+ message: "You do not have permission to perform this action.",
82
+ });
83
+ }
84
+
85
+ return;
86
+ }
87
+
88
+ if (action === "create") {
89
+ runGuard(user?.role, input.collectionName, "create", {
90
+ payload: input.data,
91
+ user: user,
92
+ }, extensionConfig);
93
+
94
+ handleFields(user?.role, input.collectionName, "create", input.data, extensionConfig);
95
+
96
+ const data = handleMutate(
97
+ user?.role,
98
+ input.collectionName,
99
+ "create",
100
+ input.data,
101
+ user,
102
+ extensionConfig,
103
+ );
104
+
105
+ return {
106
+ payload: data,
107
+ };
108
+ } else if (action === "read") {
109
+ const readFilter = getFilter(user?.role, input.collectionName, "read", extensionConfig);
110
+ const filter = lobb.utils.renderTemplateDeep(
111
+ readFilter,
112
+ {
113
+ user,
114
+ },
115
+ );
116
+
117
+ return {
118
+ filter,
119
+ };
120
+ } else if (action === "update") {
121
+ runGuard(user?.role, input.collectionName, "update", {
122
+ payload: input.data,
123
+ user: user,
124
+ }, extensionConfig);
125
+
126
+ handleFields(user?.role, input.collectionName, "update", input.data, extensionConfig);
127
+
128
+ const data = handleMutate(
129
+ user?.role,
130
+ input.collectionName,
131
+ "update",
132
+ input.data,
133
+ user,
134
+ extensionConfig,
135
+ );
136
+
137
+ return {
138
+ payload: data,
139
+ };
140
+ } else if (action === "delete") {
141
+ } else {
142
+ throw new Error(
143
+ `The (${action}) action is not implemented in the (auth) extension (handlePolicy) function`,
144
+ );
145
+ }
146
+ }
147
+
148
+ export function getFilter(
149
+ role: string = "public",
150
+ collectionName: string,
151
+ action: "read",
152
+ extensionConfig: ExtensionConfig,
153
+ ) {
154
+ const config = extensionConfig;
155
+ const permissions = config.roles[role]?.permissions;
156
+
157
+ if (permissions && permissions !== true) {
158
+ const collectionPermission = permissions[collectionName];
159
+ if (collectionPermission && collectionPermission !== true) {
160
+ const permission = collectionPermission[action];
161
+ if (permission && permission !== true) {
162
+ return permission.filter;
163
+ }
164
+ }
165
+ }
166
+ }
167
+
168
+ export function runGuard(
169
+ role: string = "public",
170
+ collectionName: string,
171
+ action: "create" | "update",
172
+ context: { payload: Record<string, unknown>; user?: User },
173
+ extensionConfig: ExtensionConfig,
174
+ ) {
175
+ const config = extensionConfig;
176
+ const permissions = config.roles[role]?.permissions;
177
+
178
+ if (permissions && permissions !== true) {
179
+ const collectionPermission = permissions[collectionName];
180
+ if (collectionPermission && collectionPermission !== true) {
181
+ const permission = collectionPermission[action];
182
+ if (permission && permission !== true) {
183
+ if (permission.payloadGuard) {
184
+ const result = permission.payloadGuard(context);
185
+ if (!result) {
186
+ throw new LobbError({
187
+ code: "FORBIDDEN",
188
+ message: "You do not have permission to perform this action.",
189
+ });
190
+ }
191
+ }
192
+ }
193
+ }
194
+ }
195
+ }
196
+
197
+ export function handleFields(
198
+ role: string = "public",
199
+ collectionName: string,
200
+ action: "create" | "update",
201
+ payload: Record<string, unknown>,
202
+ extensionConfig: ExtensionConfig,
203
+ ) {
204
+ const config = extensionConfig;
205
+ const permissions = config.roles[role]?.permissions;
206
+
207
+ if (permissions && permissions !== true) {
208
+ const collectionPermission = permissions[collectionName];
209
+ if (collectionPermission && collectionPermission !== true) {
210
+ const permission = collectionPermission[action];
211
+ if (permission && permission !== true) {
212
+ if (permission.fields) {
213
+ const fields = permission.fields;
214
+ const allowedFields = Object.keys(fields);
215
+ const existingFields = Object.keys(payload);
216
+ // add the handler logic of the fields
217
+ for (const fieldName of existingFields) {
218
+ if (!allowedFields.includes(fieldName)) {
219
+ throw new LobbError({
220
+ code: "FORBIDDEN",
221
+ message:
222
+ `You do not have permission to modify the field (${fieldName}).`,
223
+ });
224
+ }
225
+ }
226
+ }
227
+ }
228
+ }
229
+ }
230
+ }
231
+
232
+ export function handleMutate(
233
+ role: string = "public",
234
+ collectionName: string,
235
+ action: "create" | "update",
236
+ payload: Record<string, unknown>,
237
+ user: User | undefined,
238
+ extensionConfig: ExtensionConfig,
239
+ ) {
240
+ const config = extensionConfig;
241
+ const permissions = config.roles[role]?.permissions;
242
+ const returnedPayload: Record<string, unknown> = structuredClone(payload);
243
+
244
+ if (permissions && permissions !== true) {
245
+ const collectionPermission = permissions[collectionName];
246
+ if (collectionPermission && collectionPermission !== true) {
247
+ const permission = collectionPermission[action];
248
+ if (permission && permission !== true) {
249
+ if (permission.mutate) {
250
+ for (
251
+ const [fieldName, mutateFn] of Object.entries(permission.mutate)
252
+ ) {
253
+ returnedPayload[fieldName] = mutateFn({
254
+ value: payload[fieldName],
255
+ payload,
256
+ user,
257
+ });
258
+ }
259
+ }
260
+ }
261
+ }
262
+ }
263
+
264
+ return returnedPayload;
265
+ }
266
+
267
+ export function handleReadFields(
268
+ role = "public",
269
+ collectionName: string,
270
+ payload: Record<string, unknown> | Record<string, unknown>[],
271
+ extensionConfig: ExtensionConfig,
272
+ ) {
273
+ // filter the payload based on fields
274
+ const config = extensionConfig;
275
+ let clonedPayload = structuredClone(payload);
276
+
277
+ const permissions = config.roles[role]?.permissions;
278
+ if (permissions && typeof permissions !== "boolean") {
279
+ const collectionPermission = permissions[collectionName];
280
+ if (collectionPermission && typeof collectionPermission !== "boolean") {
281
+ const readPermission = collectionPermission.read;
282
+ if (readPermission && typeof readPermission !== "boolean") {
283
+ if (readPermission.fields) {
284
+ const allowedFields = Object.keys(readPermission.fields);
285
+ if (Array.isArray(payload)) {
286
+ clonedPayload = payload.map((item: Record<string, unknown>) =>
287
+ Object.fromEntries(
288
+ Object.entries(item).filter(([key]) =>
289
+ allowedFields.includes(key)
290
+ ),
291
+ )
292
+ );
293
+ } else {
294
+ clonedPayload = Object.fromEntries(
295
+ Object.entries(payload).filter(([key]) =>
296
+ allowedFields.includes(key)
297
+ ),
298
+ );
299
+ }
300
+ }
301
+ }
302
+ }
303
+ }
304
+
305
+ return clonedPayload;
306
+ }
package/lobb.ts ADDED
@@ -0,0 +1,108 @@
1
+ import { Lobb } from "@lobb-js/core";
2
+ import { auth } from "./extensions/auth/index.ts";
3
+
4
+ Lobb.init({
5
+ project: {
6
+ name: "Social To Courier",
7
+ force_sync: true,
8
+ },
9
+ database: {
10
+ host: "localhost",
11
+ port: 5432,
12
+ username: "test",
13
+ password: "test",
14
+ database: "social_to_courier",
15
+ },
16
+ web_server: {
17
+ host: "0.0.0.0",
18
+ port: 3000,
19
+ cors: {
20
+ origin: "*",
21
+ },
22
+ },
23
+ extensions: [
24
+ auth({
25
+ admin: {
26
+ email: "admin@example.com",
27
+ password: "admin",
28
+ },
29
+ extend_users: {
30
+ fields: {
31
+ instagram_user_id: {
32
+ type: "string",
33
+ length: 255,
34
+ },
35
+ instagram_token: {
36
+ type: "string",
37
+ length: 255,
38
+ },
39
+ },
40
+ },
41
+ roles: {
42
+ public: {
43
+ permissions: true,
44
+ },
45
+ },
46
+ }),
47
+ ],
48
+ collections: {
49
+ articles: {
50
+ indexes: {},
51
+ fields: {
52
+ id: {
53
+ type: "integer",
54
+ },
55
+ image: {
56
+ type: "string",
57
+ length: 255,
58
+ },
59
+ title: {
60
+ type: "string",
61
+ length: 255,
62
+ validators: {
63
+ required: true,
64
+ },
65
+ },
66
+ description: {
67
+ type: "string",
68
+ length: 255,
69
+ },
70
+ body: {
71
+ type: "string",
72
+ length: 255,
73
+ validators: {
74
+ required: true,
75
+ },
76
+ },
77
+ status: {
78
+ type: "string",
79
+ length: 255,
80
+ validators: {
81
+ enum: ["public", "private"],
82
+ },
83
+ },
84
+ },
85
+ },
86
+ comments: {
87
+ indexes: {},
88
+ fields: {
89
+ id: {
90
+ type: "integer",
91
+ },
92
+ body: {
93
+ type: "string",
94
+ length: 255,
95
+ validators: {
96
+ required: true,
97
+ },
98
+ },
99
+ article_id: {
100
+ type: "integer",
101
+ validators: {
102
+ required: true,
103
+ },
104
+ },
105
+ },
106
+ },
107
+ },
108
+ });
package/package.json CHANGED
@@ -1,23 +1,50 @@
1
1
  {
2
2
  "name": "@lobb-js/lobb-ext-auth",
3
- "version": "0.1.67",
3
+ "version": "0.2.2",
4
+ "license": "AGPL-3.0-only",
4
5
  "type": "module",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
5
9
  "exports": {
6
- ".": "./src/index.ts"
10
+ ".": "./extensions/auth/index.ts",
11
+ "./studio": {
12
+ "svelte": "./dist/index.js",
13
+ "types": "./dist/index.d.ts"
14
+ }
7
15
  },
8
16
  "scripts": {
9
- "dev": "vite",
10
- "build": "vite build",
17
+ "test": "bun run test:lobb && bun run test:studio",
18
+ "test:lobb": "bun test extensions/auth/tests",
19
+ "test:studio": "bun --bun playwright test --config extensions/auth/studio/tests/playwright.config.cjs",
20
+ "dev": "bun run lobb.ts",
21
+ "start": "LOBB_MODE=prod bun run lobb.ts",
22
+ "prepare": "svelte-kit sync || echo ''",
11
23
  "preview": "vite preview",
12
- "check": "svelte-check --tsconfig ./tsconfig.app.json && tsc -p tsconfig.node.json"
24
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
25
+ "prepublishOnly": "./scripts/prepublish.sh",
26
+ "postpublish": "./scripts/postpublish.sh",
27
+ "package": "svelte-package --input extensions/auth/studio",
28
+ "dev:studio": "vite dev",
29
+ "build:studio": "vite build"
30
+ },
31
+ "dependencies": {
32
+ "@lobb-js/core": "^0.13.3",
33
+ "argon2": "^0.40.3",
34
+ "hono": "^4.7.0"
13
35
  },
14
36
  "devDependencies": {
15
- "@lobb-js/studio": "0.6.0",
37
+ "@lobb-js/studio": "^0.7.2",
16
38
  "@lucide/svelte": "^0.563.1",
39
+ "@playwright/test": "^1.58.2",
40
+ "@sveltejs/adapter-node": "^5.5.4",
41
+ "@sveltejs/kit": "^2.55.0",
17
42
  "@sveltejs/vite-plugin-svelte": "6.2.1",
43
+ "@sveltejs/package": "^2.5.7",
18
44
  "@tailwindcss/vite": "^4.1.18",
19
45
  "@tsconfig/svelte": "^5.0.6",
20
46
  "@types/node": "^24.10.1",
47
+ "bun-types": "latest",
21
48
  "clsx": "^2.1.1",
22
49
  "svelte": "^5.49.1",
23
50
  "svelte-check": "^4.3.4",