@kuratchi/js 0.0.15 → 0.0.17

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 (70) hide show
  1. package/README.md +160 -1
  2. package/dist/cli.js +78 -45
  3. package/dist/compiler/api-route-pipeline.d.ts +8 -0
  4. package/dist/compiler/api-route-pipeline.js +23 -0
  5. package/dist/compiler/asset-pipeline.d.ts +7 -0
  6. package/dist/compiler/asset-pipeline.js +33 -0
  7. package/dist/compiler/client-module-pipeline.d.ts +25 -0
  8. package/dist/compiler/client-module-pipeline.js +257 -0
  9. package/dist/compiler/compiler-shared.d.ts +73 -0
  10. package/dist/compiler/compiler-shared.js +4 -0
  11. package/dist/compiler/component-pipeline.d.ts +15 -0
  12. package/dist/compiler/component-pipeline.js +158 -0
  13. package/dist/compiler/config-reading.d.ts +12 -0
  14. package/dist/compiler/config-reading.js +380 -0
  15. package/dist/compiler/convention-discovery.d.ts +9 -0
  16. package/dist/compiler/convention-discovery.js +83 -0
  17. package/dist/compiler/durable-object-pipeline.d.ts +9 -0
  18. package/dist/compiler/durable-object-pipeline.js +255 -0
  19. package/dist/compiler/error-page-pipeline.d.ts +1 -0
  20. package/dist/compiler/error-page-pipeline.js +16 -0
  21. package/dist/compiler/import-linking.d.ts +36 -0
  22. package/dist/compiler/import-linking.js +140 -0
  23. package/dist/compiler/index.d.ts +7 -7
  24. package/dist/compiler/index.js +181 -3321
  25. package/dist/compiler/layout-pipeline.d.ts +31 -0
  26. package/dist/compiler/layout-pipeline.js +155 -0
  27. package/dist/compiler/page-route-pipeline.d.ts +16 -0
  28. package/dist/compiler/page-route-pipeline.js +62 -0
  29. package/dist/compiler/parser.d.ts +4 -0
  30. package/dist/compiler/parser.js +436 -55
  31. package/dist/compiler/root-layout-pipeline.d.ts +10 -0
  32. package/dist/compiler/root-layout-pipeline.js +532 -0
  33. package/dist/compiler/route-discovery.d.ts +7 -0
  34. package/dist/compiler/route-discovery.js +87 -0
  35. package/dist/compiler/route-pipeline.d.ts +57 -0
  36. package/dist/compiler/route-pipeline.js +291 -0
  37. package/dist/compiler/route-state-pipeline.d.ts +26 -0
  38. package/dist/compiler/route-state-pipeline.js +139 -0
  39. package/dist/compiler/routes-module-feature-blocks.d.ts +2 -0
  40. package/dist/compiler/routes-module-feature-blocks.js +330 -0
  41. package/dist/compiler/routes-module-pipeline.d.ts +2 -0
  42. package/dist/compiler/routes-module-pipeline.js +6 -0
  43. package/dist/compiler/routes-module-runtime-shell.d.ts +2 -0
  44. package/dist/compiler/routes-module-runtime-shell.js +91 -0
  45. package/dist/compiler/routes-module-types.d.ts +45 -0
  46. package/dist/compiler/routes-module-types.js +1 -0
  47. package/dist/compiler/script-transform.d.ts +16 -0
  48. package/dist/compiler/script-transform.js +218 -0
  49. package/dist/compiler/server-module-pipeline.d.ts +13 -0
  50. package/dist/compiler/server-module-pipeline.js +124 -0
  51. package/dist/compiler/template.d.ts +13 -1
  52. package/dist/compiler/template.js +337 -71
  53. package/dist/compiler/worker-output-pipeline.d.ts +13 -0
  54. package/dist/compiler/worker-output-pipeline.js +37 -0
  55. package/dist/compiler/wrangler-sync.d.ts +14 -0
  56. package/dist/compiler/wrangler-sync.js +185 -0
  57. package/dist/runtime/app.js +15 -3
  58. package/dist/runtime/context.d.ts +4 -0
  59. package/dist/runtime/context.js +40 -2
  60. package/dist/runtime/do.js +21 -6
  61. package/dist/runtime/generated-worker.d.ts +55 -0
  62. package/dist/runtime/generated-worker.js +543 -0
  63. package/dist/runtime/index.d.ts +4 -1
  64. package/dist/runtime/index.js +2 -0
  65. package/dist/runtime/router.d.ts +6 -1
  66. package/dist/runtime/router.js +125 -31
  67. package/dist/runtime/security.d.ts +101 -0
  68. package/dist/runtime/security.js +298 -0
  69. package/dist/runtime/types.d.ts +29 -2
  70. package/package.json +5 -1
