@jchat/addon-sdk 1.0.0-alpha.11 → 1.0.0-alpha.13

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jchat/addon-sdk",
3
- "version": "1.0.0-alpha.11",
3
+ "version": "1.0.0-alpha.13",
4
4
  "private": false,
5
5
  "description": "JChat Addon SDK for building JChat addons.",
6
6
  "keywords": [
@@ -24,32 +24,59 @@
24
24
  "files": [
25
25
  "dist",
26
26
  "tsconfig.addon.json",
27
+ "skills",
27
28
  "README.md",
28
- "CHANGELOG.md"
29
+ "CHANGELOG.md",
30
+ "LICENSE"
29
31
  ],
30
32
  "type": "module",
31
- "main": "./dist/index.mjs",
32
- "types": "./dist/index.d.mts",
33
+ "main": "./src/index.ts",
34
+ "types": "./src/index.ts",
33
35
  "exports": {
34
36
  ".": {
35
- "types": "./dist/index.d.mts",
36
- "import": "./dist/index.mjs"
37
+ "types": "./src/index.ts",
38
+ "import": "./src/index.ts",
39
+ "default": "./src/index.ts"
40
+ },
41
+ "./contracts": {
42
+ "types": "./src/contracts.ts",
43
+ "import": "./src/contracts.ts",
44
+ "default": "./src/contracts.ts"
37
45
  },
38
46
  "./cli": {
39
- "types": "./dist/cli.d.mts",
40
- "import": "./dist/cli.mjs"
47
+ "types": "./src/cli.ts",
48
+ "import": "./src/cli.ts",
49
+ "default": "./src/cli.ts"
41
50
  },
42
51
  "./diagnostics": {
43
- "types": "./dist/diagnostics.d.mts",
44
- "import": "./dist/diagnostics.mjs"
52
+ "types": "./src/diagnostics.ts",
53
+ "import": "./src/diagnostics.ts",
54
+ "default": "./src/diagnostics.ts"
45
55
  },
46
56
  "./vite": {
47
- "types": "./dist/vite.d.mts",
48
- "import": "./dist/vite.mjs"
57
+ "types": "./src/vite.ts",
58
+ "import": "./src/vite.ts",
59
+ "default": "./src/vite.ts"
60
+ },
61
+ "./i18n-validator": {
62
+ "types": "./src/i18n-validator.ts",
63
+ "import": "./src/i18n-validator.ts",
64
+ "default": "./src/i18n-validator.ts"
49
65
  },
50
66
  "./ui": {
51
- "types": "./dist/ui.d.mts",
52
- "import": "./dist/ui.mjs"
67
+ "types": "./src/ui.ts",
68
+ "import": "./src/ui.ts",
69
+ "default": "./src/ui.ts"
70
+ },
71
+ "./icon": {
72
+ "types": "./src/icon.ts",
73
+ "import": "./src/icon.ts",
74
+ "default": "./src/icon.ts"
75
+ },
76
+ "./state": {
77
+ "types": "./src/state.ts",
78
+ "import": "./src/state.ts",
79
+ "default": "./src/state.ts"
53
80
  },
54
81
  "./ui/tailwind.css": {
55
82
  "style": "./src/tailwind.css",
@@ -59,6 +86,52 @@
59
86
  "./tsconfig.json": "./tsconfig.addon.json"
60
87
  },
61
88
  "publishConfig": {
89
+ "main": "./dist/index.mjs",
90
+ "types": "./dist/index.d.mts",
91
+ "exports": {
92
+ ".": {
93
+ "types": "./dist/index.d.mts",
94
+ "import": "./dist/index.mjs"
95
+ },
96
+ "./contracts": {
97
+ "types": "./dist/contracts.d.mts",
98
+ "import": "./dist/contracts.mjs"
99
+ },
100
+ "./cli": {
101
+ "types": "./dist/cli.d.mts",
102
+ "import": "./dist/cli.mjs"
103
+ },
104
+ "./diagnostics": {
105
+ "types": "./dist/diagnostics.d.mts",
106
+ "import": "./dist/diagnostics.mjs"
107
+ },
108
+ "./vite": {
109
+ "types": "./dist/vite.d.mts",
110
+ "import": "./dist/vite.mjs"
111
+ },
112
+ "./i18n-validator": {
113
+ "types": "./dist/i18n-validator.d.mts",
114
+ "import": "./dist/i18n-validator.mjs"
115
+ },
116
+ "./ui": {
117
+ "types": "./dist/ui.d.mts",
118
+ "import": "./dist/ui.mjs"
119
+ },
120
+ "./icon": {
121
+ "types": "./dist/icon.d.mts",
122
+ "import": "./dist/icon.mjs"
123
+ },
124
+ "./state": {
125
+ "types": "./dist/state.d.mts",
126
+ "import": "./dist/state.mjs"
127
+ },
128
+ "./ui/tailwind.css": {
129
+ "style": "./src/tailwind.css",
130
+ "import": "./src/tailwind.css",
131
+ "default": "./src/tailwind.css"
132
+ },
133
+ "./tsconfig.json": "./tsconfig.addon.json"
134
+ },
62
135
  "access": "public"
63
136
  },
64
137
  "scripts": {
@@ -69,7 +142,9 @@
69
142
  "typecheck": "tsc --noEmit",
70
143
  "prepack": "bun run build"
71
144
  },
72
- "dependencies": {},
145
+ "dependencies": {
146
+ "lucide-react": "catalog:"
147
+ },
73
148
  "devDependencies": {
74
149
  "@jchat/icon": "workspace:*",
75
150
  "@jchat/ui": "workspace:*",
@@ -78,14 +153,16 @@
78
153
  "@types/bun": "catalog:",
79
154
  "@types/react": "catalog:",
80
155
  "elysia": "catalog:",
156
+ "jotai": "catalog:",
81
157
  "kysely": "^catalog:",
82
- "tsdown": "^0.22.14",
158
+ "tsdown": "catalog:",
83
159
  "vite": "catalog:"
84
160
  },
85
161
  "peerDependencies": {
86
162
  "@tailwindcss/vite": "catalog:",
87
163
  "@tanstack/react-query": "catalog:",
88
164
  "elysia": "catalog:",
165
+ "jotai": "catalog:",
89
166
  "kysely": "^catalog:",
90
167
  "react": "catalog:",
91
168
  "vite": "catalog:"
@@ -0,0 +1,140 @@
1
+ ---
2
+ name: create-jchat-addon
3
+ description: Scaffold and initialize new JChat addons using @jchat/create-addon with correct templates, mount points, manifest configuration, and devkit sandbox setup.
4
+ ---
5
+
6
+ # Create JChat Addon Skill
7
+
8
+ Use this skill whenever you need to create, scaffold, or initialize a new JChat addon, whether inside the JChat monorepo or as a standalone third-party project for external developers.
9
+
10
+ ---
11
+
12
+ ## 1. Quick Start Commands
13
+
14
+ ### Inside the JChat Monorepo
15
+
16
+ When working inside the JChat monorepo root:
17
+
18
+ ```bash
19
+ # Interactive scaffolding
20
+ bunx @jchat/create-addon <addon-id> --workspace
21
+
22
+ # Non-interactive UI addon
23
+ bunx @jchat/create-addon <addon-id> --workspace --template=ui --mount-points=chat-toolbar --name="My Addon"
24
+
25
+ # Non-interactive fullstack addon (frontend UI + Elysia backend + isolated DB schema)
26
+ bunx @jchat/create-addon <addon-id> --workspace --template=fullstack --mount-points=chat-toolbar,room-settings --name="My Fullstack Addon"
27
+ ```
28
+
29
+ Monorepo addons are generated directly into the `addons/<addon-id>/` workspace directory and automatically wired into Bun workspaces.
30
+
31
+ ### Standalone (Third-Party Addon Developers)
32
+
33
+ For third-party developers building standalone addons outside the JChat monorepo:
34
+
35
+ ```bash
36
+ # Recommended command
37
+ bun create @jchat/addon <addon-id>
38
+
39
+ # Or with npx/bunx directly
40
+ bunx @jchat/create-addon <addon-id>
41
+
42
+ # With explicit flags
43
+ bunx @jchat/create-addon <addon-id> --template=fullstack --mount-points=chat-toolbar,user-profile
44
+ ```
45
+
46
+ Standalone projects generate a complete DevKit environment containing:
47
+
48
+ - `addon/` — The addon source package.
49
+ - `docker-compose.yml` — Disposable JChat development sandbox container with pre-configured PostgreSQL and Redis.
50
+ - `scripts/devkit.ts` — Lifecycle management scripts (`bun run devkit:start`, `bun run devkit:stop`).
51
+
52
+ ---
53
+
54
+ ## 2. CLI Options & Parameters
55
+
56
+ | Option | Description | Values / Examples | Default |
57
+ | ---------------- | ----------------------------------------------------------- | ------------------------------------------------ | ------------------------------------------------------ |
58
+ | `<addon-id>` | Unique identifier in kebab-case (letters, numbers, hyphens) | `gifyard`, `poll-wise`, `weather-now` | _Required_ |
59
+ | `--template` | Architecture template | `ui` or `fullstack` | `ui` |
60
+ | `--mount-points` | Comma-separated UI mount locations | `chat-toolbar,room-settings,chat-message-action` | `chat-toolbar` |
61
+ | `--name` | Human-readable display name | `--name="Weather Widget"` | Capitalized `addon-id` |
62
+ | `--target` | Destination directory | `--target=addons/my-addon` | `<addon-id>` (or `addons/<addon-id>` if `--workspace`) |
63
+ | `--workspace` | Target JChat monorepo workspace dependencies | Flag | `false` |
64
+ | `--image` | Custom JChat sandbox container image | `--image=jchat/devkit:local` | Default published sandbox image |
65
+
66
+ ---
67
+
68
+ ## 3. Choosing a Template
69
+
70
+ ### `ui` Template (Frontend Only)
71
+
72
+ Select when the addon only displays UI elements, embeds content, interacts with external third-party APIs via client fetch, or executes client-side actions (e.g. inserting text or media into the message editor).
73
+
74
+ - **Files generated**: `src/manifest.ts`, `src/ui.tsx`, `src/locales/*.json`, `vite.config.ts`, `package.json`.
75
+ - **Backend required**: None.
76
+
77
+ ### `fullstack` Template (UI + Elysia Backend + Isolated DB)
78
+
79
+ Select when the addon needs:
80
+
81
+ - Custom REST endpoints or server-side webhook processing.
82
+ - Persistent database storage (tables in PostgreSQL `addons.*` schema).
83
+ - Real-time Redis / WebSocket event broadcasting.
84
+ - Enforcing server-side authorization or managing secrets.
85
+ - **Files generated**: Everything in `ui`, plus `src/server.ts`, database migrations, and backend configuration.
86
+
87
+ ---
88
+
89
+ ## 4. UI Mount Points
90
+
91
+ Available mount points supported by the JChat host:
92
+
93
+ - `chat-toolbar`: Action button or picker in the chat composer toolbar.
94
+ - `chat-message-action`: Context menu action on existing chat messages.
95
+ - `room-settings`: Custom tab or section inside Room Settings.
96
+ - `site-settings`: Admin configuration panel for site administrators.
97
+ - `user-profile`: Extended tab or badge inside user profile cards.
98
+ - `sidebar-left` / `sidebar-right`: Persistent panels in chat sidebars.
99
+
100
+ ---
101
+
102
+ ## 5. Generated Workspace Structure
103
+
104
+ ```text
105
+ my-addon/
106
+ ├── .agents/
107
+ │ └── skills/
108
+ │ └── jchat-addon-development/
109
+ │ └── SKILL.md # In-workspace agent development guide
110
+ ├── src/
111
+ │ ├── manifest.ts # Addon definition, permissions, mount points
112
+ │ ├── ui.tsx # Main React UI entry point
113
+ │ ├── server.ts # ElysiaJS server entry point (fullstack only)
114
+ │ └── locales/ # 20 host language JSON dictionaries
115
+ │ ├── en.json
116
+ │ ├── ar.json
117
+ │ ├── es.json
118
+ │ └── ...
119
+ ├── package.json
120
+ ├── tsconfig.json
121
+ └── vite.config.ts
122
+ ```
123
+
124
+ ---
125
+
126
+ ## 6. Verification and Validation Checklist
127
+
128
+ Immediately after scaffolding an addon:
129
+
130
+ 1. **Check Manifest**: Verify `src/manifest.ts` contains the correct `id`, `name`, `mountPoints`, and `permissions`.
131
+ 2. **Verify Localization**: Ensure all 20 required language dictionaries exist in `src/locales/` (`bun check:translations` if in monorepo).
132
+ 3. **Run Typecheck & Build**:
133
+ ```bash
134
+ bun run typecheck
135
+ bun run build
136
+ ```
137
+ 4. **DevKit Sandbox (Standalone)**:
138
+ ```bash
139
+ bun run devkit:start
140
+ ```
@@ -0,0 +1,260 @@
1
+ ---
2
+ name: jchat-addon-development
3
+ description: Comprehensive guide for developing JChat addons using @jchat/addon-sdk, including manifests, UI widgets, direct icon imports, Elysia backend, isolated DB schemas, and i18n.
4
+ ---
5
+
6
+ # JChat Addon Development Skill
7
+
8
+ Use this skill when developing, updating, or debugging JChat addons using `@jchat/addon-sdk`.
9
+
10
+ ---
11
+
12
+ ## 1. Architectural Guardrails (Non-Negotiable)
13
+
14
+ 1. **Import Boundaries**:
15
+ - Addons MUST ONLY import `@jchat/addon-sdk` and `@jchat/addon-sdk/icon`.
16
+ - NEVER import private internal monorepo packages (`@jchat/icon`, `@jchat/ui`, `@jchat/db`, `@jchat/shared`, etc.).
17
+ - Host externals (`react`, `react-dom`, `@tanstack/react-query`) are provided at runtime by the JChat host.
18
+ 2. **Icons**:
19
+ - Use direct imports: `import Icons from "@jchat/addon-sdk/icon"`.
20
+ - Never call `useIcons()` or install `lucide-react` / `react-icons` directly in the addon.
21
+ 3. **Database Isolation**:
22
+ - All addon tables MUST reside in the isolated `addons` PostgreSQL schema (e.g. `addons.GlimpseStories`).
23
+ - Never write to or alter core tables (`Users`, `Rooms`, `Messages`, `Sites`).
24
+ 4. **Real-Time Event Namespacing**:
25
+ - All WebSocket/Redis events MUST follow the canonical format: `addon:<addonId>:<eventName>` (e.g. `addon:pollwise:voted`).
26
+ 5. **Localization (i18n)**:
27
+ - All addons must support all 20 host languages:
28
+ `ar`, `bg`, `de`, `el`, `en`, `es`, `fr`, `he`, `hi`, `hr`, `kn`, `ml`, `nl`, `pt`, `ro`, `ru`, `ta`, `te`, `tr`, `ur`.
29
+ - All locale dictionaries in `src/locales/*.json` must maintain 100% key parity.
30
+ 6. **Directional Styling (RTL/LTR)**:
31
+ - Use Tailwind CSS logical properties (`ps-*`, `pe-*`, `ms-*`, `me-*`, `text-start`, `text-end`, `start-*`, `end-*`, `rounded-s-*`, `rounded-e-*`).
32
+ - Never use physical `pl-*`, `pr-*`, `ml-*`, `mr-*`, `text-left`, or `text-right`.
33
+
34
+ ---
35
+
36
+ ## 2. Manifest Contract (`src/manifest.ts`)
37
+
38
+ Define addon metadata and capabilities with `defineAddonManifest`:
39
+
40
+ ```typescript
41
+ import { defineAddonManifest } from "@jchat/addon-sdk"
42
+
43
+ export default defineAddonManifest({
44
+ id: "pollwise",
45
+ name: "Pollwise Polls",
46
+ version: "1.0.0",
47
+ description: "Create and vote on live interactive polls in chat rooms.",
48
+ author: "JChat Ecosystem Team",
49
+ compatibility: {
50
+ jchat: ">=1.0.0-alpha.0 <2.0.0",
51
+ addonSdk: ">=1.0.0-alpha.0 <2.0.0"
52
+ },
53
+ locales: [
54
+ "ar",
55
+ "bg",
56
+ "de",
57
+ "el",
58
+ "en",
59
+ "es",
60
+ "fr",
61
+ "he",
62
+ "hi",
63
+ "hr",
64
+ "kn",
65
+ "ml",
66
+ "nl",
67
+ "pt",
68
+ "ro",
69
+ "ru",
70
+ "ta",
71
+ "te",
72
+ "tr",
73
+ "ur"
74
+ ],
75
+ defaultLocale: "en",
76
+ frontend: {
77
+ bundle: "./ui.js",
78
+ mountPoints: ["chat-toolbar", "room-settings"]
79
+ },
80
+ backend: {
81
+ bundle: "./server.js"
82
+ },
83
+ permissions: ["network", "storage"]
84
+ })
85
+ ```
86
+
87
+ ---
88
+
89
+ ## 3. Frontend UI Development (`src/ui.tsx`)
90
+
91
+ Addon UI components receive `AddonProps` and use hooks from `@jchat/addon-sdk`:
92
+
93
+ ```tsx
94
+ import {
95
+ type AddonProps,
96
+ useAddonSDK,
97
+ useAddonQuery,
98
+ useAddonMutation,
99
+ useAddonTranslation
100
+ } from "@jchat/addon-sdk"
101
+ import Icons from "@jchat/addon-sdk/icon"
102
+
103
+ export default function PollwiseAddon({ mountPoint, roomId }: AddonProps) {
104
+ const sdk = useAddonSDK()
105
+ const { t } = useAddonTranslation()
106
+
107
+ // 1. Data fetching via TanStack Query bridge
108
+ const { data: poll, isLoading } = useAddonQuery({
109
+ queryKey: ["poll", roomId],
110
+ queryFn: () => sdk.api.get<{ id: string; question: string }>(`/rooms/${roomId}/poll`)
111
+ })
112
+
113
+ // 2. Mutations
114
+ const voteMutation = useAddonMutation({
115
+ mutationFn: (optionId: string) => sdk.api.post(`/rooms/${roomId}/vote`, { optionId }),
116
+ onSuccess: () => {
117
+ sdk.ui.toast({
118
+ title: t("vote_success_title"),
119
+ description: t("vote_success_desc"),
120
+ variant: "success"
121
+ })
122
+ }
123
+ })
124
+
125
+ // 3. Real-time event listener
126
+ useEffect(() => {
127
+ const unsubscribe = sdk.events.on("addon:pollwise:updated", (updatedPoll) => {
128
+ // Handle incoming real-time payload
129
+ })
130
+ return () => unsubscribe()
131
+ }, [sdk])
132
+
133
+ if (isLoading) return <div>{t("loading")}</div>
134
+
135
+ return (
136
+ <div className="p-4 rounded-xl bg-card border border-border">
137
+ <div className="flex items-center gap-2 mb-3">
138
+ <Icons.BarChart3 className="size-5 text-primary" />
139
+ <h3 className="font-semibold text-foreground">{poll?.question}</h3>
140
+ </div>
141
+ <button
142
+ onClick={() => voteMutation.mutate("option-1")}
143
+ className="px-3 py-1.5 rounded-lg bg-primary text-primary-foreground hover:bg-primary/90 transition-colors"
144
+ >
145
+ {t("vote_button")}
146
+ </button>
147
+ </div>
148
+ )
149
+ }
150
+ ```
151
+
152
+ ### Direct Icon Usage
153
+
154
+ Icons are rendered directly:
155
+
156
+ ```tsx
157
+ import Icons, { resolveIcon } from "@jchat/addon-sdk/icon"
158
+
159
+ // Direct JSX:
160
+ <Icons.Sparkles className="size-4 text-primary" />
161
+ <Icons.Send className="size-5" />
162
+
163
+ // Dynamic resolution:
164
+ const DynamicIcon = resolveIcon("Smile", Icons.HelpCircle)
165
+ <DynamicIcon className="size-4" />
166
+ ```
167
+
168
+ ---
169
+
170
+ ## 4. Backend Server Development (`src/server.ts`)
171
+
172
+ Fullstack addons expose ElysiaJS routes running within the JChat server runtime:
173
+
174
+ ```typescript
175
+ import { createAddonServer } from "@jchat/addon-sdk/server"
176
+ import { t } from "elysia"
177
+
178
+ export default createAddonServer("pollwise", ({ app, db, events }) => {
179
+ return app
180
+ .get("/rooms/:roomId/poll", async ({ params: { roomId } }) => {
181
+ // Query isolated addons schema using Kysely
182
+ const poll = await db
183
+ .selectFrom("addons.Polls")
184
+ .selectAll()
185
+ .where("roomId", "=", roomId)
186
+ .executeTakeFirst()
187
+
188
+ return poll ?? { message: "No active poll" }
189
+ })
190
+ .post(
191
+ "/rooms/:roomId/vote",
192
+ async ({ params: { roomId }, body, user }) => {
193
+ // Record vote in DB
194
+ await db
195
+ .insertInto("addons.PollVotes")
196
+ .values({
197
+ pollId: body.pollId,
198
+ userId: user.id,
199
+ optionId: body.optionId
200
+ })
201
+ .execute()
202
+
203
+ // Broadcast real-time event to room subscribers
204
+ await events.publish(`addon:pollwise:updated`, {
205
+ roomId,
206
+ pollId: body.pollId
207
+ })
208
+
209
+ return { success: true }
210
+ },
211
+ {
212
+ body: t.Object({
213
+ pollId: t.String(),
214
+ optionId: t.String()
215
+ })
216
+ }
217
+ )
218
+ })
219
+ ```
220
+
221
+ ---
222
+
223
+ ## 5. Addon Localization (`src/locales/`)
224
+
225
+ Every translatable string in the UI must use `t("key")`.
226
+ Translations reside in `src/locales/<lang>.json` for all 20 supported languages:
227
+
228
+ ```json
229
+ // src/locales/en.json
230
+ {
231
+ "welcome": "Welcome to Pollwise",
232
+ "vote_button": "Submit Vote",
233
+ "vote_success_title": "Vote Recorded",
234
+ "vote_success_desc": "Thank you for participating."
235
+ }
236
+ ```
237
+
238
+ Validate key parity across all 20 languages:
239
+
240
+ ```bash
241
+ bun check:translations
242
+ ```
243
+
244
+ ---
245
+
246
+ ## 6. Build and Verification Workflow
247
+
248
+ ```bash
249
+ # 1. Typecheck the addon
250
+ bun run typecheck
251
+
252
+ # 2. Bundle the addon artifacts (frontend bundle into ui.js, backend into server.js)
253
+ bun run build
254
+
255
+ # 3. In the standalone devkit: start the disposable sandbox environment
256
+ bun run devkit:start
257
+
258
+ # 4. View sandbox logs
259
+ bun run devkit:logs
260
+ ```