@vesk/compiler 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/README.md +23 -0
  2. package/dist/acorn-ts-plugin/index.d.ts +482 -0
  3. package/dist/acorn-ts-plugin/index.d.ts.map +1 -0
  4. package/dist/acorn-ts-plugin/index.js +5028 -0
  5. package/dist/actions.d.ts +22 -0
  6. package/dist/actions.d.ts.map +1 -0
  7. package/dist/actions.js +167 -0
  8. package/dist/api-routes.d.ts +30 -0
  9. package/dist/api-routes.d.ts.map +1 -0
  10. package/dist/api-routes.js +350 -0
  11. package/dist/client-codegen.d.ts +19 -0
  12. package/dist/client-codegen.d.ts.map +1 -0
  13. package/dist/client-codegen.js +1523 -0
  14. package/dist/config.d.ts +6 -0
  15. package/dist/config.d.ts.map +1 -0
  16. package/dist/config.js +106 -0
  17. package/dist/errors.d.ts +33 -0
  18. package/dist/errors.d.ts.map +1 -0
  19. package/dist/errors.js +210 -0
  20. package/dist/index.d.ts +16 -0
  21. package/dist/index.d.ts.map +1 -0
  22. package/dist/index.js +8 -0
  23. package/dist/ir-generator.d.ts +10 -0
  24. package/dist/ir-generator.d.ts.map +1 -0
  25. package/dist/ir-generator.js +1062 -0
  26. package/dist/ir.d.ts +160 -0
  27. package/dist/ir.d.ts.map +1 -0
  28. package/dist/ir.js +219 -0
  29. package/dist/middleware.d.ts +15 -0
  30. package/dist/middleware.d.ts.map +1 -0
  31. package/dist/middleware.js +183 -0
  32. package/dist/package.json +15 -0
  33. package/dist/parser.d.ts +38 -0
  34. package/dist/parser.d.ts.map +1 -0
  35. package/dist/parser.js +242 -0
  36. package/dist/router.d.ts +31 -0
  37. package/dist/router.d.ts.map +1 -0
  38. package/dist/router.js +451 -0
  39. package/dist/scan.d.ts +106 -0
  40. package/dist/scan.d.ts.map +1 -0
  41. package/dist/scan.js +438 -0
  42. package/dist/server-codegen.d.ts +5 -0
  43. package/dist/server-codegen.d.ts.map +1 -0
  44. package/dist/server-codegen.js +4 -0
  45. package/dist/server-cookies.d.ts +2 -0
  46. package/dist/server-cookies.d.ts.map +1 -0
  47. package/dist/server-cookies.js +15 -0
  48. package/dist/server-head.d.ts +10 -0
  49. package/dist/server-head.d.ts.map +1 -0
  50. package/dist/server-head.js +289 -0
  51. package/dist/server-jsgen.d.ts +6 -0
  52. package/dist/server-jsgen.d.ts.map +1 -0
  53. package/dist/server-jsgen.js +446 -0
  54. package/dist/server-render.d.ts +16 -0
  55. package/dist/server-render.d.ts.map +1 -0
  56. package/dist/server-render.js +397 -0
  57. package/dist/server-utils.d.ts +93 -0
  58. package/dist/server-utils.d.ts.map +1 -0
  59. package/dist/server-utils.js +747 -0
  60. package/dist/ssr-store.d.ts +4 -0
  61. package/dist/ssr-store.d.ts.map +1 -0
  62. package/dist/ssr-store.js +29 -0
  63. package/dist/strip-ts.d.ts +25 -0
  64. package/dist/strip-ts.d.ts.map +1 -0
  65. package/dist/strip-ts.js +171 -0
  66. package/dist/tokens.d.ts +50 -0
  67. package/dist/tokens.d.ts.map +1 -0
  68. package/dist/tokens.js +334 -0
  69. package/dist/typecheck.d.ts +19 -0
  70. package/dist/typecheck.d.ts.map +1 -0
  71. package/dist/typecheck.js +365 -0
  72. package/dist/types.d.ts +147 -0
  73. package/dist/types.d.ts.map +1 -0
  74. package/dist/types.js +13 -0
  75. package/dist/vesk-plugin.d.ts +53 -0
  76. package/dist/vesk-plugin.d.ts.map +1 -0
  77. package/dist/vesk-plugin.js +413 -0
  78. package/dist/vsk-imports.d.ts +30 -0
  79. package/dist/vsk-imports.d.ts.map +1 -0
  80. package/dist/vsk-imports.js +141 -0
  81. package/dist/vsk-tsx.d.ts +3 -0
  82. package/dist/vsk-tsx.d.ts.map +1 -0
  83. package/dist/vsk-tsx.js +604 -0
  84. package/package.json +52 -0
