@storyshelf/storage-local 0.1.3 → 0.3.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.mjs CHANGED
@@ -1,8 +1,10 @@
1
1
  import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
+ import { createReadStream, createWriteStream } from "node:fs";
4
5
  import { access, mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
5
6
  import { dirname, join, relative, resolve, sep } from "node:path";
7
+ import { pipeline } from "node:stream/promises";
6
8
  //#region src/index.ts
7
9
  async function pathExists(target) {
8
10
  try {
@@ -39,7 +41,20 @@ function createLocalStorage(dataDir) {
39
41
  name: "Local Storage",
40
42
  version: globalThis.__PKG_VERSION__ ?? "0.0.0",
41
43
  description: "Local filesystem storage adapter",
42
- kind: "local"
44
+ kind: "local",
45
+ category: "storage"
46
+ },
47
+ lifecycle: {
48
+ init: async () => {
49
+ await mkdir(root, { recursive: true });
50
+ },
51
+ health: async () => {
52
+ const started = Date.now();
53
+ return {
54
+ ok: await pathExists(root),
55
+ latencyMs: Date.now() - started
56
+ };
57
+ }
43
58
  },
44
59
  async read(path) {
45
60
  return await readFile(toAbsolute(root, path));
@@ -59,6 +74,28 @@ function createLocalStorage(dataDir) {
59
74
  const dir = toAbsolute(root, prefix);
60
75
  if (!await pathExists(dir)) return [];
61
76
  return walk(root, dir);
77
+ },
78
+ ...buildStreamMethods(root)
79
+ };
80
+ }
81
+ /** Streaming reads/writes for a local storage root (split for lint limits). */
82
+ function buildStreamMethods(root) {
83
+ return {
84
+ async writeStream(path, stream) {
85
+ const target = toAbsolute(root, path);
86
+ await mkdir(dirname(target), { recursive: true });
87
+ const out = createWriteStream(target);
88
+ try {
89
+ await pipeline(stream, out);
90
+ } catch (error) {
91
+ await rm(target, { force: true });
92
+ throw error;
93
+ }
94
+ },
95
+ async readStream(path) {
96
+ const target = toAbsolute(root, path);
97
+ if (!await pathExists(target)) throw new Error(`No object at "${path}"`);
98
+ return createReadStream(target);
62
99
  }
63
100
  };
64
101
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["import { access, mkdir, readdir, readFile, rm, writeFile } from \"node:fs/promises\";\nimport { dirname, join, relative, resolve, sep } from \"node:path\";\n\nimport type { StorageAdapter } from \"@storyshelf/core/adapter/storage\";\n\ndeclare const __PKG_VERSION__: string | undefined;\n\nasync function pathExists(target: string): Promise<boolean> {\n try {\n await access(target);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction toAbsolute(root: string, path: string): string {\n const target = resolve(root, path);\n const rel = relative(root, target);\n if (rel === \"..\" || rel.startsWith(`..${sep}`)) {\n throw new Error(`Path escapes storage directory: ${path}`);\n }\n return target;\n}\n\nasync function walk(root: string, dir: string): Promise<string[]> {\n const entries = await readdir(dir, { withFileTypes: true });\n const nested = await Promise.all(\n entries.map(async (entry) => {\n const full = join(dir, entry.name);\n if (entry.isDirectory()) {\n return await walk(root, full);\n }\n return [relative(root, full)];\n }),\n );\n return nested.flat();\n}\n\n/**\n * Create a local filesystem-backed StorageAdapter rooted at the given directory.\n *\n * @param dataDir - Root directory in which all stored files live.\n * @returns A StorageAdapter that reads and writes files under `dataDir`.\n */\nexport function createLocalStorage(dataDir: string): StorageAdapter {\n const root = resolve(dataDir);\n\n return {\n metadata: {\n name: \"Local Storage\",\n version: (globalThis as unknown as { __PKG_VERSION__?: string }).__PKG_VERSION__ ?? \"0.0.0\",\n description: \"Local filesystem storage adapter\",\n kind: \"local\",\n },\n async read(path) {\n return await readFile(toAbsolute(root, path));\n },\n async write(path, data) {\n const target = toAbsolute(root, path);\n await mkdir(dirname(target), { recursive: true });\n await writeFile(target, data);\n },\n async delete(path) {\n await rm(toAbsolute(root, path), { force: true });\n },\n async exists(path) {\n return await pathExists(toAbsolute(root, path));\n },\n async list(prefix) {\n const dir = toAbsolute(root, prefix);\n if (!(await pathExists(dir))) {\n return [];\n }\n return walk(root, dir);\n },\n };\n}\n"],"mappings":";;;;;;AAOA,eAAe,WAAW,QAAkC;CAC1D,IAAI;EACF,MAAM,OAAO,MAAM;EACnB,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,WAAW,MAAc,MAAsB;CACtD,MAAM,SAAS,QAAQ,MAAM,IAAI;CACjC,MAAM,MAAM,SAAS,MAAM,MAAM;CACjC,IAAI,QAAQ,QAAQ,IAAI,WAAW,KAAK,KAAK,GAC3C,MAAM,IAAI,MAAM,mCAAmC,MAAM;CAE3D,OAAO;AACT;AAEA,eAAe,KAAK,MAAc,KAAgC;CAChE,MAAM,UAAU,MAAM,QAAQ,KAAK,EAAE,eAAe,KAAK,CAAC;CAU1D,QAAO,MATc,QAAQ,IAC3B,QAAQ,IAAI,OAAO,UAAU;EAC3B,MAAM,OAAO,KAAK,KAAK,MAAM,IAAI;EACjC,IAAI,MAAM,YAAY,GACpB,OAAO,MAAM,KAAK,MAAM,IAAI;EAE9B,OAAO,CAAC,SAAS,MAAM,IAAI,CAAC;CAC9B,CAAC,CACH,EAAA,CACc,KAAK;AACrB;;;;;;;AAQA,SAAgB,mBAAmB,SAAiC;CAClE,MAAM,OAAO,QAAQ,OAAO;CAE5B,OAAO;EACL,UAAU;GACR,MAAM;GACN,SAAU,WAAuD,mBAAmB;GACpF,aAAa;GACb,MAAM;EACR;EACA,MAAM,KAAK,MAAM;GACf,OAAO,MAAM,SAAS,WAAW,MAAM,IAAI,CAAC;EAC9C;EACA,MAAM,MAAM,MAAM,MAAM;GACtB,MAAM,SAAS,WAAW,MAAM,IAAI;GACpC,MAAM,MAAM,QAAQ,MAAM,GAAG,EAAE,WAAW,KAAK,CAAC;GAChD,MAAM,UAAU,QAAQ,IAAI;EAC9B;EACA,MAAM,OAAO,MAAM;GACjB,MAAM,GAAG,WAAW,MAAM,IAAI,GAAG,EAAE,OAAO,KAAK,CAAC;EAClD;EACA,MAAM,OAAO,MAAM;GACjB,OAAO,MAAM,WAAW,WAAW,MAAM,IAAI,CAAC;EAChD;EACA,MAAM,KAAK,QAAQ;GACjB,MAAM,MAAM,WAAW,MAAM,MAAM;GACnC,IAAI,CAAE,MAAM,WAAW,GAAG,GACxB,OAAO,CAAC;GAEV,OAAO,KAAK,MAAM,GAAG;EACvB;CACF;AACF"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type { StorageAdapter } from \"@storyshelf/core/adapter/storage\";\nimport { createReadStream, createWriteStream } from \"node:fs\";\nimport { access, mkdir, readdir, readFile, rm, writeFile } from \"node:fs/promises\";\nimport { dirname, join, relative, resolve, sep } from \"node:path\";\nimport { pipeline } from \"node:stream/promises\";\n\ndeclare const __PKG_VERSION__: string | undefined;\n\nasync function pathExists(target: string): Promise<boolean> {\n try {\n await access(target);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction toAbsolute(root: string, path: string): string {\n const target = resolve(root, path);\n const rel = relative(root, target);\n if (rel === \"..\" || rel.startsWith(`..${sep}`)) {\n throw new Error(`Path escapes storage directory: ${path}`);\n }\n return target;\n}\n\nasync function walk(root: string, dir: string): Promise<string[]> {\n const entries = await readdir(dir, { withFileTypes: true });\n const nested = await Promise.all(\n entries.map(async (entry) => {\n const full = join(dir, entry.name);\n if (entry.isDirectory()) {\n return await walk(root, full);\n }\n return [relative(root, full)];\n }),\n );\n return nested.flat();\n}\n\n/**\n * Create a local filesystem-backed StorageAdapter rooted at the given directory.\n *\n * @param dataDir - Root directory in which all stored files live.\n * @returns A StorageAdapter that reads and writes files under `dataDir`.\n */\nexport function createLocalStorage(dataDir: string): StorageAdapter {\n const root = resolve(dataDir);\n\n return {\n metadata: {\n name: \"Local Storage\",\n version: (globalThis as unknown as { __PKG_VERSION__?: string }).__PKG_VERSION__ ?? \"0.0.0\",\n description: \"Local filesystem storage adapter\",\n kind: \"local\",\n category: \"storage\",\n },\n lifecycle: {\n init: async () => {\n await mkdir(root, { recursive: true });\n },\n health: async () => {\n const started = Date.now();\n const ok = await pathExists(root);\n return { ok, latencyMs: Date.now() - started };\n },\n },\n async read(path) {\n return await readFile(toAbsolute(root, path));\n },\n async write(path, data) {\n const target = toAbsolute(root, path);\n await mkdir(dirname(target), { recursive: true });\n await writeFile(target, data);\n },\n async delete(path) {\n await rm(toAbsolute(root, path), { force: true });\n },\n async exists(path) {\n return await pathExists(toAbsolute(root, path));\n },\n async list(prefix) {\n const dir = toAbsolute(root, prefix);\n if (!(await pathExists(dir))) {\n return [];\n }\n return walk(root, dir);\n },\n ...buildStreamMethods(root),\n };\n}\n\n/** Streaming reads/writes for a local storage root (split for lint limits). */\nfunction buildStreamMethods(root: string): Pick<StorageAdapter, \"writeStream\" | \"readStream\"> {\n return {\n async writeStream(path, stream) {\n const target = toAbsolute(root, path);\n await mkdir(dirname(target), { recursive: true });\n const out = createWriteStream(target);\n try {\n await pipeline(stream, out);\n } catch (error) {\n await rm(target, { force: true });\n throw error;\n }\n },\n async readStream(path) {\n const target = toAbsolute(root, path);\n if (!(await pathExists(target))) {\n throw new Error(`No object at \"${path}\"`);\n }\n return createReadStream(target);\n },\n };\n}\n"],"mappings":";;;;;;;;AAQA,eAAe,WAAW,QAAkC;CAC1D,IAAI;EACF,MAAM,OAAO,MAAM;EACnB,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,WAAW,MAAc,MAAsB;CACtD,MAAM,SAAS,QAAQ,MAAM,IAAI;CACjC,MAAM,MAAM,SAAS,MAAM,MAAM;CACjC,IAAI,QAAQ,QAAQ,IAAI,WAAW,KAAK,KAAK,GAC3C,MAAM,IAAI,MAAM,mCAAmC,MAAM;CAE3D,OAAO;AACT;AAEA,eAAe,KAAK,MAAc,KAAgC;CAChE,MAAM,UAAU,MAAM,QAAQ,KAAK,EAAE,eAAe,KAAK,CAAC;CAU1D,QAAO,MATc,QAAQ,IAC3B,QAAQ,IAAI,OAAO,UAAU;EAC3B,MAAM,OAAO,KAAK,KAAK,MAAM,IAAI;EACjC,IAAI,MAAM,YAAY,GACpB,OAAO,MAAM,KAAK,MAAM,IAAI;EAE9B,OAAO,CAAC,SAAS,MAAM,IAAI,CAAC;CAC9B,CAAC,CACH,EAAA,CACc,KAAK;AACrB;;;;;;;AAQA,SAAgB,mBAAmB,SAAiC;CAClE,MAAM,OAAO,QAAQ,OAAO;CAE5B,OAAO;EACL,UAAU;GACR,MAAM;GACN,SAAU,WAAuD,mBAAmB;GACpF,aAAa;GACb,MAAM;GACN,UAAU;EACZ;EACA,WAAW;GACT,MAAM,YAAY;IAChB,MAAM,MAAM,MAAM,EAAE,WAAW,KAAK,CAAC;GACvC;GACA,QAAQ,YAAY;IAClB,MAAM,UAAU,KAAK,IAAI;IAEzB,OAAO;KAAE,IAAA,MADQ,WAAW,IAAI;KACnB,WAAW,KAAK,IAAI,IAAI;IAAQ;GAC/C;EACF;EACA,MAAM,KAAK,MAAM;GACf,OAAO,MAAM,SAAS,WAAW,MAAM,IAAI,CAAC;EAC9C;EACA,MAAM,MAAM,MAAM,MAAM;GACtB,MAAM,SAAS,WAAW,MAAM,IAAI;GACpC,MAAM,MAAM,QAAQ,MAAM,GAAG,EAAE,WAAW,KAAK,CAAC;GAChD,MAAM,UAAU,QAAQ,IAAI;EAC9B;EACA,MAAM,OAAO,MAAM;GACjB,MAAM,GAAG,WAAW,MAAM,IAAI,GAAG,EAAE,OAAO,KAAK,CAAC;EAClD;EACA,MAAM,OAAO,MAAM;GACjB,OAAO,MAAM,WAAW,WAAW,MAAM,IAAI,CAAC;EAChD;EACA,MAAM,KAAK,QAAQ;GACjB,MAAM,MAAM,WAAW,MAAM,MAAM;GACnC,IAAI,CAAE,MAAM,WAAW,GAAG,GACxB,OAAO,CAAC;GAEV,OAAO,KAAK,MAAM,GAAG;EACvB;EACA,GAAG,mBAAmB,IAAI;CAC5B;AACF;;AAGA,SAAS,mBAAmB,MAAkE;CAC5F,OAAO;EACL,MAAM,YAAY,MAAM,QAAQ;GAC9B,MAAM,SAAS,WAAW,MAAM,IAAI;GACpC,MAAM,MAAM,QAAQ,MAAM,GAAG,EAAE,WAAW,KAAK,CAAC;GAChD,MAAM,MAAM,kBAAkB,MAAM;GACpC,IAAI;IACF,MAAM,SAAS,QAAQ,GAAG;GAC5B,SAAS,OAAO;IACd,MAAM,GAAG,QAAQ,EAAE,OAAO,KAAK,CAAC;IAChC,MAAM;GACR;EACF;EACA,MAAM,WAAW,MAAM;GACrB,MAAM,SAAS,WAAW,MAAM,IAAI;GACpC,IAAI,CAAE,MAAM,WAAW,MAAM,GAC3B,MAAM,IAAI,MAAM,iBAAiB,KAAK,EAAE;GAE1C,OAAO,iBAAiB,MAAM;EAChC;CACF;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@storyshelf/storage-local",
3
- "version": "0.1.3",
3
+ "version": "0.3.2",
4
4
  "description": "Local filesystem storage adapter for StoryShelf.",
5
5
  "homepage": "https://github.com/GuptaSiddhant/StoryShelf#readme",
6
6
  "bugs": {
@@ -45,7 +45,7 @@
45
45
  "prepublishOnly": "nub run build"
46
46
  },
47
47
  "dependencies": {
48
- "@storyshelf/core": "^0.1.3"
48
+ "@storyshelf/core": "^0.3.2"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@types/node": "catalog:",