@lobb-js/lobb-ext-storage 0.5.8 → 0.8.1

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 (64) hide show
  1. package/.github/workflows/create_tag_on_version_change.yaml +45 -0
  2. package/.github/workflows/publish_npm_package.yaml +28 -0
  3. package/.vscode/settings.json +5 -0
  4. package/CHANGELOG.md +150 -29
  5. package/README.md +1 -35
  6. package/extensions/storage/adapters/index.ts +18 -0
  7. package/extensions/storage/adapters/localAdapter.ts +60 -0
  8. package/extensions/storage/adapters/storageAdapter.ts +13 -0
  9. package/extensions/storage/collections/fileSystem.ts +58 -0
  10. package/extensions/storage/collections/index.ts +12 -0
  11. package/extensions/storage/config/extensionConfigSchema.ts +15 -0
  12. package/extensions/storage/index.ts +26 -0
  13. package/extensions/storage/init.ts +6 -0
  14. package/extensions/storage/meta.ts +5 -0
  15. package/extensions/storage/migrations.ts +3 -0
  16. package/extensions/storage/openapi.ts +84 -0
  17. package/extensions/storage/studio/tests/fileManager.spec.ts +23 -0
  18. package/extensions/storage/studio/tests/package.json +1 -0
  19. package/extensions/storage/studio/tests/playwright.config.cjs +27 -0
  20. package/extensions/storage/studioExtension.json +1 -0
  21. package/extensions/storage/tests/configs/simple.ts +95 -0
  22. package/extensions/storage/tests/directories.test.ts +156 -0
  23. package/extensions/storage/tests/extraFormData.test.ts +47 -0
  24. package/extensions/storage/tests/files/rose.jpeg +0 -0
  25. package/extensions/storage/tests/files.test.ts +292 -0
  26. package/extensions/storage/tests/forceUpload.test.ts +72 -0
  27. package/extensions/storage/tests/massRemove.test.ts +189 -0
  28. package/extensions/storage/tests/meta.test.ts +26 -0
  29. package/extensions/storage/tests/recursiveDeleteMany.test.ts +208 -0
  30. package/extensions/storage/tests/recursiveDeleteOne.test.ts +206 -0
  31. package/extensions/storage/tests/storage/127 +0 -0
  32. package/extensions/storage/types.ts +11 -0
  33. package/extensions/storage/utils.ts +87 -0
  34. package/extensions/storage/workflows/controllers.ts +103 -0
  35. package/extensions/storage/workflows/index.ts +10 -0
  36. package/extensions/storage/workflows/services.ts +182 -0
  37. package/lobb.ts +54 -0
  38. package/package.json +32 -9
  39. package/scripts/postpublish.sh +12 -0
  40. package/scripts/prepublish.sh +17 -0
  41. package/studio/app.html +12 -0
  42. package/studio/routes/+layout.svelte +7 -0
  43. package/studio/routes/+layout.ts +1 -0
  44. package/studio/routes/[...path]/+page.svelte +6 -0
  45. package/svelte.config.js +23 -7
  46. package/todo.md +36 -0
  47. package/tsconfig.app.json +3 -3
  48. package/tsconfig.json +11 -5
  49. package/vite.config.ts +4 -10
  50. package/components.json +0 -16
  51. package/index.html +0 -13
  52. package/src/app.css +0 -124
  53. package/src/main.ts +0 -14
  54. /package/{src → extensions/storage/studio}/extension.types.ts +0 -0
  55. /package/{src → extensions/storage/studio}/index.ts +0 -0
  56. /package/{src → extensions/storage/studio}/lib/components/childrenFileExplorer.svelte +0 -0
  57. /package/{src → extensions/storage/studio}/lib/components/explorerNotSupported.svelte +0 -0
  58. /package/{src → extensions/storage/studio}/lib/components/fileExplorer.svelte +0 -0
  59. /package/{src → extensions/storage/studio}/lib/components/fileIcon.svelte +0 -0
  60. /package/{src → extensions/storage/studio}/lib/components/fileManagerBreadCrumbs.svelte +0 -0
  61. /package/{src → extensions/storage/studio}/lib/components/foreignKeyComponent.svelte +0 -0
  62. /package/{src → extensions/storage/studio}/lib/components/pages/fileExplorerPage.svelte +0 -0
  63. /package/{src → extensions/storage/studio}/lib/index.ts +0 -0
  64. /package/{src → extensions/storage/studio}/lib/utils.ts +0 -0
