@dereekb/firebase-server 13.3.1 → 13.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.
Files changed (31) hide show
  1. package/index.cjs.js +3874 -2940
  2. package/index.esm.js +3865 -2944
  3. package/mailgun/package.json +9 -8
  4. package/model/package.json +9 -8
  5. package/oidc/package.json +15 -8
  6. package/package.json +12 -10
  7. package/src/lib/auth/auth.service.d.ts +4 -1
  8. package/src/lib/auth/auth.service.error.d.ts +46 -0
  9. package/src/lib/env/env.config.d.ts +2 -1
  10. package/src/lib/function/error.d.ts +4 -4
  11. package/src/lib/nest/analytics/analytics.module.d.ts +38 -0
  12. package/src/lib/nest/analytics/analytics.service.d.ts +40 -0
  13. package/src/lib/nest/analytics/analytics.service.listener.d.ts +50 -0
  14. package/src/lib/nest/analytics/index.d.ts +5 -0
  15. package/src/lib/nest/analytics/providers/segment.analytics.module.d.ts +7 -0
  16. package/src/lib/nest/analytics/providers/segment.listener.service.d.ts +24 -0
  17. package/src/lib/nest/controller/auth.context.server.d.ts +2 -1
  18. package/src/lib/nest/function/nest.d.ts +10 -6
  19. package/src/lib/nest/function/schedule.d.ts +5 -5
  20. package/src/lib/nest/index.d.ts +1 -0
  21. package/src/lib/nest/model/analytics.details.d.ts +93 -0
  22. package/src/lib/nest/model/analytics.emit.d.ts +71 -0
  23. package/src/lib/nest/model/analytics.handler.d.ts +56 -0
  24. package/src/lib/nest/model/api.details.d.ts +55 -15
  25. package/src/lib/nest/model/call.model.function.d.ts +5 -0
  26. package/src/lib/nest/model/crud.assert.function.d.ts +2 -2
  27. package/src/lib/nest/model/index.d.ts +3 -0
  28. package/src/lib/nest/model/specifier.function.d.ts +1 -1
  29. package/src/lib/nest/nest.provider.d.ts +6 -2
  30. package/test/package.json +12 -8
  31. package/zoho/package.json +9 -8
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "name": "@dereekb/firebase-server/mailgun",
3
- "version": "13.3.1",
3
+ "version": "13.4.1",
4
4
  "peerDependencies": {
5
- "@dereekb/firebase": "13.3.1",
6
- "@dereekb/firebase-server": "13.3.1",
7
- "@dereekb/date": "13.3.1",
8
- "@dereekb/nestjs": "13.3.1",
9
- "@dereekb/model": "13.3.1",
10
- "@dereekb/rxjs": "13.3.1",
11
- "@dereekb/util": "13.3.1"
5
+ "@dereekb/analytics": "13.4.1",
6
+ "@dereekb/firebase": "13.4.1",
7
+ "@dereekb/firebase-server": "13.4.1",
8
+ "@dereekb/date": "13.4.1",
9
+ "@dereekb/nestjs": "13.4.1",
10
+ "@dereekb/model": "13.4.1",
11
+ "@dereekb/rxjs": "13.4.1",
12
+ "@dereekb/util": "13.4.1"
12
13
  },
