firebase-rest-firestore 0.3.1 → 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/dist/client.d.ts +60 -3
- package/dist/client.js +167 -17
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -1
- package/package.json +5 -2
- package/dist/cjs/index.d.ts +0 -59
- package/dist/cjs/index.js +0 -388
- package/dist/esm/index.d.ts +0 -59
- package/dist/esm/index.js +0 -349
package/dist/client.d.ts
CHANGED
|
@@ -33,6 +33,12 @@ export declare class FirestoreClient {
|
|
|
33
33
|
* @returns DocumentReferenceインスタンス
|
|
34
34
|
*/
|
|
35
35
|
doc(path: string): DocumentReference;
|
|
36
|
+
/**
|
|
37
|
+
* コレクショングループリファレンスを取得
|
|
38
|
+
* @param path コレクショングループのID
|
|
39
|
+
* @returns CollectionGroupインスタンス
|
|
40
|
+
*/
|
|
41
|
+
collectionGroup(path: string): CollectionGroup;
|
|
36
42
|
/**
|
|
37
43
|
* Firestoreにドキュメントを追加
|
|
38
44
|
* @param collectionName コレクション名
|
|
@@ -70,11 +76,12 @@ export declare class FirestoreClient {
|
|
|
70
76
|
delete(collectionName: string, documentId: string): Promise<boolean>;
|
|
71
77
|
/**
|
|
72
78
|
* コレクションのドキュメントを検索
|
|
73
|
-
* @param
|
|
79
|
+
* @param collectionPath コレクションパス
|
|
74
80
|
* @param options クエリオプション
|
|
81
|
+
* @param allDescendants 子孫コレクションを含むかどうか
|
|
75
82
|
* @returns 検索結果のドキュメント配列
|
|
76
83
|
*/
|
|
77
|
-
query(
|
|
84
|
+
query(collectionPath: string, options: QueryOptions | undefined, allDescendants: boolean): Promise<(Record<string, any> & {
|
|
78
85
|
id: string;
|
|
79
86
|
})[]>;
|
|
80
87
|
}
|
|
@@ -86,6 +93,10 @@ export declare class CollectionReference {
|
|
|
86
93
|
private path;
|
|
87
94
|
private _queryConstraints;
|
|
88
95
|
constructor(client: FirestoreClient, path: string);
|
|
96
|
+
/**
|
|
97
|
+
* すべての子孫コレクションを含むかどうか
|
|
98
|
+
*/
|
|
99
|
+
get allDescendants(): boolean;
|
|
89
100
|
/**
|
|
90
101
|
* ドキュメントリファレンスを取得
|
|
91
102
|
* @param documentPath ドキュメントID(省略時は自動生成)
|
|
@@ -184,12 +195,58 @@ export declare class DocumentReference {
|
|
|
184
195
|
*/
|
|
185
196
|
delete(): Promise<WriteResult>;
|
|
186
197
|
}
|
|
198
|
+
/**
|
|
199
|
+
* コレクショングループ
|
|
200
|
+
*/
|
|
201
|
+
export declare class CollectionGroup {
|
|
202
|
+
private client;
|
|
203
|
+
private path;
|
|
204
|
+
private _queryConstraints;
|
|
205
|
+
constructor(client: FirestoreClient, path: string);
|
|
206
|
+
/**
|
|
207
|
+
* すべての子孫コレクションを含むかどうか
|
|
208
|
+
*/
|
|
209
|
+
get allDescendants(): boolean;
|
|
210
|
+
/**
|
|
211
|
+
* フィルター条件を追加
|
|
212
|
+
* @param fieldPath フィールドパス
|
|
213
|
+
* @param opStr 演算子
|
|
214
|
+
* @param value 値
|
|
215
|
+
* @returns Queryインスタンス
|
|
216
|
+
*/
|
|
217
|
+
where(fieldPath: string, opStr: string, value: any): Query;
|
|
218
|
+
/**
|
|
219
|
+
* 並べ替え条件を追加
|
|
220
|
+
* @param fieldPath フィールドパス
|
|
221
|
+
* @param directionStr 並べ替え方向('asc'または'desc')
|
|
222
|
+
* @returns Queryインスタンス
|
|
223
|
+
*/
|
|
224
|
+
orderBy(fieldPath: string, directionStr?: "asc" | "desc"): Query;
|
|
225
|
+
/**
|
|
226
|
+
* 取得件数の制限を設定
|
|
227
|
+
* @param limit 最大件数
|
|
228
|
+
* @returns Queryインスタンス
|
|
229
|
+
*/
|
|
230
|
+
limit(limit: number): Query;
|
|
231
|
+
/**
|
|
232
|
+
* スキップ件数を設定
|
|
233
|
+
* @param offset スキップ件数
|
|
234
|
+
* @returns Queryインスタンス
|
|
235
|
+
*/
|
|
236
|
+
offset(offset: number): Query;
|
|
237
|
+
/**
|
|
238
|
+
* クエリを実行
|
|
239
|
+
* @returns QuerySnapshotインスタンス
|
|
240
|
+
*/
|
|
241
|
+
get(): Promise<QuerySnapshot>;
|
|
242
|
+
}
|
|
187
243
|
/**
|
|
188
244
|
* クエリクラス
|
|
189
245
|
*/
|
|
190
246
|
export declare class Query {
|
|
191
247
|
private client;
|
|
192
248
|
private collectionPath;
|
|
249
|
+
private allDescendants;
|
|
193
250
|
_queryConstraints: {
|
|
194
251
|
where: Array<{
|
|
195
252
|
field: string;
|
|
@@ -211,7 +268,7 @@ export declare class Query {
|
|
|
211
268
|
orderDirection?: string;
|
|
212
269
|
limit?: number;
|
|
213
270
|
offset?: number;
|
|
214
|
-
});
|
|
271
|
+
}, allDescendants: boolean);
|
|
215
272
|
/**
|
|
216
273
|
* フィルター条件を追加
|
|
217
274
|
* @param fieldPath フィールドパス
|
package/dist/client.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.WriteResult = exports.DocumentSnapshot = exports.QuerySnapshot = exports.Query = exports.DocumentReference = exports.CollectionReference = exports.FirestoreClient = void 0;
|
|
3
|
+
exports.WriteResult = exports.DocumentSnapshot = exports.QuerySnapshot = exports.Query = exports.CollectionGroup = exports.DocumentReference = exports.CollectionReference = exports.FirestoreClient = void 0;
|
|
4
4
|
exports.createFirestoreClient = createFirestoreClient;
|
|
5
5
|
const auth_1 = require("./utils/auth");
|
|
6
6
|
const converter_1 = require("./utils/converter");
|
|
@@ -81,6 +81,14 @@ class FirestoreClient {
|
|
|
81
81
|
const docId = parts[parts.length - 1];
|
|
82
82
|
return new DocumentReference(this, collectionPath, docId);
|
|
83
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* コレクショングループリファレンスを取得
|
|
86
|
+
* @param path コレクショングループのID
|
|
87
|
+
* @returns CollectionGroupインスタンス
|
|
88
|
+
*/
|
|
89
|
+
collectionGroup(path) {
|
|
90
|
+
return new CollectionGroup(this, path);
|
|
91
|
+
}
|
|
84
92
|
/**
|
|
85
93
|
* Firestoreにドキュメントを追加
|
|
86
94
|
* @param collectionName コレクション名
|
|
@@ -184,20 +192,35 @@ class FirestoreClient {
|
|
|
184
192
|
}
|
|
185
193
|
/**
|
|
186
194
|
* コレクションのドキュメントを検索
|
|
187
|
-
* @param
|
|
195
|
+
* @param collectionPath コレクションパス
|
|
188
196
|
* @param options クエリオプション
|
|
197
|
+
* @param allDescendants 子孫コレクションを含むかどうか
|
|
189
198
|
* @returns 検索結果のドキュメント配列
|
|
190
199
|
*/
|
|
191
|
-
async query(
|
|
200
|
+
async query(collectionPath, options = {}, allDescendants) {
|
|
192
201
|
// 操作前に設定をチェック
|
|
193
202
|
this.checkConfig();
|
|
194
|
-
// 修正: URLの形式を修正
|
|
195
203
|
// :runQueryはコレクション単位ではなく、ドキュメントルート単位で実行
|
|
196
|
-
|
|
204
|
+
// コレクション名パス形式の場合は、endpointをドキュメントルートに置き換える。collectionNameはコレクションIDにする
|
|
205
|
+
// e.g) パス形式: collectionPath = "/users/123/items" の場合は、collectionPaths = ["users", "123", "items"], collectionName = "items", basePath += "/users/123"
|
|
206
|
+
// e.g) 単一形式: collectionPath = "items" の場合は、collectionPaths = ["items"], collectionName = "items", basePath += ""
|
|
207
|
+
const collectionPaths = collectionPath.split("/");
|
|
208
|
+
let basePath = `https://firestore.googleapis.com/v1/projects/${this.config.projectId}/databases/(default)/documents`;
|
|
209
|
+
let collectionName = collectionPath;
|
|
210
|
+
if (collectionPaths.length > 1) {
|
|
211
|
+
basePath = `${basePath}/${collectionPaths.slice(0, -1).join("/")}`;
|
|
212
|
+
collectionName = collectionPaths[collectionPaths.length - 1];
|
|
213
|
+
}
|
|
197
214
|
const url = `${basePath}:runQuery`;
|
|
198
215
|
// クエリ構築
|
|
216
|
+
//allDescendants: falseの場合は直下のcollectionを参照。trueの場合は子孫コレクションも参照
|
|
199
217
|
const structuredQuery = {
|
|
200
|
-
from: [
|
|
218
|
+
from: [
|
|
219
|
+
{
|
|
220
|
+
collectionId: collectionName,
|
|
221
|
+
allDescendants,
|
|
222
|
+
},
|
|
223
|
+
],
|
|
201
224
|
};
|
|
202
225
|
// フィルター条件
|
|
203
226
|
if (options.where && options.where.length > 0) {
|
|
@@ -291,6 +314,12 @@ class CollectionReference {
|
|
|
291
314
|
where: [],
|
|
292
315
|
};
|
|
293
316
|
}
|
|
317
|
+
/**
|
|
318
|
+
* すべての子孫コレクションを含むかどうか
|
|
319
|
+
*/
|
|
320
|
+
get allDescendants() {
|
|
321
|
+
return false;
|
|
322
|
+
}
|
|
294
323
|
/**
|
|
295
324
|
* ドキュメントリファレンスを取得
|
|
296
325
|
* @param documentPath ドキュメントID(省略時は自動生成)
|
|
@@ -320,7 +349,7 @@ class CollectionReference {
|
|
|
320
349
|
where(fieldPath, opStr, value) {
|
|
321
350
|
const query = new Query(this.client, this.path, {
|
|
322
351
|
...this._queryConstraints,
|
|
323
|
-
});
|
|
352
|
+
}, this.allDescendants);
|
|
324
353
|
// 演算子の変換
|
|
325
354
|
let firestoreOp;
|
|
326
355
|
switch (opStr) {
|
|
@@ -373,7 +402,7 @@ class CollectionReference {
|
|
|
373
402
|
orderBy(fieldPath, directionStr = "asc") {
|
|
374
403
|
const query = new Query(this.client, this.path, {
|
|
375
404
|
...this._queryConstraints,
|
|
376
|
-
});
|
|
405
|
+
}, this.allDescendants);
|
|
377
406
|
query._queryConstraints.orderBy = fieldPath;
|
|
378
407
|
query._queryConstraints.orderDirection =
|
|
379
408
|
directionStr === "asc" ? "ASCENDING" : "DESCENDING";
|
|
@@ -387,7 +416,7 @@ class CollectionReference {
|
|
|
387
416
|
limit(limit) {
|
|
388
417
|
const query = new Query(this.client, this.path, {
|
|
389
418
|
...this._queryConstraints,
|
|
390
|
-
});
|
|
419
|
+
}, this.allDescendants);
|
|
391
420
|
query._queryConstraints.limit = limit;
|
|
392
421
|
return query;
|
|
393
422
|
}
|
|
@@ -399,7 +428,7 @@ class CollectionReference {
|
|
|
399
428
|
offset(offset) {
|
|
400
429
|
const query = new Query(this.client, this.path, {
|
|
401
430
|
...this._queryConstraints,
|
|
402
|
-
});
|
|
431
|
+
}, this.allDescendants);
|
|
403
432
|
query._queryConstraints.offset = offset;
|
|
404
433
|
return query;
|
|
405
434
|
}
|
|
@@ -408,7 +437,7 @@ class CollectionReference {
|
|
|
408
437
|
* @returns QuerySnapshotインスタンス
|
|
409
438
|
*/
|
|
410
439
|
async get() {
|
|
411
|
-
const results = await this.client.query(this.path, this._queryConstraints);
|
|
440
|
+
const results = await this.client.query(this.path, this._queryConstraints, this.allDescendants);
|
|
412
441
|
return new QuerySnapshot(results);
|
|
413
442
|
}
|
|
414
443
|
/**
|
|
@@ -503,14 +532,135 @@ class DocumentReference {
|
|
|
503
532
|
}
|
|
504
533
|
}
|
|
505
534
|
exports.DocumentReference = DocumentReference;
|
|
535
|
+
/**
|
|
536
|
+
* コレクショングループ
|
|
537
|
+
*/
|
|
538
|
+
class CollectionGroup {
|
|
539
|
+
constructor(client, path) {
|
|
540
|
+
this.client = client;
|
|
541
|
+
this.path = path;
|
|
542
|
+
this._queryConstraints = {
|
|
543
|
+
where: [],
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
* すべての子孫コレクションを含むかどうか
|
|
548
|
+
*/
|
|
549
|
+
get allDescendants() {
|
|
550
|
+
return true;
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* フィルター条件を追加
|
|
554
|
+
* @param fieldPath フィールドパス
|
|
555
|
+
* @param opStr 演算子
|
|
556
|
+
* @param value 値
|
|
557
|
+
* @returns Queryインスタンス
|
|
558
|
+
*/
|
|
559
|
+
where(fieldPath, opStr, value) {
|
|
560
|
+
const query = new Query(this.client, this.path, {
|
|
561
|
+
...this._queryConstraints,
|
|
562
|
+
}, this.allDescendants);
|
|
563
|
+
// 演算子の変換
|
|
564
|
+
let firestoreOp;
|
|
565
|
+
switch (opStr) {
|
|
566
|
+
case "==":
|
|
567
|
+
firestoreOp = "EQUAL";
|
|
568
|
+
break;
|
|
569
|
+
case "!=":
|
|
570
|
+
firestoreOp = "NOT_EQUAL";
|
|
571
|
+
break;
|
|
572
|
+
case "<":
|
|
573
|
+
firestoreOp = "LESS_THAN";
|
|
574
|
+
break;
|
|
575
|
+
case "<=":
|
|
576
|
+
firestoreOp = "LESS_THAN_OR_EQUAL";
|
|
577
|
+
break;
|
|
578
|
+
case ">":
|
|
579
|
+
firestoreOp = "GREATER_THAN";
|
|
580
|
+
break;
|
|
581
|
+
case ">=":
|
|
582
|
+
firestoreOp = "GREATER_THAN_OR_EQUAL";
|
|
583
|
+
break;
|
|
584
|
+
case "array-contains":
|
|
585
|
+
firestoreOp = "ARRAY_CONTAINS";
|
|
586
|
+
break;
|
|
587
|
+
case "in":
|
|
588
|
+
firestoreOp = "IN";
|
|
589
|
+
break;
|
|
590
|
+
case "array-contains-any":
|
|
591
|
+
firestoreOp = "ARRAY_CONTAINS_ANY";
|
|
592
|
+
break;
|
|
593
|
+
case "not-in":
|
|
594
|
+
firestoreOp = "NOT_IN";
|
|
595
|
+
break;
|
|
596
|
+
default:
|
|
597
|
+
firestoreOp = opStr;
|
|
598
|
+
}
|
|
599
|
+
query._queryConstraints.where.push({
|
|
600
|
+
field: fieldPath,
|
|
601
|
+
op: firestoreOp,
|
|
602
|
+
value,
|
|
603
|
+
});
|
|
604
|
+
return query;
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* 並べ替え条件を追加
|
|
608
|
+
* @param fieldPath フィールドパス
|
|
609
|
+
* @param directionStr 並べ替え方向('asc'または'desc')
|
|
610
|
+
* @returns Queryインスタンス
|
|
611
|
+
*/
|
|
612
|
+
orderBy(fieldPath, directionStr = "asc") {
|
|
613
|
+
const query = new Query(this.client, this.path, {
|
|
614
|
+
...this._queryConstraints,
|
|
615
|
+
}, this.allDescendants);
|
|
616
|
+
query._queryConstraints.orderBy = fieldPath;
|
|
617
|
+
query._queryConstraints.orderDirection =
|
|
618
|
+
directionStr === "asc" ? "ASCENDING" : "DESCENDING";
|
|
619
|
+
return query;
|
|
620
|
+
}
|
|
621
|
+
/**
|
|
622
|
+
* 取得件数の制限を設定
|
|
623
|
+
* @param limit 最大件数
|
|
624
|
+
* @returns Queryインスタンス
|
|
625
|
+
*/
|
|
626
|
+
limit(limit) {
|
|
627
|
+
const query = new Query(this.client, this.path, {
|
|
628
|
+
...this._queryConstraints,
|
|
629
|
+
}, this.allDescendants);
|
|
630
|
+
query._queryConstraints.limit = limit;
|
|
631
|
+
return query;
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* スキップ件数を設定
|
|
635
|
+
* @param offset スキップ件数
|
|
636
|
+
* @returns Queryインスタンス
|
|
637
|
+
*/
|
|
638
|
+
offset(offset) {
|
|
639
|
+
const query = new Query(this.client, this.path, {
|
|
640
|
+
...this._queryConstraints,
|
|
641
|
+
}, this.allDescendants);
|
|
642
|
+
query._queryConstraints.offset = offset;
|
|
643
|
+
return query;
|
|
644
|
+
}
|
|
645
|
+
/**
|
|
646
|
+
* クエリを実行
|
|
647
|
+
* @returns QuerySnapshotインスタンス
|
|
648
|
+
*/
|
|
649
|
+
async get() {
|
|
650
|
+
const results = await this.client.query(this.path, this._queryConstraints, this.allDescendants);
|
|
651
|
+
return new QuerySnapshot(results);
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
exports.CollectionGroup = CollectionGroup;
|
|
506
655
|
/**
|
|
507
656
|
* クエリクラス
|
|
508
657
|
*/
|
|
509
658
|
class Query {
|
|
510
|
-
constructor(client, collectionPath, constraints) {
|
|
659
|
+
constructor(client, collectionPath, constraints, allDescendants) {
|
|
511
660
|
this.client = client;
|
|
512
661
|
this.collectionPath = collectionPath;
|
|
513
662
|
this._queryConstraints = constraints;
|
|
663
|
+
this.allDescendants = allDescendants;
|
|
514
664
|
}
|
|
515
665
|
/**
|
|
516
666
|
* フィルター条件を追加
|
|
@@ -522,7 +672,7 @@ class Query {
|
|
|
522
672
|
where(fieldPath, opStr, value) {
|
|
523
673
|
const query = new Query(this.client, this.collectionPath, {
|
|
524
674
|
...this._queryConstraints,
|
|
525
|
-
});
|
|
675
|
+
}, this.allDescendants);
|
|
526
676
|
// 演算子の変換
|
|
527
677
|
let firestoreOp;
|
|
528
678
|
switch (opStr) {
|
|
@@ -575,7 +725,7 @@ class Query {
|
|
|
575
725
|
orderBy(fieldPath, directionStr = "asc") {
|
|
576
726
|
const query = new Query(this.client, this.collectionPath, {
|
|
577
727
|
...this._queryConstraints,
|
|
578
|
-
});
|
|
728
|
+
}, this.allDescendants);
|
|
579
729
|
query._queryConstraints.orderBy = fieldPath;
|
|
580
730
|
query._queryConstraints.orderDirection =
|
|
581
731
|
directionStr === "asc" ? "ASCENDING" : "DESCENDING";
|
|
@@ -589,7 +739,7 @@ class Query {
|
|
|
589
739
|
limit(limit) {
|
|
590
740
|
const query = new Query(this.client, this.collectionPath, {
|
|
591
741
|
...this._queryConstraints,
|
|
592
|
-
});
|
|
742
|
+
}, this.allDescendants);
|
|
593
743
|
query._queryConstraints.limit = limit;
|
|
594
744
|
return query;
|
|
595
745
|
}
|
|
@@ -601,7 +751,7 @@ class Query {
|
|
|
601
751
|
offset(offset) {
|
|
602
752
|
const query = new Query(this.client, this.collectionPath, {
|
|
603
753
|
...this._queryConstraints,
|
|
604
|
-
});
|
|
754
|
+
}, this.allDescendants);
|
|
605
755
|
query._queryConstraints.offset = offset;
|
|
606
756
|
return query;
|
|
607
757
|
}
|
|
@@ -610,7 +760,7 @@ class Query {
|
|
|
610
760
|
* @returns QuerySnapshotインスタンス
|
|
611
761
|
*/
|
|
612
762
|
async get() {
|
|
613
|
-
const results = await this.client.query(this.collectionPath, this._queryConstraints);
|
|
763
|
+
const results = await this.client.query(this.collectionPath, this._queryConstraints, this.allDescendants);
|
|
614
764
|
return new QuerySnapshot(results);
|
|
615
765
|
}
|
|
616
766
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export * from "./types";
|
|
2
|
-
import { FirestoreClient, createFirestoreClient, CollectionReference, DocumentReference, Query, QuerySnapshot, DocumentSnapshot, WriteResult } from "./client";
|
|
2
|
+
import { FirestoreClient, createFirestoreClient, CollectionReference, DocumentReference, CollectionGroup, Query, QuerySnapshot, DocumentSnapshot, WriteResult } from "./client";
|
|
3
3
|
export { getFirestoreToken } from "./utils/auth";
|
|
4
4
|
export { convertToFirestoreValue, convertFromFirestoreValue, convertToFirestoreDocument, convertFromFirestoreDocument, } from "./utils/converter";
|
|
5
5
|
export { getFirestoreBasePath, getDocumentId } from "./utils/path";
|
|
6
6
|
export { formatPrivateKey, formatConfig } from "./utils/config";
|
|
7
|
-
export { FirestoreClient, createFirestoreClient, CollectionReference, DocumentReference, Query, QuerySnapshot, DocumentSnapshot, WriteResult, };
|
|
7
|
+
export { FirestoreClient, createFirestoreClient, CollectionReference, DocumentReference, CollectionGroup, Query, QuerySnapshot, DocumentSnapshot, WriteResult, };
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.WriteResult = exports.DocumentSnapshot = exports.QuerySnapshot = exports.Query = exports.DocumentReference = exports.CollectionReference = exports.createFirestoreClient = exports.FirestoreClient = exports.formatConfig = exports.formatPrivateKey = exports.getDocumentId = exports.getFirestoreBasePath = exports.convertFromFirestoreDocument = exports.convertToFirestoreDocument = exports.convertFromFirestoreValue = exports.convertToFirestoreValue = exports.getFirestoreToken = void 0;
|
|
17
|
+
exports.WriteResult = exports.DocumentSnapshot = exports.QuerySnapshot = exports.Query = exports.CollectionGroup = exports.DocumentReference = exports.CollectionReference = exports.createFirestoreClient = exports.FirestoreClient = exports.formatConfig = exports.formatPrivateKey = exports.getDocumentId = exports.getFirestoreBasePath = exports.convertFromFirestoreDocument = exports.convertToFirestoreDocument = exports.convertFromFirestoreValue = exports.convertToFirestoreValue = exports.getFirestoreToken = void 0;
|
|
18
18
|
// 型定義のエクスポート
|
|
19
19
|
__exportStar(require("./types"), exports);
|
|
20
20
|
// クライアントのエクスポート
|
|
@@ -23,6 +23,7 @@ Object.defineProperty(exports, "FirestoreClient", { enumerable: true, get: funct
|
|
|
23
23
|
Object.defineProperty(exports, "createFirestoreClient", { enumerable: true, get: function () { return client_1.createFirestoreClient; } });
|
|
24
24
|
Object.defineProperty(exports, "CollectionReference", { enumerable: true, get: function () { return client_1.CollectionReference; } });
|
|
25
25
|
Object.defineProperty(exports, "DocumentReference", { enumerable: true, get: function () { return client_1.DocumentReference; } });
|
|
26
|
+
Object.defineProperty(exports, "CollectionGroup", { enumerable: true, get: function () { return client_1.CollectionGroup; } });
|
|
26
27
|
Object.defineProperty(exports, "Query", { enumerable: true, get: function () { return client_1.Query; } });
|
|
27
28
|
Object.defineProperty(exports, "QuerySnapshot", { enumerable: true, get: function () { return client_1.QuerySnapshot; } });
|
|
28
29
|
Object.defineProperty(exports, "DocumentSnapshot", { enumerable: true, get: function () { return client_1.DocumentSnapshot; } });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "firebase-rest-firestore",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Firebase Firestore REST API client for Edge runtime environments",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -29,13 +29,16 @@
|
|
|
29
29
|
"jose": "^4.14.4"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
33
|
+
"@semantic-release/git": "^10.0.1",
|
|
32
34
|
"@types/node": "^18.16.0",
|
|
33
35
|
"dotenv": "^16.4.7",
|
|
36
|
+
"semantic-release": "^24.2.3",
|
|
34
37
|
"typescript": "^5.0.4",
|
|
35
38
|
"vitest": "^3.0.9"
|
|
36
39
|
},
|
|
37
40
|
"engines": {
|
|
38
|
-
"node": ">=
|
|
41
|
+
"node": ">=20.8.1"
|
|
39
42
|
},
|
|
40
43
|
"repository": {
|
|
41
44
|
"type": "git",
|
package/dist/cjs/index.d.ts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Firestoreの認証トークンを取得する関数
|
|
3
|
-
*/
|
|
4
|
-
export declare function getFirestoreToken(): Promise<string>;
|
|
5
|
-
/**
|
|
6
|
-
* Firestoreクライアントクラス
|
|
7
|
-
*/
|
|
8
|
-
export declare class FirestoreClient {
|
|
9
|
-
private token;
|
|
10
|
-
private tokenExpiry;
|
|
11
|
-
/**
|
|
12
|
-
* 認証トークンを取得(キャッシュあり)
|
|
13
|
-
*/
|
|
14
|
-
private getToken;
|
|
15
|
-
/**
|
|
16
|
-
* Firestoreにドキュメントを作成
|
|
17
|
-
*/
|
|
18
|
-
create(collectionName: string, data: Record<string, any>): Promise<Record<string, any> & {
|
|
19
|
-
id: string;
|
|
20
|
-
}>;
|
|
21
|
-
/**
|
|
22
|
-
* ドキュメントを取得
|
|
23
|
-
*/
|
|
24
|
-
get(collectionName: string, documentId: string): Promise<(Record<string, any> & {
|
|
25
|
-
id: string;
|
|
26
|
-
}) | null>;
|
|
27
|
-
/**
|
|
28
|
-
* ドキュメントを更新
|
|
29
|
-
*/
|
|
30
|
-
update(collectionName: string, documentId: string, data: Record<string, any>): Promise<Record<string, any> & {
|
|
31
|
-
id: string;
|
|
32
|
-
}>;
|
|
33
|
-
/**
|
|
34
|
-
* ドキュメントを削除
|
|
35
|
-
*/
|
|
36
|
-
delete(collectionName: string, documentId: string): Promise<boolean>;
|
|
37
|
-
/**
|
|
38
|
-
* コレクションのドキュメントを検索
|
|
39
|
-
*/
|
|
40
|
-
query(collectionName: string, options?: {
|
|
41
|
-
where?: Array<{
|
|
42
|
-
field: string;
|
|
43
|
-
op: string;
|
|
44
|
-
value: any;
|
|
45
|
-
}>;
|
|
46
|
-
orderBy?: string;
|
|
47
|
-
limit?: number;
|
|
48
|
-
offset?: number;
|
|
49
|
-
}): Promise<(Record<string, any> & {
|
|
50
|
-
id: string;
|
|
51
|
-
})[]>;
|
|
52
|
-
}
|
|
53
|
-
export declare const firestore: FirestoreClient;
|
|
54
|
-
export declare function saveToFirestore(collectionName: string, data: Record<string, any>): Promise<{
|
|
55
|
-
documentId: string;
|
|
56
|
-
result: Record<string, any> & {
|
|
57
|
-
id: string;
|
|
58
|
-
};
|
|
59
|
-
}>;
|
package/dist/cjs/index.js
DELETED
|
@@ -1,388 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.firestore = exports.FirestoreClient = void 0;
|
|
37
|
-
exports.getFirestoreToken = getFirestoreToken;
|
|
38
|
-
exports.saveToFirestore = saveToFirestore;
|
|
39
|
-
const jose = __importStar(require("jose"));
|
|
40
|
-
// Firestore関連の定数
|
|
41
|
-
const FIREBASE_PROJECT_ID = process.env.FIREBASE_PROJECT_ID;
|
|
42
|
-
const FIREBASE_PRIVATE_KEY_ID = process.env.FIREBASE_PRIVATE_KEY_ID;
|
|
43
|
-
const FIREBASE_PRIVATE_KEY = process.env.FIREBASE_PRIVATE_KEY?.replace(/\\n/g, "\n");
|
|
44
|
-
const FIREBASE_CLIENT_EMAIL = process.env.FIREBASE_CLIENT_EMAIL;
|
|
45
|
-
const FIREBASE_CLIENT_ID = process.env.FIREBASE_CLIENT_ID;
|
|
46
|
-
const FIREBASE_CLIENT_CERT_URL = process.env.FIREBASE_CLIENT_CERT_URL;
|
|
47
|
-
// サービスアカウント情報
|
|
48
|
-
const serviceAccount = {
|
|
49
|
-
type: "service_account",
|
|
50
|
-
project_id: FIREBASE_PROJECT_ID,
|
|
51
|
-
private_key_id: FIREBASE_PRIVATE_KEY_ID,
|
|
52
|
-
private_key: FIREBASE_PRIVATE_KEY,
|
|
53
|
-
client_email: FIREBASE_CLIENT_EMAIL,
|
|
54
|
-
client_id: FIREBASE_CLIENT_ID,
|
|
55
|
-
auth_uri: "https://accounts.google.com/o/oauth2/auth",
|
|
56
|
-
token_uri: "https://oauth2.googleapis.com/token",
|
|
57
|
-
auth_provider_x509_cert_url: "https://www.googleapis.com/oauth2/v1/certs",
|
|
58
|
-
client_x509_cert_url: FIREBASE_CLIENT_CERT_URL,
|
|
59
|
-
};
|
|
60
|
-
// Firestoreのベースパス
|
|
61
|
-
const getFirestoreBasePath = (collectionName) => {
|
|
62
|
-
const basePath = `https://firestore.googleapis.com/v1/projects/${FIREBASE_PROJECT_ID}/databases/(default)/documents`;
|
|
63
|
-
return collectionName ? `${basePath}/${collectionName}` : basePath;
|
|
64
|
-
};
|
|
65
|
-
/**
|
|
66
|
-
* JSの値をFirestore形式に変換する
|
|
67
|
-
*/
|
|
68
|
-
function convertToFirestoreValue(value) {
|
|
69
|
-
if (value instanceof Date) {
|
|
70
|
-
return { timestampValue: value.toISOString() };
|
|
71
|
-
}
|
|
72
|
-
else if (typeof value === "string") {
|
|
73
|
-
return { stringValue: value };
|
|
74
|
-
}
|
|
75
|
-
else if (typeof value === "number") {
|
|
76
|
-
return Number.isInteger(value)
|
|
77
|
-
? { integerValue: value }
|
|
78
|
-
: { doubleValue: value };
|
|
79
|
-
}
|
|
80
|
-
else if (typeof value === "boolean") {
|
|
81
|
-
return { booleanValue: value };
|
|
82
|
-
}
|
|
83
|
-
else if (value === null || value === undefined) {
|
|
84
|
-
return { nullValue: null };
|
|
85
|
-
}
|
|
86
|
-
else if (Array.isArray(value)) {
|
|
87
|
-
return {
|
|
88
|
-
arrayValue: {
|
|
89
|
-
values: value.map(item => convertToFirestoreValue(item)),
|
|
90
|
-
},
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
else if (typeof value === "object") {
|
|
94
|
-
const fields = Object.entries(value).reduce((acc, [key, val]) => ({
|
|
95
|
-
...acc,
|
|
96
|
-
[key]: convertToFirestoreValue(val),
|
|
97
|
-
}), {});
|
|
98
|
-
return { mapValue: { fields } };
|
|
99
|
-
}
|
|
100
|
-
// デフォルトは文字列化
|
|
101
|
-
return { stringValue: String(value) };
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* Firestore形式からJSの値に変換する
|
|
105
|
-
*/
|
|
106
|
-
function convertFromFirestoreValue(firestoreValue) {
|
|
107
|
-
if ("stringValue" in firestoreValue) {
|
|
108
|
-
return firestoreValue.stringValue;
|
|
109
|
-
}
|
|
110
|
-
else if ("integerValue" in firestoreValue) {
|
|
111
|
-
return Number(firestoreValue.integerValue);
|
|
112
|
-
}
|
|
113
|
-
else if ("doubleValue" in firestoreValue) {
|
|
114
|
-
return firestoreValue.doubleValue;
|
|
115
|
-
}
|
|
116
|
-
else if ("booleanValue" in firestoreValue) {
|
|
117
|
-
return firestoreValue.booleanValue;
|
|
118
|
-
}
|
|
119
|
-
else if ("nullValue" in firestoreValue) {
|
|
120
|
-
return null;
|
|
121
|
-
}
|
|
122
|
-
else if ("timestampValue" in firestoreValue) {
|
|
123
|
-
return new Date(firestoreValue.timestampValue);
|
|
124
|
-
}
|
|
125
|
-
else if ("mapValue" in firestoreValue && firestoreValue.mapValue.fields) {
|
|
126
|
-
return Object.entries(firestoreValue.mapValue.fields).reduce((acc, [key, val]) => ({
|
|
127
|
-
...acc,
|
|
128
|
-
[key]: convertFromFirestoreValue(val),
|
|
129
|
-
}), {});
|
|
130
|
-
}
|
|
131
|
-
else if ("arrayValue" in firestoreValue &&
|
|
132
|
-
firestoreValue.arrayValue.values) {
|
|
133
|
-
return firestoreValue.arrayValue.values.map(convertFromFirestoreValue);
|
|
134
|
-
}
|
|
135
|
-
return null;
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* オブジェクトをFirestoreドキュメント形式に変換
|
|
139
|
-
*/
|
|
140
|
-
function convertToFirestoreDocument(data) {
|
|
141
|
-
return {
|
|
142
|
-
fields: Object.entries(data).reduce((acc, [key, value]) => ({
|
|
143
|
-
...acc,
|
|
144
|
-
[key]: convertToFirestoreValue(value),
|
|
145
|
-
}), {}),
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
/**
|
|
149
|
-
* Firestoreドキュメントをオブジェクトに変換
|
|
150
|
-
*/
|
|
151
|
-
function convertFromFirestoreDocument(doc) {
|
|
152
|
-
if (!doc.fields)
|
|
153
|
-
return { id: getDocumentId(doc.name) };
|
|
154
|
-
const result = Object.entries(doc.fields).reduce((acc, [key, value]) => ({
|
|
155
|
-
...acc,
|
|
156
|
-
[key]: convertFromFirestoreValue(value),
|
|
157
|
-
}), {});
|
|
158
|
-
return {
|
|
159
|
-
...result,
|
|
160
|
-
id: getDocumentId(doc.name),
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* ドキュメントパスからIDを抽出
|
|
165
|
-
*/
|
|
166
|
-
function getDocumentId(path) {
|
|
167
|
-
if (!path)
|
|
168
|
-
return "";
|
|
169
|
-
const pathParts = path.split("/");
|
|
170
|
-
return pathParts[pathParts.length - 1];
|
|
171
|
-
}
|
|
172
|
-
// JWT(JSON Web Token)を作成する関数
|
|
173
|
-
async function createJWT(serviceAccount) {
|
|
174
|
-
const now = Math.floor(Date.now() / 1000);
|
|
175
|
-
const payload = {
|
|
176
|
-
iss: serviceAccount.client_email,
|
|
177
|
-
sub: serviceAccount.client_email,
|
|
178
|
-
aud: "https://oauth2.googleapis.com/token",
|
|
179
|
-
iat: now,
|
|
180
|
-
exp: now + 3600, // 1時間後に期限切れ
|
|
181
|
-
scope: "https://www.googleapis.com/auth/datastore",
|
|
182
|
-
};
|
|
183
|
-
try {
|
|
184
|
-
// 秘密鍵をインポート
|
|
185
|
-
const privateKey = await jose.importPKCS8(serviceAccount.private_key, "RS256");
|
|
186
|
-
// JWTを作成
|
|
187
|
-
const token = await new jose.SignJWT(payload)
|
|
188
|
-
.setProtectedHeader({
|
|
189
|
-
alg: "RS256",
|
|
190
|
-
kid: serviceAccount.private_key_id,
|
|
191
|
-
typ: "JWT",
|
|
192
|
-
})
|
|
193
|
-
.sign(privateKey);
|
|
194
|
-
return token;
|
|
195
|
-
}
|
|
196
|
-
catch (error) {
|
|
197
|
-
console.error("JWT作成エラー:", error);
|
|
198
|
-
throw error;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
/**
|
|
202
|
-
* Firestoreの認証トークンを取得する関数
|
|
203
|
-
*/
|
|
204
|
-
async function getFirestoreToken() {
|
|
205
|
-
// トークンを取得するためのリクエスト
|
|
206
|
-
const response = await fetch("https://oauth2.googleapis.com/token", {
|
|
207
|
-
method: "POST",
|
|
208
|
-
headers: {
|
|
209
|
-
"Content-Type": "application/json",
|
|
210
|
-
},
|
|
211
|
-
body: JSON.stringify({
|
|
212
|
-
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
|
|
213
|
-
assertion: await createJWT(serviceAccount),
|
|
214
|
-
}),
|
|
215
|
-
});
|
|
216
|
-
const data = (await response.json());
|
|
217
|
-
return data.access_token;
|
|
218
|
-
}
|
|
219
|
-
/**
|
|
220
|
-
* Firestoreクライアントクラス
|
|
221
|
-
*/
|
|
222
|
-
class FirestoreClient {
|
|
223
|
-
constructor() {
|
|
224
|
-
this.token = null;
|
|
225
|
-
this.tokenExpiry = 0;
|
|
226
|
-
}
|
|
227
|
-
/**
|
|
228
|
-
* 認証トークンを取得(キャッシュあり)
|
|
229
|
-
*/
|
|
230
|
-
async getToken() {
|
|
231
|
-
const now = Date.now();
|
|
232
|
-
// トークンが期限切れか未取得の場合は新しく取得
|
|
233
|
-
if (!this.token || now >= this.tokenExpiry) {
|
|
234
|
-
this.token = await getFirestoreToken();
|
|
235
|
-
// 50分後に期限切れとする(実際は1時間)
|
|
236
|
-
this.tokenExpiry = now + 50 * 60 * 1000;
|
|
237
|
-
}
|
|
238
|
-
return this.token;
|
|
239
|
-
}
|
|
240
|
-
/**
|
|
241
|
-
* Firestoreにドキュメントを作成
|
|
242
|
-
*/
|
|
243
|
-
async create(collectionName, data) {
|
|
244
|
-
const url = getFirestoreBasePath(collectionName);
|
|
245
|
-
const firestoreData = convertToFirestoreDocument(data);
|
|
246
|
-
const token = await this.getToken();
|
|
247
|
-
const response = await fetch(url, {
|
|
248
|
-
method: "POST",
|
|
249
|
-
headers: {
|
|
250
|
-
"Content-Type": "application/json",
|
|
251
|
-
Authorization: `Bearer ${token}`,
|
|
252
|
-
},
|
|
253
|
-
body: JSON.stringify(firestoreData),
|
|
254
|
-
});
|
|
255
|
-
if (!response.ok) {
|
|
256
|
-
throw new Error(`Firestore API error: ${response.statusText}`);
|
|
257
|
-
}
|
|
258
|
-
const result = (await response.json());
|
|
259
|
-
return convertFromFirestoreDocument(result);
|
|
260
|
-
}
|
|
261
|
-
/**
|
|
262
|
-
* ドキュメントを取得
|
|
263
|
-
*/
|
|
264
|
-
async get(collectionName, documentId) {
|
|
265
|
-
const url = `${getFirestoreBasePath(collectionName)}/${documentId}`;
|
|
266
|
-
const token = await this.getToken();
|
|
267
|
-
const response = await fetch(url, {
|
|
268
|
-
method: "GET",
|
|
269
|
-
headers: {
|
|
270
|
-
Authorization: `Bearer ${token}`,
|
|
271
|
-
},
|
|
272
|
-
});
|
|
273
|
-
if (response.status === 404) {
|
|
274
|
-
return null;
|
|
275
|
-
}
|
|
276
|
-
if (!response.ok) {
|
|
277
|
-
throw new Error(`Firestore API error: ${response.statusText}`);
|
|
278
|
-
}
|
|
279
|
-
const result = (await response.json());
|
|
280
|
-
return convertFromFirestoreDocument(result);
|
|
281
|
-
}
|
|
282
|
-
/**
|
|
283
|
-
* ドキュメントを更新
|
|
284
|
-
*/
|
|
285
|
-
async update(collectionName, documentId, data) {
|
|
286
|
-
const url = `${getFirestoreBasePath(collectionName)}/${documentId}`;
|
|
287
|
-
const firestoreData = convertToFirestoreDocument(data);
|
|
288
|
-
const token = await this.getToken();
|
|
289
|
-
const response = await fetch(url, {
|
|
290
|
-
method: "PATCH",
|
|
291
|
-
headers: {
|
|
292
|
-
"Content-Type": "application/json",
|
|
293
|
-
Authorization: `Bearer ${token}`,
|
|
294
|
-
},
|
|
295
|
-
body: JSON.stringify(firestoreData),
|
|
296
|
-
});
|
|
297
|
-
if (!response.ok) {
|
|
298
|
-
throw new Error(`Firestore API error: ${response.statusText}`);
|
|
299
|
-
}
|
|
300
|
-
const result = (await response.json());
|
|
301
|
-
return convertFromFirestoreDocument(result);
|
|
302
|
-
}
|
|
303
|
-
/**
|
|
304
|
-
* ドキュメントを削除
|
|
305
|
-
*/
|
|
306
|
-
async delete(collectionName, documentId) {
|
|
307
|
-
const url = `${getFirestoreBasePath(collectionName)}/${documentId}`;
|
|
308
|
-
const token = await this.getToken();
|
|
309
|
-
const response = await fetch(url, {
|
|
310
|
-
method: "DELETE",
|
|
311
|
-
headers: {
|
|
312
|
-
Authorization: `Bearer ${token}`,
|
|
313
|
-
},
|
|
314
|
-
});
|
|
315
|
-
if (!response.ok) {
|
|
316
|
-
throw new Error(`Firestore API error: ${response.statusText}`);
|
|
317
|
-
}
|
|
318
|
-
return true;
|
|
319
|
-
}
|
|
320
|
-
/**
|
|
321
|
-
* コレクションのドキュメントを検索
|
|
322
|
-
*/
|
|
323
|
-
async query(collectionName, options = {}) {
|
|
324
|
-
const url = `${getFirestoreBasePath(collectionName)}:runQuery`;
|
|
325
|
-
// クエリ構築
|
|
326
|
-
const structuredQuery = {
|
|
327
|
-
from: [{ collectionId: collectionName }],
|
|
328
|
-
};
|
|
329
|
-
// フィルター条件
|
|
330
|
-
if (options.where && options.where.length > 0) {
|
|
331
|
-
structuredQuery.where = {
|
|
332
|
-
compositeFilter: {
|
|
333
|
-
op: "AND",
|
|
334
|
-
filters: options.where.map(condition => ({
|
|
335
|
-
fieldFilter: {
|
|
336
|
-
field: { fieldPath: condition.field },
|
|
337
|
-
op: condition.op,
|
|
338
|
-
value: convertToFirestoreValue(condition.value),
|
|
339
|
-
},
|
|
340
|
-
})),
|
|
341
|
-
},
|
|
342
|
-
};
|
|
343
|
-
}
|
|
344
|
-
// 並べ替え
|
|
345
|
-
if (options.orderBy) {
|
|
346
|
-
structuredQuery.orderBy = [
|
|
347
|
-
{
|
|
348
|
-
field: { fieldPath: options.orderBy },
|
|
349
|
-
direction: "ASCENDING",
|
|
350
|
-
},
|
|
351
|
-
];
|
|
352
|
-
}
|
|
353
|
-
// 制限
|
|
354
|
-
if (options.limit) {
|
|
355
|
-
structuredQuery.limit = options.limit;
|
|
356
|
-
}
|
|
357
|
-
// オフセット
|
|
358
|
-
if (options.offset) {
|
|
359
|
-
structuredQuery.offset = options.offset;
|
|
360
|
-
}
|
|
361
|
-
const token = await this.getToken();
|
|
362
|
-
const response = await fetch(url, {
|
|
363
|
-
method: "POST",
|
|
364
|
-
headers: {
|
|
365
|
-
"Content-Type": "application/json",
|
|
366
|
-
Authorization: `Bearer ${token}`,
|
|
367
|
-
},
|
|
368
|
-
body: JSON.stringify({
|
|
369
|
-
structuredQuery,
|
|
370
|
-
}),
|
|
371
|
-
});
|
|
372
|
-
if (!response.ok) {
|
|
373
|
-
throw new Error(`Firestore API error: ${response.statusText}`);
|
|
374
|
-
}
|
|
375
|
-
const results = (await response.json());
|
|
376
|
-
return results
|
|
377
|
-
.filter(item => item.document)
|
|
378
|
-
.map(item => convertFromFirestoreDocument(item.document));
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
exports.FirestoreClient = FirestoreClient;
|
|
382
|
-
// デフォルトのFirestoreクライアントインスタンス
|
|
383
|
-
exports.firestore = new FirestoreClient();
|
|
384
|
-
// 後方互換性のための関数
|
|
385
|
-
async function saveToFirestore(collectionName, data) {
|
|
386
|
-
const result = await exports.firestore.create(collectionName, data);
|
|
387
|
-
return { documentId: result.id, result };
|
|
388
|
-
}
|
package/dist/esm/index.d.ts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Firestoreの認証トークンを取得する関数
|
|
3
|
-
*/
|
|
4
|
-
export declare function getFirestoreToken(): Promise<string>;
|
|
5
|
-
/**
|
|
6
|
-
* Firestoreクライアントクラス
|
|
7
|
-
*/
|
|
8
|
-
export declare class FirestoreClient {
|
|
9
|
-
private token;
|
|
10
|
-
private tokenExpiry;
|
|
11
|
-
/**
|
|
12
|
-
* 認証トークンを取得(キャッシュあり)
|
|
13
|
-
*/
|
|
14
|
-
private getToken;
|
|
15
|
-
/**
|
|
16
|
-
* Firestoreにドキュメントを作成
|
|
17
|
-
*/
|
|
18
|
-
create(collectionName: string, data: Record<string, any>): Promise<Record<string, any> & {
|
|
19
|
-
id: string;
|
|
20
|
-
}>;
|
|
21
|
-
/**
|
|
22
|
-
* ドキュメントを取得
|
|
23
|
-
*/
|
|
24
|
-
get(collectionName: string, documentId: string): Promise<(Record<string, any> & {
|
|
25
|
-
id: string;
|
|
26
|
-
}) | null>;
|
|
27
|
-
/**
|
|
28
|
-
* ドキュメントを更新
|
|
29
|
-
*/
|
|
30
|
-
update(collectionName: string, documentId: string, data: Record<string, any>): Promise<Record<string, any> & {
|
|
31
|
-
id: string;
|
|
32
|
-
}>;
|
|
33
|
-
/**
|
|
34
|
-
* ドキュメントを削除
|
|
35
|
-
*/
|
|
36
|
-
delete(collectionName: string, documentId: string): Promise<boolean>;
|
|
37
|
-
/**
|
|
38
|
-
* コレクションのドキュメントを検索
|
|
39
|
-
*/
|
|
40
|
-
query(collectionName: string, options?: {
|
|
41
|
-
where?: Array<{
|
|
42
|
-
field: string;
|
|
43
|
-
op: string;
|
|
44
|
-
value: any;
|
|
45
|
-
}>;
|
|
46
|
-
orderBy?: string;
|
|
47
|
-
limit?: number;
|
|
48
|
-
offset?: number;
|
|
49
|
-
}): Promise<(Record<string, any> & {
|
|
50
|
-
id: string;
|
|
51
|
-
})[]>;
|
|
52
|
-
}
|
|
53
|
-
export declare const firestore: FirestoreClient;
|
|
54
|
-
export declare function saveToFirestore(collectionName: string, data: Record<string, any>): Promise<{
|
|
55
|
-
documentId: string;
|
|
56
|
-
result: Record<string, any> & {
|
|
57
|
-
id: string;
|
|
58
|
-
};
|
|
59
|
-
}>;
|
package/dist/esm/index.js
DELETED
|
@@ -1,349 +0,0 @@
|
|
|
1
|
-
import * as jose from "jose";
|
|
2
|
-
// Firestore関連の定数
|
|
3
|
-
const FIREBASE_PROJECT_ID = process.env.FIREBASE_PROJECT_ID;
|
|
4
|
-
const FIREBASE_PRIVATE_KEY_ID = process.env.FIREBASE_PRIVATE_KEY_ID;
|
|
5
|
-
const FIREBASE_PRIVATE_KEY = process.env.FIREBASE_PRIVATE_KEY?.replace(/\\n/g, "\n");
|
|
6
|
-
const FIREBASE_CLIENT_EMAIL = process.env.FIREBASE_CLIENT_EMAIL;
|
|
7
|
-
const FIREBASE_CLIENT_ID = process.env.FIREBASE_CLIENT_ID;
|
|
8
|
-
const FIREBASE_CLIENT_CERT_URL = process.env.FIREBASE_CLIENT_CERT_URL;
|
|
9
|
-
// サービスアカウント情報
|
|
10
|
-
const serviceAccount = {
|
|
11
|
-
type: "service_account",
|
|
12
|
-
project_id: FIREBASE_PROJECT_ID,
|
|
13
|
-
private_key_id: FIREBASE_PRIVATE_KEY_ID,
|
|
14
|
-
private_key: FIREBASE_PRIVATE_KEY,
|
|
15
|
-
client_email: FIREBASE_CLIENT_EMAIL,
|
|
16
|
-
client_id: FIREBASE_CLIENT_ID,
|
|
17
|
-
auth_uri: "https://accounts.google.com/o/oauth2/auth",
|
|
18
|
-
token_uri: "https://oauth2.googleapis.com/token",
|
|
19
|
-
auth_provider_x509_cert_url: "https://www.googleapis.com/oauth2/v1/certs",
|
|
20
|
-
client_x509_cert_url: FIREBASE_CLIENT_CERT_URL,
|
|
21
|
-
};
|
|
22
|
-
// Firestoreのベースパス
|
|
23
|
-
const getFirestoreBasePath = (collectionName) => {
|
|
24
|
-
const basePath = `https://firestore.googleapis.com/v1/projects/${FIREBASE_PROJECT_ID}/databases/(default)/documents`;
|
|
25
|
-
return collectionName ? `${basePath}/${collectionName}` : basePath;
|
|
26
|
-
};
|
|
27
|
-
/**
|
|
28
|
-
* JSの値をFirestore形式に変換する
|
|
29
|
-
*/
|
|
30
|
-
function convertToFirestoreValue(value) {
|
|
31
|
-
if (value instanceof Date) {
|
|
32
|
-
return { timestampValue: value.toISOString() };
|
|
33
|
-
}
|
|
34
|
-
else if (typeof value === "string") {
|
|
35
|
-
return { stringValue: value };
|
|
36
|
-
}
|
|
37
|
-
else if (typeof value === "number") {
|
|
38
|
-
return Number.isInteger(value)
|
|
39
|
-
? { integerValue: value }
|
|
40
|
-
: { doubleValue: value };
|
|
41
|
-
}
|
|
42
|
-
else if (typeof value === "boolean") {
|
|
43
|
-
return { booleanValue: value };
|
|
44
|
-
}
|
|
45
|
-
else if (value === null || value === undefined) {
|
|
46
|
-
return { nullValue: null };
|
|
47
|
-
}
|
|
48
|
-
else if (Array.isArray(value)) {
|
|
49
|
-
return {
|
|
50
|
-
arrayValue: {
|
|
51
|
-
values: value.map(item => convertToFirestoreValue(item)),
|
|
52
|
-
},
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
else if (typeof value === "object") {
|
|
56
|
-
const fields = Object.entries(value).reduce((acc, [key, val]) => ({
|
|
57
|
-
...acc,
|
|
58
|
-
[key]: convertToFirestoreValue(val),
|
|
59
|
-
}), {});
|
|
60
|
-
return { mapValue: { fields } };
|
|
61
|
-
}
|
|
62
|
-
// デフォルトは文字列化
|
|
63
|
-
return { stringValue: String(value) };
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Firestore形式からJSの値に変換する
|
|
67
|
-
*/
|
|
68
|
-
function convertFromFirestoreValue(firestoreValue) {
|
|
69
|
-
if ("stringValue" in firestoreValue) {
|
|
70
|
-
return firestoreValue.stringValue;
|
|
71
|
-
}
|
|
72
|
-
else if ("integerValue" in firestoreValue) {
|
|
73
|
-
return Number(firestoreValue.integerValue);
|
|
74
|
-
}
|
|
75
|
-
else if ("doubleValue" in firestoreValue) {
|
|
76
|
-
return firestoreValue.doubleValue;
|
|
77
|
-
}
|
|
78
|
-
else if ("booleanValue" in firestoreValue) {
|
|
79
|
-
return firestoreValue.booleanValue;
|
|
80
|
-
}
|
|
81
|
-
else if ("nullValue" in firestoreValue) {
|
|
82
|
-
return null;
|
|
83
|
-
}
|
|
84
|
-
else if ("timestampValue" in firestoreValue) {
|
|
85
|
-
return new Date(firestoreValue.timestampValue);
|
|
86
|
-
}
|
|
87
|
-
else if ("mapValue" in firestoreValue && firestoreValue.mapValue.fields) {
|
|
88
|
-
return Object.entries(firestoreValue.mapValue.fields).reduce((acc, [key, val]) => ({
|
|
89
|
-
...acc,
|
|
90
|
-
[key]: convertFromFirestoreValue(val),
|
|
91
|
-
}), {});
|
|
92
|
-
}
|
|
93
|
-
else if ("arrayValue" in firestoreValue &&
|
|
94
|
-
firestoreValue.arrayValue.values) {
|
|
95
|
-
return firestoreValue.arrayValue.values.map(convertFromFirestoreValue);
|
|
96
|
-
}
|
|
97
|
-
return null;
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* オブジェクトをFirestoreドキュメント形式に変換
|
|
101
|
-
*/
|
|
102
|
-
function convertToFirestoreDocument(data) {
|
|
103
|
-
return {
|
|
104
|
-
fields: Object.entries(data).reduce((acc, [key, value]) => ({
|
|
105
|
-
...acc,
|
|
106
|
-
[key]: convertToFirestoreValue(value),
|
|
107
|
-
}), {}),
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Firestoreドキュメントをオブジェクトに変換
|
|
112
|
-
*/
|
|
113
|
-
function convertFromFirestoreDocument(doc) {
|
|
114
|
-
if (!doc.fields)
|
|
115
|
-
return { id: getDocumentId(doc.name) };
|
|
116
|
-
const result = Object.entries(doc.fields).reduce((acc, [key, value]) => ({
|
|
117
|
-
...acc,
|
|
118
|
-
[key]: convertFromFirestoreValue(value),
|
|
119
|
-
}), {});
|
|
120
|
-
return {
|
|
121
|
-
...result,
|
|
122
|
-
id: getDocumentId(doc.name),
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* ドキュメントパスからIDを抽出
|
|
127
|
-
*/
|
|
128
|
-
function getDocumentId(path) {
|
|
129
|
-
if (!path)
|
|
130
|
-
return "";
|
|
131
|
-
const pathParts = path.split("/");
|
|
132
|
-
return pathParts[pathParts.length - 1];
|
|
133
|
-
}
|
|
134
|
-
// JWT(JSON Web Token)を作成する関数
|
|
135
|
-
async function createJWT(serviceAccount) {
|
|
136
|
-
const now = Math.floor(Date.now() / 1000);
|
|
137
|
-
const payload = {
|
|
138
|
-
iss: serviceAccount.client_email,
|
|
139
|
-
sub: serviceAccount.client_email,
|
|
140
|
-
aud: "https://oauth2.googleapis.com/token",
|
|
141
|
-
iat: now,
|
|
142
|
-
exp: now + 3600, // 1時間後に期限切れ
|
|
143
|
-
scope: "https://www.googleapis.com/auth/datastore",
|
|
144
|
-
};
|
|
145
|
-
try {
|
|
146
|
-
// 秘密鍵をインポート
|
|
147
|
-
const privateKey = await jose.importPKCS8(serviceAccount.private_key, "RS256");
|
|
148
|
-
// JWTを作成
|
|
149
|
-
const token = await new jose.SignJWT(payload)
|
|
150
|
-
.setProtectedHeader({
|
|
151
|
-
alg: "RS256",
|
|
152
|
-
kid: serviceAccount.private_key_id,
|
|
153
|
-
typ: "JWT",
|
|
154
|
-
})
|
|
155
|
-
.sign(privateKey);
|
|
156
|
-
return token;
|
|
157
|
-
}
|
|
158
|
-
catch (error) {
|
|
159
|
-
console.error("JWT作成エラー:", error);
|
|
160
|
-
throw error;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* Firestoreの認証トークンを取得する関数
|
|
165
|
-
*/
|
|
166
|
-
export async function getFirestoreToken() {
|
|
167
|
-
// トークンを取得するためのリクエスト
|
|
168
|
-
const response = await fetch("https://oauth2.googleapis.com/token", {
|
|
169
|
-
method: "POST",
|
|
170
|
-
headers: {
|
|
171
|
-
"Content-Type": "application/json",
|
|
172
|
-
},
|
|
173
|
-
body: JSON.stringify({
|
|
174
|
-
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
|
|
175
|
-
assertion: await createJWT(serviceAccount),
|
|
176
|
-
}),
|
|
177
|
-
});
|
|
178
|
-
const data = (await response.json());
|
|
179
|
-
return data.access_token;
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* Firestoreクライアントクラス
|
|
183
|
-
*/
|
|
184
|
-
export class FirestoreClient {
|
|
185
|
-
constructor() {
|
|
186
|
-
this.token = null;
|
|
187
|
-
this.tokenExpiry = 0;
|
|
188
|
-
}
|
|
189
|
-
/**
|
|
190
|
-
* 認証トークンを取得(キャッシュあり)
|
|
191
|
-
*/
|
|
192
|
-
async getToken() {
|
|
193
|
-
const now = Date.now();
|
|
194
|
-
// トークンが期限切れか未取得の場合は新しく取得
|
|
195
|
-
if (!this.token || now >= this.tokenExpiry) {
|
|
196
|
-
this.token = await getFirestoreToken();
|
|
197
|
-
// 50分後に期限切れとする(実際は1時間)
|
|
198
|
-
this.tokenExpiry = now + 50 * 60 * 1000;
|
|
199
|
-
}
|
|
200
|
-
return this.token;
|
|
201
|
-
}
|
|
202
|
-
/**
|
|
203
|
-
* Firestoreにドキュメントを作成
|
|
204
|
-
*/
|
|
205
|
-
async create(collectionName, data) {
|
|
206
|
-
const url = getFirestoreBasePath(collectionName);
|
|
207
|
-
const firestoreData = convertToFirestoreDocument(data);
|
|
208
|
-
const token = await this.getToken();
|
|
209
|
-
const response = await fetch(url, {
|
|
210
|
-
method: "POST",
|
|
211
|
-
headers: {
|
|
212
|
-
"Content-Type": "application/json",
|
|
213
|
-
Authorization: `Bearer ${token}`,
|
|
214
|
-
},
|
|
215
|
-
body: JSON.stringify(firestoreData),
|
|
216
|
-
});
|
|
217
|
-
if (!response.ok) {
|
|
218
|
-
throw new Error(`Firestore API error: ${response.statusText}`);
|
|
219
|
-
}
|
|
220
|
-
const result = (await response.json());
|
|
221
|
-
return convertFromFirestoreDocument(result);
|
|
222
|
-
}
|
|
223
|
-
/**
|
|
224
|
-
* ドキュメントを取得
|
|
225
|
-
*/
|
|
226
|
-
async get(collectionName, documentId) {
|
|
227
|
-
const url = `${getFirestoreBasePath(collectionName)}/${documentId}`;
|
|
228
|
-
const token = await this.getToken();
|
|
229
|
-
const response = await fetch(url, {
|
|
230
|
-
method: "GET",
|
|
231
|
-
headers: {
|
|
232
|
-
Authorization: `Bearer ${token}`,
|
|
233
|
-
},
|
|
234
|
-
});
|
|
235
|
-
if (response.status === 404) {
|
|
236
|
-
return null;
|
|
237
|
-
}
|
|
238
|
-
if (!response.ok) {
|
|
239
|
-
throw new Error(`Firestore API error: ${response.statusText}`);
|
|
240
|
-
}
|
|
241
|
-
const result = (await response.json());
|
|
242
|
-
return convertFromFirestoreDocument(result);
|
|
243
|
-
}
|
|
244
|
-
/**
|
|
245
|
-
* ドキュメントを更新
|
|
246
|
-
*/
|
|
247
|
-
async update(collectionName, documentId, data) {
|
|
248
|
-
const url = `${getFirestoreBasePath(collectionName)}/${documentId}`;
|
|
249
|
-
const firestoreData = convertToFirestoreDocument(data);
|
|
250
|
-
const token = await this.getToken();
|
|
251
|
-
const response = await fetch(url, {
|
|
252
|
-
method: "PATCH",
|
|
253
|
-
headers: {
|
|
254
|
-
"Content-Type": "application/json",
|
|
255
|
-
Authorization: `Bearer ${token}`,
|
|
256
|
-
},
|
|
257
|
-
body: JSON.stringify(firestoreData),
|
|
258
|
-
});
|
|
259
|
-
if (!response.ok) {
|
|
260
|
-
throw new Error(`Firestore API error: ${response.statusText}`);
|
|
261
|
-
}
|
|
262
|
-
const result = (await response.json());
|
|
263
|
-
return convertFromFirestoreDocument(result);
|
|
264
|
-
}
|
|
265
|
-
/**
|
|
266
|
-
* ドキュメントを削除
|
|
267
|
-
*/
|
|
268
|
-
async delete(collectionName, documentId) {
|
|
269
|
-
const url = `${getFirestoreBasePath(collectionName)}/${documentId}`;
|
|
270
|
-
const token = await this.getToken();
|
|
271
|
-
const response = await fetch(url, {
|
|
272
|
-
method: "DELETE",
|
|
273
|
-
headers: {
|
|
274
|
-
Authorization: `Bearer ${token}`,
|
|
275
|
-
},
|
|
276
|
-
});
|
|
277
|
-
if (!response.ok) {
|
|
278
|
-
throw new Error(`Firestore API error: ${response.statusText}`);
|
|
279
|
-
}
|
|
280
|
-
return true;
|
|
281
|
-
}
|
|
282
|
-
/**
|
|
283
|
-
* コレクションのドキュメントを検索
|
|
284
|
-
*/
|
|
285
|
-
async query(collectionName, options = {}) {
|
|
286
|
-
const url = `${getFirestoreBasePath(collectionName)}:runQuery`;
|
|
287
|
-
// クエリ構築
|
|
288
|
-
const structuredQuery = {
|
|
289
|
-
from: [{ collectionId: collectionName }],
|
|
290
|
-
};
|
|
291
|
-
// フィルター条件
|
|
292
|
-
if (options.where && options.where.length > 0) {
|
|
293
|
-
structuredQuery.where = {
|
|
294
|
-
compositeFilter: {
|
|
295
|
-
op: "AND",
|
|
296
|
-
filters: options.where.map(condition => ({
|
|
297
|
-
fieldFilter: {
|
|
298
|
-
field: { fieldPath: condition.field },
|
|
299
|
-
op: condition.op,
|
|
300
|
-
value: convertToFirestoreValue(condition.value),
|
|
301
|
-
},
|
|
302
|
-
})),
|
|
303
|
-
},
|
|
304
|
-
};
|
|
305
|
-
}
|
|
306
|
-
// 並べ替え
|
|
307
|
-
if (options.orderBy) {
|
|
308
|
-
structuredQuery.orderBy = [
|
|
309
|
-
{
|
|
310
|
-
field: { fieldPath: options.orderBy },
|
|
311
|
-
direction: "ASCENDING",
|
|
312
|
-
},
|
|
313
|
-
];
|
|
314
|
-
}
|
|
315
|
-
// 制限
|
|
316
|
-
if (options.limit) {
|
|
317
|
-
structuredQuery.limit = options.limit;
|
|
318
|
-
}
|
|
319
|
-
// オフセット
|
|
320
|
-
if (options.offset) {
|
|
321
|
-
structuredQuery.offset = options.offset;
|
|
322
|
-
}
|
|
323
|
-
const token = await this.getToken();
|
|
324
|
-
const response = await fetch(url, {
|
|
325
|
-
method: "POST",
|
|
326
|
-
headers: {
|
|
327
|
-
"Content-Type": "application/json",
|
|
328
|
-
Authorization: `Bearer ${token}`,
|
|
329
|
-
},
|
|
330
|
-
body: JSON.stringify({
|
|
331
|
-
structuredQuery,
|
|
332
|
-
}),
|
|
333
|
-
});
|
|
334
|
-
if (!response.ok) {
|
|
335
|
-
throw new Error(`Firestore API error: ${response.statusText}`);
|
|
336
|
-
}
|
|
337
|
-
const results = (await response.json());
|
|
338
|
-
return results
|
|
339
|
-
.filter(item => item.document)
|
|
340
|
-
.map(item => convertFromFirestoreDocument(item.document));
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
// デフォルトのFirestoreクライアントインスタンス
|
|
344
|
-
export const firestore = new FirestoreClient();
|
|
345
|
-
// 後方互換性のための関数
|
|
346
|
-
export async function saveToFirestore(collectionName, data) {
|
|
347
|
-
const result = await firestore.create(collectionName, data);
|
|
348
|
-
return { documentId: result.id, result };
|
|
349
|
-
}
|