@hot-updater/supabase 1.2.0-rc.1 → 1.2.0-rc.11

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_supabaseStorage = require("./supabaseStorage-MqoRcaii.cjs");
2
+ const require_supabaseStorage = require("./supabaseStorage-DUa49vGh.cjs");
3
3
  exports.supabaseDatabase = require_supabaseStorage.supabaseDatabase;
4
4
  exports.supabaseStorage = require_supabaseStorage.supabaseStorage;
package/dist/edge.d.cts CHANGED
@@ -1,2 +1,2 @@
1
- import { i as supabaseDatabase, n as supabaseStorage, r as SupabaseDatabaseConfig, t as SupabaseStorageConfig } from "./supabaseStorage-BryXQ72m.cjs";
1
+ import { i as supabaseDatabase, n as supabaseStorage, r as SupabaseDatabaseConfig, t as SupabaseStorageConfig } from "./supabaseStorage-C9W-69OP.cjs";
2
2
  export { type SupabaseDatabaseConfig, type SupabaseStorageConfig, supabaseDatabase, supabaseStorage };
package/dist/edge.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { i as supabaseDatabase, n as supabaseStorage, r as SupabaseDatabaseConfig, t as SupabaseStorageConfig } from "./supabaseStorage-BryXQ72m.mjs";
1
+ import { i as supabaseDatabase, n as supabaseStorage, r as SupabaseDatabaseConfig, t as SupabaseStorageConfig } from "./supabaseStorage-C9W-69OP.mjs";
2
2
  export { type SupabaseDatabaseConfig, type SupabaseStorageConfig, supabaseDatabase, supabaseStorage };
package/dist/edge.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { n as supabaseDatabase, t as supabaseStorage } from "./supabaseStorage-D4jcGa-l.mjs";
1
+ import { n as supabaseDatabase, t as supabaseStorage } from "./supabaseStorage-B6IM8UX2.mjs";
2
2
  export { supabaseDatabase, supabaseStorage };
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_supabaseStorage = require("./supabaseStorage-MqoRcaii.cjs");
2
+ const require_supabaseStorage = require("./supabaseStorage-DUa49vGh.cjs");
3
3
  let _hot_updater_plugin_core = require("@hot-updater/plugin-core");
4
4
  //#region src/supabaseSchema.ts
5
5
  /** Every table the apply RPC may name: models, index tables, settings, and the write guard. */
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { n as supabaseStorage, r as SupabaseDatabaseConfig, t as SupabaseStorageConfig } from "./supabaseStorage-BryXQ72m.cjs";
1
+ import { n as supabaseStorage, r as SupabaseDatabaseConfig, t as SupabaseStorageConfig } from "./supabaseStorage-C9W-69OP.cjs";
2
2
  import { ToolingDatabase } from "@hot-updater/plugin-core";
3
3
  //#region src/supabaseMigration.d.ts
4
4
  /**
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { n as supabaseStorage, r as SupabaseDatabaseConfig, t as SupabaseStorageConfig } from "./supabaseStorage-BryXQ72m.mjs";
1
+ import { n as supabaseStorage, r as SupabaseDatabaseConfig, t as SupabaseStorageConfig } from "./supabaseStorage-C9W-69OP.mjs";
2
2
  import { ToolingDatabase } from "@hot-updater/plugin-core";
3
3
  //#region src/supabaseMigration.d.ts
4
4
  /**
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { i as SUPABASE_TABLE_PREFIX, n as supabaseDatabase$1, r as SUPABASE_APPLY_FUNCTION, t as supabaseStorage } from "./supabaseStorage-D4jcGa-l.mjs";
1
+ import { i as SUPABASE_TABLE_PREFIX, n as supabaseDatabase$1, r as SUPABASE_APPLY_FUNCTION, t as supabaseStorage } from "./supabaseStorage-B6IM8UX2.mjs";
2
2
  import { SETTINGS_TABLE, WRITE_GUARD_TABLE, coreSettings, coreTarget, createTableStatements, generateEngineSql, isMultiIndex } from "@hot-updater/plugin-core";
3
3
  //#region src/supabaseSchema.ts
4
4
  /** Every table the apply RPC may name: models, index tables, settings, and the write guard. */
@@ -6333,9 +6333,11 @@ createExeca(mapScriptAsync, {}, deepScriptOptions, setScriptSync);
6333
6333
  const { sendMessage, getOneMessage, getEachMessage, getCancelSignal } = getIpcExport();
6334
6334
  //#endregion
6335
6335
  //#region src/supabaseConfig.ts
