@@ -4,45 +4,68 @@ import { backupFirestore } from './backup'
44import { checkFirestoreBackupStatus } from './status'
55import { Response } from 'express'
66import { getCollections } from './collections'
7+ import * as functions from 'firebase-functions'
78
8- export type FirestoreBackupOptions = {
9+ export interface FirestoreBackupOptions {
910 bucketsAllowlist ?: string [ ]
1011 projectId : string
1112}
1213
13- export type FirestoreBackupRequestOptions = {
14+ export type FirestoreBackupRequestBody =
15+ | FirestoreBackupRequestBodyComplete
16+ | FirestoreBackupRequestBodySelective
17+
18+ export interface FirestoreBackupRequestBodyBase {
1419 storageId : string
1520 path : string
16- } & (
17- | {
18- mode : 'complete'
19- }
20- | {
21- mode : 'selective'
22- ignoreCollections ?: string [ ]
23- collectionGroups ?: string [ ]
24- }
25- )
21+ }
22+
23+ export interface FirestoreBackupRequestBodyComplete
24+ extends FirestoreBackupRequestBodyBase {
25+ mode : 'complete'
26+ }
27+
28+ export interface FirestoreBackupRequestBodySelective
29+ extends FirestoreBackupRequestBodyBase {
30+ mode : 'selective'
31+ ignoreCollections ?: string [ ]
32+ collectionGroups ?: string [ ]
33+ }
2634
2735export function backupFirestoreMiddleware ( {
2836 bucketsAllowlist,
2937 projectId,
3038} : FirestoreBackupOptions ) {
3139 return asyncMiddleware ( async ( request , response ) => {
32- // TODO: Validate options
33- const options = request . body as FirestoreBackupRequestOptions
40+ // TODO: Validate body
41+ const body = request . body as FirestoreBackupRequestBody
42+
43+ if ( body . mode === 'selective' ) {
44+ functions . logger . info ( 'Requested Firestore backup' , {
45+ // NOTE: Do not ...body here to avoid logging sensitive data
46+ mode : body . mode ,
47+ ignoreCollections : body . ignoreCollections ,
48+ collectionGroups : body . collectionGroups ,
49+ bucketsAllowlist,
50+ projectId,
51+ } )
3452
35- if ( options . mode === 'selective' ) {
3653 // Get all root-level collections
3754 const allCollections = await getCollections ( )
38- const { ignoreCollections, collectionGroups } = options
39- const exportedCollections = ( ignoreCollections
40- ? allCollections . filter ( ( coll ) => ! ignoreCollections . includes ( coll ) )
41- : allCollections
55+ const { ignoreCollections, collectionGroups } = body
56+ const exportedCollections = (
57+ ignoreCollections
58+ ? allCollections . filter ( ( coll ) => ! ignoreCollections . includes ( coll ) )
59+ : allCollections
4260 ) . concat ( collectionGroups || [ ] )
4361
62+ functions . logger . info ( 'Initiating selective Firestore backup' , {
63+ exportedCollections,
64+ ignoreCollections,
65+ } )
66+
4467 // Request selective Firestore backup
45- const id = await backupFirestore ( projectId , exportedCollections , options )
68+ const id = await backupFirestore ( projectId , exportedCollections , body )
4669
4770 if ( id ) {
4871 return respondWithStatus ( response , id , {
@@ -53,8 +76,18 @@ export function backupFirestoreMiddleware({
5376 return respondWithMissingId ( response )
5477 }
5578 } else {
79+ functions . logger . info ( 'Requested Firestore backup' , {
80+ // NOTE: Do not ...body here to avoid logging sensitive data
81+ mode : body . mode ,
82+ bucketsAllowlist,
83+ projectId,
84+ } )
85+
86+ // NOTE: Back-to-back logging here is to reflect the selective backup logging
87+ functions . logger . info ( 'Initiating complete Firestore backup' )
88+
5689 // Request complete Firestore backup
57- const id = await backupFirestore ( projectId , undefined , options )
90+ const id = await backupFirestore ( projectId , undefined , body )
5891
5992 if ( id ) {
6093 return respondWithStatus ( response , id )
@@ -65,15 +98,19 @@ export function backupFirestoreMiddleware({
6598 } )
6699}
67100
68- export type FirestoreCheckBackupStatusRequestOptions = {
101+ export interface FirestoreCheckBackupStatusRequestOptions {
69102 id : string
70103}
71104
72105export function checkFirestoreBackupStatusMiddleware ( ) {
73106 return asyncMiddleware ( async ( request , response ) => {
74- // TODO: Validate options
75- const options = request . query as FirestoreCheckBackupStatusRequestOptions
76- return respondWithStatus ( response , options . id )
107+ // TODO: Validate query
108+ const query =
109+ request . query as unknown as FirestoreCheckBackupStatusRequestOptions
110+
111+ functions . logger . info ( 'Requested Firestore backup status' )
112+
113+ return respondWithStatus ( response , query . id )
77114 } )
78115}
79116
@@ -82,14 +119,22 @@ async function respondWithStatus(
82119 id : string ,
83120 extraData : object = { }
84121) {
122+ functions . logger . info ( 'Checking the backup status' , { id } )
123+
85124 const status = await checkFirestoreBackupStatus ( id )
125+ const state = status . done ? 'completed' : 'pending'
126+
127+ functions . logger . info ( 'Responding with the backup status' , { id, state } )
128+
86129 operationResponse ( response , {
87- state : status . done ? 'completed' : 'pending' ,
130+ state,
88131 data : Object . assign ( { id, status } , extraData ) ,
89132 } )
90133}
91134
92135function respondWithMissingId ( response : Response ) {
136+ functions . logger . info ( 'Responding with missing id error' )
137+
93138 operationResponse ( response , {
94139 state : 'failed' ,
95140 data : {
@@ -101,7 +146,14 @@ function respondWithMissingId(response: Response) {
101146
102147export function getCollectionsMiddleware ( ) {
103148 return asyncMiddleware ( async ( _request , response ) => {
149+ functions . logger . info ( 'Requested Firestore collections' )
150+
104151 const collections = await getCollections ( )
152+
153+ functions . logger . info ( 'Responding with Firestore collections' , {
154+ collections,
155+ } )
156+
105157 response . send ( collections )
106158 } )
107159}
0 commit comments