@@ -0,0 +1,22 @@
1
+ export interface ActionInfo {
2
+ id: string;
3
+ url: string;
4
+ }
5
+ export declare const ACTION_PREFIX = "/_vesk/action/";
6
+ export declare function hashString(str: string): string;
7
+ /**
8
+ * Transform a top-level statement's `defineAction(...)` calls.
9
+ *
10
+ * - `server`: inject a stable id as the first argument so the runtime
11
+ * registers `defineAction("<id>", {...})` into the shared registry.
12
+ * - `client`: replace the call with a stub object literal carrying the same
13
+ * id + endpoint URL. The `execute` handler (server-only code) is stripped
14
+ * from the client bundle entirely.
15
+ *
16
+ * Both modes derive the id from the raw call source, so the ids match.
17
+ */
18
+ export declare function rewriteTopLevelActions(code: string, mode: 'server' | 'client'): string;
19
+ export declare function transformTopLevelForActions(topLevelCode: string[], mode: 'server' | 'client'): string[];
20
+ /** Collect the stable action ids defined by a page source (for the manifest). */
21
+ export declare function collectActionIds(source: string): string[];
22
+ //# sourceMappingURL=actions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;CACb;AAED,eAAO,MAAM,aAAa,mBAAmB,CAAC;AAE9C,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAW9C;AA6BD;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAqCtF;AAeD,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,EAAE,CAOvG;AAED,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAsBzD"}
@@ -0,0 +1,167 @@
1
+ import { walk } from 'zimmerframe';
2
+ import { print } from 'esrap';
3
+ import ts from 'esrap/languages/ts';
4
+ import { parse } from '@vesk/compiler/src/parser';
5
+ import { stripTsTypes, hasTsSyntax, isTypeOnlyStatement, stripCodeTypes } from '@vesk/compiler/src/strip-ts';
6
+ export const ACTION_PREFIX = '/_vesk/action/';
7
+ export function hashString(str) {
8
+ let h1 = 0x811c9dc5;
9
+ let h2 = 0x01000193;
10
+ for (let i = 0; i < str.length; i++) {
11
+ const c = str.charCodeAt(i);
12
+ h1 ^= c;
13
+ h1 = Math.imul(h1, 0x01000193) >>> 0;
14
+ h2 ^= c;
15
+ h2 = Math.imul(h2, 0x01000193) >>> 0;
16
+ }
17
+ return (h1 ^ h2).toString(36).slice(0, 12);
18
+ }
19
+ function literal(value) {
20
+ return { type: 'Literal', value };
21
+ }
22
+ function memberExpr(object, property) {
23
+ return {
24
+ type: 'MemberExpression',
25
+ object,
26
+ property: { type: 'Identifier', name: property },
27
+ computed: false,
28
+ optional: false,
29
+ };
30
+ }
31
+ function isDefineActionCall(node) {
32
+ return (node.type === 'CallExpression' &&
33
+ node.callee &&
34
+ node.callee.type === 'Identifier' &&
35
+ node.callee.name === 'defineAction');
36
+ }
37
+ function actionUrl(id) {
38
+ return `${ACTION_PREFIX}${id}`;
39
+ }
40
+ /**
41
+ * Transform a top-level statement's `defineAction(...)` calls.
42
+ *
43
+ * - `server`: inject a stable id as the first argument so the runtime
44
+ * registers `defineAction("<id>", {...})` into the shared registry.
45
+ * - `client`: replace the call with a stub object literal carrying the same
46
+ * id + endpoint URL. The `execute` handler (server-only code) is stripped
47
+ * from the client bundle entirely.
48
+ *
49
+ * Both modes derive the id from the raw call source, so the ids match.
50
+ */
51
+ export function rewriteTopLevelActions(code, mode) {
52
+ if (!code.includes('defineAction'))
53
+ return stripCodeTypes(code);
54
+ let ast;
55
+ try {
56
+ ast = parse(code);
57
+ }
58
+ catch {
59
+ return code;
60
+ }
61
+ const hadTs = hasTsSyntax(ast);
62
+ ast = walk(ast, null, {
63
+ CallExpression(node, context) {
64
+ if (isDefineActionCall(node)) {
65
+ const id = hashString(code.slice(node.start ?? 0, node.end ?? code.length));
66
+ if (mode === 'client') {
67
+ return {
68
+ type: 'ObjectExpression',
69
+ properties: [
70
+ { type: 'Property', kind: 'init', method: false, shorthand: false, computed: false, key: { type: 'Identifier', name: '__veskAction' }, value: literal(true) },
71
+ { type: 'Property', kind: 'init', method: false, shorthand: false, computed: false, key: { type: 'Identifier', name: 'id' }, value: literal(id) },
72
+ { type: 'Property', kind: 'init', method: false, shorthand: false, computed: false, key: { type: 'Identifier', name: 'url' }, value: literal(actionUrl(id)) },
73
+ ],
74
+ };
75
+ }
76
+ return {
77
+ type: 'CallExpression',
78
+ callee: { type: 'Identifier', name: 'defineAction' },
79
+ arguments: [literal(id), ...(node.arguments || [])],
80
+ optional: false,
81
+ };
82
+ }
83
+ return context.next();
84
+ },
85
+ });
86
+ return printWithTypesStripped(ast, code, hadTs);
87
+ }
88
+ function printWithTypesStripped(ast, code, hadTs = hasTsSyntax(ast)) {
89
+ if (!hadTs)
90
+ return code;
91
+ const stripped = stripTsTypes(ast);
92
+ if (stripped.type === 'Program' && Array.isArray(stripped.body)) {
93
+ stripped.body = stripped.body.filter((n) => !isTypeOnlyStatement(n));
94
+ }
95
+ try {
96
+ return print(stripped, ts()).code;
97
+ }
98
+ catch {
99
+ return code;
100
+ }
101
+ }
102
+ export function transformTopLevelForActions(topLevelCode, mode) {
103
+ const out = [];
104
+ for (const c of topLevelCode) {
105
+ const rewritten = rewriteTopLevelActions(c, mode);
106
+ if (rewritten !== '')
107
+ out.push(rewritten);
108
+ }
109
+ return out;
110
+ }
111
+ /** Collect the stable action ids defined by a page source (for the manifest). */
112
+ export function collectActionIds(source) {
113
+ const ids = [];
114
+ const stmts = collectTopLevelStatements(source);
115
+ for (const code of stmts) {
116
+ if (!code.includes('defineAction'))
117
+ continue;
118
+ let ast;
119
+ try {
120
+ ast = parse(code);
121
+ }
122
+ catch {
123
+ continue;
124
+ }
125
+ walk(ast, null, {
126
+ CallExpression(node, context) {
127
+ if (isDefineActionCall(node)) {
128
+ ids.push(hashString(code.slice(node.start ?? 0, node.end ?? code.length)));
129
+ return;
130
+ }
131
+ return context.next();
132
+ },
133
+ });
134
+ }
135
+ return ids;
136
+ }
137
+ function collectTopLevelStatements(source) {
138
+ try {
139
+ const ast = parse(source);
140
+ const statements = [];
141
+ for (const node of ast.body) {
142
+ const type = node.type;
143
+ if (type === 'ImportDeclaration')
144
+ continue;
145
+ if (type === 'ExportNamedDeclaration' && node.declaration)
146
+ continue;
147
+ if (type === 'ExportDefaultDeclaration') {
148
+ const d = node.declaration;
149
+ if (d && typeof d.start === 'number' && typeof d.end === 'number') {
150
+ statements.push(source.slice(d.start, d.end));
151
+ }
152
+ continue;
153
+ }
154
+ if (type === 'ComponentDeclaration')
155
+ continue;
156
+ if (type === 'ClassDeclaration')
157
+ continue;
158
+ if (typeof node.start === 'number' && typeof node.end === 'number') {
159
+ statements.push(source.slice(node.start, node.end));
160
+ }
161
+ }
162
+ return statements;
163
+ }
164
+ catch {
165
+ return [];
166
+ }
167
+ }
@@ -0,0 +1,30 @@
1
+ import type { ApiRouteNode } from '@vesk/compiler/src/types';
2
+ export declare function scanApiRoutes(apiDir: string): ApiRouteNode[];
3
+ export declare function matchApiUrl(tree: ApiRouteNode[], pathname: string): {
4
+ node: ApiRouteNode;
5
+ params: Record<string, string>;
6
+ } | null;
7
+ export declare function parseCookies(str: string): Record<string, string>;
8
+ export interface DevCache extends Map<string, number> {
9
+ }
10
+ export type BuildWebRequestInput = {
11
+ method?: string;
12
+ headers?: Record<string, string | string[] | number | undefined>;
13
+ socket?: {
14
+ remoteAddress?: string;
15
+ };
16
+ [Symbol.asyncIterator](): AsyncIterableIterator<Buffer | Uint8Array | string>;
17
+ };
18
+ /**
19
+ * Build a standard Web API Request from a Node.js IncomingMessage.
20
+ *
21
+ * When `body` is omitted, the body is read lazily from the Node stream and
22
+ * `json()`/`text()` are patched accordingly. A `cookies` getter is attached
23
+ * (NextRequest-compatible).
24
+ */
25
+ export declare function buildWebRequest(nodeReq: BuildWebRequestInput, url: string, body?: BodyInit | null): Request & {
26
+ cookies: Record<string, string>;
27
+ query: Record<string, string>;
28
+ };
29
+ export declare function executeApiRoute(filePath: string, method: string, request: Request, params?: Record<string, string>, locals?: Record<string, unknown>, devCache?: DevCache): Promise<Response | null>;
30
+ //# sourceMappingURL=api-routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-routes.d.ts","sourceRoot":"","sources":["../src/api-routes.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAS7D,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,EAAE,CAG5D;AA+ED,wBAAgB,WAAW,CAAC,IAAI,EAAE,YAAY,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG,IAAI,CAoDjI;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAWhE;AAED,MAAM,WAAW,QAAS,SAAQ,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;CAAG;AAExD,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAAC,CAAC;IACjE,MAAM,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACpC,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,qBAAqB,CAAC,MAAM,GAAG,UAAU,GAAG,MAAM,CAAC,CAAC;CAC/E,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,oBAAoB,EAC7B,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,QAAQ,GAAG,IAAI,GACrB,OAAO,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAqC9E;AAED,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,EAChB,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EACnC,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACpC,QAAQ,CAAC,EAAE,QAAQ,GAClB,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAkI1B"}
@@ -0,0 +1,350 @@
1
+ import { readdirSync, statSync, existsSync } from 'fs';
2
+ import { join } from 'path';
3
+ function basename(p) {
4
+ const idx = p.lastIndexOf('/');
5
+ return idx === -1 ? p : p.slice(idx + 1);
6
+ }
7
+ export function scanApiRoutes(apiDir) {
8
+ if (!existsSync(apiDir))
9
+ return [];
10
+ return scanApiDir(apiDir, apiDir, '/');
11
+ }
12
+ function scanApiDir(rootDir, dir, parentPath) {
13
+ const nodes = [];
14
+ let entries;
15
+ try {
16
+ entries = readdirSync(dir);
17
+ }
18
+ catch {
19
+ return nodes;
20
+ }
21
+ let hasRoute = false;
22
+ let routeFileName = null;
23
+ for (const entry of entries) {
24
+ if (entry === 'route.js' || entry === 'route.ts') {
25
+ hasRoute = true;
26
+ routeFileName = entry;
27
+ break;
28
+ }
29
+ }
30
+ const segName = basename(dir);
31
+ const isDynamic = segName.startsWith('[') && segName.endsWith(']') && !segName.startsWith('[...');
32
+ const isCatchAll = segName.startsWith('[...') && segName.endsWith(']');
33
+ const isPrivate = segName.startsWith('_');
34
+ const isRouteGroup = segName.startsWith('(') && segName.endsWith(')');
35
+ if (isPrivate && dir !== rootDir)
36
+ return nodes;
37
+ if (isRouteGroup) {
38
+ for (const entry of entries) {
39
+ const entryPath = join(dir, entry);
40
+ let entryStat;
41
+ try {
42
+ entryStat = statSync(entryPath);
43
+ }
44
+ catch {
45
+ continue;
46
+ }
47
+ if (entryStat.isDirectory()) {
48
+ const childNodes = scanApiDir(rootDir, entryPath, parentPath);
49
+ nodes.push(...childNodes);
50
+ }
51
+ }
52
+ return nodes;
53
+ }
54
+ let seg = '';
55
+ if (dir === rootDir) {
56
+ seg = '';
57
+ }
58
+ else if (isDynamic) {
59
+ seg = ':' + segName.slice(1, -1);
60
+ }
61
+ else if (isCatchAll) {
62
+ seg = ':' + segName.slice(4, -1);
63
+ }
64
+ else {
65
+ seg = segName;
66
+ }
67
+ const fullPath = seg
68
+ ? (parentPath === '/' ? '/' : parentPath + '/') + seg
69
+ : (parentPath || '/');
70
+ const node = {
71
+ path: seg,
72
+ fullPath: fullPath.replace(/\/+/g, '/') || '/',
73
+ isDynamic,
74
+ isCatchAll,
75
+ filePath: hasRoute && routeFileName ? join(dir, routeFileName) : null,
76
+ children: [],
77
+ };
78
+ for (const entry of entries) {
79
+ const entryPath = join(dir, entry);
80
+ let entryStat;
81
+ try {
82
+ entryStat = statSync(entryPath);
83
+ }
84
+ catch {
85
+ continue;
86
+ }
87
+ if (entryStat.isDirectory()) {
88
+ const childNodes = scanApiDir(rootDir, entryPath, fullPath);
89
+ node.children.push(...childNodes);
90
+ }
91
+ }
92
+ if (node.filePath || node.children.length > 0) {
93
+ nodes.push(node);
94
+ }
95
+ return nodes;
96
+ }
97
+ export function matchApiUrl(tree, pathname) {
98
+ const normalized = (pathname.split('?')[0].split('#')[0]).replace(/^\/api(\/|$)/, '/');
99
+ const parts = normalized.split('/').filter(Boolean);
100
+ const params = {};
101
+ function matchNodes(nodes, partIndex) {
102
+ for (const node of nodes) {
103
+ if (node.fullPath === '/') {
104
+ if (partIndex >= parts.length && node.filePath)
105
+ return node;
106
+ return matchNodes(node.children, partIndex);
107
+ }
108
+ if (partIndex >= parts.length) {
109
+ if (node.filePath)
110
+ return node;
111
+ continue;
112
+ }
113
+ const part = parts[partIndex];
114
+ if (node.isCatchAll) {
115
+ const paramName = node.path.startsWith(':') ? node.path.slice(1) : node.path;
116
+ params[paramName] = parts.slice(partIndex).map(decodeURIComponent).join('/');
117
+ return node;
118
+ }
119
+ if (node.isDynamic) {
120
+ const paramName = node.path.startsWith(':') ? node.path.slice(1) : node.path;
121
+ params[paramName] = decodeURIComponent(part);
122
+ if (node.children.length > 0) {
123
+ const result = matchNodes(node.children, partIndex + 1);
124
+ if (result)
125
+ return result;
126
+ }
127
+ if (node.filePath)
128
+ return node;
129
+ delete params[paramName];
130
+ continue;
131
+ }
132
+ if (node.path === part) {
133
+ if (node.children.length > 0) {
134
+ const result = matchNodes(node.children, partIndex + 1);
135
+ if (result)
136
+ return result;
137
+ }
138
+ if (node.filePath)
139
+ return node;
140
+ continue;
141
+ }
142
+ }
143
+ return null;
144
+ }
145
+ const matched = matchNodes(tree, 0);
146
+ if (!matched)
147
+ return null;
148
+ return { node: matched, params: { ...params } };
149
+ }
150
+ export function parseCookies(str) {
151
+ const obj = {};
152
+ if (!str)
153
+ return obj;
154
+ for (const pair of str.split(';')) {
155
+ const eq = pair.indexOf('=');
156
+ if (eq === -1)
157
+ continue;
158
+ const k = pair.slice(0, eq).trim();
159
+ const v = pair.slice(eq + 1).trim();
160
+ if (k)
161
+ obj[k] = v;
162
+ }
163
+ return obj;
164
+ }
165
+ /**
166
+ * Build a standard Web API Request from a Node.js IncomingMessage.
167
+ *
168
+ * When `body` is omitted, the body is read lazily from the Node stream and
169
+ * `json()`/`text()` are patched accordingly. A `cookies` getter is attached
170
+ * (NextRequest-compatible).
171
+ */
172
+ export function buildWebRequest(nodeReq, url, body) {
173
+ const parsedUrl = new URL(url, `http://${nodeReq.headers?.host || 'localhost'}`);
174
+ const method = nodeReq.method || 'GET';
175
+ const headers = {};
176
+ for (const [k, v] of Object.entries(nodeReq.headers || {})) {
177
+ headers[k] = Array.isArray(v) ? v.join(', ') : v === undefined ? '' : String(v);
178
+ }
179
+ const webRequest = new Request(parsedUrl, { method, headers, body: body ?? null });
180
+ if (body === undefined) {
181
+ let _bodyBuffer = null;
182
+ const getBody = async () => {
183
+ if (_bodyBuffer)
184
+ return _bodyBuffer;
185
+ const chunks = [];
186
+ for await (const chunk of nodeReq)
187
+ chunks.push(chunk);
188
+ _bodyBuffer = Buffer.concat(chunks);
189
+ return _bodyBuffer;
190
+ };
191
+ Object.defineProperty(webRequest, 'json', {
192
+ value: async () => { try {
193
+ return JSON.parse((await getBody()).toString());
194
+ }
195
+ catch {
196
+ return null;
197
+ } },
198
+ configurable: true,
199
+ });
200
+ Object.defineProperty(webRequest, 'text', {
201
+ value: async () => (await getBody()).toString('utf-8'),
202
+ configurable: true,
203
+ });
204
+ }
205
+ const rawCookies = parseCookies(String(nodeReq.headers?.cookie || ''));
206
+ Object.defineProperty(webRequest, 'cookies', { get: () => rawCookies, enumerable: true });
207
+ const query = {};
208
+ for (const [k, v] of parsedUrl.searchParams.entries())
209
+ query[k] = v;
210
+ Object.defineProperty(webRequest, 'query', { get: () => query, enumerable: true });
211
+ return webRequest;
212
+ }
213
+ export async function executeApiRoute(filePath, method, request, params = {}, locals = {}, devCache) {
214
+ let mod;
215
+ try {
216
+ if (devCache && devCache.has(filePath)) {
217
+ const t = devCache.get(filePath);
218
+ const url = new URL('file://' + filePath);
219
+ url.searchParams.set('t', String(t));
220
+ mod = await import(url.href);
221
+ }
222
+ else {
223
+ mod = await import(filePath);
224
+ }
225
+ }
226
+ catch (e) {
227
+ return new Response(JSON.stringify({ error: 'Failed to load route module', details: e.message }), {
228
+ status: 500, headers: { 'Content-Type': 'application/json' },
229
+ });
230
+ }
231
+ const routeConfig = (mod.config || {});
232
+ const handler = mod[method];
233
+ if (!handler) {
234
+ if (method === 'OPTIONS') {
235
+ const allowed = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS']
236
+ .filter(m => mod[m]);
237
+ return new Response(null, {
238
+ status: 204,
239
+ headers: { Allow: allowed.join(', ') },
240
+ });
241
+ }
242
+ return new Response(JSON.stringify({ error: `Method ${method} not allowed` }), {
243
+ status: 405, headers: { 'Content-Type': 'application/json', Allow: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'].filter(m => mod[m]).join(', ') },
244
+ });
245
+ }
246
+ const ctx = {
247
+ headers: Object.fromEntries([...request.headers.entries()].map(([k, v]) => [k, Array.isArray(v) ? v.join(', ') : v])),
248
+ url: request.url,
249
+ method: request.method,
250
+ cookies: parseCookies(request.headers.get('cookie') || ''),
251
+ locals,
252
+ _request: request,
253
+ params,
254
+ };
255
+ Object.defineProperty(request, 'locals', {
256
+ get: () => locals,
257
+ enumerable: true,
258
+ });
259
+ const prev = globalThis.__vesk_request;
260
+ globalThis.__vesk_request = ctx;
261
+ try {
262
+ let signal = request.signal;
263
+ if (routeConfig.maxDuration) {
264
+ const controller = new AbortController();
265
+ const timeout = setTimeout(() => controller.abort(new Error(`Request timed out after ${routeConfig.maxDuration}s`)), routeConfig.maxDuration * 1000);
266
+ signal = controller.signal;
267
+ Object.defineProperty(request, 'signal', { value: signal, writable: false });
268
+ }
269
+ const beforeHooks = (mod.beforeRequest || []);
270
+ for (const hook of beforeHooks) {
271
+ const hookResult = await hook(request, { params, locals });
272
+ if (hookResult instanceof Response)
273
+ return hookResult;
274
+ }
275
+ const { runHooks: execHooks } = await import('@vesk/runtime/server');
276
+ let globalHookResult = await execHooks('beforeRequest', request, { params, locals });
277
+ if (globalHookResult instanceof Response)
278
+ return globalHookResult;
279
+ let response;
280
+ try {
281
+ response = await handler(request, { params: Promise.resolve(params) });
282
+ }
283
+ catch (e) {
284
+ let errorResult = await execHooks('onError', e, request);
285
+ if (errorResult instanceof Response)
286
+ return errorResult;
287
+ throw e;
288
+ }
289
+ const afterHooks = (mod.afterRequest || []);
290
+ for (const hook of afterHooks) {
291
+ const hookResult = await hook(request, response);
292
+ if (hookResult instanceof Response)
293
+ response = hookResult;
294
+ }
295
+ let globalAfterResult = await execHooks('afterRequest', request, response);
296
+ if (globalAfterResult instanceof Response)
297
+ response = globalAfterResult;
298
+ const respObj = response;
299
+ if (typeof respObj?.build === 'function') {
300
+ respObj.build();
301
+ }
302
+ if (response instanceof Response) {
303
+ const rewriteUrl = response.headers.get('x-vesk-rewrite');
304
+ if (rewriteUrl) {
305
+ return executeRewrite(rewriteUrl, request);
306
+ }
307
+ if (response.headers.get('x-vesk-next')) {
308
+ return null;
309
+ }
310
+ return response;
311
+ }
312
+ return new Response(JSON.stringify(response), {
313
+ status: 200, headers: { 'Content-Type': 'application/json' },
314
+ });
315
+ }
316
+ catch (e) {
317
+ const err = e;
318
+ if (err.name === 'Redirect') {
319
+ return new Response(null, {
320
+ status: err.status || 302,
321
+ headers: { Location: err.url || '' },
322
+ });
323
+ }
324
+ if (err.name === 'NotFoundError') {
325
+ return new Response(JSON.stringify({ error: 'Not Found' }), {
326
+ status: 404, headers: { 'Content-Type': 'application/json' },
327
+ });
328
+ }
329
+ return new Response(JSON.stringify({ error: err.message }), {
330
+ status: 500, headers: { 'Content-Type': 'application/json' },
331
+ });
332
+ }
333
+ finally {
334
+ globalThis.__vesk_request = prev;
335
+ }
336
+ }
337
+ async function executeRewrite(url, originalRequest) {
338
+ const rewriteReq = new Request(url, {
339
+ method: originalRequest.method,
340
+ headers: originalRequest.headers,
341
+ body: originalRequest.body,
342
+ });
343
+ if (originalRequest.locals) {
344
+ Object.defineProperty(rewriteReq, 'locals', {
345
+ get: () => originalRequest.locals,
346
+ enumerable: true,
347
+ });
348
+ }
349
+ return rewriteReq;
350
+ }
@@ -0,0 +1,19 @@
1
+ import type { IRNode } from '@vesk/compiler/src/ir';
2
+ import { DynamicBinding, RuntimeStatement } from '@vesk/compiler/src/ir';
3
+ import type { Expression } from '@vesk/compiler/src/ir';
4
+ export interface TrackedInfo {
5
+ cellName: string;
6
+ kind: 'virtual' | 'cell';
7
+ }
8
+ export declare function semicolonizeStatement(code: string): string;
9
+ export declare function transformTracked(irNode: Expression | RuntimeStatement | DynamicBinding, tracked: Map<string, TrackedInfo>): string;
10
+ export declare function collectTrackedNames(body: IRNode[]): Map<string, TrackedInfo>;
11
+ declare function isStaticIR(body: IRNode[]): boolean;
12
+ export declare function escapeHtml(str: string): string;
13
+ export declare function compileClient(source: string, _componentName: string | null, options?: {
14
+ forceClient?: boolean;
15
+ hydrate?: boolean;
16
+ includeTopLevel?: boolean;
17
+ }): string;
18
+ export { compileClient as compile, isStaticIR };
19
+ //# sourceMappingURL=client-codegen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-codegen.d.ts","sourceRoot":"","sources":["../src/client-codegen.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAuB,MAAM,uBAAuB,CAAC;AACzE,OAAO,EAGL,cAAc,EAQd,gBAAgB,EAOjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAsCxD,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,SAAS,GAAG,MAAM,CAAC;CAC1B;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI1D;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,gBAAgB,GAAG,cAAc,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,MAAM,CAwGlI;AAID,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAU5E;AAqjCD,iBAAS,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAe3C;AA2HD,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAO9C;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,eAAe,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,MAAM,CA0D1K;AAED,OAAO,EAAE,aAAa,IAAI,OAAO,EAAE,UAAU,EAAE,CAAC"}