@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,136 @@
1
+ import { createContext, createRoot, finishWithCleanup, inject, provide, signal } from "../reactivity.js";
2
+ import { serializeJson } from "../server.js";
3
+ const stateKey = createContext("Meeko framework state");
4
+ function assertKey(key) {
5
+ if (!key || key === "__proto__" || key === "constructor" || key === "prototype")
6
+ throw new TypeError("Invalid state key");
7
+ }
8
+ export class StateStore {
9
+ values = new Map();
10
+ constructor(initial = {}) {
11
+ serializeJson(initial);
12
+ for (const [key, value] of Object.entries(initial)) {
13
+ assertKey(key);
14
+ this.values.set(key, signal(value));
15
+ }
16
+ }
17
+ get(key, factory) {
18
+ assertKey(key);
19
+ let value = this.values.get(key);
20
+ if (!value) {
21
+ value = signal(factory());
22
+ this.values.set(key, value);
23
+ }
24
+ return value;
25
+ }
26
+ /** Seeds values returned by a later server navigation without replacing local state. */
27
+ seed(values) {
28
+ serializeJson(values);
29
+ const entries = Object.entries(values);
30
+ for (const [key] of entries)
31
+ assertKey(key);
32
+ for (const [key, value] of entries) {
33
+ if (!this.values.has(key))
34
+ this.values.set(key, signal(value));
35
+ }
36
+ }
37
+ /** Applies navigation state only if the synchronous DOM commit succeeds. */
38
+ seedForNavigation(values, commit) {
39
+ const previousKeys = new Set(this.values.keys());
40
+ this.seed(values);
41
+ try {
42
+ return commit();
43
+ }
44
+ catch (error) {
45
+ for (const key of this.values.keys())
46
+ if (!previousKeys.has(key))
47
+ this.values.delete(key);
48
+ throw error;
49
+ }
50
+ }
51
+ /** Gives an async client loader isolated signals until its route commits. */
52
+ navigationDraft() {
53
+ const initial = JSON.parse(serializeJson(this.snapshot()));
54
+ const draft = new StateStore(initial);
55
+ return {
56
+ state: draft,
57
+ commit: (work) => {
58
+ const next = draft.snapshot();
59
+ const changed = Object.entries(next).filter(([key, value]) => !Object.hasOwn(initial, key) || serializeJson(value) !== serializeJson(initial[key]));
60
+ const current = this.snapshot();
61
+ for (const [key] of changed) {
62
+ if (Object.hasOwn(current, key) !== Object.hasOwn(initial, key)
63
+ || (Object.hasOwn(initial, key) && serializeJson(current[key]) !== serializeJson(initial[key]))) {
64
+ throw new Error(`Meeko state changed while navigating: ${key}`);
65
+ }
66
+ }
67
+ const previous = new Map([...this.values].map(([key, value]) => {
68
+ const serialized = serializeJson(value.value);
69
+ return [key, { signal: value, serialized, value: JSON.parse(serialized) }];
70
+ }));
71
+ try {
72
+ for (const [key, value] of changed) {
73
+ const existing = this.values.get(key);
74
+ if (existing)
75
+ existing.value = value;
76
+ else
77
+ this.values.set(key, signal(value));
78
+ }
79
+ return work();
80
+ }
81
+ catch (error) {
82
+ const failures = [error];
83
+ for (const key of this.values.keys())
84
+ if (!previous.has(key))
85
+ this.values.delete(key);
86
+ for (const [key, prior] of previous) {
87
+ this.values.set(key, prior.signal);
88
+ let unchanged = false;
89
+ try {
90
+ unchanged = serializeJson(prior.signal.value) === prior.serialized;
91
+ }
92
+ catch { /* A now-invalid value still needs restoration. */ }
93
+ if (!unchanged) {
94
+ try {
95
+ prior.signal.value = prior.value;
96
+ }
97
+ catch (restoreError) {
98
+ failures.push(restoreError);
99
+ }
100
+ }
101
+ }
102
+ if (failures.length > 1)
103
+ throw new AggregateError(failures, "Meeko navigation state recovery failed");
104
+ throw error;
105
+ }
106
+ },
107
+ };
108
+ }
109
+ snapshot() {
110
+ const result = Object.create(null);
111
+ for (const [key, value] of this.values)
112
+ result[key] = value.value;
113
+ serializeJson(result);
114
+ return result;
115
+ }
116
+ }
117
+ /** One keyed signal per application request or browser app instance. */
118
+ export function useState(key, factory) {
119
+ return inject(stateKey).get(key, factory);
120
+ }
121
+ /** Runs synchronous SSR rendering with a state provider and releases its root. */
122
+ export function withStateStore(store, render) {
123
+ return createRoot((dispose) => {
124
+ provide(stateKey, store);
125
+ return finishWithCleanup(render, dispose);
126
+ });
127
+ }
128
+ /** Keeps the provider alive until the hydrated component is released. */
129
+ export function hydrateWithStateStore(store, hydrate) {
130
+ return createRoot((dispose) => {
131
+ provide(stateKey, store);
132
+ const release = hydrate();
133
+ return () => finishWithCleanup(release, dispose);
134
+ });
135
+ }
136
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/framework/state.ts"],"names":[],"mappings":"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","sourcesContent":["import { createContext, createRoot, finishWithCleanup, inject, provide, signal } from \"../reactivity.js\";\nimport type { Signal } from \"../reactivity.js\";\nimport { serializeJson } from \"../server.js\";\n\nconst stateKey = createContext<StateStore>(\"Meeko framework state\");\n\nfunction assertKey(key: string): void {\n if (!key || key === \"__proto__\" || key === \"constructor\" || key === \"prototype\") throw new TypeError(\"Invalid state key\");\n}\n\nexport class StateStore {\n private readonly values = new Map<string, Signal<unknown>>();\n\n constructor(initial: Readonly<Record<string, unknown>> = {}) {\n serializeJson(initial);\n for (const [key, value] of Object.entries(initial)) { assertKey(key); this.values.set(key, signal(value)); }\n }\n\n get<T>(key: string, factory: () => T): Signal<T> {\n assertKey(key);\n let value = this.values.get(key);\n if (!value) {\n value = signal(factory());\n this.values.set(key, value);\n }\n return value as Signal<T>;\n }\n\n /** Seeds values returned by a later server navigation without replacing local state. */\n seed(values: Readonly<Record<string, unknown>>): void {\n serializeJson(values);\n const entries = Object.entries(values);\n for (const [key] of entries) assertKey(key);\n for (const [key, value] of entries) {\n if (!this.values.has(key)) this.values.set(key, signal(value));\n }\n }\n\n /** Applies navigation state only if the synchronous DOM commit succeeds. */\n seedForNavigation<T>(values: Readonly<Record<string, unknown>>, commit: () => T): T {\n const previousKeys = new Set(this.values.keys());\n this.seed(values);\n try { return commit(); }\n catch (error) {\n for (const key of this.values.keys()) if (!previousKeys.has(key)) this.values.delete(key);\n throw error;\n }\n }\n\n /** Gives an async client loader isolated signals until its route commits. */\n navigationDraft(): { state: StateStore; commit<T>(work: () => T): T } {\n const initial = JSON.parse(serializeJson(this.snapshot())) as Record<string, unknown>;\n const draft = new StateStore(initial);\n return {\n state: draft,\n commit: <T>(work: () => T): T => {\n const next = draft.snapshot();\n const changed = Object.entries(next).filter(([key, value]) =>\n !Object.hasOwn(initial, key) || serializeJson(value) !== serializeJson(initial[key]));\n const current = this.snapshot();\n for (const [key] of changed) {\n if (Object.hasOwn(current, key) !== Object.hasOwn(initial, key)\n || (Object.hasOwn(initial, key) && serializeJson(current[key]) !== serializeJson(initial[key]))) {\n throw new Error(`Meeko state changed while navigating: ${key}`);\n }\n }\n const previous = new Map([...this.values].map(([key, value]) => {\n const serialized = serializeJson(value.value);\n return [key, { signal: value, serialized, value: JSON.parse(serialized) as unknown }] as const;\n }));\n try {\n for (const [key, value] of changed) {\n const existing = this.values.get(key);\n if (existing) existing.value = value;\n else this.values.set(key, signal(value));\n }\n return work();\n } catch (error) {\n const failures: unknown[] = [error];\n for (const key of this.values.keys()) if (!previous.has(key)) this.values.delete(key);\n for (const [key, prior] of previous) {\n this.values.set(key, prior.signal);\n let unchanged = false;\n try { unchanged = serializeJson(prior.signal.value) === prior.serialized; }\n catch { /* A now-invalid value still needs restoration. */ }\n if (!unchanged) {\n try { prior.signal.value = prior.value; }\n catch (restoreError) { failures.push(restoreError); }\n }\n }\n if (failures.length > 1) throw new AggregateError(failures, \"Meeko navigation state recovery failed\");\n throw error;\n }\n },\n };\n }\n\n snapshot(): Record<string, unknown> {\n const result: Record<string, unknown> = Object.create(null);\n for (const [key, value] of this.values) result[key] = value.value;\n serializeJson(result);\n return result;\n }\n}\n\n/** One keyed signal per application request or browser app instance. */\nexport function useState<T>(key: string, factory: () => T): Signal<T> {\n return inject(stateKey).get(key, factory);\n}\n\n/** Runs synchronous SSR rendering with a state provider and releases its root. */\nexport function withStateStore<T>(store: StateStore, render: () => T): T {\n return createRoot((dispose) => {\n provide(stateKey, store);\n return finishWithCleanup(render, dispose);\n });\n}\n\n/** Keeps the provider alive until the hydrated component is released. */\nexport function hydrateWithStateStore(store: StateStore, hydrate: () => () => void): () => void {\n return createRoot((dispose) => {\n provide(stateKey, store);\n const release = hydrate();\n return () => finishWithCleanup(release, dispose);\n });\n}\n"]}
@@ -0,0 +1,2 @@
1
+ /** Renders stylesheet URLs from a Vite manifest or the development convention. */
2
+ export declare function stylesheetLinks(paths: readonly string[]): string;
@@ -0,0 +1,6 @@
1
+ import { escapeHtml } from "../server.js";
2
+ /** Renders stylesheet URLs from a Vite manifest or the development convention. */
3
+ export function stylesheetLinks(paths) {
4
+ return paths.map((path) => `<link rel="stylesheet" href="${escapeHtml(path)}">`).join("");
5
+ }
6
+ //# sourceMappingURL=styles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.js","sourceRoot":"","sources":["../../src/framework/styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,kFAAkF;AAClF,MAAM,UAAU,eAAe,CAAC,KAAwB;IACtD,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,gCAAgC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC5F,CAAC","sourcesContent":["import { escapeHtml } from \"../server.js\";\n\n/** Renders stylesheet URLs from a Vite manifest or the development convention. */\nexport function stylesheetLinks(paths: readonly string[]): string {\n return paths.map((path) => `<link rel=\"stylesheet\" href=\"${escapeHtml(path)}\">`).join(\"\");\n}\n"]}
@@ -0,0 +1,5 @@
1
+ export declare const projectNames: readonly ["app", "server", "shared"];
2
+ /** Keeps TypeScript's three execution scopes under Meeko's generated directory. */
3
+ export declare function generateFrameworkTsconfigs(projectRoot: string): Promise<string[]>;
4
+ /** Generates declarations without loading a Vite server into the editor host. */
5
+ export declare function prepareFrameworkTypeDeclarations(projectRoot: string): Promise<void>;
@@ -0,0 +1,84 @@
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import { join, relative, resolve } from "node:path";
3
+ import { generateTypeScriptAutoImports } from "../autoimports-ts.js";
4
+ import { generateAppTypes } from "./check-app.js";
5
+ import { resolveConfigSources } from "./config.js";
6
+ import { generateServerContracts } from "./contracts-generate.js";
7
+ import { generateRoutes } from "./generate.js";
8
+ import { generatePageContracts } from "./page-contracts-generate.js";
9
+ export const projectNames = ["app", "server", "shared"];
10
+ const compilerOptions = {
11
+ target: "ES2022", module: "NodeNext", moduleResolution: "NodeNext", lib: ["ES2022", "DOM"],
12
+ types: ["node", "vite/client"], strict: true, noEmit: true, allowArbitraryExtensions: true,
13
+ exactOptionalPropertyTypes: true, noUncheckedIndexedAccess: true, verbatimModuleSyntax: true,
14
+ skipLibCheck: true,
15
+ };
16
+ const generatedIncludes = {
17
+ app: [
18
+ "generated/entry-client.ts", "generated/clients.client.ts", "generated/socket-contracts.ts",
19
+ "types/**/*.d.meeko.ts", "types/routes.d.ts", "types/virtual-pages.d.ts",
20
+ "types/server-contracts.d.ts", "types/autoimports/client.d.ts",
21
+ ],
22
+ server: [
23
+ "generated/entry-server.ts", "generated/clients.server.ts", "generated/socket-contracts.ts",
24
+ "generated/page-contracts.server.ts", "types/virtual-pages.d.ts", "types/routes.d.ts",
25
+ "types/**/*.d.meeko.ts", "types/autoimports/server.d.ts",
26
+ ],
27
+ shared: ["types/autoimports/shared.d.ts"],
28
+ };
29
+ async function writeIfChanged(file, source) {
30
+ try {
31
+ if (await readFile(file, "utf8") === source)
32
+ return;
33
+ }
34
+ catch (error) {
35
+ if (error.code !== "ENOENT")
36
+ throw error;
37
+ }
38
+ await writeFile(file, source, "utf8");
39
+ }
40
+ /** Keeps TypeScript's three execution scopes under Meeko's generated directory. */
41
+ export async function generateFrameworkTsconfigs(projectRoot) {
42
+ const generatedRoot = join(resolve(projectRoot), ".meeko");
43
+ const sourceRoots = (await resolveConfigSources(projectRoot)).map(({ root }) => relative(generatedRoot, root).replaceAll("\\", "/"));
44
+ await mkdir(generatedRoot, { recursive: true });
45
+ const configs = [];
46
+ for (const name of projectNames) {
47
+ const file = join(generatedRoot, `tsconfig.${name}.json`);
48
+ const includes = [...generatedIncludes[name]];
49
+ const excludes = [];
50
+ for (const root of sourceRoots) {
51
+ if (name === "app") {
52
+ includes.push(`${root}/app/**/*.ts`, `${root}/server/**/*.client.ts`, `${root}/shared/**/*.client.ts`);
53
+ excludes.push(`${root}/app/pages/**/*.route.ts`, `${root}/app/**/*.server.ts`, `${root}/app/**/*.shared.ts`);
54
+ }
55
+ else if (name === "server") {
56
+ includes.push(`${root}/server/**/*.ts`, `${root}/app/**/*.server.ts`, `${root}/app/pages/**/*.route.ts`, `${root}/shared/**/*.server.ts`);
57
+ excludes.push(`${root}/server/**/*.client.ts`, `${root}/server/**/*.shared.ts`);
58
+ }
59
+ else {
60
+ includes.push(`${root}/shared/**/*.ts`, `${root}/app/**/*.shared.ts`, `${root}/server/**/*.shared.ts`);
61
+ excludes.push(`${root}/shared/**/*.client.ts`, `${root}/shared/**/*.server.ts`);
62
+ }
63
+ }
64
+ const source = JSON.stringify({
65
+ compilerOptions: { ...compilerOptions, rootDirs: name === "shared" ? undefined : ["..", "./types"] },
66
+ include: includes,
67
+ ...(excludes.length ? { exclude: excludes } : {}),
68
+ }, null, 2) + "\n";
69
+ await writeIfChanged(file, source);
70
+ configs.push(file);
71
+ }
72
+ return configs;
73
+ }
74
+ /** Generates declarations without loading a Vite server into the editor host. */
75
+ export async function prepareFrameworkTypeDeclarations(projectRoot) {
76
+ const root = resolve(projectRoot);
77
+ await generateRoutes(root);
78
+ await generateServerContracts(root);
79
+ await generateAppTypes(root);
80
+ await generatePageContracts(root);
81
+ await generateTypeScriptAutoImports(root);
82
+ await generateFrameworkTsconfigs(root);
83
+ }
84
+ //# sourceMappingURL=type-declarations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"type-declarations.js","sourceRoot":"","sources":["../../src/framework/type-declarations.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { join, relative, resolve } from \"node:path\";\nimport { generateTypeScriptAutoImports } from \"../autoimports-ts.js\";\nimport { generateAppTypes } from \"./check-app.js\";\nimport { resolveConfigSources } from \"./config.js\";\nimport { generateServerContracts } from \"./contracts-generate.js\";\nimport { generateRoutes } from \"./generate.js\";\nimport { generatePageContracts } from \"./page-contracts-generate.js\";\n\nexport const projectNames = [\"app\", \"server\", \"shared\"] as const;\n\nconst compilerOptions = {\n target: \"ES2022\", module: \"NodeNext\", moduleResolution: \"NodeNext\", lib: [\"ES2022\", \"DOM\"],\n types: [\"node\", \"vite/client\"], strict: true, noEmit: true, allowArbitraryExtensions: true,\n exactOptionalPropertyTypes: true, noUncheckedIndexedAccess: true, verbatimModuleSyntax: true,\n skipLibCheck: true,\n} as const;\n\nconst generatedIncludes: Record<(typeof projectNames)[number], string[]> = {\n app: [\n \"generated/entry-client.ts\", \"generated/clients.client.ts\", \"generated/socket-contracts.ts\",\n \"types/**/*.d.meeko.ts\", \"types/routes.d.ts\", \"types/virtual-pages.d.ts\",\n \"types/server-contracts.d.ts\", \"types/autoimports/client.d.ts\",\n ],\n server: [\n \"generated/entry-server.ts\", \"generated/clients.server.ts\", \"generated/socket-contracts.ts\",\n \"generated/page-contracts.server.ts\", \"types/virtual-pages.d.ts\", \"types/routes.d.ts\",\n \"types/**/*.d.meeko.ts\", \"types/autoimports/server.d.ts\",\n ],\n shared: [\"types/autoimports/shared.d.ts\"],\n};\n\nasync function writeIfChanged(file: string, source: string): Promise<void> {\n try { if (await readFile(file, \"utf8\") === source) return; }\n catch (error) { if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error; }\n await writeFile(file, source, \"utf8\");\n}\n\n/** Keeps TypeScript's three execution scopes under Meeko's generated directory. */\nexport async function generateFrameworkTsconfigs(projectRoot: string): Promise<string[]> {\n const generatedRoot = join(resolve(projectRoot), \".meeko\");\n const sourceRoots = (await resolveConfigSources(projectRoot)).map(({ root }) => relative(generatedRoot, root).replaceAll(\"\\\\\", \"/\"));\n await mkdir(generatedRoot, { recursive: true });\n const configs: string[] = [];\n for (const name of projectNames) {\n const file = join(generatedRoot, `tsconfig.${name}.json`);\n const includes = [...generatedIncludes[name]];\n const excludes: string[] = [];\n for (const root of sourceRoots) {\n if (name === \"app\") {\n includes.push(`${root}/app/**/*.ts`, `${root}/server/**/*.client.ts`, `${root}/shared/**/*.client.ts`);\n excludes.push(`${root}/app/pages/**/*.route.ts`, `${root}/app/**/*.server.ts`, `${root}/app/**/*.shared.ts`);\n } else if (name === \"server\") {\n includes.push(`${root}/server/**/*.ts`, `${root}/app/**/*.server.ts`, `${root}/app/pages/**/*.route.ts`, `${root}/shared/**/*.server.ts`);\n excludes.push(`${root}/server/**/*.client.ts`, `${root}/server/**/*.shared.ts`);\n } else {\n includes.push(`${root}/shared/**/*.ts`, `${root}/app/**/*.shared.ts`, `${root}/server/**/*.shared.ts`);\n excludes.push(`${root}/shared/**/*.client.ts`, `${root}/shared/**/*.server.ts`);\n }\n }\n const source = JSON.stringify({\n compilerOptions: { ...compilerOptions, rootDirs: name === \"shared\" ? undefined : [\"..\", \"./types\"] },\n include: includes,\n ...(excludes.length ? { exclude: excludes } : {}),\n }, null, 2) + \"\\n\";\n await writeIfChanged(file, source);\n configs.push(file);\n }\n return configs;\n}\n\n/** Generates declarations without loading a Vite server into the editor host. */\nexport async function prepareFrameworkTypeDeclarations(projectRoot: string): Promise<void> {\n const root = resolve(projectRoot);\n await generateRoutes(root);\n await generateServerContracts(root);\n await generateAppTypes(root);\n await generatePageContracts(root);\n await generateTypeScriptAutoImports(root);\n await generateFrameworkTsconfigs(root);\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import type { ClientOptions } from "../framework/clients.js";
2
+ /** Dynamic options prevent a module-level client from retaining any user's credentials. */
3
+ export declare function createServerClientOptions(): ClientOptions;
@@ -0,0 +1,27 @@
1
+ import { currentRequest } from "./context.js";
2
+ /** Dynamic options prevent a module-level client from retaining any user's credentials. */
3
+ export function createServerClientOptions() {
4
+ return {
5
+ baseUrl: () => currentRequest().context.request.url,
6
+ headers: () => {
7
+ const request = currentRequest().context.request;
8
+ const headers = new Headers();
9
+ for (const name of ["cookie", "authorization"]) {
10
+ const value = request.headers.get(name);
11
+ if (value !== null)
12
+ headers.set(name, value);
13
+ }
14
+ headers.set("origin", new URL(request.url).origin);
15
+ return headers;
16
+ },
17
+ csrfToken: () => currentRequest().context.session.current?.csrfToken,
18
+ fetch: async (input, init) => {
19
+ const active = currentRequest();
20
+ const request = new Request(input, init);
21
+ if (active.serverFetch)
22
+ return active.serverFetch(request, active.context);
23
+ return fetch(request);
24
+ },
25
+ };
26
+ }
27
+ //# sourceMappingURL=auto-clients.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-clients.js","sourceRoot":"","sources":["../../src/framework-server/auto-clients.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAG9C,2FAA2F;AAC3F,MAAM,UAAU,yBAAyB;IACvC,OAAO;QACL,OAAO,EAAE,GAAG,EAAE,CAAC,cAAc,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG;QACnD,OAAO,EAAE,GAAG,EAAE;YACZ,MAAM,OAAO,GAAG,cAAc,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;YACjD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;YAC9B,KAAK,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,eAAe,CAAC,EAAE,CAAC;gBAC/C,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBACxC,IAAI,KAAK,KAAK,IAAI;oBAAE,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YAC/C,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC;YACnD,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,SAAS,EAAE,GAAG,EAAE,CAAC,cAAc,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,SAAS;QACpE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;YAC3B,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;YAChC,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YACzC,IAAI,MAAM,CAAC,WAAW;gBAAE,OAAO,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;YAC3E,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import { currentRequest } from \"./context.js\";\nimport type { ClientOptions } from \"../framework/clients.js\";\n\n/** Dynamic options prevent a module-level client from retaining any user's credentials. */\nexport function createServerClientOptions(): ClientOptions {\n return {\n baseUrl: () => currentRequest().context.request.url,\n headers: () => {\n const request = currentRequest().context.request;\n const headers = new Headers();\n for (const name of [\"cookie\", \"authorization\"]) {\n const value = request.headers.get(name);\n if (value !== null) headers.set(name, value);\n }\n headers.set(\"origin\", new URL(request.url).origin);\n return headers;\n },\n csrfToken: () => currentRequest().context.session.current?.csrfToken,\n fetch: async (input, init) => {\n const active = currentRequest();\n const request = new Request(input, init);\n if (active.serverFetch) return active.serverFetch(request, active.context);\n return fetch(request);\n },\n };\n}\n"]}
@@ -0,0 +1,21 @@
1
+ import type { SessionHandle } from "./sessions.js";
2
+ /** State belongs to one HTTP request and is never shared between users. */
3
+ export interface RequestContext<TServices = unknown> {
4
+ readonly request: Request;
5
+ readonly requestId: string;
6
+ readonly signal: AbortSignal;
7
+ readonly services: TServices;
8
+ readonly session: SessionHandle;
9
+ readonly state: Map<string, unknown>;
10
+ }
11
+ export type ServerFetch = (request: Request, context: RequestContext) => Promise<Response>;
12
+ interface ActiveRequest {
13
+ readonly context: RequestContext;
14
+ readonly serverFetch?: ServerFetch;
15
+ }
16
+ /** Binds automatic server clients to the current request across async work. */
17
+ export declare function withRequestContext<T>(context: RequestContext, serverFetch: ServerFetch | undefined, run: () => T): T;
18
+ export declare function currentRequest(): ActiveRequest;
19
+ export declare function createRequestContext<TServices>(request: Request, services: TServices, session: SessionHandle): RequestContext<TServices>;
20
+ export declare function useRequestState<T>(context: RequestContext, key: string, factory: () => T): T;
21
+ export {};
@@ -0,0 +1,22 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { AsyncLocalStorage } from "node:async_hooks";
3
+ const activeRequest = new AsyncLocalStorage();
4
+ /** Binds automatic server clients to the current request across async work. */
5
+ export function withRequestContext(context, serverFetch, run) {
6
+ return activeRequest.run({ context, ...(serverFetch ? { serverFetch } : {}) }, run);
7
+ }
8
+ export function currentRequest() {
9
+ const active = activeRequest.getStore();
10
+ if (!active)
11
+ throw new Error("Automatic server clients require an active Meeko request context");
12
+ return active;
13
+ }
14
+ export function createRequestContext(request, services, session) {
15
+ return { request, requestId: randomUUID(), signal: request.signal, services, session, state: new Map() };
16
+ }
17
+ export function useRequestState(context, key, factory) {
18
+ if (!context.state.has(key))
19
+ context.state.set(key, factory());
20
+ return context.state.get(key);
21
+ }
22
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/framework-server/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAerD,MAAM,aAAa,GAAG,IAAI,iBAAiB,EAAiB,CAAC;AAE7D,+EAA+E;AAC/E,MAAM,UAAU,kBAAkB,CAAI,OAAuB,EAAE,WAAoC,EAAE,GAAY;IAC/G,OAAO,aAAa,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;AACtF,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,MAAM,MAAM,GAAG,aAAa,CAAC,QAAQ,EAAE,CAAC;IACxC,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,kEAAkE,CAAC,CAAC;IACjG,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAY,OAAgB,EAAE,QAAmB,EAAE,OAAsB;IAC3G,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC;AAC3G,CAAC;AAED,MAAM,UAAU,eAAe,CAAI,OAAuB,EAAE,GAAW,EAAE,OAAgB;IACvF,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;QAAE,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;IAC/D,OAAO,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAM,CAAC;AACrC,CAAC","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport type { SessionHandle } from \"./sessions.js\";\n\n/** State belongs to one HTTP request and is never shared between users. */\nexport interface RequestContext<TServices = unknown> {\n readonly request: Request;\n readonly requestId: string;\n readonly signal: AbortSignal;\n readonly services: TServices;\n readonly session: SessionHandle;\n readonly state: Map<string, unknown>;\n}\n\nexport type ServerFetch = (request: Request, context: RequestContext) => Promise<Response>;\ninterface ActiveRequest { readonly context: RequestContext; readonly serverFetch?: ServerFetch }\nconst activeRequest = new AsyncLocalStorage<ActiveRequest>();\n\n/** Binds automatic server clients to the current request across async work. */\nexport function withRequestContext<T>(context: RequestContext, serverFetch: ServerFetch | undefined, run: () => T): T {\n return activeRequest.run({ context, ...(serverFetch ? { serverFetch } : {}) }, run);\n}\n\nexport function currentRequest(): ActiveRequest {\n const active = activeRequest.getStore();\n if (!active) throw new Error(\"Automatic server clients require an active Meeko request context\");\n return active;\n}\n\nexport function createRequestContext<TServices>(request: Request, services: TServices, session: SessionHandle): RequestContext<TServices> {\n return { request, requestId: randomUUID(), signal: request.signal, services, session, state: new Map() };\n}\n\nexport function useRequestState<T>(context: RequestContext, key: string, factory: () => T): T {\n if (!context.state.has(key)) context.state.set(key, factory());\n return context.state.get(key) as T;\n}\n"]}
@@ -0,0 +1,73 @@
1
+ import type { RequestContext } from "./context.js";
2
+ import { type SessionManager } from "./sessions.js";
3
+ /** Valibot schemas implement this public Standard Schema contract. */
4
+ export interface Schema<I = unknown, O = I> {
5
+ readonly "~standard": {
6
+ readonly version: 1;
7
+ readonly validate: (value: unknown) => {
8
+ value: O;
9
+ issues?: undefined;
10
+ } | {
11
+ issues: readonly unknown[];
12
+ } | Promise<{
13
+ value: O;
14
+ issues?: undefined;
15
+ } | {
16
+ issues: readonly unknown[];
17
+ }>;
18
+ readonly types?: {
19
+ readonly input: I;
20
+ readonly output: O;
21
+ } | undefined;
22
+ };
23
+ }
24
+ type Input<S> = S extends Schema<infer I, unknown> ? I : never;
25
+ type Output<S> = S extends Schema<unknown, infer O> ? O : never;
26
+ type OptionalOutput<S> = S extends Schema ? Output<S> : undefined;
27
+ export declare class ApiError extends Error {
28
+ readonly code: string;
29
+ readonly status: number;
30
+ constructor(code: string, status: number, message?: string);
31
+ }
32
+ /** Preserve public errors loaded through separate Vite module graphs; hide all others. */
33
+ export declare function normalizeServerError(error: unknown): ApiError;
34
+ export type ServerErrorObserver = (error: unknown, requestId: string) => void;
35
+ /** Observer failures cannot replace a response or escape as unhandled rejections. */
36
+ export declare function observeErrorCallback(error: unknown, observer?: (error: unknown) => void, requestId?: string): void;
37
+ /** Apply the same isolation to observers that also receive a request ID. */
38
+ export declare function observeServerError(error: unknown, requestId: string, observer?: ServerErrorObserver): void;
39
+ /** Surface internal failures to the host while keeping observers out of the response path. */
40
+ export declare function reportServerError(error: unknown, requestId: string, observer?: ServerErrorObserver): void;
41
+ export interface ApiRouteDefinition<P extends Schema | undefined, Q extends Schema | undefined, B extends Schema | undefined, R extends Schema | undefined, S = unknown> {
42
+ params?: P;
43
+ query?: Q;
44
+ body?: B;
45
+ response?: R;
46
+ auth?: "required" | "optional";
47
+ contentType?: "json" | "response";
48
+ authorize?: (context: RequestContext<S>) => boolean | Promise<boolean>;
49
+ handler: (args: {
50
+ params: OptionalOutput<P>;
51
+ query: OptionalOutput<Q>;
52
+ body: OptionalOutput<B>;
53
+ context: RequestContext<S>;
54
+ }) => Promise<R extends Schema ? Output<R> : Response> | (R extends Schema ? Output<R> : Response);
55
+ }
56
+ export declare function defineApiRoute<P extends Schema | undefined = undefined, Q extends Schema | undefined = undefined, B extends Schema | undefined = undefined, R extends Schema | undefined = undefined, S = unknown>(definition: ApiRouteDefinition<P, Q, B, R, S>): ApiRouteDefinition<P, Q, B, R, S>;
57
+ export interface RpcDefinition<I extends Schema, O extends Schema, S = unknown> {
58
+ input: I;
59
+ output: O;
60
+ auth?: "required" | "optional";
61
+ authorize?: (context: RequestContext<S>) => boolean | Promise<boolean>;
62
+ handler: (args: {
63
+ input: Output<I>;
64
+ context: RequestContext<S>;
65
+ }) => Promise<Input<O> | Output<O>> | Input<O> | Output<O>;
66
+ }
67
+ export declare function defineRpc<I extends Schema, O extends Schema, S = unknown>(definition: RpcDefinition<I, O, S>): RpcDefinition<I, O, S>;
68
+ export declare function executeApiRoute<P extends Schema | undefined, Q extends Schema | undefined, B extends Schema | undefined, R extends Schema | undefined, S>(definition: ApiRouteDefinition<P, Q, B, R, S>, context: RequestContext<S>, sessions: SessionManager, rawParams?: unknown): Promise<Response>;
69
+ export declare function executeRpc<I extends Schema, O extends Schema, S>(definition: RpcDefinition<I, O, S>, rawInput: unknown, context: RequestContext<S>, sessions: SessionManager): Promise<Output<O>>;
70
+ export declare function errorResponse(error: unknown, requestId: string): Response;
71
+ export declare function dispatchApiRoute<P extends Schema | undefined, Q extends Schema | undefined, B extends Schema | undefined, R extends Schema | undefined, S>(definition: ApiRouteDefinition<P, Q, B, R, S>, context: RequestContext<S>, sessions: SessionManager, params?: unknown, onError?: ServerErrorObserver): Promise<Response>;
72
+ export declare function dispatchRpc<I extends Schema, O extends Schema, S>(definition: RpcDefinition<I, O, S>, context: RequestContext<S>, sessions: SessionManager, onError?: ServerErrorObserver): Promise<Response>;
73
+ export {};
@@ -0,0 +1,184 @@
1
+ import { serializeJson } from "../server.js";
2
+ import { SessionSecurityError } from "./sessions.js";
3
+ export class ApiError extends Error {
4
+ code;
5
+ status;
6
+ constructor(code, status, message = code) {
7
+ super(message);
8
+ this.code = code;
9
+ this.status = status;
10
+ this.name = "ApiError";
11
+ }
12
+ }
13
+ /** Preserve public errors loaded through separate Vite module graphs; hide all others. */
14
+ export function normalizeServerError(error) {
15
+ if (error instanceof SessionSecurityError)
16
+ return new ApiError(error.code, 403);
17
+ if (error instanceof Error && (error.name === "SessionSecurityError" || error.constructor.name === "SessionSecurityError")) {
18
+ const code = error.code;
19
+ if (code === "INVALID_ORIGIN" || code === "INVALID_CSRF")
20
+ return new ApiError(code, 403);
21
+ }
22
+ if (error instanceof Error && (error instanceof ApiError || error.name === "ApiError" || error.constructor.name === "ApiError")) {
23
+ const candidate = error;
24
+ if (typeof candidate.code === "string" && candidate.code.length > 0
25
+ && typeof candidate.status === "number" && Number.isInteger(candidate.status)
26
+ && candidate.status >= 400 && candidate.status <= 599) {
27
+ return error instanceof ApiError ? error : new ApiError(candidate.code, candidate.status);
28
+ }
29
+ }
30
+ return new ApiError("INTERNAL_ERROR", 500);
31
+ }
32
+ function reportObserverFailure(error, observerError, requestId) {
33
+ try {
34
+ const label = requestId ? `Meeko server error observer failed (${requestId})` : "Meeko server error observer failed";
35
+ // Error messages and custom properties may contain private server data.
36
+ console.error(label, { original: error instanceof Error ? "Error" : typeof error, observer: observerError instanceof Error ? "Error" : typeof observerError });
37
+ }
38
+ catch { /* The fallback logger cannot change the original response. */ }
39
+ }
40
+ /** Observer failures cannot replace a response or escape as unhandled rejections. */
41
+ export function observeErrorCallback(error, observer, requestId) {
42
+ try {
43
+ void Promise.resolve(observer?.(error)).catch((observerError) => reportObserverFailure(error, observerError, requestId));
44
+ }
45
+ catch (observerError) {
46
+ reportObserverFailure(error, observerError, requestId);
47
+ }
48
+ }
49
+ /** Apply the same isolation to observers that also receive a request ID. */
50
+ export function observeServerError(error, requestId, observer) {
51
+ observeErrorCallback(error, observer ? (failure) => observer(failure, requestId) : undefined, requestId);
52
+ }
53
+ /** Surface internal failures to the host while keeping observers out of the response path. */
54
+ export function reportServerError(error, requestId, observer) {
55
+ if (normalizeServerError(error).status < 500)
56
+ return;
57
+ observeServerError(error, requestId, observer);
58
+ }
59
+ export function defineApiRoute(definition) {
60
+ return definition;
61
+ }
62
+ export function defineRpc(definition) {
63
+ return definition;
64
+ }
65
+ async function validate(schema, value, label) {
66
+ const result = await schema["~standard"].validate(value);
67
+ if ("issues" in result && result.issues)
68
+ throw new ApiError(`INVALID_${label.toUpperCase()}`, label === "response" || label === "output" ? 500 : 400);
69
+ return result.value;
70
+ }
71
+ async function readJson(request, maxBytes = 1024 * 1024) {
72
+ if (!request.headers.get("content-type")?.toLowerCase().startsWith("application/json"))
73
+ throw new ApiError("UNSUPPORTED_MEDIA_TYPE", 415);
74
+ const reader = request.body?.getReader();
75
+ if (!reader)
76
+ throw new ApiError("INVALID_JSON", 400);
77
+ let length = 0;
78
+ const chunks = [];
79
+ try {
80
+ while (true) {
81
+ const next = await reader.read();
82
+ if (next.done)
83
+ break;
84
+ length += next.value.byteLength;
85
+ if (length > maxBytes)
86
+ throw new ApiError("BODY_TOO_LARGE", 413);
87
+ chunks.push(next.value);
88
+ }
89
+ }
90
+ finally {
91
+ reader.releaseLock();
92
+ }
93
+ const bytes = new Uint8Array(length);
94
+ let position = 0;
95
+ for (const chunk of chunks) {
96
+ bytes.set(chunk, position);
97
+ position += chunk.byteLength;
98
+ }
99
+ try {
100
+ return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
101
+ }
102
+ catch {
103
+ throw new ApiError("INVALID_JSON", 400);
104
+ }
105
+ }
106
+ function queryObject(url) {
107
+ const result = Object.create(null);
108
+ for (const [key, value] of url.searchParams) {
109
+ const previous = result[key];
110
+ result[key] = previous === undefined ? value : Array.isArray(previous) ? [...previous, value] : [previous, value];
111
+ }
112
+ return result;
113
+ }
114
+ async function guard(definition, context, sessions, mutating) {
115
+ sessions.assertMutationAllowed(context.request, context.session, mutating);
116
+ if (definition.auth === "required" && !context.session.current)
117
+ throw new ApiError("UNAUTHENTICATED", 401);
118
+ if (definition.authorize && !(await definition.authorize(context)))
119
+ throw new ApiError("FORBIDDEN", 403);
120
+ }
121
+ export async function executeApiRoute(definition, context, sessions, rawParams = {}) {
122
+ await guard(definition, context, sessions);
123
+ const params = definition.params ? await validate(definition.params, rawParams, "params") : undefined;
124
+ const query = definition.query ? await validate(definition.query, queryObject(new URL(context.request.url)), "query") : undefined;
125
+ const body = definition.body ? await validate(definition.body, await readJson(context.request), "body") : undefined;
126
+ const result = await definition.handler({ params: params, query: query, body: body, context });
127
+ if (definition.contentType === "response") {
128
+ if (!(result instanceof Response))
129
+ throw new ApiError("INVALID_RESPONSE", 500);
130
+ return result;
131
+ }
132
+ if (!definition.response)
133
+ throw new ApiError("MISSING_RESPONSE_SCHEMA", 500);
134
+ const output = await validate(definition.response, result, "response");
135
+ return new Response(serializeJson(output), { headers: { "content-type": "application/json; charset=utf-8" } });
136
+ }
137
+ export async function executeRpc(definition, rawInput, context, sessions) {
138
+ await guard(definition, context, sessions, true);
139
+ const input = await validate(definition.input, rawInput, "input");
140
+ const result = await definition.handler({ input, context });
141
+ const output = await validate(definition.output, result, "output");
142
+ serializeJson(output);
143
+ return output;
144
+ }
145
+ export function errorResponse(error, requestId) {
146
+ const known = normalizeServerError(error);
147
+ return new Response(serializeJson({ code: known.code, status: known.status, requestId }), { status: known.status, headers: { "content-type": "application/json; charset=utf-8", "x-request-id": requestId } });
148
+ }
149
+ function finish(response, context) {
150
+ // Fetch-created responses such as Response.redirect have immutable headers.
151
+ // Wrap the response to preserve its status, body, and headers before adding
152
+ // request metadata and session changes.
153
+ const finished = new Response(response.body, response);
154
+ finished.headers.set("x-request-id", context.requestId);
155
+ if (context.session.cookieHeader)
156
+ finished.headers.append("set-cookie", context.session.cookieHeader);
157
+ if (context.session.current)
158
+ finished.headers.set("x-meeko-csrf-token", context.session.current.csrfToken);
159
+ else if (context.session.cookieHeader)
160
+ finished.headers.set("x-meeko-csrf-token", "");
161
+ return finished;
162
+ }
163
+ export async function dispatchApiRoute(definition, context, sessions, params = {}, onError) {
164
+ try {
165
+ return finish(await executeApiRoute(definition, context, sessions, params), context);
166
+ }
167
+ catch (error) {
168
+ reportServerError(error, context.requestId, onError);
169
+ return finish(errorResponse(error, context.requestId), context);
170
+ }
171
+ }
172
+ export async function dispatchRpc(definition, context, sessions, onError) {
173
+ try {
174
+ if (context.request.method !== "POST")
175
+ throw new ApiError("METHOD_NOT_ALLOWED", 405);
176
+ const output = await executeRpc(definition, await readJson(context.request), context, sessions);
177
+ return finish(new Response(serializeJson(output), { headers: { "content-type": "application/json; charset=utf-8" } }), context);
178
+ }
179
+ catch (error) {
180
+ reportServerError(error, context.requestId, onError);
181
+ return finish(errorResponse(error, context.requestId), context);
182
+ }
183
+ }
184
+ //# sourceMappingURL=contracts.js.map