primate 0.11.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 +176 -65
- 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/{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/basic.js +1 -1
- 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 +1 -1
- package/src/config.js +48 -0
- package/src/duck.js +4 -0
- package/src/extend.spec.js +19 -27
- package/src/http-statuses.js +5 -0
- package/src/log.js +7 -4
- package/src/mimes.js +12 -0
- package/src/respond.js +24 -0
- package/src/route.js +3 -23
- package/src/run.js +5 -5
- package/src/serve.js +25 -12
- package/README.template.md +0 -190
- package/bin/primate.js +0 -5
- package/src/conf.js +0 -30
- 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/readme/{modules → extensions/modules}/configure.js +0 -0
- /package/readme/{modules → extensions/modules}/domains/configure.js +0 -0
- /package/src/{preset/primate.conf.js → primate.config.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,7 +21,7 @@ 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)
|
|
@@ -30,13 +30,17 @@ Add `{"type": "module"}` to your `package.json` and run `npx primate`.
|
|
|
30
30
|
- [Named groups](#named-groups)
|
|
31
31
|
- [Aliasing](#aliasing)
|
|
32
32
|
- [Sharing logic across requests](#sharing-logic-across-requests)
|
|
33
|
-
- [
|
|
34
|
-
|
|
35
|
-
- [
|
|
33
|
+
- [Extensions](#extensions)
|
|
34
|
+
- [Handlers](#handlers)
|
|
35
|
+
- [HTML](#html)
|
|
36
|
+
- [Redirect](#redirect)
|
|
37
|
+
- [HTMX](#htmx)
|
|
38
|
+
- [Modules](#modules)
|
|
39
|
+
- [Data persistance](#data-persistance)
|
|
36
40
|
|
|
37
41
|
## Serving content
|
|
38
42
|
|
|
39
|
-
Create a file in `routes` that exports a default function
|
|
43
|
+
Create a file in `routes` that exports a default function.
|
|
40
44
|
|
|
41
45
|
### Plain text
|
|
42
46
|
|
|
@@ -72,39 +76,20 @@ export default router => {
|
|
|
72
76
|
import {File} from "runtime-compat/filesystem";
|
|
73
77
|
|
|
74
78
|
export default router => {
|
|
75
|
-
// `File` implements `readable`, which is a ReadableStream
|
|
79
|
+
// `File` implements `readable`, which is a `ReadableStream`
|
|
76
80
|
router.get("/users", () => new File("users.json"));
|
|
77
81
|
};
|
|
78
82
|
|
|
79
83
|
```
|
|
80
84
|
|
|
81
|
-
###
|
|
82
|
-
|
|
83
|
-
Create an HTML component in `components/user-index.html`
|
|
84
|
-
|
|
85
|
-
```html
|
|
86
|
-
<div for="${users}">
|
|
87
|
-
User ${name}.
|
|
88
|
-
Email ${email}.
|
|
89
|
-
</div>
|
|
90
|
-
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
Serve the component in your route
|
|
85
|
+
### Response
|
|
94
86
|
|
|
95
87
|
```js
|
|
96
|
-
import
|
|
88
|
+
import {Response} from "runtime-compat/http";
|
|
97
89
|
|
|
98
90
|
export default router => {
|
|
99
|
-
//
|
|
100
|
-
|
|
101
|
-
router.get("/users", () => {
|
|
102
|
-
const users = [
|
|
103
|
-
{name: "Donald", email: "donald@the.duck"},
|
|
104
|
-
{name: "Joe", email: "joe@was.absent"},
|
|
105
|
-
];
|
|
106
|
-
return html`<user-index users="${users}" />`;
|
|
107
|
-
});
|
|
91
|
+
// use a generic response instance for a custom response status
|
|
92
|
+
router.get("/create", () => new Response("created!", {status: 201}));
|
|
108
93
|
};
|
|
109
94
|
|
|
110
95
|
```
|
|
@@ -115,13 +100,9 @@ Routes map requests to responses. They are loaded from `routes`.
|
|
|
115
100
|
|
|
116
101
|
### Basic
|
|
117
102
|
|
|
118
|
-
To start serving content, create a file in `routes` returning a function as its
|
|
119
|
-
default export. This function has a `router` param used to configure HTTP
|
|
120
|
-
routes.
|
|
121
|
-
|
|
122
103
|
```js
|
|
123
104
|
export default router => {
|
|
124
|
-
// accessing /site/login will serve
|
|
105
|
+
// accessing /site/login will serve `Hello, world!` as plain text
|
|
125
106
|
router.get("/site/login", () => "Hello, world!");
|
|
126
107
|
};
|
|
127
108
|
|
|
@@ -137,6 +118,20 @@ export default router => {
|
|
|
137
118
|
|
|
138
119
|
```
|
|
139
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
|
+
|
|
140
135
|
### Regular expressions
|
|
141
136
|
|
|
142
137
|
```js
|
|
@@ -203,54 +198,166 @@ export default router => {
|
|
|
203
198
|
|
|
204
199
|
```
|
|
205
200
|
|
|
206
|
-
##
|
|
201
|
+
## Extensions
|
|
207
202
|
|
|
208
|
-
Primate
|
|
209
|
-
|
|
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
|
+
```
|
|
228
|
+
|
|
229
|
+
Create a route in `route/user.js` and serve the component in your route
|
|
210
230
|
|
|
211
231
|
```js
|
|
212
|
-
import
|
|
232
|
+
import html from "@primate/html";
|
|
213
233
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
}
|
|
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.
|
|
223
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
|
+
};
|
|
224
263
|
|
|
225
264
|
```
|
|
226
265
|
|
|
227
|
-
|
|
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
|
+
```
|
|
228
282
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
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";
|
|
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
|
+
};
|
|
322
|
+
|
|
323
|
+
```
|
|
324
|
+
|
|
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
|
|
332
|
+
|
|
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
|
|
232
343
|
|
|
233
344
|
```js
|
|
234
345
|
import {Domain} from "@primate/domains";
|
|
235
|
-
import House from "./House.js";
|
|
236
346
|
|
|
347
|
+
// A basic domain with two properies
|
|
237
348
|
export default class User extends Domain {
|
|
238
349
|
static fields = {
|
|
239
|
-
// a user's name
|
|
350
|
+
// a user's name is a string
|
|
240
351
|
name: String,
|
|
241
|
-
// a user's age
|
|
352
|
+
// a user's age is a number
|
|
242
353
|
age: Number,
|
|
243
|
-
// a user's house must have the foreign id of a house record
|
|
244
|
-
house_id: House,
|
|
245
354
|
};
|
|
246
355
|
}
|
|
247
356
|
|
|
248
357
|
```
|
|
249
358
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
Field types may also be specified as an array, to specify additional predicates
|
|
253
|
-
aside from the type.
|
|
359
|
+
Field types may also be specified as an array with additional predicates
|
|
360
|
+
aside from the type
|
|
254
361
|
|
|
255
362
|
```js
|
|
256
363
|
import {Domain} from "@primate/domains";
|
|
@@ -258,11 +365,11 @@ import House from "./House.js";
|
|
|
258
365
|
|
|
259
366
|
export default class User extends Domain {
|
|
260
367
|
static fields = {
|
|
261
|
-
// a user's name
|
|
368
|
+
// a user's name is a string unique across the user collection
|
|
262
369
|
name: [String, "unique"],
|
|
263
|
-
// a user's age
|
|
370
|
+
// a user's age is a positive integer
|
|
264
371
|
age: [Number, "integer", "positive"],
|
|
265
|
-
// a user's house
|
|
372
|
+
// a user's house has the foreign id of a house record and no two
|
|
266
373
|
// users may have the same house
|
|
267
374
|
house_id: [House, "unique"],
|
|
268
375
|
};
|
|
@@ -279,4 +386,8 @@ export default class User extends Domain {
|
|
|
279
386
|
|
|
280
387
|
MIT
|
|
281
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
|
|
282
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