hazo_files 2.1.1 → 3.1.0

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.
@@ -30,6 +30,22 @@ interface ProbeResult {
30
30
  /** Free-form detail for logging. */
31
31
  message?: string;
32
32
  }
33
+ /**
34
+ * A single entry returned by `FileStorageProvider.list()`.
35
+ *
36
+ * `path` is the same logical namespace used by `put`/`get` — callers can pass
37
+ * it directly back to those methods without any transformation.
38
+ */
39
+ interface FileEntry {
40
+ /** Logical path within the provider (same namespace as put/get). */
41
+ path: StoragePath;
42
+ /** Bare filename or directory name (the last segment of `path`). */
43
+ name: string;
44
+ /** Size in bytes. 0 for directories. */
45
+ size: number;
46
+ /** True when this entry represents a directory. */
47
+ isDirectory: boolean;
48
+ }
33
49
  /**
34
50
  * Storage provider abstraction. Every method MUST be idempotent at the
35
51
  * data-content level — re-invoking put with identical body is allowed.
@@ -44,6 +60,24 @@ interface FileStorageProvider {
44
60
  getSignedUrl(path: StoragePath, opts?: SignedUrlOpts): Promise<string>;
45
61
  /** Used by validation cron + onboarding step 2. */
46
62
  probe(): Promise<ProbeResult>;
63
+ /**
64
+ * List all entries (files and sub-directories) under a logical path prefix.
65
+ * Results are recursive — all descendants are included.
66
+ * Returns an empty array when the prefix does not exist.
67
+ */
68
+ list(prefix: StoragePath): Promise<FileEntry[]>;
69
+ /**
70
+ * Move bytes from `from` to `to`, creating any intermediate directories.
71
+ * The source is removed on success.
72
+ * Throws with a message containing "Not found" when `from` does not exist.
73
+ */
74
+ move(from: StoragePath, to: StoragePath): Promise<void>;
75
+ /**
76
+ * Rename a file or directory. `to` is the full new logical path.
77
+ * Implementations may delegate to `move`.
78
+ * Throws with a message containing "Not found" when `from` does not exist.
79
+ */
80
+ rename(from: StoragePath, to: StoragePath): Promise<void>;
47
81
  }
48
82
 
49
83
  declare class InMemoryProvider implements FileStorageProvider {
@@ -55,6 +89,9 @@ declare class InMemoryProvider implements FileStorageProvider {
55
89
  exists(path: string): Promise<boolean>;
56
90
  getSignedUrl(path: string, _opts?: SignedUrlOpts): Promise<string>;
57
91
  probe(): Promise<ProbeResult>;
92
+ list(prefix: string): Promise<FileEntry[]>;
93
+ move(from: string, to: string): Promise<void>;
94
+ rename(from: string, to: string): Promise<void>;
58
95
  /** Test-only escape hatch — exposes the internal store for assertions. */
59
96
  snapshot(): Map<string, Buffer>;
60
97
  }
@@ -30,6 +30,22 @@ interface ProbeResult {
30
30
  /** Free-form detail for logging. */
31
31
  message?: string;
32
32
  }
33
+ /**
34
+ * A single entry returned by `FileStorageProvider.list()`.
35
+ *
36
+ * `path` is the same logical namespace used by `put`/`get` — callers can pass
37
+ * it directly back to those methods without any transformation.
38
+ */
39
+ interface FileEntry {
40
+ /** Logical path within the provider (same namespace as put/get). */
41
+ path: StoragePath;
42
+ /** Bare filename or directory name (the last segment of `path`). */
43
+ name: string;
44
+ /** Size in bytes. 0 for directories. */
45
+ size: number;
46
+ /** True when this entry represents a directory. */
47
+ isDirectory: boolean;
48
+ }
33
49
  /**
34
50
  * Storage provider abstraction. Every method MUST be idempotent at the
35
51
  * data-content level — re-invoking put with identical body is allowed.
@@ -44,6 +60,24 @@ interface FileStorageProvider {
44
60
  getSignedUrl(path: StoragePath, opts?: SignedUrlOpts): Promise<string>;
45
61
  /** Used by validation cron + onboarding step 2. */
46
62
  probe(): Promise<ProbeResult>;
63
+ /**
64
+ * List all entries (files and sub-directories) under a logical path prefix.
65
+ * Results are recursive — all descendants are included.
66
+ * Returns an empty array when the prefix does not exist.
67
+ */
68
+ list(prefix: StoragePath): Promise<FileEntry[]>;
69
+ /**
70
+ * Move bytes from `from` to `to`, creating any intermediate directories.
71
+ * The source is removed on success.
72
+ * Throws with a message containing "Not found" when `from` does not exist.
73
+ */
74
+ move(from: StoragePath, to: StoragePath): Promise<void>;
75
+ /**
76
+ * Rename a file or directory. `to` is the full new logical path.
77
+ * Implementations may delegate to `move`.
78
+ * Throws with a message containing "Not found" when `from` does not exist.
79
+ */
80
+ rename(from: StoragePath, to: StoragePath): Promise<void>;
47
81
  }
