@askrjs/askr 0.0.1 → 0.0.2
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 +18 -10
- package/dist/chunk-KR6HG7HF.js +38 -0
- package/dist/chunk-KR6HG7HF.js.map +1 -0
- package/dist/{chunk-L7RL4LYV.js → chunk-MIPES65F.js} +1486 -1905
- package/dist/chunk-MIPES65F.js.map +1 -0
- package/dist/{chunk-HIWJVOS4.js → chunk-PFOLLB6A.js} +38 -17
- package/dist/chunk-PFOLLB6A.js.map +1 -0
- package/dist/chunk-QECQ2TF6.js +28 -0
- package/dist/chunk-QECQ2TF6.js.map +1 -0
- package/dist/{chunk-UUM5W2RM.js → chunk-RJWOOUYV.js} +2 -2
- package/dist/chunk-RJWOOUYV.js.map +1 -0
- package/dist/index.cjs +1760 -1972
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +52 -40
- package/dist/index.d.ts +52 -40
- package/dist/index.js +226 -52
- package/dist/index.js.map +1 -1
- package/dist/jsx/jsx-dev-runtime.cjs +9 -3
- package/dist/jsx/jsx-dev-runtime.cjs.map +1 -1
- package/dist/jsx/jsx-dev-runtime.d.cts +4 -9
- package/dist/jsx/jsx-dev-runtime.d.ts +4 -9
- package/dist/jsx/jsx-dev-runtime.js +10 -4
- package/dist/jsx/jsx-dev-runtime.js.map +1 -1
- package/dist/jsx/jsx-runtime.cjs +14 -5
- package/dist/jsx/jsx-runtime.cjs.map +1 -1
- package/dist/jsx/jsx-runtime.d.cts +9 -6
- package/dist/jsx/jsx-runtime.d.ts +9 -6
- package/dist/jsx/jsx-runtime.js +6 -2
- package/dist/{navigate-NLQOZQGM.js → navigate-SDZNA2ZE.js} +5 -5
- package/dist/{route-TVYWYCEJ.js → route-P5YQBT4T.js} +4 -4
- package/dist/{ssr-4ELUFK65.js → ssr-65K3IJ6B.js} +9 -5
- package/dist/{types-DUDmnzD8.d.cts → types-DLTViI21.d.cts} +15 -3
- package/dist/{types-DUDmnzD8.d.ts → types-DLTViI21.d.ts} +15 -3
- package/package.json +5 -3
- package/src/jsx/index.ts +4 -0
- package/src/jsx/jsx-dev-runtime.ts +7 -10
- package/src/jsx/jsx-runtime.ts +23 -11
- package/src/jsx/types.ts +22 -3
- package/src/jsx/utils.ts +19 -0
- package/dist/chunk-4CV4JOE5.js +0 -27
- package/dist/chunk-HIWJVOS4.js.map +0 -1
- package/dist/chunk-L7RL4LYV.js.map +0 -1
- package/dist/chunk-UUM5W2RM.js.map +0 -1
- package/dist/chunk-YNH3D4KW.js +0 -29
- package/dist/chunk-YNH3D4KW.js.map +0 -1
- package/dist/ssr-4ELUFK65.js.map +0 -1
- package/src/jsx/react-jsx-runtime.d.ts +0 -0
- /package/dist/{chunk-4CV4JOE5.js.map → navigate-SDZNA2ZE.js.map} +0 -0
- /package/dist/{navigate-NLQOZQGM.js.map → route-P5YQBT4T.js.map} +0 -0
- /package/dist/{route-TVYWYCEJ.js.map → ssr-65K3IJ6B.js.map} +0 -0
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
init_component,
|
|
5
5
|
route_exports,
|
|
6
6
|
setCurrentComponentInstance
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-MIPES65F.js";
|
|
8
8
|
|
|
9
9
|
// src/ssr/errors.ts
|
|
10
10
|
var SSRDataMissingError = class _SSRDataMissingError extends Error {
|
|
@@ -185,9 +185,14 @@ function renderChildrenToSink(children, sink, ctx) {
|
|
|
185
185
|
ctx
|
|
186
186
|
);
|
|
187
187
|
}
|
|
188
|
+
function isPromiseLike(x) {
|
|
189
|
+
if (!x || typeof x !== "object") return false;
|
|
190
|
+
const then = x.then;
|
|
191
|
+
return typeof then === "function";
|
|
192
|
+
}
|
|
188
193
|
function executeComponent(type, props, ctx) {
|
|
189
194
|
const res = type(props ?? {}, { signal: ctx.signal });
|
|
190
|
-
if (res
|
|
195
|
+
if (isPromiseLike(res)) {
|
|
191
196
|
throwSSRDataMissing();
|
|
192
197
|
}
|
|
193
198
|
return res;
|
|
@@ -278,6 +283,32 @@ var VOID_ELEMENTS2 = /* @__PURE__ */ new Set([
|
|
|
278
283
|
"wbr"
|
|
279
284
|
]);
|
|
280
285
|
var escapeCache2 = /* @__PURE__ */ new Map();
|
|
286
|
+
var __ssrGuardStack = [];
|
|
287
|
+
function pushSSRStrictPurityGuard() {
|
|
288
|
+
if (process.env.NODE_ENV === "production") return;
|
|
289
|
+
__ssrGuardStack.push({
|
|
290
|
+
random: Reflect.get(Math, "random"),
|
|
291
|
+
now: Reflect.get(Date, "now")
|
|
292
|
+
});
|
|
293
|
+
Reflect.set(Math, "random", () => {
|
|
294
|
+
throw new Error(
|
|
295
|
+
"SSR Strict Purity: Math.random is not allowed during synchronous SSR. Use the provided `ssr` context RNG instead."
|
|
296
|
+
);
|
|
297
|
+
});
|
|
298
|
+
Reflect.set(Date, "now", () => {
|
|
299
|
+
throw new Error(
|
|
300
|
+
"SSR Strict Purity: Date.now is not allowed during synchronous SSR. Pass timestamps explicitly or use deterministic helpers."
|
|
301
|
+
);
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
function popSSRStrictPurityGuard() {
|
|
305
|
+
if (process.env.NODE_ENV === "production") return;
|
|
306
|
+
const prev = __ssrGuardStack.pop();
|
|
307
|
+
if (prev) {
|
|
308
|
+
Reflect.set(Math, "random", prev.random);
|
|
309
|
+
Reflect.set(Date, "now", prev.now);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
281
312
|
function escapeText2(text) {
|
|
282
313
|
const cached = escapeCache2.get(text);
|
|
283
314
|
if (cached) return cached;
|
|
@@ -355,20 +386,9 @@ function renderNodeSync(node, ctx) {
|
|
|
355
386
|
return `<${typeStr}${attrs}>${childrenHtml}</${typeStr}>`;
|
|
356
387
|
}
|
|
357
388
|
function executeComponentSync(component, props, ctx) {
|
|
358
|
-
const originalRandom = Math.random;
|
|
359
|
-
const originalDateNow = Date.now;
|
|
360
389
|
try {
|
|
361
390
|
if (process.env.NODE_ENV !== "production") {
|
|
362
|
-
|
|
363
|
-
throw new Error(
|
|
364
|
-
"SSR Strict Purity: Math.random is not allowed during synchronous SSR. Use the provided `ssr` context RNG instead."
|
|
365
|
-
);
|
|
366
|
-
};
|
|
367
|
-
Date.now = () => {
|
|
368
|
-
throw new Error(
|
|
369
|
-
"SSR Strict Purity: Date.now is not allowed during synchronous SSR. Pass timestamps explicitly or use deterministic helpers."
|
|
370
|
-
);
|
|
371
|
-
};
|
|
391
|
+
pushSSRStrictPurityGuard();
|
|
372
392
|
}
|
|
373
393
|
const prev = getCurrentComponentInstance();
|
|
374
394
|
const temp = createComponentInstance(
|
|
@@ -391,8 +411,7 @@ function executeComponentSync(component, props, ctx) {
|
|
|
391
411
|
setCurrentComponentInstance(prev);
|
|
392
412
|
}
|
|
393
413
|
} finally {
|
|
394
|
-
|
|
395
|
-
Date.now = originalDateNow;
|
|
414
|
+
if (process.env.NODE_ENV !== "production") popSSRStrictPurityGuard();
|
|
396
415
|
}
|
|
397
416
|
}
|
|
398
417
|
function renderToStringSync(component, props, options) {
|
|
@@ -495,9 +514,11 @@ export {
|
|
|
495
514
|
resolvePlan,
|
|
496
515
|
collectResources,
|
|
497
516
|
resolveResources,
|
|
517
|
+
pushSSRStrictPurityGuard,
|
|
518
|
+
popSSRStrictPurityGuard,
|
|
498
519
|
renderToStringSync,
|
|
499
520
|
renderToStringSyncForUrl,
|
|
500
521
|
renderToString,
|
|
501
522
|
renderToStream
|
|
502
523
|
};
|
|
503
|
-
//# sourceMappingURL=chunk-
|
|
524
|
+
//# sourceMappingURL=chunk-PFOLLB6A.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ssr/errors.ts","../src/ssr/context.ts","../src/ssr/index.ts","../src/ssr/sink.ts","../src/ssr/render.ts","../src/ssr/data.ts"],"sourcesContent":["export class SSRDataMissingError extends Error {\n readonly code = 'SSR_DATA_MISSING';\n constructor(\n message = 'Server-side rendering requires all data to be available synchronously. This component attempted to use async data during SSR.'\n ) {\n super(message);\n this.name = 'SSRDataMissingError';\n Object.setPrototypeOf(this, SSRDataMissingError.prototype);\n }\n}\n\nexport class SSRInvariantError extends Error {\n readonly code = 'SSR_INVARIANT_VIOLATION';\n constructor(message: string) {\n super(message);\n this.name = 'SSRInvariantError';\n Object.setPrototypeOf(this, SSRInvariantError.prototype);\n }\n}\n","import type { Props } from '../shared/types';\nimport { SSRDataMissingError } from './errors';\n\nexport type SSRData = Record<string, unknown>;\n\nexport type SSRContext = {\n url: string;\n seed: number;\n data?: SSRData;\n params?: Record<string, string>;\n signal?: AbortSignal;\n};\n\n// Optional: scoped access for sink-based streaming SSR (sync and stack-scoped)\nlet current: SSRContext | null = null;\n\nexport function getSSRContext(): SSRContext | null {\n return current;\n}\n\nexport function withSSRContext<T>(ctx: SSRContext, fn: () => T): T {\n const prev = current;\n current = ctx;\n try {\n return fn();\n } finally {\n current = prev;\n }\n}\n\n// --- Render-only context (compatibility from previous ssrContext.ts) ---------\n// Deterministic seeded RNG used only inside the render context\nexport class SeededRNG {\n private seed: number;\n\n constructor(seed = 12345) {\n this.seed = seed | 0;\n }\n\n reset(seed = 12345) {\n this.seed = seed | 0;\n }\n\n // Simple LCG, stable and deterministic\n random(): number {\n this.seed = (this.seed * 9301 + 49297) % 233280;\n return this.seed / 233280;\n }\n}\n\n/** Context passed through a single render pass */\nexport type RenderContext = {\n seed: number;\n rng: SeededRNG;\n};\n\n/** Create a RenderContext from a seed */\nexport function createRenderContext(seed = 12345): RenderContext {\n const rng = new SeededRNG(seed);\n return { seed, rng };\n}\n\n// Lightweight module-level current context for SSR detection (render-only)\nlet currentSSRContext: RenderContext | null = null;\n\nexport function getCurrentSSRContext(): RenderContext | null {\n return currentSSRContext;\n}\n\nexport function runWithSSRContext<T>(ctx: RenderContext, fn: () => T): T {\n const prev = currentSSRContext;\n currentSSRContext = ctx;\n try {\n return fn();\n } finally {\n currentSSRContext = prev;\n }\n}\n\n/**\n * Centralized SSR enforcement helper — use this to throw a single, consistent\n * error when async data is encountered during synchronous SSR.\n */\nexport function throwSSRDataMissing(): never {\n throw new SSRDataMissingError();\n}\n\nexport { SSRDataMissingError };\n\n// Deterministic RNG (explicitly used by components via ctx if desired)\nexport function makeSeededRandom(seed: number) {\n // LCG\n let s = seed >>> 0;\n return () => {\n s = (s * 1664525 + 1013904223) >>> 0;\n return s / 0x100000000;\n };\n}\n\n// Helper: merge params into props for route handlers if needed\nexport function mergeRouteProps(\n props: Props | undefined,\n params?: Record<string, string>\n): Props {\n if (!params) return (props ?? {}) as Props;\n return { ...(props ?? {}), ...params } as Props;\n}\n","/**\n * SSR - Server-Side Rendering\n *\n * Renders Askr components to static HTML strings for server-side rendering.\n * SSR is synchronous: async components are not supported; async work should use\n * `resource()` which is rejected during synchronous SSR. This module throws\n * when an async component or async resource is encountered during sync SSR.\n */\n\nimport type { JSXElement } from '../jsx/types';\nimport type { RouteHandler } from '../router/route';\nimport * as RouteModule from '../router/route';\nimport type { Props } from '../shared/types';\nimport {\n createRenderContext,\n runWithSSRContext,\n throwSSRDataMissing,\n type RenderContext,\n type SSRData,\n} from './context';\nimport {\n createComponentInstance,\n setCurrentComponentInstance,\n getCurrentComponentInstance,\n} from '../runtime/component';\nimport type { ComponentFunction } from '../runtime/component';\n\nexport { SSRDataMissingError } from './context';\n\ntype VNode = {\n type: string;\n props?: Props;\n children?: (string | VNode | null | undefined | false)[];\n};\n\nexport type Component = (\n props: Props,\n context?: { signal?: AbortSignal; ssr?: RenderContext }\n) => VNode | JSXElement;\n\n// HTML5 void elements that don't have closing tags\nconst VOID_ELEMENTS = new Set([\n 'area',\n 'base',\n 'br',\n 'col',\n 'embed',\n 'hr',\n 'img',\n 'input',\n 'link',\n 'meta',\n 'param',\n 'source',\n 'track',\n 'wbr',\n]);\n\n// Escape cache for common values\nconst escapeCache = new Map<string, string>();\n\n// Dev-only SSR strictness guard helpers. We mutate globals in dev to make\n// accidental usage of Math.random/Date.now during sync SSR fail fast.\n// We implement a re-entrant stack so nested or concurrent calls don't clobber\n// global values unexpectedly.\nconst __ssrGuardStack: Array<{ random: () => number; now: () => number }> = [];\n\nexport function pushSSRStrictPurityGuard() {\n /* istanbul ignore if - dev-only guard */\n if (process.env.NODE_ENV === 'production') return;\n __ssrGuardStack.push({\n random: Reflect.get(Math, 'random') as () => number,\n now: Reflect.get(Date, 'now') as () => number,\n });\n Reflect.set(Math, 'random', () => {\n throw new Error(\n 'SSR Strict Purity: Math.random is not allowed during synchronous SSR. Use the provided `ssr` context RNG instead.'\n );\n });\n Reflect.set(Date, 'now', () => {\n throw new Error(\n 'SSR Strict Purity: Date.now is not allowed during synchronous SSR. Pass timestamps explicitly or use deterministic helpers.'\n );\n });\n}\n\nexport function popSSRStrictPurityGuard() {\n /* istanbul ignore if - dev-only guard */\n if (process.env.NODE_ENV === 'production') return;\n const prev = __ssrGuardStack.pop();\n if (prev) {\n Reflect.set(Math, 'random', prev.random);\n Reflect.set(Date, 'now', prev.now);\n }\n}\n\n/**\n * Escape HTML special characters in text content (optimized with cache)\n */\nfunction escapeText(text: string): string {\n const cached = escapeCache.get(text);\n if (cached) return cached;\n\n const str = String(text);\n // Fast path: check if escaping needed\n if (!str.includes('&') && !str.includes('<') && !str.includes('>')) {\n escapeCache.set(text, str);\n return str;\n }\n\n const result = str\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>');\n\n if (escapeCache.size < 256) {\n escapeCache.set(text, result);\n }\n return result;\n}\n\n/**\n * Escape HTML special characters in attribute values\n */\nfunction escapeAttr(value: string): string {\n const str = String(value);\n // Fast path: check if escaping needed\n if (\n !str.includes('&') &&\n !str.includes('\"') &&\n !str.includes(\"'\") &&\n !str.includes('<') &&\n !str.includes('>')\n ) {\n return str;\n }\n\n return str\n .replace(/&/g, '&')\n .replace(/\"/g, '"')\n .replace(/'/g, ''')\n .replace(/</g, '<')\n .replace(/>/g, '>');\n}\n\n/**\n * Render attributes to HTML string, excluding event handlers\n * Optimized for minimal allocations\n */\nfunction renderAttrs(props?: Props): string {\n if (!props || typeof props !== 'object') return '';\n\n let result = '';\n for (const [key, value] of Object.entries(props)) {\n // Skip event handlers (onClick, onChange, etc.)\n if (key.startsWith('on') && key[2] === key[2].toUpperCase()) {\n continue;\n }\n // Skip internal props\n if (key.startsWith('_')) {\n continue;\n }\n\n // Normalize class attribute (`class` preferred, accept `className` for compatibility)\n const attrName = key === 'class' || key === 'className' ? 'class' : key;\n\n // Boolean attributes\n if (value === true) {\n result += ` ${attrName}`;\n } else if (value === false || value === null || value === undefined) {\n // Skip falsy values\n continue;\n } else {\n // Regular attributes\n result += ` ${attrName}=\"${escapeAttr(String(value))}\"`;\n }\n }\n return result;\n}\n\n/**\n * Synchronous rendering helpers (used for strictly synchronous SSR)\n */\nfunction renderChildSync(child: unknown, ctx: RenderContext): string {\n if (typeof child === 'string') return escapeText(child);\n if (typeof child === 'number') return escapeText(String(child));\n if (child === null || child === undefined || child === false) return '';\n if (typeof child === 'object' && child !== null && 'type' in child) {\n // We already verified the shape above; assert as VNode for the sync renderer\n return renderNodeSync(child as VNode, ctx);\n }\n return '';\n}\n\nfunction renderChildrenSync(\n children: unknown[] | undefined,\n ctx: RenderContext\n): string {\n if (!children || !Array.isArray(children) || children.length === 0) return '';\n let result = '';\n for (const child of children) result += renderChildSync(child, ctx);\n return result;\n}\n\n/**\n * Render a VNode synchronously. Throws if an async component is encountered.\n */\nfunction renderNodeSync(node: VNode | JSXElement, ctx: RenderContext): string {\n const { type, props } = node;\n\n if (typeof type === 'function') {\n const result = executeComponentSync(type as Component, props, ctx);\n if (result instanceof Promise) {\n // Use centralized SSR error to maintain a single failure mode\n throwSSRDataMissing();\n }\n return renderNodeSync(result as VNode | JSXElement, ctx);\n }\n\n const typeStr = type as string;\n if (VOID_ELEMENTS.has(typeStr)) {\n const attrs = renderAttrs(props);\n return `<${typeStr}${attrs} />`;\n }\n\n const attrs = renderAttrs(props);\n const children = (node as VNode).children;\n const childrenHtml = renderChildrenSync(children, ctx);\n return `<${typeStr}${attrs}>${childrenHtml}</${typeStr}>`;\n}\n\n/**\n * Execute a component function (synchronously or async) and return VNode\n */\n/**\n * Execute a component synchronously inside a render-only context.\n * This must not create or reuse runtime ComponentInstance objects. We pass\n * the render context explicitly as `context.ssr` in the second argument so\n * components can opt-in to deterministic randomness/time via the provided RNG.\n */\nfunction executeComponentSync(\n component: Component,\n props: Record<string, unknown> | undefined,\n ctx: RenderContext\n): VNode | JSXElement {\n // Dev-only: enforce SSR purity with clear messages. We temporarily override\n // `Math.random` and `Date.now` while rendering to produce a targeted error\n // if components call them directly. We restore them immediately afterwards.\n // Re-entrant guard for dev-only SSR strict purity checks.\n // We avoid clobbering globals permanently by pushing the original functions\n // onto a stack and restoring them on exit. This is safer for nested or\n // stacked SSR render invocations.\n\n try {\n if (process.env.NODE_ENV !== 'production') {\n pushSSRStrictPurityGuard();\n }\n // Create a temporary, lightweight component instance so runtime APIs like\n // `state()` and `route()` can be called during SSR render. We avoid mounting\n // or side-effects by not attaching the instance to any DOM target.\n const prev = getCurrentComponentInstance();\n const temp = createComponentInstance(\n 'ssr-temp',\n component as ComponentFunction,\n (props || {}) as Props,\n null\n );\n temp.ssr = true;\n setCurrentComponentInstance(temp);\n try {\n return runWithSSRContext(ctx, () => {\n const result = component((props || {}) as Props, { ssr: ctx });\n if (result instanceof Promise) {\n // Use the centralized SSR error for async data/components during SSR\n throwSSRDataMissing();\n }\n return result as VNode | JSXElement;\n });\n } finally {\n // Restore the previous instance (if any)\n setCurrentComponentInstance(prev);\n }\n } finally {\n if (process.env.NODE_ENV !== 'production') popSSRStrictPurityGuard();\n }\n}\n\n/**\n * Single synchronous SSR entrypoint: render a component to an HTML string.\n * This is strictly synchronous and deterministic. Optionally provide a seed\n * for deterministic randomness via `options.seed`.\n */\nexport function renderToStringSync(\n component: (\n props?: Record<string, unknown>\n ) => VNode | JSXElement | string | number | null,\n props?: Record<string, unknown>,\n options?: { seed?: number; data?: SSRData }\n): string {\n const seed = options?.seed ?? 12345;\n // Start render-phase keying (aligns with collectResources)\n const ctx = createRenderContext(seed);\n // Provide optional SSR data via options.data\n startRenderPhase(options?.data ?? null);\n try {\n const node = executeComponentSync(component as Component, props || {}, ctx);\n return renderNodeSync(node, ctx);\n } finally {\n stopRenderPhase();\n }\n}\n\n// Synchronous server render for strict checks. Routes must be resolved before\n// the render pass so no route() calls happen during rendering.\nexport function renderToStringSyncForUrl(opts: {\n url: string;\n routes: Array<{ path: string; handler: RouteHandler; namespace?: string }>;\n options?: { seed?: number; data?: SSRData };\n}): string {\n const { url, routes, options } = opts;\n // Register routes synchronously using route() (already available in module scope)\n const {\n clearRoutes,\n route,\n setServerLocation,\n lockRouteRegistration,\n resolveRoute,\n } = RouteModule;\n\n clearRoutes();\n for (const r of routes) {\n route(r.path, r.handler, r.namespace);\n }\n\n setServerLocation(url);\n if (process.env.NODE_ENV === 'production') lockRouteRegistration();\n\n const resolved = resolveRoute(url);\n if (!resolved)\n throw new Error(`renderToStringSync: no route found for url: ${url}`);\n\n const seed = options?.seed ?? 12345;\n const ctx = createRenderContext(seed);\n // Start render-phase keying (aligns with collectResources)\n startRenderPhase(options?.data ?? null);\n try {\n const node = executeComponentSync(\n resolved.handler as Component,\n resolved.params || {},\n ctx\n );\n return renderNodeSync(node, ctx);\n } finally {\n stopRenderPhase();\n }\n}\n\n// --- Streaming sink-based renderer (v2) --------------------------------------------------\nimport { StringSink, StreamSink } from './sink';\nimport { renderNodeToSink } from './render';\nimport {\n startRenderPhase,\n stopRenderPhase,\n collectResources,\n resolvePlan,\n resolveResources,\n ResourcePlan,\n} from './data';\n\nexport type SSRRoute = {\n path: string;\n handler: RouteHandler;\n namespace?: string;\n};\n\nexport function renderToString(\n component: (\n props?: Record<string, unknown>\n ) => VNode | JSXElement | string | number | null\n): string;\nexport function renderToString(opts: {\n url: string;\n routes: SSRRoute[];\n seed?: number;\n data?: SSRData;\n}): string;\nexport function renderToString(arg: unknown): string {\n // Convenience: if a component function is passed, delegate to sync render\n if (typeof arg === 'function') {\n return renderToStringSync(\n arg as (\n props?: Record<string, unknown>\n ) => VNode | JSXElement | string | number | null\n );\n }\n const opts = arg as {\n url: string;\n routes: SSRRoute[];\n seed?: number;\n data?: SSRData;\n };\n const sink = new StringSink();\n renderToSinkInternal({ ...opts, sink });\n sink.end();\n return sink.toString();\n}\n\nexport function renderToStream(opts: {\n url: string;\n routes: SSRRoute[];\n seed?: number;\n data?: SSRData;\n onChunk(html: string): void;\n onComplete(): void;\n}): void {\n const sink = new StreamSink(opts.onChunk, opts.onComplete);\n renderToSinkInternal({ ...opts, sink });\n sink.end();\n}\n\nfunction renderToSinkInternal(opts: {\n url: string;\n routes: SSRRoute[];\n seed?: number;\n data?: SSRData;\n sink: { write(html: string): void; end(): void };\n}) {\n const { url, routes, seed = 1, data, sink } = opts;\n\n // Route resolution happens BEFORE render pass\n const {\n clearRoutes,\n route,\n setServerLocation,\n lockRouteRegistration,\n resolveRoute,\n } = RouteModule;\n\n clearRoutes();\n for (const r of routes) route(r.path, r.handler, r.namespace);\n\n setServerLocation(url);\n if (process.env.NODE_ENV === 'production') lockRouteRegistration();\n\n const resolved = resolveRoute(url);\n if (!resolved) throw new Error(`SSR: no route found for url: ${url}`);\n\n const ctx = {\n url,\n seed,\n data,\n params: resolved.params,\n signal: undefined as AbortSignal | undefined,\n };\n\n // Render the resolved handler with params\n const node = resolved.handler(resolved.params) as\n | VNode\n | JSXElement\n | string\n | number\n | null;\n\n // Start render-phase keying so resource() can lookup resolved `data` by key\n startRenderPhase(data || null);\n try {\n renderNodeToSink(node, sink, ctx);\n } finally {\n stopRenderPhase();\n }\n}\n\nexport { collectResources, resolvePlan, resolveResources, ResourcePlan };\n","export interface RenderSink {\n write(html: string): void;\n end(): void;\n}\n\nexport class StringSink implements RenderSink {\n private chunks: string[] = [];\n\n write(html: string) {\n if (html) this.chunks.push(html);\n }\n\n end() {}\n\n toString() {\n return this.chunks.join('');\n }\n}\n\nexport class StreamSink implements RenderSink {\n constructor(\n private readonly onChunk: (html: string) => void,\n private readonly onComplete: () => void\n ) {}\n\n write(html: string) {\n if (html) this.onChunk(html);\n }\n\n end() {\n this.onComplete();\n }\n}\n","import type { JSXElement } from '../jsx/types';\nimport type { Props } from '../shared/types';\nimport type { RenderSink } from './sink';\nimport {\n withSSRContext,\n type SSRContext,\n throwSSRDataMissing,\n} from './context';\n\ntype VNode = {\n type: string | Component;\n props?: Props;\n // Some JSX runtimes put children on `props.children`, others on `children`.\n children?: unknown[];\n};\n\nexport type Component = (\n props: Props,\n context?: { signal?: AbortSignal }\n) => VNode | JSXElement | string | number | null;\n\nconst VOID_ELEMENTS = new Set([\n 'area',\n 'base',\n 'br',\n 'col',\n 'embed',\n 'hr',\n 'img',\n 'input',\n 'link',\n 'meta',\n 'param',\n 'source',\n 'track',\n 'wbr',\n]);\n\nconst escapeCache = new Map<string, string>();\n\nfunction escapeText(text: string): string {\n const cached = escapeCache.get(text);\n if (cached) return cached;\n\n const str = String(text);\n if (!str.includes('&') && !str.includes('<') && !str.includes('>')) {\n if (escapeCache.size < 256) escapeCache.set(text, str);\n return str;\n }\n\n const result = str\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>');\n if (escapeCache.size < 256) escapeCache.set(text, result);\n return result;\n}\n\nfunction escapeAttr(value: string): string {\n const str = String(value);\n if (\n !str.includes('&') &&\n !str.includes('\"') &&\n !str.includes(\"'\") &&\n !str.includes('<') &&\n !str.includes('>')\n ) {\n return str;\n }\n return str\n .replace(/&/g, '&')\n .replace(/\"/g, '"')\n .replace(/'/g, ''')\n .replace(/</g, '<')\n .replace(/>/g, '>');\n}\n\nfunction styleObjToCss(value: unknown): string | null {\n if (!value || typeof value !== 'object') return null;\n const entries = Object.entries(value as Record<string, unknown>);\n if (entries.length === 0) return '';\n // camelCase -> kebab-case\n let out = '';\n for (const [k, v] of entries) {\n if (v === null || v === undefined || v === false) continue;\n const prop = k.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);\n out += `${prop}:${String(v)};`;\n }\n return out;\n}\n\nfunction renderAttrs(props?: Props): string {\n if (!props || typeof props !== 'object') return '';\n\n let result = '';\n for (const [key, value] of Object.entries(props)) {\n // Skip children in attrs\n if (key === 'children') continue;\n\n // Skip event handlers: onClick, onChange, ...\n if (key.startsWith('on') && key[2] === key[2]?.toUpperCase()) continue;\n\n // Skip internal props\n if (key.startsWith('_')) continue;\n\n const attrName = key === 'class' || key === 'className' ? 'class' : key;\n\n if (attrName === 'style') {\n const css = typeof value === 'string' ? value : styleObjToCss(value);\n if (css === null) continue;\n if (css === '') continue;\n result += ` style=\"${escapeAttr(css)}\"`;\n continue;\n }\n\n if (value === true) {\n result += ` ${attrName}`;\n } else if (value === false || value === null || value === undefined) {\n continue;\n } else {\n result += ` ${attrName}=\"${escapeAttr(String(value))}\"`;\n }\n }\n\n return result;\n}\n\nfunction isVNodeLike(x: unknown): x is VNode | JSXElement {\n return (\n !!x && typeof x === 'object' && 'type' in (x as Record<string, unknown>)\n );\n}\n\nfunction normalizeChildren(node: unknown): unknown[] {\n // Prefer explicit node.children; fallback to props.children\n const n = node as Record<string, unknown> | null | undefined;\n const direct = Array.isArray(n?.children) ? (n?.children as unknown[]) : null;\n const fromProps = (n?.props as Record<string, unknown> | undefined)\n ?.children as unknown;\n\n const raw = direct ?? fromProps;\n\n if (raw === null || raw === undefined || raw === false) return [];\n if (Array.isArray(raw)) return raw;\n return [raw];\n}\n\n// Note: renderChildToSink was removed in favor of direct renderNodeToSink inlined calls\n\nfunction renderChildrenToSink(\n children: unknown[],\n sink: RenderSink,\n ctx: SSRContext\n) {\n for (const c of children)\n renderNodeToSink(\n c as VNode | JSXElement | string | number | null,\n sink,\n ctx\n );\n}\n\nfunction isPromiseLike(x: unknown): x is PromiseLike<unknown> {\n if (!x || typeof x !== 'object') return false;\n const then = (x as { then?: unknown }).then;\n return typeof then === 'function';\n}\n\nfunction executeComponent(\n type: Component,\n props: Props | undefined,\n ctx: SSRContext\n): unknown {\n // Synchronous only. If a user returns a Promise, that's a hard error.\n const res = type(props ?? {}, { signal: ctx.signal });\n if (isPromiseLike(res)) {\n // Use centralized SSR failure mode — async components are not allowed during\n // synchronous SSR and must be pre-resolved by the developer.\n throwSSRDataMissing();\n }\n return res;\n}\n\nexport function renderNodeToSink(\n node: VNode | JSXElement | string | number | null,\n sink: RenderSink,\n ctx: SSRContext\n) {\n if (node === null || node === undefined) return;\n\n if (typeof node === 'string') {\n sink.write(escapeText(node));\n return;\n }\n if (typeof node === 'number') {\n sink.write(escapeText(String(node)));\n return;\n }\n\n if (!isVNodeLike(node)) return;\n\n const { type, props } = node as VNode;\n\n // Function component\n if (typeof type === 'function') {\n const out = withSSRContext(ctx, () =>\n executeComponent(type as Component, props, ctx)\n );\n renderNodeToSink(\n out as VNode | JSXElement | string | number | null,\n sink,\n ctx\n );\n return;\n }\n\n // Element node\n const tag = String(type);\n const attrs = renderAttrs(props);\n\n // void element\n if (VOID_ELEMENTS.has(tag)) {\n sink.write(`<${tag}${attrs} />`);\n return;\n }\n\n sink.write(`<${tag}${attrs}>`);\n const children = normalizeChildren(node);\n renderChildrenToSink(children, sink, ctx);\n sink.write(`</${tag}>`);\n}\n","import type { SSRRoute } from './index';\n\nexport type ResourceDescriptor = {\n key: string;\n fn: (opts: { signal?: AbortSignal }) => Promise<unknown> | unknown;\n deps: unknown[];\n index: number;\n};\n\nexport type ResourcePlan = {\n resources: ResourceDescriptor[]; // declarative manifest in stable order\n};\n\n// Internal collection state (collection/prepass removed)\nlet keyCounter = 0;\nlet currentRenderData: Record<string, unknown> | null = null;\n\nexport function getCurrentRenderData(): Record<string, unknown> | null {\n return currentRenderData;\n}\n\nexport function resetKeyCounter() {\n keyCounter = 0;\n}\n\nexport function getNextKey(): string {\n return `r:${keyCounter++}`;\n}\n\nexport function startCollection() {\n throw new Error(\n 'SSR collection/prepass is removed: SSR is strictly synchronous; do not call startCollection()'\n );\n}\n\nexport function stopCollection(): ResourcePlan {\n throw new Error(\n 'SSR collection/prepass is removed: SSR is strictly synchronous; do not call stopCollection()'\n );\n}\n\nexport function registerResourceIntent(\n _fn: ResourceDescriptor['fn'],\n _deps: unknown[]\n): string {\n throw new Error(\n 'SSR resource intents collection is removed: resource() no longer registers intents for prepass'\n );\n}\n\nexport function startRenderPhase(data: Record<string, unknown> | null) {\n currentRenderData = data ?? null;\n resetKeyCounter();\n}\n\nexport function stopRenderPhase() {\n currentRenderData = null;\n resetKeyCounter();\n}\n\n// Resolve a plan (execute resource functions in declared order)\nexport async function resolvePlan(\n _plan: ResourcePlan\n): Promise<Record<string, unknown>> {\n throw new Error(\n 'SSR resolution of prepass plans is removed: SSR is strictly synchronous and does not support resolving async resource plans'\n );\n}\n\nexport function collectResources(_opts: {\n url: string;\n routes: SSRRoute[];\n}): ResourcePlan {\n throw new Error(\n 'SSR collection/prepass (collectResources) is removed: SSR is strictly synchronous and does not support prepass collection'\n );\n}\n\n// Backwards-compatible alias: new public API prefers the name `resolveResources`\nexport const resolveResources = resolvePlan;\n"],"mappings":"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","names":["VOID_ELEMENTS","escapeCache","escapeText","escapeAttr","renderAttrs","attrs"]}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __esm = (fn, res) => function __init() {
|
|
4
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
5
|
+
};
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// src/jsx/types.ts
|
|
12
|
+
var ELEMENT_TYPE, Fragment;
|
|
13
|
+
var init_types = __esm({
|
|
14
|
+
"src/jsx/types.ts"() {
|
|
15
|
+
"use strict";
|
|
16
|
+
ELEMENT_TYPE = /* @__PURE__ */ Symbol.for("askr.element");
|
|
17
|
+
Fragment = /* @__PURE__ */ Symbol.for("askr.fragment");
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
export {
|
|
22
|
+
__esm,
|
|
23
|
+
__export,
|
|
24
|
+
ELEMENT_TYPE,
|
|
25
|
+
Fragment,
|
|
26
|
+
init_types
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=chunk-QECQ2TF6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/jsx/types.ts"],"sourcesContent":["/**\n * JSX type definitions\n *\n * These define the canonical JSX element shape used by:\n * - jsx-runtime\n * - jsx-dev-runtime\n * - Slot / cloneElement\n * - the reconciler\n */\n\nimport type { Props } from '../shared/types';\n\nexport const ELEMENT_TYPE = Symbol.for('askr.element');\nexport const Fragment = Symbol.for('askr.fragment');\n\nexport interface JSXElement {\n /** Internal element marker (optional for plain vnode objects) */\n $$typeof?: symbol;\n\n /** Element type: string, component, Fragment, etc */\n type: unknown;\n\n /** Props bag */\n props: Props;\n\n /** Optional key (normalized by runtime) */\n key?: string | number | null;\n}\n\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace JSX {\n // Components must be synchronous\n type Element = JSXElement;\n\n interface IntrinsicElements {\n [elem: string]: Props;\n }\n\n interface ElementAttributesProperty {\n props: Props;\n }\n }\n}\n\nexport {};\n"],"mappings":";;;;;;;;;;;AAAA,IAYa,cACA;AAbb;AAAA;AAAA;AAYO,IAAM,eAAe,uBAAO,IAAI,cAAc;AAC9C,IAAM,WAAW,uBAAO,IAAI,eAAe;AAAA;AAAA;","names":[]}
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
logger,
|
|
7
7
|
mountComponent,
|
|
8
8
|
resolveRoute
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-MIPES65F.js";
|
|
10
10
|
|
|
11
11
|
// src/router/navigate.ts
|
|
12
12
|
init_component();
|
|
@@ -81,4 +81,4 @@ export {
|
|
|
81
81
|
initializeNavigation,
|
|
82
82
|
cleanupNavigation
|
|
83
83
|
};
|
|
84
|
-
//# sourceMappingURL=chunk-
|
|
84
|
+
//# sourceMappingURL=chunk-RJWOOUYV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/router/navigate.ts"],"sourcesContent":["/**\n * Client-side navigation with History API\n */\n\nimport { resolveRoute, lockRouteRegistration } from './route';\nimport {\n mountComponent,\n cleanupComponent,\n type ComponentInstance,\n} from '../runtime/component';\nimport { logger } from '../dev/logger';\n\n// Global app state for navigation\nlet currentInstance: ComponentInstance | null = null;\n\n/**\n * Register the current app instance (called by createIsland)\n */\nexport function registerAppInstance(\n instance: ComponentInstance,\n _path: string\n): void {\n currentInstance = instance;\n // Lock further route registrations after the app has started — but allow tests to register routes.\n // Enforce only in production to avoid breaking test infra which registers routes dynamically.\n if (process.env.NODE_ENV === 'production') {\n lockRouteRegistration();\n }\n}\n\n/**\n * Navigate to a new path\n * Updates URL, resolves route, and re-mounts app with new handler\n */\nexport function navigate(path: string): void {\n if (typeof window === 'undefined') {\n // SSR context\n return;\n }\n\n // Resolve the new path to a route\n const resolved = resolveRoute(path);\n\n if (!resolved) {\n if (process.env.NODE_ENV !== 'production') {\n logger.warn(`No route found for path: ${path}`);\n }\n return;\n }\n\n // Update browser history\n window.history.pushState({ path }, '', path);\n\n // Re-render with the new route handler and params\n if (currentInstance) {\n // Cleanup previous route (abort pending operations)\n cleanupComponent(currentInstance);\n\n // The route handler IS the component function\n // It takes params as props and renders the route\n currentInstance.fn = resolved.handler as ComponentInstance['fn'];\n currentInstance.props = resolved.params;\n\n // Reset state to prevent leakage from previous route\n // Each route navigation starts completely fresh\n currentInstance.stateValues = [];\n currentInstance.expectedStateIndices = [];\n currentInstance.firstRenderComplete = false;\n currentInstance.stateIndexCheck = -1;\n // Increment generation to invalidate pending async evaluations from previous route\n currentInstance.evaluationGeneration++;\n currentInstance.notifyUpdate = null;\n\n // CRITICAL FIX: Create new AbortController for new route\n // Old controller is already aborted; we need a fresh one for async operations\n currentInstance.abortController = new AbortController();\n\n // Re-execute and re-mount component\n mountComponent(currentInstance);\n }\n}\n\n/**\n * Handle browser back/forward buttons\n */\nfunction handlePopState(_event: PopStateEvent): void {\n const path = window.location.pathname;\n\n if (!currentInstance) {\n return;\n }\n\n const resolved = resolveRoute(path);\n\n if (resolved) {\n // Cleanup old component\n cleanupComponent(currentInstance);\n\n // The route handler IS the component function\n currentInstance.fn = resolved.handler as ComponentInstance['fn'];\n currentInstance.props = resolved.params;\n\n // Reset state to prevent leakage from previous route\n currentInstance.stateValues = [];\n currentInstance.expectedStateIndices = [];\n currentInstance.firstRenderComplete = false;\n currentInstance.stateIndexCheck = -1;\n // Increment generation to invalidate pending async evaluations from previous route\n currentInstance.evaluationGeneration++;\n currentInstance.notifyUpdate = null;\n\n // CRITICAL FIX: Create new AbortController for back/forward navigation\n currentInstance.abortController = new AbortController();\n\n mountComponent(currentInstance);\n }\n}\n\n/**\n * Setup popstate listener for browser navigation\n */\nexport function initializeNavigation(): void {\n if (typeof window !== 'undefined') {\n window.addEventListener('popstate', handlePopState);\n }\n}\n\n/**\n * Cleanup navigation listeners\n */\nexport function cleanupNavigation(): void {\n if (typeof window !== 'undefined') {\n window.removeEventListener('popstate', handlePopState);\n }\n}\n"],"mappings":";;;;;;;;;;;AAKA;AAKA;AAGA,IAAI,kBAA4C;AAKzC,SAAS,oBACd,UACA,OACM;AACN,oBAAkB;AAGlB,MAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,0BAAsB;AAAA,EACxB;AACF;AAMO,SAAS,SAAS,MAAoB;AAC3C,MAAI,OAAO,WAAW,aAAa;AAEjC;AAAA,EACF;AAGA,QAAM,WAAW,aAAa,IAAI;AAElC,MAAI,CAAC,UAAU;AACb,QAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,aAAO,KAAK,4BAA4B,IAAI,EAAE;AAAA,IAChD;AACA;AAAA,EACF;AAGA,SAAO,QAAQ,UAAU,EAAE,KAAK,GAAG,IAAI,IAAI;AAG3C,MAAI,iBAAiB;AAEnB,qBAAiB,eAAe;AAIhC,oBAAgB,KAAK,SAAS;AAC9B,oBAAgB,QAAQ,SAAS;AAIjC,oBAAgB,cAAc,CAAC;AAC/B,oBAAgB,uBAAuB,CAAC;AACxC,oBAAgB,sBAAsB;AACtC,oBAAgB,kBAAkB;AAElC,oBAAgB;AAChB,oBAAgB,eAAe;AAI/B,oBAAgB,kBAAkB,IAAI,gBAAgB;AAGtD,mBAAe,eAAe;AAAA,EAChC;AACF;AAKA,SAAS,eAAe,QAA6B;AACnD,QAAM,OAAO,OAAO,SAAS;AAE7B,MAAI,CAAC,iBAAiB;AACpB;AAAA,EACF;AAEA,QAAM,WAAW,aAAa,IAAI;AAElC,MAAI,UAAU;AAEZ,qBAAiB,eAAe;AAGhC,oBAAgB,KAAK,SAAS;AAC9B,oBAAgB,QAAQ,SAAS;AAGjC,oBAAgB,cAAc,CAAC;AAC/B,oBAAgB,uBAAuB,CAAC;AACxC,oBAAgB,sBAAsB;AACtC,oBAAgB,kBAAkB;AAElC,oBAAgB;AAChB,oBAAgB,eAAe;AAG/B,oBAAgB,kBAAkB,IAAI,gBAAgB;AAEtD,mBAAe,eAAe;AAAA,EAChC;AACF;AAKO,SAAS,uBAA6B;AAC3C,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO,iBAAiB,YAAY,cAAc;AAAA,EACpD;AACF;AAKO,SAAS,oBAA0B;AACxC,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO,oBAAoB,YAAY,cAAc;AAAA,EACvD;AACF;","names":[]}
|