@firebase-function-kits/delete-user-data 0.0.1 → 0.0.2-rc.0

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.
Files changed (76) hide show
  1. package/CHANGELOG.md +1 -0
  2. package/README.md +151 -0
  3. package/lib/config.d.ts +22 -0
  4. package/lib/config.d.ts.map +1 -0
  5. package/lib/config.js +86 -0
  6. package/lib/config.js.map +1 -0
  7. package/lib/events.d.ts +18 -0
  8. package/lib/events.d.ts.map +1 -0
  9. package/lib/events.js +71 -0
  10. package/lib/events.js.map +1 -0
  11. package/lib/export-config.d.ts +55 -0
  12. package/lib/export-config.d.ts.map +1 -0
  13. package/lib/export-config.js +56 -0
  14. package/lib/export-config.js.map +1 -0
  15. package/lib/handlers.d.ts +35 -0
  16. package/lib/handlers.d.ts.map +1 -0
  17. package/lib/handlers.js +243 -0
  18. package/lib/handlers.js.map +1 -0
  19. package/lib/helpers.d.ts +19 -0
  20. package/lib/helpers.d.ts.map +1 -0
  21. package/lib/helpers.js +39 -0
  22. package/lib/helpers.js.map +1 -0
  23. package/lib/index.d.ts +6 -0
  24. package/lib/index.d.ts.map +1 -0
  25. package/lib/index.js +112 -0
  26. package/lib/index.js.map +1 -0
  27. package/lib/lib.d.ts +23 -0
  28. package/lib/lib.d.ts.map +1 -0
  29. package/lib/lib.js +38 -0
  30. package/lib/lib.js.map +1 -0
  31. package/lib/logs.d.ts +26 -0
  32. package/lib/logs.d.ts.map +1 -0
  33. package/lib/logs.js +116 -0
  34. package/lib/logs.js.map +1 -0
  35. package/lib/recursiveDelete.d.ts +18 -0
  36. package/lib/recursiveDelete.d.ts.map +1 -0
  37. package/lib/recursiveDelete.js +37 -0
  38. package/lib/recursiveDelete.js.map +1 -0
  39. package/lib/runBatchPubSubDeletions.d.ts +27 -0
  40. package/lib/runBatchPubSubDeletions.d.ts.map +1 -0
  41. package/lib/runBatchPubSubDeletions.js +47 -0
  42. package/lib/runBatchPubSubDeletions.js.map +1 -0
  43. package/lib/runCustomSearchFunction.d.ts +18 -0
  44. package/lib/runCustomSearchFunction.d.ts.map +1 -0
  45. package/lib/runCustomSearchFunction.js +78 -0
  46. package/lib/runCustomSearchFunction.js.map +1 -0
  47. package/lib/search.d.ts +19 -0
  48. package/lib/search.d.ts.map +1 -0
  49. package/lib/search.js +29 -0
  50. package/lib/search.js.map +1 -0
  51. package/package.json +37 -4
  52. package/src/config.ts +98 -0
  53. package/src/events.ts +38 -0
  54. package/src/export-config.ts +112 -0
  55. package/src/handlers.ts +271 -0
  56. package/src/helpers.ts +42 -0
  57. package/src/index.ts +100 -0
  58. package/src/lib.ts +41 -0
  59. package/src/logs.ts +127 -0
  60. package/src/recursiveDelete.ts +42 -0
  61. package/src/runBatchPubSubDeletions.ts +66 -0
  62. package/src/runCustomSearchFunction.ts +50 -0
  63. package/src/search.ts +37 -0
  64. package/tests/config.test.ts +180 -0
  65. package/tests/export-config.test.ts +117 -0
  66. package/tests/fakes.ts +325 -0
  67. package/tests/handlers.test.ts +517 -0
  68. package/tests/helpers.test.ts +126 -0
  69. package/tests/lib.test.ts +40 -0
  70. package/tests/recursiveDelete.test.ts +102 -0
  71. package/tests/runBatchPubSubDeletions.test.ts +164 -0
  72. package/tests/runCustomSearchFunction.test.ts +125 -0
  73. package/tests/search.test.ts +127 -0
  74. package/tsconfig.json +18 -0
  75. package/tsconfig.tsbuildinfo +1 -0
  76. package/index.js +0 -0
