@pwfabric/runtime 0.0.0-stage → 1.0.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (447) hide show
  1. package/LICENSE +90 -0
  2. package/README.md +43 -2
  3. package/dist/a11y/announcer.d.ts +65 -0
  4. package/dist/a11y/announcer.js +140 -0
  5. package/dist/a11y/announcer.js.map +1 -0
  6. package/dist/a11y/contrast.d.ts +54 -0
  7. package/dist/a11y/contrast.js +93 -0
  8. package/dist/a11y/contrast.js.map +1 -0
  9. package/dist/a11y/focus.d.ts +123 -0
  10. package/dist/a11y/focus.js +282 -0
  11. package/dist/a11y/focus.js.map +1 -0
  12. package/dist/a11y/index.d.ts +21 -0
  13. package/dist/a11y/index.js +18 -0
  14. package/dist/a11y/index.js.map +1 -0
  15. package/dist/a11y/keyboard.d.ts +144 -0
  16. package/dist/a11y/keyboard.js +317 -0
  17. package/dist/a11y/keyboard.js.map +1 -0
  18. package/dist/adapters/default-image.d.ts +25 -0
  19. package/dist/adapters/default-image.js +37 -0
  20. package/dist/adapters/default-image.js.map +1 -0
  21. package/dist/adapters/index.d.ts +27 -0
  22. package/dist/adapters/index.js +28 -0
  23. package/dist/adapters/index.js.map +1 -0
  24. package/dist/adapters/next-image.d.ts +38 -0
  25. package/dist/adapters/next-image.js +124 -0
  26. package/dist/adapters/next-image.js.map +1 -0
  27. package/dist/adapters/types.d.ts +61 -0
  28. package/dist/adapters/types.js +11 -0
  29. package/dist/adapters/types.js.map +1 -0
  30. package/dist/analytics/index.d.ts +14 -0
  31. package/dist/analytics/index.js +15 -0
  32. package/dist/analytics/index.js.map +1 -0
  33. package/dist/analytics/tracker.d.ts +65 -0
  34. package/dist/analytics/tracker.js +251 -0
  35. package/dist/analytics/tracker.js.map +1 -0
  36. package/dist/analytics/types.d.ts +130 -0
  37. package/dist/analytics/types.js +11 -0
  38. package/dist/analytics/types.js.map +1 -0
  39. package/dist/auth/index.d.ts +15 -0
  40. package/dist/auth/index.js +14 -0
  41. package/dist/auth/index.js.map +1 -0
  42. package/dist/auth/provider.d.ts +132 -0
  43. package/dist/auth/provider.js +473 -0
  44. package/dist/auth/provider.js.map +1 -0
  45. package/dist/auth/types.d.ts +117 -0
  46. package/dist/auth/types.js +9 -0
  47. package/dist/auth/types.js.map +1 -0
  48. package/dist/binding/collection.d.ts +190 -0
  49. package/dist/binding/collection.js +358 -0
  50. package/dist/binding/collection.js.map +1 -0
  51. package/dist/binding/datasource.d.ts +319 -0
  52. package/dist/binding/datasource.js +556 -0
  53. package/dist/binding/datasource.js.map +1 -0
  54. package/dist/binding/engine.d.ts +65 -0
  55. package/dist/binding/engine.js +268 -0
  56. package/dist/binding/engine.js.map +1 -0
  57. package/dist/binding/expression.d.ts +150 -0
  58. package/dist/binding/expression.js +787 -0
  59. package/dist/binding/expression.js.map +1 -0
  60. package/dist/binding/index.d.ts +19 -0
  61. package/dist/binding/index.js +14 -0
  62. package/dist/binding/index.js.map +1 -0
  63. package/dist/binding/two-way.d.ts +149 -0
  64. package/dist/binding/two-way.js +462 -0
  65. package/dist/binding/two-way.js.map +1 -0
  66. package/dist/binding/types.d.ts +119 -0
  67. package/dist/binding/types.js +9 -0
  68. package/dist/binding/types.js.map +1 -0
  69. package/dist/blocks/component-types.d.ts +81 -0
  70. package/dist/blocks/component-types.js +11 -0
  71. package/dist/blocks/component-types.js.map +1 -0
  72. package/dist/blocks/composition-rules.d.ts +168 -0
  73. package/dist/blocks/composition-rules.js +391 -0
  74. package/dist/blocks/composition-rules.js.map +1 -0
  75. package/dist/blocks/hooks.d.ts +31 -0
  76. package/dist/blocks/hooks.js +42 -0
  77. package/dist/blocks/hooks.js.map +1 -0
  78. package/dist/blocks/index.d.ts +14 -0
  79. package/dist/blocks/index.js +23 -0
  80. package/dist/blocks/index.js.map +1 -0
  81. package/dist/blocks/registry.d.ts +84 -0
  82. package/dist/blocks/registry.js +136 -0
  83. package/dist/blocks/registry.js.map +1 -0
  84. package/dist/blocks/rule-engine.d.ts +131 -0
  85. package/dist/blocks/rule-engine.js +321 -0
  86. package/dist/blocks/rule-engine.js.map +1 -0
  87. package/dist/blocks/surface-event-context.d.ts +13 -0
  88. package/dist/blocks/surface-event-context.js +14 -0
  89. package/dist/blocks/surface-event-context.js.map +1 -0
  90. package/dist/blocks/surface-id-context.d.ts +13 -0
  91. package/dist/blocks/surface-id-context.js +15 -0
  92. package/dist/blocks/surface-id-context.js.map +1 -0
  93. package/dist/bus.d.ts +41 -0
  94. package/dist/bus.js +158 -0
  95. package/dist/bus.js.map +1 -0
  96. package/dist/cache/index.d.ts +9 -0
  97. package/dist/cache/index.js +10 -0
  98. package/dist/cache/index.js.map +1 -0
  99. package/dist/cache/memory.d.ts +32 -0
  100. package/dist/cache/memory.js +138 -0
  101. package/dist/cache/memory.js.map +1 -0
  102. package/dist/cache/types.d.ts +62 -0
  103. package/dist/cache/types.js +9 -0
  104. package/dist/cache/types.js.map +1 -0
  105. package/dist/capability/index.d.ts +72 -0
  106. package/dist/capability/index.js +87 -0
  107. package/dist/capability/index.js.map +1 -0
  108. package/dist/capability/kernel-capabilities.d.ts +31 -0
  109. package/dist/capability/kernel-capabilities.js +36 -0
  110. package/dist/capability/kernel-capabilities.js.map +1 -0
  111. package/dist/capability/platform-capabilities.d.ts +71 -0
  112. package/dist/capability/platform-capabilities.js +267 -0
  113. package/dist/capability/platform-capabilities.js.map +1 -0
  114. package/dist/capability/type-mapping.d.ts +70 -0
  115. package/dist/capability/type-mapping.js +107 -0
  116. package/dist/capability/type-mapping.js.map +1 -0
  117. package/dist/capability/validation.d.ts +46 -0
  118. package/dist/capability/validation.js +54 -0
  119. package/dist/capability/validation.js.map +1 -0
  120. package/dist/connectors/declared-connector.d.ts +48 -0
  121. package/dist/connectors/declared-connector.js +333 -0
  122. package/dist/connectors/declared-connector.js.map +1 -0
  123. package/dist/connectors/engine-registry.d.ts +50 -0
  124. package/dist/connectors/engine-registry.js +135 -0
  125. package/dist/connectors/engine-registry.js.map +1 -0
  126. package/dist/connectors/index.d.ts +14 -0
  127. package/dist/connectors/index.js +14 -0
  128. package/dist/connectors/index.js.map +1 -0
  129. package/dist/connectors/module-loader.d.ts +70 -0
  130. package/dist/connectors/module-loader.js +143 -0
  131. package/dist/connectors/module-loader.js.map +1 -0
  132. package/dist/connectors/types.d.ts +174 -0
  133. package/dist/connectors/types.js +23 -0
  134. package/dist/connectors/types.js.map +1 -0
  135. package/dist/context.d.ts +27 -0
  136. package/dist/context.js +38 -0
  137. package/dist/context.js.map +1 -0
  138. package/dist/data/DataCapabilityProvider.d.ts +39 -0
  139. package/dist/data/DataCapabilityProvider.js +58 -0
  140. package/dist/data/DataCapabilityProvider.js.map +1 -0
  141. package/dist/data/index.d.ts +17 -0
  142. package/dist/data/index.js +18 -0
  143. package/dist/data/index.js.map +1 -0
  144. package/dist/data/manager.d.ts +40 -0
  145. package/dist/data/manager.js +442 -0
  146. package/dist/data/manager.js.map +1 -0
  147. package/dist/data/types.d.ts +218 -0
  148. package/dist/data/types.js +2 -0
  149. package/dist/data/types.js.map +1 -0
  150. package/dist/entity/aggregate.d.ts +8 -0
  151. package/dist/entity/aggregate.js +24 -0
  152. package/dist/entity/aggregate.js.map +1 -0
  153. package/dist/entity/apply-query.d.ts +58 -0
  154. package/dist/entity/apply-query.js +264 -0
  155. package/dist/entity/apply-query.js.map +1 -0
  156. package/dist/entity/behavior.d.ts +94 -0
  157. package/dist/entity/behavior.js +78 -0
  158. package/dist/entity/behavior.js.map +1 -0
  159. package/dist/entity/connector.d.ts +141 -0
  160. package/dist/entity/connector.js +89 -0
  161. package/dist/entity/connector.js.map +1 -0
  162. package/dist/entity/connectors/index.d.ts +12 -0
  163. package/dist/entity/connectors/index.js +11 -0
  164. package/dist/entity/connectors/index.js.map +1 -0
  165. package/dist/entity/connectors/static.d.ts +51 -0
  166. package/dist/entity/connectors/static.js +245 -0
  167. package/dist/entity/connectors/static.js.map +1 -0
  168. package/dist/entity/entity-datasource.d.ts +50 -0
  169. package/dist/entity/entity-datasource.js +33 -0
  170. package/dist/entity/entity-datasource.js.map +1 -0
  171. package/dist/entity/facade.d.ts +70 -0
  172. package/dist/entity/facade.js +70 -0
  173. package/dist/entity/facade.js.map +1 -0
  174. package/dist/entity/http-connector.d.ts +123 -0
  175. package/dist/entity/http-connector.js +295 -0
  176. package/dist/entity/http-connector.js.map +1 -0
  177. package/dist/entity/index.d.ts +38 -0
  178. package/dist/entity/index.js +31 -0
  179. package/dist/entity/index.js.map +1 -0
  180. package/dist/entity/postgres-connector.d.ts +64 -0
  181. package/dist/entity/postgres-connector.js +239 -0
  182. package/dist/entity/postgres-connector.js.map +1 -0
  183. package/dist/entity/registry.d.ts +59 -0
  184. package/dist/entity/registry.js +90 -0
  185. package/dist/entity/registry.js.map +1 -0
  186. package/dist/entity/store.d.ts +66 -0
  187. package/dist/entity/store.js +349 -0
  188. package/dist/entity/store.js.map +1 -0
  189. package/dist/entity/types.d.ts +180 -0
  190. package/dist/entity/types.js +10 -0
  191. package/dist/entity/types.js.map +1 -0
  192. package/dist/execution-context.d.ts +88 -0
  193. package/dist/execution-context.js +146 -0
  194. package/dist/execution-context.js.map +1 -0
  195. package/dist/executor.d.ts +27 -0
  196. package/dist/executor.js +33 -0
  197. package/dist/executor.js.map +1 -0
  198. package/dist/forms/form-entity-bridge.d.ts +94 -0
  199. package/dist/forms/form-entity-bridge.js +96 -0
  200. package/dist/forms/form-entity-bridge.js.map +1 -0
  201. package/dist/forms/form-write-target.d.ts +34 -0
  202. package/dist/forms/form-write-target.js +81 -0
  203. package/dist/forms/form-write-target.js.map +1 -0
  204. package/dist/forms/index.d.ts +22 -0
  205. package/dist/forms/index.js +25 -0
  206. package/dist/forms/index.js.map +1 -0
  207. package/dist/forms/named-control-values.d.ts +27 -0
  208. package/dist/forms/named-control-values.js +42 -0
  209. package/dist/forms/named-control-values.js.map +1 -0
  210. package/dist/forms/processor.d.ts +55 -0
  211. package/dist/forms/processor.js +154 -0
  212. package/dist/forms/processor.js.map +1 -0
  213. package/dist/forms/types.d.ts +174 -0
  214. package/dist/forms/types.js +33 -0
  215. package/dist/forms/types.js.map +1 -0
  216. package/dist/forms/validator.d.ts +61 -0
  217. package/dist/forms/validator.js +218 -0
  218. package/dist/forms/validator.js.map +1 -0
  219. package/dist/graph/index.d.ts +10 -0
  220. package/dist/graph/index.js +9 -0
  221. package/dist/graph/index.js.map +1 -0
  222. package/dist/graph/resolver.d.ts +66 -0
  223. package/dist/graph/resolver.js +243 -0
  224. package/dist/graph/resolver.js.map +1 -0
  225. package/dist/graph/types.d.ts +125 -0
  226. package/dist/graph/types.js +9 -0
  227. package/dist/graph/types.js.map +1 -0
  228. package/dist/hooks/useInstalledAtoms.d.ts +96 -0
  229. package/dist/hooks/useInstalledAtoms.js +92 -0
  230. package/dist/hooks/useInstalledAtoms.js.map +1 -0
  231. package/dist/i18n/index.d.ts +15 -0
  232. package/dist/i18n/index.js +14 -0
  233. package/dist/i18n/index.js.map +1 -0
  234. package/dist/i18n/translator.d.ts +76 -0
  235. package/dist/i18n/translator.js +357 -0
  236. package/dist/i18n/translator.js.map +1 -0
  237. package/dist/i18n/types.d.ts +93 -0
  238. package/dist/i18n/types.js +9 -0
  239. package/dist/i18n/types.js.map +1 -0
  240. package/dist/index.d.ts +64 -0
  241. package/dist/index.js +95 -0
  242. package/dist/index.js.map +1 -0
  243. package/dist/kernel.d.ts +47 -0
  244. package/dist/kernel.js +258 -0
  245. package/dist/kernel.js.map +1 -0
  246. package/dist/perf/budget.d.ts +92 -0
  247. package/dist/perf/budget.js +122 -0
  248. package/dist/perf/budget.js.map +1 -0
  249. package/dist/perf/index.d.ts +16 -0
  250. package/dist/perf/index.js +13 -0
  251. package/dist/perf/index.js.map +1 -0
  252. package/dist/perf/render-timer.d.ts +90 -0
  253. package/dist/perf/render-timer.js +136 -0
  254. package/dist/perf/render-timer.js.map +1 -0
  255. package/dist/perf/reporter.d.ts +126 -0
  256. package/dist/perf/reporter.js +241 -0
  257. package/dist/perf/reporter.js.map +1 -0
  258. package/dist/perf/web-vitals.d.ts +111 -0
  259. package/dist/perf/web-vitals.js +268 -0
  260. package/dist/perf/web-vitals.js.map +1 -0
  261. package/dist/registry.d.ts +63 -0
  262. package/dist/registry.js +126 -0
  263. package/dist/registry.js.map +1 -0
  264. package/dist/render/BehaviorSurfaceProvider.d.ts +65 -0
  265. package/dist/render/BehaviorSurfaceProvider.js +185 -0
  266. package/dist/render/BehaviorSurfaceProvider.js.map +1 -0
  267. package/dist/render/BlockErrorBoundary.d.ts +26 -0
  268. package/dist/render/BlockErrorBoundary.js +41 -0
  269. package/dist/render/BlockErrorBoundary.js.map +1 -0
  270. package/dist/render/DataBoundSurfaceRenderer.d.ts +78 -0
  271. package/dist/render/DataBoundSurfaceRenderer.js +998 -0
  272. package/dist/render/DataBoundSurfaceRenderer.js.map +1 -0
  273. package/dist/render/DynamicBlockWrapper.d.ts +23 -0
  274. package/dist/render/DynamicBlockWrapper.js +117 -0
  275. package/dist/render/DynamicBlockWrapper.js.map +1 -0
  276. package/dist/render/appearance-resolver.d.ts +50 -0
  277. package/dist/render/appearance-resolver.js +78 -0
  278. package/dist/render/appearance-resolver.js.map +1 -0
  279. package/dist/render/capability-gate.d.ts +69 -0
  280. package/dist/render/capability-gate.js +94 -0
  281. package/dist/render/capability-gate.js.map +1 -0
  282. package/dist/render/conditional-states-css.d.ts +41 -0
  283. package/dist/render/conditional-states-css.js +82 -0
  284. package/dist/render/conditional-states-css.js.map +1 -0
  285. package/dist/render/connections-context.d.ts +31 -0
  286. package/dist/render/connections-context.js +34 -0
  287. package/dist/render/connections-context.js.map +1 -0
  288. package/dist/render/dark-theme-css.d.ts +36 -0
  289. package/dist/render/dark-theme-css.js +67 -0
  290. package/dist/render/dark-theme-css.js.map +1 -0
  291. package/dist/render/data-binding-types.d.ts +191 -0
  292. package/dist/render/data-binding-types.js +11 -0
  293. package/dist/render/data-binding-types.js.map +1 -0
  294. package/dist/render/data-cache.d.ts +30 -0
  295. package/dist/render/data-cache.js +37 -0
  296. package/dist/render/data-cache.js.map +1 -0
  297. package/dist/render/derive-dark-theme.d.ts +17 -0
  298. package/dist/render/derive-dark-theme.js +18 -0
  299. package/dist/render/derive-dark-theme.js.map +1 -0
  300. package/dist/render/dynamic-artifact-context.d.ts +77 -0
  301. package/dist/render/dynamic-artifact-context.js +89 -0
  302. package/dist/render/dynamic-artifact-context.js.map +1 -0
  303. package/dist/render/dynamic-block-loader.d.ts +80 -0
  304. package/dist/render/dynamic-block-loader.js +197 -0
  305. package/dist/render/dynamic-block-loader.js.map +1 -0
  306. package/dist/render/endpoint.d.ts +18 -0
  307. package/dist/render/endpoint.js +109 -0
  308. package/dist/render/endpoint.js.map +1 -0
  309. package/dist/render/entity-facade-context.d.ts +34 -0
  310. package/dist/render/entity-facade-context.js +37 -0
  311. package/dist/render/entity-facade-context.js.map +1 -0
  312. package/dist/render/group-states-css.d.ts +41 -0
  313. package/dist/render/group-states-css.js +73 -0
  314. package/dist/render/group-states-css.js.map +1 -0
  315. package/dist/render/hooks/useSurfaceEvents.d.ts +8 -0
  316. package/dist/render/hooks/useSurfaceEvents.js +9 -0
  317. package/dist/render/hooks/useSurfaceEvents.js.map +1 -0
  318. package/dist/render/hooks/useSurfaceId.d.ts +8 -0
  319. package/dist/render/hooks/useSurfaceId.js +9 -0
  320. package/dist/render/hooks/useSurfaceId.js.map +1 -0
  321. package/dist/render/index.d.ts +48 -0
  322. package/dist/render/index.js +61 -0
  323. package/dist/render/index.js.map +1 -0
  324. package/dist/render/interaction-rule-engine.d.ts +12 -0
  325. package/dist/render/interaction-rule-engine.js +47 -0
  326. package/dist/render/interaction-rule-engine.js.map +1 -0
  327. package/dist/render/keyframes-css.d.ts +31 -0
  328. package/dist/render/keyframes-css.js +44 -0
  329. package/dist/render/keyframes-css.js.map +1 -0
  330. package/dist/render/query-state.d.ts +3 -0
  331. package/dist/render/query-state.js +70 -0
  332. package/dist/render/query-state.js.map +1 -0
  333. package/dist/render/renderer.d.ts +44 -0
  334. package/dist/render/renderer.js +937 -0
  335. package/dist/render/renderer.js.map +1 -0
  336. package/dist/render/resolve-expressions.d.ts +37 -0
  337. package/dist/render/resolve-expressions.js +309 -0
  338. package/dist/render/resolve-expressions.js.map +1 -0
  339. package/dist/render/responsive-style-css.d.ts +42 -0
  340. package/dist/render/responsive-style-css.js +123 -0
  341. package/dist/render/responsive-style-css.js.map +1 -0
  342. package/dist/render/responsive.d.ts +49 -0
  343. package/dist/render/responsive.js +99 -0
  344. package/dist/render/responsive.js.map +1 -0
  345. package/dist/render/scoped-css.d.ts +71 -0
  346. package/dist/render/scoped-css.js +102 -0
  347. package/dist/render/scoped-css.js.map +1 -0
  348. package/dist/render/shell-selection.d.ts +69 -0
  349. package/dist/render/shell-selection.js +117 -0
  350. package/dist/render/shell-selection.js.map +1 -0
  351. package/dist/render/states-css.d.ts +32 -0
  352. package/dist/render/states-css.js +63 -0
  353. package/dist/render/states-css.js.map +1 -0
  354. package/dist/render/surface-data-context.d.ts +18 -0
  355. package/dist/render/surface-data-context.js +21 -0
  356. package/dist/render/surface-data-context.js.map +1 -0
  357. package/dist/render/surface-event-bus.d.ts +19 -0
  358. package/dist/render/surface-event-bus.js +68 -0
  359. package/dist/render/surface-event-bus.js.map +1 -0
  360. package/dist/render/surface-event-context.d.ts +11 -0
  361. package/dist/render/surface-event-context.js +12 -0
  362. package/dist/render/surface-event-context.js.map +1 -0
  363. package/dist/render/surface-id-context.d.ts +8 -0
  364. package/dist/render/surface-id-context.js +9 -0
  365. package/dist/render/surface-id-context.js.map +1 -0
  366. package/dist/render/theme-utils.d.ts +14 -0
  367. package/dist/render/theme-utils.js +15 -0
  368. package/dist/render/theme-utils.js.map +1 -0
  369. package/dist/render/types.d.ts +282 -0
  370. package/dist/render/types.js +9 -0
  371. package/dist/render/types.js.map +1 -0
  372. package/dist/render/visibility-css.d.ts +42 -0
  373. package/dist/render/visibility-css.js +119 -0
  374. package/dist/render/visibility-css.js.map +1 -0
  375. package/dist/render/width-scope.d.ts +34 -0
  376. package/dist/render/width-scope.js +44 -0
  377. package/dist/render/width-scope.js.map +1 -0
  378. package/dist/render/write-only-sources.d.ts +33 -0
  379. package/dist/render/write-only-sources.js +99 -0
  380. package/dist/render/write-only-sources.js.map +1 -0
  381. package/dist/routing/index.d.ts +14 -0
  382. package/dist/routing/index.js +15 -0
  383. package/dist/routing/index.js.map +1 -0
  384. package/dist/routing/router.d.ts +42 -0
  385. package/dist/routing/router.js +218 -0
  386. package/dist/routing/router.js.map +1 -0
  387. package/dist/routing/types.d.ts +124 -0
  388. package/dist/routing/types.js +9 -0
  389. package/dist/routing/types.js.map +1 -0
  390. package/dist/seo/generator.d.ts +39 -0
  391. package/dist/seo/generator.js +236 -0
  392. package/dist/seo/generator.js.map +1 -0
  393. package/dist/seo/index.d.ts +14 -0
  394. package/dist/seo/index.js +15 -0
  395. package/dist/seo/index.js.map +1 -0
  396. package/dist/seo/types.d.ts +181 -0
  397. package/dist/seo/types.js +9 -0
  398. package/dist/seo/types.js.map +1 -0
  399. package/dist/state/index.d.ts +15 -0
  400. package/dist/state/index.js +16 -0
  401. package/dist/state/index.js.map +1 -0
  402. package/dist/state/manager.d.ts +33 -0
  403. package/dist/state/manager.js +81 -0
  404. package/dist/state/manager.js.map +1 -0
  405. package/dist/state/store.d.ts +40 -0
  406. package/dist/state/store.js +145 -0
  407. package/dist/state/store.js.map +1 -0
  408. package/dist/state/types.d.ts +107 -0
  409. package/dist/state/types.js +9 -0
  410. package/dist/state/types.js.map +1 -0
  411. package/dist/surface/expression.d.ts +65 -0
  412. package/dist/surface/expression.js +179 -0
  413. package/dist/surface/expression.js.map +1 -0
  414. package/dist/surface/index.d.ts +32 -0
  415. package/dist/surface/index.js +25 -0
  416. package/dist/surface/index.js.map +1 -0
  417. package/dist/surface/interpreter.d.ts +96 -0
  418. package/dist/surface/interpreter.js +231 -0
  419. package/dist/surface/interpreter.js.map +1 -0
  420. package/dist/surface/layout.d.ts +54 -0
  421. package/dist/surface/layout.js +288 -0
  422. package/dist/surface/layout.js.map +1 -0
  423. package/dist/surface/output.d.ts +90 -0
  424. package/dist/surface/output.js +104 -0
  425. package/dist/surface/output.js.map +1 -0
  426. package/dist/surface/primitives.d.ts +180 -0
  427. package/dist/surface/primitives.js +339 -0
  428. package/dist/surface/primitives.js.map +1 -0
  429. package/dist/surface/renderer.d.ts +96 -0
  430. package/dist/surface/renderer.js +190 -0
  431. package/dist/surface/renderer.js.map +1 -0
  432. package/dist/surface/schemas.d.ts +181 -0
  433. package/dist/surface/schemas.js +142 -0
  434. package/dist/surface/schemas.js.map +1 -0
  435. package/dist/surface/transforms.d.ts +144 -0
  436. package/dist/surface/transforms.js +120 -0
  437. package/dist/surface/transforms.js.map +1 -0
  438. package/dist/surface/types.d.ts +160 -0
  439. package/dist/surface/types.js +51 -0
  440. package/dist/surface/types.js.map +1 -0
  441. package/dist/surface/validation.d.ts +123 -0
  442. package/dist/surface/validation.js +147 -0
  443. package/dist/surface/validation.js.map +1 -0
  444. package/dist/validator.d.ts +55 -0
  445. package/dist/validator.js +100 -0
  446. package/dist/validator.js.map +1 -0
  447. package/package.json +106 -3
