@progressive-development/pd-provider-firebase-functions 0.3.0 → 0.3.1

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.d.ts CHANGED
@@ -5,5 +5,7 @@ export { requireAuth, requireClaims, requireOwnership } from './auth';
5
5
  export { success, created, handleError } from './response';
6
6
  export { getDb } from './firestore';
7
7
  export { getNextCounter } from './counter';
8
+ export type { TrashItem } from './trash';
9
+ export { moveToTrash, restoreFromTrash, permanentDelete, listTrash, getTrashItem } from './trash';
8
10
  export { logger } from './logger';
9
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAGrC,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,iBAAiB,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAGvG,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAGtE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAG3D,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAGpC,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAG3C,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAGrC,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,iBAAiB,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAGvG,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAGtE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAG3D,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAGpC,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAG3C,YAAY,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,eAAe,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAGlG,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC"}
package/dist/index.js CHANGED
@@ -4,4 +4,5 @@ export { requireAuth, requireClaims, requireOwnership } from './auth.js';
4
4
  export { created, handleError, success } from './response.js';
5
5
  export { getDb } from './firestore.js';
6
6
  export { getNextCounter } from './counter.js';
7
+ export { getTrashItem, listTrash, moveToTrash, permanentDelete, restoreFromTrash } from './trash.js';
7
8
  export { logger } from './logger.js';
@@ -0,0 +1,77 @@
1
+ import { Timestamp } from 'firebase-admin/firestore';
2
+ /**
3
+ * Represents an item in the trash collection.
4
+ * Generic type T is the shape of the original document data.
5
+ */
6
+ export interface TrashItem<T = unknown> {
7
+ /** Auto-generated trash document ID */
8
+ id: string;
9
+ /** Original document ID */
10
+ originalId: string;
11
+ /** Original collection path */
12
+ originalCollection: string;
13
+ /** Object type for filtering (e.g., "djRequest", "event") */
14
+ objectType: string;
15
+ /** When the item was deleted */
16
+ deletedAt: Timestamp;
17
+ /** UID of user who deleted */
18
+ deletedBy: string;
19
+ /** The original document data */
20
+ data: T;
21
+ }
22
+ /**
23
+ * Move a document to trash.
24
+ *
25
+ * Atomically:
26
+ * 1. Reads the original document
27
+ * 2. Creates a trash entry with metadata
28
+ * 3. Deletes the original document
29
+ *
30
+ * @param collection - The collection path (e.g., "djRequests")
31
+ * @param documentId - The document ID to trash
32
+ * @param deletedBy - UID of the user performing the deletion
33
+ * @param objectType - Type identifier for filtering (e.g., "djRequest")
34
+ * @param databaseId - Optional named database
35
+ * @returns The created trash item
36
+ * @throws NotFoundError if document doesn't exist
37
+ */
38
+ export declare function moveToTrash<T = unknown>(collection: string, documentId: string, deletedBy: string, objectType: string, databaseId?: string): Promise<TrashItem<T>>;
39
+ /**
40
+ * Restore a document from trash to its original location.
41
+ *
42
+ * Atomically:
43
+ * 1. Reads the trash entry
44
+ * 2. Recreates the original document
45
+ * 3. Deletes the trash entry
46
+ *
47
+ * @param trashItemId - The trash document ID
48
+ * @param databaseId - Optional named database
49
+ * @throws NotFoundError if trash item doesn't exist
50
+ */
51
+ export declare function restoreFromTrash(trashItemId: string, databaseId?: string): Promise<void>;
52
+ /**
53
+ * Permanently delete a document from trash.
54
+ *
55
+ * @param trashItemId - The trash document ID
56
+ * @param databaseId - Optional named database
57
+ * @throws NotFoundError if trash item doesn't exist
58
+ */
59
+ export declare function permanentDelete(trashItemId: string, databaseId?: string): Promise<void>;
60
+ /**
61
+ * List items in trash, optionally filtered by object type.
62
+ *
63
+ * @param objectType - Optional filter by object type
64
+ * @param limit - Maximum items to return (default: 100)
65
+ * @param databaseId - Optional named database
66
+ * @returns Array of trash items, newest first
67
+ */
68
+ export declare function listTrash<T = unknown>(objectType?: string, limit?: number, databaseId?: string): Promise<TrashItem<T>[]>;
69
+ /**
70
+ * Get a single trash item by ID.
71
+ *
72
+ * @param trashItemId - The trash document ID
73
+ * @param databaseId - Optional named database
74
+ * @returns The trash item or null if not found
75
+ */
76
+ export declare function getTrashItem<T = unknown>(trashItemId: string, databaseId?: string): Promise<TrashItem<T> | null>;
77
+ //# sourceMappingURL=trash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trash.d.ts","sourceRoot":"","sources":["../src/trash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAcrD;;;GAGG;AACH,MAAM,WAAW,SAAS,CAAC,CAAC,GAAG,OAAO;IACpC,uCAAuC;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,2BAA2B;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,+BAA+B;IAC/B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAC;IACnB,gCAAgC;IAChC,SAAS,EAAE,SAAS,CAAC;IACrB,8BAA8B;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,iCAAiC;IACjC,IAAI,EAAE,CAAC,CAAC;CACT;AASD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,WAAW,CAAC,CAAC,GAAG,OAAO,EAC3C,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAmCvB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CAsBf;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CAUf;AAED;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAAC,CAAC,GAAG,OAAO,EACzC,UAAU,CAAC,EAAE,MAAM,EACnB,KAAK,GAAE,MAAY,EACnB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAiBzB;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,CAAC,GAAG,OAAO,EAC5C,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAa9B"}
package/dist/trash.js ADDED
@@ -0,0 +1,80 @@
1
+ import { Timestamp } from 'firebase-admin/firestore';
2
+ import { getDb } from './firestore.js';
3
+ import { NotFoundError } from './errors.js';
4
+
5
+ const TRASH_COLLECTION = "_trash";
6
+ async function moveToTrash(collection, documentId, deletedBy, objectType, databaseId) {
7
+ const db = getDb(databaseId);
8
+ const originalRef = db.collection(collection).doc(documentId);
9
+ const trashRef = db.collection(TRASH_COLLECTION).doc();
10
+ return db.runTransaction(async (transaction) => {
11
+ const originalDoc = await transaction.get(originalRef);
12
+ if (!originalDoc.exists) {
13
+ throw new NotFoundError(`Document ${collection}/${documentId} not found`);
14
+ }
15
+ const originalData = originalDoc.data();
16
+ const trashData = {
17
+ originalId: documentId,
18
+ originalCollection: collection,
19
+ objectType,
20
+ deletedAt: Timestamp.now(),
21
+ deletedBy,
22
+ data: originalData
23
+ };
24
+ transaction.set(trashRef, trashData);
25
+ transaction.delete(originalRef);
26
+ return {
27
+ id: trashRef.id,
28
+ ...trashData
29
+ };
30
+ });
31
+ }
32
+ async function restoreFromTrash(trashItemId, databaseId) {
33
+ const db = getDb(databaseId);
34
+ const trashRef = db.collection(TRASH_COLLECTION).doc(trashItemId);
35
+ await db.runTransaction(async (transaction) => {
36
+ const trashDoc = await transaction.get(trashRef);
37
+ if (!trashDoc.exists) {
38
+ throw new NotFoundError(`Trash item ${trashItemId} not found`);
39
+ }
40
+ const trashData = trashDoc.data();
41
+ const originalRef = db.collection(trashData.originalCollection).doc(trashData.originalId);
42
+ transaction.set(originalRef, trashData.data);
43
+ transaction.delete(trashRef);
44
+ });
45
+ }
46
+ async function permanentDelete(trashItemId, databaseId) {
47
+ const db = getDb(databaseId);
48
+ const trashRef = db.collection(TRASH_COLLECTION).doc(trashItemId);
49
+ const trashDoc = await trashRef.get();
50
+ if (!trashDoc.exists) {
51
+ throw new NotFoundError(`Trash item ${trashItemId} not found`);
52
+ }
53
+ await trashRef.delete();
54
+ }
55
+ async function listTrash(objectType, limit = 100, databaseId) {
56
+ const db = getDb(databaseId);
57
+ let query = db.collection(TRASH_COLLECTION).orderBy("deletedAt", "desc").limit(limit);
58
+ if (objectType) {
59
+ query = query.where("objectType", "==", objectType);
60
+ }
61
+ const snapshot = await query.get();
62
+ return snapshot.docs.map((doc) => ({
63
+ id: doc.id,
64
+ ...doc.data()
65
+ }));
66
+ }
67
+ async function getTrashItem(trashItemId, databaseId) {
68
+ const db = getDb(databaseId);
69
+ const trashRef = db.collection(TRASH_COLLECTION).doc(trashItemId);
70
+ const doc = await trashRef.get();
71
+ if (!doc.exists) {
72
+ return null;
73
+ }
74
+ return {
75
+ id: doc.id,
76
+ ...doc.data()
77
+ };
78
+ }
79
+
80
+ export { getTrashItem, listTrash, moveToTrash, permanentDelete, restoreFromTrash };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@progressive-development/pd-provider-firebase-functions",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Firebase Functions v2 utilities for pd-spa-helper backend",
5
5
  "author": "PD Progressive Development",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -17,6 +17,15 @@
