@stacksjs/stx 0.2.155 → 0.2.157

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (241) hide show
  1. package/dist/a11y.d.ts +87 -46
  2. package/dist/animation.d.ts +96 -42
  3. package/dist/appearance-bootstrap.d.ts +49 -15
  4. package/dist/asset-roots.d.ts +32 -0
  5. package/dist/asset-roots.js +7 -0
  6. package/dist/assets.d.ts +9 -7
  7. package/dist/async-components.d.ts +78 -56
  8. package/dist/auth.d.ts +3 -0
  9. package/dist/build-externalize.d.ts +40 -0
  10. package/dist/build-externalize.js +63 -0
  11. package/dist/build-id.d.ts +22 -22
  12. package/dist/build-message.d.ts +73 -2
  13. package/dist/build-message.js +47 -8
  14. package/dist/builtins/attrs.d.ts +14 -0
  15. package/dist/builtins/drawer.d.ts +22 -0
  16. package/dist/builtins/icon.d.ts +16 -2
  17. package/dist/builtins/index.d.ts +5 -15
  18. package/dist/builtins/modal.d.ts +24 -0
  19. package/dist/builtins/safe-image.d.ts +42 -0
  20. package/dist/builtins/stx-image.d.ts +27 -0
  21. package/dist/builtins/stx-link.d.ts +9 -0
  22. package/dist/builtins/stx-loading-indicator.d.ts +11 -0
  23. package/dist/builtins/suspense.d.ts +28 -0
  24. package/dist/builtins/toast.d.ts +17 -0
  25. package/dist/builtins/transition-group.d.ts +25 -0
  26. package/dist/caching.d.ts +12 -15
  27. package/dist/cli.js +1798 -908
  28. package/dist/client/directive.d.ts +7 -0
  29. package/dist/client/index.d.ts +0 -1
  30. package/dist/client-script-bundler.d.ts +63 -5
  31. package/dist/client-script-bundler.js +30 -2
  32. package/dist/client-script.d.ts +102 -47
  33. package/dist/client-script.js +15 -3
  34. package/dist/codemod.d.ts +56 -0
  35. package/dist/codemod.js +192 -0
  36. package/dist/color-mode-boot.d.ts +83 -65
  37. package/dist/component-client-factories.d.ts +1 -6
  38. package/dist/component-processing.d.ts +58 -49
  39. package/dist/component-processing.js +1 -1
  40. package/dist/component-registry.d.ts +94 -31
  41. package/dist/component-renderer.d.ts +18 -0
  42. package/dist/composable-loader.d.ts +24 -0
  43. package/dist/composable-loader.js +12 -9
  44. package/dist/composables/index.d.ts +7 -0
  45. package/dist/composables/index.js +1 -0
  46. package/dist/composables/use-fetch.js +30 -2
  47. package/dist/composables/use-form.d.ts +91 -0
  48. package/dist/composables/use-form.js +112 -0
  49. package/dist/composables.d.ts +64 -60
  50. package/dist/computed.d.ts +86 -92
  51. package/dist/conditionals.d.ts +24 -8
  52. package/dist/conditionals.js +16 -0
  53. package/dist/config.d.ts +34 -21
  54. package/dist/config.js +35 -14
  55. package/dist/craft.js +1476 -768
  56. package/dist/crosswind-config.d.ts +58 -0
  57. package/dist/crosswind-config.js +40 -0
  58. package/dist/csp.d.ts +107 -41
  59. package/dist/defer.d.ts +24 -0
  60. package/dist/dev-server/crosswind.d.ts +35 -26
  61. package/dist/dev-server/crosswind.js +2 -18
  62. package/dist/dev-server/serve-app.js +4 -3
  63. package/dist/dev-server/terminal-colors.d.ts +32 -32
  64. package/dist/directive-api.d.ts +86 -43
  65. package/dist/document-shell.d.ts +54 -41
  66. package/dist/dynamic-components.d.ts +9 -0
  67. package/dist/error-boundaries.d.ts +47 -41
  68. package/dist/error-handling.d.ts +1 -1
  69. package/dist/errors/codes.d.ts +51 -43
  70. package/dist/errors/formatter.d.ts +58 -38
  71. package/dist/errors/index.d.ts +5 -61
  72. package/dist/errors/logger.d.ts +114 -40
  73. package/dist/errors/sanitizer.d.ts +53 -23
  74. package/dist/errors/types.d.ts +44 -31
  75. package/dist/events.d.ts +86 -25
  76. package/dist/expressions.d.ts +50 -42
  77. package/dist/forms-validation.d.ts +138 -123
  78. package/dist/forms-validation.js +1 -90
  79. package/dist/forms.d.ts +120 -66
  80. package/dist/forms.js +31 -11
  81. package/dist/fragment-container.d.ts +57 -0
  82. package/dist/fragment-container.js +109 -0
  83. package/dist/framework-composables.d.ts +32 -0
  84. package/dist/head.d.ts +156 -114
  85. package/dist/heatmap.d.ts +152 -72
  86. package/dist/html-masking.d.ts +40 -34
  87. package/dist/hydration-runtime.d.ts +20 -24
  88. package/dist/i18n.d.ts +93 -32
  89. package/dist/image-optimization/auto-sibling.d.ts +32 -4
  90. package/dist/includes.d.ts +69 -7
  91. package/dist/index.d.ts +66 -0
  92. package/dist/index.js +23 -0
  93. package/dist/internal-markdown.d.ts +12 -8
  94. package/dist/island-chunking.d.ts +30 -13
  95. package/dist/keep-alive.d.ts +72 -52
  96. package/dist/layout-types.d.ts +45 -0
  97. package/dist/layout-types.js +56 -0
  98. package/dist/lazy-module.d.ts +10 -0
  99. package/dist/loops.d.ts +66 -0
  100. package/dist/loops.js +47 -6
  101. package/dist/markdown.d.ts +0 -1
  102. package/dist/media/image/component.d.ts +25 -9
  103. package/dist/media/image/directive.d.ts +15 -1
  104. package/dist/media/image/placeholder.d.ts +20 -9
  105. package/dist/media/image/processor/cache.d.ts +40 -18
  106. package/dist/media/image/processor/index.d.ts +1 -10
  107. package/dist/media/image/processor/optimizer.d.ts +12 -1
  108. package/dist/media/image/processor/responsive.d.ts +16 -6
  109. package/dist/media/image/srcset.d.ts +47 -50
  110. package/dist/media/shared/cache.d.ts +51 -31
  111. package/dist/media/shared/hash.d.ts +7 -0
  112. package/dist/media/types.d.ts +1235 -754
  113. package/dist/media/video/directive.d.ts +15 -1
  114. package/dist/media/video/index.d.ts +39 -17
  115. package/dist/media/video/processor/cache.d.ts +42 -19
  116. package/dist/media/video/processor/index.d.ts +1 -18
  117. package/dist/media/video/processor/streaming.d.ts +17 -10
  118. package/dist/media/video/processor/thumbnail.d.ts +21 -15
  119. package/dist/media/video/processor/transcoder.d.ts +11 -1
  120. package/dist/method-spoofing.d.ts +7 -0
  121. package/dist/middleware.d.ts +60 -0
  122. package/dist/owned-routes.d.ts +42 -0
  123. package/dist/owned-routes.js +26 -0
  124. package/dist/page-meta.d.ts +38 -0
  125. package/dist/page-meta.js +16 -0
  126. package/dist/parser/directive-parser.d.ts +57 -45
  127. package/dist/parser/expression-parser.d.ts +33 -35
  128. package/dist/parser/index.d.ts +4 -39
  129. package/dist/parser/tokenizer.d.ts +61 -49
  130. package/dist/partial-hydration.d.ts +82 -50
  131. package/dist/performance-utils.d.ts +217 -124
  132. package/dist/placeholder.d.ts +18 -9
  133. package/dist/plugin-system.d.ts +264 -115
  134. package/dist/process.d.ts +11 -6
  135. package/dist/process.js +21 -4
  136. package/dist/production-builder.js +7 -0
  137. package/dist/prop-sentinels.d.ts +11 -11
  138. package/dist/public-env.d.ts +14 -0
  139. package/dist/pwa/directives.d.ts +12 -3
  140. package/dist/pwa/inject.d.ts +10 -0
  141. package/dist/pwa/precache.d.ts +22 -16
  142. package/dist/pwa/service-worker.d.ts +12 -0
  143. package/dist/pwa.js +1318 -610
  144. package/dist/reactive-bindings.d.ts +34 -11
  145. package/dist/reactive.d.ts +58 -30
  146. package/dist/reactive.js +56 -31
  147. package/dist/render.d.ts +0 -14
  148. package/dist/render.js +17 -0
  149. package/dist/route-middleware.d.ts +2 -35
  150. package/dist/route-types.d.ts +134 -0
  151. package/dist/route-types.js +24 -0
  152. package/dist/router.d.ts +5 -7
  153. package/dist/routes.d.ts +1 -3
  154. package/dist/runtime-globals.d.ts +147 -24
  155. package/dist/runtime-globals.js +16 -1
  156. package/dist/runtime-injection.d.ts +8 -0
  157. package/dist/runtime-injection.js +33 -24
  158. package/dist/script-emit.d.ts +30 -0
  159. package/dist/script-json.d.ts +36 -0
  160. package/dist/script-json.js +6 -0
  161. package/dist/script-validation.d.ts +21 -4
  162. package/dist/seo.d.ts +118 -47
  163. package/dist/server-bindings.d.ts +21 -0
  164. package/dist/sfc-template.d.ts +8 -8
  165. package/dist/signal-processing.d.ts +35 -15
  166. package/dist/signals-api.d.ts +117 -58
  167. package/dist/signals-api.js +7 -4
  168. package/dist/signals.d.ts +24 -17
  169. package/dist/signals.js +765 -60
  170. package/dist/site-builder/build.js +8 -0
  171. package/dist/site-url.d.ts +46 -0
  172. package/dist/site-url.js +70 -0
  173. package/dist/slots.d.ts +86 -20
  174. package/dist/source-signature.d.ts +45 -0
  175. package/dist/source-signature.js +20 -0
  176. package/dist/ssg.d.ts +285 -142
  177. package/dist/ssg.js +1268 -556
  178. package/dist/state-dir.d.ts +4 -4
  179. package/dist/state-management.d.ts +0 -12
  180. package/dist/state-management.js +8 -25
  181. package/dist/store-imports.d.ts +23 -0
  182. package/dist/store-imports.js +3 -0
  183. package/dist/store-loader.d.ts +10 -0
  184. package/dist/store-loader.js +10 -9
  185. package/dist/story/analytics.d.ts +138 -60
  186. package/dist/story/bookmarks.d.ts +87 -34
  187. package/dist/story/cli.d.ts +123 -69
  188. package/dist/story/collect/scanner.d.ts +4 -0
  189. package/dist/story/collect/tree.d.ts +8 -1
  190. package/dist/story/commands/build.d.ts +11 -6
  191. package/dist/story/commands/dev.d.ts +15 -8
  192. package/dist/story/commands/preview.d.ts +13 -7
  193. package/dist/story/config-watcher.d.ts +20 -13
  194. package/dist/story/config.d.ts +11 -8
  195. package/dist/story/context.d.ts +14 -8
  196. package/dist/story/hmr.d.ts +24 -26
  197. package/dist/story/hot-swap.d.ts +34 -23
  198. package/dist/story/keyboard-shortcuts.d.ts +23 -18
  199. package/dist/story/output.d.ts +46 -44
  200. package/dist/story/performance.d.ts +107 -45
  201. package/dist/story/presets.d.ts +107 -41
  202. package/dist/story/renderer.d.ts +41 -27
  203. package/dist/story/search.d.ts +23 -12
  204. package/dist/story/server.d.ts +21 -11
  205. package/dist/story/setup.d.ts +23 -15
  206. package/dist/story/testing.d.ts +65 -40
  207. package/dist/story/types.d.ts +262 -160
  208. package/dist/streaming.d.ts +119 -57
  209. package/dist/stx-virtual-ts.d.ts +165 -0
  210. package/dist/stx-virtual-ts.js +372 -0
  211. package/dist/stx.d.ts +78 -1
  212. package/dist/style-scoping.d.ts +17 -4
  213. package/dist/suspense.d.ts +67 -52
  214. package/dist/teleport.d.ts +22 -0
  215. package/dist/template-tag-balance.d.ts +22 -6
  216. package/dist/transitions.d.ts +66 -55
  217. package/dist/typecheck.d.ts +77 -0
  218. package/dist/typecheck.js +156 -0
  219. package/dist/types/component-types.d.ts +187 -122
  220. package/dist/types/config-types.d.ts +758 -297
  221. package/dist/types/context-types.d.ts +46 -24
  222. package/dist/types/csp-types.d.ts +70 -66
  223. package/dist/types/directive-types.d.ts +211 -155
  224. package/dist/types/index.d.ts +6 -109
  225. package/dist/types/pwa-types.d.ts +273 -148
  226. package/dist/types.d.ts +0 -1
  227. package/dist/typescript-templates.d.ts +11 -0
  228. package/dist/unresolved-identifiers.d.ts +24 -22
  229. package/dist/unresolved-identifiers.js +2 -0
  230. package/dist/utils.d.ts +24 -21
  231. package/dist/validator.d.ts +28 -26
  232. package/dist/variable-extractor.d.ts +48 -13
  233. package/dist/variable-extractor.js +27 -4
  234. package/dist/view-composers.d.ts +80 -81
  235. package/dist/virtual-scrolling.d.ts +101 -81
  236. package/dist/vue-template.d.ts +23 -0
  237. package/dist/web-components/css-scoping.d.ts +21 -11
  238. package/dist/web-components.d.ts +81 -58
  239. package/dist/x-element.d.ts +0 -1
  240. package/package.json +5 -5
  241. package/stx.d.ts +78 -1