@@ -0,0 +1,99 @@
1
+ /**
2
+ * WRITE-ONLY SOURCES — a form's target that nothing on the page reads.
3
+ *
4
+ * A data source a form writes to (`platform/entities` `config.formBindings[].sourceId`)
5
+ * was also fetched as a list on mount and again after every submit (the
6
+ * bridge's `refreshAll`). For an intake-only model — anonymous visitors may
7
+ * create, never list — that is a refused request on every visit and every
8
+ * submit (`GET /_host/records/<model>` → 403
9
+ * `RECORDS_NOT_PUBLIC`, `__errors.records` set, no block bound to it).
10
+ *
11
+ * A source is write-only when:
12
+ * - at least one form binding targets it, and every binding that does writes
13
+ * with POST (a PATCH/PUT needs the loaded record to know what to update), and
14
+ * - its id is referenced NOWHERE else: no block (props, expressions, actions,
15
+ * repeat), no behavior, no other source, no other capability config.
16
+ *
17
+ * The reference check is a whole-word search of every string, which errs on
18
+ * the side of fetching: a stray word equal to the id keeps today's behaviour.
19
+ * A write-only source stays declared and registered — it is still the write
20
+ * target — it is just never asked for its rows.
21
+ *
22
+ * @module @pwfabric/runtime/render/write-only-sources
23
+ */
24
+ import { isCapability } from '../capability/type-mapping.js';
25
+ function collectStrings(value, out, seen) {
26
+ if (typeof value === 'string') {
27
+ out.push(value);
28
+ return;
29
+ }
30
+ if (value === null || typeof value !== 'object')
31
+ return;
32
+ if (seen.has(value))
33
+ return;
34
+ seen.add(value);
35
+ if (Array.isArray(value)) {
36
+ for (const v of value)
37
+ collectStrings(v, out, seen);
38
+ return;
39
+ }
40
+ for (const [k, v] of Object.entries(value)) {
41
+ // A key can be a reference too (`{ records: … }` maps).
42
+ out.push(k);
43
+ collectStrings(v, out, seen);
44
+ }
45
+ }
46
+ function escapeRegExp(s) {
47
+ return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
48
+ }
49
+ /** The ids of the declared sources that are only ever written to. */
50
+ export function writeOnlySourceIds(input) {
51
+ const capabilities = (input.capabilities ?? []);
52
+ const entities = capabilities.find((c) => isCapability(c, 'platform/entities'));
53
+ const bindings = entities?.config?.formBindings;
54
+ if (!Array.isArray(bindings) || bindings.length === 0)
55
+ return new Set();
56
+ // Candidates: targeted by a form, and only ever with POST.
57
+ const postOnly = new Map();
58
+ for (const raw of bindings) {
59
+ if (typeof raw?.sourceId !== 'string')
60
+ continue;
61
+ const isPost = raw.method === undefined || raw.method === 'POST';
62
+ postOnly.set(raw.sourceId, (postOnly.get(raw.sourceId) ?? true) && isPost);
63
+ }
64
+ const declared = new Set(input.dataSources.map((s) => s.id));
65
+ const candidates = [...postOnly].filter(([id, post]) => post && declared.has(id)).map(([id]) => id);
66
+ if (candidates.length === 0)
67
+ return new Set();
68
+ // Everything that could read a source, minus the declarations themselves:
69
+ // the form bindings (they ARE the write) and the source list (each source is
70
+ // checked against the OTHER sources below).
71
+ const strings = [];
72
+ const seen = new Set();
73
+ collectStrings(input.blocks, strings, seen);
74
+ collectStrings(input.behaviors ?? [], strings, seen);
75
+ for (const c of capabilities) {
76
+ const config = c.config;
77
+ if (config === null || typeof config !== 'object')
78
+ continue;
79
+ const rest = { ...config };
80
+ delete rest['dataSources'];
81
+ delete rest['behaviors']; // collected above (the same list, seeded from persistence)
82
+ if (c === entities)
83
+ delete rest['formBindings'];
84
+ collectStrings(rest, strings, seen);
85
+ }
86
+ const result = new Set();
87
+ for (const id of candidates) {
88
+ const word = new RegExp(`(^|[^A-Za-z0-9_$])${escapeRegExp(id)}([^A-Za-z0-9_$]|$)`);
89
+ const others = [];
90
+ for (const s of input.dataSources)
91
+ if (s.id !== id)
92
+ collectStrings(s, others, new Set());
93
+ const read = strings.some((s) => word.test(s)) || others.some((s) => word.test(s));
94
+ if (!read)
95
+ result.add(id);
96
+ }
97
+ return result;
98
+ }
99
+ //# sourceMappingURL=write-only-sources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write-only-sources.js","sourceRoot":"","sources":["../../src/render/write-only-sources.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * WRITE-ONLY SOURCES — a form's target that nothing on the page reads.\n *\n * A data source a form writes to (`platform/entities` `config.formBindings[].sourceId`)\n * was also fetched as a list on mount and again after every submit (the\n * bridge's `refreshAll`). For an intake-only model — anonymous visitors may\n * create, never list — that is a refused request on every visit and every\n * submit (`GET /_host/records/<model>` → 403\n * `RECORDS_NOT_PUBLIC`, `__errors.records` set, no block bound to it).\n *\n * A source is write-only when:\n * - at least one form binding targets it, and every binding that does writes\n * with POST (a PATCH/PUT needs the loaded record to know what to update), and\n * - its id is referenced NOWHERE else: no block (props, expressions, actions,\n * repeat), no behavior, no other source, no other capability config.\n *\n * The reference check is a whole-word search of every string, which errs on\n * the side of fetching: a stray word equal to the id keeps today's behaviour.\n * A write-only source stays declared and registered — it is still the write\n * target — it is just never asked for its rows.\n *\n * @module @pwfabric/runtime/render/write-only-sources\n */\n\nimport { isCapability } from '../capability/type-mapping.js'\n\ninterface FormBindingLike {\n readonly sourceId?: unknown\n readonly method?: unknown\n}\n\ninterface CapabilityLike {\n readonly capability?: string\n readonly config?: unknown\n}\n\nexport interface WriteOnlySourceInput {\n readonly blocks: readonly unknown[]\n readonly dataSources: readonly { readonly id: string }[]\n readonly capabilities?: readonly unknown[] | undefined\n readonly behaviors?: readonly unknown[] | undefined\n}\n\nfunction collectStrings(value: unknown, out: string[], seen: Set<object>): void {\n if (typeof value === 'string') {\n out.push(value)\n return\n }\n if (value === null || typeof value !== 'object') return\n if (seen.has(value)) return\n seen.add(value)\n if (Array.isArray(value)) {\n for (const v of value) collectStrings(v, out, seen)\n return\n }\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n // A key can be a reference too (`{ records: … }` maps).\n out.push(k)\n collectStrings(v, out, seen)\n }\n}\n\nfunction escapeRegExp(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\n/** The ids of the declared sources that are only ever written to. */\nexport function writeOnlySourceIds(input: WriteOnlySourceInput): ReadonlySet<string> {\n const capabilities = (input.capabilities ?? []) as readonly CapabilityLike[]\n const entities = capabilities.find((c) => isCapability(c, 'platform/entities'))\n const bindings = (entities?.config as { formBindings?: unknown } | undefined)?.formBindings\n if (!Array.isArray(bindings) || bindings.length === 0) return new Set()\n\n // Candidates: targeted by a form, and only ever with POST.\n const postOnly = new Map<string, boolean>()\n for (const raw of bindings as readonly FormBindingLike[]) {\n if (typeof raw?.sourceId !== 'string') continue\n const isPost = raw.method === undefined || raw.method === 'POST'\n postOnly.set(raw.sourceId, (postOnly.get(raw.sourceId) ?? true) && isPost)\n }\n const declared = new Set(input.dataSources.map((s) => s.id))\n const candidates = [...postOnly].filter(([id, post]) => post && declared.has(id)).map(([id]) => id)\n if (candidates.length === 0) return new Set()\n\n // Everything that could read a source, minus the declarations themselves:\n // the form bindings (they ARE the write) and the source list (each source is\n // checked against the OTHER sources below).\n const strings: string[] = []\n const seen = new Set<object>()\n collectStrings(input.blocks, strings, seen)\n collectStrings(input.behaviors ?? [], strings, seen)\n for (const c of capabilities) {\n const config = c.config\n if (config === null || typeof config !== 'object') continue\n const rest: Record<string, unknown> = { ...(config as Record<string, unknown>) }\n delete rest['dataSources']\n delete rest['behaviors'] // collected above (the same list, seeded from persistence)\n if (c === entities) delete rest['formBindings']\n collectStrings(rest, strings, seen)\n }\n\n const result = new Set<string>()\n for (const id of candidates) {\n const word = new RegExp(`(^|[^A-Za-z0-9_$])${escapeRegExp(id)}([^A-Za-z0-9_$]|$)`)\n const others: string[] = []\n for (const s of input.dataSources) if (s.id !== id) collectStrings(s, others, new Set())\n const read = strings.some((s) => word.test(s)) || others.some((s) => word.test(s))\n if (!read) result.add(id)\n }\n return result\n}\n"]}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Routing Capability Module
3
+ *
4
+ * Route matching, navigation, and URL parameter resolution
5
+ *
6
+ * Exports:
7
+ * - Types: RouteDefinition, RouteMatch, NavigationTarget, RoutingCapability, etc.
8
+ * - Implementations: DefaultRoutingCapability
9
+ * - Factory functions: createRoutingCapability
10
+ *
11
+ * @module @pwfabric/runtime/routing
12
+ */
13
+ export type { RouteDefinition, RouteGuard, RouteGuardContext, RouteMatchResult, RouteMatch, NavigationTarget, NavigationResult, NavigationFailureReason, NavigationListener, RoutingCapability, } from './types.js';
14
+ export { DefaultRoutingCapability, createRoutingCapability } from './router.js';
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Routing Capability Module
3
+ *
4
+ * Route matching, navigation, and URL parameter resolution
5
+ *
6
+ * Exports:
7
+ * - Types: RouteDefinition, RouteMatch, NavigationTarget, RoutingCapability, etc.
8
+ * - Implementations: DefaultRoutingCapability
9
+ * - Factory functions: createRoutingCapability
10
+ *
11
+ * @module @pwfabric/runtime/routing
12
+ */
13
+ // Implementations
14
+ export { DefaultRoutingCapability, createRoutingCapability } from './router.js';
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/routing/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAgBH,kBAAkB;AAClB,OAAO,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAA","sourcesContent":["/**\n * Routing Capability Module\n *\n * Route matching, navigation, and URL parameter resolution\n *\n * Exports:\n * - Types: RouteDefinition, RouteMatch, NavigationTarget, RoutingCapability, etc.\n * - Implementations: DefaultRoutingCapability\n * - Factory functions: createRoutingCapability\n *\n * @module @pwfabric/runtime/routing\n */\n\n// Types\nexport type {\n RouteDefinition,\n RouteGuard,\n RouteGuardContext,\n RouteMatchResult,\n RouteMatch,\n NavigationTarget,\n NavigationResult,\n NavigationFailureReason,\n NavigationListener,\n RoutingCapability,\n} from './types.js'\n\n// Implementations\nexport { DefaultRoutingCapability, createRoutingCapability } from './router.js'\n"]}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Routing Capability Implementation
3
+ *
4
+ * Route matching, navigation, and parameter resolution
5
+ *
6
+ * @module @pwfabric/runtime/routing/router
7
+ */
8
+ import type { RoutingCapability, RouteDefinition, RouteMatch, RouteMatchResult, NavigationTarget, NavigationResult, NavigationListener } from './types.js';
9
+ /**
10
+ * Default routing capability implementation
11
+ */
12
+ export declare class DefaultRoutingCapability implements RoutingCapability {
13
+ private readonly routes;
14
+ private readonly listeners;
15
+ private readonly navigationHistory;
16
+ private currentRoute;
17
+ private readonly maxHistorySize;
18
+ constructor(options?: {
19
+ maxHistorySize?: number;
20
+ });
21
+ addRoute(route: RouteDefinition): void;
22
+ removeRoute(routeId: string): boolean;
23
+ matchRoute(path: string): RouteMatchResult;
24
+ navigate(target: NavigationTarget): Promise<NavigationResult>;
25
+ resolveParams(pattern: string, params: Record<string, string>): string;
26
+ getCurrentRoute(): RouteMatch | undefined;
27
+ getHistory(): readonly RouteMatch[];
28
+ onNavigate(listener: NavigationListener): () => void;
29
+ getRouteIds(): readonly string[];
30
+ clear(): void;
31
+ private compileRoute;
32
+ private tryMatch;
33
+ private parsePath;
34
+ private buildPath;
35
+ private notifyListeners;
36
+ }
37
+ /**
38
+ * Create a routing capability instance
39
+ */
40
+ export declare function createRoutingCapability(options?: {
41
+ maxHistorySize?: number;
42
+ }): RoutingCapability;
@@ -0,0 +1,218 @@
1
+ /**
2
+ * Routing Capability Implementation
3
+ *
4
+ * Route matching, navigation, and parameter resolution
5
+ *
6
+ * @module @pwfabric/runtime/routing/router
7
+ */
8
+ // ============================================================
9
+ // DEFAULT ROUTING CAPABILITY
10
+ // ============================================================
11
+ /**
12
+ * Default routing capability implementation
13
+ */
14
+ export class DefaultRoutingCapability {
15
+ routes = new Map();
16
+ listeners = new Set();
17
+ navigationHistory = [];
18
+ currentRoute = undefined;
19
+ maxHistorySize;
20
+ constructor(options) {
21
+ this.maxHistorySize = options?.maxHistorySize ?? 50;
22
+ }
23
+ addRoute(route) {
24
+ if (this.routes.has(route.id)) {
25
+ throw new Error(`Route '${route.id}' is already registered`);
26
+ }
27
+ const compiled = this.compileRoute(route);
28
+ this.routes.set(route.id, compiled);
29
+ }
30
+ removeRoute(routeId) {
31
+ return this.routes.delete(routeId);
32
+ }
33
+ matchRoute(path) {
34
+ const { pathname, query, hash } = this.parsePath(path);
35
+ for (const compiled of this.routes.values()) {
36
+ const match = this.tryMatch(compiled, pathname, query, hash);
37
+ if (match) {
38
+ return { matched: true, match };
39
+ }
40
+ }
41
+ return { matched: false, reason: `No route matches path: ${path}` };
42
+ }
43
+ async navigate(target) {
44
+ const fullPath = this.buildPath(target);
45
+ const matchResult = this.matchRoute(fullPath);
46
+ if (!matchResult.matched) {
47
+ return { success: false, reason: 'no_match' };
48
+ }
49
+ const match = matchResult.match;
50
+ // Check if navigating to the same route
51
+ if (this.currentRoute &&
52
+ this.currentRoute.route.id === match.route.id &&
53
+ this.currentRoute.path === match.path) {
54
+ return { success: false, reason: 'same_route' };
55
+ }
56
+ // Execute guards
57
+ if (match.route.guards && match.route.guards.length > 0) {
58
+ for (const guard of match.route.guards) {
59
+ const canActivate = await guard.canActivate({
60
+ from: this.currentRoute,
61
+ to: match,
62
+ params: match.params,
63
+ });
64
+ if (!canActivate) {
65
+ return { success: false, reason: 'guard_rejected' };
66
+ }
67
+ }
68
+ }
69
+ // Update current route
70
+ const previousRoute = this.currentRoute;
71
+ this.currentRoute = match;
72
+ // Add to history
73
+ if (!target.replace) {
74
+ this.navigationHistory.push(match);
75
+ while (this.navigationHistory.length > this.maxHistorySize) {
76
+ this.navigationHistory.shift();
77
+ }
78
+ }
79
+ else if (this.navigationHistory.length > 0) {
80
+ this.navigationHistory[this.navigationHistory.length - 1] = match;
81
+ }
82
+ else {
83
+ this.navigationHistory.push(match);
84
+ }
85
+ // Notify listeners
86
+ this.notifyListeners(match, previousRoute);
87
+ return { success: true, match };
88
+ }
89
+ resolveParams(pattern, params) {
90
+ let resolved = pattern;
91
+ for (const [key, value] of Object.entries(params)) {
92
+ resolved = resolved.replace(`:${key}`, encodeURIComponent(value));
93
+ }
94
+ return resolved;
95
+ }
96
+ getCurrentRoute() {
97
+ return this.currentRoute;
98
+ }
99
+ getHistory() {
100
+ return [...this.navigationHistory];
101
+ }
102
+ onNavigate(listener) {
103
+ this.listeners.add(listener);
104
+ return () => {
105
+ this.listeners.delete(listener);
106
+ };
107
+ }
108
+ getRouteIds() {
109
+ return Array.from(this.routes.keys());
110
+ }
111
+ clear() {
112
+ this.routes.clear();
113
+ this.listeners.clear();
114
+ this.navigationHistory.length = 0;
115
+ this.currentRoute = undefined;
116
+ }
117
+ // ============================================================
118
+ // PRIVATE METHODS
119
+ // ============================================================
120
+ compileRoute(route) {
121
+ const paramNames = [];
122
+ // Convert pattern to regex
123
+ // :param -> named capture group
124
+ // * -> wildcard capture
125
+ let regexStr = route.pattern
126
+ .replace(/\/:(\w+)/g, (_match, paramName) => {
127
+ paramNames.push(paramName);
128
+ return '/([^/]+)';
129
+ })
130
+ .replace(/\*$/, '(.*)');
131
+ // Ensure exact match (anchor start and end)
132
+ regexStr = `^${regexStr}$`;
133
+ return {
134
+ definition: route,
135
+ regex: new RegExp(regexStr),
136
+ paramNames,
137
+ };
138
+ }
139
+ tryMatch(compiled, pathname, query, hash) {
140
+ const match = pathname.match(compiled.regex);
141
+ if (!match)
142
+ return null;
143
+ const params = {};
144
+ for (let i = 0; i < compiled.paramNames.length; i++) {
145
+ const name = compiled.paramNames[i];
146
+ const value = match[i + 1];
147
+ if (name && value !== undefined) {
148
+ params[name] = decodeURIComponent(value);
149
+ }
150
+ }
151
+ return {
152
+ route: compiled.definition,
153
+ params,
154
+ query,
155
+ path: pathname,
156
+ hash,
157
+ };
158
+ }
159
+ parsePath(path) {
160
+ let pathname = path;
161
+ let hash = '';
162
+ const query = {};
163
+ // Extract hash
164
+ const hashIndex = pathname.indexOf('#');
165
+ if (hashIndex >= 0) {
166
+ hash = pathname.slice(hashIndex + 1);
167
+ pathname = pathname.slice(0, hashIndex);
168
+ }
169
+ // Extract query
170
+ const queryIndex = pathname.indexOf('?');
171
+ if (queryIndex >= 0) {
172
+ const queryString = pathname.slice(queryIndex + 1);
173
+ pathname = pathname.slice(0, queryIndex);
174
+ for (const pair of queryString.split('&')) {
175
+ const [key, value] = pair.split('=');
176
+ if (key) {
177
+ query[decodeURIComponent(key)] = value ? decodeURIComponent(value) : '';
178
+ }
179
+ }
180
+ }
181
+ // Normalize pathname
182
+ if (!pathname.startsWith('/')) {
183
+ pathname = '/' + pathname;
184
+ }
185
+ return { pathname, query, hash };
186
+ }
187
+ buildPath(target) {
188
+ let path = target.path;
189
+ if (target.query && Object.keys(target.query).length > 0) {
190
+ const queryParts = Object.entries(target.query).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
191
+ path += '?' + queryParts.join('&');
192
+ }
193
+ if (target.hash) {
194
+ path += '#' + target.hash;
195
+ }
196
+ return path;
197
+ }
198
+ notifyListeners(to, from) {
199
+ for (const listener of this.listeners) {
200
+ try {
201
+ listener(to, from);
202
+ }
203
+ catch {
204
+ // Swallow listener errors
205
+ }
206
+ }
207
+ }
208
+ }
209
+ // ============================================================
210
+ // FACTORY FUNCTION
211
+ // ============================================================
212
+ /**
213
+ * Create a routing capability instance
214
+ */
215
+ export function createRoutingCapability(options) {
216
+ return new DefaultRoutingCapability(options);
217
+ }
218
+ //# sourceMappingURL=router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/routing/router.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAsBH,+DAA+D;AAC/D,6BAA6B;AAC7B,+DAA+D;AAE/D;;GAEG;AACH,MAAM,OAAO,wBAAwB;IAClB,MAAM,GAAG,IAAI,GAAG,EAAyB,CAAA;IACzC,SAAS,GAAG,IAAI,GAAG,EAAsB,CAAA;IACzC,iBAAiB,GAAiB,EAAE,CAAA;IAC7C,YAAY,GAA2B,SAAS,CAAA;IACvC,cAAc,CAAQ;IAEvC,YAAY,OAAqC;QAC/C,IAAI,CAAC,cAAc,GAAG,OAAO,EAAE,cAAc,IAAI,EAAE,CAAA;IACrD,CAAC;IAED,QAAQ,CAAC,KAAsB;QAC7B,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,UAAU,KAAK,CAAC,EAAE,yBAAyB,CAAC,CAAA;QAC9D,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAA;QACzC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAA;IACrC,CAAC;IAED,WAAW,CAAC,OAAe;QACzB,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IACpC,CAAC;IAED,UAAU,CAAC,IAAY;QACrB,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;QAEtD,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;YAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,CAAA;YAC5D,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAA;YACjC,CAAC;QACH,CAAC;QAED,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,0BAA0B,IAAI,EAAE,EAAE,CAAA;IACrE,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,MAAwB;QACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;QACvC,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAA;QAE7C,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;YACzB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAA;QAC/C,CAAC;QAED,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAA;QAE/B,wCAAwC;QACxC,IACE,IAAI,CAAC,YAAY;YACjB,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,CAAC,KAAK,CAAC,EAAE;YAC7C,IAAI,CAAC,YAAY,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,EACrC,CAAC;YACD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,CAAA;QACjD,CAAC;QAED,iBAAiB;QACjB,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxD,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;gBACvC,MAAM,WAAW,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC;oBAC1C,IAAI,EAAE,IAAI,CAAC,YAAY;oBACvB,EAAE,EAAE,KAAK;oBACT,MAAM,EAAE,KAAK,CAAC,MAAM;iBACrB,CAAC,CAAA;gBACF,IAAI,CAAC,WAAW,EAAE,CAAC;oBACjB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAA;gBACrD,CAAC;YACH,CAAC;QACH,CAAC;QAED,uBAAuB;QACvB,MAAM,aAAa,GAAG,IAAI,CAAC,YAAY,CAAA;QACvC,IAAI,CAAC,YAAY,GAAG,KAAK,CAAA;QAEzB,iBAAiB;QACjB,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YAClC,OAAO,IAAI,CAAC,iBAAiB,CAAC,MAAM,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;gBAC3D,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,CAAA;YAChC,CAAC;QACH,CAAC;aAAM,IAAI,IAAI,CAAC,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7C,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,iBAAiB,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,KAAK,CAAA;QACnE,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACpC,CAAC;QAED,mBAAmB;QACnB,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,aAAa,CAAC,CAAA;QAE1C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAA;IACjC,CAAC;IAED,aAAa,CAAC,OAAe,EAAE,MAA8B;QAC3D,IAAI,QAAQ,GAAG,OAAO,CAAA;QACtB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAClD,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,GAAG,EAAE,EAAE,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAA;QACnE,CAAC;QACD,OAAO,QAAQ,CAAA;IACjB,CAAC;IAED,eAAe;QACb,OAAO,IAAI,CAAC,YAAY,CAAA;IAC1B,CAAC;IAED,UAAU;QACR,OAAO,CAAC,GAAG,IAAI,CAAC,iBAAiB,CAAC,CAAA;IACpC,CAAC;IAED,UAAU,CAAC,QAA4B;QACrC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QAC5B,OAAO,GAAG,EAAE;YACV,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;QACjC,CAAC,CAAA;IACH,CAAC;IAED,WAAW;QACT,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAA;IACvC,CAAC;IAED,KAAK;QACH,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAA;QACnB,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAA;QACtB,IAAI,CAAC,iBAAiB,CAAC,MAAM,GAAG,CAAC,CAAA;QACjC,IAAI,CAAC,YAAY,GAAG,SAAS,CAAA;IAC/B,CAAC;IAED,+DAA+D;IAC/D,kBAAkB;IAClB,+DAA+D;IAEvD,YAAY,CAAC,KAAsB;QACzC,MAAM,UAAU,GAAa,EAAE,CAAA;QAE/B,2BAA2B;QAC3B,gCAAgC;QAChC,wBAAwB;QACxB,IAAI,QAAQ,GAAG,KAAK,CAAC,OAAO;aACzB,OAAO,CAAC,WAAW,EAAE,CAAC,MAAM,EAAE,SAAiB,EAAE,EAAE;YAClD,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;YAC1B,OAAO,UAAU,CAAA;QACnB,CAAC,CAAC;aACD,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;QAEzB,4CAA4C;QAC5C,QAAQ,GAAG,IAAI,QAAQ,GAAG,CAAA;QAE1B,OAAO;YACL,UAAU,EAAE,KAAK;YACjB,KAAK,EAAE,IAAI,MAAM,CAAC,QAAQ,CAAC;YAC3B,UAAU;SACX,CAAA;IACH,CAAC;IAEO,QAAQ,CACd,QAAuB,EACvB,QAAgB,EAChB,KAA6B,EAC7B,IAAY;QAEZ,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;QAC5C,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAA;QAEvB,MAAM,MAAM,GAA2B,EAAE,CAAA;QACzC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACpD,MAAM,IAAI,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAA;YACnC,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;YAC1B,IAAI,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBAChC,MAAM,CAAC,IAAI,CAAC,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAA;YAC1C,CAAC;QACH,CAAC;QAED,OAAO;YACL,KAAK,EAAE,QAAQ,CAAC,UAAU;YAC1B,MAAM;YACN,KAAK;YACL,IAAI,EAAE,QAAQ;YACd,IAAI;SACL,CAAA;IACH,CAAC;IAEO,SAAS,CAAC,IAAY;QAK5B,IAAI,QAAQ,GAAG,IAAI,CAAA;QACnB,IAAI,IAAI,GAAG,EAAE,CAAA;QACb,MAAM,KAAK,GAA2B,EAAE,CAAA;QAExC,eAAe;QACf,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QACvC,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;YACnB,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAA;YACpC,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAA;QACzC,CAAC;QAED,gBAAgB;QAChB,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QACxC,IAAI,UAAU,IAAI,CAAC,EAAE,CAAC;YACpB,MAAM,WAAW,GAAG,QAAQ,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,CAAA;YAClD,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAA;YAExC,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC1C,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;gBACpC,IAAI,GAAG,EAAE,CAAC;oBACR,KAAK,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;gBACzE,CAAC;YACH,CAAC;QACH,CAAC;QAED,qBAAqB;QACrB,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC9B,QAAQ,GAAG,GAAG,GAAG,QAAQ,CAAA;QAC3B,CAAC;QAED,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,CAAA;IAClC,CAAC;IAEO,SAAS,CAAC,MAAwB;QACxC,IAAI,IAAI,GAAG,MAAM,CAAC,IAAI,CAAA;QAEtB,IAAI,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzD,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CACjD,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,kBAAkB,CAAC,GAAG,CAAC,IAAI,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAC5E,CAAA;YACD,IAAI,IAAI,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACpC,CAAC;QAED,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YAChB,IAAI,IAAI,GAAG,GAAG,MAAM,CAAC,IAAI,CAAA;QAC3B,CAAC;QAED,OAAO,IAAI,CAAA;IACb,CAAC;IAEO,eAAe,CAAC,EAAc,EAAE,IAA4B;QAClE,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACtC,IAAI,CAAC;gBACH,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,CAAA;YACpB,CAAC;YAAC,MAAM,CAAC;gBACP,0BAA0B;YAC5B,CAAC;QACH,CAAC;IACH,CAAC;CACF;AAED,+DAA+D;AAC/D,mBAAmB;AACnB,+DAA+D;AAE/D;;GAEG;AACH,MAAM,UAAU,uBAAuB,CAAC,OAAqC;IAC3E,OAAO,IAAI,wBAAwB,CAAC,OAAO,CAAC,CAAA;AAC9C,CAAC","sourcesContent":["/**\n * Routing Capability Implementation\n *\n * Route matching, navigation, and parameter resolution\n *\n * @module @pwfabric/runtime/routing/router\n */\n\nimport type {\n RoutingCapability,\n RouteDefinition,\n RouteMatch,\n RouteMatchResult,\n NavigationTarget,\n NavigationResult,\n NavigationListener,\n} from './types.js'\n\n// ============================================================\n// COMPILED ROUTE\n// ============================================================\n\ninterface CompiledRoute {\n definition: RouteDefinition\n regex: RegExp\n paramNames: string[]\n}\n\n// ============================================================\n// DEFAULT ROUTING CAPABILITY\n// ============================================================\n\n/**\n * Default routing capability implementation\n */\nexport class DefaultRoutingCapability implements RoutingCapability {\n private readonly routes = new Map<string, CompiledRoute>()\n private readonly listeners = new Set<NavigationListener>()\n private readonly navigationHistory: RouteMatch[] = []\n private currentRoute: RouteMatch | undefined = undefined\n private readonly maxHistorySize: number\n\n constructor(options?: { maxHistorySize?: number }) {\n this.maxHistorySize = options?.maxHistorySize ?? 50\n }\n\n addRoute(route: RouteDefinition): void {\n if (this.routes.has(route.id)) {\n throw new Error(`Route '${route.id}' is already registered`)\n }\n const compiled = this.compileRoute(route)\n this.routes.set(route.id, compiled)\n }\n\n removeRoute(routeId: string): boolean {\n return this.routes.delete(routeId)\n }\n\n matchRoute(path: string): RouteMatchResult {\n const { pathname, query, hash } = this.parsePath(path)\n\n for (const compiled of this.routes.values()) {\n const match = this.tryMatch(compiled, pathname, query, hash)\n if (match) {\n return { matched: true, match }\n }\n }\n\n return { matched: false, reason: `No route matches path: ${path}` }\n }\n\n async navigate(target: NavigationTarget): Promise<NavigationResult> {\n const fullPath = this.buildPath(target)\n const matchResult = this.matchRoute(fullPath)\n\n if (!matchResult.matched) {\n return { success: false, reason: 'no_match' }\n }\n\n const match = matchResult.match\n\n // Check if navigating to the same route\n if (\n this.currentRoute &&\n this.currentRoute.route.id === match.route.id &&\n this.currentRoute.path === match.path\n ) {\n return { success: false, reason: 'same_route' }\n }\n\n // Execute guards\n if (match.route.guards && match.route.guards.length > 0) {\n for (const guard of match.route.guards) {\n const canActivate = await guard.canActivate({\n from: this.currentRoute,\n to: match,\n params: match.params,\n })\n if (!canActivate) {\n return { success: false, reason: 'guard_rejected' }\n }\n }\n }\n\n // Update current route\n const previousRoute = this.currentRoute\n this.currentRoute = match\n\n // Add to history\n if (!target.replace) {\n this.navigationHistory.push(match)\n while (this.navigationHistory.length > this.maxHistorySize) {\n this.navigationHistory.shift()\n }\n } else if (this.navigationHistory.length > 0) {\n this.navigationHistory[this.navigationHistory.length - 1] = match\n } else {\n this.navigationHistory.push(match)\n }\n\n // Notify listeners\n this.notifyListeners(match, previousRoute)\n\n return { success: true, match }\n }\n\n resolveParams(pattern: string, params: Record<string, string>): string {\n let resolved = pattern\n for (const [key, value] of Object.entries(params)) {\n resolved = resolved.replace(`:${key}`, encodeURIComponent(value))\n }\n return resolved\n }\n\n getCurrentRoute(): RouteMatch | undefined {\n return this.currentRoute\n }\n\n getHistory(): readonly RouteMatch[] {\n return [...this.navigationHistory]\n }\n\n onNavigate(listener: NavigationListener): () => void {\n this.listeners.add(listener)\n return () => {\n this.listeners.delete(listener)\n }\n }\n\n getRouteIds(): readonly string[] {\n return Array.from(this.routes.keys())\n }\n\n clear(): void {\n this.routes.clear()\n this.listeners.clear()\n this.navigationHistory.length = 0\n this.currentRoute = undefined\n }\n\n // ============================================================\n // PRIVATE METHODS\n // ============================================================\n\n private compileRoute(route: RouteDefinition): CompiledRoute {\n const paramNames: string[] = []\n\n // Convert pattern to regex\n // :param -> named capture group\n // * -> wildcard capture\n let regexStr = route.pattern\n .replace(/\\/:(\\w+)/g, (_match, paramName: string) => {\n paramNames.push(paramName)\n return '/([^/]+)'\n })\n .replace(/\\*$/, '(.*)')\n\n // Ensure exact match (anchor start and end)\n regexStr = `^${regexStr}$`\n\n return {\n definition: route,\n regex: new RegExp(regexStr),\n paramNames,\n }\n }\n\n private tryMatch(\n compiled: CompiledRoute,\n pathname: string,\n query: Record<string, string>,\n hash: string\n ): RouteMatch | null {\n const match = pathname.match(compiled.regex)\n if (!match) return null\n\n const params: Record<string, string> = {}\n for (let i = 0; i < compiled.paramNames.length; i++) {\n const name = compiled.paramNames[i]\n const value = match[i + 1]\n if (name && value !== undefined) {\n params[name] = decodeURIComponent(value)\n }\n }\n\n return {\n route: compiled.definition,\n params,\n query,\n path: pathname,\n hash,\n }\n }\n\n private parsePath(path: string): {\n pathname: string\n query: Record<string, string>\n hash: string\n } {\n let pathname = path\n let hash = ''\n const query: Record<string, string> = {}\n\n // Extract hash\n const hashIndex = pathname.indexOf('#')\n if (hashIndex >= 0) {\n hash = pathname.slice(hashIndex + 1)\n pathname = pathname.slice(0, hashIndex)\n }\n\n // Extract query\n const queryIndex = pathname.indexOf('?')\n if (queryIndex >= 0) {\n const queryString = pathname.slice(queryIndex + 1)\n pathname = pathname.slice(0, queryIndex)\n\n for (const pair of queryString.split('&')) {\n const [key, value] = pair.split('=')\n if (key) {\n query[decodeURIComponent(key)] = value ? decodeURIComponent(value) : ''\n }\n }\n }\n\n // Normalize pathname\n if (!pathname.startsWith('/')) {\n pathname = '/' + pathname\n }\n\n return { pathname, query, hash }\n }\n\n private buildPath(target: NavigationTarget): string {\n let path = target.path\n\n if (target.query && Object.keys(target.query).length > 0) {\n const queryParts = Object.entries(target.query).map(\n ([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`\n )\n path += '?' + queryParts.join('&')\n }\n\n if (target.hash) {\n path += '#' + target.hash\n }\n\n return path\n }\n\n private notifyListeners(to: RouteMatch, from: RouteMatch | undefined): void {\n for (const listener of this.listeners) {\n try {\n listener(to, from)\n } catch {\n // Swallow listener errors\n }\n }\n }\n}\n\n// ============================================================\n// FACTORY FUNCTION\n// ============================================================\n\n/**\n * Create a routing capability instance\n */\nexport function createRoutingCapability(options?: { maxHistorySize?: number }): RoutingCapability {\n return new DefaultRoutingCapability(options)\n}\n"]}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Routing Capability Types
3
+ *
4
+ * Route matching, navigation, and URL parameter resolution
5
+ *
6
+ * @module @pwfabric/runtime/routing/types
7
+ */
8
+ /**
9
+ * Route definition for mapping URLs to surfaces
10
+ */
11
+ export interface RouteDefinition {
12
+ /** Unique route identifier */
13
+ readonly id: string;
14
+ /** URL pattern (supports :param and * wildcard) */
15
+ readonly pattern: string;
16
+ /** Surface ID this route maps to */
17
+ readonly surfaceId: string;
18
+ /** Human-readable name */
19
+ readonly name?: string;
20
+ /** Route metadata */
21
+ readonly metadata?: Readonly<Record<string, unknown>>;
22
+ /** Navigation guards for this route */
23
+ readonly guards?: readonly RouteGuard[];
24
+ /** Child routes (for nested routing) */
25
+ readonly children?: readonly RouteDefinition[];
26
+ }
27
+ /**
28
+ * Route guard function
29
+ */
30
+ export interface RouteGuard {
31
+ readonly name: string;
32
+ canActivate(context: RouteGuardContext): boolean | Promise<boolean>;
33
+ }
34
+ /**
35
+ * Context provided to route guards
36
+ */
37
+ export interface RouteGuardContext {
38
+ readonly from: RouteMatch | undefined;
39
+ readonly to: RouteMatch;
40
+ readonly params: Readonly<Record<string, string>>;
41
+ }
42
+ /**
43
+ * Result of matching a URL against routes
44
+ */
45
+ export type RouteMatchResult = {
46
+ readonly matched: true;
47
+ readonly match: RouteMatch;
48
+ } | {
49
+ readonly matched: false;
50
+ readonly reason: string;
51
+ };
52
+ /**
53
+ * A successfully matched route
54
+ */
55
+ export interface RouteMatch {
56
+ /** The matched route definition */
57
+ readonly route: RouteDefinition;
58
+ /** Extracted URL parameters */
59
+ readonly params: Readonly<Record<string, string>>;
60
+ /** Query parameters */
61
+ readonly query: Readonly<Record<string, string>>;
62
+ /** The full matched path */
63
+ readonly path: string;
64
+ /** Hash fragment (without #) */
65
+ readonly hash: string;
66
+ }
67
+ /**
68
+ * Navigation target
69
+ */
70
+ export interface NavigationTarget {
71
+ /** Path to navigate to */
72
+ readonly path: string;
73
+ /** Query parameters */
74
+ readonly query?: Readonly<Record<string, string>>;
75
+ /** Hash fragment */
76
+ readonly hash?: string;
77
+ /** Whether to replace current history entry */
78
+ readonly replace?: boolean;
79
+ /** Navigation state data */
80
+ readonly state?: unknown;
81
+ }
82
+ /**
83
+ * Navigation result
84
+ */
85
+ export type NavigationResult = {
86
+ readonly success: true;
87
+ readonly match: RouteMatch;
88
+ } | {
89
+ readonly success: false;
90
+ readonly reason: NavigationFailureReason;
91
+ };
92
+ /**
93
+ * Reasons navigation can fail
94
+ */
95
+ export type NavigationFailureReason = 'no_match' | 'guard_rejected' | 'same_route' | 'aborted';
96
+ /**
97
+ * Listener for navigation events
98
+ */
99
+ export type NavigationListener = (to: RouteMatch, from: RouteMatch | undefined) => void;
100
+ /**
101
+ * Routing capability interface for managing routes and navigation
102
+ */
103
+ export interface RoutingCapability {
104
+ /** Register a route definition */
105
+ addRoute(route: RouteDefinition): void;
106
+ /** Remove a route by ID */
107
+ removeRoute(routeId: string): boolean;
108
+ /** Match a URL path against registered routes */
109
+ matchRoute(path: string): RouteMatchResult;
110
+ /** Navigate to a target */
111
+ navigate(target: NavigationTarget): Promise<NavigationResult>;
112
+ /** Resolve parameters from a route pattern and values */
113
+ resolveParams(pattern: string, params: Record<string, string>): string;
114
+ /** Get the current route match */
115
+ getCurrentRoute(): RouteMatch | undefined;
116
+ /** Get navigation history */
117
+ getHistory(): readonly RouteMatch[];
118
+ /** Subscribe to navigation events */
119
+ onNavigate(listener: NavigationListener): () => void;
120
+ /** Get all registered route IDs */
121
+ getRouteIds(): readonly string[];
122
+ /** Clear all routes */
123
+ clear(): void;
124
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Routing Capability Types
3
+ *
4
+ * Route matching, navigation, and URL parameter resolution
5
+ *
6
+ * @module @pwfabric/runtime/routing/types
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/routing/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG","sourcesContent":["/**\n * Routing Capability Types\n *\n * Route matching, navigation, and URL parameter resolution\n *\n * @module @pwfabric/runtime/routing/types\n */\n\n// ============================================================\n// ROUTE DEFINITION\n// ============================================================\n\n/**\n * Route definition for mapping URLs to surfaces\n */\nexport interface RouteDefinition {\n /** Unique route identifier */\n readonly id: string\n\n /** URL pattern (supports :param and * wildcard) */\n readonly pattern: string\n\n /** Surface ID this route maps to */\n readonly surfaceId: string\n\n /** Human-readable name */\n readonly name?: string\n\n /** Route metadata */\n readonly metadata?: Readonly<Record<string, unknown>>\n\n /** Navigation guards for this route */\n readonly guards?: readonly RouteGuard[]\n\n /** Child routes (for nested routing) */\n readonly children?: readonly RouteDefinition[]\n}\n\n/**\n * Route guard function\n */\nexport interface RouteGuard {\n readonly name: string\n canActivate(context: RouteGuardContext): boolean | Promise<boolean>\n}\n\n/**\n * Context provided to route guards\n */\nexport interface RouteGuardContext {\n readonly from: RouteMatch | undefined\n readonly to: RouteMatch\n readonly params: Readonly<Record<string, string>>\n}\n\n// ============================================================\n// ROUTE MATCH\n// ============================================================\n\n/**\n * Result of matching a URL against routes\n */\nexport type RouteMatchResult =\n | { readonly matched: true; readonly match: RouteMatch }\n | { readonly matched: false; readonly reason: string }\n\n/**\n * A successfully matched route\n */\nexport interface RouteMatch {\n /** The matched route definition */\n readonly route: RouteDefinition\n\n /** Extracted URL parameters */\n readonly params: Readonly<Record<string, string>>\n\n /** Query parameters */\n readonly query: Readonly<Record<string, string>>\n\n /** The full matched path */\n readonly path: string\n\n /** Hash fragment (without #) */\n readonly hash: string\n}\n\n// ============================================================\n// NAVIGATION\n// ============================================================\n\n/**\n * Navigation target\n */\nexport interface NavigationTarget {\n /** Path to navigate to */\n readonly path: string\n\n /** Query parameters */\n readonly query?: Readonly<Record<string, string>>\n\n /** Hash fragment */\n readonly hash?: string\n\n /** Whether to replace current history entry */\n readonly replace?: boolean\n\n /** Navigation state data */\n readonly state?: unknown\n}\n\n/**\n * Navigation result\n */\nexport type NavigationResult =\n | { readonly success: true; readonly match: RouteMatch }\n | { readonly success: false; readonly reason: NavigationFailureReason }\n\n/**\n * Reasons navigation can fail\n */\nexport type NavigationFailureReason = 'no_match' | 'guard_rejected' | 'same_route' | 'aborted'\n\n/**\n * Listener for navigation events\n */\nexport type NavigationListener = (to: RouteMatch, from: RouteMatch | undefined) => void\n\n// ============================================================\n// ROUTING CAPABILITY INTERFACE\n// ============================================================\n\n/**\n * Routing capability interface for managing routes and navigation\n */\nexport interface RoutingCapability {\n /** Register a route definition */\n addRoute(route: RouteDefinition): void\n\n /** Remove a route by ID */\n removeRoute(routeId: string): boolean\n\n /** Match a URL path against registered routes */\n matchRoute(path: string): RouteMatchResult\n\n /** Navigate to a target */\n navigate(target: NavigationTarget): Promise<NavigationResult>\n\n /** Resolve parameters from a route pattern and values */\n resolveParams(pattern: string, params: Record<string, string>): string\n\n /** Get the current route match */\n getCurrentRoute(): RouteMatch | undefined\n\n /** Get navigation history */\n getHistory(): readonly RouteMatch[]\n\n /** Subscribe to navigation events */\n onNavigate(listener: NavigationListener): () => void\n\n /** Get all registered route IDs */\n getRouteIds(): readonly string[]\n\n /** Clear all routes */\n clear(): void\n}\n"]}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * SEO Capability Implementation
3
+ *
4
+ * Meta tag generation, JSON-LD structured data, and Open Graph tags
5
+ *
6
+ * All outputs are plain serializable objects suitable for SSR.
7
+ *
8
+ * @module @pwfabric/runtime/seo/generator
9
+ */
10
+ import type { SeoCapability, MetaTagInput, MetaTagOutput, StructuredDataInput, StructuredDataOutput, OpenGraphInput, OpenGraphOutput, SeoConfig, SeoOutput } from './types.js';
11
+ /**
12
+ * Default SEO capability implementation
13
+ */
14
+ export declare class DefaultSeoCapability implements SeoCapability {
15
+ private readonly defaults;
16
+ constructor(defaults?: Partial<SeoDefaults>);
17
+ generateMetaTags(input: MetaTagInput): MetaTagOutput;
18
+ generateStructuredData(input: StructuredDataInput): StructuredDataOutput;
19
+ generateOpenGraph(input: OpenGraphInput): OpenGraphOutput;
20
+ generateAll(config: SeoConfig): SeoOutput;
21
+ }
22
+ interface SeoDefaults {
23
+ siteName: string;
24
+ titleSeparator: string;
25
+ defaultViewport: string;
26
+ defaultCharset: string;
27
+ defaultRobots: string;
28
+ }
29
+ /**
30
+ * Create an SEO capability instance
31
+ */
32
+ export declare function createSeoCapability(defaults?: {
33
+ siteName?: string;
34
+ titleSeparator?: string;
35
+ defaultViewport?: string;
36
+ defaultCharset?: string;
37
+ defaultRobots?: string;
38
+ }): SeoCapability;
39
+ export {};