@jskit-ai/agent-docs 0.1.246 → 0.1.248

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.
Files changed (57) hide show
  1. package/guide/agent/app-extras/assistant-conversation.md +10 -4
  2. package/guide/agent/app-extras/realtime.md +8 -4
  3. package/guide/agent/framework/translation.md +227 -0
  4. package/guide/agent/index.md +1 -0
  5. package/package.json +1 -1
  6. package/patterns/feature-package/example/booking-engine/package.json +1 -1
  7. package/patterns/minimal-foundation/example/package.json +3 -3
  8. package/patterns/shell-foundation/example/package.json +4 -4
  9. package/patterns/shell-foundation/example/packages/main/package.json +1 -1
  10. package/reference/autogen/KERNEL_MAP.md +29 -2
  11. package/reference/autogen/PATTERN_INDEX.md +37 -37
  12. package/reference/autogen/packages/assistant-core.md +22 -4
  13. package/reference/autogen/packages/assistant-runtime.md +15 -0
  14. package/reference/autogen/packages/assistant-voice.md +13 -5
  15. package/reference/autogen/packages/auth-core.md +14 -1
  16. package/reference/autogen/packages/auth-provider-local-core.md +1 -1
  17. package/reference/autogen/packages/auth-web.md +12 -2
  18. package/reference/autogen/packages/connector-google-calendar.md +6 -1
  19. package/reference/autogen/packages/connectors-catalog.md +19 -4
  20. package/reference/autogen/packages/connectors-core.md +5 -1
  21. package/reference/autogen/packages/connectors-web.md +5 -0
  22. package/reference/autogen/packages/database-runtime.md +8 -1
  23. package/reference/autogen/packages/http-runtime.md +6 -3
  24. package/reference/autogen/packages/http-web.md +27 -18
  25. package/reference/autogen/packages/kernel.md +76 -7
  26. package/reference/autogen/packages/mobile-capacitor.md +6 -1
  27. package/reference/autogen/packages/payments-core.md +2 -2
  28. package/reference/autogen/packages/payments-web.md +8 -0
  29. package/reference/autogen/packages/realtime.md +6 -0
  30. package/reference/autogen/packages/rewarded-web.md +5 -0
  31. package/reference/autogen/packages/shell-web.md +13 -3
  32. package/reference/autogen/packages/uploads-image-web.md +5 -0
  33. package/reference/autogen/packages/uploads-runtime.md +1 -1
  34. package/reference/autogen/packages/users-core.md +1 -0
  35. package/reference/autogen/packages/users-web.md +22 -0
  36. package/reference/autogen/packages/workspaces-core.md +10 -3
  37. package/reference/autogen/packages/workspaces-web.md +4 -0
  38. package/reference/autogen/tooling/jskit-catalog.md +28 -0
  39. package/skills/jskit/SKILL.md +3 -3
  40. package/skills/jskit/references/pattern-index.md +37 -37
  41. package/skills/jskit/references/patterns/app/minimal-foundation/example/package.json +3 -3
  42. package/skills/jskit/references/patterns/app/shell-foundation/example/package.json +4 -4
  43. package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/package.json +1 -1
  44. package/skills/jskit/references/patterns/auth/accounts-hub/example/package.json +2 -2
  45. package/skills/jskit/references/patterns/auth/oidc-sign-in/example/package.json +2 -2
  46. package/skills/jskit/references/patterns/auth/supabase-auth/example/package.json +1 -1
  47. package/skills/jskit/references/patterns/connectors/calendar-cli/example/package.json +4 -4
  48. package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/package.json +2 -2
  49. package/skills/jskit/references/patterns/database/mysql-application/example/package.json +1 -1
  50. package/skills/jskit/references/patterns/database/postgres-application/example/package.json +1 -1
  51. package/skills/jskit/references/patterns/realtime/realtime-application/example/package.json +2 -2
  52. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/package.json +1 -1
  53. package/skills/jskit/references/patterns/users/account-settings/PATTERN.md +10 -0
  54. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/package.json +2 -2
  55. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/package.json +3 -3
  56. package/skills/jskit/references/patterns/workspaces/workspace-server/PATTERN.md +7 -0
  57. package/skills/jskit/references/translation.md +227 -0
