@estjs/server 0.0.15-beta.14 → 0.0.15-beta.17
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/dist/server.cjs.js +2 -1
- package/dist/server.cjs.js.map +1 -1
- package/dist/server.d.cts +166 -26
- package/dist/server.d.ts +166 -26
- package/dist/server.dev.cjs.js +401 -0
- package/dist/server.dev.cjs.js.map +1 -0
- package/dist/server.dev.esm.js +368 -0
- package/dist/server.dev.esm.js.map +1 -0
- package/dist/server.esm.js +2 -1
- package/dist/server.esm.js.map +1 -1
- package/package.json +4 -3
package/dist/server.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils.ts","../src/render.ts","../../signals/dist/signals.dev.esm.js","../src/attrs.ts"],"names":["convertToString","content","isSvg","isNil","isString","isArray","item","isFunction","ROOT_ELEMENT_REGEX","INDEX_ATTRIBUTE_REGEX","COMMENT_REGEX","addAttributes","htmlContent","hydrationId","renderToString","component","props","error","resetHydrationKey","scope","createScope","result","runWithScope","disposeScope","render","templates","hydrationKey","components","parts","templateLen","componentLen","i","createSSGComponent","isSignal","value","isComputed","normalizeProps","className","style","normalizeClassName","normalizeStyle","setSSGAttr","attrName","attrValue","normalizedStyle","styleToString","normalizedClassName"],"mappings":"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","file":"server.esm.js","sourcesContent":["import { isArray, isFunction, isNil, isString } from '@estjs/shared';\n\n/**\n * Convert content to string for SSR output\n *\n * @param content - the content to convert\n * @param isSvg - whether the content is SVG\n * @returns the content as a string\n */\nexport function convertToString(content: unknown, isSvg = false): string {\n if (isNil(content)) {\n return '';\n }\n\n if (isString(content)) {\n return content;\n }\n\n if (isArray(content)) {\n return (content as unknown[]).map((item: unknown) => convertToString(item, isSvg)).join('');\n }\n\n if (isFunction(content)) {\n return convertToString((content as () => unknown)(), isSvg);\n }\n\n return String(content);\n}\n\n/** Regex to match the root element */\n// eslint-disable-next-line regexp/no-super-linear-backtracking\nconst ROOT_ELEMENT_REGEX = /^<([a-z]+)(\\s*)([^>]*)>/i;\n/** Regex to match data-idx attributes */\nconst INDEX_ATTRIBUTE_REGEX = /data-idx=\"(\\d+)\"/g;\n/** Regex to match HTML comments */\nconst COMMENT_REGEX = /<!--(.*?)-->/g;\n\n/**\n * Add hydration attributes to HTML content\n *\n * @param htmlContent - the html content\n * @param hydrationId - the hydration id\n * @returns the html content with hydration attributes\n */\nexport function addAttributes(htmlContent: string, hydrationId: string): string {\n return htmlContent\n .replace(ROOT_ELEMENT_REGEX, `<$1$2$3 data-hk=\"${hydrationId}\">`)\n .replaceAll(INDEX_ATTRIBUTE_REGEX, `data-idx=\"${hydrationId}-$1\"`)\n .replaceAll(COMMENT_REGEX, `<!--${hydrationId}-$1-->`);\n}\n","import { error, isFunction } from '@estjs/shared';\nimport {\n type ComponentFn,\n type ComponentProps,\n createScope,\n disposeScope,\n resetHydrationKey,\n runWithScope,\n} from '@estjs/template';\nimport { addAttributes, convertToString } from './utils';\n\n/**\n * Render a component to HTML string\n * @param {ComponentFn} component - the component to render\n * @param {ComponentProps} props - the props to pass to the component\n * @returns {string} the rendered HTML string\n */\nexport function renderToString<P extends ComponentProps = ComponentProps>(\n component: ComponentFn<P>,\n props: P | ComponentProps = {},\n): string {\n if (!isFunction(component)) {\n error('Component must be a function');\n return '';\n }\n\n // Reset the hydration key counter\n resetHydrationKey();\n\n // Create root scope for SSR to support provide/inject\n const scope = createScope(null);\n\n let result: unknown;\n try {\n // Render the component within scope\n result = runWithScope(scope, () => component(props as P));\n } finally {\n // Clean up scope after rendering\n disposeScope(scope);\n }\n\n // Convert the result to string\n return convertToString(result);\n}\n\n/**\n * Render template with components (used by babel plugin in SSG mode)\n * @param {string[]} templates - the template fragments\n * @param {string} hydrationKey - the hydration key\n * @param {...string[]} components - the rendered component strings\n * @returns {string} the rendered HTML string\n */\nexport function render(templates: string[], hydrationKey: string, ...components: string[]): string {\n /**\n * JSX source code:\n * <div>\n * <div>\n * <Component1 />\n * <Component2 />\n * </div>\n * <Component3 />\n * </div>\n *\n * Compiles to:\n *\n * let _tmpl = [\n * '<div><div>',\n * '</div>',\n * '</div>',\n * ]\n *\n * function component(props) {\n * return render(_tmpl, getHydrationKey(),\n * createSSGComponent(Component1, {}),\n * createSSGComponent(Component2, {}),\n * createSSGComponent(Component3, {})\n * );\n * }\n */\n\n // Build content using array join for better performance\n const parts: string[] = [];\n const templateLen = templates.length;\n const componentLen = components.length;\n\n for (let i = 0; i < templateLen; i++) {\n parts.push(templates[i]);\n if (i < componentLen && components[i]) {\n parts.push(convertToString(components[i]));\n }\n }\n\n const content = parts.join('');\n\n // Add hydration key attribute\n return addAttributes(content, hydrationKey);\n}\n\n/**\n * Create a SSG component (renders component to string)\n * @param {ComponentFn} component - the component to create\n * @param {ComponentProps} props - the props to pass to the component\n * @returns {string} the rendered component as a string\n */\nexport function createSSGComponent<P extends ComponentProps = ComponentProps>(\n component: ComponentFn<P>,\n props: P | ComponentProps = {},\n): string {\n if (!isFunction(component)) {\n error('createSSGComponent: Component is not a function');\n return '';\n }\n\n // Create child scope inheriting from current active scope (if any)\n // This allows nested components to access parent's provided values\n const scope = createScope();\n\n let result: unknown;\n try {\n // Render the component within scope\n result = runWithScope(scope, () => component(props as P));\n } finally {\n // Clean up scope after rendering\n disposeScope(scope);\n }\n\n return convertToString(result);\n}\n","import { isFunction, isObject, warn, error, isPlainObject, hasChanged, isArray, isSet, isMap, isWeakMap, isWeakSet, hasOwn, isStringNumber } from '@estjs/shared';\n\nvar __defProp = Object.defineProperty;\nvar __defProps = Object.defineProperties;\nvar __getOwnPropDescs = Object.getOwnPropertyDescriptors;\nvar __getOwnPropSymbols = Object.getOwnPropertySymbols;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __propIsEnum = Object.prototype.propertyIsEnumerable;\nvar __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;\nvar __spreadValues = (a, b) => {\n for (var prop in b || (b = {}))\n if (__hasOwnProp.call(b, prop))\n __defNormalProp(a, prop, b[prop]);\n if (__getOwnPropSymbols)\n for (var prop of __getOwnPropSymbols(b)) {\n if (__propIsEnum.call(b, prop))\n __defNormalProp(a, prop, b[prop]);\n }\n return a;\n};\nvar __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));\n\n// src/constants.ts\nvar TriggerOpTypes = {\n SET: \"SET\",\n ADD: \"ADD\",\n DELETE: \"DELETE\",\n CLEAR: \"CLEAR\"\n};\nvar ARRAY_KEY = /* @__PURE__ */ Symbol(\"Array_Key\" );\nvar COLLECTION_KEY = /* @__PURE__ */ Symbol(\"Collection_Key\" );\nvar WEAK_COLLECTION_KEY = /* @__PURE__ */ Symbol(\"WeakCollection_Key\" );\nvar ITERATE_KEY = /* @__PURE__ */ Symbol(\"Iterate_Key\" );\nvar ARRAY_ITERATE_KEY = /* @__PURE__ */ Symbol(\"Array_Iterate_Key\" );\n\n// src/propagation.ts\nfunction enqueueEffect(effect2) {\n var _a5;\n (_a5 = effect2 == null ? void 0 : effect2.notify) == null ? void 0 : _a5.call(effect2);\n}\nfunction propagate(link) {\n let next = link.nextSubLink;\n let stack;\n top: do {\n const sub = link.subNode;\n const watcherBit = sub.flag & 2 /* WATCHING */;\n let flags = sub.flag;\n if (!(flags & (16 /* DIRTY */ | 32 /* PENDING */ | 8 /* RECURSED */ | 4 /* RECURSED_CHECK */))) {\n sub.flag = flags | 32 /* PENDING */;\n if (watcherBit) {\n enqueueEffect(sub);\n }\n } else if (!(flags & (8 /* RECURSED */ | 4 /* RECURSED_CHECK */))) {\n flags = 0 /* NONE */;\n } else if (!(flags & 4 /* RECURSED_CHECK */)) {\n sub.flag = flags & -9 /* RECURSED */ | 32 /* PENDING */;\n } else if (!(flags & (16 /* DIRTY */ | 32 /* PENDING */)) && isValidLink(link, sub)) {\n sub.flag = flags | (8 /* RECURSED */ | 32 /* PENDING */);\n if (watcherBit) {\n enqueueEffect(sub);\n }\n flags &= 1 /* MUTABLE */;\n } else {\n flags = 0 /* NONE */;\n }\n if (flags & 1 /* MUTABLE */) {\n const subSubs = sub.subLink;\n if (subSubs !== void 0) {\n const nextSub = subSubs.nextSubLink;\n if (nextSub !== void 0) {\n stack = { value: next, prev: stack };\n next = nextSub;\n }\n link = subSubs;\n continue;\n }\n }\n if ((link = next) !== void 0) {\n next = link.nextSubLink;\n continue;\n }\n while (stack !== void 0) {\n link = stack.value;\n stack = stack.prev;\n if (link !== void 0) {\n next = link.nextSubLink;\n continue top;\n }\n }\n break;\n } while (true);\n}\nfunction shallowPropagate(link) {\n while (link) {\n const sub = link.subNode;\n const flags = sub.flag;\n if ((flags & (32 /* PENDING */ | 16 /* DIRTY */)) === 32 /* PENDING */) {\n sub.flag = flags | 16 /* DIRTY */;\n if ((flags & (2 /* WATCHING */ | 4 /* RECURSED_CHECK */)) === 2 /* WATCHING */) {\n enqueueEffect(sub);\n }\n }\n link = link.nextSubLink;\n }\n}\n\n// src/link.ts\nvar currentLinkVersion = 0;\nvar activeSub;\nvar isUntracking = false;\nfunction linkReactiveNode(depNode, subNode) {\n if (isUntracking) {\n return void 0;\n }\n const prevDep = subNode.depLinkTail;\n if (prevDep && prevDep.depNode === depNode) {\n return prevDep;\n }\n const nextDep = prevDep ? prevDep.nextDepLink : subNode.depLink;\n if (nextDep && nextDep.depNode === depNode) {\n nextDep.version = currentLinkVersion;\n subNode.depLinkTail = nextDep;\n return nextDep;\n }\n const prevSub = depNode.subLinkTail;\n if (prevSub && prevSub.version === currentLinkVersion && prevSub.subNode === subNode) {\n subNode.depLinkTail = prevSub;\n return prevSub;\n }\n const newLink = {\n version: currentLinkVersion,\n depNode,\n subNode,\n // Subscriber chain pointers (horizontal)\n prevSubLink: prevSub,\n nextSubLink: void 0,\n // Dependency chain pointers (vertical)\n prevDepLink: prevDep,\n nextDepLink: nextDep\n };\n if (nextDep) {\n nextDep.prevDepLink = newLink;\n }\n if (prevDep) {\n prevDep.nextDepLink = newLink;\n } else {\n subNode.depLink = newLink;\n }\n if (prevSub) {\n prevSub.nextSubLink = newLink;\n } else {\n depNode.subLink = newLink;\n }\n depNode.subLinkTail = newLink;\n subNode.depLinkTail = newLink;\n {\n if (subNode.onTrack && isFunction(subNode == null ? void 0 : subNode.onTrack)) {\n subNode.onTrack({\n effect: subNode,\n target: depNode,\n type: \"get\",\n key: void 0\n });\n }\n }\n return newLink;\n}\nfunction unlinkReactiveNode(linkNode, subNode = linkNode.subNode) {\n const depNode = linkNode.depNode;\n const prevSub = linkNode.prevSubLink;\n const nextSub = linkNode.nextSubLink;\n const prevDep = linkNode.prevDepLink;\n const nextDep = linkNode.nextDepLink;\n if (nextDep) {\n nextDep.prevDepLink = prevDep;\n } else {\n subNode.depLinkTail = prevDep;\n }\n if (prevDep) {\n prevDep.nextDepLink = nextDep;\n } else {\n subNode.depLink = nextDep;\n }\n if (nextSub) {\n nextSub.prevSubLink = prevSub;\n } else {\n depNode.subLinkTail = prevSub;\n }\n if (prevSub) {\n prevSub.nextSubLink = nextSub;\n } else {\n depNode.subLink = nextSub;\n if (nextSub === void 0) {\n let toRemove = depNode.depLink;\n while (toRemove) {\n toRemove = unlinkReactiveNode(toRemove, depNode);\n }\n depNode.depLinkTail = void 0;\n depNode.flag |= 16 /* DIRTY */;\n {\n if (depNode.depLink) {\n error(\n \"[Link] Cascading cleanup failed: depNode still has dependency links. This indicates a bug in the unlinking logic.\"\n );\n }\n }\n }\n }\n return nextDep;\n}\nfunction checkDirty(link, sub) {\n let stack;\n let checkDepth = 0;\n let dirty = false;\n top: do {\n let currentDirty = false;\n if (sub.flag & 16 /* DIRTY */) {\n currentDirty = true;\n } else {\n const dep = link.depNode;\n const depFlags = dep.flag;\n if ((depFlags & (1 /* MUTABLE */ | 16 /* DIRTY */)) === (1 /* MUTABLE */ | 16 /* DIRTY */)) {\n const subs = dep.subLink;\n if (subs && subs.nextSubLink) {\n shallowPropagate2(subs);\n }\n currentDirty = true;\n } else if ((depFlags & (1 /* MUTABLE */ | 32 /* PENDING */)) === (1 /* MUTABLE */ | 32 /* PENDING */)) {\n if (dep.depLink) {\n stack = { link, prev: stack };\n link = dep.depLink;\n sub = dep;\n ++checkDepth;\n continue top;\n } else {\n dep.flag &= -33 /* PENDING */;\n }\n } else if (depFlags & 32 /* PENDING */) {\n dep.flag &= -33 /* PENDING */;\n }\n }\n if (!currentDirty && link.nextDepLink !== void 0) {\n link = link.nextDepLink;\n continue top;\n }\n dirty = currentDirty;\n while (checkDepth--) {\n link = stack.link;\n stack = stack.prev;\n sub = link.subNode;\n const checkedDep = link.depNode;\n if (dirty) {\n checkedDep.flag = checkedDep.flag & -33 /* PENDING */ | 16 /* DIRTY */;\n } else {\n checkedDep.flag &= -33 /* PENDING */;\n }\n if (checkedDep.flag & 16 /* DIRTY */) {\n dirty = true;\n }\n if (!dirty && link.nextDepLink !== void 0) {\n link = link.nextDepLink;\n continue top;\n }\n }\n if (dirty) {\n sub.flag = sub.flag & -33 /* PENDING */ | 16 /* DIRTY */;\n } else {\n sub.flag &= -33 /* PENDING */;\n }\n return dirty;\n } while (true);\n}\nfunction shallowPropagate2(link) {\n while (link) {\n const sub = link.subNode;\n const flags = sub.flag;\n if ((flags & (32 /* PENDING */ | 16 /* DIRTY */)) === 32 /* PENDING */) {\n sub.flag = flags | 16 /* DIRTY */;\n }\n link = link.nextSubLink;\n }\n}\nfunction setActiveSub(sub) {\n const prev = activeSub;\n activeSub = sub;\n return prev;\n}\nfunction startTracking(sub) {\n currentLinkVersion++;\n sub.depLinkTail = void 0;\n sub.flag = sub.flag & -57 | 4 /* RECURSED_CHECK */;\n return setActiveSub(sub);\n}\nfunction endTracking(sub, prevSub) {\n activeSub = prevSub;\n const depsTail = sub.depLinkTail;\n let toRemove = depsTail ? depsTail.nextDepLink : sub.depLink;\n while (toRemove) {\n toRemove = unlinkReactiveNode(toRemove, sub);\n }\n sub.flag &= -5 /* RECURSED_CHECK */;\n}\nfunction untrack(fn) {\n const prevSub = setActiveSub(void 0);\n const prevUntracking = isUntracking;\n isUntracking = true;\n try {\n return fn();\n } finally {\n isUntracking = prevUntracking;\n setActiveSub(prevSub);\n }\n}\nfunction isValidLink(checkLink, sub) {\n let link = sub.depLinkTail;\n while (link) {\n if (link === checkLink) {\n return true;\n }\n link = link.prevDepLink;\n }\n return false;\n}\nvar targetMap = /* @__PURE__ */ new WeakMap();\nvar triggerVersion = 0;\nfunction collectTriggeredEffects(dep, effects, version) {\n if (!dep) {\n return;\n }\n dep.forEach((effect2) => {\n if (effect2.flag & 2 /* WATCHING */ && !effect2._active) {\n dep.delete(effect2);\n return;\n }\n if (effect2._triggerVersion === version) {\n return;\n }\n effect2._triggerVersion = version;\n effects.push(effect2);\n });\n}\nfunction track(target, key) {\n if (!activeSub || isUntracking) {\n return;\n }\n let depsMap = targetMap.get(target);\n if (!depsMap) {\n depsMap = /* @__PURE__ */ new Map();\n targetMap.set(target, depsMap);\n }\n let dep = depsMap.get(key);\n if (!dep) {\n dep = /* @__PURE__ */ new Set();\n depsMap.set(key, dep);\n }\n const sizeBefore = dep.size ;\n dep.add(activeSub);\n if (dep.size !== sizeBefore && isFunction(activeSub.onTrack)) {\n activeSub.onTrack({\n effect: activeSub,\n target,\n type: \"get\",\n key\n });\n }\n}\nfunction trigger(target, type, key, newValue) {\n var _a5;\n const depsMap = targetMap.get(target);\n if (!depsMap) {\n return;\n }\n const effects = [];\n const version = ++triggerVersion;\n if (key !== void 0) {\n if (Array.isArray(key)) {\n for (const element of key) {\n collectTriggeredEffects(depsMap.get(element), effects, version);\n }\n } else {\n collectTriggeredEffects(depsMap.get(key), effects, version);\n }\n }\n if (type === \"ADD\" || type === \"DELETE\" || type === \"CLEAR\") {\n const iterationKey = Array.isArray(target) ? ARRAY_ITERATE_KEY : ITERATE_KEY;\n collectTriggeredEffects(depsMap.get(iterationKey), effects, version);\n }\n for (const effect2 of effects) {\n if (isFunction(effect2.onTrigger)) {\n effect2.onTrigger({\n effect: effect2,\n target,\n type,\n key,\n newValue\n });\n }\n if (effect2.flag & 2 /* WATCHING */) {\n (_a5 = effect2.notify) == null ? void 0 : _a5.call(effect2);\n } else if (effect2.flag & 1 /* MUTABLE */) {\n effect2.flag |= 16 /* DIRTY */;\n if (effect2.subLink) {\n propagate(effect2.subLink);\n }\n }\n }\n}\nvar reactiveCaches = /* @__PURE__ */ new WeakMap();\nfunction toRaw(value) {\n if (!value || !isObject(value)) {\n return value;\n }\n const raw = value[\"_RAW\" /* RAW */];\n if (raw) {\n return toRaw(raw);\n }\n if (isSignal(value)) {\n return toRaw(value.peek());\n }\n return value;\n}\nvar arrayInstrumentations = createArrayInstrumentations();\nfunction createArrayInstrumentations() {\n const instrumentations = {};\n [\"includes\", \"indexOf\", \"lastIndexOf\"].forEach((key) => {\n instrumentations[key] = function(...args) {\n const arr = toRaw(this);\n track(arr, ARRAY_ITERATE_KEY);\n let res = arr[key](...args);\n if ((res === -1 || res === false) && args.length > 0) {\n const rawArgs = args.map((arg) => toRaw(arg));\n res = arr[key](...rawArgs);\n }\n return res;\n };\n });\n [\"find\", \"findIndex\", \"findLast\", \"findLastIndex\"].forEach((key) => {\n instrumentations[key] = function(...args) {\n const arr = toRaw(this);\n const isShallowMode = isShallow(this);\n track(arr, ARRAY_ITERATE_KEY);\n const res = arr[key](...args);\n if ((key === \"find\" || key === \"findLast\") && isObject(res) && !isShallowMode) {\n return reactiveImpl(res);\n }\n return res;\n };\n });\n [\"push\", \"pop\", \"shift\", \"unshift\", \"splice\", \"sort\", \"reverse\", \"fill\", \"copyWithin\"].forEach(\n (key) => {\n instrumentations[key] = function(...args) {\n const arr = toRaw(this);\n const res = Array.prototype[key].apply(arr, args);\n trigger(arr, TriggerOpTypes.SET, [ARRAY_KEY, ARRAY_ITERATE_KEY]);\n return res;\n };\n }\n );\n [\"toReversed\", \"toSorted\", \"toSpliced\"].forEach((key) => {\n instrumentations[key] = function(...args) {\n const arr = toRaw(this);\n const isShallowMode = isShallow(this);\n track(arr, ARRAY_ITERATE_KEY);\n if (key === \"toSpliced\") {\n for (let i = 0, l = arr.length; i < l; i++) {\n track(arr, `${i}`);\n }\n }\n const res = Array.prototype[key].apply(arr, args);\n if (!Array.isArray(res)) {\n return res;\n }\n return res.map((item) => isObject(item) ? reactiveImpl(item, isShallowMode) : item);\n };\n });\n [\"concat\", \"slice\", \"filter\", \"map\", \"flatMap\", \"flat\"].forEach((key) => {\n instrumentations[key] = function(...args) {\n const arr = toRaw(this);\n track(arr, ARRAY_ITERATE_KEY);\n const res = Array.prototype[key].apply(arr, args);\n return res;\n };\n });\n [\"join\", \"toString\", \"toLocaleString\"].forEach((key) => {\n instrumentations[key] = function(...args) {\n const arr = toRaw(this);\n track(arr, ARRAY_ITERATE_KEY);\n return Array.prototype[key].apply(arr, args);\n };\n });\n [\"values\", \"keys\", \"entries\", Symbol.iterator].forEach((key) => {\n instrumentations[key] = function() {\n const arr = toRaw(this);\n const isShallowMode = isShallow(this);\n track(arr, ARRAY_KEY);\n const rawIterator = key === Symbol.iterator ? arr[Symbol.iterator]() : arr[key]();\n return {\n next() {\n const { value, done } = rawIterator.next();\n if (done) {\n return { value, done };\n }\n if (Array.isArray(value)) {\n return {\n value: value.map((v) => isObject(v) ? reactiveImpl(v, isShallowMode) : v),\n done\n };\n }\n return {\n value: isObject(value) ? reactiveImpl(value, isShallowMode) : value,\n done\n };\n },\n [Symbol.iterator]() {\n return this;\n }\n };\n };\n });\n return instrumentations;\n}\nvar arrayHandlers = (shallow) => ({\n get: (target, key, receiver) => {\n if (key === \"_RAW\" /* RAW */) {\n return target;\n }\n if (key === \"_IS_REACTIVE\" /* IS_REACTIVE */) {\n return true;\n }\n if (key === \"_IS_SHALLOW\" /* IS_SHALLOW */) {\n return shallow;\n }\n if (hasOwn(arrayInstrumentations, key)) {\n return arrayInstrumentations[key];\n }\n const value = Reflect.get(target, key, receiver);\n if (isStringNumber(key)) {\n track(target, key);\n }\n track(target, ARRAY_KEY);\n if (isObject(value) && !shallow) {\n return reactiveImpl(value);\n }\n return value;\n },\n set: (target, key, value, receiver) => {\n const oldValue = Reflect.get(target, key, receiver);\n const result = Reflect.set(target, key, value, receiver);\n if (hasChanged(value, oldValue)) {\n if (isStringNumber(key)) {\n trigger(target, TriggerOpTypes.SET, [key, ARRAY_ITERATE_KEY, ARRAY_KEY]);\n } else {\n trigger(target, TriggerOpTypes.SET, key);\n }\n }\n return result;\n }\n});\nvar shallowArrayHandlers = arrayHandlers(true);\nvar deepArrayHandlers = arrayHandlers(false);\nvar collectionHandlers = {\n get(target, key) {\n if (key === \"_IS_REACTIVE\" /* IS_REACTIVE */) {\n return true;\n }\n if (key === \"_RAW\" /* RAW */) {\n return target;\n }\n return Reflect.get(\n hasOwn(collectionInstrumentations, key) ? collectionInstrumentations : target,\n key,\n target\n );\n }\n};\nvar weakCollectionHandlers = {\n get(target, key) {\n if (key === \"_IS_REACTIVE\" /* IS_REACTIVE */) {\n return true;\n }\n if (key === \"_RAW\" /* RAW */) {\n return target;\n }\n return Reflect.get(\n hasOwn(weakInstrumentations, key) && key in target ? weakInstrumentations : target,\n key,\n target\n );\n }\n};\nvar collectionInstrumentations = {\n get(key) {\n const target = toRaw(this);\n track(target, COLLECTION_KEY);\n const value = target.get(key);\n if (isObject(value) && !isShallow(this)) {\n return reactiveImpl(value);\n }\n return value;\n },\n set(key, value) {\n const target = toRaw(this);\n const hadKey = target.has(key);\n const oldValue = target.get(key);\n const rawValue = toRaw(value);\n target.set(key, rawValue);\n if (!hadKey || hasChanged(oldValue, rawValue)) {\n trigger(target, TriggerOpTypes.SET, COLLECTION_KEY);\n }\n return this;\n },\n add(value) {\n const target = toRaw(this);\n const rawValue = toRaw(value);\n const hadValue = target.has(rawValue);\n target.add(rawValue);\n if (!hadValue) {\n trigger(target, TriggerOpTypes.ADD, COLLECTION_KEY);\n } else {\n trigger(target, TriggerOpTypes.SET, COLLECTION_KEY);\n }\n return this;\n },\n has(key) {\n const target = toRaw(this);\n track(target, COLLECTION_KEY);\n const hasKey = target.has(key);\n if (!hasKey && isObject(key)) {\n return target.has(toRaw(key));\n }\n return hasKey;\n },\n delete(key) {\n const target = toRaw(this);\n const hadKey = target.has(key);\n let result = target.delete(key);\n if (!result && isObject(key)) {\n result = target.delete(toRaw(key));\n }\n if (hadKey || result) {\n trigger(target, TriggerOpTypes.DELETE, COLLECTION_KEY);\n }\n return result;\n },\n clear() {\n const target = toRaw(this);\n const hadItems = target.size > 0;\n const result = target.clear();\n if (hadItems) {\n trigger(target, TriggerOpTypes.CLEAR, COLLECTION_KEY);\n }\n return result;\n },\n forEach(callback, thisArg) {\n const target = toRaw(this);\n const isShallowMode = isShallow(this);\n track(target, COLLECTION_KEY);\n target.forEach((value, key) => {\n const wrappedValue = isShallowMode || !isObject(value) ? value : reactiveImpl(value);\n const wrappedKey = isShallowMode || !isObject(key) ? key : reactiveImpl(key);\n callback.call(thisArg, wrappedValue, wrappedKey, this);\n });\n },\n [Symbol.iterator]() {\n const target = toRaw(this);\n const isShallowMode = isShallow(this);\n track(target, COLLECTION_KEY);\n const rawIterator = target[Symbol.iterator]();\n return {\n next() {\n const { value, done } = rawIterator.next();\n if (done) {\n return { value, done };\n }\n if (isShallowMode) {\n return { value, done };\n }\n if (Array.isArray(value)) {\n return {\n value: value.map((v) => isObject(v) ? reactiveImpl(v) : v),\n done\n };\n }\n return {\n value: isObject(value) ? reactiveImpl(value) : value,\n done\n };\n },\n [Symbol.iterator]() {\n return this;\n }\n };\n },\n get size() {\n const target = toRaw(this);\n track(target, COLLECTION_KEY);\n return target.size;\n },\n keys() {\n const target = toRaw(this);\n const isShallowMode = isShallow(this);\n track(target, COLLECTION_KEY);\n const rawIterator = target.keys();\n return {\n next() {\n const { value, done } = rawIterator.next();\n if (done) {\n return { value, done };\n }\n return {\n value: isShallowMode || !isObject(value) ? value : reactiveImpl(value),\n done\n };\n },\n [Symbol.iterator]() {\n return this;\n }\n };\n },\n values() {\n const target = toRaw(this);\n const isShallowMode = isShallow(this);\n track(target, COLLECTION_KEY);\n const rawIterator = target.values();\n return {\n next() {\n const { value, done } = rawIterator.next();\n if (done) {\n return { value, done };\n }\n return {\n value: isShallowMode || !isObject(value) ? value : reactiveImpl(value),\n done\n };\n },\n [Symbol.iterator]() {\n return this;\n }\n };\n },\n entries() {\n const target = toRaw(this);\n const isShallowMode = isShallow(this);\n track(target, COLLECTION_KEY);\n const rawIterator = target.entries();\n return {\n next() {\n const { value, done } = rawIterator.next();\n if (done) {\n return { value, done };\n }\n if (isShallowMode) {\n return { value, done };\n }\n return {\n value: value.map((v) => isObject(v) ? reactiveImpl(v) : v),\n done\n };\n },\n [Symbol.iterator]() {\n return this;\n }\n };\n }\n};\nvar weakInstrumentations = {\n get(key) {\n const target = toRaw(this);\n track(target, WEAK_COLLECTION_KEY);\n let value = target.get(key);\n if (value === void 0 && isReactive(key)) {\n value = target.get(toRaw(key));\n }\n if (isObject(value) && !isShallow(this)) {\n return reactiveImpl(value);\n }\n return value;\n },\n set(key, value) {\n const target = toRaw(this);\n const rawKey = toRaw(key);\n const hadKey = target.has(rawKey);\n const oldValue = target.get(rawKey);\n const rawValue = toRaw(value);\n target.set(rawKey, rawValue);\n if (!hadKey || hasChanged(oldValue, rawValue)) {\n trigger(target, TriggerOpTypes.SET, WEAK_COLLECTION_KEY);\n }\n return this;\n },\n add(value) {\n const target = toRaw(this);\n const rawValue = toRaw(value);\n const hadValue = target.has(rawValue);\n target.add(rawValue);\n if (!hadValue) {\n trigger(target, TriggerOpTypes.ADD, WEAK_COLLECTION_KEY);\n }\n return this;\n },\n has(key) {\n const target = toRaw(this);\n track(target, WEAK_COLLECTION_KEY);\n let hasKey = target.has(key);\n if (!hasKey && isReactive(key)) {\n hasKey = target.has(toRaw(key));\n }\n return hasKey;\n },\n delete(key) {\n const target = toRaw(this);\n const rawKey = toRaw(key);\n const hadKey = target.has(rawKey);\n const result = target.delete(rawKey);\n if (hadKey || result) {\n trigger(target, TriggerOpTypes.DELETE, WEAK_COLLECTION_KEY);\n }\n return result;\n }\n};\nvar objectHandlers = (shallow) => ({\n get(target, key, receiver) {\n if (key === \"_RAW\" /* RAW */) {\n return target;\n }\n if (key === \"_IS_REACTIVE\" /* IS_REACTIVE */) {\n return true;\n }\n if (key === \"_IS_SHALLOW\" /* IS_SHALLOW */) {\n return shallow;\n }\n const value = Reflect.get(target, key, receiver);\n const valueUnwrapped = isSignal(value) ? value.value : value;\n track(target, key);\n if (isObject(valueUnwrapped) && !shallow) {\n return reactiveImpl(valueUnwrapped);\n }\n return valueUnwrapped;\n },\n set: (target, key, value, receiver) => {\n const oldValue = Reflect.get(target, key, receiver);\n const result = Reflect.set(target, key, toRaw(value), receiver);\n if (hasChanged(value, oldValue)) {\n trigger(target, TriggerOpTypes.SET, key, value);\n }\n return result;\n },\n deleteProperty: (target, key) => {\n const hadKey = hasOwn(target, key);\n const result = Reflect.deleteProperty(target, key);\n if (hadKey && result) {\n trigger(target, TriggerOpTypes.DELETE, key, void 0);\n }\n return result;\n }\n});\nvar shallowObjectHandlers = objectHandlers(true);\nvar deepObjectHandlers = objectHandlers(false);\nfunction reactiveImpl(target, shallow = false) {\n if (!isObject(target)) {\n return target;\n }\n if (isReactive(target)) {\n return target;\n }\n const existingProxy = reactiveCaches.get(target);\n if (existingProxy) {\n return existingProxy;\n }\n let handler;\n if (isArray(target)) {\n handler = shallow ? shallowArrayHandlers : deepArrayHandlers;\n } else if (isSet(target) || isMap(target)) {\n handler = collectionHandlers;\n } else if (isWeakMap(target) || isWeakSet(target)) {\n handler = weakCollectionHandlers;\n } else {\n handler = shallow ? shallowObjectHandlers : deepObjectHandlers;\n }\n const proxy = new Proxy(target, handler);\n reactiveCaches.set(target, proxy);\n return proxy;\n}\nfunction isReactive(target) {\n return !!(target && target[\"_IS_REACTIVE\" /* IS_REACTIVE */]);\n}\nfunction reactive(target) {\n if (isReactive(target)) {\n return target;\n }\n if (isSignal(target)) {\n return target;\n }\n return reactiveImpl(target);\n}\nfunction shallowReactive(target) {\n if (isReactive(target)) {\n return target;\n }\n if (isSignal(target)) {\n return target;\n }\n return reactiveImpl(target, true);\n}\nfunction isShallow(value) {\n return !!(value && value[\"_IS_SHALLOW\" /* IS_SHALLOW */]);\n}\nvar toReactive = (value) => isObject(value) ? reactive(value) : value;\n\n// src/signal.ts\nvar _a;\n_a = \"_IS_SIGNAL\" /* IS_SIGNAL */;\nvar SignalImpl = class {\n /**\n * Create a new Signal with the given initial value.\n *\n * @param value - Initial value\n * @param shallow - Whether only the top level should be reactive\n */\n constructor(value, shallow = false) {\n this.flag = 1 /* MUTABLE */;\n // Mark whether it's shallow reactive\n // @ts-ignore: used internally by isSignal typeguard\n this[_a] = true;\n const unwrapped = toRaw(value);\n this._rawValue = unwrapped;\n this[\"_IS_SHALLOW\" /* IS_SHALLOW */] = shallow;\n if (!isObject(unwrapped)) {\n this._value = unwrapped;\n } else {\n if (isReactive(value)) {\n this._value = value;\n } else {\n this._value = shallow ? shallowReactive(unwrapped) : reactive(unwrapped);\n }\n }\n }\n // dep getter, returns itself for dependency collection\n get dep() {\n return this;\n }\n get value() {\n const sub = activeSub;\n if (sub) {\n linkReactiveNode(this, sub);\n }\n const flags = this.flag;\n if (flags & 16 /* DIRTY */ && this.shouldUpdate()) {\n const subs = this.subLink;\n if (subs) {\n shallowPropagate2(subs);\n }\n }\n return this._value;\n }\n // value setter, triggers update when value changes\n set value(newValue) {\n if (isSignal(newValue)) {\n {\n warn(\n \"Setting a signal value to another signal is not recommended. The value will be unwrapped automatically.\"\n );\n }\n newValue = newValue.peek();\n }\n const originalValue = newValue;\n const rawValue = toRaw(newValue);\n if (!hasChanged(this._rawValue, rawValue)) {\n return;\n }\n this._oldValue = this._rawValue;\n this._rawValue = rawValue;\n this.flag |= 16 /* DIRTY */;\n if (!isObject(rawValue)) {\n this._value = rawValue;\n } else if (isReactive(originalValue)) {\n this._value = originalValue;\n } else {\n const shallow = this[\"_IS_SHALLOW\" /* IS_SHALLOW */];\n this._value = shallow ? shallowReactive(rawValue) : reactive(rawValue);\n }\n const subs = this.subLink;\n if (subs) {\n propagate(subs);\n }\n }\n // Check if the value should be updated\n shouldUpdate() {\n this.flag &= -17 /* DIRTY */;\n if (!(\"_oldValue\" in this)) {\n return true;\n }\n const changed = hasChanged(this._oldValue, this._rawValue);\n this._oldValue = this._rawValue;\n return changed;\n }\n // Get current value without triggering dependency tracking\n peek() {\n return this._value;\n }\n // set method is an alias for the value setter\n set(value) {\n this.value = value;\n }\n // Update value using an updater function\n update(updater) {\n const nextValue = updater(this.peek());\n if (isSignal(nextValue)) {\n {\n warn(\n \"Returning a signal from an update function is not recommended. The value will be unwrapped.\"\n );\n }\n this.value = nextValue.peek();\n } else {\n this.value = nextValue;\n }\n }\n};\nfunction signal(value) {\n if (isSignal(value)) {\n {\n warn(\n \"Creating a signal with another signal is not recommended. The value will be unwrapped.\"\n );\n }\n return value;\n }\n return new SignalImpl(value);\n}\nfunction shallowSignal(value) {\n if (isSignal(value)) {\n value = value.peek();\n }\n return new SignalImpl(value, true);\n}\nfunction isSignal(value) {\n return !!value && !!value[\"_IS_SIGNAL\" /* IS_SIGNAL */];\n}\nvar queue = /* @__PURE__ */ new Set();\nvar activePreFlushCbs = /* @__PURE__ */ new Set();\nvar p = Promise.resolve();\nvar isFlushPending = false;\nfunction nextTick(fn) {\n return fn ? p.then(fn) : p;\n}\nfunction queueJob(job) {\n queue.add(job);\n queueFlush();\n}\nfunction queueFlush() {\n if (!isFlushPending) {\n isFlushPending = true;\n nextTick(flushJobs);\n }\n}\nfunction queuePreFlushCb(cb) {\n activePreFlushCbs.add(cb);\n queueFlush();\n}\nfunction flushJobs() {\n isFlushPending = false;\n flushPreFlushCbs();\n while (queue.size > 0) {\n for (const job of queue) {\n try {\n job();\n } catch (_error) {\n {\n error(\"Error executing queued job:\", _error);\n }\n }\n }\n queue.clear();\n }\n}\nfunction flushPreFlushCbs() {\n const callbacks = Array.from(activePreFlushCbs);\n activePreFlushCbs.clear();\n for (const callback of callbacks) {\n try {\n callback();\n } catch (_error) {\n {\n error(\"Error executing pre-flush callback:\", _error);\n }\n }\n }\n}\nfunction createScheduler(effect2, flush) {\n switch (flush) {\n case \"sync\":\n return () => effect2();\n case \"pre\":\n return () => queuePreFlushCb(effect2);\n case \"post\":\n return () => queueJob(effect2);\n default:\n {\n warn(`Invalid flush timing: ${flush}. Defaulting to 'post'.`);\n }\n return () => queueJob(effect2);\n }\n}\n\n// src/batch.ts\nvar batchDepth = 0;\nfunction batch(fn) {\n startBatch();\n try {\n return fn();\n } finally {\n endBatch();\n }\n}\nfunction startBatch() {\n batchDepth++;\n}\nfunction endBatch() {\n if (batchDepth === 0) {\n warn(\n \"[Batch] endBatch() called without matching startBatch(). This indicates unbalanced batch calls in your code. Make sure every startBatch() has a corresponding endBatch(), or use the batch() function which handles this automatically.\"\n );\n return;\n }\n batchDepth--;\n if (batchDepth === 0) {\n flushJobs();\n }\n}\nfunction isBatching() {\n return batchDepth > 0;\n}\nfunction getBatchDepth() {\n return batchDepth;\n}\n\n// src/effect.ts\nvar _a2;\n_a2 = \"_IS_EFFECT\" /* IS_EFFECT */;\nvar EffectImpl = class {\n /**\n * Create an Effect instance\n *\n * @param fn - The effect function\n * @param options - Configuration options\n */\n constructor(fn, options) {\n this.flag = 2 /* WATCHING */ | 16 /* DIRTY */;\n // @ts-ignore: used internally by isEffect typeguard\n this[_a2] = true;\n // State management\n this._active = true;\n var _a5;\n this.fn = fn;\n if (options) {\n const scheduler = (_a5 = options.scheduler) != null ? _a5 : options.flush;\n if (scheduler) {\n this._flushScheduler = isFunction(scheduler) ? () => scheduler(this) : createScheduler(() => this.run(), scheduler);\n }\n if (options.onStop) this.onStop = options.onStop;\n {\n if (options.onTrack) this.onTrack = options.onTrack;\n if (options.onTrigger) this.onTrigger = options.onTrigger;\n }\n }\n }\n /**\n * Check if the Effect is active\n */\n get active() {\n return this._active;\n }\n /**\n * Check if the Effect is dirty (needs re-execution)\n */\n get dirty() {\n const flags = this.flag;\n if (flags & 16 /* DIRTY */) {\n return true;\n }\n if (flags & 32 /* PENDING */) {\n if (this.depLink && checkDirty(this.depLink, this)) {\n this.flag = flags & -33 /* PENDING */ | 16 /* DIRTY */;\n return true;\n }\n this.flag = flags & -33 /* PENDING */;\n }\n return false;\n }\n /**\n * Pause Effect execution\n *\n * When an effect is paused:\n * - It stops responding to dependency changes\n * - Notifications are ignored (see notify method)\n * - DIRTY and PENDING flags are still set when dependencies change\n * - The effect remains active and maintains its dependency links\n *\n * Use cases:\n * - Temporarily disable effects during bulk updates\n * - Prevent effects from running during initialization\n * - Control when side effects should execute\n *\n * @example\n * ```typescript\n * const count = signal(0);\n * const runner = effect(() => console.log(count.value));\n *\n * runner.effect.pause();\n * count.value = 1; // Effect won't run\n * count.value = 2; // Effect won't run\n * runner.effect.resume(); // Effect runs once with latest value\n * ```\n */\n pause() {\n this.flag |= 256 /* PAUSED */;\n }\n /**\n * Resume Effect execution\n *\n * When an effect is resumed:\n * - The PAUSED flag is cleared\n * - If dependencies changed during pause (DIRTY or PENDING flags set),\n * the effect executes immediately via notify()\n * - If no changes occurred, the effect simply becomes active again\n *\n * State management:\n * - Clears PAUSED flag atomically\n * - Checks for accumulated DIRTY/PENDING flags\n * - Triggers execution if needed\n *\n * @example\n * ```typescript\n * const count = signal(0);\n * const runner = effect(() => console.log(count.value));\n *\n * runner.effect.pause();\n * count.value = 1; // Queued\n * count.value = 2; // Queued\n * runner.effect.resume(); // Executes once with count.value = 2\n * ```\n */\n resume() {\n const flags = this.flag;\n const nextFlags = flags & -257 /* PAUSED */;\n this.flag = nextFlags;\n const wasDirty = (nextFlags & 16 /* DIRTY */) !== 0;\n const wasPending = (nextFlags & 32 /* PENDING */) !== 0;\n if (wasDirty || wasPending) {\n this.notify();\n }\n }\n /**\n * Execute the Effect function\n *\n * Core execution flow:\n * 1. Check if active\n * 2. Clear dirty flag\n * 3. Start tracking dependencies\n * 4. Execute user function\n * 5. End tracking, clean up stale dependencies\n \n * @returns The return value of the effect function\n */\n run() {\n if (!this._active) {\n return this.fn();\n }\n const flags = this.flag;\n this.flag = flags & -49 | 512 /* RUNNING */;\n const prevSub = startTracking(this);\n try {\n return this.fn();\n } catch (error5) {\n this.flag |= 16 /* DIRTY */;\n throw error5;\n } finally {\n this.flag &= -513 /* RUNNING */;\n endTracking(this, prevSub);\n }\n }\n /**\n * Get or create the job function for this effect\n */\n getJob() {\n if (!this._job) {\n this._job = () => this.run();\n }\n return this._job;\n }\n /**\n * Notify that the Effect needs to execute\n *\n * Called by dependent reactive values.\n * Decides whether to execute immediately or defer based on scheduling strategy.\n */\n notify() {\n var _a5;\n const flags = this.flag;\n if (!this._active || flags & (256 /* PAUSED */ | 512 /* RUNNING */ | 16 /* DIRTY */)) {\n return;\n }\n this.flag = flags | 16 /* DIRTY */;\n if (this == null ? void 0 : this.onTrigger) {\n this.onTrigger({\n effect: this,\n target: {},\n type: \"set\"\n });\n }\n if (this._flushScheduler) {\n (_a5 = this._flushScheduler) == null ? void 0 : _a5.call(this);\n } else if (isBatching()) {\n queueJob(this.getJob());\n } else {\n this.run();\n }\n }\n /**\n * Stop the Effect\n *\n * After stopping:\n * - No longer responds to dependency changes\n * - Disconnects all dependency links\n * - Clears cached job function\n * - Calls onStop callback\n * - Verifies complete cleanup in development mode\n */\n stop() {\n if (!this._active) {\n {\n warn(\"[Effect] Attempting to stop an already stopped effect.\");\n }\n return;\n }\n this._active = false;\n let dep = this.depLink;\n while (dep) {\n dep = unlinkReactiveNode(dep, this);\n }\n let sub = this.subLink;\n while (sub) {\n sub = unlinkReactiveNode(sub);\n }\n this._job = void 0;\n this._flushScheduler = void 0;\n this.depLinkTail = void 0;\n this.subLinkTail = void 0;\n {\n if (this.depLink) {\n error(\n \"[Effect] Cleanup verification failed: depLink not cleared. This indicates a memory leak in the dependency tracking system.\"\n );\n }\n if (this.subLink) {\n error(\n \"[Effect] Cleanup verification failed: subLink not cleared. This indicates a memory leak in the subscription system.\"\n );\n }\n }\n if (this == null ? void 0 : this.onStop) {\n this.onStop();\n }\n }\n};\nfunction effect(fn, options) {\n const effectInstance = new EffectImpl(fn, options);\n try {\n effectInstance.run();\n } catch (_error) {\n effectInstance.stop();\n {\n error(\n \"[Effect] Effect failed during initial execution and has been stopped. Fix the error in your effect function.\",\n _error\n );\n }\n throw _error;\n }\n const runner = () => effectInstance.run();\n runner.effect = effectInstance;\n runner.stop = () => effectInstance.stop();\n return runner;\n}\nfunction stop(runner) {\n runner.effect.stop();\n}\nfunction isEffect(value) {\n return !!(value && value[\"_IS_EFFECT\" /* IS_EFFECT */]);\n}\nfunction memoEffect(fn, initialState, options) {\n let currentState = initialState;\n const effectFn = () => {\n const result = fn(currentState);\n currentState = result;\n };\n return effect(effectFn, options);\n}\nvar NO_VALUE = /* @__PURE__ */ Symbol(\"computed-no-value\");\nvar _a3;\n_a3 = \"_IS_COMPUTED\" /* IS_COMPUTED */;\nvar ComputedImpl = class {\n /**\n * Create a Computed instance\n *\n * @param getter - The computation function\n * @param setter - Optional setter function\n * @param onTrack - Optional debug callback for dependency tracking\n * @param onTrigger - Optional debug callback for triggers\n */\n constructor(getter, setter, onTrack, onTrigger) {\n this.flag = 1 /* MUTABLE */ | 16 /* DIRTY */;\n // @ts-ignore: used internally by isComputed typeguard\n this[_a3] = true;\n // Cache\n // Use symbol sentinel to distinguish \"no value\" from undefined/null values\n this._value = NO_VALUE;\n this.getter = getter;\n this.setter = setter;\n this.onTrack = onTrack;\n this.onTrigger = onTrigger;\n this.flag |= 16 /* DIRTY */;\n }\n get value() {\n if (activeSub) {\n linkReactiveNode(this, activeSub);\n }\n const flags = this.flag;\n const hasValue = this._value !== NO_VALUE;\n if (hasValue && !(flags & (16 /* DIRTY */ | 32 /* PENDING */))) {\n return this._value;\n }\n if (!hasValue || flags & 16 /* DIRTY */) {\n this.recompute();\n return this._value;\n }\n if (flags & 32 /* PENDING */) {\n if (this.depLink && checkDirty(this.depLink, this)) {\n this.recompute();\n } else {\n this.flag = flags & -33 /* PENDING */;\n }\n }\n return this._value;\n }\n /**\n * Set value (only effective when setter is provided)\n *\n * @param newValue - The new value\n */\n set value(newValue) {\n if (this.setter) {\n this.setter(newValue);\n } else {\n warn(\n \"[Computed] Cannot set readonly computed value. Provide a setter in the computed options to make it writable.\\nExample: computed({ get: () => value, set: (v) => { ... } })\"\n );\n }\n }\n /**\n * Read value without tracking dependencies\n *\n * @returns Current value\n */\n peek() {\n if (this._value === NO_VALUE) {\n this.recompute();\n }\n return this._value;\n }\n /**\n * Recompute the value\n *\n * computation logic:\n * 1. Start tracking dependencies\n * 2. Execute getter function\n * 3. Check if value changed using optimized comparison\n * 4. If changed, update cache and notify subscribers\n * 5. End tracking, clean up stale dependencies\n * @private\n */\n recompute() {\n const oldValue = this._value;\n const hadValue = oldValue !== NO_VALUE;\n const prevSub = startTracking(this);\n try {\n const newValue = this.getter();\n const flags = this.flag;\n const subs = this.subLink;\n const clearMask = ~(16 /* DIRTY */ | 32 /* PENDING */);\n const valueChanged = !hadValue || hasChanged(oldValue, newValue);\n if (valueChanged) {\n this._value = newValue;\n this.flag = flags & clearMask;\n if (this.onTrigger) {\n this.onTrigger({\n effect: this,\n target: this,\n type: \"set\",\n key: \"value\",\n newValue\n });\n }\n if (subs) {\n shallowPropagate(subs);\n }\n } else {\n this.flag = flags & clearMask;\n }\n } catch (_error) {\n const clearMask = -49;\n this.flag &= clearMask;\n this._value = NO_VALUE;\n {\n error(\n \"[Computed] Error occurred while computing value.\\nThe computed will retry on next access.\\nCommon causes:\\n - Accessing undefined properties\\n - Circular dependencies\\n - Exceptions in getter function\\nCheck your getter function for errors.\",\n _error\n );\n }\n throw _error;\n } finally {\n endTracking(this, prevSub);\n }\n }\n /**\n * Check if update is needed\n *\n * Internal use, called by reactive system.\n *\n * @returns true if value changed\n */\n shouldUpdate() {\n const hadValue = this._value !== NO_VALUE;\n const oldValue = this._value;\n this.recompute();\n if (!hadValue) {\n return true;\n }\n return hasChanged(this._value, oldValue);\n }\n};\nfunction computed(getterOrOptions) {\n if (isComputed(getterOrOptions)) {\n {\n warn(\n \"[Computed] Creating a computed from another computed is not recommended. The existing computed will be returned to avoid unnecessary wrapping.\"\n );\n }\n return getterOrOptions;\n }\n if (!getterOrOptions) {\n throw new Error(\n \"[Computed] Invalid argument: computed() requires a getter function or options object.\"\n );\n }\n if (isFunction(getterOrOptions)) {\n return new ComputedImpl(getterOrOptions);\n }\n if (isPlainObject(getterOrOptions)) {\n const { get, set, onTrack, onTrigger } = getterOrOptions;\n if (!get) {\n throw new Error(\n \"[Computed] Invalid options: getter function is required.\\nUsage: computed({ get: () => value, set: (v) => { ... } })\"\n );\n }\n if (!isFunction(get)) {\n throw new TypeError(\n `[Computed] Invalid options: getter must be a function.\nReceived: ${typeof get}`\n );\n }\n return new ComputedImpl(get, set, onTrack, onTrigger);\n }\n throw new Error(\n `[Computed] Invalid argument: expected a function or options object.\nReceived: ${typeof getterOrOptions}`\n );\n}\nfunction isComputed(value) {\n return !!value && !!value[\"_IS_COMPUTED\" /* IS_COMPUTED */];\n}\nfunction createOptionsStore(options) {\n if (!options.state) {\n warn(\"Store state is required\");\n throw new Error(\"Store state is required\");\n }\n const { state, getters, actions } = options;\n const initState = __spreadValues({}, state);\n const reactiveState = reactive(state);\n const subscriptions = /* @__PURE__ */ new Set();\n const actionCallbacks = /* @__PURE__ */ new Set();\n const notifySubscribers = (state2) => {\n subscriptions.forEach((callback) => callback(state2));\n actionCallbacks.forEach((callback) => callback(state2));\n };\n const defaultActions = {\n patch$(payload) {\n if (!payload) {\n warn(\"Patch payload is required\");\n return;\n }\n batch(() => {\n Object.assign(reactiveState, payload);\n });\n notifySubscribers(reactiveState);\n },\n subscribe$(callback) {\n if (!callback) {\n warn(\"Subscribe callback is required\");\n return;\n }\n subscriptions.add(callback);\n },\n unsubscribe$(callback) {\n subscriptions.delete(callback);\n },\n onAction$(callback) {\n if (!callback) {\n warn(\"Action callback is required\");\n return;\n }\n actionCallbacks.add(callback);\n },\n reset$() {\n batch(() => {\n Object.assign(reactiveState, initState);\n });\n notifySubscribers(reactiveState);\n }\n };\n const store = __spreadValues(__spreadProps(__spreadValues({}, reactiveState), {\n state: reactiveState\n }), defaultActions);\n if (getters) {\n for (const key in getters) {\n const getter = getters[key];\n if (!getter) continue;\n Object.defineProperty(store, key, {\n get: () => computed(() => getter.call(store, reactiveState)).value,\n enumerable: true,\n configurable: true\n });\n }\n }\n if (actions) {\n for (const key in actions) {\n const action = actions[key];\n if (action) {\n Reflect.set(store, key, (...args) => {\n const result = action.apply(reactiveState, args);\n actionCallbacks.forEach((callback) => callback(reactiveState));\n return result;\n });\n }\n }\n }\n return store;\n}\nfunction createClassStore(StoreClass) {\n const instance = new StoreClass();\n const state = /* @__PURE__ */ Object.create(null);\n const getters = {};\n const actions = {};\n Object.getOwnPropertyNames(instance).forEach((key) => {\n state[key] = instance[key];\n });\n Object.getOwnPropertyNames(StoreClass.prototype).forEach((key) => {\n const descriptor = Object.getOwnPropertyDescriptor(StoreClass.prototype, key);\n if (descriptor) {\n if (typeof descriptor.get === \"function\") {\n getters[key] = function() {\n return descriptor.get.call(this);\n };\n } else if (typeof descriptor.value === \"function\" && key !== \"constructor\") {\n actions[key] = function(...args) {\n return descriptor.value.apply(this, args);\n };\n }\n }\n });\n return {\n state,\n getters,\n actions\n };\n}\nfunction createStore(storeDefinition) {\n if (!storeDefinition) {\n warn(\"Store definition is required\");\n throw new Error(\"Store definition is required\");\n }\n return () => {\n let options;\n if (isFunction(storeDefinition)) {\n options = createClassStore(storeDefinition);\n } else {\n options = storeDefinition;\n }\n const store = createOptionsStore(options);\n if (isFunction(storeDefinition) && options.actions) {\n Object.keys(options.actions).forEach((key) => {\n Reflect.set(store, key, options.actions[key].bind(store));\n });\n }\n return store;\n };\n}\nvar _a4, _b;\nvar RefImpl = class extends (_b = SignalImpl, _a4 = \"_IS_REF\" /* IS_REF */, _b) {\n /**\n * Creates a new ref with the given initial value.\n *\n * @param value - The initial value\n */\n constructor(value) {\n super(value, true);\n // @ts-ignore: used internally by isRef typeguard\n this[_a4] = true;\n }\n get value() {\n const sub = activeSub;\n if (sub) {\n linkReactiveNode(this, sub);\n }\n return this._value;\n }\n set value(newValue) {\n if (isSignal(newValue)) {\n newValue = newValue.peek();\n }\n if (isRef(newValue)) {\n newValue = newValue.value;\n }\n if (hasChanged(this._value, newValue)) {\n this._rawValue = newValue;\n this._value = newValue;\n this.flag |= 16 /* DIRTY */;\n if (this.subLink) {\n propagate(this.subLink);\n }\n }\n }\n};\nfunction ref(value = void 0) {\n if (isRef(value)) {\n return value;\n }\n if (isSignal(value)) {\n return new RefImpl(value.peek());\n }\n return new RefImpl(value);\n}\nfunction isRef(value) {\n return !!value && !!value[\"_IS_REF\" /* IS_REF */];\n}\nvar INITIAL_WATCHER_VALUE = {};\nvar cleanupMap = /* @__PURE__ */ new WeakMap();\nfunction traverse(value, seen = /* @__PURE__ */ new Set()) {\n if (!isObject(value) || seen.has(value)) {\n return value;\n }\n seen.add(value);\n if (isSignal(value) || isComputed(value)) {\n return traverse(value.value, seen);\n }\n if (Array.isArray(value)) {\n for (const element of value) {\n traverse(element, seen);\n }\n } else if (isMap(value)) {\n value.forEach((v) => {\n traverse(v, seen);\n });\n value.keys();\n value.values();\n } else if (isSet(value)) {\n value.forEach((v) => {\n traverse(v, seen);\n });\n value.values();\n } else {\n Object.keys(value).forEach((key) => {\n traverse(value[key], seen);\n });\n }\n return value;\n}\nfunction cloneValue(value) {\n if (!isObject(value)) {\n return value;\n }\n if (Array.isArray(value)) {\n return value.map((item) => cloneValue(item));\n }\n if (isMap(value)) {\n const cloned2 = /* @__PURE__ */ new Map();\n value.forEach((v, k) => {\n cloned2.set(k, cloneValue(v));\n });\n return cloned2;\n }\n if (isSet(value)) {\n const cloned2 = /* @__PURE__ */ new Set();\n value.forEach((v) => {\n cloned2.add(cloneValue(v));\n });\n return cloned2;\n }\n const cloned = {};\n for (const key of Object.keys(value)) {\n cloned[key] = cloneValue(value[key]);\n }\n return cloned;\n}\nfunction resolveSource(source) {\n if (Array.isArray(source)) {\n return () => source.map((s) => {\n if (isSignal(s) || isComputed(s)) {\n return s.value;\n }\n if (isReactive(s)) {\n return traverse(s);\n }\n if (isFunction(s)) {\n return s();\n }\n return s;\n });\n }\n if (isFunction(source)) {\n return source;\n }\n if (isSignal(source)) {\n return () => source.value;\n }\n if (isObject(source) && \"value\" in source) {\n return () => source.value;\n }\n if (isReactive(source)) {\n return () => traverse(source);\n }\n return () => source;\n}\nfunction watch(source, callback, options = {}) {\n const { immediate = false, deep = false } = options;\n let oldValue = INITIAL_WATCHER_VALUE;\n const getter = resolveSource(source);\n const job = () => {\n const currentEffect = runner.effect;\n if (!currentEffect.run) {\n return;\n }\n const newValue = currentEffect.run();\n if (hasChanged(newValue, oldValue)) {\n callback(newValue, oldValue === INITIAL_WATCHER_VALUE ? void 0 : oldValue);\n oldValue = cloneValue(newValue);\n }\n };\n const runner = effect(\n () => {\n const value = getter();\n if (deep) {\n traverse(value);\n }\n return value;\n },\n {\n // Use scheduler to queue job, implementing async and debouncing.\n scheduler: () => queueJob(job)\n }\n );\n if (immediate) {\n job();\n } else {\n oldValue = cloneValue(runner.effect.run());\n }\n return () => {\n runner.stop();\n const cleanups = cleanupMap.get(runner.effect);\n if (cleanups) {\n cleanups.forEach((fn) => fn());\n cleanupMap.delete(runner.effect);\n }\n };\n}\n\nexport { TriggerOpTypes, batch, computed, createStore, effect, endBatch, getBatchDepth, isBatching, isComputed, isEffect, isReactive, isRef, isShallow, isSignal, memoEffect, nextTick, queueJob, queuePreFlushCb, reactive, ref, shallowReactive, shallowSignal, signal, startBatch, stop, toRaw, toReactive, trigger, untrack, watch };\n","import { isComputed, isSignal } from '@estjs/signals';\nimport { isString, normalizeClassName, normalizeStyle, styleToString } from '@estjs/shared';\n\n/**\n * Normalize component properties\n *\n * Special handling for class and style attributes, converting them to normalized format\n *\n * @param props - Original component properties\n * @returns Normalized component properties\n */\nexport function normalizeProps(props: Record<string, any> | null): Record<string, any> | null {\n if (!props) {\n return null;\n }\n\n const { class: className, style } = props;\n\n // Normalize class attribute\n if (className && !isString(className)) {\n props.class = normalizeClassName(className);\n }\n\n // Normalize style attribute\n if (style) {\n props.style = normalizeStyle(style);\n }\n\n return props;\n}\n\n/**\n * Generate server-side rendering attribute string\n *\n * Generate HTML-compatible attribute string based on attribute type, handling special cases:\n * - Automatic unwrapping of reactive values\n * - Normalization of special attributes (style/class)\n * - Ignoring event attributes\n * - Special handling for boolean attributes\n *\n * @param attrName - Attribute name\n * @param attrValue - Attribute value\n * @param hydrationId - Hydration ID (for client-side reuse)\n * @returns Formatted HTML attribute string\n */\nexport function setSSGAttr(attrName: string, attrValue: any, hydrationId: string): string {\n // Handle reactive values (signals or computed values)\n if (isSignal(attrValue) || isComputed(attrValue)) {\n return setSSGAttr(attrName, attrValue.value, hydrationId);\n }\n\n // Ignore null, undefined, and false value attributes\n if (!attrValue && attrValue !== 0) {\n return '';\n }\n\n // Special attribute handling: style\n if (attrName === 'style') {\n const normalizedStyle = normalizeStyle(attrValue);\n if (!normalizedStyle) {\n return '';\n }\n\n if (isString(normalizedStyle)) {\n return ` style=\"${normalizedStyle}\"`;\n }\n\n return ` style=\"${styleToString(normalizedStyle)}\"`;\n }\n\n // Special attribute handling: class\n if (attrName === 'class') {\n const normalizedClassName = normalizeClassName(attrValue);\n return normalizedClassName ? ` class=\"${normalizedClassName}\"` : '';\n }\n\n // Ignore event handler attributes (client-side behavior)\n if (attrName.startsWith('on')) {\n return '';\n }\n\n // Special handling for boolean attributes\n if (attrValue === true) {\n return ` ${attrName}`;\n }\n\n // Standard attribute handling\n return ` ${attrName}=\"${attrValue}\"`;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/context.ts","../src/utils.ts","../src/render.ts","../src/attrs.ts","../src/ssr.ts","../src/components.ts"],"names":["createSSRContext","store","AsyncLocalStorage","getSSRContext","_a","runWithSSRContext","ctx","fn","convertToString","content","isSvg","isNil","isString","isArray","item","isFunction","convertTextChildToString","escapeHTML","HYDRATION_REWRITE_REGEX","injectRootHydrationAttribute","htmlContent","hydrationId","tagStart","quote","char","insertAt","j","prev","addAttributes","_match","dataIdx","commentBody","runInFreshScope","parent","getActiveScope","scope","createScope","runWithScope","disposeScope","renderToString","component","props","context","error","resetHydrationKey","result","render","templates","hydrationKey","components","templateLen","componentLen","i","renderToStringAsync","_0","__async","isPromise","convertToStringAsync","c","createSSGComponent","normalizeProps","className","style","needsClassNorm","needsStyleNorm","__spreadValues","normalizeClassName","normalizeStyle","setSSGAttr","attrName","attrValue","isSignal","isComputed","normalizedStyle","styleToString","normalizedClassName","ssrAttr","name","value","ssrClass","normalized","normalizeClassSSR","ssrStyle","isObject","obj","parts","key","v","prop","camelToKebab","ssrSpread","out","k","UPPER_RE","str","m","Fragment","TELEPORT_CALLSITE_ANCHOR","TELEPORT_BLOCK_START","TELEPORT_BLOCK_END","Portal","target","children","rendered","Suspense","fallback","resolveList","input","_b","For","list"],"mappings":"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","file":"server.esm.js","sourcesContent":["// Use bare specifier (not `node:async_hooks`) as a workaround for tsup's\n// dts worker on TS 6.x, which reports TS2591 against the `node:` prefix\n// in some CI environments.\n// eslint-disable-next-line unicorn/prefer-node-protocol\nimport { AsyncLocalStorage } from 'async_hooks';\n\n/**\n * SSR rendering context.\n\n */\nexport interface SSRContext {\n /**\n * Map of teleport target → concatenated HTML string. The caller is\n * responsible for inlining each entry into the final document\n * (e.g. by replacing a placeholder in a shell template).\n */\n teleports: Record<string, string>;\n\n /**\n * Free-form key/value bag for user-defined per-render metadata\n * (e.g. collected `<head>` tags, status codes, response headers).\n */\n [key: string]: unknown;\n}\n\n/**\n * Create an empty SSR context with all collection slots initialised.\n */\nexport function createSSRContext(): SSRContext {\n return {\n teleports: Object.create(null) as Record<string, string>,\n };\n}\n\n/**\n * Async-safe SSR context propagation.\n */\ninterface ContextStore {\n getStore(): SSRContext | null | undefined;\n run<T>(ctx: SSRContext | null, fn: () => T): T;\n}\nconst store: ContextStore = new AsyncLocalStorage<SSRContext | null>();\n\n/**\n * Get the current SSR context, if any. Returns `null` when called outside of\n * a `renderToString` invocation, or when the caller did not pass a context.\n */\nexport function getSSRContext(): SSRContext | null {\n return store.getStore() ?? null;\n}\n\n/**\n * Run `fn` with `ctx` as the active SSR context. The context is preserved\n * across awaits inside `fn` and restored on exit (including when `fn` throws).\n */\nexport function runWithSSRContext<T>(ctx: SSRContext | null, fn: () => T): T {\n return store.run(ctx, fn);\n}\n","import { escapeHTML, isArray, isFunction, isNil, isString } from '@estjs/shared';\n\n/**\n * Convert content to string for SSR output.\n *\n * @param content - The content to convert.\n * @param isSvg - Whether the content is SVG.\n * @returns {string} The content as a string.\n */\nexport function convertToString(content: unknown, isSvg = false): string {\n if (isNil(content)) {\n return '';\n }\n\n if (isString(content)) {\n return content;\n }\n if (isArray(content)) {\n return (content as unknown[]).map((item: unknown) => convertToString(item, isSvg)).join('');\n }\n\n if (isFunction(content)) {\n return convertToString((content as () => unknown)(), isSvg);\n }\n\n return String(content);\n}\n\n/**\n * Convert child-expression content to escaped text for SSR output.\n *\n * JSX expression children have text semantics, so primitives must be escaped\n * before interpolation into the surrounding HTML template.\n */\nexport function convertTextChildToString(content: unknown): string {\n if (content === false || isNil(content)) {\n return '';\n }\n\n if (isString(content)) {\n return escapeHTML(content);\n }\n\n if (isArray(content)) {\n return (content as unknown[]).map((item) => convertTextChildToString(item)).join('');\n }\n\n if (isFunction(content)) {\n return convertTextChildToString((content as () => unknown)());\n }\n\n return escapeHTML(String(content));\n}\n\n/**\n * Combined regex that matches either a `data-idx=\"<digits>\"` attribute or a\n * hydration comment marker (numeric body only) in a single scan. Capture groups:\n * 1. data-idx index value (if attribute matched)\n * 2. numeric comment body (if hydration marker matched)\n *\n * Non-numeric comments (e.g. `<!-- user content -->`) are preserved unchanged.\n */\nconst HYDRATION_REWRITE_REGEX = /data-idx=\"(\\d+)\"|<!--(\\d+)-->/g;\n\n/**\n * Inject the root hydration attribute into the opening tag without corrupting\n * self-closing tags such as `<img />` or `<input/>`.\n */\nfunction injectRootHydrationAttribute(htmlContent: string, hydrationId: string): string {\n const tagStart = htmlContent.indexOf('<');\n if (tagStart === -1) {\n return htmlContent;\n }\n\n let quote: '\"' | \"'\" | undefined;\n for (let i = tagStart + 1; i < htmlContent.length; i++) {\n const char = htmlContent[i];\n\n if (quote) {\n if (char === quote) {\n quote = undefined;\n }\n continue;\n }\n\n if (char === '\"' || char === \"'\") {\n quote = char;\n continue;\n }\n\n if (char === '>') {\n let insertAt = i;\n for (let j = i - 1; j > tagStart; j--) {\n const prev = htmlContent[j];\n if (prev === ' ' || prev === '\\n' || prev === '\\t' || prev === '\\r') {\n continue;\n }\n if (prev === '/') {\n insertAt = j;\n }\n break;\n }\n\n return `${htmlContent.slice(0, insertAt)} data-hk=\"${hydrationId}\"${htmlContent.slice(insertAt)}`;\n }\n }\n\n return htmlContent;\n}\n\n/**\n * Add hydration attributes to HTML content.\n *\n * @param htmlContent - The html content.\n * @param hydrationId - The hydration id.\n * @returns {string} The html content with hydration attributes.\n */\nexport function addAttributes(htmlContent: string, hydrationId: string): string {\n // Single-pass rewrite for both `data-idx` and comment markers — half the\n // string traversals compared to chained `replaceAll` calls.\n return injectRootHydrationAttribute(htmlContent, hydrationId).replaceAll(\n HYDRATION_REWRITE_REGEX,\n (_match, dataIdx, commentBody) =>\n dataIdx !== undefined\n ? `data-idx=\"${hydrationId}-${dataIdx}\"`\n : `<!--${hydrationId}-${commentBody}-->`,\n );\n}\n","import { error, isFunction, isPromise } from '@estjs/shared';\nimport { type ComponentFn, type ComponentProps, resetHydrationKey } from '@estjs/template';\nimport {\n type Scope,\n createScope,\n disposeScope,\n getActiveScope,\n runWithScope,\n} from '@estjs/template/internal';\nimport { type SSRContext, runWithSSRContext } from './context';\nimport { addAttributes, convertToString } from './utils';\n\n/**\n * Runs `fn` inside a freshly created scope whose parent is the currently\n * active scope (if any). The scope is always disposed, even when `fn` throws,\n * so `provide` / `inject` state from one render cannot leak into another.\n */\nfunction runInFreshScope<T>(fn: () => T, parent: Scope | null = getActiveScope()): T {\n const scope = createScope(parent);\n try {\n return runWithScope(scope, fn);\n } finally {\n disposeScope(scope);\n }\n}\n\n/**\n * Render a component to HTML string.\n *\n * Each invocation runs inside its own root scope so that `provide()` calls\n * stay isolated between independent `renderToString` calls.\n *\n * @param component - The component to render.\n * @param props - The props to pass to the component.\n * @param context - Optional {@link SSRContext} that collects out-of-tree\n * render output (currently: `Portal`/`Teleport` content). The same context\n * is visible to nested `createSSGComponent` calls; the caller integrates\n * `context.teleports[selector]` into the final document.\n * @returns {string} The rendered HTML string.\n */\nexport function renderToString<P extends ComponentProps = ComponentProps>(\n component: ComponentFn<P>,\n props: P | ComponentProps = {},\n context: SSRContext | null = null,\n): string {\n if (!isFunction(component)) {\n error('Component must be a function');\n return '';\n }\n\n // Reset the hydration key counter\n resetHydrationKey();\n\n // Render the component within a fresh root scope (parent: null).\n const result = runWithSSRContext(context, () =>\n runInFreshScope(() => component(props as P), null),\n );\n\n if (__DEV__ && isPromise(result)) {\n error('renderToString received a Promise — use renderToStringAsync for async components.');\n }\n\n // Convert the result to string\n return convertToString(result);\n}\n\n/**\n * Render template with components (used by babel plugin in SSG mode).\n *\n * @param templates - The template fragments.\n * @param hydrationKey - The hydration key.\n * @param components - The rendered component strings.\n * @returns {string} The rendered HTML string.\n */\nexport function render(templates: string[], hydrationKey: string, ...components: string[]): string {\n /**\n * JSX source code:\n * <div>\n * <div>\n * <Component1 />\n * <Component2 />\n * </div>\n * <Component3 />\n * </div>\n *\n * Compiles to:\n *\n * let _tmpl = [\n * '<div><div>',\n * '</div>',\n * '</div>',\n * ]\n *\n * function component(props) {\n * return render(_tmpl, getHydrationKey(),\n * createSSGComponent(Component1, {}),\n * createSSGComponent(Component2, {}),\n * createSSGComponent(Component3, {})\n * );\n * }\n */\n\n // Direct string concatenation — avoids array allocation + join overhead\n // for typical 2-4 template fragments.\n const templateLen = templates.length;\n const componentLen = components.length;\n let content = '';\n\n for (let i = 0; i < templateLen; i++) {\n content += templates[i];\n if (i < componentLen && components[i]) {\n content += convertToString(components[i]);\n }\n }\n\n // Add hydration key attribute (data-hk) to the root element\n return addAttributes(content, hydrationKey);\n}\n\n/**\n * Async variant of {@link renderToString}. Awaits component results so that\n * `async` components and promise-returning expressions can participate in SSR.\n *\n * The awaited value is passed through the same {@link convertToString}\n * pipeline as the synchronous path, which itself transparently awaits any\n * nested promises (arrays of promises, promise-returning thunks, etc.).\n */\nexport async function renderToStringAsync<P extends ComponentProps = ComponentProps>(\n component: ComponentFn<P>,\n props: P | ComponentProps = {},\n context: SSRContext | null = null,\n): Promise<string> {\n if (!isFunction(component)) {\n error('Component must be a function');\n return '';\n }\n\n resetHydrationKey();\n\n const scope = createScope(null);\n try {\n // Keep both the SSR context and the reactive scope active for the entire\n // async render lifetime. This ensures that Portal() calls after an `await`\n // inside async components can still access `getSSRContext()`.\n return await runWithSSRContext(context, async () => {\n let result: unknown = runWithScope(scope, () => component(props as P));\n if (isPromise(result)) {\n result = await result;\n }\n return convertToStringAsync(result);\n });\n } finally {\n disposeScope(scope);\n }\n}\n\n/**\n * Promise-aware variant of `convertToString` used by {@link renderToStringAsync}.\n * Recursively unwraps promises and arrays of promises.\n */\nasync function convertToStringAsync(content: unknown): Promise<string> {\n if (isPromise(content)) {\n return convertToStringAsync(await content);\n }\n if (Array.isArray(content)) {\n const parts = await Promise.all(content.map((c) => convertToStringAsync(c)));\n return parts.join('');\n }\n if (isFunction(content)) {\n return convertToStringAsync((content as () => unknown)());\n }\n return convertToString(content);\n}\n\n/**\n * Create a SSG component (renders component to string).\n *\n * The component executes inside a child scope that inherits from the current\n * active scope, so `inject()` calls can resolve values from ancestor\n * `provide()` calls, and `provide()` inside the component is scoped to it.\n *\n * @param component - The component to create.\n * @param props - The props to pass to the component.\n * @returns {string} The rendered component as a string.\n */\nexport function createSSGComponent<P extends ComponentProps = ComponentProps>(\n component: ComponentFn<P>,\n props: P | ComponentProps = {},\n): string {\n if (!isFunction(component)) {\n error('createSSGComponent: Component is not a function');\n return '';\n }\n\n // Inherit the active scope (set by the enclosing renderToString call or by\n // an outer createSSGComponent) so that provide/inject follow the component\n // tree hierarchy.\n const result = runInFreshScope(() => component(props as P));\n\n return convertToString(result);\n}\n","import { isComputed, isSignal } from '@estjs/signals';\nimport {\n escapeHTML,\n isString,\n normalizeClassName,\n normalizeStyle,\n styleToString,\n} from '@estjs/shared';\n\n/**\n * Normalize component properties\n *\n * Special handling for class and style attributes, converting them to normalized format.\n * Returns a new object when normalization is needed, preserving the original.\n *\n * @param props - Original component properties\n * @returns Normalized component properties\n */\nexport function normalizeProps(props: Record<string, any> | null): Record<string, any> | null {\n if (!props) {\n return null;\n }\n\n const { class: className, style } = props;\n const needsClassNorm = className && !isString(className);\n const needsStyleNorm = !!style;\n\n if (!needsClassNorm && !needsStyleNorm) {\n return props;\n }\n\n // Shallow copy to avoid mutating the caller's props\n const result = { ...props };\n\n if (needsClassNorm) {\n result.class = normalizeClassName(className);\n }\n\n if (needsStyleNorm) {\n result.style = normalizeStyle(style);\n }\n\n return result;\n}\n\n/**\n * Generate server-side rendering attribute string\n *\n * Generate HTML-compatible attribute string based on attribute type, handling special cases:\n * - Automatic unwrapping of reactive values\n * - Normalization of special attributes (style/class)\n * - Ignoring event attributes\n * - Special handling for boolean attributes\n *\n * @param attrName - Attribute name\n * @param attrValue - Attribute value\n * @returns Formatted HTML attribute string\n */\nexport function setSSGAttr(attrName: string, attrValue: any): string {\n // Handle reactive values (signals or computed values)\n if (isSignal(attrValue) || isComputed(attrValue)) {\n return setSSGAttr(attrName, attrValue.value);\n }\n\n // Ignore null, undefined, and false value attributes\n if (!attrValue && attrValue !== 0) {\n return '';\n }\n\n // Special attribute handling: style\n if (attrName === 'style') {\n const normalizedStyle = normalizeStyle(attrValue);\n if (!normalizedStyle) {\n return '';\n }\n\n if (isString(normalizedStyle)) {\n return ` style=\"${normalizedStyle}\"`;\n }\n\n return ` style=\"${styleToString(normalizedStyle)}\"`;\n }\n\n // Special attribute handling: class\n if (attrName === 'class') {\n const normalizedClassName = normalizeClassName(attrValue);\n return normalizedClassName ? ` class=\"${normalizedClassName}\"` : '';\n }\n\n // Ignore event handler attributes (client-side behavior)\n if (attrName.startsWith('on')) {\n return '';\n }\n\n // Special handling for boolean attributes\n if (attrValue === true) {\n return ` ${attrName}`;\n }\n\n // Standard attribute handling — escape to prevent attribute injection (XSS)\n return ` ${attrName}=\"${escapeHTML(String(attrValue))}\"`;\n}\n","import { escapeHTML, isArray, isNil, isObject, isString } from '@estjs/shared';\n\n// ---------------------------------------------------------------------------\n// SSR attribute helpers\n// Used by babel-plugin server-mode generated code.\n// ---------------------------------------------------------------------------\n\n/**\n * Render a single attribute as an HTML attribute string.\n *\n * @param name - The name of the attribute.\n * @param value - The value of the attribute.\n * @returns {string} The rendered attribute string (e.g., ` name=\"value\"`).\n */\nexport function ssrAttr(name: string, value: unknown): string {\n if (isNil(value) || value === false) return '';\n if (value === true) return ` ${name}`;\n return ` ${name}=\"${escapeHTML(String(value))}\"`;\n}\n\n/**\n * Render a `class` attribute as an HTML attribute string.\n *\n * @param value - The class value (string, object, or array).\n * @returns {string} The rendered class attribute string.\n */\nexport function ssrClass(value: unknown): string {\n const normalized = normalizeClassSSR(value);\n if (!normalized) return '';\n return ` class=\"${escapeHTML(normalized)}\"`;\n}\n\n/**\n * Render a `style` attribute as an HTML attribute string.\n *\n * @param value - The style value (string or object).\n * @returns {string} The rendered style attribute string.\n */\nexport function ssrStyle(value: unknown): string {\n if (isNil(value)) return '';\n if (isString(value)) return value ? ` style=\"${escapeHTML(value)}\"` : '';\n if (isObject(value)) {\n const obj = value as Record<string, unknown>;\n const parts: string[] = [];\n for (const key in obj) {\n const v = obj[key];\n if (v != null && v !== false) {\n const prop = key.startsWith('--') ? key : camelToKebab(key);\n parts.push(`${prop}:${escapeHTML(String(v))}`);\n }\n }\n if (!parts.length) return '';\n return ` style=\"${parts.join(';')}\"`;\n }\n return '';\n}\n\n/**\n * Render a spread of props as HTML attribute strings.\n * Skips event handlers and special keys.\n *\n * @param props - The props object to spread.\n * @returns {string} The rendered attribute strings.\n */\nexport function ssrSpread(props: Record<string, unknown>): string {\n if (!props || !isObject(props)) return '';\n let out = '';\n for (const key in props) {\n if (key === 'children' || key === 'ref' || key.startsWith('on')) continue;\n if (key === 'class' || key === 'className') {\n out += ssrClass(props[key]);\n } else if (key === 'style') {\n out += ssrStyle(props[key]);\n } else {\n out += ssrAttr(key, props[key]);\n }\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Normalizes SSR class input into a string.\n */\nfunction normalizeClassSSR(value: unknown): string {\n if (isNil(value) || value === false) return '';\n if (isString(value)) return value;\n if (isArray(value)) {\n return (value as unknown[]).map(normalizeClassSSR).filter(Boolean).join(' ');\n }\n if (isObject(value)) {\n const obj = value as Record<string, unknown>;\n return Object.keys(obj)\n .filter((k) => Boolean(obj[k]))\n .join(' ');\n }\n return String(value);\n}\n\n/**\n * Matches uppercase characters for camelCase to kebab-case conversion.\n */\nconst UPPER_RE = /[A-Z]/g;\n\n/**\n * Converts a camelCase CSS property into kebab-case.\n */\nfunction camelToKebab(str: string): string {\n return str.replaceAll(UPPER_RE, (m) => `-${m.toLowerCase()}`);\n}\n","import { isFunction, isNil, isObject, isString, warn } from '@estjs/shared';\nimport { convertToString } from './utils';\nimport { getSSRContext } from './context';\n\nexport interface SSRComponentProps {\n children?: unknown;\n [key: string]: unknown;\n}\n\n/**\n * SSR Fragment — returns children converted to a string.\n */\nexport function Fragment(props: SSRComponentProps): string {\n return convertToString(props.children);\n}\n\n// ---------------------------------------------------------------------------\n// Portal (SSR)\n// ---------------------------------------------------------------------------\n\nexport interface SSRPortalProps extends SSRComponentProps {\n /**\n * Teleport target — only CSS selector strings are meaningful on the server.\n * Element references are silently inlined (they have no server-side meaning).\n */\n target?: string;\n /**\n * When truthy, children render inline instead of being teleported.\n * The babel plugin resolves reactive getters before reaching the component,\n * so only a plain boolean is needed on the server.\n */\n disabled?: boolean | (() => boolean);\n}\n\nexport const TELEPORT_CALLSITE_ANCHOR = '<!--teleport-anchor-->';\nexport const TELEPORT_BLOCK_START = '<!--teleport-start-->';\nexport const TELEPORT_BLOCK_END = '<!--teleport-end-->';\n\n/**\n * SSR Portal — collects teleported content into `ctx.teleports[target]`.\n *\n * Emits `<!--teleport-anchor-->` at the call site and wraps children with\n * `<!--teleport-start-->...<!--teleport-end-->` in the target buffer.\n * Disabled / no-target / no-context falls back to inline rendering.\n */\nexport function Portal(props: SSRPortalProps): string {\n const { target, children } = props;\n const rendered = convertToString(children);\n\n // Unwrap disabled getter (for API parity with client)\n const disabled = isFunction(props.disabled)\n ? !!(props.disabled as () => boolean)()\n : !!props.disabled;\n\n if (disabled || !target) return rendered;\n\n const ctx = getSSRContext();\n if (!ctx) return rendered;\n\n // Only string selectors are meaningful for SSR; DOM nodes are inlined.\n if (!isString(target)) {\n if (__DEV__) {\n warn('[Portal] SSR only supports string selector targets; rendering inline.');\n }\n return rendered;\n }\n\n ctx.teleports[target] =\n (ctx.teleports[target] ?? '') + TELEPORT_BLOCK_START + rendered + TELEPORT_BLOCK_END;\n\n return TELEPORT_CALLSITE_ANCHOR;\n}\n\n// ---------------------------------------------------------------------------\n// Suspense (SSR)\n// ---------------------------------------------------------------------------\n\n/**\n * SSR Suspense — renders children when available, otherwise the fallback slot.\n */\nexport function Suspense(props: SSRComponentProps & { fallback?: unknown }): string {\n const { children, fallback } = props;\n return isNil(children) ? convertToString(fallback) : convertToString(children);\n}\n\n// ---------------------------------------------------------------------------\n// For (SSR)\n// ---------------------------------------------------------------------------\n\nexport interface SSRForProps<T> {\n each: T[] | { value: T[] } | (() => T[]);\n children: (item: T, index: number) => unknown;\n key?: (item: T, index: number) => unknown;\n fallback?: unknown;\n}\n\n/** Unwrap signal / getter / plain array for SSR without subscribing. */\nfunction resolveList<T>(input: SSRForProps<T>['each']): T[] {\n if (isNil(input)) return [];\n // Duck-type signal check — avoids importing @estjs/signals on the server.\n if (isObject(input) && 'value' in input) {\n return ((input as { value: T[] }).value ?? []) as T[];\n }\n if (isFunction(input)) {\n return ((input as () => T[])() ?? []) as T[];\n }\n return input as T[];\n}\n\n/**\n * SSR For — maps each item through the render function and joins the output.\n */\nexport function For<T>(props: SSRForProps<T>): string {\n const list = resolveList<T>(props.each);\n\n if (list.length === 0) {\n return convertToString(props.fallback);\n }\n\n const render = props.children;\n if (!isFunction(render)) return '';\n\n return list.map((item, i) => convertToString(render(item, i))).join('');\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@estjs/server",
|
|
3
|
-
"version": "0.0.15-beta.
|
|
3
|
+
"version": "0.0.15-beta.17",
|
|
4
4
|
"description": "Server-side rendering for Essor framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -34,8 +34,9 @@
|
|
|
34
34
|
},
|
|
35
35
|
"sideEffects": false,
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@
|
|
38
|
-
"@estjs/
|
|
37
|
+
"@types/node": "^25.6.0",
|
|
38
|
+
"@estjs/shared": "0.0.15-beta.17",
|
|
39
|
+
"@estjs/template": "0.0.15-beta.17"
|
|
39
40
|
},
|
|
40
41
|
"scripts": {
|
|
41
42
|
"build": "tsup && cross-env NODE_ENV=production tsup --clean=false --treeshake --sourcemap=false",
|