@digitalaidseattle/firebase 1.0.9 → 1.0.12

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,8 +1,15 @@
1
- import { AuthError, AuthService, OAuthResponse, User } from '@digitalaidseattle/core';
2
- declare class FirebaseAuthService implements AuthService {
3
- currentUser: User | undefined;
4
- auth: import("@firebase/auth").Auth;
5
- constructor();
1
+ /**
2
+ * storageService.ts
3
+ *
4
+ * @copyright 2024 Digital Aid Seattle
5
+ *
6
+ */
7
+ import { AuthError, AuthService, OAuthResponse } from '@digitalaidseattle/core';
8
+ import { FirebaseApp } from 'firebase/app';
9
+ import { Auth } from 'firebase/auth';
10
+ export declare class FirebaseAuthService implements AuthService {
11
+ auth: Auth;
12
+ constructor(firebaseClient: FirebaseApp);
6
13
  getProviders(): string[];
7
14
  signInWith(provider: string): Promise<OAuthResponse>;
8
15
  hasUser(): Promise<boolean>;
@@ -12,4 +19,3 @@ declare class FirebaseAuthService implements AuthService {
12
19
  }>;
13
20
  signInWithGoogle: () => Promise<any>;
14
21
  }
15
- export { FirebaseAuthService };
@@ -1,18 +1,21 @@
1
1
  /**
2
- * storageService.ts
2
+ * FirebaseStorageService.ts
3
3
  *
4
- * @copyright 2024 Digital Aid Seattle
4
+ * @copyright 2026 Digital Aid Seattle
5
5
  *
6
6
  */
7
7
  import { StorageService } from "@digitalaidseattle/core";
8
+ import { FirebaseApp } from "firebase/app";
9
+ import { FirebaseStorage } from "firebase/storage";
8
10
  export declare class FirebaseStorageService implements StorageService {
9
- storage: import("@firebase/storage").FirebaseStorage;
11
+ storage: FirebaseStorage;
10
12
  decoder: TextDecoder;
13
+ constructor(firebaseClient: FirebaseApp);
11
14
  downloadFile: (filepath: string) => Promise<string>;
12
15
  getUrlAsync(filepath: string): Promise<string>;
13
- list(filepath?: string): Promise<any[]>;
14
16
  getUrl(filepath: string): string;
15
- upload(path: string, blob: any): Promise<any>;
16
17
  downloadBlob(filepath: string): Promise<Blob | null>;
17
- removeFile(fileName: string): Promise<any>;
18
+ removeFile(path: string): Promise<void>;
19
+ list(filepath?: string): Promise<any[]>;
20
+ upload(path: string, file: any): Promise<any>;
18
21
  }
@@ -7,8 +7,9 @@ declare class FirestoreService<T extends Entity> implements EntityService<T> {
7
7
  getById(id: string, select?: string, mapper?: (json: any) => T): Promise<T>;
8
8
  batchInsert(entities: T[], select?: string, mapper?: (json: any) => T, user?: User): Promise<T[]>;
9
9
  insert(entity: T, select?: string, mapper?: (json: any) => T, user?: User): Promise<T>;
10
- update(entityId: Identifier, updatedFields: T, select?: string, mapper?: (json: any) => T, user?: User): Promise<T>;
10
+ update(entityId: Identifier, updatedFields: Partial<T>, select?: string, mapper?: (json: any) => T, user?: User): Promise<T>;
11
11
  delete(entityId: Identifier): Promise<void>;
12
+ upsert(entity: T): Promise<T>;
12
13
  }
13
14
  export { FirestoreService };
14
15
  export type { Entity };
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Institution AI Service
3
+ *
4
+ *
5
+ * Provision Firebase application in Google Cloud
6
+ * <ol>
7
+ * <li>Go to the Google Cloud Console.</li>
8
+ * <li>Select an existing project.</li>
9
+ * <li>Navigate to the "APIs & Services" page.</li>
10
+ * <li>Click on "Credential".</li>
11
+ * <li>Edit API (the key should match the API key in the .env file).</li>
12
+ * <li>Enable the "Generative Language API" and "Firebase AI Logic API" restrictions.</li>
13
+ * </ol>
14
+ */
15
+ import { AiService } from "@digitalaidseattle/core";
16
+ import { AI } from "firebase/ai";
17
+ declare class GeminiService implements AiService {
18
+ ai: AI;
19
+ constructor(modelType?: string);
20
+ getModels(): string[];
21
+ calcTokenCount(model: string, prompt: string): Promise<number>;
22
+ generateContent(model: string, prompt: string): Promise<any>;
23
+ generateParameterizedContent(model: string, prompt: string, schemaParams: string[]): Promise<any>;
24
+ }
25
+ export { GeminiService };
@@ -2,3 +2,4 @@ export * from "./FirebaseAuthService.js";
2
2
  export * from "./firebaseClient.js";
3
3
  export * from "./FirebaseStorageService.js";
4
4
  export * from "./FirestoreService.js";
5
+ export * from "./GeminiService.js";
@@ -12,35 +12,35 @@ var app = require('firebase/app');
12
12
  var storage = require('firebase/storage');
13
13
  var _objectSpread = require('@babel/runtime/helpers/objectSpread2');
14
14
  var firestore = require('firebase/firestore');
15
+ var firebase = require('@digitalaidseattle/firebase');
16
+ var ai = require('firebase/ai');
15
17
 
16
18
  function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
17
19
 
18
20
  var _regeneratorRuntime__default = /*#__PURE__*/_interopDefault(_regeneratorRuntime);
19
21
 
20
- var firebaseConfig = {
21
- apiKey: undefined.VITE_FIREBASE_API_KEY,
22
- authDomain: undefined.VITE_FIREBASE_AUTH_DOMAIN,
23
- projectId: undefined.VITE_FIREBASE_PROJECT_ID,
24
- storageBucket: undefined.VITE_FIREBASE_STORAGE_BUCKET,
25
- messagingSenderId: undefined.VITE_FIREBASE_MESSAGING_SENDER_ID,
26
- appId: undefined.VITE_FIREBASE_APP_ID,
27
- measurementId: undefined.VITE_FIREBASE_MEASUREMENT_ID
28
- };
29
-
30
- // Initialize Firebase
31
- var firebaseClient = app.initializeApp(firebaseConfig);
32
-
33
22
  var FirebaseAuthService = /*#__PURE__*/function () {
34
- function FirebaseAuthService() {
23
+ function FirebaseAuthService(firebaseClient) {
35
24
  var _this = this;
36
25
  _classCallCheck(this, FirebaseAuthService);
37
- _defineProperty(this, "currentUser", undefined);
38
- _defineProperty(this, "auth", auth.getAuth(firebaseClient));
39
26
  _defineProperty(this, "getUser", /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime__default["default"].mark(function _callee() {
40
27
  return _regeneratorRuntime__default["default"].wrap(function (_context) {
41
28
  while (1) switch (_context.prev = _context.next) {
42
29
  case 0:
43
- return _context.abrupt("return", _this.currentUser);
30
+ return _context.abrupt("return", new Promise(function (resolve) {
31
+ var unsubscribe = auth.onAuthStateChanged(_this.auth, function (gUser) {
32
+ unsubscribe(); // stop listening after first call
33
+ var user = gUser ? {
34
+ email: gUser.email,
35
+ user_metadata: {
36
+ name: gUser.displayName,
37
+ avatar_url: gUser.photoURL,
38
+ email: gUser.email
39
+ }
40
+ } : null;
41
+ resolve(user);
42
+ });
43
+ }));
44
44
  case 1:
45
45
  case "end":
46
46
  return _context.stop();
@@ -51,19 +51,20 @@ var FirebaseAuthService = /*#__PURE__*/function () {
51
51
  return _regeneratorRuntime__default["default"].wrap(function (_context2) {
52
52
  while (1) switch (_context2.prev = _context2.next) {
53
53
  case 0:
54
- _this.currentUser = undefined;
55
- _this.auth.signOut();
54
+ _context2.next = 1;
55
+ return _this.auth.signOut();
56
+ case 1:
56
57
  return _context2.abrupt("return", {
57
58
  error: null
58
59
  });
59
- case 1:
60
+ case 2:
60
61
  case "end":
61
62
  return _context2.stop();
62
63
  }
63
64
  }, _callee2);
64
65
  })));
65
66
  _defineProperty(this, "signInWithGoogle", /*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime__default["default"].mark(function _callee3() {
66
- var provider, resp, _t;
67
+ var provider, _t;
67
68
  return _regeneratorRuntime__default["default"].wrap(function (_context3) {
68
69
  while (1) switch (_context3.prev = _context3.next) {
69
70
  case 0:
@@ -72,15 +73,6 @@ var FirebaseAuthService = /*#__PURE__*/function () {
72
73
  _context3.next = 1;
73
74
  return auth.signInWithPopup(_this.auth, provider);
74
75
  case 1:
75
- resp = _context3.sent;
76
- _this.currentUser = {
77
- email: resp.user.email,
78
- user_metadata: {
79
- name: resp.user.displayName,
80
- avatar_url: resp.user.photoURL,
81
- email: resp.user.email
82
- }
83
- };
84
76
  return _context3.abrupt("return", {
85
77
  data: {
86
78
  url: undefined.VITE_AUTH_DOMAIN
@@ -89,25 +81,15 @@ var FirebaseAuthService = /*#__PURE__*/function () {
89
81
  case 2:
90
82
  _context3.prev = 2;
91
83
  _t = _context3["catch"](0);
92
- console.error(_t);
84
+ console.error('signInWithGoogle', _t);
85
+ throw _t;
93
86
  case 3:
94
87
  case "end":
95
88
  return _context3.stop();
96
89
  }
97
90
  }, _callee3, null, [[0, 2]]);
98
91
  })));
99
- this.auth.onAuthStateChanged(function (user) {
100
- if (user) {
101
- _this.currentUser = {
102
- email: user.email,
103
- user_metadata: {
104
- name: user.displayName,
105
- avatar_url: user.photoURL,
106
- email: user.email
107
- }
108
- };
109
- }
110
- });
92
+ this.auth = auth.getAuth(firebaseClient);
111
93
  }
112
94
  return _createClass(FirebaseAuthService, [{
113
95
  key: "getProviders",
@@ -127,17 +109,34 @@ var FirebaseAuthService = /*#__PURE__*/function () {
127
109
  }, {
128
110
  key: "hasUser",
129
111
  value: function hasUser() {
130
- return Promise.resolve(this.currentUser !== null);
112
+ var _this2 = this;
113
+ return new Promise(function (resolve) {
114
+ var unsubscribe = auth.onAuthStateChanged(_this2.auth, function (user) {
115
+ unsubscribe(); // stop listening after first call
116
+ resolve(user ? true : false);
117
+ });
118
+ });
131
119
  }
132
120
  }]);
133
121
  }();
134
122
 
123
+ var firebaseConfig = {
124
+ apiKey: undefined.VITE_FIREBASE_API_KEY,
125
+ authDomain: undefined.VITE_FIREBASE_AUTH_DOMAIN,
126
+ projectId: undefined.VITE_FIREBASE_PROJECT_ID,
127
+ storageBucket: undefined.VITE_FIREBASE_STORAGE_BUCKET,
128
+ messagingSenderId: undefined.VITE_FIREBASE_MESSAGING_SENDER_ID,
129
+ appId: undefined.VITE_FIREBASE_APP_ID,
130
+ measurementId: undefined.VITE_FIREBASE_MEASUREMENT_ID
131
+ };
132
+
133
+ // Initialize Firebase
134
+ var firebaseClient = app.initializeApp(firebaseConfig);
135
+
135
136
  var FirebaseStorageService = /*#__PURE__*/function () {
136
- function FirebaseStorageService() {
137
+ function FirebaseStorageService(firebaseClient) {
137
138
  var _this = this;
138
139
  _classCallCheck(this, FirebaseStorageService);
139
- _defineProperty(this, "storage", storage.getStorage(firebaseClient));
140
- _defineProperty(this, "decoder", new TextDecoder("utf-8"));
141
140
  _defineProperty(this, "downloadFile", /*#__PURE__*/function () {
142
141
  var _ref = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime__default["default"].mark(function _callee(filepath) {
143
142
  var fileRef;
@@ -158,6 +157,8 @@ var FirebaseStorageService = /*#__PURE__*/function () {
158
157
  return _ref.apply(this, arguments);
159
158
  };
160
159
  }());
160
+ this.storage = storage.getStorage(firebaseClient);
161
+ this.decoder = new TextDecoder("utf-8");
161
162
  }
162
163
  return _createClass(FirebaseStorageService, [{
163
164
  key: "getUrlAsync",
@@ -189,31 +190,128 @@ var FirebaseStorageService = /*#__PURE__*/function () {
189
190
  }
190
191
  return getUrlAsync;
191
192
  }()
192
- }, {
193
- key: "list",
194
- value: function list(filepath) {
195
- throw new Error("Method not implemented.");
196
- }
197
193
  }, {
198
194
  key: "getUrl",
199
195
  value: function getUrl(filepath) {
200
196
  throw new Error("Method not supported.");
201
197
  }
202
- }, {
203
- key: "upload",
204
- value: function upload(path, blob) {
205
- throw new Error("Method not implemented.");
206
- }
207
198
  }, {
208
199
  key: "downloadBlob",
209
200
  value: function downloadBlob(filepath) {
210
- throw new Error("Method not implemented.");
201
+ var fileRef = storage.ref(this.storage, filepath);
202
+ return storage.getBytes(fileRef).then(function (bytes) {
203
+ return new Blob([bytes]);
204
+ });
211
205
  }
212
206
  }, {
213
207
  key: "removeFile",
214
- value: function removeFile(fileName) {
215
- throw new Error("Method not implemented.");
208
+ value: function removeFile(path) {
209
+ try {
210
+ var fileRef = storage.ref(this.storage, path);
211
+ return storage.deleteObject(fileRef);
212
+ } catch (error) {
213
+ if (error.code === "storage/object-not-found") {
214
+ console.warn("File does not exist");
215
+ } else if (error.code === "storage/unauthorized") {
216
+ console.error("User not authorized to delete file");
217
+ } else {
218
+ console.error("Delete failed:", error);
219
+ }
220
+ throw error;
221
+ }
216
222
  }
223
+ }, {
224
+ key: "list",
225
+ value: function () {
226
+ var _list = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime__default["default"].mark(function _callee4(filepath) {
227
+ var folderRef, result, files;
228
+ return _regeneratorRuntime__default["default"].wrap(function (_context4) {
229
+ while (1) switch (_context4.prev = _context4.next) {
230
+ case 0:
231
+ if (filepath) {
232
+ _context4.next = 1;
233
+ break;
234
+ }
235
+ return _context4.abrupt("return", []);
236
+ case 1:
237
+ folderRef = storage.ref(this.storage, filepath);
238
+ _context4.next = 2;
239
+ return storage.listAll(folderRef);
240
+ case 2:
241
+ result = _context4.sent;
242
+ _context4.next = 3;
243
+ return Promise.all(result.items.map(/*#__PURE__*/function () {
244
+ var _ref2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime__default["default"].mark(function _callee3(item) {
245
+ var metadata;
246
+ return _regeneratorRuntime__default["default"].wrap(function (_context3) {
247
+ while (1) switch (_context3.prev = _context3.next) {
248
+ case 0:
249
+ _context3.next = 1;
250
+ return storage.getMetadata(item);
251
+ case 1:
252
+ metadata = _context3.sent;
253
+ return _context3.abrupt("return", {
254
+ name: item.name,
255
+ fullPath: item.fullPath,
256
+ type: metadata.contentType,
257
+ size: metadata.size,
258
+ updated: metadata.updated
259
+ });
260
+ case 2:
261
+ case "end":
262
+ return _context3.stop();
263
+ }
264
+ }, _callee3);
265
+ }));
266
+ return function (_x4) {
267
+ return _ref2.apply(this, arguments);
268
+ };
269
+ }()));
270
+ case 3:
271
+ files = _context4.sent;
272
+ return _context4.abrupt("return", files);
273
+ case 4:
274
+ case "end":
275
+ return _context4.stop();
276
+ }
277
+ }, _callee4, this);
278
+ }));
279
+ function list(_x3) {
280
+ return _list.apply(this, arguments);
281
+ }
282
+ return list;
283
+ }()
284
+ }, {
285
+ key: "upload",
286
+ value: function () {
287
+ var _upload = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime__default["default"].mark(function _callee5(path, file) {
288
+ var storageRef, snapshot, downloadUrl;
289
+ return _regeneratorRuntime__default["default"].wrap(function (_context5) {
290
+ while (1) switch (_context5.prev = _context5.next) {
291
+ case 0:
292
+ storageRef = storage.ref(this.storage, path); // Upload file
293
+ _context5.next = 1;
294
+ return storage.uploadBytes(storageRef, file, {
295
+ contentType: file === null || file === void 0 ? void 0 : file.type
296
+ });
297
+ case 1:
298
+ snapshot = _context5.sent;
299
+ _context5.next = 2;
300
+ return storage.getDownloadURL(snapshot.ref);
301
+ case 2:
302
+ downloadUrl = _context5.sent;
303
+ return _context5.abrupt("return", downloadUrl);
304
+ case 3:
305
+ case "end":
306
+ return _context5.stop();
307
+ }
308
+ }, _callee5, this);
309
+ }));
310
+ function upload(_x5, _x6) {
311
+ return _upload.apply(this, arguments);
312
+ }
313
+ return upload;
314
+ }()
217
315
  }]);
218
316
  }();
219
317
 
@@ -405,10 +503,112 @@ var FirestoreService = /*#__PURE__*/function () {
405
503
  }
406
504
  return _delete;
407
505
  }()
506
+ }, {
507
+ key: "upsert",
508
+ value: function () {
509
+ var _upsert = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime__default["default"].mark(function _callee7(entity) {
510
+ return _regeneratorRuntime__default["default"].wrap(function (_context7) {
511
+ while (1) switch (_context7.prev = _context7.next) {
512
+ case 0:
513
+ _context7.next = 1;
514
+ return firestore.setDoc(firestore.doc(this.db, this.collectionName, entity.id), entity);
515
+ case 1:
516
+ return _context7.abrupt("return", entity);
517
+ case 2:
518
+ case "end":
519
+ return _context7.stop();
520
+ }
521
+ }, _callee7, this);
522
+ }));
523
+ function upsert(_x19) {
524
+ return _upsert.apply(this, arguments);
525
+ }
526
+ return upsert;
527
+ }()
528
+ }]);
529
+ }();
530
+
531
+ var GeminiService = /*#__PURE__*/function () {
532
+ function GeminiService(modelType) {
533
+ _classCallCheck(this, GeminiService);
534
+ this.ai = ai.getAI(firebase.firebaseClient, {
535
+ backend: new ai.GoogleAIBackend()
536
+ });
537
+ }
538
+ return _createClass(GeminiService, [{
539
+ key: "getModels",
540
+ value: function getModels() {
541
+ return ["gemini-2.5-flash", "gemini-2.5-pro", "gemini-2.5-flash-lite"];
542
+ }
543
+ }, {
544
+ key: "calcTokenCount",
545
+ value: function calcTokenCount(model, prompt) {
546
+ return ai.getGenerativeModel(this.ai, {
547
+ model: model
548
+ }).countTokens(prompt).then(function (response) {
549
+ return response.totalTokens;
550
+ });
551
+ }
552
+
553
+ // Wrap in an async function so you can use await
554
+ }, {
555
+ key: "generateContent",
556
+ value: function generateContent(model, prompt) {
557
+ // To generate text output, call generateContent with the text input
558
+ console.log('generateContent', model, prompt);
559
+ return ai.getGenerativeModel(this.ai, {
560
+ model: model
561
+ }).generateContent(prompt).then(function (result) {
562
+ return result.response.text();
563
+ })["catch"](function (error) {
564
+ console.error("Error querying AI: ", error);
565
+ throw new Error("Failed to query AI: " + error.message);
566
+ });
567
+ }
568
+
569
+ // Wrap in an async function so you can use await
570
+ }, {
571
+ key: "generateParameterizedContent",
572
+ value: function generateParameterizedContent(model, prompt, schemaParams) {
573
+ // Provide a JSON schema object using a standard format.
574
+ // Later, pass this schema object into `responseSchema` in the generation config.
575
+ var schema = ai.Schema.object({
576
+ properties: {
577
+ characters: ai.Schema.array({
578
+ items: ai.Schema.object({
579
+ properties: Object.fromEntries(schemaParams.map(function (field) {
580
+ return [field, ai.Schema.string()];
581
+ }))
582
+ })
583
+ })
584
+ }
585
+ });
586
+
587
+ // Create a `GenerativeModel` instance with a model that supports your use case
588
+ var jModel = ai.getGenerativeModel(this.ai, {
589
+ model: model,
590
+ // In the generation config, set the `responseMimeType` to `application/json`
591
+ // and pass the JSON schema object into `responseSchema`.
592
+ generationConfig: {
593
+ responseMimeType: "application/json",
594
+ responseSchema: schema
595
+ }
596
+ });
597
+
598
+ // To generate text output, call generateContent with the text input
599
+ return jModel.generateContent(prompt).then(function (result) {
600
+ var content = result.response.text();
601
+ return JSON.parse(content).characters[0];
602
+ })["catch"](function (error) {
603
+ console.error("Error querying AI: ", error);
604
+ throw new Error("Failed to query AI: " + error.message);
605
+ });
606
+ }
408
607
  }]);
409
608
  }();
410
609
 
411
610
  exports.FirebaseAuthService = FirebaseAuthService;
412
611
  exports.FirebaseStorageService = FirebaseStorageService;
413
612
  exports.FirestoreService = FirestoreService;
613
+ exports.GeminiService = GeminiService;
414
614
  exports.firebaseClient = firebaseClient;