@primate/core 0.2.4 → 0.3.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/lib/private/App.d.ts +5 -0
- package/lib/private/App.js +18 -13
- package/lib/private/Binder.d.ts +1 -1
- package/lib/private/BindingContext.d.ts +1 -1
- package/lib/private/BuildApp.d.ts +7 -1
- package/lib/private/BuildApp.js +33 -33
- package/lib/private/Loader.d.ts +1 -1
- package/lib/private/Loader.js +4 -3
- package/lib/private/ServeApp.d.ts +8 -6
- package/lib/private/ServeApp.js +29 -20
- package/lib/private/ServeInit.d.ts +1 -1
- package/lib/private/backend/TAG.d.ts +3 -0
- package/lib/private/backend/TAG.js +2 -0
- package/lib/private/builtin/DevModule.js +1 -3
- package/lib/private/client/Data.d.ts +1 -1
- package/lib/private/client/app.d.ts +2 -0
- package/lib/private/client/{App.js → app.js} +4 -2
- package/lib/private/client/spa/index.js +4 -0
- package/lib/private/database/Query.d.ts +3 -3
- package/lib/private/database/QueryBuilder.d.ts +2 -2
- package/lib/private/database/{DataRecord.d.ts → Schema.d.ts} +3 -3
- package/lib/private/database/Schema.js +3 -0
- package/lib/private/database/Store.d.ts +11 -11
- package/lib/private/frontend/Module.d.ts +2 -2
- package/lib/private/frontend/Module.js +47 -40
- package/lib/private/frontend/Render.d.ts +1 -1
- package/lib/private/frontend/ServerData.d.ts +2 -2
- package/lib/private/frontend/ServerView.d.ts +5 -0
- package/lib/private/frontend/ServerView.js +2 -0
- package/lib/private/frontend/View.d.ts +8 -0
- package/lib/private/frontend/View.js +2 -0
- package/lib/private/frontend/bundle-server.js +3 -3
- package/lib/private/hook/build.js +83 -75
- package/lib/private/i18n/Module.js +16 -3
- package/lib/private/location.d.ts +2 -0
- package/lib/private/location.js +4 -0
- package/lib/private/request/RequestBody.d.ts +8 -7
- package/lib/private/request/RequestBody.js +30 -14
- package/lib/private/response/ResponseFunction.d.ts +2 -2
- package/lib/private/response/redirect.js +5 -1
- package/lib/private/response/view.d.ts +3 -3
- package/lib/private/response/view.js +14 -12
- package/lib/private/route/wrap.d.ts +1 -5
- package/lib/private/route/wrap.js +4 -9
- package/lib/private/target/Manager.js +1 -1
- package/lib/private/target/web.js +0 -10
- package/lib/private/wasm/encode-request.js +25 -28
- package/lib/public/backend/TAG.d.ts +2 -0
- package/lib/public/backend/TAG.js +2 -0
- package/lib/public/client/app.d.ts +2 -0
- package/lib/public/client/app.js +2 -0
- package/lib/public/fail.d.ts +2 -0
- package/lib/public/fail.js +2 -0
- package/package.json +4 -4
- package/lib/private/client/App.d.ts +0 -4
- package/lib/private/database/DataRecord.js +0 -3
- package/lib/private/frontend/Component.d.ts +0 -8
- package/lib/private/frontend/Component.js +0 -2
- package/lib/private/frontend/ServerComponent.d.ts +0 -5
- package/lib/private/frontend/ServerComponent.js +0 -2
- package/lib/public/client/App.d.ts +0 -2
- package/lib/public/client/App.js +0 -2
- package/lib/public/route/wrap.d.ts +0 -2
- package/lib/public/route/wrap.js +0 -2
|
@@ -1,19 +1,26 @@
|
|
|
1
1
|
import fail from "#fail";
|
|
2
2
|
import json from "@rcompat/http/mime/application/json";
|
|
3
3
|
import binary from "@rcompat/http/mime/application/octet-stream";
|
|
4
|
-
import
|
|
5
|
-
import
|
|
4
|
+
import www_form from "@rcompat/http/mime/application/x-www-form-urlencoded";
|
|
5
|
+
import form_data from "@rcompat/http/mime/multipart/form-data";
|
|
6
6
|
import text from "@rcompat/http/mime/text/plain";
|
|
7
|
-
async function
|
|
8
|
-
const
|
|
7
|
+
async function anyform(request) {
|
|
8
|
+
const form = Object.create(null);
|
|
9
|
+
const files = Object.create(null);
|
|
9
10
|
for (const [key, value] of (await request.formData()).entries()) {
|
|
10
|
-
|
|
11
|
+
if (typeof value === "string") {
|
|
12
|
+
form[key] = value;
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
files[key] = value;
|
|
16
|
+
}
|
|
11
17
|
}
|
|
12
|
-
return
|
|
18
|
+
return { form, files };
|
|
13
19
|
}
|
|
14
20
|
;
|
|
15
21
|
export default class RequestBody {
|
|
16
22
|
#parsed;
|
|
23
|
+
#files;
|
|
17
24
|
static async parse(request, url) {
|
|
18
25
|
const raw = request.headers.get("content-type") ?? "none";
|
|
19
26
|
const type = raw.split(";")[0].trim().toLowerCase();
|
|
@@ -22,9 +29,11 @@ export default class RequestBody {
|
|
|
22
29
|
switch (type) {
|
|
23
30
|
case binary:
|
|
24
31
|
return new RequestBody({ type: "binary", value: await request.blob() });
|
|
25
|
-
case
|
|
26
|
-
case
|
|
27
|
-
|
|
32
|
+
case www_form:
|
|
33
|
+
case form_data: {
|
|
34
|
+
const { form, files } = await anyform(request);
|
|
35
|
+
return new RequestBody({ type: "form", value: form }, files);
|
|
36
|
+
}
|
|
28
37
|
case json:
|
|
29
38
|
return new RequestBody({ type: "json", value: await request.json() });
|
|
30
39
|
case text:
|
|
@@ -43,8 +52,9 @@ export default class RequestBody {
|
|
|
43
52
|
static none() {
|
|
44
53
|
return new RequestBody({ type: "none", value: null });
|
|
45
54
|
}
|
|
46
|
-
constructor(
|
|
47
|
-
this.#parsed =
|
|
55
|
+
constructor(parsed, files = {}) {
|
|
56
|
+
this.#parsed = parsed;
|
|
57
|
+
this.#files = files;
|
|
48
58
|
}
|
|
49
59
|
get type() {
|
|
50
60
|
return this.#parsed.type;
|
|
@@ -62,13 +72,19 @@ export default class RequestBody {
|
|
|
62
72
|
const value = this.#value();
|
|
63
73
|
return schema ? schema.parse(value) : value;
|
|
64
74
|
}
|
|
65
|
-
|
|
66
|
-
if (this.type !== "
|
|
67
|
-
this.#throw("form
|
|
75
|
+
form(schema) {
|
|
76
|
+
if (this.type !== "form") {
|
|
77
|
+
this.#throw("form");
|
|
68
78
|
}
|
|
69
79
|
const value = this.#value();
|
|
70
80
|
return schema ? schema.parse(value) : value;
|
|
71
81
|
}
|
|
82
|
+
files() {
|
|
83
|
+
if (this.type !== "form") {
|
|
84
|
+
this.#throw("form");
|
|
85
|
+
}
|
|
86
|
+
return this.#files;
|
|
87
|
+
}
|
|
72
88
|
text() {
|
|
73
89
|
if (this.type !== "text") {
|
|
74
90
|
this.#throw("plaintext");
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import type View from "#frontend/View";
|
|
2
2
|
import type RequestFacade from "#request/RequestFacade";
|
|
3
3
|
import type ServeApp from "#ServeApp";
|
|
4
4
|
import type Dict from "@rcompat/type/Dict";
|
|
5
5
|
import type MaybePromise from "@rcompat/type/MaybePromise";
|
|
6
|
-
type ResponseFunction = (app: ServeApp, transfer: Dict, request: RequestFacade) => MaybePromise<
|
|
6
|
+
type ResponseFunction = (app: ServeApp, transfer: Dict, request: RequestFacade) => MaybePromise<View | null | Response | undefined>;
|
|
7
7
|
export { ResponseFunction as default };
|
|
8
8
|
//# sourceMappingURL=ResponseFunction.d.ts.map
|
|
@@ -56,7 +56,11 @@ function toNormalized(relative, base) {
|
|
|
56
56
|
export default (location, status) =>
|
|
57
57
|
// no body
|
|
58
58
|
app => app.respond(null, {
|
|
59
|
-
headers: {
|
|
59
|
+
headers: {
|
|
60
|
+
"Content-Length": String(0),
|
|
61
|
+
Location: location,
|
|
62
|
+
"Cache-Control": 'no-cache',
|
|
63
|
+
},
|
|
60
64
|
status: status ?? Status.FOUND,
|
|
61
65
|
});
|
|
62
66
|
//# sourceMappingURL=redirect.js.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type ViewResponse from "#frontend/ViewResponse";
|
|
2
2
|
/**
|
|
3
|
-
* Render a component using a frontend for the given filename extension
|
|
4
|
-
* @param
|
|
5
|
-
* @param props props for
|
|
3
|
+
* Render a view component using a frontend for the given filename extension
|
|
4
|
+
* @param view path to view
|
|
5
|
+
* @param props props for view
|
|
6
6
|
* @param options rendering options
|
|
7
7
|
* @return Response rendering function
|
|
8
8
|
*/
|
|
@@ -15,27 +15,29 @@ const backmap = {
|
|
|
15
15
|
voby: "voby",
|
|
16
16
|
vue: "vue",
|
|
17
17
|
webc: "webc",
|
|
18
|
+
tsx: "react",
|
|
19
|
+
jsx: "react",
|
|
18
20
|
};
|
|
19
|
-
function no_frontend(
|
|
20
|
-
const extension = new FileRef(
|
|
21
|
+
function no_frontend(view) {
|
|
22
|
+
const extension = new FileRef(view).fullExtension.slice(1);
|
|
21
23
|
const hasPkg = extension in backmap;
|
|
22
24
|
const error = "No frontend for {0}";
|
|
23
|
-
const fix = hasPkg ? "
|
|
24
|
-
const pkgname = hasPkg ?
|
|
25
|
-
throw fail(`${error}${fix}`,
|
|
25
|
+
const fix = hasPkg ? ", did you configure {1}?" : "";
|
|
26
|
+
const pkgname = hasPkg ? `@primate/${backmap[extension]}` : "";
|
|
27
|
+
throw fail(`${error}${fix}`, view, pkgname);
|
|
26
28
|
}
|
|
27
29
|
/**
|
|
28
|
-
* Render a component using a frontend for the given filename extension
|
|
29
|
-
* @param
|
|
30
|
-
* @param props props for
|
|
30
|
+
* Render a view component using a frontend for the given filename extension
|
|
31
|
+
* @param view path to view
|
|
32
|
+
* @param props props for view
|
|
31
33
|
* @param options rendering options
|
|
32
34
|
* @return Response rendering function
|
|
33
35
|
*/
|
|
34
|
-
const view = (function viewResponse(
|
|
36
|
+
const view = (function viewResponse(name, props, options) {
|
|
35
37
|
return (app, transfer, request) => extensions
|
|
36
|
-
.map(extension => app.frontends[new FileRef(
|
|
37
|
-
.find(extension => extension !== undefined)?.(
|
|
38
|
-
?? no_frontend(
|
|
38
|
+
.map(extension => app.frontends[new FileRef(name)[extension]])
|
|
39
|
+
.find(extension => extension !== undefined)?.(name, props, options)(app, transfer, request)
|
|
40
|
+
?? no_frontend(name);
|
|
39
41
|
});
|
|
40
42
|
export default view;
|
|
41
43
|
//# sourceMappingURL=view.js.map
|
|
@@ -1,6 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
export default function wrap(code: string, file: FileRef, build: {
|
|
3
|
-
id: string;
|
|
4
|
-
stage: FileRef;
|
|
5
|
-
}): string;
|
|
1
|
+
export default function wrap(code: string, path: string, build_id: string): string;
|
|
6
2
|
//# sourceMappingURL=wrap.d.ts.map
|
|
@@ -1,16 +1,11 @@
|
|
|
1
|
-
import location from "#location";
|
|
2
1
|
import dedent from "@rcompat/string/dedent";
|
|
3
|
-
export default function wrap(code,
|
|
4
|
-
const router = `ROUTER_${
|
|
5
|
-
const debased = file.debase(build.stage.join(location.routes)).path
|
|
6
|
-
.slice(1, -file.extension.length);
|
|
2
|
+
export default function wrap(code, path, build_id) {
|
|
3
|
+
const router = `ROUTER_${build_id}`;
|
|
7
4
|
const prelude = dedent `
|
|
8
5
|
import ${router} from "primate/router";
|
|
9
|
-
${router}.push("${
|
|
6
|
+
${router}.push("${path}");
|
|
10
7
|
`;
|
|
11
|
-
const postlude =
|
|
12
|
-
${router}.pop();
|
|
13
|
-
`;
|
|
8
|
+
const postlude = `\n${router}.pop();\n`;
|
|
14
9
|
return `${prelude}${code}${postlude}`;
|
|
15
10
|
}
|
|
16
11
|
;
|
|
@@ -36,16 +36,6 @@ const web = {
|
|
|
36
36
|
inline: false,
|
|
37
37
|
}`).join(",\n ")}];
|
|
38
38
|
|
|
39
|
-
const imports = {
|
|
40
|
-
app: "${client_imports.find(({ src }) => src.includes("app") && src.endsWith(".js")).src}"
|
|
41
|
-
};
|
|
42
|
-
// importmap
|
|
43
|
-
assets.push({
|
|
44
|
-
inline: true,
|
|
45
|
-
code: { imports },
|
|
46
|
-
type: "importmap",
|
|
47
|
-
});
|
|
48
|
-
|
|
49
39
|
const pages = {
|
|
50
40
|
${pages_str}
|
|
51
41
|
};
|
|
@@ -16,7 +16,7 @@ const HEADERS_SECTION = 4;
|
|
|
16
16
|
const COOKIES_SECTION = 5;
|
|
17
17
|
const BODY_KIND_NULL = 0;
|
|
18
18
|
const BODY_KIND_TEXT = 1;
|
|
19
|
-
const
|
|
19
|
+
const BODY_KIND_FORM = 2;
|
|
20
20
|
const BODY_KIND_BINARY = 3;
|
|
21
21
|
const BODY_KIND_JSON = 4;
|
|
22
22
|
const BODY_KIND_MAP_VALUE_STRING = 0;
|
|
@@ -28,15 +28,17 @@ const sizeOfBodySection = (body) => {
|
|
|
28
28
|
return size; // 0 kind null
|
|
29
29
|
if (body.type === "text")
|
|
30
30
|
return size + stringSize(body.text());
|
|
31
|
-
if (body.type === "
|
|
31
|
+
if (body.type === "form") {
|
|
32
32
|
size += I32_SIZE; // entry count
|
|
33
|
-
const
|
|
34
|
-
for (const [key, value] of Object.entries(fields)) {
|
|
33
|
+
for (const [key, value] of Object.entries(body.form())) {
|
|
35
34
|
size += stringSize(key);
|
|
36
|
-
size += I32_SIZE // value kind
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
size += I32_SIZE; // value kind
|
|
36
|
+
size += stringSize(value);
|
|
37
|
+
}
|
|
38
|
+
for (const [key, value] of Object.entries(body.files())) {
|
|
39
|
+
size += stringSize(key);
|
|
40
|
+
size += I32_SIZE; // value kind
|
|
41
|
+
size += filesize(value);
|
|
40
42
|
}
|
|
41
43
|
return size;
|
|
42
44
|
}
|
|
@@ -46,11 +48,9 @@ const sizeOfBodySection = (body) => {
|
|
|
46
48
|
size += I32_SIZE + bin.size;
|
|
47
49
|
return size;
|
|
48
50
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
return size;
|
|
53
|
-
}
|
|
51
|
+
const json = body.json();
|
|
52
|
+
size += stringSize(JSON.stringify(json));
|
|
53
|
+
return size;
|
|
54
54
|
throw new Error("Invalid RequestLike body");
|
|
55
55
|
};
|
|
56
56
|
const sizeOfMapSection = (map) => {
|
|
@@ -137,22 +137,19 @@ const encodeSectionBody = async (body, view) => {
|
|
|
137
137
|
view.writeU32(BODY_KIND_TEXT);
|
|
138
138
|
encodeString(text, view);
|
|
139
139
|
}
|
|
140
|
-
else if (body.type === "
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
140
|
+
else if (body.type === "form") {
|
|
141
|
+
const entries = Object.entries(body.form());
|
|
142
|
+
view.writeU32(BODY_KIND_FORM);
|
|
143
|
+
view.writeU32(entries.length);
|
|
144
|
+
for (const [key, value] of entries) {
|
|
145
|
+
encodeString(key, view);
|
|
146
|
+
view.writeU32(BODY_KIND_MAP_VALUE_STRING);
|
|
147
|
+
encodeString(value, view);
|
|
148
|
+
}
|
|
149
|
+
for (const [key, value] of Object.entries(body.files())) {
|
|
147
150
|
encodeString(key, view);
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
encodeString(value, view);
|
|
151
|
-
}
|
|
152
|
-
else {
|
|
153
|
-
view.writeU32(BODY_KIND_MAP_VALUE_BLOB);
|
|
154
|
-
await encodeFile(value, view);
|
|
155
|
-
}
|
|
151
|
+
view.writeU32(BODY_KIND_MAP_VALUE_BLOB);
|
|
152
|
+
await encodeFile(value, view);
|
|
156
153
|
}
|
|
157
154
|
}
|
|
158
155
|
else if (body.type === "binary") {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@primate/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "The universal web framework",
|
|
5
5
|
"homepage": "https://primate.run",
|
|
6
6
|
"bugs": "https://github.com/primate-run/primate/issues",
|
|
@@ -24,15 +24,15 @@
|
|
|
24
24
|
"@rcompat/build": "^0.14.0",
|
|
25
25
|
"@rcompat/cli": "^0.11.3",
|
|
26
26
|
"@rcompat/crypto": "^0.10.0",
|
|
27
|
-
"@rcompat/fs": "^0.21.
|
|
27
|
+
"@rcompat/fs": "^0.21.2",
|
|
28
28
|
"@rcompat/function": "^0.9.0",
|
|
29
29
|
"@rcompat/http": "^0.15.1",
|
|
30
30
|
"@rcompat/kv": "^0.3.0",
|
|
31
31
|
"@rcompat/package": "^0.22.0",
|
|
32
32
|
"@rcompat/record": "^0.9.1",
|
|
33
|
-
"@rcompat/string": "^0.10.
|
|
33
|
+
"@rcompat/string": "^0.10.1",
|
|
34
34
|
"@rcompat/type": "^0.6.1",
|
|
35
|
-
"pema": "^0.
|
|
35
|
+
"pema": "^0.3.0"
|
|
36
36
|
},
|
|
37
37
|
"type": "module",
|
|
38
38
|
"imports": {
|
package/lib/public/client/App.js
DELETED
package/lib/public/route/wrap.js
DELETED