@palettelab/sdk 0.1.15 → 0.1.17

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/dist/index.js CHANGED
@@ -21,8 +21,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var src_exports = {};
22
22
  __export(src_exports, {
23
23
  DataRoomClient: () => DataRoomClient,
24
+ Link: () => Link,
24
25
  OrganizationClient: () => OrganizationClient,
25
26
  PaletteApiError: () => PaletteApiError,
27
+ PaletteAppRouter: () => PaletteAppRouter,
26
28
  PlatformCtx: () => PlatformCtx,
27
29
  PluginProvider: () => PluginProvider,
28
30
  StorageClient: () => StorageClient,
@@ -33,8 +35,10 @@ __export(src_exports, {
33
35
  createPaletteClient: () => createPaletteClient,
34
36
  createSandboxBridge: () => createSandboxBridge,
35
37
  dataRooms: () => dataRooms,
38
+ disconnectConnection: () => disconnectConnection,
36
39
  errorFromResponse: () => errorFromResponse,
37
40
  getBaseUrl: () => getBaseUrl,
41
+ getConnections: () => getConnections,
38
42
  getInstallConfig: () => getInstallConfig,
39
43
  hasAllPermissions: () => hasAllPermissions,
40
44
  hasAnyPermission: () => hasAnyPermission,
@@ -42,15 +46,22 @@ __export(src_exports, {
42
46
  isPaletteApiError: () => isPaletteApiError,
43
47
  isSandboxRuntime: () => isSandboxRuntime,
44
48
  normalizePaletteLanguage: () => normalizePaletteLanguage,
49
+ notFound: () => notFound,
50
+ requireConnection: () => requireConnection,
45
51
  setBaseUrl: () => setBaseUrl,
52
+ startConnection: () => startConnection,
46
53
  translate: () => translate,
47
54
  updateInstallConfig: () => updateInstallConfig,
48
55
  uploadToSignedUrl: () => uploadToSignedUrl,
56
+ useParams: () => useParams,
57
+ usePathname: () => usePathname,
49
58
  usePlatform: () => usePlatform,
50
59
  usePluginChat: () => usePluginChat,
51
60
  usePluginDataRooms: () => usePluginDataRooms,
52
61
  usePluginTasks: () => usePluginTasks,
53
62
  usePluginTranslations: () => usePluginTranslations,
63
+ useRouter: () => useRouter,
64
+ useSearchParams: () => useSearchParams,
54
65
  withPluginProvider: () => withPluginProvider
55
66
  });
56
67
  module.exports = __toCommonJS(src_exports);
@@ -167,6 +178,32 @@ async function updateInstallConfig(pluginId, config) {
167
178
  return res.json();
168
179
  }
169
180
 
181
+ // src/connections.ts
182
+ async function getConnections(pluginId) {
183
+ const res = await apiFetch(`/api/v1/app-installs/${encodeURIComponent(pluginId)}/connections`);
184
+ return res.json();
185
+ }
186
+ async function startConnection(pluginId, connectionId) {
187
+ const res = await apiFetch(
188
+ `/api/v1/app-installs/${encodeURIComponent(pluginId)}/connections/${encodeURIComponent(connectionId)}/authorize`,
189
+ { method: "POST" }
190
+ );
191
+ return res.json();
192
+ }
193
+ async function disconnectConnection(pluginId, connectionId) {
194
+ await apiFetch(
195
+ `/api/v1/app-installs/${encodeURIComponent(pluginId)}/connections/${encodeURIComponent(connectionId)}`,
196
+ { method: "DELETE" }
197
+ );
198
+ }
199
+ async function requireConnection(pluginId, connectionId) {
200
+ const connection = (await getConnections(pluginId)).find((item) => item.id === connectionId);
201
+ if (!connection || !["connected", "expiring"].includes(connection.status)) {
202
+ throw new Error(`Palette connection is not configured: ${connectionId}`);
203
+ }
204
+ return connection;
205
+ }
206
+
170
207
  // src/test-utils.tsx
171
208
  var import_react2 = require("react");
172
209
 
@@ -228,6 +265,7 @@ function createMockPlatformContext(overrides = {}) {
228
265
  apiFetch: async () => new Response(JSON.stringify({}), { status: 200 }),
229
266
  navigate: () => {
230
267
  },
268
+ routePath: "/",
231
269
  showToast: () => {
232
270
  },
233
271
  ...overrides
@@ -641,6 +679,28 @@ function createPaletteClient(ctx) {
641
679
  return updateInstallConfig(resolved, values);
642
680
  }
643
681
  },
682
+ connections: {
683
+ list: (pluginId = ctx?.pluginId ?? "") => {
684
+ const resolved = pluginId || defaultPluginId2();
685
+ if (!resolved) throw new Error("pluginId is required to read connections");
686
+ return getConnections(resolved);
687
+ },
688
+ connect: (connectionId, pluginId = ctx?.pluginId ?? "") => {
689
+ const resolved = pluginId || defaultPluginId2();
690
+ if (!resolved) throw new Error("pluginId is required to start a connection");
691
+ return startConnection(resolved, connectionId);
692
+ },
693
+ disconnect: (connectionId, pluginId = ctx?.pluginId ?? "") => {
694
+ const resolved = pluginId || defaultPluginId2();
695
+ if (!resolved) throw new Error("pluginId is required to disconnect a connection");
696
+ return disconnectConnection(resolved, connectionId);
697
+ },
698
+ require: (connectionId, pluginId = ctx?.pluginId ?? "") => {
699
+ const resolved = pluginId || defaultPluginId2();
700
+ if (!resolved) throw new Error("pluginId is required to require a connection");
701
+ return requireConnection(resolved, connectionId);
702
+ }
703
+ },
644
704
  permissions: {
645
705
  has: (permission) => ctx ? hasPermission(ctx, permission) : false,
646
706
  hasAny: (permissions) => ctx ? hasAnyPermission(ctx, permissions) : false,
@@ -717,14 +777,207 @@ function usePluginTranslations(resources, options = {}) {
717
777
  };
718
778
  }
719
779
 
720
- // src/hooks/use-plugin-tasks.ts
780
+ // src/router.tsx
721
781
  var import_react4 = require("react");
782
+ var RouterCtx = (0, import_react4.createContext)(null);
783
+ var NOT_FOUND = /* @__PURE__ */ Symbol.for("palette.router.not-found");
784
+ function notFound() {
785
+ throw Object.assign(new Error("Palette route not found"), { code: NOT_FOUND });
786
+ }
787
+ function normalizePath(path) {
788
+ const clean = String(path || "/").split("#")[0].split("?")[0] || "/";
789
+ return `/${clean.replace(/^\/+/, "").replace(/\/+$/, "")}`.replace(/^\/$/, "/");
790
+ }
791
+ function splitPath(path) {
792
+ return normalizePath(path).split("/").filter(Boolean).map(decodeURIComponent);
793
+ }
794
+ function routeScore(route) {
795
+ if (typeof route.score === "number") return route.score;
796
+ return route.segments.reduce((score, segment) => {
797
+ if (segment.kind === "static") return score + 10;
798
+ if (segment.kind === "dynamic") return score + 5;
799
+ return score + (segment.optional ? 1 : 2);
800
+ }, route.segments.length);
801
+ }
802
+ function matchRoute(route, path) {
803
+ const parts = splitPath(path);
804
+ const params = {};
805
+ let index = 0;
806
+ for (const segment of route.segments) {
807
+ if (segment.kind === "catchAll") {
808
+ const rest = parts.slice(index);
809
+ if (!segment.optional && rest.length === 0) return null;
810
+ params[segment.name] = rest;
811
+ index = parts.length;
812
+ break;
813
+ }
814
+ const value = parts[index];
815
+ if (value === void 0) return null;
816
+ if (segment.kind === "static") {
817
+ if (value !== segment.value) return null;
818
+ } else {
819
+ params[segment.name] = value;
820
+ }
821
+ index += 1;
822
+ }
823
+ return index === parts.length ? params : null;
824
+ }
825
+ function currentPluginPath(pluginId, routePath) {
826
+ if (routePath) return normalizePath(routePath);
827
+ if (typeof window === "undefined") return "/";
828
+ const path = window.location.pathname;
829
+ if (pluginId) {
830
+ const prefix = `/apps/${pluginId}`;
831
+ if (path === prefix) return "/";
832
+ if (path.startsWith(`${prefix}/`)) return normalizePath(path.slice(prefix.length));
833
+ }
834
+ return normalizePath(path);
835
+ }
836
+ function currentSearchParams() {
837
+ if (typeof window === "undefined") return new URLSearchParams();
838
+ return new URLSearchParams(window.location.search);
839
+ }
840
+ var PaletteRouteErrorBoundary = class extends import_react4.Component {
841
+ constructor() {
842
+ super(...arguments);
843
+ this.state = { error: null };
844
+ this.reset = () => this.setState({ error: null });
845
+ }
846
+ static getDerivedStateFromError(error) {
847
+ return { error };
848
+ }
849
+ componentDidCatch(_error, _info) {
850
+ }
851
+ render() {
852
+ const error = this.state.error;
853
+ if (!error) return this.props.children;
854
+ if (error.code === NOT_FOUND && this.props.notFound) {
855
+ return (0, import_react4.createElement)(this.props.notFound);
856
+ }
857
+ if (this.props.fallback) {
858
+ return (0, import_react4.createElement)(this.props.fallback, { error, reset: this.reset });
859
+ }
860
+ throw error;
861
+ }
862
+ };
863
+ function renderRoute(route) {
864
+ const page = (0, import_react4.createElement)(route.page);
865
+ const wrapped = (route.layouts || []).reduceRight(
866
+ (children, Layout) => (0, import_react4.createElement)(Layout, null, children),
867
+ page
868
+ );
869
+ return (0, import_react4.createElement)(
870
+ PaletteRouteErrorBoundary,
871
+ { fallback: route.error, notFound: route.notFound },
872
+ wrapped
873
+ );
874
+ }
875
+ function PaletteAppRouter({
876
+ routes,
877
+ notFound: NotFound
878
+ }) {
879
+ const platform = usePlatform();
880
+ const [location, setLocation] = (0, import_react4.useState)(() => ({
881
+ pathname: currentPluginPath(platform.pluginId, platform.routePath),
882
+ searchParams: currentSearchParams()
883
+ }));
884
+ (0, import_react4.useEffect)(() => {
885
+ setLocation({
886
+ pathname: currentPluginPath(platform.pluginId, platform.routePath),
887
+ searchParams: currentSearchParams()
888
+ });
889
+ }, [platform.pluginId, platform.routePath]);
890
+ (0, import_react4.useEffect)(() => {
891
+ const sync = () => setLocation({
892
+ pathname: currentPluginPath(platform.pluginId, platform.routePath),
893
+ searchParams: currentSearchParams()
894
+ });
895
+ window.addEventListener("popstate", sync);
896
+ return () => window.removeEventListener("popstate", sync);
897
+ }, [platform.pluginId, platform.routePath]);
898
+ const sortedRoutes = (0, import_react4.useMemo)(
899
+ () => [...routes].sort((a, b) => routeScore(b) - routeScore(a)),
900
+ [routes]
901
+ );
902
+ const matched = (0, import_react4.useMemo)(() => {
903
+ for (const route of sortedRoutes) {
904
+ const params = matchRoute(route, location.pathname);
905
+ if (params) return { route, params };
906
+ }
907
+ return null;
908
+ }, [location.pathname, sortedRoutes]);
909
+ const navigate = (0, import_react4.useCallback)((target, replace = false) => {
910
+ const [pathPart, queryPart = ""] = String(target || "/").split("?");
911
+ const pathname = normalizePath(pathPart);
912
+ const next = `${pathname}${queryPart ? `?${queryPart}` : ""}`;
913
+ setLocation({ pathname, searchParams: new URLSearchParams(queryPart) });
914
+ const currentPath = typeof window === "undefined" ? "" : window.location.pathname;
915
+ const inPalettePath = platform.pluginId && (currentPath.startsWith(`/apps/${platform.pluginId}`) || platform.routePath !== void 0);
916
+ const osPath = inPalettePath && platform.pluginId ? `/apps/${platform.pluginId}${pathname === "/" ? "" : pathname}${queryPart ? `?${queryPart}` : ""}` : next;
917
+ if (replace && typeof window !== "undefined") window.history.replaceState(null, "", osPath);
918
+ else platform.navigate(osPath);
919
+ }, [platform]);
920
+ const state = (0, import_react4.useMemo)(() => ({
921
+ pathname: location.pathname,
922
+ searchParams: location.searchParams,
923
+ params: matched?.params || {},
924
+ push: (path) => navigate(path, false),
925
+ replace: (path) => navigate(path, true)
926
+ }), [location.pathname, location.searchParams, matched?.params, navigate]);
927
+ const content = matched ? renderRoute(matched.route) : NotFound ? (0, import_react4.createElement)(NotFound) : (0, import_react4.createElement)("div", null, "Page not found");
928
+ return (0, import_react4.createElement)(RouterCtx.Provider, { value: state }, content);
929
+ }
930
+ function useRouterState() {
931
+ const value = (0, import_react4.useContext)(RouterCtx);
932
+ if (!value) throw new Error("Palette app router hooks must be used inside PaletteAppRouter");
933
+ return value;
934
+ }
935
+ function useRouter() {
936
+ const { push, replace } = useRouterState();
937
+ return { push, replace, back: () => window.history.back(), forward: () => window.history.forward() };
938
+ }
939
+ function usePathname() {
940
+ return useRouterState().pathname;
941
+ }
942
+ function useSearchParams() {
943
+ return useRouterState().searchParams;
944
+ }
945
+ function useParams() {
946
+ return useRouterState().params;
947
+ }
948
+ function Link({
949
+ href,
950
+ replace,
951
+ onClick,
952
+ children,
953
+ ...props
954
+ }) {
955
+ const router = useRouter();
956
+ return (0, import_react4.createElement)(
957
+ "a",
958
+ {
959
+ ...props,
960
+ href,
961
+ onClick: (event) => {
962
+ onClick?.(event);
963
+ if (event.defaultPrevented || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
964
+ event.preventDefault();
965
+ if (replace) router.replace(href);
966
+ else router.push(href);
967
+ }
968
+ },
969
+ children
970
+ );
971
+ }
972
+
973
+ // src/hooks/use-plugin-tasks.ts
974
+ var import_react5 = require("react");
722
975
  function usePluginTasks(agentId) {
723
976
  const { apiFetch: apiFetch2 } = usePlatform();
724
- const [tasks, setTasks] = (0, import_react4.useState)([]);
725
- const [stats, setStats] = (0, import_react4.useState)(null);
726
- const [loading, setLoading] = (0, import_react4.useState)(true);
727
- const fetchTasks = (0, import_react4.useCallback)(async () => {
977
+ const [tasks, setTasks] = (0, import_react5.useState)([]);
978
+ const [stats, setStats] = (0, import_react5.useState)(null);
979
+ const [loading, setLoading] = (0, import_react5.useState)(true);
980
+ const fetchTasks = (0, import_react5.useCallback)(async () => {
728
981
  try {
729
982
  const params = new URLSearchParams();
730
983
  if (agentId) params.set("agent_id", String(agentId));
@@ -733,18 +986,18 @@ function usePluginTasks(agentId) {
733
986
  } catch {
734
987
  }
735
988
  }, [apiFetch2, agentId]);
736
- const fetchStats = (0, import_react4.useCallback)(async () => {
989
+ const fetchStats = (0, import_react5.useCallback)(async () => {
737
990
  try {
738
991
  const res = await apiFetch2("/api/v1/tasks/stats");
739
992
  setStats(await res.json());
740
993
  } catch {
741
994
  }
742
995
  }, [apiFetch2]);
743
- (0, import_react4.useEffect)(() => {
996
+ (0, import_react5.useEffect)(() => {
744
997
  setLoading(true);
745
998
  Promise.all([fetchTasks(), fetchStats()]).finally(() => setLoading(false));
746
999
  }, [fetchTasks, fetchStats]);
747
- const createTask = (0, import_react4.useCallback)(async (payload) => {
1000
+ const createTask = (0, import_react5.useCallback)(async (payload) => {
748
1001
  const res = await apiFetch2("/api/v1/tasks", {
749
1002
  method: "POST",
750
1003
  body: JSON.stringify(payload)
@@ -753,7 +1006,7 @@ function usePluginTasks(agentId) {
753
1006
  await Promise.all([fetchTasks(), fetchStats()]);
754
1007
  return task;
755
1008
  }, [apiFetch2, fetchTasks, fetchStats]);
756
- const updateTask = (0, import_react4.useCallback)(async (taskId, payload) => {
1009
+ const updateTask = (0, import_react5.useCallback)(async (taskId, payload) => {
757
1010
  const res = await apiFetch2(`/api/v1/tasks/${taskId}`, {
758
1011
  method: "PATCH",
759
1012
  body: JSON.stringify(payload)
@@ -762,7 +1015,7 @@ function usePluginTasks(agentId) {
762
1015
  await Promise.all([fetchTasks(), fetchStats()]);
763
1016
  return task;
764
1017
  }, [apiFetch2, fetchTasks, fetchStats]);
765
- const deleteTask = (0, import_react4.useCallback)(async (taskId) => {
1018
+ const deleteTask = (0, import_react5.useCallback)(async (taskId) => {
766
1019
  await apiFetch2(`/api/v1/tasks/${taskId}`, { method: "DELETE" });
767
1020
  await Promise.all([fetchTasks(), fetchStats()]);
768
1021
  }, [apiFetch2, fetchTasks, fetchStats]);
@@ -770,23 +1023,23 @@ function usePluginTasks(agentId) {
770
1023
  }
771
1024
 
772
1025
  // src/hooks/use-plugin-data-rooms.ts
773
- var import_react5 = require("react");
1026
+ var import_react6 = require("react");
774
1027
  function usePluginDataRooms() {
775
1028
  const { apiFetch: apiFetch2 } = usePlatform();
776
- const [rooms, setRooms] = (0, import_react5.useState)([]);
777
- const [loading, setLoading] = (0, import_react5.useState)(true);
778
- const fetchRooms = (0, import_react5.useCallback)(async () => {
1029
+ const [rooms, setRooms] = (0, import_react6.useState)([]);
1030
+ const [loading, setLoading] = (0, import_react6.useState)(true);
1031
+ const fetchRooms = (0, import_react6.useCallback)(async () => {
779
1032
  try {
780
1033
  const res = await apiFetch2("/api/v1/data-rooms");
781
1034
  setRooms(await res.json());
782
1035
  } catch {
783
1036
  }
784
1037
  }, [apiFetch2]);
785
- (0, import_react5.useEffect)(() => {
1038
+ (0, import_react6.useEffect)(() => {
786
1039
  setLoading(true);
787
1040
  fetchRooms().finally(() => setLoading(false));
788
1041
  }, [fetchRooms]);
789
- const fetchFolder = (0, import_react5.useCallback)(async (roomId, folderId) => {
1042
+ const fetchFolder = (0, import_react6.useCallback)(async (roomId, folderId) => {
790
1043
  const path = folderId ? `/api/v1/data-rooms/${roomId}/folders/${folderId}` : `/api/v1/data-rooms/${roomId}`;
791
1044
  const res = await apiFetch2(path);
792
1045
  return res.json();
@@ -795,19 +1048,19 @@ function usePluginDataRooms() {
795
1048
  }
796
1049
 
797
1050
  // src/hooks/use-plugin-chat.ts
798
- var import_react6 = require("react");
1051
+ var import_react7 = require("react");
799
1052
  function usePluginChat(agentId) {
800
1053
  const { apiFetch: apiFetch2 } = usePlatform();
801
- const [threads, setThreads] = (0, import_react6.useState)([]);
802
- const [messages, setMessages] = (0, import_react6.useState)([]);
803
- const [streaming, setStreaming] = (0, import_react6.useState)(false);
804
- const [activeThreadId, setActiveThreadId] = (0, import_react6.useState)(null);
805
- const abortRef = (0, import_react6.useRef)(null);
806
- const fetchThreads = (0, import_react6.useCallback)(async () => {
1054
+ const [threads, setThreads] = (0, import_react7.useState)([]);
1055
+ const [messages, setMessages] = (0, import_react7.useState)([]);
1056
+ const [streaming, setStreaming] = (0, import_react7.useState)(false);
1057
+ const [activeThreadId, setActiveThreadId] = (0, import_react7.useState)(null);
1058
+ const abortRef = (0, import_react7.useRef)(null);
1059
+ const fetchThreads = (0, import_react7.useCallback)(async () => {
807
1060
  const res = await apiFetch2(`/api/v1/chat/${agentId}/threads`);
808
1061
  setThreads(await res.json());
809
1062
  }, [apiFetch2, agentId]);
810
- const createThread = (0, import_react6.useCallback)(async () => {
1063
+ const createThread = (0, import_react7.useCallback)(async () => {
811
1064
  const res = await apiFetch2(`/api/v1/chat/${agentId}/threads`, { method: "POST" });
812
1065
  const thread = await res.json();
813
1066
  setActiveThreadId(thread.id);
@@ -815,13 +1068,13 @@ function usePluginChat(agentId) {
815
1068
  await fetchThreads();
816
1069
  return thread;
817
1070
  }, [apiFetch2, agentId, fetchThreads]);
818
- const fetchMessages = (0, import_react6.useCallback)(async (threadId) => {
1071
+ const fetchMessages = (0, import_react7.useCallback)(async (threadId) => {
819
1072
  const res = await apiFetch2(`/api/v1/chat/threads/${threadId}/messages`);
820
1073
  const msgs = await res.json();
821
1074
  setMessages(msgs);
822
1075
  setActiveThreadId(threadId);
823
1076
  }, [apiFetch2]);
824
- const sendMessage = (0, import_react6.useCallback)(async (threadId, content) => {
1077
+ const sendMessage = (0, import_react7.useCallback)(async (threadId, content) => {
825
1078
  setStreaming(true);
826
1079
  abortRef.current = new AbortController();
827
1080
  const userMsg = {
@@ -889,7 +1142,7 @@ function usePluginChat(agentId) {
889
1142
  abortRef.current = null;
890
1143
  }
891
1144
  }, []);
892
- const stopStreaming = (0, import_react6.useCallback)(() => {
1145
+ const stopStreaming = (0, import_react7.useCallback)(() => {
893
1146
  abortRef.current?.abort();
894
1147
  }, []);
895
1148
  return {
@@ -907,8 +1160,10 @@ function usePluginChat(agentId) {
907
1160
  // Annotate the CommonJS export names for ESM import in node:
908
1161
  0 && (module.exports = {
909
1162
  DataRoomClient,
1163
+ Link,
910
1164
  OrganizationClient,
911
1165
  PaletteApiError,
1166
+ PaletteAppRouter,
912
1167
  PlatformCtx,
913
1168
  PluginProvider,
914
1169
  StorageClient,
@@ -919,8 +1174,10 @@ function usePluginChat(agentId) {
919
1174
  createPaletteClient,
920
1175
  createSandboxBridge,
921
1176
  dataRooms,
1177
+ disconnectConnection,
922
1178
  errorFromResponse,
923
1179
  getBaseUrl,
1180
+ getConnections,
924
1181
  getInstallConfig,
925
1182
  hasAllPermissions,
926
1183
  hasAnyPermission,
@@ -928,14 +1185,21 @@ function usePluginChat(agentId) {
928
1185
  isPaletteApiError,
929
1186
  isSandboxRuntime,
930
1187
  normalizePaletteLanguage,
1188
+ notFound,
1189
+ requireConnection,
931
1190
  setBaseUrl,
1191
+ startConnection,
932
1192
  translate,
933
1193
  updateInstallConfig,
934
1194
  uploadToSignedUrl,
1195
+ useParams,
1196
+ usePathname,
935
1197
  usePlatform,
936
1198
  usePluginChat,
937
1199
  usePluginDataRooms,
938
1200
  usePluginTasks,
939
1201
  usePluginTranslations,
1202
+ useRouter,
1203
+ useSearchParams,
940
1204
  withPluginProvider
941
1205
  });