@emkodev/emroute 1.6.2 → 1.6.4

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 (128) hide show
  1. package/README.md +6 -6
  2. package/dist/runtime/abstract.runtime.d.ts +94 -0
  3. package/dist/runtime/abstract.runtime.js +339 -0
  4. package/dist/runtime/abstract.runtime.js.map +1 -0
  5. package/dist/runtime/bun/esbuild-runtime-loader.plugin.d.ts +25 -0
  6. package/dist/runtime/bun/esbuild-runtime-loader.plugin.js +72 -0
  7. package/dist/runtime/bun/esbuild-runtime-loader.plugin.js.map +1 -0
  8. package/dist/runtime/bun/fs/bun-fs.runtime.d.ts +21 -0
  9. package/dist/runtime/bun/fs/bun-fs.runtime.js +205 -0
  10. package/dist/runtime/bun/fs/bun-fs.runtime.js.map +1 -0
  11. package/dist/runtime/bun/sqlite/bun-sqlite.runtime.d.ts +27 -0
  12. package/dist/runtime/bun/sqlite/bun-sqlite.runtime.js +234 -0
  13. package/dist/runtime/bun/sqlite/bun-sqlite.runtime.js.map +1 -0
  14. package/dist/runtime/sitemap.generator.d.ts +58 -0
  15. package/dist/runtime/sitemap.generator.js +107 -0
  16. package/dist/runtime/sitemap.generator.js.map +1 -0
  17. package/dist/runtime/universal/fs/universal-fs.runtime.d.ts +29 -0
  18. package/dist/runtime/universal/fs/universal-fs.runtime.js +213 -0
  19. package/dist/runtime/universal/fs/universal-fs.runtime.js.map +1 -0
  20. package/dist/server/codegen.util.d.ts +16 -0
  21. package/dist/server/codegen.util.js +46 -0
  22. package/dist/server/codegen.util.js.map +1 -0
  23. package/dist/server/emroute.server.d.ts +37 -0
  24. package/dist/server/emroute.server.js +314 -0
  25. package/dist/server/emroute.server.js.map +1 -0
  26. package/dist/server/esbuild-manifest.plugin.d.ts +26 -0
  27. package/dist/server/esbuild-manifest.plugin.js +187 -0
  28. package/dist/server/esbuild-manifest.plugin.js.map +1 -0
  29. package/dist/server/scanner.util.d.ts +22 -0
  30. package/dist/server/scanner.util.js +194 -0
  31. package/dist/server/scanner.util.js.map +1 -0
  32. package/dist/server/server-api.type.d.ts +71 -0
  33. package/dist/server/server-api.type.js +9 -0
  34. package/dist/server/server-api.type.js.map +1 -0
  35. package/dist/src/component/abstract.component.d.ts +197 -0
  36. package/dist/src/component/abstract.component.js +84 -0
  37. package/dist/src/component/abstract.component.js.map +1 -0
  38. package/dist/src/component/page.component.d.ts +74 -0
  39. package/dist/src/component/page.component.js +107 -0
  40. package/dist/src/component/page.component.js.map +1 -0
  41. package/dist/src/component/widget.component.d.ts +47 -0
  42. package/dist/src/component/widget.component.js +69 -0
  43. package/dist/src/component/widget.component.js.map +1 -0
  44. package/dist/src/element/component.element.d.ts +79 -0
  45. package/dist/src/element/component.element.js +293 -0
  46. package/dist/src/element/component.element.js.map +1 -0
  47. package/dist/src/element/markdown.element.d.ts +36 -0
  48. package/dist/src/element/markdown.element.js +93 -0
  49. package/dist/src/element/markdown.element.js.map +1 -0
  50. package/dist/src/element/slot.element.d.ts +30 -0
  51. package/dist/src/element/slot.element.js +31 -0
  52. package/dist/src/element/slot.element.js.map +1 -0
  53. package/dist/src/index.d.ts +23 -0
  54. package/dist/src/index.js +24 -0
  55. package/dist/src/index.js.map +1 -0
  56. package/dist/src/overlay/mod.d.ts +9 -0
  57. package/dist/src/overlay/mod.js +9 -0
  58. package/dist/src/overlay/mod.js.map +1 -0
  59. package/dist/src/overlay/overlay.css.d.ts +8 -0
  60. package/dist/src/overlay/overlay.css.js +170 -0
  61. package/dist/src/overlay/overlay.css.js.map +1 -0
  62. package/dist/src/overlay/overlay.service.d.ts +14 -0
  63. package/dist/src/overlay/overlay.service.js +307 -0
  64. package/dist/src/overlay/overlay.service.js.map +1 -0
  65. package/dist/src/overlay/overlay.type.d.ts +33 -0
  66. package/dist/src/overlay/overlay.type.js +11 -0
  67. package/dist/src/overlay/overlay.type.js.map +1 -0
  68. package/dist/src/renderer/spa/base.renderer.d.ts +39 -0
  69. package/dist/src/renderer/spa/base.renderer.js +149 -0
  70. package/dist/src/renderer/spa/base.renderer.js.map +1 -0
  71. package/dist/src/renderer/spa/hash.renderer.d.ts +78 -0
  72. package/dist/src/renderer/spa/hash.renderer.js +162 -0
  73. package/dist/src/renderer/spa/hash.renderer.js.map +1 -0
  74. package/dist/src/renderer/spa/html.renderer.d.ts +81 -0
  75. package/dist/src/renderer/spa/html.renderer.js +304 -0
  76. package/dist/src/renderer/spa/html.renderer.js.map +1 -0
  77. package/dist/src/renderer/spa/mod.d.ts +30 -0
  78. package/dist/src/renderer/spa/mod.js +35 -0
  79. package/dist/src/renderer/spa/mod.js.map +1 -0
  80. package/dist/src/renderer/ssr/html.renderer.d.ts +49 -0
  81. package/dist/src/renderer/ssr/html.renderer.js +108 -0
  82. package/dist/src/renderer/ssr/html.renderer.js.map +1 -0
  83. package/dist/src/renderer/ssr/md.renderer.d.ts +40 -0
  84. package/dist/src/renderer/ssr/md.renderer.js +100 -0
  85. package/dist/src/renderer/ssr/md.renderer.js.map +1 -0
  86. package/dist/src/renderer/ssr/ssr.renderer.d.ts +74 -0
  87. package/dist/src/renderer/ssr/ssr.renderer.js +185 -0
  88. package/dist/src/renderer/ssr/ssr.renderer.js.map +1 -0
  89. package/dist/src/route/route.core.d.ts +129 -0
  90. package/dist/src/route/route.core.js +255 -0
  91. package/dist/src/route/route.core.js.map +1 -0
  92. package/dist/src/route/route.matcher.d.ts +86 -0
  93. package/dist/src/route/route.matcher.js +214 -0
  94. package/dist/src/route/route.matcher.js.map +1 -0
  95. package/dist/src/type/logger.type.d.ts +17 -0
  96. package/dist/src/type/logger.type.js +9 -0
  97. package/dist/src/type/logger.type.js.map +1 -0
  98. package/dist/src/type/markdown.type.d.ts +20 -0
  99. package/dist/src/type/markdown.type.js +2 -0
  100. package/dist/src/type/markdown.type.js.map +1 -0
  101. package/dist/src/type/route.type.d.ts +112 -0
  102. package/dist/src/type/route.type.js +8 -0
  103. package/dist/src/type/route.type.js.map +1 -0
  104. package/dist/src/type/widget.type.d.ts +55 -0
  105. package/dist/src/type/widget.type.js +10 -0
  106. package/dist/src/type/widget.type.js.map +1 -0
  107. package/dist/src/util/html.util.d.ts +29 -0
  108. package/dist/src/util/html.util.js +158 -0
  109. package/dist/src/util/html.util.js.map +1 -0
  110. package/dist/src/util/logger.util.d.ts +26 -0
  111. package/dist/src/util/logger.util.js +80 -0
  112. package/dist/src/util/logger.util.js.map +1 -0
  113. package/dist/src/util/widget-resolve.util.d.ts +52 -0
  114. package/dist/src/util/widget-resolve.util.js +149 -0
  115. package/dist/src/util/widget-resolve.util.js.map +1 -0
  116. package/dist/src/widget/breadcrumb.widget.d.ts +48 -0
  117. package/dist/src/widget/breadcrumb.widget.js +72 -0
  118. package/dist/src/widget/breadcrumb.widget.js.map +1 -0
  119. package/dist/src/widget/page-title.widget.d.ts +33 -0
  120. package/dist/src/widget/page-title.widget.js +33 -0
  121. package/dist/src/widget/page-title.widget.js.map +1 -0
  122. package/dist/src/widget/widget.parser.d.ts +26 -0
  123. package/dist/src/widget/widget.parser.js +76 -0
  124. package/dist/src/widget/widget.parser.js.map +1 -0
  125. package/dist/src/widget/widget.registry.d.ts +23 -0
  126. package/dist/src/widget/widget.registry.js +42 -0
  127. package/dist/src/widget/widget.registry.js.map +1 -0
  128. package/package.json +63 -13
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Hash Router
3
+ *
4
+ * Lightweight client-side router for leaf mode mini-apps.
5
+ * Uses hashchange events + RouteCore pattern matching.
6
+ *
7
+ * Routes are defined inline by the consumer, not from the main manifest.
8
+ * Coexists with SpaHtmlRouter in root mode (SPA router skips hash changes).
9
+ */
10
+ import { RouteCore } from "../../route/route.core.js";
11
+ import { escapeHtml } from "../../util/html.util.js";
12
+ import { logger } from "../../util/logger.util.js";
13
+ import { BaseRenderer } from "./base.renderer.js";
14
+ /**
15
+ * Build an internal RoutesManifest from inline hash route definitions.
16
+ * Each route's pattern is used as the moduleLoaders key so RouteCore.loadModule works.
17
+ */
18
+ function buildManifest(routes) {
19
+ return {
20
+ routes: routes.map((r) => ({
21
+ pattern: r.pattern,
22
+ type: 'page',
23
+ modulePath: r.pattern,
24
+ files: { ts: r.pattern },
25
+ })),
26
+ errorBoundaries: [],
27
+ statusPages: new Map(),
28
+ moduleLoaders: Object.fromEntries(routes.map((r) => [r.pattern, r.loader])),
29
+ };
30
+ }
31
+ /**
32
+ * Hash-based mini-app router for leaf mode pages.
33
+ *
34
+ * Listens to `hashchange`, maps `#/path` → pattern match via RouteCore,
35
+ * renders matched PageComponent into a slot element.
36
+ *
37
+ * @experimental
38
+ */
39
+ export class HashRouter extends BaseRenderer {
40
+ boundHandler = null;
41
+ constructor(manifest, options) {
42
+ const core = new RouteCore(manifest, {
43
+ extendContext: options?.extendContext,
44
+ });
45
+ super(core);
46
+ }
47
+ /**
48
+ * Initialize: find slot, attach hashchange listener, render initial hash.
49
+ */
50
+ async initialize(slot = 'hash-slot') {
51
+ this.slot = typeof slot === 'string' ? document.querySelector(slot) : slot;
52
+ if (!this.slot) {
53
+ console.error(`[HashRouter] Slot not found: ${slot}`);
54
+ return;
55
+ }
56
+ this.boundHandler = () => {
57
+ this.handleHashChange();
58
+ };
59
+ globalThis.addEventListener('hashchange', this.boundHandler);
60
+ // Render initial hash if present
61
+ if (location.hash.length > 1) {
62
+ await this.handleHashChange();
63
+ }
64
+ }
65
+ /**
66
+ * Navigate to a hash path. Triggers hashchange → render.
67
+ */
68
+ navigate(hash) {
69
+ location.hash = hash.startsWith('#') ? hash : '#' + hash;
70
+ }
71
+ /**
72
+ * Add event listener for router events.
73
+ */
74
+ addEventListener(listener) {
75
+ return this.core.addEventListener(listener);
76
+ }
77
+ /**
78
+ * Remove event listeners and release references.
79
+ */
80
+ dispose() {
81
+ if (this.boundHandler) {
82
+ globalThis.removeEventListener('hashchange', this.boundHandler);
83
+ this.boundHandler = null;
84
+ }
85
+ this.slot = null;
86
+ }
87
+ /**
88
+ * Handle a hashchange event: parse hash, match, render.
89
+ */
90
+ async handleHashChange() {
91
+ const path = location.hash.slice(1) || '/';
92
+ const matchUrl = new URL(path, location.origin);
93
+ logger.nav('hash', path, path);
94
+ const controller = new AbortController();
95
+ const { signal } = controller;
96
+ try {
97
+ const matched = this.core.match(matchUrl);
98
+ if (!matched) {
99
+ logger.nav('hash-not-found', path, path);
100
+ if (this.slot) {
101
+ this.slot.setHTMLUnsafe(`
102
+ <h1>Not Found</h1>
103
+ <p>Path: ${escapeHtml(path)}</p>
104
+ `);
105
+ }
106
+ return;
107
+ }
108
+ logger.nav('hash-matched', path, matched.route.pattern, { params: matched.params });
109
+ this.core.currentRoute = matched;
110
+ const routeInfo = this.core.toRouteInfo(matched, path);
111
+ await this.renderPage(routeInfo, matched, signal);
112
+ if (signal.aborted)
113
+ return;
114
+ this.core.emit({
115
+ type: 'navigate',
116
+ pathname: path,
117
+ params: matched.params,
118
+ });
119
+ }
120
+ catch (error) {
121
+ if (signal.aborted)
122
+ return;
123
+ console.error('[HashRouter] Render error:', error);
124
+ this.core.emit({
125
+ type: 'error',
126
+ pathname: path,
127
+ params: {},
128
+ error: error instanceof Error ? error : new Error(String(error)),
129
+ });
130
+ if (this.slot) {
131
+ const message = error instanceof Error ? error.message : String(error);
132
+ this.slot.setHTMLUnsafe(`
133
+ <h1>Error</h1>
134
+ <p>${escapeHtml(message)}</p>
135
+ `);
136
+ }
137
+ }
138
+ }
139
+ }
140
+ /**
141
+ * Create and initialize a hash router for a leaf-mode mini-app.
142
+ *
143
+ * The router instance is stored on `globalThis.__emroute_hash_router` for
144
+ * programmatic access. Calling twice returns the existing router with a warning.
145
+ *
146
+ * @experimental
147
+ */
148
+ export async function createHashRouter(options) {
149
+ const g = globalThis;
150
+ if (g.__emroute_hash_router) {
151
+ console.warn('eMroute: Hash router already initialized.');
152
+ return g.__emroute_hash_router;
153
+ }
154
+ const manifest = buildManifest(options.routes);
155
+ const router = new HashRouter(manifest, {
156
+ extendContext: options.extendContext,
157
+ });
158
+ await router.initialize(options.slot ?? 'hash-slot');
159
+ g.__emroute_hash_router = router;
160
+ return router;
161
+ }
162
+ //# sourceMappingURL=hash.renderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.renderer.js","sourceRoot":"","sources":["../../../../src/renderer/spa/hash.renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AA0BlD;;;GAGG;AACH,SAAS,aAAa,CAAC,MAAyB;IAC9C,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACzB,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,IAAI,EAAE,MAAe;YACrB,UAAU,EAAE,CAAC,CAAC,OAAO;YACrB,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE;SACzB,CAAC,CAAC;QACH,eAAe,EAAE,EAAE;QACnB,WAAW,EAAE,IAAI,GAAG,EAAE;QACtB,aAAa,EAAE,MAAM,CAAC,WAAW,CAC/B,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CACzC;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,OAAO,UAAW,SAAQ,YAAY;IAClC,YAAY,GAAwB,IAAI,CAAC;IAEjD,YAAY,QAAwB,EAAE,OAA6C;QACjF,MAAM,IAAI,GAAG,IAAI,SAAS,CAAC,QAAQ,EAAE;YACnC,aAAa,EAAE,OAAO,EAAE,aAAa;SACtC,CAAC,CAAC;QACH,KAAK,CAAC,IAAI,CAAC,CAAC;IACd,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,UAAU,CAAC,OAAyB,WAAW;QACnD,IAAI,CAAC,IAAI,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAE3E,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,gCAAgC,IAAI,EAAE,CAAC,CAAC;YACtD,OAAO;QACT,CAAC;QAED,IAAI,CAAC,YAAY,GAAG,GAAG,EAAE;YACvB,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAC1B,CAAC,CAAC;QACF,UAAU,CAAC,gBAAgB,CAAC,YAAY,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QAE7D,iCAAiC;QACjC,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAChC,CAAC;IACH,CAAC;IAED;;OAEG;IACH,QAAQ,CAAC,IAAY;QACnB,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC;IAC3D,CAAC;IAED;;OAEG;IACH,gBAAgB,CACd,QAAsD;QAEtD,OAAO,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAC9C,CAAC;IAED;;OAEG;IACH,OAAO;QACL,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,UAAU,CAAC,mBAAmB,CAAC,YAAY,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;YAChE,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QAC3B,CAAC;QACD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,gBAAgB;QAC5B,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC;QAC3C,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;QAEhD,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAE/B,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC;QAE9B,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAE1C,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,MAAM,CAAC,GAAG,CAAC,gBAAgB,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;gBACzC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;oBACd,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC;;uBAEX,UAAU,CAAC,IAAI,CAAC;WAC5B,CAAC,CAAC;gBACL,CAAC;gBACD,OAAO;YACT,CAAC;YAED,MAAM,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;YAEpF,IAAI,CAAC,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC;YACjC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YAEvD,MAAM,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;YAElD,IAAI,MAAM,CAAC,OAAO;gBAAE,OAAO;YAE3B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;gBACb,IAAI,EAAE,UAAU;gBAChB,QAAQ,EAAE,IAAI;gBACd,MAAM,EAAE,OAAO,CAAC,MAAM;aACvB,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,MAAM,CAAC,OAAO;gBAAE,OAAO;YAC3B,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,KAAK,CAAC,CAAC;YAEnD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;gBACb,IAAI,EAAE,OAAO;gBACb,QAAQ,EAAE,IAAI;gBACd,MAAM,EAAE,EAAE;gBACV,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;aACjE,CAAC,CAAC;YAEH,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACd,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACvE,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC;;eAEjB,UAAU,CAAC,OAAO,CAAC;SACzB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;CACF;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,OAA0B;IAE1B,MAAM,CAAC,GAAG,UAAqC,CAAC;IAChD,IAAI,CAAC,CAAC,qBAAqB,EAAE,CAAC;QAC5B,OAAO,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;QAC1D,OAAO,CAAC,CAAC,qBAAmC,CAAC;IAC/C,CAAC;IAED,MAAM,QAAQ,GAAG,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,QAAQ,EAAE;QACtC,aAAa,EAAE,OAAO,CAAC,aAAa;KACrC,CAAC,CAAC;IACH,MAAM,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,IAAI,WAAW,CAAC,CAAC;IACrD,CAAC,CAAC,qBAAqB,GAAG,MAAM,CAAC;IACjC,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * SPA HTML Renderer
3
+ *
4
+ * Browser-based Single Page Application renderer.
5
+ * Handles:
6
+ * - DOM manipulation (slot.innerHTML)
7
+ * - Navigation API (navigate event, intercept, scroll restoration)
8
+ * - Document title via component.getTitle()
9
+ * - View transitions
10
+ */
11
+ import type { MatchedRoute, NavigateOptions, RouteParams, RoutesManifest } from '../../type/route.type.ts';
12
+ import type { ContextProvider } from '../../component/abstract.component.ts';
13
+ import { type BasePath, RouteCore } from '../../route/route.core.ts';
14
+ import { BaseRenderer } from './base.renderer.ts';
15
+ /** Options for SPA HTML Router */
16
+ export interface SpaHtmlRouterOptions {
17
+ /** Enriches every ComponentContext with app-level services before it reaches components. */
18
+ extendContext?: ContextProvider;
19
+ /** Base paths for SSR endpoints. SPA uses html basePath for routing, md for passthrough. */
20
+ basePath?: BasePath;
21
+ }
22
+ /**
23
+ * SPA Router for browser-based HTML rendering.
24
+ */
25
+ export declare class SpaHtmlRouter extends BaseRenderer {
26
+ private abortController;
27
+ /** Base paths for SSR endpoints. */
28
+ private htmlBase;
29
+ private mdBase;
30
+ constructor(manifest: RoutesManifest, options?: SpaHtmlRouterOptions);
31
+ /**
32
+ * Initialize router with slot element.
33
+ * Sets up Navigation API listener and performs initial navigation.
34
+ */
35
+ initialize(slotSelector?: string): Promise<void>;
36
+ /**
37
+ * Remove event listeners and release references.
38
+ */
39
+ dispose(): void;
40
+ /**
41
+ * Navigate to a new URL.
42
+ */
43
+ navigate(url: string, options?: NavigateOptions): Promise<void>;
44
+ /**
45
+ * Add event listener for router events.
46
+ */
47
+ addEventListener(listener: Parameters<RouteCore['addEventListener']>[0]): () => void;
48
+ /**
49
+ * Get current route parameters.
50
+ */
51
+ getParams(): RouteParams;
52
+ /**
53
+ * Get current matched route.
54
+ */
55
+ getCurrentRoute(): MatchedRoute | null;
56
+ /**
57
+ * Handle navigation to a URL.
58
+ *
59
+ * Pure render function — URL updates and scroll restoration are handled
60
+ * by the Navigation API. Abort is signalled via the navigate event's signal.
61
+ */
62
+ private handleNavigation;
63
+ /**
64
+ * Render a status-specific page.
65
+ */
66
+ private renderStatusPage;
67
+ /** Try to load and render an error boundary or handler module into the slot. */
68
+ private tryRenderErrorModule;
69
+ /**
70
+ * Handle errors during navigation/rendering.
71
+ */
72
+ private handleError;
73
+ }
74
+ /**
75
+ * Create and initialize SPA HTML router.
76
+ *
77
+ * The router instance is stored on `globalThis.__emroute_router` for
78
+ * programmatic access from consumer scripts (navigate, getParams, etc.).
79
+ * Calling this function twice returns the existing router with a warning.
80
+ */
81
+ export declare function createSpaHtmlRouter(manifest: RoutesManifest, options?: SpaHtmlRouterOptions): Promise<SpaHtmlRouter>;
@@ -0,0 +1,304 @@
1
+ /// <reference path="../../type/navigation-api.d.ts" />
2
+ import { ComponentElement } from "../../element/component.element.js";
3
+ import { assertSafeRedirect, DEFAULT_BASE_PATH, RouteCore, } from "../../route/route.core.js";
4
+ import { escapeHtml, STATUS_MESSAGES } from "../../util/html.util.js";
5
+ import { logger } from "../../util/logger.util.js";
6
+ import { BaseRenderer } from "./base.renderer.js";
7
+ import defaultPageComponent from "../../component/page.component.js";
8
+ /**
9
+ * SPA Router for browser-based HTML rendering.
10
+ */
11
+ export class SpaHtmlRouter extends BaseRenderer {
12
+ abortController = null;
13
+ /** Base paths for SSR endpoints. */
14
+ htmlBase;
15
+ mdBase;
16
+ constructor(manifest, options) {
17
+ const bp = options?.basePath ?? DEFAULT_BASE_PATH;
18
+ const core = new RouteCore(manifest, {
19
+ extendContext: options?.extendContext,
20
+ basePath: bp.html,
21
+ });
22
+ super(core);
23
+ this.htmlBase = bp.html;
24
+ this.mdBase = bp.md;
25
+ if (options?.extendContext) {
26
+ ComponentElement.setContextProvider(options.extendContext);
27
+ }
28
+ }
29
+ /**
30
+ * Initialize router with slot element.
31
+ * Sets up Navigation API listener and performs initial navigation.
32
+ */
33
+ async initialize(slotSelector = 'router-slot') {
34
+ this.slot = document.querySelector(slotSelector);
35
+ if (!this.slot) {
36
+ console.error(`[Router] Slot not found: ${slotSelector}`);
37
+ return;
38
+ }
39
+ // Navigation API required for SPA routing — SSR handles browsers without it
40
+ if (!('navigation' in globalThis)) {
41
+ logger.info('init', 'Navigation API not available — using SSR full-page navigation');
42
+ return;
43
+ }
44
+ this.abortController = new AbortController();
45
+ const { signal } = this.abortController;
46
+ // Single handler for ALL navigations: link clicks, back/forward,
47
+ // navigate() calls, form submissions. Replaces popstate + click listeners.
48
+ navigation.addEventListener('navigate', (event) => {
49
+ if (!event.canIntercept)
50
+ return;
51
+ if (event.hashChange)
52
+ return;
53
+ if (event.downloadRequest !== null)
54
+ return;
55
+ const url = new URL(event.destination.url);
56
+ // /md/ paths pass through to server for full page load
57
+ if (url.pathname.startsWith(this.mdBase + '/') || url.pathname === this.mdBase) {
58
+ return;
59
+ }
60
+ event.intercept({
61
+ scroll: 'manual',
62
+ handler: async () => {
63
+ await this.handleNavigation(url.pathname + url.search + url.hash, event.signal);
64
+ event.scroll();
65
+ },
66
+ });
67
+ }, { signal });
68
+ // Check for SSR content — skip initial render if route matches.
69
+ // data-ssr-route stores the full path including basePath (e.g. /html/about).
70
+ const ssrRoute = this.slot.getAttribute('data-ssr-route');
71
+ if (ssrRoute) {
72
+ const currentPath = location.pathname;
73
+ logger.ssr('check-adoption', `SSR route=${ssrRoute}, current=${currentPath}`);
74
+ if (currentPath === ssrRoute || currentPath === ssrRoute + '/') {
75
+ // Adopt SSR content — patterns are prefixed, match directly
76
+ const matched = this.core.match(new URL(ssrRoute, location.origin));
77
+ if (matched) {
78
+ logger.ssr('adopt', ssrRoute);
79
+ this.core.currentRoute = matched;
80
+ navigation.updateCurrentEntry({
81
+ state: { pathname: ssrRoute, params: matched.params },
82
+ });
83
+ }
84
+ this.slot.removeAttribute('data-ssr-route');
85
+ return;
86
+ }
87
+ else {
88
+ logger.ssr('mismatch', `Expected ${ssrRoute}, got ${currentPath}`);
89
+ }
90
+ }
91
+ // No SSR content or route mismatch — full client-side render
92
+ logger.info('init', `Initial navigation to ${location.pathname}`);
93
+ await this.handleNavigation(location.pathname + location.search + location.hash, this.abortController.signal);
94
+ }
95
+ /**
96
+ * Remove event listeners and release references.
97
+ */
98
+ dispose() {
99
+ this.abortController?.abort();
100
+ this.abortController = null;
101
+ this.slot = null;
102
+ ComponentElement.setContextProvider(undefined);
103
+ }
104
+ /**
105
+ * Navigate to a new URL.
106
+ */
107
+ async navigate(url, options = {}) {
108
+ const normalizedUrl = this.core.normalizeUrl(url);
109
+ try {
110
+ const { finished } = navigation.navigate(normalizedUrl, {
111
+ state: options.state,
112
+ history: options.replace ? 'replace' : 'auto',
113
+ });
114
+ await finished;
115
+ }
116
+ catch (e) {
117
+ // Navigation interrupted (e.g. by a redirect) — not an error
118
+ if (e instanceof DOMException && e.name === 'AbortError')
119
+ return;
120
+ throw e;
121
+ }
122
+ }
123
+ /**
124
+ * Add event listener for router events.
125
+ */
126
+ addEventListener(listener) {
127
+ return this.core.addEventListener(listener);
128
+ }
129
+ /**
130
+ * Get current route parameters.
131
+ */
132
+ getParams() {
133
+ return this.core.getParams();
134
+ }
135
+ /**
136
+ * Get current matched route.
137
+ */
138
+ getCurrentRoute() {
139
+ return this.core.currentRoute;
140
+ }
141
+ /**
142
+ * Handle navigation to a URL.
143
+ *
144
+ * Pure render function — URL updates and scroll restoration are handled
145
+ * by the Navigation API. Abort is signalled via the navigate event's signal.
146
+ */
147
+ async handleNavigation(url, signal) {
148
+ const urlObj = new URL(url, location.origin);
149
+ const pathname = urlObj.pathname;
150
+ logger.nav('start', location.pathname, pathname);
151
+ // /md/ paths are handled server-side (initial load only — navigate handler filters these)
152
+ if (pathname.startsWith(this.mdBase + '/') || pathname === this.mdBase) {
153
+ logger.nav('redirect-md', pathname, pathname, { reason: 'server-side markdown' });
154
+ globalThis.location.href = url;
155
+ return;
156
+ }
157
+ try {
158
+ const matched = this.core.match(urlObj);
159
+ if (!matched) {
160
+ logger.nav('not-found', pathname, pathname);
161
+ await this.renderStatusPage(404, pathname);
162
+ return;
163
+ }
164
+ logger.nav('matched', pathname, matched.route.pattern, { params: matched.params });
165
+ // Handle redirect — starts a new navigation, aborting this one
166
+ if (matched.route.type === 'redirect') {
167
+ const module = await this.core.loadModule(matched.route.modulePath);
168
+ if (signal.aborted)
169
+ return;
170
+ assertSafeRedirect(module.default.to);
171
+ navigation.navigate(module.default.to, { history: 'replace' });
172
+ return;
173
+ }
174
+ // Render page
175
+ this.core.currentRoute = matched;
176
+ const routeInfo = this.core.toRouteInfo(matched, pathname);
177
+ if (document.startViewTransition) {
178
+ const transition = document.startViewTransition(async () => {
179
+ await this.renderPage(routeInfo, matched, signal);
180
+ });
181
+ signal.addEventListener('abort', () => transition.skipTransition(), { once: true });
182
+ await transition.updateCallbackDone;
183
+ }
184
+ else {
185
+ await this.renderPage(routeInfo, matched, signal);
186
+ }
187
+ if (signal.aborted)
188
+ return;
189
+ // Emit navigate event
190
+ this.core.emit({
191
+ type: 'navigate',
192
+ pathname,
193
+ params: matched.params,
194
+ });
195
+ }
196
+ catch (error) {
197
+ if (signal.aborted)
198
+ return;
199
+ if (error instanceof Response) {
200
+ await this.renderStatusPage(error.status, pathname);
201
+ return;
202
+ }
203
+ await this.handleError(error, pathname);
204
+ }
205
+ }
206
+ /**
207
+ * Render a status-specific page.
208
+ */
209
+ async renderStatusPage(status, pathname) {
210
+ if (!this.slot)
211
+ return;
212
+ const statusPage = this.core.matcher.getStatusPage(status);
213
+ if (statusPage) {
214
+ try {
215
+ const component = statusPage.files?.ts
216
+ ? (await this.core.loadModule(statusPage.files.ts)).default
217
+ : defaultPageComponent;
218
+ const ri = {
219
+ pathname,
220
+ pattern: statusPage.pattern,
221
+ params: {},
222
+ searchParams: new URLSearchParams(),
223
+ };
224
+ const context = await this.core.buildComponentContext(ri, statusPage);
225
+ const data = await component.getData({ params: {}, context });
226
+ this.slot.setHTMLUnsafe(component.renderHTML({ data, params: {}, context }));
227
+ this.updateTitle();
228
+ return;
229
+ }
230
+ catch (e) {
231
+ console.error(`[Router] Failed to render ${status} page:`, e);
232
+ }
233
+ }
234
+ this.slot.setHTMLUnsafe(`
235
+ <h1>${STATUS_MESSAGES[status] ?? 'Error'}</h1>
236
+ <p>Path: ${escapeHtml(pathname)}</p>
237
+ `);
238
+ this.updateTitle();
239
+ }
240
+ /** Try to load and render an error boundary or handler module into the slot. */
241
+ async tryRenderErrorModule(modulePath) {
242
+ try {
243
+ const module = await this.core.loadModule(modulePath);
244
+ const component = module.default;
245
+ const minCtx = { pathname: '', pattern: '', params: {}, searchParams: new URLSearchParams() };
246
+ const data = await component.getData({ params: {}, context: minCtx });
247
+ const html = component.renderHTML({ data, params: {}, context: minCtx });
248
+ if (this.slot) {
249
+ this.slot.setHTMLUnsafe(html);
250
+ this.updateTitle();
251
+ }
252
+ return true;
253
+ }
254
+ catch (e) {
255
+ console.error('[Router] Error module failed:', e);
256
+ return false;
257
+ }
258
+ }
259
+ /**
260
+ * Handle errors during navigation/rendering.
261
+ */
262
+ async handleError(error, pathname) {
263
+ console.error('[Router] Navigation error:', error);
264
+ this.core.emit({
265
+ type: 'error',
266
+ pathname,
267
+ params: {},
268
+ error: error instanceof Error ? error : new Error(String(error)),
269
+ });
270
+ const boundary = this.core.matcher.findErrorBoundary(pathname);
271
+ if (boundary && await this.tryRenderErrorModule(boundary.modulePath))
272
+ return;
273
+ const errorHandler = this.core.matcher.getErrorHandler();
274
+ if (errorHandler && await this.tryRenderErrorModule(errorHandler.modulePath))
275
+ return;
276
+ if (this.slot) {
277
+ const message = error instanceof Error ? error.message : String(error);
278
+ this.slot.setHTMLUnsafe(`
279
+ <h1>Error</h1>
280
+ <p>${escapeHtml(message)}</p>
281
+ `);
282
+ this.updateTitle();
283
+ }
284
+ }
285
+ }
286
+ /**
287
+ * Create and initialize SPA HTML router.
288
+ *
289
+ * The router instance is stored on `globalThis.__emroute_router` for
290
+ * programmatic access from consumer scripts (navigate, getParams, etc.).
291
+ * Calling this function twice returns the existing router with a warning.
292
+ */
293
+ export async function createSpaHtmlRouter(manifest, options) {
294
+ const g = globalThis;
295
+ if (g.__emroute_router) {
296
+ console.warn('eMroute: SPA router already initialized. Remove duplicate <script> tags.');
297
+ return g.__emroute_router;
298
+ }
299
+ const router = new SpaHtmlRouter(manifest, options);
300
+ await router.initialize();
301
+ g.__emroute_router = router;
302
+ return router;
303
+ }
304
+ //# sourceMappingURL=html.renderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.renderer.js","sourceRoot":"","sources":["../../../../src/renderer/spa/html.renderer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * SPA (Browser) Module
3
+ *
4
+ * Everything needed for the browser bundle:
5
+ * - SPA router with client-side navigation
6
+ * - Custom elements for rendering and hydrating SSR islands
7
+ * - Widget registry (built-in widgets are opt-in)
8
+ */
9
+ import { RouterSlot } from '../../element/slot.element.ts';
10
+ import { MarkdownElement } from '../../element/markdown.element.ts';
11
+ import { ComponentElement } from '../../element/component.element.ts';
12
+ import { WidgetRegistry } from '../../widget/widget.registry.ts';
13
+ export { createSpaHtmlRouter, SpaHtmlRouter, type SpaHtmlRouterOptions } from './html.renderer.ts';
14
+ export { createHashRouter, type HashRouteConfig, HashRouter, type HashRouterOptions, } from './hash.renderer.ts';
15
+ export { ComponentElement, MarkdownElement, RouterSlot, WidgetRegistry };
16
+ export type { SpaMode, WidgetsManifest } from '../../type/widget.type.ts';
17
+ export { PageComponent } from '../../component/page.component.ts';
18
+ export { WidgetComponent } from '../../component/widget.component.ts';
19
+ export { Component, type ComponentContext, type ComponentManifestEntry, type ContextProvider, type RenderContext, } from '../../component/abstract.component.ts';
20
+ export type { MatchedRoute, NavigateOptions, RouteParams, RouterEvent, RouterEventListener, RouterEventType, RoutesManifest, } from '../../type/route.type.ts';
21
+ export type { MarkdownRenderer } from '../../type/markdown.type.ts';
22
+ export { type BasePath, DEFAULT_BASE_PATH } from '../../route/route.core.ts';
23
+ export { escapeHtml, scopeWidgetCss } from '../../util/html.util.ts';
24
+ export type { ErrorBoundary, RedirectConfig, RouteConfig, RouteFiles, RouteFileType, RouteInfo, RouterState, } from '../../type/route.type.ts';
25
+ export type { ParsedWidgetBlock, WidgetManifestEntry } from '../../type/widget.type.ts';
26
+ export { type Logger, setLogger } from '../../type/logger.type.ts';
27
+ export { createOverlayService } from '../../overlay/overlay.service.ts';
28
+ export type { ModalOptions, OverlayService, PopoverOptions, ToastOptions, } from '../../overlay/overlay.type.ts';
29
+ export { PageTitleWidget } from '../../widget/page-title.widget.ts';
30
+ export { BreadcrumbWidget } from '../../widget/breadcrumb.widget.ts';
@@ -0,0 +1,35 @@
1
+ /**
2
+ * SPA (Browser) Module
3
+ *
4
+ * Everything needed for the browser bundle:
5
+ * - SPA router with client-side navigation
6
+ * - Custom elements for rendering and hydrating SSR islands
7
+ * - Widget registry (built-in widgets are opt-in)
8
+ */
9
+ import { RouterSlot } from "../../element/slot.element.js";
10
+ import { MarkdownElement } from "../../element/markdown.element.js";
11
+ import { ComponentElement } from "../../element/component.element.js";
12
+ import { WidgetRegistry } from "../../widget/widget.registry.js";
13
+ export { createSpaHtmlRouter, SpaHtmlRouter } from "./html.renderer.js";
14
+ export { createHashRouter, HashRouter, } from "./hash.renderer.js";
15
+ export { ComponentElement, MarkdownElement, RouterSlot, WidgetRegistry };
16
+ // Re-export base classes and types for consumer code (pages, widgets)
17
+ export { PageComponent } from "../../component/page.component.js";
18
+ export { WidgetComponent } from "../../component/widget.component.js";
19
+ export { Component, } from "../../component/abstract.component.js";
20
+ export { DEFAULT_BASE_PATH } from "../../route/route.core.js";
21
+ export { escapeHtml, scopeWidgetCss } from "../../util/html.util.js";
22
+ export { setLogger } from "../../type/logger.type.js";
23
+ // Register core custom elements in the browser
24
+ if (globalThis.customElements) {
25
+ if (!customElements.get('router-slot'))
26
+ customElements.define('router-slot', RouterSlot);
27
+ if (!customElements.get('mark-down'))
28
+ customElements.define('mark-down', MarkdownElement);
29
+ }
30
+ // Overlay API (tree-shakeable - only bundled if imported)
31
+ export { createOverlayService } from "../../overlay/overlay.service.js";
32
+ // Optional: Built-in widgets (tree-shakeable - only bundled if imported)
33
+ export { PageTitleWidget } from "../../widget/page-title.widget.js";
34
+ export { BreadcrumbWidget } from "../../widget/breadcrumb.widget.js";
35
+ //# sourceMappingURL=mod.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.js","sourceRoot":"","sources":["../../../../src/renderer/spa/mod.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AACtE,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEjE,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAA6B,MAAM,oBAAoB,CAAC;AACnG,OAAO,EACL,gBAAgB,EAEhB,UAAU,GAEX,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC;AAGzE,sEAAsE;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,qCAAqC,CAAC;AACtE,OAAO,EACL,SAAS,GAKV,MAAM,uCAAuC,CAAC;AAW/C,OAAO,EAAiB,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC7E,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAWrE,OAAO,EAAe,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAEnE,+CAA+C;AAC/C,IAAI,UAAU,CAAC,cAAc,EAAE,CAAC;IAC9B,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,aAAa,CAAC;QAAE,cAAc,CAAC,MAAM,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;IACzF,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,WAAW,CAAC;QAAE,cAAc,CAAC,MAAM,CAAC,WAAW,EAAE,eAAe,CAAC,CAAC;AAC5F,CAAC;AAED,0DAA0D;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AAQxE,yEAAyE;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC"}