@notion-headless-cms/core 0.3.9 → 0.3.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cache/memory.d.mts +1 -1
- package/dist/{content-BIcYVt2y.d.mts → content-Bffid8da.d.mts} +5 -5
- package/dist/{hooks-C0Pv0WYd.d.mts → hooks-CqqVxrYg.d.mts} +2 -2
- package/dist/hooks.d.mts +1 -1
- package/dist/index.d.mts +21 -4
- package/dist/index.mjs +12 -1
- package/dist/index.mjs.map +1 -1
- package/dist/{memory-V04Q09jC.d.mts → memory-CA1uTRbr.d.mts} +2 -2
- package/package.json +1 -1
package/dist/cache/memory.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as memoryCache, n as MemoryDocumentOptions, r as MemoryImageOptions, t as MemoryCacheOptions } from "../memory-
|
|
1
|
+
import { i as memoryCache, n as MemoryDocumentOptions, r as MemoryImageOptions, t as MemoryCacheOptions } from "../memory-CA1uTRbr.mjs";
|
|
2
2
|
export { MemoryCacheOptions, MemoryDocumentOptions, MemoryImageOptions, memoryCache };
|
|
@@ -94,10 +94,10 @@ interface BaseContentItem {
|
|
|
94
94
|
title?: string | null;
|
|
95
95
|
/** 最終更新タイムスタンプ(変更検知に必須)。 */
|
|
96
96
|
updatedAt: string;
|
|
97
|
-
/** コンテンツのステータス。ステータスのない DB では省略可能。 */
|
|
98
|
-
status?: string;
|
|
99
|
-
/** 公開日時。日付プロパティのない DB では省略可能。 */
|
|
100
|
-
publishedAt?: string;
|
|
97
|
+
/** コンテンツのステータス。ステータスのない DB では省略可能。Notion の select 型は null を返す場合がある。 */
|
|
98
|
+
status?: string | null;
|
|
99
|
+
/** 公開日時。日付プロパティのない DB では省略可能。Notion の date 型は null を返す場合がある。 */
|
|
100
|
+
publishedAt?: string | null;
|
|
101
101
|
}
|
|
102
102
|
/**
|
|
103
103
|
* メタデータのみの軽量キャッシュエントリ。
|
|
@@ -143,4 +143,4 @@ interface CMSSchemaProperties {
|
|
|
143
143
|
}
|
|
144
144
|
//#endregion
|
|
145
145
|
export { CachedItemMeta as a, ContentResult as c, CachedItemList as i, ImageRef as l, CMSSchemaProperties as n, StorageBinary as o, CachedItemContent as r, ContentBlock as s, BaseContentItem as t, InlineNode as u };
|
|
146
|
-
//# sourceMappingURL=content-
|
|
146
|
+
//# sourceMappingURL=content-Bffid8da.d.mts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as CachedItemMeta, i as CachedItemList, r as CachedItemContent, t as BaseContentItem } from "./content-
|
|
1
|
+
import { a as CachedItemMeta, i as CachedItemList, r as CachedItemContent, t as BaseContentItem } from "./content-Bffid8da.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/types/hooks.d.ts
|
|
4
4
|
type MaybePromise<T> = T | Promise<T>;
|
|
@@ -75,4 +75,4 @@ declare function mergeLoggers(plugins: Array<{
|
|
|
75
75
|
}>, directLogger?: Logger): Logger | undefined;
|
|
76
76
|
//#endregion
|
|
77
77
|
export { Logger as a, definePlugin as i, mergeLoggers as n, CMSHooks as o, CMSPlugin as r, MaybePromise as s, mergeHooks as t };
|
|
78
|
-
//# sourceMappingURL=hooks-
|
|
78
|
+
//# sourceMappingURL=hooks-CqqVxrYg.d.mts.map
|
package/dist/hooks.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as mergeLoggers, t as mergeHooks } from "./hooks-
|
|
1
|
+
import { n as mergeLoggers, t as mergeHooks } from "./hooks-CqqVxrYg.mjs";
|
|
2
2
|
export { mergeHooks, mergeLoggers };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { a as CachedItemMeta, c as ContentResult, i as CachedItemList, l as ImageRef, n as CMSSchemaProperties, o as StorageBinary, r as CachedItemContent, s as ContentBlock, t as BaseContentItem, u as InlineNode } from "./content-
|
|
2
|
-
import { a as CacheAdapter, c as DataSource, d as PropertyDef, f as PropertyMap, i as memoryCache, l as InvalidateKind, o as DocumentCacheOps, p as WebhookConfig, s as ImageCacheOps, t as MemoryCacheOptions, u as InvalidateScope } from "./memory-
|
|
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-
|
|
1
|
+
import { a as CachedItemMeta, c as ContentResult, i as CachedItemList, l as ImageRef, n as CMSSchemaProperties, o as StorageBinary, r as CachedItemContent, s as ContentBlock, t as BaseContentItem, u as InlineNode } from "./content-Bffid8da.mjs";
|
|
2
|
+
import { a as CacheAdapter, c as DataSource, d as PropertyDef, f as PropertyMap, i as memoryCache, l as InvalidateKind, o as DocumentCacheOps, p as WebhookConfig, s as ImageCacheOps, t as MemoryCacheOptions, u as InvalidateScope } from "./memory-CA1uTRbr.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-CqqVxrYg.mjs";
|
|
4
4
|
import { BuiltInCMSErrorCode, CMSError, CMSErrorCode, CMSErrorContext, isCMSError, isCMSErrorInNamespace } from "./errors.mjs";
|
|
5
5
|
|
|
6
6
|
//#region src/types/collection.d.ts
|
|
@@ -76,6 +76,13 @@ interface CollectionCacheOps<T extends BaseContentItem> {
|
|
|
76
76
|
next: T | null;
|
|
77
77
|
}>;
|
|
78
78
|
}
|
|
79
|
+
/** `check()` の戻り値。差分なしか、差分ありの場合はアイテムを含む。 */
|
|
80
|
+
type CheckResult<T extends BaseContentItem> = {
|
|
81
|
+
stale: false;
|
|
82
|
+
} | {
|
|
83
|
+
stale: true;
|
|
84
|
+
item: ItemWithRender<T>;
|
|
85
|
+
};
|
|
79
86
|
/**
|
|
80
87
|
* コレクション別の CMS クライアント。
|
|
81
88
|
* `cms.posts.get(slug)` / `cms.posts.list()` のようにアクセスする。
|
|
@@ -96,6 +103,15 @@ interface CollectionClient<T extends BaseContentItem = BaseContentItem> {
|
|
|
96
103
|
params(): Promise<{
|
|
97
104
|
slug: string;
|
|
98
105
|
}[]>;
|
|
106
|
+
/**
|
|
107
|
+
* Notion から最新版を取得し、`currentVersion`(`item.updatedAt`)と比較する。
|
|
108
|
+
* 差分があればキャッシュを更新してアイテムを返す。
|
|
109
|
+
* ページ表示後の1回限りのクライアント再検証エンドポイント用。
|
|
110
|
+
*
|
|
111
|
+
* @returns 差分なし: `{ stale: false }`、差分あり: `{ stale: true; item }`、
|
|
112
|
+
* アイテムが存在しない: `null`
|
|
113
|
+
*/
|
|
114
|
+
check(slug: string, currentVersion: string): Promise<CheckResult<T> | null>;
|
|
99
115
|
/** キャッシュ操作 namespace。 */
|
|
100
116
|
cache: CollectionCacheOps<T>;
|
|
101
117
|
}
|
|
@@ -374,6 +390,7 @@ declare class CollectionClientImpl<T extends BaseContentItem> implements Collect
|
|
|
374
390
|
params(): Promise<{
|
|
375
391
|
slug: string;
|
|
376
392
|
}[]>;
|
|
393
|
+
check(slug: string, currentVersion: string): Promise<CheckResult<T> | null>;
|
|
377
394
|
private invalidateImpl;
|
|
378
395
|
private warmImpl;
|
|
379
396
|
private adjacentImpl;
|
|
@@ -394,5 +411,5 @@ declare class CollectionClientImpl<T extends BaseContentItem> implements Collect
|
|
|
394
411
|
private findRaw;
|
|
395
412
|
}
|
|
396
413
|
//#endregion
|
|
397
|
-
export { type AdjacencyOptions, type BaseContentItem, type BuiltInCMSErrorCode, type CMSClient, CMSError, type CMSErrorCode, type CMSErrorContext, type CMSGlobalOps, type CMSHooks, type CMSPlugin, type CMSSchemaProperties, type CacheAdapter, type CachedItemContent, type CachedItemList, type CachedItemMeta, type CollectionCacheOps, type CollectionClient, CollectionClientImpl, type CollectionContext, type CollectionDef, type CollectionsConfig, type ContentBlock, type ContentConfig, type ContentResult, type CreateCMSOptions, DEFAULT_RETRY_CONFIG, type DataSource, type DocumentCacheOps, type GetOptions, type HandlerAdapter, type HandlerOptions, type ImageCacheOps, type ImageRef, type InferCollectionItem, type InlineNode, type InvalidateKind, type InvalidateScope, type ItemWithRender, type ListOptions, type LogLevel, type Logger, type MaybePromise, type MemoryCacheOptions, type PropertyDef, type PropertyMap, type RateLimiterConfig, type RenderOptions, type RendererFn, type RendererPluginList, type RetryConfig, type SortOption, type StorageBinary, type WarmOptions, type WebhookConfig, collectionKey, createCMS, createHandler, definePlugin, isCMSError, isCMSErrorInNamespace, isStale, memoryCache, mergeHooks, mergeLoggers, noopDocOps, noopImgOps, sha256Hex, withRetry };
|
|
414
|
+
export { type AdjacencyOptions, type BaseContentItem, type BuiltInCMSErrorCode, type CMSClient, CMSError, type CMSErrorCode, type CMSErrorContext, type CMSGlobalOps, type CMSHooks, type CMSPlugin, type CMSSchemaProperties, type CacheAdapter, type CachedItemContent, type CachedItemList, type CachedItemMeta, type CheckResult, type CollectionCacheOps, type CollectionClient, CollectionClientImpl, type CollectionContext, type CollectionDef, type CollectionsConfig, type ContentBlock, type ContentConfig, type ContentResult, type CreateCMSOptions, DEFAULT_RETRY_CONFIG, type DataSource, type DocumentCacheOps, type GetOptions, type HandlerAdapter, type HandlerOptions, type ImageCacheOps, type ImageRef, type InferCollectionItem, type InlineNode, type InvalidateKind, type InvalidateScope, type ItemWithRender, type ListOptions, type LogLevel, type Logger, type MaybePromise, type MemoryCacheOptions, type PropertyDef, type PropertyMap, type RateLimiterConfig, type RenderOptions, type RendererFn, type RendererPluginList, type RetryConfig, type SortOption, type StorageBinary, type WarmOptions, type WebhookConfig, collectionKey, createCMS, createHandler, definePlugin, isCMSError, isCMSErrorInNamespace, isStale, memoryCache, mergeHooks, mergeLoggers, noopDocOps, noopImgOps, sha256Hex, withRetry };
|
|
398
415
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
CHANGED
|
@@ -373,6 +373,17 @@ var CollectionClientImpl = class {
|
|
|
373
373
|
async params() {
|
|
374
374
|
return (await this.fetchList()).map((item) => ({ slug: item.slug }));
|
|
375
375
|
}
|
|
376
|
+
async check(slug, currentVersion) {
|
|
377
|
+
const raw = await this.findRaw(slug);
|
|
378
|
+
if (!raw) return null;
|
|
379
|
+
if (raw.updatedAt === currentVersion) return { stale: false };
|
|
380
|
+
const meta = await this.persistMeta(slug, raw);
|
|
381
|
+
await this.invalidateContent(slug);
|
|
382
|
+
return {
|
|
383
|
+
stale: true,
|
|
384
|
+
item: this.attachLazyContent(meta)
|
|
385
|
+
};
|
|
386
|
+
}
|
|
376
387
|
async invalidateImpl(slug) {
|
|
377
388
|
if (slug !== void 0) {
|
|
378
389
|
this.ctx.logger?.debug?.("アイテムキャッシュを無効化", {
|
|
@@ -640,7 +651,7 @@ function applyListOptions(items, opts) {
|
|
|
640
651
|
let result = items;
|
|
641
652
|
if (opts.status) {
|
|
642
653
|
const allow = new Set(Array.isArray(opts.status) ? opts.status : [opts.status]);
|
|
643
|
-
result = result.filter((it) => it.status
|
|
654
|
+
result = result.filter((it) => it.status != null && allow.has(it.status));
|
|
644
655
|
}
|
|
645
656
|
if (opts.tag) {
|
|
646
657
|
const tag = opts.tag;
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/cache.ts","../src/cache/noop.ts","../src/image.ts","../src/rendering.ts","../src/retry.ts","../src/collection.ts","../src/handler.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 type {\n\tBaseContentItem,\n\tCachedItemContent,\n\tCachedItemList,\n\tCachedItemMeta,\n\tDocumentCacheOps,\n\tImageCacheOps,\n\tStorageBinary,\n} from \"../types/index\";\n\n/** 何もキャッシュしないドキュメントオペレーション。常に null を返す。 */\nconst noopDoc: DocumentCacheOps = {\n\tgetList<T extends BaseContentItem>(\n\t\t_collection: string,\n\t): Promise<CachedItemList<T> | null> {\n\t\treturn Promise.resolve(null);\n\t},\n\tsetList<T extends BaseContentItem>(\n\t\t_collection: string,\n\t\t_data: CachedItemList<T>,\n\t): Promise<void> {\n\t\treturn Promise.resolve();\n\t},\n\tgetMeta<T extends BaseContentItem>(\n\t\t_collection: string,\n\t\t_slug: string,\n\t): Promise<CachedItemMeta<T> | null> {\n\t\treturn Promise.resolve(null);\n\t},\n\tsetMeta<T extends BaseContentItem>(\n\t\t_collection: string,\n\t\t_slug: string,\n\t\t_data: CachedItemMeta<T>,\n\t): Promise<void> {\n\t\treturn Promise.resolve();\n\t},\n\tgetContent(\n\t\t_collection: string,\n\t\t_slug: string,\n\t): Promise<CachedItemContent | null> {\n\t\treturn Promise.resolve(null);\n\t},\n\tsetContent(\n\t\t_collection: string,\n\t\t_slug: string,\n\t\t_data: CachedItemContent,\n\t): Promise<void> {\n\t\treturn Promise.resolve();\n\t},\n\tinvalidate(): Promise<void> {\n\t\treturn Promise.resolve();\n\t},\n};\n\n/** 何もキャッシュしない画像オペレーション。 */\nconst noopImg: ImageCacheOps = {\n\tget(_hash: string): Promise<StorageBinary | null> {\n\t\treturn Promise.resolve(null);\n\t},\n\tset(): Promise<void> {\n\t\treturn Promise.resolve();\n\t},\n};\n\n/**\n * 何もキャッシュしないアダプタ。`createCMS({ cache })` 未指定時の内部デフォルト。\n * テストでも使える。\n */\nexport const noopDocOps: DocumentCacheOps = noopDoc;\nexport const noopImgOps: ImageCacheOps = noopImg;\n","import { sha256Hex } from \"./cache\";\nimport { CMSError, isCMSError } from \"./errors\";\nimport type { ImageCacheOps, Logger, 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 * URL → SHA-256 hash のメモ化マップ。\n * Notion の画像 URL は同じ画像でも署名が時刻ごとに変わるが、\n * 1 リクエスト内では同一 URL が複数回現れることが多い (重複ハッシュ計算を回避)。\n *\n * メモリリーク防止に最大エントリ数を設けており、超過時は最古から削除する LRU。\n */\nconst HASH_MEMO_LIMIT = 1024;\nconst hashMemo = new Map<string, string>();\n\nasync function memoSha256(url: string): Promise<string> {\n\tconst cached = hashMemo.get(url);\n\tif (cached !== undefined) {\n\t\t// LRU: アクセスを末尾に移動\n\t\thashMemo.delete(url);\n\t\thashMemo.set(url, cached);\n\t\treturn cached;\n\t}\n\tconst hash = await sha256Hex(url);\n\thashMemo.set(url, hash);\n\tif (hashMemo.size > HASH_MEMO_LIMIT) {\n\t\tconst firstKey = hashMemo.keys().next().value;\n\t\tif (firstKey !== undefined) hashMemo.delete(firstKey);\n\t}\n\treturn hash;\n}\n\n/**\n * Notion画像URLをfetchして ImageCacheOps にキャッシュし、プロキシURL を返す。\n * 既存キャッシュがあれば再fetchしない。\n */\nasync function fetchAndCacheImage(\n\tcache: ImageCacheOps,\n\tcacheName: string,\n\tnotionUrl: string,\n\timageProxyBase: string,\n\tlogger?: Logger,\n): Promise<string> {\n\tconst hash = await memoSha256(notionUrl);\n\tconst proxyUrl = `${imageProxyBase}/${hash}`;\n\n\tconst existing = await cache.get(hash);\n\tif (existing) {\n\t\tlogger?.debug?.(\"画像キャッシュヒット\", {\n\t\t\toperation: \"fetchAndCacheImage\",\n\t\t\tcacheAdapter: cacheName,\n\t\t\timageHash: hash,\n\t\t});\n\t\treturn proxyUrl;\n\t}\n\n\tlogger?.debug?.(\"画像キャッシュミス、Notion からフェッチ\", {\n\t\toperation: \"fetchAndCacheImage\",\n\t\tcacheAdapter: cacheName,\n\t\timageHash: hash,\n\t});\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\tlogger?.debug?.(\"画像をキャッシュに保存\", {\n\t\t\toperation: \"fetchAndCacheImage\",\n\t\t\tcacheAdapter: cacheName,\n\t\t\timageHash: hash,\n\t\t});\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/**\n * `ImageCacheOps` と `imageProxyBase` から `cacheImage` 関数を構築する。\n * 返り値は Notion 画像 URL を受け取り、SHA-256 ハッシュをキャッシュキーとして\n * {@link ImageCacheOps} に保存後、プロキシ URL を返す。\n */\nexport function buildCacheImageFn(\n\tcache: ImageCacheOps,\n\tcacheName: string,\n\timageProxyBase: string,\n\tlogger?: Logger,\n): (notionUrl: string) => Promise<string> {\n\treturn (notionUrl) =>\n\t\tfetchAndCacheImage(cache, cacheName, notionUrl, imageProxyBase, logger);\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\tCachedItemContent,\n\tCachedItemMeta,\n\tCMSHooks,\n\tContentConfig,\n\tDataSource,\n\tImageCacheOps,\n\tLogger,\n\tRendererFn,\n} from \"./types/index\";\n\n/** 本文レンダリングに必要な依存を束ねたコンテキスト。 */\nexport interface RenderContext<T extends BaseContentItem> {\n\tsource: DataSource<T>;\n\trendererFn: RendererFn | undefined;\n\timgCache: ImageCacheOps;\n\timgCacheName: string;\n\thasImageCache: boolean;\n\timageProxyBase: string;\n\tcontentConfig: ContentConfig | undefined;\n\thooks: CMSHooks<T>;\n\tlogger: Logger | undefined;\n}\n\n/**\n * メタデータキャッシュエントリを生成する。Notion API も renderer も呼ばない軽量関数。\n */\nexport function buildCachedItemMeta<T extends BaseContentItem>(\n\titem: T,\n\tsource: DataSource<T>,\n): CachedItemMeta<T> {\n\treturn {\n\t\titem,\n\t\tnotionUpdatedAt: source.getLastModified(item),\n\t\tcachedAt: Date.now(),\n\t};\n}\n\n/**\n * アイテム本文を Markdown ロード → blocks 生成 → HTML レンダリング → フック適用まで\n * 実行し、本文キャッシュ用の `CachedItemContent` を返す。\n */\nexport async function buildCachedItemContent<T extends BaseContentItem>(\n\titem: T,\n\tctx: RenderContext<T>,\n): Promise<CachedItemContent> {\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: \"buildCachedItemContent: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(\n\t\t\t\tctx.imgCache,\n\t\t\t\tctx.imgCacheName,\n\t\t\t\tctx.imageProxyBase,\n\t\t\t\tctx.logger,\n\t\t\t)\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: \"buildCachedItemContent: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: CachedItemContent = {\n\t\thtml,\n\t\tblocks,\n\t\tmarkdown,\n\t\tnotionUpdatedAt: ctx.source.getLastModified(item),\n\t\tcachedAt: Date.now(),\n\t};\n\n\tif (ctx.hooks.beforeCacheContent) {\n\t\tresult = await ctx.hooks.beforeCacheContent(result, item);\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 */\nasync 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/**\n * 指数バックオフ(オプションでジッター付き)でリトライする。\n *\n * `config.retryOn` に含まれるステータスコードを持つエラーのみリトライ対象。\n * 遅延は `baseDelayMs * 2^attempt` の指数バックオフ。\n * `jitter` が `true`(デフォルト)の場合、0.5〜1.0 の乱数係数を乗算して\n * Thundering Herd を防ぐ。`false` にすると確定的な遅延になる。\n */\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 { RenderContext } from \"./rendering\";\nimport { buildCachedItemContent, buildCachedItemMeta } from \"./rendering\";\nimport type { RetryConfig } from \"./retry\";\nimport { withRetry } from \"./retry\";\nimport type {\n\tAdjacencyOptions,\n\tBaseContentItem,\n\tCachedItemContent,\n\tCachedItemList,\n\tCachedItemMeta,\n\tCMSHooks,\n\tCollectionCacheOps,\n\tCollectionClient,\n\tDataSource,\n\tDocumentCacheOps,\n\tGetOptions,\n\tItemWithRender,\n\tListOptions,\n\tLogger,\n\tSortOption,\n\tWarmOptions,\n} from \"./types/index\";\n\n/**\n * コレクション別キャッシュキーを生成する。\n * item: `{collection}:{slug}` / list: `{collection}`\n *\n * (Cache adapter 内部のキー戦略はアダプタごとに異なるが、\n * 表示や再計算用に core 側でも公開ヘルパーを提供する)\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: DocumentCacheOps;\n\tdocCacheName: string;\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 として使うフィールド名 (CLI 生成の `CollectionDef.slugField`)。\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\treadonly cache: CollectionCacheOps<T>;\n\n\tconstructor(private readonly ctx: CollectionContext<T>) {\n\t\tthis.cache = {\n\t\t\tinvalidate: (slug?: string) => this.invalidateImpl(slug),\n\t\t\twarm: (opts?: WarmOptions) => this.warmImpl(opts),\n\t\t\tadjacent: (slug, opts) => this.adjacentImpl(slug, opts),\n\t\t};\n\t}\n\n\t// ── 基本取得 ──────────────────────────────────────────────────────────\n\n\tasync get(\n\t\tslug: string,\n\t\topts: GetOptions = {},\n\t): Promise<ItemWithRender<T> | null> {\n\t\t// fresh: 強制ブロッキング取得\n\t\tif (opts.fresh) {\n\t\t\tthis.ctx.hooks.onCacheMiss?.(slug);\n\t\t\tconst item = await this.findRaw(slug);\n\t\t\tif (!item) return null;\n\t\t\tconst meta = await this.persistMeta(slug, item);\n\t\t\tawait this.invalidateContent(slug);\n\t\t\treturn this.attachLazyContent(meta);\n\t\t}\n\n\t\tconst cachedMeta = await this.ctx.docCache.getMeta<T>(\n\t\t\tthis.ctx.collection,\n\t\t\tslug,\n\t\t);\n\t\tif (cachedMeta) {\n\t\t\tif (\n\t\t\t\tthis.ctx.ttlMs !== undefined &&\n\t\t\t\tisStale(cachedMeta.cachedAt, this.ctx.ttlMs)\n\t\t\t) {\n\t\t\t\t// TTL 切れ: ブロッキング再取得\n\t\t\t\tthis.ctx.logger?.debug?.(\"キャッシュ期限切れ(TTL)、フェッチ\", {\n\t\t\t\t\toperation: \"get\",\n\t\t\t\t\tslug,\n\t\t\t\t\tcollection: this.ctx.collection,\n\t\t\t\t\tcacheAdapter: this.ctx.docCacheName,\n\t\t\t\t});\n\t\t\t\tthis.ctx.hooks.onCacheMiss?.(slug);\n\t\t\t\tconst item = await this.findRaw(slug);\n\t\t\t\tif (!item) return null;\n\t\t\t\tconst meta = await this.persistMeta(slug, item);\n\t\t\t\tawait this.invalidateContent(slug);\n\t\t\t\treturn this.attachLazyContent(meta);\n\t\t\t}\n\t\t\t// SWR: キャッシュ即時返却 + バックグラウンド差分チェック\n\t\t\tconst bg = this.checkAndUpdateItemBg(slug, cachedMeta);\n\t\t\tif (this.ctx.waitUntil) this.ctx.waitUntil(bg);\n\t\t\tthis.ctx.logger?.debug?.(\"キャッシュヒット\", {\n\t\t\t\toperation: \"get\",\n\t\t\t\tslug,\n\t\t\t\tcollection: this.ctx.collection,\n\t\t\t\tcacheAdapter: this.ctx.docCacheName,\n\t\t\t\tcachedAt: cachedMeta.cachedAt,\n\t\t\t});\n\t\t\tthis.ctx.hooks.onCacheHit?.(slug, cachedMeta);\n\t\t\treturn this.attachLazyContent(cachedMeta);\n\t\t}\n\n\t\t// メタ未キャッシュ: 同期フェッチ (保存はバックグラウンド可)\n\t\tthis.ctx.logger?.debug?.(\"キャッシュミス、フェッチ\", {\n\t\t\toperation: \"get\",\n\t\t\tslug,\n\t\t\tcollection: this.ctx.collection,\n\t\t\tcacheAdapter: this.ctx.docCacheName,\n\t\t});\n\t\tthis.ctx.hooks.onCacheMiss?.(slug);\n\t\tconst item = await this.findRaw(slug);\n\t\tif (!item) return null;\n\t\tconst meta = await this.persistMeta(slug, item, { background: true });\n\t\treturn this.attachLazyContent(meta);\n\t}\n\n\tasync list(opts?: ListOptions<T>): Promise<T[]> {\n\t\tconst allItems = await this.fetchList();\n\t\treturn applyListOptions(allItems, opts);\n\t}\n\n\tasync params(): Promise<{ slug: string }[]> {\n\t\tconst items = await this.fetchList();\n\t\treturn items.map((item) => ({ slug: item.slug }));\n\t}\n\n\t// ── キャッシュ操作 ────────────────────────────────────────────────────\n\n\tprivate async invalidateImpl(slug?: string): Promise<void> {\n\t\tif (slug !== undefined) {\n\t\t\tthis.ctx.logger?.debug?.(\"アイテムキャッシュを無効化\", {\n\t\t\t\toperation: \"cache.invalidate\",\n\t\t\t\tcollection: this.ctx.collection,\n\t\t\t\tcacheAdapter: this.ctx.docCacheName,\n\t\t\t\tslug,\n\t\t\t});\n\t\t\tawait this.ctx.docCache.invalidate({\n\t\t\t\tcollection: this.ctx.collection,\n\t\t\t\tslug,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tthis.ctx.logger?.debug?.(\"コレクション全体のキャッシュを無効化\", {\n\t\t\toperation: \"cache.invalidate\",\n\t\t\tcollection: this.ctx.collection,\n\t\t\tcacheAdapter: this.ctx.docCacheName,\n\t\t});\n\t\tawait this.ctx.docCache.invalidate({ collection: this.ctx.collection });\n\t}\n\n\tprivate async warmImpl(\n\t\topts?: WarmOptions,\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\tawait this.persistMeta(item.slug, item);\n\t\t\t\t\t\tconst content = await buildCachedItemContent(item, this.ctx.render);\n\t\t\t\t\t\tawait this.ctx.docCache.setContent(\n\t\t\t\t\t\t\tthis.ctx.collection,\n\t\t\t\t\t\t\titem.slug,\n\t\t\t\t\t\t\tcontent,\n\t\t\t\t\t\t);\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?.(\"warm: アイテムの事前レンダリングに失敗\", {\n\t\t\t\t\t\t\tslug: item.slug,\n\t\t\t\t\t\t\tpageId: item.id,\n\t\t\t\t\t\t\terror: err instanceof Error ? err.message : String(err),\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(this.ctx.collection, {\n\t\t\titems,\n\t\t\tcachedAt: Date.now(),\n\t\t});\n\t\treturn { ok, failed };\n\t}\n\n\tprivate async adjacentImpl(\n\t\tslug: string,\n\t\topts?: AdjacencyOptions<T>,\n\t): Promise<{ prev: T | null; next: T | null }> {\n\t\tconst items = applyListOptions(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\tprivate async persistMeta(\n\t\tslug: string,\n\t\titem: T,\n\t\topts: { background?: boolean } = {},\n\t): Promise<CachedItemMeta<T>> {\n\t\tlet meta = buildCachedItemMeta(item, this.ctx.source);\n\t\tif (this.ctx.hooks.beforeCacheMeta) {\n\t\t\tmeta = await this.ctx.hooks.beforeCacheMeta(meta);\n\t\t}\n\t\tconst save = this.ctx.docCache.setMeta(this.ctx.collection, slug, meta);\n\t\tif (opts.background && 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 meta;\n\t}\n\n\tprivate async invalidateContent(slug: string): Promise<void> {\n\t\tawait this.ctx.docCache.invalidate({\n\t\t\tcollection: this.ctx.collection,\n\t\t\tslug,\n\t\t\tkind: \"content\",\n\t\t});\n\t}\n\n\t/**\n\t * 本文キャッシュをロードする。キャッシュが無いか、メタとの整合性が取れない場合は\n\t * 再生成して書き戻す。\n\t */\n\tprivate async loadOrBuildContent(\n\t\tslug: string,\n\t\titem: T,\n\t): Promise<CachedItemContent> {\n\t\tconst expected = this.ctx.source.getLastModified(item);\n\t\tconst cached = await this.ctx.docCache.getContent(\n\t\t\tthis.ctx.collection,\n\t\t\tslug,\n\t\t);\n\t\tif (cached && cached.notionUpdatedAt === expected) return cached;\n\n\t\tconst fresh = await buildCachedItemContent(item, this.ctx.render);\n\t\tawait this.ctx.docCache.setContent(this.ctx.collection, slug, fresh);\n\t\tthis.ctx.hooks.onContentRevalidated?.(slug, fresh);\n\t\treturn fresh;\n\t}\n\n\t/** メタ既知の状態で本文だけバックグラウンド再生成する。エラーは握りつぶす。 */\n\tprivate async rebuildContentBg(slug: string, item: T): Promise<void> {\n\t\ttry {\n\t\t\tconst fresh = await buildCachedItemContent(item, this.ctx.render);\n\t\t\tawait this.ctx.docCache.setContent(this.ctx.collection, slug, fresh);\n\t\t\tthis.ctx.hooks.onContentRevalidated?.(slug, fresh);\n\t\t} catch (err) {\n\t\t\tthis.ctx.logger?.warn?.(\"本文のバックグラウンド再生成に失敗\", {\n\t\t\t\tslug,\n\t\t\t\tcollection: this.ctx.collection,\n\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate attachLazyContent(meta: CachedItemMeta<T>): ItemWithRender<T> {\n\t\tconst slug = meta.item.slug;\n\t\tconst item = meta.item;\n\t\t// 同一インスタンス内で本文ロードを集約する (複数 render() でも 1 回の I/O)\n\t\tlet payloadPromise: Promise<CachedItemContent> | undefined;\n\t\tconst loadPayload = (): Promise<CachedItemContent> => {\n\t\t\tif (!payloadPromise) {\n\t\t\t\tpayloadPromise = this.loadOrBuildContent(slug, item);\n\t\t\t}\n\t\t\treturn payloadPromise;\n\t\t};\n\n\t\tconst render = async (opts?: {\n\t\t\tformat?: \"html\" | \"markdown\";\n\t\t}): Promise<string> => {\n\t\t\tconst payload = await loadPayload();\n\t\t\treturn opts?.format === \"markdown\" ? payload.markdown : payload.html;\n\t\t};\n\n\t\treturn Object.assign(Object.create(null) as object, item, {\n\t\t\trender,\n\t\t}) as ItemWithRender<T>;\n\t}\n\n\tprivate async fetchList(): Promise<T[]> {\n\t\tconst cached = await this.ctx.docCache.getList<T>(this.ctx.collection);\n\t\tif (cached) {\n\t\t\tif (\n\t\t\t\tthis.ctx.ttlMs !== undefined &&\n\t\t\t\tisStale(cached.cachedAt, this.ctx.ttlMs)\n\t\t\t) {\n\t\t\t\t// TTL 切れ: ブロッキング再取得\n\t\t\t\tthis.ctx.logger?.debug?.(\"リストキャッシュ期限切れ(TTL)、フェッチ\", {\n\t\t\t\t\toperation: \"list\",\n\t\t\t\t\tcollection: this.ctx.collection,\n\t\t\t\t\tcacheAdapter: this.ctx.docCacheName,\n\t\t\t\t});\n\t\t\t\tthis.ctx.hooks.onListCacheMiss?.();\n\t\t\t\tconst items = await this.fetchListRaw();\n\t\t\t\tawait this.ctx.docCache.setList(this.ctx.collection, {\n\t\t\t\t\titems,\n\t\t\t\t\tcachedAt: Date.now(),\n\t\t\t\t});\n\t\t\t\treturn items;\n\t\t\t}\n\t\t\t// SWR: 即時返却 + バックグラウンド差分チェック\n\t\t\tconst bg = this.checkAndUpdateListBg(cached);\n\t\t\tif (this.ctx.waitUntil) this.ctx.waitUntil(bg);\n\t\t\tthis.ctx.logger?.debug?.(\"リストキャッシュヒット\", {\n\t\t\t\toperation: \"list\",\n\t\t\t\tcollection: this.ctx.collection,\n\t\t\t\tcacheAdapter: this.ctx.docCacheName,\n\t\t\t});\n\t\t\tthis.ctx.hooks.onListCacheHit?.(cached);\n\t\t\treturn cached.items;\n\t\t}\n\n\t\t// 未キャッシュ: 同期フェッチ\n\t\tthis.ctx.logger?.debug?.(\"リストキャッシュミス、フェッチ\", {\n\t\t\toperation: \"list\",\n\t\t\tcollection: this.ctx.collection,\n\t\t\tcacheAdapter: this.ctx.docCacheName,\n\t\t});\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(this.ctx.collection, {\n\t\t\titems,\n\t\t\tcachedAt,\n\t\t});\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 async checkAndUpdateItemBg(\n\t\tslug: string,\n\t\tcached: CachedItemMeta<T>,\n\t): Promise<void> {\n\t\ttry {\n\t\t\tconst item = await this.findRaw(slug);\n\t\t\tif (!item) return;\n\t\t\tconst lm = this.ctx.source.getLastModified(item);\n\t\t\tif (lm !== cached.notionUpdatedAt) {\n\t\t\t\tconst meta = await this.persistMeta(slug, item);\n\t\t\t\tawait this.invalidateContent(slug);\n\t\t\t\tthis.ctx.logger?.debug?.(\"SWR: 差分を検出、メタを差し替え\", {\n\t\t\t\t\toperation: \"get:bg\",\n\t\t\t\t\tslug,\n\t\t\t\t\tcollection: this.ctx.collection,\n\t\t\t\t\tnotionUpdatedAt: cached.notionUpdatedAt,\n\t\t\t\t});\n\t\t\t\tthis.ctx.hooks.onCacheRevalidated?.(slug, meta);\n\t\t\t\tawait this.rebuildContentBg(slug, item);\n\t\t\t} else if (this.ctx.ttlMs !== undefined) {\n\t\t\t\t// 変更なし + TTL あり: cachedAt をリセットして次回の期限切れを先送りする\n\t\t\t\tawait this.ctx.docCache.setMeta(this.ctx.collection, slug, {\n\t\t\t\t\t...cached,\n\t\t\t\t\tcachedAt: Date.now(),\n\t\t\t\t});\n\t\t\t\tthis.ctx.logger?.debug?.(\"SWR: 差分なし、TTL をリセット\", {\n\t\t\t\t\toperation: \"get:bg\",\n\t\t\t\t\tslug,\n\t\t\t\t\tcollection: this.ctx.collection,\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tthis.ctx.logger?.warn?.(\n\t\t\t\t\"SWR: アイテムのバックグラウンド差分チェックに失敗\",\n\t\t\t\t{\n\t\t\t\t\tslug,\n\t\t\t\t\tcollection: this.ctx.collection,\n\t\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate async checkAndUpdateListBg(cached: CachedItemList<T>): Promise<void> {\n\t\ttry {\n\t\t\tconst items = await this.fetchListRaw();\n\t\t\tif (\n\t\t\t\tthis.ctx.source.getListVersion(items) !==\n\t\t\t\tthis.ctx.source.getListVersion(cached.items)\n\t\t\t) {\n\t\t\t\tconst listEntry = { items, cachedAt: Date.now() };\n\t\t\t\tawait this.ctx.docCache.setList(this.ctx.collection, listEntry);\n\t\t\t\tthis.ctx.logger?.debug?.(\n\t\t\t\t\t\"SWR: リスト差分を検出、キャッシュを差し替え\",\n\t\t\t\t\t{\n\t\t\t\t\t\toperation: \"list:bg\",\n\t\t\t\t\t\tcollection: this.ctx.collection,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tthis.ctx.hooks.onListCacheRevalidated?.(listEntry);\n\t\t\t} else if (this.ctx.ttlMs !== undefined) {\n\t\t\t\tawait this.ctx.docCache.setList(this.ctx.collection, {\n\t\t\t\t\t...cached,\n\t\t\t\t\tcachedAt: Date.now(),\n\t\t\t\t});\n\t\t\t\tthis.ctx.logger?.debug?.(\"SWR: リスト差分なし、TTL をリセット\", {\n\t\t\t\t\toperation: \"list:bg\",\n\t\t\t\t\tcollection: this.ctx.collection,\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tthis.ctx.logger?.warn?.(\n\t\t\t\t\"SWR: リストのバックグラウンド差分チェックに失敗\",\n\t\t\t\t{\n\t\t\t\t\tcollection: this.ctx.collection,\n\t\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\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?.(\"list() リトライ中\", { 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?.(\"get() リトライ中\", {\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// slugField から Notion プロパティ名を解決して効率的なフィルタクエリを実行する。\n\t\tconst notionPropName =\n\t\t\tthis.ctx.source.properties?.[this.ctx.slugField]?.notion;\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 applyListOptions<T extends BaseContentItem>(\n\titems: T[],\n\topts?: ListOptions<T>,\n): T[] {\n\tif (!opts) return items;\n\tlet result = items;\n\n\tif (opts.status) {\n\t\tconst allow = new Set(\n\t\t\tArray.isArray(opts.status) ? opts.status : [opts.status],\n\t\t);\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.dir === \"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 { ImageCacheOps, 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: ImageCacheOps;\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 { noopDocOps, noopImgOps } 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 type { RenderContext } from \"./rendering\";\nimport type { RetryConfig } from \"./retry\";\nimport { DEFAULT_RETRY_CONFIG } from \"./retry\";\nimport type {\n\tBaseContentItem,\n\tCacheAdapter,\n\tCMSHooks,\n\tCollectionClient,\n\tCollectionsConfig,\n\tCreateCMSOptions,\n\tDataSource,\n\tDocumentCacheOps,\n\tImageCacheOps,\n\tInferCollectionItem,\n\tInvalidateScope,\n\tLogger,\n\tLogLevel,\n\tRendererFn,\n\tStorageBinary,\n} from \"./types/index\";\n\nconst DEFAULT_IMAGE_PROXY_BASE = \"/api/images\";\n\n/** `CMSClient<C>` — コレクション別アクセス + グローバル操作の合成型。 */\nexport type CMSClient<C extends CollectionsConfig> = {\n\t[K in keyof C]: CollectionClient<InferCollectionItem<C[K]>>;\n} & CMSGlobalOps;\n\n/** `CMSClient` のグローバル名前空間。`$` プレフィックス。 */\nexport interface CMSGlobalOps {\n\t/** 登録されているコレクション名の一覧。 */\n\treadonly $collections: readonly string[];\n\t/** 全コレクションまたは特定スコープのキャッシュを無効化する。 */\n\t$invalidate(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): Promise<StorageBinary | null>;\n}\n\ninterface ResolvedCache {\n\tdoc: DocumentCacheOps;\n\tdocName: string;\n\timg: ImageCacheOps;\n\timgName: string;\n\thasImg: boolean;\n}\n\n/**\n * `cache` オプションから document / image オペレーションを解決する。\n *\n * - 配列で渡された場合は各 adapter の `handles` を見て先勝ち (最初に見つかったもの) で振り分ける\n * - 単体で渡された場合は `handles` の領域だけ反映、片側は noop\n * - 未指定なら両方 noop\n */\nfunction resolveCache(\n\tcache: CacheAdapter | readonly CacheAdapter[] | undefined,\n): ResolvedCache {\n\tconst adapters =\n\t\tcache === undefined ? [] : Array.isArray(cache) ? cache : [cache];\n\n\tlet doc: DocumentCacheOps = noopDocOps;\n\tlet docName = \"noop-document\";\n\tlet img: ImageCacheOps = noopImgOps;\n\tlet imgName = \"noop-image\";\n\tlet docFound = false;\n\tlet imgFound = false;\n\n\tfor (const adapter of adapters) {\n\t\tif (!docFound && adapter.handles.includes(\"document\") && adapter.doc) {\n\t\t\tdoc = adapter.doc;\n\t\t\tdocName = adapter.name;\n\t\t\tdocFound = true;\n\t\t}\n\t\tif (!imgFound && adapter.handles.includes(\"image\") && adapter.img) {\n\t\t\timg = adapter.img;\n\t\t\timgName = adapter.name;\n\t\t\timgFound = true;\n\t\t}\n\t}\n\n\treturn { doc, docName, img, imgName, hasImg: imgFound };\n}\n\nconst LOG_LEVEL_ORDER: Record<LogLevel, number> = {\n\tdebug: 0,\n\tinfo: 1,\n\twarn: 2,\n\terror: 3,\n};\n\n/** `logger` から `minLevel` 未満のレベルを除いた新しい Logger を返す。 */\nfunction applyLogLevel(\n\tlogger: Logger | undefined,\n\tminLevel: LogLevel,\n): Logger | undefined {\n\tif (!logger) return undefined;\n\tconst minOrder = LOG_LEVEL_ORDER[minLevel];\n\tconst filtered: Logger = {};\n\tfor (const level of [\"debug\", \"info\", \"warn\", \"error\"] as const) {\n\t\tif (LOG_LEVEL_ORDER[level] >= minOrder) {\n\t\t\tfiltered[level] = logger[level];\n\t\t}\n\t}\n\treturn filtered;\n}\n\n/**\n * 複数の `CollectionDef` を束ねた CMS クライアントを生成する。\n *\n * 通常はユーザーが直接呼ぶことはなく、CLI 生成の `nhc.ts` の `createCMS`\n * (低レベルのこの関数をラップしたもの) を経由する。\n *\n * @example\n * createCMS({\n * collections: {\n * posts: {\n * source: createNotionCollection({ token, dataSourceId, properties }),\n * slugField: \"slug\",\n * statusField: \"status\",\n * publishedStatuses: [\"公開済み\"],\n * }\n * },\n * cache: memoryCache({ ttlMs: 5 * 60_000 }),\n * });\n */\nexport function createCMS<C extends CollectionsConfig>(\n\topts: CreateCMSOptions<C>,\n): CMSClient<C> {\n\tif (!opts.collections || Object.keys(opts.collections).length === 0) {\n\t\tthrow new CMSError({\n\t\t\tcode: \"core/config_invalid\",\n\t\t\tmessage:\n\t\t\t\t\"createCMS: collections に少なくとも 1 つのコレクションを指定してください。\",\n\t\t\tcontext: { operation: \"createCMS\" },\n\t\t});\n\t}\n\n\tfor (const [name, def] of Object.entries(opts.collections)) {\n\t\tif (!def.source) {\n\t\t\tthrow new CMSError({\n\t\t\t\tcode: \"core/config_invalid\",\n\t\t\t\tmessage: `createCMS: コレクション \"${name}\" の source は必須です。`,\n\t\t\t\tcontext: { operation: \"createCMS\", collection: name },\n\t\t\t});\n\t\t}\n\t\tif (!def.slugField) {\n\t\t\tthrow new CMSError({\n\t\t\t\tcode: \"core/config_invalid\",\n\t\t\t\tmessage: `createCMS: コレクション \"${name}\" の slugField は必須です。`,\n\t\t\t\tcontext: { operation: \"createCMS\", collection: name },\n\t\t\t});\n\t\t}\n\t}\n\n\tconst cacheRes = resolveCache(opts.cache);\n\tconst ttlMs = opts.ttlMs;\n\tconst imageProxyBase = opts.imageProxyBase ?? DEFAULT_IMAGE_PROXY_BASE;\n\tconst contentConfig = opts.content;\n\tconst rendererFn: RendererFn | undefined = opts.renderer;\n\tconst waitUntil = opts.waitUntil;\n\tconst baseLogger: Logger | undefined = mergeLoggers(\n\t\topts.plugins ?? [],\n\t\topts.logger,\n\t);\n\tconst logger = opts.logLevel\n\t\t? applyLogLevel(baseLogger, opts.logLevel)\n\t\t: baseLogger;\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.collections) as (keyof C & 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 def = opts.collections[name];\n\t\tconst source = def.source as DataSource<BaseContentItem>;\n\t\tconst colHooks = def.hooks as CMSHooks<BaseContentItem> | undefined;\n\t\tconst collectionHooks: CMSHooks<BaseContentItem> = colHooks\n\t\t\t? mergeHooks([{ name: `${name}:global`, hooks }], colHooks, logger)\n\t\t\t: hooks;\n\t\tconst renderCtx: RenderContext<BaseContentItem> = {\n\t\t\tsource,\n\t\t\trendererFn,\n\t\t\timgCache: cacheRes.img,\n\t\t\timgCacheName: cacheRes.imgName,\n\t\t\thasImageCache: cacheRes.hasImg,\n\t\t\timageProxyBase,\n\t\t\tcontentConfig,\n\t\t\thooks: collectionHooks,\n\t\t\tlogger,\n\t\t};\n\t\tconst ctx: CollectionContext<BaseContentItem> = {\n\t\t\tcollection: name,\n\t\t\tsource,\n\t\t\tdocCache: cacheRes.doc,\n\t\t\tdocCacheName: cacheRes.docName,\n\t\t\trender: renderCtx,\n\t\t\thooks: collectionHooks,\n\t\t\tlogger,\n\t\t\tttlMs,\n\t\t\tpublishedStatuses: def.publishedStatuses\n\t\t\t\t? [...def.publishedStatuses]\n\t\t\t\t: [],\n\t\t\taccessibleStatuses: def.accessibleStatuses\n\t\t\t\t? [...def.accessibleStatuses]\n\t\t\t\t: [],\n\t\t\tretryConfig,\n\t\t\tmaxConcurrent,\n\t\t\twaitUntil,\n\t\t\tslugField: def.slugField,\n\t\t};\n\t\tcollections[name] = new CollectionClientImpl(ctx);\n\t}\n\n\tconst globalOps: CMSGlobalOps = {\n\t\t$collections: collectionNames,\n\t\tasync $invalidate(scope?: InvalidateScope): Promise<void> {\n\t\t\tlogger?.debug?.(\"グローバルキャッシュを無効化\", {\n\t\t\t\toperation: \"$invalidate\",\n\t\t\t\tcacheAdapter: cacheRes.docName,\n\t\t\t});\n\t\t\tawait cacheRes.doc.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: cacheRes.img,\n\t\t\t\t\tparseWebhook: async (req, webhookSecret) => {\n\t\t\t\t\t\tfor (const name of collectionNames) {\n\t\t\t\t\t\t\tconst ds = opts.collections[name]\n\t\t\t\t\t\t\t\t.source 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, collection } だけの汎用 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.$invalidate(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 cacheRes.img.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<C>;\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/cache/noop.ts","../src/image.ts","../src/rendering.ts","../src/retry.ts","../src/collection.ts","../src/handler.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 type {\n\tBaseContentItem,\n\tCachedItemContent,\n\tCachedItemList,\n\tCachedItemMeta,\n\tDocumentCacheOps,\n\tImageCacheOps,\n\tStorageBinary,\n} from \"../types/index\";\n\n/** 何もキャッシュしないドキュメントオペレーション。常に null を返す。 */\nconst noopDoc: DocumentCacheOps = {\n\tgetList<T extends BaseContentItem>(\n\t\t_collection: string,\n\t): Promise<CachedItemList<T> | null> {\n\t\treturn Promise.resolve(null);\n\t},\n\tsetList<T extends BaseContentItem>(\n\t\t_collection: string,\n\t\t_data: CachedItemList<T>,\n\t): Promise<void> {\n\t\treturn Promise.resolve();\n\t},\n\tgetMeta<T extends BaseContentItem>(\n\t\t_collection: string,\n\t\t_slug: string,\n\t): Promise<CachedItemMeta<T> | null> {\n\t\treturn Promise.resolve(null);\n\t},\n\tsetMeta<T extends BaseContentItem>(\n\t\t_collection: string,\n\t\t_slug: string,\n\t\t_data: CachedItemMeta<T>,\n\t): Promise<void> {\n\t\treturn Promise.resolve();\n\t},\n\tgetContent(\n\t\t_collection: string,\n\t\t_slug: string,\n\t): Promise<CachedItemContent | null> {\n\t\treturn Promise.resolve(null);\n\t},\n\tsetContent(\n\t\t_collection: string,\n\t\t_slug: string,\n\t\t_data: CachedItemContent,\n\t): Promise<void> {\n\t\treturn Promise.resolve();\n\t},\n\tinvalidate(): Promise<void> {\n\t\treturn Promise.resolve();\n\t},\n};\n\n/** 何もキャッシュしない画像オペレーション。 */\nconst noopImg: ImageCacheOps = {\n\tget(_hash: string): Promise<StorageBinary | null> {\n\t\treturn Promise.resolve(null);\n\t},\n\tset(): Promise<void> {\n\t\treturn Promise.resolve();\n\t},\n};\n\n/**\n * 何もキャッシュしないアダプタ。`createCMS({ cache })` 未指定時の内部デフォルト。\n * テストでも使える。\n */\nexport const noopDocOps: DocumentCacheOps = noopDoc;\nexport const noopImgOps: ImageCacheOps = noopImg;\n","import { sha256Hex } from \"./cache\";\nimport { CMSError, isCMSError } from \"./errors\";\nimport type { ImageCacheOps, Logger, 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 * URL → SHA-256 hash のメモ化マップ。\n * Notion の画像 URL は同じ画像でも署名が時刻ごとに変わるが、\n * 1 リクエスト内では同一 URL が複数回現れることが多い (重複ハッシュ計算を回避)。\n *\n * メモリリーク防止に最大エントリ数を設けており、超過時は最古から削除する LRU。\n */\nconst HASH_MEMO_LIMIT = 1024;\nconst hashMemo = new Map<string, string>();\n\nasync function memoSha256(url: string): Promise<string> {\n\tconst cached = hashMemo.get(url);\n\tif (cached !== undefined) {\n\t\t// LRU: アクセスを末尾に移動\n\t\thashMemo.delete(url);\n\t\thashMemo.set(url, cached);\n\t\treturn cached;\n\t}\n\tconst hash = await sha256Hex(url);\n\thashMemo.set(url, hash);\n\tif (hashMemo.size > HASH_MEMO_LIMIT) {\n\t\tconst firstKey = hashMemo.keys().next().value;\n\t\tif (firstKey !== undefined) hashMemo.delete(firstKey);\n\t}\n\treturn hash;\n}\n\n/**\n * Notion画像URLをfetchして ImageCacheOps にキャッシュし、プロキシURL を返す。\n * 既存キャッシュがあれば再fetchしない。\n */\nasync function fetchAndCacheImage(\n\tcache: ImageCacheOps,\n\tcacheName: string,\n\tnotionUrl: string,\n\timageProxyBase: string,\n\tlogger?: Logger,\n): Promise<string> {\n\tconst hash = await memoSha256(notionUrl);\n\tconst proxyUrl = `${imageProxyBase}/${hash}`;\n\n\tconst existing = await cache.get(hash);\n\tif (existing) {\n\t\tlogger?.debug?.(\"画像キャッシュヒット\", {\n\t\t\toperation: \"fetchAndCacheImage\",\n\t\t\tcacheAdapter: cacheName,\n\t\t\timageHash: hash,\n\t\t});\n\t\treturn proxyUrl;\n\t}\n\n\tlogger?.debug?.(\"画像キャッシュミス、Notion からフェッチ\", {\n\t\toperation: \"fetchAndCacheImage\",\n\t\tcacheAdapter: cacheName,\n\t\timageHash: hash,\n\t});\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\tlogger?.debug?.(\"画像をキャッシュに保存\", {\n\t\t\toperation: \"fetchAndCacheImage\",\n\t\t\tcacheAdapter: cacheName,\n\t\t\timageHash: hash,\n\t\t});\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/**\n * `ImageCacheOps` と `imageProxyBase` から `cacheImage` 関数を構築する。\n * 返り値は Notion 画像 URL を受け取り、SHA-256 ハッシュをキャッシュキーとして\n * {@link ImageCacheOps} に保存後、プロキシ URL を返す。\n */\nexport function buildCacheImageFn(\n\tcache: ImageCacheOps,\n\tcacheName: string,\n\timageProxyBase: string,\n\tlogger?: Logger,\n): (notionUrl: string) => Promise<string> {\n\treturn (notionUrl) =>\n\t\tfetchAndCacheImage(cache, cacheName, notionUrl, imageProxyBase, logger);\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\tCachedItemContent,\n\tCachedItemMeta,\n\tCMSHooks,\n\tContentConfig,\n\tDataSource,\n\tImageCacheOps,\n\tLogger,\n\tRendererFn,\n} from \"./types/index\";\n\n/** 本文レンダリングに必要な依存を束ねたコンテキスト。 */\nexport interface RenderContext<T extends BaseContentItem> {\n\tsource: DataSource<T>;\n\trendererFn: RendererFn | undefined;\n\timgCache: ImageCacheOps;\n\timgCacheName: string;\n\thasImageCache: boolean;\n\timageProxyBase: string;\n\tcontentConfig: ContentConfig | undefined;\n\thooks: CMSHooks<T>;\n\tlogger: Logger | undefined;\n}\n\n/**\n * メタデータキャッシュエントリを生成する。Notion API も renderer も呼ばない軽量関数。\n */\nexport function buildCachedItemMeta<T extends BaseContentItem>(\n\titem: T,\n\tsource: DataSource<T>,\n): CachedItemMeta<T> {\n\treturn {\n\t\titem,\n\t\tnotionUpdatedAt: source.getLastModified(item),\n\t\tcachedAt: Date.now(),\n\t};\n}\n\n/**\n * アイテム本文を Markdown ロード → blocks 生成 → HTML レンダリング → フック適用まで\n * 実行し、本文キャッシュ用の `CachedItemContent` を返す。\n */\nexport async function buildCachedItemContent<T extends BaseContentItem>(\n\titem: T,\n\tctx: RenderContext<T>,\n): Promise<CachedItemContent> {\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: \"buildCachedItemContent: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(\n\t\t\t\tctx.imgCache,\n\t\t\t\tctx.imgCacheName,\n\t\t\t\tctx.imageProxyBase,\n\t\t\t\tctx.logger,\n\t\t\t)\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: \"buildCachedItemContent: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: CachedItemContent = {\n\t\thtml,\n\t\tblocks,\n\t\tmarkdown,\n\t\tnotionUpdatedAt: ctx.source.getLastModified(item),\n\t\tcachedAt: Date.now(),\n\t};\n\n\tif (ctx.hooks.beforeCacheContent) {\n\t\tresult = await ctx.hooks.beforeCacheContent(result, item);\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 */\nasync 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/**\n * 指数バックオフ(オプションでジッター付き)でリトライする。\n *\n * `config.retryOn` に含まれるステータスコードを持つエラーのみリトライ対象。\n * 遅延は `baseDelayMs * 2^attempt` の指数バックオフ。\n * `jitter` が `true`(デフォルト)の場合、0.5〜1.0 の乱数係数を乗算して\n * Thundering Herd を防ぐ。`false` にすると確定的な遅延になる。\n */\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 { RenderContext } from \"./rendering\";\nimport { buildCachedItemContent, buildCachedItemMeta } from \"./rendering\";\nimport type { RetryConfig } from \"./retry\";\nimport { withRetry } from \"./retry\";\nimport type {\n\tAdjacencyOptions,\n\tBaseContentItem,\n\tCachedItemContent,\n\tCachedItemList,\n\tCachedItemMeta,\n\tCheckResult,\n\tCMSHooks,\n\tCollectionCacheOps,\n\tCollectionClient,\n\tDataSource,\n\tDocumentCacheOps,\n\tGetOptions,\n\tItemWithRender,\n\tListOptions,\n\tLogger,\n\tSortOption,\n\tWarmOptions,\n} from \"./types/index\";\n\n/**\n * コレクション別キャッシュキーを生成する。\n * item: `{collection}:{slug}` / list: `{collection}`\n *\n * (Cache adapter 内部のキー戦略はアダプタごとに異なるが、\n * 表示や再計算用に core 側でも公開ヘルパーを提供する)\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: DocumentCacheOps;\n\tdocCacheName: string;\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 として使うフィールド名 (CLI 生成の `CollectionDef.slugField`)。\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\treadonly cache: CollectionCacheOps<T>;\n\n\tconstructor(private readonly ctx: CollectionContext<T>) {\n\t\tthis.cache = {\n\t\t\tinvalidate: (slug?: string) => this.invalidateImpl(slug),\n\t\t\twarm: (opts?: WarmOptions) => this.warmImpl(opts),\n\t\t\tadjacent: (slug, opts) => this.adjacentImpl(slug, opts),\n\t\t};\n\t}\n\n\t// ── 基本取得 ──────────────────────────────────────────────────────────\n\n\tasync get(\n\t\tslug: string,\n\t\topts: GetOptions = {},\n\t): Promise<ItemWithRender<T> | null> {\n\t\t// fresh: 強制ブロッキング取得\n\t\tif (opts.fresh) {\n\t\t\tthis.ctx.hooks.onCacheMiss?.(slug);\n\t\t\tconst item = await this.findRaw(slug);\n\t\t\tif (!item) return null;\n\t\t\tconst meta = await this.persistMeta(slug, item);\n\t\t\tawait this.invalidateContent(slug);\n\t\t\treturn this.attachLazyContent(meta);\n\t\t}\n\n\t\tconst cachedMeta = await this.ctx.docCache.getMeta<T>(\n\t\t\tthis.ctx.collection,\n\t\t\tslug,\n\t\t);\n\t\tif (cachedMeta) {\n\t\t\tif (\n\t\t\t\tthis.ctx.ttlMs !== undefined &&\n\t\t\t\tisStale(cachedMeta.cachedAt, this.ctx.ttlMs)\n\t\t\t) {\n\t\t\t\t// TTL 切れ: ブロッキング再取得\n\t\t\t\tthis.ctx.logger?.debug?.(\"キャッシュ期限切れ(TTL)、フェッチ\", {\n\t\t\t\t\toperation: \"get\",\n\t\t\t\t\tslug,\n\t\t\t\t\tcollection: this.ctx.collection,\n\t\t\t\t\tcacheAdapter: this.ctx.docCacheName,\n\t\t\t\t});\n\t\t\t\tthis.ctx.hooks.onCacheMiss?.(slug);\n\t\t\t\tconst item = await this.findRaw(slug);\n\t\t\t\tif (!item) return null;\n\t\t\t\tconst meta = await this.persistMeta(slug, item);\n\t\t\t\tawait this.invalidateContent(slug);\n\t\t\t\treturn this.attachLazyContent(meta);\n\t\t\t}\n\t\t\t// SWR: キャッシュ即時返却 + バックグラウンド差分チェック\n\t\t\tconst bg = this.checkAndUpdateItemBg(slug, cachedMeta);\n\t\t\tif (this.ctx.waitUntil) this.ctx.waitUntil(bg);\n\t\t\tthis.ctx.logger?.debug?.(\"キャッシュヒット\", {\n\t\t\t\toperation: \"get\",\n\t\t\t\tslug,\n\t\t\t\tcollection: this.ctx.collection,\n\t\t\t\tcacheAdapter: this.ctx.docCacheName,\n\t\t\t\tcachedAt: cachedMeta.cachedAt,\n\t\t\t});\n\t\t\tthis.ctx.hooks.onCacheHit?.(slug, cachedMeta);\n\t\t\treturn this.attachLazyContent(cachedMeta);\n\t\t}\n\n\t\t// メタ未キャッシュ: 同期フェッチ (保存はバックグラウンド可)\n\t\tthis.ctx.logger?.debug?.(\"キャッシュミス、フェッチ\", {\n\t\t\toperation: \"get\",\n\t\t\tslug,\n\t\t\tcollection: this.ctx.collection,\n\t\t\tcacheAdapter: this.ctx.docCacheName,\n\t\t});\n\t\tthis.ctx.hooks.onCacheMiss?.(slug);\n\t\tconst item = await this.findRaw(slug);\n\t\tif (!item) return null;\n\t\tconst meta = await this.persistMeta(slug, item, { background: true });\n\t\treturn this.attachLazyContent(meta);\n\t}\n\n\tasync list(opts?: ListOptions<T>): Promise<T[]> {\n\t\tconst allItems = await this.fetchList();\n\t\treturn applyListOptions(allItems, opts);\n\t}\n\n\tasync params(): Promise<{ slug: string }[]> {\n\t\tconst items = await this.fetchList();\n\t\treturn items.map((item) => ({ slug: item.slug }));\n\t}\n\n\tasync check(\n\t\tslug: string,\n\t\tcurrentVersion: string,\n\t): Promise<CheckResult<T> | null> {\n\t\tconst raw = await this.findRaw(slug);\n\t\tif (!raw) return null;\n\t\tif (raw.updatedAt === currentVersion) return { stale: false };\n\t\tconst meta = await this.persistMeta(slug, raw);\n\t\tawait this.invalidateContent(slug);\n\t\treturn { stale: true, item: this.attachLazyContent(meta) };\n\t}\n\n\t// ── キャッシュ操作 ────────────────────────────────────────────────────\n\n\tprivate async invalidateImpl(slug?: string): Promise<void> {\n\t\tif (slug !== undefined) {\n\t\t\tthis.ctx.logger?.debug?.(\"アイテムキャッシュを無効化\", {\n\t\t\t\toperation: \"cache.invalidate\",\n\t\t\t\tcollection: this.ctx.collection,\n\t\t\t\tcacheAdapter: this.ctx.docCacheName,\n\t\t\t\tslug,\n\t\t\t});\n\t\t\tawait this.ctx.docCache.invalidate({\n\t\t\t\tcollection: this.ctx.collection,\n\t\t\t\tslug,\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tthis.ctx.logger?.debug?.(\"コレクション全体のキャッシュを無効化\", {\n\t\t\toperation: \"cache.invalidate\",\n\t\t\tcollection: this.ctx.collection,\n\t\t\tcacheAdapter: this.ctx.docCacheName,\n\t\t});\n\t\tawait this.ctx.docCache.invalidate({ collection: this.ctx.collection });\n\t}\n\n\tprivate async warmImpl(\n\t\topts?: WarmOptions,\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\tawait this.persistMeta(item.slug, item);\n\t\t\t\t\t\tconst content = await buildCachedItemContent(item, this.ctx.render);\n\t\t\t\t\t\tawait this.ctx.docCache.setContent(\n\t\t\t\t\t\t\tthis.ctx.collection,\n\t\t\t\t\t\t\titem.slug,\n\t\t\t\t\t\t\tcontent,\n\t\t\t\t\t\t);\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?.(\"warm: アイテムの事前レンダリングに失敗\", {\n\t\t\t\t\t\t\tslug: item.slug,\n\t\t\t\t\t\t\tpageId: item.id,\n\t\t\t\t\t\t\terror: err instanceof Error ? err.message : String(err),\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(this.ctx.collection, {\n\t\t\titems,\n\t\t\tcachedAt: Date.now(),\n\t\t});\n\t\treturn { ok, failed };\n\t}\n\n\tprivate async adjacentImpl(\n\t\tslug: string,\n\t\topts?: AdjacencyOptions<T>,\n\t): Promise<{ prev: T | null; next: T | null }> {\n\t\tconst items = applyListOptions(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\tprivate async persistMeta(\n\t\tslug: string,\n\t\titem: T,\n\t\topts: { background?: boolean } = {},\n\t): Promise<CachedItemMeta<T>> {\n\t\tlet meta = buildCachedItemMeta(item, this.ctx.source);\n\t\tif (this.ctx.hooks.beforeCacheMeta) {\n\t\t\tmeta = await this.ctx.hooks.beforeCacheMeta(meta);\n\t\t}\n\t\tconst save = this.ctx.docCache.setMeta(this.ctx.collection, slug, meta);\n\t\tif (opts.background && 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 meta;\n\t}\n\n\tprivate async invalidateContent(slug: string): Promise<void> {\n\t\tawait this.ctx.docCache.invalidate({\n\t\t\tcollection: this.ctx.collection,\n\t\t\tslug,\n\t\t\tkind: \"content\",\n\t\t});\n\t}\n\n\t/**\n\t * 本文キャッシュをロードする。キャッシュが無いか、メタとの整合性が取れない場合は\n\t * 再生成して書き戻す。\n\t */\n\tprivate async loadOrBuildContent(\n\t\tslug: string,\n\t\titem: T,\n\t): Promise<CachedItemContent> {\n\t\tconst expected = this.ctx.source.getLastModified(item);\n\t\tconst cached = await this.ctx.docCache.getContent(\n\t\t\tthis.ctx.collection,\n\t\t\tslug,\n\t\t);\n\t\tif (cached && cached.notionUpdatedAt === expected) return cached;\n\n\t\tconst fresh = await buildCachedItemContent(item, this.ctx.render);\n\t\tawait this.ctx.docCache.setContent(this.ctx.collection, slug, fresh);\n\t\tthis.ctx.hooks.onContentRevalidated?.(slug, fresh);\n\t\treturn fresh;\n\t}\n\n\t/** メタ既知の状態で本文だけバックグラウンド再生成する。エラーは握りつぶす。 */\n\tprivate async rebuildContentBg(slug: string, item: T): Promise<void> {\n\t\ttry {\n\t\t\tconst fresh = await buildCachedItemContent(item, this.ctx.render);\n\t\t\tawait this.ctx.docCache.setContent(this.ctx.collection, slug, fresh);\n\t\t\tthis.ctx.hooks.onContentRevalidated?.(slug, fresh);\n\t\t} catch (err) {\n\t\t\tthis.ctx.logger?.warn?.(\"本文のバックグラウンド再生成に失敗\", {\n\t\t\t\tslug,\n\t\t\t\tcollection: this.ctx.collection,\n\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate attachLazyContent(meta: CachedItemMeta<T>): ItemWithRender<T> {\n\t\tconst slug = meta.item.slug;\n\t\tconst item = meta.item;\n\t\t// 同一インスタンス内で本文ロードを集約する (複数 render() でも 1 回の I/O)\n\t\tlet payloadPromise: Promise<CachedItemContent> | undefined;\n\t\tconst loadPayload = (): Promise<CachedItemContent> => {\n\t\t\tif (!payloadPromise) {\n\t\t\t\tpayloadPromise = this.loadOrBuildContent(slug, item);\n\t\t\t}\n\t\t\treturn payloadPromise;\n\t\t};\n\n\t\tconst render = async (opts?: {\n\t\t\tformat?: \"html\" | \"markdown\";\n\t\t}): Promise<string> => {\n\t\t\tconst payload = await loadPayload();\n\t\t\treturn opts?.format === \"markdown\" ? payload.markdown : payload.html;\n\t\t};\n\n\t\treturn Object.assign(Object.create(null) as object, item, {\n\t\t\trender,\n\t\t}) as ItemWithRender<T>;\n\t}\n\n\tprivate async fetchList(): Promise<T[]> {\n\t\tconst cached = await this.ctx.docCache.getList<T>(this.ctx.collection);\n\t\tif (cached) {\n\t\t\tif (\n\t\t\t\tthis.ctx.ttlMs !== undefined &&\n\t\t\t\tisStale(cached.cachedAt, this.ctx.ttlMs)\n\t\t\t) {\n\t\t\t\t// TTL 切れ: ブロッキング再取得\n\t\t\t\tthis.ctx.logger?.debug?.(\"リストキャッシュ期限切れ(TTL)、フェッチ\", {\n\t\t\t\t\toperation: \"list\",\n\t\t\t\t\tcollection: this.ctx.collection,\n\t\t\t\t\tcacheAdapter: this.ctx.docCacheName,\n\t\t\t\t});\n\t\t\t\tthis.ctx.hooks.onListCacheMiss?.();\n\t\t\t\tconst items = await this.fetchListRaw();\n\t\t\t\tawait this.ctx.docCache.setList(this.ctx.collection, {\n\t\t\t\t\titems,\n\t\t\t\t\tcachedAt: Date.now(),\n\t\t\t\t});\n\t\t\t\treturn items;\n\t\t\t}\n\t\t\t// SWR: 即時返却 + バックグラウンド差分チェック\n\t\t\tconst bg = this.checkAndUpdateListBg(cached);\n\t\t\tif (this.ctx.waitUntil) this.ctx.waitUntil(bg);\n\t\t\tthis.ctx.logger?.debug?.(\"リストキャッシュヒット\", {\n\t\t\t\toperation: \"list\",\n\t\t\t\tcollection: this.ctx.collection,\n\t\t\t\tcacheAdapter: this.ctx.docCacheName,\n\t\t\t});\n\t\t\tthis.ctx.hooks.onListCacheHit?.(cached);\n\t\t\treturn cached.items;\n\t\t}\n\n\t\t// 未キャッシュ: 同期フェッチ\n\t\tthis.ctx.logger?.debug?.(\"リストキャッシュミス、フェッチ\", {\n\t\t\toperation: \"list\",\n\t\t\tcollection: this.ctx.collection,\n\t\t\tcacheAdapter: this.ctx.docCacheName,\n\t\t});\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(this.ctx.collection, {\n\t\t\titems,\n\t\t\tcachedAt,\n\t\t});\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 async checkAndUpdateItemBg(\n\t\tslug: string,\n\t\tcached: CachedItemMeta<T>,\n\t): Promise<void> {\n\t\ttry {\n\t\t\tconst item = await this.findRaw(slug);\n\t\t\tif (!item) return;\n\t\t\tconst lm = this.ctx.source.getLastModified(item);\n\t\t\tif (lm !== cached.notionUpdatedAt) {\n\t\t\t\tconst meta = await this.persistMeta(slug, item);\n\t\t\t\tawait this.invalidateContent(slug);\n\t\t\t\tthis.ctx.logger?.debug?.(\"SWR: 差分を検出、メタを差し替え\", {\n\t\t\t\t\toperation: \"get:bg\",\n\t\t\t\t\tslug,\n\t\t\t\t\tcollection: this.ctx.collection,\n\t\t\t\t\tnotionUpdatedAt: cached.notionUpdatedAt,\n\t\t\t\t});\n\t\t\t\tthis.ctx.hooks.onCacheRevalidated?.(slug, meta);\n\t\t\t\tawait this.rebuildContentBg(slug, item);\n\t\t\t} else if (this.ctx.ttlMs !== undefined) {\n\t\t\t\t// 変更なし + TTL あり: cachedAt をリセットして次回の期限切れを先送りする\n\t\t\t\tawait this.ctx.docCache.setMeta(this.ctx.collection, slug, {\n\t\t\t\t\t...cached,\n\t\t\t\t\tcachedAt: Date.now(),\n\t\t\t\t});\n\t\t\t\tthis.ctx.logger?.debug?.(\"SWR: 差分なし、TTL をリセット\", {\n\t\t\t\t\toperation: \"get:bg\",\n\t\t\t\t\tslug,\n\t\t\t\t\tcollection: this.ctx.collection,\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tthis.ctx.logger?.warn?.(\n\t\t\t\t\"SWR: アイテムのバックグラウンド差分チェックに失敗\",\n\t\t\t\t{\n\t\t\t\t\tslug,\n\t\t\t\t\tcollection: this.ctx.collection,\n\t\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate async checkAndUpdateListBg(cached: CachedItemList<T>): Promise<void> {\n\t\ttry {\n\t\t\tconst items = await this.fetchListRaw();\n\t\t\tif (\n\t\t\t\tthis.ctx.source.getListVersion(items) !==\n\t\t\t\tthis.ctx.source.getListVersion(cached.items)\n\t\t\t) {\n\t\t\t\tconst listEntry = { items, cachedAt: Date.now() };\n\t\t\t\tawait this.ctx.docCache.setList(this.ctx.collection, listEntry);\n\t\t\t\tthis.ctx.logger?.debug?.(\n\t\t\t\t\t\"SWR: リスト差分を検出、キャッシュを差し替え\",\n\t\t\t\t\t{\n\t\t\t\t\t\toperation: \"list:bg\",\n\t\t\t\t\t\tcollection: this.ctx.collection,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tthis.ctx.hooks.onListCacheRevalidated?.(listEntry);\n\t\t\t} else if (this.ctx.ttlMs !== undefined) {\n\t\t\t\tawait this.ctx.docCache.setList(this.ctx.collection, {\n\t\t\t\t\t...cached,\n\t\t\t\t\tcachedAt: Date.now(),\n\t\t\t\t});\n\t\t\t\tthis.ctx.logger?.debug?.(\"SWR: リスト差分なし、TTL をリセット\", {\n\t\t\t\t\toperation: \"list:bg\",\n\t\t\t\t\tcollection: this.ctx.collection,\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tthis.ctx.logger?.warn?.(\n\t\t\t\t\"SWR: リストのバックグラウンド差分チェックに失敗\",\n\t\t\t\t{\n\t\t\t\t\tcollection: this.ctx.collection,\n\t\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\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?.(\"list() リトライ中\", { 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?.(\"get() リトライ中\", {\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// slugField から Notion プロパティ名を解決して効率的なフィルタクエリを実行する。\n\t\tconst notionPropName =\n\t\t\tthis.ctx.source.properties?.[this.ctx.slugField]?.notion;\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 applyListOptions<T extends BaseContentItem>(\n\titems: T[],\n\topts?: ListOptions<T>,\n): T[] {\n\tif (!opts) return items;\n\tlet result = items;\n\n\tif (opts.status) {\n\t\tconst allow = new Set(\n\t\t\tArray.isArray(opts.status) ? opts.status : [opts.status],\n\t\t);\n\t\tresult = result.filter((it) => it.status != null && allow.has(it.status));\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.dir === \"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 { ImageCacheOps, 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: ImageCacheOps;\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 { noopDocOps, noopImgOps } 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 type { RenderContext } from \"./rendering\";\nimport type { RetryConfig } from \"./retry\";\nimport { DEFAULT_RETRY_CONFIG } from \"./retry\";\nimport type {\n\tBaseContentItem,\n\tCacheAdapter,\n\tCMSHooks,\n\tCollectionClient,\n\tCollectionsConfig,\n\tCreateCMSOptions,\n\tDataSource,\n\tDocumentCacheOps,\n\tImageCacheOps,\n\tInferCollectionItem,\n\tInvalidateScope,\n\tLogger,\n\tLogLevel,\n\tRendererFn,\n\tStorageBinary,\n} from \"./types/index\";\n\nconst DEFAULT_IMAGE_PROXY_BASE = \"/api/images\";\n\n/** `CMSClient<C>` — コレクション別アクセス + グローバル操作の合成型。 */\nexport type CMSClient<C extends CollectionsConfig> = {\n\t[K in keyof C]: CollectionClient<InferCollectionItem<C[K]>>;\n} & CMSGlobalOps;\n\n/** `CMSClient` のグローバル名前空間。`$` プレフィックス。 */\nexport interface CMSGlobalOps {\n\t/** 登録されているコレクション名の一覧。 */\n\treadonly $collections: readonly string[];\n\t/** 全コレクションまたは特定スコープのキャッシュを無効化する。 */\n\t$invalidate(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): Promise<StorageBinary | null>;\n}\n\ninterface ResolvedCache {\n\tdoc: DocumentCacheOps;\n\tdocName: string;\n\timg: ImageCacheOps;\n\timgName: string;\n\thasImg: boolean;\n}\n\n/**\n * `cache` オプションから document / image オペレーションを解決する。\n *\n * - 配列で渡された場合は各 adapter の `handles` を見て先勝ち (最初に見つかったもの) で振り分ける\n * - 単体で渡された場合は `handles` の領域だけ反映、片側は noop\n * - 未指定なら両方 noop\n */\nfunction resolveCache(\n\tcache: CacheAdapter | readonly CacheAdapter[] | undefined,\n): ResolvedCache {\n\tconst adapters =\n\t\tcache === undefined ? [] : Array.isArray(cache) ? cache : [cache];\n\n\tlet doc: DocumentCacheOps = noopDocOps;\n\tlet docName = \"noop-document\";\n\tlet img: ImageCacheOps = noopImgOps;\n\tlet imgName = \"noop-image\";\n\tlet docFound = false;\n\tlet imgFound = false;\n\n\tfor (const adapter of adapters) {\n\t\tif (!docFound && adapter.handles.includes(\"document\") && adapter.doc) {\n\t\t\tdoc = adapter.doc;\n\t\t\tdocName = adapter.name;\n\t\t\tdocFound = true;\n\t\t}\n\t\tif (!imgFound && adapter.handles.includes(\"image\") && adapter.img) {\n\t\t\timg = adapter.img;\n\t\t\timgName = adapter.name;\n\t\t\timgFound = true;\n\t\t}\n\t}\n\n\treturn { doc, docName, img, imgName, hasImg: imgFound };\n}\n\nconst LOG_LEVEL_ORDER: Record<LogLevel, number> = {\n\tdebug: 0,\n\tinfo: 1,\n\twarn: 2,\n\terror: 3,\n};\n\n/** `logger` から `minLevel` 未満のレベルを除いた新しい Logger を返す。 */\nfunction applyLogLevel(\n\tlogger: Logger | undefined,\n\tminLevel: LogLevel,\n): Logger | undefined {\n\tif (!logger) return undefined;\n\tconst minOrder = LOG_LEVEL_ORDER[minLevel];\n\tconst filtered: Logger = {};\n\tfor (const level of [\"debug\", \"info\", \"warn\", \"error\"] as const) {\n\t\tif (LOG_LEVEL_ORDER[level] >= minOrder) {\n\t\t\tfiltered[level] = logger[level];\n\t\t}\n\t}\n\treturn filtered;\n}\n\n/**\n * 複数の `CollectionDef` を束ねた CMS クライアントを生成する。\n *\n * 通常はユーザーが直接呼ぶことはなく、CLI 生成の `nhc.ts` の `createCMS`\n * (低レベルのこの関数をラップしたもの) を経由する。\n *\n * @example\n * createCMS({\n * collections: {\n * posts: {\n * source: createNotionCollection({ token, dataSourceId, properties }),\n * slugField: \"slug\",\n * statusField: \"status\",\n * publishedStatuses: [\"公開済み\"],\n * }\n * },\n * cache: memoryCache({ ttlMs: 5 * 60_000 }),\n * });\n */\nexport function createCMS<C extends CollectionsConfig>(\n\topts: CreateCMSOptions<C>,\n): CMSClient<C> {\n\tif (!opts.collections || Object.keys(opts.collections).length === 0) {\n\t\tthrow new CMSError({\n\t\t\tcode: \"core/config_invalid\",\n\t\t\tmessage:\n\t\t\t\t\"createCMS: collections に少なくとも 1 つのコレクションを指定してください。\",\n\t\t\tcontext: { operation: \"createCMS\" },\n\t\t});\n\t}\n\n\tfor (const [name, def] of Object.entries(opts.collections)) {\n\t\tif (!def.source) {\n\t\t\tthrow new CMSError({\n\t\t\t\tcode: \"core/config_invalid\",\n\t\t\t\tmessage: `createCMS: コレクション \"${name}\" の source は必須です。`,\n\t\t\t\tcontext: { operation: \"createCMS\", collection: name },\n\t\t\t});\n\t\t}\n\t\tif (!def.slugField) {\n\t\t\tthrow new CMSError({\n\t\t\t\tcode: \"core/config_invalid\",\n\t\t\t\tmessage: `createCMS: コレクション \"${name}\" の slugField は必須です。`,\n\t\t\t\tcontext: { operation: \"createCMS\", collection: name },\n\t\t\t});\n\t\t}\n\t}\n\n\tconst cacheRes = resolveCache(opts.cache);\n\tconst ttlMs = opts.ttlMs;\n\tconst imageProxyBase = opts.imageProxyBase ?? DEFAULT_IMAGE_PROXY_BASE;\n\tconst contentConfig = opts.content;\n\tconst rendererFn: RendererFn | undefined = opts.renderer;\n\tconst waitUntil = opts.waitUntil;\n\tconst baseLogger: Logger | undefined = mergeLoggers(\n\t\topts.plugins ?? [],\n\t\topts.logger,\n\t);\n\tconst logger = opts.logLevel\n\t\t? applyLogLevel(baseLogger, opts.logLevel)\n\t\t: baseLogger;\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.collections) as (keyof C & 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 def = opts.collections[name];\n\t\tconst source = def.source as DataSource<BaseContentItem>;\n\t\tconst colHooks = def.hooks as CMSHooks<BaseContentItem> | undefined;\n\t\tconst collectionHooks: CMSHooks<BaseContentItem> = colHooks\n\t\t\t? mergeHooks([{ name: `${name}:global`, hooks }], colHooks, logger)\n\t\t\t: hooks;\n\t\tconst renderCtx: RenderContext<BaseContentItem> = {\n\t\t\tsource,\n\t\t\trendererFn,\n\t\t\timgCache: cacheRes.img,\n\t\t\timgCacheName: cacheRes.imgName,\n\t\t\thasImageCache: cacheRes.hasImg,\n\t\t\timageProxyBase,\n\t\t\tcontentConfig,\n\t\t\thooks: collectionHooks,\n\t\t\tlogger,\n\t\t};\n\t\tconst ctx: CollectionContext<BaseContentItem> = {\n\t\t\tcollection: name,\n\t\t\tsource,\n\t\t\tdocCache: cacheRes.doc,\n\t\t\tdocCacheName: cacheRes.docName,\n\t\t\trender: renderCtx,\n\t\t\thooks: collectionHooks,\n\t\t\tlogger,\n\t\t\tttlMs,\n\t\t\tpublishedStatuses: def.publishedStatuses\n\t\t\t\t? [...def.publishedStatuses]\n\t\t\t\t: [],\n\t\t\taccessibleStatuses: def.accessibleStatuses\n\t\t\t\t? [...def.accessibleStatuses]\n\t\t\t\t: [],\n\t\t\tretryConfig,\n\t\t\tmaxConcurrent,\n\t\t\twaitUntil,\n\t\t\tslugField: def.slugField,\n\t\t};\n\t\tcollections[name] = new CollectionClientImpl(ctx);\n\t}\n\n\tconst globalOps: CMSGlobalOps = {\n\t\t$collections: collectionNames,\n\t\tasync $invalidate(scope?: InvalidateScope): Promise<void> {\n\t\t\tlogger?.debug?.(\"グローバルキャッシュを無効化\", {\n\t\t\t\toperation: \"$invalidate\",\n\t\t\t\tcacheAdapter: cacheRes.docName,\n\t\t\t});\n\t\t\tawait cacheRes.doc.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: cacheRes.img,\n\t\t\t\t\tparseWebhook: async (req, webhookSecret) => {\n\t\t\t\t\t\tfor (const name of collectionNames) {\n\t\t\t\t\t\t\tconst ds = opts.collections[name]\n\t\t\t\t\t\t\t\t.source 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, collection } だけの汎用 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.$invalidate(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 cacheRes.img.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<C>;\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":";;;;;AACA,eAAsB,UAAU,OAAgC;CAC/D,MAAM,OAAO,IAAI,aAAa,CAAC,OAAO,MAAM;CAC5C,MAAM,OAAO,MAAM,OAAO,OAAO,OAAO,WAAW,KAAK;AACxD,QAAO,MAAM,KAAK,IAAI,WAAW,KAAK,CAAC,CACrC,KAAK,MAAM,EAAE,SAAS,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,CAC3C,KAAK,GAAG;;;;;;AAOX,SAAgB,QAAQ,UAAkB,OAAyB;AAClE,KAAI,UAAU,KAAA,EAAW,QAAO;AAChC,QAAO,KAAK,KAAK,GAAG,WAAW;;;;;ACJhC,MAAM,UAA4B;CACjC,QACC,aACoC;AACpC,SAAO,QAAQ,QAAQ,KAAK;;CAE7B,QACC,aACA,OACgB;AAChB,SAAO,QAAQ,SAAS;;CAEzB,QACC,aACA,OACoC;AACpC,SAAO,QAAQ,QAAQ,KAAK;;CAE7B,QACC,aACA,OACA,OACgB;AAChB,SAAO,QAAQ,SAAS;;CAEzB,WACC,aACA,OACoC;AACpC,SAAO,QAAQ,QAAQ,KAAK;;CAE7B,WACC,aACA,OACA,OACgB;AAChB,SAAO,QAAQ,SAAS;;CAEzB,aAA4B;AAC3B,SAAO,QAAQ,SAAS;;CAEzB;;AAGD,MAAM,UAAyB;CAC9B,IAAI,OAA8C;AACjD,SAAO,QAAQ,QAAQ,KAAK;;CAE7B,MAAqB;AACpB,SAAO,QAAQ,SAAS;;CAEzB;;;;;AAMD,MAAa,aAA+B;AAC5C,MAAa,aAA4B;;;;AChEzC,SAAS,iBACR,KACA,qBACS;AACT,KAAI,qBAAqB,WAAW,SAAS,CAC5C,QAAO,oBAAoB,MAAM,IAAI,CAAC,GAAG,MAAM;AAEhD,KAAI,IAAI,SAAS,OAAO,CAAE,QAAO;AACjC,KAAI,IAAI,SAAS,OAAO,CAAE,QAAO;AACjC,KAAI,IAAI,SAAS,QAAQ,CAAE,QAAO;AAClC,QAAO;;;;;;;;;AAUR,MAAM,kBAAkB;AACxB,MAAM,2BAAW,IAAI,KAAqB;AAE1C,eAAe,WAAW,KAA8B;CACvD,MAAM,SAAS,SAAS,IAAI,IAAI;AAChC,KAAI,WAAW,KAAA,GAAW;AAEzB,WAAS,OAAO,IAAI;AACpB,WAAS,IAAI,KAAK,OAAO;AACzB,SAAO;;CAER,MAAM,OAAO,MAAM,UAAU,IAAI;AACjC,UAAS,IAAI,KAAK,KAAK;AACvB,KAAI,SAAS,OAAO,iBAAiB;EACpC,MAAM,WAAW,SAAS,MAAM,CAAC,MAAM,CAAC;AACxC,MAAI,aAAa,KAAA,EAAW,UAAS,OAAO,SAAS;;AAEtD,QAAO;;;;;;AAOR,eAAe,mBACd,OACA,WACA,WACA,gBACA,QACkB;CAClB,MAAM,OAAO,MAAM,WAAW,UAAU;CACxC,MAAM,WAAW,GAAG,eAAe,GAAG;AAGtC,KAAI,MADmB,MAAM,IAAI,KAAK,EACxB;AACb,UAAQ,QAAQ,cAAc;GAC7B,WAAW;GACX,cAAc;GACd,WAAW;GACX,CAAC;AACF,SAAO;;AAGR,SAAQ,QAAQ,2BAA2B;EAC1C,WAAW;EACX,cAAc;EACd,WAAW;EACX,CAAC;AAEF,KAAI;EACH,MAAM,WAAW,MAAM,MAAM,WAAW,EACvC,QAAQ,YAAY,QAAQ,IAAO,EACnC,CAAC;AACF,MAAI,CAAC,SAAS,GACb,OAAM,IAAI,SAAS;GAClB,MAAM;GACN,SAAS,sCAAsC,SAAS;GACxD,SAAS;IACR,WAAW;IACX;IACA,YAAY,SAAS;IACrB;GACD,CAAC;EAGH,MAAM,OAAO,MAAM,SAAS,aAAa;EACzC,MAAM,cAAc,iBACnB,WACA,SAAS,QAAQ,IAAI,eAAe,CACpC;AACD,QAAM,MAAM,IAAI,MAAM,MAAM,YAAY;AACxC,UAAQ,QAAQ,eAAe;GAC9B,WAAW;GACX,cAAc;GACd,WAAW;GACX,CAAC;UACM,KAAK;AACb,MAAI,WAAW,IAAI,CAAE,OAAM;AAC3B,QAAM,IAAI,SAAS;GAClB,MAAM;GACN,SAAS;GACT,OAAO;GACP,SAAS;IAAE,WAAW;IAAsB;IAAW;GACvD,CAAC;;AAGH,QAAO;;;;;;;AAQR,SAAgB,kBACf,OACA,WACA,gBACA,QACyC;AACzC,SAAQ,cACP,mBAAmB,OAAO,WAAW,WAAW,gBAAgB,OAAO;;;;;;;AChGzE,SAAgB,oBACf,MACA,QACoB;AACpB,QAAO;EACN;EACA,iBAAiB,OAAO,gBAAgB,KAAK;EAC7C,UAAU,KAAK,KAAK;EACpB;;;;;;AAOF,eAAsB,uBACrB,MACA,KAC6B;CAC7B,MAAM,QAAQ,KAAK,KAAK;AACxB,KAAI,QAAQ,OAAO,kBAAkB;EACpC,MAAM,KAAK;EACX,QAAQ,KAAK;EACb,CAAC;AACF,KAAI,MAAM,gBAAgB,KAAK,KAAK;CAEpC,IAAI;AACJ,KAAI;AACH,aAAW,MAAM,IAAI,OAAO,aAAa,KAAK;UACtC,KAAK;AACb,MAAI,WAAW,IAAI,CAAE,OAAM;AAC3B,QAAM,IAAI,SAAS;GAClB,MAAM;GACN,SAAS;GACT,OAAO;GACP,SAAS;IACR,WAAW;IACX,QAAQ,KAAK;IACb,MAAM,KAAK;IACX;GACD,CAAC;;CAGH,IAAI,SAAyB,EAAE;AAC/B,KAAI;AACH,WAAS,MAAM,IAAI,OAAO,WAAW,KAAK;UAClC,KAAK;AACb,MAAI,QAAQ,OAAO,kCAAkC;GACpD,MAAM,KAAK;GACX,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;GACvD,CAAC;AACF,WAAS,EAAE;;CAGZ,MAAM,aAAa,IAAI,gBACpB,kBACA,IAAI,UACJ,IAAI,cACJ,IAAI,gBACJ,IAAI,OACJ,GACA,KAAA;CAEH,IAAI;CACJ,MAAM,aAAa,IAAI,cAAe,MAAM,qBAAqB;AACjE,KAAI;AACH,SAAO,MAAM,WAAW,UAAU;GACjC,gBAAgB,IAAI;GACpB;GACA,eAAe,IAAI,eAAe;GAClC,eAAe,IAAI,eAAe;GAClC,CAAC;UACM,KAAK;AACb,MAAI,WAAW,IAAI,CAAE,OAAM;AAC3B,QAAM,IAAI,SAAS;GAClB,MAAM;GACN,SAAS;GACT,OAAO;GACP,SAAS;IACR,WAAW;IACX,QAAQ,KAAK;IACb,MAAM,KAAK;IACX;GACD,CAAC;;AAGH,KAAI,IAAI,MAAM,YACb,QAAO,MAAM,IAAI,MAAM,YAAY,MAAM,KAAK;CAG/C,IAAI,SAA4B;EAC/B;EACA;EACA;EACA,iBAAiB,IAAI,OAAO,gBAAgB,KAAK;EACjD,UAAU,KAAK,KAAK;EACpB;AAED,KAAI,IAAI,MAAM,mBACb,UAAS,MAAM,IAAI,MAAM,mBAAmB,QAAQ,KAAK;CAG1D,MAAM,aAAa,KAAK,KAAK,GAAG;AAChC,KAAI,QAAQ,OAAO,kBAAkB;EACpC,MAAM,KAAK;EACX;EACA,CAAC;AACF,KAAI,MAAM,cAAc,KAAK,MAAM,WAAW;AAE9C,QAAO;;;;;;;AAQR,eAAe,sBAA2C;AACzD,KAAI;AAEH,UAAO,MADW,OAAO,kCACd;UACH,KAAK;AACb,QAAM,IAAI,SAAS;GAClB,MAAM;GACN,SACC;GAED,OAAO;GACP,SAAS,EAAE,WAAW,uBAAuB;GAC7C,CAAC;;;;;ACvJJ,MAAa,uBAAoC;CAChD,SAAS;EAAC;EAAK;EAAK;EAAI;CACxB,YAAY;CACZ,aAAa;CACb,QAAQ;CACR;;;;;;;;;AAUD,eAAsB,UACrB,IACA,QACa;CACb,IAAI;AACJ,MAAK,IAAI,UAAU,GAAG,WAAW,OAAO,YAAY,UACnD,KAAI;AACH,SAAO,MAAM,IAAI;UACT,KAAK;EACb,MAAM,SAAU,IAA4B;AAC5C,MAAI,WAAW,KAAA,KAAa,CAAC,OAAO,QAAQ,SAAS,OAAO,CAC3D,OAAM;AAEP,cAAY;AACZ,MAAI,UAAU,OAAO,YAAY;AAChC,UAAO,UAAU,UAAU,GAAG,OAAO;GACrC,MAAM,eACL,OAAO,WAAW,QAAQ,KAAM,KAAK,QAAQ,GAAG,KAAM;GACvD,MAAM,QAAQ,OAAO,cAAc,KAAK,UAAU;AAClD,SAAM,IAAI,SAAS,YAAY,WAAW,SAAS,MAAM,CAAC;;;AAI7D,OAAM;;;;;;;;;;;ACfP,SAAgB,cAAc,YAAoB,MAAuB;AACxE,QAAO,OAAO,GAAG,WAAW,GAAG,SAAS;;;AA2BzC,IAAa,uBAAb,MAEA;CACC;CAEA,YAAY,KAA4C;AAA3B,OAAA,MAAA;AAC5B,OAAK,QAAQ;GACZ,aAAa,SAAkB,KAAK,eAAe,KAAK;GACxD,OAAO,SAAuB,KAAK,SAAS,KAAK;GACjD,WAAW,MAAM,SAAS,KAAK,aAAa,MAAM,KAAK;GACvD;;CAKF,MAAM,IACL,MACA,OAAmB,EAAE,EACe;AAEpC,MAAI,KAAK,OAAO;AACf,QAAK,IAAI,MAAM,cAAc,KAAK;GAClC,MAAM,OAAO,MAAM,KAAK,QAAQ,KAAK;AACrC,OAAI,CAAC,KAAM,QAAO;GAClB,MAAM,OAAO,MAAM,KAAK,YAAY,MAAM,KAAK;AAC/C,SAAM,KAAK,kBAAkB,KAAK;AAClC,UAAO,KAAK,kBAAkB,KAAK;;EAGpC,MAAM,aAAa,MAAM,KAAK,IAAI,SAAS,QAC1C,KAAK,IAAI,YACT,KACA;AACD,MAAI,YAAY;AACf,OACC,KAAK,IAAI,UAAU,KAAA,KACnB,QAAQ,WAAW,UAAU,KAAK,IAAI,MAAM,EAC3C;AAED,SAAK,IAAI,QAAQ,QAAQ,uBAAuB;KAC/C,WAAW;KACX;KACA,YAAY,KAAK,IAAI;KACrB,cAAc,KAAK,IAAI;KACvB,CAAC;AACF,SAAK,IAAI,MAAM,cAAc,KAAK;IAClC,MAAM,OAAO,MAAM,KAAK,QAAQ,KAAK;AACrC,QAAI,CAAC,KAAM,QAAO;IAClB,MAAM,OAAO,MAAM,KAAK,YAAY,MAAM,KAAK;AAC/C,UAAM,KAAK,kBAAkB,KAAK;AAClC,WAAO,KAAK,kBAAkB,KAAK;;GAGpC,MAAM,KAAK,KAAK,qBAAqB,MAAM,WAAW;AACtD,OAAI,KAAK,IAAI,UAAW,MAAK,IAAI,UAAU,GAAG;AAC9C,QAAK,IAAI,QAAQ,QAAQ,YAAY;IACpC,WAAW;IACX;IACA,YAAY,KAAK,IAAI;IACrB,cAAc,KAAK,IAAI;IACvB,UAAU,WAAW;IACrB,CAAC;AACF,QAAK,IAAI,MAAM,aAAa,MAAM,WAAW;AAC7C,UAAO,KAAK,kBAAkB,WAAW;;AAI1C,OAAK,IAAI,QAAQ,QAAQ,gBAAgB;GACxC,WAAW;GACX;GACA,YAAY,KAAK,IAAI;GACrB,cAAc,KAAK,IAAI;GACvB,CAAC;AACF,OAAK,IAAI,MAAM,cAAc,KAAK;EAClC,MAAM,OAAO,MAAM,KAAK,QAAQ,KAAK;AACrC,MAAI,CAAC,KAAM,QAAO;EAClB,MAAM,OAAO,MAAM,KAAK,YAAY,MAAM,MAAM,EAAE,YAAY,MAAM,CAAC;AACrE,SAAO,KAAK,kBAAkB,KAAK;;CAGpC,MAAM,KAAK,MAAqC;AAE/C,SAAO,iBAAiB,MADD,KAAK,WAAW,EACL,KAAK;;CAGxC,MAAM,SAAsC;AAE3C,UAAO,MADa,KAAK,WAAW,EACvB,KAAK,UAAU,EAAE,MAAM,KAAK,MAAM,EAAE;;CAGlD,MAAM,MACL,MACA,gBACiC;EACjC,MAAM,MAAM,MAAM,KAAK,QAAQ,KAAK;AACpC,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI,IAAI,cAAc,eAAgB,QAAO,EAAE,OAAO,OAAO;EAC7D,MAAM,OAAO,MAAM,KAAK,YAAY,MAAM,IAAI;AAC9C,QAAM,KAAK,kBAAkB,KAAK;AAClC,SAAO;GAAE,OAAO;GAAM,MAAM,KAAK,kBAAkB,KAAK;GAAE;;CAK3D,MAAc,eAAe,MAA8B;AAC1D,MAAI,SAAS,KAAA,GAAW;AACvB,QAAK,IAAI,QAAQ,QAAQ,iBAAiB;IACzC,WAAW;IACX,YAAY,KAAK,IAAI;IACrB,cAAc,KAAK,IAAI;IACvB;IACA,CAAC;AACF,SAAM,KAAK,IAAI,SAAS,WAAW;IAClC,YAAY,KAAK,IAAI;IACrB;IACA,CAAC;AACF;;AAED,OAAK,IAAI,QAAQ,QAAQ,sBAAsB;GAC9C,WAAW;GACX,YAAY,KAAK,IAAI;GACrB,cAAc,KAAK,IAAI;GACvB,CAAC;AACF,QAAM,KAAK,IAAI,SAAS,WAAW,EAAE,YAAY,KAAK,IAAI,YAAY,CAAC;;CAGxE,MAAc,SACb,MAC0C;EAC1C,MAAM,QAAQ,MAAM,KAAK,cAAc;EACvC,MAAM,cAAc,MAAM,eAAe,KAAK,IAAI;EAClD,IAAI,KAAK;EACT,IAAI,SAAS;AAEb,OAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,aAAa;GACnD,MAAM,QAAQ,MAAM,MAAM,GAAG,IAAI,YAAY;AAC7C,SAAM,QAAQ,IACb,MAAM,IAAI,OAAO,SAAS;AACzB,QAAI;AACH,WAAM,KAAK,YAAY,KAAK,MAAM,KAAK;KACvC,MAAM,UAAU,MAAM,uBAAuB,MAAM,KAAK,IAAI,OAAO;AACnE,WAAM,KAAK,IAAI,SAAS,WACvB,KAAK,IAAI,YACT,KAAK,MACL,QACA;AACD;aACQ,KAAK;AACb;AACA,UAAK,IAAI,QAAQ,OAAO,0BAA0B;MACjD,MAAM,KAAK;MACX,QAAQ,KAAK;MACb,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;MACvD,CAAC;;KAEF,CACF;AACD,SAAM,aAAa,KAAK,IAAI,IAAI,aAAa,MAAM,OAAO,EAAE,MAAM,OAAO;;AAG1E,QAAM,KAAK,IAAI,SAAS,QAAQ,KAAK,IAAI,YAAY;GACpD;GACA,UAAU,KAAK,KAAK;GACpB,CAAC;AACF,SAAO;GAAE;GAAI;GAAQ;;CAGtB,MAAc,aACb,MACA,MAC8C;EAC9C,MAAM,QAAQ,iBAAiB,MAAM,KAAK,WAAW,EAAE,EACtD,MAAM,MAAM,MACZ,CAAC;EACF,MAAM,QAAQ,MAAM,WAAW,OAAO,GAAG,SAAS,KAAK;AACvD,MAAI,UAAU,GAAI,QAAO;GAAE,MAAM;GAAM,MAAM;GAAM;AACnD,SAAO;GACN,MAAM,QAAQ,IAAK,MAAM,QAAQ,MAAM,OAAQ;GAC/C,MAAM,QAAQ,MAAM,SAAS,IAAK,MAAM,QAAQ,MAAM,OAAQ;GAC9D;;CAKF,MAAc,YACb,MACA,MACA,OAAiC,EAAE,EACN;EAC7B,IAAI,OAAO,oBAAoB,MAAM,KAAK,IAAI,OAAO;AACrD,MAAI,KAAK,IAAI,MAAM,gBAClB,QAAO,MAAM,KAAK,IAAI,MAAM,gBAAgB,KAAK;EAElD,MAAM,OAAO,KAAK,IAAI,SAAS,QAAQ,KAAK,IAAI,YAAY,MAAM,KAAK;AACvE,MAAI,KAAK,cAAc,KAAK,IAAI,UAC/B,MAAK,IAAI,UAAU,KAAK;MAExB,OAAM;AAEP,SAAO;;CAGR,MAAc,kBAAkB,MAA6B;AAC5D,QAAM,KAAK,IAAI,SAAS,WAAW;GAClC,YAAY,KAAK,IAAI;GACrB;GACA,MAAM;GACN,CAAC;;;;;;CAOH,MAAc,mBACb,MACA,MAC6B;EAC7B,MAAM,WAAW,KAAK,IAAI,OAAO,gBAAgB,KAAK;EACtD,MAAM,SAAS,MAAM,KAAK,IAAI,SAAS,WACtC,KAAK,IAAI,YACT,KACA;AACD,MAAI,UAAU,OAAO,oBAAoB,SAAU,QAAO;EAE1D,MAAM,QAAQ,MAAM,uBAAuB,MAAM,KAAK,IAAI,OAAO;AACjE,QAAM,KAAK,IAAI,SAAS,WAAW,KAAK,IAAI,YAAY,MAAM,MAAM;AACpE,OAAK,IAAI,MAAM,uBAAuB,MAAM,MAAM;AAClD,SAAO;;;CAIR,MAAc,iBAAiB,MAAc,MAAwB;AACpE,MAAI;GACH,MAAM,QAAQ,MAAM,uBAAuB,MAAM,KAAK,IAAI,OAAO;AACjE,SAAM,KAAK,IAAI,SAAS,WAAW,KAAK,IAAI,YAAY,MAAM,MAAM;AACpE,QAAK,IAAI,MAAM,uBAAuB,MAAM,MAAM;WAC1C,KAAK;AACb,QAAK,IAAI,QAAQ,OAAO,qBAAqB;IAC5C;IACA,YAAY,KAAK,IAAI;IACrB,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;IACvD,CAAC;;;CAIJ,kBAA0B,MAA4C;EACrE,MAAM,OAAO,KAAK,KAAK;EACvB,MAAM,OAAO,KAAK;EAElB,IAAI;EACJ,MAAM,oBAAgD;AACrD,OAAI,CAAC,eACJ,kBAAiB,KAAK,mBAAmB,MAAM,KAAK;AAErD,UAAO;;EAGR,MAAM,SAAS,OAAO,SAEC;GACtB,MAAM,UAAU,MAAM,aAAa;AACnC,UAAO,MAAM,WAAW,aAAa,QAAQ,WAAW,QAAQ;;AAGjE,SAAO,OAAO,OAAO,OAAO,OAAO,KAAK,EAAY,MAAM,EACzD,QACA,CAAC;;CAGH,MAAc,YAA0B;EACvC,MAAM,SAAS,MAAM,KAAK,IAAI,SAAS,QAAW,KAAK,IAAI,WAAW;AACtE,MAAI,QAAQ;AACX,OACC,KAAK,IAAI,UAAU,KAAA,KACnB,QAAQ,OAAO,UAAU,KAAK,IAAI,MAAM,EACvC;AAED,SAAK,IAAI,QAAQ,QAAQ,0BAA0B;KAClD,WAAW;KACX,YAAY,KAAK,IAAI;KACrB,cAAc,KAAK,IAAI;KACvB,CAAC;AACF,SAAK,IAAI,MAAM,mBAAmB;IAClC,MAAM,QAAQ,MAAM,KAAK,cAAc;AACvC,UAAM,KAAK,IAAI,SAAS,QAAQ,KAAK,IAAI,YAAY;KACpD;KACA,UAAU,KAAK,KAAK;KACpB,CAAC;AACF,WAAO;;GAGR,MAAM,KAAK,KAAK,qBAAqB,OAAO;AAC5C,OAAI,KAAK,IAAI,UAAW,MAAK,IAAI,UAAU,GAAG;AAC9C,QAAK,IAAI,QAAQ,QAAQ,eAAe;IACvC,WAAW;IACX,YAAY,KAAK,IAAI;IACrB,cAAc,KAAK,IAAI;IACvB,CAAC;AACF,QAAK,IAAI,MAAM,iBAAiB,OAAO;AACvC,UAAO,OAAO;;AAIf,OAAK,IAAI,QAAQ,QAAQ,mBAAmB;GAC3C,WAAW;GACX,YAAY,KAAK,IAAI;GACrB,cAAc,KAAK,IAAI;GACvB,CAAC;AACF,OAAK,IAAI,MAAM,mBAAmB;EAClC,MAAM,QAAQ,MAAM,KAAK,cAAc;EACvC,MAAM,WAAW,KAAK,KAAK;EAC3B,MAAM,OAAO,KAAK,IAAI,SAAS,QAAQ,KAAK,IAAI,YAAY;GAC3D;GACA;GACA,CAAC;AACF,MAAI,KAAK,IAAI,UACZ,MAAK,IAAI,UAAU,KAAK;MAExB,OAAM;AAEP,SAAO;;CAGR,MAAc,qBACb,MACA,QACgB;AAChB,MAAI;GACH,MAAM,OAAO,MAAM,KAAK,QAAQ,KAAK;AACrC,OAAI,CAAC,KAAM;AAEX,OADW,KAAK,IAAI,OAAO,gBAAgB,KACrC,KAAK,OAAO,iBAAiB;IAClC,MAAM,OAAO,MAAM,KAAK,YAAY,MAAM,KAAK;AAC/C,UAAM,KAAK,kBAAkB,KAAK;AAClC,SAAK,IAAI,QAAQ,QAAQ,sBAAsB;KAC9C,WAAW;KACX;KACA,YAAY,KAAK,IAAI;KACrB,iBAAiB,OAAO;KACxB,CAAC;AACF,SAAK,IAAI,MAAM,qBAAqB,MAAM,KAAK;AAC/C,UAAM,KAAK,iBAAiB,MAAM,KAAK;cAC7B,KAAK,IAAI,UAAU,KAAA,GAAW;AAExC,UAAM,KAAK,IAAI,SAAS,QAAQ,KAAK,IAAI,YAAY,MAAM;KAC1D,GAAG;KACH,UAAU,KAAK,KAAK;KACpB,CAAC;AACF,SAAK,IAAI,QAAQ,QAAQ,uBAAuB;KAC/C,WAAW;KACX;KACA,YAAY,KAAK,IAAI;KACrB,CAAC;;WAEK,KAAK;AACb,QAAK,IAAI,QAAQ,OAChB,+BACA;IACC;IACA,YAAY,KAAK,IAAI;IACrB,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;IACvD,CACD;;;CAIH,MAAc,qBAAqB,QAA0C;AAC5E,MAAI;GACH,MAAM,QAAQ,MAAM,KAAK,cAAc;AACvC,OACC,KAAK,IAAI,OAAO,eAAe,MAAM,KACrC,KAAK,IAAI,OAAO,eAAe,OAAO,MAAM,EAC3C;IACD,MAAM,YAAY;KAAE;KAAO,UAAU,KAAK,KAAK;KAAE;AACjD,UAAM,KAAK,IAAI,SAAS,QAAQ,KAAK,IAAI,YAAY,UAAU;AAC/D,SAAK,IAAI,QAAQ,QAChB,4BACA;KACC,WAAW;KACX,YAAY,KAAK,IAAI;KACrB,CACD;AACD,SAAK,IAAI,MAAM,yBAAyB,UAAU;cACxC,KAAK,IAAI,UAAU,KAAA,GAAW;AACxC,UAAM,KAAK,IAAI,SAAS,QAAQ,KAAK,IAAI,YAAY;KACpD,GAAG;KACH,UAAU,KAAK,KAAK;KACpB,CAAC;AACF,SAAK,IAAI,QAAQ,QAAQ,0BAA0B;KAClD,WAAW;KACX,YAAY,KAAK,IAAI;KACrB,CAAC;;WAEK,KAAK;AACb,QAAK,IAAI,QAAQ,OAChB,8BACA;IACC,YAAY,KAAK,IAAI;IACrB,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;IACvD,CACD;;;CAIH,eAAqC;AACpC,SAAO,gBAEL,KAAK,IAAI,OAAO,KAAK,EACpB,mBACC,KAAK,IAAI,kBAAkB,SAAS,IACjC,KAAK,IAAI,oBACT,KAAA,GACJ,CAAC,EACH;GACC,GAAG,KAAK,IAAI;GACZ,UAAU,SAAS,WAAW;AAC7B,SAAK,IAAI,QAAQ,OAAO,gBAAgB;KAAE;KAAS;KAAQ,CAAC;;GAE7D,CACD;;CAGF,MAAc,QAAQ,MAAiC;EACtD,MAAM,YAAY;GACjB,GAAG,KAAK,IAAI;GACZ,UAAU,SAAiB,WAAmB;AAC7C,SAAK,IAAI,QAAQ,OAAO,eAAe;KACtC;KACA;KACA;KACA,CAAC;;GAEH;EAGD,MAAM,iBACL,KAAK,IAAI,OAAO,aAAa,KAAK,IAAI,YAAY;EAEnD,IAAI;EACJ,MAAM,aAAa,KAAK,IAAI,OAAO,YAAY,KAAK,KAAK,IAAI,OAAO;AACpE,MAAI,kBAAkB,WACrB,QAAO,MAAM,gBAAgB,WAAW,gBAAgB,KAAK,EAAE,UAAU;MAIzE,SAAO,MADW,gBAAgB,KAAK,IAAI,OAAO,MAAM,EAAE,UAAU,EACzD,MAAM,MAAM,EAAE,SAAS,KAAK,IAAI;AAG5C,MAAI,CAAC,KAAM,QAAO;AAClB,MACC,KAAK,IAAI,mBAAmB,SAAS,MACpC,CAAC,KAAK,UAAU,CAAC,KAAK,IAAI,mBAAmB,SAAS,KAAK,OAAO,EAEnE,QAAO;AAER,SAAO;;;AAIT,SAAS,iBACR,OACA,MACM;AACN,KAAI,CAAC,KAAM,QAAO;CAClB,IAAI,SAAS;AAEb,KAAI,KAAK,QAAQ;EAChB,MAAM,QAAQ,IAAI,IACjB,MAAM,QAAQ,KAAK,OAAO,GAAG,KAAK,SAAS,CAAC,KAAK,OAAO,CACxD;AACD,WAAS,OAAO,QAAQ,OAAO,GAAG,UAAU,QAAQ,MAAM,IAAI,GAAG,OAAO,CAAC;;AAG1E,KAAI,KAAK,KAAK;EACb,MAAM,MAAM,KAAK;AACjB,WAAS,OAAO,QAAQ,OAAO;GAC9B,MAAM,OAAQ,GAAqC;AACnD,UAAO,MAAM,QAAQ,KAAK,IAAI,KAAK,SAAS,IAAI;IAC/C;;AAGH,KAAI,KAAK,OAAO;EACf,MAAM,QAAQ,KAAK;AACnB,WAAS,OAAO,QAAQ,OACvB,OAAO,QAAQ,MAAM,CAAC,OACpB,CAAC,KAAK,WAAY,GAA+B,SAAS,MAC3D,CACD;;AAGF,KAAI,KAAK,KACR,UAAS,CAAC,GAAG,OAAO,CAAC,KAAK,eAAe,KAAK,KAAK,CAAC;CAGrD,MAAM,OAAO,KAAK,QAAQ;CAC1B,MAAM,QAAQ,KAAK;AACnB,KAAI,OAAO,KAAK,UAAU,KAAA,EACzB,UAAS,OAAO,MAAM,MAAM,UAAU,KAAA,IAAY,OAAO,QAAQ,KAAA,EAAU;AAG5E,QAAO;;AAGR,SAAS,eACR,MACyB;CACzB,MAAM,KAAK,KAAK;CAChB,MAAM,MAAM,KAAK,QAAQ,QAAQ,IAAI;AACrC,SAAQ,GAAG,MAAM;EAChB,MAAM,KAAM,EAA8B;EAC1C,MAAM,KAAM,EAA8B;AAC1C,MAAI,OAAO,GAAI,QAAO;AACtB,MAAI,OAAO,KAAA,EAAW,QAAO;AAC7B,MAAI,OAAO,KAAA,EAAW,QAAO;AAE7B,SAAQ,KAAc,KAAa,MAAM,CAAC;;;;;ACriB5C,MAAM,eAAe;CACpB,UAAU;CACV,YAAY;CACZ,gBAAgB;CAChB;;;;;;;;;AAUD,SAAgB,cACf,SACA,OAAuB,EAAE,EACa;CACtC,MAAM,WAAW,kBAAkB,KAAK,YAAY,aAAa,SAAS;CAC1E,MAAM,aAAa,KAAK,cAAc,aAAa;CACnD,MAAM,iBAAiB,KAAK,kBAAkB,aAAa;AAE3D,QAAO,OAAO,QAAoC;EAEjD,MAAM,OAAO,IADG,IAAI,IAAI,IACR,CAAC;AAEjB,MAAI,CAAC,KAAK,WAAW,SAAS,CAC7B,QAAO,IAAI,SAAS,aAAa,EAAE,QAAQ,KAAK,CAAC;EAElD,MAAM,MAAM,KAAK,MAAM,SAAS,OAAO,IAAI;AAG3C,MAAI,IAAI,WAAW,SAAS,IAAI,WAAW,GAAG,WAAW,GAAG,EAAE;GAC7D,MAAM,OAAO,IAAI,MAAM,WAAW,SAAS,EAAE;AAC7C,OAAI,CAAC,KAAM,QAAO,IAAI,SAAS,eAAe,EAAE,QAAQ,KAAK,CAAC;GAC9D,MAAM,SAAS,MAAM,QAAQ,WAAW,IAAI,KAAK;AACjD,OAAI,CAAC,OAAQ,QAAO,IAAI,SAAS,aAAa,EAAE,QAAQ,KAAK,CAAC;GAC9D,MAAM,UAAU,IAAI,SAAS;AAC7B,OAAI,OAAO,YAAa,SAAQ,IAAI,gBAAgB,OAAO,YAAY;AACvE,WAAQ,IAAI,iBAAiB,sCAAsC;AACnE,UAAO,IAAI,SAAS,OAAO,MAAM,EAAE,SAAS,CAAC;;AAI9C,MAAI,IAAI,WAAW,UAAU,QAAQ,gBAAgB;GACpD,MAAM,QAAQ,MAAM,QAAQ,aAAa,KAAK,KAAK,cAAc;AACjE,OAAI,CAAC,MACJ,QAAO,IAAI,SAAS,KAAK,UAAU;IAAE,IAAI;IAAO,QAAQ;IAAW,CAAC,EAAE;IACrE,QAAQ;IACR,SAAS,EAAE,gBAAgB,oBAAoB;IAC/C,CAAC;AAEH,SAAM,QAAQ,WAAW,MAAM;AAC/B,UAAO,IAAI,SAAS,KAAK,UAAU;IAAE,IAAI;IAAM;IAAO,CAAC,EAAE;IACxD,QAAQ;IACR,SAAS,EAAE,gBAAgB,oBAAoB;IAC/C,CAAC;;AAGH,SAAO,IAAI,SAAS,aAAa,EAAE,QAAQ,KAAK,CAAC;;;AAInD,SAAS,kBAAkB,GAAmB;AAC7C,QAAO,EAAE,SAAS,IAAI,GAAG,EAAE,MAAM,GAAG,GAAG,GAAG;;;;ACjE3C,MAAM,2BAA2B;;;;;;;;AAkCjC,SAAS,aACR,OACgB;CAChB,MAAM,WACL,UAAU,KAAA,IAAY,EAAE,GAAG,MAAM,QAAQ,MAAM,GAAG,QAAQ,CAAC,MAAM;CAElE,IAAI,MAAwB;CAC5B,IAAI,UAAU;CACd,IAAI,MAAqB;CACzB,IAAI,UAAU;CACd,IAAI,WAAW;CACf,IAAI,WAAW;AAEf,MAAK,MAAM,WAAW,UAAU;AAC/B,MAAI,CAAC,YAAY,QAAQ,QAAQ,SAAS,WAAW,IAAI,QAAQ,KAAK;AACrE,SAAM,QAAQ;AACd,aAAU,QAAQ;AAClB,cAAW;;AAEZ,MAAI,CAAC,YAAY,QAAQ,QAAQ,SAAS,QAAQ,IAAI,QAAQ,KAAK;AAClE,SAAM,QAAQ;AACd,aAAU,QAAQ;AAClB,cAAW;;;AAIb,QAAO;EAAE;EAAK;EAAS;EAAK;EAAS,QAAQ;EAAU;;AAGxD,MAAM,kBAA4C;CACjD,OAAO;CACP,MAAM;CACN,MAAM;CACN,OAAO;CACP;;AAGD,SAAS,cACR,QACA,UACqB;AACrB,KAAI,CAAC,OAAQ,QAAO,KAAA;CACpB,MAAM,WAAW,gBAAgB;CACjC,MAAM,WAAmB,EAAE;AAC3B,MAAK,MAAM,SAAS;EAAC;EAAS;EAAQ;EAAQ;EAAQ,CACrD,KAAI,gBAAgB,UAAU,SAC7B,UAAS,SAAS,OAAO;AAG3B,QAAO;;;;;;;;;;;;;;;;;;;;;AAsBR,SAAgB,UACf,MACe;AACf,KAAI,CAAC,KAAK,eAAe,OAAO,KAAK,KAAK,YAAY,CAAC,WAAW,EACjE,OAAM,IAAI,SAAS;EAClB,MAAM;EACN,SACC;EACD,SAAS,EAAE,WAAW,aAAa;EACnC,CAAC;AAGH,MAAK,MAAM,CAAC,MAAM,QAAQ,OAAO,QAAQ,KAAK,YAAY,EAAE;AAC3D,MAAI,CAAC,IAAI,OACR,OAAM,IAAI,SAAS;GAClB,MAAM;GACN,SAAS,sBAAsB,KAAK;GACpC,SAAS;IAAE,WAAW;IAAa,YAAY;IAAM;GACrD,CAAC;AAEH,MAAI,CAAC,IAAI,UACR,OAAM,IAAI,SAAS;GAClB,MAAM;GACN,SAAS,sBAAsB,KAAK;GACpC,SAAS;IAAE,WAAW;IAAa,YAAY;IAAM;GACrD,CAAC;;CAIJ,MAAM,WAAW,aAAa,KAAK,MAAM;CACzC,MAAM,QAAQ,KAAK;CACnB,MAAM,iBAAiB,KAAK,kBAAkB;CAC9C,MAAM,gBAAgB,KAAK;CAC3B,MAAM,aAAqC,KAAK;CAChD,MAAM,YAAY,KAAK;CACvB,MAAM,aAAiC,aACtC,KAAK,WAAW,EAAE,EAClB,KAAK,OACL;CACD,MAAM,SAAS,KAAK,WACjB,cAAc,YAAY,KAAK,SAAS,GACxC;CACH,MAAM,QAAmC,WACxC,KAAK,WAAW,EAAE,EAClB,KAAK,OACL,OACA;CACD,MAAM,gBAAgB,KAAK,aAAa,iBAAiB;CACzD,MAAM,cAA2B;EAChC,GAAG;EACH,GAAI,KAAK,eAAe,EAAE;EAC1B;CAED,MAAM,kBAAkB,OAAO,KAAK,KAAK,YAAY;CAGrD,MAAM,cAAqD,EAAE;AAC7D,MAAK,MAAM,QAAQ,iBAAiB;EACnC,MAAM,MAAM,KAAK,YAAY;EAC7B,MAAM,SAAS,IAAI;EACnB,MAAM,WAAW,IAAI;EACrB,MAAM,kBAA6C,WAChD,WAAW,CAAC;GAAE,MAAM,GAAG,KAAK;GAAU;GAAO,CAAC,EAAE,UAAU,OAAO,GACjE;EACH,MAAM,YAA4C;GACjD;GACA;GACA,UAAU,SAAS;GACnB,cAAc,SAAS;GACvB,eAAe,SAAS;GACxB;GACA;GACA,OAAO;GACP;GACA;AAqBD,cAAY,QAAQ,IAAI,qBAAqB;GAnB5C,YAAY;GACZ;GACA,UAAU,SAAS;GACnB,cAAc,SAAS;GACvB,QAAQ;GACR,OAAO;GACP;GACA;GACA,mBAAmB,IAAI,oBACpB,CAAC,GAAG,IAAI,kBAAkB,GAC1B,EAAE;GACL,oBAAoB,IAAI,qBACrB,CAAC,GAAG,IAAI,mBAAmB,GAC3B,EAAE;GACL;GACA;GACA;GACA,WAAW,IAAI;GAEgC,CAAC;;CAGlD,MAAM,YAA0B;EAC/B,cAAc;EACd,MAAM,YAAY,OAAwC;AACzD,WAAQ,QAAQ,kBAAkB;IACjC,WAAW;IACX,cAAc,SAAS;IACvB,CAAC;AACF,SAAM,SAAS,IAAI,WAAW,SAAS,MAAM;;EAE9C,SAAS,aAA8B;AACtC,UAAO,cACN;IACC,YAAY,SAAS;IACrB,cAAc,OAAO,KAAK,kBAAkB;AAC3C,UAAK,MAAM,QAAQ,iBAAiB;MACnC,MAAM,KAAK,KAAK,YAAY,MAC1B;AACF,UAAI,GAAG,aACN,KAAI;AAIH,cAAO,MAHa,GAAG,aAAa,IAAI,OAAO,EAAE,EAChD,QAAQ,eACR,CAAC;eAEM,KAAK;AACb,eAAQ,OAAO,mBAAmB;QACjC,YAAY;QACZ,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;QACvD,CAAC;;;AAKL,SAAI;MACH,MAAM,OAAQ,MAAM,IAAI,MAAM;AAI9B,UAAI,KAAK,QAAQ,KAAK,WACrB,QAAO;OAAE,YAAY,KAAK;OAAY,MAAM,KAAK;OAAM;AAExD,UAAI,KAAK,WACR,QAAO,EAAE,YAAY,KAAK,YAAY;aAEhC;AAGR,YAAO;;IAER,aAAa,UAAU,UAAU,YAAY,MAAM;IACnD,EACD,YACA;;EAEF,gBAAgB,MAAM;AACrB,UAAO,SAAS,IAAI,IAAI,KAAK;;EAE9B;AAED,QAAO,OAAO,OACb,OAAO,OAAO,KAAK,EACnB,aACA,UACA;;;;ACzRF,SAAgB,aACf,QACe;AACf,QAAO"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as CachedItemMeta, i as CachedItemList, l as ImageRef, o as StorageBinary, r as CachedItemContent, s as ContentBlock, t as BaseContentItem } from "./content-
|
|
1
|
+
import { a as CachedItemMeta, i as CachedItemList, l as ImageRef, o as StorageBinary, r as CachedItemContent, s as ContentBlock, t as BaseContentItem } from "./content-Bffid8da.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/types/data-source.d.ts
|
|
4
4
|
/**
|
|
@@ -143,4 +143,4 @@ interface MemoryCacheOptions extends MemoryDocumentOptions, MemoryImageOptions {
|
|
|
143
143
|
declare function memoryCache(options?: MemoryCacheOptions): CacheAdapter;
|
|
144
144
|
//#endregion
|
|
145
145
|
export { CacheAdapter as a, DataSource as c, PropertyDef as d, PropertyMap as f, memoryCache as i, InvalidateKind as l, MemoryDocumentOptions as n, DocumentCacheOps as o, WebhookConfig as p, MemoryImageOptions as r, ImageCacheOps as s, MemoryCacheOptions as t, InvalidateScope as u };
|
|
146
|
-
//# sourceMappingURL=memory-
|
|
146
|
+
//# sourceMappingURL=memory-CA1uTRbr.d.mts.map
|