mindoodb-app-sdk 0.0.71 → 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.
@@ -1,11 +1,19 @@
1
1
  import {
2
2
  MINDOODB_APP_VALUE_TAG,
3
+ MindooDBAppEmbedValidationError,
3
4
  assertValidMindooDBCreateIds,
4
5
  mindooDBAppComponentFieldsMatch,
6
+ mindooDBAppComponentSupports,
7
+ normalizeMindooDBAppInspectAnchor,
8
+ normalizeMindooDBAppInspectRequest,
9
+ normalizeMindooDBAppInspection,
10
+ normalizeMindooDBAppIssues,
5
11
  pageUsers,
12
+ performMindooDBAppEmbeddingSave,
6
13
  releaseMindooDBAppBridgeSessions,
14
+ resolveMindooDBAppEmbedValidation,
7
15
  validateMindooDBAppDefinition
8
- } from "../chunk-GTNDGA7P.js";
16
+ } from "../chunk-UFP7O4OJ.js";
9
17
 
10
18
  // src/testing/index.ts
11
19
  import * as Automerge from "@automerge/automerge";
@@ -470,6 +478,13 @@ function createMockEmbedHost(options, getDatabase, listDatabaseIds = () => []) {
470
478
  let nextSaveError = null;
471
479
  let embeddingDirty;
472
480
  let saveRequestHandler = null;
481
+ let inspectionProvider = null;
482
+ let showIssuesHandler = null;
483
+ let revealHandler = null;
484
+ const embeddingValidations = [];
485
+ let embeddingSaveCount = 0;
486
+ const beforeSaveHandlers = /* @__PURE__ */ new Map();
487
+ const savedListeners = /* @__PURE__ */ new Set();
473
488
  let embedCounter = 0;
474
489
  let embeddingFinish = null;
475
490
  const accessRequests = [];
@@ -530,7 +545,10 @@ function createMockEmbedHost(options, getDatabase, listDatabaseIds = () => []) {
530
545
  rect: mockRect(input),
531
546
  visible: input.visible !== false,
532
547
  active: false,
533
- agentTools: null
548
+ agentTools: null,
549
+ supports: [...component.supports ?? []],
550
+ beforeSave: null,
551
+ requests: []
534
552
  });
535
553
  setActive(embedId);
536
554
  return embedId;
@@ -583,6 +601,7 @@ function createMockEmbedHost(options, getDatabase, listDatabaseIds = () => []) {
583
601
  handles.get(embedId)?.settle(event);
584
602
  handles.delete(embedId);
585
603
  toolNames.delete(embedId);
604
+ beforeSaveHandlers.delete(embedId);
586
605
  closedListeners.forEach((listener) => listener(event));
587
606
  notifyChange();
588
607
  }
