@stdout-design/core 0.1.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.
@@ -0,0 +1,460 @@
1
+ import { a as isZodObject, n as PropValidationError, o as validateProps, r as PropValidationIssue, s as zodToJsonSchemaShape, t as PropSchema } from "./validation-BUNZnc-5.mjs";
2
+ import { z } from "zod";
3
+ import { fromJsx } from "takumi-js/helpers/jsx";
4
+ import { ComponentType } from "react";
5
+ import { Node } from "takumi-js";
6
+ //#region src/shared/types.d.ts
7
+ interface TemplateEntry {
8
+ componentPath: string;
9
+ description?: string;
10
+ }
11
+ interface Preset {
12
+ id: string;
13
+ width: number;
14
+ height: number;
15
+ platform: string;
16
+ }
17
+ interface StudioConfig {
18
+ templates: Record<string, TemplateEntry>;
19
+ presets: Preset[];
20
+ defaultPreset?: string;
21
+ locales?: string[];
22
+ outDir?: string;
23
+ }
24
+ interface TemplateModule {
25
+ default: (props: Record<string, unknown>) => unknown;
26
+ propsSchema: z.ZodObject<Record<string, z.ZodTypeAny>>;
27
+ }
28
+ //#endregion
29
+ //#region src/shared/config-schema.d.ts
30
+ declare const studioConfigSchema: z.ZodObject<{
31
+ defaultPreset: z.ZodOptional<z.ZodString>;
32
+ locales: z.ZodOptional<z.ZodArray<z.ZodString>>;
33
+ outDir: z.ZodOptional<z.ZodString>;
34
+ presets: z.ZodArray<z.ZodObject<{
35
+ height: z.ZodNumber;
36
+ id: z.ZodString;
37
+ platform: z.ZodString;
38
+ width: z.ZodNumber;
39
+ }, z.core.$strip>>;
40
+ templates: z.ZodRecord<z.ZodString, z.ZodObject<{
41
+ componentPath: z.ZodString;
42
+ description: z.ZodOptional<z.ZodString>;
43
+ }, z.core.$strip>>;
44
+ }, z.core.$strip>;
45
+ //#endregion
46
+ //#region src/shared/render.d.ts
47
+ interface CompiledTemplate {
48
+ node: Node;
49
+ stylesheets: string[];
50
+ }
51
+ declare const compileTemplate: (element: Parameters<typeof fromJsx>[0], options?: Parameters<typeof fromJsx>[1]) => Promise<CompiledTemplate>;
52
+ //#endregion
53
+ //#region src/shared/error-codes.d.ts
54
+ declare const ErrorCode: {
55
+ readonly API_ERROR: "API_ERROR";
56
+ readonly CACHE_CLEANUP_FAILED: "CACHE_CLEANUP_FAILED";
57
+ readonly CACHE_CORRUPT_ENTRY: "CACHE_CORRUPT_ENTRY";
58
+ readonly CACHE_INIT_FAILED: "CACHE_INIT_FAILED";
59
+ readonly CACHE_WRITE_FAILED: "CACHE_WRITE_FAILED";
60
+ readonly CONFIG_INVALID: "CONFIG_INVALID";
61
+ readonly CONFIG_NOT_FOUND: "CONFIG_NOT_FOUND";
62
+ readonly FONT_REGISTRATION_FAILED: "FONT_REGISTRATION_FAILED";
63
+ readonly INTERNAL_ERROR: "INTERNAL_ERROR";
64
+ readonly LOCALE_LOAD_FAILED: "LOCALE_LOAD_FAILED";
65
+ readonly PROP_VALIDATION_FAILED: "PROP_VALIDATION_FAILED";
66
+ readonly RENDERER_NOT_INITIALIZED: "RENDERER_NOT_INITIALIZED";
67
+ readonly RENDER_FAILED: "RENDER_FAILED";
68
+ readonly SSE_ERROR: "SSE_ERROR";
69
+ readonly TEMPLATE_INVALID_EXPORT: "TEMPLATE_INVALID_EXPORT";
70
+ readonly TEMPLATE_LOAD_FAILED: "TEMPLATE_LOAD_FAILED";
71
+ readonly TEMPLATE_NOT_FOUND: "TEMPLATE_NOT_FOUND";
72
+ readonly UI_RENDER_ERROR: "UI_RENDER_ERROR";
73
+ };
74
+ type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode];
75
+ declare class AppError extends Error {
76
+ readonly code: ErrorCode;
77
+ readonly context: Record<string, unknown>;
78
+ constructor(code: ErrorCode, message: string, context?: Record<string, unknown>);
79
+ }
80
+ //#endregion
81
+ //#region src/shared/logger.d.ts
82
+ type LogLevel = "debug" | "info" | "warn" | "error";
83
+ declare const logDebug: (message: string, context?: Record<string, unknown>) => void;
84
+ declare const logInfo: (message: string, context?: Record<string, unknown>) => void;
85
+ declare const logWarn: (message: string, context?: Record<string, unknown>) => void;
86
+ declare const logError: (code: ErrorCode, message: string, context?: Record<string, unknown>) => void;
87
+ //#endregion
88
+ //#region src/node/cache-keys.d.ts
89
+ /**
90
+ * Cache key derivation, shared by every component that needs to name a
91
+ * cache entry consistently. Pulled out of the old monolithic RenderCache
92
+ * specifically so CompileCache, MetadataStore, and FsStore all derive keys
93
+ * the same way -- a duplicated hashing implementation across components
94
+ * is exactly the kind of drift risk this split is meant to eliminate.
95
+ */
96
+ interface CompileCacheKeyInput {
97
+ templateId: string;
98
+ templateContentHash: string;
99
+ propsJSON: string;
100
+ }
101
+ interface PixelCacheKeyInput {
102
+ templateContentHash: string;
103
+ propsJSON: string;
104
+ width: number;
105
+ height: number;
106
+ format?: string;
107
+ }
108
+ declare const createCompileCacheKey: (input: CompileCacheKeyInput) => string;
109
+ declare const createPixelCacheKey: (input: PixelCacheKeyInput) => string;
110
+ //#endregion
111
+ //#region src/node/render-cache.d.ts
112
+ interface CacheStats {
113
+ compiled: {
114
+ entries: number;
115
+ };
116
+ pixels: {
117
+ entries: number;
118
+ sizeBytes: number;
119
+ maxSizeBytes: number;
120
+ };
121
+ cacheDir: string;
122
+ }
123
+ interface RenderCacheOptions {
124
+ cacheDir?: string;
125
+ maxSizeMB?: number;
126
+ /** Max in-memory compiled entries to retain. Default 100. */
127
+ compiledMaxEntries?: number;
128
+ /** Caps concurrent Pixel cache disk writes/reads. Default: unbounded (matches pre-split behavior). */
129
+ maxConcurrentWrites?: number;
130
+ /** Debounce window between a write and the next eviction check. Default 250ms. */
131
+ evictionDebounceMs?: number;
132
+ }
133
+ interface SweepOutcome {
134
+ freedBytes: number;
135
+ }
136
+ /**
137
+ * Content-addressed two-stage render cache -- coordinator.
138
+ *
139
+ * This class used to own SQLite calls, filesystem calls, atomicity
140
+ * handling, and eviction policy directly (~400 lines, five
141
+ * responsibilities). It now owns none of that: it constructs and wires
142
+ * together CompileCache, MetadataStore, FsStore, and EvictionCoordinator,
143
+ * and exposes the exact same public method signatures CLI, MCP, and
144
+ * dev-server already depend on. No downstream consumer needs to change
145
+ * anything as a result of this refactor.
146
+ */
147
+ declare class RenderCache {
148
+ private readonly cacheDir;
149
+ private readonly maxSizeBytes;
150
+ private readonly compiled;
151
+ private readonly maxConcurrentWrites;
152
+ private readonly evictionDebounceMs;
153
+ private metadata;
154
+ private fsStore;
155
+ private eviction;
156
+ private initialized;
157
+ static readonly createCompileCacheKey: typeof createCompileCacheKey;
158
+ static readonly createPixelCacheKey: typeof createPixelCacheKey;
159
+ constructor(options?: RenderCacheOptions);
160
+ init(): Promise<void>;
161
+ close(): void;
162
+ getCompiled(key: string): unknown;
163
+ setCompiled(key: string, value: unknown): void;
164
+ setCompiledWithContentHash(key: string, contentHash: string, value: unknown): void;
165
+ invalidateCompiledByContentHash(contentHash: string): void;
166
+ clearCompiled(): void;
167
+ getPixels(key: string): Promise<Buffer | null>;
168
+ setPixels(key: string, bytes: Buffer, width: number, height: number, format?: string): Promise<string>;
169
+ stats(): Promise<CacheStats>;
170
+ /** Full wipe -- unlike a budget-triggered sweep, always removes everything, still lock-coordinated. */
171
+ clean(): Promise<SweepOutcome>;
172
+ private performSweep;
173
+ private requireMetadata;
174
+ private recoverMetadata;
175
+ private requireFsStore;
176
+ private requireEviction;
177
+ }
178
+ //#endregion
179
+ //#region src/node/takumi-types-shim.d.ts
180
+ /**
181
+ * Type-only shim for `@takumi-rs/core` (as re-exported by `takumi-js/node`).
182
+ *
183
+ * Migrated for Takumi v2. The v1 shim existed to work around a broken
184
+ * `export.d.ts` re-export chain in @takumi-rs/core@1.8.6 that hid
185
+ * `render`/`measure` and several option types from consumers on
186
+ * `moduleResolution: "nodenext"`. This file re-declares the v2 surface we
187
+ * actually use, backed by the real runtime export.
188
+ *
189
+ * TODO(verify-on-upgrade): the v1 packaging bug this shim worked around
190
+ * has not been independently re-verified against the v2 release actually
191
+ * installed. Once upgraded, run the same isolated-probe check described
192
+ * in the v1 version of this file (import the types directly from
193
+ * "takumi-js/node" in a throwaway file and see if `render`/`measure`/
194
+ * `registerFont` resolve). If they do, delete this file and switch all
195
+ * importers back to `takumi-js/node` directly. Tracked against the
196
+ * upstream repo: https://github.com/kane50613/takumi
197
+ *
198
+ * v2 breaking changes reflected below (see /docs/upgrade/v2):
199
+ * - `new Renderer(options)` -> `new Renderer()`. The constructor takes no
200
+ * arguments; fonts and images are now per-render options instead of
201
+ * construction-time state.
202
+ * - `loadFont` / `loadFonts` / `loadFontSync` -> `registerFont`. Use this
203
+ * only to preload a font once and reuse it across many renders; most
204
+ * callers should just pass `fonts` on the render/measure call instead.
205
+ * - The persistent image store and `GlobalContext` are gone.
206
+ * `putPersistentImage` / `clearImageStore` no longer exist. Every image
207
+ * a render needs must be passed through `images`, keyed by `src`.
208
+ * - `fetchedResources` -> `images`. `images` also accepts a group form
209
+ * (`{ sources, fetch, fetchCache }`) that combines pre-fetched entries,
210
+ * a custom fetch implementation, and a shared byte cache.
211
+ * - `format` stays a string, but `quality` (jpeg / lossy webp) and
212
+ * `lossless` (webp) are now separate optional fields instead of one
213
+ * combined quality argument.
214
+ * - `fonts` entries may be bare URL strings, fetched and cached on demand,
215
+ * in addition to loaded font descriptors / raw bytes.
216
+ */
217
+ interface FontDescriptor {
218
+ name?: string;
219
+ data: Uint8Array | ArrayBuffer | Buffer | (() => Promise<ArrayBuffer | Uint8Array>);
220
+ weight?: number;
221
+ style?: "normal" | "italic" | "oblique" | `oblique ${number}deg` | (string & {});
222
+ }
223
+ /** A font supplied to a render/measure call: a loaded descriptor, raw bytes, or a bare URL fetched on demand. */
224
+ type Font = FontDescriptor | Uint8Array | ArrayBuffer | Buffer | string;
225
+ interface ImageSourceEntry {
226
+ src: string;
227
+ data: Uint8Array | ArrayBuffer;
228
+ }
229
+ /** Shared byte cache across renders -- dedupes concurrent fetches of the same URL. */
230
+ type ImageFetchCache = Map<string, Promise<ArrayBuffer>>;
231
+ type ImageFetchFn = (url: string, signal?: AbortSignal) => Promise<ArrayBuffer>;
232
+ interface ImageResourcesGroup {
233
+ /** Pre-fetched entries, keyed by src. Not re-fetched. */
234
+ sources?: ImageSourceEntry[];
235
+ fetch?: ImageFetchFn;
236
+ timeout?: number;
237
+ fetchCache?: ImageFetchCache;
238
+ }
239
+ /** Either a flat list of pre-fetched images, or the group form with fetch behavior + a shared cache. */
240
+ type ImagesOption = ImageSourceEntry[] | ImageResourcesGroup;
241
+ type OutputFormat$1 = "webp" | "png" | "jpeg" | "ico" | "raw";
242
+ type DitheringAlgorithm = "none" | "ordered-bayer" | "floyd-steinberg";
243
+ interface RenderOptions {
244
+ width?: number;
245
+ height?: number;
246
+ format?: OutputFormat$1;
247
+ /** JPEG and lossy WebP only. */
248
+ quality?: number;
249
+ /** WebP only (napi binding). Ignored on wasm, where WebP is always lossless. */
250
+ lossless?: boolean;
251
+ drawDebugBorder?: boolean;
252
+ images?: ImagesOption;
253
+ /** Fonts needed for this render. Descriptors, raw bytes, or bare URLs. */
254
+ fonts?: Font[];
255
+ /** Ordered fallback chain of family names. Defaults to every registered family in registration order. */
256
+ fontFamilies?: string[];
257
+ /** BCP-47 language tag for locale-aware shaping. Inherited by children. */
258
+ lang?: string;
259
+ stylesheets?: string[];
260
+ devicePixelRatio?: number;
261
+ timeMs?: number;
262
+ dithering?: DitheringAlgorithm;
263
+ }
264
+ interface MeasuredTextRun {
265
+ text: string;
266
+ x: number;
267
+ y: number;
268
+ width: number;
269
+ height: number;
270
+ }
271
+ interface MeasuredNode {
272
+ width: number;
273
+ height: number;
274
+ transform: [number, number, number, number, number, number];
275
+ children: MeasuredNode[];
276
+ runs: MeasuredTextRun[];
277
+ }
278
+ //#endregion
279
+ //#region src/node/renderer.d.ts
280
+ /**
281
+ * Preload a font once and reuse it across many renders without re-passing
282
+ * its bytes on every call. Optional -- per Takumi's v2 guidance, passing
283
+ * `fonts` directly in a render/measure call's options covers most cases.
284
+ */
285
+ declare const registerFont: (font: Font, signal?: AbortSignal) => Promise<string[]>;
286
+ interface RenderOutput {
287
+ bytes: Buffer;
288
+ width: number;
289
+ height: number;
290
+ format: NonNullable<RenderOptions["format"]>;
291
+ }
292
+ /**
293
+ * Renders a compiled template to pixels.
294
+ *
295
+ * `width`/`height` are REQUIRED here, not optional pass-through fields.
296
+ * Takumi's `render()` returns only a Buffer -- it does not report back the
297
+ * dimensions it used, so auto-sized output isn't supported by this
298
+ * wrapper. Callers that need auto-sizing must call `measureTemplate` first
299
+ * and pass the resulting width/height through explicitly (see
300
+ * `renderAutoSized` below).
301
+ *
302
+ * Any `fonts`/`fontFamilies`/`images` the template needs must be supplied
303
+ * via `options` -- there is no construction-time renderer config to fall
304
+ * back on in v2.
305
+ */
306
+ declare const renderToPixels: (template: CompiledTemplate, dimensions: {
307
+ width: number;
308
+ height: number;
309
+ }, options?: Omit<RenderOptions, "width" | "height">, signal?: AbortSignal) => Promise<RenderOutput>;
310
+ declare const measureTemplate: (template: CompiledTemplate, options?: RenderOptions, signal?: AbortSignal) => Promise<MeasuredNode>;
311
+ /**
312
+ * Convenience: measure to discover natural dimensions, then render at
313
+ * those dimensions in one call. This is the "auto-size" path -- it costs
314
+ * one extra round-trip into the renderer vs. passing explicit dimensions,
315
+ * so prefer explicit width/height (e.g. from a chosen output preset) when
316
+ * you have them.
317
+ */
318
+ declare const renderAutoSized: (template: CompiledTemplate, options?: RenderOptions, signal?: AbortSignal) => Promise<RenderOutput>;
319
+ //#endregion
320
+ //#region src/batch/types.d.ts
321
+ type OutputFormat = "webp" | "png" | "jpeg" | "ico" | "raw";
322
+ interface MatrixCell {
323
+ rowIndex: number;
324
+ rowKey: string;
325
+ locale: string;
326
+ preset: Pick<Preset, "id" | "width" | "height">;
327
+ props: Record<string, unknown>;
328
+ }
329
+ interface RenderOneInput {
330
+ compiledTemplate: CompiledTemplate;
331
+ templateId: string;
332
+ contentHash: string;
333
+ props: Record<string, unknown>;
334
+ width: number;
335
+ height: number;
336
+ locale?: string;
337
+ format?: OutputFormat;
338
+ cache: RenderCache;
339
+ outDir: string;
340
+ filename: string;
341
+ signal?: AbortSignal;
342
+ renderOptions?: Pick<RenderOptions, "fonts" | "fontFamilies" | "lang"> & Record<string, unknown>;
343
+ }
344
+ interface RenderOneOutput {
345
+ outputPath: string;
346
+ cacheHit: boolean;
347
+ durationMs: number;
348
+ }
349
+ interface ManifestEntry {
350
+ rowIndex: number;
351
+ locale: string;
352
+ preset: string;
353
+ outputPath: string;
354
+ cacheHit: boolean;
355
+ }
356
+ interface Manifest {
357
+ status: "completed" | "aborted";
358
+ completedCount: number;
359
+ totalCount: number;
360
+ succeeded: ManifestEntry[];
361
+ failed: {
362
+ rowIndex: number;
363
+ locale: string;
364
+ preset: string;
365
+ error: string;
366
+ }[];
367
+ }
368
+ //#endregion
369
+ //#region src/batch/matrix.d.ts
370
+ interface MatrixLocaleInput {
371
+ id: string;
372
+ data?: Record<string, unknown>;
373
+ }
374
+ interface DataRow {
375
+ key?: string;
376
+ id?: string;
377
+ slug?: string;
378
+ [key: string]: unknown;
379
+ }
380
+ interface MatrixInput {
381
+ rows: DataRow[];
382
+ locales: MatrixLocaleInput[];
383
+ presets: Pick<Preset, "id" | "width" | "height">[];
384
+ baseProps?: Record<string, unknown>;
385
+ }
386
+ /**
387
+ * Expands rows × locales × presets into a flat array of matrix cells.
388
+ * Locale data is merged into props during expansion so each cell carries
389
+ * fully resolved props.
390
+ */
391
+ declare const expandMatrix: (input: MatrixInput) => MatrixCell[];
392
+ //#endregion
393
+ //#region src/batch/render-one.d.ts
394
+ declare const renderOne: (input: RenderOneInput) => Promise<RenderOneOutput>;
395
+ //#endregion
396
+ //#region src/batch/naming.d.ts
397
+ interface NamingOptions {
398
+ templateId: string;
399
+ locale: string;
400
+ presetId: string;
401
+ rowKey: string;
402
+ format?: string;
403
+ }
404
+ declare const generateOutputFilename: (options: NamingOptions) => string;
405
+ //#endregion
406
+ //#region src/batch/manifest.d.ts
407
+ declare const writeManifest: (filePath: string, manifest: Manifest) => Promise<void>;
408
+ //#endregion
409
+ //#region src/batch/single.d.ts
410
+ interface SingleInput {
411
+ component: ComponentType<any>;
412
+ propsSchema: PropSchema;
413
+ props: Record<string, unknown>;
414
+ preset: {
415
+ id: string;
416
+ width: number;
417
+ height: number;
418
+ };
419
+ outDir?: string;
420
+ format?: "webp" | "png" | "jpeg" | "ico" | "raw";
421
+ }
422
+ interface SingleOutput {
423
+ outputPath: string;
424
+ }
425
+ declare const renderComponent: (input: SingleInput) => Promise<SingleOutput>;
426
+ //#endregion
427
+ //#region src/batch/batch.d.ts
428
+ interface BatchInput {
429
+ rootDir: string;
430
+ templateId: string;
431
+ dataFile?: string;
432
+ rows?: Record<string, unknown>[];
433
+ baseProps?: Record<string, unknown>;
434
+ presets?: string[];
435
+ locales?: string[];
436
+ outDir?: string;
437
+ cacheDir?: string;
438
+ concurrency?: number;
439
+ failFast?: boolean;
440
+ }
441
+ interface BatchOutput {
442
+ manifest: Manifest;
443
+ elapsedMs: number;
444
+ }
445
+ declare const runBatch: (input: BatchInput) => Promise<BatchOutput>;
446
+ //#endregion
447
+ //#region src/batch/loaders.d.ts
448
+ interface LoadedTemplate {
449
+ module: TemplateModule;
450
+ contentHash: string;
451
+ }
452
+ declare const loadConfig: (rootDir: string) => Promise<StudioConfig>;
453
+ declare const importTemplateForBatch: (rootDir: string, componentPath: string, templateId: string) => Promise<LoadedTemplate>;
454
+ declare const parseDataFile: (filePath: string) => Promise<Record<string, unknown>[]>;
455
+ declare const resolveLocales: (rootDir: string, localeCodes: string[], templateId: string) => Promise<{
456
+ id: string;
457
+ data?: Record<string, unknown>;
458
+ }[]>;
459
+ //#endregion
460
+ export { AppError, type BatchInput, type BatchOutput, type CacheStats, type CompileCacheKeyInput, type CompiledTemplate, type DataRow, ErrorCode, type ErrorCode as ErrorCodeType, type Font, type LoadedTemplate, type LogLevel, type Manifest, type ManifestEntry, type MatrixCell, type MatrixInput, type MatrixLocaleInput, type NamingOptions, type PixelCacheKeyInput, type Preset, PropValidationError, type PropValidationIssue, RenderCache, type RenderCacheOptions, type RenderOneInput, type RenderOneOutput, type RenderOptions, type RenderOutput, type SingleInput, type SingleOutput, type StudioConfig, type TemplateEntry, type TemplateModule, compileTemplate, expandMatrix, generateOutputFilename, importTemplateForBatch, isZodObject, loadConfig, logDebug, logError, logInfo, logWarn, measureTemplate, parseDataFile, registerFont, renderAutoSized, renderComponent, renderOne, renderToPixels, resolveLocales, runBatch, studioConfigSchema, validateProps, writeManifest, zodToJsonSchemaShape };