@skgo/sveltekit-adapter 0.31.0 → 0.32.1

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skgo/sveltekit-adapter",
3
- "version": "0.31.0",
3
+ "version": "0.32.1",
4
4
  "description": "SvelteKit adapter for skgo: builds a frontend that a Go binary renders and answers",
5
5
  "keywords": [
6
6
  "adapter",
@@ -23,7 +23,7 @@ import {
23
23
  import { HandledHttpError } from '@sveltejs/kit/internal';
24
24
  import * as devalue from 'skgo:devalue';
25
25
  import { decoders, init_transport, parse } from 'skgo:kit/transport';
26
- import { components, universalLoads } from 'skgo:nodes';
26
+ import { componentLoaders, universalLoaders } from 'skgo:nodes';
27
27
  import { transport } from 'skgo:hooks';
28
28
  import { serialize_data } from 'skgo:kit/serialize-data';
29
29
  import { create_universal_fetch } from 'skgo:kit/load-data';
@@ -227,13 +227,18 @@ async function build_props(req, url, event, state, fetched, serialized) {
227
227
  };
228
228
 
229
229
  const branch = req.branch ?? [];
230
- const error_components = (req.error_components ?? []).map((i) =>
231
- i == null ? undefined : components[i]
232
- );
230
+ const error_components = await Promise.all((req.error_components ?? []).map(async (i) => {
231
+ try {
232
+ return i == null ? undefined : await componentLoaders[i]?.();
233
+ } catch {
234
+ // Kit skips error components that cannot load (runtime/error-chain.js).
235
+ return undefined;
236
+ }
237
+ }));
233
238
 
234
239
  const props = new Props({
235
240
  page,
236
- tree: new RenderNode(components[branch[0].node], undefined),
241
+ tree: new RenderNode(await componentLoaders[branch[0].node]?.(), undefined),
237
242
  form,
238
243
  error: req.error ?? undefined
239
244
  });
@@ -243,7 +248,7 @@ async function build_props(req, url, event, state, fetched, serialized) {
243
248
 
244
249
  for (let i = 0; i < branch.length; i += 1) {
245
250
  const server_data = node_data(branch[i]);
246
- const load = universalLoads[branch[i].node];
251
+ const load = await universalLoaders[branch[i].node]?.();
247
252
  const parent_data = data;
248
253
  const result = load
249
254
  ? await with_request_store({ event, state }, () =>
@@ -270,7 +275,7 @@ async function build_props(req, url, event, state, fetched, serialized) {
270
275
 
271
276
  if (i < branch.length - 1) {
272
277
  current_node = current_node.child = new RenderNode(
273
- components[branch[i + 1].node],
278
+ await componentLoaders[branch[i + 1].node]?.(),
274
279
  error_components[i + 1]
275
280
  );
276
281
  }
@@ -11,6 +11,7 @@ export function protectEnvironmentFiles({ root, kitOut, output, base = '/', toke
11
11
  const files = [
12
12
  resolve(root, '.svelte-kit/skgo-env-values.js'),
13
13
  resolve(root, '.svelte-kit/skgo-env-runtime.json'),
14
+ resolve(root, '.svelte-kit/skgo-dev-supervisor.json'),
14
15
  resolve(root, kitOut, 'generated/build/env/config.js'),
15
16
  resolve(root, kitOut, 'generated/dev/env/config.js'),
16
17
  resolve(root, output, 'env.json')
@@ -29,7 +29,7 @@ import { execFileSync } from 'node:child_process';
29
29
  import { createHash, randomBytes } from 'node:crypto';
30
30
  import { protectEnvironmentFiles } from './env-private.js';
31
31
  import { existsSync, readdirSync, readFileSync, realpathSync, rmSync, statSync, mkdirSync, writeFileSync, chmodSync } from 'node:fs';
32
- import { dirname, isAbsolute, join, relative, resolve } from 'node:path';
32
+ import { dirname, isAbsolute, join, posix as posixPath, relative, resolve } from 'node:path';
33
33
  import { fileURLToPath, pathToFileURL } from 'node:url';
34
34
 
35
35
  /**
@@ -460,7 +460,7 @@ export function nodeTable(root, nodes) {
460
460
  nodes.forEach((node, i) => {
461
461
  if (node.universal) {
462
462
  imports.push(`import * as U${i} from ${JSON.stringify(join(root, node.universal))};`);
463
- loads.push(`U${i}.load`);
463
+ loads.push(`() => U${i}.load`);
464
464
  } else {
465
465
  loads.push('undefined');
466
466
  }
@@ -469,9 +469,9 @@ export function nodeTable(root, nodes) {
469
469
  return;
470
470
  }
471
471
  imports.push(`import N${i} from ${JSON.stringify(join(root, node.component))};`);
472
- table.push(`N${i}`);
472
+ table.push(`() => N${i}`);
473
473
  });
474
- return `${imports.join('\n')}\nexport const components = [${table.join(', ')}];\nexport const universalLoads = [${loads.join(', ')}];\n`;
474
+ return `${imports.join('\n')}\nexport const componentLoaders = [${table.join(', ')}];\nexport const universalLoaders = [${loads.join(', ')}];\n`;
475
475
  }
476
476
 
477
477
  /**
@@ -613,26 +613,21 @@ function posix(p) {
613
613
  */
614
614
  function devNodeTable(manifest, root) {
615
615
  if (!manifest) throw new Error('skgo: the live Kit manifest is not ready');
616
- /** @type {string[]} */
617
- const imports = [];
618
- /** @type {string[]} */
619
- const table = [];
616
+ const components = [];
620
617
  const loads = [];
621
- for (const [index, node] of manifest.nodes.entries()) {
622
- if (node.universal) {
623
- imports.push(`import * as U${index} from ${JSON.stringify(resolve(root, node.universal))};`);
624
- loads.push(`U${index}.load`);
625
- } else {
626
- loads.push('undefined');
627
- }
628
- if (!node.component) {
629
- table.push('undefined');
630
- continue;
631
- }
632
- imports.push(`import N${index} from ${JSON.stringify(resolve(root, node.component))};`);
633
- table.push(`N${index}`);
618
+ for (const node of manifest.nodes) {
619
+ // Kit's dev manifest supplies lazy component functions and resolves
620
+ // universal modules only when that node belongs to the requested page
621
+ // (exports/vite/dev/generate_manifest.js). Keep imports behind calls so
622
+ // bringing up the renderer cannot evaluate unrelated route modules.
623
+ components.push(node.component
624
+ ? `() => import(${JSON.stringify(resolve(root, node.component))}).then(m => m.default)`
625
+ : 'undefined');
626
+ loads.push(node.universal
627
+ ? `() => import(${JSON.stringify(resolve(root, node.universal))}).then(m => m.load)`
628
+ : 'undefined');
634
629
  }
635
- return `${imports.join('\n')}\nexport const components = [${table.join(', ')}];\nexport const universalLoads = [${loads.join(', ')}];\n`;
630
+ return `export const componentLoaders = [${components.join(', ')}];\nexport const universalLoaders = [${loads.join(', ')}];\n`;
636
631
  }
637
632
 
638
633
  /**
@@ -1268,6 +1263,55 @@ function errorText(e) {
1268
1263
  // Values are validated by Go once before Kit loads its environment declaration.
1269
1264
  // This must be a real file: Kit imports env.ts in a separate Vite server with
1270
1265
  // configFile:false, where this adapter's virtual modules do not exist.
1266
+ // The Go supervisor publishes readiness through Vite's existing HMR protocol.
1267
+ // This is adapter glue: the browser keeps using Vite's own client and overlay.
1268
+ export function goSupervisorReload() {
1269
+ return {
1270
+ name: 'skgo-supervisor-reload',
1271
+ configureServer(server) {
1272
+ const token = randomBytes(32).toString('hex');
1273
+ const file = join(server.config.root, '.svelte-kit/skgo-dev-supervisor.json');
1274
+ // Vite's client imports @vite/env. Import analysis rewrites that to
1275
+ // its installed env.mjs, either under root or through /@fs/. Publish
1276
+ // only this exact bootstrap dependency, never an application prefix.
1277
+ const envFile = app.resolve('vite/dist/client/env.mjs').replaceAll('\\', '/');
1278
+ const root = server.config.root.replaceAll('\\', '/').replace(/\/$/, '');
1279
+ const envURL = envFile.startsWith(root + '/') ? envFile.slice(root.length) : posixPath.join('/@fs/', envFile);
1280
+ const clientFiles = [server.config.base.replace(/\/$/, '') + envURL];
1281
+ mkdirSync(dirname(file), { recursive: true });
1282
+ writeFileSync(file, JSON.stringify({ token, base: server.config.base, clientFiles }), { mode: 0o600 });
1283
+ chmodSync(file, 0o600);
1284
+ let failure;
1285
+ server.ws.on('vite:client:connect', (_, client) => {
1286
+ if (failure) client.send(failure);
1287
+ });
1288
+ server.middlewares.use((req, res, next) => {
1289
+ if ((req.url || '').split('?')[0] !== '/__skgo_dev/supervisor') return next();
1290
+ if (req.method !== 'POST' || req.headers['x-skgo-dev-token'] !== token) {
1291
+ res.statusCode = 403; res.end('Forbidden'); return;
1292
+ }
1293
+ let body = '', size = 0;
1294
+ req.setEncoding('utf8');
1295
+ req.on('data', chunk => {
1296
+ size += Buffer.byteLength(chunk);
1297
+ if (size <= 1048576) body += chunk;
1298
+ });
1299
+ req.on('end', () => {
1300
+ let message;
1301
+ try { message = JSON.parse(body); } catch {}
1302
+ if (size > 1048576 || !message || typeof message.diagnostic !== 'string') {
1303
+ res.statusCode = 400; res.end('Invalid supervisor status'); return;
1304
+ }
1305
+ failure = message.diagnostic ? { type: 'error', err: { message: message.diagnostic, stack: '', plugin: 'skgo' } } : undefined;
1306
+ // Kit also omits path for full-reload: app.html is not the page URL.
1307
+ server.ws.send(failure || { type: 'full-reload' });
1308
+ res.statusCode = 204; res.end();
1309
+ });
1310
+ });
1311
+ }
1312
+ };
1313
+ }
1314
+
1271
1315
  export function goEnvironmentValues(output = 'build') {
1272
1316
  let token = '';
1273
1317
  let kitOut = '.svelte-kit';
package/skgo-adapter.js CHANGED
@@ -21,7 +21,7 @@ import {
21
21
  remoteEndpoint,
22
22
  remoteLoad
23
23
  } from './skgo-adapter/prerender.js';
24
- import { gojaDevEnvironment, gojaDevUnchangedFiles, gojaEnvironment, goEnvironmentValues, nodeTable, SSR_TARGET } from './skgo-adapter/env.js';
24
+ import { gojaDevEnvironment, gojaDevUnchangedFiles, gojaEnvironment, goEnvironmentValues, goSupervisorReload, nodeTable, SSR_TARGET } from './skgo-adapter/env.js';
25
25
  import { prerenderModules } from './skgo-adapter/prerender-modules.js';
26
26
  import { identity } from './skgo-adapter/identity.js';
27
27
  import { checkEndpoints, validateGenerated } from './skgo-adapter/generated.js';
@@ -116,7 +116,7 @@ export default function skgo({ out = 'build', precompress = true, prerenderPacka
116
116
  // compiles the SSR bundle in is also declared in `vite dev`, where Go
117
117
  // pulls one transformed module at a time out of it instead. Each plugin
118
118
  // states its own `apply`, so only one of them is ever live.
119
- vite: { plugins: { pre: [prerenderOwnerPlugin, prerenderModules()], post: [environment.plugin, goja.plugin, gojaDevEnvironment(), gojaDevUnchangedFiles({ out })] } },
119
+ vite: { plugins: { pre: [prerenderOwnerPlugin, prerenderModules()], post: [environment.plugin, goSupervisorReload(), goja.plugin, gojaDevEnvironment(), gojaDevUnchangedFiles({ out })] } },
120
120
  async adapt(builder) {
121
121
  let failure;
122
122
  try {