@hot-updater/firebase 0.29.2 → 0.29.4

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.
@@ -1493,12 +1493,12 @@ function mergeBundleUpdate(baseBundle, patch) {
1493
1493
  */
1494
1494
  function createDatabasePlugin(options) {
1495
1495
  return (config, hooks) => {
1496
+ let cachedMethods = null;
1497
+ const getMethods = () => {
1498
+ if (!cachedMethods) cachedMethods = options.factory(config);
1499
+ return cachedMethods;
1500
+ };
1496
1501
  return () => {
1497
- let cachedMethods = null;
1498
- const getMethods = () => {
1499
- if (!cachedMethods) cachedMethods = options.factory(config);
1500
- return cachedMethods;
1501
- };
1502
1502
  const changedMap = /* @__PURE__ */ new Map();
1503
1503
  const markChanged = (operation, data) => {
1504
1504
  changedMap.set(data.id, {
@@ -1529,8 +1529,8 @@ function createDatabasePlugin(options) {
1529
1529
  const params = { changedSets: Array.from(changedMap.values()) };
1530
1530
  if (context === void 0) await methods.commitBundle(params);
1531
1531
  else await methods.commitBundle(params, context);
1532
- await hooks?.onDatabaseUpdated?.();
1533
1532
  changedMap.clear();
1533
+ await hooks?.onDatabaseUpdated?.();
1534
1534
  },
1535
1535
  async updateBundle(targetBundleId, newBundle, context) {
1536
1536
  const pendingChange = changedMap.get(targetBundleId);
@@ -1673,6 +1673,23 @@ const sortBundles = (bundles, orderBy) => {
1673
1673
  return direction === "asc" ? result : -result;
1674
1674
  });
1675
1675
  };
1676
+ const applyFirestoreQueryableFilters = (query, where) => {
1677
+ let nextQuery = query;
1678
+ if (where?.channel) nextQuery = nextQuery.where("channel", "==", where.channel);
1679
+ if (where?.platform) nextQuery = nextQuery.where("platform", "==", where.platform);
1680
+ if (where?.enabled !== void 0) nextQuery = nextQuery.where("enabled", "==", where.enabled);
1681
+ if (where?.fingerprintHash !== void 0 && where.fingerprintHash !== null) nextQuery = nextQuery.where("fingerprint_hash", "==", where.fingerprintHash);
1682
+ if (where?.targetAppVersion !== void 0 && where.targetAppVersion !== null) nextQuery = nextQuery.where("target_app_version", "==", where.targetAppVersion);
1683
+ if (where?.id?.eq) nextQuery = nextQuery.where("id", "==", where.id.eq);
1684
+ if (where?.id?.gt) nextQuery = nextQuery.where("id", ">", where.id.gt);
1685
+ if (where?.id?.gte) nextQuery = nextQuery.where("id", ">=", where.id.gte);
1686
+ if (where?.id?.lt) nextQuery = nextQuery.where("id", "<", where.id.lt);
1687
+ if (where?.id?.lte) nextQuery = nextQuery.where("id", "<=", where.id.lte);
1688
+ return nextQuery;
1689
+ };
1690
+ const requiresInMemoryFiltering = (where) => {
1691
+ return Boolean(where?.id?.in || where?.targetAppVersionIn || where?.targetAppVersionNotNull || where?.targetAppVersion === null || where?.fingerprintHash === null);
1692
+ };
1676
1693
  const convertToBundle = (firestoreData) => ({
1677
1694
  channel: firestoreData.channel,
1678
1695
  enabled: Boolean(firestoreData.enabled),
@@ -1692,7 +1709,6 @@ const convertToBundle = (firestoreData) => ({
1692
1709
  const firebaseDatabase = createDatabasePlugin({
1693
1710
  name: "firebaseDatabase",
1694
1711
  factory: (config) => {
1695
- let bundles = [];
1696
1712
  let app;
1697
1713
  try {
1698
1714
  app = firebase_admin.default.app();
@@ -1703,32 +1719,30 @@ const firebaseDatabase = createDatabasePlugin({
1703
1719
  const bundlesCollection = db.collection("bundles");
1704
1720
  return {
1705
1721
  async getBundleById(bundleId) {
1706
- const found = bundles.find((b) => b.id === bundleId);
1707
- if (found) return found;
1708
1722
  const bundleSnap = await bundlesCollection.doc(bundleId).get();
1709
1723
  if (!bundleSnap.exists) return null;
1710
1724
  return convertToBundle(bundleSnap.data());
1711
1725
  },
1712
1726
  async getBundles(options) {
1713
1727
  const { where, limit, offset, orderBy } = options;
1714
- let query = bundlesCollection;
1715
- if (where?.channel) query = query.where("channel", "==", where.channel);
1716
- if (where?.platform) query = query.where("platform", "==", where.platform);
1717
- if (where?.enabled !== void 0) query = query.where("enabled", "==", where.enabled);
1718
- if (where?.fingerprintHash !== void 0 && where.fingerprintHash !== null) query = query.where("fingerprint_hash", "==", where.fingerprintHash);
1719
- if (where?.targetAppVersion !== void 0 && where.targetAppVersion !== null) query = query.where("target_app_version", "==", where.targetAppVersion);
1720
- if (where?.id?.eq) query = query.where("id", "==", where.id.eq);
1721
- if (where?.id?.gt) query = query.where("id", ">", where.id.gt);
1722
- if (where?.id?.gte) query = query.where("id", ">=", where.id.gte);
1723
- if (where?.id?.lt) query = query.where("id", "<", where.id.lt);
1724
- if (where?.id?.lte) query = query.where("id", "<=", where.id.lte);
1728
+ let query = applyFirestoreQueryableFilters(bundlesCollection, where);
1725
1729
  query = query.orderBy("id", orderBy?.direction === "asc" ? "asc" : "desc");
1730
+ if (requiresInMemoryFiltering(where)) {
1731
+ const filteredBundles = sortBundles((await query.get()).docs.map((doc) => convertToBundle(doc.data())).filter((bundle) => bundleMatchesQueryWhere(bundle, where)), orderBy);
1732
+ const total = filteredBundles.length;
1733
+ return {
1734
+ data: filteredBundles.slice(offset, offset + limit),
1735
+ pagination: calculatePagination(total, {
1736
+ limit,
1737
+ offset
1738
+ })
1739
+ };
1740
+ }
1726
1741
  const total = (await query.get()).size;
1727
1742
  if (offset > 0) query = query.offset(offset);
1728
1743
  if (limit) query = query.limit(limit);
1729
- bundles = sortBundles((await query.get()).docs.map((doc) => convertToBundle(doc.data())).filter((bundle) => bundleMatchesQueryWhere(bundle, where)), orderBy);
1730
1744
  return {
1731
- data: bundles,
1745
+ data: sortBundles((await query.get()).docs.map((doc) => convertToBundle(doc.data())), orderBy),
1732
1746
  pagination: calculatePagination(total, {
1733
1747
  limit,
1734
1748
  offset
@@ -1748,7 +1762,6 @@ const firebaseDatabase = createDatabasePlugin({
1748
1762
  async commitBundle({ changedSets }) {
1749
1763
  if (changedSets.length === 0) return;
1750
1764
  let isTargetAppVersionChanged = false;
1751
- const deletedBundleIds = /* @__PURE__ */ new Set();
1752
1765
  await db.runTransaction(async (transaction) => {
1753
1766
  const bundlesSnapshot = await transaction.get(bundlesCollection);
1754
1767
  const targetVersionsSnapshot = await transaction.get(db.collection("target_app_versions"));
@@ -1779,7 +1792,6 @@ const firebaseDatabase = createDatabasePlugin({
1779
1792
  } else if (operation === "delete") {
1780
1793
  if (!bundlesMap[data.id]) throw new Error(`Bundle with id ${data.id} not found`);
1781
1794
  delete bundlesMap[data.id];
1782
- deletedBundleIds.add(data.id);
1783
1795
  isTargetAppVersionChanged = true;
1784
1796
  }
1785
1797
  }
@@ -1827,7 +1839,6 @@ const firebaseDatabase = createDatabasePlugin({
1827
1839
  }
1828
1840
  for (const channelDoc of channelsSnapshot.docs) if (!requiredChannels.has(channelDoc.id)) transaction.delete(channelDoc.ref);
1829
1841
  });
1830
- for (const bundleId of deletedBundleIds) bundles = bundles.filter((b) => b.id !== bundleId);
1831
1842
  }
1832
1843
  };
1833
1844
  }
@@ -22,6 +22,10 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
22
22
  enumerable: true
23
23
  }) : target, mod));
24
24
  //#endregion
25
+ let fs = require("fs");
26
+ fs = __toESM(fs);
27
+ let path = require("path");
28
+ path = __toESM(path);
25
29
  let _hot_updater_cli_tools = require("@hot-updater/cli-tools");
26
30
  let node_url = require("node:url");
27
31
  let node_child_process = require("node:child_process");
@@ -33,10 +37,6 @@ let node_tty = require("node:tty");
33
37
  node_tty = __toESM(node_tty);
34
38
  let node_path = require("node:path");
35
39
  node_path = __toESM(node_path);
36
- let path = require("path");
37
- path = __toESM(path);
38
- let fs = require("fs");
39
- fs = __toESM(fs);
40
40
  let node_timers_promises = require("node:timers/promises");
41
41
  let node_os = require("node:os");
42
42
  let node_events = require("node:events");
@@ -6780,7 +6780,7 @@ const syncFunctionsPackageJson = async (functionsDir) => {
6780
6780
  const packageJsonPath = path.default.join(functionsDir, "package.json");
6781
6781
  const packageJson = JSON.parse(await fs.default.promises.readFile(packageJsonPath, "utf-8"));
6782
6782
  packageJson.dependencies = {
6783
- ...packageJson.dependencies ?? {},
6783
+ ...packageJson.dependencies,
6784
6784
  "@hot-updater/server": runtimePackageInfo.serverPackageVersion,
6785
6785
  hono: runtimePackageInfo.honoVersion
6786
6786
  };
@@ -1,4 +1,6 @@
1
1
  import { createRequire } from "node:module";
2
+ import fs from "fs";
3
+ import path from "path";
2
4
  import { ConfigBuilder, HOT_UPDATER_SERVER_PACKAGE_VERSION_ENV, copyDirToTmp, link, makeEnv, p, resolveHotUpdaterServerVersion, resolvePackageVersion, transformEnv, transformTemplate } from "@hot-updater/cli-tools";
3
5
  import { fileURLToPath } from "node:url";
4
6
  import { ChildProcess, execFile, spawn, spawnSync } from "node:child_process";
@@ -6,9 +8,7 @@ import { StringDecoder } from "node:string_decoder";
6
8
  import { aborted, callbackify, debuglog, inspect, promisify, stripVTControlCharacters } from "node:util";
7
9
  import process$1, { execArgv, execPath, hrtime, platform } from "node:process";
8
10
  import tty from "node:tty";
9
- import path from "node:path";
10
- import path$1 from "path";
11
- import fs from "fs";
11
+ import path$1 from "node:path";
12
12
  import { scheduler, setImmediate, setTimeout } from "node:timers/promises";
13
13
  import { constants } from "node:os";
14
14
  import { EventEmitter, addAbortListener, on, once, setMaxListeners } from "node:events";
@@ -1431,33 +1431,33 @@ function toPath(urlOrPath) {
1431
1431
  }
1432
1432
  function traversePathUp(startPath) {
1433
1433
  return { *[Symbol.iterator]() {
1434
- let currentPath = path.resolve(toPath(startPath));
1434
+ let currentPath = path$1.resolve(toPath(startPath));
1435
1435
  let previousPath;
1436
1436
  while (previousPath !== currentPath) {
1437
1437
  yield currentPath;
1438
1438
  previousPath = currentPath;
1439
- currentPath = path.resolve(currentPath, "..");
1439
+ currentPath = path$1.resolve(currentPath, "..");
1440
1440
  }
1441
1441
  } };
1442
1442
  }
1443
1443
  //#endregion
1444
1444
  //#region ../../node_modules/.pnpm/npm-run-path@6.0.0/node_modules/npm-run-path/index.js
1445
1445
  const npmRunPath = ({ cwd = process$1.cwd(), path: pathOption = process$1.env[pathKey()], preferLocal = true, execPath = process$1.execPath, addExecPath = true } = {}) => {
1446
- const cwdPath = path.resolve(toPath(cwd));
1446
+ const cwdPath = path$1.resolve(toPath(cwd));
1447
1447
  const result = [];
1448
- const pathParts = pathOption.split(path.delimiter);
1448
+ const pathParts = pathOption.split(path$1.delimiter);
1449
1449
  if (preferLocal) applyPreferLocal(result, pathParts, cwdPath);
1450
1450
  if (addExecPath) applyExecPath(result, pathParts, execPath, cwdPath);
1451
- return pathOption === "" || pathOption === path.delimiter ? `${result.join(path.delimiter)}${pathOption}` : [...result, pathOption].join(path.delimiter);
1451
+ return pathOption === "" || pathOption === path$1.delimiter ? `${result.join(path$1.delimiter)}${pathOption}` : [...result, pathOption].join(path$1.delimiter);
1452
1452
  };
1453
1453
  const applyPreferLocal = (result, pathParts, cwdPath) => {
1454
1454
  for (const directory of traversePathUp(cwdPath)) {
1455
- const pathPart = path.join(directory, "node_modules/.bin");
1455
+ const pathPart = path$1.join(directory, "node_modules/.bin");
1456
1456
  if (!pathParts.includes(pathPart)) result.push(pathPart);
1457
1457
  }
1458
1458
  };
1459
1459
  const applyExecPath = (result, pathParts, execPath, cwdPath) => {
1460
- const pathPart = path.resolve(cwdPath, toPath(execPath), "..");
1460
+ const pathPart = path$1.resolve(cwdPath, toPath(execPath), "..");
1461
1461
  if (!pathParts.includes(pathPart)) result.push(pathPart);
1462
1462
  };
1463
1463
  const npmRunPathEnv = ({ env = process$1.env, ...options } = {}) => {
@@ -2467,7 +2467,7 @@ const mapNode = ({ options }) => {
2467
2467
  const handleNodeOption = (file, commandArguments, { node: shouldHandleNode = false, nodePath = execPath, nodeOptions = execArgv.filter((nodeOption) => !nodeOption.startsWith("--inspect")), cwd, execPath: formerNodePath, ...options }) => {
2468
2468
  if (formerNodePath !== void 0) throw new TypeError("The \"execPath\" option has been removed. Please use the \"nodePath\" option instead.");
2469
2469
  const normalizedNodePath = safeNormalizeFileUrl(nodePath, "The \"nodePath\" option");
2470
- const resolvedNodePath = path.resolve(cwd, normalizedNodePath);
2470
+ const resolvedNodePath = path$1.resolve(cwd, normalizedNodePath);
2471
2471
  const newOptions = {
2472
2472
  ...options,
2473
2473
  nodePath: resolvedNodePath,
@@ -2479,7 +2479,7 @@ const handleNodeOption = (file, commandArguments, { node: shouldHandleNode = fal
2479
2479
  commandArguments,
2480
2480
  newOptions
2481
2481
  ];
2482
- if (path.basename(file, ".exe") === "node") throw new TypeError("When the \"node\" option is true, the first argument does not need to be \"node\".");
2482
+ if (path$1.basename(file, ".exe") === "node") throw new TypeError("When the \"node\" option is true, the first argument does not need to be \"node\".");
2483
2483
  return [
2484
2484
  resolvedNodePath,
2485
2485
  [
@@ -2563,7 +2563,7 @@ const serializeEncoding = (encoding) => typeof encoding === "string" ? `"${encod
2563
2563
  //#region ../../node_modules/.pnpm/execa@9.5.2/node_modules/execa/lib/arguments/cwd.js
2564
2564
  const normalizeCwd = (cwd = getDefaultCwd()) => {
2565
2565
  const cwdString = safeNormalizeFileUrl(cwd, "The \"cwd\" option");
2566
- return path.resolve(cwdString);
2566
+ return path$1.resolve(cwdString);
2567
2567
  };
2568
2568
  const getDefaultCwd = () => {
2569
2569
  try {
@@ -2601,7 +2601,7 @@ const normalizeOptions = (filePath, rawArguments, rawOptions) => {
2601
2601
  options.killSignal = normalizeKillSignal(options.killSignal);
2602
2602
  options.forceKillAfterDelay = normalizeForceKillAfterDelay(options.forceKillAfterDelay);
2603
2603
  options.lines = options.lines.map((lines, fdNumber) => lines && !BINARY_ENCODINGS.has(options.encoding) && options.buffer[fdNumber]);
2604
- if (process$1.platform === "win32" && path.basename(file, ".exe") === "cmd") commandArguments.unshift("/q");
2604
+ if (process$1.platform === "win32" && path$1.basename(file, ".exe") === "cmd") commandArguments.unshift("/q");
2605
2605
  return {
2606
2606
  file,
2607
2607
  commandArguments,
@@ -6427,8 +6427,8 @@ const ensureExists = async (targetPath, description) => {
6427
6427
  }
6428
6428
  };
6429
6429
  const normalizeFunctionsPackage = async (functionsDir) => {
6430
- const templatePackagePath = path.join(functionsDir, "_package.json");
6431
- const packageJsonPath = path.join(functionsDir, "package.json");
6430
+ const templatePackagePath = path$1.join(functionsDir, "_package.json");
6431
+ const packageJsonPath = path$1.join(functionsDir, "package.json");
6432
6432
  try {
6433
6433
  await fs$1.rename(templatePackagePath, packageJsonPath);
6434
6434
  } catch (error) {
@@ -6437,12 +6437,12 @@ const normalizeFunctionsPackage = async (functionsDir) => {
6437
6437
  }
6438
6438
  };
6439
6439
  const prepareFirebaseTemplate = async (firebaseRootDir) => {
6440
- const publicDir = path.join(firebaseRootDir, "public");
6441
- const builtFunctionsDir = path.join(firebaseRootDir, "functions");
6440
+ const publicDir = path$1.join(firebaseRootDir, "public");
6441
+ const builtFunctionsDir = path$1.join(firebaseRootDir, "functions");
6442
6442
  await ensureExists(publicDir, "public template directory");
6443
6443
  await ensureExists(builtFunctionsDir, "functions build directory");
6444
6444
  const { tmpDir, removeTmpDir } = await copyDirToTmp(publicDir);
6445
- const functionsDir = path.join(tmpDir, "functions");
6445
+ const functionsDir = path$1.join(tmpDir, "functions");
6446
6446
  await fs$1.cp(builtFunctionsDir, functionsDir, { recursive: true });
6447
6447
  await normalizeFunctionsPackage(functionsDir);
6448
6448
  return {
@@ -6763,7 +6763,7 @@ const REGIONS = [
6763
6763
  }
6764
6764
  ];
6765
6765
  const getFirebaseRuntimePackageInfo = () => {
6766
- const firebasePackageRoot = path$1.dirname(__require.resolve("@hot-updater/firebase/package.json"));
6766
+ const firebasePackageRoot = path.dirname(__require.resolve("@hot-updater/firebase/package.json"));
6767
6767
  return {
6768
6768
  currentPackageVersion: resolvePackageVersion("@hot-updater/firebase"),
6769
6769
  serverPackageVersion: resolveHotUpdaterServerVersion("@hot-updater/firebase"),
@@ -6772,10 +6772,10 @@ const getFirebaseRuntimePackageInfo = () => {
6772
6772
  };
6773
6773
  const syncFunctionsPackageJson = async (functionsDir) => {
6774
6774
  const runtimePackageInfo = getFirebaseRuntimePackageInfo();
6775
- const packageJsonPath = path$1.join(functionsDir, "package.json");
6775
+ const packageJsonPath = path.join(functionsDir, "package.json");
6776
6776
  const packageJson = JSON.parse(await fs.promises.readFile(packageJsonPath, "utf-8"));
6777
6777
  packageJson.dependencies = {
6778
- ...packageJson.dependencies ?? {},
6778
+ ...packageJson.dependencies,
6779
6779
  "@hot-updater/server": runtimePackageInfo.serverPackageVersion,
6780
6780
  hono: runtimePackageInfo.honoVersion
6781
6781
  };
@@ -6810,9 +6810,9 @@ const deployFirestore = async (cwd) => {
6810
6810
  fieldOverrides: []
6811
6811
  };
6812
6812
  } catch {}
6813
- const newIndexes = JSON.parse(await fs.promises.readFile(path$1.join(cwd, "firestore.indexes.json"), "utf-8"));
6813
+ const newIndexes = JSON.parse(await fs.promises.readFile(path.join(cwd, "firestore.indexes.json"), "utf-8"));
6814
6814
  const mergedIndexes = mergeIndexes(originalIndexes, newIndexes);
6815
- await fs.promises.writeFile(path$1.join(cwd, "firestore.indexes.json"), JSON.stringify(mergedIndexes, null, 2));
6815
+ await fs.promises.writeFile(path.join(cwd, "firestore.indexes.json"), JSON.stringify(mergedIndexes, null, 2));
6816
6816
  try {
6817
6817
  await execa("npx", [
6818
6818
  "firebase",
@@ -6884,8 +6884,8 @@ const runInit = async ({ build }) => {
6884
6884
  p.log.step(link("https://cloud.google.com/sdk/docs/install"));
6885
6885
  process.exit(1);
6886
6886
  }
6887
- const { tmpDir, removeTmpDir, functionsDir } = await prepareFirebaseTemplate(path$1.dirname(path$1.dirname(__require.resolve("@hot-updater/firebase/functions"))));
6888
- const functionsIndexPath = path$1.join(functionsDir, "index.cjs");
6887
+ const { tmpDir, removeTmpDir, functionsDir } = await prepareFirebaseTemplate(path.dirname(path.dirname(__require.resolve("@hot-updater/firebase/functions"))));
6888
+ const functionsIndexPath = path.join(functionsDir, "index.cjs");
6889
6889
  const runtimePackageInfo = await syncFunctionsPackageJson(functionsDir);
6890
6890
  const initializeVariable = await initFirebaseUser(tmpDir);
6891
6891
  let currentRegion;
package/dist/index.cjs CHANGED
@@ -54,6 +54,23 @@ const sortBundles = (bundles, orderBy) => {
54
54
  return direction === "asc" ? result : -result;
55
55
  });
56
56
  };
57
+ const applyFirestoreQueryableFilters = (query, where) => {
58
+ let nextQuery = query;
59
+ if (where?.channel) nextQuery = nextQuery.where("channel", "==", where.channel);
60
+ if (where?.platform) nextQuery = nextQuery.where("platform", "==", where.platform);
61
+ if (where?.enabled !== void 0) nextQuery = nextQuery.where("enabled", "==", where.enabled);
62
+ if (where?.fingerprintHash !== void 0 && where.fingerprintHash !== null) nextQuery = nextQuery.where("fingerprint_hash", "==", where.fingerprintHash);
63
+ if (where?.targetAppVersion !== void 0 && where.targetAppVersion !== null) nextQuery = nextQuery.where("target_app_version", "==", where.targetAppVersion);
64
+ if (where?.id?.eq) nextQuery = nextQuery.where("id", "==", where.id.eq);
65
+ if (where?.id?.gt) nextQuery = nextQuery.where("id", ">", where.id.gt);
66
+ if (where?.id?.gte) nextQuery = nextQuery.where("id", ">=", where.id.gte);
67
+ if (where?.id?.lt) nextQuery = nextQuery.where("id", "<", where.id.lt);
68
+ if (where?.id?.lte) nextQuery = nextQuery.where("id", "<=", where.id.lte);
69
+ return nextQuery;
70
+ };
71
+ const requiresInMemoryFiltering = (where) => {
72
+ return Boolean(where?.id?.in || where?.targetAppVersionIn || where?.targetAppVersionNotNull || where?.targetAppVersion === null || where?.fingerprintHash === null);
73
+ };
57
74
  const convertToBundle = (firestoreData) => ({
58
75
  channel: firestoreData.channel,
59
76
  enabled: Boolean(firestoreData.enabled),
@@ -73,7 +90,6 @@ const convertToBundle = (firestoreData) => ({
73
90
  const firebaseDatabase = (0, _hot_updater_plugin_core.createDatabasePlugin)({
74
91
  name: "firebaseDatabase",
75
92
  factory: (config) => {
76
- let bundles = [];
77
93
  let app;
78
94
  try {
79
95
  app = firebase_admin.default.app();
@@ -84,32 +100,30 @@ const firebaseDatabase = (0, _hot_updater_plugin_core.createDatabasePlugin)({
84
100
  const bundlesCollection = db.collection("bundles");
85
101
  return {
86
102
  async getBundleById(bundleId) {
87
- const found = bundles.find((b) => b.id === bundleId);
88
- if (found) return found;
89
103
  const bundleSnap = await bundlesCollection.doc(bundleId).get();
90
104
  if (!bundleSnap.exists) return null;
91
105
  return convertToBundle(bundleSnap.data());
92
106
  },
93
107
  async getBundles(options) {
94
108
  const { where, limit, offset, orderBy } = options;
95
- let query = bundlesCollection;
96
- if (where?.channel) query = query.where("channel", "==", where.channel);
97
- if (where?.platform) query = query.where("platform", "==", where.platform);
98
- if (where?.enabled !== void 0) query = query.where("enabled", "==", where.enabled);
99
- if (where?.fingerprintHash !== void 0 && where.fingerprintHash !== null) query = query.where("fingerprint_hash", "==", where.fingerprintHash);
100
- if (where?.targetAppVersion !== void 0 && where.targetAppVersion !== null) query = query.where("target_app_version", "==", where.targetAppVersion);
101
- if (where?.id?.eq) query = query.where("id", "==", where.id.eq);
102
- if (where?.id?.gt) query = query.where("id", ">", where.id.gt);
103
- if (where?.id?.gte) query = query.where("id", ">=", where.id.gte);
104
- if (where?.id?.lt) query = query.where("id", "<", where.id.lt);
105
- if (where?.id?.lte) query = query.where("id", "<=", where.id.lte);
109
+ let query = applyFirestoreQueryableFilters(bundlesCollection, where);
106
110
  query = query.orderBy("id", orderBy?.direction === "asc" ? "asc" : "desc");
111
+ if (requiresInMemoryFiltering(where)) {
112
+ const filteredBundles = sortBundles((await query.get()).docs.map((doc) => convertToBundle(doc.data())).filter((bundle) => bundleMatchesQueryWhere(bundle, where)), orderBy);
113
+ const total = filteredBundles.length;
114
+ return {
115
+ data: filteredBundles.slice(offset, offset + limit),
116
+ pagination: (0, _hot_updater_plugin_core.calculatePagination)(total, {
117
+ limit,
118
+ offset
119
+ })
120
+ };
121
+ }
107
122
  const total = (await query.get()).size;
108
123
  if (offset > 0) query = query.offset(offset);
109
124
  if (limit) query = query.limit(limit);
110
- bundles = sortBundles((await query.get()).docs.map((doc) => convertToBundle(doc.data())).filter((bundle) => bundleMatchesQueryWhere(bundle, where)), orderBy);
111
125
  return {
112
- data: bundles,
126
+ data: sortBundles((await query.get()).docs.map((doc) => convertToBundle(doc.data())), orderBy),
113
127
  pagination: (0, _hot_updater_plugin_core.calculatePagination)(total, {
114
128
  limit,
115
129
  offset
@@ -129,7 +143,6 @@ const firebaseDatabase = (0, _hot_updater_plugin_core.createDatabasePlugin)({
129
143
  async commitBundle({ changedSets }) {
130
144
  if (changedSets.length === 0) return;
131
145
  let isTargetAppVersionChanged = false;
132
- const deletedBundleIds = /* @__PURE__ */ new Set();
133
146
  await db.runTransaction(async (transaction) => {
134
147
  const bundlesSnapshot = await transaction.get(bundlesCollection);
135
148
  const targetVersionsSnapshot = await transaction.get(db.collection("target_app_versions"));
@@ -160,7 +173,6 @@ const firebaseDatabase = (0, _hot_updater_plugin_core.createDatabasePlugin)({
160
173
  } else if (operation === "delete") {
161
174
  if (!bundlesMap[data.id]) throw new Error(`Bundle with id ${data.id} not found`);
162
175
  delete bundlesMap[data.id];
163
- deletedBundleIds.add(data.id);
164
176
  isTargetAppVersionChanged = true;
165
177
  }
166
178
  }
@@ -208,7 +220,6 @@ const firebaseDatabase = (0, _hot_updater_plugin_core.createDatabasePlugin)({
208
220
  }
209
221
  for (const channelDoc of channelsSnapshot.docs) if (!requiredChannels.has(channelDoc.id)) transaction.delete(channelDoc.ref);
210
222
  });
211
- for (const bundleId of deletedBundleIds) bundles = bundles.filter((b) => b.id !== bundleId);
212
223
  }
213
224
  };
214
225
  }
package/dist/index.mjs CHANGED
@@ -28,6 +28,23 @@ const sortBundles = (bundles, orderBy) => {
28
28
  return direction === "asc" ? result : -result;
29
29
  });
30
30
  };
31
+ const applyFirestoreQueryableFilters = (query, where) => {
32
+ let nextQuery = query;
33
+ if (where?.channel) nextQuery = nextQuery.where("channel", "==", where.channel);
34
+ if (where?.platform) nextQuery = nextQuery.where("platform", "==", where.platform);
35
+ if (where?.enabled !== void 0) nextQuery = nextQuery.where("enabled", "==", where.enabled);
36
+ if (where?.fingerprintHash !== void 0 && where.fingerprintHash !== null) nextQuery = nextQuery.where("fingerprint_hash", "==", where.fingerprintHash);
37
+ if (where?.targetAppVersion !== void 0 && where.targetAppVersion !== null) nextQuery = nextQuery.where("target_app_version", "==", where.targetAppVersion);
38
+ if (where?.id?.eq) nextQuery = nextQuery.where("id", "==", where.id.eq);
39
+ if (where?.id?.gt) nextQuery = nextQuery.where("id", ">", where.id.gt);
40
+ if (where?.id?.gte) nextQuery = nextQuery.where("id", ">=", where.id.gte);
41
+ if (where?.id?.lt) nextQuery = nextQuery.where("id", "<", where.id.lt);
42
+ if (where?.id?.lte) nextQuery = nextQuery.where("id", "<=", where.id.lte);
43
+ return nextQuery;
44
+ };
45
+ const requiresInMemoryFiltering = (where) => {
46
+ return Boolean(where?.id?.in || where?.targetAppVersionIn || where?.targetAppVersionNotNull || where?.targetAppVersion === null || where?.fingerprintHash === null);
47
+ };
31
48
  const convertToBundle = (firestoreData) => ({
32
49
  channel: firestoreData.channel,
33
50
  enabled: Boolean(firestoreData.enabled),
@@ -47,7 +64,6 @@ const convertToBundle = (firestoreData) => ({
47
64
  const firebaseDatabase = createDatabasePlugin({
48
65
  name: "firebaseDatabase",
49
66
  factory: (config) => {
50
- let bundles = [];
51
67
  let app;
52
68
  try {
53
69
  app = admin.app();
@@ -58,32 +74,30 @@ const firebaseDatabase = createDatabasePlugin({
58
74
  const bundlesCollection = db.collection("bundles");
59
75
  return {
60
76
  async getBundleById(bundleId) {
61
- const found = bundles.find((b) => b.id === bundleId);
62
- if (found) return found;
63
77
  const bundleSnap = await bundlesCollection.doc(bundleId).get();
64
78
  if (!bundleSnap.exists) return null;
65
79
  return convertToBundle(bundleSnap.data());
66
80
  },
67
81
  async getBundles(options) {
68
82
  const { where, limit, offset, orderBy } = options;
69
- let query = bundlesCollection;
70
- if (where?.channel) query = query.where("channel", "==", where.channel);
71
- if (where?.platform) query = query.where("platform", "==", where.platform);
72
- if (where?.enabled !== void 0) query = query.where("enabled", "==", where.enabled);
73
- if (where?.fingerprintHash !== void 0 && where.fingerprintHash !== null) query = query.where("fingerprint_hash", "==", where.fingerprintHash);
74
- if (where?.targetAppVersion !== void 0 && where.targetAppVersion !== null) query = query.where("target_app_version", "==", where.targetAppVersion);
75
- if (where?.id?.eq) query = query.where("id", "==", where.id.eq);
76
- if (where?.id?.gt) query = query.where("id", ">", where.id.gt);
77
- if (where?.id?.gte) query = query.where("id", ">=", where.id.gte);
78
- if (where?.id?.lt) query = query.where("id", "<", where.id.lt);
79
- if (where?.id?.lte) query = query.where("id", "<=", where.id.lte);
83
+ let query = applyFirestoreQueryableFilters(bundlesCollection, where);
80
84
  query = query.orderBy("id", orderBy?.direction === "asc" ? "asc" : "desc");
85
+ if (requiresInMemoryFiltering(where)) {
86
+ const filteredBundles = sortBundles((await query.get()).docs.map((doc) => convertToBundle(doc.data())).filter((bundle) => bundleMatchesQueryWhere(bundle, where)), orderBy);
87
+ const total = filteredBundles.length;
88
+ return {
89
+ data: filteredBundles.slice(offset, offset + limit),
90
+ pagination: calculatePagination(total, {
91
+ limit,
92
+ offset
93
+ })
94
+ };
95
+ }
81
96
  const total = (await query.get()).size;
82
97
  if (offset > 0) query = query.offset(offset);
83
98
  if (limit) query = query.limit(limit);
84
- bundles = sortBundles((await query.get()).docs.map((doc) => convertToBundle(doc.data())).filter((bundle) => bundleMatchesQueryWhere(bundle, where)), orderBy);
85
99
  return {
86
- data: bundles,
100
+ data: sortBundles((await query.get()).docs.map((doc) => convertToBundle(doc.data())), orderBy),
87
101
  pagination: calculatePagination(total, {
88
102
  limit,
89
103
  offset
@@ -103,7 +117,6 @@ const firebaseDatabase = createDatabasePlugin({
103
117
  async commitBundle({ changedSets }) {
104
118
  if (changedSets.length === 0) return;
105
119
  let isTargetAppVersionChanged = false;
106
- const deletedBundleIds = /* @__PURE__ */ new Set();
107
120
  await db.runTransaction(async (transaction) => {
108
121
  const bundlesSnapshot = await transaction.get(bundlesCollection);
109
122
  const targetVersionsSnapshot = await transaction.get(db.collection("target_app_versions"));
@@ -134,7 +147,6 @@ const firebaseDatabase = createDatabasePlugin({
134
147
  } else if (operation === "delete") {
135
148
  if (!bundlesMap[data.id]) throw new Error(`Bundle with id ${data.id} not found`);
136
149
  delete bundlesMap[data.id];
137
- deletedBundleIds.add(data.id);
138
150
  isTargetAppVersionChanged = true;
139
151
  }
140
152
  }
@@ -182,7 +194,6 @@ const firebaseDatabase = createDatabasePlugin({
182
194
  }
183
195
  for (const channelDoc of channelsSnapshot.docs) if (!requiredChannels.has(channelDoc.id)) transaction.delete(channelDoc.ref);
184
196
  });
185
- for (const bundleId of deletedBundleIds) bundles = bundles.filter((b) => b.id !== bundleId);
186
197
  }
187
198
  };
188
199
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@hot-updater/firebase",
3
3
  "type": "module",
4
- "version": "0.29.2",
4
+ "version": "0.29.4",
5
5
  "description": "React Native OTA solution for self-hosted",
6
6
  "main": "dist/index.cjs",
7
7
  "types": "dist/index.d.cts",
@@ -36,10 +36,10 @@
36
36
  "dependencies": {
37
37
  "firebase": "^11.3.1",
38
38
  "hono": "4.12.9",
39
- "@hot-updater/cli-tools": "0.29.2",
40
- "@hot-updater/core": "0.29.2",
41
- "@hot-updater/plugin-core": "0.29.2",
42
- "@hot-updater/server": "0.29.2"
39
+ "@hot-updater/cli-tools": "0.29.4",
40
+ "@hot-updater/plugin-core": "0.29.4",
41
+ "@hot-updater/server": "0.29.4",
42
+ "@hot-updater/core": "0.29.4"
43
43
  },
44
44
  "publishConfig": {
45
45
  "access": "public"
@@ -54,9 +54,9 @@
54
54
  "firebase-tools": "^13.32.0",
55
55
  "fkill": "^9.0.0",
56
56
  "mime": "^4.0.4",
57
- "@hot-updater/js": "0.29.2",
58
- "@hot-updater/mock": "0.29.2",
59
- "@hot-updater/test-utils": "0.29.2"
57
+ "@hot-updater/js": "0.29.4",
58
+ "@hot-updater/mock": "0.29.4",
59
+ "@hot-updater/test-utils": "0.29.4"
60
60
  },
61
61
  "peerDependencies": {
62
62
  "firebase-admin": "*",