@kuratchi/js 0.0.2 → 0.0.4

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.
@@ -13,6 +13,21 @@
13
13
  * User code never touches these — they're wired up from kuratchi.config.ts.
14
14
  */
15
15
  // ── Internal: stub resolver registry ────────────────────────
16
+ let __doSelf = null;
17
+ /** @internal — called by compiler-generated method wrappers */
18
+ export function __setDoContext(self) {
19
+ __doSelf = self;
20
+ }
21
+ /** Get the DO's ORM database instance */
22
+ export function getDb() {
23
+ if (!__doSelf)
24
+ throw new Error('getDb() called outside of a DO context');
25
+ return __doSelf.db;
26
+ }
27
+ /** @internal — read by context.ts getCtx()/getEnv() */
28
+ export function __getDoSelf() {
29
+ return __doSelf;
30
+ }
16
31
  const _resolvers = new Map();
17
32
  const _classBindings = new WeakMap();
18
33
  /** @internal — called by compiler-generated init code */
@@ -1,8 +1,9 @@
1
1
  export { createApp } from './app.js';
2
2
  export { defineConfig } from './config.js';
3
+ export { defineRuntime } from './runtime.js';
3
4
  export { Router, filePathToPattern } from './router.js';
4
5
  export { getCtx, getRequest, getLocals, getParams, getParam, redirect, goto, setBreadcrumbs, getBreadcrumbs, breadcrumbsHome, breadcrumbsPrev, breadcrumbsNext, breadcrumbsCurrent, buildDefaultBreadcrumbs, } from './context.js';
5
6
  export { kuratchiDO, doRpc } from './do.js';
6
7
  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 { AppConfig, Env, AuthConfig, RouteContext, RouteModule, ApiRouteModule, HttpMethod, LayoutModule, RuntimeContext, RuntimeDefinition, RuntimeStep, RuntimeNext, RuntimeErrorResult, } from './types.js';
8
9
  export type { RpcOf } from './do.js';
@@ -1,5 +1,6 @@
1
1
  export { createApp } from './app.js';
2
2
  export { defineConfig } from './config.js';
3
+ export { defineRuntime } from './runtime.js';
3
4
  export { Router, filePathToPattern } from './router.js';
4
5
  export { getCtx, getRequest, getLocals, getParams, getParam, redirect, goto, setBreadcrumbs, getBreadcrumbs, breadcrumbsHome, breadcrumbsPrev, breadcrumbsNext, breadcrumbsCurrent, buildDefaultBreadcrumbs, } from './context.js';
5
6
  export { kuratchiDO, doRpc } from './do.js';
