@akairos/typeset-studio 0.2.0 → 0.2.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": "@akairos/typeset-studio",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Algorithmic typesetting studio & zzhub-pipeline image renderer plugin",
5
5
  "publishConfig": {
6
6
  "access": "public"
package/src/adapter.ts CHANGED
@@ -192,7 +192,7 @@ async function renderRemoteBatch(
192
192
 
193
193
  export const typesetStudioAdapter: ImageRenderPlugin = {
194
194
  name: "typeset-studio",
195
- version: "0.2.0",
195
+ version: "0.2.1",
196
196
 
197
197
  async doctor(): Promise<PipelinePluginDoctorCheck[]> {
198
198
  const checks: PipelinePluginDoctorCheck[] = [];
@@ -1,20 +1,38 @@
1
1
  import { existsSync, mkdirSync, readdirSync, readFileSync, unlinkSync, writeFileSync } from "fs";
2
- import { join } from "path";
2
+ import { dirname, join, resolve } from "path";
3
+ import { fileURLToPath } from "url";
3
4
  import { Hono } from "hono";
4
5
  import { getDefaultConfig } from "../../core/engine";
5
6
  import { TemplateSlot, TypesetConfig } from "../../core/types";
6
7
 
7
- const TEMPLATES_DIR = join(process.cwd(), "data", "templates");
8
+ export function resolveDataDir(): string {
9
+ if (process.env.TYPESET_DATA_DIR) {
10
+ return process.env.TYPESET_DATA_DIR;
11
+ }
12
+ const currentDir = typeof __dirname !== "undefined" ? __dirname : dirname(fileURLToPath(import.meta.url));
13
+ const candidateLib = resolve(currentDir, "../../data");
14
+ if (existsSync(candidateLib)) return candidateLib;
15
+ const candidateSrc = resolve(currentDir, "../../../data");
16
+ if (existsSync(candidateSrc)) return candidateSrc;
17
+ const candidateCwd = resolve(process.cwd(), "data");
18
+ if (existsSync(candidateCwd)) return candidateCwd;
19
+ return candidateLib;
20
+ }
21
+
22
+ const TEMPLATES_DIR = join(resolveDataDir(), "templates");
8
23
 
9
24
  function ensureTemplatesDir(): void {
10
25
  if (!existsSync(TEMPLATES_DIR)) {
11
- mkdirSync(TEMPLATES_DIR, { recursive: true });
26
+ try {
27
+ mkdirSync(TEMPLATES_DIR, { recursive: true });
28
+ } catch {
29
+ // Ignore write errors in read-only environments
30
+ }
12
31
  }
13
32
  seedDefaultTemplates();
14
33
  }
15
34
 
16
- function seedDefaultTemplates(): void {
17
- const presets: TypesetConfig[] = [
35
+ export const BUILTIN_PRESETS: TypesetConfig[] = [
18
36
  {
19
37
  ...getDefaultConfig("wechat-cover-2.35"),
20
38
  id: "tpl_wechat_cover_minimal",
@@ -325,13 +343,21 @@ function seedDefaultTemplates(): void {
325
343
  },
326
344
  ];
327
345
 
328
- for (const preset of presets) {
346
+ function seedDefaultTemplates(): void {
347
+ if (!existsSync(TEMPLATES_DIR)) return;
348
+ for (const preset of BUILTIN_PRESETS) {
329
349
  const filePath = join(TEMPLATES_DIR, `${preset.id}.json`);
330
- writeFileSync(filePath, JSON.stringify(preset, null, 2), "utf-8");
350
+ if (!existsSync(filePath)) {
351
+ try {
352
+ writeFileSync(filePath, JSON.stringify(preset, null, 2), "utf-8");
353
+ } catch {
354
+ // Ignore write failures in package directories
355
+ }
356
+ }
331
357
  }
332
358
  }
333
359
 
334
- const DEFAULT_SETTINGS_PATH = join(process.cwd(), "data", "default-template.json");
360
+ const DEFAULT_SETTINGS_PATH = join(resolveDataDir(), "default-template.json");
335
361
 
336
362
  export const BUILTIN_SLOT_DEFAULTS: Record<TemplateSlot, string> = {
337
363
  article_cover: "tpl_wechat_cover_minimal",
@@ -411,7 +437,21 @@ export function setDefaultTemplateId(id: string): void {
411
437
  }
412
438
 
413
439
  export function findTemplateByKeyOrName(key: string): TypesetConfig | null {
414
- ensureTemplatesDir();
440
+ const lowerKey = key.trim().toLowerCase();
441
+
442
+ // 1. Direct match in built-in memory presets
443
+ const builtin = BUILTIN_PRESETS.find(
444
+ (p) => p.id?.toLowerCase() === lowerKey || p.name.toLowerCase() === lowerKey,
445
+ );
446
+ if (builtin) return builtin;
447
+
448
+ // 2. Partial match in built-in memory presets
449
+ const builtinPartial = BUILTIN_PRESETS.find((p) => p.name.toLowerCase().includes(lowerKey));
450
+ if (builtinPartial) return builtinPartial;
451
+
452
+ // 3. Scan disk if templates directory exists
453
+ if (!existsSync(TEMPLATES_DIR)) return null;
454
+
415
455
  const directPath = join(TEMPLATES_DIR, `${key}.json`);
416
456
  if (existsSync(directPath)) {
417
457
  try {
@@ -421,9 +461,8 @@ export function findTemplateByKeyOrName(key: string): TypesetConfig | null {
421
461
  }
422
462
  }
423
463
 
424
- // Scan all templates
464
+ // Scan all templates on disk
425
465
  const files = readdirSync(TEMPLATES_DIR).filter((f) => f.endsWith(".json"));
426
- const lowerKey = key.trim().toLowerCase();
427
466
 
428
467
  for (const file of files) {
429
468
  try {