@hot-updater/firebase 0.20.11 → 0.20.13

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/index.js CHANGED
@@ -1,8 +1,159 @@
1
- import path from "path";
2
1
  import { calculatePagination, createDatabasePlugin, createStorageKeyBuilder } from "@hot-updater/plugin-core";
3
2
  import * as admin from "firebase-admin";
4
3
  import fs from "fs/promises";
4
+ import path from "path";
5
+
6
+ //#region src/firebaseDatabase.ts
7
+ const convertToBundle = (firestoreData) => ({
8
+ channel: firestoreData.channel,
9
+ enabled: Boolean(firestoreData.enabled),
10
+ shouldForceUpdate: Boolean(firestoreData.should_force_update),
11
+ fileHash: firestoreData.file_hash,
12
+ gitCommitHash: firestoreData.git_commit_hash,
13
+ id: firestoreData.id,
14
+ message: firestoreData.message,
15
+ platform: firestoreData.platform,
16
+ targetAppVersion: firestoreData.target_app_version,
17
+ storageUri: firestoreData.storage_uri,
18
+ fingerprintHash: firestoreData.fingerprint_hash,
19
+ metadata: firestoreData?.metadata ?? {}
20
+ });
21
+ const firebaseDatabase = (config, hooks) => {
22
+ let bundles = [];
23
+ return createDatabasePlugin("firebaseDatabase", {
24
+ getContext: () => {
25
+ let app;
26
+ try {
27
+ app = admin.app();
28
+ } catch {
29
+ app = admin.initializeApp(config);
30
+ }
31
+ const db = admin.firestore(app);
32
+ return {
33
+ db,
34
+ bundlesCollection: db.collection("bundles")
35
+ };
36
+ },
37
+ async getBundleById(context, bundleId) {
38
+ const found = bundles.find((b) => b.id === bundleId);
39
+ if (found) return found;
40
+ const bundleSnap = await context.bundlesCollection.doc(bundleId).get();
41
+ if (!bundleSnap.exists) return null;
42
+ return convertToBundle(bundleSnap.data());
43
+ },
44
+ async getBundles(context, options) {
45
+ const { where, limit, offset } = options;
46
+ let query = context.bundlesCollection;
47
+ if (where?.channel) query = query.where("channel", "==", where.channel);
48
+ if (where?.platform) query = query.where("platform", "==", where.platform);
49
+ query = query.orderBy("id", "desc");
50
+ const total = (await query.get()).size;
51
+ if (offset > 0) query = query.offset(offset);
52
+ if (limit) query = query.limit(limit);
53
+ bundles = (await query.get()).docs.map((doc) => convertToBundle(doc.data()));
54
+ return {
55
+ data: bundles,
56
+ pagination: calculatePagination(total, {
57
+ limit,
58
+ offset
59
+ })
60
+ };
61
+ },
62
+ async getChannels(context) {
63
+ const querySnapshot = await context.db.collection("channels").get();
64
+ if (querySnapshot.empty) return [];
65
+ const channels = /* @__PURE__ */ new Set();
66
+ for (const doc of querySnapshot.docs) {
67
+ const data = doc.data();
68
+ if (data.name) channels.add(data.name);
69
+ }
70
+ return Array.from(channels);
71
+ },
72
+ async commitBundle(context, { changedSets }) {
73
+ if (changedSets.length === 0) return;
74
+ let isTargetAppVersionChanged = false;
75
+ const deletedBundleIds = /* @__PURE__ */ new Set();
76
+ await context.db.runTransaction(async (transaction) => {
77
+ const bundlesSnapshot = await transaction.get(context.bundlesCollection);
78
+ const targetVersionsSnapshot = await transaction.get(context.db.collection("target_app_versions"));
79
+ const channelsSnapshot = await transaction.get(context.db.collection("channels"));
80
+ const bundlesMap = {};
81
+ for (const doc of bundlesSnapshot.docs) bundlesMap[doc.id] = doc.data();
82
+ for (const { operation, data } of changedSets) {
83
+ if (data.targetAppVersion) isTargetAppVersionChanged = true;
84
+ if (operation === "insert" || operation === "update") {
85
+ bundlesMap[data.id] = {
86
+ id: data.id,
87
+ channel: data.channel,
88
+ enabled: data.enabled,
89
+ should_force_update: data.shouldForceUpdate,
90
+ file_hash: data.fileHash,
91
+ git_commit_hash: data.gitCommitHash || null,
92
+ message: data.message || null,
93
+ platform: data.platform,
94
+ target_app_version: data.targetAppVersion,
95
+ storage_uri: data.storageUri,
96
+ fingerprint_hash: data.fingerprintHash,
97
+ metadata: data.metadata ?? {}
98
+ };
99
+ const channelRef = context.db.collection("channels").doc(data.channel);
100
+ transaction.set(channelRef, { name: data.channel }, { merge: true });
101
+ } else if (operation === "delete") {
102
+ if (!bundlesMap[data.id]) throw new Error(`Bundle with id ${data.id} not found`);
103
+ delete bundlesMap[data.id];
104
+ deletedBundleIds.add(data.id);
105
+ isTargetAppVersionChanged = true;
106
+ }
107
+ }
108
+ const requiredTargetVersionKeys = /* @__PURE__ */ new Set();
109
+ const requiredChannels = /* @__PURE__ */ new Set();
110
+ for (const bundle of Object.values(bundlesMap)) {
111
+ if (bundle.target_app_version) {
112
+ const key = `${bundle.platform}_${bundle.channel}_${bundle.target_app_version}`;
113
+ requiredTargetVersionKeys.add(key);
114
+ }
115
+ requiredChannels.add(bundle.channel);
116
+ }
117
+ for (const { operation, data } of changedSets) {
118
+ const bundleRef = context.bundlesCollection.doc(data.id);
119
+ if (operation === "insert" || operation === "update") {
120
+ transaction.set(bundleRef, {
121
+ id: data.id,
122
+ channel: data.channel,
123
+ enabled: data.enabled,
124
+ should_force_update: data.shouldForceUpdate,
125
+ file_hash: data.fileHash,
126
+ git_commit_hash: data.gitCommitHash || null,
127
+ message: data.message || null,
128
+ platform: data.platform,
129
+ target_app_version: data.targetAppVersion || null,
130
+ storage_uri: data.storageUri,
131
+ fingerprint_hash: data.fingerprintHash,
132
+ metadata: data.metadata ?? {}
133
+ }, { merge: true });
134
+ if (data.targetAppVersion) {
135
+ const versionDocId = `${data.platform}_${data.channel}_${data.targetAppVersion}`;
136
+ const targetAppVersionsRef = context.db.collection("target_app_versions").doc(versionDocId);
137
+ transaction.set(targetAppVersionsRef, {
138
+ channel: data.channel,
139
+ platform: data.platform,
140
+ target_app_version: data.targetAppVersion
141
+ }, { merge: true });
142
+ }
143
+ } else if (operation === "delete") transaction.delete(bundleRef);
144
+ }
145
+ if (isTargetAppVersionChanged) {
146
+ for (const targetDoc of targetVersionsSnapshot.docs) if (!requiredTargetVersionKeys.has(targetDoc.id)) transaction.delete(targetDoc.ref);
147
+ }
148
+ for (const channelDoc of channelsSnapshot.docs) if (!requiredChannels.has(channelDoc.id)) transaction.delete(channelDoc.ref);
149
+ });
150
+ for (const bundleId of deletedBundleIds) bundles = bundles.filter((b) => b.id !== bundleId);
151
+ hooks?.onDatabaseUpdated?.();
152
+ }
153
+ }, hooks);
154
+ };
5
155
 