@@ -0,0 +1,372 @@
1
+ import { STX_RUNTIME_GLOBALS } from "./runtime-globals.js";
2
+ const SCRIPT_RE = /<script(\s[^>]*)?>([\s\S]*?)<\/script>/gi;
3
+ export function extractScriptBlocks(source) {
4
+ const blocks = [];
5
+ SCRIPT_RE.lastIndex = 0;
6
+ let match;
7
+ while ((match = SCRIPT_RE.exec(source)) !== null) {
8
+ const attrs = (match[1] || "").trim(), body = match[2] ?? "";
9
+ if (/\bsrc\s*=/.test(attrs))
10
+ continue;
11
+ const typeMatch = attrs.match(/\btype\s*=\s*["']([^"']+)["']/i);
12
+ if (typeMatch && !/^(?:module|text\/(?:javascript|typescript))$/i.test(typeMatch[1]))
13
+ continue;
14
+ const kind = /\bserver\b/.test(attrs) ? "server" : /\bclient\b/.test(attrs) ? "client" : "plain", openTag = match[0].match(/^<script[^>]*>/i)?.[0] ?? "<script>", startLine = lineAt(source, match.index + openTag.length);
15
+ blocks.push({ kind, code: body, startLine, attrs });
16
+ }
17
+ return blocks;
18
+ }
19
+ function lineAt(source, offset) {
20
+ let line = 1;
21
+ for (let i = 0;i < offset && i < source.length; i++)
22
+ if (source.charCodeAt(i) === 10)
23
+ line++;
24
+ return line;
25
+ }
26
+ function columnAt(source, offset) {
27
+ const lineStart = source.lastIndexOf(`
28
+ `, offset - 1) + 1;
29
+ return offset - lineStart + 1;
30
+ }
31
+ export function maskNonTemplateRegions(source) {
32
+ const chars = source.split(""), blank = (start, end) => {
33
+ for (let i = start;i < end && i < chars.length; i++)
34
+ if (chars[i] !== `
35
+ `)
36
+ chars[i] = " ";
37
+ }, regions = [
38
+ /<script(?:\s[^>]*)?>[\s\S]*?<\/script>/gi,
39
+ /<style(?:\s[^>]*)?>[\s\S]*?<\/style>/gi,
40
+ /<!--[\s\S]*?-->/g,
41
+ /\{\{--[\s\S]*?--\}\}/g,
42
+ /@verbatim\b[\s\S]*?@endverbatim\b/g
43
+ ];
44
+ for (const re of regions) {
45
+ re.lastIndex = 0;
46
+ let m;
47
+ while ((m = re.exec(source)) !== null)
48
+ blank(m.index, m.index + m[0].length);
49
+ }
50
+ return chars.join("");
51
+ }
52
+ export function stripFilterChain(expression) {
53
+ let depth = 0, quote = "";
54
+ for (let i = 0;i < expression.length; i++) {
55
+ const ch = expression[i];
56
+ if (quote) {
57
+ if (ch === "\\") {
58
+ i++;
59
+ continue;
60
+ }
61
+ if (ch === quote)
62
+ quote = "";
63
+ continue;
64
+ }
65
+ if (ch === '"' || ch === "'" || ch === "`") {
66
+ quote = ch;
67
+ continue;
68
+ }
69
+ if (ch === "(" || ch === "[" || ch === "{") {
70
+ depth++;
71
+ continue;
72
+ }
73
+ if (ch === ")" || ch === "]" || ch === "}") {
74
+ depth--;
75
+ continue;
76
+ }
77
+ if (ch === "|" && depth === 0) {
78
+ if (expression[i + 1] === "|") {
79
+ i++;
80
+ continue;
81
+ }
82
+ if (expression[i - 1] === "|")
83
+ continue;
84
+ return expression.slice(0, i);
85
+ }
86
+ }
87
+ return expression;
88
+ }
89
+ const FOR_ATTRS = new Set([":for", "x-for", "v-for"]), DIRECTIVE_ATTR_RE = /(?:^|\s)((?::|x-|v-|@)[\w.:-]+)\s*=\s*(["'])([\s\S]*?)\2/g;
90
+ export const INTERPOLATION_PLACEHOLDER = "__stx_interpolated", ELEMENT_HELPER = "__StxElement", UNWRAP_HELPER = "__StxTemplateValue";
91
+ const UNWRAP_HELPER_DECL = `type ${UNWRAP_HELPER}<T> = T extends { readonly _isSignal: true } | { readonly _isDerived: true } ? (T extends () => infer V ? T & V : T) : T`;
92
+ export function substituteInterpolations(value) {
93
+ return value.replace(/\{\{[\s\S]*?\}\}/g, INTERPOLATION_PLACEHOLDER).replace(/\{!![\s\S]*?!!\}/g, INTERPOLATION_PLACEHOLDER);
94
+ }
95
+ const NON_EXPRESSION_ATTRS = new Set([
96
+ "x-cloak",
97
+ "x-ref",
98
+ "x-transition",
99
+ "x-teleport",
100
+ "v-slot",
101
+ "x-hydrate",
102
+ ":key"
103
+ ]);
104
+ export function extractTemplateExpressions(source) {
105
+ const masked = maskNonTemplateRegions(source), found = [], interpolation = /(@?)\{\{([\s\S]*?)\}\}|(@?)\{!!([\s\S]*?)!!\}/g;
106
+ let m;
107
+ while ((m = interpolation.exec(masked)) !== null) {
108
+ if (m[1] || m[3])
109
+ continue;
110
+ const raw = m[2] ?? m[4] ?? "", openLength = m[2] !== void 0 ? 2 : 3, code = stripFilterChain(raw);
111
+ if (!code.trim())
112
+ continue;
113
+ const offset = m.index + openLength + (code.length - code.trimStart().length);
114
+ found.push({
115
+ code: code.trim(),
116
+ line: lineAt(masked, offset),
117
+ column: columnAt(masked, offset),
118
+ kind: "interpolation"
119
+ });
120
+ }
121
+ DIRECTIVE_ATTR_RE.lastIndex = 0;
122
+ while ((m = DIRECTIVE_ATTR_RE.exec(masked)) !== null) {
123
+ const name = m[1], value = m[3] ?? "", base = name.replace(/\..*$/, "");
124
+ if (NON_EXPRESSION_ATTRS.has(base) || NON_EXPRESSION_ATTRS.has(name))
125
+ continue;
126
+ if (!value.trim())
127
+ continue;
128
+ const offset = m.index + m[0].indexOf(m[2], m[0].indexOf(name) + name.length) + 1;
129
+ if (FOR_ATTRS.has(base)) {
130
+ const inMatch = value.match(/\s+(?:in|of)\s+/);
131
+ if (!inMatch || inMatch.index === void 0)
132
+ continue;
133
+ const iterable = value.slice(inMatch.index + inMatch[0].length), iterableStart = inMatch.index + inMatch[0].length + (iterable.length - iterable.trimStart().length);
134
+ found.push({
135
+ code: substituteInterpolations(iterable.trim()),
136
+ line: lineAt(masked, offset + iterableStart),
137
+ column: columnAt(masked, offset + iterableStart),
138
+ kind: "directive",
139
+ attribute: base
140
+ });
141
+ continue;
142
+ }
143
+ const lead = value.length - value.trimStart().length;
144
+ found.push({
145
+ code: substituteInterpolations(value.trim()),
146
+ line: lineAt(masked, offset + lead),
147
+ column: columnAt(masked, offset + lead),
148
+ kind: "directive",
149
+ attribute: base
150
+ });
151
+ }
152
+ found.sort((a, b) => a.line - b.line || a.column - b.column);
153
+ return found;
154
+ }
155
+ export function collectTemplateBindings(source) {
156
+ const bindings = new Map, add = (raw, iterable) => {
157
+ const parts = raw.split(/[,[\]{}()\s]+/).filter(Boolean);
158
+ for (const part of parts) {
159
+ const name = part.replace(/^\.\.\./, "").trim();
160
+ if (!/^\$?[A-Z_$][\w$]*$/i.test(name))
161
+ continue;
162
+ const typed = parts.length === 1 ? iterable : void 0, existing = bindings.get(name);
163
+ if (!existing)
164
+ bindings.set(name, { name, iterable: typed });
165
+ else if (existing.iterable !== typed)
166
+ existing.iterable = void 0;
167
+ }
168
+ }, IDENTIFIER = /^\$?[A-Z_$][\w$]*$/i, iterableOf = (raw) => {
169
+ const trimmed = raw.trim();
170
+ return IDENTIFIER.test(trimmed) ? trimmed : void 0;
171
+ };
172
+ for (const m of source.matchAll(/@for(?:each|else)\s*\(([\s\S]*?)\)/g)) {
173
+ const asMatch = m[1].match(/^([\s\S]*?)\bas\b([\s\S]*)$/);
174
+ if (!asMatch)
175
+ continue;
176
+ add(asMatch[2].replace(/=>/g, " "), iterableOf(asMatch[1]));
177
+ }
178
+ for (const m of source.matchAll(/@for\s*\(\s*(?:let|const|var)\s+([\w$]+)/g))
179
+ add(m[1]);
180
+ const masked = maskNonTemplateRegions(source);
181
+ DIRECTIVE_ATTR_RE.lastIndex = 0;
182
+ let m;
183
+ while ((m = DIRECTIVE_ATTR_RE.exec(masked)) !== null) {
184
+ const base = m[1].replace(/\..*$/, "");
185
+ if (!FOR_ATTRS.has(base))
186
+ continue;
187
+ const inMatch = m[3].match(/\s+(?:in|of)\s+/);
188
+ if (!inMatch || inMatch.index === void 0)
189
+ continue;
190
+ add(m[3].slice(0, inMatch.index), iterableOf(m[3].slice(inMatch.index + inMatch[0].length)));
191
+ }
192
+ for (const block of source.matchAll(/@(?:php|js|ts)\b([\s\S]*?)@end(?:php|js|ts)\b/g))
193
+ for (const decl of block[1].matchAll(/\b(?:const|let|var|function|class)\s+([\w$]+)/g))
194
+ add(decl[1]);
195
+ return [...bindings.values()].sort((a, b) => a.name.localeCompare(b.name));
196
+ }
197
+ export function collectBlockDeclarations(code) {
198
+ const names = new Set;
199
+ for (const m of code.matchAll(/^\s*(?:export\s+)?(?:const|let|var)\s+([\w$]+)/gm))
200
+ names.add(m[1]);
201
+ for (const m of code.matchAll(/^\s*(?:export\s+)?(?:async\s+)?function\s*\*?\s*([\w$]+)/gm))
202
+ names.add(m[1]);
203
+ for (const m of code.matchAll(/^\s*(?:export\s+)?class\s+([\w$]+)/gm))
204
+ names.add(m[1]);
205
+ for (const m of code.matchAll(/^\s*(?:export\s+)?(?:const|let|var)\s*[[{]([^\]}]*)[\]}]/gm))
206
+ for (const part of m[1].split(",")) {
207
+ const name = part.split(":").pop().split("=")[0].replace(/^\.\.\./, "").trim();
208
+ if (/^[A-Z_$][\w$]*$/i.test(name))
209
+ names.add(name);
210
+ }
211
+ return [...names].sort();
212
+ }
213
+ const IMPORT_LINE_RE = /^\s*import\s[\s\S]*?(?:$|;)/;
214
+ export function runtimeGlobalDeclarations() {
215
+ return [
216
+ "declare var window: any",
217
+ ...STX_RUNTIME_GLOBALS.map((name) => `declare var ${name}: any`)
218
+ ].join(`
219
+ `);
220
+ }
221
+ export const STX_SERVER_CONTEXT = [
222
+ "params",
223
+ "query",
224
+ "cookies",
225
+ "host",
226
+ "ip",
227
+ "setResponseStatus",
228
+ "setResponseHeader",
229
+ "request",
230
+ "url",
231
+ "definePageMeta"
232
+ ];
233
+ export function serverContextDeclarations() {
234
+ return STX_SERVER_CONTEXT.map((name) => `declare var ${name}: any`).join(`
235
+ `);
236
+ }
237
+ export const STX_TEMPLATE_GLOBALS = [
238
+ "$env",
239
+ "$user",
240
+ "$slot",
241
+ "$slots",
242
+ "$attrs",
243
+ "$props",
244
+ "$page",
245
+ "$route",
246
+ "$loop",
247
+ "$errors",
248
+ "$csrf",
249
+ "props",
250
+ "slot"
251
+ ];
252
+ export function crossScopeCollisions(blocks) {
253
+ const server = new Set, client = new Set;
254
+ for (const block of blocks) {
255
+ const target = block.kind === "server" ? server : client;
256
+ for (const name of collectBlockDeclarations(block.code))
257
+ target.add(name);
258
+ }
259
+ return [...server].filter((name) => client.has(name)).sort();
260
+ }
261
+ const DIRECT_ASSIGNMENT_RE = /^\s*[A-Z_$][\w$]*\s*=[^=]/i;
262
+ export function expressionStatement(expression) {
263
+ const code = expression.code.trim();
264
+ if (!code)
265
+ return null;
266
+ if (expression.attribute?.startsWith("@")) {
267
+ if (DIRECT_ASSIGNMENT_RE.test(code))
268
+ return null;
269
+ const prefix = ";(($event: any): void => { ";
270
+ return { text: `${prefix}${code} });`, prefixLength: prefix.length };
271
+ }
272
+ const prefix = ";void ((";
273
+ return { text: `${prefix}${code}));`, prefixLength: prefix.length };
274
+ }
275
+ export function buildVirtualTypeScript(source, options = {}) {
276
+ const blocks = extractScriptBlocks(source), sourceLines = source.split(`
277
+ `), lines = Array.from({ length: sourceLines.length }, () => ""), lineMap = new Map;
278
+ for (const block of blocks)
279
+ block.code.split(`
280
+ `).forEach((text, i) => {
281
+ const index = block.startLine - 1 + i;
282
+ if (index < lines.length)
283
+ lines[index] = text;
284
+ });
285
+ const append = (text, origin) => {
286
+ lines.push(text);
287
+ if (origin)
288
+ lineMap.set(lines.length, origin);
289
+ };
290
+ if (options.globals !== !1) {
291
+ append("");
292
+ if (options.runtimeGlobals !== !1)
293
+ for (const decl of runtimeGlobalDeclarations().split(`
294
+ `))
295
+ append(decl);
296
+ for (const decl of serverContextDeclarations().split(`
297
+ `))
298
+ append(decl);
299
+ for (const name of STX_TEMPLATE_GLOBALS)
300
+ append(`declare var ${name}: any`);
301
+ append(`declare var ${INTERPOLATION_PLACEHOLDER}: any`);
302
+ const declared = new Set(blocks.flatMap((block) => collectBlockDeclarations(block.code)));
303
+ append(`type ${ELEMENT_HELPER}<T> = T extends readonly (infer E)[] ? E : T extends Iterable<infer E2> ? E2 : any`);
304
+ for (const binding of collectTemplateBindings(source)) {
305
+ if (declared.has(binding.name))
306
+ continue;
307
+ const type = binding.iterable && declared.has(binding.iterable) ? `${ELEMENT_HELPER}<typeof ${binding.iterable}>` : "any";
308
+ append(`declare var ${binding.name}: ${type}`);
309
+ }
310
+ }
311
+ if (options.templateExpressions !== !1) {
312
+ const statements = extractTemplateExpressions(source).map((expression) => ({ expression, statement: expressionStatement(expression) })).filter((entry) => entry.statement !== null);
313
+ if (statements.length > 0) {
314
+ const shadowed = [...new Set(blocks.flatMap((block) => collectBlockDeclarations(block.code)))].filter((name) => /^[A-Z_$][\w$]*$/i.test(name));
315
+ let indent = 0;
316
+ if (shadowed.length > 0) {
317
+ append(UNWRAP_HELPER_DECL);
318
+ for (const name of shadowed)
319
+ append(`type __StxT_${name} = ${UNWRAP_HELPER}<typeof ${name}>`);
320
+ append(`;((${shadowed.map((name) => `${name}: __StxT_${name}`).join(", ")}) => {`);
321
+ indent = 1;
322
+ }
323
+ for (const { expression, statement } of statements) {
324
+ const pad = " ".repeat(indent);
325
+ append(pad + statement.text, {
326
+ line: expression.line,
327
+ column: expression.column,
328
+ expression,
329
+ prefixLength: statement.prefixLength + pad.length
330
+ });
331
+ }
332
+ if (indent > 0)
333
+ append("});");
334
+ }
335
+ }
336
+ append("export {}");
337
+ return { text: lines.join(`
338
+ `), lineMap, sourceLineCount: sourceLines.length };
339
+ }
340
+ export function lineStarts(text) {
341
+ const starts = [0];
342
+ for (let i = 0;i < text.length; i++)
343
+ if (text.charCodeAt(i) === 10)
344
+ starts.push(i + 1);
345
+ return starts;
346
+ }
347
+ export function offsetToPosition(starts, offset) {
348
+ let low = 0, high = starts.length - 1;
349
+ while (low < high) {
350
+ const mid = Math.ceil((low + high) / 2);
351
+ if (starts[mid] <= offset)
352
+ low = mid;
353
+ else
354
+ high = mid - 1;
355
+ }
356
+ return { line: low + 1, column: offset - starts[low] + 1 };
357
+ }
358
+ export function positionToOffset(starts, line, column) {
359
+ const index = Math.min(Math.max(line, 1), starts.length) - 1, next = index + 1 < starts.length ? starts[index + 1] - 1 : Number.MAX_SAFE_INTEGER;
360
+ return Math.min(starts[index] + Math.max(column, 1) - 1, next);
361
+ }
362
+ export function resolvePosition(virtual, line, column) {
363
+ const mapped = virtual.lineMap.get(line);
364
+ if (!mapped)
365
+ return line <= virtual.sourceLineCount ? { line, column } : null;
366
+ const within = Math.max(0, column - 1 - (mapped.prefixLength ?? 0));
367
+ return {
368
+ line: mapped.line,
369
+ column: mapped.column + within,
370
+ expression: mapped.expression
371
+ };
372
+ }
package/dist/stx.d.ts CHANGED
@@ -124,9 +124,24 @@ interface StxNavigateOptions {
124
124
  * shape that actually shipped — but keeping it out of the type means nothing
125
125
  * that type-checks today changes meaning (#1807).
126
126
  */
127
- declare function navigate(_url: string, _options?: StxNavigateOptions): void
127
+ declare function navigate<T extends string>(
128
+ _url: T & import('@stacksjs/stx').CheckHref<T>,
129
+ _options?: StxNavigateOptions,
130
+ ): void
128
131
  declare function goBack(): void
129
132
  declare function goForward(): void
133
+
134
+ /**
135
+ * Re-run the current route against the server and swap the result, without a
136
+ * document load. Use after a mutation that changed server-rendered content.
137
+ */
138
+ declare function refresh(): Promise<boolean>
139
+
140
+ /**
141
+ * Expire one cached route so the next visit re-fetches it. Defaults to the
142
+ * current path.
143
+ */
144
+ declare function invalidateRoute(_url?: string): void
130
145
  declare function useRoute(): {
131
146
  path: string
132
147
  params: Record<string, string>
@@ -134,6 +149,17 @@ declare function useRoute(): {
134
149
  hash: string
135
150
  }
136
151
  declare function setRouteParams(_params: Record<string, string>): void
152
+
153
+ /**
154
+ * Reactive access to the current route's dynamic segments.
155
+ *
156
+ * Published on `window.stx` by 5daaba1f9b but never added to the auto-imported
157
+ * list, so it was reachable only as `window.stx.useRouteParams()` — exactly the
158
+ * authoring-surface gap in #1846.
159
+ */
160
+ declare function useRouteParams(): StxSignal<Record<string, string>>
161
+ /** One dynamic segment, as a signal. */
162
+ declare function useRouteParam(_name: string, _defaultValue?: string): StxSignal<string>
137
163
  /** How a search-param mutation is written to session history (#1825). */
138
164
  interface StxSearchParamsCommitOptions {
139
165
  /** Replace the current history entry instead of pushing a new one. */
@@ -190,6 +216,52 @@ interface StxMutationResult<T> {
190
216
  declare function useFetch<T = any>(_url: string, _options?: any): StxQueryResult<T>
191
217
  declare function useQuery<T = any>(_url: string, _options?: any): StxQueryResult<T>
192
218
  declare function useMutation<T = any>(_url: string, _options?: any): StxMutationResult<T>
219
+
220
+ /** Context handed to a request interceptor. Mutate it; the return is ignored. */
221
+ interface StxFetchRequestContext {
222
+ /** Which primitive made the call: 'useFetch' | 'useQuery' | 'useMutation'. */
223
+ source: string
224
+ /** Reassignable, so a hook can prefix a baseURL. */
225
+ url: string
226
+ /** `headers` is normalised to an object before the hook runs. */
227
+ options: RequestInit & { headers: Record<string, string> }
228
+ }
229
+
230
+ /** Context handed to a response interceptor. */
231
+ interface StxFetchResponseContext extends StxFetchRequestContext {
232
+ response: Response
233
+ }
234
+
235
+ /**
236
+ * Context handed to an error interceptor. `response` is the non-ok Response, or
237
+ * null when the fetch itself threw (a network failure); `error` is set only in
238
+ * the latter case.
239
+ */
240
+ interface StxFetchErrorContext extends StxFetchRequestContext {
241
+ response: Response | null
242
+ error: Error | null
243
+ }
244
+
245
+ /**
246
+ * Install request/response interceptors for every stx data primitive.
247
+ *
248
+ * All three funnel through one internal fetch, so a single pair of hooks
249
+ * carries an auth header or observes a 401 across `useFetch`, `useQuery` and
250
+ * `useMutation`. Calling this again REPLACES the hooks rather than adding to
251
+ * them, so a re-evaluated module cannot install the same interceptor twice.
252
+ *
253
+ * `onResponseError` fires for a non-ok response and for a thrown fetch. Return
254
+ * a Response to replace the failed one — the shape a 401 -> refresh -> retry
255
+ * takes: refresh the token, re-issue the request with a plain `fetch()` (not
256
+ * this data layer, so it does not re-enter the hook), and return that Response.
257
+ * Return nothing to let the original error stand.
258
+ */
259
+ declare function configureFetch(_config: {
260
+ onRequest?: (_ctx: StxFetchRequestContext) => void | Promise<void>
261
+ onResponse?: (_ctx: StxFetchResponseContext) => void | Promise<void>
262
+ onResponseError?: (_ctx: StxFetchErrorContext) => void | Response | Promise<void | Response>
263
+ }): void
264
+
193
265
  declare function useOptimistic<T = any, A = any>(
194
266
  _base: StxSignal<T> | (() => T) | T,
195
267
  _reducer: (_current: T, _action: A) => T,
@@ -591,14 +663,19 @@ interface StxRuntimeRegistry {
591
663
  useRef: typeof useRef
592
664
  useQuery: typeof useQuery
593
665
  useMutation: typeof useMutation
666
+ configureFetch: typeof configureFetch
594
667
  useOptimistic: typeof useOptimistic
595
668
 
596
669
  // Routing
597
670
  navigate: typeof navigate
598
671
  goBack: typeof goBack
599
672
  goForward: typeof goForward
673
+ refresh: typeof refresh
674
+ invalidateRoute: typeof invalidateRoute
600
675
  useRoute: typeof useRoute
601
676
  setRouteParams: typeof setRouteParams
677
+ useRouteParams: typeof useRouteParams
678
+ useRouteParam: typeof useRouteParam
602
679
  useSearchParams: typeof useSearchParams
603
680
 
604
681
  // Composition
@@ -1,3 +1,20 @@
1
+ /**
2
+ * SFC Style Scoping
3
+ *
4
+ * Processes `<style scoped>` blocks in `.stx` single-file components.
5
+ * Scopes CSS selectors to the component using a deterministic hash attribute,
6
+ * preventing style leakage between components.
7
+ *
8
+ * Uses the CSS scoping utilities from `web-components/css-scoping.ts`.
9
+ *
10
+ * @module style-scoping
11
+ */
12
+ export interface ScopedStyleResult {
13
+ /** The modified HTML with scope attributes added to root elements and scoped style tags */
14
+ html: string;
15
+ /** Whether any scoped styles were found and processed */
16
+ hasScoped: boolean;
17
+ }
1
18
  /**
2
19
  * Keep one copy of each rendered scoped stylesheet.
3
20
  *
@@ -23,7 +40,3 @@ export declare function dedupeScopedStyles(html: string): string;
23
40
  * @returns Processed template with scoped styles
24
41
  */
25
42
  export declare function processScopedStyles(template: string, filePath: string): ScopedStyleResult;
26
- export declare interface ScopedStyleResult {
27
- html: string
28
- hasScoped: boolean
29
- }
@@ -1,3 +1,58 @@
1
+ /**
2
+ * STX Suspense
3
+ *
4
+ * Coordinates async loading across component trees, showing a fallback
5
+ * until all async children are resolved.
6
+ *
7
+ * @module suspense
8
+ *
9
+ * @example
10
+ * ```html
11
+ * @suspense
12
+ * <UserProfile :id="userId" />
13
+ * <UserActivity :id="userId" />
14
+ * <UserStats :id="userId" />
15
+ * @fallback
16
+ * <PageSkeleton />
17
+ * @endsuspense
18
+ * ```
19
+ */
20
+ export interface SuspenseOptions {
21
+ /** Custom ID for tracking */
22
+ id?: string;
23
+ /** Timeout before showing error (ms) */
24
+ timeout?: number;
25
+ /** Callback when all children resolve */
26
+ onResolve?: () => void;
27
+ /** Callback when any child rejects */
28
+ onError?: (error: Error) => void;
29
+ /** Callback when loading starts */
30
+ onPending?: () => void;
31
+ }
32
+ export interface SuspenseState {
33
+ /** Current state */
34
+ status: 'pending' | 'resolved' | 'rejected';
35
+ /** Pending async children */
36
+ pending: Set<string>;
37
+ /** Resolved async children */
38
+ resolved: Set<string>;
39
+ /** First error encountered */
40
+ error: Error | null;
41
+ }
42
+ export interface SuspenseBoundary {
43
+ /** Unique boundary ID */
44
+ id: string;
45
+ /** Current state */
46
+ state: SuspenseState;
47
+ /** Register an async child */
48
+ register: (childId: string) => void;
49
+ /** Mark a child as resolved */
50
+ resolve: (childId: string) => void;
51
+ /** Mark a child as rejected */
52
+ reject: (childId: string, error: Error) => void;
53
+ /** Reset the boundary */
54
+ reset: () => void;
55
+ }
1
56
  /**
2
57
  * Process @suspense directives in templates.
3
58
  *
@@ -12,6 +67,14 @@
12
67
  * @suspense(timeout: 10000)
13
68
  */
14
69
  export declare function processSuspenseDirectives(template: string, _context?: Record<string, unknown>, _filePath?: string): string;
70
+ /**
71
+ * Server-side suspense boundary for SSR streaming.
72
+ */
73
+ export interface SSRSuspenseBoundary {
74
+ id: string;
75
+ fallback: string;
76
+ content: Promise<string>;
77
+ }
15
78
  /**
16
79
  * Create an SSR suspense boundary.
17
80
  * Returns the fallback immediately, then streams the content when ready.
@@ -21,7 +84,10 @@ export declare function createSSRSuspense(id: string, contentPromise: Promise<st
21
84
  * Render SSR suspense boundaries for streaming.
22
85
  * Returns initial HTML with fallbacks, plus a script to replace them when content loads.
23
86
  */
24
- export declare function renderSSRSuspense(boundaries: SSRSuspenseBoundary[]): Promise<{ initial: string; streaming: AsyncGenerator<string> }>;
87
+ export declare function renderSSRSuspense(boundaries: SSRSuspenseBoundary[]): Promise<{
88
+ initial: string;
89
+ streaming: AsyncGenerator<string>;
90
+ }>;
25
91
  /**
26
92
  * Generate CSS for suspense styling.
27
93
  */
@@ -30,54 +96,3 @@ export declare function generateSuspenseCSS(): string;
30
96
  * Generate client-side runtime for suspense.
31
97
  */
32
98
  export declare function generateSuspenseRuntime(): string;
33
- /**
34
- * STX Suspense
35
- *
36
- * Coordinates async loading across component trees, showing a fallback
37
- * until all async children are resolved.
38
- *
39
- * @module suspense
40
- *
41
- * @example
42
- * ```html
43
- * @suspense
44
- * <UserProfile :id="userId" />
45
- * <UserActivity :id="userId" />
46
- * <UserStats :id="userId" />
47
- * @fallback
48
- * <PageSkeleton />
49
- * @endsuspense
50
- * ```
51
- */
52
- // =============================================================================
53
- // Types
54
- // =============================================================================
55
- export declare interface SuspenseOptions {
56
- id?: string
57
- timeout?: number
58
- onResolve?: () => void
59
- onError?: (error: Error) => void
60
- onPending?: () => void
61
- }
62
- export declare interface SuspenseState {
63
- status: 'pending' | 'resolved' | 'rejected'
64
- pending: Set<string>
65
- resolved: Set<string>
66
- error: Error | null
67
- }
68
- export declare interface SuspenseBoundary {
69
- id: string
70
- state: SuspenseState
71
- register: (childId: string) => void
72
- resolve: (childId: string) => void
73
- reject: (childId: string, error: Error) => void
74
- reset: () => void
75
- }
76
- /**
77
- * Server-side suspense boundary for SSR streaming.
78
- */
79
- export declare interface SSRSuspenseBoundary {
80
- id: string
81
- fallback: string
82
- content: Promise<string>
83
- }
@@ -1,3 +1,25 @@
1
+ /**
2
+ * Teleport Directive
3
+ *
4
+ * Moves content to a different location in the DOM.
5
+ * Useful for modals, tooltips, notifications that need to escape
6
+ * their parent's stacking context.
7
+ *
8
+ * Usage:
9
+ * @teleport('#modals')
10
+ * <div class="modal">Modal content</div>
11
+ * @endteleport
12
+ *
13
+ * With disabled state:
14
+ * @teleport('#modals', disabled: isInline)
15
+ * <div class="modal">Modal content</div>
16
+ * @endteleport
17
+ *
18
+ * Multiple targets:
19
+ * @teleport('body') - Appends to body
20
+ * @teleport('#app') - Appends to #app element
21
+ * @teleport('.modals-container') - Appends to first matching element
22
+ */
1
23
  /**
2
24
  * Process @teleport directives in template
3
25
  */