@jskit-ai/agent-docs 0.1.280 → 0.1.281

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 (71) hide show
  1. package/guide/agent/app-extras/assistant-conversation.md +5 -1
  2. package/guide/agent/app-extras/realtime.md +20 -10
  3. package/guide/agent/app-setup/authentication.md +20 -1
  4. package/guide/agent/app-setup/database-layer.md +75 -31
  5. package/guide/agent/app-setup/existing-application-migration.md +7 -1
  6. package/guide/agent/app-setup/multi-homing.md +6 -2
  7. package/guide/agent/app-setup/upgrading-jskit.md +75 -0
  8. package/guide/agent/framework/client-features.md +35 -1
  9. package/guide/agent/framework/sanity-checks.md +4 -3
  10. package/guide/agent/framework/typed-features.md +79 -30
  11. package/package.json +1 -1
  12. package/patterns/feature-package/example/booking-engine/package.json +1 -1
  13. package/patterns/minimal-foundation/example/AGENTS.md +14 -7
  14. package/patterns/minimal-foundation/example/package.json +3 -3
  15. package/patterns/minimal-foundation/example/playwright.config.mjs +3 -33
  16. package/patterns/minimal-foundation/example/server.js +7 -1
  17. package/patterns/minimal-foundation/example/tests/e2e/startup.spec.ts +13 -0
  18. package/patterns/shell-foundation/example/AGENTS.md +14 -7
  19. package/patterns/shell-foundation/example/package.json +4 -4
  20. package/patterns/shell-foundation/example/packages/main/package.json +1 -1
  21. package/patterns/shell-foundation/example/playwright.config.mjs +3 -33
  22. package/patterns/shell-foundation/example/server.js +7 -1
  23. package/patterns/shell-foundation/example/tests/e2e/startup.spec.ts +13 -0
  24. package/reference/autogen/PATTERN_INDEX.md +37 -37
  25. package/reference/autogen/packages/architecture-inspector.md +1 -0
  26. package/reference/autogen/packages/assistant-runtime.md +1 -1
  27. package/reference/autogen/packages/auth-provider-local-core.md +2 -1
  28. package/reference/autogen/packages/connectors-catalog.md +8 -0
  29. package/reference/autogen/packages/database-runtime.md +33 -0
  30. package/reference/autogen/packages/kernel.md +27 -1
  31. package/reference/autogen/packages/oidc-issuer-core.md +0 -1
  32. package/reference/autogen/packages/realtime.md +8 -5
  33. package/reference/autogen/packages/shell-web.md +4 -3
  34. package/reference/autogen/packages/workspaces-core.md +1 -1
  35. package/reference/autogen/tooling/jskit-catalog.md +71 -1
  36. package/skills/jskit/SKILL.md +8 -6
  37. package/skills/jskit/references/client-features.md +35 -1
  38. package/skills/jskit/references/existing-application-migration.md +7 -1
  39. package/skills/jskit/references/heuristics/typed-features.md +2 -2
  40. package/skills/jskit/references/heuristics/ui-testing.md +21 -16
  41. package/skills/jskit/references/multi-homing.md +6 -2
  42. package/skills/jskit/references/pattern-index.md +37 -37
  43. package/skills/jskit/references/patterns/app/minimal-foundation/example/AGENTS.md +14 -7
  44. package/skills/jskit/references/patterns/app/minimal-foundation/example/package.json +3 -3
  45. package/skills/jskit/references/patterns/app/minimal-foundation/example/playwright.config.mjs +3 -33
  46. package/skills/jskit/references/patterns/app/minimal-foundation/example/server.js +7 -1
  47. package/skills/jskit/references/patterns/app/minimal-foundation/example/tests/e2e/startup.spec.ts +13 -0
  48. package/skills/jskit/references/patterns/app/shell-foundation/example/AGENTS.md +14 -7
  49. package/skills/jskit/references/patterns/app/shell-foundation/example/package.json +4 -4
  50. package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/package.json +1 -1
  51. package/skills/jskit/references/patterns/app/shell-foundation/example/playwright.config.mjs +3 -33
  52. package/skills/jskit/references/patterns/app/shell-foundation/example/server.js +7 -1
  53. package/skills/jskit/references/patterns/app/shell-foundation/example/tests/e2e/startup.spec.ts +13 -0
  54. package/skills/jskit/references/patterns/auth/accounts-hub/example/package.json +2 -2
  55. package/skills/jskit/references/patterns/auth/oidc-sign-in/example/package.json +2 -2
  56. package/skills/jskit/references/patterns/auth/supabase-auth/example/package.json +1 -1
  57. package/skills/jskit/references/patterns/connectors/calendar-cli/example/package.json +4 -4
  58. package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/package.json +2 -2
  59. package/skills/jskit/references/patterns/database/mysql-application/PATTERN.md +34 -24
  60. package/skills/jskit/references/patterns/database/mysql-application/example/package.json +3 -2
  61. package/skills/jskit/references/patterns/database/mysql-application/example/tests/e2e/databases.js +25 -0
  62. package/skills/jskit/references/patterns/database/postgres-application/PATTERN.md +12 -0
  63. package/skills/jskit/references/patterns/database/postgres-application/example/package.json +3 -2
  64. package/skills/jskit/references/patterns/database/postgres-application/example/tests/e2e/databases.js +25 -0
  65. package/skills/jskit/references/patterns/realtime/realtime-application/example/package.json +2 -2
  66. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/package.json +1 -1
  67. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/package.json +2 -2
  68. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/package.json +3 -3
  69. package/skills/jskit/references/sanity-checks.md +4 -3
  70. package/skills/jskit/references/typed-features.md +79 -30
  71. package/skills/jskit/references/patterns/database/mysql-application/example/tests/browser/database.js +0 -68
