@notion-headless-cms/core 0.3.24 → 0.3.25
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/{config-D4JQ_pmq.d.mts → config-DYxyW3SR.d.mts} +2 -2
- package/dist/{errors-DTt9ii0i.d.mts → errors-DcNErfYk.d.mts} +3 -2
- package/dist/errors.d.mts +1 -1
- package/dist/errors.mjs.map +1 -1
- package/dist/hooks.d.mts +1 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +3 -2
- package/dist/index.mjs.map +1 -1
- package/dist/{plugin-B795Ok3X.d.mts → plugin-Dct12kp2.d.mts} +2 -2
- package/dist/preset/node.d.mts +1 -1
- package/dist/source-author.d.mts +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as BaseContentItem } from "./content-DwsfWZao.mjs";
|
|
2
2
|
import { i as DataSource, t as CacheAdapter } from "./cache-DS81aOcC.mjs";
|
|
3
|
-
import { i as CMSHooks, r as Logger, t as CMSPlugin } from "./plugin-
|
|
3
|
+
import { i as CMSHooks, r as Logger, t as CMSPlugin } from "./plugin-Dct12kp2.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/types/sources.d.ts
|
|
6
6
|
/**
|
|
@@ -147,4 +147,4 @@ interface CreateClientOptions<S extends CMSSources = CMSSources> {
|
|
|
147
147
|
}
|
|
148
148
|
//#endregion
|
|
149
149
|
export { InferCollectionItem as a, RenderOptions as c, SWRConfig as d, CMSAdapter as f, CreateClientOptions as i, RendererFn as l, MergeSourceCollections as m, CollectionsConfig as n, LogLevel as o, CMSSources as p, ContentConfig as r, RateLimiterConfig as s, CollectionDef as t, RendererPluginList as u };
|
|
150
|
-
//# sourceMappingURL=config-
|
|
150
|
+
//# sourceMappingURL=config-DYxyW3SR.d.mts.map
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* | `source/fetch_item_failed` | `DataSource.findByProp()` 失敗 |
|
|
17
17
|
* | `source/load_markdown_failed` | `DataSource.loadMarkdown()` 失敗 |
|
|
18
18
|
* | `source/load_blocks_failed` | `DataSource.loadBlocks()` 失敗 |
|
|
19
|
+
* | `source/blocks_unsupported` | 選択した fetch 戦略が NotionBlockTree 取得を提供していない (markdown 戦略選択時など) |
|
|
19
20
|
* | `cache/io_failed` | document / image キャッシュの I/O 失敗 |
|
|
20
21
|
* | `cache/image_fetch_failed` | Notion 画像の HTTP 取得失敗 |
|
|
21
22
|
* | `cache/image_invalid_content_type` | 画像レスポンスの Content-Type が不正 |
|
|
@@ -33,7 +34,7 @@
|
|
|
33
34
|
*
|
|
34
35
|
* サードパーティアダプタが独自コードを追加したい場合は `CMSErrorCode` を参照。
|
|
35
36
|
*/
|
|
36
|
-
type BuiltInCMSErrorCode = "core/config_invalid" | "core/schema_invalid" | "core/notion_orm_missing" | "core/sort_unsupported_type" | "webhook/signature_invalid" | "webhook/payload_invalid" | "webhook/unknown_collection" | "webhook/not_implemented" | "source/fetch_items_failed" | "source/fetch_item_failed" | "source/load_markdown_failed" | "source/load_blocks_failed" | "cache/io_failed" | "cache/image_fetch_failed" | "cache/image_invalid_content_type" | "renderer/failed" | "swr/item_check_failed" | "swr/list_check_failed" | "swr/content_rebuild_failed" | "cli/config_invalid" | "cli/config_load_failed" | "cli/schema_invalid" | "cli/generate_failed" | "cli/init_failed" | "cli/notion_api_failed" | "cli/env_file_not_found";
|
|
37
|
+
type BuiltInCMSErrorCode = "core/config_invalid" | "core/schema_invalid" | "core/notion_orm_missing" | "core/sort_unsupported_type" | "webhook/signature_invalid" | "webhook/payload_invalid" | "webhook/unknown_collection" | "webhook/not_implemented" | "source/fetch_items_failed" | "source/fetch_item_failed" | "source/load_markdown_failed" | "source/load_blocks_failed" | "source/blocks_unsupported" | "cache/io_failed" | "cache/image_fetch_failed" | "cache/image_invalid_content_type" | "renderer/failed" | "swr/item_check_failed" | "swr/list_check_failed" | "swr/content_rebuild_failed" | "cli/config_invalid" | "cli/config_load_failed" | "cli/schema_invalid" | "cli/generate_failed" | "cli/init_failed" | "cli/notion_api_failed" | "cli/env_file_not_found";
|
|
37
38
|
/**
|
|
38
39
|
* CMS エラーコード。
|
|
39
40
|
* `BuiltInCMSErrorCode` のリテラル補完を維持しつつ、
|
|
@@ -92,4 +93,4 @@ declare function matchCMSError<R>(error: unknown, handlers: Partial<Record<CMSEr
|
|
|
92
93
|
}): R | undefined;
|
|
93
94
|
//#endregion
|
|
94
95
|
export { isCMSError as a, CMSErrorContext as i, CMSError as n, isCMSErrorInNamespace as o, CMSErrorCode as r, matchCMSError as s, BuiltInCMSErrorCode as t };
|
|
95
|
-
//# sourceMappingURL=errors-
|
|
96
|
+
//# sourceMappingURL=errors-DcNErfYk.d.mts.map
|
package/dist/errors.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as isCMSError, i as CMSErrorContext, n as CMSError, o as isCMSErrorInNamespace, r as CMSErrorCode, s as matchCMSError, t as BuiltInCMSErrorCode } from "./errors-
|
|
1
|
+
import { a as isCMSError, i as CMSErrorContext, n as CMSError, o as isCMSErrorInNamespace, r as CMSErrorCode, s as matchCMSError, t as BuiltInCMSErrorCode } from "./errors-DcNErfYk.mjs";
|
|
2
2
|
export { BuiltInCMSErrorCode, CMSError, CMSErrorCode, CMSErrorContext, isCMSError, isCMSErrorInNamespace, matchCMSError };
|
package/dist/errors.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.mjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/**\n * ライブラリ組み込みの CMS エラーコード。\n *\n * | コード | 発生条件 |\n * |---|---|\n * | `core/config_invalid` | 設定不備(token 未設定など) |\n * | `core/schema_invalid` | schema/mapping の型不整合 |\n * | `core/notion_orm_missing` | `@notion-headless-cms/notion-orm` の動的ロード失敗 |\n * | `core/sort_unsupported_type` | ソートキーの値型が string / number でない |\n * | `webhook/signature_invalid` | Webhook 署名検証失敗 |\n * | `webhook/payload_invalid` | Webhook ペイロード形式不正 |\n * | `webhook/unknown_collection` | Webhook の対象コレクションが未知 |\n * | `webhook/not_implemented` | DataSource が parseWebhook を実装していない |\n * | `source/fetch_items_failed` | `DataSource.list()` 失敗 |\n * | `source/fetch_item_failed` | `DataSource.findByProp()` 失敗 |\n * | `source/load_markdown_failed` | `DataSource.loadMarkdown()` 失敗 |\n * | `source/load_blocks_failed` | `DataSource.loadBlocks()` 失敗 |\n * | `cache/io_failed` | document / image キャッシュの I/O 失敗 |\n * | `cache/image_fetch_failed` | Notion 画像の HTTP 取得失敗 |\n * | `cache/image_invalid_content_type` | 画像レスポンスの Content-Type が不正 |\n * | `renderer/failed` | Markdown → HTML 変換失敗 |\n * | `swr/item_check_failed` | SWR バックグラウンドのアイテム差分チェック失敗 |\n * | `swr/list_check_failed` | SWR バックグラウンドのリスト差分チェック失敗 |\n * | `swr/content_rebuild_failed` | SWR バックグラウンドの本文再生成失敗 |\n * | `cli/config_invalid` | `nhc.config.ts` の内容不整合 |\n * | `cli/config_load_failed` | 設定ファイルの読み込み / 評価失敗 |\n * | `cli/schema_invalid` | CLI が受け取ったスキーマ / マッピング不整合 |\n * | `cli/generate_failed` | `nhc generate` の処理失敗 |\n * | `cli/init_failed` | `nhc init` の処理失敗 |\n * | `cli/notion_api_failed` | CLI が Notion API を呼び出す際の失敗 |\n * | `cli/env_file_not_found` | `--env-file` で指定したファイルが存在しない |\n *\n * サードパーティアダプタが独自コードを追加したい場合は `CMSErrorCode` を参照。\n */\nexport type BuiltInCMSErrorCode =\n | \"core/config_invalid\"\n | \"core/schema_invalid\"\n | \"core/notion_orm_missing\"\n | \"core/sort_unsupported_type\"\n | \"webhook/signature_invalid\"\n | \"webhook/payload_invalid\"\n | \"webhook/unknown_collection\"\n | \"webhook/not_implemented\"\n | \"source/fetch_items_failed\"\n | \"source/fetch_item_failed\"\n | \"source/load_markdown_failed\"\n | \"source/load_blocks_failed\"\n | \"cache/io_failed\"\n | \"cache/image_fetch_failed\"\n | \"cache/image_invalid_content_type\"\n | \"renderer/failed\"\n | \"swr/item_check_failed\"\n | \"swr/list_check_failed\"\n | \"swr/content_rebuild_failed\"\n | \"cli/config_invalid\"\n | \"cli/config_load_failed\"\n | \"cli/schema_invalid\"\n | \"cli/generate_failed\"\n | \"cli/init_failed\"\n | \"cli/notion_api_failed\"\n | \"cli/env_file_not_found\";\n\n/**\n * CMS エラーコード。\n * `BuiltInCMSErrorCode` のリテラル補完を維持しつつ、\n * サードパーティアダプタが独自コードを定義できるよう `string & {}` で拡張可能にする。\n */\nexport type CMSErrorCode = BuiltInCMSErrorCode | (string & {});\n\nexport interface CMSErrorContext {\n operation: string;\n slug?: string;\n dataSourceId?: string;\n pageId?: string;\n [key: string]: string | number | boolean | null | undefined;\n}\n\nexport class CMSError extends Error {\n readonly code: CMSErrorCode;\n override readonly cause?: unknown;\n readonly context: CMSErrorContext;\n /** エラーを解消するための次のアクション(表示用)。 */\n readonly nextSteps?: readonly string[];\n /** 詳細ドキュメントへの URL(表示用)。 */\n readonly docsUrl?: string;\n\n constructor(params: {\n code: CMSErrorCode;\n message: string;\n cause?: unknown;\n context: CMSErrorContext;\n nextSteps?: readonly string[];\n docsUrl?: string;\n }) {\n super(params.message, { cause: params.cause });\n this.name = \"CMSError\";\n this.code = params.code;\n this.cause = params.cause;\n this.context = params.context;\n this.nextSteps = params.nextSteps;\n this.docsUrl = params.docsUrl;\n }\n\n /** エラーコードが指定した値と一致するか判定する。 */\n is(code: CMSErrorCode): boolean {\n return this.code === code;\n }\n\n /** エラーコードが指定した名前空間に属するか判定する(例: `\"source/\"`)。 */\n inNamespace(namespace: string): boolean {\n return this.code.startsWith(namespace);\n }\n\n /**\n * nextSteps と docsUrl を含む人間向けの詳細メッセージを返す。\n * エラーダイアログ・ログ出力時に使う。\n */\n format(): string {\n const lines: string[] = [this.message];\n if (this.nextSteps?.length) {\n lines.push(\"\\n次にやること:\");\n for (const step of this.nextSteps) {\n lines.push(` - ${step}`);\n }\n }\n if (this.docsUrl) {\n lines.push(`\\n詳細: ${this.docsUrl}`);\n }\n return lines.join(\"\\n\");\n }\n}\n\nexport function isCMSError(error: unknown): error is CMSError {\n return error instanceof CMSError;\n}\n\n/** エラーコードが特定の名前空間に属するかを判定する(例: \"source/\")。 */\nexport function isCMSErrorInNamespace(\n error: unknown,\n namespace: string,\n): error is CMSError {\n return isCMSError(error) && error.code.startsWith(namespace);\n}\n\ntype CMSErrorHandler<R> = (err: CMSError) => R;\n\n/**\n * `CMSError` を switch 式のように分岐して処理するユーティリティ。\n * `_` キーはフォールバック(CMSError 以外 or 未マッチ時)に使われる。\n *\n * @example\n * matchCMSError(err, {\n * \"source/fetch_items_failed\": (e) => handleFetchError(e),\n * _: (e) => { throw e; },\n * });\n */\nexport function matchCMSError<R>(\n error: unknown,\n handlers: Partial<Record<CMSErrorCode, CMSErrorHandler<R>>> & {\n _?: (err: unknown) => R;\n },\n): R | undefined {\n if (!isCMSError(error)) {\n return handlers._?.(error);\n }\n const handler =\n handlers[error.code as CMSErrorCode] ??\n (handlers._ as CMSErrorHandler<R> | undefined);\n return handler?.(error);\n}\n"],"mappings":";
|
|
1
|
+
{"version":3,"file":"errors.mjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/**\n * ライブラリ組み込みの CMS エラーコード。\n *\n * | コード | 発生条件 |\n * |---|---|\n * | `core/config_invalid` | 設定不備(token 未設定など) |\n * | `core/schema_invalid` | schema/mapping の型不整合 |\n * | `core/notion_orm_missing` | `@notion-headless-cms/notion-orm` の動的ロード失敗 |\n * | `core/sort_unsupported_type` | ソートキーの値型が string / number でない |\n * | `webhook/signature_invalid` | Webhook 署名検証失敗 |\n * | `webhook/payload_invalid` | Webhook ペイロード形式不正 |\n * | `webhook/unknown_collection` | Webhook の対象コレクションが未知 |\n * | `webhook/not_implemented` | DataSource が parseWebhook を実装していない |\n * | `source/fetch_items_failed` | `DataSource.list()` 失敗 |\n * | `source/fetch_item_failed` | `DataSource.findByProp()` 失敗 |\n * | `source/load_markdown_failed` | `DataSource.loadMarkdown()` 失敗 |\n * | `source/load_blocks_failed` | `DataSource.loadBlocks()` 失敗 |\n * | `source/blocks_unsupported` | 選択した fetch 戦略が NotionBlockTree 取得を提供していない (markdown 戦略選択時など) |\n * | `cache/io_failed` | document / image キャッシュの I/O 失敗 |\n * | `cache/image_fetch_failed` | Notion 画像の HTTP 取得失敗 |\n * | `cache/image_invalid_content_type` | 画像レスポンスの Content-Type が不正 |\n * | `renderer/failed` | Markdown → HTML 変換失敗 |\n * | `swr/item_check_failed` | SWR バックグラウンドのアイテム差分チェック失敗 |\n * | `swr/list_check_failed` | SWR バックグラウンドのリスト差分チェック失敗 |\n * | `swr/content_rebuild_failed` | SWR バックグラウンドの本文再生成失敗 |\n * | `cli/config_invalid` | `nhc.config.ts` の内容不整合 |\n * | `cli/config_load_failed` | 設定ファイルの読み込み / 評価失敗 |\n * | `cli/schema_invalid` | CLI が受け取ったスキーマ / マッピング不整合 |\n * | `cli/generate_failed` | `nhc generate` の処理失敗 |\n * | `cli/init_failed` | `nhc init` の処理失敗 |\n * | `cli/notion_api_failed` | CLI が Notion API を呼び出す際の失敗 |\n * | `cli/env_file_not_found` | `--env-file` で指定したファイルが存在しない |\n *\n * サードパーティアダプタが独自コードを追加したい場合は `CMSErrorCode` を参照。\n */\nexport type BuiltInCMSErrorCode =\n | \"core/config_invalid\"\n | \"core/schema_invalid\"\n | \"core/notion_orm_missing\"\n | \"core/sort_unsupported_type\"\n | \"webhook/signature_invalid\"\n | \"webhook/payload_invalid\"\n | \"webhook/unknown_collection\"\n | \"webhook/not_implemented\"\n | \"source/fetch_items_failed\"\n | \"source/fetch_item_failed\"\n | \"source/load_markdown_failed\"\n | \"source/load_blocks_failed\"\n | \"source/blocks_unsupported\"\n | \"cache/io_failed\"\n | \"cache/image_fetch_failed\"\n | \"cache/image_invalid_content_type\"\n | \"renderer/failed\"\n | \"swr/item_check_failed\"\n | \"swr/list_check_failed\"\n | \"swr/content_rebuild_failed\"\n | \"cli/config_invalid\"\n | \"cli/config_load_failed\"\n | \"cli/schema_invalid\"\n | \"cli/generate_failed\"\n | \"cli/init_failed\"\n | \"cli/notion_api_failed\"\n | \"cli/env_file_not_found\";\n\n/**\n * CMS エラーコード。\n * `BuiltInCMSErrorCode` のリテラル補完を維持しつつ、\n * サードパーティアダプタが独自コードを定義できるよう `string & {}` で拡張可能にする。\n */\nexport type CMSErrorCode = BuiltInCMSErrorCode | (string & {});\n\nexport interface CMSErrorContext {\n operation: string;\n slug?: string;\n dataSourceId?: string;\n pageId?: string;\n [key: string]: string | number | boolean | null | undefined;\n}\n\nexport class CMSError extends Error {\n readonly code: CMSErrorCode;\n override readonly cause?: unknown;\n readonly context: CMSErrorContext;\n /** エラーを解消するための次のアクション(表示用)。 */\n readonly nextSteps?: readonly string[];\n /** 詳細ドキュメントへの URL(表示用)。 */\n readonly docsUrl?: string;\n\n constructor(params: {\n code: CMSErrorCode;\n message: string;\n cause?: unknown;\n context: CMSErrorContext;\n nextSteps?: readonly string[];\n docsUrl?: string;\n }) {\n super(params.message, { cause: params.cause });\n this.name = \"CMSError\";\n this.code = params.code;\n this.cause = params.cause;\n this.context = params.context;\n this.nextSteps = params.nextSteps;\n this.docsUrl = params.docsUrl;\n }\n\n /** エラーコードが指定した値と一致するか判定する。 */\n is(code: CMSErrorCode): boolean {\n return this.code === code;\n }\n\n /** エラーコードが指定した名前空間に属するか判定する(例: `\"source/\"`)。 */\n inNamespace(namespace: string): boolean {\n return this.code.startsWith(namespace);\n }\n\n /**\n * nextSteps と docsUrl を含む人間向けの詳細メッセージを返す。\n * エラーダイアログ・ログ出力時に使う。\n */\n format(): string {\n const lines: string[] = [this.message];\n if (this.nextSteps?.length) {\n lines.push(\"\\n次にやること:\");\n for (const step of this.nextSteps) {\n lines.push(` - ${step}`);\n }\n }\n if (this.docsUrl) {\n lines.push(`\\n詳細: ${this.docsUrl}`);\n }\n return lines.join(\"\\n\");\n }\n}\n\nexport function isCMSError(error: unknown): error is CMSError {\n return error instanceof CMSError;\n}\n\n/** エラーコードが特定の名前空間に属するかを判定する(例: \"source/\")。 */\nexport function isCMSErrorInNamespace(\n error: unknown,\n namespace: string,\n): error is CMSError {\n return isCMSError(error) && error.code.startsWith(namespace);\n}\n\ntype CMSErrorHandler<R> = (err: CMSError) => R;\n\n/**\n * `CMSError` を switch 式のように分岐して処理するユーティリティ。\n * `_` キーはフォールバック(CMSError 以外 or 未マッチ時)に使われる。\n *\n * @example\n * matchCMSError(err, {\n * \"source/fetch_items_failed\": (e) => handleFetchError(e),\n * _: (e) => { throw e; },\n * });\n */\nexport function matchCMSError<R>(\n error: unknown,\n handlers: Partial<Record<CMSErrorCode, CMSErrorHandler<R>>> & {\n _?: (err: unknown) => R;\n },\n): R | undefined {\n if (!isCMSError(error)) {\n return handlers._?.(error);\n }\n const handler =\n handlers[error.code as CMSErrorCode] ??\n (handlers._ as CMSErrorHandler<R> | undefined);\n return handler?.(error);\n}\n"],"mappings":";AA+EA,IAAa,WAAb,cAA8B,MAAM;CAClC;CACA;CACA;;CAEA;;CAEA;CAEA,YAAY,QAOT;EACD,MAAM,OAAO,SAAS,EAAE,OAAO,OAAO,MAAM,CAAC;EAC7C,KAAK,OAAO;EACZ,KAAK,OAAO,OAAO;EACnB,KAAK,QAAQ,OAAO;EACpB,KAAK,UAAU,OAAO;EACtB,KAAK,YAAY,OAAO;EACxB,KAAK,UAAU,OAAO;CACxB;;CAGA,GAAG,MAA6B;EAC9B,OAAO,KAAK,SAAS;CACvB;;CAGA,YAAY,WAA4B;EACtC,OAAO,KAAK,KAAK,WAAW,SAAS;CACvC;;;;;CAMA,SAAiB;EACf,MAAM,QAAkB,CAAC,KAAK,OAAO;EACrC,IAAI,KAAK,WAAW,QAAQ;GAC1B,MAAM,KAAK,WAAW;GACtB,KAAK,MAAM,QAAQ,KAAK,WACtB,MAAM,KAAK,OAAO,MAAM;EAE5B;EACA,IAAI,KAAK,SACP,MAAM,KAAK,SAAS,KAAK,SAAS;EAEpC,OAAO,MAAM,KAAK,IAAI;CACxB;AACF;AAEA,SAAgB,WAAW,OAAmC;CAC5D,OAAO,iBAAiB;AAC1B;;AAGA,SAAgB,sBACd,OACA,WACmB;CACnB,OAAO,WAAW,KAAK,KAAK,MAAM,KAAK,WAAW,SAAS;AAC7D;;;;;;;;;;;AAcA,SAAgB,cACd,OACA,UAGe;CACf,IAAI,CAAC,WAAW,KAAK,GACnB,OAAO,SAAS,IAAI,KAAK;CAK3B,QAFE,SAAS,MAAM,SACd,SAAS,KACK,KAAK;AACxB"}
|
package/dist/hooks.d.mts
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
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-DwsfWZao.mjs";
|
|
2
2
|
import { a as InvalidateKind, c as PropertyMap, i as DataSource, l as WebhookConfig, n as DocumentCacheOps, o as InvalidateScope, r as ImageCacheOps, s as PropertyDef, t as CacheAdapter } from "./cache-DS81aOcC.mjs";
|
|
3
|
-
import { a as isCMSError, i as CMSErrorContext, n as CMSError, o as isCMSErrorInNamespace, r as CMSErrorCode, s as matchCMSError, t as BuiltInCMSErrorCode } from "./errors-
|
|
4
|
-
import { a as MaybePromise, i as CMSHooks, n as definePlugin, r as Logger, t as CMSPlugin } from "./plugin-
|
|
5
|
-
import { a as InferCollectionItem, c as RenderOptions, d as SWRConfig, i as CreateClientOptions, l as RendererFn, m as MergeSourceCollections, n as CollectionsConfig, o as LogLevel, p as CMSSources, r as ContentConfig, s as RateLimiterConfig, u as RendererPluginList } from "./config-
|
|
3
|
+
import { a as isCMSError, i as CMSErrorContext, n as CMSError, o as isCMSErrorInNamespace, r as CMSErrorCode, s as matchCMSError, t as BuiltInCMSErrorCode } from "./errors-DcNErfYk.mjs";
|
|
4
|
+
import { a as MaybePromise, i as CMSHooks, n as definePlugin, r as Logger, t as CMSPlugin } from "./plugin-Dct12kp2.mjs";
|
|
5
|
+
import { a as InferCollectionItem, c as RenderOptions, d as SWRConfig, i as CreateClientOptions, l as RendererFn, m as MergeSourceCollections, n as CollectionsConfig, o as LogLevel, p as CMSSources, r as ContentConfig, s as RateLimiterConfig, u as RendererPluginList } from "./config-DYxyW3SR.mjs";
|
|
6
6
|
import { MemoryCacheOptions, memoryCache } from "./cache/memory.mjs";
|
|
7
7
|
import { mergeHooks, mergeLoggers } from "./hooks.mjs";
|
|
8
8
|
import { NodePresetOptions, nodePreset } from "./preset/node.mjs";
|
package/dist/index.mjs
CHANGED
|
@@ -231,8 +231,9 @@ async function buildCachedItemContent(item, ctx) {
|
|
|
231
231
|
if (ctx.source.loadNotionBlocks) try {
|
|
232
232
|
notionBlocks = await ctx.source.loadNotionBlocks(item);
|
|
233
233
|
} catch (err) {
|
|
234
|
-
if (isCMSError(err))
|
|
235
|
-
|
|
234
|
+
if (isCMSError(err) && err.is("source/blocks_unsupported")) notionBlocks = void 0;
|
|
235
|
+
else if (isCMSError(err)) throw err;
|
|
236
|
+
else throw new CMSError({
|
|
236
237
|
code: "source/load_blocks_failed",
|
|
237
238
|
message: "Failed to load Notion blocks from source.",
|
|
238
239
|
cause: err,
|
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 const data = new TextEncoder().encode(input);\n const hash = await crypto.subtle.digest(\"SHA-256\", data);\n return Array.from(new Uint8Array(hash))\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\n/**\n * キャッシュが有効期限切れかどうかを判定する。\n * ttlMs が未指定の場合は常に false(無期限有効)を返す。\n */\nexport function isStale(cachedAt: number, ttlMs?: number): boolean {\n if (ttlMs === undefined) return false;\n return Date.now() - cachedAt > ttlMs;\n}\n","import type {\n BaseContentItem,\n CachedItemContent,\n CachedItemList,\n CachedItemMeta,\n DocumentCacheOps,\n ImageCacheOps,\n StorageBinary,\n} from \"../types/index\";\n\n/** 何もキャッシュしないドキュメントオペレーション。常に null を返す。 */\nconst noopDoc: DocumentCacheOps = {\n getList<T extends BaseContentItem>(\n _collection: string,\n ): Promise<CachedItemList<T> | null> {\n return Promise.resolve(null);\n },\n setList<T extends BaseContentItem>(\n _collection: string,\n _data: CachedItemList<T>,\n ): Promise<void> {\n return Promise.resolve();\n },\n getMeta<T extends BaseContentItem>(\n _collection: string,\n _slug: string,\n ): Promise<CachedItemMeta<T> | null> {\n return Promise.resolve(null);\n },\n setMeta<T extends BaseContentItem>(\n _collection: string,\n _slug: string,\n _data: CachedItemMeta<T>,\n ): Promise<void> {\n return Promise.resolve();\n },\n getContent(\n _collection: string,\n _slug: string,\n ): Promise<CachedItemContent | null> {\n return Promise.resolve(null);\n },\n setContent(\n _collection: string,\n _slug: string,\n _data: CachedItemContent,\n ): Promise<void> {\n return Promise.resolve();\n },\n invalidate(): Promise<void> {\n return Promise.resolve();\n },\n};\n\n/** 何もキャッシュしない画像オペレーション。 */\nconst noopImg: ImageCacheOps = {\n get(_hash: string): Promise<StorageBinary | null> {\n return Promise.resolve(null);\n },\n set(): Promise<void> {\n return Promise.resolve();\n },\n};\n\n/**\n * 何もキャッシュしないアダプタ。`createClient({ 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/**\n * レスポンスの Content-Type ヘッダから画像の MIME タイプを取り出す。\n * ヘッダがない、または image/* でない場合は CMSError を投げる。\n * URL 拡張子からの推測や jpeg デフォルトは行わない。\n */\nfunction pickImageContentType(\n headerValue: string | null,\n notionUrl: string,\n): string {\n if (!headerValue) {\n throw new CMSError({\n code: \"cache/image_invalid_content_type\",\n message: \"Image response missing Content-Type header.\",\n context: { operation: \"fetchAndCacheImage:contentType\", notionUrl },\n });\n }\n const value = (headerValue.split(\";\")[0] ?? headerValue).trim().toLowerCase();\n if (!value.startsWith(\"image/\")) {\n throw new CMSError({\n code: \"cache/image_invalid_content_type\",\n message: `Image response has non-image Content-Type: ${value}`,\n context: {\n operation: \"fetchAndCacheImage:contentType\",\n notionUrl,\n contentType: value,\n },\n });\n }\n return value;\n}\n\n/**\n * Notion画像URLをfetchして ImageCacheOps にキャッシュし、プロキシURL を返す。\n * 既存キャッシュがあれば再fetchしない。\n */\nasync function fetchAndCacheImage(\n cache: ImageCacheOps,\n cacheName: string,\n notionUrl: string,\n hash: string,\n imageProxyBase: string,\n logger?: Logger,\n): Promise<string> {\n const proxyUrl = `${imageProxyBase}/${hash}`;\n\n const existing = await cache.get(hash);\n if (existing) {\n logger?.debug?.(\"画像キャッシュヒット\", {\n operation: \"fetchAndCacheImage\",\n cacheAdapter: cacheName,\n imageHash: hash,\n });\n return proxyUrl;\n }\n\n logger?.debug?.(\"画像キャッシュミス、Notion からフェッチ\", {\n operation: \"fetchAndCacheImage\",\n cacheAdapter: cacheName,\n imageHash: hash,\n });\n\n try {\n const response = await fetch(notionUrl, {\n signal: AbortSignal.timeout(10_000),\n });\n if (!response.ok) {\n throw new CMSError({\n code: \"cache/image_fetch_failed\",\n message: `Failed to fetch Notion image: HTTP ${response.status}`,\n context: {\n operation: \"fetchAndCacheImage\",\n notionUrl,\n httpStatus: response.status,\n },\n });\n }\n\n const data = await response.arrayBuffer();\n const contentType = pickImageContentType(\n response.headers.get(\"content-type\"),\n notionUrl,\n );\n await cache.set(hash, data, contentType);\n logger?.debug?.(\"画像をキャッシュに保存\", {\n operation: \"fetchAndCacheImage\",\n cacheAdapter: cacheName,\n imageHash: hash,\n });\n } catch (err) {\n if (isCMSError(err)) throw err;\n throw new CMSError({\n code: \"cache/io_failed\",\n message: \"Failed to fetch or cache Notion image.\",\n cause: err,\n context: { operation: \"fetchAndCacheImage\", notionUrl },\n });\n }\n\n return proxyUrl;\n}\n\n/**\n * `ImageCacheOps` と `imageProxyBase` から `cacheImage` 関数を構築する。\n * 返り値は Notion 画像 URL を受け取り、SHA-256 ハッシュをキャッシュキーとして\n * {@link ImageCacheOps} に保存後、プロキシ URL を返す。\n *\n * ハッシュのメモ化はファクトリ呼び出し単位でスコープ化されており、\n * インスタンス間でキャッシュを共有しない。\n */\nexport function buildCacheImageFn(\n cache: ImageCacheOps,\n cacheName: string,\n imageProxyBase: string,\n logger?: Logger,\n): (notionUrl: string) => Promise<string> {\n const hashMemo = new Map<string, string>();\n return async (notionUrl) => {\n let hash = hashMemo.get(notionUrl);\n if (hash === undefined) {\n hash = await sha256Hex(notionUrl);\n hashMemo.set(notionUrl, hash);\n }\n return fetchAndCacheImage(\n cache,\n cacheName,\n notionUrl,\n hash,\n imageProxyBase,\n logger,\n );\n };\n}\n\nexport type { StorageBinary };\n","import type { ContentBlock } from \"./content/blocks\";\nimport { CMSError, isCMSError } from \"./errors\";\nimport { buildCacheImageFn } from \"./image\";\nimport type {\n BaseContentItem,\n CachedItemContent,\n CachedItemMeta,\n CMSHooks,\n ContentConfig,\n DataSource,\n ImageCacheOps,\n Logger,\n RendererFn,\n} from \"./types/index\";\n\n/**\n * `@notion-headless-cms/markdown-html` を動的 import してデフォルトレンダラーを返す。\n * core のゼロ依存ルールを守るため静的 import は禁止。\n */\nasync function loadDefaultRenderer(): Promise<RendererFn> {\n try {\n const mod = await import(\"@notion-headless-cms/markdown-html\");\n return (mod as { renderMarkdown: RendererFn }).renderMarkdown;\n } catch {\n throw new CMSError({\n code: \"core/config_invalid\",\n message:\n \"renderer が未指定で、@notion-headless-cms/markdown-html のロードにも失敗しました。\" +\n \" createClient の renderer オプションを指定するか、@notion-headless-cms/markdown-html をインストールしてください。\",\n context: { operation: \"loadDefaultRenderer\" },\n });\n }\n}\n\n/** 本文レンダリングに必要な依存を束ねたコンテキスト。 */\nexport interface RenderContext<T extends BaseContentItem> {\n source: DataSource<T>;\n rendererFn: RendererFn | undefined;\n imgCache: ImageCacheOps;\n imgCacheName: string;\n hasImageCache: boolean;\n imageProxyBase: string;\n contentConfig: ContentConfig | undefined;\n hooks: CMSHooks<T>;\n logger: Logger | undefined;\n}\n\n/**\n * メタデータキャッシュエントリを生成する。Notion API も renderer も呼ばない軽量関数。\n */\nexport function buildCachedItemMeta<T extends BaseContentItem>(\n item: T,\n source: DataSource<T>,\n): CachedItemMeta<T> {\n return {\n item,\n notionUpdatedAt: source.getLastModified(item),\n cachedAt: Date.now(),\n };\n}\n\n/**\n * アイテム本文を Markdown ロード → blocks 生成 → HTML レンダリング → フック適用まで\n * 実行し、本文キャッシュ用の `CachedItemContent` を返す。\n */\nexport async function buildCachedItemContent<T extends BaseContentItem>(\n item: T,\n ctx: RenderContext<T>,\n): Promise<CachedItemContent> {\n const start = Date.now();\n ctx.logger?.info?.(\"コンテンツのレンダリング開始\", {\n slug: item.slug,\n pageId: item.id,\n });\n ctx.hooks.onRenderStart?.(item.slug);\n\n let markdown: string;\n try {\n markdown = await ctx.source.loadMarkdown(item);\n } catch (err) {\n if (isCMSError(err)) throw err;\n throw new CMSError({\n code: \"source/load_markdown_failed\",\n message: \"Failed to load markdown from source.\",\n cause: err,\n context: {\n operation: \"buildCachedItemContent:loadMarkdown\",\n pageId: item.id,\n slug: item.slug,\n },\n });\n }\n\n let blocks: ContentBlock[];\n try {\n blocks = await ctx.source.loadBlocks(item);\n } catch (err) {\n if (isCMSError(err)) throw err;\n throw new CMSError({\n code: \"source/load_blocks_failed\",\n message: \"Failed to load blocks from source.\",\n cause: err,\n context: {\n operation: \"buildCachedItemContent:loadBlocks\",\n pageId: item.id,\n slug: item.slug,\n },\n });\n }\n\n // react-renderer など Notion 形式を直接消費する利用側のため、\n // DataSource が対応していれば BlockObjectResponse ツリーも取得・キャッシュする。\n let notionBlocks: unknown[] | undefined;\n if (ctx.source.loadNotionBlocks) {\n try {\n notionBlocks = await ctx.source.loadNotionBlocks(item);\n } catch (err) {\n if (isCMSError(err)) throw err;\n throw new CMSError({\n code: \"source/load_blocks_failed\",\n message: \"Failed to load Notion blocks from source.\",\n cause: err,\n context: {\n operation: \"buildCachedItemContent:loadNotionBlocks\",\n pageId: item.id,\n slug: item.slug,\n },\n });\n }\n }\n\n const cacheImage = ctx.hasImageCache\n ? buildCacheImageFn(\n ctx.imgCache,\n ctx.imgCacheName,\n ctx.imageProxyBase,\n ctx.logger,\n )\n : undefined;\n\n const rendererFn = ctx.rendererFn ?? (await loadDefaultRenderer());\n\n let html: string;\n try {\n html = await rendererFn(markdown, {\n imageProxyBase: ctx.imageProxyBase,\n cacheImage,\n remarkPlugins: ctx.contentConfig?.remarkPlugins,\n rehypePlugins: ctx.contentConfig?.rehypePlugins,\n });\n } catch (err) {\n if (isCMSError(err)) throw err;\n throw new CMSError({\n code: \"renderer/failed\",\n message: \"Failed to render markdown.\",\n cause: err,\n context: {\n operation: \"buildCachedItemContent:renderMarkdown\",\n pageId: item.id,\n slug: item.slug,\n },\n });\n }\n\n if (ctx.hooks.afterRender) {\n html = await ctx.hooks.afterRender(html, item);\n }\n\n let result: CachedItemContent = {\n html,\n blocks,\n markdown,\n notionBlocks,\n notionUpdatedAt: ctx.source.getLastModified(item),\n cachedAt: Date.now(),\n };\n\n if (ctx.hooks.beforeCacheContent) {\n result = await ctx.hooks.beforeCacheContent(result, item);\n }\n\n const durationMs = Date.now() - start;\n ctx.logger?.info?.(\"コンテンツのレンダリング完了\", {\n slug: item.slug,\n durationMs,\n });\n ctx.hooks.onRenderEnd?.(item.slug, durationMs);\n\n return result;\n}\n","export interface RetryConfig {\n retryOn: number[];\n maxRetries: number;\n baseDelayMs: number;\n /** true のとき指数バックオフにランダムジッターを加える(Thundering Herd 対策)。デフォルト: true */\n jitter?: boolean;\n onRetry?: (attempt: number, status: number) => void;\n}\n\nexport const DEFAULT_RETRY_CONFIG: RetryConfig = {\n retryOn: [429, 502, 503],\n maxRetries: 4,\n baseDelayMs: 1000,\n jitter: 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 fn: () => Promise<T>,\n config: RetryConfig,\n): Promise<T> {\n let lastError: unknown;\n for (let attempt = 0; attempt <= config.maxRetries; attempt++) {\n try {\n return await fn();\n } catch (err) {\n const status = (err as { status?: number }).status;\n if (status === undefined || !config.retryOn.includes(status)) {\n throw err;\n }\n lastError = err;\n if (attempt < config.maxRetries) {\n config.onRetry?.(attempt + 1, status);\n const jitterFactor =\n config.jitter !== false ? 0.5 + Math.random() * 0.5 : 1;\n const delay = config.baseDelayMs * 2 ** attempt * jitterFactor;\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n }\n throw lastError;\n}\n","import { isStale } from \"./cache\";\nimport { CMSError, isCMSError } from \"./errors\";\nimport type { RenderContext } from \"./rendering\";\nimport { buildCachedItemContent, buildCachedItemMeta } from \"./rendering\";\nimport type { RetryConfig } from \"./retry\";\nimport { withRetry } from \"./retry\";\nimport type {\n AdjacencyOptions,\n BaseContentItem,\n CachedItemContent,\n CachedItemList,\n CachedItemMeta,\n CheckResult,\n CMSHooks,\n CollectionCacheOps,\n CollectionClient,\n DataSource,\n DocumentCacheOps,\n FindOptions,\n ItemWithContent,\n ListOptions,\n Logger,\n SortOption,\n WarmOptions,\n WarmResult,\n WhereClause,\n} from \"./types/index\";\n\n/**\n * コレクション別キャッシュキーを生成する (item: `{collection}:{slug}` / list: `{collection}`)。\n *\n * 各 cache adapter は内部で独自のキー戦略を持つが、ログ出力や差分再計算で\n * 同一表現が必要になるため core 側にも公開する。\n */\nexport function collectionKey(collection: string, slug?: string): string {\n return slug ? `${collection}:${slug}` : collection;\n}\n\nexport interface CollectionContext<T extends BaseContentItem> {\n collection: string;\n source: DataSource<T>;\n docCache: DocumentCacheOps;\n docCacheName: string;\n render: RenderContext<T>;\n hooks: CMSHooks<T>;\n logger: Logger | undefined;\n ttlMs: number | undefined;\n publishedStatuses: string[];\n accessibleStatuses: string[];\n retryConfig: RetryConfig;\n maxConcurrent: number;\n waitUntil: ((p: Promise<unknown>) => void) | undefined;\n /**\n * slug として使うフィールド名。`source.properties[slugField].notion` を\n * Notion プロパティ名として `findByProp` を呼び出す。\n */\n slugField: string;\n}\n\nexport class CollectionClientImpl<T extends BaseContentItem>\n implements CollectionClient<T>\n{\n readonly cache: CollectionCacheOps<T>;\n\n constructor(private readonly ctx: CollectionContext<T>) {\n this.cache = {\n invalidate: () => this.invalidateImpl(),\n invalidateItem: (slug: string) => this.invalidateItemImpl(slug),\n warm: (opts?: WarmOptions) => this.warmImpl(opts),\n };\n }\n\n // ── 基本取得 ──────────────────────────────────────────────────────────\n\n async find(\n slug: string,\n opts: FindOptions = {},\n ): Promise<ItemWithContent<T> | null> {\n if (opts.bypassCache) {\n this.ctx.hooks.onCacheMiss?.(slug);\n const item = await this.fetchRaw(slug);\n if (!item) return null;\n const meta = await this.persistMeta(slug, item);\n await this.invalidateContentEntry(slug);\n return this.attachLazyContent(meta);\n }\n\n const cachedMeta = await this.ctx.docCache.getMeta<T>(\n this.ctx.collection,\n slug,\n );\n if (cachedMeta) {\n // TTL 切れはブロッキングで再取得する (stale を返さない要件)\n if (\n this.ctx.ttlMs !== undefined &&\n isStale(cachedMeta.cachedAt, this.ctx.ttlMs)\n ) {\n this.ctx.logger?.debug?.(\"キャッシュ期限切れ(TTL)、フェッチ\", {\n operation: \"find\",\n slug,\n collection: this.ctx.collection,\n cacheAdapter: this.ctx.docCacheName,\n });\n this.ctx.hooks.onCacheMiss?.(slug);\n const item = await this.fetchRaw(slug);\n if (!item) return null;\n const meta = await this.persistMeta(slug, item);\n await this.invalidateContentEntry(slug);\n return this.attachLazyContent(meta);\n }\n // SWR: 即時返却しつつバックグラウンドで差分チェック\n const bg = this.checkAndUpdateItemBg(slug, cachedMeta);\n if (this.ctx.waitUntil) this.ctx.waitUntil(bg);\n this.ctx.logger?.debug?.(\"キャッシュヒット\", {\n operation: \"find\",\n slug,\n collection: this.ctx.collection,\n cacheAdapter: this.ctx.docCacheName,\n cachedAt: cachedMeta.cachedAt,\n });\n this.ctx.hooks.onCacheHit?.(slug, cachedMeta);\n return this.attachLazyContent(cachedMeta);\n }\n\n this.ctx.logger?.debug?.(\"キャッシュミス、フェッチ\", {\n operation: \"find\",\n slug,\n collection: this.ctx.collection,\n cacheAdapter: this.ctx.docCacheName,\n });\n this.ctx.hooks.onCacheMiss?.(slug);\n const item = await this.fetchRaw(slug);\n if (!item) return null;\n // 保存だけはバックグラウンド可: ユーザー向けレスポンスを早めに返す\n const meta = await this.persistMeta(slug, item, { background: true });\n return this.attachLazyContent(meta);\n }\n\n async list(opts?: ListOptions<T>): Promise<T[]> {\n const allItems = await this.fetchList();\n return applyListOptions(allItems, opts);\n }\n\n async params(): Promise<string[]> {\n const items = await this.fetchList();\n return items.map((item) => item.slug);\n }\n\n async peekVersion(\n slug: string,\n ): Promise<{ notionUpdatedAt: string; cachedAt: number } | null> {\n const meta = await this.ctx.docCache.getMeta<T>(this.ctx.collection, slug);\n if (!meta) return null;\n return { notionUpdatedAt: meta.notionUpdatedAt, cachedAt: meta.cachedAt };\n }\n\n async check(\n slug: string,\n currentVersion: string,\n ): Promise<CheckResult<T> | null> {\n const raw = await this.fetchRaw(slug);\n if (!raw) return null;\n if (raw.lastEditedTime === currentVersion) return { stale: false };\n const meta = await this.persistMeta(slug, raw);\n await this.invalidateContentEntry(slug);\n return { stale: true, item: this.attachLazyContent(meta) };\n }\n\n async adjacent(\n slug: string,\n opts?: AdjacencyOptions<T>,\n ): Promise<{ prev: T | null; next: T | null }> {\n const items = applyListOptions(await this.fetchList(), {\n sort: opts?.sort,\n });\n const index = items.findIndex((it) => it.slug === slug);\n if (index === -1) return { prev: null, next: null };\n return {\n prev: index > 0 ? (items[index - 1] ?? null) : null,\n next: index < items.length - 1 ? (items[index + 1] ?? null) : null,\n };\n }\n\n // ── キャッシュ操作 ────────────────────────────────────────────────────\n\n private async invalidateImpl(): Promise<void> {\n this.ctx.logger?.debug?.(\"コレクション全体のキャッシュを無効化\", {\n operation: \"cache.invalidate\",\n collection: this.ctx.collection,\n cacheAdapter: this.ctx.docCacheName,\n });\n await this.ctx.docCache.invalidate({ collection: this.ctx.collection });\n }\n\n private async invalidateItemImpl(slug: string): Promise<void> {\n this.ctx.logger?.debug?.(\"アイテムキャッシュを無効化\", {\n operation: \"cache.invalidateItem\",\n collection: this.ctx.collection,\n cacheAdapter: this.ctx.docCacheName,\n slug,\n });\n await this.ctx.docCache.invalidate({\n collection: this.ctx.collection,\n slug,\n });\n }\n\n private async warmImpl(opts?: WarmOptions): Promise<WarmResult> {\n const items = await this.fetchListRaw();\n const concurrency = opts?.concurrency ?? this.ctx.maxConcurrent;\n let ok = 0;\n const failed: Array<{ slug: string; error: unknown }> = [];\n\n for (let i = 0; i < items.length; i += concurrency) {\n const chunk = items.slice(i, i + concurrency);\n await Promise.all(\n chunk.map(async (item) => {\n try {\n await this.persistMeta(item.slug, item);\n const content = await buildCachedItemContent(item, this.ctx.render);\n await this.ctx.docCache.setContent(\n this.ctx.collection,\n item.slug,\n content,\n );\n ok++;\n } catch (err) {\n failed.push({ slug: item.slug, error: err });\n this.ctx.logger?.warn?.(\"warm: アイテムの事前レンダリングに失敗\", {\n slug: item.slug,\n pageId: item.id,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }),\n );\n opts?.onProgress?.(Math.min(i + concurrency, items.length), items.length);\n }\n\n await this.ctx.docCache.setList(this.ctx.collection, {\n items,\n cachedAt: Date.now(),\n });\n return { ok, failed };\n }\n\n // ── 内部 ──────────────────────────────────────────────────────────────\n\n private async persistMeta(\n slug: string,\n item: T,\n opts: { background?: boolean } = {},\n ): Promise<CachedItemMeta<T>> {\n let meta = buildCachedItemMeta(item, this.ctx.source);\n if (this.ctx.hooks.beforeCacheMeta) {\n meta = await this.ctx.hooks.beforeCacheMeta(meta);\n }\n const save = this.ctx.docCache.setMeta(this.ctx.collection, slug, meta);\n if (opts.background && this.ctx.waitUntil) {\n this.ctx.waitUntil(save);\n } else {\n await save;\n }\n return meta;\n }\n\n private async invalidateContentEntry(slug: string): Promise<void> {\n await this.ctx.docCache.invalidate({\n collection: this.ctx.collection,\n slug,\n kind: \"content\",\n });\n }\n\n /** 本文キャッシュ。メタとの整合 (`notionUpdatedAt`) が崩れていれば再生成して書き戻す。 */\n private async loadOrBuildContent(\n slug: string,\n item: T,\n ): Promise<CachedItemContent> {\n const expected = this.ctx.source.getLastModified(item);\n const cached = await this.ctx.docCache.getContent(\n this.ctx.collection,\n slug,\n );\n if (cached && cached.notionUpdatedAt === expected) {\n return cached;\n }\n\n const fresh = await buildCachedItemContent(item, this.ctx.render);\n await this.ctx.docCache.setContent(this.ctx.collection, slug, fresh);\n this.ctx.hooks.onContentRevalidated?.(slug, fresh);\n return fresh;\n }\n\n /** メタ既知の状態で本文だけ再生成する。エラーは onSwrError フックに通知して握り潰す。 */\n private async rebuildContentBg(slug: string, item: T): Promise<void> {\n try {\n const fresh = await buildCachedItemContent(item, this.ctx.render);\n await this.ctx.docCache.setContent(this.ctx.collection, slug, fresh);\n this.ctx.hooks.onContentRevalidated?.(slug, fresh);\n } catch (err) {\n const cmsErr = isCMSError(err)\n ? err\n : new CMSError({\n code: \"swr/content_rebuild_failed\",\n message: \"SWR background content rebuild failed.\",\n cause: err,\n context: {\n operation: \"swr.rebuildContentBg\",\n collection: this.ctx.collection,\n slug,\n },\n });\n this.ctx.hooks.onSwrError?.(cmsErr, { phase: \"item-content\", slug });\n this.ctx.logger?.warn?.(\"本文のバックグラウンド再生成に失敗\", {\n slug,\n collection: this.ctx.collection,\n code: cmsErr.code,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n private attachLazyContent(meta: CachedItemMeta<T>): ItemWithContent<T> {\n const slug = meta.item.slug;\n const item = meta.item;\n // html() / markdown() / blocks() を同じアイテムから複数回呼んでも I/O は 1 回に集約する\n let payloadPromise: Promise<CachedItemContent> | undefined;\n const loadPayload = (): Promise<CachedItemContent> => {\n if (!payloadPromise) {\n payloadPromise = this.loadOrBuildContent(slug, item);\n }\n return payloadPromise;\n };\n\n return Object.assign(Object.create(null) as object, item, {\n html: async () => (await loadPayload()).html,\n markdown: async () => (await loadPayload()).markdown,\n blocks: async () => (await loadPayload()).blocks,\n notionBlocks: async () => (await loadPayload()).notionBlocks,\n }) as ItemWithContent<T>;\n }\n\n private async fetchList(): Promise<T[]> {\n const cached = await this.ctx.docCache.getList<T>(this.ctx.collection);\n if (cached) {\n // TTL 切れはブロッキングで再取得する (find と同じ理由)\n if (\n this.ctx.ttlMs !== undefined &&\n isStale(cached.cachedAt, this.ctx.ttlMs)\n ) {\n this.ctx.logger?.debug?.(\"リストキャッシュ期限切れ(TTL)、フェッチ\", {\n operation: \"list\",\n collection: this.ctx.collection,\n cacheAdapter: this.ctx.docCacheName,\n });\n this.ctx.hooks.onListCacheMiss?.();\n const items = await this.fetchListRaw();\n await this.ctx.docCache.setList(this.ctx.collection, {\n items,\n cachedAt: Date.now(),\n });\n return items;\n }\n const bg = this.checkAndUpdateListBg(cached);\n if (this.ctx.waitUntil) this.ctx.waitUntil(bg);\n this.ctx.logger?.debug?.(\"リストキャッシュヒット\", {\n operation: \"list\",\n collection: this.ctx.collection,\n cacheAdapter: this.ctx.docCacheName,\n });\n this.ctx.hooks.onListCacheHit?.(cached);\n return cached.items;\n }\n\n this.ctx.logger?.debug?.(\"リストキャッシュミス、フェッチ\", {\n operation: \"list\",\n collection: this.ctx.collection,\n cacheAdapter: this.ctx.docCacheName,\n });\n this.ctx.hooks.onListCacheMiss?.();\n const items = await this.fetchListRaw();\n const cachedAt = Date.now();\n const save = this.ctx.docCache.setList(this.ctx.collection, {\n items,\n cachedAt,\n });\n if (this.ctx.waitUntil) {\n this.ctx.waitUntil(save);\n } else {\n await save;\n }\n return items;\n }\n\n private async checkAndUpdateItemBg(\n slug: string,\n cached: CachedItemMeta<T>,\n ): Promise<void> {\n try {\n const item = await this.fetchRaw(slug);\n if (!item) return;\n const lm = this.ctx.source.getLastModified(item);\n if (lm !== cached.notionUpdatedAt) {\n const meta = await this.persistMeta(slug, item);\n await this.invalidateContentEntry(slug);\n this.ctx.logger?.debug?.(\"SWR: 差分を検出、メタを差し替え\", {\n operation: \"find:bg\",\n slug,\n collection: this.ctx.collection,\n notionUpdatedAt: cached.notionUpdatedAt,\n });\n this.ctx.hooks.onCacheRevalidated?.(slug, meta);\n await this.rebuildContentBg(slug, item);\n } else {\n await this.ctx.docCache.setMeta(this.ctx.collection, slug, {\n ...cached,\n cachedAt: Date.now(),\n });\n this.ctx.logger?.debug?.(\"SWR: 差分なし、cachedAt を更新\", {\n operation: \"find:bg\",\n slug,\n collection: this.ctx.collection,\n });\n }\n } catch (err) {\n const cmsErr = isCMSError(err)\n ? err\n : new CMSError({\n code: \"swr/item_check_failed\",\n message: \"SWR background item check failed.\",\n cause: err,\n context: {\n operation: \"swr.checkAndUpdateItemBg\",\n collection: this.ctx.collection,\n slug,\n },\n });\n this.ctx.hooks.onSwrError?.(cmsErr, { phase: \"item-meta\", slug });\n this.ctx.logger?.warn?.(\n \"SWR: アイテムのバックグラウンド差分チェックに失敗\",\n {\n slug,\n collection: this.ctx.collection,\n code: cmsErr.code,\n error: err instanceof Error ? err.message : String(err),\n },\n );\n }\n }\n\n private async checkAndUpdateListBg(cached: CachedItemList<T>): Promise<void> {\n try {\n const items = await this.fetchListRaw();\n if (\n this.ctx.source.getListVersion(items) !==\n this.ctx.source.getListVersion(cached.items)\n ) {\n const listEntry = { items, cachedAt: Date.now() };\n await this.ctx.docCache.setList(this.ctx.collection, listEntry);\n this.ctx.logger?.debug?.(\n \"SWR: リスト差分を検出、キャッシュを差し替え\",\n {\n operation: \"list:bg\",\n collection: this.ctx.collection,\n },\n );\n this.ctx.hooks.onListCacheRevalidated?.(listEntry);\n } else if (this.ctx.ttlMs !== undefined) {\n await this.ctx.docCache.setList(this.ctx.collection, {\n ...cached,\n cachedAt: Date.now(),\n });\n this.ctx.logger?.debug?.(\"SWR: リスト差分なし、TTL をリセット\", {\n operation: \"list:bg\",\n collection: this.ctx.collection,\n });\n }\n } catch (err) {\n const cmsErr = isCMSError(err)\n ? err\n : new CMSError({\n code: \"swr/list_check_failed\",\n message: \"SWR background list check failed.\",\n cause: err,\n context: {\n operation: \"swr.checkAndUpdateListBg\",\n collection: this.ctx.collection,\n },\n });\n this.ctx.hooks.onSwrError?.(cmsErr, { phase: \"list\" });\n this.ctx.logger?.warn?.(\n \"SWR: リストのバックグラウンド差分チェックに失敗\",\n {\n collection: this.ctx.collection,\n code: cmsErr.code,\n error: err instanceof Error ? err.message : String(err),\n },\n );\n }\n }\n\n private async fetchListRaw(): Promise<T[]> {\n const items = await withRetry(\n () =>\n this.ctx.source.list({\n publishedStatuses:\n this.ctx.publishedStatuses.length > 0\n ? this.ctx.publishedStatuses\n : undefined,\n }),\n {\n ...this.ctx.retryConfig,\n onRetry: (attempt, status) => {\n this.ctx.logger?.warn?.(\"list() リトライ中\", { attempt, status });\n },\n },\n );\n return items.filter((item) => {\n if (item.isArchived || item.isInTrash) return false;\n if (\n this.ctx.accessibleStatuses.length > 0 &&\n (!item.status || !this.ctx.accessibleStatuses.includes(item.status))\n )\n return false;\n return true;\n });\n }\n\n private async fetchRaw(slug: string): Promise<T | null> {\n const retryOpts = {\n ...this.ctx.retryConfig,\n onRetry: (attempt: number, status: number) => {\n this.ctx.logger?.warn?.(\"find() リトライ中\", {\n attempt,\n status,\n slug,\n });\n },\n };\n\n // PropertyMap が解決できる場合は単一プロパティ filter で 1 ページだけ取得する (高速)\n const notionPropName =\n this.ctx.source.properties?.[this.ctx.slugField]?.notion;\n\n let item: T | null;\n const findByProp = this.ctx.source.findByProp?.bind(this.ctx.source);\n if (notionPropName && findByProp) {\n item = await withRetry(() => findByProp(notionPropName, slug), retryOpts);\n } else {\n // PropertyMap 未提供 / findByProp 未実装の DataSource 向けフォールバック\n const all = await withRetry(() => this.ctx.source.list(), retryOpts);\n item = all.find((i) => i.slug === slug) ?? null;\n }\n\n if (!item) return null;\n if (item.isArchived || item.isInTrash) return null;\n if (\n this.ctx.accessibleStatuses.length > 0 &&\n (!item.status || !this.ctx.accessibleStatuses.includes(item.status))\n ) {\n return null;\n }\n return item;\n }\n}\n\nfunction matchesWhere<T extends BaseContentItem>(\n item: T,\n where: WhereClause<T>,\n): boolean {\n for (const key of Object.keys(where) as (keyof T & string)[]) {\n const expected = where[key];\n const actual = item[key];\n if (Array.isArray(expected)) {\n if (!(expected as readonly unknown[]).includes(actual)) return false;\n } else {\n if (actual !== expected) return false;\n }\n }\n return true;\n}\n\nfunction applyListOptions<T extends BaseContentItem>(\n items: T[],\n opts?: ListOptions<T>,\n): T[] {\n if (!opts) return sortByPublishedAtDesc(items);\n let result = items;\n\n if (opts.statuses) {\n const allow = new Set(\n Array.isArray(opts.statuses) ? opts.statuses : [opts.statuses],\n );\n result = result.filter((it) => it.status != null && allow.has(it.status));\n }\n\n if (opts.tag) {\n const tag = opts.tag;\n result = result.filter((it) => {\n const tags = (it as { tags?: string[] }).tags;\n return Array.isArray(tags) && tags.includes(tag);\n });\n }\n\n if (opts.where) {\n const where = opts.where;\n result = result.filter((it) => matchesWhere(it, where));\n }\n\n if (opts.filter) {\n result = result.filter(opts.filter);\n }\n\n if (opts.sort) {\n result = [...result].sort(makeComparator(opts.sort));\n } else {\n result = sortByPublishedAtDesc(result);\n }\n\n const skip = opts.skip ?? 0;\n const limit = opts.limit;\n if (skip > 0 || limit !== undefined) {\n result = result.slice(skip, limit !== undefined ? skip + limit : undefined);\n }\n\n return result;\n}\n\n/** publishedAt 降順 (未設定なら lastEditedTime 降順) でソートする。 */\nfunction sortByPublishedAtDesc<T extends BaseContentItem>(items: T[]): T[] {\n return [...items].sort((a, b) => {\n const av = a.publishedAt ?? a.lastEditedTime;\n const bv = b.publishedAt ?? b.lastEditedTime;\n if (av === bv) return 0;\n return av > bv ? -1 : 1;\n });\n}\n\nfunction makeComparator<T extends BaseContentItem>(\n sort: SortOption<T>,\n): (a: T, b: T) => number {\n if (sort.compare) return sort.compare;\n const by = sort.by as keyof T;\n const dir = sort.dir === \"asc\" ? 1 : -1;\n return (a, b) => {\n const av = a[by];\n const bv = b[by];\n if (av === bv) return 0;\n if (av === undefined || av === null) return 1;\n if (bv === undefined || bv === null) return -1;\n if (typeof av === \"string\" && typeof bv === \"string\") {\n return av > bv ? dir : -dir;\n }\n if (typeof av === \"number\" && typeof bv === \"number\") {\n return av > bv ? dir : -dir;\n }\n throw new CMSError({\n code: \"core/sort_unsupported_type\",\n message: `\"${String(by)}\" フィールドの型 \"${typeof av}\" はソート非対応です。compare 関数を指定してください。`,\n context: {\n operation: \"makeComparator\",\n field: String(by),\n type: typeof av,\n },\n });\n };\n}\n","import { isCMSError } from \"./errors\";\nimport type { ImageCacheOps, InvalidateScope } from \"./types/index\";\n\n/** `$handler()` の挙動設定。 */\nexport interface HandlerOptions {\n /** マウントするベースパス。デフォルト `/api/cms`。 */\n basePath?: string;\n /** 画像プロキシのパス (basePath 相対)。デフォルト `/images/:hash`。 */\n imagesPath?: string;\n /** revalidate webhook のパス (basePath 相対)。デフォルト `/revalidate`。 */\n revalidatePath?: string;\n /** Webhook 署名検証用シークレット (未指定なら検証スキップ)。 */\n webhookSecret?: string;\n /** デフォルト実装を無効化する場合 true。 */\n disabled?: boolean;\n}\n\n/** `$handler()` が内部で依存する CMS 機能の最小セット。 */\nexport interface HandlerAdapter {\n imageCache: ImageCacheOps;\n /**\n * 指定コレクションの DataSource.parseWebhook を呼ぶ。\n * 未知コレクション → `webhook/unknown_collection` CMSError\n * parseWebhook 未実装 → `webhook/not_implemented` CMSError\n */\n parseWebhookFor(\n collection: string,\n req: Request,\n webhookSecret: string | undefined,\n ): Promise<InvalidateScope>;\n revalidate(scope: InvalidateScope): Promise<void>;\n}\n\nconst DEFAULT_OPTS = {\n basePath: \"/api/cms\",\n imagesPath: \"/images\",\n revalidatePath: \"/revalidate\",\n} as const;\n\n/** Webhook 系の CMSError コードを HTTP ステータスへ写像する。未対応コードは null。 */\nfunction webhookErrorStatus(code: string): number | null {\n if (code === \"webhook/signature_invalid\") return 401;\n if (code === \"webhook/not_implemented\") return 501;\n if (code === \"webhook/unknown_collection\") return 404;\n if (code === \"webhook/payload_invalid\") return 400;\n return null;\n}\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/:collection` — Webhook 受信 + $revalidate()\n */\nexport function createHandler(\n adapter: HandlerAdapter,\n opts: HandlerOptions = {},\n): (req: Request) => Promise<Response> {\n const basePath = trimTrailingSlash(opts.basePath ?? DEFAULT_OPTS.basePath);\n const imagesPath = opts.imagesPath ?? DEFAULT_OPTS.imagesPath;\n const revalidatePath = opts.revalidatePath ?? DEFAULT_OPTS.revalidatePath;\n\n return async (req: Request): Promise<Response> => {\n const url = new URL(req.url);\n const path = url.pathname;\n\n if (!path.startsWith(basePath)) {\n return new Response(\"Not Found\", { status: 404 });\n }\n const rel = path.slice(basePath.length) || \"/\";\n\n if (req.method === \"GET\" && rel.startsWith(`${imagesPath}/`)) {\n const hash = rel.slice(imagesPath.length + 1);\n if (!hash) return new Response(\"Bad Request\", { status: 400 });\n const object = await adapter.imageCache.get(hash);\n if (!object) return new Response(\"Not Found\", { status: 404 });\n const headers = new Headers();\n if (object.contentType) headers.set(\"content-type\", object.contentType);\n headers.set(\"cache-control\", \"public, max-age=31536000, immutable\");\n return new Response(object.data, { headers });\n }\n\n if (req.method === \"POST\" && rel.startsWith(`${revalidatePath}/`)) {\n const collection = rel.slice(revalidatePath.length + 1);\n if (!collection || collection.includes(\"/\")) {\n return new Response(\n JSON.stringify({ ok: false, reason: \"collection required\" }),\n { status: 400, headers: { \"content-type\": \"application/json\" } },\n );\n }\n try {\n const scope = await adapter.parseWebhookFor(\n collection,\n req,\n opts.webhookSecret,\n );\n await adapter.revalidate(scope);\n return new Response(JSON.stringify({ ok: true, scope }), {\n status: 200,\n headers: { \"content-type\": \"application/json\" },\n });\n } catch (err) {\n if (isCMSError(err)) {\n const status = webhookErrorStatus(err.code);\n if (status !== null) {\n return new Response(JSON.stringify({ ok: false, code: err.code }), {\n status,\n headers: { \"content-type\": \"application/json\" },\n });\n }\n }\n throw err;\n }\n }\n\n return new Response(\"Not Found\", { status: 404 });\n };\n}\n\nfunction trimTrailingSlash(s: string): string {\n return 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 { buildCacheImageFn } from \"./image\";\nimport type { RenderContext } from \"./rendering\";\nimport type { RetryConfig } from \"./retry\";\nimport { DEFAULT_RETRY_CONFIG } from \"./retry\";\nimport type {\n BaseContentItem,\n CacheAdapter,\n CMSHooks,\n CollectionClient,\n CollectionsConfig,\n CreateClientOptions,\n DataSource,\n DocumentCacheOps,\n ImageCacheOps,\n InferCollectionItem,\n InvalidateScope,\n Logger,\n LogLevel,\n RendererFn,\n StorageBinary,\n} from \"./types/index\";\nimport type {\n CMSAdapter,\n CMSSources,\n MergeSourceCollections,\n} from \"./types/sources\";\n\nconst DEFAULT_IMAGE_PROXY_BASE = \"/api/images\";\n\n/** コレクション別アクセス + グローバル操作の合成型。 */\nexport type CMSClient<C extends CollectionsConfig> = {\n [K in keyof C]: CollectionClient<InferCollectionItem<C[K]>>;\n} & CMSGlobalOps;\n\nexport interface CMSGlobalOps {\n readonly collections: readonly string[];\n invalidate(scope?: InvalidateScope): Promise<void>;\n /** Web Standard な Request/Response ベースのルートハンドラ (画像プロキシ + webhook)。 */\n handler(opts?: HandlerOptions): (req: Request) => Promise<Response>;\n getCachedImage(hash: string): Promise<StorageBinary | null>;\n /**\n * Notion 画像 URL を `{imageProxyBase}/{sha256}` 形式へ変換しキャッシュへ書き込む。\n * 画像キャッシュが未設定 (noop) の場合は `undefined`。\n */\n readonly cacheImage: ((url: string) => Promise<string>) | undefined;\n readonly imageProxyBase: string;\n}\n\ninterface ResolvedCache {\n doc: DocumentCacheOps;\n docName: string;\n img: ImageCacheOps;\n imgName: string;\n hasImg: boolean;\n}\n\n/**\n * adapter の `handles` を見て先勝ちで document / image を割り当てる。未指定は両方 noop。\n */\nfunction resolveCache(\n cache: readonly CacheAdapter[] | undefined,\n): ResolvedCache {\n const adapters = cache ?? [];\n\n let doc: DocumentCacheOps = noopDocOps;\n let docName = \"noop-document\";\n let img: ImageCacheOps = noopImgOps;\n let imgName = \"noop-image\";\n let docFound = false;\n let imgFound = false;\n\n for (const adapter of adapters) {\n if (!docFound && adapter.handles.includes(\"document\") && adapter.doc) {\n doc = adapter.doc;\n docName = adapter.name;\n docFound = true;\n }\n if (!imgFound && adapter.handles.includes(\"image\") && adapter.img) {\n img = adapter.img;\n imgName = adapter.name;\n imgFound = true;\n }\n }\n\n return { doc, docName, img, imgName, hasImg: imgFound };\n}\n\nconst LOG_LEVEL_ORDER: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\n\nfunction applyLogLevel(\n logger: Logger | undefined,\n minLevel: LogLevel,\n): Logger | undefined {\n if (!logger) return undefined;\n const minOrder = LOG_LEVEL_ORDER[minLevel];\n const filtered: Logger = {};\n for (const level of [\"debug\", \"info\", \"warn\", \"error\"] as const) {\n if (LOG_LEVEL_ORDER[level] >= minOrder) {\n filtered[level] = logger[level];\n }\n }\n return filtered;\n}\n\n/**\n * CMS クライアントを生成する。\n *\n * @example\n * import { createClient, nodePreset } from \"@notion-headless-cms/core\";\n * import { notionSource } from \"@notion-headless-cms/notion-source\";\n * import { schema } from \"./generated/nhc.schema\";\n *\n * const cms = createClient({\n * sources: { notion: notionSource({ schema, token: process.env.NOTION_TOKEN! }) },\n * ...nodePreset(),\n * });\n *\n * const posts = await cms.posts.list();\n */\nexport function createClient<S extends CMSSources = CMSSources>(\n opts: CreateClientOptions<S>,\n): CMSClient<\n MergeSourceCollections<S> extends CollectionsConfig\n ? MergeSourceCollections<S>\n : CollectionsConfig\n> {\n // sources の各アダプタが持つ collections をマージする\n const collectionsInput: CollectionsConfig = {};\n if (opts.sources) {\n for (const adapter of Object.values(\n opts.sources as unknown as Record<string, CMSAdapter | undefined>,\n )) {\n if (adapter) Object.assign(collectionsInput, adapter.collections);\n }\n }\n\n if (Object.keys(collectionsInput).length === 0) {\n throw new CMSError({\n code: \"core/config_invalid\",\n message:\n \"createClient: sources に少なくとも 1 つのコレクションを指定してください。\",\n context: { operation: \"createClient\" },\n nextSteps: [\n \"notionSource({ schema, token }) を sources.notion に渡す\",\n \"`nhc generate` でスキーマを生成してから import する\",\n ],\n docsUrl:\n \"https://github.com/kjfsm/notion-headless-cms/blob/main/docs/quickstart.md\",\n });\n }\n\n for (const [name, def] of Object.entries(collectionsInput)) {\n if (!def.source) {\n throw new CMSError({\n code: \"core/config_invalid\",\n message: `createClient: コレクション \"${name}\" の source は必須です。`,\n context: { operation: \"createClient\", collection: name },\n nextSteps: [\"notionSource(...) を sources に渡しているか確認する\"],\n });\n }\n if (!def.slugField) {\n throw new CMSError({\n code: \"core/config_invalid\",\n message: `createClient: コレクション \"${name}\" の slugField は必須です。`,\n context: { operation: \"createClient\", collection: name },\n nextSteps: [\n `nhc.config.ts の ${name} コレクションに slugField を設定する`,\n ],\n });\n }\n }\n\n const cacheRes = resolveCache(opts.cache);\n const ttlMs = opts.swr?.ttlMs;\n const imageProxyBase = opts.imageProxyBase ?? DEFAULT_IMAGE_PROXY_BASE;\n const contentConfig = opts.content;\n const rendererFn: RendererFn | undefined = opts.renderer;\n const waitUntil = opts.waitUntil;\n const baseLogger: Logger | undefined = mergeLoggers(\n opts.plugins ?? [],\n opts.logger,\n );\n const logger = opts.logLevel\n ? applyLogLevel(baseLogger, opts.logLevel)\n : baseLogger;\n const hooks: CMSHooks<BaseContentItem> = mergeHooks(\n opts.plugins ?? [],\n opts.hooks,\n logger,\n );\n const maxConcurrent = opts.rateLimiter?.maxConcurrent ?? 3;\n const retryConfig: RetryConfig = {\n ...DEFAULT_RETRY_CONFIG,\n ...(opts.rateLimiter ?? {}),\n };\n\n const collectionNames: string[] = [];\n const collections: Record<string, CollectionClient<BaseContentItem>> = {};\n for (const [name, def] of Object.entries(collectionsInput)) {\n collectionNames.push(name);\n const source = def.source as DataSource<BaseContentItem>;\n const colHooks = def.hooks as CMSHooks<BaseContentItem> | undefined;\n const collectionHooks: CMSHooks<BaseContentItem> = colHooks\n ? mergeHooks([{ name: `${name}:global`, hooks }], colHooks, logger)\n : hooks;\n const renderCtx: RenderContext<BaseContentItem> = {\n source,\n rendererFn,\n imgCache: cacheRes.img,\n imgCacheName: cacheRes.imgName,\n hasImageCache: cacheRes.hasImg,\n imageProxyBase,\n contentConfig,\n hooks: collectionHooks,\n logger,\n };\n const ctx: CollectionContext<BaseContentItem> = {\n collection: name,\n source,\n docCache: cacheRes.doc,\n docCacheName: cacheRes.docName,\n render: renderCtx,\n hooks: collectionHooks,\n logger,\n ttlMs,\n publishedStatuses: def.publishedStatuses\n ? [...def.publishedStatuses]\n : [],\n accessibleStatuses: def.accessibleStatuses\n ? [...def.accessibleStatuses]\n : [],\n retryConfig,\n maxConcurrent,\n waitUntil,\n slugField: def.slugField,\n };\n collections[name] = new CollectionClientImpl(ctx);\n }\n\n const cacheImage = cacheRes.hasImg\n ? buildCacheImageFn(cacheRes.img, cacheRes.imgName, imageProxyBase, logger)\n : undefined;\n\n const globalOps: CMSGlobalOps = {\n collections: collectionNames,\n cacheImage,\n imageProxyBase,\n async invalidate(scope?: InvalidateScope): Promise<void> {\n logger?.debug?.(\"グローバルキャッシュを無効化\", {\n operation: \"invalidate\",\n cacheAdapter: cacheRes.docName,\n });\n await cacheRes.doc.invalidate(scope ?? \"all\");\n },\n handler(handlerOpts?: HandlerOptions) {\n return createHandler(\n {\n imageCache: cacheRes.img,\n async parseWebhookFor(collection, req, webhookSecret) {\n const def = collectionsInput[collection];\n if (!def) {\n throw new CMSError({\n code: \"webhook/unknown_collection\",\n message: `Unknown collection: ${collection}`,\n context: { operation: \"parseWebhookFor\", collection },\n });\n }\n const ds = def.source as DataSource<BaseContentItem>;\n if (!ds.parseWebhook) {\n throw new CMSError({\n code: \"webhook/not_implemented\",\n message: `Collection \"${collection}\" does not support webhooks.`,\n context: { operation: \"parseWebhookFor\", collection },\n });\n }\n return ds.parseWebhook(req, { secret: webhookSecret });\n },\n revalidate: (scope) => globalOps.invalidate(scope),\n },\n handlerOpts,\n );\n },\n getCachedImage(hash) {\n return cacheRes.img.get(hash);\n },\n };\n\n return Object.assign(\n Object.create(null) as object,\n collections,\n globalOps,\n ) as CMSClient<\n MergeSourceCollections<S> extends CollectionsConfig\n ? MergeSourceCollections<S>\n : CollectionsConfig\n >;\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 name: string;\n hooks?: CMSHooks<T>;\n logger?: Partial<Logger>;\n}\n\nexport function definePlugin<T extends BaseContentItem>(\n plugin: CMSPlugin<T>,\n): CMSPlugin<T> {\n return 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 const data = new TextEncoder().encode(input);\n const hash = await crypto.subtle.digest(\"SHA-256\", data);\n return Array.from(new Uint8Array(hash))\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\n/**\n * キャッシュが有効期限切れかどうかを判定する。\n * ttlMs が未指定の場合は常に false(無期限有効)を返す。\n */\nexport function isStale(cachedAt: number, ttlMs?: number): boolean {\n if (ttlMs === undefined) return false;\n return Date.now() - cachedAt > ttlMs;\n}\n","import type {\n BaseContentItem,\n CachedItemContent,\n CachedItemList,\n CachedItemMeta,\n DocumentCacheOps,\n ImageCacheOps,\n StorageBinary,\n} from \"../types/index\";\n\n/** 何もキャッシュしないドキュメントオペレーション。常に null を返す。 */\nconst noopDoc: DocumentCacheOps = {\n getList<T extends BaseContentItem>(\n _collection: string,\n ): Promise<CachedItemList<T> | null> {\n return Promise.resolve(null);\n },\n setList<T extends BaseContentItem>(\n _collection: string,\n _data: CachedItemList<T>,\n ): Promise<void> {\n return Promise.resolve();\n },\n getMeta<T extends BaseContentItem>(\n _collection: string,\n _slug: string,\n ): Promise<CachedItemMeta<T> | null> {\n return Promise.resolve(null);\n },\n setMeta<T extends BaseContentItem>(\n _collection: string,\n _slug: string,\n _data: CachedItemMeta<T>,\n ): Promise<void> {\n return Promise.resolve();\n },\n getContent(\n _collection: string,\n _slug: string,\n ): Promise<CachedItemContent | null> {\n return Promise.resolve(null);\n },\n setContent(\n _collection: string,\n _slug: string,\n _data: CachedItemContent,\n ): Promise<void> {\n return Promise.resolve();\n },\n invalidate(): Promise<void> {\n return Promise.resolve();\n },\n};\n\n/** 何もキャッシュしない画像オペレーション。 */\nconst noopImg: ImageCacheOps = {\n get(_hash: string): Promise<StorageBinary | null> {\n return Promise.resolve(null);\n },\n set(): Promise<void> {\n return Promise.resolve();\n },\n};\n\n/**\n * 何もキャッシュしないアダプタ。`createClient({ 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/**\n * レスポンスの Content-Type ヘッダから画像の MIME タイプを取り出す。\n * ヘッダがない、または image/* でない場合は CMSError を投げる。\n * URL 拡張子からの推測や jpeg デフォルトは行わない。\n */\nfunction pickImageContentType(\n headerValue: string | null,\n notionUrl: string,\n): string {\n if (!headerValue) {\n throw new CMSError({\n code: \"cache/image_invalid_content_type\",\n message: \"Image response missing Content-Type header.\",\n context: { operation: \"fetchAndCacheImage:contentType\", notionUrl },\n });\n }\n const value = (headerValue.split(\";\")[0] ?? headerValue).trim().toLowerCase();\n if (!value.startsWith(\"image/\")) {\n throw new CMSError({\n code: \"cache/image_invalid_content_type\",\n message: `Image response has non-image Content-Type: ${value}`,\n context: {\n operation: \"fetchAndCacheImage:contentType\",\n notionUrl,\n contentType: value,\n },\n });\n }\n return value;\n}\n\n/**\n * Notion画像URLをfetchして ImageCacheOps にキャッシュし、プロキシURL を返す。\n * 既存キャッシュがあれば再fetchしない。\n */\nasync function fetchAndCacheImage(\n cache: ImageCacheOps,\n cacheName: string,\n notionUrl: string,\n hash: string,\n imageProxyBase: string,\n logger?: Logger,\n): Promise<string> {\n const proxyUrl = `${imageProxyBase}/${hash}`;\n\n const existing = await cache.get(hash);\n if (existing) {\n logger?.debug?.(\"画像キャッシュヒット\", {\n operation: \"fetchAndCacheImage\",\n cacheAdapter: cacheName,\n imageHash: hash,\n });\n return proxyUrl;\n }\n\n logger?.debug?.(\"画像キャッシュミス、Notion からフェッチ\", {\n operation: \"fetchAndCacheImage\",\n cacheAdapter: cacheName,\n imageHash: hash,\n });\n\n try {\n const response = await fetch(notionUrl, {\n signal: AbortSignal.timeout(10_000),\n });\n if (!response.ok) {\n throw new CMSError({\n code: \"cache/image_fetch_failed\",\n message: `Failed to fetch Notion image: HTTP ${response.status}`,\n context: {\n operation: \"fetchAndCacheImage\",\n notionUrl,\n httpStatus: response.status,\n },\n });\n }\n\n const data = await response.arrayBuffer();\n const contentType = pickImageContentType(\n response.headers.get(\"content-type\"),\n notionUrl,\n );\n await cache.set(hash, data, contentType);\n logger?.debug?.(\"画像をキャッシュに保存\", {\n operation: \"fetchAndCacheImage\",\n cacheAdapter: cacheName,\n imageHash: hash,\n });\n } catch (err) {\n if (isCMSError(err)) throw err;\n throw new CMSError({\n code: \"cache/io_failed\",\n message: \"Failed to fetch or cache Notion image.\",\n cause: err,\n context: { operation: \"fetchAndCacheImage\", notionUrl },\n });\n }\n\n return proxyUrl;\n}\n\n/**\n * `ImageCacheOps` と `imageProxyBase` から `cacheImage` 関数を構築する。\n * 返り値は Notion 画像 URL を受け取り、SHA-256 ハッシュをキャッシュキーとして\n * {@link ImageCacheOps} に保存後、プロキシ URL を返す。\n *\n * ハッシュのメモ化はファクトリ呼び出し単位でスコープ化されており、\n * インスタンス間でキャッシュを共有しない。\n */\nexport function buildCacheImageFn(\n cache: ImageCacheOps,\n cacheName: string,\n imageProxyBase: string,\n logger?: Logger,\n): (notionUrl: string) => Promise<string> {\n const hashMemo = new Map<string, string>();\n return async (notionUrl) => {\n let hash = hashMemo.get(notionUrl);\n if (hash === undefined) {\n hash = await sha256Hex(notionUrl);\n hashMemo.set(notionUrl, hash);\n }\n return fetchAndCacheImage(\n cache,\n cacheName,\n notionUrl,\n hash,\n imageProxyBase,\n logger,\n );\n };\n}\n\nexport type { StorageBinary };\n","import type { ContentBlock } from \"./content/blocks\";\nimport { CMSError, isCMSError } from \"./errors\";\nimport { buildCacheImageFn } from \"./image\";\nimport type {\n BaseContentItem,\n CachedItemContent,\n CachedItemMeta,\n CMSHooks,\n ContentConfig,\n DataSource,\n ImageCacheOps,\n Logger,\n RendererFn,\n} from \"./types/index\";\n\n/**\n * `@notion-headless-cms/markdown-html` を動的 import してデフォルトレンダラーを返す。\n * core のゼロ依存ルールを守るため静的 import は禁止。\n */\nasync function loadDefaultRenderer(): Promise<RendererFn> {\n try {\n const mod = await import(\"@notion-headless-cms/markdown-html\");\n return (mod as { renderMarkdown: RendererFn }).renderMarkdown;\n } catch {\n throw new CMSError({\n code: \"core/config_invalid\",\n message:\n \"renderer が未指定で、@notion-headless-cms/markdown-html のロードにも失敗しました。\" +\n \" createClient の renderer オプションを指定するか、@notion-headless-cms/markdown-html をインストールしてください。\",\n context: { operation: \"loadDefaultRenderer\" },\n });\n }\n}\n\n/** 本文レンダリングに必要な依存を束ねたコンテキスト。 */\nexport interface RenderContext<T extends BaseContentItem> {\n source: DataSource<T>;\n rendererFn: RendererFn | undefined;\n imgCache: ImageCacheOps;\n imgCacheName: string;\n hasImageCache: boolean;\n imageProxyBase: string;\n contentConfig: ContentConfig | undefined;\n hooks: CMSHooks<T>;\n logger: Logger | undefined;\n}\n\n/**\n * メタデータキャッシュエントリを生成する。Notion API も renderer も呼ばない軽量関数。\n */\nexport function buildCachedItemMeta<T extends BaseContentItem>(\n item: T,\n source: DataSource<T>,\n): CachedItemMeta<T> {\n return {\n item,\n notionUpdatedAt: source.getLastModified(item),\n cachedAt: Date.now(),\n };\n}\n\n/**\n * アイテム本文を Markdown ロード → blocks 生成 → HTML レンダリング → フック適用まで\n * 実行し、本文キャッシュ用の `CachedItemContent` を返す。\n */\nexport async function buildCachedItemContent<T extends BaseContentItem>(\n item: T,\n ctx: RenderContext<T>,\n): Promise<CachedItemContent> {\n const start = Date.now();\n ctx.logger?.info?.(\"コンテンツのレンダリング開始\", {\n slug: item.slug,\n pageId: item.id,\n });\n ctx.hooks.onRenderStart?.(item.slug);\n\n let markdown: string;\n try {\n markdown = await ctx.source.loadMarkdown(item);\n } catch (err) {\n if (isCMSError(err)) throw err;\n throw new CMSError({\n code: \"source/load_markdown_failed\",\n message: \"Failed to load markdown from source.\",\n cause: err,\n context: {\n operation: \"buildCachedItemContent:loadMarkdown\",\n pageId: item.id,\n slug: item.slug,\n },\n });\n }\n\n let blocks: ContentBlock[];\n try {\n blocks = await ctx.source.loadBlocks(item);\n } catch (err) {\n if (isCMSError(err)) throw err;\n throw new CMSError({\n code: \"source/load_blocks_failed\",\n message: \"Failed to load blocks from source.\",\n cause: err,\n context: {\n operation: \"buildCachedItemContent:loadBlocks\",\n pageId: item.id,\n slug: item.slug,\n },\n });\n }\n\n // react-renderer など Notion 形式を直接消費する利用側のため、\n // DataSource が対応していれば BlockObjectResponse ツリーも取得・キャッシュする。\n // markdown 戦略のように loadNotionBlocks 未対応の場合は `source/blocks_unsupported`\n // を吸収して undefined にする (ページ描画は markdown 経路で代替する想定)。\n let notionBlocks: unknown[] | undefined;\n if (ctx.source.loadNotionBlocks) {\n try {\n notionBlocks = await ctx.source.loadNotionBlocks(item);\n } catch (err) {\n if (isCMSError(err) && err.is(\"source/blocks_unsupported\")) {\n notionBlocks = undefined;\n } else if (isCMSError(err)) {\n throw err;\n } else {\n throw new CMSError({\n code: \"source/load_blocks_failed\",\n message: \"Failed to load Notion blocks from source.\",\n cause: err,\n context: {\n operation: \"buildCachedItemContent:loadNotionBlocks\",\n pageId: item.id,\n slug: item.slug,\n },\n });\n }\n }\n }\n\n const cacheImage = ctx.hasImageCache\n ? buildCacheImageFn(\n ctx.imgCache,\n ctx.imgCacheName,\n ctx.imageProxyBase,\n ctx.logger,\n )\n : undefined;\n\n const rendererFn = ctx.rendererFn ?? (await loadDefaultRenderer());\n\n let html: string;\n try {\n html = await rendererFn(markdown, {\n imageProxyBase: ctx.imageProxyBase,\n cacheImage,\n remarkPlugins: ctx.contentConfig?.remarkPlugins,\n rehypePlugins: ctx.contentConfig?.rehypePlugins,\n });\n } catch (err) {\n if (isCMSError(err)) throw err;\n throw new CMSError({\n code: \"renderer/failed\",\n message: \"Failed to render markdown.\",\n cause: err,\n context: {\n operation: \"buildCachedItemContent:renderMarkdown\",\n pageId: item.id,\n slug: item.slug,\n },\n });\n }\n\n if (ctx.hooks.afterRender) {\n html = await ctx.hooks.afterRender(html, item);\n }\n\n let result: CachedItemContent = {\n html,\n blocks,\n markdown,\n notionBlocks,\n notionUpdatedAt: ctx.source.getLastModified(item),\n cachedAt: Date.now(),\n };\n\n if (ctx.hooks.beforeCacheContent) {\n result = await ctx.hooks.beforeCacheContent(result, item);\n }\n\n const durationMs = Date.now() - start;\n ctx.logger?.info?.(\"コンテンツのレンダリング完了\", {\n slug: item.slug,\n durationMs,\n });\n ctx.hooks.onRenderEnd?.(item.slug, durationMs);\n\n return result;\n}\n","export interface RetryConfig {\n retryOn: number[];\n maxRetries: number;\n baseDelayMs: number;\n /** true のとき指数バックオフにランダムジッターを加える(Thundering Herd 対策)。デフォルト: true */\n jitter?: boolean;\n onRetry?: (attempt: number, status: number) => void;\n}\n\nexport const DEFAULT_RETRY_CONFIG: RetryConfig = {\n retryOn: [429, 502, 503],\n maxRetries: 4,\n baseDelayMs: 1000,\n jitter: 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 fn: () => Promise<T>,\n config: RetryConfig,\n): Promise<T> {\n let lastError: unknown;\n for (let attempt = 0; attempt <= config.maxRetries; attempt++) {\n try {\n return await fn();\n } catch (err) {\n const status = (err as { status?: number }).status;\n if (status === undefined || !config.retryOn.includes(status)) {\n throw err;\n }\n lastError = err;\n if (attempt < config.maxRetries) {\n config.onRetry?.(attempt + 1, status);\n const jitterFactor =\n config.jitter !== false ? 0.5 + Math.random() * 0.5 : 1;\n const delay = config.baseDelayMs * 2 ** attempt * jitterFactor;\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n }\n throw lastError;\n}\n","import { isStale } from \"./cache\";\nimport { CMSError, isCMSError } from \"./errors\";\nimport type { RenderContext } from \"./rendering\";\nimport { buildCachedItemContent, buildCachedItemMeta } from \"./rendering\";\nimport type { RetryConfig } from \"./retry\";\nimport { withRetry } from \"./retry\";\nimport type {\n AdjacencyOptions,\n BaseContentItem,\n CachedItemContent,\n CachedItemList,\n CachedItemMeta,\n CheckResult,\n CMSHooks,\n CollectionCacheOps,\n CollectionClient,\n DataSource,\n DocumentCacheOps,\n FindOptions,\n ItemWithContent,\n ListOptions,\n Logger,\n SortOption,\n WarmOptions,\n WarmResult,\n WhereClause,\n} from \"./types/index\";\n\n/**\n * コレクション別キャッシュキーを生成する (item: `{collection}:{slug}` / list: `{collection}`)。\n *\n * 各 cache adapter は内部で独自のキー戦略を持つが、ログ出力や差分再計算で\n * 同一表現が必要になるため core 側にも公開する。\n */\nexport function collectionKey(collection: string, slug?: string): string {\n return slug ? `${collection}:${slug}` : collection;\n}\n\nexport interface CollectionContext<T extends BaseContentItem> {\n collection: string;\n source: DataSource<T>;\n docCache: DocumentCacheOps;\n docCacheName: string;\n render: RenderContext<T>;\n hooks: CMSHooks<T>;\n logger: Logger | undefined;\n ttlMs: number | undefined;\n publishedStatuses: string[];\n accessibleStatuses: string[];\n retryConfig: RetryConfig;\n maxConcurrent: number;\n waitUntil: ((p: Promise<unknown>) => void) | undefined;\n /**\n * slug として使うフィールド名。`source.properties[slugField].notion` を\n * Notion プロパティ名として `findByProp` を呼び出す。\n */\n slugField: string;\n}\n\nexport class CollectionClientImpl<T extends BaseContentItem>\n implements CollectionClient<T>\n{\n readonly cache: CollectionCacheOps<T>;\n\n constructor(private readonly ctx: CollectionContext<T>) {\n this.cache = {\n invalidate: () => this.invalidateImpl(),\n invalidateItem: (slug: string) => this.invalidateItemImpl(slug),\n warm: (opts?: WarmOptions) => this.warmImpl(opts),\n };\n }\n\n // ── 基本取得 ──────────────────────────────────────────────────────────\n\n async find(\n slug: string,\n opts: FindOptions = {},\n ): Promise<ItemWithContent<T> | null> {\n if (opts.bypassCache) {\n this.ctx.hooks.onCacheMiss?.(slug);\n const item = await this.fetchRaw(slug);\n if (!item) return null;\n const meta = await this.persistMeta(slug, item);\n await this.invalidateContentEntry(slug);\n return this.attachLazyContent(meta);\n }\n\n const cachedMeta = await this.ctx.docCache.getMeta<T>(\n this.ctx.collection,\n slug,\n );\n if (cachedMeta) {\n // TTL 切れはブロッキングで再取得する (stale を返さない要件)\n if (\n this.ctx.ttlMs !== undefined &&\n isStale(cachedMeta.cachedAt, this.ctx.ttlMs)\n ) {\n this.ctx.logger?.debug?.(\"キャッシュ期限切れ(TTL)、フェッチ\", {\n operation: \"find\",\n slug,\n collection: this.ctx.collection,\n cacheAdapter: this.ctx.docCacheName,\n });\n this.ctx.hooks.onCacheMiss?.(slug);\n const item = await this.fetchRaw(slug);\n if (!item) return null;\n const meta = await this.persistMeta(slug, item);\n await this.invalidateContentEntry(slug);\n return this.attachLazyContent(meta);\n }\n // SWR: 即時返却しつつバックグラウンドで差分チェック\n const bg = this.checkAndUpdateItemBg(slug, cachedMeta);\n if (this.ctx.waitUntil) this.ctx.waitUntil(bg);\n this.ctx.logger?.debug?.(\"キャッシュヒット\", {\n operation: \"find\",\n slug,\n collection: this.ctx.collection,\n cacheAdapter: this.ctx.docCacheName,\n cachedAt: cachedMeta.cachedAt,\n });\n this.ctx.hooks.onCacheHit?.(slug, cachedMeta);\n return this.attachLazyContent(cachedMeta);\n }\n\n this.ctx.logger?.debug?.(\"キャッシュミス、フェッチ\", {\n operation: \"find\",\n slug,\n collection: this.ctx.collection,\n cacheAdapter: this.ctx.docCacheName,\n });\n this.ctx.hooks.onCacheMiss?.(slug);\n const item = await this.fetchRaw(slug);\n if (!item) return null;\n // 保存だけはバックグラウンド可: ユーザー向けレスポンスを早めに返す\n const meta = await this.persistMeta(slug, item, { background: true });\n return this.attachLazyContent(meta);\n }\n\n async list(opts?: ListOptions<T>): Promise<T[]> {\n const allItems = await this.fetchList();\n return applyListOptions(allItems, opts);\n }\n\n async params(): Promise<string[]> {\n const items = await this.fetchList();\n return items.map((item) => item.slug);\n }\n\n async peekVersion(\n slug: string,\n ): Promise<{ notionUpdatedAt: string; cachedAt: number } | null> {\n const meta = await this.ctx.docCache.getMeta<T>(this.ctx.collection, slug);\n if (!meta) return null;\n return { notionUpdatedAt: meta.notionUpdatedAt, cachedAt: meta.cachedAt };\n }\n\n async check(\n slug: string,\n currentVersion: string,\n ): Promise<CheckResult<T> | null> {\n const raw = await this.fetchRaw(slug);\n if (!raw) return null;\n if (raw.lastEditedTime === currentVersion) return { stale: false };\n const meta = await this.persistMeta(slug, raw);\n await this.invalidateContentEntry(slug);\n return { stale: true, item: this.attachLazyContent(meta) };\n }\n\n async adjacent(\n slug: string,\n opts?: AdjacencyOptions<T>,\n ): Promise<{ prev: T | null; next: T | null }> {\n const items = applyListOptions(await this.fetchList(), {\n sort: opts?.sort,\n });\n const index = items.findIndex((it) => it.slug === slug);\n if (index === -1) return { prev: null, next: null };\n return {\n prev: index > 0 ? (items[index - 1] ?? null) : null,\n next: index < items.length - 1 ? (items[index + 1] ?? null) : null,\n };\n }\n\n // ── キャッシュ操作 ────────────────────────────────────────────────────\n\n private async invalidateImpl(): Promise<void> {\n this.ctx.logger?.debug?.(\"コレクション全体のキャッシュを無効化\", {\n operation: \"cache.invalidate\",\n collection: this.ctx.collection,\n cacheAdapter: this.ctx.docCacheName,\n });\n await this.ctx.docCache.invalidate({ collection: this.ctx.collection });\n }\n\n private async invalidateItemImpl(slug: string): Promise<void> {\n this.ctx.logger?.debug?.(\"アイテムキャッシュを無効化\", {\n operation: \"cache.invalidateItem\",\n collection: this.ctx.collection,\n cacheAdapter: this.ctx.docCacheName,\n slug,\n });\n await this.ctx.docCache.invalidate({\n collection: this.ctx.collection,\n slug,\n });\n }\n\n private async warmImpl(opts?: WarmOptions): Promise<WarmResult> {\n const items = await this.fetchListRaw();\n const concurrency = opts?.concurrency ?? this.ctx.maxConcurrent;\n let ok = 0;\n const failed: Array<{ slug: string; error: unknown }> = [];\n\n for (let i = 0; i < items.length; i += concurrency) {\n const chunk = items.slice(i, i + concurrency);\n await Promise.all(\n chunk.map(async (item) => {\n try {\n await this.persistMeta(item.slug, item);\n const content = await buildCachedItemContent(item, this.ctx.render);\n await this.ctx.docCache.setContent(\n this.ctx.collection,\n item.slug,\n content,\n );\n ok++;\n } catch (err) {\n failed.push({ slug: item.slug, error: err });\n this.ctx.logger?.warn?.(\"warm: アイテムの事前レンダリングに失敗\", {\n slug: item.slug,\n pageId: item.id,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }),\n );\n opts?.onProgress?.(Math.min(i + concurrency, items.length), items.length);\n }\n\n await this.ctx.docCache.setList(this.ctx.collection, {\n items,\n cachedAt: Date.now(),\n });\n return { ok, failed };\n }\n\n // ── 内部 ──────────────────────────────────────────────────────────────\n\n private async persistMeta(\n slug: string,\n item: T,\n opts: { background?: boolean } = {},\n ): Promise<CachedItemMeta<T>> {\n let meta = buildCachedItemMeta(item, this.ctx.source);\n if (this.ctx.hooks.beforeCacheMeta) {\n meta = await this.ctx.hooks.beforeCacheMeta(meta);\n }\n const save = this.ctx.docCache.setMeta(this.ctx.collection, slug, meta);\n if (opts.background && this.ctx.waitUntil) {\n this.ctx.waitUntil(save);\n } else {\n await save;\n }\n return meta;\n }\n\n private async invalidateContentEntry(slug: string): Promise<void> {\n await this.ctx.docCache.invalidate({\n collection: this.ctx.collection,\n slug,\n kind: \"content\",\n });\n }\n\n /** 本文キャッシュ。メタとの整合 (`notionUpdatedAt`) が崩れていれば再生成して書き戻す。 */\n private async loadOrBuildContent(\n slug: string,\n item: T,\n ): Promise<CachedItemContent> {\n const expected = this.ctx.source.getLastModified(item);\n const cached = await this.ctx.docCache.getContent(\n this.ctx.collection,\n slug,\n );\n if (cached && cached.notionUpdatedAt === expected) {\n return cached;\n }\n\n const fresh = await buildCachedItemContent(item, this.ctx.render);\n await this.ctx.docCache.setContent(this.ctx.collection, slug, fresh);\n this.ctx.hooks.onContentRevalidated?.(slug, fresh);\n return fresh;\n }\n\n /** メタ既知の状態で本文だけ再生成する。エラーは onSwrError フックに通知して握り潰す。 */\n private async rebuildContentBg(slug: string, item: T): Promise<void> {\n try {\n const fresh = await buildCachedItemContent(item, this.ctx.render);\n await this.ctx.docCache.setContent(this.ctx.collection, slug, fresh);\n this.ctx.hooks.onContentRevalidated?.(slug, fresh);\n } catch (err) {\n const cmsErr = isCMSError(err)\n ? err\n : new CMSError({\n code: \"swr/content_rebuild_failed\",\n message: \"SWR background content rebuild failed.\",\n cause: err,\n context: {\n operation: \"swr.rebuildContentBg\",\n collection: this.ctx.collection,\n slug,\n },\n });\n this.ctx.hooks.onSwrError?.(cmsErr, { phase: \"item-content\", slug });\n this.ctx.logger?.warn?.(\"本文のバックグラウンド再生成に失敗\", {\n slug,\n collection: this.ctx.collection,\n code: cmsErr.code,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n private attachLazyContent(meta: CachedItemMeta<T>): ItemWithContent<T> {\n const slug = meta.item.slug;\n const item = meta.item;\n // html() / markdown() / blocks() を同じアイテムから複数回呼んでも I/O は 1 回に集約する\n let payloadPromise: Promise<CachedItemContent> | undefined;\n const loadPayload = (): Promise<CachedItemContent> => {\n if (!payloadPromise) {\n payloadPromise = this.loadOrBuildContent(slug, item);\n }\n return payloadPromise;\n };\n\n return Object.assign(Object.create(null) as object, item, {\n html: async () => (await loadPayload()).html,\n markdown: async () => (await loadPayload()).markdown,\n blocks: async () => (await loadPayload()).blocks,\n notionBlocks: async () => (await loadPayload()).notionBlocks,\n }) as ItemWithContent<T>;\n }\n\n private async fetchList(): Promise<T[]> {\n const cached = await this.ctx.docCache.getList<T>(this.ctx.collection);\n if (cached) {\n // TTL 切れはブロッキングで再取得する (find と同じ理由)\n if (\n this.ctx.ttlMs !== undefined &&\n isStale(cached.cachedAt, this.ctx.ttlMs)\n ) {\n this.ctx.logger?.debug?.(\"リストキャッシュ期限切れ(TTL)、フェッチ\", {\n operation: \"list\",\n collection: this.ctx.collection,\n cacheAdapter: this.ctx.docCacheName,\n });\n this.ctx.hooks.onListCacheMiss?.();\n const items = await this.fetchListRaw();\n await this.ctx.docCache.setList(this.ctx.collection, {\n items,\n cachedAt: Date.now(),\n });\n return items;\n }\n const bg = this.checkAndUpdateListBg(cached);\n if (this.ctx.waitUntil) this.ctx.waitUntil(bg);\n this.ctx.logger?.debug?.(\"リストキャッシュヒット\", {\n operation: \"list\",\n collection: this.ctx.collection,\n cacheAdapter: this.ctx.docCacheName,\n });\n this.ctx.hooks.onListCacheHit?.(cached);\n return cached.items;\n }\n\n this.ctx.logger?.debug?.(\"リストキャッシュミス、フェッチ\", {\n operation: \"list\",\n collection: this.ctx.collection,\n cacheAdapter: this.ctx.docCacheName,\n });\n this.ctx.hooks.onListCacheMiss?.();\n const items = await this.fetchListRaw();\n const cachedAt = Date.now();\n const save = this.ctx.docCache.setList(this.ctx.collection, {\n items,\n cachedAt,\n });\n if (this.ctx.waitUntil) {\n this.ctx.waitUntil(save);\n } else {\n await save;\n }\n return items;\n }\n\n private async checkAndUpdateItemBg(\n slug: string,\n cached: CachedItemMeta<T>,\n ): Promise<void> {\n try {\n const item = await this.fetchRaw(slug);\n if (!item) return;\n const lm = this.ctx.source.getLastModified(item);\n if (lm !== cached.notionUpdatedAt) {\n const meta = await this.persistMeta(slug, item);\n await this.invalidateContentEntry(slug);\n this.ctx.logger?.debug?.(\"SWR: 差分を検出、メタを差し替え\", {\n operation: \"find:bg\",\n slug,\n collection: this.ctx.collection,\n notionUpdatedAt: cached.notionUpdatedAt,\n });\n this.ctx.hooks.onCacheRevalidated?.(slug, meta);\n await this.rebuildContentBg(slug, item);\n } else {\n await this.ctx.docCache.setMeta(this.ctx.collection, slug, {\n ...cached,\n cachedAt: Date.now(),\n });\n this.ctx.logger?.debug?.(\"SWR: 差分なし、cachedAt を更新\", {\n operation: \"find:bg\",\n slug,\n collection: this.ctx.collection,\n });\n }\n } catch (err) {\n const cmsErr = isCMSError(err)\n ? err\n : new CMSError({\n code: \"swr/item_check_failed\",\n message: \"SWR background item check failed.\",\n cause: err,\n context: {\n operation: \"swr.checkAndUpdateItemBg\",\n collection: this.ctx.collection,\n slug,\n },\n });\n this.ctx.hooks.onSwrError?.(cmsErr, { phase: \"item-meta\", slug });\n this.ctx.logger?.warn?.(\n \"SWR: アイテムのバックグラウンド差分チェックに失敗\",\n {\n slug,\n collection: this.ctx.collection,\n code: cmsErr.code,\n error: err instanceof Error ? err.message : String(err),\n },\n );\n }\n }\n\n private async checkAndUpdateListBg(cached: CachedItemList<T>): Promise<void> {\n try {\n const items = await this.fetchListRaw();\n if (\n this.ctx.source.getListVersion(items) !==\n this.ctx.source.getListVersion(cached.items)\n ) {\n const listEntry = { items, cachedAt: Date.now() };\n await this.ctx.docCache.setList(this.ctx.collection, listEntry);\n this.ctx.logger?.debug?.(\n \"SWR: リスト差分を検出、キャッシュを差し替え\",\n {\n operation: \"list:bg\",\n collection: this.ctx.collection,\n },\n );\n this.ctx.hooks.onListCacheRevalidated?.(listEntry);\n } else if (this.ctx.ttlMs !== undefined) {\n await this.ctx.docCache.setList(this.ctx.collection, {\n ...cached,\n cachedAt: Date.now(),\n });\n this.ctx.logger?.debug?.(\"SWR: リスト差分なし、TTL をリセット\", {\n operation: \"list:bg\",\n collection: this.ctx.collection,\n });\n }\n } catch (err) {\n const cmsErr = isCMSError(err)\n ? err\n : new CMSError({\n code: \"swr/list_check_failed\",\n message: \"SWR background list check failed.\",\n cause: err,\n context: {\n operation: \"swr.checkAndUpdateListBg\",\n collection: this.ctx.collection,\n },\n });\n this.ctx.hooks.onSwrError?.(cmsErr, { phase: \"list\" });\n this.ctx.logger?.warn?.(\n \"SWR: リストのバックグラウンド差分チェックに失敗\",\n {\n collection: this.ctx.collection,\n code: cmsErr.code,\n error: err instanceof Error ? err.message : String(err),\n },\n );\n }\n }\n\n private async fetchListRaw(): Promise<T[]> {\n const items = await withRetry(\n () =>\n this.ctx.source.list({\n publishedStatuses:\n this.ctx.publishedStatuses.length > 0\n ? this.ctx.publishedStatuses\n : undefined,\n }),\n {\n ...this.ctx.retryConfig,\n onRetry: (attempt, status) => {\n this.ctx.logger?.warn?.(\"list() リトライ中\", { attempt, status });\n },\n },\n );\n return items.filter((item) => {\n if (item.isArchived || item.isInTrash) return false;\n if (\n this.ctx.accessibleStatuses.length > 0 &&\n (!item.status || !this.ctx.accessibleStatuses.includes(item.status))\n )\n return false;\n return true;\n });\n }\n\n private async fetchRaw(slug: string): Promise<T | null> {\n const retryOpts = {\n ...this.ctx.retryConfig,\n onRetry: (attempt: number, status: number) => {\n this.ctx.logger?.warn?.(\"find() リトライ中\", {\n attempt,\n status,\n slug,\n });\n },\n };\n\n // PropertyMap が解決できる場合は単一プロパティ filter で 1 ページだけ取得する (高速)\n const notionPropName =\n this.ctx.source.properties?.[this.ctx.slugField]?.notion;\n\n let item: T | null;\n const findByProp = this.ctx.source.findByProp?.bind(this.ctx.source);\n if (notionPropName && findByProp) {\n item = await withRetry(() => findByProp(notionPropName, slug), retryOpts);\n } else {\n // PropertyMap 未提供 / findByProp 未実装の DataSource 向けフォールバック\n const all = await withRetry(() => this.ctx.source.list(), retryOpts);\n item = all.find((i) => i.slug === slug) ?? null;\n }\n\n if (!item) return null;\n if (item.isArchived || item.isInTrash) return null;\n if (\n this.ctx.accessibleStatuses.length > 0 &&\n (!item.status || !this.ctx.accessibleStatuses.includes(item.status))\n ) {\n return null;\n }\n return item;\n }\n}\n\nfunction matchesWhere<T extends BaseContentItem>(\n item: T,\n where: WhereClause<T>,\n): boolean {\n for (const key of Object.keys(where) as (keyof T & string)[]) {\n const expected = where[key];\n const actual = item[key];\n if (Array.isArray(expected)) {\n if (!(expected as readonly unknown[]).includes(actual)) return false;\n } else {\n if (actual !== expected) return false;\n }\n }\n return true;\n}\n\nfunction applyListOptions<T extends BaseContentItem>(\n items: T[],\n opts?: ListOptions<T>,\n): T[] {\n if (!opts) return sortByPublishedAtDesc(items);\n let result = items;\n\n if (opts.statuses) {\n const allow = new Set(\n Array.isArray(opts.statuses) ? opts.statuses : [opts.statuses],\n );\n result = result.filter((it) => it.status != null && allow.has(it.status));\n }\n\n if (opts.tag) {\n const tag = opts.tag;\n result = result.filter((it) => {\n const tags = (it as { tags?: string[] }).tags;\n return Array.isArray(tags) && tags.includes(tag);\n });\n }\n\n if (opts.where) {\n const where = opts.where;\n result = result.filter((it) => matchesWhere(it, where));\n }\n\n if (opts.filter) {\n result = result.filter(opts.filter);\n }\n\n if (opts.sort) {\n result = [...result].sort(makeComparator(opts.sort));\n } else {\n result = sortByPublishedAtDesc(result);\n }\n\n const skip = opts.skip ?? 0;\n const limit = opts.limit;\n if (skip > 0 || limit !== undefined) {\n result = result.slice(skip, limit !== undefined ? skip + limit : undefined);\n }\n\n return result;\n}\n\n/** publishedAt 降順 (未設定なら lastEditedTime 降順) でソートする。 */\nfunction sortByPublishedAtDesc<T extends BaseContentItem>(items: T[]): T[] {\n return [...items].sort((a, b) => {\n const av = a.publishedAt ?? a.lastEditedTime;\n const bv = b.publishedAt ?? b.lastEditedTime;\n if (av === bv) return 0;\n return av > bv ? -1 : 1;\n });\n}\n\nfunction makeComparator<T extends BaseContentItem>(\n sort: SortOption<T>,\n): (a: T, b: T) => number {\n if (sort.compare) return sort.compare;\n const by = sort.by as keyof T;\n const dir = sort.dir === \"asc\" ? 1 : -1;\n return (a, b) => {\n const av = a[by];\n const bv = b[by];\n if (av === bv) return 0;\n if (av === undefined || av === null) return 1;\n if (bv === undefined || bv === null) return -1;\n if (typeof av === \"string\" && typeof bv === \"string\") {\n return av > bv ? dir : -dir;\n }\n if (typeof av === \"number\" && typeof bv === \"number\") {\n return av > bv ? dir : -dir;\n }\n throw new CMSError({\n code: \"core/sort_unsupported_type\",\n message: `\"${String(by)}\" フィールドの型 \"${typeof av}\" はソート非対応です。compare 関数を指定してください。`,\n context: {\n operation: \"makeComparator\",\n field: String(by),\n type: typeof av,\n },\n });\n };\n}\n","import { isCMSError } from \"./errors\";\nimport type { ImageCacheOps, InvalidateScope } from \"./types/index\";\n\n/** `$handler()` の挙動設定。 */\nexport interface HandlerOptions {\n /** マウントするベースパス。デフォルト `/api/cms`。 */\n basePath?: string;\n /** 画像プロキシのパス (basePath 相対)。デフォルト `/images/:hash`。 */\n imagesPath?: string;\n /** revalidate webhook のパス (basePath 相対)。デフォルト `/revalidate`。 */\n revalidatePath?: string;\n /** Webhook 署名検証用シークレット (未指定なら検証スキップ)。 */\n webhookSecret?: string;\n /** デフォルト実装を無効化する場合 true。 */\n disabled?: boolean;\n}\n\n/** `$handler()` が内部で依存する CMS 機能の最小セット。 */\nexport interface HandlerAdapter {\n imageCache: ImageCacheOps;\n /**\n * 指定コレクションの DataSource.parseWebhook を呼ぶ。\n * 未知コレクション → `webhook/unknown_collection` CMSError\n * parseWebhook 未実装 → `webhook/not_implemented` CMSError\n */\n parseWebhookFor(\n collection: string,\n req: Request,\n webhookSecret: string | undefined,\n ): Promise<InvalidateScope>;\n revalidate(scope: InvalidateScope): Promise<void>;\n}\n\nconst DEFAULT_OPTS = {\n basePath: \"/api/cms\",\n imagesPath: \"/images\",\n revalidatePath: \"/revalidate\",\n} as const;\n\n/** Webhook 系の CMSError コードを HTTP ステータスへ写像する。未対応コードは null。 */\nfunction webhookErrorStatus(code: string): number | null {\n if (code === \"webhook/signature_invalid\") return 401;\n if (code === \"webhook/not_implemented\") return 501;\n if (code === \"webhook/unknown_collection\") return 404;\n if (code === \"webhook/payload_invalid\") return 400;\n return null;\n}\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/:collection` — Webhook 受信 + $revalidate()\n */\nexport function createHandler(\n adapter: HandlerAdapter,\n opts: HandlerOptions = {},\n): (req: Request) => Promise<Response> {\n const basePath = trimTrailingSlash(opts.basePath ?? DEFAULT_OPTS.basePath);\n const imagesPath = opts.imagesPath ?? DEFAULT_OPTS.imagesPath;\n const revalidatePath = opts.revalidatePath ?? DEFAULT_OPTS.revalidatePath;\n\n return async (req: Request): Promise<Response> => {\n const url = new URL(req.url);\n const path = url.pathname;\n\n if (!path.startsWith(basePath)) {\n return new Response(\"Not Found\", { status: 404 });\n }\n const rel = path.slice(basePath.length) || \"/\";\n\n if (req.method === \"GET\" && rel.startsWith(`${imagesPath}/`)) {\n const hash = rel.slice(imagesPath.length + 1);\n if (!hash) return new Response(\"Bad Request\", { status: 400 });\n const object = await adapter.imageCache.get(hash);\n if (!object) return new Response(\"Not Found\", { status: 404 });\n const headers = new Headers();\n if (object.contentType) headers.set(\"content-type\", object.contentType);\n headers.set(\"cache-control\", \"public, max-age=31536000, immutable\");\n return new Response(object.data, { headers });\n }\n\n if (req.method === \"POST\" && rel.startsWith(`${revalidatePath}/`)) {\n const collection = rel.slice(revalidatePath.length + 1);\n if (!collection || collection.includes(\"/\")) {\n return new Response(\n JSON.stringify({ ok: false, reason: \"collection required\" }),\n { status: 400, headers: { \"content-type\": \"application/json\" } },\n );\n }\n try {\n const scope = await adapter.parseWebhookFor(\n collection,\n req,\n opts.webhookSecret,\n );\n await adapter.revalidate(scope);\n return new Response(JSON.stringify({ ok: true, scope }), {\n status: 200,\n headers: { \"content-type\": \"application/json\" },\n });\n } catch (err) {\n if (isCMSError(err)) {\n const status = webhookErrorStatus(err.code);\n if (status !== null) {\n return new Response(JSON.stringify({ ok: false, code: err.code }), {\n status,\n headers: { \"content-type\": \"application/json\" },\n });\n }\n }\n throw err;\n }\n }\n\n return new Response(\"Not Found\", { status: 404 });\n };\n}\n\nfunction trimTrailingSlash(s: string): string {\n return 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 { buildCacheImageFn } from \"./image\";\nimport type { RenderContext } from \"./rendering\";\nimport type { RetryConfig } from \"./retry\";\nimport { DEFAULT_RETRY_CONFIG } from \"./retry\";\nimport type {\n BaseContentItem,\n CacheAdapter,\n CMSHooks,\n CollectionClient,\n CollectionsConfig,\n CreateClientOptions,\n DataSource,\n DocumentCacheOps,\n ImageCacheOps,\n InferCollectionItem,\n InvalidateScope,\n Logger,\n LogLevel,\n RendererFn,\n StorageBinary,\n} from \"./types/index\";\nimport type {\n CMSAdapter,\n CMSSources,\n MergeSourceCollections,\n} from \"./types/sources\";\n\nconst DEFAULT_IMAGE_PROXY_BASE = \"/api/images\";\n\n/** コレクション別アクセス + グローバル操作の合成型。 */\nexport type CMSClient<C extends CollectionsConfig> = {\n [K in keyof C]: CollectionClient<InferCollectionItem<C[K]>>;\n} & CMSGlobalOps;\n\nexport interface CMSGlobalOps {\n readonly collections: readonly string[];\n invalidate(scope?: InvalidateScope): Promise<void>;\n /** Web Standard な Request/Response ベースのルートハンドラ (画像プロキシ + webhook)。 */\n handler(opts?: HandlerOptions): (req: Request) => Promise<Response>;\n getCachedImage(hash: string): Promise<StorageBinary | null>;\n /**\n * Notion 画像 URL を `{imageProxyBase}/{sha256}` 形式へ変換しキャッシュへ書き込む。\n * 画像キャッシュが未設定 (noop) の場合は `undefined`。\n */\n readonly cacheImage: ((url: string) => Promise<string>) | undefined;\n readonly imageProxyBase: string;\n}\n\ninterface ResolvedCache {\n doc: DocumentCacheOps;\n docName: string;\n img: ImageCacheOps;\n imgName: string;\n hasImg: boolean;\n}\n\n/**\n * adapter の `handles` を見て先勝ちで document / image を割り当てる。未指定は両方 noop。\n */\nfunction resolveCache(\n cache: readonly CacheAdapter[] | undefined,\n): ResolvedCache {\n const adapters = cache ?? [];\n\n let doc: DocumentCacheOps = noopDocOps;\n let docName = \"noop-document\";\n let img: ImageCacheOps = noopImgOps;\n let imgName = \"noop-image\";\n let docFound = false;\n let imgFound = false;\n\n for (const adapter of adapters) {\n if (!docFound && adapter.handles.includes(\"document\") && adapter.doc) {\n doc = adapter.doc;\n docName = adapter.name;\n docFound = true;\n }\n if (!imgFound && adapter.handles.includes(\"image\") && adapter.img) {\n img = adapter.img;\n imgName = adapter.name;\n imgFound = true;\n }\n }\n\n return { doc, docName, img, imgName, hasImg: imgFound };\n}\n\nconst LOG_LEVEL_ORDER: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\n\nfunction applyLogLevel(\n logger: Logger | undefined,\n minLevel: LogLevel,\n): Logger | undefined {\n if (!logger) return undefined;\n const minOrder = LOG_LEVEL_ORDER[minLevel];\n const filtered: Logger = {};\n for (const level of [\"debug\", \"info\", \"warn\", \"error\"] as const) {\n if (LOG_LEVEL_ORDER[level] >= minOrder) {\n filtered[level] = logger[level];\n }\n }\n return filtered;\n}\n\n/**\n * CMS クライアントを生成する。\n *\n * @example\n * import { createClient, nodePreset } from \"@notion-headless-cms/core\";\n * import { notionSource } from \"@notion-headless-cms/notion-source\";\n * import { schema } from \"./generated/nhc.schema\";\n *\n * const cms = createClient({\n * sources: { notion: notionSource({ schema, token: process.env.NOTION_TOKEN! }) },\n * ...nodePreset(),\n * });\n *\n * const posts = await cms.posts.list();\n */\nexport function createClient<S extends CMSSources = CMSSources>(\n opts: CreateClientOptions<S>,\n): CMSClient<\n MergeSourceCollections<S> extends CollectionsConfig\n ? MergeSourceCollections<S>\n : CollectionsConfig\n> {\n // sources の各アダプタが持つ collections をマージする\n const collectionsInput: CollectionsConfig = {};\n if (opts.sources) {\n for (const adapter of Object.values(\n opts.sources as unknown as Record<string, CMSAdapter | undefined>,\n )) {\n if (adapter) Object.assign(collectionsInput, adapter.collections);\n }\n }\n\n if (Object.keys(collectionsInput).length === 0) {\n throw new CMSError({\n code: \"core/config_invalid\",\n message:\n \"createClient: sources に少なくとも 1 つのコレクションを指定してください。\",\n context: { operation: \"createClient\" },\n nextSteps: [\n \"notionSource({ schema, token }) を sources.notion に渡す\",\n \"`nhc generate` でスキーマを生成してから import する\",\n ],\n docsUrl:\n \"https://github.com/kjfsm/notion-headless-cms/blob/main/docs/quickstart.md\",\n });\n }\n\n for (const [name, def] of Object.entries(collectionsInput)) {\n if (!def.source) {\n throw new CMSError({\n code: \"core/config_invalid\",\n message: `createClient: コレクション \"${name}\" の source は必須です。`,\n context: { operation: \"createClient\", collection: name },\n nextSteps: [\"notionSource(...) を sources に渡しているか確認する\"],\n });\n }\n if (!def.slugField) {\n throw new CMSError({\n code: \"core/config_invalid\",\n message: `createClient: コレクション \"${name}\" の slugField は必須です。`,\n context: { operation: \"createClient\", collection: name },\n nextSteps: [\n `nhc.config.ts の ${name} コレクションに slugField を設定する`,\n ],\n });\n }\n }\n\n const cacheRes = resolveCache(opts.cache);\n const ttlMs = opts.swr?.ttlMs;\n const imageProxyBase = opts.imageProxyBase ?? DEFAULT_IMAGE_PROXY_BASE;\n const contentConfig = opts.content;\n const rendererFn: RendererFn | undefined = opts.renderer;\n const waitUntil = opts.waitUntil;\n const baseLogger: Logger | undefined = mergeLoggers(\n opts.plugins ?? [],\n opts.logger,\n );\n const logger = opts.logLevel\n ? applyLogLevel(baseLogger, opts.logLevel)\n : baseLogger;\n const hooks: CMSHooks<BaseContentItem> = mergeHooks(\n opts.plugins ?? [],\n opts.hooks,\n logger,\n );\n const maxConcurrent = opts.rateLimiter?.maxConcurrent ?? 3;\n const retryConfig: RetryConfig = {\n ...DEFAULT_RETRY_CONFIG,\n ...(opts.rateLimiter ?? {}),\n };\n\n const collectionNames: string[] = [];\n const collections: Record<string, CollectionClient<BaseContentItem>> = {};\n for (const [name, def] of Object.entries(collectionsInput)) {\n collectionNames.push(name);\n const source = def.source as DataSource<BaseContentItem>;\n const colHooks = def.hooks as CMSHooks<BaseContentItem> | undefined;\n const collectionHooks: CMSHooks<BaseContentItem> = colHooks\n ? mergeHooks([{ name: `${name}:global`, hooks }], colHooks, logger)\n : hooks;\n const renderCtx: RenderContext<BaseContentItem> = {\n source,\n rendererFn,\n imgCache: cacheRes.img,\n imgCacheName: cacheRes.imgName,\n hasImageCache: cacheRes.hasImg,\n imageProxyBase,\n contentConfig,\n hooks: collectionHooks,\n logger,\n };\n const ctx: CollectionContext<BaseContentItem> = {\n collection: name,\n source,\n docCache: cacheRes.doc,\n docCacheName: cacheRes.docName,\n render: renderCtx,\n hooks: collectionHooks,\n logger,\n ttlMs,\n publishedStatuses: def.publishedStatuses\n ? [...def.publishedStatuses]\n : [],\n accessibleStatuses: def.accessibleStatuses\n ? [...def.accessibleStatuses]\n : [],\n retryConfig,\n maxConcurrent,\n waitUntil,\n slugField: def.slugField,\n };\n collections[name] = new CollectionClientImpl(ctx);\n }\n\n const cacheImage = cacheRes.hasImg\n ? buildCacheImageFn(cacheRes.img, cacheRes.imgName, imageProxyBase, logger)\n : undefined;\n\n const globalOps: CMSGlobalOps = {\n collections: collectionNames,\n cacheImage,\n imageProxyBase,\n async invalidate(scope?: InvalidateScope): Promise<void> {\n logger?.debug?.(\"グローバルキャッシュを無効化\", {\n operation: \"invalidate\",\n cacheAdapter: cacheRes.docName,\n });\n await cacheRes.doc.invalidate(scope ?? \"all\");\n },\n handler(handlerOpts?: HandlerOptions) {\n return createHandler(\n {\n imageCache: cacheRes.img,\n async parseWebhookFor(collection, req, webhookSecret) {\n const def = collectionsInput[collection];\n if (!def) {\n throw new CMSError({\n code: \"webhook/unknown_collection\",\n message: `Unknown collection: ${collection}`,\n context: { operation: \"parseWebhookFor\", collection },\n });\n }\n const ds = def.source as DataSource<BaseContentItem>;\n if (!ds.parseWebhook) {\n throw new CMSError({\n code: \"webhook/not_implemented\",\n message: `Collection \"${collection}\" does not support webhooks.`,\n context: { operation: \"parseWebhookFor\", collection },\n });\n }\n return ds.parseWebhook(req, { secret: webhookSecret });\n },\n revalidate: (scope) => globalOps.invalidate(scope),\n },\n handlerOpts,\n );\n },\n getCachedImage(hash) {\n return cacheRes.img.get(hash);\n },\n };\n\n return Object.assign(\n Object.create(null) as object,\n collections,\n globalOps,\n ) as CMSClient<\n MergeSourceCollections<S> extends CollectionsConfig\n ? MergeSourceCollections<S>\n : CollectionsConfig\n >;\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 name: string;\n hooks?: CMSHooks<T>;\n logger?: Partial<Logger>;\n}\n\nexport function definePlugin<T extends BaseContentItem>(\n plugin: CMSPlugin<T>,\n): CMSPlugin<T> {\n return plugin;\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as CachedItemMeta, i as CachedItemList, r as CachedItemContent, t as BaseContentItem } from "./content-DwsfWZao.mjs";
|
|
2
|
-
import { n as CMSError } from "./errors-
|
|
2
|
+
import { n as CMSError } from "./errors-DcNErfYk.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/types/hooks.d.ts
|
|
5
5
|
type MaybePromise<T> = T | Promise<T>;
|
|
@@ -73,4 +73,4 @@ interface CMSPlugin<T extends BaseContentItem = BaseContentItem> {
|
|
|
73
73
|
declare function definePlugin<T extends BaseContentItem>(plugin: CMSPlugin<T>): CMSPlugin<T>;
|
|
74
74
|
//#endregion
|
|
75
75
|
export { MaybePromise as a, CMSHooks as i, definePlugin as n, Logger as r, CMSPlugin as t };
|
|
76
|
-
//# sourceMappingURL=plugin-
|
|
76
|
+
//# sourceMappingURL=plugin-Dct12kp2.d.mts.map
|
package/dist/preset/node.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as CacheAdapter } from "../cache-DS81aOcC.mjs";
|
|
2
|
-
import { d as SWRConfig } from "../config-
|
|
2
|
+
import { d as SWRConfig } from "../config-DYxyW3SR.mjs";
|
|
3
3
|
import { MemoryCacheOptions } from "../cache/memory.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/preset/node.d.ts
|
package/dist/source-author.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { t as BaseContentItem } from "./content-DwsfWZao.mjs";
|
|
2
|
-
import { a as InferCollectionItem, f as CMSAdapter, m as MergeSourceCollections, n as CollectionsConfig, p as CMSSources, t as CollectionDef } from "./config-
|
|
2
|
+
import { a as InferCollectionItem, f as CMSAdapter, m as MergeSourceCollections, n as CollectionsConfig, p as CMSSources, t as CollectionDef } from "./config-DYxyW3SR.mjs";
|
|
3
3
|
export type { BaseContentItem, CMSAdapter, CMSSources, CollectionDef, CollectionsConfig, InferCollectionItem, MergeSourceCollections };
|