@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
@@ -4,8 +4,8 @@ import { island_sourcemaps_plugin } from "./sourcemaps.js";
4
4
  import { server_sourcemaps_plugin } from "./server-sourcemaps.js";
5
5
  import { install_dev_client_maps, install_dev_maps, install_dev_page_keys } from "./dev-maps.js";
6
6
  import { CLIENT_BINDING_STUB, DEFAULT_IMPORT_KEYS, asRegionLocals, import_keys_hint, is_island_path, islandChunkFileName, islandId, islandPublicUrl, normalize_import_keys, wrapperVirtualId } from "../compiler/region/transform.js";
7
- import { regionId, regionIdentity, strategyKey } from "../compiler/region/identity.js";
8
7
  import { rewrite_lake_import_to_placeholder } from "../compiler/region/emit.js";
8
+ import { regionId, regionIdentity, strategyKey } from "../compiler/region/identity.js";
9
9
  import { debarrel } from "../compiler/debarrel/plugin.js";
10
10
  import { definePlugin, find_plugins, resolve_plugins } from "./plugin-api.js";
11
11
  import { assert_no_legacy_options, resolve_options, validate_region_presets } from "./options.js";
@@ -16,7 +16,7 @@ import { fill_profiler_maps } from "./profiler-maps.js";
16
16
  import { DEFAULT_REGION_TTL_SEC } from "../server/endpoint.js";
17
17
  import { RENEW_WINDOW_SEC } from "../server/shared-cache.js";
18
18
  import { derive_id_salt, secret_has_min_entropy } from "../server/hmac.js";
19
- import { buildFoucCssModuleSource, collectFoucCssReachable, compileFoucScopedCss, foucRelFromId, isFoucCssId, isFoucScopedId } from "../compiler/fouc-css.js";
19
+ import { buildFoucCssModuleSource, collectFoucCssReachable, compileFoucScopedCss, foucRelFromId, isFoucCssId, isFoucScopedId, svelteHasStyle } from "../compiler/fouc-css.js";
20
20
  import { preprocess_component_for_css } from "./style-preprocess.js";
21
21
  import { needs_csr_false_full_reload, needs_island_entry_full_reload } from "../compiler/dev/hmr.js";
22
22
  import { derive_css_scope_owners } from "../compiler/dev/css-scope.js";
@@ -34,7 +34,8 @@ import { async_twin_redirect, svelte_async_enabled } from "./late-island.js";
34
34
  import { flags_manifest } from "../compiler/flags.js";
35
35
  import { RESOLVED, V_ROUTER_CSS, V_ROUTE_CONFIG, V_ROUTE_CSR, V_SERVER_ISLANDS, V_SERVER_MANIFEST } from "../compiler/ids.js";
36
36
  import { OWN_PACKAGE_NAMES, is_own_specifier } from "../own-package.js";
37
- import { APP_SHIMS, CLIENT_BINDING_STUB_FILE, HMAC_MODULE, KIT_REMOTE_CLIENT, KIT_REMOTE_STATE, OGYGIA_INJECTED_FILES, OGYGIA_INJECTED_IMPORTS, OGYGIA_REGION_MODULES, PKG_ROOT, PKG_ROOT_ID, REGION_ENDPOINT_MODULE, RUNTIME_DIR, RUNTIME_HASH, STUB_CLIENT, STUB_PATHS, STUB_STATE, real_posix, scan_entry_pattern } from "./paths.js";
37
+ import { APP_SHIMS, CLIENT_BINDING_STUB_FILE, HMAC_MODULE, KIT_REMOTE_CLIENT, KIT_REMOTE_STATE, OGYGIA_INJECTED_FILES, OGYGIA_INJECTED_IMPORTS, OGYGIA_REGION_MODULES, OGYGIA_VERSION, PKG_ROOT, PKG_ROOT_ID, REGION_ENDPOINT_MODULE, RUNTIME_DIR, RUNTIME_HASH, STUB_CLIENT, STUB_PATHS, STUB_STATE, real_posix, scan_entry_pattern } from "./paths.js";
38
+ import { OgygiaError, line, warn } from "../messages/build.js";
38
39
  import crypto from "node:crypto";
39
40
  import fs from "node:fs";
40
41
  import path from "node:path";
@@ -44,6 +45,7 @@ import { loadEnv } from "vite";
44
45
  const KIT_CLIENT_APP_RE = /\/generated\/(?:build\/|dev\/)?client(-optimized)?\/app\.js$/;
45
46
  const ROUTE_HOST_OR_OPTION_RE = /[\\/]\+(page|layout)(\.server)?\.(svelte|js|ts)$/;
46
47
  const KIT_PAGE_THREAD = "\nimport { page as __og_kit_page, navigating as __og_kit_nav } from '$app/state';\nimport * as __og_kit_navigation from '$app/navigation';\nglobalThis[Symbol.for('ogygia.kit-page')] = { page: __og_kit_page, navigating: __og_kit_nav, navigation: __og_kit_navigation };\n";
48
+ const KIT_DISCLOSE_VERSION = `((globalThis.__ogygia ??= {}).v ??= new Set()).add(${JSON.stringify(OGYGIA_VERSION)});\n`;
47
49
  /** css-ish file the dev bridge manages (mirrors the bridge's glob). */
48
50
  const DEV_CSS_FILE_RE = /\.(css|scss|sass|less|styl)$/;
49
51
  const CSS_EXT_RE = /\.css$/;