@@ -34,7 +34,8 @@ Exports
34
34
  - `PROVIDER_ID`
35
35
  - `buildAuthPayload({ user, session, profileProjector, profileOptions = {} })`
36
36
  - `buildAuthResult({ user, session, appProfile })`
37
- - `buildSessionAuthPayload({ appProfileProjection, devAuth, profileProjector, request, session, user, syncProfile = true })`
37
+ - `buildProfileChangePayload({ user, profileProjector })`
38
+ - `buildSessionAuthPayload({ appProfileProjection, devAuth, profileProjector, request, session, user, syncProfile = true, onlyWhenChanged = false })`
38
39
  - `findExistingAppProfile(user, profileProjector)`
39
40
  - `isAuthenticatingSession(session)`
40
41
  Local functions
@@ -951,6 +951,14 @@ Exports
951
951
  - `zohoOAuthMetadata(accounts)`
952
952
  - `normalizeZohoTokenResponse(response, expectedApiOrigin)`
953
953
 
954
+ ### `src/shared/ai-definition.js`
955
+ Exports
956
+ - `aiAccessLabels`
957
+ - `aiDefinition`
958
+ - `byAccessThenKey(a, b)`
959
+ - `catalogueProvider(provider, connection)`
960
+ - `configurableProviders`
961
+
954
962
  ### `src/shared/ai.js`
955
963
  Exports
956
964
  - `aiCatalogue`
@@ -16,6 +16,7 @@ Use this on demand; do not load the full index at startup.
16
16
 
17
17
  ### `src/server/database.js`
18
18
  Exports
19
+ - `RUNTIME_QUERY_CHANNEL`
19
20
  - `createDatabase({ driver, env })`
20
21
  Local functions
21
22
  - `resolveDriverDialectId(driver)`
@@ -55,6 +56,38 @@ Local functions
55
56
  Exports
56
57
  - `DatabaseProvider`
57
58
 