@@ -0,0 +1,87 @@
1
+ import type { Context } from "hono";
2
+ import type { Lobb } from "@lobb-js/core";
3
+ import { StorageAdapter } from "./adapters/index.ts";
4
+ import { LobbError } from "@lobb-js/core";
5
+
6
+ export async function getFileFromRequestBody(
7
+ c: Context,
8
+ ): Promise<File | undefined> {
9
+ const contentType = c.req.header("Content-Type");
10
+ if (contentType?.startsWith("multipart/form-data")) {
11
+ const formData = await c.req.formData();
12
+ const entry = formData.get("file");
13
+ if (entry instanceof File) {
14
+ return entry;
15
+ }
16
+ }
17
+ // return undefined if no file or wrong content type
18
+ return undefined;
19
+ }
20
+
21
+ export async function validatePathExists(path: string, lobb: Lobb) {
22
+ const pathArray = path.split("/").filter(Boolean);
23
+ if (pathArray.length > 0) {
24
+ const directoryName = pathArray[pathArray.length - 1];
25
+ pathArray.pop();
26
+ const directoryPath = "/" + pathArray.join("/");
27
+ const directory = (await lobb.collectionStore.findAll({
28
+ collectionName: "storage_fs",
29
+ params: {
30
+ filter: {
31
+ name: directoryName,
32
+ path: directoryPath,
33
+ },
34
+ },
35
+ })).data[0];
36
+
37
+ if (!directory) {
38
+ throw new LobbError({
39
+ code: "BAD_REQUEST",
40
+ message: `The specified path does not exist. Please create it first.`,
41
+ });
42
+ }
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Ensures a directory path exists, creating it if necessary
48
+ */
49
+ export async function ensurePathExists(path: string, lobb: Lobb): Promise<void> {
50
+ if (!path || path === "/") {
51
+ return; // Root always exists
52
+ }
53
+
54
+ // Parse the path into segments
55
+ const pathArray = path.split("/").filter(Boolean);
56
+
57
+ // Check and create each directory in the path
58
+ let currentPath = "/";
59
+ for (const dirName of pathArray) {
60
+ // Check if this directory exists
61
+ const existing = (await lobb.collectionStore.findAll({
62
+ collectionName: "storage_fs",
63
+ params: {
64
+ filter: {
65
+ name: dirName,
66
+ path: currentPath,
67
+ type: "directory",
68
+ },
69
+ },
70
+ })).data;
71
+
72
+ // Create the directory if it doesn't exist
73
+ if (existing.length === 0) {
74
+ await lobb.collectionStore.createOne({
75
+ collectionName: "storage_fs",
76
+ data: {
77
+ name: dirName,
78
+ path: currentPath,
79
+ type: "directory",
80
+ },
81
+ });
82
+ }
83
+
84
+ // Update current path for next iteration
85
+ currentPath = currentPath + dirName + "/";
86
+ }
87
+ }
@@ -0,0 +1,103 @@
1
+ import type { Lobb, Workflow } from "@lobb-js/core";
2
+ import type { Context } from "hono";
3
+ import type { StorageFsCreateOne, StorageFsFindOne } from "../types.ts";
4
+
5
+ export function getControllersWorkflows(): Workflow[] {
6
+ return [
7
+ {
8
+ name: "storagePreCreateController",
9
+ eventName: "core.controllers.createOne.override",
10
+ handler: async (input, ctx) => {
11
+ if (input.collectionName === "storage_fs") {
12
+ const context = input.context as Context;
13
+ const lobb = context.get("lobb") as Lobb;
14
+ const contentType = context.req.header("Content-Type");
15
+
16
+ if (contentType?.startsWith("multipart/form-data")) {
17
+ const body = await context.req.parseBody({ all: true });
18
+ const fileEntry = body["file"];
19
+
20
+ if (!fileEntry) {
21
+ throw new ctx.LobbError({
22
+ code: "BAD_REQUEST",
23
+ message: "No files were provided.",
24
+ });
25
+ }
26
+
27
+ if (Array.isArray(fileEntry)) {
28
+ throw new ctx.LobbError({
29
+ code: "BAD_REQUEST",
30
+ message: "Only one file can be uploaded at a time.",
31
+ });
32
+ }
33
+
34
+ if (!(fileEntry instanceof File)) {
35
+ throw new ctx.LobbError({
36
+ code: "BAD_REQUEST",
37
+ message: "The file shouldnt be a string",
38
+ });
39
+ }
40
+
41
+ const force = context.req.query("force") === "true";
42
+
43
+ const extraData: Record<string, string> = {};
44
+ for (const [key, val] of Object.entries(body)) {
45
+ if (key !== "file" && key !== "payload" && typeof val === "string") {
46
+ extraData[key] = val;
47
+ }
48
+ }
49
+
50
+ const result = await ctx.lobb.collectionService.createOne<StorageFsCreateOne>({
51
+ collectionName: "storage_fs",
52
+ file: fileEntry,
53
+ force,
54
+ data: extraData,
55
+ });
56
+
57
+ return context.json(result, 201);
58
+ }
59
+ }
60
+ },
61
+ },
62
+ {
63
+ name: "storageFindOneController",
64
+ eventName: "core.controllers.findOne.override",
65
+ handler: async (input, ctx) => {
66
+ if (input.collectionName === "storage_fs") {
67
+ const context = input.context as Context;
68
+ const action = context.req.query("action");
69
+
70
+ if (action === "view" || action === "download") {
71
+ const result = await ctx.lobb.collectionService.findOne<StorageFsFindOne>({
72
+ collectionName: "storage_fs",
73
+ id: input.id,
74
+ readFile: true,
75
+ });
76
+
77
+ if (!result.data) {
78
+ throw new ctx.LobbError({
79
+ code: "NOT_FOUND",
80
+ message: "The record is not found",
81
+ });
82
+ }
83
+
84
+ const headers: Record<string, string> = {
85
+ "Content-Type": result.data.file_mime_type,
86
+ };
87
+ if (action === "download") {
88
+ headers["Content-Disposition"] =
89
+ `attachment; filename="${result.data.name}"`;
90
+ }
91
+
92
+ return new Response(result.file.buffer as ArrayBuffer, { status: 200, headers });
93
+ } else if (action) {
94
+ throw new ctx.LobbError({
95
+ code: "BAD_REQUEST",
96
+ message: `The passed (${action}) action query param is not supported`,
97
+ });
98
+ }
99
+ }
100
+ },
101
+ },
102
+ ];
103
+ }
@@ -0,0 +1,10 @@
1
+ import type { ExtensionConfig } from "../config/extensionConfigSchema.ts";
2
+ import { getControllersWorkflows } from "./controllers.ts";
3
+ import { getServicesWorkflows } from "./services.ts";
4
+
5
+ export function getWorkflows(extensionConfig: ExtensionConfig) {
6
+ return [
7
+ ...getServicesWorkflows(extensionConfig),
8
+ ...getControllersWorkflows(),
9
+ ];
10
+ }
@@ -0,0 +1,182 @@
1
+ import type { Workflow } from "@lobb-js/core";
2
+ import type { ExtensionConfig } from "../config/extensionConfigSchema.ts";
3
+ import { initStorageAdapter } from "../adapters/index.ts";
4
+ import { validatePathExists, ensurePathExists } from "../utils.ts";
5
+
6
+ export function getServicesWorkflows(extensionConfig: ExtensionConfig): Workflow[] {
7
+ return [
8
+ {
9
+ name: "storageFindOneService",
10
+ eventName: "core.service.findOne.override",
11
+ handler: async (input, ctx) => {
12
+ if (input.collectionName === "storage_fs") {
13
+ const result = await ctx.lobb.collectionStore.findOne({
14
+ collectionName: "storage_fs",
15
+ id: input.id,
16
+ });
17
+
18
+ if (result.data?.type === "file" && input.readFile) {
19
+ const adapter = initStorageAdapter(extensionConfig);
20
+ const file = await adapter.readFile(result.data.id);
21
+ return { ...result, file: new Uint8Array(file) };
22
+ }
23
+
24
+ return result;
25
+ }
26
+ },
27
+ },
28
+ {
29
+ name: "storageCreateOneServiceOverride",
30
+ eventName: "core.service.createOne.override",
31
+ handler: async (input, ctx) => {
32
+ if (input.collectionName === "storage_fs") {
33
+ if (input.file) {
34
+ const filePath = input.data?.path ?? "/";
35
+
36
+ if (input.force) {
37
+ await ensurePathExists(filePath, ctx.lobb);
38
+ } else if (filePath !== "/") {
39
+ await validatePathExists(filePath, ctx.lobb);
40
+ }
41
+
42
+ const { path: _path, name: _name, type: _type, file_mime_type: _mime, file_size: _size, ...extraData } = input.data ?? {};
43
+
44
+ const result = await ctx.lobb.collectionStore.createOne({
45
+ collectionName: "storage_fs",
46
+ data: {
47
+ ...extraData,
48
+ name: input.file.name,
49
+ path: filePath,
50
+ type: "file",
51
+ file_mime_type: input.file.type,
52
+ file_size: input.file.size,
53
+ },
54
+ });
55
+
56
+ const adapter = initStorageAdapter(extensionConfig);
57
+ await adapter.createFile(result.data.id, input.file);
58
+
59
+ return result;
60
+ } else {
61
+ if (input.data?.path) {
62
+ await validatePathExists(input.data.path, ctx.lobb);
63
+ }
64
+ }
65
+ }
66
+ },
67
+ },
68
+ {
69
+ name: "storageDeleteOneService",
70
+ eventName: "core.service.deleteOne.override",
71
+ handler: async (input, ctx) => {
72
+ if (input.collectionName === "storage_fs") {
73
+ const entry = (await ctx.lobb.collectionStore.findOne({
74
+ collectionName: "storage_fs",
75
+ id: input.id,
76
+ })).data;
77
+
78
+ const adapter = initStorageAdapter(extensionConfig);
79
+ if (entry.type === "file") {
80
+ await adapter.removeFile(entry.id);
81
+ } else if (entry.type === "directory") {
82
+ const directoryPath = entry.path + entry.name;
83
+
84
+ const entries = (await ctx.lobb.collectionService.findAll({
85
+ collectionName: "storage_fs",
86
+ params: {
87
+ filter: {
88
+ path: {
89
+ $starts_with: directoryPath,
90
+ },
91
+ },
92
+ },
93
+ })).data;
94
+
95
+ for (let index = 0; index < entries.length; index++) {
96
+ const entry = entries[index];
97
+ if (entry.type === "file") {
98
+ await adapter.removeFile(entry.id);
99
+ }
100
+ }
101
+
102
+ await ctx.lobb.collectionStore.deleteMany({
103
+ collectionName: "storage_fs",
104
+ filter: {
105
+ path: {
106
+ $starts_with: directoryPath,
107
+ },
108
+ },
109
+ });
110
+ }
111
+
112
+ return ctx.lobb.collectionStore.deleteOne({
113
+ collectionName: "storage_fs",
114
+ id: input.id,
115
+ });
116
+ }
117
+ },
118
+ },
119
+ {
120
+ name: "storageDeleteManyService",
121
+ eventName: "core.service.deleteMany.override",
122
+ handler: async (input, ctx) => {
123
+ if (input.collectionName === "storage_fs") {
124
+ const matchedEntries = (await ctx.lobb.collectionStore.findAll({
125
+ collectionName: "storage_fs",
126
+ params: { filter: input.filter },
127
+ })).data;
128
+
129
+ const adapter = initStorageAdapter(extensionConfig);
130
+
131
+ for (const entry of matchedEntries) {
132
+ if (entry.type === "directory") {
133
+ const directoryPath = entry.path + entry.name;
134
+
135
+ const nestedEntries = (await ctx.lobb.collectionStore.findAll({
136
+ collectionName: "storage_fs",
137
+ params: {
138
+ filter: { path: { $starts_with: directoryPath } },
139
+ },
140
+ })).data;
141
+
142
+ for (const nested of nestedEntries) {
143
+ if (nested.type === "file") {
144
+ await adapter.removeFile(nested.id);
145
+ }
146
+ }
147
+
148
+ await ctx.lobb.collectionStore.deleteMany({
149
+ collectionName: "storage_fs",
150
+ filter: { path: { $starts_with: directoryPath } },
151
+ });
152
+ } else if (entry.type === "file") {
153
+ await adapter.removeFile(entry.id);
154
+ }
155
+ }
156
+
157
+ return ctx.lobb.collectionStore.deleteMany({
158
+ collectionName: "storage_fs",
159
+ filter: input.filter,
160
+ });
161
+ }
162
+ },
163
+ },
164
+ {
165
+ name: "storageUpdateOneService",
166
+ eventName: "core.service.updateOne.override",
167
+ handler: async (input, ctx) => {
168
+ if (input.collectionName === "storage_fs") {
169
+ if (input.data.path) {
170
+ await validatePathExists(input.data.path, ctx.lobb);
171
+ }
172
+
173
+ return ctx.lobb.collectionStore.updateOne({
174
+ collectionName: "storage_fs",
175
+ id: input.id,
176
+ data: input.data,
177
+ });
178
+ }
179
+ },
180
+ },
181
+ ];
182
+ }
package/lobb.ts ADDED
@@ -0,0 +1,54 @@
1
+ import { Lobb } from "@lobb-js/core";
2
+ import { storage } from "./extensions/storage/index.ts";
3
+
4
+ Lobb.init({
5
+ project: {
6
+ name: "Storage Extension Test",
7
+ force_sync: true,
8
+ },
9
+ database: {
10
+ host: Bun.env.DATABASE_HOST ?? "localhost",
11
+ port: Number(Bun.env.DATABASE_PORT ?? 5432),
12
+ username: Bun.env.DATABASE_USER ?? "test",
13
+ password: Bun.env.DATABASE_PASSWORD ?? "test",
14
+ database: Bun.env.DATABASE_NAME ?? "storage_ext",
15
+ },
16
+ web_server: {
17
+ host: Bun.env.WEB_SERVER_HOST ?? "0.0.0.0",
18
+ port: Number(Bun.env.WEB_SERVER_PORT ?? 3000),
19
+ cors: {
20
+ origin: "*",
21
+ },
22
+ },
23
+ extensions: [
24
+ storage({
25
+ adapter: "local",
26
+ storagePath: "./storage",
27
+ }),
28
+ ],
29
+ collections: {
30
+ articles: {
31
+ indexes: {},
32
+ fields: {
33
+ id: {
34
+ type: "integer",
35
+ },
36
+ image: {
37
+ type: "string",
38
+ length: 255,
39
+ },
40
+ title: {
41
+ type: "string",
42
+ length: 255,
43
+ validators: {
44
+ required: true,
45
+ },
46
+ },
47
+ body: {
48
+ type: "string",
49
+ length: 255,
50
+ },
51
+ },
52
+ },
53
+ },
54
+ });
package/package.json CHANGED
@@ -1,31 +1,54 @@
1
1
  {
2
2
  "name": "@lobb-js/lobb-ext-storage",
3
- "version": "0.5.8",
3
+ "version": "0.8.1",
4
+ "license": "AGPL-3.0-only",
4
5
  "type": "module",
5
6
  "publishConfig": {
6
7
  "access": "public"
7
8
  },
8
9
  "exports": {
9
- ".": "./src/index.ts"
10
+ ".": "./extensions/storage/index.ts",
11
+ "./studio": {
12
+ "svelte": "./dist/index.js",
13
+ "types": "./dist/index.d.ts"
14
+ }
10
15
  },
11
16
  "scripts": {
12
- "dev": "vite",
13
- "build": "vite build",
17
+ "test": "bun run test:lobb && bun run test:studio",
18
+ "test:lobb": "bun test extensions/storage/tests",
19
+ "test:studio": "bun --bun playwright test --config extensions/storage/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 ''",
14
23
  "preview": "vite preview",
15
- "check": "svelte-check --tsconfig ./tsconfig.app.json && tsc -p tsconfig.node.json"
24
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
25
+ "postinstall": "bun --bun playwright install chromium",
26
+ "prepublishOnly": "./scripts/prepublish.sh",
27
+ "postpublish": "./scripts/postpublish.sh",
28
+ "package": "svelte-package --input extensions/storage/studio",
29
+ "dev:studio": "vite dev",
30
+ "build:studio": "vite build"
16
31
  },
17
32
  "dependencies": {
18
- "path-browserify": "^1.0.1",
19
- "browser-fs-access": "^0.35.0"
33
+ "@lobb-js/core": "0.13.1",
34
+ "browser-fs-access": "^0.35.0",
35
+ "hono": "^4.7.0",
36
+ "openapi-types": "^12.1.3",
37
+ "path-browserify": "^1.0.1"
20
38
  },
21
39
  "devDependencies": {
22
- "@lobb-js/studio": "0.5.0",
40
+ "@lobb-js/studio": "0.7.1",
23
41
  "@lucide/svelte": "^0.563.1",
42
+ "@playwright/test": "^1.58.2",
43
+ "@sveltejs/adapter-node": "^5.5.4",
44
+ "@sveltejs/kit": "^2.55.0",
24
45
  "@sveltejs/vite-plugin-svelte": "6.2.1",
46
+ "@sveltejs/package": "^2.5.7",
25
47
  "@tailwindcss/vite": "^4.1.18",
26
48
  "@tsconfig/svelte": "^5.0.6",
27
- "@types/path-browserify": "^1.0.3",
28
49
  "@types/node": "^24.10.1",
50
+ "@types/path-browserify": "^1.0.3",
51
+ "bun-types": "latest",
29
52
  "clsx": "^2.1.1",
30
53
  "svelte": "^5.49.1",
31
54
  "svelte-check": "^4.3.4",
@@ -0,0 +1,12 @@
1
+ #!/bin/bash
2
+
3
+ # Postpublish script for @lobb-js/lobb-ext-storage
4
+ # Reverts package.json exports and cleans dist to avoid uncommitted changes
5
+
6
+ echo "📝 Reverting package.json exports to development mode..."
7
+ jq '."exports"["./studio"] = "./extensions/storage/studio/index.ts"' package.json > package.json.tmp && mv package.json.tmp package.json
8
+
9
+ echo "🧹 Cleaning dist directory..."
10
+ rm -rf dist
11
+
12
+ echo "✅ Postpublish complete"
@@ -0,0 +1,17 @@
1
+ #!/bin/bash
2
+
3
+ # Prepublish script for @lobb-js/lobb-ext-storage
4
+ # Builds the studio package and updates exports for publishing
5
+
6
+ echo "📦 Building studio package..."
7
+ bun run package
8
+
9
+ if [ $? -ne 0 ]; then
10
+ echo "❌ Build failed"
11
+ exit 1
12
+ fi
13
+
14
+ echo "📝 Updating package.json exports for publishing..."
15
+ jq '."exports"["./studio"] = {"svelte": "./dist/index.js", "types": "./dist/index.d.ts"}' package.json > package.json.tmp && mv package.json.tmp package.json
16
+
17
+ echo "✅ Prepublish complete"
@@ -0,0 +1,12 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <link rel="icon" href="%sveltekit.assets%/vite.svg" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
7
+ %sveltekit.head%
8
+ </head>
9
+ <body data-sveltekit-preload-data="hover">
10
+ <div style="display: contents">%sveltekit.body%</div>
11
+ </body>
12
+ </html>
@@ -0,0 +1,7 @@
1
+ <script lang="ts">
2
+ import "@lobb-js/studio/app.css";
3
+
4
+ let { children } = $props();
5
+ </script>
6
+
7
+ {@render children()}
@@ -0,0 +1 @@
1
+ export const ssr = false;
@@ -0,0 +1,6 @@
1
+ <script lang="ts">
2
+ import { Studio } from "@lobb-js/studio";
3
+ import { env } from "$env/dynamic/public";
4
+ </script>
5
+
6
+ <Studio lobbUrl={env.PUBLIC_LOBB_URL} />
package/svelte.config.js CHANGED
@@ -1,8 +1,24 @@
1
- import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
1
+ import adapter from '@sveltejs/adapter-node';
2
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
- }
3
+ /** @type {import('@sveltejs/kit').Config} */
4
+ const config = {
5
+ kit: {
6
+ adapter: adapter(),
7
+ paths: {
8
+ base: '/studio'
9
+ },
10
+ files: {
11
+ lib: 'studio/lib',
12
+ routes: 'studio/routes',
13
+ appTemplate: 'studio/app.html',
14
+ assets: 'public',
15
+ hooks: {
16
+ server: 'studio/hooks.server',
17
+ client: 'studio/hooks.client',
18
+ },
19
+ params: 'studio/params',
20
+ }
21
+ }
22
+ };
23
+
24
+ export default config;
package/todo.md ADDED
@@ -0,0 +1,36 @@
1
+ # high priority
2
+
3
+ - move the validation logic that checks if the directory of uploaded file path exists or not in the service level and not in the controller level.
4
+
5
+ - a better way to implement this extension is to update or overright the collectionService. so that you can use the same exsting CollectionService class normally but with the ability to adjust the params of that service funciton. so the storage extension version of the normal collection overright will have different params set. for example it should have a param of type blob or File. so you shouldnt really expose services. in the mod.ts. the services already exists why expose. we shouldnt really have at all the services property
6
+ - remove services from this extension and from everywhere
7
+ - instead of creating your own service method. you can just overwrite or update the existing method
8
+ - for example to upload a file you can just use the collectionService mutated create version instead of creating your own function
9
+ - you need to also overwrite the controllers to call the new service function correctly
10
+ - this way is much better from exposing a bunch of service functions and more consistant
11
+ - you should use workflows to overwrite the controllers and the services
12
+ - make sure the tests work correctly
13
+ - remove totally the services from this extension and from the extensionSystem totally
14
+ - go to the `social_to_courier` and fix the storage update part.
15
+
16
+ - remove the unique index of (location, name)
17
+ - implement uploading a file by drag and drop
18
+ - implement the listview
19
+
20
+ # low priority
21
+
22
+ - you need to add a refresh button
23
+ - when the user tries to upload a file or a directory in a non existing.
24
+ directory you have to respond with a 400 Error
25
+ - check if a file exists by sending a GET request instead of reading the
26
+ directory. because thats a unit test specific to local adapter. but the first
27
+ way would work in all kinds of adapters. and it will make the unit tests more
28
+ adaptable
29
+ - prevent the user from not adding a / at the beggining of the path or adding a
30
+ / at the end of the path when inserting or updating a storage record and make
31
+ sure the path is not empty
32
+ - implement a validation mechanism at the instatiating of the storage extension
33
+ that checks of all operations are successfully doable in that specific adapter
34
+ without issues. (really important)
35
+ - Allow multiple versions of a file to be stored, enabling users to access
36
+ previous versions if needed.
package/tsconfig.app.json CHANGED
@@ -19,9 +19,9 @@
19
19
  "moduleDetection": "force",
20
20
  "baseUrl": ".",
21
21
  "paths": {
22
- "$lib": ["./src/lib"],
23
- "$lib/*": ["./src/lib/*"]
22
+ "$lib": ["./studio/lib"],
23
+ "$lib/*": ["./studio/lib/*"]
24
24
  }
25
25
  },
26
- "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"]
26
+ "include": ["studio/**/*.ts", "studio/**/*.js", "studio/**/*.svelte"]
27
27
  }
package/tsconfig.json CHANGED
@@ -1,7 +1,13 @@
1
1
  {
2
- "files": [],
3
- "references": [
4
- { "path": "./tsconfig.app.json" },
5
- { "path": "./tsconfig.node.json" }
6
- ]
2
+ "extends": "./.svelte-kit/tsconfig.json",
3
+ "compilerOptions": {
4
+ "allowJs": true,
5
+ "checkJs": true,
6
+ "esModuleInterop": true,
7
+ "forceConsistentCasingInFileNames": true,
8
+ "resolveJsonModule": true,
9
+ "skipLibCheck": true,
10
+ "sourceMap": true,
11
+ "strict": true
12
+ }
7
13
  }