@primate/core 0.7.3 → 0.7.4

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.
@@ -2,12 +2,12 @@ declare const _default: import("pema").ObjectType<import("pema").NormalizeSchema
2
2
  readonly mode: import("pema").DefaultType<import("pema").UnionType<[import("pema").LiteralType<"production">, import("pema").LiteralType<"development">, import("pema").LiteralType<"testing">]>, "development" | "production" | "testing">;
3
3
  readonly target: import("pema").DefaultType<import("pema").StringType, "web">;
4
4
  readonly outdir: import("pema").DefaultType<import("pema").StringType, "build">;
5
- readonly log: import("pema").DefaultType<import("pema").UnionType<[import("pema").LiteralType<"error">, import("pema").LiteralType<"warn">, import("pema").LiteralType<"info">, import("pema").LiteralType<"trace">]>, "trace" | "info" | "error" | "warn">;
5
+ readonly log: import("pema").DefaultType<import("pema").UnionType<[import("pema").LiteralType<"error">, import("pema").LiteralType<"warn">, import("pema").LiteralType<"info">, import("pema").LiteralType<"trace">]>, "info" | "error" | "trace" | "warn">;
6
6
  }>, {
7
7
  mode: "development" | "production" | "testing";
8
8
  target: string;
9
9
  outdir: string;
10
- log: "trace" | "info" | "error" | "warn";
10
+ log: "info" | "error" | "trace" | "warn";
11
11
  }>;
12
12
  export default _default;
13
13
  //# sourceMappingURL=Flags.d.ts.map
@@ -1,6 +1,8 @@
1
1
  import plugin_alias from "#build/client/plugin/alias";
2
2
  import plugin_entrypoint from "#build/client/plugin/entrypoint";
3
3
  import plugin_frontend from "#build/client/plugin/frontend";
4
+ import plugin_route_module from "#build/client/plugin/route-module";
5
+ import plugin_route_view from "#build/client/plugin/route-view";
4
6
  import plugin_routes from "#build/client/plugin/routes";
5
7
  import plugin_server_stamp from "#build/client/plugin/server-stamp";
6
8
  import plugin_view from "#build/client/plugin/view";