59
+ ### `src/server/testDatabaseFile.js`
60
+ Exports
61
+ - None
62
+ Local functions
63
+ - `isRunning(pid)`
64
+ - `claimDatabase(directory, databases)`
65
+
66
+ ### `src/server/testDatabases.js`
67
+ Exports
68
+ - `RUN_SETTINGS_FILE`
69
+ - `countQueries(knex, work)`
70
+ - `countRuntimeQueries(work)`
71
+ - `matchesSnapshot(knexConfig, database, snapshot)`
72
+ - `prepareTestDatabases({ knexConfig, environment, variable = "TEST_DB_NAME", count = 1, seed, schema = {}, appRoot = process.cwd() })`
73
+ - `requireDisposableDatabase(environment, variable, count = 1, { connected = "" } = {})`
74
+ - `restoreTestDatabase(knexConfig, database, snapshot)`
75
+ - `testDatabaseNames(name, count)`
76
+ - `testDatabaseRun({ knexConfig, environment, count, schema, appRoot = process.cwd() })`
77
+ - `testDatabaseSnapshotKey(knexConfig, { appRoot = process.cwd(), schemaFiles = [] } = {})`
78
+ - `type TestDatabaseSchema`
79
+ Local functions
80
+ - `folded(value)`
81
+ - `milliseconds(since)`
82
+ - `ledgerOf(knexConfig)`
83
+ - `connectedDatabaseName(environment)`
84
+ - `knexOn(knexConfig, database, connectionOptions = {})`
85
+ - `withKnex(knexConfig, database, use, connectionOptions)`
86
+ - `ledgerNames(knex, ledger, tables)`
87
+ - `dialectOf(knexConfig)`
88
+ - `refusedPrivilege(error)`
89
+ - `recordStatements(listen, work)`
90
+
58
91
  ### `src/server/types.js`
59
92
  Exports
60
93
  - `type RuntimeDatabase`
@@ -538,6 +538,8 @@ Local functions
538
538
  - `isSurfaceRootRecord(record)`
539
539
  - `hostsChildViews(record)`
540
540
  - `hashScrollMargin(hash)`
541
+ - `isLazyRouteComponent(component)`
542
+ - `preloadOpeningRouteComponents(router, fallbackRoute)`
541
543
 
542
544
  ### `client/shellRouting.js`
543
545
  Exports
@@ -604,8 +606,12 @@ Local functions
604
606
  - `hasClientExport(packageJson)`
605
607
  - `isPathInsideRoot(rootPath, candidatePath)`
606
608
  - `splitSpecifierSuffix(source)`
609
+ - `exportFile(target)`
610
+ - `resolveClientBootImports(installedPackage, { packageMetadataUiRoutes, packageMetadataClientProviders })`
607
611
  - `resolveClientModulesFromInstalledPackages(installedPackages = [])`
608
612
  - `normalizeClientModulePackageMetadataEntries(value)`
613
+ - `normalizeBootProviders(bootImports)`
614
+ - `clientBootSpecifiers(entry)`
609
615
  - `resolveClientRuntimeDedupeSpecifiers(userResolveConfig = {})`
610
616
 
611
617
  ### `client/vite/index.js`
@@ -798,6 +804,12 @@ Local functions
798
804
  - `emptyInput()`
799
805
  - `handlerAsGiven(handler)`
800
806
 
807
+ ### `server/http/lib/deepFrozen.js`
808
+ Exports
809
+ - `isDeepFrozen(value)`
810
+ Local functions
811
+ - `isFrozenThroughout(node, checked)`
812
+
801
813
  ### `server/http/lib/errors.js`
802
814
  Exports
803
815
  - `HttpKernelError`
@@ -831,6 +843,10 @@ Exports
831
843
  - `type ActionCatalogue`
832
844
  - `type RuntimeFastify`
833
845
  Local functions
846
+ - `sharedValidationSchema(schema)`
847
+ - `namesEveryType(value)`
848
+ - `isSharedResponseSchema(entry)`
849
+ - `copyRouteSchema(schema)`
834
850
  - `toFastifyRouteOptions(route)`
835
851
  - `shouldStripFastifyBodySchema(route, schema)`
836
852
  - `normalizeHeaderValue(value)`
@@ -860,6 +876,7 @@ Exports
860
876
  - `resolveRouteValidatorOptions({ method = "", path = "", options = {} } = {})`
861
877
  Local functions
862
878
  - `stripJsonRestTransportExtensions(value)`
879
+ - `stripSchemaCopy(value)`
863
880
  - `normalizeRouteSchemaSection(value, { context = "route section", defaultMode = "patch" } = {})`
864
881
  - `normalizeResponseDefinition(value, { context = "route responses" } = {})`
865
882
  - `normalizeAdvancedFastifySchema(value, { context = "route validator" } = {})`
