mindoodb-app-sdk 0.0.71 → 0.0.73

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.
@@ -66,6 +66,297 @@ 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
+ var SUPPORTS_ARGUMENT = /^[a-z0-9][a-z0-9-]{0,31}$/;
318
+ function isMindooDBAppSupportsEntry(entry, contractPattern) {
319
+ const [capability, argument, ...rest] = entry.split(":");
320
+ if (rest.length || !capability || !SUPPORTS_CAPABILITY.test(capability)) {
321
+ return false;
322
+ }
323
+ return argument === void 0 || contractPattern.test(argument) || SUPPORTS_ARGUMENT.test(argument);
324
+ }
325
+ async function performMindooDBAppEmbeddingSave(steps) {
326
+ const validation = await steps.validate();
327
+ if (!validation.ok) {
328
+ if (validation.issues.length && steps.showIssues) {
329
+ try {
330
+ await steps.showIssues(validation.issues);
331
+ } catch (error) {
332
+ console.warn("[mindoodb-app-sdk] Showing issues failed.", error);
333
+ }
334
+ }
335
+ throw new MindooDBAppEmbedValidationError(validation.issues);
336
+ }
337
+ let inspection = null;
338
+ if (steps.provider) {
339
+ try {
340
+ inspection = mindooDBAppInspectionSummaryValue(normalizeMindooDBAppInspection(await steps.provider({})));
341
+ } catch (error) {
342
+ console.warn("[mindoodb-app-sdk] Could not summarize the document.", error);
343
+ }
344
+ }
345
+ await steps.flush({ inspection, issues: validation.issues });
346
+ await steps.saved();
347
+ return validation;
348
+ }
349
+ async function resolveMindooDBAppEmbedValidation(issues, interactive, confirm) {
350
+ if (issues.some((issue) => issue.severity === "error")) {
351
+ return { ok: false, issues };
352
+ }
353
+ const warnings = issues.filter((issue) => issue.severity === "warning");
354
+ if (!warnings.length || !interactive) {
355
+ return { ok: true, issues };
356
+ }
357
+ return { ok: await confirm(warnings) === true, issues };
358
+ }
359
+
69
360
  // src/appDefinition.ts
70
361
  var MINDOODB_APP_DEFINITION_FORMAT = "mindoodb.haven.app";
71
362
  var MINDOODB_APP_DEFINITION_VERSION = 1;
@@ -96,7 +387,7 @@ var MINDOODB_APP_AGENT_LIMIT_MAX = 300;
96
387
  var MINDOODB_APP_AGENT_GUIDE_MAX_BYTES = 8 * 1024;
97
388
  var MINDOODB_APP_AGENT_TOOL_NAME_PATTERN = /^[a-z][a-z0-9_]{0,47}$/;
98
389
  var LOGICAL_DATABASE_ID_PATTERN = /^[a-z0-9][a-z0-9._-]*$/i;
