@open-xamu-co/firebase-nuxt 2.0.0-next.1 → 2.0.0-next.2
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 +17 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +34 -31
- package/dist/runtime/client/types/entities/logs.d.ts +10 -1
- package/dist/runtime/client/types/entities/user.d.ts +1 -1
- package/dist/runtime/composables/firestore/write.d.ts +4 -4
- package/dist/runtime/functions/types/entities/instance.d.ts +7 -7
- package/dist/runtime/functions/types/entities/logs.d.ts +26 -0
- package/dist/runtime/functions/utils/logger.d.ts +4 -0
- package/dist/runtime/functions/utils/logger.js +24 -1
- package/dist/runtime/server/api/{all-collection-document.get.d.ts → all-collection-document.d.ts} +1 -1
- package/dist/runtime/server/api/all-collection-document.js +75 -0
- package/dist/runtime/server/api/{all-collection.get.d.ts → all-collection.d.ts} +1 -1
- package/dist/runtime/server/api/all-collection.js +85 -0
- package/dist/runtime/server/api/{media.get.d.ts → media.d.ts} +1 -1
- package/dist/runtime/server/api/{media.get.js → media.js} +20 -4
- package/dist/runtime/server/middleware/1.context.js +5 -17
- package/dist/runtime/server/utils/cache.d.ts +3 -1
- package/dist/runtime/server/utils/cache.js +6 -5
- package/dist/runtime/server/utils/firestore.d.ts +1 -1
- package/dist/runtime/server/utils/firestore.js +7 -10
- package/dist/runtime/server/utils/instance.js +3 -3
- package/package.json +4 -3
- package/dist/runtime/server/api/all-collection-document.get.js +0 -56
- package/dist/runtime/server/api/all-collection.get.js +0 -67
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
Firebase nuxt
|
|
2
2
|
|
|
3
|
+
# [2.0.0-next.2](https://github.com/xamu-co/firebase-nuxt/compare/v2.0.0-next.1...v2.0.0-next.2) (2026-01-15)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* prevent no content on head responses ([a16a768](https://github.com/xamu-co/firebase-nuxt/commit/a16a7682d3fb322bafda64177f5d57541069beac))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* accept head & options request ([2822f2f](https://github.com/xamu-co/firebase-nuxt/commit/2822f2ffeb27cc5b6034cb4fe131ae20ae0bde99))
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### BREAKING CHANGES
|
|
17
|
+
|
|
18
|
+
* less args at resolveServerDocumentRefs
|
|
19
|
+
|
|
3
20
|
# [2.0.0-next.1](https://github.com/xamu-co/firebase-nuxt/compare/v1.2.0-next.2...v2.0.0-next.1) (2026-01-13)
|
|
4
21
|
|
|
5
22
|
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -84,37 +84,40 @@ const module$1 = defineNuxtModule({
|
|
|
84
84
|
middleware: true,
|
|
85
85
|
handler: resolve(runtimePath, "server/middleware/1.context")
|
|
86
86
|
});
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
87
|
+
const methods = ["get", "head", "options"];
|
|
88
|
+
methods.forEach((method) => {
|
|
89
|
+
if (moduleOptions.media) {
|
|
90
|
+
addServerHandler({
|
|
91
|
+
method,
|
|
92
|
+
route: "/api/media/**:path",
|
|
93
|
+
handler: resolve(runtimePath, "server/api/media")
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
if (moduleOptions.readCollection) {
|
|
97
|
+
addServerHandler({
|
|
98
|
+
method,
|
|
99
|
+
route: "/api/all/:collectionId",
|
|
100
|
+
handler: resolve(runtimePath, "server/api/all-collection")
|
|
101
|
+
});
|
|
102
|
+
addServerHandler({
|
|
103
|
+
method,
|
|
104
|
+
route: "/api/all/:collectionId/:documentId",
|
|
105
|
+
handler: resolve(runtimePath, "server/api/all-collection-document")
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
if (moduleOptions.readInstanceCollection) {
|
|
109
|
+
addServerHandler({
|
|
110
|
+
method,
|
|
111
|
+
route: "/api/instance/all/:collectionId",
|
|
112
|
+
handler: resolve(runtimePath, "server/api/all-collection")
|
|
113
|
+
});
|
|
114
|
+
addServerHandler({
|
|
115
|
+
method,
|
|
116
|
+
route: "/api/instance/all/:collectionId/:documentId",
|
|
117
|
+
handler: resolve(runtimePath, "server/api/all-collection-document")
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
});
|
|
118
121
|
},
|
|
119
122
|
moduleDependencies() {
|
|
120
123
|
const { resolve } = createResolver(import.meta.url);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { DocumentReference } from "firebase/firestore";
|
|
2
|
+
import type { LogData, OffenderData } from "../../../functions/types/index.js";
|
|
2
3
|
import type { FromData } from "./base.js";
|
|
3
4
|
import type { GetSharedRef } from "./user.js";
|
|
4
5
|
/** @output Log */
|
|
@@ -7,3 +8,11 @@ export interface Log extends FromData<LogData> {
|
|
|
7
8
|
/** @input Omit automation */
|
|
8
9
|
export interface LogRef extends GetSharedRef<Log> {
|
|
9
10
|
}
|
|
11
|
+
/** @output Offender */
|
|
12
|
+
export interface Offender extends FromData<OffenderData> {
|
|
13
|
+
lastLog?: Log;
|
|
14
|
+
}
|
|
15
|
+
/** @input Omit automation */
|
|
16
|
+
export interface OffenderRef extends GetSharedRef<Offender> {
|
|
17
|
+
lastLogRef?: DocumentReference<LogData>;
|
|
18
|
+
}
|
|
@@ -9,7 +9,7 @@ import type { Instance, SharedDocument } from "./instance.js";
|
|
|
9
9
|
* Removed properties are not required or are part of automation
|
|
10
10
|
*/
|
|
11
11
|
export type GetSharedRef<T extends SharedDocument, O extends keyof T = never> = {
|
|
12
|
-
[K in keyof FromData<Omit<T,
|
|
12
|
+
[K in keyof FromData<Omit<T, O>> as K extends `${string}At` ? never : K]: FromData<Omit<T, O>>[K];
|
|
13
13
|
} & {
|
|
14
14
|
createdByRef?: DocumentReference | FieldValue;
|
|
15
15
|
updatedByRef?: DocumentReference | FieldValue;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { DocumentReference } from "firebase/firestore";
|
|
2
2
|
import type { iNodeFnResponseStream } from "@open-xamu-co/ui-common-types";
|
|
3
|
-
import type { GetRef, SharedDocument, FirebaseDocument, iSnapshotConfig } from "../../client/types/index.js";
|
|
3
|
+
import type { GetRef, SharedDocument, FirebaseDocument, iSnapshotConfig, FromData } from "../../client/types/index.js";
|
|
4
4
|
interface iUseDocumentOptions extends iSnapshotConfig {
|
|
5
5
|
omitLoggings?: boolean;
|
|
6
6
|
}
|
|
7
7
|
/** Creates document with the given values */
|
|
8
|
-
export declare function useDocumentCreate<Vgr extends GetRef<
|
|
8
|
+
export declare function useDocumentCreate<Vgr extends GetRef<SharedDocument>, V extends FromData<Vgr> = FromData<Vgr>>(collectionPath: string, partialRef: Vgr, createdCallback?: (ref: DocumentReference<Vgr, V>) => Promise<void> | void, { omitLoggings, ...config }?: iUseDocumentOptions): Promise<iNodeFnResponseStream<V>>;
|
|
9
9
|
/**
|
|
10
10
|
* Updates a given document in Firestore.
|
|
11
11
|
*
|
|
@@ -13,9 +13,9 @@ export declare function useDocumentCreate<Vgr extends GetRef<V>, V extends Fireb
|
|
|
13
13
|
* @param partialRef - The partial data to update the document with.
|
|
14
14
|
* @returns A boolean promise.
|
|
15
15
|
*/
|
|
16
|
-
export declare function useDocumentUpdate<Vgr extends GetRef<
|
|
16
|
+
export declare function useDocumentUpdate<Vgr extends GetRef<SharedDocument>, V extends FromData<Vgr> = FromData<Vgr>>(node: SharedDocument, middleRef?: Partial<Vgr>, { omitLoggings, ...config }?: iUseDocumentOptions): Promise<iNodeFnResponseStream<V>>;
|
|
17
17
|
/** Clones given document */
|
|
18
|
-
export declare function useDocumentClone<Vgr extends GetRef<
|
|
18
|
+
export declare function useDocumentClone<Vgr extends GetRef<SharedDocument>, V extends FromData<Vgr> = FromData<Vgr>>(node: SharedDocument, middleRef?: Partial<Vgr>, { omitLoggings, ...config }?: iUseDocumentOptions): Promise<iNodeFnResponseStream<V>>;
|
|
19
19
|
/** Deletes given document */
|
|
20
20
|
export declare function useDocumentDelete<T extends FirebaseDocument = FirebaseDocument>(node: SharedDocument, { omitLoggings }?: iUseDocumentOptions): Promise<iNodeFnResponseStream<T>>;
|
|
21
21
|
export {};
|
|
@@ -30,6 +30,12 @@ export interface RootData extends InstanceData {
|
|
|
30
30
|
/** @example "Xamu" */
|
|
31
31
|
poweredBy?: string;
|
|
32
32
|
}
|
|
33
|
+
export interface InstanceDataConfig extends FirebaseData {
|
|
34
|
+
/**
|
|
35
|
+
* When tenants are enabled, domains are required
|
|
36
|
+
*/
|
|
37
|
+
domains?: string[];
|
|
38
|
+
}
|
|
33
39
|
/**
|
|
34
40
|
* App instance
|
|
35
41
|
*
|
|
@@ -46,13 +52,7 @@ export interface InstanceData extends SharedData {
|
|
|
46
52
|
* @automated
|
|
47
53
|
*/
|
|
48
54
|
url?: string;
|
|
49
|
-
config?:
|
|
50
|
-
[key: string]: any;
|
|
51
|
-
/**
|
|
52
|
-
* When tenants are enabled, domains are required
|
|
53
|
-
*/
|
|
54
|
-
domains?: string[];
|
|
55
|
-
};
|
|
55
|
+
config?: InstanceDataConfig;
|
|
56
56
|
}
|
|
57
57
|
/**
|
|
58
58
|
* Firebase log
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { DocumentReference } from "firebase-admin/firestore";
|
|
1
2
|
import type { FirebaseData } from "./base.js";
|
|
2
3
|
/** General log entity */
|
|
3
4
|
export interface LogData extends FirebaseData {
|
|
@@ -13,3 +14,28 @@ export interface LogData extends FirebaseData {
|
|
|
13
14
|
*/
|
|
14
15
|
internal?: boolean;
|
|
15
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Offender entity
|
|
19
|
+
*
|
|
20
|
+
* Keep track of abbussive requests
|
|
21
|
+
*/
|
|
22
|
+
export interface OffenderData extends FirebaseData {
|
|
23
|
+
/** IP address */
|
|
24
|
+
ip?: string;
|
|
25
|
+
/** ISO country codes */
|
|
26
|
+
countries?: string[];
|
|
27
|
+
/** User agents */
|
|
28
|
+
userAgents?: string[];
|
|
29
|
+
/** Preferred languages */
|
|
30
|
+
languages?: string[];
|
|
31
|
+
/**
|
|
32
|
+
* Number of hits
|
|
33
|
+
* @automated
|
|
34
|
+
*/
|
|
35
|
+
hits?: number;
|
|
36
|
+
/**
|
|
37
|
+
* Log reference
|
|
38
|
+
* @automated
|
|
39
|
+
*/
|
|
40
|
+
lastLogRef?: DocumentReference<LogData>;
|
|
41
|
+
}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
import { DocumentReference, type Firestore } from "firebase-admin/firestore";
|
|
2
2
|
import type { tLogger } from "@open-xamu-co/ui-common-types";
|
|
3
3
|
export declare function makeFunctionsLogger(at: DocumentReference | Firestore, authorRef?: DocumentReference, metadata?: Record<string, any>): tLogger;
|
|
4
|
+
/**
|
|
5
|
+
* Log offending requests sources
|
|
6
|
+
*/
|
|
7
|
+
export declare function offenderLogger(at: DocumentReference | Firestore, lastLogRef: DocumentReference, metadata?: any): void;
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
DocumentReference,
|
|
3
|
+
FieldValue
|
|
4
|
+
} from "firebase-admin/firestore";
|
|
5
|
+
import acceptLanguageParser from "accept-language-parser";
|
|
2
6
|
import { getLog } from "./logs.js";
|
|
3
7
|
export function makeFunctionsLogger(at, authorRef, metadata = {}) {
|
|
4
8
|
return function(...args) {
|
|
@@ -15,3 +19,22 @@ export function makeFunctionsLogger(at, authorRef, metadata = {}) {
|
|
|
15
19
|
}
|
|
16
20
|
};
|
|
17
21
|
}
|
|
22
|
+
export function offenderLogger(at, lastLogRef, metadata) {
|
|
23
|
+
if (!metadata || typeof metadata !== "object") return;
|
|
24
|
+
const headers = metadata.headers || {};
|
|
25
|
+
const ip = headers["cf-connecting-ip"] || headers["x-fah-client-ip"] || headers["ip"];
|
|
26
|
+
const userAgent = headers["from"] || headers["user-agent"];
|
|
27
|
+
const country = headers["cf-ipcountry"];
|
|
28
|
+
const [preferredLanguage] = acceptLanguageParser.parse(headers["accept-language"]);
|
|
29
|
+
if (!ip) return;
|
|
30
|
+
const offendersRef = at.collection("offenders");
|
|
31
|
+
const offenderDoc = offendersRef.doc(ip);
|
|
32
|
+
const offenderData = { ip, hits: FieldValue.increment(1), lastLogRef };
|
|
33
|
+
if (country) offenderData.countries = FieldValue.arrayUnion(country);
|
|
34
|
+
if (userAgent) offenderData.userAgents = FieldValue.arrayUnion(userAgent);
|
|
35
|
+
if (preferredLanguage) {
|
|
36
|
+
const { code, region } = preferredLanguage;
|
|
37
|
+
offenderData.languages = FieldValue.arrayUnion(`${code}-${region}`);
|
|
38
|
+
}
|
|
39
|
+
offenderDoc.set(offenderData, { merge: true });
|
|
40
|
+
}
|
package/dist/runtime/server/api/{all-collection-document.get.d.ts → all-collection-document.d.ts}
RENAMED
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @auth guest
|
|
5
5
|
*/
|
|
6
|
-
declare const _default: import("../types/index.js").CachedEventHandler<import("h3").EventHandlerRequest, Promise<void | FirebaseFirestore.DocumentData>>;
|
|
6
|
+
declare const _default: import("../types/index.js").CachedEventHandler<import("h3").EventHandlerRequest, Promise<void | FirebaseFirestore.DocumentData | "Ok">>;
|
|
7
7
|
export default _default;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createError,
|
|
3
|
+
getRouterParam,
|
|
4
|
+
isError,
|
|
5
|
+
sendNoContent,
|
|
6
|
+
setResponseHeaders,
|
|
7
|
+
setResponseStatus
|
|
8
|
+
} from "h3";
|
|
9
|
+
import { defineConditionallyCachedEventHandler } from "../utils/cache.js";
|
|
10
|
+
import { debugFirebaseServer, resolveServerDocumentRefs } from "../utils/firestore.js";
|
|
11
|
+
import { apiLogger, getServerFirebase } from "../utils/firebase.js";
|
|
12
|
+
import { readCollection, readInstanceCollection } from "#internal/firebase-nuxt";
|
|
13
|
+
export default defineConditionallyCachedEventHandler(async (event) => {
|
|
14
|
+
const { firebaseFirestore } = getServerFirebase("api:all:[collectionId]:[documentId]");
|
|
15
|
+
const { currentInstanceRef } = event.context;
|
|
16
|
+
const Allow = "GET,HEAD";
|
|
17
|
+
try {
|
|
18
|
+
setResponseHeaders(event, {
|
|
19
|
+
Allow,
|
|
20
|
+
"Access-Control-Allow-Methods": Allow,
|
|
21
|
+
"Content-Type": "application/json"
|
|
22
|
+
});
|
|
23
|
+
if (!["GET", "HEAD", "OPTIONS"].includes(event.method?.toUpperCase())) {
|
|
24
|
+
throw createError({ statusCode: 405, statusMessage: "Unsupported method" });
|
|
25
|
+
} else if (event.method?.toUpperCase() === "OPTIONS") {
|
|
26
|
+
return sendNoContent(event);
|
|
27
|
+
}
|
|
28
|
+
const collectionId = getRouterParam(event, "collectionId");
|
|
29
|
+
const documentId = getRouterParam(event, "documentId");
|
|
30
|
+
debugFirebaseServer(event, "api:all:[collectionId]:[documentId]", collectionId, documentId);
|
|
31
|
+
if (!collectionId || !documentId) {
|
|
32
|
+
throw createError({
|
|
33
|
+
statusCode: 400,
|
|
34
|
+
statusMessage: `collectionId & documentId are required`
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
let collectionRef = firebaseFirestore.collection(collectionId);
|
|
38
|
+
if (event.path.startsWith("/api/instance/all")) {
|
|
39
|
+
if (!currentInstanceRef) {
|
|
40
|
+
throw createError({ statusCode: 401, statusMessage: "Missing instance" });
|
|
41
|
+
} else if (!readInstanceCollection(collectionId, event.context)) {
|
|
42
|
+
throw createError({
|
|
43
|
+
statusCode: 401,
|
|
44
|
+
statusMessage: `Can't get "instance/${collectionId}" document`
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
collectionRef = currentInstanceRef.collection(collectionId);
|
|
48
|
+
} else if (!readCollection(collectionId, event.context)) {
|
|
49
|
+
throw createError({
|
|
50
|
+
statusCode: 401,
|
|
51
|
+
statusMessage: `Can't get "${collectionId}" document`
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
const documentsRef = collectionRef.doc(documentId);
|
|
55
|
+
const documentSnapshot = await documentsRef.get();
|
|
56
|
+
if (!documentSnapshot?.exists) {
|
|
57
|
+
let statusMessage = `No "${collectionId}" document matched`;
|
|
58
|
+
if (documentSnapshot?.ref.path) {
|
|
59
|
+
statusMessage = `${statusMessage} for ${documentSnapshot.ref.path}`;
|
|
60
|
+
}
|
|
61
|
+
throw createError({ statusCode: 404, statusMessage });
|
|
62
|
+
}
|
|
63
|
+
if (event.method?.toUpperCase() === "HEAD") {
|
|
64
|
+
setResponseStatus(event, 200);
|
|
65
|
+
return "Ok";
|
|
66
|
+
}
|
|
67
|
+
return resolveServerDocumentRefs(event, documentSnapshot);
|
|
68
|
+
} catch (err) {
|
|
69
|
+
if (isError(err)) {
|
|
70
|
+
apiLogger(event, "api:all:[collectionId]:[documentId]", err.message, err);
|
|
71
|
+
return setResponseStatus(event, err.statusCode || 500, err.statusMessage);
|
|
72
|
+
}
|
|
73
|
+
throw err;
|
|
74
|
+
}
|
|
75
|
+
});
|
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
* @auth guest
|
|
5
5
|
* @order createdAt
|
|
6
6
|
*/
|
|
7
|
-
declare const _default: import("../types/index.js").CachedEventHandler<import("h3").EventHandlerRequest, Promise<void | import("@open-xamu-co/ui-common-types").iPageEdge<FirebaseFirestore.DocumentData, string>[] | import("@open-xamu-co/ui-common-types").iPage<FirebaseFirestore.DocumentData, string
|
|
7
|
+
declare const _default: import("../types/index.js").CachedEventHandler<import("h3").EventHandlerRequest, Promise<void | import("@open-xamu-co/ui-common-types").iPageEdge<FirebaseFirestore.DocumentData, string>[] | import("@open-xamu-co/ui-common-types").iPage<FirebaseFirestore.DocumentData, string> | "Ok">>;
|
|
8
8
|
export default _default;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { FieldPath } from "firebase-admin/firestore";
|
|
2
|
+
import {
|
|
3
|
+
createError,
|
|
4
|
+
getQuery,
|
|
5
|
+
getRouterParam,
|
|
6
|
+
isError,
|
|
7
|
+
sendNoContent,
|
|
8
|
+
setResponseHeaders,
|
|
9
|
+
setResponseStatus
|
|
10
|
+
} from "h3";
|
|
11
|
+
import { defineConditionallyCachedEventHandler } from "../utils/cache.js";
|
|
12
|
+
import { getBoolean } from "../utils/guards.js";
|
|
13
|
+
import { getDocumentId } from "../../client/utils/resolver.js";
|
|
14
|
+
import {
|
|
15
|
+
debugFirebaseServer,
|
|
16
|
+
getEdgesPage,
|
|
17
|
+
getOrderedQuery,
|
|
18
|
+
getQueryAsEdges
|
|
19
|
+
} from "../utils/firestore.js";
|
|
20
|
+
import { apiLogger, getServerFirebase } from "../utils/firebase.js";
|
|
21
|
+
import { readCollection, readInstanceCollection } from "#internal/firebase-nuxt";
|
|
22
|
+
export default defineConditionallyCachedEventHandler(async (event) => {
|
|
23
|
+
const fieldDocument = FieldPath.documentId();
|
|
24
|
+
const { firebaseFirestore } = getServerFirebase("api:all:[collectionId]");
|
|
25
|
+
const { currentInstanceRef } = event.context;
|
|
26
|
+
const Allow = "GET,HEAD";
|
|
27
|
+
try {
|
|
28
|
+
setResponseHeaders(event, {
|
|
29
|
+
Allow,
|
|
30
|
+
"Access-Control-Allow-Methods": Allow,
|
|
31
|
+
"Content-Type": "application/json"
|
|
32
|
+
});
|
|
33
|
+
if (!["GET", "HEAD", "OPTIONS"].includes(event.method?.toUpperCase())) {
|
|
34
|
+
throw createError({ statusCode: 405, statusMessage: "Unsupported method" });
|
|
35
|
+
} else if (event.method?.toUpperCase() === "OPTIONS") {
|
|
36
|
+
return sendNoContent(event);
|
|
37
|
+
}
|
|
38
|
+
const params = getQuery(event);
|
|
39
|
+
const page = getBoolean(params.page);
|
|
40
|
+
const collectionId = getRouterParam(event, "collectionId");
|
|
41
|
+
debugFirebaseServer(event, "api:all:[collectionId]", collectionId);
|
|
42
|
+
if (!collectionId) {
|
|
43
|
+
throw createError({ statusCode: 400, statusMessage: `collectionId is required` });
|
|
44
|
+
}
|
|
45
|
+
let query = firebaseFirestore.collection(collectionId);
|
|
46
|
+
if (event.path.startsWith("/api/instance/all")) {
|
|
47
|
+
if (!currentInstanceRef) {
|
|
48
|
+
throw createError({ statusCode: 401, statusMessage: "Missing instance" });
|
|
49
|
+
} else if (!readInstanceCollection(collectionId, event.context)) {
|
|
50
|
+
throw createError({
|
|
51
|
+
statusCode: 401,
|
|
52
|
+
statusMessage: `Can't list "instance/${collectionId}"`
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
query = currentInstanceRef.collection(collectionId);
|
|
56
|
+
} else if (!readCollection(collectionId, event.context)) {
|
|
57
|
+
throw createError({
|
|
58
|
+
statusCode: 401,
|
|
59
|
+
statusMessage: `Can't list "${collectionId}"`
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
if (event.method?.toUpperCase() === "HEAD") {
|
|
63
|
+
setResponseStatus(event, 200);
|
|
64
|
+
return "Ok";
|
|
65
|
+
}
|
|
66
|
+
if (params.include) {
|
|
67
|
+
let include = Array.isArray(params.include) ? params.include : [params.include];
|
|
68
|
+
include = include.filter((uid) => uid && !getBoolean(uid)).map(getDocumentId);
|
|
69
|
+
debugFirebaseServer(event, "api:all:[collectionId]:filtered", include);
|
|
70
|
+
if (!include.length) return [];
|
|
71
|
+
query = query.orderBy(fieldDocument).where(fieldDocument, "in", include);
|
|
72
|
+
return getQueryAsEdges(event, query);
|
|
73
|
+
}
|
|
74
|
+
query = getOrderedQuery(event, query);
|
|
75
|
+
if (page) return getEdgesPage(event, query);
|
|
76
|
+
const first = Math.min(Number(params.first) || 10, 100);
|
|
77
|
+
return getQueryAsEdges(event, query.limit(first));
|
|
78
|
+
} catch (err) {
|
|
79
|
+
if (isError(err)) {
|
|
80
|
+
apiLogger(event, "api:all:[collectionId]", err.message, err);
|
|
81
|
+
return setResponseStatus(event, err.statusCode || 500, err.statusMessage);
|
|
82
|
+
}
|
|
83
|
+
throw err;
|
|
84
|
+
}
|
|
85
|
+
});
|
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
* Buffer check because of nitro issue:
|
|
5
5
|
* @see https://github.com/unjs/nitro/issues/1894
|
|
6
6
|
*/
|
|
7
|
-
declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void | Buffer<ArrayBuffer
|
|
7
|
+
declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void | Buffer<ArrayBuffer> | "Ok">>;
|
|
8
8
|
export default _default;
|
|
@@ -7,7 +7,10 @@ import {
|
|
|
7
7
|
getRouterParam,
|
|
8
8
|
isError,
|
|
9
9
|
sendError,
|
|
10
|
-
|
|
10
|
+
sendNoContent,
|
|
11
|
+
setHeaders,
|
|
12
|
+
setResponseHeaders,
|
|
13
|
+
setResponseStatus
|
|
11
14
|
} from "h3";
|
|
12
15
|
import { storageBucket } from "../utils/environment.js";
|
|
13
16
|
import { debugFirebaseServer } from "../utils/firestore.js";
|
|
@@ -52,6 +55,7 @@ const cachedBufferHandler = defineCachedFunction(
|
|
|
52
55
|
const [exists] = await file.exists();
|
|
53
56
|
const headers = { "Content-Type": "image/webp" };
|
|
54
57
|
if (exists) {
|
|
58
|
+
if (event.method?.toUpperCase() === "HEAD") return { headers };
|
|
55
59
|
const [buffer] = await file.download();
|
|
56
60
|
return { buffer, headers };
|
|
57
61
|
}
|
|
@@ -83,16 +87,28 @@ const cachedBufferHandler = defineCachedFunction(
|
|
|
83
87
|
maxAge,
|
|
84
88
|
getKey(event, path) {
|
|
85
89
|
const [baseAndExtension] = path.split("?");
|
|
86
|
-
|
|
90
|
+
const hash = createHash("sha256").update(baseAndExtension).digest("hex");
|
|
91
|
+
return `${hash}:${event.method}`;
|
|
87
92
|
}
|
|
88
93
|
}
|
|
89
94
|
);
|
|
90
95
|
export default defineEventHandler(async (event) => {
|
|
91
96
|
const path = getRouterParam(event, "path") || "";
|
|
97
|
+
const Allow = "GET,HEAD";
|
|
92
98
|
try {
|
|
93
|
-
|
|
94
|
-
if (
|
|
99
|
+
setResponseHeaders(event, { Allow, "Access-Control-Allow-Methods": Allow });
|
|
100
|
+
if (!["GET", "HEAD", "OPTIONS"].includes(event.method?.toUpperCase())) {
|
|
101
|
+
throw createError({ statusCode: 405, statusMessage: "Unsupported method" });
|
|
102
|
+
} else if (event.method?.toUpperCase() === "OPTIONS") {
|
|
103
|
+
return sendNoContent(event);
|
|
104
|
+
}
|
|
105
|
+
const { buffer, headers = {}, error } = await cachedBufferHandler(event, path);
|
|
106
|
+
setHeaders(event, headers);
|
|
95
107
|
if (error || !buffer) {
|
|
108
|
+
if (!error && event.method?.toUpperCase() === "HEAD") {
|
|
109
|
+
setResponseStatus(event, 200);
|
|
110
|
+
return "Ok";
|
|
111
|
+
}
|
|
96
112
|
const err = error || createError({
|
|
97
113
|
statusCode: 500,
|
|
98
114
|
statusMessage: `Something went wrong while trying to get file with path: "${path}"`
|
|
@@ -18,20 +18,7 @@ export default defineEventHandler(async (event) => {
|
|
|
18
18
|
const { firebaseFirestore } = getServerFirebase("api:middleware:context");
|
|
19
19
|
const headers = getRequestHeaders(event);
|
|
20
20
|
const corsHeaders = ["Origin", "Referer", "User-Agent"].join(", ");
|
|
21
|
-
if (!event.path.startsWith("/api"))
|
|
22
|
-
setResponseHeaders(event, {
|
|
23
|
-
"Access-Control-Allow-Methods": "GET,HEAD",
|
|
24
|
-
Vary: "Host, Origin"
|
|
25
|
-
});
|
|
26
|
-
if (event.method === "OPTIONS") {
|
|
27
|
-
setResponseHeaders(event, {
|
|
28
|
-
"Access-Control-Allow-Headers": corsHeaders,
|
|
29
|
-
"Access-Control-Expose-Headers": corsHeaders
|
|
30
|
-
});
|
|
31
|
-
setResponseStatus(event, 204, "No Content");
|
|
32
|
-
}
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
21
|
+
if (!event.path.startsWith("/api")) return;
|
|
35
22
|
const {
|
|
36
23
|
host = "",
|
|
37
24
|
"x-forwarded-host": forwardedHost = host,
|
|
@@ -57,18 +44,19 @@ export default defineEventHandler(async (event) => {
|
|
|
57
44
|
"Host",
|
|
58
45
|
"Xamu-Context-Source"
|
|
59
46
|
].join(", ");
|
|
47
|
+
const Allow = "GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS";
|
|
60
48
|
setResponseHeaders(event, {
|
|
61
|
-
|
|
49
|
+
Allow,
|
|
50
|
+
"Access-Control-Allow-Methods": Allow,
|
|
62
51
|
"Access-Control-Allow-Credentials": "true",
|
|
63
52
|
"Access-Control-Allow-Origin": corsOrigin,
|
|
64
53
|
Vary: "Host, Origin"
|
|
65
54
|
});
|
|
66
|
-
if (event.method === "OPTIONS") {
|
|
55
|
+
if (event.method?.toUpperCase() === "OPTIONS") {
|
|
67
56
|
setResponseHeaders(event, {
|
|
68
57
|
"Access-Control-Allow-Headers": corsHeadersAccept,
|
|
69
58
|
"Access-Control-Expose-Headers": corsHeadersExpose
|
|
70
59
|
});
|
|
71
|
-
setResponseStatus(event, 204, "No Content");
|
|
72
60
|
}
|
|
73
61
|
const authorization = getRequestHeader(event, "X-Forwarded-Authorization") || getRequestHeader(event, "Authorization");
|
|
74
62
|
if (!authorization) return;
|
|
@@ -5,6 +5,8 @@ interface CachedEventHandlerOptions<T extends EventHandlerRequest = EventHandler
|
|
|
5
5
|
getKey?: (...args: [CachedH3Event<T>]) => string | Promise<string>;
|
|
6
6
|
/** Partition cache by instance */
|
|
7
7
|
instanceOnly?: boolean;
|
|
8
|
+
/** Partition cache by method */
|
|
9
|
+
methodOnly?: boolean;
|
|
8
10
|
}
|
|
9
11
|
/**
|
|
10
12
|
* Conditionally cache event data.
|
|
@@ -17,5 +19,5 @@ interface CachedEventHandlerOptions<T extends EventHandlerRequest = EventHandler
|
|
|
17
19
|
* @param options optional key generator and instanceOnly flag
|
|
18
20
|
* @returns event handler
|
|
19
21
|
*/
|
|
20
|
-
export declare const defineConditionallyCachedEventHandler: <T extends EventHandlerRequest, D extends EventHandlerResponse = EventHandlerResponse>(handler: CachedEventHandler<T, D>, { getKey, instanceOnly }?: CachedEventHandlerOptions<T>) => CachedEventHandler<T, D>;
|
|
22
|
+
export declare const defineConditionallyCachedEventHandler: <T extends EventHandlerRequest, D extends EventHandlerResponse = EventHandlerResponse>(handler: CachedEventHandler<T, D>, { getKey, instanceOnly, methodOnly }?: CachedEventHandlerOptions<T>) => CachedEventHandler<T, D>;
|
|
21
23
|
export {};
|
|
@@ -2,16 +2,17 @@ import { defineEventHandler } from "h3";
|
|
|
2
2
|
import { defineCachedEventHandler } from "nitropack/runtime";
|
|
3
3
|
import { debugNitro } from "../utils/environment.js";
|
|
4
4
|
import { sudo } from "#internal/firebase-nuxt";
|
|
5
|
-
export const defineConditionallyCachedEventHandler = (handler, { getKey, instanceOnly = true } = {}) => {
|
|
5
|
+
export const defineConditionallyCachedEventHandler = (handler, { getKey, instanceOnly = true, methodOnly = true } = {}) => {
|
|
6
6
|
const cachedHandler = defineCachedEventHandler(handler, {
|
|
7
7
|
maxAge: 30,
|
|
8
8
|
// 30 seconds
|
|
9
|
-
getKey
|
|
9
|
+
getKey(event) {
|
|
10
10
|
const { currentInstanceHost } = event.context;
|
|
11
|
-
|
|
12
|
-
if (currentInstanceHost)
|
|
11
|
+
let key = getKey?.(event) || event.path;
|
|
12
|
+
if (instanceOnly && currentInstanceHost) key += `:${currentInstanceHost}`;
|
|
13
|
+
if (methodOnly) key += `:${event.method}`;
|
|
13
14
|
return key;
|
|
14
|
-
}
|
|
15
|
+
}
|
|
15
16
|
});
|
|
16
17
|
return defineEventHandler(async (event) => {
|
|
17
18
|
if (sudo(event.context) || debugNitro.value()) return handler(event);
|
|
@@ -9,7 +9,7 @@ export declare function debugFirebaseServer<T extends EventHandlerRequest>(event
|
|
|
9
9
|
/**
|
|
10
10
|
* This one is used on api endpoints
|
|
11
11
|
*/
|
|
12
|
-
export declare function resolveServerDocumentRefs<T extends PseudoNode, R extends FromData<T> = FromData<T>>(event: H3Event, snapshot?: DocumentSnapshot<T, R>,
|
|
12
|
+
export declare function resolveServerDocumentRefs<T extends PseudoNode, R extends FromData<T> = FromData<T>>(event: H3Event, snapshot?: DocumentSnapshot<T, R>, withAuth?: boolean): Promise<R | undefined> | undefined;
|
|
13
13
|
/**
|
|
14
14
|
* Resolve general refs
|
|
15
15
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getRequestURL,
|
|
1
|
+
import { getRequestURL, getQuery } from "h3";
|
|
2
2
|
import { useEvent } from "nitropack/runtime";
|
|
3
3
|
import { getBoolean, isNumberOrString } from "../utils/guards.js";
|
|
4
4
|
import { makeResolveRefs } from "../../client/utils/resolver.js";
|
|
@@ -17,16 +17,13 @@ export function debugFirebaseServer(event, mss, ...args) {
|
|
|
17
17
|
console.groupEnd();
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
|
-
export function resolveServerDocumentRefs(event, snapshot,
|
|
21
|
-
if (
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
export function resolveServerDocumentRefs(event, snapshot, withAuth) {
|
|
21
|
+
if (snapshot?.exists) {
|
|
22
|
+
const params = getQuery(event);
|
|
23
|
+
const level = Array.isArray(params.level) || !params.level ? 0 : Number(params.level);
|
|
24
|
+
const omit = Array.isArray(params.omit) ? params.omit : [params.omit];
|
|
25
|
+
return resolveServerRefs(snapshot, { level, omit }, withAuth);
|
|
25
26
|
}
|
|
26
|
-
const params = getQuery(event);
|
|
27
|
-
const level = Array.isArray(params.level) || !params.level ? 0 : Number(params.level);
|
|
28
|
-
const omit = Array.isArray(params.omit) ? params.omit : [params.omit];
|
|
29
|
-
return resolveServerRefs(snapshot, { level, omit }, withAuth);
|
|
30
27
|
}
|
|
31
28
|
export async function resolveServerRefs(snapshot, config = {}, withAuth) {
|
|
32
29
|
const event = useEvent();
|
|
@@ -25,8 +25,8 @@ export const getInstance = defineCachedFunction(
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
const millis = snapshot.data()?.createdAt?.toMillis();
|
|
28
|
-
const instance = await resolveServerDocumentRefs(event, snapshot,
|
|
29
|
-
if (!instance
|
|
28
|
+
const instance = await resolveServerDocumentRefs(event, snapshot, false);
|
|
29
|
+
if (!instance?.id || !millis) {
|
|
30
30
|
throw createError({
|
|
31
31
|
statusCode: 502,
|
|
32
32
|
statusMessage: `Invalid app instance for ${host}`,
|
|
@@ -59,7 +59,7 @@ export const getRootInstance = defineCachedFunction(
|
|
|
59
59
|
const instancesRef = firebaseFirestore.collection("instances");
|
|
60
60
|
debugFirebaseServer(event, "middleware:getRootInstance");
|
|
61
61
|
const snapshot = await instancesRef.doc(rootInstanceId).get();
|
|
62
|
-
return resolveServerDocumentRefs(event, snapshot,
|
|
62
|
+
return resolveServerDocumentRefs(event, snapshot, false) || {};
|
|
63
63
|
},
|
|
64
64
|
{
|
|
65
65
|
name: "getRootInstance",
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-xamu-co/firebase-nuxt",
|
|
3
|
-
"version": "2.0.0-next.
|
|
3
|
+
"version": "2.0.0-next.2",
|
|
4
|
+
"stableVersion": "1.1.0",
|
|
4
5
|
"description": "Nuxt 3 module for the xamu project",
|
|
5
6
|
"author": "@xamu-co",
|
|
6
7
|
"type": "module",
|
|
@@ -88,6 +89,7 @@
|
|
|
88
89
|
"@open-xamu-co/ui-common-helpers": "^4.0.0-next.2",
|
|
89
90
|
"@open-xamu-co/ui-nuxt": "^4.0.0-next.6",
|
|
90
91
|
"@pinia/nuxt": "^0.11.0",
|
|
92
|
+
"accept-language-parser": "^1.5.0",
|
|
91
93
|
"firebase": "^11.0.2",
|
|
92
94
|
"firebase-admin": "^13.6.0",
|
|
93
95
|
"firebase-functions": "^7.0.3",
|
|
@@ -160,6 +162,5 @@
|
|
|
160
162
|
},
|
|
161
163
|
"browserslist": [
|
|
162
164
|
"defaults"
|
|
163
|
-
]
|
|
164
|
-
"stableVersion": "1.1.0"
|
|
165
|
+
]
|
|
165
166
|
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { createError, getRouterParam, isError, setResponseStatus } from "h3";
|
|
2
|
-
import { defineConditionallyCachedEventHandler } from "../utils/cache.js";
|
|
3
|
-
import { debugFirebaseServer, resolveServerDocumentRefs } from "../utils/firestore.js";
|
|
4
|
-
import { apiLogger, getServerFirebase } from "../utils/firebase.js";
|
|
5
|
-
import { readCollection, readInstanceCollection } from "#internal/firebase-nuxt";
|
|
6
|
-
export default defineConditionallyCachedEventHandler(
|
|
7
|
-
async (event) => {
|
|
8
|
-
const { firebaseFirestore } = getServerFirebase("api:all:[collectionId]:[documentId]");
|
|
9
|
-
const { currentInstanceRef } = event.context;
|
|
10
|
-
try {
|
|
11
|
-
const collectionId = getRouterParam(event, "collectionId");
|
|
12
|
-
const documentId = getRouterParam(event, "documentId");
|
|
13
|
-
debugFirebaseServer(
|
|
14
|
-
event,
|
|
15
|
-
"api:all:[collectionId]:[documentId]",
|
|
16
|
-
collectionId,
|
|
17
|
-
documentId
|
|
18
|
-
);
|
|
19
|
-
if (!collectionId || !documentId) {
|
|
20
|
-
throw createError({
|
|
21
|
-
statusCode: 400,
|
|
22
|
-
statusMessage: `collectionId & documentId are required`
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
let collectionRef = firebaseFirestore.collection(collectionId);
|
|
26
|
-
if (event.path.startsWith("/api/instance/all")) {
|
|
27
|
-
if (!currentInstanceRef) {
|
|
28
|
-
throw createError({ statusCode: 401, statusMessage: "Missing instance" });
|
|
29
|
-
} else if (!readInstanceCollection(collectionId, event.context)) {
|
|
30
|
-
throw createError({
|
|
31
|
-
statusCode: 401,
|
|
32
|
-
statusMessage: `Can't get "instance/${collectionId}" document`
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
collectionRef = currentInstanceRef.collection(collectionId);
|
|
36
|
-
} else if (!readCollection(collectionId, event.context)) {
|
|
37
|
-
throw createError({
|
|
38
|
-
statusCode: 401,
|
|
39
|
-
statusMessage: `Can't get "${collectionId}" document`
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
const documentsRef = collectionRef.doc(documentId);
|
|
43
|
-
const documentSnapshot = await documentsRef.get();
|
|
44
|
-
return resolveServerDocumentRefs(event, documentSnapshot, collectionId);
|
|
45
|
-
} catch (err) {
|
|
46
|
-
if (isError(err)) {
|
|
47
|
-
apiLogger(event, "api:all:[collectionId]:[documentId]", err.message, err);
|
|
48
|
-
return setResponseStatus(event, err.statusCode || 500, err.statusMessage);
|
|
49
|
-
}
|
|
50
|
-
throw err;
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
instanceOnly: false
|
|
55
|
-
}
|
|
56
|
-
);
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { FieldPath } from "firebase-admin/firestore";
|
|
2
|
-
import { createError, getQuery, getRouterParam, isError, setResponseStatus } from "h3";
|
|
3
|
-
import { defineConditionallyCachedEventHandler } from "../utils/cache.js";
|
|
4
|
-
import { getBoolean } from "../utils/guards.js";
|
|
5
|
-
import { getDocumentId } from "../../client/utils/resolver.js";
|
|
6
|
-
import {
|
|
7
|
-
debugFirebaseServer,
|
|
8
|
-
getEdgesPage,
|
|
9
|
-
getOrderedQuery,
|
|
10
|
-
getQueryAsEdges
|
|
11
|
-
} from "../utils/firestore.js";
|
|
12
|
-
import { apiLogger, getServerFirebase } from "../utils/firebase.js";
|
|
13
|
-
import { readCollection, readInstanceCollection } from "#internal/firebase-nuxt";
|
|
14
|
-
export default defineConditionallyCachedEventHandler(
|
|
15
|
-
async (event) => {
|
|
16
|
-
const fieldDocument = FieldPath.documentId();
|
|
17
|
-
const { firebaseFirestore } = getServerFirebase("api:all:[collectionId]");
|
|
18
|
-
const { currentInstanceRef } = event.context;
|
|
19
|
-
try {
|
|
20
|
-
const params = getQuery(event);
|
|
21
|
-
const page = getBoolean(params.page);
|
|
22
|
-
const collectionId = getRouterParam(event, "collectionId");
|
|
23
|
-
debugFirebaseServer(event, "api:all:[collectionId]", collectionId);
|
|
24
|
-
if (!collectionId) {
|
|
25
|
-
throw createError({ statusCode: 400, statusMessage: `collectionId is required` });
|
|
26
|
-
}
|
|
27
|
-
let query = firebaseFirestore.collection(collectionId);
|
|
28
|
-
if (event.path.startsWith("/api/instance/all")) {
|
|
29
|
-
if (!currentInstanceRef) {
|
|
30
|
-
throw createError({ statusCode: 401, statusMessage: "Missing instance" });
|
|
31
|
-
} else if (!readInstanceCollection(collectionId, event.context)) {
|
|
32
|
-
throw createError({
|
|
33
|
-
statusCode: 401,
|
|
34
|
-
statusMessage: `Can't list "instance/${collectionId}"`
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
query = currentInstanceRef.collection(collectionId);
|
|
38
|
-
} else if (!readCollection(collectionId, event.context)) {
|
|
39
|
-
throw createError({
|
|
40
|
-
statusCode: 401,
|
|
41
|
-
statusMessage: `Can't list "${collectionId}"`
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
if (params.include) {
|
|
45
|
-
let include = Array.isArray(params.include) ? params.include : [params.include];
|
|
46
|
-
include = include.filter((uid) => uid && !getBoolean(uid)).map(getDocumentId);
|
|
47
|
-
debugFirebaseServer(event, "api:all:[collectionId]:filtered", include);
|
|
48
|
-
if (!include.length) return [];
|
|
49
|
-
query = query.orderBy(fieldDocument).where(fieldDocument, "in", include);
|
|
50
|
-
return getQueryAsEdges(event, query);
|
|
51
|
-
}
|
|
52
|
-
query = getOrderedQuery(event, query);
|
|
53
|
-
if (page) return getEdgesPage(event, query);
|
|
54
|
-
const first = Math.min(Number(params.first) || 10, 100);
|
|
55
|
-
return getQueryAsEdges(event, query.limit(first));
|
|
56
|
-
} catch (err) {
|
|
57
|
-
if (isError(err)) {
|
|
58
|
-
apiLogger(event, "api:all:[collectionId]", err.message, err);
|
|
59
|
-
return setResponseStatus(event, err.statusCode || 500, err.statusMessage);
|
|
60
|
-
}
|
|
61
|
-
throw err;
|
|
62
|
-
}
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
instanceOnly: false
|
|
66
|
-
}
|
|
67
|
-
);
|