@arcblock/did-connect-service 4.1.56 → 4.1.57
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/dist/handlers/oauth-handler.d.ts.map +1 -1
- package/dist/handlers/oauth-handler.js +17 -19
- package/dist/handlers/oauth-handler.js.map +1 -1
- package/dist/og/generator.d.ts +13 -0
- package/dist/og/generator.d.ts.map +1 -1
- package/dist/og/generator.js +19 -5
- package/dist/og/generator.js.map +1 -1
- package/dist/og/index.d.ts +4 -2
- package/dist/og/index.d.ts.map +1 -1
- package/dist/og/index.js +2 -1
- package/dist/og/index.js.map +1 -1
- package/dist/og/node-config.d.ts +2 -0
- package/dist/og/node-config.d.ts.map +1 -1
- package/dist/og/node-config.js +1 -0
- package/dist/og/node-config.js.map +1 -1
- package/dist/og/node-wasm-fallback.d.ts.map +1 -1
- package/dist/og/node-wasm-fallback.js +12 -5
- package/dist/og/node-wasm-fallback.js.map +1 -1
- package/dist/og/tree-node.d.ts +73 -0
- package/dist/og/tree-node.d.ts.map +1 -0
- package/dist/og/tree-node.js +192 -0
- package/dist/og/tree-node.js.map +1 -0
- package/dist/og/tree.d.ts +192 -0
- package/dist/og/tree.d.ts.map +1 -0
- package/dist/og/tree.js +921 -0
- package/dist/og/tree.js.map +1 -0
- package/dist/og/worker.d.ts +74 -2
- package/dist/og/worker.d.ts.map +1 -1
- package/dist/og/worker.js +194 -57
- package/dist/og/worker.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node entry of the tree renderer (`og-node` → `renderOgTree`, ArcBlock/did#300).
|
|
3
|
+
*
|
|
4
|
+
* Same contract as the Worker's `renderOgTree` (`worker.ts`): the tree is
|
|
5
|
+
* validated by `tree.ts` first (data: images only, hard limits, bounded
|
|
6
|
+
* shadows/filters/text, nothing is fetched), renders run one at a time per
|
|
7
|
+
* process, and the result is PNG bytes from the same satori +
|
|
8
|
+
* `@resvg/resvg-wasm` stack the Worker uses — never sharp, so output and memory
|
|
9
|
+
* behave the same on both runtimes and in a `bun --compile` binary.
|
|
10
|
+
*
|
|
11
|
+
* Fonts: Node has one CJK family (Noto Sans SC — it also covers Latin, kana
|
|
12
|
+
* and most Traditional glyphs), so `locale` only shapes the observer event.
|
|
13
|
+
* - Regular: `fontUrl` / `CONNECT_OG_FONT_URL` / the bundled face (like og.png).
|
|
14
|
+
* - Bold: `boldFontUrl` / `CONNECT_OG_FONT_BOLD_URL`; when neither is set it is
|
|
15
|
+
* DERIVED from the Regular URL by swapping `Regular`→`Bold` in the file name
|
|
16
|
+
* (`…/NotoSansSC-Regular.otf` → `…/NotoSansSC-Bold.otf`,
|
|
17
|
+
* `…/noto-sans-sc-regular.otf` → `…/noto-sans-sc-bold.otf`). No Bold is
|
|
18
|
+
* bundled in the npm package. `file:` URLs are read from disk.
|
|
19
|
+
* - Missing Bold renders 700 with Regular (`boldFallback: true` on the event).
|
|
20
|
+
* Only a success, "not configured", or a missing DERIVED file is cached; a
|
|
21
|
+
* failure of an explicitly configured URL is retried on the next render.
|
|
22
|
+
*
|
|
23
|
+
* No wall-clock guard around satori/resvg here (`Resvg.render()` is one
|
|
24
|
+
* synchronous wasm call; a timer cannot interrupt it). Render cost is bounded
|
|
25
|
+
* up front instead: the validator refuses SVG styles/filters and caps images,
|
|
26
|
+
* text, inline <svg> and an area-weighted shadow/filter budget, and
|
|
27
|
+
* `og-tree.test.ts` asserts the worst tree within those caps renders in < 3 s.
|
|
28
|
+
* Moving renders into `worker_threads` with a timeout is left to the host
|
|
29
|
+
* (ArcBlock/arc#8746) if still wanted.
|
|
30
|
+
*/
|
|
31
|
+
import { createHash } from "node:crypto";
|
|
32
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
33
|
+
import { readFile } from "node:fs/promises";
|
|
34
|
+
import { createRequire } from "node:module";
|
|
35
|
+
import { tmpdir } from "node:os";
|
|
36
|
+
import { dirname, join } from "node:path";
|
|
37
|
+
import { fileURLToPath } from "node:url";
|
|
38
|
+
import { consoleLogger } from "../logger.js";
|
|
39
|
+
import { FONT_FETCH_TIMEOUT_MS, loadFont } from "./generator.js";
|
|
40
|
+
import { resolveNodeOgConfig } from "./node-config.js";
|
|
41
|
+
import { rasterizeSvgToPngWithWasm } from "./node-wasm-fallback.js";
|
|
42
|
+
import { createSerialQueue, OG_RENDER_UNAVAILABLE_CODES, OG_TREE_ERROR_CODES, OgRenderUnavailableError, OgTreeRenderError, prepareOgTree, wantsBold, withTimeout, } from "./tree.js";
|
|
43
|
+
/** Default deadline for waiting in the process render queue. */
|
|
44
|
+
export const OG_NODE_QUEUE_MAX_WAIT_MS = 20_000;
|
|
45
|
+
const serialRender = createSerialQueue();
|
|
46
|
+
let satoriReady;
|
|
47
|
+
/** One cached Bold result (keyed by its URL); a different URL replaces it. `null` = no Bold. */
|
|
48
|
+
let boldSlot;
|
|
49
|
+
let boldMissingWarned = false;
|
|
50
|
+
/**
|
|
51
|
+
* `satori/standalone` with yoga.wasm read from disk — the default `satori`
|
|
52
|
+
* build instantiates its inlined yoga by calling `fetch()` on a data: URI,
|
|
53
|
+
* and a tree render makes no fetch calls at all.
|
|
54
|
+
*/
|
|
55
|
+
function loadSatori() {
|
|
56
|
+
if (!satoriReady) {
|
|
57
|
+
satoriReady = (async () => {
|
|
58
|
+
const { default: satori, init } = await import("satori/standalone");
|
|
59
|
+
const require = createRequire(import.meta.url);
|
|
60
|
+
await init(readFileSync(require.resolve("satori/yoga.wasm")));
|
|
61
|
+
return satori;
|
|
62
|
+
})().catch((error) => {
|
|
63
|
+
satoriReady = undefined;
|
|
64
|
+
throw error;
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
return satoriReady;
|
|
68
|
+
}
|
|
69
|
+
function md5(s) {
|
|
70
|
+
return createHash("md5").update(s).digest("hex");
|
|
71
|
+
}
|
|
72
|
+
/** `…Regular…` → `…Bold…` in the last path segment; undefined when the name has no Regular marker. */
|
|
73
|
+
export function deriveBoldFontUrl(regularUrl) {
|
|
74
|
+
if (!regularUrl)
|
|
75
|
+
return undefined;
|
|
76
|
+
const slash = regularUrl.lastIndexOf("/");
|
|
77
|
+
const head = regularUrl.slice(0, slash + 1);
|
|
78
|
+
const name = regularUrl.slice(slash + 1);
|
|
79
|
+
const bold = name.replace(/Regular/, "Bold").replace(/regular/, "bold");
|
|
80
|
+
return bold === name ? undefined : head + bold;
|
|
81
|
+
}
|
|
82
|
+
async function fetchFontBytes(url, fontCacheDir, fetchImpl) {
|
|
83
|
+
if (url.startsWith("file:"))
|
|
84
|
+
return readFile(fileURLToPath(url));
|
|
85
|
+
const diskPath = join(fontCacheDir, `${md5(url)}.font`);
|
|
86
|
+
if (existsSync(diskPath))
|
|
87
|
+
return readFile(diskPath);
|
|
88
|
+
const res = await fetchImpl(url, { signal: AbortSignal.timeout(FONT_FETCH_TIMEOUT_MS) });
|
|
89
|
+
if (!res.ok)
|
|
90
|
+
throw new Error(`font fetch failed: ${res.status}`);
|
|
91
|
+
const buf = Buffer.from(await res.arrayBuffer());
|
|
92
|
+
mkdirSync(dirname(diskPath), { recursive: true });
|
|
93
|
+
writeFileSync(diskPath, buf);
|
|
94
|
+
return buf;
|
|
95
|
+
}
|
|
96
|
+
async function loadBold(explicitUrl, regularUrl, fontCacheDir, fetchImpl, logger) {
|
|
97
|
+
const url = explicitUrl ?? deriveBoldFontUrl(regularUrl);
|
|
98
|
+
const key = url ?? "(not configured)";
|
|
99
|
+
if (boldSlot?.key === key)
|
|
100
|
+
return boldSlot.bytes;
|
|
101
|
+
if (!url) {
|
|
102
|
+
boldSlot = { key, bytes: null };
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
const bytes = await fetchFontBytes(url, fontCacheDir, fetchImpl);
|
|
107
|
+
boldSlot = { key, bytes };
|
|
108
|
+
return bytes;
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
if (!explicitUrl) {
|
|
112
|
+
// A derived sibling that does not exist is "not configured", not an outage.
|
|
113
|
+
boldSlot = { key, bytes: null };
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
// Explicit URL failed: fall back for THIS render only; retry next time.
|
|
117
|
+
logger.warn({ message: "[og] bold font load failed; rendering weight 700 with the regular face", mod: "og", err });
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/** Test isolation: forget cached Bold bytes and re-arm the missing-Bold warning. */
|
|
122
|
+
export function resetOgNodeTreeFontsForTesting() {
|
|
123
|
+
boldSlot = undefined;
|
|
124
|
+
boldMissingWarned = false;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Renders a caller-built satori tree to PNG bytes. Rejects with an
|
|
128
|
+
* `OgTreeRenderError` (400, see `OG_TREE_ERROR_CODES`) before any work when the
|
|
129
|
+
* tree breaks a rule, or with an `OgRenderUnavailableError` (503) when fonts or
|
|
130
|
+
* the queue time out.
|
|
131
|
+
*/
|
|
132
|
+
export async function renderOgTree(options) {
|
|
133
|
+
const startedAt = performance.now();
|
|
134
|
+
const tree = prepareOgTree(options);
|
|
135
|
+
const config = resolveNodeOgConfig();
|
|
136
|
+
const logger = options.logger ?? consoleLogger;
|
|
137
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
138
|
+
const fontCacheDir = options.fontCacheDir ?? join(tmpdir(), "og-fonts");
|
|
139
|
+
const fontTimeout = options.fontReadTimeoutMs ?? FONT_FETCH_TIMEOUT_MS;
|
|
140
|
+
const regularUrl = options.fontUrl ?? config.fontUrl;
|
|
141
|
+
const timeoutError = () => new OgRenderUnavailableError(OG_RENDER_UNAVAILABLE_CODES.fontTimeout, `font load exceeded ${fontTimeout}ms`);
|
|
142
|
+
const { png, queueMs, fontReadMs, boldFallback } = await serialRender(async ({ queueMs }) => {
|
|
143
|
+
const satori = await loadSatori();
|
|
144
|
+
const fontStart = performance.now();
|
|
145
|
+
const regular = await withTimeout(loadFont({ fontUrl: regularUrl, fontCacheDir, fetchImpl, logger, timeoutMs: fontTimeout }), fontTimeout, timeoutError);
|
|
146
|
+
let bold = null;
|
|
147
|
+
const boldWanted = wantsBold(options.weights);
|
|
148
|
+
if (boldWanted) {
|
|
149
|
+
bold = await withTimeout(loadBold(options.boldFontUrl ?? config.boldFontUrl, regularUrl, fontCacheDir, fetchImpl, logger), fontTimeout, timeoutError);
|
|
150
|
+
if (!bold && !boldMissingWarned) {
|
|
151
|
+
boldMissingWarned = true;
|
|
152
|
+
logger.warn({ message: "[og] bold font missing; rendering weight 700 with the regular face", mod: "og" });
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
const fontReadMs = performance.now() - fontStart;
|
|
156
|
+
// Fresh ArrayBuffer copies per render: satori's parsed font objects are
|
|
157
|
+
// released with them instead of staying resident (same as the Worker).
|
|
158
|
+
const copy = (b) => b.buffer.slice(b.byteOffset, b.byteOffset + b.byteLength);
|
|
159
|
+
const fonts = [
|
|
160
|
+
{ name: "Noto", data: copy(regular), weight: 400, style: "normal" },
|
|
161
|
+
];
|
|
162
|
+
if (bold)
|
|
163
|
+
fonts.push({ name: "Noto", data: copy(bold), weight: 700, style: "normal" });
|
|
164
|
+
let png;
|
|
165
|
+
try {
|
|
166
|
+
// No `loadAdditionalAsset`: og.png's emoji loader downloads glyphs, and a
|
|
167
|
+
// tree render must make no request on behalf of its content.
|
|
168
|
+
const svg = await satori(tree, {
|
|
169
|
+
width: options.width,
|
|
170
|
+
height: options.height,
|
|
171
|
+
fonts,
|
|
172
|
+
});
|
|
173
|
+
png = await rasterizeSvgToPngWithWasm(svg, regular);
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
// satori/resvg messages can quote the input; report a generic 400.
|
|
177
|
+
throw new OgTreeRenderError(OG_TREE_ERROR_CODES.renderFailed, "the tree could not be rendered");
|
|
178
|
+
}
|
|
179
|
+
return { png, queueMs, fontReadMs, boldFallback: boldWanted && !bold };
|
|
180
|
+
}, { maxWaitMs: options.queueMaxWaitMs ?? OG_NODE_QUEUE_MAX_WAIT_MS });
|
|
181
|
+
options.observer?.({
|
|
182
|
+
locale: options.locale,
|
|
183
|
+
cacheStatus: "BYPASS",
|
|
184
|
+
durationMs: performance.now() - startedAt,
|
|
185
|
+
queueMs,
|
|
186
|
+
fontReadMs,
|
|
187
|
+
template: "tree",
|
|
188
|
+
...(boldFallback ? { boldFallback: true } : {}),
|
|
189
|
+
});
|
|
190
|
+
return new Uint8Array(png.buffer, png.byteOffset, png.byteLength);
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=tree-node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree-node.js","sourceRoot":"","sources":["../../src/og/tree-node.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime-neutral half of the tree renderer (`renderOgTree`, ArcBlock/did#300).
|
|
3
|
+
*
|
|
4
|
+
* A caller hands in a plain satori object tree (the same `{ type, props }`
|
|
5
|
+
* shape `templates.ts` builds). Before anything is parsed or rasterized, this
|
|
6
|
+
* module walks the whole tree and enforces the image contract:
|
|
7
|
+
*
|
|
8
|
+
* - every image reference (`src`, `href`, any `url(...)` in a style or other
|
|
9
|
+
* prop) must be a `data:` URI — anything else rejects the WHOLE render and
|
|
10
|
+
* no request is ever made (keeps did#220's no-remote-media stance);
|
|
11
|
+
* - the bytes must be PNG / JPEG / SVG by magic bytes, matching the declared
|
|
12
|
+
* MIME type;
|
|
13
|
+
* - hard limits are read from the image headers (never by decoding):
|
|
14
|
+
* PNG/JPEG ≤ 1.5 MP and ≤ 1 MB each, SVG ≤ 256 KB, the whole tree
|
|
15
|
+
* ≤ 2.5 MP and ≤ 2 MB of raw image bytes. Nothing is resized; an
|
|
16
|
+
* over-limit tree is refused with a code that names the reason.
|
|
17
|
+
*
|
|
18
|
+
* Both runtime entries (`worker.ts` → `og-worker`, `tree-node.ts` → `og-node`)
|
|
19
|
+
* call {@link validateOgTree} and share {@link createSerialQueue}.
|
|
20
|
+
*/
|
|
21
|
+
import { OgValidationError } from "./types.js";
|
|
22
|
+
/** Font weights a tree may declare. Fonts are loaded by the renderer per locale. */
|
|
23
|
+
export type OgTreeWeight = 400 | 700;
|
|
24
|
+
/** A satori node: `{ type, props }`, children under `props.children`. */
|
|
25
|
+
export interface OgTreeNode {
|
|
26
|
+
type: string;
|
|
27
|
+
props?: Record<string, unknown>;
|
|
28
|
+
}
|
|
29
|
+
export interface OgTreeRenderOptions {
|
|
30
|
+
/** Plain satori object tree. Only `data:` image URIs are accepted. */
|
|
31
|
+
tree: OgTreeNode;
|
|
32
|
+
width: number;
|
|
33
|
+
height: number;
|
|
34
|
+
/** BCP-47-ish locale; selects the font family (normalized like og.png). */
|
|
35
|
+
locale: string;
|
|
36
|
+
/** Weights the tree uses. Defaults to `[400]`. Regular is always loaded. */
|
|
37
|
+
weights?: readonly OgTreeWeight[];
|
|
38
|
+
}
|
|
39
|
+
/** Font family name trees should use in `fontFamily` (same as the templates). */
|
|
40
|
+
export declare const OG_TREE_FONT_FAMILY = "Noto";
|
|
41
|
+
export declare const OG_TREE_LIMITS: {
|
|
42
|
+
/** PNG/JPEG: max pixels per image. */
|
|
43
|
+
readonly maxImagePixels: 1500000;
|
|
44
|
+
/** PNG/JPEG: max raw bytes per image. */
|
|
45
|
+
readonly maxImageBytes: 1000000;
|
|
46
|
+
/** SVG: max raw bytes per image. */
|
|
47
|
+
readonly maxSvgBytes: number;
|
|
48
|
+
/** Sum of PNG/JPEG pixels over every image occurrence in the tree. */
|
|
49
|
+
readonly maxTotalPixels: 2500000;
|
|
50
|
+
/** Sum of raw image bytes (all types) over every image occurrence. */
|
|
51
|
+
readonly maxTotalBytes: 2000000;
|
|
52
|
+
/** Image occurrences per tree. */
|
|
53
|
+
readonly maxImages: 32;
|
|
54
|
+
/** Output canvas. */
|
|
55
|
+
readonly maxCanvasDimension: 2400;
|
|
56
|
+
readonly maxCanvasPixels: 1000000;
|
|
57
|
+
/** Tree shape. */
|
|
58
|
+
readonly maxDepth: 64;
|
|
59
|
+
readonly maxNodes: 5000;
|
|
60
|
+
/** Characters per text string (satori lays out every glyph). */
|
|
61
|
+
readonly maxStringChars: 2000;
|
|
62
|
+
/** Characters of text over the whole tree. */
|
|
63
|
+
readonly maxTextChars: 10000;
|
|
64
|
+
/** Characters per non-image prop string; inline `<svg>` props (path data) get more. */
|
|
65
|
+
readonly maxPropStringChars: 2000;
|
|
66
|
+
readonly maxSvgPropStringChars: 16384;
|
|
67
|
+
/** Characters over all non-image prop strings in the tree. */
|
|
68
|
+
readonly maxPropChars: 65536;
|
|
69
|
+
/** box-shadow / text-shadow: entries per value; |offset| per entry, in px. */
|
|
70
|
+
readonly maxShadows: 4;
|
|
71
|
+
readonly maxShadowLengthPx: 100;
|
|
72
|
+
/** Blur radius and spread for shadows, drop-shadow() and blur(), in px — blur drives render cost. */
|
|
73
|
+
readonly maxBlurPx: 16;
|
|
74
|
+
readonly maxSpreadPx: 16;
|
|
75
|
+
/** CSS filter: functions per value. */
|
|
76
|
+
readonly maxFilterFunctions: 4;
|
|
77
|
+
/**
|
|
78
|
+
* Tree-wide effect budget, in units. Render cost of a shadow or filter
|
|
79
|
+
* follows the AREA it covers, not its blur radius (measured on the Worker
|
|
80
|
+
* stack: a full-canvas box-shadow ≈ 0.4 s, a CSS filter on a full-canvas
|
|
81
|
+
* group ≈ 1.6 s at blur 4px and 16px alike). An element's area unit count
|
|
82
|
+
* is ceil(width × height / 250,000) from numeric px `width`/`height` in its
|
|
83
|
+
* style, or the whole canvas when either is not a number. Charges:
|
|
84
|
+
* - each boxShadow entry: 1 × area units;
|
|
85
|
+
* - each CSS filter function: 1 × area units, `blur()` 4 × area units (so a
|
|
86
|
+
* blur fits only on an element ≤ 250,000 px); filters are allowed only on
|
|
87
|
+
* elements without children (a filtered group rasterizes its whole,
|
|
88
|
+
* possibly overflowing, subtree: 6–8 s measured);
|
|
89
|
+
* - each textShadow entry: 1 per started 250 characters of every text
|
|
90
|
+
* string it reaches (textShadow is inherited, so a declaration on a
|
|
91
|
+
* container is paid for every text node below it).
|
|
92
|
+
* `drop-shadow()` is refused (use boxShadow).
|
|
93
|
+
*/
|
|
94
|
+
readonly maxEffects: 4;
|
|
95
|
+
readonly effectAreaUnitPx: 250000;
|
|
96
|
+
readonly effectCostBlur: 4;
|
|
97
|
+
readonly textShadowCharsPerUnit: 250;
|
|
98
|
+
/** Inline <svg>: nodes and prop characters per tree (paths are costly to rasterize). */
|
|
99
|
+
readonly maxSvgNodes: 500;
|
|
100
|
+
readonly maxSvgChars: 16384;
|
|
101
|
+
};
|
|
102
|
+
export declare const OG_TREE_ERROR_CODES: {
|
|
103
|
+
readonly treeInvalid: "OG_TREE_INVALID";
|
|
104
|
+
readonly canvasInvalid: "OG_TREE_CANVAS_INVALID";
|
|
105
|
+
readonly weightsInvalid: "OG_TREE_WEIGHTS_INVALID";
|
|
106
|
+
readonly imageNotDataUri: "OG_IMAGE_NOT_DATA_URI";
|
|
107
|
+
readonly imageUnsupportedType: "OG_IMAGE_UNSUPPORTED_TYPE";
|
|
108
|
+
readonly imageUnreadable: "OG_IMAGE_UNREADABLE";
|
|
109
|
+
readonly imageTooManyPixels: "OG_IMAGE_TOO_MANY_PIXELS";
|
|
110
|
+
readonly imageTooLarge: "OG_IMAGE_TOO_LARGE";
|
|
111
|
+
readonly svgTooLarge: "OG_SVG_TOO_LARGE";
|
|
112
|
+
readonly svgUnsafe: "OG_SVG_UNSAFE";
|
|
113
|
+
readonly treeTooManyImages: "OG_TREE_TOO_MANY_IMAGES";
|
|
114
|
+
readonly treeTooManyPixels: "OG_TREE_TOO_MANY_PIXELS";
|
|
115
|
+
readonly treeTooManyBytes: "OG_TREE_TOO_MANY_BYTES";
|
|
116
|
+
readonly svgFilterForbidden: "OG_SVG_FILTER_FORBIDDEN";
|
|
117
|
+
readonly shadowLimit: "OG_TREE_SHADOW_LIMIT";
|
|
118
|
+
readonly cssFilterLimit: "OG_TREE_FILTER_LIMIT";
|
|
119
|
+
readonly textTooLong: "OG_TREE_TEXT_TOO_LONG";
|
|
120
|
+
/** satori/resvg failed on a tree that passed validation (generic; no input echoed). */
|
|
121
|
+
readonly renderFailed: "OG_TREE_RENDER_FAILED";
|
|
122
|
+
};
|
|
123
|
+
export type OgTreeErrorCode = (typeof OG_TREE_ERROR_CODES)[keyof typeof OG_TREE_ERROR_CODES];
|
|
124
|
+
/** Rejection of a tree render. `statusCode` 400 (inherited): the input is at fault. */
|
|
125
|
+
export declare class OgTreeRenderError extends OgValidationError {
|
|
126
|
+
readonly code: OgTreeErrorCode;
|
|
127
|
+
constructor(code: OgTreeErrorCode, message: string);
|
|
128
|
+
}
|
|
129
|
+
export declare const OG_RENDER_UNAVAILABLE_CODES: {
|
|
130
|
+
/** A font read did not finish within the timeout; the cached slot was dropped. */
|
|
131
|
+
readonly fontTimeout: "OG_FONT_TIMEOUT";
|
|
132
|
+
/** The render waited in the isolate/process queue past its deadline. */
|
|
133
|
+
readonly queueTimeout: "OG_QUEUE_TIMEOUT";
|
|
134
|
+
};
|
|
135
|
+
export type OgRenderUnavailableCode = (typeof OG_RENDER_UNAVAILABLE_CODES)[keyof typeof OG_RENDER_UNAVAILABLE_CODES];
|
|
136
|
+
/** The renderer is temporarily unable to serve (font storage hung, queue backed up). Retryable: 503. */
|
|
137
|
+
export declare class OgRenderUnavailableError extends Error {
|
|
138
|
+
readonly statusCode = 503;
|
|
139
|
+
readonly code: OgRenderUnavailableCode;
|
|
140
|
+
constructor(code: OgRenderUnavailableCode, message: string);
|
|
141
|
+
}
|
|
142
|
+
/** Rejects with `onTimeout()` if `promise` has not settled within `ms`. */
|
|
143
|
+
export declare function withTimeout<T>(promise: Promise<T>, ms: number, onTimeout: () => Error): Promise<T>;
|
|
144
|
+
export type OgImageKind = "png" | "jpeg" | "svg";
|
|
145
|
+
/** Detects PNG / JPEG / SVG from the bytes themselves; anything else is `undefined`. */
|
|
146
|
+
export declare function sniffOgImageKind(bytes: Uint8Array): OgImageKind | undefined;
|
|
147
|
+
export declare function ogImageMime(kind: OgImageKind): string;
|
|
148
|
+
export interface OgTreeImageStats {
|
|
149
|
+
imageCount: number;
|
|
150
|
+
totalPixels: number;
|
|
151
|
+
totalBytes: number;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Validates a tree render request without rendering. Throws an
|
|
155
|
+
* {@link OgTreeRenderError} naming the first violated rule; never performs I/O.
|
|
156
|
+
*/
|
|
157
|
+
export declare function validateOgTree(options: OgTreeRenderOptions): OgTreeImageStats;
|
|
158
|
+
/** Validation for the renderers: returns the snapshot that was validated — render exactly this. */
|
|
159
|
+
export declare function prepareOgTree(options: OgTreeRenderOptions): OgTreeNode;
|
|
160
|
+
export type OgImageInspection = {
|
|
161
|
+
kind: OgImageKind;
|
|
162
|
+
width: number | null;
|
|
163
|
+
height: number | null;
|
|
164
|
+
bytes: number;
|
|
165
|
+
} | {
|
|
166
|
+
code: OgTreeErrorCode;
|
|
167
|
+
};
|
|
168
|
+
/**
|
|
169
|
+
* Checks ONE image data: URI against the per-image rules (type, bytes, pixels,
|
|
170
|
+
* SVG safety) without rendering, so a caller can drop an image before building
|
|
171
|
+
* a tree. `width`/`height` are null for SVG. Tree-wide totals are not applied.
|
|
172
|
+
*/
|
|
173
|
+
export declare function inspectOgImage(dataUri: string): OgImageInspection;
|
|
174
|
+
export declare function wantsBold(weights: readonly OgTreeWeight[] | undefined): boolean;
|
|
175
|
+
export interface SerialTaskInfo {
|
|
176
|
+
/** Milliseconds the task waited in the queue before starting. */
|
|
177
|
+
queueMs: number;
|
|
178
|
+
}
|
|
179
|
+
export type SerialQueue = <T>(task: (info: SerialTaskInfo) => Promise<T>, options?: {
|
|
180
|
+
maxWaitMs?: number;
|
|
181
|
+
}) => Promise<T>;
|
|
182
|
+
/**
|
|
183
|
+
* A FIFO mutex: a task starts only after every previously queued task has
|
|
184
|
+
* settled (fulfilled or rejected). One queue per isolate/process keeps
|
|
185
|
+
* satori's per-render font parse and resvg's wasm heap from stacking.
|
|
186
|
+
*
|
|
187
|
+
* `maxWaitMs`: a task still waiting when the deadline passes is rejected with
|
|
188
|
+
* an {@link OgRenderUnavailableError} (`OG_QUEUE_TIMEOUT`) and never runs, so a
|
|
189
|
+
* wedged predecessor cannot pile up callers forever.
|
|
190
|
+
*/
|
|
191
|
+
export declare function createSerialQueue(): SerialQueue;
|
|
192
|
+
//# sourceMappingURL=tree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree.d.ts","sourceRoot":"","sources":["../../src/og/tree.ts"],"names":[],"mappings":"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"}
|