@@ -0,0 +1,37 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ export function resolveRuntimeImportPath(projectDir) {
4
+ const candidates = [
5
+ { file: 'src/server/runtime.hook.ts', importPath: '../src/server/runtime.hook' },
6
+ ];
7
+ for (const candidate of candidates) {
8
+ if (fs.existsSync(path.join(projectDir, candidate.file))) {
9
+ return candidate.importPath;
10
+ }
11
+ }
12
+ return null;
13
+ }
14
+ export function toWorkerImportPath(projectDir, outDir, filePath) {
15
+ const absPath = path.isAbsolute(filePath) ? filePath : path.join(projectDir, filePath);
16
+ let rel = path.relative(outDir, absPath).replace(/\\/g, '/');
17
+ if (!rel.startsWith('.'))
18
+ rel = `./${rel}`;
19
+ return rel.replace(/\.(ts|js|mjs|cjs)$/, '');
20
+ }
21
+ export function buildWorkerEntrypointSource(opts) {
22
+ const workerClassExports = opts.workerClassEntries
23
+ .map((entry) => {
24
+ const importPath = toWorkerImportPath(opts.projectDir, opts.outDir, entry.file);
25
+ if (entry.exportKind === 'default') {
26
+ return `export { default as ${entry.className} } from '${importPath}';`;
27
+ }
28
+ return `export { ${entry.className} } from '${importPath}';`;
29
+ });
30
+ return [
31
+ '// Auto-generated by kuratchi — do not edit.',
32
+ "export { default } from './routes.ts';",
33
+ ...opts.doClassNames.map((className) => `export { ${className} } from './routes.ts';`),
34
+ ...workerClassExports,
35
+ '',
36
+ ].join('\n');
37
+ }
@@ -0,0 +1,14 @@
1
+ export interface WranglerSyncEntry {
2
+ binding: string;
3
+ className: string;
4
+ }
5
+ export interface WranglerSyncConfig {
6
+ workflows: WranglerSyncEntry[];
7
+ containers: WranglerSyncEntry[];
8
+ durableObjects: WranglerSyncEntry[];
9
+ }
10
+ export declare function syncWranglerConfig(opts: {
11
+ projectDir: string;
12
+ config: WranglerSyncConfig;
13
+ writeFile: (filePath: string, content: string) => void;
14
+ }): void;
@@ -0,0 +1,185 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ function stripJsonComments(content) {
4
+ let result = '';
5
+ let i = 0;
6
+ let inString = false;
7
+ let stringChar = '';
8
+ while (i < content.length) {
9
+ const ch = content[i];
10
+ const next = content[i + 1];
11
+ if (inString) {
12
+ result += ch;
13
+ if (ch === '\\' && i + 1 < content.length) {
14
+ result += next;
15
+ i += 2;
16
+ continue;
17
+ }
18
+ if (ch === stringChar) {
19
+ inString = false;
20
+ }
21
+ i++;
22
+ continue;
23
+ }
24
+ if (ch === '"' || ch === "'") {
25
+ inString = true;
26
+ stringChar = ch;
27
+ result += ch;
28
+ i++;
29
+ continue;
30
+ }
31
+ if (ch === '/' && next === '/') {
32
+ while (i < content.length && content[i] !== '\n')
33
+ i++;
34
+ continue;
35
+ }
36
+ if (ch === '/' && next === '*') {
37
+ i += 2;
38
+ while (i < content.length - 1 && !(content[i] === '*' && content[i + 1] === '/'))
39
+ i++;
40
+ i += 2;
41
+ continue;
42
+ }
43
+ result += ch;
44
+ i++;
45
+ }
46
+ return result;
47
+ }
48
+ export function syncWranglerConfig(opts) {
49
+ const jsoncPath = path.join(opts.projectDir, 'wrangler.jsonc');
50
+ const jsonPath = path.join(opts.projectDir, 'wrangler.json');
51
+ const tomlPath = path.join(opts.projectDir, 'wrangler.toml');
52
+ let configPath;
53
+ let isJsonc = false;
54
+ if (fs.existsSync(jsoncPath)) {
55
+ configPath = jsoncPath;
56
+ isJsonc = true;
57
+ }
58
+ else if (fs.existsSync(jsonPath)) {
59
+ configPath = jsonPath;
60
+ }
61
+ else if (fs.existsSync(tomlPath)) {
62
+ console.log('[kuratchi] wrangler.toml detected. Auto-sync requires wrangler.jsonc. Skipping wrangler sync.');
63
+ return;
64
+ }
65
+ else {
66
+ console.log('[kuratchi] Creating wrangler.jsonc with workflow config...');
67
+ configPath = jsoncPath;
68
+ isJsonc = true;
69
+ }
70
+ let rawContent = '';
71
+ let wranglerConfig = {};
72
+ if (fs.existsSync(configPath)) {
73
+ rawContent = fs.readFileSync(configPath, 'utf-8');
74
+ try {
75
+ const jsonContent = stripJsonComments(rawContent);
76
+ wranglerConfig = JSON.parse(jsonContent);
77
+ }
78
+ catch (err) {
79
+ console.error(`[kuratchi] Failed to parse ${path.basename(configPath)}: ${err.message}`);
80
+ console.error('[kuratchi] Skipping wrangler sync. Please fix the JSON syntax.');
81
+ return;
82
+ }
83
+ }
84
+ let changed = false;
85
+ if (opts.config.workflows.length > 0) {
86
+ const existingWorkflows = wranglerConfig.workflows || [];
87
+ const existingByBinding = new Map(existingWorkflows.map((workflow) => [workflow.binding, workflow]));
88
+ for (const workflow of opts.config.workflows) {
89
+ const name = workflow.binding.toLowerCase().replace(/_/g, '-');
90
+ const entry = {
91
+ name,
92
+ binding: workflow.binding,
93
+ class_name: workflow.className,
94
+ };
95
+ const existing = existingByBinding.get(workflow.binding);
96
+ if (!existing) {
97
+ existingWorkflows.push(entry);
98
+ changed = true;
99
+ console.log(`[kuratchi] Added workflow "${workflow.binding}" to wrangler config`);
100
+ }
101
+ else if (existing.class_name !== workflow.className) {
102
+ existing.class_name = workflow.className;
103
+ changed = true;
104
+ console.log(`[kuratchi] Updated workflow "${workflow.binding}" class_name to "${workflow.className}"`);
105
+ }
106
+ }
107
+ const configBindings = new Set(opts.config.workflows.map((workflow) => workflow.binding));
108
+ const filtered = existingWorkflows.filter((workflow) => {
109
+ if (!configBindings.has(workflow.binding)) {
110
+ const expectedName = workflow.binding.toLowerCase().replace(/_/g, '-');
111
+ if (workflow.name === expectedName) {
112
+ console.log(`[kuratchi] Removed workflow "${workflow.binding}" from wrangler config`);
113
+ changed = true;
114
+ return false;
115
+ }
116
+ }
117
+ return true;
118
+ });
119
+ if (filtered.length !== existingWorkflows.length) {
120
+ wranglerConfig.workflows = filtered;
121
+ }
122
+ else {
123
+ wranglerConfig.workflows = existingWorkflows;
124
+ }
125
+ if (wranglerConfig.workflows.length === 0) {
126
+ delete wranglerConfig.workflows;
127
+ }
128
+ }
129
+ if (opts.config.containers.length > 0) {
130
+ const existingContainers = wranglerConfig.containers || [];
131
+ const existingByBinding = new Map(existingContainers.map((container) => [container.binding, container]));
132
+ for (const container of opts.config.containers) {
133
+ const name = container.binding.toLowerCase().replace(/_/g, '-');
134
+ const entry = {
135
+ name,
136
+ binding: container.binding,
137
+ class_name: container.className,
138
+ };
139
+ const existing = existingByBinding.get(container.binding);
140
+ if (!existing) {
141
+ existingContainers.push(entry);
142
+ changed = true;
143
+ console.log(`[kuratchi] Added container "${container.binding}" to wrangler config`);
144
+ }
145
+ else if (existing.class_name !== container.className) {
146
+ existing.class_name = container.className;
147
+ changed = true;
148
+ console.log(`[kuratchi] Updated container "${container.binding}" class_name to "${container.className}"`);
149
+ }
150
+ }
151
+ wranglerConfig.containers = existingContainers;
152
+ if (wranglerConfig.containers.length === 0) {
153
+ delete wranglerConfig.containers;
154
+ }
155
+ }
156
+ if (opts.config.durableObjects.length > 0) {
157
+ if (!wranglerConfig.durable_objects) {
158
+ wranglerConfig.durable_objects = { bindings: [] };
159
+ }
160
+ const existingBindings = wranglerConfig.durable_objects.bindings || [];
161
+ const existingByName = new Map(existingBindings.map((binding) => [binding.name, binding]));
162
+ for (const durableObject of opts.config.durableObjects) {
163
+ const entry = {
164
+ name: durableObject.binding,
165
+ class_name: durableObject.className,
166
+ };
167
+ const existing = existingByName.get(durableObject.binding);
168
+ if (!existing) {
169
+ existingBindings.push(entry);
170
+ changed = true;
171
+ console.log(`[kuratchi] Added durable_object "${durableObject.binding}" to wrangler config`);
172
+ }
173
+ else if (existing.class_name !== durableObject.className) {
174
+ existing.class_name = durableObject.className;
175
+ changed = true;
176
+ console.log(`[kuratchi] Updated durable_object "${durableObject.binding}" class_name to "${durableObject.className}"`);
177
+ }
178
+ }
179
+ wranglerConfig.durable_objects.bindings = existingBindings;
180
+ }
181
+ if (!changed)
182
+ return;
183
+ const newContent = JSON.stringify(wranglerConfig, null, isJsonc ? '\t' : '\t');
184
+ opts.writeFile(configPath, newContent + '\n');
185
+ }
@@ -133,13 +133,25 @@ export function createApp(config) {
133
133
  }
