@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.
- package/guide/agent/app-extras/assistant-conversation.md +88 -35
- package/guide/agent/app-extras/assistant.md +28 -28
- package/guide/agent/app-setup/authentication.md +36 -17
- package/guide/agent/app-setup/database-layer.md +116 -17
- package/guide/agent/app-setup/existing-application-migration.md +29 -25
- package/guide/agent/app-setup/multi-homing.md +94 -48
- package/guide/agent/app-setup/run-an-accounts-hub.md +6 -4
- package/guide/agent/framework/client-features.md +496 -0
- package/guide/agent/framework/crud-operations.md +5 -5
- package/guide/agent/framework/translation.md +4 -3
- package/guide/agent/framework/typed-features.md +1104 -0
- package/guide/agent/framework/ui-operations.md +2 -2
- package/guide/agent/index.md +6 -1
- package/package.json +1 -1
- package/patterns/feature-package/PATTERN.md +104 -10
- package/patterns/feature-package/example/booking-engine/package.json +9 -4
- package/patterns/feature-package/example/booking-engine/src/server/BookingEngineFeature.js +24 -0
- package/patterns/feature-package/example/booking-engine/src/server/bookingAvailability.js +10 -0
- package/patterns/feature-package/example/booking-engine/src/server/bookingEngine.js +29 -0
- package/patterns/feature-package/example/booking-engine/src/server/bookingEngineActions.js +26 -0
- package/patterns/feature-package/example/booking-engine/src/server/inputSchemas.js +1 -2
- package/patterns/feature-package/example/booking-engine/src/server/types.js +12 -0
- package/patterns/feature-package/example/variations/AvailabilityEngineFeature.js +19 -0
- package/patterns/feature-package/example/variations/InvoiceRollupFeature.js +23 -0
- package/patterns/feature-package/example/variations/availabilityEngineActions.js +26 -0
- package/patterns/feature-package/example/variations/customKnexRepository.js +32 -26
- package/patterns/feature-package/example/variations/invoiceRollupActions.js +26 -0
- package/patterns/feature-package/example/variations/orchestratorService.js +24 -19
- package/patterns/feature-package/example/variations/types.js +7 -0
- package/patterns/minimal-foundation/PATTERN.md +30 -1
- package/patterns/minimal-foundation/example/AGENTS.md +14 -0
- package/patterns/minimal-foundation/example/bin/develop.js +10 -5
- package/patterns/minimal-foundation/example/eslint.config.mjs +21 -2
- package/patterns/minimal-foundation/example/package.json +5 -4
- package/patterns/minimal-foundation/example/playwright.config.mjs +1 -1
- package/patterns/minimal-foundation/example/server/lib/envFile.js +19 -0
- package/patterns/minimal-foundation/example/server/lib/loggerOptions.js +15 -0
- package/patterns/minimal-foundation/example/server/lib/runtimeEnv.js +17 -17
- package/patterns/minimal-foundation/example/server.js +32 -29
- package/patterns/minimal-foundation/example/tests/server/smoke.test.js +2 -1
- package/patterns/shell-foundation/PATTERN.md +29 -0
- package/patterns/shell-foundation/example/AGENTS.md +14 -0
- package/patterns/shell-foundation/example/bin/develop.js +10 -5
- package/patterns/shell-foundation/example/eslint.config.mjs +21 -2
- package/patterns/shell-foundation/example/package.json +6 -5
- package/patterns/shell-foundation/example/packages/main/package.json +1 -1
- package/patterns/shell-foundation/example/packages/main/src/client/providers/MainClientProvider.js +1 -0
- package/patterns/shell-foundation/example/playwright.config.mjs +1 -1
- package/patterns/shell-foundation/example/server/lib/envFile.js +19 -0
- package/patterns/shell-foundation/example/server/lib/loggerOptions.js +15 -0
- package/patterns/shell-foundation/example/server/lib/runtimeEnv.js +17 -17
- package/patterns/shell-foundation/example/server.js +32 -29
- package/patterns/shell-foundation/example/tests/server/smoke.test.js +2 -1
- package/reference/autogen/KERNEL_MAP.md +14 -8
- package/reference/autogen/PATTERN_INDEX.md +37 -37
- package/reference/autogen/README.md +2 -0
- package/reference/autogen/packages/agent-docs.md +70 -26
- package/reference/autogen/packages/agent-runtime.md +129 -0
- package/reference/autogen/packages/agent.md +149 -0
- package/reference/autogen/packages/architecture-inspector.md +97 -44
- package/reference/autogen/packages/assistant-core.md +786 -292
- package/reference/autogen/packages/assistant-runtime.md +182 -57
- package/reference/autogen/packages/assistant-voice-sherpa.md +4 -0
- package/reference/autogen/packages/assistant-voice.md +54 -8
- package/reference/autogen/packages/auth-core.md +44 -13
- package/reference/autogen/packages/auth-provider-local-core.md +86 -34
- package/reference/autogen/packages/auth-provider-local-db-core.md +1 -2
- package/reference/autogen/packages/auth-provider-oidc-core.md +10 -4
- package/reference/autogen/packages/auth-provider-supabase-core.md +52 -66
- package/reference/autogen/packages/auth-web.md +19 -11
- package/reference/autogen/packages/connectors-catalog.md +71 -43
- package/reference/autogen/packages/connectors-core.md +42 -4
- package/reference/autogen/packages/console-core.md +27 -14
- package/reference/autogen/packages/crud-core.md +178 -170
- package/reference/autogen/packages/database-runtime-mysql.md +0 -2
- package/reference/autogen/packages/database-runtime-postgres.md +0 -2
- package/reference/autogen/packages/database-runtime.md +39 -10
- package/reference/autogen/packages/http-runtime.md +79 -57
- package/reference/autogen/packages/json-rest-api-core.md +11 -8
- package/reference/autogen/packages/kernel.md +144 -83
- package/reference/autogen/packages/oidc-issuer-core.md +49 -20
- package/reference/autogen/packages/payments-core.md +20 -3
- package/reference/autogen/packages/realtime.md +47 -22
- package/reference/autogen/packages/resource-core.md +1 -1
- package/reference/autogen/packages/resource-crud-core.md +64 -26
- package/reference/autogen/packages/rewarded-core.md +47 -36
- package/reference/autogen/packages/shell-web.md +7 -10
- package/reference/autogen/packages/storage-runtime.md +6 -2
- package/reference/autogen/packages/uploads-runtime.md +10 -2
- package/reference/autogen/packages/users-core.md +73 -71
- package/reference/autogen/packages/workspaces-core.md +121 -106
- package/reference/autogen/packages/workspaces-web.md +1 -2
- package/reference/autogen/tooling/config-eslint.md +302 -0
- package/reference/autogen/tooling/jskit-catalog.md +28 -18
- package/reference/autogen/tooling/jskit-release.md +35 -20
- package/reference/autogen/tooling/testUtils.md +3 -1
- package/skills/jskit/SKILL.md +9 -8
- package/skills/jskit/references/app-operations.md +1 -1
- package/skills/jskit/references/client-features.md +491 -0
- package/skills/jskit/references/crud-form-actions.md +1 -1
- package/skills/jskit/references/crud-operations.md +7 -7
- package/skills/jskit/references/existing-application-migration.md +31 -27
- package/skills/jskit/references/heuristics/INDEX.md +5 -1
- package/skills/jskit/references/heuristics/child-cruds.md +1 -1
- package/skills/jskit/references/heuristics/client-features.md +66 -0
- package/skills/jskit/references/heuristics/client-requests.md +1 -1
- package/skills/jskit/references/heuristics/crud-authoring.md +12 -2
- package/skills/jskit/references/heuristics/crud-links.md +1 -1
- package/skills/jskit/references/heuristics/crud-repository-mapping.md +3 -3
- package/skills/jskit/references/heuristics/filters.md +1 -1
- package/skills/jskit/references/heuristics/live-actions.md +1 -1
- package/skills/jskit/references/heuristics/page-redirects.md +1 -1
- package/skills/jskit/references/heuristics/page-scaffolding.md +1 -1
- package/skills/jskit/references/heuristics/placements.md +1 -1
- package/skills/jskit/references/heuristics/row-policies.md +1 -1
- package/skills/jskit/references/heuristics/server-search.md +1 -1
- package/skills/jskit/references/heuristics/surfaces.md +1 -1
- package/skills/jskit/references/heuristics/typed-features.md +100 -0
- package/skills/jskit/references/heuristics/ui-contract.md +1 -1
- package/skills/jskit/references/heuristics/ui-testing.md +4 -4
- package/skills/jskit/references/material-3.md +2 -2
- package/skills/jskit/references/multi-homing.md +96 -50
- package/skills/jskit/references/pattern-index.md +37 -37
- package/skills/jskit/references/patterns/app/minimal-foundation/PATTERN.md +30 -1
- package/skills/jskit/references/patterns/app/minimal-foundation/example/AGENTS.md +14 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/bin/develop.js +10 -5
- package/skills/jskit/references/patterns/app/minimal-foundation/example/eslint.config.mjs +21 -2
- package/skills/jskit/references/patterns/app/minimal-foundation/example/package.json +5 -4
- package/skills/jskit/references/patterns/app/minimal-foundation/example/playwright.config.mjs +1 -1
- package/skills/jskit/references/patterns/app/minimal-foundation/example/server/lib/envFile.js +19 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/server/lib/loggerOptions.js +15 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/server/lib/runtimeEnv.js +17 -17
- package/skills/jskit/references/patterns/app/minimal-foundation/example/server.js +32 -29
- package/skills/jskit/references/patterns/app/minimal-foundation/example/tests/server/smoke.test.js +2 -1
- package/skills/jskit/references/patterns/app/shell-foundation/PATTERN.md +29 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/AGENTS.md +14 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/bin/develop.js +10 -5
- package/skills/jskit/references/patterns/app/shell-foundation/example/eslint.config.mjs +21 -2
- package/skills/jskit/references/patterns/app/shell-foundation/example/package.json +6 -5
- package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/package.json +1 -1
- package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/src/client/providers/MainClientProvider.js +1 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/playwright.config.mjs +1 -1
- package/skills/jskit/references/patterns/app/shell-foundation/example/server/lib/envFile.js +19 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/server/lib/loggerOptions.js +15 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/server/lib/runtimeEnv.js +17 -17
- package/skills/jskit/references/patterns/app/shell-foundation/example/server.js +32 -29
- package/skills/jskit/references/patterns/app/shell-foundation/example/tests/server/smoke.test.js +2 -1
- package/skills/jskit/references/patterns/assistant/assistant-surface/example/src/ApplicationAiFeature.js +4 -2
- package/skills/jskit/references/patterns/auth/accounts-hub/PATTERN.md +2 -1
- package/skills/jskit/references/patterns/auth/accounts-hub/example/package.json +2 -2
- package/skills/jskit/references/patterns/auth/accounts-hub/example/server/hubPaths.js +9 -3
- package/skills/jskit/references/patterns/auth/auth-surface/PATTERN.md +25 -12
- package/skills/jskit/references/patterns/auth/auth-surface/example/tools/preview-identity +7 -1
- package/skills/jskit/references/patterns/auth/oidc-sign-in/example/package.json +2 -2
- package/skills/jskit/references/patterns/auth/supabase-auth/example/package.json +1 -1
- package/skills/jskit/references/patterns/connectors/ai-connections/PATTERN.md +16 -1
- package/skills/jskit/references/patterns/connectors/ai-connections/example/ai-model.js +12 -3
- package/skills/jskit/references/patterns/connectors/ai-connections/example/perplexity-answer.js +15 -4
- package/skills/jskit/references/patterns/connectors/api-key-connection/PATTERN.md +9 -1
- package/skills/jskit/references/patterns/connectors/api-key-connection/example/connections.js +5 -2
- package/skills/jskit/references/patterns/connectors/aws-storage-queries/PATTERN.md +13 -3
- package/skills/jskit/references/patterns/connectors/aws-storage-queries/example/s3-transfer.js +14 -3
- package/skills/jskit/references/patterns/connectors/calendar-cli/PATTERN.md +8 -0
- package/skills/jskit/references/patterns/connectors/calendar-cli/example/knexfile.js +1 -1
- package/skills/jskit/references/patterns/connectors/calendar-cli/example/package.json +4 -4
- package/skills/jskit/references/patterns/connectors/calendar-cli/example/scripts/calendar.js +8 -4
- package/skills/jskit/references/patterns/connectors/event-delivery/PATTERN.md +1 -1
- package/skills/jskit/references/patterns/connectors/firebase-messaging/PATTERN.md +10 -0
- package/skills/jskit/references/patterns/connectors/firebase-messaging/example/server/notifications.js +8 -0
- package/skills/jskit/references/patterns/connectors/google-ads-search/PATTERN.md +18 -7
- package/skills/jskit/references/patterns/connectors/google-ads-search/example/ads-setup.js +13 -5
- package/skills/jskit/references/patterns/connectors/oauth-connection/PATTERN.md +1 -1
- package/skills/jskit/references/patterns/connectors/paddle-catalogue/PATTERN.md +11 -2
- package/skills/jskit/references/patterns/connectors/paddle-catalogue/example/create-products.js +5 -2
- package/skills/jskit/references/patterns/connectors/public-image/PATTERN.md +10 -1
- package/skills/jskit/references/patterns/connectors/public-image/example/logo-url.js +4 -1
- package/skills/jskit/references/patterns/connectors/redshift-queries/PATTERN.md +1 -1
- package/skills/jskit/references/patterns/connectors/source-scanning/PATTERN.md +13 -2
- package/skills/jskit/references/patterns/connectors/source-scanning/example/source-scanner.js +9 -0
- package/skills/jskit/references/patterns/crud/json-api-resource-package/PATTERN.md +102 -23
- package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/package.json +3 -2
- package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/src/server/types.js +5 -0
- package/skills/jskit/references/patterns/crud/resource-contract/PATTERN.md +54 -1
- package/skills/jskit/references/patterns/database/mysql-application/PATTERN.md +16 -5
- package/skills/jskit/references/patterns/database/mysql-application/example/knexfile.js +2 -2
- package/skills/jskit/references/patterns/database/mysql-application/example/package.json +1 -1
- package/skills/jskit/references/patterns/database/mysql-application/example/scripts/prepare-database.js +1 -1
- package/skills/jskit/references/patterns/database/postgres-application/PATTERN.md +16 -5
- package/skills/jskit/references/patterns/database/postgres-application/example/knexfile.js +2 -2
- package/skills/jskit/references/patterns/database/postgres-application/example/package.json +1 -1
- package/skills/jskit/references/patterns/database/postgres-application/example/scripts/prepare-database.js +1 -1
- package/skills/jskit/references/patterns/realtime/realtime-application/example/package.json +2 -2
- package/skills/jskit/references/patterns/rewards/google-rewarded/example/GoogleRewardedDeliveryProvider.js +1 -1
- package/skills/jskit/references/patterns/rewards/google-rewarded/example/googlePublisherTag.js +5 -11
- package/skills/jskit/references/patterns/server/feature-package/PATTERN.md +104 -10
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/package.json +9 -4
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/BookingEngineFeature.js +24 -0
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/bookingAvailability.js +10 -0
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/bookingEngine.js +29 -0
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/bookingEngineActions.js +26 -0
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/inputSchemas.js +1 -2
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/types.js +12 -0
- package/skills/jskit/references/patterns/server/feature-package/example/variations/AvailabilityEngineFeature.js +19 -0
- package/skills/jskit/references/patterns/server/feature-package/example/variations/InvoiceRollupFeature.js +23 -0
- package/skills/jskit/references/patterns/server/feature-package/example/variations/availabilityEngineActions.js +26 -0
- package/skills/jskit/references/patterns/server/feature-package/example/variations/customKnexRepository.js +32 -26
- package/skills/jskit/references/patterns/server/feature-package/example/variations/invoiceRollupActions.js +26 -0
- package/skills/jskit/references/patterns/server/feature-package/example/variations/orchestratorService.js +24 -19
- package/skills/jskit/references/patterns/server/feature-package/example/variations/types.js +7 -0
- package/skills/jskit/references/patterns/users/user-administration-server/PATTERN.md +16 -1
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/package.json +3 -2
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/src/server/types.js +5 -0
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/package.json +4 -3
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/src/server/UsersWorkspaceFeature.js +2 -9
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/src/server/types.js +5 -0
- package/skills/jskit/references/patterns/workspaces/workspace-server/PATTERN.md +42 -17
- package/skills/jskit/references/patterns/workspaces/workspace-server/example/packages/main/src/server/WorkspaceInvitationsFeature.js +27 -0
- package/skills/jskit/references/patterns/workspaces/workspace-server/example/packages/main/src/server/email/workspaceInviteEmail.js +11 -10
- package/skills/jskit/references/patterns/workspaces/workspace-server/example/packages/main/src/server/email/workspaceInviteMailer.js +27 -0
- package/skills/jskit/references/translation.md +5 -4
- package/skills/jskit/references/typed-features.md +1099 -0
- package/skills/jskit/references/ui-operations.md +3 -3
- package/patterns/feature-package/example/booking-engine/src/server/BookingEngineProvider.js +0 -33
- package/patterns/feature-package/example/booking-engine/src/server/actions.js +0 -24
- package/patterns/feature-package/example/variations/AvailabilityEngineProvider.js +0 -31
- package/patterns/feature-package/example/variations/InvoiceRollupProvider.js +0 -36
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/BookingEngineProvider.js +0 -33
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/actions.js +0 -24
- package/skills/jskit/references/patterns/server/feature-package/example/variations/AvailabilityEngineProvider.js +0 -31
- package/skills/jskit/references/patterns/server/feature-package/example/variations/InvoiceRollupProvider.js +0 -36
|
@@ -93,7 +93,7 @@ as not sent with `conversation_message_cancelled`. It also stops a submission
|
|
|
93
93
|
that holds the message, and afterwards discards its unconfirmed request or
|
|
94
94
|
pending native attempt. A message already accepted stays history. An
|
|
95
95
|
application conversation provides this as `cancelDelivery({ messageId })`;
|
|
96
|
-
without it the operation answers `
|
|
96
|
+
without it the operation answers `conversation_message_cancel_unsupported`. Browser inputs cannot set the actor,
|
|
97
97
|
native host or engine context.
|
|
98
98
|
`readConversation(id, { beforeTurnId, limit, signal })` optionally requests an
|
|
99
99
|
earlier or bounded page through the same authenticated GET. Its query contains
|
|
@@ -1120,8 +1120,8 @@ separate concerns.
|
|
|
1120
1120
|
## Optional shared capabilities
|
|
1121
1121
|
|
|
1122
1122
|
All capabilities below are optional. Omit their adapter field to leave them off.
|
|
1123
|
-
They work in the aggregate element and as separately exported components;
|
|
1124
|
-
|
|
1123
|
+
They work in the aggregate element and as separately exported components; a hosted
|
|
1124
|
+
editor can use the same components with its native transport and project policy.
|
|
1125
1125
|
Configuration UI never grants backend permissions.
|
|
1126
1126
|
|
|
1127
1127
|
### Working status and suggestions
|
|
@@ -1312,7 +1312,7 @@ adapter.attachments = reactive(useAssistantAttachments({
|
|
|
1312
1312
|
```
|
|
1313
1313
|
|
|
1314
1314
|
`sessionId` is an opaque application upload scope, such as a conversation or
|
|
1315
|
-
session identifier. It does not require
|
|
1315
|
+
session identifier. It does not require a hosted editor. The application owns routes,
|
|
1316
1316
|
authentication, storage, limits, inspection, retention and provider file access.
|
|
1317
1317
|
An upload returns `{ attachmentId, fileName, size }` with optional `reference` and
|
|
1318
1318
|
application fields. Progress reports use `{ loaded, total }`. The controller
|
|
@@ -1479,7 +1479,7 @@ history, sends, stops, deletion and attachment reads. The memory reference
|
|
|
1479
1479
|
adapter requires a nonempty string; other adapters may use structured scopes.
|
|
1480
1480
|
|
|
1481
1481
|
Each callback receives these asynchronous operations. The first six serve the
|
|
1482
|
-
transcript service. All
|
|
1482
|
+
transcript service. All the others are mandatory for `createConversationRuntime()`:
|
|
1483
1483
|
|
|
1484
1484
|
| Transaction operation | Contract |
|
|
1485
1485
|
| --- | --- |
|
|
@@ -1493,6 +1493,9 @@ transcript service. All nine are mandatory for `createConversationRuntime()`:
|
|
|
1493
1493
|
| `readMetadata()` | Detached conversation metadata object; return `{}` for an empty scope. |
|
|
1494
1494
|
| `writeMetadata(value)` | Replace conversation metadata within this transaction, committing atomically with its turn/message changes. |
|
|
1495
1495
|
| `updateTurnMetadata(turnId, patch)` | Shallow-merge a detached patch into an existing turn's metadata; preserve unrelated keys and reject absent turns. |
|
|
1496
|
+
| `readTurnsAfter(turnId)` | Detached snapshots of the turns after that turn, oldest first, as `readTurn` returns them; `""` reads every turn. Reject an absent turn. |
|
|
1497
|
+
| `readSummary()` | The API compaction summary `{ text, throughTurnId }` (the last turn it covers), detached, or null. |
|
|
1498
|
+
| `writeSummary({ text, throughTurnId })` | Replace that summary within this transaction; reject empty text or an absent turn. Messages are never deleted. |
|
|
1496
1499
|
|
|
1497
1500
|
`write` serializes mutations for the same scope, including duplicate checks and
|
|
1498
1501
|
ID allocation. A successful return means the write is durable for that adapter.
|
|
@@ -1505,6 +1508,9 @@ Reads must not expose mutable backing objects.
|
|
|
1505
1508
|
Use storage-level locks or transactions when several processes share storage;
|
|
1506
1509
|
an in-process promise queue alone does not provide that guarantee.
|
|
1507
1510
|
|
|
1511
|
+
`readConversationLog(scope, { afterTurnId })` reads only the turns after that turn,
|
|
1512
|
+
through the transaction's `readTurnsAfter`.
|
|
1513
|
+
|
|
1508
1514
|
The service exposes `readConversationLog`, `readConversationLogPage`,
|
|
1509
1515
|
`conversationMessageIdExists`, `writeConversationUserMessage`,
|
|
1510
1516
|
`writeConversationAssistantMessage`, `writeConversationThinkingMessage`,
|
|
@@ -1536,7 +1542,8 @@ await verifyConversationStorageContract(storage, { runtime: true });
|
|
|
1536
1542
|
Those checks cover scoped isolation, concurrent duplicate writes, stable
|
|
1537
1543
|
ordering, pagination, final replacement, attachments and detached reads. An
|
|
1538
1544
|
adapter selected with `runtime: true` also checks all metadata operations, scope
|
|
1539
|
-
isolation, patch preservation
|
|
1545
|
+
isolation, patch preservation, combined transcript/metadata rollback, reading the
|
|
1546
|
+
turns after a turn and the saved, scoped and rolled-back compaction summary. Use a
|
|
1540
1547
|
fresh isolated fixture for each invocation; omit the option only for transcript-only
|
|
1541
1548
|
adapters. An app must additionally test its authentication, crash/reopen behavior,
|
|
1542
1549
|
multi-process writes, failed commits and attachment cleanup.
|
|
@@ -2390,7 +2397,8 @@ the same transaction. The file adapter remains one-writer storage.
|
|
|
2390
2397
|
|
|
2391
2398
|
`createConversationStorage({ readRecord, writeRecord, deleteRecord, recordVersion })` is exported
|
|
2392
2399
|
for custom single-writer record stores. Each record contains `{ turns: Map,
|
|
2393
|
-
metadata: object }
|
|
2400
|
+
metadata: object }` and, once an API conversation is compacted, `summary: { text,
|
|
2401
|
+
throughTurnId }`; a missing record uses an empty map and metadata object. Its
|
|
2394
2402
|
copy-on-write transaction methods match the supplied memory/file adapters. Saved
|
|
2395
2403
|
records are shared and never changed in place; a transaction copies only the turn
|
|
2396
2404
|
map and the turns it changes. The optional `recordVersion(id)` returns a cheap
|
|
@@ -2405,26 +2413,69 @@ serializes writes through one instance, not across processes. A database-backed
|
|
|
2405
2413
|
application with concurrent writers must implement `read`/`write` using its own
|
|
2406
2414
|
database transaction or hold that transaction across record loading and commit.
|
|
2407
2415
|
|
|
2408
|
-
The
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2416
|
+
The API driver runs each reply on the agent engine, `@jskit-ai/agent`. It supports
|
|
2417
|
+
application action tools and authorized attachments, and reports steering and native
|
|
2418
|
+
goals as unsupported. Limits can bound input and output characters, output tokens,
|
|
2419
|
+
steps and request duration. `limits.maxOutputCharacters` bounds each step's text
|
|
2420
|
+
and the final reply; reasoning is bounded by output tokens instead.
|
|
2421
|
+
|
|
2422
|
+
A long conversation is compacted rather than refused. `limits.contextTokens`
|
|
2423
|
+
(default 128,000) is the model's window, and the engine's sizes scale to it. Past
|
|
2424
|
+
the engine's compaction point, everything but the latest turns is folded into a
|
|
2425
|
+
summary written for the model, and storage keeps that summary with the last turn
|
|
2426
|
+
it covers (`writeSummary`). Later turns read only the turns after it
|
|
2427
|
+
(`readTurnsAfter`) and send the summary in the system prompt; messages are never
|
|
2428
|
+
deleted. Should compacting fail, the engine's last-resort cut drops the oldest
|
|
2429
|
+
messages and tells the model so. A bound conversation's host owns its transcript,
|
|
2430
|
+
so it is not compacted, and history an application supplies as `apiHistory` is
|
|
2431
|
+
used as given. History turns within the newest 20 messages send their files again;
|
|
2432
|
+
older turns name their files without their content.
|
|
2433
|
+
|
|
2434
|
+
Each reply streams one message per step: `reply-1`, `reply-2` and so on. A step
|
|
2435
|
+
that also calls actions ends as commentary, complete before the first of its actions
|
|
2436
|
+
runs, and the reply's last step becomes the answer. The answer leaves out words already shown as commentary, unless they are
|
|
2437
|
+
all the reply says. Reasoning a model writes inline in `<think>` tags is kept as
|
|
2438
|
+
reasoning, including tags split across chunks. Provider tool markup and DeepSeek's
|
|
2439
|
+
own tokens never reach visible text, and a call written out as text never runs: the
|
|
2440
|
+
markup check below tells the model so. Every structured action call runs through
|
|
2441
|
+
the same authorized execution and saved receipts; a call to an action the model was
|
|
2442
|
+
not given is answered as a tool error, and nothing runs or is saved for it. A
|
|
2443
|
+
failed action reaches the model as its error; an unknown outcome or a broken
|
|
2444
|
+
receipt ends the reply at once with its error. A completed step is required before
|
|
2445
|
+
any of its calls runs.
|
|
2446
|
+
Results of earlier turns past 6,000 characters are cut, and the third, fifth and
|
|
2447
|
+
eighth identical call in a row tells the model it is not making progress.
|
|
2448
|
+
|
|
2449
|
+
A finished reply gets the engine's checks. Each sends it back once to carry on from
|
|
2450
|
+
its own steps: raw markup (nothing in it ran), a reply that stops at announcing
|
|
2451
|
+
its next step, and, when neither ran, a claimed action that the reply's own
|
|
2452
|
+
actions do not support (one short model call compares them). The completion
|
|
2453
|
+
metadata names the check as `check`. A reply that ends with the engine's own
|
|
2454
|
+
account of where it got to is never sent back as stopping short.
|
|
2455
|
+
|
|
2456
|
+
A reply runs at most `limits.maxSteps` steps (default 40, the engine's limit for
|
|
2457
|
+
work with app tools). Out of steps, or past the engine's 15-minute reply deadline,
|
|
2458
|
+
it ends with the model's own short account of what it did and what is left, and
|
|
2459
|
+
the completion metadata says why as `unfinished`. Failed model calls are tried
|
|
2460
|
+
again six times with growing waits (or the provider's retry-after), about two
|
|
2461
|
+
minutes in all. When nothing has been done yet, the call's error fails the turn as
|
|
2462
|
+
status information; after some steps, the engine's account ends the reply instead.
|
|
2463
|
+
|
|
2464
|
+
Admission precedes every model call. The first resolves the authorized connection,
|
|
2465
|
+
checks access and admits the request; every later call (steps, checks, summaries,
|
|
2466
|
+
accounts) authorizes the same connection again and stops the reply when access is
|
|
2467
|
+
gone. A configured `effort` reaches every provider as the AI SDK's standard
|
|
2468
|
+
reasoning setting; without one, the engine's default applies (adaptive thinking at
|
|
2469
|
+
high effort for Anthropic-format models). The system prompt is the configured
|
|
2470
|
+
instructions, then the summary, then the engine's state note with the current UTC
|
|
2471
|
+
time.
|
|
2421
2472
|
|
|
2422
2473
|
An application can set server-owned `limits.maxApiToolProgressCharacters` to a
|
|
2423
2474
|
positive safe integer to bound the decoded text accompanying confirmed API tool
|
|
2424
2475
|
calls. The API driver rejects oversized progress before executing any call from
|
|
2425
2476
|
that response; it does not clip the text or ask the model to repeat the operation.
|
|
2426
2477
|
Omit the limit to retain the original API policy. It does not change final-answer
|
|
2427
|
-
limits or the
|
|
2478
|
+
limits or the step limit. This option
|
|
2428
2479
|
applies only to the direct API carrier; native tool progress needs association
|
|
2429
2480
|
with its exact admitted native use at that engine's execution boundary.
|
|
2430
2481
|
|
|
@@ -2440,14 +2491,9 @@ OpenCode delivery recovery applies the bound to the joined decoded native reply
|
|
|
2440
2491
|
while retaining the proven user admission and avoiding another inference. An advanced
|
|
2441
2492
|
host supplying its own native runtime retains that runtime's writer policy.
|
|
2442
2493
|
|
|
2443
|
-
The
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
clock action marked `current-time` runs before inference for time questions only
|
|
2447
|
-
when it requires no parameters, after connection authorization and turn admission.
|
|
2448
|
-
Uncertain application effects stop the turn; recovery never silently retries them.
|
|
2449
|
-
The legacy database service delegates to the same loop through its transactional
|
|
2450
|
-
adapter over the existing conversation, message and request-claim rows.
|
|
2494
|
+
The state note carries the current time; no action runs before inference. Uncertain application effects stop the turn; nothing
|
|
2495
|
+
silently retries them. The legacy database service delegates to the same driver through its
|
|
2496
|
+
transactional adapter over the existing conversation, message and request-claim rows.
|
|
2451
2497
|
|
|
2452
2498
|
### Authorized attachments
|
|
2453
2499
|
|
|
@@ -2545,7 +2591,8 @@ or application turn owns separate call identities, even if the model reuses an
|
|
|
2545
2591
|
ID. An interrupted reservation without a
|
|
2546
2592
|
result or a server failure after execution stops the turn with an unknown-outcome
|
|
2547
2593
|
error instead of executing again. Applications
|
|
2548
|
-
still
|
|
2594
|
+
still make each action tolerate a repeated request in its own domain, and
|
|
2595
|
+
inspect uncertain external effects.
|
|
2549
2596
|
The runtime cannot infer whether two different call IDs mean the same mutation.
|
|
2550
2597
|
|
|
2551
2598
|
Events with `type: "tool"` carry the call's `id`, `name`, `arguments`, `status` and,
|
|
@@ -2769,8 +2816,8 @@ execution identity remains the filesystem boundary for those tools.
|
|
|
2769
2816
|
|
|
2770
2817
|
Install Claude Code and log in with `claude auth login` under the application's
|
|
2771
2818
|
server identity. The ordinary single-user host uses that account and owned POSIX
|
|
2772
|
-
process groups. It requires no
|
|
2773
|
-
callbacks:
|
|
2819
|
+
process groups. It requires no hosted editor, project tooling or application-specific
|
|
2820
|
+
startup callbacks:
|
|
2774
2821
|
|
|
2775
2822
|
```js
|
|
2776
2823
|
const runtime = createConversationRuntime({
|
|
@@ -3535,6 +3582,12 @@ facilities before inspecting its own native state. Its history-idle query reads
|
|
|
3535
3582
|
that same state; the host separately checks durable process receipts and actual
|
|
3536
3583
|
terminal activity. No second activity cache or restoration loop is required.
|
|
3537
3584
|
|
|
3585
|
+
The application that creates the owner may pass its own error builder as
|
|
3586
|
+
`createError(message, { code })`. Every refusal the owner raises passes its own
|
|
3587
|
+
code, such as `conversation_claude_session_closing` or
|
|
3588
|
+
`conversation_claude_message_required`, so the builder forwards that code
|
|
3589
|
+
instead of giving every refusal the same one.
|
|
3590
|
+
|
|
3538
3591
|
The owner serializes preparation with native controls and preserves the original
|
|
3539
3592
|
control-interrupt followed by mandatory process drain. A failed drain stays an
|
|
3540
3593
|
error. The host retains execution policy, durable cleanup and publication at
|
|
@@ -3721,7 +3774,7 @@ acknowledgement, stream blocks, nested-event exclusion, background-task
|
|
|
3721
3774
|
completion and the interruption barrier for steering. Normalized owner events
|
|
3722
3775
|
let the host persist admissions and publish application state; receiver
|
|
3723
3776
|
completion alone does not prove process exit. `claudeNativeMessageId()`
|
|
3724
|
-
retains the same stable native message IDs
|
|
3777
|
+
retains the same stable native message IDs that a host's own adapter uses.
|
|
3725
3778
|
An exact native acknowledgement ends its ACK deadline before the admission
|
|
3726
3779
|
writer runs; a slow write remains awaited, and a rejected write rejects admission.
|
|
3727
3780
|
A missing acknowledgement remains uncertain. Native failure-result text stays
|
|
@@ -3933,8 +3986,8 @@ sandbox or resource limiter. It does not grant a permission bypass by default.
|
|
|
3933
3986
|
The native executable and its account login must already exist. Call `stop()`
|
|
3934
3987
|
and await its proof on shutdown; closing the protocol stream alone does not
|
|
3935
3988
|
prove that native work stopped. Failed cleanup remains an error or an unconfirmed
|
|
3936
|
-
proof, and the owning application must retain its stop handle. Managed
|
|
3937
|
-
|
|
3989
|
+
proof, and the owning application must retain its stop handle. Managed hosts
|
|
3990
|
+
replace execution to enforce identity, resources and scope cleanup.
|
|
3938
3991
|
|
|
3939
3992
|
For native history retirement, `nativeConversationStoragePolicy(engineId)` from
|
|
3940
3993
|
`/server/conversation` describes the engine's writer requirements. Codex's native
|
|
@@ -369,6 +369,12 @@ must have a documented exclusion or a description, output contract, result adapt
|
|
|
369
369
|
and execution fixture. Application-defined automation actions require the same
|
|
370
370
|
review; automation capability alone does not mean model exposure is safe.
|
|
371
371
|
|
|
372
|
+
An application test that checks which actions a surface's assistant offers, or
|
|
373
|
+
calls them as the assistant would, builds the catalogue the runtime builds:
|
|
374
|
+
`createSurfaceAwareToolCatalog(actions, { appConfig })` from
|
|
375
|
+
`@jskit-ai/assistant-runtime/server`, with the application's `runtime.actions`
|
|
376
|
+
and its server configuration. Each call names its surface in `context.surface`.
|
|
377
|
+
|
|
372
378
|
Generated list and view actions use JSON:API query shapes directly. `include`
|
|
373
379
|
is a comma-separated string, and `fields` is keyed by resource type:
|
|
374
380
|
|
|
@@ -432,8 +438,7 @@ catalog by opting it in explicitly:
|
|
|
432
438
|
```js
|
|
433
439
|
extensions: {
|
|
434
440
|
assistant: {
|
|
435
|
-
alwaysAvailable: true
|
|
436
|
-
preflight: ["current-time"]
|
|
441
|
+
alwaysAvailable: true
|
|
437
442
|
}
|
|
438
443
|
}
|
|
439
444
|
```
|
|
@@ -446,32 +451,27 @@ lookup before discovery-mode execution.
|
|
|
446
451
|
### Database surface conversation lifecycle
|
|
447
452
|
|
|
448
453
|
The client receives answer text incrementally and shows working status before
|
|
449
|
-
text arrives. Tool calls produce timeline events. Internal reasoning
|
|
450
|
-
tool arguments do not become visible answer text.
|
|
451
|
-
its provisional answer;
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
The clock action and its timezone policy remain application-owned; JSKIT does
|
|
472
|
-
not invent a clock action or infer the current date from model knowledge. Make
|
|
473
|
-
that action automation-capable and available on the assistant surface if the
|
|
474
|
-
product needs now, today, tomorrow, or other relative-date answers.
|
|
454
|
+
text arrives. Tool calls produce timeline events. Internal reasoning, provider tool
|
|
455
|
+
markup and raw tool arguments do not become visible answer text. Each model step
|
|
456
|
+
streams its own provisional answer; a step that also calls actions is kept as
|
|
457
|
+
commentary, separately from the chat rows, and the last step becomes the completed
|
|
458
|
+
answer in the existing chat rows.
|
|
459
|
+
|
|
460
|
+
Replies run on the agent engine (`@jskit-ai/agent`), up to 40 steps by default, so
|
|
461
|
+
catalog search, contract lookup and execution can complete in one turn. A failed
|
|
462
|
+
action reaches the model as its error. A reply that runs out of steps ends with
|
|
463
|
+
the model's own account of what it did and what is left. The engine's checks send
|
|
464
|
+
a reply back once when it leaks markup, stops at announcing its next step (“Let me
|
|
465
|
+
query…”), or claims an action no tool performed. Long conversations are summarised
|
|
466
|
+
rather than refused; see the conversation runtime guide.
|
|
467
|
+
|
|
468
|
+
Every request carries the current date and time in UTC in the engine's state
|
|
469
|
+
note, so no turn needs an extra action to learn it, and no action runs before
|
|
470
|
+
the model asks for one. The workspace's own time
|
|
471
|
+
zone and clock remain application-owned: when answers need local now, today or
|
|
472
|
+
tomorrow, make a clock action automation-capable, available on the assistant
|
|
473
|
+
surface and `alwaysAvailable` when the catalog can enter discovery mode, and the
|
|
474
|
+
model calls it like any other action.
|
|
475
475
|
|
|
476
476
|
Conversation restoration loads every transcript page needed to retain the
|
|
477
477
|
newest bounded transcript window, so a completed response on page two does not
|
|
@@ -44,12 +44,15 @@ An application with accounts always includes the managed-preview login, whether
|
|
|
44
44
|
or not anyone asked for it. Adding authentication adds both parts from the
|
|
45
45
|
`auth/auth-surface` pattern:
|
|
46
46
|
|
|
47
|
-
- the committed, executable `tools/preview-identity` from its example
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
47
|
+
- the committed, executable `tools/preview-identity` from its example, which
|
|
48
|
+
passes `runManagedPreviewIdentityCommand` the preview host's protocol id, the
|
|
49
|
+
hostnames, besides loopback, that the host serves the app on, and the process
|
|
50
|
+
environment;
|
|
51
|
+
- its declaration to the preview host in the form that host reads (for a host
|
|
52
|
+
that reads the web `Outputs` target, the pattern's `#### Preview identity`
|
|
53
|
+
block: Command `tools/preview-identity`, the same protocol id, Identity types
|
|
54
|
+
`email` `user-id`, Enabled environment `AUTH_DEV_BYPASS_ENABLED`, Secret
|
|
55
|
+
environment `AUTH_DEV_BYPASS_SECRET`, Runtimes `nodejs`).
|
|
53
56
|
|
|
54
57
|
The preview host supplies both environment values per run, so a managed
|
|
55
58
|
preview can sign its browser in as an existing account. Which accounts it may
|
|
@@ -76,32 +79,48 @@ capability using an ordinary application provider:
|
|
|
76
79
|
|
|
77
80
|
```js
|
|
78
81
|
import { defineProvider } from "@jskit-ai/kernel/shared/capabilities";
|
|
82
|
+
import { createRecoverySender } from "./recoverySender.js";
|
|
79
83
|
|
|
80
84
|
export const RecoveryEmailProvider = defineProvider({
|
|
81
85
|
id: "app.recovery-email",
|
|
82
86
|
requires: { mail: "app.mail" },
|
|
83
87
|
provides: { recoverySender: "auth.local.recovery-sender" },
|
|
88
|
+
/** @param {{ mail: import("@local/mail/server/types").AppMail }} capabilities */
|
|
84
89
|
setup({ mail }) {
|
|
85
|
-
return {
|
|
86
|
-
recoverySender: async ({ email, recoveryUrl }) => {
|
|
87
|
-
await mail.send({
|
|
88
|
-
to: email,
|
|
89
|
-
subject: "Reset your password",
|
|
90
|
-
text: `Open this link to reset your password:\n\n${recoveryUrl}\n`
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
};
|
|
90
|
+
return { recoverySender: createRecoverySender({ mail }) };
|
|
94
91
|
}
|
|
95
92
|
});
|
|
96
93
|
```
|
|
97
94
|
|
|
95
|
+
```js
|
|
96
|
+
// recoverySender.js
|
|
97
|
+
/** @param {{ mail: import("@local/mail/server/types").AppMail }} dependencies */
|
|
98
|
+
function createRecoverySender({ mail }) {
|
|
99
|
+
/** @type {import("@jskit-ai/auth-provider-local-core/server/types").AuthLocalRecoverySender} */
|
|
100
|
+
async function sendRecoveryEmail({ email, recoveryUrl }) {
|
|
101
|
+
await mail.send({
|
|
102
|
+
to: email,
|
|
103
|
+
subject: "Reset your password",
|
|
104
|
+
text: `Open this link to reset your password:\n\n${recoveryUrl}\n`
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return sendRecoveryEmail;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export { createRecoverySender };
|
|
112
|
+
```
|
|
113
|
+
|
|
98
114
|
`app.mail` is an application-owned capability in this example, not a built-in
|
|
99
115
|
JSKIT email API. Its `send()` implementation owns the selected integration,
|
|
100
116
|
credential resolution and safe error mapping. A connected account or a domain
|
|
101
117
|
listing adapter alone does not implement email sending. Install this provider
|
|
102
118
|
alongside the application's mail provider and `AuthLocalProvider`.
|
|
119
|
+
[Typed features](/guide/framework/typed-features) describes how application
|
|
120
|
+
providers name and type the capabilities they receive.
|
|
103
121
|
For direct library composition, pass the same function as `recoverySender` to
|
|
104
|
-
`createLocalAuthService()
|
|
122
|
+
`createLocalAuthService()`, with a configuration from
|
|
123
|
+
`resolveLocalAuthConfig({ appRoot, env, fileBackend, emailRecovery: true })`.
|
|
105
124
|
|
|
106
125
|
Set `APP_PUBLIC_URL` to the application's actual public URL. When a sender is
|
|
107
126
|
configured, auth requires this value and does not return or log the recovery
|
|
@@ -213,7 +232,7 @@ in the server process and use `loginAsExistingUser()` from
|
|
|
213
232
|
client environment.
|
|
214
233
|
|
|
215
234
|
A managed host instead supplies authenticated state through
|
|
216
|
-
`
|
|
235
|
+
`PLAYWRIGHT_STORAGE_STATE` and the app-owned Playwright config. Treat the
|
|
217
236
|
file as a temporary secret, use relative URLs, and do not call the localhost
|
|
218
237
|
login helper or start a duplicate server.
|
|
219
238
|
|
|
@@ -54,14 +54,20 @@ application file is small:
|
|
|
54
54
|
import { createKnexMigrationConfigFromApp } from
|
|
55
55
|
"@jskit-ai/database-runtime/server/knexMigrationConfig";
|
|
56
56
|
|
|
57
|
-
export default await createKnexMigrationConfigFromApp({ client: "mysql2" });
|
|
57
|
+
export default await createKnexMigrationConfigFromApp({ client: "mysql2", environment: process.env });
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
-
Use `client: "pg"` for PostgreSQL. The
|
|
60
|
+
Use `client: "pg"` for PostgreSQL. The environment is always passed: JSKIT reads
|
|
61
|
+
the connection values from what the application gives it, never from
|
|
62
|
+
`process.env` on its own. The complete examples are in:
|
|
61
63
|
|
|
62
64
|
- `database/mysql-application`
|
|
63
65
|
- `database/postgres-application`
|
|
64
66
|
|
|
67
|
+
Each example is complete for its own engine. Copy files only from the selected
|
|
68
|
+
driver's pattern and never merge the two; for example, the CI workflow must
|
|
69
|
+
contain only that engine's database service.
|
|
70
|
+
|
|
65
71
|
The config discovers migrations directly from the current installed package
|
|
66
72
|
graph. Application migrations live in the app's `migrations/` directory;
|
|
67
73
|
package-owned migrations live in directories declared by the installed
|
|
@@ -111,6 +117,30 @@ package's metadata:
|
|
|
111
117
|
}
|
|
112
118
|
```
|
|
113
119
|
|
|
120
|
+
A `constraints/` subdirectory of a declared directory, such as
|
|
121
|
+
`migrations/constraints/`, holds the package's constraints migrations; it runs
|
|
122
|
+
later, as described below.
|
|
123
|
+
|
|
124
|
+
A package whose table migrations use another package's tables names that
|
|
125
|
+
package in `after`, and its migrations, and its constraints, then run after
|
|
126
|
+
that package's:
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"jskit": {
|
|
131
|
+
"migrations": {
|
|
132
|
+
"directories": ["migrations"],
|
|
133
|
+
"after": ["@jskit-ai/users-core"]
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Each name in `after` must be another installed JSKIT package; a name that is
|
|
140
|
+
not installed, the package's own name, or packages that each name the other
|
|
141
|
+
stop discovery with an error. A named package without migrations orders
|
|
142
|
+
nothing.
|
|
143
|
+
|
|
114
144
|
Names must remain unique across the effective migration directories. Preserve
|
|
115
145
|
the basename when relocating a migration: Knex records that name in its ledger.
|
|
116
146
|
Do not rename it to force execution or edit an already-applied migration's body;
|
|
@@ -121,24 +151,60 @@ changed schema behavior requires a new migration.
|
|
|
121
151
|
`createKnexMigrationConfigFromApp()` sets `sortDirsSeparately: true` and runs
|
|
122
152
|
pending migrations in this order, using the default `migrationsDirectory`:
|
|
123
153
|
|
|
124
|
-
1.
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
154
|
+
1. Discovered package migration directories, sorted by their absolute paths
|
|
155
|
+
using `localeCompare`, except that a package's directories follow those of
|
|
156
|
+
every package its `after` names, which follow theirs in turn, each in the
|
|
157
|
+
order listed. Without `after` the path order is unchanged.
|
|
158
|
+
2. Application `migrations/`.
|
|
159
|
+
3. The `constraints/` subdirectory of each discovered package migration
|
|
160
|
+
directory that has one, in the same order.
|
|
161
|
+
4. Application `migrations/constraints/`.
|
|
128
162
|
|
|
129
163
|
Knex sorts filenames within each directory, not across the whole graph; see
|
|
130
164
|
its [`sortDirsSeparately` option](https://knexjs.org/guide/migrations.html#migration-api).
|
|
131
|
-
Package discovery does not
|
|
132
|
-
timestamp in an earlier package still runs before
|
|
165
|
+
Package discovery does not read tables or foreign keys; only `after` changes
|
|
166
|
+
the package order. A newer timestamp in an earlier package still runs before
|
|
167
|
+
every file in a later package.
|
|
133
168
|
Inspect the effective `knexfile.js` configuration if the app customizes it.
|
|
134
169
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
170
|
+
Every package table exists before the application's own migrations run, so a
|
|
171
|
+
root `migrations/` file can reference a package table directly, for example a
|
|
172
|
+
`books.user_id` foreign key to `users.id`. A package's table migrations must
|
|
173
|
+
never depend on an application table.
|
|
174
|
+
|
|
175
|
+
Keep table and column creation with the owning package. Put foreign keys
|
|
176
|
+
between two packages, and other constraints that need the complete schema, in a
|
|
177
|
+
constraints phase: the referencing package's own `constraints/` subdirectory
|
|
178
|
+
when it ships the key, or application `migrations/constraints/`. A package
|
|
179
|
+
constraints migration runs after the application's `migrations/`, so it can also
|
|
180
|
+
reference a table that may belong to the application, such as `users`; for
|
|
181
|
+
example, `@jskit-ai/assistant-runtime` adds its `users` and `workspaces` keys
|
|
182
|
+
from `migrations/constraints/`. Similarly, a `pet_notes.product_id` column can be
|
|
139
183
|
added by the pet-notes package, but its foreign key to the products package's
|
|
140
|
-
`products.id` belongs in
|
|
141
|
-
package-directory order to make a cross-package reference work
|
|
184
|
+
`products.id` belongs in a constraints phase. Do not rely on the
|
|
185
|
+
package-directory path order to make a cross-package reference work; when a
|
|
186
|
+
package's table migrations need another package's table, declare `after`.
|
|
187
|
+
|
|
188
|
+
Until `@jskit-ai/database-runtime` 0.1.252, root `migrations/` ran before the
|
|
189
|
+
package directories, so a fresh database failed on any application migration
|
|
190
|
+
that referenced a package table. Applied migrations stay in the Knex ledger;
|
|
191
|
+
only pending ones follow the new order. An application migration that still
|
|
192
|
+
creates a package-owned table belongs in that package.
|
|
193
|
+
|
|
194
|
+
The assistant-runtime, console-core and rewarded-core table migrations used to
|
|
195
|
+
add their keys to `users`, `workspaces` and later tables inline. A fresh MySQL
|
|
196
|
+
or MariaDB database failed when the parent table did not exist yet (errno 150),
|
|
197
|
+
and the assistant tables silently skipped their `workspaces` keys. They now add
|
|
198
|
+
them from `migrations/constraints/`. A database migrated earlier keeps the keys
|
|
199
|
+
it already has, and gains any that are missing.
|
|
200
|
+
|
|
201
|
+
`@jskit-ai/database-runtime/server/foreignKeyMigrations` serves constraints
|
|
202
|
+
migrations that must run on fresh and already-migrated databases alike.
|
|
203
|
+
`addMissingForeignKey(knex, key)` adds a single-column key only when no key
|
|
204
|
+
already links that column to the parent column. It fails, naming the table,
|
|
205
|
+
column and count, when rows have no parent, and it deletes nothing; repair
|
|
206
|
+
those rows and migrate again. `dropForeignKeyIfPresent(knex, key)` serves
|
|
207
|
+
`down()`.
|
|
142
208
|
|
|
143
209
|
Before adding the key, check that both tables and columns exist, the referenced
|
|
144
210
|
key is indexed appropriately, column types match (including integer signedness),
|
|
@@ -206,7 +272,40 @@ Repositories own database access. Services and lifecycle hooks orchestrate
|
|
|
206
272
|
repositories. External delivery belongs after commit; when it must be durable,
|
|
207
273
|
write an outbox record inside the transaction and deliver it separately.
|
|
208
274
|
A separate Feature is warranted when an operation belongs to another domain,
|
|
209
|
-
not merely because a useful resource has behavior beyond list and save.
|
|
275
|
+
not merely because a useful resource has behavior beyond list and save. Write
|
|
276
|
+
it as a [typed feature](/guide/framework/typed-features).
|
|
277
|
+
|
|
278
|
+
## Optimistic locking
|
|
279
|
+
|
|
280
|
+
A CRUD resource whose records carry a version number names it with
|
|
281
|
+
`lockVersionField`, an integer schema field over a non-null integer column
|
|
282
|
+
with a starting value, such as `0`:
|
|
283
|
+
|
|
284
|
+
```js
|
|
285
|
+
defineCrudResource({
|
|
286
|
+
namespace: "contracts",
|
|
287
|
+
tableName: "contracts",
|
|
288
|
+
autofilter: "workspace",
|
|
289
|
+
lockVersionField: "lockVersion",
|
|
290
|
+
schema: {
|
|
291
|
+
// ...
|
|
292
|
+
lockVersion: { type: "integer", min: 0, readOnly: true, column: "lock_version" }
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
The CRUD repository's
|
|
298
|
+
`patchDocumentIfLockVersion(recordId, expectedLockVersion, patch, { trx, context })`
|
|
299
|
+
then applies `patch` only while the record still holds `expectedLockVersion`, a
|
|
300
|
+
non-negative integer, and adds one to the lock version in the same
|
|
301
|
+
transaction: the caller's `trx`, or one it owns. It returns the patched document, which carries the new lock
|
|
302
|
+
version, or `null` when the record does not exist or is outside the caller's
|
|
303
|
+
scope. A record whose lock version has moved on rejects with a 409 coded
|
|
304
|
+
`crud.document.lockVersionConflict` ("This record changed. Reload and try
|
|
305
|
+
again."), and nothing is written. The patch leaves the lock field out; an app
|
|
306
|
+
that wants its own wording for the conflict catches that code. A resource
|
|
307
|
+
without `lockVersionField` cannot call it, and `defineCrudResource()` rejects
|
|
308
|
+
a `lockVersionField` that names no integer schema field.
|
|
210
309
|
|
|
211
310
|
## Deadlock retries
|
|
212
311
|
|
|
@@ -218,8 +317,8 @@ request instead of a 500. This applies to `runInTransaction()` and
|
|
|
218
317
|
`createWithTransaction()` from `@jskit-ai/database-runtime/shared`, to
|
|
219
318
|
`transactionManager.inTransaction()`, to the seed transaction, to every JSON
|
|
220
319
|
REST repository's `withTransaction()` (CRUD, users and workspaces), and to a
|
|
221
|
-
CRUD `createDocument`, `patchDocumentById
|
|
222
|
-
`trx`, which owns its own transaction. A lock wait timeout (errno 1205) is not
|
|
320
|
+
CRUD `createDocument`, `patchDocumentById`, `patchDocumentIfLockVersion` or
|
|
321
|
+
`deleteDocumentById` given no `trx`, which owns its own transaction. A lock wait timeout (errno 1205) is not
|
|
223
322
|
retried.
|
|
224
323
|
|
|
225
324
|
Only the outermost transaction retries. A call given an existing `trx`, or a
|