@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/firebase/functions/index.cjs +117 -229
- package/dist/iac/index.cjs +174 -304
- package/dist/iac/index.js +189 -319
- package/dist/index.cjs +157 -167
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +156 -166
- package/package.json +4 -4
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
|
-
|
|
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
|
|
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
|
|
1373
|
-
|
|
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.
|
|
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.
|
|
38
|
-
"@hot-updater/
|
|
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.
|
|
56
|
+
"@hot-updater/js": "0.20.13"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"firebase-admin": "*"
|