@askrjs/askr 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 (43) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +298 -0
  3. package/dist/chunk-4CV4JOE5.js +27 -0
  4. package/dist/chunk-4CV4JOE5.js.map +1 -0
  5. package/dist/chunk-HIWJVOS4.js +503 -0
  6. package/dist/chunk-HIWJVOS4.js.map +1 -0
  7. package/dist/chunk-L7RL4LYV.js +3442 -0
  8. package/dist/chunk-L7RL4LYV.js.map +1 -0
  9. package/dist/chunk-UUM5W2RM.js +84 -0
  10. package/dist/chunk-UUM5W2RM.js.map +1 -0
  11. package/dist/chunk-YNH3D4KW.js +29 -0
  12. package/dist/chunk-YNH3D4KW.js.map +1 -0
  13. package/dist/index.cjs +4733 -0
  14. package/dist/index.cjs.map +1 -0
  15. package/dist/index.d.cts +446 -0
  16. package/dist/index.d.ts +446 -0
  17. package/dist/index.js +683 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/jsx/jsx-dev-runtime.cjs +40 -0
  20. package/dist/jsx/jsx-dev-runtime.cjs.map +1 -0
  21. package/dist/jsx/jsx-dev-runtime.d.cts +16 -0
  22. package/dist/jsx/jsx-dev-runtime.d.ts +16 -0
  23. package/dist/jsx/jsx-dev-runtime.js +16 -0
  24. package/dist/jsx/jsx-dev-runtime.js.map +1 -0
  25. package/dist/jsx/jsx-runtime.cjs +45 -0
  26. package/dist/jsx/jsx-runtime.cjs.map +1 -0
  27. package/dist/jsx/jsx-runtime.d.cts +17 -0
  28. package/dist/jsx/jsx-runtime.d.ts +17 -0
  29. package/dist/jsx/jsx-runtime.js +14 -0
  30. package/dist/jsx/jsx-runtime.js.map +1 -0
  31. package/dist/navigate-NLQOZQGM.js +16 -0
  32. package/dist/navigate-NLQOZQGM.js.map +1 -0
  33. package/dist/route-TVYWYCEJ.js +31 -0
  34. package/dist/route-TVYWYCEJ.js.map +1 -0
  35. package/dist/ssr-4ELUFK65.js +24 -0
  36. package/dist/ssr-4ELUFK65.js.map +1 -0
  37. package/dist/types-DUDmnzD8.d.cts +38 -0
  38. package/dist/types-DUDmnzD8.d.ts +38 -0
  39. package/package.json +83 -0
  40. package/src/jsx/jsx-dev-runtime.ts +26 -0
  41. package/src/jsx/jsx-runtime.ts +36 -0
  42. package/src/jsx/react-jsx-runtime.d.ts +0 -0
  43. package/src/jsx/types.ts +27 -0
