@kuratchi/js 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.
- package/README.md +29 -0
- package/dist/cli.d.ts +5 -0
- package/dist/cli.js +78 -0
- package/dist/compiler/index.d.ts +34 -0
- package/dist/compiler/index.js +2200 -0
- package/dist/compiler/parser.d.ts +40 -0
- package/dist/compiler/parser.js +534 -0
- package/dist/compiler/template.d.ts +30 -0
- package/dist/compiler/template.js +625 -0
- package/dist/create.d.ts +7 -0
- package/dist/create.js +876 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +15 -0
- package/dist/runtime/app.d.ts +12 -0
- package/dist/runtime/app.js +118 -0
- package/dist/runtime/config.d.ts +5 -0
- package/dist/runtime/config.js +6 -0
- package/dist/runtime/containers.d.ts +61 -0
- package/dist/runtime/containers.js +127 -0
- package/dist/runtime/context.d.ts +54 -0
- package/dist/runtime/context.js +134 -0
- package/dist/runtime/do.d.ts +81 -0
- package/dist/runtime/do.js +123 -0
- package/dist/runtime/index.d.ts +8 -0
- package/dist/runtime/index.js +8 -0
- package/dist/runtime/router.d.ts +29 -0
- package/dist/runtime/router.js +73 -0
- package/dist/runtime/types.d.ts +207 -0
- package/dist/runtime/types.js +4 -0
- package/package.json +50 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KuratchiJS — Durable Object helpers
|
|
3
|
+
*
|
|
4
|
+
* kuratchiDO
|
|
5
|
+
* Base class for DO handler modules. Extend it, write your methods,
|
|
6
|
+
* declare `static binding = 'BINDING_NAME'` — the compiler does the rest.
|
|
7
|
+
*
|
|
8
|
+
* - Methods are copied onto the generated DO class prototype
|
|
9
|
+
* - RPC proxy exports are auto-generated for pages
|
|
10
|
+
* - Stub resolvers are registered from config
|
|
11
|
+
*
|
|
12
|
+
* The compiler uses __registerDoResolver / __getDoStub internally.
|
|
13
|
+
* User code never touches these — they're wired up from kuratchi.config.ts.
|
|
14
|
+
*/
|
|
15
|
+
// ── Internal: stub resolver registry ────────────────────────
|
|
16
|
+
const _resolvers = new Map();
|
|
17
|
+
const _classBindings = new WeakMap();
|
|
18
|
+
/** @internal — called by compiler-generated init code */
|
|
19
|
+
export function __registerDoResolver(binding, resolver) {
|
|
20
|
+
_resolvers.set(binding, resolver);
|
|
21
|
+
}
|
|
22
|
+
/** @internal — called by compiler-generated init code */
|
|
23
|
+
export function __registerDoClassBinding(klass, binding) {
|
|
24
|
+
if (!klass || !binding)
|
|
25
|
+
return;
|
|
26
|
+
_classBindings.set(klass, binding);
|
|
27
|
+
}
|
|
28
|
+
/** @internal — called by compiler-generated RPC proxy modules */
|
|
29
|
+
export async function __getDoStub(binding) {
|
|
30
|
+
const resolver = _resolvers.get(binding);
|
|
31
|
+
if (!resolver) {
|
|
32
|
+
throw new Error(`[KuratchiJS] No DO resolver registered for binding '${binding}'. Check your durableObjects config.`);
|
|
33
|
+
}
|
|
34
|
+
return resolver();
|
|
35
|
+
}
|
|
36
|
+
// ── kuratchiDO base class ──────────────────────────────────────
|
|
37
|
+
/**
|
|
38
|
+
* Base class for Durable Object handler modules.
|
|
39
|
+
*
|
|
40
|
+
* ```ts
|
|
41
|
+
* // sites.ts — extend, write methods, done.
|
|
42
|
+
* export default class Sites extends kuratchiDO {
|
|
43
|
+
* static binding = 'ORG_DB';
|
|
44
|
+
*
|
|
45
|
+
* async getSites(userId: number) {
|
|
46
|
+
* return (await this.db.sites.where({ userId }).many()).data ?? [];
|
|
47
|
+
* }
|
|
48
|
+
* }
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* `this.db` is the ORM instance — set by the generated DO class at runtime.
|
|
52
|
+
*
|
|
53
|
+
* Call `Sites.rpc()` in the same file if you need to call DO methods
|
|
54
|
+
* from worker-side helper functions:
|
|
55
|
+
*
|
|
56
|
+
* ```ts
|
|
57
|
+
* const remote = Sites.rpc();
|
|
58
|
+
*
|
|
59
|
+
* export async function createSite(formData: FormData) {
|
|
60
|
+
* await remote.createSiteRecord({ name, slug, userId });
|
|
61
|
+
* }
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export class kuratchiDO {
|
|
65
|
+
/** The DO namespace binding this handler belongs to (e.g. 'ORG_DB'). */
|
|
66
|
+
static binding;
|
|
67
|
+
/**
|
|
68
|
+
* Implicit RPC proxy getter.
|
|
69
|
+
*
|
|
70
|
+
* Lets handler modules call `MyDO.remote.someMethod()` without declaring
|
|
71
|
+
* `const remote = MyDO.rpc();` boilerplate.
|
|
72
|
+
*/
|
|
73
|
+
static get remote() {
|
|
74
|
+
return this.rpc();
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Create a typed RPC proxy for calling DO methods from worker-side code.
|
|
78
|
+
* The actual stub resolution is lazy — happens at call time, not import time.
|
|
79
|
+
*/
|
|
80
|
+
static rpc() {
|
|
81
|
+
const klass = this;
|
|
82
|
+
return new Proxy({}, {
|
|
83
|
+
get(_, method) {
|
|
84
|
+
return async (...args) => {
|
|
85
|
+
const binding = this.binding || _classBindings.get(klass);
|
|
86
|
+
if (!binding) {
|
|
87
|
+
throw new Error(`[KuratchiJS] Missing DO binding for class '${this?.name || 'UnknownDO'}'. Add static binding or ensure compiler binding registration is active.`);
|
|
88
|
+
}
|
|
89
|
+
console.log(`[rpc] ${binding}.${method}() — resolving stub...`);
|
|
90
|
+
const stub = await __getDoStub(binding);
|
|
91
|
+
if (!stub) {
|
|
92
|
+
throw new Error(`[KuratchiJS] Not authenticated — cannot call '${method}' on ${binding}`);
|
|
93
|
+
}
|
|
94
|
+
console.log(`[rpc] ${binding}.${method}() — stub type: ${stub?.constructor?.name ?? typeof stub}`);
|
|
95
|
+
console.log(`[rpc] ${binding}.${method}() — calling with ${args.length} arg(s)...`);
|
|
96
|
+
try {
|
|
97
|
+
// Call method directly on the stub — DO NOT detach with stub[method]
|
|
98
|
+
// then .apply(). Workers RPC stubs are Proxy-based; detaching breaks
|
|
99
|
+
// the runtime's interception and causes DataCloneError trying to
|
|
100
|
+
// serialize the DurableObject as `this`.
|
|
101
|
+
const result = await stub[method](...args);
|
|
102
|
+
console.log(`[rpc] ${binding}.${method}() — returned, result type: ${typeof result}`);
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
console.error(`[rpc] ${binding}.${method}() — THREW: ${err.message}`);
|
|
107
|
+
throw err;
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* DX helper for worker-side code in DO handler modules.
|
|
116
|
+
*
|
|
117
|
+
* Usage:
|
|
118
|
+
* `const doSites = doRpc(Sites);`
|
|
119
|
+
* `await doSites.getSiteBySlug(slug);`
|
|
120
|
+
*/
|
|
121
|
+
export function doRpc(klass) {
|
|
122
|
+
return klass.rpc();
|
|
123
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { createApp } from './app.js';
|
|
2
|
+
export { defineConfig } from './config.js';
|
|
3
|
+
export { Router, filePathToPattern } from './router.js';
|
|
4
|
+
export { getEnv, getCtx, getRequest, getLocals, getParams, getParam, redirect, goto, setBreadcrumbs, getBreadcrumbs, breadcrumbsHome, breadcrumbsPrev, breadcrumbsNext, breadcrumbsCurrent, buildDefaultBreadcrumbs, } from './context.js';
|
|
5
|
+
export { kuratchiDO, doRpc } from './do.js';
|
|
6
|
+
export { extractSubdomainSlug, extractSlugFromPrefix, matchContainerViewPath, rewriteProxyLocationHeader, buildContainerRequest, createContainerEnvVars, startContainer, proxyToContainer, handleContainerRouting, forwardJsonPostToContainerDO, matchSiteViewPath, buildSiteContainerRequest, createWpContainerEnvVars, startSiteContainer, proxyToSiteContainer, } from './containers.js';
|
|
7
|
+
export type { AppConfig, Env, AuthConfig, RouteContext, RouteModule, LayoutModule } from './types.js';
|
|
8
|
+
export type { RpcOf } from './do.js';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { createApp } from './app.js';
|
|
2
|
+
export { defineConfig } from './config.js';
|
|
3
|
+
export { Router, filePathToPattern } from './router.js';
|
|
4
|
+
export { getEnv, getCtx, getRequest, getLocals, getParams, getParam, redirect, goto, setBreadcrumbs, getBreadcrumbs, breadcrumbsHome, breadcrumbsPrev, breadcrumbsNext, breadcrumbsCurrent, buildDefaultBreadcrumbs, } from './context.js';
|
|
5
|
+
export { kuratchiDO, doRpc } from './do.js';
|
|
6
|
+
export { extractSubdomainSlug, extractSlugFromPrefix, matchContainerViewPath, rewriteProxyLocationHeader, buildContainerRequest, createContainerEnvVars, startContainer, proxyToContainer, handleContainerRouting, forwardJsonPostToContainerDO,
|
|
7
|
+
// Compatibility aliases
|
|
8
|
+
matchSiteViewPath, buildSiteContainerRequest, createWpContainerEnvVars, startSiteContainer, proxyToSiteContainer, } from './containers.js';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URL router — matches incoming requests to route modules.
|
|
3
|
+
*
|
|
4
|
+
* Supports:
|
|
5
|
+
* /todos → static
|
|
6
|
+
* /blog/:slug → named param
|
|
7
|
+
* /files/*rest → catch-all
|
|
8
|
+
*/
|
|
9
|
+
export interface MatchResult {
|
|
10
|
+
params: Record<string, string>;
|
|
11
|
+
index: number;
|
|
12
|
+
}
|
|
13
|
+
export declare class Router {
|
|
14
|
+
private routes;
|
|
15
|
+
/** Register a pattern (e.g. '/blog/:slug') and associate it with an index. */
|
|
16
|
+
add(pattern: string, index: number): void;
|
|
17
|
+
/** Match a pathname against registered routes. Returns null if no match. */
|
|
18
|
+
match(pathname: string): MatchResult | null;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Convert a file-system path to a route pattern.
|
|
22
|
+
*
|
|
23
|
+
* Examples:
|
|
24
|
+
* 'index' → '/'
|
|
25
|
+
* 'about' → '/about'
|
|
26
|
+
* 'blog/[slug]' → '/blog/:slug'
|
|
27
|
+
* 'files/[...path]' → '/files/*path'
|
|
28
|
+
*/
|
|
29
|
+
export declare function filePathToPattern(filePath: string): string;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URL router — matches incoming requests to route modules.
|
|
3
|
+
*
|
|
4
|
+
* Supports:
|
|
5
|
+
* /todos → static
|
|
6
|
+
* /blog/:slug → named param
|
|
7
|
+
* /files/*rest → catch-all
|
|
8
|
+
*/
|
|
9
|
+
export class Router {
|
|
10
|
+
routes = [];
|
|
11
|
+
/** Register a pattern (e.g. '/blog/:slug') and associate it with an index. */
|
|
12
|
+
add(pattern, index) {
|
|
13
|
+
const paramNames = [];
|
|
14
|
+
// Convert pattern to regex
|
|
15
|
+
// :param → named capture group
|
|
16
|
+
// *param → catch-all capture group
|
|
17
|
+
let regexStr = pattern
|
|
18
|
+
// Catch-all: /files/*rest → /files/(?<rest>.+)
|
|
19
|
+
.replace(/\*(\w+)/g, (_match, name) => {
|
|
20
|
+
paramNames.push(name);
|
|
21
|
+
return `(?<${name}>.+)`;
|
|
22
|
+
})
|
|
23
|
+
// Named params: /blog/:slug → /blog/(?<slug>[^/]+)
|
|
24
|
+
.replace(/:(\w+)/g, (_match, name) => {
|
|
25
|
+
paramNames.push(name);
|
|
26
|
+
return `(?<${name}>[^/]+)`;
|
|
27
|
+
});
|
|
28
|
+
// Anchor
|
|
29
|
+
regexStr = `^${regexStr}$`;
|
|
30
|
+
this.routes.push({
|
|
31
|
+
regex: new RegExp(regexStr),
|
|
32
|
+
paramNames,
|
|
33
|
+
index,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/** Match a pathname against registered routes. Returns null if no match. */
|
|
37
|
+
match(pathname) {
|
|
38
|
+
// Normalize: strip trailing slash (except root)
|
|
39
|
+
const normalized = pathname === '/' ? '/' : pathname.replace(/\/$/, '');
|
|
40
|
+
for (const route of this.routes) {
|
|
41
|
+
const m = normalized.match(route.regex);
|
|
42
|
+
if (m) {
|
|
43
|
+
const params = {};
|
|
44
|
+
for (const name of route.paramNames) {
|
|
45
|
+
params[name] = m.groups?.[name] ?? '';
|
|
46
|
+
}
|
|
47
|
+
return { params, index: route.index };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Convert a file-system path to a route pattern.
|
|
55
|
+
*
|
|
56
|
+
* Examples:
|
|
57
|
+
* 'index' → '/'
|
|
58
|
+
* 'about' → '/about'
|
|
59
|
+
* 'blog/[slug]' → '/blog/:slug'
|
|
60
|
+
* 'files/[...path]' → '/files/*path'
|
|
61
|
+
*/
|
|
62
|
+
export function filePathToPattern(filePath) {
|
|
63
|
+
if (filePath === 'index')
|
|
64
|
+
return '/';
|
|
65
|
+
let pattern = '/' + filePath
|
|
66
|
+
// [...param] → *param (catch-all)
|
|
67
|
+
.replace(/\[\.\.\.(\w+)\]/g, '*$1')
|
|
68
|
+
// [param] → :param
|
|
69
|
+
.replace(/\[(\w+)\]/g, ':$1');
|
|
70
|
+
// Remove trailing /index
|
|
71
|
+
pattern = pattern.replace(/\/index$/, '') || '/';
|
|
72
|
+
return pattern;
|
|
73
|
+
}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core framework types
|
|
3
|
+
*/
|
|
4
|
+
/** Cloudflare Worker env — consumers define their own Env type */
|
|
5
|
+
export type Env = Record<string, any>;
|
|
6
|
+
/** Route context — passed to load functions, actions, and server utilities */
|
|
7
|
+
export interface RouteContext<E extends Env = Env> {
|
|
8
|
+
/** The incoming Request (standard Web API) */
|
|
9
|
+
request: Request;
|
|
10
|
+
/** Cloudflare Worker env — D1, KV, R2, DO, AI, etc. */
|
|
11
|
+
env: E;
|
|
12
|
+
/** Cloudflare execution context */
|
|
13
|
+
ctx: ExecutionContext;
|
|
14
|
+
/** Route parameters (e.g., { slug: 'hello-world' }) */
|
|
15
|
+
params: Record<string, string>;
|
|
16
|
+
/** Request-scoped state (set by middleware, read by load/actions) */
|
|
17
|
+
locals: Record<string, any>;
|
|
18
|
+
/** Parsed URL */
|
|
19
|
+
url: URL;
|
|
20
|
+
}
|
|
21
|
+
/** A compiled route module */
|
|
22
|
+
export interface RouteModule {
|
|
23
|
+
/** Pattern string (e.g., '/todos', '/blog/:slug') */
|
|
24
|
+
pattern: string;
|
|
25
|
+
/** Load function — runs on GET, returns data for the template */
|
|
26
|
+
load?: (ctx: RouteContext) => Promise<Record<string, any>> | Record<string, any>;
|
|
27
|
+
/** Form actions — keyed by action name */
|
|
28
|
+
actions?: Record<string, (formData: FormData, env: Env, ctx: RouteContext) => Promise<any>>;
|
|
29
|
+
/** RPC functions — callable from client via fetch */
|
|
30
|
+
rpc?: Record<string, (args: any[], env: Env, ctx: RouteContext) => Promise<any>>;
|
|
31
|
+
/** Render function — returns HTML string from data */
|
|
32
|
+
render: (data: Record<string, any>) => string;
|
|
33
|
+
/** Layout name (default: 'default') */
|
|
34
|
+
layout?: string;
|
|
35
|
+
}
|
|
36
|
+
/** Layout module */
|
|
37
|
+
export interface LayoutModule {
|
|
38
|
+
/** Render function — wraps page content */
|
|
39
|
+
render: (data: {
|
|
40
|
+
content: string;
|
|
41
|
+
data: Record<string, any>;
|
|
42
|
+
head?: string;
|
|
43
|
+
}) => string;
|
|
44
|
+
}
|
|
45
|
+
/** App configuration (internal — used by compiler-generated code) */
|
|
46
|
+
export interface AppConfig<E extends Env = Env> {
|
|
47
|
+
/** Route modules — generated by compiler or defined manually */
|
|
48
|
+
routes?: RouteModule[];
|
|
49
|
+
/** Layout modules — keyed by name */
|
|
50
|
+
layouts?: Record<string, LayoutModule>;
|
|
51
|
+
/** Static file directory (relative to project root) */
|
|
52
|
+
publicDir?: string;
|
|
53
|
+
}
|
|
54
|
+
/** Database schema config — maps a binding name to its schema */
|
|
55
|
+
export interface DatabaseConfig {
|
|
56
|
+
/** Schema definition (SchemaDsl or DatabaseSchema from @kuratchi/orm) */
|
|
57
|
+
schema: any;
|
|
58
|
+
/** Storage type: 'd1' (default) or 'do' (Durable Object SqlStorage) */
|
|
59
|
+
type?: 'd1' | 'do';
|
|
60
|
+
/** Skip migrations for this database (e.g., in production). Default: false */
|
|
61
|
+
skipMigrations?: boolean;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Framework configuration — the user-facing config file (kuratchi.config.ts)
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* // kuratchi.config.ts
|
|
69
|
+
* import { defineConfig } from '@kuratchi/js';
|
|
70
|
+
* import { todoSchema } from './src/schemas/todo';
|
|
71
|
+
*
|
|
72
|
+
* export default defineConfig({
|
|
73
|
+
* orm: {
|
|
74
|
+
* databases: {
|
|
75
|
+
* DB: { schema: todoSchema }
|
|
76
|
+
* }
|
|
77
|
+
* }
|
|
78
|
+
* });
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export interface kuratchiConfig<E extends Env = Env> {
|
|
82
|
+
/** ORM configuration — schema definitions and auto-migration */
|
|
83
|
+
orm?: {
|
|
84
|
+
/** Map of D1 binding names to their database configs */
|
|
85
|
+
databases: Record<string, DatabaseConfig>;
|
|
86
|
+
};
|
|
87
|
+
/** UI configuration — opt into @kuratchi/ui theme and components */
|
|
88
|
+
ui?: {
|
|
89
|
+
/** Theme to inject: 'default' uses @kuratchi/ui's built-in theme, or a path to a custom CSS file */
|
|
90
|
+
theme?: 'default' | string;
|
|
91
|
+
};
|
|
92
|
+
/** Auth configuration — @kuratchi/auth plugin setup */
|
|
93
|
+
auth?: AuthConfig;
|
|
94
|
+
/**
|
|
95
|
+
* Durable Object configuration — config-driven DO class generation.
|
|
96
|
+
*
|
|
97
|
+
* Map a DO namespace binding to its class name and optional configuration.
|
|
98
|
+
* Supports string shorthand or an object with stubId option.
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```ts
|
|
102
|
+
* durableObjects: {
|
|
103
|
+
* // Object form — stubId tells the framework which user field identifies the stub
|
|
104
|
+
* ORG_DB: {
|
|
105
|
+
* className: 'OrganizationDO',
|
|
106
|
+
* stubId: 'user.orgId'
|
|
107
|
+
* },
|
|
108
|
+
* // String shorthand — className only, no auto-stub resolution
|
|
109
|
+
* CACHE_DB: 'CacheDO'
|
|
110
|
+
* }
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
durableObjects?: Record<string, string | {
|
|
114
|
+
className: string;
|
|
115
|
+
/** The user field path that identifies the DO stub (e.g. 'user.orgId') */
|
|
116
|
+
stubId?: string;
|
|
117
|
+
}>;
|
|
118
|
+
}
|
|
119
|
+
/** Auth configuration for kuratchi.config.ts */
|
|
120
|
+
export interface AuthConfig {
|
|
121
|
+
/** Session cookie name (default: 'kuratchi_session') */
|
|
122
|
+
cookieName?: string;
|
|
123
|
+
/** Auth secret env binding name (default: 'AUTH_SECRET') */
|
|
124
|
+
secretEnvKey?: string;
|
|
125
|
+
/** Enable session parsing on every request (default: true) */
|
|
126
|
+
sessionEnabled?: boolean;
|
|
127
|
+
/** Credentials config — enables signUp/signIn/signOut/getCurrentUser */
|
|
128
|
+
credentials?: {
|
|
129
|
+
/** D1 binding name for auth database (default: 'DB') */
|
|
130
|
+
binding?: string;
|
|
131
|
+
/** Default role for new users (default: 'user') */
|
|
132
|
+
defaultRole?: string;
|
|
133
|
+
/** Session duration in ms (default: 30 days) */
|
|
134
|
+
sessionDuration?: number;
|
|
135
|
+
/** Min password length (default: 8) */
|
|
136
|
+
minPasswordLength?: number;
|
|
137
|
+
/** Redirect after signup (default: '/auth/login') */
|
|
138
|
+
signUpRedirect?: string;
|
|
139
|
+
/** Redirect after signin (default: '/admin') */
|
|
140
|
+
signInRedirect?: string;
|
|
141
|
+
/** Redirect after signout (default: '/auth/login') */
|
|
142
|
+
signOutRedirect?: string;
|
|
143
|
+
};
|
|
144
|
+
/** Activity tracking config — enables logActivity/getActivity */
|
|
145
|
+
activity?: Record<string, {
|
|
146
|
+
label: string;
|
|
147
|
+
severity?: 'info' | 'warning' | 'critical';
|
|
148
|
+
category?: string;
|
|
149
|
+
}>;
|
|
150
|
+
/** Role definitions — enables hasRole/hasPermission/assignRole */
|
|
151
|
+
roles?: Record<string, string[]>;
|
|
152
|
+
/** OAuth providers config — enables startOAuth/handleOAuthCallback */
|
|
153
|
+
oauth?: {
|
|
154
|
+
providers?: Record<string, {
|
|
155
|
+
clientIdEnv: string;
|
|
156
|
+
clientSecretEnv: string;
|
|
157
|
+
scopes?: string[];
|
|
158
|
+
}>;
|
|
159
|
+
/** Redirect after OAuth login (default: '/admin') */
|
|
160
|
+
loginRedirect?: string;
|
|
161
|
+
};
|
|
162
|
+
/** Route guards — protect paths, redirect if not authenticated */
|
|
163
|
+
guards?: {
|
|
164
|
+
paths?: string[];
|
|
165
|
+
exclude?: string[];
|
|
166
|
+
redirectTo?: string;
|
|
167
|
+
};
|
|
168
|
+
/** Rate limiting — throttle requests per route */
|
|
169
|
+
rateLimit?: {
|
|
170
|
+
defaultWindowMs?: number;
|
|
171
|
+
defaultMaxRequests?: number;
|
|
172
|
+
kvBinding?: string;
|
|
173
|
+
keyPrefix?: string;
|
|
174
|
+
routes?: {
|
|
175
|
+
id?: string;
|
|
176
|
+
path: string;
|
|
177
|
+
methods?: string[];
|
|
178
|
+
maxRequests?: number;
|
|
179
|
+
windowMs?: number;
|
|
180
|
+
message?: string;
|
|
181
|
+
}[];
|
|
182
|
+
};
|
|
183
|
+
/** Turnstile bot protection — verify Cloudflare Turnstile tokens */
|
|
184
|
+
turnstile?: {
|
|
185
|
+
/** Env var name for Turnstile secret key (default: 'TURNSTILE_SECRET') */
|
|
186
|
+
secretEnv?: string;
|
|
187
|
+
/** Env var name for Turnstile site key (default: 'TURNSTILE_SITE_KEY') — exposed to client */
|
|
188
|
+
siteKeyEnv?: string;
|
|
189
|
+
/** Skip Turnstile verification in dev mode (default: true) */
|
|
190
|
+
skipInDev?: boolean;
|
|
191
|
+
/** Routes that require Turnstile verification */
|
|
192
|
+
routes?: {
|
|
193
|
+
id?: string;
|
|
194
|
+
path: string;
|
|
195
|
+
methods?: string[];
|
|
196
|
+
tokenField?: string;
|
|
197
|
+
tokenHeader?: string;
|
|
198
|
+
message?: string;
|
|
199
|
+
expectedAction?: string;
|
|
200
|
+
}[];
|
|
201
|
+
};
|
|
202
|
+
/** Organization multi-tenancy — DO-backed per-org databases */
|
|
203
|
+
organizations?: {
|
|
204
|
+
/** DO namespace binding name in env (e.g. 'ORG_DB') */
|
|
205
|
+
binding: string;
|
|
206
|
+
};
|
|
207
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kuratchi/js",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "A thin, Cloudflare Workers-native web framework with Svelte-inspired syntax",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"kuratchi": "./dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"README.md"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc -p tsconfig.build.json",
|
|
17
|
+
"check": "tsc -p tsconfig.build.json --noEmit",
|
|
18
|
+
"prepublishOnly": "npm run build"
|
|
19
|
+
},
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"import": "./dist/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./runtime/context.js": {
|
|
26
|
+
"types": "./dist/runtime/context.d.ts",
|
|
27
|
+
"import": "./dist/runtime/context.js"
|
|
28
|
+
},
|
|
29
|
+
"./runtime/do.js": {
|
|
30
|
+
"types": "./dist/runtime/do.d.ts",
|
|
31
|
+
"import": "./dist/runtime/do.js"
|
|
32
|
+
},
|
|
33
|
+
"./package.json": "./package.json"
|
|
34
|
+
},
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": "\u003e=18"
|
|
37
|
+
},
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@cloudflare/workers-types": "^4.20260223.0",
|
|
43
|
+
"@types/node": "^24.4.0",
|
|
44
|
+
"typescript": "^5.8.0"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|