@xiongtao.xt/tau-plugins 0.19.0 → 0.20.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/CHANGELOG.md +7 -0
- package/PUBLISH-DATA.md +14 -4
- package/package.json +1 -1
- package/publish-artifacts.js +50 -13
- package/publish-client.js +17 -8
- package/types/packages/markdown/src/codec.d.ts +2 -2
- package/types/packages/plugins/src/categories.d.ts +40 -0
- package/types/packages/plugins/src/package.d.ts +10 -1
- package/types/packages/plugins/src/publish-artifacts.d.ts +0 -1
- package/types/packages/plugins/src/publish-data.d.ts +18 -12
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# 更新记录
|
|
2
2
|
|
|
3
|
+
## 0.20.0
|
|
4
|
+
|
|
5
|
+
- manifest 支持 `categories`(插件中心分类)与 `keywords`(目录搜索),门户上传严格校验,客户端忽略未知值。
|
|
6
|
+
- 博客模板包(`template` 分支)同样支持分类与关键词,只含静态站点产物,不能同时声明代码插件入口。
|
|
7
|
+
- publish-data:站点级数据(`settings`、`collections`、`cardTagTree`、`projectTrees`)改为只在清单中出现;内容文件新增 `links`,只含本文用到且已发布的站内链接目标。
|
|
8
|
+
- publish-client:`readData` 随正文带回清单的 `settings`;检索引擎按索引缓存,不再每次查询重建。
|
|
9
|
+
|
|
3
10
|
## 0.19.0
|
|
4
11
|
|
|
5
12
|
- 补齐 publish-data 类型、publish-client 纯数据客户端及 publish-artifacts 协议校验/定义求值入口;数据与产物声明不连带载入 Editor/React/UI 类型。
|
package/PUBLISH-DATA.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
普通 Tau 插件仍然使用 SDK 类型开发,构建时将宿主注入模块设为 external。SDK 根入口和 UI 包不携带编辑器、组件或页面的运行实现。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
博客模板一般直接使用 `@tau/blog`:它包含数据读取、搜索、正文渲染和内容插件接入,见该包 README。只想读取数据、自己渲染正文的站点,可使用 `@tau/plugins/publish-data` 的纯数据类型和 `@tau/plugins/publish-client` 的数据客户端。客户端只有数据读取、摘要校验、取消和搜索,不包含 React、渲染器、路由或预览界面。
|
|
6
6
|
|
|
7
7
|
```ts
|
|
8
8
|
import { createClient } from "@tau/plugins/publish-client";
|
|
@@ -12,8 +12,18 @@ const manifest = await client.readManifest();
|
|
|
12
12
|
const result = await client.readData({ key: manifest.items[0].key });
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
## 数据分布
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
- 清单 `site.<摘要>.json`:站点信息、全部内容的 key 与数据文件、搜索索引引用,以及只出现一次的站点级数据——`settings`(发布外观设置)、`collections`(项目列表)、`cardTagTree`(卡片标签树)、`projectTrees`(按项目 id 的文档目录)。`readData` 会把 `settings` 一并带回。
|
|
18
|
+
- 内容文件:`key`、`meta`、`content`,以及可选的 `links`(本文正文里已发布的站内链接目标)、`pluginRenderers`(内容插件产物)和 `contentStyles`(正文动态样式)。资源以所属数据文件的 URL 为上下文解析。
|
|
19
|
+
- 公开路由完全由模板决定,数据里只有 ContentRef(`{ key, type, id? }`),没有 URL。
|
|
18
20
|
|
|
19
|
-
|
|
21
|
+
正文的站内链接由 `@tau/blog` 按 `links` 渲染,模板只提供 `hrefFor`。自己渲染正文的站点按 `links` 的键(`${contentType}:${refId}`,与求索资料的 `citeKey` 同一口径)查目标,查不到即目标未发布。
|
|
22
|
+
|
|
23
|
+
## 样式
|
|
24
|
+
|
|
25
|
+
`contentStyles` 是宿主为正文里的 HTML 节点编译的 Tailwind 工具类,属于过渡产物:按原文加载,含 `:root` 主题变量和全局类名,正文挂载期间对整个页面生效。模板若自定义了同名 Tailwind 主题变量,正文挂载时可能被这些默认值覆盖。
|
|
26
|
+
|
|
27
|
+
## 插件产物
|
|
28
|
+
|
|
29
|
+
`@tau/plugins/publish-artifacts` 提供 C23 清单校验、定义求值与节点归属检查,仅处理协议,不提供 UI、模块映射或资源生命周期。共享模块由模板通过实际公开能力提供;`@tau/blog` 已内置这部分接入。
|
package/package.json
CHANGED
package/publish-artifacts.js
CHANGED
|
@@ -36,6 +36,53 @@ function comparePluginVersions(left, right) {
|
|
|
36
36
|
return 0;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
// packages/plugins/src/categories.ts
|
|
40
|
+
var PLUGIN_CATEGORIES = [
|
|
41
|
+
{ id: "sync", label: "\u540C\u6B65" },
|
|
42
|
+
{ id: "upload", label: "\u8D44\u6E90\u4E0A\u4F20" },
|
|
43
|
+
{ id: "editor", label: "\u7F16\u8F91\u5668" },
|
|
44
|
+
{ id: "whiteboard", label: "\u767D\u677F" },
|
|
45
|
+
{ id: "blog-template", label: "\u535A\u5BA2\u6A21\u677F" },
|
|
46
|
+
{ id: "ai", label: "AI" },
|
|
47
|
+
{ id: "voice", label: "\u8BED\u97F3" },
|
|
48
|
+
{ id: "page", label: "\u9875\u9762" }
|
|
49
|
+
];
|
|
50
|
+
var PLUGIN_KEYWORD_LIMIT = 5;
|
|
51
|
+
var PLUGIN_KEYWORD_MAX_LENGTH = 20;
|
|
52
|
+
var categoryIds = new Set(PLUGIN_CATEGORIES.map((item) => item.id));
|
|
53
|
+
var isPluginCategory = (value) => typeof value === "string" && categoryIds.has(value);
|
|
54
|
+
function readCatalogFields(item, strict) {
|
|
55
|
+
const fail = (message) => {
|
|
56
|
+
if (strict) throw new Error(message);
|
|
57
|
+
};
|
|
58
|
+
const list = (value, name) => {
|
|
59
|
+
if (value === void 0) return [];
|
|
60
|
+
if (Array.isArray(value)) return value;
|
|
61
|
+
fail(`${name} \u5FC5\u987B\u662F\u6570\u7EC4`);
|
|
62
|
+
return [];
|
|
63
|
+
};
|
|
64
|
+
const categories = [];
|
|
65
|
+
for (const value of list(item.categories, "categories")) {
|
|
66
|
+
if (!isPluginCategory(value)) fail(`\u672A\u77E5\u63D2\u4EF6\u5206\u7C7B\uFF1A${String(value)}`);
|
|
67
|
+
else if (!categories.includes(value)) categories.push(value);
|
|
68
|
+
}
|
|
69
|
+
const keywords = [];
|
|
70
|
+
for (const value of list(item.keywords, "keywords")) {
|
|
71
|
+
const keyword = typeof value === "string" ? value.trim() : "";
|
|
72
|
+
if (!keyword || keyword.length > PLUGIN_KEYWORD_MAX_LENGTH)
|
|
73
|
+
fail(`\u5173\u952E\u8BCD\u5FC5\u987B\u4E3A 1 \u81F3 ${PLUGIN_KEYWORD_MAX_LENGTH} \u5B57`);
|
|
74
|
+
else if (!keywords.includes(keyword)) keywords.push(keyword);
|
|
75
|
+
}
|
|
76
|
+
if (keywords.length > PLUGIN_KEYWORD_LIMIT) {
|
|
77
|
+
fail(`\u5173\u952E\u8BCD\u6700\u591A ${PLUGIN_KEYWORD_LIMIT} \u4E2A`);
|
|
78
|
+
keywords.length = PLUGIN_KEYWORD_LIMIT;
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
...categories.length ? { categories: Object.freeze(categories) } : {},
|
|
82
|
+
...keywords.length ? { keywords: Object.freeze(keywords) } : {}
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
39
86
|
// packages/plugins/src/package.ts
|
|
40
87
|
var PLUGIN_SHARED_MODULES = [
|
|
41
88
|
"@tau/plugins",
|
|
@@ -48,7 +95,7 @@ var PLUGIN_SHARED_MODULES = [
|
|
|
48
95
|
"react/jsx-runtime",
|
|
49
96
|
"react/jsx-dev-runtime"
|
|
50
97
|
];
|
|
51
|
-
function validatePluginManifest(value) {
|
|
98
|
+
function validatePluginManifest(value, options = {}) {
|
|
52
99
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
53
100
|
throw new Error("\u63D2\u4EF6\u6E05\u5355\u5FC5\u987B\u662F\u5BF9\u8C61");
|
|
54
101
|
const item = value;
|
|
@@ -73,6 +120,7 @@ function validatePluginManifest(value) {
|
|
|
73
120
|
if (item.editor !== void 0 && item.editor !== true) throw new Error("editor \u53EA\u80FD\u58F0\u660E\u4E3A true");
|
|
74
121
|
if (item.whiteboard !== void 0 && item.whiteboard !== true)
|
|
75
122
|
throw new Error("whiteboard \u53EA\u80FD\u58F0\u660E\u4E3A true");
|
|
123
|
+
const catalog = readCatalogFields(item, options.strict === true);
|
|
76
124
|
const integrity = {};
|
|
77
125
|
for (const name of [main, ...styles ? [styles] : []]) {
|
|
78
126
|
const hash = item.integrity && typeof item.integrity === "object" ? item.integrity[name] : void 0;
|
|
@@ -92,21 +140,12 @@ function validatePluginManifest(value) {
|
|
|
92
140
|
main,
|
|
93
141
|
...item.editor === true ? { editor: true } : {},
|
|
94
142
|
...item.whiteboard === true ? { whiteboard: true } : {},
|
|
143
|
+
...catalog,
|
|
95
144
|
integrity: Object.freeze(integrity),
|
|
96
145
|
...styles === void 0 ? {} : { styles }
|
|
97
146
|
});
|
|
98
147
|
}
|
|
99
148
|
|
|
100
|
-
// packages/plugins/src/sidebar.ts
|
|
101
|
-
var SIDEBAR_GROUPS = Object.freeze({
|
|
102
|
-
daily: "daily",
|
|
103
|
-
knowledge: "knowledge",
|
|
104
|
-
learning: "learning",
|
|
105
|
-
ai: "ai",
|
|
106
|
-
sharing: "sharing",
|
|
107
|
-
plugins: "plugins"
|
|
108
|
-
});
|
|
109
|
-
|
|
110
149
|
// packages/plugins/src/rendering.ts
|
|
111
150
|
var PLUGIN_RENDER_VERSION = 1;
|
|
112
151
|
function evaluatePluginPackage(artifact, modules) {
|
|
@@ -197,7 +236,6 @@ function assertRenderTypes(definition, expected) {
|
|
|
197
236
|
}
|
|
198
237
|
|
|
199
238
|
// packages/plugins/src/publish-artifacts.ts
|
|
200
|
-
var SIDEBAR_GROUPS2 = SIDEBAR_GROUPS;
|
|
201
239
|
var PLUGIN_RENDER_VERSION2 = PLUGIN_RENDER_VERSION;
|
|
202
240
|
function evaluatePluginPackage2(artifact, modules) {
|
|
203
241
|
return evaluatePluginPackage(artifact, modules);
|
|
@@ -208,7 +246,6 @@ function assertRenderTypes2(definition, types) {
|
|
|
208
246
|
export {
|
|
209
247
|
PLUGIN_RENDER_VERSION2 as PLUGIN_RENDER_VERSION,
|
|
210
248
|
PLUGIN_SHARED_MODULES,
|
|
211
|
-
SIDEBAR_GROUPS2 as SIDEBAR_GROUPS,
|
|
212
249
|
assertRenderTypes2 as assertRenderTypes,
|
|
213
250
|
evaluatePluginPackage2 as evaluatePluginPackage,
|
|
214
251
|
validatePluginManifest
|
package/publish-client.js
CHANGED
|
@@ -45,6 +45,7 @@ function createClient({ manifestUrl }) {
|
|
|
45
45
|
const cache = /* @__PURE__ */ new Map();
|
|
46
46
|
let manifestPromise;
|
|
47
47
|
let searchPromise;
|
|
48
|
+
let engine;
|
|
48
49
|
function json(url, expected) {
|
|
49
50
|
assert(/^[a-f0-9]{64}$/.test(expected), "INVALID_DATA", "\u6458\u8981\u683C\u5F0F\u9519\u8BEF");
|
|
50
51
|
const filenameHash = new URL(url).pathname.match(/\.([a-f0-9]{64})\.json$/)?.[1];
|
|
@@ -207,7 +208,11 @@ function createClient({ manifestUrl }) {
|
|
|
207
208
|
"IDENTITY_MISMATCH",
|
|
208
209
|
"\u5185\u5BB9\u8EAB\u4EFD\u4E0D\u5339\u914D"
|
|
209
210
|
);
|
|
210
|
-
return {
|
|
211
|
+
return {
|
|
212
|
+
data: value,
|
|
213
|
+
dataUrl,
|
|
214
|
+
...source.settings ? { settings: source.settings } : {}
|
|
215
|
+
};
|
|
211
216
|
},
|
|
212
217
|
async search(query, { limit = 12, signal } = {}) {
|
|
213
218
|
cancelled(signal);
|
|
@@ -219,13 +224,17 @@ function createClient({ manifestUrl }) {
|
|
|
219
224
|
signal
|
|
220
225
|
);
|
|
221
226
|
cancelled(signal);
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
227
|
+
if (engine?.documents !== documents)
|
|
228
|
+
engine = {
|
|
229
|
+
documents,
|
|
230
|
+
fuse: new Fuse(documents, {
|
|
231
|
+
keys: ["title", "summary", "content", "tags"],
|
|
232
|
+
includeMatches: true,
|
|
233
|
+
threshold: 0.3,
|
|
234
|
+
ignoreLocation: true
|
|
235
|
+
})
|
|
236
|
+
};
|
|
237
|
+
return engine.fuse.search(normalized, { limit }).map(({ item, matches }) => {
|
|
229
238
|
const { content: _content, ...hit } = item;
|
|
230
239
|
const ranges = (matches ?? []).flatMap((match) => {
|
|
231
240
|
if (!match.value || !["title", "summary", "content", "tags"].includes(match.key ?? ""))
|
|
@@ -41,7 +41,7 @@ export interface MarkdownCodec {
|
|
|
41
41
|
*/
|
|
42
42
|
fence?: {
|
|
43
43
|
language: string | readonly string[];
|
|
44
|
-
/** 源码落进元素的字段名,默认 "content"
|
|
44
|
+
/** 源码落进元素的字段名,默认 "content",由领域声明覆盖。 */
|
|
45
45
|
property?: string;
|
|
46
46
|
};
|
|
47
47
|
/**
|
|
@@ -69,7 +69,7 @@ export interface MarkdownCodec {
|
|
|
69
69
|
parent: Descendant | null;
|
|
70
70
|
previousSibling: Descendant | null;
|
|
71
71
|
nextSibling: Descendant | null;
|
|
72
|
-
/**
|
|
72
|
+
/** 按领域声明把块级子元素降级为行内形态,无声明则原样返回。 */
|
|
73
73
|
demote: (child: Descendant) => Descendant;
|
|
74
74
|
}) => Descendant[] | null;
|
|
75
75
|
/** 按目标类型贡献规范化,先于该类型自身 normalize;按 codec 顺序首个非 null 替换生效。 */
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/** 插件中心分类按扩展点划分,顺序即展示顺序;新增面向用户的扩展点时同步扩充。 */
|
|
2
|
+
export declare const PLUGIN_CATEGORIES: readonly [{
|
|
3
|
+
readonly id: "sync";
|
|
4
|
+
readonly label: "同步";
|
|
5
|
+
}, {
|
|
6
|
+
readonly id: "upload";
|
|
7
|
+
readonly label: "资源上传";
|
|
8
|
+
}, {
|
|
9
|
+
readonly id: "editor";
|
|
10
|
+
readonly label: "编辑器";
|
|
11
|
+
}, {
|
|
12
|
+
readonly id: "whiteboard";
|
|
13
|
+
readonly label: "白板";
|
|
14
|
+
}, {
|
|
15
|
+
readonly id: "blog-template";
|
|
16
|
+
readonly label: "博客模板";
|
|
17
|
+
}, {
|
|
18
|
+
readonly id: "ai";
|
|
19
|
+
readonly label: "AI";
|
|
20
|
+
}, {
|
|
21
|
+
readonly id: "voice";
|
|
22
|
+
readonly label: "语音";
|
|
23
|
+
}, {
|
|
24
|
+
readonly id: "page";
|
|
25
|
+
readonly label: "页面";
|
|
26
|
+
}];
|
|
27
|
+
export type PluginCategory = (typeof PLUGIN_CATEGORIES)[number]["id"];
|
|
28
|
+
export declare const PLUGIN_KEYWORD_LIMIT = 5;
|
|
29
|
+
export declare const PLUGIN_KEYWORD_MAX_LENGTH = 20;
|
|
30
|
+
export declare const isPluginCategory: (value: unknown) => value is PluginCategory;
|
|
31
|
+
export interface PluginCatalogFields {
|
|
32
|
+
categories?: readonly PluginCategory[];
|
|
33
|
+
keywords?: readonly string[];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 读取 manifest 中的分类与关键词。
|
|
37
|
+
* strict 用于门户上传,非法值直接报错;客户端用宽松模式静默丢弃,
|
|
38
|
+
* 使老客户端不会因词表新增或上限调整而拒收插件。
|
|
39
|
+
*/
|
|
40
|
+
export declare function readCatalogFields(item: Record<string, unknown>, strict: boolean): PluginCatalogFields;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { assertLocalId } from "./ids";
|
|
2
|
+
import { type PluginCategory } from "./categories";
|
|
2
3
|
export { comparePluginVersions } from "./version";
|
|
4
|
+
export { PLUGIN_CATEGORIES, PLUGIN_KEYWORD_LIMIT, PLUGIN_KEYWORD_MAX_LENGTH, isPluginCategory, type PluginCategory, } from "./categories";
|
|
3
5
|
export declare const PLUGIN_SHARED_MODULES: readonly ["@tau/plugins", "@tau/plugins/whiteboard", "@tau/plugins/sync", "@tau/ui", "react", "react-dom", "react-dom/client", "react/jsx-runtime", "react/jsx-dev-runtime"];
|
|
4
6
|
export interface PluginManifest {
|
|
5
7
|
formatVersion: 1;
|
|
@@ -16,6 +18,10 @@ export interface PluginManifest {
|
|
|
16
18
|
/** 静态编辑器贡献在窗口启动时装配,启停需重启。 */
|
|
17
19
|
editor?: true;
|
|
18
20
|
whiteboard?: true;
|
|
21
|
+
/** 插件中心分类,作者自填,不与实际注册对账。 */
|
|
22
|
+
categories?: readonly PluginCategory[];
|
|
23
|
+
/** 仅参与搜索匹配。 */
|
|
24
|
+
keywords?: readonly string[];
|
|
19
25
|
integrity: Record<string, string>;
|
|
20
26
|
}
|
|
21
27
|
/** 宿主内部传输的已读取产物,不属于作者运行时 API。 */
|
|
@@ -24,6 +30,9 @@ export interface DevelopmentPluginPackage {
|
|
|
24
30
|
code: string;
|
|
25
31
|
css?: string;
|
|
26
32
|
}
|
|
27
|
-
|
|
33
|
+
/** strict 供门户上传使用:分类或关键词不合规时报错,客户端默认静默丢弃。 */
|
|
34
|
+
export declare function validatePluginManifest(value: unknown, options?: {
|
|
35
|
+
strict?: boolean;
|
|
36
|
+
}): PluginManifest;
|
|
28
37
|
/** 静态内容贡献在启动时固定,启停与更新需要重启。 */
|
|
29
38
|
export declare const isContentPlugin: (manifest: Pick<PluginManifest, "editor" | "whiteboard">) => boolean;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export { validatePluginManifest, PLUGIN_SHARED_MODULES } from "./package";
|
|
2
|
-
export declare const SIDEBAR_GROUPS: Readonly<Record<string, string>>;
|
|
3
2
|
import type { DevelopmentPluginPackage } from "./package";
|
|
4
3
|
export declare const PLUGIN_RENDER_VERSION: 1;
|
|
5
4
|
export type { PublishedPluginRender } from "./render-artifact";
|
|
@@ -27,6 +27,15 @@ export interface SiteData {
|
|
|
27
27
|
mimeType: string;
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
|
+
export interface PublishSettings {
|
|
31
|
+
appearance?: {
|
|
32
|
+
image?: {
|
|
33
|
+
borderRadius?: string;
|
|
34
|
+
shadow?: string | boolean;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/** 站点级数据只在清单中出现一次,各内容文件不重复携带。 */
|
|
30
39
|
export interface DataManifest {
|
|
31
40
|
version: 1;
|
|
32
41
|
site: SiteData;
|
|
@@ -35,6 +44,11 @@ export interface DataManifest {
|
|
|
35
44
|
integrity: string;
|
|
36
45
|
};
|
|
37
46
|
items: ManifestItem[];
|
|
47
|
+
settings?: PublishSettings;
|
|
48
|
+
collections?: Collection[];
|
|
49
|
+
cardTagTree?: CardTagTree[];
|
|
50
|
+
/** 键为项目 id。 */
|
|
51
|
+
projectTrees?: Record<string, TreeItem[]>;
|
|
38
52
|
}
|
|
39
53
|
export interface ContentNode {
|
|
40
54
|
[field: string]: unknown;
|
|
@@ -205,20 +219,10 @@ export interface CardTagTree {
|
|
|
205
219
|
export interface PublishedCommon {
|
|
206
220
|
version: 1;
|
|
207
221
|
key: string;
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
cardTagTree?: CardTagTree[];
|
|
211
|
-
contentLinkTargets?: Record<string, ContentRef>;
|
|
222
|
+
/** 本文正文里已发布的站内链接目标,键与 QuestMaterial.citeKey 同一口径;未发布的链接不在其中。 */
|
|
223
|
+
links?: Record<string, ContentRef>;
|
|
212
224
|
pluginRenderers?: import("./render-artifact").PublishedPluginRender[];
|
|
213
225
|
contentStyles?: ResourceRef[];
|
|
214
|
-
settings?: {
|
|
215
|
-
appearance?: {
|
|
216
|
-
image?: {
|
|
217
|
-
borderRadius?: string;
|
|
218
|
-
shadow?: string | boolean;
|
|
219
|
-
};
|
|
220
|
-
};
|
|
221
|
-
};
|
|
222
226
|
}
|
|
223
227
|
export type PublishedData = {
|
|
224
228
|
[K in DataKind]: PublishedCommon & {
|
|
@@ -239,6 +243,8 @@ export type PublishedData = {
|
|
|
239
243
|
export interface DataResult {
|
|
240
244
|
data: PublishedData;
|
|
241
245
|
dataUrl: string;
|
|
246
|
+
/** 清单中的发布设置,由客户端随正文带回。 */
|
|
247
|
+
settings?: PublishSettings;
|
|
242
248
|
}
|
|
243
249
|
export interface SearchDocument extends ContentRef {
|
|
244
250
|
type: "card" | "article" | "doc" | "quest";
|