cic-kit-firebase-functions 0.0.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/README.md ADDED
@@ -0,0 +1,76 @@
1
+ # cic-kit-firebase-functions
2
+
3
+ Set di Firebase Functions riutilizzabili per progetti CIC.
4
+
5
+ **Installazione**
6
+ ```bash
7
+ npm i cic-kit-firebase-functions
8
+ ```
9
+
10
+ **Peer Dependencies**
11
+ ```bash
12
+ npm i firebase-admin firebase-functions
13
+ ```
14
+
15
+ **Uso Consigliato**
16
+ ```ts
17
+ import { cicInit } from 'cic-kit-firebase-functions';
18
+
19
+ const { sendUserPush, syncPublicUser } = cicInit({
20
+ region: 'europe-west1',
21
+ https: { cors: true },
22
+ });
23
+
24
+ export { sendUserPush, syncPublicUser };
25
+ ```
26
+
27
+ **Uso Avanzato (Factory)**
28
+ ```ts
29
+ import { createSendUserPush, createSyncPublicUser } from 'cic-kit-firebase-functions';
30
+
31
+ export const sendUserPush = createSendUserPush({ region: 'europe-west1', cors: true });
32
+ export const syncPublicUser = createSyncPublicUser('europe-west1');
33
+ ```
34
+
35
+ **API**
36
+ `cicInit(options)`
37
+ - `options.region`: `SupportedRegion` (default `europe-west1`)
38
+ - `options.https.cors`: `boolean | string | RegExp | Array<string | RegExp>` (default `true`)
39
+
40
+ `sendUserPush` (Callable)
41
+ - Input:
42
+ ```ts
43
+ {
44
+ toUid: string;
45
+ title: string;
46
+ options?: WebpushNotification;
47
+ }
48
+ ```
49
+ - Behavior: legge `users/{toUid}`, usa `fcmTokens`, invia WebPush con `title` + `options`, ripulisce token invalidi.
50
+ - Return:
51
+ ```ts
52
+ { sent: number; total: number; cleaned: number }
53
+ ```
54
+
55
+ `syncPublicUser` (Firestore trigger)
56
+ - Trigger: `users/{userId}`
57
+ - Copia i campi indicati in `publicKey` dentro `users_public/{userId}`
58
+ - Se `birthHideYear === true` maschera l'anno della data di nascita
59
+
60
+ **Dati Attesi in Firestore**
61
+ `users/{userId}`
62
+ - `fcmTokens`: `string[]`
63
+ - `publicKey`: `string[]` (lista campi da esporre)
64
+ - `birthHideYear`: `boolean` (opzionale)
65
+ - `birthDate`: `string` (formato `dd/mm/yyyy`, opzionale)
66
+ - `name`, `surname`, `createdAt`, `updatedAt` (opzionali)
67
+
68
+ **Build**
69
+ ```bash
70
+ npm run build
71
+ ```
72
+
73
+ **Note**
74
+ - Questo pacchetto esporta funzioni già pronte. Se usi `cicInit`, chiamala prima di esportare le function.
75
+ - L'opzione `options.data.url` in `sendUserPush` viene usata come link webpush (fallback `/`).
76
+ - Il pacchetto e' ESM: usare `import`, non `require`.
@@ -0,0 +1,4 @@
1
+ import { type App } from 'firebase-admin/app';
2
+ export declare const app: App;
3
+ export declare const db: FirebaseFirestore.Firestore;
4
+ export declare const messaging: import("firebase-admin/messaging").Messaging;
package/dist/admin.js ADDED
@@ -0,0 +1,9 @@
1
+ // functions/src/libs/admin.ts
2
+ import { getApps, initializeApp } from 'firebase-admin/app';
3
+ import { getFirestore } from 'firebase-admin/firestore';
4
+ import { getMessaging } from 'firebase-admin/messaging';
5
+ const _app = getApps();
6
+ export const app = (_app.length && _app?.[0]) ? _app[0] : initializeApp();
7
+ export const db = getFirestore(app);
8
+ export const messaging = getMessaging(app);
9
+ //# sourceMappingURL=admin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin.js","sourceRoot":"","sources":["../src/admin.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAC9B,OAAO,EAAE,OAAO,EAAE,aAAa,EAAY,MAAM,oBAAoB,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAExD,MAAM,IAAI,GAAU,OAAO,EAAE,CAAC;AAC9B,MAAM,CAAC,MAAM,GAAG,GAAQ,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;AAC/E,MAAM,CAAC,MAAM,EAAE,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;AACpC,MAAM,CAAC,MAAM,SAAS,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { CicInitOptions } from './config/env.js';
2
+ export declare function cicInit(options?: CicInitOptions): {
3
+ readonly sendUserPush: import("firebase-functions/v2/https").CallableFunction<{
4
+ toUid: string;
5
+ title: string;
6
+ options?: import("firebase-admin/messaging").WebpushNotification;
7
+ }, Promise<{
8
+ sent: number;
9
+ total: number;
10
+ cleaned: number;
11
+ }>>;
12
+ readonly syncPublicUser: import("firebase-functions/v2").CloudFunction<import("firebase-functions/v2/firestore").FirestoreEvent<import("firebase-functions").Change<import("firebase-functions/v2/firestore").DocumentSnapshot> | undefined, {
13
+ userId: string;
14
+ }>>;
15
+ };
@@ -0,0 +1,11 @@
1
+ import { setConfig } from './config/env.js';
2
+ import { createSendUserPush } from './features/senderPush/sendUserPush.js';
3
+ import { createSyncPublicUser } from './features/syncPublicUser/syncPublicUser.js';
4
+ export function cicInit(options = {}) {
5
+ setConfig(options);
6
+ return {
7
+ sendUserPush: createSendUserPush(),
8
+ syncPublicUser: createSyncPublicUser(),
9
+ };
10
+ }
11
+ //# sourceMappingURL=cicInit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cicInit.js","sourceRoot":"","sources":["../src/cicInit.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAE,MAAM,6CAA6C,CAAC;AAEnF,MAAM,UAAU,OAAO,CAAC,UAA0B,EAAE;IAClD,SAAS,CAAC,OAAO,CAAC,CAAC;IAEnB,OAAO;QACL,YAAY,EAAE,kBAAkB,EAAE;QAClC,cAAc,EAAE,oBAAoB,EAAE;KAC9B,CAAC;AACb,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { SupportedRegion } from 'firebase-functions/v2/options';
2
+ export type CicInitOptions = {
3
+ region?: SupportedRegion;
4
+ https?: {
5
+ cors?: boolean;
6
+ };
7
+ };
8
+ export declare function setConfig(options?: CicInitOptions): void;
9
+ export declare function getRegion(): SupportedRegion;
10
+ export declare function getHttpsDefaults(): {
11
+ readonly region: SupportedRegion;
12
+ readonly cors: boolean;
13
+ };
@@ -0,0 +1,23 @@
1
+ const defaultConfig = {
2
+ region: 'europe-west1',
3
+ https: {
4
+ cors: true,
5
+ },
6
+ };
7
+ let config = {
8
+ region: defaultConfig.region,
9
+ https: { ...defaultConfig.https },
10
+ };
11
+ export function setConfig(options = {}) {
12
+ if (options.region)
13
+ config.region = options.region;
14
+ if (options.https?.cors !== undefined)
15
+ config.https.cors = options.https.cors;
16
+ }
17
+ export function getRegion() {
18
+ return config.region;
19
+ }
20
+ export function getHttpsDefaults() {
21
+ return { region: config.region, cors: config.https.cors };
22
+ }
23
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/config/env.ts"],"names":[],"mappings":"AAiBA,MAAM,aAAa,GAAc;IAC/B,MAAM,EAAE,cAAc;IACtB,KAAK,EAAE;QACL,IAAI,EAAE,IAAI;KACX;CACF,CAAC;AAEF,IAAI,MAAM,GAAc;IACtB,MAAM,EAAE,aAAa,CAAC,MAAM;IAC5B,KAAK,EAAE,EAAE,GAAG,aAAa,CAAC,KAAK,EAAE;CAClC,CAAC;AAEF,MAAM,UAAU,SAAS,CAAC,UAA0B,EAAE;IACpD,IAAI,OAAO,CAAC,MAAM;QAAE,MAAM,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IACnD,IAAI,OAAO,CAAC,KAAK,EAAE,IAAI,KAAK,SAAS;QAAE,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC;AAChF,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,OAAO,MAAM,CAAC,MAAM,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI,EAAW,CAAC;AACrE,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { WebpushNotification } from 'firebase-admin/messaging';
2
+ export declare const MAX_FCM_CHUNK = 500;
3
+ export declare function chunk<T>(arr: T[], n?: number): T[][];
4
+ type SendUserPushInput = {
5
+ toUid: string;
6
+ title: string;
7
+ options?: WebpushNotification;
8
+ };
9
+ export declare function createSendUserPush(httpsDefaults?: {
10
+ readonly region: import("firebase-functions/v2").SupportedRegion;
11
+ readonly cors: boolean;
12
+ }): import("firebase-functions/v2/https").CallableFunction<SendUserPushInput, Promise<{
13
+ sent: number;
14
+ total: number;
15
+ cleaned: number;
16
+ }>>;
17
+ export {};
@@ -0,0 +1,77 @@
1
+ // functions/src/features/push/sendUserPush.ts
2
+ import { onCall, HttpsError } from 'firebase-functions/v2/https';
3
+ import { logger } from 'firebase-functions';
4
+ import { db, messaging } from '../../admin.js';
5
+ import { getHttpsDefaults } from '../../config/env.js';
6
+ export const MAX_FCM_CHUNK = 500;
7
+ export function chunk(arr, n = MAX_FCM_CHUNK) {
8
+ return arr.reduce((acc, _, i) => (i % n ? acc : [...acc, arr.slice(i, i + n)]), []);
9
+ }
10
+ async function handleSendUserPush(request) {
11
+ if (!request.auth) {
12
+ throw new HttpsError('unauthenticated', 'Login richiesto.');
13
+ }
14
+ const { toUid, title, options = {} } = (request.data ?? {});
15
+ if (!toUid || !title) {
16
+ throw new HttpsError('invalid-argument', 'toUid e title sono obbligatori');
17
+ }
18
+ const userDoc = await db.collection('users').doc(toUid).get();
19
+ if (!userDoc.exists) {
20
+ console.warn('sendUserPush: user non trovato', { toUid });
21
+ logger.warn('sendUserPush: user non trovato', { toUid });
22
+ return { sent: 0, total: 0, cleaned: 0 };
23
+ }
24
+ const fcmTokens = Array.isArray(userDoc.get('fcmTokens'))
25
+ ? userDoc.get('fcmTokens').filter(Boolean)
26
+ : [];
27
+ if (!fcmTokens.length) {
28
+ return { sent: 0, total: 0, cleaned: 0 };
29
+ }
30
+ const { silent, ...ops } = options;
31
+ const webpush = {
32
+ notification: {
33
+ title,
34
+ ...(silent === null ? {} : { silent }),
35
+ ...ops
36
+ },
37
+ fcmOptions: {
38
+ link: options?.data?.url ?? '/'
39
+ },
40
+ headers: {
41
+ TTL: '3600',
42
+ Urgency: 'normal',
43
+ },
44
+ };
45
+ let sent = 0;
46
+ let cleaned = 0;
47
+ let stillValid = new Set(fcmTokens);
48
+ for (const part of chunk(fcmTokens)) {
49
+ const res = await messaging.sendEachForMulticast({
50
+ tokens: part,
51
+ notification: { title, body: options?.body ?? 'undefined' },
52
+ webpush,
53
+ });
54
+ sent += res.responses.filter(r => r.success).length;
55
+ res.responses.forEach((r, i) => {
56
+ if (!r.success) {
57
+ const code = r.error?.code || '';
58
+ const token = part[i];
59
+ if ((code.includes('registration-token-not-registered') ||
60
+ code.includes('invalid-argument')) && token) {
61
+ if (stillValid.delete(token))
62
+ cleaned++;
63
+ }
64
+ }
65
+ });
66
+ }
67
+ if (cleaned > 0) {
68
+ await db.collection('users').doc(toUid).update({
69
+ fcmTokens: Array.from(stillValid),
70
+ });
71
+ }
72
+ return { sent, total: fcmTokens.length, cleaned };
73
+ }
74
+ export function createSendUserPush(httpsDefaults = getHttpsDefaults()) {
75
+ return onCall(httpsDefaults, handleSendUserPush);
76
+ }
77
+ //# sourceMappingURL=sendUserPush.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sendUserPush.js","sourceRoot":"","sources":["../../../src/features/senderPush/sendUserPush.ts"],"names":[],"mappings":"AAEA,8CAA8C;AAC9C,OAAO,EAAE,MAAM,EAAE,UAAU,EAAwB,MAAM,6BAA6B,CAAC;AACvF,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEvD,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,CAAC;AACjC,MAAM,UAAU,KAAK,CAAI,GAAQ,EAAE,CAAC,GAAG,aAAa;IAClD,OAAO,GAAG,CAAC,MAAM,CAAQ,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC7F,CAAC;AAQD,KAAK,UAAU,kBAAkB,CAAC,OAA2C;IAC3E,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QAClB,MAAM,IAAI,UAAU,CAAC,iBAAiB,EAAE,kBAAkB,CAAC,CAAA;IAC7D,CAAC;IAED,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,GAAG,EAAE,EAAE,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE,CAAsB,CAAA;IAChF,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC;QACrB,MAAM,IAAI,UAAU,CAAC,kBAAkB,EAAE,gCAAgC,CAAC,CAAA;IAC5E,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,CAAA;IAC7D,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;QACpB,OAAO,CAAC,IAAI,CAAC,gCAAgC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QAC1D,MAAM,CAAC,IAAI,CAAC,gCAAgC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAA;QACxD,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAA;IAC1C,CAAC;IAED,MAAM,SAAS,GAAa,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACjE,CAAC,CAAE,OAAO,CAAC,GAAG,CAAC,WAAW,CAAc,CAAC,MAAM,CAAC,OAAO,CAAC;QACxD,CAAC,CAAC,EAAE,CAAA;IAEN,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;QACtB,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAA;IAC1C,CAAC;IAED,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,EAAE,GAAG,OAAO,CAAA;IAClC,MAAM,OAAO,GAAkB;QAC7B,YAAY,EAAE;YACZ,KAAK;YACL,GAAG,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC;YACtC,GAAG,GAAG;SACP;QACD,UAAU,EAAE;YACV,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,IAAI,GAAG;SAChC;QACD,OAAO,EAAE;YACP,GAAG,EAAE,MAAM;YACX,OAAO,EAAE,QAAQ;SAClB;KACF,CAAA;IAED,IAAI,IAAI,GAAG,CAAC,CAAA;IACZ,IAAI,OAAO,GAAG,CAAC,CAAA;IACf,IAAI,UAAU,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAA;IAEnC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;QACpC,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,oBAAoB,CAAC;YAC/C,MAAM,EAAE,IAAI;YACZ,YAAY,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,IAAI,WAAW,EAAE;YAC3D,OAAO;SACR,CAAC,CAAA;QAEF,IAAI,IAAI,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAA;QAEnD,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YAC7B,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;gBACf,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,IAAI,IAAI,EAAE,CAAA;gBAChC,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;gBACrB,IAAI,CACF,IAAI,CAAC,QAAQ,CAAC,mCAAmC,CAAC;oBAClD,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAClC,IAAI,KAAK,EAAE,CAAC;oBACX,IAAI,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC;wBAAE,OAAO,EAAE,CAAA;gBACzC,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QAChB,MAAM,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;YAC7C,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC;SAClC,CAAC,CAAA;IACJ,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,CAAA;AACnD,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,aAAa,GAAG,gBAAgB,EAAE;IACnE,OAAO,MAAM,CAAC,aAAa,EAAE,kBAAkB,CAAC,CAAC;AACnD,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { type DocumentSnapshot, type FirestoreEvent } from 'firebase-functions/v2/firestore';
2
+ import type { Change } from 'firebase-functions/v2';
3
+ export declare function createSyncPublicUser(region?: import("firebase-functions/v2").SupportedRegion): import("firebase-functions/v2").CloudFunction<FirestoreEvent<Change<DocumentSnapshot> | undefined, {
4
+ userId: string;
5
+ }>>;
6
+ export declare const syncPublicUser: import("firebase-functions/v2").CloudFunction<FirestoreEvent<Change<DocumentSnapshot> | undefined, {
7
+ userId: string;
8
+ }>>;
@@ -0,0 +1,59 @@
1
+ import { onDocumentWritten } from 'firebase-functions/v2/firestore';
2
+ import { Timestamp } from 'firebase-admin/firestore';
3
+ import { db } from '../../admin.js';
4
+ import { getRegion } from '../../config/env.js';
5
+ function pickPublicFields(user, publicKeys) {
6
+ const out = {};
7
+ for (const key of publicKeys) {
8
+ if (typeof key !== 'string')
9
+ continue;
10
+ if (key in user)
11
+ out[key] = user[key];
12
+ }
13
+ return out;
14
+ }
15
+ function maskBirthDate(date) {
16
+ const match = /^(\d{2}\/\d{2})\/\d{4}$/.exec(date);
17
+ return (match && match[1]) ? match[1] : date;
18
+ }
19
+ // users -> users_public sync
20
+ async function handleSyncPublicUser(event) {
21
+ const id = event.params.userId;
22
+ const beforeExists = event.data?.before.exists ?? false;
23
+ const afterExists = event.data?.after.exists ?? false;
24
+ const publicRef = db.doc(`users_public/${id}`);
25
+ // Se lo user viene eliminato, elimina anche la versione pubblica
26
+ if (beforeExists && !afterExists) {
27
+ await publicRef.delete();
28
+ return;
29
+ }
30
+ // Se non esiste after, non fare nulla (caso strano ma safe)
31
+ if (!afterExists)
32
+ return;
33
+ const user = event.data.after.data();
34
+ // publicKey: lista campi da esporre
35
+ const publicKeys = Array.isArray(user.publicKey) ? user.publicKey : [];
36
+ const picked = pickPublicFields(user, publicKeys);
37
+ if (user.birthHideYear === true && typeof picked.birthDate === 'string') {
38
+ picked.birthDate = maskBirthDate(picked.birthDate);
39
+ }
40
+ // opzionale: metadati utili
41
+ const updatedAt = user.updatedAt ?? Timestamp.now();
42
+ const createdAt = user.createdAt ?? updatedAt;
43
+ const name = typeof user.name === 'string' ? user.name : '';
44
+ const surname = typeof user.surname === 'string' ? user.surname : '';
45
+ // Set "merge: false" cosi se togli una key da publicKey, sparisce anche dal doc pubblico
46
+ await publicRef.set({
47
+ ...picked,
48
+ id,
49
+ name,
50
+ surname,
51
+ createdAt,
52
+ updatedAt,
53
+ }, { merge: false });
54
+ }
55
+ export function createSyncPublicUser(region = getRegion()) {
56
+ return onDocumentWritten({ region, document: 'users/{userId}' }, handleSyncPublicUser);
57
+ }
58
+ export const syncPublicUser = createSyncPublicUser();
59
+ //# sourceMappingURL=syncPublicUser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syncPublicUser.js","sourceRoot":"","sources":["../../../src/features/syncPublicUser/syncPublicUser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export type { CicInitOptions } from './config/env.js';
2
+ export { cicInit } from './cicInit.js';
3
+ export { getHttpsDefaults } from './config/env.js';
4
+ export { app, db, messaging } from './admin.js';
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export { cicInit } from './cicInit.js';
2
+ export { getHttpsDefaults } from './config/env.js';
3
+ export { app, db, messaging } from './admin.js';
4
+ // export { createSendUserPush } from './features/senderPush/sendUserPush.js';
5
+ // export { createSyncPublicUser } from './features/syncPublicUser/syncPublicUser.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEhD,8EAA8E;AAC9E,sFAAsF"}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "cic-kit-firebase-functions",
3
+ "version": "0.0.1",
4
+ "description": "Firebase Functions riutilizzabili per progetti CIC.",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "default": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "README.md",
18
+ "package.json"
19
+ ],
20
+ "scripts": {
21
+ "build": "tsc",
22
+ "pack": "npm run build && npm pack"
23
+ },
24
+ "peerDependencies": {
25
+ "firebase-admin": "^12.0.0",
26
+ "firebase-functions": "^5.0.0"
27
+ },
28
+ "devDependencies": {
29
+ "typescript": "^5.9.0"
30
+ },
31
+ "keywords": [
32
+ "firebase",
33
+ "firebase-functions",
34
+ "firebase-admin",
35
+ "cloud-functions",
36
+ "cic"
37
+ ],
38
+ "author": "",
39
+ "license": "ISC",
40
+ "type": "module",
41
+ "dependencies": {
42
+ "typescript": "^5.9.3"
43
+ }
44
+ }