@skgo/sveltekit-adapter 0.9.5 → 0.10.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.9.5",
3
+ "version": "0.10.1",
4
4
  "description": "SvelteKit adapter for skgo: builds a frontend that a Go binary renders and answers",
5
5
  "keywords": [
6
6
  "adapter",
@@ -22,7 +22,7 @@ import {
22
22
  } from '@sveltejs/kit/internal/server';
23
23
  import * as devalue from 'skgo:devalue';
24
24
  import { decoders, init_transport, parse } from 'skgo:kit/transport';
25
- import { components } from 'skgo:nodes';
25
+ import { components, universalLoads } from 'skgo:nodes';
26
26
  import { transport } from 'skgo:hooks';
27
27
 
28
28
  /**
@@ -218,7 +218,7 @@ function node_data(node) {
218
218
  });
219
219
  }
220
220
 
221
- function build_props(req, url) {
221
+ async function build_props(req, url, event, state) {
222
222
  const form = req.form ? devalue.parse(req.form, decoders) : null;
223
223
  const page = {
224
224
  error: req.error ?? null,
@@ -248,7 +248,32 @@ function build_props(req, url) {
248
248
  let data = props.page.data;
249
249
 
250
250
  for (let i = 0; i < branch.length; i += 1) {
251
- data = { ...data, ...node_data(branch[i]) };
251
+ const server_data = node_data(branch[i]);
252
+ const load = universalLoads[branch[i].node];
253
+ const parent_data = data;
254
+ const result = load
255
+ ? await with_request_store({ event, state }, () =>
256
+ load.call(null, {
257
+ url,
258
+ params: req.params ?? {},
259
+ data: server_data,
260
+ route: { id: req.route_id ?? null },
261
+ parent: async () => parent_data,
262
+ depends: () => {},
263
+ untrack: (fn) => fn(),
264
+ fetch: () => {
265
+ throw new Error('skgo: universal load fetch is not supported during rendering');
266
+ },
267
+ setHeaders: () => {
268
+ throw new Error('skgo: universal load setHeaders is not supported during rendering');
269
+ }
270
+ })
271
+ )
272
+ : server_data;
273
+ if (result != null && Object.getPrototypeOf(result) !== Object.prototype) {
274
+ throw new Error('skgo: universal load must return a plain object');
275
+ }
276
+ data = { ...data, ...result };
252
277
  current_node.data = data;
253
278
 
254
279
  if (i < branch.length - 1) {
@@ -344,48 +369,48 @@ globalThis.__skgo_render = function (req_json) {
344
369
  try {
345
370
  const req = JSON.parse(req_json);
346
371
  const url = new URL(req.url);
347
- const props = build_props(req, url);
348
372
  const state = make_state();
349
373
  const event = make_event(req, url);
350
-
351
- result.status = props.page.status;
352
- result.error = req.error ?? null;
353
-
354
- const options = {
355
- context: new Map([['__request__', { page: props.page }]]),
356
- // kit's own \`csp.script_needs_nonce ? { nonce: csp.nonce } : {
357
- // hash: csp.script_needs_hash }\` (page/render.js:198), passed to
358
- // Svelte's own renderer so the one inline script Svelte can still
359
- // emit on its own — its hydratable-async-block script
360
- // (internal/server/renderer.js's #hydratable_block, for a
361
- // component's own top-level await) — carries the same nonce or
362
- // hash decision the boot script gets from Go (csp.go). Go decided
363
- // which branch this request is in before the engine ever ran;
364
- // req.csp carries only the answer.
365
- csp: req.csp.nonce ? { nonce: req.csp.nonce } : { hash: !!req.csp.hash },
366
- // kit's own (page/render.js): the transform every error boundary's
367
- // error passes through on its way to the failed snippet. It is
368
- // what makes page.status and page.error inside a rendering
369
- // component the values kit would give, and what turns an
370
- // unexpected throw into Internal Error rather than a stack trace on
371
- // the page. A redirect is rethrown, because a redirect is an answer
372
- // for the whole document rather than for one boundary.
373
- transformError: (e) => {
374
- if (e instanceof Redirect) throw e;
375
- const handled = handle_error(e);
376
- result.error = handled;
377
- result.status = handled.status;
378
- props.page.error = handled;
379
- props.page.status = handled.status;
380
- return handled;
381
- }
382
- };
383
- // seed_form runs inside the request store rather than before it: a
384
- // keyed submission's call to for(key) needs the request store, the
385
- // same as the page component's own call to it does.
386
- const promise = with_request_store({ event, state }, () => {
387
- seed_form(req, state);
388
- return render(Root, { ...options, props });
374
+ const props_promise = build_props(req, url, event, state);
375
+ const promise = props_promise.then((props) => {
376
+ result.status = props.page.status;
377
+ result.error = req.error ?? null;
378
+ const options = {
379
+ context: new Map([['__request__', { page: props.page }]]),
380
+ // kit's own \`csp.script_needs_nonce ? { nonce: csp.nonce } : {
381
+ // hash: csp.script_needs_hash }\` (page/render.js:198), passed to
382
+ // Svelte's own renderer so the one inline script Svelte can still
383
+ // emit on its own — its hydratable-async-block script
384
+ // (internal/server/renderer.js's #hydratable_block, for a
385
+ // component's own top-level await) — carries the same nonce or
386
+ // hash decision the boot script gets from Go (csp.go). Go decided
387
+ // which branch this request is in before the engine ever ran;
388
+ // req.csp carries only the answer.
389
+ csp: req.csp.nonce ? { nonce: req.csp.nonce } : { hash: !!req.csp.hash },
390
+ // kit's own (page/render.js): the transform every error boundary's
391
+ // error passes through on its way to the failed snippet. It is
392
+ // what makes page.status and page.error inside a rendering
393
+ // component the values kit would give, and what turns an
394
+ // unexpected throw into Internal Error rather than a stack trace on
395
+ // the page. A redirect is rethrown, because a redirect is an answer
396
+ // for the whole document rather than for one boundary.
397
+ transformError: (e) => {
398
+ if (e instanceof Redirect) throw e;
399
+ const handled = handle_error(e);
400
+ result.error = handled;
401
+ result.status = handled.status;
402
+ props.page.error = handled;
403
+ props.page.status = handled.status;
404
+ return handled;
405
+ }
406
+ };
407
+ // seed_form runs inside the request store rather than before it: a
408
+ // keyed submission's call to for(key) needs the request store, the
409
+ // same as the page component's own call to it does.
410
+ return with_request_store({ event, state }, () => {
411
+ seed_form(req, state);
412
+ return render(Root, { ...options, props });
413
+ });
389
414
  });
390
415
 
391
416
  Promise.resolve(promise).then(
@@ -428,14 +428,21 @@ function basenameOf(file) {
428
428
  * kit's build produced, in the manifest's own node order.
429
429
  *
430
430
  * @param {string} root
431
- * @param {Array<{ component: string | null }>} nodes
431
+ * @param {Array<{ component: string | null, universal: string | null }>} nodes
432
432
  */
433
433
  export function nodeTable(root, nodes) {
434
434
  /** @type {string[]} */
435
435
  const imports = [];
436
436
  /** @type {string[]} */
437
437
  const table = [];
438
+ const loads = [];
438
439
  nodes.forEach((node, i) => {
440
+ if (node.universal) {
441
+ imports.push(`import * as U${i} from ${JSON.stringify(join(root, node.universal))};`);
442
+ loads.push(`U${i}.load`);
443
+ } else {
444
+ loads.push('undefined');
445
+ }
439
446
  if (!node.component) {
440
447
  table.push('undefined');
441
448
  return;
@@ -443,7 +450,7 @@ export function nodeTable(root, nodes) {
443
450
  imports.push(`import N${i} from ${JSON.stringify(join(root, node.component))};`);
444
451
  table.push(`N${i}`);
445
452
  });
446
- return `${imports.join('\n')}\nexport const components = [${table.join(', ')}];\n`;
453
+ return `${imports.join('\n')}\nexport const components = [${table.join(', ')}];\nexport const universalLoads = [${loads.join(', ')}];\n`;
447
454
  }
448
455
 
449
456
  /**
@@ -565,7 +572,14 @@ function devNodeTable(manifest, root) {
565
572
  const imports = [];
566
573
  /** @type {string[]} */
567
574
  const table = [];
575
+ const loads = [];
568
576
  for (const [index, node] of manifest.nodes.entries()) {
577
+ if (node.universal) {
578
+ imports.push(`import * as U${index} from ${JSON.stringify(resolve(root, node.universal))};`);
579
+ loads.push(`U${index}.load`);
580
+ } else {
581
+ loads.push('undefined');
582
+ }
569
583
  if (!node.component) {
570
584
  table.push('undefined');
571
585
  continue;
@@ -573,7 +587,7 @@ function devNodeTable(manifest, root) {
573
587
  imports.push(`import N${index} from ${JSON.stringify(resolve(root, node.component))};`);
574
588
  table.push(`N${index}`);
575
589
  }
576
- return `${imports.join('\n')}\nexport const components = [${table.join(', ')}];\n`;
590
+ return `${imports.join('\n')}\nexport const components = [${table.join(', ')}];\nexport const universalLoads = [${loads.join(', ')}];\n`;
577
591
  }
578
592
 
579
593
  /**
package/skgo-adapter.js CHANGED
@@ -389,16 +389,10 @@ async function readNodes(builder, source, kit) {
389
389
  }
390
390
  const module = await import(pathToFileURL(file).href);
391
391
 
392
- if (typeof module.universal?.load === 'function') {
393
- throw new Error(
394
- `skgo: ${module.universal_id} exports a \`load\`. Every load in a skgo app is written in Go; ` +
395
- 'a universal load would have to run in the browser and in the SSR engine, and skgo runs neither.'
396
- );
397
- }
398
-
399
392
  nodes.push({
400
393
  index,
401
394
  server: module.server_id ?? '',
395
+ universal: typeof module.universal?.load === 'function' ? module.universal_id : null,
402
396
  component: module.component ? componentSource(file, dir) : null,
403
397
  imports: module.imports ?? [],
404
398
  stylesheets: module.stylesheets ?? [],
@@ -415,6 +409,7 @@ async function readNodes(builder, source, kit) {
415
409
  * @typedef {{
416
410
  * index: number,
417
411
  * server: string,
412
+ * universal: string | null,
418
413
  * component: string | null,
419
414
  * imports: string[],
420
415
  * stylesheets: string[],