@aeriajs/builtins 0.0.276 → 0.0.278

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.
Files changed (53) hide show
  1. package/dist/authentication.js +6 -11
  2. package/dist/collections/file/description.js +10 -14
  3. package/dist/collections/file/download.js +21 -25
  4. package/dist/collections/file/index.js +15 -18
  5. package/dist/collections/file/insert.js +8 -12
  6. package/dist/collections/file/remove.js +7 -11
  7. package/dist/collections/file/removeAll.js +5 -9
  8. package/dist/collections/index.js +4 -20
  9. package/dist/collections/log/index.js +5 -8
  10. package/dist/collections/resourceUsage/index.js +2 -5
  11. package/dist/collections/user/activate.js +31 -35
  12. package/dist/collections/user/authenticate.js +29 -33
  13. package/dist/collections/user/createAccount.js +25 -29
  14. package/dist/collections/user/description.js +5 -8
  15. package/dist/collections/user/editProfile.js +12 -16
  16. package/dist/collections/user/getActivationLink.js +21 -26
  17. package/dist/collections/user/getCurrentUser.js +12 -16
  18. package/dist/collections/user/getInfo.js +22 -26
  19. package/dist/collections/user/getRedefinePasswordLink.js +15 -19
  20. package/dist/collections/user/index.d.ts +10 -10
  21. package/dist/collections/user/index.js +39 -42
  22. package/dist/collections/user/insert.js +16 -20
  23. package/dist/collections/user/redefinePassword.js +31 -35
  24. package/dist/functions/describe.js +21 -25
  25. package/dist/functions/index.js +1 -17
  26. package/dist/index.d.ts +15 -15
  27. package/dist/index.js +11 -29
  28. package/package.json +11 -17
  29. package/dist/authentication.mjs +0 -58
  30. package/dist/collections/file/description.mjs +0 -75
  31. package/dist/collections/file/download.mjs +0 -115
  32. package/dist/collections/file/index.mjs +0 -59
  33. package/dist/collections/file/insert.mjs +0 -44
  34. package/dist/collections/file/remove.mjs +0 -21
  35. package/dist/collections/file/removeAll.mjs +0 -22
  36. package/dist/collections/index.mjs +0 -5
  37. package/dist/collections/log/index.mjs +0 -55
  38. package/dist/collections/resourceUsage/index.mjs +0 -39
  39. package/dist/collections/user/activate.mjs +0 -119
  40. package/dist/collections/user/authenticate.mjs +0 -165
  41. package/dist/collections/user/createAccount.mjs +0 -93
  42. package/dist/collections/user/description.mjs +0 -149
  43. package/dist/collections/user/editProfile.mjs +0 -52
  44. package/dist/collections/user/getActivationLink.mjs +0 -88
  45. package/dist/collections/user/getCurrentUser.mjs +0 -57
  46. package/dist/collections/user/getInfo.mjs +0 -85
  47. package/dist/collections/user/getRedefinePasswordLink.mjs +0 -63
  48. package/dist/collections/user/index.mjs +0 -71
  49. package/dist/collections/user/insert.mjs +0 -70
  50. package/dist/collections/user/redefinePassword.mjs +0 -110
  51. package/dist/functions/describe.mjs +0 -95
  52. package/dist/functions/index.mjs +0 -2
  53. package/dist/index.mjs +0 -21