@@ -869,9 +886,14 @@ Local functions
869
886
  ### `server/http/responseSerializerFactory.js`
870
887
  Exports
871
888
  - `createCachedResponseSerializerFactory(buildSerializer)`
889
+ - `schemaCacheKey(schema)`
872
890
  Local functions
891
+ - `schemaTools()`
873
892
  - `isJsonValue(value, ancestors = new Set())`
874
- - `schemaCacheKey(schema)`
893
+ - `assertValidSchema(schema, name)`
894
+ - `filedSchemaId(schema, fallback)`
895
+ - `everyRefResolves(schema, externalSchemas)`
896
+ - `compiledOnFirstUse(compile, options, key)`
875
897
 
876
898
  ### `server/http/securityHeaders.js`
877
899
  Exports
@@ -1055,6 +1077,7 @@ Exports
1055
1077
  Local functions
1056
1078
  - `fileLockError(message = "", code = FILE_LOCK_ERROR_CODE)`
1057
1079
  - `normalizedAbsolutePath(value = "", label = "path", errorCode = FILE_LOCK_ERROR_CODE)`
1080
+ - `lockThroughDescriptor(fd, cwd)`
1058
1081
 
1059
1082
  ### `server/support/importFreshModuleFromAbsolutePath.js`
1060
1083
  Exports
@@ -1146,3 +1169,6 @@ Local functions
1146
1169
  - `resolveFileDependencyRoot(appRoot, specifier = "")`
1147
1170
  - `resolveInstalledPackageRoot({ appRoot, packageId, parentPackageRoot = "" })`
1148
1171
  - `resolvePackageRoots({ appRoot, packageId, directSpecifier = "", parentPackageRoot = "" })`
1172
+ - `fileStamp(filePath)`
1173
+ - `stampsOf(filePaths)`
1174
+ - `walkInstalledPackages(normalizedAppRoot)`
@@ -174,7 +174,6 @@ Local functions
174
174
  - `isHubPath(url)`
175
175
  - `bearerToken(request)`
176
176
  - `sendRegistrationError(reply, error)`
177
- - `onProviderStatus(reply, matches, action)`
178
177
  - `parseJsonBody(buffer)`
179
178
 
180
179
  ### `src/server/mailer.js`
@@ -76,6 +76,7 @@ Exports
76
76
  - `type RuntimeDatabase`
77
77
  - `type RuntimeLogger`
78
78
  - `type ActorRoomsResolver`
79
+ - `type ActorsRoomsResolver`
79
80
  - `type AudienceContributors`
80
81
  Local functions
81
82
  - `flattenEntries(value)`
@@ -107,16 +108,17 @@ Exports
107
108
 
108
109
  ### `src/server/realtimeDelivery.js`
109
110
  Exports
110
- - `createRealtimeDelivery({ io, database, logger, authService, audiences: { mayContribute, resolveActorRooms } })`
111
+ - `createRealtimeDelivery({ io, database, logger, authService, audiences: { mayContribute, resolveActorsRooms } })`
111
112
  - `matchesRealtimeEvent(event)`
112
113
  - `type AuthService`
113
114
  - `type ActorRoomsResolver`
115
+ - `type ActorsRoomsResolver`
114
116
  - `type AudienceContributors`
115
117
  Local functions
116
118
  - `publicRealtimePayload(event)`
117
- - `valueAsKey(value)`
118
- - `sharedWithinPass(load, keyOf = valueAsKey)`
119
- - `createPassChecks(authService, resolveActorRooms)`
119
+ - `sharedWithinPass(load, keyOf)`
120
+ - `createPassChecks(authService, resolveActorsRooms)`
121
+ - `rememberedActorId(socket)`
120
122
 
121
123
  ### `src/server/RealtimeProvider.js`
122
124
  Exports
@@ -133,7 +135,7 @@ Exports
133
135
  - `REDIS_NAMESPACE_ENV_KEY`
134
136
  - `resolveRealtimeRedisUrl(env)`
135
137
  - `resolveRealtimeRedisNamespace(env)`
