@concord-consortium/object-storage 1.0.0-pre.4 → 1.0.0-pre.6

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,39 +1,20 @@
1
- import { DemoObjectStorageConfig, IObjectStorage, ObjectMetadata, ObjectData, StoredObject, ObjectWithId, MonitorCallback, DemonitorFunction, AddOptions } from './types';
1
+ import { DemoObjectStorageConfig, IObjectStorage, ObjectMetadata, ObjectData, StoredObject, MonitorCallback, DemonitorFunction, AddOptions, ObjectMetadataWithId } from './types';
2
2
  export declare class DemoObjectStorage implements IObjectStorage {
3
3
  private config;
4
4
  private objects;
5
5
  private monitors;
6
6
  constructor(config: DemoObjectStorageConfig);
7
- /**
8
- * Lists metadata documents for objects owned by the current user
9
- */
10
- listMine(): Promise<ObjectWithId[]>;
11
- /**
12
- * Lists metadata documents for objects linked to the current user
13
- */
14
- listLinked(): Promise<ObjectWithId[]>;
7
+ private getQuestionMetadata;
15
8
  /**
16
9
  * Lists metadata documents for objects associated with specific question IDs
17
10
  */
18
- list(questionIds: string[]): Promise<ObjectWithId[]>;
19
- /**
20
- * Monitors metadata documents for objects owned by the current user
21
- * Invokes callback at start and on any change
22
- * Returns a function to stop monitoring
23
- */
24
- monitorMine(callback: MonitorCallback): DemonitorFunction;
25
- /**
26
- * Monitors metadata documents for objects linked to the current user
27
- * Invokes callback at start and on any change
28
- * Returns a function to stop monitoring
29
- */
30
- monitorLinked(callback: MonitorCallback): DemonitorFunction;
11
+ list(questionId: string): Promise<ObjectMetadataWithId[]>;
31
12
  /**
32
13
  * Monitors metadata documents for objects associated with specific question IDs
33
14
  * Invokes callback at start and on any change
34
15
  * Returns a function to stop monitoring
35
16
  */
36
- monitor(questionIds: string[], callback: MonitorCallback): DemonitorFunction;
17
+ monitor(questionId: string, callback: MonitorCallback): DemonitorFunction;
37
18
  /**
38
19
  * Adds both metadata and data documents for a new object
39
20
  * Returns the generated object ID (nanoid) or the provided ID if specified in options
@@ -11,76 +11,33 @@ class DemoObjectStorage {
11
11
  this.objects = new Map();
12
12
  this.monitors = new Map();
13
13
  }
14
- /**
15
- * Lists metadata documents for objects owned by the current user
16
- */
17
- async listMine() {
18
- return Array.from(this.objects.values());
19
- }
20
- /**
21
- * Lists metadata documents for objects linked to the current user
22
- */
23
- async listLinked() {
24
- // not applicable in demo storage
25
- return [];
14
+ getQuestionMetadata() {
15
+ // In demo mode, just return all objects since there are no other questions
16
+ // that can use this storage instance
17
+ return Array.from(this.objects.entries()).map(([id, obj]) => {
18
+ return { id, metadata: obj.metadata };
19
+ });
26
20
  }
27
21
  /**
28
22
  * Lists metadata documents for objects associated with specific question IDs
29
23
  */
30
- async list(questionIds) {
31
- // In demo mode, just return all objects
32
- return Array.from(this.objects.values());
33
- }
34
- /**
35
- * Monitors metadata documents for objects owned by the current user
36
- * Invokes callback at start and on any change
37
- * Returns a function to stop monitoring
38
- */
39
- monitorMine(callback) {
40
- const key = 'mine';
41
- if (!this.monitors.has(key)) {
42
- this.monitors.set(key, []);
43
- }
44
- this.monitors.get(key).push(callback);
45
- // Invoke callback immediately with current state
46
- callback(Array.from(this.objects.values()));
47
- return () => {
48
- const callbacks = this.monitors.get(key);
49
- if (callbacks) {
50
- const index = callbacks.indexOf(callback);
51
- if (index > -1) {
52
- callbacks.splice(index, 1);
53
- }
54
- }
55
- };
56
- }
57
- /**
58
- * Monitors metadata documents for objects linked to the current user
59
- * Invokes callback at start and on any change
60
- * Returns a function to stop monitoring
61
- */
62
- monitorLinked(callback) {
63
- // not applicable in demo storage
64
- callback([]);
65
- return () => {
66
- // no-op
67
- };
24
+ async list(questionId) {
25
+ return this.getQuestionMetadata();
68
26
  }
69
27
  /**
70
28
  * Monitors metadata documents for objects associated with specific question IDs
71
29
  * Invokes callback at start and on any change
72
30
  * Returns a function to stop monitoring
73
31
  */
74
- monitor(questionIds, callback) {
75
- const key = `monitor-${questionIds.join(',')}`;
76
- if (!this.monitors.has(key)) {
77
- this.monitors.set(key, []);
32
+ monitor(questionId, callback) {
33
+ if (!this.monitors.has(questionId)) {
34
+ this.monitors.set(questionId, []);
78
35
  }
79
- this.monitors.get(key).push(callback);
36
+ this.monitors.get(questionId).push(callback);
80
37
  // Invoke callback immediately with current state
81
- callback(Array.from(this.objects.values()));
38
+ callback(this.getQuestionMetadata());
82
39
  return () => {
83
- const callbacks = this.monitors.get(key);
40
+ const callbacks = this.monitors.get(questionId);
84
41
  if (callbacks) {
85
42
  const index = callbacks.indexOf(callback);
86
43
  if (index > -1) {
@@ -95,12 +52,7 @@ class DemoObjectStorage {
95
52
  */
96
53
  async add(object, options) {
97
54
  const id = options?.id ?? (0, nanoid_1.nanoid)();
98
- const objectWithId = {
99
- id,
100
- metadata: object.metadata,
101
- data: object.data
102
- };
103
- this.objects.set(id, objectWithId);
55
+ this.objects.set(id, object);
104
56
  // Notify all monitors
105
57
  this.notifyMonitors();
106
58
  return id;
@@ -151,7 +103,7 @@ class DemoObjectStorage {
151
103
  * Notifies all active monitors of changes
152
104
  */
153
105
  notifyMonitors() {
154
- const allObjects = Array.from(this.objects.values());
106
+ const allObjects = this.getQuestionMetadata();
155
107
  this.monitors.forEach(callbacks => {
156
108
  callbacks.forEach(callback => callback(allObjects));
157
109
  });
@@ -1,37 +1,37 @@
1
- import { FirebaseObjectStorageConfig, IObjectStorage, ObjectMetadata, ObjectData, StoredObject, ObjectWithId, MonitorCallback, DemonitorFunction, AddOptions } from './types';
1
+ import "firebase/compat/auth";
2
+ import "firebase/compat/firestore";
3
+ import { FirebaseObjectStorageConfig, IObjectStorage, ObjectMetadata, ObjectData, StoredObject, MonitorCallback, DemonitorFunction, AddOptions, ObjectMetadataWithId } from './types';
2
4
  export declare class FirebaseObjectStorage implements IObjectStorage {
3
5
  private config;
6
+ private initPromise;
7
+ private initialized;
8
+ private app;
4
9
  constructor(config: FirebaseObjectStorageConfig);
5
- /**
6
- * Lists metadata documents for objects owned by the current user
7
- */
8
- listMine(): Promise<ObjectWithId[]>;
9
- /**
10
- * Lists metadata documents for objects linked to the current user
11
- */
12
- listLinked(): Promise<ObjectWithId[]>;
10
+ private initialize;
11
+ private ensureInitialized;
12
+ private createDocument;
13
+ private getPaths;
14
+ private getRefs;
15
+ private getMetadataQuery;
16
+ /**
17
+ * Ensures the provided ID is in question ID format as opposed to reference ID format
18
+ *
19
+ * eg: "404-MWInteractive" transforms to "mw_interactive_404"
20
+ *
21
+ * @param questionOrRefId
22
+ * @returns
23
+ */
24
+ private ensureIdIsQuestionId;
13
25
  /**
14
26
  * Lists metadata documents for objects associated with specific question IDs
15
27
  */
16
- list(questionIds: string[]): Promise<ObjectWithId[]>;
17
- /**
18
- * Monitors metadata documents for objects owned by the current user
19
- * Invokes callback at start and on any change
20
- * Returns a function to stop monitoring
21
- */
22
- monitorMine(callback: MonitorCallback): DemonitorFunction;
23
- /**
24
- * Monitors metadata documents for objects linked to the current user
25
- * Invokes callback at start and on any change
26
- * Returns a function to stop monitoring
27
- */
28
- monitorLinked(callback: MonitorCallback): DemonitorFunction;
28
+ list(questionOrRefId: string): Promise<ObjectMetadataWithId[]>;
29
29
  /**
30
30
  * Monitors metadata documents for objects associated with specific question IDs
31
31
  * Invokes callback at start and on any change
32
32
  * Returns a function to stop monitoring
33
33
  */
34
- monitor(questionIds: string[], callback: MonitorCallback): DemonitorFunction;
34
+ monitor(questionOrRefId: string, callback: MonitorCallback): DemonitorFunction;
35
35
  /**
36
36
  * Adds both metadata and data documents for a new object
37
37
  * Returns the generated object ID (nanoid) or the provided ID if specified in options
@@ -1,69 +1,146 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.FirebaseObjectStorage = void 0;
4
7
  const nanoid_1 = require("nanoid");
8
+ const app_1 = __importDefault(require("firebase/compat/app"));
9
+ require("firebase/compat/auth");
10
+ require("firebase/compat/firestore");
5
11
  class FirebaseObjectStorage {
6
12
  constructor(config) {
13
+ this.initialized = false;
7
14
  if (config.version !== 1) {
8
15
  throw new Error(`Unsupported config version: ${config.version}. Expected version 1.`);
9
16
  }
10
- this.config = config;
17
+ this.config = { ...config };
18
+ // ensure the question id is in the correct format
19
+ this.config.questionId = this.ensureIdIsQuestionId(this.config.questionId);
20
+ this.app = app_1.default.initializeApp(this.config.app);
21
+ this.app.firestore().settings({
22
+ ignoreUndefinedProperties: true,
23
+ });
24
+ // Start initialization immediately in constructor
25
+ this.initPromise = this.initialize();
11
26
  }
12
- /**
13
- * Lists metadata documents for objects owned by the current user
14
- */
15
- async listMine() {
16
- // TODO: Implement Firebase query for user's own objects
17
- return [];
27
+ async initialize() {
28
+ if (this.initialized)
29
+ return;
30
+ if (this.config.user.type === "authenticated") {
31
+ // ensure any previous auth state is cleared before signing in
32
+ await this.app.auth().signOut();
33
+ await this.app.auth().signInWithCustomToken(this.config.user.jwt);
34
+ }
35
+ this.initialized = true;
18
36
  }
19
- /**
20
- * Lists metadata documents for objects linked to the current user
21
- */
22
- async listLinked() {
23
- // TODO: Implement Firebase query for linked objects
24
- return [];
37
+ async ensureInitialized() {
38
+ await this.initPromise;
25
39
  }
26
- /**
27
- * Lists metadata documents for objects associated with specific question IDs
28
- */
29
- async list(questionIds) {
30
- // TODO: Implement Firebase query for objects by question IDs
31
- return [];
40
+ createDocument(contents) {
41
+ const { questionId } = this.config;
42
+ if (this.config.user.type === "authenticated") {
43
+ const { contextId, platformId, platformUserId, resourceLinkId } = this.config.user;
44
+ return {
45
+ created_at: app_1.default.firestore.FieldValue.serverTimestamp(),
46
+ context_id: contextId,
47
+ platform_id: platformId,
48
+ platform_user_id: platformUserId,
49
+ resource_link_id: resourceLinkId,
50
+ run_key: "",
51
+ question_id: questionId,
52
+ ...contents
53
+ };
54
+ }
55
+ else {
56
+ const { runKey } = this.config.user;
57
+ return {
58
+ created_at: app_1.default.firestore.FieldValue.serverTimestamp(),
59
+ run_key: runKey,
60
+ platform_user_id: runKey,
61
+ question_id: questionId,
62
+ ...contents
63
+ };
64
+ }
65
+ }
66
+ getPaths(objectId) {
67
+ const metadataPath = `${this.config.root}/object_store_metadata${objectId ? `/${objectId}` : ''}`;
68
+ const dataPath = `${this.config.root}/object_store_data${objectId ? `/${objectId}` : ''}`;
69
+ return { metadataPath, dataPath };
70
+ }
71
+ getRefs(objectId) {
72
+ const { metadataPath, dataPath } = this.getPaths(objectId);
73
+ const metadataRef = this.app.firestore().doc(metadataPath);
74
+ const dataRef = this.app.firestore().doc(dataPath);
75
+ return { metadataRef, dataRef };
76
+ }
77
+ getMetadataQuery(questionOrRefId) {
78
+ const questionId = this.ensureIdIsQuestionId(questionOrRefId);
79
+ const { metadataPath } = this.getPaths();
80
+ let query = this.app.firestore().collection(metadataPath)
81
+ .where("question_id", "==", questionId);
82
+ if (this.config.user.type === "authenticated") { // logged in user
83
+ const { contextId, platformId, resourceLinkId, platformUserId } = this.config.user;
84
+ query = query
85
+ .where("context_id", "==", contextId)
86
+ .where("platform_id", "==", platformId)
87
+ .where("platform_user_id", "==", platformUserId.toString())
88
+ .where("resource_link_id", "==", resourceLinkId);
89
+ }
90
+ else {
91
+ query = query.where("run_key", "==", this.config.user.runKey);
92
+ }
93
+ query = query.orderBy("created_at", "asc");
94
+ return query;
32
95
  }
33
96
  /**
34
- * Monitors metadata documents for objects owned by the current user
35
- * Invokes callback at start and on any change
36
- * Returns a function to stop monitoring
97
+ * Ensures the provided ID is in question ID format as opposed to reference ID format
98
+ *
99
+ * eg: "404-MWInteractive" transforms to "mw_interactive_404"
100
+ *
101
+ * @param questionOrRefId
102
+ * @returns
37
103
  */
38
- monitorMine(callback) {
39
- // TODO: Implement Firebase realtime listener for user's own objects
40
- callback([]);
41
- return () => {
42
- // TODO: Implement cleanup
43
- };
104
+ ensureIdIsQuestionId(questionOrRefId) {
105
+ const refIdRegEx = /(\d*)-(\D*)/g;
106
+ const parsed = refIdRegEx.exec(questionOrRefId);
107
+ if (parsed?.length) {
108
+ const [, embeddableId, embeddableType] = parsed;
109
+ const snakeCased = embeddableType.replace(/(?!^)([A-Z])/g, "_$1").toLowerCase();
110
+ return `${snakeCased}_${embeddableId}`;
111
+ }
112
+ return questionOrRefId;
44
113
  }
45
114
  /**
46
- * Monitors metadata documents for objects linked to the current user
47
- * Invokes callback at start and on any change
48
- * Returns a function to stop monitoring
115
+ * Lists metadata documents for objects associated with specific question IDs
49
116
  */
50
- monitorLinked(callback) {
51
- // TODO: Implement Firebase realtime listener for linked objects
52
- callback([]);
53
- return () => {
54
- // TODO: Implement cleanup
55
- };
117
+ async list(questionOrRefId) {
118
+ await this.ensureInitialized();
119
+ const query = this.getMetadataQuery(questionOrRefId);
120
+ const querySnapshot = await query.get();
121
+ const results = [];
122
+ querySnapshot.forEach(doc => {
123
+ results.push({ id: doc.id, metadata: doc.data().metadata });
124
+ });
125
+ return results;
56
126
  }
57
127
  /**
58
128
  * Monitors metadata documents for objects associated with specific question IDs
59
129
  * Invokes callback at start and on any change
60
130
  * Returns a function to stop monitoring
61
131
  */
62
- monitor(questionIds, callback) {
63
- // TODO: Implement Firebase realtime listener for objects by question IDs
64
- callback([]);
132
+ monitor(questionOrRefId, callback) {
133
+ // await this.ensureInitialized();
134
+ const query = this.getMetadataQuery(questionOrRefId);
135
+ const unsub = query.onSnapshot(snapshot => {
136
+ const results = [];
137
+ snapshot.forEach(doc => {
138
+ results.push({ id: doc.id, metadata: doc.data().metadata });
139
+ });
140
+ callback(results);
141
+ });
65
142
  return () => {
66
- // TODO: Implement cleanup
143
+ unsub();
67
144
  };
68
145
  }
69
146
  /**
@@ -71,36 +148,56 @@ class FirebaseObjectStorage {
71
148
  * Returns the generated object ID (nanoid) or the provided ID if specified in options
72
149
  */
73
150
  async add(object, options) {
74
- // TODO: Generate nanoid if not provided in options
75
- // TODO: Add metadata document to Firebase
76
- // TODO: Add data document to Firebase
77
- const newObjectId = options?.id ?? 'placeholder-id';
151
+ await this.ensureInitialized();
152
+ const newObjectId = options?.id ?? (0, nanoid_1.nanoid)();
153
+ const { data, metadata } = object;
154
+ const { metadataRef, dataRef } = this.getRefs(newObjectId);
155
+ const dataDoc = this.createDocument({ data });
156
+ const metadataDoc = this.createDocument({ metadata });
157
+ const batch = this.app.firestore().batch();
158
+ batch.set(dataRef, dataDoc);
159
+ batch.set(metadataRef, metadataDoc);
160
+ await batch.commit();
78
161
  return newObjectId;
79
162
  }
80
163
  /**
81
164
  * Reads both metadata and data documents for an object
82
165
  */
83
166
  async read(objectId) {
84
- // TODO: Read metadata document from Firebase
85
- // TODO: Read data document from Firebase
86
- return {
87
- metadata: {},
88
- data: {}
89
- };
167
+ await this.ensureInitialized();
168
+ const metadata = await this.readMetadata(objectId);
169
+ if (!metadata) {
170
+ return undefined;
171
+ }
172
+ const data = await this.readData(objectId);
173
+ if (!data) {
174
+ return undefined;
175
+ }
176
+ return { metadata, data };
90
177
  }
91
178
  /**
92
179
  * Reads only the metadata document for an object
93
180
  */
94
181
  async readMetadata(objectId) {
95
- // TODO: Read metadata document from Firebase
96
- return {};
182
+ await this.ensureInitialized();
183
+ const { metadataRef } = this.getRefs(objectId);
184
+ const metadataSnapshot = await metadataRef.get();
185
+ if (!metadataSnapshot.exists) {
186
+ return undefined;
187
+ }
188
+ return metadataSnapshot.data()?.metadata ?? {};
97
189
  }
98
190
  /**
99
191
  * Reads only the data document for an object
100
192
  */
101
193
  async readData(objectId) {
102
- // TODO: Read data document from Firebase
103
- return {};
194
+ await this.ensureInitialized();
195
+ const { dataRef } = this.getRefs(objectId);
196
+ const dataSnapshot = await dataRef.get();
197
+ if (!dataSnapshot.exists) {
198
+ return undefined;
199
+ }
200
+ return dataSnapshot.data()?.data ?? {};
104
201
  }
105
202
  /**
106
203
  * Generates a new unique ID using nanoid
package/dist/index.d.ts CHANGED
@@ -2,5 +2,5 @@ export { DemoObjectStorage } from './demo-object-storage';
2
2
  export { FirebaseObjectStorage } from './firebase-object-storage';
3
3
  export { createObjectStorage } from './object-storage';
4
4
  export { ObjectStorageProvider, useObjectStorage } from './object-storage-context';
5
- export { IObjectStorage, ObjectStorageConfig, DemoObjectStorageConfig, FirebaseObjectStorageConfig, ObjectMetadata, ObjectData, StoredObject, ObjectWithId, MonitorCallback, DemonitorFunction } from './types';
5
+ export { IObjectStorage, ObjectStorageConfig, DemoObjectStorageConfig, FirebaseObjectStorageUser, FirebaseObjectStorageConfig, ObjectMetadata, ObjectData, StoredObject, ObjectWithId, MonitorCallback, DemonitorFunction } from './types';
6
6
  export * from './typed-object';
@@ -64,7 +64,7 @@ export declare class TypedObject implements StoredObject {
64
64
  data: TypedData;
65
65
  constructor(options?: TypedObjectOptions);
66
66
  static IsSupportedTypedObject(storedObject: StoredObject): boolean;
67
- static IsSupportedTypedObjectMetadata(storedObjectMetadata?: StoredObject["metadata"]): boolean;
67
+ static IsSupportedTypedObjectMetadata(storedObjectMetadata?: StoredObject["metadata"]): storedObjectMetadata is TypedMetadata;
68
68
  static FromStoredObject(id: string, storedObject: StoredObject): TypedObject;
69
69
  addImage(options: AddImageOptions): void;
70
70
  addDataTable(options: AddDataTableOptions): void;
@@ -69,8 +69,13 @@ class TypedObject {
69
69
  if (options.description !== undefined) {
70
70
  this.metadata.items[id].description = options.description;
71
71
  }
72
+ // firebase does not support nested arrays well, so we store rows as an object with numeric keys
73
+ const rowsObj = {};
74
+ options.rows.forEach((row, index) => {
75
+ rowsObj[index.toString()] = row;
76
+ });
72
77
  this.data[id] = {
73
- rows: options.rows
78
+ rows: rowsObj
74
79
  };
75
80
  }
76
81
  addText(options) {
package/dist/types.d.ts CHANGED
@@ -1,22 +1,35 @@
1
1
  export interface DemoObjectStorageConfig {
2
- type: "demo";
3
2
  version: 1;
3
+ type: "demo";
4
+ }
5
+ export interface AuthenticatedUser {
6
+ type: "authenticated";
7
+ jwt: string;
8
+ contextId: string;
9
+ platformId: string;
10
+ resourceLinkId: string;
11
+ platformUserId: string;
12
+ }
13
+ export interface AnonymousUser {
14
+ type: "anonymous";
15
+ runKey: string;
4
16
  }
17
+ export type FirebaseObjectStorageUser = AuthenticatedUser | AnonymousUser;
5
18
  export interface FirebaseObjectStorageConfig {
6
- type: "firebase";
7
19
  version: 1;
20
+ type: "firebase";
21
+ app: Object;
22
+ root: string;
23
+ user: FirebaseObjectStorageUser;
24
+ questionId: string;
8
25
  }
9
26
  export type ObjectStorageConfig = DemoObjectStorageConfig | FirebaseObjectStorageConfig;
10
27
  export interface AddOptions {
11
28
  id?: string;
12
29
  }
13
30
  export interface IObjectStorage {
14
- listMine(): Promise<ObjectWithId[]>;
15
- listLinked(): Promise<ObjectWithId[]>;
16
- list(questionIds: string[]): Promise<ObjectWithId[]>;
17
- monitorMine(callback: MonitorCallback): DemonitorFunction;
18
- monitorLinked(callback: MonitorCallback): DemonitorFunction;
19
- monitor(questionIds: string[], callback: MonitorCallback): DemonitorFunction;
31
+ list(questionOrRefId: string): Promise<ObjectMetadataWithId[]>;
32
+ monitor(questionOrRefId: string, callback: MonitorCallback): DemonitorFunction;
20
33
  add(object: StoredObject, options?: AddOptions): Promise<string>;
21
34
  read(objectId: string): Promise<StoredObject | undefined>;
22
35
  readMetadata(objectId: string): Promise<ObjectMetadata | undefined>;
@@ -33,8 +46,18 @@ export interface StoredObject {
33
46
  metadata: ObjectMetadata;
34
47
  data: ObjectData;
35
48
  }
36
- export interface ObjectWithId extends StoredObject {
49
+ export interface ObjectMetadataWithId {
50
+ id: string;
51
+ metadata: ObjectMetadata;
52
+ }
53
+ export interface ObjectDataWithId {
54
+ id: string;
55
+ data: ObjectData;
56
+ }
57
+ export interface ObjectWithId {
37
58
  id: string;
59
+ metadata: ObjectMetadata;
60
+ data: ObjectData;
38
61
  }
39
- export type MonitorCallback = (objects: ObjectWithId[]) => void;
62
+ export type MonitorCallback = (objects: ObjectMetadataWithId[]) => void;
40
63
  export type DemonitorFunction = () => void;
package/dist/types.js CHANGED
@@ -1,2 +1,3 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ ;
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@concord-consortium/object-storage",
3
- "version": "1.0.0-pre.4",
3
+ "version": "1.0.0-pre.6",
4
4
  "description": "A TypeScript library for object storage",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "scripts": {
8
8
  "build": "tsc",
9
+ "build:watch": "tsc --watch",
9
10
  "test": "jest",
10
11
  "test:watch": "jest --watch",
11
12
  "test:coverage": "jest --coverage",
@@ -25,6 +26,7 @@
25
26
  "access": "public"
26
27
  },
27
28
  "dependencies": {
29
+ "firebase": "^9.8.1",
28
30
  "nanoid": "^3.3.7"
29
31
  },
30
32
  "peerDependencies": {