primate 0.3.1 → 0.5.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 +10 -7
- package/debris.json +5 -0
- package/jsconfig.json +8 -0
- package/package.json +16 -4
- package/source/client/Action.js +20 -22
- package/source/client/Client.js +13 -17
- package/source/client/Context.js +10 -16
- package/source/client/Element.js +18 -14
- package/source/client/Session.js +27 -0
- package/source/client/View.js +1 -2
- package/source/client/document.js +1 -1
- package/source/preset/primate.json +2 -8
- package/source/server/Action.js +57 -75
- package/source/server/App.js +27 -8
- package/source/server/Bundler.js +13 -16
- package/source/server/Context.js +63 -56
- package/source/server/{promises/Eager.js → EagerPromise.js} +4 -2
- package/source/server/File.js +5 -1
- package/source/server/Projector.js +86 -0
- package/source/server/Router.js +15 -24
- package/source/server/Session.js +9 -33
- package/source/server/attributes.js +3 -0
- package/source/server/conf.js +20 -26
- package/source/server/{Crypto.js → crypto.js} +0 -0
- package/source/server/domain/Domain.js +56 -46
- package/source/server/domain/Field.js +34 -36
- package/source/server/domain/Predicate.js +24 -0
- package/source/server/domain/domains.js +17 -1
- package/source/server/errors/InternalServer.js +1 -1
- package/source/server/errors/Predicate.js +1 -1
- package/source/server/errors.js +0 -1
- package/source/server/exports.js +10 -9
- package/source/server/{utils/extend_object.js → extend_object.js} +0 -0
- package/source/server/invariants.js +23 -10
- package/source/server/sanitize.js +10 -0
- package/source/server/servers/Dynamic.js +19 -13
- package/source/server/servers/Server.js +1 -1
- package/source/server/servers/Static.js +25 -20
- package/source/server/store/Store.js +13 -0
- package/source/server/types/Array.js +2 -2
- package/source/server/types/Boolean.js +2 -2
- package/source/server/types/Date.js +2 -2
- package/source/server/types/Domain.js +1 -6
- package/source/server/types/Instance.js +1 -1
- package/source/server/types/Number.js +2 -2
- package/source/server/types/Object.js +2 -2
- package/source/server/types/Primitive.js +1 -1
- package/source/server/types/Storeable.js +12 -19
- package/source/server/types/String.js +2 -2
- package/source/server/view/TreeNode.js +2 -0
- package/source/server/view/View.js +6 -1
- package/source/client/Base.js +0 -5
- package/source/server/Base.js +0 -35
- package/source/server/errors/Fallback.js +0 -1
- package/source/server/fallback.js +0 -11
- package/source/server/promises/Meta.js +0 -42
- package/source/server/promises.js +0 -2
package/README.md
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
# Primate: a JavaScript framework
|
|
2
2
|
|
|
3
|
-
⚠️ **This software is currently its initial development phase. It is not
|
|
4
|
-
considered production-ready. Expect breakage.** ⚠️
|
|
5
|
-
|
|
6
3
|
Primate is a server-client JavaScript framework for web applications aimed at
|
|
7
4
|
relieving you of dealing with repetitive, error-prone tasks and letting you
|
|
8
5
|
concentrate on writing effective, expressive code.
|
|
@@ -10,7 +7,7 @@ concentrate on writing effective, expressive code.
|
|
|
10
7
|
## Installing
|
|
11
8
|
|
|
12
9
|
```
|
|
13
|
-
|
|
10
|
+
npm install primate
|
|
14
11
|
```
|
|
15
12
|
|
|
16
13
|
## Concepts
|
|
@@ -23,11 +20,12 @@ yarn add primate
|
|
|
23
20
|
* **Correct** data verification using field definitions in domains
|
|
24
21
|
* **Secure** serving hash-verified scripts on secure HTTP with a strong CSP
|
|
25
22
|
* **Roles** access control with contexts
|
|
26
|
-
* **Sessions** using cookies that are `
|
|
23
|
+
* **Sessions** using cookies that are `Secure`, `SameSite=Strict`, `HttpOnly`
|
|
24
|
+
and `Path`-limited
|
|
27
25
|
* **Sane defaults** minimally opinionated with good, overrideable defaults
|
|
28
26
|
for most features
|
|
29
27
|
* **Data linking** modeling `1:1`, `1:n` and `n:m` relationships on domains via
|
|
30
|
-
ad-hoc getters
|
|
28
|
+
cacheable ad-hoc getters
|
|
31
29
|
|
|
32
30
|
## Getting started
|
|
33
31
|
|
|
@@ -35,7 +33,10 @@ See the [getting started][getting-started] guide.
|
|
|
35
33
|
|
|
36
34
|
## Resources
|
|
37
35
|
|
|
38
|
-
|
|
36
|
+
* [Source code][source-code]
|
|
37
|
+
* [Issues][issues]
|
|
38
|
+
|
|
39
|
+
A full guide is coming soon.
|
|
39
40
|
|
|
40
41
|
## Versioning
|
|
41
42
|
|
|
@@ -49,3 +50,5 @@ BSD-3-Clause
|
|
|
49
50
|
|
|
50
51
|
[ws]: https://github.com/websockets/ws
|
|
51
52
|
[getting-started]: https://primatejs.com/getting-started
|
|
53
|
+
[source-code]: https://adaptivecloud.dev/primate/primate
|
|
54
|
+
[issues]: https://adaptivecloud.dev/primate/primate/issues
|
package/debris.json
ADDED
package/jsconfig.json
ADDED
package/package.json
CHANGED
|
@@ -1,19 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "primate",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"author": "Primate core team <core@primatejs.com>",
|
|
5
5
|
"homepage": "https://primatejs.com",
|
|
6
|
+
"bugs": "https://adaptivecloud.dev/primate/primate/issues",
|
|
7
|
+
"repository": "https://adaptivecloud.dev/primate/primate",
|
|
6
8
|
"description": "Server-client framework",
|
|
7
9
|
"license": "BSD-3-Clause",
|
|
8
10
|
"dependencies": {
|
|
9
|
-
"ws": "^8.
|
|
11
|
+
"ws": "^8.5.0"
|
|
10
12
|
},
|
|
11
13
|
"scripts": {
|
|
12
|
-
"
|
|
14
|
+
"copy": "rm -rf output && mkdir output && cp source/* output -a",
|
|
15
|
+
"instrument": "nyc instrument source ./output",
|
|
16
|
+
"debris": "node --experimental-json-modules node_modules/debris debris.json",
|
|
17
|
+
"coverage": "npm run instrument && nyc npm run debris",
|
|
18
|
+
"test": "npm run copy && npm run debris"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"debris": "^0.2.0",
|
|
22
|
+
"eslint": "^8.11.0",
|
|
23
|
+
"eslint-plugin-json": "^3.1.0",
|
|
24
|
+
"nyc": "^15.1.0"
|
|
13
25
|
},
|
|
14
26
|
"type": "module",
|
|
15
27
|
"exports": "./source/server/exports.js",
|
|
16
28
|
"engines": {
|
|
17
|
-
"node": ">=17.
|
|
29
|
+
"node": ">=17.7.2"
|
|
18
30
|
}
|
|
19
31
|
}
|
package/source/client/Action.js
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
import Element from "../Element.js";
|
|
2
2
|
import View from "./View.js";
|
|
3
|
-
import
|
|
4
|
-
import {origin_base} from "./document.js";
|
|
3
|
+
import {origin_base, origin} from "./document.js";
|
|
5
4
|
|
|
6
|
-
export default class Action
|
|
7
|
-
constructor(name,
|
|
8
|
-
super();
|
|
5
|
+
export default class Action {
|
|
6
|
+
constructor(name, session) {
|
|
9
7
|
this.name = name;
|
|
10
|
-
this.
|
|
8
|
+
this.session = session;
|
|
11
9
|
this.listeners = [];
|
|
12
10
|
}
|
|
13
11
|
|
|
14
12
|
before() {}
|
|
15
13
|
|
|
16
|
-
|
|
14
|
+
enter(data) {
|
|
17
15
|
if (data.location) {
|
|
18
16
|
location.href = data.location;
|
|
19
17
|
} else {
|
|
@@ -23,20 +21,20 @@ export default class Action extends Base {
|
|
|
23
21
|
|
|
24
22
|
create_view(data, root, save_history = true) {
|
|
25
23
|
if (save_history) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
if (data.url !== document.location.href.replace(origin, "")) {
|
|
25
|
+
history.pushState({}, "", data.url);
|
|
26
|
+
}
|
|
29
27
|
}
|
|
30
28
|
this.view = new View(data, this, root);
|
|
31
29
|
}
|
|
32
30
|
|
|
33
|
-
create_and_return_view(data, root
|
|
31
|
+
create_and_return_view(data, root) {
|
|
34
32
|
return new View(data, this, root);
|
|
35
33
|
}
|
|
36
34
|
|
|
37
35
|
get_form_data(target) {
|
|
38
36
|
const payload = {};
|
|
39
|
-
const elements = target
|
|
37
|
+
const {elements} = target;
|
|
40
38
|
for (let i = 0; i < elements.length; i++) {
|
|
41
39
|
const element = elements[i];
|
|
42
40
|
const type = Element.value(element, "type");
|
|
@@ -66,16 +64,16 @@ export default class Action extends Base {
|
|
|
66
64
|
}
|
|
67
65
|
|
|
68
66
|
async onsubmit(event) {
|
|
69
|
-
const target = event
|
|
67
|
+
const {target} = event;
|
|
70
68
|
const stop = this.fire("submit", event);
|
|
71
69
|
if (stop) {
|
|
72
70
|
return event.preventDefault();
|
|
73
71
|
}
|
|
74
72
|
event.preventDefault();
|
|
75
73
|
const data = await this.write(target.action, this.get_form_data(target));
|
|
76
|
-
return data.
|
|
74
|
+
return data.type === "update"
|
|
77
75
|
? this.view.update(data.payload)
|
|
78
|
-
: this.
|
|
76
|
+
: this.session.run(data);
|
|
79
77
|
}
|
|
80
78
|
|
|
81
79
|
async onclick(event) {
|
|
@@ -96,8 +94,7 @@ export default class Action extends Base {
|
|
|
96
94
|
if (event.button === 0 && url.href.startsWith(origin_base)) {
|
|
97
95
|
event.preventDefault();
|
|
98
96
|
if (href !== "") {
|
|
99
|
-
|
|
100
|
-
await this.context.run(data);
|
|
97
|
+
await this.session.run(await this.read(href));
|
|
101
98
|
}
|
|
102
99
|
}
|
|
103
100
|
}
|
|
@@ -111,13 +108,13 @@ export default class Action extends Base {
|
|
|
111
108
|
}
|
|
112
109
|
|
|
113
110
|
oninput() {
|
|
114
|
-
|
|
111
|
+
this.fire("input", event);
|
|
115
112
|
}
|
|
116
113
|
|
|
117
114
|
fire(type, event) {
|
|
118
115
|
const listeners = this.listeners[type];
|
|
119
116
|
if (listeners !== undefined) {
|
|
120
|
-
const target = event
|
|
117
|
+
const {target} = event;
|
|
121
118
|
for (const listener of listeners) {
|
|
122
119
|
if (event.target.closest(listener.selector)) {
|
|
123
120
|
listener.listener(event, target);
|
|
@@ -134,7 +131,8 @@ export default class Action extends Base {
|
|
|
134
131
|
const index = this.listeners[event]
|
|
135
132
|
.findIndex(listener => listener.selector === selector);
|
|
136
133
|
const object = {selector, listener};
|
|
137
|
-
|
|
134
|
+
const not_found = -1;
|
|
135
|
+
if (index === not_found) {
|
|
138
136
|
this.listeners[event].push(object);
|
|
139
137
|
} else {
|
|
140
138
|
this.listeners[event].splice(index, 1, object);
|
|
@@ -150,10 +148,10 @@ export default class Action extends Base {
|
|
|
150
148
|
}
|
|
151
149
|
|
|
152
150
|
read(pathname) {
|
|
153
|
-
return this.
|
|
151
|
+
return this.session.read(pathname);
|
|
154
152
|
}
|
|
155
153
|
|
|
156
154
|
write(pathname, payload) {
|
|
157
|
-
return this.
|
|
155
|
+
return this.session.write(pathname, payload);
|
|
158
156
|
}
|
|
159
157
|
}
|
package/source/client/Client.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {contexts} from "./exports.js";
|
|
1
|
+
import Session from "./Session.js";
|
|
3
2
|
import {base, host, origin_base} from "./document.js";
|
|
4
3
|
|
|
5
4
|
const events = ["submit", "click", "change", "input"];
|
|
@@ -9,43 +8,37 @@ const location = `wss://${host}${base}`;
|
|
|
9
8
|
export default class Client {
|
|
10
9
|
constructor(conf) {
|
|
11
10
|
this.conf = conf;
|
|
11
|
+
this.session = new Session(this);
|
|
12
12
|
|
|
13
13
|
window.onpopstate = async event => {
|
|
14
14
|
const {pathname, search} = event.target.location;
|
|
15
|
-
return this.
|
|
15
|
+
return this.session.run(await this.read(pathname + search));
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
for (const key of events) {
|
|
19
|
-
window.addEventListener(key, event => this.
|
|
19
|
+
window.addEventListener(key, event => this.session.on(key, event));
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
open() {
|
|
24
24
|
return this.connection?.readyState === 1 ? this
|
|
25
25
|
: new Promise(resolve => {
|
|
26
|
-
|
|
27
|
-
connection.addEventListener("message", ({data}) => data === "open"
|
|
26
|
+
this.connection = new WebSocket(location);
|
|
27
|
+
this.connection.addEventListener("message", ({data}) => data === "open"
|
|
28
28
|
? resolve(this)
|
|
29
29
|
: this.receive(JSON.parse(data)));
|
|
30
|
-
this.connection = connection;
|
|
31
30
|
});
|
|
32
31
|
}
|
|
33
32
|
|
|
34
33
|
async receive(data) {
|
|
35
|
-
if (back
|
|
34
|
+
if (back === undefined) {
|
|
35
|
+
await this.session.execute(data);
|
|
36
|
+
} else {
|
|
36
37
|
back(data);
|
|
37
38
|
back = undefined;
|
|
38
|
-
} else {
|
|
39
|
-
await this.execute(data);
|
|
40
39
|
}
|
|
41
40
|
}
|
|
42
41
|
|
|
43
|
-
async execute(data) {
|
|
44
|
-
const {context} = data;
|
|
45
|
-
this.context = new (contexts[context] ?? Context)(context, this);
|
|
46
|
-
await this.context.run(data);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
42
|
read(url) {
|
|
50
43
|
return this.send("read", url);
|
|
51
44
|
}
|
|
@@ -57,9 +50,12 @@ export default class Client {
|
|
|
57
50
|
async send(type, url, payload = {}) {
|
|
58
51
|
await this.open();
|
|
59
52
|
const {pathname, search} = new URL(url, origin_base);
|
|
53
|
+
const _url = pathname + search;
|
|
60
54
|
return new Promise(resolve => {
|
|
61
55
|
back = data => resolve(data);
|
|
62
|
-
this.connection.send(JSON.stringify({
|
|
56
|
+
this.connection.send(JSON.stringify({
|
|
57
|
+
type, pathname, search, payload, "url": _url,
|
|
58
|
+
}));
|
|
63
59
|
});
|
|
64
60
|
}
|
|
65
61
|
}
|
package/source/client/Context.js
CHANGED
|
@@ -1,24 +1,26 @@
|
|
|
1
|
-
import Base from "./Base.js";
|
|
2
1
|
import Action from "./Action.js";
|
|
3
2
|
import {routes} from "./exports.js";
|
|
4
3
|
|
|
5
|
-
export default class Context
|
|
6
|
-
constructor(name,
|
|
7
|
-
super();
|
|
4
|
+
export default class Context {
|
|
5
|
+
constructor(name, session) {
|
|
8
6
|
this.name = name;
|
|
9
7
|
this.actions = {};
|
|
10
8
|
this.used_actions = [];
|
|
11
|
-
this.
|
|
9
|
+
this.session = session;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
get Class() {
|
|
13
|
+
return this.constructor;
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
async run(data) {
|
|
15
17
|
const {namespace, action} = data;
|
|
16
18
|
const route = `${namespace}/${action}`;
|
|
17
|
-
const
|
|
18
|
-
this.actions[route] = new
|
|
19
|
+
const Module = routes?.[namespace]?.[action] ?? Action;
|
|
20
|
+
this.actions[route] = new Module(action, this.session);
|
|
19
21
|
const nextaction = this.actions[route];
|
|
20
22
|
nextaction.enter(data);
|
|
21
|
-
await this.Class
|
|
23
|
+
await this.Class.before(nextaction);
|
|
22
24
|
nextaction.before();
|
|
23
25
|
this.action = nextaction;
|
|
24
26
|
}
|
|
@@ -31,14 +33,6 @@ export default class Context extends Base {
|
|
|
31
33
|
return data;
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
read(pathname) {
|
|
35
|
-
return this.client.read(pathname);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
write(pathname, payload) {
|
|
39
|
-
return this.client.write(pathname, payload);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
36
|
on(key, event) {
|
|
43
37
|
this.action[`on${key}`](event);
|
|
44
38
|
}
|
package/source/client/Element.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
const file_listener = event => reader.readAsDataURL(event.target.files[0]);
|
|
2
1
|
const reader = new FileReader();
|
|
2
|
+
const file_listener = event => reader.readAsDataURL(event.target.files[0]);
|
|
3
3
|
|
|
4
4
|
const replace = (attribute, source) => {
|
|
5
5
|
if (attribute.includes(".")) {
|
|
@@ -20,11 +20,11 @@ const fulfill = (attribute, source) => {
|
|
|
20
20
|
if (source === undefined) {
|
|
21
21
|
return undefined;
|
|
22
22
|
}
|
|
23
|
-
let value = attribute
|
|
23
|
+
let {value} = attribute;
|
|
24
24
|
const matches = [...value.matchAll(data_regex)];
|
|
25
25
|
if (matches.length > 0) {
|
|
26
26
|
for (const match of matches) {
|
|
27
|
-
const key = match
|
|
27
|
+
const [key] = match;
|
|
28
28
|
const new_value = replace(match[1], source);
|
|
29
29
|
value = value.replace(key, new_value);
|
|
30
30
|
}
|
|
@@ -34,7 +34,6 @@ const fulfill = (attribute, source) => {
|
|
|
34
34
|
return value;
|
|
35
35
|
};
|
|
36
36
|
|
|
37
|
-
|
|
38
37
|
const $selector = Symbol("$selector");
|
|
39
38
|
const $element = Symbol("$element");
|
|
40
39
|
const $action = Symbol("$action");
|
|
@@ -47,13 +46,13 @@ const proxy_handler = {
|
|
|
47
46
|
if (property === "on" || property === "insert") {
|
|
48
47
|
return target[property].bind(target);
|
|
49
48
|
}
|
|
50
|
-
if (target.element
|
|
51
|
-
return (...args) => target[property] !== undefined
|
|
52
|
-
? target[property](...args)
|
|
53
|
-
: receiver;
|
|
54
|
-
} else {
|
|
49
|
+
if (target.element === null) {
|
|
55
50
|
return () => receiver;
|
|
56
51
|
}
|
|
52
|
+
|
|
53
|
+
return (...args) => target[property] === undefined
|
|
54
|
+
? receiver
|
|
55
|
+
: target[property](...args);
|
|
57
56
|
},
|
|
58
57
|
};
|
|
59
58
|
|
|
@@ -77,8 +76,7 @@ export default class Element {
|
|
|
77
76
|
}
|
|
78
77
|
|
|
79
78
|
static value(element, name) {
|
|
80
|
-
|
|
81
|
-
return attribute === null ? null : attribute.value;
|
|
79
|
+
return element?.attributes.getNamedItem(name)?.value;
|
|
82
80
|
}
|
|
83
81
|
|
|
84
82
|
static evaluate(attribute, source, data) {
|
|
@@ -146,7 +144,7 @@ export default class Element {
|
|
|
146
144
|
class(classes, set) {
|
|
147
145
|
classes.split(" ").forEach(name => {
|
|
148
146
|
this.element.classList.toggle(name, set !== false);
|
|
149
|
-
})
|
|
147
|
+
});
|
|
150
148
|
return this;
|
|
151
149
|
}
|
|
152
150
|
|
|
@@ -183,7 +181,8 @@ export default class Element {
|
|
|
183
181
|
|
|
184
182
|
options(value) {
|
|
185
183
|
value instanceof Array && value.forEach(option => {
|
|
186
|
-
|
|
184
|
+
const children = [...this.element.children];
|
|
185
|
+
if (!children.find(child => child.value === option._id)) {
|
|
187
186
|
const newElement = document.createElement("option");
|
|
188
187
|
newElement.setAttribute("value", option._id);
|
|
189
188
|
newElement.innerHTML = option.name;
|
|
@@ -203,11 +202,13 @@ export default class Element {
|
|
|
203
202
|
|
|
204
203
|
select_value(value) {
|
|
205
204
|
this.element.value = value === undefined ? "" : value;
|
|
205
|
+
return this;
|
|
206
206
|
}
|
|
207
207
|
|
|
208
208
|
input_value(value) {
|
|
209
209
|
const type = Element.value(this.element, "type");
|
|
210
210
|
this[`input_${type}_value`]?.(value) ?? this.input_input_value(value);
|
|
211
|
+
return this;
|
|
211
212
|
}
|
|
212
213
|
|
|
213
214
|
textarea_value(value) {
|
|
@@ -218,21 +219,24 @@ export default class Element {
|
|
|
218
219
|
if (value === true) {
|
|
219
220
|
this.element.checked = true;
|
|
220
221
|
}
|
|
222
|
+
return this;
|
|
221
223
|
}
|
|
222
224
|
|
|
223
225
|
input_file_value(value) {
|
|
224
|
-
const element = this
|
|
226
|
+
const {element} = this;
|
|
225
227
|
if (value !== undefined) {
|
|
226
228
|
element.setAttribute("base64", value);
|
|
227
229
|
}
|
|
228
230
|
reader.onload = ({target}) => element.setAttribute("base64", target.result);
|
|
229
231
|
element.addEventListener("change", file_listener);
|
|
232
|
+
return this;
|
|
230
233
|
}
|
|
231
234
|
|
|
232
235
|
input_input_value(value) {
|
|
233
236
|
if (value !== undefined) {
|
|
234
237
|
this.element.value = value;
|
|
235
238
|
}
|
|
239
|
+
return this;
|
|
236
240
|
}
|
|
237
241
|
|
|
238
242
|
default_value(value) {
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import Context from "./Context.js";
|
|
2
|
+
import {contexts} from "./exports.js";
|
|
3
|
+
|
|
4
|
+
export default class Session {
|
|
5
|
+
constructor(client) {
|
|
6
|
+
this.client = client;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
async run(data) {
|
|
10
|
+
const {context} = data;
|
|
11
|
+
this.context = new (contexts[context] ?? Context)(context, this);
|
|
12
|
+
|
|
13
|
+
await this.context.run(data);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
on(key, event) {
|
|
17
|
+
this.context.on(key, event);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
read(pathname) {
|
|
21
|
+
return this.client.read(pathname);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
write(pathname, payload) {
|
|
25
|
+
return this.client.write(pathname, payload);
|
|
26
|
+
}
|
|
27
|
+
}
|
package/source/client/View.js
CHANGED
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
import Element from "../Element.js";
|
|
4
4
|
import Node from "./Node.js";
|
|
5
5
|
|
|
6
|
-
const data_regex = /\${([^}]*)}/g;
|
|
7
|
-
|
|
8
6
|
export default class View {
|
|
9
7
|
constructor(data, action, root) {
|
|
10
8
|
this.sources = {};
|
|
@@ -87,4 +85,5 @@ export default class View {
|
|
|
87
85
|
write(pathname, payload) {
|
|
88
86
|
return this.action.write(pathname, payload);
|
|
89
87
|
}
|
|
88
|
+
|
|
90
89
|
}
|
|
@@ -2,10 +2,7 @@
|
|
|
2
2
|
"base": "/",
|
|
3
3
|
"debug": false,
|
|
4
4
|
"defaults": {
|
|
5
|
-
"
|
|
6
|
-
"context": "guest",
|
|
7
|
-
"namespace": "default",
|
|
8
|
-
"store": "default.js"
|
|
5
|
+
"context": "guest"
|
|
9
6
|
},
|
|
10
7
|
"files": {
|
|
11
8
|
"index": "index.html"
|
|
@@ -20,10 +17,7 @@
|
|
|
20
17
|
},
|
|
21
18
|
"paths": {
|
|
22
19
|
"client": "client",
|
|
23
|
-
"
|
|
24
|
-
"domains": "domains",
|
|
25
|
-
"stores": "stores"
|
|
26
|
-
},
|
|
20
|
+
"domains": "domains",
|
|
27
21
|
"public": "public",
|
|
28
22
|
"server": "server",
|
|
29
23
|
"static": "static"
|