@hot-updater/supabase 0.31.3 → 0.32.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 +1 -1
- package/dist/edge.d.cts +1 -1
- package/dist/edge.d.mts +1 -1
- package/dist/edge.mjs +1 -1
- package/dist/iac/index.cjs +33 -14
- package/dist/iac/index.d.cts +2 -1
- package/dist/iac/index.d.mts +2 -1
- package/dist/iac/index.mjs +28 -10
- package/dist/index.cjs +50 -8
- package/dist/index.d.cts +17 -10
- package/dist/index.d.mts +17 -10
- package/dist/index.mjs +48 -6
- package/dist/{supabaseEdgeFunctionStorage-BKU_mLzA.mjs → supabaseEdgeFunctionStorage-B4KN0khj.mjs} +28 -7
- package/dist/{supabaseEdgeFunctionStorage-CXmcRBZ2.d.mts → supabaseEdgeFunctionStorage-BRxGvt-r.d.mts} +3 -2
- package/dist/{supabaseEdgeFunctionStorage-hkokSgXP.d.cts → supabaseEdgeFunctionStorage-CU396KO3.d.cts} +3 -2
- package/dist/{supabaseEdgeFunctionStorage-BZC0Z0XP.cjs → supabaseEdgeFunctionStorage-D933mGy9.cjs} +33 -6
- package/package.json +9 -9
- package/supabase/edge-functions/index.ts +0 -1
- package/supabase/migrations/20260520014100_hot-updater_rls.sql +48 -0
- package/supabase/migrations.spec.ts +67 -0
package/dist/edge.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_supabaseEdgeFunctionStorage = require("./supabaseEdgeFunctionStorage-
|
|
2
|
+
const require_supabaseEdgeFunctionStorage = require("./supabaseEdgeFunctionStorage-D933mGy9.cjs");
|
|
3
3
|
exports.supabaseEdgeFunctionDatabase = require_supabaseEdgeFunctionStorage.supabaseEdgeFunctionDatabase;
|
|
4
4
|
exports.supabaseEdgeFunctionStorage = require_supabaseEdgeFunctionStorage.supabaseEdgeFunctionStorage;
|
package/dist/edge.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as supabaseEdgeFunctionDatabase, n as supabaseEdgeFunctionStorage } from "./supabaseEdgeFunctionStorage-
|
|
1
|
+
import { i as supabaseEdgeFunctionDatabase, n as supabaseEdgeFunctionStorage } from "./supabaseEdgeFunctionStorage-CU396KO3.cjs";
|
|
2
2
|
export { supabaseEdgeFunctionDatabase, supabaseEdgeFunctionStorage };
|
package/dist/edge.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as supabaseEdgeFunctionDatabase, n as supabaseEdgeFunctionStorage } from "./supabaseEdgeFunctionStorage-
|
|
1
|
+
import { i as supabaseEdgeFunctionDatabase, n as supabaseEdgeFunctionStorage } from "./supabaseEdgeFunctionStorage-BRxGvt-r.mjs";
|
|
2
2
|
export { supabaseEdgeFunctionDatabase, supabaseEdgeFunctionStorage };
|
package/dist/edge.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as supabaseEdgeFunctionDatabase, t as supabaseEdgeFunctionStorage } from "./supabaseEdgeFunctionStorage-
|
|
1
|
+
import { n as supabaseEdgeFunctionDatabase, t as supabaseEdgeFunctionStorage } from "./supabaseEdgeFunctionStorage-B4KN0khj.mjs";
|
|
2
2
|
export { supabaseEdgeFunctionDatabase, supabaseEdgeFunctionStorage };
|
package/dist/iac/index.cjs
CHANGED
|
@@ -6,7 +6,7 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
6
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
7
|
var __getProtoOf = Object.getPrototypeOf;
|
|
8
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
-
var __commonJSMin = (cb, mod) => () => (mod ||
|
|
9
|
+
var __commonJSMin = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
10
10
|
var __copyProps = (to, from, except, desc) => {
|
|
11
11
|
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
12
12
|
key = keys[i];
|
|
@@ -23,21 +23,21 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
23
|
}) : target, mod));
|
|
24
24
|
//#endregion
|
|
25
25
|
let fs_promises = require("fs/promises");
|
|
26
|
-
fs_promises = __toESM(fs_promises
|
|
26
|
+
fs_promises = __toESM(fs_promises);
|
|
27
27
|
let node_module = require("node:module");
|
|
28
28
|
let path = require("path");
|
|
29
|
-
path = __toESM(path
|
|
29
|
+
path = __toESM(path);
|
|
30
30
|
let _hot_updater_cli_tools = require("@hot-updater/cli-tools");
|
|
31
31
|
let node_url = require("node:url");
|
|
32
32
|
let node_child_process = require("node:child_process");
|
|
33
33
|
let node_string_decoder = require("node:string_decoder");
|
|
34
34
|
let node_util = require("node:util");
|
|
35
35
|
let node_process = require("node:process");
|
|
36
|
-
node_process = __toESM(node_process
|
|
36
|
+
node_process = __toESM(node_process);
|
|
37
37
|
let node_tty = require("node:tty");
|
|
38
|
-
node_tty = __toESM(node_tty
|
|
38
|
+
node_tty = __toESM(node_tty);
|
|
39
39
|
let node_path = require("node:path");
|
|
40
|
-
node_path = __toESM(node_path
|
|
40
|
+
node_path = __toESM(node_path);
|
|
41
41
|
let node_timers_promises = require("node:timers/promises");
|
|
42
42
|
let node_os = require("node:os");
|
|
43
43
|
let node_events = require("node:events");
|
|
@@ -6233,8 +6233,8 @@ createExeca(mapScriptAsync, {}, deepScriptOptions, setScriptSync);
|
|
|
6233
6233
|
const { sendMessage, getOneMessage, getEachMessage, getCancelSignal } = getIpcExport();
|
|
6234
6234
|
//#endregion
|
|
6235
6235
|
//#region iac/supabaseApi.ts
|
|
6236
|
-
const supabaseApi = (supabaseUrl,
|
|
6237
|
-
const supabase = (0, _supabase_supabase_js.createClient)(supabaseUrl,
|
|
6236
|
+
const supabaseApi = (supabaseUrl, supabaseServiceRoleKey) => {
|
|
6237
|
+
const supabase = (0, _supabase_supabase_js.createClient)(supabaseUrl, supabaseServiceRoleKey);
|
|
6238
6238
|
return {
|
|
6239
6239
|
listBuckets: async () => {
|
|
6240
6240
|
const { data, error } = await supabase.storage.listBuckets();
|
|
@@ -6268,7 +6268,7 @@ const getConfigScaffold = (build) => {
|
|
|
6268
6268
|
}],
|
|
6269
6269
|
configString: `supabaseStorage({
|
|
6270
6270
|
supabaseUrl: process.env.HOT_UPDATER_SUPABASE_URL!,
|
|
6271
|
-
|
|
6271
|
+
supabaseServiceRoleKey: process.env.HOT_UPDATER_SUPABASE_SERVICE_ROLE_KEY!,
|
|
6272
6272
|
bucketName: process.env.HOT_UPDATER_SUPABASE_BUCKET_NAME!,
|
|
6273
6273
|
})`
|
|
6274
6274
|
}).setDatabase({
|
|
@@ -6278,10 +6278,27 @@ const getConfigScaffold = (build) => {
|
|
|
6278
6278
|
}],
|
|
6279
6279
|
configString: `supabaseDatabase({
|
|
6280
6280
|
supabaseUrl: process.env.HOT_UPDATER_SUPABASE_URL!,
|
|
6281
|
-
|
|
6281
|
+
supabaseServiceRoleKey: process.env.HOT_UPDATER_SUPABASE_SERVICE_ROLE_KEY!,
|
|
6282
6282
|
})`
|
|
6283
6283
|
}));
|
|
6284
6284
|
};
|
|
6285
|
+
const getLegacySupabaseConfigReference = (configText) => {
|
|
6286
|
+
if (configText.includes("HOT_UPDATER_SUPABASE_ANON_KEY")) return "HOT_UPDATER_SUPABASE_ANON_KEY";
|
|
6287
|
+
if (/\bsupabaseAnonKey\s*:/.test(configText)) return "supabaseAnonKey";
|
|
6288
|
+
return null;
|
|
6289
|
+
};
|
|
6290
|
+
const assertSkippedConfigDoesNotUseLegacySupabaseKey = async (configWriteResult) => {
|
|
6291
|
+
if (configWriteResult.status !== "skipped") return;
|
|
6292
|
+
const configText = await fs_promises.default.readFile(configWriteResult.path, "utf-8").catch((error) => {
|
|
6293
|
+
if (error.code === "ENOENT") return null;
|
|
6294
|
+
throw error;
|
|
6295
|
+
});
|
|
6296
|
+
const legacyReference = configText === null ? null : getLegacySupabaseConfigReference(configText);
|
|
6297
|
+
if (!legacyReference) return;
|
|
6298
|
+
_hot_updater_cli_tools.p.log.error(`Existing '${configWriteResult.path}' still references '${legacyReference}'.`);
|
|
6299
|
+
_hot_updater_cli_tools.p.log.message("Update it to use 'supabaseServiceRoleKey' with 'HOT_UPDATER_SUPABASE_SERVICE_ROLE_KEY', then run init again.");
|
|
6300
|
+
process.exit(1);
|
|
6301
|
+
};
|
|
6285
6302
|
const SOURCE_TEMPLATE = `// add this to your App.tsx
|
|
6286
6303
|
import { HotUpdater } from "@hot-updater/react-native";
|
|
6287
6304
|
|
|
@@ -6642,9 +6659,9 @@ const runInit = async ({ build }) => {
|
|
|
6642
6659
|
process.exit(1);
|
|
6643
6660
|
}
|
|
6644
6661
|
spinner.stop();
|
|
6645
|
-
const
|
|
6646
|
-
if (!
|
|
6647
|
-
const bucket = await selectBucket(supabaseApi(`https://${project.id}.supabase.co`,
|
|
6662
|
+
const serviceRoleApiKey = apiKeys.find((key) => key.name === "service_role");
|
|
6663
|
+
if (!serviceRoleApiKey) throw new Error("Service role key not found, is your project paused?");
|
|
6664
|
+
const bucket = await selectBucket(supabaseApi(`https://${project.id}.supabase.co`, serviceRoleApiKey.api_key));
|
|
6648
6665
|
const { tmpDir, removeTmpDir } = await (0, _hot_updater_cli_tools.copyDirToTmp)(path.default.dirname(path.default.resolve(require$1.resolve("@hot-updater/supabase/scaffold"))), "supabase");
|
|
6649
6666
|
const migrationPath = await path.default.join(tmpDir, "supabase", "migrations");
|
|
6650
6667
|
const migrationFiles = await fs_promises.default.readdir(migrationPath);
|
|
@@ -6663,8 +6680,9 @@ const runInit = async ({ build }) => {
|
|
|
6663
6680
|
await deployEdgeFunction(tmpDir, project.id);
|
|
6664
6681
|
await removeTmpDir();
|
|
6665
6682
|
const configWriteResult = await (0, _hot_updater_cli_tools.writeHotUpdaterConfig)(getConfigScaffold(build));
|
|
6683
|
+
await assertSkippedConfigDoesNotUseLegacySupabaseKey(configWriteResult);
|
|
6666
6684
|
await (0, _hot_updater_cli_tools.makeEnv)({
|
|
6667
|
-
|
|
6685
|
+
HOT_UPDATER_SUPABASE_SERVICE_ROLE_KEY: serviceRoleApiKey.api_key,
|
|
6668
6686
|
HOT_UPDATER_SUPABASE_BUCKET_NAME: bucket.name,
|
|
6669
6687
|
HOT_UPDATER_SUPABASE_URL: `https://${project.id}.supabase.co`
|
|
6670
6688
|
});
|
|
@@ -6677,6 +6695,7 @@ const runInit = async ({ build }) => {
|
|
|
6677
6695
|
_hot_updater_cli_tools.p.log.success("Done! 🎉");
|
|
6678
6696
|
};
|
|
6679
6697
|
//#endregion
|
|
6698
|
+
exports.getLegacySupabaseConfigReference = getLegacySupabaseConfigReference;
|
|
6680
6699
|
exports.resolveEdgeFunctionDenoConfig = resolveEdgeFunctionDenoConfig;
|
|
6681
6700
|
exports.runInit = runInit;
|
|
6682
6701
|
exports.selectBucket = selectBucket;
|
package/dist/iac/index.d.cts
CHANGED
|
@@ -16,6 +16,7 @@ interface SupabaseApi {
|
|
|
16
16
|
}
|
|
17
17
|
//#endregion
|
|
18
18
|
//#region iac/index.d.ts
|
|
19
|
+
declare const getLegacySupabaseConfigReference: (configText: string) => "HOT_UPDATER_SUPABASE_ANON_KEY" | "supabaseAnonKey" | null;
|
|
19
20
|
declare const resolveEdgeFunctionDenoConfig: (targetDir: string) => Promise<{
|
|
20
21
|
imports: Record<string, string>;
|
|
21
22
|
}>;
|
|
@@ -34,4 +35,4 @@ declare const runInit: ({
|
|
|
34
35
|
build: BuildType;
|
|
35
36
|
}) => Promise<void>;
|
|
36
37
|
//#endregion
|
|
37
|
-
export { resolveEdgeFunctionDenoConfig, runInit, selectBucket, selectProject };
|
|
38
|
+
export { getLegacySupabaseConfigReference, resolveEdgeFunctionDenoConfig, runInit, selectBucket, selectProject };
|
package/dist/iac/index.d.mts
CHANGED
|
@@ -16,6 +16,7 @@ interface SupabaseApi {
|
|
|
16
16
|
}
|
|
17
17
|
//#endregion
|
|
18
18
|
//#region iac/index.d.ts
|
|
19
|
+
declare const getLegacySupabaseConfigReference: (configText: string) => "HOT_UPDATER_SUPABASE_ANON_KEY" | "supabaseAnonKey" | null;
|
|
19
20
|
declare const resolveEdgeFunctionDenoConfig: (targetDir: string) => Promise<{
|
|
20
21
|
imports: Record<string, string>;
|
|
21
22
|
}>;
|
|
@@ -34,4 +35,4 @@ declare const runInit: ({
|
|
|
34
35
|
build: BuildType;
|
|
35
36
|
}) => Promise<void>;
|
|
36
37
|
//#endregion
|
|
37
|
-
export { resolveEdgeFunctionDenoConfig, runInit, selectBucket, selectProject };
|
|
38
|
+
export { getLegacySupabaseConfigReference, resolveEdgeFunctionDenoConfig, runInit, selectBucket, selectProject };
|
package/dist/iac/index.mjs
CHANGED
|
@@ -25,7 +25,7 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
25
25
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
26
26
|
var __getProtoOf = Object.getPrototypeOf;
|
|
27
27
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
28
|
-
var __commonJSMin = (cb, mod) => () => (mod ||
|
|
28
|
+
var __commonJSMin = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
29
29
|
var __copyProps = (to, from, except, desc) => {
|
|
30
30
|
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
31
31
|
key = keys[i];
|
|
@@ -6228,8 +6228,8 @@ createExeca(mapScriptAsync, {}, deepScriptOptions, setScriptSync);
|
|
|
6228
6228
|
const { sendMessage, getOneMessage, getEachMessage, getCancelSignal } = getIpcExport();
|
|
6229
6229
|
//#endregion
|
|
6230
6230
|
//#region iac/supabaseApi.ts
|
|
6231
|
-
const supabaseApi = (supabaseUrl,
|
|
6232
|
-
const supabase = createClient(supabaseUrl,
|
|
6231
|
+
const supabaseApi = (supabaseUrl, supabaseServiceRoleKey) => {
|
|
6232
|
+
const supabase = createClient(supabaseUrl, supabaseServiceRoleKey);
|
|
6233
6233
|
return {
|
|
6234
6234
|
listBuckets: async () => {
|
|
6235
6235
|
const { data, error } = await supabase.storage.listBuckets();
|
|
@@ -6263,7 +6263,7 @@ const getConfigScaffold = (build) => {
|
|
|
6263
6263
|
}],
|
|
6264
6264
|
configString: `supabaseStorage({
|
|
6265
6265
|
supabaseUrl: process.env.HOT_UPDATER_SUPABASE_URL!,
|
|
6266
|
-
|
|
6266
|
+
supabaseServiceRoleKey: process.env.HOT_UPDATER_SUPABASE_SERVICE_ROLE_KEY!,
|
|
6267
6267
|
bucketName: process.env.HOT_UPDATER_SUPABASE_BUCKET_NAME!,
|
|
6268
6268
|
})`
|
|
6269
6269
|
}).setDatabase({
|
|
@@ -6273,10 +6273,27 @@ const getConfigScaffold = (build) => {
|
|
|
6273
6273
|
}],
|
|
6274
6274
|
configString: `supabaseDatabase({
|
|
6275
6275
|
supabaseUrl: process.env.HOT_UPDATER_SUPABASE_URL!,
|
|
6276
|
-
|
|
6276
|
+
supabaseServiceRoleKey: process.env.HOT_UPDATER_SUPABASE_SERVICE_ROLE_KEY!,
|
|
6277
6277
|
})`
|
|
6278
6278
|
}));
|
|
6279
6279
|
};
|
|
6280
|
+
const getLegacySupabaseConfigReference = (configText) => {
|
|
6281
|
+
if (configText.includes("HOT_UPDATER_SUPABASE_ANON_KEY")) return "HOT_UPDATER_SUPABASE_ANON_KEY";
|
|
6282
|
+
if (/\bsupabaseAnonKey\s*:/.test(configText)) return "supabaseAnonKey";
|
|
6283
|
+
return null;
|
|
6284
|
+
};
|
|
6285
|
+
const assertSkippedConfigDoesNotUseLegacySupabaseKey = async (configWriteResult) => {
|
|
6286
|
+
if (configWriteResult.status !== "skipped") return;
|
|
6287
|
+
const configText = await fs.readFile(configWriteResult.path, "utf-8").catch((error) => {
|
|
6288
|
+
if (error.code === "ENOENT") return null;
|
|
6289
|
+
throw error;
|
|
6290
|
+
});
|
|
6291
|
+
const legacyReference = configText === null ? null : getLegacySupabaseConfigReference(configText);
|
|
6292
|
+
if (!legacyReference) return;
|
|
6293
|
+
p.log.error(`Existing '${configWriteResult.path}' still references '${legacyReference}'.`);
|
|
6294
|
+
p.log.message("Update it to use 'supabaseServiceRoleKey' with 'HOT_UPDATER_SUPABASE_SERVICE_ROLE_KEY', then run init again.");
|
|
6295
|
+
process.exit(1);
|
|
6296
|
+
};
|
|
6280
6297
|
const SOURCE_TEMPLATE = `// add this to your App.tsx
|
|
6281
6298
|
import { HotUpdater } from "@hot-updater/react-native";
|
|
6282
6299
|
|
|
@@ -6637,9 +6654,9 @@ const runInit = async ({ build }) => {
|
|
|
6637
6654
|
process.exit(1);
|
|
6638
6655
|
}
|
|
6639
6656
|
spinner.stop();
|
|
6640
|
-
const
|
|
6641
|
-
if (!
|
|
6642
|
-
const bucket = await selectBucket(supabaseApi(`https://${project.id}.supabase.co`,
|
|
6657
|
+
const serviceRoleApiKey = apiKeys.find((key) => key.name === "service_role");
|
|
6658
|
+
if (!serviceRoleApiKey) throw new Error("Service role key not found, is your project paused?");
|
|
6659
|
+
const bucket = await selectBucket(supabaseApi(`https://${project.id}.supabase.co`, serviceRoleApiKey.api_key));
|
|
6643
6660
|
const { tmpDir, removeTmpDir } = await copyDirToTmp(path.dirname(path.resolve(require$1.resolve("@hot-updater/supabase/scaffold"))), "supabase");
|
|
6644
6661
|
const migrationPath = await path.join(tmpDir, "supabase", "migrations");
|
|
6645
6662
|
const migrationFiles = await fs.readdir(migrationPath);
|
|
@@ -6658,8 +6675,9 @@ const runInit = async ({ build }) => {
|
|
|
6658
6675
|
await deployEdgeFunction(tmpDir, project.id);
|
|
6659
6676
|
await removeTmpDir();
|
|
6660
6677
|
const configWriteResult = await writeHotUpdaterConfig(getConfigScaffold(build));
|
|
6678
|
+
await assertSkippedConfigDoesNotUseLegacySupabaseKey(configWriteResult);
|
|
6661
6679
|
await makeEnv({
|
|
6662
|
-
|
|
6680
|
+
HOT_UPDATER_SUPABASE_SERVICE_ROLE_KEY: serviceRoleApiKey.api_key,
|
|
6663
6681
|
HOT_UPDATER_SUPABASE_BUCKET_NAME: bucket.name,
|
|
6664
6682
|
HOT_UPDATER_SUPABASE_URL: `https://${project.id}.supabase.co`
|
|
6665
6683
|
});
|
|
@@ -6672,4 +6690,4 @@ const runInit = async ({ build }) => {
|
|
|
6672
6690
|
p.log.success("Done! 🎉");
|
|
6673
6691
|
};
|
|
6674
6692
|
//#endregion
|
|
6675
|
-
export { resolveEdgeFunctionDenoConfig, runInit, selectBucket, selectProject };
|
|
6693
|
+
export { getLegacySupabaseConfigReference, resolveEdgeFunctionDenoConfig, runInit, selectBucket, selectProject };
|
package/dist/index.cjs
CHANGED
|
@@ -21,19 +21,44 @@ 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-
|
|
24
|
+
const require_supabaseEdgeFunctionStorage = require("./supabaseEdgeFunctionStorage-D933mGy9.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");
|
|
28
|
-
fs_promises = __toESM(fs_promises
|
|
28
|
+
fs_promises = __toESM(fs_promises);
|
|
29
29
|
let path = require("path");
|
|
30
|
-
path = __toESM(path
|
|
30
|
+
path = __toESM(path);
|
|
31
31
|
//#region src/supabaseStorage.ts
|
|
32
|
+
function getErrorMessage(error) {
|
|
33
|
+
if (error instanceof Error) return error.message;
|
|
34
|
+
if (error && typeof error === "object" && "message" in error && typeof error.message === "string") return error.message;
|
|
35
|
+
return String(error);
|
|
36
|
+
}
|
|
37
|
+
async function createSignedUrlOrThrow({ bucket, key, expiresIn }) {
|
|
38
|
+
let data = null;
|
|
39
|
+
let error = null;
|
|
40
|
+
try {
|
|
41
|
+
const response = await bucket.createSignedUrl(key, expiresIn);
|
|
42
|
+
data = response.data;
|
|
43
|
+
error = response.error;
|
|
44
|
+
} catch (thrownError) {
|
|
45
|
+
error = thrownError;
|
|
46
|
+
}
|
|
47
|
+
if (!error && data?.signedUrl) return data.signedUrl;
|
|
48
|
+
throw new Error(`Failed to generate download URL for "${key}": ${getErrorMessage(error ?? /* @__PURE__ */ new Error("missing signed URL"))}`);
|
|
49
|
+
}
|
|
50
|
+
async function verifyObjectCanBeSignedForRuntime({ bucket, key }) {
|
|
51
|
+
await createSignedUrlOrThrow({
|
|
52
|
+
bucket,
|
|
53
|
+
key,
|
|
54
|
+
expiresIn: 3600
|
|
55
|
+
});
|
|
56
|
+
}
|
|
32
57
|
const supabaseStorage = (0, _hot_updater_plugin_core.createUniversalStoragePlugin)({
|
|
33
58
|
name: "supabaseStorage",
|
|
34
59
|
supportedProtocol: "supabase-storage",
|
|
35
60
|
factory: (config) => {
|
|
36
|
-
const bucket = (0, _supabase_supabase_js.createClient)(config.supabaseUrl, config
|
|
61
|
+
const bucket = (0, _supabase_supabase_js.createClient)(config.supabaseUrl, require_supabaseEdgeFunctionStorage.resolveSupabaseServiceRoleKey(config)).storage.from(config.bucketName);
|
|
37
62
|
const getStorageKey = (0, _hot_updater_plugin_core.createStorageKeyBuilder)(config.basePath);
|
|
38
63
|
return {
|
|
39
64
|
node: {
|
|
@@ -56,8 +81,24 @@ const supabaseStorage = (0, _hot_updater_plugin_core.createUniversalStoragePlugi
|
|
|
56
81
|
headers: {}
|
|
57
82
|
});
|
|
58
83
|
if (upload.error) throw upload.error;
|
|
84
|
+
await verifyObjectCanBeSignedForRuntime({
|
|
85
|
+
bucket,
|
|
86
|
+
key: Key
|
|
87
|
+
});
|
|
59
88
|
return { storageUri: `supabase-storage://${upload.data.fullPath}` };
|
|
60
89
|
},
|
|
90
|
+
async exists(storageUri) {
|
|
91
|
+
const { key, bucket: bucketName } = (0, _hot_updater_plugin_core.parseStorageUri)(storageUri, "supabase-storage");
|
|
92
|
+
if (bucketName !== config.bucketName) throw new Error(`Bucket name mismatch: expected "${config.bucketName}", but found "${bucketName}".`);
|
|
93
|
+
const { data, error } = await bucket.exists(key);
|
|
94
|
+
if (data === false) return false;
|
|
95
|
+
if (error) throw error;
|
|
96
|
+
await verifyObjectCanBeSignedForRuntime({
|
|
97
|
+
bucket,
|
|
98
|
+
key
|
|
99
|
+
});
|
|
100
|
+
return data;
|
|
101
|
+
},
|
|
61
102
|
async downloadFile(storageUri, filePath) {
|
|
62
103
|
const { key, bucket: bucketName } = (0, _hot_updater_plugin_core.parseStorageUri)(storageUri, "supabase-storage");
|
|
63
104
|
if (bucketName !== config.bucketName) throw new Error(`Bucket name mismatch: expected "${config.bucketName}", but found "${bucketName}".`);
|
|
@@ -86,10 +127,11 @@ const supabaseStorage = (0, _hot_updater_plugin_core.createUniversalStoragePlugi
|
|
|
86
127
|
let key = `${u.host}${u.pathname}`.replace(/^\//, "");
|
|
87
128
|
if (!key) throw new Error("Invalid Supabase storage URI: missing key");
|
|
88
129
|
if (key.startsWith(`${config.bucketName}/`)) key = key.substring(`${config.bucketName}/`.length);
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
130
|
+
return { fileUrl: await createSignedUrlOrThrow({
|
|
131
|
+
bucket,
|
|
132
|
+
key,
|
|
133
|
+
expiresIn: 3600
|
|
134
|
+
}) };
|
|
93
135
|
}
|
|
94
136
|
}
|
|
95
137
|
};
|
package/dist/index.d.cts
CHANGED
|
@@ -1,22 +1,29 @@
|
|
|
1
|
-
import { i as supabaseEdgeFunctionDatabase, n as supabaseEdgeFunctionStorage, r as SupabaseEdgeFunctionDatabaseConfig, t as SupabaseEdgeFunctionStorageConfig } from "./supabaseEdgeFunctionStorage-
|
|
1
|
+
import { i as supabaseEdgeFunctionDatabase, n as supabaseEdgeFunctionStorage, r as SupabaseEdgeFunctionDatabaseConfig, t as SupabaseEdgeFunctionStorageConfig } from "./supabaseEdgeFunctionStorage-CU396KO3.cjs";
|
|
2
|
+
import * as _$_hot_updater_plugin_core0 from "@hot-updater/plugin-core";
|
|
2
3
|
|
|
3
|
-
//#region src/
|
|
4
|
-
|
|
4
|
+
//#region src/supabaseConfig.d.ts
|
|
5
|
+
type SupabaseServiceRoleConfig = {
|
|
6
|
+
supabaseUrl: string;
|
|
7
|
+
supabaseServiceRoleKey: string;
|
|
8
|
+
supabaseAnonKey?: string;
|
|
9
|
+
} | {
|
|
5
10
|
supabaseUrl: string;
|
|
6
11
|
supabaseAnonKey: string;
|
|
7
|
-
|
|
8
|
-
|
|
12
|
+
supabaseServiceRoleKey?: string;
|
|
13
|
+
};
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/supabaseDatabase.d.ts
|
|
16
|
+
type SupabaseDatabaseConfig = SupabaseServiceRoleConfig;
|
|
17
|
+
declare const supabaseDatabase: (config: SupabaseServiceRoleConfig, hooks?: _$_hot_updater_plugin_core0.DatabasePluginHooks) => () => _$_hot_updater_plugin_core0.DatabasePlugin<unknown>;
|
|
9
18
|
//#endregion
|
|
10
19
|
//#region src/supabaseStorage.d.ts
|
|
11
|
-
|
|
12
|
-
supabaseUrl: string;
|
|
13
|
-
supabaseAnonKey: string;
|
|
20
|
+
type SupabaseStorageConfig = SupabaseServiceRoleConfig & {
|
|
14
21
|
bucketName: string;
|
|
15
22
|
/**
|
|
16
23
|
* Base path where bundles will be stored in the bucket
|
|
17
24
|
*/
|
|
18
25
|
basePath?: string;
|
|
19
|
-
}
|
|
20
|
-
declare const supabaseStorage: (config: SupabaseStorageConfig, hooks?:
|
|
26
|
+
};
|
|
27
|
+
declare const supabaseStorage: (config: SupabaseStorageConfig, hooks?: _$_hot_updater_plugin_core0.StoragePluginHooks) => () => _$_hot_updater_plugin_core0.UniversalStoragePlugin<unknown>;
|
|
21
28
|
//#endregion
|
|
22
29
|
export { SupabaseDatabaseConfig, SupabaseEdgeFunctionDatabaseConfig, SupabaseEdgeFunctionStorageConfig, SupabaseStorageConfig, supabaseDatabase, supabaseEdgeFunctionDatabase, supabaseEdgeFunctionStorage, supabaseStorage };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,22 +1,29 @@
|
|
|
1
|
-
import { i as supabaseEdgeFunctionDatabase, n as supabaseEdgeFunctionStorage, r as SupabaseEdgeFunctionDatabaseConfig, t as SupabaseEdgeFunctionStorageConfig } from "./supabaseEdgeFunctionStorage-
|
|
1
|
+
import { i as supabaseEdgeFunctionDatabase, n as supabaseEdgeFunctionStorage, r as SupabaseEdgeFunctionDatabaseConfig, t as SupabaseEdgeFunctionStorageConfig } from "./supabaseEdgeFunctionStorage-BRxGvt-r.mjs";
|
|
2
|
+
import * as _$_hot_updater_plugin_core0 from "@hot-updater/plugin-core";
|
|
2
3
|
|
|
3
|
-
//#region src/
|
|
4
|
-
|
|
4
|
+
//#region src/supabaseConfig.d.ts
|
|
5
|
+
type SupabaseServiceRoleConfig = {
|
|
6
|
+
supabaseUrl: string;
|
|
7
|
+
supabaseServiceRoleKey: string;
|
|
8
|
+
supabaseAnonKey?: string;
|
|
9
|
+
} | {
|
|
5
10
|
supabaseUrl: string;
|
|
6
11
|
supabaseAnonKey: string;
|
|
7
|
-
|
|
8
|
-
|
|
12
|
+
supabaseServiceRoleKey?: string;
|
|
13
|
+
};
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/supabaseDatabase.d.ts
|
|
16
|
+
type SupabaseDatabaseConfig = SupabaseServiceRoleConfig;
|
|
17
|
+
declare const supabaseDatabase: (config: SupabaseServiceRoleConfig, hooks?: _$_hot_updater_plugin_core0.DatabasePluginHooks) => () => _$_hot_updater_plugin_core0.DatabasePlugin<unknown>;
|
|
9
18
|
//#endregion
|
|
10
19
|
//#region src/supabaseStorage.d.ts
|
|
11
|
-
|
|
12
|
-
supabaseUrl: string;
|
|
13
|
-
supabaseAnonKey: string;
|
|
20
|
+
type SupabaseStorageConfig = SupabaseServiceRoleConfig & {
|
|
14
21
|
bucketName: string;
|
|
15
22
|
/**
|
|
16
23
|
* Base path where bundles will be stored in the bucket
|
|
17
24
|
*/
|
|
18
25
|
basePath?: string;
|
|
19
|
-
}
|
|
20
|
-
declare const supabaseStorage: (config: SupabaseStorageConfig, hooks?:
|
|
26
|
+
};
|
|
27
|
+
declare const supabaseStorage: (config: SupabaseStorageConfig, hooks?: _$_hot_updater_plugin_core0.StoragePluginHooks) => () => _$_hot_updater_plugin_core0.UniversalStoragePlugin<unknown>;
|
|
21
28
|
//#endregion
|
|
22
29
|
export { SupabaseDatabaseConfig, SupabaseEdgeFunctionDatabaseConfig, SupabaseEdgeFunctionStorageConfig, SupabaseStorageConfig, supabaseDatabase, supabaseEdgeFunctionDatabase, supabaseEdgeFunctionStorage, supabaseStorage };
|
package/dist/index.mjs
CHANGED
|
@@ -1,14 +1,39 @@
|
|
|
1
|
-
import { n as supabaseEdgeFunctionDatabase, r as supabaseDatabase, t as supabaseEdgeFunctionStorage } from "./supabaseEdgeFunctionStorage-
|
|
1
|
+
import { i as resolveSupabaseServiceRoleKey, n as supabaseEdgeFunctionDatabase, r as supabaseDatabase, t as supabaseEdgeFunctionStorage } from "./supabaseEdgeFunctionStorage-B4KN0khj.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";
|
|
5
5
|
import path from "path";
|
|
6
6
|
//#region src/supabaseStorage.ts
|
|
7
|
+
function getErrorMessage(error) {
|
|
8
|
+
if (error instanceof Error) return error.message;
|
|
9
|
+
if (error && typeof error === "object" && "message" in error && typeof error.message === "string") return error.message;
|
|
10
|
+
return String(error);
|
|
11
|
+
}
|
|
12
|
+
async function createSignedUrlOrThrow({ bucket, key, expiresIn }) {
|
|
13
|
+
let data = null;
|
|
14
|
+
let error = null;
|
|
15
|
+
try {
|
|
16
|
+
const response = await bucket.createSignedUrl(key, expiresIn);
|
|
17
|
+
data = response.data;
|
|
18
|
+
error = response.error;
|
|
19
|
+
} catch (thrownError) {
|
|
20
|
+
error = thrownError;
|
|
21
|
+
}
|
|
22
|
+
if (!error && data?.signedUrl) return data.signedUrl;
|
|
23
|
+
throw new Error(`Failed to generate download URL for "${key}": ${getErrorMessage(error ?? /* @__PURE__ */ new Error("missing signed URL"))}`);
|
|
24
|
+
}
|
|
25
|
+
async function verifyObjectCanBeSignedForRuntime({ bucket, key }) {
|
|
26
|
+
await createSignedUrlOrThrow({
|
|
27
|
+
bucket,
|
|
28
|
+
key,
|
|
29
|
+
expiresIn: 3600
|
|
30
|
+
});
|
|
31
|
+
}
|
|
7
32
|
const supabaseStorage = createUniversalStoragePlugin({
|
|
8
33
|
name: "supabaseStorage",
|
|
9
34
|
supportedProtocol: "supabase-storage",
|
|
10
35
|
factory: (config) => {
|
|
11
|
-
const bucket = createClient(config.supabaseUrl, config
|
|
36
|
+
const bucket = createClient(config.supabaseUrl, resolveSupabaseServiceRoleKey(config)).storage.from(config.bucketName);
|
|
12
37
|
const getStorageKey = createStorageKeyBuilder(config.basePath);
|
|
13
38
|
return {
|
|
14
39
|
node: {
|
|
@@ -31,8 +56,24 @@ const supabaseStorage = createUniversalStoragePlugin({
|
|
|
31
56
|
headers: {}
|
|
32
57
|
});
|
|
33
58
|
if (upload.error) throw upload.error;
|
|
59
|
+
await verifyObjectCanBeSignedForRuntime({
|
|
60
|
+
bucket,
|
|
61
|
+
key: Key
|
|
62
|
+
});
|
|
34
63
|
return { storageUri: `supabase-storage://${upload.data.fullPath}` };
|
|
35
64
|
},
|
|
65
|
+
async exists(storageUri) {
|
|
66
|
+
const { key, bucket: bucketName } = parseStorageUri(storageUri, "supabase-storage");
|
|
67
|
+
if (bucketName !== config.bucketName) throw new Error(`Bucket name mismatch: expected "${config.bucketName}", but found "${bucketName}".`);
|
|
68
|
+
const { data, error } = await bucket.exists(key);
|
|
69
|
+
if (data === false) return false;
|
|
70
|
+
if (error) throw error;
|
|
71
|
+
await verifyObjectCanBeSignedForRuntime({
|
|
72
|
+
bucket,
|
|
73
|
+
key
|
|
74
|
+
});
|
|
75
|
+
return data;
|
|
76
|
+
},
|
|
36
77
|
async downloadFile(storageUri, filePath) {
|
|
37
78
|
const { key, bucket: bucketName } = parseStorageUri(storageUri, "supabase-storage");
|
|
38
79
|
if (bucketName !== config.bucketName) throw new Error(`Bucket name mismatch: expected "${config.bucketName}", but found "${bucketName}".`);
|
|
@@ -61,10 +102,11 @@ const supabaseStorage = createUniversalStoragePlugin({
|
|
|
61
102
|
let key = `${u.host}${u.pathname}`.replace(/^\//, "");
|
|
62
103
|
if (!key) throw new Error("Invalid Supabase storage URI: missing key");
|
|
63
104
|
if (key.startsWith(`${config.bucketName}/`)) key = key.substring(`${config.bucketName}/`.length);
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
105
|
+
return { fileUrl: await createSignedUrlOrThrow({
|
|
106
|
+
bucket,
|
|
107
|
+
key,
|
|
108
|
+
expiresIn: 3600
|
|
109
|
+
}) };
|
|
68
110
|
}
|
|
69
111
|
}
|
|
70
112
|
};
|
package/dist/{supabaseEdgeFunctionStorage-BKU_mLzA.mjs → supabaseEdgeFunctionStorage-B4KN0khj.mjs}
RENAMED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { DEFAULT_ROLLOUT_COHORT_COUNT, getAssetBaseStorageUri, getBundlePatches, getManifestFileHash, getManifestStorageUri, stripBundleArtifactMetadata } from "@hot-updater/core";
|
|
2
2
|
import { calculatePagination, createDatabasePlugin, createDatabasePluginGetUpdateInfo, createRuntimeStoragePlugin } from "@hot-updater/plugin-core";
|
|
3
3
|
import { createClient } from "@supabase/supabase-js";
|
|
4
|
+
//#region src/supabaseConfig.ts
|
|
5
|
+
const resolveSupabaseServiceRoleKey = (config) => {
|
|
6
|
+
const key = config.supabaseServiceRoleKey ?? config.supabaseAnonKey;
|
|
7
|
+
if (!key) throw new Error("Supabase service role key is required. Set supabaseServiceRoleKey.");
|
|
8
|
+
return key;
|
|
9
|
+
};
|
|
10
|
+
//#endregion
|
|
4
11
|
//#region src/supabaseDatabase.ts
|
|
5
12
|
const normalizeMetadata = (value) => {
|
|
6
13
|
if (!value) return {};
|
|
@@ -99,7 +106,7 @@ const bundleToPatchRows = (bundle) => getBundlePatches(bundle).map((patch, index
|
|
|
99
106
|
const supabaseDatabase = createDatabasePlugin({
|
|
100
107
|
name: "supabaseDatabase",
|
|
101
108
|
factory: (config) => {
|
|
102
|
-
const supabase = createClient(config.supabaseUrl, config
|
|
109
|
+
const supabase = createClient(config.supabaseUrl, resolveSupabaseServiceRoleKey(config));
|
|
103
110
|
const fetchPatchMap = async (bundleIds) => {
|
|
104
111
|
const patchMap = /* @__PURE__ */ new Map();
|
|
105
112
|
if (bundleIds.length === 0) return patchMap;
|
|
@@ -228,11 +235,16 @@ const supabaseDatabase = createDatabasePlugin({
|
|
|
228
235
|
const supabaseEdgeFunctionDatabase = (config, hooks) => {
|
|
229
236
|
return supabaseDatabase({
|
|
230
237
|
supabaseUrl: config.supabaseUrl,
|
|
231
|
-
|
|
238
|
+
supabaseServiceRoleKey: config.supabaseServiceRoleKey
|
|
232
239
|
}, hooks);
|
|
233
240
|
};
|
|
234
241
|
//#endregion
|
|
235
242
|
//#region src/supabaseEdgeFunctionStorage.ts
|
|
243
|
+
function getErrorMessage(error) {
|
|
244
|
+
if (error instanceof Error) return error.message;
|
|
245
|
+
if (error && typeof error === "object" && "message" in error && typeof error.message === "string") return error.message;
|
|
246
|
+
return String(error);
|
|
247
|
+
}
|
|
236
248
|
const parseSupabaseStorageUri = (storageUri) => {
|
|
237
249
|
const storageUrl = new URL(storageUri);
|
|
238
250
|
if (storageUrl.protocol !== "supabase-storage:") throw new Error("Invalid Supabase storage URI protocol");
|
|
@@ -262,13 +274,22 @@ const supabaseEdgeFunctionStorage = createRuntimeStoragePlugin({
|
|
|
262
274
|
},
|
|
263
275
|
async getDownloadUrl(storageUri) {
|
|
264
276
|
const { bucketName, key } = parseSupabaseStorageUri(storageUri);
|
|
265
|
-
const
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
277
|
+
const bucket = supabase.storage.from(bucketName);
|
|
278
|
+
const expiresIn = config.signedUrlExpiresIn ?? 3600;
|
|
279
|
+
let data = null;
|
|
280
|
+
let error = null;
|
|
281
|
+
try {
|
|
282
|
+
const response = await bucket.createSignedUrl(key, expiresIn);
|
|
283
|
+
data = response.data;
|
|
284
|
+
error = response.error;
|
|
285
|
+
} catch (thrownError) {
|
|
286
|
+
error = thrownError;
|
|
287
|
+
}
|
|
288
|
+
if (!error && data?.signedUrl) return { fileUrl: data.signedUrl };
|
|
289
|
+
throw new Error(`Failed to generate download URL for "${bucketName}/${key}": ${getErrorMessage(error ?? /* @__PURE__ */ new Error("missing signed URL"))}`);
|
|
269
290
|
}
|
|
270
291
|
};
|
|
271
292
|
}
|
|
272
293
|
});
|
|
273
294
|
//#endregion
|
|
274
|
-
export { supabaseEdgeFunctionDatabase as n, supabaseDatabase as r, supabaseEdgeFunctionStorage as t };
|
|
295
|
+
export { resolveSupabaseServiceRoleKey as i, supabaseEdgeFunctionDatabase as n, supabaseDatabase as r, supabaseEdgeFunctionStorage as t };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as _$_hot_updater_plugin_core0 from "@hot-updater/plugin-core";
|
|
1
2
|
import { DatabasePluginHooks } from "@hot-updater/plugin-core";
|
|
2
3
|
|
|
3
4
|
//#region src/supabaseEdgeFunctionDatabase.d.ts
|
|
@@ -5,7 +6,7 @@ interface SupabaseEdgeFunctionDatabaseConfig {
|
|
|
5
6
|
supabaseUrl: string;
|
|
6
7
|
supabaseServiceRoleKey: string;
|
|
7
8
|
}
|
|
8
|
-
declare const supabaseEdgeFunctionDatabase: (config: SupabaseEdgeFunctionDatabaseConfig, hooks?: DatabasePluginHooks) => () =>
|
|
9
|
+
declare const supabaseEdgeFunctionDatabase: (config: SupabaseEdgeFunctionDatabaseConfig, hooks?: DatabasePluginHooks) => () => _$_hot_updater_plugin_core0.DatabasePlugin<unknown>;
|
|
9
10
|
//#endregion
|
|
10
11
|
//#region src/supabaseEdgeFunctionStorage.d.ts
|
|
11
12
|
interface SupabaseEdgeFunctionStorageConfig {
|
|
@@ -13,6 +14,6 @@ interface SupabaseEdgeFunctionStorageConfig {
|
|
|
13
14
|
supabaseServiceRoleKey: string;
|
|
14
15
|
signedUrlExpiresIn?: number;
|
|
15
16
|
}
|
|
16
|
-
declare const supabaseEdgeFunctionStorage: (config: SupabaseEdgeFunctionStorageConfig, hooks?:
|
|
17
|
+
declare const supabaseEdgeFunctionStorage: (config: SupabaseEdgeFunctionStorageConfig, hooks?: _$_hot_updater_plugin_core0.StoragePluginHooks) => () => _$_hot_updater_plugin_core0.RuntimeStoragePlugin<unknown>;
|
|
17
18
|
//#endregion
|
|
18
19
|
export { supabaseEdgeFunctionDatabase as i, supabaseEdgeFunctionStorage as n, SupabaseEdgeFunctionDatabaseConfig as r, SupabaseEdgeFunctionStorageConfig as t };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as _$_hot_updater_plugin_core0 from "@hot-updater/plugin-core";
|
|
1
2
|
import { DatabasePluginHooks } from "@hot-updater/plugin-core";
|
|
2
3
|
|
|
3
4
|
//#region src/supabaseEdgeFunctionDatabase.d.ts
|
|
@@ -5,7 +6,7 @@ interface SupabaseEdgeFunctionDatabaseConfig {
|
|
|
5
6
|
supabaseUrl: string;
|
|
6
7
|
supabaseServiceRoleKey: string;
|
|
7
8
|
}
|
|
8
|
-
declare const supabaseEdgeFunctionDatabase: (config: SupabaseEdgeFunctionDatabaseConfig, hooks?: DatabasePluginHooks) => () =>
|
|
9
|
+
declare const supabaseEdgeFunctionDatabase: (config: SupabaseEdgeFunctionDatabaseConfig, hooks?: DatabasePluginHooks) => () => _$_hot_updater_plugin_core0.DatabasePlugin<unknown>;
|
|
9
10
|
//#endregion
|
|
10
11
|
//#region src/supabaseEdgeFunctionStorage.d.ts
|
|
11
12
|
interface SupabaseEdgeFunctionStorageConfig {
|
|
@@ -13,6 +14,6 @@ interface SupabaseEdgeFunctionStorageConfig {
|
|
|
13
14
|
supabaseServiceRoleKey: string;
|
|
14
15
|
signedUrlExpiresIn?: number;
|
|
15
16
|
}
|
|
16
|
-
declare const supabaseEdgeFunctionStorage: (config: SupabaseEdgeFunctionStorageConfig, hooks?:
|
|
17
|
+
declare const supabaseEdgeFunctionStorage: (config: SupabaseEdgeFunctionStorageConfig, hooks?: _$_hot_updater_plugin_core0.StoragePluginHooks) => () => _$_hot_updater_plugin_core0.RuntimeStoragePlugin<unknown>;
|
|
17
18
|
//#endregion
|
|
18
19
|
export { supabaseEdgeFunctionDatabase as i, supabaseEdgeFunctionStorage as n, SupabaseEdgeFunctionDatabaseConfig as r, SupabaseEdgeFunctionStorageConfig as t };
|
package/dist/{supabaseEdgeFunctionStorage-BZC0Z0XP.cjs → supabaseEdgeFunctionStorage-D933mGy9.cjs}
RENAMED
|
@@ -2,6 +2,13 @@ require("./index.cjs");
|
|
|
2
2
|
let _hot_updater_core = require("@hot-updater/core");
|
|
3
3
|
let _hot_updater_plugin_core = require("@hot-updater/plugin-core");
|
|
4
4
|
let _supabase_supabase_js = require("@supabase/supabase-js");
|
|
5
|
+
//#region src/supabaseConfig.ts
|
|
6
|
+
const resolveSupabaseServiceRoleKey = (config) => {
|
|
7
|
+
const key = config.supabaseServiceRoleKey ?? config.supabaseAnonKey;
|
|
8
|
+
if (!key) throw new Error("Supabase service role key is required. Set supabaseServiceRoleKey.");
|
|
9
|
+
return key;
|
|
10
|
+
};
|
|
11
|
+
//#endregion
|
|
5
12
|
//#region src/supabaseDatabase.ts
|
|
6
13
|
const normalizeMetadata = (value) => {
|
|
7
14
|
if (!value) return {};
|
|
@@ -100,7 +107,7 @@ const bundleToPatchRows = (bundle) => (0, _hot_updater_core.getBundlePatches)(bu
|
|
|
100
107
|
const supabaseDatabase = (0, _hot_updater_plugin_core.createDatabasePlugin)({
|
|
101
108
|
name: "supabaseDatabase",
|
|
102
109
|
factory: (config) => {
|
|
103
|
-
const supabase = (0, _supabase_supabase_js.createClient)(config.supabaseUrl, config
|
|
110
|
+
const supabase = (0, _supabase_supabase_js.createClient)(config.supabaseUrl, resolveSupabaseServiceRoleKey(config));
|
|
104
111
|
const fetchPatchMap = async (bundleIds) => {
|
|
105
112
|
const patchMap = /* @__PURE__ */ new Map();
|
|
106
113
|
if (bundleIds.length === 0) return patchMap;
|
|
@@ -229,11 +236,16 @@ const supabaseDatabase = (0, _hot_updater_plugin_core.createDatabasePlugin)({
|
|
|
229
236
|
const supabaseEdgeFunctionDatabase = (config, hooks) => {
|
|
230
237
|
return supabaseDatabase({
|
|
231
238
|
supabaseUrl: config.supabaseUrl,
|
|
232
|
-
|
|
239
|
+
supabaseServiceRoleKey: config.supabaseServiceRoleKey
|
|
233
240
|
}, hooks);
|
|
234
241
|
};
|
|
235
242
|
//#endregion
|
|
236
243
|
//#region src/supabaseEdgeFunctionStorage.ts
|
|
244
|
+
function getErrorMessage(error) {
|
|
245
|
+
if (error instanceof Error) return error.message;
|
|
246
|
+
if (error && typeof error === "object" && "message" in error && typeof error.message === "string") return error.message;
|
|
247
|
+
return String(error);
|
|
248
|
+
}
|
|
237
249
|
const parseSupabaseStorageUri = (storageUri) => {
|
|
238
250
|
const storageUrl = new URL(storageUri);
|
|
239
251
|
if (storageUrl.protocol !== "supabase-storage:") throw new Error("Invalid Supabase storage URI protocol");
|
|
@@ -263,15 +275,30 @@ const supabaseEdgeFunctionStorage = (0, _hot_updater_plugin_core.createRuntimeSt
|
|
|
263
275
|
},
|
|
264
276
|
async getDownloadUrl(storageUri) {
|
|
265
277
|
const { bucketName, key } = parseSupabaseStorageUri(storageUri);
|
|
266
|
-
const
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
278
|
+
const bucket = supabase.storage.from(bucketName);
|
|
279
|
+
const expiresIn = config.signedUrlExpiresIn ?? 3600;
|
|
280
|
+
let data = null;
|
|
281
|
+
let error = null;
|
|
282
|
+
try {
|
|
283
|
+
const response = await bucket.createSignedUrl(key, expiresIn);
|
|
284
|
+
data = response.data;
|
|
285
|
+
error = response.error;
|
|
286
|
+
} catch (thrownError) {
|
|
287
|
+
error = thrownError;
|
|
288
|
+
}
|
|
289
|
+
if (!error && data?.signedUrl) return { fileUrl: data.signedUrl };
|
|
290
|
+
throw new Error(`Failed to generate download URL for "${bucketName}/${key}": ${getErrorMessage(error ?? /* @__PURE__ */ new Error("missing signed URL"))}`);
|
|
270
291
|
}
|
|
271
292
|
};
|
|
272
293
|
}
|
|
273
294
|
});
|
|
274
295
|
//#endregion
|
|
296
|
+
Object.defineProperty(exports, "resolveSupabaseServiceRoleKey", {
|
|
297
|
+
enumerable: true,
|
|
298
|
+
get: function() {
|
|
299
|
+
return resolveSupabaseServiceRoleKey;
|
|
300
|
+
}
|
|
301
|
+
});
|
|
275
302
|
Object.defineProperty(exports, "supabaseDatabase", {
|
|
276
303
|
enumerable: true,
|
|
277
304
|
get: function() {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hot-updater/supabase",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.32.0",
|
|
5
5
|
"description": "React Native OTA solution for self-hosted",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
7
7
|
"module": "dist/index.mjs",
|
|
@@ -47,10 +47,10 @@
|
|
|
47
47
|
"@supabase/supabase-js": "2.76.1",
|
|
48
48
|
"hono": "4.12.9",
|
|
49
49
|
"uuidv7": "^1.0.2",
|
|
50
|
-
"@hot-updater/core": "0.
|
|
51
|
-
"@hot-updater/
|
|
52
|
-
"@hot-updater/
|
|
53
|
-
"@hot-updater/
|
|
50
|
+
"@hot-updater/core": "0.32.0",
|
|
51
|
+
"@hot-updater/plugin-core": "0.32.0",
|
|
52
|
+
"@hot-updater/cli-tools": "0.32.0",
|
|
53
|
+
"@hot-updater/server": "0.32.0"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@electric-sql/pglite": "0.2.17",
|
|
@@ -60,10 +60,10 @@
|
|
|
60
60
|
"execa": "9.5.2",
|
|
61
61
|
"@types/node": "^20",
|
|
62
62
|
"mime": "^4.0.4",
|
|
63
|
-
"@hot-updater/js": "0.
|
|
64
|
-
"@hot-updater/
|
|
65
|
-
"@hot-updater/
|
|
66
|
-
"@hot-updater/
|
|
63
|
+
"@hot-updater/js": "0.32.0",
|
|
64
|
+
"@hot-updater/mock": "0.32.0",
|
|
65
|
+
"@hot-updater/test-utils": "0.32.0",
|
|
66
|
+
"@hot-updater/postgres": "0.32.0"
|
|
67
67
|
},
|
|
68
68
|
"scripts": {
|
|
69
69
|
"build": "tsdown",
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
-- HotUpdater.supabase_rls
|
|
2
|
+
|
|
3
|
+
ALTER TABLE public.bundles ENABLE ROW LEVEL SECURITY;
|
|
4
|
+
ALTER TABLE public.bundle_patches ENABLE ROW LEVEL SECURITY;
|
|
5
|
+
|
|
6
|
+
ALTER FUNCTION public.get_target_app_version_list(public.platforms, uuid)
|
|
7
|
+
SET search_path = public, pg_catalog;
|
|
8
|
+
ALTER FUNCTION public.get_channels()
|
|
9
|
+
SET search_path = public, pg_catalog;
|
|
10
|
+
ALTER FUNCTION public.positive_mod(integer, integer)
|
|
11
|
+
SET search_path = public, pg_catalog;
|
|
12
|
+
ALTER FUNCTION public.hash_rollout_value(text)
|
|
13
|
+
SET search_path = public, pg_catalog;
|
|
14
|
+
ALTER FUNCTION public.normalize_cohort_value(text)
|
|
15
|
+
SET search_path = public, pg_catalog;
|
|
16
|
+
ALTER FUNCTION public.gcd_int(integer, integer)
|
|
17
|
+
SET search_path = public, pg_catalog;
|
|
18
|
+
ALTER FUNCTION public.get_rollout_multiplier(uuid)
|
|
19
|
+
SET search_path = public, pg_catalog;
|
|
20
|
+
ALTER FUNCTION public.get_rollout_offset(uuid)
|
|
21
|
+
SET search_path = public, pg_catalog;
|
|
22
|
+
ALTER FUNCTION public.get_modular_inverse(integer, integer)
|
|
23
|
+
SET search_path = public, pg_catalog;
|
|
24
|
+
ALTER FUNCTION public.is_numeric_cohort(text)
|
|
25
|
+
SET search_path = public, pg_catalog;
|
|
26
|
+
ALTER FUNCTION public.get_numeric_cohort_rollout_position(uuid, text)
|
|
27
|
+
SET search_path = public, pg_catalog;
|
|
28
|
+
ALTER FUNCTION public.is_cohort_eligible(uuid, text, integer, text[])
|
|
29
|
+
SET search_path = public, pg_catalog;
|
|
30
|
+
ALTER FUNCTION public.get_update_info_by_fingerprint_hash(
|
|
31
|
+
public.platforms,
|
|
32
|
+
uuid,
|
|
33
|
+
uuid,
|
|
34
|
+
text,
|
|
35
|
+
text,
|
|
36
|
+
text
|
|
37
|
+
)
|
|
38
|
+
SET search_path = public, pg_catalog;
|
|
39
|
+
ALTER FUNCTION public.get_update_info_by_app_version(
|
|
40
|
+
public.platforms,
|
|
41
|
+
text,
|
|
42
|
+
uuid,
|
|
43
|
+
uuid,
|
|
44
|
+
text,
|
|
45
|
+
text[],
|
|
46
|
+
text
|
|
47
|
+
)
|
|
48
|
+
SET search_path = public, pg_catalog;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
import { describe, expect, it } from "vitest";
|
|
5
|
+
|
|
6
|
+
const rlsMigrationPath = path.resolve(
|
|
7
|
+
"plugins/supabase/supabase/migrations/20260520014100_hot-updater_rls.sql",
|
|
8
|
+
);
|
|
9
|
+
const migrationsDir = path.dirname(rlsMigrationPath);
|
|
10
|
+
|
|
11
|
+
describe("Supabase RLS migration", () => {
|
|
12
|
+
it("runs after Supabase function redefinition migrations", async () => {
|
|
13
|
+
const migrations = (await fs.readdir(migrationsDir))
|
|
14
|
+
.filter((file) => file.endsWith(".sql"))
|
|
15
|
+
.sort();
|
|
16
|
+
|
|
17
|
+
expect(migrations.at(-1)).toBe(path.basename(rlsMigrationPath));
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("enables RLS on Hot Updater tables", async () => {
|
|
21
|
+
const sql = await fs.readFile(rlsMigrationPath, "utf8");
|
|
22
|
+
|
|
23
|
+
expect(sql).toContain(
|
|
24
|
+
"ALTER TABLE public.bundles ENABLE ROW LEVEL SECURITY;",
|
|
25
|
+
);
|
|
26
|
+
expect(sql).toContain(
|
|
27
|
+
"ALTER TABLE public.bundle_patches ENABLE ROW LEVEL SECURITY;",
|
|
28
|
+
);
|
|
29
|
+
expect(sql).not.toContain("REVOKE ALL ON TABLE");
|
|
30
|
+
expect(sql).not.toContain("GRANT SELECT, INSERT, UPDATE, DELETE");
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("pins search_path for public Hot Updater functions", async () => {
|
|
34
|
+
const sql = await fs.readFile(rlsMigrationPath, "utf8");
|
|
35
|
+
const hotUpdaterFunctions = [
|
|
36
|
+
"get_target_app_version_list",
|
|
37
|
+
"get_channels",
|
|
38
|
+
"positive_mod",
|
|
39
|
+
"hash_rollout_value",
|
|
40
|
+
"normalize_cohort_value",
|
|
41
|
+
"gcd_int",
|
|
42
|
+
"get_rollout_multiplier",
|
|
43
|
+
"get_rollout_offset",
|
|
44
|
+
"get_modular_inverse",
|
|
45
|
+
"is_numeric_cohort",
|
|
46
|
+
"get_numeric_cohort_rollout_position",
|
|
47
|
+
"is_cohort_eligible",
|
|
48
|
+
"get_update_info_by_fingerprint_hash",
|
|
49
|
+
"get_update_info_by_app_version",
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
for (const functionName of hotUpdaterFunctions) {
|
|
53
|
+
expect(sql).toContain(`ALTER FUNCTION public.${functionName}`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
expect(sql.match(/SET search_path = public, pg_catalog;/g)).toHaveLength(
|
|
57
|
+
hotUpdaterFunctions.length,
|
|
58
|
+
);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("does not change function execution grants", async () => {
|
|
62
|
+
const sql = await fs.readFile(rlsMigrationPath, "utf8");
|
|
63
|
+
|
|
64
|
+
expect(sql).not.toContain("REVOKE EXECUTE");
|
|
65
|
+
expect(sql).not.toContain("GRANT EXECUTE");
|
|
66
|
+
});
|
|
67
|
+
});
|