@causa/runtime-google 0.39.1 → 0.40.0

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.
@@ -1,9 +1,20 @@
1
1
  import { type DynamicModule } from '@nestjs/common';
2
2
  import { type AppOptions } from 'firebase-admin/app';
3
+ import { type Settings } from 'firebase-admin/firestore';
4
+ /**
5
+ * Options for the various Firebase services (other than the base Firebase app).
6
+ */
7
+ export type FirebaseModuleServiceOptions = {
8
+ /**
9
+ * Options for the Firestore client.
10
+ * The default configuration sets {@link Settings.ignoreUndefinedProperties} to `true`.
11
+ */
12
+ firestore?: Settings;
13
+ };
3
14
  /**
4
15
  * Options when configuring the {@link FirebaseModule}.
5
16
  */
6
- export type FirebaseModuleOptions = AppOptions & {
17
+ export type FirebaseModuleOptions = AppOptions & FirebaseModuleServiceOptions & {
7
18
  /**
8
19
  * The name of the Firebase app to initialize.
9
20
  */
@@ -36,7 +47,8 @@ export declare class FirebaseModule {
36
47
  * {@link initializeApp}.
37
48
  * When testing, this avoids repeatedly initializing the same app, which would result in an error.
38
49
  *
50
+ * @param options Options for the Firebase services (other than the base Firebase app).
39
51
  * @returns The module.
40
52
  */
41
- static forTesting(): DynamicModule;
53
+ static forTesting(options?: FirebaseModuleServiceOptions): DynamicModule;
42
54
  }
@@ -9,22 +9,48 @@ import { Module, } from '@nestjs/common';
9
9
  import { initializeApp } from 'firebase-admin/app';
10
10
  import { AppCheck, getAppCheck } from 'firebase-admin/app-check';
11
11
  import { Auth, getAuth } from 'firebase-admin/auth';
12
- import { Firestore, getFirestore } from 'firebase-admin/firestore';
13
- import { Messaging, getMessaging } from 'firebase-admin/messaging';
12
+ import { Firestore, getFirestore, } from 'firebase-admin/firestore';
13
+ import { getMessaging, Messaging } from 'firebase-admin/messaging';
14
14
  import { getDefaultFirebaseApp } from './app.js';
15
15
  import { FirestoreAdminClient } from './firestore-admin-client.type.js';
16
16
  import { FIREBASE_APP_TOKEN } from './inject-firebase-app.decorator.js';
17
17
  import { FirebaseLifecycleService } from './lifecycle.service.js';
18
+ /**
19
+ * The NestJS injection token for Firestore settings.
20
+ */
21
+ const FIRESTORE_SETTINGS_TOKEN = 'CAUSA_FIRESTORE_SETTINGS';
22
+ /**
23
+ * The default Firestore settings to use when initializing the Firestore client.
24
+ */
25
+ const DEFAULT_FIRESTORE_SETTINGS = {
26
+ ignoreUndefinedProperties: true,
27
+ };
18
28
  /**
19
29
  * The providers for service-specific Firebase clients.
20
- * Those do not have any options as they inherit them from the `App`.
30
+ * Options for the services can be passed using injection tokens.
21
31
  */
22
32
  const childProviders = [
23
33
  { provide: Auth, useFactory: getAuth, inject: [FIREBASE_APP_TOKEN] },
24
34
  {
25
35
  provide: Firestore,
26
- useFactory: getFirestore,
27
- inject: [FIREBASE_APP_TOKEN],
36
+ useFactory: (app, settings) => {
37
+ const firestore = getFirestore(app);
38
+ try {
39
+ // Firestore settings can only be set once, but we cannot know if they've already been set without using private
40
+ // APIs. Calling this several times could occur in testing, when the default app is reused.
41
+ firestore.settings(settings);
42
+ return firestore;
43
+ }
44
+ catch (error) {
45
+ // The Firestore SDK does not type the error more precisely.
46
+ if (error instanceof Error &&
47
+ error.message.includes('Firestore has already been initialized.')) {
48
+ return firestore;
49
+ }
50
+ throw error;
51
+ }
52
+ },
53
+ inject: [FIREBASE_APP_TOKEN, FIRESTORE_SETTINGS_TOKEN],
28
54
  },
29
55
  { provide: AppCheck, useFactory: getAppCheck, inject: [FIREBASE_APP_TOKEN] },
30
56
  {
@@ -40,20 +66,22 @@ const childProviders = [
40
66
  /**
41
67
  * Creates the module metadata for the {@link FirebaseModule}.
42
68
  *
69
+ * @param useDefaultFactory Whether to use {@link getDefaultFirebaseApp} to (re)use the default Firebase app.
43
70
  * @param options Options when configuring the {@link FirebaseModule}.
44
- * If set to `default`, the default Firebase app will be (re)used using {@link getDefaultFirebaseApp}.
71
+ * If the default Firebase app is used, app options are ignored.
45
72
  * @returns The module metadata.
46
73
  */
47
- function createModuleMetadata(options = {}) {
48
- const useDefaultFactory = options === 'default';
49
- const { appName, ...appOptions } = useDefaultFactory
50
- ? {}
51
- : options;
74
+ function createModuleMetadata(useDefaultFactory, options) {
75
+ const { appName, firestore, ...appOptions } = options;
52
76
  const appFactory = useDefaultFactory
53
77
  ? getDefaultFirebaseApp
54
78
  : () => initializeApp(appOptions, appName);
55
79
  const providers = [
56
80
  { provide: FIREBASE_APP_TOKEN, useFactory: appFactory },
81
+ {
82
+ provide: FIRESTORE_SETTINGS_TOKEN,
83
+ useValue: { ...DEFAULT_FIRESTORE_SETTINGS, ...firestore },
84
+ },
57
85
  ...childProviders,
58
86
  ];
59
87
  if (!useDefaultFactory) {
@@ -79,7 +107,7 @@ let FirebaseModule = FirebaseModule_1 = class FirebaseModule {
79
107
  */
80
108
  static forRoot(options = {}) {
81
109
  return {
82
- ...createModuleMetadata(options),
110
+ ...createModuleMetadata(false, options),
83
111
  module: FirebaseModule_1,
84
112
  global: true,
85
113
  };
@@ -92,7 +120,7 @@ let FirebaseModule = FirebaseModule_1 = class FirebaseModule {
92
120
  */
93
121
  static register(options = {}) {
94
122
  return {
95
- ...createModuleMetadata(options),
123
+ ...createModuleMetadata(false, options),
96
124
  module: FirebaseModule_1,
97
125
  };
98
126
  }
@@ -102,17 +130,18 @@ let FirebaseModule = FirebaseModule_1 = class FirebaseModule {
102
130
  * {@link initializeApp}.
103
131
  * When testing, this avoids repeatedly initializing the same app, which would result in an error.
104
132
  *
133
+ * @param options Options for the Firebase services (other than the base Firebase app).
105
134
  * @returns The module.
106
135
  */
107
- static forTesting() {
136
+ static forTesting(options = {}) {
108
137
  return {
109
- ...createModuleMetadata('default'),
138
+ ...createModuleMetadata(true, options),
110
139
  module: FirebaseModule_1,
111
140
  global: true,
112
141
  };
113
142
  }
114
143
  };
115
144
  FirebaseModule = FirebaseModule_1 = __decorate([
116
- Module(createModuleMetadata())
145
+ Module(createModuleMetadata(false, {}))
117
146
  ], FirebaseModule);
118
147
  export { FirebaseModule };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@causa/runtime-google",
3
- "version": "0.39.1",
3
+ "version": "0.40.0",
4
4
  "description": "An extension to the Causa runtime SDK (`@causa/runtime`), providing Google-specific features.",
5
5
  "repository": "github:causa-io/runtime-typescript-google",
6
6
  "license": "ISC",
@@ -29,49 +29,49 @@
29
29
  "test:cov": "npm run test -- --coverage"
30
30
  },
31
31
  "dependencies": {
32
- "@causa/runtime": ">= 0.27.1 < 1.0.0",
33
- "@google-cloud/precise-date": "^4.0.0",
34
- "@google-cloud/pubsub": "^4.10.0",
35
- "@google-cloud/spanner": "^7.18.1",
36
- "@google-cloud/tasks": "^5.5.2",
37
- "@grpc/grpc-js": "^1.12.6",
38
- "@nestjs/common": "^11.0.11",
39
- "@nestjs/config": "^4.0.1",
40
- "@nestjs/core": "^11.0.11",
32
+ "@causa/runtime": ">= 0.27.2 < 1.0.0",
33
+ "@google-cloud/precise-date": "^5.0.0",
34
+ "@google-cloud/pubsub": "^5.0.0",
35
+ "@google-cloud/spanner": "^8.0.0",
36
+ "@google-cloud/tasks": "^6.1.0",
37
+ "@grpc/grpc-js": "^1.13.4",
38
+ "@nestjs/common": "^11.1.2",
39
+ "@nestjs/config": "^4.0.2",
40
+ "@nestjs/core": "^11.1.2",
41
41
  "@nestjs/passport": "^11.0.5",
42
42
  "@nestjs/terminus": "^11.0.0",
43
43
  "class-transformer": "^0.5.1",
44
- "class-validator": "^0.14.1",
45
- "express": "^5.0.1",
46
- "firebase-admin": "^13.1.0",
44
+ "class-validator": "^0.14.2",
45
+ "express": "^5.1.0",
46
+ "firebase-admin": "^13.4.0",
47
47
  "jsonwebtoken": "^9.0.2",
48
48
  "passport-http-bearer": "^1.0.1",
49
- "pino": "^9.6.0",
49
+ "pino": "^9.7.0",
50
50
  "reflect-metadata": "^0.2.2"
51
51
  },
52
52
  "devDependencies": {
53
- "@nestjs/testing": "^11.0.11",
54
- "@swc/core": "^1.11.7",
55
- "@swc/jest": "^0.2.37",
56
- "@tsconfig/node22": "^22.0.0",
53
+ "@nestjs/testing": "^11.1.2",
54
+ "@swc/core": "^1.11.29",
55
+ "@swc/jest": "^0.2.38",
56
+ "@tsconfig/node22": "^22.0.2",
57
57
  "@types/jest": "^29.5.14",
58
58
  "@types/jsonwebtoken": "^9.0.9",
59
- "@types/node": "^22.13.9",
59
+ "@types/node": "^22.15.23",
60
60
  "@types/passport-http-bearer": "^1.0.41",
61
- "@types/supertest": "^6.0.2",
61
+ "@types/supertest": "^6.0.3",
62
62
  "@types/uuid": "^10.0.0",
63
- "dotenv": "^16.4.7",
64
- "eslint": "^9.21.0",
65
- "eslint-config-prettier": "^10.0.2",
66
- "eslint-plugin-prettier": "^5.2.3",
63
+ "dotenv": "^16.5.0",
64
+ "eslint": "^9.27.0",
65
+ "eslint-config-prettier": "^10.1.5",
66
+ "eslint-plugin-prettier": "^5.4.0",
67
67
  "jest": "^29.7.0",
68
- "jest-extended": "^4.0.2",
68
+ "jest-extended": "^5.0.3",
69
69
  "rimraf": "^6.0.1",
70
- "supertest": "^7.0.0",
71
- "ts-jest": "^29.2.6",
70
+ "supertest": "^7.1.1",
71
+ "ts-jest": "^29.3.4",
72
72
  "ts-node": "^10.9.2",
73
- "typescript": "^5.8.2",
74
- "typescript-eslint": "^8.26.0",
73
+ "typescript": "^5.8.3",
74
+ "typescript-eslint": "^8.33.0",
75
75
  "uuid": "^11.1.0"
76
76
  }
77
77
  }