@sutraspaces/mcp-server 1.0.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 +134 -0
- package/package.json +44 -0
- package/src/client.js +66 -0
- package/src/index.js +59 -0
- package/src/tools/broadcasts.js +102 -0
- package/src/tools/content.js +228 -0
- package/src/tools/coupons.js +75 -0
- package/src/tools/deep.js +181 -0
- package/src/tools/invitations.js +117 -0
- package/src/tools/members.js +144 -0
- package/src/tools/plans.js +131 -0
- package/src/tools/properties.js +181 -0
- package/src/tools/spaces.js +106 -0
- package/src/tools/surveys.js +87 -0
- package/src/utils/extract-text.js +85 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
export function registerPropertyTools(server, client) {
|
|
4
|
+
// --- Member Properties ---
|
|
5
|
+
|
|
6
|
+
server.tool(
|
|
7
|
+
"list_member_properties",
|
|
8
|
+
"List member property definitions for a space. Member properties are custom fields like company, role, or interests.",
|
|
9
|
+
{
|
|
10
|
+
space_id: z.string().describe("Space ID (sp_...)"),
|
|
11
|
+
limit: z.number().optional().describe("Max results (default 25)"),
|
|
12
|
+
cursor: z.string().optional().describe("Pagination cursor"),
|
|
13
|
+
},
|
|
14
|
+
async ({ space_id, limit, cursor }) => {
|
|
15
|
+
const data = await client.get(`/spaces/${space_id}/member_properties`, { limit, cursor });
|
|
16
|
+
return json(data);
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
server.tool(
|
|
21
|
+
"create_member_property",
|
|
22
|
+
"Create a member property definition for a space.",
|
|
23
|
+
{
|
|
24
|
+
space_id: z.string().describe("Space ID (sp_...)"),
|
|
25
|
+
name: z.string().describe("Display name"),
|
|
26
|
+
key: z.string().describe("Machine key (e.g. company, role)"),
|
|
27
|
+
type: z.enum(["text", "select", "multi_select", "number", "date", "url", "phone", "location"]).describe("Property type"),
|
|
28
|
+
options: z.any().optional().describe("For select/multi_select: { values: [{ value, name }] }"),
|
|
29
|
+
visibility: z.array(z.string()).optional().describe("Visibility settings"),
|
|
30
|
+
},
|
|
31
|
+
async ({ space_id, ...body }) => {
|
|
32
|
+
const data = await client.post(`/spaces/${space_id}/member_properties`, body);
|
|
33
|
+
return json(data);
|
|
34
|
+
}
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
server.tool(
|
|
38
|
+
"update_member_property",
|
|
39
|
+
"Update a member property definition.",
|
|
40
|
+
{
|
|
41
|
+
member_property_id: z.string().describe("Member property ID (mprop_...)"),
|
|
42
|
+
name: z.string().optional(),
|
|
43
|
+
type: z.enum(["text", "select", "multi_select", "number", "date", "url", "phone", "location"]).optional(),
|
|
44
|
+
options: z.any().optional(),
|
|
45
|
+
visibility: z.array(z.string()).optional(),
|
|
46
|
+
},
|
|
47
|
+
async ({ member_property_id, ...body }) => {
|
|
48
|
+
const data = await client.patch(`/member_properties/${member_property_id}`, body);
|
|
49
|
+
return json(data);
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
server.tool(
|
|
54
|
+
"delete_member_property",
|
|
55
|
+
"Delete a member property definition.",
|
|
56
|
+
{
|
|
57
|
+
member_property_id: z.string().describe("Member property ID (mprop_...)"),
|
|
58
|
+
},
|
|
59
|
+
async ({ member_property_id }) => {
|
|
60
|
+
const data = await client.delete(`/member_properties/${member_property_id}`);
|
|
61
|
+
return json(data);
|
|
62
|
+
}
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
server.tool(
|
|
66
|
+
"get_member_property_values",
|
|
67
|
+
"Get all property values for a specific member in a space.",
|
|
68
|
+
{
|
|
69
|
+
space_id: z.string().describe("Space ID (sp_...)"),
|
|
70
|
+
member_id: z.string().describe("Member ID (mem_...)"),
|
|
71
|
+
},
|
|
72
|
+
async ({ space_id, member_id }) => {
|
|
73
|
+
const data = await client.get(`/spaces/${space_id}/members/${member_id}/properties`);
|
|
74
|
+
return json(data);
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
server.tool(
|
|
79
|
+
"update_member_property_values",
|
|
80
|
+
"Set property values for a member. Use null to clear a value. Keys can be property keys or mprop_ IDs.",
|
|
81
|
+
{
|
|
82
|
+
space_id: z.string().describe("Space ID (sp_...)"),
|
|
83
|
+
member_id: z.string().describe("Member ID (mem_...)"),
|
|
84
|
+
properties: z.record(z.any()).describe("Object keyed by property key or mprop_ ID, values to set (null to clear)"),
|
|
85
|
+
},
|
|
86
|
+
async ({ space_id, member_id, properties }) => {
|
|
87
|
+
const data = await client.patch(`/spaces/${space_id}/members/${member_id}/properties`, { properties });
|
|
88
|
+
return json(data);
|
|
89
|
+
}
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
// --- Space Properties ---
|
|
93
|
+
|
|
94
|
+
server.tool(
|
|
95
|
+
"list_space_properties",
|
|
96
|
+
"List space property definitions owned by a space. Space properties describe child spaces (e.g. category, date, featured).",
|
|
97
|
+
{
|
|
98
|
+
space_id: z.string().describe("Space ID (sp_...)"),
|
|
99
|
+
limit: z.number().optional().describe("Max results (default 25)"),
|
|
100
|
+
cursor: z.string().optional().describe("Pagination cursor"),
|
|
101
|
+
},
|
|
102
|
+
async ({ space_id, limit, cursor }) => {
|
|
103
|
+
const data = await client.get(`/spaces/${space_id}/space_properties`, { limit, cursor });
|
|
104
|
+
return json(data);
|
|
105
|
+
}
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
server.tool(
|
|
109
|
+
"create_space_property",
|
|
110
|
+
"Create a space property definition for a space.",
|
|
111
|
+
{
|
|
112
|
+
space_id: z.string().describe("Space ID (sp_...)"),
|
|
113
|
+
name: z.string().describe("Display name"),
|
|
114
|
+
key: z.string().describe("Machine key"),
|
|
115
|
+
type: z.enum(["text", "select", "multi_select", "number", "date", "url", "phone", "location"]).describe("Property type"),
|
|
116
|
+
options: z.any().optional().describe("For select/multi_select: { values: [{ value, name }] }"),
|
|
117
|
+
visibility: z.array(z.string()).optional(),
|
|
118
|
+
},
|
|
119
|
+
async ({ space_id, ...body }) => {
|
|
120
|
+
const data = await client.post(`/spaces/${space_id}/space_properties`, body);
|
|
121
|
+
return json(data);
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
server.tool(
|
|
126
|
+
"update_space_property",
|
|
127
|
+
"Update a space property definition.",
|
|
128
|
+
{
|
|
129
|
+
space_property_id: z.string().describe("Space property ID (sprop_...)"),
|
|
130
|
+
name: z.string().optional(),
|
|
131
|
+
type: z.enum(["text", "select", "multi_select", "number", "date", "url", "phone", "location"]).optional(),
|
|
132
|
+
options: z.any().optional(),
|
|
133
|
+
visibility: z.array(z.string()).optional(),
|
|
134
|
+
},
|
|
135
|
+
async ({ space_property_id, ...body }) => {
|
|
136
|
+
const data = await client.patch(`/space_properties/${space_property_id}`, body);
|
|
137
|
+
return json(data);
|
|
138
|
+
}
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
server.tool(
|
|
142
|
+
"delete_space_property",
|
|
143
|
+
"Delete a space property definition.",
|
|
144
|
+
{
|
|
145
|
+
space_property_id: z.string().describe("Space property ID (sprop_...)"),
|
|
146
|
+
},
|
|
147
|
+
async ({ space_property_id }) => {
|
|
148
|
+
const data = await client.delete(`/space_properties/${space_property_id}`);
|
|
149
|
+
return json(data);
|
|
150
|
+
}
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
server.tool(
|
|
154
|
+
"get_space_property_values",
|
|
155
|
+
"Get all property values for a space (typically a child space with properties defined by its parent).",
|
|
156
|
+
{
|
|
157
|
+
space_id: z.string().describe("Space ID (sp_...)"),
|
|
158
|
+
},
|
|
159
|
+
async ({ space_id }) => {
|
|
160
|
+
const data = await client.get(`/spaces/${space_id}/properties`);
|
|
161
|
+
return json(data);
|
|
162
|
+
}
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
server.tool(
|
|
166
|
+
"update_space_property_values",
|
|
167
|
+
"Set property values on a space. Use null to clear a value. Keys can be property keys or sprop_ IDs.",
|
|
168
|
+
{
|
|
169
|
+
space_id: z.string().describe("Space ID (sp_...)"),
|
|
170
|
+
properties: z.record(z.any()).describe("Object keyed by property key or sprop_ ID, values to set (null to clear)"),
|
|
171
|
+
},
|
|
172
|
+
async ({ space_id, properties }) => {
|
|
173
|
+
const data = await client.patch(`/spaces/${space_id}/properties`, { properties });
|
|
174
|
+
return json(data);
|
|
175
|
+
}
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function json(data) {
|
|
180
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
181
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
export function registerSpaceTools(server, client) {
|
|
4
|
+
server.tool(
|
|
5
|
+
"list_spaces",
|
|
6
|
+
"List all spaces the API token can access. Returns space IDs (sp_...), names, types, and states. Start here to discover available spaces.",
|
|
7
|
+
{
|
|
8
|
+
limit: z.number().optional().describe("Max results per page (default 25, max 100)"),
|
|
9
|
+
cursor: z.string().optional().describe("Pagination cursor from a previous response"),
|
|
10
|
+
},
|
|
11
|
+
async ({ limit, cursor }) => {
|
|
12
|
+
const data = await client.get("/spaces", { limit, cursor });
|
|
13
|
+
return json(data);
|
|
14
|
+
}
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
server.tool(
|
|
18
|
+
"get_space",
|
|
19
|
+
"Get details for a single space by its ID (sp_...).",
|
|
20
|
+
{
|
|
21
|
+
space_id: z.string().describe("Space ID (sp_...)"),
|
|
22
|
+
},
|
|
23
|
+
async ({ space_id }) => {
|
|
24
|
+
const data = await client.get(`/spaces/${space_id}`);
|
|
25
|
+
return json(data);
|
|
26
|
+
}
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
server.tool(
|
|
30
|
+
"list_child_spaces",
|
|
31
|
+
"List direct child spaces of a parent space. Use this to explore the space hierarchy.",
|
|
32
|
+
{
|
|
33
|
+
space_id: z.string().describe("Parent space ID (sp_...)"),
|
|
34
|
+
limit: z.number().optional().describe("Max results (default 25)"),
|
|
35
|
+
cursor: z.string().optional().describe("Pagination cursor"),
|
|
36
|
+
},
|
|
37
|
+
async ({ space_id, limit, cursor }) => {
|
|
38
|
+
const data = await client.get(`/spaces/${space_id}/children`, { limit, cursor });
|
|
39
|
+
return json(data);
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
server.tool(
|
|
44
|
+
"create_space",
|
|
45
|
+
"Create a new space. Omit parent_id for a top-level space, or include it to create a child space.",
|
|
46
|
+
{
|
|
47
|
+
name: z.string().describe("Space name"),
|
|
48
|
+
description: z.string().optional().describe("Space description"),
|
|
49
|
+
type: z.string().optional().describe("Space type (default: content)"),
|
|
50
|
+
privacy: z.string().optional().describe("Privacy level (default: open)"),
|
|
51
|
+
pod_type: z.enum(["standard", "readonly"]).optional().describe("Pod type (default: standard)"),
|
|
52
|
+
parent_id: z.string().optional().describe("Parent space ID (sp_...) to create as a child"),
|
|
53
|
+
},
|
|
54
|
+
async ({ name, description, type, privacy, pod_type, parent_id }) => {
|
|
55
|
+
const body = { name, description, type, privacy, pod_type, parent_id };
|
|
56
|
+
const data = await client.post("/spaces", body);
|
|
57
|
+
return json(data);
|
|
58
|
+
}
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
server.tool(
|
|
62
|
+
"update_space",
|
|
63
|
+
"Update an existing space's name, description, type, privacy, or state.",
|
|
64
|
+
{
|
|
65
|
+
space_id: z.string().describe("Space ID (sp_...)"),
|
|
66
|
+
name: z.string().optional().describe("New name"),
|
|
67
|
+
description: z.string().optional().describe("New description"),
|
|
68
|
+
type: z.string().optional().describe("New type"),
|
|
69
|
+
privacy: z.string().optional().describe("New privacy level"),
|
|
70
|
+
state: z.enum(["active", "archived"]).optional().describe("Set active or archived"),
|
|
71
|
+
},
|
|
72
|
+
async ({ space_id, ...updates }) => {
|
|
73
|
+
const data = await client.patch(`/spaces/${space_id}`, updates);
|
|
74
|
+
return json(data);
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
server.tool(
|
|
79
|
+
"delete_space",
|
|
80
|
+
"Delete a space. This archives the space and queues cleanup.",
|
|
81
|
+
{
|
|
82
|
+
space_id: z.string().describe("Space ID (sp_...)"),
|
|
83
|
+
},
|
|
84
|
+
async ({ space_id }) => {
|
|
85
|
+
const data = await client.delete(`/spaces/${space_id}`);
|
|
86
|
+
return json(data);
|
|
87
|
+
}
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
server.tool(
|
|
91
|
+
"reorder_child_spaces",
|
|
92
|
+
"Reorder child spaces within a parent by providing the desired order of space IDs.",
|
|
93
|
+
{
|
|
94
|
+
space_id: z.string().describe("Parent space ID (sp_...)"),
|
|
95
|
+
space_ids: z.array(z.string()).describe("Ordered array of child space IDs (sp_...)"),
|
|
96
|
+
},
|
|
97
|
+
async ({ space_id, space_ids }) => {
|
|
98
|
+
const data = await client.patch(`/spaces/${space_id}/children/reorder`, { space_ids });
|
|
99
|
+
return json(data);
|
|
100
|
+
}
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function json(data) {
|
|
105
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
106
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
export function registerSurveyTools(server, client) {
|
|
4
|
+
server.tool(
|
|
5
|
+
"list_surveys",
|
|
6
|
+
"List surveys in a space.",
|
|
7
|
+
{
|
|
8
|
+
space_id: z.string().describe("Space ID (sp_...)"),
|
|
9
|
+
limit: z.number().optional().describe("Max results (default 25)"),
|
|
10
|
+
cursor: z.string().optional().describe("Pagination cursor"),
|
|
11
|
+
},
|
|
12
|
+
async ({ space_id, limit, cursor }) => {
|
|
13
|
+
const data = await client.get(`/spaces/${space_id}/surveys`, { limit, cursor });
|
|
14
|
+
return json(data);
|
|
15
|
+
}
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
server.tool(
|
|
19
|
+
"get_survey",
|
|
20
|
+
"Get a single survey with its questions.",
|
|
21
|
+
{
|
|
22
|
+
survey_id: z.string().describe("Survey ID (surv_...)"),
|
|
23
|
+
},
|
|
24
|
+
async ({ survey_id }) => {
|
|
25
|
+
const data = await client.get(`/surveys/${survey_id}`);
|
|
26
|
+
return json(data);
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
server.tool(
|
|
31
|
+
"get_survey_submissions",
|
|
32
|
+
"Get submissions (responses) for a survey.",
|
|
33
|
+
{
|
|
34
|
+
survey_id: z.string().describe("Survey ID (surv_...)"),
|
|
35
|
+
limit: z.number().optional().describe("Max results (default 25)"),
|
|
36
|
+
cursor: z.string().optional().describe("Pagination cursor"),
|
|
37
|
+
},
|
|
38
|
+
async ({ survey_id, limit, cursor }) => {
|
|
39
|
+
const data = await client.get(`/surveys/${survey_id}/submissions`, { limit, cursor });
|
|
40
|
+
return json(data);
|
|
41
|
+
}
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
server.tool(
|
|
45
|
+
"create_survey",
|
|
46
|
+
"Create a survey in a space.",
|
|
47
|
+
{
|
|
48
|
+
space_id: z.string().describe("Space ID (sp_...)"),
|
|
49
|
+
title: z.string().optional().describe("Survey title"),
|
|
50
|
+
questions: z.array(z.any()).optional().describe("Array of question objects"),
|
|
51
|
+
},
|
|
52
|
+
async ({ space_id, ...body }) => {
|
|
53
|
+
const data = await client.post(`/spaces/${space_id}/surveys`, body);
|
|
54
|
+
return json(data);
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
server.tool(
|
|
59
|
+
"update_survey",
|
|
60
|
+
"Update a survey.",
|
|
61
|
+
{
|
|
62
|
+
survey_id: z.string().describe("Survey ID (surv_...)"),
|
|
63
|
+
title: z.string().optional(),
|
|
64
|
+
questions: z.array(z.any()).optional(),
|
|
65
|
+
},
|
|
66
|
+
async ({ survey_id, ...body }) => {
|
|
67
|
+
const data = await client.patch(`/surveys/${survey_id}`, body);
|
|
68
|
+
return json(data);
|
|
69
|
+
}
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
server.tool(
|
|
73
|
+
"delete_survey",
|
|
74
|
+
"Delete a survey.",
|
|
75
|
+
{
|
|
76
|
+
survey_id: z.string().describe("Survey ID (surv_...)"),
|
|
77
|
+
},
|
|
78
|
+
async ({ survey_id }) => {
|
|
79
|
+
const data = await client.delete(`/surveys/${survey_id}`);
|
|
80
|
+
return json(data);
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function json(data) {
|
|
86
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
87
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
export function extractFromTiptap(node) {
|
|
2
|
+
if (!node) return "";
|
|
3
|
+
if (typeof node === "string") return node;
|
|
4
|
+
if (Array.isArray(node)) {
|
|
5
|
+
return node.map(extractFromTiptap).filter(Boolean).join("\n");
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
if (node.type === "text") return node.text || "";
|
|
9
|
+
|
|
10
|
+
const children = node.content
|
|
11
|
+
? node.content.map(extractFromTiptap).filter(Boolean)
|
|
12
|
+
: [];
|
|
13
|
+
|
|
14
|
+
switch (node.type) {
|
|
15
|
+
case "doc":
|
|
16
|
+
return children.join("\n\n");
|
|
17
|
+
case "paragraph":
|
|
18
|
+
return children.join("");
|
|
19
|
+
case "heading": {
|
|
20
|
+
const prefix = "#".repeat(node.attrs?.level || 1);
|
|
21
|
+
return `${prefix} ${children.join("")}`;
|
|
22
|
+
}
|
|
23
|
+
case "bulletList":
|
|
24
|
+
case "bullet_list":
|
|
25
|
+
return children.map((c) => `- ${c}`).join("\n");
|
|
26
|
+
case "orderedList":
|
|
27
|
+
case "ordered_list":
|
|
28
|
+
return children.map((c, i) => `${i + 1}. ${c}`).join("\n");
|
|
29
|
+
case "listItem":
|
|
30
|
+
case "list_item":
|
|
31
|
+
return children.join("\n");
|
|
32
|
+
case "blockquote":
|
|
33
|
+
return children.map((c) => `> ${c}`).join("\n");
|
|
34
|
+
case "codeBlock":
|
|
35
|
+
case "code_block":
|
|
36
|
+
return `\`\`\`\n${children.join("\n")}\n\`\`\``;
|
|
37
|
+
case "hardBreak":
|
|
38
|
+
case "hard_break":
|
|
39
|
+
return "\n";
|
|
40
|
+
case "horizontalRule":
|
|
41
|
+
case "horizontal_rule":
|
|
42
|
+
return "---";
|
|
43
|
+
case "image":
|
|
44
|
+
return `[Image: ${node.attrs?.alt || node.attrs?.src || ""}]`;
|
|
45
|
+
case "mention":
|
|
46
|
+
return `@${node.attrs?.label || node.attrs?.id || "someone"}`;
|
|
47
|
+
case "sutra_embed":
|
|
48
|
+
case "sutra_video":
|
|
49
|
+
case "sutra_audio":
|
|
50
|
+
case "sutra_file":
|
|
51
|
+
return `[${node.type}: ${node.attrs?.title || node.attrs?.name || node.attrs?.url || ""}]`;
|
|
52
|
+
default:
|
|
53
|
+
return children.join("\n");
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function extractFromHtml(html) {
|
|
58
|
+
if (!html || typeof html !== "string") return "";
|
|
59
|
+
return html
|
|
60
|
+
.replace(/<\/(p|div|h[1-6]|li|br|tr)>/gi, "\n")
|
|
61
|
+
.replace(/<br\s*\/?>/gi, "\n")
|
|
62
|
+
.replace(/<[^>]+>/g, "")
|
|
63
|
+
.replace(/&/g, "&")
|
|
64
|
+
.replace(/</g, "<")
|
|
65
|
+
.replace(/>/g, ">")
|
|
66
|
+
.replace(/"/g, '"')
|
|
67
|
+
.replace(/'/g, "'")
|
|
68
|
+
.replace(/ /g, " ")
|
|
69
|
+
.replace(/\n{3,}/g, "\n\n")
|
|
70
|
+
.trim();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function extractText(content) {
|
|
74
|
+
if (!content) return "";
|
|
75
|
+
if (typeof content === "string") {
|
|
76
|
+
if (/<[a-z][\s\S]*>/i.test(content)) return extractFromHtml(content);
|
|
77
|
+
try {
|
|
78
|
+
return extractFromTiptap(JSON.parse(content));
|
|
79
|
+
} catch {
|
|
80
|
+
return content.trim();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (typeof content === "object") return extractFromTiptap(content);
|
|
84
|
+
return String(content);
|
|
85
|
+
}
|