@notion-headless-cms/core 0.3.12 → 0.3.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cache/memory.d.mts +1 -1
- package/dist/cache/memory.mjs +1 -1
- package/dist/cache/memory.mjs.map +1 -1
- package/dist/{content-CYf6NtCC.d.mts → content-D7PfY-bV.d.mts} +17 -9
- package/dist/errors-CC_x98vG.d.mts +84 -0
- package/dist/errors.d.mts +2 -56
- package/dist/errors.mjs +23 -1
- package/dist/errors.mjs.map +1 -1
- package/dist/{hooks-D3omfgl4.d.mts → hooks-C4HRqHLo.d.mts} +12 -2
- package/dist/hooks.d.mts +1 -1
- package/dist/hooks.mjs.map +1 -1
- package/dist/index.d.mts +98 -68
- package/dist/index.mjs +286 -173
- package/dist/index.mjs.map +1 -1
- package/dist/{memory-Cp-dnNGC.d.mts → memory-BKDsuGVN.d.mts} +3 -3
- package/package.json +2 -4
package/dist/cache/memory.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as memoryCache, n as MemoryDocumentOptions, r as MemoryImageOptions, t as MemoryCacheOptions } from "../memory-
|
|
1
|
+
import { i as memoryCache, n as MemoryDocumentOptions, r as MemoryImageOptions, t as MemoryCacheOptions } from "../memory-BKDsuGVN.mjs";
|
|
2
2
|
export { MemoryCacheOptions, MemoryDocumentOptions, MemoryImageOptions, memoryCache };
|
package/dist/cache/memory.mjs
CHANGED
|
@@ -136,7 +136,7 @@ var MemoryImageOps = class {
|
|
|
136
136
|
* プロセス再起動でクリアされるため、ローカル開発・SSG ビルド・テスト用途。
|
|
137
137
|
*
|
|
138
138
|
* @example
|
|
139
|
-
* cache: memoryCache({
|
|
139
|
+
* cache: [memoryCache({ maxItems: 1000 })]
|
|
140
140
|
*/
|
|
141
141
|
function memoryCache(options) {
|
|
142
142
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.mjs","names":[],"sources":["../../src/cache/memory.ts"],"sourcesContent":["import type {\n
|
|
1
|
+
{"version":3,"file":"memory.mjs","names":[],"sources":["../../src/cache/memory.ts"],"sourcesContent":["import type {\n BaseContentItem,\n CacheAdapter,\n CachedItemContent,\n CachedItemList,\n CachedItemMeta,\n DocumentCacheOps,\n ImageCacheOps,\n InvalidateScope,\n StorageBinary,\n} from \"../types/index\";\n\nexport interface MemoryDocumentOptions {\n /** アイテム保持上限。未指定時は上限なし。超過時は LRU で古いものから削除。 */\n maxItems?: number;\n}\n\nexport interface MemoryImageOptions {\n /** エントリ保持上限。未指定時は上限なし。超過時は LRU で古いものから削除。 */\n maxItems?: number;\n /** 合計保持サイズ上限(バイト)。未指定時は上限なし。超過時は LRU で古いものから削除。 */\n maxSizeBytes?: number;\n}\n\nexport interface MemoryCacheOptions\n extends MemoryDocumentOptions,\n MemoryImageOptions {}\n\n/**\n * Map の挿入順を LRU として扱う軽量実装。\n * `touch` で既存キーを末尾に移動、`enforceLimit` で古いキー(先頭)から削除する。\n */\nfunction touch<K, V>(map: Map<K, V>, key: K): void {\n const v = map.get(key);\n if (v === undefined) return;\n map.delete(key);\n map.set(key, v);\n}\n\nconst itemKey = (collection: string, slug: string): string =>\n `${collection}:${slug}`;\n\n/** インメモリのドキュメントオペレーション実装。プロセス再起動でクリアされる。 */\nclass MemoryDocumentOps implements DocumentCacheOps {\n private lists = new Map<string, CachedItemList<BaseContentItem>>();\n private metas = new Map<string, CachedItemMeta<BaseContentItem>>();\n private contents = new Map<string, CachedItemContent>();\n private readonly maxItems: number | undefined;\n\n constructor(options?: MemoryDocumentOptions) {\n this.maxItems = options?.maxItems;\n }\n\n getList<T extends BaseContentItem>(\n collection: string,\n ): Promise<CachedItemList<T> | null> {\n return Promise.resolve(\n (this.lists.get(collection) as CachedItemList<T> | undefined) ?? null,\n );\n }\n\n setList<T extends BaseContentItem>(\n collection: string,\n data: CachedItemList<T>,\n ): Promise<void> {\n this.lists.set(collection, data);\n return Promise.resolve();\n }\n\n getMeta<T extends BaseContentItem>(\n collection: string,\n slug: string,\n ): Promise<CachedItemMeta<T> | null> {\n const key = itemKey(collection, slug);\n const entry = this.metas.get(key) as CachedItemMeta<T> | undefined;\n if (entry) touch(this.metas, key);\n return Promise.resolve(entry ?? null);\n }\n\n setMeta<T extends BaseContentItem>(\n collection: string,\n slug: string,\n data: CachedItemMeta<T>,\n ): Promise<void> {\n const key = itemKey(collection, slug);\n if (this.metas.has(key)) this.metas.delete(key);\n this.metas.set(key, data);\n this.enforceLimit();\n return Promise.resolve();\n }\n\n getContent(\n collection: string,\n slug: string,\n ): Promise<CachedItemContent | null> {\n const key = itemKey(collection, slug);\n const entry = this.contents.get(key);\n if (entry) touch(this.contents, key);\n return Promise.resolve(entry ?? null);\n }\n\n setContent(\n collection: string,\n slug: string,\n data: CachedItemContent,\n ): Promise<void> {\n const key = itemKey(collection, slug);\n if (this.contents.has(key)) this.contents.delete(key);\n this.contents.set(key, data);\n this.enforceLimit();\n return Promise.resolve();\n }\n\n invalidate(scope: InvalidateScope): Promise<void> {\n if (scope === \"all\") {\n this.lists.clear();\n this.metas.clear();\n this.contents.clear();\n return Promise.resolve();\n }\n const kind = scope.kind ?? \"all\";\n const collection = scope.collection;\n if (\"slug\" in scope) {\n const key = itemKey(collection, scope.slug);\n if (kind === \"all\" || kind === \"meta\") this.metas.delete(key);\n if (kind === \"all\" || kind === \"content\") this.contents.delete(key);\n // 単一スラッグ無効化ではリストは触らない(リスト全体の整合は別管理)\n return Promise.resolve();\n }\n // コレクション全体\n if (kind === \"all\" || kind === \"meta\") {\n this.lists.delete(collection);\n const prefix = `${collection}:`;\n for (const key of [...this.metas.keys()]) {\n if (key.startsWith(prefix)) this.metas.delete(key);\n }\n }\n if (kind === \"all\" || kind === \"content\") {\n const prefix = `${collection}:`;\n for (const key of [...this.contents.keys()]) {\n if (key.startsWith(prefix)) this.contents.delete(key);\n }\n }\n return Promise.resolve();\n }\n\n private enforceLimit(): void {\n if (this.maxItems === undefined) return;\n while (this.metas.size > this.maxItems) {\n const firstKey = this.metas.keys().next().value;\n if (firstKey === undefined) break;\n this.metas.delete(firstKey);\n }\n while (this.contents.size > this.maxItems) {\n const firstKey = this.contents.keys().next().value;\n if (firstKey === undefined) break;\n this.contents.delete(firstKey);\n }\n }\n}\n\n/** インメモリの画像オペレーション実装。 */\nclass MemoryImageOps implements ImageCacheOps {\n private store = new Map<string, StorageBinary>();\n private totalBytes = 0;\n private readonly maxItems: number | undefined;\n private readonly maxSizeBytes: number | undefined;\n\n constructor(options?: MemoryImageOptions) {\n this.maxItems = options?.maxItems;\n this.maxSizeBytes = options?.maxSizeBytes;\n }\n\n get(hash: string): Promise<StorageBinary | null> {\n const entry = this.store.get(hash);\n if (entry) touch(this.store, hash);\n return Promise.resolve(entry ?? null);\n }\n\n set(hash: string, data: ArrayBuffer, contentType: string): Promise<void> {\n const existing = this.store.get(hash);\n if (existing) {\n this.totalBytes -= existing.data.byteLength;\n this.store.delete(hash);\n }\n this.store.set(hash, { data, contentType });\n this.totalBytes += data.byteLength;\n this.enforceLimit();\n return Promise.resolve();\n }\n\n private enforceLimit(): void {\n while (\n (this.maxItems !== undefined && this.store.size > this.maxItems) ||\n (this.maxSizeBytes !== undefined && this.totalBytes > this.maxSizeBytes)\n ) {\n const firstKey = this.store.keys().next().value;\n if (firstKey === undefined) break;\n const victim = this.store.get(firstKey);\n if (victim) this.totalBytes -= victim.data.byteLength;\n this.store.delete(firstKey);\n }\n }\n}\n\n/**\n * インメモリのキャッシュアダプタ。document + image 両方を担当する。\n * プロセス再起動でクリアされるため、ローカル開発・SSG ビルド・テスト用途。\n *\n * @example\n * cache: [memoryCache({ maxItems: 1000 })]\n */\nexport function memoryCache(options?: MemoryCacheOptions): CacheAdapter {\n return {\n name: \"memory\",\n handles: [\"document\", \"image\"] as const,\n doc: new MemoryDocumentOps(options),\n img: new MemoryImageOps(options),\n };\n}\n"],"mappings":"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"}
|
|
@@ -86,20 +86,28 @@ interface ImageRef {
|
|
|
86
86
|
* createCMS<Post>({ source: createNotionCollection({ ... }) })
|
|
87
87
|
*/
|
|
88
88
|
interface BaseContentItem {
|
|
89
|
-
/**
|
|
89
|
+
/** ページ ID(変更検知に必須)。 */
|
|
90
90
|
id: string;
|
|
91
91
|
/** URL キー(必須)。 */
|
|
92
92
|
slug: string;
|
|
93
|
-
/**
|
|
93
|
+
/** ページ名(title 型プロパティのテキスト)。 */
|
|
94
94
|
title?: string | null;
|
|
95
|
-
/**
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
lastEditedTime?: string;
|
|
99
|
-
/** コンテンツのステータス。ステータスのない DB では省略可能。Notion の select 型は null を返す場合がある。 */
|
|
95
|
+
/** ページの最終編集日時(Notion の last_edited_time、変更検知に必須)。 */
|
|
96
|
+
lastEditedTime: string;
|
|
97
|
+
/** コンテンツのステータス。ステータスのない DB では省略可能。 */
|
|
100
98
|
status?: string | null;
|
|
101
|
-
/** 公開日時。日付プロパティのない DB では省略可能。
|
|
99
|
+
/** 公開日時。日付プロパティのない DB では省略可能。 */
|
|
102
100
|
publishedAt?: string | null;
|
|
101
|
+
/** ページ作成日時(ISO8601)。 */
|
|
102
|
+
createdAt?: string;
|
|
103
|
+
/** Notion の archived フラグ (手動アーカイブ)。list() から自動的に除外される。 */
|
|
104
|
+
isArchived?: boolean;
|
|
105
|
+
/** Notion の in_trash フラグ (ゴミ箱)。list() から自動的に除外される。 */
|
|
106
|
+
isInTrash?: boolean;
|
|
107
|
+
/** カバー画像の URL。cover が設定されていない場合は null。 */
|
|
108
|
+
coverImageUrl?: string | null;
|
|
109
|
+
/** 絵文字アイコン。icon が絵文字でない場合や未設定の場合は null。 */
|
|
110
|
+
iconEmoji?: string | null;
|
|
103
111
|
}
|
|
104
112
|
/**
|
|
105
113
|
* メタデータのみの軽量キャッシュエントリ。
|
|
@@ -145,4 +153,4 @@ interface CMSSchemaProperties {
|
|
|
145
153
|
}
|
|
146
154
|
//#endregion
|
|
147
155
|
export { CachedItemMeta as a, ContentResult as c, CachedItemList as i, ImageRef as l, CMSSchemaProperties as n, StorageBinary as o, CachedItemContent as r, ContentBlock as s, BaseContentItem as t, InlineNode as u };
|
|
148
|
-
//# sourceMappingURL=content-
|
|
156
|
+
//# sourceMappingURL=content-D7PfY-bV.d.mts.map
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
//#region src/errors.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* ライブラリ組み込みの CMS エラーコード。
|
|
4
|
+
*
|
|
5
|
+
* | コード | 発生条件 |
|
|
6
|
+
* |---|---|
|
|
7
|
+
* | `core/config_invalid` | 設定不備(token 未設定など) |
|
|
8
|
+
* | `core/schema_invalid` | schema/mapping の型不整合 |
|
|
9
|
+
* | `core/notion_orm_missing` | `@notion-headless-cms/notion-orm` の動的ロード失敗 |
|
|
10
|
+
* | `core/sort_unsupported_type` | ソートキーの値型が string / number でない |
|
|
11
|
+
* | `webhook/signature_invalid` | Webhook 署名検証失敗 |
|
|
12
|
+
* | `webhook/payload_invalid` | Webhook ペイロード形式不正 |
|
|
13
|
+
* | `webhook/unknown_collection` | Webhook の対象コレクションが未知 |
|
|
14
|
+
* | `webhook/not_implemented` | DataSource が parseWebhook を実装していない |
|
|
15
|
+
* | `source/fetch_items_failed` | `DataSource.list()` 失敗 |
|
|
16
|
+
* | `source/fetch_item_failed` | `DataSource.findByProp()` 失敗 |
|
|
17
|
+
* | `source/load_markdown_failed` | `DataSource.loadMarkdown()` 失敗 |
|
|
18
|
+
* | `source/load_blocks_failed` | `DataSource.loadBlocks()` 失敗 |
|
|
19
|
+
* | `cache/io_failed` | document / image キャッシュの I/O 失敗 |
|
|
20
|
+
* | `cache/image_fetch_failed` | Notion 画像の HTTP 取得失敗 |
|
|
21
|
+
* | `cache/image_invalid_content_type` | 画像レスポンスの Content-Type が不正 |
|
|
22
|
+
* | `renderer/failed` | Markdown → HTML 変換失敗 |
|
|
23
|
+
* | `swr/item_check_failed` | SWR バックグラウンドのアイテム差分チェック失敗 |
|
|
24
|
+
* | `swr/list_check_failed` | SWR バックグラウンドのリスト差分チェック失敗 |
|
|
25
|
+
* | `swr/content_rebuild_failed` | SWR バックグラウンドの本文再生成失敗 |
|
|
26
|
+
* | `cli/config_invalid` | `nhc.config.ts` の内容不整合 |
|
|
27
|
+
* | `cli/config_load_failed` | 設定ファイルの読み込み / 評価失敗 |
|
|
28
|
+
* | `cli/schema_invalid` | CLI が受け取ったスキーマ / マッピング不整合 |
|
|
29
|
+
* | `cli/generate_failed` | `nhc generate` の処理失敗 |
|
|
30
|
+
* | `cli/init_failed` | `nhc init` の処理失敗 |
|
|
31
|
+
* | `cli/notion_api_failed` | CLI が Notion API を呼び出す際の失敗 |
|
|
32
|
+
* | `cli/env_file_not_found` | `--env-file` で指定したファイルが存在しない |
|
|
33
|
+
*
|
|
34
|
+
* サードパーティアダプタが独自コードを追加したい場合は `CMSErrorCode` を参照。
|
|
35
|
+
*/
|
|
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
|
+
/**
|
|
38
|
+
* CMS エラーコード。
|
|
39
|
+
* `BuiltInCMSErrorCode` のリテラル補完を維持しつつ、
|
|
40
|
+
* サードパーティアダプタが独自コードを定義できるよう `string & {}` で拡張可能にする。
|
|
41
|
+
*/
|
|
42
|
+
type CMSErrorCode = BuiltInCMSErrorCode | (string & {});
|
|
43
|
+
interface CMSErrorContext {
|
|
44
|
+
operation: string;
|
|
45
|
+
slug?: string;
|
|
46
|
+
dataSourceId?: string;
|
|
47
|
+
pageId?: string;
|
|
48
|
+
[key: string]: string | number | boolean | null | undefined;
|
|
49
|
+
}
|
|
50
|
+
declare class CMSError extends Error {
|
|
51
|
+
readonly code: CMSErrorCode;
|
|
52
|
+
readonly cause?: unknown;
|
|
53
|
+
readonly context: CMSErrorContext;
|
|
54
|
+
constructor(params: {
|
|
55
|
+
code: CMSErrorCode;
|
|
56
|
+
message: string;
|
|
57
|
+
cause?: unknown;
|
|
58
|
+
context: CMSErrorContext;
|
|
59
|
+
});
|
|
60
|
+
/** エラーコードが指定した値と一致するか判定する。 */
|
|
61
|
+
is(code: CMSErrorCode): boolean;
|
|
62
|
+
/** エラーコードが指定した名前空間に属するか判定する(例: `"source/"`)。 */
|
|
63
|
+
inNamespace(namespace: string): boolean;
|
|
64
|
+
}
|
|
65
|
+
declare function isCMSError(error: unknown): error is CMSError;
|
|
66
|
+
/** エラーコードが特定の名前空間に属するかを判定する(例: "source/")。 */
|
|
67
|
+
declare function isCMSErrorInNamespace(error: unknown, namespace: string): error is CMSError;
|
|
68
|
+
type CMSErrorHandler<R> = (err: CMSError) => R;
|
|
69
|
+
/**
|
|
70
|
+
* `CMSError` を switch 式のように分岐して処理するユーティリティ。
|
|
71
|
+
* `_` キーはフォールバック(CMSError 以外 or 未マッチ時)に使われる。
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* matchCMSError(err, {
|
|
75
|
+
* "source/fetch_items_failed": (e) => handleFetchError(e),
|
|
76
|
+
* _: (e) => { throw e; },
|
|
77
|
+
* });
|
|
78
|
+
*/
|
|
79
|
+
declare function matchCMSError<R>(error: unknown, handlers: Partial<Record<CMSErrorCode, CMSErrorHandler<R>>> & {
|
|
80
|
+
_?: (err: unknown) => R;
|
|
81
|
+
}): R | undefined;
|
|
82
|
+
//#endregion
|
|
83
|
+
export { isCMSError as a, CMSErrorContext as i, CMSError as n, isCMSErrorInNamespace as o, CMSErrorCode as r, matchCMSError as s, BuiltInCMSErrorCode as t };
|
|
84
|
+
//# sourceMappingURL=errors-CC_x98vG.d.mts.map
|
package/dist/errors.d.mts
CHANGED
|
@@ -1,56 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
* ライブラリ組み込みの CMS エラーコード。
|
|
4
|
-
*
|
|
5
|
-
* | コード | 発生条件 |
|
|
6
|
-
* |---|---|
|
|
7
|
-
* | `core/config_invalid` | 設定不備(token 未設定など) |
|
|
8
|
-
* | `core/schema_invalid` | schema/mapping の型不整合 |
|
|
9
|
-
* | `core/notion_orm_missing` | `@notion-headless-cms/notion-orm` の動的ロード失敗 |
|
|
10
|
-
* | `source/fetch_items_failed` | `DataSource.list()` 失敗 |
|
|
11
|
-
* | `source/fetch_item_failed` | `DataSource.findByProp()` 失敗 |
|
|
12
|
-
* | `source/load_markdown_failed` | `DataSource.loadMarkdown()` 失敗 |
|
|
13
|
-
* | `cache/io_failed` | document / image キャッシュの I/O 失敗 |
|
|
14
|
-
* | `cache/image_fetch_failed` | Notion 画像の HTTP 取得失敗 |
|
|
15
|
-
* | `renderer/failed` | Markdown → HTML 変換失敗 |
|
|
16
|
-
* | `cli/config_invalid` | `nhc.config.ts` の内容不整合 |
|
|
17
|
-
* | `cli/config_load_failed` | 設定ファイルの読み込み / 評価失敗 |
|
|
18
|
-
* | `cli/schema_invalid` | CLI が受け取ったスキーマ / マッピング不整合 |
|
|
19
|
-
* | `cli/generate_failed` | `nhc generate` の処理失敗 |
|
|
20
|
-
* | `cli/init_failed` | `nhc init` の処理失敗 |
|
|
21
|
-
* | `cli/notion_api_failed` | CLI が Notion API を呼び出す際の失敗 |
|
|
22
|
-
* | `cli/env_file_not_found` | `--env-file` で指定したファイルが存在しない |
|
|
23
|
-
*
|
|
24
|
-
* サードパーティアダプタが独自コードを追加したい場合は `CMSErrorCode` を参照。
|
|
25
|
-
*/
|
|
26
|
-
type BuiltInCMSErrorCode = "core/config_invalid" | "core/schema_invalid" | "core/notion_orm_missing" | "source/fetch_items_failed" | "source/fetch_item_failed" | "source/load_markdown_failed" | "cache/io_failed" | "cache/image_fetch_failed" | "renderer/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";
|
|
27
|
-
/**
|
|
28
|
-
* CMS エラーコード。
|
|
29
|
-
* `BuiltInCMSErrorCode` のリテラル補完を維持しつつ、
|
|
30
|
-
* サードパーティアダプタが独自コードを定義できるよう `string & {}` で拡張可能にする。
|
|
31
|
-
*/
|
|
32
|
-
type CMSErrorCode = BuiltInCMSErrorCode | (string & {});
|
|
33
|
-
interface CMSErrorContext {
|
|
34
|
-
operation: string;
|
|
35
|
-
slug?: string;
|
|
36
|
-
dataSourceId?: string;
|
|
37
|
-
pageId?: string;
|
|
38
|
-
[key: string]: string | number | boolean | null | undefined;
|
|
39
|
-
}
|
|
40
|
-
declare class CMSError extends Error {
|
|
41
|
-
readonly code: CMSErrorCode;
|
|
42
|
-
readonly cause?: unknown;
|
|
43
|
-
readonly context: CMSErrorContext;
|
|
44
|
-
constructor(params: {
|
|
45
|
-
code: CMSErrorCode;
|
|
46
|
-
message: string;
|
|
47
|
-
cause?: unknown;
|
|
48
|
-
context: CMSErrorContext;
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
declare function isCMSError(error: unknown): error is CMSError;
|
|
52
|
-
/** エラーコードが特定の名前空間に属するかを判定する(例: "source/")。 */
|
|
53
|
-
declare function isCMSErrorInNamespace(error: unknown, namespace: string): error is CMSError;
|
|
54
|
-
//#endregion
|
|
55
|
-
export { BuiltInCMSErrorCode, CMSError, CMSErrorCode, CMSErrorContext, isCMSError, isCMSErrorInNamespace };
|
|
56
|
-
//# sourceMappingURL=errors.d.mts.map
|
|
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-CC_x98vG.mjs";
|
|
2
|
+
export { BuiltInCMSErrorCode, CMSError, CMSErrorCode, CMSErrorContext, isCMSError, isCMSErrorInNamespace, matchCMSError };
|
package/dist/errors.mjs
CHANGED
|
@@ -10,6 +10,14 @@ var CMSError = class extends Error {
|
|
|
10
10
|
this.cause = params.cause;
|
|
11
11
|
this.context = params.context;
|
|
12
12
|
}
|
|
13
|
+
/** エラーコードが指定した値と一致するか判定する。 */
|
|
14
|
+
is(code) {
|
|
15
|
+
return this.code === code;
|
|
16
|
+
}
|
|
17
|
+
/** エラーコードが指定した名前空間に属するか判定する(例: `"source/"`)。 */
|
|
18
|
+
inNamespace(namespace) {
|
|
19
|
+
return this.code.startsWith(namespace);
|
|
20
|
+
}
|
|
13
21
|
};
|
|
14
22
|
function isCMSError(error) {
|
|
15
23
|
return error instanceof CMSError;
|
|
@@ -18,7 +26,21 @@ function isCMSError(error) {
|
|
|
18
26
|
function isCMSErrorInNamespace(error, namespace) {
|
|
19
27
|
return isCMSError(error) && error.code.startsWith(namespace);
|
|
20
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* `CMSError` を switch 式のように分岐して処理するユーティリティ。
|
|
31
|
+
* `_` キーはフォールバック(CMSError 以外 or 未マッチ時)に使われる。
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* matchCMSError(err, {
|
|
35
|
+
* "source/fetch_items_failed": (e) => handleFetchError(e),
|
|
36
|
+
* _: (e) => { throw e; },
|
|
37
|
+
* });
|
|
38
|
+
*/
|
|
39
|
+
function matchCMSError(error, handlers) {
|
|
40
|
+
if (!isCMSError(error)) return handlers._?.(error);
|
|
41
|
+
return (handlers[error.code] ?? handlers._)?.(error);
|
|
42
|
+
}
|
|
21
43
|
//#endregion
|
|
22
|
-
export { CMSError, isCMSError, isCMSErrorInNamespace };
|
|
44
|
+
export { CMSError, isCMSError, isCMSErrorInNamespace, matchCMSError };
|
|
23
45
|
|
|
24
46
|
//# sourceMappingURL=errors.mjs.map
|
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 * | `source/fetch_items_failed` | `DataSource.list()` 失敗 |\n * | `source/fetch_item_failed` | `DataSource.findByProp()` 失敗 |\n * | `source/load_markdown_failed` | `DataSource.loadMarkdown()` 失敗 |\n * | `cache/io_failed` | document / image キャッシュの I/O 失敗 |\n * | `cache/image_fetch_failed` | Notion 画像の HTTP 取得失敗 |\n * | `renderer/failed` | Markdown → HTML 変換失敗 |\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
|
|
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 constructor(params: {\n code: CMSErrorCode;\n message: string;\n cause?: unknown;\n context: CMSErrorContext;\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 }\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\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":";AA6EA,IAAa,WAAb,cAA8B,MAAM;CAClC;CACA;CACA;CAEA,YAAY,QAKT;AACD,QAAM,OAAO,SAAS,EAAE,OAAO,OAAO,OAAO,CAAC;AAC9C,OAAK,OAAO;AACZ,OAAK,OAAO,OAAO;AACnB,OAAK,QAAQ,OAAO;AACpB,OAAK,UAAU,OAAO;;;CAIxB,GAAG,MAA6B;AAC9B,SAAO,KAAK,SAAS;;;CAIvB,YAAY,WAA4B;AACtC,SAAO,KAAK,KAAK,WAAW,UAAU;;;AAI1C,SAAgB,WAAW,OAAmC;AAC5D,QAAO,iBAAiB;;;AAI1B,SAAgB,sBACd,OACA,WACmB;AACnB,QAAO,WAAW,MAAM,IAAI,MAAM,KAAK,WAAW,UAAU;;;;;;;;;;;;AAe9D,SAAgB,cACd,OACA,UAGe;AACf,KAAI,CAAC,WAAW,MAAM,CACpB,QAAO,SAAS,IAAI,MAAM;AAK5B,SAFE,SAAS,MAAM,SACd,SAAS,KACK,MAAM"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { a as CachedItemMeta, i as CachedItemList, r as CachedItemContent, t as BaseContentItem } from "./content-
|
|
1
|
+
import { a as CachedItemMeta, i as CachedItemList, r as CachedItemContent, t as BaseContentItem } from "./content-D7PfY-bV.mjs";
|
|
2
|
+
import { n as CMSError } from "./errors-CC_x98vG.mjs";
|
|
2
3
|
|
|
3
4
|
//#region src/types/hooks.d.ts
|
|
4
5
|
type MaybePromise<T> = T | Promise<T>;
|
|
@@ -24,6 +25,15 @@ interface CMSHooks<T extends BaseContentItem = BaseContentItem> {
|
|
|
24
25
|
onError?(error: Error): void;
|
|
25
26
|
onRenderStart?(slug: string): void;
|
|
26
27
|
onRenderEnd?(slug: string, durationMs: number): void;
|
|
28
|
+
/**
|
|
29
|
+
* SWR バックグラウンド処理(差分チェック / 本文再生成)の失敗ハンドラ。
|
|
30
|
+
* これらは UI に伝搬させずに握り続ける必要があるため、エラーを補足するには
|
|
31
|
+
* この hook を実装する。実装しない場合、エラーは logger.warn のみで消える。
|
|
32
|
+
*/
|
|
33
|
+
onSwrError?(error: CMSError, ctx: {
|
|
34
|
+
phase: "item-meta" | "item-content" | "list";
|
|
35
|
+
slug?: string;
|
|
36
|
+
}): void;
|
|
27
37
|
}
|
|
28
38
|
//#endregion
|
|
29
39
|
//#region src/types/logger.d.ts
|
|
@@ -75,4 +85,4 @@ declare function mergeLoggers(plugins: Array<{
|
|
|
75
85
|
}>, directLogger?: Logger): Logger | undefined;
|
|
76
86
|
//#endregion
|
|
77
87
|
export { Logger as a, definePlugin as i, mergeLoggers as n, CMSHooks as o, CMSPlugin as r, MaybePromise as s, mergeHooks as t };
|
|
78
|
-
//# sourceMappingURL=hooks-
|
|
88
|
+
//# sourceMappingURL=hooks-C4HRqHLo.d.mts.map
|
package/dist/hooks.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as mergeLoggers, t as mergeHooks } from "./hooks-
|
|
1
|
+
import { n as mergeLoggers, t as mergeHooks } from "./hooks-C4HRqHLo.mjs";
|
|
2
2
|
export { mergeHooks, mergeLoggers };
|
package/dist/hooks.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.mjs","names":[],"sources":["../src/hooks.ts"],"sourcesContent":["import type { BaseContentItem } from \"./types/content\";\nimport type { CMSHooks, MaybePromise } from \"./types/hooks\";\nimport type { Logger } from \"./types/logger\";\nimport type { CMSPlugin } from \"./types/plugin\";\n\n/**\n * プラグイン配列とダイレクトフックを合成して単一の CMSHooks を返す。\n * beforeCacheMeta / beforeCacheContent / afterRender はパイプライン(前の出力が次の入力)。\n * オブザーバー系は全員に同じ値を渡し、例外は logger に流して握りつぶす。\n */\nexport function mergeHooks<T extends BaseContentItem>(\n
|
|
1
|
+
{"version":3,"file":"hooks.mjs","names":[],"sources":["../src/hooks.ts"],"sourcesContent":["import type { BaseContentItem } from \"./types/content\";\nimport type { CMSHooks, MaybePromise } from \"./types/hooks\";\nimport type { Logger } from \"./types/logger\";\nimport type { CMSPlugin } from \"./types/plugin\";\n\n/**\n * プラグイン配列とダイレクトフックを合成して単一の CMSHooks を返す。\n * beforeCacheMeta / beforeCacheContent / afterRender はパイプライン(前の出力が次の入力)。\n * オブザーバー系は全員に同じ値を渡し、例外は logger に流して握りつぶす。\n */\nexport function mergeHooks<T extends BaseContentItem>(\n plugins: CMSPlugin<T>[],\n directHooks?: CMSHooks<T>,\n logger?: Logger,\n): CMSHooks<T> {\n const allHooks: CMSHooks<T>[] = [\n ...plugins.map((p) => p.hooks ?? {}),\n ...(directHooks ? [directHooks] : []),\n ];\n\n if (allHooks.length === 0) return {};\n\n return {\n beforeCacheMeta: buildMetaPipeline(allHooks),\n beforeCacheContent: buildContentPipeline(allHooks),\n afterRender: buildRenderPipeline(allHooks),\n onCacheHit: buildObserver(allHooks, \"onCacheHit\", logger),\n onCacheMiss: buildObserver(allHooks, \"onCacheMiss\", logger),\n onCacheRevalidated: buildObserver(allHooks, \"onCacheRevalidated\", logger),\n onContentRevalidated: buildObserver(\n allHooks,\n \"onContentRevalidated\",\n logger,\n ),\n onListCacheHit: buildObserver(allHooks, \"onListCacheHit\", logger),\n onListCacheMiss: buildObserver(allHooks, \"onListCacheMiss\", logger),\n onListCacheRevalidated: buildObserver(\n allHooks,\n \"onListCacheRevalidated\",\n logger,\n ),\n onError: buildObserver(allHooks, \"onError\", logger),\n onRenderStart: buildObserver(allHooks, \"onRenderStart\", logger),\n onRenderEnd: buildObserver(allHooks, \"onRenderEnd\", logger),\n };\n}\n\nfunction buildMetaPipeline<T extends BaseContentItem>(\n hooks: CMSHooks<T>[],\n): CMSHooks<T>[\"beforeCacheMeta\"] {\n const fns = hooks\n .map((h) => h.beforeCacheMeta)\n .filter(Boolean) as NonNullable<CMSHooks<T>[\"beforeCacheMeta\"]>[];\n if (fns.length === 0) return undefined;\n return async (meta) => {\n let current = meta;\n for (const fn of fns) {\n current = await (fn(current) as MaybePromise<typeof meta>);\n }\n return current;\n };\n}\n\nfunction buildContentPipeline<T extends BaseContentItem>(\n hooks: CMSHooks<T>[],\n): CMSHooks<T>[\"beforeCacheContent\"] {\n const fns = hooks\n .map((h) => h.beforeCacheContent)\n .filter(Boolean) as NonNullable<CMSHooks<T>[\"beforeCacheContent\"]>[];\n if (fns.length === 0) return undefined;\n return async (content, item) => {\n let current = content;\n for (const fn of fns) {\n current = await (fn(current, item) as MaybePromise<typeof content>);\n }\n return current;\n };\n}\n\nfunction buildRenderPipeline<T extends BaseContentItem>(\n hooks: CMSHooks<T>[],\n): CMSHooks<T>[\"afterRender\"] {\n const fns = hooks.map((h) => h.afterRender).filter(Boolean) as NonNullable<\n CMSHooks<T>[\"afterRender\"]\n >[];\n if (fns.length === 0) return undefined;\n return async (html, item) => {\n let current = html;\n for (const fn of fns) {\n current = await (fn(current, item) as MaybePromise<string>);\n }\n return current;\n };\n}\n\nfunction buildObserver<T extends BaseContentItem, K extends keyof CMSHooks<T>>(\n hooks: CMSHooks<T>[],\n key: K,\n logger?: Logger,\n): CMSHooks<T>[K] {\n const fns = hooks.map((h) => h[key]).filter(Boolean);\n if (fns.length === 0) return undefined;\n return ((...args: unknown[]) => {\n for (const fn of fns) {\n try {\n (fn as (...a: unknown[]) => void)(...args);\n } catch (err) {\n logger?.error?.(\"観測フックで例外が発生\", {\n hook: String(key),\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n }) as CMSHooks<T>[K];\n}\n\n/** プラグイン配列とダイレクトロガーを合成して単一の Logger を返す。 */\nexport function mergeLoggers(\n plugins: Array<{ logger?: Partial<Logger> }>,\n directLogger?: Logger,\n): Logger | undefined {\n const loggers: Partial<Logger>[] = [\n ...plugins.map((p) => p.logger ?? {}),\n ...(directLogger ? [directLogger] : []),\n ];\n if (loggers.length === 0) return undefined;\n\n const merged: Logger = {};\n for (const level of [\"debug\", \"info\", \"warn\", \"error\"] as const) {\n const fns = loggers.map((l) => l[level]).filter(Boolean) as NonNullable<\n Logger[typeof level]\n >[];\n if (fns.length > 0) {\n merged[level] = (message, context) => {\n for (const fn of fns) fn(message, context);\n };\n }\n }\n return merged;\n}\n"],"mappings":";;;;;;AAUA,SAAgB,WACd,SACA,aACA,QACa;CACb,MAAM,WAA0B,CAC9B,GAAG,QAAQ,KAAK,MAAM,EAAE,SAAS,EAAE,CAAC,EACpC,GAAI,cAAc,CAAC,YAAY,GAAG,EAAE,CACrC;AAED,KAAI,SAAS,WAAW,EAAG,QAAO,EAAE;AAEpC,QAAO;EACL,iBAAiB,kBAAkB,SAAS;EAC5C,oBAAoB,qBAAqB,SAAS;EAClD,aAAa,oBAAoB,SAAS;EAC1C,YAAY,cAAc,UAAU,cAAc,OAAO;EACzD,aAAa,cAAc,UAAU,eAAe,OAAO;EAC3D,oBAAoB,cAAc,UAAU,sBAAsB,OAAO;EACzE,sBAAsB,cACpB,UACA,wBACA,OACD;EACD,gBAAgB,cAAc,UAAU,kBAAkB,OAAO;EACjE,iBAAiB,cAAc,UAAU,mBAAmB,OAAO;EACnE,wBAAwB,cACtB,UACA,0BACA,OACD;EACD,SAAS,cAAc,UAAU,WAAW,OAAO;EACnD,eAAe,cAAc,UAAU,iBAAiB,OAAO;EAC/D,aAAa,cAAc,UAAU,eAAe,OAAO;EAC5D;;AAGH,SAAS,kBACP,OACgC;CAChC,MAAM,MAAM,MACT,KAAK,MAAM,EAAE,gBAAgB,CAC7B,OAAO,QAAQ;AAClB,KAAI,IAAI,WAAW,EAAG,QAAO,KAAA;AAC7B,QAAO,OAAO,SAAS;EACrB,IAAI,UAAU;AACd,OAAK,MAAM,MAAM,IACf,WAAU,MAAO,GAAG,QAAQ;AAE9B,SAAO;;;AAIX,SAAS,qBACP,OACmC;CACnC,MAAM,MAAM,MACT,KAAK,MAAM,EAAE,mBAAmB,CAChC,OAAO,QAAQ;AAClB,KAAI,IAAI,WAAW,EAAG,QAAO,KAAA;AAC7B,QAAO,OAAO,SAAS,SAAS;EAC9B,IAAI,UAAU;AACd,OAAK,MAAM,MAAM,IACf,WAAU,MAAO,GAAG,SAAS,KAAK;AAEpC,SAAO;;;AAIX,SAAS,oBACP,OAC4B;CAC5B,MAAM,MAAM,MAAM,KAAK,MAAM,EAAE,YAAY,CAAC,OAAO,QAAQ;AAG3D,KAAI,IAAI,WAAW,EAAG,QAAO,KAAA;AAC7B,QAAO,OAAO,MAAM,SAAS;EAC3B,IAAI,UAAU;AACd,OAAK,MAAM,MAAM,IACf,WAAU,MAAO,GAAG,SAAS,KAAK;AAEpC,SAAO;;;AAIX,SAAS,cACP,OACA,KACA,QACgB;CAChB,MAAM,MAAM,MAAM,KAAK,MAAM,EAAE,KAAK,CAAC,OAAO,QAAQ;AACpD,KAAI,IAAI,WAAW,EAAG,QAAO,KAAA;AAC7B,UAAS,GAAG,SAAoB;AAC9B,OAAK,MAAM,MAAM,IACf,KAAI;AACD,MAAiC,GAAG,KAAK;WACnC,KAAK;AACZ,WAAQ,QAAQ,eAAe;IAC7B,MAAM,OAAO,IAAI;IACjB,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;IACxD,CAAC;;;;;AAOV,SAAgB,aACd,SACA,cACoB;CACpB,MAAM,UAA6B,CACjC,GAAG,QAAQ,KAAK,MAAM,EAAE,UAAU,EAAE,CAAC,EACrC,GAAI,eAAe,CAAC,aAAa,GAAG,EAAE,CACvC;AACD,KAAI,QAAQ,WAAW,EAAG,QAAO,KAAA;CAEjC,MAAM,SAAiB,EAAE;AACzB,MAAK,MAAM,SAAS;EAAC;EAAS;EAAQ;EAAQ;EAAQ,EAAW;EAC/D,MAAM,MAAM,QAAQ,KAAK,MAAM,EAAE,OAAO,CAAC,OAAO,QAAQ;AAGxD,MAAI,IAAI,SAAS,EACf,QAAO,UAAU,SAAS,YAAY;AACpC,QAAK,MAAM,MAAM,IAAK,IAAG,SAAS,QAAQ;;;AAIhD,QAAO"}
|