@nano-app/plugins 0.4.4 → 0.6.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/build/crud/Query.js +18 -1
- package/build/crud/index.js +2 -2
- package/build/crud/routes/index.route.js +27 -59
- package/build/rate-limit/index.js +1 -1
- package/package.json +3 -3
package/build/crud/Query.js
CHANGED
|
@@ -1,8 +1,25 @@
|
|
|
1
1
|
// crud/Query.ts
|
|
2
2
|
/** Records a list answers when the request sends no `top` */
|
|
3
3
|
const DEFAULT_TOP = 100;
|
|
4
|
-
/**
|
|
4
|
+
/** Reads a model of the app's Prisma client with core's `QueryParams` */
|
|
5
5
|
var Query = class Query {
|
|
6
|
+
/** A list of the model with its total, or one record by its `where` */
|
|
7
|
+
static async read(oModel, oQuery, oWhere) {
|
|
8
|
+
const oArgs = Query.toPrisma(oQuery);
|
|
9
|
+
if (oWhere) {
|
|
10
|
+
const { select, include } = oArgs;
|
|
11
|
+
return { result: await oModel.findUniqueOrThrow({
|
|
12
|
+
where: oWhere,
|
|
13
|
+
select,
|
|
14
|
+
include
|
|
15
|
+
}) };
|
|
16
|
+
}
|
|
17
|
+
const [aRecords, iCount] = await Promise.all([oModel.findMany(oArgs), oModel.count({ where: oArgs.where })]);
|
|
18
|
+
return {
|
|
19
|
+
result: aRecords,
|
|
20
|
+
count: iCount
|
|
21
|
+
};
|
|
22
|
+
}
|
|
6
23
|
/** `filter` → `where`, `orderby` → `orderBy`, `top`/`skip` → `take`/`skip`, `select` and `expand` → `select` or `include` */
|
|
7
24
|
static toPrisma(oQuery) {
|
|
8
25
|
const { filter, orderby, top, skip, select, expand } = oQuery;
|
package/build/crud/index.js
CHANGED
|
@@ -7,7 +7,7 @@ var crud_default = createPlugin((options) => ({
|
|
|
7
7
|
name: "crud",
|
|
8
8
|
basePath: options?.basePath ?? "/api",
|
|
9
9
|
stage: "after",
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
routesDir: resolve(dirname(fileURLToPath(import.meta.url)), "routes"),
|
|
11
|
+
options
|
|
12
12
|
}));
|
|
13
13
|
export { crud_default as default };
|
|
@@ -14,67 +14,35 @@ const ID_TYPES = {
|
|
|
14
14
|
Int: Number,
|
|
15
15
|
BigInt
|
|
16
16
|
};
|
|
17
|
-
/** The Prisma delegate of the URL's model: 404 when the app does not publish it, 403 without its permission */
|
|
18
|
-
async function delegate(oReq, oParams) {
|
|
19
|
-
const sModel = String(oReq.params.model);
|
|
20
|
-
if (!oParams.models.includes(sModel)) throw {
|
|
21
|
-
status: 404,
|
|
22
|
-
message: "Not found"
|
|
23
|
-
};
|
|
24
|
-
if (!await isGranted(oParams, { [sModel]: [ACTIONS[oReq.method]] })) throw {
|
|
25
|
-
status: 403,
|
|
26
|
-
message: "Forbidden"
|
|
27
|
-
};
|
|
28
|
-
return oParams.db[sModel];
|
|
29
|
-
}
|
|
30
|
-
/** The `where` of the URL's id, converted to the type of the model's id */
|
|
31
|
-
function where(oReq, oModel) {
|
|
32
|
-
const sId = String(oReq.params.id);
|
|
33
|
-
return { id: ID_TYPES[oModel.fields.id.typeName]?.(sId) ?? sId };
|
|
34
|
-
}
|
|
35
|
-
/** A list of the model with its total, or one record by its id */
|
|
36
|
-
async function read(oReq, oParams) {
|
|
37
|
-
const { id } = oReq.params;
|
|
38
|
-
const oModel = await delegate(oReq, oParams);
|
|
39
|
-
const oArgs = Query.toPrisma(oReq.body ?? {});
|
|
40
|
-
if (id) {
|
|
41
|
-
const { select, include } = oArgs;
|
|
42
|
-
return { result: await oModel.findUniqueOrThrow({
|
|
43
|
-
where: where(oReq, oModel),
|
|
44
|
-
select,
|
|
45
|
-
include
|
|
46
|
-
}) };
|
|
47
|
-
}
|
|
48
|
-
const [aRecords, iCount] = await Promise.all([oModel.findMany(oArgs), oModel.count({ where: oArgs.where })]);
|
|
49
|
-
return {
|
|
50
|
-
result: aRecords,
|
|
51
|
-
count: iCount
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
/** Creates a record with the body as its data */
|
|
55
|
-
async function create(oReq, oParams) {
|
|
56
|
-
return { result: await (await delegate(oReq, oParams)).create({ data: oReq.body }) };
|
|
57
|
-
}
|
|
58
|
-
/** Updates only the fields of the body */
|
|
59
|
-
async function update(oReq, oParams) {
|
|
60
|
-
const oModel = await delegate(oReq, oParams);
|
|
61
|
-
return { result: await oModel.update({
|
|
62
|
-
where: where(oReq, oModel),
|
|
63
|
-
data: oReq.body
|
|
64
|
-
}) };
|
|
65
|
-
}
|
|
66
|
-
/** Deletes a record and answers it */
|
|
67
|
-
async function remove(oReq, oParams) {
|
|
68
|
-
const oModel = await delegate(oReq, oParams);
|
|
69
|
-
return { result: await oModel.delete({ where: where(oReq, oModel) }) };
|
|
70
|
-
}
|
|
71
17
|
/** `GET` reads without parameters, `QUERY` with `QueryParams` as its body */
|
|
72
18
|
var index_route_default = createRoute({
|
|
73
19
|
expression: "/:model{/:id}",
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
20
|
+
callbacks: { onBefore: async (oReq, sMethod, oParams) => {
|
|
21
|
+
const sModel = String(oReq.params.model);
|
|
22
|
+
const { id } = oReq.params;
|
|
23
|
+
if (!oParams.models.includes(sModel)) throw {
|
|
24
|
+
status: 404,
|
|
25
|
+
message: "Not found"
|
|
26
|
+
};
|
|
27
|
+
if (!await isGranted(oParams, { [sModel]: [ACTIONS[sMethod]] })) throw {
|
|
28
|
+
status: 403,
|
|
29
|
+
message: "Forbidden"
|
|
30
|
+
};
|
|
31
|
+
const oModel = oParams.db[sModel];
|
|
32
|
+
if (!id) return { model: oModel };
|
|
33
|
+
const sId = String(id);
|
|
34
|
+
return {
|
|
35
|
+
model: oModel,
|
|
36
|
+
where: { id: ID_TYPES[oModel.fields.id.typeName]?.(sId) ?? sId }
|
|
37
|
+
};
|
|
38
|
+
} },
|
|
39
|
+
GET: async (oReq, { onBeforeResult }) => Query.read(onBeforeResult?.model, oReq.body ?? {}, onBeforeResult?.where),
|
|
40
|
+
QUERY: async (oReq, { onBeforeResult }) => Query.read(onBeforeResult?.model, oReq.body ?? {}, onBeforeResult?.where),
|
|
41
|
+
POST: async (oReq, { onBeforeResult }) => ({ result: await onBeforeResult?.model.create({ data: oReq.body }) }),
|
|
42
|
+
PUT: async (oReq, { onBeforeResult }) => ({ result: await onBeforeResult?.model.update({
|
|
43
|
+
where: onBeforeResult.where,
|
|
44
|
+
data: oReq.body
|
|
45
|
+
}) }),
|
|
46
|
+
DELETE: async (_oReq, { onBeforeResult }) => ({ result: await onBeforeResult?.model.delete({ where: onBeforeResult.where }) })
|
|
79
47
|
});
|
|
80
48
|
export { index_route_default as default };
|
|
@@ -8,8 +8,8 @@ var rate_limit_default = createPlugin((options) => {
|
|
|
8
8
|
const { capacity = 100, refillPerSecond = 1, message = "Too many requests, please try again later." } = options ?? {};
|
|
9
9
|
return {
|
|
10
10
|
name: "rate-limit",
|
|
11
|
-
routesDir: "",
|
|
12
11
|
stage: "before",
|
|
12
|
+
routesDir: "",
|
|
13
13
|
callbacks: { onMount: async (oApp) => {
|
|
14
14
|
const fnRefill = (oBucket, iNow) => Math.min(capacity, oBucket.iTokens + (iNow - oBucket.iTime) / 1e3 * refillPerSecond);
|
|
15
15
|
const oBuckets = /* @__PURE__ */ new Map();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nano-app/plugins",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Official plugins for @nano-app/backend",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"node": "^22.23.4 || ^24.22.1 || >=26.12.1"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
|
-
"@nano-app/backend": ">=0.
|
|
40
|
+
"@nano-app/backend": ">=0.12.5"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@happy-dom/global-registrator": "^21.0.4",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"next": "^16.4.3",
|
|
51
51
|
"pg": "^8.23.1",
|
|
52
52
|
"prisma": "^7.10.1",
|
|
53
|
-
"tsdown": "^0.23.
|
|
53
|
+
"tsdown": "^0.23.5",
|
|
54
54
|
"tsx": "^4.23.15",
|
|
55
55
|
"typescript": "^7.0.2"
|
|
56
56
|
}
|