package/lib/logs.js ADDED
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright 2019 Google LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * https://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.customFunctionError = exports.storagePathError = exports.storagePath404 = exports.storagePathDeleting = exports.storagePathDeleted = exports.storageNotConfigured = exports.storageDeleting = exports.storageDeleted = exports.start = exports.rtdbPathError = exports.rtdbPathDeleting = exports.rtdbNotConfigured = exports.rtdbPathDeleted = exports.rtdbDeleting = exports.rtdbDeleted = exports.init = exports.firestorePathError = exports.firestorePathDeleting = exports.firestorePathDeleted = exports.firestoreNotConfigured = exports.firestoreDeleting = exports.firestoreDeleted = exports.complete = void 0;
19
+ exports.warnInvalidPaths = warnInvalidPaths;
20
+ const firebase_functions_1 = require("firebase-functions");
21
+ const complete = (uid) => {
22
+ firebase_functions_1.logger.log(`Successfully removed data for user: ${uid}`);
23
+ };
24
+ exports.complete = complete;
25
+ const firestoreDeleted = () => {
26
+ firebase_functions_1.logger.log("Finished deleting user data from Cloud Firestore");
27
+ };
28
+ exports.firestoreDeleted = firestoreDeleted;
29
+ const firestoreDeleting = () => {
30
+ firebase_functions_1.logger.log("Deleting user data from Cloud Firestore");
31
+ };
32
+ exports.firestoreDeleting = firestoreDeleting;
33
+ const firestoreNotConfigured = () => {
34
+ firebase_functions_1.logger.log("Cloud Firestore paths are not configured, skipping");
35
+ };
36
+ exports.firestoreNotConfigured = firestoreNotConfigured;
37
+ const firestorePathDeleted = (path, recursive) => {
38
+ firebase_functions_1.logger.log(`Deleted: '${path}' from Cloud Firestore ${recursive ? "with recursive delete" : ""}`);
39
+ };
40
+ exports.firestorePathDeleted = firestorePathDeleted;
41
+ const firestorePathDeleting = (path, recursive) => {
42
+ firebase_functions_1.logger.log(`Deleting: '${path}' from Cloud Firestore ${recursive ? "with recursive delete" : ""}`);
43
+ };
44
+ exports.firestorePathDeleting = firestorePathDeleting;
45
+ const firestorePathError = (path, err) => {
46
+ firebase_functions_1.logger.error(`Error when deleting: '${path}' from Cloud Firestore`, err);
47
+ };
48
+ exports.firestorePathError = firestorePathError;
49
+ const init = (config) => {
50
+ firebase_functions_1.logger.log("Initializing extension with configuration", config);
51
+ };
52
+ exports.init = init;
53
+ const rtdbDeleted = () => {
54
+ firebase_functions_1.logger.log("Finished deleting user data from the Realtime Database");
55
+ };
56
+ exports.rtdbDeleted = rtdbDeleted;
57
+ const rtdbDeleting = () => {
58
+ firebase_functions_1.logger.log("Deleting user data from the Realtime Database");
59
+ };
60
+ exports.rtdbDeleting = rtdbDeleting;
61
+ const rtdbPathDeleted = (path) => {
62
+ firebase_functions_1.logger.log(`Deleted: '${path}' from the Realtime Database`);
63
+ };
64
+ exports.rtdbPathDeleted = rtdbPathDeleted;
65
+ const rtdbNotConfigured = () => {
66
+ firebase_functions_1.logger.log("Realtime Database paths are not configured, skipping");
67
+ };
68
+ exports.rtdbNotConfigured = rtdbNotConfigured;
69
+ const rtdbPathDeleting = (path) => {
70
+ firebase_functions_1.logger.log(`Deleting: '${path}' from the Realtime Database`);
71
+ };
72
+ exports.rtdbPathDeleting = rtdbPathDeleting;
73
+ const rtdbPathError = (path, err) => {
74
+ firebase_functions_1.logger.error(`Error when deleting: '${path}' from the Realtime Database`, err);
75
+ };
76
+ exports.rtdbPathError = rtdbPathError;
77
+ const start = (config) => {
78
+ firebase_functions_1.logger.log("Started extension execution with configuration", config);
79
+ };
80
+ exports.start = start;
81
+ const storageDeleted = () => {
82
+ firebase_functions_1.logger.log("Finished deleting user data from Cloud Storage");
83
+ };
84
+ exports.storageDeleted = storageDeleted;
85
+ const storageDeleting = () => {
86
+ firebase_functions_1.logger.log("Deleting user data from Cloud Storage");
87
+ };
88
+ exports.storageDeleting = storageDeleting;
89
+ const storageNotConfigured = () => {
90
+ firebase_functions_1.logger.log("Cloud Storage paths are not configured, skipping");
91
+ };
92
+ exports.storageNotConfigured = storageNotConfigured;
93
+ const storagePathDeleted = (path) => {
94
+ firebase_functions_1.logger.log(`Deleted: '${path}' from Cloud Storage`);
95
+ };
96
+ exports.storagePathDeleted = storagePathDeleted;
97
+ const storagePathDeleting = (path) => {
98
+ firebase_functions_1.logger.log(`Deleting: '${path}' from Cloud Storage`);
99
+ };
100
+ exports.storagePathDeleting = storagePathDeleting;
101
+ const storagePath404 = (path) => {
102
+ firebase_functions_1.logger.log(`File: '${path}' does not exist in Cloud Storage, skipping`);
103
+ };
104
+ exports.storagePath404 = storagePath404;
105
+ const storagePathError = (path, err) => {
106
+ firebase_functions_1.logger.error(`Error deleting: '${path}' from Cloud Storage`, err);
107
+ };
108
+ exports.storagePathError = storagePathError;
109
+ const customFunctionError = (err) => {
110
+ firebase_functions_1.logger.error(`Call to custom hook function threw an error`, err);
111
+ };
112
+ exports.customFunctionError = customFunctionError;
113
+ function warnInvalidPaths(invalidPathCount, uid) {
114
+ firebase_functions_1.logger.warn(`Attempted to delete ${invalidPathCount} invalid paths for deleted user ${uid}`);
115
+ }
116
+ //# sourceMappingURL=logs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs.js","sourceRoot":"","sources":["../src/logs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Copyright 2026 Google LLC
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * https://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import type * as admin from "firebase-admin";
17
+ export declare const recursiveDelete: (path: string, db: admin.firestore.Firestore) => Promise<void>;
18
+ //# sourceMappingURL=recursiveDelete.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recursiveDelete.d.ts","sourceRoot":"","sources":["../src/recursiveDelete.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,KAAK,KAAK,MAAM,gBAAgB,CAAC;AAI7C,eAAO,MAAM,eAAe,SACpB,MAAM,MACR,KAAK,CAAC,SAAS,CAAC,SAAS,kBAmB9B,CAAC"}
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright 2026 Google LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * https://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.recursiveDelete = void 0;
19
+ const MAX_RETRY_ATTEMPTS = 3;
20
+ const recursiveDelete = async (path, db) => {
21
+ // Recursively delete a reference and log the references of failures.
22
+ const bulkWriter = db.bulkWriter();
23
+ bulkWriter.onWriteError((error) => {
24
+ if (error.failedAttempts < MAX_RETRY_ATTEMPTS) {
25
+ return true;
26
+ }
27
+ else {
28
+ console.warn("Failed to delete document: ", error.documentRef.path);
29
+ return false;
30
+ }
31
+ });
32
+ const isDocument = path.split("/").length % 2 === 0;
33
+ const reference = isDocument ? db.doc(path) : db.collection(path);
34
+ await db.recursiveDelete(reference, bulkWriter);
35
+ };
36
+ exports.recursiveDelete = recursiveDelete;
37
+ //# sourceMappingURL=recursiveDelete.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recursiveDelete.js","sourceRoot":"","sources":["../src/recursiveDelete.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;AAIH,MAAM,kBAAkB,GAAG,CAAC,CAAC;AAEtB,MAAM,eAAe,GAAG,KAAK,EAClC,IAAY,EACZ,EAA6B,EAC7B,EAAE;IACF,qEAAqE;IACrE,MAAM,UAAU,GAAG,EAAE,CAAC,UAAU,EAAE,CAAC;IAEnC,UAAU,CAAC,YAAY,CAAC,CAAC,KAAK,EAAE,EAAE;QAChC,IAAI,KAAK,CAAC,cAAc,GAAG,kBAAkB,EAAE,CAAC;YAC9C,OAAO,IAAI,CAAC;QACd,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,IAAI,CAAC,6BAA6B,EAAE,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;YACpE,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC;IAEpD,MAAM,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IAElE,MAAM,EAAE,CAAC,eAAe,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;AAClD,CAAC,CAAC;AArBW,QAAA,eAAe,GAAf,eAAe,CAqB1B"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Copyright 2026 Google LLC
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * https://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import type { PubSub } from "@google-cloud/pubsub";
17
+ import type { ResolvedDeleteUserDataConfig } from "./export-config";
18
+ export interface DeletionPaths {
19
+ firestorePaths: string[];
20
+ }
21
+ export interface PublisherContext {
22
+ pubsub: PubSub;
23
+ config: ResolvedDeleteUserDataConfig;
24
+ }
25
+ export declare function publishSearch(uid: string, depth: number, path: string, ctx: PublisherContext): Promise<void>;
26
+ export declare function runBatchPubSubDeletions(paths: DeletionPaths, uid: string, ctx: PublisherContext): Promise<void>;
27
+ //# sourceMappingURL=runBatchPubSubDeletions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runBatchPubSubDeletions.d.ts","sourceRoot":"","sources":["../src/runBatchPubSubDeletions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,iBAAiB,CAAC;AAEpE,MAAM,WAAW,aAAa;IAC5B,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,4BAA4B,CAAC;CACtC;AAaD,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,gBAAgB,GACpB,OAAO,CAAC,IAAI,CAAC,CAIf;AAED,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,aAAa,EACpB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,gBAAgB,GACpB,OAAO,CAAC,IAAI,CAAC,CAUf"}
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright 2026 Google LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * https://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ var __importDefault = (this && this.__importDefault) || function (mod) {
18
+ return (mod && mod.__esModule) ? mod : { "default": mod };
19
+ };
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.publishSearch = publishSearch;
22
+ exports.runBatchPubSubDeletions = runBatchPubSubDeletions;
23
+ const lodash_chunk_1 = __importDefault(require("lodash.chunk"));
24
+ function topicPath(config, topicName) {
25
+ const projectId = config.projectId ??
26
+ process.env.GOOGLE_CLOUD_PROJECT ??
27
+ process.env.PROJECT_ID;
28
+ return projectId ? `projects/${projectId}/topics/${topicName}` : topicName;
29
+ }
30
+ async function publishSearch(uid, depth, path, ctx) {
31
+ await ctx.pubsub
32
+ .topic(topicPath(ctx.config, ctx.config.discoveryTopicName))
33
+ .publishMessage({ json: { path, uid, depth } });
34
+ }
35
+ async function runBatchPubSubDeletions(paths, uid, ctx) {
36
+ const { firestorePaths } = paths;
37
+ if (!firestorePaths || !Array.isArray(firestorePaths))
38
+ return;
39
+ if (firestorePaths.length === 0)
40
+ return;
41
+ for (const chunkedPaths of (0, lodash_chunk_1.default)(firestorePaths, 450)) {
42
+ await ctx.pubsub
43
+ .topic(topicPath(ctx.config, ctx.config.deletionTopicName))
44
+ .publishMessage({ json: { paths: chunkedPaths, uid } });
45
+ }
46
+ }
47
+ //# sourceMappingURL=runBatchPubSubDeletions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runBatchPubSubDeletions.js","sourceRoot":"","sources":["../src/runBatchPubSubDeletions.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;;;;;AAGH,gEAAiC;AAYjC,SAAS,SAAS,CAChB,MAAoC,EACpC,SAAiB;IAEjB,MAAM,SAAS,GACb,MAAM,CAAC,SAAS;QAChB,OAAO,CAAC,GAAG,CAAC,oBAAoB;QAChC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;IACzB,OAAO,SAAS,CAAC,CAAC,CAAC,YAAY,SAAS,WAAW,SAAS,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAC7E,CAAC;AAEM,KAAK,wBACV,GAAW,EACX,KAAa,EACb,IAAY,EACZ,GAAqB;IAErB,MAAM,GAAG,CAAC,MAAM;SACb,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;SAC3D,cAAc,CAAC,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;AACpD,CAAC;AAEM,KAAK,kCACV,KAAoB,EACpB,GAAW,EACX,GAAqB;IAErB,MAAM,EAAE,cAAc,EAAE,GAAG,KAAK,CAAC;IACjC,IAAI,CAAC,cAAc,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC;QAAE,OAAO;IAC9D,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAExC,KAAK,MAAM,YAAY,IAAI,IAAA,sBAAK,EAAS,cAAc,EAAE,GAAG,CAAC,EAAE,CAAC;QAC9D,MAAM,GAAG,CAAC,MAAM;aACb,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;aAC1D,cAAc,CAAC,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;IAC5D,CAAC;AACH,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Copyright 2026 Google LLC
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * https://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import type { PublisherContext } from "./runBatchPubSubDeletions";
17
+ export declare const runCustomSearchFunction: (uid: string, ctx: PublisherContext) => Promise<void>;
18
+ //# sourceMappingURL=runCustomSearchFunction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runCustomSearchFunction.d.ts","sourceRoot":"","sources":["../src/runCustomSearchFunction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAGlE,eAAO,MAAM,uBAAuB,QAC7B,MAAM,OACN,gBAAgB,KACpB,OAAO,CAAC,IAAI,CAyBd,CAAC"}
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright 2026 Google LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * https://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
18
+ if (k2 === undefined) k2 = k;
19
+ var desc = Object.getOwnPropertyDescriptor(m, k);
20
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
21
+ desc = { enumerable: true, get: function() { return m[k]; } };
22
+ }
23
+ Object.defineProperty(o, k2, desc);
24
+ }) : (function(o, m, k, k2) {
25
+ if (k2 === undefined) k2 = k;
26
+ o[k2] = m[k];
27
+ }));
28
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
29
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
30
+ }) : function(o, v) {
31
+ o["default"] = v;
32
+ });
33
+ var __importStar = (this && this.__importStar) || (function () {
34
+ var ownKeys = function(o) {
35
+ ownKeys = Object.getOwnPropertyNames || function (o) {
36
+ var ar = [];
37
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
38
+ return ar;
39
+ };
40
+ return ownKeys(o);
41
+ };
42
+ return function (mod) {
43
+ if (mod && mod.__esModule) return mod;
44
+ var result = {};
45
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
46
+ __setModuleDefault(result, mod);
47
+ return result;
48
+ };
49
+ })();
50
+ var __importDefault = (this && this.__importDefault) || function (mod) {
51
+ return (mod && mod.__esModule) ? mod : { "default": mod };
52
+ };
53
+ Object.defineProperty(exports, "__esModule", { value: true });
54
+ exports.runCustomSearchFunction = void 0;
55
+ const node_fetch_1 = __importDefault(require("node-fetch"));
56
+ const logs = __importStar(require("./logs"));
57
+ const runBatchPubSubDeletions_1 = require("./runBatchPubSubDeletions");
58
+ const runCustomSearchFunction = async (uid, ctx) => {
59
+ if (!ctx.config.searchFunction)
60
+ return;
61
+ const response = await (0, node_fetch_1.default)(ctx.config.searchFunction, {
62
+ method: "POST",
63
+ body: JSON.stringify({ uid }),
64
+ headers: { "Content-Type": "application/json" },
65
+ });
66
+ if (!response.ok) {
67
+ const body = await response.text();
68
+ logs.customFunctionError(new Error(body));
69
+ return;
70
+ }
71
+ const json = await response.json();
72
+ if (Array.isArray(json)) {
73
+ return (0, runBatchPubSubDeletions_1.runBatchPubSubDeletions)({ firestorePaths: json }, uid, ctx);
74
+ }
75
+ return (0, runBatchPubSubDeletions_1.runBatchPubSubDeletions)(json, uid, ctx);
76
+ };
77
+ exports.runCustomSearchFunction = runCustomSearchFunction;
78
+ //# sourceMappingURL=runCustomSearchFunction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runCustomSearchFunction.js","sourceRoot":"","sources":["../src/runCustomSearchFunction.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,4DAA+B;AAC/B,MAAY,IAAI,mCAAe;AAE/B,uEAAoE;AAE7D,MAAM,uBAAuB,GAAG,KAAK,EAC1C,GAAW,EACX,GAAqB,EACN,EAAE;IACjB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,cAAc;QAAE,OAAO;IAEvC,MAAM,QAAQ,GAAG,MAAM,IAAA,oBAAK,EAAC,GAAG,CAAC,MAAM,CAAC,cAAc,EAAE;QACtD,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,CAAC;QAC7B,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;KAChD,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnC,IAAI,CAAC,mBAAmB,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QAC1C,OAAO;IACT,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IACnC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,OAAO,IAAA,iDAAuB,EAAC,EAAE,cAAc,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IACrE,CAAC;IAED,OAAO,IAAA,iDAAuB,EAC5B,IAAoC,EACpC,GAAG,EACH,GAAG,CACJ,CAAC;AACJ,CAAC,CAAC;AA5BW,QAAA,uBAAuB,GAAvB,uBAAuB,CA4BlC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Copyright 2026 Google LLC
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * https://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import type * as admin from "firebase-admin";
17
+ import { type PublisherContext } from "./runBatchPubSubDeletions";
18
+ export declare const search: (uid: string, depth: number, db: admin.firestore.Firestore, ctx: PublisherContext, document?: admin.firestore.DocumentReference<admin.firestore.DocumentData>) => Promise<void>;
19
+ //# sourceMappingURL=search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,KAAK,KAAK,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EACL,KAAK,gBAAgB,EAEtB,MAAM,2BAA2B,CAAC;AAEnC,eAAO,MAAM,MAAM,QACZ,MAAM,SACJ,MAAM,MACT,KAAK,CAAC,SAAS,CAAC,SAAS,OACxB,gBAAgB,aACV,KAAK,CAAC,SAAS,CAAC,iBAAiB,CAAC,KAAK,CAAC,SAAS,CAAC,YAAY,CAAC,KACzE,OAAO,CAAC,IAAI,CAQd,CAAC"}
package/lib/search.js ADDED
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright 2026 Google LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * https://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.search = void 0;
19
+ const runBatchPubSubDeletions_1 = require("./runBatchPubSubDeletions");
20
+ const search = async (uid, depth, db, ctx, document) => {
21
+ const collections = !document
22
+ ? await db.listCollections()
23
+ : await document.listCollections();
24
+ for (const collection of collections) {
25
+ await (0, runBatchPubSubDeletions_1.publishSearch)(uid, depth, collection.path, ctx);
26
+ }
27
+ };
28
+ exports.search = search;
29
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;AAGH,uEAGmC;AAE5B,MAAM,MAAM,GAAG,KAAK,EACzB,GAAW,EACX,KAAa,EACb,EAA6B,EAC7B,GAAqB,EACrB,QAA0E,EAC3D,EAAE;IACjB,MAAM,WAAW,GAAG,CAAC,QAAQ;QAC3B,CAAC,CAAC,MAAM,EAAE,CAAC,eAAe,EAAE;QAC5B,CAAC,CAAC,MAAM,QAAQ,CAAC,eAAe,EAAE,CAAC;IAErC,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;QACrC,MAAM,IAAA,uCAAa,EAAC,GAAG,EAAE,KAAK,EAAE,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACxD,CAAC;AACH,CAAC,CAAC;AAdW,QAAA,MAAM,GAAN,MAAM,CAcjB"}
package/package.json CHANGED
@@ -1,12 +1,45 @@
1
1
  {
2
2
  "name": "@firebase-function-kits/delete-user-data",
3
- "version": "0.0.1",
3
+ "version": "0.0.2-rc.0",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "https://github.com/firebase/extensions.git",
7
+ "directory": "kits/delete-user-data"
8
+ },
4
9
  "description": "Delete user data across Firestore, RTDB, and Storage on account deletion",
