@notion-headless-cms/core 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +145 -47
- package/dist/cache/memory.d.ts +54 -0
- package/dist/cache/memory.js +15 -0
- package/dist/cache/memory.js.map +1 -0
- package/dist/cache/noop.d.ts +9 -0
- package/dist/cache/noop.js +9 -0
- package/dist/cache/noop.js.map +1 -0
- package/dist/cache-DvbyemBK.d.ts +33 -0
- package/dist/chunk-4KGKWKKI.js +80 -0
- package/dist/chunk-4KGKWKKI.js.map +1 -0
- package/dist/chunk-6DG63XUF.js +42 -0
- package/dist/chunk-6DG63XUF.js.map +1 -0
- package/dist/chunk-6LHROEPI.js +104 -0
- package/dist/chunk-6LHROEPI.js.map +1 -0
- package/dist/chunk-V6ML4QE5.js +26 -0
- package/dist/chunk-V6ML4QE5.js.map +1 -0
- package/dist/content-Biqf0l_o.d.ts +51 -0
- package/dist/errors.d.ts +30 -0
- package/dist/errors.js +11 -0
- package/dist/errors.js.map +1 -0
- package/dist/hooks-B83RUclt.d.ts +41 -0
- package/dist/hooks.d.ts +2 -0
- package/dist/hooks.js +9 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +171 -185
- package/dist/index.js +373 -276
- package/dist/index.js.map +1 -0
- package/package.json +29 -11
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var CMSError = class extends Error {
|
|
3
|
+
code;
|
|
4
|
+
cause;
|
|
5
|
+
context;
|
|
6
|
+
constructor(params) {
|
|
7
|
+
super(params.message, { cause: params.cause });
|
|
8
|
+
this.name = "CMSError";
|
|
9
|
+
this.code = params.code;
|
|
10
|
+
this.cause = params.cause;
|
|
11
|
+
this.context = params.context;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
function isCMSError(error) {
|
|
15
|
+
return error instanceof CMSError;
|
|
16
|
+
}
|
|
17
|
+
function isCMSErrorInNamespace(error, namespace) {
|
|
18
|
+
return isCMSError(error) && error.code.startsWith(namespace);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export {
|
|
22
|
+
CMSError,
|
|
23
|
+
isCMSError,
|
|
24
|
+
isCMSErrorInNamespace
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=chunk-V6ML4QE5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts"],"sourcesContent":["type BuiltInCMSErrorCode =\n\t| \"core/config_invalid\"\n\t| \"core/schema_invalid\"\n\t| \"source/fetch_items_failed\"\n\t| \"source/fetch_item_failed\"\n\t| \"source/load_markdown_failed\"\n\t| \"cache/io_failed\"\n\t| \"cache/image_fetch_failed\"\n\t| \"renderer/failed\";\n\n/**\n * CMS エラーコード。\n * `BuiltInCMSErrorCode` のリテラル補完を維持しつつ、\n * サードパーティアダプタが独自コードを定義できるよう `string & {}` で拡張可能にする。\n */\nexport type CMSErrorCode = BuiltInCMSErrorCode | (string & {});\n\nexport interface CMSErrorContext {\n\toperation: string;\n\tslug?: string;\n\tdataSourceId?: string;\n\tpageId?: string;\n\t[key: string]: string | number | boolean | null | undefined;\n}\n\nexport class CMSError extends Error {\n\treadonly code: CMSErrorCode;\n\toverride readonly cause?: unknown;\n\treadonly context: CMSErrorContext;\n\n\tconstructor(params: {\n\t\tcode: CMSErrorCode;\n\t\tmessage: string;\n\t\tcause?: unknown;\n\t\tcontext: CMSErrorContext;\n\t}) {\n\t\tsuper(params.message, { cause: params.cause });\n\t\tthis.name = \"CMSError\";\n\t\tthis.code = params.code;\n\t\tthis.cause = params.cause;\n\t\tthis.context = params.context;\n\t}\n}\n\nexport function isCMSError(error: unknown): error is CMSError {\n\treturn error instanceof CMSError;\n}\n\n/** エラーコードが特定の名前空間に属するかを判定する(例: \"source/\")。 */\nexport function isCMSErrorInNamespace(\n\terror: unknown,\n\tnamespace: string,\n): error is CMSError {\n\treturn isCMSError(error) && error.code.startsWith(namespace);\n}\n"],"mappings":";AAyBO,IAAM,WAAN,cAAuB,MAAM;AAAA,EAC1B;AAAA,EACS;AAAA,EACT;AAAA,EAET,YAAY,QAKT;AACF,UAAM,OAAO,SAAS,EAAE,OAAO,OAAO,MAAM,CAAC;AAC7C,SAAK,OAAO;AACZ,SAAK,OAAO,OAAO;AACnB,SAAK,QAAQ,OAAO;AACpB,SAAK,UAAU,OAAO;AAAA,EACvB;AACD;AAEO,SAAS,WAAW,OAAmC;AAC7D,SAAO,iBAAiB;AACzB;AAGO,SAAS,sBACf,OACA,WACoB;AACpB,SAAO,WAAW,KAAK,KAAK,MAAM,KAAK,WAAW,SAAS;AAC5D;","names":[]}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ライブラリが動作するために必須なフィールド。
|
|
3
|
+
* 利用者はこのインターフェースを拡張して独自のコンテンツ型を定義する。
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* interface Post extends BaseContentItem {
|
|
7
|
+
* title: string;
|
|
8
|
+
* author: string;
|
|
9
|
+
* }
|
|
10
|
+
* createCMS<Post>({ source: notionAdapter({ ... }) })
|
|
11
|
+
*/
|
|
12
|
+
interface BaseContentItem {
|
|
13
|
+
/** Notion ページ ID(変更検知に必須)。 */
|
|
14
|
+
id: string;
|
|
15
|
+
/** URL キー(必須)。 */
|
|
16
|
+
slug: string;
|
|
17
|
+
/** 最終更新タイムスタンプ(変更検知に必須)。 */
|
|
18
|
+
updatedAt: string;
|
|
19
|
+
/** コンテンツのステータス。ステータスのない DB では省略可能。 */
|
|
20
|
+
status?: string;
|
|
21
|
+
/** 公開日時。日付プロパティのない DB では省略可能。 */
|
|
22
|
+
publishedAt?: string;
|
|
23
|
+
}
|
|
24
|
+
/** ストレージにキャッシュされたレンダリング済みコンテンツ。 */
|
|
25
|
+
interface CachedItem<T extends BaseContentItem = BaseContentItem> {
|
|
26
|
+
html: string;
|
|
27
|
+
item: T;
|
|
28
|
+
notionUpdatedAt: string;
|
|
29
|
+
cachedAt: number;
|
|
30
|
+
}
|
|
31
|
+
/** ストレージにキャッシュされたコンテンツ一覧。 */
|
|
32
|
+
interface CachedItemList<T extends BaseContentItem = BaseContentItem> {
|
|
33
|
+
items: T[];
|
|
34
|
+
cachedAt: number;
|
|
35
|
+
}
|
|
36
|
+
/** ストレージから取得したバイナリオブジェクト。 */
|
|
37
|
+
interface StorageBinary {
|
|
38
|
+
data: ArrayBuffer;
|
|
39
|
+
contentType?: string;
|
|
40
|
+
}
|
|
41
|
+
/** Notionのプロパティ名マッピング(すべてオプション)。 */
|
|
42
|
+
interface CMSSchemaProperties {
|
|
43
|
+
/** Notionのスラッグプロパティ名。デフォルト: 'Slug' */
|
|
44
|
+
slug?: string;
|
|
45
|
+
/** Notionのステータスプロパティ名。デフォルト: 'Status' */
|
|
46
|
+
status?: string;
|
|
47
|
+
/** Notionの公開日プロパティ名。デフォルト: 'CreatedAt' */
|
|
48
|
+
date?: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export type { BaseContentItem as B, CMSSchemaProperties as C, StorageBinary as S, CachedItem as a, CachedItemList as b };
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
type BuiltInCMSErrorCode = "core/config_invalid" | "core/schema_invalid" | "source/fetch_items_failed" | "source/fetch_item_failed" | "source/load_markdown_failed" | "cache/io_failed" | "cache/image_fetch_failed" | "renderer/failed";
|
|
2
|
+
/**
|
|
3
|
+
* CMS エラーコード。
|
|
4
|
+
* `BuiltInCMSErrorCode` のリテラル補完を維持しつつ、
|
|
5
|
+
* サードパーティアダプタが独自コードを定義できるよう `string & {}` で拡張可能にする。
|
|
6
|
+
*/
|
|
7
|
+
type CMSErrorCode = BuiltInCMSErrorCode | (string & {});
|
|
8
|
+
interface CMSErrorContext {
|
|
9
|
+
operation: string;
|
|
10
|
+
slug?: string;
|
|
11
|
+
dataSourceId?: string;
|
|
12
|
+
pageId?: string;
|
|
13
|
+
[key: string]: string | number | boolean | null | undefined;
|
|
14
|
+
}
|
|
15
|
+
declare class CMSError extends Error {
|
|
16
|
+
readonly code: CMSErrorCode;
|
|
17
|
+
readonly cause?: unknown;
|
|
18
|
+
readonly context: CMSErrorContext;
|
|
19
|
+
constructor(params: {
|
|
20
|
+
code: CMSErrorCode;
|
|
21
|
+
message: string;
|
|
22
|
+
cause?: unknown;
|
|
23
|
+
context: CMSErrorContext;
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
declare function isCMSError(error: unknown): error is CMSError;
|
|
27
|
+
/** エラーコードが特定の名前空間に属するかを判定する(例: "source/")。 */
|
|
28
|
+
declare function isCMSErrorInNamespace(error: unknown, namespace: string): error is CMSError;
|
|
29
|
+
|
|
30
|
+
export { CMSError, type CMSErrorCode, type CMSErrorContext, isCMSError, isCMSErrorInNamespace };
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { B as BaseContentItem, a as CachedItem } from './content-Biqf0l_o.js';
|
|
2
|
+
|
|
3
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
4
|
+
interface CMSHooks<T extends BaseContentItem = BaseContentItem> {
|
|
5
|
+
beforeCache?: (item: CachedItem<T>) => MaybePromise<CachedItem<T>>;
|
|
6
|
+
afterRender?: (html: string, item: T) => MaybePromise<string>;
|
|
7
|
+
onCacheHit?: (slug: string, item: CachedItem<T>) => void;
|
|
8
|
+
onCacheMiss?: (slug: string) => void;
|
|
9
|
+
onListCacheHit?: (items: T[], cachedAt: number) => void;
|
|
10
|
+
onListCacheMiss?: () => void;
|
|
11
|
+
onError?: (error: Error) => void;
|
|
12
|
+
onRenderStart?: (slug: string) => void;
|
|
13
|
+
onRenderEnd?: (slug: string, durationMs: number) => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface Logger {
|
|
17
|
+
debug?: (message: string, context?: Record<string, unknown>) => void;
|
|
18
|
+
info?: (message: string, context?: Record<string, unknown>) => void;
|
|
19
|
+
warn?: (message: string, context?: Record<string, unknown>) => void;
|
|
20
|
+
error?: (message: string, context?: Record<string, unknown>) => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface CMSPlugin<T extends BaseContentItem = BaseContentItem> {
|
|
24
|
+
name: string;
|
|
25
|
+
hooks?: CMSHooks<T>;
|
|
26
|
+
logger?: Partial<Logger>;
|
|
27
|
+
}
|
|
28
|
+
declare function definePlugin<T extends BaseContentItem>(plugin: CMSPlugin<T>): CMSPlugin<T>;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* プラグイン配列とダイレクトフックを合成して単一の CMSHooks を返す。
|
|
32
|
+
* beforeCache / afterRender はパイプライン(前の出力が次の入力)。
|
|
33
|
+
* onCacheHit などオブザーバー系は全員に同じ値を渡し、例外は logger に流して握りつぶす。
|
|
34
|
+
*/
|
|
35
|
+
declare function mergeHooks<T extends BaseContentItem>(plugins: CMSPlugin<T>[], directHooks?: CMSHooks<T>, logger?: Logger): CMSHooks<T>;
|
|
36
|
+
/** プラグイン配列とダイレクトロガーを合成して単一の Logger を返す。 */
|
|
37
|
+
declare function mergeLoggers(plugins: Array<{
|
|
38
|
+
logger?: Partial<Logger>;
|
|
39
|
+
}>, directLogger?: Logger): Logger | undefined;
|
|
40
|
+
|
|
41
|
+
export { type CMSHooks as C, type Logger as L, type MaybePromise as M, type CMSPlugin as a, mergeLoggers as b, definePlugin as d, mergeHooks as m };
|
package/dist/hooks.d.ts
ADDED
package/dist/hooks.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
|
|
1
|
+
export { MemoryDocumentCacheOptions, MemoryImageCacheOptions, memoryCache, memoryDocumentCache, memoryImageCache } from './cache/memory.js';
|
|
2
|
+
export { noopDocumentCache, noopImageCache } from './cache/noop.js';
|
|
3
|
+
import { B as BaseContentItem, C as CMSSchemaProperties, a as CachedItem, S as StorageBinary } from './content-Biqf0l_o.js';
|
|
4
|
+
export { b as CachedItemList } from './content-Biqf0l_o.js';
|
|
5
|
+
import { PluggableList } from '@notion-headless-cms/renderer';
|
|
6
|
+
import { C as CacheConfig } from './cache-DvbyemBK.js';
|
|
7
|
+
export { D as DocumentCacheAdapter, I as ImageCacheAdapter } from './cache-DvbyemBK.js';
|
|
8
|
+
import { C as CMSHooks, a as CMSPlugin, L as Logger } from './hooks-B83RUclt.js';
|
|
9
|
+
export { M as MaybePromise, d as definePlugin, m as mergeHooks, b as mergeLoggers } from './hooks-B83RUclt.js';
|
|
10
|
+
export { CMSError, CMSErrorCode, CMSErrorContext, isCMSError, isCMSErrorInNamespace } from './errors.js';
|
|
5
11
|
|
|
6
12
|
/** 文字列をSHA-256でハッシュ化し、16進数文字列として返す。画像キーの生成に使用。 */
|
|
7
13
|
declare function sha256Hex(input: string): Promise<string>;
|
|
@@ -11,78 +17,26 @@ declare function sha256Hex(input: string): Promise<string>;
|
|
|
11
17
|
*/
|
|
12
18
|
declare function isStale(cachedAt: number, ttlMs?: number): boolean;
|
|
13
19
|
|
|
14
|
-
/**
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
slug: string;
|
|
28
|
-
status: string;
|
|
29
|
-
publishedAt: string;
|
|
30
|
-
updatedAt: string;
|
|
20
|
+
/** ソース側クエリのフィルタ・ソート条件。 */
|
|
21
|
+
interface SourceQueryOptions {
|
|
22
|
+
filter?: {
|
|
23
|
+
statuses?: string[];
|
|
24
|
+
tags?: string[];
|
|
25
|
+
[key: string]: unknown;
|
|
26
|
+
};
|
|
27
|
+
sort?: {
|
|
28
|
+
property: string;
|
|
29
|
+
direction: "asc" | "desc";
|
|
30
|
+
}[];
|
|
31
|
+
pageSize?: number;
|
|
32
|
+
cursor?: string;
|
|
31
33
|
}
|
|
32
|
-
/**
|
|
33
|
-
interface
|
|
34
|
-
html: string;
|
|
35
|
-
item: T;
|
|
36
|
-
notionUpdatedAt: string;
|
|
37
|
-
cachedAt: number;
|
|
38
|
-
}
|
|
39
|
-
/** ストレージにキャッシュされたコンテンツ一覧。 */
|
|
40
|
-
interface CachedItemList<T extends BaseContentItem = BaseContentItem> {
|
|
34
|
+
/** ソース側クエリの結果。 */
|
|
35
|
+
interface SourceQueryResult<T> {
|
|
41
36
|
items: T[];
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
/** ストレージから取得したバイナリオブジェクト。 */
|
|
45
|
-
interface StorageBinary {
|
|
46
|
-
data: ArrayBuffer;
|
|
47
|
-
contentType?: string;
|
|
48
|
-
}
|
|
49
|
-
/** Notionのプロパティ名マッピング(すべてオプション)。 */
|
|
50
|
-
interface CMSSchemaProperties {
|
|
51
|
-
/** Notionのスラッグプロパティ名。デフォルト: 'Slug' */
|
|
52
|
-
slug?: string;
|
|
53
|
-
/** Notionのステータスプロパティ名。デフォルト: 'Status' */
|
|
54
|
-
status?: string;
|
|
55
|
-
/** Notionの公開日プロパティ名。デフォルト: 'CreatedAt' */
|
|
56
|
-
date?: string;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/** ドキュメントキャッシュを抽象化するインターフェース。 */
|
|
60
|
-
interface DocumentCacheAdapter<T extends BaseContentItem = BaseContentItem> {
|
|
61
|
-
readonly name: string;
|
|
62
|
-
getList(): Promise<CachedItemList<T> | null>;
|
|
63
|
-
setList(data: CachedItemList<T>): Promise<void>;
|
|
64
|
-
getItem(slug: string): Promise<CachedItem<T> | null>;
|
|
65
|
-
setItem(slug: string, data: CachedItem<T>): Promise<void>;
|
|
66
|
-
invalidate?(scope: "all" | {
|
|
67
|
-
slug: string;
|
|
68
|
-
} | {
|
|
69
|
-
tag: string;
|
|
70
|
-
}): Promise<void>;
|
|
71
|
-
}
|
|
72
|
-
/** 画像キャッシュを抽象化するインターフェース。 */
|
|
73
|
-
interface ImageCacheAdapter {
|
|
74
|
-
readonly name: string;
|
|
75
|
-
get(hash: string): Promise<StorageBinary | null>;
|
|
76
|
-
set(hash: string, data: ArrayBuffer, contentType: string): Promise<void>;
|
|
77
|
-
}
|
|
78
|
-
/** キャッシュ設定オブジェクト。document / image それぞれ独立したアダプタを差し込める。 */
|
|
79
|
-
interface CacheConfig<T extends BaseContentItem = BaseContentItem> {
|
|
80
|
-
document?: DocumentCacheAdapter<T> | false;
|
|
81
|
-
image?: ImageCacheAdapter | false;
|
|
82
|
-
/** キャッシュの有効期間(ミリ秒)。未設定の場合はTTLなし。 */
|
|
83
|
-
ttlMs?: number;
|
|
37
|
+
hasMore: boolean;
|
|
38
|
+
nextCursor?: string;
|
|
84
39
|
}
|
|
85
|
-
|
|
86
40
|
/**
|
|
87
41
|
* コンテンツソース(Notion など)を抽象化するインターフェース。
|
|
88
42
|
* core は Notion の知識を持たず、DataSourceAdapter 経由でのみデータを取得する。
|
|
@@ -96,21 +50,30 @@ interface DataSourceAdapter<T extends BaseContentItem = BaseContentItem> {
|
|
|
96
50
|
}): Promise<T[]>;
|
|
97
51
|
findBySlug(slug: string): Promise<T | null>;
|
|
98
52
|
loadMarkdown(item: T): Promise<string>;
|
|
53
|
+
/** Notion 側でフィルタ・ソートを行うクエリ(オプション)。 */
|
|
54
|
+
query?(opts: SourceQueryOptions): Promise<SourceQueryResult<T>>;
|
|
99
55
|
}
|
|
100
56
|
|
|
57
|
+
/**
|
|
58
|
+
* render() オプション。core は renderer の実装を知らず、この型だけを扱う。
|
|
59
|
+
* @notion-headless-cms/renderer の renderMarkdown() はこのシグネチャと構造的に互換。
|
|
60
|
+
*/
|
|
61
|
+
interface RenderOptions {
|
|
62
|
+
imageProxyBase?: string;
|
|
63
|
+
cacheImage?: (url: string) => Promise<string>;
|
|
64
|
+
remarkPlugins?: PluggableList;
|
|
65
|
+
rehypePlugins?: PluggableList;
|
|
66
|
+
}
|
|
67
|
+
/** カスタムレンダラー関数の型。デフォルトは @notion-headless-cms/renderer の renderMarkdown。 */
|
|
68
|
+
type RendererFn = (markdown: string, opts?: RenderOptions) => Promise<string>;
|
|
101
69
|
/** スキーマ設定。公開ステータスのフィルタやプロパティ名マッピングを制御する。 */
|
|
102
70
|
interface SchemaConfig<T extends BaseContentItem = BaseContentItem> {
|
|
103
|
-
/**
|
|
104
|
-
* Notionページをコンテンツ型 T にマッピングするカスタム関数。
|
|
105
|
-
* 指定した場合 properties の設定は無視される(slug プロパティ名のみ例外)。
|
|
106
|
-
*/
|
|
107
|
-
mapItem?: (page: PageObjectResponse) => T;
|
|
108
|
-
/** mapItem 未使用時のプロパティ名マッピング。 */
|
|
109
|
-
properties?: CMSSchemaProperties;
|
|
110
71
|
/** list() で返す「公開済み」ステータス値の配列。デフォルト: [] (全件返す) */
|
|
111
72
|
publishedStatuses?: string[];
|
|
112
73
|
/** findBySlug() でアクセス可能なステータス値の配列。デフォルト: [] (全件許可) */
|
|
113
74
|
accessibleStatuses?: string[];
|
|
75
|
+
/** mapItem 未使用時のプロパティ名マッピング。source-notion 経由で渡す場合は不要。 */
|
|
76
|
+
properties?: CMSSchemaProperties;
|
|
114
77
|
}
|
|
115
78
|
/** レンダリング・コンテンツ処理設定。 */
|
|
116
79
|
interface ContentConfig {
|
|
@@ -120,10 +83,17 @@ interface ContentConfig {
|
|
|
120
83
|
remarkPlugins?: PluggableList;
|
|
121
84
|
/** 追加する rehype プラグイン。 */
|
|
122
85
|
rehypePlugins?: PluggableList;
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
86
|
+
}
|
|
87
|
+
/** レートリミット・リトライ設定。 */
|
|
88
|
+
interface RateLimiterConfig {
|
|
89
|
+
/** 同時実行数の上限。デフォルト: 3 */
|
|
90
|
+
maxConcurrent?: number;
|
|
91
|
+
/** リトライ対象の HTTP ステータスコード。デフォルト: [429, 502, 503] */
|
|
92
|
+
retryOn?: number[];
|
|
93
|
+
/** 最大リトライ回数。デフォルト: 4 */
|
|
94
|
+
maxRetries?: number;
|
|
95
|
+
/** リトライ時の基準待機時間(ミリ秒)。デフォルト: 1000 */
|
|
96
|
+
baseDelayMs?: number;
|
|
127
97
|
}
|
|
128
98
|
/**
|
|
129
99
|
* createCMS() に渡すオプション。
|
|
@@ -132,6 +102,8 @@ interface ContentConfig {
|
|
|
132
102
|
interface CreateCMSOptions<T extends BaseContentItem = BaseContentItem> {
|
|
133
103
|
/** データソースアダプタ(Notion など)。 */
|
|
134
104
|
source: DataSourceAdapter<T>;
|
|
105
|
+
/** レンダラー関数。未指定時は @notion-headless-cms/renderer の renderMarkdown を使用。 */
|
|
106
|
+
renderer?: RendererFn;
|
|
135
107
|
/** キャッシュ設定。未設定時はキャッシュなし。 */
|
|
136
108
|
cache?: CacheConfig<T>;
|
|
137
109
|
/** スキーマ・ステータス設定。 */
|
|
@@ -140,75 +112,64 @@ interface CreateCMSOptions<T extends BaseContentItem = BaseContentItem> {
|
|
|
140
112
|
content?: ContentConfig;
|
|
141
113
|
/** Cloudflare Workers の waitUntil に相当する非同期処理の登録関数。 */
|
|
142
114
|
waitUntil?: (p: Promise<unknown>) => void;
|
|
115
|
+
/** ライフサイクルフック。 */
|
|
116
|
+
hooks?: CMSHooks<T>;
|
|
117
|
+
/** プラグイン配列。フックとロガーを組み合わせて提供できる。 */
|
|
118
|
+
plugins?: CMSPlugin<T>[];
|
|
119
|
+
/** ロガー。 */
|
|
120
|
+
logger?: Logger;
|
|
121
|
+
/** レートリミット・リトライ設定。 */
|
|
122
|
+
rateLimiter?: RateLimiterConfig;
|
|
143
123
|
}
|
|
144
124
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
declare
|
|
154
|
-
|
|
155
|
-
/** 何もしないドキュメントキャッシュを返す(シングルトン)。 */
|
|
156
|
-
declare function noopDocumentCache<T extends BaseContentItem = BaseContentItem>(): DocumentCacheAdapter<T>;
|
|
157
|
-
/** 何もしない画像キャッシュを返す(シングルトン)。 */
|
|
158
|
-
declare function noopImageCache(): ImageCacheAdapter;
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Notion をバックエンドとして使う汎用ヘッドレス CMS クラス。
|
|
162
|
-
*
|
|
163
|
-
* @example
|
|
164
|
-
* const cms = createCMS({
|
|
165
|
-
* source: notionAdapter({ token: '...', dataSourceId: '...' }),
|
|
166
|
-
* schema: { publishedStatuses: ['公開'] },
|
|
167
|
-
* });
|
|
168
|
-
* const items = await cms.list();
|
|
169
|
-
*/
|
|
170
|
-
declare class CMS<T extends BaseContentItem = BaseContentItem> {
|
|
125
|
+
interface QueryResult<T> {
|
|
126
|
+
items: T[];
|
|
127
|
+
total: number;
|
|
128
|
+
page: number;
|
|
129
|
+
perPage: number;
|
|
130
|
+
hasNext: boolean;
|
|
131
|
+
hasPrev: boolean;
|
|
132
|
+
}
|
|
133
|
+
declare class QueryBuilder<T extends BaseContentItem> {
|
|
171
134
|
private readonly source;
|
|
172
|
-
private readonly
|
|
173
|
-
private
|
|
174
|
-
private
|
|
175
|
-
private
|
|
176
|
-
private
|
|
177
|
-
private
|
|
178
|
-
private
|
|
179
|
-
private
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
findBySlug(slug: string): Promise<T | null>;
|
|
186
|
-
/** アイテムが publishedStatuses に含まれるステータスかどうかを返す。 */
|
|
187
|
-
isPublished(item: T): boolean;
|
|
188
|
-
/** コンテンツを Markdown → HTML にレンダリングし、CachedItem として返す。 */
|
|
189
|
-
render(item: T): Promise<CachedItem<T>>;
|
|
190
|
-
/** スラッグでコンテンツを取得して Markdown → HTML にレンダリングする。 */
|
|
191
|
-
renderBySlug(slug: string): Promise<CachedItem<T> | null>;
|
|
192
|
-
/** ステータスでフィルタリングした一覧を返す。 */
|
|
193
|
-
listByStatus(status: string | readonly string[]): Promise<T[]>;
|
|
194
|
-
/** 任意の条件でフィルタリングした一覧を返す。 */
|
|
195
|
-
where(predicate: (item: T) => boolean): Promise<T[]>;
|
|
196
|
-
/** ページネーション付き一覧を返す。 */
|
|
135
|
+
private readonly defaultStatuses;
|
|
136
|
+
private _statuses;
|
|
137
|
+
private _tags;
|
|
138
|
+
private _predicate;
|
|
139
|
+
private _sortField;
|
|
140
|
+
private _sortDir;
|
|
141
|
+
private _page;
|
|
142
|
+
private _perPage;
|
|
143
|
+
constructor(source: DataSourceAdapter<T>, defaultStatuses?: string[]);
|
|
144
|
+
status(s: string | string[]): this;
|
|
145
|
+
tag(t: string | string[]): this;
|
|
146
|
+
where(predicate: (item: T) => boolean): this;
|
|
147
|
+
sortBy(field: keyof T & string, dir?: "asc" | "desc"): this;
|
|
197
148
|
paginate(opts: {
|
|
198
149
|
page: number;
|
|
199
150
|
perPage: number;
|
|
200
|
-
}):
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
hasNext: boolean;
|
|
206
|
-
}>;
|
|
207
|
-
/** 指定スラッグの前後コンテンツを返す。 */
|
|
208
|
-
getAdjacent(slug: string): Promise<{
|
|
151
|
+
}): this;
|
|
152
|
+
execute(): Promise<QueryResult<T>>;
|
|
153
|
+
executeOne(): Promise<T | null>;
|
|
154
|
+
/** 前後アイテムを返す。sortBy() で指定したソート順を適用する。 */
|
|
155
|
+
adjacent(slug: string): Promise<{
|
|
209
156
|
prev: T | null;
|
|
210
157
|
next: T | null;
|
|
211
158
|
}>;
|
|
159
|
+
/** 最初の 1 件を返す。`.paginate({ page: 1, perPage: 1 }).executeOne()` の短縮形。 */
|
|
160
|
+
first(): Promise<T | null>;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** キャッシュ系の公開名前空間。SWR 読み取りとキャッシュ管理を統合する。 */
|
|
164
|
+
interface CacheAccessor<T extends BaseContentItem> {
|
|
165
|
+
/** キャッシュ優先でコンテンツ一覧を返す(SWR)。 */
|
|
166
|
+
getList(): Promise<{
|
|
167
|
+
items: T[];
|
|
168
|
+
isStale: boolean;
|
|
169
|
+
cachedAt: number;
|
|
170
|
+
}>;
|
|
171
|
+
/** キャッシュ優先で単一コンテンツを返す(SWR)。HTML 付きの CachedItem を返す。 */
|
|
172
|
+
get(slug: string): Promise<CachedItem<T> | null>;
|
|
212
173
|
/** 全コンテンツを事前レンダリングしてキャッシュに保存する。 */
|
|
213
174
|
prefetchAll(opts?: {
|
|
214
175
|
concurrency?: number;
|
|
@@ -217,32 +178,25 @@ declare class CMS<T extends BaseContentItem = BaseContentItem> {
|
|
|
217
178
|
ok: number;
|
|
218
179
|
failed: number;
|
|
219
180
|
}>;
|
|
220
|
-
/** 静的生成用のスラッグ一覧を返す。 */
|
|
221
|
-
getStaticSlugs(): Promise<string[]>;
|
|
222
181
|
/** 指定スコープのキャッシュを無効化する。 */
|
|
223
182
|
revalidate(scope?: "all" | {
|
|
224
183
|
slug: string;
|
|
225
184
|
}): Promise<void>;
|
|
226
185
|
/** Webhook ペイロードを元にキャッシュを同期する。 */
|
|
227
|
-
|
|
186
|
+
sync(payload?: {
|
|
228
187
|
slug?: string;
|
|
229
188
|
}): Promise<{
|
|
230
189
|
updated: string[];
|
|
231
190
|
}>;
|
|
232
|
-
/**
|
|
233
|
-
|
|
234
|
-
items: T[];
|
|
235
|
-
listVersion: string;
|
|
236
|
-
}>;
|
|
237
|
-
/** キャッシュ優先で単一コンテンツを返す(SWR)。 */
|
|
238
|
-
getItem(slug: string): Promise<CachedItem<T> | null>;
|
|
239
|
-
checkListUpdate(version: string): Promise<{
|
|
191
|
+
/** リスト全体の変更を検知する。version はリスト取得時の buildListVersion の値。 */
|
|
192
|
+
checkList(version: string): Promise<{
|
|
240
193
|
changed: false;
|
|
241
194
|
} | {
|
|
242
195
|
changed: true;
|
|
243
196
|
items: T[];
|
|
244
197
|
}>;
|
|
245
|
-
|
|
198
|
+
/** 単一アイテムの変更を検知し、変更があれば再レンダリングしてキャッシュを更新する。 */
|
|
199
|
+
checkItem(slug: string, lastEdited: string): Promise<{
|
|
246
200
|
changed: false;
|
|
247
201
|
} | {
|
|
248
202
|
changed: true;
|
|
@@ -250,43 +204,75 @@ declare class CMS<T extends BaseContentItem = BaseContentItem> {
|
|
|
250
204
|
item: T;
|
|
251
205
|
notionUpdatedAt: string;
|
|
252
206
|
}>;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Notion をバックエンドとして使う汎用ヘッドレス CMS クラス。
|
|
210
|
+
*
|
|
211
|
+
* @example
|
|
212
|
+
* const cms = createCMS({
|
|
213
|
+
* source: notionAdapter({ token: '...', dataSourceId: '...' }),
|
|
214
|
+
* });
|
|
215
|
+
* const items = await cms.list();
|
|
216
|
+
* const entry = await cms.cache.get('my-post');
|
|
217
|
+
*/
|
|
218
|
+
declare class CMS<T extends BaseContentItem = BaseContentItem> {
|
|
219
|
+
private readonly source;
|
|
220
|
+
private readonly docCache;
|
|
221
|
+
private readonly imgCache;
|
|
222
|
+
private readonly hasImageCache;
|
|
223
|
+
private readonly ttlMs;
|
|
224
|
+
private readonly publishedStatuses;
|
|
225
|
+
private readonly accessibleStatuses;
|
|
226
|
+
private readonly imageProxyBase;
|
|
227
|
+
private readonly contentConfig;
|
|
228
|
+
private readonly rendererFn;
|
|
229
|
+
private readonly waitUntil;
|
|
230
|
+
private readonly hooks;
|
|
231
|
+
private readonly logger;
|
|
232
|
+
private readonly retryConfig;
|
|
233
|
+
private readonly maxConcurrent;
|
|
234
|
+
readonly cache: CacheAccessor<T>;
|
|
235
|
+
constructor(opts: CreateCMSOptions<T>);
|
|
236
|
+
/** 公開済みコンテンツ一覧をソースから直接取得する。 */
|
|
237
|
+
list(): Promise<T[]>;
|
|
238
|
+
/** スラッグでコンテンツをソースから直接取得する。 */
|
|
239
|
+
find(slug: string): Promise<T | null>;
|
|
240
|
+
/** 複数スラッグをまとめてソースから直接取得する。accessibleStatuses フィルタを適用する。 */
|
|
241
|
+
findMany(slugs: string[]): Promise<Map<string, T>>;
|
|
242
|
+
/** アイテムが publishedStatuses に含まれるステータスかどうかを返す。 */
|
|
243
|
+
isPublished(item: T): boolean;
|
|
244
|
+
/** コンテンツを Markdown → HTML にレンダリングし、CachedItem として返す。キャッシュには保存しない。 */
|
|
245
|
+
render(item: T): Promise<CachedItem<T>>;
|
|
246
|
+
/** QueryBuilder を返す。ステータス・タグ・ページネーションなどを連鎖で指定できる。 */
|
|
247
|
+
query(): QueryBuilder<T>;
|
|
248
|
+
/** 静的生成用のスラッグ一覧を返す。 */
|
|
249
|
+
getStaticSlugs(): Promise<string[]>;
|
|
253
250
|
/** ハッシュキーでキャッシュ画像を取得する。 */
|
|
254
251
|
getCachedImage(hash: string): Promise<StorageBinary | null>;
|
|
255
252
|
/** ハッシュキーでキャッシュ画像を Response として返す。 */
|
|
256
253
|
createCachedImageResponse(hash: string): Promise<Response | null>;
|
|
254
|
+
private cachedList;
|
|
255
|
+
private cachedGet;
|
|
256
|
+
private prefetchAll;
|
|
257
|
+
private revalidate;
|
|
258
|
+
private syncFromWebhook;
|
|
259
|
+
private checkListUpdate;
|
|
260
|
+
private checkItemUpdate;
|
|
257
261
|
private buildCachedItem;
|
|
258
262
|
}
|
|
259
263
|
/** 設定済みの CMS インスタンスを生成するファクトリ関数。 */
|
|
260
264
|
declare function createCMS<T extends BaseContentItem = BaseContentItem>(opts: CreateCMSOptions<T>): CMS<T>;
|
|
261
265
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
}
|
|
270
|
-
declare class CMSError extends Error {
|
|
271
|
-
readonly code: CMSErrorCode;
|
|
272
|
-
readonly cause?: unknown;
|
|
273
|
-
readonly context: CMSErrorContext;
|
|
274
|
-
constructor(params: {
|
|
275
|
-
code: CMSErrorCode;
|
|
276
|
-
message: string;
|
|
277
|
-
cause?: unknown;
|
|
278
|
-
context: CMSErrorContext;
|
|
279
|
-
});
|
|
266
|
+
interface RetryConfig {
|
|
267
|
+
retryOn: number[];
|
|
268
|
+
maxRetries: number;
|
|
269
|
+
baseDelayMs: number;
|
|
270
|
+
/** true のとき指数バックオフにランダムジッターを加える(Thundering Herd 対策)。デフォルト: true */
|
|
271
|
+
jitter?: boolean;
|
|
272
|
+
onRetry?: (attempt: number, status: number) => void;
|
|
280
273
|
}
|
|
281
|
-
declare
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
declare function getPlainText(items: RichTextItemResponse[] | undefined): string;
|
|
285
|
-
/**
|
|
286
|
-
* NotionのPageObjectResponseをデフォルトの BaseContentItem に変換する。
|
|
287
|
-
* 独自の拡張型(title などを含む)が必要な場合は、本関数の戻り値に
|
|
288
|
-
* 追加フィールドを足してカスタム mapItem を実装する。
|
|
289
|
-
*/
|
|
290
|
-
declare function mapItem(page: PageObjectResponse, props: Required<CMSSchemaProperties>): BaseContentItem;
|
|
274
|
+
declare const DEFAULT_RETRY_CONFIG: RetryConfig;
|
|
275
|
+
/** 指数バックオフ(オプションでジッター付き)でリトライする。retryOn に含まれる HTTP エラーのみ対象。 */
|
|
276
|
+
declare function withRetry<T>(fn: () => Promise<T>, config: RetryConfig): Promise<T>;
|
|
291
277
|
|
|
292
|
-
export {
|
|
278
|
+
export { BaseContentItem, CMS, CMSHooks, CMSPlugin, CMSSchemaProperties, type CacheAccessor, CacheConfig, CachedItem, type ContentConfig, type CreateCMSOptions, DEFAULT_RETRY_CONFIG, type DataSourceAdapter, Logger, QueryBuilder, type QueryResult, type RateLimiterConfig, type RenderOptions, type RendererFn, type RetryConfig, type SchemaConfig, type SourceQueryOptions, type SourceQueryResult, StorageBinary, createCMS, isStale, sha256Hex, withRetry };
|