primate 0.5.2 → 0.6.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/README.md +21 -36
- package/debris.json +1 -2
- package/package.json +7 -10
- package/source/App.js +36 -0
- package/source/Bundler.js +51 -0
- package/source/{server/Directory.js → Directory.js} +0 -0
- package/source/{server/EagerPromise.js → EagerPromise.js} +5 -7
- package/source/{server/File.js → File.js} +0 -0
- package/source/Router.js +28 -0
- package/source/Server.js +105 -0
- package/source/{server/Session.js → Session.js} +2 -21
- 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 +7 -9
- package/source/{server/domain → domain}/Field.js +0 -0
- package/source/{server/domain → domain}/Predicate.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} +6 -3
- 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 +30 -0
- package/source/handlers/http.js +6 -0
- package/source/handlers/json.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 +3 -7
- package/source/preset/static/index.html +0 -2
- package/source/preset/stores/default.js +1 -1
- 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/server/Action.js +0 -100
- package/source/server/App.js +0 -62
- 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/domain/domains.js +0 -31
- package/source/server/servers/Dynamic.js +0 -57
- package/source/server/servers/Server.js +0 -5
- package/source/server/servers/Static.js +0 -117
- 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.2",
|
|
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
|
}
|
package/source/App.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {resolve} from "path";
|
|
2
|
+
import Bundler from "./Bundler.js";
|
|
3
|
+
import File from "./File.js";
|
|
4
|
+
import Directory from "./Directory.js";
|
|
5
|
+
import Router from "./Router.js";
|
|
6
|
+
import Server from "./Server.js";
|
|
7
|
+
import log from "./log.js";
|
|
8
|
+
import package_json from "../package.json" assert {"type": "json"};
|
|
9
|
+
|
|
10
|
+
export default class App {
|
|
11
|
+
constructor(conf) {
|
|
12
|
+
this.conf = conf;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async run() {
|
|
16
|
+
log.reset("Primate").yellow(package_json.version);
|
|
17
|
+
|
|
18
|
+
const routes = await Directory.list(this.conf.paths.routes);
|
|
19
|
+
for (const route of routes) {
|
|
20
|
+
await import(`${this.conf.paths.routes}/${route}`);
|
|
21
|
+
}
|
|
22
|
+
await new Bundler(this.conf).bundle();
|
|
23
|
+
|
|
24
|
+
const conf = {"router": Router,
|
|
25
|
+
"serve_from": this.conf.paths.public,
|
|
26
|
+
"http": {
|
|
27
|
+
...this.conf.http,
|
|
28
|
+
"key": File.read_sync(resolve(this.conf.http.ssl.key)),
|
|
29
|
+
"cert": File.read_sync(resolve(this.conf.http.ssl.cert)),
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
this.server = new Server(conf);
|
|
33
|
+
await this.server.run();
|
|
34
|
+
this.server.listen();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
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
|
+
await File.remove(`${paths.public}/${this.index}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const index = async conf => {
|
|
43
|
+
let file;
|
|
44
|
+
const subdirectory = "static";
|
|
45
|
+
try {
|
|
46
|
+
file = await File.read(`${conf.paths[subdirectory]}/${conf.files.index}`);
|
|
47
|
+
} catch (error) {
|
|
48
|
+
file = await File.read(`${preset}/${subdirectory}/${conf.files.index}`);
|
|
49
|
+
}
|
|
50
|
+
return file;
|
|
51
|
+
};
|
|
File without changes
|
|
@@ -10,14 +10,12 @@ const handler = {
|
|
|
10
10
|
return promise[property].bind(promise);
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
return EagerPromise.resolve(promise.then(result =>
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
return inconstructible_function(result[property])
|
|
13
|
+
return EagerPromise.resolve(promise.then(result => property === "bind"
|
|
14
|
+
? result
|
|
15
|
+
: inconstructible_function(result[property])
|
|
18
16
|
? result[property].bind(result)
|
|
19
|
-
: result[property]
|
|
20
|
-
|
|
17
|
+
: result[property]
|
|
18
|
+
));
|
|
21
19
|
},
|
|
22
20
|
"apply": (target, that, args) =>
|
|
23
21
|
EagerPromise.resolve(target[$promise].then(result =>
|
|
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,105 @@
|
|
|
1
|
+
import zlib from "zlib";
|
|
2
|
+
import {createServer} from "https";
|
|
3
|
+
import {join} from "path";
|
|
4
|
+
import {parse} from "url";
|
|
5
|
+
import Session from "./Session.js";
|
|
6
|
+
import File from "./File.js";
|
|
7
|
+
import log from "./log.js";
|
|
8
|
+
import codes from "./http-codes.json" assert {"type": "json"};
|
|
9
|
+
import mimes from "./mimes.json" assert {"type": "json"};
|
|
10
|
+
import {http404} from "./handlers/http.js";
|
|
11
|
+
|
|
12
|
+
const regex = /\.([a-z1-9]*)$/u;
|
|
13
|
+
const mime = filename => mimes[filename.match(regex)[1]] ?? mimes.binary;
|
|
14
|
+
|
|
15
|
+
const stream = (from, response) => {
|
|
16
|
+
response.setHeader("Content-Encoding", "br");
|
|
17
|
+
response.writeHead(codes.OK);
|
|
18
|
+
return from.pipe(zlib.createBrotliCompress())
|
|
19
|
+
.pipe(response)
|
|
20
|
+
.on("close", () => response.end());
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default class Server {
|
|
24
|
+
constructor(conf) {
|
|
25
|
+
this.conf = conf;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async run() {
|
|
29
|
+
const {http} = this.conf;
|
|
30
|
+
const {csp, "same-site": same_site = "Strict"} = http;
|
|
31
|
+
this.csp = Object.keys(csp).reduce((policy_string, key) =>
|
|
32
|
+
policy_string + `${key} ${csp[key]};`, "");
|
|
33
|
+
|
|
34
|
+
this.server = await createServer(http, async (request, response) => {
|
|
35
|
+
const session = await Session.get(request.headers.cookie);
|
|
36
|
+
if (!session.has_cookie) {
|
|
37
|
+
const {cookie} = session;
|
|
38
|
+
response.setHeader("Set-Cookie", `${cookie}; SameSite=${same_site}`);
|
|
39
|
+
}
|
|
40
|
+
response.session = session;
|
|
41
|
+
const buffers = [];
|
|
42
|
+
|
|
43
|
+
for await (const chunk of request) {
|
|
44
|
+
buffers.push(chunk);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const data = Buffer.concat(buffers).toString();
|
|
48
|
+
const payload = Object.fromEntries(decodeURI(data).replaceAll("+", " ")
|
|
49
|
+
.split("&")
|
|
50
|
+
.map(part => part.split("="))
|
|
51
|
+
.filter(([, value]) => value !== ""));
|
|
52
|
+
this.try(parse(request.url).path, request, response, payload);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async try(url, request, response, payload) {
|
|
57
|
+
try {
|
|
58
|
+
await this.serve(url, request, response, payload);
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.log(error);
|
|
61
|
+
response.writeHead(codes.InternalServerError);
|
|
62
|
+
response.end();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async serve_file(url, filename, file, response) {
|
|
67
|
+
response.setHeader("Content-Type", mime(filename));
|
|
68
|
+
response.setHeader("Etag", file.modified);
|
|
69
|
+
await response.session.log("green", url);
|
|
70
|
+
return stream(file.read_stream, response);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async serve(url, request, response, payload) {
|
|
74
|
+
const filename = join(this.conf.serve_from, url);
|
|
75
|
+
const file = await new File(filename);
|
|
76
|
+
return await file.is_file
|
|
77
|
+
? this.serve_file(url, filename, file, response, payload)
|
|
78
|
+
: this.serve_route(url, request, response, payload);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async serve_route(pathname, request, response, payload) {
|
|
82
|
+
const req = {pathname, "method": request.method.toLowerCase(), payload};
|
|
83
|
+
let result;
|
|
84
|
+
try {
|
|
85
|
+
result = await this.conf.router.process(req);
|
|
86
|
+
for (const [key, value] of Object.entries(result.headers)) {
|
|
87
|
+
response.setHeader(key, value);
|
|
88
|
+
}
|
|
89
|
+
} catch (error) {
|
|
90
|
+
console.log(error);
|
|
91
|
+
result = http404``;
|
|
92
|
+
}
|
|
93
|
+
const {body, code} = result;
|
|
94
|
+
response.setHeader("Content-Security-Policy", this.csp);
|
|
95
|
+
response.setHeader("Referrer-Policy", "same-origin");
|
|
96
|
+
response.writeHead(code);
|
|
97
|
+
response.end(body);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
listen() {
|
|
101
|
+
const {port, host} = this.conf.http;
|
|
102
|
+
log.reset("on").yellow(`https://${host}:${port}`).nl();
|
|
103
|
+
this.server.listen(port, host);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import Context from "./Context.js";
|
|
2
1
|
import Domain from "./domain/Domain.js";
|
|
3
2
|
|
|
4
3
|
const extract_id = cookie_header => cookie_header
|
|
@@ -8,23 +7,14 @@ export default class Session extends Domain {
|
|
|
8
7
|
static get fields() {
|
|
9
8
|
return {
|
|
10
9
|
"?data": Object,
|
|
11
|
-
"context" : String,
|
|
12
10
|
"created": value => value ?? new Date(),
|
|
13
11
|
};
|
|
14
12
|
}
|
|
15
13
|
|
|
16
|
-
async
|
|
17
|
-
(await Context.get(this.context)).log(color, message);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
route(router, url) {
|
|
21
|
-
return router.route(url, this.context);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
static async get(cookie_header, default_context) {
|
|
14
|
+
static async get(cookie_header) {
|
|
25
15
|
const session = await Session.touch({"_id": extract_id(cookie_header)});
|
|
16
|
+
await session.save();
|
|
26
17
|
if (session.new) {
|
|
27
|
-
await session.save({"context": default_context});
|
|
28
18
|
session.has_cookie = false;
|
|
29
19
|
}
|
|
30
20
|
return session;
|
|
@@ -33,13 +23,4 @@ export default class Session extends Domain {
|
|
|
33
23
|
get cookie() {
|
|
34
24
|
return `session_id=${this._id}; Path=/; Secure; HttpOnly`;
|
|
35
25
|
}
|
|
36
|
-
|
|
37
|
-
async switch_context(context, data = {}) {
|
|
38
|
-
await this.save({context, data});
|
|
39
|
-
return this;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
async run(request) {
|
|
43
|
-
return (await Context.get(this.context)).run(request, this);
|
|
44
|
-
}
|
|
45
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";
|
|
@@ -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
|
|
@@ -2,15 +2,12 @@ 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" ;
|
|
11
9
|
|
|
12
10
|
export {default as Domain} from "./domain/Domain.js";
|
|
13
|
-
export {default as domains} from "./domain/domains.js";
|
|
14
11
|
export {default as Storeable} from "./types/Storeable.js";
|
|
15
12
|
|
|
16
13
|
export * from "./errors.js";
|
|
@@ -23,6 +20,12 @@ export {default as log} from "./log.js";
|
|
|
23
20
|
export {default as extend_object} from "./extend_object.js";
|
|
24
21
|
export {default as sanitize} from "./sanitize.js";
|
|
25
22
|
|
|
23
|
+
export {default as html} from "./handlers/html.js";
|
|
24
|
+
export {default as json} from "./handlers/json.js";
|
|
25
|
+
export {default as redirect} from "./handlers/redirect.js";
|
|
26
|
+
|
|
27
|
+
export {default as router} from "./Router.js";
|
|
28
|
+
|
|
26
29
|
const app = new App(conf());
|
|
27
30
|
|
|
28
31
|
export {app};
|
|
File without changes
|