firebase-mcp 0.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/README.md +119 -0
- package/dist/access/index.d.ts +23 -0
- package/dist/access/index.d.ts.map +1 -0
- package/dist/access/index.js +35 -0
- package/dist/access/index.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +14 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/config/index.d.ts +51 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +56 -0
- package/dist/config/index.js.map +1 -0
- package/dist/firebase/index.d.ts +21 -0
- package/dist/firebase/index.d.ts.map +1 -0
- package/dist/firebase/index.js +42 -0
- package/dist/firebase/index.js.map +1 -0
- package/dist/server/index.d.ts +23 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +60 -0
- package/dist/server/index.js.map +1 -0
- package/dist/tools/firestore/aggregate_collection.d.ts +34 -0
- package/dist/tools/firestore/aggregate_collection.d.ts.map +1 -0
- package/dist/tools/firestore/aggregate_collection.js +86 -0
- package/dist/tools/firestore/aggregate_collection.js.map +1 -0
- package/dist/tools/firestore/count_documents.d.ts +25 -0
- package/dist/tools/firestore/count_documents.d.ts.map +1 -0
- package/dist/tools/firestore/count_documents.js +54 -0
- package/dist/tools/firestore/count_documents.js.map +1 -0
- package/dist/tools/firestore/get_collection_schema.d.ts +30 -0
- package/dist/tools/firestore/get_collection_schema.d.ts.map +1 -0
- package/dist/tools/firestore/get_collection_schema.js +129 -0
- package/dist/tools/firestore/get_collection_schema.js.map +1 -0
- package/dist/tools/firestore/get_document.d.ts +32 -0
- package/dist/tools/firestore/get_document.d.ts.map +1 -0
- package/dist/tools/firestore/get_document.js +62 -0
- package/dist/tools/firestore/get_document.js.map +1 -0
- package/dist/tools/firestore/get_many_documents.d.ts +33 -0
- package/dist/tools/firestore/get_many_documents.d.ts.map +1 -0
- package/dist/tools/firestore/get_many_documents.js +86 -0
- package/dist/tools/firestore/get_many_documents.js.map +1 -0
- package/dist/tools/firestore/index.d.ts +12 -0
- package/dist/tools/firestore/index.d.ts.map +1 -0
- package/dist/tools/firestore/index.js +28 -0
- package/dist/tools/firestore/index.js.map +1 -0
- package/dist/tools/firestore/list_collections.d.ts +24 -0
- package/dist/tools/firestore/list_collections.d.ts.map +1 -0
- package/dist/tools/firestore/list_collections.js +61 -0
- package/dist/tools/firestore/list_collections.js.map +1 -0
- package/dist/tools/firestore/list_documents.d.ts +24 -0
- package/dist/tools/firestore/list_documents.d.ts.map +1 -0
- package/dist/tools/firestore/list_documents.js +60 -0
- package/dist/tools/firestore/list_documents.js.map +1 -0
- package/dist/tools/firestore/list_indexes.d.ts +32 -0
- package/dist/tools/firestore/list_indexes.d.ts.map +1 -0
- package/dist/tools/firestore/list_indexes.js +99 -0
- package/dist/tools/firestore/list_indexes.js.map +1 -0
- package/dist/tools/firestore/normalize.d.ts +8 -0
- package/dist/tools/firestore/normalize.d.ts.map +1 -0
- package/dist/tools/firestore/normalize.js +36 -0
- package/dist/tools/firestore/normalize.js.map +1 -0
- package/dist/tools/firestore/query_collection.d.ts +34 -0
- package/dist/tools/firestore/query_collection.d.ts.map +1 -0
- package/dist/tools/firestore/query_collection.js +96 -0
- package/dist/tools/firestore/query_collection.js.map +1 -0
- package/dist/tools/firestore/query_collection_group.d.ts +34 -0
- package/dist/tools/firestore/query_collection_group.d.ts.map +1 -0
- package/dist/tools/firestore/query_collection_group.js +94 -0
- package/dist/tools/firestore/query_collection_group.js.map +1 -0
- package/dist/tools/firestore/read_collections.d.ts +44 -0
- package/dist/tools/firestore/read_collections.d.ts.map +1 -0
- package/dist/tools/firestore/read_collections.js +95 -0
- package/dist/tools/firestore/read_collections.js.map +1 -0
- package/dist/tools/firestore/types.d.ts +52 -0
- package/dist/tools/firestore/types.d.ts.map +1 -0
- package/dist/tools/firestore/types.js +75 -0
- package/dist/tools/firestore/types.js.map +1 -0
- package/dist/tools/index.d.ts +104 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +121 -0
- package/dist/tools/index.js.map +1 -0
- package/package.json +48 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
import { Effect } from 'effect';
|
|
3
|
+
import { AccessService } from '../../access';
|
|
4
|
+
import { FirebaseService } from '../../firebase';
|
|
5
|
+
import { QueryFilter } from './types';
|
|
6
|
+
declare const FirestoreCountError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
7
|
+
readonly _tag: "FirestoreCountError";
|
|
8
|
+
} & Readonly<A>;
|
|
9
|
+
export declare class FirestoreCountError extends FirestoreCountError_base<{
|
|
10
|
+
readonly message: string;
|
|
11
|
+
readonly cause?: unknown;
|
|
12
|
+
}> {
|
|
13
|
+
}
|
|
14
|
+
export declare const COUNT_DOCUMENTS: "count_documents";
|
|
15
|
+
export interface CountDocumentsArgs {
|
|
16
|
+
collection: string;
|
|
17
|
+
filters?: QueryFilter[];
|
|
18
|
+
}
|
|
19
|
+
export declare const countDocumentsDefinition: Tool;
|
|
20
|
+
export declare const countDocuments: (input: CountDocumentsArgs) => Effect.Effect<{
|
|
21
|
+
collection: string;
|
|
22
|
+
count: number;
|
|
23
|
+
}, import("../../access").AccessDeniedError | FirestoreCountError, AccessService | FirebaseService>;
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=count_documents.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"count_documents.d.ts","sourceRoot":"","sources":["../../../src/tools/firestore/count_documents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAC1D,OAAO,EAAQ,MAAM,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAsB,WAAW,EAAE,MAAM,SAAS,CAAC;;;;AAE1D,qBAAa,mBAAoB,SAAQ,yBAEvC;IACA,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CAC1B,CAAC;CAAG;AAEL,eAAO,MAAM,eAAe,EAAG,iBAA0B,CAAC;AAE1D,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;CACzB;AAED,eAAO,MAAM,wBAAwB,EAAE,IAmBtC,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,OAAO,kBAAkB;;;mGA8BpD,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.countDocuments = exports.countDocumentsDefinition = exports.COUNT_DOCUMENTS = exports.FirestoreCountError = void 0;
|
|
4
|
+
const effect_1 = require("effect");
|
|
5
|
+
const access_1 = require("../../access");
|
|
6
|
+
const firebase_1 = require("../../firebase");
|
|
7
|
+
const types_1 = require("./types");
|
|
8
|
+
class FirestoreCountError extends effect_1.Data.TaggedError('FirestoreCountError') {
|
|
9
|
+
}
|
|
10
|
+
exports.FirestoreCountError = FirestoreCountError;
|
|
11
|
+
exports.COUNT_DOCUMENTS = 'count_documents';
|
|
12
|
+
exports.countDocumentsDefinition = {
|
|
13
|
+
name: exports.COUNT_DOCUMENTS,
|
|
14
|
+
description: 'Count documents in a Firestore collection, with optional filters. Uses native server-side count — does not fetch documents.',
|
|
15
|
+
inputSchema: {
|
|
16
|
+
type: 'object',
|
|
17
|
+
properties: {
|
|
18
|
+
collection: {
|
|
19
|
+
type: 'string',
|
|
20
|
+
description: "Collection path, e.g. 'users' or 'users/123/posts'",
|
|
21
|
+
},
|
|
22
|
+
filters: {
|
|
23
|
+
type: 'array',
|
|
24
|
+
description: 'Optional where-clause filters to narrow the count',
|
|
25
|
+
items: types_1.FILTER_SCHEMA_ITEM,
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
required: ['collection'],
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
const countDocuments = (input) => effect_1.Effect.gen(function* () {
|
|
32
|
+
const access = yield* access_1.AccessService;
|
|
33
|
+
yield* access.check(input.collection);
|
|
34
|
+
const { firestore } = yield* firebase_1.FirebaseService;
|
|
35
|
+
const count = yield* effect_1.Effect.tryPromise({
|
|
36
|
+
try: () => {
|
|
37
|
+
let query = firestore().collection(input.collection);
|
|
38
|
+
for (const filter of input.filters ?? []) {
|
|
39
|
+
query = query.where(filter.field, filter.operator, filter.value);
|
|
40
|
+
}
|
|
41
|
+
return query
|
|
42
|
+
.count()
|
|
43
|
+
.get()
|
|
44
|
+
.then((snap) => snap.data().count);
|
|
45
|
+
},
|
|
46
|
+
catch: (cause) => new FirestoreCountError({
|
|
47
|
+
message: `Failed to count documents in: ${input.collection}`,
|
|
48
|
+
cause,
|
|
49
|
+
}),
|
|
50
|
+
});
|
|
51
|
+
return { collection: input.collection, count };
|
|
52
|
+
});
|
|
53
|
+
exports.countDocuments = countDocuments;
|
|
54
|
+
//# sourceMappingURL=count_documents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"count_documents.js","sourceRoot":"","sources":["../../../src/tools/firestore/count_documents.ts"],"names":[],"mappings":";;;AACA,mCAAsC;AACtC,yCAA6C;AAC7C,6CAAiD;AACjD,mCAA0D;AAE1D,MAAa,mBAAoB,SAAQ,aAAI,CAAC,WAAW,CACvD,qBAAqB,CAIrB;CAAG;AALL,kDAKK;AAEQ,QAAA,eAAe,GAAG,iBAA0B,CAAC;AAO7C,QAAA,wBAAwB,GAAS;IAC5C,IAAI,EAAE,uBAAe;IACrB,WAAW,EACT,6HAA6H;IAC/H,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,UAAU,EAAE;gBACV,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,oDAAoD;aAClE;YACD,OAAO,EAAE;gBACP,IAAI,EAAE,OAAO;gBACb,WAAW,EAAE,mDAAmD;gBAChE,KAAK,EAAE,0BAAkB;aAC1B;SACF;QACD,QAAQ,EAAE,CAAC,YAAY,CAAC;KACzB;CACF,CAAC;AAEK,MAAM,cAAc,GAAG,CAAC,KAAyB,EAAE,EAAE,CAC1D,eAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,sBAAa,CAAC;IACpC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAEtC,MAAM,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC,CAAC,0BAAe,CAAC;IAE7C,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,eAAM,CAAC,UAAU,CAAC;QACrC,GAAG,EAAE,GAAG,EAAE;YACR,IAAI,KAAK,GAA4B,SAAS,EAAE,CAAC,UAAU,CACzD,KAAK,CAAC,UAAU,CACjB,CAAC;YAEF,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;gBACzC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;YACnE,CAAC;YAED,OAAO,KAAK;iBACT,KAAK,EAAE;iBACP,GAAG,EAAE;iBACL,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC;QACvC,CAAC;QACD,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CACf,IAAI,mBAAmB,CAAC;YACtB,OAAO,EAAE,iCAAiC,KAAK,CAAC,UAAU,EAAE;YAC5D,KAAK;SACN,CAAC;KACL,CAAC,CAAC;IAEH,OAAO,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,KAAK,EAAE,CAAC;AACjD,CAAC,CAAC,CAAC;AA9BQ,QAAA,cAAc,kBA8BtB"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
import { Effect } from 'effect';
|
|
3
|
+
import { AccessService } from '../../access';
|
|
4
|
+
import { FirebaseService } from '../../firebase';
|
|
5
|
+
declare const FirestoreSchemaError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
6
|
+
readonly _tag: "FirestoreSchemaError";
|
|
7
|
+
} & Readonly<A>;
|
|
8
|
+
export declare class FirestoreSchemaError extends FirestoreSchemaError_base<{
|
|
9
|
+
readonly message: string;
|
|
10
|
+
readonly cause?: unknown;
|
|
11
|
+
}> {
|
|
12
|
+
}
|
|
13
|
+
export declare const GET_COLLECTION_SCHEMA: "get_collection_schema";
|
|
14
|
+
export interface GetCollectionSchemaArgs {
|
|
15
|
+
collection: string;
|
|
16
|
+
sampleSize?: number;
|
|
17
|
+
}
|
|
18
|
+
interface FieldSchema {
|
|
19
|
+
types: string[];
|
|
20
|
+
coverage: string;
|
|
21
|
+
}
|
|
22
|
+
export declare const getCollectionSchemaDefinition: Tool;
|
|
23
|
+
export declare const getCollectionSchema: (input: GetCollectionSchemaArgs) => Effect.Effect<{
|
|
24
|
+
collection: string;
|
|
25
|
+
totalSampled: number;
|
|
26
|
+
sampleStrategy: string;
|
|
27
|
+
fields: Record<string, FieldSchema>;
|
|
28
|
+
}, import("../../access").AccessDeniedError | FirestoreSchemaError, AccessService | FirebaseService>;
|
|
29
|
+
export {};
|
|
30
|
+
//# sourceMappingURL=get_collection_schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get_collection_schema.d.ts","sourceRoot":"","sources":["../../../src/tools/firestore/get_collection_schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAC1D,OAAO,EAAQ,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGtC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;;;;AAEjD,qBAAa,oBAAqB,SAAQ,0BAExC;IACA,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CAC1B,CAAC;CAAG;AAEL,eAAO,MAAM,qBAAqB,EAAG,uBAAgC,CAAC;AAEtE,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,UAAU,WAAW;IACnB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAqBD,eAAO,MAAM,6BAA6B,EAAE,IAoB3C,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,OAAO,uBAAuB;;;;;oGAiF9D,CAAC"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getCollectionSchema = exports.getCollectionSchemaDefinition = exports.GET_COLLECTION_SCHEMA = exports.FirestoreSchemaError = void 0;
|
|
7
|
+
const effect_1 = require("effect");
|
|
8
|
+
const firebase_admin_1 = __importDefault(require("firebase-admin"));
|
|
9
|
+
const access_1 = require("../../access");
|
|
10
|
+
const firebase_1 = require("../../firebase");
|
|
11
|
+
class FirestoreSchemaError extends effect_1.Data.TaggedError('FirestoreSchemaError') {
|
|
12
|
+
}
|
|
13
|
+
exports.FirestoreSchemaError = FirestoreSchemaError;
|
|
14
|
+
exports.GET_COLLECTION_SCHEMA = 'get_collection_schema';
|
|
15
|
+
const inferType = (value) => {
|
|
16
|
+
if (value === null || value === undefined)
|
|
17
|
+
return 'null';
|
|
18
|
+
if (typeof value === 'boolean')
|
|
19
|
+
return 'boolean';
|
|
20
|
+
if (typeof value === 'string')
|
|
21
|
+
return 'string';
|
|
22
|
+
if (typeof value === 'number') {
|
|
23
|
+
return Number.isInteger(value) ? 'integer' : 'float';
|
|
24
|
+
}
|
|
25
|
+
if (value instanceof firebase_admin_1.default.firestore.Timestamp)
|
|
26
|
+
return 'timestamp';
|
|
27
|
+
if (value instanceof firebase_admin_1.default.firestore.GeoPoint)
|
|
28
|
+
return 'geopoint';
|
|
29
|
+
if (value instanceof firebase_admin_1.default.firestore.DocumentReference)
|
|
30
|
+
return 'reference';
|
|
31
|
+
if (Array.isArray(value)) {
|
|
32
|
+
if (value.length === 0)
|
|
33
|
+
return 'array<unknown>';
|
|
34
|
+
const itemTypes = [...new Set(value.map(inferType))];
|
|
35
|
+
return `array<${itemTypes.join(' | ')}>`;
|
|
36
|
+
}
|
|
37
|
+
if (typeof value === 'object')
|
|
38
|
+
return 'map';
|
|
39
|
+
return 'unknown';
|
|
40
|
+
};
|
|
41
|
+
exports.getCollectionSchemaDefinition = {
|
|
42
|
+
name: exports.GET_COLLECTION_SCHEMA,
|
|
43
|
+
description: 'Infer the schema of a Firestore collection by sampling documents. Returns field names, inferred types (integer, float, string, boolean, timestamp, geopoint, reference, array, map), and coverage (how many sampled docs contained each field). Coverage of 10/10 does not guarantee a field is always present — documents may have different fields depending on their state or lifecycle stage.',
|
|
44
|
+
inputSchema: {
|
|
45
|
+
type: 'object',
|
|
46
|
+
properties: {
|
|
47
|
+
collection: {
|
|
48
|
+
type: 'string',
|
|
49
|
+
description: "Collection path, e.g. 'users' or 'shared/stores_data/ABC/data/stock'",
|
|
50
|
+
},
|
|
51
|
+
sampleSize: {
|
|
52
|
+
type: 'number',
|
|
53
|
+
description: 'Total number of documents to sample (default: 20). Split evenly between the start and end of the collection for varied coverage.',
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
required: ['collection'],
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
const getCollectionSchema = (input) => effect_1.Effect.gen(function* () {
|
|
60
|
+
const access = yield* access_1.AccessService;
|
|
61
|
+
yield* access.check(input.collection);
|
|
62
|
+
const { firestore } = yield* firebase_1.FirebaseService;
|
|
63
|
+
const total = input.sampleSize ?? 20;
|
|
64
|
+
const half = Math.ceil(total / 2);
|
|
65
|
+
const fromStart = yield* effect_1.Effect.tryPromise({
|
|
66
|
+
try: () => firestore().collection(input.collection).limit(half).get(),
|
|
67
|
+
catch: (cause) => new FirestoreSchemaError({
|
|
68
|
+
message: `Failed to sample collection: ${input.collection}`,
|
|
69
|
+
cause,
|
|
70
|
+
}),
|
|
71
|
+
});
|
|
72
|
+
// Attempt to sample from the end for better coverage.
|
|
73
|
+
// Falls back gracefully if a composite index is not available.
|
|
74
|
+
const fromEnd = yield* effect_1.Effect.tryPromise({
|
|
75
|
+
try: () => firestore()
|
|
76
|
+
.collection(input.collection)
|
|
77
|
+
.orderBy(firebase_admin_1.default.firestore.FieldPath.documentId(), 'desc')
|
|
78
|
+
.limit(total - half)
|
|
79
|
+
.get()
|
|
80
|
+
.catch(() => null),
|
|
81
|
+
catch: () => new FirestoreSchemaError({ message: 'fallback' }),
|
|
82
|
+
});
|
|
83
|
+
// Deduplicate by document ID
|
|
84
|
+
const seen = new Set();
|
|
85
|
+
const docs = [];
|
|
86
|
+
const snaps = fromEnd ? [fromStart, fromEnd] : [fromStart];
|
|
87
|
+
for (const snap of snaps) {
|
|
88
|
+
for (const doc of snap.docs) {
|
|
89
|
+
if (!seen.has(doc.id)) {
|
|
90
|
+
seen.add(doc.id);
|
|
91
|
+
const data = doc.data();
|
|
92
|
+
if (data)
|
|
93
|
+
docs.push(data);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const sampleStrategy = fromEnd
|
|
98
|
+
? `${half} from start + ${total - half} from end (deduplicated)`
|
|
99
|
+
: `${half} from start only (descending index unavailable)`;
|
|
100
|
+
const totalSampled = docs.length;
|
|
101
|
+
// Build schema: track types seen and presence count per field
|
|
102
|
+
const fieldTypes = new Map();
|
|
103
|
+
const fieldCount = new Map();
|
|
104
|
+
for (const doc of docs) {
|
|
105
|
+
for (const [key, value] of Object.entries(doc)) {
|
|
106
|
+
const type = inferType(value);
|
|
107
|
+
if (!fieldTypes.has(key))
|
|
108
|
+
fieldTypes.set(key, new Set());
|
|
109
|
+
fieldTypes.get(key).add(type);
|
|
110
|
+
fieldCount.set(key, (fieldCount.get(key) ?? 0) + 1);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const fields = {};
|
|
114
|
+
for (const [field, types] of fieldTypes.entries()) {
|
|
115
|
+
const count = fieldCount.get(field) ?? 0;
|
|
116
|
+
fields[field] = {
|
|
117
|
+
types: [...types],
|
|
118
|
+
coverage: `${count}/${totalSampled} sampled`,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
collection: input.collection,
|
|
123
|
+
totalSampled,
|
|
124
|
+
sampleStrategy,
|
|
125
|
+
fields,
|
|
126
|
+
};
|
|
127
|
+
});
|
|
128
|
+
exports.getCollectionSchema = getCollectionSchema;
|
|
129
|
+
//# sourceMappingURL=get_collection_schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get_collection_schema.js","sourceRoot":"","sources":["../../../src/tools/firestore/get_collection_schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
import { Effect } from 'effect';
|
|
3
|
+
import { AccessService } from '../../access';
|
|
4
|
+
import { FirebaseService } from '../../firebase';
|
|
5
|
+
declare const FirestoreGetError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
6
|
+
readonly _tag: "FirestoreGetError";
|
|
7
|
+
} & Readonly<A>;
|
|
8
|
+
export declare class FirestoreGetError extends FirestoreGetError_base<{
|
|
9
|
+
readonly message: string;
|
|
10
|
+
readonly cause?: unknown;
|
|
11
|
+
}> {
|
|
12
|
+
}
|
|
13
|
+
declare const DocumentNotFoundError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
14
|
+
readonly _tag: "DocumentNotFoundError";
|
|
15
|
+
} & Readonly<A>;
|
|
16
|
+
export declare class DocumentNotFoundError extends DocumentNotFoundError_base<{
|
|
17
|
+
readonly path: string;
|
|
18
|
+
}> {
|
|
19
|
+
}
|
|
20
|
+
export declare const GET_DOCUMENT: "get_document";
|
|
21
|
+
export interface GetDocumentArgs {
|
|
22
|
+
path: string;
|
|
23
|
+
select?: string[];
|
|
24
|
+
}
|
|
25
|
+
export declare const getDocumentDefinition: Tool;
|
|
26
|
+
export declare const getDocument: (input: GetDocumentArgs) => Effect.Effect<{
|
|
27
|
+
id: string;
|
|
28
|
+
path: string;
|
|
29
|
+
data: unknown;
|
|
30
|
+
}, import("../../access").AccessDeniedError | FirestoreGetError | DocumentNotFoundError, AccessService | FirebaseService>;
|
|
31
|
+
export {};
|
|
32
|
+
//# sourceMappingURL=get_document.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get_document.d.ts","sourceRoot":"","sources":["../../../src/tools/firestore/get_document.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAC1D,OAAO,EAAQ,MAAM,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;;;;AAGjD,qBAAa,iBAAkB,SAAQ,uBAAsC;IAC3E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CAC1B,CAAC;CAAG;;;;AAEL,qBAAa,qBAAsB,SAAQ,2BAEzC;IACA,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,CAAC;CAAG;AAEL,eAAO,MAAM,YAAY,EAAG,cAAuB,CAAC;AAEpD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,eAAO,MAAM,qBAAqB,EAAE,IAmBnC,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,OAAO,eAAe;;;;yHAqC9C,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getDocument = exports.getDocumentDefinition = exports.GET_DOCUMENT = exports.DocumentNotFoundError = exports.FirestoreGetError = void 0;
|
|
4
|
+
const effect_1 = require("effect");
|
|
5
|
+
const access_1 = require("../../access");
|
|
6
|
+
const firebase_1 = require("../../firebase");
|
|
7
|
+
const types_1 = require("./types");
|
|
8
|
+
class FirestoreGetError extends effect_1.Data.TaggedError('FirestoreGetError') {
|
|
9
|
+
}
|
|
10
|
+
exports.FirestoreGetError = FirestoreGetError;
|
|
11
|
+
class DocumentNotFoundError extends effect_1.Data.TaggedError('DocumentNotFoundError') {
|
|
12
|
+
}
|
|
13
|
+
exports.DocumentNotFoundError = DocumentNotFoundError;
|
|
14
|
+
exports.GET_DOCUMENT = 'get_document';
|
|
15
|
+
exports.getDocumentDefinition = {
|
|
16
|
+
name: exports.GET_DOCUMENT,
|
|
17
|
+
description: 'Get a single Firestore document by path',
|
|
18
|
+
inputSchema: {
|
|
19
|
+
type: 'object',
|
|
20
|
+
properties: {
|
|
21
|
+
path: {
|
|
22
|
+
type: 'string',
|
|
23
|
+
description: "Full document path, e.g. 'users/123' ",
|
|
24
|
+
},
|
|
25
|
+
select: {
|
|
26
|
+
type: 'array',
|
|
27
|
+
items: { type: 'string' },
|
|
28
|
+
description: 'Optional list of field paths to return. Omit to return all fields.',
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
required: ['path'],
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
const getDocument = (input) => effect_1.Effect.gen(function* () {
|
|
35
|
+
const access = yield* access_1.AccessService;
|
|
36
|
+
yield* access.check(input.path);
|
|
37
|
+
const { firestore } = yield* firebase_1.FirebaseService;
|
|
38
|
+
const docRef = yield* effect_1.Effect.try({
|
|
39
|
+
try: () => firestore().doc(input.path),
|
|
40
|
+
catch: (cause) => new FirestoreGetError({
|
|
41
|
+
message: `Invalid document path: ${input.path}`,
|
|
42
|
+
cause,
|
|
43
|
+
}),
|
|
44
|
+
});
|
|
45
|
+
const snap = yield* effect_1.Effect.tryPromise({
|
|
46
|
+
try: () => input.select?.length
|
|
47
|
+
? firestore()
|
|
48
|
+
.getAll(docRef, { fieldMask: input.select })
|
|
49
|
+
.then((snaps) => snaps[0])
|
|
50
|
+
: docRef.get(),
|
|
51
|
+
catch: (cause) => new FirestoreGetError({
|
|
52
|
+
message: `Failed to get document: ${input.path}`,
|
|
53
|
+
cause,
|
|
54
|
+
}),
|
|
55
|
+
});
|
|
56
|
+
if (!snap.exists) {
|
|
57
|
+
return yield* effect_1.Effect.fail(new DocumentNotFoundError({ path: input.path }));
|
|
58
|
+
}
|
|
59
|
+
return (0, types_1.normalizeDocument)(snap);
|
|
60
|
+
});
|
|
61
|
+
exports.getDocument = getDocument;
|
|
62
|
+
//# sourceMappingURL=get_document.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get_document.js","sourceRoot":"","sources":["../../../src/tools/firestore/get_document.ts"],"names":[],"mappings":";;;AACA,mCAAsC;AACtC,yCAA6C;AAC7C,6CAAiD;AACjD,mCAA4C;AAE5C,MAAa,iBAAkB,SAAQ,aAAI,CAAC,WAAW,CAAC,mBAAmB,CAGzE;CAAG;AAHL,8CAGK;AAEL,MAAa,qBAAsB,SAAQ,aAAI,CAAC,WAAW,CACzD,uBAAuB,CAGvB;CAAG;AAJL,sDAIK;AAEQ,QAAA,YAAY,GAAG,cAAuB,CAAC;AAOvC,QAAA,qBAAqB,GAAS;IACzC,IAAI,EAAE,oBAAY;IAClB,WAAW,EAAE,yCAAyC;IACtD,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,uCAAuC;aACrD;YACD,MAAM,EAAE;gBACN,IAAI,EAAE,OAAO;gBACb,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBACzB,WAAW,EACT,oEAAoE;aACvE;SACF;QACD,QAAQ,EAAE,CAAC,MAAM,CAAC;KACnB;CACF,CAAC;AAEK,MAAM,WAAW,GAAG,CAAC,KAAsB,EAAE,EAAE,CACpD,eAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,sBAAa,CAAC;IACpC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEhC,MAAM,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC,CAAC,0BAAe,CAAC;IAE7C,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,eAAM,CAAC,GAAG,CAAC;QAC/B,GAAG,EAAE,GAAG,EAAE,CAAC,SAAS,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;QACtC,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CACf,IAAI,iBAAiB,CAAC;YACpB,OAAO,EAAE,0BAA0B,KAAK,CAAC,IAAI,EAAE;YAC/C,KAAK;SACN,CAAC;KACL,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,eAAM,CAAC,UAAU,CAAC;QACpC,GAAG,EAAE,GAAG,EAAE,CACR,KAAK,CAAC,MAAM,EAAE,MAAM;YAClB,CAAC,CAAC,SAAS,EAAE;iBACR,MAAM,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC;iBAC3C,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAC9B,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE;QAClB,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CACf,IAAI,iBAAiB,CAAC;YACpB,OAAO,EAAE,2BAA2B,KAAK,CAAC,IAAI,EAAE;YAChD,KAAK;SACN,CAAC;KACL,CAAC,CAAC;IAEH,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;QACjB,OAAO,KAAK,CAAC,CAAC,eAAM,CAAC,IAAI,CACvB,IAAI,qBAAqB,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAChD,CAAC;IACJ,CAAC;IAED,OAAO,IAAA,yBAAiB,EAAC,IAAI,CAAC,CAAC;AACjC,CAAC,CAAC,CAAC;AArCQ,QAAA,WAAW,eAqCnB"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
import { Effect } from 'effect';
|
|
3
|
+
import { AccessService } from '../../access';
|
|
4
|
+
import { ConfigService } from '../../config';
|
|
5
|
+
import { FirebaseService } from '../../firebase';
|
|
6
|
+
declare const FirestoreGetManyError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
7
|
+
readonly _tag: "FirestoreGetManyError";
|
|
8
|
+
} & Readonly<A>;
|
|
9
|
+
export declare class FirestoreGetManyError extends FirestoreGetManyError_base<{
|
|
10
|
+
readonly message: string;
|
|
11
|
+
readonly cause?: unknown;
|
|
12
|
+
}> {
|
|
13
|
+
}
|
|
14
|
+
export declare const GET_MANY_DOCUMENTS: "get_many_documents";
|
|
15
|
+
export interface GetManyDocumentsArgs {
|
|
16
|
+
paths?: string[];
|
|
17
|
+
collection?: string;
|
|
18
|
+
ids?: string[];
|
|
19
|
+
select?: string[];
|
|
20
|
+
}
|
|
21
|
+
export declare const getManyDocumentsDefinition: Tool;
|
|
22
|
+
export declare const getManyDocuments: (input: GetManyDocumentsArgs) => Effect.Effect<({
|
|
23
|
+
id: string;
|
|
24
|
+
path: string;
|
|
25
|
+
data: unknown;
|
|
26
|
+
found: boolean;
|
|
27
|
+
} | {
|
|
28
|
+
found: boolean;
|
|
29
|
+
id: string;
|
|
30
|
+
path: string;
|
|
31
|
+
})[], import("../../access").AccessDeniedError | FirestoreGetManyError, ConfigService | AccessService | FirebaseService>;
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=get_many_documents.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get_many_documents.d.ts","sourceRoot":"","sources":["../../../src/tools/firestore/get_many_documents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAC1D,OAAO,EAAQ,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;;;;AAGjD,qBAAa,qBAAsB,SAAQ,2BAEzC;IACA,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CAC1B,CAAC;CAAG;AAEL,eAAO,MAAM,kBAAkB,EAAG,oBAA6B,CAAC;AAEhE,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,eAAO,MAAM,0BAA0B,EAAE,IAgCxC,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,OAAO,oBAAoB;;;;;;;;;wHA0DxD,CAAC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getManyDocuments = exports.getManyDocumentsDefinition = exports.GET_MANY_DOCUMENTS = exports.FirestoreGetManyError = void 0;
|
|
4
|
+
const effect_1 = require("effect");
|
|
5
|
+
const access_1 = require("../../access");
|
|
6
|
+
const config_1 = require("../../config");
|
|
7
|
+
const firebase_1 = require("../../firebase");
|
|
8
|
+
const types_1 = require("./types");
|
|
9
|
+
class FirestoreGetManyError extends effect_1.Data.TaggedError('FirestoreGetManyError') {
|
|
10
|
+
}
|
|
11
|
+
exports.FirestoreGetManyError = FirestoreGetManyError;
|
|
12
|
+
exports.GET_MANY_DOCUMENTS = 'get_many_documents';
|
|
13
|
+
exports.getManyDocumentsDefinition = {
|
|
14
|
+
name: exports.GET_MANY_DOCUMENTS,
|
|
15
|
+
description: 'Fetch multiple Firestore documents in a single batch. Provide either an array of full document paths, or a collection path plus an array of document IDs. More efficient than calling get_document repeatedly.',
|
|
16
|
+
inputSchema: {
|
|
17
|
+
type: 'object',
|
|
18
|
+
properties: {
|
|
19
|
+
paths: {
|
|
20
|
+
type: 'array',
|
|
21
|
+
items: { type: 'string' },
|
|
22
|
+
description: "Full document paths, e.g. ['users/123', 'orders/456']. Use this for fetching documents across different collections.",
|
|
23
|
+
},
|
|
24
|
+
collection: {
|
|
25
|
+
type: 'string',
|
|
26
|
+
description: "Collection path when all documents are in the same collection, e.g. 'shared/stores_data/ABC/data/stock'.",
|
|
27
|
+
},
|
|
28
|
+
ids: {
|
|
29
|
+
type: 'array',
|
|
30
|
+
items: { type: 'string' },
|
|
31
|
+
description: "Document IDs within the collection specified by the collection field, e.g. ['0021451', '01010000'].",
|
|
32
|
+
},
|
|
33
|
+
select: {
|
|
34
|
+
type: 'array',
|
|
35
|
+
items: { type: 'string' },
|
|
36
|
+
description: 'Optional list of field paths to return. Omit to return all fields.',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
const getManyDocuments = (input) => effect_1.Effect.gen(function* () {
|
|
42
|
+
const access = yield* access_1.AccessService;
|
|
43
|
+
const { config } = yield* config_1.ConfigService;
|
|
44
|
+
const { firestore } = yield* firebase_1.FirebaseService;
|
|
45
|
+
const maxBatchSize = config.firestore.maxBatchFetchSize;
|
|
46
|
+
// Resolve all paths — full paths take priority, otherwise build from collection + ids
|
|
47
|
+
let allPaths = [];
|
|
48
|
+
if (input.paths?.length) {
|
|
49
|
+
allPaths = input.paths;
|
|
50
|
+
}
|
|
51
|
+
else if (input.collection && input.ids?.length) {
|
|
52
|
+
allPaths = input.ids.map((id) => `${input.collection}/${id}`);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
return yield* effect_1.Effect.fail(new FirestoreGetManyError({
|
|
56
|
+
message: 'Provide either paths, or both collection and ids.',
|
|
57
|
+
}));
|
|
58
|
+
}
|
|
59
|
+
if (allPaths.length > maxBatchSize) {
|
|
60
|
+
return yield* effect_1.Effect.fail(new FirestoreGetManyError({
|
|
61
|
+
message: `Batch size ${allPaths.length} exceeds maxBatchSize (${maxBatchSize}). Split into smaller batches.`,
|
|
62
|
+
}));
|
|
63
|
+
}
|
|
64
|
+
// Access check on each unique collection path
|
|
65
|
+
const uniqueCollections = [
|
|
66
|
+
...new Set(allPaths.map((p) => p.split('/').slice(0, -1).join('/'))),
|
|
67
|
+
];
|
|
68
|
+
for (const col of uniqueCollections) {
|
|
69
|
+
yield* access.check(col);
|
|
70
|
+
}
|
|
71
|
+
const docRefs = allPaths.map((p) => firestore().doc(p));
|
|
72
|
+
const snaps = yield* effect_1.Effect.tryPromise({
|
|
73
|
+
try: () => input.select?.length
|
|
74
|
+
? firestore().getAll(...docRefs, { fieldMask: input.select })
|
|
75
|
+
: firestore().getAll(...docRefs),
|
|
76
|
+
catch: (cause) => new FirestoreGetManyError({
|
|
77
|
+
message: 'Batch fetch failed',
|
|
78
|
+
cause,
|
|
79
|
+
}),
|
|
80
|
+
});
|
|
81
|
+
return snaps.map((snap) => snap.exists
|
|
82
|
+
? { found: true, ...(0, types_1.normalizeDocument)(snap) }
|
|
83
|
+
: { found: false, id: snap.id, path: snap.ref.path });
|
|
84
|
+
});
|
|
85
|
+
exports.getManyDocuments = getManyDocuments;
|
|
86
|
+
//# sourceMappingURL=get_many_documents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get_many_documents.js","sourceRoot":"","sources":["../../../src/tools/firestore/get_many_documents.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from './aggregate_collection';
|
|
2
|
+
export * from './count_documents';
|
|
3
|
+
export * from './get_collection_schema';
|
|
4
|
+
export * from './get_document';
|
|
5
|
+
export * from './get_many_documents';
|
|
6
|
+
export * from './list_collections';
|
|
7
|
+
export * from './list_documents';
|
|
8
|
+
export * from './list_indexes';
|
|
9
|
+
export * from './query_collection';
|
|
10
|
+
export * from './query_collection_group';
|
|
11
|
+
export * from './read_collections';
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/firestore/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,yBAAyB,CAAC;AACxC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./aggregate_collection"), exports);
|
|
18
|
+
__exportStar(require("./count_documents"), exports);
|
|
19
|
+
__exportStar(require("./get_collection_schema"), exports);
|
|
20
|
+
__exportStar(require("./get_document"), exports);
|
|
21
|
+
__exportStar(require("./get_many_documents"), exports);
|
|
22
|
+
__exportStar(require("./list_collections"), exports);
|
|
23
|
+
__exportStar(require("./list_documents"), exports);
|
|
24
|
+
__exportStar(require("./list_indexes"), exports);
|
|
25
|
+
__exportStar(require("./query_collection"), exports);
|
|
26
|
+
__exportStar(require("./query_collection_group"), exports);
|
|
27
|
+
__exportStar(require("./read_collections"), exports);
|
|
28
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/firestore/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,yDAAuC;AACvC,oDAAkC;AAClC,0DAAwC;AACxC,iDAA+B;AAC/B,uDAAqC;AACrC,qDAAmC;AACnC,mDAAiC;AACjC,iDAA+B;AAC/B,qDAAmC;AACnC,2DAAyC;AACzC,qDAAmC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
import { Effect } from 'effect';
|
|
3
|
+
import { AccessService } from '../../access';
|
|
4
|
+
import { FirebaseService } from '../../firebase';
|
|
5
|
+
declare const FirestoreListCollectionsError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
6
|
+
readonly _tag: "FirestoreListCollectionsError";
|
|
7
|
+
} & Readonly<A>;
|
|
8
|
+
export declare class FirestoreListCollectionsError extends FirestoreListCollectionsError_base<{
|
|
9
|
+
readonly message: string;
|
|
10
|
+
readonly cause?: unknown;
|
|
11
|
+
}> {
|
|
12
|
+
}
|
|
13
|
+
export declare const LIST_COLLECTIONS: "list_collections";
|
|
14
|
+
export interface ListCollectionsArgs {
|
|
15
|
+
path?: string;
|
|
16
|
+
includeCounts?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export declare const listCollectionsDefinition: Tool;
|
|
19
|
+
export declare const listCollections: (input: ListCollectionsArgs) => Effect.Effect<{
|
|
20
|
+
id: string;
|
|
21
|
+
path: string;
|
|
22
|
+
}[], import("../../access").AccessDeniedError | FirestoreListCollectionsError, AccessService | FirebaseService>;
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=list_collections.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list_collections.d.ts","sourceRoot":"","sources":["../../../src/tools/firestore/list_collections.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAC1D,OAAO,EAAQ,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;;;;AAEjD,qBAAa,6BAA8B,SAAQ,mCAEjD;IACA,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CAC1B,CAAC;CAAG;AAEL,eAAO,MAAM,gBAAgB,EAAG,kBAA2B,CAAC;AAE5D,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,eAAO,MAAM,yBAAyB,EAAE,IAmBvC,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,OAAO,mBAAmB;;;+GA0CtD,CAAC"}
|