48
82
 
49
83
  declare class InMemoryProvider implements FileStorageProvider {
@@ -55,6 +89,9 @@ declare class InMemoryProvider implements FileStorageProvider {
55
89
  exists(path: string): Promise<boolean>;
56
90
  getSignedUrl(path: string, _opts?: SignedUrlOpts): Promise<string>;
57
91
  probe(): Promise<ProbeResult>;
92
+ list(prefix: string): Promise<FileEntry[]>;
93
+ move(from: string, to: string): Promise<void>;
94
+ rename(from: string, to: string): Promise<void>;
58
95
  /** Test-only escape hatch — exposes the internal store for assertions. */
59
96
  snapshot(): Map<string, Buffer>;
60
97
  }
@@ -55,6 +55,39 @@ var InMemoryProvider = class {
55
55
  async probe() {
56
56
  return { ok: true };
57
57
  }
58
+ async list(prefix) {
59
+ const base = prefix.replace(/\/$/, "");
60
+ const matchPrefix = `${base}/`;
61
+ const entries = [];
62
+ const seenDirs = /* @__PURE__ */ new Set();
63
+ for (const [key, buf] of this.store.entries()) {
64
+ if (key !== base && !key.startsWith(matchPrefix)) continue;
65
+ const rel = key.startsWith(matchPrefix) ? key.slice(matchPrefix.length) : "";
66
+ if (!rel) {
67
+ entries.push({ path: key, name: key.split("/").pop(), size: buf.length, isDirectory: false });
68
+ continue;
69
+ }
70
+ const parts = rel.split("/");
71
+ for (let i = 1; i < parts.length; i++) {
72
+ const dirPath = matchPrefix + parts.slice(0, i).join("/");
73
+ if (!seenDirs.has(dirPath)) {
74
+ seenDirs.add(dirPath);
75
+ entries.push({ path: dirPath, name: parts[i - 1], size: 0, isDirectory: true });
76
+ }
77
+ }
78
+ entries.push({ path: key, name: parts[parts.length - 1], size: buf.length, isDirectory: false });
79
+ }
80
+ return entries;
81
+ }
82
+ async move(from, to) {
83
+ const buf = this.store.get(from);
84
+ if (!buf) throw new Error(`Not found: ${from}`);
85
+ this.store.set(to, buf);
86
+ this.store.delete(from);
87
+ }
88
+ async rename(from, to) {
89
+ return this.move(from, to);
90
+ }
58
91
  /** Test-only escape hatch — exposes the internal store for assertions. */
59
92
  snapshot() {
60
93
  return new Map(this.store);
@@ -29,6 +29,39 @@ var InMemoryProvider = class {
29
29
  async probe() {
30
30
  return { ok: true };
31
31
  }
32
+ async list(prefix) {
33
+ const base = prefix.replace(/\/$/, "");
34
+ const matchPrefix = `${base}/`;
35
+ const entries = [];
36
+ const seenDirs = /* @__PURE__ */ new Set();
37
+ for (const [key, buf] of this.store.entries()) {
38
+ if (key !== base && !key.startsWith(matchPrefix)) continue;
39
+ const rel = key.startsWith(matchPrefix) ? key.slice(matchPrefix.length) : "";
40
+ if (!rel) {
41
+ entries.push({ path: key, name: key.split("/").pop(), size: buf.length, isDirectory: false });
42
+ continue;
43
+ }
44
+ const parts = rel.split("/");
45
+ for (let i = 1; i < parts.length; i++) {
46
+ const dirPath = matchPrefix + parts.slice(0, i).join("/");
47
+ if (!seenDirs.has(dirPath)) {
48
+ seenDirs.add(dirPath);
49
+ entries.push({ path: dirPath, name: parts[i - 1], size: 0, isDirectory: true });
50
+ }
51
+ }
52
+ entries.push({ path: key, name: parts[parts.length - 1], size: buf.length, isDirectory: false });
53
+ }
54
+ return entries;
55
+ }
56
+ async move(from, to) {
57
+ const buf = this.store.get(from);
58
+ if (!buf) throw new Error(`Not found: ${from}`);
59
+ this.store.set(to, buf);
60
+ this.store.delete(from);
61
+ }
62
+ async rename(from, to) {
63
+ return this.move(from, to);
64
+ }
32
65
  /** Test-only escape hatch — exposes the internal store for assertions. */
33
66
  snapshot() {
34
67
  return new Map(this.store);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hazo_files",
3
- "version": "2.1.1",
3
+ "version": "3.1.0",
4
4
  "description": "File management including integration to cloud files",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -102,8 +102,9 @@
102
102
  "@types/react": "^18.3.3",
103
103
  "@types/react-dom": "^18.3.0",
104
104
  "dropbox": "^10.34.0",
105
- "hazo_jobs": "^0.8.0",
106
- "hazo_llm_api": "^1.2.7",
105
+ "hazo_core": "^1.1.0",
106
+ "hazo_jobs": "^0.12.0",
107
+ "hazo_llm_api": "^2.1.0",
107
108
  "jsdom": "^28.1.0",
108
109
  "react": "^18.2.0",
109
110
  "react-dom": "^18.2.0",
@@ -115,20 +116,22 @@
115
116
  },
116
117
  "peerDependencies": {
117
118
  "@dnd-kit/core": "^6.0.0",
118
- "@dnd-kit/sortable": ">=8.0.0",
119
+ "@dnd-kit/sortable": "^8.0.0",
119
120
  "@dnd-kit/utilities": "^3.0.0",
120
121
  "dropbox": "^10.0.0",
121
122
  "googleapis": "^140.0.0",
122
- "hazo_connect": "^2.6.0",
123
- "hazo_debug": "^2.0.0",
124
- "hazo_jobs": "^0.8.0",
125
- "hazo_llm_api": "^1.2.0",
126
- "hazo_logs": "^1.0.13",
127
- "hazo_secure": "^0.5.0",
123
+ "hazo_connect": "^3.4.1",
124
+ "hazo_core": "^1.1.0",
125
+ "hazo_debug": "^3.1.1",
126
+ "hazo_jobs": "^0.12.0",
127
+ "hazo_llm_api": "^2.1.0",
128
+ "hazo_logs": "^2.0.3",
129
+ "hazo_secure": "^1.2.0",
130
+ "hazo_ui": "^3.2.1",
128
131
  "react": "^18.0.0",
129
132
  "react-dom": "^18.0.0",
130
- "server-only": ">=0.0.1",
131
- "sonner": ">=1.0.0",
133
+ "server-only": "^0.0.1",
134
+ "sonner": "^2.0.7",
132
135
  "xxhash-wasm": "^1.0.0"
133
136
  },
134
137
  "peerDependenciesMeta": {
@@ -150,6 +153,9 @@
150
153
  "hazo_connect": {
151
154
  "optional": true
152
155
  },
156
+ "hazo_core": {
157
+ "optional": true
158
+ },
153
159
  "hazo_debug": {
154
160
  "optional": true
155
161
  },
@@ -159,6 +165,9 @@
159
165
  "hazo_llm_api": {
160
166
  "optional": true
161
167
  },
168
+ "hazo_ui": {
169
+ "optional": true
170
+ },
162
171
  "server-only": {
163
172
  "optional": true
164
173
  },