134
134
  /** Render a page through its layout */
135
135
  function renderPage(route, data, layouts) {
136
- const content = route.render(data);
136
+ const rendered = normalizeRenderOutput(route.render(data));
137
137
  const layoutName = route.layout ?? 'default';
138
138
  const layout = layouts[layoutName];
139
139
  const html = layout
140
- ? layout.render({ content, data })
141
- : content;
140
+ ? layout.render({ content: rendered.html, data, head: rendered.head })
141
+ : rendered.html;
142
142
  return new Response(html, {
143
143
  headers: { 'content-type': 'text/html; charset=utf-8' },
144
144
  });
145
145
  }
146
+ function normalizeRenderOutput(output) {
147
+ if (typeof output === 'string') {
148
+ return { html: output, head: '' };
149
+ }
150
+ return {
151
+ html: typeof output?.html === 'string' ? output.html : '',
152
+ head: typeof output?.head === 'string' ? output.head : '',
153
+ fragments: output && typeof output === 'object' && !Array.isArray(output) && typeof output.fragments === 'object'
154
+ ? (output.fragments ?? {})
155
+ : {},
156
+ };
157
+ }
@@ -57,3 +57,7 @@ export declare function __esc(v: any): string;
57
57
  export declare function __rawHtml(v: any): string;