@@ -0,0 +1,16 @@
1
+ /**
2
+ * PageError — throw from a route's load scope to return a specific HTTP status page.
3
+ *
4
+ * Without PageError, any thrown error becomes a 500. PageError lets you return
5
+ * the correct HTTP status (404, 403, 401, etc.) and an optional message.
6
+ *
7
+ * @example
8
+ * const post = await db.posts.findOne({ id: params.id });
9
+ * if (!post) throw new PageError(404);
10
+ * if (!post.isPublished) throw new PageError(403, 'This post is not published');
11
+ */
12
+ export declare class PageError extends Error {
13
+ readonly isPageError = true;
14
+ readonly status: number;
15
+ constructor(status: number, message?: string);
16
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * PageError — throw from a route's load scope to return a specific HTTP status page.
3
+ *
4
+ * Without PageError, any thrown error becomes a 500. PageError lets you return
5
+ * the correct HTTP status (404, 403, 401, etc.) and an optional message.
6
+ *
7
+ * @example
8
+ * const post = await db.posts.findOne({ id: params.id });
9
+ * if (!post) throw new PageError(404);
10
+ * if (!post.isPublished) throw new PageError(403, 'This post is not published');
11
+ */
12
+ export class PageError extends Error {
13
+ isPageError = true;
14
+ status;
15
+ constructor(status, message) {
16
+ super(message);
17
+ this.name = 'PageError';
18
+ this.status = status;
19
+ }
20
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Runtime extension system
3
+ */
4
+ import type { Env, RuntimeDefinition } from './types.js';
5
+ export declare function defineRuntime<E extends Env = Env>(runtime: RuntimeDefinition<E>): RuntimeDefinition<E>;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Runtime extension system
3
+ */
4
+ export function defineRuntime(runtime) {
5
+ return runtime;
6
+ }
@@ -1,13 +1,13 @@
1
1
  /**
2
2
  * Core framework types
3
3
  */
4
- /** Cloudflare Worker env — consumers define their own Env type */
4
+ /** Cloudflare Worker env â€" consumers define their own Env type */
5
5
  export type Env = Record<string, any>;
6
- /** Route context — passed to load functions, actions, and server utilities */
6
+ /** Route context â€" passed to load functions, actions, and server utilities */
7
7
  export interface RouteContext<E extends Env = Env> {
8
8
  /** The incoming Request (standard Web API) */
9
9
  request: Request;
10
- /** Cloudflare Worker env — D1, KV, R2, DO, AI, etc. */
10
+ /** Cloudflare Worker env â€" D1, KV, R2, DO, AI, etc. */
11
11
  env: E;
12
12
  /** Cloudflare execution context */
13
13
  ctx: ExecutionContext;
@@ -22,36 +22,47 @@ export interface RouteContext<E extends Env = Env> {
22
22
  export interface RouteModule {
23
23
  /** Pattern string (e.g., '/todos', '/blog/:slug') */
24
24
  pattern: string;
25
- /** Load function — runs on GET, returns data for the template */
25
+ /** Load function â€" runs on GET, returns data for the template */
26
26
  load?: (ctx: RouteContext) => Promise<Record<string, any>> | Record<string, any>;
27
- /** Form actions — keyed by action name */
27
+ /** Form actions â€" keyed by action name */
28
28
  actions?: Record<string, (formData: FormData, env: Env, ctx: RouteContext) => Promise<any>>;
29
- /** RPC functions — callable from client via fetch */
29
+ /** RPC functions â€" callable from client via fetch */
30
30
  rpc?: Record<string, (args: any[], env: Env, ctx: RouteContext) => Promise<any>>;
31
- /** Render function — returns HTML string from data */
31
+ /** Render function â€" returns HTML string from data */
32
32
  render: (data: Record<string, any>) => string;
33
33
  /** Layout name (default: 'default') */
34
34
  layout?: string;
35
35
  }
36
+ /** HTTP methods supported by API routes */
37
+ export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';
38
+ /** A compiled API route module (route.ts) — returns raw Response objects */
39
+ export interface ApiRouteModule {
40
+ /** Pattern string (e.g., '/api/v1/health', '/api/v1/db/:name') */
41
+ pattern: string;
42
+ /** Marker that distinguishes API routes from page routes */
43
+ __api: true;
44
+ /** Method handlers — keyed by HTTP method */
45
+ [method: string]: ((ctx: RouteContext) => Promise<Response> | Response) | string | boolean;
46
+ }
36
47
  /** Layout module */
37
48
  export interface LayoutModule {
38
- /** Render function — wraps page content */
49
+ /** Render function â€" wraps page content */
39
50
  render: (data: {
40
51
  content: string;
41
52
  data: Record<string, any>;
42
53
  head?: string;
43
54
  }) => string;
44
55
  }
45
- /** App configuration (internal — used by compiler-generated code) */
56
+ /** App configuration (internal â€" used by compiler-generated code) */
46
57
  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 */
58
+ /** Route modules â€" generated by compiler or defined manually */
59
+ routes?: (RouteModule | ApiRouteModule)[];
60
+ /** Layout modules â€" keyed by name */
50
61
  layouts?: Record<string, LayoutModule>;
51
62
  /** Static file directory (relative to project root) */
52
63
  publicDir?: string;
53
64
  }
54
- /** Database schema config — maps a binding name to its schema */
65
+ /** Database schema config â€" maps a binding name to its schema */
55
66
  export interface DatabaseConfig {
56
67
  /** Schema definition (SchemaDsl or DatabaseSchema from @kuratchi/orm) */
57
68
  schema: any;
@@ -61,7 +72,7 @@ export interface DatabaseConfig {
61
72
  skipMigrations?: boolean;
62
73
  }
63
74
  /**
64
- * Framework configuration — the user-facing config file (kuratchi.config.ts)
75
+ * Framework configuration â€" the user-facing config file (kuratchi.config.ts)
65
76
  *
66
77
  * @example
67
78
  * ```ts
@@ -79,20 +90,21 @@ export interface DatabaseConfig {
79
90
  * ```
80
91
  */
81
92
  export interface kuratchiConfig<E extends Env = Env> {
82
- /** ORM configuration — schema definitions and auto-migration */
93
+ /** ORM configuration â€" schema definitions and auto-migration */
83
94
  orm?: {
84
95
  /** Map of D1 binding names to their database configs */
85
- databases: Record<string, DatabaseConfig>;
96
+ databases?: Record<string, DatabaseConfig>;
97
+ [key: string]: any;
86
98
  };
87
- /** UI configuration — opt into @kuratchi/ui theme and components */
99
+ /** UI configuration â€" opt into @kuratchi/ui theme and components */
88
100
  ui?: {
89
101
  /** Theme to inject: 'default' uses @kuratchi/ui's built-in theme, or a path to a custom CSS file */
90
102
  theme?: 'default' | string;
91
103
  };
92
- /** Auth configuration — @kuratchi/auth plugin setup */
93
- auth?: AuthConfig;
104
+ /** Auth configuration â€" @kuratchi/auth plugin setup */
105
+ auth?: AuthConfig | Record<string, any>;
94
106
  /**
95
- * Durable Object configuration — config-driven DO class generation.
107
+ * Durable Object configuration â€" config-driven DO class generation.
96
108
  *
97
109
  * Map a DO namespace binding to its class name and optional configuration.
98
110
  * Supports string shorthand or an object with stubId option.
@@ -100,12 +112,12 @@ export interface kuratchiConfig<E extends Env = Env> {
100
112
  * @example
101
113
  * ```ts
102
114
  * durableObjects: {
103
- * // Object form — stubId tells the framework which user field identifies the stub
115
+ * // Object form â€" stubId tells the framework which user field identifies the stub
104
116
  * ORG_DB: {
105
117
  * className: 'OrganizationDO',
106
118
  * stubId: 'user.orgId'
107
119
  * },
108
- * // String shorthand — className only, no auto-stub resolution
120
+ * // String shorthand â€" className only, no auto-stub resolution
109
121
  * CACHE_DB: 'CacheDO'
110
122
  * }
111
123
  * ```
@@ -114,6 +126,22 @@ export interface kuratchiConfig<E extends Env = Env> {
114
126
  className: string;
115
127
  /** The user field path that identifies the DO stub (e.g. 'user.orgId') */
116
128
  stubId?: string;
129
+ /** DO source files (e.g. ['auth.do.ts', 'sites.do.ts']) */
130
+ files?: string[];
131
+ }>;
132
+ /** Container classes exported into the generated worker entry. */
133
+ containers?: Record<string, string | {
134
+ /** Relative path from project root. Must end in `.container.ts|js|mjs|cjs`. */
135
+ file: string;
136
+ /** Optional override; inferred from exported class in `file` when omitted. */
137
+ className?: string;
138
+ }>;
139
+ /** Workflow classes exported into the generated worker entry. */
140
+ workflows?: Record<string, string | {
141
+ /** Relative path from project root. Must end in `.workflow.ts|js|mjs|cjs`. */
142
+ file: string;
143
+ /** Optional override; inferred from exported class in `file` when omitted. */
144
+ className?: string;
117
145
  }>;
118
146
  }
119
147
  /** Auth configuration for kuratchi.config.ts */
@@ -124,7 +152,7 @@ export interface AuthConfig {
124
152
  secretEnvKey?: string;
125
153
  /** Enable session parsing on every request (default: true) */
126
154
  sessionEnabled?: boolean;
127
- /** Credentials config — enables signUp/signIn/signOut/getCurrentUser */
155
+ /** Credentials config â€" enables signUp/signIn/signOut/getCurrentUser */
128
156
  credentials?: {
129
157
  /** D1 binding name for auth database (default: 'DB') */
130
158
  binding?: string;
@@ -140,16 +168,17 @@ export interface AuthConfig {
140
168
  signInRedirect?: string;
141
169
  /** Redirect after signout (default: '/auth/login') */
142
170
  signOutRedirect?: string;
171
+ [key: string]: any;
143
172
  };
144
- /** Activity tracking config — enables logActivity/getActivity */
173
+ /** Activity tracking config â€" enables logActivity/getActivity */
145
174
  activity?: Record<string, {
146
175
  label: string;
147
176
  severity?: 'info' | 'warning' | 'critical';
148
177
  category?: string;
149
178
  }>;
150
- /** Role definitions — enables hasRole/hasPermission/assignRole */
179
+ /** Role definitions â€" enables hasRole/hasPermission/assignRole */
151
180
  roles?: Record<string, string[]>;
152
- /** OAuth providers config — enables startOAuth/handleOAuthCallback */
181
+ /** OAuth providers config â€" enables startOAuth/handleOAuthCallback */
153
182
  oauth?: {
154
183
  providers?: Record<string, {
155
184
  clientIdEnv: string;
@@ -158,14 +187,16 @@ export interface AuthConfig {
158
187
  }>;
159
188
  /** Redirect after OAuth login (default: '/admin') */
160
189
  loginRedirect?: string;
190
+ [key: string]: any;
161
191
  };
162
- /** Route guards — protect paths, redirect if not authenticated */
192
+ /** Route guards â€" protect paths, redirect if not authenticated */
163
193
  guards?: {
164
194
  paths?: string[];
165
195
  exclude?: string[];
166
196
  redirectTo?: string;
197
+ [key: string]: any;
167
198
  };
168
- /** Rate limiting — throttle requests per route */
199
+ /** Rate limiting â€" throttle requests per route */
169
200
  rateLimit?: {
170
201
  defaultWindowMs?: number;
171
202
  defaultMaxRequests?: number;
@@ -179,12 +210,13 @@ export interface AuthConfig {
179
210
  windowMs?: number;
180
211
  message?: string;
181
212
  }[];
213
+ [key: string]: any;
182
214
  };
183
- /** Turnstile bot protection — verify Cloudflare Turnstile tokens */
215
+ /** Turnstile bot protection â€" verify Cloudflare Turnstile tokens */
184
216
  turnstile?: {
185
217
  /** Env var name for Turnstile secret key (default: 'TURNSTILE_SECRET') */
186
218
  secretEnv?: string;
187
- /** Env var name for Turnstile site key (default: 'TURNSTILE_SITE_KEY') — exposed to client */
219
+ /** Env var name for Turnstile site key (default: 'TURNSTILE_SITE_KEY') â€" exposed to client */
188
220
  siteKeyEnv?: string;
189
221
  /** Skip Turnstile verification in dev mode (default: true) */
190
222
  skipInDev?: boolean;
@@ -198,10 +230,30 @@ export interface AuthConfig {
198
230
  message?: string;
199
231
  expectedAction?: string;
200
232
  }[];
233
+ [key: string]: any;
201
234
  };
202
- /** Organization multi-tenancy — DO-backed per-org databases */
235
+ /** Organization multi-tenancy â€" DO-backed per-org databases */
203
236
  organizations?: {
204
237
  /** DO namespace binding name in env (e.g. 'ORG_DB') */
205
- binding: string;
206
- };
238
+ binding?: string;
239
+ [key: string]: any;
240
+ } | Record<string, any>;
241
+ }
242
+ /** Runtime pipeline context - shared across runtime step handlers */
243
+ export interface RuntimeContext<E extends Env = Env> {
244
+ request: Request;
245
+ env: E;
246
+ ctx: ExecutionContext;
247
+ url: URL;
248
+ params: Record<string, string>;
249
+ locals: Record<string, any>;
250
+ }
251
+ export type RuntimeNext = () => Promise<Response>;
252
+ export type RuntimeErrorResult = Response | null | undefined | void;
253
+ export interface RuntimeStep<E extends Env = Env> {
254
+ request?: (ctx: RuntimeContext<E>, next: RuntimeNext) => Promise<Response> | Response;
255
+ route?: (ctx: RuntimeContext<E>, next: RuntimeNext) => Promise<Response> | Response;
256
+ response?: (ctx: RuntimeContext<E>, response: Response) => Promise<Response> | Response;
257
+ error?: (ctx: RuntimeContext<E>, error: unknown) => Promise<RuntimeErrorResult> | RuntimeErrorResult;
207
258
  }
259
+ export type RuntimeDefinition<E extends Env = Env> = Record<string, RuntimeStep<E>>;
package/package.json CHANGED
@@ -1,46 +1,48 @@
1
1
  {
2
- "name": "@kuratchi/js",
3
- "version": "0.0.2",
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
- }
2
+ "name": "@kuratchi/js",
3
+ "version": "0.0.4",
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
+ "test": "bun test",
19
+ "test:watch": "bun test --watch",
20
+ "prepublishOnly": "npm run build"
21
+ },
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/index.d.ts",
25
+ "import": "./dist/index.js"
26
+ },
27
+ "./runtime/context.js": {
28
+ "types": "./dist/runtime/context.d.ts",
29
+ "import": "./dist/runtime/context.js"
30
+ },
31
+ "./runtime/do.js": {
32
+ "types": "./dist/runtime/do.d.ts",
33
+ "import": "./dist/runtime/do.js"
34
+ },
35
+ "./package.json": "./package.json"
36
+ },
37
+ "engines": {
38
+ "node": "\u003e=18"
39
+ },
40
+ "publishConfig": {
41
+ "access": "public"
42
+ },
43
+ "devDependencies": {
44
+ "@cloudflare/workers-types": "^4.20260223.0",
45
+ "@types/node": "^24.4.0",
46
+ "typescript": "^5.8.0"
47
+ }
48
+ }