@@ -1,58 +0,0 @@
1
- "use strict";
2
- import { signToken } from "@aeriajs/core";
3
- export const AuthenticationError = {
4
- InvalidCredentials: "INVALID_CREDENTIALS",
5
- InactiveUser: "INACTIVE_USER"
6
- };
7
- export const successfulAuthentication = async (user, context) => {
8
- const tokenContent = {
9
- sub: user._id,
10
- roles: user.roles,
11
- picture: user.picture,
12
- userinfo: {}
13
- };
14
- if (context.config.security.authenticationRateLimiting) {
15
- }
16
- if (context.config.security.logSuccessfulAuthentications) {
17
- await context.log("successful authentication", {
18
- email: user.email,
19
- roles: user.roles,
20
- _id: user._id
21
- });
22
- }
23
- if (context.config.tokenUserProperties) {
24
- const userinfo = {};
25
- for (const prop of context.config.tokenUserProperties) {
26
- userinfo[prop] = user[prop];
27
- }
28
- tokenContent.userinfo = userinfo;
29
- }
30
- const token = await signToken(tokenContent);
31
- return {
32
- user,
33
- token: {
34
- type: "bearer",
35
- content: token
36
- }
37
- };
38
- };
39
- export const defaultSuccessfulAuthentication = async () => {
40
- const token = await signToken({
41
- sub: null,
42
- roles: ["root"],
43
- userinfo: {}
44
- });
45
- return {
46
- user: {
47
- _id: null,
48
- name: "God Mode",
49
- email: "",
50
- roles: ["root"],
51
- active: true
52
- },
53
- token: {
54
- type: "bearer",
55
- content: token
56
- }
57
- };
58
- };
@@ -1,75 +0,0 @@
1
- "use strict";
2
- import { ObjectId } from "mongodb";
3
- import { defineDescription } from "@aeriajs/core";
4
- import { getConfig } from "@aeriajs/entrypoint";
5
- const timestamp = (lastModified) => lastModified instanceof Date ? new Date(lastModified).getTime() : "fresh";
6
- export const getFileLink = async (fileId) => {
7
- const config = await getConfig();
8
- return `${config.publicUrl || ""}/file/${fileId}`;
9
- };
10
- export const description = defineDescription({
11
- $id: "file",
12
- icon: "paperclip",
13
- owned: "always",
14
- presets: ["owned"],
15
- indexes: [
16
- "name",
17
- "link",
18
- "type",
19
- "size"
20
- ],
21
- properties: {
22
- type: {
23
- type: "string"
24
- },
25
- size: {
26
- type: "number"
27
- },
28
- last_modified: {
29
- type: "string",
30
- format: "date-time"
31
- },
32
- name: {
33
- type: "string"
34
- },
35
- absolute_path: {
36
- type: "string"
37
- },
38
- relative_path: {
39
- type: "string"
40
- },
41
- immutable: {
42
- type: "boolean"
43
- },
44
- link: {
45
- type: "getter",
46
- getter: async (doc) => {
47
- if ("_id" in doc && "last_modified" in doc && doc._id instanceof ObjectId) {
48
- return `${await getFileLink(doc._id)}/${timestamp(doc.last_modified)}`;
49
- }
50
- }
51
- },
52
- download_link: {
53
- type: "getter",
54
- getter: async (doc) => {
55
- if ("_id" in doc && "last_modified" in doc && doc._id instanceof ObjectId) {
56
- return `${await getFileLink(doc._id)}/download/${timestamp(doc.last_modified)}`;
57
- }
58
- }
59
- }
60
- },
61
- actions: {
62
- deleteAll: {
63
- label: "Remover",
64
- ask: true,
65
- selection: true
66
- }
67
- },
68
- individualActions: {
69
- remove: {
70
- label: "Remover",
71
- icon: "trash",
72
- ask: true
73
- }
74
- }
75
- });
@@ -1,115 +0,0 @@
1
- "use strict";
2
- import { HTTPStatus, ACError, defineContract, endpointErrorSchema } from "@aeriajs/types";
3
- import { ObjectId } from "@aeriajs/core";
4
- import * as fs from "node:fs";
5
- export const DownloadError = {
6
- RangeNotSatisfiable: "RANGE_NOT_SATISFIABLE"
7
- };
8
- export const downloadContract = defineContract({
9
- payload: {
10
- type: "object",
11
- required: ["fileId"],
12
- properties: {
13
- fileId: {
14
- type: "string"
15
- },
16
- options: {
17
- type: "array",
18
- items: {
19
- enum: [
20
- "picture",
21
- "download"
22
- ]
23
- }
24
- },
25
- noHeaders: {
26
- type: "boolean"
27
- }
28
- }
29
- },
30
- response: [
31
- endpointErrorSchema({
32
- httpStatus: [
33
- HTTPStatus.NotFound,
34
- HTTPStatus.RangeNotSatisfiable
35
- ],
36
- code: [
37
- ACError.ResourceNotFound,
38
- DownloadError.RangeNotSatisfiable
39
- ]
40
- }),
41
- {
42
- type: "object",
43
- additionalProperties: true
44
- }
45
- ]
46
- });
47
- export const download = async (payload, context) => {
48
- const { fileId, options = [] } = payload;
49
- const file = await context.collection.model.findOne({
50
- _id: new ObjectId(fileId)
51
- }, {
52
- projection: {
53
- absolute_path: 1,
54
- name: 1,
55
- type: 1
56
- }
57
- });
58
- if (!file) {
59
- if (!payload.noHeaders) {
60
- context.response.writeHead(HTTPStatus.NotFound, {
61
- "content-type": "application/json"
62
- });
63
- }
64
- return context.error(HTTPStatus.NotFound, {
65
- code: ACError.ResourceNotFound
66
- });
67
- }
68
- let stat;
69
- try {
70
- stat = await fs.promises.stat(file.absolute_path);
71
- } catch (e) {
72
- context.response.writeHead(404, {
73
- "content-type": "application/json"
74
- });
75
- return context.error(HTTPStatus.NotFound, {
76
- code: ACError.ResourceNotFound
77
- });
78
- }
79
- const range = context.request.headers.range;
80
- if (typeof range === "string") {
81
- const parts = range.replace(/bytes=/, "").split("-");
82
- const start = parseInt(parts[0]);
83
- const end = parts[1] ? parseInt(parts[1]) : stat.size - 1;
84
- if (start >= stat.size || end >= stat.size) {
85
- context.response.writeHead(HTTPStatus.RangeNotSatisfiable, {
86
- "content-type": "application/json",
87
- "content-range": `bytes */${stat.size}`
88
- });
89
- return context.error(HTTPStatus.RangeNotSatisfiable, {
90
- code: DownloadError.RangeNotSatisfiable
91
- });
92
- }
93
- const chunkSize = end - start + 1;
94
- if (!payload.noHeaders) {
95
- context.response.writeHead(206, {
96
- "accept-ranges": "bytes",
97
- "content-range": `bytes ${start}-${end}/${stat.size}`,
98
- "content-length": chunkSize,
99
- "content-type": file.type,
100
- "content-disposition": `${options.includes("download") ? "attachment; " : ""}name=${encodeURI(file.name)}`
101
- });
102
- }
103
- return fs.createReadStream(file.absolute_path, {
104
- start,
105
- end
106
- });
107
- }
108
- if (!payload.noHeaders) {
109
- context.response.writeHead(HTTPStatus.Ok, {
110
- "content-type": file.type,
111
- "content-disposition": `${options.includes("download") ? "attachment; " : ""}name=${encodeURI(file.name)}`
112
- });
113
- }
114
- return fs.createReadStream(file.absolute_path);
115
- };
@@ -1,59 +0,0 @@
1
- "use strict";
2
- import { defineCollection, get } from "@aeriajs/core";
3
- import { description } from "./description.mjs";
4
- import { insert } from "./insert.mjs";
5
- import { download, downloadContract } from "./download.mjs";
6
- import { remove } from "./remove.mjs";
7
- import { removeAll } from "./removeAll.mjs";
8
- export const tempFile = defineCollection({
9
- description: {
10
- $id: "tempFile",
11
- icon: "file",
12
- hidden: true,
13
- temporary: {
14
- index: "created_at",
15
- expireAfterSeconds: 3600
16
- },
17
- properties: {
18
- created_at: {
19
- type: "string",
20
- format: "date-time"
21
- },
22
- absolute_path: {
23
- type: "string"
24
- },
25
- size: {
26
- type: "number"
27
- },
28
- mime: {
29
- type: "number"
30
- },
31
- collection: {
32
- type: "string"
33
- },
34
- filename: {
35
- type: "string"
36
- }
37
- }
38
- }
39
- });
40
- export const file = defineCollection({
41
- description,
42
- functions: {
43
- get,
44
- insert,
45
- download,
46
- remove,
47
- removeAll
48
- },
49
- exposedFunctions: {
50
- get: "unauthenticated",
51
- insert: true,
52
- download: "unauthenticated",
53
- remove: true,
54
- removeAll: true
55
- },
56
- contracts: {
57
- download: downloadContract
58
- }
59
- });
@@ -1,44 +0,0 @@
1
- "use strict";
2
- import { createHash } from "node:crypto";
3
- import { writeFile, unlink } from "node:fs/promises";
4
- import { insert as originalInsert } from "@aeriajs/core";
5
- export const insert = async (payload, context) => {
6
- if (!context.token.authenticated) {
7
- throw new Error("");
8
- }
9
- const { content, ...what } = Object.assign({}, payload.what);
10
- if (context.token.sub) {
11
- what.owner = context.token.sub;
12
- }
13
- const extension = what.name.split(".").at(-1);
14
- if (!context.config.storage) {
15
- throw new Error("config.storage is not set");
16
- }
17
- const tempPath = context.config.storage.tempFs || context.config.storage.fs;
18
- if (!tempPath) {
19
- throw new Error("config.storage.fs and config.storage.tempFs are not set");
20
- }
21
- if (!extension) {
22
- throw new Error("filename lacks extension");
23
- }
24
- const oldFile = await context.collection.model.findOne(
25
- {
26
- _id: payload.what._id
27
- },
28
- {
29
- projection: {
30
- absolute_path: 1
31
- }
32
- }
33
- );
34
- if (oldFile && oldFile.absolute_path) {
35
- await unlink(oldFile.absolute_path).catch(console.trace);
36
- }
37
- const filenameHash = createHash("sha1").update(what.name + Date.now()).digest("hex");
38
- what.absolute_path = `${tempPath}/${filenameHash}.${extension}`;
39
- await writeFile(what.absolute_path, Buffer.from(content.split(",").at(-1), "base64"));
40
- return originalInsert({
41
- ...payload,
42
- what
43
- }, context);
44
- };
@@ -1,21 +0,0 @@
1
- "use strict";
2
- import { Result } from "@aeriajs/types";
3
- import { remove as originalRemove, get } from "@aeriajs/core";
4
- import * as fs from "node:fs/promises";
5
- export const remove = async (payload, context) => {
6
- const { error, result: file } = await get({
7
- filters: {
8
- _id: payload.filters._id
9
- },
10
- project: ["absolute_path"]
11
- }, context);
12
- if (error) {
13
- return Result.error(error);
14
- }
15
- try {
16
- await fs.unlink(file.absolute_path);
17
- } catch (err) {
18
- console.trace(err);
19
- }
20
- return originalRemove(payload, context);
21
- };
@@ -1,22 +0,0 @@
1
- "use strict";
2
- import { ObjectId, removeAll as originalRemoveAll } from "@aeriajs/core";
3
- import * as fs from "node:fs/promises";
4
- export const removeAll = async (payload, context) => {
5
- const files = context.collection.model.find({
6
- _id: {
7
- $in: payload.filters.map((oid) => new ObjectId(oid))
8
- }
9
- }, {
10
- projection: {
11
- absolute_path: 1
12
- }
13
- });
14
- for await (const file of files) {
15
- try {
16
- await fs.unlink(file.absolute_path);
17
- } catch (err) {
18
- console.trace(err);
19
- }
20
- }
21
- return originalRemoveAll(payload, context);
22
- };
@@ -1,5 +0,0 @@
1
- "use strict";
2
- export * from "./file/index.mjs";
3
- export * from "./log/index.mjs";
4
- export * from "./resourceUsage/index.mjs";
5
- export * from "./user/index.mjs";
@@ -1,55 +0,0 @@
1
- "use strict";
2
- import { defineCollection, get, getAll, insert } from "@aeriajs/core";
3
- export const log = defineCollection({
4
- description: {
5
- $id: "log",
6
- icon: "magnifying-glass",
7
- required: [
8
- "context",
9
- "message"
10
- ],
11
- table: [
12
- "owner",
13
- "context",
14
- "message",
15
- "created_at"
16
- ],
17
- properties: {
18
- owner: {
19
- // don't use "owned: true", we want it this way
20
- $ref: "user",
21
- noForm: true
22
- },
23
- context: {
24
- type: "string"
25
- },
26
- message: {
27
- type: "string"
28
- },
29
- details: {
30
- type: "object",
31
- additionalProperties: true
32
- },
33
- created_at: {
34
- type: "string",
35
- format: "date-time"
36
- }
37
- },
38
- presets: ["view"],
39
- filters: [
40
- "context",
41
- "message",
42
- "owner"
43
- ]
44
- },
45
- functions: {
46
- get,
47
- getAll,
48
- insert
49
- },
50
- exposedFunctions: {
51
- get: true,
52
- getAll: true,
53
- insert: true
54
- }
55
- });
@@ -1,39 +0,0 @@
1
- "use strict";
2
- import { defineCollection } from "@aeriajs/core";
3
- export const resourceUsage = defineCollection({
4
- description: {
5
- $id: "resourceUsage",
6
- icon: "wrench",
7
- required: ["usage"],
8
- properties: {
9
- user: {
10
- $ref: "user"
11
- },
12
- address: {
13
- type: "string"
14
- },
15
- usage: {
16
- type: "object",
17
- additionalProperties: {
18
- type: "object",
19
- properties: {
20
- hits: {
21
- type: "integer"
22
- },
23
- points: {
24
- type: "integer"
25
- },
26
- last_reach: {
27
- type: "string",
28
- format: "date-time"
29
- },
30
- last_maximum_reach: {
31
- type: "string",
32
- format: "date-time"
33
- }
34
- }
35
- }
36
- }
37
- }
38
- }
39
- });
@@ -1,119 +0,0 @@
1
- "use strict";
2
- import { decodeToken, ObjectId } from "@aeriajs/core";
3
- import { Result, ACError, HTTPStatus, defineContract, resultSchema, endpointErrorSchema } from "@aeriajs/types";
4
- import * as bcrypt from "bcryptjs";
5
- export const ActivationError = {
6
- UserNotFound: "USER_NOT_FOUND",
7
- AlreadyActiveUser: "ALREADY_ACTIVE_USER",
8
- InvalidLink: "INVALID_LINK",
9
- InvalidToken: "INVALID_TOKEN"
10
- };
11
- export const activateContract = defineContract({
12
- payload: {
13
- type: "object",
14
- required: [],
15
- properties: {
16
- password: {
17
- type: "string"
18
- },
19
- userId: {
20
- type: "string"
21
- },
22
- token: {
23
- type: "string"
24
- }
25
- }
26
- },
27
- response: [
28
- endpointErrorSchema({
29
- httpStatus: [
30
- HTTPStatus.NotFound,
31
- HTTPStatus.Forbidden,
32
- HTTPStatus.Unauthorized,
33
- HTTPStatus.UnprocessableContent
34
- ],
35
- code: [
36
- ACError.ResourceNotFound,
37
- ACError.MalformedInput,
38
- ActivationError.AlreadyActiveUser,
39
- ActivationError.InvalidLink,
40
- ActivationError.InvalidToken,
41
- ActivationError.UserNotFound
42
- ]
43
- }),
44
- resultSchema({
45
- type: "object",
46
- properties: {
47
- userId: {
48
- type: "string",
49
- format: "objectid"
50
- }
51
- }
52
- })
53
- ]
54
- });
55
- export const activate = async (payload, context) => {
56
- const {
57
- userId,
58
- token,
59
- password
60
- } = payload;
61
- if (!context.config.secret) {
62
- throw new Error("config.secret is not set");
63
- }
64
- if (!userId || !token) {
65
- return context.error(HTTPStatus.NotFound, {
66
- code: ActivationError.InvalidLink
67
- });
68
- }
69
- const user = await context.collection.model.findOne({
70
- _id: new ObjectId(userId)
71
- }, {
72
- projection: {
73
- password: 1,
74
- active: 1
75
- }
76
- });
77
- if (!user) {
78
- return context.error(HTTPStatus.NotFound, {
79
- code: ActivationError.UserNotFound
80
- });
81
- }
82
- if (user.active) {
83
- return context.error(HTTPStatus.Forbidden, {
84
- code: ActivationError.AlreadyActiveUser
85
- });
86
- }
87
- const decoded = await decodeToken(token, context.config.secret);
88
- if (!decoded) {
89
- return context.error(HTTPStatus.Unauthorized, {
90
- code: ActivationError.InvalidToken
91
- });
92
- }
93
- if (!user.password) {
94
- if (!password) {
95
- return context.error(HTTPStatus.UnprocessableContent, {
96
- code: ACError.MalformedInput
97
- });
98
- }
99
- await context.collection.model.updateOne({
100
- _id: user._id
101
- }, {
102
- $set: {
103
- active: true,
104
- password: await bcrypt.hash(password, 10)
105
- }
106
- });
107
- } else {
108
- await context.collection.model.updateOne({
109
- _id: user._id
110
- }, {
111
- $set: {
112
- active: true
113
- }
114
- });
115
- }
116
- return Result.result({
117
- userId: user._id
118
- });
119
- };