primate 0.10.0 → 0.12.0
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/LICENSE +0 -2
- package/README.md +178 -68
- package/exports.js +1 -3
- package/module.json +4 -4
- package/package.json +9 -9
- package/readme/extensions/handlers/htmx/user-index.html +4 -0
- package/readme/extensions/handlers/htmx/user.js +23 -0
- package/readme/extensions/handlers/redirect/user.js +6 -0
- package/readme/extensions/modules/configure.js +3 -0
- package/readme/extensions/modules/domains/configure.js +5 -0
- package/readme/{domains → extensions/modules/domains}/fields.js +3 -4
- package/readme/{domains → extensions/modules/domains}/predicates.js +3 -3
- package/readme/{domains → extensions/modules/domains}/short-field-notation.js +3 -3
- package/readme/routing/accessing-the-request-body.js +3 -0
- package/readme/routing/basic.js +2 -5
- package/readme/serving-content/response.js +6 -0
- package/readme/serving-content/streams.js +1 -1
- package/readme/template.md +226 -0
- package/scripts/docs.sh +7 -0
- package/src/bin.js +2 -0
- package/src/bundle.js +3 -4
- package/src/config.js +48 -0
- package/src/duck.js +4 -0
- package/src/extend.spec.js +19 -27
- package/src/handlers/http404.js +2 -5
- package/src/handlers/json.js +2 -5
- package/src/handlers/stream.js +2 -5
- package/src/handlers/text.js +2 -5
- package/src/http-statuses.js +5 -0
- package/src/log.js +8 -1
- package/src/mimes.js +12 -0
- package/src/{preset/primate.js → primate.config.js} +1 -0
- package/src/respond.js +24 -0
- package/src/route.js +6 -20
- package/src/run.js +7 -16
- package/src/serve.js +35 -25
- package/README.template.md +0 -149
- package/bin/primate.js +0 -5
- package/src/conf.js +0 -27
- package/src/http-statuses.json +0 -5
- package/src/mimes.json +0 -12
- package/src/preset/stores/default.js +0 -2
- /package/readme/{serving-content → extensions/handlers/html}/user-index.html +0 -0
- /package/readme/{serving-content/html.js → extensions/handlers/html/user.js} +0 -0
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Primate
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Expressive, minimal and extensible framework for JavaScript.
|
|
4
4
|
|
|
5
5
|
## Getting started
|
|
6
6
|
|
|
@@ -13,7 +13,7 @@ export default router => {
|
|
|
13
13
|
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
Add `{"type": "module"}` to your `package.json` and run `npx primate`.
|
|
16
|
+
Add `{"type": "module"}` to your `package.json` and run `npx -y primate@latest`.
|
|
17
17
|
|
|
18
18
|
## Table of Contents
|
|
19
19
|
|
|
@@ -21,21 +21,26 @@ Add `{"type": "module"}` to your `package.json` and run `npx primate`.
|
|
|
21
21
|
- [Plain text](#plain-text)
|
|
22
22
|
- [JSON](#json)
|
|
23
23
|
- [Streams](#streams)
|
|
24
|
-
- [
|
|
24
|
+
- [Response](#response)
|
|
25
25
|
- [Routing](#routing)
|
|
26
26
|
- [Basic](#basic)
|
|
27
27
|
- [The request object](#the-request-object)
|
|
28
|
+
- [Accessing the request body](#accessing-the-request-body)
|
|
28
29
|
- [Regular expressions](#regular-expressions)
|
|
29
30
|
- [Named groups](#named-groups)
|
|
30
31
|
- [Aliasing](#aliasing)
|
|
31
32
|
- [Sharing logic across requests](#sharing-logic-across-requests)
|
|
32
|
-
- [
|
|
33
|
-
|
|
34
|
-
- [
|
|
33
|
+
- [Extensions](#extensions)
|
|
34
|
+
- [Handlers](#handlers)
|
|
35
|
+
- [HTML](#html)
|
|
36
|
+
- [Redirect](#redirect)
|
|
37
|
+
- [HTMX](#htmx)
|
|
38
|
+
- [Modules](#modules)
|
|
39
|
+
- [Data persistance](#data-persistance)
|
|
35
40
|
|
|
36
41
|
## Serving content
|
|
37
42
|
|
|
38
|
-
Create a file in `routes` that exports a default function
|
|
43
|
+
Create a file in `routes` that exports a default function.
|
|
39
44
|
|
|
40
45
|
### Plain text
|
|
41
46
|
|
|
@@ -71,39 +76,20 @@ export default router => {
|
|
|
71
76
|
import {File} from "runtime-compat/filesystem";
|
|
72
77
|
|
|
73
78
|
export default router => {
|
|
74
|
-
// `File` implements `readable`, which is a ReadableStream
|
|
79
|
+
// `File` implements `readable`, which is a `ReadableStream`
|
|
75
80
|
router.get("/users", () => new File("users.json"));
|
|
76
81
|
};
|
|
77
82
|
|
|
78
83
|
```
|
|
79
84
|
|
|
80
|
-
###
|
|
81
|
-
|
|
82
|
-
Create an HTML component in `components/user-index.html`
|
|
83
|
-
|
|
84
|
-
```html
|
|
85
|
-
<div for="${users}">
|
|
86
|
-
User ${name}.
|
|
87
|
-
Email ${email}.
|
|
88
|
-
</div>
|
|
89
|
-
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
Serve the component in your route
|
|
85
|
+
### Response
|
|
93
86
|
|
|
94
87
|
```js
|
|
95
|
-
import
|
|
88
|
+
import {Response} from "runtime-compat/http";
|
|
96
89
|
|
|
97
90
|
export default router => {
|
|
98
|
-
//
|
|
99
|
-
|
|
100
|
-
router.get("/users", () => {
|
|
101
|
-
const users = [
|
|
102
|
-
{name: "Donald", email: "donald@the.duck"},
|
|
103
|
-
{name: "Joe", email: "joe@was.absent"},
|
|
104
|
-
];
|
|
105
|
-
return html`<user-index users="${users}" />`;
|
|
106
|
-
});
|
|
91
|
+
// use a generic response instance for a custom response status
|
|
92
|
+
router.get("/create", () => new Response("created!", {status: 201}));
|
|
107
93
|
};
|
|
108
94
|
|
|
109
95
|
```
|
|
@@ -112,18 +98,12 @@ export default router => {
|
|
|
112
98
|
|
|
113
99
|
Routes map requests to responses. They are loaded from `routes`.
|
|
114
100
|
|
|
115
|
-
The order in which routes are declared is irrelevant. Redeclaring a route
|
|
116
|
-
(same pathname and same HTTP verb) throws an error.
|
|
117
|
-
|
|
118
101
|
### Basic
|
|
119
102
|
|
|
120
103
|
```js
|
|
121
|
-
import html from "@primate/html";
|
|
122
|
-
|
|
123
104
|
export default router => {
|
|
124
|
-
// accessing /site/login will serve
|
|
125
|
-
|
|
126
|
-
router.get("/site/login", () => html`<site-login />`);
|
|
105
|
+
// accessing /site/login will serve `Hello, world!` as plain text
|
|
106
|
+
router.get("/site/login", () => "Hello, world!");
|
|
127
107
|
};
|
|
128
108
|
|
|
129
109
|
```
|
|
@@ -138,6 +118,20 @@ export default router => {
|
|
|
138
118
|
|
|
139
119
|
```
|
|
140
120
|
|
|
121
|
+
### Accessing the request body
|
|
122
|
+
|
|
123
|
+
For requests containing a body, Primate will attempt to parse the body according
|
|
124
|
+
to the content type sent along the request. Currently supported are
|
|
125
|
+
`application/x-www-form-urlencoded` (typically for form submission) and
|
|
126
|
+
`application/json`.
|
|
127
|
+
|
|
128
|
+
```js
|
|
129
|
+
export default router => {
|
|
130
|
+
router.post("/site/login", ({body}) => `submitted user: ${body.username}`);
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
|
|
141
135
|
### Regular expressions
|
|
142
136
|
|
|
143
137
|
```js
|
|
@@ -204,54 +198,166 @@ export default router => {
|
|
|
204
198
|
|
|
205
199
|
```
|
|
206
200
|
|
|
207
|
-
##
|
|
201
|
+
## Extensions
|
|
202
|
+
|
|
203
|
+
There are two ways to extend Primate's core functionality. Handlers are used
|
|
204
|
+
per route to serve new types of content not supported by core. Modules extend
|
|
205
|
+
an app's entire scope.
|
|
206
|
+
|
|
207
|
+
Handlers and modules listed here are officially developed and supported by
|
|
208
|
+
Primate.
|
|
209
|
+
|
|
210
|
+
### Handlers
|
|
211
|
+
|
|
212
|
+
#### HTML
|
|
213
|
+
|
|
214
|
+
*[`@primate/html`][primate-html]*
|
|
215
|
+
|
|
216
|
+
Serve HTML tagged templates. This handler reads HTML component files from
|
|
217
|
+
`components`.
|
|
218
|
+
|
|
219
|
+
Create an HTML component in `components/user-index.html`
|
|
220
|
+
|
|
221
|
+
```html
|
|
222
|
+
<div for="${users}">
|
|
223
|
+
User ${name}.
|
|
224
|
+
Email ${email}.
|
|
225
|
+
</div>
|
|
226
|
+
|
|
227
|
+
```
|
|
208
228
|
|
|
209
|
-
|
|
210
|
-
collection in a store using the class `fields` property.
|
|
229
|
+
Create a route in `route/user.js` and serve the component in your route
|
|
211
230
|
|
|
212
231
|
```js
|
|
213
|
-
import
|
|
232
|
+
import html from "@primate/html";
|
|
214
233
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
}
|
|
234
|
+
export default router => {
|
|
235
|
+
// the HTML tagged template handler loads a component from the `components`
|
|
236
|
+
// directory and serves it as HTML, passing any given data as attributes
|
|
237
|
+
router.get("/users", () => {
|
|
238
|
+
const users = [
|
|
239
|
+
{name: "Donald", email: "donald@the.duck"},
|
|
240
|
+
{name: "Joe", email: "joe@was.absent"},
|
|
241
|
+
];
|
|
242
|
+
return html`<user-index users="${users}" />`;
|
|
243
|
+
});
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
#### Redirect
|
|
249
|
+
|
|
250
|
+
*[`@primate/redirect`][primate-redirect]*
|
|
251
|
+
|
|
252
|
+
Redirect the request.
|
|
253
|
+
|
|
254
|
+
Create a route in `route/user.js`
|
|
255
|
+
|
|
256
|
+
```js
|
|
257
|
+
import redirect from "@primate/html";
|
|
258
|
+
|
|
259
|
+
export default router => {
|
|
260
|
+
// redirect the request
|
|
261
|
+
router.get("/user", () => redirect`/users`);
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
#### HTMX
|
|
267
|
+
|
|
268
|
+
*[`@primate/htmx`][primate-htmx]*
|
|
269
|
+
|
|
270
|
+
Serve HTML tagged templates with HTMX support. This handler reads HTML component
|
|
271
|
+
files from `components`.
|
|
272
|
+
|
|
273
|
+
Create an HTML component in `components/user-index.html`
|
|
274
|
+
|
|
275
|
+
```html
|
|
276
|
+
<div for="${users}" hx-get="/other-users" hx-swap="outerHTML">
|
|
277
|
+
User ${name}.
|
|
278
|
+
Email ${email}.
|
|
279
|
+
</div>
|
|
280
|
+
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Create a route in `route/user.js` and serve the component in your route
|
|
284
|
+
|
|
285
|
+
```js
|
|
286
|
+
import {default as htmx, partial} from "@primate/htmx";
|
|
224
287
|
|
|
288
|
+
export default router => {
|
|
289
|
+
// the HTML tagged template handler loads a component from the `components`
|
|
290
|
+
// directory and serves it as HTML, passing any given data as attributes
|
|
291
|
+
router.get("/users", () => {
|
|
292
|
+
const users = [
|
|
293
|
+
{name: "Donald", email: "donald@the.duck"},
|
|
294
|
+
{name: "Joe", email: "joe@was.absent"},
|
|
295
|
+
];
|
|
296
|
+
return htmx`<user-index users="${users}" />`;
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
// this is the same as above, with support for partial rendering (without
|
|
300
|
+
// index.html)
|
|
301
|
+
router.get("/other-users", () => {
|
|
302
|
+
const users = [
|
|
303
|
+
{name: "Other Donald", email: "donald@the.goose"},
|
|
304
|
+
{name: "Other Joe", email: "joe@was.around"},
|
|
305
|
+
];
|
|
306
|
+
return partial`<user-index users="${users}" />`;
|
|
307
|
+
});
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### Modules
|
|
313
|
+
|
|
314
|
+
To add modules, create a `primate.config.js` configuration file in your
|
|
315
|
+
project's root. This file should export a default object with the property
|
|
316
|
+
`modules` used for extending your app.
|
|
317
|
+
|
|
318
|
+
```js
|
|
319
|
+
export default {
|
|
320
|
+
modules: [],
|
|
321
|
+
};
|
|
225
322
|
|
|
226
323
|
```
|
|
227
324
|
|
|
228
|
-
|
|
325
|
+
#### Data persistance
|
|
326
|
+
|
|
327
|
+
*[`@primate/domains`][primate-domains]*
|
|
328
|
+
|
|
329
|
+
Add data persistance in the form of ORM backed up by various drivers.
|
|
330
|
+
|
|
331
|
+
Import and initialize this module in your configuration file
|
|
229
332
|
|
|
230
|
-
|
|
231
|
-
domains
|
|
232
|
-
|
|
333
|
+
```js
|
|
334
|
+
import domains from "@primate/domains";
|
|
335
|
+
|
|
336
|
+
export default {
|
|
337
|
+
modules: [domains()],
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
A domain represents a collection in a store using the static `fields` property
|
|
233
343
|
|
|
234
344
|
```js
|
|
235
345
|
import {Domain} from "@primate/domains";
|
|
236
|
-
import House from "./House.js";
|
|
237
346
|
|
|
347
|
+
// A basic domain with two properies
|
|
238
348
|
export default class User extends Domain {
|
|
239
349
|
static fields = {
|
|
240
|
-
// a user's name
|
|
350
|
+
// a user's name is a string
|
|
241
351
|
name: String,
|
|
242
|
-
// a user's age
|
|
352
|
+
// a user's age is a number
|
|
243
353
|
age: Number,
|
|
244
|
-
// a user's house must have the foreign id of a house record
|
|
245
|
-
house_id: House,
|
|
246
354
|
};
|
|
247
355
|
}
|
|
248
356
|
|
|
249
357
|
```
|
|
250
358
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
Field types may also be specified as an array, to specify additional predicates
|
|
254
|
-
aside from the type.
|
|
359
|
+
Field types may also be specified as an array with additional predicates
|
|
360
|
+
aside from the type
|
|
255
361
|
|
|
256
362
|
```js
|
|
257
363
|
import {Domain} from "@primate/domains";
|
|
@@ -259,11 +365,11 @@ import House from "./House.js";
|
|
|
259
365
|
|
|
260
366
|
export default class User extends Domain {
|
|
261
367
|
static fields = {
|
|
262
|
-
// a user's name
|
|
368
|
+
// a user's name is a string unique across the user collection
|
|
263
369
|
name: [String, "unique"],
|
|
264
|
-
// a user's age
|
|
370
|
+
// a user's age is a positive integer
|
|
265
371
|
age: [Number, "integer", "positive"],
|
|
266
|
-
// a user's house
|
|
372
|
+
// a user's house has the foreign id of a house record and no two
|
|
267
373
|
// users may have the same house
|
|
268
374
|
house_id: [House, "unique"],
|
|
269
375
|
};
|
|
@@ -280,4 +386,8 @@ export default class User extends Domain {
|
|
|
280
386
|
|
|
281
387
|
MIT
|
|
282
388
|
|
|
389
|
+
[primate-html]: https://github.com/primatejs/primate-html
|
|
390
|
+
[primate-redirect]: https://github.com/primatejs/primate-redirect
|
|
391
|
+
[primate-htmx]: https://github.com/primatejs/primate-htmx
|
|
283
392
|
[primate-domains]: https://github.com/primatejs/primate-domains
|
|
393
|
+
[primate-sessions]: https://github.com/primatejs/primate-sessions
|
package/exports.js
CHANGED
package/module.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "primate",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
3
|
+
"version": "0.11.0",
|
|
4
|
+
"homepage": "https://primatejs.com",
|
|
5
5
|
"bugs": "https://github.com/primatejs/primate/issues",
|
|
6
6
|
"repository": "https://github.com/primatejs/primate",
|
|
7
|
-
"description": "
|
|
7
|
+
"description": "Expressive, minimal and extensible framework for JavaScript",
|
|
8
8
|
"license": "MIT",
|
|
9
|
-
"bin": "bin
|
|
9
|
+
"bin": "src/bin.js"
|
|
10
10
|
}
|
package/package.json
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "primate",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"author": "Terrablue <terrablue@proton.me>",
|
|
3
|
+
"version": "0.12.0",
|
|
5
4
|
"homepage": "https://primatejs.com",
|
|
6
5
|
"bugs": "https://github.com/primatejs/primate/issues",
|
|
7
6
|
"repository": "https://github.com/primatejs/primate",
|
|
8
|
-
"description": "
|
|
7
|
+
"description": "Expressive, minimal and extensible framework for JavaScript",
|
|
9
8
|
"license": "MIT",
|
|
9
|
+
"bin": "src/bin.js",
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"runtime-compat": "^0.
|
|
11
|
+
"runtime-compat": "^0.14.1"
|
|
12
12
|
},
|
|
13
|
-
"bin": "bin/primate.js",
|
|
14
13
|
"devDependencies": {
|
|
15
|
-
"@babel/core": "^7.21.
|
|
16
|
-
"@babel/eslint-parser": "^7.
|
|
14
|
+
"@babel/core": "^7.21.4",
|
|
15
|
+
"@babel/eslint-parser": "^7.21.3",
|
|
17
16
|
"@babel/plugin-syntax-import-assertions": "^7.20.0",
|
|
18
|
-
"eslint": "^8.
|
|
17
|
+
"eslint": "^8.37.0",
|
|
19
18
|
"eslint-plugin-json": "^3.1.0"
|
|
20
19
|
},
|
|
21
20
|
"scripts": {
|
|
22
|
-
"docs": "
|
|
21
|
+
"docs": "scripts/docs.sh",
|
|
22
|
+
"test": "npx debris"
|
|
23
23
|
},
|
|
24
24
|
"type": "module",
|
|
25
25
|
"exports": "./exports.js",
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import {default as htmx, partial} from "@primate/htmx";
|
|
2
|
+
|
|
3
|
+
export default router => {
|
|
4
|
+
// the HTML tagged template handler loads a component from the `components`
|
|
5
|
+
// directory and serves it as HTML, passing any given data as attributes
|
|
6
|
+
router.get("/users", () => {
|
|
7
|
+
const users = [
|
|
8
|
+
{name: "Donald", email: "donald@the.duck"},
|
|
9
|
+
{name: "Joe", email: "joe@was.absent"},
|
|
10
|
+
];
|
|
11
|
+
return htmx`<user-index users="${users}" />`;
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
// this is the same as above, with support for partial rendering (without
|
|
15
|
+
// index.html)
|
|
16
|
+
router.get("/other-users", () => {
|
|
17
|
+
const users = [
|
|
18
|
+
{name: "Other Donald", email: "donald@the.goose"},
|
|
19
|
+
{name: "Other Joe", email: "joe@was.around"},
|
|
20
|
+
];
|
|
21
|
+
return partial`<user-index users="${users}" />`;
|
|
22
|
+
});
|
|
23
|
+
};
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import {Domain} from "@primate/domains";
|
|
2
2
|
|
|
3
|
-
// A basic domain
|
|
3
|
+
// A basic domain with two properies
|
|
4
4
|
export default class User extends Domain {
|
|
5
5
|
static fields = {
|
|
6
|
-
// a user's name
|
|
6
|
+
// a user's name is a string
|
|
7
7
|
name: String,
|
|
8
|
-
// a user's age
|
|
8
|
+
// a user's age is a number
|
|
9
9
|
age: Number,
|
|
10
10
|
};
|
|
11
11
|
}
|
|
12
|
-
|
|
@@ -3,11 +3,11 @@ import House from "./House.js";
|
|
|
3
3
|
|
|
4
4
|
export default class User extends Domain {
|
|
5
5
|
static fields = {
|
|
6
|
-
// a user's name
|
|
6
|
+
// a user's name is a string unique across the user collection
|
|
7
7
|
name: [String, "unique"],
|
|
8
|
-
// a user's age
|
|
8
|
+
// a user's age is a positive integer
|
|
9
9
|
age: [Number, "integer", "positive"],
|
|
10
|
-
// a user's house
|
|
10
|
+
// a user's house has the foreign id of a house record and no two
|
|
11
11
|
// users may have the same house
|
|
12
12
|
house_id: [House, "unique"],
|
|
13
13
|
};
|
|
@@ -3,11 +3,11 @@ import House from "./House.js";
|
|
|
3
3
|
|
|
4
4
|
export default class User extends Domain {
|
|
5
5
|
static fields = {
|
|
6
|
-
// a user's name
|
|
6
|
+
// a user's name is a string
|
|
7
7
|
name: String,
|
|
8
|
-
// a user's age
|
|
8
|
+
// a user's age is a number
|
|
9
9
|
age: Number,
|
|
10
|
-
// a user's house
|
|
10
|
+
// a user's house has the foreign id of a house record
|
|
11
11
|
house_id: House,
|
|
12
12
|
};
|
|
13
13
|
}
|
package/readme/routing/basic.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import html from "@primate/html";
|
|
2
|
-
|
|
3
1
|
export default router => {
|
|
4
|
-
// accessing /site/login will serve
|
|
5
|
-
|
|
6
|
-
router.get("/site/login", () => html`<site-login />`);
|
|
2
|
+
// accessing /site/login will serve `Hello, world!` as plain text
|
|
3
|
+
router.get("/site/login", () => "Hello, world!");
|
|
7
4
|
};
|