@@ -0,0 +1,446 @@
1
+ import { J as JSXElement, P as Props } from './types-DUDmnzD8.cjs';
2
+ export { Fragment, jsx, jsxs } from './jsx/jsx-runtime.cjs';
3
+
4
+ /**
5
+ * Context system: lexical scope + render-time snapshots
6
+ *
7
+ * CORE SEMANTIC (Option A — Snapshot-Based):
8
+ * ============================================
9
+ * An async resource observes the context of the render that created it.
10
+ * Context changes only take effect via re-render, not magically mid-await.
11
+ *
12
+ * This ensures:
13
+ * - Deterministic behavior
14
+ * - Concurrency safety
15
+ * - Replayable execution
16
+ * - Debuggability
17
+ *
18
+ * INVARIANTS:
19
+ * - readContext() only works during component render (has currentContextFrame)
20
+ * - Each render captures a context snapshot
21
+ * - Async continuations see the snapshot from render start (frozen)
22
+ * - Provider (Scope) creates a new frame that shadows parent
23
+ * - Context updates require re-render to take effect
24
+ */
25
+
26
+ type ContextKey = symbol;
27
+ interface Context<T> {
28
+ readonly key: ContextKey;
29
+ readonly defaultValue: T;
30
+ readonly Scope: (props: {
31
+ value: T;
32
+ children?: unknown;
33
+ }) => JSXElement;
34
+ }
35
+ interface ContextFrame {
36
+ parent: ContextFrame | null;
37
+ values: Map<ContextKey, unknown> | null;
38
+ }
39
+ declare function defineContext<T>(defaultValue: T): Context<T>;
40
+ declare function readContext<T>(context: Context<T>): T;
41
+
42
+ /**
43
+ * Component instance lifecycle management
44
+ * Internal only — users never see this
45
+ */
46
+
47
+ type ComponentFunction = (props: Props, context?: {
48
+ signal: AbortSignal;
49
+ }) => JSXElement | VNode$1 | string | number | null;
50
+ type VNode$1 = {
51
+ type: string;
52
+ props?: Props;
53
+ children?: (string | VNode$1 | null | undefined | false)[];
54
+ };
55
+ interface ComponentInstance {
56
+ id: string;
57
+ fn: ComponentFunction;
58
+ props: Props;
59
+ target: Element | null;
60
+ mounted: boolean;
61
+ abortController: AbortController;
62
+ ssr?: boolean;
63
+ stateValues: State<unknown>[];
64
+ evaluationGeneration: number;
65
+ notifyUpdate: (() => void) | null;
66
+ _pendingFlushTask?: () => void;
67
+ _pendingRunTask?: () => void;
68
+ _enqueueRun?: () => void;
69
+ stateIndexCheck: number;
70
+ expectedStateIndices: number[];
71
+ firstRenderComplete: boolean;
72
+ mountOperations: Array<() => void | (() => void) | Promise<void | (() => void)>>;
73
+ cleanupFns: Array<() => void>;
74
+ hasPendingUpdate: boolean;
75
+ ownerFrame: ContextFrame | null;
76
+ isRoot?: boolean;
77
+ _currentRenderToken?: number;
78
+ lastRenderToken?: number;
79
+ _pendingReadStates?: Set<State<unknown>>;
80
+ _lastReadStates?: Set<State<unknown>>;
81
+ }
82
+ /**
83
+ * Get the abort signal for the current component
84
+ * Used to cancel async operations on unmount/navigation
85
+ *
86
+ * The signal is guaranteed to be aborted when:
87
+ * - Component unmounts
88
+ * - Navigation occurs (different route)
89
+ * - Parent is destroyed
90
+ *
91
+ * IMPORTANT: getSignal() must be called during component render execution.
92
+ * It captures the current component instance from context.
93
+ *
94
+ * @returns AbortSignal that will be aborted when component unmounts
95
+ * @throws Error if called outside component execution
96
+ *
97
+ * @example
98
+ * ```ts
99
+ * // ✅ Correct: called during render, used in async operation
100
+ * export async function UserPage({ id }: { id: string }) {
101
+ * const signal = getSignal();
102
+ * const user = await fetch(`/api/users/${id}`, { signal });
103
+ * return <div>{user.name}</div>;
104
+ * }
105
+ *
106
+ * // ✅ Correct: passed to event handler
107
+ * export function Button() {
108
+ * const signal = getSignal();
109
+ * return {
110
+ * type: 'button',
111
+ * props: {
112
+ * onClick: async () => {
113
+ * const data = await fetch(url, { signal });
114
+ * }
115
+ * }
116
+ * };
117
+ * }
118
+ *
119
+ * // ❌ Wrong: called outside component context
120
+ * const signal = getSignal(); // Error: not in component
121
+ * ```
122
+ */
123
+ declare function getSignal(): AbortSignal;
124
+
125
+ /**
126
+ * State primitive for Askr components
127
+ * Optimized for minimal overhead and fast updates
128
+ *
129
+ * INVARIANTS ENFORCED:
130
+ * - state() only callable during component render (currentInstance exists)
131
+ * - state() called at top-level only (indices must be monotonically increasing)
132
+ * - state values persist across re-renders (stored in stateValues array)
133
+ * - state.set() cannot be called during render (causes infinite loops)
134
+ * - state.set() always enqueues through scheduler (never direct mutation)
135
+ * - state.set() callback (notifyUpdate) always available
136
+ */
137
+
138
+ /**
139
+ * State value holder - callable to read, has set method to update
140
+ * @example
141
+ * const count = state(0);
142
+ * count(); // read: 0
143
+ * count.set(1); // write: triggers re-render
144
+ */
145
+ interface State<T> {
146
+ (): T;
147
+ set(value: T): void;
148
+ _hasBeenRead?: boolean;
149
+ _readers?: Map<ComponentInstance, number>;
150
+ }
151
+ /**
152
+ * Creates a local state value for a component
153
+ * Optimized for:
154
+ * - O(1) read performance
155
+ * - Minimal allocation per state
156
+ * - Fast scheduler integration
157
+ *
158
+ * IMPORTANT: state() must be called during component render execution.
159
+ * It captures the current component instance from context.
160
+ * Calling outside a component function will throw an error.
161
+ *
162
+ * @example
163
+ * ```ts
164
+ * // ✅ Correct: called during render
165
+ * export function Counter() {
166
+ * const count = state(0);
167
+ * return { type: 'button', children: [count()] };
168
+ * }
169
+ *
170
+ * // ❌ Wrong: called outside component
171
+ * const count = state(0);
172
+ * export function BadComponent() {
173
+ * return { type: 'div' };
174
+ * }
175
+ * ```
176
+ */
177
+ declare function state<T>(initialValue: T): State<T>;
178
+
179
+ declare function scheduleEventHandler(handler: EventListener): EventListener;
180
+
181
+ interface DataResult<T> {
182
+ value: T | null;
183
+ pending: boolean;
184
+ error: Error | null;
185
+ refresh(): void;
186
+ }
187
+ /**
188
+ * Resource primitive — simple, deterministic async primitive
189
+ * Usage: resource(fn, deps)
190
+ * - fn receives { signal }
191
+ * - captures execution context once at creation (synchronous step only)
192
+ * - executes at most once per generation; stale async results are ignored
193
+ * - refresh() cancels in-flight execution, increments generation and re-runs
194
+ * - exposes { value, pending, error, refresh }
195
+ * - during SSR, async results are disallowed and will throw synchronously
196
+ */
197
+ declare function resource<T>(fn: (opts: {
198
+ signal: AbortSignal;
199
+ }) => Promise<T> | T, deps?: unknown[]): DataResult<T>;
200
+
201
+ /**
202
+ * Route definition and matching
203
+ * Supports dynamic route registration for micro frontends
204
+ *
205
+ * Optimization: Index by depth but maintain insertion order within each depth
206
+ */
207
+ interface RouteHandler {
208
+ (params: Record<string, string>, context?: {
209
+ signal: AbortSignal;
210
+ }): unknown;
211
+ }
212
+ interface Route {
213
+ path: string;
214
+ handler: RouteHandler;
215
+ namespace?: string;
216
+ }
217
+ /**
218
+ * RouteMatch, RouteQuery, RouteSnapshot
219
+ * These describe the read-only snapshot returned by the render-time route() accessor
220
+ */
221
+ interface RouteMatch {
222
+ path: string;
223
+ params: Readonly<Record<string, string>>;
224
+ name?: string;
225
+ namespace?: string;
226
+ }
227
+ interface RouteQuery {
228
+ get(key: string): string | null;
229
+ getAll(key: string): string[];
230
+ has(key: string): boolean;
231
+ toJSON(): Record<string, string | string[]>;
232
+ }
233
+ interface RouteSnapshot {
234
+ path: string;
235
+ params: Readonly<Record<string, string>>;
236
+ query: Readonly<RouteQuery>;
237
+ hash: string | null;
238
+ name?: string;
239
+ namespace?: string;
240
+ matches: readonly RouteMatch[];
241
+ }
242
+ declare function setServerLocation(url: string | null): void;
243
+ declare function route(path?: string, handler?: RouteHandler, namespace?: string): void | RouteSnapshot;
244
+ /**
245
+ * Get all registered routes
246
+ */
247
+ declare function getRoutes(): Route[];
248
+ /**
249
+ * Get routes for a specific namespace
250
+ */
251
+ declare function getNamespaceRoutes(namespace: string): Route[];
252
+ /**
253
+ * Unload all routes from a namespace (for MFE unmounting)
254
+ */
255
+ declare function unloadNamespace(namespace: string): number;
256
+ /**
257
+ * Clear all registered routes (mainly for testing)
258
+ */
259
+ declare function clearRoutes(): void;
260
+ /**
261
+ * Get all loaded namespaces (MFE identifiers)
262
+ */
263
+ declare function getLoadedNamespaces(): string[];
264
+
265
+ /**
266
+ * App bootstrap and mount
267
+ */
268
+
269
+ interface AppConfig {
270
+ root: Element | string;
271
+ component: ComponentFunction;
272
+ }
273
+ /**
274
+ * Bootstrap and mount app on client
275
+ * Supports both sync and async components
276
+ *
277
+ * If createApp is called multiple times on the same root, the existing instance
278
+ * is reused and its component function is updated. This ensures:
279
+ * - Generation tokens work correctly (old async renders don't overwrite new ones)
280
+ * - State is preserved across updates (if desired)
281
+ * - DOM is diffed/updated rather than replaced
282
+ */
283
+ declare function createApp(config: AppConfig | SPAConfig): void;
284
+
285
+ type IslandConfig = {
286
+ root: Element | string;
287
+ component: ComponentFunction;
288
+ routes?: never;
289
+ };
290
+ type SPAConfig = {
291
+ root: Element | string;
292
+ routes: Route[];
293
+ component?: never;
294
+ };
295
+ type HydrateSPAConfig = {
296
+ root: Element | string;
297
+ routes: Route[];
298
+ };
299
+ /**
300
+ * createIsland: Enhances existing DOM (no router, mounts once)
301
+ */
302
+ declare function createIsland(config: IslandConfig): void;
303
+ /**
304
+ * createSPA: Initializes router and mounts the app with provided route table
305
+ */
306
+ declare function createSPA(config: SPAConfig): Promise<void>;
307
+ /**
308
+ * hydrateSPA: Hydrate server-rendered HTML with explicit routes
309
+ */
310
+ declare function hydrateSPA(config: HydrateSPAConfig): Promise<void>;
311
+ /**
312
+ * Cleanup an app mounted on a root element (element or id).
313
+ * Safe to call multiple times — no-op when nothing is mounted.
314
+ */
315
+ declare function cleanupApp(root: Element | string): void;
316
+ /**
317
+ * Check whether an app is mounted on the given root
318
+ */
319
+ declare function hasApp(root: Element | string): boolean;
320
+
321
+ /**
322
+ * Small layout helper (centralized)
323
+ * Usage: const parent = layout(ParentLayout); route('/parent', () => parent(<Child />));
324
+ *
325
+ * A layout is simply a component that receives `children`.
326
+ * This helper intentionally avoids vnode inspection, heuristics, or double-invocation.
327
+ * Prefer boring, explicit code over cleverness.
328
+ *
329
+ * Example:
330
+ * const Parent = ({ children }: { children?: unknown }) => <div class="parent">{children}</div>;
331
+ * const parent = layout(Parent);
332
+ * route('/parent', () => parent(<div class="child">C</div>));
333
+ */
334
+ type Component<P = object> = (props: P & {
335
+ children?: unknown;
336
+ }) => unknown;
337
+ declare function layout<P>(Layout: Component<P>): (children?: unknown) => unknown;
338
+
339
+ /**
340
+ * Client-side navigation with History API
341
+ */
342
+
343
+ /**
344
+ * Navigate to a new path
345
+ * Updates URL, resolves route, and re-mounts app with new handler
346
+ */
347
+ declare function navigate(path: string): void;
348
+
349
+ /**
350
+ * Link component for client-side navigation
351
+ */
352
+
353
+ interface LinkProps {
354
+ href: string;
355
+ children?: unknown;
356
+ }
357
+ /**
358
+ * Link component that prevents default navigation and uses navigate()
359
+ * Provides declarative way to navigate between routes
360
+ *
361
+ * Respects:
362
+ * - Middle-click (opens in new tab)
363
+ * - Ctrl/Cmd+click (opens in new tab)
364
+ * - Shift+click (opens in new window)
365
+ * - Right-click context menu
366
+ */
367
+ declare function Link({ href, children }: LinkProps): JSXElement;
368
+
369
+ type SSRData = Record<string, unknown>;
370
+
371
+ type ResourceDescriptor = {
372
+ key: string;
373
+ fn: (opts: {
374
+ signal?: AbortSignal;
375
+ }) => Promise<unknown> | unknown;
376
+ deps: unknown[];
377
+ index: number;
378
+ };
379
+ type ResourcePlan = {
380
+ resources: ResourceDescriptor[];
381
+ };
382
+ declare function resolvePlan(_plan: ResourcePlan): Promise<Record<string, unknown>>;
383
+ declare function collectResources(_opts: {
384
+ url: string;
385
+ routes: SSRRoute[];
386
+ }): ResourcePlan;
387
+ declare const resolveResources: typeof resolvePlan;
388
+
389
+ /**
390
+ * SSR - Server-Side Rendering
391
+ *
392
+ * Renders Askr components to static HTML strings for server-side rendering.
393
+ * SSR is synchronous: async components are not supported; async work should use
394
+ * `resource()` which is rejected during synchronous SSR. This module throws
395
+ * when an async component or async resource is encountered during sync SSR.
396
+ */
397
+
398
+ type VNode = {
399
+ type: string;
400
+ props?: Props;
401
+ children?: (string | VNode | null | undefined | false)[];
402
+ };
403
+ /**
404
+ * Single synchronous SSR entrypoint: render a component to an HTML string.
405
+ * This is strictly synchronous and deterministic. Optionally provide a seed
406
+ * for deterministic randomness via `options.seed`.
407
+ */
408
+ declare function renderToStringSync(component: (props?: Record<string, unknown>) => VNode | JSXElement | string | number | null, props?: Record<string, unknown>, options?: {
409
+ seed?: number;
410
+ data?: SSRData;
411
+ }): string;
412
+ declare function renderToStringSyncForUrl(opts: {
413
+ url: string;
414
+ routes: Array<{
415
+ path: string;
416
+ handler: RouteHandler;
417
+ namespace?: string;
418
+ }>;
419
+ options?: {
420
+ seed?: number;
421
+ data?: SSRData;
422
+ };
423
+ }): string;
424
+
425
+ type SSRRoute = {
426
+ path: string;
427
+ handler: RouteHandler;
428
+ namespace?: string;
429
+ };
430
+ declare function renderToString(component: (props?: Record<string, unknown>) => VNode | JSXElement | string | number | null): string;
431
+ declare function renderToString(opts: {
432
+ url: string;
433
+ routes: SSRRoute[];
434
+ seed?: number;
435
+ data?: SSRData;
436
+ }): string;
437
+ declare function renderToStream(opts: {
438
+ url: string;
439
+ routes: SSRRoute[];
440
+ seed?: number;
441
+ data?: SSRData;
442
+ onChunk(html: string): void;
443
+ onComplete(): void;
444
+ }): void;
445
+
446
+ export { type Context, type DataResult, type HydrateSPAConfig, type IslandConfig, Link, type LinkProps, Props, type Route, type RouteHandler, type RouteMatch, type RouteSnapshot, type SPAConfig, type State, cleanupApp, clearRoutes, collectResources, createApp, createIsland, createSPA, defineContext, getLoadedNamespaces, getNamespaceRoutes, getRoutes, getSignal, hasApp, hydrateSPA, layout, navigate, readContext, renderToStream, renderToString, renderToStringSync, renderToStringSyncForUrl, resolveResources, resource, route, scheduleEventHandler, setServerLocation, state, unloadNamespace };