primate 0.6.0 → 0.6.3

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 CHANGED
@@ -1,6 +1,8 @@
1
1
  # Primate, A JavaScript Framework
2
2
 
3
- A full-stack Javascript framework with batteries included, Primate relieves you of dealing with repetitive, error-prone tasks and lets you concentrate on writing effective, expressive code.
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.
4
6
 
5
7
  ## Installing
6
8
 
@@ -14,7 +16,9 @@ npm install primate
14
16
  * Secure by default with HTTPS, hash-verified scripts and a strong CSP
15
17
  * Built-in support for sessions with secure cookies
16
18
  * Input verification using data domains
17
- * Many different data store modules: In-Memory (built-in), [File][primate-store-file], [JSON][primate-store-json], [MongoDB][primate-store-mongodb]
19
+ * Many different data store modules: In-Memory (built-in),
20
+ [File][primate-store-file], [JSON][primate-store-json],
21
+ [MongoDB][primate-store-mongodb]
18
22
  * Easy modelling of`1:1`, `1:n` and `n:m` relationships
19
23
  * Minimally opinionated with sane, overrideable defaults
20
24
  * No dependencies
@@ -23,11 +27,6 @@ npm install primate
23
27
 
24
28
  See the [getting started][getting-started] guide.
25
29
 
26
- ## Resources
27
-
28
- * [Source code][source-code]
29
- * [Issues][issues]
30
-
31
30
  ## License
32
31
 
33
32
  BSD-3-Clause
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "primate",
3
- "version": "0.6.0",
3
+ "version": "0.6.3",
4
4
  "author": "Primate core team <core@primatejs.com>",
5
5
  "homepage": "https://primatejs.com",
6
6
  "bugs": "https://github.com/primatejs/primate/issues",
7
7
  "repository": "https://github.com/primatejs/primate",
8
- "description": "Server-client framework",
8
+ "description": "Full-stack JavaScript framework",
9
9
  "license": "BSD-3-Clause",
