@meekojs/meeko 0.0.3 → 0.1.0

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 (188) hide show
  1. package/README.md +35 -16
  2. package/dist/autoimports-ts.d.ts +26 -0
  3. package/dist/autoimports-ts.js +183 -0
  4. package/dist/autoimports-ts.js.map +1 -0
  5. package/dist/autoimports.d.ts +21 -0
  6. package/dist/autoimports.js +301 -0
  7. package/dist/autoimports.js.map +1 -0
  8. package/dist/check.js +74 -33
  9. package/dist/check.js.map +1 -0
  10. package/dist/cli.js +67 -5
  11. package/dist/cli.js.map +1 -0
  12. package/dist/compiler/events.d.ts +2 -0
  13. package/dist/compiler/events.js +6 -0
  14. package/dist/compiler/events.js.map +1 -0
  15. package/dist/compiler/import-graph.d.ts +8 -0
  16. package/dist/compiler/import-graph.js +33 -0
  17. package/dist/compiler/import-graph.js.map +1 -0
  18. package/dist/compiler/mapping.js +1 -0
  19. package/dist/compiler/mapping.js.map +1 -0
  20. package/dist/compiler/project-root.d.ts +2 -0
  21. package/dist/compiler/project-root.js +18 -0
  22. package/dist/compiler/project-root.js.map +1 -0
  23. package/dist/compiler/props.d.ts +12 -0
  24. package/dist/compiler/props.js +32 -0
  25. package/dist/compiler/props.js.map +1 -0
  26. package/dist/compiler/sfc.js +1 -0
  27. package/dist/compiler/sfc.js.map +1 -0
  28. package/dist/compiler/sourcemap.d.ts +3 -0
  29. package/dist/compiler/sourcemap.js +75 -0
  30. package/dist/compiler/sourcemap.js.map +1 -0
  31. package/dist/compiler/template.js +1 -0
  32. package/dist/compiler/template.js.map +1 -0
  33. package/dist/compiler.js +66 -17
  34. package/dist/compiler.js.map +1 -0
  35. package/dist/component-errors.d.ts +18 -0
  36. package/dist/component-errors.js +65 -0
  37. package/dist/component-errors.js.map +1 -0
  38. package/dist/devtools-ui/index.js +1 -0
  39. package/dist/devtools-ui/index.js.map +1 -0
  40. package/dist/devtools.js +3 -4
  41. package/dist/devtools.js.map +1 -0
  42. package/dist/dom.d.ts +18 -5
  43. package/dist/dom.js +295 -90
  44. package/dist/dom.js.map +1 -0
  45. package/dist/error-observer.d.ts +6 -0
  46. package/dist/error-observer.js +41 -0
  47. package/dist/error-observer.js.map +1 -0
  48. package/dist/framework/check-app.d.ts +5 -0
  49. package/dist/framework/check-app.js +214 -0
  50. package/dist/framework/check-app.js.map +1 -0
  51. package/dist/framework/check-project.d.ts +4 -0
  52. package/dist/framework/check-project.js +42 -0
  53. package/dist/framework/check-project.js.map +1 -0
  54. package/dist/framework/client.d.ts +48 -0
  55. package/dist/framework/client.js +249 -0
  56. package/dist/framework/client.js.map +1 -0
  57. package/dist/framework/clients.d.ts +82 -0
  58. package/dist/framework/clients.js +190 -0
  59. package/dist/framework/clients.js.map +1 -0
  60. package/dist/framework/config-type.d.ts +10 -0
  61. package/dist/framework/config-type.js +4 -0
  62. package/dist/framework/config-type.js.map +1 -0
  63. package/dist/framework/config.d.ts +15 -0
  64. package/dist/framework/config.js +138 -0
  65. package/dist/framework/config.js.map +1 -0
  66. package/dist/framework/contracts-generate.d.ts +8 -0
  67. package/dist/framework/contracts-generate.js +290 -0
  68. package/dist/framework/contracts-generate.js.map +1 -0
  69. package/dist/framework/generate.d.ts +7 -0
  70. package/dist/framework/generate.js +67 -0
  71. package/dist/framework/generate.js.map +1 -0
  72. package/dist/framework/init.d.ts +2 -0
  73. package/dist/framework/init.js +183 -0
  74. package/dist/framework/init.js.map +1 -0
  75. package/dist/framework/middleware.d.ts +14 -0
  76. package/dist/framework/middleware.js +16 -0
  77. package/dist/framework/middleware.js.map +1 -0
  78. package/dist/framework/modules.d.ts +22 -0
  79. package/dist/framework/modules.js +29 -0
  80. package/dist/framework/modules.js.map +1 -0
  81. package/dist/framework/page-contracts-check.d.ts +8 -0
  82. package/dist/framework/page-contracts-check.js +110 -0
  83. package/dist/framework/page-contracts-check.js.map +1 -0
  84. package/dist/framework/page-contracts-generate.d.ts +2 -0
  85. package/dist/framework/page-contracts-generate.js +94 -0
  86. package/dist/framework/page-contracts-generate.js.map +1 -0
  87. package/dist/framework/page.d.ts +64 -0
  88. package/dist/framework/page.js +44 -0
  89. package/dist/framework/page.js.map +1 -0
  90. package/dist/framework/prerender.d.ts +14 -0
  91. package/dist/framework/prerender.js +110 -0
  92. package/dist/framework/prerender.js.map +1 -0
  93. package/dist/framework/project-templates.d.ts +3 -0
  94. package/dist/framework/project-templates.js +119 -0
  95. package/dist/framework/project-templates.js.map +1 -0
  96. package/dist/framework/project.d.ts +9 -0
  97. package/dist/framework/project.js +272 -0
  98. package/dist/framework/project.js.map +1 -0
  99. package/dist/framework/router.d.ts +41 -0
  100. package/dist/framework/router.js +259 -0
  101. package/dist/framework/router.js.map +1 -0
  102. package/dist/framework/server.d.ts +65 -0
  103. package/dist/framework/server.js +239 -0
  104. package/dist/framework/server.js.map +1 -0
  105. package/dist/framework/socket-contracts-generate.d.ts +5 -0
  106. package/dist/framework/socket-contracts-generate.js +162 -0
  107. package/dist/framework/socket-contracts-generate.js.map +1 -0
  108. package/dist/framework/socket.d.ts +72 -0
  109. package/dist/framework/socket.js +252 -0
  110. package/dist/framework/socket.js.map +1 -0
  111. package/dist/framework/standard-schema-types.d.ts +7 -0
  112. package/dist/framework/standard-schema-types.js +69 -0
  113. package/dist/framework/standard-schema-types.js.map +1 -0
  114. package/dist/framework/state.d.ts +22 -0
  115. package/dist/framework/state.js +136 -0
  116. package/dist/framework/state.js.map +1 -0
  117. package/dist/framework/styles.d.ts +2 -0
  118. package/dist/framework/styles.js +6 -0
  119. package/dist/framework/styles.js.map +1 -0
  120. package/dist/framework/type-declarations.d.ts +5 -0
  121. package/dist/framework/type-declarations.js +84 -0
  122. package/dist/framework/type-declarations.js.map +1 -0
  123. package/dist/framework-server/auto-clients.d.ts +3 -0
  124. package/dist/framework-server/auto-clients.js +27 -0
  125. package/dist/framework-server/auto-clients.js.map +1 -0
  126. package/dist/framework-server/context.d.ts +21 -0
  127. package/dist/framework-server/context.js +22 -0
  128. package/dist/framework-server/context.js.map +1 -0
  129. package/dist/framework-server/contracts.d.ts +73 -0
  130. package/dist/framework-server/contracts.js +184 -0
  131. package/dist/framework-server/contracts.js.map +1 -0
  132. package/dist/framework-server/discovery.d.ts +43 -0
  133. package/dist/framework-server/discovery.js +257 -0
  134. package/dist/framework-server/discovery.js.map +1 -0
  135. package/dist/framework-server/local.d.ts +21 -0
  136. package/dist/framework-server/local.js +100 -0
  137. package/dist/framework-server/local.js.map +1 -0
  138. package/dist/framework-server/middleware.d.ts +4 -0
  139. package/dist/framework-server/middleware.js +56 -0
  140. package/dist/framework-server/middleware.js.map +1 -0
  141. package/dist/framework-server/node-upgrade.d.ts +23 -0
  142. package/dist/framework-server/node-upgrade.js +96 -0
  143. package/dist/framework-server/node-upgrade.js.map +1 -0
  144. package/dist/framework-server/node-websocket.d.ts +16 -0
  145. package/dist/framework-server/node-websocket.js +127 -0
  146. package/dist/framework-server/node-websocket.js.map +1 -0
  147. package/dist/framework-server/openapi.d.ts +17 -0
  148. package/dist/framework-server/openapi.js +118 -0
  149. package/dist/framework-server/openapi.js.map +1 -0
  150. package/dist/framework-server/session-stores.d.ts +73 -0
  151. package/dist/framework-server/session-stores.js +122 -0
  152. package/dist/framework-server/session-stores.js.map +1 -0
  153. package/dist/framework-server/sessions.d.ts +70 -0
  154. package/dist/framework-server/sessions.js +167 -0
  155. package/dist/framework-server/sessions.js.map +1 -0
  156. package/dist/framework-server/socket.d.ts +83 -0
  157. package/dist/framework-server/socket.js +196 -0
  158. package/dist/framework-server/socket.js.map +1 -0
  159. package/dist/framework-server.d.ts +23 -0
  160. package/dist/framework-server.js +13 -0
  161. package/dist/framework-server.js.map +1 -0
  162. package/dist/framework.d.ts +31 -0
  163. package/dist/framework.js +14 -0
  164. package/dist/framework.js.map +1 -0
  165. package/dist/hmr.js +75 -24
  166. package/dist/hmr.js.map +1 -0
  167. package/dist/index.d.ts +5 -3
  168. package/dist/index.js +3 -1
  169. package/dist/index.js.map +1 -0
  170. package/dist/init.js +31 -3
  171. package/dist/init.js.map +1 -0
  172. package/dist/internal.d.ts +2 -2
  173. package/dist/internal.js +3 -2
  174. package/dist/internal.js.map +1 -0
  175. package/dist/node.d.ts +16 -0
  176. package/dist/node.js +122 -0
  177. package/dist/node.js.map +1 -0
  178. package/dist/reactivity.d.ts +22 -1
  179. package/dist/reactivity.js +132 -18
  180. package/dist/reactivity.js.map +1 -0
  181. package/dist/server.js +1 -0
  182. package/dist/server.js.map +1 -0
  183. package/dist/types.d.ts +2 -0
  184. package/dist/types.js +26 -9
  185. package/dist/types.js.map +1 -0
  186. package/dist/vite.js +112 -7
  187. package/dist/vite.js.map +1 -0
  188. package/package.json +15 -4
