@palettelab/sdk 0.1.10 → 0.1.11

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 CHANGED
@@ -122,6 +122,7 @@ import {
122
122
  PluginProvider,
123
123
  usePlatform,
124
124
  createPaletteClient,
125
+ usePluginTranslations,
125
126
  usePluginTasks,
126
127
  usePluginDataRooms,
127
128
  usePluginChat,
@@ -169,6 +170,37 @@ export default function PluginRoot(props: PluginComponentProps) {
169
170
  }
170
171
  ```
171
172
 
173
+ ## App Translations And OS Language
174
+
175
+ Palette OS passes the current global language into every plugin through
176
+ `usePlatform()`. Keep translations in your app repo, then let the SDK choose the
177
+ right language.
178
+
179
+ ```tsx
180
+ import { usePluginTranslations, type TranslationResources } from "@palettelab/sdk"
181
+
182
+ const resources = {
183
+ en: { title: "Invoices", greeting: "Hello, {{name}}" },
184
+ ko: { title: "청구서", greeting: "안녕하세요, {{name}}님" },
185
+ } satisfies TranslationResources
186
+
187
+ function App() {
188
+ const { t, language, setLanguage } = usePluginTranslations(resources)
189
+
190
+ return (
191
+ <main>
192
+ <h1>{t("title")}</h1>
193
+ <button onClick={() => setLanguage(language === "ko" ? "en" : "ko")}>
194
+ {language === "ko" ? "EN" : "KO"}
195
+ </button>
196
+ </main>
197
+ )
198
+ }
199
+ ```
200
+
201
+ The same context is available in `pltt dev`, so local development and OS runtime
202
+ use the same translation path.
203
+
172
204
  ## Palette Client
173
205
 
174
206
  Use `createPaletteClient()` when an app needs common Palette OS services without
@@ -332,7 +364,7 @@ Use the SDK test utilities to render plugin components with a mock platform cont
332
364
  import { createMockPlatformContext, withPluginProvider } from "@palettelab/sdk"
333
365
 
334
366
  const ctx = createMockPlatformContext({
335
- pluginId: "hello-sdk",
367
+ pluginId: "my-plugin",
336
368
  organizationId: 1,
337
369
  })
338
370
 
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import react__default from 'react';
3
- import { P as PlatformContext } from '../plugin-o-qmdCBl.mjs';
3
+ import { P as PlatformContext } from '../plugin-DZRaxKt3.mjs';
4
4
 
5
5
  /**
6
6
  * Provider that wraps plugin components with the platform context.
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import react__default from 'react';
3
- import { P as PlatformContext } from '../plugin-o-qmdCBl.js';
3
+ import { P as PlatformContext } from '../plugin-DZRaxKt3.js';
4
4
 
5
5
  /**
6
6
  * Provider that wraps plugin components with the platform context.
@@ -1,71 +1,4 @@
1
- import * as react from 'react';
2
- import { P as PlatformContext } from '../plugin-o-qmdCBl.mjs';
3
- import { T as Task, i as TaskStats, g as TaskCreatePayload, l as TaskUpdatePayload, D as DataRoom, a as DataRoomFolder, b as DataRoomFile, d as ChatThread, c as ChatMessage } from '../data-room-Dtd9LLHf.mjs';
4
-
5
- /**
6
- * React context for platform services.
7
- * The platform runtime provides this — plugin developers consume it.
8
- */
9
- declare const PlatformCtx: react.Context<PlatformContext | null>;
10
- /**
11
- * Access the platform context from within a plugin component.
12
- *
13
- * Provides: user, organizationId, agents, apiFetch, navigate, showToast
14
- *
15
- * @example
16
- * ```tsx
17
- * import { usePlatform } from "@palettelab/sdk/hooks"
18
- *
19
- * function MyPlugin() {
20
- * const { user, apiFetch, showToast } = usePlatform()
21
- * // ...
22
- * }
23
- * ```
24
- */
25
- declare function usePlatform(): PlatformContext;
26
-
27
- /**
28
- * Hook for managing tasks from within a plugin.
29
- *
30
- * @param agentId - Optional agent ID to filter tasks
31
- */
32
- declare function usePluginTasks(agentId?: number): {
33
- tasks: Task[];
34
- stats: TaskStats | null;
35
- loading: boolean;
36
- createTask: (payload: TaskCreatePayload) => Promise<Task>;
37
- updateTask: (taskId: number, payload: TaskUpdatePayload) => Promise<Task>;
38
- deleteTask: (taskId: number) => Promise<void>;
39
- refetch: () => Promise<void>;
40
- };
41
-
42
- /**
43
- * Hook for accessing data rooms from within a plugin.
44
- */
45
- declare function usePluginDataRooms(): {
46
- rooms: DataRoom[];
47
- loading: boolean;
48
- fetchFolder: (roomId: number, folderId?: number) => Promise<{
49
- folders: DataRoomFolder[];
50
- files: DataRoomFile[];
51
- }>;
52
- refetch: () => Promise<void>;
53
- };
54
-
55
- /**
56
- * Hook for chat functionality within a plugin.
57
- * Supports creating threads, sending messages, and SSE streaming.
58
- */
59
- declare function usePluginChat(agentId: number): {
60
- threads: ChatThread[];
61
- messages: ChatMessage[];
62
- streaming: boolean;
63
- activeThreadId: string | null;
64
- fetchThreads: () => Promise<void>;
65
- createThread: () => Promise<ChatThread>;
66
- fetchMessages: (threadId: string) => Promise<void>;
67
- sendMessage: (threadId: string, content: string) => Promise<void>;
68
- stopStreaming: () => void;
69
- };
70
-
71
- export { PlatformCtx, usePlatform, usePluginChat, usePluginDataRooms, usePluginTasks };
1
+ export { P as PlatformCtx, u as usePlatform, e as usePluginChat, f as usePluginDataRooms, g as usePluginTasks, h as usePluginTranslations } from '../index-BL37Z-Ns.mjs';
2
+ import 'react';
3
+ import '../plugin-DZRaxKt3.mjs';
4
+ import '../data-room-Dtd9LLHf.mjs';
@@ -1,71 +1,4 @@
1
- import * as react from 'react';
2
- import { P as PlatformContext } from '../plugin-o-qmdCBl.js';
3
- import { T as Task, i as TaskStats, g as TaskCreatePayload, l as TaskUpdatePayload, D as DataRoom, a as DataRoomFolder, b as DataRoomFile, d as ChatThread, c as ChatMessage } from '../data-room-Dtd9LLHf.js';
4
-
5
- /**
6
- * React context for platform services.
7
- * The platform runtime provides this — plugin developers consume it.
8
- */
9
- declare const PlatformCtx: react.Context<PlatformContext | null>;
10
- /**
11
- * Access the platform context from within a plugin component.
12
- *
13
- * Provides: user, organizationId, agents, apiFetch, navigate, showToast
14
- *
15
- * @example
16
- * ```tsx
17
- * import { usePlatform } from "@palettelab/sdk/hooks"
18
- *
19
- * function MyPlugin() {
20
- * const { user, apiFetch, showToast } = usePlatform()
21
- * // ...
22
- * }
23
- * ```
24
- */
25
- declare function usePlatform(): PlatformContext;
26
-
27
- /**
28
- * Hook for managing tasks from within a plugin.
29
- *
30
- * @param agentId - Optional agent ID to filter tasks
31
- */
32
- declare function usePluginTasks(agentId?: number): {
33
- tasks: Task[];
34
- stats: TaskStats | null;
35
- loading: boolean;
36
- createTask: (payload: TaskCreatePayload) => Promise<Task>;
37
- updateTask: (taskId: number, payload: TaskUpdatePayload) => Promise<Task>;
38
- deleteTask: (taskId: number) => Promise<void>;
39
- refetch: () => Promise<void>;
40
- };
41
-
42
- /**
43
- * Hook for accessing data rooms from within a plugin.
44
- */
45
- declare function usePluginDataRooms(): {
46
- rooms: DataRoom[];
47
- loading: boolean;
48
- fetchFolder: (roomId: number, folderId?: number) => Promise<{
49
- folders: DataRoomFolder[];
50
- files: DataRoomFile[];
51
- }>;
52
- refetch: () => Promise<void>;
53
- };
54
-
55
- /**
56
- * Hook for chat functionality within a plugin.
57
- * Supports creating threads, sending messages, and SSE streaming.
58
- */
59
- declare function usePluginChat(agentId: number): {
60
- threads: ChatThread[];
61
- messages: ChatMessage[];
62
- streaming: boolean;
63
- activeThreadId: string | null;
64
- fetchThreads: () => Promise<void>;
65
- createThread: () => Promise<ChatThread>;
66
- fetchMessages: (threadId: string) => Promise<void>;
67
- sendMessage: (threadId: string, content: string) => Promise<void>;
68
- stopStreaming: () => void;
69
- };
70
-
71
- export { PlatformCtx, usePlatform, usePluginChat, usePluginDataRooms, usePluginTasks };
1
+ export { P as PlatformCtx, u as usePlatform, e as usePluginChat, f as usePluginDataRooms, g as usePluginTasks, h as usePluginTranslations } from '../index-DEvPH60n.js';
2
+ import 'react';
3
+ import '../plugin-DZRaxKt3.js';
4
+ import '../data-room-Dtd9LLHf.js';
@@ -24,7 +24,8 @@ __export(hooks_exports, {
24
24
  usePlatform: () => usePlatform,
25
25
  usePluginChat: () => usePluginChat,
26
26
  usePluginDataRooms: () => usePluginDataRooms,
27
- usePluginTasks: () => usePluginTasks
27
+ usePluginTasks: () => usePluginTasks,
28
+ usePluginTranslations: () => usePluginTranslations
28
29
  });
29
30
  module.exports = __toCommonJS(hooks_exports);
30
31
 
@@ -242,11 +243,75 @@ function usePluginChat(agentId) {
242
243
  stopStreaming
243
244
  };
244
245
  }
246
+
247
+ // src/i18n.ts
248
+ var import_react5 = require("react");
249
+ function normalizePaletteLanguage(language, fallback = "en") {
250
+ const trimmed = language?.trim().toLowerCase();
251
+ if (!trimmed) return fallback;
252
+ return trimmed.split("-")[0] || fallback;
253
+ }
254
+ function languageCandidates(language, fallbackLanguage = "en") {
255
+ const candidates = [
256
+ language,
257
+ normalizePaletteLanguage(language, fallbackLanguage),
258
+ fallbackLanguage,
259
+ normalizePaletteLanguage(fallbackLanguage, "en"),
260
+ "en"
261
+ ].filter(Boolean);
262
+ return Array.from(new Set(candidates));
263
+ }
264
+ function getValue(dictionary, key) {
265
+ if (!dictionary) return void 0;
266
+ let current = dictionary;
267
+ for (const part of key.split(".")) {
268
+ if (current === null || typeof current !== "object" || Array.isArray(current)) return void 0;
269
+ current = current[part];
270
+ }
271
+ if (typeof current === "string" || typeof current === "number" || typeof current === "boolean" || current === null) {
272
+ return current;
273
+ }
274
+ return void 0;
275
+ }
276
+ function interpolate(template, values) {
277
+ if (!values) return template;
278
+ return template.replace(/\{\{?\s*([a-zA-Z0-9_.-]+)\s*\}?\}/g, (match, key) => {
279
+ const value = values[key];
280
+ return value === void 0 || value === null ? match : String(value);
281
+ });
282
+ }
283
+ function translate(resources, key, options = {}) {
284
+ const fallbackLanguage = normalizePaletteLanguage(options.fallbackLanguage, "en");
285
+ for (const language of languageCandidates(options.language, fallbackLanguage)) {
286
+ const value = getValue(resources[language], key);
287
+ if (value !== void 0) {
288
+ return interpolate(String(value ?? ""), options.values);
289
+ }
290
+ }
291
+ return interpolate(options.defaultValue ?? key, options.values);
292
+ }
293
+ function usePluginTranslations(resources, options = {}) {
294
+ const platform = usePlatform();
295
+ const language = normalizePaletteLanguage(platform.language, options.fallbackLanguage ?? platform.fallbackLanguage);
296
+ const fallbackLanguage = normalizePaletteLanguage(options.fallbackLanguage ?? platform.fallbackLanguage, "en");
297
+ const t = (0, import_react5.useCallback)(
298
+ (key, values, defaultValue) => translate(resources, key, { language, fallbackLanguage, values, defaultValue }),
299
+ [fallbackLanguage, language, resources]
300
+ );
301
+ return {
302
+ language,
303
+ fallbackLanguage,
304
+ supportedLanguages: platform.supportedLanguages,
305
+ setLanguage: platform.setLanguage,
306
+ t
307
+ };
308
+ }
245
309
  // Annotate the CommonJS export names for ESM import in node:
246
310
  0 && (module.exports = {
247
311
  PlatformCtx,
248
312
  usePlatform,
249
313
  usePluginChat,
250
314
  usePluginDataRooms,
251
- usePluginTasks
315
+ usePluginTasks,
316
+ usePluginTranslations
252
317
  });
@@ -212,10 +212,74 @@ function usePluginChat(agentId) {
212
212
  stopStreaming
213
213
  };
214
214
  }
215
+
216
+ // src/i18n.ts
217
+ import { useCallback as useCallback4 } from "react";
218
+ function normalizePaletteLanguage(language, fallback = "en") {
219
+ const trimmed = language?.trim().toLowerCase();
220
+ if (!trimmed) return fallback;
221
+ return trimmed.split("-")[0] || fallback;
222
+ }
223
+ function languageCandidates(language, fallbackLanguage = "en") {
224
+ const candidates = [
225
+ language,
226
+ normalizePaletteLanguage(language, fallbackLanguage),
227
+ fallbackLanguage,
228
+ normalizePaletteLanguage(fallbackLanguage, "en"),
229
+ "en"
230
+ ].filter(Boolean);
231
+ return Array.from(new Set(candidates));
232
+ }
233
+ function getValue(dictionary, key) {
234
+ if (!dictionary) return void 0;
235
+ let current = dictionary;
236
+ for (const part of key.split(".")) {
237
+ if (current === null || typeof current !== "object" || Array.isArray(current)) return void 0;
238
+ current = current[part];
239
+ }
240
+ if (typeof current === "string" || typeof current === "number" || typeof current === "boolean" || current === null) {
241
+ return current;
242
+ }
243
+ return void 0;
244
+ }
245
+ function interpolate(template, values) {
246
+ if (!values) return template;
247
+ return template.replace(/\{\{?\s*([a-zA-Z0-9_.-]+)\s*\}?\}/g, (match, key) => {
248
+ const value = values[key];
249
+ return value === void 0 || value === null ? match : String(value);
250
+ });
251
+ }
252
+ function translate(resources, key, options = {}) {
253
+ const fallbackLanguage = normalizePaletteLanguage(options.fallbackLanguage, "en");
254
+ for (const language of languageCandidates(options.language, fallbackLanguage)) {
255
+ const value = getValue(resources[language], key);
256
+ if (value !== void 0) {
257
+ return interpolate(String(value ?? ""), options.values);
258
+ }
259
+ }
260
+ return interpolate(options.defaultValue ?? key, options.values);
261
+ }
262
+ function usePluginTranslations(resources, options = {}) {
263
+ const platform = usePlatform();
264
+ const language = normalizePaletteLanguage(platform.language, options.fallbackLanguage ?? platform.fallbackLanguage);
265
+ const fallbackLanguage = normalizePaletteLanguage(options.fallbackLanguage ?? platform.fallbackLanguage, "en");
266
+ const t = useCallback4(
267
+ (key, values, defaultValue) => translate(resources, key, { language, fallbackLanguage, values, defaultValue }),
268
+ [fallbackLanguage, language, resources]
269
+ );
270
+ return {
271
+ language,
272
+ fallbackLanguage,
273
+ supportedLanguages: platform.supportedLanguages,
274
+ setLanguage: platform.setLanguage,
275
+ t
276
+ };
277
+ }
215
278
  export {
216
279
  PlatformCtx,
217
280
  usePlatform,
218
281
  usePluginChat,
219
282
  usePluginDataRooms,
220
- usePluginTasks
283
+ usePluginTasks,
284
+ usePluginTranslations
221
285
  };
@@ -0,0 +1,96 @@
1
+ import * as react from 'react';
2
+ import { d as PaletteLanguage, P as PlatformContext } from './plugin-DZRaxKt3.mjs';
3
+ import { T as Task, i as TaskStats, g as TaskCreatePayload, l as TaskUpdatePayload, D as DataRoom, a as DataRoomFolder, b as DataRoomFile, d as ChatThread, c as ChatMessage } from './data-room-Dtd9LLHf.mjs';
4
+
5
+ type TranslationPrimitive = string | number | boolean | null;
6
+ type TranslationDictionary = {
7
+ [key: string]: TranslationPrimitive | TranslationDictionary;
8
+ };
9
+ type TranslationResources = Record<PaletteLanguage, TranslationDictionary>;
10
+ type TranslationValues = Record<string, string | number | boolean | null | undefined>;
11
+ interface TranslateOptions {
12
+ language?: PaletteLanguage;
13
+ fallbackLanguage?: PaletteLanguage;
14
+ defaultValue?: string;
15
+ values?: TranslationValues;
16
+ }
17
+ interface UsePluginTranslationsOptions {
18
+ fallbackLanguage?: PaletteLanguage;
19
+ }
20
+ declare function normalizePaletteLanguage(language?: string | null, fallback?: PaletteLanguage): PaletteLanguage;
21
+ declare function translate(resources: TranslationResources, key: string, options?: TranslateOptions): string;
22
+ declare function usePluginTranslations(resources: TranslationResources, options?: UsePluginTranslationsOptions): {
23
+ language: string;
24
+ fallbackLanguage: string;
25
+ supportedLanguages: string[];
26
+ setLanguage: (language: PaletteLanguage) => void;
27
+ t: (key: string, values?: TranslationValues, defaultValue?: string) => string;
28
+ };
29
+
30
+ /**
31
+ * React context for platform services.
32
+ * The platform runtime provides this — plugin developers consume it.
33
+ */
34
+ declare const PlatformCtx: react.Context<PlatformContext | null>;
35
+ /**
36
+ * Access the platform context from within a plugin component.
37
+ *
38
+ * Provides: user, organizationId, agents, apiFetch, navigate, showToast
39
+ *
40
+ * @example
41
+ * ```tsx
42
+ * import { usePlatform } from "@palettelab/sdk/hooks"
43
+ *
44
+ * function MyPlugin() {
45
+ * const { user, apiFetch, showToast } = usePlatform()
46
+ * // ...
47
+ * }
48
+ * ```
49
+ */
50
+ declare function usePlatform(): PlatformContext;
51
+
52
+ /**
53
+ * Hook for managing tasks from within a plugin.
54
+ *
55
+ * @param agentId - Optional agent ID to filter tasks
56
+ */
57
+ declare function usePluginTasks(agentId?: number): {
58
+ tasks: Task[];
59
+ stats: TaskStats | null;
60
+ loading: boolean;
61
+ createTask: (payload: TaskCreatePayload) => Promise<Task>;
62
+ updateTask: (taskId: number, payload: TaskUpdatePayload) => Promise<Task>;
63
+ deleteTask: (taskId: number) => Promise<void>;
64
+ refetch: () => Promise<void>;
65
+ };
66
+
67
+ /**
68
+ * Hook for accessing data rooms from within a plugin.
69
+ */
70
+ declare function usePluginDataRooms(): {
71
+ rooms: DataRoom[];
72
+ loading: boolean;
73
+ fetchFolder: (roomId: number, folderId?: number) => Promise<{
74
+ folders: DataRoomFolder[];
75
+ files: DataRoomFile[];
76
+ }>;
77
+ refetch: () => Promise<void>;
78
+ };
79
+
80
+ /**
81
+ * Hook for chat functionality within a plugin.
82
+ * Supports creating threads, sending messages, and SSE streaming.
83
+ */
84
+ declare function usePluginChat(agentId: number): {
85
+ threads: ChatThread[];
86
+ messages: ChatMessage[];
87
+ streaming: boolean;
88
+ activeThreadId: string | null;
89
+ fetchThreads: () => Promise<void>;
90
+ createThread: () => Promise<ChatThread>;
91
+ fetchMessages: (threadId: string) => Promise<void>;
92
+ sendMessage: (threadId: string, content: string) => Promise<void>;
93
+ stopStreaming: () => void;
94
+ };
95
+
96
+ export { PlatformCtx as P, type TranslateOptions as T, type UsePluginTranslationsOptions as U, type TranslationDictionary as a, type TranslationPrimitive as b, type TranslationResources as c, type TranslationValues as d, usePluginChat as e, usePluginDataRooms as f, usePluginTasks as g, usePluginTranslations as h, normalizePaletteLanguage as n, translate as t, usePlatform as u };
@@ -0,0 +1,96 @@
1
+ import * as react from 'react';
2
+ import { d as PaletteLanguage, P as PlatformContext } from './plugin-DZRaxKt3.js';
3
+ import { T as Task, i as TaskStats, g as TaskCreatePayload, l as TaskUpdatePayload, D as DataRoom, a as DataRoomFolder, b as DataRoomFile, d as ChatThread, c as ChatMessage } from './data-room-Dtd9LLHf.js';
4
+
5
+ type TranslationPrimitive = string | number | boolean | null;
6
+ type TranslationDictionary = {
7
+ [key: string]: TranslationPrimitive | TranslationDictionary;
8
+ };
9
+ type TranslationResources = Record<PaletteLanguage, TranslationDictionary>;
10
+ type TranslationValues = Record<string, string | number | boolean | null | undefined>;
11
+ interface TranslateOptions {
12
+ language?: PaletteLanguage;
13
+ fallbackLanguage?: PaletteLanguage;
14
+ defaultValue?: string;
15
+ values?: TranslationValues;
16
+ }
17
+ interface UsePluginTranslationsOptions {
18
+ fallbackLanguage?: PaletteLanguage;
19
+ }
20
+ declare function normalizePaletteLanguage(language?: string | null, fallback?: PaletteLanguage): PaletteLanguage;
21
+ declare function translate(resources: TranslationResources, key: string, options?: TranslateOptions): string;
22
+ declare function usePluginTranslations(resources: TranslationResources, options?: UsePluginTranslationsOptions): {
23
+ language: string;
24
+ fallbackLanguage: string;
25
+ supportedLanguages: string[];
26
+ setLanguage: (language: PaletteLanguage) => void;
27
+ t: (key: string, values?: TranslationValues, defaultValue?: string) => string;
28
+ };
29
+
30
+ /**
31
+ * React context for platform services.
32
+ * The platform runtime provides this — plugin developers consume it.
33
+ */
34
+ declare const PlatformCtx: react.Context<PlatformContext | null>;
35
+ /**
36
+ * Access the platform context from within a plugin component.
37
+ *
38
+ * Provides: user, organizationId, agents, apiFetch, navigate, showToast
39
+ *
40
+ * @example
41
+ * ```tsx
42
+ * import { usePlatform } from "@palettelab/sdk/hooks"
43
+ *
44
+ * function MyPlugin() {
45
+ * const { user, apiFetch, showToast } = usePlatform()
46
+ * // ...
47
+ * }
48
+ * ```
49
+ */
50
+ declare function usePlatform(): PlatformContext;
51
+
52
+ /**
53
+ * Hook for managing tasks from within a plugin.
54
+ *
55
+ * @param agentId - Optional agent ID to filter tasks
56
+ */
57
+ declare function usePluginTasks(agentId?: number): {
58
+ tasks: Task[];
59
+ stats: TaskStats | null;
60
+ loading: boolean;
61
+ createTask: (payload: TaskCreatePayload) => Promise<Task>;
62
+ updateTask: (taskId: number, payload: TaskUpdatePayload) => Promise<Task>;
63
+ deleteTask: (taskId: number) => Promise<void>;
64
+ refetch: () => Promise<void>;
65
+ };
66
+
67
+ /**
68
+ * Hook for accessing data rooms from within a plugin.
69
+ */
70
+ declare function usePluginDataRooms(): {
71
+ rooms: DataRoom[];
72
+ loading: boolean;
73
+ fetchFolder: (roomId: number, folderId?: number) => Promise<{
74
+ folders: DataRoomFolder[];
75
+ files: DataRoomFile[];
76
+ }>;
77
+ refetch: () => Promise<void>;
78
+ };
79
+
80
+ /**
81
+ * Hook for chat functionality within a plugin.
82
+ * Supports creating threads, sending messages, and SSE streaming.
83
+ */
84
+ declare function usePluginChat(agentId: number): {
85
+ threads: ChatThread[];
86
+ messages: ChatMessage[];
87
+ streaming: boolean;
88
+ activeThreadId: string | null;
89
+ fetchThreads: () => Promise<void>;
90
+ createThread: () => Promise<ChatThread>;
91
+ fetchMessages: (threadId: string) => Promise<void>;
92
+ sendMessage: (threadId: string, content: string) => Promise<void>;
93
+ stopStreaming: () => void;
94
+ };
95
+
96
+ export { PlatformCtx as P, type TranslateOptions as T, type UsePluginTranslationsOptions as U, type TranslationDictionary as a, type TranslationPrimitive as b, type TranslationResources as c, type TranslationValues as d, usePluginChat as e, usePluginDataRooms as f, usePluginTasks as g, usePluginTranslations as h, normalizePaletteLanguage as n, translate as t, usePlatform as u };
package/dist/index.d.mts CHANGED
@@ -1,10 +1,10 @@
1
- import { P as PlatformContext, O as OrgSummary, U as User } from './plugin-o-qmdCBl.mjs';
2
- export { A as Agent, a as AgentConfig, b as AppCategory, c as AuthContextValue, d as PluginAgentDefinition, e as PluginComponentProps, f as PluginManifest, g as PluginToolDefinition } from './plugin-o-qmdCBl.mjs';
1
+ import { P as PlatformContext, O as OrgSummary, U as User } from './plugin-DZRaxKt3.mjs';
2
+ export { A as Agent, a as AgentConfig, b as AppCategory, c as AuthContextValue, d as PaletteLanguage, e as PluginAgentDefinition, f as PluginComponentProps, g as PluginManifest, h as PluginToolDefinition } from './plugin-DZRaxKt3.mjs';
3
3
  import { D as DataRoom, a as DataRoomFolder, b as DataRoomFile } from './data-room-Dtd9LLHf.mjs';
4
4
  export { C as ChatAttachment, c as ChatMessage, d as ChatThread, e as DataRoomPermission, T as Task, f as TaskAgentSnippet, g as TaskCreatePayload, h as TaskPriority, i as TaskStats, j as TaskStatus, k as TaskType, l as TaskUpdatePayload } from './data-room-Dtd9LLHf.mjs';
5
5
  export { AgentResource, ResourcesByGroup } from './types/index.mjs';
6
6
  import { ReactElement } from 'react';
7
- export { PlatformCtx, usePlatform, usePluginChat, usePluginDataRooms, usePluginTasks } from './hooks/index.mjs';
7
+ export { P as PlatformCtx, T as TranslateOptions, a as TranslationDictionary, b as TranslationPrimitive, c as TranslationResources, d as TranslationValues, U as UsePluginTranslationsOptions, n as normalizePaletteLanguage, t as translate, u as usePlatform, e as usePluginChat, f as usePluginDataRooms, g as usePluginTasks, h as usePluginTranslations } from './index-BL37Z-Ns.mjs';
8
8
  export { PluginProvider } from './components/index.mjs';
9
9
  import 'react/jsx-runtime';
10
10
 
@@ -43,8 +43,10 @@ type SandboxBridge = {
43
43
  apiFetch: PlatformContext["apiFetch"];
44
44
  navigate: (path: string) => void;
45
45
  showToast: (message: string, type?: ToastType) => void;
46
+ getLanguage: () => PlatformContext["language"];
47
+ setLanguage: PlatformContext["setLanguage"];
46
48
  };
47
- declare function createSandboxBridge(platform: Pick<PlatformContext, "apiFetch" | "navigate" | "showToast">): SandboxBridge;
49
+ declare function createSandboxBridge(platform: Pick<PlatformContext, "apiFetch" | "navigate" | "showToast"> & Partial<Pick<PlatformContext, "language" | "setLanguage">>): SandboxBridge;
48
50
  declare function isSandboxRuntime(): boolean;
49
51
 
50
52
  type InstallConfig = Record<string, unknown>;
package/dist/index.d.ts CHANGED
@@ -1,10 +1,10 @@
1
- import { P as PlatformContext, O as OrgSummary, U as User } from './plugin-o-qmdCBl.js';
2
- export { A as Agent, a as AgentConfig, b as AppCategory, c as AuthContextValue, d as PluginAgentDefinition, e as PluginComponentProps, f as PluginManifest, g as PluginToolDefinition } from './plugin-o-qmdCBl.js';
1
+ import { P as PlatformContext, O as OrgSummary, U as User } from './plugin-DZRaxKt3.js';
2
+ export { A as Agent, a as AgentConfig, b as AppCategory, c as AuthContextValue, d as PaletteLanguage, e as PluginAgentDefinition, f as PluginComponentProps, g as PluginManifest, h as PluginToolDefinition } from './plugin-DZRaxKt3.js';
3
3
  import { D as DataRoom, a as DataRoomFolder, b as DataRoomFile } from './data-room-Dtd9LLHf.js';
4
4
  export { C as ChatAttachment, c as ChatMessage, d as ChatThread, e as DataRoomPermission, T as Task, f as TaskAgentSnippet, g as TaskCreatePayload, h as TaskPriority, i as TaskStats, j as TaskStatus, k as TaskType, l as TaskUpdatePayload } from './data-room-Dtd9LLHf.js';
5
5
  export { AgentResource, ResourcesByGroup } from './types/index.js';
6
6
  import { ReactElement } from 'react';
7
- export { PlatformCtx, usePlatform, usePluginChat, usePluginDataRooms, usePluginTasks } from './hooks/index.js';
7
+ export { P as PlatformCtx, T as TranslateOptions, a as TranslationDictionary, b as TranslationPrimitive, c as TranslationResources, d as TranslationValues, U as UsePluginTranslationsOptions, n as normalizePaletteLanguage, t as translate, u as usePlatform, e as usePluginChat, f as usePluginDataRooms, g as usePluginTasks, h as usePluginTranslations } from './index-DEvPH60n.js';
8
8
  export { PluginProvider } from './components/index.js';
9
9
  import 'react/jsx-runtime';
10
10
 
@@ -43,8 +43,10 @@ type SandboxBridge = {
43
43
  apiFetch: PlatformContext["apiFetch"];
44
44
  navigate: (path: string) => void;
45
45
  showToast: (message: string, type?: ToastType) => void;
46
+ getLanguage: () => PlatformContext["language"];
47
+ setLanguage: PlatformContext["setLanguage"];
46
48
  };
47
- declare function createSandboxBridge(platform: Pick<PlatformContext, "apiFetch" | "navigate" | "showToast">): SandboxBridge;
49
+ declare function createSandboxBridge(platform: Pick<PlatformContext, "apiFetch" | "navigate" | "showToast"> & Partial<Pick<PlatformContext, "language" | "setLanguage">>): SandboxBridge;
48
50
  declare function isSandboxRuntime(): boolean;
49
51
 
50
52
  type InstallConfig = Record<string, unknown>;
package/dist/index.js CHANGED
@@ -41,13 +41,16 @@ __export(src_exports, {
41
41
  hasPermission: () => hasPermission,
42
42
  isPaletteApiError: () => isPaletteApiError,
43
43
  isSandboxRuntime: () => isSandboxRuntime,
44
+ normalizePaletteLanguage: () => normalizePaletteLanguage,
44
45
  setBaseUrl: () => setBaseUrl,
46
+ translate: () => translate,
45
47
  updateInstallConfig: () => updateInstallConfig,
46
48
  uploadToSignedUrl: () => uploadToSignedUrl,
47
49
  usePlatform: () => usePlatform,
48
50
  usePluginChat: () => usePluginChat,
49
51
  usePluginDataRooms: () => usePluginDataRooms,
50
52
  usePluginTasks: () => usePluginTasks,
53
+ usePluginTranslations: () => usePluginTranslations,
51
54
  withPluginProvider: () => withPluginProvider
52
55
  });
53
56
  module.exports = __toCommonJS(src_exports);
@@ -140,7 +143,10 @@ function createSandboxBridge(platform) {
140
143
  return {
141
144
  apiFetch: platform.apiFetch,
142
145
  navigate: platform.navigate,
143
- showToast: platform.showToast
146
+ showToast: platform.showToast,
147
+ getLanguage: () => platform.language ?? "en",
148
+ setLanguage: platform.setLanguage ?? (() => {
149
+ })
144
150
  };
145
151
  }
146
152
  function isSandboxRuntime() {
@@ -214,6 +220,11 @@ function createMockPlatformContext(overrides = {}) {
214
220
  orgs: [],
215
221
  agents: [],
216
222
  permissions: [],
223
+ language: "en",
224
+ fallbackLanguage: "en",
225
+ supportedLanguages: ["en", "ko"],
226
+ setLanguage: () => {
227
+ },
217
228
  apiFetch: async () => new Response(JSON.stringify({}), { status: 200 }),
218
229
  navigate: () => {
219
230
  },
@@ -435,14 +446,77 @@ function createPaletteClient(ctx) {
435
446
  };
436
447
  }
437
448
 
438
- // src/hooks/use-plugin-tasks.ts
449
+ // src/i18n.ts
439
450
  var import_react3 = require("react");
451
+ function normalizePaletteLanguage(language, fallback = "en") {
452
+ const trimmed = language?.trim().toLowerCase();
453
+ if (!trimmed) return fallback;
454
+ return trimmed.split("-")[0] || fallback;
455
+ }
456
+ function languageCandidates(language, fallbackLanguage = "en") {
457
+ const candidates = [
458
+ language,
459
+ normalizePaletteLanguage(language, fallbackLanguage),
460
+ fallbackLanguage,
461
+ normalizePaletteLanguage(fallbackLanguage, "en"),
462
+ "en"
463
+ ].filter(Boolean);
464
+ return Array.from(new Set(candidates));
465
+ }
466
+ function getValue(dictionary, key) {
467
+ if (!dictionary) return void 0;
468
+ let current = dictionary;
469
+ for (const part of key.split(".")) {
470
+ if (current === null || typeof current !== "object" || Array.isArray(current)) return void 0;
471
+ current = current[part];
472
+ }
473
+ if (typeof current === "string" || typeof current === "number" || typeof current === "boolean" || current === null) {
474
+ return current;
475
+ }
476
+ return void 0;
477
+ }
478
+ function interpolate(template, values) {
479
+ if (!values) return template;
480
+ return template.replace(/\{\{?\s*([a-zA-Z0-9_.-]+)\s*\}?\}/g, (match, key) => {
481
+ const value = values[key];
482
+ return value === void 0 || value === null ? match : String(value);
483
+ });
484
+ }
485
+ function translate(resources, key, options = {}) {
486
+ const fallbackLanguage = normalizePaletteLanguage(options.fallbackLanguage, "en");
487
+ for (const language of languageCandidates(options.language, fallbackLanguage)) {
488
+ const value = getValue(resources[language], key);
489
+ if (value !== void 0) {
490
+ return interpolate(String(value ?? ""), options.values);
491
+ }
492
+ }
493
+ return interpolate(options.defaultValue ?? key, options.values);
494
+ }
495
+ function usePluginTranslations(resources, options = {}) {
496
+ const platform = usePlatform();
497
+ const language = normalizePaletteLanguage(platform.language, options.fallbackLanguage ?? platform.fallbackLanguage);
498
+ const fallbackLanguage = normalizePaletteLanguage(options.fallbackLanguage ?? platform.fallbackLanguage, "en");
499
+ const t = (0, import_react3.useCallback)(
500
+ (key, values, defaultValue) => translate(resources, key, { language, fallbackLanguage, values, defaultValue }),
501
+ [fallbackLanguage, language, resources]
502
+ );
503
+ return {
504
+ language,
505
+ fallbackLanguage,
506
+ supportedLanguages: platform.supportedLanguages,
507
+ setLanguage: platform.setLanguage,
508
+ t
509
+ };
510
+ }
511
+
512
+ // src/hooks/use-plugin-tasks.ts
513
+ var import_react4 = require("react");
440
514
  function usePluginTasks(agentId) {
441
515
  const { apiFetch: apiFetch2 } = usePlatform();
442
- const [tasks, setTasks] = (0, import_react3.useState)([]);
443
- const [stats, setStats] = (0, import_react3.useState)(null);
444
- const [loading, setLoading] = (0, import_react3.useState)(true);
445
- const fetchTasks = (0, import_react3.useCallback)(async () => {
516
+ const [tasks, setTasks] = (0, import_react4.useState)([]);
517
+ const [stats, setStats] = (0, import_react4.useState)(null);
518
+ const [loading, setLoading] = (0, import_react4.useState)(true);
519
+ const fetchTasks = (0, import_react4.useCallback)(async () => {
446
520
  try {
447
521
  const params = new URLSearchParams();
448
522
  if (agentId) params.set("agent_id", String(agentId));
@@ -451,18 +525,18 @@ function usePluginTasks(agentId) {
451
525
  } catch {
452
526
  }
453
527
  }, [apiFetch2, agentId]);
454
- const fetchStats = (0, import_react3.useCallback)(async () => {
528
+ const fetchStats = (0, import_react4.useCallback)(async () => {
455
529
  try {
456
530
  const res = await apiFetch2("/api/v1/tasks/stats");
457
531
  setStats(await res.json());
458
532
  } catch {
459
533
  }
460
534
  }, [apiFetch2]);
461
- (0, import_react3.useEffect)(() => {
535
+ (0, import_react4.useEffect)(() => {
462
536
  setLoading(true);
463
537
  Promise.all([fetchTasks(), fetchStats()]).finally(() => setLoading(false));
464
538
  }, [fetchTasks, fetchStats]);
465
- const createTask = (0, import_react3.useCallback)(async (payload) => {
539
+ const createTask = (0, import_react4.useCallback)(async (payload) => {
466
540
  const res = await apiFetch2("/api/v1/tasks", {
467
541
  method: "POST",
468
542
  body: JSON.stringify(payload)
@@ -471,7 +545,7 @@ function usePluginTasks(agentId) {
471
545
  await Promise.all([fetchTasks(), fetchStats()]);
472
546
  return task;
473
547
  }, [apiFetch2, fetchTasks, fetchStats]);
474
- const updateTask = (0, import_react3.useCallback)(async (taskId, payload) => {
548
+ const updateTask = (0, import_react4.useCallback)(async (taskId, payload) => {
475
549
  const res = await apiFetch2(`/api/v1/tasks/${taskId}`, {
476
550
  method: "PATCH",
477
551
  body: JSON.stringify(payload)
@@ -480,7 +554,7 @@ function usePluginTasks(agentId) {
480
554
  await Promise.all([fetchTasks(), fetchStats()]);
481
555
  return task;
482
556
  }, [apiFetch2, fetchTasks, fetchStats]);
483
- const deleteTask = (0, import_react3.useCallback)(async (taskId) => {
557
+ const deleteTask = (0, import_react4.useCallback)(async (taskId) => {
484
558
  await apiFetch2(`/api/v1/tasks/${taskId}`, { method: "DELETE" });
485
559
  await Promise.all([fetchTasks(), fetchStats()]);
486
560
  }, [apiFetch2, fetchTasks, fetchStats]);
@@ -488,23 +562,23 @@ function usePluginTasks(agentId) {
488
562
  }
489
563
 
490
564
  // src/hooks/use-plugin-data-rooms.ts
491
- var import_react4 = require("react");
565
+ var import_react5 = require("react");
492
566
  function usePluginDataRooms() {
493
567
  const { apiFetch: apiFetch2 } = usePlatform();
494
- const [rooms, setRooms] = (0, import_react4.useState)([]);
495
- const [loading, setLoading] = (0, import_react4.useState)(true);
496
- const fetchRooms = (0, import_react4.useCallback)(async () => {
568
+ const [rooms, setRooms] = (0, import_react5.useState)([]);
569
+ const [loading, setLoading] = (0, import_react5.useState)(true);
570
+ const fetchRooms = (0, import_react5.useCallback)(async () => {
497
571
  try {
498
572
  const res = await apiFetch2("/api/v1/data-rooms");
499
573
  setRooms(await res.json());
500
574
  } catch {
501
575
  }
502
576
  }, [apiFetch2]);
503
- (0, import_react4.useEffect)(() => {
577
+ (0, import_react5.useEffect)(() => {
504
578
  setLoading(true);
505
579
  fetchRooms().finally(() => setLoading(false));
506
580
  }, [fetchRooms]);
507
- const fetchFolder = (0, import_react4.useCallback)(async (roomId, folderId) => {
581
+ const fetchFolder = (0, import_react5.useCallback)(async (roomId, folderId) => {
508
582
  const path = folderId ? `/api/v1/data-rooms/${roomId}/folders/${folderId}` : `/api/v1/data-rooms/${roomId}`;
509
583
  const res = await apiFetch2(path);
510
584
  return res.json();
@@ -513,19 +587,19 @@ function usePluginDataRooms() {
513
587
  }
514
588
 
515
589
  // src/hooks/use-plugin-chat.ts
516
- var import_react5 = require("react");
590
+ var import_react6 = require("react");
517
591
  function usePluginChat(agentId) {
518
592
  const { apiFetch: apiFetch2 } = usePlatform();
519
- const [threads, setThreads] = (0, import_react5.useState)([]);
520
- const [messages, setMessages] = (0, import_react5.useState)([]);
521
- const [streaming, setStreaming] = (0, import_react5.useState)(false);
522
- const [activeThreadId, setActiveThreadId] = (0, import_react5.useState)(null);
523
- const abortRef = (0, import_react5.useRef)(null);
524
- const fetchThreads = (0, import_react5.useCallback)(async () => {
593
+ const [threads, setThreads] = (0, import_react6.useState)([]);
594
+ const [messages, setMessages] = (0, import_react6.useState)([]);
595
+ const [streaming, setStreaming] = (0, import_react6.useState)(false);
596
+ const [activeThreadId, setActiveThreadId] = (0, import_react6.useState)(null);
597
+ const abortRef = (0, import_react6.useRef)(null);
598
+ const fetchThreads = (0, import_react6.useCallback)(async () => {
525
599
  const res = await apiFetch2(`/api/v1/chat/${agentId}/threads`);
526
600
  setThreads(await res.json());
527
601
  }, [apiFetch2, agentId]);
528
- const createThread = (0, import_react5.useCallback)(async () => {
602
+ const createThread = (0, import_react6.useCallback)(async () => {
529
603
  const res = await apiFetch2(`/api/v1/chat/${agentId}/threads`, { method: "POST" });
530
604
  const thread = await res.json();
531
605
  setActiveThreadId(thread.id);
@@ -533,13 +607,13 @@ function usePluginChat(agentId) {
533
607
  await fetchThreads();
534
608
  return thread;
535
609
  }, [apiFetch2, agentId, fetchThreads]);
536
- const fetchMessages = (0, import_react5.useCallback)(async (threadId) => {
610
+ const fetchMessages = (0, import_react6.useCallback)(async (threadId) => {
537
611
  const res = await apiFetch2(`/api/v1/chat/threads/${threadId}/messages`);
538
612
  const msgs = await res.json();
539
613
  setMessages(msgs);
540
614
  setActiveThreadId(threadId);
541
615
  }, [apiFetch2]);
542
- const sendMessage = (0, import_react5.useCallback)(async (threadId, content) => {
616
+ const sendMessage = (0, import_react6.useCallback)(async (threadId, content) => {
543
617
  setStreaming(true);
544
618
  abortRef.current = new AbortController();
545
619
  const userMsg = {
@@ -607,7 +681,7 @@ function usePluginChat(agentId) {
607
681
  abortRef.current = null;
608
682
  }
609
683
  }, []);
610
- const stopStreaming = (0, import_react5.useCallback)(() => {
684
+ const stopStreaming = (0, import_react6.useCallback)(() => {
611
685
  abortRef.current?.abort();
612
686
  }, []);
613
687
  return {
@@ -645,12 +719,15 @@ function usePluginChat(agentId) {
645
719
  hasPermission,
646
720
  isPaletteApiError,
647
721
  isSandboxRuntime,
722
+ normalizePaletteLanguage,
648
723
  setBaseUrl,
724
+ translate,
649
725
  updateInstallConfig,
650
726
  uploadToSignedUrl,
651
727
  usePlatform,
652
728
  usePluginChat,
653
729
  usePluginDataRooms,
654
730
  usePluginTasks,
731
+ usePluginTranslations,
655
732
  withPluginProvider
656
733
  });
package/dist/index.mjs CHANGED
@@ -86,7 +86,10 @@ function createSandboxBridge(platform) {
86
86
  return {
87
87
  apiFetch: platform.apiFetch,
88
88
  navigate: platform.navigate,
89
- showToast: platform.showToast
89
+ showToast: platform.showToast,
90
+ getLanguage: () => platform.language ?? "en",
91
+ setLanguage: platform.setLanguage ?? (() => {
92
+ })
90
93
  };
91
94
  }
92
95
  function isSandboxRuntime() {
@@ -160,6 +163,11 @@ function createMockPlatformContext(overrides = {}) {
160
163
  orgs: [],
161
164
  agents: [],
162
165
  permissions: [],
166
+ language: "en",
167
+ fallbackLanguage: "en",
168
+ supportedLanguages: ["en", "ko"],
169
+ setLanguage: () => {
170
+ },
163
171
  apiFetch: async () => new Response(JSON.stringify({}), { status: 200 }),
164
172
  navigate: () => {
165
173
  },
@@ -381,14 +389,77 @@ function createPaletteClient(ctx) {
381
389
  };
382
390
  }
383
391
 
392
+ // src/i18n.ts
393
+ import { useCallback } from "react";
394
+ function normalizePaletteLanguage(language, fallback = "en") {
395
+ const trimmed = language?.trim().toLowerCase();
396
+ if (!trimmed) return fallback;
397
+ return trimmed.split("-")[0] || fallback;
398
+ }
399
+ function languageCandidates(language, fallbackLanguage = "en") {
400
+ const candidates = [
401
+ language,
402
+ normalizePaletteLanguage(language, fallbackLanguage),
403
+ fallbackLanguage,
404
+ normalizePaletteLanguage(fallbackLanguage, "en"),
405
+ "en"
406
+ ].filter(Boolean);
407
+ return Array.from(new Set(candidates));
408
+ }
409
+ function getValue(dictionary, key) {
410
+ if (!dictionary) return void 0;
411
+ let current = dictionary;
412
+ for (const part of key.split(".")) {
413
+ if (current === null || typeof current !== "object" || Array.isArray(current)) return void 0;
414
+ current = current[part];
415
+ }
416
+ if (typeof current === "string" || typeof current === "number" || typeof current === "boolean" || current === null) {
417
+ return current;
418
+ }
419
+ return void 0;
420
+ }
421
+ function interpolate(template, values) {
422
+ if (!values) return template;
423
+ return template.replace(/\{\{?\s*([a-zA-Z0-9_.-]+)\s*\}?\}/g, (match, key) => {
424
+ const value = values[key];
425
+ return value === void 0 || value === null ? match : String(value);
426
+ });
427
+ }
428
+ function translate(resources, key, options = {}) {
429
+ const fallbackLanguage = normalizePaletteLanguage(options.fallbackLanguage, "en");
430
+ for (const language of languageCandidates(options.language, fallbackLanguage)) {
431
+ const value = getValue(resources[language], key);
432
+ if (value !== void 0) {
433
+ return interpolate(String(value ?? ""), options.values);
434
+ }
435
+ }
436
+ return interpolate(options.defaultValue ?? key, options.values);
437
+ }
438
+ function usePluginTranslations(resources, options = {}) {
439
+ const platform = usePlatform();
440
+ const language = normalizePaletteLanguage(platform.language, options.fallbackLanguage ?? platform.fallbackLanguage);
441
+ const fallbackLanguage = normalizePaletteLanguage(options.fallbackLanguage ?? platform.fallbackLanguage, "en");
442
+ const t = useCallback(
443
+ (key, values, defaultValue) => translate(resources, key, { language, fallbackLanguage, values, defaultValue }),
444
+ [fallbackLanguage, language, resources]
445
+ );
446
+ return {
447
+ language,
448
+ fallbackLanguage,
449
+ supportedLanguages: platform.supportedLanguages,
450
+ setLanguage: platform.setLanguage,
451
+ t
452
+ };
453
+ }
454
+
384
455
  // src/hooks/use-plugin-tasks.ts
385
- import { useCallback, useEffect, useState } from "react";
456
+ import { useCallback as useCallback2, useEffect, useState } from "react";
386
457
  function usePluginTasks(agentId) {
387
458
  const { apiFetch: apiFetch2 } = usePlatform();
388
459
  const [tasks, setTasks] = useState([]);
389
460
  const [stats, setStats] = useState(null);
390
461
  const [loading, setLoading] = useState(true);
391
- const fetchTasks = useCallback(async () => {
462
+ const fetchTasks = useCallback2(async () => {
392
463
  try {
393
464
  const params = new URLSearchParams();
394
465
  if (agentId) params.set("agent_id", String(agentId));
@@ -397,7 +468,7 @@ function usePluginTasks(agentId) {
397
468
  } catch {
398
469
  }
399
470
  }, [apiFetch2, agentId]);
400
- const fetchStats = useCallback(async () => {
471
+ const fetchStats = useCallback2(async () => {
401
472
  try {
402
473
  const res = await apiFetch2("/api/v1/tasks/stats");
403
474
  setStats(await res.json());
@@ -408,7 +479,7 @@ function usePluginTasks(agentId) {
408
479
  setLoading(true);
409
480
  Promise.all([fetchTasks(), fetchStats()]).finally(() => setLoading(false));
410
481
  }, [fetchTasks, fetchStats]);
411
- const createTask = useCallback(async (payload) => {
482
+ const createTask = useCallback2(async (payload) => {
412
483
  const res = await apiFetch2("/api/v1/tasks", {
413
484
  method: "POST",
414
485
  body: JSON.stringify(payload)
@@ -417,7 +488,7 @@ function usePluginTasks(agentId) {
417
488
  await Promise.all([fetchTasks(), fetchStats()]);
418
489
  return task;
419
490
  }, [apiFetch2, fetchTasks, fetchStats]);
420
- const updateTask = useCallback(async (taskId, payload) => {
491
+ const updateTask = useCallback2(async (taskId, payload) => {
421
492
  const res = await apiFetch2(`/api/v1/tasks/${taskId}`, {
422
493
  method: "PATCH",
423
494
  body: JSON.stringify(payload)
@@ -426,7 +497,7 @@ function usePluginTasks(agentId) {
426
497
  await Promise.all([fetchTasks(), fetchStats()]);
427
498
  return task;
428
499
  }, [apiFetch2, fetchTasks, fetchStats]);
429
- const deleteTask = useCallback(async (taskId) => {
500
+ const deleteTask = useCallback2(async (taskId) => {
430
501
  await apiFetch2(`/api/v1/tasks/${taskId}`, { method: "DELETE" });
431
502
  await Promise.all([fetchTasks(), fetchStats()]);
432
503
  }, [apiFetch2, fetchTasks, fetchStats]);
@@ -434,12 +505,12 @@ function usePluginTasks(agentId) {
434
505
  }
435
506
 
436
507
  // src/hooks/use-plugin-data-rooms.ts
437
- import { useCallback as useCallback2, useEffect as useEffect2, useState as useState2 } from "react";
508
+ import { useCallback as useCallback3, useEffect as useEffect2, useState as useState2 } from "react";
438
509
  function usePluginDataRooms() {
439
510
  const { apiFetch: apiFetch2 } = usePlatform();
440
511
  const [rooms, setRooms] = useState2([]);
441
512
  const [loading, setLoading] = useState2(true);
442
- const fetchRooms = useCallback2(async () => {
513
+ const fetchRooms = useCallback3(async () => {
443
514
  try {
444
515
  const res = await apiFetch2("/api/v1/data-rooms");
445
516
  setRooms(await res.json());
@@ -450,7 +521,7 @@ function usePluginDataRooms() {
450
521
  setLoading(true);
451
522
  fetchRooms().finally(() => setLoading(false));
452
523
  }, [fetchRooms]);
453
- const fetchFolder = useCallback2(async (roomId, folderId) => {
524
+ const fetchFolder = useCallback3(async (roomId, folderId) => {
454
525
  const path = folderId ? `/api/v1/data-rooms/${roomId}/folders/${folderId}` : `/api/v1/data-rooms/${roomId}`;
455
526
  const res = await apiFetch2(path);
456
527
  return res.json();
@@ -459,7 +530,7 @@ function usePluginDataRooms() {
459
530
  }
460
531
 
461
532
  // src/hooks/use-plugin-chat.ts
462
- import { useCallback as useCallback3, useRef, useState as useState3 } from "react";
533
+ import { useCallback as useCallback4, useRef, useState as useState3 } from "react";
463
534
  function usePluginChat(agentId) {
464
535
  const { apiFetch: apiFetch2 } = usePlatform();
465
536
  const [threads, setThreads] = useState3([]);
@@ -467,11 +538,11 @@ function usePluginChat(agentId) {
467
538
  const [streaming, setStreaming] = useState3(false);
468
539
  const [activeThreadId, setActiveThreadId] = useState3(null);
469
540
  const abortRef = useRef(null);
470
- const fetchThreads = useCallback3(async () => {
541
+ const fetchThreads = useCallback4(async () => {
471
542
  const res = await apiFetch2(`/api/v1/chat/${agentId}/threads`);
472
543
  setThreads(await res.json());
473
544
  }, [apiFetch2, agentId]);
474
- const createThread = useCallback3(async () => {
545
+ const createThread = useCallback4(async () => {
475
546
  const res = await apiFetch2(`/api/v1/chat/${agentId}/threads`, { method: "POST" });
476
547
  const thread = await res.json();
477
548
  setActiveThreadId(thread.id);
@@ -479,13 +550,13 @@ function usePluginChat(agentId) {
479
550
  await fetchThreads();
480
551
  return thread;
481
552
  }, [apiFetch2, agentId, fetchThreads]);
482
- const fetchMessages = useCallback3(async (threadId) => {
553
+ const fetchMessages = useCallback4(async (threadId) => {
483
554
  const res = await apiFetch2(`/api/v1/chat/threads/${threadId}/messages`);
484
555
  const msgs = await res.json();
485
556
  setMessages(msgs);
486
557
  setActiveThreadId(threadId);
487
558
  }, [apiFetch2]);
488
- const sendMessage = useCallback3(async (threadId, content) => {
559
+ const sendMessage = useCallback4(async (threadId, content) => {
489
560
  setStreaming(true);
490
561
  abortRef.current = new AbortController();
491
562
  const userMsg = {
@@ -553,7 +624,7 @@ function usePluginChat(agentId) {
553
624
  abortRef.current = null;
554
625
  }
555
626
  }, []);
556
- const stopStreaming = useCallback3(() => {
627
+ const stopStreaming = useCallback4(() => {
557
628
  abortRef.current?.abort();
558
629
  }, []);
559
630
  return {
@@ -590,12 +661,15 @@ export {
590
661
  hasPermission,
591
662
  isPaletteApiError,
592
663
  isSandboxRuntime,
664
+ normalizePaletteLanguage,
593
665
  setBaseUrl,
666
+ translate,
594
667
  updateInstallConfig,
595
668
  uploadToSignedUrl,
596
669
  usePlatform,
597
670
  usePluginChat,
598
671
  usePluginDataRooms,
599
672
  usePluginTasks,
673
+ usePluginTranslations,
600
674
  withPluginProvider
601
675
  };
@@ -67,6 +67,8 @@ interface AgentConfig {
67
67
  notes: string | null;
68
68
  }
69
69
 
70
+ /** BCP-47 language tag used by Palette OS and plugin translation helpers */
71
+ type PaletteLanguage = string;
70
72
  /** App store category */
71
73
  type AppCategory = "All" | "Productivity" | "Design" | "Marketing" | "Analytics";
72
74
  /** Plugin manifest — corresponds to palette-plugin.json */
@@ -149,6 +151,14 @@ interface PlatformContext {
149
151
  orgs: OrgSummary[];
150
152
  /** Available agents */
151
153
  agents: Agent[];
154
+ /** Current Palette OS language, normalized for plugin translation lookup */
155
+ language: PaletteLanguage;
156
+ /** Fallback language used when a plugin does not provide a key for language */
157
+ fallbackLanguage: PaletteLanguage;
158
+ /** Languages available in the current Palette OS environment */
159
+ supportedLanguages: PaletteLanguage[];
160
+ /** Update the Palette OS language preference */
161
+ setLanguage: (language: PaletteLanguage) => void;
152
162
  /** API fetch helper with auth handling */
153
163
  apiFetch: (path: string, init?: RequestInit) => Promise<Response>;
154
164
  /** Navigate to a platform route */
@@ -163,4 +173,4 @@ interface PluginComponentProps {
163
173
  platform: PlatformContext;
164
174
  }
165
175
 
166
- export type { Agent as A, OrgSummary as O, PlatformContext as P, User as U, AgentConfig as a, AppCategory as b, AuthContextValue as c, PluginAgentDefinition as d, PluginComponentProps as e, PluginManifest as f, PluginToolDefinition as g };
176
+ export type { Agent as A, OrgSummary as O, PlatformContext as P, User as U, AgentConfig as a, AppCategory as b, AuthContextValue as c, PaletteLanguage as d, PluginAgentDefinition as e, PluginComponentProps as f, PluginManifest as g, PluginToolDefinition as h };
@@ -67,6 +67,8 @@ interface AgentConfig {
67
67
  notes: string | null;
68
68
  }
69
69
 
70
+ /** BCP-47 language tag used by Palette OS and plugin translation helpers */
71
+ type PaletteLanguage = string;
70
72
  /** App store category */
71
73
  type AppCategory = "All" | "Productivity" | "Design" | "Marketing" | "Analytics";
72
74
  /** Plugin manifest — corresponds to palette-plugin.json */
@@ -149,6 +151,14 @@ interface PlatformContext {
149
151
  orgs: OrgSummary[];
150
152
  /** Available agents */
151
153
  agents: Agent[];
154
+ /** Current Palette OS language, normalized for plugin translation lookup */
155
+ language: PaletteLanguage;
156
+ /** Fallback language used when a plugin does not provide a key for language */
157
+ fallbackLanguage: PaletteLanguage;
158
+ /** Languages available in the current Palette OS environment */
159
+ supportedLanguages: PaletteLanguage[];
160
+ /** Update the Palette OS language preference */
161
+ setLanguage: (language: PaletteLanguage) => void;
152
162
  /** API fetch helper with auth handling */
153
163
  apiFetch: (path: string, init?: RequestInit) => Promise<Response>;
154
164
  /** Navigate to a platform route */
@@ -163,4 +173,4 @@ interface PluginComponentProps {
163
173
  platform: PlatformContext;
164
174
  }
165
175
 
166
- export type { Agent as A, OrgSummary as O, PlatformContext as P, User as U, AgentConfig as a, AppCategory as b, AuthContextValue as c, PluginAgentDefinition as d, PluginComponentProps as e, PluginManifest as f, PluginToolDefinition as g };
176
+ export type { Agent as A, OrgSummary as O, PlatformContext as P, User as U, AgentConfig as a, AppCategory as b, AuthContextValue as c, PaletteLanguage as d, PluginAgentDefinition as e, PluginComponentProps as f, PluginManifest as g, PluginToolDefinition as h };
@@ -1,4 +1,4 @@
1
- export { A as Agent, a as AgentConfig, b as AppCategory, c as AuthContextValue, O as OrgSummary, P as PlatformContext, d as PluginAgentDefinition, e as PluginComponentProps, f as PluginManifest, g as PluginToolDefinition, U as User } from '../plugin-o-qmdCBl.mjs';
1
+ export { A as Agent, a as AgentConfig, b as AppCategory, c as AuthContextValue, O as OrgSummary, d as PaletteLanguage, P as PlatformContext, e as PluginAgentDefinition, f as PluginComponentProps, g as PluginManifest, h as PluginToolDefinition, U as User } from '../plugin-DZRaxKt3.mjs';
2
2
  export { C as ChatAttachment, c as ChatMessage, d as ChatThread, D as DataRoom, b as DataRoomFile, a as DataRoomFolder, e as DataRoomPermission, T as Task, f as TaskAgentSnippet, g as TaskCreatePayload, h as TaskPriority, i as TaskStats, j as TaskStatus, k as TaskType, l as TaskUpdatePayload } from '../data-room-Dtd9LLHf.mjs';
3
3
 
4
4
  interface AgentResource {
@@ -1,4 +1,4 @@
1
- export { A as Agent, a as AgentConfig, b as AppCategory, c as AuthContextValue, O as OrgSummary, P as PlatformContext, d as PluginAgentDefinition, e as PluginComponentProps, f as PluginManifest, g as PluginToolDefinition, U as User } from '../plugin-o-qmdCBl.js';
1
+ export { A as Agent, a as AgentConfig, b as AppCategory, c as AuthContextValue, O as OrgSummary, d as PaletteLanguage, P as PlatformContext, e as PluginAgentDefinition, f as PluginComponentProps, g as PluginManifest, h as PluginToolDefinition, U as User } from '../plugin-DZRaxKt3.js';
2
2
  export { C as ChatAttachment, c as ChatMessage, d as ChatThread, D as DataRoom, b as DataRoomFile, a as DataRoomFolder, e as DataRoomPermission, T as Task, f as TaskAgentSnippet, g as TaskCreatePayload, h as TaskPriority, i as TaskStats, j as TaskStatus, k as TaskType, l as TaskUpdatePayload } from '../data-room-Dtd9LLHf.js';
3
3
 
4
4
  interface AgentResource {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@palettelab/sdk",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "description": "Palette Platform SDK for building plugins and apps",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",