@jchat/create-addon 1.0.0-alpha.10
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/CHANGELOG.md +47 -0
- package/LICENSE +23 -0
- package/README.md +39 -0
- package/dist/cli.d.mts +11 -0
- package/dist/cli.mjs +2 -0
- package/dist/generator.mjs +246 -0
- package/dist/index.d.mts +26 -0
- package/dist/index.mjs +1 -0
- package/package.json +60 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# @jchat/create-addon
|
|
2
|
+
|
|
3
|
+
## 1.0.0-alpha.10
|
|
4
|
+
|
|
5
|
+
## 1.0.0-alpha.9
|
|
6
|
+
|
|
7
|
+
## 1.0.0-alpha.8
|
|
8
|
+
|
|
9
|
+
## 1.0.0-alpha.7
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- 7cef24c: - Enhance addon package diagnostics with semantic version compatibility validation for JChat host and Addon SDK
|
|
14
|
+
- Add support for local workspace development, sandbox test harnesses, and distribution packaging
|
|
15
|
+
- Improve runtime license verification and multi-environment path resolution
|
|
16
|
+
- Update addon generator templates with 20-language i18n support, standard scripts, and type definitions
|
|
17
|
+
|
|
18
|
+
## 1.0.0-alpha.6
|
|
19
|
+
|
|
20
|
+
## 1.0.0-alpha.5
|
|
21
|
+
|
|
22
|
+
### Patch Changes
|
|
23
|
+
|
|
24
|
+
- 9755c28: Export curated UI components, types, and Tailwind styles from `@jchat/addon-sdk/ui` (`@jchat/addon-sdk/ui/tailwind.css`) for sandbox and third-party addon developers.
|
|
25
|
+
- 8b8297f: Rename package from `create-jchat-addon` to `@jchat/create-addon` and update binary script to `create-addon`.
|
|
26
|
+
- 5bbb2b6: Inherit jchatVersion and addonSdkVersion directly from @jchat/create-addon package version when generating standalone devkit.
|
|
27
|
+
|
|
28
|
+
## 1.0.0-alpha.4
|
|
29
|
+
|
|
30
|
+
### Patch Changes
|
|
31
|
+
|
|
32
|
+
- 8b8297f: Rename package from `create-jchat-addon` to `@jchat/create-addon` and update binary script to `create-addon`.
|
|
33
|
+
- 5bbb2b6: Inherit jchatVersion and addonSdkVersion directly from @jchat/create-addon package version when generating standalone devkit.
|
|
34
|
+
|
|
35
|
+
## 1.0.0-alpha.3
|
|
36
|
+
|
|
37
|
+
## 1.0.0-alpha.2
|
|
38
|
+
|
|
39
|
+
## 1.0.0-alpha.1
|
|
40
|
+
|
|
41
|
+
### Patch Changes
|
|
42
|
+
|
|
43
|
+
- 70537c0: Cleanup folder structure.
|
|
44
|
+
|
|
45
|
+
## 1.0.0-alpha.0
|
|
46
|
+
|
|
47
|
+
- Initial public alpha release.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
CUSTOM COMMERCIAL END USER LICENSE AGREEMENT (EULA)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 JChat Project. All rights reserved.
|
|
4
|
+
|
|
5
|
+
1. DEFINITIONS
|
|
6
|
+
"Software" refers to this npm package and its source code.
|
|
7
|
+
"Authorized Application" refers strictly to the application known as "JChat".
|
|
8
|
+
|
|
9
|
+
2. LICENSE GRANT
|
|
10
|
+
Subject to the terms of this Agreement and payment of any applicable fees, the
|
|
11
|
+
Licensor grants you a non-exclusive, non-transferable, revocable license to
|
|
12
|
+
download, install, and use the Software.
|
|
13
|
+
|
|
14
|
+
3. RESTRICTIONS ON USE
|
|
15
|
+
You are expressly prohibited from using this Software, in whole or in part,
|
|
16
|
+
in any application, product, or service other than the Authorized Application (JChat).
|
|
17
|
+
Any deployment, linking, execution, or inclusion of this Software into an
|
|
18
|
+
application that is not JChat constitutes a breach of this contract and
|
|
19
|
+
an infringement of copyright law.
|
|
20
|
+
|
|
21
|
+
4. NO REDISTRIBUTION
|
|
22
|
+
You may not sub-license, rent, lease, or publicly redistribute this Software
|
|
23
|
+
to any third party without explicit written consent from the Licensor.
|
package/README.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# @jchat/create-addon
|
|
2
|
+
|
|
3
|
+
A CLI tool for generating a self-contained JChat addon development workspace.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
Generate a new addon workspace:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
bunx @jchat/create-addon <addon-id>
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### Options
|
|
14
|
+
|
|
15
|
+
- `<addon-id>`: (Required) The unique ID for your addon, typically hyphenated (e.g., `weather-addon`).
|
|
16
|
+
- `--target=<directory>`: (Optional) The directory to generate the workspace in. Defaults to `../<addon-id>` relative to the current working directory.
|
|
17
|
+
- `--image=<image>`: (Optional) A specific Docker / Podman container image to use for the sandbox environment. Defaults to `ghcr.io/mjjabarullah/jchat-sandbox`.
|
|
18
|
+
|
|
19
|
+
### Example
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
bunx @jchat/create-addon my-addon
|
|
23
|
+
cd my-addon
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Requirements
|
|
27
|
+
|
|
28
|
+
- Bun 1.3+
|
|
29
|
+
- Docker or Podman
|
|
30
|
+
|
|
31
|
+
## Licensing
|
|
32
|
+
|
|
33
|
+
The creator package and JChat-authored template material are licensed under Apache License 2.0.
|
|
34
|
+
You retain ownership of the original code and content you add to a generated project and may choose
|
|
35
|
+
the license for that original work. Any JChat-authored template portions and third-party components
|
|
36
|
+
remain subject to their respective licenses and notices.
|
|
37
|
+
|
|
38
|
+
The generated developer sandbox does not grant a production JChat license. Production use remains
|
|
39
|
+
subject to the applicable JChat and addon marketplace terms.
|
package/dist/cli.d.mts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/cli.d.ts
|
|
2
|
+
interface CreatorArguments {
|
|
3
|
+
addonId: string;
|
|
4
|
+
targetDir: string;
|
|
5
|
+
sandboxImage?: string;
|
|
6
|
+
workspace?: boolean;
|
|
7
|
+
}
|
|
8
|
+
declare function parseCreatorArguments(arguments_: readonly string[]): CreatorArguments;
|
|
9
|
+
declare function runCreator(arguments_: readonly string[]): Promise<string>;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { CreatorArguments, parseCreatorArguments, runCreator };
|
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import{i as e,r as t}from"./generator.mjs";import*as n from"node:path";function r(e){let t=e.find(e=>!e.startsWith(`--`));if(t===void 0||t.startsWith(`-`))throw Error(`Usage: bunx @jchat/create-addon <addon-id> [--target=<directory>] [--image=<image>] [--workspace]`);let r=e.find(e=>e.startsWith(`--target=`)),i=e.find(e=>e.startsWith(`--image=`)),a=e.includes(`--workspace`),o=a?n.join(`addons`,t):t;return{addonId:t,targetDir:r?.slice(9)||o,sandboxImage:i?.slice(8)||void 0,workspace:a}}async function i(i){let a=await Bun.file(new URL(`../package.json`,import.meta.url)).json(),o=r(i);return o.workspace?(await t({addonId:o.addonId,targetDir:o.targetDir,isMonorepoWorkspace:!0,jchatVersion:a.version,addonSdkVersion:a.version}),n.resolve(o.targetDir)):(await e({...o,jchatVersion:a.version,addonSdkVersion:a.version,sandboxImage:o.sandboxImage??`${a.jchat?.sandboxImage??`ghcr.io/mjjabarullah/jchat-sandbox`}:${a.version.replaceAll(`+`,`-`)}`}),n.resolve(o.targetDir))}if(import.meta.main)try{let e=await i(process.argv.slice(2));console.log(`Created addon at ${e}`)}catch(e){console.error(e),process.exit(1)}export{r as parseCreatorArguments,i as runCreator};
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import*as e from"node:fs";import*as t from"node:path";function n(e){try{Bun.semver.order(e,e)}catch{throw Error(`Invalid semantic version: ${e}`)}let t=/^(?:v|=)?(\d+)\./.exec(e)?.[1],n=t?Number(t):NaN;if(!Number.isSafeInteger(n))throw Error(`Invalid semantic version: ${e}`);return`>=${e} <${n+1}.0.0`}const r=/^[a-z0-9]+(?:-[a-z0-9]+)*$/;function i(e){if(!r.test(e.addonId))throw Error(`Addon id must contain lowercase letters, numbers, and hyphens`);let t={id:e.addonId,name:P(e.addonId),version:`1.0.0`,description:`${P(e.addonId)} addon for JChat`,author:`Developer`,compatibility:{jchat:n(e.jchatVersion??`1.0.0`),addonSdk:n(e.addonSdkVersion??`1.0.0`)},locales:[`ar`,`de`,`en`,`es`,`fr`,`hi`,`kn`,`ml`,`ta`,`te`,`ur`],defaultLocale:`en`,frontend:{bundle:`./ui.js`,mountPoints:[`chat-toolbar`]},permissions:[]},i=e.isMonorepoWorkspace?d(e.addonId):m(e.addonId,e.addonSdkVersion??`1.0.0`),a=e.isMonorepoWorkspace?f():h();return Object.freeze({"package.json":`${JSON.stringify(i,null,2)}\n`,"tsconfig.json":`${JSON.stringify(a,null,2)}\n`,"src/manifest.ts":g(t),"src/tailwind.css":j(),"src/locales/ar.json":_(t.name),"src/locales/de.json":v(t.name),"src/locales/en.json":y(t.name),"src/locales/es.json":b(t.name),"src/locales/fr.json":x(t.name),"src/locales/hi.json":S(t.name),"src/locales/kn.json":C(t.name),"src/locales/ml.json":w(t.name),"src/locales/ta.json":T(t.name),"src/locales/te.json":E(t.name),"src/locales/ur.json":D(t.name),"src/locales/index.ts":O(),"src/locales.test.ts":k(),"src/ui.tsx":A(t.name)})}async function a(n){let r=t.resolve(n.targetDir);if(e.existsSync(r))throw Error(`Addon target already exists: ${r}`);let a=Object.entries(i(n));for(let[n]of a){let i=t.join(r,...n.split(`/`));e.mkdirSync(t.dirname(i),{recursive:!0})}await Promise.all(a.map(([e,n])=>{let i=t.join(r,...e.split(`/`));return Bun.write(i,n)}))}function o(e){if(!r.test(e.addonId))throw Error(`Addon id must contain lowercase letters, numbers, and hyphens`);let t=e.sandboxImage??`ghcr.io/mjjabarullah/jchat-sandbox:${e.jchatVersion.replace(/\+/g,`-`)}`,n=i({addonId:e.addonId,isMonorepoWorkspace:!1,jchatVersion:e.jchatVersion,addonSdkVersion:e.addonSdkVersion}),a={".env.example":c(e.addonId,t),".gitignore":[`node_modules/`,`addon/node_modules/`,`addon/build/`,`.env`,``].join(`
|
|
2
|
+
`),"README.md":N(e.addonId),"docker-compose.yml":l(),"package.json":`${JSON.stringify(u(e.addonId),null,2)}\n`,"scripts/devkit.ts":M()};for(let[e,t]of Object.entries(n))a[`addon/${e}`]=t;return Object.freeze(a)}async function s(n){let r=t.resolve(n.targetDir);if(e.existsSync(r))throw Error(`Development kit target already exists: ${r}`);let i=Object.entries(o(n));for(let[n]of i){let i=t.join(r,...n.split(`/`));e.mkdirSync(t.dirname(i),{recursive:!0})}await Promise.all(i.map(([e,n])=>{let i=t.join(r,...e.split(`/`));return Bun.write(i,n)}))}function c(e,t){return[`JCHAT_SANDBOX_IMAGE=${t}`,`JCHAT_SANDBOX_ADDON_ID=${e}`,`JCHAT_SANDBOX_PORT=4317`,`JCHAT_SANDBOX_HTTP_MOCK_PORT=4318`,`JCHAT_SANDBOX_HTTP_MOCK_OFFLINE=false`,`JCHAT_SANDBOX_ADDON_HTTP_MOCK_URL=http://http-mock:4318`,``].join(`
|
|
3
|
+
`)}function l(){return`services:
|
|
4
|
+
sandbox:
|
|
5
|
+
image: \${JCHAT_SANDBOX_IMAGE:?Copy .env.example to .env}
|
|
6
|
+
restart: unless-stopped
|
|
7
|
+
environment:
|
|
8
|
+
NODE_ENV: development
|
|
9
|
+
JCHAT_PORT: "4317"
|
|
10
|
+
JCHAT_COOKIE_SECRET: addon-sandbox-cookie-secret
|
|
11
|
+
JCHAT_DATABASE_URL: postgresql://jchat:jchat@db:5432/jchat
|
|
12
|
+
JCHAT_REDIS_DATABASE_URL: redis://redis:6379
|
|
13
|
+
JCHAT_STORAGE_TYPE: LOCAL
|
|
14
|
+
JCHAT_BOT_NAME: Sandbox Bot
|
|
15
|
+
JCHAT_BOT_EMAIL: bot@sandbox.local
|
|
16
|
+
JCHAT_DOMAIN: localhost
|
|
17
|
+
JCHAT_SITE_URL: http://localhost:\${JCHAT_SANDBOX_PORT:-4317}
|
|
18
|
+
JCHAT_ROUTING_MODE: path
|
|
19
|
+
JCHAT_ADDON_ENCRYPTION_KEY: addon-sandbox-encryption-key
|
|
20
|
+
JCHAT_ADDON_HTTP_MOCK_URL: \${JCHAT_SANDBOX_ADDON_HTTP_MOCK_URL-http://http-mock:4318}
|
|
21
|
+
ports:
|
|
22
|
+
- "127.0.0.1:\${JCHAT_SANDBOX_PORT:-4317}:4317"
|
|
23
|
+
volumes:
|
|
24
|
+
- ./addon:/app/addons/\${JCHAT_SANDBOX_ADDON_ID:?Set addon id}:ro
|
|
25
|
+
- sandbox_uploads:/app/uploads
|
|
26
|
+
depends_on:
|
|
27
|
+
db:
|
|
28
|
+
condition: service_healthy
|
|
29
|
+
redis:
|
|
30
|
+
condition: service_healthy
|
|
31
|
+
http-mock:
|
|
32
|
+
condition: service_healthy
|
|
33
|
+
|
|
34
|
+
http-mock:
|
|
35
|
+
image: \${JCHAT_SANDBOX_IMAGE:?Copy .env.example to .env}
|
|
36
|
+
entrypoint: ["/app/addon-http-mock"]
|
|
37
|
+
environment:
|
|
38
|
+
JCHAT_SANDBOX_HTTP_MOCK_PORT: "4318"
|
|
39
|
+
JCHAT_SANDBOX_HTTP_MOCK_OFFLINE: \${JCHAT_SANDBOX_HTTP_MOCK_OFFLINE:-false}
|
|
40
|
+
ports:
|
|
41
|
+
- "127.0.0.1:\${JCHAT_SANDBOX_HTTP_MOCK_PORT:-4318}:4318"
|
|
42
|
+
healthcheck:
|
|
43
|
+
test: ["CMD", "/app/addon-http-mock", "--healthcheck"]
|
|
44
|
+
interval: 2s
|
|
45
|
+
timeout: 3s
|
|
46
|
+
retries: 30
|
|
47
|
+
|
|
48
|
+
db:
|
|
49
|
+
image: postgres:18-alpine
|
|
50
|
+
environment:
|
|
51
|
+
POSTGRES_USER: jchat
|
|
52
|
+
POSTGRES_PASSWORD: jchat
|
|
53
|
+
POSTGRES_DB: jchat
|
|
54
|
+
volumes:
|
|
55
|
+
- sandbox_postgres:/var/lib/postgresql/data
|
|
56
|
+
healthcheck:
|
|
57
|
+
test: ["CMD-SHELL", "pg_isready -U jchat"]
|
|
58
|
+
interval: 2s
|
|
59
|
+
timeout: 3s
|
|
60
|
+
retries: 30
|
|
61
|
+
|
|
62
|
+
redis:
|
|
63
|
+
image: redis:8.0.6-alpine3.21
|
|
64
|
+
volumes:
|
|
65
|
+
- sandbox_redis:/data
|
|
66
|
+
healthcheck:
|
|
67
|
+
test: ["CMD", "redis-cli", "ping"]
|
|
68
|
+
interval: 2s
|
|
69
|
+
timeout: 3s
|
|
70
|
+
retries: 30
|
|
71
|
+
|
|
72
|
+
volumes:
|
|
73
|
+
sandbox_postgres:
|
|
74
|
+
sandbox_redis:
|
|
75
|
+
sandbox_uploads:
|
|
76
|
+
`}function u(e){return{name:`${e}-development-kit`,private:!0,type:`module`,workspaces:[`addon`],scripts:{sandbox:`bun run ./scripts/devkit.ts run`,"sandbox:test":`bun run ./scripts/devkit.ts test`,"sandbox:reset":`bun run ./scripts/devkit.ts reset`,"sandbox:package":`bun run ./scripts/devkit.ts package`,"sandbox:cleanup":`bun run ./scripts/devkit.ts cleanup`},devDependencies:{"@types/bun":`^1.4.0`},engines:{bun:`>=1.4.0`}}}function d(e){return{name:`@jchat/${e}`,version:`1.0.0-alpha.0`,private:!0,description:`${P(e)} addon for JChat`,repository:{type:`git`,url:`git+https://github.com/mjjabarullah/jchat.git`,directory:`addons/${e}`},type:`module`,scripts:{dev:`jchat-addon dev`,build:`tsc --noEmit && jchat-addon build`,test:`bun test`,lint:`oxlint .`,format:`oxfmt . --write`,typecheck:`tsc --noEmit`},dependencies:{"lucide-react":`catalog:`,"usehooks-ts":`catalog:`},devDependencies:{"@tailwindcss/vite":`catalog:`,"@types/bun":`catalog:`,"@types/react":`catalog:`,"@types/react-dom":`catalog:`,elysia:`catalog:`,vite:`catalog:`},peerDependencies:{"@jchat/addon-sdk":`workspace:*`,"@tanstack/react-query":`catalog:`,react:`catalog:`,"react-dom":`catalog:`}}}function f(){return{extends:`@jchat/addon-sdk/tsconfig.json`,include:[`src/**/*`]}}function p(){try{let n=import.meta.dirname;for(let r=0;r<6;r++){let r=t.join(n,`package.json`);if(e.existsSync(r)){let t=e.readFileSync(r,`utf8`),n=JSON.parse(t);if(n.catalog&&typeof n.catalog==`object`)return n.catalog}let i=t.dirname(n);if(i===n)break;n=i}}catch{}return{}}function m(e,t){let n=p();return{name:`@jchat/${e}`,version:`1.0.0`,private:!0,type:`module`,scripts:{dev:`jchat-addon dev`,build:`tsc --noEmit && jchat-addon build`,test:`bun test`,typecheck:`tsc --noEmit`},dependencies:{"@jchat/addon-sdk":`^${t}`,"@tanstack/react-query":n[`@tanstack/react-query`]??`^5.101.4`,"lucide-react":n[`lucide-react`]??`1.31.0`,react:n.react??`^19.2.8`,"react-dom":n[`react-dom`]??`^19.2.8`,"usehooks-ts":n[`usehooks-ts`]??`^3.1.1`},devDependencies:{"@tailwindcss/vite":n[`@tailwindcss/vite`]??`^4.3.3`,"@types/bun":n[`@types/bun`]??`^1.4.0`,"@types/react":n[`@types/react`]??`^19.2.18`,"@types/react-dom":n[`@types/react-dom`]??`^19.2.4`,elysia:n.elysia??`^1.4.29`,tailwindcss:n.tailwindcss??`^4.3.3`,typescript:n.typescript??`^7.0.2`,vite:n.vite??`^8.2.1`}}}function h(){return{extends:`@jchat/addon-sdk/tsconfig.json`,include:[`src/**/*.ts`,`src/**/*.tsx`]}}function g(e){return`import type { AddonManifest } from "@jchat/addon-sdk"
|
|
77
|
+
|
|
78
|
+
const manifest: AddonManifest = ${JSON.stringify(e,null,2)}
|
|
79
|
+
|
|
80
|
+
export default manifest
|
|
81
|
+
`}function _(e){return`${JSON.stringify({welcome:`مرحبًا بك في ${e}`,mounted_at:`تم التثبيت في {{mountPoint}}`,test_button:`اختبار الإضافة`,toast_message:`مرحبًا من ${e}`},null,2)}\n`}function v(e){return`${JSON.stringify({welcome:`Willkommen bei ${e}`,mounted_at:`Eingebunden an {{mountPoint}}`,test_button:`Addon testen`,toast_message:`Hallo von ${e}`},null,2)}\n`}function y(e){return`${JSON.stringify({welcome:`Welcome to ${e}`,mounted_at:`Mounted at {{mountPoint}}`,test_button:`Test addon`,toast_message:`Hello from ${e}`},null,2)}\n`}function b(e){return`${JSON.stringify({welcome:`Bienvenido a ${e}`,mounted_at:`Montado en {{mountPoint}}`,test_button:`Probar complemento`,toast_message:`Hola desde ${e}`},null,2)}\n`}function x(e){return`${JSON.stringify({welcome:`Bienvenue sur ${e}`,mounted_at:`Monté sur {{mountPoint}}`,test_button:`Tester le plugin`,toast_message:`Bonjour de ${e}`},null,2)}\n`}function S(e){return`${JSON.stringify({welcome:`${e} में आपका स्वागत है`,mounted_at:`{{mountPoint}} पर माउंट किया गया`,test_button:`ऐडऑन का परीक्षण करें`,toast_message:`${e} की ओर से नमस्कार`},null,2)}\n`}function C(e){return`${JSON.stringify({welcome:`${e} ಗೆ ಸುಸ್ವಾಗತ`,mounted_at:`{{mountPoint}} ನಲ್ಲಿ ಸ್ಥಾಪಿಸಲಾಗಿದೆ`,test_button:`ಆಡ್ಆನ್ ಪರೀಕ್ಷಿಸಿ`,toast_message:`${e} ನಿಂದ ನಮಸ್ಕಾರ`},null,2)}\n`}function w(e){return`${JSON.stringify({welcome:`${e}-ലേക്ക് സ്വാഗതം`,mounted_at:`{{mountPoint}}-ൽ ഘടിപ്പിച്ചിരിക്കുന്നു`,test_button:`ആഡ്ഓൺ പരിശോധിക്കുക`,toast_message:`${e}-ൽ നിന്നുള്ള ആശംസകൾ`},null,2)}\n`}function T(e){return`${JSON.stringify({welcome:`${e}-க்கு வரவேற்கிறோம்`,mounted_at:`{{mountPoint}}-ல் பொருத்தப்பட்டுள்ளது`,test_button:`செருகுநிரலை சோதிக்கவும்`,toast_message:`${e}-லிருந்து வணக்கம்`},null,2)}\n`}function E(e){return`${JSON.stringify({welcome:`${e}కి స్వాగతం`,mounted_at:`{{mountPoint}} వద్ద మౌంట్ చేయబడింది`,test_button:`యాడ్ఆన్ని పరీక్షించండి`,toast_message:`${e} నుండి నమస్కారం`},null,2)}\n`}function D(e){return`${JSON.stringify({welcome:`${e} میں خوش آمدید`,mounted_at:`{{mountPoint}} پر نصب ہے`,test_button:`ایڈ آن کا تجربہ کریں`,toast_message:`${e} کی طرف سے ہیلو`},null,2)}\n`}function O(){return`import ar from "./ar.json"
|
|
82
|
+
import de from "./de.json"
|
|
83
|
+
import en from "./en.json"
|
|
84
|
+
import es from "./es.json"
|
|
85
|
+
import fr from "./fr.json"
|
|
86
|
+
import hi from "./hi.json"
|
|
87
|
+
import kn from "./kn.json"
|
|
88
|
+
import ml from "./ml.json"
|
|
89
|
+
import ta from "./ta.json"
|
|
90
|
+
import te from "./te.json"
|
|
91
|
+
import ur from "./ur.json"
|
|
92
|
+
|
|
93
|
+
export type TranslationKey = keyof typeof en
|
|
94
|
+
|
|
95
|
+
export const locales = {
|
|
96
|
+
ar,
|
|
97
|
+
de,
|
|
98
|
+
en,
|
|
99
|
+
es,
|
|
100
|
+
fr,
|
|
101
|
+
hi,
|
|
102
|
+
kn,
|
|
103
|
+
ml,
|
|
104
|
+
ta,
|
|
105
|
+
te,
|
|
106
|
+
ur
|
|
107
|
+
} as const
|
|
108
|
+
|
|
109
|
+
export default locales
|
|
110
|
+
`}function k(){return`import { describe, expect, test } from "bun:test"
|
|
111
|
+
import { validateAddonLocales } from "@jchat/addon-sdk"
|
|
112
|
+
import * as path from "node:path"
|
|
113
|
+
|
|
114
|
+
describe("addon locales", () => {
|
|
115
|
+
test("maintains key parity across all 11 host languages", () => {
|
|
116
|
+
const localesDir = path.join(import.meta.dir, "locales")
|
|
117
|
+
const result = validateAddonLocales(localesDir)
|
|
118
|
+
if (!result.valid) {
|
|
119
|
+
console.error(result.errors.join("\\n"))
|
|
120
|
+
}
|
|
121
|
+
expect(result.valid).toBe(true)
|
|
122
|
+
})
|
|
123
|
+
})
|
|
124
|
+
`}function A(e){return`import type { AddonProps } from "@jchat/addon-sdk"
|
|
125
|
+
import { useAddonSDK, useIcons, useTranslation } from "@jchat/addon-sdk"
|
|
126
|
+
import locales from "./locales"
|
|
127
|
+
import "./tailwind.css"
|
|
128
|
+
|
|
129
|
+
export default function Addon({ mountPoint }: AddonProps) {
|
|
130
|
+
const sdk = useAddonSDK()
|
|
131
|
+
const { Icons } = useIcons()
|
|
132
|
+
const { t, dir } = useTranslation(locales)
|
|
133
|
+
|
|
134
|
+
return (
|
|
135
|
+
<div dir={dir} className="rounded border border-border bg-card p-2 text-card-foreground">
|
|
136
|
+
<div className="mb-2 flex items-center gap-2">
|
|
137
|
+
<Icons.Plus aria-hidden="true" className="size-4 text-primary" />
|
|
138
|
+
<strong>${e}</strong>
|
|
139
|
+
</div>
|
|
140
|
+
<p className="mb-2 text-sm text-muted-foreground">{t("mounted_at", { mountPoint })}</p>
|
|
141
|
+
<button
|
|
142
|
+
type="button"
|
|
143
|
+
className="rounded bg-primary px-3 py-2 text-primary-foreground"
|
|
144
|
+
onClick={() => sdk.toast(t("toast_message", { name: "${e}" }))}
|
|
145
|
+
>
|
|
146
|
+
{t("test_button")}
|
|
147
|
+
</button>
|
|
148
|
+
</div>
|
|
149
|
+
)
|
|
150
|
+
}
|
|
151
|
+
`}function j(){return`@import "@jchat/addon-sdk/ui/tailwind.css";`}function M(){return`import * as fs from "node:fs"
|
|
152
|
+
import * as path from "node:path"
|
|
153
|
+
|
|
154
|
+
type Command = "run" | "test" | "reset" | "package" | "cleanup"
|
|
155
|
+
|
|
156
|
+
const command = (process.argv[2] ?? "run") as Command
|
|
157
|
+
if (!["run", "test", "reset", "package", "cleanup"].includes(command)) {
|
|
158
|
+
throw new Error(\`Unknown development-kit command: \${command}\`)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const root = path.resolve(import.meta.dir, "..")
|
|
162
|
+
const environment = {
|
|
163
|
+
...process.env,
|
|
164
|
+
...readEnvironment(path.join(root, ".env"))
|
|
165
|
+
}
|
|
166
|
+
const addonId = environment.JCHAT_SANDBOX_ADDON_ID
|
|
167
|
+
if (!addonId) throw new Error("JCHAT_SANDBOX_ADDON_ID is missing from .env")
|
|
168
|
+
const compose = [
|
|
169
|
+
"docker",
|
|
170
|
+
"compose",
|
|
171
|
+
"--project-name",
|
|
172
|
+
\`jchat-addon-devkit-\${addonId}\`,
|
|
173
|
+
"--file",
|
|
174
|
+
path.join(root, "docker-compose.yml")
|
|
175
|
+
]
|
|
176
|
+
|
|
177
|
+
if (command === "test") {
|
|
178
|
+
await run(["bun", "test"], path.join(root, "addon"), environment)
|
|
179
|
+
} else if (command === "package") {
|
|
180
|
+
await run(["bun", "run", "build"], path.join(root, "addon"), environment)
|
|
181
|
+
} else if (command === "cleanup") {
|
|
182
|
+
await run([...compose, "down", "--remove-orphans", "--volumes"], root, environment)
|
|
183
|
+
} else {
|
|
184
|
+
if (command === "reset") {
|
|
185
|
+
await run([...compose, "down", "--remove-orphans", "--volumes"], root, environment)
|
|
186
|
+
}
|
|
187
|
+
await run(["bun", "run", "build"], path.join(root, "addon"), environment)
|
|
188
|
+
const watcher = Bun.spawn(["bun", "run", "dev"], {
|
|
189
|
+
cwd: path.join(root, "addon"),
|
|
190
|
+
env: environment,
|
|
191
|
+
stdout: "inherit",
|
|
192
|
+
stderr: "inherit"
|
|
193
|
+
})
|
|
194
|
+
try {
|
|
195
|
+
await run([...compose, "up"], root, environment)
|
|
196
|
+
} finally {
|
|
197
|
+
watcher.kill()
|
|
198
|
+
await watcher.exited
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
async function run(command: string[], cwd: string, env: Record<string, string | undefined>) {
|
|
203
|
+
const child = Bun.spawn(command, { cwd, env, stdin: "inherit", stdout: "inherit", stderr: "inherit" })
|
|
204
|
+
const exitCode = await child.exited
|
|
205
|
+
if (exitCode !== 0) throw new Error(\`\${command.join(" ")} exited with code \${exitCode}\`)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function readEnvironment(file: string): Record<string, string> {
|
|
209
|
+
if (!fs.existsSync(file)) throw new Error("Copy .env.example to .env before running the kit")
|
|
210
|
+
return Object.fromEntries(
|
|
211
|
+
fs.readFileSync(file, "utf8")
|
|
212
|
+
.split(/\\r?\\n/)
|
|
213
|
+
.filter((line) => line && !line.startsWith("#"))
|
|
214
|
+
.map((line) => {
|
|
215
|
+
const separator = line.indexOf("=")
|
|
216
|
+
return [line.slice(0, separator), line.slice(separator + 1)]
|
|
217
|
+
})
|
|
218
|
+
)
|
|
219
|
+
}
|
|
220
|
+
`}function N(e){return`# ${P(e)} Development Kit
|
|
221
|
+
|
|
222
|
+
This workspace develops \`${e}\` against the license-free JChat developer sandbox without
|
|
223
|
+
including JChat Core source.
|
|
224
|
+
|
|
225
|
+
## Start
|
|
226
|
+
|
|
227
|
+
\`\`\`powershell
|
|
228
|
+
Copy-Item .env.example .env
|
|
229
|
+
bun install
|
|
230
|
+
bun sandbox
|
|
231
|
+
\`\`\`
|
|
232
|
+
|
|
233
|
+
Open \`http://127.0.0.1:4317\`. The HTTP fixture recorder is available at
|
|
234
|
+
\`http://127.0.0.1:4318/requests\`.
|
|
235
|
+
|
|
236
|
+
## Commands
|
|
237
|
+
|
|
238
|
+
- \`bun sandbox\`
|
|
239
|
+
- \`bun sandbox:test\`
|
|
240
|
+
- \`bun sandbox:reset\`
|
|
241
|
+
- \`bun sandbox:package\`
|
|
242
|
+
- \`bun sandbox:cleanup\`
|
|
243
|
+
|
|
244
|
+
The referenced JChat packages and sandbox image must be published before this standalone kit can
|
|
245
|
+
install or start outside the JChat repository.
|
|
246
|
+
`}function P(e){return e.split(`-`).map(e=>`${e[0]?.toUpperCase()??``}${e.slice(1)}`).join(` `)}export{s as i,o as n,a as r,i as t};
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//#region src/generator.d.ts
|
|
2
|
+
interface StandaloneDevkitOptions {
|
|
3
|
+
addonId: string;
|
|
4
|
+
targetDir: string;
|
|
5
|
+
jchatVersion: string;
|
|
6
|
+
addonSdkVersion: string;
|
|
7
|
+
sandboxImage?: string;
|
|
8
|
+
}
|
|
9
|
+
interface AddonWorkspaceOptions {
|
|
10
|
+
addonId: string;
|
|
11
|
+
targetDir: string;
|
|
12
|
+
isMonorepoWorkspace?: boolean;
|
|
13
|
+
jchatVersion?: string;
|
|
14
|
+
addonSdkVersion?: string;
|
|
15
|
+
}
|
|
16
|
+
declare function createAddonFiles(options: {
|
|
17
|
+
addonId: string;
|
|
18
|
+
isMonorepoWorkspace?: boolean;
|
|
19
|
+
jchatVersion?: string;
|
|
20
|
+
addonSdkVersion?: string;
|
|
21
|
+
}): Readonly<Record<string, string>>;
|
|
22
|
+
declare function writeAddonWorkspace(options: AddonWorkspaceOptions): Promise<void>;
|
|
23
|
+
declare function createStandaloneDevkitFiles(options: StandaloneDevkitOptions): Readonly<Record<string, string>>;
|
|
24
|
+
declare function writeStandaloneDevkit(options: StandaloneDevkitOptions): Promise<void>;
|
|
25
|
+
//#endregion
|
|
26
|
+
export { type AddonWorkspaceOptions, type StandaloneDevkitOptions, createAddonFiles, createStandaloneDevkitFiles, writeAddonWorkspace, writeStandaloneDevkit };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{i as e,n as t,r as n,t as r}from"./generator.mjs";export{r as createAddonFiles,t as createStandaloneDevkitFiles,n as writeAddonWorkspace,e as writeStandaloneDevkit};
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jchat/create-addon",
|
|
3
|
+
"version": "1.0.0-alpha.10",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Command line tool for jchat addon creation.",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"addon",
|
|
8
|
+
"chat",
|
|
9
|
+
"cli",
|
|
10
|
+
"create",
|
|
11
|
+
"jchat",
|
|
12
|
+
"plugin",
|
|
13
|
+
"scaffold"
|
|
14
|
+
],
|
|
15
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/mjjabarullah/jchat.git",
|
|
19
|
+
"directory": "packages/create-addon"
|
|
20
|
+
},
|
|
21
|
+
"bin": {
|
|
22
|
+
"create-addon": "./dist/cli.mjs"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist",
|
|
26
|
+
"README.md",
|
|
27
|
+
"CHANGELOG.md"
|
|
28
|
+
],
|
|
29
|
+
"type": "module",
|
|
30
|
+
"main": "./dist/index.mjs",
|
|
31
|
+
"types": "./dist/index.d.mts",
|
|
32
|
+
"exports": {
|
|
33
|
+
".": {
|
|
34
|
+
"types": "./dist/index.d.mts",
|
|
35
|
+
"import": "./dist/index.mjs"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "tsdown",
|
|
43
|
+
"test": "bun test",
|
|
44
|
+
"lint": "oxlint .",
|
|
45
|
+
"format": "oxfmt . --write",
|
|
46
|
+
"typecheck": "tsc --noEmit",
|
|
47
|
+
"prepack": "bun run build"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@jchat/addon-sdk": "workspace:*",
|
|
51
|
+
"@types/bun": "catalog:",
|
|
52
|
+
"tsdown": "^0.22.14"
|
|
53
|
+
},
|
|
54
|
+
"engines": {
|
|
55
|
+
"bun": ">=1.4.0"
|
|
56
|
+
},
|
|
57
|
+
"jchat": {
|
|
58
|
+
"sandboxImage": "ghcr.io/mjjabarullah/jchat-sandbox"
|
|
59
|
+
}
|
|
60
|
+
}
|