@jskit-ai/agent-docs 0.1.257 → 0.1.259

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 (230) hide show
  1. package/guide/agent/app-extras/assistant-conversation.md +88 -35
  2. package/guide/agent/app-extras/assistant.md +28 -28
  3. package/guide/agent/app-setup/authentication.md +36 -17
  4. package/guide/agent/app-setup/database-layer.md +116 -17
  5. package/guide/agent/app-setup/existing-application-migration.md +29 -25
  6. package/guide/agent/app-setup/multi-homing.md +94 -48
  7. package/guide/agent/app-setup/run-an-accounts-hub.md +6 -4
  8. package/guide/agent/framework/client-features.md +496 -0
  9. package/guide/agent/framework/crud-operations.md +5 -5
  10. package/guide/agent/framework/translation.md +4 -3
  11. package/guide/agent/framework/typed-features.md +1104 -0
  12. package/guide/agent/framework/ui-operations.md +2 -2
  13. package/guide/agent/index.md +6 -1
  14. package/package.json +1 -1
  15. package/patterns/feature-package/PATTERN.md +104 -10
  16. package/patterns/feature-package/example/booking-engine/package.json +9 -4
  17. package/patterns/feature-package/example/booking-engine/src/server/BookingEngineFeature.js +24 -0
  18. package/patterns/feature-package/example/booking-engine/src/server/bookingAvailability.js +10 -0
  19. package/patterns/feature-package/example/booking-engine/src/server/bookingEngine.js +29 -0
  20. package/patterns/feature-package/example/booking-engine/src/server/bookingEngineActions.js +26 -0
  21. package/patterns/feature-package/example/booking-engine/src/server/inputSchemas.js +1 -2
  22. package/patterns/feature-package/example/booking-engine/src/server/types.js +12 -0
  23. package/patterns/feature-package/example/variations/AvailabilityEngineFeature.js +19 -0
  24. package/patterns/feature-package/example/variations/InvoiceRollupFeature.js +23 -0
  25. package/patterns/feature-package/example/variations/availabilityEngineActions.js +26 -0
  26. package/patterns/feature-package/example/variations/customKnexRepository.js +32 -26
  27. package/patterns/feature-package/example/variations/invoiceRollupActions.js +26 -0
  28. package/patterns/feature-package/example/variations/orchestratorService.js +24 -19
  29. package/patterns/feature-package/example/variations/types.js +7 -0
  30. package/patterns/minimal-foundation/PATTERN.md +30 -1
  31. package/patterns/minimal-foundation/example/AGENTS.md +14 -0
  32. package/patterns/minimal-foundation/example/bin/develop.js +10 -5
  33. package/patterns/minimal-foundation/example/eslint.config.mjs +21 -2
  34. package/patterns/minimal-foundation/example/package.json +5 -4
  35. package/patterns/minimal-foundation/example/playwright.config.mjs +1 -1
  36. package/patterns/minimal-foundation/example/server/lib/envFile.js +19 -0
  37. package/patterns/minimal-foundation/example/server/lib/loggerOptions.js +15 -0
  38. package/patterns/minimal-foundation/example/server/lib/runtimeEnv.js +17 -17
  39. package/patterns/minimal-foundation/example/server.js +32 -29
  40. package/patterns/minimal-foundation/example/tests/server/smoke.test.js +2 -1
  41. package/patterns/shell-foundation/PATTERN.md +29 -0
  42. package/patterns/shell-foundation/example/AGENTS.md +14 -0
  43. package/patterns/shell-foundation/example/bin/develop.js +10 -5
  44. package/patterns/shell-foundation/example/eslint.config.mjs +21 -2
  45. package/patterns/shell-foundation/example/package.json +6 -5
  46. package/patterns/shell-foundation/example/packages/main/package.json +1 -1
  47. package/patterns/shell-foundation/example/packages/main/src/client/providers/MainClientProvider.js +1 -0
  48. package/patterns/shell-foundation/example/playwright.config.mjs +1 -1
  49. package/patterns/shell-foundation/example/server/lib/envFile.js +19 -0
  50. package/patterns/shell-foundation/example/server/lib/loggerOptions.js +15 -0
  51. package/patterns/shell-foundation/example/server/lib/runtimeEnv.js +17 -17
  52. package/patterns/shell-foundation/example/server.js +32 -29
  53. package/patterns/shell-foundation/example/tests/server/smoke.test.js +2 -1
  54. package/reference/autogen/KERNEL_MAP.md +14 -8
  55. package/reference/autogen/PATTERN_INDEX.md +37 -37
  56. package/reference/autogen/README.md +2 -0
  57. package/reference/autogen/packages/agent-docs.md +70 -26
  58. package/reference/autogen/packages/agent-runtime.md +129 -0
  59. package/reference/autogen/packages/agent.md +149 -0
  60. package/reference/autogen/packages/architecture-inspector.md +97 -44
  61. package/reference/autogen/packages/assistant-core.md +786 -292
  62. package/reference/autogen/packages/assistant-runtime.md +182 -57
  63. package/reference/autogen/packages/assistant-voice-sherpa.md +4 -0
  64. package/reference/autogen/packages/assistant-voice.md +54 -8
  65. package/reference/autogen/packages/auth-core.md +44 -13
  66. package/reference/autogen/packages/auth-provider-local-core.md +86 -34
  67. package/reference/autogen/packages/auth-provider-local-db-core.md +1 -2
  68. package/reference/autogen/packages/auth-provider-oidc-core.md +10 -4
  69. package/reference/autogen/packages/auth-provider-supabase-core.md +52 -66
  70. package/reference/autogen/packages/auth-web.md +19 -11
  71. package/reference/autogen/packages/connectors-catalog.md +71 -43
  72. package/reference/autogen/packages/connectors-core.md +42 -4
  73. package/reference/autogen/packages/console-core.md +27 -14
  74. package/reference/autogen/packages/crud-core.md +178 -170
  75. package/reference/autogen/packages/database-runtime-mysql.md +0 -2
  76. package/reference/autogen/packages/database-runtime-postgres.md +0 -2
  77. package/reference/autogen/packages/database-runtime.md +39 -10
  78. package/reference/autogen/packages/http-runtime.md +79 -57
  79. package/reference/autogen/packages/json-rest-api-core.md +11 -8
  80. package/reference/autogen/packages/kernel.md +144 -83
  81. package/reference/autogen/packages/oidc-issuer-core.md +49 -20
  82. package/reference/autogen/packages/payments-core.md +20 -3
  83. package/reference/autogen/packages/realtime.md +47 -22
  84. package/reference/autogen/packages/resource-core.md +1 -1
  85. package/reference/autogen/packages/resource-crud-core.md +64 -26
  86. package/reference/autogen/packages/rewarded-core.md +47 -36
  87. package/reference/autogen/packages/shell-web.md +7 -10
  88. package/reference/autogen/packages/storage-runtime.md +6 -2
  89. package/reference/autogen/packages/uploads-runtime.md +10 -2
  90. package/reference/autogen/packages/users-core.md +73 -71
  91. package/reference/autogen/packages/workspaces-core.md +121 -106
  92. package/reference/autogen/packages/workspaces-web.md +1 -2
  93. package/reference/autogen/tooling/config-eslint.md +302 -0
  94. package/reference/autogen/tooling/jskit-catalog.md +28 -18
  95. package/reference/autogen/tooling/jskit-release.md +35 -20
  96. package/reference/autogen/tooling/testUtils.md +3 -1
  97. package/skills/jskit/SKILL.md +9 -8
  98. package/skills/jskit/references/app-operations.md +1 -1
  99. package/skills/jskit/references/client-features.md +491 -0
  100. package/skills/jskit/references/crud-form-actions.md +1 -1
  101. package/skills/jskit/references/crud-operations.md +7 -7
  102. package/skills/jskit/references/existing-application-migration.md +31 -27
  103. package/skills/jskit/references/heuristics/INDEX.md +5 -1
  104. package/skills/jskit/references/heuristics/child-cruds.md +1 -1
  105. package/skills/jskit/references/heuristics/client-features.md +66 -0
  106. package/skills/jskit/references/heuristics/client-requests.md +1 -1
  107. package/skills/jskit/references/heuristics/crud-authoring.md +12 -2
  108. package/skills/jskit/references/heuristics/crud-links.md +1 -1
  109. package/skills/jskit/references/heuristics/crud-repository-mapping.md +3 -3
  110. package/skills/jskit/references/heuristics/filters.md +1 -1
  111. package/skills/jskit/references/heuristics/live-actions.md +1 -1
  112. package/skills/jskit/references/heuristics/page-redirects.md +1 -1
  113. package/skills/jskit/references/heuristics/page-scaffolding.md +1 -1
  114. package/skills/jskit/references/heuristics/placements.md +1 -1
  115. package/skills/jskit/references/heuristics/row-policies.md +1 -1
  116. package/skills/jskit/references/heuristics/server-search.md +1 -1
  117. package/skills/jskit/references/heuristics/surfaces.md +1 -1
  118. package/skills/jskit/references/heuristics/typed-features.md +100 -0
  119. package/skills/jskit/references/heuristics/ui-contract.md +1 -1
  120. package/skills/jskit/references/heuristics/ui-testing.md +4 -4
  121. package/skills/jskit/references/material-3.md +2 -2
  122. package/skills/jskit/references/multi-homing.md +96 -50
  123. package/skills/jskit/references/pattern-index.md +37 -37
  124. package/skills/jskit/references/patterns/app/minimal-foundation/PATTERN.md +30 -1
  125. package/skills/jskit/references/patterns/app/minimal-foundation/example/AGENTS.md +14 -0
  126. package/skills/jskit/references/patterns/app/minimal-foundation/example/bin/develop.js +10 -5
  127. package/skills/jskit/references/patterns/app/minimal-foundation/example/eslint.config.mjs +21 -2
  128. package/skills/jskit/references/patterns/app/minimal-foundation/example/package.json +5 -4
  129. package/skills/jskit/references/patterns/app/minimal-foundation/example/playwright.config.mjs +1 -1
  130. package/skills/jskit/references/patterns/app/minimal-foundation/example/server/lib/envFile.js +19 -0
  131. package/skills/jskit/references/patterns/app/minimal-foundation/example/server/lib/loggerOptions.js +15 -0
  132. package/skills/jskit/references/patterns/app/minimal-foundation/example/server/lib/runtimeEnv.js +17 -17
  133. package/skills/jskit/references/patterns/app/minimal-foundation/example/server.js +32 -29
  134. package/skills/jskit/references/patterns/app/minimal-foundation/example/tests/server/smoke.test.js +2 -1
  135. package/skills/jskit/references/patterns/app/shell-foundation/PATTERN.md +29 -0
  136. package/skills/jskit/references/patterns/app/shell-foundation/example/AGENTS.md +14 -0
  137. package/skills/jskit/references/patterns/app/shell-foundation/example/bin/develop.js +10 -5
  138. package/skills/jskit/references/patterns/app/shell-foundation/example/eslint.config.mjs +21 -2
  139. package/skills/jskit/references/patterns/app/shell-foundation/example/package.json +6 -5
  140. package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/package.json +1 -1
  141. package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/src/client/providers/MainClientProvider.js +1 -0
  142. package/skills/jskit/references/patterns/app/shell-foundation/example/playwright.config.mjs +1 -1
  143. package/skills/jskit/references/patterns/app/shell-foundation/example/server/lib/envFile.js +19 -0
  144. package/skills/jskit/references/patterns/app/shell-foundation/example/server/lib/loggerOptions.js +15 -0
  145. package/skills/jskit/references/patterns/app/shell-foundation/example/server/lib/runtimeEnv.js +17 -17
  146. package/skills/jskit/references/patterns/app/shell-foundation/example/server.js +32 -29
  147. package/skills/jskit/references/patterns/app/shell-foundation/example/tests/server/smoke.test.js +2 -1
  148. package/skills/jskit/references/patterns/assistant/assistant-surface/example/src/ApplicationAiFeature.js +4 -2
  149. package/skills/jskit/references/patterns/auth/accounts-hub/PATTERN.md +2 -1
  150. package/skills/jskit/references/patterns/auth/accounts-hub/example/package.json +2 -2
  151. package/skills/jskit/references/patterns/auth/accounts-hub/example/server/hubPaths.js +9 -3
  152. package/skills/jskit/references/patterns/auth/auth-surface/PATTERN.md +25 -12
  153. package/skills/jskit/references/patterns/auth/auth-surface/example/tools/preview-identity +7 -1
  154. package/skills/jskit/references/patterns/auth/oidc-sign-in/example/package.json +2 -2
  155. package/skills/jskit/references/patterns/auth/supabase-auth/example/package.json +1 -1
  156. package/skills/jskit/references/patterns/connectors/ai-connections/PATTERN.md +16 -1
  157. package/skills/jskit/references/patterns/connectors/ai-connections/example/ai-model.js +12 -3
  158. package/skills/jskit/references/patterns/connectors/ai-connections/example/perplexity-answer.js +15 -4
  159. package/skills/jskit/references/patterns/connectors/api-key-connection/PATTERN.md +9 -1
  160. package/skills/jskit/references/patterns/connectors/api-key-connection/example/connections.js +5 -2
  161. package/skills/jskit/references/patterns/connectors/aws-storage-queries/PATTERN.md +13 -3
  162. package/skills/jskit/references/patterns/connectors/aws-storage-queries/example/s3-transfer.js +14 -3
  163. package/skills/jskit/references/patterns/connectors/calendar-cli/PATTERN.md +8 -0
  164. package/skills/jskit/references/patterns/connectors/calendar-cli/example/knexfile.js +1 -1
  165. package/skills/jskit/references/patterns/connectors/calendar-cli/example/package.json +4 -4
  166. package/skills/jskit/references/patterns/connectors/calendar-cli/example/scripts/calendar.js +8 -4
  167. package/skills/jskit/references/patterns/connectors/event-delivery/PATTERN.md +1 -1
  168. package/skills/jskit/references/patterns/connectors/firebase-messaging/PATTERN.md +10 -0
  169. package/skills/jskit/references/patterns/connectors/firebase-messaging/example/server/notifications.js +8 -0
  170. package/skills/jskit/references/patterns/connectors/google-ads-search/PATTERN.md +18 -7
  171. package/skills/jskit/references/patterns/connectors/google-ads-search/example/ads-setup.js +13 -5
  172. package/skills/jskit/references/patterns/connectors/oauth-connection/PATTERN.md +1 -1
  173. package/skills/jskit/references/patterns/connectors/paddle-catalogue/PATTERN.md +11 -2
  174. package/skills/jskit/references/patterns/connectors/paddle-catalogue/example/create-products.js +5 -2
  175. package/skills/jskit/references/patterns/connectors/public-image/PATTERN.md +10 -1
  176. package/skills/jskit/references/patterns/connectors/public-image/example/logo-url.js +4 -1
  177. package/skills/jskit/references/patterns/connectors/redshift-queries/PATTERN.md +1 -1
  178. package/skills/jskit/references/patterns/connectors/source-scanning/PATTERN.md +13 -2
  179. package/skills/jskit/references/patterns/connectors/source-scanning/example/source-scanner.js +9 -0
  180. package/skills/jskit/references/patterns/crud/json-api-resource-package/PATTERN.md +102 -23
  181. package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/package.json +3 -2
  182. package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/src/server/types.js +5 -0
  183. package/skills/jskit/references/patterns/crud/resource-contract/PATTERN.md +54 -1
  184. package/skills/jskit/references/patterns/database/mysql-application/PATTERN.md +16 -5
  185. package/skills/jskit/references/patterns/database/mysql-application/example/knexfile.js +2 -2
  186. package/skills/jskit/references/patterns/database/mysql-application/example/package.json +1 -1
  187. package/skills/jskit/references/patterns/database/mysql-application/example/scripts/prepare-database.js +1 -1
  188. package/skills/jskit/references/patterns/database/postgres-application/PATTERN.md +16 -5
  189. package/skills/jskit/references/patterns/database/postgres-application/example/knexfile.js +2 -2
  190. package/skills/jskit/references/patterns/database/postgres-application/example/package.json +1 -1
  191. package/skills/jskit/references/patterns/database/postgres-application/example/scripts/prepare-database.js +1 -1
  192. package/skills/jskit/references/patterns/realtime/realtime-application/example/package.json +2 -2
  193. package/skills/jskit/references/patterns/rewards/google-rewarded/example/GoogleRewardedDeliveryProvider.js +1 -1
  194. package/skills/jskit/references/patterns/rewards/google-rewarded/example/googlePublisherTag.js +5 -11
  195. package/skills/jskit/references/patterns/server/feature-package/PATTERN.md +104 -10
  196. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/package.json +9 -4
  197. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/BookingEngineFeature.js +24 -0
  198. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/bookingAvailability.js +10 -0
  199. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/bookingEngine.js +29 -0
  200. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/bookingEngineActions.js +26 -0
  201. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/inputSchemas.js +1 -2
  202. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/types.js +12 -0
  203. package/skills/jskit/references/patterns/server/feature-package/example/variations/AvailabilityEngineFeature.js +19 -0
  204. package/skills/jskit/references/patterns/server/feature-package/example/variations/InvoiceRollupFeature.js +23 -0
  205. package/skills/jskit/references/patterns/server/feature-package/example/variations/availabilityEngineActions.js +26 -0
  206. package/skills/jskit/references/patterns/server/feature-package/example/variations/customKnexRepository.js +32 -26
  207. package/skills/jskit/references/patterns/server/feature-package/example/variations/invoiceRollupActions.js +26 -0
  208. package/skills/jskit/references/patterns/server/feature-package/example/variations/orchestratorService.js +24 -19
  209. package/skills/jskit/references/patterns/server/feature-package/example/variations/types.js +7 -0
  210. package/skills/jskit/references/patterns/users/user-administration-server/PATTERN.md +16 -1
  211. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/package.json +3 -2
  212. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/src/server/types.js +5 -0
  213. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/package.json +4 -3
  214. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/src/server/UsersWorkspaceFeature.js +2 -9
  215. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/src/server/types.js +5 -0
  216. package/skills/jskit/references/patterns/workspaces/workspace-server/PATTERN.md +42 -17
  217. package/skills/jskit/references/patterns/workspaces/workspace-server/example/packages/main/src/server/WorkspaceInvitationsFeature.js +27 -0
  218. package/skills/jskit/references/patterns/workspaces/workspace-server/example/packages/main/src/server/email/workspaceInviteEmail.js +11 -10
  219. package/skills/jskit/references/patterns/workspaces/workspace-server/example/packages/main/src/server/email/workspaceInviteMailer.js +27 -0
  220. package/skills/jskit/references/translation.md +5 -4
  221. package/skills/jskit/references/typed-features.md +1099 -0
  222. package/skills/jskit/references/ui-operations.md +3 -3
  223. package/patterns/feature-package/example/booking-engine/src/server/BookingEngineProvider.js +0 -33
  224. package/patterns/feature-package/example/booking-engine/src/server/actions.js +0 -24
  225. package/patterns/feature-package/example/variations/AvailabilityEngineProvider.js +0 -31
  226. package/patterns/feature-package/example/variations/InvoiceRollupProvider.js +0 -36
  227. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/BookingEngineProvider.js +0 -33
  228. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/actions.js +0 -24
  229. package/skills/jskit/references/patterns/server/feature-package/example/variations/AvailabilityEngineProvider.js +0 -31
  230. package/skills/jskit/references/patterns/server/feature-package/example/variations/InvoiceRollupProvider.js +0 -36
