@progressive-development/pd-provider-firebase-functions 0.3.5 → 0.4.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/auth-trash.d.ts.map +1 -1
- package/dist/auth-trash.js +31 -11
- package/dist/auth.d.ts.map +1 -1
- package/dist/counter.d.ts.map +1 -1
- package/dist/counter.js +5 -1
- package/dist/import-templates.d.ts +28 -0
- package/dist/import-templates.d.ts.map +1 -0
- package/dist/import-templates.js +113 -0
- package/dist/index.d.ts +7 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/response.d.ts.map +1 -1
- package/dist/response.js +4 -1
- package/dist/script-helpers.d.ts +35 -0
- package/dist/script-helpers.d.ts.map +1 -0
- package/dist/script-helpers.js +52 -0
- package/package.json +1 -1
package/dist/auth-trash.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-trash.d.ts","sourceRoot":"","sources":["../src/auth-trash.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,
|
|
1
|
+
{"version":3,"file":"auth-trash.d.ts","sourceRoot":"","sources":["../src/auth-trash.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,SAAS,CAAC;AAQjB,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,aAAa,CAAC,EAAE,YAAY,GAAG,MAAM,CAAC;IAEtC,8BAA8B;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAoCD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,mBAAmB,CAAC,CAAC,GAAG,OAAO,EACnD,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CA0CvB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,wBAAwB,CAC5C,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,IAAI,CAAC,CAuCf;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,uBAAuB,CAC3C,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,gBAAgB,GACzB,OAAO,CAAC,IAAI,CAAC,CAmCf"}
|
package/dist/auth-trash.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getAuth } from 'firebase-admin/auth';
|
|
2
|
-
import { moveToTrash, getTrashItem,
|
|
2
|
+
import { moveToTrash, getTrashItem, permanentDelete, restoreFromTrash } from './trash.js';
|
|
3
3
|
import { NotFoundError } from './errors.js';
|
|
4
4
|
import { logger } from './logger.js';
|
|
5
5
|
|
|
@@ -11,20 +11,28 @@ function getAuthUidFromTrashItem(trashItem, options) {
|
|
|
11
11
|
const data = trashItem.data;
|
|
12
12
|
const uid = data[source];
|
|
13
13
|
if (typeof uid !== "string" || !uid) {
|
|
14
|
-
throw new Error(
|
|
14
|
+
throw new Error(
|
|
15
|
+
`Auth UID field '${source}' not found or empty in trash item data`
|
|
16
|
+
);
|
|
15
17
|
}
|
|
16
18
|
return uid;
|
|
17
19
|
}
|
|
18
20
|
async function moveToTrashWithAuth(collection, documentId, deletedBy, objectType, options) {
|
|
19
21
|
const authUid = options?.authUidSource === "documentId" || !options?.authUidSource ? documentId : documentId;
|
|
20
|
-
logger.info("Disabling Auth user before trash", {
|
|
22
|
+
logger.info("Disabling Auth user before trash", {
|
|
23
|
+
authUid,
|
|
24
|
+
collection,
|
|
25
|
+
documentId
|
|
26
|
+
});
|
|
21
27
|
try {
|
|
22
28
|
await getAuth().updateUser(authUid, { disabled: true });
|
|
23
29
|
logger.info("Auth user disabled", { authUid });
|
|
24
30
|
} catch (error) {
|
|
25
31
|
const authError = error;
|
|
26
32
|
if (authError.code === "auth/user-not-found") {
|
|
27
|
-
logger.info("Auth user not found, continuing with trash operation", {
|
|
33
|
+
logger.info("Auth user not found, continuing with trash operation", {
|
|
34
|
+
authUid
|
|
35
|
+
});
|
|
28
36
|
} else {
|
|
29
37
|
throw error;
|
|
30
38
|
}
|
|
@@ -56,14 +64,20 @@ async function restoreFromTrashWithAuth(trashItemId, options) {
|
|
|
56
64
|
await restoreFromTrash(trashItemId, options?.databaseId);
|
|
57
65
|
try {
|
|
58
66
|
await getAuth().updateUser(authUid, { disabled: false });
|
|
59
|
-
logger.info("Document restored and Auth user re-enabled", {
|
|
67
|
+
logger.info("Document restored and Auth user re-enabled", {
|
|
68
|
+
trashItemId,
|
|
69
|
+
authUid
|
|
70
|
+
});
|
|
60
71
|
} catch (error) {
|
|
61
72
|
const authError = error;
|
|
62
73
|
if (authError.code === "auth/user-not-found") {
|
|
63
|
-
logger.warn(
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
74
|
+
logger.warn(
|
|
75
|
+
"Document restored but Auth user not found - manual Auth user creation required",
|
|
76
|
+
{
|
|
77
|
+
trashItemId,
|
|
78
|
+
authUid
|
|
79
|
+
}
|
|
80
|
+
);
|
|
67
81
|
} else {
|
|
68
82
|
throw error;
|
|
69
83
|
}
|
|
@@ -82,11 +96,17 @@ async function permanentDeleteWithAuth(trashItemId, options) {
|
|
|
82
96
|
await permanentDelete(trashItemId, options?.databaseId);
|
|
83
97
|
try {
|
|
84
98
|
await getAuth().deleteUser(authUid);
|
|
85
|
-
logger.info("Trash item and Auth user permanently deleted", {
|
|
99
|
+
logger.info("Trash item and Auth user permanently deleted", {
|
|
100
|
+
trashItemId,
|
|
101
|
+
authUid
|
|
102
|
+
});
|
|
86
103
|
} catch (error) {
|
|
87
104
|
const authError = error;
|
|
88
105
|
if (authError.code === "auth/user-not-found") {
|
|
89
|
-
logger.info("Auth user not found, trash item deleted", {
|
|
106
|
+
logger.info("Auth user not found, trash item deleted", {
|
|
107
|
+
trashItemId,
|
|
108
|
+
authUid
|
|
109
|
+
});
|
|
90
110
|
} else {
|
|
91
111
|
throw error;
|
|
92
112
|
}
|
package/dist/auth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAE9D,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAGtC;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,eAAe,GAAG,WAAW,CASjE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,eAAe,EACxB,YAAY,EAAE,MAAM,EAAE,GACrB,WAAW,CAUb;AAED;;GAEG;AACH,wBAAgB,gBAAgB,
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAE9D,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAGtC;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,eAAe,GAAG,WAAW,CASjE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,eAAe,EACxB,YAAY,EAAE,MAAM,EAAE,GACrB,WAAW,CAUb;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,WAAW,EACjB,eAAe,EAAE,MAAM,GACtB,IAAI,CAMN"}
|
package/dist/counter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"counter.d.ts","sourceRoot":"","sources":["../src/counter.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"counter.d.ts","sourceRoot":"","sources":["../src/counter.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC,CAejB"}
|
package/dist/counter.js
CHANGED
|
@@ -8,7 +8,11 @@ async function getNextCounter(counterName, databaseId) {
|
|
|
8
8
|
const doc = await transaction.get(counterRef);
|
|
9
9
|
const current = doc.exists ? doc.data()?.value ?? 0 : 0;
|
|
10
10
|
const next = current + 1;
|
|
11
|
-
transaction.set(
|
|
11
|
+
transaction.set(
|
|
12
|
+
counterRef,
|
|
13
|
+
{ value: next, updatedAt: /* @__PURE__ */ new Date() },
|
|
14
|
+
{ merge: true }
|
|
15
|
+
);
|
|
12
16
|
return next;
|
|
13
17
|
});
|
|
14
18
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reusable Mail Templates Import
|
|
3
|
+
*
|
|
4
|
+
* Imports mail templates from a templates directory into Firestore.
|
|
5
|
+
* Each template consists of three files:
|
|
6
|
+
* - {name}.json — metadata (name, subject)
|
|
7
|
+
* - {name}.html.hbs — HTML template
|
|
8
|
+
* - {name}.txt.hbs — Text template
|
|
9
|
+
*/
|
|
10
|
+
export interface ImportTemplatesConfig {
|
|
11
|
+
/** Path to the mail-templates/ directory */
|
|
12
|
+
templatesDir: string;
|
|
13
|
+
/** Path to the serviceAccountKey.json */
|
|
14
|
+
serviceAccountPath: string;
|
|
15
|
+
/** Optional Firestore named database */
|
|
16
|
+
databaseId?: string;
|
|
17
|
+
/** Optional collection name (default: "emailTemplates") */
|
|
18
|
+
collection?: string;
|
|
19
|
+
/** Optional single template name to import */
|
|
20
|
+
templateFilter?: string;
|
|
21
|
+
/** If true, no writes are performed (default: false) */
|
|
22
|
+
dryRun?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Import mail templates into Firestore.
|
|
26
|
+
*/
|
|
27
|
+
export declare function runImportTemplates(config: ImportTemplatesConfig): Promise<void>;
|
|
28
|
+
//# sourceMappingURL=import-templates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-templates.d.ts","sourceRoot":"","sources":["../src/import-templates.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,MAAM,WAAW,qBAAqB;IACpC,4CAA4C;IAC5C,YAAY,EAAE,MAAM,CAAC;IACrB,yCAAyC;IACzC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,wCAAwC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,wDAAwD;IACxD,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAiDD;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,IAAI,CAAC,CA2Ff"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync } from 'fs';
|
|
2
|
+
import { scriptLog, createScriptContext } from './script-helpers.js';
|
|
3
|
+
|
|
4
|
+
function findTemplates(templatesDir) {
|
|
5
|
+
const files = readdirSync(templatesDir);
|
|
6
|
+
const jsonFiles = files.filter(
|
|
7
|
+
(f) => f.endsWith(".json") && f !== "serviceAccountKey.json"
|
|
8
|
+
);
|
|
9
|
+
return jsonFiles.map((f) => f.replace(".json", ""));
|
|
10
|
+
}
|
|
11
|
+
function loadTemplate(templatesDir, name) {
|
|
12
|
+
const jsonPath = `${templatesDir}/${name}.json`;
|
|
13
|
+
const htmlPath = `${templatesDir}/${name}.html.hbs`;
|
|
14
|
+
const textPath = `${templatesDir}/${name}.txt.hbs`;
|
|
15
|
+
if (!existsSync(jsonPath)) {
|
|
16
|
+
scriptLog(`Metadata not found: ${jsonPath}`, "error");
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
if (!existsSync(htmlPath)) {
|
|
20
|
+
scriptLog(`HTML template not found: ${htmlPath}`, "error");
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
if (!existsSync(textPath)) {
|
|
24
|
+
scriptLog(`Text template not found: ${textPath}`, "error");
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
const metadata = JSON.parse(
|
|
28
|
+
readFileSync(jsonPath, "utf-8")
|
|
29
|
+
);
|
|
30
|
+
const html = readFileSync(htmlPath, "utf-8");
|
|
31
|
+
const text = readFileSync(textPath, "utf-8");
|
|
32
|
+
return { ...metadata, html, text };
|
|
33
|
+
}
|
|
34
|
+
async function runImportTemplates(config) {
|
|
35
|
+
const {
|
|
36
|
+
templatesDir,
|
|
37
|
+
serviceAccountPath,
|
|
38
|
+
databaseId,
|
|
39
|
+
collection = "emailTemplates",
|
|
40
|
+
templateFilter,
|
|
41
|
+
dryRun = false
|
|
42
|
+
} = config;
|
|
43
|
+
if (!existsSync(templatesDir)) {
|
|
44
|
+
scriptLog(`Templates directory not found: ${templatesDir}`, "error");
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
const { db } = createScriptContext({
|
|
48
|
+
title: "Mail Templates Import",
|
|
49
|
+
serviceAccountPath,
|
|
50
|
+
databaseId,
|
|
51
|
+
dryRun
|
|
52
|
+
});
|
|
53
|
+
scriptLog(`Templates dir: ${templatesDir}`);
|
|
54
|
+
scriptLog(`Target collection: ${collection}`);
|
|
55
|
+
let templates = findTemplates(templatesDir);
|
|
56
|
+
if (templateFilter) {
|
|
57
|
+
templates = templates.filter((t) => t === templateFilter);
|
|
58
|
+
if (templates.length === 0) {
|
|
59
|
+
scriptLog(`Template not found: ${templateFilter}`, "error");
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
scriptLog(`Found ${templates.length} template(s): ${templates.join(", ")}`);
|
|
64
|
+
console.log("");
|
|
65
|
+
let successCount = 0;
|
|
66
|
+
let errorCount = 0;
|
|
67
|
+
for (const templateName of templates) {
|
|
68
|
+
const template = loadTemplate(templatesDir, templateName);
|
|
69
|
+
if (!template) {
|
|
70
|
+
errorCount++;
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const docId = `${templateName}Id`;
|
|
74
|
+
console.log(`
|
|
75
|
+
${templateName}`);
|
|
76
|
+
console.log(` Document ID: ${docId}`);
|
|
77
|
+
console.log(` Subject: ${template.subject}`);
|
|
78
|
+
console.log(` HTML: ${template.html.length} chars`);
|
|
79
|
+
console.log(` Text: ${template.text.length} chars`);
|
|
80
|
+
if (!dryRun) {
|
|
81
|
+
try {
|
|
82
|
+
await db.collection(collection).doc(docId).set({
|
|
83
|
+
name: template.name,
|
|
84
|
+
subject: template.subject,
|
|
85
|
+
html: template.html,
|
|
86
|
+
text: template.text,
|
|
87
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
88
|
+
});
|
|
89
|
+
scriptLog(`Imported: ${templateName} -> ${docId}`, "success");
|
|
90
|
+
successCount++;
|
|
91
|
+
} catch (error) {
|
|
92
|
+
scriptLog(`Failed to import ${templateName}: ${error}`, "error");
|
|
93
|
+
errorCount++;
|
|
94
|
+
}
|
|
95
|
+
} else {
|
|
96
|
+
scriptLog(`Would import: ${templateName} -> ${docId}`, "info");
|
|
97
|
+
successCount++;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
console.log("\n" + "-".repeat(50));
|
|
101
|
+
console.log(`
|
|
102
|
+
Summary:`);
|
|
103
|
+
console.log(` Success: ${successCount}`);
|
|
104
|
+
console.log(` Errors: ${errorCount}`);
|
|
105
|
+
if (dryRun) {
|
|
106
|
+
console.log(`
|
|
107
|
+
Run without --dry-run to apply changes.
|
|
108
|
+
`);
|
|
109
|
+
}
|
|
110
|
+
process.exit(errorCount > 0 ? 1 : 0);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export { runImportTemplates };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
export type { ApiResponse, AuthContext } from './types';
|
|
2
2
|
export { StatusCode } from './types';
|
|
3
|
-
export { AppError, ValidationError, UnauthorizedError, ForbiddenError, NotFoundError, ConflictError, EmailAlreadyUsedError, SC_EMAIL_ALREADY_USED } from './errors';
|
|
3
|
+
export { AppError, ValidationError, UnauthorizedError, ForbiddenError, NotFoundError, ConflictError, EmailAlreadyUsedError, SC_EMAIL_ALREADY_USED, } from './errors';
|
|
4
4
|
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
8
|
export type { TrashItem } from './trash';
|
|
9
|
-
export { moveToTrash, restoreFromTrash, permanentDelete, listTrash, getTrashItem } from './trash';
|
|
9
|
+
export { moveToTrash, restoreFromTrash, permanentDelete, listTrash, getTrashItem, } from './trash';
|
|
10
10
|
export type { AuthTrashOptions } from './auth-trash';
|
|
11
|
-
export { moveToTrashWithAuth, restoreFromTrashWithAuth, permanentDeleteWithAuth } from './auth-trash';
|
|
11
|
+
export { moveToTrashWithAuth, restoreFromTrashWithAuth, permanentDeleteWithAuth, } from './auth-trash';
|
|
12
12
|
export { logger } from './logger';
|
|
13
|
+
export type { LogType, ScriptContextConfig, ScriptContext, } from './script-helpers';
|
|
14
|
+
export { scriptLog, initFirebaseAdmin, createScriptContext, } from './script-helpers';
|
|
15
|
+
export type { ImportTemplatesConfig } from './import-templates';
|
|
16
|
+
export { runImportTemplates } from './import-templates';
|
|
13
17
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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,
|
|
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,EACL,QAAQ,EACR,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,aAAa,EACb,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,UAAU,CAAC;AAGlB,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,EACL,WAAW,EACX,gBAAgB,EAChB,eAAe,EACf,SAAS,EACT,YAAY,GACb,MAAM,SAAS,CAAC;AAGjB,YAAY,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EACxB,uBAAuB,GACxB,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGlC,YAAY,EACV,OAAO,EACP,mBAAmB,EACnB,aAAa,GACd,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAG1B,YAAY,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -7,3 +7,5 @@ export { getNextCounter } from './counter.js';
|
|
|
7
7
|
export { getTrashItem, listTrash, moveToTrash, permanentDelete, restoreFromTrash } from './trash.js';
|
|
8
8
|
export { moveToTrashWithAuth, permanentDeleteWithAuth, restoreFromTrashWithAuth } from './auth-trash.js';
|
|
9
9
|
export { logger } from './logger.js';
|
|
10
|
+
export { createScriptContext, initFirebaseAdmin, scriptLog } from './script-helpers.js';
|
|
11
|
+
export { runImportTemplates } from './import-templates.js';
|
package/dist/response.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"response.d.ts","sourceRoot":"","sources":["../src/response.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAc,MAAM,SAAS,CAAC;AAIlD,wBAAgB,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAElD;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAElD;AAED,wBAAgB,WAAW,
|
|
1
|
+
{"version":3,"file":"response.d.ts","sourceRoot":"","sources":["../src/response.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAc,MAAM,SAAS,CAAC;AAIlD,wBAAgB,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAElD;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAElD;AAED,wBAAgB,WAAW,CACzB,KAAK,EAAE,OAAO,GACb,WAAW,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAsB9C"}
|
package/dist/response.js
CHANGED
|
@@ -13,7 +13,10 @@ function handleError(error) {
|
|
|
13
13
|
if (error.statusCode >= 500) {
|
|
14
14
|
logger.error("App error", error);
|
|
15
15
|
} else {
|
|
16
|
-
logger.warn("Request error", {
|
|
16
|
+
logger.warn("Request error", {
|
|
17
|
+
code: error.code,
|
|
18
|
+
message: error.message
|
|
19
|
+
});
|
|
17
20
|
}
|
|
18
21
|
return {
|
|
19
22
|
statusCode: error.statusCode,
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Firestore } from 'firebase-admin/firestore';
|
|
2
|
+
export type LogType = "info" | "success" | "error" | "warn";
|
|
3
|
+
/**
|
|
4
|
+
* Print a prefixed log message to console.
|
|
5
|
+
*/
|
|
6
|
+
export declare function scriptLog(message: string, type?: LogType): void;
|
|
7
|
+
/**
|
|
8
|
+
* Initialize Firebase Admin SDK if not already initialized.
|
|
9
|
+
*/
|
|
10
|
+
export declare function initFirebaseAdmin(serviceAccountPath: string): void;
|
|
11
|
+
export interface ScriptContextConfig {
|
|
12
|
+
/** Script title shown in console header */
|
|
13
|
+
title: string;
|
|
14
|
+
/** Path to serviceAccountKey.json */
|
|
15
|
+
serviceAccountPath: string;
|
|
16
|
+
/** Optional Firestore named database */
|
|
17
|
+
databaseId?: string;
|
|
18
|
+
/** Dry-run mode (default: false) */
|
|
19
|
+
dryRun?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface ScriptContext {
|
|
22
|
+
/** Firestore instance (cached via getDb) */
|
|
23
|
+
db: Firestore;
|
|
24
|
+
/** Whether dry-run mode is active */
|
|
25
|
+
dryRun: boolean;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Set up a script context: validates paths, initializes Firebase,
|
|
29
|
+
* returns a ready-to-use Firestore instance.
|
|
30
|
+
*
|
|
31
|
+
* Prints title, connection info, and dry-run banner.
|
|
32
|
+
* Calls `process.exit(1)` if the service account key is missing.
|
|
33
|
+
*/
|
|
34
|
+
export declare function createScriptContext(config: ScriptContextConfig): ScriptContext;
|
|
35
|
+
//# sourceMappingURL=script-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"script-helpers.d.ts","sourceRoot":"","sources":["../src/script-helpers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAQ1D,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;AAS5D;;GAEG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,OAAgB,GAAG,IAAI,CAEvE;AAMD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAWlE;AAMD,MAAM,WAAW,mBAAmB;IAClC,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,qCAAqC;IACrC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,wCAAwC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oCAAoC;IACpC,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,4CAA4C;IAC5C,EAAE,EAAE,SAAS,CAAC;IACd,qCAAqC;IACrC,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,mBAAmB,GAC1B,aAAa,CA+Bf"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { getApps, initializeApp, cert } from 'firebase-admin/app';
|
|
2
|
+
import { existsSync, readFileSync } from 'fs';
|
|
3
|
+
import { getDb } from './firestore.js';
|
|
4
|
+
|
|
5
|
+
const LOG_PREFIX = {
|
|
6
|
+
info: "i ",
|
|
7
|
+
success: "OK",
|
|
8
|
+
error: "X ",
|
|
9
|
+
warn: "! "
|
|
10
|
+
};
|
|
11
|
+
function scriptLog(message, type = "info") {
|
|
12
|
+
console.log(`${LOG_PREFIX[type]} ${message}`);
|
|
13
|
+
}
|
|
14
|
+
function initFirebaseAdmin(serviceAccountPath) {
|
|
15
|
+
if (getApps().length > 0) return;
|
|
16
|
+
const serviceAccount = JSON.parse(
|
|
17
|
+
readFileSync(serviceAccountPath, "utf-8")
|
|
18
|
+
);
|
|
19
|
+
initializeApp({
|
|
20
|
+
credential: cert(serviceAccount),
|
|
21
|
+
databaseURL: `https://${serviceAccount.projectId}.firebaseio.com`
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
function createScriptContext(config) {
|
|
25
|
+
const { title, serviceAccountPath, databaseId, dryRun = false } = config;
|
|
26
|
+
console.log(`
|
|
27
|
+
${title}
|
|
28
|
+
`);
|
|
29
|
+
console.log("-".repeat(50));
|
|
30
|
+
if (!existsSync(serviceAccountPath)) {
|
|
31
|
+
scriptLog("Service Account Key not found!", "error");
|
|
32
|
+
console.log(`
|
|
33
|
+
Expected: ${serviceAccountPath}`);
|
|
34
|
+
console.log(`
|
|
35
|
+
Download from Firebase Console:`);
|
|
36
|
+
console.log(
|
|
37
|
+
` Project Settings > Service Accounts > Generate new private key
|
|
38
|
+
`
|
|
39
|
+
);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
initFirebaseAdmin(serviceAccountPath);
|
|
43
|
+
const db = getDb(databaseId);
|
|
44
|
+
scriptLog(`Firestore: ${databaseId ?? "(default)"}`);
|
|
45
|
+
if (dryRun) {
|
|
46
|
+
scriptLog("DRY RUN - No changes will be made", "warn");
|
|
47
|
+
}
|
|
48
|
+
console.log("-".repeat(50));
|
|
49
|
+
return { db, dryRun };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export { createScriptContext, initFirebaseAdmin, scriptLog };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@progressive-development/pd-provider-firebase-functions",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.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",
|