@jchat/addon-sdk 1.0.0-alpha.30 → 1.0.0-alpha.32

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 CHANGED
@@ -1,5 +1,34 @@
1
1
  # @jchat/addon-sdk
2
2
 
3
+ ## 1.0.0-alpha.32
4
+
5
+ No changes in this release.
6
+
7
+ ## 1.0.0-alpha.31
8
+
9
+ ### Minor Changes
10
+
11
+ - Add receiverId to message mutable data and findUserByName to AddonServerContext
12
+
13
+ ### Patch Changes
14
+
15
+ - Clarify mandatory English base localization policy and fix dependency catalog configuration
16
+
17
+ - Add useAddonSettings hook and AddonSettingsLoading component
18
+
19
+ - Allow optional host language translation files with automatic English fallback
20
+
21
+ - Add generic return type to AddonServerContext getConfig
22
+
23
+ - Add findUserByName mock to testing context
24
+
25
+ - Upgrade package type-checking to native bun check for faster validation
26
+
27
+ - Consolidate icons and Tailwind styles into @jchat/addon-sdk/ui
28
+
29
+ - Bumped `@jchat/*` dependencies:
30
+ - [`ui@1.0.0-alpha.28`](https://github.com/jchatcloud/jchat/releases/tag/ui@v1.0.0-alpha.28)
31
+
3
32
  ## 1.0.0-alpha.30
4
33
 
5
34
  ### Minor Changes
package/README.md CHANGED
@@ -14,10 +14,10 @@ Provides typed interfaces, manifest contracts, Vite bundler plugins, and CLI dev
14
14
  JChat addons are **sandboxed, modular extensions** designed to enhance real-time chats without modifying core database schemas or server code.
15
15
 
16
16
  - **Ultra-Lightweight Server Bundles**: Elysia and TypeBox are externalized and provided directly by the host server runtime via `ctx.t` and `app`. Server bundles (`build/api.js`) compile down to just **2–7 KB**.
17
- - **Zero Frontend Bundle Bloat**: Host externals (`react`, `react-dom`, `@jchat/ui`, `@jchat/icon`, `@tanstack/react-query`, `jotai`) are injected at runtime by the JChat host application.
17
+ - **Zero Frontend Bundle Bloat**: Host externals (`react`, `react-dom`, `@jchat/ui`, `@tanstack/react-query`, `jotai`) are injected at runtime by the JChat host application.
18
18
  - **Isolated Database Schema**: Addon tables reside exclusively in the isolated `addons` PostgreSQL schema (e.g. `addons.GlimpseStories`), preventing collisions with core chat tables.
19
19
  - **Scoped Cache & Real-Time Events**: Addons receive namespaced Redis cache (`addon:<id>:<key>`) and real-time WebSocket event broadcasting scoped to sites, rooms, or users.
20
- - **20-Language i18n Standard**: First-class internationalization with 100% parity across all 20 supported host languages, including full RTL direction support.
20
+ - **First-Class i18n & RTL Support**: English (`en.json`) is mandatory as the base localization; the other 19 host languages are optional with automatic runtime fallback to English and full RTL direction support.
21
21
 
22
22
  ---
23
23
 
@@ -121,7 +121,7 @@ Addon UI components receive typed `AddonProps` and access host services via the
121
121
 
122
122
  ```tsx
123
123
  import { useAddonSDK, useAddonQuery, useTranslation, type AddonProps } from "@jchat/addon-sdk"
124
- import Icons from "@jchat/addon-sdk/icon"
124
+ import { Icons } from "@jchat/addon-sdk/ui"
125
125
  import locales from "./locales"
126
126
 
127
127
  export default function MyAddon({ mountPoint, roomId }: AddonProps) {
@@ -308,8 +308,7 @@ export const activeTabAtom = atom<"trending" | "search">("trending")
308
308
 
309
309
  ### 4. Localization: `useTranslation()` & `useLocale()`
310
310
 
311
- Addons must support all **20 host languages**:
312
- `ar`, `bg`, `de`, `el`, `en`, `es`, `fr`, `he`, `hi`, `hr`, `kn`, `ml`, `nl`, `pt`, `ro`, `ru`, `ta`, `te`, `tr`, `ur`.
311
+ English (`en.json`) is strictly mandatory as the base localization. The other 19 host languages (`ar`, `bg`, `de`, `el`, `es`, `fr`, `he`, `hi`, `hr`, `kn`, `ml`, `nl`, `pt`, `ro`, `ru`, `ta`, `te`, `tr`, `ur`) are optional and automatically fall back to English at runtime.
313
312
 
314
313
  ```tsx
315
314
  import { useTranslation, useLocale } from "@jchat/addon-sdk"
@@ -325,12 +324,12 @@ For backend server routes (`src/api.ts`), use `createTranslator(locales, default
325
324
 
326
325
  ---
327
326
 
328
- ### 5. Icons: `@jchat/addon-sdk/icon`
327
+ ### 5. Icons: `@jchat/addon-sdk/ui`
329
328
 
330
- Imports the site's active icon pack directly, ensuring visual consistency with the host theme:
329
+ Imports the site's active icon pack directly from `@jchat/addon-sdk/ui`, ensuring visual consistency with the host theme:
331
330
 
332
331
  ```tsx
333
- import Icons from "@jchat/addon-sdk/icon"
332
+ import { Icons } from "@jchat/addon-sdk/ui"
334
333
 
335
334
  ;<Icons.Heart className="size-4 text-red-500" />
336
335
  ```
@@ -6,12 +6,18 @@ export interface AddonLocaleValidationResult {
6
6
  missingKeys: Record<string, string[]>;
7
7
  extraKeys: Record<string, string[]>;
8
8
  }
9
+ export interface ValidateAddonLocalesOptions {
10
+ strict?: boolean;
11
+ }
9
12
  /**
10
- * Validates that an addon's `locales/` directory contains valid translation files for all 20 host
11
- * languages with 100% key parity against `en.json`.
13
+ * Validates that an addon's `locales/` directory contains a valid `en.json` base file, and that any
14
+ * provided host language files contain valid JSON and matching keys. Missing translations
15
+ * automatically fall back to English at runtime.
12
16
  *
13
17
  * @param dirPath - Path to the addon's locales directory.
14
18
  * @param domainName - Optional label for error messages (defaults to "Addon").
19
+ * @param options - Optional configuration (e.g. `{ strict: true }` to enforce 100% presence of all
20
+ * 20 language files).
15
21
  */
16
- export declare function validateAddonLocales(dirPath: string, domainName?: string): AddonLocaleValidationResult;
22
+ export declare function validateAddonLocales(dirPath: string, domainName?: string, options?: ValidateAddonLocalesOptions): AddonLocaleValidationResult;
17
23
  //#endregion
@@ -14,13 +14,17 @@ function extractNestedKeys(obj, prefix = "") {
14
14
  return keys;
15
15
  }
16
16
  /**
17
- * Validates that an addon's `locales/` directory contains valid translation files for all 20 host
18
- * languages with 100% key parity against `en.json`.
17
+ * Validates that an addon's `locales/` directory contains a valid `en.json` base file, and that any
18
+ * provided host language files contain valid JSON and matching keys. Missing translations
19
+ * automatically fall back to English at runtime.
19
20
  *
20
21
  * @param dirPath - Path to the addon's locales directory.
21
22
  * @param domainName - Optional label for error messages (defaults to "Addon").
23
+ * @param options - Optional configuration (e.g. `{ strict: true }` to enforce 100% presence of all
24
+ * 20 language files).
22
25
  */
23
- function validateAddonLocales(dirPath, domainName = "Addon") {
26
+ function validateAddonLocales(dirPath, domainName = "Addon", options) {
27
+ const isStrict = Boolean(options?.strict);
24
28
  const errors = [];
25
29
  const missingFiles = [];
26
30
  const missingKeys = {};
@@ -58,17 +62,17 @@ function validateAddonLocales(dirPath, domainName = "Addon") {
58
62
  const langFileName = `${lang}.json`;
59
63
  const langPath = path$1.join(dirPath, langFileName);
60
64
  if (!fs$1.existsSync(langPath)) {
61
- errors.push(`[${domainName}] Missing locale file: ${langFileName}`);
62
65
  missingFiles.push(langFileName);
66
+ if (isStrict) errors.push(`[${domainName}] Missing locale file: ${langFileName}`);
63
67
  continue;
64
68
  }
65
69
  try {
66
70
  const langContent = JSON.parse(fs$1.readFileSync(langPath, "utf-8"));
67
71
  const langKeys = new Set(extractNestedKeys(langContent));
68
72
  for (const key of enKeys) if (!langKeys.has(key)) {
69
- errors.push(`[${domainName}] Missing key in ${langFileName}: "${key}"`);
70
73
  if (!missingKeys[lang]) missingKeys[lang] = [];
71
74
  missingKeys[lang].push(key);
75
+ if (isStrict) errors.push(`[${domainName}] Missing key in ${langFileName}: "${key}"`);
72
76
  }
73
77
  for (const key of langKeys) if (!enKeys.has(key)) {
74
78
  errors.push(`[${domainName}] Extra key in ${langFileName} (not in en.json): "${key}"`);