@hot-updater/supabase 0.35.11 → 0.36.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.
package/dist/edge.cjs CHANGED
@@ -1,4 +1,4 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_supabaseEdgeFunctionStorage = require("./supabaseEdgeFunctionStorage-DRxwDPRy.cjs");
2
+ const require_supabaseEdgeFunctionStorage = require("./supabaseEdgeFunctionStorage-CRgm-8_T.cjs");
3
3
  exports.supabaseEdgeFunctionDatabase = require_supabaseEdgeFunctionStorage.supabaseEdgeFunctionDatabase;
4
4
  exports.supabaseEdgeFunctionStorage = require_supabaseEdgeFunctionStorage.supabaseEdgeFunctionStorage;
package/dist/edge.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { n as supabaseEdgeFunctionDatabase, t as supabaseEdgeFunctionStorage } from "./supabaseEdgeFunctionStorage-CO70azPw.mjs";
1
+ import { r as supabaseEdgeFunctionDatabase, t as supabaseEdgeFunctionStorage } from "./supabaseEdgeFunctionStorage-DaRCRhn-.mjs";
2
2
  export { supabaseEdgeFunctionDatabase, supabaseEdgeFunctionStorage };
package/dist/index.cjs CHANGED
@@ -21,7 +21,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
21
21
  enumerable: true
22
22
  }) : target, mod));
23
23
  //#endregion
24
- const require_supabaseEdgeFunctionStorage = require("./supabaseEdgeFunctionStorage-DRxwDPRy.cjs");
24
+ const require_supabaseEdgeFunctionStorage = require("./supabaseEdgeFunctionStorage-CRgm-8_T.cjs");
25
25
  let _hot_updater_plugin_core = require("@hot-updater/plugin-core");
26
26
  let _supabase_supabase_js = require("@supabase/supabase-js");
27
27
  let fs_promises = require("fs/promises");