@@ -34,7 +34,7 @@
34
34
  "dependencies": {
35
35
  "@local/main": "0.1.0",
36
36
  "@fastify/static": "^10.1.3",
37
- "@jskit-ai/kernel": "0.1.247",
37
+ "@jskit-ai/kernel": "0.2.0",
38
38
  "@tanstack/vue-query": "^5.101.0",
39
39
  "fastify": "^5.8.5",
40
40
  "json-rest-schema": "^1.0.17",
@@ -42,15 +42,15 @@
42
42
  "vue": "^3.5.44",
43
43
  "vue-router": "^5.3.1",
44
44
  "vuetify": "^4.1.2",
45
- "@jskit-ai/http-runtime": "0.1.245",
45
+ "@jskit-ai/http-runtime": "0.2.0",
46
46
  "@mdi/js": "^7.4.47",
47
- "@jskit-ai/shell-web": "0.1.254",
47
+ "@jskit-ai/shell-web": "0.2.0",
48
48
  "@fastify/fast-json-stringify-compiler": "^5.1.0",
49
49
  "@vue/devtools-api": "^8.2.1"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@jskit-ai/config-eslint": "0.1.241",
53
- "@jskit-ai/jskit-catalog": "0.1.299",
53
+ "@jskit-ai/jskit-catalog": "0.2.0",
54
54
  "@playwright/test": "1.61.1",
55
55
  "@vitejs/plugin-vue": "^6.0.7",
56
56
  "eslint": "^10.8.0",
@@ -9,7 +9,7 @@
9
9
  },
10
10
  "description": "App-local runtime composition and lightweight glue.",
11
11
  "dependencies": {
12
- "@jskit-ai/kernel": "0.1.247"
12
+ "@jskit-ai/kernel": "0.2.0"
13
13
  },
14
14
  "jskit": {
15
15
  "kind": "runtime",
@@ -2,7 +2,7 @@
2
2
  "private": true,
3
3
  "type": "module",
4
4
  "dependencies": {
5
- "@jskit-ai/database-runtime-mysql": "0.1.245",
6
- "@jskit-ai/oidc-issuer-core": "0.1.3"
5
+ "@jskit-ai/database-runtime-mysql": "0.1.247",
6
+ "@jskit-ai/oidc-issuer-core": "0.1.5"
7
7
  }
8
8
  }
@@ -2,7 +2,7 @@
2
2
  "private": true,
3
3
  "type": "module",
4
4
  "dependencies": {
5
- "@jskit-ai/auth-provider-oidc-core": "0.1.4",
6
- "@jskit-ai/auth-web": "0.1.250"
5
+ "@jskit-ai/auth-provider-oidc-core": "0.2.0",
6
+ "@jskit-ai/auth-web": "0.2.0"
7
7
  }
8
8
  }
@@ -2,6 +2,6 @@
2
2
  "private": true,
3
3
  "type": "module",
4
4
  "dependencies": {
5
- "@jskit-ai/auth-provider-supabase-core": "0.1.244"
5
+ "@jskit-ai/auth-provider-supabase-core": "0.2.0"
6
6
  }
7
7
  }
@@ -7,10 +7,10 @@
7
7
  "db:migrate:status": "knex --knexfile ./knexfile.js migrate:list"
8
8
  },
9
9
  "dependencies": {
10
- "@jskit-ai/connectors-core": "0.1.64",
11
- "@jskit-ai/connector-google-calendar": "0.1.64",
12
- "@jskit-ai/database-runtime": "0.1.247",
13
- "@jskit-ai/database-runtime-mysql": "0.1.245",
10
+ "@jskit-ai/connectors-core": "0.2.0",
11
+ "@jskit-ai/connector-google-calendar": "0.2.0",
12
+ "@jskit-ai/database-runtime": "0.1.249",
13
+ "@jskit-ai/database-runtime-mysql": "0.1.247",
14
14
  "knex": "^3.1.0"
15
15
  }