136
- - `configureSocketIoRedisAdapter(io, { redisUrl = "", redisNamespace = "", logger, createRedisAdapter = createSocketIoRedisAdapter, createRedisConnection = createRedisClient })`
138
+ - `configureSocketIoRedisAdapter(io, { redisUrl = "", redisNamespace = "", logger, createRedisAdapter, createRedisConnection })`
137
139
  - `closeSocketIoRedisConnections({ pubClient, subClient })`
138
140
  - `countConnectedClients(io)`
139
141
  Local functions
@@ -149,6 +151,7 @@ Exports
149
151
  Exports
150
152
  - `type RuntimeRealtime`
151
153
  - `type ActorRoomsResolver`
154
+ - `type ActorsRoomsResolver`
152
155
  - `type AudienceContributors`
153
156
  - `type RealtimeAudienceContributor`
154
157
 
@@ -500,10 +500,11 @@ Exports
500
500
  - `resolveAppPlacementTopologyExport(exported, logger)`
501
501
  Local functions
502
502
  - `loadAppModule({ importModule, specifier, label, resolve, invalidExportMessage = "", loadFailureMessage, fallback, logger, asyncModuleRecoveryRuntime })`
503
- - `loadAppPlacementDefinitions(logger, asyncModuleRecoveryRuntime)`
504
- - `loadAppPlacementTopology(logger, asyncModuleRecoveryRuntime)`
503
+ - `importAppModules()`
504
+ - `loadAppPlacementDefinitions(logger, asyncModuleRecoveryRuntime, pendingImport)`
505
+ - `loadAppPlacementTopology(logger, asyncModuleRecoveryRuntime, pendingImport)`
505
506
  - `createErrorConfigToolkit(errorRuntime)`
506
- - `loadAppErrorConfig(logger, errorRuntime, asyncModuleRecoveryRuntime)`
507
+ - `loadAppErrorConfig(logger, errorRuntime, asyncModuleRecoveryRuntime, pendingImport)`
507
508
  - `installVueErrorBridge(vueApp, errorRuntime, logger)`
508
509
  - `installRouterErrorBridge(router, errorRuntime, logger)`
509
510
 
@@ -252,7 +252,7 @@ Exports
252
252
  Exports
253
253
  - `WorkspacesIntegrationsProvider`
254
254
  Local functions
255
- - `resolveWorkspaceRealtimeScopes(workspaceMemberships, actorId)`
255
+ - `resolveWorkspaceRealtimeScopes(workspaceMemberships, actorIds)`
256
256
 
257
257
  ### `src/server/workspacesRuntime.js`
258
258
  Exports
@@ -14,6 +14,45 @@ Use this on demand; do not load the full index at startup.
14
14
 
15
15
  ### scripts
16
16
 
17
+ ### `scripts/browser-test-build.mjs`
18
+ Exports
19
+ - `buildFrontend({ appRoot = process.cwd(), build = "npm run build", run = runToCompletion } = {})`
20
+ Local functions
21
+ - `seconds(since)`
22
+ - `digest(file)`
23
+ - `buildFingerprint(appRoot, build, env = process.env)`
24
+ - `runToCompletion(command, appRoot)`
25
+ - `lastBuild(appRoot)`
26
+ - `isRunning(pid)`
27
+ - `lockBuild(appRoot)`
28
+ - `isCurrent(appRoot, inputs)`
29
+
30
+ ### `scripts/browser-test-servers.mjs`
31
+ Exports
32
+ - None
33
+ Local functions
34
+ - `seconds(since)`
35
+ - `words(command)`
36
+ - `prepareWorkers(appRoot, prepare, workers, baseUrls)`
37
+ - `signInWorkers(appRoot, signIn, baseUrls, environments, signedInStates)`
38
+ - `waitUntilReady(url, server, name)`
39
+ - `stopServers()`
40
+
41
+ ### `scripts/browser-test-times.mjs`
42
+ Exports
43
+ - None
44
+
45
+ ### `scripts/browser-tests.mjs`
46
+ Exports
47
+ - `SETTINGS_VARIABLE`
48
+ - `browserTestConfig({ testDir = "./tests/e2e", port = DEFAULT_PORT, server = "node ./bin/server.js", build = "npm run build", prepare = "", signIn = "", env = {}, health = "/api/health", globalTimeout = GLOBAL_TIMEOUT_MS, environment = process.env, cwd = process.cwd() } = {})`
49
+ - `browserTestWorkers({ env = process.env, argv = process.argv } = {})`
50
+ Local functions
51
+ - `positiveInteger(value)`
52
+ - `managedBaseUrl(env)`
53
+ - `commandLineWorkers(argv)`
54
+ - `preparedWorkerEnvironment(file, index)`
55
+
17
56
  ### `scripts/build-catalog.mjs`