@@ -104,6 +106,31 @@ function ogygia(options = {}) {
104
106
  let id_salt = "";
105
107
  /** content_css_key → emitted CSS asset referenceId (client leg). Resolved to hrefs in writeBundle. */
106
108
  const content_css_refs = /* @__PURE__ */ new Map();
109
+ const compiled_css = /* @__PURE__ */ new Map();
110
+ const tree_css_walk = (ctx) => {
111
+ const walk_resolve = bundler_resolve(ctx);
112
+ return async (abs, opts = {}) => {
113
+ const { own, skip } = opts;
114
+ const parts = [];
115
+ for (const e of await collectFoucCssReachable(abs, {
116
+ root,
117
+ libDir,
118
+ readFile: own == null ? readFile : (p) => p === abs ? own : readFile(p),
119
+ alias: resolve_alias,
120
+ resolve: walk_resolve
121
+ })) {
122
+ if (own != null && e.abs === abs || skip?.(e.abs)) continue;
123
+ let css = compiled_css.get(e.abs);
124
+ if (css === void 0) {
125
+ const src = readFile(e.abs);
126
+ css = src == null ? null : e.kind === "scoped" ? compileFoucScopedCss(e.abs, await preprocess_component_for_css(src, e.abs, root), { keepScript: true }) : CSS_EXT_RE.test(e.abs) ? src : null;
127
+ compiled_css.set(e.abs, css);
128
+ }
129
+ if (css) parts.push(css);
130
+ }
131
+ return parts.join("\n");
132
+ };
133
+ };
107
134
  /** router-css `rcss:<rel>` key → emitted CSS asset referenceId (client leg). A server router page
108
135
  * component's whole-tree scoped CSS, compiled + emitted as a dedicated asset (link/router-css.ts). */
109
136
  const router_css_refs = /* @__PURE__ */ new Map();
@@ -265,9 +292,11 @@ function ogygia(options = {}) {
265
292
  __OGYGIA_SERVER_DELTA__: JSON.stringify(server_delta),
266
293
  __OGYGIA_DEVTOOLS__: JSON.stringify(devtools_effective),
267
294
  __OGYGIA_DEVTOOLS_LAZY__: JSON.stringify(devtools_lazy),
295
+ __OGYGIA_RULES__: JSON.stringify(process.env.OGYGIA_RULES === "1"),
268
296
  __OGYGIA_BEACON__: JSON.stringify(measure || devtools_effective),
269
297
  __OGYGIA_CLIENT_PLUGINS__: JSON.stringify(client_plugins.length > 0),
270
- __OGYGIA_KIT_MAJOR__: JSON.stringify(kit_major(path.resolve(userConfig.root ?? ".")))
298
+ __OGYGIA_KIT_MAJOR__: JSON.stringify(kit_major(path.resolve(userConfig.root ?? "."))),
299
+ __OGYGIA_VERSION__: JSON.stringify(OGYGIA_VERSION)
271
300
  },
272
301
  server: { fs: { allow: [PKG_ROOT] } },
273
302
  build: { rolldownOptions: { preserveEntrySignatures: "exports-only" } }
@@ -280,7 +309,10 @@ function ogygia(options = {}) {
280
309
  svelte_async = svelte_async_enabled(config.plugins);
281
310
  if (config.command === "serve") {
282
311
  const own = (config.optimizeDeps?.include ?? []).filter((d) => is_own_specifier(d));
283
- if (own.length) config.logger.warn(`[ogygia] optimizeDeps.include lists ${own.join(", ")}: ogygia must not be pre-bundled in dev (the page would run two copies of its runtime, and islands with snippet props fail to hydrate). Remove ${own.length === 1 ? "it" : "them"}.`);
312
+ if (own.length) config.logger.warn(line("optimize_deps_includes_ogygia", {
313
+ specifiers: own.join(", "),
314
+ count: own.length
315
+ }));
284
316
  }
285
317
  const app_dir_define = config.define?.["__SVELTEKIT_APP_DIR__"];
286
318
  if (typeof app_dir_define === "string") try {
@@ -313,7 +345,7 @@ function ogygia(options = {}) {
313
345
  }
314
346
  const env_secret = process.env.OGYGIA_SECRET?.trim() || "";
315
347
  if (env_secret) {
316
- if (is_build && !secret_has_min_entropy(env_secret)) throw new Error(`[ogygia] OGYGIA_SECRET is too short for production builds (need ≥16 UTF-8 bytes).`);
348
+ if (is_build && !secret_has_min_entropy(env_secret)) throw new OgygiaError("secret_too_short", { min_bytes: 16 });
317
349
  id_salt = derive_id_salt(env_secret);
318
350
  } else id_salt = "";
319
351
  ({kit_wire_path, kit_remote_index, universal_hooks, client_hooks, kit_transport_init} = resolve_kit_paths(root));
@@ -393,86 +425,33 @@ function ogygia(options = {}) {
393
425
  emitRuntime: emit_runtime,
394
426
  loaded
395
427
  });
396
- if (skipped && isMainThread) console.log(`[ogygia] ${skipped} island chunk(s) not emitted: their host modules are not in the server bundle (unreachable from this build's routes).`);
428
+ if (skipped && isMainThread) console.log(line("island_chunks_not_emitted", { count: skipped }));
429
+ compiled_css.clear();
430
+ const tree_css = tree_css_walk(this);
397
431
  router_css_refs.clear();
398
- const walk_resolve = bundler_resolve(this);
399
432
  for (const abs of compiler.router_css_roots()) {
400
- const parts = [];
401
- for (const e of await collectFoucCssReachable(abs, {
402
- root,
403
- libDir,
404
- readFile,
405
- alias: resolve_alias,
406
- resolve: walk_resolve
407
- })) if (e.kind === "scoped") {
408
- const src = readFile(e.abs);
409
- if (src == null) continue;
410
- const css = compileFoucScopedCss(e.abs, await preprocess_component_for_css(src, e.abs, root), { keepScript: true });
411
- if (css) parts.push(css);
412
- } else if (CSS_EXT_RE.test(e.abs)) {
413
- const css = readFile(e.abs);
414
- if (css) parts.push(css);
415
- }
416
- if (!parts.length) continue;
417
- const ref = this.emitFile({
433
+ const source = await tree_css(abs);
434
+ if (source) router_css_refs.set(router_css_key(root, abs), this.emitFile({
418
435
  type: "asset",
419
436
  name: "og-rcss.css",
420
- source: parts.join("\n")
421
- });
422
- router_css_refs.set(router_css_key(root, abs), ref);
437
+ source
438
+ }));
423
439
  }
424
440
  hole_css_refs.clear();
425
441
  const hole_css_by_abs = /* @__PURE__ */ new Map();
426
442
  for (const { iid, abs } of compiler.server_island_css_roots()) {
427
443
  let ref = hole_css_by_abs.get(abs);
428
444
  if (ref === void 0) {
429
- const parts = [];
430
- for (const e of await collectFoucCssReachable(abs, {
431
- root,
432
- libDir,
433
- readFile,
434
- alias: resolve_alias,
435
- resolve: walk_resolve
436
- })) if (e.kind === "scoped") {
437
- const src = readFile(e.abs);
438
- if (src == null) continue;
439
- const css = compileFoucScopedCss(e.abs, await preprocess_component_for_css(src, e.abs, root), { keepScript: true });
440
- if (css) parts.push(css);
441
- } else if (CSS_EXT_RE.test(e.abs)) {
442
- const css = readFile(e.abs);
443
- if (css) parts.push(css);
444
- }
445
- ref = parts.length ? this.emitFile({
445
+ const source = await tree_css(abs);
446
+ ref = source ? this.emitFile({
446
447
  type: "asset",
447
448
  name: "og-hole.css",
448
- source: parts.join("\n")
449
+ source
449
450
  }) : "";
450
451
  hole_css_by_abs.set(abs, ref);
451
452
  }
452
453
  if (ref) hole_css_refs.set(iid, ref);
453
454
  }
454
- content_css_refs.clear();
455
- const styles = markup.flatMap((m) => m.styles ? [...m.styles] : []);
456
- if (styles.length) {
457
- const { compile } = await import("svelte/compiler");
458
- for (const [abs, source] of styles) try {
459
- const { css } = compile(source, {
460
- filename: abs,
461
- css: "external",
462
- dev: false,
463
- generate: "client",
464
- experimental: { async: true }
465
- });
466
- if (css?.code) {
467
- const ref = this.emitFile({
468
- type: "asset",
469
- name: "og-content.css",
470
- source: css.code
471
- });
472
- content_css_refs.set(content_css_key(abs), ref);
473
- }
474
- } catch {}
475
- }
476
455
  }
477
456
  },
478
457
  configureServer(server) {
@@ -532,7 +511,7 @@ function ogygia(options = {}) {
532
511
  fs.mkdirSync(path.dirname(handoff), { recursive: true });
533
512
  fs.writeFileSync(handoff, JSON.stringify(compiler.ssr_transformed_hosts()));
534
513
  } catch (e) {
535
- if (isMainThread) console.warn("[ogygia] could not write the server-leg island handoff:", e);
514
+ if (isMainThread) warn("island_handoff_write_failed", e);
536
515
  }
537
516
  if (__P) {
538
517
  const keys = [...__outHash.keys()].sort();
@@ -599,7 +578,7 @@ function ogygia(options = {}) {
599
578
  }
600
579
  const ssr = options?.ssr === true;
601
580
  if (!ssr && source === "__sveltekit/remote") {
602
- if (!kit_remote_index) throw new Error("[ogygia] could not locate Kit's client remote-functions (src). Use an @sveltejs/kit that publishes its `src/` (2.70.2 or later, or 3.x).");
581
+ if (!kit_remote_index) throw new OgygiaError("kit_remote_src_missing");
603
582
  return kit_remote_index;
604
583
  }
605
584
  if (!ssr && importer && importer.includes("/remote-functions/")) {
@@ -669,7 +648,7 @@ function ogygia(options = {}) {
669
648
  },
670
649
  async transform(code, id, options) {
671
650
  let source = code;
672
- if (!options?.ssr && KIT_CLIENT_APP_RE.test(id)) source += KIT_PAGE_THREAD;
651
+ if (!options?.ssr && KIT_CLIENT_APP_RE.test(id)) source += KIT_PAGE_THREAD + KIT_DISCLOSE_VERSION;
673
652
  const result = await compiler.transform_module(source, id, {
674
653
  ssr: options?.ssr === true,
675
654
  emitFile: (chunk) => this.emitFile(chunk)
@@ -699,13 +678,43 @@ function ogygia(options = {}) {
699
678
  chunkFileNames: ours(output.chunkFileNames, "[name]-[hash].js")
700
679
  };
701
680
  },
702
- generateBundle() {
681
+ async generateBundle() {
703
682
  if (!is_build || server_leg_of(this)) return;
704
683
  for (const file of compiler.location_maps((ref) => this.getFileName(ref))) this.emitFile({
705
684
  type: "asset",
706
685
  fileName: file.fileName,
707
686
  source: file.source
708
687
  });
688
+ content_css_refs.clear();
689
+ const modules = markup.flatMap((m) => m.modules ? [...m.modules] : []);
690
+ if (!modules.length) return;
691
+ const client = /* @__PURE__ */ new Set();
692
+ for (const id of this.getModuleIds()) client.add(path.normalize(id.split("?")[0]));
693
+ const tree_css = tree_css_walk(this);
694
+ const { compile } = await import("svelte/compiler");
695
+ for (const [abs, source] of modules) try {
696
+ let own = "";
697
+ if (svelteHasStyle(source)) {
698
+ const { css } = compile(source, {
699
+ filename: abs,
700
+ css: "external",
701
+ dev: false,
702
+ generate: "client",
703
+ experimental: { async: true }
704
+ });
705
+ own = css?.code ?? "";
706
+ }
707
+ const tree = await tree_css(abs, {
708
+ own: source,
709
+ skip: (p) => client.has(p)
710
+ });
711
+ const css = [own, tree].filter(Boolean).join("\n");
712
+ if (css) content_css_refs.set(content_css_key(abs), this.emitFile({
713
+ type: "asset",
714
+ name: "og-content.css",
715
+ source: css
716
+ }));
717
+ } catch {}
709
718
  },
710
719
  closeBundle: {
711
720
  order: "pre",
@@ -737,7 +746,7 @@ function ogygia(options = {}) {
737
746
  fs.mkdirSync(dir, { recursive: true });
738
747
  const manifest = flags_manifest(program.flag_sites);
739
748
  fs.writeFileSync(path.join(dir, "flags-manifest.json"), JSON.stringify(manifest, null, " ") + "\n");
740
- console.log(`[ogygia] flags manifest: ${manifest.names.length} flag(s) → node_modules/.ogygia/flags-manifest.json`);
749
+ console.log(line("flags_manifest_written", { count: manifest.names.length }));
741
750
  } catch {}
742
751
  await follow_pending_page_calls(program, (s, importer) => this.resolve(s, importer));
743
752
  const remote_hash = (id) => remote_hash_of(id, process.cwd());
@@ -1,4 +1,5 @@
1
1
  import { DEFAULT_KIT_DIRS, set_kit_dirs, set_kit_inline_style_threshold } from "../compiler/kit.js";
2
+ import { warn } from "../messages/build.js";
2
3
  import { existsSync } from "node:fs";
3
4
  import path from "node:path";
4
5
  import { pathToFileURL } from "node:url";
@@ -47,7 +48,12 @@ async function kit_options_from_file(root) {
47
48
  try {
48
49
  return (await import(pathToFileURL(file).href)).default?.kit ?? {};
49
50
  } catch (e) {
50
- console.warn(`[ogygia] could not read ${path.relative(root, file)} for kit.files.routes / kit.outDir — using the defaults (${DEFAULT_KIT_DIRS.routes}, ${DEFAULT_KIT_DIRS.out}). ${e instanceof Error ? e.message : String(e)}`);
51
+ warn("kit_config_unreadable", {
52
+ file: path.relative(root, file),
53
+ routes: DEFAULT_KIT_DIRS.routes,
54
+ out: DEFAULT_KIT_DIRS.out,
55
+ reason: e instanceof Error ? e.message : String(e)
56
+ });
51
57
  return null;
52
58
  }
53
59
  }
@@ -178,7 +178,8 @@ export interface OgygiaOptions {
178
178
  */
179
179
  standalone?: boolean;
180
180
  }
181
- /** The rename map: a legacy key errors with its new spelling, never silently no-ops. */
181
+ /** The rename map (`RETIRED_OPTIONS`, with the messages): a legacy key errors with its new
182
+ * spelling, never silently no-ops. */
182
183
  export declare function assert_no_legacy_options(options: OgygiaOptions): void;
183
184
  /**
184
185
  * Config-time region-preset validation — the transform re-checks on USE (with file/line context), but
@@ -1,22 +1,9 @@
1
+ import { OgygiaError, RETIRED_OPTIONS } from "../messages/build.js";
1
2
  // src/vite/options.ts
2
- /**
3
- * Retired option spellings. Detected at config load and answered with the exact new spelling — a
4
- * rename map, never silent aliasing (a legacy key that silently did nothing would un-tune real apps).
5
- */
6
- const LEGACY_OPTION_RENAMES = {
7
- regions: "`regions` is gone — its keys sit at the root now: write `visible`, `presets`, `ttl` and `maxPageAge` directly in `ogygia({ … })`.",
8
- continuity: "`continuity` is gone — form continuity rides the router. Write `router: { forms: false }` to disable it.",
9
- regionTtl: "`regionTtl` is `ttl` now — write `ogygia({ ttl: … })`.",
10
- preload: "`preload` is gone — there is nothing to choose any more. The page carries each island’s chunk list as data, and the runtime preloads an island’s whole graph when it wakes (after the page has painted), so no island code moves before its wake and none waits on a waterfall after it. Remove the key.",
11
- plugins: "`plugins` is gone — ogygia plugins are Vite plugins: list them beside `ogygia()` in vite.config, `plugins: [ogygia(), flags(), sveltekit()]`.",
12
- freeze: "`freeze` is a plugin now, named postrender — install `@ogygia/postrender` and list `postrender({ ttl, default })` (from `@ogygia/postrender/vite`) beside `ogygia()` in vite.config `plugins`.",
13
- content: "`content` is a plugin now — install `@ogygia/content` and list `content({ markdown, presets })` (from `@ogygia/content/vite`) beside `ogygia()` in vite.config `plugins`; the svelte config takes `preprocess()` / `extensions()` from there too.",
14
- devtools: "`devtools` is a plugin now — install `@ogygia/devtools` and list `devtools()` (from `@ogygia/devtools/vite`) beside `ogygia()` in vite.config `plugins`; only where you want it, e.g. `...(mode !== 'production' ? [devtools()] : [])`.",
15
- profiler: "`profiler` is part of the devtools plugin now — install `@ogygia/devtools` and list `devtools({ profiler: { … } })` (from `@ogygia/devtools/vite`) beside `ogygia()` in vite.config `plugins`."
16
- };
17
- /** The rename map: a legacy key errors with its new spelling, never silently no-ops. */
3
+ /** The rename map (`RETIRED_OPTIONS`, with the messages): a legacy key errors with its new
4
+ * spelling, never silently no-ops. */
18
5
  function assert_no_legacy_options(options) {
19
- for (const key of Object.keys(LEGACY_OPTION_RENAMES)) if (key in options) throw new Error(`[ogygia] ${LEGACY_OPTION_RENAMES[key]}`);
6
+ for (const key of Object.keys(RETIRED_OPTIONS)) if (key in options) throw new OgygiaError("option_retired", { option: key });
20
7
  }
21
8
  const REGION_PRESET_KEYS = /* @__PURE__ */ new Set([
22
9
  "render",
@@ -36,8 +23,12 @@ const REGION_PRESET_KEYS = /* @__PURE__ */ new Set([
36
23
  */
37
24
  function validate_region_presets(presets) {
38
25
  for (const [name, bag] of Object.entries(presets)) {
39
- if (!bag || typeof bag !== "object" || Object.keys(bag).length === 0) throw new Error(`[ogygia] presets.${name} is empty — a preset with nothing is a mistake.`);
40
- for (const k of Object.keys(bag)) if (!REGION_PRESET_KEYS.has(k)) throw new Error(`[ogygia] presets.${name}: unknown key \`${k}\`. A preset takes ${[...REGION_PRESET_KEYS].join(", ")}.`);
26
+ if (!bag || typeof bag !== "object" || Object.keys(bag).length === 0) throw new OgygiaError("preset_empty", { name });
27
+ for (const k of Object.keys(bag)) if (!REGION_PRESET_KEYS.has(k)) throw new OgygiaError("preset_key_unknown", {
28
+ name,
29
+ key: k,
30
+ allowed: [...REGION_PRESET_KEYS].join(", ")
31
+ });
41
32
  }
42
33
  }
43
34
  /**
@@ -57,7 +48,7 @@ function resolve_options(options, defaultRegionTtl, defaultRenewWindow = 691200)
57
48
  const session_cookie = typeof options.sessionCookie === "string" && options.sessionCookie.length > 0 ? options.sessionCookie : "";
58
49
  const region_ttl = Math.min(86400, Math.max(60, Math.floor(options.ttl ?? defaultRegionTtl)));
59
50
  const renew_raw = options.maxPageAge;
60
- if (renew_raw !== void 0 && !(typeof renew_raw === "number" && Number.isFinite(renew_raw) && renew_raw >= 0)) throw new Error(`[ogygia] maxPageAge must be a number of seconds ≥ 0 (got ${String(renew_raw)}). Write e.g. \`30 * 24 * 3600\` for 30 days, or \`0\` to turn renewal off.`);
51
+ if (renew_raw !== void 0 && !(typeof renew_raw === "number" && Number.isFinite(renew_raw) && renew_raw >= 0)) throw new OgygiaError("max_page_age_invalid", { value: String(renew_raw) });
61
52
  const renew_window = Math.min(31536e4, Math.floor(renew_raw ?? defaultRenewWindow));
62
53
  const router_enabled = options.router !== false;
63
54
  return {
@@ -1,4 +1,5 @@
1
1
  import { OWN_PACKAGE_NAMES } from "../own-package.js";
2
+ import { OgygiaError, warn } from "../messages/build.js";
2
3
  import fs from "node:fs";
3
4
  import path from "node:path";
4
5
  import { globSync } from "tinyglobby";
@@ -37,7 +38,10 @@ function discover_package_files(app_root) {
37
38
  const pkg_dir = path.join(app_root, "node_modules", ...name.split("/"));
38
39
  const declared = (read_manifest(pkg_dir)?.ogygia)?.files;
39
40
  if (declared == null) continue;
40
- if (!Array.isArray(declared) || !declared.every((p) => typeof p === "string")) throw new Error(`[ogygia] ${name}: \`"ogygia": { "files": […] }\` must be an array of package-relative paths/globs (like npm's "files") — got ${JSON.stringify(declared)}.`);
41
+ if (!Array.isArray(declared) || !declared.every((p) => typeof p === "string")) throw new OgygiaError("package_files_not_array", {
42
+ package: name,
43
+ got: JSON.stringify(declared)
44
+ });
41
45
  let root;
42
46
  try {
43
47
  root = fs.realpathSync(pkg_dir);
@@ -61,12 +65,18 @@ function discover_package_files(app_root) {
61
65
  continue;
62
66
  }
63
67
  const abs = path.resolve(root, entry);
64
- if (abs !== root && !abs.startsWith(root + path.sep)) throw new Error(`[ogygia] ${name}: ogygia.files entry '${entry}' escapes the package.`);
68
+ if (abs !== root && !abs.startsWith(root + path.sep)) throw new OgygiaError("package_files_escapes", {
69
+ package: name,
70
+ entry
71
+ });
65
72
  let stat;
66
73
  try {
67
74
  stat = fs.statSync(abs);
68
75
  } catch {
69
- console.warn(`[ogygia] ${name}: ogygia.files entry '${entry}' does not exist — skipped.`);
76
+ warn("package_files_missing", {
77
+ package: name,
78
+ entry
79
+ });
70
80
  continue;
71
81
  }
72
82
  if (stat.isDirectory()) dirs.push(posix(fs.realpathSync(abs)));
@@ -1,6 +1,8 @@
1
1
  /** This package's root (the plugin runs from `dist/vite/`, so `../..` is the package root). A NATIVE
2
2
  * path (backslashes on Windows): for the file system, never to compare against a module id. */
3
3
  export declare const PKG_ROOT: string;
4
+ /** This package's version, as installed (the runtime discloses it: runtime/disclose-version.ts). */
5
+ export declare const OGYGIA_VERSION: string;
4
6
  /** A native path as Vite writes module ids: symlinks resolved (pnpm), forward slashes (Windows). */
5
7
  export declare function real_posix(p: string): string;
6
8
  /** A native directory as the PREFIX of the module ids inside it: `real_posix` + one trailing `/`, so a
@@ -12,6 +12,8 @@ import { fileURLToPath } from "node:url";
12
12
  /** This package's root (the plugin runs from `dist/vite/`, so `../..` is the package root). A NATIVE
13
13
  * path (backslashes on Windows): for the file system, never to compare against a module id. */
14
14
  const PKG_ROOT = fileURLToPath(new URL("../..", import.meta.url));
15
+ /** This package's version, as installed (the runtime discloses it: runtime/disclose-version.ts). */
16
+ const OGYGIA_VERSION = JSON.parse(fs.readFileSync(path.join(PKG_ROOT, "package.json"), "utf8")).version;
15
17
  /** Windows separators → posix. */
16
18
  const WIN_SEP_RE = /\\/g;
17
19
  /** A native path as Vite writes module ids: symlinks resolved (pnpm), forward slashes (Windows). */
@@ -93,9 +95,7 @@ function runtime_content_hash() {
93
95
  fileURLToPath(new URL("../keep-fallback-marker.js", import.meta.url)),
94
96
  fileURLToPath(new URL("../shims/page-store.svelte.js", import.meta.url)),
95
97
  fileURLToPath(new URL("../shims/kit-remote/client-stub.js", import.meta.url)),
96
- fileURLToPath(new URL("../NestedProvider.svelte", import.meta.url)),
97
- fileURLToPath(new URL("../LiveHost.svelte", import.meta.url)),
98
- fileURLToPath(new URL("../KeepHost.svelte", import.meta.url))
98
+ fileURLToPath(new URL("../nested.js", import.meta.url))
99
99
  ];
100
100
  try {
101
101
  const rt_dir = fileURLToPath(new URL("../runtime", import.meta.url));
@@ -109,4 +109,4 @@ function runtime_content_hash() {
109
109
  }
110
110
  /** The runtime chunk's source-content hash (the immutable-filename base; feature hash rides on top). */
111
111
  const RUNTIME_HASH = runtime_content_hash();
112
- export { APP_SHIMS, CLIENT_BINDING_STUB_FILE, HMAC_MODULE, KIT_REMOTE_CLIENT, KIT_REMOTE_STATE, OGYGIA_INJECTED_FILES, OGYGIA_INJECTED_IMPORTS, OGYGIA_REGION_MODULES, PKG_ROOT, PKG_ROOT_ID, REGION_ENDPOINT_MODULE, RUNTIME_DIR, RUNTIME_HASH, STUB_CLIENT, STUB_PATHS, STUB_STATE, id_dir, real_posix, scan_entry_pattern };
112
+ export { APP_SHIMS, CLIENT_BINDING_STUB_FILE, HMAC_MODULE, KIT_REMOTE_CLIENT, KIT_REMOTE_STATE, OGYGIA_INJECTED_FILES, OGYGIA_INJECTED_IMPORTS, OGYGIA_REGION_MODULES, OGYGIA_VERSION, PKG_ROOT, PKG_ROOT_ID, REGION_ENDPOINT_MODULE, RUNTIME_DIR, RUNTIME_HASH, STUB_CLIENT, STUB_PATHS, STUB_STATE, id_dir, real_posix, scan_entry_pattern };
@@ -40,7 +40,7 @@ export interface MacroContext {
40
40
  readonly markupExts: readonly string[];
41
41
  }
42
42
  /** A source format that becomes Svelte only through a preprocessor (markdown → Svelte): how its
43
- * islands and its modules' own scoped CSS reach the build. */
43
+ * islands and its modules' CSS reach the build. */
44
44
  export interface MarkupSource {
45
45
  /** The format's file extensions (`['.svx', '.md']`). */
46
46
  extensions: readonly string[];
@@ -50,10 +50,11 @@ export interface MarkupSource {
50
50
  root: string;
51
51
  readFile(abs: string): string | null;
52
52
  }): void | Promise<void>;
53
- /** Modules that carry their OWN scoped `<style>`, absolute path → their post-preprocess Svelte
54
- * source: the build compiles each one's CSS and ships it as a client asset (the module itself
55
- * only ever renders on the server). The plugin keeps filling this map; the build reads it late. */
56
- styles?: ReadonlyMap<string, string>;
53
+ /** The format's modules, absolute path → their post-preprocess Svelte source. A module only ever
54
+ * renders on the server, so no client chunk carries its CSS: the build ships, as one client asset
55
+ * per module, the scoped CSS of its own `<style>` and of every component it imports (and plain
56
+ * style imports). The plugin keeps filling this map; the build reads it late. */
57
+ modules?: ReadonlyMap<string, string>;
57
58
  }
58
59
  /** What the build hands back for a markup source: run the region transform on preprocessed Svelte. */
59
60
  export interface MarkupRegions {
@@ -1,3 +1,4 @@
1
+ import { OgygiaError } from "../messages/build.js";
1
2
  import { createRequire } from "node:module";
2
3
  import fs from "node:fs";
3
4
  import path from "node:path";
@@ -34,7 +35,7 @@ function definePlugin(definition) {
34
35
  name: definition.name,
35
36
  [PLUGIN]: definition,
36
37
  configResolved(config) {
37
- if (!config.plugins.some((p) => p.name === OGYGIA_VITE_PLUGIN)) throw new Error(`[ogygia] \`${definition.name}\` is listed in vite.config but \`ogygia()\` is not — add \`ogygia()\` from \`ogygia/vite\` to \`plugins\`.`);
38
+ if (!config.plugins.some((p) => p.name === OGYGIA_VITE_PLUGIN)) throw new OgygiaError("plugin_without_ogygia", { plugin: definition.name });
38
39
  }
39
40
  };
40
41
  }
@@ -53,13 +54,13 @@ async function find_plugins(list) {
53
54
  for (const item of value) await walk(item);
54
55
  return;
55
56
  }
56
- if (typeof value === "function") throw new Error("[ogygia] a function is listed in vite.config `plugins` — call the factory: `flags()`, not `flags`.");
57
+ if (typeof value === "function") throw new OgygiaError("plugin_factory_not_called");
57
58
  const plugin = value;
58
59
  const name = typeof plugin?.name === "string" ? plugin.name : "";
59
60
  const definition = plugin?.[PLUGIN];
60
61
  if (name.startsWith(KIT_VITE_PLUGIN_PREFIX)) kit_seen = true;
61
62
  const own = name === OGYGIA_VITE_PLUGIN;
62
- if ((own || definition) && kit_seen) throw new Error(`[ogygia] \`${own ? "ogygia()" : String(definition?.name)}\` is listed after \`sveltekit()\` in vite.config — list \`ogygia()\` and its plugins first: \`plugins: [ogygia(), flags(), sveltekit()]\`.`);
63
+ if ((own || definition) && kit_seen) throw new OgygiaError("plugin_after_sveltekit", { plugin: own ? "ogygia()" : String(definition?.name) });
63
64
  if (definition) found.push(definition);
64
65
  };
65
66
  await walk(list);
@@ -90,14 +91,17 @@ function check_plugins(plugins) {
90
91
  const seen = /* @__PURE__ */ new Set();
91
92
  for (const p of plugins) {
92
93
  const plugin = p;
93
- if (!plugin || typeof plugin !== "object" || typeof plugin.name !== "string" || plugin.name === "") throw new Error("[ogygia] a plugin definition needs a `name` (its package name).");
94
- if (seen.has(plugin.name)) throw new Error(`[ogygia] plugin \`${plugin.name}\` is listed twice.`);
94
+ if (!plugin || typeof plugin !== "object" || typeof plugin.name !== "string" || plugin.name === "") throw new OgygiaError("plugin_name_missing");
95
+ if (seen.has(plugin.name)) throw new OgygiaError("plugin_listed_twice", { plugin: plugin.name });
95
96
  seen.add(plugin.name);
96
- for (const realm of ["server", "client"]) if (plugin[realm] !== void 0 && typeof plugin[realm] !== "string") throw new Error(`[ogygia] plugin \`${plugin.name}\`: \`${realm}\` is a module location — \`import.meta.resolve('./${realm}.ts')\`.`);
97
+ for (const realm of ["server", "client"]) if (plugin[realm] !== void 0 && typeof plugin[realm] !== "string") throw new OgygiaError("plugin_realm_not_location", {
98
+ plugin: plugin.name,
99
+ realm
100
+ });
97
101
  if (plugin.options !== void 0) try {
98
102
  JSON.stringify(plugin.options);
99
103
  } catch {
100
- throw new Error(`[ogygia] plugin \`${plugin.name}\`: \`options\` must be plain JSON (configure live objects in hooks.server.ts).`);
104
+ throw new OgygiaError("plugin_options_not_json", { plugin: plugin.name });
101
105
  }
102
106
  }
103
107
  return plugins;
@@ -108,7 +112,11 @@ function realm_path(plugin, realm) {
108
112
  const where = plugin[realm];
109
113
  if (where === void 0) return null;
110
114
  const abs = where.startsWith("file:") ? fileURLToPath(where) : where;
111
- if (!path.isAbsolute(abs) || !fs.existsSync(abs)) throw new Error(`[ogygia] plugin \`${plugin.name}\`: its \`${realm}\` realm \`${where}\` is not a file — resolve it next to the factory: \`import.meta.resolve('./${realm}.ts')\`.`);
115
+ if (!path.isAbsolute(abs) || !fs.existsSync(abs)) throw new OgygiaError("plugin_realm_not_file", {
116
+ plugin: plugin.name,
117
+ realm,
118
+ location: where
119
+ });
112
120
  return abs.split(path.sep).join("/");
113
121
  }
114
122
  function package_resolves(req, name) {
@@ -145,7 +153,10 @@ function resolve_plugins(plugins, root, dev, markup_transform = () => null) {
145
153
  const config_owner = /* @__PURE__ */ new Map();
146
154
  const macro_owner = /* @__PURE__ */ new Map();
147
155
  for (const plugin of ordered) {
148
- if (!package_resolves(req, plugin.name)) throw new Error(`[ogygia] plugin \`${plugin.name}\`: no package by that name resolves from ${root} — its name must be its package name.`);
156
+ if (!package_resolves(req, plugin.name)) throw new OgygiaError("plugin_package_unresolved", {
157
+ plugin: plugin.name,
158
+ root
159
+ });
149
160
  const server = realm_path(plugin, "server");
150
161
  if (server) out.servers.push({
151
162
  name: plugin.name,
@@ -158,9 +169,16 @@ function resolve_plugins(plugins, root, dev, markup_transform = () => null) {
158
169
  root,
159
170
  dev,
160
171
  routeConfig(key) {
161
- if (!ROUTE_CONFIG_KEY_RE.test(key)) throw new Error(`[ogygia] plugin \`${plugin.name}\`: route config key \`${key}\` must be a camelCase identifier.`);
172
+ if (!ROUTE_CONFIG_KEY_RE.test(key)) throw new OgygiaError("route_config_key_invalid", {
173
+ plugin: plugin.name,
174
+ key
175
+ });
162
176
  const owner = config_owner.get(key);
163
- if (owner && owner !== plugin.name) throw new Error(`[ogygia] route config key \`${key}\` is claimed by both \`${owner}\` and \`${plugin.name}\`.`);
177
+ if (owner && owner !== plugin.name) throw new OgygiaError("route_config_key_claimed", {
178
+ key,
179
+ owner,
180
+ plugin: plugin.name
181
+ });
164
182
  if (!owner) {
165
183
  config_owner.set(key, plugin.name);
166
184
  out.route_config.push(key);
@@ -170,9 +188,16 @@ function resolve_plugins(plugins, root, dev, markup_transform = () => null) {
170
188
  out.foreign_hydrate = true;
171
189
  },
172
190
  macro(name, handler) {
173
- if (!MACRO_NAME_RE.test(name) || CORE_MACROS.has(name)) throw new Error(`[ogygia] plugin \`${plugin.name}\`: macro \`import.meta.og.${name}\` must be a camelCase name core does not own.`);
191
+ if (!MACRO_NAME_RE.test(name) || CORE_MACROS.has(name)) throw new OgygiaError("plugin_macro_name_invalid", {
192
+ plugin: plugin.name,
193
+ name
194
+ });
174
195
  const owner = macro_owner.get(name);
175
- if (owner) throw new Error(`[ogygia] macro \`import.meta.og.${name}\` is claimed by both \`${owner}\` and \`${plugin.name}\`.`);
196
+ if (owner) throw new OgygiaError("plugin_macro_claimed", {
197
+ name,
198
+ owner,
199
+ plugin: plugin.name
200
+ });
176
201
  macro_owner.set(name, plugin.name);
177
202
  out.macros.push({
178
203
  name,
@@ -201,7 +226,10 @@ function resolve_plugins(plugins, root, dev, markup_transform = () => null) {
201
226
  pageModules(modules) {
202
227
  for (const spec of modules.importers ?? []) if (!out.page_modules.importers.includes(spec)) out.page_modules.importers.push(spec);
203
228
  for (const file of modules.files ?? []) {
204
- if (!path.isAbsolute(file)) throw new Error(`[ogygia] plugin \`${plugin.name}\`: \`pageModules({ files })\` takes absolute paths (got \`${file}\`).`);
229
+ if (!path.isAbsolute(file)) throw new OgygiaError("page_modules_not_absolute", {
230
+ plugin: plugin.name,
231
+ file
232
+ });
205
233
  if (!out.page_modules.files.includes(file)) out.page_modules.files.push(file);
206
234
  }
207
235
  }
@@ -1,3 +1,4 @@
1
+ import { warn } from "../messages/build.js";
1
2
  import { createRequire } from "node:module";
2
3
  import path from "node:path";
3
4
  // src/vite/style-preprocess.ts
@@ -52,7 +53,7 @@ async function preprocess_component_for_css(source, abs, root) {
52
53
  if (!compiler) {
53
54
  if (!sass_warned) {
54
55
  sass_warned = true;
55
- console.warn("[ogygia] a server-rendered component has `<style lang=\"scss\">` but neither `sass-embedded` nor `sass` is installed — its hole/router CSS ships unprocessed");
56
+ warn("sass_missing");
56
57
  }
57
58
  } else out = out.replace(STYLE_BLOCK_G, (whole, attrs, body) => {
58
59
  const lang = STYLE_LANG_ATTR.exec(attrs)?.[1]?.toLowerCase();
@@ -70,7 +71,10 @@ async function preprocess_component_for_css(source, abs, root) {
70
71
  });
71
72
  return `<style${attrs.replace(STYLE_LANG_ATTR, "")}>${css}</style>`;
72
73
  } catch (err) {
73
- console.warn(`[ogygia] ${path.relative(root, abs)}: scss compile failed — ${err.message}`);
74
+ warn("scss_compile_failed", {
75
+ file: path.relative(root, abs),
76
+ reason: err.message
77
+ });
74
78
  return whole;
75
79
  }
76
80
  });
@@ -86,7 +90,10 @@ async function preprocess_component_for_css(source, abs, root) {
86
90
  const { code } = await ts(body, abs + ".ts");
87
91
  out = out.replace(whole, `<script${attrs}>${code}<\/script>`);
88
92
  } catch (err) {
89
- console.warn(`[ogygia] ${path.relative(root, abs)}: TypeScript strip failed — ${err.message}`);
93
+ warn("ts_strip_failed", {
94
+ file: path.relative(root, abs),
95
+ reason: err.message
96
+ });
90
97
  }
91
98
  }
92
99
  }