@primate/core 0.7.4 → 0.8.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 +128 -65
- package/lib/private/Bag.d.ts +11 -0
- package/lib/private/Bag.js +31 -0
- package/lib/private/Flags.d.ts +5 -5
- package/lib/private/Flags.js +2 -1
- package/lib/private/app/Facade.client.d.ts +20 -0
- package/lib/private/app/Facade.client.js +30 -0
- package/lib/private/app/{Facade.d.ts → Facade.server.d.ts} +141 -72
- package/lib/private/app/{Facade.js → Facade.server.js} +12 -4
- package/lib/private/build/App.d.ts +0 -2
- package/lib/private/build/App.js +0 -7
- package/lib/private/build/client/index.js +29 -27
- package/lib/private/build/client/plugin/frontend.js +1 -1
- package/lib/private/build/hook.js +0 -3
- package/lib/private/build/server/index.js +5 -18
- package/lib/private/build/server/plugin/native-addons.d.ts +1 -1
- package/lib/private/build/server/plugin/native-addons.js +1 -1
- package/lib/private/client/create-form.d.ts +13 -9
- package/lib/private/client/create-form.js +21 -4
- package/lib/private/client/transport.js +0 -2
- package/lib/private/config/index.d.ts +6 -2
- package/lib/private/config/schema.d.ts +28 -21
- package/lib/private/config/schema.js +5 -3
- package/lib/private/cookie.d.ts +5 -5
- package/lib/private/db/errors.d.ts +82 -82
- package/lib/private/db/migrate/store.d.ts +2 -2
- package/lib/private/db/primary.d.ts +1 -1
- package/lib/private/db/sql.d.ts +1 -1
- package/lib/private/errors.d.ts +80 -68
- package/lib/private/errors.js +22 -0
- package/lib/private/frontend.d.ts +7 -7
- package/lib/private/frontend.js +7 -10
- package/lib/private/i18n/API.d.ts +14 -18
- package/lib/private/i18n/config.client.d.ts +7 -0
- package/lib/private/i18n/config.client.js +130 -0
- package/lib/private/i18n/config.server.d.ts +7 -0
- package/lib/private/i18n/{index/server.js → config.server.js} +31 -23
- package/lib/private/i18n/constant/COOKIE_NAME.d.ts +1 -1
- package/lib/private/i18n/constant/DEFAULT_LOCALE.d.ts +1 -1
- package/lib/private/i18n/constant/DEFAULT_PERSIST_MODE.d.ts +1 -1
- package/lib/private/i18n/constant/PERSIST_HEADER.d.ts +1 -1
- package/lib/private/i18n/constant/PERSIST_METHOD.d.ts +1 -1
- package/lib/private/i18n/constant/PERSIST_STORAGE_KEY.d.ts +1 -1
- package/lib/private/i18n/index.d.ts +42 -0
- package/lib/private/i18n/index.js +6 -0
- package/lib/private/i18n/missing.d.ts +5 -0
- package/lib/private/i18n/missing.js +38 -0
- package/lib/private/i18n/module.js +36 -52
- package/lib/private/i18n/schema.d.ts +4 -4
- package/lib/private/loader.d.ts +5 -0
- package/lib/private/loader.js +28 -0
- package/lib/private/logger.d.ts +1 -1
- package/lib/private/request/RequestBag.d.ts +12 -13
- package/lib/private/request/RequestBag.js +5 -4
- package/lib/private/request/RequestView.d.ts +5 -5
- package/lib/private/request/RequestView.js +0 -1
- package/lib/private/response/view.d.ts +1 -0
- package/lib/private/response/view.js +0 -7
- package/lib/private/route/Handler.d.ts +1 -1
- package/lib/private/route/NarrowedRequest.d.ts +6 -1
- package/lib/private/route/Options.d.ts +2 -1
- package/lib/private/route/hook.d.ts +1 -2
- package/lib/private/route/router.d.ts +9 -9
- package/lib/private/route/router.js +9 -0
- package/lib/private/route.client.d.ts +21 -12
- package/lib/private/route.client.js +9 -4
- package/lib/private/route.d.ts +3 -0
- package/lib/private/route.js +2 -0
- package/lib/private/serve/App.d.ts +2 -13
- package/lib/private/serve/App.js +63 -46
- package/lib/private/serve/Init.d.ts +0 -3
- package/lib/private/server/TAG.d.ts +1 -1
- package/lib/private/session/config.client.d.ts +4 -0
- package/lib/private/session/config.client.js +24 -0
- package/lib/private/session/config.server.d.ts +15 -0
- package/lib/private/session/config.server.js +44 -0
- package/lib/private/session/index.d.ts +2 -14
- package/lib/private/session/index.js +2 -43
- package/lib/private/session/schema.d.ts +5 -5
- package/lib/private/store/PrimaryKey.d.ts +1 -1
- package/lib/private/store.client.d.ts +13 -0
- package/lib/private/store.client.js +9 -0
- package/lib/private/store.d.ts +2 -0
- package/lib/private/target/Manager.d.ts +2 -0
- package/lib/private/target/Manager.js +29 -5
- package/lib/private/target/Target.d.ts +2 -0
- package/lib/public/i18n.d.ts +3 -0
- package/lib/public/{i18n/config.js → i18n.js} +1 -1
- package/lib/public/loader.d.ts +2 -0
- package/lib/public/loader.js +2 -0
- package/lib/public/response.d.ts +1 -1
- package/lib/public/{session/config.d.ts → session.d.ts} +1 -1
- package/lib/public/{session/config.js → session.js} +1 -1
- package/package.json +27 -13
- package/lib/private/app/Facade.browser.d.ts +0 -11
- package/lib/private/app/Facade.browser.js +0 -19
- package/lib/private/build/server/plugin/store.d.ts +0 -4
- package/lib/private/build/server/plugin/store.js +0 -25
- package/lib/private/build/server/plugin/stores.d.ts +0 -4
- package/lib/private/build/server/plugin/stores.js +0 -28
- package/lib/private/i18n/index/client.d.ts +0 -9
- package/lib/private/i18n/index/client.js +0 -152
- package/lib/private/i18n/index/server.d.ts +0 -9
- package/lib/private/i18n/symbol/internal.d.ts +0 -3
- package/lib/private/i18n/symbol/internal.js +0 -3
- package/lib/public/i18n/API.d.ts +0 -2
- package/lib/public/i18n/API.js +0 -2
- package/lib/public/i18n/Catalogs.d.ts +0 -2
- package/lib/public/i18n/Catalogs.js +0 -2
- package/lib/public/i18n/ContextData.d.ts +0 -2
- package/lib/public/i18n/ContextData.js +0 -2
- package/lib/public/i18n/config.d.ts +0 -2
- package/lib/public/i18n/locale.d.ts +0 -2
- package/lib/public/i18n/locale.js +0 -2
- package/lib/public/i18n/sInternal.d.ts +0 -2
- package/lib/public/i18n/sInternal.js +0 -2
- package/lib/public/route/hook.d.ts +0 -2
- package/lib/public/route/hook.js +0 -2
- /package/lib/private/i18n/{index/types.d.ts → types.d.ts} +0 -0
- /package/lib/private/i18n/{index/types.js → types.js} +0 -0
|
@@ -14,6 +14,15 @@ class Router {
|
|
|
14
14
|
assert.maybe.dict(options);
|
|
15
15
|
if (is_hook_file(path))
|
|
16
16
|
throw E.hook_route_functions_not_allowed(path);
|
|
17
|
+
if (options?.path !== undefined) {
|
|
18
|
+
const declared = Object.keys(options.path.properties);
|
|
19
|
+
const expected = [...path.matchAll(/\[([^\]]+)\]/g)].map(m => m[1]);
|
|
20
|
+
const missing = expected.filter(k => !declared.includes(k));
|
|
21
|
+
const extra = declared.filter(k => !expected.includes(k));
|
|
22
|
+
if (missing.length > 0 || extra.length > 0) {
|
|
23
|
+
throw E.build_path_schema_mismatch(path, method, expected, declared);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
17
26
|
if (!(path in this.#routes))
|
|
18
27
|
this.#routes[path] = {};
|
|
19
28
|
this.#routes[path][method] = { handler, options: options ?? {} };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type ResponseLike from "#response/ResponseLike";
|
|
1
2
|
import type ContentTypeMap from "#route/ContentTypeMap";
|
|
2
3
|
import type RouteHandler from "#route/Handler";
|
|
3
4
|
import type RouteOptions from "#route/Options";
|
|
@@ -9,35 +10,43 @@ type Body<O extends RouteOptions> = O extends {
|
|
|
9
10
|
} ? Unpack<S["infer"]> : O extends {
|
|
10
11
|
contentType: infer CT extends keyof ContentTypeMap;
|
|
11
12
|
} ? ContentTypeMap[CT] : never;
|
|
13
|
+
type Path<O extends RouteOptions> = O extends {
|
|
14
|
+
path: infer S extends Parsed<unknown>;
|
|
15
|
+
} ? Unpack<S["infer"]> : never;
|
|
12
16
|
type MethodMeta = {
|
|
13
17
|
contentType?: string;
|
|
14
18
|
};
|
|
15
|
-
type ClientMethod<O extends RouteOptions> = MethodMeta &
|
|
19
|
+
type ClientMethod<O extends RouteOptions, R = unknown> = MethodMeta & {
|
|
20
|
+
_result?: R;
|
|
21
|
+
} & (Body<O> extends never ? Path<O> extends never ? () => Promise<Response> : (args: {
|
|
22
|
+
path: Path<O>;
|
|
23
|
+
}) => Promise<Response> : Path<O> extends never ? (args: {
|
|
16
24
|
body: Body<O>;
|
|
25
|
+
}) => Promise<Response> : (args: {
|
|
26
|
+
body: Body<O>;
|
|
27
|
+
path: Path<O>;
|
|
17
28
|
}) => Promise<Response>);
|
|
18
29
|
type ClientRoute<R> = {
|
|
19
30
|
[K in keyof R]: R[K] extends {
|
|
20
31
|
options: infer O extends RouteOptions;
|
|
21
|
-
|
|
32
|
+
result?: infer Result;
|
|
33
|
+
} ? ClientMethod<O, Result> : () => Promise<Response>;
|
|
22
34
|
};
|
|
23
|
-
type WithResult<O extends RouteOptions> = {
|
|
35
|
+
type WithResult<O extends RouteOptions, R = unknown> = {
|
|
24
36
|
handler: RouteHandler<O>;
|
|
25
37
|
options: O;
|
|
38
|
+
result?: R;
|
|
26
39
|
};
|
|
27
40
|
type RouteHandlers = {
|
|
28
41
|
[key: string]: RouteHandler | WithResult<RouteOptions>;
|
|
29
42
|
};
|
|
30
|
-
declare function route<R extends RouteHandlers>(handlers: R):
|
|
31
|
-
_handlers: {
|
|
32
|
-
[k: string]: {
|
|
33
|
-
contentType: ("application/x-7z-compressed" | "application/octet-stream" | "application/x-bzip2" | "application/gzip" | "application/json" | "application/ld+json" | "application/pdf" | "application/x-rar-compressed" | "application/rss+xml" | "application/x-tar" | "application/wasm" | "application/manifest+json" | "application/xml" | "application/yaml" | "application/zip" | "audio/mpeg" | "audio/ogg" | "audio/wav" | "audio/webm" | "font/otf" | "font/ttf" | "font/woff" | "font/woff2" | "image/apng" | "image/avif" | "image/bmp" | "image/gif" | "image/x-icon" | "image/jpeg" | "image/png" | "image/svg+xml" | "image/tiff" | "image/webp" | "text/css" | "text/csv" | "text/html" | "text/javascript" | "text/markdown" | "text/rtf" | "text/plain" | "text/tab-separated-values" | "text/vtt" | "video/quicktime" | "video/mp4" | "video/ogg" | "video/mp2t" | "video/webm" | "application/x-www-form-urlencoded" | "multipart/form-data" | "text/event-stream") | undefined;
|
|
34
|
-
};
|
|
35
|
-
};
|
|
36
|
-
connect(path: string): ClientRoute<R>;
|
|
37
|
-
};
|
|
43
|
+
declare function route<R extends RouteHandlers>(handlers: R): ClientRoute<R>;
|
|
38
44
|
declare namespace route {
|
|
39
|
-
var _a: <O extends RouteOptions>(options: O, handler: RouteHandler<O>) => WithResult<O>;
|
|
45
|
+
var _a: <O extends RouteOptions, R extends ResponseLike>(options: O, handler: RouteHandler<O, R>) => WithResult<O, R>;
|
|
40
46
|
export { _a as with };
|
|
41
47
|
}
|
|
48
|
+
declare namespace route {
|
|
49
|
+
var hook: typeof import("#route/hook").default;
|
|
50
|
+
}
|
|
42
51
|
export default route;
|
|
43
52
|
//# sourceMappingURL=route.client.d.ts.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import hook from "#route/hook";
|
|
1
2
|
function is_with(value) {
|
|
2
3
|
return typeof value === "object" &&
|
|
3
4
|
value !== null &&
|
|
@@ -7,9 +8,8 @@ function is_with(value) {
|
|
|
7
8
|
function serialize_body(contentType, body) {
|
|
8
9
|
if (body === undefined)
|
|
9
10
|
return undefined;
|
|
10
|
-
if (contentType === "application/json")
|
|
11
|
+
if (contentType === "application/json")
|
|
11
12
|
return JSON.stringify(body);
|
|
12
|
-
}
|
|
13
13
|
if (contentType === "application/x-www-form-urlencoded") {
|
|
14
14
|
return body instanceof URLSearchParams
|
|
15
15
|
? body
|
|
@@ -25,7 +25,7 @@ function headers(contentType) {
|
|
|
25
25
|
return { "Content-Type": contentType };
|
|
26
26
|
}
|
|
27
27
|
function route(handlers) {
|
|
28
|
-
|
|
28
|
+
const r = {
|
|
29
29
|
_handlers: Object.fromEntries(Object.entries(handlers).map(([method, value]) => {
|
|
30
30
|
const options = is_with(value) ? value.options : {};
|
|
31
31
|
return [method, { contentType: options.contentType }];
|
|
@@ -33,7 +33,10 @@ function route(handlers) {
|
|
|
33
33
|
connect(path) {
|
|
34
34
|
return Object.fromEntries(Object.entries(this._handlers).map(([method, { contentType }]) => {
|
|
35
35
|
const fn = async (args = {}) => {
|
|
36
|
-
|
|
36
|
+
const resolved = args.path !== undefined
|
|
37
|
+
? path.replace(/\[([^\]]+)\]/g, (_, key) => encodeURIComponent(args.path[key] ?? `[${key}]`))
|
|
38
|
+
: path;
|
|
39
|
+
return fetch(resolved, {
|
|
37
40
|
method: method.toUpperCase(),
|
|
38
41
|
headers: headers(contentType),
|
|
39
42
|
body: serialize_body(contentType, args.body),
|
|
@@ -43,9 +46,11 @@ function route(handlers) {
|
|
|
43
46
|
}));
|
|
44
47
|
},
|
|
45
48
|
};
|
|
49
|
+
return r;
|
|
46
50
|
}
|
|
47
51
|
route.with = function (options, handler) {
|
|
48
52
|
return { handler, options };
|
|
49
53
|
};
|
|
54
|
+
route.hook = hook;
|
|
50
55
|
export default route;
|
|
51
56
|
//# sourceMappingURL=route.client.js.map
|
package/lib/private/route.d.ts
CHANGED
|
@@ -21,5 +21,8 @@ declare namespace route {
|
|
|
21
21
|
var _a: <O extends RouteOptions>(options: O, handler: RouteHandler<O>) => WithResult<O>;
|
|
22
22
|
export { _a as with };
|
|
23
23
|
}
|
|
24
|
+
declare namespace route {
|
|
25
|
+
var hook: typeof import("#route/hook").default;
|
|
26
|
+
}
|
|
24
27
|
export default route;
|
|
25
28
|
//# sourceMappingURL=route.d.ts.map
|
package/lib/private/route.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import E from "#errors";
|
|
2
|
+
import hook from "#route/hook";
|
|
2
3
|
import is from "@rcompat/is";
|
|
3
4
|
const BRAND = Symbol("route.with");
|
|
4
5
|
function is_with(value) {
|
|
@@ -18,5 +19,6 @@ route.with = function (options, handler) {
|
|
|
18
19
|
}
|
|
19
20
|
return { [BRAND]: true, handler, options };
|
|
20
21
|
};
|
|
22
|
+
route.hook = hook;
|
|
21
23
|
export default route;
|
|
22
24
|
//# sourceMappingURL=route.js.map
|
|
@@ -1,24 +1,16 @@
|
|
|
1
1
|
import App from "#App";
|
|
2
2
|
import type Asset from "#asset/Asset";
|
|
3
|
-
import
|
|
3
|
+
import Bag from "#Bag";
|
|
4
4
|
import type ViewOptions from "#client/ViewOptions";
|
|
5
5
|
import type ViewResponse from "#client/ViewResponse";
|
|
6
|
-
import type I18NConfig from "#i18n/Config";
|
|
7
6
|
import type RequestFacade from "#request/RequestFacade";
|
|
8
7
|
import type RouteHandler from "#route/Handler";
|
|
9
8
|
import type ServeInit from "#serve/Init";
|
|
10
9
|
import FileRouter from "@rcompat/fs/FileRouter";
|
|
11
10
|
import type { Actions } from "@rcompat/http";
|
|
12
|
-
import type { Dict } from "@rcompat/type";
|
|
13
11
|
interface FullViewOptions extends ViewOptions {
|
|
14
12
|
body: string;
|
|
15
13
|
}
|
|
16
|
-
interface PublishOptions {
|
|
17
|
-
code: string;
|
|
18
|
-
inline: boolean;
|
|
19
|
-
src?: string;
|
|
20
|
-
type: string;
|
|
21
|
-
}
|
|
22
14
|
export default class ServeApp extends App {
|
|
23
15
|
#private;
|
|
24
16
|
constructor(rootfile: string, init: ServeInit);
|
|
@@ -27,9 +19,7 @@ export default class ServeApp extends App {
|
|
|
27
19
|
get frontends(): {
|
|
28
20
|
[k: string]: ViewResponse;
|
|
29
21
|
};
|
|
30
|
-
get
|
|
31
|
-
get i18n(): I18NConfig | undefined;
|
|
32
|
-
loadView<T = ServerView>(name: string): T;
|
|
22
|
+
get views(): Bag;
|
|
33
23
|
headers(csp?: {}): {
|
|
34
24
|
"Content-Security-Policy"?: string | undefined;
|
|
35
25
|
};
|
|
@@ -38,7 +28,6 @@ export default class ServeApp extends App {
|
|
|
38
28
|
respond(body: BodyInit | null, init?: ResponseInit): Response;
|
|
39
29
|
view(options: FullViewOptions): Response;
|
|
40
30
|
media(content_type: string, response?: ResponseInit): ResponseInit;
|
|
41
|
-
publish({ code, inline, src, type }: PublishOptions): Promise<void>;
|
|
42
31
|
create_csp(): void;
|
|
43
32
|
frontend(extension: string, view_response: ViewResponse): void;
|
|
44
33
|
page(name?: string): string;
|
package/lib/private/serve/App.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import App from "#App";
|
|
2
2
|
import { s_config } from "#app/Facade";
|
|
3
|
+
import Bag from "#Bag";
|
|
3
4
|
import E from "#errors";
|
|
4
5
|
import hash from "#hash";
|
|
5
6
|
import i18n_module from "#i18n/module";
|
|
@@ -48,6 +49,36 @@ const render_head = (assets, head) => {
|
|
|
48
49
|
? tags.style({ code, href: src, inline })
|
|
49
50
|
: tags.script({ code, inline, integrity, src, type })).join("\n")).concat("\n", head ?? "");
|
|
50
51
|
};
|
|
52
|
+
function entrypoint_name(src) {
|
|
53
|
+
const file = src.split("/").at(-1) ?? src;
|
|
54
|
+
return file.replace(/-[A-Z0-9]+(?=\.(?:js|css)$)/i, "")
|
|
55
|
+
.replace(/\.(?:js|css)$/i, "");
|
|
56
|
+
}
|
|
57
|
+
function render_entrypoint(asset) {
|
|
58
|
+
if (asset.type === "style") {
|
|
59
|
+
return tags.style({
|
|
60
|
+
code: asset.code,
|
|
61
|
+
href: asset.src,
|
|
62
|
+
inline: asset.inline,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return tags.script({
|
|
66
|
+
code: asset.code,
|
|
67
|
+
inline: asset.inline,
|
|
68
|
+
integrity: asset.integrity,
|
|
69
|
+
src: asset.src,
|
|
70
|
+
type: "module",
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
function render_entrypoints(assets, names) {
|
|
74
|
+
return Object.fromEntries(names.map(name => {
|
|
75
|
+
const asset = assets.find(asset => asset.src !== undefined && entrypoint_name(asset.src) === name);
|
|
76
|
+
if (asset === undefined) {
|
|
77
|
+
throw new Error(`entrypoint ${name} not emitted`);
|
|
78
|
+
}
|
|
79
|
+
return [name, render_entrypoint(asset)];
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
51
82
|
const s_http = Symbol("s_http");
|
|
52
83
|
const content_type_method = {
|
|
53
84
|
"application/json": "json",
|
|
@@ -56,7 +87,7 @@ const content_type_method = {
|
|
|
56
87
|
"multipart/form-data": "multipart",
|
|
57
88
|
"application/octet-stream": "blob",
|
|
58
89
|
};
|
|
59
|
-
;
|
|
90
|
+
const asset_extensions = [".js", ".css", ".woff2"];
|
|
60
91
|
export default class ServeApp extends App {
|
|
61
92
|
#init;
|
|
62
93
|
#server;
|
|
@@ -65,10 +96,9 @@ export default class ServeApp extends App {
|
|
|
65
96
|
#assets = [];
|
|
66
97
|
#serve_assets;
|
|
67
98
|
#pages;
|
|
68
|
-
#stores;
|
|
69
99
|
#frontends = new Map();
|
|
70
100
|
#router;
|
|
71
|
-
#
|
|
101
|
+
#entrypoints = {};
|
|
72
102
|
constructor(rootfile, init) {
|
|
73
103
|
const dir = fs.ref(rootfile).directory;
|
|
74
104
|
super(dir, init.facade[s_config], {
|
|
@@ -78,12 +108,18 @@ export default class ServeApp extends App {
|
|
|
78
108
|
log: init.log,
|
|
79
109
|
});
|
|
80
110
|
this.#init = init;
|
|
81
|
-
this.#views =
|
|
82
|
-
|
|
111
|
+
this.#views = new Bag((init.views ?? []).map(([k, v]) => {
|
|
112
|
+
if (is.undefined(v.default))
|
|
113
|
+
throw E.view_missing_default_export(k);
|
|
114
|
+
return [k, v.default];
|
|
115
|
+
}), name => {
|
|
116
|
+
const f = fs.ref(name).path;
|
|
117
|
+
const extension = Object.keys(this.frontends).find(e => f.endsWith(e));
|
|
118
|
+
return is.undefined(extension) ? name : f.slice(0, -extension.length);
|
|
119
|
+
});
|
|
83
120
|
this.#serve_assets = init.assets;
|
|
84
121
|
this.#pages = init.pages;
|
|
85
122
|
const http_config = this.#init.facade[s_config].http;
|
|
86
|
-
this.#i18n_config = init.i18n;
|
|
87
123
|
this.set(s_http, {
|
|
88
124
|
host: http_config.host,
|
|
89
125
|
port: http_config.port,
|
|
@@ -107,8 +143,9 @@ export default class ServeApp extends App {
|
|
|
107
143
|
if (init.session !== undefined) {
|
|
108
144
|
this.register(session_module(init.session));
|
|
109
145
|
}
|
|
110
|
-
|
|
111
|
-
|
|
146
|
+
const i18n_config = init.facade[s_config].i18n;
|
|
147
|
+
if (i18n_config !== undefined)
|
|
148
|
+
this.register(i18n_module(i18n_config));
|
|
112
149
|
this.register(create({
|
|
113
150
|
name: "builtin/handle",
|
|
114
151
|
setup({ onHandle }) {
|
|
@@ -139,25 +176,9 @@ export default class ServeApp extends App {
|
|
|
139
176
|
get frontends() {
|
|
140
177
|
return Object.fromEntries(this.#frontends);
|
|
141
178
|
}
|
|
142
|
-
get
|
|
143
|
-
return this.#
|
|
144
|
-
}
|
|
145
|
-
get i18n() {
|
|
146
|
-
return this.#i18n_config;
|
|
147
|
-
}
|
|
148
|
-
loadView(name) {
|
|
149
|
-
const f = fs.ref(name).path;
|
|
150
|
-
const frontends = Object.keys(this.frontends);
|
|
151
|
-
const extension = frontends.find(client => f.endsWith(client));
|
|
152
|
-
const base = is.undefined(extension) ? name : f.slice(0, -extension.length);
|
|
153
|
-
const view = this.#views[base];
|
|
154
|
-
if (is.undefined(view))
|
|
155
|
-
throw E.view_missing(name);
|
|
156
|
-
if (is.undefined(view.default))
|
|
157
|
-
throw E.view_missing_default_export(name);
|
|
158
|
-
return view.default;
|
|
179
|
+
get views() {
|
|
180
|
+
return this.#views;
|
|
159
181
|
}
|
|
160
|
-
;
|
|
161
182
|
headers(csp = {}) {
|
|
162
183
|
const base = Object.entries(this.config("http.csp") ?? {});
|
|
163
184
|
return {
|
|
@@ -171,7 +192,12 @@ export default class ServeApp extends App {
|
|
|
171
192
|
render(content) {
|
|
172
193
|
const { body, head, page, partial, placeholders = {} } = content;
|
|
173
194
|
["body", "head"].forEach(key => assert.undefined(placeholders[key]));
|
|
174
|
-
|
|
195
|
+
const all_placeholders = {
|
|
196
|
+
...this.#entrypoints,
|
|
197
|
+
...placeholders,
|
|
198
|
+
};
|
|
199
|
+
const entrypoint_names = Object.keys(this.config("entrypoints") ?? {});
|
|
200
|
+
return partial === true ? body : Object.entries(all_placeholders)
|
|
175
201
|
// replace given placeholders, defaulting to ""
|
|
176
202
|
.reduce((rendered, [key, value]) => rendered
|
|
177
203
|
.replaceAll(`%${key}%`, value?.toString() ?? ""), this.page(page))
|
|
@@ -179,7 +205,8 @@ export default class ServeApp extends App {
|
|
|
179
205
|
.replaceAll(/(?<keep>%(?:head|body)%)|%.*?%/gus, "$1")
|
|
180
206
|
// replace body and head
|
|
181
207
|
.replace("%body%", body)
|
|
182
|
-
.replace("%head%", render_head(this.#assets
|
|
208
|
+
.replace("%head%", render_head(this.#assets.filter(asset => asset.src === undefined
|
|
209
|
+
|| !entrypoint_names.includes(entrypoint_name(asset.src))), head));
|
|
183
210
|
}
|
|
184
211
|
body_length(body) {
|
|
185
212
|
return is.string(body) ? utf8.size(body) : 0;
|
|
@@ -214,20 +241,6 @@ export default class ServeApp extends App {
|
|
|
214
241
|
};
|
|
215
242
|
}
|
|
216
243
|
;
|
|
217
|
-
async publish({ code, inline = false, src, type = "" }) {
|
|
218
|
-
if (inline || type === "style") {
|
|
219
|
-
this.#assets.push({
|
|
220
|
-
code: inline ? code : "",
|
|
221
|
-
inline,
|
|
222
|
-
integrity: await hash(code),
|
|
223
|
-
src: fs.join(this.config("http.static.root"), src ?? "").path,
|
|
224
|
-
type,
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
// rehash assets_csp
|
|
228
|
-
this.create_csp();
|
|
229
|
-
}
|
|
230
|
-
;
|
|
231
244
|
create_csp() {
|
|
232
245
|
this.#csp = this.#assets.map(({ integrity, type: directive }) => [`${directive === "style" ? "style" : "script"}-src`, integrity])
|
|
233
246
|
.reduce((csp, [directive, _hash]) => ({
|
|
@@ -293,7 +306,7 @@ export default class ServeApp extends App {
|
|
|
293
306
|
async start() {
|
|
294
307
|
if (this.mode === "production") {
|
|
295
308
|
this.#assets = await Promise.all(Object.entries(this.#serve_assets.client)
|
|
296
|
-
.filter(([src]) =>
|
|
309
|
+
.filter(([src]) => asset_extensions.some(ext => src.endsWith(ext)))
|
|
297
310
|
.map(async ([src, asset]) => {
|
|
298
311
|
const type = src.endsWith(".css") ? "style" : "js";
|
|
299
312
|
const code = atob(asset.data);
|
|
@@ -311,7 +324,7 @@ export default class ServeApp extends App {
|
|
|
311
324
|
const files = await client_dir.exists()
|
|
312
325
|
? await client_dir.files({
|
|
313
326
|
recursive: true,
|
|
314
|
-
filter: info =>
|
|
327
|
+
filter: info => asset_extensions.includes(info.extension),
|
|
315
328
|
})
|
|
316
329
|
: [];
|
|
317
330
|
this.#assets = await Promise.all(files.map(async (file) => {
|
|
@@ -326,6 +339,8 @@ export default class ServeApp extends App {
|
|
|
326
339
|
};
|
|
327
340
|
}));
|
|
328
341
|
}
|
|
342
|
+
this.#entrypoints = render_entrypoints(this.#assets, Object.keys(this.config("entrypoints") ?? {}));
|
|
343
|
+
this.create_csp();
|
|
329
344
|
this.#server = await serve(async (request) => {
|
|
330
345
|
try {
|
|
331
346
|
return await handle(this, parse(request));
|
|
@@ -387,7 +402,7 @@ export default class ServeApp extends App {
|
|
|
387
402
|
return undefined;
|
|
388
403
|
}
|
|
389
404
|
const handler = route_path.handler;
|
|
390
|
-
const { contentType, body } = route_path.options;
|
|
405
|
+
const { contentType, body, path } = route_path.options;
|
|
391
406
|
if (contentType !== undefined) {
|
|
392
407
|
const raw = request.headers.try("content-type") ?? "";
|
|
393
408
|
const actual = raw.split(";")[0].trim().toLowerCase();
|
|
@@ -396,7 +411,9 @@ export default class ServeApp extends App {
|
|
|
396
411
|
}
|
|
397
412
|
}
|
|
398
413
|
const refined = Object.assign(Object.create(request), {
|
|
399
|
-
path: new RequestBag(
|
|
414
|
+
path: new RequestBag(is.defined(path)
|
|
415
|
+
? path.parse(matched.params)
|
|
416
|
+
: matched.params, "path", {
|
|
400
417
|
normalize: k => k.toLowerCase(),
|
|
401
418
|
raw: request.url.pathname,
|
|
402
419
|
}),
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type AppFacade from "#app/Facade";
|
|
2
|
-
import type I18NConfig from "#i18n/Config";
|
|
3
2
|
import type { Schema as LogSchema } from "#logger";
|
|
4
3
|
import type Mode from "#Mode";
|
|
5
4
|
import type SessionConfig from "#session/Config";
|
|
@@ -19,7 +18,6 @@ type ServeInit = {
|
|
|
19
18
|
}>;
|
|
20
19
|
};
|
|
21
20
|
views?: [string, Import][];
|
|
22
|
-
stores?: [string, Import][];
|
|
23
21
|
facade: AppFacade;
|
|
24
22
|
routes: [string, {
|
|
25
23
|
default: any;
|
|
@@ -29,7 +27,6 @@ type ServeInit = {
|
|
|
29
27
|
log: typeof LogSchema.infer;
|
|
30
28
|
pages: Dict<string>;
|
|
31
29
|
session?: SessionConfig;
|
|
32
|
-
i18n?: I18NConfig;
|
|
33
30
|
};
|
|
34
31
|
export type { ServeInit as default };
|
|
35
32
|
//# sourceMappingURL=Init.d.ts.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export default function session() {
|
|
2
|
+
const facade = {
|
|
3
|
+
get id() {
|
|
4
|
+
return "";
|
|
5
|
+
},
|
|
6
|
+
get exists() {
|
|
7
|
+
return false;
|
|
8
|
+
},
|
|
9
|
+
create() {
|
|
10
|
+
},
|
|
11
|
+
get() {
|
|
12
|
+
return {};
|
|
13
|
+
},
|
|
14
|
+
try() {
|
|
15
|
+
return {};
|
|
16
|
+
},
|
|
17
|
+
set() {
|
|
18
|
+
},
|
|
19
|
+
destroy() {
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
return facade;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=config.client.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import configSchema from "#session/schema";
|
|
2
|
+
import type SessionFacade from "#session/SessionFacade";
|
|
3
|
+
import type Store from "#store/Store";
|
|
4
|
+
import type { InferStore, StoreSchema } from "pema";
|
|
5
|
+
type ConfigInput = typeof configSchema.input;
|
|
6
|
+
type X<T> = {
|
|
7
|
+
[K in keyof T]: T[K];
|
|
8
|
+
} & {};
|
|
9
|
+
type Infer<S extends StoreSchema> = X<Omit<InferStore<S>, "id" | "session_id">>;
|
|
10
|
+
export default function session<S extends StoreSchema>(config: {
|
|
11
|
+
store: Store<S>;
|
|
12
|
+
} & Partial<ConfigInput>): SessionFacade<Infer<S>>;
|
|
13
|
+
export default function session(Infer?: Omit<Partial<ConfigInput>, "store">): SessionFacade<unknown>;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=config.server.d.ts.map
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import E from "#errors";
|
|
2
|
+
import configSchema from "#session/schema";
|
|
3
|
+
import local_storage from "#session/storage";
|
|
4
|
+
import s_config from "#symbol/config";
|
|
5
|
+
export default function session(config) {
|
|
6
|
+
const parsed = configSchema.parse(config ?? {});
|
|
7
|
+
const store = parsed.store;
|
|
8
|
+
// bind the ALS store to this T
|
|
9
|
+
const storage = local_storage();
|
|
10
|
+
const current = () => {
|
|
11
|
+
const s = storage.getStore();
|
|
12
|
+
if (s === undefined)
|
|
13
|
+
throw E.session_handle_unavailable();
|
|
14
|
+
return s;
|
|
15
|
+
};
|
|
16
|
+
const facade = {
|
|
17
|
+
get id() {
|
|
18
|
+
return current().id;
|
|
19
|
+
},
|
|
20
|
+
get exists() {
|
|
21
|
+
return current().exists;
|
|
22
|
+
},
|
|
23
|
+
create(initial) {
|
|
24
|
+
current().create(initial);
|
|
25
|
+
},
|
|
26
|
+
get() {
|
|
27
|
+
return current().get();
|
|
28
|
+
},
|
|
29
|
+
try() {
|
|
30
|
+
return current().try();
|
|
31
|
+
},
|
|
32
|
+
set(next) {
|
|
33
|
+
current().set(next);
|
|
34
|
+
},
|
|
35
|
+
destroy() {
|
|
36
|
+
current().destroy();
|
|
37
|
+
},
|
|
38
|
+
get [s_config]() {
|
|
39
|
+
return { ...parsed, store };
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
return facade;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=config.server.js.map
|
|
@@ -1,15 +1,3 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import type Store from "#store/Store";
|
|
4
|
-
import type { InferStore, StoreSchema } from "pema";
|
|
5
|
-
type ConfigInput = typeof configSchema.input;
|
|
6
|
-
type X<T> = {
|
|
7
|
-
[K in keyof T]: T[K];
|
|
8
|
-
} & {};
|
|
9
|
-
type Infer<S extends StoreSchema> = X<Omit<InferStore<S>, "id" | "session_id">>;
|
|
10
|
-
export default function session<S extends StoreSchema>(config: {
|
|
11
|
-
store: Store<S>;
|
|
12
|
-
} & Partial<ConfigInput>): SessionFacade<Infer<S>>;
|
|
13
|
-
export default function session(Infer?: Omit<Partial<ConfigInput>, "store">): SessionFacade<unknown>;
|
|
14
|
-
export {};
|
|
1
|
+
import config from "#session/config";
|
|
2
|
+
export default config;
|
|
15
3
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,44 +1,3 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import local_storage from "#session/storage";
|
|
4
|
-
import s_config from "#symbol/config";
|
|
5
|
-
export default function session(config) {
|
|
6
|
-
const parsed = configSchema.parse(config ?? {});
|
|
7
|
-
const store = parsed.store;
|
|
8
|
-
// bind the ALS store to this T
|
|
9
|
-
const storage = local_storage();
|
|
10
|
-
const current = () => {
|
|
11
|
-
const s = storage.getStore();
|
|
12
|
-
if (s === undefined)
|
|
13
|
-
throw E.session_handle_unavailable();
|
|
14
|
-
return s;
|
|
15
|
-
};
|
|
16
|
-
const facade = {
|
|
17
|
-
get id() {
|
|
18
|
-
return current().id;
|
|
19
|
-
},
|
|
20
|
-
get exists() {
|
|
21
|
-
return current().exists;
|
|
22
|
-
},
|
|
23
|
-
create(initial) {
|
|
24
|
-
current().create(initial);
|
|
25
|
-
},
|
|
26
|
-
get() {
|
|
27
|
-
return current().get();
|
|
28
|
-
},
|
|
29
|
-
try() {
|
|
30
|
-
return current().try();
|
|
31
|
-
},
|
|
32
|
-
set(next) {
|
|
33
|
-
current().set(next);
|
|
34
|
-
},
|
|
35
|
-
destroy() {
|
|
36
|
-
current().destroy();
|
|
37
|
-
},
|
|
38
|
-
get [s_config]() {
|
|
39
|
-
return { ...parsed, store };
|
|
40
|
-
},
|
|
41
|
-
};
|
|
42
|
-
return facade;
|
|
43
|
-
}
|
|
1
|
+
import config from "#session/config";
|
|
2
|
+
export default config;
|
|
44
3
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import Store from "#store/Store";
|
|
2
2
|
declare const _default: import("pema").ObjectType<import("pema").NormalizeSchemaObject<{
|
|
3
3
|
readonly cookie: {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
httpOnly: import("pema").DefaultType<import("pema").BooleanType<undefined>, true>;
|
|
5
|
+
name: import("pema").DefaultType<import("pema").StringType, "session_id">;
|
|
6
|
+
path: import("pema").DefaultType<import("pema").StringType, "/">;
|
|
7
|
+
sameSite: import("pema").DefaultType<import("pema").UnionType<[import("pema").LiteralType<"Strict", undefined>, import("pema").LiteralType<"Lax", undefined>, import("pema").LiteralType<"None", undefined>], undefined>, "Lax" | "None" | "Strict">;
|
|
8
8
|
};
|
|
9
9
|
readonly store: import("pema").DefaultType<import("pema").ConstructorType<typeof Store>, Store<import("../store/StoreInput.js").default, string>>;
|
|
10
|
-
}>, {
|
|
10
|
+
}>, undefined, {
|
|
11
11
|
cookie: {
|
|
12
12
|
httpOnly: boolean;
|
|
13
13
|
name: string;
|
|
@@ -8,7 +8,7 @@ export default class PrimaryKey<T extends AllowedPKType> {
|
|
|
8
8
|
constructor(type: T, options?: Options);
|
|
9
9
|
static new<T extends AllowedPKType>(type: T, options?: Options): PrimaryKey<T>;
|
|
10
10
|
get type(): T;
|
|
11
|
-
get datatype(): "
|
|
11
|
+
get datatype(): "u128" | "u16" | "u32" | "u64" | "u8" | "uuid" | "uuid_v4" | "uuid_v7";
|
|
12
12
|
get name(): string;
|
|
13
13
|
get nullable(): boolean;
|
|
14
14
|
get generate(): boolean;
|
|
@@ -7,5 +7,18 @@ declare function store(): {
|
|
|
7
7
|
update: () => Promise<number>;
|
|
8
8
|
delete: () => Promise<number>;
|
|
9
9
|
};
|
|
10
|
+
declare namespace store {
|
|
11
|
+
var key: {
|
|
12
|
+
primary(): void;
|
|
13
|
+
foreign(): void;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
declare namespace store {
|
|
17
|
+
var relation: {
|
|
18
|
+
one(): void;
|
|
19
|
+
many(): void;
|
|
20
|
+
is(): void;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
10
23
|
export default store;
|
|
11
24
|
//# sourceMappingURL=store.client.d.ts.map
|
|
@@ -14,5 +14,14 @@ function store() {
|
|
|
14
14
|
delete: async () => 0,
|
|
15
15
|
};
|
|
16
16
|
}
|
|
17
|
+
store.key = {
|
|
18
|
+
primary() { },
|
|
19
|
+
foreign() { },
|
|
20
|
+
};
|
|
21
|
+
store.relation = {
|
|
22
|
+
one() { },
|
|
23
|
+
many() { },
|
|
24
|
+
is() { },
|
|
25
|
+
};
|
|
17
26
|
export default store;
|
|
18
27
|
//# sourceMappingURL=store.client.js.map
|