13
14
  "exports": {
14
15
  "./package.json": "./package.json",
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "name": "@dereekb/firebase-server/model",
3
- "version": "13.3.1",
3
+ "version": "13.4.1",
4
4
  "peerDependencies": {
5
- "@dereekb/date": "13.3.1",
6
- "@dereekb/firebase": "13.3.1",
7
- "@dereekb/firebase-server": "13.3.1",
8
- "@dereekb/model": "13.3.1",
9
- "@dereekb/nestjs": "13.3.1",
10
- "@dereekb/rxjs": "13.3.1",
11
- "@dereekb/util": "13.3.1",
5
+ "@dereekb/analytics": "13.4.1",
6
+ "@dereekb/date": "13.4.1",
7
+ "@dereekb/firebase": "13.4.1",
8
+ "@dereekb/firebase-server": "13.4.1",
9
+ "@dereekb/model": "13.4.1",
10
+ "@dereekb/nestjs": "13.4.1",
11
+ "@dereekb/rxjs": "13.4.1",
12
+ "@dereekb/util": "13.4.1",
12
13
  "@nestjs/common": "^11.1.16",
13
14
  "@nestjs/config": "^4.0.3",
14
15
  "archiver": "^7.0.0",
package/oidc/package.json CHANGED
@@ -1,14 +1,21 @@
1
1
  {
2
2
  "name": "@dereekb/firebase-server/oidc",
3
- "version": "13.3.1",
3
+ "version": "13.4.1",
4
4
  "peerDependencies": {
5
- "@dereekb/date": "13.3.1",
6
- "@dereekb/model": "13.3.1",
7
- "@dereekb/nestjs": "13.3.1",
8
- "@dereekb/rxjs": "13.3.1",
9
- "@dereekb/firebase": "13.3.1",
10
- "@dereekb/util": "13.3.1",
11
- "@dereekb/zoho": "13.3.1",
5
+ "@dereekb/analytics": "13.4.1",
6
+ "@dereekb/date": "13.4.1",
7
+ "@dereekb/firebase": "13.4.1",
8
+ "@dereekb/firebase-server": "13.4.1",
9
+ "@dereekb/model": "13.4.1",
10
+ "@dereekb/nestjs": "13.4.1",
11
+ "@dereekb/rxjs": "13.4.1",
12
+ "@dereekb/util": "13.4.1",
13
+ "@dereekb/zoho": "13.4.1",
14
+ "@nestjs/common": "^11.1.16",
15
+ "@nestjs/config": "^4.0.3",
16
+ "express": "^5.0.0",
17
+ "firebase-admin": "^13.0.0",
18
+ "nanoid": "^5.1.7",
12
19
  "oidc-provider": "^9.7.0"
13
20
  },
14
21
  "exports": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dereekb/firebase-server",
3
- "version": "13.3.1",
3
+ "version": "13.4.1",
4
4
  "exports": {
5
5
  "./test": {
6
6
  "module": "./test/index.esm.js",
@@ -43,14 +43,15 @@
43
43
  "main": "./index.cjs.js",
44
44
  "types": "./src/index.d.ts",
45
45
  "peerDependencies": {
46
- "@dereekb/date": "13.3.1",
47
- "@dereekb/dbx-core": "13.3.1",
48
- "@dereekb/firebase": "13.3.1",
49
- "@dereekb/model": "13.3.1",
50
- "@dereekb/nestjs": "13.3.1",
51
- "@dereekb/rxjs": "13.3.1",
52
- "@dereekb/util": "13.3.1",
53
- "@dereekb/zoho": "13.3.1",
46
+ "@dereekb/analytics": "13.4.1",
47
+ "@dereekb/date": "13.4.1",
48
+ "@dereekb/dbx-core": "13.4.1",
49
+ "@dereekb/firebase": "13.4.1",
50
+ "@dereekb/model": "13.4.1",
51
+ "@dereekb/nestjs": "13.4.1",
52
+ "@dereekb/rxjs": "13.4.1",
53
+ "@dereekb/util": "13.4.1",
54
+ "@dereekb/zoho": "13.4.1",
54
55
  "@google-cloud/firestore": "^7.11.6",
55
56
  "@google-cloud/storage": "^7.19.0",
56
57
  "@nestjs/common": "^11.1.16",
@@ -65,9 +66,10 @@
65
66
  "firebase-admin": "^13.0.0",
66
67
  "firebase-functions": "^7.0.0",
67
68
  "firebase-functions-test": "3.4.1",
68
- "oidc-provider": "^9.7.0",
69
69
  "jsonwebtoken": "^9.0.0",
70
70
  "make-error": "^1.3.0",
71
+ "nanoid": "^5.1.7",
72
+ "oidc-provider": "^9.7.0",
71
73
  "rxjs": "^7.8.0",
72
74
  "ts-essentials": "^10.0.0"
73
75
  },
@@ -322,7 +322,10 @@ export interface FirebaseServerAuthInitializeNewUser<D = unknown> {
322
322
  */
323
323
  readonly email?: EmailAddress;
324
324
  /**
325
- * Phone for the new user, if applicable.
325
+ * Phone for the new user, if applicable. Must be a valid {@link E164PhoneNumber} (e.g. `'+17206620850'`).
326
+ *
327
+ * Firebase Auth requires E.164 format. If the value is not valid, {@link FirebaseServerAuthUserBadInputError}
328
+ * is thrown with code `auth/invalid-phone-number`.
326
329
  */
327
330
  readonly phone?: E164PhoneNumber;
328
331
  /**
@@ -1,4 +1,50 @@
1
+ import { type FirebaseErrorCode } from '@dereekb/firebase';
1
2
  import { BaseError } from 'make-error';
3
+ /**
4
+ * The type of identifier that caused the user-already-exists conflict.
5
+ */
6
+ export type FirebaseServerAuthUserExistsErrorIdentifierType = 'phone' | 'email';
7
+ /**
8
+ * Thrown by {@link AbstractFirebaseServerNewUserService.createNewUser} when Firebase Auth rejects
9
+ * user creation because the provided phone number or email is already associated with another account.
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * try {
14
+ * await newUserService.initializeNewUser({ email, phone });
15
+ * } catch (e) {
16
+ * if (e instanceof FirebaseServerAuthUserExistsError && e.identifierType === 'phone') {
17
+ * const existingUser = await auth.getUserByPhoneNumber(e.identifierValue);
18
+ * }
19
+ * }
20
+ * ```
21
+ */
22
+ export declare class FirebaseServerAuthUserExistsError extends BaseError {
23
+ readonly code: FirebaseErrorCode;
24
+ readonly identifierType: FirebaseServerAuthUserExistsErrorIdentifierType;
25
+ readonly identifierValue: string;
26
+ constructor(code: FirebaseErrorCode, identifierType: FirebaseServerAuthUserExistsErrorIdentifierType, identifierValue: string);
27
+ }
28
+ /**
29
+ * Thrown by {@link AbstractFirebaseServerNewUserService.createNewUser} when Firebase Auth rejects
30
+ * user creation due to invalid input (e.g., a malformed phone number).
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * try {
35
+ * await newUserService.initializeNewUser({ email, phone: 'not-e164' });
36
+ * } catch (e) {
37
+ * if (e instanceof FirebaseServerAuthUserBadInputError) {
38
+ * console.log(`Bad input (${e.code}): ${e.inputValue}`);
39
+ * }
40
+ * }
41
+ * ```
42
+ */
43
+ export declare class FirebaseServerAuthUserBadInputError extends BaseError {
44
+ readonly code: FirebaseErrorCode;
45
+ readonly inputValue: string;
46
+ constructor(code: FirebaseErrorCode, inputValue: string, message?: string);
47
+ }
2
48
  /**
3
49
  * Thrown by sendSetupDetails() if the user has no setup configuration available, meaning they probably already have accepted their invite or is in an invalid state.
4
50
  */
@@ -1,12 +1,13 @@
1
1
  import { type InjectionToken, type Provider } from '@nestjs/common';
2
2
  import { type ServerEnvironmentConfig } from '@dereekb/nestjs';
3
+ import { type WebsiteUrlWithPrefix } from '@dereekb/util';
3
4
  /**
4
5
  * Extension of ServerEnvironmentConfig for Firebase server applications.
5
6
  *
6
7
  * Requires appUrl to be provided.
7
8
  */
8
9
  export interface FirebaseServerEnvironmentConfig extends ServerEnvironmentConfig {
9
- readonly appUrl: string;
10
+ readonly appUrl: WebsiteUrlWithPrefix;
10
11
  }
11
12
  /**
12
13
  * Token to access a configured FirebaseServerEnvironmentServiceConfig for the app.
@@ -1,4 +1,4 @@
1
- import { type ErrorMessageOrPartialServerError, type ServerError, type StringErrorCode, type ThrowErrorFunction } from '@dereekb/util';
1
+ import { type ErrorMessageOrPartialServerError, type Maybe, type ServerError, type StringErrorCode, type ThrowErrorFunction } from '@dereekb/util';
2
2
  import type * as admin from 'firebase-admin';
3
3
  import { type FirebaseErrorCode } from '@dereekb/firebase';
4
4
  import { HttpsError } from 'firebase-functions/https';
@@ -119,15 +119,15 @@ export declare function firebaseServerErrorInfo(e: unknown): FirebaseServerError
119
119
  /**
120
120
  * Returns a tuple of [firebaseErrorCode, errorInfo] for pattern-matching on Firebase error codes.
121
121
  */
122
- export declare function firebaseServerErrorInfoCodePair(e: unknown): [FirebaseErrorCode | undefined, FirebaseServerErrorInfo];
122
+ export declare function firebaseServerErrorInfoCodePair(e: unknown): [Maybe<FirebaseErrorCode>, FirebaseServerErrorInfo];
123
123
  /**
124
124
  * Returns a tuple of [serverError, errorInfo] for pattern-matching on embedded server error details.
125
125
  */
126
- export declare function firebaseServerErrorInfoServerErrorPair(e: unknown): [ServerError | undefined, FirebaseServerErrorInfo];
126
+ export declare function firebaseServerErrorInfoServerErrorPair(e: unknown): [Maybe<ServerError>, FirebaseServerErrorInfo];
127
127
  /**
128
128
  * Returns a tuple of [serverErrorCode, errorInfo] for pattern-matching on server error string codes.
129
129
  */
130
- export declare function firebaseServerErrorInfoServerErrorCodePair(e: unknown): [StringErrorCode | undefined, FirebaseServerErrorInfo];
130
+ export declare function firebaseServerErrorInfoServerErrorCodePair(e: unknown): [Maybe<StringErrorCode>, FirebaseServerErrorInfo];
131
131
  /**
132
132
  * Handles a caught error if it is a Firebase Admin error, passing it to the given handler function.
133
133
  *
@@ -0,0 +1,38 @@
1
+ import { type ModuleMetadata } from '@nestjs/common';
2
+ import { type Maybe } from '@dereekb/util';
3
+ /**
4
+ * Configuration for {@link appAnalyticsModuleMetadata}.
5
+ */
6
+ export interface ProvideAppAnalyticsMetadataConfig extends Pick<ModuleMetadata, 'imports' | 'exports' | 'providers'> {
7
+ /**
8
+ * Optional dependency module that provides a {@link FirebaseServerAnalyticsServiceListener} implementation.
9
+ *
10
+ * If omitted, the {@link FirebaseServerAnalyticsService} falls back to a no-op listener.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * appAnalyticsModuleMetadata({
15
+ * dependencyModule: FirebaseServerAnalyticsSegmentModule
16
+ * })
17
+ * ```
18
+ */
19
+ readonly dependencyModule?: Maybe<Required<ModuleMetadata>['imports'][0]>;
20
+ }
21
+ /**
22
+ * Generates NestJS {@link ModuleMetadata} for an app's analytics module.
23
+ *
24
+ * Provides {@link FirebaseServerAnalyticsService} and registers it as the
25
+ * {@link ON_CALL_MODEL_ANALYTICS_SERVICE} token for the onCall dispatch chain.
26
+ *
27
+ * @param config - the configuration including an optional dependency module and additional providers
28
+ * @returns module metadata ready for use with `@Module()`
29
+ *
30
+ * @example
31
+ * ```ts
32
+ * @Module(appAnalyticsModuleMetadata({
33
+ * dependencyModule: FirebaseServerAnalyticsSegmentModule
34
+ * }))
35
+ * export class AppAnalyticsModule {}
36
+ * ```
37
+ */
38
+ export declare function appAnalyticsModuleMetadata(config: ProvideAppAnalyticsMetadataConfig): ModuleMetadata;
@@ -0,0 +1,40 @@
1
+ import { type AnalyticsEvent, type AnalyticsEventData, type AnalyticsEventName, type AnalyticsUser } from '@dereekb/analytics';
2
+ import { type Maybe } from '@dereekb/util';
3
+ import { type OnCallModelAnalyticsEvent, OnCallModelAnalyticsService } from '../model/analytics.handler';
4
+ import { FirebaseServerAnalyticsServiceListener } from './analytics.service.listener';
5
+ /**
6
+ * Reference interface for injecting {@link FirebaseServerAnalyticsService}.
7
+ */
8
+ export interface FirebaseServerAnalyticsServiceRef {
9
+ readonly analyticsService: FirebaseServerAnalyticsService;
10
+ }
11
+ /**
12
+ * Central server-side analytics service that delegates events to a registered {@link FirebaseServerAnalyticsServiceListener}.
13
+ *
14
+ * Extends {@link OnCallModelAnalyticsService} for CRUD lifecycle events and adds general-purpose
15
+ * methods (`sendEventData`, `sendEventType`, `sendEvent`, `sendUserPropertiesEvent`) mirroring the
16
+ * Angular {@link DbxAnalyticsService}.
17
+ *
18
+ * If no listener is provided via DI, a no-op listener is used and a warning is logged.
19
+ *
20
+ * Provided via {@link appAnalyticsModuleMetadata} with an optional dependency module
21
+ * (e.g., {@link FirebaseServerAnalyticsSegmentModule}).
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * // Send a custom event from a NestJS service
26
+ * analyticsService.sendEventData(uid, 'Report Generated', { reportId: 'rpt_123' });
27
+ *
28
+ * // Send user properties update
29
+ * analyticsService.sendUserPropertiesEvent({ user: uid, properties: { plan: 'premium' } });
30
+ * ```
31
+ */
32
+ export declare class FirebaseServerAnalyticsService extends OnCallModelAnalyticsService {
33
+ private readonly _listener;
34
+ constructor(listener: FirebaseServerAnalyticsServiceListener);
35
+ handleOnCallAnalyticsEvent(event: OnCallModelAnalyticsEvent): void;
36
+ sendEventData(userId: Maybe<string>, name: AnalyticsEventName, data: AnalyticsEventData): void;
37
+ sendEventType(userId: Maybe<string>, eventType: AnalyticsEventName): void;
38
+ sendEvent(userId: Maybe<string>, event: AnalyticsEvent): void;
39
+ sendUserPropertiesEvent(user: AnalyticsUser): void;
40
+ }
@@ -0,0 +1,50 @@
1
+ import { type AnalyticsEvent, type AnalyticsEventData, type AnalyticsEventName, type AnalyticsUser } from '@dereekb/analytics';
2
+ import { type Maybe } from '@dereekb/util';
3
+ import { type OnCallModelAnalyticsEvent } from '../model/analytics.handler';
4
+ /**
5
+ * Listener for {@link FirebaseServerAnalyticsService}.
6
+ * Events are forwarded from FirebaseServerAnalyticsService to this listener
7
+ * for processing by an analytics provider (e.g., Segment).
8
+ */
9
+ export declare abstract class FirebaseServerAnalyticsServiceListener {
10
+ /**
11
+ * Handles a structured analytics event from the onCall CRUD dispatch chain.
12
+ *
13
+ * @param event - the lifecycle event containing call context, model type, and properties
14
+ */
15
+ abstract handleOnCallAnalyticsEvent(event: OnCallModelAnalyticsEvent): void;
16
+ /**
17
+ * Sends a named analytics event with a data payload.
18
+ *
19
+ * @param userId - the user to associate with the event, or nullish to skip
20
+ * @param name - the event name (e.g., `'Item Purchased'`)
21
+ * @param data - key-value data attached to the event
22
+ */
23
+ abstract sendEventData(userId: Maybe<string>, name: AnalyticsEventName, data: AnalyticsEventData): void;
24
+ /**
25
+ * Sends a named analytics event with no additional data.
26
+ *
27
+ * @param userId - the user to associate with the event, or nullish to skip
28
+ * @param eventType - the event name to track
29
+ */
30
+ abstract sendEventType(userId: Maybe<string>, eventType: AnalyticsEventName): void;
31
+ /**
32
+ * Sends a fully constructed {@link AnalyticsEvent} object.
33
+ *
34
+ * @param userId - the user to associate with the event, or nullish to skip
35
+ * @param event - the event containing name, optional value, and data
36
+ */
37
+ abstract sendEvent(userId: Maybe<string>, event: AnalyticsEvent): void;
38
+ /**
39
+ * Sends a user properties/traits update to the analytics provider (e.g., Segment `identify()`).
40
+ *
41
+ * @param user - the user whose properties are being synced
42
+ */
43
+ abstract sendUserPropertiesEvent(user: AnalyticsUser): void;
44
+ }
45
+ /**
46
+ * Creates a default no-op {@link FirebaseServerAnalyticsServiceListener}.
47
+ *
48
+ * Used when no analytics provider is configured. All methods are no-ops.
49
+ */
50
+ export declare function noopFirebaseServerAnalyticsServiceListener(): FirebaseServerAnalyticsServiceListener;
@@ -0,0 +1,5 @@
1
+ export * from './analytics.module';
2
+ export * from './analytics.service';
3
+ export * from './analytics.service.listener';
4
+ export * from './providers/segment.listener.service';
5
+ export * from './providers/segment.analytics.module';
@@ -0,0 +1,7 @@
1
+ /**
2
+ * A pre-configured dependency module that can be imported into the {@link appAnalyticsModuleMetadata} call.
3
+ *
4
+ * This module provides the {@link FirebaseServerAnalyticsSegmentListenerService} as the {@link FirebaseServerAnalyticsServiceListener} implementation and exports {@link SegmentServiceModule} for use in the app.
5
+ */
6
+ export declare class FirebaseServerAnalyticsSegmentModule {
7
+ }
@@ -0,0 +1,24 @@
1
+ import { type AnalyticsEvent, type AnalyticsEventData, type AnalyticsEventName, type AnalyticsUser } from '@dereekb/analytics';
2
+ import { type Maybe } from '@dereekb/util';
3
+ import { SegmentService } from '@dereekb/analytics/nestjs';
4
+ import { FirebaseServerAnalyticsServiceListener } from '../analytics.service.listener';
5
+ import { type OnCallModelAnalyticsEvent } from '../../model/analytics.handler';
6
+ /**
7
+ * Segment implementation of {@link FirebaseServerAnalyticsServiceListener}.
8
+ *
9
+ * Routes analytics events to the {@link SegmentService}:
10
+ * - CRUD lifecycle events → `tryTrack()` with call/model/lifecycle context as properties
11
+ * - General events (`sendEventData`, `sendEventType`, `sendEvent`) → `tryTrack()`
12
+ * - User properties (`sendUserPropertiesEvent`) → `identify()`
13
+ *
14
+ * Provided by {@link FirebaseServerAnalyticsSegmentModule}.
15
+ */
16
+ export declare class FirebaseServerAnalyticsSegmentListenerService extends FirebaseServerAnalyticsServiceListener {
17
+ private readonly _segmentService;
18
+ constructor(_segmentService: SegmentService);
19
+ handleOnCallAnalyticsEvent(event: OnCallModelAnalyticsEvent): void;
20
+ sendEventData(userId: Maybe<string>, name: AnalyticsEventName, data: AnalyticsEventData): void;
21
+ sendEventType(userId: Maybe<string>, eventType: AnalyticsEventName): void;
22
+ sendEvent(userId: Maybe<string>, event: AnalyticsEvent): void;
23
+ sendUserPropertiesEvent(user: AnalyticsUser): void;
24
+ }
@@ -1,5 +1,6 @@
1
1
  import { type AuthData } from '../../type';
2
2
  import { type Request } from 'express';
3
+ import { type FirebaseAuthUserId } from '@dereekb/firebase';
3
4
  /**
4
5
  * Minimum auth data shape shared by all server-side auth contexts.
5
6
  *
@@ -9,7 +10,7 @@ export interface FirebaseServerAuthData extends AuthData {
9
10
  /**
10
11
  * The authenticated user's UID.
11
12
  */
12
- readonly uid: string;
13
+ readonly uid: FirebaseAuthUserId;
13
14
  }
14
15
  /**
15
16
  * Extends Express Request with an `auth` field for authenticated requests.
@@ -22,26 +22,30 @@ export type NestRef<N> = {
22
22
  readonly nest: N;
23
23
  };
24
24
  /**
25
- * Augments a request type with a typed nest context. This is the primary request shape used by
26
- * nest-integrated Firebase function handlers throughout the codebase.
25
+ * Augments a request type with a typed nest context and the raw {@link INestApplicationContext}.
26
+ *
27
+ * This is the primary request shape used by nest-integrated Firebase function handlers throughout the codebase.
28
+ * It extends {@link NestApplicationContextRequest} so that handlers always have access to both the
29
+ * typed domain context and the underlying NestJS application context.
27
30
  *
28
31
  * @typeParam N - The nest context type, typically an application-specific context class.
29
32
  * @typeParam R - The base request type to augment.
30
33
  */
31
- export type NestContextRequest<N, R> = R & {
34
+ export type NestContextRequest<N, R> = NestApplicationContextRequest<R> & {
32
35
  readonly nest: N;
33
36
  };
34
37
  /**
35
38
  * Creates a new request object with the typed nest context spread into it.
36
39
  *
37
40
  * Unlike {@link injectNestApplicationContextIntoRequest}, this attaches a domain-specific context rather
38
- * than the raw NestJS application context.
41
+ * than the raw NestJS application context. The input request must already be a {@link NestApplicationContextRequest}
42
+ * so that the resulting {@link NestContextRequest} retains access to the raw application context.
39
43
  *
40
44
  * @param nest - The typed nest context to attach.
41
- * @param request - The base request to augment.
45
+ * @param request - The base request to augment (must include the nestApplication reference).
42
46
  * @returns A new object combining the request properties with the nest context.
43
47
  */
44
- export declare function injectNestIntoRequest<N, R>(nest: N, request: R): NestContextRequest<N, R>;
48
+ export declare function injectNestIntoRequest<N, R>(nest: N, request: NestApplicationContextRequest<R>): NestContextRequest<N, R>;
45
49
  /**
46
50
  * Creates a new request object with the raw {@link INestApplicationContext} spread into it.
47
51
  *
@@ -1,4 +1,4 @@
1
- import { type Minutes, type PromiseOrValue } from '@dereekb/util';
1
+ import { type Minutes, type PromiseOrValue, type Seconds, type TimezoneString } from '@dereekb/util';
2
2
  import { type MakeNestContext, type NestApplicationFunctionFactory } from '../nest.provider';
3
3
  import { type NestApplicationContextRequest, type NestContextRequest } from './nest';
4
4
  /**
@@ -23,7 +23,7 @@ export interface OnScheduleConfig {
23
23
  /**
24
24
  * Optional timezone to specify.
25
25
  */
26
- readonly timezone?: string;
26
+ readonly timezone?: TimezoneString;
27
27
  /**
28
28
  * The number of retry attempts for a failed run.
29
29
  */
@@ -31,15 +31,15 @@ export interface OnScheduleConfig {
31
31
  /**
32
32
  * The time limit for retrying.
33
33
  */
34
- readonly maxRetrySeconds?: number;
34
+ readonly maxRetrySeconds?: Seconds;
35
35
  /**
36
36
  * The minimum time to wait before retying.
37
37
  */
38
- readonly minBackoffSeconds?: number;
38
+ readonly minBackoffSeconds?: Seconds;
39
39
  /**
40
40
  * The maximum time to wait before retrying.
41
41
  */
42
- readonly maxBackoffSeconds?: number;
42
+ readonly maxBackoffSeconds?: Seconds;
43
43
  /**
44
44
  * The time between will double max doublings times.
45
45
  */
@@ -1,3 +1,4 @@
1
+ export * from './analytics';
1
2
  export * from './auth';
2
3
  export * from './controller';
3
4
  export * from './development';
@@ -0,0 +1,93 @@
1
+ import { type OnCallModelAnalyticsService, type OnCallModelAnalyticsEvent } from './analytics.handler';
2
+ import { type AuthData } from '../../type';
3
+ import { type NestContextCallableRequestWithAuth } from '../function/nest';
4
+ import { type ModelFirebaseCrudFunctionSpecifierRef, type FirebaseAuthUserId, type OnCallFunctionType, type FirestoreModelType, type ModelFirebaseCrudFunctionSpecifier } from '@dereekb/firebase';
5
+ import { type Maybe } from '@dereekb/util';
6
+ /**
7
+ * Per-invocation analytics emitter passed to lifecycle callbacks.
8
+ *
9
+ * Pre-binds the analytics service, dispatch context, and lifecycle stage so callbacks
10
+ * can send events with convenience methods without manually constructing full event objects.
11
+ *
12
+ * Analogous to how {@link DbxAnalyticsService} is passed to {@link DbxActionAnalyticsConfig} callbacks.
13
+ */
14
+ export interface OnCallAnalyticsEmitter {
15
+ readonly service: OnCallModelAnalyticsService;
16
+ readonly context: OnCallAnalyticsContext;
17
+ readonly lifecycle: OnCallModelAnalyticsEvent['lifecycle'];
18
+ /**
19
+ * Send a named event with optional properties.
20
+ * Context (call, modelType, specifier, uid, lifecycle) is auto-filled from the dispatch context.
21
+ */
22
+ sendEvent(event: string, properties?: Record<string, any>): void;
23
+ /**
24
+ * Send a named event type with no properties.
25
+ */
26
+ sendEventType(event: string): void;
27
+ }
28
+ /**
29
+ * Analytics lifecycle configuration for a single onCall model handler.
30
+ *
31
+ * Mirrors the frontend {@link DbxActionAnalyticsConfig} pattern: lifecycle callbacks
32
+ * receive an {@link OnCallAnalyticsEmitter} and the typed request, and are responsible
33
+ * for deciding what analytics events to emit.
34
+ *
35
+ * @typeParam R - The request type passed to the handler function.
36
+ * @typeParam O - The output/return type of the handler function.
37
+ */
38
+ export interface OnCallModelFunctionAnalyticsDetails<R = any, O = any> {
39
+ /**
40
+ * Called before handler executes.
41
+ */
42
+ readonly onTriggered?: OnCallAnalyticsLifecycleFn<R, void>;
43
+ /**
44
+ * Called after successful handler completion.
45
+ */
46
+ readonly onSuccess?: OnCallAnalyticsLifecycleFn<R, O>;
47
+ /**
48
+ * Called when handler throws.
49
+ */
50
+ readonly onError?: OnCallAnalyticsErrorFn<R>;
51
+ /**
52
+ * Called always after handler completes (success or error).
53
+ */
54
+ readonly onComplete?: OnCallAnalyticsCompleteFn<R, O>;
55
+ }
56
+ /**
57
+ * Context available to the dispatch chain for building analytics emitters.
58
+ *
59
+ * Captured at the start of a handler invocation and used to auto-fill event fields
60
+ * (call, modelType, specifier, uid, auth) on every emitted {@link OnCallModelAnalyticsEvent}.
61
+ *
62
+ * @typeParam I - The input/request data type.
63
+ */
64
+ export interface OnCallAnalyticsContext<I = any> {
65
+ /** The CRUD operation type (e.g., `'create'`, `'update'`). */
66
+ readonly call: OnCallFunctionType;
67
+ /** The model type being operated on (e.g., `'guestbook'`). */
68
+ readonly modelType: FirestoreModelType;
69
+ /** Optional operation specifier for variant handlers. */
70
+ readonly specifier: Maybe<ModelFirebaseCrudFunctionSpecifier>;
71
+ /** The Firebase Auth UID of the calling user. */
72
+ readonly uid?: FirebaseAuthUserId;
73
+ /** The full Firebase Auth context. */
74
+ readonly auth?: AuthData;
75
+ /** The typed request data. */
76
+ readonly data?: I;
77
+ /** The full NestContext callable request with auth and specifier. */
78
+ readonly request: NestContextCallableRequestWithAuth<unknown, I> & ModelFirebaseCrudFunctionSpecifierRef;
79
+ }
80
+ /**
81
+ * Lifecycle function for onTriggered/onSuccess.
82
+ *
83
+ * Receives the {@link OnCallAnalyticsEmitter} for sending events and the typed request.
84
+ */
85
+ export type OnCallAnalyticsLifecycleFn<R, O> = (emitter: OnCallAnalyticsEmitter, request: R, result?: O) => void;
86
+ /**
87
+ * Lifecycle function for onError.
88
+ */
89
+ export type OnCallAnalyticsErrorFn<R> = (emitter: OnCallAnalyticsEmitter, request: R, error: unknown) => void;
90
+ /**
91
+ * Lifecycle function for onComplete.
92
+ */
93
+ export type OnCallAnalyticsCompleteFn<R, O> = (emitter: OnCallAnalyticsEmitter, request: R, result?: O, error?: unknown) => void;