18
57
  Exports
19
58
  - None
@@ -245,10 +284,26 @@ Exports
245
284
  Exports
246
285
  - `planTestRuns(args, { cwd = process.cwd(), concurrency = testConcurrency() } = {})`
247
286
  - `runTests(args)`
287
+ - `withTimeReporter(run, destination)`
248
288
  Local functions
249
289
  - `findTestFiles(patterns, cwd)`
250
290
  - `readAloneFiles(files, cwd)`
251
- - `runNode(args)`
291
+ - `aloneDestination(destination)`
292
+ - `aloneRunOptions(options)`
293
+ - `aloneShard(files, options)`
294
+ - `runNode(args, env)`
295
+
296
+ ### `scripts/test-databases.mjs`
297
+ Exports
298
+ - `DATABASES_OPTION`
299
+ - `testDatabaseRunFor(count, cwd = process.cwd())`
300
+ Local functions
301
+ - `withOwnEnvironment(load)`
302
+
303
+ ### `scripts/test-file-stop.mjs`
304
+ Exports
305
+ - `STOPPED_PREFIX`
306
+ - `STOPS_VARIABLE`
252
307
 
253
308
  ### `scripts/test-runs.mjs`
254
309
  Exports
@@ -262,8 +317,23 @@ Local functions
262
317
  - `configOption(args)`
263
318
  - `lineOf(contents, needle, after = "")`
264
319
  - `findConfig(directory, explicit, names)`
320
+ - `usesBrowserHarness(source)`
321
+ - `developmentServerCommand(source)`
322
+ - `checkPlaywrightIsolation({ file, source, report })`
265
323
  - `checkRunnerConfig({ root, configPath, directory, runner, report })`
266
324
 
325
+ ### `scripts/test-time-report.mjs`
326
+ Exports
327
+ - `BOUNDS_FILE`
328
+ - `FILE_TIMES`
329
+ - `checkTestTimes({ bounds, files, tests, wallMs, stopped = [] })`
330
+ - `fileStop({ bound, recorded })`
331
+ - `reportTestTimes({ cwd, collected, directory, wallMs })`
332
+ - `writeFileStops({ cwd, files, directory })`
333
+ Local functions
334
+ - `seconds(ms)`
335
+ - `readTestTimeBounds(cwd)`
336
+
267
337
  ### `scripts/verify-packages.mjs`
268
338
  Exports
269
339
  - `main()`
@@ -131,9 +131,11 @@ slowest files. Find why a check is slow; never raise its time limit. Typed
131
131
  features' repository and Tests rules say how.
132
132
 
133
133
  Test files run in parallel by default, bounded by the machine: a script runs
134
- `jskit test`, never `node --test` or a fixed `--test-concurrency`, and
135
- Playwright's `workers` and Vitest's `maxWorkers` are `testConcurrency()` from
136
- `@jskit-ai/jskit-catalog/test-budget`; plain `jskit check` fails anything else.
137
- Files that collide when run together get isolated (their own port, temporary
138
- directory and database), never serialised. A file that truly must run alone
139
- says why on its first line, `// jskit-test: alone - <reason>`.
134
+ `jskit test` (`--databases`: a `TEST_DB_NAME` copy per file), never
135
+ `node --test` or a fixed `--test-concurrency`; Playwright's config is
136
+ `browserTestConfig()` from `@jskit-ai/jskit-catalog/browser-tests` and Vitest's
137
+ `maxWorkers` is `testConcurrency()` from `@jskit-ai/jskit-catalog/test-budget`.
138
+ Plain `jskit check` fails anything else. Files that collide when run together
139
+ get isolated (their own port, temporary directory and database), never
140
+ serialised. A file that truly must run alone says why on its first line,
141
+ `// jskit-test: alone - <reason>`.
@@ -232,7 +232,7 @@ const ConversationClientProvider = defineProvider({
232
232
  },
233
233
  /** @param {{ components: import("@jskit-ai/kernel/client/types").ClientComponents }} capabilities */
234
234
  setup({ components }) {
235
- components.register("conversation.web.settings.element", ConversationSettingsElement);
235
+ components.register("conversation.web.status.widget", ConversationStatusWidget);
236
236
  }
237
237
  });