16
16
  }
@@ -8,8 +8,8 @@
8
8
  "./shared": "./src/shared/index.js"
9
9
  },
10
10
  "dependencies": {
11
- "@jskit-ai/crud-core": "0.1.258",
12
- "@jskit-ai/resource-crud-core": "0.1.189"
11
+ "@jskit-ai/crud-core": "0.2.0",
12
+ "@jskit-ai/resource-crud-core": "0.1.191"
13
13
  },
14
14
  "jskit": {
15
15
  "kind": "runtime",
@@ -8,6 +8,6 @@
8
8
  "db:migrate:status": "knex --knexfile ./knexfile.js migrate:list"
9
9
  },
10
10
  "dependencies": {
11
- "@jskit-ai/database-runtime-mysql": "0.1.245"
11
+ "@jskit-ai/database-runtime-mysql": "0.1.247"
12
12
  }
13
13
  }
@@ -8,6 +8,6 @@
8
8
  "db:migrate:status": "knex --knexfile ./knexfile.js migrate:list"
9
9
  },
10
10
  "dependencies": {
11
- "@jskit-ai/database-runtime-postgres": "0.1.244"
11
+ "@jskit-ai/database-runtime-postgres": "0.1.246"
12
12
  }
13
13
  }
@@ -2,7 +2,7 @@
2
2
  "private": true,
3
3
  "type": "module",
4
4
  "dependencies": {
5
- "@jskit-ai/realtime": "0.1.247",
6
- "@jskit-ai/shell-web": "0.1.254"
5
+ "@jskit-ai/realtime": "0.2.0",
6
+ "@jskit-ai/shell-web": "0.2.0"
7
7
  }
8
8
  }
@@ -5,7 +5,7 @@
5
5
  "private": true,
6
6
  "type": "module",
7
7
  "dependencies": {
8
- "@jskit-ai/kernel": "0.1.247",
8
+ "@jskit-ai/kernel": "0.2.0",
9
9
  "json-rest-schema": "^1.0.17"
10
10
  },
11
11
  "exports": {
@@ -28,6 +28,16 @@ section order, and which account operations require reauthentication.
28
28
  Use account settings elements and composables from `@jskit-ai/users-web`,
29
29
  ordinary `useCommand()` mutation behavior, and JSKIT shell placements.
30
30
 
31
+ The runtime's `preferences.options.locale` lists the app's `config.languages`
32
+ (`[{ code, name }]` in the public app config), or a built-in list when the app
33
+ configures none; theme, date and number format options arrive translated. The
34
+ saved locale is a canonical BCP 47 code. `useAccountLocale()` from
35
+ `@jskit-ai/users-web/client` returns it as a read-only ref (`""` when signed
36
+ out), updated at bootstrap and after preferences save. JSKIT does not switch the
37
+ app's language; the app does, for example
38
+ `watch(useAccountLocale(), (code) => { if (code) i18n.global.locale.value = code; }, { immediate: true })`.
39
+ Section titles may be plain text, a message key or `{ key, fallback }`.
40
+
31
41
  ## Invariants
32
42
 
33
43
  - Sections use JSKIT account settings APIs rather than direct HTTP helpers.
@@ -9,8 +9,8 @@
9
9
  "./shared": "./src/shared/index.js"
10
10
  },
11
11
  "dependencies": {
12
- "@jskit-ai/crud-core": "0.1.258",
13
- "@jskit-ai/resource-crud-core": "0.1.189"
12
+ "@jskit-ai/crud-core": "0.2.0",
13
+ "@jskit-ai/resource-crud-core": "0.1.191"
14
14
  },
15
15
  "jskit": {
16
16
  "kind": "runtime",
@@ -9,9 +9,9 @@
9
9
  "./shared": "./src/shared/index.js"
10
10
  },