@@ -0,0 +1,249 @@
1
+ import { createAppErrorChannel, provideAppErrorChannel } from "../component-errors.js";
2
+ import { finishWithCleanup, signal } from "../reactivity.js";
3
+ import { pageSearchObject, validatePageInputs } from "./page.js";
4
+ import { runRouteMiddleware } from "./middleware.js";
5
+ import { createNavigator, matchRoute, reportNavigationError } from "./router.js";
6
+ import { hydrateWithStateStore, StateStore, withStateStore } from "./state.js";
7
+ function isRecord(value) {
8
+ return typeof value === "object" && value !== null && !Array.isArray(value);
9
+ }
10
+ function readPayload(value) {
11
+ const parsed = typeof value === "string" ? JSON.parse(value) : value;
12
+ if (!isRecord(parsed) || typeof parsed.route !== "string" || !isRecord(parsed.props) || !isRecord(parsed.state)) {
13
+ throw new TypeError("Invalid Meeko hydration payload");
14
+ }
15
+ if (!isRecord(parsed.props.params) || !isRecord(parsed.props.search))
16
+ throw new TypeError("Invalid Meeko route props");
17
+ if (parsed.sharedState !== undefined && !isRecord(parsed.sharedState))
18
+ throw new TypeError("Invalid Meeko shared state");
19
+ return { route: parsed.route, props: parsed.props, state: parsed.state, sharedState: parsed.sharedState ?? {} };
20
+ }
21
+ function applyCsrfToken(browser, token) {
22
+ const meta = browser.document.querySelector('meta[name="meeko-csrf-token"]');
23
+ const previous = meta?.getAttribute("content") ?? null;
24
+ let created;
25
+ if (token && meta)
26
+ meta.content = token;
27
+ else if (token) {
28
+ created = browser.document.createElement("meta");
29
+ created.name = "meeko-csrf-token";
30
+ created.content = token;
31
+ browser.document.head.append(created);
32
+ }
33
+ else
34
+ meta?.remove();
35
+ return () => {
36
+ if (meta) {
37
+ if (!meta.isConnected)
38
+ browser.document.head.append(meta);
39
+ if (previous === null)
40
+ meta.removeAttribute("content");
41
+ else
42
+ meta.setAttribute("content", previous);
43
+ }
44
+ else
45
+ created?.remove();
46
+ };
47
+ }
48
+ function bind(component, props) {
49
+ return {
50
+ renderWithState: () => component.renderWithState(props),
51
+ renderToString: () => component.renderToString(props),
52
+ hydrateScope: (scope, _unused, state) => component.hydrateScope(scope, props, state),
53
+ };
54
+ }
55
+ async function createTree(route, props, loadPage, fromLayout) {
56
+ let component = bind(await loadPage(route.file), props);
57
+ const layouts = [];
58
+ for (let index = route.layouts.length - 1; index >= fromLayout; index--) {
59
+ const file = route.layouts[index];
60
+ const outlet = signal(component);
61
+ const layoutProps = Object.defineProperty({}, "outlet", {
62
+ enumerable: true,
63
+ get: () => outlet.value,
64
+ });
65
+ component = bind(await loadPage(file), layoutProps);
66
+ layouts.unshift({ file, outlet });
67
+ }
68
+ return { component, layouts };
69
+ }
70
+ /**
71
+ * Hydrates the SSR tree and updates only the first changed outlet on navigation.
72
+ * Layout templates render their outlet with <component is="props.outlet"/>.
73
+ */
74
+ export async function mountClientApp(options) {
75
+ const browser = options.browser ?? window;
76
+ const payload = readPayload(options.payload);
77
+ const initial = matchRoute(options.routes, browser.location.pathname);
78
+ if (!initial || initial.route.id !== payload.route)
79
+ throw new Error("Meeko route hydration mismatch");
80
+ if (JSON.stringify(initial.params) !== JSON.stringify(payload.props.params))
81
+ throw new Error("Meeko route parameters do not match SSR");
82
+ const stateStore = new StateStore(payload.sharedState);
83
+ const errorChannel = createAppErrorChannel();
84
+ const observeNavigationError = options.onNavigationError ?? ((error) => {
85
+ const handler = errorChannel.current();
86
+ if (handler)
87
+ return handler(error);
88
+ reportNavigationError(browser, error);
89
+ });
90
+ const hydrateApp = (hydrate) => hydrateWithStateStore(stateStore, () => {
91
+ provideAppErrorChannel(errorChannel);
92
+ return hydrate();
93
+ });
94
+ const first = await createTree(initial.route, payload.props, options.loadPage, 0);
95
+ let layouts = first.layouts;
96
+ let release = hydrateApp(() => first.component.hydrateScope({ root: options.root }, {}, payload.state));
97
+ let disposed = false;
98
+ let stableUrl = browser.location.href;
99
+ const recoverCommitFailure = (error) => {
100
+ // A failed outlet update or hydration can leave live scopes attached to a
101
+ // partially replaced tree. Recreate the last committed route with SSR.
102
+ try {
103
+ browser.location.replace(stableUrl);
104
+ }
105
+ catch (recoveryError) {
106
+ throw new AggregateError([error, recoveryError], "Meeko navigation failed and could not restore the previous route");
107
+ }
108
+ throw error;
109
+ };
110
+ const navigator = createNavigator(options.routes, async (context) => {
111
+ if (options.loadMiddleware) {
112
+ const response = await runRouteMiddleware(await options.loadMiddleware(), {
113
+ url: context.url, match: context.match, signal: context.signal, phase: "client",
114
+ });
115
+ if (context.signal.aborted || disposed)
116
+ return false;
117
+ if (response) {
118
+ const location = response.headers.get("location");
119
+ if (response.status >= 300 && response.status < 400 && location) {
120
+ const target = new URL(location, context.url);
121
+ if (target.href === context.url.href)
122
+ throw new Error("Route middleware redirected to the same URL");
123
+ browser.location.assign(target.href);
124
+ }
125
+ else
126
+ reportNavigationError(browser, new Error(`Route middleware blocked navigation: HTTP ${response.status}`), observeNavigationError);
127
+ return false;
128
+ }
129
+ }
130
+ let props;
131
+ let serverSharedState;
132
+ let serverCsrfToken = null;
133
+ let loaderDraft;
134
+ if (options.serverData && !options.loadRoute) {
135
+ const response = await (options.fetch ?? fetch)(context.url.href, {
136
+ headers: { accept: "application/meeko+json" }, credentials: "same-origin", signal: context.signal,
137
+ });
138
+ if (!response.ok)
139
+ throw new Error(`Route data request failed: HTTP ${response.status}`);
140
+ serverCsrfToken = response.headers.get("x-meeko-csrf-token");
141
+ const payload = readPayload(await response.text());
142
+ if (payload.route !== context.match.route.id)
143
+ throw new Error("Meeko route data mismatch");
144
+ if (context.signal.aborted || disposed)
145
+ return;
146
+ serverSharedState = payload.sharedState;
147
+ props = payload.props;
148
+ }
149
+ else {
150
+ const sidecar = context.match.route.sidecar && options.loadRoute
151
+ ? await options.loadRoute(context.match.route.sidecar)
152
+ : undefined;
153
+ const validated = await validatePageInputs(sidecar, context.match.params, pageSearchObject(context.url.searchParams));
154
+ loaderDraft = sidecar?.load ? stateStore.navigationDraft() : undefined;
155
+ const data = sidecar?.load ? await sidecar.load({ ...context, ...validated, state: loaderDraft.state }) : undefined;
156
+ props = {
157
+ params: validated.params,
158
+ search: validated.search,
159
+ ...(data === undefined ? {} : { data }),
160
+ };
161
+ }
162
+ if (context.signal.aborted || disposed)
163
+ return;
164
+ const retained = Math.min(context.retainedLayouts, layouts.length);
165
+ const next = await createTree(context.match.route, props, options.loadPage, retained);
166
+ if (context.signal.aborted || disposed)
167
+ return;
168
+ const commit = () => {
169
+ if (retained) {
170
+ try {
171
+ withStateStore(stateStore, () => { layouts[retained - 1].outlet.value = next.component; });
172
+ }
173
+ catch (error) {
174
+ recoverCommitFailure(error);
175
+ }
176
+ layouts = [...layouts.slice(0, retained), ...next.layouts];
177
+ stableUrl = context.url.href;
178
+ return;
179
+ }
180
+ const rendered = withStateStore(stateStore, () => next.component.renderWithState({}));
181
+ try {
182
+ release();
183
+ options.root.innerHTML = rendered.html;
184
+ release = hydrateApp(() => next.component.hydrateScope({ root: options.root }, {}, rendered.state));
185
+ }
186
+ catch (error) {
187
+ recoverCommitFailure(error);
188
+ }
189
+ layouts = next.layouts;
190
+ stableUrl = context.url.href;
191
+ };
192
+ const commitWithToken = () => {
193
+ const restoreToken = serverCsrfToken === null ? undefined : applyCsrfToken(browser, serverCsrfToken);
194
+ try {
195
+ commit();
196
+ }
197
+ catch (error) {
198
+ try {
199
+ restoreToken?.();
200
+ }
201
+ catch (restoreError) {
202
+ throw new AggregateError([error, restoreError], "Meeko navigation and CSRF recovery failed");
203
+ }
204
+ throw error;
205
+ }
206
+ };
207
+ if (serverSharedState)
208
+ stateStore.seedForNavigation(serverSharedState, commitWithToken);
209
+ else if (loaderDraft)
210
+ loaderDraft.commit(commitWithToken);
211
+ else
212
+ commitWithToken();
213
+ }, browser, observeNavigationError);
214
+ const onClick = (event) => {
215
+ if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey)
216
+ return;
217
+ const target = event.target;
218
+ if (!target || !("closest" in target) || typeof target.closest !== "function")
219
+ return;
220
+ const anchor = target.closest("a[href]");
221
+ if (!anchor || anchor.hasAttribute("download") || (anchor.target && anchor.target !== "_self"))
222
+ return;
223
+ let url;
224
+ try {
225
+ url = new URL(anchor.href, browser.location.href);
226
+ }
227
+ catch {
228
+ return;
229
+ }
230
+ if (url.origin !== browser.location.origin || !matchRoute(options.routes, url.pathname))
231
+ return;
232
+ event.preventDefault();
233
+ void navigator.navigate(url.href).catch((error) => reportNavigationError(browser, error, observeNavigationError));
234
+ };
235
+ browser.document.addEventListener("click", onClick);
236
+ return {
237
+ navigate: navigator.navigate,
238
+ state: stateStore,
239
+ dispose() {
240
+ if (disposed)
241
+ return;
242
+ disposed = true;
243
+ navigator.dispose();
244
+ browser.document.removeEventListener("click", onClick);
245
+ finishWithCleanup(release, () => errorChannel.clear());
246
+ },
247
+ };
248
+ }
249
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/framework/client.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Component, DomScope } from \"../dom.js\";\nimport { createAppErrorChannel, provideAppErrorChannel } from \"../component-errors.js\";\nimport { finishWithCleanup, signal } from \"../reactivity.js\";\nimport type { Signal } from \"../reactivity.js\";\nimport { pageSearchObject, validatePageInputs } from \"./page.js\";\nimport type { PageSchema } from \"./page.js\";\nimport { runRouteMiddleware } from \"./middleware.js\";\nimport type { RouteMiddleware } from \"./middleware.js\";\nimport { createNavigator, matchRoute, reportNavigationError } from \"./router.js\";\nimport type { NavigationContext, Navigator, RouteRecord } from \"./router.js\";\nimport { hydrateWithStateStore, StateStore, withStateStore } from \"./state.js\";\n\n/** The public shape emitted by the .meeko compiler. */\nexport interface ClientComponent {\n renderWithState(props: Record<string, unknown>): { html: string; state: Record<string, unknown> };\n renderToString(props: Record<string, unknown>, state?: Record<string, unknown>): string;\n hydrateScope(scope: DomScope, props: Record<string, unknown>, state?: Record<string, unknown>): () => void;\n}\n\nexport interface ClientRoute {\n /** Client-safe loader. Server-only sidecars must not be passed to loadRoute. */\n params?: PageSchema;\n search?: PageSchema;\n load?: (context: NavigationContext & {\n params: Readonly<Record<string, unknown>>;\n search: Readonly<Record<string, unknown>>;\n state: StateStore;\n }) => Promise<unknown> | unknown;\n}\n\nexport interface ClientAppOptions {\n readonly routes: readonly RouteRecord[];\n readonly root: Element;\n readonly payload: string | unknown;\n readonly loadPage: (file: string) => Promise<ClientComponent>;\n readonly loadRoute?: (file: string) => Promise<ClientRoute>;\n /** Runs the same route guards as SSR before a browser navigation fetch. */\n readonly loadMiddleware?: () => Promise<readonly RouteMiddleware[]>;\n /** Fetches public loader data from the SSR handler during browser navigation. */\n readonly serverData?: boolean;\n readonly fetch?: typeof fetch;\n readonly onNavigationError?: (error: unknown) => void;\n readonly browser?: Window;\n}\n\nexport interface ClientApp {\n navigate: Navigator[\"navigate\"];\n readonly state: StateStore;\n dispose(): void;\n}\n\ninterface HydrationPayload {\n route: string;\n props: Record<string, unknown>;\n state: Record<string, unknown>;\n sharedState: Record<string, unknown>;\n}\n\ninterface LayoutInstance {\n file: string;\n outlet: Signal<Component<Record<string, unknown>>>;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction readPayload(value: unknown): HydrationPayload {\n const parsed: unknown = typeof value === \"string\" ? JSON.parse(value) : value;\n if (!isRecord(parsed) || typeof parsed.route !== \"string\" || !isRecord(parsed.props) || !isRecord(parsed.state)) {\n throw new TypeError(\"Invalid Meeko hydration payload\");\n }\n if (!isRecord(parsed.props.params) || !isRecord(parsed.props.search)) throw new TypeError(\"Invalid Meeko route props\");\n if (parsed.sharedState !== undefined && !isRecord(parsed.sharedState)) throw new TypeError(\"Invalid Meeko shared state\");\n return { route: parsed.route, props: parsed.props, state: parsed.state, sharedState: parsed.sharedState ?? {} };\n}\n\nfunction applyCsrfToken(browser: Window, token: string): () => void {\n const meta = browser.document.querySelector<HTMLMetaElement>('meta[name=\"meeko-csrf-token\"]');\n const previous = meta?.getAttribute(\"content\") ?? null;\n let created: HTMLMetaElement | undefined;\n if (token && meta) meta.content = token;\n else if (token) {\n created = browser.document.createElement(\"meta\");\n created.name = \"meeko-csrf-token\";\n created.content = token;\n browser.document.head.append(created);\n } else meta?.remove();\n return () => {\n if (meta) {\n if (!meta.isConnected) browser.document.head.append(meta);\n if (previous === null) meta.removeAttribute(\"content\");\n else meta.setAttribute(\"content\", previous);\n } else created?.remove();\n };\n}\n\nfunction bind(component: ClientComponent, props: Record<string, unknown>): Component<Record<string, unknown>> {\n return {\n renderWithState: () => component.renderWithState(props),\n renderToString: () => component.renderToString(props),\n hydrateScope: (scope, _unused, state) => component.hydrateScope(scope, props, state),\n };\n}\n\nasync function createTree(\n route: RouteRecord,\n props: Record<string, unknown>,\n loadPage: ClientAppOptions[\"loadPage\"],\n fromLayout: number,\n): Promise<{ component: Component<Record<string, unknown>>; layouts: LayoutInstance[] }> {\n let component = bind(await loadPage(route.file), props);\n const layouts: LayoutInstance[] = [];\n for (let index = route.layouts.length - 1; index >= fromLayout; index--) {\n const file = route.layouts[index]!;\n const outlet = signal(component);\n const layoutProps = Object.defineProperty({}, \"outlet\", {\n enumerable: true,\n get: () => outlet.value,\n }) as Record<string, unknown>;\n component = bind(await loadPage(file), layoutProps);\n layouts.unshift({ file, outlet });\n }\n return { component, layouts };\n}\n\n/**\n * Hydrates the SSR tree and updates only the first changed outlet on navigation.\n * Layout templates render their outlet with <component is=\"props.outlet\"/>.\n */\nexport async function mountClientApp(options: ClientAppOptions): Promise<ClientApp> {\n const browser = options.browser ?? window;\n const payload = readPayload(options.payload);\n const initial = matchRoute(options.routes, browser.location.pathname);\n if (!initial || initial.route.id !== payload.route) throw new Error(\"Meeko route hydration mismatch\");\n if (JSON.stringify(initial.params) !== JSON.stringify(payload.props.params)) throw new Error(\"Meeko route parameters do not match SSR\");\n const stateStore = new StateStore(payload.sharedState);\n const errorChannel = createAppErrorChannel();\n const observeNavigationError = options.onNavigationError ?? ((error: unknown) => {\n const handler = errorChannel.current();\n if (handler) return handler(error);\n reportNavigationError(browser, error);\n });\n const hydrateApp = (hydrate: () => () => void) => hydrateWithStateStore(stateStore, () => {\n provideAppErrorChannel(errorChannel);\n return hydrate();\n });\n const first = await createTree(initial.route, payload.props, options.loadPage, 0);\n let layouts = first.layouts;\n let release = hydrateApp(() => first.component.hydrateScope({ root: options.root }, {}, payload.state));\n let disposed = false;\n let stableUrl = browser.location.href;\n const recoverCommitFailure = (error: unknown): never => {\n // A failed outlet update or hydration can leave live scopes attached to a\n // partially replaced tree. Recreate the last committed route with SSR.\n try {\n browser.location.replace(stableUrl);\n } catch (recoveryError) {\n throw new AggregateError([error, recoveryError], \"Meeko navigation failed and could not restore the previous route\");\n }\n throw error;\n };\n const navigator = createNavigator(options.routes, async (context) => {\n if (options.loadMiddleware) {\n const response = await runRouteMiddleware(await options.loadMiddleware(), {\n url: context.url, match: context.match, signal: context.signal, phase: \"client\",\n });\n if (context.signal.aborted || disposed) return false;\n if (response) {\n const location = response.headers.get(\"location\");\n if (response.status >= 300 && response.status < 400 && location) {\n const target = new URL(location, context.url);\n if (target.href === context.url.href) throw new Error(\"Route middleware redirected to the same URL\");\n browser.location.assign(target.href);\n } else reportNavigationError(browser, new Error(`Route middleware blocked navigation: HTTP ${response.status}`), observeNavigationError);\n return false;\n }\n }\n let props: Record<string, unknown>;\n let serverSharedState: Record<string, unknown> | undefined;\n let serverCsrfToken: string | null = null;\n let loaderDraft: ReturnType<StateStore[\"navigationDraft\"]> | undefined;\n if (options.serverData && !options.loadRoute) {\n const response = await (options.fetch ?? fetch)(context.url.href, {\n headers: { accept: \"application/meeko+json\" }, credentials: \"same-origin\", signal: context.signal,\n });\n if (!response.ok) throw new Error(`Route data request failed: HTTP ${response.status}`);\n serverCsrfToken = response.headers.get(\"x-meeko-csrf-token\");\n const payload = readPayload(await response.text());\n if (payload.route !== context.match.route.id) throw new Error(\"Meeko route data mismatch\");\n if (context.signal.aborted || disposed) return;\n serverSharedState = payload.sharedState;\n props = payload.props;\n } else {\n const sidecar = context.match.route.sidecar && options.loadRoute\n ? await options.loadRoute(context.match.route.sidecar)\n : undefined;\n const validated = await validatePageInputs(sidecar, context.match.params, pageSearchObject(context.url.searchParams));\n loaderDraft = sidecar?.load ? stateStore.navigationDraft() : undefined;\n const data = sidecar?.load ? await sidecar.load({ ...context, ...validated, state: loaderDraft!.state }) : undefined;\n props = {\n params: validated.params,\n search: validated.search,\n ...(data === undefined ? {} : { data }),\n };\n }\n if (context.signal.aborted || disposed) return;\n const retained = Math.min(context.retainedLayouts, layouts.length);\n const next = await createTree(context.match.route, props, options.loadPage, retained);\n if (context.signal.aborted || disposed) return;\n const commit = () => {\n if (retained) {\n try {\n withStateStore(stateStore, () => { layouts[retained - 1]!.outlet.value = next.component; });\n } catch (error) {\n recoverCommitFailure(error);\n }\n layouts = [...layouts.slice(0, retained), ...next.layouts];\n stableUrl = context.url.href;\n return;\n }\n const rendered = withStateStore(stateStore, () => next.component.renderWithState({}));\n try {\n release();\n options.root.innerHTML = rendered.html;\n release = hydrateApp(() => next.component.hydrateScope({ root: options.root }, {}, rendered.state));\n } catch (error) {\n recoverCommitFailure(error);\n }\n layouts = next.layouts;\n stableUrl = context.url.href;\n };\n const commitWithToken = () => {\n const restoreToken = serverCsrfToken === null ? undefined : applyCsrfToken(browser, serverCsrfToken);\n try { commit(); }\n catch (error) {\n try { restoreToken?.(); }\n catch (restoreError) { throw new AggregateError([error, restoreError], \"Meeko navigation and CSRF recovery failed\"); }\n throw error;\n }\n };\n if (serverSharedState) stateStore.seedForNavigation(serverSharedState, commitWithToken);\n else if (loaderDraft) loaderDraft.commit(commitWithToken);\n else commitWithToken();\n }, browser, observeNavigationError);\n const onClick = (event: MouseEvent) => {\n if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;\n const target = event.target;\n if (!target || !(\"closest\" in target) || typeof target.closest !== \"function\") return;\n const anchor = target.closest(\"a[href]\") as HTMLAnchorElement | null;\n if (!anchor || anchor.hasAttribute(\"download\") || (anchor.target && anchor.target !== \"_self\")) return;\n let url: URL;\n try { url = new URL(anchor.href, browser.location.href); }\n catch { return; }\n if (url.origin !== browser.location.origin || !matchRoute(options.routes, url.pathname)) return;\n event.preventDefault();\n void navigator.navigate(url.href).catch((error: unknown) => reportNavigationError(browser, error, observeNavigationError));\n };\n browser.document.addEventListener(\"click\", onClick);\n return {\n navigate: navigator.navigate,\n state: stateStore,\n dispose() {\n if (disposed) return;\n disposed = true;\n navigator.dispose();\n browser.document.removeEventListener(\"click\", onClick);\n finishWithCleanup(release, () => errorChannel.clear());\n },\n };\n}\n"]}
@@ -0,0 +1,82 @@
1
+ /** Public descriptors intentionally omit handler files and server schemas. */
2
+ export interface PublicApiEndpoint {
3
+ readonly clientKey: string;
4
+ readonly pathname: string;
5
+ readonly method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
6
+ readonly contentType?: "json" | "response";
7
+ }
8
+ export interface PublicRpcEndpoint {
9
+ readonly id: string;
10
+ readonly pathname: string;
11
+ }
12
+ export interface PublicServerManifest {
13
+ readonly api: readonly PublicApiEndpoint[];
14
+ readonly rpc: readonly PublicRpcEndpoint[];
15
+ }
16
+ /** Strips private handler paths before serializing a discovered server manifest. */
17
+ export declare function createPublicServerManifest(manifest: PublicServerManifest): PublicServerManifest;
18
+ /** Type-only operation declarations can be inferred from public shared schemas. */
19
+ export interface ApiOperation<Params = undefined, Query = undefined, Body = undefined, Output = unknown> {
20
+ readonly params: Params;
21
+ readonly query: Query;
22
+ readonly body: Body;
23
+ readonly output: Output;
24
+ }
25
+ export interface RpcOperation<Input = unknown, Output = unknown> {
26
+ readonly input: Input;
27
+ readonly output: Output;
28
+ }
29
+ type AnyApiOperation = ApiOperation<unknown, unknown, unknown, unknown>;
30
+ type RequestOptions = {
31
+ readonly signal?: AbortSignal;
32
+ };
33
+ type ParamOption<T> = T extends undefined ? {
34
+ readonly params?: never;
35
+ } : {
36
+ readonly params: T;
37
+ };
38
+ type QueryOption<T> = T extends undefined ? {
39
+ readonly query?: never;
40
+ } : {
41
+ readonly query: T;
42
+ };
43
+ type BodyOption<T> = T extends undefined ? {
44
+ readonly body?: never;
45
+ } : {
46
+ readonly body: T;
47
+ };
48
+ type ApiArguments<O extends AnyApiOperation> = O["params"] extends undefined ? O["query"] extends undefined ? O["body"] extends undefined ? [options?: ParamOption<O["params"]> & QueryOption<O["query"]> & BodyOption<O["body"]> & RequestOptions] : [options: ParamOption<O["params"]> & QueryOption<O["query"]> & BodyOption<O["body"]> & RequestOptions] : [options: ParamOption<O["params"]> & QueryOption<O["query"]> & BodyOption<O["body"]> & RequestOptions] : [options: ParamOption<O["params"]> & QueryOption<O["query"]> & BodyOption<O["body"]> & RequestOptions];
49
+ type Nest<Path extends string, Value> = Path extends `${infer Head}.${infer Tail}` ? {
50
+ [K in Head]: Nest<Tail, Value>;
51
+ } : {
52
+ [K in Path]: Value;
53
+ };
54
+ type Intersection<Union> = (Union extends unknown ? (value: Union) => void : never) extends (value: infer Result) => void ? Result : never;
55
+ type ApiMethods<Operations> = {
56
+ [Method in keyof Operations]: Operations[Method] extends AnyApiOperation ? (...args: ApiArguments<Operations[Method]>) => Promise<Operations[Method]["output"]> : never;
57
+ };
58
+ export type ApiClient<Contract extends Record<string, Record<string, AnyApiOperation>>> = Intersection<{
59
+ [Key in keyof Contract & string]: Nest<Key, ApiMethods<Contract[Key]>>;
60
+ }[keyof Contract & string]>;
61
+ export type RpcClient<Contract extends Record<string, RpcOperation>> = Intersection<{
62
+ [Key in keyof Contract & string]: Nest<Key, (input: Contract[Key]["input"], options?: RequestOptions) => Promise<Contract[Key]["output"]>>;
63
+ }[keyof Contract & string]>;
64
+ export declare class ClientError extends Error {
65
+ readonly code: string;
66
+ readonly status: number;
67
+ readonly requestId?: string | undefined;
68
+ constructor(code: string, status: number, requestId?: string | undefined);
69
+ }
70
+ export interface ClientOptions {
71
+ readonly baseUrl?: string | (() => string);
72
+ readonly fetch?: typeof fetch;
73
+ readonly csrfToken?: string | (() => string | undefined);
74
+ readonly headers?: HeadersInit | (() => HeadersInit);
75
+ }
76
+ /** Reads the current document token at call time, including after client navigation. */
77
+ export declare function createBrowserClientOptions(): ClientOptions;
78
+ /** Creates browser API methods from public endpoint paths, without server imports. */
79
+ export declare function createApiClient<Contract extends Record<string, Record<string, AnyApiOperation>>>(manifest: Pick<PublicServerManifest, "api">, options?: ClientOptions): ApiClient<Contract>;
80
+ /** Creates browser RPC procedures from public endpoint paths. */
81
+ export declare function createRpcClient<Contract extends Record<string, RpcOperation>>(manifest: Pick<PublicServerManifest, "rpc">, options?: ClientOptions): RpcClient<Contract>;
82
+ export {};
@@ -0,0 +1,190 @@
1
+ /** Strips private handler paths before serializing a discovered server manifest. */
2
+ export function createPublicServerManifest(manifest) {
3
+ return {
4
+ api: manifest.api.map(({ clientKey, pathname, method, contentType }) => ({
5
+ clientKey, pathname, method, ...(contentType ? { contentType } : {}),
6
+ })),
7
+ rpc: manifest.rpc.map(({ id, pathname }) => ({ id, pathname })),
8
+ };
9
+ }
10
+ export class ClientError extends Error {
11
+ code;
12
+ status;
13
+ requestId;
14
+ constructor(code, status, requestId) {
15
+ super(code);
16
+ this.code = code;
17
+ this.status = status;
18
+ this.requestId = requestId;
19
+ this.name = "ClientError";
20
+ }
21
+ }
22
+ /** Reads the current document token at call time, including after client navigation. */
23
+ export function createBrowserClientOptions() {
24
+ const currentCsrfToken = () => typeof document === "undefined"
25
+ ? undefined
26
+ : document.querySelector('meta[name="meeko-csrf-token"]')?.getAttribute("content") ?? undefined;
27
+ return {
28
+ csrfToken: currentCsrfToken,
29
+ fetch: async (input, init) => {
30
+ const sourceDocument = typeof document === "undefined" ? undefined : document;
31
+ const csrfTokenAtStart = currentCsrfToken();
32
+ const response = await fetch(input, init);
33
+ const token = response.headers.get("x-meeko-csrf-token");
34
+ // Navigation or a newer response may have rotated or cleared the token.
35
+ if (token !== null && sourceDocument && document === sourceDocument && currentCsrfToken() === csrfTokenAtStart) {
36
+ let meta = document.querySelector('meta[name="meeko-csrf-token"]');
37
+ if (!token) {
38
+ meta?.remove();
39
+ return response;
40
+ }
41
+ if (!meta) {
42
+ meta = document.createElement("meta");
43
+ meta.setAttribute("name", "meeko-csrf-token");
44
+ document.head.append(meta);
45
+ }
46
+ meta.setAttribute("content", token);
47
+ }
48
+ return response;
49
+ },
50
+ };
51
+ }
52
+ function pathWithParams(pathname, params = {}) {
53
+ const used = new Set();
54
+ const path = pathname.replace(/\[(\.\.\.)?([A-Za-z_$][\w$]*)\]/g, (_match, rest, name) => {
55
+ const value = params[name];
56
+ if (!value)
57
+ throw new TypeError(`Missing route parameter: ${name}`);
58
+ used.add(name);
59
+ const parts = rest ? value.split("/") : [value];
60
+ if (parts.some((part) => !part || part === "." || part === ".." || part.includes("/") || part.includes("\\")))
61
+ throw new TypeError(`Invalid route parameter: ${name}`);
62
+ return parts.map(encodeURIComponent).join("/");
63
+ });
64
+ for (const key of Object.keys(params))
65
+ if (!used.has(key))
66
+ throw new TypeError(`Unknown route parameter: ${key}`);
67
+ return path;
68
+ }
69
+ function queryString(query) {
70
+ if (!query)
71
+ return "";
72
+ const search = new URLSearchParams();
73
+ for (const [key, raw] of Object.entries(query)) {
74
+ for (const value of Array.isArray(raw) ? raw : [raw]) {
75
+ if (value !== null && value !== undefined)
76
+ search.append(key, String(value));
77
+ }
78
+ }
79
+ const result = search.toString();
80
+ return result ? `?${result}` : "";
81
+ }
82
+ async function responseValue(response, contentType = "json") {
83
+ if (!response.ok) {
84
+ let payload;
85
+ try {
86
+ payload = await response.json();
87
+ }
88
+ catch { /* Bad error bodies still produce a normalized error. */ }
89
+ const record = payload && typeof payload === "object" ? payload : {};
90
+ const code = typeof record.code === "string" ? record.code : "HTTP_ERROR";
91
+ const requestId = typeof record.requestId === "string" ? record.requestId : response.headers.get("x-request-id") ?? undefined;
92
+ throw new ClientError(code, response.status, requestId);
93
+ }
94
+ if (contentType === "response")
95
+ return response;
96
+ if (response.status === 204)
97
+ return undefined;
98
+ try {
99
+ return await response.json();
100
+ }
101
+ catch {
102
+ throw new ClientError("INVALID_RESPONSE", response.status, response.headers.get("x-request-id") ?? undefined);
103
+ }
104
+ }
105
+ function endpointUrl(pathname, options) {
106
+ const baseUrl = typeof options.baseUrl === "function" ? options.baseUrl() : options.baseUrl;
107
+ return baseUrl ? new URL(pathname, baseUrl).toString() : pathname;
108
+ }
109
+ function headersFor(options, method, json) {
110
+ const headers = new Headers(typeof options.headers === "function" ? options.headers() : options.headers);
111
+ if (json)
112
+ headers.set("content-type", "application/json");
113
+ if (method !== "GET" && method !== "HEAD") {
114
+ const csrf = typeof options.csrfToken === "function" ? options.csrfToken() : options.csrfToken;
115
+ if (csrf)
116
+ headers.set("x-meeko-csrf", csrf);
117
+ }
118
+ return headers;
119
+ }
120
+ function insert(root, key, value) {
121
+ const parts = key.split(".");
122
+ if (parts.some((part) => !/^[A-Za-z_$][\w$]*$/.test(part)))
123
+ throw new TypeError(`Invalid client key: ${key}`);
124
+ let node = root;
125
+ for (const part of parts.slice(0, -1)) {
126
+ const existing = node[part];
127
+ if (existing === undefined)
128
+ node[part] = Object.create(null);
129
+ else if (!existing || typeof existing !== "object")
130
+ throw new TypeError(`Client key collision: ${key}`);
131
+ node = node[part];
132
+ }
133
+ const last = parts.at(-1);
134
+ if (node[last] !== undefined)
135
+ throw new TypeError(`Client key collision: ${key}`);
136
+ node[last] = value;
137
+ }
138
+ function ensureObject(root, key) {
139
+ const parts = key.split(".");
140
+ if (parts.some((part) => !/^[A-Za-z_$][\w$]*$/.test(part)))
141
+ throw new TypeError(`Invalid client key: ${key}`);
142
+ let node = root;
143
+ for (const part of parts) {
144
+ const existing = node[part];
145
+ if (existing === undefined)
146
+ node[part] = Object.create(null);
147
+ else if (!existing || typeof existing !== "object")
148
+ throw new TypeError(`Client key collision: ${key}`);
149
+ node = node[part];
150
+ }
151
+ return node;
152
+ }
153
+ /** Creates browser API methods from public endpoint paths, without server imports. */
154
+ export function createApiClient(manifest, options = {}) {
155
+ const root = Object.create(null);
156
+ for (const endpoint of manifest.api) {
157
+ const methods = ensureObject(root, endpoint.clientKey);
158
+ const method = endpoint.method.toLowerCase();
159
+ if (methods[method])
160
+ throw new TypeError(`Duplicate API method: ${endpoint.clientKey}.${method}`);
161
+ methods[method] = async (input = {}) => {
162
+ const path = pathWithParams(endpoint.pathname, input.params) + queryString(input.query);
163
+ const url = endpointUrl(path, options);
164
+ const fetcher = options.fetch ?? fetch;
165
+ const response = await fetcher(url, {
166
+ method: endpoint.method, headers: headersFor(options, endpoint.method, input.body !== undefined),
167
+ credentials: "same-origin", ...(input.body === undefined ? {} : { body: JSON.stringify(input.body) }),
168
+ ...(input.signal ? { signal: input.signal } : {}),
169
+ });
170
+ return responseValue(response, endpoint.contentType);
171
+ };
172
+ }
173
+ return root;
174
+ }
175
+ /** Creates browser RPC procedures from public endpoint paths. */
176
+ export function createRpcClient(manifest, options = {}) {
177
+ const root = Object.create(null);
178
+ for (const endpoint of manifest.rpc) {
179
+ insert(root, endpoint.id, async (input, request = {}) => {
180
+ const fetcher = options.fetch ?? fetch;
181
+ const response = await fetcher(endpointUrl(endpoint.pathname, options), {
182
+ method: "POST", headers: headersFor(options, "POST", true), credentials: "same-origin",
183
+ body: JSON.stringify(input), ...(request.signal ? { signal: request.signal } : {}),
184
+ });
185
+ return responseValue(response);
186
+ });
187
+ }
188
+ return root;
189
+ }
190
+ //# sourceMappingURL=clients.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clients.js","sourceRoot":"","sources":["../../src/framework/clients.ts"],"names":[],"mappings":"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","sourcesContent":["/** Public descriptors intentionally omit handler files and server schemas. */\nexport interface PublicApiEndpoint {\n readonly clientKey: string;\n readonly pathname: string;\n readonly method: \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\";\n readonly contentType?: \"json\" | \"response\";\n}\n\nexport interface PublicRpcEndpoint {\n readonly id: string;\n readonly pathname: string;\n}\n\nexport interface PublicServerManifest {\n readonly api: readonly PublicApiEndpoint[];\n readonly rpc: readonly PublicRpcEndpoint[];\n}\n\n/** Strips private handler paths before serializing a discovered server manifest. */\nexport function createPublicServerManifest(manifest: PublicServerManifest): PublicServerManifest {\n return {\n api: manifest.api.map(({ clientKey, pathname, method, contentType }) => ({\n clientKey, pathname, method, ...(contentType ? { contentType } : {}),\n })),\n rpc: manifest.rpc.map(({ id, pathname }) => ({ id, pathname })),\n };\n}\n\n/** Type-only operation declarations can be inferred from public shared schemas. */\nexport interface ApiOperation<Params = undefined, Query = undefined, Body = undefined, Output = unknown> {\n readonly params: Params;\n readonly query: Query;\n readonly body: Body;\n readonly output: Output;\n}\n\nexport interface RpcOperation<Input = unknown, Output = unknown> {\n readonly input: Input;\n readonly output: Output;\n}\n\ntype AnyApiOperation = ApiOperation<unknown, unknown, unknown, unknown>;\n\ntype SearchValue = string | number | boolean | null | undefined;\ntype QueryValue = SearchValue | readonly SearchValue[];\ntype RequestOptions = { readonly signal?: AbortSignal };\ntype ParamOption<T> = T extends undefined ? { readonly params?: never } : { readonly params: T };\ntype QueryOption<T> = T extends undefined ? { readonly query?: never } : { readonly query: T };\ntype BodyOption<T> = T extends undefined ? { readonly body?: never } : { readonly body: T };\ntype ApiArguments<O extends AnyApiOperation> = O[\"params\"] extends undefined\n ? O[\"query\"] extends undefined\n ? O[\"body\"] extends undefined ? [options?: ParamOption<O[\"params\"]> & QueryOption<O[\"query\"]> & BodyOption<O[\"body\"]> & RequestOptions] : [options: ParamOption<O[\"params\"]> & QueryOption<O[\"query\"]> & BodyOption<O[\"body\"]> & RequestOptions]\n : [options: ParamOption<O[\"params\"]> & QueryOption<O[\"query\"]> & BodyOption<O[\"body\"]> & RequestOptions]\n : [options: ParamOption<O[\"params\"]> & QueryOption<O[\"query\"]> & BodyOption<O[\"body\"]> & RequestOptions];\ntype Nest<Path extends string, Value> = Path extends `${infer Head}.${infer Tail}` ? { [K in Head]: Nest<Tail, Value> } : { [K in Path]: Value };\ntype Intersection<Union> = (Union extends unknown ? (value: Union) => void : never) extends (value: infer Result) => void ? Result : never;\ntype ApiMethods<Operations> = { [Method in keyof Operations]: Operations[Method] extends AnyApiOperation\n ? (...args: ApiArguments<Operations[Method]>) => Promise<Operations[Method][\"output\"]>\n : never };\nexport type ApiClient<Contract extends Record<string, Record<string, AnyApiOperation>>> = Intersection<{\n [Key in keyof Contract & string]: Nest<Key, ApiMethods<Contract[Key]>>\n}[keyof Contract & string]>;\nexport type RpcClient<Contract extends Record<string, RpcOperation>> = Intersection<{\n [Key in keyof Contract & string]: Nest<Key, (input: Contract[Key][\"input\"], options?: RequestOptions) => Promise<Contract[Key][\"output\"]>>\n}[keyof Contract & string]>;\n\nexport class ClientError extends Error {\n constructor(public readonly code: string, public readonly status: number, public readonly requestId?: string) {\n super(code);\n this.name = \"ClientError\";\n }\n}\n\nexport interface ClientOptions {\n readonly baseUrl?: string | (() => string);\n readonly fetch?: typeof fetch;\n readonly csrfToken?: string | (() => string | undefined);\n readonly headers?: HeadersInit | (() => HeadersInit);\n}\n\n/** Reads the current document token at call time, including after client navigation. */\nexport function createBrowserClientOptions(): ClientOptions {\n const currentCsrfToken = (): string | undefined => typeof document === \"undefined\"\n ? undefined\n : document.querySelector('meta[name=\"meeko-csrf-token\"]')?.getAttribute(\"content\") ?? undefined;\n return {\n csrfToken: currentCsrfToken,\n fetch: async (input, init) => {\n const sourceDocument = typeof document === \"undefined\" ? undefined : document;\n const csrfTokenAtStart = currentCsrfToken();\n const response = await fetch(input, init);\n const token = response.headers.get(\"x-meeko-csrf-token\");\n // Navigation or a newer response may have rotated or cleared the token.\n if (token !== null && sourceDocument && document === sourceDocument && currentCsrfToken() === csrfTokenAtStart) {\n let meta = document.querySelector('meta[name=\"meeko-csrf-token\"]');\n if (!token) {\n meta?.remove();\n return response;\n }\n if (!meta) {\n meta = document.createElement(\"meta\");\n meta.setAttribute(\"name\", \"meeko-csrf-token\");\n document.head.append(meta);\n }\n meta.setAttribute(\"content\", token);\n }\n return response;\n },\n };\n}\n\nfunction pathWithParams(pathname: string, params: Readonly<Record<string, string>> = {}): string {\n const used = new Set<string>();\n const path = pathname.replace(/\\[(\\.\\.\\.)?([A-Za-z_$][\\w$]*)\\]/g, (_match, rest: string | undefined, name: string) => {\n const value = params[name];\n if (!value) throw new TypeError(`Missing route parameter: ${name}`);\n used.add(name);\n const parts = rest ? value.split(\"/\") : [value];\n if (parts.some((part) => !part || part === \".\" || part === \"..\" || part.includes(\"/\") || part.includes(\"\\\\\"))) throw new TypeError(`Invalid route parameter: ${name}`);\n return parts.map(encodeURIComponent).join(\"/\");\n });\n for (const key of Object.keys(params)) if (!used.has(key)) throw new TypeError(`Unknown route parameter: ${key}`);\n return path;\n}\n\nfunction queryString(query: Readonly<Record<string, QueryValue>> | undefined): string {\n if (!query) return \"\";\n const search = new URLSearchParams();\n for (const [key, raw] of Object.entries(query)) {\n for (const value of Array.isArray(raw) ? raw : [raw]) {\n if (value !== null && value !== undefined) search.append(key, String(value));\n }\n }\n const result = search.toString();\n return result ? `?${result}` : \"\";\n}\n\nasync function responseValue(response: Response, contentType: \"json\" | \"response\" = \"json\"): Promise<unknown> {\n if (!response.ok) {\n let payload: unknown;\n try { payload = await response.json(); } catch { /* Bad error bodies still produce a normalized error. */ }\n const record = payload && typeof payload === \"object\" ? payload as Record<string, unknown> : {};\n const code = typeof record.code === \"string\" ? record.code : \"HTTP_ERROR\";\n const requestId = typeof record.requestId === \"string\" ? record.requestId : response.headers.get(\"x-request-id\") ?? undefined;\n throw new ClientError(code, response.status, requestId);\n }\n if (contentType === \"response\") return response;\n if (response.status === 204) return undefined;\n try { return await response.json(); }\n catch { throw new ClientError(\"INVALID_RESPONSE\", response.status, response.headers.get(\"x-request-id\") ?? undefined); }\n}\n\nfunction endpointUrl(pathname: string, options: ClientOptions): string {\n const baseUrl = typeof options.baseUrl === \"function\" ? options.baseUrl() : options.baseUrl;\n return baseUrl ? new URL(pathname, baseUrl).toString() : pathname;\n}\n\nfunction headersFor(options: ClientOptions, method: string, json: boolean): Headers {\n const headers = new Headers(typeof options.headers === \"function\" ? options.headers() : options.headers);\n if (json) headers.set(\"content-type\", \"application/json\");\n if (method !== \"GET\" && method !== \"HEAD\") {\n const csrf = typeof options.csrfToken === \"function\" ? options.csrfToken() : options.csrfToken;\n if (csrf) headers.set(\"x-meeko-csrf\", csrf);\n }\n return headers;\n}\n\nfunction insert(root: Record<string, unknown>, key: string, value: unknown): void {\n const parts = key.split(\".\");\n if (parts.some((part) => !/^[A-Za-z_$][\\w$]*$/.test(part))) throw new TypeError(`Invalid client key: ${key}`);\n let node = root;\n for (const part of parts.slice(0, -1)) {\n const existing = node[part];\n if (existing === undefined) node[part] = Object.create(null) as Record<string, unknown>;\n else if (!existing || typeof existing !== \"object\") throw new TypeError(`Client key collision: ${key}`);\n node = node[part] as Record<string, unknown>;\n }\n const last = parts.at(-1)!;\n if (node[last] !== undefined) throw new TypeError(`Client key collision: ${key}`);\n node[last] = value;\n}\n\nfunction ensureObject(root: Record<string, unknown>, key: string): Record<string, unknown> {\n const parts = key.split(\".\");\n if (parts.some((part) => !/^[A-Za-z_$][\\w$]*$/.test(part))) throw new TypeError(`Invalid client key: ${key}`);\n let node = root;\n for (const part of parts) {\n const existing = node[part];\n if (existing === undefined) node[part] = Object.create(null) as Record<string, unknown>;\n else if (!existing || typeof existing !== \"object\") throw new TypeError(`Client key collision: ${key}`);\n node = node[part] as Record<string, unknown>;\n }\n return node;\n}\n\n/** Creates browser API methods from public endpoint paths, without server imports. */\nexport function createApiClient<Contract extends Record<string, Record<string, AnyApiOperation>>>(manifest: Pick<PublicServerManifest, \"api\">, options: ClientOptions = {}): ApiClient<Contract> {\n const root: Record<string, unknown> = Object.create(null);\n for (const endpoint of manifest.api) {\n const methods = ensureObject(root, endpoint.clientKey);\n const method = endpoint.method.toLowerCase();\n if (methods[method]) throw new TypeError(`Duplicate API method: ${endpoint.clientKey}.${method}`);\n methods[method] = async (input: { params?: Record<string, string>; query?: Record<string, QueryValue>; body?: unknown; signal?: AbortSignal } = {}) => {\n const path = pathWithParams(endpoint.pathname, input.params) + queryString(input.query);\n const url = endpointUrl(path, options);\n const fetcher = options.fetch ?? fetch;\n const response = await fetcher(url, {\n method: endpoint.method, headers: headersFor(options, endpoint.method, input.body !== undefined),\n credentials: \"same-origin\", ...(input.body === undefined ? {} : { body: JSON.stringify(input.body) }),\n ...(input.signal ? { signal: input.signal } : {}),\n });\n return responseValue(response, endpoint.contentType);\n };\n }\n return root as ApiClient<Contract>;\n}\n\n/** Creates browser RPC procedures from public endpoint paths. */\nexport function createRpcClient<Contract extends Record<string, RpcOperation>>(manifest: Pick<PublicServerManifest, \"rpc\">, options: ClientOptions = {}): RpcClient<Contract> {\n const root: Record<string, unknown> = Object.create(null);\n for (const endpoint of manifest.rpc) {\n insert(root, endpoint.id, async (input: unknown, request: RequestOptions = {}) => {\n const fetcher = options.fetch ?? fetch;\n const response = await fetcher(endpointUrl(endpoint.pathname, options), {\n method: \"POST\", headers: headersFor(options, \"POST\", true), credentials: \"same-origin\",\n body: JSON.stringify(input), ...(request.signal ? { signal: request.signal } : {}),\n });\n return responseValue(response);\n });\n }\n return root as RpcClient<Contract>;\n}\n"]}
@@ -0,0 +1,10 @@
1
+ export interface MeekoConfig {
2
+ /** Layers are applied after the application, in declaration order. Collisions fail. */
3
+ readonly extends?: readonly string[];
4
+ /** Modules use the same app/pages convention as layers. */
5
+ readonly modules?: readonly string[];
6
+ readonly imports?: {
7
+ readonly serverDirs?: readonly string[];
8
+ };
9
+ }
10
+ export declare function defineMeekoConfig<const T extends MeekoConfig>(config: T): T;
@@ -0,0 +1,4 @@
1
+ export function defineMeekoConfig(config) {
2
+ return config;
3
+ }
4
+ //# sourceMappingURL=config-type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-type.js","sourceRoot":"","sources":["../../src/framework/config-type.ts"],"names":[],"mappings":"AAQA,MAAM,UAAU,iBAAiB,CAA8B,MAAS;IACtE,OAAO,MAAM,CAAC;AAChB,CAAC","sourcesContent":["export interface MeekoConfig {\n /** Layers are applied after the application, in declaration order. Collisions fail. */\n readonly extends?: readonly string[];\n /** Modules use the same app/pages convention as layers. */\n readonly modules?: readonly string[];\n readonly imports?: { readonly serverDirs?: readonly string[] };\n}\n\nexport function defineMeekoConfig<const T extends MeekoConfig>(config: T): T {\n return config;\n}\n"]}