mindoodb-app-sdk 0.0.70 → 0.0.72
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 +106 -1
- package/dist/{chunk-P7SOHCEQ.js → chunk-UFP7O4OJ.js} +746 -36
- package/dist/index.d.ts +3 -55
- package/dist/index.js +61 -1
- package/dist/testing/index.d.ts +136 -2
- package/dist/testing/index.js +422 -18
- package/dist/{types-7oOzrSr5.d.ts → types-DN-E0X34.d.ts} +542 -5
- package/package.json +1 -1
|
@@ -66,6 +66,296 @@ function assertValidMindooDBCreateIds(input, methodName = "createDocument") {
|
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
// src/inspection.ts
|
|
70
|
+
var MINDOODB_INSPECT_DOCUMENT = "mindoo.inspect.document@1";
|
|
71
|
+
var MINDOODB_INSPECT_SPREADSHEET = "mindoo.inspect.spreadsheet@1";
|
|
72
|
+
var MINDOODB_INSPECT_SLIDES = "mindoo.inspect.slides@1";
|
|
73
|
+
var MINDOODB_APP_INSPECTION_FIELD = "inspection";
|
|
74
|
+
var MINDOODB_APP_INSPECTION_SUMMARY_MAX_BYTES = 8 * 1024;
|
|
75
|
+
var MINDOODB_APP_INSPECTION_MAX_BYTES = 256 * 1024;
|
|
76
|
+
var MINDOODB_APP_ISSUES_MAX = 100;
|
|
77
|
+
var MindooDBAppEmbedValidationError = class extends Error {
|
|
78
|
+
constructor(issues) {
|
|
79
|
+
const first = issues.find((issue) => issue.severity === "error") ?? issues[0];
|
|
80
|
+
super(first ? first.message : "The document was not saved.");
|
|
81
|
+
this.issues = issues;
|
|
82
|
+
this.name = "MindooDBAppEmbedValidationError";
|
|
83
|
+
}
|
|
84
|
+
issues;
|
|
85
|
+
};
|
|
86
|
+
var SUPPORTS_CAPABILITY = /^[a-z][a-z0-9-]{0,31}$/;
|
|
87
|
+
function mindooDBAppComponentSupports(supports, requirement) {
|
|
88
|
+
const wanted = requirement.trim();
|
|
89
|
+
return (supports ?? []).some((entry) => entry === wanted || !wanted.includes(":") && entry.startsWith(`${wanted}:`));
|
|
90
|
+
}
|
|
91
|
+
function mindooDBAppInspectContracts(supports) {
|
|
92
|
+
return (supports ?? []).filter((entry) => entry.startsWith("inspect:")).map((entry) => entry.slice("inspect:".length));
|
|
93
|
+
}
|
|
94
|
+
function isPlainObject(value) {
|
|
95
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
96
|
+
}
|
|
97
|
+
function normalizeMindooDBAppInspectAnchor(raw) {
|
|
98
|
+
if (!isPlainObject(raw)) {
|
|
99
|
+
return void 0;
|
|
100
|
+
}
|
|
101
|
+
if (raw.kind === "heading" && typeof raw.id === "string" && raw.id && raw.id.length <= 200) {
|
|
102
|
+
return { kind: "heading", id: raw.id };
|
|
103
|
+
}
|
|
104
|
+
if (raw.kind === "cell" && typeof raw.ref === "string" && raw.ref && raw.ref.length <= 200) {
|
|
105
|
+
return { kind: "cell", ref: raw.ref };
|
|
106
|
+
}
|
|
107
|
+
if (raw.kind === "slide" && Number.isInteger(raw.index) && raw.index >= 0) {
|
|
108
|
+
return { kind: "slide", index: raw.index };
|
|
109
|
+
}
|
|
110
|
+
return void 0;
|
|
111
|
+
}
|
|
112
|
+
function normalizeMindooDBAppIssues(raw) {
|
|
113
|
+
if (!Array.isArray(raw)) {
|
|
114
|
+
return [];
|
|
115
|
+
}
|
|
116
|
+
const issues = [];
|
|
117
|
+
for (const entry of raw) {
|
|
118
|
+
if (issues.length >= MINDOODB_APP_ISSUES_MAX) {
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
if (!isPlainObject(entry) || typeof entry.message !== "string" || !entry.message.trim()) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
const severity = entry.severity === "warning" || entry.severity === "info" ? entry.severity : entry.severity === "error" ? "error" : null;
|
|
125
|
+
if (!severity) {
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
const anchor = normalizeMindooDBAppInspectAnchor(entry.anchor);
|
|
129
|
+
const code = typeof entry.code === "string" && entry.code.trim() ? entry.code.trim().slice(0, 64) : void 0;
|
|
130
|
+
issues.push({
|
|
131
|
+
severity,
|
|
132
|
+
message: entry.message.trim().slice(0, 500),
|
|
133
|
+
...anchor ? { anchor } : {},
|
|
134
|
+
...code ? { code } : {}
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
return issues;
|
|
138
|
+
}
|
|
139
|
+
function normalizeMindooDBAppInspectRequest(raw) {
|
|
140
|
+
const input = isPlainObject(raw) ? raw : {};
|
|
141
|
+
const strings = (value, max) => Array.isArray(value) ? [...new Set(value.filter((entry) => typeof entry === "string" && !!entry && entry.length <= 200))].slice(0, max) : [];
|
|
142
|
+
const include = strings(input.include, 16);
|
|
143
|
+
const cells = strings(input.cells, 200);
|
|
144
|
+
const maxTextLength = Number(input.maxTextLength);
|
|
145
|
+
return {
|
|
146
|
+
...typeof input.contract === "string" && input.contract ? { contract: input.contract.slice(0, 200) } : {},
|
|
147
|
+
...include.length ? { include } : {},
|
|
148
|
+
...cells.length ? { cells } : {},
|
|
149
|
+
...Number.isFinite(maxTextLength) && maxTextLength > 0 ? { maxTextLength: Math.min(Math.floor(maxTextLength), 5e4) } : {}
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
function normalizeMindooDBAppInspection(raw) {
|
|
153
|
+
let json;
|
|
154
|
+
try {
|
|
155
|
+
json = JSON.stringify(raw);
|
|
156
|
+
} catch {
|
|
157
|
+
throw new Error("An inspection must be plain JSON.");
|
|
158
|
+
}
|
|
159
|
+
if (!json || json.length > MINDOODB_APP_INSPECTION_MAX_BYTES) {
|
|
160
|
+
throw new Error(`An inspection must not be larger than ${MINDOODB_APP_INSPECTION_MAX_BYTES / 1024} KiB.`);
|
|
161
|
+
}
|
|
162
|
+
const value = JSON.parse(json);
|
|
163
|
+
if (!isPlainObject(value) || typeof value.contract !== "string" || !value.contract) {
|
|
164
|
+
throw new Error("An inspection must be an object with a contract.");
|
|
165
|
+
}
|
|
166
|
+
return value;
|
|
167
|
+
}
|
|
168
|
+
var SUMMARY_TEXT_STEPS = [500, 200, 0];
|
|
169
|
+
var SUMMARY_LIST_STEPS = [50, 20, 5, 0];
|
|
170
|
+
function shorten(value, textMax, listMax, marks) {
|
|
171
|
+
if (typeof value === "string") {
|
|
172
|
+
if (value.length <= textMax) return value;
|
|
173
|
+
marks.truncated = true;
|
|
174
|
+
return value.slice(0, textMax);
|
|
175
|
+
}
|
|
176
|
+
if (Array.isArray(value)) {
|
|
177
|
+
if (value.length > listMax) marks.truncated = true;
|
|
178
|
+
return value.slice(0, listMax).map((entry) => shorten(entry, Math.min(textMax || 80, 80), listMax, marks));
|
|
179
|
+
}
|
|
180
|
+
if (isPlainObject(value)) {
|
|
181
|
+
return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, shorten(entry, textMax, listMax, marks)]));
|
|
182
|
+
}
|
|
183
|
+
return value;
|
|
184
|
+
}
|
|
185
|
+
function summarizeMindooDBAppInspection(inspection, maxBytes = MINDOODB_APP_INSPECTION_SUMMARY_MAX_BYTES) {
|
|
186
|
+
const { cells: _cells, ...rest } = inspection;
|
|
187
|
+
const base = JSON.parse(JSON.stringify(rest));
|
|
188
|
+
for (const textMax of SUMMARY_TEXT_STEPS) {
|
|
189
|
+
for (const listMax of SUMMARY_LIST_STEPS) {
|
|
190
|
+
const marks = { truncated: false };
|
|
191
|
+
const next = shorten(base, textMax, listMax, marks);
|
|
192
|
+
if (textMax === 0 && typeof next.text === "string") delete next.text;
|
|
193
|
+
next.contract = inspection.contract;
|
|
194
|
+
if (typeof inspection.subject === "string") next.subject = inspection.subject.slice(0, 200);
|
|
195
|
+
if (marks.truncated || inspection.truncated) next.truncated = true;
|
|
196
|
+
if (JSON.stringify(next).length <= maxBytes) {
|
|
197
|
+
return next;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return { contract: inspection.contract, truncated: true };
|
|
202
|
+
}
|
|
203
|
+
function mindooDBAppInspectionSummaryValue(inspection) {
|
|
204
|
+
return MindooDBAppValue.atomic(JSON.stringify(summarizeMindooDBAppInspection(inspection)));
|
|
205
|
+
}
|
|
206
|
+
function readMindooDBAppInspectionSummary(root) {
|
|
207
|
+
let value = root?.[MINDOODB_APP_INSPECTION_FIELD];
|
|
208
|
+
if (typeof value === "string") {
|
|
209
|
+
try {
|
|
210
|
+
value = JSON.parse(value);
|
|
211
|
+
} catch {
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return isPlainObject(value) && typeof value.contract === "string" ? value : null;
|
|
216
|
+
}
|
|
217
|
+
function outcomeIssues(rule, outcome) {
|
|
218
|
+
if (!outcome) return [];
|
|
219
|
+
if (typeof outcome === "string") {
|
|
220
|
+
return [{ severity: rule.severity ?? "error", message: outcome, code: rule.code }];
|
|
221
|
+
}
|
|
222
|
+
return (Array.isArray(outcome) ? outcome : [outcome]).map((issue) => ({ code: rule.code, ...issue }));
|
|
223
|
+
}
|
|
224
|
+
function defineDocumentRules(definition) {
|
|
225
|
+
const request = normalizeMindooDBAppInspectRequest(definition);
|
|
226
|
+
function check(inspection) {
|
|
227
|
+
if (!inspection || definition.contract && inspection.contract !== definition.contract) {
|
|
228
|
+
return [];
|
|
229
|
+
}
|
|
230
|
+
const issues = definition.rules.flatMap((rule) => {
|
|
231
|
+
try {
|
|
232
|
+
return outcomeIssues(rule, rule.check(inspection));
|
|
233
|
+
} catch (error) {
|
|
234
|
+
return [
|
|
235
|
+
{
|
|
236
|
+
severity: "warning",
|
|
237
|
+
code: rule.code,
|
|
238
|
+
message: `Check "${rule.code}" failed: ${error instanceof Error ? error.message : String(error)}`
|
|
239
|
+
}
|
|
240
|
+
];
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
return normalizeMindooDBAppIssues(issues);
|
|
244
|
+
}
|
|
245
|
+
const rules = {
|
|
246
|
+
request,
|
|
247
|
+
check,
|
|
248
|
+
checkRoot: (root) => check(readMindooDBAppInspectionSummary(root)),
|
|
249
|
+
beforeSave: ({ inspection }) => ({ issues: check(inspection) }),
|
|
250
|
+
attach: (embed) => embed.onBeforeSave(rules.beforeSave, { inspect: request })
|
|
251
|
+
};
|
|
252
|
+
return rules;
|
|
253
|
+
}
|
|
254
|
+
function plural(count, one, many) {
|
|
255
|
+
return `${count} ${count === 1 ? one : many}`;
|
|
256
|
+
}
|
|
257
|
+
var mindooDBAppInspectRules = {
|
|
258
|
+
/** Documents: no placeholder or MERGEFIELD left open. */
|
|
259
|
+
noOpenPlaceholders(severity = "error", message) {
|
|
260
|
+
return {
|
|
261
|
+
code: "open-placeholders",
|
|
262
|
+
severity,
|
|
263
|
+
check: (inspection) => {
|
|
264
|
+
const names = (inspection.placeholders ?? []).map((entry) => entry.name);
|
|
265
|
+
if (!names.length) return null;
|
|
266
|
+
return message?.(names) ?? `${plural(names.length, "placeholder is", "placeholders are")} not filled in: ${names.slice(0, 5).join(", ")}${names.length > 5 ? ", \u2026" : ""}`;
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
},
|
|
270
|
+
/** Documents: every comment resolved. */
|
|
271
|
+
noOpenComments(severity = "warning", message) {
|
|
272
|
+
return {
|
|
273
|
+
code: "open-comments",
|
|
274
|
+
severity,
|
|
275
|
+
check: (inspection) => inspection.openComments > 0 ? message?.(inspection.openComments) ?? `${plural(inspection.openComments, "comment is", "comments are")} not resolved.` : null
|
|
276
|
+
};
|
|
277
|
+
},
|
|
278
|
+
/** Documents: every tracked change accepted or rejected. */
|
|
279
|
+
noOpenTrackedChanges(severity = "warning", message) {
|
|
280
|
+
return {
|
|
281
|
+
code: "open-tracked-changes",
|
|
282
|
+
severity,
|
|
283
|
+
check: (inspection) => inspection.openTrackedChanges > 0 ? message?.(inspection.openTrackedChanges) ?? `${plural(inspection.openTrackedChanges, "tracked change is", "tracked changes are")} not accepted or rejected.` : null
|
|
284
|
+
};
|
|
285
|
+
},
|
|
286
|
+
/** Spreadsheets: no formula evaluates to an error; one issue per cell. */
|
|
287
|
+
noFormulaErrors(severity = "error") {
|
|
288
|
+
return {
|
|
289
|
+
code: "formula-errors",
|
|
290
|
+
severity,
|
|
291
|
+
check: (inspection) => (inspection.formulaErrors ?? []).map((entry) => ({
|
|
292
|
+
severity,
|
|
293
|
+
message: `${entry.ref}: ${entry.error}`,
|
|
294
|
+
anchor: { kind: "cell", ref: entry.ref }
|
|
295
|
+
}))
|
|
296
|
+
};
|
|
297
|
+
},
|
|
298
|
+
/** Presentations: no layout placeholder left empty; one issue per slide. */
|
|
299
|
+
noEmptySlidePlaceholders(severity = "warning") {
|
|
300
|
+
return {
|
|
301
|
+
code: "empty-placeholders",
|
|
302
|
+
severity,
|
|
303
|
+
check: (inspection) => {
|
|
304
|
+
const bySlide = /* @__PURE__ */ new Map();
|
|
305
|
+
for (const entry of inspection.emptyPlaceholders ?? []) {
|
|
306
|
+
bySlide.set(entry.slide, [...bySlide.get(entry.slide) ?? [], entry.placeholder]);
|
|
307
|
+
}
|
|
308
|
+
return [...bySlide.entries()].map(([slide, names]) => ({
|
|
309
|
+
severity,
|
|
310
|
+
message: `Slide ${slide + 1}: empty ${names.join(", ")}`,
|
|
311
|
+
anchor: { kind: "slide", index: slide }
|
|
312
|
+
}));
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
};
|
|
317
|
+
function isMindooDBAppSupportsEntry(entry, contractPattern) {
|
|
318
|
+
const [capability, contract, ...rest] = entry.split(":");
|
|
319
|
+
if (rest.length || !capability || !SUPPORTS_CAPABILITY.test(capability)) {
|
|
320
|
+
return false;
|
|
321
|
+
}
|
|
322
|
+
return contract === void 0 || contractPattern.test(contract);
|
|
323
|
+
}
|
|
324
|
+
async function performMindooDBAppEmbeddingSave(steps) {
|
|
325
|
+
const validation = await steps.validate();
|
|
326
|
+
if (!validation.ok) {
|
|
327
|
+
if (validation.issues.length && steps.showIssues) {
|
|
328
|
+
try {
|
|
329
|
+
await steps.showIssues(validation.issues);
|
|
330
|
+
} catch (error) {
|
|
331
|
+
console.warn("[mindoodb-app-sdk] Showing issues failed.", error);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
throw new MindooDBAppEmbedValidationError(validation.issues);
|
|
335
|
+
}
|
|
336
|
+
let inspection = null;
|
|
337
|
+
if (steps.provider) {
|
|
338
|
+
try {
|
|
339
|
+
inspection = mindooDBAppInspectionSummaryValue(normalizeMindooDBAppInspection(await steps.provider({})));
|
|
340
|
+
} catch (error) {
|
|
341
|
+
console.warn("[mindoodb-app-sdk] Could not summarize the document.", error);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
await steps.flush({ inspection, issues: validation.issues });
|
|
345
|
+
await steps.saved();
|
|
346
|
+
return validation;
|
|
347
|
+
}
|
|
348
|
+
async function resolveMindooDBAppEmbedValidation(issues, interactive, confirm) {
|
|
349
|
+
if (issues.some((issue) => issue.severity === "error")) {
|
|
350
|
+
return { ok: false, issues };
|
|
351
|
+
}
|
|
352
|
+
const warnings = issues.filter((issue) => issue.severity === "warning");
|
|
353
|
+
if (!warnings.length || !interactive) {
|
|
354
|
+
return { ok: true, issues };
|
|
355
|
+
}
|
|
356
|
+
return { ok: await confirm(warnings) === true, issues };
|
|
357
|
+
}
|
|
358
|
+
|
|
69
359
|
// src/appDefinition.ts
|
|
70
360
|
var MINDOODB_APP_DEFINITION_FORMAT = "mindoodb.haven.app";
|
|
71
361
|
var MINDOODB_APP_DEFINITION_VERSION = 1;
|
|
@@ -86,8 +376,17 @@ var MINDOODB_APP_DEFINITION_REGISTRATION_PERMISSIONS = ["proposeapps"];
|
|
|
86
376
|
var MINDOODB_APP_LISTING_SUMMARY_MAX = 300;
|
|
87
377
|
var MINDOODB_APP_LISTING_DESCRIPTION_MAX = 4e3;
|
|
88
378
|
var MINDOODB_APP_LISTING_MAX_SCREENSHOTS = 8;
|
|
379
|
+
var MINDOODB_APP_AGENT_SUMMARY_MAX = 400;
|
|
380
|
+
var MINDOODB_APP_AGENT_CAPABILITIES_MAX = 8;
|
|
381
|
+
var MINDOODB_APP_AGENT_CAPABILITY_TITLE_MAX = 80;
|
|
382
|
+
var MINDOODB_APP_AGENT_CAPABILITY_TOOLS_MAX = 64;
|
|
383
|
+
var MINDOODB_APP_AGENT_LIST_MAX = 8;
|
|
384
|
+
var MINDOODB_APP_AGENT_EXAMPLE_MAX = 200;
|
|
385
|
+
var MINDOODB_APP_AGENT_LIMIT_MAX = 300;
|
|
386
|
+
var MINDOODB_APP_AGENT_GUIDE_MAX_BYTES = 8 * 1024;
|
|
387
|
+
var MINDOODB_APP_AGENT_TOOL_NAME_PATTERN = /^[a-z][a-z0-9_]{0,47}$/;
|
|
89
388
|
var LOGICAL_DATABASE_ID_PATTERN = /^[a-z0-9][a-z0-9._-]*$/i;
|
|
90
|
-
function
|
|
389
|
+
function isPlainObject2(value) {
|
|
91
390
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
92
391
|
}
|
|
93
392
|
function readOptionalString(raw, key, errors) {
|
|
@@ -118,7 +417,7 @@ function readStringRecord(raw, key, errors) {
|
|
|
118
417
|
if (value === void 0 || value === null) {
|
|
119
418
|
return void 0;
|
|
120
419
|
}
|
|
121
|
-
if (!
|
|
420
|
+
if (!isPlainObject2(value)) {
|
|
122
421
|
errors.push(`App definition ${key} must be an object of string values.`);
|
|
123
422
|
return void 0;
|
|
124
423
|
}
|
|
@@ -184,7 +483,7 @@ function readDatabases(value, errors) {
|
|
|
184
483
|
const result = [];
|
|
185
484
|
const seen = /* @__PURE__ */ new Set();
|
|
186
485
|
value.forEach((entry, index) => {
|
|
187
|
-
if (!
|
|
486
|
+
if (!isPlainObject2(entry)) {
|
|
188
487
|
errors.push(`App definition database #${index} must be an object.`);
|
|
189
488
|
return;
|
|
190
489
|
}
|
|
@@ -237,7 +536,7 @@ function readLocalizedText(value, label, maxLength, errors) {
|
|
|
237
536
|
}
|
|
238
537
|
return trimmed || void 0;
|
|
239
538
|
}
|
|
240
|
-
if (!
|
|
539
|
+
if (!isPlainObject2(value)) {
|
|
241
540
|
errors.push(`${label} must be a string or an object of per-locale strings.`);
|
|
242
541
|
return void 0;
|
|
243
542
|
}
|
|
@@ -284,7 +583,7 @@ function readAccepts(value, errors) {
|
|
|
284
583
|
const ids = /* @__PURE__ */ new Set();
|
|
285
584
|
value.forEach((entry, index) => {
|
|
286
585
|
const label = `App definition accepts[${index}]`;
|
|
287
|
-
if (!
|
|
586
|
+
if (!isPlainObject2(entry)) {
|
|
288
587
|
errors.push(`${label} must be an object.`);
|
|
289
588
|
return;
|
|
290
589
|
}
|
|
@@ -345,7 +644,7 @@ var COMPONENT_FIELD_PATTERN = /^[A-Za-z_][A-Za-z0-9_]{0,63}$/;
|
|
|
345
644
|
var COMPONENT_INTENTS = ["create", "edit", "view"];
|
|
346
645
|
var COMPONENT_CREATE_MAX_BYTES = 16 * 1024;
|
|
347
646
|
function readComponentFieldMatch(value, label, errors) {
|
|
348
|
-
if (!
|
|
647
|
+
if (!isPlainObject2(value)) {
|
|
349
648
|
errors.push(`${label} must be an object of field values.`);
|
|
350
649
|
return void 0;
|
|
351
650
|
}
|
|
@@ -368,6 +667,28 @@ var MINDOODB_APP_COMPONENT_CONTRACT_PATTERN = /^[a-z][a-z0-9-]*(\.[a-z][a-z0-9-]
|
|
|
368
667
|
var COMPONENT_CONTRACTS_MAX = 8;
|
|
369
668
|
var COMPONENT_REFERENCES_MAX = 8;
|
|
370
669
|
var COMPONENT_REFERENCE_SHOW_MAX = 8;
|
|
670
|
+
var COMPONENT_SUPPORTS_MAX = 16;
|
|
671
|
+
function readComponentSupports(value, label, errors) {
|
|
672
|
+
if (value === void 0) {
|
|
673
|
+
return void 0;
|
|
674
|
+
}
|
|
675
|
+
if (!Array.isArray(value) || value.length > COMPONENT_SUPPORTS_MAX) {
|
|
676
|
+
errors.push(`${label} must be an array of at most ${COMPONENT_SUPPORTS_MAX} entries.`);
|
|
677
|
+
return void 0;
|
|
678
|
+
}
|
|
679
|
+
const result = [];
|
|
680
|
+
for (const entry of value) {
|
|
681
|
+
const text = typeof entry === "string" ? entry.trim() : "";
|
|
682
|
+
if (!isMindooDBAppSupportsEntry(text, MINDOODB_APP_COMPONENT_CONTRACT_PATTERN)) {
|
|
683
|
+
errors.push(`${label} entries must look like "validate" or "inspect:mindoo.inspect.document@1", received ${JSON.stringify(entry)}.`);
|
|
684
|
+
return void 0;
|
|
685
|
+
}
|
|
686
|
+
if (!result.includes(text)) {
|
|
687
|
+
result.push(text);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
return result.length ? result : void 0;
|
|
691
|
+
}
|
|
371
692
|
function readComponentContracts(value, label, errors) {
|
|
372
693
|
if (value === void 0) {
|
|
373
694
|
return void 0;
|
|
@@ -378,14 +699,14 @@ function readComponentContracts(value, label, errors) {
|
|
|
378
699
|
}
|
|
379
700
|
const result = [];
|
|
380
701
|
for (const [index, entry] of value.entries()) {
|
|
381
|
-
const contract =
|
|
702
|
+
const contract = isPlainObject2(entry) && typeof entry.contract === "string" ? entry.contract.trim() : "";
|
|
382
703
|
if (!MINDOODB_APP_COMPONENT_CONTRACT_PATTERN.test(contract)) {
|
|
383
704
|
errors.push(`${label}[${index}].contract must look like "mindoo.contacts.company@1".`);
|
|
384
705
|
return void 0;
|
|
385
706
|
}
|
|
386
707
|
let fields;
|
|
387
|
-
if (
|
|
388
|
-
if (!
|
|
708
|
+
if (isPlainObject2(entry) && entry.fields !== void 0) {
|
|
709
|
+
if (!isPlainObject2(entry.fields)) {
|
|
389
710
|
errors.push(`${label}[${index}].fields must map contract fields to document fields.`);
|
|
390
711
|
return void 0;
|
|
391
712
|
}
|
|
@@ -414,7 +735,7 @@ function readComponentReferences(value, label, rootMatch, errors) {
|
|
|
414
735
|
const fieldsSeen = /* @__PURE__ */ new Set();
|
|
415
736
|
for (const [index, entry] of value.entries()) {
|
|
416
737
|
const at = `${label}[${index}]`;
|
|
417
|
-
if (!
|
|
738
|
+
if (!isPlainObject2(entry)) {
|
|
418
739
|
errors.push(`${at} must be an object.`);
|
|
419
740
|
return void 0;
|
|
420
741
|
}
|
|
@@ -463,7 +784,7 @@ function readComponents(value, errors) {
|
|
|
463
784
|
value.forEach((entry, index) => {
|
|
464
785
|
const label = `App definition components[${index}]`;
|
|
465
786
|
const errorCount = errors.length;
|
|
466
|
-
if (!
|
|
787
|
+
if (!isPlainObject2(entry)) {
|
|
467
788
|
errors.push(`${label} must be an object.`);
|
|
468
789
|
return;
|
|
469
790
|
}
|
|
@@ -510,7 +831,7 @@ function readComponents(value, errors) {
|
|
|
510
831
|
}
|
|
511
832
|
let create;
|
|
512
833
|
if (entry.create !== void 0) {
|
|
513
|
-
if (!
|
|
834
|
+
if (!isPlainObject2(entry.create)) {
|
|
514
835
|
errors.push(`${label}.create must be an object of initial field values.`);
|
|
515
836
|
return;
|
|
516
837
|
}
|
|
@@ -539,7 +860,7 @@ function readComponents(value, errors) {
|
|
|
539
860
|
}
|
|
540
861
|
let children;
|
|
541
862
|
if (entry.children !== void 0) {
|
|
542
|
-
if (!
|
|
863
|
+
if (!isPlainObject2(entry.children)) {
|
|
543
864
|
errors.push(`${label}.children must be an object.`);
|
|
544
865
|
return;
|
|
545
866
|
}
|
|
@@ -568,6 +889,7 @@ function readComponents(value, errors) {
|
|
|
568
889
|
}
|
|
569
890
|
const provides = readComponentContracts(entry.provides, `${label}.provides`, errors);
|
|
570
891
|
const references = readComponentReferences(entry.references, `${label}.references`, match, errors);
|
|
892
|
+
const supports = readComponentSupports(entry.supports, `${label}.supports`, errors);
|
|
571
893
|
if (errors.length !== errorCount) {
|
|
572
894
|
return;
|
|
573
895
|
}
|
|
@@ -582,7 +904,8 @@ function readComponents(value, errors) {
|
|
|
582
904
|
...children ? { children } : {},
|
|
583
905
|
...category ? { category } : {},
|
|
584
906
|
...provides ? { provides } : {},
|
|
585
|
-
...references ? { references } : {}
|
|
907
|
+
...references ? { references } : {},
|
|
908
|
+
...supports ? { supports } : {}
|
|
586
909
|
});
|
|
587
910
|
});
|
|
588
911
|
return result.length ? result : void 0;
|
|
@@ -622,7 +945,7 @@ function readListing(value, errors) {
|
|
|
622
945
|
if (value === void 0 || value === null) {
|
|
623
946
|
return void 0;
|
|
624
947
|
}
|
|
625
|
-
if (!
|
|
948
|
+
if (!isPlainObject2(value)) {
|
|
626
949
|
errors.push("App definition listing must be an object.");
|
|
627
950
|
return void 0;
|
|
628
951
|
}
|
|
@@ -662,7 +985,7 @@ function readListing(value, errors) {
|
|
|
662
985
|
value.screenshots.forEach((entry, index) => {
|
|
663
986
|
const label = `App definition listing.screenshots[${index}]`;
|
|
664
987
|
const raw = typeof entry === "string" ? { file: entry } : entry;
|
|
665
|
-
if (!
|
|
988
|
+
if (!isPlainObject2(raw)) {
|
|
666
989
|
errors.push(`${label} must be a path or an object with a file.`);
|
|
667
990
|
return;
|
|
668
991
|
}
|
|
@@ -677,7 +1000,7 @@ function readListing(value, errors) {
|
|
|
677
1000
|
}
|
|
678
1001
|
}
|
|
679
1002
|
if (value.publisher !== void 0 && value.publisher !== null) {
|
|
680
|
-
const publisher =
|
|
1003
|
+
const publisher = isPlainObject2(value.publisher) ? value.publisher : {};
|
|
681
1004
|
const name = typeof publisher.name === "string" ? publisher.name.trim() : "";
|
|
682
1005
|
if (!name) {
|
|
683
1006
|
errors.push("App definition listing.publisher must be an object with a non-empty name.");
|
|
@@ -692,6 +1015,163 @@ function readListing(value, errors) {
|
|
|
692
1015
|
}
|
|
693
1016
|
return Object.keys(listing).length ? listing : void 0;
|
|
694
1017
|
}
|
|
1018
|
+
var AGENT_CAPABILITY_ID_PATTERN = /^[a-z0-9][a-z0-9_-]{0,47}$/;
|
|
1019
|
+
var AGENT_LOCALE_PATTERN = /^[a-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$/;
|
|
1020
|
+
var AGENT_GUIDE_PATH_PATTERN = /^[A-Za-z0-9_][A-Za-z0-9_.\/-]{0,199}\.md$/;
|
|
1021
|
+
function readAgentLocaleText(value, label, maxLength, errors) {
|
|
1022
|
+
if (!isPlainObject2(value)) {
|
|
1023
|
+
errors.push(`${label} must be an object of per-locale strings with an "en" entry.`);
|
|
1024
|
+
return void 0;
|
|
1025
|
+
}
|
|
1026
|
+
const result = {};
|
|
1027
|
+
for (const [locale, text] of Object.entries(value)) {
|
|
1028
|
+
if (!AGENT_LOCALE_PATTERN.test(locale)) {
|
|
1029
|
+
errors.push(`${label} has an invalid locale ${JSON.stringify(locale)}.`);
|
|
1030
|
+
return void 0;
|
|
1031
|
+
}
|
|
1032
|
+
const trimmed = typeof text === "string" ? text.trim() : "";
|
|
1033
|
+
if (!trimmed) {
|
|
1034
|
+
errors.push(`${label}.${locale} must be a non-empty string.`);
|
|
1035
|
+
return void 0;
|
|
1036
|
+
}
|
|
1037
|
+
if (trimmed.length > maxLength) {
|
|
1038
|
+
errors.push(`${label}.${locale} must not be longer than ${maxLength} characters.`);
|
|
1039
|
+
return void 0;
|
|
1040
|
+
}
|
|
1041
|
+
result[locale] = trimmed;
|
|
1042
|
+
}
|
|
1043
|
+
if (!result.en) {
|
|
1044
|
+
errors.push(`${label} must include an "en" entry as the fallback for other locales.`);
|
|
1045
|
+
return void 0;
|
|
1046
|
+
}
|
|
1047
|
+
return result;
|
|
1048
|
+
}
|
|
1049
|
+
function readAgentLocaleList(value, label, maxLength, errors) {
|
|
1050
|
+
if (value === void 0) {
|
|
1051
|
+
return void 0;
|
|
1052
|
+
}
|
|
1053
|
+
if (!isPlainObject2(value)) {
|
|
1054
|
+
errors.push(`${label} must be an object of per-locale string arrays with an "en" entry.`);
|
|
1055
|
+
return void 0;
|
|
1056
|
+
}
|
|
1057
|
+
const result = {};
|
|
1058
|
+
for (const [locale, entries] of Object.entries(value)) {
|
|
1059
|
+
if (!AGENT_LOCALE_PATTERN.test(locale)) {
|
|
1060
|
+
errors.push(`${label} has an invalid locale ${JSON.stringify(locale)}.`);
|
|
1061
|
+
return void 0;
|
|
1062
|
+
}
|
|
1063
|
+
if (!Array.isArray(entries) || !entries.length || entries.length > MINDOODB_APP_AGENT_LIST_MAX) {
|
|
1064
|
+
errors.push(`${label}.${locale} must be an array of 1-${MINDOODB_APP_AGENT_LIST_MAX} strings.`);
|
|
1065
|
+
return void 0;
|
|
1066
|
+
}
|
|
1067
|
+
const list = [];
|
|
1068
|
+
for (const entry of entries) {
|
|
1069
|
+
const trimmed = typeof entry === "string" ? entry.trim() : "";
|
|
1070
|
+
if (!trimmed || trimmed.length > maxLength) {
|
|
1071
|
+
errors.push(`${label}.${locale} must only hold non-empty strings of at most ${maxLength} characters.`);
|
|
1072
|
+
return void 0;
|
|
1073
|
+
}
|
|
1074
|
+
list.push(trimmed);
|
|
1075
|
+
}
|
|
1076
|
+
result[locale] = list;
|
|
1077
|
+
}
|
|
1078
|
+
if (!result.en) {
|
|
1079
|
+
errors.push(`${label} must include an "en" entry as the fallback for other locales.`);
|
|
1080
|
+
return void 0;
|
|
1081
|
+
}
|
|
1082
|
+
return result;
|
|
1083
|
+
}
|
|
1084
|
+
function readAgentCapabilities(value, errors) {
|
|
1085
|
+
const label = "App definition agent.capabilities";
|
|
1086
|
+
if (!Array.isArray(value) || !value.length || value.length > MINDOODB_APP_AGENT_CAPABILITIES_MAX) {
|
|
1087
|
+
errors.push(`${label} must be an array of 1-${MINDOODB_APP_AGENT_CAPABILITIES_MAX} capabilities.`);
|
|
1088
|
+
return void 0;
|
|
1089
|
+
}
|
|
1090
|
+
const result = [];
|
|
1091
|
+
const ids = /* @__PURE__ */ new Set();
|
|
1092
|
+
for (const [index, entry] of value.entries()) {
|
|
1093
|
+
const at = `${label}[${index}]`;
|
|
1094
|
+
if (!isPlainObject2(entry)) {
|
|
1095
|
+
errors.push(`${at} must be an object.`);
|
|
1096
|
+
return void 0;
|
|
1097
|
+
}
|
|
1098
|
+
const id = typeof entry.id === "string" ? entry.id.trim() : "";
|
|
1099
|
+
if (!AGENT_CAPABILITY_ID_PATTERN.test(id)) {
|
|
1100
|
+
errors.push(`${at}.id must be 1-48 lowercase letters, digits, "-" or "_", received ${JSON.stringify(entry.id)}.`);
|
|
1101
|
+
return void 0;
|
|
1102
|
+
}
|
|
1103
|
+
if (ids.has(id)) {
|
|
1104
|
+
errors.push(`${at}.id "${id}" is used twice.`);
|
|
1105
|
+
return void 0;
|
|
1106
|
+
}
|
|
1107
|
+
ids.add(id);
|
|
1108
|
+
const title = readAgentLocaleText(entry.title, `${at}.title`, MINDOODB_APP_AGENT_CAPABILITY_TITLE_MAX, errors);
|
|
1109
|
+
if (!title) {
|
|
1110
|
+
return void 0;
|
|
1111
|
+
}
|
|
1112
|
+
if (!Array.isArray(entry.tools) || !entry.tools.length || entry.tools.length > MINDOODB_APP_AGENT_CAPABILITY_TOOLS_MAX) {
|
|
1113
|
+
errors.push(`${at}.tools must be an array of 1-${MINDOODB_APP_AGENT_CAPABILITY_TOOLS_MAX} tool names.`);
|
|
1114
|
+
return void 0;
|
|
1115
|
+
}
|
|
1116
|
+
const tools = [];
|
|
1117
|
+
for (const tool of entry.tools) {
|
|
1118
|
+
const name = typeof tool === "string" ? tool.trim() : "";
|
|
1119
|
+
if (!MINDOODB_APP_AGENT_TOOL_NAME_PATTERN.test(name) || /^haven(?:_|$)/.test(name)) {
|
|
1120
|
+
errors.push(
|
|
1121
|
+
`${at}.tools contains ${JSON.stringify(tool)}; name the app's own tools as registered, without prefix and never "haven_*".`
|
|
1122
|
+
);
|
|
1123
|
+
return void 0;
|
|
1124
|
+
}
|
|
1125
|
+
if (!tools.includes(name)) {
|
|
1126
|
+
tools.push(name);
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
result.push({ id, title, tools });
|
|
1130
|
+
}
|
|
1131
|
+
return result;
|
|
1132
|
+
}
|
|
1133
|
+
function readAgentProfile(value, errors) {
|
|
1134
|
+
if (value === void 0 || value === null) {
|
|
1135
|
+
return void 0;
|
|
1136
|
+
}
|
|
1137
|
+
if (!isPlainObject2(value)) {
|
|
1138
|
+
errors.push("App definition agent must be an object.");
|
|
1139
|
+
return void 0;
|
|
1140
|
+
}
|
|
1141
|
+
const errorCount = errors.length;
|
|
1142
|
+
const summary = readAgentLocaleText(value.summary, "App definition agent.summary", MINDOODB_APP_AGENT_SUMMARY_MAX, errors);
|
|
1143
|
+
const capabilities = readAgentCapabilities(value.capabilities, errors);
|
|
1144
|
+
const examples = readAgentLocaleList(value.examples, "App definition agent.examples", MINDOODB_APP_AGENT_EXAMPLE_MAX, errors);
|
|
1145
|
+
const limits = readAgentLocaleList(value.limits, "App definition agent.limits", MINDOODB_APP_AGENT_LIMIT_MAX, errors);
|
|
1146
|
+
let guide;
|
|
1147
|
+
if (value.guide !== void 0) {
|
|
1148
|
+
guide = readAgentLocaleText(value.guide, "App definition agent.guide", 200, errors);
|
|
1149
|
+
for (const [locale, path] of Object.entries(guide ?? {})) {
|
|
1150
|
+
if (!AGENT_GUIDE_PATH_PATTERN.test(path) || path.split("/").some((part) => part === "." || part === "..")) {
|
|
1151
|
+
errors.push(
|
|
1152
|
+
`App definition agent.guide.${locale} must be a relative path to a .md file next to the manifest, e.g. "agent/agent.${locale}.md".`
|
|
1153
|
+
);
|
|
1154
|
+
guide = void 0;
|
|
1155
|
+
break;
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
if (errors.length !== errorCount || !summary || !capabilities) {
|
|
1160
|
+
return void 0;
|
|
1161
|
+
}
|
|
1162
|
+
return {
|
|
1163
|
+
summary,
|
|
1164
|
+
capabilities,
|
|
1165
|
+
...examples ? { examples } : {},
|
|
1166
|
+
...limits ? { limits } : {},
|
|
1167
|
+
...guide ? { guide } : {}
|
|
1168
|
+
};
|
|
1169
|
+
}
|
|
1170
|
+
function validateMindooDBAppAgentProfile(value) {
|
|
1171
|
+
const errors = [];
|
|
1172
|
+
const agent = readAgentProfile(value, errors);
|
|
1173
|
+
return { agent: errors.length ? void 0 : agent, errors };
|
|
1174
|
+
}
|
|
695
1175
|
function resolveMindooDBAppLocalizedText(text, locale) {
|
|
696
1176
|
if (text === void 0) {
|
|
697
1177
|
return "";
|
|
@@ -717,7 +1197,7 @@ function resolveMindooDBAppListingAssetUrl(path, originUrl) {
|
|
|
717
1197
|
}
|
|
718
1198
|
function validateMindooDBAppDefinition(raw) {
|
|
719
1199
|
const errors = [];
|
|
720
|
-
if (!
|
|
1200
|
+
if (!isPlainObject2(raw)) {
|
|
721
1201
|
return { definition: null, errors: ["App definition must be a JSON object."] };
|
|
722
1202
|
}
|
|
723
1203
|
if (raw.format !== MINDOODB_APP_DEFINITION_FORMAT) {
|
|
@@ -772,6 +1252,7 @@ function validateMindooDBAppDefinition(raw) {
|
|
|
772
1252
|
const listing = readListing(raw.listing, errors);
|
|
773
1253
|
const accepts = readAccepts(raw.accepts, errors);
|
|
774
1254
|
const components = readComponents(raw.components, errors);
|
|
1255
|
+
const agent = readAgentProfile(raw.agent, errors);
|
|
775
1256
|
const agentToolPrefix = readOptionalString(raw, "agentToolPrefix", errors);
|
|
776
1257
|
if (agentToolPrefix !== void 0 && (!/^[a-z][a-z0-9_]{0,15}$/.test(agentToolPrefix) || agentToolPrefix.endsWith("_") || /^haven(?:_|$)/.test(agentToolPrefix))) {
|
|
777
1258
|
errors.push(
|
|
@@ -813,7 +1294,8 @@ function validateMindooDBAppDefinition(raw) {
|
|
|
813
1294
|
databases,
|
|
814
1295
|
accepts,
|
|
815
1296
|
components,
|
|
816
|
-
listing
|
|
1297
|
+
listing,
|
|
1298
|
+
agent
|
|
817
1299
|
},
|
|
818
1300
|
errors: []
|
|
819
1301
|
};
|
|
@@ -1229,29 +1711,29 @@ function bindDragSource(element, options, start, follow) {
|
|
|
1229
1711
|
}
|
|
1230
1712
|
|
|
1231
1713
|
// src/client/agentInput.ts
|
|
1232
|
-
function
|
|
1714
|
+
function isPlainObject3(value) {
|
|
1233
1715
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1234
1716
|
}
|
|
1235
1717
|
function isPlaceholder(value) {
|
|
1236
1718
|
if (value === null || value === void 0) return true;
|
|
1237
1719
|
if (typeof value === "string") return value.trim() === "";
|
|
1238
1720
|
if (Array.isArray(value)) return value.length === 0;
|
|
1239
|
-
if (
|
|
1721
|
+
if (isPlainObject3(value)) return Object.keys(value).length === 0;
|
|
1240
1722
|
return false;
|
|
1241
1723
|
}
|
|
1242
1724
|
function normalizeValue(value, schema) {
|
|
1243
|
-
if (!
|
|
1725
|
+
if (!isPlainObject3(schema)) return value;
|
|
1244
1726
|
if (Array.isArray(value)) {
|
|
1245
1727
|
const items = schema.items;
|
|
1246
|
-
return
|
|
1728
|
+
return isPlainObject3(items) ? value.map((item) => normalizeValue(item, items)) : value;
|
|
1247
1729
|
}
|
|
1248
|
-
if (
|
|
1730
|
+
if (isPlainObject3(value) && isPlainObject3(schema.properties)) {
|
|
1249
1731
|
return normalizeObject(value, schema);
|
|
1250
1732
|
}
|
|
1251
1733
|
return value;
|
|
1252
1734
|
}
|
|
1253
1735
|
function normalizeObject(input, schema) {
|
|
1254
|
-
const properties =
|
|
1736
|
+
const properties = isPlainObject3(schema.properties) ? schema.properties : {};
|
|
1255
1737
|
const required = new Set(Array.isArray(schema.required) ? schema.required.filter((key) => typeof key === "string") : []);
|
|
1256
1738
|
const result = {};
|
|
1257
1739
|
for (const [key, raw] of Object.entries(input)) {
|
|
@@ -1266,7 +1748,7 @@ function normalizeObject(input, schema) {
|
|
|
1266
1748
|
return result;
|
|
1267
1749
|
}
|
|
1268
1750
|
function normalizeAgentToolInput(input, schema) {
|
|
1269
|
-
return
|
|
1751
|
+
return isPlainObject3(input) ? normalizeObject(input, schema) : input;
|
|
1270
1752
|
}
|
|
1271
1753
|
|
|
1272
1754
|
// src/client/agentTools.ts
|
|
@@ -1483,6 +1965,15 @@ import { parseMindooDBFormulaBooleanExpression } from "mindoodb-view-language";
|
|
|
1483
1965
|
function isEmbedEventMessage(message) {
|
|
1484
1966
|
return message.kind === "embed-event";
|
|
1485
1967
|
}
|
|
1968
|
+
function isEmbedRequestMessage(message) {
|
|
1969
|
+
return message.kind === "embed-request";
|
|
1970
|
+
}
|
|
1971
|
+
function isMethodNotFound(error) {
|
|
1972
|
+
return error instanceof Error && error.name === "method-not-found";
|
|
1973
|
+
}
|
|
1974
|
+
function errorMessage(error) {
|
|
1975
|
+
return error instanceof Error ? error.message : String(error);
|
|
1976
|
+
}
|
|
1486
1977
|
function isEmbeddingRequestMessage(message) {
|
|
1487
1978
|
return message.kind === "embedding-request";
|
|
1488
1979
|
}
|
|
@@ -1549,13 +2040,14 @@ function createComponentFrame(container, url, allow) {
|
|
|
1549
2040
|
return frame;
|
|
1550
2041
|
}
|
|
1551
2042
|
var MindooDBAppEmbedImpl = class {
|
|
1552
|
-
constructor(rpc, embedId, componentKey, databaseId, docId, frame, container) {
|
|
2043
|
+
constructor(rpc, embedId, componentKey, databaseId, docId, frame, container, supports = []) {
|
|
1553
2044
|
this.rpc = rpc;
|
|
1554
2045
|
this.embedId = embedId;
|
|
1555
2046
|
this.componentKey = componentKey;
|
|
1556
2047
|
this.databaseId = databaseId;
|
|
1557
2048
|
this.docId = docId;
|
|
1558
2049
|
this.frame = frame;
|
|
2050
|
+
this.supports = supports;
|
|
1559
2051
|
this.closed = new Promise((resolve) => {
|
|
1560
2052
|
this.resolveClosed = resolve;
|
|
1561
2053
|
});
|
|
@@ -1572,6 +2064,7 @@ var MindooDBAppEmbedImpl = class {
|
|
|
1572
2064
|
databaseId;
|
|
1573
2065
|
docId;
|
|
1574
2066
|
frame;
|
|
2067
|
+
supports;
|
|
1575
2068
|
closed;
|
|
1576
2069
|
resolveClosed;
|
|
1577
2070
|
closedEvent = null;
|
|
@@ -1581,6 +2074,8 @@ var MindooDBAppEmbedImpl = class {
|
|
|
1581
2074
|
tracker = null;
|
|
1582
2075
|
toolsState = null;
|
|
1583
2076
|
toolsListeners = /* @__PURE__ */ new Set();
|
|
2077
|
+
beforeSaveHandler = null;
|
|
2078
|
+
savedListeners = /* @__PURE__ */ new Set();
|
|
1584
2079
|
get placement() {
|
|
1585
2080
|
return this.frame ? "frame" : "overlay";
|
|
1586
2081
|
}
|
|
@@ -1663,6 +2158,88 @@ var MindooDBAppEmbedImpl = class {
|
|
|
1663
2158
|
const stopClosed = this.onClosed(() => finish(null));
|
|
1664
2159
|
});
|
|
1665
2160
|
}
|
|
2161
|
+
async inspect(request) {
|
|
2162
|
+
const result = await this.rpc.call("embeds.inspect", {
|
|
2163
|
+
embedId: this.embedId,
|
|
2164
|
+
request: normalizeMindooDBAppInspectRequest(request)
|
|
2165
|
+
});
|
|
2166
|
+
return normalizeMindooDBAppInspection(result);
|
|
2167
|
+
}
|
|
2168
|
+
onBeforeSave(handler, options) {
|
|
2169
|
+
this.beforeSaveHandler = handler;
|
|
2170
|
+
this.announceBeforeSave(true, options?.inspect);
|
|
2171
|
+
return () => {
|
|
2172
|
+
if (this.beforeSaveHandler === handler) {
|
|
2173
|
+
this.beforeSaveHandler = null;
|
|
2174
|
+
this.announceBeforeSave(false);
|
|
2175
|
+
}
|
|
2176
|
+
};
|
|
2177
|
+
}
|
|
2178
|
+
/** Haven only asks hosts that said they check, and fetches the inspection they want. */
|
|
2179
|
+
announceBeforeSave(enabled, inspect) {
|
|
2180
|
+
if (this.closedEvent) {
|
|
2181
|
+
return;
|
|
2182
|
+
}
|
|
2183
|
+
void this.rpc.call("embeds.setBeforeSave", {
|
|
2184
|
+
embedId: this.embedId,
|
|
2185
|
+
enabled,
|
|
2186
|
+
...enabled ? { inspect: normalizeMindooDBAppInspectRequest(inspect) } : {}
|
|
2187
|
+
}).catch((error) => {
|
|
2188
|
+
if (!isMethodNotFound(error)) {
|
|
2189
|
+
console.warn("[mindoodb-app-sdk] Could not register the save check.", error);
|
|
2190
|
+
}
|
|
2191
|
+
});
|
|
2192
|
+
}
|
|
2193
|
+
/** Haven asks before the component saves: run the handler, never longer than Haven waits. */
|
|
2194
|
+
async answerBeforeSave(params) {
|
|
2195
|
+
const handler = this.beforeSaveHandler;
|
|
2196
|
+
if (!handler || this.closedEvent) {
|
|
2197
|
+
return { issues: [] };
|
|
2198
|
+
}
|
|
2199
|
+
const result = await handler({
|
|
2200
|
+
embedId: this.embedId,
|
|
2201
|
+
inspection: params?.inspection ?? null,
|
|
2202
|
+
root: params?.root ?? null
|
|
2203
|
+
});
|
|
2204
|
+
return { issues: normalizeMindooDBAppIssues(result?.issues) };
|
|
2205
|
+
}
|
|
2206
|
+
onAfterSave(listener) {
|
|
2207
|
+
this.savedListeners.add(listener);
|
|
2208
|
+
return () => {
|
|
2209
|
+
this.savedListeners.delete(listener);
|
|
2210
|
+
};
|
|
2211
|
+
}
|
|
2212
|
+
/** The component reported that it saved. */
|
|
2213
|
+
notifySaved() {
|
|
2214
|
+
if (this.closedEvent) {
|
|
2215
|
+
return;
|
|
2216
|
+
}
|
|
2217
|
+
const event = { embedId: this.embedId };
|
|
2218
|
+
this.savedListeners.forEach((listener) => {
|
|
2219
|
+
try {
|
|
2220
|
+
listener(event);
|
|
2221
|
+
} catch (error) {
|
|
2222
|
+
console.error("MindooDB embed saved listener failed.", error);
|
|
2223
|
+
}
|
|
2224
|
+
});
|
|
2225
|
+
}
|
|
2226
|
+
async showIssues(issues) {
|
|
2227
|
+
await this.rpc.call("embeds.showIssues", { embedId: this.embedId, issues: normalizeMindooDBAppIssues(issues) });
|
|
2228
|
+
}
|
|
2229
|
+
async reveal(anchor) {
|
|
2230
|
+
const normalized = normalizeMindooDBAppInspectAnchor(anchor);
|
|
2231
|
+
if (!normalized) {
|
|
2232
|
+
throw new Error("Invalid anchor.");
|
|
2233
|
+
}
|
|
2234
|
+
await this.rpc.call("embeds.reveal", { embedId: this.embedId, anchor: normalized });
|
|
2235
|
+
}
|
|
2236
|
+
async callTool(name, input) {
|
|
2237
|
+
return await this.rpc.call("embeds.callTool", {
|
|
2238
|
+
embedId: this.embedId,
|
|
2239
|
+
name: String(name),
|
|
2240
|
+
input: input === void 0 ? {} : JSON.parse(JSON.stringify(input))
|
|
2241
|
+
});
|
|
2242
|
+
}
|
|
1666
2243
|
async setRect(rect) {
|
|
1667
2244
|
if (this.closedEvent) {
|
|
1668
2245
|
return;
|
|
@@ -1717,6 +2294,8 @@ var MindooDBAppEmbedImpl = class {
|
|
|
1717
2294
|
});
|
|
1718
2295
|
this.listeners.clear();
|
|
1719
2296
|
this.dirtyListeners.clear();
|
|
2297
|
+
this.savedListeners.clear();
|
|
2298
|
+
this.beforeSaveHandler = null;
|
|
1720
2299
|
this.toolsState = null;
|
|
1721
2300
|
this.toolsListeners.forEach((listener) => {
|
|
1722
2301
|
try {
|
|
@@ -1736,6 +2315,10 @@ var MindooDBAppEmbedsClient = class {
|
|
|
1736
2315
|
void this.answerRequest(message);
|
|
1737
2316
|
return;
|
|
1738
2317
|
}
|
|
2318
|
+
if (isEmbedRequestMessage(message)) {
|
|
2319
|
+
void this.answerEmbedRequest(message);
|
|
2320
|
+
return;
|
|
2321
|
+
}
|
|
1739
2322
|
if (!isEmbedEventMessage(message)) {
|
|
1740
2323
|
return;
|
|
1741
2324
|
}
|
|
@@ -1759,6 +2342,10 @@ var MindooDBAppEmbedsClient = class {
|
|
|
1759
2342
|
}
|
|
1760
2343
|
return;
|
|
1761
2344
|
}
|
|
2345
|
+
if (message.event?.type === "saved") {
|
|
2346
|
+
this.open.get(message.event.embedId)?.notifySaved();
|
|
2347
|
+
return;
|
|
2348
|
+
}
|
|
1762
2349
|
if (message.event?.type !== "closed") {
|
|
1763
2350
|
return;
|
|
1764
2351
|
}
|
|
@@ -1796,7 +2383,8 @@ var MindooDBAppEmbedsClient = class {
|
|
|
1796
2383
|
input.databaseId,
|
|
1797
2384
|
input.docId,
|
|
1798
2385
|
frame,
|
|
1799
|
-
container
|
|
2386
|
+
container,
|
|
2387
|
+
Array.isArray(response.supports) ? response.supports.filter((entry) => typeof entry === "string") : []
|
|
1800
2388
|
);
|
|
1801
2389
|
const earlyDirty = this.earlyDirty.get(embed.embedId);
|
|
1802
2390
|
if (earlyDirty !== void 0) {
|
|
@@ -1872,7 +2460,45 @@ var MindooDBAppEmbedsClient = class {
|
|
|
1872
2460
|
this.saveHandler = null;
|
|
1873
2461
|
}
|
|
1874
2462
|
};
|
|
1875
|
-
}
|
|
2463
|
+
},
|
|
2464
|
+
provideInspection: (provider) => {
|
|
2465
|
+
this.inspectionProvider = provider;
|
|
2466
|
+
return () => {
|
|
2467
|
+
if (this.inspectionProvider === provider) {
|
|
2468
|
+
this.inspectionProvider = null;
|
|
2469
|
+
}
|
|
2470
|
+
};
|
|
2471
|
+
},
|
|
2472
|
+
onShowIssues: (handler) => {
|
|
2473
|
+
this.showIssuesHandler = handler;
|
|
2474
|
+
return () => {
|
|
2475
|
+
if (this.showIssuesHandler === handler) {
|
|
2476
|
+
this.showIssuesHandler = null;
|
|
2477
|
+
}
|
|
2478
|
+
};
|
|
2479
|
+
},
|
|
2480
|
+
onReveal: (handler) => {
|
|
2481
|
+
this.revealHandler = handler;
|
|
2482
|
+
return () => {
|
|
2483
|
+
if (this.revealHandler === handler) {
|
|
2484
|
+
this.revealHandler = null;
|
|
2485
|
+
}
|
|
2486
|
+
};
|
|
2487
|
+
},
|
|
2488
|
+
validate: async (options) => await this.validate(options),
|
|
2489
|
+
save: async (flush, options) => await performMindooDBAppEmbeddingSave({
|
|
2490
|
+
validate: () => this.validate(options),
|
|
2491
|
+
provider: this.inspectionProvider,
|
|
2492
|
+
showIssues: this.showIssuesHandler,
|
|
2493
|
+
flush,
|
|
2494
|
+
// Only news for the host: a lost message must not fail a save that happened.
|
|
2495
|
+
saved: () => this.rpc.call("embedding.saved", {}).then(
|
|
2496
|
+
() => {
|
|
2497
|
+
},
|
|
2498
|
+
() => {
|
|
2499
|
+
}
|
|
2500
|
+
)
|
|
2501
|
+
})
|
|
1876
2502
|
};
|
|
1877
2503
|
}
|
|
1878
2504
|
rpc;
|
|
@@ -1887,18 +2513,53 @@ var MindooDBAppEmbedsClient = class {
|
|
|
1887
2513
|
stopListening;
|
|
1888
2514
|
/** This app as a component: what to do when its host asks it to save. */
|
|
1889
2515
|
saveHandler = null;
|
|
1890
|
-
|
|
2516
|
+
inspectionProvider = null;
|
|
2517
|
+
showIssuesHandler = null;
|
|
2518
|
+
revealHandler = null;
|
|
2519
|
+
/** `embedding.validate`; ok when Haven cannot check (not embedded, older Haven). */
|
|
2520
|
+
async validate(options) {
|
|
2521
|
+
try {
|
|
2522
|
+
const result = await this.rpc.call("embedding.validate", {
|
|
2523
|
+
interactive: options?.interactive !== false
|
|
2524
|
+
});
|
|
2525
|
+
return {
|
|
2526
|
+
ok: result?.ok !== false,
|
|
2527
|
+
issues: normalizeMindooDBAppIssues(result?.issues),
|
|
2528
|
+
...result?.timedOut ? { timedOut: true } : {}
|
|
2529
|
+
};
|
|
2530
|
+
} catch (error) {
|
|
2531
|
+
if (isMethodNotFound(error) || error instanceof Error && error.name === "unsupported") {
|
|
2532
|
+
return { ok: true, issues: [] };
|
|
2533
|
+
}
|
|
2534
|
+
throw error;
|
|
2535
|
+
}
|
|
2536
|
+
}
|
|
2537
|
+
/** Runs the matching handler and tells Haven how it went; Haven answers the host. */
|
|
1891
2538
|
async answerRequest(message) {
|
|
1892
2539
|
let response;
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
try {
|
|
2540
|
+
try {
|
|
2541
|
+
const params = message.params ?? {};
|
|
2542
|
+
if (message.request === "save" && this.saveHandler) {
|
|
1897
2543
|
await this.saveHandler();
|
|
1898
2544
|
response = { ok: true };
|
|
1899
|
-
}
|
|
1900
|
-
|
|
2545
|
+
} else if (message.request === "inspect" && this.inspectionProvider) {
|
|
2546
|
+
const inspection = await this.inspectionProvider(normalizeMindooDBAppInspectRequest(params.request));
|
|
2547
|
+
response = { ok: true, result: normalizeMindooDBAppInspection(inspection) };
|
|
2548
|
+
} else if (message.request === "showIssues" && this.showIssuesHandler) {
|
|
2549
|
+
await this.showIssuesHandler(normalizeMindooDBAppIssues(params.issues));
|
|
2550
|
+
response = { ok: true };
|
|
2551
|
+
} else if (message.request === "reveal" && this.revealHandler) {
|
|
2552
|
+
const anchor = normalizeMindooDBAppInspectAnchor(params.anchor);
|
|
2553
|
+
if (!anchor) {
|
|
2554
|
+
throw new Error("Invalid anchor.");
|
|
2555
|
+
}
|
|
2556
|
+
await this.revealHandler(anchor);
|
|
2557
|
+
response = { ok: true };
|
|
2558
|
+
} else {
|
|
2559
|
+
response = { ok: false, error: "unsupported" };
|
|
1901
2560
|
}
|
|
2561
|
+
} catch (error) {
|
|
2562
|
+
response = { ok: false, error: errorMessage(error) };
|
|
1902
2563
|
}
|
|
1903
2564
|
try {
|
|
1904
2565
|
await this.rpc.call("embedding.respond", { requestId: message.requestId, ...response });
|
|
@@ -1906,6 +2567,24 @@ var MindooDBAppEmbedsClient = class {
|
|
|
1906
2567
|
console.warn("[mindoodb-app-sdk] Could not answer the host's request.", error);
|
|
1907
2568
|
}
|
|
1908
2569
|
}
|
|
2570
|
+
/** This app as a host: Haven asks before one of its components saves. */
|
|
2571
|
+
async answerEmbedRequest(message) {
|
|
2572
|
+
let response;
|
|
2573
|
+
const embed = this.open.get(message.embedId);
|
|
2574
|
+
try {
|
|
2575
|
+
response = message.request === "beforeSave" ? { ok: true, result: embed ? await embed.answerBeforeSave(message.params) : { issues: [] } } : { ok: false, error: "unsupported" };
|
|
2576
|
+
} catch (error) {
|
|
2577
|
+
response = {
|
|
2578
|
+
ok: true,
|
|
2579
|
+
result: { issues: [{ severity: "warning", message: `The check failed: ${errorMessage(error)}`, code: "check-failed" }] }
|
|
2580
|
+
};
|
|
2581
|
+
}
|
|
2582
|
+
try {
|
|
2583
|
+
await this.rpc.call("embeds.respond", { requestId: message.requestId, ...response });
|
|
2584
|
+
} catch (error) {
|
|
2585
|
+
console.warn("[mindoodb-app-sdk] Could not answer Haven's request.", error);
|
|
2586
|
+
}
|
|
2587
|
+
}
|
|
1909
2588
|
dispose() {
|
|
1910
2589
|
this.stopListening();
|
|
1911
2590
|
}
|
|
@@ -3739,6 +4418,27 @@ export {
|
|
|
3739
4418
|
isValidMindooDBDocumentId,
|
|
3740
4419
|
mindooDBDocumentId,
|
|
3741
4420
|
assertValidMindooDBCreateIds,
|
|
4421
|
+
MINDOODB_INSPECT_DOCUMENT,
|
|
4422
|
+
MINDOODB_INSPECT_SPREADSHEET,
|
|
4423
|
+
MINDOODB_INSPECT_SLIDES,
|
|
4424
|
+
MINDOODB_APP_INSPECTION_FIELD,
|
|
4425
|
+
MINDOODB_APP_INSPECTION_SUMMARY_MAX_BYTES,
|
|
4426
|
+
MINDOODB_APP_INSPECTION_MAX_BYTES,
|
|
4427
|
+
MINDOODB_APP_ISSUES_MAX,
|
|
4428
|
+
MindooDBAppEmbedValidationError,
|
|
4429
|
+
mindooDBAppComponentSupports,
|
|
4430
|
+
mindooDBAppInspectContracts,
|
|
4431
|
+
normalizeMindooDBAppInspectAnchor,
|
|
4432
|
+
normalizeMindooDBAppIssues,
|
|
4433
|
+
normalizeMindooDBAppInspectRequest,
|
|
4434
|
+
normalizeMindooDBAppInspection,
|
|
4435
|
+
summarizeMindooDBAppInspection,
|
|
4436
|
+
mindooDBAppInspectionSummaryValue,
|
|
4437
|
+
readMindooDBAppInspectionSummary,
|
|
4438
|
+
defineDocumentRules,
|
|
4439
|
+
mindooDBAppInspectRules,
|
|
4440
|
+
performMindooDBAppEmbeddingSave,
|
|
4441
|
+
resolveMindooDBAppEmbedValidation,
|
|
3742
4442
|
MINDOODB_APP_DEFINITION_FORMAT,
|
|
3743
4443
|
MINDOODB_APP_DEFINITION_VERSION,
|
|
3744
4444
|
MINDOODB_APP_DEFINITION_FILE_NAME,
|
|
@@ -3747,6 +4447,15 @@ export {
|
|
|
3747
4447
|
MINDOODB_APP_LISTING_SUMMARY_MAX,
|
|
3748
4448
|
MINDOODB_APP_LISTING_DESCRIPTION_MAX,
|
|
3749
4449
|
MINDOODB_APP_LISTING_MAX_SCREENSHOTS,
|
|
4450
|
+
MINDOODB_APP_AGENT_SUMMARY_MAX,
|
|
4451
|
+
MINDOODB_APP_AGENT_CAPABILITIES_MAX,
|
|
4452
|
+
MINDOODB_APP_AGENT_CAPABILITY_TITLE_MAX,
|
|
4453
|
+
MINDOODB_APP_AGENT_CAPABILITY_TOOLS_MAX,
|
|
4454
|
+
MINDOODB_APP_AGENT_LIST_MAX,
|
|
4455
|
+
MINDOODB_APP_AGENT_EXAMPLE_MAX,
|
|
4456
|
+
MINDOODB_APP_AGENT_LIMIT_MAX,
|
|
4457
|
+
MINDOODB_APP_AGENT_GUIDE_MAX_BYTES,
|
|
4458
|
+
MINDOODB_APP_AGENT_TOOL_NAME_PATTERN,
|
|
3750
4459
|
MINDOODB_APP_ACCEPTS_MAX,
|
|
3751
4460
|
validateMindooDBAppAccepts,
|
|
3752
4461
|
mindooDBAppAcceptMatchesType,
|
|
@@ -3754,6 +4463,7 @@ export {
|
|
|
3754
4463
|
MINDOODB_APP_COMPONENT_CONTRACT_PATTERN,
|
|
3755
4464
|
validateMindooDBAppComponents,
|
|
3756
4465
|
mindooDBAppComponentFieldsMatch,
|
|
4466
|
+
validateMindooDBAppAgentProfile,
|
|
3757
4467
|
resolveMindooDBAppLocalizedText,
|
|
3758
4468
|
resolveMindooDBAppListingAssetUrl,
|
|
3759
4469
|
validateMindooDBAppDefinition,
|