5
10
  "license": "Apache-2.0",
6
- "main": "index.js",
7
- "private": false,
8
- "repository": "firebase/extensions",
11
+ "main": "lib/index.js",
12
+ "types": "lib/index.d.ts",
13
+ "exports": {
14
+ ".": {
15
+ "types": "./lib/index.d.ts",
16
+ "default": "./lib/index.js"
17
+ },
18
+ "./lib": {
19
+ "types": "./lib/lib.d.ts",
20
+ "default": "./lib/lib.js"
21
+ }
22
+ },
9
23
  "engines": {
10
24
  "node": ">=22"
25
+ },
26
+ "scripts": {
27
+ "build": "tsc -b",
28
+ "clean": "tsc -b --clean",
29
+ "test": "vitest run",
30
+ "deploy": "pnpm build && firebase deploy --only functions",
31
+ "serve": "firebase emulators:start --only functions"
32
+ },
33
+ "dependencies": {
34
+ "@google-cloud/pubsub": "^4.3.3",
35
+ "firebase-admin": "^13.2.0",
36
+ "firebase-functions": "7.3.2",
37
+ "lodash.chunk": "^4.2.0",
38
+ "node-fetch": "^2.6.2"
39
+ },
40
+ "devDependencies": {
41
+ "@types/lodash.chunk": "^4.2.7",
42
+ "@types/node-fetch": "^2.6.2",
43
+ "vitest": "^4.1.10"
11
44
  }