6336
- const resolveSupabaseServiceRoleKey = (config) => {
6337
- if (!config.supabaseServiceRoleKey) throw new Error("Supabase service role key is required. Set supabaseServiceRoleKey.");
6338
- return config.supabaseServiceRoleKey;
6336
+ const resolveSupabaseServiceRoleKey = async (config) => {
6337
+ const { supabaseServiceRoleKey } = config;
6338
+ const key = typeof supabaseServiceRoleKey === "function" ? await supabaseServiceRoleKey() : supabaseServiceRoleKey;
6339
+ if (!key) throw new Error("Supabase service role key is required. Set supabaseServiceRoleKey.");
6340
+ return key;
6339
6341
  };
6340
6342
  //#endregion
6341
6343
  //#region src/supabaseInfrastructureNames.ts
@@ -6375,9 +6377,16 @@ const withCode = (error) => Object.assign(new Error(error.message, { cause: erro
6375
6377
  */
6376
6378
  const supabaseExecutor = (client) => {
6377
6379
  let created;
6378
- const clientOf = () => typeof client === "function" ? created ??= client() : client;
6380
+ const clientOf = async () => {
6381
+ if (typeof client !== "function") return client;
6382
+ created ??= Promise.resolve().then(client).catch((error) => {
6383
+ created = void 0;
6384
+ throw error;
6385
+ });
6386
+ return created;
6387
+ };
6379
6388
  const apply = async (statements) => {
6380
- const { data, error } = await clientOf().rpc(SUPABASE_APPLY_FUNCTION, { p_statements: statements.map(toApplyStatement) });
6389
+ const { data, error } = await (await clientOf()).rpc(SUPABASE_APPLY_FUNCTION, { p_statements: statements.map(toApplyStatement) });
6381
6390
  if (error) throw withCode(error);
6382
6391
  return data;
6383
6392
  };
@@ -6400,7 +6409,7 @@ const supabaseExecutor = (client) => {
6400
6409
  */
6401
6410
  const supabaseDatabase = (config) => {
6402
6411
  const { migrations: _migrations, ...adapter } = (0, _hot_updater_plugin_core.createSqlAdapter)({
6403
- executor: supabaseExecutor(() => (0, _supabase_supabase_js.createClient)(config.supabaseUrl, resolveSupabaseServiceRoleKey(config))),
6412
+ executor: supabaseExecutor(async () => (0, _supabase_supabase_js.createClient)(config.supabaseUrl, await resolveSupabaseServiceRoleKey(config))),
6404
6413
  tablePrefix: SUPABASE_TABLE_PREFIX
6405
6414
  });
6406
6415
  return (0, _hot_updater_plugin_core.createEngineDatabase)({
@@ -6410,27 +6419,39 @@ const supabaseDatabase = (config) => {
6410
6419
  };
6411
6420
  //#endregion
6412
6421
  //#region iac/configTemplate.ts
6413
- const getConfigScaffold = (build) => {
6414
- return (0, _hot_updater_cli_tools.createHotUpdaterConfigScaffoldFromBuilder)(new _hot_updater_cli_tools.ConfigBuilder().setBuildType(build).setStorage({
6422
+ /**
6423
+ * The config init writes. With the `resources` init set up, it names them,
6424
+ * and reads the service role key with `secret()`, from the environment and
6425
+ * `.env.hotupdater`, then the config's `secrets` adapter. Without them, as
6426
+ * the agent scaffold writes it before the agent creates the project, it
6427
+ * reads the URL and bucket from the environment, where the agent records
6428
+ * them, and the key with `secret()` alike.
6429
+ */
6430
+ const getConfigScaffold = (build, resources) => {
6431
+ const supabaseUrl = resources === void 0 ? "process.env.HOT_UPDATER_SUPABASE_URL!" : JSON.stringify(resources.supabaseUrl);
6432
+ const serviceRoleKey = "secret(\"HOT_UPDATER_SUPABASE_SERVICE_ROLE_KEY\")";
6433
+ const storageConfig = {
6415
6434
  imports: [{
6416
6435
  pkg: "@hot-updater/supabase",
6417
6436
  named: ["supabaseStorage"]
6418
6437
  }],
6419
6438
  configString: `supabaseStorage({
6420
- supabaseUrl: process.env.HOT_UPDATER_SUPABASE_URL!,
6421
- supabaseServiceRoleKey: process.env.HOT_UPDATER_SUPABASE_SERVICE_ROLE_KEY!,
6422
- bucketName: process.env.HOT_UPDATER_SUPABASE_BUCKET_NAME!,
6439
+ supabaseUrl: ${supabaseUrl},
6440
+ supabaseServiceRoleKey: ${serviceRoleKey},
6441
+ bucketName: ${resources === void 0 ? "process.env.HOT_UPDATER_SUPABASE_BUCKET_NAME!" : JSON.stringify(resources.bucketName)},
6423
6442
  })`
6424
- }).setDatabase({
6443
+ };
6444
+ const databaseConfig = {
6425
6445
  imports: [{
6426
6446
  pkg: "@hot-updater/supabase",
6427
6447
  named: ["supabaseDatabase"]
6428
6448
  }],
6429
6449
  configString: `supabaseDatabase({
6430
- supabaseUrl: process.env.HOT_UPDATER_SUPABASE_URL!,
6431
- supabaseServiceRoleKey: process.env.HOT_UPDATER_SUPABASE_SERVICE_ROLE_KEY!,
6450
+ supabaseUrl: ${supabaseUrl},
6451
+ supabaseServiceRoleKey: ${serviceRoleKey},
6432
6452
  })`
6433
- }).setPlugins({
6453
+ };
6454
+ const builder = new _hot_updater_cli_tools.ConfigBuilder().setBuildType(build).setStorage(storageConfig).setDatabase(databaseConfig).setPlugins({
6434
6455
  imports: [{
6435
6456
  pkg: "hot-updater/plugins",
6436
6457
  named: [
@@ -6440,7 +6461,12 @@ const getConfigScaffold = (build) => {
6440
6461
  ]
6441
6462
  }],
6442
6463
  configString: "[apiKeys(), insights(), remoteConfig()]"
6443
- }));
6464
+ });
6465
+ builder.addImport({
6466
+ pkg: "hot-updater",
6467
+ named: ["secret"]
6468
+ });
6469
+ return (0, _hot_updater_cli_tools.createHotUpdaterConfigScaffoldFromBuilder)(builder);
6444
6470
  };
6445
6471
  //#endregion
6446
6472
  //#region iac/init/index.ts
@@ -6546,7 +6572,8 @@ const initProvider = {
6546
6572
  type: "password"
6547
6573
  }
6548
6574
  }
6549
- }
6575
+ },
6576
+ secrets: ["HOT_UPDATER_SUPABASE_SERVICE_ROLE_KEY"]
6550
6577
  };
6551
6578
  //#endregion
6552
6579
  //#region iac/supabaseApi.ts
@@ -7515,9 +7542,9 @@ const withSupabaseCliMetadataCleanup = async (cwd, operation) => {
7515
7542
  });
7516
7543
  }
7517
7544
  };
7518
- const runInitWithoutCliMetadata = async ({ build, envFile }) => {
7545
+ const runInitWithoutCliMetadata = async ({ build, envFile, secretsEnv }) => {
7519
7546
  const nonInteractive = envFile !== void 0;
7520
- const initEnvSources = await (0, _hot_updater_cli_tools.readHotUpdaterInitEnv)(process.cwd(), envFile);
7547
+ const initEnvSources = await (0, _hot_updater_cli_tools.readHotUpdaterInitEnv)(process.cwd(), envFile, secretsEnv);
7521
7548
  const { inputEnv, managedEnv } = initEnvSources;
7522
7549
  const initInputEnv = (0, _hot_updater_cli_tools.getHotUpdaterInitInputEnv)(initEnvSources, nonInteractive);
7523
7550
  const savedInputs = resolveSupabaseInitInputs(initInputEnv, {
@@ -7596,6 +7623,7 @@ const runInitWithoutCliMetadata = async ({ build, envFile }) => {
7596
7623
  const { tmpDir, removeTmpDir } = await (0, _hot_updater_cli_tools.copyDirToTmp)(scaffoldLibPath, "supabase");
7597
7624
  let credential;
7598
7625
  let clientPlugins = [];
7626
+ let resources;
7599
7627
  try {
7600
7628
  await stageEdgeFunction({
7601
7629
  bucketName: bucketSelection.name,
@@ -7637,6 +7665,10 @@ const runInitWithoutCliMetadata = async ({ build, envFile }) => {
7637
7665
  [initProvider.inputs.bucketName.envKey]: bucket.name,
7638
7666
  HOT_UPDATER_SUPABASE_URL: `https://${project.id}.supabase.co`
7639
7667
  });
7668
+ resources = {
7669
+ supabaseUrl: `https://${project.id}.supabase.co`,
7670
+ bucketName: bucket.name
7671
+ };
7640
7672
  await linkSupabase(tmpDir, {
7641
7673
  accessToken,
7642
7674
  projectId: project.id,
@@ -7674,7 +7706,7 @@ const runInitWithoutCliMetadata = async ({ build, envFile }) => {
7674
7706
  await removeTmpDir();
7675
7707
  }
7676
7708
  _hot_updater_cli_tools.p.log.success("Generated '.env.hotupdater' file with Supabase settings.");
7677
- await (0, _hot_updater_cli_tools.writeHotUpdaterFiles)(getConfigScaffold(build), {
7709
+ await (0, _hot_updater_cli_tools.writeHotUpdaterFiles)(getConfigScaffold(build, resources), {
7678
7710
  cwd: process.cwd(),
7679
7711
  settings: "Supabase"
7680
7712
  });
@@ -99,6 +99,7 @@ declare const initProvider: {
99
99
  };
100
100
  };
101
101
  };
102
+ readonly secrets: readonly ["HOT_UPDATER_SUPABASE_SERVICE_ROLE_KEY"];
102
103
  };
103
104
  //#endregion
104
105
  //#region iac/supabaseManagementApi.d.ts
@@ -99,6 +99,7 @@ declare const initProvider: {
99
99
  };
100
100
  };
101
101
  };
102
+ readonly secrets: readonly ["HOT_UPDATER_SUPABASE_SERVICE_ROLE_KEY"];
102
103
  };
103
104
  //#endregion
104
105
  //#region iac/supabaseManagementApi.d.ts
@@ -6328,9 +6328,11 @@ createExeca(mapScriptAsync, {}, deepScriptOptions, setScriptSync);
6328
6328
  const { sendMessage, getOneMessage, getEachMessage, getCancelSignal } = getIpcExport();
6329
6329
  //#endregion
6330
6330
  //#region src/supabaseConfig.ts
6331
- const resolveSupabaseServiceRoleKey = (config) => {
6332
- if (!config.supabaseServiceRoleKey) throw new Error("Supabase service role key is required. Set supabaseServiceRoleKey.");
6333
- return config.supabaseServiceRoleKey;
6331
+ const resolveSupabaseServiceRoleKey = async (config) => {
6332
+ const { supabaseServiceRoleKey } = config;
6333
+ const key = typeof supabaseServiceRoleKey === "function" ? await supabaseServiceRoleKey() : supabaseServiceRoleKey;
6334
+ if (!key) throw new Error("Supabase service role key is required. Set supabaseServiceRoleKey.");
6335
+ return key;
6334
6336
  };
6335
6337
  //#endregion
6336
6338
  //#region src/supabaseInfrastructureNames.ts
@@ -6370,9 +6372,16 @@ const withCode = (error) => Object.assign(new Error(error.message, { cause: erro
6370
6372
  */
6371
6373
  const supabaseExecutor = (client) => {
6372
6374
  let created;
6373
- const clientOf = () => typeof client === "function" ? created ??= client() : client;
6375
+ const clientOf = async () => {
6376
+ if (typeof client !== "function") return client;
6377
+ created ??= Promise.resolve().then(client).catch((error) => {
6378
+ created = void 0;
6379
+ throw error;
6380
+ });
6381
+ return created;
6382
+ };
6374
6383
  const apply = async (statements) => {
6375
- const { data, error } = await clientOf().rpc(SUPABASE_APPLY_FUNCTION, { p_statements: statements.map(toApplyStatement) });
6384
+ const { data, error } = await (await clientOf()).rpc(SUPABASE_APPLY_FUNCTION, { p_statements: statements.map(toApplyStatement) });
6376
6385
  if (error) throw withCode(error);
6377
6386
  return data;
6378
6387
  };
@@ -6395,7 +6404,7 @@ const supabaseExecutor = (client) => {
6395
6404
  */
6396
6405
  const supabaseDatabase = (config) => {
6397
6406
  const { migrations: _migrations, ...adapter } = createSqlAdapter({
6398
- executor: supabaseExecutor(() => createClient(config.supabaseUrl, resolveSupabaseServiceRoleKey(config))),
6407
+ executor: supabaseExecutor(async () => createClient(config.supabaseUrl, await resolveSupabaseServiceRoleKey(config))),
6399
6408
  tablePrefix: SUPABASE_TABLE_PREFIX
6400
6409
  });
6401
6410
  return createEngineDatabase({
@@ -6405,27 +6414,39 @@ const supabaseDatabase = (config) => {
6405
6414
  };
6406
6415
  //#endregion
6407
6416
  //#region iac/configTemplate.ts
6408
- const getConfigScaffold = (build) => {
6409
- return createHotUpdaterConfigScaffoldFromBuilder(new ConfigBuilder().setBuildType(build).setStorage({
6417
+ /**
6418
+ * The config init writes. With the `resources` init set up, it names them,
6419
+ * and reads the service role key with `secret()`, from the environment and
6420
+ * `.env.hotupdater`, then the config's `secrets` adapter. Without them, as
6421
+ * the agent scaffold writes it before the agent creates the project, it
6422
+ * reads the URL and bucket from the environment, where the agent records
6423
+ * them, and the key with `secret()` alike.
6424
+ */
6425
+ const getConfigScaffold = (build, resources) => {
6426
+ const supabaseUrl = resources === void 0 ? "process.env.HOT_UPDATER_SUPABASE_URL!" : JSON.stringify(resources.supabaseUrl);
6427
+ const serviceRoleKey = "secret(\"HOT_UPDATER_SUPABASE_SERVICE_ROLE_KEY\")";
6428
+ const storageConfig = {
6410
6429
  imports: [{
6411
6430
  pkg: "@hot-updater/supabase",
6412
6431
  named: ["supabaseStorage"]
6413
6432
  }],
6414
6433
  configString: `supabaseStorage({
6415
- supabaseUrl: process.env.HOT_UPDATER_SUPABASE_URL!,
6416
- supabaseServiceRoleKey: process.env.HOT_UPDATER_SUPABASE_SERVICE_ROLE_KEY!,
6417
- bucketName: process.env.HOT_UPDATER_SUPABASE_BUCKET_NAME!,
6434
+ supabaseUrl: ${supabaseUrl},
6435
+ supabaseServiceRoleKey: ${serviceRoleKey},
6436
+ bucketName: ${resources === void 0 ? "process.env.HOT_UPDATER_SUPABASE_BUCKET_NAME!" : JSON.stringify(resources.bucketName)},
6418
6437
  })`
6419
- }).setDatabase({
6438
+ };
6439
+ const databaseConfig = {
6420
6440
  imports: [{
6421
6441
  pkg: "@hot-updater/supabase",
6422
6442
  named: ["supabaseDatabase"]
6423
6443
  }],
6424
6444
  configString: `supabaseDatabase({
6425
- supabaseUrl: process.env.HOT_UPDATER_SUPABASE_URL!,
6426
- supabaseServiceRoleKey: process.env.HOT_UPDATER_SUPABASE_SERVICE_ROLE_KEY!,
6445
+ supabaseUrl: ${supabaseUrl},
6446
+ supabaseServiceRoleKey: ${serviceRoleKey},
6427
6447
  })`
6428
- }).setPlugins({
6448
+ };
6449
+ const builder = new ConfigBuilder().setBuildType(build).setStorage(storageConfig).setDatabase(databaseConfig).setPlugins({
6429
6450
  imports: [{
6430
6451
  pkg: "hot-updater/plugins",
6431
6452
  named: [
@@ -6435,7 +6456,12 @@ const getConfigScaffold = (build) => {
6435
6456
  ]
6436
6457
  }],
6437
6458
  configString: "[apiKeys(), insights(), remoteConfig()]"
6438
- }));
6459
+ });
6460
+ builder.addImport({
6461
+ pkg: "hot-updater",
6462
+ named: ["secret"]
6463
+ });
6464
+ return createHotUpdaterConfigScaffoldFromBuilder(builder);
6439
6465
  };
6440
6466
  //#endregion
6441
6467
  //#region iac/init/index.ts
@@ -6541,7 +6567,8 @@ const initProvider = {
6541
6567
  type: "password"
6542
6568
  }
6543
6569
  }
6544
- }
6570
+ },
6571
+ secrets: ["HOT_UPDATER_SUPABASE_SERVICE_ROLE_KEY"]
6545
6572
  };
6546
6573
  //#endregion
6547
6574
  //#region iac/supabaseApi.ts
@@ -7510,9 +7537,9 @@ const withSupabaseCliMetadataCleanup = async (cwd, operation) => {
7510
7537
  });
7511
7538
  }
7512
7539
  };
7513
- const runInitWithoutCliMetadata = async ({ build, envFile }) => {
7540
+ const runInitWithoutCliMetadata = async ({ build, envFile, secretsEnv }) => {
7514
7541
  const nonInteractive = envFile !== void 0;
7515
- const initEnvSources = await readHotUpdaterInitEnv(process.cwd(), envFile);
7542
+ const initEnvSources = await readHotUpdaterInitEnv(process.cwd(), envFile, secretsEnv);
7516
7543
  const { inputEnv, managedEnv } = initEnvSources;
7517
7544
  const initInputEnv = getHotUpdaterInitInputEnv(initEnvSources, nonInteractive);
7518
7545
  const savedInputs = resolveSupabaseInitInputs(initInputEnv, {
@@ -7591,6 +7618,7 @@ const runInitWithoutCliMetadata = async ({ build, envFile }) => {
7591
7618
  const { tmpDir, removeTmpDir } = await copyDirToTmp(scaffoldLibPath, "supabase");
7592
7619
  let credential;
7593
7620
  let clientPlugins = [];
7621
+ let resources;
7594
7622
  try {
7595
7623
  await stageEdgeFunction({
7596
7624
  bucketName: bucketSelection.name,
@@ -7632,6 +7660,10 @@ const runInitWithoutCliMetadata = async ({ build, envFile }) => {
7632
7660
  [initProvider.inputs.bucketName.envKey]: bucket.name,
7633
7661
  HOT_UPDATER_SUPABASE_URL: `https://${project.id}.supabase.co`
7634
7662
  });
7663
+ resources = {
7664
+ supabaseUrl: `https://${project.id}.supabase.co`,
7665
+ bucketName: bucket.name
7666
+ };
7635
7667
  await linkSupabase(tmpDir, {
7636
7668
  accessToken,
7637
7669
  projectId: project.id,
@@ -7669,7 +7701,7 @@ const runInitWithoutCliMetadata = async ({ build, envFile }) => {
7669
7701
  await removeTmpDir();
7670
7702
  }
7671
7703
  p.log.success("Generated '.env.hotupdater' file with Supabase settings.");
7672
- await writeHotUpdaterFiles(getConfigScaffold(build), {
7704
+ await writeHotUpdaterFiles(getConfigScaffold(build, resources), {
7673
7705
  cwd: process.cwd(),
7674
7706
  settings: "Supabase"
7675
7707
  });
@@ -1,9 +1,11 @@
1
1
  import { SETTINGS_TABLE, createEngineDatabase, createSqlAdapter, createStorageAdapter, createStorageKeyBuilder, createStorageUri, parseStorageUri } from "@hot-updater/plugin-core";
2
2
  import { createClient } from "@supabase/supabase-js";
3
3
  //#region src/supabaseConfig.ts
4
- const resolveSupabaseServiceRoleKey = (config) => {
5
- if (!config.supabaseServiceRoleKey) throw new Error("Supabase service role key is required. Set supabaseServiceRoleKey.");
6
- return config.supabaseServiceRoleKey;
4
+ const resolveSupabaseServiceRoleKey = async (config) => {
5
+ const { supabaseServiceRoleKey } = config;
6
+ const key = typeof supabaseServiceRoleKey === "function" ? await supabaseServiceRoleKey() : supabaseServiceRoleKey;
7
+ if (!key) throw new Error("Supabase service role key is required. Set supabaseServiceRoleKey.");
8
+ return key;
7
9
  };
8
10
  //#endregion
9
11
  //#region src/supabaseInfrastructureNames.ts
@@ -42,9 +44,16 @@ const withCode = (error) => Object.assign(new Error(error.message, { cause: erro
42
44
  */
43
45
  const supabaseExecutor = (client) => {
44
46
  let created;
45
- const clientOf = () => typeof client === "function" ? created ??= client() : client;
47
+ const clientOf = async () => {
48
+ if (typeof client !== "function") return client;
49
+ created ??= Promise.resolve().then(client).catch((error) => {
50
+ created = void 0;
51
+ throw error;
52
+ });
53
+ return created;
54
+ };
46
55
  const apply = async (statements) => {
47
- const { data, error } = await clientOf().rpc(SUPABASE_APPLY_FUNCTION, { p_statements: statements.map(toApplyStatement) });
56
+ const { data, error } = await (await clientOf()).rpc(SUPABASE_APPLY_FUNCTION, { p_statements: statements.map(toApplyStatement) });
48
57
  if (error) throw withCode(error);
49
58
  return data;
50
59
  };
@@ -67,7 +76,7 @@ const supabaseExecutor = (client) => {
67
76
  */
68
77
  const supabaseDatabase = (config) => {
69
78
  const { migrations: _migrations, ...adapter } = createSqlAdapter({
70
- executor: supabaseExecutor(() => createClient(config.supabaseUrl, resolveSupabaseServiceRoleKey(config))),
79
+ executor: supabaseExecutor(async () => createClient(config.supabaseUrl, await resolveSupabaseServiceRoleKey(config))),
71
80
  tablePrefix: SUPABASE_TABLE_PREFIX
72
81
  });
73
82
  return createEngineDatabase({
@@ -157,7 +166,15 @@ const isMissingObjectError = async (error) => {
157
166
  };
158
167
  /** A character Storage rejects in an object name, `?`, or `!`. */
159
168
  const ESCAPED_CHARACTER = /[^A-Za-z0-9_/.*'() &$=@;:+,-]/gu;
169
+ const ESCAPE_SEQUENCE = /!([0-9A-F]{2})/gu;
160
170
  const utf8 = new TextEncoder();
171
+ const utf8Decoder = new TextDecoder("utf-8", { fatal: true });
172
+ /** Objects Storage lists a page at a time. */
173
+ const LIST_PAGE_SIZE = 1e3;
174
+ /** Names Storage removes in one request. */
175
+ const DELETE_BATCH_SIZE = 1e3;
176
+ /** The object the Supabase dashboard keeps in a folder it creates. */
177
+ const EMPTY_FOLDER_PLACEHOLDER = ".emptyFolderPlaceholder";
161
178
  /**
162
179
  * The object name Storage keeps a key under. Storage accepts names of ASCII
163
180
  * letters, digits and `_/!.*'() &$=@;:+,?-` only, and supabase-js puts a name
@@ -168,12 +185,44 @@ const utf8 = new TextEncoder();
168
185
  * Deploy's keys, such as `<bundleId>/manifest.json`, are stored as they are.
169
186
  */
170
187
  const toObjectName = (key) => key.replace(ESCAPED_CHARACTER, (character) => Array.from(utf8.encode(character), (byte) => `!${byte.toString(16).toUpperCase().padStart(2, "0")}`).join(""));
188
+ /** The key `toObjectName` stored under `name`, or null for a name it never makes. */
189
+ const fromObjectName = (name) => {
190
+ const bytes = [];
191
+ const parts = [];
192
+ const flush = () => {
193
+ if (bytes.length === 0) return true;
194
+ try {
195
+ parts.push(utf8Decoder.decode(new Uint8Array(bytes)));
196
+ } catch {
197
+ return false;
198
+ }
199
+ bytes.length = 0;
200
+ return true;
201
+ };
202
+ let index = 0;
203
+ for (const match of name.matchAll(ESCAPE_SEQUENCE)) {
204
+ if (match.index !== index) {
205
+ if (!flush()) return null;
206
+ parts.push(name.slice(index, match.index));
207
+ }
208
+ bytes.push(Number.parseInt(match[1], 16));
209
+ index = match.index + match[0].length;
210
+ }
211
+ if (!flush()) return null;
212
+ parts.push(name.slice(index));
213
+ const key = parts.join("");
214
+ return toObjectName(key) === name ? key : null;
215
+ };
171
216
  const supabaseStorage = (config) => {
172
217
  let client;
173
- const bucket = () => (client ??= createClient(config.supabaseUrl, resolveSupabaseServiceRoleKey(config))).storage.from(config.bucketName);
218
+ const bucket = async () => (await (client ??= resolveSupabaseServiceRoleKey(config).then((key) => createClient(config.supabaseUrl, key), (error) => {
219
+ client = void 0;
220
+ throw error;
221
+ }))).storage.from(config.bucketName);
174
222
  const getStorageKey = createStorageKeyBuilder(config.basePath);
223
+ const basePrefix = getStorageKey() ? `${getStorageKey()}/` : "";
175
224
  const resolveSignedUrl = createSupabaseSignedUrlBatcher({
176
- createSignedUrls: (_bucketName, keys, expiresIn) => bucket().createSignedUrls(keys, expiresIn),
225
+ createSignedUrls: async (_bucketName, keys, expiresIn) => (await bucket()).createSignedUrls(keys, expiresIn),
177
226
  expiresIn: config.signedUrlExpiresIn ?? 3600,
178
227
  formatObjectPath: (_bucketName, key) => key
179
228
  });
@@ -187,7 +236,7 @@ const supabaseStorage = (config) => {
187
236
  protocol: "supabase-storage",
188
237
  async put({ key, body, contentLength, contentType }) {
189
238
  const storageKey = getStorageKey(key);
190
- const { error } = await bucket().upload(toObjectName(storageKey), body, {
239
+ const { error } = await (await bucket()).upload(toObjectName(storageKey), body, {
191
240
  contentType,
192
241
  cacheControl: "max-age=31536000",
193
242
  upsert: true,
@@ -203,7 +252,7 @@ const supabaseStorage = (config) => {
203
252
  },
204
253
  async get({ storageUri }) {
205
254
  const { key } = parseAndValidate(storageUri);
206
- const { data, error } = await bucket().download(toObjectName(key));
255
+ const { data, error } = await (await bucket()).download(toObjectName(key));
207
256
  if (error) {
208
257
  if (await isMissingObjectError(error)) return { response: null };
209
258
  throw new Error(`Failed to download storage object: ${error.message}`);
@@ -216,7 +265,7 @@ const supabaseStorage = (config) => {
216
265
  },
217
266
  async exists({ storageUri }) {
218
267
  const { key } = parseAndValidate(storageUri);
219
- const { data, error } = await bucket().exists(toObjectName(key));
268
+ const { data, error } = await (await bucket()).exists(toObjectName(key));
220
269
  if (error) {
221
270
  if (isMissingExistsError(error)) return { exists: false };
222
271
  throw error;
@@ -225,9 +274,54 @@ const supabaseStorage = (config) => {
225
274
  },
226
275
  async delete({ storageUri }) {
227
276
  const { key } = parseAndValidate(storageUri);
228
- const { error } = await bucket().remove([toObjectName(key)]);
277
+ const { error } = await (await bucket()).remove([toObjectName(key)]);
229
278
  if (error && !isNotFoundError(error)) throw new Error(`Failed to delete storage object: ${error.message}`);
230
279
  return { deleted: true };
280
+ },
281
+ async listObjects(prefix) {
282
+ const objects = [];
283
+ const folder = toObjectName(getStorageKey(prefix ?? ""));
284
+ let cursor;
285
+ do {
286
+ const { data, error } = await (await bucket()).listV2({
287
+ prefix: folder ? `${folder}/` : "",
288
+ limit: LIST_PAGE_SIZE,
289
+ ...cursor === void 0 ? {} : { cursor }
290
+ });
291
+ if (error) throw new Error(`Failed to list storage objects: ${error.message}`);
292
+ for (const entry of data.objects) {
293
+ const name = entry.key ?? entry.name;
294
+ if (name.split("/").at(-1) === EMPTY_FOLDER_PLACEHOLDER) continue;
295
+ const key = fromObjectName(name);
296
+ if (key === null || !key.startsWith(basePrefix)) continue;
297
+ let storageUri;
298
+ try {
299
+ storageUri = createStorageUri({
300
+ protocol: "supabase-storage",
301
+ bucket: config.bucketName,
302
+ key
303
+ });
304
+ } catch {
305
+ continue;
306
+ }
307
+ const updatedAt = entry.updated_at ?? entry.created_at;
308
+ objects.push({
309
+ key: key.slice(basePrefix.length),
310
+ ...updatedAt ? { lastModifiedAt: new Date(updatedAt) } : {},
311
+ size: Number(entry.metadata?.size ?? 0),
312
+ storageUri
313
+ });
314
+ }
315
+ cursor = data.hasNext ? data.nextCursor : void 0;
316
+ } while (cursor !== void 0);
317
+ return objects;
318
+ },
319
+ async deleteObjects(relativeKeys) {
320
+ const names = relativeKeys.map((key) => toObjectName(getStorageKey(key)));
321
+ for (let offset = 0; offset < names.length; offset += DELETE_BATCH_SIZE) {
322
+ const { error } = await (await bucket()).remove(names.slice(offset, offset + DELETE_BATCH_SIZE));
323
+ if (error && !isNotFoundError(error)) throw new Error(`Failed to delete storage objects: ${error.message}`);
324
+ }
231
325
  }
232
326
  });
233
327
  };
@@ -1,8 +1,13 @@
1
- import { EngineDatabase, StorageAdapterWith } from "@hot-updater/plugin-core";
1
+ import { EngineDatabase, Lazy, StorageAdapterWith } from "@hot-updater/plugin-core";
2
2
  //#region src/supabaseConfig.d.ts
3
3
  type SupabaseServiceRoleConfig = {
4
4
  supabaseUrl: string;
5
- supabaseServiceRoleKey: string;
5
+ /**
6
+ * The project's service role key, or a function that returns it, such as
7
+ * `secret("<name>")` in `hot-updater.config.ts`: called on the first
8
+ * request, so a config loads without the key.
9
+ */
10
+ supabaseServiceRoleKey: Lazy<string>;
6
11
  };
7
12
  //#endregion
8
13
  //#region src/supabaseDatabase.d.ts
@@ -23,6 +28,6 @@ type SupabaseStorageConfig = SupabaseServiceRoleConfig & {
23
28
  /** Signed download URL lifetime in seconds. @default 3600 */
24
29
  signedUrlExpiresIn?: number;
25
30
  };
26
- declare const supabaseStorage: (config: SupabaseStorageConfig) => StorageAdapterWith<"put" | "get" | "getDownloadUrl" | "exists" | "delete">;
31
+ declare const supabaseStorage: (config: SupabaseStorageConfig) => StorageAdapterWith<"put" | "get" | "getDownloadUrl" | "exists" | "delete" | "listObjects" | "deleteObjects">;
27
32
  //#endregion
28
33
  export { supabaseDatabase as i, supabaseStorage as n, SupabaseDatabaseConfig as r, SupabaseStorageConfig as t };
@@ -1,8 +1,13 @@
1
- import { EngineDatabase, StorageAdapterWith } from "@hot-updater/plugin-core";
1
+ import { EngineDatabase, Lazy, StorageAdapterWith } from "@hot-updater/plugin-core";
2
2
  //#region src/supabaseConfig.d.ts
3
3
  type SupabaseServiceRoleConfig = {
4
4
  supabaseUrl: string;
5
- supabaseServiceRoleKey: string;
5
+ /**
6
+ * The project's service role key, or a function that returns it, such as
7
+ * `secret("<name>")` in `hot-updater.config.ts`: called on the first
8
+ * request, so a config loads without the key.
9
+ */
10
+ supabaseServiceRoleKey: Lazy<string>;
6
11
  };
7
12
  //#endregion
8
13
  //#region src/supabaseDatabase.d.ts
@@ -23,6 +28,6 @@ type SupabaseStorageConfig = SupabaseServiceRoleConfig & {
23
28
  /** Signed download URL lifetime in seconds. @default 3600 */
24
29
  signedUrlExpiresIn?: number;
25
30
  };
26
- declare const supabaseStorage: (config: SupabaseStorageConfig) => StorageAdapterWith<"put" | "get" | "getDownloadUrl" | "exists" | "delete">;
31
+ declare const supabaseStorage: (config: SupabaseStorageConfig) => StorageAdapterWith<"put" | "get" | "getDownloadUrl" | "exists" | "delete" | "listObjects" | "deleteObjects">;
27
32
  //#endregion
28
33
  export { supabaseDatabase as i, supabaseStorage as n, SupabaseDatabaseConfig as r, SupabaseStorageConfig as t };
@@ -1,9 +1,11 @@
1
1
  let _hot_updater_plugin_core = require("@hot-updater/plugin-core");
2
2
  let _supabase_supabase_js = require("@supabase/supabase-js");
3
3
  //#region src/supabaseConfig.ts
4
- const resolveSupabaseServiceRoleKey = (config) => {
5
- if (!config.supabaseServiceRoleKey) throw new Error("Supabase service role key is required. Set supabaseServiceRoleKey.");
6
- return config.supabaseServiceRoleKey;
4
+ const resolveSupabaseServiceRoleKey = async (config) => {
5
+ const { supabaseServiceRoleKey } = config;
6
+ const key = typeof supabaseServiceRoleKey === "function" ? await supabaseServiceRoleKey() : supabaseServiceRoleKey;
7
+ if (!key) throw new Error("Supabase service role key is required. Set supabaseServiceRoleKey.");
8
+ return key;
7
9
  };
8
10
  //#endregion
9
11
  //#region src/supabaseInfrastructureNames.ts
@@ -42,9 +44,16 @@ const withCode = (error) => Object.assign(new Error(error.message, { cause: erro
42
44
  */
43
45
  const supabaseExecutor = (client) => {
44
46
  let created;
45
- const clientOf = () => typeof client === "function" ? created ??= client() : client;
47
+ const clientOf = async () => {
48
+ if (typeof client !== "function") return client;
49
+ created ??= Promise.resolve().then(client).catch((error) => {
50
+ created = void 0;
51
+ throw error;
52
+ });
53
+ return created;
54
+ };
46
55
  const apply = async (statements) => {
47
- const { data, error } = await clientOf().rpc(SUPABASE_APPLY_FUNCTION, { p_statements: statements.map(toApplyStatement) });
56
+ const { data, error } = await (await clientOf()).rpc(SUPABASE_APPLY_FUNCTION, { p_statements: statements.map(toApplyStatement) });
48
57
  if (error) throw withCode(error);
49
58
  return data;
50
59
  };
@@ -67,7 +76,7 @@ const supabaseExecutor = (client) => {
67
76
  */
68
77
  const supabaseDatabase = (config) => {
69
78
  const { migrations: _migrations, ...adapter } = (0, _hot_updater_plugin_core.createSqlAdapter)({
70
- executor: supabaseExecutor(() => (0, _supabase_supabase_js.createClient)(config.supabaseUrl, resolveSupabaseServiceRoleKey(config))),
79
+ executor: supabaseExecutor(async () => (0, _supabase_supabase_js.createClient)(config.supabaseUrl, await resolveSupabaseServiceRoleKey(config))),
71
80
  tablePrefix: SUPABASE_TABLE_PREFIX
72
81
  });
73
82
  return (0, _hot_updater_plugin_core.createEngineDatabase)({
@@ -157,7 +166,15 @@ const isMissingObjectError = async (error) => {
157
166
  };
158
167
  /** A character Storage rejects in an object name, `?`, or `!`. */
159
168
  const ESCAPED_CHARACTER = /[^A-Za-z0-9_/.*'() &$=@;:+,-]/gu;
169
+ const ESCAPE_SEQUENCE = /!([0-9A-F]{2})/gu;
160
170
  const utf8 = new TextEncoder();
171
+ const utf8Decoder = new TextDecoder("utf-8", { fatal: true });
172
+ /** Objects Storage lists a page at a time. */
173
+ const LIST_PAGE_SIZE = 1e3;
174
+ /** Names Storage removes in one request. */
175
+ const DELETE_BATCH_SIZE = 1e3;
176
+ /** The object the Supabase dashboard keeps in a folder it creates. */
177
+ const EMPTY_FOLDER_PLACEHOLDER = ".emptyFolderPlaceholder";
161
178
  /**
162
179
  * The object name Storage keeps a key under. Storage accepts names of ASCII
163
180
  * letters, digits and `_/!.*'() &$=@;:+,?-` only, and supabase-js puts a name
@@ -168,12 +185,44 @@ const utf8 = new TextEncoder();
168
185
  * Deploy's keys, such as `<bundleId>/manifest.json`, are stored as they are.
169
186
  */
170
187
  const toObjectName = (key) => key.replace(ESCAPED_CHARACTER, (character) => Array.from(utf8.encode(character), (byte) => `!${byte.toString(16).toUpperCase().padStart(2, "0")}`).join(""));
188
+ /** The key `toObjectName` stored under `name`, or null for a name it never makes. */
189
+ const fromObjectName = (name) => {
190
+ const bytes = [];
191
+ const parts = [];
192
+ const flush = () => {
193
+ if (bytes.length === 0) return true;
194
+ try {
195
+ parts.push(utf8Decoder.decode(new Uint8Array(bytes)));
196
+ } catch {
197
+ return false;
198
+ }
199
+ bytes.length = 0;
200
+ return true;
201
+ };
202
+ let index = 0;
203
+ for (const match of name.matchAll(ESCAPE_SEQUENCE)) {
204
+ if (match.index !== index) {
205
+ if (!flush()) return null;
206
+ parts.push(name.slice(index, match.index));
207
+ }
208
+ bytes.push(Number.parseInt(match[1], 16));
209
+ index = match.index + match[0].length;
210
+ }
211
+ if (!flush()) return null;
212
+ parts.push(name.slice(index));
213
+ const key = parts.join("");
214
+ return toObjectName(key) === name ? key : null;
215
+ };
171
216
  const supabaseStorage = (config) => {
172
217
  let client;
173
- const bucket = () => (client ??= (0, _supabase_supabase_js.createClient)(config.supabaseUrl, resolveSupabaseServiceRoleKey(config))).storage.from(config.bucketName);
218
+ const bucket = async () => (await (client ??= resolveSupabaseServiceRoleKey(config).then((key) => (0, _supabase_supabase_js.createClient)(config.supabaseUrl, key), (error) => {
219
+ client = void 0;
220
+ throw error;
221
+ }))).storage.from(config.bucketName);
174
222
  const getStorageKey = (0, _hot_updater_plugin_core.createStorageKeyBuilder)(config.basePath);
223
+ const basePrefix = getStorageKey() ? `${getStorageKey()}/` : "";
175
224
  const resolveSignedUrl = createSupabaseSignedUrlBatcher({
176
- createSignedUrls: (_bucketName, keys, expiresIn) => bucket().createSignedUrls(keys, expiresIn),
225
+ createSignedUrls: async (_bucketName, keys, expiresIn) => (await bucket()).createSignedUrls(keys, expiresIn),
177
226
  expiresIn: config.signedUrlExpiresIn ?? 3600,
178
227
  formatObjectPath: (_bucketName, key) => key
179
228
  });
@@ -187,7 +236,7 @@ const supabaseStorage = (config) => {
187
236
  protocol: "supabase-storage",
188
237
  async put({ key, body, contentLength, contentType }) {
189
238
  const storageKey = getStorageKey(key);
190
- const { error } = await bucket().upload(toObjectName(storageKey), body, {
239
+ const { error } = await (await bucket()).upload(toObjectName(storageKey), body, {
191
240
  contentType,
192
241
  cacheControl: "max-age=31536000",
193
242
  upsert: true,
@@ -203,7 +252,7 @@ const supabaseStorage = (config) => {
203
252
  },
204
253
  async get({ storageUri }) {
205
254
  const { key } = parseAndValidate(storageUri);
206
- const { data, error } = await bucket().download(toObjectName(key));
255
+ const { data, error } = await (await bucket()).download(toObjectName(key));
207
256
  if (error) {
208
257
  if (await isMissingObjectError(error)) return { response: null };
209
258
  throw new Error(`Failed to download storage object: ${error.message}`);
@@ -216,7 +265,7 @@ const supabaseStorage = (config) => {
216
265
  },
217
266
  async exists({ storageUri }) {
218
267
  const { key } = parseAndValidate(storageUri);
219
- const { data, error } = await bucket().exists(toObjectName(key));
268
+ const { data, error } = await (await bucket()).exists(toObjectName(key));
220
269
  if (error) {
221
270
  if (isMissingExistsError(error)) return { exists: false };
222
271
  throw error;
@@ -225,9 +274,54 @@ const supabaseStorage = (config) => {
225
274
  },
226
275
  async delete({ storageUri }) {
227
276
  const { key } = parseAndValidate(storageUri);
228
- const { error } = await bucket().remove([toObjectName(key)]);
277
+ const { error } = await (await bucket()).remove([toObjectName(key)]);
229
278
  if (error && !isNotFoundError(error)) throw new Error(`Failed to delete storage object: ${error.message}`);
230
279
  return { deleted: true };
280
+ },
281
+ async listObjects(prefix) {
282
+ const objects = [];
283
+ const folder = toObjectName(getStorageKey(prefix ?? ""));
284
+ let cursor;
285
+ do {
286
+ const { data, error } = await (await bucket()).listV2({
287
+ prefix: folder ? `${folder}/` : "",
288
+ limit: LIST_PAGE_SIZE,
289
+ ...cursor === void 0 ? {} : { cursor }
290
+ });
291
+ if (error) throw new Error(`Failed to list storage objects: ${error.message}`);
292
+ for (const entry of data.objects) {
293
+ const name = entry.key ?? entry.name;
294
+ if (name.split("/").at(-1) === EMPTY_FOLDER_PLACEHOLDER) continue;
295
+ const key = fromObjectName(name);
296
+ if (key === null || !key.startsWith(basePrefix)) continue;
297
+ let storageUri;
298
+ try {
299
+ storageUri = (0, _hot_updater_plugin_core.createStorageUri)({
300
+ protocol: "supabase-storage",
301
+ bucket: config.bucketName,
302
+ key
303
+ });
304
+ } catch {
305
+ continue;
306
+ }
307
+ const updatedAt = entry.updated_at ?? entry.created_at;
308
+ objects.push({
309
+ key: key.slice(basePrefix.length),
310
+ ...updatedAt ? { lastModifiedAt: new Date(updatedAt) } : {},
311
+ size: Number(entry.metadata?.size ?? 0),
312
+ storageUri
313
+ });
314
+ }
315
+ cursor = data.hasNext ? data.nextCursor : void 0;
316
+ } while (cursor !== void 0);
317
+ return objects;
318
+ },
319
+ async deleteObjects(relativeKeys) {
320
+ const names = relativeKeys.map((key) => toObjectName(getStorageKey(key)));
321
+ for (let offset = 0; offset < names.length; offset += DELETE_BATCH_SIZE) {
322
+ const { error } = await (await bucket()).remove(names.slice(offset, offset + DELETE_BATCH_SIZE));
323
+ if (error && !isNotFoundError(error)) throw new Error(`Failed to delete storage objects: ${error.message}`);
324
+ }
231
325
  }
232
326
  });
233
327
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@hot-updater/supabase",
3
3
  "type": "module",
4
- "version": "1.2.0-rc.1",
4
+ "version": "1.2.0-rc.11",
5
5
  "description": "React Native OTA solution for self-hosted",
6
6
  "main": "dist/index.cjs",
7
7
  "module": "dist/index.mjs",
@@ -51,10 +51,10 @@
51
51
  "@supabase/supabase-js": "2.76.1",
52
52
  "hono": "4.12.34",
53
53
  "uuidv7": "^1.0.2",
54
- "@hot-updater/protocol": "1.2.0-rc.1",
55
- "@hot-updater/plugin-core": "1.2.0-rc.1",
56
- "@hot-updater/cli-tools": "1.2.0-rc.1",
57
- "@hot-updater/server": "1.2.0-rc.1"
54
+ "@hot-updater/protocol": "1.2.0-rc.11",
55
+ "@hot-updater/plugin-core": "1.2.0-rc.11",
56
+ "@hot-updater/cli-tools": "1.2.0-rc.11",
57
+ "@hot-updater/server": "1.2.0-rc.11"
58
58
  },
59
59
  "devDependencies": {
60
60
  "@electric-sql/pglite": "0.4.1",
@@ -64,9 +64,9 @@
64
64
  "execa": "9.5.2",
65
65
  "@types/node": "^20",
66
66
  "mime": "^4.0.4",
67
- "@hot-updater/test-utils": "1.2.0-rc.1",
68
- "@hot-updater/postgres": "1.2.0-rc.1",
69
- "@hot-updater/mock": "1.2.0-rc.1"
67
+ "@hot-updater/mock": "1.2.0-rc.11",
68
+ "@hot-updater/test-utils": "1.2.0-rc.11",
69
+ "@hot-updater/postgres": "1.2.0-rc.11"
70
70
  },
71
71
  "scripts": {
72
72
  "build": "tsdown",