primate 0.5.1 → 0.6.1
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 +21 -36
- package/debris.json +1 -2
- package/package.json +7 -10
- package/source/{server/App.js → App.js} +14 -19
- package/source/Bundler.js +43 -0
- package/source/{server/Directory.js → Directory.js} +0 -0
- package/source/{server/EagerPromise.js → EagerPromise.js} +0 -0
- package/source/{server/File.js → File.js} +0 -0
- package/source/Router.js +28 -0
- package/source/Server.js +103 -0
- package/source/Session.js +26 -0
- package/source/{server/attributes.js → attributes.js} +0 -0
- package/source/{server/cache.js → cache.js} +0 -0
- package/source/{server/conf.js → conf.js} +1 -1
- package/source/{server/crypto.js → crypto.js} +0 -0
- package/source/{server/domain → domain}/Domain.js +8 -10
- package/source/{server/domain → domain}/Field.js +0 -0
- package/source/{server/domain → domain}/Predicate.js +0 -0
- package/source/{server/domain → domain}/domains.js +0 -0
- package/source/{server/errors → errors}/InternalServer.js +0 -0
- package/source/{server/errors → errors}/Predicate.js +0 -0
- package/source/{server/errors.js → errors.js} +0 -0
- package/source/{server/exports.js → exports.js} +4 -2
- package/source/{server/extend_object.js → extend_object.js} +0 -0
- package/source/handlers/DOM/Node.js +184 -0
- package/source/{server/view → handlers/DOM}/Parser.js +22 -18
- package/source/handlers/html.js +27 -0
- package/source/handlers/http.js +6 -0
- package/source/handlers/redirect.js +10 -0
- package/source/{server/servers/http-codes.json → http-codes.json} +0 -0
- package/source/{server/invariants.js → invariants.js} +0 -0
- package/source/{server/log.js → log.js} +0 -0
- package/source/{server/servers/mimes.json → mimes.json} +0 -0
- package/source/preset/primate.json +12 -4
- package/source/preset/static/index.html +0 -2
- package/source/preset/stores/default.js +2 -0
- package/source/{server/sanitize.js → sanitize.js} +0 -0
- package/source/{server/store → store}/Memory.js +0 -0
- package/source/{server/store → store}/Store.js +1 -1
- package/source/{server/types → types}/Array.js +0 -0
- package/source/{server/types → types}/Boolean.js +0 -0
- package/source/{server/types → types}/Date.js +0 -0
- package/source/{server/types → types}/Domain.js +0 -0
- package/source/{server/types → types}/Instance.js +0 -0
- package/source/{server/types → types}/Number.js +0 -0
- package/source/{server/types → types}/Object.js +0 -0
- package/source/{server/types → types}/Primitive.js +0 -0
- package/source/{server/types → types}/Storeable.js +0 -0
- package/source/{server/types → types}/String.js +0 -0
- package/source/{server/types → types}/errors/Array.json +0 -0
- package/source/{server/types → types}/errors/Boolean.json +0 -0
- package/source/{server/types → types}/errors/Date.json +0 -0
- package/source/{server/types → types}/errors/Number.json +0 -0
- package/source/{server/types → types}/errors/Object.json +0 -0
- package/source/{server/types → types}/errors/String.json +0 -0
- package/source/{server/types.js → types.js} +0 -0
- package/source/client/Action.js +0 -157
- package/source/client/App.js +0 -16
- package/source/client/Client.js +0 -61
- package/source/client/Context.js +0 -47
- package/source/client/Element.js +0 -249
- package/source/client/Node.js +0 -13
- package/source/client/Session.js +0 -27
- package/source/client/View.js +0 -89
- package/source/client/document.js +0 -6
- package/source/client/exports.js +0 -15
- package/source/preset/client/Element.js +0 -2
- package/source/preset/client/app.js +0 -2
- package/source/preset/data/stores/default.js +0 -2
- package/source/server/Action.js +0 -100
- package/source/server/Bundler.js +0 -177
- package/source/server/Context.js +0 -97
- package/source/server/Projector.js +0 -86
- package/source/server/Router.js +0 -52
- package/source/server/Session.js +0 -45
- package/source/server/servers/Dynamic.js +0 -57
- package/source/server/servers/Server.js +0 -5
- package/source/server/servers/Static.js +0 -118
- package/source/server/servers/content-security-policy.json +0 -7
- package/source/server/view/TreeNode.js +0 -197
- package/source/server/view/View.js +0 -35
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# Primate
|
|
1
|
+
# Primate, A JavaScript Framework
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
A full-stack Javascript framework, Primate relieves you of dealing with
|
|
4
|
+
repetitive, error-prone tasks and lets you concentrate on writing effective,
|
|
5
|
+
expressive code.
|
|
6
6
|
|
|
7
7
|
## Installing
|
|
8
8
|
|
|
@@ -10,45 +10,30 @@ concentrate on writing effective, expressive code.
|
|
|
10
10
|
npm install primate
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
##
|
|
14
|
-
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
|
|
25
|
-
* **Sane defaults** minimally opinionated with good, overrideable defaults
|
|
26
|
-
for most features
|
|
27
|
-
* **Data linking** modeling `1:1`, `1:n` and `n:m` relationships on domains via
|
|
28
|
-
cacheable ad-hoc getters
|
|
13
|
+
## Highlights
|
|
14
|
+
|
|
15
|
+
* Flexible HTTP routing, returning HTML, JSON or a custom handler
|
|
16
|
+
* Secure by default with HTTPS, hash-verified scripts and a strong CSP
|
|
17
|
+
* Built-in support for sessions with secure cookies
|
|
18
|
+
* Input verification using data domains
|
|
19
|
+
* Many different data store modules: In-Memory (built-in),
|
|
20
|
+
[File][primate-store-file], [JSON][primate-store-json],
|
|
21
|
+
[MongoDB][primate-store-mongodb]
|
|
22
|
+
* Easy modelling of`1:1`, `1:n` and `n:m` relationships
|
|
23
|
+
* Minimally opinionated with sane, overrideable defaults
|
|
24
|
+
* No dependencies
|
|
29
25
|
|
|
30
26
|
## Getting started
|
|
31
27
|
|
|
32
28
|
See the [getting started][getting-started] guide.
|
|
33
29
|
|
|
34
|
-
## Resources
|
|
35
|
-
|
|
36
|
-
* [Source code][source-code]
|
|
37
|
-
* [Issues][issues]
|
|
38
|
-
|
|
39
|
-
A full guide is coming soon.
|
|
40
|
-
|
|
41
|
-
## Versioning
|
|
42
|
-
|
|
43
|
-
This software is still in its initial development phase and is not considered
|
|
44
|
-
stable or recommended for production. Once we release a stable version `1`, we
|
|
45
|
-
will move over to semantic versioning.
|
|
46
|
-
|
|
47
30
|
## License
|
|
48
31
|
|
|
49
32
|
BSD-3-Clause
|
|
50
33
|
|
|
51
|
-
[ws]: https://github.com/websockets/ws
|
|
52
34
|
[getting-started]: https://primatejs.com/getting-started
|
|
53
|
-
[source-code]: https://
|
|
54
|
-
[issues]: https://
|
|
35
|
+
[source-code]: https://github.com/primatejs/primate
|
|
36
|
+
[issues]: https://github.com/primatejs/primate/issues
|
|
37
|
+
[primate-store-file]: https://npmjs.com/primate-store-file
|
|
38
|
+
[primate-store-json]: https://npmjs.com/primate-store-json
|
|
39
|
+
[primate-store-mongodb]: https://npmjs.com/primate-store-mongodb
|
package/debris.json
CHANGED
package/package.json
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "primate",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"author": "Primate core team <core@primatejs.com>",
|
|
5
5
|
"homepage": "https://primatejs.com",
|
|
6
|
-
"bugs": "https://
|
|
7
|
-
"repository": "https://
|
|
6
|
+
"bugs": "https://github.com/primatejs/primate/issues",
|
|
7
|
+
"repository": "https://github.com/primatejs/primate",
|
|
8
8
|
"description": "Server-client framework",
|
|
9
9
|
"license": "BSD-3-Clause",
|
|
10
|
-
"dependencies": {
|
|
11
|
-
"ws": "^8.5.0"
|
|
12
|
-
},
|
|
13
10
|
"scripts": {
|
|
14
11
|
"copy": "rm -rf output && mkdir output && cp source/* output -a",
|
|
15
12
|
"instrument": "nyc instrument source ./output",
|
|
@@ -18,14 +15,14 @@
|
|
|
18
15
|
"test": "npm run copy && npm run debris"
|
|
19
16
|
},
|
|
20
17
|
"devDependencies": {
|
|
21
|
-
"debris": "^0.2.
|
|
22
|
-
"eslint": "^8.
|
|
18
|
+
"debris": "^0.2.2",
|
|
19
|
+
"eslint": "^8.13.0",
|
|
23
20
|
"eslint-plugin-json": "^3.1.0",
|
|
24
21
|
"nyc": "^15.1.0"
|
|
25
22
|
},
|
|
26
23
|
"type": "module",
|
|
27
|
-
"exports": "./source/
|
|
24
|
+
"exports": "./source/exports.js",
|
|
28
25
|
"engines": {
|
|
29
|
-
"node": ">=17.
|
|
26
|
+
"node": ">=17.9.0"
|
|
30
27
|
}
|
|
31
28
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {resolve} from "path";
|
|
2
2
|
import Bundler from "./Bundler.js";
|
|
3
3
|
import File from "./File.js";
|
|
4
|
+
import Directory from "./Directory.js";
|
|
4
5
|
import Router from "./Router.js";
|
|
5
|
-
import
|
|
6
|
-
import StaticServer from "./servers/Static.js";
|
|
6
|
+
import Server from "./Server.js";
|
|
7
7
|
import cache from "./cache.js";
|
|
8
8
|
import log from "./log.js";
|
|
9
|
-
import package_json from "
|
|
9
|
+
import package_json from "../package.json" assert {"type": "json"};
|
|
10
10
|
|
|
11
11
|
export default class App {
|
|
12
12
|
constructor(conf) {
|
|
@@ -29,33 +29,28 @@ export default class App {
|
|
|
29
29
|
async run() {
|
|
30
30
|
log.reset("Primate").yellow(package_json.version);
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
|
|
32
|
+
const routes = await Directory.list(this.conf.paths.routes);
|
|
33
|
+
for (const route of routes) {
|
|
34
|
+
await import(`${this.conf.paths.routes}/${route}`);
|
|
35
|
+
}
|
|
36
|
+
const index = await new this.Bundler(this.conf).bundle();
|
|
35
37
|
|
|
36
|
-
const conf = {index,
|
|
38
|
+
const conf = {index, "router": Router,
|
|
37
39
|
"serve_from": this.conf.paths.public,
|
|
38
40
|
"http": {
|
|
41
|
+
...this.conf.http,
|
|
39
42
|
"key": File.read_sync(resolve(this.conf.http.ssl.key)),
|
|
40
43
|
"cert": File.read_sync(resolve(this.conf.http.ssl.cert)),
|
|
41
44
|
},
|
|
42
|
-
"context": this.conf.defaults.context,
|
|
43
45
|
};
|
|
44
|
-
this.
|
|
45
|
-
await this.
|
|
46
|
-
|
|
47
|
-
this.dynamic_server = new DynamicServer({router,
|
|
48
|
-
"path": this.conf.base,
|
|
49
|
-
"server": this.static_server.server,
|
|
50
|
-
"context": this.conf.defaults.context,
|
|
51
|
-
});
|
|
52
|
-
await this.dynamic_server.run();
|
|
46
|
+
this.server = new Server(conf);
|
|
47
|
+
await this.server.run();
|
|
53
48
|
|
|
54
49
|
const {port, host} = this.conf.http;
|
|
55
|
-
this.
|
|
50
|
+
this.server.listen(port, host);
|
|
56
51
|
}
|
|
57
52
|
|
|
58
53
|
stop() {
|
|
59
|
-
this.
|
|
54
|
+
this.server.close();
|
|
60
55
|
}
|
|
61
56
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {dirname} from "path";
|
|
2
|
+
import {fileURLToPath} from "url";
|
|
3
|
+
import File from "./File.js";
|
|
4
|
+
|
|
5
|
+
const meta_url = fileURLToPath(import.meta.url);
|
|
6
|
+
const directory = dirname(meta_url);
|
|
7
|
+
const preset = `${directory}/preset`;
|
|
8
|
+
|
|
9
|
+
export default class Bundler {
|
|
10
|
+
constructor(conf) {
|
|
11
|
+
this.conf = conf;
|
|
12
|
+
this.debug = conf.debug;
|
|
13
|
+
this.index = conf.files.index;
|
|
14
|
+
this.scripts = [];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async copy_with_preset(subdirectory, to) {
|
|
18
|
+
const {paths} = this.conf;
|
|
19
|
+
|
|
20
|
+
// copy files preset files first
|
|
21
|
+
await File.copy(`${preset}/${subdirectory}`, to);
|
|
22
|
+
|
|
23
|
+
// copy any user code over it, not recreating the folder
|
|
24
|
+
try {
|
|
25
|
+
await File.copy(paths[subdirectory], to, false);
|
|
26
|
+
} catch(error) {
|
|
27
|
+
// directory doesn't exist
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async bundle() {
|
|
32
|
+
const {paths} = this.conf;
|
|
33
|
+
|
|
34
|
+
// copy static files to public
|
|
35
|
+
await this.copy_with_preset("static", paths.public);
|
|
36
|
+
|
|
37
|
+
// read index.html from public, then remove it (we serve it dynamically)
|
|
38
|
+
const index_html = await File.read(`${paths.public}/${this.index}`);
|
|
39
|
+
await File.remove(`${paths.public}/${this.index}`);
|
|
40
|
+
|
|
41
|
+
return index_html;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/source/Router.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import {http404} from "./handlers/http.js";
|
|
2
|
+
|
|
3
|
+
const aliases = [];
|
|
4
|
+
const routes = [];
|
|
5
|
+
const dealias = path => aliases.reduce((dealiased, {key, value}) =>
|
|
6
|
+
dealiased.replace(key, () => value), path);
|
|
7
|
+
const push = (type, path, handler) =>
|
|
8
|
+
routes.push({type, "path": new RegExp(`^${dealias(path)}$`, "u"), handler});
|
|
9
|
+
const find = (type, path, fallback) => routes.find(route =>
|
|
10
|
+
route.type === type && route.path.test(path))?.handler ?? fallback;
|
|
11
|
+
|
|
12
|
+
export default {
|
|
13
|
+
"map": (path, callback) => push("map", path, callback),
|
|
14
|
+
"get": (path, callback) => push("get", path, callback),
|
|
15
|
+
"post": (path, callback) => push("post", path, callback),
|
|
16
|
+
"alias": (key, value) => aliases.push({key, value}),
|
|
17
|
+
"process": async original_request => {
|
|
18
|
+
const {method} = original_request;
|
|
19
|
+
const url = new URL(`https://primatejs.com${original_request.pathname}`);
|
|
20
|
+
const {pathname, searchParams} = url;
|
|
21
|
+
const params = Object.fromEntries(searchParams);
|
|
22
|
+
const request = {...original_request, pathname, params,
|
|
23
|
+
"path": pathname.split("/").filter(path => path !== ""),
|
|
24
|
+
};
|
|
25
|
+
const verb = find(method, pathname, () => http404``);
|
|
26
|
+
return verb(await find("map", pathname, _ => _)(request));
|
|
27
|
+
},
|
|
28
|
+
};
|
package/source/Server.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import zlib from "zlib";
|
|
2
|
+
import {Readable} from "stream";
|
|
3
|
+
import {createServer} from "https";
|
|
4
|
+
import {join} from "path";
|
|
5
|
+
import {parse} from "url";
|
|
6
|
+
import Session from "./Session.js";
|
|
7
|
+
import File from "./File.js";
|
|
8
|
+
import {algorithm, hash} from "./crypto.js";
|
|
9
|
+
import log from "./log.js";
|
|
10
|
+
import codes from "./http-codes.json" assert {"type": "json"};
|
|
11
|
+
import mimes from "./mimes.json" assert {"type": "json"};
|
|
12
|
+
|
|
13
|
+
const regex = /\.([a-z1-9]*)$/u;
|
|
14
|
+
const mime = filename => mimes[filename.match(regex)[1]] ?? mimes.binary;
|
|
15
|
+
|
|
16
|
+
const stream = (from, response) => {
|
|
17
|
+
response.setHeader("Content-Encoding", "br");
|
|
18
|
+
response.writeHead(codes.OK);
|
|
19
|
+
return from.pipe(zlib.createBrotliCompress())
|
|
20
|
+
.pipe(response)
|
|
21
|
+
.on("close", () => response.end());
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export default class Server {
|
|
25
|
+
constructor(conf) {
|
|
26
|
+
this.conf = conf;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async run() {
|
|
30
|
+
const {http} = this.conf;
|
|
31
|
+
const {csp, "same-site": same_site = "Strict"} = http;
|
|
32
|
+
this.csp = Object.keys(csp).reduce((policy_string, key) =>
|
|
33
|
+
policy_string + `${key} ${csp[key]};`, "");
|
|
34
|
+
|
|
35
|
+
this.server = await createServer(http, async (request, response) => {
|
|
36
|
+
const session = await Session.get(request.headers.cookie);
|
|
37
|
+
if (!session.has_cookie) {
|
|
38
|
+
const {cookie} = session;
|
|
39
|
+
response.setHeader("Set-Cookie", `${cookie}; SameSite=${same_site}`);
|
|
40
|
+
}
|
|
41
|
+
response.session = session;
|
|
42
|
+
const buffers = [];
|
|
43
|
+
|
|
44
|
+
for await (const chunk of request) {
|
|
45
|
+
buffers.push(chunk);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const data = Buffer.concat(buffers).toString();
|
|
49
|
+
const payload = Object.fromEntries(decodeURI(data).replaceAll("+", " ")
|
|
50
|
+
.split("&")
|
|
51
|
+
.map(part => part.split("="))
|
|
52
|
+
.filter(([, value]) => value !== ""));
|
|
53
|
+
this.try(parse(request.url).path, request, response, payload);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async try(url, request, response, payload) {
|
|
58
|
+
try {
|
|
59
|
+
await this.serve(url, request, response, payload);
|
|
60
|
+
} catch (error) {
|
|
61
|
+
console.log(error);
|
|
62
|
+
// await response.session.log("red", error.message);
|
|
63
|
+
response.writeHead(codes.InternalServerError);
|
|
64
|
+
response.end();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async serve_file(url, filename, file, response) {
|
|
69
|
+
response.setHeader("Content-Type", mime(filename));
|
|
70
|
+
response.setHeader("Etag", file.modified);
|
|
71
|
+
await response.session.log("green", url);
|
|
72
|
+
return stream(file.read_stream, response);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async serve(url, request, response, payload) {
|
|
76
|
+
const filename = join(this.conf.serve_from, url);
|
|
77
|
+
const file = await new File(filename);
|
|
78
|
+
return await file.is_file
|
|
79
|
+
? this.serve_file(url, filename, file, response, payload)
|
|
80
|
+
: this.serve_data(url, request, response, payload);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async serve_data(pathname, request, response, payload) {
|
|
84
|
+
const {session} = response;
|
|
85
|
+
const request2 = {pathname, "method": request.method.toLowerCase(), payload};
|
|
86
|
+
const res = await this.conf.router.process(request2);
|
|
87
|
+
const {body, code, headers} = res;
|
|
88
|
+
|
|
89
|
+
const result = this.conf.index.replace("<body>", () => `<body>${body}`);
|
|
90
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
91
|
+
response.setHeader(key, value);
|
|
92
|
+
}
|
|
93
|
+
response.setHeader("Content-Security-Policy", this.csp);
|
|
94
|
+
response.setHeader("Referrer-Policy", "same-origin");
|
|
95
|
+
response.writeHead(code);
|
|
96
|
+
response.end(result);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
listen(port, host) {
|
|
100
|
+
log.reset("on").yellow(`https://${host}:${port}`).nl();
|
|
101
|
+
this.server.listen(port, host);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import Domain from "./domain/Domain.js";
|
|
2
|
+
|
|
3
|
+
const extract_id = cookie_header => cookie_header
|
|
4
|
+
?.split(";").filter(text => text.includes("session_id="))[0]?.split("=")[1];
|
|
5
|
+
|
|
6
|
+
export default class Session extends Domain {
|
|
7
|
+
static get fields() {
|
|
8
|
+
return {
|
|
9
|
+
"?data": Object,
|
|
10
|
+
"created": value => value ?? new Date(),
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
static async get(cookie_header) {
|
|
15
|
+
const session = await Session.touch({"_id": extract_id(cookie_header)});
|
|
16
|
+
await session.save();
|
|
17
|
+
if (session.new) {
|
|
18
|
+
session.has_cookie = false;
|
|
19
|
+
}
|
|
20
|
+
return session;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
get cookie() {
|
|
24
|
+
return `session_id=${this._id}; Path=/; Secure; HttpOnly`;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
File without changes
|
|
File without changes
|
|
@@ -2,7 +2,7 @@ import {join, resolve} from "path";
|
|
|
2
2
|
import cache from "./cache.js";
|
|
3
3
|
import File from "./File.js";
|
|
4
4
|
import extend_object from "./extend_object.js";
|
|
5
|
-
import primate_json from "
|
|
5
|
+
import primate_json from "./preset/primate.json" assert {"type": "json" };
|
|
6
6
|
|
|
7
7
|
const qualify = (root, paths) =>
|
|
8
8
|
Object.keys(paths).reduce((sofar, key) => {
|
|
File without changes
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import {resolve as path_resolve} from "path";
|
|
2
1
|
import Field from "./Field.js";
|
|
3
2
|
import {PredicateError} from "../errors.js";
|
|
4
3
|
import EagerPromise from "../EagerPromise.js";
|
|
@@ -10,7 +9,7 @@ import {random} from "../crypto.js";
|
|
|
10
9
|
const length = 12;
|
|
11
10
|
|
|
12
11
|
export default class Domain {
|
|
13
|
-
static stores_directory = "
|
|
12
|
+
static stores_directory = "stores";
|
|
14
13
|
static store_file = "default.js";
|
|
15
14
|
|
|
16
15
|
static {
|
|
@@ -27,8 +26,8 @@ export default class Domain {
|
|
|
27
26
|
"in": value => value ?? random(length).toString("hex"),
|
|
28
27
|
});
|
|
29
28
|
return new Proxy(this, {"get": (target, property, receiver) =>
|
|
30
|
-
Reflect.get(target, property, receiver) ?? target.#proxy(property)
|
|
31
|
-
}).set({...document, errors})
|
|
29
|
+
Reflect.get(target, property, receiver) ?? target.#proxy(property),
|
|
30
|
+
}).set({...document, errors});
|
|
32
31
|
}
|
|
33
32
|
|
|
34
33
|
get Class() {
|
|
@@ -47,7 +46,7 @@ export default class Domain {
|
|
|
47
46
|
}
|
|
48
47
|
|
|
49
48
|
static get store() {
|
|
50
|
-
return EagerPromise.resolve(cache(this, "store",
|
|
49
|
+
return EagerPromise.resolve(cache(this, "store", () =>
|
|
51
50
|
Store.get(this.stores_directory, this.store_file)
|
|
52
51
|
));
|
|
53
52
|
}
|
|
@@ -101,8 +100,8 @@ export default class Domain {
|
|
|
101
100
|
#link(name) {
|
|
102
101
|
const field = this.fields[`${name}_id`];
|
|
103
102
|
if (field?.is_domain) {
|
|
104
|
-
const collection = field.Type
|
|
105
|
-
const cache = this.Class
|
|
103
|
+
const {collection} = field.Type;
|
|
104
|
+
const {cache} = this.Class;
|
|
106
105
|
if (cache[collection] === undefined) {
|
|
107
106
|
cache[collection] = {};
|
|
108
107
|
}
|
|
@@ -110,9 +109,8 @@ export default class Domain {
|
|
|
110
109
|
cache[collection][this[`${name}_id`]] = field.by_id(this[`${name}_id`]);
|
|
111
110
|
}
|
|
112
111
|
return cache[collection][this[`${name}_id`]];
|
|
113
|
-
} else {
|
|
114
|
-
return undefined
|
|
115
112
|
}
|
|
113
|
+
return undefined;
|
|
116
114
|
}
|
|
117
115
|
|
|
118
116
|
// Serializing is done from the instance's point of view.
|
|
@@ -163,7 +161,7 @@ export default class Domain {
|
|
|
163
161
|
|
|
164
162
|
async verify(delta) {
|
|
165
163
|
this.set(delta);
|
|
166
|
-
const fields = this
|
|
164
|
+
const {fields} = this;
|
|
167
165
|
this.errors = (await Promise.all(Object.keys(fields).map(async property =>
|
|
168
166
|
({property, "value": await fields[property].verify(property, this)}))))
|
|
169
167
|
.filter(result => typeof result.value === "string")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -2,9 +2,7 @@ import conf from "./conf.js";
|
|
|
2
2
|
import App from "./App.js";
|
|
3
3
|
|
|
4
4
|
export {App};
|
|
5
|
-
export {default as Action} from "./Action.js";
|
|
6
5
|
export {default as Bundler} from "./Bundler.js";
|
|
7
|
-
export {default as Context} from "./Context.js";
|
|
8
6
|
export {default as Directory} from "./Directory.js";
|
|
9
7
|
export {default as File} from "./File.js";
|
|
10
8
|
export {default as EagerPromise, eager} from "./EagerPromise.js" ;
|
|
@@ -23,6 +21,10 @@ export {default as log} from "./log.js";
|
|
|
23
21
|
export {default as extend_object} from "./extend_object.js";
|
|
24
22
|
export {default as sanitize} from "./sanitize.js";
|
|
25
23
|
|
|
24
|
+
export {default as html} from "./handlers/html.js";
|
|
25
|
+
export {default as redirect} from "./handlers/redirect.js";
|
|
26
|
+
export {default as router} from "./Router.js";
|
|
27
|
+
|
|
26
28
|
const app = new App(conf());
|
|
27
29
|
|
|
28
30
|
export {app};
|
|
File without changes
|