@@ -60,6 +60,11 @@ const supabaseStorage = (0, _hot_updater_plugin_core.createUniversalStoragePlugi
60
60
  factory: (config) => {
61
61
  const bucket = (0, _supabase_supabase_js.createClient)(config.supabaseUrl, require_supabaseEdgeFunctionStorage.resolveSupabaseServiceRoleKey(config)).storage.from(config.bucketName);
62
62
  const getStorageKey = (0, _hot_updater_plugin_core.createStorageKeyBuilder)(config.basePath);
63
+ const resolveSignedUrl = require_supabaseEdgeFunctionStorage.createSupabaseSignedUrlBatcher({
64
+ createSignedUrls: (_bucketName, keys, expiresIn) => bucket.createSignedUrls(keys, expiresIn),
65
+ expiresIn: 3600,
66
+ formatObjectPath: (_bucketName, key) => key
67
+ });
63
68
  return {
64
69
  node: {
65
70
  async delete(storageUri) {
@@ -127,11 +132,7 @@ const supabaseStorage = (0, _hot_updater_plugin_core.createUniversalStoragePlugi
127
132
  let key = `${u.host}${u.pathname}`.replace(/^\//, "");
128
133
  if (!key) throw new Error("Invalid Supabase storage URI: missing key");
129
134
  if (key.startsWith(`${config.bucketName}/`)) key = key.substring(`${config.bucketName}/`.length);
130
- return { fileUrl: await createSignedUrlOrThrow({
131
- bucket,
132
- key,
133
- expiresIn: 3600
134
- }) };
135
+ return { fileUrl: await resolveSignedUrl(config.bucketName, key) };
135
136
  }
136
137
  }
137
138
  };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { i as resolveSupabaseServiceRoleKey, n as supabaseEdgeFunctionDatabase, r as supabaseDatabase, t as supabaseEdgeFunctionStorage } from "./supabaseEdgeFunctionStorage-CO70azPw.mjs";
1
+ import { a as resolveSupabaseServiceRoleKey, i as supabaseDatabase, n as createSupabaseSignedUrlBatcher, r as supabaseEdgeFunctionDatabase, t as supabaseEdgeFunctionStorage } from "./supabaseEdgeFunctionStorage-DaRCRhn-.mjs";
2
2
  import { createStorageKeyBuilder, createUniversalStoragePlugin, getContentType, parseStorageUri } from "@hot-updater/plugin-core";
3
3
  import { createClient } from "@supabase/supabase-js";
4
4
  import fs from "fs/promises";
@@ -35,6 +35,11 @@ const supabaseStorage = createUniversalStoragePlugin({
35
35
  factory: (config) => {
36
36
  const bucket = createClient(config.supabaseUrl, resolveSupabaseServiceRoleKey(config)).storage.from(config.bucketName);
37
37
  const getStorageKey = createStorageKeyBuilder(config.basePath);
38
+ const resolveSignedUrl = createSupabaseSignedUrlBatcher({
39
+ createSignedUrls: (_bucketName, keys, expiresIn) => bucket.createSignedUrls(keys, expiresIn),
40
+ expiresIn: 3600,
41
+ formatObjectPath: (_bucketName, key) => key
42
+ });
38
43
  return {
39
44
  node: {
40
45
  async delete(storageUri) {
@@ -102,11 +107,7 @@ const supabaseStorage = createUniversalStoragePlugin({
102
107
  let key = `${u.host}${u.pathname}`.replace(/^\//, "");
103
108
  if (!key) throw new Error("Invalid Supabase storage URI: missing key");
104
109
  if (key.startsWith(`${config.bucketName}/`)) key = key.substring(`${config.bucketName}/`.length);
105
- return { fileUrl: await createSignedUrlOrThrow({
106
- bucket,
107
- key,
108
- expiresIn: 3600
109
- }) };
110
+ return { fileUrl: await resolveSignedUrl(config.bucketName, key) };
110
111
  }
111
112
  }
112
113
  };
@@ -264,12 +264,59 @@ const supabaseEdgeFunctionDatabase = (config, hooks) => {
264
264
  }, hooks);
265
265
  };
266
266
  //#endregion
267
- //#region src/supabaseEdgeFunctionStorage.ts
267
+ //#region src/supabaseSignedUrlBatcher.ts
268
268
  function getErrorMessage(error) {
269
269
  if (error instanceof Error) return error.message;
270
270
  if (error && typeof error === "object" && "message" in error && typeof error.message === "string") return error.message;
271
271
  return String(error);
272
272
  }
273
+ const createSupabaseSignedUrlBatcher = ({ createSignedUrls, expiresIn, formatObjectPath }) => {
274
+ let pendingByBucket = /* @__PURE__ */ new Map();
275
+ let flushScheduled = false;
276
+ const createSignedUrlError = (bucketName, key, error) => /* @__PURE__ */ new Error(`Failed to generate download URL for "${formatObjectPath(bucketName, key)}": ${getErrorMessage(error)}`);
277
+ const flush = async () => {
278
+ const batches = pendingByBucket;
279
+ pendingByBucket = /* @__PURE__ */ new Map();
280
+ flushScheduled = false;
281
+ await Promise.all([...batches.entries()].map(async ([bucketName, pending]) => {
282
+ try {
283
+ const { data, error } = await createSignedUrls(bucketName, pending.map(({ key }) => key), expiresIn);
284
+ if (error || !data) {
285
+ const batchError = error ?? /* @__PURE__ */ new Error("missing signed URL response");
286
+ for (const request of pending) request.reject(createSignedUrlError(bucketName, request.key, batchError));
287
+ return;
288
+ }
289
+ pending.forEach((request, index) => {
290
+ const result = data[index];
291
+ if (!result?.error && result?.signedUrl) {
292
+ request.resolve(result.signedUrl);
293
+ return;
294
+ }
295
+ request.reject(createSignedUrlError(bucketName, request.key, result?.error ?? /* @__PURE__ */ new Error("missing signed URL")));
296
+ });
297
+ } catch (error) {
298
+ for (const request of pending) request.reject(createSignedUrlError(bucketName, request.key, error));
299
+ }
300
+ }));
301
+ };
302
+ return (bucketName, key) => new Promise((resolve, reject) => {
303
+ const pending = pendingByBucket.get(bucketName) ?? [];
304
+ pending.push({
305
+ key,
306
+ reject,
307
+ resolve
308
+ });
309
+ pendingByBucket.set(bucketName, pending);
310
+ if (!flushScheduled) {
311
+ flushScheduled = true;
312
+ queueMicrotask(() => {
313
+ flush();
314
+ });
315
+ }
316
+ });
317
+ };
318
+ //#endregion
319
+ //#region src/supabaseEdgeFunctionStorage.ts
273
320
  const parseSupabaseStorageUri = (storageUri) => {
274
321
  const storageUrl = new URL(storageUri);
275
322
  if (storageUrl.protocol !== "supabase-storage:") throw new Error("Invalid Supabase storage URI protocol");
@@ -286,6 +333,11 @@ const supabaseEdgeFunctionStorage = (0, _hot_updater_plugin_core.createRuntimeSt
286
333
  supportedProtocol: "supabase-storage",
287
334
  factory: (config) => {
288
335
  const supabase = (0, _supabase_supabase_js.createClient)(config.supabaseUrl, config.supabaseServiceRoleKey);
336
+ const resolveSignedUrl = createSupabaseSignedUrlBatcher({
337
+ createSignedUrls: (bucketName, keys, expiresIn) => supabase.storage.from(bucketName).createSignedUrls(keys, expiresIn),
338
+ expiresIn: config.signedUrlExpiresIn ?? 3600,
339
+ formatObjectPath: (bucketName, key) => `${bucketName}/${key}`
340
+ });
289
341
  return {
290
342
  async readText(storageUri) {
291
343
  const { bucketName, key } = parseSupabaseStorageUri(storageUri);
@@ -299,24 +351,18 @@ const supabaseEdgeFunctionStorage = (0, _hot_updater_plugin_core.createRuntimeSt
299
351
  },
300
352
  async getDownloadUrl(storageUri) {
301
353
  const { bucketName, key } = parseSupabaseStorageUri(storageUri);
302
- const bucket = supabase.storage.from(bucketName);
303
- const expiresIn = config.signedUrlExpiresIn ?? 3600;
304
- let data = null;
305
- let error = null;
306
- try {
307
- const response = await bucket.createSignedUrl(key, expiresIn);
308
- data = response.data;
309
- error = response.error;
310
- } catch (thrownError) {
311
- error = thrownError;
312
- }
313
- if (!error && data?.signedUrl) return { fileUrl: data.signedUrl };
314
- throw new Error(`Failed to generate download URL for "${bucketName}/${key}": ${getErrorMessage(error ?? /* @__PURE__ */ new Error("missing signed URL"))}`);
354
+ return { fileUrl: await resolveSignedUrl(bucketName, key) };
315
355
  }
316
356
  };
317
357
  }
318
358
  });
319
359
  //#endregion
360
+ Object.defineProperty(exports, "createSupabaseSignedUrlBatcher", {
361
+ enumerable: true,
362
+ get: function() {
363
+ return createSupabaseSignedUrlBatcher;
364
+ }
365
+ });
320
366
  Object.defineProperty(exports, "resolveSupabaseServiceRoleKey", {
321
367
  enumerable: true,
322
368
  get: function() {
@@ -263,12 +263,59 @@ const supabaseEdgeFunctionDatabase = (config, hooks) => {
263
263
  }, hooks);
264
264
  };
265
265
  //#endregion
266
- //#region src/supabaseEdgeFunctionStorage.ts
266
+ //#region src/supabaseSignedUrlBatcher.ts
267
267
  function getErrorMessage(error) {
268
268
  if (error instanceof Error) return error.message;
269
269
  if (error && typeof error === "object" && "message" in error && typeof error.message === "string") return error.message;
270
270
  return String(error);
271
271
  }
272
+ const createSupabaseSignedUrlBatcher = ({ createSignedUrls, expiresIn, formatObjectPath }) => {
273
+ let pendingByBucket = /* @__PURE__ */ new Map();
274
+ let flushScheduled = false;
275
+ const createSignedUrlError = (bucketName, key, error) => /* @__PURE__ */ new Error(`Failed to generate download URL for "${formatObjectPath(bucketName, key)}": ${getErrorMessage(error)}`);
276
+ const flush = async () => {
277
+ const batches = pendingByBucket;
278
+ pendingByBucket = /* @__PURE__ */ new Map();
279
+ flushScheduled = false;
280
+ await Promise.all([...batches.entries()].map(async ([bucketName, pending]) => {
281
+ try {
282
+ const { data, error } = await createSignedUrls(bucketName, pending.map(({ key }) => key), expiresIn);
283
+ if (error || !data) {
284
+ const batchError = error ?? /* @__PURE__ */ new Error("missing signed URL response");
285
+ for (const request of pending) request.reject(createSignedUrlError(bucketName, request.key, batchError));
286
+ return;
287
+ }
288
+ pending.forEach((request, index) => {
289
+ const result = data[index];
290
+ if (!result?.error && result?.signedUrl) {
291
+ request.resolve(result.signedUrl);
292
+ return;
293
+ }
294
+ request.reject(createSignedUrlError(bucketName, request.key, result?.error ?? /* @__PURE__ */ new Error("missing signed URL")));
295
+ });
296
+ } catch (error) {
297
+ for (const request of pending) request.reject(createSignedUrlError(bucketName, request.key, error));
298
+ }
299
+ }));
300
+ };
301
+ return (bucketName, key) => new Promise((resolve, reject) => {
302
+ const pending = pendingByBucket.get(bucketName) ?? [];
303
+ pending.push({
304
+ key,
305
+ reject,
306
+ resolve
307
+ });
308
+ pendingByBucket.set(bucketName, pending);
309
+ if (!flushScheduled) {
310
+ flushScheduled = true;
311
+ queueMicrotask(() => {
312
+ flush();
313
+ });
314
+ }
315
+ });
316
+ };
317
+ //#endregion
318
+ //#region src/supabaseEdgeFunctionStorage.ts
272
319
  const parseSupabaseStorageUri = (storageUri) => {
273
320
  const storageUrl = new URL(storageUri);
274
321
  if (storageUrl.protocol !== "supabase-storage:") throw new Error("Invalid Supabase storage URI protocol");
@@ -285,6 +332,11 @@ const supabaseEdgeFunctionStorage = createRuntimeStoragePlugin({
285
332
  supportedProtocol: "supabase-storage",
286
333
  factory: (config) => {
287
334
  const supabase = createClient(config.supabaseUrl, config.supabaseServiceRoleKey);
335
+ const resolveSignedUrl = createSupabaseSignedUrlBatcher({
336
+ createSignedUrls: (bucketName, keys, expiresIn) => supabase.storage.from(bucketName).createSignedUrls(keys, expiresIn),
337
+ expiresIn: config.signedUrlExpiresIn ?? 3600,
338
+ formatObjectPath: (bucketName, key) => `${bucketName}/${key}`
339
+ });
288
340
  return {
289
341
  async readText(storageUri) {
290
342
  const { bucketName, key } = parseSupabaseStorageUri(storageUri);
@@ -298,22 +350,10 @@ const supabaseEdgeFunctionStorage = createRuntimeStoragePlugin({
298
350
  },
299
351
  async getDownloadUrl(storageUri) {
300
352
  const { bucketName, key } = parseSupabaseStorageUri(storageUri);
301
- const bucket = supabase.storage.from(bucketName);
302
- const expiresIn = config.signedUrlExpiresIn ?? 3600;
303
- let data = null;
304
- let error = null;
305
- try {
306
- const response = await bucket.createSignedUrl(key, expiresIn);
307
- data = response.data;
308
- error = response.error;
309
- } catch (thrownError) {
310
- error = thrownError;
311
- }
312
- if (!error && data?.signedUrl) return { fileUrl: data.signedUrl };
313
- throw new Error(`Failed to generate download URL for "${bucketName}/${key}": ${getErrorMessage(error ?? /* @__PURE__ */ new Error("missing signed URL"))}`);
353
+ return { fileUrl: await resolveSignedUrl(bucketName, key) };
314
354
  }
315
355
  };
316
356
  }
317
357
  });
318
358
  //#endregion
319
- export { resolveSupabaseServiceRoleKey as i, supabaseEdgeFunctionDatabase as n, supabaseDatabase as r, supabaseEdgeFunctionStorage as t };
359
+ export { resolveSupabaseServiceRoleKey as a, supabaseDatabase as i, createSupabaseSignedUrlBatcher as n, supabaseEdgeFunctionDatabase as r, supabaseEdgeFunctionStorage as t };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@hot-updater/supabase",
3
3
  "type": "module",
4
- "version": "0.35.11",
4
+ "version": "0.36.0",
5
5
  "description": "React Native OTA solution for self-hosted",
6
6
  "main": "dist/index.cjs",
7
7
  "module": "dist/index.mjs",
@@ -55,10 +55,10 @@
55
55
  "@supabase/supabase-js": "2.76.1",
56
56
  "hono": "4.12.9",
57
57
  "uuidv7": "^1.0.2",
58
- "@hot-updater/core": "0.35.11",
59
- "@hot-updater/cli-tools": "0.35.11",
60
- "@hot-updater/server": "0.35.11",
61
- "@hot-updater/plugin-core": "0.35.11"
58
+ "@hot-updater/core": "0.36.0",
59
+ "@hot-updater/cli-tools": "0.36.0",
60
+ "@hot-updater/server": "0.36.0",
61
+ "@hot-updater/plugin-core": "0.36.0"
62
62
  },
63
63
  "devDependencies": {
64
64
  "@electric-sql/pglite": "0.4.1",
@@ -68,10 +68,10 @@
68
68
  "execa": "9.5.2",
69
69
  "@types/node": "^20",
70
70
  "mime": "^4.0.4",
71
- "@hot-updater/js": "0.35.11",
72
- "@hot-updater/mock": "0.35.11",
73
- "@hot-updater/postgres": "0.35.11",
74
- "@hot-updater/test-utils": "0.35.11"
71
+ "@hot-updater/js": "0.36.0",
72
+ "@hot-updater/mock": "0.36.0",
73
+ "@hot-updater/test-utils": "0.36.0",
74
+ "@hot-updater/postgres": "0.36.0"
75
75
  },
76
76
  "scripts": {
77
77
  "build": "tsdown",