@@ -0,0 +1,496 @@
1
+ <!-- Generated by `npm run agent-docs:build` from `packages/agent-docs/site/guide/framework/client-features.md`. Do not edit manually. -->
2
+
3
+ ---
4
+ title: Client features
5
+ description: How JSKIT client code is written (composables, components, client factories and providers), rule by rule with a good and a bad example, and the lint rules that check it.
6
+ ---
7
+
8
+ # Client features
9
+
10
+ Read this page before writing or reviewing JSKIT client code: a composable, a
11
+ Vue component, a client factory or a client provider. It is the client half of
12
+ [typed features](/guide/framework/typed-features): the same rule, the same
13
+ `readable-check: allow` vocabulary and the same size limits, applied to Vue.
14
+ `clientFeaturesConfig` makes the rules a machine can see errors
15
+ ([checks](#checks)); the others are checked by reading.
16
+
17
+ The [client features heuristic](https://github.com/mobily-enterprises/jskit-ai/blob/main/packages/agent-docs/heuristics/client-features.md)
18
+ maps keywords and lint findings to the section that fixes them.
19
+
20
+ ## The rule
21
+
22
+ > Every collaborator client code uses arrives through its options, props,
23
+ > injection or provider capabilities, typed where it is received and required,
24
+ > never probed, so each call has one visible destination.
25
+
26
+ - A **collaborator** is an object or function with behaviour that code calls:
27
+ an adapter, an API client, a state object with methods, a callback, a router.
28
+ Plain data (a label, a list, a record) is not one.
29
+ - A **composable** is a `use<Name>()` function that holds Vue state; a **client
30
+ factory** is a `create<Name>()` that holds none.
31
+
32
+ ## Simplicity
33
+
34
+ ### Simple to reason about
35
+
36
+ **A reader follows each flow top to bottom: plain functions, direct calls,
37
+ names that say what they do.** Satisfying a rule by adding a layer, a
38
+ registry, a pass-through wrapper, meta-programming or a one-use abstraction is
39
+ wrong, and so is splitting a file into many tiny modules to meet a size limit.
40
+
41
+ Signs of over-cleverness: a `create*` that only forwards to another; handlers
42
+ built in a loop or from strings; `Object.fromEntries(… .map(…))` to build an
43
+ API; a `Proxy`; a factory used once; a registry for two entries; a module of
44
+ one three-line helper; files named `utils2`, `part1` or `…Helpers`.
45
+
46
+ Why: the rules exist so code is easy to follow; a contortion that silences one
47
+ defeats it.
48
+
49
+ ```js
50
+ // good: the contract is required, so the calls are direct
51
+ function resend(messageId) {
52
+ return controller.resend(messageId);
53
+ }
54
+
55
+ // bad: a computed layer that hides two probes
56
+ const operations = Object.fromEntries(["find", "resend"].map((name) => [name, (...args) => controller.value?.[name]?.(...args)]));
57
+ ```
58
+
59
+ When a rule seems to force a contortion, take the direct reading that meets
60
+ its intent, and report the case so the rule can be narrowed.
61
+
62
+ ## Types and collaborators
63
+
64
+ ### Client types
65
+
66
+ **A package's client types live in `src/client/types.js`, exported as
67
+ `./client/types` when another package uses them: one `@typedef` per value its
68
+ client code hands out or receives across files.** That is a composable's
69
+ result (`ReturnType<typeof useX>`), a client factory's result, and each
70
+ contract an application implements, written once with its optional members
71
+ marked `?`. Kernel capabilities come from `@jskit-ai/kernel/client/types`:
72
+ `ClientComponents`, `ClientVueApp`, `ClientRouter`, `ClientPinia`,
73
+ `ClientQueryClient`, `ClientEnv`, `ClientSurfaceRuntime`, `ClientSurfaceMode`
74
+ and `ClientLogger`.
75
+
76
+ Why: a parameter that names its type sends a reader to one file.
77
+
78
+ ```js
79
+ // good: src/client/types.js
80
+ /** @typedef {ReturnType<typeof import("./useAttachmentQueue.js").useAttachmentQueue>} AttachmentQueue */
81
+ /**
82
+ * What an application supplies to render a conversation.
83
+ * @typedef {object} ConversationAdapter
84
+ * @property {(text: string) => Promise<void>} send
85
+ * @property {MessageDelivery} [delivery] Present when the application tracks delivery.
86
+ */
87
+ export {};
88
+
89
+ // bad: the shape is whatever the caller passed
90
+ function useConversationActions({ adapter }) {
91
+ ```
92
+
93
+ ### Typed options
94
+
95
+ **A composable, client factory or helper destructures its options in its
96
+ signature and types them with a JSDoc `@param`.** An options object's `= {}`
97
+ stays only where a real caller passes nothing and every member has its own
98
+ default.
99
+
100
+ Why: the same one-step reading as server code; `useX(options)` read in the
101
+ body hides what it needs.
102
+
103
+ ```js
104
+ // good
105
+ /** @param {{ uploadAttachment: AttachmentUpload, onUploaded: (attachment: Attachment) => void }} options */
106
+ function useAttachments({ uploadAttachment, onUploaded }) {
107
+
108
+ // bad
109
+ function useAttachments(options = {}) {
110
+ const upload = options.uploadAttachment;
111
+ ```
112
+
113
+ ### Required options
114
+
115
+ **A collaborator every real caller passes is required: no `= null`, `= {}` or
116
+ no-op default, no `typeof x === "function"` probe and no `x?.()` call.** A
117
+ default that is the production implementation stays (`now = Date.now`).
118
+
119
+ Why: a probe gives each call a second outcome that production never takes.
120
+
121
+ ```js
122
+ // good
123
+ function useAttachments({ uploadAttachment }) {
124
+
125
+ // bad: every caller passes uploadAttachment, yet it is probed
126
+ function useAttachments({ uploadAttachment = null } = {}) {
127
+ if (typeof uploadAttachment !== "function") return;
128
+ ```
129
+
130
+ ### Absent options
131
+
132
+ **What a real caller leaves out takes one of the server's two forms.** A
133
+ per-call callback (`onError`, `onProgress`) defaults to a named no-op and is
134
+ called plainly. An optional operation, a contract member some real caller
135
+ omits, is typed `?`, received with no default, probed once with an
136
+ `optional operation:` allow comment, and branched on that one boolean.
137
+
138
+ - When the member is read live (an application binding behind a getter), probe
139
+ it where it is called, with one allow comment, through one local reader
140
+ function when several sites call it.
141
+ - In a template, call it in the binding, `adapter.actions.reload?.()`, with one
142
+ HTML allow comment directly above the element's opening tag; it covers that
143
+ element's bindings, not its children's. Never `a?.b && a.b()`.
144
+ - A maybe-ref input (`MaybeRefOrGetter<T>`) is read with Vue's `toValue()`.
145
+ - A function whose one job is normalizing a documented external value of
146
+ several shapes carries one `input validation:` allow comment directly above
147
+ it, which covers the probes in its own body. Nowhere else: never over a
148
+ composable, a `setup()` or a function that does more than normalize.
149
+
150
+ A test-only omission counts for none of these: complete the double.
151
+
152
+ Why: one spelling for "may be absent" across server and client, and one probe
153
+ instead of one per call.
154
+
155
+ ```js
156
+ // good
157
+ function ignoreProgress() {}
158
+ function useUpload({ onProgress = ignoreProgress }) {
159
+ onProgress(0);
160
+ }
161
+ /** @param {{ deleteAttachment?: AttachmentDelete }} options */
162
+ function useAttachments({ deleteAttachment }) {
163
+ // readable-check: allow method-probe - optional operation: a read-only queue has no deleteAttachment, so removal stays local
164
+ const canDelete = typeof deleteAttachment === "function";
165
+ }
166
+ const text = toValue(source);
167
+
168
+ // bad
169
+ function useUpload({ onProgress = null }) {
170
+ onProgress?.(0);
171
+ }
172
+ const text = typeof source === "function" ? source() : source.value;
173
+ ```
174
+
175
+ ```html
176
+ <!-- good -->
177
+ <!-- readable-check: allow optional-call - optional operation: a read-only transcript has no reload -->
178
+ <v-btn :disabled="loading" @click="adapter.actions.reload?.()" />
179
+
180
+ <!-- bad -->
181
+ <v-btn v-if="adapter.actions?.reload" @click="adapter.actions.reload()" />
182
+ ```
183
+
184
+ ### Platform probes
185
+
186
+ **A probe of a host object lives in one helper per package,
187
+ `hasWindowFunction(name)`, with one `platform object:` allow comment, and is
188
+ imported.**
189
+
190
+ Why: one treatment per probe kind; copies of a `window` probe drift.
191
+
192
+ ```js
193
+ // good: src/client/browser.js
194
+ /** Whether the page's window has the named function; outside a browser there is no window. */
195
+ function hasWindowFunction(name) {
196
+ // readable-check: allow method-probe - platform object: window and its functions exist only in a browser
197
+ return typeof window !== "undefined" && typeof window[name] === "function";
198
+ }
199
+
200
+ // bad, in five places
201
+ if (typeof window !== "undefined" && typeof window.clearTimeout === "function") window.clearTimeout(timer);
202
+ ```
203
+
204
+ ### Client providers
205
+
206
+ **A client provider follows the server's token rules: `requires`, `optional`
207
+ and `provides` one per line, hooks typed with the kernel's or the owner's
208
+ types, registration in `setup()`, a replaceable value as an `optional` token
209
+ with a named default, and no module-level registry.**
210
+
211
+ Why: client providers are capabilities like server features; a slot filled by
212
+ a setter or a module map has no visible owner.
213
+
214
+ ```js
215
+ // good
216
+ const ConversationClientProvider = defineProvider({
217
+ id: "conversation.web.client",
218
+ requires: {
219
+ components: "client.components"
220
+ },
221
+ /** @param {{ components: import("@jskit-ai/kernel/client/types").ClientComponents }} capabilities */
222
+ setup({ components }) {
223
+ components.register("conversation.web.settings.element", ConversationSettingsElement);
224
+ }
225
+ });
226
+
227
+ // bad
228
+ const components = new Map();
229
+ export function registerComponent(id, component) { components.set(id, component); }
230
+ ```
231
+
232
+ ### Injected values
233
+
234
+ **`inject()` takes the owner's exported key, never a literal. A required value
235
+ is `inject(KEY)`; one that may be absent is `inject(KEY, NAMED_DEFAULT)` with
236
+ the named default exported beside the key. The binding names its type.** A
237
+ key another package owns is imported, with its type and disabled default, from
238
+ that package; a consumer that cannot depend on it writes the key in place,
239
+ typed, with a named `NO_*` default.
240
+
241
+ Why: injection is the client's capability lookup: one key, one type, one
242
+ resolution.
243
+
244
+ ```js
245
+ // good
246
+ /** @type {import("@jskit-ai/workspaces-web/client/types").WorkspaceScopeSupport} */
247
+ const support = inject(WORKSPACE_SCOPE_KEY, NO_WORKSPACE_SCOPE);
248
+
249
+ // bad
250
+ const support = inject("workspaceScope", null);
251
+ if (!support || typeof support.readRouteScope !== "function") return FALLBACK;
252
+ ```
253
+
254
+ ## Components
255
+
256
+ ### Collaborator props
257
+
258
+ **Every prop has a `type` and is required or has a real default. A prop the
259
+ component calls is `required: true`, typed with a `PropType` cast to its
260
+ typedef, and called without `?.`.** A collaborator prop that real callers
261
+ genuinely leave out keeps `default: null`, is typed `PropType<X | null>`,
262
+ carries one `optional operation:` allow comment and is branched on once.
263
+
264
+ Why: a `default: null` collaborator is a probe at every use; a chain of `?.`
265
+ calls on one adapter hides which parts are really optional.
266
+
267
+ ```js
268
+ // good
269
+ const props = defineProps({
270
+ state: { type: /** @type {import("vue").PropType<GoalState>} */ (Object), required: true }
271
+ });
272
+ const canSet = computed(() => !props.state.loading && props.state.available);
273
+
274
+ // bad
275
+ const props = defineProps({ state: { type: Object, default: null } });
276
+ const canSet = computed(() => typeof props.state?.set === "function");
277
+ ```
278
+
279
+ ### Declared emits
280
+
281
+ **`defineEmits()` lists every event the component emits, including those a
282
+ composable emits through the `emit` it receives.**
283
+
284
+ Why: the declaration is the component's event contract, and an undeclared
285
+ event also falls through as a DOM listener.
286
+
287
+ ```js
288
+ // good
289
+ const emit = defineEmits(["close", "closed"]);
290
+
291
+ // bad
292
+ const emit = defineEmits(["close"]);
293
+ emit("closed");
294
+ ```
295
+
296
+ ### Presenting scripts
297
+
298
+ **A component's `<script>` presents: props, emits, element refs, display
299
+ `computed`s and handlers that call a composable or emit.** Requests, state
300
+ machines, timers, parsing and projections live in a composable or a plain
301
+ module, moved verbatim. Split by concern into a few cohesive pieces; a large
302
+ style block moves to `<style scoped src="./X.css">`. Never a subcomponent made
303
+ only to shrink a file: it changes scoped styles and slots.
304
+
305
+ Why: logic in a composable is read and tested without mounting a component.
306
+
307
+ ```text
308
+ good: Transcript.vue (template and presentation), useTranscriptScroll.js,
309
+ transcriptEntries.js (pure projection), Transcript.css via <style scoped src>
310
+ bad: Transcript.vue, 1,600 lines: rendering, scroll anchoring, delivery state and 500 lines of CSS
311
+ ```
312
+
313
+ ## Composables
314
+
315
+ ### Fixed result shape
316
+
317
+ **A composable returns one object literal of named members, the same on every
318
+ path: nothing assigned after construction, no spread of another composable's
319
+ result, no conditional keys, and never `Object.freeze`.** That includes a
320
+ result a callback builds: a wrapper passes what the result needs into the
321
+ callback instead of patching what it returned. An extension that needs the
322
+ object it extends is listed in the literal (`application: null`) and filled
323
+ once right after construction, with a `cycle:` allow comment. A plain
324
+ `create*` that holds no Vue state keeps `Object.freeze`.
325
+
326
+ Why: a fixed shape keeps the type true; and `reactive()` leaves a frozen
327
+ object unproxied while `proxyRefs()` (applied to a `setup()` return and to
328
+ `defineExpose()`) throws on one, so Vue state is never frozen.
329
+
330
+ ```js
331
+ // good
332
+ const suggestions = useSuggestions();
333
+ return { messages, send, suggestions };
334
+ const runtime = app.runWithContext(() => createRuntime(readers, retain));
335
+
336
+ // bad
337
+ return Object.freeze({ messages, send, ...useSuggestions() });
338
+ const runtime = app.runWithContext(() => createRuntime(readers));
339
+ runtime.retain = retain;
340
+ ```
341
+
342
+ ### Effect order
343
+
344
+ **Splitting a composable keeps its `watch()` and `watchEffect()` calls in the
345
+ original composable, in their creation order, calling the extracted module's
346
+ functions.**
347
+
348
+ Why: pre-flush watchers in one scope run in trigger order, so moving them into
349
+ a helper composable can reorder an application's callbacks.
350
+
351
+ ```js
352
+ // good: useConversation.js keeps its watchers in order
353
+ watch(messages, (next) => scroll.follow(next));
354
+ watch(draft, (text) => drafts.save(text));
355
+
356
+ // bad: one watcher moved into useDrafts(), now created before the scroll watcher
357
+ const drafts = useDrafts(draft);
358
+ watch(messages, (next) => scroll.follow(next));
359
+ ```
360
+
361
+ ### Released listeners
362
+
363
+ **Everything client code starts, it stops: each `addEventListener`,
364
+ `setInterval`, observer and `.on()` is released in `onScopeDispose` or
365
+ `onBeforeUnmount`, or registered with `{ once: true }` or an `AbortSignal`
366
+ aborted there.** A listener on an object the code creates with `new` and drops
367
+ with it (its own socket, closed in `disconnect`) goes with that object.
368
+
369
+ Why: a listener that outlives its component leaks memory and fires against
370
+ unmounted state.
371
+
372
+ ```js
373
+ // good
374
+ onMounted(() => window.addEventListener("resize", measure));
375
+ onBeforeUnmount(() => window.removeEventListener("resize", measure));
376
+
377
+ // bad
378
+ onMounted(() => window.addEventListener("resize", () => measure()));
379
+ ```
380
+
381
+ ### Module state
382
+
383
+ **State lives inside the composable or factory that owns it. A module-level
384
+ `let`, `ref()` or `reactive()` exists only when every instance on the page
385
+ must share it, with a `shared resource:` allow comment.** A private memo
386
+ cache nothing fills from outside stays.
387
+
388
+ Why: module scope is shared by every component instance and every application
389
+ on the page, and survives unmounting.
390
+
391
+ ```js
392
+ // good: each composer owns its draft
393
+ function useComposer() {
394
+ const draft = ref("");
395
+ }
396
+ // readable-check: allow module-state - shared resource: every attachment queue on the page draws ids from one sequence
397
+ let attachmentClientSequence = 0;
398
+
399
+ // bad: every composer on the page shares one draft
400
+ let pendingDraft = "";
401
+ ```
402
+
403
+ ## Helpers and sizes
404
+
405
+ ### One helper per package
406
+
407
+ **A pure helper exists once in a package and is imported; one the kernel owns
408
+ (`isRecord`, `normalizeText`) comes from
409
+ `@jskit-ai/kernel/shared/support/normalize`; one client and server code both
410
+ need lives in the package's `src/shared`.**
411
+
412
+ Why: copies drift, and the next reader cannot tell which is right.
413
+
414
+ ```js
415
+ // good
416
+ import { isRecord } from "@jskit-ai/kernel/shared/support/normalize";
417
+
418
+ // bad: a copy in src/client/lib/api.js
419
+ function isRecord(value) { return Boolean(value) && typeof value === "object" && !Array.isArray(value); }
420
+ ```
421
+
422
+ ### Size limits
423
+
424
+ **Files stay under 750 lines and functions under 600; a `.vue` file counts
425
+ whole: template, script and style.** Split by concern
426
+ ([presenting scripts](#presenting-scripts)), never into tiny modules
427
+ ([simple to reason about](#simple-to-reason-about)).
428
+
429
+ Why: a reader holds one concern at a time.
430
+
431
+ ```text
432
+ good: Transcript.vue 420 lines, useTranscriptScroll.js 180, transcriptEntries.js 240
433
+ bad: Transcript.vue 1,600 lines; or eight 90-line files named transcriptPart1.js to transcriptPart8.js
434
+ ```
435
+
436
+ ## Checks
437
+
438
+ ### Running the checks
439
+
440
+ `clientFeaturesConfig(globs)` makes the client rules errors for the client
441
+ code the globs select, Vue components included and tests excluded. A new
442
+ application lists all of it; an existing one lists each client tree as it
443
+ converts it, and nothing else changes until it does:
444
+
445
+ ```js
446
+ import { baseConfig, clientFeaturesConfig, typedFeaturesConfig, vueConfig } from "@jskit-ai/config-eslint/server";
447
+
448
+ export default [
449
+ ...baseConfig,
450
+ ...typedFeaturesConfig(["packages/*/src/server/**", "packages/*/src/shared/**"]),
451
+ ...vueConfig,
452
+ ...clientFeaturesConfig(["packages/*/src/client/**", "src/**"])
453
+ ];
454
+ ```
455
+
456
+ It runs the typed-features rules that read client code, with `use*`
457
+ composables counted as factories and templates read for probes, and the
458
+ client-only rules below. The server's action and error rules do not apply.
459
+
460
+ ### Lint rules
461
+
462
+ | Rule | Reports | Section |
463
+ | --- | --- | --- |
464
+ | `jskit/typed-inject` | `inject()` with a literal key, an untyped binding, or a `null` / `{}` default | [Injected values](#injected-values) |
465
+ | `jskit/collaborator-props` | a prop the component calls that is optional with no named default, or typed only `Object` | [Collaborator props](#collaborator-props) |
466
+ | `jskit/fixed-result-shape` | behaviour assigned to a `use*` / `create*` result after it is built, also one a wrapper's callback built | [Fixed result shape](#fixed-result-shape) |
467
+ | `jskit/no-frozen-vue-state` | `Object.freeze` over refs, computeds or reactive state | [Fixed result shape](#fixed-result-shape) |
468
+ | `jskit/released-listeners` | a listener, interval, observer or subscription the file starts and never releases | [Released listeners](#released-listeners) |
469
+ | `jskit/no-module-state` | a module-level `let`, `ref()` or `reactive()` | [Module state](#module-state) |
470
+ | `vue/require-prop-types`, `vue/require-default-prop`, `vue/require-valid-default-prop`, `vue/no-required-prop-with-default` | a prop without a type, optional without a default, or both | [Collaborator props](#collaborator-props) |
471
+ | `vue/require-explicit-emits` | an emitted event the component does not declare | [Declared emits](#declared-emits) |
472
+
473
+ The typed-features rules keep their own sections:
474
+ [`typed-dependencies`](/guide/framework/typed-features#typed-collaborators),
475
+ [`required-collaborators`](/guide/framework/typed-features#required-collaborators),
476
+ [`no-duplicate-helper`](/guide/framework/typed-features#one-helper-per-package),
477
+ [`no-factory-spread`](/guide/framework/typed-features#named-members) and the
478
+ rest. In client code, `no-slot-setter` reports only a setter named like a slot
479
+ (`setProvider`), `frozen-factory-result` leaves Vue state unfrozen, and
480
+ `no-duplicate-helper` compares a client helper with the whole package, server
481
+ and shared code included.
482
+
483
+ Simplicity, effect order and presenting scripts are checked by reading.
484
+
485
+ ### Exceptions
486
+
487
+ Client exceptions use the
488
+ [typed features exceptions](/guide/framework/typed-features#exceptions): a
489
+ comment on the line before the finding, naming the rule or the finding, with a
490
+ reason prefix. Client code adds three placements:
491
+
492
+ | Placement | The exception |
493
+ | --- | --- |
494
+ | `// readable-check: allow module-state - shared resource: <what the page shares>` | module state every instance on the page shares on purpose |
495
+ | `<!-- readable-check: allow optional-call - optional operation: <what lacks it> -->` above an element | that element's bindings call an optional operation |
496
+ | `// readable-check: allow method-probe - input validation: <the shapes>` above a function | the probes of a function whose one job is normalizing an external value of several shapes |
@@ -338,11 +338,11 @@ make a live table or a generator the sole source of truth. Inspect schemas for
338
338
  adoption and diagnosis; inspection is optional.
339
339
 
340
340
  Read [ordering and recovery](https://mobily-enterprises.github.io/jskit-ai/guide/app-setup/database-layer#directory-order-comes-before-filenames)
341
- before schema work; check Knex configuration and ledger.
342
- `createKnexMigrationConfigFromApp()` uses `sortDirsSeparately: true`: root
343
- `migrations/`, sorted package directories, then `migrations/constraints/`.
344
- Timestamps order only within directories. Keep tables/columns with their package;
345
- put cross-package foreign keys in the final phase.
341
+ before schema work; check Knex configuration and ledger. Package table
342
+ migrations run first, then root `migrations/`, then the constraints phases.
343
+ Timestamps order only within directories. Root migrations may reference package
344
+ tables; keep tables/columns with their package and put foreign keys between
345
+ packages in a constraints phase.
346
346
 
347
347
  MySQL/MariaDB can leave committed DDL without a ledger entry. Check columns and
348
348
  keys separately; `hasColumn()` is insufficient. Validate existing definitions,
@@ -140,9 +140,10 @@ the English `message`:
140
140
  `messageParams` for the exact sentence.
141
141
 
142
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.
143
+ English for that code. An app's own sentence under JSKIT's shared code is shown
144
+ exactly as written, and so is any text whose code has no catalog entry. That is
145
+ why each refusal an app throws
146
+ [carries its own code](/guide/framework/typed-features#refusals-carry-their-own-code).
146
147
 
147
148
  App code that shows errors uses the same helper JSKIT's components use:
148
149