11
11
  "dependencies": {
12
- "@jskit-ai/crud-core": "0.1.258",
13
- "@jskit-ai/resource-crud-core": "0.1.189",
14
- "@jskit-ai/workspaces-core": "0.1.225"
12
+ "@jskit-ai/crud-core": "0.2.0",
13
+ "@jskit-ai/resource-crud-core": "0.1.191",
14
+ "@jskit-ai/workspaces-core": "0.2.0"
15
15
  },
16
16
  "jskit": {
17
17
  "kind": "runtime",
@@ -49,6 +49,13 @@ responses expose optional `roleLabel` alongside the unchanged `roleSid`.
49
49
  Applications with their own invitation renderer may use its optional
50
50
  `roleLabel` input; `roleSid` remains the stored role id.
51
51
 
52
+ Invitation emails use the recipient's language: `locale` is the saved
53
+ `user_settings.locale` of an existing account with the invited email, else `en`.
54
+ Renderers receive `locale` and `t(key, params)`, which renders a
55
+ `jskit.workspaces.inviteEmail.*` message from the app's
56
+ `src/locales/<code>/jskit.json` (exact locale, then language, then English); the
57
+ mailer's `sendWorkspaceInvite` receives `locale` too.
58
+
52
59
  Keep existing permissions, inheritance, assignability and
53
60
  `workspace.defaultInviteRole` when adding a label. `owner` remains
54
61
  nonassignable. Custom roles, including specialised Training roles, are ordinary
@@ -0,0 +1,227 @@
1
+ <!-- Generated from `packages/agent-docs/site/guide/framework/translation.md` by `npm run agent-docs:build`. -->
2
+
3
+ # Translating a JSKIT app
4
+
5
+ JSKIT ships every screen, message and error in English and can show all of them
6
+ in another language. An app supplies translation files only: it never copies or
7
+ overrides JSKIT components to translate them. An app that supplies no
8
+ translations looks and behaves exactly as an English-only app.
9
+
10
+ ## How it fits together
11
+
12
+ - Every JSKIT package with user-visible text ships `locales/en.json`, a nested
13
+ catalog under its own namespace: `jskit.auth.*`, `jskit.users.*`,
14
+ `jskit.shell.*`, `jskit.http.*`, and so on.
15
+ - JSKIT components translate through the app's
16
+ [vue-i18n](https://vue-i18n.intlify.dev/) instance when the app supplies one,
17
+ and through the bundled English otherwise. `vue-i18n` is an optional peer
18
+ dependency; install it only when the app is translated.
19
+ - The server never decides the language of an error. Every error response
20
+ carries a stable `code`, its `params` and the English `message`; the client
21
+ renders the code in the user's language.
22
+ - Choosing and switching the language is the app's job. JSKIT components follow
23
+ vue-i18n's active locale.
24
+
25
+ ## Pass the app's vue-i18n instance
26
+
27
+ Create the instance in composition mode and give it to the client bootstrap:
28
+
29
+ ```js
30
+ import { createI18n } from "vue-i18n";
31
+ import { bootstrapClientShellApp } from "@jskit-ai/kernel/client";
32
+ import it from "./locales/it/jskit.json" with { type: "json" };
33
+
34
+ const i18n = createI18n({
35
+ legacy: false,
36
+ locale: "en",
37
+ fallbackLocale: "en",
38
+ messages: { it }
39
+ });
40
+
41
+ await bootstrapClientShellApp({ /* existing options */, i18n });
42
+ ```
43
+
44
+ The bootstrap installs the instance (unless `appPlugins` already does) and
45
+ merges every installed package's English into its `en` messages. The app's own
46
+ `en` messages win, so an app can reword a JSKIT text by defining the same key.
47
+ JSKIT refuses a legacy-mode instance (`createI18n({ legacy: true })`).
48
+
49
+ ## Add a language
50
+
51
+ 1. Write the merged English of the app's installed JSKIT packages to a file for
52
+ translators:
53
+
54
+ ```bash
55
+ npx jskit i18n export it
56
+ ```
57
+
58
+ This creates `src/locales/it/jskit.json`. Running it again after upgrading
59
+ JSKIT adds new keys in English and keeps every existing translation.
60
+ 2. Translate the values. Keep every `{placeholder}` exactly; plural messages
61
+ keep the same number of `|`-separated choices as the English.
62
+ 3. Check the file against the installed packages:
63
+
64
+ ```bash
65
+ npx jskit i18n check it
66
+ ```
67
+
68
+ It reports missing and extra keys, invalid messages, placeholder and plural
69
+ mismatches, and (as warnings) values still identical to the English. It exits
70
+ non-zero when keys are missing, a message is invalid or placeholders differ,
71
+ so it can run in CI.
72
+ 4. Load the file into the vue-i18n instance under its locale code, as above.
73
+
74
+ Missing keys fall back to English, so a partly translated language still works.
75
+
76
+ ### Message syntax
77
+
78
+ JSKIT catalogs use a subset of vue-i18n's syntax, and translations must too:
79
+
80
+ - named placeholders: `Use at least {min} characters.`
81
+ - literal text in quotes for the characters `{ } @ $ |`: `support{'@'}example.com`
82
+ - plural choices separated by `|`, chosen by `count`:
83
+ `{count} file | {count} files` (one | other) or
84
+ `no files | one file | {count} files` (zero | one | other)
85
+
86
+ Linked messages (`@:key`), list placeholders (`{0}`) and HTML are not used.
87
+
88
+ ## Use the user's saved language
89
+
90
+ Account preferences store the user's language in `user_settings.locale` as a
91
+ BCP 47 code (for example `it-IT`). The "Language / locale" select offers the
92
+ app's configured languages:
93
+
94
+ ```js
95
+ // config/public.js
96
+ config.languages = [
97
+ { code: "en-US", name: "English (US)" },
98
+ { code: "it-IT", name: "Italiano" }
99
+ ];
100
+ ```
101
+
102
+ Each `name` may also be a message key. A saved locale that is not among the
103
+ configured languages stays selectable under its language name. Without
104
+ `config.languages` the select keeps JSKIT's built-in list, unchanged.
105
+
106
+ JSKIT never switches the app's language itself. `useAccountLocale()` from
107
+ `@jskit-ai/users-web/client` is a read-only ref holding the signed-in user's
108
+ saved locale (`""` when nobody is signed in); it updates after sign-in and after
109
+ the preferences are saved. Follow it in the app:
110
+
111
+ ```js
112
+ import { watch } from "vue";
113
+ import { useAccountLocale } from "@jskit-ai/users-web/client";
114
+
115
+ watch(useAccountLocale(), (locale) => {
116
+ if (locale) i18n.global.locale.value = pickSupportedLocale(locale);
117
+ }, { immediate: true });
118
+ ```
119
+
120
+ `pickSupportedLocale` is the app's own choice, for example `it-IT` → `it` when
121
+ the app ships only `src/locales/it/jskit.json`.
122
+
123
+ ## How errors are shown
124
+
125
+ Every error response from a JSKIT HTTP API has a `code` and `params` next to
126
+ the English `message`:
127
+
128
+ ```json
129
+ { "error": "Invalid email or password.", "code": "auth.login.invalidCredentials", "params": {} }
130
+ ```
131
+
132
+ - Codes added for translation are dotted (`<namespace>.<area>.<name>`) and
133
+ render from the key `jskit.<code>`.
134
+ - Older codes such as `ACTION_PERMISSION_DENIED` or `not_found` keep their
135
+ values and render from `jskit.errors.<code>`.
136
+ - Validation errors keep `details.fieldErrors` (English) and add
137
+ `details.fieldErrorCodes: { field: { code, params } }`.
138
+ - Where one code covers several different sentences (for example
139
+ `connector_input_invalid`), the response also has `messageCode` and
140
+ `messageParams` for the exact sentence.
141
+
142
+ The client translates a code only when the English the server sent is JSKIT's
143
+ English for that code. An app's own sentence under a shared code (for example
144
+ `throw new NotFoundError("Contact not found.")`) is shown exactly as written, and
145
+ so is any text whose code has no catalog entry.
146
+
147
+ App code that shows errors uses the same helper JSKIT's components use:
148
+
149
+ ```js
150
+ import { useJskitText } from "@jskit-ai/kernel/client";
151
+
152
+ const { serverMessage, fieldErrorMessages } = useJskitText();
153
+ const message = serverMessage(error); // translated, or the English sent
154
+ const fieldMessages = fieldErrorMessages(error); // { field: text }
155
+ ```
156
+
157
+ To give the app's own errors codes, throw them with a code and params and add
158
+ the app's English and translations to its vue-i18n messages under the key the
159
+ code maps to:
160
+
161
+ ```js
162
+ throw new AppError(409, "That slug is taken.", { code: "app.project.slugTaken" });
163
+ // en: { jskit: { app: { project: { slugTaken: "That slug is taken." } } } }
164
+ ```
165
+
166
+ ## Placement labels
167
+
168
+ A placement `label` or `title` may be a message key, `{ key, fallback, params }`
169
+ or plain text. JSKIT's menus, tabs, profile menu and account-settings sections
170
+ translate a key and show any other string as written:
171
+
172
+ ```js
173
+ { label: "jskit.users.accountSettings.menuLabel" }
174
+ { label: { key: "app.menu.reports", fallback: "Reports" } }
175
+ { label: "Reports" }
176
+ ```
177
+
178
+ ## Dates and numbers
179
+
180
+ JSKIT formats dates, times, numbers and relative times with `Intl` in the
181
+ active vue-i18n locale. Without an instance, each text keeps the format it had
182
+ before translation support (usually the browser's default).
183
+ App code can use the same helpers from `useJskitText()`: `formatDate`,
184
+ `formatTime`, `formatDateTime`, `formatNumber` and `formatRelativeTime`.
185
+
186
+ ## Emails
187
+
188
+ The workspace invitation email is rendered in the recipient's saved
189
+ `user_settings.locale` when the recipient already has an account, and in English
190
+ otherwise. The server reads the same `src/locales/<code>/jskit.json` files the
191
+ client uses, so translating `jskit.workspaces.inviteEmail.*` there translates
192
+ the email too. It looks for the exact locale (`it-IT`), then the language
193
+ (`it`), then English. The app's invite mailer also receives the chosen `locale`.
194
+
195
+ Server code that renders JSKIT-style messages itself uses the same lookup:
196
+
197
+ ```js
198
+ import { createServerI18n } from "@jskit-ai/kernel/server/i18n";
199
+
200
+ const i18n = createServerI18n({ appRoot, catalogs: [english] });
201
+ i18n.t("it-IT", "jskit.workspaces.inviteEmail.subject", { workspace: "Acme" });
202
+ ```
203
+
204
+ Password-reset emails are sent by the app's own recovery sender (local
205
+ accounts) or by the identity provider (Supabase, OIDC), so their language is
206
+ the app's or the provider's choice.
207
+
208
+ ## What the app translates itself
209
+
210
+ JSKIT's catalogs cover JSKIT's own code. These texts belong to the app:
211
+
212
+ - Vuetify's built-in texts (close buttons, pagination, "No data available").
213
+ Translate them through Vuetify's locale options, or let Vuetify share the
214
+ vue-i18n instance with its `createVueI18nAdapter`.
215
+ - Files the app copied from a JSKIT starter or pattern, such as its
216
+ account-settings sections, placement entries and pages. Once copied they are
217
+ app code: give their texts the app's own keys.
218
+ - The startup HTML in `index.html` (for example "Loading application…"), shown
219
+ before any JavaScript runs.
220
+
221
+ ## Checks inside JSKIT
222
+
223
+ Each JSKIT package with a catalog has a test that compiles every message with
224
+ vue-i18n, requires every key and dotted code its source uses to exist, rejects
225
+ unused keys and refuses a key another package already defines. ESLint's
226
+ `@intlify/vue-i18n/no-raw-text` rule rejects untranslated template text in JSKIT
227
+ client code.