@ryusenkei/maezae 0.7.1 → 0.9.0
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 +2 -0
- package/dist/analytics.js +3 -3
- package/dist/delivery.js +9 -9
- package/dist/model.js +24 -2
- package/dist/{page-TFUlKv3R.js → page-BnwHL-LC.js} +22 -1
- package/dist/types/analytics/src/index.d.ts +1 -1
- package/dist/types/analytics/src/record.d.ts +3 -3
- package/dist/types/analytics/src/source.d.ts +6 -6
- package/dist/types/cms-contract/src/embeds.d.ts +1 -1
- package/dist/types/cms-contract/src/errors.d.ts +1 -1
- package/dist/types/cms-contract/src/import.d.ts +101 -0
- package/dist/types/cms-contract/src/index.d.ts +2 -1
- package/dist/types/cms-contract/src/webhooks.d.ts +16 -1
- package/dist/types/model/src/index.d.ts +1 -1
- package/dist/types/model/src/mediaUrl.d.ts +3 -3
- package/dist/types/model/src/model.d.ts +22 -11
- package/dist/types/model/src/schema.d.ts +1 -1
- package/dist/types/{delivery-client/src → sdk/src/delivery}/client.d.ts +7 -6
- package/dist/types/{delivery-client/src → sdk/src/delivery}/index.d.ts +1 -1
- package/dist/types/{delivery-client/src → sdk/src/delivery}/media.d.ts +1 -1
- package/dist/types/{delivery-client/src → sdk/src/delivery}/query.d.ts +1 -1
- package/dist/types/{delivery-client/src → sdk/src/delivery}/schema.d.ts +1 -1
- package/dist/types/{delivery-client/src → sdk/src/delivery}/values.d.ts +2 -2
- package/dist/types/sdk/src/delivery.d.ts +2 -2
- package/dist/types/sdk/src/dev.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -51,3 +51,5 @@ import { type PublishCheckRequest, SIGNED_HEADERS, verifyRequest } from '@ryusen
|
|
|
51
51
|
if (!(await verifyRequest(env.CMS_FUNCTION_SECRET, request, { header: SIGNED_HEADERS.outbound }))) return new Response(null, { status: 401 });
|
|
52
52
|
const body = (await request.json()) as PublishCheckRequest;
|
|
53
53
|
```
|
|
54
|
+
|
|
55
|
+
- Webhook の重複: 失敗した送信は同じ本文で再送する。本文の `id`(イベントの ID)を処理済みとして保存し、同じ `id` は処理せずに 2xx を返す
|
package/dist/analytics.js
CHANGED
|
@@ -11,7 +11,7 @@ const BOT = /bot|crawl|spider|slurp|preview|monitor|headless/i;
|
|
|
11
11
|
/** ボットの UA か */
|
|
12
12
|
const isBot = (userAgent) => BOT.test(userAgent ?? "");
|
|
13
13
|
/** 閲覧を1件記録(対象: GET で応答が200の HTML・ボット以外、記録の失敗は無視) */
|
|
14
|
-
function recordView(dataset, request, response, { classify, timeZone,
|
|
14
|
+
function recordView(dataset, request, response, { classify, timeZone, project }) {
|
|
15
15
|
if (!dataset || request.method !== "GET" || response.status !== 200) return;
|
|
16
16
|
if (!response.headers.get("content-type")?.includes("text/html") || isBot(request.headers.get("user-agent"))) return;
|
|
17
17
|
const path = new URL(request.url).pathname;
|
|
@@ -24,9 +24,9 @@ function recordView(dataset, request, response, { classify, timeZone, tenant })
|
|
|
24
24
|
path,
|
|
25
25
|
dayIn(timeZone),
|
|
26
26
|
"view",
|
|
27
|
-
|
|
27
|
+
project ?? ""
|
|
28
28
|
],
|
|
29
|
-
indexes: [
|
|
29
|
+
indexes: [project ?? kind]
|
|
30
30
|
});
|
|
31
31
|
} catch {}
|
|
32
32
|
}
|
package/dist/delivery.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
//
|
|
1
|
+
import { a as optionsOf, l as cropRect, o as typeOf, p as createClock, t as pagePathOf, u as croppedHotspot } from "./page-BnwHL-LC.js";
|
|
2
|
+
// src/delivery/query.ts
|
|
3
3
|
const isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
4
4
|
/** in の値の検査(コンマを含む値はクエリで区切れない) */
|
|
5
5
|
const joined = (values) => {
|
|
@@ -25,7 +25,7 @@ function listParams(query) {
|
|
|
25
25
|
if (query.cursor) params.cursor = query.cursor;
|
|
26
26
|
return params;
|
|
27
27
|
}
|
|
28
|
-
//
|
|
28
|
+
// src/delivery/client.ts
|
|
29
29
|
/** 配信 API のパスの前半 */
|
|
30
30
|
const DELIVERY_PATH = "/content/v1";
|
|
31
31
|
/** 配信 API の取得の失敗(call: 失敗した経路、status: 応答のステータス) */
|
|
@@ -134,10 +134,10 @@ const VIDEO_PATH = /^\/videos\/([A-Za-z0-9_-]+)\/([A-Za-z0-9_-]+)\.([a-z0-9]+)$/
|
|
|
134
134
|
function parseMediaPath(pathname) {
|
|
135
135
|
const image = IMAGE_PATH.exec(pathname);
|
|
136
136
|
if (image) {
|
|
137
|
-
const [,
|
|
137
|
+
const [, project, id, width, height, ext] = image;
|
|
138
138
|
return mediaMimeOf(ext)?.startsWith("image/") ? {
|
|
139
139
|
kind: "image",
|
|
140
|
-
|
|
140
|
+
project,
|
|
141
141
|
id,
|
|
142
142
|
ext,
|
|
143
143
|
width: Number(width),
|
|
@@ -146,10 +146,10 @@ function parseMediaPath(pathname) {
|
|
|
146
146
|
}
|
|
147
147
|
const video = VIDEO_PATH.exec(pathname);
|
|
148
148
|
if (video) {
|
|
149
|
-
const [,
|
|
149
|
+
const [, project, id, ext] = video;
|
|
150
150
|
return mediaMimeOf(ext)?.startsWith("video/") ? {
|
|
151
151
|
kind: "video",
|
|
152
|
-
|
|
152
|
+
project,
|
|
153
153
|
id,
|
|
154
154
|
ext
|
|
155
155
|
} : null;
|
|
@@ -224,7 +224,7 @@ function imageParamsOf(query) {
|
|
|
224
224
|
...rect && { rect }
|
|
225
225
|
};
|
|
226
226
|
}
|
|
227
|
-
//
|
|
227
|
+
// src/delivery/media.ts
|
|
228
228
|
/** 配信 URL の画像の切り抜き(クエリ rect、範囲なしは元の URL) */
|
|
229
229
|
const deliveredImageUrl = (src, rect) => rect ? withImageParams(src, { rect }) : src;
|
|
230
230
|
/**
|
|
@@ -274,7 +274,7 @@ function mediaOf(base, imageUrl) {
|
|
|
274
274
|
};
|
|
275
275
|
};
|
|
276
276
|
}
|
|
277
|
-
//
|
|
277
|
+
// src/delivery/schema.ts
|
|
278
278
|
/** 選択肢の項目から表示名の表(値 → 表示名、key はまとまりの中なら `links.kind` の形、選択肢の項目でなければ空) */
|
|
279
279
|
const optionLabels = (schema, type, key) => Object.fromEntries(optionsOf(typeOf(schema, type), key).map((o) => [o.value, o.label]));
|
|
280
280
|
/** 型の項目(なければ例外: 導入先の設定の誤り) */
|
package/dist/model.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { c as coverStart, d as objectPosition, f as stillOf, i as acceptsRole, l as cropRect, m as isDateOnly, n as publicPathOf, o as typeOf, p as createClock, r as FIELD_ROLES, s as coverPosition, t as pagePathOf, u as croppedHotspot } from "./page-BnwHL-LC.js";
|
|
2
2
|
import { i as CORE_COMPONENTS, t as declaredComponentsSchema } from "./declared-9_jI3JXH.js";
|
|
3
3
|
import "./src-BrLwIWaT.js";
|
|
4
4
|
import { z } from "zod";
|
|
@@ -413,6 +413,12 @@ function computedProblems(fields) {
|
|
|
413
413
|
return [...[...fields.find((g) => g.key === f.computed.from)?.type === "body" ? [] : [`${f.key}: 計算の元 ${f.computed.from} が同じ型の本文の項目でない`], ...COMPUTED_TYPES[f.computed.kind]?.(f) ? [] : [`${f.key}: 計算の種類 ${f.computed.kind} に合わない項目の種類 ${f.type}`]], ...inner];
|
|
414
414
|
});
|
|
415
415
|
}
|
|
416
|
+
/** 役割の宣言の誤り(最上位にない key・役割が受け付けない項目) */
|
|
417
|
+
const roleProblems = (roles, fields) => Object.entries(roles).flatMap(([role, key]) => {
|
|
418
|
+
const f = fields.find((g) => g.key === key);
|
|
419
|
+
if (!f) return [`${role}: 項目 ${key} が最上位にない`];
|
|
420
|
+
return acceptsRole(role, f) ? [] : [`${role}: 項目 ${key}(${f.type})は役割に合わない`];
|
|
421
|
+
});
|
|
416
422
|
/** 本文の項目が使用する部品の名前(まとまりの中も、key は項目の key) */
|
|
417
423
|
const bodyComponents = (fields) => fields.flatMap((f) => f.type === "body" ? f.profile.components.map((name) => ({
|
|
418
424
|
key: f.key,
|
|
@@ -438,7 +444,8 @@ const contentType = z.object({
|
|
|
438
444
|
field: fieldKey
|
|
439
445
|
})).optional(),
|
|
440
446
|
og: z.string().startsWith("/", "OG 画像の雛形は / で始まる").optional(),
|
|
441
|
-
idInput: z.boolean().optional()
|
|
447
|
+
idInput: z.boolean().optional(),
|
|
448
|
+
roles: z.partialRecord(z.enum(FIELD_ROLES), fieldKey).optional()
|
|
442
449
|
}).refine((t) => new Set(t.fields.map((f) => f.key)).size === t.fields.length, { message: "項目の key が重複" }).refine((t) => conditionsValid(t.fields), { message: "項目の条件が同じ階層の選択肢の項目と値を指していない" }).refine((t) => (t.pages ?? []).every((p) => conditionValid(p.when, t.fields)), { message: "ページの条件が型の選択肢の項目と値を指していない" }).superRefine((t, ctx) => {
|
|
443
450
|
for (const k of reservedKeysOf(t)) ctx.addIssue({
|
|
444
451
|
code: "custom",
|
|
@@ -452,6 +459,11 @@ const contentType = z.object({
|
|
|
452
459
|
code: "custom",
|
|
453
460
|
message: `型 ${t.id} の項目 ${m}`
|
|
454
461
|
});
|
|
462
|
+
for (const m of roleProblems(t.roles ?? {}, t.fields)) ctx.addIssue({
|
|
463
|
+
code: "custom",
|
|
464
|
+
message: `型 ${t.id} の役割 ${m}`,
|
|
465
|
+
path: ["roles"]
|
|
466
|
+
});
|
|
455
467
|
});
|
|
456
468
|
const modelSchema = z.object({
|
|
457
469
|
components: declaredComponentsSchema.optional(),
|
|
@@ -527,6 +539,11 @@ const DEFAULT_SCHEMA = { "types": [
|
|
|
527
539
|
"id": "post",
|
|
528
540
|
"label": "投稿",
|
|
529
541
|
"publishing": "review",
|
|
542
|
+
"roles": {
|
|
543
|
+
"title": "title",
|
|
544
|
+
"image": "image",
|
|
545
|
+
"body": "body"
|
|
546
|
+
},
|
|
530
547
|
"fields": [
|
|
531
548
|
{
|
|
532
549
|
"key": "title",
|
|
@@ -635,6 +652,10 @@ const DEFAULT_SCHEMA = { "types": [
|
|
|
635
652
|
{
|
|
636
653
|
"id": "author",
|
|
637
654
|
"label": "著者",
|
|
655
|
+
"roles": {
|
|
656
|
+
"title": "name",
|
|
657
|
+
"image": "portrait"
|
|
658
|
+
},
|
|
638
659
|
"fields": [
|
|
639
660
|
{
|
|
640
661
|
"key": "name",
|
|
@@ -659,6 +680,7 @@ const DEFAULT_SCHEMA = { "types": [
|
|
|
659
680
|
{
|
|
660
681
|
"id": "tag",
|
|
661
682
|
"label": "タグ",
|
|
683
|
+
"roles": { "title": "label" },
|
|
662
684
|
"fields": [{
|
|
663
685
|
"key": "label",
|
|
664
686
|
"label": "名前",
|
|
@@ -101,6 +101,14 @@ function croppedHotspot(hotspot, crop) {
|
|
|
101
101
|
};
|
|
102
102
|
}
|
|
103
103
|
// ../model/src/model.ts
|
|
104
|
+
/** 項目の役割(製品の処理が型ごとの key によらず参照する項目) */
|
|
105
|
+
const FIELD_ROLES = [
|
|
106
|
+
"title",
|
|
107
|
+
"image",
|
|
108
|
+
"body",
|
|
109
|
+
"summary",
|
|
110
|
+
"date"
|
|
111
|
+
];
|
|
104
112
|
/** コンテンツスキーマの型(id から、なければ例外: 導入先の設定の誤り) */
|
|
105
113
|
function typeOf(model, id) {
|
|
106
114
|
const type = model.types.find((t) => t.id === id);
|
|
@@ -114,6 +122,19 @@ function optionsOf(type, key) {
|
|
|
114
122
|
for (const k of rest) field = field?.type === "group" ? field.fields.find((f) => f.key === k) : void 0;
|
|
115
123
|
return field?.type === "select" ? field.options : [];
|
|
116
124
|
}
|
|
125
|
+
/** 入力する項目か(計算の項目を除く) */
|
|
126
|
+
const isInputField = (f) => !f.computed;
|
|
127
|
+
/** 役割ごとに受け付ける項目(宣言の検査と、宣言のない型の推測で共通) */
|
|
128
|
+
const ROLE_ACCEPTS = {
|
|
129
|
+
title: (f) => (f.type === "text" || f.type === "textarea") && !f.multiple && isInputField(f),
|
|
130
|
+
image: (f) => f.type === "media" && !f.multiple && (!f.accept || f.accept.includes("image")),
|
|
131
|
+
body: (f) => f.type === "body",
|
|
132
|
+
summary: (f) => (f.type === "text" || f.type === "textarea") && !f.multiple,
|
|
133
|
+
date: (f) => f.type === "date" || f.type === "datetime"
|
|
134
|
+
};
|
|
135
|
+
ROLE_ACCEPTS.image, ROLE_ACCEPTS.body;
|
|
136
|
+
/** 役割の項目が受け付ける項目か(宣言の検査に使用) */
|
|
137
|
+
const acceptsRole = (role, f) => ROLE_ACCEPTS[role](f);
|
|
117
138
|
// ../model/src/page.ts
|
|
118
139
|
const matches = (when, entry) => !when || when.in.includes(String(entry[when.key]));
|
|
119
140
|
const passes = (rule, entry, now) => {
|
|
@@ -149,4 +170,4 @@ function hasPublicPage(type, entry, now) {
|
|
|
149
170
|
function publicPathOf(type, entry, now) {
|
|
150
171
|
return hasPublicPage(type, entry, now) ? pagePathOf(type, entry) : null;
|
|
151
172
|
}
|
|
152
|
-
export {
|
|
173
|
+
export { optionsOf as a, coverStart as c, objectPosition as d, stillOf as f, acceptsRole as i, cropRect as l, isDateOnly as m, publicPathOf as n, typeOf as o, createClock as p, FIELD_ROLES as r, coverPosition as s, pagePathOf as t, croppedHotspot as u };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { recordView, type Classify, type Dataset } from './record.js';
|
|
2
2
|
export { syncCron } from './schedule.js';
|
|
3
|
-
export { analyticsEngine, type DailyRow, fixedSource, type Source,
|
|
3
|
+
export { analyticsEngine, type DailyRow, fixedSource, type Source, projectDaily, type ProjectSource } from './source.js';
|
|
4
4
|
export { readDaily, syncDaily } from './store.js';
|
|
@@ -11,12 +11,12 @@ export type Classify = (path: string) => {
|
|
|
11
11
|
kind: string;
|
|
12
12
|
id: string;
|
|
13
13
|
};
|
|
14
|
-
/** 記録の設定(
|
|
14
|
+
/** 記録の設定(project は媒体の識別子) */
|
|
15
15
|
type RecordOptions = {
|
|
16
16
|
classify: Classify;
|
|
17
17
|
timeZone: string;
|
|
18
|
-
|
|
18
|
+
project?: string;
|
|
19
19
|
};
|
|
20
20
|
/** 閲覧を1件記録(対象: GET で応答が200の HTML・ボット以外、記録の失敗は無視) */
|
|
21
|
-
export declare function recordView(dataset: Dataset | undefined, request: Request, response: Response, { classify, timeZone,
|
|
21
|
+
export declare function recordView(dataset: Dataset | undefined, request: Request, response: Response, { classify, timeZone, project }: RecordOptions): void;
|
|
22
22
|
export {};
|
|
@@ -9,25 +9,25 @@ export type DailyRow = {
|
|
|
9
9
|
export type Source = {
|
|
10
10
|
daily(since: string): Promise<DailyRow[]>;
|
|
11
11
|
};
|
|
12
|
-
/** Analytics Engine の接続の設定(token は Account Analytics の読み取りの API トークン、
|
|
12
|
+
/** Analytics Engine の接続の設定(token は Account Analytics の読み取りの API トークン、project は絞り込む媒体の識別子) */
|
|
13
13
|
type AnalyticsEngineOptions = {
|
|
14
14
|
accountId: string;
|
|
15
15
|
token: string;
|
|
16
16
|
dataset: string;
|
|
17
|
-
|
|
17
|
+
project?: string;
|
|
18
18
|
};
|
|
19
19
|
/** 1回の問い合わせの行数 */
|
|
20
20
|
export declare const PAGE_ROWS = 10000;
|
|
21
21
|
/** 問い合わせの回数の上限(PAGE_ROWS との積が1回で集計できる行数) */
|
|
22
22
|
export declare const MAX_PAGES = 20;
|
|
23
23
|
/** Analytics Engine の SQL API の読み込み元 */
|
|
24
|
-
export declare function analyticsEngine({ accountId, token, dataset,
|
|
24
|
+
export declare function analyticsEngine({ accountId, token, dataset, project }: AnalyticsEngineOptions): Source;
|
|
25
25
|
/** 全媒体の読み込み元の型(since 以降の日付の閲覧数を媒体の識別子ごとに) */
|
|
26
|
-
export type
|
|
27
|
-
|
|
26
|
+
export type ProjectSource = {
|
|
27
|
+
dailyByProject(since: string): Promise<ReadonlyMap<string, DailyRow[]>>;
|
|
28
28
|
};
|
|
29
29
|
/** 全媒体を1回の問い合わせで集計する Analytics Engine の読み込み元(媒体の列が空の記録は除外) */
|
|
30
|
-
export declare function
|
|
30
|
+
export declare function projectDaily(options: Omit<AnalyticsEngineOptions, 'project'>): ProjectSource;
|
|
31
31
|
/** 集計済みの行の読み込み元(定期の集計で全媒体の問い合わせ結果を媒体ごとに受け渡し、daily は since 以降の行) */
|
|
32
32
|
export declare const fixedSource: (rows: readonly DailyRow[]) => Source;
|
|
33
33
|
export {};
|
|
@@ -70,7 +70,7 @@ export type ErrorParams = {
|
|
|
70
70
|
/** 使用先: in_use */
|
|
71
71
|
by?: 'uses' | 'places' | 'outputs' | 'entry' | 'writers' | 'members' | 'accounts';
|
|
72
72
|
/** 状態の不一致の理由: invalid_state */
|
|
73
|
-
reason?: 'not_draft' | 'not_in_review' | 'request_handled' | 'deleted' | 'not_deleted' | 'schema_confirm' | 'no_publishing' | 'no_review';
|
|
73
|
+
reason?: 'not_draft' | 'no_draft' | 'not_in_review' | 'request_handled' | 'deleted' | 'not_deleted' | 'schema_confirm' | 'no_publishing' | 'no_review';
|
|
74
74
|
/** 取得の対象: upstream_failed */
|
|
75
75
|
resource?: 'page' | 'image' | 'webhook';
|
|
76
76
|
/**
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/** 1回のリクエストで取り込む件数の上限(画像の取得の時間と、本文の大きさの上限 JSON_BODY_MAX のため) */
|
|
2
|
+
export declare const IMPORT_ITEMS_MAX = 50;
|
|
3
|
+
/** 取り込む1件(fields は項目の key と値、source は報告に載せる元の位置: ファイルの行・元の CMS の ID など) */
|
|
4
|
+
export type ImportItem = Readonly<{
|
|
5
|
+
type: string;
|
|
6
|
+
id?: string;
|
|
7
|
+
fields: Readonly<Record<string, unknown>>;
|
|
8
|
+
source?: string;
|
|
9
|
+
}>;
|
|
10
|
+
/** 取り込みの問題の種類 */
|
|
11
|
+
export declare const IMPORT_PROBLEMS: readonly ["unknown_type", "forbidden", "invalid_id", "id_conflict", "duplicate_id", "unknown_field", "invalid_value", "image_failed", "markdown", "save_rejected", "reference_lowercased"];
|
|
12
|
+
export type ImportProblemCode = (typeof IMPORT_PROBLEMS)[number];
|
|
13
|
+
/** 問題の種類の表示名 */
|
|
14
|
+
export declare const IMPORT_PROBLEM_LABELS: {
|
|
15
|
+
readonly unknown_type: "取り込めない型";
|
|
16
|
+
readonly forbidden: "作成の権限がない";
|
|
17
|
+
readonly invalid_id: "ID の形が不正";
|
|
18
|
+
readonly id_conflict: "ID の変換でぶつかる";
|
|
19
|
+
readonly duplicate_id: "ID が重複";
|
|
20
|
+
readonly unknown_field: "スキーマにない項目(取り込まない)";
|
|
21
|
+
readonly invalid_value: "値の形が不正";
|
|
22
|
+
readonly image_failed: "画像を取り込めない";
|
|
23
|
+
readonly markdown: "本文を変換できない";
|
|
24
|
+
readonly save_rejected: "保存の検査で拒否";
|
|
25
|
+
readonly reference_lowercased: "参照の ID を小文字に変換";
|
|
26
|
+
};
|
|
27
|
+
/** 取り込みの問題(error は取り込まない、warning は取り込んで報告、path は項目の key・まとまりの中はドットで連結) */
|
|
28
|
+
export type ImportProblem = Readonly<{
|
|
29
|
+
level: 'error' | 'warning';
|
|
30
|
+
code: ImportProblemCode;
|
|
31
|
+
path: string;
|
|
32
|
+
message: string;
|
|
33
|
+
}>;
|
|
34
|
+
/** 1件の結果(created は作成、ready は試しの実行で作成できる、skipped は問題で取り込まない) */
|
|
35
|
+
export type ImportItemReport = Readonly<{
|
|
36
|
+
source: string;
|
|
37
|
+
type: string;
|
|
38
|
+
id: string | null;
|
|
39
|
+
status: 'created' | 'ready' | 'skipped';
|
|
40
|
+
problems: readonly ImportProblem[];
|
|
41
|
+
}>;
|
|
42
|
+
/** 画像の結果(checked は試しの実行で取得できた、asset は保存した画像の ID) */
|
|
43
|
+
export type ImportImage = Readonly<{
|
|
44
|
+
url: string;
|
|
45
|
+
status: 'imported' | 'existing' | 'checked' | 'failed';
|
|
46
|
+
asset: string | null;
|
|
47
|
+
message: string | null;
|
|
48
|
+
}>;
|
|
49
|
+
/** 小文字に変換した ID(paths は型のページの旧と新のパス、ページのない型は null) */
|
|
50
|
+
export type ImportIdChange = Readonly<{
|
|
51
|
+
type: string;
|
|
52
|
+
from: string;
|
|
53
|
+
to: string;
|
|
54
|
+
source: string;
|
|
55
|
+
paths: Readonly<{
|
|
56
|
+
from: string;
|
|
57
|
+
to: string;
|
|
58
|
+
}> | null;
|
|
59
|
+
}>;
|
|
60
|
+
/** 変換でぶつかる ID(ids は元の ID、existing は変換後の ID の行がすでにある) */
|
|
61
|
+
export type ImportIdConflict = Readonly<{
|
|
62
|
+
type: string;
|
|
63
|
+
id: string;
|
|
64
|
+
ids: readonly string[];
|
|
65
|
+
sources: readonly string[];
|
|
66
|
+
existing: boolean;
|
|
67
|
+
}>;
|
|
68
|
+
/** 取り込みの報告 */
|
|
69
|
+
export type ImportReport = Readonly<{
|
|
70
|
+
dryRun: boolean;
|
|
71
|
+
summary: Readonly<{
|
|
72
|
+
items: number;
|
|
73
|
+
created: number;
|
|
74
|
+
ready: number;
|
|
75
|
+
skipped: number;
|
|
76
|
+
images: Readonly<Record<ImportImage['status'], number>>;
|
|
77
|
+
}>;
|
|
78
|
+
items: readonly ImportItemReport[];
|
|
79
|
+
images: readonly ImportImage[];
|
|
80
|
+
idChanges: readonly ImportIdChange[];
|
|
81
|
+
idConflicts: readonly ImportIdConflict[];
|
|
82
|
+
}>;
|
|
83
|
+
/** 取り込む ID(前後の空白を除き小文字に、changed は大文字を含んでいた) */
|
|
84
|
+
export declare function importIdOf(raw: string): Readonly<{
|
|
85
|
+
id: string;
|
|
86
|
+
changed: boolean;
|
|
87
|
+
}>;
|
|
88
|
+
/** 入力の中の ID の計画(conflicts は大文字と小文字の違いだけでぶつかる組み合わせ、duplicates は同じ ID が複数、どちらも位置 index の集合で除外) */
|
|
89
|
+
export type ImportIdPlan = Readonly<{
|
|
90
|
+
conflicts: readonly ImportIdConflict[];
|
|
91
|
+
excluded: ReadonlySet<number>;
|
|
92
|
+
duplicates: ReadonlySet<number>;
|
|
93
|
+
}>;
|
|
94
|
+
/** 入力の中で ID がぶつかる行(型ごと、ID のない行は自動の ID で対象外) */
|
|
95
|
+
export declare function planImportIds(items: readonly ImportItem[]): ImportIdPlan;
|
|
96
|
+
/** 報告に載せる元の位置(指定がなければ入力の何件目か) */
|
|
97
|
+
export declare const sourceOf: (item: ImportItem, index: number) => string;
|
|
98
|
+
/** 件数を数え直した報告 */
|
|
99
|
+
export declare function importReportOf(dryRun: boolean, parts: Omit<ImportReport, 'dryRun' | 'summary'>): ImportReport;
|
|
100
|
+
/** 分けて送った取り込みの報告を1つに(同じ URL の画像は先の結果) */
|
|
101
|
+
export declare function mergeImportReports(dryRun: boolean, reports: readonly ImportReport[], extra?: Partial<Omit<ImportReport, 'dryRun' | 'summary'>>): ImportReport;
|
|
@@ -12,8 +12,9 @@ export { type AccountLink, type Action, ACTION_LEVELS, ACTIONS, allows, ANY_TARG
|
|
|
12
12
|
export { ADMIN_PERMISSIONS, ADMIN_ROLE, isAdmin, rolePermissionsOf, type Role, SYSTEM_ROLES, type User, WRITER_ROLE } from './roles.js';
|
|
13
13
|
export { isServerPath, OPS_PATHS, SERVER_PATHS } from './paths.js';
|
|
14
14
|
export { CONFIG_FORMAT, type ConfigBundle, type ConfigPreview } from './transfer.js';
|
|
15
|
+
export { IMPORT_ITEMS_MAX, IMPORT_PROBLEM_LABELS, IMPORT_PROBLEMS, type ImportIdChange, type ImportIdConflict, importIdOf, type ImportIdPlan, type ImportImage, type ImportItem, type ImportItemReport, type ImportProblem, type ImportProblemCode, type ImportReport, importReportOf, mergeImportReports, planImportIds, sourceOf } from './import.js';
|
|
15
16
|
export { EMBED_CONTEXT_PARAM, EMBED_CONTEXT_TTL_SEC, EMBED_MESSAGES, EMBED_PLACEMENTS, type EmbedContext, type EmbedEntry, type EmbedMessage, type EmbedPlacement, type ExternalScreen } from './embeds.js';
|
|
16
17
|
export { type ExternalFunction, FUNCTION_HOOK_LABELS, FUNCTION_HOOKS, functionEventLabel, functionEventOf, type FunctionHook, type FunctionOnError, type FunctionRequest, type PublishCheckRequest, type PublishCheckResponse, type SaveCheckRequest, type SaveCheckResponse } from './functions.js';
|
|
17
|
-
export { parseWebhookEvent, type Webhook, WEBHOOK_ACTION_LABELS, type WebhookBody, WEBHOOK_ACTIONS, type WebhookAction, type WebhookEvent, webhookEventLabel, webhookEventOf, type WebhookKind } from './webhooks.js';
|
|
18
|
+
export { parseWebhookEvent, type Webhook, WEBHOOK_ACTION_LABELS, type WebhookBody, WEBHOOK_ACTIONS, type WebhookAction, type WebhookDelivery, type WebhookEvent, webhookEventLabel, webhookEventOf, type WebhookKind } from './webhooks.js';
|
|
18
19
|
export { type SavedView, VIEW_ACTIONS, type ViewAction, type ViewDefinition } from './views.js';
|
|
19
20
|
export { canManageSettings, isSettingsTarget, managedAreasOf, SETTINGS_AREA_LABELS, SETTINGS_AREAS, type SettingsArea, settingsTarget } from './settings.js';
|
|
@@ -31,9 +31,11 @@ export type Webhook = Readonly<{
|
|
|
31
31
|
}>;
|
|
32
32
|
/**
|
|
33
33
|
* json の形式の本文(編集機能を持つ型の出来事、署名はヘッダー x-cms-signature で登録ごとの鍵)
|
|
34
|
-
* -
|
|
34
|
+
* - id: イベントの ID(再送しても同じ値、受け手は処理済みの id を捨てて重複を除く)
|
|
35
|
+
* - item: 行の ID と題、by: 操作した人の表示名、at: 出来事の日時(ISO 8601、再送しても同じ値)
|
|
35
36
|
*/
|
|
36
37
|
export type WebhookBody = Readonly<{
|
|
38
|
+
id: string;
|
|
37
39
|
event: WebhookEvent;
|
|
38
40
|
type: string;
|
|
39
41
|
item: Readonly<{
|
|
@@ -43,3 +45,16 @@ export type WebhookBody = Readonly<{
|
|
|
43
45
|
by: string;
|
|
44
46
|
at: string;
|
|
45
47
|
}>;
|
|
48
|
+
/** 送信の記録(attempt は何回目の送信か、retryAt は次の再送の予定の日時、再送なしは null) */
|
|
49
|
+
export type WebhookDelivery = Readonly<{
|
|
50
|
+
id: number;
|
|
51
|
+
source: 'webhook' | 'function';
|
|
52
|
+
event: string;
|
|
53
|
+
status: number;
|
|
54
|
+
error: string | null;
|
|
55
|
+
eventId: string | null;
|
|
56
|
+
attempt: number;
|
|
57
|
+
retryAt: string | null;
|
|
58
|
+
label: string | null;
|
|
59
|
+
created_at: string;
|
|
60
|
+
}>;
|
|
@@ -8,7 +8,7 @@ export { primaryTypeOf, requiredPrimaryTypeOf, SOURCES_FIELD, sourceIdsOf, sourc
|
|
|
8
8
|
export { appliesTo, checkFields, fieldsFor } from './check.js';
|
|
9
9
|
export { deliveredFields, emptyValues, pickValues, referencedIds, referencesOf, valueFieldsOf } from './values.js';
|
|
10
10
|
export { entryRefsOf, type EntryRef } from './refs.js';
|
|
11
|
-
export {
|
|
11
|
+
export { acceptsRole, bodyFieldsOf, computedFieldsOf, FIELD_ROLES, idInputOf, initialValueOf, isEditorial, isInputField, isListType, isMediaType, isSingleton, isStoredType, MEDIA_TYPE_IDS, optionLabelOf, optionsOf, publishingOf, requestReferencesOf, resolvedRolesOf, roleFieldOf, toneOf, typeOf, type ComputedKind, type FieldRole, type FieldRoles, type FieldComputed, type ContentFormat, type ContentModel, type ContentType, type FieldCondition, type FieldDef, type FieldDerive, type FieldFixedBy, type CountDef, type FieldProblem, type MediaKind, type OptionTone, type Publishing, type ReferenceRules, type SelectOption } from './model.js';
|
|
12
12
|
export { hasPublicPage, imageFrameOf, pagePathOf, publicPathOf, withPagesFrom, type ImageFrame, type ImageFrameDef, type PageDef, type PageEntry, type PageRule } from './page.js';
|
|
13
13
|
export { schemaRulesOf, type SchemaRule } from './rules.js';
|
|
14
14
|
export { parseModel } from './schema.js';
|
|
@@ -6,16 +6,16 @@ export declare const mediaMimeOf: (ext: string) => string | null;
|
|
|
6
6
|
/** 配信 URL のパスの要素(寸法は画像だけ) */
|
|
7
7
|
export type MediaPath = Readonly<{
|
|
8
8
|
kind: 'image' | 'video';
|
|
9
|
-
|
|
9
|
+
project: string;
|
|
10
10
|
id: string;
|
|
11
11
|
ext: string;
|
|
12
12
|
width?: number;
|
|
13
13
|
height?: number;
|
|
14
14
|
}>;
|
|
15
15
|
/** 配信 URL のパス(媒体・ID の形が不正、配信しない形式なら null) */
|
|
16
|
-
export declare function mediaPathOf({ kind,
|
|
16
|
+
export declare function mediaPathOf({ kind, project, id, mimeType, width, height }: Readonly<{
|
|
17
17
|
kind: 'image' | 'video';
|
|
18
|
-
|
|
18
|
+
project: string;
|
|
19
19
|
id: string;
|
|
20
20
|
mimeType: string;
|
|
21
21
|
width: number;
|
|
@@ -134,6 +134,7 @@ export type Publishing = 'none' | 'draft' | 'review';
|
|
|
134
134
|
* - counts: 被参照の件数(ページの公開中の条件・ページの公開で必須の判定に使用)
|
|
135
135
|
* - og: サイトの OG 画像のパスの雛形({key} は行の値、管理画面の OG 画像のプレビュー)
|
|
136
136
|
* - idInput: 作成のときに管理画面で ID を入力できる(ページのある型は常に入力可、空欄は自動)
|
|
137
|
+
* - roles: 項目の役割(役割ごとに最上位の項目の key、roleFieldOf)
|
|
137
138
|
*/
|
|
138
139
|
export type ContentType = Readonly<{
|
|
139
140
|
id: string;
|
|
@@ -146,7 +147,13 @@ export type ContentType = Readonly<{
|
|
|
146
147
|
counts?: readonly CountDef[];
|
|
147
148
|
og?: string;
|
|
148
149
|
idInput?: boolean;
|
|
150
|
+
roles?: FieldRoles;
|
|
149
151
|
}>;
|
|
152
|
+
/** 項目の役割(製品の処理が型ごとの key によらず参照する項目) */
|
|
153
|
+
export declare const FIELD_ROLES: readonly ["title", "image", "body", "summary", "date"];
|
|
154
|
+
export type FieldRole = (typeof FIELD_ROLES)[number];
|
|
155
|
+
/** 型の役割の宣言(役割ごとに最上位の項目の key) */
|
|
156
|
+
export type FieldRoles = Readonly<Partial<Record<FieldRole, string>>>;
|
|
150
157
|
/** コンテンツスキーマ(導入先ごとに1つ) */
|
|
151
158
|
export type ContentModel = Readonly<{
|
|
152
159
|
types: readonly ContentType[];
|
|
@@ -189,18 +196,22 @@ export declare const toneOf: (type: ContentType, key: string, value: string) =>
|
|
|
189
196
|
export declare const optionLabelOf: (type: ContentType, key: string, value: string) => string;
|
|
190
197
|
/** 入力する項目か(計算の項目を除く) */
|
|
191
198
|
export declare const isInputField: (f: FieldDef) => boolean;
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
199
|
+
type BodyField = Extract<FieldDef, {
|
|
200
|
+
type: 'body';
|
|
201
|
+
}>;
|
|
202
|
+
/** 役割の項目が受け付ける項目か(宣言の検査に使用) */
|
|
203
|
+
export declare const acceptsRole: (role: FieldRole, f: FieldDef) => boolean;
|
|
204
|
+
/**
|
|
205
|
+
* 型の役割の項目(宣言 roles の項目、宣言のない役割は推測、なければ null)
|
|
206
|
+
* - 用途: 題は行の表示名、画像は一覧・参照の候補・アイキャッチ、本文は Markdown・点検・制作の案内、要約は説明、日付は暦
|
|
207
|
+
* - 宣言が最上位の項目を指さない・受け付けない項目を指す: null(検査は schema.ts)
|
|
208
|
+
*/
|
|
209
|
+
export declare function roleFieldOf(type: ContentType, role: 'body'): BodyField | null;
|
|
210
|
+
export declare function roleFieldOf(type: ContentType, role: FieldRole): FieldDef | null;
|
|
211
|
+
/** 宣言のない役割も推測で埋めた役割の宣言(既存の型に役割を書き足す移行に使用) */
|
|
212
|
+
export declare function resolvedRolesOf(type: ContentType): FieldRoles;
|
|
200
213
|
/** 最上位で本文の種類の項目(表 entry_bodies に保存、一覧では取得しない) */
|
|
201
|
-
export declare const bodyFieldsOf: (type: ContentType) =>
|
|
202
|
-
type: "body";
|
|
203
|
-
}>[];
|
|
214
|
+
export declare const bodyFieldsOf: (type: ContentType) => BodyField[];
|
|
204
215
|
/** 型の計算の項目(最上位) */
|
|
205
216
|
export declare const computedFieldsOf: (type: ContentType) => FieldDef[];
|
|
206
217
|
/** 追加の依頼ができる参照の項目(参照先が一覧で管理する型で requests の指定があるもの、タグ・分類など) */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ContentType } from '
|
|
1
|
+
import type { ContentType } from '../../../model/src/index.js';
|
|
2
2
|
import { type ListQuery, type Page } from './query.js';
|
|
3
3
|
/** 配信 API のパスの前半 */
|
|
4
4
|
export declare const DELIVERY_PATH = "/content/v1";
|
|
@@ -43,13 +43,14 @@ export declare function createDeliveryClient(delivery: Delivery, { drafts, at }?
|
|
|
43
43
|
id: string;
|
|
44
44
|
label: string;
|
|
45
45
|
description?: string;
|
|
46
|
-
format?: import("
|
|
47
|
-
publishing?: import("
|
|
48
|
-
fields: readonly import("
|
|
49
|
-
pages?: readonly import("
|
|
50
|
-
counts?: readonly import("
|
|
46
|
+
format?: import("../../../model/src/model.js").ContentFormat;
|
|
47
|
+
publishing?: import("../../../model/src/model.js").Publishing;
|
|
48
|
+
fields: readonly import("../model.js").FieldDef[];
|
|
49
|
+
pages?: readonly import("../model.js").PageDef[];
|
|
50
|
+
counts?: readonly import("../../../model/src/model.js").CountDef[];
|
|
51
51
|
og?: string;
|
|
52
52
|
idInput?: boolean;
|
|
53
|
+
roles?: import("../../../model/src/model.js").FieldRoles;
|
|
53
54
|
}>>(path: string, query: ListQuery<T> & Readonly<{
|
|
54
55
|
limit: number;
|
|
55
56
|
}>) => Promise<Page<I>>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { createDeliveryClient, DELIVERY_PATH, DeliveryError, subPath, type BundleResult, type Delivery, type DeliveryClient, type Prefetched } from './client.js';
|
|
2
2
|
export { deliveredImageUrl, mediaOf, type ImageUrl, type MediaOf } from './media.js';
|
|
3
|
-
export { imageParamsOf, parseMediaPath, withImageParams, type ImageParams, type MediaPath } from '
|
|
3
|
+
export { imageParamsOf, parseMediaPath, withImageParams, type ImageParams, type MediaPath } from '../../../model/src/index.js';
|
|
4
4
|
export { listParams, type ListFilter, type ListQuery, type Page } from './query.js';
|
|
5
5
|
export { createDeliveryClock, fieldOf, limitOf, optionLabels, pagePath, type DeliveryClock } from './schema.js';
|
|
6
6
|
export type { DeliveredAsset, FieldValue, Item, ItemMeta, ItemOf } from './values.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type CropRect, type Media } from '
|
|
1
|
+
import { type CropRect, type Media } from '../../../model/src/index.js';
|
|
2
2
|
/** 配信する画像の URL(元の URL と、元画像の画素での切り抜きの範囲から、配信の側で変換する URL) */
|
|
3
3
|
export type ImageUrl = (src: string, rect?: CropRect) => string;
|
|
4
4
|
/** 配信 URL の画像の切り抜き(クエリ rect、範囲なしは元の URL) */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Clock, type ContentModel, type DateString, type FieldDef, type PageEntry } from '
|
|
1
|
+
import { type Clock, type ContentModel, type DateString, type FieldDef, type PageEntry } from '../../../model/src/index.js';
|
|
2
2
|
/** 選択肢の項目から表示名の表(値 → 表示名、key はまとまりの中なら `links.kind` の形、選択肢の項目でなければ空) */
|
|
3
3
|
export declare const optionLabels: <K extends string = string>(schema: ContentModel, type: string, key: string) => Readonly<Record<K, string>>;
|
|
4
4
|
/** 型の項目(なければ例外: 導入先の設定の誤り) */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Body } from '
|
|
2
|
-
import type { ContentType, Crop, DateString, FieldDef, Hotspot } from '
|
|
1
|
+
import type { Body } from '../../../body/src/index.js';
|
|
2
|
+
import type { ContentType, Crop, DateString, FieldDef, Hotspot } from '../../../model/src/index.js';
|
|
3
3
|
/** 配信 API の1件の値(id・項目の key・メタ情報 _meta) */
|
|
4
4
|
export type Item = Readonly<Record<string, unknown>>;
|
|
5
5
|
/** 配信 API が解決した実体(url は配信 URL で配信のオリジンがある CMS だけ、hotspot・crop は元の画像に対する割合) */
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { createDeliveryClient, createDeliveryClock, deliveredImageUrl, DELIVERY_PATH, DeliveryError, fieldOf, imageParamsOf, limitOf, listParams, mediaOf, optionLabels, pagePath, parseMediaPath, subPath, withImageParams } from '
|
|
2
|
-
export type { BundleResult, DeliveredAsset, Delivery, DeliveryClient, DeliveryClock, FieldValue, ImageParams, ImageUrl, Item, ItemMeta, ItemOf, ListFilter, ListQuery, MediaOf, MediaPath, Page, Prefetched } from '
|
|
1
|
+
export { createDeliveryClient, createDeliveryClock, deliveredImageUrl, DELIVERY_PATH, DeliveryError, fieldOf, imageParamsOf, limitOf, listParams, mediaOf, optionLabels, pagePath, parseMediaPath, subPath, withImageParams } from './delivery/index.js';
|
|
2
|
+
export type { BundleResult, DeliveredAsset, Delivery, DeliveryClient, DeliveryClock, FieldValue, ImageParams, ImageUrl, Item, ItemMeta, ItemOf, ListFilter, ListQuery, MediaOf, MediaPath, Page, Prefetched } from './delivery/index.js';
|