@notion-headless-cms/core 0.3.6 → 0.3.8

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,5 +1,5 @@
1
- import { a as StorageBinary, i as CachedItemList, r as CachedItem, t as BaseContentItem } from "../content-WydAfQtk.mjs";
2
- import { l as InvalidateScope, n as DocumentCacheAdapter, r as ImageCacheAdapter } from "../cache-D051BP4G.mjs";
1
+ import { a as CachedItemMeta, i as CachedItemList, r as CachedItemContent, s as StorageBinary, t as BaseContentItem } from "../content-DyrOwjbA.mjs";
2
+ import { n as DocumentCacheAdapter, r as ImageCacheAdapter, u as InvalidateScope } from "../cache-QrXdXYMs.mjs";
3
3
 
4
4
  //#region src/cache/memory.d.ts
5
5
  interface MemoryDocumentCacheOptions {
@@ -16,13 +16,16 @@ interface MemoryImageCacheOptions {
16
16
  declare class MemoryDocumentCache<T extends BaseContentItem = BaseContentItem> implements DocumentCacheAdapter<T> {
17
17
  readonly name = "memory-document";
18
18
  private list;
19
- private items;
19
+ private metas;
20
+ private contents;
20
21
  private readonly maxItems;
21
22
  constructor(options?: MemoryDocumentCacheOptions);
22
23
  getList(): Promise<CachedItemList<T> | null>;
23
24
  setList(data: CachedItemList<T>): Promise<void>;
24
- getItem(slug: string): Promise<CachedItem<T> | null>;
25
- setItem(slug: string, data: CachedItem<T>): Promise<void>;
25
+ getItemMeta(slug: string): Promise<CachedItemMeta<T> | null>;
26
+ setItemMeta(slug: string, data: CachedItemMeta<T>): Promise<void>;
27
+ getItemContent(slug: string): Promise<CachedItemContent | null>;
28
+ setItemContent(slug: string, data: CachedItemContent): Promise<void>;
26
29
  invalidate(scope: InvalidateScope): Promise<void>;
27
30
  private enforceLimit;
28
31
  }
@@ -13,7 +13,8 @@ function touch(map, key) {
13
13
  var MemoryDocumentCache = class {
14
14
  name = "memory-document";
15
15
  list = null;
16
- items = /* @__PURE__ */ new Map();
16
+ metas = /* @__PURE__ */ new Map();
17
+ contents = /* @__PURE__ */ new Map();
17
18
  maxItems;
18
19
  constructor(options) {
19
20
  this.maxItems = options?.maxItems;
@@ -25,36 +26,61 @@ var MemoryDocumentCache = class {
25
26
  this.list = data;
26
27
  return Promise.resolve();
27
28
  }
28
- getItem(slug) {
29
- const entry = this.items.get(slug);
30
- if (entry) touch(this.items, slug);
29
+ getItemMeta(slug) {
30
+ const entry = this.metas.get(slug);
31
+ if (entry) touch(this.metas, slug);
31
32
  return Promise.resolve(entry ?? null);
32
33
  }
33
- setItem(slug, data) {
34
- if (this.items.has(slug)) this.items.delete(slug);
35
- this.items.set(slug, data);
34
+ setItemMeta(slug, data) {
35
+ if (this.metas.has(slug)) this.metas.delete(slug);
36
+ this.metas.set(slug, data);
37
+ this.enforceLimit();
38
+ return Promise.resolve();
39
+ }
40
+ getItemContent(slug) {
41
+ const entry = this.contents.get(slug);
42
+ if (entry) touch(this.contents, slug);
43
+ return Promise.resolve(entry ?? null);
44
+ }
45
+ setItemContent(slug, data) {
46
+ if (this.contents.has(slug)) this.contents.delete(slug);
47
+ this.contents.set(slug, data);
36
48
  this.enforceLimit();
37
49
  return Promise.resolve();
38
50
  }
39
51
  async invalidate(scope) {
40
52
  if (scope === "all") {
41
53
  this.list = null;
42
- this.items.clear();
54
+ this.metas.clear();
55
+ this.contents.clear();
43
56
  return;
44
57
  }
45
- this.list = null;
46
- if ("slug" in scope) this.items.delete(scope.slug);
47
- else {
58
+ const kind = scope.kind ?? "all";
59
+ if (kind === "all" || kind === "meta") this.list = null;
60
+ if ("slug" in scope) {
61
+ if (kind === "all" || kind === "meta") this.metas.delete(scope.slug);
62
+ if (kind === "all" || kind === "content") this.contents.delete(scope.slug);
63
+ } else {
48
64
  const prefix = `${scope.collection}:`;
49
- for (const key of [...this.items.keys()]) if (key.startsWith(prefix)) this.items.delete(key);
65
+ if (kind === "all" || kind === "meta") {
66
+ for (const key of [...this.metas.keys()]) if (key.startsWith(prefix)) this.metas.delete(key);
67
+ }
68
+ if (kind === "all" || kind === "content") {
69
+ for (const key of [...this.contents.keys()]) if (key.startsWith(prefix)) this.contents.delete(key);
70
+ }
50
71
  }
51
72
  }
52
73
  enforceLimit() {
53
74
  if (this.maxItems === void 0) return;
54
- while (this.items.size > this.maxItems) {
55
- const firstKey = this.items.keys().next().value;
75
+ while (this.metas.size > this.maxItems) {
76
+ const firstKey = this.metas.keys().next().value;
77
+ if (firstKey === void 0) break;
78
+ this.metas.delete(firstKey);
79
+ }
80
+ while (this.contents.size > this.maxItems) {
81
+ const firstKey = this.contents.keys().next().value;
56
82
  if (firstKey === void 0) break;
57
- this.items.delete(firstKey);
83
+ this.contents.delete(firstKey);
58
84
  }
59
85
  }
60
86
  };
@@ -1 +1 @@
1
- {"version":3,"file":"memory.mjs","names":[],"sources":["../../src/cache/memory.ts"],"sourcesContent":["import type {\n\tBaseContentItem,\n\tCachedItem,\n\tCachedItemList,\n\tDocumentCacheAdapter,\n\tImageCacheAdapter,\n\tInvalidateScope,\n\tStorageBinary,\n} from \"../types/index\";\n\nexport interface MemoryDocumentCacheOptions {\n\t/** アイテム保持上限。未指定時は上限なし。超過時は LRU で古いものから削除。 */\n\tmaxItems?: number;\n}\n\nexport interface MemoryImageCacheOptions {\n\t/** エントリ保持上限。未指定時は上限なし。超過時は LRU で古いものから削除。 */\n\tmaxItems?: number;\n\t/** 合計保持サイズ上限(バイト)。未指定時は上限なし。超過時は LRU で古いものから削除。 */\n\tmaxSizeBytes?: number;\n}\n\n/**\n * Map の挿入順を LRU として扱う軽量実装。\n * `touch` で既存キーを末尾に移動、`enforceLimit` で古いキー(先頭)から削除する。\n */\nfunction touch<K, V>(map: Map<K, V>, key: K): void {\n\tconst v = map.get(key);\n\tif (v === undefined) return;\n\tmap.delete(key);\n\tmap.set(key, v);\n}\n\n/** インメモリのドキュメントキャッシュ実装。プロセス再起動でクリアされる。ローカル開発向け。 */\nexport class MemoryDocumentCache<T extends BaseContentItem = BaseContentItem>\n\timplements DocumentCacheAdapter<T>\n{\n\treadonly name = \"memory-document\";\n\tprivate list: CachedItemList<T> | null = null;\n\tprivate items = new Map<string, CachedItem<T>>();\n\tprivate readonly maxItems: number | undefined;\n\n\tconstructor(options?: MemoryDocumentCacheOptions) {\n\t\tthis.maxItems = options?.maxItems;\n\t}\n\n\tgetList(): Promise<CachedItemList<T> | null> {\n\t\treturn Promise.resolve(this.list);\n\t}\n\n\tsetList(data: CachedItemList<T>): Promise<void> {\n\t\tthis.list = data;\n\t\treturn Promise.resolve();\n\t}\n\n\tgetItem(slug: string): Promise<CachedItem<T> | null> {\n\t\tconst entry = this.items.get(slug);\n\t\tif (entry) touch(this.items, slug);\n\t\treturn Promise.resolve(entry ?? null);\n\t}\n\n\tsetItem(slug: string, data: CachedItem<T>): Promise<void> {\n\t\tif (this.items.has(slug)) this.items.delete(slug);\n\t\tthis.items.set(slug, data);\n\t\tthis.enforceLimit();\n\t\treturn Promise.resolve();\n\t}\n\n\tasync invalidate(scope: InvalidateScope): Promise<void> {\n\t\tif (scope === \"all\") {\n\t\t\tthis.list = null;\n\t\t\tthis.items.clear();\n\t\t\treturn;\n\t\t}\n\t\t// list は常に破棄する\n\t\tthis.list = null;\n\t\tif (\"slug\" in scope) {\n\t\t\tthis.items.delete(scope.slug);\n\t\t} else {\n\t\t\t// { collection }: プレフィックスに一致するアイテムをすべて削除する\n\t\t\t// scopeDocumentCache 経由の場合、キーは `{collection}:{slug}` 形式になる\n\t\t\tconst prefix = `${scope.collection}:`;\n\t\t\tfor (const key of [...this.items.keys()]) {\n\t\t\t\tif (key.startsWith(prefix)) {\n\t\t\t\t\tthis.items.delete(key);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate enforceLimit(): void {\n\t\tif (this.maxItems === undefined) return;\n\t\twhile (this.items.size > this.maxItems) {\n\t\t\tconst firstKey = this.items.keys().next().value;\n\t\t\tif (firstKey === undefined) break;\n\t\t\tthis.items.delete(firstKey);\n\t\t}\n\t}\n}\n\n/** インメモリの画像キャッシュ実装。プロセス再起動でクリアされる。ローカル開発向け。 */\nexport class MemoryImageCache implements ImageCacheAdapter {\n\treadonly name = \"memory-image\";\n\tprivate store = new Map<string, StorageBinary>();\n\tprivate totalBytes = 0;\n\tprivate readonly maxItems: number | undefined;\n\tprivate readonly maxSizeBytes: number | undefined;\n\n\tconstructor(options?: MemoryImageCacheOptions) {\n\t\tthis.maxItems = options?.maxItems;\n\t\tthis.maxSizeBytes = options?.maxSizeBytes;\n\t}\n\n\tget(hash: string): Promise<StorageBinary | null> {\n\t\tconst entry = this.store.get(hash);\n\t\tif (entry) touch(this.store, hash);\n\t\treturn Promise.resolve(entry ?? null);\n\t}\n\n\tset(hash: string, data: ArrayBuffer, contentType: string): Promise<void> {\n\t\tconst existing = this.store.get(hash);\n\t\tif (existing) {\n\t\t\tthis.totalBytes -= existing.data.byteLength;\n\t\t\tthis.store.delete(hash);\n\t\t}\n\t\tthis.store.set(hash, { data, contentType });\n\t\tthis.totalBytes += data.byteLength;\n\t\tthis.enforceLimit();\n\t\treturn Promise.resolve();\n\t}\n\n\tprivate enforceLimit(): void {\n\t\twhile (\n\t\t\t(this.maxItems !== undefined && this.store.size > this.maxItems) ||\n\t\t\t(this.maxSizeBytes !== undefined && this.totalBytes > this.maxSizeBytes)\n\t\t) {\n\t\t\tconst firstKey = this.store.keys().next().value;\n\t\t\tif (firstKey === undefined) break;\n\t\t\tconst victim = this.store.get(firstKey);\n\t\t\tif (victim) this.totalBytes -= victim.data.byteLength;\n\t\t\tthis.store.delete(firstKey);\n\t\t}\n\t}\n}\n\n/** インメモリキャッシュ(ドキュメント用)を生成する。 */\nexport function memoryDocumentCache<\n\tT extends BaseContentItem = BaseContentItem,\n>(options?: MemoryDocumentCacheOptions): DocumentCacheAdapter<T> {\n\treturn new MemoryDocumentCache<T>(options);\n}\n\n/** インメモリキャッシュ(画像用)を生成する。 */\nexport function memoryImageCache(\n\toptions?: MemoryImageCacheOptions,\n): ImageCacheAdapter {\n\treturn new MemoryImageCache(options);\n}\n"],"mappings":";;;;;AA0BA,SAAS,MAAY,KAAgB,KAAc;CAClD,MAAM,IAAI,IAAI,IAAI,IAAI;AACtB,KAAI,MAAM,KAAA,EAAW;AACrB,KAAI,OAAO,IAAI;AACf,KAAI,IAAI,KAAK,EAAE;;;AAIhB,IAAa,sBAAb,MAEA;CACC,OAAgB;CAChB,OAAyC;CACzC,wBAAgB,IAAI,KAA4B;CAChD;CAEA,YAAY,SAAsC;AACjD,OAAK,WAAW,SAAS;;CAG1B,UAA6C;AAC5C,SAAO,QAAQ,QAAQ,KAAK,KAAK;;CAGlC,QAAQ,MAAwC;AAC/C,OAAK,OAAO;AACZ,SAAO,QAAQ,SAAS;;CAGzB,QAAQ,MAA6C;EACpD,MAAM,QAAQ,KAAK,MAAM,IAAI,KAAK;AAClC,MAAI,MAAO,OAAM,KAAK,OAAO,KAAK;AAClC,SAAO,QAAQ,QAAQ,SAAS,KAAK;;CAGtC,QAAQ,MAAc,MAAoC;AACzD,MAAI,KAAK,MAAM,IAAI,KAAK,CAAE,MAAK,MAAM,OAAO,KAAK;AACjD,OAAK,MAAM,IAAI,MAAM,KAAK;AAC1B,OAAK,cAAc;AACnB,SAAO,QAAQ,SAAS;;CAGzB,MAAM,WAAW,OAAuC;AACvD,MAAI,UAAU,OAAO;AACpB,QAAK,OAAO;AACZ,QAAK,MAAM,OAAO;AAClB;;AAGD,OAAK,OAAO;AACZ,MAAI,UAAU,MACb,MAAK,MAAM,OAAO,MAAM,KAAK;OACvB;GAGN,MAAM,SAAS,GAAG,MAAM,WAAW;AACnC,QAAK,MAAM,OAAO,CAAC,GAAG,KAAK,MAAM,MAAM,CAAC,CACvC,KAAI,IAAI,WAAW,OAAO,CACzB,MAAK,MAAM,OAAO,IAAI;;;CAM1B,eAA6B;AAC5B,MAAI,KAAK,aAAa,KAAA,EAAW;AACjC,SAAO,KAAK,MAAM,OAAO,KAAK,UAAU;GACvC,MAAM,WAAW,KAAK,MAAM,MAAM,CAAC,MAAM,CAAC;AAC1C,OAAI,aAAa,KAAA,EAAW;AAC5B,QAAK,MAAM,OAAO,SAAS;;;;;AAM9B,IAAa,mBAAb,MAA2D;CAC1D,OAAgB;CAChB,wBAAgB,IAAI,KAA4B;CAChD,aAAqB;CACrB;CACA;CAEA,YAAY,SAAmC;AAC9C,OAAK,WAAW,SAAS;AACzB,OAAK,eAAe,SAAS;;CAG9B,IAAI,MAA6C;EAChD,MAAM,QAAQ,KAAK,MAAM,IAAI,KAAK;AAClC,MAAI,MAAO,OAAM,KAAK,OAAO,KAAK;AAClC,SAAO,QAAQ,QAAQ,SAAS,KAAK;;CAGtC,IAAI,MAAc,MAAmB,aAAoC;EACxE,MAAM,WAAW,KAAK,MAAM,IAAI,KAAK;AACrC,MAAI,UAAU;AACb,QAAK,cAAc,SAAS,KAAK;AACjC,QAAK,MAAM,OAAO,KAAK;;AAExB,OAAK,MAAM,IAAI,MAAM;GAAE;GAAM;GAAa,CAAC;AAC3C,OAAK,cAAc,KAAK;AACxB,OAAK,cAAc;AACnB,SAAO,QAAQ,SAAS;;CAGzB,eAA6B;AAC5B,SACE,KAAK,aAAa,KAAA,KAAa,KAAK,MAAM,OAAO,KAAK,YACtD,KAAK,iBAAiB,KAAA,KAAa,KAAK,aAAa,KAAK,cAC1D;GACD,MAAM,WAAW,KAAK,MAAM,MAAM,CAAC,MAAM,CAAC;AAC1C,OAAI,aAAa,KAAA,EAAW;GAC5B,MAAM,SAAS,KAAK,MAAM,IAAI,SAAS;AACvC,OAAI,OAAQ,MAAK,cAAc,OAAO,KAAK;AAC3C,QAAK,MAAM,OAAO,SAAS;;;;;AAM9B,SAAgB,oBAEd,SAA+D;AAChE,QAAO,IAAI,oBAAuB,QAAQ;;;AAI3C,SAAgB,iBACf,SACoB;AACpB,QAAO,IAAI,iBAAiB,QAAQ"}
1
+ {"version":3,"file":"memory.mjs","names":[],"sources":["../../src/cache/memory.ts"],"sourcesContent":["import type {\n\tBaseContentItem,\n\tCachedItemContent,\n\tCachedItemList,\n\tCachedItemMeta,\n\tDocumentCacheAdapter,\n\tImageCacheAdapter,\n\tInvalidateScope,\n\tStorageBinary,\n} from \"../types/index\";\n\nexport interface MemoryDocumentCacheOptions {\n\t/** アイテム保持上限。未指定時は上限なし。超過時は LRU で古いものから削除。 */\n\tmaxItems?: number;\n}\n\nexport interface MemoryImageCacheOptions {\n\t/** エントリ保持上限。未指定時は上限なし。超過時は LRU で古いものから削除。 */\n\tmaxItems?: number;\n\t/** 合計保持サイズ上限(バイト)。未指定時は上限なし。超過時は LRU で古いものから削除。 */\n\tmaxSizeBytes?: number;\n}\n\n/**\n * Map の挿入順を LRU として扱う軽量実装。\n * `touch` で既存キーを末尾に移動、`enforceLimit` で古いキー(先頭)から削除する。\n */\nfunction touch<K, V>(map: Map<K, V>, key: K): void {\n\tconst v = map.get(key);\n\tif (v === undefined) return;\n\tmap.delete(key);\n\tmap.set(key, v);\n}\n\n/** インメモリのドキュメントキャッシュ実装。プロセス再起動でクリアされる。ローカル開発向け。 */\nexport class MemoryDocumentCache<T extends BaseContentItem = BaseContentItem>\n\timplements DocumentCacheAdapter<T>\n{\n\treadonly name = \"memory-document\";\n\tprivate list: CachedItemList<T> | null = null;\n\tprivate metas = new Map<string, CachedItemMeta<T>>();\n\tprivate contents = new Map<string, CachedItemContent>();\n\tprivate readonly maxItems: number | undefined;\n\n\tconstructor(options?: MemoryDocumentCacheOptions) {\n\t\tthis.maxItems = options?.maxItems;\n\t}\n\n\tgetList(): Promise<CachedItemList<T> | null> {\n\t\treturn Promise.resolve(this.list);\n\t}\n\n\tsetList(data: CachedItemList<T>): Promise<void> {\n\t\tthis.list = data;\n\t\treturn Promise.resolve();\n\t}\n\n\tgetItemMeta(slug: string): Promise<CachedItemMeta<T> | null> {\n\t\tconst entry = this.metas.get(slug);\n\t\tif (entry) touch(this.metas, slug);\n\t\treturn Promise.resolve(entry ?? null);\n\t}\n\n\tsetItemMeta(slug: string, data: CachedItemMeta<T>): Promise<void> {\n\t\tif (this.metas.has(slug)) this.metas.delete(slug);\n\t\tthis.metas.set(slug, data);\n\t\tthis.enforceLimit();\n\t\treturn Promise.resolve();\n\t}\n\n\tgetItemContent(slug: string): Promise<CachedItemContent | null> {\n\t\tconst entry = this.contents.get(slug);\n\t\tif (entry) touch(this.contents, slug);\n\t\treturn Promise.resolve(entry ?? null);\n\t}\n\n\tsetItemContent(slug: string, data: CachedItemContent): Promise<void> {\n\t\tif (this.contents.has(slug)) this.contents.delete(slug);\n\t\tthis.contents.set(slug, data);\n\t\tthis.enforceLimit();\n\t\treturn Promise.resolve();\n\t}\n\n\tasync invalidate(scope: InvalidateScope): Promise<void> {\n\t\tif (scope === \"all\") {\n\t\t\tthis.list = null;\n\t\t\tthis.metas.clear();\n\t\t\tthis.contents.clear();\n\t\t\treturn;\n\t\t}\n\t\tconst kind = scope.kind ?? \"all\";\n\t\tif (kind === \"all\" || kind === \"meta\") {\n\t\t\tthis.list = null;\n\t\t}\n\t\tif (\"slug\" in scope) {\n\t\t\tif (kind === \"all\" || kind === \"meta\") this.metas.delete(scope.slug);\n\t\t\tif (kind === \"all\" || kind === \"content\")\n\t\t\t\tthis.contents.delete(scope.slug);\n\t\t} else {\n\t\t\t// scopeDocumentCache 経由でキーは `{collection}:{slug}` 形式になる\n\t\t\tconst prefix = `${scope.collection}:`;\n\t\t\tif (kind === \"all\" || kind === \"meta\") {\n\t\t\t\tfor (const key of [...this.metas.keys()]) {\n\t\t\t\t\tif (key.startsWith(prefix)) this.metas.delete(key);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (kind === \"all\" || kind === \"content\") {\n\t\t\t\tfor (const key of [...this.contents.keys()]) {\n\t\t\t\t\tif (key.startsWith(prefix)) this.contents.delete(key);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate enforceLimit(): void {\n\t\tif (this.maxItems === undefined) return;\n\t\twhile (this.metas.size > this.maxItems) {\n\t\t\tconst firstKey = this.metas.keys().next().value;\n\t\t\tif (firstKey === undefined) break;\n\t\t\tthis.metas.delete(firstKey);\n\t\t}\n\t\twhile (this.contents.size > this.maxItems) {\n\t\t\tconst firstKey = this.contents.keys().next().value;\n\t\t\tif (firstKey === undefined) break;\n\t\t\tthis.contents.delete(firstKey);\n\t\t}\n\t}\n}\n\n/** インメモリの画像キャッシュ実装。プロセス再起動でクリアされる。ローカル開発向け。 */\nexport class MemoryImageCache implements ImageCacheAdapter {\n\treadonly name = \"memory-image\";\n\tprivate store = new Map<string, StorageBinary>();\n\tprivate totalBytes = 0;\n\tprivate readonly maxItems: number | undefined;\n\tprivate readonly maxSizeBytes: number | undefined;\n\n\tconstructor(options?: MemoryImageCacheOptions) {\n\t\tthis.maxItems = options?.maxItems;\n\t\tthis.maxSizeBytes = options?.maxSizeBytes;\n\t}\n\n\tget(hash: string): Promise<StorageBinary | null> {\n\t\tconst entry = this.store.get(hash);\n\t\tif (entry) touch(this.store, hash);\n\t\treturn Promise.resolve(entry ?? null);\n\t}\n\n\tset(hash: string, data: ArrayBuffer, contentType: string): Promise<void> {\n\t\tconst existing = this.store.get(hash);\n\t\tif (existing) {\n\t\t\tthis.totalBytes -= existing.data.byteLength;\n\t\t\tthis.store.delete(hash);\n\t\t}\n\t\tthis.store.set(hash, { data, contentType });\n\t\tthis.totalBytes += data.byteLength;\n\t\tthis.enforceLimit();\n\t\treturn Promise.resolve();\n\t}\n\n\tprivate enforceLimit(): void {\n\t\twhile (\n\t\t\t(this.maxItems !== undefined && this.store.size > this.maxItems) ||\n\t\t\t(this.maxSizeBytes !== undefined && this.totalBytes > this.maxSizeBytes)\n\t\t) {\n\t\t\tconst firstKey = this.store.keys().next().value;\n\t\t\tif (firstKey === undefined) break;\n\t\t\tconst victim = this.store.get(firstKey);\n\t\t\tif (victim) this.totalBytes -= victim.data.byteLength;\n\t\t\tthis.store.delete(firstKey);\n\t\t}\n\t}\n}\n\n/** インメモリキャッシュ(ドキュメント用)を生成する。 */\nexport function memoryDocumentCache<\n\tT extends BaseContentItem = BaseContentItem,\n>(options?: MemoryDocumentCacheOptions): DocumentCacheAdapter<T> {\n\treturn new MemoryDocumentCache<T>(options);\n}\n\n/** インメモリキャッシュ(画像用)を生成する。 */\nexport function memoryImageCache(\n\toptions?: MemoryImageCacheOptions,\n): ImageCacheAdapter {\n\treturn new MemoryImageCache(options);\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { t as BaseContentItem } from "../content-WydAfQtk.mjs";
2
- import { n as DocumentCacheAdapter, r as ImageCacheAdapter } from "../cache-D051BP4G.mjs";
1
+ import { t as BaseContentItem } from "../content-DyrOwjbA.mjs";
2
+ import { n as DocumentCacheAdapter, r as ImageCacheAdapter } from "../cache-QrXdXYMs.mjs";
3
3
 
4
4
  //#region src/cache/noop.d.ts
5
5
  /** 何もしないドキュメントキャッシュを返す(シングルトン)。 */
@@ -8,10 +8,16 @@ var NoopDocumentCache = class {
8
8
  setList(_data) {
9
9
  return Promise.resolve();
10
10
  }
11
- getItem(_slug) {
11
+ getItemMeta(_slug) {
12
12
  return Promise.resolve(null);
13
13
  }
14
- setItem(_slug, _data) {
14
+ setItemMeta(_slug, _data) {
15
+ return Promise.resolve();
16
+ }
17
+ getItemContent(_slug) {
18
+ return Promise.resolve(null);
19
+ }
20
+ setItemContent(_slug, _data) {
15
21
  return Promise.resolve();
16
22
  }
17
23
  invalidate(_scope) {
@@ -1 +1 @@
1
- {"version":3,"file":"noop.mjs","names":[],"sources":["../../src/cache/noop.ts"],"sourcesContent":["import type {\n\tBaseContentItem,\n\tCachedItem,\n\tCachedItemList,\n\tDocumentCacheAdapter,\n\tImageCacheAdapter,\n\tInvalidateScope,\n\tStorageBinary,\n} from \"../types/index\";\n\n/** 何もキャッシュしないドキュメントキャッシュ実装。常に null を返す。 */\nclass NoopDocumentCache<T extends BaseContentItem = BaseContentItem>\n\timplements DocumentCacheAdapter<T>\n{\n\treadonly name = \"noop-document\";\n\n\tgetList(): Promise<CachedItemList<T> | null> {\n\t\treturn Promise.resolve(null);\n\t}\n\n\tsetList(_data: CachedItemList<T>): Promise<void> {\n\t\treturn Promise.resolve();\n\t}\n\n\tgetItem(_slug: string): Promise<CachedItem<T> | null> {\n\t\treturn Promise.resolve(null);\n\t}\n\n\tsetItem(_slug: string, _data: CachedItem<T>): Promise<void> {\n\t\treturn Promise.resolve();\n\t}\n\n\tinvalidate(_scope: InvalidateScope): Promise<void> {\n\t\treturn Promise.resolve();\n\t}\n}\n\n/** 何もキャッシュしない画像キャッシュ実装。常に null を返す。 */\nclass NoopImageCache implements ImageCacheAdapter {\n\treadonly name = \"noop-image\";\n\n\tget(_hash: string): Promise<StorageBinary | null> {\n\t\treturn Promise.resolve(null);\n\t}\n\n\tset(_hash: string, _data: ArrayBuffer, _contentType: string): Promise<void> {\n\t\treturn Promise.resolve();\n\t}\n}\n\nconst _noopDocument = new NoopDocumentCache();\nconst _noopImage = new NoopImageCache();\n\n/** 何もしないドキュメントキャッシュを返す(シングルトン)。 */\nexport function noopDocumentCache<\n\tT extends BaseContentItem = BaseContentItem,\n>(): DocumentCacheAdapter<T> {\n\treturn _noopDocument as DocumentCacheAdapter<T>;\n}\n\n/** 何もしない画像キャッシュを返す(シングルトン)。 */\nexport function noopImageCache(): ImageCacheAdapter {\n\treturn _noopImage;\n}\n"],"mappings":";;AAWA,IAAM,oBAAN,MAEA;CACC,OAAgB;CAEhB,UAA6C;AAC5C,SAAO,QAAQ,QAAQ,KAAK;;CAG7B,QAAQ,OAAyC;AAChD,SAAO,QAAQ,SAAS;;CAGzB,QAAQ,OAA8C;AACrD,SAAO,QAAQ,QAAQ,KAAK;;CAG7B,QAAQ,OAAe,OAAqC;AAC3D,SAAO,QAAQ,SAAS;;CAGzB,WAAW,QAAwC;AAClD,SAAO,QAAQ,SAAS;;;;AAK1B,IAAM,iBAAN,MAAkD;CACjD,OAAgB;CAEhB,IAAI,OAA8C;AACjD,SAAO,QAAQ,QAAQ,KAAK;;CAG7B,IAAI,OAAe,OAAoB,cAAqC;AAC3E,SAAO,QAAQ,SAAS;;;AAI1B,MAAM,gBAAgB,IAAI,mBAAmB;AAC7C,MAAM,aAAa,IAAI,gBAAgB;;AAGvC,SAAgB,oBAEa;AAC5B,QAAO;;;AAIR,SAAgB,iBAAoC;AACnD,QAAO"}
1
+ {"version":3,"file":"noop.mjs","names":[],"sources":["../../src/cache/noop.ts"],"sourcesContent":["import type {\n\tBaseContentItem,\n\tCachedItemContent,\n\tCachedItemList,\n\tCachedItemMeta,\n\tDocumentCacheAdapter,\n\tImageCacheAdapter,\n\tInvalidateScope,\n\tStorageBinary,\n} from \"../types/index\";\n\n/** 何もキャッシュしないドキュメントキャッシュ実装。常に null を返す。 */\nclass NoopDocumentCache<T extends BaseContentItem = BaseContentItem>\n\timplements DocumentCacheAdapter<T>\n{\n\treadonly name = \"noop-document\";\n\n\tgetList(): Promise<CachedItemList<T> | null> {\n\t\treturn Promise.resolve(null);\n\t}\n\n\tsetList(_data: CachedItemList<T>): Promise<void> {\n\t\treturn Promise.resolve();\n\t}\n\n\tgetItemMeta(_slug: string): Promise<CachedItemMeta<T> | null> {\n\t\treturn Promise.resolve(null);\n\t}\n\n\tsetItemMeta(_slug: string, _data: CachedItemMeta<T>): Promise<void> {\n\t\treturn Promise.resolve();\n\t}\n\n\tgetItemContent(_slug: string): Promise<CachedItemContent | null> {\n\t\treturn Promise.resolve(null);\n\t}\n\n\tsetItemContent(_slug: string, _data: CachedItemContent): Promise<void> {\n\t\treturn Promise.resolve();\n\t}\n\n\tinvalidate(_scope: InvalidateScope): Promise<void> {\n\t\treturn Promise.resolve();\n\t}\n}\n\n/** 何もキャッシュしない画像キャッシュ実装。常に null を返す。 */\nclass NoopImageCache implements ImageCacheAdapter {\n\treadonly name = \"noop-image\";\n\n\tget(_hash: string): Promise<StorageBinary | null> {\n\t\treturn Promise.resolve(null);\n\t}\n\n\tset(_hash: string, _data: ArrayBuffer, _contentType: string): Promise<void> {\n\t\treturn Promise.resolve();\n\t}\n}\n\nconst _noopDocument = new NoopDocumentCache();\nconst _noopImage = new NoopImageCache();\n\n/** 何もしないドキュメントキャッシュを返す(シングルトン)。 */\nexport function noopDocumentCache<\n\tT extends BaseContentItem = BaseContentItem,\n>(): DocumentCacheAdapter<T> {\n\treturn _noopDocument as DocumentCacheAdapter<T>;\n}\n\n/** 何もしない画像キャッシュを返す(シングルトン)。 */\nexport function noopImageCache(): ImageCacheAdapter {\n\treturn _noopImage;\n}\n"],"mappings":";;AAYA,IAAM,oBAAN,MAEA;CACC,OAAgB;CAEhB,UAA6C;AAC5C,SAAO,QAAQ,QAAQ,KAAK;;CAG7B,QAAQ,OAAyC;AAChD,SAAO,QAAQ,SAAS;;CAGzB,YAAY,OAAkD;AAC7D,SAAO,QAAQ,QAAQ,KAAK;;CAG7B,YAAY,OAAe,OAAyC;AACnE,SAAO,QAAQ,SAAS;;CAGzB,eAAe,OAAkD;AAChE,SAAO,QAAQ,QAAQ,KAAK;;CAG7B,eAAe,OAAe,OAAyC;AACtE,SAAO,QAAQ,SAAS;;CAGzB,WAAW,QAAwC;AAClD,SAAO,QAAQ,SAAS;;;;AAK1B,IAAM,iBAAN,MAAkD;CACjD,OAAgB;CAEhB,IAAI,OAA8C;AACjD,SAAO,QAAQ,QAAQ,KAAK;;CAG7B,IAAI,OAAe,OAAoB,cAAqC;AAC3E,SAAO,QAAQ,SAAS;;;AAI1B,MAAM,gBAAgB,IAAI,mBAAmB;AAC7C,MAAM,aAAa,IAAI,gBAAgB;;AAGvC,SAAgB,oBAEa;AAC5B,QAAO;;;AAIR,SAAgB,iBAAoC;AACnD,QAAO"}
@@ -1,4 +1,4 @@
1
- import { a as StorageBinary, c as ImageRef, i as CachedItemList, o as ContentBlock, r as CachedItem, t as BaseContentItem } from "./content-WydAfQtk.mjs";
1
+ import { a as CachedItemMeta, c as ContentBlock, i as CachedItemList, r as CachedItemContent, s as StorageBinary, t as BaseContentItem, u as ImageRef } from "./content-DyrOwjbA.mjs";
2
2
 
3
3
  //#region src/types/data-source.d.ts
4
4
  /**
@@ -12,14 +12,24 @@ interface PropertyDef {
12
12
  }
13
13
  /** Notion DB のプロパティ一覧マップ。CLI 生成の `*Properties` の型。 */
14
14
  type PropertyMap = Record<string, PropertyDef>;
15
+ /**
16
+ * 無効化対象の粒度。
17
+ * - "meta" — メタデータキャッシュのみ失効
18
+ * - "content" — 本文キャッシュのみ失効(リスト次回読み出しで lazy 再生成)
19
+ * - "all" — 両方(既定)
20
+ */
21
+ type InvalidateKind = "meta" | "content" | "all";
15
22
  /**
16
23
  * キャッシュ無効化のスコープ (DataSource 層で参照する形)。
24
+ * `kind` を省略した場合は `"all"` 相当として扱う。
17
25
  */
18
26
  type InvalidateScope = "all" | {
19
27
  collection: string;
28
+ kind?: InvalidateKind;
20
29
  } | {
21
30
  collection: string;
22
31
  slug: string;
32
+ kind?: InvalidateKind;
23
33
  };
24
34
  /**
25
35
  * Webhook 受信時の検証設定。
@@ -119,13 +129,25 @@ type DataSourceFactory<TOptions = unknown> = <T extends BaseContentItem>(args: {
119
129
  }) => DataSource<T>;
120
130
  //#endregion
121
131
  //#region src/types/cache.d.ts
122
- /** ドキュメントキャッシュを抽象化するインターフェース。 */
132
+ /**
133
+ * ドキュメントキャッシュを抽象化するインターフェース。
134
+ *
135
+ * v0.4.0 で `getItem`/`setItem` を `getItemMeta`/`setItemMeta` +
136
+ * `getItemContent`/`setItemContent` に分割した。
137
+ * メタデータのみ取り出す軽量パスと、本文を遅延ロードするパスを分離するため。
138
+ */
123
139
  interface DocumentCacheAdapter<T extends BaseContentItem = BaseContentItem> {
124
140
  readonly name: string;
125
141
  getList(): Promise<CachedItemList<T> | null>;
126
142
  setList(data: CachedItemList<T>): Promise<void>;
127
- getItem(slug: string): Promise<CachedItem<T> | null>;
128
- setItem(slug: string, data: CachedItem<T>): Promise<void>;
143
+ getItemMeta(slug: string): Promise<CachedItemMeta<T> | null>;
144
+ setItemMeta(slug: string, data: CachedItemMeta<T>): Promise<void>;
145
+ getItemContent(slug: string): Promise<CachedItemContent | null>;
146
+ setItemContent(slug: string, data: CachedItemContent): Promise<void>;
147
+ /**
148
+ * 無効化。`scope.kind` で meta/content の粒度を指定できる。
149
+ * 省略時は両方失効させる。
150
+ */
129
151
  invalidate?(scope: InvalidateScope): Promise<void>;
130
152
  }
131
153
  /** 画像キャッシュを抽象化するインターフェース。 */
@@ -144,5 +166,5 @@ type CacheConfig<T extends BaseContentItem = BaseContentItem> = "disabled" | {
144
166
  ttlMs?: number;
145
167
  };
146
168
  //#endregion
147
- export { CollectionConfig as a, InferCollectionItem as c, PropertyMap as d, WebhookConfig as f, CMSSchema as i, InvalidateScope as l, DocumentCacheAdapter as n, DataSource as o, ImageCacheAdapter as r, DataSourceFactory as s, CacheConfig as t, PropertyDef as u };
148
- //# sourceMappingURL=cache-D051BP4G.d.mts.map
169
+ export { CollectionConfig as a, InferCollectionItem as c, PropertyDef as d, PropertyMap as f, CMSSchema as i, InvalidateKind as l, DocumentCacheAdapter as n, DataSource as o, WebhookConfig as p, ImageCacheAdapter as r, DataSourceFactory as s, CacheConfig as t, InvalidateScope as u };
170
+ //# sourceMappingURL=cache-QrXdXYMs.d.mts.map
@@ -53,15 +53,16 @@ type InlineNode = {
53
53
  type: "break";
54
54
  };
55
55
  /**
56
- * `getItem({ include: { content: true } })` で返される本文。
57
- * blocks は常に同梱。html / markdown は遅延生成。
56
+ * `getItem()` で返される本文アクセサ。すべて遅延ロード(async)。
57
+ * メタデータと別キーから本文をフェッチするため、最初の呼び出しで I/O が発生し、
58
+ * 同一インスタンス内ではメモ化される。
58
59
  */
59
60
  interface ContentResult {
60
- /** 本文の AST (第一級)。 */
61
- blocks: ContentBlock[];
62
- /** 遅延 HTML。renderer が必要な場合のみ呼ぶ。 */
61
+ /** 本文 AST。 */
62
+ blocks(): Promise<ContentBlock[]>;
63
+ /** HTML。 */
63
64
  html(): Promise<string>;
64
- /** 遅延 Markdown。 */
65
+ /** Markdown。 */
65
66
  markdown(): Promise<string>;
66
67
  }
67
68
  /** 画像参照 (DataSource.resolveImageUrl に渡す)。 */
@@ -98,14 +99,38 @@ interface BaseContentItem {
98
99
  /** 公開日時。日付プロパティのない DB では省略可能。 */
99
100
  publishedAt?: string;
100
101
  }
101
- /** ストレージにキャッシュされたレンダリング済みコンテンツ。 */
102
- interface CachedItem<T extends BaseContentItem = BaseContentItem> {
103
- html: string;
102
+ /**
103
+ * メタデータのみの軽量キャッシュエントリ。
104
+ * `checkForUpdate` の差分判定や一覧表示など、本文を必要としないパスで使う。
105
+ */
106
+ interface CachedItemMeta<T extends BaseContentItem = BaseContentItem> {
104
107
  item: T;
108
+ /** Notion 側の最終更新時刻(差分検知用)。 */
105
109
  notionUpdatedAt: string;
110
+ /** キャッシュ書き込み時刻(TTL 判定用、ms)。 */
106
111
  cachedAt: number;
107
- blocks?: ContentBlock[];
108
- markdown?: string;
112
+ }
113
+ /**
114
+ * 本文(HTML / Markdown / blocks)のキャッシュエントリ。
115
+ * メタデータと別ストレージキーで保存し、必要時のみロードする。
116
+ */
117
+ interface CachedItemContent {
118
+ html: string;
119
+ markdown: string;
120
+ blocks: ContentBlock[];
121
+ /** メタデータ整合性検証用に同じ値を保持する。 */
122
+ notionUpdatedAt: string;
123
+ cachedAt: number;
124
+ }
125
+ /**
126
+ * 本文クライアント送信用 DTO(cachedAt を除いた `CachedItemContent`)。
127
+ * `useSWR` の cache に格納できるよう関数を含まない pure JSON。
128
+ */
129
+ interface ItemContentPayload {
130
+ html: string;
131
+ markdown: string;
132
+ blocks: ContentBlock[];
133
+ notionUpdatedAt: string;
109
134
  }
110
135
  /** ストレージにキャッシュされたコンテンツ一覧。 */
111
136
  interface CachedItemList<T extends BaseContentItem = BaseContentItem> {
@@ -127,5 +152,5 @@ interface CMSSchemaProperties {
127
152
  date?: string;
128
153
  }
129
154
  //#endregion
130
- export { StorageBinary as a, ImageRef as c, CachedItemList as i, InlineNode as l, CMSSchemaProperties as n, ContentBlock as o, CachedItem as r, ContentResult as s, BaseContentItem as t };
131
- //# sourceMappingURL=content-WydAfQtk.d.mts.map
155
+ export { CachedItemMeta as a, ContentBlock as c, InlineNode as d, CachedItemList as i, ContentResult as l, CMSSchemaProperties as n, ItemContentPayload as o, CachedItemContent as r, StorageBinary as s, BaseContentItem as t, ImageRef as u };
156
+ //# sourceMappingURL=content-DyrOwjbA.d.mts.map
@@ -1,14 +1,22 @@
1
- import { i as CachedItemList, r as CachedItem, t as BaseContentItem } from "./content-WydAfQtk.mjs";
1
+ import { a as CachedItemMeta, i as CachedItemList, r as CachedItemContent, t as BaseContentItem } from "./content-DyrOwjbA.mjs";
2
2
 
3
3
  //#region src/types/hooks.d.ts
4
4
  type MaybePromise<T> = T | Promise<T>;
5
5
  interface CMSHooks<T extends BaseContentItem = BaseContentItem> {
6
- beforeCache?: (item: CachedItem<T>) => MaybePromise<CachedItem<T>>;
6
+ /**
7
+ * 本文キャッシュ書き込み直前に呼ばれる。html を加工したい場合などに使う。
8
+ * 戻り値が新しい `CachedItemContent` として保存される。
9
+ */
10
+ beforeCacheContent?: (content: CachedItemContent, item: T) => MaybePromise<CachedItemContent>;
11
+ /** メタデータキャッシュ書き込み直前に呼ばれる。 */
12
+ beforeCacheMeta?: (meta: CachedItemMeta<T>) => MaybePromise<CachedItemMeta<T>>;
7
13
  afterRender?: (html: string, item: T) => MaybePromise<string>;
8
- onCacheHit?: (slug: string, item: CachedItem<T>) => void;
14
+ onCacheHit?: (slug: string, meta: CachedItemMeta<T>) => void;
9
15
  onCacheMiss?: (slug: string) => void;
10
- /** SWR バックグラウンド差分チェックで更新を検出し、キャッシュを差し替えたときに呼ばれる。 */
11
- onCacheRevalidated?: (slug: string, item: CachedItem<T>) => void;
16
+ /** SWR バックグラウンド差分チェックで更新を検出し、メタを差し替えたときに呼ばれる。 */
17
+ onCacheRevalidated?: (slug: string, meta: CachedItemMeta<T>) => void;
18
+ /** 本文キャッシュが(lazy ロード or バックグラウンド再生成で)更新されたときに呼ばれる。 */
19
+ onContentRevalidated?: (slug: string, content: CachedItemContent) => void;
12
20
  onListCacheHit?: (list: CachedItemList<T>) => void;
13
21
  onListCacheMiss?: () => void;
14
22
  /** SWR バックグラウンド差分チェックでリスト更新を検出し、キャッシュを差し替えたときに呼ばれる。 */
@@ -57,8 +65,8 @@ declare function definePlugin<T extends BaseContentItem>(plugin: CMSPlugin<T>):
57
65
  //#region src/hooks.d.ts
58
66
  /**
59
67
  * プラグイン配列とダイレクトフックを合成して単一の CMSHooks を返す。
60
- * beforeCache / afterRender はパイプライン(前の出力が次の入力)。
61
- * onCacheHit などオブザーバー系は全員に同じ値を渡し、例外は logger に流して握りつぶす。
68
+ * beforeCacheMeta / beforeCacheContent / afterRender はパイプライン(前の出力が次の入力)。
69
+ * オブザーバー系は全員に同じ値を渡し、例外は logger に流して握りつぶす。
62
70
  */
63
71
  declare function mergeHooks<T extends BaseContentItem>(plugins: CMSPlugin<T>[], directHooks?: CMSHooks<T>, logger?: Logger): CMSHooks<T>;
64
72
  /** プラグイン配列とダイレクトロガーを合成して単一の Logger を返す。 */
@@ -67,4 +75,4 @@ declare function mergeLoggers(plugins: Array<{
67
75
  }>, directLogger?: Logger): Logger | undefined;
68
76
  //#endregion
69
77
  export { Logger as a, definePlugin as i, mergeLoggers as n, CMSHooks as o, CMSPlugin as r, MaybePromise as s, mergeHooks as t };
70
- //# sourceMappingURL=hooks-D8Lgf-Co.d.mts.map
78
+ //# sourceMappingURL=hooks-CPRRo9IN.d.mts.map
package/dist/hooks.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { n as mergeLoggers, t as mergeHooks } from "./hooks-D8Lgf-Co.mjs";
1
+ import { n as mergeLoggers, t as mergeHooks } from "./hooks-CPRRo9IN.mjs";
2
2
  export { mergeHooks, mergeLoggers };
package/dist/hooks.mjs CHANGED
@@ -1,18 +1,20 @@
1
1
  //#region src/hooks.ts
2
2
  /**
3
3
  * プラグイン配列とダイレクトフックを合成して単一の CMSHooks を返す。
4
- * beforeCache / afterRender はパイプライン(前の出力が次の入力)。
5
- * onCacheHit などオブザーバー系は全員に同じ値を渡し、例外は logger に流して握りつぶす。
4
+ * beforeCacheMeta / beforeCacheContent / afterRender はパイプライン(前の出力が次の入力)。
5
+ * オブザーバー系は全員に同じ値を渡し、例外は logger に流して握りつぶす。
6
6
  */
7
7
  function mergeHooks(plugins, directHooks, logger) {
8
8
  const allHooks = [...plugins.map((p) => p.hooks ?? {}), ...directHooks ? [directHooks] : []];
9
9
  if (allHooks.length === 0) return {};
10
10
  return {
11
- beforeCache: buildPipeline(allHooks, "beforeCache"),
11
+ beforeCacheMeta: buildMetaPipeline(allHooks),
12
+ beforeCacheContent: buildContentPipeline(allHooks),
12
13
  afterRender: buildRenderPipeline(allHooks),
13
14
  onCacheHit: buildObserver(allHooks, "onCacheHit", logger),
14
15
  onCacheMiss: buildObserver(allHooks, "onCacheMiss", logger),
15
16
  onCacheRevalidated: buildObserver(allHooks, "onCacheRevalidated", logger),
17
+ onContentRevalidated: buildObserver(allHooks, "onContentRevalidated", logger),
16
18
  onListCacheHit: buildObserver(allHooks, "onListCacheHit", logger),
17
19
  onListCacheMiss: buildObserver(allHooks, "onListCacheMiss", logger),
18
20
  onListCacheRevalidated: buildObserver(allHooks, "onListCacheRevalidated", logger),
@@ -21,15 +23,24 @@ function mergeHooks(plugins, directHooks, logger) {
21
23
  onRenderEnd: buildObserver(allHooks, "onRenderEnd", logger)
22
24
  };
23
25
  }
24
- function buildPipeline(hooks, key) {
25
- const fns = hooks.map((h) => h[key]).filter(Boolean);
26
+ function buildMetaPipeline(hooks) {
27
+ const fns = hooks.map((h) => h.beforeCacheMeta).filter(Boolean);
26
28
  if (fns.length === 0) return void 0;
27
- return async (item) => {
28
- let current = item;
29
+ return async (meta) => {
30
+ let current = meta;
29
31
  for (const fn of fns) current = await fn(current);
30
32
  return current;
31
33
  };
32
34
  }
35
+ function buildContentPipeline(hooks) {
36
+ const fns = hooks.map((h) => h.beforeCacheContent).filter(Boolean);
37
+ if (fns.length === 0) return void 0;
38
+ return async (content, item) => {
39
+ let current = content;
40
+ for (const fn of fns) current = await fn(current, item);
41
+ return current;
42
+ };
43
+ }
33
44
  function buildRenderPipeline(hooks) {
34
45
  const fns = hooks.map((h) => h.afterRender).filter(Boolean);
35
46
  if (fns.length === 0) return void 0;
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.mjs","names":[],"sources":["../src/hooks.ts"],"sourcesContent":["import type { BaseContentItem } from \"./types/content\";\nimport type { CMSHooks, MaybePromise } from \"./types/hooks\";\nimport type { Logger } from \"./types/logger\";\nimport type { CMSPlugin } from \"./types/plugin\";\n\n/**\n * プラグイン配列とダイレクトフックを合成して単一の CMSHooks を返す。\n * beforeCache / afterRender はパイプライン(前の出力が次の入力)。\n * onCacheHit などオブザーバー系は全員に同じ値を渡し、例外は logger に流して握りつぶす。\n */\nexport function mergeHooks<T extends BaseContentItem>(\n\tplugins: CMSPlugin<T>[],\n\tdirectHooks?: CMSHooks<T>,\n\tlogger?: Logger,\n): CMSHooks<T> {\n\tconst allHooks: CMSHooks<T>[] = [\n\t\t...plugins.map((p) => p.hooks ?? {}),\n\t\t...(directHooks ? [directHooks] : []),\n\t];\n\n\tif (allHooks.length === 0) return {};\n\n\treturn {\n\t\tbeforeCache: buildPipeline(allHooks, \"beforeCache\"),\n\t\tafterRender: buildRenderPipeline(allHooks),\n\t\tonCacheHit: buildObserver(allHooks, \"onCacheHit\", logger),\n\t\tonCacheMiss: buildObserver(allHooks, \"onCacheMiss\", logger),\n\t\tonCacheRevalidated: buildObserver(allHooks, \"onCacheRevalidated\", logger),\n\t\tonListCacheHit: buildObserver(allHooks, \"onListCacheHit\", logger),\n\t\tonListCacheMiss: buildObserver(allHooks, \"onListCacheMiss\", logger),\n\t\tonListCacheRevalidated: buildObserver(\n\t\t\tallHooks,\n\t\t\t\"onListCacheRevalidated\",\n\t\t\tlogger,\n\t\t),\n\t\tonError: buildObserver(allHooks, \"onError\", logger),\n\t\tonRenderStart: buildObserver(allHooks, \"onRenderStart\", logger),\n\t\tonRenderEnd: buildObserver(allHooks, \"onRenderEnd\", logger),\n\t};\n}\n\nfunction buildPipeline<T extends BaseContentItem>(\n\thooks: CMSHooks<T>[],\n\tkey: \"beforeCache\",\n): CMSHooks<T>[\"beforeCache\"] {\n\tconst fns = hooks.map((h) => h[key]).filter(Boolean) as NonNullable<\n\t\tCMSHooks<T>[\"beforeCache\"]\n\t>[];\n\tif (fns.length === 0) return undefined;\n\treturn async (item) => {\n\t\tlet current = item;\n\t\tfor (const fn of fns) {\n\t\t\tcurrent = await (fn(current) as MaybePromise<typeof item>);\n\t\t}\n\t\treturn current;\n\t};\n}\n\nfunction buildRenderPipeline<T extends BaseContentItem>(\n\thooks: CMSHooks<T>[],\n): CMSHooks<T>[\"afterRender\"] {\n\tconst fns = hooks.map((h) => h.afterRender).filter(Boolean) as NonNullable<\n\t\tCMSHooks<T>[\"afterRender\"]\n\t>[];\n\tif (fns.length === 0) return undefined;\n\treturn async (html, item) => {\n\t\tlet current = html;\n\t\tfor (const fn of fns) {\n\t\t\tcurrent = await (fn(current, item) as MaybePromise<string>);\n\t\t}\n\t\treturn current;\n\t};\n}\n\nfunction buildObserver<T extends BaseContentItem, K extends keyof CMSHooks<T>>(\n\thooks: CMSHooks<T>[],\n\tkey: K,\n\tlogger?: Logger,\n): CMSHooks<T>[K] {\n\tconst fns = hooks.map((h) => h[key]).filter(Boolean);\n\tif (fns.length === 0) return undefined;\n\treturn ((...args: unknown[]) => {\n\t\tfor (const fn of fns) {\n\t\t\ttry {\n\t\t\t\t(fn as (...a: unknown[]) => void)(...args);\n\t\t\t} catch (err) {\n\t\t\t\tlogger?.error?.(\"観測フックで例外が発生\", {\n\t\t\t\t\thook: String(key),\n\t\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}) as CMSHooks<T>[K];\n}\n\n/** プラグイン配列とダイレクトロガーを合成して単一の Logger を返す。 */\nexport function mergeLoggers(\n\tplugins: Array<{ logger?: Partial<Logger> }>,\n\tdirectLogger?: Logger,\n): Logger | undefined {\n\tconst loggers: Partial<Logger>[] = [\n\t\t...plugins.map((p) => p.logger ?? {}),\n\t\t...(directLogger ? [directLogger] : []),\n\t];\n\tif (loggers.length === 0) return undefined;\n\n\tconst merged: Logger = {};\n\tfor (const level of [\"debug\", \"info\", \"warn\", \"error\"] as const) {\n\t\tconst fns = loggers.map((l) => l[level]).filter(Boolean) as NonNullable<\n\t\t\tLogger[typeof level]\n\t\t>[];\n\t\tif (fns.length > 0) {\n\t\t\tmerged[level] = (message, context) => {\n\t\t\t\tfor (const fn of fns) fn(message, context);\n\t\t\t};\n\t\t}\n\t}\n\treturn merged;\n}\n"],"mappings":";;;;;;AAUA,SAAgB,WACf,SACA,aACA,QACc;CACd,MAAM,WAA0B,CAC/B,GAAG,QAAQ,KAAK,MAAM,EAAE,SAAS,EAAE,CAAC,EACpC,GAAI,cAAc,CAAC,YAAY,GAAG,EAAE,CACpC;AAED,KAAI,SAAS,WAAW,EAAG,QAAO,EAAE;AAEpC,QAAO;EACN,aAAa,cAAc,UAAU,cAAc;EACnD,aAAa,oBAAoB,SAAS;EAC1C,YAAY,cAAc,UAAU,cAAc,OAAO;EACzD,aAAa,cAAc,UAAU,eAAe,OAAO;EAC3D,oBAAoB,cAAc,UAAU,sBAAsB,OAAO;EACzE,gBAAgB,cAAc,UAAU,kBAAkB,OAAO;EACjE,iBAAiB,cAAc,UAAU,mBAAmB,OAAO;EACnE,wBAAwB,cACvB,UACA,0BACA,OACA;EACD,SAAS,cAAc,UAAU,WAAW,OAAO;EACnD,eAAe,cAAc,UAAU,iBAAiB,OAAO;EAC/D,aAAa,cAAc,UAAU,eAAe,OAAO;EAC3D;;AAGF,SAAS,cACR,OACA,KAC6B;CAC7B,MAAM,MAAM,MAAM,KAAK,MAAM,EAAE,KAAK,CAAC,OAAO,QAAQ;AAGpD,KAAI,IAAI,WAAW,EAAG,QAAO,KAAA;AAC7B,QAAO,OAAO,SAAS;EACtB,IAAI,UAAU;AACd,OAAK,MAAM,MAAM,IAChB,WAAU,MAAO,GAAG,QAAQ;AAE7B,SAAO;;;AAIT,SAAS,oBACR,OAC6B;CAC7B,MAAM,MAAM,MAAM,KAAK,MAAM,EAAE,YAAY,CAAC,OAAO,QAAQ;AAG3D,KAAI,IAAI,WAAW,EAAG,QAAO,KAAA;AAC7B,QAAO,OAAO,MAAM,SAAS;EAC5B,IAAI,UAAU;AACd,OAAK,MAAM,MAAM,IAChB,WAAU,MAAO,GAAG,SAAS,KAAK;AAEnC,SAAO;;;AAIT,SAAS,cACR,OACA,KACA,QACiB;CACjB,MAAM,MAAM,MAAM,KAAK,MAAM,EAAE,KAAK,CAAC,OAAO,QAAQ;AACpD,KAAI,IAAI,WAAW,EAAG,QAAO,KAAA;AAC7B,UAAS,GAAG,SAAoB;AAC/B,OAAK,MAAM,MAAM,IAChB,KAAI;AACF,MAAiC,GAAG,KAAK;WAClC,KAAK;AACb,WAAQ,QAAQ,eAAe;IAC9B,MAAM,OAAO,IAAI;IACjB,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;IACvD,CAAC;;;;;AAON,SAAgB,aACf,SACA,cACqB;CACrB,MAAM,UAA6B,CAClC,GAAG,QAAQ,KAAK,MAAM,EAAE,UAAU,EAAE,CAAC,EACrC,GAAI,eAAe,CAAC,aAAa,GAAG,EAAE,CACtC;AACD,KAAI,QAAQ,WAAW,EAAG,QAAO,KAAA;CAEjC,MAAM,SAAiB,EAAE;AACzB,MAAK,MAAM,SAAS;EAAC;EAAS;EAAQ;EAAQ;EAAQ,EAAW;EAChE,MAAM,MAAM,QAAQ,KAAK,MAAM,EAAE,OAAO,CAAC,OAAO,QAAQ;AAGxD,MAAI,IAAI,SAAS,EAChB,QAAO,UAAU,SAAS,YAAY;AACrC,QAAK,MAAM,MAAM,IAAK,IAAG,SAAS,QAAQ;;;AAI7C,QAAO"}
1
+ {"version":3,"file":"hooks.mjs","names":[],"sources":["../src/hooks.ts"],"sourcesContent":["import type { BaseContentItem } from \"./types/content\";\nimport type { CMSHooks, MaybePromise } from \"./types/hooks\";\nimport type { Logger } from \"./types/logger\";\nimport type { CMSPlugin } from \"./types/plugin\";\n\n/**\n * プラグイン配列とダイレクトフックを合成して単一の CMSHooks を返す。\n * beforeCacheMeta / beforeCacheContent / afterRender はパイプライン(前の出力が次の入力)。\n * オブザーバー系は全員に同じ値を渡し、例外は logger に流して握りつぶす。\n */\nexport function mergeHooks<T extends BaseContentItem>(\n\tplugins: CMSPlugin<T>[],\n\tdirectHooks?: CMSHooks<T>,\n\tlogger?: Logger,\n): CMSHooks<T> {\n\tconst allHooks: CMSHooks<T>[] = [\n\t\t...plugins.map((p) => p.hooks ?? {}),\n\t\t...(directHooks ? [directHooks] : []),\n\t];\n\n\tif (allHooks.length === 0) return {};\n\n\treturn {\n\t\tbeforeCacheMeta: buildMetaPipeline(allHooks),\n\t\tbeforeCacheContent: buildContentPipeline(allHooks),\n\t\tafterRender: buildRenderPipeline(allHooks),\n\t\tonCacheHit: buildObserver(allHooks, \"onCacheHit\", logger),\n\t\tonCacheMiss: buildObserver(allHooks, \"onCacheMiss\", logger),\n\t\tonCacheRevalidated: buildObserver(allHooks, \"onCacheRevalidated\", logger),\n\t\tonContentRevalidated: buildObserver(\n\t\t\tallHooks,\n\t\t\t\"onContentRevalidated\",\n\t\t\tlogger,\n\t\t),\n\t\tonListCacheHit: buildObserver(allHooks, \"onListCacheHit\", logger),\n\t\tonListCacheMiss: buildObserver(allHooks, \"onListCacheMiss\", logger),\n\t\tonListCacheRevalidated: buildObserver(\n\t\t\tallHooks,\n\t\t\t\"onListCacheRevalidated\",\n\t\t\tlogger,\n\t\t),\n\t\tonError: buildObserver(allHooks, \"onError\", logger),\n\t\tonRenderStart: buildObserver(allHooks, \"onRenderStart\", logger),\n\t\tonRenderEnd: buildObserver(allHooks, \"onRenderEnd\", logger),\n\t};\n}\n\nfunction buildMetaPipeline<T extends BaseContentItem>(\n\thooks: CMSHooks<T>[],\n): CMSHooks<T>[\"beforeCacheMeta\"] {\n\tconst fns = hooks\n\t\t.map((h) => h.beforeCacheMeta)\n\t\t.filter(Boolean) as NonNullable<CMSHooks<T>[\"beforeCacheMeta\"]>[];\n\tif (fns.length === 0) return undefined;\n\treturn async (meta) => {\n\t\tlet current = meta;\n\t\tfor (const fn of fns) {\n\t\t\tcurrent = await (fn(current) as MaybePromise<typeof meta>);\n\t\t}\n\t\treturn current;\n\t};\n}\n\nfunction buildContentPipeline<T extends BaseContentItem>(\n\thooks: CMSHooks<T>[],\n): CMSHooks<T>[\"beforeCacheContent\"] {\n\tconst fns = hooks\n\t\t.map((h) => h.beforeCacheContent)\n\t\t.filter(Boolean) as NonNullable<CMSHooks<T>[\"beforeCacheContent\"]>[];\n\tif (fns.length === 0) return undefined;\n\treturn async (content, item) => {\n\t\tlet current = content;\n\t\tfor (const fn of fns) {\n\t\t\tcurrent = await (fn(current, item) as MaybePromise<typeof content>);\n\t\t}\n\t\treturn current;\n\t};\n}\n\nfunction buildRenderPipeline<T extends BaseContentItem>(\n\thooks: CMSHooks<T>[],\n): CMSHooks<T>[\"afterRender\"] {\n\tconst fns = hooks.map((h) => h.afterRender).filter(Boolean) as NonNullable<\n\t\tCMSHooks<T>[\"afterRender\"]\n\t>[];\n\tif (fns.length === 0) return undefined;\n\treturn async (html, item) => {\n\t\tlet current = html;\n\t\tfor (const fn of fns) {\n\t\t\tcurrent = await (fn(current, item) as MaybePromise<string>);\n\t\t}\n\t\treturn current;\n\t};\n}\n\nfunction buildObserver<T extends BaseContentItem, K extends keyof CMSHooks<T>>(\n\thooks: CMSHooks<T>[],\n\tkey: K,\n\tlogger?: Logger,\n): CMSHooks<T>[K] {\n\tconst fns = hooks.map((h) => h[key]).filter(Boolean);\n\tif (fns.length === 0) return undefined;\n\treturn ((...args: unknown[]) => {\n\t\tfor (const fn of fns) {\n\t\t\ttry {\n\t\t\t\t(fn as (...a: unknown[]) => void)(...args);\n\t\t\t} catch (err) {\n\t\t\t\tlogger?.error?.(\"観測フックで例外が発生\", {\n\t\t\t\t\thook: String(key),\n\t\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}) as CMSHooks<T>[K];\n}\n\n/** プラグイン配列とダイレクトロガーを合成して単一の Logger を返す。 */\nexport function mergeLoggers(\n\tplugins: Array<{ logger?: Partial<Logger> }>,\n\tdirectLogger?: Logger,\n): Logger | undefined {\n\tconst loggers: Partial<Logger>[] = [\n\t\t...plugins.map((p) => p.logger ?? {}),\n\t\t...(directLogger ? [directLogger] : []),\n\t];\n\tif (loggers.length === 0) return undefined;\n\n\tconst merged: Logger = {};\n\tfor (const level of [\"debug\", \"info\", \"warn\", \"error\"] as const) {\n\t\tconst fns = loggers.map((l) => l[level]).filter(Boolean) as NonNullable<\n\t\t\tLogger[typeof level]\n\t\t>[];\n\t\tif (fns.length > 0) {\n\t\t\tmerged[level] = (message, context) => {\n\t\t\t\tfor (const fn of fns) fn(message, context);\n\t\t\t};\n\t\t}\n\t}\n\treturn merged;\n}\n"],"mappings":";;;;;;AAUA,SAAgB,WACf,SACA,aACA,QACc;CACd,MAAM,WAA0B,CAC/B,GAAG,QAAQ,KAAK,MAAM,EAAE,SAAS,EAAE,CAAC,EACpC,GAAI,cAAc,CAAC,YAAY,GAAG,EAAE,CACpC;AAED,KAAI,SAAS,WAAW,EAAG,QAAO,EAAE;AAEpC,QAAO;EACN,iBAAiB,kBAAkB,SAAS;EAC5C,oBAAoB,qBAAqB,SAAS;EAClD,aAAa,oBAAoB,SAAS;EAC1C,YAAY,cAAc,UAAU,cAAc,OAAO;EACzD,aAAa,cAAc,UAAU,eAAe,OAAO;EAC3D,oBAAoB,cAAc,UAAU,sBAAsB,OAAO;EACzE,sBAAsB,cACrB,UACA,wBACA,OACA;EACD,gBAAgB,cAAc,UAAU,kBAAkB,OAAO;EACjE,iBAAiB,cAAc,UAAU,mBAAmB,OAAO;EACnE,wBAAwB,cACvB,UACA,0BACA,OACA;EACD,SAAS,cAAc,UAAU,WAAW,OAAO;EACnD,eAAe,cAAc,UAAU,iBAAiB,OAAO;EAC/D,aAAa,cAAc,UAAU,eAAe,OAAO;EAC3D;;AAGF,SAAS,kBACR,OACiC;CACjC,MAAM,MAAM,MACV,KAAK,MAAM,EAAE,gBAAgB,CAC7B,OAAO,QAAQ;AACjB,KAAI,IAAI,WAAW,EAAG,QAAO,KAAA;AAC7B,QAAO,OAAO,SAAS;EACtB,IAAI,UAAU;AACd,OAAK,MAAM,MAAM,IAChB,WAAU,MAAO,GAAG,QAAQ;AAE7B,SAAO;;;AAIT,SAAS,qBACR,OACoC;CACpC,MAAM,MAAM,MACV,KAAK,MAAM,EAAE,mBAAmB,CAChC,OAAO,QAAQ;AACjB,KAAI,IAAI,WAAW,EAAG,QAAO,KAAA;AAC7B,QAAO,OAAO,SAAS,SAAS;EAC/B,IAAI,UAAU;AACd,OAAK,MAAM,MAAM,IAChB,WAAU,MAAO,GAAG,SAAS,KAAK;AAEnC,SAAO;;;AAIT,SAAS,oBACR,OAC6B;CAC7B,MAAM,MAAM,MAAM,KAAK,MAAM,EAAE,YAAY,CAAC,OAAO,QAAQ;AAG3D,KAAI,IAAI,WAAW,EAAG,QAAO,KAAA;AAC7B,QAAO,OAAO,MAAM,SAAS;EAC5B,IAAI,UAAU;AACd,OAAK,MAAM,MAAM,IAChB,WAAU,MAAO,GAAG,SAAS,KAAK;AAEnC,SAAO;;;AAIT,SAAS,cACR,OACA,KACA,QACiB;CACjB,MAAM,MAAM,MAAM,KAAK,MAAM,EAAE,KAAK,CAAC,OAAO,QAAQ;AACpD,KAAI,IAAI,WAAW,EAAG,QAAO,KAAA;AAC7B,UAAS,GAAG,SAAoB;AAC/B,OAAK,MAAM,MAAM,IAChB,KAAI;AACF,MAAiC,GAAG,KAAK;WAClC,KAAK;AACb,WAAQ,QAAQ,eAAe;IAC9B,MAAM,OAAO,IAAI;IACjB,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;IACvD,CAAC;;;;;AAON,SAAgB,aACf,SACA,cACqB;CACrB,MAAM,UAA6B,CAClC,GAAG,QAAQ,KAAK,MAAM,EAAE,UAAU,EAAE,CAAC,EACrC,GAAI,eAAe,CAAC,aAAa,GAAG,EAAE,CACtC;AACD,KAAI,QAAQ,WAAW,EAAG,QAAO,KAAA;CAEjC,MAAM,SAAiB,EAAE;AACzB,MAAK,MAAM,SAAS;EAAC;EAAS;EAAQ;EAAQ;EAAQ,EAAW;EAChE,MAAM,MAAM,QAAQ,KAAK,MAAM,EAAE,OAAO,CAAC,OAAO,QAAQ;AAGxD,MAAI,IAAI,SAAS,EAChB,QAAO,UAAU,SAAS,YAAY;AACrC,QAAK,MAAM,MAAM,IAAK,IAAG,SAAS,QAAQ;;;AAI7C,QAAO"}