@ogygia/core 0.12.2 → 0.13.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 (227) hide show
  1. package/dist/LateIsland.svelte +3 -2
  2. package/dist/LateIslandAwait.svelte +6 -2
  3. package/dist/Region.svelte +22 -33
  4. package/dist/boundary.d.ts +0 -2
  5. package/dist/boundary.js +8 -6
  6. package/dist/compiler/debarrel/barrel.d.ts +15 -8
  7. package/dist/compiler/debarrel/barrel.js +92 -45
  8. package/dist/compiler/debarrel/plugin.js +41 -17
  9. package/dist/compiler/dev/dev-hmr.d.ts +3 -0
  10. package/dist/compiler/dev/dev-hmr.js +3 -0
  11. package/dist/compiler/driver.js +11 -4
  12. package/dist/compiler/flags.js +21 -7
  13. package/dist/compiler/fouc-css.js +5 -1
  14. package/dist/compiler/kit.js +5 -1
  15. package/dist/compiler/link/build-output.js +12 -3
  16. package/dist/compiler/macros/bake.js +18 -4
  17. package/dist/compiler/macros/dollar.js +6 -1
  18. package/dist/compiler/macros/source.js +6 -1
  19. package/dist/compiler/macros/store.js +10 -2
  20. package/dist/compiler/macros/wire.js +6 -1
  21. package/dist/compiler/parse/scan.js +10 -3
  22. package/dist/compiler/region/transform.js +188 -74
  23. package/dist/context-bridge.js +13 -5
  24. package/dist/context.d.ts +9 -0
  25. package/dist/context.js +30 -1
  26. package/dist/document.d.ts +1 -1
  27. package/dist/document.js +7 -1
  28. package/dist/early-holes-head.d.ts +5 -0
  29. package/dist/early-holes-head.js +20 -0
  30. package/dist/early-holes.d.ts +34 -0
  31. package/dist/early-holes.js +51 -0
  32. package/dist/entry-hydrate.js +9 -12
  33. package/dist/events/bus.js +7 -2
  34. package/dist/events/schema.d.ts +2 -2
  35. package/dist/fn-transport.js +4 -3
  36. package/dist/hooks.js +94 -163
  37. package/dist/insights/page-assets.js +11 -3
  38. package/dist/insights/page-insights.d.ts +0 -2
  39. package/dist/insights/page-insights.js +14 -10
  40. package/dist/insights/session-insights.js +2 -2
  41. package/dist/internal-instruments.d.ts +3 -1
  42. package/dist/internal-instruments.js +3 -1
  43. package/dist/internal-server.d.ts +3 -2
  44. package/dist/internal-server.js +3 -2
  45. package/dist/internal.d.ts +1 -2
  46. package/dist/internal.js +1 -2
  47. package/dist/keep-fallback.d.ts +0 -2
  48. package/dist/keep-fallback.js +4 -5
  49. package/dist/live-transport.js +3 -2
  50. package/dist/messages/build.d.ts +585 -0
  51. package/dist/messages/build.js +800 -0
  52. package/dist/messages/core.d.ts +464 -0
  53. package/dist/messages/core.js +843 -0
  54. package/dist/messages/define.d.ts +62 -0
  55. package/dist/messages/define.js +49 -0
  56. package/dist/messages/index.d.ts +6 -0
  57. package/dist/messages/index.js +6 -0
  58. package/dist/messages/island.d.ts +4 -0
  59. package/dist/messages/island.js +34 -0
  60. package/dist/messages/lazy.d.ts +3 -0
  61. package/dist/messages/lazy.js +22 -0
  62. package/dist/messages/prose.d.ts +15 -0
  63. package/dist/messages/prose.js +43 -0
  64. package/dist/messages/server.d.ts +142 -0
  65. package/dist/messages/server.js +246 -0
  66. package/dist/nested.d.ts +3 -0
  67. package/dist/nested.js +8 -1
  68. package/dist/plugin/css.js +14 -13
  69. package/dist/plugin/facts.d.ts +2 -0
  70. package/dist/plugin/facts.js +10 -6
  71. package/dist/plugin/hooks.d.ts +7 -17
  72. package/dist/plugin/hooks.js +32 -4
  73. package/dist/plugin/index.d.ts +9 -2
  74. package/dist/plugin/request-scope.d.ts +20 -0
  75. package/dist/plugin/request-scope.js +149 -0
  76. package/dist/plugin/server.d.ts +20 -2
  77. package/dist/plugin/server.js +98 -28
  78. package/dist/plugin/testing.d.ts +6 -0
  79. package/dist/plugin/testing.js +14 -2
  80. package/dist/policies.d.ts +21 -0
  81. package/dist/policies.js +66 -0
  82. package/dist/preference.js +6 -1
  83. package/dist/preload.js +6 -9
  84. package/dist/ref-watch.d.ts +0 -10
  85. package/dist/ref-watch.js +14 -1
  86. package/dist/ref.js +17 -5
  87. package/dist/region-snippet.js +9 -3
  88. package/dist/region.js +2 -1
  89. package/dist/report-thrown.d.ts +9 -0
  90. package/dist/report-thrown.js +15 -0
  91. package/dist/rules.d.ts +17 -0
  92. package/dist/rules.js +57 -0
  93. package/dist/runtime/beacon.d.ts +0 -4
  94. package/dist/runtime/beacon.js +58 -43
  95. package/dist/runtime/boot-link.js +19 -2
  96. package/dist/runtime/client-hooks.js +2 -1
  97. package/dist/runtime/concurrency.d.ts +16 -5
  98. package/dist/runtime/concurrency.js +123 -7
  99. package/dist/runtime/core.d.ts +3 -1
  100. package/dist/runtime/core.js +718 -384
  101. package/dist/runtime/devalue-lane.d.ts +13 -0
  102. package/dist/runtime/devalue-lane.js +49 -0
  103. package/dist/runtime/disclose-version.d.ts +1 -0
  104. package/dist/runtime/disclose-version.js +14 -0
  105. package/dist/runtime/early-holes.d.ts +4 -0
  106. package/dist/runtime/early-holes.js +40 -0
  107. package/dist/runtime/entry-locations.js +40 -49
  108. package/dist/runtime/foreign-props.d.ts +0 -7
  109. package/dist/runtime/foreign-props.js +2 -1
  110. package/dist/runtime/form-continuity.d.ts +2 -2
  111. package/dist/runtime/form-continuity.js +30 -8
  112. package/dist/runtime/frame-nav.d.ts +7 -1
  113. package/dist/runtime/frame-nav.js +84 -18
  114. package/dist/runtime/frame-store.d.ts +25 -16
  115. package/dist/runtime/frame-store.js +124 -98
  116. package/dist/runtime/frames.js +8 -4
  117. package/dist/runtime/hole-facts.js +6 -7
  118. package/dist/runtime/hole-fetch.d.ts +17 -0
  119. package/dist/runtime/hole-fetch.js +47 -0
  120. package/dist/runtime/hydrate-core.d.ts +4 -4
  121. package/dist/runtime/hydrate-core.js +80 -64
  122. package/dist/runtime/import-again.d.ts +33 -0
  123. package/dist/runtime/import-again.js +217 -0
  124. package/dist/runtime/interaction-replay.d.ts +5 -3
  125. package/dist/runtime/interaction-replay.js +6 -6
  126. package/dist/runtime/interaction.d.ts +14 -3
  127. package/dist/runtime/interaction.js +46 -23
  128. package/dist/runtime/kit-page-thread.svelte.d.ts +2 -1
  129. package/dist/runtime/kit-page-thread.svelte.js +44 -20
  130. package/dist/runtime/lakes.d.ts +1 -1
  131. package/dist/runtime/lakes.js +18 -5
  132. package/dist/runtime/live.d.ts +1 -2
  133. package/dist/runtime/live.js +6 -8
  134. package/dist/runtime/load-scheduler.d.ts +29 -18
  135. package/dist/runtime/load-scheduler.js +236 -136
  136. package/dist/runtime/nav-handle.js +25 -6
  137. package/dist/runtime/navigation.d.ts +24 -0
  138. package/dist/runtime/navigation.js +24 -0
  139. package/dist/runtime/ownership.d.ts +1 -1
  140. package/dist/runtime/page-defer.js +3 -3
  141. package/dist/runtime/parse-html.d.ts +15 -4
  142. package/dist/runtime/parse-html.js +24 -5
  143. package/dist/runtime/pushable-props.svelte.d.ts +21 -0
  144. package/dist/runtime/pushable-props.svelte.js +37 -0
  145. package/dist/runtime/region-endpoint-url.js +4 -6
  146. package/dist/runtime/region-machines.d.ts +111 -0
  147. package/dist/runtime/region-machines.js +97 -0
  148. package/dist/runtime/region-sheets.d.ts +31 -0
  149. package/dist/runtime/region-sheets.js +49 -0
  150. package/dist/runtime/restore-report.d.ts +1 -0
  151. package/dist/runtime/restore-report.js +36 -0
  152. package/dist/runtime/restore.d.ts +5 -2
  153. package/dist/runtime/restore.js +33 -14
  154. package/dist/runtime/router-nav.d.ts +32 -12
  155. package/dist/runtime/router-nav.js +320 -228
  156. package/dist/runtime/router.d.ts +83 -19
  157. package/dist/runtime/router.js +297 -129
  158. package/dist/runtime/rules.d.ts +35 -0
  159. package/dist/runtime/rules.js +137 -0
  160. package/dist/runtime/schedule.d.ts +6 -3
  161. package/dist/runtime/schedule.js +172 -57
  162. package/dist/runtime/seeds.d.ts +5 -1
  163. package/dist/runtime/seeds.js +11 -5
  164. package/dist/runtime/session.d.ts +46 -7
  165. package/dist/runtime/session.js +78 -10
  166. package/dist/runtime/slots.d.ts +53 -20
  167. package/dist/runtime/slots.js +2 -3
  168. package/dist/runtime/soft-refresh.d.ts +16 -0
  169. package/dist/runtime/soft-refresh.js +14 -0
  170. package/dist/runtime/svelte-warnings.d.ts +4 -10
  171. package/dist/runtime/svelte-warnings.js +7 -4
  172. package/dist/runtime/wire-classes.js +21 -8
  173. package/dist/runtime/wire-format.js +6 -3
  174. package/dist/script.js +8 -7
  175. package/dist/seed-ref-reviver.d.ts +0 -9
  176. package/dist/seed-ref-reviver.js +2 -1
  177. package/dist/seed-refs.d.ts +46 -36
  178. package/dist/seed-refs.js +131 -92
  179. package/dist/server/document-tail.d.ts +6 -0
  180. package/dist/server/document-tail.js +7 -1
  181. package/dist/server/early-holes-csp.d.ts +14 -0
  182. package/dist/server/early-holes-csp.js +73 -0
  183. package/dist/server/page-facts.d.ts +4 -1
  184. package/dist/server/page-facts.js +4 -1
  185. package/dist/server/page-seed.d.ts +2 -2
  186. package/dist/server/page-seed.js +104 -11
  187. package/dist/server/page-stream.d.ts +14 -1
  188. package/dist/server/page-stream.js +119 -2
  189. package/dist/server/personal-response.d.ts +0 -5
  190. package/dist/server/personal-response.js +6 -2
  191. package/dist/server/props-wire.js +5 -1
  192. package/dist/server/region-endpoint.js +10 -2
  193. package/dist/server/render-cache.d.ts +24 -20
  194. package/dist/server/render-cache.js +99 -40
  195. package/dist/server/render-page.js +46 -15
  196. package/dist/server/request-stats.d.ts +10 -8
  197. package/dist/server/request-stats.js +20 -12
  198. package/dist/server/rules.d.ts +11 -0
  199. package/dist/server/rules.js +64 -0
  200. package/dist/server/signing-key.js +31 -18
  201. package/dist/server/stream-regions.d.ts +14 -1
  202. package/dist/server/stream-regions.js +38 -2
  203. package/dist/shared-state.js +5 -1
  204. package/dist/shims/app-navigation.js +3 -2
  205. package/dist/shims/page-store.svelte.js +16 -2
  206. package/dist/source.js +7 -2
  207. package/dist/store-transport.js +12 -5
  208. package/dist/transport.js +3 -2
  209. package/dist/vite/index.js +83 -74
  210. package/dist/vite/kit-dirs.js +7 -1
  211. package/dist/vite/options.d.ts +2 -1
  212. package/dist/vite/options.js +11 -20
  213. package/dist/vite/package-files.js +13 -3
  214. package/dist/vite/paths.d.ts +2 -0
  215. package/dist/vite/paths.js +4 -4
  216. package/dist/vite/plugin-api.d.ts +6 -5
  217. package/dist/vite/plugin-api.js +42 -14
  218. package/dist/vite/style-preprocess.js +10 -3
  219. package/package.json +8 -1
  220. package/dist/KeepHost.svelte +0 -19
  221. package/dist/KeepHost.svelte.d.ts +0 -10
  222. package/dist/LiveHost.svelte +0 -19
  223. package/dist/LiveHost.svelte.d.ts +0 -10
  224. package/dist/NestedProvider.svelte +0 -13
  225. package/dist/NestedProvider.svelte.d.ts +0 -8
  226. package/dist/runtime/page-cache.d.ts +0 -23
  227. package/dist/runtime/page-cache.js +0 -74