@@ -53,6 +55,8 @@ export default async function build_client(app) {
53
55
  app.plugin("client", plugin_alias(app));
54
56
  app.plugin("client", plugin_view(app));
55
57
  app.plugin("client", plugin_app_request(app));
58
+ app.plugin("client", plugin_route_view(app));
59
+ app.plugin("client", plugin_route_module(app));
56
60
  app.plugin("client", plugin_routes(app));
57
61
  app.plugin("client", plugin_server_stamp(app));
58
62
  app.plugin("client", plugin_entrypoint(app));
@@ -0,0 +1,4 @@
1
+ import type BuildApp from "#build/App";
2
+ import type { Plugin } from "esbuild";
3
+ export default function plugin_client_route_module(app: BuildApp): Plugin;
4
+ //# sourceMappingURL=route-module.d.ts.map
@@ -0,0 +1,32 @@
1
+ import fs from "@rcompat/fs";
2
+ export default function plugin_client_route_module(app) {
3
+ return {
4
+ name: "primate/client/route-module",
5
+ setup(build) {
6
+ build.onResolve({ filter: /^app:route\// }, args => {
7
+ const rel = args.path.slice("app:route/".length);
8
+ return { path: rel, namespace: "primate-route" };
9
+ });
10
+ build.onLoad({ filter: /.*/, namespace: "primate-route" }, async (args) => {
11
+ const base = app.path.routes.join(args.path);
12
+ for (const ext of app.extensions) {
13
+ const candidate = fs.ref(base.path + ext);
14
+ if (await candidate.exists()) {
15
+ const binder = app.binder(candidate);
16
+ const contents = binder
17
+ ? await binder(candidate, { build: { id: app.id }, context: "routes" })
18
+ : await candidate.text();
19
+ return {
20
+ contents,
21
+ loader: ext === ".ts" ? "ts" : "js",
22
+ resolveDir: candidate.directory.path,
23
+ watchFiles: [candidate.path],
24
+ };
25
+ }
26
+ }
27
+ return null;
28
+ });
29
+ },
30
+ };
31
+ }
32
+ //# sourceMappingURL=route-module.js.map
@@ -0,0 +1,4 @@
1
+ import type BuildApp from "#build/App";
2
+ import type { Plugin } from "esbuild";
3
+ export default function plugin_client_route_view(app: BuildApp): Plugin;
4
+ //# sourceMappingURL=route-view.d.ts.map
@@ -0,0 +1,37 @@
1
+ import fs from "@rcompat/fs";
2
+ export default function plugin_client_route_view(app) {
3
+ return {
4
+ name: "primate/client/route-view",
5
+ setup(build) {
6
+ build.onResolve({ filter: /.*/ }, async (args) => {
7
+ if (args.namespace !== "primate-route")
8
+ return null;
9
+ if (args.pluginData === "primate-view-inner")
10
+ return null;
11
+ const result = await build.resolve(args.path, {
12
+ resolveDir: args.resolveDir,
13
+ kind: args.kind,
14
+ pluginData: "primate-view-inner",
15
+ });
16
+ if (result.errors.length > 0 || !result.path)
17
+ return null;
18
+ const resolved = fs.ref(result.path);
19
+ if (!resolved.path.startsWith(app.path.views.path + "/"))
20
+ return null;
21
+ return {
22
+ path: resolved.path,
23
+ namespace: "primate-client-route-view",
24
+ };
25
+ });
26
+ build.onLoad({ filter: /.*/, namespace: "primate-client-route-view" }, args => {
27
+ const rel = fs.ref(args.path).debase(app.path.views).path.replace(/^[\\/]/, "");
28
+ return {
29
+ contents: `export default ${JSON.stringify(rel)};`,
30
+ loader: "js",
31
+ resolveDir: app.root.path,
32
+ };
33
+ });
34
+ },
35
+ };
36
+ }
37
+ //# sourceMappingURL=route-view.js.map
@@ -1,29 +1,9 @@
1
1
  import intercept from "#build/shared/intercept";
2
- import E from "#errors";
3
2
  import fs from "@rcompat/fs";
4
- const body_serializer = {
5
- "application/json": "JSON.stringify(body)",
6
- "application/x-www-form-urlencoded": "new URLSearchParams(body).toString()",
7
- "multipart/form-data": "body",
8
- "text/plain": "body",
9
- "application/octet-stream": "body",
10
- };
11
3
  export default function plugin_client_routes(app) {
12
- let manifest;
13
- async function get_manifest() {
14
- if (manifest === undefined) {
15
- manifest = await app.path.build
16
- .join("route.manifest.json")
17
- .json();
18
- }
19
- return manifest;
20
- }
21
4
  return {
22
5
  name: "primate/client/routes",
23
6
  setup(build) {
24
- build.onStart(() => {
25
- manifest = undefined;
26
- });
27
7
  build.onResolve({ filter: /.*/ }, async (args) => {
28
8
  if (args.pluginData === "primate-client-route-inner")
29
9
  return null;
@@ -40,36 +20,24 @@ export default function plugin_client_routes(app) {
40
20
  if (!resolved.path.startsWith(app.path.routes.path + "/"))
41
21
  return null;
42
22
  const rel = app.basename(resolved, app.path.routes);
43
- return { path: rel, namespace: "primate-client-route" };
23
+ return {
24
+ namespace: "primate-client-route",
25
+ path: resolved.path,
26
+ pluginData: { rel },
27
+ };
44
28
  });
45
29
  build.onLoad({ filter: /.*/, namespace: "primate-client-route" }, async (args) => {
46
- const manifest = await get_manifest();
47
- const methods_def = manifest[args.path];
48
- if (!methods_def)
49
- throw new Error(`no manifest entry for ${args.path}`);
50
- if (args.path.includes("["))
51
- throw E.build_no_path_schema(args.path);
52
- const methods = Object.entries(methods_def).map(([method, { contentType }]) => {
53
- const arg = contentType ? "{ body }" : "";
54
- const headers = contentType && contentType !== "multipart/form-data"
55
- ? `{ "Content-Type": "${contentType}" }`
56
- : "{}";
57
- const body_str = contentType !== undefined
58
- ? (body_serializer[contentType] ?? "body")
59
- : "undefined";
60
- const method_fn = `async (${arg}) => fetch("/${args.path}", {
61
- method: "${method.toUpperCase()}",
62
- headers: ${headers},
63
- ${contentType ? `body: ${body_str},` : ""}
64
- })`;
65
- return `
66
- ${method}: Object.assign(${method_fn}, {
67
- contentType: ${contentType ? `"${contentType}"` : "undefined"},
68
- }),
69
- `;
70
- }).join("\n");
71
- const contents = `export default { ${methods} };`;
72
- return { contents, loader: "js", resolveDir: app.root.path };
30
+ const file = fs.ref(args.path);
31
+ const rel = args.pluginData.rel;
32
+ return {
33
+ contents: `
34
+ import _mod from "app:route/${rel}";
35
+ export default _mod.connect(${JSON.stringify(`/${rel}`)});
36
+ `,
37
+ loader: "js",
38
+ resolveDir: app.root.path,
39
+ watchFiles: [file.path],
40
+ };
73
41
  });
74
42
  },
75
43
  };
@@ -1,5 +1,4 @@
1
1
  import build_client from "#build/client/index";
2
- import build_preclient from "#build/preclient/index";
3
2
  import build_server from "#build/server/index";
4
3
  import E from "#errors";
5
4
  import location from "#location";
@@ -33,8 +32,6 @@ async function pre(app) {
33
32
  app.session_active = await session_ts.exists() || await session_js.exists();
34
33
  }
35
34
  async function post(app) {
36
- app.log.trace `building preclient`;
37
- await build_preclient(app);
38
35
  app.log.trace `building client`;
39
36
  await build_client(app);
40
37
  app.log.trace `building server`;
@@ -1,46 +1,5 @@
1
1
  import intercept from "#build/shared/intercept";
2
2
  import fs from "@rcompat/fs";
3
- const fake_body = {
4
- "application/json": `{
5
- json: () => body,
6
- text: () => JSON.stringify(body),
7
- form: () => { throw new Error("cannot parse JSON as form") },
8
- multipart: () => { throw new Error("cannot parse JSON as multipart") },
9
- blob: () => new Blob([JSON.stringify(body)]),
10
- }`,
11
- "text/plain": `{
12
- json: () => JSON.parse(body),
13
- text: () => body,
14
- form: () => { throw new Error("cannot parse text as form") },
15
- multipart: () => { throw new Error("cannot parse text as multipart") },
16
- blob: () => new Blob([body]),
17
- }`,
18
- "application/x-www-form-urlencoded": `{
19
- json: () => { throw new Error("cannot parse form as JSON") },
20
- text: () => new URLSearchParams(body).toString(),
21
- //form: () => body,
22
- form: () => Object.fromEntries(new URLSearchParams(body)),
23
- multipart: () => ({ form: body, files: [] }),
24
- blob: () => new Blob([new URLSearchParams(body).toString()]),
25
- }`,
26
- "multipart/form-data": `{
27
- json: () => { throw new Error("cannot parse multipart as JSON") },
28
- text: () => body,
29
- form: () => body.form,
30
- multipart: () => ({
31
- form: Object.fromEntries([...body.entries()].filter(([, v]) => !(v instanceof File))),
32
- files: Object.fromEntries([...body.entries()].filter(([, v]) => v instanceof File)),
33
- }),
34
- blob: () => new Blob([]),
35
- }`,
36
- "application/octet-stream": `{
37
- json: () => { throw new Error("cannot parse binary as JSON") },
38
- text: () => body.text(),
39
- form: () => { throw new Error("cannot parse binary as form") },
40
- multipart: () => { throw new Error("cannot parse binary as multipart") },
41
- blob: () => body,
42
- }`,
43
- };
44
3
  export default function plugin_server_route_client(app) {
45
4
  return {
46
5
  name: "primate/server/route-client",
@@ -65,45 +24,129 @@ export default function plugin_server_route_client(app) {
65
24
  if (!args.resolveDir.startsWith(app.path.views.path))
66
25
  return null;
67
26
  const rel = app.basename(resolved, app.path.routes);
68
- return { path: rel, namespace: "primate-server-route-client" };
27
+ return {
28
+ path: rel,
29
+ namespace: "primate-server-route-client",
30
+ };
69
31
  });
70
32
  build.onLoad({ filter: /.*/, namespace: "primate-server-route-client" }, async (args) => {
71
- const manifest = await app.path.build
72
- .join("route.manifest.json")
73
- .json();
74
- const methods_def = manifest[args.path];
75
- if (!methods_def)
76
- throw new Error(`no manifest entry for ${args.path}`);
77
- const methods = Object.entries(methods_def).map(([method, { contentType }]) => {
78
- const arg = contentType ? "{ body }" : "";
79
- const fake = contentType
80
- ? `{ body: ${fake_body[contentType] ?? fake_body["application/json"]} }`
81
- : "{}";
82
- return `
83
- ${method}: async (${arg}) => {
84
- const { handler } = mod.${method};
85
- const result = await handler(${fake});
86
- if (result instanceof Blob) {
87
- return new Response(result, {
88
- headers: { "Content-Type": result.type || "application/octet-stream" },
89
- });
90
- }
91
- if (typeof result === "string") {
92
- return new Response(result, {
93
- headers: { "Content-Type": "text/plain" },
94
- });
95
- }
96
- return new Response(JSON.stringify(result), {
97
- headers: { "Content-Type": "application/json" },
98
- });
99
- },
100
- `;
101
- }).join("\n");
102
33
  const contents = `
103
34
  import mod from "app:route/${args.path}";
104
- export default { ${methods} };
35
+
36
+ function fake_body(contentType, body) {
37
+ switch (contentType) {
38
+ case "application/json":
39
+ return {
40
+ json: () => body,
41
+ text: () => JSON.stringify(body),
42
+ form: () => { throw new Error("cannot parse JSON as form"); },
43
+ multipart: () => { throw new Error("cannot parse JSON as multipart"); },
44
+ blob: () => new Blob([JSON.stringify(body)]),
45
+ };
46
+
47
+ case "text/plain":
48
+ return {
49
+ json: () => JSON.parse(body),
50
+ text: () => body,
51
+ form: () => { throw new Error("cannot parse text as form"); },
52
+ multipart: () => { throw new Error("cannot parse text as multipart"); },
53
+ blob: () => new Blob([body]),
54
+ };
55
+
56
+ case "application/x-www-form-urlencoded":
57
+ return {
58
+ json: () => { throw new Error("cannot parse form as JSON"); },
59
+ text: () => new URLSearchParams(body).toString(),
60
+ form: () => Object.fromEntries(new URLSearchParams(body)),
61
+ multipart: () => ({ form: body, files: [] }),
62
+ blob: () => new Blob([new URLSearchParams(body).toString()]),
63
+ };
64
+
65
+ case "multipart/form-data":
66
+ return {
67
+ json: () => { throw new Error("cannot parse multipart as JSON"); },
68
+ text: () => body,
69
+ form: () => body.form,
70
+ multipart: () => ({
71
+ form: Object.fromEntries([...body.entries()].filter(([, v]) => !(v instanceof File))),
72
+ files: Object.fromEntries([...body.entries()].filter(([, v]) => v instanceof File)),
73
+ }),
74
+ blob: () => new Blob([]),
75
+ };
76
+
77
+ case "application/octet-stream":
78
+ return {
79
+ json: () => { throw new Error("cannot parse binary as JSON"); },
80
+ text: () => body.text(),
81
+ form: () => { throw new Error("cannot parse binary as form"); },
82
+ multipart: () => { throw new Error("cannot parse binary as multipart"); },
83
+ blob: () => body,
84
+ };
85
+
86
+ default:
87
+ return {
88
+ json: () => body,
89
+ text: () => JSON.stringify(body),
90
+ form: () => { throw new Error("cannot parse body as form"); },
91
+ multipart: () => { throw new Error("cannot parse body as multipart"); },
92
+ blob: () => new Blob([JSON.stringify(body)]),
93
+ };
94
+ }
95
+ }
96
+
97
+ function fake_request(contentType, body) {
98
+ return contentType === undefined
99
+ ? {}
100
+ : { body: fake_body(contentType, body) };
101
+ }
102
+
103
+ function to_response(result) {
104
+ if (result instanceof Response) {
105
+ return result;
106
+ }
107
+
108
+ if (result instanceof Blob) {
109
+ return new Response(result, {
110
+ headers: { "Content-Type": result.type || "application/octet-stream" },
111
+ });
112
+ }
113
+
114
+ if (typeof result === "string") {
115
+ return new Response(result, {
116
+ headers: { "Content-Type": "text/plain" },
117
+ });
118
+ }
119
+
120
+ if (result === null || result === undefined) {
121
+ return new Response(null, { status: 204 });
122
+ }
123
+
124
+ return new Response(JSON.stringify(result), {
125
+ headers: { "Content-Type": "application/json" },
126
+ });
127
+ }
128
+
129
+ export default Object.fromEntries(
130
+ Object.entries(mod).map(([method, route]) => {
131
+ const contentType = route.options?.contentType;
132
+
133
+ const client_method = async ({ body } = {}) => {
134
+ const result = await route.handler(fake_request(contentType, body));
135
+ return to_response(result);
136
+ };
137
+
138
+ return [
139
+ method,
140
+ Object.assign(client_method, { contentType }),
141
+ ];
142
+ }),
143
+ );
105
144
  `;
106
- return { contents, loader: "js", resolveDir: app.root.path };
145
+ return {
146
+ contents,
147
+ loader: "js",
148
+ resolveDir: app.root.path,
149
+ };
107
150
  });
108
151
  },
109
152
  };
@@ -219,6 +219,8 @@ export default function frontend_module(init) {
219
219
  });
220
220
  const filter = new RegExp(`(${extensions.map(e => e.replace(".", "\\.")).join("|")})$`);
221
221
  build.onLoad({ filter }, async (args) => {
222
+ if (args.namespace !== "file")
223
+ return null;
222
224
  const file = fs.ref(args.path);
223
225
  // compile file to JavaScript and potentially CSS
224
226
  const compiled = await compile_client(await file.text(), file, false);
@@ -1,5 +1,5 @@
1
1
  import type { LogHook } from "#module/Setup";
2
- declare const Schema: import("pema").DefaultType<import("pema").UnionType<[import("pema").LiteralType<"error">, import("pema").LiteralType<"warn">, import("pema").LiteralType<"info">, import("pema").LiteralType<"trace">]>, "trace" | "info" | "error" | "warn">;
2
+ declare const Schema: import("pema").DefaultType<import("pema").UnionType<[import("pema").LiteralType<"error">, import("pema").LiteralType<"warn">, import("pema").LiteralType<"info">, import("pema").LiteralType<"trace">]>, "info" | "error" | "trace" | "warn">;
3
3
  export { Schema };
4
4
  declare const levels: {
5
5
  readonly error: 0;
@@ -0,0 +1,13 @@
1
+ declare const _default: {
2
+ binary: () => never;
3
+ error: () => never;
4
+ json: () => never;
5
+ redirect: () => never;
6
+ sse: () => never;
7
+ text: () => never;
8
+ view: () => never;
9
+ ws: () => never;
10
+ null: () => never;
11
+ };
12
+ export default _default;
13
+ //# sourceMappingURL=response.client.d.ts.map
@@ -0,0 +1,15 @@
1
+ function server_only(name) {
2
+ throw new Error(`response.${name}() is server-only`);
3
+ }
4
+ export default {
5
+ binary: () => server_only("binary"),
6
+ error: () => server_only("error"),
7
+ json: () => server_only("json"),
8
+ redirect: () => server_only("redirect"),
9
+ sse: () => server_only("sse"),
10
+ text: () => server_only("text"),
11
+ view: () => server_only("view"),
12
+ ws: () => server_only("ws"),
13
+ null: () => server_only("null"),
14
+ };
15
+ //# sourceMappingURL=response.client.js.map
@@ -27,7 +27,14 @@ type WithResult<O extends RouteOptions> = {
27
27
  type RouteHandlers = {
28
28
  [key: string]: RouteHandler | WithResult<RouteOptions>;
29
29
  };
30
- declare function route<R extends RouteHandlers>(handlers: R): ClientRoute<R>;
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
+ };
31
38
  declare namespace route {
32
39
  var _a: <O extends RouteOptions>(options: O, handler: RouteHandler<O>) => WithResult<O>;
33
40
  export { _a as with };
@@ -1,5 +1,48 @@
1
+ function is_with(value) {
2
+ return typeof value === "object" &&
3
+ value !== null &&
4
+ "handler" in value &&
5
+ "options" in value;
6
+ }
7
+ function serialize_body(contentType, body) {
8
+ if (body === undefined)
9
+ return undefined;
10
+ if (contentType === "application/json") {
11
+ return JSON.stringify(body);
12
+ }
13
+ if (contentType === "application/x-www-form-urlencoded") {
14
+ return body instanceof URLSearchParams
15
+ ? body
16
+ : new URLSearchParams(body);
17
+ }
18
+ return body;
19
+ }
20
+ function headers(contentType) {
21
+ if (contentType === undefined)
22
+ return {};
23
+ if (contentType === "multipart/form-data")
24
+ return {};
25
+ return { "Content-Type": contentType };
26
+ }
1
27
  function route(handlers) {
2
- return {};
28
+ return {
29
+ _handlers: Object.fromEntries(Object.entries(handlers).map(([method, value]) => {
30
+ const options = is_with(value) ? value.options : {};
31
+ return [method, { contentType: options.contentType }];
32
+ })),
33
+ connect(path) {
34
+ return Object.fromEntries(Object.entries(this._handlers).map(([method, { contentType }]) => {
35
+ const fn = async (args = {}) => {
36
+ return fetch(path, {
37
+ method: method.toUpperCase(),
38
+ headers: headers(contentType),
39
+ body: serialize_body(contentType, args.body),
40
+ });
41
+ };
42
+ return [method, Object.assign(fn, { contentType })];
43
+ }));
44
+ },
45
+ };
3
46
  }
4
47
  route.with = function (options, handler) {
5
48
  return { handler, options };
@@ -0,0 +1,11 @@
1
+ declare function store(): {
2
+ create: () => Promise<undefined>;
3
+ drop: () => Promise<undefined>;
4
+ find: () => Promise<never[]>;
5
+ get: () => Promise<undefined>;
6
+ insert: () => Promise<undefined>;
7
+ update: () => Promise<number>;
8
+ delete: () => Promise<number>;
9
+ };
10
+ export default store;
11
+ //# sourceMappingURL=store.client.d.ts.map
@@ -0,0 +1,18 @@
1
+ function method() {
2
+ return async () => {
3
+ return undefined;
4
+ };
5
+ }
6
+ function store() {
7
+ return {
8
+ create: method(),
9
+ drop: method(),
10
+ find: async () => [],
11
+ get: method(),
12
+ insert: method(),
13
+ update: async () => 0,
14
+ delete: async () => 0,
15
+ };
16
+ }
17
+ export default store;
18
+ //# sourceMappingURL=store.client.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@primate/core",
3
- "version": "0.7.3",
3
+ "version": "0.7.4",
4
4
  "description": "The universal web framework",
5
5
  "homepage": "https://primate.run",
6
6
  "bugs": "https://github.com/primate-run/primate/issues",
@@ -60,6 +60,16 @@
60
60
  "browser": "./lib/public/route.client.js",
61
61
  "default": "./lib/public/route.js"
62
62
  },
63
+ "./response": {
64
+ "@primate/source": "./src/public/response.ts",
65
+ "browser": "./lib/private/response.client.js",
66
+ "default": "./lib/public/response.js"
67
+ },
68
+ "./store": {
69
+ "@primate/source": "./src/public/store.ts",
70
+ "browser": "./lib/private/store.client.js",
71
+ "default": "./lib/public/store.js"
72
+ },
63
73
  "./*": {
64
74
  "@primate/source": "./src/public/*.ts",
65
75
  "default": "./lib/public/*.js"
@@ -1,3 +0,0 @@
1
- import type BuildApp from "#build/App";
2
- export default function build_preclient(app: BuildApp): Promise<void>;
3
- //# sourceMappingURL=index.d.ts.map
@@ -1,69 +0,0 @@
1
- import plugin_preclient_routes from "#build/preclient/plugin/routes";
2
- import plugin_assets from "#build/server/plugin/assets";
3
- import plugin_config from "#build/server/plugin/config";
4
- import plugin_frontend from "#build/server/plugin/frontend";
5
- import plugin_native_addons from "#build/server/plugin/native-addons";
6
- import plugin_node_imports from "#build/server/plugin/node-imports";
7
- import plugin_requires from "#build/server/plugin/requires";
8
- import plugin_roots from "#build/server/plugin/roots";
9
- import plugin_server_route from "#build/server/plugin/route";
10
- import plugin_stores from "#build/server/plugin/stores";
11
- import plugin_view from "#build/server/plugin/view";
12
- import plugin_views from "#build/server/plugin/views";
13
- import plugin_virtual_pages from "#build/server/plugin/virtual-pages";
14
- import plugin_wasm from "#build/server/plugin/wasm";
15
- import plugin_app_request from "#build/shared/plugin/app-request";
16
- import * as esbuild from "esbuild";
17
- export default async function build_preclient(app) {
18
- const tsconfig_json = app.root.join("tsconfig.json");
19
- const preclient = app.path.build.join("preclient.js");
20
- const plugins = [
21
- plugin_preclient_routes(app),
22
- plugin_node_imports(app),
23
- plugin_frontend(app),
24
- plugin_view(app),
25
- plugin_virtual_pages(app),
26
- plugin_server_route(app),
27
- plugin_roots(app),
28
- plugin_views(app),
29
- plugin_assets(app),
30
- plugin_stores(app),
31
- plugin_native_addons(app),
32
- plugin_requires(app),
33
- plugin_config(app),
34
- plugin_wasm(app),
35
- plugin_app_request(app),
36
- ...app.plugins("server"),
37
- ];
38
- await esbuild.build({
39
- entryPoints: ["app:preclient-routes"],
40
- bundle: true,
41
- write: true,
42
- outfile: preclient.path,
43
- format: "esm",
44
- platform: "node",
45
- packages: "external",
46
- resolveExtensions: app.extensions,
47
- absWorkingDir: app.root.path,
48
- ...await tsconfig_json.exists() ? { tsconfig: tsconfig_json.path } : {},
49
- conditions: ["node", "module", "import", "default"],
50
- plugins,
51
- });
52
- const bundle = await preclient.import("default");
53
- const manifest = {};
54
- for (const [path, methods] of Object.entries(bundle)) {
55
- manifest[path] = Object.fromEntries(Object.entries(methods).map(([method, { options }]) => [
56
- method, {
57
- ...(options?.contentType !== undefined && {
58
- contentType: options.contentType,
59
- }),
60
- ...(options?.body !== undefined && {
61
- body: options.body.toJSON(),
62
- }),
63
- },
64
- ]));
65
- }
66
- await preclient.remove();
67
- await app.path.build.join("route.manifest.json").writeJSON(manifest);
68
- }
69
- //# sourceMappingURL=index.js.map
@@ -1,4 +0,0 @@
1
- import type BuildApp from "#build/App";
2
- import type { Plugin } from "esbuild";
3
- export default function plugin_preclient_routes(app: BuildApp): Plugin;
4
- //# sourceMappingURL=routes.d.ts.map
@@ -1,44 +0,0 @@
1
- function is_hook_file(p) {
2
- const basename = p.split("/").at(-1) ?? p;
3
- return basename === "+hook" || basename.startsWith("+hook.");
4
- }
5
- export default function plugin_preclient_routes(app) {
6
- const extension_pattern = new RegExp(`(${app.extensions.map(e => e.replace(".", "\\.")).join("|")})$`);
7
- function is_route_file(f) {
8
- return !f.name.endsWith("~") &&
9
- !f.name.startsWith(".") &&
10
- !f.name.startsWith("-") &&
11
- extension_pattern.test(f.path);
12
- }
13
- return {
14
- name: "primate/preclient/routes",
15
- setup(build) {
16
- build.onResolve({ filter: /^app:preclient-routes$/ }, () => {
17
- return { path: "preclient-routes", namespace: "primate-preclient-routes" };
18
- });
19
- build.onLoad({ filter: /.*/, namespace: "primate-preclient-routes" }, async () => {
20
- const route_files = await app.path.routes.files({
21
- filter: is_route_file,
22
- recursive: true,
23
- });
24
- const filtered = route_files
25
- .filter(file => !is_hook_file(app.basename(file, app.path.routes)));
26
- const contents = `
27
- ${filtered.map((file, i) => {
28
- const path = app.basename(file, app.path.routes);
29
- return `import route${i} from "app:route/${path}";`;
30
- }).join("\n")}
31
-
32
- export default {
33
- ${filtered.map((file, i) => {
34
- const path = app.basename(file, app.path.routes);
35
- return `"${path}": route${i},`;
36
- }).join("\n")}
37
- };
38
- `;
39
- return { contents, loader: "js", resolveDir: app.root.path };
40
- });
41
- },
42
- };
43
- }
44
- //# sourceMappingURL=routes.js.map