99
- function isPlainObject(value) {
390
+ function isPlainObject2(value) {
100
391
  return typeof value === "object" && value !== null && !Array.isArray(value);
101
392
  }
102
393
  function readOptionalString(raw, key, errors) {
@@ -127,7 +418,7 @@ function readStringRecord(raw, key, errors) {
127
418
  if (value === void 0 || value === null) {
128
419
  return void 0;
129
420
  }
130
- if (!isPlainObject(value)) {
421
+ if (!isPlainObject2(value)) {
131
422
  errors.push(`App definition ${key} must be an object of string values.`);
132
423
  return void 0;
133
424
  }
@@ -193,7 +484,7 @@ function readDatabases(value, errors) {
193
484
  const result = [];
194
485
  const seen = /* @__PURE__ */ new Set();
195
486
  value.forEach((entry, index) => {
196
- if (!isPlainObject(entry)) {
487
+ if (!isPlainObject2(entry)) {
197
488
  errors.push(`App definition database #${index} must be an object.`);
198
489
  return;
199
490
  }
@@ -246,7 +537,7 @@ function readLocalizedText(value, label, maxLength, errors) {
246
537
  }
247
538
  return trimmed || void 0;
248
539
  }
249
- if (!isPlainObject(value)) {
540
+ if (!isPlainObject2(value)) {
250
541
  errors.push(`${label} must be a string or an object of per-locale strings.`);
251
542
  return void 0;
252
543
  }
@@ -293,7 +584,7 @@ function readAccepts(value, errors) {
293
584
  const ids = /* @__PURE__ */ new Set();
294
585
  value.forEach((entry, index) => {
295
586
  const label = `App definition accepts[${index}]`;
296
- if (!isPlainObject(entry)) {
587
+ if (!isPlainObject2(entry)) {
297
588
  errors.push(`${label} must be an object.`);
298
589
  return;
299
590
  }
@@ -354,7 +645,7 @@ var COMPONENT_FIELD_PATTERN = /^[A-Za-z_][A-Za-z0-9_]{0,63}$/;
354
645
  var COMPONENT_INTENTS = ["create", "edit", "view"];
355
646
  var COMPONENT_CREATE_MAX_BYTES = 16 * 1024;
356
647
  function readComponentFieldMatch(value, label, errors) {
357
- if (!isPlainObject(value)) {
648
+ if (!isPlainObject2(value)) {
358
649
  errors.push(`${label} must be an object of field values.`);
359
650
  return void 0;
360
651
  }
@@ -377,6 +668,28 @@ var MINDOODB_APP_COMPONENT_CONTRACT_PATTERN = /^[a-z][a-z0-9-]*(\.[a-z][a-z0-9-]
377
668
  var COMPONENT_CONTRACTS_MAX = 8;
378
669
  var COMPONENT_REFERENCES_MAX = 8;
379
670
  var COMPONENT_REFERENCE_SHOW_MAX = 8;
671
+ var COMPONENT_SUPPORTS_MAX = 16;
672
+ function readComponentSupports(value, label, errors) {
673
+ if (value === void 0) {
674
+ return void 0;
675
+ }
676
+ if (!Array.isArray(value) || value.length > COMPONENT_SUPPORTS_MAX) {
677
+ errors.push(`${label} must be an array of at most ${COMPONENT_SUPPORTS_MAX} entries.`);
678
+ return void 0;
679
+ }
680
+ const result = [];
681
+ for (const entry of value) {
682
+ const text = typeof entry === "string" ? entry.trim() : "";
683
+ if (!isMindooDBAppSupportsEntry(text, MINDOODB_APP_COMPONENT_CONTRACT_PATTERN)) {
684
+ errors.push(`${label} entries must look like "validate", "export:pdf" or "inspect:mindoo.inspect.document@1", received ${JSON.stringify(entry)}.`);
685
+ return void 0;
686
+ }
687
+ if (!result.includes(text)) {
688
+ result.push(text);
689
+ }
690
+ }
691
+ return result.length ? result : void 0;
692
+ }
380
693
  function readComponentContracts(value, label, errors) {
381
694
  if (value === void 0) {
382
695
  return void 0;
@@ -387,14 +700,14 @@ function readComponentContracts(value, label, errors) {
387
700
  }
388
701
  const result = [];
389
702
  for (const [index, entry] of value.entries()) {
390
- const contract = isPlainObject(entry) && typeof entry.contract === "string" ? entry.contract.trim() : "";
703
+ const contract = isPlainObject2(entry) && typeof entry.contract === "string" ? entry.contract.trim() : "";
391
704
  if (!MINDOODB_APP_COMPONENT_CONTRACT_PATTERN.test(contract)) {
392
705
  errors.push(`${label}[${index}].contract must look like "mindoo.contacts.company@1".`);
393
706
  return void 0;
394
707
  }
395
708
  let fields;
396
- if (isPlainObject(entry) && entry.fields !== void 0) {
397
- if (!isPlainObject(entry.fields)) {
709
+ if (isPlainObject2(entry) && entry.fields !== void 0) {
710
+ if (!isPlainObject2(entry.fields)) {
398
711
  errors.push(`${label}[${index}].fields must map contract fields to document fields.`);
399
712
  return void 0;
400
713
  }
@@ -423,7 +736,7 @@ function readComponentReferences(value, label, rootMatch, errors) {
423
736
  const fieldsSeen = /* @__PURE__ */ new Set();
424
737
  for (const [index, entry] of value.entries()) {
425
738
  const at = `${label}[${index}]`;
426
- if (!isPlainObject(entry)) {
739
+ if (!isPlainObject2(entry)) {
427
740
  errors.push(`${at} must be an object.`);
428
741
  return void 0;
429
742
  }
@@ -472,7 +785,7 @@ function readComponents(value, errors) {
472
785
  value.forEach((entry, index) => {
473
786
  const label = `App definition components[${index}]`;
474
787
  const errorCount = errors.length;
475
- if (!isPlainObject(entry)) {
788
+ if (!isPlainObject2(entry)) {
476
789
  errors.push(`${label} must be an object.`);
477
790
  return;
478
791
  }
@@ -519,7 +832,7 @@ function readComponents(value, errors) {
519
832
  }
520
833
  let create;
521
834
  if (entry.create !== void 0) {
522
- if (!isPlainObject(entry.create)) {
835
+ if (!isPlainObject2(entry.create)) {
523
836
  errors.push(`${label}.create must be an object of initial field values.`);
524
837
  return;
525
838
  }
@@ -548,7 +861,7 @@ function readComponents(value, errors) {
548
861
  }
549
862
  let children;
550
863
  if (entry.children !== void 0) {
551
- if (!isPlainObject(entry.children)) {
864
+ if (!isPlainObject2(entry.children)) {
552
865
  errors.push(`${label}.children must be an object.`);
553
866
  return;
554
867
  }
@@ -577,6 +890,7 @@ function readComponents(value, errors) {
577
890
  }
578
891
  const provides = readComponentContracts(entry.provides, `${label}.provides`, errors);
579
892
  const references = readComponentReferences(entry.references, `${label}.references`, match, errors);
893
+ const supports = readComponentSupports(entry.supports, `${label}.supports`, errors);
580
894
  if (errors.length !== errorCount) {
581
895
  return;
582
896
  }
@@ -591,7 +905,8 @@ function readComponents(value, errors) {
591
905
  ...children ? { children } : {},
592
906
  ...category ? { category } : {},
593
907
  ...provides ? { provides } : {},
594
- ...references ? { references } : {}
908
+ ...references ? { references } : {},
909
+ ...supports ? { supports } : {}
595
910
  });
596
911
  });
597
912
  return result.length ? result : void 0;
@@ -631,7 +946,7 @@ function readListing(value, errors) {
631
946
  if (value === void 0 || value === null) {
632
947
  return void 0;
633
948
  }
634
- if (!isPlainObject(value)) {
949
+ if (!isPlainObject2(value)) {
635
950
  errors.push("App definition listing must be an object.");
636
951
  return void 0;
637
952
  }
@@ -671,7 +986,7 @@ function readListing(value, errors) {
671
986
  value.screenshots.forEach((entry, index) => {
672
987
  const label = `App definition listing.screenshots[${index}]`;
673
988
  const raw = typeof entry === "string" ? { file: entry } : entry;
674
- if (!isPlainObject(raw)) {
989
+ if (!isPlainObject2(raw)) {
675
990
  errors.push(`${label} must be a path or an object with a file.`);
676
991
  return;
677
992
  }
@@ -686,7 +1001,7 @@ function readListing(value, errors) {
686
1001
  }
687
1002
  }
688
1003
  if (value.publisher !== void 0 && value.publisher !== null) {
689
- const publisher = isPlainObject(value.publisher) ? value.publisher : {};
1004
+ const publisher = isPlainObject2(value.publisher) ? value.publisher : {};
690
1005
  const name = typeof publisher.name === "string" ? publisher.name.trim() : "";
691
1006
  if (!name) {
692
1007
  errors.push("App definition listing.publisher must be an object with a non-empty name.");
@@ -705,7 +1020,7 @@ var AGENT_CAPABILITY_ID_PATTERN = /^[a-z0-9][a-z0-9_-]{0,47}$/;
705
1020
  var AGENT_LOCALE_PATTERN = /^[a-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$/;
706
1021
  var AGENT_GUIDE_PATH_PATTERN = /^[A-Za-z0-9_][A-Za-z0-9_.\/-]{0,199}\.md$/;
707
1022
  function readAgentLocaleText(value, label, maxLength, errors) {
708
- if (!isPlainObject(value)) {
1023
+ if (!isPlainObject2(value)) {
709
1024
  errors.push(`${label} must be an object of per-locale strings with an "en" entry.`);
710
1025
  return void 0;
711
1026
  }
@@ -736,7 +1051,7 @@ function readAgentLocaleList(value, label, maxLength, errors) {
736
1051
  if (value === void 0) {
737
1052
  return void 0;
738
1053
  }
739
- if (!isPlainObject(value)) {
1054
+ if (!isPlainObject2(value)) {
740
1055
  errors.push(`${label} must be an object of per-locale string arrays with an "en" entry.`);
741
1056
  return void 0;
742
1057
  }
@@ -777,7 +1092,7 @@ function readAgentCapabilities(value, errors) {
777
1092
  const ids = /* @__PURE__ */ new Set();
778
1093
  for (const [index, entry] of value.entries()) {
779
1094
  const at = `${label}[${index}]`;
780
- if (!isPlainObject(entry)) {
1095
+ if (!isPlainObject2(entry)) {
781
1096
  errors.push(`${at} must be an object.`);
782
1097
  return void 0;
783
1098
  }
@@ -820,7 +1135,7 @@ function readAgentProfile(value, errors) {
820
1135
  if (value === void 0 || value === null) {
821
1136
  return void 0;
822
1137
  }
823
- if (!isPlainObject(value)) {
1138
+ if (!isPlainObject2(value)) {
824
1139
  errors.push("App definition agent must be an object.");
825
1140
  return void 0;
826
1141
  }
@@ -883,7 +1198,7 @@ function resolveMindooDBAppListingAssetUrl(path, originUrl) {
883
1198
  }
884
1199
  function validateMindooDBAppDefinition(raw) {
885
1200
  const errors = [];
886
- if (!isPlainObject(raw)) {
1201
+ if (!isPlainObject2(raw)) {
887
1202
  return { definition: null, errors: ["App definition must be a JSON object."] };
888
1203
  }
889
1204
  if (raw.format !== MINDOODB_APP_DEFINITION_FORMAT) {
@@ -1397,29 +1712,29 @@ function bindDragSource(element, options, start, follow) {
1397
1712
  }
1398
1713
 
1399
1714
  // src/client/agentInput.ts
1400
- function isPlainObject2(value) {
1715
+ function isPlainObject3(value) {
1401
1716
  return typeof value === "object" && value !== null && !Array.isArray(value);
1402
1717
  }
1403
1718
  function isPlaceholder(value) {
1404
1719
  if (value === null || value === void 0) return true;
1405
1720
  if (typeof value === "string") return value.trim() === "";
1406
1721
  if (Array.isArray(value)) return value.length === 0;
1407
- if (isPlainObject2(value)) return Object.keys(value).length === 0;
1722
+ if (isPlainObject3(value)) return Object.keys(value).length === 0;
1408
1723
  return false;
1409
1724
  }
1410
1725
  function normalizeValue(value, schema) {
1411
- if (!isPlainObject2(schema)) return value;
1726
+ if (!isPlainObject3(schema)) return value;
1412
1727
  if (Array.isArray(value)) {
1413
1728
  const items = schema.items;
1414
- return isPlainObject2(items) ? value.map((item) => normalizeValue(item, items)) : value;
1729
+ return isPlainObject3(items) ? value.map((item) => normalizeValue(item, items)) : value;
1415
1730
  }
1416
- if (isPlainObject2(value) && isPlainObject2(schema.properties)) {
1731
+ if (isPlainObject3(value) && isPlainObject3(schema.properties)) {
1417
1732
  return normalizeObject(value, schema);
1418
1733
  }
1419
1734
  return value;
1420
1735
  }
1421
1736
  function normalizeObject(input, schema) {
1422
- const properties = isPlainObject2(schema.properties) ? schema.properties : {};
1737
+ const properties = isPlainObject3(schema.properties) ? schema.properties : {};
1423
1738
  const required = new Set(Array.isArray(schema.required) ? schema.required.filter((key) => typeof key === "string") : []);
1424
1739
  const result = {};
1425
1740
  for (const [key, raw] of Object.entries(input)) {
@@ -1434,7 +1749,7 @@ function normalizeObject(input, schema) {
1434
1749
  return result;
1435
1750
  }
1436
1751
  function normalizeAgentToolInput(input, schema) {
1437
- return isPlainObject2(input) ? normalizeObject(input, schema) : input;
1752
+ return isPlainObject3(input) ? normalizeObject(input, schema) : input;
1438
1753
  }
1439
1754
 
1440
1755
  // src/client/agentTools.ts
@@ -1538,6 +1853,83 @@ var MindooDBAppAgentApiImpl = class {
1538
1853
  }
1539
1854
  };
1540
1855
 
1856
+ // src/embedExchange.ts
1857
+ var MINDOODB_APP_EMBED_VARIABLES_MAX = 200;
1858
+ var VARIABLE_KEY = /^[A-Za-z_][A-Za-z0-9_.-]{0,63}$/;
1859
+ function normalizeMindooDBAppEmbedVariables(raw) {
1860
+ if (!Array.isArray(raw)) {
1861
+ return [];
1862
+ }
1863
+ const byKey = /* @__PURE__ */ new Map();
1864
+ for (const entry of raw) {
1865
+ if (!entry || typeof entry !== "object") continue;
1866
+ const { key, label, value, group } = entry;
1867
+ if (typeof key !== "string" || !VARIABLE_KEY.test(key)) continue;
1868
+ const text = (input, max) => typeof input === "string" ? input.slice(0, max) : "";
1869
+ byKey.delete(key);
1870
+ byKey.set(key, {
1871
+ key,
1872
+ label: text(label, 120).trim() || key,
1873
+ value: typeof value === "number" || typeof value === "boolean" ? String(value) : text(value, 4e3),
1874
+ ...typeof group === "string" && group.trim() ? { group: group.trim().slice(0, 80) } : {}
1875
+ });
1876
+ if (byKey.size >= MINDOODB_APP_EMBED_VARIABLES_MAX) break;
1877
+ }
1878
+ return [...byKey.values()];
1879
+ }
1880
+ function resolveMindooDBAppVariables(text, variables, options = {}) {
1881
+ const values = new Map(variables.map((variable) => [variable.key, variable.value]));
1882
+ return text.replace(/\{\{\s*([A-Za-z_][A-Za-z0-9_.-]{0,63})\s*\}\}/g, (match, key) => {
1883
+ const value = values.get(key);
1884
+ return value === void 0 || !value && !options.keepEmpty ? match : value;
1885
+ });
1886
+ }
1887
+ var MINDOODB_APP_EMBED_EXPORT_MAX_BYTES = 64 * 1024 * 1024;
1888
+ var EXPORT_TYPES = {
1889
+ pdf: "application/pdf",
1890
+ docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
1891
+ xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
1892
+ pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
1893
+ png: "image/png",
1894
+ md: "text/markdown",
1895
+ csv: "text/csv"
1896
+ };
1897
+ function mindooDBAppExportMimeType(format) {
1898
+ return EXPORT_TYPES[format] ?? "application/octet-stream";
1899
+ }
1900
+ function normalizeMindooDBAppEmbedExportRequest(raw) {
1901
+ const input = raw && typeof raw === "object" ? raw : {};
1902
+ const format = typeof input.format === "string" ? input.format.trim().toLowerCase() : "";
1903
+ if (!/^[a-z0-9][a-z0-9-]{0,31}$/.test(format)) {
1904
+ throw new Error('An export needs a format such as "pdf" or "png".');
1905
+ }
1906
+ const size = (value) => {
1907
+ const number = Number(value);
1908
+ return Number.isFinite(number) && number > 0 ? Math.min(Math.round(number), 8192) : void 0;
1909
+ };
1910
+ const maxWidth = size(input.maxWidth);
1911
+ const maxHeight = size(input.maxHeight);
1912
+ return { format, ...maxWidth ? { maxWidth } : {}, ...maxHeight ? { maxHeight } : {} };
1913
+ }
1914
+ async function mindooDBAppExportPayload(result, request, baseName = "document") {
1915
+ const blob = result instanceof Blob ? result : null;
1916
+ const data = blob ?? result.data;
1917
+ const bytes = data instanceof Blob ? await data.arrayBuffer() : ArrayBuffer.isView(data) ? data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength) : data;
1918
+ if (Object.prototype.toString.call(bytes) !== "[object ArrayBuffer]") {
1919
+ throw new Error("An export must be a Blob, an ArrayBuffer or a Uint8Array.");
1920
+ }
1921
+ if (bytes.byteLength > MINDOODB_APP_EMBED_EXPORT_MAX_BYTES) {
1922
+ throw new Error(`An export must not be larger than ${MINDOODB_APP_EMBED_EXPORT_MAX_BYTES / 1024 / 1024} MiB.`);
1923
+ }
1924
+ const named = blob ? blob.name : result.name;
1925
+ const mimeType = !blob && result.mimeType || (blob?.type ? blob.type : "") || mindooDBAppExportMimeType(request.format);
1926
+ const name = (typeof named === "string" && named.trim() ? named.trim() : `${baseName}.${request.format}`).slice(0, 200);
1927
+ return { data: bytes, name, mimeType };
1928
+ }
1929
+ function mindooDBAppExportFile(payload) {
1930
+ return new File([payload.data], payload.name, { type: payload.mimeType });
1931
+ }
1932
+
1541
1933
  // src/directoryPaging.ts
1542
1934
  var LIST_USERS_DEFAULT_LIMIT = 50;
1543
1935
  var LIST_USERS_MAX_LIMIT = 500;
@@ -1651,6 +2043,15 @@ import { parseMindooDBFormulaBooleanExpression } from "mindoodb-view-language";
1651
2043
  function isEmbedEventMessage(message) {
1652
2044
  return message.kind === "embed-event";
1653
2045
  }
2046
+ function isEmbedRequestMessage(message) {
2047
+ return message.kind === "embed-request";
2048
+ }
2049
+ function isMethodNotFound(error) {
2050
+ return error instanceof Error && error.name === "method-not-found";
2051
+ }
2052
+ function errorMessage(error) {
2053
+ return error instanceof Error ? error.message : String(error);
2054
+ }
1654
2055
  function isEmbeddingRequestMessage(message) {
1655
2056
  return message.kind === "embedding-request";
1656
2057
  }
@@ -1717,13 +2118,14 @@ function createComponentFrame(container, url, allow) {
1717
2118
  return frame;
1718
2119
  }
1719
2120
  var MindooDBAppEmbedImpl = class {
1720
- constructor(rpc, embedId, componentKey, databaseId, docId, frame, container) {
2121
+ constructor(rpc, embedId, componentKey, databaseId, docId, frame, container, supports = []) {
1721
2122
  this.rpc = rpc;
1722
2123
  this.embedId = embedId;
1723
2124
  this.componentKey = componentKey;
1724
2125
  this.databaseId = databaseId;
1725
2126
  this.docId = docId;
1726
2127
  this.frame = frame;
2128
+ this.supports = supports;
1727
2129
  this.closed = new Promise((resolve) => {
1728
2130
  this.resolveClosed = resolve;
1729
2131
  });
@@ -1740,6 +2142,7 @@ var MindooDBAppEmbedImpl = class {
1740
2142
  databaseId;
1741
2143
  docId;
1742
2144
  frame;
2145
+ supports;
1743
2146
  closed;
1744
2147
  resolveClosed;
1745
2148
  closedEvent = null;
@@ -1749,6 +2152,8 @@ var MindooDBAppEmbedImpl = class {
1749
2152
  tracker = null;
1750
2153
  toolsState = null;
1751
2154
  toolsListeners = /* @__PURE__ */ new Set();
2155
+ beforeSaveHandler = null;
2156
+ savedListeners = /* @__PURE__ */ new Set();
1752
2157
  get placement() {
1753
2158
  return this.frame ? "frame" : "overlay";
1754
2159
  }
@@ -1831,6 +2236,104 @@ var MindooDBAppEmbedImpl = class {
1831
2236
  const stopClosed = this.onClosed(() => finish(null));
1832
2237
  });
1833
2238
  }
2239
+ async inspect(request) {
2240
+ const result = await this.rpc.call("embeds.inspect", {
2241
+ embedId: this.embedId,
2242
+ request: normalizeMindooDBAppInspectRequest(request)
2243
+ });
2244
+ return normalizeMindooDBAppInspection(result);
2245
+ }
2246
+ onBeforeSave(handler, options) {
2247
+ this.beforeSaveHandler = handler;
2248
+ this.announceBeforeSave(true, options?.inspect);
2249
+ return () => {
2250
+ if (this.beforeSaveHandler === handler) {
2251
+ this.beforeSaveHandler = null;
2252
+ this.announceBeforeSave(false);
2253
+ }
2254
+ };
2255
+ }
2256
+ /** Haven only asks hosts that said they check, and fetches the inspection they want. */
2257
+ announceBeforeSave(enabled, inspect) {
2258
+ if (this.closedEvent) {
2259
+ return;
2260
+ }
2261
+ void this.rpc.call("embeds.setBeforeSave", {
2262
+ embedId: this.embedId,
2263
+ enabled,
2264
+ ...enabled ? { inspect: normalizeMindooDBAppInspectRequest(inspect) } : {}
2265
+ }).catch((error) => {
2266
+ if (!isMethodNotFound(error)) {
2267
+ console.warn("[mindoodb-app-sdk] Could not register the save check.", error);
2268
+ }
2269
+ });
2270
+ }
2271
+ /** Haven asks before the component saves: run the handler, never longer than Haven waits. */
2272
+ async answerBeforeSave(params) {
2273
+ const handler = this.beforeSaveHandler;
2274
+ if (!handler || this.closedEvent) {
2275
+ return { issues: [] };
2276
+ }
2277
+ const result = await handler({
2278
+ embedId: this.embedId,
2279
+ inspection: params?.inspection ?? null,
2280
+ root: params?.root ?? null
2281
+ });
2282
+ return { issues: normalizeMindooDBAppIssues(result?.issues) };
2283
+ }
2284
+ onAfterSave(listener) {
2285
+ this.savedListeners.add(listener);
2286
+ return () => {
2287
+ this.savedListeners.delete(listener);
2288
+ };
2289
+ }
2290
+ /** The component reported that it saved. */
2291
+ notifySaved() {
2292
+ if (this.closedEvent) {
2293
+ return;
2294
+ }
2295
+ const event = { embedId: this.embedId };
2296
+ this.savedListeners.forEach((listener) => {
2297
+ try {
2298
+ listener(event);
2299
+ } catch (error) {
2300
+ console.error("MindooDB embed saved listener failed.", error);
2301
+ }
2302
+ });
2303
+ }
2304
+ async showIssues(issues) {
2305
+ await this.rpc.call("embeds.showIssues", { embedId: this.embedId, issues: normalizeMindooDBAppIssues(issues) });
2306
+ }
2307
+ async reveal(anchor) {
2308
+ const normalized = normalizeMindooDBAppInspectAnchor(anchor);
2309
+ if (!normalized) {
2310
+ throw new Error("Invalid anchor.");
2311
+ }
2312
+ await this.rpc.call("embeds.reveal", { embedId: this.embedId, anchor: normalized });
2313
+ }
2314
+ async setVariables(variables) {
2315
+ await this.rpc.call("embeds.setVariables", {
2316
+ embedId: this.embedId,
2317
+ variables: normalizeMindooDBAppEmbedVariables(variables)
2318
+ });
2319
+ }
2320
+ async export(request) {
2321
+ const payload = await this.rpc.call("embeds.export", {
2322
+ embedId: this.embedId,
2323
+ request: normalizeMindooDBAppEmbedExportRequest(request)
2324
+ });
2325
+ if (!payload || Object.prototype.toString.call(payload.data) !== "[object ArrayBuffer]") {
2326
+ throw new Error("The component handed over no file.");
2327
+ }
2328
+ return mindooDBAppExportFile(payload);
2329
+ }
2330
+ async callTool(name, input) {
2331
+ return await this.rpc.call("embeds.callTool", {
2332
+ embedId: this.embedId,
2333
+ name: String(name),
2334
+ input: input === void 0 ? {} : JSON.parse(JSON.stringify(input))
2335
+ });
2336
+ }
1834
2337
  async setRect(rect) {
1835
2338
  if (this.closedEvent) {
1836
2339
  return;
@@ -1885,6 +2388,8 @@ var MindooDBAppEmbedImpl = class {
1885
2388
  });
1886
2389
  this.listeners.clear();
1887
2390
  this.dirtyListeners.clear();
2391
+ this.savedListeners.clear();
2392
+ this.beforeSaveHandler = null;
1888
2393
  this.toolsState = null;
1889
2394
  this.toolsListeners.forEach((listener) => {
1890
2395
  try {
@@ -1904,6 +2409,10 @@ var MindooDBAppEmbedsClient = class {
1904
2409
  void this.answerRequest(message);
1905
2410
  return;
1906
2411
  }
2412
+ if (isEmbedRequestMessage(message)) {
2413
+ void this.answerEmbedRequest(message);
2414
+ return;
2415
+ }
1907
2416
  if (!isEmbedEventMessage(message)) {
1908
2417
  return;
1909
2418
  }
@@ -1927,6 +2436,10 @@ var MindooDBAppEmbedsClient = class {
1927
2436
  }
1928
2437
  return;
1929
2438
  }
2439
+ if (message.event?.type === "saved") {
2440
+ this.open.get(message.event.embedId)?.notifySaved();
2441
+ return;
2442
+ }
1930
2443
  if (message.event?.type !== "closed") {
1931
2444
  return;
1932
2445
  }
@@ -1951,10 +2464,17 @@ var MindooDBAppEmbedsClient = class {
1951
2464
  open: async (input) => {
1952
2465
  const { container, rect, ...rest } = input;
1953
2466
  const initialRect = container ? containerRect(container) : toRect(rect ?? { left: 0, top: 0, width: 0, height: 0 });
2467
+ const { variables, template, ...plain } = rest;
1954
2468
  const response = await this.rpc.call("embeds.open", {
1955
2469
  // `frame`: Haven hands back a page for the container instead of laying
1956
2470
  // the component over this app. Havens that do not know it ignore it.
1957
- input: { ...rest, rect: initialRect, ...container ? { placement: "frame" } : {} }
2471
+ input: {
2472
+ ...plain,
2473
+ rect: initialRect,
2474
+ ...container ? { placement: "frame" } : {},
2475
+ ...variables ? { variables: normalizeMindooDBAppEmbedVariables(variables) } : {},
2476
+ ...template ? { template: { docId: String(template.docId), ...template.databaseId ? { databaseId: String(template.databaseId) } : {} } } : {}
2477
+ }
1958
2478
  });
1959
2479
  const frame = container && response.frame?.url ? createComponentFrame(container, response.frame.url, response.frame.allow) : null;
1960
2480
  const embed = new MindooDBAppEmbedImpl(
@@ -1964,7 +2484,8 @@ var MindooDBAppEmbedsClient = class {
1964
2484
  input.databaseId,
1965
2485
  input.docId,
1966
2486
  frame,
1967
- container
2487
+ container,
2488
+ Array.isArray(response.supports) ? response.supports.filter((entry) => typeof entry === "string") : []
1968
2489
  );
1969
2490
  const earlyDirty = this.earlyDirty.get(embed.embedId);
1970
2491
  if (earlyDirty !== void 0) {
@@ -2040,7 +2561,74 @@ var MindooDBAppEmbedsClient = class {
2040
2561
  this.saveHandler = null;
2041
2562
  }
2042
2563
  };
2043
- }
2564
+ },
2565
+ provideInspection: (provider) => {
2566
+ this.inspectionProvider = provider;
2567
+ return () => {
2568
+ if (this.inspectionProvider === provider) {
2569
+ this.inspectionProvider = null;
2570
+ }
2571
+ };
2572
+ },
2573
+ onShowIssues: (handler) => {
2574
+ this.showIssuesHandler = handler;
2575
+ return () => {
2576
+ if (this.showIssuesHandler === handler) {
2577
+ this.showIssuesHandler = null;
2578
+ }
2579
+ };
2580
+ },
2581
+ getVariables: async () => {
2582
+ if (this.variables) {
2583
+ return this.variables.map((variable) => ({ ...variable }));
2584
+ }
2585
+ try {
2586
+ const result = await this.rpc.call("embedding.getVariables", {});
2587
+ this.variables ??= normalizeMindooDBAppEmbedVariables(result?.variables);
2588
+ } catch (error) {
2589
+ if (!isMethodNotFound(error) && !(error instanceof Error && error.name === "unsupported")) {
2590
+ throw error;
2591
+ }
2592
+ this.variables ??= [];
2593
+ }
2594
+ return this.variables.map((variable) => ({ ...variable }));
2595
+ },
2596
+ onVariablesChange: (listener) => {
2597
+ this.variableListeners.add(listener);
2598
+ return () => {
2599
+ this.variableListeners.delete(listener);
2600
+ };
2601
+ },
2602
+ provideExport: (provider) => {
2603
+ this.exportProvider = provider;
2604
+ return () => {
2605
+ if (this.exportProvider === provider) {
2606
+ this.exportProvider = null;
2607
+ }
2608
+ };
2609
+ },
2610
+ onReveal: (handler) => {
2611
+ this.revealHandler = handler;
2612
+ return () => {
2613
+ if (this.revealHandler === handler) {
2614
+ this.revealHandler = null;
2615
+ }
2616
+ };
2617
+ },
2618
+ validate: async (options) => await this.validate(options),
2619
+ save: async (flush, options) => await performMindooDBAppEmbeddingSave({
2620
+ validate: () => this.validate(options),
2621
+ provider: this.inspectionProvider,
2622
+ showIssues: this.showIssuesHandler,
2623
+ flush,
2624
+ // Only news for the host: a lost message must not fail a save that happened.
2625
+ saved: () => this.rpc.call("embedding.saved", {}).then(
2626
+ () => {
2627
+ },
2628
+ () => {
2629
+ }
2630
+ )
2631
+ })
2044
2632
  };
2045
2633
  }
2046
2634
  rpc;
@@ -2055,18 +2643,71 @@ var MindooDBAppEmbedsClient = class {
2055
2643
  stopListening;
2056
2644
  /** This app as a component: what to do when its host asks it to save. */
2057
2645
  saveHandler = null;
2058
- /** Runs the save handler and tells Haven how it went; Haven answers the host. */
2646
+ inspectionProvider = null;
2647
+ showIssuesHandler = null;
2648
+ revealHandler = null;
2649
+ exportProvider = null;
2650
+ /** The host's variables as last pushed; null until known (then asked for on first use). */
2651
+ variables = null;
2652
+ variableListeners = /* @__PURE__ */ new Set();
2653
+ /** `embedding.validate`; ok when Haven cannot check (not embedded, older Haven). */
2654
+ async validate(options) {
2655
+ try {
2656
+ const result = await this.rpc.call("embedding.validate", {
2657
+ interactive: options?.interactive !== false
2658
+ });
2659
+ return {
2660
+ ok: result?.ok !== false,
2661
+ issues: normalizeMindooDBAppIssues(result?.issues),
2662
+ ...result?.timedOut ? { timedOut: true } : {}
2663
+ };
2664
+ } catch (error) {
2665
+ if (isMethodNotFound(error) || error instanceof Error && error.name === "unsupported") {
2666
+ return { ok: true, issues: [] };
2667
+ }
2668
+ throw error;
2669
+ }
2670
+ }
2671
+ /** Runs the matching handler and tells Haven how it went; Haven answers the host. */
2059
2672
  async answerRequest(message) {
2060
2673
  let response;
2061
- if (message.request !== "save" || !this.saveHandler) {
2062
- response = { ok: false, error: "unsupported" };
2063
- } else {
2064
- try {
2674
+ try {
2675
+ const params = message.params ?? {};
2676
+ if (message.request === "save" && this.saveHandler) {
2065
2677
  await this.saveHandler();
2066
2678
  response = { ok: true };
2067
- } catch (error) {
2068
- response = { ok: false, error: error instanceof Error ? error.message : String(error) };
2679
+ } else if (message.request === "inspect" && this.inspectionProvider) {
2680
+ const inspection = await this.inspectionProvider(normalizeMindooDBAppInspectRequest(params.request));
2681
+ response = { ok: true, result: normalizeMindooDBAppInspection(inspection) };
2682
+ } else if (message.request === "showIssues" && this.showIssuesHandler) {
2683
+ await this.showIssuesHandler(normalizeMindooDBAppIssues(params.issues));
2684
+ response = { ok: true };
2685
+ } else if (message.request === "reveal" && this.revealHandler) {
2686
+ const anchor = normalizeMindooDBAppInspectAnchor(params.anchor);
2687
+ if (!anchor) {
2688
+ throw new Error("Invalid anchor.");
2689
+ }
2690
+ await this.revealHandler(anchor);
2691
+ response = { ok: true };
2692
+ } else if (message.request === "variables") {
2693
+ this.variables = normalizeMindooDBAppEmbedVariables(params.variables);
2694
+ const variables = this.variables;
2695
+ this.variableListeners.forEach((listener) => {
2696
+ try {
2697
+ listener(variables.map((variable) => ({ ...variable })));
2698
+ } catch (error) {
2699
+ console.error("MindooDB embedding variables listener failed.", error);
2700
+ }
2701
+ });
2702
+ response = { ok: true };
2703
+ } else if (message.request === "export" && this.exportProvider) {
2704
+ const request = normalizeMindooDBAppEmbedExportRequest(params.request);
2705
+ response = { ok: true, result: await mindooDBAppExportPayload(await this.exportProvider(request), request) };
2706
+ } else {
2707
+ response = { ok: false, error: "unsupported" };
2069
2708
  }
2709
+ } catch (error) {
2710
+ response = { ok: false, error: errorMessage(error) };
2070
2711
  }
2071
2712
  try {
2072
2713
  await this.rpc.call("embedding.respond", { requestId: message.requestId, ...response });
@@ -2074,6 +2715,24 @@ var MindooDBAppEmbedsClient = class {
2074
2715
  console.warn("[mindoodb-app-sdk] Could not answer the host's request.", error);
2075
2716
  }
2076
2717
  }
2718
+ /** This app as a host: Haven asks before one of its components saves. */
2719
+ async answerEmbedRequest(message) {
2720
+ let response;
2721
+ const embed = this.open.get(message.embedId);
2722
+ try {
2723
+ response = message.request === "beforeSave" ? { ok: true, result: embed ? await embed.answerBeforeSave(message.params) : { issues: [] } } : { ok: false, error: "unsupported" };
2724
+ } catch (error) {
2725
+ response = {
2726
+ ok: true,
2727
+ result: { issues: [{ severity: "warning", message: `The check failed: ${errorMessage(error)}`, code: "check-failed" }] }
2728
+ };
2729
+ }
2730
+ try {
2731
+ await this.rpc.call("embeds.respond", { requestId: message.requestId, ...response });
2732
+ } catch (error) {
2733
+ console.warn("[mindoodb-app-sdk] Could not answer Haven's request.", error);
2734
+ }
2735
+ }
2077
2736
  dispose() {
2078
2737
  this.stopListening();
2079
2738
  }
@@ -3907,6 +4566,27 @@ export {
3907
4566
  isValidMindooDBDocumentId,
3908
4567
  mindooDBDocumentId,
3909
4568
  assertValidMindooDBCreateIds,
4569
+ MINDOODB_INSPECT_DOCUMENT,
4570
+ MINDOODB_INSPECT_SPREADSHEET,
4571
+ MINDOODB_INSPECT_SLIDES,
4572
+ MINDOODB_APP_INSPECTION_FIELD,
4573
+ MINDOODB_APP_INSPECTION_SUMMARY_MAX_BYTES,
4574
+ MINDOODB_APP_INSPECTION_MAX_BYTES,
4575
+ MINDOODB_APP_ISSUES_MAX,
4576
+ MindooDBAppEmbedValidationError,
4577
+ mindooDBAppComponentSupports,
4578
+ mindooDBAppInspectContracts,
4579
+ normalizeMindooDBAppInspectAnchor,
4580
+ normalizeMindooDBAppIssues,
4581
+ normalizeMindooDBAppInspectRequest,
4582
+ normalizeMindooDBAppInspection,
4583
+ summarizeMindooDBAppInspection,
4584
+ mindooDBAppInspectionSummaryValue,
4585
+ readMindooDBAppInspectionSummary,
4586
+ defineDocumentRules,
4587
+ mindooDBAppInspectRules,
4588
+ performMindooDBAppEmbeddingSave,
4589
+ resolveMindooDBAppEmbedValidation,
3910
4590
  MINDOODB_APP_DEFINITION_FORMAT,
3911
4591
  MINDOODB_APP_DEFINITION_VERSION,
3912
4592
  MINDOODB_APP_DEFINITION_FILE_NAME,
@@ -3952,6 +4632,14 @@ export {
3952
4632
  bindDragSource,
3953
4633
  normalizeAgentToolInput,
3954
4634
  MindooDBAppAgentToolError,
4635
+ MINDOODB_APP_EMBED_VARIABLES_MAX,
4636
+ normalizeMindooDBAppEmbedVariables,
4637
+ resolveMindooDBAppVariables,
4638
+ MINDOODB_APP_EMBED_EXPORT_MAX_BYTES,
4639
+ mindooDBAppExportMimeType,
4640
+ normalizeMindooDBAppEmbedExportRequest,
4641
+ mindooDBAppExportPayload,
4642
+ mindooDBAppExportFile,
3955
4643
  pageUsers,
3956
4644
  DEFAULT_HAVEN_HOST_SHORTCUTS,
3957
4645
  matchHostShortcut,