156
+ //#endregion
6
157
  //#region ../../node_modules/.pnpm/mime@4.0.4/node_modules/mime/dist/types/other.js
7
158
  const types$1 = {
8
159
  "application/prs.cww": ["cww"],
@@ -1306,8 +1457,7 @@ var Mime = class {
1306
1457
  const last = path$1.replace(/^.*[/\\]/, "").toLowerCase();
1307
1458
  const ext = last.replace(/^.*\./, "").toLowerCase();
1308
1459
  const hasPath = last.length < path$1.length;
1309
- const hasDot = ext.length < last.length - 1;
1310
- if (!hasDot && hasPath) return null;
1460
+ if (!(ext.length < last.length - 1) && hasPath) return null;
1311
1461
  return __classPrivateFieldGet(this, _Mime_extensionToType, "f").get(ext) ?? null;
1312
1462
  }
1313
1463
  getExtension(type) {
@@ -1347,7 +1497,7 @@ const firebaseStorage = (config, hooks) => (_) => {
1347
1497
  let app;
1348
1498
  try {
1349
1499
  app = admin.app();
1350
- } catch (e) {
1500
+ } catch {
1351
1501
  app = admin.initializeApp(config);
1352
1502
  }
1353
1503
  const bucket = app.storage().bucket(config.storageBucket);
@@ -1369,10 +1519,8 @@ const firebaseStorage = (config, hooks) => (_) => {
1369
1519
  try {
1370
1520
  const fileContent = await fs.readFile(bundlePath);
1371
1521
  const contentType = src_default.getType(bundlePath) ?? "application/octet-stream";
1372
- const filename = path.basename(bundlePath);
1373
- const key = getStorageKey(bundleId, filename);
1374
- const file = bucket.file(key);
1375
- await file.save(fileContent, { metadata: { contentType } });
1522
+ const key = getStorageKey(bundleId, path.basename(bundlePath));
1523
+ await bucket.file(key).save(fileContent, { metadata: { contentType } });
1376
1524
  hooks?.onStorageUploaded?.();
1377
1525
  return { storageUri: `gs://${config.storageBucket}/${key}` };
1378
1526
  } catch (error) {
@@ -1384,163 +1532,5 @@ const firebaseStorage = (config, hooks) => (_) => {
1384
1532
  };
1385
1533
  };
1386
1534
 
1387
- //#endregion
1388
- //#region src/firebaseDatabase.ts
1389
- const convertToBundle = (firestoreData) => ({
1390
- channel: firestoreData.channel,
1391
- enabled: Boolean(firestoreData.enabled),
1392
- shouldForceUpdate: Boolean(firestoreData.should_force_update),
1393
- fileHash: firestoreData.file_hash,
1394
- gitCommitHash: firestoreData.git_commit_hash,
1395
- id: firestoreData.id,
1396
- message: firestoreData.message,
1397
- platform: firestoreData.platform,
1398
- targetAppVersion: firestoreData.target_app_version,
1399
- storageUri: firestoreData.storage_uri,
1400
- fingerprintHash: firestoreData.fingerprint_hash,
1401
- metadata: firestoreData?.metadata ?? {}
1402
- });
1403
- const firebaseDatabase = (config, hooks) => {
1404
- let bundles = [];
1405
- return createDatabasePlugin("firebaseDatabase", {
1406
- getContext: () => {
1407
- let app;
1408
- try {
1409
- app = admin.app();
1410
- } catch (e) {
1411
- app = admin.initializeApp(config);
1412
- }
1413
- const db = admin.firestore(app);
1414
- const bundlesCollection = db.collection("bundles");
1415
- return {
1416
- db,
1417
- bundlesCollection
1418
- };
1419
- },
1420
- async getBundleById(context, bundleId) {
1421
- const found = bundles.find((b) => b.id === bundleId);
1422
- if (found) return found;
1423
- const bundleRef = context.bundlesCollection.doc(bundleId);
1424
- const bundleSnap = await bundleRef.get();
1425
- if (!bundleSnap.exists) return null;
1426
- const firestoreData = bundleSnap.data();
1427
- return convertToBundle(firestoreData);
1428
- },
1429
- async getBundles(context, options) {
1430
- const { where, limit, offset } = options;
1431
- let query = context.bundlesCollection;
1432
- if (where?.channel) query = query.where("channel", "==", where.channel);
1433
- if (where?.platform) query = query.where("platform", "==", where.platform);
1434
- query = query.orderBy("id", "desc");
1435
- const totalCountQuery = query;
1436
- const totalSnapshot = await totalCountQuery.get();
1437
- const total = totalSnapshot.size;
1438
- if (offset > 0) query = query.offset(offset);
1439
- if (limit) query = query.limit(limit);
1440
- const querySnapshot = await query.get();
1441
- bundles = querySnapshot.docs.map((doc) => convertToBundle(doc.data()));
1442
- return {
1443
- data: bundles,
1444
- pagination: calculatePagination(total, {
1445
- limit,
1446
- offset
1447
- })
1448
- };
1449
- },
1450
- async getChannels(context) {
1451
- const channelsCollection = context.db.collection("channels");
1452
- const querySnapshot = await channelsCollection.get();
1453
- if (querySnapshot.empty) return [];
1454
- const channels = /* @__PURE__ */ new Set();
1455
- for (const doc of querySnapshot.docs) {
1456
- const data = doc.data();
1457
- if (data.name) channels.add(data.name);
1458
- }
1459
- return Array.from(channels);
1460
- },
1461
- async commitBundle(context, { changedSets }) {
1462
- if (changedSets.length === 0) return;
1463
- let isTargetAppVersionChanged = false;
1464
- const deletedBundleIds = /* @__PURE__ */ new Set();
1465
- await context.db.runTransaction(async (transaction) => {
1466
- const bundlesSnapshot = await transaction.get(context.bundlesCollection);
1467
- const targetVersionsSnapshot = await transaction.get(context.db.collection("target_app_versions"));
1468
- const channelsSnapshot = await transaction.get(context.db.collection("channels"));
1469
- const bundlesMap = {};
1470
- for (const doc of bundlesSnapshot.docs) bundlesMap[doc.id] = doc.data();
1471
- for (const { operation, data } of changedSets) {
1472
- if (data.targetAppVersion) isTargetAppVersionChanged = true;
1473
- if (operation === "insert" || operation === "update") {
1474
- bundlesMap[data.id] = {
1475
- id: data.id,
1476
- channel: data.channel,
1477
- enabled: data.enabled,
1478
- should_force_update: data.shouldForceUpdate,
1479
- file_hash: data.fileHash,
1480
- git_commit_hash: data.gitCommitHash || null,
1481
- message: data.message || null,
1482
- platform: data.platform,
1483
- target_app_version: data.targetAppVersion,
1484
- storage_uri: data.storageUri,
1485
- fingerprint_hash: data.fingerprintHash,
1486
- metadata: data.metadata ?? {}
1487
- };
1488
- const channelRef = context.db.collection("channels").doc(data.channel);
1489
- transaction.set(channelRef, { name: data.channel }, { merge: true });
1490
- } else if (operation === "delete") {
1491
- if (!bundlesMap[data.id]) throw new Error(`Bundle with id ${data.id} not found`);
1492
- delete bundlesMap[data.id];
1493
- deletedBundleIds.add(data.id);
1494
- isTargetAppVersionChanged = true;
1495
- }
1496
- }
1497
- const requiredTargetVersionKeys = /* @__PURE__ */ new Set();
1498
- const requiredChannels = /* @__PURE__ */ new Set();
1499
- for (const bundle of Object.values(bundlesMap)) {
1500
- if (bundle.target_app_version) {
1501
- const key = `${bundle.platform}_${bundle.channel}_${bundle.target_app_version}`;
1502
- requiredTargetVersionKeys.add(key);
1503
- }
1504
- requiredChannels.add(bundle.channel);
1505
- }
1506
- for (const { operation, data } of changedSets) {
1507
- const bundleRef = context.bundlesCollection.doc(data.id);
1508
- if (operation === "insert" || operation === "update") {
1509
- transaction.set(bundleRef, {
1510
- id: data.id,
1511
- channel: data.channel,
1512
- enabled: data.enabled,
1513
- should_force_update: data.shouldForceUpdate,
1514
- file_hash: data.fileHash,
1515
- git_commit_hash: data.gitCommitHash || null,
1516
- message: data.message || null,
1517
- platform: data.platform,
1518
- target_app_version: data.targetAppVersion || null,
1519
- storage_uri: data.storageUri,
1520
- fingerprint_hash: data.fingerprintHash,
1521
- metadata: data.metadata ?? {}
1522
- }, { merge: true });
1523
- if (data.targetAppVersion) {
1524
- const versionDocId = `${data.platform}_${data.channel}_${data.targetAppVersion}`;
1525
- const targetAppVersionsRef = context.db.collection("target_app_versions").doc(versionDocId);
1526
- transaction.set(targetAppVersionsRef, {
1527
- channel: data.channel,
1528
- platform: data.platform,
1529
- target_app_version: data.targetAppVersion
1530
- }, { merge: true });
1531
- }
1532
- } else if (operation === "delete") transaction.delete(bundleRef);
1533
- }
1534
- if (isTargetAppVersionChanged) {
1535
- for (const targetDoc of targetVersionsSnapshot.docs) if (!requiredTargetVersionKeys.has(targetDoc.id)) transaction.delete(targetDoc.ref);
1536
- }
1537
- for (const channelDoc of channelsSnapshot.docs) if (!requiredChannels.has(channelDoc.id)) transaction.delete(channelDoc.ref);
1538
- });
1539
- for (const bundleId of deletedBundleIds) bundles = bundles.filter((b) => b.id !== bundleId);
1540
- hooks?.onDatabaseUpdated?.();
1541
- }
1542
- }, hooks);
1543
- };
1544
-
1545
1535
  //#endregion
1546
1536
  export { firebaseDatabase, firebaseStorage };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@hot-updater/firebase",
3
3
  "type": "module",
4
- "version": "0.20.11",
4
+ "version": "0.20.13",
5
5
  "description": "React Native OTA solution for self-hosted",
6
6
  "main": "dist/index.cjs",
7
7
  "types": "dist/index.d.ts",
@@ -34,8 +34,8 @@
34
34
  ],
35
35
  "dependencies": {
36
36
  "firebase": "^11.3.1",
37
- "@hot-updater/core": "0.20.11",
38
- "@hot-updater/plugin-core": "0.20.11"
37
+ "@hot-updater/plugin-core": "0.20.13",
38
+ "@hot-updater/core": "0.20.13"
39
39
  },
40
40
  "publishConfig": {
41
41
  "access": "public"
@@ -53,7 +53,7 @@
53
53
  "hono": "^4.6.3",
54
54
  "mime": "^4.0.4",
55
55
  "picocolors": "1.1.1",
56
- "@hot-updater/js": "0.20.11"
56
+ "@hot-updater/js": "0.20.13"
57
57
  },
58
58
  "peerDependencies": {
59
59
  "firebase-admin": "*"