238
238
 
@@ -241,6 +241,40 @@ const components = new Map();
241
241
  export function registerComponent(id, component) { components.set(id, component); }
242
242
  ```
243
243
 
244
+ ### Provider subpaths
245
+
246
+ **Export each client provider by a subpath of its own. The provider's file
247
+ imports only what every page needs, such as a widget the shell always shows; a
248
+ screen that only some routes show is imported by those routes.**
249
+
250
+ Why: every page of every app loads the client providers, and what they import,
251
+ before it shows anything. The client bootstrap imports a provider through the
252
+ subpath export that names its file, so the screens `./client` re-exports, and
253
+ their libraries, load only with the routes that show them. A provider without a
254
+ subpath, or a `./client` that declares `routeComponents` or `clientRoutes` or
255
+ uses `export *`, brings all of `./client` to every page.
256
+
257
+ ```json
258
+ // good: package.json
259
+ "exports": {
260
+ "./client": "./src/client/index.js",
261
+ "./client/providers/ConversationClientProvider": "./src/client/providers/ConversationClientProvider.js"
262
+ }
263
+
264
+ // bad: package.json, no subpath for the provider, so every page loads all of ./client
265
+ "exports": {
266
+ "./client": "./src/client/index.js"
267
+ }
268
+ ```
269
+
270
+ ```js
271
+ // good: the provider's file imports the widget every page shows
272
+ import ConversationStatusWidget from "../components/ConversationStatusWidget.vue";
273
+
274
+ // bad: the provider's file imports a screen that only its route shows
275
+ import ConversationSettingsScreen from "../components/ConversationSettingsScreen.vue";
276
+ ```
277
+
244
278
  ### Injected values
245
279
 
246
280
  **`inject()` takes the owner's exported key, never a literal. A required value
@@ -128,7 +128,13 @@ The foundation servers reuse compiled response serializers for identical JSON
128
128
  schemas through `createCachedResponseSerializerFactory` from
129
129
  `@jskit-ai/kernel/server/http`. This reduces duplicate startup compilation and
130
130
  retained memory in applications with many routes. Each Fastify compiler context
131
- keeps its own cache; request data and response payloads are not cached.
131
+ keeps its own cache; request data and response payloads are not cached. A
132
+ serializer is compiled when a response first uses it, in every environment, so
133
+ startup compiles none. Startup still checks every response schema as
134
+ fast-json-stringify would before building it: an invalid schema or a `$ref`
135
+ that does not resolve stops the server. A problem fast-json-stringify only
136
+ finds while generating a serializer fails the first response that uses it, so
137
+ keep a test that calls each route.
132
138
 
133
139
  Existing applications adopt the same setup in their own `server.js` after
134
140
  upgrading JSKIT and declaring the directly used
@@ -85,9 +85,9 @@ ends with the same link.
85
85
  - [Tests are not callers](../typed-features.md#tests-are-not-callers)
86
86
  - `…ForTests`, `__reset…`, `testOnly…` exports (`jskit/no-test-only-export`)
87
87
  - [No test-only exports](../typed-features.md#no-test-only-exports)
88
- - a list, batch or write test with one to three rows, no query count, a fixed query ceiling tuned to pass, a slow endpoint first seen with real data
88
+ - a list, batch or write test with one to three rows, no query count, a fixed query ceiling tuned to pass, a slow endpoint first seen with real data, a hand-written `knex.on("query")` counter, a patched `Client.prototype.query`, `countQueries`, `countRuntimeQueries`, a route's query count
89
89
  - [Query counts at realistic sizes](../typed-features.md#query-counts-at-realistic-sizes)
90
- - `node --test --test-concurrency=1`, `workers: 1`, `fileParallelism: false`, a suite that runs one file at a time, test files that collide when run together, `test/*` findings of `jskit check`
90
+ - `node --test --test-concurrency=1`, `workers: 1`, `fileParallelism: false`, a suite that runs one file at a time, test files that collide when run together, a Playwright webServer running `npm run develop` or `vite`, a browser suite that takes hours, `test/*` findings of `jskit check`
91
91
  - [Test files run in parallel](../typed-features.md#test-files-run-in-parallel)
92
92
  - `knex.migrate.latest()` in each test file, a template database rebuilt by migrating, test preparation slower than its tests
93
93
  - [Test databases are prepared once](../typed-features.md#test-databases-are-prepared-once)
@@ -50,23 +50,28 @@ Rules:
50
50
  ## Keep startup incremental
51
51
 
52
52
  Run related cases in one suite invocation. Prepare the isolated database and
53
- fixtures once for that invocation, never once per test. Retain the test schema
54
- and migration ledger, apply only pending migrations, and reset fixture data
55
- deterministically. Restore any migration-owned baseline rows through the test
56
- seed. MySQL applications start from the `database/mysql-application` pattern's
57
- `example/tests/browser/database.js`. Require a repeat-start regression test that
58
- proves unchanged migration history, removal of stale data, pending migration
59
- application, and isolation from the normal database.
60
-
61
- Use `BROWSER_TEST_DB_NAME` for that retained schema and a different
62
- `TEST_DB_NAME` for disposable integration and migration tests. Reject a name
63
- collision before connecting. Include disposable cleanup between browser starts
64
- in the regression: one test's teardown must not erase another test's migrations.
65
-
66
- Do not drop/recreate the database, replay completed migrations, build every
67
- module fixture, or run a production frontend build for each focused check. A
53
+ fixtures once for that invocation, never once per test. An app's
54
+ `playwright.config.mjs` is `browserTestConfig()` from
55
+ `@jskit-ai/jskit-catalog/browser-tests`: the production build, made once and
56
+ reused while its sources are unchanged, and one server, port and database per
57
+ worker. Its `prepare` module (the `database/mysql-application` and
58
+ `database/postgres-application` patterns' `example/tests/e2e/databases.js`)
59
+ restores each worker's copy of `BROWSER_TEST_DB_NAME` from the stored schema
60
+ snapshot and runs the fixture seed, which restores any migration-owned
61
+ baseline rows. The migrations are replayed only when one changes, so a second
62
+ run reports a stored snapshot, no stale rows, and an unchanged normal
63
+ database.
64
+
65
+ Use `BROWSER_TEST_DB_NAME` for the browser copies and a different
66
+ `TEST_DB_NAME` for disposable integration and migration tests; the harness
67
+ refuses a collision, or one with the application's database, before
68
+ connecting.
69
+
70
+ Do not replay completed migrations, build every module fixture, or run a
71
+ production frontend build for each focused check. A
68
72
  build made once for a whole run is different: it is the fix when a development
69
- server makes every page load slow. Choose small fixture sets for the selected
73
+ server makes every page load slow, and browser tests never run on the
74
+ development server. Choose small fixture sets for the selected
70
75
  suite; realistic row counts belong in the database tests that compare each
71
76
  endpoint's query counts. Fresh-schema
72
77
  migration tests and production-artifact tests are separate operations. Measure
@@ -56,8 +56,12 @@ config.tenancyPolicy = {
56
56
  ```
57
57
 
58
58
  Provisioning runs in the users profile-sync lifecycle after registration and
59
- sign-in. The first run creates the personal workspace, its owner membership and
60
- its settings; later runs reuse it. The default name is the user's display name,
59
+ sign-in, at each session refresh, and on a request whose identity's email or
60
+ display name changed. The first run creates the personal workspace, its owner
61
+ membership and its settings; later runs reuse it. An ordinary request only reads
62
+ the existing profile, so a personal workspace, owner membership or settings row
63
+ deleted while the person is signed in comes back at their next sign-in or
64
+ session refresh, not at their next request. The default name is the user's display name,
61
65
  or email, followed by "'s Workspace". To choose another, provide the
62
66
  `workspaces.personal-workspace-name` capability from an application feature. It
63
67
  receives the synchronized profile (`id`, `displayName`, `email`, `username`), and