58
58
  /** Best-effort HTML sanitizer for {@html ...} template output. */
59
59
  export declare function __sanitizeHtml(v: any): string;
60
+ /** Get CSRF token for form injection (used by template compiler) */
61
+ export declare function __getCsrfToken(): string;
62
+ /** Sign a fragment ID for secure polling (used by template compiler) */
63
+ export declare function __signFragment(fragmentId: string): string;
@@ -161,13 +161,51 @@ export function __rawHtml(v) {
161
161
  /** Best-effort HTML sanitizer for {@html ...} template output. */
162
162
  export function __sanitizeHtml(v) {
163
163
  let html = __rawHtml(v);
164
+ // Remove dangerous elements entirely
164
165
  html = html.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, '');
165
166
  html = html.replace(/<iframe\b[^>]*>[\s\S]*?<\/iframe>/gi, '');
166
167
  html = html.replace(/<object\b[^>]*>[\s\S]*?<\/object>/gi, '');
167
168
  html = html.replace(/<embed\b[^>]*>/gi, '');
169
+ html = html.replace(/<base\b[^>]*>/gi, '');
170
+ html = html.replace(/<meta\b[^>]*>/gi, '');
171
+ html = html.replace(/<link\b[^>]*>/gi, '');
172
+ html = html.replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, '');
173
+ html = html.replace(/<template\b[^>]*>[\s\S]*?<\/template>/gi, '');
174
+ html = html.replace(/<noscript\b[^>]*>[\s\S]*?<\/noscript>/gi, '');
175
+ // Remove all event handlers (on*)
168
176
  html = html.replace(/\son[a-z]+\s*=\s*("[^"]*"|'[^']*'|[^\s>]+)/gi, '');
169
- html = html.replace(/\s(href|src|xlink:href)\s*=\s*(["'])\s*javascript:[\s\S]*?\2/gi, ' $1="#"');
170
- html = html.replace(/\s(href|src|xlink:href)\s*=\s*javascript:[^\s>]+/gi, ' $1="#"');
177
+ // Remove javascript: URLs in href, src, xlink:href, action, formaction, data
178
+ html = html.replace(/\s(href|src|xlink:href|action|formaction|data)\s*=\s*(["'])\s*javascript:[\s\S]*?\2/gi, ' $1="#"');
179
+ html = html.replace(/\s(href|src|xlink:href|action|formaction|data)\s*=\s*javascript:[^\s>]+/gi, ' $1="#"');
180
+ // Remove vbscript: URLs
181
+ html = html.replace(/\s(href|src|xlink:href|action|formaction|data)\s*=\s*(["'])\s*vbscript:[\s\S]*?\2/gi, ' $1="#"');
182
+ html = html.replace(/\s(href|src|xlink:href|action|formaction|data)\s*=\s*vbscript:[^\s>]+/gi, ' $1="#"');
183
+ // Remove data: URLs in src (can contain scripts)
184
+ html = html.replace(/\ssrc\s*=\s*(["'])\s*data:[\s\S]*?\1/gi, ' src="#"');
185
+ html = html.replace(/\ssrc\s*=\s*data:[^\s>]+/gi, ' src="#"');
186
+ // Remove srcdoc (can contain arbitrary HTML)
171
187
  html = html.replace(/\ssrcdoc\s*=\s*("[^"]*"|'[^']*'|[^\s>]+)/gi, '');
188
+ // Remove form-related dangerous attributes
189
+ html = html.replace(/\sformaction\s*=\s*("[^"]*"|'[^']*'|[^\s>]+)/gi, '');
190
+ // Remove SVG-specific dangerous elements
191
+ html = html.replace(/<foreignObject\b[^>]*>[\s\S]*?<\/foreignObject>/gi, '');
192
+ html = html.replace(/<use\b[^>]*>/gi, '');
172
193
  return html;
173
194
  }
195
+ /** Get CSRF token for form injection (used by template compiler) */
196
+ export function __getCsrfToken() {
197
+ return __locals.__csrfToken || '';
198
+ }
199
+ /** Sign a fragment ID for secure polling (used by template compiler) */
200
+ export function __signFragment(fragmentId) {
201
+ const token = __locals.__csrfToken || '';
202
+ const routePath = __locals.__currentRoutePath || '/';
203
+ const payload = `${fragmentId}:${routePath}:${token}`;
204
+ // FNV-1a hash for fast, consistent signing
205
+ let hash = 2166136261;
206
+ for (let i = 0; i < payload.length; i++) {
207
+ hash ^= payload.charCodeAt(i);
208
+ hash = (hash * 16777619) >>> 0;
209
+ }
210
+ return `${fragmentId}:${hash.toString(36)}`;
211
+ }
@@ -30,6 +30,10 @@ export function __getDoSelf() {
30
30
  }
31
31
  const _resolvers = new Map();
32
32
  const _classBindings = new WeakMap();
33
+ const _rpcProxyCache = new WeakMap();
34
+ function __isDevMode() {
35
+ return !!globalThis.__kuratchi_DEV__;
36
+ }
33
37
  /** @internal — called by compiler-generated init code */
34
38
  export function __registerDoResolver(binding, resolver) {
35
39
  _resolvers.set(binding, resolver);
@@ -94,36 +98,47 @@ export class kuratchiDO {
94
98
  */
95
99
  static rpc() {
96
100
  const klass = this;
97
- return new Proxy({}, {
101
+ // Cache proxy per class to avoid repeated Proxy creation
102
+ let cached = _rpcProxyCache.get(klass);
103
+ if (cached)
104
+ return cached;
105
+ const proxy = new Proxy({}, {
98
106
  get(_, method) {
99
107
  return async (...args) => {
100
108
  const binding = this.binding || _classBindings.get(klass);
101
109
  if (!binding) {
102
110
  throw new Error(`[KuratchiJS] Missing DO binding for class '${this?.name || 'UnknownDO'}'. Add static binding or ensure compiler binding registration is active.`);
103
111
  }
104
- console.log(`[rpc] ${binding}.${method}() — resolving stub...`);
112
+ if (__isDevMode())
113
+ console.log(`[rpc] ${binding}.${method}() — resolving stub...`);
105
114
  const stub = await __getDoStub(binding);
106
115
  if (!stub) {
107
116
  throw new Error(`[KuratchiJS] Not authenticated — cannot call '${method}' on ${binding}`);
108
117
  }
109
- console.log(`[rpc] ${binding}.${method}() — stub type: ${stub?.constructor?.name ?? typeof stub}`);
110
- console.log(`[rpc] ${binding}.${method}() — calling with ${args.length} arg(s)...`);
118
+ if (__isDevMode()) {
119
+ console.log(`[rpc] ${binding}.${method}() — stub type: ${stub?.constructor?.name ?? typeof stub}`);
120
+ console.log(`[rpc] ${binding}.${method}() — calling with ${args.length} arg(s)...`);
121
+ }
111
122
  try {
112
123
  // Call method directly on the stub — DO NOT detach with stub[method]
113
124
  // then .apply(). Workers RPC stubs are Proxy-based; detaching breaks
114
125
  // the runtime's interception and causes DataCloneError trying to
115
126
  // serialize the DurableObject as `this`.
116
127
  const result = await stub[method](...args);
117
- console.log(`[rpc] ${binding}.${method}() — returned, result type: ${typeof result}`);
128
+ if (__isDevMode())
129
+ console.log(`[rpc] ${binding}.${method}() — returned, result type: ${typeof result}`);
118
130
  return result;
119
131
  }
120
132
  catch (err) {
121
- console.error(`[rpc] ${binding}.${method}() — THREW: ${err.message}`);
133
+ if (__isDevMode())
134
+ console.error(`[rpc] ${binding}.${method}() — THREW: ${err.message}`);
122
135
  throw err;
123
136
  }
124
137
  };
125
138
  },
126
139
  });
140
+ _rpcProxyCache.set(klass, proxy);
141
+ return proxy;
127
142
  }
128
143
  }
129
144
  /**
@@ -0,0 +1,55 @@
1
+ import type { PageRenderOutput, RuntimeContext, RuntimeDefinition } from './types.js';
2
+ export interface GeneratedAssetEntry {
3
+ content: string;
4
+ mime: string;
5
+ etag: string;
6
+ }
7
+ export interface GeneratedApiRoute {
8
+ pattern: string;
9
+ __api: true;
10
+ [method: string]: unknown;
11
+ }
12
+ export interface GeneratedPageRoute {
13
+ pattern: string;
14
+ load?: (params: Record<string, string>) => Promise<unknown> | unknown;
15
+ actions?: Record<string, (...args: any[]) => Promise<unknown> | unknown>;
16
+ rpc?: Record<string, (...args: any[]) => Promise<unknown> | unknown>;
17
+ /** Allowed query function names for this route (for query override validation) */
18
+ allowedQueries?: string[];
19
+ render: (data: Record<string, any>) => PageRenderOutput;
20
+ }
21
+ export interface SecurityOptions {
22
+ /** Enable CSRF protection (default: true) */
23
+ csrfEnabled?: boolean;
24
+ /** CSRF cookie name (default: '__kuratchi_csrf') */
25
+ csrfCookieName?: string;
26
+ /** CSRF header name (default: 'x-kuratchi-csrf') */
27
+ csrfHeaderName?: string;
28
+ /** Require authentication for RPC (default: false) */
29
+ rpcRequireAuth?: boolean;
30
+ /** Require authentication for form actions (default: false) */
31
+ actionRequireAuth?: boolean;
32
+ /** Content Security Policy directive string */
33
+ contentSecurityPolicy?: string | null;
34
+ /** Strict-Transport-Security header value */
35
+ strictTransportSecurity?: string | null;
36
+ /** Permissions-Policy header value */
37
+ permissionsPolicy?: string | null;
38
+ }
39
+ export interface GeneratedWorkerOptions {
40
+ routes: Array<GeneratedPageRoute | GeneratedApiRoute>;
41
+ layout: (content: string, head?: string) => Promise<string> | string;
42
+ layoutActions: Record<string, (...args: any[]) => Promise<unknown> | unknown>;
43
+ assetsPrefix: string;
44
+ assets: Record<string, GeneratedAssetEntry>;
45
+ errorPages: Record<number, (detail?: string) => string>;
46
+ runtimeDefinition?: RuntimeDefinition;
47
+ workflowStatusRpc?: Record<string, (instanceId: string) => Promise<unknown>>;
48
+ initializeRequest?: (ctx: RuntimeContext) => Promise<void> | void;
49
+ preRouteChecks?: (ctx: RuntimeContext) => Promise<Response | null | undefined> | Response | null | undefined;
50
+ /** Security configuration */
51
+ security?: SecurityOptions;
52
+ }
53
+ export declare function createGeneratedWorker(opts: GeneratedWorkerOptions): {
54
+ fetch(request: Request, env: Record<string, any>, ctx: ExecutionContext): Promise<Response>;
55
+ };