10
10
  "scripts": {
11
11
  "copy": "rm -rf output && mkdir output && cp source/* output -a",
package/source/App.js CHANGED
@@ -4,26 +4,12 @@ import File from "./File.js";
4
4
  import Directory from "./Directory.js";
5
5
  import Router from "./Router.js";
6
6
  import Server from "./Server.js";
7
- import cache from "./cache.js";
8
7
  import log from "./log.js";
9
8
  import package_json from "../package.json" assert {"type": "json"};
10
9
 
11
10
  export default class App {
12
11
  constructor(conf) {
13
12
  this.conf = conf;
14
- this.Bundler = Bundler;
15
- }
16
-
17
- get routes() {
18
- return cache(this, "routes", async () => {
19
- try {
20
- const path = `${this.conf.root}/routes.json`;
21
- return (await import(path, {"assert": {"type": "json"}})).default;
22
- } catch (error) {
23
- // local routes.json not required
24
- return [];
25
- }
26
- });
27
13
  }
28
14
 
29
15
  async run() {
@@ -33,9 +19,9 @@ export default class App {
33
19
  for (const route of routes) {
34
20
  await import(`${this.conf.paths.routes}/${route}`);
35
21
  }
36
- const index = await new this.Bundler(this.conf).bundle();
22
+ await new Bundler(this.conf).bundle();
37
23
 
38
- const conf = {index, "router": Router,
24
+ const conf = {"router": Router,
39
25
  "serve_from": this.conf.paths.public,
40
26
  "http": {
41
27
  ...this.conf.http,
@@ -45,12 +31,6 @@ export default class App {
45
31
  };
46
32
  this.server = new Server(conf);
47
33
  await this.server.run();
48
-
49
- const {port, host} = this.conf.http;
50
- this.server.listen(port, host);
51
- }
52
-
53
- stop() {
54
- this.server.close();
34
+ this.server.listen();
55
35
  }
56
36
  }
package/source/Bundler.js CHANGED
@@ -35,9 +35,17 @@ export default class Bundler {
35
35
  await this.copy_with_preset("static", paths.public);
36
36
 
37
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
38
  await File.remove(`${paths.public}/${this.index}`);
40
-
41
- return index_html;
42
39
  }
43
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
+ };
@@ -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
- if (property === "bind") {
15
- return result;
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 =>
package/source/Router.js CHANGED
@@ -14,9 +14,14 @@ export default {
14
14
  "get": (path, callback) => push("get", path, callback),
15
15
  "post": (path, callback) => push("post", path, callback),
16
16
  "alias": (key, value) => aliases.push({key, value}),
17
- "process": async request => {
18
- const {pathname, method} = request;
19
- request.path = pathname.split("/").filter(path => path !== "");
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
+ };
20
25
  const verb = find(method, pathname, () => http404``);
21
26
  return verb(await find("map", pathname, _ => _)(request));
22
27
  },
package/source/Server.js CHANGED
@@ -1,14 +1,13 @@
1
1
  import zlib from "zlib";
2
- import {Readable} from "stream";
3
2
  import {createServer} from "https";
4
3
  import {join} from "path";
5
4
  import {parse} from "url";
6
5
  import Session from "./Session.js";
7
6
  import File from "./File.js";
8
- import {algorithm, hash} from "./crypto.js";
9
7
  import log from "./log.js";
10
8
  import codes from "./http-codes.json" assert {"type": "json"};
11
9
  import mimes from "./mimes.json" assert {"type": "json"};
10
+ import {http404} from "./handlers/http.js";
12
11
 
13
12
  const regex = /\.([a-z1-9]*)$/u;
14
13
  const mime = filename => mimes[filename.match(regex)[1]] ?? mimes.binary;
@@ -46,7 +45,7 @@ export default class Server {
46
45
  }
47
46
 
48
47
  const data = Buffer.concat(buffers).toString();
49
- const payload = Object.fromEntries(data
48
+ const payload = Object.fromEntries(decodeURI(data).replaceAll("+", " ")
50
49
  .split("&")
51
50
  .map(part => part.split("="))
52
51
  .filter(([, value]) => value !== ""));
@@ -59,7 +58,6 @@ export default class Server {
59
58
  await this.serve(url, request, response, payload);
60
59
  } catch (error) {
61
60
  console.log(error);
62
- // await response.session.log("red", error.message);
63
61
  response.writeHead(codes.InternalServerError);
64
62
  response.end();
65
63
  }
@@ -77,26 +75,30 @@ export default class Server {
77
75
  const file = await new File(filename);
78
76
  return await file.is_file
79
77
  ? this.serve_file(url, filename, file, response, payload)
80
- : this.serve_data(url, request, response, payload);
78
+ : this.serve_route(url, request, response, payload);
81
79
  }
82
80
 
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);
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
92
  }
93
+ const {body, code} = result;
93
94
  response.setHeader("Content-Security-Policy", this.csp);
94
95
  response.setHeader("Referrer-Policy", "same-origin");
95
96
  response.writeHead(code);
96
- response.end(result);
97
+ response.end(body);
97
98
  }
98
99
 
99
- listen(port, host) {
100
+ listen() {
101
+ const {port, host} = this.conf.http;
100
102
  log.reset("on").yellow(`https://${host}:${port}`).nl();
101
103
  this.server.listen(port, host);
102
104
  }
package/source/exports.js CHANGED
@@ -8,7 +8,6 @@ export {default as File} from "./File.js";
8
8
  export {default as EagerPromise, eager} from "./EagerPromise.js" ;
9
9
 
10
10
  export {default as Domain} from "./domain/Domain.js";
11
- export {default as domains} from "./domain/domains.js";
12
11
  export {default as Storeable} from "./types/Storeable.js";
13
12
 
14
13
  export * from "./errors.js";
@@ -22,7 +21,9 @@ export {default as extend_object} from "./extend_object.js";
22
21
  export {default as sanitize} from "./sanitize.js";
23
22
 
24
23
  export {default as html} from "./handlers/html.js";
24
+ export {default as json} from "./handlers/json.js";
25
25
  export {default as redirect} from "./handlers/redirect.js";
26
+
26
27
  export {default as router} from "./Router.js";
27
28
 
28
29
  const app = new App(conf());
@@ -89,7 +89,7 @@ export default class Node {
89
89
  }
90
90
  }
91
91
 
92
- as_tag() {
92
+ async render() {
93
93
  let tag = "<" + this.tag_name;
94
94
  for (const [key, value] of Object.entries(this.attributes)) {
95
95
  if (value === undefined) {
@@ -109,20 +109,16 @@ export default class Node {
109
109
  } else {
110
110
  tag += ">";
111
111
  for (const child of this.children) {
112
- tag += child.as_tag();
112
+ tag += await child.render();
113
113
  }
114
114
  if (this.text) {
115
- tag += this.text;
115
+ tag += await this.text;
116
116
  }
117
117
  tag += "</" + this.tag_name + ">";
118
118
  }
119
119
  return tag;
120
120
  }
121
121
 
122
- render() {
123
- return this.as_tag();
124
- }
125
-
126
122
  compose(components) {
127
123
  if (components[this.tag_name]) {
128
124
  return Parser.parse(components[this.tag_name], this.attributes);
@@ -144,11 +140,11 @@ export default class Node {
144
140
  }
145
141
  }
146
142
 
147
- expand() {
143
+ async expand() {
148
144
  if (this.attributes["data-for"] !== undefined) {
149
145
  const key = this.attributes["data-for"];
150
146
  delete this.attributes["data-for"];
151
- const value = this.data[key];
147
+ const value = await this.data[key];
152
148
  const arr = Array.isArray(value) ? value : [value];
153
149
  const newparent = new Node();
154
150
  for (const val of arr) {
@@ -168,16 +164,15 @@ export default class Node {
168
164
  this.text = fulfilled;
169
165
  }
170
166
  break;
171
- case "data-href":
172
- fulfill(this.attributes[attribute], this.data);
173
- this.attributes.href = fulfilled;
167
+ default:
168
+ this.attributes[attribute.slice(5)] = fulfilled;
174
169
  break;
175
170
  }
176
171
  delete this.attributes[attribute];
177
172
  }
178
173
  }
179
174
  for (let i = 0; i < this.children.length; i++) {
180
- this.children[i] = this.children[i].expand();
175
+ this.children[i] = await this.children[i].expand();
181
176
  }
182
177
  return this;
183
178
  }
@@ -1,10 +1,12 @@
1
1
  import Parser from "./DOM/Parser.js";
2
- import conf from "../conf.js";
3
2
  import Directory from "../Directory.js";
4
3
  import File from "../File.js";
4
+ import {index} from "../Bundler.js";
5
+ import _conf from "../conf.js";
6
+ const conf = _conf();
5
7
 
6
8
  const last = -1;
7
- const {paths: {"components": path}} = conf();
9
+ const {"paths": {"components": path}} = conf;
8
10
  const components = {};
9
11
  if (await File.exists(path)) {
10
12
  const names = await Directory.list(path);
@@ -15,12 +17,13 @@ if (await File.exists(path)) {
15
17
 
16
18
  export default async (strings, ...keys) => {
17
19
  const awaited_keys = await Promise.all(keys);
18
- const body = Parser.parse(strings
20
+ const rendered = await (await Parser.parse(strings
19
21
  .slice(0, last)
20
22
  .map((string, i) => `${string}$${i}`)
21
23
  .join("") + strings[strings.length+last], awaited_keys)
22
- .unfold(components)
24
+ .unfold(components))
23
25
  .render();
26
+ const body = (await index(conf)).replace("<body>", () => `<body>${rendered}`);
24
27
  const code = 200;
25
28
  const headers = {"Content-Type": "text/html"};
26
29
  return {code, body, headers};
@@ -0,0 +1,6 @@
1
+ export default async (strings, ...keys) => {
2
+ const body = JSON.stringify(await keys[0]);
3
+ const headers = {"Content-Type": "application/json"};
4
+ const code = 200;
5
+ return {body, code, headers};
6
+ };
@@ -1,9 +1,6 @@
1
1
  {
2
2
  "base": "/",
3
3
  "debug": false,
4
- "defaults": {
5
- "context": "guest"
6
- },
7
4
  "files": {
8
5
  "index": "index.html"
9
6
  },
@@ -24,7 +21,6 @@
24
21
  "same-site": "Strict"
25
22
  },
26
23
  "paths": {
27
- "domains": "domains",
28
24
  "public": "public",
29
25
  "static": "static",
30
26
  "routes": "routes",
@@ -1,31 +0,0 @@
1
- import conf from "../conf.js";
2
- import File from "../File.js";
3
- import Field from "./Field.js";
4
- import Domain from "./Domain.js";
5
-
6
- const domains = {};
7
- const base = conf().paths.domains;
8
-
9
- for (const domain of await new File(base).list(".js")) {
10
- const name = domain.slice(0, -3);
11
- import(`${base}/${domain}`).then(module => {
12
- domains[name] = module.default;
13
- });
14
- }
15
-
16
- export const actuals = {};
17
- for (const domain in domains) {
18
- if (domains[domain].prototype instanceof Domain) {
19
- const fields = {};
20
- for (const field in domains[domain]._fields) {
21
- const Type = domains[domain]._fields[field].Type;
22
- if(Type.prototype instanceof Domain) {
23
- fields[field.slice(0, -3)] = Type.name;
24
- }
25
- }
26
- actuals[domain] = fields;
27
- }
28
- }
29
-
30
-
31
- export default domains;