@tern-secure/backend 1.2.0-canary.v20251209193320 → 1.2.0-canary.v20251210182014

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.
@@ -0,0 +1,84 @@
1
+ import type { UserRecord } from 'firebase-admin/auth';
2
+ import * as functions from 'firebase-functions/v1';
3
+ export interface PostgresSyncOptions {
4
+ /**
5
+ * A function that executes a SQL query.
6
+ * Compatible with 'pg' Pool.query or Client.query.
7
+ * You can pass `pool.query.bind(pool)` here.
8
+ */
9
+ query: (text: string, params?: any[]) => Promise<any>;
10
+ /**
11
+ * The name of the table to insert users into.
12
+ * @example 'users'
13
+ * @example 'public.profiles'
14
+ */
15
+ tableName: string;
16
+ /**
17
+ * Map Firebase UserRecord fields to your database columns.
18
+ * Key: Firebase field (e.g., 'uid', 'email', 'displayName', 'photoURL')
19
+ * Value: Database column name
20
+ */
21
+ fieldMapping: Partial<Record<keyof UserRecord, string>>;
22
+ /**
23
+ * Optional: Add extra static values or computed values.
24
+ * @example { role: 'user', created_at: new Date() }
25
+ */
26
+ extraFields?: (user: UserRecord) => Record<string, any>;
27
+ /**
28
+ * Optional: Callback to run after successful sync
29
+ */
30
+ onSuccess?: (user: UserRecord) => Promise<void>;
31
+ /**
32
+ * Optional: Callback to run on error
33
+ */
34
+ onError?: (error: any, user: UserRecord) => Promise<void>;
35
+ }
36
+ /**
37
+ * Creates a Firebase Authentication Trigger that syncs new users to a Postgres database.
38
+ *
39
+ * @example
40
+ * export const syncUser = createPostgresSync({
41
+ * query: pool.query.bind(pool),
42
+ * tableName: 'users',
43
+ * fieldMapping: {
44
+ * uid: 'id',
45
+ * email: 'email',
46
+ * displayName: 'full_name'
47
+ * }
48
+ * });
49
+ */
50
+ export declare const createPostgresSync: (options: PostgresSyncOptions) => functions.CloudFunction<UserRecord>;
51
+ export interface GenericSyncOptions {
52
+ /**
53
+ * Map Firebase UserRecord fields to your database columns/fields.
54
+ * Key: Firebase field (e.g., 'uid', 'email')
55
+ * Value: Your database field name
56
+ */
57
+ fieldMapping: Partial<Record<keyof UserRecord, string>>;
58
+ /**
59
+ * Optional: Add extra static values or computed values.
60
+ */
61
+ extraFields?: (user: UserRecord) => Record<string, any>;
62
+ /**
63
+ * Function to save the mapped data to your database.
64
+ * Receives a plain object with the mapped keys and values.
65
+ */
66
+ syncFn: (data: Record<string, any>, user: UserRecord) => Promise<void>;
67
+ /**
68
+ * Optional: Callback to run on error
69
+ */
70
+ onError?: (error: any, user: UserRecord) => Promise<void>;
71
+ }
72
+ /**
73
+ * Creates a generic Firebase Authentication Trigger for syncing users to any database (Prisma, Drizzle, Mongo, etc).
74
+ *
75
+ * @example
76
+ * export const syncUser = createGenericSync({
77
+ * fieldMapping: { uid: 'id', email: 'email' },
78
+ * syncFn: async (data) => {
79
+ * await prisma.user.create({ data });
80
+ * }
81
+ * });
82
+ */
83
+ export declare const createGenericSync: (options: GenericSyncOptions) => functions.CloudFunction<UserRecord>;
84
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/functions/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,SAAS,MAAM,uBAAuB,CAAC;AAEnD,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;IAEtD;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;;;OAIG;IACH,YAAY,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;IAExD;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAExD;;OAEG;IACH,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhD;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3D;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,kBAAkB,GAAI,SAAS,mBAAmB,wCAqD9D,CAAC;AAEF,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,YAAY,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;IAExD;;OAEG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAExD;;;OAGG;IACH,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvE;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3D;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,GAAI,SAAS,kBAAkB,wCA+B5D,CAAC"}
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/functions/index.ts
31
+ var functions_exports = {};
32
+ __export(functions_exports, {
33
+ createGenericSync: () => createGenericSync,
34
+ createPostgresSync: () => createPostgresSync
35
+ });
36
+ module.exports = __toCommonJS(functions_exports);
37
+ var functions = __toESM(require("firebase-functions/v1"));
38
+ var createPostgresSync = (options) => {
39
+ return functions.auth.user().onCreate(async (user) => {
40
+ const { query, tableName, fieldMapping, extraFields, onSuccess, onError } = options;
41
+ try {
42
+ const columns = [];
43
+ const values = [];
44
+ const placeholders = [];
45
+ Object.entries(fieldMapping).forEach(([userField, dbColumn]) => {
46
+ if (dbColumn) {
47
+ columns.push(dbColumn);
48
+ values.push(user[userField]);
49
+ placeholders.push(`$${values.length}`);
50
+ }
51
+ });
52
+ if (extraFields) {
53
+ const extras = extraFields(user);
54
+ Object.entries(extras).forEach(([column, value]) => {
55
+ columns.push(column);
56
+ values.push(value);
57
+ placeholders.push(`$${values.length}`);
58
+ });
59
+ }
60
+ if (columns.length === 0) {
61
+ console.warn("createPostgresSync: No fields mapped for insertion.");
62
+ return;
63
+ }
64
+ const queryText = `
65
+ INSERT INTO ${tableName} (${columns.join(", ")})
66
+ VALUES (${placeholders.join(", ")})
67
+ ON CONFLICT DO NOTHING
68
+ `;
69
+ await query(queryText, values);
70
+ if (onSuccess) {
71
+ await onSuccess(user);
72
+ }
73
+ } catch (error) {
74
+ console.error("createPostgresSync: Failed to sync user", error);
75
+ if (onError) {
76
+ await onError(error, user);
77
+ } else {
78
+ throw error;
79
+ }
80
+ }
81
+ });
82
+ };
83
+ var createGenericSync = (options) => {
84
+ return functions.auth.user().onCreate(async (user) => {
85
+ const { fieldMapping, extraFields, syncFn, onError } = options;
86
+ try {
87
+ const data = {};
88
+ Object.entries(fieldMapping).forEach(([userField, dbField]) => {
89
+ if (dbField) {
90
+ data[dbField] = user[userField];
91
+ }
92
+ });
93
+ if (extraFields) {
94
+ const extras = extraFields(user);
95
+ Object.assign(data, extras);
96
+ }
97
+ await syncFn(data, user);
98
+ } catch (error) {
99
+ console.error("createGenericSync: Failed to sync user", error);
100
+ if (onError) {
101
+ await onError(error, user);
102
+ } else {
103
+ throw error;
104
+ }
105
+ }
106
+ });
107
+ };
108
+ // Annotate the CommonJS export names for ESM import in node:
109
+ 0 && (module.exports = {
110
+ createGenericSync,
111
+ createPostgresSync
112
+ });
113
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/functions/index.ts"],"sourcesContent":["import type { UserRecord } from 'firebase-admin/auth';\nimport * as functions from 'firebase-functions/v1';\n\nexport interface PostgresSyncOptions {\n /**\n * A function that executes a SQL query.\n * Compatible with 'pg' Pool.query or Client.query.\n * You can pass `pool.query.bind(pool)` here.\n */\n query: (text: string, params?: any[]) => Promise<any>;\n \n /**\n * The name of the table to insert users into.\n * @example 'users'\n * @example 'public.profiles'\n */\n tableName: string;\n\n /**\n * Map Firebase UserRecord fields to your database columns.\n * Key: Firebase field (e.g., 'uid', 'email', 'displayName', 'photoURL')\n * Value: Database column name\n */\n fieldMapping: Partial<Record<keyof UserRecord, string>>;\n\n /**\n * Optional: Add extra static values or computed values.\n * @example { role: 'user', created_at: new Date() }\n */\n extraFields?: (user: UserRecord) => Record<string, any>;\n \n /**\n * Optional: Callback to run after successful sync\n */\n onSuccess?: (user: UserRecord) => Promise<void>;\n\n /**\n * Optional: Callback to run on error\n */\n onError?: (error: any, user: UserRecord) => Promise<void>;\n}\n\n/**\n * Creates a Firebase Authentication Trigger that syncs new users to a Postgres database.\n * \n * @example\n * export const syncUser = createPostgresSync({\n * query: pool.query.bind(pool),\n * tableName: 'users',\n * fieldMapping: {\n * uid: 'id',\n * email: 'email',\n * displayName: 'full_name'\n * }\n * });\n */\nexport const createPostgresSync = (options: PostgresSyncOptions) => {\n return functions.auth.user().onCreate(async (user) => {\n const { query, tableName, fieldMapping, extraFields, onSuccess, onError } = options;\n\n try {\n const columns: string[] = [];\n const values: any[] = [];\n const placeholders: string[] = [];\n\n // Handle mapped fields\n Object.entries(fieldMapping).forEach(([userField, dbColumn]) => {\n if (dbColumn) {\n columns.push(dbColumn);\n values.push((user as any)[userField]);\n placeholders.push(`$${values.length}`);\n }\n });\n\n // Handle extra fields\n if (extraFields) {\n const extras = extraFields(user);\n Object.entries(extras).forEach(([column, value]) => {\n columns.push(column);\n values.push(value);\n placeholders.push(`$${values.length}`);\n });\n }\n\n if (columns.length === 0) {\n console.warn('createPostgresSync: No fields mapped for insertion.');\n return;\n }\n\n const queryText = `\n INSERT INTO ${tableName} (${columns.join(', ')})\n VALUES (${placeholders.join(', ')})\n ON CONFLICT DO NOTHING\n `;\n\n await query(queryText, values);\n\n if (onSuccess) {\n await onSuccess(user);\n }\n } catch (error) {\n console.error('createPostgresSync: Failed to sync user', error);\n if (onError) {\n await onError(error, user);\n } else {\n throw error;\n }\n }\n });\n};\n\nexport interface GenericSyncOptions {\n /**\n * Map Firebase UserRecord fields to your database columns/fields.\n * Key: Firebase field (e.g., 'uid', 'email')\n * Value: Your database field name\n */\n fieldMapping: Partial<Record<keyof UserRecord, string>>;\n\n /**\n * Optional: Add extra static values or computed values.\n */\n extraFields?: (user: UserRecord) => Record<string, any>;\n\n /**\n * Function to save the mapped data to your database.\n * Receives a plain object with the mapped keys and values.\n */\n syncFn: (data: Record<string, any>, user: UserRecord) => Promise<void>;\n\n /**\n * Optional: Callback to run on error\n */\n onError?: (error: any, user: UserRecord) => Promise<void>;\n}\n\n/**\n * Creates a generic Firebase Authentication Trigger for syncing users to any database (Prisma, Drizzle, Mongo, etc).\n * \n * @example\n * export const syncUser = createGenericSync({\n * fieldMapping: { uid: 'id', email: 'email' },\n * syncFn: async (data) => {\n * await prisma.user.create({ data });\n * }\n * });\n */\nexport const createGenericSync = (options: GenericSyncOptions) => {\n return functions.auth.user().onCreate(async (user) => {\n const { fieldMapping, extraFields, syncFn, onError } = options;\n\n try {\n const data: Record<string, any> = {};\n\n // Handle mapped fields\n Object.entries(fieldMapping).forEach(([userField, dbField]) => {\n if (dbField) {\n data[dbField] = (user as any)[userField];\n }\n });\n\n // Handle extra fields\n if (extraFields) {\n const extras = extraFields(user);\n Object.assign(data, extras);\n }\n\n await syncFn(data, user);\n\n } catch (error) {\n console.error('createGenericSync: Failed to sync user', error);\n if (onError) {\n await onError(error, user);\n } else {\n throw error;\n }\n }\n });\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,gBAA2B;AAuDpB,IAAM,qBAAqB,CAAC,YAAiC;AAClE,SAAiB,eAAK,KAAK,EAAE,SAAS,OAAO,SAAS;AACpD,UAAM,EAAE,OAAO,WAAW,cAAc,aAAa,WAAW,QAAQ,IAAI;AAE5E,QAAI;AACF,YAAM,UAAoB,CAAC;AAC3B,YAAM,SAAgB,CAAC;AACvB,YAAM,eAAyB,CAAC;AAGhC,aAAO,QAAQ,YAAY,EAAE,QAAQ,CAAC,CAAC,WAAW,QAAQ,MAAM;AAC9D,YAAI,UAAU;AACZ,kBAAQ,KAAK,QAAQ;AACrB,iBAAO,KAAM,KAAa,SAAS,CAAC;AACpC,uBAAa,KAAK,IAAI,OAAO,MAAM,EAAE;AAAA,QACvC;AAAA,MACF,CAAC;AAGD,UAAI,aAAa;AACf,cAAM,SAAS,YAAY,IAAI;AAC/B,eAAO,QAAQ,MAAM,EAAE,QAAQ,CAAC,CAAC,QAAQ,KAAK,MAAM;AAClD,kBAAQ,KAAK,MAAM;AACnB,iBAAO,KAAK,KAAK;AACjB,uBAAa,KAAK,IAAI,OAAO,MAAM,EAAE;AAAA,QACvC,CAAC;AAAA,MACH;AAEA,UAAI,QAAQ,WAAW,GAAG;AACxB,gBAAQ,KAAK,qDAAqD;AAClE;AAAA,MACF;AAEA,YAAM,YAAY;AAAA,sBACF,SAAS,KAAK,QAAQ,KAAK,IAAI,CAAC;AAAA,kBACpC,aAAa,KAAK,IAAI,CAAC;AAAA;AAAA;AAInC,YAAM,MAAM,WAAW,MAAM;AAE7B,UAAI,WAAW;AACb,cAAM,UAAU,IAAI;AAAA,MACtB;AAAA,IACF,SAAS,OAAO;AACd,cAAQ,MAAM,2CAA2C,KAAK;AAC9D,UAAI,SAAS;AACX,cAAM,QAAQ,OAAO,IAAI;AAAA,MAC3B,OAAO;AACL,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAsCO,IAAM,oBAAoB,CAAC,YAAgC;AAChE,SAAiB,eAAK,KAAK,EAAE,SAAS,OAAO,SAAS;AACpD,UAAM,EAAE,cAAc,aAAa,QAAQ,QAAQ,IAAI;AAEvD,QAAI;AACF,YAAM,OAA4B,CAAC;AAGnC,aAAO,QAAQ,YAAY,EAAE,QAAQ,CAAC,CAAC,WAAW,OAAO,MAAM;AAC7D,YAAI,SAAS;AACX,eAAK,OAAO,IAAK,KAAa,SAAS;AAAA,QACzC;AAAA,MACF,CAAC;AAGD,UAAI,aAAa;AACf,cAAM,SAAS,YAAY,IAAI;AAC/B,eAAO,OAAO,MAAM,MAAM;AAAA,MAC5B;AAEA,YAAM,OAAO,MAAM,IAAI;AAAA,IAEzB,SAAS,OAAO;AACd,cAAQ,MAAM,0CAA0C,KAAK;AAC7D,UAAI,SAAS;AACX,cAAM,QAAQ,OAAO,IAAI;AAAA,MAC3B,OAAO;AACL,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF,CAAC;AACH;","names":[]}
@@ -0,0 +1,77 @@
1
+ // src/functions/index.ts
2
+ import * as functions from "firebase-functions/v1";
3
+ var createPostgresSync = (options) => {
4
+ return functions.auth.user().onCreate(async (user) => {
5
+ const { query, tableName, fieldMapping, extraFields, onSuccess, onError } = options;
6
+ try {
7
+ const columns = [];
8
+ const values = [];
9
+ const placeholders = [];
10
+ Object.entries(fieldMapping).forEach(([userField, dbColumn]) => {
11
+ if (dbColumn) {
12
+ columns.push(dbColumn);
13
+ values.push(user[userField]);
14
+ placeholders.push(`$${values.length}`);
15
+ }
16
+ });
17
+ if (extraFields) {
18
+ const extras = extraFields(user);
19
+ Object.entries(extras).forEach(([column, value]) => {
20
+ columns.push(column);
21
+ values.push(value);
22
+ placeholders.push(`$${values.length}`);
23
+ });
24
+ }
25
+ if (columns.length === 0) {
26
+ console.warn("createPostgresSync: No fields mapped for insertion.");
27
+ return;
28
+ }
29
+ const queryText = `
30
+ INSERT INTO ${tableName} (${columns.join(", ")})
31
+ VALUES (${placeholders.join(", ")})
32
+ ON CONFLICT DO NOTHING
33
+ `;
34
+ await query(queryText, values);
35
+ if (onSuccess) {
36
+ await onSuccess(user);
37
+ }
38
+ } catch (error) {
39
+ console.error("createPostgresSync: Failed to sync user", error);
40
+ if (onError) {
41
+ await onError(error, user);
42
+ } else {
43
+ throw error;
44
+ }
45
+ }
46
+ });
47
+ };
48
+ var createGenericSync = (options) => {
49
+ return functions.auth.user().onCreate(async (user) => {
50
+ const { fieldMapping, extraFields, syncFn, onError } = options;
51
+ try {
52
+ const data = {};
53
+ Object.entries(fieldMapping).forEach(([userField, dbField]) => {
54
+ if (dbField) {
55
+ data[dbField] = user[userField];
56
+ }
57
+ });
58
+ if (extraFields) {
59
+ const extras = extraFields(user);
60
+ Object.assign(data, extras);
61
+ }
62
+ await syncFn(data, user);
63
+ } catch (error) {
64
+ console.error("createGenericSync: Failed to sync user", error);
65
+ if (onError) {
66
+ await onError(error, user);
67
+ } else {
68
+ throw error;
69
+ }
70
+ }
71
+ });
72
+ };
73
+ export {
74
+ createGenericSync,
75
+ createPostgresSync
76
+ };
77
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/functions/index.ts"],"sourcesContent":["import type { UserRecord } from 'firebase-admin/auth';\nimport * as functions from 'firebase-functions/v1';\n\nexport interface PostgresSyncOptions {\n /**\n * A function that executes a SQL query.\n * Compatible with 'pg' Pool.query or Client.query.\n * You can pass `pool.query.bind(pool)` here.\n */\n query: (text: string, params?: any[]) => Promise<any>;\n \n /**\n * The name of the table to insert users into.\n * @example 'users'\n * @example 'public.profiles'\n */\n tableName: string;\n\n /**\n * Map Firebase UserRecord fields to your database columns.\n * Key: Firebase field (e.g., 'uid', 'email', 'displayName', 'photoURL')\n * Value: Database column name\n */\n fieldMapping: Partial<Record<keyof UserRecord, string>>;\n\n /**\n * Optional: Add extra static values or computed values.\n * @example { role: 'user', created_at: new Date() }\n */\n extraFields?: (user: UserRecord) => Record<string, any>;\n \n /**\n * Optional: Callback to run after successful sync\n */\n onSuccess?: (user: UserRecord) => Promise<void>;\n\n /**\n * Optional: Callback to run on error\n */\n onError?: (error: any, user: UserRecord) => Promise<void>;\n}\n\n/**\n * Creates a Firebase Authentication Trigger that syncs new users to a Postgres database.\n * \n * @example\n * export const syncUser = createPostgresSync({\n * query: pool.query.bind(pool),\n * tableName: 'users',\n * fieldMapping: {\n * uid: 'id',\n * email: 'email',\n * displayName: 'full_name'\n * }\n * });\n */\nexport const createPostgresSync = (options: PostgresSyncOptions) => {\n return functions.auth.user().onCreate(async (user) => {\n const { query, tableName, fieldMapping, extraFields, onSuccess, onError } = options;\n\n try {\n const columns: string[] = [];\n const values: any[] = [];\n const placeholders: string[] = [];\n\n // Handle mapped fields\n Object.entries(fieldMapping).forEach(([userField, dbColumn]) => {\n if (dbColumn) {\n columns.push(dbColumn);\n values.push((user as any)[userField]);\n placeholders.push(`$${values.length}`);\n }\n });\n\n // Handle extra fields\n if (extraFields) {\n const extras = extraFields(user);\n Object.entries(extras).forEach(([column, value]) => {\n columns.push(column);\n values.push(value);\n placeholders.push(`$${values.length}`);\n });\n }\n\n if (columns.length === 0) {\n console.warn('createPostgresSync: No fields mapped for insertion.');\n return;\n }\n\n const queryText = `\n INSERT INTO ${tableName} (${columns.join(', ')})\n VALUES (${placeholders.join(', ')})\n ON CONFLICT DO NOTHING\n `;\n\n await query(queryText, values);\n\n if (onSuccess) {\n await onSuccess(user);\n }\n } catch (error) {\n console.error('createPostgresSync: Failed to sync user', error);\n if (onError) {\n await onError(error, user);\n } else {\n throw error;\n }\n }\n });\n};\n\nexport interface GenericSyncOptions {\n /**\n * Map Firebase UserRecord fields to your database columns/fields.\n * Key: Firebase field (e.g., 'uid', 'email')\n * Value: Your database field name\n */\n fieldMapping: Partial<Record<keyof UserRecord, string>>;\n\n /**\n * Optional: Add extra static values or computed values.\n */\n extraFields?: (user: UserRecord) => Record<string, any>;\n\n /**\n * Function to save the mapped data to your database.\n * Receives a plain object with the mapped keys and values.\n */\n syncFn: (data: Record<string, any>, user: UserRecord) => Promise<void>;\n\n /**\n * Optional: Callback to run on error\n */\n onError?: (error: any, user: UserRecord) => Promise<void>;\n}\n\n/**\n * Creates a generic Firebase Authentication Trigger for syncing users to any database (Prisma, Drizzle, Mongo, etc).\n * \n * @example\n * export const syncUser = createGenericSync({\n * fieldMapping: { uid: 'id', email: 'email' },\n * syncFn: async (data) => {\n * await prisma.user.create({ data });\n * }\n * });\n */\nexport const createGenericSync = (options: GenericSyncOptions) => {\n return functions.auth.user().onCreate(async (user) => {\n const { fieldMapping, extraFields, syncFn, onError } = options;\n\n try {\n const data: Record<string, any> = {};\n\n // Handle mapped fields\n Object.entries(fieldMapping).forEach(([userField, dbField]) => {\n if (dbField) {\n data[dbField] = (user as any)[userField];\n }\n });\n\n // Handle extra fields\n if (extraFields) {\n const extras = extraFields(user);\n Object.assign(data, extras);\n }\n\n await syncFn(data, user);\n\n } catch (error) {\n console.error('createGenericSync: Failed to sync user', error);\n if (onError) {\n await onError(error, user);\n } else {\n throw error;\n }\n }\n });\n};\n"],"mappings":";AACA,YAAY,eAAe;AAuDpB,IAAM,qBAAqB,CAAC,YAAiC;AAClE,SAAiB,eAAK,KAAK,EAAE,SAAS,OAAO,SAAS;AACpD,UAAM,EAAE,OAAO,WAAW,cAAc,aAAa,WAAW,QAAQ,IAAI;AAE5E,QAAI;AACF,YAAM,UAAoB,CAAC;AAC3B,YAAM,SAAgB,CAAC;AACvB,YAAM,eAAyB,CAAC;AAGhC,aAAO,QAAQ,YAAY,EAAE,QAAQ,CAAC,CAAC,WAAW,QAAQ,MAAM;AAC9D,YAAI,UAAU;AACZ,kBAAQ,KAAK,QAAQ;AACrB,iBAAO,KAAM,KAAa,SAAS,CAAC;AACpC,uBAAa,KAAK,IAAI,OAAO,MAAM,EAAE;AAAA,QACvC;AAAA,MACF,CAAC;AAGD,UAAI,aAAa;AACf,cAAM,SAAS,YAAY,IAAI;AAC/B,eAAO,QAAQ,MAAM,EAAE,QAAQ,CAAC,CAAC,QAAQ,KAAK,MAAM;AAClD,kBAAQ,KAAK,MAAM;AACnB,iBAAO,KAAK,KAAK;AACjB,uBAAa,KAAK,IAAI,OAAO,MAAM,EAAE;AAAA,QACvC,CAAC;AAAA,MACH;AAEA,UAAI,QAAQ,WAAW,GAAG;AACxB,gBAAQ,KAAK,qDAAqD;AAClE;AAAA,MACF;AAEA,YAAM,YAAY;AAAA,sBACF,SAAS,KAAK,QAAQ,KAAK,IAAI,CAAC;AAAA,kBACpC,aAAa,KAAK,IAAI,CAAC;AAAA;AAAA;AAInC,YAAM,MAAM,WAAW,MAAM;AAE7B,UAAI,WAAW;AACb,cAAM,UAAU,IAAI;AAAA,MACtB;AAAA,IACF,SAAS,OAAO;AACd,cAAQ,MAAM,2CAA2C,KAAK;AAC9D,UAAI,SAAS;AACX,cAAM,QAAQ,OAAO,IAAI;AAAA,MAC3B,OAAO;AACL,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAsCO,IAAM,oBAAoB,CAAC,YAAgC;AAChE,SAAiB,eAAK,KAAK,EAAE,SAAS,OAAO,SAAS;AACpD,UAAM,EAAE,cAAc,aAAa,QAAQ,QAAQ,IAAI;AAEvD,QAAI;AACF,YAAM,OAA4B,CAAC;AAGnC,aAAO,QAAQ,YAAY,EAAE,QAAQ,CAAC,CAAC,WAAW,OAAO,MAAM;AAC7D,YAAI,SAAS;AACX,eAAK,OAAO,IAAK,KAAa,SAAS;AAAA,QACzC;AAAA,MACF,CAAC;AAGD,UAAI,aAAa;AACf,cAAM,SAAS,YAAY,IAAI;AAC/B,eAAO,OAAO,MAAM,MAAM;AAAA,MAC5B;AAEA,YAAM,OAAO,MAAM,IAAI;AAAA,IAEzB,SAAS,OAAO;AACd,cAAQ,MAAM,0CAA0C,KAAK;AAC7D,UAAI,SAAS;AACX,cAAM,QAAQ,OAAO,IAAI;AAAA,MAC3B,OAAO;AACL,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF,CAAC;AACH;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tern-secure/backend",
3
- "version": "1.2.0-canary.v20251209193320",
3
+ "version": "1.2.0-canary.v20251210182014",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/TernSecure/auth.git",
@@ -81,16 +81,25 @@
81
81
  "default": "./dist/jwt/index.js"
82
82
  }
83
83
  },
84
+ "./functions": {
85
+ "import": {
86
+ "types": "./dist/functions/index.d.ts",
87
+ "default": "./dist/functions/index.mjs"
88
+ },
89
+ "require": {
90
+ "types": "./dist/functions/index.d.ts",
91
+ "default": "./dist/functions/index.js"
92
+ }
93
+ },
84
94
  "./package.json": "./package.json"
85
95
  },
86
96
  "main": "./dist/index.js",
87
97
  "dependencies": {
88
- "@upstash/redis": "^1.35.2",
89
98
  "cookie": "1.0.2",
90
99
  "jose": "^5.10.0",
91
100
  "tslib": "2.8.1",
92
- "@tern-secure/shared": "1.3.0-canary.v20251209193320",
93
- "@tern-secure/types": "1.1.0-canary.v20251209193320"
101
+ "@tern-secure/shared": "1.3.0-canary.v20251210182014",
102
+ "@tern-secure/types": "1.1.0-canary.v20251210182014"
94
103
  },
95
104
  "devDependencies": {
96
105
  "@types/js-cookie": "^3.0.6",
@@ -98,7 +107,9 @@
98
107
  "vitest-environment-miniflare": "2.14.4"
99
108
  },
100
109
  "peerDependencies": {
101
- "firebase-admin": "^12.7.0"
110
+ "@upstash/redis": "^1.35.2",
111
+ "firebase-admin": "^12.7.0",
112
+ "firebase-functions": "^6.1.2"
102
113
  },
103
114
  "engines": {
104
115
  "node": ">=20"