nuxt-filer 0.0.14 → 0.0.15

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/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nuxt-filer",
3
3
  "configKey": "filer",
4
- "version": "0.0.14",
4
+ "version": "0.0.15",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "3.6.1"
@@ -1,4 +1,17 @@
1
1
  import { randomUUID } from "node:crypto";
2
+ async function mapWithConcurrency(items, limit, fn) {
3
+ const results = new Array(items.length);
4
+ let next = 0;
5
+ const worker = async () => {
6
+ while (next < items.length) {
7
+ const index = next++;
8
+ results[index] = await fn(items[index], index);
9
+ }
10
+ };
11
+ const workers = Array.from({ length: Math.min(limit, items.length) || 1 }, worker);
12
+ await Promise.all(workers);
13
+ return results;
14
+ }
2
15
  export function createS3Provider(options) {
3
16
  const prefix = options.prefix ? options.prefix.replace(/\/+$/, "") + "/" : "";
4
17
  let clientPromise;
@@ -67,11 +80,14 @@ export function createS3Provider(options) {
67
80
  },
68
81
  async list(groupId) {
69
82
  const client = await getClient();
83
+ const keys = [];
84
+ for await (const key of client.listKeys(metaPrefix(groupId))) keys.push(key);
85
+ const metas = await mapWithConcurrency(keys, 32, (key) => readMeta(client, key));
70
86
  const files = [];
71
- for await (const key of client.listKeys(metaPrefix(groupId))) {
72
- const meta = await readMeta(client, key);
87
+ for (let i = 0; i < keys.length; i++) {
88
+ const meta = metas[i];
73
89
  if (!meta) continue;
74
- files.push(toStoredFile(idFromKey(key), groupId, meta));
90
+ files.push(toStoredFile(idFromKey(keys[i]), groupId, meta));
75
91
  }
76
92
  return files;
77
93
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-filer",
3
- "version": "0.0.14",
3
+ "version": "0.0.15",
4
4
  "description": "File storage module for Nuxt",
5
5
  "repository": {
6
6
  "type": "git",
@@ -38,6 +38,31 @@ export interface S3ProviderOptions {
38
38
 
39
39
  type InternalMeta = FileMeta & { _createdAt?: string; _updatedAt?: string };
40
40
 
41
+ /**
42
+ * Map over `items` with at most `limit` promises in flight, preserving order.
43
+ * Used to read many meta objects concurrently instead of one-at-a-time — on a
44
+ * remote store (R2/S3) the per-object round-trip latency dominates, so a
45
+ * sequential `for await` over N files is ~N × RTT. Bounded so a huge group
46
+ * doesn't open thousands of sockets at once.
47
+ */
48
+ async function mapWithConcurrency<T, R>(
49
+ items: T[],
50
+ limit: number,
51
+ fn: (item: T, index: number) => Promise<R>,
52
+ ): Promise<R[]> {
53
+ const results = new Array<R>(items.length);
54
+ let next = 0;
55
+ const worker = async () => {
56
+ while (next < items.length) {
57
+ const index = next++;
58
+ results[index] = await fn(items[index], index);
59
+ }
60
+ };
61
+ const workers = Array.from({ length: Math.min(limit, items.length) || 1 }, worker);
62
+ await Promise.all(workers);
63
+ return results;
64
+ }
65
+
41
66
  /**
42
67
  * S3-backed {@link FileStorageProvider}. Binary data and a JSON metadata
43
68
  * sidecar are stored as separate objects per file, mirroring the built-in
@@ -143,11 +168,17 @@ export function createS3Provider(options: S3ProviderOptions): FileStorageProvide
143
168
 
144
169
  async list(groupId) {
145
170
  const client = await getClient();
171
+ // Enumerate the group's meta keys (cheap paginated LIST), then read every
172
+ // meta object in parallel. The previous sequential read was one blocking
173
+ // GET per file, so listing a group cost ~N round-trips to the store.
174
+ const keys: string[] = [];
175
+ for await (const key of client.listKeys(metaPrefix(groupId))) keys.push(key);
176
+ const metas = await mapWithConcurrency(keys, 32, (key) => readMeta(client, key));
146
177
  const files: StoredFile[] = [];
147
- for await (const key of client.listKeys(metaPrefix(groupId))) {
148
- const meta = await readMeta(client, key);
178
+ for (let i = 0; i < keys.length; i++) {
179
+ const meta = metas[i];
149
180
  if (!meta) continue;
150
- files.push(toStoredFile(idFromKey(key), groupId, meta));
181
+ files.push(toStoredFile(idFromKey(keys[i]), groupId, meta));
151
182
  }
152
183
  return files;
153
184
  },