@cocreate/firestore 1.0.0 → 1.1.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.
- package/CHANGELOG.md +7 -0
- package/package.json +1 -1
- package/src/index.js +42 -23
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# [1.1.0](https://github.com/CoCreate-app/CoCreate-firestore/compare/v1.0.0...v1.1.0) (2026-07-18)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* Enhance Firestore client connection handling and normalize storage URL usage ([a97f76b](https://github.com/CoCreate-app/CoCreate-firestore/commit/a97f76b0dde45697e24875af2436e3b53c3b5b8f))
|
|
7
|
+
|
|
1
8
|
# 1.0.0 (2026-07-18)
|
|
2
9
|
|
|
3
10
|
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -12,26 +12,43 @@ const organizations = {};
|
|
|
12
12
|
/**
|
|
13
13
|
* Dynamically resolves or caches a long-lived Firestore database client connection.
|
|
14
14
|
* Caches the connection promise to prevent duplicate authentication handshakes.
|
|
15
|
-
* Normalizes custom credential protocols directly out of standard CoCreate storageUrls.
|
|
15
|
+
* Normalizes custom credential protocols directly out of standard CoCreate storageUrls or urls.
|
|
16
16
|
*/
|
|
17
17
|
async function dbClient(data) {
|
|
18
|
-
|
|
18
|
+
const storageUrl = data.storageUrl || data.url;
|
|
19
|
+
const storageName = data.storageName || data.provider || "firestore";
|
|
20
|
+
|
|
21
|
+
if (storageUrl) {
|
|
19
22
|
if (!organizations[data.organization_id]) {
|
|
20
23
|
organizations[data.organization_id] = {};
|
|
21
24
|
}
|
|
22
25
|
try {
|
|
23
|
-
if (!organizations[data.organization_id][
|
|
26
|
+
if (!organizations[data.organization_id][storageUrl]) {
|
|
24
27
|
const connectionPromise = (async () => {
|
|
25
28
|
let config = {};
|
|
26
29
|
|
|
27
|
-
// Option A: The Credentials
|
|
28
|
-
if (
|
|
29
|
-
const
|
|
30
|
+
// Option A: The Structured Credentials Object (Highly recommended)
|
|
31
|
+
if (typeof storageUrl === "object" && storageUrl !== null) {
|
|
32
|
+
const projectId = storageUrl.projectId || storageUrl.project_id;
|
|
33
|
+
const clientEmail = storageUrl.clientEmail || storageUrl.client_email;
|
|
34
|
+
const privateKey = storageUrl.privateKey || storageUrl.private_key;
|
|
35
|
+
|
|
36
|
+
config = {
|
|
37
|
+
projectId,
|
|
38
|
+
credentials: {
|
|
39
|
+
client_email: clientEmail,
|
|
40
|
+
private_key: privateKey ? privateKey.replace(/\\n/g, "\n") : undefined
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
// Option B: The Credentials Path URL (e.g. firestore:///path/to/credentials.json)
|
|
45
|
+
else if (typeof storageUrl === "string" && storageUrl.startsWith("firestore:///")) {
|
|
46
|
+
const filePath = storageUrl.replace("firestore://", "");
|
|
30
47
|
config = { keyFilename: filePath };
|
|
31
48
|
}
|
|
32
|
-
// Option
|
|
33
|
-
else if (
|
|
34
|
-
const urlParsed = new URL(
|
|
49
|
+
// Option C: Query Params Encoded URI (e.g. firestore://project-id?client_email=...&private_key=...)
|
|
50
|
+
else if (typeof storageUrl === "string" && storageUrl.startsWith("firestore://")) {
|
|
51
|
+
const urlParsed = new URL(storageUrl);
|
|
35
52
|
const projectId = urlParsed.host || urlParsed.hostname;
|
|
36
53
|
const clientEmail = urlParsed.searchParams.get("client_email");
|
|
37
54
|
const privateKey = urlParsed.searchParams.get("private_key");
|
|
@@ -57,21 +74,21 @@ async function dbClient(data) {
|
|
|
57
74
|
return client;
|
|
58
75
|
})();
|
|
59
76
|
|
|
60
|
-
organizations[data.organization_id][
|
|
77
|
+
organizations[data.organization_id][storageUrl] = connectionPromise;
|
|
61
78
|
}
|
|
62
79
|
|
|
63
80
|
// Await connection resolution safely
|
|
64
|
-
return await organizations[data.organization_id][
|
|
81
|
+
return await organizations[data.organization_id][storageUrl];
|
|
65
82
|
} catch (error) {
|
|
66
83
|
console.error(
|
|
67
|
-
`${data.organization_id}:
|
|
84
|
+
`${data.organization_id}: Firestore failed to connect`
|
|
68
85
|
);
|
|
69
86
|
errorHandler(data, error);
|
|
70
87
|
return { status: false };
|
|
71
88
|
}
|
|
72
89
|
}
|
|
73
90
|
|
|
74
|
-
errorHandler(data, "missing
|
|
91
|
+
errorHandler(data, "missing Firestore Connection URL/Credentials");
|
|
75
92
|
return;
|
|
76
93
|
}
|
|
77
94
|
|
|
@@ -121,6 +138,7 @@ function send(data) {
|
|
|
121
138
|
* "database" operations mapped to Firestore Databases.
|
|
122
139
|
*/
|
|
123
140
|
function database(method, data) {
|
|
141
|
+
const storageName = data.storageName || data.provider || "firestore";
|
|
124
142
|
return new Promise(
|
|
125
143
|
async (resolve, reject) => {
|
|
126
144
|
let type = "database";
|
|
@@ -147,13 +165,13 @@ function database(method, data) {
|
|
|
147
165
|
if (isFilter) {
|
|
148
166
|
databaseArray.push({
|
|
149
167
|
database: dbObj,
|
|
150
|
-
storage:
|
|
168
|
+
storage: storageName
|
|
151
169
|
});
|
|
152
170
|
}
|
|
153
171
|
} else {
|
|
154
172
|
databaseArray.push({
|
|
155
173
|
database: dbObj,
|
|
156
|
-
storage:
|
|
174
|
+
storage: storageName
|
|
157
175
|
});
|
|
158
176
|
}
|
|
159
177
|
resolve(createData(data, databaseArray, type));
|
|
@@ -187,6 +205,7 @@ function database(method, data) {
|
|
|
187
205
|
* "array" operations mapped to Firestore Collections.
|
|
188
206
|
*/
|
|
189
207
|
function array(method, data) {
|
|
208
|
+
const storageName = data.storageName || data.provider || "firestore";
|
|
190
209
|
return new Promise(
|
|
191
210
|
async (resolve, reject) => {
|
|
192
211
|
let type = "array";
|
|
@@ -220,14 +239,14 @@ function array(method, data) {
|
|
|
220
239
|
arrayArray.push({
|
|
221
240
|
name: col.id,
|
|
222
241
|
database,
|
|
223
|
-
storage:
|
|
242
|
+
storage: storageName
|
|
224
243
|
});
|
|
225
244
|
}
|
|
226
245
|
} else {
|
|
227
246
|
arrayArray.push({
|
|
228
247
|
name: col.id,
|
|
229
248
|
database,
|
|
230
|
-
storage:
|
|
249
|
+
storage: storageName
|
|
231
250
|
});
|
|
232
251
|
}
|
|
233
252
|
}
|
|
@@ -260,7 +279,7 @@ function array(method, data) {
|
|
|
260
279
|
arrayArray.push({
|
|
261
280
|
name: array,
|
|
262
281
|
database,
|
|
263
|
-
storage:
|
|
282
|
+
storage: storageName
|
|
264
283
|
});
|
|
265
284
|
|
|
266
285
|
arraysLength -= 1;
|
|
@@ -295,7 +314,7 @@ function array(method, data) {
|
|
|
295
314
|
name: newName,
|
|
296
315
|
oldName: oldName,
|
|
297
316
|
database,
|
|
298
|
-
storage:
|
|
317
|
+
storage: storageName
|
|
299
318
|
});
|
|
300
319
|
|
|
301
320
|
arraysLength -= 1;
|
|
@@ -319,7 +338,7 @@ function array(method, data) {
|
|
|
319
338
|
arrayArray.push({
|
|
320
339
|
name: array,
|
|
321
340
|
database,
|
|
322
|
-
storage:
|
|
341
|
+
storage: storageName
|
|
323
342
|
});
|
|
324
343
|
|
|
325
344
|
arraysLength -= 1;
|
|
@@ -349,6 +368,7 @@ function array(method, data) {
|
|
|
349
368
|
* "object" operations mapped to Firestore Documents.
|
|
350
369
|
*/
|
|
351
370
|
function object(method, data) {
|
|
371
|
+
const storageName = data.storageName || data.provider || "firestore";
|
|
352
372
|
return new Promise(
|
|
353
373
|
async (resolve, reject) => {
|
|
354
374
|
try {
|
|
@@ -371,7 +391,7 @@ function object(method, data) {
|
|
|
371
391
|
|
|
372
392
|
for (let array of arrays) {
|
|
373
393
|
const reference = {
|
|
374
|
-
$storage:
|
|
394
|
+
$storage: storageName,
|
|
375
395
|
$database: database,
|
|
376
396
|
$array: array
|
|
377
397
|
};
|
|
@@ -396,7 +416,7 @@ function object(method, data) {
|
|
|
396
416
|
if (!Array.isArray($database)) $database = [data[type][i].$database];
|
|
397
417
|
if (!Array.isArray($array)) $array = [data[type][i].$array];
|
|
398
418
|
|
|
399
|
-
if (!$storage.includes(
|
|
419
|
+
if (!$storage.includes(storageName)) $storage.push(storageName);
|
|
400
420
|
if (!$database.includes(database)) $database.push(database);
|
|
401
421
|
if (!$array.includes(array)) $array.push(array);
|
|
402
422
|
|
|
@@ -456,7 +476,6 @@ function object(method, data) {
|
|
|
456
476
|
queryRef = queryRef.limit(data.$filter.limit);
|
|
457
477
|
}
|
|
458
478
|
if (data.$filter && typeof data.$filter.index === "number") {
|
|
459
|
-
// Standard offset queries are supported but startAt is normally preferred in production
|
|
460
479
|
queryRef = queryRef.offset(data.$filter.index);
|
|
461
480
|
}
|
|
462
481
|
|