@palettelab/sdk 0.1.15 → 0.1.16
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 +26 -0
- package/dist/components/index.d.mts +1 -1
- package/dist/components/index.d.ts +1 -1
- package/dist/hooks/index.d.mts +2 -2
- package/dist/hooks/index.d.ts +2 -2
- package/dist/{index-Bu5EQGYo.d.mts → index-BGT6xBGD.d.mts} +1 -1
- package/dist/{index-BDVWt7DE.d.ts → index-Beo6F2Fr.d.ts} +1 -1
- package/dist/index.d.mts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +235 -27
- package/dist/index.mjs +236 -26
- package/dist/{plugin-UV46q1mU.d.mts → plugin-CG6spHKI.d.mts} +3 -1
- package/dist/{plugin-UV46q1mU.d.ts → plugin-CG6spHKI.d.ts} +3 -1
- package/dist/router/index.d.mts +346 -0
- package/dist/router/index.d.ts +346 -0
- package/dist/router/index.js +247 -0
- package/dist/router/index.mjs +225 -0
- package/dist/types/index.d.mts +1 -1
- package/dist/types/index.d.ts +1 -1
- package/package.json +6 -1
package/dist/index.mjs
CHANGED
|
@@ -171,6 +171,7 @@ function createMockPlatformContext(overrides = {}) {
|
|
|
171
171
|
apiFetch: async () => new Response(JSON.stringify({}), { status: 200 }),
|
|
172
172
|
navigate: () => {
|
|
173
173
|
},
|
|
174
|
+
routePath: "/",
|
|
174
175
|
showToast: () => {
|
|
175
176
|
},
|
|
176
177
|
...overrides
|
|
@@ -660,14 +661,216 @@ function usePluginTranslations(resources, options = {}) {
|
|
|
660
661
|
};
|
|
661
662
|
}
|
|
662
663
|
|
|
664
|
+
// src/router.tsx
|
|
665
|
+
import {
|
|
666
|
+
Component,
|
|
667
|
+
createContext as createContext2,
|
|
668
|
+
createElement as createElement2,
|
|
669
|
+
useCallback as useCallback2,
|
|
670
|
+
useContext as useContext2,
|
|
671
|
+
useEffect,
|
|
672
|
+
useMemo,
|
|
673
|
+
useState
|
|
674
|
+
} from "react";
|
|
675
|
+
var RouterCtx = createContext2(null);
|
|
676
|
+
var NOT_FOUND = /* @__PURE__ */ Symbol.for("palette.router.not-found");
|
|
677
|
+
function notFound() {
|
|
678
|
+
throw Object.assign(new Error("Palette route not found"), { code: NOT_FOUND });
|
|
679
|
+
}
|
|
680
|
+
function normalizePath(path) {
|
|
681
|
+
const clean = String(path || "/").split("#")[0].split("?")[0] || "/";
|
|
682
|
+
return `/${clean.replace(/^\/+/, "").replace(/\/+$/, "")}`.replace(/^\/$/, "/");
|
|
683
|
+
}
|
|
684
|
+
function splitPath(path) {
|
|
685
|
+
return normalizePath(path).split("/").filter(Boolean).map(decodeURIComponent);
|
|
686
|
+
}
|
|
687
|
+
function routeScore(route) {
|
|
688
|
+
if (typeof route.score === "number") return route.score;
|
|
689
|
+
return route.segments.reduce((score, segment) => {
|
|
690
|
+
if (segment.kind === "static") return score + 10;
|
|
691
|
+
if (segment.kind === "dynamic") return score + 5;
|
|
692
|
+
return score + (segment.optional ? 1 : 2);
|
|
693
|
+
}, route.segments.length);
|
|
694
|
+
}
|
|
695
|
+
function matchRoute(route, path) {
|
|
696
|
+
const parts = splitPath(path);
|
|
697
|
+
const params = {};
|
|
698
|
+
let index = 0;
|
|
699
|
+
for (const segment of route.segments) {
|
|
700
|
+
if (segment.kind === "catchAll") {
|
|
701
|
+
const rest = parts.slice(index);
|
|
702
|
+
if (!segment.optional && rest.length === 0) return null;
|
|
703
|
+
params[segment.name] = rest;
|
|
704
|
+
index = parts.length;
|
|
705
|
+
break;
|
|
706
|
+
}
|
|
707
|
+
const value = parts[index];
|
|
708
|
+
if (value === void 0) return null;
|
|
709
|
+
if (segment.kind === "static") {
|
|
710
|
+
if (value !== segment.value) return null;
|
|
711
|
+
} else {
|
|
712
|
+
params[segment.name] = value;
|
|
713
|
+
}
|
|
714
|
+
index += 1;
|
|
715
|
+
}
|
|
716
|
+
return index === parts.length ? params : null;
|
|
717
|
+
}
|
|
718
|
+
function currentPluginPath(pluginId, routePath) {
|
|
719
|
+
if (routePath) return normalizePath(routePath);
|
|
720
|
+
if (typeof window === "undefined") return "/";
|
|
721
|
+
const path = window.location.pathname;
|
|
722
|
+
if (pluginId) {
|
|
723
|
+
const prefix = `/apps/${pluginId}`;
|
|
724
|
+
if (path === prefix) return "/";
|
|
725
|
+
if (path.startsWith(`${prefix}/`)) return normalizePath(path.slice(prefix.length));
|
|
726
|
+
}
|
|
727
|
+
return normalizePath(path);
|
|
728
|
+
}
|
|
729
|
+
function currentSearchParams() {
|
|
730
|
+
if (typeof window === "undefined") return new URLSearchParams();
|
|
731
|
+
return new URLSearchParams(window.location.search);
|
|
732
|
+
}
|
|
733
|
+
var PaletteRouteErrorBoundary = class extends Component {
|
|
734
|
+
constructor() {
|
|
735
|
+
super(...arguments);
|
|
736
|
+
this.state = { error: null };
|
|
737
|
+
this.reset = () => this.setState({ error: null });
|
|
738
|
+
}
|
|
739
|
+
static getDerivedStateFromError(error) {
|
|
740
|
+
return { error };
|
|
741
|
+
}
|
|
742
|
+
componentDidCatch(_error, _info) {
|
|
743
|
+
}
|
|
744
|
+
render() {
|
|
745
|
+
const error = this.state.error;
|
|
746
|
+
if (!error) return this.props.children;
|
|
747
|
+
if (error.code === NOT_FOUND && this.props.notFound) {
|
|
748
|
+
return createElement2(this.props.notFound);
|
|
749
|
+
}
|
|
750
|
+
if (this.props.fallback) {
|
|
751
|
+
return createElement2(this.props.fallback, { error, reset: this.reset });
|
|
752
|
+
}
|
|
753
|
+
throw error;
|
|
754
|
+
}
|
|
755
|
+
};
|
|
756
|
+
function renderRoute(route) {
|
|
757
|
+
const page = createElement2(route.page);
|
|
758
|
+
const wrapped = (route.layouts || []).reduceRight(
|
|
759
|
+
(children, Layout) => createElement2(Layout, null, children),
|
|
760
|
+
page
|
|
761
|
+
);
|
|
762
|
+
return createElement2(
|
|
763
|
+
PaletteRouteErrorBoundary,
|
|
764
|
+
{ fallback: route.error, notFound: route.notFound },
|
|
765
|
+
wrapped
|
|
766
|
+
);
|
|
767
|
+
}
|
|
768
|
+
function PaletteAppRouter({
|
|
769
|
+
routes,
|
|
770
|
+
notFound: NotFound
|
|
771
|
+
}) {
|
|
772
|
+
const platform = usePlatform();
|
|
773
|
+
const [location, setLocation] = useState(() => ({
|
|
774
|
+
pathname: currentPluginPath(platform.pluginId, platform.routePath),
|
|
775
|
+
searchParams: currentSearchParams()
|
|
776
|
+
}));
|
|
777
|
+
useEffect(() => {
|
|
778
|
+
setLocation({
|
|
779
|
+
pathname: currentPluginPath(platform.pluginId, platform.routePath),
|
|
780
|
+
searchParams: currentSearchParams()
|
|
781
|
+
});
|
|
782
|
+
}, [platform.pluginId, platform.routePath]);
|
|
783
|
+
useEffect(() => {
|
|
784
|
+
const sync = () => setLocation({
|
|
785
|
+
pathname: currentPluginPath(platform.pluginId, platform.routePath),
|
|
786
|
+
searchParams: currentSearchParams()
|
|
787
|
+
});
|
|
788
|
+
window.addEventListener("popstate", sync);
|
|
789
|
+
return () => window.removeEventListener("popstate", sync);
|
|
790
|
+
}, [platform.pluginId, platform.routePath]);
|
|
791
|
+
const sortedRoutes = useMemo(
|
|
792
|
+
() => [...routes].sort((a, b) => routeScore(b) - routeScore(a)),
|
|
793
|
+
[routes]
|
|
794
|
+
);
|
|
795
|
+
const matched = useMemo(() => {
|
|
796
|
+
for (const route of sortedRoutes) {
|
|
797
|
+
const params = matchRoute(route, location.pathname);
|
|
798
|
+
if (params) return { route, params };
|
|
799
|
+
}
|
|
800
|
+
return null;
|
|
801
|
+
}, [location.pathname, sortedRoutes]);
|
|
802
|
+
const navigate = useCallback2((target, replace = false) => {
|
|
803
|
+
const [pathPart, queryPart = ""] = String(target || "/").split("?");
|
|
804
|
+
const pathname = normalizePath(pathPart);
|
|
805
|
+
const next = `${pathname}${queryPart ? `?${queryPart}` : ""}`;
|
|
806
|
+
setLocation({ pathname, searchParams: new URLSearchParams(queryPart) });
|
|
807
|
+
const currentPath = typeof window === "undefined" ? "" : window.location.pathname;
|
|
808
|
+
const inPalettePath = platform.pluginId && (currentPath.startsWith(`/apps/${platform.pluginId}`) || platform.routePath !== void 0);
|
|
809
|
+
const osPath = inPalettePath && platform.pluginId ? `/apps/${platform.pluginId}${pathname === "/" ? "" : pathname}${queryPart ? `?${queryPart}` : ""}` : next;
|
|
810
|
+
if (replace && typeof window !== "undefined") window.history.replaceState(null, "", osPath);
|
|
811
|
+
else platform.navigate(osPath);
|
|
812
|
+
}, [platform]);
|
|
813
|
+
const state = useMemo(() => ({
|
|
814
|
+
pathname: location.pathname,
|
|
815
|
+
searchParams: location.searchParams,
|
|
816
|
+
params: matched?.params || {},
|
|
817
|
+
push: (path) => navigate(path, false),
|
|
818
|
+
replace: (path) => navigate(path, true)
|
|
819
|
+
}), [location.pathname, location.searchParams, matched?.params, navigate]);
|
|
820
|
+
const content = matched ? renderRoute(matched.route) : NotFound ? createElement2(NotFound) : createElement2("div", null, "Page not found");
|
|
821
|
+
return createElement2(RouterCtx.Provider, { value: state }, content);
|
|
822
|
+
}
|
|
823
|
+
function useRouterState() {
|
|
824
|
+
const value = useContext2(RouterCtx);
|
|
825
|
+
if (!value) throw new Error("Palette app router hooks must be used inside PaletteAppRouter");
|
|
826
|
+
return value;
|
|
827
|
+
}
|
|
828
|
+
function useRouter() {
|
|
829
|
+
const { push, replace } = useRouterState();
|
|
830
|
+
return { push, replace, back: () => window.history.back(), forward: () => window.history.forward() };
|
|
831
|
+
}
|
|
832
|
+
function usePathname() {
|
|
833
|
+
return useRouterState().pathname;
|
|
834
|
+
}
|
|
835
|
+
function useSearchParams() {
|
|
836
|
+
return useRouterState().searchParams;
|
|
837
|
+
}
|
|
838
|
+
function useParams() {
|
|
839
|
+
return useRouterState().params;
|
|
840
|
+
}
|
|
841
|
+
function Link({
|
|
842
|
+
href,
|
|
843
|
+
replace,
|
|
844
|
+
onClick,
|
|
845
|
+
children,
|
|
846
|
+
...props
|
|
847
|
+
}) {
|
|
848
|
+
const router = useRouter();
|
|
849
|
+
return createElement2(
|
|
850
|
+
"a",
|
|
851
|
+
{
|
|
852
|
+
...props,
|
|
853
|
+
href,
|
|
854
|
+
onClick: (event) => {
|
|
855
|
+
onClick?.(event);
|
|
856
|
+
if (event.defaultPrevented || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
|
|
857
|
+
event.preventDefault();
|
|
858
|
+
if (replace) router.replace(href);
|
|
859
|
+
else router.push(href);
|
|
860
|
+
}
|
|
861
|
+
},
|
|
862
|
+
children
|
|
863
|
+
);
|
|
864
|
+
}
|
|
865
|
+
|
|
663
866
|
// src/hooks/use-plugin-tasks.ts
|
|
664
|
-
import { useCallback as
|
|
867
|
+
import { useCallback as useCallback3, useEffect as useEffect2, useState as useState2 } from "react";
|
|
665
868
|
function usePluginTasks(agentId) {
|
|
666
869
|
const { apiFetch: apiFetch2 } = usePlatform();
|
|
667
|
-
const [tasks, setTasks] =
|
|
668
|
-
const [stats, setStats] =
|
|
669
|
-
const [loading, setLoading] =
|
|
670
|
-
const fetchTasks =
|
|
870
|
+
const [tasks, setTasks] = useState2([]);
|
|
871
|
+
const [stats, setStats] = useState2(null);
|
|
872
|
+
const [loading, setLoading] = useState2(true);
|
|
873
|
+
const fetchTasks = useCallback3(async () => {
|
|
671
874
|
try {
|
|
672
875
|
const params = new URLSearchParams();
|
|
673
876
|
if (agentId) params.set("agent_id", String(agentId));
|
|
@@ -676,18 +879,18 @@ function usePluginTasks(agentId) {
|
|
|
676
879
|
} catch {
|
|
677
880
|
}
|
|
678
881
|
}, [apiFetch2, agentId]);
|
|
679
|
-
const fetchStats =
|
|
882
|
+
const fetchStats = useCallback3(async () => {
|
|
680
883
|
try {
|
|
681
884
|
const res = await apiFetch2("/api/v1/tasks/stats");
|
|
682
885
|
setStats(await res.json());
|
|
683
886
|
} catch {
|
|
684
887
|
}
|
|
685
888
|
}, [apiFetch2]);
|
|
686
|
-
|
|
889
|
+
useEffect2(() => {
|
|
687
890
|
setLoading(true);
|
|
688
891
|
Promise.all([fetchTasks(), fetchStats()]).finally(() => setLoading(false));
|
|
689
892
|
}, [fetchTasks, fetchStats]);
|
|
690
|
-
const createTask =
|
|
893
|
+
const createTask = useCallback3(async (payload) => {
|
|
691
894
|
const res = await apiFetch2("/api/v1/tasks", {
|
|
692
895
|
method: "POST",
|
|
693
896
|
body: JSON.stringify(payload)
|
|
@@ -696,7 +899,7 @@ function usePluginTasks(agentId) {
|
|
|
696
899
|
await Promise.all([fetchTasks(), fetchStats()]);
|
|
697
900
|
return task;
|
|
698
901
|
}, [apiFetch2, fetchTasks, fetchStats]);
|
|
699
|
-
const updateTask =
|
|
902
|
+
const updateTask = useCallback3(async (taskId, payload) => {
|
|
700
903
|
const res = await apiFetch2(`/api/v1/tasks/${taskId}`, {
|
|
701
904
|
method: "PATCH",
|
|
702
905
|
body: JSON.stringify(payload)
|
|
@@ -705,7 +908,7 @@ function usePluginTasks(agentId) {
|
|
|
705
908
|
await Promise.all([fetchTasks(), fetchStats()]);
|
|
706
909
|
return task;
|
|
707
910
|
}, [apiFetch2, fetchTasks, fetchStats]);
|
|
708
|
-
const deleteTask =
|
|
911
|
+
const deleteTask = useCallback3(async (taskId) => {
|
|
709
912
|
await apiFetch2(`/api/v1/tasks/${taskId}`, { method: "DELETE" });
|
|
710
913
|
await Promise.all([fetchTasks(), fetchStats()]);
|
|
711
914
|
}, [apiFetch2, fetchTasks, fetchStats]);
|
|
@@ -713,23 +916,23 @@ function usePluginTasks(agentId) {
|
|
|
713
916
|
}
|
|
714
917
|
|
|
715
918
|
// src/hooks/use-plugin-data-rooms.ts
|
|
716
|
-
import { useCallback as
|
|
919
|
+
import { useCallback as useCallback4, useEffect as useEffect3, useState as useState3 } from "react";
|
|
717
920
|
function usePluginDataRooms() {
|
|
718
921
|
const { apiFetch: apiFetch2 } = usePlatform();
|
|
719
|
-
const [rooms, setRooms] =
|
|
720
|
-
const [loading, setLoading] =
|
|
721
|
-
const fetchRooms =
|
|
922
|
+
const [rooms, setRooms] = useState3([]);
|
|
923
|
+
const [loading, setLoading] = useState3(true);
|
|
924
|
+
const fetchRooms = useCallback4(async () => {
|
|
722
925
|
try {
|
|
723
926
|
const res = await apiFetch2("/api/v1/data-rooms");
|
|
724
927
|
setRooms(await res.json());
|
|
725
928
|
} catch {
|
|
726
929
|
}
|
|
727
930
|
}, [apiFetch2]);
|
|
728
|
-
|
|
931
|
+
useEffect3(() => {
|
|
729
932
|
setLoading(true);
|
|
730
933
|
fetchRooms().finally(() => setLoading(false));
|
|
731
934
|
}, [fetchRooms]);
|
|
732
|
-
const fetchFolder =
|
|
935
|
+
const fetchFolder = useCallback4(async (roomId, folderId) => {
|
|
733
936
|
const path = folderId ? `/api/v1/data-rooms/${roomId}/folders/${folderId}` : `/api/v1/data-rooms/${roomId}`;
|
|
734
937
|
const res = await apiFetch2(path);
|
|
735
938
|
return res.json();
|
|
@@ -738,19 +941,19 @@ function usePluginDataRooms() {
|
|
|
738
941
|
}
|
|
739
942
|
|
|
740
943
|
// src/hooks/use-plugin-chat.ts
|
|
741
|
-
import { useCallback as
|
|
944
|
+
import { useCallback as useCallback5, useRef, useState as useState4 } from "react";
|
|
742
945
|
function usePluginChat(agentId) {
|
|
743
946
|
const { apiFetch: apiFetch2 } = usePlatform();
|
|
744
|
-
const [threads, setThreads] =
|
|
745
|
-
const [messages, setMessages] =
|
|
746
|
-
const [streaming, setStreaming] =
|
|
747
|
-
const [activeThreadId, setActiveThreadId] =
|
|
947
|
+
const [threads, setThreads] = useState4([]);
|
|
948
|
+
const [messages, setMessages] = useState4([]);
|
|
949
|
+
const [streaming, setStreaming] = useState4(false);
|
|
950
|
+
const [activeThreadId, setActiveThreadId] = useState4(null);
|
|
748
951
|
const abortRef = useRef(null);
|
|
749
|
-
const fetchThreads =
|
|
952
|
+
const fetchThreads = useCallback5(async () => {
|
|
750
953
|
const res = await apiFetch2(`/api/v1/chat/${agentId}/threads`);
|
|
751
954
|
setThreads(await res.json());
|
|
752
955
|
}, [apiFetch2, agentId]);
|
|
753
|
-
const createThread =
|
|
956
|
+
const createThread = useCallback5(async () => {
|
|
754
957
|
const res = await apiFetch2(`/api/v1/chat/${agentId}/threads`, { method: "POST" });
|
|
755
958
|
const thread = await res.json();
|
|
756
959
|
setActiveThreadId(thread.id);
|
|
@@ -758,13 +961,13 @@ function usePluginChat(agentId) {
|
|
|
758
961
|
await fetchThreads();
|
|
759
962
|
return thread;
|
|
760
963
|
}, [apiFetch2, agentId, fetchThreads]);
|
|
761
|
-
const fetchMessages =
|
|
964
|
+
const fetchMessages = useCallback5(async (threadId) => {
|
|
762
965
|
const res = await apiFetch2(`/api/v1/chat/threads/${threadId}/messages`);
|
|
763
966
|
const msgs = await res.json();
|
|
764
967
|
setMessages(msgs);
|
|
765
968
|
setActiveThreadId(threadId);
|
|
766
969
|
}, [apiFetch2]);
|
|
767
|
-
const sendMessage =
|
|
970
|
+
const sendMessage = useCallback5(async (threadId, content) => {
|
|
768
971
|
setStreaming(true);
|
|
769
972
|
abortRef.current = new AbortController();
|
|
770
973
|
const userMsg = {
|
|
@@ -832,7 +1035,7 @@ function usePluginChat(agentId) {
|
|
|
832
1035
|
abortRef.current = null;
|
|
833
1036
|
}
|
|
834
1037
|
}, []);
|
|
835
|
-
const stopStreaming =
|
|
1038
|
+
const stopStreaming = useCallback5(() => {
|
|
836
1039
|
abortRef.current?.abort();
|
|
837
1040
|
}, []);
|
|
838
1041
|
return {
|
|
@@ -849,8 +1052,10 @@ function usePluginChat(agentId) {
|
|
|
849
1052
|
}
|
|
850
1053
|
export {
|
|
851
1054
|
DataRoomClient,
|
|
1055
|
+
Link,
|
|
852
1056
|
OrganizationClient,
|
|
853
1057
|
PaletteApiError,
|
|
1058
|
+
PaletteAppRouter,
|
|
854
1059
|
PlatformCtx,
|
|
855
1060
|
PluginProvider,
|
|
856
1061
|
StorageClient,
|
|
@@ -870,14 +1075,19 @@ export {
|
|
|
870
1075
|
isPaletteApiError,
|
|
871
1076
|
isSandboxRuntime,
|
|
872
1077
|
normalizePaletteLanguage,
|
|
1078
|
+
notFound,
|
|
873
1079
|
setBaseUrl,
|
|
874
1080
|
translate,
|
|
875
1081
|
updateInstallConfig,
|
|
876
1082
|
uploadToSignedUrl,
|
|
1083
|
+
useParams,
|
|
1084
|
+
usePathname,
|
|
877
1085
|
usePlatform,
|
|
878
1086
|
usePluginChat,
|
|
879
1087
|
usePluginDataRooms,
|
|
880
1088
|
usePluginTasks,
|
|
881
1089
|
usePluginTranslations,
|
|
1090
|
+
useRouter,
|
|
1091
|
+
useSearchParams,
|
|
882
1092
|
withPluginProvider
|
|
883
1093
|
};
|
|
@@ -106,7 +106,7 @@ interface PluginManifest {
|
|
|
106
106
|
frontend?: {
|
|
107
107
|
entry: string;
|
|
108
108
|
sandbox?: boolean;
|
|
109
|
-
framework?: "react" | "next";
|
|
109
|
+
framework?: "react" | "next" | "palette-app";
|
|
110
110
|
config?: string;
|
|
111
111
|
};
|
|
112
112
|
backend?: {
|
|
@@ -165,6 +165,8 @@ interface PlatformContext {
|
|
|
165
165
|
apiFetch: (path: string, init?: RequestInit) => Promise<Response>;
|
|
166
166
|
/** Navigate to a platform route */
|
|
167
167
|
navigate: (path: string) => void;
|
|
168
|
+
/** Current route path within the plugin app, when mounted by Palette OS */
|
|
169
|
+
routePath?: string;
|
|
168
170
|
/** Show a toast notification */
|
|
169
171
|
showToast: (message: string, type?: "success" | "error" | "info") => void;
|
|
170
172
|
/** Permissions declared for the current plugin install/runtime */
|
|
@@ -106,7 +106,7 @@ interface PluginManifest {
|
|
|
106
106
|
frontend?: {
|
|
107
107
|
entry: string;
|
|
108
108
|
sandbox?: boolean;
|
|
109
|
-
framework?: "react" | "next";
|
|
109
|
+
framework?: "react" | "next" | "palette-app";
|
|
110
110
|
config?: string;
|
|
111
111
|
};
|
|
112
112
|
backend?: {
|
|
@@ -165,6 +165,8 @@ interface PlatformContext {
|
|
|
165
165
|
apiFetch: (path: string, init?: RequestInit) => Promise<Response>;
|
|
166
166
|
/** Navigate to a platform route */
|
|
167
167
|
navigate: (path: string) => void;
|
|
168
|
+
/** Current route path within the plugin app, when mounted by Palette OS */
|
|
169
|
+
routePath?: string;
|
|
168
170
|
/** Show a toast notification */
|
|
169
171
|
showToast: (message: string, type?: "success" | "error" | "info") => void;
|
|
170
172
|
/** Permissions declared for the current plugin install/runtime */
|