@ethercorps/sveltekit-og 4.3.0-next.13 → 4.3.0-next.15

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.
@@ -1,3 +1,3 @@
1
1
  import type { Component } from "svelte";
2
2
  import type { ComponentOptions, VNode } from "../types.js";
3
- export declare function createVNode(element: string | Component, componentProps?: ComponentOptions): VNode;
3
+ export declare function createVNode(element: string | Component, componentOptions?: ComponentOptions): VNode;
@@ -1,11 +1,11 @@
1
1
  import { html } from "satori-html";
2
2
  import { handleSync, ErrorCodes } from "./error-handler.js";
3
3
  import { renderComponentToHtml } from "./to-html.js";
4
- export function createVNode(element, componentProps) {
4
+ export function createVNode(element, componentOptions) {
5
5
  return handleSync(() => {
6
6
  if (typeof element === "string")
7
7
  return html(element.replaceAll("\n", "").trim());
8
- const { body, head } = renderComponentToHtml(element, componentProps?.props);
8
+ const { body, head } = renderComponentToHtml(element, componentOptions?.props);
9
9
  return html(body + head);
10
10
  }, ErrorCodes.VNODE_CREATION_FAILED, "Failed to create VNode");
11
11
  }
@@ -4,14 +4,13 @@ import { handleAsync, ErrorCodes } from "../helpers/error-handler.js";
4
4
  /**
5
5
  * Lazy singleton around a node/edge wasm module pair. The edge/node choice is
6
6
  * made per-runtime via std-env; both sides stay direct import() expressions so
7
- * the bundler can emit the wasm chunk. The instance is only cached after its
8
- * wasm finished initializing, so a failed init can be retried.
7
+ * the bundler can emit the wasm chunk. Memoizes the init promise (like
8
+ * takumi/renderer.ts) so concurrent first requests share one init, and clears
9
+ * it on rejection so a failed init can be retried.
9
10
  */
10
11
  function createProvider(label, errorCode, imports) {
11
- let instance;
12
- return async (debug = false) => {
13
- if (instance)
14
- return instance;
12
+ let instancePromise;
13
+ const init = async (debug) => {
15
14
  const log = createLogger(debug);
16
15
  log.debug(`Initializing ${label}`);
17
16
  const isWorkerLikeRuntime = isEdgeLight || isWorkerd;
@@ -19,8 +18,14 @@ function createProvider(label, errorCode, imports) {
19
18
  const moduleImport = isWorkerLikeRuntime ? imports.edge() : imports.node();
20
19
  const loaded = await handleAsync(() => moduleImport.then((m) => m.default), errorCode, `Failed to import ${label} module`);
21
20
  await handleAsync(() => loaded.initWasmPromise, errorCode, `Failed to initialize ${label} WASM`);
22
- instance = loaded;
23
- return instance;
21
+ return loaded;
22
+ };
23
+ return (debug = false) => {
24
+ instancePromise ??= init(debug).catch((error) => {
25
+ instancePromise = undefined;
26
+ throw error;
27
+ });
28
+ return instancePromise;
24
29
  };
25
30
  }
26
31
  const useResvgModule = createProvider("ReSVG", ErrorCodes.RESVG_INIT_FAILED, {
@@ -1,14 +1,13 @@
1
1
  import { render as takumiRender, renderSvg } from "takumi-js";
2
- import { renderComponentToHtml } from "../helpers/to-html.js";
3
2
  import { useTakumiRenderer, registerTakumiFonts } from "./renderer.js";
4
3
  import { resolveTakumiFonts } from "./fonts.js";
5
4
  import { createLogger } from "../helpers/logger.js";
6
- import { handleAsync, handleSync, ErrorCodes } from "../helpers/error-handler.js";
5
+ import { handleAsync, ErrorCodes, handleSync } from "../helpers/error-handler.js";
7
6
  import { createVNode } from "../helpers/toJSX.js";
8
7
  /** Render an HTML string or Svelte component to image bytes (or an svg string). */
9
8
  export async function createTakumiImage(element, options, props) {
10
9
  const log = createLogger(options.debug ?? false);
11
- const vNode = handleSync(() => createVNode(element, props), ErrorCodes.VNODE_CREATION_FAILED, "Failed to create HTML for Takumi");
10
+ const vNode = handleSync(() => createVNode(element, { props }), ErrorCodes.VNODE_CREATION_FAILED, "Failed to create HTML for Takumi");
12
11
  const renderer = await useTakumiRenderer();
13
12
  if (options.fonts?.length) {
14
13
  const fonts = await resolveTakumiFonts(options.fonts);
@@ -1,6 +1,7 @@
1
1
  import type { Renderer as NodeRenderer, FontDetails } from "takumi-js/node";
2
2
  export type TakumiRenderer = NodeRenderer;
3
- /** Lazily creates and caches the Takumi renderer for the current runtime. */
3
+ /** Lazily creates and caches the Takumi renderer for the current runtime.
4
+ * A rejected init clears the cache so the next request retries. */
4
5
  export declare function useTakumiRenderer(): Promise<TakumiRenderer>;
5
6
  /** Register each font once, keyed by name/weight/style. */
6
7
  export declare function registerTakumiFonts(renderer: TakumiRenderer, fonts: FontDetails[]): Promise<void>;
@@ -18,9 +18,13 @@ async function initRenderer() {
18
18
  }, ErrorCodes.TAKUMI_INIT_FAILED, "Failed to initialize Takumi WASM");
19
19
  return new Renderer();
20
20
  }
21
- /** Lazily creates and caches the Takumi renderer for the current runtime. */
21
+ /** Lazily creates and caches the Takumi renderer for the current runtime.
22
+ * A rejected init clears the cache so the next request retries. */
22
23
  export async function useTakumiRenderer() {
23
- rendererPromise ??= initRenderer();
24
+ rendererPromise ??= initRenderer().catch((error) => {
25
+ rendererPromise = undefined;
26
+ throw error;
27
+ });
24
28
  return rendererPromise;
25
29
  }
26
30
  /** Register each font once, keyed by name/weight/style. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ethercorps/sveltekit-og",
3
- "version": "4.3.0-next.13",
3
+ "version": "4.3.0-next.15",
4
4
  "license": "MIT",
5
5
  "homepage": "https://sveltekit-og.dev",
6
6
  "repository": "github:ethercorps/sveltekit-og",