@palettelab/cli 0.3.25 → 0.3.27
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 +21 -3
- package/backend-sdk/palette_sdk/__init__.py +1 -1
- package/backend-sdk/palette_sdk/data_rooms.py +17 -0
- package/backend-sdk/palette_sdk/db/alembic_env.py +4 -2
- package/backend-sdk/palette_sdk/plugin_context.py +6 -0
- package/backend-sdk/pyproject.toml +1 -1
- package/docs/python-backend-sdk.md +641 -0
- package/lib/commands/build.js +4 -0
- package/lib/dev-simulator.js +30 -1
- package/package.json +2 -1
- package/template-fallback/frontend/src/index.tsx +35 -23
- package/template-fallback/frontend/src/translations.ts +36 -0
- package/template-fallback/package.json +1 -1
- package/template-fallback/palette-plugin.json +1 -1
- package/template-fallback/templates/dashboard/frontend/src/index.tsx +5 -3
- package/template-fallback/templates/dashboard/frontend/src/translations.ts +12 -0
- package/template-fallback/templates/dashboard/package.json +1 -1
- package/template-fallback/templates/dashboard/palette-plugin.json +1 -1
- package/template-fallback/templates/database/frontend/src/index.tsx +13 -12
- package/template-fallback/templates/database/frontend/src/translations.ts +30 -0
- package/template-fallback/templates/database/package.json +1 -1
- package/template-fallback/templates/database/palette-plugin.json +1 -1
- package/template-fallback/templates/external-service/frontend/src/index.tsx +5 -3
- package/template-fallback/templates/external-service/frontend/src/translations.ts +12 -0
- package/template-fallback/templates/external-service/package.json +1 -1
- package/template-fallback/templates/external-service/palette-plugin.json +1 -1
- package/template-fallback/templates/frontend-only/frontend/src/index.tsx +6 -3
- package/template-fallback/templates/frontend-only/frontend/src/translations.ts +12 -0
- package/template-fallback/templates/frontend-only/package.json +1 -1
- package/template-fallback/templates/frontend-only/palette-plugin.json +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@palettelab/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.27",
|
|
4
4
|
"description": "Developer CLI for building Palette platform plugins — no platform source access required.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"pltt": "bin/pltt.js"
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"files": [
|
|
9
9
|
"bin",
|
|
10
10
|
"backend-sdk",
|
|
11
|
+
"docs",
|
|
11
12
|
"lib",
|
|
12
13
|
"platform-dev",
|
|
13
14
|
"template-fallback",
|
|
@@ -5,46 +5,58 @@
|
|
|
5
5
|
*
|
|
6
6
|
* This is the root component that the platform renders when your plugin is opened.
|
|
7
7
|
* It receives a `platform` prop with access to the authenticated user, API client,
|
|
8
|
-
* navigation, and
|
|
8
|
+
* navigation, toast notifications, and Palette OS language.
|
|
9
9
|
*
|
|
10
10
|
* Available hooks from @palettelab/sdk:
|
|
11
|
-
* - usePlatform()
|
|
12
|
-
* -
|
|
13
|
-
* -
|
|
14
|
-
* -
|
|
11
|
+
* - usePlatform() - access user, org, API, language, navigate, showToast
|
|
12
|
+
* - usePluginTranslations() - translate app-owned resource files using OS language
|
|
13
|
+
* - usePluginTasks() - CRUD tasks
|
|
14
|
+
* - usePluginDataRooms() - browse data rooms and files
|
|
15
|
+
* - usePluginChat() - chat with agents
|
|
15
16
|
*/
|
|
16
17
|
|
|
17
|
-
import { usePlatform, usePluginTasks } from "@palettelab/sdk"
|
|
18
|
+
import { usePlatform, usePluginTasks, usePluginTranslations } from "@palettelab/sdk"
|
|
18
19
|
import type { PluginComponentProps } from "@palettelab/sdk"
|
|
20
|
+
import { translations } from "./translations"
|
|
19
21
|
|
|
20
|
-
export default function MyPlugin(
|
|
22
|
+
export default function MyPlugin(_props: PluginComponentProps) {
|
|
21
23
|
const { user, showToast } = usePlatform()
|
|
22
24
|
const { tasks, loading, createTask } = usePluginTasks()
|
|
25
|
+
const { t, language, setLanguage } = usePluginTranslations(translations)
|
|
23
26
|
|
|
24
27
|
return (
|
|
25
28
|
<div className="p-6 space-y-6">
|
|
26
|
-
<div>
|
|
27
|
-
<
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
<div className="flex flex-wrap items-start justify-between gap-3">
|
|
30
|
+
<div>
|
|
31
|
+
<h1 className="text-2xl font-bold">{t("title")}</h1>
|
|
32
|
+
<p className="text-muted-foreground mt-1">
|
|
33
|
+
{t("greeting", { name: user.name })}
|
|
34
|
+
</p>
|
|
35
|
+
</div>
|
|
36
|
+
<button
|
|
37
|
+
className="px-3 py-1.5 text-sm border rounded-md hover:bg-muted"
|
|
38
|
+
onClick={() => setLanguage(language === "ko" ? "en" : "ko")}
|
|
39
|
+
aria-label={t("language")}
|
|
40
|
+
>
|
|
41
|
+
{language === "ko" ? "EN" : "KO"}
|
|
42
|
+
</button>
|
|
31
43
|
</div>
|
|
32
44
|
|
|
33
45
|
<div className="rounded-lg border p-4 space-y-3">
|
|
34
|
-
<h2 className="font-semibold">
|
|
46
|
+
<h2 className="font-semibold">{t("quickStart")}</h2>
|
|
35
47
|
<ul className="text-sm text-muted-foreground space-y-1 list-disc list-inside">
|
|
36
|
-
<li>
|
|
37
|
-
<li>
|
|
38
|
-
<li>
|
|
39
|
-
<li>
|
|
40
|
-
<li>
|
|
48
|
+
<li>{t("editUi")}</li>
|
|
49
|
+
<li>{t("editApi")}</li>
|
|
50
|
+
<li>{t("usePlatform")}</li>
|
|
51
|
+
<li>{t("useTasks")}</li>
|
|
52
|
+
<li>{t("useDataRooms")}</li>
|
|
41
53
|
</ul>
|
|
42
54
|
</div>
|
|
43
55
|
|
|
44
56
|
<div className="rounded-lg border p-4">
|
|
45
|
-
<h2 className="font-semibold mb-2">
|
|
57
|
+
<h2 className="font-semibold mb-2">{t("tasks")} ({loading ? "..." : tasks.length})</h2>
|
|
46
58
|
{!loading && tasks.length === 0 && (
|
|
47
|
-
<p className="text-sm text-muted-foreground">
|
|
59
|
+
<p className="text-sm text-muted-foreground">{t("noTasks")}</p>
|
|
48
60
|
)}
|
|
49
61
|
{tasks.slice(0, 5).map(task => (
|
|
50
62
|
<div key={task.id} className="flex items-center justify-between py-1 text-sm">
|
|
@@ -55,11 +67,11 @@ export default function MyPlugin({ platform }: PluginComponentProps) {
|
|
|
55
67
|
<button
|
|
56
68
|
className="mt-3 px-3 py-1.5 text-sm bg-primary text-primary-foreground rounded-md hover:bg-primary/90"
|
|
57
69
|
onClick={async () => {
|
|
58
|
-
await createTask({ title: "
|
|
59
|
-
showToast("
|
|
70
|
+
await createTask({ title: t("sampleTaskTitle"), priority: "medium" })
|
|
71
|
+
showToast(t("taskCreated"), "success")
|
|
60
72
|
}}
|
|
61
73
|
>
|
|
62
|
-
|
|
74
|
+
{t("createSampleTask")}
|
|
63
75
|
</button>
|
|
64
76
|
</div>
|
|
65
77
|
</div>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { TranslationResources } from "@palettelab/sdk"
|
|
2
|
+
|
|
3
|
+
export const translations = {
|
|
4
|
+
en: {
|
|
5
|
+
title: "My Plugin",
|
|
6
|
+
greeting: "Hello, {{name}}! This plugin follows the Palette OS language.",
|
|
7
|
+
quickStart: "Quick Start",
|
|
8
|
+
editUi: "Edit frontend/src/index.tsx to build your UI",
|
|
9
|
+
editApi: "Edit backend/api/main.py to add API endpoints",
|
|
10
|
+
usePlatform: "Use usePlatform() to access the authenticated user and API",
|
|
11
|
+
useTasks: "Use usePluginTasks() to manage tasks",
|
|
12
|
+
useDataRooms: "Use usePluginDataRooms() to browse files",
|
|
13
|
+
tasks: "Tasks",
|
|
14
|
+
noTasks: "No tasks yet.",
|
|
15
|
+
createSampleTask: "Create Sample Task",
|
|
16
|
+
sampleTaskTitle: "Sample task from plugin",
|
|
17
|
+
taskCreated: "Task created!",
|
|
18
|
+
language: "Language",
|
|
19
|
+
},
|
|
20
|
+
ko: {
|
|
21
|
+
title: "내 플러그인",
|
|
22
|
+
greeting: "안녕하세요, {{name}}님! 이 플러그인은 Palette OS 언어를 따릅니다.",
|
|
23
|
+
quickStart: "빠른 시작",
|
|
24
|
+
editUi: "frontend/src/index.tsx를 수정해 UI를 만드세요",
|
|
25
|
+
editApi: "backend/api/main.py를 수정해 API 엔드포인트를 추가하세요",
|
|
26
|
+
usePlatform: "usePlatform()으로 인증 사용자와 API에 접근하세요",
|
|
27
|
+
useTasks: "usePluginTasks()로 작업을 관리하세요",
|
|
28
|
+
useDataRooms: "usePluginDataRooms()로 파일을 둘러보세요",
|
|
29
|
+
tasks: "작업",
|
|
30
|
+
noTasks: "아직 작업이 없습니다.",
|
|
31
|
+
createSampleTask: "샘플 작업 만들기",
|
|
32
|
+
sampleTaskTitle: "플러그인에서 만든 샘플 작업",
|
|
33
|
+
taskCreated: "작업이 생성되었습니다!",
|
|
34
|
+
language: "언어",
|
|
35
|
+
},
|
|
36
|
+
} satisfies TranslationResources
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
3
|
import { useEffect, useState } from "react"
|
|
4
|
-
import { usePlatform } from "@palettelab/sdk"
|
|
4
|
+
import { usePlatform, usePluginTranslations } from "@palettelab/sdk"
|
|
5
5
|
import type { PluginComponentProps } from "@palettelab/sdk"
|
|
6
|
+
import { translations } from "./translations"
|
|
6
7
|
|
|
7
8
|
type Series = { label: string; value: number }
|
|
8
9
|
|
|
9
10
|
export default function DashboardWidget(_props: PluginComponentProps) {
|
|
10
11
|
const { apiFetch } = usePlatform()
|
|
12
|
+
const { t } = usePluginTranslations(translations)
|
|
11
13
|
const [data, setData] = useState<Series[]>([])
|
|
12
14
|
const [loading, setLoading] = useState(true)
|
|
13
15
|
|
|
@@ -22,9 +24,9 @@ export default function DashboardWidget(_props: PluginComponentProps) {
|
|
|
22
24
|
|
|
23
25
|
return (
|
|
24
26
|
<div className="p-6 space-y-4">
|
|
25
|
-
<h1 className="text-2xl font-bold">
|
|
27
|
+
<h1 className="text-2xl font-bold">{t("title")}</h1>
|
|
26
28
|
{loading ? (
|
|
27
|
-
<p className="text-muted-foreground">
|
|
29
|
+
<p className="text-muted-foreground">{t("loading")}</p>
|
|
28
30
|
) : (
|
|
29
31
|
<div className="space-y-2">
|
|
30
32
|
{data.map((d) => (
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"description": "A widget that exposes a dashboard data source and renders a chart from it.",
|
|
10
10
|
"icon": "ChartBar",
|
|
11
11
|
"gradient": { "bg": "linear-gradient(135deg, #06B6D4, #6366F1)", "text": "#fff" },
|
|
12
|
-
"sdk": { "frontend": "^0.1.
|
|
12
|
+
"sdk": { "frontend": "^0.1.11", "backend": "^0.1.0" },
|
|
13
13
|
"platform": { "min_version": "0.1.0" },
|
|
14
14
|
"capabilities": {
|
|
15
15
|
"frontend": true,
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
3
|
import { useEffect, useState } from "react"
|
|
4
|
-
import { usePlatform } from "@palettelab/sdk"
|
|
4
|
+
import { usePlatform, usePluginTranslations } from "@palettelab/sdk"
|
|
5
5
|
import type { PluginComponentProps } from "@palettelab/sdk"
|
|
6
|
+
import { translations } from "./translations"
|
|
6
7
|
|
|
7
8
|
type Note = { id: number; body: string }
|
|
8
9
|
|
|
@@ -96,6 +97,7 @@ const styles = `
|
|
|
96
97
|
|
|
97
98
|
export default function NotesApp(_props: PluginComponentProps) {
|
|
98
99
|
const { apiFetch, showToast, user } = usePlatform()
|
|
100
|
+
const { t } = usePluginTranslations(translations)
|
|
99
101
|
const [notes, setNotes] = useState<Note[]>([])
|
|
100
102
|
const [body, setBody] = useState("")
|
|
101
103
|
const [loading, setLoading] = useState(true)
|
|
@@ -105,7 +107,7 @@ export default function NotesApp(_props: PluginComponentProps) {
|
|
|
105
107
|
setLoading(true)
|
|
106
108
|
try {
|
|
107
109
|
const response = await apiFetch("/api/v1/plugins/my-db-plugin/notes")
|
|
108
|
-
if (!response.ok) throw new Error("
|
|
110
|
+
if (!response.ok) throw new Error(t("loadError"))
|
|
109
111
|
setNotes(await response.json())
|
|
110
112
|
} finally {
|
|
111
113
|
setLoading(false)
|
|
@@ -126,9 +128,9 @@ export default function NotesApp(_props: PluginComponentProps) {
|
|
|
126
128
|
headers: { "Content-Type": "application/json" },
|
|
127
129
|
body: JSON.stringify({ body: cleaned }),
|
|
128
130
|
})
|
|
129
|
-
if (!response.ok) throw new Error("
|
|
131
|
+
if (!response.ok) throw new Error(t("saveError"))
|
|
130
132
|
setBody("")
|
|
131
|
-
showToast("
|
|
133
|
+
showToast(t("saved"), "success")
|
|
132
134
|
await load()
|
|
133
135
|
} finally {
|
|
134
136
|
setSaving(false)
|
|
@@ -139,11 +141,10 @@ export default function NotesApp(_props: PluginComponentProps) {
|
|
|
139
141
|
<div className="notes-app">
|
|
140
142
|
<style>{styles}</style>
|
|
141
143
|
<main className="notes-shell">
|
|
142
|
-
<p className="notes-kicker">
|
|
143
|
-
<h1 className="notes-title">
|
|
144
|
+
<p className="notes-kicker">{t("kicker")}</p>
|
|
145
|
+
<h1 className="notes-title">{t("title")}</h1>
|
|
144
146
|
<p className="notes-copy">
|
|
145
|
-
|
|
146
|
-
SDK database session exposed as <code>ctx.db</code>.
|
|
147
|
+
{t("copy", { name: user.name })}
|
|
147
148
|
</p>
|
|
148
149
|
<section className="notes-form">
|
|
149
150
|
<input
|
|
@@ -153,7 +154,7 @@ export default function NotesApp(_props: PluginComponentProps) {
|
|
|
153
154
|
onKeyDown={(event) => {
|
|
154
155
|
if (event.key === "Enter") void add()
|
|
155
156
|
}}
|
|
156
|
-
placeholder="
|
|
157
|
+
placeholder={t("placeholder")}
|
|
157
158
|
/>
|
|
158
159
|
<button
|
|
159
160
|
type="button"
|
|
@@ -161,14 +162,14 @@ export default function NotesApp(_props: PluginComponentProps) {
|
|
|
161
162
|
disabled={saving || body.trim().length === 0}
|
|
162
163
|
className="notes-button"
|
|
163
164
|
>
|
|
164
|
-
{saving ? "
|
|
165
|
+
{saving ? t("saving") : t("add")}
|
|
165
166
|
</button>
|
|
166
167
|
</section>
|
|
167
168
|
<section className="notes-list">
|
|
168
169
|
{loading ? (
|
|
169
|
-
<p className="notes-empty">
|
|
170
|
+
<p className="notes-empty">{t("loading")}</p>
|
|
170
171
|
) : notes.length === 0 ? (
|
|
171
|
-
<p className="notes-empty">
|
|
172
|
+
<p className="notes-empty">{t("empty")}</p>
|
|
172
173
|
) : (
|
|
173
174
|
notes.map((note) => (
|
|
174
175
|
<p key={note.id} className="notes-item">
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { TranslationResources } from "@palettelab/sdk"
|
|
2
|
+
|
|
3
|
+
export const translations = {
|
|
4
|
+
en: {
|
|
5
|
+
kicker: "Palette DB App",
|
|
6
|
+
title: "Org Notes",
|
|
7
|
+
copy: "Built for {{name}}. This app uses a Python backend and the Palette SDK database session exposed as ctx.db.",
|
|
8
|
+
placeholder: "New note...",
|
|
9
|
+
add: "Add Note",
|
|
10
|
+
saving: "Saving",
|
|
11
|
+
loading: "Loading notes...",
|
|
12
|
+
empty: "No notes yet.",
|
|
13
|
+
loadError: "Could not load notes",
|
|
14
|
+
saveError: "Could not save note",
|
|
15
|
+
saved: "Note saved",
|
|
16
|
+
},
|
|
17
|
+
ko: {
|
|
18
|
+
kicker: "Palette DB 앱",
|
|
19
|
+
title: "조직 노트",
|
|
20
|
+
copy: "{{name}}님을 위해 생성되었습니다. 이 앱은 Python 백엔드와 ctx.db로 제공되는 Palette SDK 데이터베이스 세션을 사용합니다.",
|
|
21
|
+
placeholder: "새 노트...",
|
|
22
|
+
add: "노트 추가",
|
|
23
|
+
saving: "저장 중",
|
|
24
|
+
loading: "노트를 불러오는 중...",
|
|
25
|
+
empty: "아직 노트가 없습니다.",
|
|
26
|
+
loadError: "노트를 불러올 수 없습니다",
|
|
27
|
+
saveError: "노트를 저장할 수 없습니다",
|
|
28
|
+
saved: "노트가 저장되었습니다",
|
|
29
|
+
},
|
|
30
|
+
} satisfies TranslationResources
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"description": "Stores notes per organization with RLS-enforced isolation.",
|
|
10
10
|
"icon": "Database",
|
|
11
11
|
"gradient": { "bg": "linear-gradient(135deg, #8B5CF6, #EC4899)", "text": "#fff" },
|
|
12
|
-
"sdk": { "frontend": "^0.1.
|
|
12
|
+
"sdk": { "frontend": "^0.1.11", "backend": "^0.1.0" },
|
|
13
13
|
"platform": { "min_version": "0.1.0" },
|
|
14
14
|
"capabilities": {
|
|
15
15
|
"frontend": true,
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
3
|
import { useState } from "react"
|
|
4
|
-
import { usePlatform } from "@palettelab/sdk"
|
|
4
|
+
import { usePlatform, usePluginTranslations } from "@palettelab/sdk"
|
|
5
5
|
import type { PluginComponentProps } from "@palettelab/sdk"
|
|
6
|
+
import { translations } from "./translations"
|
|
6
7
|
|
|
7
8
|
export default function ExternalServiceWidget(_props: PluginComponentProps) {
|
|
8
9
|
const { apiFetch } = usePlatform()
|
|
10
|
+
const { t } = usePluginTranslations(translations)
|
|
9
11
|
const [result, setResult] = useState<string>("")
|
|
10
12
|
|
|
11
13
|
return (
|
|
12
14
|
<div className="p-6 space-y-3">
|
|
13
|
-
<h1 className="text-2xl font-bold">
|
|
15
|
+
<h1 className="text-2xl font-bold">{t("title")}</h1>
|
|
14
16
|
<button
|
|
15
17
|
className="px-3 py-1.5 rounded bg-primary text-primary-foreground text-sm"
|
|
16
18
|
onClick={async () => {
|
|
@@ -18,7 +20,7 @@ export default function ExternalServiceWidget(_props: PluginComponentProps) {
|
|
|
18
20
|
setResult(await r.text())
|
|
19
21
|
}}
|
|
20
22
|
>
|
|
21
|
-
|
|
23
|
+
{t("call")}
|
|
22
24
|
</button>
|
|
23
25
|
{result && <pre className="text-xs">{result}</pre>}
|
|
24
26
|
</div>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { TranslationResources } from "@palettelab/sdk"
|
|
2
|
+
|
|
3
|
+
export const translations = {
|
|
4
|
+
en: {
|
|
5
|
+
title: "External Service",
|
|
6
|
+
call: "Call api.example.com",
|
|
7
|
+
},
|
|
8
|
+
ko: {
|
|
9
|
+
title: "외부 서비스",
|
|
10
|
+
call: "api.example.com 호출",
|
|
11
|
+
},
|
|
12
|
+
} satisfies TranslationResources
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"description": "Demonstrates declared external_network access and a scoped per-org config token.",
|
|
10
10
|
"icon": "CloudArrowUp",
|
|
11
11
|
"gradient": { "bg": "linear-gradient(135deg, #10B981, #06B6D4)", "text": "#fff" },
|
|
12
|
-
"sdk": { "frontend": "^0.1.
|
|
12
|
+
"sdk": { "frontend": "^0.1.11", "backend": "^0.1.0" },
|
|
13
13
|
"platform": { "min_version": "0.1.0" },
|
|
14
14
|
"capabilities": {
|
|
15
15
|
"frontend": true,
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
-
import { usePlatform } from "@palettelab/sdk"
|
|
3
|
+
import { usePlatform, usePluginTranslations } from "@palettelab/sdk"
|
|
4
4
|
import type { PluginComponentProps } from "@palettelab/sdk"
|
|
5
|
+
import { translations } from "./translations"
|
|
5
6
|
|
|
6
7
|
export default function FrontendOnlyPlugin(_props: PluginComponentProps) {
|
|
7
8
|
const { user } = usePlatform()
|
|
9
|
+
const { t } = usePluginTranslations(translations)
|
|
10
|
+
|
|
8
11
|
return (
|
|
9
12
|
<div className="p-6">
|
|
10
|
-
<h1 className="text-2xl font-bold">
|
|
13
|
+
<h1 className="text-2xl font-bold">{t("title", { name: user.name })}</h1>
|
|
11
14
|
<p className="text-muted-foreground mt-2">
|
|
12
|
-
|
|
15
|
+
{t("body")}
|
|
13
16
|
</p>
|
|
14
17
|
</div>
|
|
15
18
|
)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { TranslationResources } from "@palettelab/sdk"
|
|
2
|
+
|
|
3
|
+
export const translations = {
|
|
4
|
+
en: {
|
|
5
|
+
title: "Hello, {{name}}",
|
|
6
|
+
body: "This plugin runs entirely in the browser sandbox and follows the Palette OS language.",
|
|
7
|
+
},
|
|
8
|
+
ko: {
|
|
9
|
+
title: "안녕하세요, {{name}}님",
|
|
10
|
+
body: "이 플러그인은 브라우저 샌드박스에서만 실행되며 Palette OS 언어를 따릅니다.",
|
|
11
|
+
},
|
|
12
|
+
} satisfies TranslationResources
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"description": "A frontend-only plugin — renders inside the platform iframe sandbox with no backend.",
|
|
10
10
|
"icon": "Puzzle",
|
|
11
11
|
"gradient": { "bg": "linear-gradient(135deg, #6366F1, #8B5CF6)", "text": "#fff" },
|
|
12
|
-
"sdk": { "frontend": "^0.1.
|
|
12
|
+
"sdk": { "frontend": "^0.1.11" },
|
|
13
13
|
"platform": { "min_version": "0.1.0" },
|
|
14
14
|
"capabilities": {
|
|
15
15
|
"frontend": true,
|