12
45
  }
package/src/config.ts ADDED
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Copyright 2026 Google LLC
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * https://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import {
18
+ defineBoolean,
19
+ defineInt,
20
+ defineString,
21
+ expr,
22
+ projectID,
23
+ select,
24
+ storageBucket,
25
+ } from "firebase-functions/params";
26
+ import type { DeleteUserDataConfig } from "./export-config";
27
+
28
+ const instanceId = defineString("INSTANCE_ID");
29
+
30
+ const params = {
31
+ instanceId,
32
+ firestorePaths: defineString("FIRESTORE_PATHS", { default: "" }),
33
+ firestoreDatabaseId: defineString("FIRESTORE_DATABASE_ID", {
34
+ default: "(default)",
35
+ }),
36
+ firestoreDeleteMode: defineString("FIRESTORE_DELETE_MODE", {
37
+ default: "shallow",
38
+ input: select(["recursive", "shallow"]),
39
+ }),
40
+ rtdbInstance: defineString("SELECTED_DATABASE_INSTANCE", { default: "" }),
41
+ rtdbLocation: defineString("SELECTED_DATABASE_LOCATION", {
42
+ default: "us-central1",
43
+ input: select(["us-central1", "europe-west1", "asia-southeast1"]),
44
+ }),
45
+ rtdbPaths: defineString("RTDB_PATHS", { default: "" }),
46
+ storageBucket: defineString("CLOUD_STORAGE_BUCKET", {
47
+ default: storageBucket,
48
+ }),
49
+ storagePaths: defineString("STORAGE_PATHS", { default: "" }),
50
+ enableAutoDiscovery: defineBoolean("ENABLE_AUTO_DISCOVERY", {
51
+ default: false,
52
+ }),
53
+ searchDepth: defineInt("AUTO_DISCOVERY_SEARCH_DEPTH", { default: 3 }),
54
+ searchFields: defineString("AUTO_DISCOVERY_SEARCH_FIELDS", {
55
+ default: "id,uid,userId",
56
+ }),
57
+ searchFunction: defineString("SEARCH_FUNCTION", { default: "" }),
58
+ // Non-empty defaults so Pub/Sub trigger bindings resolve during deploy
59
+ // discovery without freezing an empty topic name into the manifest.
60
+ discoveryTopicName: defineString("DISCOVERY_TOPIC_NAME", {
61
+ default: expr`kit-${instanceId}-discovery`,
62
+ }),
63
+ deletionTopicName: defineString("DELETION_TOPIC_NAME", {
64
+ default: expr`kit-${instanceId}-deletion`,
65
+ }),
66
+ };
67
+
68
+ export const CONFIG_EXPRESSIONS = {
69
+ discoveryTopicName: params.discoveryTopicName,
70
+ deletionTopicName: params.deletionTopicName,
71
+ } as const;
72
+
73
+ function optional(value: string): string | undefined {
74
+ return value.length > 0 ? value : undefined;
75
+ }
76
+
77
+ export function configFromEnv(): DeleteUserDataConfig {
78
+ return {
79
+ firestorePaths: optional(params.firestorePaths.value()),
80
+ firestoreDatabaseId: params.firestoreDatabaseId.value(),
81
+ firestoreDeleteMode:
82
+ params.firestoreDeleteMode.value() as DeleteUserDataConfig["firestoreDeleteMode"],
83
+ rtdbInstance: optional(params.rtdbInstance.value()),
84
+ rtdbLocation: optional(params.rtdbLocation.value()),
85
+ rtdbPaths: optional(params.rtdbPaths.value()),
86
+ storageBucket:
87
+ optional(params.storageBucket.value()) ?? process.env.STORAGE_BUCKET,
88
+ storagePaths: optional(params.storagePaths.value()),
89
+ enableAutoDiscovery: params.enableAutoDiscovery.value(),
90
+ searchDepth: params.searchDepth.value(),
91
+ searchFields: params.searchFields.value(),
92
+ searchFunction: optional(params.searchFunction.value()),
93
+ instanceId: params.instanceId.value(),
94
+ discoveryTopicName: optional(params.discoveryTopicName.value()),
95
+ deletionTopicName: optional(params.deletionTopicName.value()),
96
+ projectId: projectID.value(),
97
+ };
98
+ }
package/src/events.ts ADDED
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Copyright 2026 Google LLC
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * https://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import * as eventArc from "firebase-admin/eventarc";
18
+
19
+ let eventChannel: eventArc.Channel | undefined;
20
+
21
+ export const setupEventChannel = (): void => {
22
+ eventChannel = process.env.EVENTARC_CHANNEL
23
+ ? eventArc.getEventarc().channel(process.env.EVENTARC_CHANNEL, {
24
+ allowedEventTypes: process.env.EXT_SELECTED_EVENTS,
25
+ })
26
+ : undefined;
27
+ };
28
+
29
+ export async function publishDeletionEvent(
30
+ target: "firestore" | "database" | "storage",
31
+ data: object
32
+ ): Promise<unknown> {
33
+ if (!eventChannel) return Promise.resolve();
34
+ return eventChannel.publish({
35
+ type: `firebase.extensions.delete-user-data.v1.${target}`,
36
+ data,
37
+ });
38
+ }