@@ -605,6 +624,40 @@ function createMockEmbedHost(options, getDatabase, listDatabaseIds = () => []) {
605
624
  closed;
606
625
  dirty = void 0;
607
626
  dirtyListeners = /* @__PURE__ */ new Set();
627
+ savedListeners = /* @__PURE__ */ new Set();
628
+ get supports() {
629
+ return embeds.get(this.embedId)?.supports ?? [];
630
+ }
631
+ async inspect(request) {
632
+ return await inspectEmbed(this.embedId, request);
633
+ }
634
+ onBeforeSave(handler, options2) {
635
+ setBeforeSave(this.embedId, handler, options2?.inspect);
636
+ return () => {
637
+ if (beforeSaveHandlers.get(this.embedId) === handler) {
638
+ setBeforeSave(this.embedId, null);
639
+ }
640
+ };
641
+ }
642
+ onAfterSave(listener) {
643
+ this.savedListeners.add(listener);
644
+ return () => {
645
+ this.savedListeners.delete(listener);
646
+ };
647
+ }
648
+ notifySaved() {
649
+ const event = { embedId: this.embedId };
650
+ this.savedListeners.forEach((listener) => listener(event));
651
+ }
652
+ async showIssues(issues) {
653
+ await showEmbedIssues(this.embedId, issues);
654
+ }
655
+ async reveal(anchor) {
656
+ await revealInEmbed(this.embedId, anchor);
657
+ }
658
+ async callTool(name, input) {
659
+ return await callEmbedTool(this.embedId, name, input ?? {});
660
+ }
608
661
  onDirtyChange(listener) {
609
662
  this.dirtyListeners.add(listener);
610
663
  return () => {
@@ -704,7 +757,8 @@ function createMockEmbedHost(options, getDatabase, listDatabaseIds = () => []) {
704
757
  notifyChange();
705
758
  }
706
759
  async function saveEmbed(embedId) {
707
- if (!embeds.has(embedId)) {
760
+ const entry = embeds.get(embedId);
761
+ if (!entry) {
708
762
  throw new Error("Unknown embed.");
709
763
  }
710
764
  const error = nextSaveError;
@@ -712,7 +766,117 @@ function createMockEmbedHost(options, getDatabase, listDatabaseIds = () => []) {
712
766
  if (error) {
713
767
  throw new Error(error);
714
768
  }
769
+ if (mindooDBAppComponentSupports(entry.supports, "validate")) {
770
+ const validation = await validateEmbed(embedId);
771
+ if (!validation.ok) {
772
+ throw new MindooDBAppEmbedValidationError(validation.issues);
773
+ }
774
+ }
715
775
  setEmbedDirty(embedId, false);
776
+ notifyEmbedSaved(embedId);
777
+ }
778
+ function entryOf(embedId) {
779
+ const entry = embeds.get(embedId);
780
+ if (!entry) {
781
+ throw new Error("Unknown embed.");
782
+ }
783
+ return entry;
784
+ }
785
+ function unsupported(message) {
786
+ return Object.assign(new Error(message), { name: "unsupported" });
787
+ }
788
+ async function inspectEmbed(embedId, request) {
789
+ const entry = entryOf(embedId);
790
+ const inspect = normalizeMindooDBAppInspectRequest(request);
791
+ entry.requests.push({ request: "inspect", inspect });
792
+ if (!options.embedInspection || !mindooDBAppComponentSupports(entry.supports, "inspect")) {
793
+ throw unsupported("The component cannot describe its document.");
794
+ }
795
+ return normalizeMindooDBAppInspection(await options.embedInspection(structuredClone(entry), inspect));
796
+ }
797
+ function setBeforeSave(embedId, handler, inspect) {
798
+ const entry = entryOf(embedId);
799
+ if (handler) {
800
+ beforeSaveHandlers.set(embedId, handler);
801
+ entry.beforeSave = { inspect: normalizeMindooDBAppInspectRequest(inspect) };
802
+ } else {
803
+ beforeSaveHandlers.delete(embedId);
804
+ entry.beforeSave = null;
805
+ }
806
+ notifyChange();
807
+ }
808
+ async function validateEmbed(embedId, validateOptions = {}) {
809
+ const entry = entryOf(embedId);
810
+ const handler = beforeSaveHandlers.get(embedId);
811
+ if (!handler) {
812
+ return { ok: true, issues: [] };
813
+ }
814
+ let inspection = null;
815
+ if (options.embedInspection && mindooDBAppComponentSupports(entry.supports, "inspect")) {
816
+ inspection = normalizeMindooDBAppInspection(
817
+ await options.embedInspection(structuredClone(entry), entry.beforeSave?.inspect ?? {})
818
+ );
819
+ }
820
+ const root = await getDatabase(entry.databaseId).documents.get(entry.docId);
821
+ const answer = await handler({
822
+ embedId,
823
+ inspection,
824
+ root: root ? JSON.parse(JSON.stringify(root.data)) : null
825
+ });
826
+ return await resolveMindooDBAppEmbedValidation(
827
+ normalizeMindooDBAppIssues(answer?.issues),
828
+ validateOptions.interactive !== false,
829
+ options.confirmSaveWarnings ?? (() => true)
830
+ );
831
+ }
832
+ function notifyEmbedSaved(embedId) {
833
+ if (!embeds.has(embedId)) {
834
+ return;
835
+ }
836
+ handles.get(embedId)?.notifySaved();
837
+ savedListeners.forEach((listener) => listener({ embedId }));
838
+ }
839
+ async function showEmbedIssues(embedId, issues) {
840
+ const entry = entryOf(embedId);
841
+ entry.requests.push({ request: "showIssues", issues: normalizeMindooDBAppIssues(issues) });
842
+ if (!mindooDBAppComponentSupports(entry.supports, "issues")) {
843
+ throw unsupported("The component cannot show issues.");
844
+ }
845
+ }
846
+ async function revealInEmbed(embedId, anchor) {
847
+ const entry = entryOf(embedId);
848
+ const normalized = normalizeMindooDBAppInspectAnchor(anchor);
849
+ if (!normalized) {
850
+ throw new Error("Invalid anchor.");
851
+ }
852
+ entry.requests.push({ request: "reveal", anchor: normalized });
853
+ if (!mindooDBAppComponentSupports(entry.supports, "reveal")) {
854
+ throw unsupported("The component cannot reveal places.");
855
+ }
856
+ }
857
+ async function callEmbedTool(embedId, name, input) {
858
+ const entry = entryOf(embedId);
859
+ const prefix = `${toolPrefix(entry.component)}_`;
860
+ const bare = name.startsWith(prefix) ? name.slice(prefix.length) : name;
861
+ entry.requests.push({ request: "callTool", name: bare, input: structuredClone(input) });
862
+ if (!options.embedTools) {
863
+ throw unsupported(`The component has no tool "${bare}".`);
864
+ }
865
+ return structuredClone(await options.embedTools(structuredClone(entry), bare, structuredClone(input)));
866
+ }
867
+ async function validateEmbedding(validateOptions = {}) {
868
+ const interactive = validateOptions.interactive !== false;
869
+ const raw = await options.embeddingValidation?.({ interactive }) ?? { ok: true, issues: [] };
870
+ const result = {
871
+ ok: raw.ok !== false,
872
+ issues: normalizeMindooDBAppIssues(raw.issues),
873
+ ...raw.timedOut ? { timedOut: true } : {}
874
+ };
875
+ embeddingValidations.push({ interactive, result: structuredClone(result) });
876
+ return result;
877
+ }
878
+ function unsupportedHandler() {
879
+ throw unsupported("unsupported");
716
880
  }
717
881
  function setVisible(embedId, visible) {
718
882
  const entry = embeds.get(embedId);
@@ -724,7 +888,7 @@ function createMockEmbedHost(options, getDatabase, listDatabaseIds = () => []) {
724
888
  return {
725
889
  components: {
726
890
  async list(query) {
727
- return components.filter((entry) => !query?.intent || entry.intents.includes(query.intent)).filter((entry) => !query?.document || mindooDBAppComponentFieldsMatch(entry.match, query.document)).map((entry) => structuredClone(entry));
891
+ return components.filter((entry) => !query?.intent || entry.intents.includes(query.intent)).filter((entry) => (query?.requires ?? []).every((requirement) => mindooDBAppComponentSupports(entry.supports, requirement))).filter((entry) => !query?.document || mindooDBAppComponentFieldsMatch(entry.match, query.document)).map((entry) => structuredClone(entry));
728
892
  }
729
893
  },
730
894
  embeds: {
@@ -759,6 +923,36 @@ function createMockEmbedHost(options, getDatabase, listDatabaseIds = () => []) {
759
923
  saveRequestHandler = null;
760
924
  }
761
925
  };
926
+ },
927
+ provideInspection(provider) {
928
+ inspectionProvider = provider;
929
+ return () => {
930
+ if (inspectionProvider === provider) inspectionProvider = null;
931
+ };
932
+ },
933
+ onShowIssues(handler) {
934
+ showIssuesHandler = handler;
935
+ return () => {
936
+ if (showIssuesHandler === handler) showIssuesHandler = null;
937
+ };
938
+ },
939
+ onReveal(handler) {
940
+ revealHandler = handler;
941
+ return () => {
942
+ if (revealHandler === handler) revealHandler = null;
943
+ };
944
+ },
945
+ validate: validateEmbedding,
946
+ async save(flush, saveOptions) {
947
+ return await performMindooDBAppEmbeddingSave({
948
+ validate: () => validateEmbedding(saveOptions),
949
+ provider: inspectionProvider,
950
+ showIssues: showIssuesHandler,
951
+ flush,
952
+ saved: () => {
953
+ embeddingSaveCount += 1;
954
+ }
955
+ });
762
956
  }
763
957
  },
764
958
  openEmbed,
@@ -822,6 +1016,44 @@ function createMockEmbedHost(options, getDatabase, listDatabaseIds = () => []) {
822
1016
  },
823
1017
  setSaveRequestHandler(handler) {
824
1018
  saveRequestHandler = handler;
1019
+ },
1020
+ inspectEmbed,
1021
+ setBeforeSave,
1022
+ validateEmbed,
1023
+ notifyEmbedSaved,
1024
+ onSaved(listener) {
1025
+ savedListeners.add(listener);
1026
+ return () => {
1027
+ savedListeners.delete(listener);
1028
+ };
1029
+ },
1030
+ showEmbedIssues,
1031
+ revealInEmbed,
1032
+ callEmbedTool,
1033
+ getEmbedRequests(embedId) {
1034
+ return structuredClone(embeds.get(embedId)?.requests ?? []);
1035
+ },
1036
+ async requestEmbeddingInspection(request) {
1037
+ if (!inspectionProvider) unsupportedHandler();
1038
+ return normalizeMindooDBAppInspection(await inspectionProvider(normalizeMindooDBAppInspectRequest(request)));
1039
+ },
1040
+ async requestEmbeddingShowIssues(issues) {
1041
+ if (!showIssuesHandler) unsupportedHandler();
1042
+ await showIssuesHandler(normalizeMindooDBAppIssues(issues));
1043
+ },
1044
+ async requestEmbeddingReveal(anchor) {
1045
+ if (!revealHandler) unsupportedHandler();
1046
+ await revealHandler(anchor);
1047
+ },
1048
+ getEmbeddingValidations() {
1049
+ return structuredClone(embeddingValidations);
1050
+ },
1051
+ getEmbeddingSaveCount() {
1052
+ return embeddingSaveCount;
1053
+ },
1054
+ validateEmbedding,
1055
+ recordEmbeddingSaved() {
1056
+ embeddingSaveCount += 1;
825
1057
  }
826
1058
  };
827
1059
  }
@@ -6030,7 +6262,15 @@ function createMockMindooDBAppSession(options = {}) {
6030
6262
  setEmbedAgentTools: (embedId, names, toolOptions) => state.embedHost.setEmbedAgentTools(embedId, names, toolOptions),
6031
6263
  failNextEmbedSave: (message) => state.embedHost.failNextSave(message),
6032
6264
  getEmbeddingDirty: () => state.embedHost.getEmbeddingDirty(),
6033
- requestEmbeddingSave: () => state.embedHost.requestEmbeddingSave()
6265
+ requestEmbeddingSave: () => state.embedHost.requestEmbeddingSave(),
6266
+ validateEmbed: (embedId, validateOptions) => state.embedHost.validateEmbed(embedId, validateOptions),
6267
+ notifyEmbedSaved: (embedId) => state.embedHost.notifyEmbedSaved(embedId),
6268
+ getEmbedRequests: (embedId) => state.embedHost.getEmbedRequests(embedId),
6269
+ requestEmbeddingInspection: (request) => state.embedHost.requestEmbeddingInspection(request),
6270
+ requestEmbeddingShowIssues: (issues) => state.embedHost.requestEmbeddingShowIssues(issues),
6271
+ requestEmbeddingReveal: (anchor) => state.embedHost.requestEmbeddingReveal(anchor),
6272
+ getEmbeddingValidations: () => state.embedHost.getEmbeddingValidations(),
6273
+ getEmbeddingSaveCount: () => state.embedHost.getEmbeddingSaveCount()
6034
6274
  };
6035
6275
  replicaStates.set(controller, state);
6036
6276
  return controller;
@@ -6076,8 +6316,25 @@ function createFakeBridgeHost(options = {}) {
6076
6316
  (port) => port.postMessage({ protocol: PROTOCOL, kind: "embed-event", event: { type: "agentTools", ...event } })
6077
6317
  );
6078
6318
  });
6319
+ state.embedHost.onSaved((event) => {
6320
+ connectedPorts.forEach(
6321
+ (port) => port.postMessage({ protocol: PROTOCOL, kind: "embed-event", event: { type: "saved", ...event } })
6322
+ );
6323
+ });
6079
6324
  const embeddingRequests = /* @__PURE__ */ new Map();
6080
6325
  let embeddingRequestCounter = 0;
6326
+ function pushEmbeddingRequest(request, params) {
6327
+ embeddingRequestCounter += 1;
6328
+ const requestId = `embedding-request-${embeddingRequestCounter}`;
6329
+ return new Promise((resolve, reject) => {
6330
+ embeddingRequests.set(requestId, { resolve, reject });
6331
+ connectedPorts.forEach(
6332
+ (port) => port.postMessage({ protocol: PROTOCOL, kind: "embedding-request", requestId, request, ...params ? { params } : {} })
6333
+ );
6334
+ });
6335
+ }
6336
+ const embedRequests = /* @__PURE__ */ new Map();
6337
+ let embedRequestCounter = 0;
6081
6338
  const beforeCloseWaiters = /* @__PURE__ */ new Map();
6082
6339
  let beforeCloseCounter = 0;
6083
6340
  const viewSessions = /* @__PURE__ */ new Map();
@@ -6314,8 +6571,66 @@ function createFakeBridgeHost(options = {}) {
6314
6571
  case "embeds.open": {
6315
6572
  const input = params.input;
6316
6573
  const embedId = await state.embedHost.openEmbed(input);
6317
- return input.placement === "frame" && options.embedFrameUrl ? { embedId, frame: { url: options.embedFrameUrl } } : { embedId };
6574
+ const supports = state.embedHost.listEmbeds().find((entry) => entry.embedId === embedId)?.supports ?? [];
6575
+ return {
6576
+ embedId,
6577
+ ...input.placement === "frame" && options.embedFrameUrl ? { frame: { url: options.embedFrameUrl } } : {},
6578
+ ...supports.length ? { supports } : {}
6579
+ };
6580
+ }
6581
+ case "embeds.inspect":
6582
+ return await state.embedHost.inspectEmbed(
6583
+ String(params.embedId),
6584
+ params.request
6585
+ );
6586
+ case "embeds.setBeforeSave": {
6587
+ const embedId = String(params.embedId);
6588
+ state.embedHost.setBeforeSave(
6589
+ embedId,
6590
+ params.enabled === true ? (input) => {
6591
+ embedRequestCounter += 1;
6592
+ const requestId = `embed-request-${embedRequestCounter}`;
6593
+ return new Promise((resolve) => {
6594
+ embedRequests.set(requestId, (result) => resolve(result));
6595
+ connectedPorts.forEach(
6596
+ (port) => port.postMessage({
6597
+ protocol: PROTOCOL,
6598
+ kind: "embed-request",
6599
+ requestId,
6600
+ embedId,
6601
+ request: "beforeSave",
6602
+ params: { inspection: input.inspection, root: input.root }
6603
+ })
6604
+ );
6605
+ });
6606
+ } : null,
6607
+ params.inspect
6608
+ );
6609
+ return { ok: true };
6318
6610
  }
6611
+ case "embeds.respond": {
6612
+ const resolve = embedRequests.get(String(params.requestId));
6613
+ embedRequests.delete(String(params.requestId));
6614
+ resolve?.(params.ok === true ? params.result : { issues: [] });
6615
+ return { ok: true };
6616
+ }
6617
+ case "embeds.showIssues":
6618
+ await state.embedHost.showEmbedIssues(String(params.embedId), params.issues);
6619
+ return { ok: true };
6620
+ case "embeds.reveal":
6621
+ await state.embedHost.revealInEmbed(String(params.embedId), params.anchor);
6622
+ return { ok: true };
6623
+ case "embeds.callTool":
6624
+ return await state.embedHost.callEmbedTool(
6625
+ String(params.embedId),
6626
+ String(params.name),
6627
+ params.input ?? {}
6628
+ );
6629
+ case "embedding.validate":
6630
+ return await state.embedHost.validateEmbedding({ interactive: params.interactive !== false });
6631
+ case "embedding.saved":
6632
+ state.embedHost.recordEmbeddingSaved();
6633
+ return { ok: true };
6319
6634
  case "embeds.requestAccess":
6320
6635
  return await state.embedHost.embeds.requestAccess(
6321
6636
  params.input ?? { components: [] }
@@ -6348,9 +6663,10 @@ function createFakeBridgeHost(options = {}) {
6348
6663
  const pending = embeddingRequests.get(String(params.requestId));
6349
6664
  embeddingRequests.delete(String(params.requestId));
6350
6665
  if (params.ok === true) {
6351
- pending?.resolve();
6666
+ pending?.resolve(params.result);
6352
6667
  } else {
6353
- pending?.reject(new Error(typeof params.error === "string" ? params.error : "Save failed."));
6668
+ const message = typeof params.error === "string" ? params.error : "Save failed.";
6669
+ pending?.reject(Object.assign(new Error(message), message === "unsupported" ? { name: "unsupported" } : {}));
6354
6670
  }
6355
6671
  return { ok: true };
6356
6672
  }
@@ -6988,16 +7304,23 @@ function createFakeBridgeHost(options = {}) {
6988
7304
  setEmbedAgentTools: (embedId, names, toolOptions) => state.embedHost.setEmbedAgentTools(embedId, names, toolOptions),
6989
7305
  failNextEmbedSave: (message) => state.embedHost.failNextSave(message),
6990
7306
  getEmbeddingDirty: () => state.embedHost.getEmbeddingDirty(),
6991
- requestEmbeddingSave() {
6992
- embeddingRequestCounter += 1;
6993
- const requestId = `embedding-request-${embeddingRequestCounter}`;
6994
- return new Promise((resolve, reject) => {
6995
- embeddingRequests.set(requestId, { resolve, reject });
6996
- connectedPorts.forEach(
6997
- (port) => port.postMessage({ protocol: PROTOCOL, kind: "embedding-request", requestId, request: "save" })
6998
- );
6999
- });
7307
+ async requestEmbeddingSave() {
7308
+ await pushEmbeddingRequest("save");
7309
+ },
7310
+ validateEmbed: (embedId, validateOptions) => state.embedHost.validateEmbed(embedId, validateOptions),
7311
+ notifyEmbedSaved: (embedId) => state.embedHost.notifyEmbedSaved(embedId),
7312
+ getEmbedRequests: (embedId) => state.embedHost.getEmbedRequests(embedId),
7313
+ async requestEmbeddingInspection(request) {
7314
+ return await pushEmbeddingRequest("inspect", { request: request ?? {} });
7315
+ },
7316
+ async requestEmbeddingShowIssues(issues) {
7317
+ await pushEmbeddingRequest("showIssues", { issues });
7318
+ },
7319
+ async requestEmbeddingReveal(anchor) {
7320
+ await pushEmbeddingRequest("reveal", { anchor });
7000
7321
  },
7322
+ getEmbeddingValidations: () => state.embedHost.getEmbeddingValidations(),
7323
+ getEmbeddingSaveCount: () => state.embedHost.getEmbeddingSaveCount(),
7001
7324
  dispose() {
7002
7325
  restoreWindow();
7003
7326
  connectedPorts.forEach((port) => {