@crowi/plugin-storage-local 0.1.0-alpha.0 → 0.1.0-alpha.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.
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +10 -5
package/dist/index.js
CHANGED
|
@@ -50,7 +50,7 @@ var plugin = {
|
|
|
50
50
|
version: "0.1.0-dev",
|
|
51
51
|
configSchema: LocalStorageConfigSchema,
|
|
52
52
|
adminPlacement: {
|
|
53
|
-
label: "
|
|
53
|
+
label: "Local storage",
|
|
54
54
|
icon: "hard-drive"
|
|
55
55
|
// section omitted: derived from registerStorage → 'storage'
|
|
56
56
|
},
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { createReadStream, createWriteStream, existsSync } from 'node:fs';\nimport { mkdir, rm, stat } from 'node:fs/promises';\nimport path from 'node:path';\nimport { Readable } from 'node:stream';\nimport { pipeline } from 'node:stream/promises';\nimport { z } from 'zod/v3';\nimport type { CrowiPlugin, StorageDriver } from '@crowi/plugin-api';\n\nconst LocalStorageConfigSchema = z\n .object({\n /** Relative paths resolve against the directory containing `crowi.config.json`. */\n rootDir: z.string().default('data/uploads'),\n })\n .strict();\n\ntype LocalStorageConfig = z.infer<typeof LocalStorageConfigSchema>;\n\nconst plugin: CrowiPlugin = {\n name: '@crowi/plugin-storage-local',\n version: '0.1.0-dev',\n configSchema: LocalStorageConfigSchema,\n adminPlacement: {\n label: '
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { createReadStream, createWriteStream, existsSync } from 'node:fs';\nimport { mkdir, rm, stat } from 'node:fs/promises';\nimport path from 'node:path';\nimport { Readable } from 'node:stream';\nimport { pipeline } from 'node:stream/promises';\nimport { z } from 'zod/v3';\nimport type { CrowiPlugin, StorageDriver } from '@crowi/plugin-api';\n\nconst LocalStorageConfigSchema = z\n .object({\n /** Relative paths resolve against the directory containing `crowi.config.json`. */\n rootDir: z.string().default('data/uploads'),\n })\n .strict();\n\ntype LocalStorageConfig = z.infer<typeof LocalStorageConfigSchema>;\n\nconst plugin: CrowiPlugin = {\n name: '@crowi/plugin-storage-local',\n version: '0.1.0-dev',\n configSchema: LocalStorageConfigSchema,\n adminPlacement: {\n label: 'Local storage',\n icon: 'hard-drive',\n // section omitted: derived from registerStorage → 'storage'\n },\n\n registerStorage: (registry, ctx) => {\n const driver: StorageDriver = createLocalDriver(ctx.config<LocalStorageConfig>());\n registry.register('local', driver);\n ctx.log.debug('registered local storage driver');\n },\n};\n\nexport default plugin;\n\nexport function createLocalDriver(config: LocalStorageConfig): StorageDriver {\n const root = path.isAbsolute(config.rootDir) ? config.rootDir : path.resolve(process.cwd(), config.rootDir);\n\n // Reject `..` / absolute paths that would escape rootDir\n // (e.g. key = '../../etc/passwd').\n const resolveSafe = (key: string): string => {\n const resolved = path.resolve(root, key);\n if (resolved !== root && !resolved.startsWith(root + path.sep)) {\n throw new Error(`Storage key '${key}' resolves outside of rootDir`);\n }\n return resolved;\n };\n\n return {\n async put(key, body, _meta) {\n const target = resolveSafe(key);\n await mkdir(path.dirname(target), { recursive: true });\n const source = body instanceof Buffer ? Readable.from(body) : body;\n await pipeline(source, createWriteStream(target));\n return { key };\n },\n\n async get(key) {\n const target = resolveSafe(key);\n if (!existsSync(target)) {\n // Object.assign (not a cast) so tsup emits valid JS for ts-node;\n // the cast form leaves a raw `err.code = …` that ts-node rejects.\n throw Object.assign(new Error(`Storage key '${key}' does not exist`), { code: 'ENOENT' });\n }\n return createReadStream(target);\n },\n\n async delete(key) {\n const target = resolveSafe(key);\n await rm(target, { force: true });\n },\n\n // No signedUrl: local files are streamed via `get()` through the\n // API. Browsers cannot fetch them directly anyway.\n };\n}\n\n/**\n * Lightweight stat helper — useful for tests / debugging. Returns\n * null when the key does not exist.\n */\nexport async function statKey(driverConfig: LocalStorageConfig, key: string): Promise<{ size: number } | null> {\n const root = path.isAbsolute(driverConfig.rootDir) ? driverConfig.rootDir : path.resolve(process.cwd(), driverConfig.rootDir);\n const target = path.resolve(root, key);\n try {\n const s = await stat(target);\n return { size: s.size };\n } catch {\n return null;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAAgE;AAChE,sBAAgC;AAChC,uBAAiB;AACjB,yBAAyB;AACzB,IAAAA,mBAAyB;AACzB,gBAAkB;AAGlB,IAAM,2BAA2B,YAC9B,OAAO;AAAA;AAAA,EAEN,SAAS,YAAE,OAAO,EAAE,QAAQ,cAAc;AAC5C,CAAC,EACA,OAAO;AAIV,IAAM,SAAsB;AAAA,EAC1B,MAAM;AAAA,EACN,SAAS;AAAA,EACT,cAAc;AAAA,EACd,gBAAgB;AAAA,IACd,OAAO;AAAA,IACP,MAAM;AAAA;AAAA,EAER;AAAA,EAEA,iBAAiB,CAAC,UAAU,QAAQ;AAClC,UAAM,SAAwB,kBAAkB,IAAI,OAA2B,CAAC;AAChF,aAAS,SAAS,SAAS,MAAM;AACjC,QAAI,IAAI,MAAM,iCAAiC;AAAA,EACjD;AACF;AAEA,IAAO,gBAAQ;AAER,SAAS,kBAAkB,QAA2C;AAC3E,QAAM,OAAO,iBAAAC,QAAK,WAAW,OAAO,OAAO,IAAI,OAAO,UAAU,iBAAAA,QAAK,QAAQ,QAAQ,IAAI,GAAG,OAAO,OAAO;AAI1G,QAAM,cAAc,CAAC,QAAwB;AAC3C,UAAM,WAAW,iBAAAA,QAAK,QAAQ,MAAM,GAAG;AACvC,QAAI,aAAa,QAAQ,CAAC,SAAS,WAAW,OAAO,iBAAAA,QAAK,GAAG,GAAG;AAC9D,YAAM,IAAI,MAAM,gBAAgB,GAAG,+BAA+B;AAAA,IACpE;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,MAAM,IAAI,KAAK,MAAM,OAAO;AAC1B,YAAM,SAAS,YAAY,GAAG;AAC9B,gBAAM,uBAAM,iBAAAA,QAAK,QAAQ,MAAM,GAAG,EAAE,WAAW,KAAK,CAAC;AACrD,YAAM,SAAS,gBAAgB,SAAS,4BAAS,KAAK,IAAI,IAAI;AAC9D,gBAAM,2BAAS,YAAQ,kCAAkB,MAAM,CAAC;AAChD,aAAO,EAAE,IAAI;AAAA,IACf;AAAA,IAEA,MAAM,IAAI,KAAK;AACb,YAAM,SAAS,YAAY,GAAG;AAC9B,UAAI,KAAC,2BAAW,MAAM,GAAG;AAGvB,cAAM,OAAO,OAAO,IAAI,MAAM,gBAAgB,GAAG,kBAAkB,GAAG,EAAE,MAAM,SAAS,CAAC;AAAA,MAC1F;AACA,iBAAO,iCAAiB,MAAM;AAAA,IAChC;AAAA,IAEA,MAAM,OAAO,KAAK;AAChB,YAAM,SAAS,YAAY,GAAG;AAC9B,gBAAM,oBAAG,QAAQ,EAAE,OAAO,KAAK,CAAC;AAAA,IAClC;AAAA;AAAA;AAAA,EAIF;AACF;AAMA,eAAsB,QAAQ,cAAkC,KAA+C;AAC7G,QAAM,OAAO,iBAAAA,QAAK,WAAW,aAAa,OAAO,IAAI,aAAa,UAAU,iBAAAA,QAAK,QAAQ,QAAQ,IAAI,GAAG,aAAa,OAAO;AAC5H,QAAM,SAAS,iBAAAA,QAAK,QAAQ,MAAM,GAAG;AACrC,MAAI;AACF,UAAM,IAAI,UAAM,sBAAK,MAAM;AAC3B,WAAO,EAAE,MAAM,EAAE,KAAK;AAAA,EACxB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":["import_promises","path"]}
|
package/dist/index.mjs
CHANGED
|
@@ -14,7 +14,7 @@ var plugin = {
|
|
|
14
14
|
version: "0.1.0-dev",
|
|
15
15
|
configSchema: LocalStorageConfigSchema,
|
|
16
16
|
adminPlacement: {
|
|
17
|
-
label: "
|
|
17
|
+
label: "Local storage",
|
|
18
18
|
icon: "hard-drive"
|
|
19
19
|
// section omitted: derived from registerStorage → 'storage'
|
|
20
20
|
},
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { createReadStream, createWriteStream, existsSync } from 'node:fs';\nimport { mkdir, rm, stat } from 'node:fs/promises';\nimport path from 'node:path';\nimport { Readable } from 'node:stream';\nimport { pipeline } from 'node:stream/promises';\nimport { z } from 'zod/v3';\nimport type { CrowiPlugin, StorageDriver } from '@crowi/plugin-api';\n\nconst LocalStorageConfigSchema = z\n .object({\n /** Relative paths resolve against the directory containing `crowi.config.json`. */\n rootDir: z.string().default('data/uploads'),\n })\n .strict();\n\ntype LocalStorageConfig = z.infer<typeof LocalStorageConfigSchema>;\n\nconst plugin: CrowiPlugin = {\n name: '@crowi/plugin-storage-local',\n version: '0.1.0-dev',\n configSchema: LocalStorageConfigSchema,\n adminPlacement: {\n label: '
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { createReadStream, createWriteStream, existsSync } from 'node:fs';\nimport { mkdir, rm, stat } from 'node:fs/promises';\nimport path from 'node:path';\nimport { Readable } from 'node:stream';\nimport { pipeline } from 'node:stream/promises';\nimport { z } from 'zod/v3';\nimport type { CrowiPlugin, StorageDriver } from '@crowi/plugin-api';\n\nconst LocalStorageConfigSchema = z\n .object({\n /** Relative paths resolve against the directory containing `crowi.config.json`. */\n rootDir: z.string().default('data/uploads'),\n })\n .strict();\n\ntype LocalStorageConfig = z.infer<typeof LocalStorageConfigSchema>;\n\nconst plugin: CrowiPlugin = {\n name: '@crowi/plugin-storage-local',\n version: '0.1.0-dev',\n configSchema: LocalStorageConfigSchema,\n adminPlacement: {\n label: 'Local storage',\n icon: 'hard-drive',\n // section omitted: derived from registerStorage → 'storage'\n },\n\n registerStorage: (registry, ctx) => {\n const driver: StorageDriver = createLocalDriver(ctx.config<LocalStorageConfig>());\n registry.register('local', driver);\n ctx.log.debug('registered local storage driver');\n },\n};\n\nexport default plugin;\n\nexport function createLocalDriver(config: LocalStorageConfig): StorageDriver {\n const root = path.isAbsolute(config.rootDir) ? config.rootDir : path.resolve(process.cwd(), config.rootDir);\n\n // Reject `..` / absolute paths that would escape rootDir\n // (e.g. key = '../../etc/passwd').\n const resolveSafe = (key: string): string => {\n const resolved = path.resolve(root, key);\n if (resolved !== root && !resolved.startsWith(root + path.sep)) {\n throw new Error(`Storage key '${key}' resolves outside of rootDir`);\n }\n return resolved;\n };\n\n return {\n async put(key, body, _meta) {\n const target = resolveSafe(key);\n await mkdir(path.dirname(target), { recursive: true });\n const source = body instanceof Buffer ? Readable.from(body) : body;\n await pipeline(source, createWriteStream(target));\n return { key };\n },\n\n async get(key) {\n const target = resolveSafe(key);\n if (!existsSync(target)) {\n // Object.assign (not a cast) so tsup emits valid JS for ts-node;\n // the cast form leaves a raw `err.code = …` that ts-node rejects.\n throw Object.assign(new Error(`Storage key '${key}' does not exist`), { code: 'ENOENT' });\n }\n return createReadStream(target);\n },\n\n async delete(key) {\n const target = resolveSafe(key);\n await rm(target, { force: true });\n },\n\n // No signedUrl: local files are streamed via `get()` through the\n // API. Browsers cannot fetch them directly anyway.\n };\n}\n\n/**\n * Lightweight stat helper — useful for tests / debugging. Returns\n * null when the key does not exist.\n */\nexport async function statKey(driverConfig: LocalStorageConfig, key: string): Promise<{ size: number } | null> {\n const root = path.isAbsolute(driverConfig.rootDir) ? driverConfig.rootDir : path.resolve(process.cwd(), driverConfig.rootDir);\n const target = path.resolve(root, key);\n try {\n const s = await stat(target);\n return { size: s.size };\n } catch {\n return null;\n }\n}\n"],"mappings":";AAAA,SAAS,kBAAkB,mBAAmB,kBAAkB;AAChE,SAAS,OAAO,IAAI,YAAY;AAChC,OAAO,UAAU;AACjB,SAAS,gBAAgB;AACzB,SAAS,gBAAgB;AACzB,SAAS,SAAS;AAGlB,IAAM,2BAA2B,EAC9B,OAAO;AAAA;AAAA,EAEN,SAAS,EAAE,OAAO,EAAE,QAAQ,cAAc;AAC5C,CAAC,EACA,OAAO;AAIV,IAAM,SAAsB;AAAA,EAC1B,MAAM;AAAA,EACN,SAAS;AAAA,EACT,cAAc;AAAA,EACd,gBAAgB;AAAA,IACd,OAAO;AAAA,IACP,MAAM;AAAA;AAAA,EAER;AAAA,EAEA,iBAAiB,CAAC,UAAU,QAAQ;AAClC,UAAM,SAAwB,kBAAkB,IAAI,OAA2B,CAAC;AAChF,aAAS,SAAS,SAAS,MAAM;AACjC,QAAI,IAAI,MAAM,iCAAiC;AAAA,EACjD;AACF;AAEA,IAAO,gBAAQ;AAER,SAAS,kBAAkB,QAA2C;AAC3E,QAAM,OAAO,KAAK,WAAW,OAAO,OAAO,IAAI,OAAO,UAAU,KAAK,QAAQ,QAAQ,IAAI,GAAG,OAAO,OAAO;AAI1G,QAAM,cAAc,CAAC,QAAwB;AAC3C,UAAM,WAAW,KAAK,QAAQ,MAAM,GAAG;AACvC,QAAI,aAAa,QAAQ,CAAC,SAAS,WAAW,OAAO,KAAK,GAAG,GAAG;AAC9D,YAAM,IAAI,MAAM,gBAAgB,GAAG,+BAA+B;AAAA,IACpE;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,MAAM,IAAI,KAAK,MAAM,OAAO;AAC1B,YAAM,SAAS,YAAY,GAAG;AAC9B,YAAM,MAAM,KAAK,QAAQ,MAAM,GAAG,EAAE,WAAW,KAAK,CAAC;AACrD,YAAM,SAAS,gBAAgB,SAAS,SAAS,KAAK,IAAI,IAAI;AAC9D,YAAM,SAAS,QAAQ,kBAAkB,MAAM,CAAC;AAChD,aAAO,EAAE,IAAI;AAAA,IACf;AAAA,IAEA,MAAM,IAAI,KAAK;AACb,YAAM,SAAS,YAAY,GAAG;AAC9B,UAAI,CAAC,WAAW,MAAM,GAAG;AAGvB,cAAM,OAAO,OAAO,IAAI,MAAM,gBAAgB,GAAG,kBAAkB,GAAG,EAAE,MAAM,SAAS,CAAC;AAAA,MAC1F;AACA,aAAO,iBAAiB,MAAM;AAAA,IAChC;AAAA,IAEA,MAAM,OAAO,KAAK;AAChB,YAAM,SAAS,YAAY,GAAG;AAC9B,YAAM,GAAG,QAAQ,EAAE,OAAO,KAAK,CAAC;AAAA,IAClC;AAAA;AAAA;AAAA,EAIF;AACF;AAMA,eAAsB,QAAQ,cAAkC,KAA+C;AAC7G,QAAM,OAAO,KAAK,WAAW,aAAa,OAAO,IAAI,aAAa,UAAU,KAAK,QAAQ,QAAQ,IAAI,GAAG,aAAa,OAAO;AAC5H,QAAM,SAAS,KAAK,QAAQ,MAAM,GAAG;AACrC,MAAI;AACF,UAAM,IAAI,MAAM,KAAK,MAAM;AAC3B,WAAO,EAAE,MAAM,EAAE,KAAK;AAAA,EACxB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crowi/plugin-storage-local",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.2",
|
|
4
4
|
"description": "Local filesystem storage driver for Crowi 2.0. Default-on; preserves the v1.x data/uploads/ layout.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/crowi/crowi.git",
|
|
8
|
+
"directory": "packages/plugin-storage-local"
|
|
9
|
+
},
|
|
5
10
|
"main": "dist/index.js",
|
|
6
11
|
"module": "dist/index.mjs",
|
|
7
12
|
"types": "dist/index.d.ts",
|
|
@@ -20,18 +25,18 @@
|
|
|
20
25
|
"access": "public"
|
|
21
26
|
},
|
|
22
27
|
"peerDependencies": {
|
|
23
|
-
"zod": "^4
|
|
28
|
+
"zod": "^4"
|
|
24
29
|
},
|
|
25
30
|
"devDependencies": {
|
|
26
31
|
"@types/node": "^24",
|
|
27
32
|
"tsup": "^8.3.5",
|
|
28
33
|
"typescript": "^5.8.3",
|
|
29
34
|
"zod": "^4.4.3",
|
|
30
|
-
"@crowi/
|
|
31
|
-
"@crowi/
|
|
35
|
+
"@crowi/plugin-api": "0.1.0-alpha.1",
|
|
36
|
+
"@crowi/tsconfig": "0.1.0-alpha.0"
|
|
32
37
|
},
|
|
33
38
|
"dependencies": {
|
|
34
|
-
"@crowi/plugin-api": "^0.1.0-alpha.
|
|
39
|
+
"@crowi/plugin-api": "^0.1.0-alpha.1"
|
|
35
40
|
},
|
|
36
41
|
"scripts": {
|
|
37
42
|
"build": "tsup",
|