@edgedev/firebase 2.1.47 → 2.1.49
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/edgeFirebase.ts +55 -20
- package/package.json +1 -1
- package/src/.env.dev +10 -1
- package/src/.env.prod +10 -1
- package/src/config.js +13 -13
- package/src/edgeFirebase.js +149 -3
- package/src/package.json +2 -1
- package/src/postinstall.sh +23 -1
package/edgeFirebase.ts
CHANGED
|
@@ -56,12 +56,11 @@ import {
|
|
|
56
56
|
} from "firebase/auth";
|
|
57
57
|
|
|
58
58
|
|
|
59
|
-
import { getStorage, ref, uploadBytesResumable, getDownloadURL, connectStorageEmulator, listAll, deleteObject} from "firebase/storage";
|
|
59
|
+
import { getStorage, ref, uploadBytesResumable, getDownloadURL, connectStorageEmulator, listAll, deleteObject, getMetadata} from "firebase/storage";
|
|
60
60
|
|
|
61
61
|
import { getFunctions, httpsCallable, connectFunctionsEmulator } from "firebase/functions";
|
|
62
62
|
|
|
63
63
|
import { getAnalytics, logEvent } from "firebase/analytics";
|
|
64
|
-
import { get } from "http";
|
|
65
64
|
|
|
66
65
|
interface FirestoreQuery {
|
|
67
66
|
field: string;
|
|
@@ -206,7 +205,6 @@ interface Meta {
|
|
|
206
205
|
[key: string]: unknown;
|
|
207
206
|
}
|
|
208
207
|
|
|
209
|
-
|
|
210
208
|
export const EdgeFirebase = class {
|
|
211
209
|
constructor(
|
|
212
210
|
firebaseConfig: firebaseConfig = {
|
|
@@ -1235,6 +1233,7 @@ export const EdgeFirebase = class {
|
|
|
1235
1233
|
registrationCode: "",
|
|
1236
1234
|
registrationMeta: {},
|
|
1237
1235
|
ruleHelpers: {},
|
|
1236
|
+
currentUploadProgress: 0,
|
|
1238
1237
|
});
|
|
1239
1238
|
|
|
1240
1239
|
public getDocData = async (
|
|
@@ -2095,8 +2094,13 @@ export const EdgeFirebase = class {
|
|
|
2095
2094
|
|
|
2096
2095
|
|
|
2097
2096
|
// File functions
|
|
2098
|
-
public uploadFile = async (
|
|
2099
|
-
|
|
2097
|
+
public uploadFile = async (orgId: string, file: Blob, filePath: string = "", isPublic: boolean = false, toR2: boolean = false): Promise<actionResponse> => {
|
|
2098
|
+
// Finish toCF function hook.
|
|
2099
|
+
this.state.currentUploadProgress = 0;
|
|
2100
|
+
let collectionPath = "organizations/" + orgId;
|
|
2101
|
+
if (filePath) {
|
|
2102
|
+
collectionPath = "organizations/" + orgId + "/" + filePath;
|
|
2103
|
+
}
|
|
2100
2104
|
// Validate if file is provided
|
|
2101
2105
|
if (!file) {
|
|
2102
2106
|
return this.sendResponse({
|
|
@@ -2107,10 +2111,11 @@ export const EdgeFirebase = class {
|
|
|
2107
2111
|
}
|
|
2108
2112
|
|
|
2109
2113
|
// Check if the user has write permission to the filePath
|
|
2110
|
-
let hasWritePermission = await this.permissionCheck("write",
|
|
2114
|
+
let hasWritePermission = await this.permissionCheck("write", collectionPath);
|
|
2111
2115
|
if (isPublic) {
|
|
2112
2116
|
hasWritePermission = true;
|
|
2113
2117
|
filePath = "public";
|
|
2118
|
+
collectionPath = "public";
|
|
2114
2119
|
}
|
|
2115
2120
|
if (!hasWritePermission) {
|
|
2116
2121
|
return this.sendResponse({
|
|
@@ -2121,17 +2126,44 @@ export const EdgeFirebase = class {
|
|
|
2121
2126
|
}
|
|
2122
2127
|
|
|
2123
2128
|
try {
|
|
2124
|
-
|
|
2129
|
+
const fileDoc = {
|
|
2130
|
+
orgId,
|
|
2131
|
+
uploadCompleted: false,
|
|
2132
|
+
uploadCompletedToR2: false,
|
|
2133
|
+
fileName: file.name,
|
|
2134
|
+
name: file.name,
|
|
2135
|
+
fileSize: file.size,
|
|
2136
|
+
fileType: file.type,
|
|
2137
|
+
directory: filePath,
|
|
2138
|
+
filePath: '',
|
|
2139
|
+
r2filePath: '',
|
|
2140
|
+
r2URL: '',
|
|
2141
|
+
isPublic: isPublic,
|
|
2142
|
+
toR2: toR2,
|
|
2143
|
+
};
|
|
2144
|
+
|
|
2145
|
+
const result: any = await this.runFunction("edgeFirebase-addUpdateFileDoc", fileDoc);
|
|
2146
|
+
const fileDocId = (result.data as { docId: string }).docId;
|
|
2147
|
+
let tempFilePath = `${collectionPath.replaceAll('/', '-')}` + '/' + fileDocId + '-' + file.name;
|
|
2125
2148
|
if (isPublic) {
|
|
2126
|
-
|
|
2149
|
+
tempFilePath = `${collectionPath.replaceAll('/', '-')}` + '/' + orgId + '-' + fileDocId + '-' + file.name;
|
|
2127
2150
|
}
|
|
2128
|
-
|
|
2151
|
+
await this.runFunction("edgeFirebase-addUpdateFileDoc", {orgId, docId: fileDocId, filePath: tempFilePath });
|
|
2129
2152
|
const storage = getStorage();
|
|
2130
2153
|
const fileRef = ref(storage, tempFilePath);
|
|
2131
2154
|
|
|
2132
2155
|
const metadata = {
|
|
2133
|
-
contentType: file.type,
|
|
2134
2156
|
cacheControl: isPublic ? 'public, max-age=31536000' : undefined,
|
|
2157
|
+
customMetadata: {
|
|
2158
|
+
orgId,
|
|
2159
|
+
uid: this.user.uid,
|
|
2160
|
+
contentType: file.type,
|
|
2161
|
+
fileName: file.name,
|
|
2162
|
+
fileDocId: fileDocId,
|
|
2163
|
+
filePath: tempFilePath,
|
|
2164
|
+
toR2: toR2 ? 'true' : '',
|
|
2165
|
+
isPublic: isPublic ? 'true' : ''
|
|
2166
|
+
}
|
|
2135
2167
|
};
|
|
2136
2168
|
|
|
2137
2169
|
// Resumable upload
|
|
@@ -2143,14 +2175,14 @@ export const EdgeFirebase = class {
|
|
|
2143
2175
|
(snapshot) => {
|
|
2144
2176
|
// Progress, pause, and resume events
|
|
2145
2177
|
const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
|
|
2146
|
-
|
|
2178
|
+
this.state.currentUploadProgress = progress;
|
|
2147
2179
|
},
|
|
2148
2180
|
(error) => {
|
|
2149
2181
|
// Handle unsuccessful uploads
|
|
2150
2182
|
reject(this.sendResponse({
|
|
2151
2183
|
success: false,
|
|
2152
2184
|
message: "An error occurred during file upload.",
|
|
2153
|
-
meta: { error: error.message }
|
|
2185
|
+
meta: { error: error.message, fileDocId}
|
|
2154
2186
|
}));
|
|
2155
2187
|
},
|
|
2156
2188
|
() => {
|
|
@@ -2158,13 +2190,16 @@ export const EdgeFirebase = class {
|
|
|
2158
2190
|
resolve(this.sendResponse({
|
|
2159
2191
|
success: true,
|
|
2160
2192
|
message: "File uploaded successfully.",
|
|
2161
|
-
meta: { file: tempFilePath }
|
|
2193
|
+
meta: { file: tempFilePath, fileDocId }
|
|
2162
2194
|
}));
|
|
2163
2195
|
}
|
|
2164
2196
|
);
|
|
2165
2197
|
});
|
|
2166
|
-
|
|
2167
|
-
|
|
2198
|
+
|
|
2199
|
+
|
|
2200
|
+
const uploadStatus = await uploadPromise;
|
|
2201
|
+
await this.runFunction("edgeFirebase-addUpdateFileDoc", {orgId, docId: fileDocId, uploadStatus, uploadCompleted: true });
|
|
2202
|
+
return uploadStatus;
|
|
2168
2203
|
|
|
2169
2204
|
} catch (error) {
|
|
2170
2205
|
return this.sendResponse({
|
|
@@ -2191,11 +2226,11 @@ export const EdgeFirebase = class {
|
|
|
2191
2226
|
try {
|
|
2192
2227
|
const fileRef = ref(this.storage, filePath);
|
|
2193
2228
|
await deleteObject(fileRef);
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2229
|
+
this.sendResponse({
|
|
2230
|
+
success: true,
|
|
2231
|
+
message: "File deleted successfully.",
|
|
2232
|
+
meta: {}
|
|
2233
|
+
});
|
|
2199
2234
|
} catch (error) {
|
|
2200
2235
|
return this.sendResponse({
|
|
2201
2236
|
success: false,
|
package/package.json
CHANGED
package/src/.env.dev
CHANGED
|
@@ -4,4 +4,13 @@ STRIPE_RETURN_URL=
|
|
|
4
4
|
OPENAI_API_KEY=
|
|
5
5
|
TWILIO_SID=
|
|
6
6
|
TWILIO_AUTH_TOKEN=
|
|
7
|
-
TWILIO_SYSTEM_NUMBER=
|
|
7
|
+
TWILIO_SYSTEM_NUMBER=
|
|
8
|
+
FIREBASE_STORAGE_BUCKET=
|
|
9
|
+
FIREBASE_STORAGE_BUCKET_REGION=
|
|
10
|
+
FIREBASE_STORAGE_BUCKET=
|
|
11
|
+
FIREBASE_STORAGE_BUCKET_REGION=
|
|
12
|
+
CLOUDFLARE_R2_PUBLIC_URL=
|
|
13
|
+
CLOUDFLARE_R2_ENDPOINT=
|
|
14
|
+
CLOUDFLARE_R2_ACCESS_KEY_ID=
|
|
15
|
+
CLOUDFLARE_R2_SECRET_ACCESS_KEY=
|
|
16
|
+
CLOUDFLARE_R2_BUCKET_NAME=
|
package/src/.env.prod
CHANGED
|
@@ -4,4 +4,13 @@ STRIPE_RETURN_URL=
|
|
|
4
4
|
OPENAI_API_KEY=
|
|
5
5
|
TWILIO_SID=
|
|
6
6
|
TWILIO_AUTH_TOKEN=
|
|
7
|
-
TWILIO_SYSTEM_NUMBER=
|
|
7
|
+
TWILIO_SYSTEM_NUMBER=
|
|
8
|
+
FIREBASE_STORAGE_BUCKET=
|
|
9
|
+
FIREBASE_STORAGE_BUCKET_REGION=
|
|
10
|
+
FIREBASE_STORAGE_BUCKET=
|
|
11
|
+
FIREBASE_STORAGE_BUCKET_REGION=
|
|
12
|
+
CLOUDFLARE_R2_PUBLIC_URL=
|
|
13
|
+
CLOUDFLARE_R2_ENDPOINT=
|
|
14
|
+
CLOUDFLARE_R2_ACCESS_KEY_ID=
|
|
15
|
+
CLOUDFLARE_R2_SECRET_ACCESS_KEY=
|
|
16
|
+
CLOUDFLARE_R2_BUCKET_NAME=
|
package/src/config.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
2
|
-
/* eslint-disable no-undef */
|
|
3
1
|
const functions = require('firebase-functions')
|
|
4
2
|
const { PubSub } = require('@google-cloud/pubsub')
|
|
5
3
|
const admin = require('firebase-admin')
|
|
@@ -13,6 +11,7 @@ const { onMessagePublished } = require('firebase-functions/v2/pubsub')
|
|
|
13
11
|
const { onCall, HttpsError, onRequest } = require('firebase-functions/v2/https')
|
|
14
12
|
const { onSchedule } = require('firebase-functions/v2/scheduler')
|
|
15
13
|
const { Storage } = require('@google-cloud/storage')
|
|
14
|
+
const { onObjectFinalized, onObjectDeleted } = require('firebase-functions/v2/storage')
|
|
16
15
|
const {
|
|
17
16
|
onDocumentWritten,
|
|
18
17
|
onDocumentCreated,
|
|
@@ -22,18 +21,18 @@ const {
|
|
|
22
21
|
FirestoreEvent,
|
|
23
22
|
} = require('firebase-functions/v2/firestore')
|
|
24
23
|
const { logger } = require('firebase-functions/v2')
|
|
25
|
-
const { getFirestore } = require('firebase-admin/firestore')
|
|
24
|
+
const { Firestore, getFirestore } = require('firebase-admin/firestore')
|
|
26
25
|
const twilio = require('twilio')
|
|
27
26
|
const db = getFirestore()
|
|
28
27
|
|
|
29
28
|
// The permissionCheck function
|
|
30
29
|
|
|
31
30
|
const permissions = {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
31
|
+
admin: { assign: true, delete: true, read: true, write: true },
|
|
32
|
+
editor: { assign: false, delete: true, read: true, write: true },
|
|
33
|
+
user: { assign: false, delete: false, read: true, write: false },
|
|
34
|
+
writer: { assign: false, delete: false, read: true, write: true },
|
|
35
|
+
}
|
|
37
36
|
|
|
38
37
|
const permissionCheck = async (userId, action, originalFilePath) => {
|
|
39
38
|
// Fetch user document
|
|
@@ -52,16 +51,17 @@ const permissionCheck = async (userId, action, originalFilePath) => {
|
|
|
52
51
|
// Check if the role's collectionPath is a prefix of the collectionPath
|
|
53
52
|
if (collectionPath.startsWith(role.collectionPath)) {
|
|
54
53
|
// Use permissions object instead of fetching collection data
|
|
55
|
-
const rolePermissions = permissions[role.role]
|
|
54
|
+
const rolePermissions = permissions[role.role]
|
|
56
55
|
if (rolePermissions && rolePermissions[action]) {
|
|
57
|
-
return true
|
|
56
|
+
return true
|
|
58
57
|
}
|
|
59
58
|
}
|
|
60
59
|
}
|
|
61
|
-
return false
|
|
60
|
+
return false
|
|
62
61
|
}
|
|
63
62
|
|
|
64
63
|
module.exports = {
|
|
64
|
+
Firestore,
|
|
65
65
|
pubsub,
|
|
66
66
|
onMessagePublished,
|
|
67
67
|
onRequest,
|
|
@@ -82,6 +82,6 @@ module.exports = {
|
|
|
82
82
|
db,
|
|
83
83
|
Storage,
|
|
84
84
|
permissionCheck,
|
|
85
|
+
onObjectFinalized,
|
|
86
|
+
onObjectDeleted,
|
|
85
87
|
}
|
|
86
|
-
|
|
87
|
-
|
package/src/edgeFirebase.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const { onCall, HttpsError, logger, getFirestore, functions, admin, twilio, db, onSchedule, onDocumentUpdated, pubsub, Storage, permissionCheck } = require('./config.js')
|
|
1
|
+
const AWS = require('aws-sdk')
|
|
2
|
+
const { onCall, HttpsError, logger, getFirestore, functions, admin, twilio, db, onSchedule, onDocumentUpdated, pubsub, Storage, permissionCheck, onObjectFinalized, onObjectDeleted, onDocumentDeleted } = require('./config.js')
|
|
4
3
|
|
|
5
4
|
const authToken = process.env.TWILIO_AUTH_TOKEN
|
|
6
5
|
const accountSid = process.env.TWILIO_SID
|
|
@@ -13,6 +12,153 @@ function formatPhoneNumber(phone) {
|
|
|
13
12
|
return `+1${numericPhone}`
|
|
14
13
|
}
|
|
15
14
|
|
|
15
|
+
exports.uploadDocumentDeleted = onDocumentDeleted(
|
|
16
|
+
{ document: 'organizations/{orgId}/files/{docId}', timeoutSeconds: 180 },
|
|
17
|
+
async (event) => {
|
|
18
|
+
const fileData = event.data.data()
|
|
19
|
+
const filePath = fileData.filePath
|
|
20
|
+
// Check if the file exists in the bucket
|
|
21
|
+
const bucket = admin.storage().bucket()
|
|
22
|
+
const [exists] = await bucket.file(filePath).exists()
|
|
23
|
+
if (exists) {
|
|
24
|
+
// Delete the file if it exists
|
|
25
|
+
await bucket.file(filePath).delete()
|
|
26
|
+
console.log(`File deleted: ${filePath}`)
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
console.log(`File not found: ${filePath}`)
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
exports.addUpdateFileDoc = onCall(async (request) => {
|
|
35
|
+
const data = request.data
|
|
36
|
+
const auth = request.auth
|
|
37
|
+
let docId = data?.docId
|
|
38
|
+
if (data.uid === auth.uid) {
|
|
39
|
+
console.log(data)
|
|
40
|
+
const orgId = data.orgId
|
|
41
|
+
if (docId) {
|
|
42
|
+
const docRef = db.collection(`organizations/${orgId}/files`).doc(docId)
|
|
43
|
+
await docRef.set(data, { merge: true })
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
const docRef = db.collection(`organizations/${orgId}/files`).doc()
|
|
47
|
+
await docRef.set(data)
|
|
48
|
+
docId = docRef.id
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
console.log(docId)
|
|
52
|
+
return { docId }
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
const deleteR2File = async (filePath) => {
|
|
56
|
+
const r2 = new AWS.S3({
|
|
57
|
+
endpoint: process.env.CLOUDFLARE_R2_ENDPOINT, // e.g., "https://<account-id>.r2.cloudflarestorage.com"
|
|
58
|
+
accessKeyId: process.env.CLOUDFLARE_R2_ACCESS_KEY_ID,
|
|
59
|
+
secretAccessKey: process.env.CLOUDFLARE_R2_SECRET_ACCESS_KEY,
|
|
60
|
+
region: 'auto', // Cloudflare R2 uses "auto" for region
|
|
61
|
+
})
|
|
62
|
+
const params = {
|
|
63
|
+
Bucket: 'files',
|
|
64
|
+
Key: filePath,
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
await r2.deleteObject(params).promise()
|
|
68
|
+
console.log(`File deleted from Cloudflare R2: ${filePath}`)
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
console.error('Error deleting file from Cloudflare R2:', error)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
exports.fileDeleted = onObjectDeleted(async (event) => {
|
|
76
|
+
const docId = event.data.metadata?.fileDocId
|
|
77
|
+
const toR2 = event.data.metadata?.toR2
|
|
78
|
+
if (toR2) {
|
|
79
|
+
await deleteR2File(event.data.metadata?.r2FilePath)
|
|
80
|
+
}
|
|
81
|
+
if (docId) {
|
|
82
|
+
const orgId = event.data.metadata?.orgId
|
|
83
|
+
const docRef = db.collection(`organizations/${orgId}/files`).doc(docId)
|
|
84
|
+
const docSnapshot = await docRef.get()
|
|
85
|
+
if (docSnapshot.exists) {
|
|
86
|
+
console.log('Deleting file document:', docId)
|
|
87
|
+
await docRef.delete()
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
console.log('File document not found:', docId)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
exports.toR2 = onObjectFinalized(
|
|
96
|
+
{
|
|
97
|
+
bucket: process.env.FIREBASE_STORAGE_BUCKET,
|
|
98
|
+
region: process.env.FIREBASE_STORAGE_BUCKET_REGION,
|
|
99
|
+
memory: '2GiB',
|
|
100
|
+
cpu: 2,
|
|
101
|
+
timeoutSeconds: 540,
|
|
102
|
+
}, async (event) => {
|
|
103
|
+
const toR2 = event.data.metadata?.toR2
|
|
104
|
+
if (toR2) {
|
|
105
|
+
const r2 = new AWS.S3({
|
|
106
|
+
endpoint: process.env.CLOUDFLARE_R2_ENDPOINT, // e.g., "https://<account-id>.r2.cloudflarestorage.com"
|
|
107
|
+
accessKeyId: process.env.CLOUDFLARE_R2_ACCESS_KEY_ID,
|
|
108
|
+
secretAccessKey: process.env.CLOUDFLARE_R2_SECRET_ACCESS_KEY,
|
|
109
|
+
region: 'auto', // Cloudflare R2 uses "auto" for region
|
|
110
|
+
})
|
|
111
|
+
const fileBucket = event.data.bucket // Storage bucket containing the file.
|
|
112
|
+
const filePath = event.data.name // File path in the bucket.
|
|
113
|
+
const r2FilePath = `${process.env.FIREBASE_STORAGE_BUCKET}/${event.data.metadata?.filePath}`
|
|
114
|
+
const r2URL = `${process.env.CLOUDFLARE_R2_PUBLIC_URL}/${r2FilePath}`
|
|
115
|
+
const fileName = event.data.metadata?.fileName // File name.
|
|
116
|
+
const contentType = event.data.contentType // File content type.
|
|
117
|
+
|
|
118
|
+
// Download file into memory from bucket.
|
|
119
|
+
const bucket = admin.storage().bucket(fileBucket)
|
|
120
|
+
const downloadResponse = await bucket.file(filePath).download()
|
|
121
|
+
const file = downloadResponse[0]
|
|
122
|
+
|
|
123
|
+
// Upload the file to Cloudflare R2.
|
|
124
|
+
const params = {
|
|
125
|
+
Bucket: 'files',
|
|
126
|
+
Key: r2FilePath,
|
|
127
|
+
Body: file,
|
|
128
|
+
ContentType: contentType,
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
await r2.upload(params).promise()
|
|
132
|
+
const fileDocId = event.data.metadata?.fileDocId
|
|
133
|
+
const orgId = event.data.metadata?.orgId
|
|
134
|
+
const docRef = db.collection(`organizations/${orgId}/files`).doc(fileDocId)
|
|
135
|
+
await docRef.set({ r2FilePath, r2URL, uploadCompletedToR2: true }, { merge: true })
|
|
136
|
+
const fileRef = bucket.file(filePath)
|
|
137
|
+
|
|
138
|
+
const blankBuffer = Buffer.from('')
|
|
139
|
+
await fileRef.save(blankBuffer, {
|
|
140
|
+
contentType: 'application/octet-stream',
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
// Step 2: Update metadata with additional fields
|
|
144
|
+
const updatedMetadata = {
|
|
145
|
+
metadata: {
|
|
146
|
+
...event.data.metadata,
|
|
147
|
+
r2FilePath,
|
|
148
|
+
r2URL,
|
|
149
|
+
uploadCompletedToR2: 'true', // Add custom metadata after file save
|
|
150
|
+
},
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
await fileRef.setMetadata(updatedMetadata)
|
|
154
|
+
console.log(`File uploaded to Cloudflare R2: ${fileName}`)
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
console.error('Error uploading file to Cloudflare R2:', error)
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
})
|
|
161
|
+
|
|
16
162
|
exports.topicQueue = onSchedule({ schedule: 'every 1 minutes', timeoutSeconds: 180 }, async (event) => {
|
|
17
163
|
const queuedTopicsRef = db.collection('topic-queue')
|
|
18
164
|
const snapshot = await queuedTopicsRef.get()
|
package/src/package.json
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@google-cloud/pubsub": "^4.9.0",
|
|
18
|
+
"aws-sdk": "^2.1692.0",
|
|
18
19
|
"crypto": "^1.0.1",
|
|
19
20
|
"dotenv": "^16.3.1",
|
|
20
21
|
"exceljs": "^4.4.0",
|
|
@@ -28,6 +29,6 @@
|
|
|
28
29
|
"twilio": "^4.18.0"
|
|
29
30
|
},
|
|
30
31
|
"devDependencies": {
|
|
31
|
-
"firebase-functions-test": "^
|
|
32
|
+
"firebase-functions-test": "^3.4.0"
|
|
32
33
|
}
|
|
33
34
|
}
|
package/src/postinstall.sh
CHANGED
|
@@ -73,4 +73,26 @@ if [ ! -f "$project_root/functions/package.json" ]; then
|
|
|
73
73
|
cd "$project_root/functions"
|
|
74
74
|
npm install --no-audit --silent
|
|
75
75
|
cd "$project_root"
|
|
76
|
-
fi
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
# Upgrade specific npm packages in the functions directory
|
|
79
|
+
cd "$project_root/functions"
|
|
80
|
+
|
|
81
|
+
# List of packages to upgrade
|
|
82
|
+
npm install --save \
|
|
83
|
+
"@google-cloud/pubsub@^4.9.0" \
|
|
84
|
+
"aws-sdk@^2.1692.0" \
|
|
85
|
+
"crypto@^1.0.1" \
|
|
86
|
+
"dotenv@^16.3.1" \
|
|
87
|
+
"exceljs@^4.4.0" \
|
|
88
|
+
"firebase-admin@^13.0.2" \
|
|
89
|
+
"firebase-functions@^6.2.0" \
|
|
90
|
+
"form-data@^4.0.0" \
|
|
91
|
+
"formidable-serverless@^1.1.1" \
|
|
92
|
+
"moment-timezone@^0.5.43" \
|
|
93
|
+
"openai@^4.11.1" \
|
|
94
|
+
"stripe@^13.8.0" \
|
|
95
|
+
"twilio@^4.18.0"
|
|
96
|
+
|
|
97
|
+
# Return to the project root
|
|
98
|
+
cd "$project_root"
|