@primate/core 0.2.4 → 0.3.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/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 +3 -2
- package/lib/private/ServeApp.js +27 -15
- 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,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import fail from "#fail";
|
|
2
2
|
import bundle from "#frontend/bundle-server";
|
|
3
3
|
import inline from "#inline";
|
|
4
4
|
import location from "#location";
|
|
@@ -13,13 +13,13 @@ import pema from "pema";
|
|
|
13
13
|
import array from "pema/array";
|
|
14
14
|
import boolean from "pema/boolean";
|
|
15
15
|
import string from "pema/string";
|
|
16
|
-
const contexts = ["
|
|
16
|
+
const contexts = ["views", "components"];
|
|
17
17
|
async function normalize(path) {
|
|
18
18
|
return `p_${await hash(path)}`;
|
|
19
19
|
}
|
|
20
20
|
export default class FrontendModule extends Module {
|
|
21
21
|
#options;
|
|
22
|
-
render = async (
|
|
22
|
+
render = async (view, props) => ({ body: await view(props) });
|
|
23
23
|
root;
|
|
24
24
|
compile = {};
|
|
25
25
|
css;
|
|
@@ -50,39 +50,41 @@ export default class FrontendModule extends Module {
|
|
|
50
50
|
return this.#options.spa;
|
|
51
51
|
}
|
|
52
52
|
#load(name, props, app) {
|
|
53
|
-
const
|
|
54
|
-
return {
|
|
53
|
+
const view = app.loadView(name);
|
|
54
|
+
return { view, name, props };
|
|
55
55
|
}
|
|
56
56
|
;
|
|
57
57
|
async #render(server, client, app) {
|
|
58
58
|
const { body, head = "", headers = {} } = this.ssr
|
|
59
|
-
? await this.render(server.
|
|
59
|
+
? await this.render(server.view, server.props)
|
|
60
60
|
: { body: "", head: "" };
|
|
61
61
|
if (!this.client) {
|
|
62
62
|
return { body, head, headers };
|
|
63
63
|
}
|
|
64
|
-
const
|
|
65
|
-
|
|
64
|
+
const app_asset = app.assets.find(asset => asset.src?.includes("app") && asset.src.endsWith(".js"));
|
|
65
|
+
if (!app_asset)
|
|
66
|
+
throw fail("Could not find app.js in assets");
|
|
67
|
+
const app_script = `<script type="module" src="${app_asset.src}" integrity="${app_asset.integrity}"></script>`;
|
|
66
68
|
const json_props = JSON.stringify({ frontend: this.name, ...client });
|
|
67
69
|
const hydrated = await inline(json_props, APPLICATION_JSON, "hydration");
|
|
68
|
-
const script_src = [
|
|
70
|
+
const script_src = [hydrated.integrity, `'${app_asset.integrity}'`];
|
|
69
71
|
return {
|
|
70
72
|
body,
|
|
71
|
-
head: head.concat(
|
|
73
|
+
head: head.concat(app_script, hydrated.head),
|
|
72
74
|
headers: app.headers({ "script-src": script_src }),
|
|
73
75
|
};
|
|
74
76
|
}
|
|
75
77
|
normalize(name) {
|
|
76
78
|
return normalize(name);
|
|
77
79
|
}
|
|
78
|
-
respond = (
|
|
80
|
+
respond = (view, props = {}, options = {}) => async (app, { as_layout, layouts = [] } = {}, request) => {
|
|
79
81
|
if (as_layout) {
|
|
80
|
-
return this.#load(
|
|
82
|
+
return this.#load(view, props, app);
|
|
81
83
|
}
|
|
82
|
-
const
|
|
84
|
+
const views = (await Promise.all(layouts
|
|
83
85
|
.map(layout => layout(app, { as_layout: true }, request))))
|
|
84
|
-
/* set the actual page as the last
|
|
85
|
-
.concat(this.#load(
|
|
86
|
+
/* set the actual page as the last view */
|
|
87
|
+
.concat(this.#load(view, props, app));
|
|
86
88
|
const $request = {
|
|
87
89
|
context: request.context,
|
|
88
90
|
cookies: request.cookies.toJSON(),
|
|
@@ -93,35 +95,41 @@ export default class FrontendModule extends Module {
|
|
|
93
95
|
};
|
|
94
96
|
const $props = this.layouts
|
|
95
97
|
? {
|
|
96
|
-
|
|
97
|
-
props:
|
|
98
|
+
views: await map(views, ({ name }) => normalize(name)),
|
|
99
|
+
props: views.map(c => c.props),
|
|
98
100
|
request: $request,
|
|
99
101
|
}
|
|
100
102
|
: { props, request: $request };
|
|
101
103
|
const client = {
|
|
102
|
-
|
|
104
|
+
view: this.layouts ? "root" : await normalize(view),
|
|
103
105
|
spa: this.spa,
|
|
104
106
|
ssr: this.ssr,
|
|
105
107
|
...$props,
|
|
106
108
|
};
|
|
107
109
|
if (this.spa && request.headers.get("Accept") === APPLICATION_JSON) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
+
const json_body = JSON.stringify(client);
|
|
111
|
+
return new Response(json_body, {
|
|
112
|
+
headers: {
|
|
113
|
+
...app.headers(),
|
|
114
|
+
"Content-Type": APPLICATION_JSON,
|
|
115
|
+
"Content-Length": String(app.body_length(json_body)),
|
|
116
|
+
"Cache-Control": "no-store",
|
|
117
|
+
},
|
|
110
118
|
status: options.status ?? Status.OK,
|
|
111
119
|
});
|
|
112
120
|
}
|
|
113
121
|
try {
|
|
114
122
|
const server = this.layouts
|
|
115
123
|
? {
|
|
116
|
-
|
|
124
|
+
view: app.loadView(`${this.rootname}.js`),
|
|
117
125
|
props: {
|
|
118
|
-
|
|
119
|
-
props:
|
|
126
|
+
views: views.map(c => c.view),
|
|
127
|
+
props: views.map(c => c.props),
|
|
120
128
|
request: $request,
|
|
121
129
|
},
|
|
122
130
|
}
|
|
123
131
|
: {
|
|
124
|
-
|
|
132
|
+
view: app.loadView(view),
|
|
125
133
|
props,
|
|
126
134
|
request: $request,
|
|
127
135
|
};
|
|
@@ -129,8 +137,8 @@ export default class FrontendModule extends Module {
|
|
|
129
137
|
return app.view({ body, head, headers, ...options });
|
|
130
138
|
}
|
|
131
139
|
catch (error) {
|
|
132
|
-
const path = `${location.
|
|
133
|
-
throw
|
|
140
|
+
const path = `${location.views}/${view}`;
|
|
141
|
+
throw fail("error in view{0}\n{1}", path, error);
|
|
134
142
|
}
|
|
135
143
|
};
|
|
136
144
|
serve(app, next) {
|
|
@@ -168,19 +176,19 @@ export default class FrontendModule extends Module {
|
|
|
168
176
|
: null;
|
|
169
177
|
});
|
|
170
178
|
}
|
|
171
|
-
const
|
|
172
|
-
const
|
|
173
|
-
build.onResolve({ filter:
|
|
179
|
+
const views_filter = new RegExp(`^${name}:views`);
|
|
180
|
+
const views_base = app.root.join(location.views);
|
|
181
|
+
build.onResolve({ filter: views_filter }, ({ path }) => {
|
|
174
182
|
return { namespace: `${name}`, path };
|
|
175
183
|
});
|
|
176
|
-
build.onLoad({ filter:
|
|
177
|
-
const
|
|
184
|
+
build.onLoad({ filter: views_filter }, async () => {
|
|
185
|
+
const views = await views_base
|
|
178
186
|
.collect(c => fileExtensions.includes(c.fullExtension));
|
|
179
187
|
let contents = "";
|
|
180
|
-
for (const
|
|
181
|
-
const { path } =
|
|
188
|
+
for (const view of views) {
|
|
189
|
+
const { path } = view.debase(views_base, "/");
|
|
182
190
|
contents += `export { default as ${await normalize(path)} }
|
|
183
|
-
from "#
|
|
191
|
+
from "#view/${path}";\n`;
|
|
184
192
|
}
|
|
185
193
|
return { contents, resolveDir: app.root.path };
|
|
186
194
|
});
|
|
@@ -207,20 +215,19 @@ export default class FrontendModule extends Module {
|
|
|
207
215
|
init(app, next) {
|
|
208
216
|
this.fileExtensions.forEach(e => {
|
|
209
217
|
app.bind(e, async (file, { context }) => {
|
|
210
|
-
assert(contexts.includes(context), `${this.name}: only components
|
|
218
|
+
assert(contexts.includes(context), `${this.name}: only components supported`);
|
|
211
219
|
if (this.compile.server) {
|
|
212
|
-
const
|
|
213
|
-
const source = app.path[context].join(original);
|
|
214
|
-
const code = await this.compile.server(await source.text());
|
|
220
|
+
const code = await this.compile.server(await file.text());
|
|
215
221
|
const bundled = await bundle({
|
|
216
222
|
code,
|
|
217
|
-
source,
|
|
223
|
+
source: file,
|
|
218
224
|
root: app.root,
|
|
219
225
|
extensions: this.fileExtensions,
|
|
220
226
|
compile: async (s) => this.compile.server(s),
|
|
221
227
|
});
|
|
222
|
-
|
|
228
|
+
return bundled;
|
|
223
229
|
}
|
|
230
|
+
return await file.text();
|
|
224
231
|
});
|
|
225
232
|
});
|
|
226
233
|
return next(app);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type Dict from "@rcompat/type/Dict";
|
|
2
2
|
import type MaybePromise from "@rcompat/type/MaybePromise";
|
|
3
|
-
type Render<
|
|
3
|
+
type Render<V = unknown> = (view: V, props: Dict) => MaybePromise<{
|
|
4
4
|
body: string;
|
|
5
5
|
head?: string;
|
|
6
6
|
headers?: Record<string, string>;
|
|
@@ -13,12 +13,12 @@ export default async function bundleServer(init) {
|
|
|
13
13
|
const contents = await compile(src, file);
|
|
14
14
|
return { contents, loader: "js", resolveDir: file.directory.path };
|
|
15
15
|
});
|
|
16
|
-
// externalise anything not relative nor "#
|
|
16
|
+
// externalise anything not relative nor "#view/"
|
|
17
17
|
build.onResolve({ filter: /.*/ }, args => {
|
|
18
18
|
const p = args.path;
|
|
19
19
|
const relative = p.startsWith("./") || p.startsWith("../");
|
|
20
|
-
const
|
|
21
|
-
if (!relative && !
|
|
20
|
+
const views = p.startsWith("#view/");
|
|
21
|
+
if (!relative && !views)
|
|
22
22
|
return { path: p, external: true };
|
|
23
23
|
return null;
|
|
24
24
|
});
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import fail from "#fail";
|
|
2
2
|
import location from "#location";
|
|
3
3
|
import log from "#log";
|
|
4
4
|
import reducer from "#reducer";
|
|
5
5
|
import $router from "#request/router";
|
|
6
|
+
import wrap from "#route/wrap";
|
|
6
7
|
import s_layout_depth from "#symbol/layout-depth";
|
|
7
8
|
import FileRef from "@rcompat/fs/FileRef";
|
|
8
9
|
import json from "@rcompat/package/json";
|
|
@@ -12,10 +13,10 @@ const pre = async (app) => {
|
|
|
12
13
|
// remove build directory in case exists
|
|
13
14
|
await app.path.build.remove();
|
|
14
15
|
await app.path.build.create();
|
|
15
|
-
await Promise.all(["server", "client", "
|
|
16
|
+
await Promise.all(["server", "client", "views"]
|
|
16
17
|
.map(directory => app.runpath(directory).create()));
|
|
17
18
|
// this has to occur before post, so that layout depth is available for
|
|
18
|
-
// compiling root
|
|
19
|
+
// compiling root views
|
|
19
20
|
// bindings should have been registered during `init`
|
|
20
21
|
const router = await $router(app.path.routes, app.extensions);
|
|
21
22
|
app.set(s_layout_depth, router.depth("layout"));
|
|
@@ -27,33 +28,36 @@ const pre = async (app) => {
|
|
|
27
28
|
app.i18n_active = has_i18n_config;
|
|
28
29
|
return app;
|
|
29
30
|
};
|
|
30
|
-
async function
|
|
31
|
-
|
|
32
|
-
const default_database = `${export_from} "#stage/config/database/index.js";`;
|
|
33
|
-
// app/config/database does not exist
|
|
31
|
+
async function index_database(base) {
|
|
32
|
+
// app/config/database does not exist -> use prelayered default
|
|
34
33
|
if (!await base.exists())
|
|
35
|
-
return
|
|
34
|
+
return "";
|
|
36
35
|
const databases = await base.list();
|
|
37
36
|
const n = databases.length;
|
|
38
|
-
// none in app/config/database ->
|
|
37
|
+
// none in app/config/database -> use prelayered default
|
|
39
38
|
if (n === 0)
|
|
40
|
-
return default_database;
|
|
41
|
-
// index database file found, will be overwritten in next step
|
|
42
|
-
if (databases.some(d => d.base === "index"))
|
|
43
39
|
return "";
|
|
44
40
|
const names = databases.map(d => d.name);
|
|
45
|
-
//
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
// app/config/
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
//
|
|
54
|
-
if (
|
|
55
|
-
return
|
|
56
|
-
|
|
41
|
+
// index database file found, will be overwritten in next step -> do nothing
|
|
42
|
+
if (names.includes("index.ts") || names.includes("index.js")) {
|
|
43
|
+
return ""; // empty string means: don't generate, user provided own
|
|
44
|
+
}
|
|
45
|
+
// app/config/default.ts -> reexport
|
|
46
|
+
if (names.includes("default.ts")) {
|
|
47
|
+
return "export { default } from \"./default.js\";";
|
|
48
|
+
}
|
|
49
|
+
// app/config/default.js -> reexport
|
|
50
|
+
if (names.includes("default.js")) {
|
|
51
|
+
return "export { default } from \"./default.js\";";
|
|
52
|
+
}
|
|
53
|
+
// exactly one in app/config/database -> reexport that
|
|
54
|
+
if (n === 1) {
|
|
55
|
+
const onlyFile = names[0];
|
|
56
|
+
const withoutExt = onlyFile.replace(/\.(ts|js)$/, ".js");
|
|
57
|
+
return `export { default } from "./${withoutExt}";`;
|
|
58
|
+
}
|
|
59
|
+
// multiple files, none is index or default -> error
|
|
60
|
+
throw fail("multiple database drivers, add index or default.(ts|js); found {0}", names.join(", "));
|
|
57
61
|
}
|
|
58
62
|
const js_re = /^.*.js$/;
|
|
59
63
|
const write_directories = async (build_directory, app) => {
|
|
@@ -81,22 +85,22 @@ store.push(["${FileRef.webpath(bare)}", store${i}]);`).join("\n")}
|
|
|
81
85
|
export default store;`;
|
|
82
86
|
await build_directory.join("stores.js").write(stores_js);
|
|
83
87
|
};
|
|
84
|
-
const
|
|
85
|
-
const d2 = app.runpath(location.
|
|
88
|
+
const write_views = async (build_directory, app) => {
|
|
89
|
+
const d2 = app.runpath(location.views);
|
|
86
90
|
const e = await Promise.all((await FileRef.collect(d2, file => js_re.test(file.path)))
|
|
87
91
|
.map(async (path) => `${path}`.replace(d2.toString(), _ => "")));
|
|
88
|
-
const
|
|
89
|
-
const
|
|
90
|
-
${e.map(path => path.slice(1, -".js".length)).map((bare, i) => `import * as
|
|
91
|
-
|
|
92
|
+
const views_js = `
|
|
93
|
+
const view = [];
|
|
94
|
+
${e.map(path => path.slice(1, -".js".length)).map((bare, i) => `import * as view${i} from "${FileRef.webpath(`#view/${bare}`)}";
|
|
95
|
+
view.push(["${FileRef.webpath(bare)}", view${i}]);`).join("\n")}
|
|
92
96
|
|
|
93
97
|
${app.roots.map((root, i) => `
|
|
94
98
|
import * as root${i} from "${FileRef.webpath(`../server/${root.name}`)}";
|
|
95
|
-
|
|
99
|
+
view.push(["${root.name.slice(0, -".js".length)}", root${i}]);
|
|
96
100
|
`).join("\n")}
|
|
97
101
|
|
|
98
|
-
export default
|
|
99
|
-
await build_directory.join("
|
|
102
|
+
export default view;`;
|
|
103
|
+
await build_directory.join("views.js").write(views_js);
|
|
100
104
|
};
|
|
101
105
|
const write_bootstrap = async (app, mode, i18n_active) => {
|
|
102
106
|
const build_start_script = `
|
|
@@ -104,7 +108,7 @@ import serve from "primate/serve";
|
|
|
104
108
|
const files = {};
|
|
105
109
|
${app.server_build.map(name => `${name}s`).map(name => `import ${name} from "./${app.id}/${name}.js";
|
|
106
110
|
files.${name} = ${name};`).join("\n")}
|
|
107
|
-
import
|
|
111
|
+
import views from "./${app.id}/views.js";
|
|
108
112
|
import stores from "./${app.id}/stores.js";
|
|
109
113
|
import target from "./target.js";
|
|
110
114
|
import session from "#session";
|
|
@@ -122,7 +126,7 @@ const app = await serve(import.meta.url, {
|
|
|
122
126
|
...target,
|
|
123
127
|
config,
|
|
124
128
|
files,
|
|
125
|
-
|
|
129
|
+
views,
|
|
126
130
|
stores,
|
|
127
131
|
mode: "${mode}",
|
|
128
132
|
session_config: session[s_config],
|
|
@@ -135,39 +139,50 @@ export default app;
|
|
|
135
139
|
};
|
|
136
140
|
const post = async (app) => {
|
|
137
141
|
const defaults = FileRef.join(import.meta.url, "../../defaults");
|
|
138
|
-
await app.
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
142
|
+
await app.compile(app.path.routes, "routes", {
|
|
143
|
+
loader: (source, file) => {
|
|
144
|
+
const path = app.basename(file, app.path.routes);
|
|
145
|
+
return wrap(source, path, app.id);
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
await app.compile(app.path.stores, "stores", {
|
|
149
|
+
resolver: basename => `${basename}.original`, // First pass: save original
|
|
150
|
+
});
|
|
151
|
+
if (await app.path.stores.exists()) {
|
|
152
|
+
const stores = await app.path.stores.collect(({ path }) => app.extensions.some(e => path.endsWith(e)));
|
|
153
|
+
for (const file of stores) {
|
|
154
|
+
const basename = app.basename(file, app.path.stores);
|
|
155
|
+
const wrapper = dedent `
|
|
156
|
+
import database from "#database";
|
|
157
|
+
import store from "./${basename}.original.js";
|
|
158
|
+
import wrap from "primate/database/wrap";
|
|
159
|
+
export default wrap("${basename}", store, database);
|
|
160
|
+
`;
|
|
161
|
+
const target = app.runpath("stores", `${basename}.js`);
|
|
162
|
+
await target.write(wrapper);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
148
165
|
const configs = FileRef.join(dirname, "../../private/config/config");
|
|
149
166
|
const database_base = app.path.config.join("database");
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
167
|
+
// prelayer config default
|
|
168
|
+
await app.compile(configs, "config", {
|
|
169
|
+
loader: async (source, file) => {
|
|
170
|
+
const relative = file.debase(configs);
|
|
171
|
+
if (relative.path === "/database/index.js") {
|
|
172
|
+
const indexContent = await index_database(database_base);
|
|
173
|
+
// if empty, user provided own index -> use the compiled source
|
|
174
|
+
return indexContent || source;
|
|
175
|
+
}
|
|
176
|
+
return source;
|
|
177
|
+
},
|
|
154
178
|
});
|
|
155
|
-
await app.
|
|
156
|
-
|
|
157
|
-
await app.
|
|
158
|
-
//
|
|
159
|
-
await app.
|
|
160
|
-
//
|
|
161
|
-
await app.
|
|
162
|
-
export * from "#stage/lib${file}";
|
|
163
|
-
`);
|
|
164
|
-
// stage components
|
|
165
|
-
await app.stage(app.path.components, "components", file => `
|
|
166
|
-
import * as component from "#stage/component${file}";
|
|
167
|
-
|
|
168
|
-
export * from "#stage/component${file}";
|
|
169
|
-
export default component?.default;
|
|
170
|
-
`);
|
|
179
|
+
await app.compile(app.path.modules, "modules");
|
|
180
|
+
await app.compile(app.path.locales, "locales");
|
|
181
|
+
await app.compile(app.path.config, "config");
|
|
182
|
+
// reusable components
|
|
183
|
+
await app.compile(app.path.components, "components");
|
|
184
|
+
// view components
|
|
185
|
+
await app.compile(app.path.views, "views");
|
|
171
186
|
// copy framework pages
|
|
172
187
|
await defaults.copy(app.runpath(location.server, location.pages));
|
|
173
188
|
// copy pages to build
|
|
@@ -184,7 +199,7 @@ const post = async (app) => {
|
|
|
184
199
|
const src = file.debase(app.path.static);
|
|
185
200
|
app.build.export(`import "./${location.static}${src}";`);
|
|
186
201
|
}));
|
|
187
|
-
app.build.export("
|
|
202
|
+
app.build.export("import \"primate/client/app\";");
|
|
188
203
|
app.build.plugin({
|
|
189
204
|
name: "@primate/core/frontend",
|
|
190
205
|
setup(build) {
|
|
@@ -213,7 +228,7 @@ const post = async (app) => {
|
|
|
213
228
|
const build_directory = app.path.build.join(app.id);
|
|
214
229
|
// TODO: remove after rcompat automatically creates directories
|
|
215
230
|
await build_directory.create();
|
|
216
|
-
await
|
|
231
|
+
await write_views(build_directory, app);
|
|
217
232
|
await write_stores(build_directory, app);
|
|
218
233
|
await write_directories(build_directory, app);
|
|
219
234
|
await write_bootstrap(app, app.mode, app.i18n_active);
|
|
@@ -227,18 +242,11 @@ const post = async (app) => {
|
|
|
227
242
|
"#database/*": "./config/database/*.js",
|
|
228
243
|
"#session": "./config/session.js",
|
|
229
244
|
"#i18n": "./config/i18n.js",
|
|
230
|
-
"#
|
|
245
|
+
"#view/*": "./views/*.js",
|
|
231
246
|
"#component/*": "./components/*.js",
|
|
232
247
|
"#locale/*": "./locales/*.js",
|
|
233
248
|
"#module/*": "./modules/*.js",
|
|
234
249
|
"#route/*": "./routes/*.js",
|
|
235
|
-
"#stage/lib/*": "./stage/lib/*.js",
|
|
236
|
-
"#stage/component/*": "./stage/components/*.js",
|
|
237
|
-
"#stage/locale/*": "./stage/locales/*.js",
|
|
238
|
-
"#stage/config/*": "./stage/config/*.js",
|
|
239
|
-
"#stage/module/*": "./stage/modules/*.js",
|
|
240
|
-
"#stage/route/*": "./stage/routes/*.js",
|
|
241
|
-
"#stage/store/*": "./stage/stores/*.js",
|
|
242
250
|
"#store/*": "./stores/*.js",
|
|
243
251
|
},
|
|
244
252
|
};
|
|
@@ -66,17 +66,30 @@ export default class I18NModule extends Module {
|
|
|
66
66
|
return next(request);
|
|
67
67
|
// only cookie-persistance is server-supported
|
|
68
68
|
if (this.#persist !== "cookie")
|
|
69
|
-
return new Response(null, {
|
|
69
|
+
return new Response(null, {
|
|
70
|
+
headers: {
|
|
71
|
+
"Content-Length": String(0),
|
|
72
|
+
},
|
|
73
|
+
status: Status.NO_CONTENT
|
|
74
|
+
});
|
|
70
75
|
// only accept configured locales
|
|
71
76
|
if (!this.#configured(requested))
|
|
72
|
-
return new Response(null, {
|
|
77
|
+
return new Response(null, {
|
|
78
|
+
headers: {
|
|
79
|
+
"Content-Length": String(0),
|
|
80
|
+
},
|
|
81
|
+
status: Status.NO_CONTENT
|
|
82
|
+
});
|
|
73
83
|
const header = cookie(COOKIE_NAME, requested, {
|
|
74
84
|
secure: this.#secure,
|
|
75
85
|
path: "/",
|
|
76
86
|
sameSite: "Strict",
|
|
77
87
|
});
|
|
78
88
|
return new Response(null, {
|
|
79
|
-
headers: {
|
|
89
|
+
headers: {
|
|
90
|
+
"Set-Cookie": header,
|
|
91
|
+
"Content-Length": String(0),
|
|
92
|
+
},
|
|
80
93
|
status: Status.NO_CONTENT,
|
|
81
94
|
});
|
|
82
95
|
}
|
package/lib/private/location.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type Dict from "@rcompat/type/Dict";
|
|
2
2
|
import type JSONValue from "@rcompat/type/JSONValue";
|
|
3
3
|
import type Schema from "@rcompat/type/Schema";
|
|
4
|
-
type
|
|
4
|
+
type Form = Dict<string>;
|
|
5
5
|
type Parsed = {
|
|
6
6
|
type: "binary";
|
|
7
7
|
value: Blob;
|
|
8
8
|
} | {
|
|
9
|
-
type: "
|
|
10
|
-
value:
|
|
9
|
+
type: "form";
|
|
10
|
+
value: Dict<string>;
|
|
11
11
|
} | {
|
|
12
12
|
type: "json";
|
|
13
13
|
value: JSONValue;
|
|
@@ -25,12 +25,13 @@ export default class RequestBody {
|
|
|
25
25
|
#private;
|
|
26
26
|
static parse(request: Request, url: URL): Promise<RequestBody>;
|
|
27
27
|
static none(): RequestBody;
|
|
28
|
-
constructor(
|
|
29
|
-
get type(): "binary" | "
|
|
28
|
+
constructor(parsed: Parsed, files?: Dict<File>);
|
|
29
|
+
get type(): "binary" | "form" | "json" | "none" | "text";
|
|
30
30
|
json(): JSONValue;
|
|
31
31
|
json<S extends Schema<unknown>>(schema: S): ParseReturn<S>;
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
form(): Form;
|
|
33
|
+
form<S extends Schema<unknown>>(schema: S): ParseReturn<S>;
|
|
34
|
+
files(): Dict<File>;
|
|
34
35
|
text(): string;
|
|
35
36
|
binary(): Blob;
|
|
36
37
|
none(): null;
|