@notion-headless-cms/core 0.3.0 → 0.3.2

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-BlD8UPas.mjs";
2
- import { l as InvalidateScope, n as DocumentCacheAdapter, r as ImageCacheAdapter } from "../cache-CcabrGjI.mjs";
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";
3
3
 
4
4
  //#region src/cache/memory.d.ts
5
5
  interface MemoryDocumentCacheOptions {
@@ -42,11 +42,6 @@ declare class MemoryImageCache implements ImageCacheAdapter {
42
42
  declare function memoryDocumentCache<T extends BaseContentItem = BaseContentItem>(options?: MemoryDocumentCacheOptions): DocumentCacheAdapter<T>;
43
43
  /** インメモリキャッシュ(画像用)を生成する。 */
44
44
  declare function memoryImageCache(options?: MemoryImageCacheOptions): ImageCacheAdapter;
45
- /**
46
- * ドキュメントと画像の両方にインメモリキャッシュを返す便利関数。
47
- * memoryCache() はドキュメントキャッシュを返す(後方互換)。
48
- */
49
- declare function memoryCache<T extends BaseContentItem = BaseContentItem>(options?: MemoryDocumentCacheOptions): DocumentCacheAdapter<T>;
50
45
  //#endregion
51
- export { MemoryDocumentCache, MemoryDocumentCacheOptions, MemoryImageCache, MemoryImageCacheOptions, memoryCache, memoryDocumentCache, memoryImageCache };
46
+ export { MemoryDocumentCache, MemoryDocumentCacheOptions, MemoryImageCache, MemoryImageCacheOptions, memoryDocumentCache, memoryImageCache };
52
47
  //# sourceMappingURL=memory.d.mts.map
@@ -102,14 +102,7 @@ function memoryDocumentCache(options) {
102
102
  function memoryImageCache(options) {
103
103
  return new MemoryImageCache(options);
104
104
  }
105
- /**
106
- * ドキュメントと画像の両方にインメモリキャッシュを返す便利関数。
107
- * memoryCache() はドキュメントキャッシュを返す(後方互換)。
108
- */
109
- function memoryCache(options) {
110
- return new MemoryDocumentCache(options);
111
- }
112
105
  //#endregion
113
- export { MemoryDocumentCache, MemoryImageCache, memoryCache, memoryDocumentCache, memoryImageCache };
106
+ export { MemoryDocumentCache, MemoryImageCache, memoryDocumentCache, memoryImageCache };
114
107
 
115
108
  //# sourceMappingURL=memory.mjs.map
@@ -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// { collection } または { collection, slug }。単一コレクション想定のため\n\t\t// list を必ず破棄し、slug 指定があれば該当 item も削除する\n\t\tthis.list = null;\n\t\tif (\"slug\" in scope) {\n\t\t\tthis.items.delete(scope.slug);\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\n/**\n * ドキュメントと画像の両方にインメモリキャッシュを返す便利関数。\n * memoryCache() はドキュメントキャッシュを返す(後方互換)。\n */\nexport function memoryCache<T extends BaseContentItem = BaseContentItem>(\n\toptions?: MemoryDocumentCacheOptions,\n): DocumentCacheAdapter<T> {\n\treturn new MemoryDocumentCache<T>(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;;AAID,OAAK,OAAO;AACZ,MAAI,UAAU,MACb,MAAK,MAAM,OAAO,MAAM,KAAK;;CAI/B,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;;;;;;AAOrC,SAAgB,YACf,SAC0B;AAC1B,QAAO,IAAI,oBAAuB,QAAQ"}
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// { collection } または { collection, slug }。単一コレクション想定のため\n\t\t// list を必ず破棄し、slug 指定があれば該当 item も削除する\n\t\tthis.list = null;\n\t\tif (\"slug\" in scope) {\n\t\t\tthis.items.delete(scope.slug);\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;;AAID,OAAK,OAAO;AACZ,MAAI,UAAU,MACb,MAAK,MAAM,OAAO,MAAM,KAAK;;CAI/B,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,5 +1,5 @@
1
- import { t as BaseContentItem } from "../content-BlD8UPas.mjs";
2
- import { n as DocumentCacheAdapter, r as ImageCacheAdapter } from "../cache-CcabrGjI.mjs";
1
+ import { t as BaseContentItem } from "../content-WydAfQtk.mjs";
2
+ import { n as DocumentCacheAdapter, r as ImageCacheAdapter } from "../cache-D051BP4G.mjs";
3
3
 
4
4
  //#region src/cache/noop.d.ts
5
5
  /** 何もしないドキュメントキャッシュを返す(シングルトン)。 */
@@ -1,79 +1,5 @@
1
- import { a as StorageBinary, i as CachedItemList, r as CachedItem, t as BaseContentItem } from "./content-BlD8UPas.mjs";
1
+ import { a as StorageBinary, c as ImageRef, i as CachedItemList, o as ContentBlock, r as CachedItem, t as BaseContentItem } from "./content-WydAfQtk.mjs";
2
2
 
3
- //#region src/content/blocks.d.ts
4
- /**
5
- * CMS 本文の中間表現 (AST)。
6
- *
7
- * DataSource が本文をこの配列にノーマライズして返す。
8
- * レンダラー (`blocksToHtml`) やカスタム React コンポーネントは
9
- * この型だけを扱えばよい。
10
- *
11
- * 対応が難しいブロック (Notion の column / synced block など) は
12
- * `{ type: "raw", html }` にフォールバックする。
13
- */
14
- type ContentBlock = {
15
- type: "paragraph";
16
- children: InlineNode[];
17
- } | {
18
- type: "heading";
19
- level: 1 | 2 | 3;
20
- children: InlineNode[];
21
- } | {
22
- type: "image";
23
- src: string;
24
- alt?: string;
25
- cachedHash?: string;
26
- } | {
27
- type: "code";
28
- lang?: string;
29
- value: string;
30
- } | {
31
- type: "list";
32
- ordered: boolean;
33
- items: ContentBlock[][];
34
- } | {
35
- type: "quote";
36
- children: ContentBlock[];
37
- } | {
38
- type: "divider";
39
- } | {
40
- type: "raw";
41
- html: string;
42
- };
43
- /** paragraph / heading 等の子に並ぶインラインノード。 */
44
- type InlineNode = {
45
- type: "text";
46
- value: string;
47
- bold?: boolean;
48
- italic?: boolean;
49
- code?: boolean;
50
- } | {
51
- type: "link";
52
- url: string;
53
- children: InlineNode[];
54
- } | {
55
- type: "break";
56
- };
57
- /**
58
- * `getItem({ include: { content: true } })` で返される本文。
59
- * blocks は常に同梱。html / markdown は遅延生成。
60
- */
61
- interface ContentResult {
62
- /** 本文の AST (第一級)。 */
63
- blocks: ContentBlock[];
64
- /** 遅延 HTML。renderer が必要な場合のみ呼ぶ。 */
65
- html(): Promise<string>;
66
- /** 遅延 Markdown。 */
67
- markdown(): Promise<string>;
68
- }
69
- /** 画像参照 (DataSource.resolveImageUrl に渡す)。 */
70
- interface ImageRef {
71
- /** 元の Notion 画像 URL (期限切れの可能性あり)。 */
72
- originalUrl: string;
73
- /** 関連するアイテム ID。 */
74
- itemId?: string;
75
- }
76
- //#endregion
77
3
  //#region src/types/data-source.d.ts
78
4
  /**
79
5
  * Notion プロパティ1件の型情報とプロパティ名を保持する。
@@ -112,10 +38,6 @@ interface WebhookConfig {
112
38
  interface DataSource<T extends BaseContentItem = BaseContentItem> {
113
39
  /** ソース識別子 (ロギング・デバッグ用)。 */
114
40
  readonly name: string;
115
- /** 公開扱いするステータス値 (ORM 側デフォルト)。 */
116
- readonly publishedStatuses?: readonly string[];
117
- /** アクセス許可するステータス値 (ORM 側デフォルト)。 */
118
- readonly accessibleStatuses?: readonly string[];
119
41
  /**
120
42
  * CLI 生成の `*Properties` に対応するプロパティマップ。
121
43
  * `properties` オプション経由で生成された DataSource のみ設定される。
@@ -126,12 +48,6 @@ interface DataSource<T extends BaseContentItem = BaseContentItem> {
126
48
  list(opts?: {
127
49
  publishedStatuses?: readonly string[];
128
50
  }): Promise<T[]>;
129
- /**
130
- * スラッグで単件取得。見つからなければ null。
131
- * @deprecated `properties` + `findByProp` を使用する新形式では不要。
132
- * 後方互換のため残す。
133
- */
134
- findBySlug?(slug: string): Promise<T | null>;
135
51
  /**
136
52
  * 指定した Notion プロパティ名と値で1件検索する。
137
53
  * Core が slug フィールドのルックアップに使用する。
@@ -228,5 +144,5 @@ type CacheConfig<T extends BaseContentItem = BaseContentItem> = "disabled" | {
228
144
  ttlMs?: number;
229
145
  };
230
146
  //#endregion
231
- export { CollectionConfig as a, InferCollectionItem as c, PropertyMap as d, WebhookConfig as f, InlineNode as g, ImageRef as h, CMSSchema as i, InvalidateScope as l, ContentResult as m, DocumentCacheAdapter as n, DataSource as o, ContentBlock as p, ImageCacheAdapter as r, DataSourceFactory as s, CacheConfig as t, PropertyDef as u };
232
- //# sourceMappingURL=cache-CcabrGjI.d.mts.map
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
@@ -0,0 +1,131 @@
1
+ //#region src/content/blocks.d.ts
2
+ /**
3
+ * CMS 本文の中間表現 (AST)。
4
+ *
5
+ * DataSource が本文をこの配列にノーマライズして返す。
6
+ * レンダラー (`blocksToHtml`) やカスタム React コンポーネントは
7
+ * この型だけを扱えばよい。
8
+ *
9
+ * 対応が難しいブロック (Notion の column / synced block など) は
10
+ * `{ type: "raw", html }` にフォールバックする。
11
+ */
12
+ type ContentBlock = {
13
+ type: "paragraph";
14
+ children: InlineNode[];
15
+ } | {
16
+ type: "heading";
17
+ level: 1 | 2 | 3;
18
+ children: InlineNode[];
19
+ } | {
20
+ type: "image";
21
+ src: string;
22
+ alt?: string;
23
+ cachedHash?: string;
24
+ } | {
25
+ type: "code";
26
+ lang?: string;
27
+ value: string;
28
+ } | {
29
+ type: "list";
30
+ ordered: boolean;
31
+ items: ContentBlock[][];
32
+ } | {
33
+ type: "quote";
34
+ children: ContentBlock[];
35
+ } | {
36
+ type: "divider";
37
+ } | {
38
+ type: "raw";
39
+ html: string;
40
+ };
41
+ /** paragraph / heading 等の子に並ぶインラインノード。 */
42
+ type InlineNode = {
43
+ type: "text";
44
+ value: string;
45
+ bold?: boolean;
46
+ italic?: boolean;
47
+ code?: boolean;
48
+ } | {
49
+ type: "link";
50
+ url: string;
51
+ children: InlineNode[];
52
+ } | {
53
+ type: "break";
54
+ };
55
+ /**
56
+ * `getItem({ include: { content: true } })` で返される本文。
57
+ * blocks は常に同梱。html / markdown は遅延生成。
58
+ */
59
+ interface ContentResult {
60
+ /** 本文の AST (第一級)。 */
61
+ blocks: ContentBlock[];
62
+ /** 遅延 HTML。renderer が必要な場合のみ呼ぶ。 */
63
+ html(): Promise<string>;
64
+ /** 遅延 Markdown。 */
65
+ markdown(): Promise<string>;
66
+ }
67
+ /** 画像参照 (DataSource.resolveImageUrl に渡す)。 */
68
+ interface ImageRef {
69
+ /** 元の Notion 画像 URL (期限切れの可能性あり)。 */
70
+ originalUrl: string;
71
+ /** 関連するアイテム ID。 */
72
+ itemId?: string;
73
+ }
74
+ //#endregion
75
+ //#region src/types/content.d.ts
76
+ /**
77
+ * ライブラリが動作するために必須なフィールド。
78
+ * 利用者はこのインターフェースを拡張して独自のコンテンツ型を定義する。
79
+ *
80
+ * @example
81
+ * interface Post extends BaseContentItem {
82
+ * title: string;
83
+ * author: string;
84
+ * }
85
+ * createCMS<Post>({ source: createNotionCollection({ ... }) })
86
+ */
87
+ interface BaseContentItem {
88
+ /** Notion ページ ID(変更検知に必須)。 */
89
+ id: string;
90
+ /** URL キー(必須)。 */
91
+ slug: string;
92
+ /** Notion ページ名(title 型プロパティのテキスト)。 */
93
+ title?: string | null;
94
+ /** 最終更新タイムスタンプ(変更検知に必須)。 */
95
+ updatedAt: string;
96
+ /** コンテンツのステータス。ステータスのない DB では省略可能。 */
97
+ status?: string;
98
+ /** 公開日時。日付プロパティのない DB では省略可能。 */
99
+ publishedAt?: string;
100
+ }
101
+ /** ストレージにキャッシュされたレンダリング済みコンテンツ。 */
102
+ interface CachedItem<T extends BaseContentItem = BaseContentItem> {
103
+ html: string;
104
+ item: T;
105
+ notionUpdatedAt: string;
106
+ cachedAt: number;
107
+ blocks?: ContentBlock[];
108
+ markdown?: string;
109
+ }
110
+ /** ストレージにキャッシュされたコンテンツ一覧。 */
111
+ interface CachedItemList<T extends BaseContentItem = BaseContentItem> {
112
+ items: T[];
113
+ cachedAt: number;
114
+ }
115
+ /** ストレージから取得したバイナリオブジェクト。 */
116
+ interface StorageBinary {
117
+ data: ArrayBuffer;
118
+ contentType?: string;
119
+ }
120
+ /** Notionのプロパティ名マッピング(すべてオプション)。 */
121
+ interface CMSSchemaProperties {
122
+ /** Notionのスラッグプロパティ名。デフォルト: 'Slug' */
123
+ slug?: string;
124
+ /** Notionのステータスプロパティ名。デフォルト: 'Status' */
125
+ status?: string;
126
+ /** Notionの公開日プロパティ名。デフォルト: 'CreatedAt' */
127
+ date?: string;
128
+ }
129
+ //#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
@@ -1,4 +1,4 @@
1
- import { r as CachedItem, t as BaseContentItem } from "./content-BlD8UPas.mjs";
1
+ import { r as CachedItem, t as BaseContentItem } from "./content-WydAfQtk.mjs";
2
2
 
3
3
  //#region src/types/hooks.d.ts
4
4
  type MaybePromise<T> = T | Promise<T>;
@@ -57,4 +57,4 @@ declare function mergeLoggers(plugins: Array<{
57
57
  }>, directLogger?: Logger): Logger | undefined;
58
58
  //#endregion
59
59
  export { Logger as a, definePlugin as i, mergeLoggers as n, CMSHooks as o, CMSPlugin as r, MaybePromise as s, mergeHooks as t };
60
- //# sourceMappingURL=hooks-DKnjPzHO.d.mts.map
60
+ //# sourceMappingURL=hooks-DwCisXsr.d.mts.map
package/dist/hooks.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { n as mergeLoggers, t as mergeHooks } from "./hooks-DKnjPzHO.mjs";
1
+ import { n as mergeLoggers, t as mergeHooks } from "./hooks-DwCisXsr.mjs";
2
2
  export { mergeHooks, mergeLoggers };
package/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
- import { a as StorageBinary, i as CachedItemList, n as CMSSchemaProperties, r as CachedItem, t as BaseContentItem } from "./content-BlD8UPas.mjs";
2
- import { a as CollectionConfig, c as InferCollectionItem, d as PropertyMap, f as WebhookConfig, g as InlineNode, h as ImageRef, i as CMSSchema, l as InvalidateScope, m as ContentResult, n as DocumentCacheAdapter, o as DataSource, p as ContentBlock, r as ImageCacheAdapter, s as DataSourceFactory, t as CacheConfig, u as PropertyDef } from "./cache-CcabrGjI.mjs";
3
- import { a as Logger, i as definePlugin, n as mergeLoggers, o as CMSHooks, r as CMSPlugin, s as MaybePromise, t as mergeHooks } from "./hooks-DKnjPzHO.mjs";
4
- import { MemoryDocumentCacheOptions, MemoryImageCacheOptions, memoryCache, memoryDocumentCache, memoryImageCache } from "./cache/memory.mjs";
1
+ import { a as StorageBinary, c as ImageRef, i as CachedItemList, l as InlineNode, n as CMSSchemaProperties, o as ContentBlock, r as CachedItem, s as ContentResult, t as BaseContentItem } from "./content-WydAfQtk.mjs";
2
+ import { a as CollectionConfig, c as InferCollectionItem, d as PropertyMap, f as WebhookConfig, i as CMSSchema, l as InvalidateScope, n as DocumentCacheAdapter, o as DataSource, r as ImageCacheAdapter, s as DataSourceFactory, t as CacheConfig, u as PropertyDef } from "./cache-D051BP4G.mjs";
3
+ import { a as Logger, i as definePlugin, n as mergeLoggers, o as CMSHooks, r as CMSPlugin, s as MaybePromise, t as mergeHooks } from "./hooks-DwCisXsr.mjs";
4
+ import { MemoryDocumentCacheOptions, MemoryImageCacheOptions, memoryDocumentCache, memoryImageCache } from "./cache/memory.mjs";
5
5
  import { noopDocumentCache, noopImageCache } from "./cache/noop.mjs";
6
6
  import { CMSError, CMSErrorCode, CMSErrorContext, isCMSError, isCMSErrorInNamespace } from "./errors.mjs";
7
7
 
@@ -394,5 +394,5 @@ interface NodePresetOptions {
394
394
  */
395
395
  declare function nodePreset(opts?: NodePresetOptions): Pick<CreateCMSOptions, "cache" | "renderer">;
396
396
  //#endregion
397
- export { type AdjacencyOptions, type BaseContentItem, type CMSClient, CMSError, type CMSErrorCode, type CMSErrorContext, type CMSGlobalOps, type CMSHooks, type CMSPlugin, type CMSSchema, type CMSSchemaProperties, type CacheConfig, type CachedItem, type CachedItemList, type CollectionClient, CollectionClientImpl, type CollectionConfig, type CollectionContext, type CollectionSemantics, type ContentBlock, type ContentConfig, type ContentResult, type CreateCMSOptions, DEFAULT_RETRY_CONFIG, type DataSource, type DataSourceFactory, type DataSourceMap, type DocumentCacheAdapter, type GetListOptions, type HandlerAdapter, type HandlerOptions, type ImageCacheAdapter, type ImageRef, type InferCollectionItem, type InferDataSourceItem, type InlineNode, type InvalidateScope, type ItemWithContent, type Logger, type MaybePromise, type MemoryDocumentCacheOptions, type MemoryImageCacheOptions, type NodePresetOptions, type PropertyDef, type PropertyMap, type RateLimiterConfig, type RenderOptions, type RendererFn, type RendererPluginList, type RetryConfig, type SortOption, type StorageBinary, type WebhookConfig, collectionKey, createCMS, createHandler, definePlugin, isCMSError, isCMSErrorInNamespace, isStale, memoryCache, memoryDocumentCache, memoryImageCache, mergeHooks, mergeLoggers, nodePreset, noopDocumentCache, noopImageCache, sha256Hex, withRetry };
397
+ export { type AdjacencyOptions, type BaseContentItem, type CMSClient, CMSError, type CMSErrorCode, type CMSErrorContext, type CMSGlobalOps, type CMSHooks, type CMSPlugin, type CMSSchema, type CMSSchemaProperties, type CacheConfig, type CachedItem, type CachedItemList, type CollectionClient, CollectionClientImpl, type CollectionConfig, type CollectionContext, type CollectionSemantics, type ContentBlock, type ContentConfig, type ContentResult, type CreateCMSOptions, DEFAULT_RETRY_CONFIG, type DataSource, type DataSourceFactory, type DataSourceMap, type DocumentCacheAdapter, type GetListOptions, type HandlerAdapter, type HandlerOptions, type ImageCacheAdapter, type ImageRef, type InferCollectionItem, type InferDataSourceItem, type InlineNode, type InvalidateScope, type ItemWithContent, type Logger, type MaybePromise, type MemoryDocumentCacheOptions, type MemoryImageCacheOptions, type NodePresetOptions, type PropertyDef, type PropertyMap, type RateLimiterConfig, type RenderOptions, type RendererFn, type RendererPluginList, type RetryConfig, type SortOption, type StorageBinary, type WebhookConfig, collectionKey, createCMS, createHandler, definePlugin, isCMSError, isCMSErrorInNamespace, isStale, memoryDocumentCache, memoryImageCache, mergeHooks, mergeLoggers, nodePreset, noopDocumentCache, noopImageCache, sha256Hex, withRetry };
398
398
  //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { memoryCache, memoryDocumentCache, memoryImageCache } from "./cache/memory.mjs";
1
+ import { memoryDocumentCache, memoryImageCache } from "./cache/memory.mjs";
2
2
  import { noopDocumentCache, noopImageCache } from "./cache/noop.mjs";
3
3
  import { CMSError, isCMSError, isCMSErrorInNamespace } from "./errors.mjs";
4
4
  import { mergeHooks, mergeLoggers } from "./hooks.mjs";
@@ -150,7 +150,7 @@ async function buildCachedItem(item, ctx) {
150
150
  /**
151
151
  * renderer オプション未指定時のフォールバック。
152
152
  * @notion-headless-cms/renderer を動的 import する。
153
- * adapter-cloudflare / adapter-node は renderer を明示注入するためこのパスは通らない。
153
+ * createCMS({ renderer }) で明示注入された場合はこのパスを通らない。
154
154
  */
155
155
  async function loadDefaultRenderer() {
156
156
  try {
@@ -308,8 +308,7 @@ var CollectionClientImpl = class {
308
308
  return markdownCache;
309
309
  }
310
310
  };
311
- const maybeBlocks = cached.blocks;
312
- if (maybeBlocks) blocksCache = maybeBlocks;
311
+ if (cached.blocks) blocksCache = cached.blocks;
313
312
  return Object.assign(Object.create(null), item, { content });
314
313
  }
315
314
  async fetchList() {
@@ -355,9 +354,7 @@ var CollectionClientImpl = class {
355
354
  const notionPropName = slugField ? this.ctx.source.properties?.[slugField]?.notion : void 0;
356
355
  let item;
357
356
  const findByProp = this.ctx.source.findByProp?.bind(this.ctx.source);
358
- const findBySlug = this.ctx.source.findBySlug?.bind(this.ctx.source);
359
357
  if (notionPropName && findByProp) item = await withRetry(() => findByProp(notionPropName, slug), retryOpts);
360
- else if (findBySlug) item = await withRetry(() => findBySlug(slug), retryOpts);
361
358
  else item = (await withRetry(() => this.ctx.source.list(), retryOpts)).find((i) => i.slug === slug) ?? null;
362
359
  if (!item) return null;
363
360
  if (this.ctx.accessibleStatuses.length > 0 && (!item.status || !this.ctx.accessibleStatuses.includes(item.status))) return null;
@@ -511,29 +508,12 @@ function hasImageCacheConfigured(cache) {
511
508
  */
512
509
  function scopeDocumentCache(base, collection) {
513
510
  const itemKey = (slug) => `${collection}:${slug}`;
514
- const listKey = collection;
515
511
  return {
516
512
  name: `${base.name}@${collection}`,
517
- async getList() {
518
- const anyBase = base;
519
- if (typeof anyBase.getListByKey === "function") return anyBase.getListByKey(listKey);
520
- return base.getList();
521
- },
522
- async setList(data) {
523
- const anyBase = base;
524
- if (typeof anyBase.setListByKey === "function") return anyBase.setListByKey(listKey, data);
525
- return base.setList(data);
526
- },
527
- async getItem(slug) {
528
- const anyBase = base;
529
- if (typeof anyBase.getItemByKey === "function") return anyBase.getItemByKey(itemKey(slug));
530
- return base.getItem(slug);
531
- },
532
- async setItem(slug, data) {
533
- const anyBase = base;
534
- if (typeof anyBase.setItemByKey === "function") return anyBase.setItemByKey(itemKey(slug), data);
535
- return base.setItem(slug, data);
536
- },
513
+ getList: () => base.getList(),
514
+ setList: (data) => base.setList(data),
515
+ getItem: (slug) => base.getItem(itemKey(slug)),
516
+ setItem: (slug, data) => base.setItem(itemKey(slug), data),
537
517
  async invalidate(scope) {
538
518
  if (!base.invalidate) return;
539
519
  if (scope === "all") return base.invalidate({ collection });
@@ -544,7 +524,7 @@ function scopeDocumentCache(base, collection) {
544
524
  /**
545
525
  * `preset` オプションを解決して `cache` / `renderer` のデフォルトを補完する内部関数。
546
526
  * 明示的な `cache` / `renderer` がある場合はそちらが優先される。
547
- * `preset` 未指定時は opts をそのまま返す(後方互換)。
527
+ * `preset` 未指定時は opts をそのまま返す。
548
528
  */
549
529
  function resolvePreset(opts) {
550
530
  if (opts.preset === "disabled") return {
@@ -636,8 +616,8 @@ function createCMS(opts) {
636
616
  hooks,
637
617
  logger,
638
618
  ttlMs,
639
- publishedStatuses: col?.publishedStatuses ? [...col.publishedStatuses] : source.publishedStatuses ? [...source.publishedStatuses] : [],
640
- accessibleStatuses: col?.accessibleStatuses ? [...col.accessibleStatuses] : source.accessibleStatuses ? [...source.accessibleStatuses] : [],
619
+ publishedStatuses: col?.publishedStatuses ? [...col.publishedStatuses] : [],
620
+ accessibleStatuses: col?.accessibleStatuses ? [...col.accessibleStatuses] : [],
641
621
  retryConfig,
642
622
  maxConcurrent,
643
623
  waitUntil,
@@ -690,6 +670,6 @@ function definePlugin(plugin) {
690
670
  return plugin;
691
671
  }
692
672
  //#endregion
693
- export { CMSError, CollectionClientImpl, DEFAULT_RETRY_CONFIG, collectionKey, createCMS, createHandler, definePlugin, isCMSError, isCMSErrorInNamespace, isStale, memoryCache, memoryDocumentCache, memoryImageCache, mergeHooks, mergeLoggers, nodePreset, noopDocumentCache, noopImageCache, sha256Hex, withRetry };
673
+ export { CMSError, CollectionClientImpl, DEFAULT_RETRY_CONFIG, collectionKey, createCMS, createHandler, definePlugin, isCMSError, isCMSErrorInNamespace, isStale, memoryDocumentCache, memoryImageCache, mergeHooks, mergeLoggers, nodePreset, noopDocumentCache, noopImageCache, sha256Hex, withRetry };
694
674
 
695
675
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/cache.ts","../src/image.ts","../src/rendering.ts","../src/retry.ts","../src/collection.ts","../src/handler.ts","../src/preset-node.ts","../src/cms.ts","../src/types/plugin.ts"],"sourcesContent":["/** 文字列をSHA-256でハッシュ化し、16進数文字列として返す。画像キーの生成に使用。 */\nexport async function sha256Hex(input: string): Promise<string> {\n\tconst data = new TextEncoder().encode(input);\n\tconst hash = await crypto.subtle.digest(\"SHA-256\", data);\n\treturn Array.from(new Uint8Array(hash))\n\t\t.map((b) => b.toString(16).padStart(2, \"0\"))\n\t\t.join(\"\");\n}\n\n/**\n * キャッシュが有効期限切れかどうかを判定する。\n * ttlMs が未指定の場合は常に false(無期限有効)を返す。\n */\nexport function isStale(cachedAt: number, ttlMs?: number): boolean {\n\tif (ttlMs === undefined) return false;\n\treturn Date.now() - cachedAt > ttlMs;\n}\n","import { sha256Hex } from \"./cache\";\nimport { CMSError, isCMSError } from \"./errors\";\nimport type { ImageCacheAdapter, StorageBinary } from \"./types/index\";\n\n/** レスポンスヘッダまたはURLの拡張子からContent-Typeを推測する。 */\nfunction inferContentType(\n\turl: string,\n\tresponseContentType: string | null,\n): string {\n\tif (responseContentType?.startsWith(\"image/\")) {\n\t\treturn responseContentType.split(\";\")[0].trim();\n\t}\n\tif (url.includes(\".png\")) return \"image/png\";\n\tif (url.includes(\".gif\")) return \"image/gif\";\n\tif (url.includes(\".webp\")) return \"image/webp\";\n\treturn \"image/jpeg\";\n}\n\n/**\n * Notion画像URLをfetchしてImageCacheAdapterにキャッシュし、プロキシURL を返す。\n * 既存キャッシュがあれば再fetchしない。\n */\nasync function fetchAndCacheImage(\n\tcache: ImageCacheAdapter,\n\tnotionUrl: string,\n\timageProxyBase: string,\n): Promise<string> {\n\tconst hash = await sha256Hex(notionUrl);\n\tconst proxyUrl = `${imageProxyBase}/${hash}`;\n\n\tconst existing = await cache.get(hash);\n\tif (existing) return proxyUrl;\n\n\ttry {\n\t\tconst response = await fetch(notionUrl, {\n\t\t\tsignal: AbortSignal.timeout(10_000),\n\t\t});\n\t\tif (!response.ok) {\n\t\t\tthrow new CMSError({\n\t\t\t\tcode: \"cache/image_fetch_failed\",\n\t\t\t\tmessage: `Failed to fetch Notion image: HTTP ${response.status}`,\n\t\t\t\tcontext: {\n\t\t\t\t\toperation: \"fetchAndCacheImage\",\n\t\t\t\t\tnotionUrl,\n\t\t\t\t\thttpStatus: response.status,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\tconst data = await response.arrayBuffer();\n\t\tconst contentType = inferContentType(\n\t\t\tnotionUrl,\n\t\t\tresponse.headers.get(\"content-type\"),\n\t\t);\n\t\tawait cache.set(hash, data, contentType);\n\t} catch (err) {\n\t\tif (isCMSError(err)) throw err;\n\t\tthrow new CMSError({\n\t\t\tcode: \"cache/io_failed\",\n\t\t\tmessage: \"Failed to fetch or cache Notion image.\",\n\t\t\tcause: err,\n\t\t\tcontext: { operation: \"fetchAndCacheImage\", notionUrl },\n\t\t});\n\t}\n\n\treturn proxyUrl;\n}\n\n/** ImageCacheAdapter と imageProxyBase から cacheImage 関数を構築するファクトリ。 */\nexport function buildCacheImageFn(\n\tcache: ImageCacheAdapter,\n\timageProxyBase: string,\n): (notionUrl: string) => Promise<string> {\n\treturn (notionUrl) => fetchAndCacheImage(cache, notionUrl, imageProxyBase);\n}\n\nexport type { StorageBinary };\n","import type { ContentBlock } from \"./content/blocks\";\nimport { CMSError, isCMSError } from \"./errors\";\nimport { buildCacheImageFn } from \"./image\";\nimport type {\n\tBaseContentItem,\n\tCachedItem,\n\tCMSHooks,\n\tContentConfig,\n\tDataSource,\n\tImageCacheAdapter,\n\tLogger,\n\tRendererFn,\n} from \"./types/index\";\n\n/** `buildCachedItem` に必要な CMS の依存を束ねたコンテキスト。 */\nexport interface RenderContext<T extends BaseContentItem> {\n\tsource: DataSource<T>;\n\trendererFn: RendererFn | undefined;\n\timgCache: ImageCacheAdapter;\n\thasImageCache: boolean;\n\timageProxyBase: string;\n\tcontentConfig: ContentConfig | undefined;\n\thooks: CMSHooks<T>;\n\tlogger: Logger | undefined;\n}\n\n/**\n * キャッシュに保存する CachedItem を拡張し、`blocks` を同梱できるようにする。\n * `CachedItem<T>` の構造互換性を保ちつつ blocks を optional で載せる。\n */\nexport type CachedItemWithBlocks<T extends BaseContentItem> = CachedItem<T> & {\n\tblocks?: ContentBlock[];\n\tmarkdown?: string;\n};\n\n/**\n * コンテンツアイテムをソースから Markdown ロード → blocks 生成 → HTML レンダリング\n * → フック適用まで実行し、キャッシュ保存用の `CachedItem` を返す。\n */\nexport async function buildCachedItem<T extends BaseContentItem>(\n\titem: T,\n\tctx: RenderContext<T>,\n): Promise<CachedItemWithBlocks<T>> {\n\tconst start = Date.now();\n\tctx.logger?.info?.(\"コンテンツのレンダリング開始\", {\n\t\tslug: item.slug,\n\t\tpageId: item.id,\n\t});\n\tctx.hooks.onRenderStart?.(item.slug);\n\n\tlet markdown: string;\n\ttry {\n\t\tmarkdown = await ctx.source.loadMarkdown(item);\n\t} catch (err) {\n\t\tif (isCMSError(err)) throw err;\n\t\tthrow new CMSError({\n\t\t\tcode: \"source/load_markdown_failed\",\n\t\t\tmessage: \"Failed to load markdown from source.\",\n\t\t\tcause: err,\n\t\t\tcontext: {\n\t\t\t\toperation: \"buildCachedItem:loadMarkdown\",\n\t\t\t\tpageId: item.id,\n\t\t\t\tslug: item.slug,\n\t\t\t},\n\t\t});\n\t}\n\n\tlet blocks: ContentBlock[] = [];\n\ttry {\n\t\tblocks = await ctx.source.loadBlocks(item);\n\t} catch (err) {\n\t\tctx.logger?.warn?.(\"loadBlocks に失敗したため raw フォールバック\", {\n\t\t\tslug: item.slug,\n\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t});\n\t\tblocks = [];\n\t}\n\n\tconst cacheImage = ctx.hasImageCache\n\t\t? buildCacheImageFn(ctx.imgCache, ctx.imageProxyBase)\n\t\t: undefined;\n\n\tlet html: string;\n\tconst rendererFn = ctx.rendererFn ?? (await loadDefaultRenderer());\n\ttry {\n\t\thtml = await rendererFn(markdown, {\n\t\t\timageProxyBase: ctx.imageProxyBase,\n\t\t\tcacheImage,\n\t\t\tremarkPlugins: ctx.contentConfig?.remarkPlugins,\n\t\t\trehypePlugins: ctx.contentConfig?.rehypePlugins,\n\t\t});\n\t} catch (err) {\n\t\tif (isCMSError(err)) throw err;\n\t\tthrow new CMSError({\n\t\t\tcode: \"renderer/failed\",\n\t\t\tmessage: \"Failed to render markdown.\",\n\t\t\tcause: err,\n\t\t\tcontext: {\n\t\t\t\toperation: \"buildCachedItem:renderMarkdown\",\n\t\t\t\tpageId: item.id,\n\t\t\t\tslug: item.slug,\n\t\t\t},\n\t\t});\n\t}\n\n\tif (ctx.hooks.afterRender) {\n\t\thtml = await ctx.hooks.afterRender(html, item);\n\t}\n\n\tlet result: CachedItemWithBlocks<T> = {\n\t\thtml,\n\t\tblocks,\n\t\tmarkdown,\n\t\titem,\n\t\tnotionUpdatedAt: ctx.source.getLastModified(item),\n\t\tcachedAt: Date.now(),\n\t};\n\n\tif (ctx.hooks.beforeCache) {\n\t\tresult = (await ctx.hooks.beforeCache(result)) as CachedItemWithBlocks<T>;\n\t}\n\n\tconst durationMs = Date.now() - start;\n\tctx.logger?.info?.(\"コンテンツのレンダリング完了\", {\n\t\tslug: item.slug,\n\t\tdurationMs,\n\t});\n\tctx.hooks.onRenderEnd?.(item.slug, durationMs);\n\n\treturn result;\n}\n\n/**\n * renderer オプション未指定時のフォールバック。\n * @notion-headless-cms/renderer を動的 import する。\n * adapter-cloudflare / adapter-node は renderer を明示注入するためこのパスは通らない。\n */\nexport async function loadDefaultRenderer(): Promise<RendererFn> {\n\ttry {\n\t\tconst mod = await import(\"@notion-headless-cms/renderer\");\n\t\treturn mod.renderMarkdown as RendererFn;\n\t} catch (err) {\n\t\tthrow new CMSError({\n\t\t\tcode: \"renderer/failed\",\n\t\t\tmessage:\n\t\t\t\t\"renderer オプションが未指定で @notion-headless-cms/renderer が見つかりません。\" +\n\t\t\t\t\" createCMS({ renderer }) でレンダラーを注入するか、@notion-headless-cms/renderer をインストールしてください。\",\n\t\t\tcause: err,\n\t\t\tcontext: { operation: \"loadDefaultRenderer\" },\n\t\t});\n\t}\n}\n","export interface RetryConfig {\n\tretryOn: number[];\n\tmaxRetries: number;\n\tbaseDelayMs: number;\n\t/** true のとき指数バックオフにランダムジッターを加える(Thundering Herd 対策)。デフォルト: true */\n\tjitter?: boolean;\n\tonRetry?: (attempt: number, status: number) => void;\n}\n\nexport const DEFAULT_RETRY_CONFIG: RetryConfig = {\n\tretryOn: [429, 502, 503],\n\tmaxRetries: 4,\n\tbaseDelayMs: 1000,\n\tjitter: true,\n};\n\n/** 指数バックオフ(オプションでジッター付き)でリトライする。retryOn に含まれる HTTP エラーのみ対象。 */\nexport async function withRetry<T>(\n\tfn: () => Promise<T>,\n\tconfig: RetryConfig,\n): Promise<T> {\n\tlet lastError: unknown;\n\tfor (let attempt = 0; attempt <= config.maxRetries; attempt++) {\n\t\ttry {\n\t\t\treturn await fn();\n\t\t} catch (err) {\n\t\t\tconst status = (err as { status?: number }).status;\n\t\t\tif (status === undefined || !config.retryOn.includes(status)) {\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t\tlastError = err;\n\t\t\tif (attempt < config.maxRetries) {\n\t\t\t\tconfig.onRetry?.(attempt + 1, status);\n\t\t\t\tconst jitterFactor =\n\t\t\t\t\tconfig.jitter !== false ? 0.5 + Math.random() * 0.5 : 1;\n\t\t\t\tconst delay = config.baseDelayMs * 2 ** attempt * jitterFactor;\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, delay));\n\t\t\t}\n\t\t}\n\t}\n\tthrow lastError;\n}\n","import { isStale } from \"./cache\";\nimport type { ContentBlock, ContentResult } from \"./content/blocks\";\nimport type { RenderContext } from \"./rendering\";\nimport { buildCachedItem } from \"./rendering\";\nimport type { RetryConfig } from \"./retry\";\nimport { withRetry } from \"./retry\";\nimport type {\n\tAdjacencyOptions,\n\tBaseContentItem,\n\tCachedItem,\n\tCMSHooks,\n\tCollectionClient,\n\tDataSource,\n\tDocumentCacheAdapter,\n\tGetListOptions,\n\tItemWithContent,\n\tLogger,\n\tSortOption,\n} from \"./types/index\";\n\n/**\n * コレクション別キャッシュキーを生成する。\n * item: `{collection}:{slug}` / list: `{collection}`\n */\nexport function collectionKey(collection: string, slug?: string): string {\n\treturn slug ? `${collection}:${slug}` : collection;\n}\n\n/** 単一コレクションの DataSource + SWR キャッシュ依存を束ねたコンテキスト。 */\nexport interface CollectionContext<T extends BaseContentItem> {\n\tcollection: string;\n\tsource: DataSource<T>;\n\tdocCache: DocumentCacheAdapter<T>;\n\trender: RenderContext<T>;\n\thooks: CMSHooks<T>;\n\tlogger: Logger | undefined;\n\tttlMs: number | undefined;\n\tpublishedStatuses: string[];\n\taccessibleStatuses: string[];\n\tretryConfig: RetryConfig;\n\tmaxConcurrent: number;\n\twaitUntil: ((p: Promise<unknown>) => void) | undefined;\n\t/**\n\t * slug として使うフィールド名。\n\t * `createCMS({ collections })` で指定した値。\n\t * 設定時は `source.properties[slugField].notion` を Notion プロパティ名として\n\t * `findByProp` を呼び出す。\n\t */\n\tslugField?: string;\n}\n\n/** CollectionClient の実装。ユーザーは `createCMS` 経由でインスタンスを受け取る。 */\nexport class CollectionClientImpl<T extends BaseContentItem>\n\timplements CollectionClient<T>\n{\n\tconstructor(private readonly ctx: CollectionContext<T>) {}\n\n\t// ── 基本取得 ──────────────────────────────────────────────────────────\n\n\tasync getItem(slug: string): Promise<ItemWithContent<T> | null> {\n\t\tconst cached = await this.ctx.docCache.getItem(slug);\n\t\tif (cached && !isStale(cached.cachedAt, this.ctx.ttlMs)) {\n\t\t\tthis.ctx.hooks.onCacheHit?.(slug, cached);\n\t\t\treturn this.attachContent(cached.item, cached);\n\t\t}\n\n\t\tthis.ctx.hooks.onCacheMiss?.(slug);\n\t\tconst item = await this.findRaw(slug);\n\t\tif (!item) return null;\n\n\t\tconst entry = await buildCachedItem(item, this.ctx.render);\n\t\tconst save = this.ctx.docCache.setItem(slug, entry);\n\t\tif (this.ctx.waitUntil) {\n\t\t\tthis.ctx.waitUntil(save);\n\t\t} else {\n\t\t\tawait save;\n\t\t}\n\n\t\treturn this.attachContent(entry.item, entry);\n\t}\n\n\tasync getList(opts?: GetListOptions<T>): Promise<T[]> {\n\t\tconst items = await this.fetchList();\n\t\treturn applyGetListOptions(items, opts);\n\t}\n\n\t// ── SSG / ナビゲーション ─────────────────────────────────────────────\n\n\tasync getStaticParams(): Promise<{ slug: string }[]> {\n\t\tconst items = await this.fetchList();\n\t\treturn items.map((item) => ({ slug: item.slug }));\n\t}\n\n\tasync getStaticPaths(): Promise<string[]> {\n\t\tconst items = await this.fetchList();\n\t\treturn items.map((item) => item.slug);\n\t}\n\n\tasync adjacent(\n\t\tslug: string,\n\t\topts?: AdjacencyOptions<T>,\n\t): Promise<{ prev: T | null; next: T | null }> {\n\t\tconst items = applyGetListOptions(await this.fetchList(), {\n\t\t\tsort: opts?.sort,\n\t\t});\n\t\tconst index = items.findIndex((it) => it.slug === slug);\n\t\tif (index === -1) return { prev: null, next: null };\n\t\treturn {\n\t\t\tprev: index > 0 ? (items[index - 1] ?? null) : null,\n\t\t\tnext: index < items.length - 1 ? (items[index + 1] ?? null) : null,\n\t\t};\n\t}\n\n\t// ── キャッシュ ────────────────────────────────────────────────────────\n\n\tasync revalidate(scope?: \"all\" | { slug: string }): Promise<void> {\n\t\tif (!this.ctx.docCache.invalidate) return;\n\t\tif (scope === undefined || scope === \"all\") {\n\t\t\tawait this.ctx.docCache.invalidate({ collection: this.ctx.collection });\n\t\t} else {\n\t\t\tawait this.ctx.docCache.invalidate({\n\t\t\t\tcollection: this.ctx.collection,\n\t\t\t\tslug: scope.slug,\n\t\t\t});\n\t\t}\n\t}\n\n\tasync prefetch(opts?: {\n\t\tconcurrency?: number;\n\t\tonProgress?: (done: number, total: number) => void;\n\t}): Promise<{ ok: number; failed: number }> {\n\t\tconst items = await this.fetchListRaw();\n\t\tconst concurrency = opts?.concurrency ?? this.ctx.maxConcurrent;\n\t\tlet ok = 0;\n\t\tlet failed = 0;\n\n\t\tfor (let i = 0; i < items.length; i += concurrency) {\n\t\t\tconst chunk = items.slice(i, i + concurrency);\n\t\t\tawait Promise.all(\n\t\t\t\tchunk.map(async (item) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst rendered = await buildCachedItem(item, this.ctx.render);\n\t\t\t\t\t\tawait this.ctx.docCache.setItem(item.slug, rendered);\n\t\t\t\t\t\tok++;\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tfailed++;\n\t\t\t\t\t\tthis.ctx.logger?.warn?.(\n\t\t\t\t\t\t\t\"prefetch: アイテムの事前レンダリングに失敗\",\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tslug: item.slug,\n\t\t\t\t\t\t\t\tpageId: item.id,\n\t\t\t\t\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t);\n\t\t\topts?.onProgress?.(Math.min(i + concurrency, items.length), items.length);\n\t\t}\n\n\t\tawait this.ctx.docCache.setList({ items, cachedAt: Date.now() });\n\t\treturn { ok, failed };\n\t}\n\n\t// ── 内部 ──────────────────────────────────────────────────────────────\n\n\tprivate attachContent(item: T, cached: CachedItem<T>): ItemWithContent<T> {\n\t\tconst ctx = this.ctx;\n\t\tlet blocksCache: ContentBlock[] | undefined;\n\t\tlet htmlCache: string | undefined = cached.html;\n\t\tlet markdownCache: string | undefined;\n\n\t\tconst content: ContentResult = {\n\t\t\tget blocks(): ContentBlock[] {\n\t\t\t\tif (!blocksCache) {\n\t\t\t\t\t// lazy: キャッシュに blocks が保存されていない場合、簡易な single-raw に落とす\n\t\t\t\t\tblocksCache = [\n\t\t\t\t\t\t{ type: \"raw\", html: cached.html } satisfies ContentBlock,\n\t\t\t\t\t];\n\t\t\t\t}\n\t\t\t\treturn blocksCache;\n\t\t\t},\n\t\t\tasync html(): Promise<string> {\n\t\t\t\tif (htmlCache !== undefined) return htmlCache;\n\t\t\t\thtmlCache = cached.html;\n\t\t\t\treturn htmlCache;\n\t\t\t},\n\t\t\tasync markdown(): Promise<string> {\n\t\t\t\tif (markdownCache !== undefined) return markdownCache;\n\t\t\t\tmarkdownCache = await ctx.source.loadMarkdown(item);\n\t\t\t\treturn markdownCache;\n\t\t\t},\n\t\t};\n\n\t\t// blocks が CachedItem に乗っていれば優先的に採用する\n\t\tconst maybeBlocks = (cached as CachedItem<T> & { blocks?: ContentBlock[] })\n\t\t\t.blocks;\n\t\tif (maybeBlocks) blocksCache = maybeBlocks;\n\n\t\treturn Object.assign(Object.create(null) as object, item, {\n\t\t\tcontent,\n\t\t}) as ItemWithContent<T>;\n\t}\n\n\tprivate async fetchList(): Promise<T[]> {\n\t\tconst cached = await this.ctx.docCache.getList();\n\t\tif (cached && !isStale(cached.cachedAt, this.ctx.ttlMs)) {\n\t\t\tthis.ctx.hooks.onListCacheHit?.(cached.items, cached.cachedAt);\n\t\t\treturn cached.items;\n\t\t}\n\n\t\tthis.ctx.hooks.onListCacheMiss?.();\n\t\tconst items = await this.fetchListRaw();\n\t\tconst cachedAt = Date.now();\n\t\tconst save = this.ctx.docCache.setList({ items, cachedAt });\n\t\tif (this.ctx.waitUntil) {\n\t\t\tthis.ctx.waitUntil(save);\n\t\t} else {\n\t\t\tawait save;\n\t\t}\n\t\treturn items;\n\t}\n\n\tprivate fetchListRaw(): Promise<T[]> {\n\t\treturn withRetry(\n\t\t\t() =>\n\t\t\t\tthis.ctx.source.list({\n\t\t\t\t\tpublishedStatuses:\n\t\t\t\t\t\tthis.ctx.publishedStatuses.length > 0\n\t\t\t\t\t\t\t? this.ctx.publishedStatuses\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t}),\n\t\t\t{\n\t\t\t\t...this.ctx.retryConfig,\n\t\t\t\tonRetry: (attempt, status) => {\n\t\t\t\t\tthis.ctx.logger?.warn?.(\"getList() リトライ中\", { attempt, status });\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\t}\n\n\tprivate async findRaw(slug: string): Promise<T | null> {\n\t\tconst retryOpts = {\n\t\t\t...this.ctx.retryConfig,\n\t\t\tonRetry: (attempt: number, status: number) => {\n\t\t\t\tthis.ctx.logger?.warn?.(\"getItem() リトライ中\", {\n\t\t\t\t\tattempt,\n\t\t\t\t\tstatus,\n\t\t\t\t\tslug,\n\t\t\t\t});\n\t\t\t},\n\t\t};\n\n\t\t// slug フィールドが指定され、DataSource が findByProp を持つ場合は\n\t\t// Notion プロパティ名を解決して効率的なフィルタクエリを実行する。\n\t\tconst slugField = this.ctx.slugField;\n\t\tconst notionPropName = slugField\n\t\t\t? this.ctx.source.properties?.[slugField]?.notion\n\t\t\t: undefined;\n\n\t\tlet item: T | null;\n\t\tconst findByProp = this.ctx.source.findByProp?.bind(this.ctx.source);\n\t\tconst findBySlug = this.ctx.source.findBySlug?.bind(this.ctx.source);\n\t\tif (notionPropName && findByProp) {\n\t\t\titem = await withRetry(() => findByProp(notionPropName, slug), retryOpts);\n\t\t} else if (findBySlug) {\n\t\t\titem = await withRetry(() => findBySlug(slug), retryOpts);\n\t\t} else {\n\t\t\tconst all = await withRetry(() => this.ctx.source.list(), retryOpts);\n\t\t\titem = all.find((i) => i.slug === slug) ?? null;\n\t\t}\n\n\t\tif (!item) return null;\n\t\tif (\n\t\t\tthis.ctx.accessibleStatuses.length > 0 &&\n\t\t\t(!item.status || !this.ctx.accessibleStatuses.includes(item.status))\n\t\t) {\n\t\t\treturn null;\n\t\t}\n\t\treturn item;\n\t}\n}\n\nfunction applyGetListOptions<T extends BaseContentItem>(\n\titems: T[],\n\topts?: GetListOptions<T>,\n): T[] {\n\tif (!opts) return items;\n\tlet result = items;\n\n\tif (opts.statuses && opts.statuses.length > 0) {\n\t\tconst allow = new Set(opts.statuses);\n\t\tresult = result.filter(\n\t\t\t(it) => it.status !== undefined && allow.has(it.status),\n\t\t);\n\t}\n\n\tif (opts.tag) {\n\t\tconst tag = opts.tag;\n\t\tresult = result.filter((it) => {\n\t\t\tconst tags = (it as unknown as { tags?: unknown }).tags;\n\t\t\treturn Array.isArray(tags) && tags.includes(tag);\n\t\t});\n\t}\n\n\tif (opts.where) {\n\t\tconst where = opts.where;\n\t\tresult = result.filter((it) =>\n\t\t\tObject.entries(where).every(\n\t\t\t\t([key, value]) => (it as Record<string, unknown>)[key] === value,\n\t\t\t),\n\t\t);\n\t}\n\n\tif (opts.sort) {\n\t\tresult = [...result].sort(makeComparator(opts.sort));\n\t}\n\n\tconst skip = opts.skip ?? 0;\n\tconst limit = opts.limit;\n\tif (skip > 0 || limit !== undefined) {\n\t\tresult = result.slice(skip, limit !== undefined ? skip + limit : undefined);\n\t}\n\n\treturn result;\n}\n\nfunction makeComparator<T extends BaseContentItem>(\n\tsort: SortOption<T>,\n): (a: T, b: T) => number {\n\tconst by = sort.by;\n\tconst dir = sort.direction === \"asc\" ? 1 : -1;\n\treturn (a, b) => {\n\t\tconst av = (a as Record<string, unknown>)[by];\n\t\tconst bv = (b as Record<string, unknown>)[by];\n\t\tif (av === bv) return 0;\n\t\tif (av === undefined) return 1;\n\t\tif (bv === undefined) return -1;\n\t\t// biome-ignore lint/suspicious/noExplicitAny: 汎用比較\n\t\treturn (av as any) > (bv as any) ? dir : -dir;\n\t};\n}\n","import type { ImageCacheAdapter, InvalidateScope } from \"./types/index\";\n\n/** `$handler()` の挙動設定。 */\nexport interface HandlerOptions {\n\t/** マウントするベースパス。デフォルト `/api/cms`。 */\n\tbasePath?: string;\n\t/** 画像プロキシのパス (basePath 相対)。デフォルト `/images/:hash`。 */\n\timagesPath?: string;\n\t/** revalidate webhook のパス (basePath 相対)。デフォルト `/revalidate`。 */\n\trevalidatePath?: string;\n\t/** Webhook 署名検証用シークレット (未指定なら検証スキップ)。 */\n\twebhookSecret?: string;\n\t/** デフォルト実装を無効化する場合 true。 */\n\tdisabled?: boolean;\n}\n\n/** `$handler()` が内部で依存する CMS 機能の最小セット。 */\nexport interface HandlerAdapter {\n\timageCache: ImageCacheAdapter;\n\t/** コレクション名で DataSource を取り出し parseWebhook にフォワードする。 */\n\tparseWebhook(\n\t\treq: Request,\n\t\twebhookSecret: string | undefined,\n\t): Promise<InvalidateScope | null>;\n\trevalidate(scope: InvalidateScope): Promise<void>;\n}\n\nconst DEFAULT_OPTS = {\n\tbasePath: \"/api/cms\",\n\timagesPath: \"/images\",\n\trevalidatePath: \"/revalidate\",\n} as const;\n\n/**\n * Web Standard な Request → Response ルーター。\n * Next.js / React Router / Hono / Cloudflare Workers いずれでも使える。\n *\n * ルート:\n * - GET `{basePath}/images/:hash` — 画像プロキシ\n * - POST `{basePath}/revalidate` — Webhook 受信 + $revalidate()\n */\nexport function createHandler(\n\tadapter: HandlerAdapter,\n\topts: HandlerOptions = {},\n): (req: Request) => Promise<Response> {\n\tconst basePath = trimTrailingSlash(opts.basePath ?? DEFAULT_OPTS.basePath);\n\tconst imagesPath = opts.imagesPath ?? DEFAULT_OPTS.imagesPath;\n\tconst revalidatePath = opts.revalidatePath ?? DEFAULT_OPTS.revalidatePath;\n\n\treturn async (req: Request): Promise<Response> => {\n\t\tconst url = new URL(req.url);\n\t\tconst path = url.pathname;\n\n\t\tif (!path.startsWith(basePath)) {\n\t\t\treturn new Response(\"Not Found\", { status: 404 });\n\t\t}\n\t\tconst rel = path.slice(basePath.length) || \"/\";\n\n\t\t// 画像: GET {basePath}/images/:hash\n\t\tif (req.method === \"GET\" && rel.startsWith(`${imagesPath}/`)) {\n\t\t\tconst hash = rel.slice(imagesPath.length + 1);\n\t\t\tif (!hash) return new Response(\"Bad Request\", { status: 400 });\n\t\t\tconst object = await adapter.imageCache.get(hash);\n\t\t\tif (!object) return new Response(\"Not Found\", { status: 404 });\n\t\t\tconst headers = new Headers();\n\t\t\tif (object.contentType) headers.set(\"content-type\", object.contentType);\n\t\t\theaders.set(\"cache-control\", \"public, max-age=31536000, immutable\");\n\t\t\treturn new Response(object.data, { headers });\n\t\t}\n\n\t\t// Revalidate: POST {basePath}/revalidate\n\t\tif (req.method === \"POST\" && rel === revalidatePath) {\n\t\t\tconst scope = await adapter.parseWebhook(req, opts.webhookSecret);\n\t\t\tif (!scope) {\n\t\t\t\treturn new Response(JSON.stringify({ ok: false, reason: \"invalid\" }), {\n\t\t\t\t\tstatus: 400,\n\t\t\t\t\theaders: { \"content-type\": \"application/json\" },\n\t\t\t\t});\n\t\t\t}\n\t\t\tawait adapter.revalidate(scope);\n\t\t\treturn new Response(JSON.stringify({ ok: true, scope }), {\n\t\t\t\tstatus: 200,\n\t\t\t\theaders: { \"content-type\": \"application/json\" },\n\t\t\t});\n\t\t}\n\n\t\treturn new Response(\"Not Found\", { status: 404 });\n\t};\n}\n\nfunction trimTrailingSlash(s: string): string {\n\treturn s.endsWith(\"/\") ? s.slice(0, -1) : s;\n}\n","import { memoryDocumentCache, memoryImageCache } from \"./cache/memory\";\nimport type { CacheConfig, CreateCMSOptions, RendererFn } from \"./types/index\";\n\n/** `nodePreset()` のオプション。 */\nexport interface NodePresetOptions {\n\t/**\n\t * キャッシュ設定。\n\t * - 省略時: memoryDocumentCache + memoryImageCache をデフォルト有効化\n\t * - `\"disabled\"`: キャッシュを完全無効化\n\t * - オブジェクト: 任意の cache adapter を差し込む\n\t */\n\tcache?: CacheConfig | \"disabled\";\n\t/** SWR の TTL (ミリ秒)。`cache` をオブジェクトで渡した場合はそちらが優先される。 */\n\tttlMs?: number;\n\t/** カスタムレンダラー。未指定時は core が @notion-headless-cms/renderer を動的ロード。 */\n\trenderer?: RendererFn;\n}\n\n/**\n * Node.js ランタイム向けの `createCMS` オプションプリセット。\n * メモリキャッシュをデフォルト有効にした `{ cache, renderer }` を返す。\n *\n * @example\n * import { createCMS, nodePreset } from \"@notion-headless-cms/core\";\n * import { cmsDataSources } from \"./generated/cms-schema\";\n *\n * const cms = createCMS({\n * ...nodePreset({ ttlMs: 5 * 60_000 }),\n * dataSources: cmsDataSources,\n * });\n */\nexport function nodePreset(\n\topts: NodePresetOptions = {},\n): Pick<CreateCMSOptions, \"cache\" | \"renderer\"> {\n\tif (opts.cache === \"disabled\") {\n\t\treturn { cache: undefined, renderer: opts.renderer };\n\t}\n\treturn {\n\t\tcache: opts.cache ?? {\n\t\t\tdocument: memoryDocumentCache(),\n\t\t\timage: memoryImageCache(),\n\t\t\tttlMs: opts.ttlMs,\n\t\t},\n\t\trenderer: opts.renderer,\n\t};\n}\n","import { noopDocumentCache, noopImageCache } from \"./cache/noop\";\nimport { CollectionClientImpl, type CollectionContext } from \"./collection\";\nimport { CMSError } from \"./errors\";\nimport { createHandler, type HandlerOptions } from \"./handler\";\nimport { mergeHooks, mergeLoggers } from \"./hooks\";\nimport { nodePreset } from \"./preset-node\";\nimport type { RenderContext } from \"./rendering\";\nimport type { RetryConfig } from \"./retry\";\nimport { DEFAULT_RETRY_CONFIG } from \"./retry\";\nimport type {\n\tBaseContentItem,\n\tCacheConfig,\n\tCMSHooks,\n\tCollectionClient,\n\tCollectionSemantics,\n\tCreateCMSOptions,\n\tDataSource,\n\tDataSourceMap,\n\tDocumentCacheAdapter,\n\tImageCacheAdapter,\n\tInferDataSourceItem,\n\tInvalidateScope,\n\tLogger,\n\tRendererFn,\n} from \"./types/index\";\n\nconst DEFAULT_IMAGE_PROXY_BASE = \"/api/images\";\n\n/** `CMSClient<D>` — コレクション別アクセス + グローバル操作の合成型。 */\nexport type CMSClient<D extends DataSourceMap> = {\n\t[K in keyof D]: CollectionClient<InferDataSourceItem<D[K]>>;\n} & CMSGlobalOps<D>;\n\n/** `CMSClient` のグローバル名前空間。`$` プレフィックス。 */\nexport interface CMSGlobalOps<D extends DataSourceMap> {\n\t/** 登録されているコレクション名の一覧。 */\n\treadonly $collections: readonly (keyof D & string)[];\n\t/** 全コレクションまたは特定コレクションのキャッシュを無効化する。 */\n\t$revalidate(scope?: InvalidateScope): Promise<void>;\n\t/** Web Standard なルーティングハンドラ (画像プロキシ / webhook) を生成する。 */\n\t$handler(opts?: HandlerOptions): (req: Request) => Promise<Response>;\n\t/** ハッシュキーでキャッシュ画像を取得する。 */\n\t$getCachedImage(hash: string): ReturnType<ImageCacheAdapter[\"get\"]>;\n}\n\nfunction resolveDocumentCache(\n\tcache: CacheConfig | undefined,\n\t// biome-ignore lint/suspicious/noExplicitAny: 横断的に利用\n): DocumentCacheAdapter<any> {\n\tif (!cache || cache === \"disabled\" || !cache.document) {\n\t\treturn noopDocumentCache();\n\t}\n\treturn cache.document;\n}\n\nfunction resolveImageCache(cache: CacheConfig | undefined): ImageCacheAdapter {\n\tif (!cache || cache === \"disabled\" || !cache.image) {\n\t\treturn noopImageCache();\n\t}\n\treturn cache.image;\n}\n\nfunction resolveTtl(cache: CacheConfig | undefined): number | undefined {\n\tif (!cache || cache === \"disabled\") return undefined;\n\treturn cache.ttlMs;\n}\n\nfunction hasImageCacheConfigured(cache: CacheConfig | undefined): boolean {\n\tif (!cache || cache === \"disabled\") return false;\n\treturn !!cache.image;\n}\n\n/**\n * `{collection}:{slug}` キー空間で動作するコレクション別キャッシュビューを生成する。\n * 単一の `DocumentCacheAdapter` に複数コレクションを同居させるためのアダプタ。\n */\nfunction scopeDocumentCache<T extends BaseContentItem>(\n\t// biome-ignore lint/suspicious/noExplicitAny: 共有ストレージのため\n\tbase: DocumentCacheAdapter<any>,\n\tcollection: string,\n): DocumentCacheAdapter<T> {\n\tconst itemKey = (slug: string): string => `${collection}:${slug}`;\n\tconst listKey = collection;\n\n\treturn {\n\t\tname: `${base.name}@${collection}`,\n\t\tasync getList() {\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: キー別 namespace\n\t\t\tconst anyBase = base as any;\n\t\t\tif (typeof anyBase.getListByKey === \"function\") {\n\t\t\t\treturn anyBase.getListByKey(listKey);\n\t\t\t}\n\t\t\treturn base.getList();\n\t\t},\n\t\tasync setList(data) {\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: キー別 namespace\n\t\t\tconst anyBase = base as any;\n\t\t\tif (typeof anyBase.setListByKey === \"function\") {\n\t\t\t\treturn anyBase.setListByKey(listKey, data);\n\t\t\t}\n\t\t\treturn base.setList(data);\n\t\t},\n\t\tasync getItem(slug) {\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: キー別 namespace\n\t\t\tconst anyBase = base as any;\n\t\t\tif (typeof anyBase.getItemByKey === \"function\") {\n\t\t\t\treturn anyBase.getItemByKey(itemKey(slug));\n\t\t\t}\n\t\t\treturn base.getItem(slug);\n\t\t},\n\t\tasync setItem(slug, data) {\n\t\t\t// biome-ignore lint/suspicious/noExplicitAny: キー別 namespace\n\t\t\tconst anyBase = base as any;\n\t\t\tif (typeof anyBase.setItemByKey === \"function\") {\n\t\t\t\treturn anyBase.setItemByKey(itemKey(slug), data);\n\t\t\t}\n\t\t\treturn base.setItem(slug, data);\n\t\t},\n\t\tasync invalidate(scope) {\n\t\t\tif (!base.invalidate) return;\n\t\t\tif (scope === \"all\") {\n\t\t\t\treturn base.invalidate({ collection });\n\t\t\t}\n\t\t\treturn base.invalidate(scope);\n\t\t},\n\t};\n}\n\n/**\n * `preset` オプションを解決して `cache` / `renderer` のデフォルトを補完する内部関数。\n * 明示的な `cache` / `renderer` がある場合はそちらが優先される。\n * `preset` 未指定時は opts をそのまま返す(後方互換)。\n */\nfunction resolvePreset<D extends DataSourceMap>(\n\topts: CreateCMSOptions<D>,\n): CreateCMSOptions<D> {\n\tif (opts.preset === \"disabled\") {\n\t\treturn { ...opts, cache: undefined };\n\t}\n\tif (opts.preset === \"node\") {\n\t\tconst presetResult = nodePreset({ ttlMs: opts.ttlMs });\n\t\treturn {\n\t\t\t...opts,\n\t\t\tcache: opts.cache ?? presetResult.cache,\n\t\t\trenderer: opts.renderer ?? presetResult.renderer,\n\t\t};\n\t}\n\treturn opts;\n}\n\n/**\n * 複数の DataSource を束ねた CMS クライアントを生成する。\n *\n * @example\n * // Node.js(preset を使った簡潔な記法)\n * const cms = createCMS({ dataSources: cmsDataSources, preset: \"node\", ttlMs: 5 * 60_000 });\n *\n * @example\n * // 従来の spread パターン(引き続き動作する)\n * const cms = createCMS({ ...nodePreset({ ttlMs: 5 * 60_000 }), dataSources: cmsDataSources });\n *\n * @example\n * // キャッシュを細かく指定する場合\n * const cms = createCMS({\n * dataSources,\n * cache: { document, image, ttlMs: 60_000 },\n * });\n */\nexport function createCMS<D extends DataSourceMap>(\n\topts: CreateCMSOptions<D>,\n): CMSClient<D> {\n\tif (!opts.dataSources || Object.keys(opts.dataSources).length === 0) {\n\t\tthrow new CMSError({\n\t\t\tcode: \"core/config_invalid\",\n\t\t\tmessage:\n\t\t\t\t\"createCMS: dataSources に少なくとも1つのコレクションを指定してください。\",\n\t\t\tcontext: { operation: \"createCMS\" },\n\t\t});\n\t}\n\n\t// collections が指定されたコレクションは slug が必須。\n\tfor (const [name, col] of Object.entries(opts.collections ?? {})) {\n\t\tconst c = col as CollectionSemantics | undefined;\n\t\tif (c && !c.slug) {\n\t\t\tthrow new CMSError({\n\t\t\t\tcode: \"core/config_invalid\",\n\t\t\t\tmessage: `createCMS: コレクション \"${name}\" の collections.slug は必須です。slug として使うフィールド名を指定してください。`,\n\t\t\t\tcontext: { operation: \"createCMS\", collection: name },\n\t\t\t});\n\t\t}\n\t}\n\n\tconst resolved = resolvePreset(opts);\n\n\tconst baseDocCache = resolveDocumentCache(resolved.cache);\n\tconst imgCache = resolveImageCache(resolved.cache);\n\tconst hasImageCache = hasImageCacheConfigured(resolved.cache);\n\tconst ttlMs = resolveTtl(resolved.cache);\n\tconst imageProxyBase =\n\t\topts.content?.imageProxyBase ?? DEFAULT_IMAGE_PROXY_BASE;\n\tconst contentConfig = opts.content;\n\tconst rendererFn: RendererFn | undefined = resolved.renderer;\n\tconst waitUntil = opts.waitUntil;\n\tconst logger: Logger | undefined = mergeLoggers(\n\t\topts.plugins ?? [],\n\t\topts.logger,\n\t);\n\tconst hooks: CMSHooks<BaseContentItem> = mergeHooks(\n\t\topts.plugins ?? [],\n\t\topts.hooks,\n\t\tlogger,\n\t);\n\tconst maxConcurrent = opts.rateLimiter?.maxConcurrent ?? 3;\n\tconst retryConfig: RetryConfig = {\n\t\t...DEFAULT_RETRY_CONFIG,\n\t\t...(opts.rateLimiter ?? {}),\n\t};\n\n\tconst collectionNames = Object.keys(opts.dataSources) as (keyof D & string)[];\n\n\t// biome-ignore lint/suspicious/noExplicitAny: 各 T を保持\n\tconst collections: Record<string, CollectionClient<any>> = {};\n\tfor (const name of collectionNames) {\n\t\tconst source = opts.dataSources[name] as DataSource<BaseContentItem>;\n\t\tconst scopedCache = scopeDocumentCache<BaseContentItem>(baseDocCache, name);\n\t\tconst renderCtx: RenderContext<BaseContentItem> = {\n\t\t\tsource,\n\t\t\trendererFn,\n\t\t\timgCache,\n\t\t\thasImageCache,\n\t\t\timageProxyBase,\n\t\t\tcontentConfig,\n\t\t\thooks,\n\t\t\tlogger,\n\t\t};\n\t\tconst col = opts.collections?.[name] as CollectionSemantics | undefined;\n\t\tconst ctx: CollectionContext<BaseContentItem> = {\n\t\t\tcollection: name,\n\t\t\tsource,\n\t\t\tdocCache: scopedCache,\n\t\t\trender: renderCtx,\n\t\t\thooks,\n\t\t\tlogger,\n\t\t\tttlMs,\n\t\t\t// collections で指定した値を優先し、未指定時は DataSource 側のデフォルトを使う\n\t\t\tpublishedStatuses: col?.publishedStatuses\n\t\t\t\t? [...col.publishedStatuses]\n\t\t\t\t: source.publishedStatuses\n\t\t\t\t\t? [...source.publishedStatuses]\n\t\t\t\t\t: [],\n\t\t\taccessibleStatuses: col?.accessibleStatuses\n\t\t\t\t? [...col.accessibleStatuses]\n\t\t\t\t: source.accessibleStatuses\n\t\t\t\t\t? [...source.accessibleStatuses]\n\t\t\t\t\t: [],\n\t\t\tretryConfig,\n\t\t\tmaxConcurrent,\n\t\t\twaitUntil,\n\t\t\tslugField: col?.slug,\n\t\t};\n\t\tcollections[name] = new CollectionClientImpl(ctx);\n\t}\n\n\tconst globalOps: CMSGlobalOps<D> = {\n\t\t$collections: collectionNames,\n\t\tasync $revalidate(scope?: InvalidateScope): Promise<void> {\n\t\t\tif (!baseDocCache.invalidate) return;\n\t\t\tawait baseDocCache.invalidate(scope ?? \"all\");\n\t\t},\n\t\t$handler(handlerOpts?: HandlerOptions) {\n\t\t\treturn createHandler(\n\t\t\t\t{\n\t\t\t\t\timageCache: imgCache,\n\t\t\t\t\tparseWebhook: async (req, webhookSecret) => {\n\t\t\t\t\t\t// 各 DataSource の parseWebhook を順に試す\n\t\t\t\t\t\tfor (const name of collectionNames) {\n\t\t\t\t\t\t\tconst ds = opts.dataSources[name] as DataSource<BaseContentItem>;\n\t\t\t\t\t\t\tif (ds.parseWebhook) {\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tconst scope = await ds.parseWebhook(req.clone(), {\n\t\t\t\t\t\t\t\t\t\tsecret: webhookSecret,\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\treturn scope;\n\t\t\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\t\t\tlogger?.warn?.(\"parseWebhook 失敗\", {\n\t\t\t\t\t\t\t\t\t\tcollection: name,\n\t\t\t\t\t\t\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// フォールバック: { slug } だけの汎用 JSON body\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst body = (await req.json()) as {\n\t\t\t\t\t\t\t\tslug?: string;\n\t\t\t\t\t\t\t\tcollection?: string;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tif (body.slug && body.collection) {\n\t\t\t\t\t\t\t\treturn { collection: body.collection, slug: body.slug };\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (body.collection) {\n\t\t\t\t\t\t\t\treturn { collection: body.collection };\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// ignore\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t},\n\t\t\t\t\trevalidate: (scope) => globalOps.$revalidate(scope),\n\t\t\t\t},\n\t\t\t\thandlerOpts,\n\t\t\t);\n\t\t},\n\t\t$getCachedImage(hash) {\n\t\t\treturn imgCache.get(hash);\n\t\t},\n\t};\n\n\treturn Object.assign(\n\t\tObject.create(null) as object,\n\t\tcollections,\n\t\tglobalOps,\n\t) as CMSClient<D>;\n}\n","import type { BaseContentItem } from \"./content\";\nimport type { CMSHooks } from \"./hooks\";\nimport type { Logger } from \"./logger\";\n\nexport interface CMSPlugin<T extends BaseContentItem = BaseContentItem> {\n\tname: string;\n\thooks?: CMSHooks<T>;\n\tlogger?: Partial<Logger>;\n}\n\nexport function definePlugin<T extends BaseContentItem>(\n\tplugin: CMSPlugin<T>,\n): CMSPlugin<T> {\n\treturn plugin;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/cache.ts","../src/image.ts","../src/rendering.ts","../src/retry.ts","../src/collection.ts","../src/handler.ts","../src/preset-node.ts","../src/cms.ts","../src/types/plugin.ts"],"sourcesContent":["/** 文字列をSHA-256でハッシュ化し、16進数文字列として返す。画像キーの生成に使用。 */\nexport async function sha256Hex(input: string): Promise<string> {\n\tconst data = new TextEncoder().encode(input);\n\tconst hash = await crypto.subtle.digest(\"SHA-256\", data);\n\treturn Array.from(new Uint8Array(hash))\n\t\t.map((b) => b.toString(16).padStart(2, \"0\"))\n\t\t.join(\"\");\n}\n\n/**\n * キャッシュが有効期限切れかどうかを判定する。\n * ttlMs が未指定の場合は常に false(無期限有効)を返す。\n */\nexport function isStale(cachedAt: number, ttlMs?: number): boolean {\n\tif (ttlMs === undefined) return false;\n\treturn Date.now() - cachedAt > ttlMs;\n}\n","import { sha256Hex } from \"./cache\";\nimport { CMSError, isCMSError } from \"./errors\";\nimport type { ImageCacheAdapter, StorageBinary } from \"./types/index\";\n\n/** レスポンスヘッダまたはURLの拡張子からContent-Typeを推測する。 */\nfunction inferContentType(\n\turl: string,\n\tresponseContentType: string | null,\n): string {\n\tif (responseContentType?.startsWith(\"image/\")) {\n\t\treturn responseContentType.split(\";\")[0].trim();\n\t}\n\tif (url.includes(\".png\")) return \"image/png\";\n\tif (url.includes(\".gif\")) return \"image/gif\";\n\tif (url.includes(\".webp\")) return \"image/webp\";\n\treturn \"image/jpeg\";\n}\n\n/**\n * Notion画像URLをfetchしてImageCacheAdapterにキャッシュし、プロキシURL を返す。\n * 既存キャッシュがあれば再fetchしない。\n */\nasync function fetchAndCacheImage(\n\tcache: ImageCacheAdapter,\n\tnotionUrl: string,\n\timageProxyBase: string,\n): Promise<string> {\n\tconst hash = await sha256Hex(notionUrl);\n\tconst proxyUrl = `${imageProxyBase}/${hash}`;\n\n\tconst existing = await cache.get(hash);\n\tif (existing) return proxyUrl;\n\n\ttry {\n\t\tconst response = await fetch(notionUrl, {\n\t\t\tsignal: AbortSignal.timeout(10_000),\n\t\t});\n\t\tif (!response.ok) {\n\t\t\tthrow new CMSError({\n\t\t\t\tcode: \"cache/image_fetch_failed\",\n\t\t\t\tmessage: `Failed to fetch Notion image: HTTP ${response.status}`,\n\t\t\t\tcontext: {\n\t\t\t\t\toperation: \"fetchAndCacheImage\",\n\t\t\t\t\tnotionUrl,\n\t\t\t\t\thttpStatus: response.status,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\tconst data = await response.arrayBuffer();\n\t\tconst contentType = inferContentType(\n\t\t\tnotionUrl,\n\t\t\tresponse.headers.get(\"content-type\"),\n\t\t);\n\t\tawait cache.set(hash, data, contentType);\n\t} catch (err) {\n\t\tif (isCMSError(err)) throw err;\n\t\tthrow new CMSError({\n\t\t\tcode: \"cache/io_failed\",\n\t\t\tmessage: \"Failed to fetch or cache Notion image.\",\n\t\t\tcause: err,\n\t\t\tcontext: { operation: \"fetchAndCacheImage\", notionUrl },\n\t\t});\n\t}\n\n\treturn proxyUrl;\n}\n\n/** ImageCacheAdapter と imageProxyBase から cacheImage 関数を構築するファクトリ。 */\nexport function buildCacheImageFn(\n\tcache: ImageCacheAdapter,\n\timageProxyBase: string,\n): (notionUrl: string) => Promise<string> {\n\treturn (notionUrl) => fetchAndCacheImage(cache, notionUrl, imageProxyBase);\n}\n\nexport type { StorageBinary };\n","import type { ContentBlock } from \"./content/blocks\";\nimport { CMSError, isCMSError } from \"./errors\";\nimport { buildCacheImageFn } from \"./image\";\nimport type {\n\tBaseContentItem,\n\tCachedItem,\n\tCMSHooks,\n\tContentConfig,\n\tDataSource,\n\tImageCacheAdapter,\n\tLogger,\n\tRendererFn,\n} from \"./types/index\";\n\n/** `buildCachedItem` に必要な CMS の依存を束ねたコンテキスト。 */\nexport interface RenderContext<T extends BaseContentItem> {\n\tsource: DataSource<T>;\n\trendererFn: RendererFn | undefined;\n\timgCache: ImageCacheAdapter;\n\thasImageCache: boolean;\n\timageProxyBase: string;\n\tcontentConfig: ContentConfig | undefined;\n\thooks: CMSHooks<T>;\n\tlogger: Logger | undefined;\n}\n\n/**\n * コンテンツアイテムをソースから Markdown ロード → blocks 生成 → HTML レンダリング\n * → フック適用まで実行し、キャッシュ保存用の `CachedItem` を返す。\n */\nexport async function buildCachedItem<T extends BaseContentItem>(\n\titem: T,\n\tctx: RenderContext<T>,\n): Promise<CachedItem<T>> {\n\tconst start = Date.now();\n\tctx.logger?.info?.(\"コンテンツのレンダリング開始\", {\n\t\tslug: item.slug,\n\t\tpageId: item.id,\n\t});\n\tctx.hooks.onRenderStart?.(item.slug);\n\n\tlet markdown: string;\n\ttry {\n\t\tmarkdown = await ctx.source.loadMarkdown(item);\n\t} catch (err) {\n\t\tif (isCMSError(err)) throw err;\n\t\tthrow new CMSError({\n\t\t\tcode: \"source/load_markdown_failed\",\n\t\t\tmessage: \"Failed to load markdown from source.\",\n\t\t\tcause: err,\n\t\t\tcontext: {\n\t\t\t\toperation: \"buildCachedItem:loadMarkdown\",\n\t\t\t\tpageId: item.id,\n\t\t\t\tslug: item.slug,\n\t\t\t},\n\t\t});\n\t}\n\n\tlet blocks: ContentBlock[] = [];\n\ttry {\n\t\tblocks = await ctx.source.loadBlocks(item);\n\t} catch (err) {\n\t\tctx.logger?.warn?.(\"loadBlocks に失敗したため raw フォールバック\", {\n\t\t\tslug: item.slug,\n\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t});\n\t\tblocks = [];\n\t}\n\n\tconst cacheImage = ctx.hasImageCache\n\t\t? buildCacheImageFn(ctx.imgCache, ctx.imageProxyBase)\n\t\t: undefined;\n\n\tlet html: string;\n\tconst rendererFn = ctx.rendererFn ?? (await loadDefaultRenderer());\n\ttry {\n\t\thtml = await rendererFn(markdown, {\n\t\t\timageProxyBase: ctx.imageProxyBase,\n\t\t\tcacheImage,\n\t\t\tremarkPlugins: ctx.contentConfig?.remarkPlugins,\n\t\t\trehypePlugins: ctx.contentConfig?.rehypePlugins,\n\t\t});\n\t} catch (err) {\n\t\tif (isCMSError(err)) throw err;\n\t\tthrow new CMSError({\n\t\t\tcode: \"renderer/failed\",\n\t\t\tmessage: \"Failed to render markdown.\",\n\t\t\tcause: err,\n\t\t\tcontext: {\n\t\t\t\toperation: \"buildCachedItem:renderMarkdown\",\n\t\t\t\tpageId: item.id,\n\t\t\t\tslug: item.slug,\n\t\t\t},\n\t\t});\n\t}\n\n\tif (ctx.hooks.afterRender) {\n\t\thtml = await ctx.hooks.afterRender(html, item);\n\t}\n\n\tlet result: CachedItem<T> = {\n\t\thtml,\n\t\tblocks,\n\t\tmarkdown,\n\t\titem,\n\t\tnotionUpdatedAt: ctx.source.getLastModified(item),\n\t\tcachedAt: Date.now(),\n\t};\n\n\tif (ctx.hooks.beforeCache) {\n\t\tresult = (await ctx.hooks.beforeCache(result)) as CachedItem<T>;\n\t}\n\n\tconst durationMs = Date.now() - start;\n\tctx.logger?.info?.(\"コンテンツのレンダリング完了\", {\n\t\tslug: item.slug,\n\t\tdurationMs,\n\t});\n\tctx.hooks.onRenderEnd?.(item.slug, durationMs);\n\n\treturn result;\n}\n\n/**\n * renderer オプション未指定時のフォールバック。\n * @notion-headless-cms/renderer を動的 import する。\n * createCMS({ renderer }) で明示注入された場合はこのパスを通らない。\n */\nexport async function loadDefaultRenderer(): Promise<RendererFn> {\n\ttry {\n\t\tconst mod = await import(\"@notion-headless-cms/renderer\");\n\t\treturn mod.renderMarkdown as RendererFn;\n\t} catch (err) {\n\t\tthrow new CMSError({\n\t\t\tcode: \"renderer/failed\",\n\t\t\tmessage:\n\t\t\t\t\"renderer オプションが未指定で @notion-headless-cms/renderer が見つかりません。\" +\n\t\t\t\t\" createCMS({ renderer }) でレンダラーを注入するか、@notion-headless-cms/renderer をインストールしてください。\",\n\t\t\tcause: err,\n\t\t\tcontext: { operation: \"loadDefaultRenderer\" },\n\t\t});\n\t}\n}\n","export interface RetryConfig {\n\tretryOn: number[];\n\tmaxRetries: number;\n\tbaseDelayMs: number;\n\t/** true のとき指数バックオフにランダムジッターを加える(Thundering Herd 対策)。デフォルト: true */\n\tjitter?: boolean;\n\tonRetry?: (attempt: number, status: number) => void;\n}\n\nexport const DEFAULT_RETRY_CONFIG: RetryConfig = {\n\tretryOn: [429, 502, 503],\n\tmaxRetries: 4,\n\tbaseDelayMs: 1000,\n\tjitter: true,\n};\n\n/** 指数バックオフ(オプションでジッター付き)でリトライする。retryOn に含まれる HTTP エラーのみ対象。 */\nexport async function withRetry<T>(\n\tfn: () => Promise<T>,\n\tconfig: RetryConfig,\n): Promise<T> {\n\tlet lastError: unknown;\n\tfor (let attempt = 0; attempt <= config.maxRetries; attempt++) {\n\t\ttry {\n\t\t\treturn await fn();\n\t\t} catch (err) {\n\t\t\tconst status = (err as { status?: number }).status;\n\t\t\tif (status === undefined || !config.retryOn.includes(status)) {\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t\tlastError = err;\n\t\t\tif (attempt < config.maxRetries) {\n\t\t\t\tconfig.onRetry?.(attempt + 1, status);\n\t\t\t\tconst jitterFactor =\n\t\t\t\t\tconfig.jitter !== false ? 0.5 + Math.random() * 0.5 : 1;\n\t\t\t\tconst delay = config.baseDelayMs * 2 ** attempt * jitterFactor;\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, delay));\n\t\t\t}\n\t\t}\n\t}\n\tthrow lastError;\n}\n","import { isStale } from \"./cache\";\nimport type { ContentBlock, ContentResult } from \"./content/blocks\";\nimport type { RenderContext } from \"./rendering\";\nimport { buildCachedItem } from \"./rendering\";\nimport type { RetryConfig } from \"./retry\";\nimport { withRetry } from \"./retry\";\nimport type {\n\tAdjacencyOptions,\n\tBaseContentItem,\n\tCachedItem,\n\tCMSHooks,\n\tCollectionClient,\n\tDataSource,\n\tDocumentCacheAdapter,\n\tGetListOptions,\n\tItemWithContent,\n\tLogger,\n\tSortOption,\n} from \"./types/index\";\n\n/**\n * コレクション別キャッシュキーを生成する。\n * item: `{collection}:{slug}` / list: `{collection}`\n */\nexport function collectionKey(collection: string, slug?: string): string {\n\treturn slug ? `${collection}:${slug}` : collection;\n}\n\n/** 単一コレクションの DataSource + SWR キャッシュ依存を束ねたコンテキスト。 */\nexport interface CollectionContext<T extends BaseContentItem> {\n\tcollection: string;\n\tsource: DataSource<T>;\n\tdocCache: DocumentCacheAdapter<T>;\n\trender: RenderContext<T>;\n\thooks: CMSHooks<T>;\n\tlogger: Logger | undefined;\n\tttlMs: number | undefined;\n\tpublishedStatuses: string[];\n\taccessibleStatuses: string[];\n\tretryConfig: RetryConfig;\n\tmaxConcurrent: number;\n\twaitUntil: ((p: Promise<unknown>) => void) | undefined;\n\t/**\n\t * slug として使うフィールド名。\n\t * `createCMS({ collections })` で指定した値。\n\t * 設定時は `source.properties[slugField].notion` を Notion プロパティ名として\n\t * `findByProp` を呼び出す。\n\t */\n\tslugField?: string;\n}\n\n/** CollectionClient の実装。ユーザーは `createCMS` 経由でインスタンスを受け取る。 */\nexport class CollectionClientImpl<T extends BaseContentItem>\n\timplements CollectionClient<T>\n{\n\tconstructor(private readonly ctx: CollectionContext<T>) {}\n\n\t// ── 基本取得 ──────────────────────────────────────────────────────────\n\n\tasync getItem(slug: string): Promise<ItemWithContent<T> | null> {\n\t\tconst cached = await this.ctx.docCache.getItem(slug);\n\t\tif (cached && !isStale(cached.cachedAt, this.ctx.ttlMs)) {\n\t\t\tthis.ctx.hooks.onCacheHit?.(slug, cached);\n\t\t\treturn this.attachContent(cached.item, cached);\n\t\t}\n\n\t\tthis.ctx.hooks.onCacheMiss?.(slug);\n\t\tconst item = await this.findRaw(slug);\n\t\tif (!item) return null;\n\n\t\tconst entry = await buildCachedItem(item, this.ctx.render);\n\t\tconst save = this.ctx.docCache.setItem(slug, entry);\n\t\tif (this.ctx.waitUntil) {\n\t\t\tthis.ctx.waitUntil(save);\n\t\t} else {\n\t\t\tawait save;\n\t\t}\n\n\t\treturn this.attachContent(entry.item, entry);\n\t}\n\n\tasync getList(opts?: GetListOptions<T>): Promise<T[]> {\n\t\tconst items = await this.fetchList();\n\t\treturn applyGetListOptions(items, opts);\n\t}\n\n\t// ── SSG / ナビゲーション ─────────────────────────────────────────────\n\n\tasync getStaticParams(): Promise<{ slug: string }[]> {\n\t\tconst items = await this.fetchList();\n\t\treturn items.map((item) => ({ slug: item.slug }));\n\t}\n\n\tasync getStaticPaths(): Promise<string[]> {\n\t\tconst items = await this.fetchList();\n\t\treturn items.map((item) => item.slug);\n\t}\n\n\tasync adjacent(\n\t\tslug: string,\n\t\topts?: AdjacencyOptions<T>,\n\t): Promise<{ prev: T | null; next: T | null }> {\n\t\tconst items = applyGetListOptions(await this.fetchList(), {\n\t\t\tsort: opts?.sort,\n\t\t});\n\t\tconst index = items.findIndex((it) => it.slug === slug);\n\t\tif (index === -1) return { prev: null, next: null };\n\t\treturn {\n\t\t\tprev: index > 0 ? (items[index - 1] ?? null) : null,\n\t\t\tnext: index < items.length - 1 ? (items[index + 1] ?? null) : null,\n\t\t};\n\t}\n\n\t// ── キャッシュ ────────────────────────────────────────────────────────\n\n\tasync revalidate(scope?: \"all\" | { slug: string }): Promise<void> {\n\t\tif (!this.ctx.docCache.invalidate) return;\n\t\tif (scope === undefined || scope === \"all\") {\n\t\t\tawait this.ctx.docCache.invalidate({ collection: this.ctx.collection });\n\t\t} else {\n\t\t\tawait this.ctx.docCache.invalidate({\n\t\t\t\tcollection: this.ctx.collection,\n\t\t\t\tslug: scope.slug,\n\t\t\t});\n\t\t}\n\t}\n\n\tasync prefetch(opts?: {\n\t\tconcurrency?: number;\n\t\tonProgress?: (done: number, total: number) => void;\n\t}): Promise<{ ok: number; failed: number }> {\n\t\tconst items = await this.fetchListRaw();\n\t\tconst concurrency = opts?.concurrency ?? this.ctx.maxConcurrent;\n\t\tlet ok = 0;\n\t\tlet failed = 0;\n\n\t\tfor (let i = 0; i < items.length; i += concurrency) {\n\t\t\tconst chunk = items.slice(i, i + concurrency);\n\t\t\tawait Promise.all(\n\t\t\t\tchunk.map(async (item) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst rendered = await buildCachedItem(item, this.ctx.render);\n\t\t\t\t\t\tawait this.ctx.docCache.setItem(item.slug, rendered);\n\t\t\t\t\t\tok++;\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tfailed++;\n\t\t\t\t\t\tthis.ctx.logger?.warn?.(\n\t\t\t\t\t\t\t\"prefetch: アイテムの事前レンダリングに失敗\",\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tslug: item.slug,\n\t\t\t\t\t\t\t\tpageId: item.id,\n\t\t\t\t\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t);\n\t\t\topts?.onProgress?.(Math.min(i + concurrency, items.length), items.length);\n\t\t}\n\n\t\tawait this.ctx.docCache.setList({ items, cachedAt: Date.now() });\n\t\treturn { ok, failed };\n\t}\n\n\t// ── 内部 ──────────────────────────────────────────────────────────────\n\n\tprivate attachContent(item: T, cached: CachedItem<T>): ItemWithContent<T> {\n\t\tconst ctx = this.ctx;\n\t\tlet blocksCache: ContentBlock[] | undefined;\n\t\tlet htmlCache: string | undefined = cached.html;\n\t\tlet markdownCache: string | undefined;\n\n\t\tconst content: ContentResult = {\n\t\t\tget blocks(): ContentBlock[] {\n\t\t\t\tif (!blocksCache) {\n\t\t\t\t\t// lazy: キャッシュに blocks が保存されていない場合、簡易な single-raw に落とす\n\t\t\t\t\tblocksCache = [\n\t\t\t\t\t\t{ type: \"raw\", html: cached.html } satisfies ContentBlock,\n\t\t\t\t\t];\n\t\t\t\t}\n\t\t\t\treturn blocksCache;\n\t\t\t},\n\t\t\tasync html(): Promise<string> {\n\t\t\t\tif (htmlCache !== undefined) return htmlCache;\n\t\t\t\thtmlCache = cached.html;\n\t\t\t\treturn htmlCache;\n\t\t\t},\n\t\t\tasync markdown(): Promise<string> {\n\t\t\t\tif (markdownCache !== undefined) return markdownCache;\n\t\t\t\tmarkdownCache = await ctx.source.loadMarkdown(item);\n\t\t\t\treturn markdownCache;\n\t\t\t},\n\t\t};\n\n\t\tif (cached.blocks) blocksCache = cached.blocks;\n\n\t\treturn Object.assign(Object.create(null) as object, item, {\n\t\t\tcontent,\n\t\t}) as ItemWithContent<T>;\n\t}\n\n\tprivate async fetchList(): Promise<T[]> {\n\t\tconst cached = await this.ctx.docCache.getList();\n\t\tif (cached && !isStale(cached.cachedAt, this.ctx.ttlMs)) {\n\t\t\tthis.ctx.hooks.onListCacheHit?.(cached.items, cached.cachedAt);\n\t\t\treturn cached.items;\n\t\t}\n\n\t\tthis.ctx.hooks.onListCacheMiss?.();\n\t\tconst items = await this.fetchListRaw();\n\t\tconst cachedAt = Date.now();\n\t\tconst save = this.ctx.docCache.setList({ items, cachedAt });\n\t\tif (this.ctx.waitUntil) {\n\t\t\tthis.ctx.waitUntil(save);\n\t\t} else {\n\t\t\tawait save;\n\t\t}\n\t\treturn items;\n\t}\n\n\tprivate fetchListRaw(): Promise<T[]> {\n\t\treturn withRetry(\n\t\t\t() =>\n\t\t\t\tthis.ctx.source.list({\n\t\t\t\t\tpublishedStatuses:\n\t\t\t\t\t\tthis.ctx.publishedStatuses.length > 0\n\t\t\t\t\t\t\t? this.ctx.publishedStatuses\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t}),\n\t\t\t{\n\t\t\t\t...this.ctx.retryConfig,\n\t\t\t\tonRetry: (attempt, status) => {\n\t\t\t\t\tthis.ctx.logger?.warn?.(\"getList() リトライ中\", { attempt, status });\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\t}\n\n\tprivate async findRaw(slug: string): Promise<T | null> {\n\t\tconst retryOpts = {\n\t\t\t...this.ctx.retryConfig,\n\t\t\tonRetry: (attempt: number, status: number) => {\n\t\t\t\tthis.ctx.logger?.warn?.(\"getItem() リトライ中\", {\n\t\t\t\t\tattempt,\n\t\t\t\t\tstatus,\n\t\t\t\t\tslug,\n\t\t\t\t});\n\t\t\t},\n\t\t};\n\n\t\t// slug フィールドが指定され、DataSource が findByProp を持つ場合は\n\t\t// Notion プロパティ名を解決して効率的なフィルタクエリを実行する。\n\t\tconst slugField = this.ctx.slugField;\n\t\tconst notionPropName = slugField\n\t\t\t? this.ctx.source.properties?.[slugField]?.notion\n\t\t\t: undefined;\n\n\t\tlet item: T | null;\n\t\tconst findByProp = this.ctx.source.findByProp?.bind(this.ctx.source);\n\t\tif (notionPropName && findByProp) {\n\t\t\titem = await withRetry(() => findByProp(notionPropName, slug), retryOpts);\n\t\t} else {\n\t\t\t// フォールバック: list して線形探索\n\t\t\tconst all = await withRetry(() => this.ctx.source.list(), retryOpts);\n\t\t\titem = all.find((i) => i.slug === slug) ?? null;\n\t\t}\n\n\t\tif (!item) return null;\n\t\tif (\n\t\t\tthis.ctx.accessibleStatuses.length > 0 &&\n\t\t\t(!item.status || !this.ctx.accessibleStatuses.includes(item.status))\n\t\t) {\n\t\t\treturn null;\n\t\t}\n\t\treturn item;\n\t}\n}\n\nfunction applyGetListOptions<T extends BaseContentItem>(\n\titems: T[],\n\topts?: GetListOptions<T>,\n): T[] {\n\tif (!opts) return items;\n\tlet result = items;\n\n\tif (opts.statuses && opts.statuses.length > 0) {\n\t\tconst allow = new Set(opts.statuses);\n\t\tresult = result.filter(\n\t\t\t(it) => it.status !== undefined && allow.has(it.status),\n\t\t);\n\t}\n\n\tif (opts.tag) {\n\t\tconst tag = opts.tag;\n\t\tresult = result.filter((it) => {\n\t\t\tconst tags = (it as unknown as { tags?: unknown }).tags;\n\t\t\treturn Array.isArray(tags) && tags.includes(tag);\n\t\t});\n\t}\n\n\tif (opts.where) {\n\t\tconst where = opts.where;\n\t\tresult = result.filter((it) =>\n\t\t\tObject.entries(where).every(\n\t\t\t\t([key, value]) => (it as Record<string, unknown>)[key] === value,\n\t\t\t),\n\t\t);\n\t}\n\n\tif (opts.sort) {\n\t\tresult = [...result].sort(makeComparator(opts.sort));\n\t}\n\n\tconst skip = opts.skip ?? 0;\n\tconst limit = opts.limit;\n\tif (skip > 0 || limit !== undefined) {\n\t\tresult = result.slice(skip, limit !== undefined ? skip + limit : undefined);\n\t}\n\n\treturn result;\n}\n\nfunction makeComparator<T extends BaseContentItem>(\n\tsort: SortOption<T>,\n): (a: T, b: T) => number {\n\tconst by = sort.by;\n\tconst dir = sort.direction === \"asc\" ? 1 : -1;\n\treturn (a, b) => {\n\t\tconst av = (a as Record<string, unknown>)[by];\n\t\tconst bv = (b as Record<string, unknown>)[by];\n\t\tif (av === bv) return 0;\n\t\tif (av === undefined) return 1;\n\t\tif (bv === undefined) return -1;\n\t\t// biome-ignore lint/suspicious/noExplicitAny: 汎用比較\n\t\treturn (av as any) > (bv as any) ? dir : -dir;\n\t};\n}\n","import type { ImageCacheAdapter, InvalidateScope } from \"./types/index\";\n\n/** `$handler()` の挙動設定。 */\nexport interface HandlerOptions {\n\t/** マウントするベースパス。デフォルト `/api/cms`。 */\n\tbasePath?: string;\n\t/** 画像プロキシのパス (basePath 相対)。デフォルト `/images/:hash`。 */\n\timagesPath?: string;\n\t/** revalidate webhook のパス (basePath 相対)。デフォルト `/revalidate`。 */\n\trevalidatePath?: string;\n\t/** Webhook 署名検証用シークレット (未指定なら検証スキップ)。 */\n\twebhookSecret?: string;\n\t/** デフォルト実装を無効化する場合 true。 */\n\tdisabled?: boolean;\n}\n\n/** `$handler()` が内部で依存する CMS 機能の最小セット。 */\nexport interface HandlerAdapter {\n\timageCache: ImageCacheAdapter;\n\t/** コレクション名で DataSource を取り出し parseWebhook にフォワードする。 */\n\tparseWebhook(\n\t\treq: Request,\n\t\twebhookSecret: string | undefined,\n\t): Promise<InvalidateScope | null>;\n\trevalidate(scope: InvalidateScope): Promise<void>;\n}\n\nconst DEFAULT_OPTS = {\n\tbasePath: \"/api/cms\",\n\timagesPath: \"/images\",\n\trevalidatePath: \"/revalidate\",\n} as const;\n\n/**\n * Web Standard な Request → Response ルーター。\n * Next.js / React Router / Hono / Cloudflare Workers いずれでも使える。\n *\n * ルート:\n * - GET `{basePath}/images/:hash` — 画像プロキシ\n * - POST `{basePath}/revalidate` — Webhook 受信 + $revalidate()\n */\nexport function createHandler(\n\tadapter: HandlerAdapter,\n\topts: HandlerOptions = {},\n): (req: Request) => Promise<Response> {\n\tconst basePath = trimTrailingSlash(opts.basePath ?? DEFAULT_OPTS.basePath);\n\tconst imagesPath = opts.imagesPath ?? DEFAULT_OPTS.imagesPath;\n\tconst revalidatePath = opts.revalidatePath ?? DEFAULT_OPTS.revalidatePath;\n\n\treturn async (req: Request): Promise<Response> => {\n\t\tconst url = new URL(req.url);\n\t\tconst path = url.pathname;\n\n\t\tif (!path.startsWith(basePath)) {\n\t\t\treturn new Response(\"Not Found\", { status: 404 });\n\t\t}\n\t\tconst rel = path.slice(basePath.length) || \"/\";\n\n\t\t// 画像: GET {basePath}/images/:hash\n\t\tif (req.method === \"GET\" && rel.startsWith(`${imagesPath}/`)) {\n\t\t\tconst hash = rel.slice(imagesPath.length + 1);\n\t\t\tif (!hash) return new Response(\"Bad Request\", { status: 400 });\n\t\t\tconst object = await adapter.imageCache.get(hash);\n\t\t\tif (!object) return new Response(\"Not Found\", { status: 404 });\n\t\t\tconst headers = new Headers();\n\t\t\tif (object.contentType) headers.set(\"content-type\", object.contentType);\n\t\t\theaders.set(\"cache-control\", \"public, max-age=31536000, immutable\");\n\t\t\treturn new Response(object.data, { headers });\n\t\t}\n\n\t\t// Revalidate: POST {basePath}/revalidate\n\t\tif (req.method === \"POST\" && rel === revalidatePath) {\n\t\t\tconst scope = await adapter.parseWebhook(req, opts.webhookSecret);\n\t\t\tif (!scope) {\n\t\t\t\treturn new Response(JSON.stringify({ ok: false, reason: \"invalid\" }), {\n\t\t\t\t\tstatus: 400,\n\t\t\t\t\theaders: { \"content-type\": \"application/json\" },\n\t\t\t\t});\n\t\t\t}\n\t\t\tawait adapter.revalidate(scope);\n\t\t\treturn new Response(JSON.stringify({ ok: true, scope }), {\n\t\t\t\tstatus: 200,\n\t\t\t\theaders: { \"content-type\": \"application/json\" },\n\t\t\t});\n\t\t}\n\n\t\treturn new Response(\"Not Found\", { status: 404 });\n\t};\n}\n\nfunction trimTrailingSlash(s: string): string {\n\treturn s.endsWith(\"/\") ? s.slice(0, -1) : s;\n}\n","import { memoryDocumentCache, memoryImageCache } from \"./cache/memory\";\nimport type { CacheConfig, CreateCMSOptions, RendererFn } from \"./types/index\";\n\n/** `nodePreset()` のオプション。 */\nexport interface NodePresetOptions {\n\t/**\n\t * キャッシュ設定。\n\t * - 省略時: memoryDocumentCache + memoryImageCache をデフォルト有効化\n\t * - `\"disabled\"`: キャッシュを完全無効化\n\t * - オブジェクト: 任意の cache adapter を差し込む\n\t */\n\tcache?: CacheConfig | \"disabled\";\n\t/** SWR の TTL (ミリ秒)。`cache` をオブジェクトで渡した場合はそちらが優先される。 */\n\tttlMs?: number;\n\t/** カスタムレンダラー。未指定時は core が @notion-headless-cms/renderer を動的ロード。 */\n\trenderer?: RendererFn;\n}\n\n/**\n * Node.js ランタイム向けの `createCMS` オプションプリセット。\n * メモリキャッシュをデフォルト有効にした `{ cache, renderer }` を返す。\n *\n * @example\n * import { createCMS, nodePreset } from \"@notion-headless-cms/core\";\n * import { cmsDataSources } from \"./generated/cms-schema\";\n *\n * const cms = createCMS({\n * ...nodePreset({ ttlMs: 5 * 60_000 }),\n * dataSources: cmsDataSources,\n * });\n */\nexport function nodePreset(\n\topts: NodePresetOptions = {},\n): Pick<CreateCMSOptions, \"cache\" | \"renderer\"> {\n\tif (opts.cache === \"disabled\") {\n\t\treturn { cache: undefined, renderer: opts.renderer };\n\t}\n\treturn {\n\t\tcache: opts.cache ?? {\n\t\t\tdocument: memoryDocumentCache(),\n\t\t\timage: memoryImageCache(),\n\t\t\tttlMs: opts.ttlMs,\n\t\t},\n\t\trenderer: opts.renderer,\n\t};\n}\n","import { noopDocumentCache, noopImageCache } from \"./cache/noop\";\nimport { CollectionClientImpl, type CollectionContext } from \"./collection\";\nimport { CMSError } from \"./errors\";\nimport { createHandler, type HandlerOptions } from \"./handler\";\nimport { mergeHooks, mergeLoggers } from \"./hooks\";\nimport { nodePreset } from \"./preset-node\";\nimport type { RenderContext } from \"./rendering\";\nimport type { RetryConfig } from \"./retry\";\nimport { DEFAULT_RETRY_CONFIG } from \"./retry\";\nimport type {\n\tBaseContentItem,\n\tCacheConfig,\n\tCMSHooks,\n\tCollectionClient,\n\tCollectionSemantics,\n\tCreateCMSOptions,\n\tDataSource,\n\tDataSourceMap,\n\tDocumentCacheAdapter,\n\tImageCacheAdapter,\n\tInferDataSourceItem,\n\tInvalidateScope,\n\tLogger,\n\tRendererFn,\n} from \"./types/index\";\n\nconst DEFAULT_IMAGE_PROXY_BASE = \"/api/images\";\n\n/** `CMSClient<D>` — コレクション別アクセス + グローバル操作の合成型。 */\nexport type CMSClient<D extends DataSourceMap> = {\n\t[K in keyof D]: CollectionClient<InferDataSourceItem<D[K]>>;\n} & CMSGlobalOps<D>;\n\n/** `CMSClient` のグローバル名前空間。`$` プレフィックス。 */\nexport interface CMSGlobalOps<D extends DataSourceMap> {\n\t/** 登録されているコレクション名の一覧。 */\n\treadonly $collections: readonly (keyof D & string)[];\n\t/** 全コレクションまたは特定コレクションのキャッシュを無効化する。 */\n\t$revalidate(scope?: InvalidateScope): Promise<void>;\n\t/** Web Standard なルーティングハンドラ (画像プロキシ / webhook) を生成する。 */\n\t$handler(opts?: HandlerOptions): (req: Request) => Promise<Response>;\n\t/** ハッシュキーでキャッシュ画像を取得する。 */\n\t$getCachedImage(hash: string): ReturnType<ImageCacheAdapter[\"get\"]>;\n}\n\nfunction resolveDocumentCache(\n\tcache: CacheConfig | undefined,\n\t// biome-ignore lint/suspicious/noExplicitAny: 横断的に利用\n): DocumentCacheAdapter<any> {\n\tif (!cache || cache === \"disabled\" || !cache.document) {\n\t\treturn noopDocumentCache();\n\t}\n\treturn cache.document;\n}\n\nfunction resolveImageCache(cache: CacheConfig | undefined): ImageCacheAdapter {\n\tif (!cache || cache === \"disabled\" || !cache.image) {\n\t\treturn noopImageCache();\n\t}\n\treturn cache.image;\n}\n\nfunction resolveTtl(cache: CacheConfig | undefined): number | undefined {\n\tif (!cache || cache === \"disabled\") return undefined;\n\treturn cache.ttlMs;\n}\n\nfunction hasImageCacheConfigured(cache: CacheConfig | undefined): boolean {\n\tif (!cache || cache === \"disabled\") return false;\n\treturn !!cache.image;\n}\n\n/**\n * `{collection}:{slug}` キー空間で動作するコレクション別キャッシュビューを生成する。\n * 単一の `DocumentCacheAdapter` に複数コレクションを同居させるためのアダプタ。\n */\nfunction scopeDocumentCache<T extends BaseContentItem>(\n\t// biome-ignore lint/suspicious/noExplicitAny: 共有ストレージのため\n\tbase: DocumentCacheAdapter<any>,\n\tcollection: string,\n): DocumentCacheAdapter<T> {\n\tconst itemKey = (slug: string): string => `${collection}:${slug}`;\n\n\treturn {\n\t\tname: `${base.name}@${collection}`,\n\t\tgetList: () => base.getList(),\n\t\tsetList: (data) => base.setList(data),\n\t\tgetItem: (slug) => base.getItem(itemKey(slug)),\n\t\tsetItem: (slug, data) => base.setItem(itemKey(slug), data),\n\t\tasync invalidate(scope) {\n\t\t\tif (!base.invalidate) return;\n\t\t\tif (scope === \"all\") {\n\t\t\t\treturn base.invalidate({ collection });\n\t\t\t}\n\t\t\treturn base.invalidate(scope);\n\t\t},\n\t};\n}\n\n/**\n * `preset` オプションを解決して `cache` / `renderer` のデフォルトを補完する内部関数。\n * 明示的な `cache` / `renderer` がある場合はそちらが優先される。\n * `preset` 未指定時は opts をそのまま返す。\n */\nfunction resolvePreset<D extends DataSourceMap>(\n\topts: CreateCMSOptions<D>,\n): CreateCMSOptions<D> {\n\tif (opts.preset === \"disabled\") {\n\t\treturn { ...opts, cache: undefined };\n\t}\n\tif (opts.preset === \"node\") {\n\t\tconst presetResult = nodePreset({ ttlMs: opts.ttlMs });\n\t\treturn {\n\t\t\t...opts,\n\t\t\tcache: opts.cache ?? presetResult.cache,\n\t\t\trenderer: opts.renderer ?? presetResult.renderer,\n\t\t};\n\t}\n\treturn opts;\n}\n\n/**\n * 複数の DataSource を束ねた CMS クライアントを生成する。\n *\n * @example\n * // Node.js(preset を使った簡潔な記法)\n * const cms = createCMS({ dataSources: cmsDataSources, preset: \"node\", ttlMs: 5 * 60_000 });\n *\n * @example\n * // 従来の spread パターン(引き続き動作する)\n * const cms = createCMS({ ...nodePreset({ ttlMs: 5 * 60_000 }), dataSources: cmsDataSources });\n *\n * @example\n * // キャッシュを細かく指定する場合\n * const cms = createCMS({\n * dataSources,\n * cache: { document, image, ttlMs: 60_000 },\n * });\n */\nexport function createCMS<D extends DataSourceMap>(\n\topts: CreateCMSOptions<D>,\n): CMSClient<D> {\n\tif (!opts.dataSources || Object.keys(opts.dataSources).length === 0) {\n\t\tthrow new CMSError({\n\t\t\tcode: \"core/config_invalid\",\n\t\t\tmessage:\n\t\t\t\t\"createCMS: dataSources に少なくとも1つのコレクションを指定してください。\",\n\t\t\tcontext: { operation: \"createCMS\" },\n\t\t});\n\t}\n\n\t// collections が指定されたコレクションは slug が必須。\n\tfor (const [name, col] of Object.entries(opts.collections ?? {})) {\n\t\tconst c = col as CollectionSemantics | undefined;\n\t\tif (c && !c.slug) {\n\t\t\tthrow new CMSError({\n\t\t\t\tcode: \"core/config_invalid\",\n\t\t\t\tmessage: `createCMS: コレクション \"${name}\" の collections.slug は必須です。slug として使うフィールド名を指定してください。`,\n\t\t\t\tcontext: { operation: \"createCMS\", collection: name },\n\t\t\t});\n\t\t}\n\t}\n\n\tconst resolved = resolvePreset(opts);\n\n\tconst baseDocCache = resolveDocumentCache(resolved.cache);\n\tconst imgCache = resolveImageCache(resolved.cache);\n\tconst hasImageCache = hasImageCacheConfigured(resolved.cache);\n\tconst ttlMs = resolveTtl(resolved.cache);\n\tconst imageProxyBase =\n\t\topts.content?.imageProxyBase ?? DEFAULT_IMAGE_PROXY_BASE;\n\tconst contentConfig = opts.content;\n\tconst rendererFn: RendererFn | undefined = resolved.renderer;\n\tconst waitUntil = opts.waitUntil;\n\tconst logger: Logger | undefined = mergeLoggers(\n\t\topts.plugins ?? [],\n\t\topts.logger,\n\t);\n\tconst hooks: CMSHooks<BaseContentItem> = mergeHooks(\n\t\topts.plugins ?? [],\n\t\topts.hooks,\n\t\tlogger,\n\t);\n\tconst maxConcurrent = opts.rateLimiter?.maxConcurrent ?? 3;\n\tconst retryConfig: RetryConfig = {\n\t\t...DEFAULT_RETRY_CONFIG,\n\t\t...(opts.rateLimiter ?? {}),\n\t};\n\n\tconst collectionNames = Object.keys(opts.dataSources) as (keyof D & string)[];\n\n\t// biome-ignore lint/suspicious/noExplicitAny: 各 T を保持\n\tconst collections: Record<string, CollectionClient<any>> = {};\n\tfor (const name of collectionNames) {\n\t\tconst source = opts.dataSources[name] as DataSource<BaseContentItem>;\n\t\tconst scopedCache = scopeDocumentCache<BaseContentItem>(baseDocCache, name);\n\t\tconst renderCtx: RenderContext<BaseContentItem> = {\n\t\t\tsource,\n\t\t\trendererFn,\n\t\t\timgCache,\n\t\t\thasImageCache,\n\t\t\timageProxyBase,\n\t\t\tcontentConfig,\n\t\t\thooks,\n\t\t\tlogger,\n\t\t};\n\t\tconst col = opts.collections?.[name] as CollectionSemantics | undefined;\n\t\tconst ctx: CollectionContext<BaseContentItem> = {\n\t\t\tcollection: name,\n\t\t\tsource,\n\t\t\tdocCache: scopedCache,\n\t\t\trender: renderCtx,\n\t\t\thooks,\n\t\t\tlogger,\n\t\t\tttlMs,\n\t\t\t// 公開条件は CollectionSemantics(createCMS の collections オプション)が権威\n\t\t\tpublishedStatuses: col?.publishedStatuses\n\t\t\t\t? [...col.publishedStatuses]\n\t\t\t\t: [],\n\t\t\taccessibleStatuses: col?.accessibleStatuses\n\t\t\t\t? [...col.accessibleStatuses]\n\t\t\t\t: [],\n\t\t\tretryConfig,\n\t\t\tmaxConcurrent,\n\t\t\twaitUntil,\n\t\t\tslugField: col?.slug,\n\t\t};\n\t\tcollections[name] = new CollectionClientImpl(ctx);\n\t}\n\n\tconst globalOps: CMSGlobalOps<D> = {\n\t\t$collections: collectionNames,\n\t\tasync $revalidate(scope?: InvalidateScope): Promise<void> {\n\t\t\tif (!baseDocCache.invalidate) return;\n\t\t\tawait baseDocCache.invalidate(scope ?? \"all\");\n\t\t},\n\t\t$handler(handlerOpts?: HandlerOptions) {\n\t\t\treturn createHandler(\n\t\t\t\t{\n\t\t\t\t\timageCache: imgCache,\n\t\t\t\t\tparseWebhook: async (req, webhookSecret) => {\n\t\t\t\t\t\t// 各 DataSource の parseWebhook を順に試す\n\t\t\t\t\t\tfor (const name of collectionNames) {\n\t\t\t\t\t\t\tconst ds = opts.dataSources[name] as DataSource<BaseContentItem>;\n\t\t\t\t\t\t\tif (ds.parseWebhook) {\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tconst scope = await ds.parseWebhook(req.clone(), {\n\t\t\t\t\t\t\t\t\t\tsecret: webhookSecret,\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\treturn scope;\n\t\t\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\t\t\tlogger?.warn?.(\"parseWebhook 失敗\", {\n\t\t\t\t\t\t\t\t\t\tcollection: name,\n\t\t\t\t\t\t\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// フォールバック: { slug } だけの汎用 JSON body\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst body = (await req.json()) as {\n\t\t\t\t\t\t\t\tslug?: string;\n\t\t\t\t\t\t\t\tcollection?: string;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tif (body.slug && body.collection) {\n\t\t\t\t\t\t\t\treturn { collection: body.collection, slug: body.slug };\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (body.collection) {\n\t\t\t\t\t\t\t\treturn { collection: body.collection };\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// ignore\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t},\n\t\t\t\t\trevalidate: (scope) => globalOps.$revalidate(scope),\n\t\t\t\t},\n\t\t\t\thandlerOpts,\n\t\t\t);\n\t\t},\n\t\t$getCachedImage(hash) {\n\t\t\treturn imgCache.get(hash);\n\t\t},\n\t};\n\n\treturn Object.assign(\n\t\tObject.create(null) as object,\n\t\tcollections,\n\t\tglobalOps,\n\t) as CMSClient<D>;\n}\n","import type { BaseContentItem } from \"./content\";\nimport type { CMSHooks } from \"./hooks\";\nimport type { Logger } from \"./logger\";\n\nexport interface CMSPlugin<T extends BaseContentItem = BaseContentItem> {\n\tname: string;\n\thooks?: CMSHooks<T>;\n\tlogger?: Partial<Logger>;\n}\n\nexport function definePlugin<T extends BaseContentItem>(\n\tplugin: CMSPlugin<T>,\n): CMSPlugin<T> {\n\treturn plugin;\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@notion-headless-cms/core",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "Core CMS engine for notion-headless-cms — fetch, transform, cache with stale-while-revalidate strategy",
5
5
  "keywords": [
6
6
  "notion",
@@ -55,7 +55,7 @@
55
55
  "provenance": true
56
56
  },
57
57
  "peerDependencies": {
58
- "@notion-headless-cms/renderer": "0.1.3"
58
+ "@notion-headless-cms/renderer": "0.1.4"
59
59
  },
60
60
  "peerDependenciesMeta": {
61
61
  "@notion-headless-cms/renderer": {
@@ -63,7 +63,7 @@
63
63
  }
64
64
  },
65
65
  "devDependencies": {
66
- "@notion-headless-cms/renderer": "0.1.3"
66
+ "@notion-headless-cms/renderer": "0.1.4"
67
67
  },
68
68
  "scripts": {
69
69
  "build": "tsdown src/index.ts src/errors.ts src/hooks.ts src/cache/memory.ts src/cache/noop.ts --format esm --dts --sourcemap --out-dir dist",
@@ -1,55 +0,0 @@
1
- //#region src/types/content.d.ts
2
- /**
3
- * ライブラリが動作するために必須なフィールド。
4
- * 利用者はこのインターフェースを拡張して独自のコンテンツ型を定義する。
5
- *
6
- * @example
7
- * interface Post extends BaseContentItem {
8
- * title: string;
9
- * author: string;
10
- * }
11
- * createCMS<Post>({ source: notionAdapter({ ... }) })
12
- */
13
- interface BaseContentItem {
14
- /** Notion ページ ID(変更検知に必須)。 */
15
- id: string;
16
- /** URL キー(必須)。 */
17
- slug: string;
18
- /** Notion ページ名(title 型プロパティのテキスト)。 */
19
- title?: string | null;
20
- /** 最終更新タイムスタンプ(変更検知に必須)。 */
21
- updatedAt: string;
22
- /** コンテンツのステータス。ステータスのない DB では省略可能。 */
23
- status?: string;
24
- /** 公開日時。日付プロパティのない DB では省略可能。 */
25
- publishedAt?: string;
26
- }
27
- /** ストレージにキャッシュされたレンダリング済みコンテンツ。 */
28
- interface CachedItem<T extends BaseContentItem = BaseContentItem> {
29
- html: string;
30
- item: T;
31
- notionUpdatedAt: string;
32
- cachedAt: number;
33
- }
34
- /** ストレージにキャッシュされたコンテンツ一覧。 */
35
- interface CachedItemList<T extends BaseContentItem = BaseContentItem> {
36
- items: T[];
37
- cachedAt: number;
38
- }
39
- /** ストレージから取得したバイナリオブジェクト。 */
40
- interface StorageBinary {
41
- data: ArrayBuffer;
42
- contentType?: string;
43
- }
44
- /** Notionのプロパティ名マッピング(すべてオプション)。 */
45
- interface CMSSchemaProperties {
46
- /** Notionのスラッグプロパティ名。デフォルト: 'Slug' */
47
- slug?: string;
48
- /** Notionのステータスプロパティ名。デフォルト: 'Status' */
49
- status?: string;
50
- /** Notionの公開日プロパティ名。デフォルト: 'CreatedAt' */
51
- date?: string;
52
- }
53
- //#endregion
54
- export { StorageBinary as a, CachedItemList as i, CMSSchemaProperties as n, CachedItem as r, BaseContentItem as t };
55
- //# sourceMappingURL=content-BlD8UPas.d.mts.map