@lobb-js/lobb-ext-auth 0.1.58

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 (79) hide show
  1. package/.zed/settings.json +22 -0
  2. package/deno.json +18 -0
  3. package/deno.lock +968 -0
  4. package/lobb/lobb.ts +108 -0
  5. package/lobb/src/collections/activityFeed.ts +53 -0
  6. package/lobb/src/collections/collections.ts +44 -0
  7. package/lobb/src/collections/sessions.ts +34 -0
  8. package/lobb/src/collections/users.ts +44 -0
  9. package/lobb/src/config/config.ts +11 -0
  10. package/lobb/src/config/extensionConfigSchema.ts +47 -0
  11. package/lobb/src/config/permissionsAction/create.ts +20 -0
  12. package/lobb/src/config/permissionsAction/delete.ts +3 -0
  13. package/lobb/src/config/permissionsAction/read.ts +10 -0
  14. package/lobb/src/config/permissionsAction/update.ts +20 -0
  15. package/lobb/src/database/init.ts +51 -0
  16. package/lobb/src/database/migrations.ts +56 -0
  17. package/lobb/src/database/utils.ts +35 -0
  18. package/lobb/src/extension.json +1 -0
  19. package/lobb/src/meta/meta.ts +11 -0
  20. package/lobb/src/mod.ts +27 -0
  21. package/lobb/src/openapi.ts +469 -0
  22. package/lobb/src/utils.ts +17 -0
  23. package/lobb/src/workflows/baseWorkflow.ts +159 -0
  24. package/lobb/src/workflows/hashHandlerWorkflows.ts +29 -0
  25. package/lobb/src/workflows/index.ts +28 -0
  26. package/lobb/src/workflows/meAliasWorkflows.ts +48 -0
  27. package/lobb/src/workflows/policiesWorkflows.ts +228 -0
  28. package/lobb/src/workflows/utils.ts +297 -0
  29. package/lobb/tests/collections/extend_users_collection.test.ts +63 -0
  30. package/lobb/tests/configs/auth.ts +72 -0
  31. package/lobb/tests/configs/auth_no_roles.ts +64 -0
  32. package/lobb/tests/configs/auth_public_full_access.ts +68 -0
  33. package/lobb/tests/configs/auth_with_different_admin_creds.ts +80 -0
  34. package/lobb/tests/configs/auth_with_extend_users.ts +80 -0
  35. package/lobb/tests/configs/auth_with_refresh_token.ts +85 -0
  36. package/lobb/tests/configs/auth_with_short_access_token_only.ts +94 -0
  37. package/lobb/tests/configs/auth_with_short_time_refresh_token.ts +85 -0
  38. package/lobb/tests/configs/social_blog.ts +155 -0
  39. package/lobb/tests/controllers/change_password.test.ts +114 -0
  40. package/lobb/tests/controllers/dashboardAccessRoles.test.ts +29 -0
  41. package/lobb/tests/controllers/login.test.ts +103 -0
  42. package/lobb/tests/controllers/logout.test.ts +88 -0
  43. package/lobb/tests/controllers/me.test.ts +275 -0
  44. package/lobb/tests/controllers/register.test.ts +46 -0
  45. package/lobb/tests/database/db.test.ts +68 -0
  46. package/lobb/tests/database/differentAdminCreds.test.ts +50 -0
  47. package/lobb/tests/middlewares/adminAuthGuard.test.ts +160 -0
  48. package/lobb/tests/middlewares/publicAllowBasic.test.ts +142 -0
  49. package/lobb/tests/middlewares/publicPreventBasic.test.ts +111 -0
  50. package/lobb/tests/socialBlog.test.ts +260 -0
  51. package/lobb/tests/utils/addArticles.ts +26 -0
  52. package/lobb/tests/utils/addSocialBlogArticles.ts +60 -0
  53. package/lobb/tests/utils/data/articles.ts +65 -0
  54. package/lobb/tests/utils/data/socialBlogArticles.ts +56 -0
  55. package/package.json +32 -0
  56. package/studio/.env +1 -0
  57. package/studio/README.md +1 -0
  58. package/studio/index.html +13 -0
  59. package/studio/postcss.config.js +6 -0
  60. package/studio/public/vite.svg +1 -0
  61. package/studio/src/auth.ts +57 -0
  62. package/studio/src/index.ts +54 -0
  63. package/studio/src/main.ts +12 -0
  64. package/studio/src/onStartup.ts +25 -0
  65. package/studio/src/pages/loginPage/index.svelte +64 -0
  66. package/studio/src/pages/settings/index.svelte +53 -0
  67. package/studio/src/pages/settings/pages/activityFeed.svelte +21 -0
  68. package/studio/src/pages/settings/pages/rolesAndPermissions.svelte +21 -0
  69. package/studio/src/pages/settings/pages/users.svelte +21 -0
  70. package/studio/src/pages/userSettings/components/account.svelte +106 -0
  71. package/studio/src/pages/userSettings/components/profile.svelte +87 -0
  72. package/studio/src/pages/userSettings/index.svelte +48 -0
  73. package/studio/svelte.config.js +8 -0
  74. package/studio/tailwind.config.ts +93 -0
  75. package/studio/tsconfig.app.json +22 -0
  76. package/studio/tsconfig.json +7 -0
  77. package/studio/tsconfig.node.json +26 -0
  78. package/studio/vite.config.ts +14 -0
  79. package/todo.md +37 -0
