@kuratchi/js 0.0.11 → 0.0.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/LICENSE +21 -0
- package/README.md +33 -0
- package/dist/compiler/index.js +25 -10
- package/dist/compiler/parser.js +15 -0
- package/package.json +5 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kuratchi contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -54,6 +54,7 @@ Kuratchi routes are server-first.
|
|
|
54
54
|
- Top-level route `<script>` blocks run on the server.
|
|
55
55
|
- Template expressions, `if`, and `for` blocks render on the server.
|
|
56
56
|
- `src/server` is for private server-only modules and reusable backend logic.
|
|
57
|
+
- `src/server/runtime.hook.ts` is the server runtime hook entrypoint for request interception.
|
|
57
58
|
- Reactive `$:` code is the browser-only escape hatch.
|
|
58
59
|
|
|
59
60
|
Route files are not client files. They are server-rendered routes that can opt into small browser-side reactive behavior when needed.
|
|
@@ -542,6 +543,38 @@ const postSlug = slug;
|
|
|
542
543
|
- `slug` is `params.slug` when the matched route defines a `slug` param.
|
|
543
544
|
- `headers`, `method`, and `params` are also exported from `@kuratchi/js/request`.
|
|
544
545
|
- Use `getRequest()` when you want the raw native `Request` object.
|
|
546
|
+
|
|
547
|
+
## Runtime Hook
|
|
548
|
+
|
|
549
|
+
Optional server runtime hook file. Export a `RuntimeDefinition` from `src/server/runtime.hook.ts`
|
|
550
|
+
to intercept requests before they reach the framework router. Use it for agent routing,
|
|
551
|
+
pre-route auth, or custom response/error handling.
|
|
552
|
+
|
|
553
|
+
```ts
|
|
554
|
+
import type { RuntimeDefinition } from '@kuratchi/js';
|
|
555
|
+
|
|
556
|
+
const runtime: RuntimeDefinition = {
|
|
557
|
+
agents: {
|
|
558
|
+
async request(ctx, next) {
|
|
559
|
+
if (!ctx.url.pathname.startsWith('/agents/')) {
|
|
560
|
+
return next();
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
return new Response('Agent response');
|
|
564
|
+
},
|
|
565
|
+
},
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
export default runtime;
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
`ctx` includes:
|
|
572
|
+
|
|
573
|
+
- `ctx.url` - parsed URL
|
|
574
|
+
- `ctx.request` - raw Request
|
|
575
|
+
- `ctx.env` - Cloudflare env bindings
|
|
576
|
+
- `next()` - pass control to the next handler
|
|
577
|
+
|
|
545
578
|
## Environment bindings
|
|
546
579
|
|
|
547
580
|
Cloudflare env is server-only.
|
package/dist/compiler/index.js
CHANGED
|
@@ -725,6 +725,8 @@ export function compile(options) {
|
|
|
725
725
|
// 500.html receives `error` as a variable; others don't need it
|
|
726
726
|
compiledErrorPages.set(status, `function __error_${status}(error) {\n ${body}\n return __html;\n}`);
|
|
727
727
|
}
|
|
728
|
+
// Read assets prefix from kuratchi.config.ts (default: /assets/)
|
|
729
|
+
const assetsPrefix = readAssetsPrefix(projectDir);
|
|
728
730
|
// Read kuratchi.config.ts at build time to discover ORM database configs
|
|
729
731
|
const ormDatabases = readOrmConfig(projectDir);
|
|
730
732
|
// Read auth config from kuratchi.config.ts
|
|
@@ -1262,6 +1264,7 @@ export function compile(options) {
|
|
|
1262
1264
|
compiledLayoutActions,
|
|
1263
1265
|
hasRuntime,
|
|
1264
1266
|
runtimeImportPath,
|
|
1267
|
+
assetsPrefix,
|
|
1265
1268
|
});
|
|
1266
1269
|
// Write to .kuratchi/routes.js
|
|
1267
1270
|
const outFile = options.outFile ?? path.join(projectDir, '.kuratchi', 'routes.js');
|
|
@@ -1668,7 +1671,9 @@ function buildRouteObject(opts) {
|
|
|
1668
1671
|
explicitLoadFunction = transpileTypeScript(explicitLoadFunction, `route-load:${pattern}.ts`);
|
|
1669
1672
|
}
|
|
1670
1673
|
const scriptReturnVars = parsed.script
|
|
1671
|
-
? parsed.dataVars.filter((v) => !queryVars.includes(v)
|
|
1674
|
+
? parsed.dataVars.filter((v) => !queryVars.includes(v) &&
|
|
1675
|
+
!parsed.actionFunctions.includes(v) &&
|
|
1676
|
+
!parsed.pollFunctions.includes(v))
|
|
1672
1677
|
: [];
|
|
1673
1678
|
// Load function �" internal server prepass for async route script bodies
|
|
1674
1679
|
// and data-get query state hydration.
|
|
@@ -2047,6 +2052,21 @@ function resolveClassExportFromFile(absPath, errorLabel) {
|
|
|
2047
2052
|
}
|
|
2048
2053
|
throw new Error(`[kuratchi] ${errorLabel} must export a class via "export class X" or "export default class X". File: ${absPath}`);
|
|
2049
2054
|
}
|
|
2055
|
+
function readAssetsPrefix(projectDir) {
|
|
2056
|
+
const configPath = path.join(projectDir, 'kuratchi.config.ts');
|
|
2057
|
+
if (!fs.existsSync(configPath))
|
|
2058
|
+
return '/assets/';
|
|
2059
|
+
const source = fs.readFileSync(configPath, 'utf-8');
|
|
2060
|
+
const match = source.match(/assetsPrefix\s*:\s*['"]([^'"]+)['"]/);
|
|
2061
|
+
if (!match)
|
|
2062
|
+
return '/assets/';
|
|
2063
|
+
let prefix = match[1];
|
|
2064
|
+
if (!prefix.startsWith('/'))
|
|
2065
|
+
prefix = '/' + prefix;
|
|
2066
|
+
if (!prefix.endsWith('/'))
|
|
2067
|
+
prefix += '/';
|
|
2068
|
+
return prefix;
|
|
2069
|
+
}
|
|
2050
2070
|
function discoverConventionClassFiles(projectDir, dir, suffix, errorLabel) {
|
|
2051
2071
|
const absDir = path.join(projectDir, dir);
|
|
2052
2072
|
const files = discoverFilesWithSuffix(absDir, suffix);
|
|
@@ -2941,9 +2961,9 @@ ${migrationInit ? ' await __runMigrations();\n' : ''}${authInit ? ' __init
|
|
|
2941
2961
|
const url = __runtimeCtx.url;
|
|
2942
2962
|
${ac?.hasRateLimit ? '\n // Rate limiting - check before route handlers\n { const __rlRes = await __checkRL(); if (__rlRes) return __secHeaders(__rlRes); }\n' : ''}${ac?.hasTurnstile ? ' // Turnstile bot protection\n { const __tsRes = await __checkTS(); if (__tsRes) return __secHeaders(__tsRes); }\n' : ''}${ac?.hasGuards ? ' // Route guards - redirect if not authenticated\n { const __gRes = __checkGuard(); if (__gRes) return __secHeaders(__gRes); }\n' : ''}
|
|
2943
2963
|
|
|
2944
|
-
// Serve static assets from src/assets/
|
|
2945
|
-
if (url.pathname.startsWith('
|
|
2946
|
-
const name = url.pathname.slice('
|
|
2964
|
+
// Serve static assets from src/assets/
|
|
2965
|
+
if (url.pathname.startsWith('${opts.assetsPrefix}')) {
|
|
2966
|
+
const name = url.pathname.slice('${opts.assetsPrefix}'.length);
|
|
2947
2967
|
const asset = __assets[name];
|
|
2948
2968
|
if (asset) {
|
|
2949
2969
|
if (request.headers.get('if-none-match') === asset.etag) {
|
|
@@ -3124,12 +3144,7 @@ ${ac?.hasRateLimit ? '\n // Rate limiting - check before route handlers\n
|
|
|
3124
3144
|
}
|
|
3125
3145
|
function resolveRuntimeImportPath(projectDir) {
|
|
3126
3146
|
const candidates = [
|
|
3127
|
-
{ file: 'src/
|
|
3128
|
-
{ file: 'src/kuratchi.runtime.js', importPath: '../src/kuratchi.runtime' },
|
|
3129
|
-
{ file: 'src/kuratchi.runtime.mjs', importPath: '../src/kuratchi.runtime' },
|
|
3130
|
-
{ file: 'kuratchi.runtime.ts', importPath: '../kuratchi.runtime' },
|
|
3131
|
-
{ file: 'kuratchi.runtime.js', importPath: '../kuratchi.runtime' },
|
|
3132
|
-
{ file: 'kuratchi.runtime.mjs', importPath: '../kuratchi.runtime' },
|
|
3147
|
+
{ file: 'src/server/runtime.hook.ts', importPath: '../src/server/runtime.hook' },
|
|
3133
3148
|
];
|
|
3134
3149
|
for (const candidate of candidates) {
|
|
3135
3150
|
if (fs.existsSync(path.join(projectDir, candidate.file))) {
|
package/dist/compiler/parser.js
CHANGED
|
@@ -770,6 +770,21 @@ export function parseFile(source, options = {}) {
|
|
|
770
770
|
if (!dataVars.includes(name))
|
|
771
771
|
dataVars.push(name);
|
|
772
772
|
}
|
|
773
|
+
// Server import named bindings are also data vars (available in templates)
|
|
774
|
+
for (const line of serverImports) {
|
|
775
|
+
const namesMatch = line.match(/import\s*\{([^}]+)\}/);
|
|
776
|
+
if (!namesMatch)
|
|
777
|
+
continue;
|
|
778
|
+
for (const part of namesMatch[1].split(',')) {
|
|
779
|
+
const trimmed = part.trim();
|
|
780
|
+
if (!trimmed)
|
|
781
|
+
continue;
|
|
782
|
+
const segments = trimmed.split(/\s+as\s+/);
|
|
783
|
+
const localName = (segments[1] || segments[0]).trim();
|
|
784
|
+
if (localName && !dataVars.includes(localName))
|
|
785
|
+
dataVars.push(localName);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
773
788
|
}
|
|
774
789
|
const hasLoad = scriptBody.length > 0 || !!loadFunction;
|
|
775
790
|
// Strip HTML comments from the template before scanning for action references.
|
package/package.json
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kuratchi/js",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.13",
|
|
4
4
|
"description": "A thin, Cloudflare Workers-native web framework with Svelte-inspired syntax",
|
|
5
|
+
"license": "MIT",
|
|
5
6
|
"type": "module",
|
|
6
7
|
"main": "./dist/index.js",
|
|
7
8
|
"types": "./dist/index.d.ts",
|
|
8
9
|
"bin": {
|
|
9
|
-
"kuratchi": "
|
|
10
|
+
"kuratchi": "dist/cli.js"
|
|
10
11
|
},
|
|
11
12
|
"files": [
|
|
12
13
|
"dist",
|
|
13
|
-
"README.md"
|
|
14
|
+
"README.md",
|
|
15
|
+
"LICENSE"
|
|
14
16
|
],
|
|
15
17
|
"scripts": {
|
|
16
18
|
"build": "tsc -p tsconfig.build.json",
|