@evjs/build-tools 0.0.1-rc.13

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/AGENT.md ADDED
@@ -0,0 +1,110 @@
1
+ # @evjs/build-tools — Agent Guide
2
+
3
+ > AI-agent reference for the `@evjs/build-tools` package. This is an internal package — application developers don't use it directly.
4
+
5
+ ## Overview
6
+
7
+ Bundler-agnostic build utilities for the evjs server function pipeline. Consumed by `@evjs/webpack-plugin` and other bundler adapters.
8
+
9
+ ## API
10
+
11
+ ### `transformServerFile(source, options): string`
12
+
13
+ Transforms a `"use server"` file for either client or server target.
14
+
15
+ **Client transform:**
16
+ ```
17
+ Input: "use server"; export async function getUsers() { return db.find(); }
18
+ Output: import { __fn_call } from "@evjs/runtime";
19
+ export const getUsers = __fn_call("hash:getUsers", "hash");
20
+ ```
21
+
22
+ **Server transform:**
23
+ ```
24
+ Input: "use server"; export async function getUsers() { return db.find(); }
25
+ Output: import { registerServerFn } from "@evjs/runtime/server/register";
26
+ export async function getUsers() { return db.find(); }
27
+ registerServerFn("hash:getUsers", getUsers);
28
+ ```
29
+
30
+ ### `generateServerEntry(config, modules): string`
31
+
32
+ Generates server entry source code that imports all discovered server modules and bootstraps the Hono app.
33
+
34
+ ```ts
35
+ generateServerEntry(
36
+ {
37
+ appFactory: "@evjs/runtime/server#createApp",
38
+ runner: "@evjs/runtime/server#serve",
39
+ middleware: ["./middleware/auth#default"],
40
+ },
41
+ ["./api/users.server", "./api/posts.server"]
42
+ );
43
+ ```
44
+
45
+ ### `detectUseServer(source): boolean`
46
+
47
+ Returns `true` if source starts with `"use server";` directive.
48
+
49
+ ### `makeFnId(rootContext, resourcePath, exportName): string`
50
+
51
+ Derives a stable SHA-256 function ID from the project root, file path, and export name.
52
+
53
+ ### `parseModuleRef(ref): { module, export }`
54
+
55
+ Parses `"module#exportName"` strings into module and export components.
56
+
57
+ ## Types
58
+
59
+ ```ts
60
+ interface TransformOptions {
61
+ resourcePath: string; // absolute path to source file
62
+ rootContext: string; // project root directory
63
+ isServer: boolean; // true = server build, false = client
64
+ onServerFn?: (fnId: string, meta: { moduleId: string; export: string }) => void;
65
+ }
66
+
67
+ interface ServerEntryConfig {
68
+ appFactory?: string; // default: "@evjs/runtime/server#createApp"
69
+ runner?: string; // e.g. "@evjs/runtime/server#serve"
70
+ middleware?: string[]; // middleware module refs
71
+ }
72
+ ```
73
+
74
+ ## Constants (`RUNTIME`)
75
+
76
+ Identifiers used in generated code — bundler adapters should use these:
77
+
78
+ ```ts
79
+ RUNTIME.serverModule // "@evjs/runtime/server/register"
80
+ RUNTIME.appModule // "@evjs/runtime/server"
81
+ RUNTIME.clientTransportModule // "@evjs/runtime/client/transport"
82
+ RUNTIME.registerServerFn // "registerServerFn"
83
+ RUNTIME.clientCall // "__fn_call"
84
+ RUNTIME.clientRegister // "__fn_register"
85
+ ```
86
+
87
+ ## Key Files
88
+
89
+ | File | Purpose |
90
+ |------|---------|
91
+ | `src/transforms/index.ts` | `transformServerFile` — main transform |
92
+ | `src/transforms/client/` | Client-side SWC transform (stub generation) |
93
+ | `src/transforms/server/` | Server-side SWC transform (registration) |
94
+ | `src/transforms/utils.ts` | AST utilities |
95
+ | `src/entry.ts` | `generateServerEntry` |
96
+ | `src/codegen.ts` | `detectUseServer` |
97
+ | `src/utils.ts` | `makeFnId`, `parseModuleRef` |
98
+ | `src/types.ts` | Type definitions |
99
+
100
+ ## Writing a New Bundler Adapter
101
+
102
+ To integrate with a new bundler (e.g., Vite, Rollup):
103
+
104
+ 1. Use `detectUseServer(source)` to identify server function files
105
+ 2. Call `transformServerFile(source, { isServer, ... })` in your loader/plugin
106
+ 3. Collect server functions via `onServerFn` callback
107
+ 4. Call `generateServerEntry(config, collectedModules)` to create the server entry
108
+ 5. Emit the server entry as a virtual module
109
+
110
+ See `@evjs/webpack-plugin` for reference implementation.
package/README.md ADDED
@@ -0,0 +1,88 @@
1
+ # @evjs/build-tools
2
+
3
+ Bundler-agnostic build utilities for the **ev** framework. Contains all core logic for server function handling, decoupled from any specific bundler.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @evjs/build-tools
9
+ ```
10
+
11
+ ## Exports
12
+
13
+ | Export | Description |
14
+ |--------|-------------|
15
+ | `generateServerEntry(config, modules)` | Generate server entry source from discovered modules |
16
+ | `transformServerFile(source, options)` | SWC-based transform for `"use server"` files |
17
+ | `detectUseServer(source)` | Check if a file starts with the `"use server"` directive |
18
+ | `makeFnId(root, path, name)` | Derive a stable SHA-256 function ID |
19
+ | `parseModuleRef(ref)` | Parse `"module#export"` reference strings |
20
+ | `ServerEntryConfig` | Config type for server entry generation |
21
+ | `TransformOptions` | Options type for file transformation |
22
+
23
+ ## Usage
24
+
25
+ This package is consumed by bundler adapters (e.g., `@evjs/webpack-plugin`), not directly by application code.
26
+
27
+ ```ts
28
+ import {
29
+ generateServerEntry,
30
+ transformServerFile,
31
+ detectUseServer,
32
+ } from "@evjs/build-tools";
33
+
34
+ // Generate server entry source
35
+ const entrySource = generateServerEntry(
36
+ { appFactory: "@evjs/runtime/server#createApp" },
37
+ ["/path/to/api/users.server.ts"],
38
+ );
39
+
40
+ // Transform a "use server" file for client build
41
+ const clientStub = await transformServerFile(source, {
42
+ resourcePath: "/path/to/api/users.server.ts",
43
+ rootContext: "/path/to/project",
44
+ isServer: false,
45
+ });
46
+ ```
47
+
48
+ ## Architecture
49
+
50
+ ### Transform Pipeline
51
+
52
+ `transformServerFile()` parses the source with SWC, extracts exported function names via AST traversal, then delegates to the appropriate transform:
53
+
54
+ - **Client transform** — replaces function bodies with `__fn_call(fnId, args)` transport stubs and registers them via `__fn_register()` for query cache keys.
55
+ - **Server transform** — keeps original source, prepends the `registerServerFn` import, and appends registration calls for each export.
56
+
57
+ ### Entry Generation
58
+
59
+ `generateServerEntry()` produces a self-contained server entry that imports all discovered `"use server"` modules, creates a Hono app via `createApp()`, and optionally invokes a runner (e.g., `serve`) for self-starting bundles.
60
+
61
+ ### Code Emitter
62
+
63
+ All generated code passes through `emitCode()` — a SWC `parseSync → printSync` roundtrip that validates syntax at build time and produces consistently formatted output.
64
+
65
+ ### RUNTIME Constants
66
+
67
+ All runtime identifiers (module paths, function names, property names) are centralized in a single `RUNTIME` constant — no hardcoded strings in templates:
68
+
69
+ ```ts
70
+ RUNTIME.serverModule // "@evjs/runtime/server/register"
71
+ RUNTIME.appModule // "@evjs/runtime/server"
72
+ RUNTIME.clientTransportModule // "@evjs/runtime/client/transport"
73
+ RUNTIME.registerServerFn // "registerServerFn"
74
+ RUNTIME.clientCall // "__fn_call"
75
+ RUNTIME.clientRegister // "__fn_register"
76
+ ```
77
+
78
+ ## Bundler Adapter Pattern
79
+
80
+ ```
81
+ @evjs/build-tools (pure functions) Bundler Adapters
82
+ ──────────────────────────────── ─────────────────
83
+ • generateServerEntry() @evjs/webpack-plugin
84
+ • transformServerFile() → EvWebpackPlugin
85
+ • detectUseServer() → server-fn-loader
86
+ • makeFnId()
87
+ • parseModuleRef() (future: @evjs/vite-plugin)
88
+ ```
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Parse source code and re-emit via SWC for consistent formatting.
3
+ * Validates the code is syntactically correct at build time.
4
+ */
5
+ export declare function emitCode(source: string): string;
6
+ //# sourceMappingURL=codegen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../src/codegen.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAG/C"}
package/esm/codegen.js ADDED
@@ -0,0 +1,10 @@
1
+ import { parseSync, printSync } from "@swc/core";
2
+ /**
3
+ * Parse source code and re-emit via SWC for consistent formatting.
4
+ * Validates the code is syntactically correct at build time.
5
+ */
6
+ export function emitCode(source) {
7
+ const ast = parseSync(source, { syntax: "ecmascript" });
8
+ return printSync(ast, { jsc: { target: "esnext" } }).code;
9
+ }
10
+ //# sourceMappingURL=codegen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codegen.js","sourceRoot":"","sources":["../src/codegen.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEjD;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,MAAc;IACrC,MAAM,GAAG,GAAG,SAAS,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC;IACxD,OAAO,SAAS,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC;AAC5D,CAAC"}
package/esm/entry.d.ts ADDED
@@ -0,0 +1,18 @@
1
+ import { type ServerEntryConfig } from "./types.js";
2
+ /**
3
+ * Generate the server entry source code from discovered server modules.
4
+ *
5
+ * The generated entry:
6
+ * 1. Imports user's "use server" modules (registering functions as side effects)
7
+ * 2. Re-exports them as named exports (_fns_0, _fns_1, ...)
8
+ * 3. Re-exports `createApp` so the adapter can create a Hono app that
9
+ * shares the same function registry
10
+ *
11
+ * The adapter layer (node/ecma) handles server startup.
12
+ *
13
+ * @param config - Server entry configuration (setup imports)
14
+ * @param serverModulePaths - Absolute paths to discovered "use server" modules
15
+ * @returns The generated server entry source code string
16
+ */
17
+ export declare function generateServerEntry(config: ServerEntryConfig | undefined, serverModulePaths: string[]): string;
18
+ //# sourceMappingURL=entry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry.d.ts","sourceRoot":"","sources":["../src/entry.ts"],"names":[],"mappings":"AACA,OAAO,EAAW,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE7D;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,iBAAiB,GAAG,SAAS,EACrC,iBAAiB,EAAE,MAAM,EAAE,GAC1B,MAAM,CAkBR"}
package/esm/entry.js ADDED
@@ -0,0 +1,33 @@
1
+ import { emitCode } from "./codegen.js";
2
+ import { RUNTIME } from "./types.js";
3
+ /**
4
+ * Generate the server entry source code from discovered server modules.
5
+ *
6
+ * The generated entry:
7
+ * 1. Imports user's "use server" modules (registering functions as side effects)
8
+ * 2. Re-exports them as named exports (_fns_0, _fns_1, ...)
9
+ * 3. Re-exports `createApp` so the adapter can create a Hono app that
10
+ * shares the same function registry
11
+ *
12
+ * The adapter layer (node/ecma) handles server startup.
13
+ *
14
+ * @param config - Server entry configuration (setup imports)
15
+ * @param serverModulePaths - Absolute paths to discovered "use server" modules
16
+ * @returns The generated server entry source code string
17
+ */
18
+ export function generateServerEntry(config, serverModulePaths) {
19
+ const moduleImports = serverModulePaths
20
+ .map((p, i) => `import * as _fns_${i} from ${JSON.stringify(p)};`)
21
+ .join("\n");
22
+ const fnsExports = serverModulePaths.map((_p, i) => `_fns_${i}`);
23
+ const allExports = [...fnsExports];
24
+ return emitCode([
25
+ `export { createApp } from "${RUNTIME.appModule}";`,
26
+ ...(config?.middleware ?? []),
27
+ moduleImports,
28
+ allExports.length ? `export { ${allExports.join(", ")} };` : "",
29
+ ]
30
+ .filter(Boolean)
31
+ .join("\n"));
32
+ }
33
+ //# sourceMappingURL=entry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry.js","sourceRoot":"","sources":["../src/entry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,OAAO,EAA0B,MAAM,YAAY,CAAC;AAE7D;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAAqC,EACrC,iBAA2B;IAE3B,MAAM,aAAa,GAAG,iBAAiB;SACpC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,oBAAoB,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC;SACjE,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,MAAM,UAAU,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACjE,MAAM,UAAU,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC;IAEnC,OAAO,QAAQ,CACb;QACE,8BAA8B,OAAO,CAAC,SAAS,IAAI;QACnD,GAAG,CAAC,MAAM,EAAE,UAAU,IAAI,EAAE,CAAC;QAC7B,aAAa;QACb,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;KAChE;SACE,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,IAAI,CAAC,CACd,CAAC;AACJ,CAAC"}
package/esm/index.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Bundler-agnostic build utilities for the ev framework.
3
+ */
4
+ export { generateServerEntry } from "./entry.js";
5
+ export { transformServerFile } from "./transforms/index.js";
6
+ export type { ServerEntryConfig, TransformOptions } from "./types.js";
7
+ export { detectUseServer, hashString, makeFnId, makeModuleId, parseModuleRef, } from "./utils.js";
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACtE,OAAO,EACL,eAAe,EACf,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,cAAc,GACf,MAAM,YAAY,CAAC"}
package/esm/index.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Bundler-agnostic build utilities for the ev framework.
3
+ */
4
+ export { generateServerEntry } from "./entry.js";
5
+ export { transformServerFile } from "./transforms/index.js";
6
+ export { detectUseServer, hashString, makeFnId, makeModuleId, parseModuleRef, } from "./utils.js";
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,OAAO,EACL,eAAe,EACf,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,cAAc,GACf,MAAM,YAAY,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { type TransformOptions } from "../../types.js";
2
+ /** Client build: replace function bodies with __fn_call transport stubs. */
3
+ export declare function buildClientOutput(exportNames: string[], options: TransformOptions): string;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/transforms/client/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAW,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAGhE,4EAA4E;AAC5E,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,EAAE,EACrB,OAAO,EAAE,gBAAgB,GACxB,MAAM,CAiBR"}
@@ -0,0 +1,18 @@
1
+ import { emitCode } from "../../codegen.js";
2
+ import { RUNTIME } from "../../types.js";
3
+ import { makeFnId } from "../../utils.js";
4
+ /** Client build: replace function bodies with __fn_call transport stubs. */
5
+ export function buildClientOutput(exportNames, options) {
6
+ const stubs = exportNames.map((name) => {
7
+ const fnId = JSON.stringify(makeFnId(options.rootContext, options.resourcePath, name));
8
+ return [
9
+ `export function ${name}(...args) { return ${RUNTIME.clientCall}(${fnId}, args); }`,
10
+ `${RUNTIME.clientRegister}(${name}, ${fnId}, ${JSON.stringify(name)});`,
11
+ ].join("\n");
12
+ });
13
+ return emitCode([
14
+ `import { ${RUNTIME.clientCall}, ${RUNTIME.clientRegister} } from "${RUNTIME.clientTransportModule}";`,
15
+ ...stubs,
16
+ ].join("\n"));
17
+ }
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/transforms/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAyB,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,4EAA4E;AAC5E,MAAM,UAAU,iBAAiB,CAC/B,WAAqB,EACrB,OAAyB;IAEzB,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACrC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CACzB,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,YAAY,EAAE,IAAI,CAAC,CAC1D,CAAC;QACF,OAAO;YACL,mBAAmB,IAAI,sBAAsB,OAAO,CAAC,UAAU,IAAI,IAAI,YAAY;YACnF,GAAG,OAAO,CAAC,cAAc,IAAI,IAAI,KAAK,IAAI,KAAK,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI;SACxE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACf,CAAC,CAAC,CAAC;IAEH,OAAO,QAAQ,CACb;QACE,YAAY,OAAO,CAAC,UAAU,KAAK,OAAO,CAAC,cAAc,YAAY,OAAO,CAAC,qBAAqB,IAAI;QACtG,GAAG,KAAK;KACT,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;AACJ,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { TransformOptions } from "../types.js";
2
+ /**
3
+ * Transform a "use server" file for either client or server builds.
4
+ * This is a pure function with no bundler dependency.
5
+ *
6
+ * - **Server**: keeps original source + appends `registerServerFn()` calls
7
+ * - **Client**: replaces function bodies with `__fn_call()` transport stubs
8
+ */
9
+ export declare function transformServerFile(source: string, options: TransformOptions): Promise<string>;
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transforms/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAMpD;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,MAAM,CAAC,CAoBjB"}
@@ -0,0 +1,31 @@
1
+ import { parse } from "@swc/core";
2
+ import { detectUseServer } from "../utils.js";
3
+ import { buildClientOutput } from "./client/index.js";
4
+ import { buildServerOutput } from "./server/index.js";
5
+ import { extractExportNames } from "./utils.js";
6
+ /**
7
+ * Transform a "use server" file for either client or server builds.
8
+ * This is a pure function with no bundler dependency.
9
+ *
10
+ * - **Server**: keeps original source + appends `registerServerFn()` calls
11
+ * - **Client**: replaces function bodies with `__fn_call()` transport stubs
12
+ */
13
+ export async function transformServerFile(source, options) {
14
+ if (!detectUseServer(source)) {
15
+ return source;
16
+ }
17
+ const program = await parse(source, {
18
+ syntax: "typescript",
19
+ tsx: true,
20
+ comments: false,
21
+ script: false,
22
+ });
23
+ const exportNames = extractExportNames(program.body);
24
+ if (exportNames.length === 0) {
25
+ return source;
26
+ }
27
+ return options.isServer
28
+ ? buildServerOutput(source, exportNames, options)
29
+ : buildClientOutput(exportNames, options);
30
+ }
31
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/transforms/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEhD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,MAAc,EACd,OAAyB;IAEzB,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7B,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,MAAM,EAAE;QAClC,MAAM,EAAE,YAAY;QACpB,GAAG,EAAE,IAAI;QACT,QAAQ,EAAE,KAAK;QACf,MAAM,EAAE,KAAK;KACd,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,OAAO,OAAO,CAAC,QAAQ;QACrB,CAAC,CAAC,iBAAiB,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,CAAC;QACjD,CAAC,CAAC,iBAAiB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { type TransformOptions } from "../../types.js";
2
+ /** Server build: keep original source, prepend import, append registrations. */
3
+ export declare function buildServerOutput(source: string, exportNames: string[], options: TransformOptions): string;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/transforms/server/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAW,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAgBhE,gFAAgF;AAChF,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EAAE,EACrB,OAAO,EAAE,gBAAgB,GACxB,MAAM,CAeR"}
@@ -0,0 +1,27 @@
1
+ import { emitCode } from "../../codegen.js";
2
+ import { RUNTIME } from "../../types.js";
3
+ import { makeFnId, makeModuleId } from "../../utils.js";
4
+ /** Notify the manifest collector about each server function. */
5
+ function reportToManifest(exportNames, options) {
6
+ if (!options.onServerFn)
7
+ return;
8
+ const moduleId = makeModuleId(options.rootContext, options.resourcePath);
9
+ for (const name of exportNames) {
10
+ const fnId = makeFnId(options.rootContext, options.resourcePath, name);
11
+ options.onServerFn(fnId, { moduleId, export: name });
12
+ }
13
+ }
14
+ /** Server build: keep original source, prepend import, append registrations. */
15
+ export function buildServerOutput(source, exportNames, options) {
16
+ reportToManifest(exportNames, options);
17
+ const registrations = exportNames.map((name) => {
18
+ const fnId = JSON.stringify(makeFnId(options.rootContext, options.resourcePath, name));
19
+ return `${RUNTIME.registerServerFn}(${fnId}, ${name});`;
20
+ });
21
+ return [
22
+ `import { ${RUNTIME.registerServerFn} } from "${RUNTIME.serverModule}";`,
23
+ source,
24
+ emitCode(registrations.join("\n")),
25
+ ].join("\n");
26
+ }
27
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/transforms/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAyB,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAExD,gEAAgE;AAChE,SAAS,gBAAgB,CACvB,WAAqB,EACrB,OAAyB;IAEzB,IAAI,CAAC,OAAO,CAAC,UAAU;QAAE,OAAO;IAChC,MAAM,QAAQ,GAAG,YAAY,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IACzE,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;QACvE,OAAO,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACvD,CAAC;AACH,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,iBAAiB,CAC/B,MAAc,EACd,WAAqB,EACrB,OAAyB;IAEzB,gBAAgB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAEvC,MAAM,aAAa,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CACzB,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,YAAY,EAAE,IAAI,CAAC,CAC1D,CAAC;QACF,OAAO,GAAG,OAAO,CAAC,gBAAgB,IAAI,IAAI,KAAK,IAAI,IAAI,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,YAAY,OAAO,CAAC,gBAAgB,YAAY,OAAO,CAAC,YAAY,IAAI;QACxE,MAAM;QACN,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;KACnC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { ModuleItem } from "@swc/types";
2
+ /** Extract exported function/variable names from a parsed SWC module. */
3
+ export declare function extractExportNames(body: ModuleItem[]): string[];
4
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/transforms/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,yEAAyE;AACzE,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,MAAM,EAAE,CA4B/D"}
@@ -0,0 +1,32 @@
1
+ /** Extract exported function/variable names from a parsed SWC module. */
2
+ export function extractExportNames(body) {
3
+ const names = [];
4
+ for (const item of body) {
5
+ if (item.type === "ExportDeclaration") {
6
+ const decl = item.declaration;
7
+ if (decl.type === "FunctionDeclaration") {
8
+ if (decl.identifier.value)
9
+ names.push(decl.identifier.value);
10
+ }
11
+ else if (decl.type === "VariableDeclaration") {
12
+ for (const v of decl.declarations) {
13
+ if (v.id.type === "Identifier") {
14
+ names.push(v.id.value);
15
+ }
16
+ }
17
+ }
18
+ }
19
+ else if (item.type === "ExportNamedDeclaration") {
20
+ for (const specifier of item.specifiers) {
21
+ if (specifier.type === "ExportSpecifier") {
22
+ const exported = specifier.exported ?? specifier.orig;
23
+ if (exported.type === "Identifier") {
24
+ names.push(exported.value);
25
+ }
26
+ }
27
+ }
28
+ }
29
+ }
30
+ return names;
31
+ }
32
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/transforms/utils.ts"],"names":[],"mappings":"AAEA,yEAAyE;AACzE,MAAM,UAAU,kBAAkB,CAAC,IAAkB;IACnD,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;QACxB,IAAI,IAAI,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;YACtC,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC;YAC9B,IAAI,IAAI,CAAC,IAAI,KAAK,qBAAqB,EAAE,CAAC;gBACxC,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK;oBAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;YAC/D,CAAC;iBAAM,IAAI,IAAI,CAAC,IAAI,KAAK,qBAAqB,EAAE,CAAC;gBAC/C,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;oBAClC,IAAI,CAAC,CAAC,EAAE,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;wBAC/B,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;oBACzB,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;aAAM,IAAI,IAAI,CAAC,IAAI,KAAK,wBAAwB,EAAE,CAAC;YAClD,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;gBACxC,IAAI,SAAS,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;oBACzC,MAAM,QAAQ,GAAG,SAAS,CAAC,QAAQ,IAAI,SAAS,CAAC,IAAI,CAAC;oBACtD,IAAI,QAAQ,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;wBACnC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;oBAC7B,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
package/esm/types.d.ts ADDED
@@ -0,0 +1,46 @@
1
+ /** Configuration for the generated server entry. */
2
+ export interface ServerEntryConfig {
3
+ /**
4
+ * Middleware module paths to auto-register in the server entry.
5
+ */
6
+ middleware?: string[];
7
+ }
8
+ /** Options for transforming a "use server" file. */
9
+ export interface TransformOptions {
10
+ /** Absolute path to the source file. */
11
+ resourcePath: string;
12
+ /** Root directory of the project. */
13
+ rootContext: string;
14
+ /** Whether this is a server-side build. */
15
+ isServer: boolean;
16
+ /** Callback to register a server function in the manifest. */
17
+ onServerFn?: (fnId: string, meta: {
18
+ moduleId: string;
19
+ export: string;
20
+ }) => void;
21
+ }
22
+ /**
23
+ * Runtime identifiers used in generated code.
24
+ *
25
+ * These are build-time constants — the actual module paths and function names
26
+ * that appear in codegen output. They must stay in sync with the `@evjs/runtime`
27
+ * package exports.
28
+ *
29
+ * Note: `DEFAULT_ENDPOINT` (the default HTTP path for server functions) is a runtime
30
+ * concern and lives in `@evjs/runtime/src/constants.ts`, not here.
31
+ */
32
+ export declare const RUNTIME: {
33
+ /** Module path for server-side function registration (no Hono dependency). */
34
+ readonly serverModule: "@evjs/runtime/server/register";
35
+ /** Module path for the server app factory (Hono app + server function handler). */
36
+ readonly appModule: "@evjs/runtime/server";
37
+ /** Module path for client-side transport stubs. */
38
+ readonly clientTransportModule: "@evjs/runtime/client/transport";
39
+ /** Server function registration call name. */
40
+ readonly registerServerFn: "registerServerFn";
41
+ /** Client-side server function call name. */
42
+ readonly clientCall: "__fn_call";
43
+ /** Client-side function registration call name. */
44
+ readonly clientRegister: "__fn_register";
45
+ };
46
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,oDAAoD;AACpD,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,oDAAoD;AACpD,MAAM,WAAW,gBAAgB;IAC/B,wCAAwC;IACxC,YAAY,EAAE,MAAM,CAAC;IACrB,qCAAqC;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,2CAA2C;IAC3C,QAAQ,EAAE,OAAO,CAAC;IAClB,8DAA8D;IAC9D,UAAU,CAAC,EAAE,CACX,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KACvC,IAAI,CAAC;CACX;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,OAAO;IAClB,8EAA8E;;IAE9E,mFAAmF;;IAEnF,mDAAmD;;IAEnD,8CAA8C;;IAE9C,6CAA6C;;IAE7C,mDAAmD;;CAE3C,CAAC"}
package/esm/types.js ADDED
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Runtime identifiers used in generated code.
3
+ *
4
+ * These are build-time constants — the actual module paths and function names
5
+ * that appear in codegen output. They must stay in sync with the `@evjs/runtime`
6
+ * package exports.
7
+ *
8
+ * Note: `DEFAULT_ENDPOINT` (the default HTTP path for server functions) is a runtime
9
+ * concern and lives in `@evjs/runtime/src/constants.ts`, not here.
10
+ */
11
+ export const RUNTIME = {
12
+ /** Module path for server-side function registration (no Hono dependency). */
13
+ serverModule: "@evjs/runtime/server/register",
14
+ /** Module path for the server app factory (Hono app + server function handler). */
15
+ appModule: "@evjs/runtime/server",
16
+ /** Module path for client-side transport stubs. */
17
+ clientTransportModule: "@evjs/runtime/client/transport",
18
+ /** Server function registration call name. */
19
+ registerServerFn: "registerServerFn",
20
+ /** Client-side server function call name. */
21
+ clientCall: "__fn_call",
22
+ /** Client-side function registration call name. */
23
+ clientRegister: "__fn_register",
24
+ };
25
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAuBA;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB,8EAA8E;IAC9E,YAAY,EAAE,+BAA+B;IAC7C,mFAAmF;IACnF,SAAS,EAAE,sBAAsB;IACjC,mDAAmD;IACnD,qBAAqB,EAAE,gCAAgC;IACvD,8CAA8C;IAC9C,gBAAgB,EAAE,kBAAkB;IACpC,6CAA6C;IAC7C,UAAU,EAAE,WAAW;IACvB,mDAAmD;IACnD,cAAc,EAAE,eAAe;CACvB,CAAC"}
package/esm/utils.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ /** Parse a "module#export" reference string. */
2
+ export declare function parseModuleRef(ref: string): {
3
+ module: string;
4
+ exportName: string;
5
+ };
6
+ /** Hash a string to a 16-character hex digest (SHA-256, truncated). */
7
+ export declare function hashString(input: string): string;
8
+ /** Derive a stable module ID from a file path relative to root. */
9
+ export declare function makeModuleId(rootContext: string, resourcePath: string): string;
10
+ /** Derive a stable function ID from the file path and export name. */
11
+ export declare function makeFnId(rootContext: string, resourcePath: string, exportName: string): string;
12
+ /** Check whether the source starts with the "use server" directive. */
13
+ export declare function detectUseServer(source: string): boolean;
14
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAGA,gDAAgD;AAChD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB,CAQA;AAED,uEAAuE;AACvE,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,mEAAmE;AACnE,wBAAgB,YAAY,CAC1B,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB,MAAM,CAER;AAED,sEAAsE;AACtE,wBAAgB,QAAQ,CACtB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,GACjB,MAAM,CAGR;AAED,uEAAuE;AACvE,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAGvD"}
package/esm/utils.js ADDED
@@ -0,0 +1,29 @@
1
+ import { createHash } from "node:crypto";
2
+ import path from "node:path";
3
+ /** Parse a "module#export" reference string. */
4
+ export function parseModuleRef(ref) {
5
+ const idx = ref.indexOf("#");
6
+ if (idx === -1) {
7
+ throw new Error(`Invalid module reference "${ref}". Expected format: "module#exportName".`);
8
+ }
9
+ return { module: ref.slice(0, idx), exportName: ref.slice(idx + 1) };
10
+ }
11
+ /** Hash a string to a 16-character hex digest (SHA-256, truncated). */
12
+ export function hashString(input) {
13
+ return createHash("sha256").update(input).digest("hex").slice(0, 16);
14
+ }
15
+ /** Derive a stable module ID from a file path relative to root. */
16
+ export function makeModuleId(rootContext, resourcePath) {
17
+ return hashString(path.relative(rootContext, resourcePath));
18
+ }
19
+ /** Derive a stable function ID from the file path and export name. */
20
+ export function makeFnId(rootContext, resourcePath, exportName) {
21
+ const relativePath = path.relative(rootContext, resourcePath);
22
+ return hashString(`${relativePath}:${exportName}`);
23
+ }
24
+ /** Check whether the source starts with the "use server" directive. */
25
+ export function detectUseServer(source) {
26
+ const trimmed = source.replace(/^(\s|\/\/[^\n]*\n|\/\*[\s\S]*?\*\/)*/, "");
27
+ return /^["']use server["'];?\s/.test(trimmed);
28
+ }
29
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,gDAAgD;AAChD,MAAM,UAAU,cAAc,CAAC,GAAW;IAIxC,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,6BAA6B,GAAG,0CAA0C,CAC3E,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC;AACvE,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACvE,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,YAAY,CAC1B,WAAmB,EACnB,YAAoB;IAEpB,OAAO,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC,CAAC;AAC9D,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,QAAQ,CACtB,WAAmB,EACnB,YAAoB,EACpB,UAAkB;IAElB,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;IAC9D,OAAO,UAAU,CAAC,GAAG,YAAY,IAAI,UAAU,EAAE,CAAC,CAAC;AACrD,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,sCAAsC,EAAE,EAAE,CAAC,CAAC;IAC3E,OAAO,yBAAyB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACjD,CAAC"}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@evjs/build-tools",
3
+ "version": "0.0.1-rc.13",
4
+ "description": "Bundler-agnostic build utilities for the ev framework",
5
+ "type": "module",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "main": "./esm/index.js",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./esm/index.d.ts",
13
+ "import": "./esm/index.js"
14
+ }
15
+ },
16
+ "scripts": {
17
+ "build": "tsc",
18
+ "test": "vitest run",
19
+ "check-types": "tsc --noEmit"
20
+ },
21
+ "files": [
22
+ "esm",
23
+ "AGENT.md"
24
+ ],
25
+ "keywords": [
26
+ "evjs",
27
+ "build-tools",
28
+ "server-functions",
29
+ "code-transform",
30
+ "typescript"
31
+ ],
32
+ "author": "xusd320",
33
+ "license": "MIT",
34
+ "dependencies": {
35
+ "@swc/core": "^1.15.18"
36
+ },
37
+ "devDependencies": {
38
+ "@swc/types": "^0.1.25",
39
+ "typescript": "^5.7.3"
40
+ },
41
+ "homepage": "https://github.com/evaijs/evjs#readme",
42
+ "bugs": {
43
+ "url": "https://github.com/evaijs/evjs/issues"
44
+ },
45
+ "repository": {
46
+ "type": "git",
47
+ "url": "git+https://github.com/evaijs/evjs.git"
48
+ }
49
+ }