17
17
  "README.md",
18
18
  "LICENSE"
19
19
  ],
20
+ "scripts": {
21
+ "build": "vite build",
22
+ "clean": "rm -rf dist",
23
+ "clean:all": "rm -rf dist node_modules pnpm-lock.yaml",
24
+ "lint": "eslint --ext .ts src --ignore-path ../../.eslintignore && prettier \"**/*.ts\" --check --ignore-path ../../.eslintignore",
25
+ "format": "eslint --ext .ts src --fix --ignore-path ../../.eslintignore && prettier \"**/*.ts\" --write --ignore-path ../../.eslintignore",
26
+ "check": "pnpm run lint && pnpm run build",
27
+ "prepublishOnly": "pnpm run clean && pnpm run build"
28
+ },
20
29
  "dependencies": {
21
30
  "firebase-admin": "^12.6.0",
22
31
  "firebase-functions": "^6.0.0"
@@ -32,13 +41,5 @@
32
41
  "firebase",
33
42
  "functions",
34
43
  "backend"
35
- ],
36
- "scripts": {
37
- "build": "vite build",
38
- "clean": "rm -rf dist",
39
- "clean:all": "rm -rf dist node_modules pnpm-lock.yaml",
40
- "lint": "eslint --ext .ts src --ignore-path ../../.eslintignore && prettier \"**/*.ts\" --check --ignore-path ../../.eslintignore",
41
- "format": "eslint --ext .ts src --fix --ignore-path ../../.eslintignore && prettier \"**/*.ts\" --write --ignore-path ../../.eslintignore",
42
- "check": "pnpm run lint && pnpm run build"
43
- }
44
- }
44
+ ]
45
+ }