@@ -0,0 +1,843 @@
1
+ import { define_messages } from "./define.js";
2
+ import { prose } from "./prose.js";
3
+ // src/messages/core.ts
4
+ /**
5
+ * EVERY MESSAGE OGYGIA'S RUNTIME PRINTS IN THE BROWSER, in one place: its code, whether it is thrown
6
+ * or logged, its wording, and what to do about it (./define.ts says how the system works).
7
+ *
8
+ * throw new OgygiaError('goto_not_http');
9
+ * warn('island_hydrate_failed', { entry }, err);
10
+ *
11
+ * Dev: the wording and the code's page. A production build: the page's link alone. The runtime's lazy
12
+ * chunks take the same two from ./lazy.ts, island-side code (a shim a component imports) from
13
+ * ./island.ts — neither imports this module (see there).
14
+ */
15
+ const BUG = "An ogygia bug: please report it with the page that shows it.";
16
+ /** Each message's arguments are its `text`'s: the one place they are written. */
17
+ /** The errors: `throw new OgygiaError(code, args)`, or `console.error(new OgygiaError(…), err)` for a
18
+ * failure that is caught. */
19
+ const ERRORS = {
20
+ goto_not_http: {
21
+ text: () => "goto() only supports http(s) URLs",
22
+ details: () => prose`
23
+ \`goto()\` was called with a URL whose scheme is not \`http:\` or \`https:\` (a \`mailto:\`,
24
+ a \`javascript:\`, a custom scheme). Navigate to it with a plain link or
25
+ \`location.assign()\` instead.
26
+ `
27
+ },
28
+ goto_cross_origin: {
29
+ text: () => "goto() only supports same-origin URLs (pass { external: true } to leave)",
30
+ details: () => prose`
31
+ \`goto()\` navigates inside the app, so a URL on another origin is refused. To leave the
32
+ app, pass \`{ external: true }\`: \`goto(url, { external: true })\` does a full page load.
33
+ `
34
+ },
35
+ island_load_failed: {
36
+ text: (a) => `island entry failed to load: ${a.entry}`,
37
+ details: () => prose`
38
+ The island's module could not be fetched, so the island stays as its server HTML. This is
39
+ a load error, not a hydration error: the file is missing or the network failed. After a
40
+ deploy, ogygia retries the current build's file first.
41
+ `
42
+ },
43
+ chunk_reload_needed: {
44
+ text: (a) => `a file this page needs cannot load until the page reloads: ${a.url}`,
45
+ details: () => prose`
46
+ A file the runtime loads when it needs it (an island's code, a part of the runtime) failed,
47
+ and asking for it again failed the same way although the file itself came: one of the files
48
+ it imports failed to download, and the browser keeps that failure for the life of the page.
49
+ No retry can load it, so ogygia stops asking. The islands that need it stay as their server
50
+ HTML until the page reloads. Said once per page.
51
+ `
52
+ },
53
+ runtime_load_failed: {
54
+ text: () => "the ogygia runtime failed to load: no island on this page wakes",
55
+ details: () => prose`
56
+ The runtime's script, or one of the files it imports, failed to download (a dropped
57
+ connection, a file a deploy removed). The runtime never ran, so every island on the page
58
+ stays as its server HTML: links and forms still work, nothing interactive does. Reloading
59
+ the page loads it again. Printed by the runtime's script tag itself, as the page link alone.
60
+ `
61
+ },
62
+ island_load_failed_stale_deps: {
63
+ text: (a) => prose`
64
+ island entry failed to load: ${a.entry}
65
+
66
+ The module could not be FETCHED (not a hydration error). In dev this almost always means
67
+ Vite re-optimized dependencies and rotated its optimizer hash while this tab was open, so
68
+ its dep imports 404. Recovering… Original error:
69
+ `,
70
+ details: () => prose`
71
+ Dev only. Vite re-optimized its dependencies while the tab was open, so the island's
72
+ imports point at files that no longer exist. ogygia reloads the page to recover.
73
+ `
74
+ },
75
+ island_hydrate_failed: {
76
+ text: (a) => `hydration failed for ${a.entry}`,
77
+ details: () => prose`
78
+ The island's module loaded, but hydrating it threw. The error follows the message: it is
79
+ usually the component itself throwing while it initializes.
80
+ `
81
+ },
82
+ interaction_hydrate_failed: {
83
+ text: () => "interaction island failed to hydrate — leaving it static.",
84
+ details: () => prose`
85
+ An island waking on interaction threw while it hydrated, so it stays as its server HTML.
86
+ The click that woke it is replayed on that HTML. The error follows the message.
87
+ `
88
+ },
89
+ restore_markup_broken: {
90
+ text: (a) => `the transform broke hydration markup: ${a.diff}`,
91
+ details: () => prose`
92
+ A transform rewrote a restored region's markup so that its hydration markers no longer
93
+ match. \`diff\` names the first difference. (The restore runs as a self-contained script,
94
+ so it prints this code's link itself.)
95
+ `
96
+ },
97
+ client_hooks_init_failed: {
98
+ text: () => "hooks.client init failed:",
99
+ details: () => "The app's `hooks.client` `init()` threw. The error follows the message."
100
+ },
101
+ wired_class_foreign: {
102
+ text: () => prose`
103
+ a wired class crossed a build boundary: foreign (stitched-fragment) island props must be
104
+ plain data — wired live objects cannot reunite across two svelte runtimes. Pass the
105
+ underlying data instead.
106
+ `,
107
+ details: () => prose`
108
+ A stitched fragment's island received a wired object (a class registered with ogygia's
109
+ wire) from another build. Two Svelte runtimes cannot share it. Pass plain data instead.
110
+ `
111
+ },
112
+ devalue_not_loaded: {
113
+ text: () => "a devalue-lane payload was read before devalue loaded (load_devalue() first)",
114
+ details: () => BUG
115
+ },
116
+ slot_not_linked: {
117
+ text: (a) => `runtime chunk used \`slots.${a.name}\` before the boot linked it`,
118
+ details: () => BUG
119
+ },
120
+ boundary_refused: {
121
+ text: (a) => `${a.site} — og.$ value${a.path ? ` @ ${a.path}` : ""}: ${a.detail}${a.more ? ` (+${a.more} more)` : ""}`,
122
+ details: () => prose`
123
+ A value marked with \`import.meta.og.$\` cannot cross into an island: a DOM node, a bare
124
+ function, a class with no wire codec, a secret. It fails where it is marked, so the file
125
+ and line point at it. Pass plain data, or give the class a codec.
126
+ `
127
+ },
128
+ function_prop_cannot_cross: {
129
+ text: (a) => prose`
130
+ ${a.where} is a function that can't cross the island boundary — ${a.reason}. Island props
131
+ must be SERIALIZABLE; a function crosses only as a Svelte snippet that freezes to HTML, and
132
+ this one didn't. Usually one of:
133
+
134
+ • it's a PLAIN function (an event handler / callback) — those can't cross into an island;
135
+ pass serializable data as props and keep the behavior inside the island component;
136
+
137
+ • it's a snippet WITH PARAMETERS — declare it as a {#snippet} so it crosses LIVE, or pass
138
+ its data as props;
139
+
140
+ • it's children containing a NESTED island — keep those out of frozen children for now.
141
+ `,
142
+ details: () => prose`
143
+ An island's props must be serializable. A function only crosses as a snippet that freezes
144
+ to HTML, and this one could not.
145
+
146
+ A plain function (an event handler, a callback) never crosses: keep the behavior inside the
147
+ island and pass data. A snippet with parameters crosses live when it is declared as a
148
+ snippet. Children that contain another island cannot be frozen yet.
149
+ `
150
+ },
151
+ region_snippet_on_client: {
152
+ text: () => prose`
153
+ region_snippet(fn) freezes a snippet by server-rendering it — call it during SSR, not on
154
+ the client. Pass a raw { render, setup } region snippet for client-constructed regions.
155
+ `,
156
+ details: () => prose`
157
+ \`region_snippet(fn)\` renders the snippet on the server to freeze it. In the browser, build
158
+ the region from a raw \`{ render, setup }\` snippet instead.
159
+ `
160
+ },
161
+ raw_region_on_client: {
162
+ text: () => prose`
163
+ a \`with { region: 'raw' }\` component must be turned into a region on the server (the
164
+ signer lives server-side). Call region() in a load / remote / render context, not in client
165
+ code.
166
+ `,
167
+ details: () => prose`
168
+ A held region is signed on the server, so \`region()\` on a \`with { region: 'raw' }\`
169
+ component must run there: in a load, a remote function or a render.
170
+ `
171
+ },
172
+ held_region_plain_import: {
173
+ text: () => prose`
174
+ a held region reached the wire but its component is a plain import, so nothing built a
175
+ chunk for it. \`await\` the region before returning it from a remote/load — an awaited
176
+ region bakes its SSR HTML and crosses as an HTML-only ticket. Or import the component
177
+ \`with { region: 'raw' }\` (or a \`wake:\` mark) to make it a signed, fetchable capability. On
178
+ a csr=false page you can also skip the wire entirely: call \`get()\` in a universal
179
+ \`+page.ts\` load / the component — its data reaches the render by reference.
180
+ `,
181
+ details: () => prose`
182
+ A region returned from a load or a remote function has to travel: as HTML, or as a signed
183
+ address the browser fetches. This one's component was imported plainly, so neither exists.
184
+
185
+ \`await\` the region (it then travels as its HTML), or import the component
186
+ \`with { region: 'raw' }\` or with a \`wake\` mark.
187
+ `
188
+ },
189
+ region_kind_mismatch: {
190
+ text: () => "region kind claimed a non-region value",
191
+ details: () => BUG
192
+ },
193
+ keep_fallback_inline: {
194
+ text: () => prose`
195
+ keepFallback() ran inside the PAGE render: this server island is nested inside a \`wake\`
196
+ island, where \`render: "deferred"\` is ignored and its component renders inline — nothing
197
+ catches the signal there and its fallback never shows. Move the island out of the
198
+ enclosing island (into the page, a layout, or a lake), or drop keepFallback() from a
199
+ component that can render inline.
200
+ `,
201
+ details: () => prose`
202
+ \`keepFallback()\` tells a deferred region to keep the page's fallback. Inside a \`wake\`
203
+ island the region renders inline instead, so nothing can keep a fallback. Move the region
204
+ out of the island (into the page, a layout or a lake).
205
+ `
206
+ },
207
+ keep_fallback_signal: {
208
+ text: () => "keepFallback(): the page fallback stands",
209
+ details: () => prose`
210
+ Not an error: the signal \`keepFallback()\` throws to end a deferred region's render. You
211
+ only see it when something catches and logs every error the render throws.
212
+ `
213
+ },
214
+ preference_default_invalid: {
215
+ text: (a) => `preference('${a.name}'): default '${a.fallback}' is not one of values [${a.values}]`,
216
+ details: () => prose`
217
+ A preference's \`default\` must be one of its \`values\`.
218
+ `
219
+ },
220
+ fn_factory_missing: {
221
+ text: (a) => prose`
222
+ fn_handle("${a.tag}"): its factory is not registered on this side. The generated module
223
+ must be imported as a VALUE at the call site (the compiler emits this import).
224
+ `,
225
+ details: () => prose`
226
+ A function marked to cross into an island is rebuilt on the other side from a factory the
227
+ compiler generates. That factory's module was not imported here. Import it as a value, not
228
+ \`import type\`.
229
+ `
230
+ },
231
+ fn_factory_not_function: {
232
+ text: (a) => `fn factory "${a.tag}" did not return a function.`,
233
+ details: () => BUG
234
+ },
235
+ fn_revive_missing: {
236
+ text: (a) => prose`
237
+ cannot revive fn "${a.tag}": its factory is not loaded on this side and the payload carries
238
+ no source. The island must import the generated module as a VALUE so \`__register_fn\`
239
+ runs in its bundle (or the fn manifest must be in the runtime).
240
+ `,
241
+ details: () => prose`
242
+ An island received a function it cannot rebuild: the module that registers its factory is
243
+ not in the island's bundle. Import that module as a value in the island.
244
+ `
245
+ },
246
+ transportable_class_missing: {
247
+ text: (a) => prose`
248
+ cannot revive transportable "${a.tag}": its class is not loaded on this side. The island
249
+ must import the class as a VALUE (not \`import type\`) so its codec travels with the
250
+ island's bundle.
251
+ `,
252
+ details: () => prose`
253
+ An island received an instance of a wired class whose module it never imports, so the
254
+ class's codec is not there to rebuild it. Import the class as a value in the island.
255
+ `
256
+ },
257
+ transportable_unregistered: {
258
+ text: (a) => prose`
259
+ class "${a.name}" has a [import.meta.og.wire] codec but was never registered. Transportable
260
+ classes must be declared in a module the ogygia vite plugin transforms (an \`export class\`
261
+ in your app source, not node_modules or a dynamic eval).
262
+ `,
263
+ details: () => prose`
264
+ A class with a wire codec is registered by the ogygia Vite plugin while it compiles the
265
+ class's module. This class was declared somewhere the plugin does not compile. Declare it
266
+ as an \`export class\` in the app's source.
267
+ `
268
+ },
269
+ ref_kind_missing: {
270
+ text: (a) => prose`
271
+ cannot resolve a "${a.kind}" ref: no such kind is registered on this side. The module that
272
+ registers it must be imported as a VALUE in this bundle.
273
+ `,
274
+ details: () => prose`
275
+ A value crossed into an island as a reference of a kind this bundle does not know. Import
276
+ the module that registers that kind as a value.
277
+ `
278
+ },
279
+ continuity_id_collision: {
280
+ text: (a) => prose`
281
+ two transportables both use continuity id "${a.name}" ("${a.owner}" and "${a.tag}"). A
282
+ continuity id must be unique per class — rename one, or they will clobber each other in the
283
+ session Keep.
284
+ `,
285
+ details: () => prose`
286
+ Two different wired classes claim the same continuity id, so they would share one kept
287
+ instance. Give each class its own id.
288
+ `
289
+ },
290
+ shared_state_not_plain: {
291
+ text: (a) => prose`
292
+ SharedState '${a.name}': values must be plain data (devalue-serializable — JSON, Date, Map,
293
+ Set, BigInt, RegExp). Functions, class instances, and DOM nodes do not cross build
294
+ boundaries — share facts, not live objects. (${a.reason})
295
+ `,
296
+ details: () => prose`
297
+ Shared state crosses between builds as data, so its values must serialize. Share plain
298
+ facts; keep live objects (functions, class instances, DOM nodes) on one side.
299
+ `
300
+ },
301
+ og_derived_formula_missing: {
302
+ text: () => prose`
303
+ cannot resume og_derived: its formula did not cross — mark it with import.meta.og.$ at the
304
+ og_derived call site so it travels as a fn ref.
305
+ `,
306
+ details: () => prose`
307
+ An \`og_derived\` crossed into an island without its formula. Mark the formula with
308
+ \`import.meta.og.$\` where \`og_derived\` is called, so it travels too.
309
+ `
310
+ },
311
+ script_run_not_function: {
312
+ text: () => "script(): `run` must be a function",
313
+ details: () => "`script({ run })` takes a function, which it inlines as the script body."
314
+ },
315
+ script_imports_need_module: {
316
+ text: () => "script(): `imports` needs `type: 'module'` (a static import only works in a module)",
317
+ details: () => "`imports` become static `import` lines, which only work in a module: add `type: 'module'`."
318
+ },
319
+ script_import_not_url: {
320
+ text: (a) => `script(): \`imports.${a.name}\` must be a URL string`,
321
+ details: () => "Each entry of `imports` is a module URL, as a string."
322
+ },
323
+ script_run_rewritten: {
324
+ text: () => prose`
325
+ script(): \`run\` was rewritten by the bundler (it holds \`__vite_ssr_…\`): an \`import()\` or
326
+ an imported binding inside it cannot cross into the browser. Declare the module in
327
+ \`imports\` (with \`type: 'module'\`) and read it from \`run\`'s first parameter.
328
+ `,
329
+ details: () => prose`
330
+ \`run\` is inlined into the page as its source, so it cannot use what Vite rewrites for
331
+ the server: an \`import()\` or an imported binding. Declare the module in \`imports\` and
332
+ read it from \`run\`'s first parameter.
333
+ `
334
+ },
335
+ script_not_json: {
336
+ text: (a) => `script(): \`${a.key}\` must be JSON-serializable`,
337
+ details: () => "The value is written into the page as JSON, so it must serialize to JSON."
338
+ },
339
+ script_one_kind: {
340
+ text: (a) => `script(): pass exactly one of \`run\`, \`json\`, \`ld\`, \`importmap\`, \`speculation\` (got ${a.count})`,
341
+ details: () => "A script has one body: pass one of `run`, `json`, `ld`, `importmap` or `speculation`."
342
+ },
343
+ script_bad_attribute: {
344
+ text: (a) => `script(): \`${a.key}\` is not an attribute name`,
345
+ details: () => "Options other than the body become attributes of the script element, so each must be a valid attribute name."
346
+ }
347
+ };
348
+ /** The warnings: `warn(code, args, ...rest)`. */
349
+ const WARNINGS = {
350
+ shallow_routing_unsupported: {
351
+ text: (a) => `${a.method}() shallow routing is not supported; use goto().`,
352
+ details: () => prose`
353
+ Kit's \`pushState\` / \`replaceState\` (shallow routing) have no equivalent in the ogygia
354
+ router: the call does nothing. Navigate with \`goto()\`, or keep the state in the URL.
355
+ `
356
+ },
357
+ scroll_handling_noop: {
358
+ text: () => "disableScrollHandling() is a no-op in the islands SPA router.",
359
+ details: () => prose`
360
+ The ogygia router restores and resets scroll itself on every navigation;
361
+ \`disableScrollHandling()\` does nothing there.
362
+ `
363
+ },
364
+ hole_without_address: {
365
+ text: (a) => prose`
366
+ deferred region ${a.region} was rendered in the browser with no server-minted address,
367
+ and the document records none for it (a client-side navigation mounted it, or its props
368
+ differ from the server render) — its fallback stands. A hole is server HTML: render it on
369
+ the server.
370
+ `,
371
+ details: () => prose`
372
+ A deferred region (a hole) is fetched from an address the server signs while it renders
373
+ the page. This one was created in the browser, so it has no address and keeps its
374
+ fallback.
375
+
376
+ Render the hole on the server: keep it out of browser-only branches, and give it the same
377
+ props on both sides.
378
+ `
379
+ },
380
+ nested_region_rides_parent: {
381
+ text: (a) => prose`
382
+ nested region "${a.entry}" skipped self-run; the nearest region above it is awake, so it
383
+ rides that hydration (inner hydrate "${a.wake}" ignored).
384
+ `,
385
+ details: () => prose`
386
+ A region inside an awake region hydrates with it, once, as part of the outer island. Its
387
+ own \`wake\` schedule is ignored. To give it its own schedule, put a lake
388
+ (\`wake: 'none'\`) between the two.
389
+ `
390
+ },
391
+ region_endpoint_foreign: {
392
+ text: (a) => `refused non-same-origin region endpoint ${a.endpoint}`,
393
+ details: () => prose`
394
+ A region's \`endpoint\` pointed at another origin. The runtime only fetches region answers
395
+ from the page's own origin; the fallback stands.
396
+ `
397
+ },
398
+ region_answer_denied: {
399
+ text: (a) => prose`
400
+ region answer refused for ${a.endpoint}:
401
+ ${a.deny.startsWith("not ogygia") ? a.deny : `the islands endpoint refused its capability (403: ${a.deny})`}.
402
+ ${a.deny.startsWith("foreign-key") && prose`
403
+ The page and its islands endpoint came from different deployments (two keys): route
404
+ the endpoint to the deployment that served the page, or give every deployment one
405
+ OGYGIA_SECRET.
406
+ `}
407
+ The fallback stands.
408
+ `,
409
+ details: () => prose`
410
+ The islands endpoint refused the signed address of a region (a 403), so its fallback
411
+ stands. The reason is in \`deny\`.
412
+
413
+ \`foreign-key\`: the page and its islands endpoint came from different deployments, each
414
+ signing with its own key. Route the endpoint to the deployment that served the page, or
415
+ give every deployment the same \`OGYGIA_SECRET\`.
416
+
417
+ \`not ogygia\`: the answer did not come from ogygia at all; something in front of
418
+ \`ogygia.handle()\` answered it.
419
+ `
420
+ },
421
+ region_answer_redirected: {
422
+ text: (a) => prose`
423
+ region answer refused for ${a.endpoint}: the request was
424
+ ${a.how === "redirected" ? "redirected to" : "answered with a whole document at"} ${a.final_url}.
425
+ A handle in front of ogygia.handle() (an auth redirect, a locale bounce, a 404 handler)
426
+ took the region request — exempt the islands endpoint there. The fallback stands.
427
+ `,
428
+ details: () => prose`
429
+ A handle that runs before \`ogygia.handle()\` answered the region request itself: an auth
430
+ redirect, a locale bounce, a 404 page. The runtime refuses such an answer and keeps the
431
+ fallback.
432
+
433
+ Exempt the islands endpoint (\`/__ogygia__\`) in that handle.
434
+ `
435
+ },
436
+ region_fetch_failed: {
437
+ text: (a) => `region fetch failed for ${a.endpoint}`,
438
+ details: () => prose`
439
+ The request for a region's HTML failed (the network, a server error). The runtime retries
440
+ a few times; the fallback stands until one succeeds. The error follows the message.
441
+ `
442
+ },
443
+ island_healed: {
444
+ text: (a) => prose`
445
+ island "${a.entry}" was edited while it slept (its light DOM no longer matched the server
446
+ render — a design-system runtime, an A/B tool, a translator), so its server HTML was put
447
+ back and hydrated instead of re-rendering it client-side. Whatever the edit added is gone;
448
+ the script that made it should leave <ogygia-region> subtrees alone.
449
+
450
+ ${a.drift && `What drifted: ${a.drift}`}
451
+ `,
452
+ details: () => prose`
453
+ Dev only. Something edited the island's HTML before it woke (a design-system runtime, an
454
+ A/B tool, a translator). ogygia put the server HTML back and hydrated that, instead of
455
+ letting Svelte throw it away and re-render. Whatever the edit added is gone.
456
+
457
+ Make the script that edits the page leave \`<ogygia-region>\` subtrees alone.
458
+ `
459
+ },
460
+ ownership_conflict: {
461
+ text: (a) => prose`
462
+ ${a.element} is a web component that changed its own children in a position Svelte's
463
+ hydration reads, so the repair had to remove the nodes it added. Render that subtree with
464
+ {@html} or as static markup (Svelte never reads inside it), put it in a lake
465
+ (wake: 'none'), or mark the element data-ogygia-keep.
466
+ `,
467
+ details: () => prose`
468
+ Dev only. A web component inside the island added children where Svelte's hydration
469
+ expects the server's nodes. To hydrate the island, the repair removed them.
470
+
471
+ Render that subtree with \`{@html}\` or as static markup (Svelte never reads inside it),
472
+ put it in a lake (\`wake: 'none'\`), or mark the element \`data-ogygia-keep\`.
473
+ `
474
+ },
475
+ hydration_discarded: {
476
+ text: (a) => prose`
477
+ island "${a.entry}" discarded its ENTIRE server-rendered DOM during hydration and
478
+ re-rendered client-side (Svelte hydration-mismatch recovery). Three things cause this.
479
+ (1) Something changed this region's HTML between SSR and wake — a post-SSR transform
480
+ (transformPageChunk / an HTML-rewriting middleware), an A/B-testing snippet, or an edge
481
+ rewriter; whatever it injected (e.g. declarative shadow DOM) was just destroyed, and the
482
+ swap is timing-dependent, so symptoms look erratic. (2) A component in this island reads
483
+ a page/layout CONTEXT via plain Svelte setContext — on csr=false that runs only on the
484
+ server, so getContext returns undefined on the client and the island renders a different
485
+ tree. (3) A block in this island ({#if} / {:else if} / {#each} / {#await}) took a
486
+ DIFFERENT branch on the client than on the server — its condition reads something that
487
+ differs between the two (a browser global, a store's client default, url/page state, a
488
+ Date). Svelte recovers a branch mismatch SILENTLY (no throw); the walk is then off and
489
+ the rest of the tree follows.
490
+
491
+ ${a.drift && `What changed: ${a.drift}`}
492
+
493
+ ${a.strict ? `Svelte threw on the strict attempt (after repair): ${a.strict}` : a.drift ? "Svelte did not throw after the repair — the mismatch is one this walk does not model." : prose`
494
+ The server node sequence was INTACT and Svelte did not throw: nothing mutated
495
+ this region's DOM, so this is (3) (or (2)). Find the block whose branch
496
+ differs: in the server markup its anchor reads <!--[N--> where N is the
497
+ branch the SERVER chose.
498
+ `}
499
+
500
+ Fix: for (1) make the mutation invisible to hydration (mutate only <head>, attributes, or
501
+ shadow templates — never the region's light DOM), or freeze the foreign-owned subtree
502
+ with a wake:'none' (lake) boundary; for (2) provide the value with setContext / <Provide>
503
+ / createContext imported from 'ogygia', read it with the same getContext(key); for (3)
504
+ make the condition read the same value on both sides (a prop / page.data), or move the
505
+ browser-only branch behind an $effect / hydratedBy().
506
+ `,
507
+ details: () => prose`
508
+ Svelte could not adopt the island's server HTML, so it threw it away and rendered the
509
+ island again in the browser: a flash, and anything injected into that HTML is gone. Three
510
+ things cause it.
511
+
512
+ 1. Something changed the region's HTML between the server render and the wake: a
513
+ post-SSR transform (\`transformPageChunk\`, an HTML-rewriting middleware), an A/B-testing
514
+ snippet, an edge rewriter. \`drift\` names the first difference. Mutate only the head,
515
+ attributes or shadow templates, never the region's light DOM, or freeze that subtree in a
516
+ lake (\`wake: 'none'\`).
517
+
518
+ 2. A component reads a page or layout context set with plain \`setContext\`. On a
519
+ csr=false page that runs only on the server, so the browser renders a different tree.
520
+ Provide the value with \`setContext\` / \`<Provide>\` / \`createContext\` imported from
521
+ \`ogygia\`.
522
+
523
+ 3. A block (\`if\`, \`each\`, \`await\`) took a different branch in the browser than on
524
+ the server: its condition reads a browser global, a store's client default, URL state or a
525
+ date. With no \`drift\` and no \`strict\` error this is the cause. Make the condition read
526
+ the same value on both sides (a prop, \`page.data\`), or move the browser-only branch
527
+ behind an \`$effect\` or \`hydratedBy()\`.
528
+ `
529
+ },
530
+ prop_mutation: {
531
+ text: (a) => prose`
532
+ mutating prop '${a.prop}' inside island ${a.entry} — island props are a serialized
533
+ snapshot of the host, or a reference into page.data shared with every island that reads
534
+ it: the write updates nothing (or leaks into page.data). Move mutable state inside the
535
+ island component.
536
+ `,
537
+ details: () => prose`
538
+ Dev only. An island's props are a snapshot the server serialized, or a reference into
539
+ \`page.data\` that every island shares. Writing to them updates nothing on the page (or
540
+ leaks into \`page.data\`). Copy the value into the island's own \`$state\` and change that.
541
+ `
542
+ },
543
+ island_on_kit_page: {
544
+ text: (a) => prose`
545
+ island "${a.entry}" is on a csr=true page; Kit hydrates it, so the island directive is
546
+ redundant here (it behaves as a normal component).
547
+ `,
548
+ details: () => prose`
549
+ Dev only. On a csr=true page Kit hydrates the whole page, so an island there is an
550
+ ordinary component. Its \`wake\` does nothing on this page.
551
+ `
552
+ },
553
+ island_block_in_inline: {
554
+ text: (a) => prose`
555
+ island "${a.entry}" rendered a BLOCK element inline inside a <p> (or other phrasing-only
556
+ context). The browser's HTML parser hoisted that block out of the paragraph before
557
+ hydration, so this region is empty and a SECOND copy is about to mount here — the
558
+ server-rendered copy is now an orphaned sibling of the paragraph. Fix: make the component
559
+ render an inline element (e.g. <span> instead of <div>), or place the island on its own
560
+ line (block context) rather than inside a sentence.
561
+ `,
562
+ details: () => prose`
563
+ Dev only. The island renders a block element (a \`div\`, a \`p\`) inside a paragraph. The
564
+ browser's parser moves that block out of the paragraph before any script runs, so the
565
+ region is empty and a second copy mounts beside the first.
566
+
567
+ Render an inline element (a \`span\`), or place the island on its own line.
568
+ `
569
+ },
570
+ keep_without_router: {
571
+ text: (a) => prose`
572
+ island "${a.entry}" has keep:'${a.key}' but the SPA router is off
573
+ (ogygia({ router: false })) — keep relies on SPA navigation; a full-page load replaces
574
+ the DOM, so the attribute is a no-op here.
575
+ `,
576
+ details: () => prose`
577
+ Dev only. \`keep\` keeps an island across client navigations, so it needs the ogygia
578
+ router. With \`ogygia({ router: false })\` every navigation is a full page load and nothing
579
+ is kept.
580
+ `
581
+ },
582
+ live_feature_missing: {
583
+ text: () => "live region needs the live feature plugin (pushable props missing)",
584
+ details: () => prose`
585
+ Dev only. A live region woke, but the build has no live feature to hydrate it with. ${BUG}
586
+ `
587
+ },
588
+ live_region_no_host: {
589
+ text: (a) => prose`
590
+ render:'live' region "${a.id}" has no island host — on regular pages it will never
591
+ revalidate (only on documents served from a page store). Wrap it in a wake:'load' island
592
+ to drive remount revalidation.
593
+ `,
594
+ details: () => prose`
595
+ A \`render: 'live'\` lake revalidates when the island around it remounts. This one has no
596
+ island around it, so it never refreshes on a regular page. Wrap it in a
597
+ \`wake: 'load'\` island.
598
+ `
599
+ },
600
+ live_region_no_endpoint: {
601
+ text: (a) => prose`
602
+ region "${a.id}" is render:'live' but no signed endpoint was captured at SSR — painting
603
+ the cache only.
604
+ `,
605
+ details: () => prose`
606
+ Dev only. The live region has no signed address from the server render, so it shows its
607
+ cached HTML and never refreshes.
608
+ `
609
+ },
610
+ region_newer_page_data: {
611
+ text: (a) => prose`
612
+ a region came back rendered with newer page.data (${a.keys}) than this Kit page holds.
613
+ Refresh the page's data (invalidateAll()) before refreshing the region, or the islands
614
+ inside it hydrate against the older values.
615
+ `,
616
+ details: () => prose`
617
+ A region's answer was rendered against newer \`page.data\` than the Kit page in the
618
+ browser holds, so the islands inside it would hydrate against older values. Call
619
+ \`invalidateAll()\` before refreshing the region.
620
+ `
621
+ },
622
+ kit_page_waiting: {
623
+ text: (a) => prose`
624
+ islands inside a lake / hole answer on this Kit (csr=true) page have waited ${a.seconds}s
625
+ for Kit to apply its page and are still holding their server HTML.
626
+ ${a.booted ? "Kit's client entry evaluated but start() has not applied the page (status is still -1) — Kit's start() may have thrown; check the console above." : "Kit's client entry has not evaluated (no page bridge yet) — Kit's boot script may be blocked, failing, or missing."}
627
+ They hydrate the moment Kit does; nothing is discarded meanwhile.
628
+ `,
629
+ details: () => prose`
630
+ Dev only. On a csr=true page, an island inside a lake or a hole answer waits for Kit to
631
+ apply its page before it hydrates. Kit has not done so yet.
632
+
633
+ \`booted=false\`: Kit's client entry never ran; its boot script is blocked, failing or
634
+ missing. \`booted=true\`: it ran, but \`start()\` has not applied the page; it may have
635
+ thrown, so check the console above. The islands keep their server HTML meanwhile.
636
+ `
637
+ },
638
+ foreign_page_read: {
639
+ text: (a) => prose`
640
+ ${a.expr} was read inside a mounted MFE island (${a.entry}, from ${a.origin}).
641
+
642
+ In the browser this is the SHELL's page, not the MFE's. The HTML you see was rendered with
643
+ the MFE's own load data, so this island will repaint with different values after hydrate.
644
+
645
+ Pass the value as a prop, or read it with a remote function.
646
+ `,
647
+ details: () => prose`
648
+ Dev only. An island from another app (a stitched fragment) read the page store. In the
649
+ browser that is the host app's page, not the fragment's, so the island repaints with
650
+ different values after it hydrates. Pass the value as a prop, or read it with a remote
651
+ function.
652
+ `
653
+ },
654
+ context_marker_large: {
655
+ text: (a) => prose`
656
+ the island context marker is ${a.size}kB — it ships in every page's HTML. Biggest keys:
657
+ ${a.top}. Slim the values, or mark host-only keys with setContext(key, value, { islands:
658
+ false }).
659
+ `,
660
+ details: () => prose`
661
+ Dev only. Context set above islands is serialized into the page so the islands can read it,
662
+ and it has grown large. Slim the values, or keep a key on the server with
663
+ \`setContext(key, value, { islands: false })\`.
664
+ `
665
+ },
666
+ context_dropped: {
667
+ text: (a) => `context '${a.key}' could not be serialized for islands and was dropped.`,
668
+ details: () => prose`
669
+ Dev only. A context value set above islands could not be serialized, so islands do not see
670
+ it. Pass plain data, or a wired value.
671
+ `
672
+ },
673
+ context_unserializable: {
674
+ text: (a) => `context '${a.key}'${a.path ? ` @ ${a.path}` : ""}: ${a.detail}`,
675
+ details: () => prose`
676
+ Dev only. Part of a context value set above islands does not cross into them: \`path\`
677
+ names where, \`detail\` what. Pass plain data there.
678
+ `
679
+ },
680
+ page_seed_ref_missing: {
681
+ text: (a) => prose`
682
+ island props reference page.data at ${a.path} but the page seed does not carry it — the
683
+ island receives undefined there.
684
+ `,
685
+ details: () => prose`
686
+ Dev only. An island's props point into \`page.data\`, but the page did not ship that part,
687
+ so the island reads \`undefined\` there.
688
+ `
689
+ },
690
+ store_not_extensible: {
691
+ text: (a) => prose`
692
+ store "${a.tag}": the store object is not extensible (frozen/sealed), so it cannot carry
693
+ its factory brand — it will cross boundaries as a plain writable (custom methods
694
+ unavailable). Brand before freezing, or leave the store extensible.
695
+ `,
696
+ details: () => prose`
697
+ A store crosses into an island with a mark naming the factory that rebuilds it. A frozen
698
+ store cannot take the mark, so it crosses as a plain writable. Freeze it after it is
699
+ branded, or leave it extensible.
700
+ `
701
+ },
702
+ store_factory_missing: {
703
+ text: (a) => prose`
704
+ store "${a.tag}": factory not loaded in this bundle — degraded to a plain writable (custom
705
+ methods unavailable). Import the factory's module in the island (or its graph) so
706
+ \`__register_store_factory\` runs there.
707
+ `,
708
+ details: () => prose`
709
+ The island received a store whose factory module it never imports, so the store arrives
710
+ as a plain writable. Import that module in the island.
711
+ `
712
+ },
713
+ store_factory_bad_rebuild: {
714
+ text: (a) => prose`
715
+ store "${a.tag}": factory returned ${a.got} while rebuilding — degraded to a plain writable
716
+ (custom methods unavailable). A store factory must return a store on every call; move
717
+ environment guards inside the factory body.
718
+ `,
719
+ details: () => prose`
720
+ A store factory returned something other than a store while the island rebuilt it. Return
721
+ a store on every call, and put environment checks inside the factory's body.
722
+ `
723
+ },
724
+ store_factory_unbranded: {
725
+ text: (a) => prose`
726
+ store "${a.tag}": factory returned ${a.got} — nothing to brand, value passed through as-is.
727
+ Fine for a client-only store; a store that must cross an island boundary has to exist on
728
+ the server too — return e.g. writable(seed) under your guard and gate the side effects
729
+ inside the factory instead.
730
+ `,
731
+ details: () => prose`
732
+ A store factory returned something other than a store, so it cannot be marked to cross
733
+ into islands. That is fine for a store only the browser uses; to cross, the factory must
734
+ return a store on the server too.
735
+ `
736
+ },
737
+ region_promise_no_placeholder: {
738
+ text: () => prose`
739
+ <Region of={promise}> has no \`placeholder\` — the region will sit empty until the promise
740
+ resolves and its stylesheet loads. Add {#snippet placeholder()}…{/snippet} for the wait.
741
+ `,
742
+ details: () => prose`
743
+ Dev only. A region given a promise shows nothing until it resolves. Give it a
744
+ \`placeholder\` snippet for the wait.
745
+ `
746
+ },
747
+ nested_server_island_inline: {
748
+ text: (a) => prose`
749
+ nested server island "${a.entry}" is inside another island; it renders inline as frozen
750
+ HTML (no JS ships; islands inside it wake on their own) — 'deferred' ignored.
751
+ `,
752
+ details: () => prose`
753
+ Dev only. A deferred region inside an island cannot be fetched on its own, so it renders
754
+ inline as part of the island's HTML.
755
+ `
756
+ },
757
+ nested_island_with_parent: {
758
+ text: (a) => `nested island "${a.entry}" is inside another island; it hydrates with its parent (strategy ignored).`,
759
+ details: () => prose`
760
+ Dev only. An island inside an island hydrates with the outer one, so its own \`wake\` is
761
+ ignored. Put a lake (\`wake: 'none'\`) between them to give it its own schedule.
762
+ `
763
+ },
764
+ lake_mounted_without_html: {
765
+ text: (a) => prose`
766
+ lake "${a.entry}" was mounted by Kit on the client with no server HTML to adopt (a
767
+ client-side navigation, or a hydration failure — look for an error above). The runtime
768
+ restores it from its server HTML when this document rendered it; otherwise it stays empty.
769
+ A lake is server HTML: keep chrome lakes in a layout that persists across navigations, or
770
+ serve that route csr=false.
771
+ `,
772
+ details: () => prose`
773
+ Dev only. On a csr=true page Kit mounted a lake in the browser, but a lake is server HTML
774
+ and there was none to adopt. Keep such lakes in a layout that stays across navigations, or
775
+ serve the route with \`csr = false\`.
776
+ `
777
+ },
778
+ rule_region_mounted_twice: {
779
+ text: (a) => `rule broken, one mount per region: ${a.detail}`,
780
+ details: () => prose`
781
+ Dev and e2e only (a rule ogygia checks on itself). A region element holds one island at a
782
+ time, and an island whose element left the page is let go with it. One held two, or kept
783
+ its island after its element left: ${BUG}
784
+ `
785
+ },
786
+ rule_address_bar_drift: {
787
+ text: (a) => `rule broken, the address bar and the router's history agree: ${a.detail}`,
788
+ details: () => prose`
789
+ Dev and e2e only (a rule ogygia checks on itself). With no navigation out, the address bar
790
+ is the router's page on screen. They differ: a later back or forward step would show the
791
+ wrong page, or scroll to the wrong place. If the app writes \`history\` itself (outside
792
+ \`pushState\`/\`replaceState\` from \`$app/navigation\`), that is the likely cause; else
793
+ ${BUG}
794
+ `
795
+ },
796
+ rule_old_page_open: {
797
+ text: (a) => `rule broken, nothing of a page that was left stays open: ${a.detail}`,
798
+ details: () => prose`
799
+ Dev and e2e only (a rule ogygia checks on itself). Each page the router shows owns what it
800
+ starts (listeners, timers, streams), and all of it is let go when the next page takes over.
801
+ Something of an earlier page is still open: ${BUG}
802
+ `
803
+ },
804
+ rule_failure_uncoded: {
805
+ text: (a) => `rule broken, no failure leaves ogygia without a code: ${a.detail}`,
806
+ details: () => prose`
807
+ Dev and e2e only (a rule ogygia checks on itself). Every failure ogygia lets out names its
808
+ code's page, and its internal \`STALE\` answer is never a rejection. One got out without
809
+ either: ${BUG}
810
+ `
811
+ },
812
+ rule_parse_upgraded: {
813
+ text: (a) => `rule broken, a parsed answer is inert: ${a.detail}`,
814
+ details: () => prose`
815
+ Dev and e2e only (a rule ogygia checks on itself). A region or hole answer is parsed in a
816
+ document with no browsing context, so no component's constructor runs before the restore
817
+ puts the answer in the shape its components expect. An element of an answer was built
818
+ during the parse anyway: the engine built custom elements in a document that has no
819
+ registry. ${BUG}
820
+ `
821
+ },
822
+ restore_late: {
823
+ text: (a) => `<${a.host}> was upgraded before the restore reached it; its own root is kept and the server's copy of its render dropped.`,
824
+ details: () => prose`
825
+ A custom element of a reversible transform (an \`og-h\` host) already had a shadow root when
826
+ the restore reached it: a component runtime upgraded it first. The restore keeps the root
827
+ the component made, puts its light DOM back into Svelte's form (its children, its
828
+ attributes) and drops the server's rendered copy, which would otherwise show a second time
829
+ through the slot. Until the component renders, that part of the page is empty.
830
+
831
+ Load the component runtime after ogygia's restore (the handle inlines it at the end of the
832
+ body), or let it hydrate a declarative root instead of attaching its own in the
833
+ constructor. Said once per page and element name.
834
+ `
835
+ }
836
+ };
837
+ const core = /* @__PURE__ */ define_messages(import.meta.env?.DEV ? ERRORS : null, import.meta.env?.DEV ? WARNINGS : null);
838
+ /** `throw new OgygiaError(code, args)`; `warn(code, args, ...rest)` logs. Wording and link in dev,
839
+ * the link alone in a production build. */
840
+ const OgygiaError = core.OgygiaError;
841
+ const warn = core.warn;
842
+ const line = core.line;
843
+ export { ERRORS, OgygiaError, WARNINGS, line, warn };