@@ -0,0 +1,25 @@
1
+ import type { ExtensionUtils } from "../extension.types";
2
+ import { Auth } from "./auth";
3
+
4
+ export async function onStartup(utils: ExtensionUtils) {
5
+ // logout if we got an Unauthorized response
6
+ const auth = new Auth(utils);
7
+ utils.lobb.onResponse(async (response) => {
8
+ if (response.status === 401) {
9
+ const body = await response.json();
10
+ if (
11
+ body.message === "JWT token has expired" ||
12
+ body.message === "Invalid JWT token"
13
+ ) {
14
+ auth.logout();
15
+ }
16
+ }
17
+ });
18
+ const session = auth.getSession();
19
+ // if user is logged in
20
+ if (session) {
21
+ utils.ctx.extensions.auth.session = session;
22
+ return;
23
+ }
24
+ await auth.logout()
25
+ }
@@ -0,0 +1,64 @@
1
+ <script lang="ts">
2
+ import type { ExtensionProps } from "src/extensions/extension.types";
3
+ import { Auth } from "../../auth";
4
+
5
+ const { utils }: ExtensionProps = $props();
6
+
7
+ let formData = {
8
+ email:
9
+ window.location.hostname === "demo.lobb.app"
10
+ ? "admin@example.com"
11
+ : "",
12
+ password: window.location.hostname === "demo.lobb.app" ? "admin" : "",
13
+ };
14
+
15
+ async function handleOnSubmit(e: Event) {
16
+ e.preventDefault();
17
+ if (!formData.email && !formData.password) {
18
+ utils.toast.error("Please complete all fields");
19
+ return;
20
+ }
21
+
22
+ const auth = new Auth(utils);
23
+ await auth.login(formData);
24
+ }
25
+ </script>
26
+
27
+ <div
28
+ class="fixed left-0 top-0 flex h-screen w-screen items-center justify-center bg-muted"
29
+ >
30
+ <div class="flex w-full max-w-[25rem] flex-col gap-6 p-6">
31
+ <div>
32
+ <div class="text-4xl">Welcome back</div>
33
+ <div>Sign in to your account</div>
34
+ </div>
35
+ <form
36
+ class="flex flex-col gap-6 rounded-md border bg-white p-6"
37
+ onsubmit={handleOnSubmit}
38
+ >
39
+ <div class="flex flex-col gap-2">
40
+ <div>
41
+ <div class="mb-1 text-sm font-medium">Email</div>
42
+ <utils.components.Input
43
+ bind:value={formData.email}
44
+ autocomplete="email"
45
+ placeholder="email@example.com"
46
+ />
47
+ </div>
48
+ <div>
49
+ <div class="mb-1 text-sm font-medium">Password</div>
50
+ <utils.components.Input
51
+ bind:value={formData.password}
52
+ type="password"
53
+ autocomplete="current-password"
54
+ placeholder="••••••••"
55
+ />
56
+ </div>
57
+ </div>
58
+ <utils.components.Button type="submit">
59
+ Sign In
60
+ </utils.components.Button>
61
+ <div class="text-sm underline">Forgot Password?</div>
62
+ </form>
63
+ </div>
64
+ </div>
@@ -0,0 +1,53 @@
1
+ <script lang="ts">
2
+ import type { ExtensionProps } from "src/extensions/extension.types";
3
+ import Users from "./pages/users.svelte";
4
+ import RolesAndPermissions from "./pages/rolesAndPermissions.svelte";
5
+ import ActivityFeed from "./pages/activityFeed.svelte";
6
+
7
+ const props: ExtensionProps = $props();
8
+ const components = props.utils.components;
9
+ const { Sidebar } = components;
10
+ const { Icons } = components;
11
+ const auth_settings_page = $derived(props.utils.location.url.pathname.split("/")[4]);
12
+ const isSmall = $derived(!props.utils.mediaQueries.sm.current);
13
+ </script>
14
+
15
+ <!-- TODO: add the sidebar in here to add these pages
16
+ - users
17
+ - roles and permissions
18
+ - invitation page
19
+ - activity feed
20
+ -->
21
+
22
+ <Sidebar
23
+ title="Auth settings"
24
+ showSearch={false}
25
+ isSelected={(element) => {
26
+ const element_page = element.href?.split("/")[4];
27
+ return element_page === auth_settings_page;
28
+ }}
29
+ data={[
30
+ {
31
+ name: "Users",
32
+ href: "/extensions/auth/settings/users",
33
+ icon: Icons.Users
34
+ },
35
+ {
36
+ name: "roles and permissions",
37
+ href: "/extensions/auth/settings/roles_and_permissions",
38
+ icon: Icons.ShieldUser
39
+ },
40
+ {
41
+ name: "activity feed",
42
+ href: "/extensions/auth/settings/activity_feed",
43
+ icon: Icons.ClipboardList
44
+ },
45
+ ]} >
46
+ {#if auth_settings_page === 'users'}
47
+ <Users {...props} />
48
+ {:else if auth_settings_page === 'roles_and_permissions'}
49
+ <RolesAndPermissions {...props} />
50
+ {:else if auth_settings_page === 'activity_feed'}
51
+ <ActivityFeed {...props} />
52
+ {/if}
53
+ </Sidebar>
@@ -0,0 +1,21 @@
1
+ <script lang="ts">
2
+ import type { ExtensionProps } from "src/extensions/extension.types";
3
+
4
+ const { utils }: ExtensionProps = $props();
5
+ const components = utils.components;
6
+ </script>
7
+
8
+ <div class="flex flex-col gap-4 p-4 h-full">
9
+ <div>
10
+ <div class="text-xl font-bold">Activity Feed</div>
11
+ <div class="text-sm text-muted-foreground">
12
+ Monitor your users Activity Feed.
13
+ </div>
14
+ </div>
15
+ <components.Separator />
16
+ <div class="flex gap-4 border rounded-md overflow-hidden h-full bg-soft">
17
+ <components.DataTable
18
+ collectionName="auth_activity_feed"
19
+ />
20
+ </div>
21
+ </div>
@@ -0,0 +1,21 @@
1
+ <script lang="ts">
2
+ import type { ExtensionProps } from "src/extensions/extension.types";
3
+
4
+ const { utils }: ExtensionProps = $props();
5
+ const components = utils.components;
6
+ </script>
7
+
8
+ <div class="flex flex-col gap-4 p-4 h-full">
9
+ <div>
10
+ <div class="text-xl font-bold">Roles and Permissions</div>
11
+ <div class="text-sm text-muted-foreground">
12
+ Manage the Roles and Permissions of the system.
13
+ </div>
14
+ </div>
15
+ <components.Separator />
16
+ <div class="flex gap-4 border rounded-md overflow-hidden h-full bg-soft">
17
+ <components.DataTable
18
+ collectionName="auth_roles"
19
+ />
20
+ </div>
21
+ </div>
@@ -0,0 +1,21 @@
1
+ <script lang="ts">
2
+ import type { ExtensionProps } from "src/extensions/extension.types";
3
+
4
+ const { utils }: ExtensionProps = $props();
5
+ const components = utils.components;
6
+ </script>
7
+
8
+ <div class="flex flex-col gap-4 p-4 h-full">
9
+ <div>
10
+ <div class="text-xl font-bold">Users</div>
11
+ <div class="text-sm text-muted-foreground">
12
+ Manage the users of the system.
13
+ </div>
14
+ </div>
15
+ <components.Separator />
16
+ <div class="flex gap-4 border rounded-md overflow-hidden h-full bg-soft">
17
+ <components.DataTable
18
+ collectionName="auth_users"
19
+ />
20
+ </div>
21
+ </div>
@@ -0,0 +1,106 @@
1
+ <script lang="ts">
2
+ import type { ExtensionProps } from "src/extensions/extension.types";
3
+ import { onMount } from "svelte";
4
+
5
+ const { utils }: ExtensionProps = $props();
6
+
7
+ let user = $state({
8
+ old_password: "",
9
+ new_password: "",
10
+ });
11
+ const icons = utils.components.Icons;
12
+
13
+ // @ts-ignore: Im sure the session object exist
14
+ const currentUserId = utils.ctx.extensions.auth.session.user.id;
15
+ let loaded = $state(false);
16
+ onMount(async () => {
17
+ const response = await utils.lobb.findOne("auth_users", currentUserId);
18
+ const result = await response.json();
19
+ user = result.data;
20
+ loaded = true;
21
+ });
22
+
23
+ async function onUpdateCLick() {
24
+ if (!user.new_password) {
25
+ utils.toast.error("Make sure you fill the new password");
26
+ return;
27
+ } else if (!user.old_password) {
28
+ utils.toast.error("Make sure you fill the old password");
29
+ return;
30
+ }
31
+
32
+ const result = await utils.lobb.request({
33
+ method: "POST",
34
+ route: "/api/extensions/auth/change_password",
35
+ payload: {
36
+ old_password: user.old_password,
37
+ new_password: user.new_password,
38
+ },
39
+ });
40
+
41
+ if (result.status >= 400) {
42
+ return;
43
+ }
44
+
45
+ utils.toast.success("Account updated successfully.");
46
+ }
47
+ </script>
48
+
49
+ {#if loaded}
50
+ <div class="flex max-w-[40rem] flex-1 flex-col gap-4 overflow-y-visible">
51
+ <div>
52
+ <div class="text-lg font-semibold">Account</div>
53
+ <div class="text-sm text-muted-foreground">
54
+ Update your account settings.
55
+ </div>
56
+ </div>
57
+ <utils.components.Separator />
58
+ <!-- TODO: add prefered language here too -->
59
+ <div class="flex flex-col gap-2">
60
+ <div class="text-sm">Change Password</div>
61
+ <div class="flex gap-4">
62
+ <utils.components.Input
63
+ bind:value={user.old_password}
64
+ placeholder="Old password"
65
+ type="password"
66
+ />
67
+ <utils.components.Input
68
+ bind:value={user.new_password}
69
+ placeholder="New password"
70
+ type="password"
71
+ />
72
+ </div>
73
+ <div class="text-xs text-muted-foreground">
74
+ This is where you can change your password.
75
+ </div>
76
+ </div>
77
+ <utils.components.Button
78
+ class="self-start"
79
+ onclick={onUpdateCLick}
80
+ Icon={icons.Pencil}
81
+ >
82
+ Update Account
83
+ </utils.components.Button>
84
+ </div>
85
+ {:else}
86
+ <div class="flex max-w-[40rem] flex-1 flex-col gap-8 overflow-y-visible">
87
+ <div class="grid gap-2">
88
+ <utils.components.Skeleton class="h-8 w-full max-w-60" />
89
+ <utils.components.Skeleton class="h-4 w-full max-w-96" />
90
+ </div>
91
+ <utils.components.Separator />
92
+ <div class="flex flex-col gap-2">
93
+ <utils.components.Skeleton class="h-4 w-full max-w-36" />
94
+ <utils.components.Skeleton class="h-8 w-full max-w-60" />
95
+ <utils.components.Skeleton class="h-4 w-full max-w-96" />
96
+ </div>
97
+ <div class="flex flex-col gap-2">
98
+ <utils.components.Skeleton class="h-4 w-full max-w-36" />
99
+ <div class="flex gap-4">
100
+ <utils.components.Skeleton class="h-8 w-full max-w-60" />
101
+ <utils.components.Skeleton class="h-8 w-full max-w-60" />
102
+ </div>
103
+ <utils.components.Skeleton class="h-4 w-full max-w-96" />
104
+ </div>
105
+ </div>
106
+ {/if}
@@ -0,0 +1,87 @@
1
+ <script lang="ts">
2
+ import type { ExtensionProps } from "src/extensions/extension.types";
3
+ import { onMount } from "svelte";
4
+
5
+ const { utils }: ExtensionProps = $props();
6
+
7
+ let user = $state({
8
+ name: "",
9
+ });
10
+ const icons = utils.components.Icons;
11
+
12
+ // @ts-ignore: Im sure the session object exist
13
+ const currentUserId = utils.ctx.extensions.auth.session.user.id;
14
+ let loaded = $state(false);
15
+ onMount(async () => {
16
+ const response = await utils.lobb.findOne("auth_users", currentUserId);
17
+ const result = await response.json();
18
+ user = result.data;
19
+ loaded = true;
20
+ });
21
+
22
+ async function onUpdateCLick() {
23
+ // TODO: add the logic of updating some of the current user's information
24
+ const updateObject: any = {};
25
+ updateObject["name"] = user.name;
26
+ const response = await utils.lobb.updateOne(
27
+ "auth_users",
28
+ currentUserId,
29
+ updateObject,
30
+ );
31
+ if (response.status >= 400) {
32
+ const result = await response.json();
33
+ utils.toast.error(result.message);
34
+ return;
35
+ }
36
+ utils.toast.success("Profile updated successfully.");
37
+ }
38
+ </script>
39
+
40
+ {#if loaded}
41
+ <div class="flex max-w-[40rem] flex-1 flex-col gap-4 overflow-y-visible">
42
+ <div>
43
+ <div class="text-lg font-semibold">Profile</div>
44
+ <div class="text-sm text-muted-foreground">
45
+ Edit information that others will see.
46
+ </div>
47
+ </div>
48
+ <utils.components.Separator />
49
+ <!-- TODO: you should add name and other stuff like phone number and stuff like that -->
50
+ <div class="flex flex-col gap-2">
51
+ <div class="text-sm">Full Name</div>
52
+ <utils.components.Input
53
+ placeholder="Full Name"
54
+ bind:value={user.name}
55
+ />
56
+ <div class="text-xs text-muted-foreground">
57
+ This is your public display name. It can be your real name or a
58
+ pseudonym.
59
+ </div>
60
+ </div>
61
+ <utils.components.Button
62
+ class="self-start"
63
+ onclick={onUpdateCLick}
64
+ Icon={icons.Pencil}
65
+ >
66
+ Update Profile
67
+ </utils.components.Button>
68
+ </div>
69
+ {:else}
70
+ <div class="flex max-w-[40rem] flex-1 flex-col gap-8 overflow-y-visible">
71
+ <div class="grid gap-2">
72
+ <utils.components.Skeleton class="h-8 w-full max-w-60" />
73
+ <utils.components.Skeleton class="h-4 w-full max-w-96" />
74
+ </div>
75
+ <utils.components.Separator />
76
+ <div class="flex flex-col gap-2">
77
+ <utils.components.Skeleton class="h-4 w-full max-w-36" />
78
+ <utils.components.Skeleton class="h-8 w-full max-w-60" />
79
+ <utils.components.Skeleton class="h-4 w-full max-w-96" />
80
+ </div>
81
+ <div class="flex flex-col gap-2">
82
+ <utils.components.Skeleton class="h-4 w-full max-w-36" />
83
+ <utils.components.Skeleton class="h-8 w-full max-w-60" />
84
+ <utils.components.Skeleton class="h-4 w-full max-w-96" />
85
+ </div>
86
+ </div>
87
+ {/if}
@@ -0,0 +1,48 @@
1
+ <script lang="ts">
2
+ import type { ExtensionProps } from "src/extensions/extension.types";
3
+ import Profile from "./components/profile.svelte";
4
+ import Account from "./components/account.svelte";
5
+
6
+ const props: ExtensionProps = $props();
7
+ const components = props.utils.components;
8
+ const isSmall = $derived(!props.utils.mediaQueries.sm.current);
9
+
10
+ let selectedView: "profile" | "account" = $state("profile");
11
+ </script>
12
+
13
+ <div class="flex flex-col gap-4 p-4">
14
+ <div>
15
+ <div class="text-xl font-bold">User Settings</div>
16
+ <div class="text-sm text-muted-foreground">
17
+ Manage your user settings.
18
+ </div>
19
+ </div>
20
+ <components.Separator />
21
+ <div class="flex gap-4 {isSmall ? "flex-col" : ""}">
22
+ <div class="flex w-64 {isSmall ? "" : "flex-col"}">
23
+ <components.Button
24
+ onclick={() => (selectedView = "profile")}
25
+ variant="ghost"
26
+ class="flex justify-start text-muted-foreground hover:underline"
27
+ >
28
+ Profile
29
+ </components.Button>
30
+ <components.Button
31
+ onclick={() => (selectedView = "account")}
32
+ variant="ghost"
33
+ class="flex justify-start text-muted-foreground hover:underline"
34
+ >
35
+ Account
36
+ </components.Button>
37
+ </div>
38
+ {#if selectedView === "profile"}
39
+ <Profile {...props} />
40
+ {:else if selectedView === "account"}
41
+ <Account {...props} />
42
+ {:else}
43
+ <div class="font-bold text-red-500">
44
+ The "{selectedView}" view doesnt exist
45
+ </div>
46
+ {/if}
47
+ </div>
48
+ </div>
@@ -0,0 +1,8 @@
1
+ import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
2
+
3
+ /** @type {import("@sveltejs/vite-plugin-svelte").SvelteConfig} */
4
+ export default {
5
+ // Consult https://svelte.dev/docs#compile-time-svelte-preprocess
6
+ // for more information about preprocessors
7
+ preprocess: vitePreprocess(),
8
+ }
@@ -0,0 +1,93 @@
1
+ import { fontFamily } from "tailwindcss/defaultTheme";
2
+ import type { Config } from "tailwindcss";
3
+ import tailwindcssAnimate from "tailwindcss-animate";
4
+
5
+ const config: Config = {
6
+ darkMode: ["class"],
7
+ content: [
8
+ "./src/**/*.{html,js,svelte,ts}",
9
+ // TODO: this part should be removed .. it doesnt make sense
10
+ "../../../packages/studio/src/**/*.{html,js,svelte,ts}",
11
+ ],
12
+ safelist: ["dark"],
13
+ theme: {
14
+ container: {
15
+ center: true,
16
+ padding: "2rem",
17
+ screens: {
18
+ "2xl": "1400px",
19
+ },
20
+ },
21
+ extend: {
22
+ colors: {
23
+ border: "hsl(var(--border) / <alpha-value>)",
24
+ input: "hsl(var(--input) / <alpha-value>)",
25
+ ring: "hsl(var(--ring) / <alpha-value>)",
26
+ background: "hsl(var(--background) / <alpha-value>)",
27
+ foreground: "hsl(var(--foreground) / <alpha-value>)",
28
+ primary: {
29
+ DEFAULT: "hsl(var(--primary) / <alpha-value>)",
30
+ foreground: "hsl(var(--primary-foreground) / <alpha-value>)",
31
+ },
32
+ secondary: {
33
+ DEFAULT: "hsl(var(--secondary) / <alpha-value>)",
34
+ foreground: "hsl(var(--secondary-foreground) / <alpha-value>)",
35
+ },
36
+ destructive: {
37
+ DEFAULT: "hsl(var(--destructive) / <alpha-value>)",
38
+ foreground: "hsl(var(--destructive-foreground) / <alpha-value>)",
39
+ },
40
+ soft: {
41
+ DEFAULT: "hsl(var(--soft) / <alpha-value>)",
42
+ },
43
+ muted: {
44
+ DEFAULT: "hsl(var(--muted) / <alpha-value>)",
45
+ foreground: "hsl(var(--muted-foreground) / <alpha-value>)",
46
+ },
47
+ accent: {
48
+ DEFAULT: "hsl(var(--accent) / <alpha-value>)",
49
+ foreground: "hsl(var(--accent-foreground) / <alpha-value>)",
50
+ },
51
+ popover: {
52
+ DEFAULT: "hsl(var(--popover) / <alpha-value>)",
53
+ foreground: "hsl(var(--popover-foreground) / <alpha-value>)",
54
+ },
55
+ card: {
56
+ DEFAULT: "hsl(var(--card) / <alpha-value>)",
57
+ foreground: "hsl(var(--card-foreground) / <alpha-value>)",
58
+ },
59
+ },
60
+ borderRadius: {
61
+ xl: "calc(var(--radius) + 4px)",
62
+ lg: "var(--radius)",
63
+ md: "calc(var(--radius) - 2px)",
64
+ sm: "calc(var(--radius) - 4px)",
65
+ },
66
+ fontFamily: {
67
+ sans: [...fontFamily.sans],
68
+ },
69
+ keyframes: {
70
+ "accordion-down": {
71
+ from: { height: "0" },
72
+ to: { height: "var(--bits-accordion-content-height)" },
73
+ },
74
+ "accordion-up": {
75
+ from: { height: "var(--bits-accordion-content-height)" },
76
+ to: { height: "0" },
77
+ },
78
+ "caret-blink": {
79
+ "0%,70%,100%": { opacity: "1" },
80
+ "20%,50%": { opacity: "0" },
81
+ },
82
+ },
83
+ animation: {
84
+ "accordion-down": "accordion-down 0.2s ease-out",
85
+ "accordion-up": "accordion-up 0.2s ease-out",
86
+ "caret-blink": "caret-blink 1.25s ease-out infinite",
87
+ },
88
+ },
89
+ },
90
+ plugins: [tailwindcssAnimate],
91
+ };
92
+
93
+ export default config;
@@ -0,0 +1,22 @@
1
+ {
2
+ "extends": "@tsconfig/svelte/tsconfig.json",
3
+ "compilerOptions": {
4
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
5
+ "target": "ES2022",
6
+ "useDefineForClassFields": true,
7
+ "module": "ESNext",
8
+ "types": ["svelte", "vite/client"],
9
+ "noEmit": true,
10
+ "allowArbitraryExtensions": true,
11
+ /**
12
+ * Typecheck JS in `.svelte` and `.js` files by default.
13
+ * Disable checkJs if you'd like to use dynamic types in JS.
14
+ * Note that setting allowJs false does not prevent the use
15
+ * of JS in `.svelte` files.
16
+ */
17
+ "allowJs": true,
18
+ "checkJs": true,
19
+ "moduleDetection": "force"
20
+ },
21
+ "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"]
22
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "files": [],
3
+ "references": [
4
+ { "path": "./tsconfig.app.json" },
5
+ { "path": "./tsconfig.node.json" }
6
+ ]
7
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "compilerOptions": {
3
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
4
+ "target": "ES2023",
5
+ "lib": ["ES2023"],
6
+ "module": "ESNext",
7
+ "types": ["node"],
8
+ "skipLibCheck": true,
9
+
10
+ /* Bundler mode */
11
+ "moduleResolution": "bundler",
12
+ "allowImportingTsExtensions": true,
13
+ "verbatimModuleSyntax": true,
14
+ "moduleDetection": "force",
15
+ "noEmit": true,
16
+
17
+ /* Linting */
18
+ "strict": true,
19
+ "noUnusedLocals": true,
20
+ "noUnusedParameters": true,
21
+ "erasableSyntaxOnly": true,
22
+ "noFallthroughCasesInSwitch": true,
23
+ "noUncheckedSideEffectImports": true
24
+ },
25
+ "include": ["vite.config.ts"]
26
+ }
@@ -0,0 +1,14 @@
1
+ import { defineConfig } from "vite";
2
+ import { svelte } from "@sveltejs/vite-plugin-svelte";
3
+ import path from "path";
4
+
5
+ // https://vite.dev/config/
6
+ export default defineConfig({
7
+ plugins: [svelte()],
8
+ resolve: {
9
+ alias: {
10
+ // TODO: remove this. this prevents this app from being portable
11
+ $lib: path.resolve("../../../packages/studio/src/lib"),
12
+ },
13
+ },
14
+ });
package/todo.md ADDED
@@ -0,0 +1,37 @@
1
+ # high priority
2
+
3
+ - remove the `dashboard_access_roles` and just put it in the specific role in the `roles` property
4
+ - currently we have the payloadGuard. you can later implement the `recordGuard`
5
+ for `update` and `delete`
6
+ - implement rotating refresh token mechanism
7
+ - you can implement the firebase adapter and get all other adapters
8
+ - check `https://passkeys.dev/`. the new standart to abandon passwords
9
+ - prevent any one from creating a user with the admin role
10
+
11
+ # low priority
12
+
13
+ - add basic authentication in lobb. or at least make something like it. where
14
+ you have a users.json file and those will be the users without creating a
15
+ users or anything like that. its much simpler for simpler usage
16
+ - the collection_name property in the refresh_token property default value in
17
+ the schema doent work. its similar to the issue of the auth collection name.
18
+ although Im adding a default value to that property. but its value is
19
+ undefined for some reason. investigate it
20
+ - remove keep only the user id in the payload of the access and refresh tokens
21
+ - rotational refresh tokens where the refresh token is changes every time its
22
+ used to refresh an access token
23
+ - prepare the views directory for extensions in a better way. now there is a way
24
+ to view all component you have in an isolated manner. and when you run
25
+ `npm run build` it will generate a js compiled version of the svelte
26
+ component.
27
+ - for now you need to import the main css file in all of the components in order
28
+ for tailwind stuff to be indluded in the main style.css. but in the future you
29
+ should import all component in an index file and include the main css there
30
+ and force vite to create seperate chunks for each imported svelte compoenent
31
+ there. so that you dont get one bundle because you need them seperated
32
+ - change the views from svelte files into directories that holds index.svelte
33
+ files. (this is better because maybe in the future you want to modularize or
34
+ split your code or have other files. so they will all be organized inside that
35
+ directory and you dont need to have a svelte file and then have a directory
36
+ with the same name of that file to hold all the imports of that svelte file.
37
+ its better to have them all stored in one directory)