akanjs 3.1.0-rc.2 → 3.1.0-rc.21
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/base/baseEnv.ts +5 -2
- package/client/device.ts +1 -1
- package/client/frameConfig.ts +2 -2
- package/client/href.ts +35 -0
- package/client/index.ts +1 -0
- package/client/makePageProto.tsx +3 -2
- package/client/router.ts +6 -4
- package/client/rscNavigation.ts +1 -1
- package/client/transitionTypes.ts +0 -4
- package/client/translator.ts +16 -0
- package/client/types.ts +3 -2
- package/client/viewportMeta.ts +23 -8
- package/client/webManifest.ts +5 -3
- package/common/TrustedProxy.ts +14 -0
- package/common/codeAgentWire.ts +8 -1
- package/common/index.ts +1 -0
- package/common/interpolateTranslation.ts +17 -3
- package/common/isEmail.ts +1 -1
- package/common/localeConfig.ts +10 -4
- package/common/markdownSpans.ts +1 -1
- package/common/restClient.ts +3 -1
- package/common/routeConvention.ts +4 -4
- package/common/trimSlashes.ts +11 -0
- package/common/types.ts +1 -1
- package/constant/fieldInfo.ts +2 -2
- package/constant/fieldPlan.ts +80 -0
- package/constant/index.ts +3 -0
- package/constant/inputParser.ts +148 -0
- package/constant/invalidInputError.ts +13 -0
- package/constant/serialize.ts +36 -20
- package/constant/types.ts +1 -1
- package/constant/via.ts +2 -0
- package/dictionary/base.dictionary.ts +4 -0
- package/dictionary/trans.ts +8 -0
- package/document/database.ts +3 -6
- package/document/documentSchema.ts +1 -1
- package/document/noDocumentError.ts +6 -1
- package/fetch/client/fetchClient.ts +2 -1
- package/fetch/client/sliceInitHandle.ts +2 -3
- package/fetch/fetchType/appliedReturn.type.ts +3 -1
- package/fetch/types.ts +4 -2
- package/index.ts +2 -0
- package/package.json +31 -21
- package/server/akanApp.ts +15 -3
- package/server/akanServer.ts +34 -14
- package/server/artifact/routeClientCache.ts +4 -5
- package/server/artifact/routeSeedIndexStore.ts +3 -20
- package/server/artifact/routeSeedMatcher.ts +70 -0
- package/server/console.ts +1 -1
- package/server/di/diLifecycle.ts +16 -7
- package/server/imageOptimizer.ts +1 -1
- package/server/index.ts +1 -0
- package/server/machine/machineAccount.ts +28 -3
- package/server/machine/machineToken.ts +27 -3
- package/server/mcp/McpDispatcher.ts +2 -3
- package/server/mcp/McpExecutionContext.ts +9 -3
- package/server/migration/docPath.ts +121 -0
- package/server/migration/index.ts +15 -0
- package/server/migration/migrationChangeLog.ts +86 -0
- package/server/migration/migrationChanges.ts +70 -0
- package/server/migration/migrationCommand.ts +179 -0
- package/server/migration/migrationContext.ts +53 -0
- package/server/migration/migrationDefinition.ts +87 -0
- package/server/migration/migrationError.ts +45 -0
- package/server/migration/migrationLedger.ts +172 -0
- package/server/migration/migrationLock.ts +103 -0
- package/server/migration/migrationParams.ts +122 -0
- package/server/migration/migrationPulse.ts +39 -0
- package/server/migration/migrationRunner.ts +525 -0
- package/server/migration/migrationScope.ts +93 -0
- package/server/migration/migrationTable.ts +258 -0
- package/server/migration/migrations.ts +57 -0
- package/server/ops/opsCommand.ts +30 -1
- package/server/resolver/CascadeRunner.ts +15 -2
- package/server/resolver/signal.resolver.ts +35 -55
- package/server/routeState.ts +0 -6
- package/server/rscClient.tsx +22 -37
- package/server/rscNavigationState.ts +3 -5
- package/server/rscScrollRestoration.ts +116 -0
- package/server/rscWorker.tsx +12 -19
- package/server/sitemap.ts +4 -4
- package/server/tunnel/TunnelAgent.ts +9 -1
- package/server/webRouter.ts +17 -2
- package/service/agent.service.ts +21 -1
- package/service/endpointCacheKeys.ts +35 -0
- package/service/index.ts +1 -0
- package/service/injectInfo.ts +2 -2
- package/service/predefinedAdaptor/anthropicLlm.ts +37 -17
- package/service/predefinedAdaptor/database.adaptor.ts +15 -0
- package/service/predefinedAdaptor/documentTransfer.ts +50 -0
- package/service/predefinedAdaptor/endpointCacheControl.adaptor.ts +19 -0
- package/service/predefinedAdaptor/index.ts +1 -0
- package/service/predefinedAdaptor/llm.adaptor.ts +7 -0
- package/service/predefinedAdaptor/openaiDialect.ts +53 -17
- package/service/predefinedAdaptor/openaiLlm.ts +1 -1
- package/service/predefinedAdaptor/sql/MigrationTables.ts +90 -0
- package/service/predefinedAdaptor/sql/RawDocumentTable.ts +200 -0
- package/service/predefinedAdaptor/sql/SqlDocumentStore.ts +6 -2
- package/service/predefinedAdaptor/sql/SqliteInsightSession.ts +4 -1
- package/service/predefinedAdaptor/sql/dialect/postgres.ts +0 -1
- package/service/predefinedAdaptor/sql/dialect/sqlite.ts +0 -1
- package/service/predefinedAdaptor/sql/types.ts +3 -1
- package/service/predefinedAdaptor/storage.adaptor.ts +19 -0
- package/signal/endpointCache.ts +23 -7
- package/signal/endpointErrorContract.ts +37 -0
- package/signal/endpointIdempotency.ts +5 -3
- package/signal/endpointInfo.ts +4 -1
- package/signal/endpointRateLimit.ts +6 -2
- package/signal/exception.ts +4 -1
- package/signal/index.ts +1 -0
- package/signal/mcp/McpDocument.ts +16 -1
- package/signal/mcp/McpUriTemplate.ts +1 -1
- package/signal/middlewareChain.ts +105 -0
- package/signal/openapi/openapi.ts +46 -2
- package/signal/serializer/fetch.serializer.ts +1 -0
- package/signal/signalContext.ts +110 -82
- package/signal/slice.ts +2 -2
- package/signal/trace.ts +8 -2
- package/signal/types.ts +13 -0
- package/store/action.ts +102 -42
- package/store/agent/ScreenImage.ts +166 -0
- package/store/agent/ScreenReader.ts +2 -1
- package/store/agent/StoreSurfaceSource.ts +41 -2
- package/store/agent/index.ts +2 -1
- package/store/databaseStateNames.ts +1 -0
- package/store/formUploadOf.ts +41 -0
- package/store/index.ts +1 -0
- package/store/liveInsert.ts +2 -2
- package/store/state.ts +9 -1
- package/store/stateBuilder.ts +8 -2
- package/store/storeInstance.ts +12 -3
- package/store/withSelector.ts +2 -2
- package/types/client/href.d.ts +11 -0
- package/types/client/index.d.ts +1 -0
- package/types/client/rscNavigation.d.ts +1 -1
- package/types/client/transitionTypes.d.ts +0 -2
- package/types/client/translator.d.ts +2 -0
- package/types/common/codeAgentWire.d.ts +7 -0
- package/types/common/index.d.ts +1 -0
- package/types/common/trimSlashes.d.ts +2 -0
- package/types/common/types.d.ts +1 -1
- package/types/constant/fieldInfo.d.ts +2 -2
- package/types/constant/fieldPlan.d.ts +33 -0
- package/types/constant/index.d.ts +3 -0
- package/types/constant/inputParser.d.ts +11 -0
- package/types/constant/invalidInputError.d.ts +8 -0
- package/types/constant/types.d.ts +1 -1
- package/types/dictionary/base.dictionary.d.ts +1 -1
- package/types/dictionary/dictionary.d.ts +3 -3
- package/types/dictionary/trans.d.ts +3 -0
- package/types/document/database.d.ts +2 -3
- package/types/document/documentSchema.d.ts +1 -1
- package/types/document/noDocumentError.d.ts +6 -1
- package/types/fetch/fetchType/appliedReturn.type.d.ts +3 -1
- package/types/fetch/types.d.ts +2 -2
- package/types/index.d.ts +5 -0
- package/types/server/akanServer.d.ts +1 -1
- package/types/server/artifact/routeSeedMatcher.d.ts +8 -0
- package/types/server/di/diLifecycle.d.ts +1 -0
- package/types/server/index.d.ts +1 -0
- package/types/server/machine/machineAccount.d.ts +1 -0
- package/types/server/machine/machineToken.d.ts +9 -0
- package/types/server/migration/docPath.d.ts +20 -0
- package/types/server/migration/index.d.ts +15 -0
- package/types/server/migration/migrationChangeLog.d.ts +27 -0
- package/types/server/migration/migrationChanges.d.ts +27 -0
- package/types/server/migration/migrationCommand.d.ts +33 -0
- package/types/server/migration/migrationContext.d.ts +28 -0
- package/types/server/migration/migrationDefinition.d.ts +42 -0
- package/types/server/migration/migrationError.d.ts +15 -0
- package/types/server/migration/migrationLedger.d.ts +51 -0
- package/types/server/migration/migrationLock.d.ts +34 -0
- package/types/server/migration/migrationParams.d.ts +41 -0
- package/types/server/migration/migrationPulse.d.ts +15 -0
- package/types/server/migration/migrationRunner.d.ts +93 -0
- package/types/server/migration/migrationScope.d.ts +42 -0
- package/types/server/migration/migrationTable.d.ts +52 -0
- package/types/server/migration/migrations.d.ts +12 -0
- package/types/server/migration.d.ts +1 -0
- package/types/server/ops/opsCommand.d.ts +10 -1
- package/types/server/routeState.d.ts +1 -4
- package/types/server/rscNavigationState.d.ts +2 -3
- package/types/server/rscScrollRestoration.d.ts +14 -0
- package/types/server/sitemap.d.ts +1 -1
- package/types/service/agent.service.d.ts +2 -0
- package/types/service/endpointCacheKeys.d.ts +8 -0
- package/types/service/index.d.ts +1 -0
- package/types/service/injectInfo.d.ts +2 -2
- package/types/service/predefinedAdaptor/anthropicLlm.d.ts +9 -4
- package/types/service/predefinedAdaptor/database.adaptor.d.ts +8 -1
- package/types/service/predefinedAdaptor/documentTransfer.d.ts +1 -0
- package/types/service/predefinedAdaptor/endpointCacheControl.adaptor.d.ts +9 -0
- package/types/service/predefinedAdaptor/index.d.ts +1 -0
- package/types/service/predefinedAdaptor/llm.adaptor.d.ts +7 -0
- package/types/service/predefinedAdaptor/openaiDialect.d.ts +20 -5
- package/types/service/predefinedAdaptor/sql/MigrationTables.d.ts +17 -0
- package/types/service/predefinedAdaptor/sql/RawDocumentTable.d.ts +38 -0
- package/types/service/predefinedAdaptor/sql/types.d.ts +1 -0
- package/types/service/predefinedAdaptor/storage.adaptor.d.ts +8 -0
- package/types/signal/endpointCache.d.ts +2 -0
- package/types/signal/endpointErrorContract.d.ts +10 -0
- package/types/signal/endpointIdempotency.d.ts +1 -0
- package/types/signal/endpointRateLimit.d.ts +1 -1
- package/types/signal/exception.d.ts +4 -1
- package/types/signal/index.d.ts +1 -0
- package/types/signal/middlewareChain.d.ts +11 -0
- package/types/signal/signalContext.d.ts +2 -6
- package/types/signal/slice.d.ts +1 -1
- package/types/signal/trace.d.ts +1 -1
- package/types/signal/types.d.ts +12 -0
- package/types/store/action.d.ts +2 -0
- package/types/store/agent/ScreenImage.d.ts +27 -0
- package/types/store/agent/StoreSurfaceSource.d.ts +1 -1
- package/types/store/agent/index.d.ts +2 -1
- package/types/store/databaseStateNames.d.ts +1 -0
- package/types/store/formUploadOf.d.ts +9 -0
- package/types/store/index.d.ts +1 -0
- package/types/store/state.d.ts +7 -1
- package/types/store/stateBuilder.d.ts +2 -1
- package/types/store/storeInstance.d.ts +2 -2
- package/types/store/withSelector.d.ts +1 -1
- package/types/ui/Agent/Composer.d.ts +2 -0
- package/types/ui/Agent/Menu.d.ts +2 -0
- package/types/ui/CsrImage.d.ts +2 -0
- package/types/ui/Data/CardList.d.ts +1 -1
- package/types/ui/Data/Dashboard.d.ts +1 -1
- package/types/ui/Data/Insight.d.ts +1 -1
- package/types/ui/Data/Item.d.ts +2 -2
- package/types/ui/Data/ListContainer.d.ts +1 -1
- package/types/ui/Data/Pagination.d.ts +1 -1
- package/types/ui/Data/TableList.d.ts +1 -1
- package/types/ui/Field/Relation.d.ts +13 -10
- package/types/ui/Field/index.d.ts +4 -4
- package/types/ui/Field/useRelationOptions.d.ts +3 -1
- package/types/ui/Field/useRelationWindow.d.ts +14 -0
- package/types/ui/Image.d.ts +3 -1
- package/types/ui/Load/View.d.ts +1 -1
- package/types/ui/Pagination.d.ts +1 -1
- package/types/ui/Signal/Arg.d.ts +1 -1
- package/types/ui/System/CSR.d.ts +1 -1
- package/types/ui/System/Client.d.ts +1 -1
- package/types/ui/System/SSR.d.ts +1 -1
- package/types/vendor/@akanjs/native/packages/core/src/plugin.d.ts +3 -3
- package/types/vendor/@akanjs/native/packages/desktop/src/page-veto.d.ts +1 -1
- package/types/vendor/@akanjs/native/packages/desktop/src/plugin.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/auth-session/src/desktop.d.ts +2 -2
- package/types/vendor/@akanjs/native/plugins/auth-session/src/index.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/autostart/src/desktop.d.ts +2 -2
- package/types/vendor/@akanjs/native/plugins/autostart/src/index.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/badge/src/desktop.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/badge/src/index.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/badge/src/web.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/biometric/src/index.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/camera/src/desktop.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/camera/src/index.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/camera/src/web.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/clipboard/src/desktop.d.ts +2 -2
- package/types/vendor/@akanjs/native/plugins/clipboard/src/index.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/clipboard/src/web.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/contacts/src/index.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/device/src/desktop.d.ts +2 -2
- package/types/vendor/@akanjs/native/plugins/device/src/index.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/device/src/web.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/dialog/src/desktop.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/dialog/src/index.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/dialog/src/web.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/dock/src/desktop.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/dock/src/index.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/file-picker/src/desktop.d.ts +2 -2
- package/types/vendor/@akanjs/native/plugins/file-picker/src/web.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/filesystem/src/desktop.d.ts +2 -2
- package/types/vendor/@akanjs/native/plugins/filesystem/src/web.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/haptics/src/index.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/haptics/src/web.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/http/src/desktop.d.ts +2 -2
- package/types/vendor/@akanjs/native/plugins/http/src/web.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/keep-awake/src/desktop.d.ts +2 -2
- package/types/vendor/@akanjs/native/plugins/keep-awake/src/index.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/keep-awake/src/web.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/opener/src/desktop.d.ts +2 -2
- package/types/vendor/@akanjs/native/plugins/opener/src/index.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/opener/src/web.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/preferences/src/desktop.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/preferences/src/index.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/preferences/src/web.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/secure-storage/src/desktop.d.ts +2 -2
- package/types/vendor/@akanjs/native/plugins/secure-storage/src/index.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/share/src/index.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/share/src/web.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/single-instance/src/desktop.d.ts +2 -2
- package/types/vendor/@akanjs/native/plugins/splash-screen/src/index.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/splash-screen/src/web.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/sqlite/src/desktop.d.ts +2 -2
- package/types/vendor/@akanjs/native/plugins/toast/src/index.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/toast/src/web.d.ts +1 -1
- package/types/vendor/@akanjs/native/plugins/window/src/index.d.ts +2 -2
- package/types/vendor/@akanjs/native/plugins/window-state/src/desktop.d.ts +2 -2
- package/types/vendor/@akanjs/native/plugins/window-state/src/index.d.ts +1 -1
- package/types/vendor/use-agentic/Compaction.d.ts +3 -1
- package/types/vendor/use-agentic/Reference.d.ts +9 -1
- package/types/vendor/use-agentic/ToolOutput.d.ts +6 -1
- package/types/vendor/use-agentic/ToolReturn.d.ts +18 -0
- package/types/vendor/use-agentic/Transcript.d.ts +7 -0
- package/types/vendor/use-agentic/index.d.ts +1 -0
- package/types/vendor/use-agentic/types.d.ts +6 -0
- package/types/webkit/useDebounce.d.ts +1 -1
- package/ui/Agent/Chat.tsx +1 -0
- package/ui/Agent/Composer.tsx +2 -0
- package/ui/Agent/Menu.tsx +5 -1
- package/ui/Agent/agentSessionOf.ts +15 -8
- package/ui/Agent/mentionDraft.ts +2 -3
- package/ui/Agent/useReferenceMenu.ts +1 -0
- package/ui/Agent/useSlashMenu.ts +1 -0
- package/ui/Clipboard.tsx +1 -0
- package/ui/CsrImage.tsx +3 -1
- package/ui/Data/CardList.tsx +1 -1
- package/ui/Data/Dashboard.tsx +1 -1
- package/ui/Data/Insight.tsx +1 -1
- package/ui/Data/Item.tsx +5 -2
- package/ui/Data/ListContainer.tsx +2 -2
- package/ui/Data/Pagination.tsx +1 -1
- package/ui/Data/TableList.tsx +1 -1
- package/ui/DraggableList.tsx +1 -0
- package/ui/Field/Collection.tsx +4 -0
- package/ui/Field/Relation.tsx +33 -14
- package/ui/Field/useRelationOptions.ts +33 -5
- package/ui/Field/useRelationWindow.ts +50 -0
- package/ui/Image.tsx +4 -4
- package/ui/Input.tsx +1 -0
- package/ui/Layout/Sider.tsx +1 -1
- package/ui/Link/Anchor.tsx +7 -5
- package/ui/Load/Units.tsx +17 -7
- package/ui/Load/View.tsx +2 -2
- package/ui/Model/Edit.tsx +1 -1
- package/ui/Model/EditModal.tsx +11 -5
- package/ui/Model/New.tsx +1 -1
- package/ui/Model/SureToRemove.tsx +1 -0
- package/ui/Model/ViewEditModal.tsx +17 -5
- package/ui/Model/ViewModal.tsx +2 -2
- package/ui/ObjectId.tsx +5 -1
- package/ui/Pagination.tsx +1 -1
- package/ui/Signal/Arg.tsx +1 -3
- package/ui/Signal/Doc.tsx +5 -1
- package/ui/System/CSR.tsx +1 -1
- package/ui/System/Client.tsx +1 -1
- package/ui/System/Reconnect.tsx +1 -1
- package/ui/System/SSR.tsx +3 -36
- package/ui/ToggleSelect.tsx +2 -0
- package/ui/styles.css +10 -103
- package/vendor/@akanjs/native/native/ios/Sources/AkanNativeBridge.swift +3 -2
- package/vendor/@akanjs/native/packages/cli/src/lib/addons.ts +4 -1
- package/vendor/@akanjs/native/packages/cli/src/lib/apk.ts +2 -2
- package/vendor/@akanjs/native/packages/cli/src/lib/codegen.ts +1 -1
- package/vendor/@akanjs/native/packages/cli/src/lib/csp.ts +4 -3
- package/vendor/@akanjs/native/packages/cli/src/lib/googleservices.ts +7 -1
- package/vendor/@akanjs/native/packages/cli/src/lib/hmr.ts +8 -5
- package/vendor/@akanjs/native/packages/cli/src/lib/html.ts +18 -3
- package/vendor/@akanjs/native/packages/cli/src/lib/manifestmerge.ts +1 -1
- package/vendor/@akanjs/native/packages/cli/src/lib/plist.ts +2 -4
- package/vendor/@akanjs/native/packages/cli/src/lib/toolchains.ts +1 -1
- package/vendor/@akanjs/native/packages/cli/src/lib/updates.ts +10 -4
- package/vendor/@akanjs/native/packages/cli/src/lib/xml.ts +4 -3
- package/vendor/@akanjs/native/packages/cli/src/platforms/android.ts +3 -3
- package/vendor/@akanjs/native/packages/core/src/kernel.ts +3 -3
- package/vendor/@akanjs/native/packages/core/src/live.ts +1 -0
- package/vendor/@akanjs/native/packages/core/src/plugin.ts +5 -3
- package/vendor/@akanjs/native/packages/desktop/src/host.ts +13 -5
- package/vendor/@akanjs/native/packages/desktop/src/lifecycle.ts +1 -0
- package/vendor/@akanjs/native/packages/desktop/src/page-veto.ts +1 -1
- package/vendor/@akanjs/native/packages/desktop/src/plugin.ts +4 -1
- package/vendor/@akanjs/native/plugins/camera/src/web.ts +3 -3
- package/vendor/@akanjs/native/plugins/file-picker/src/index.ts +4 -1
- package/vendor/@akanjs/native/plugins/local-notifications/src/web.ts +1 -1
- package/vendor/@akanjs/native/plugins/secure-storage/src/desktop.ts +1 -1
- package/vendor/@akanjs/native/plugins/share/src/options.ts +1 -1
- package/vendor/@akanjs/native/plugins/single-instance/src/desktop.ts +3 -2
- package/vendor/@akanjs/native/plugins/updates/src/desktop.ts +4 -1
- package/vendor/@akanjs/native/plugins/window/src/index.ts +2 -2
- package/vendor/use-agentic/Compaction.ts +38 -7
- package/vendor/use-agentic/Reference.ts +16 -9
- package/vendor/use-agentic/ToolOutput.ts +25 -3
- package/vendor/use-agentic/ToolReturn.ts +32 -0
- package/vendor/use-agentic/ToolRunner.ts +15 -13
- package/vendor/use-agentic/Transcript.ts +38 -2
- package/vendor/use-agentic/WIRE.md +20 -0
- package/vendor/use-agentic/index.ts +1 -0
- package/vendor/use-agentic/types.ts +6 -0
- package/webkit/McpAppAgent.ts +12 -2
- package/webkit/RenderLayer.tsx +23 -4
- package/webkit/useDebounce.ts +23 -14
- package/client/viewTransition.ts +0 -10
- package/types/client/viewTransition.d.ts +0 -3
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { type AkanSqlClient, MigrationTables } from "akanjs/service";
|
|
2
|
+
import type { DocSlot } from "./docPath";
|
|
3
|
+
|
|
4
|
+
/** `delete` is written by a rollback alone, removing a row an apply inserted. */
|
|
5
|
+
export type MigrationChangeOp = "update" | "insert" | "delete";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* One row write. `before` and `after` map each changed `_doc` path to its slot; `$removedAt` is the row's removal time
|
|
9
|
+
* and `$doc` a whole `_doc` an insert or delete wrote or took away.
|
|
10
|
+
*/
|
|
11
|
+
export interface MigrationChange {
|
|
12
|
+
runId: string;
|
|
13
|
+
seq: number;
|
|
14
|
+
table: string;
|
|
15
|
+
id: string;
|
|
16
|
+
op: MigrationChangeOp;
|
|
17
|
+
before: Record<string, DocSlot>;
|
|
18
|
+
after: Record<string, DocSlot>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface MigrationChangeRow {
|
|
22
|
+
runId: string;
|
|
23
|
+
seq: number | string;
|
|
24
|
+
tableName: string;
|
|
25
|
+
docId: string;
|
|
26
|
+
op: MigrationChangeOp;
|
|
27
|
+
before: string;
|
|
28
|
+
after: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export class MigrationChangeLog {
|
|
32
|
+
readonly runId: string;
|
|
33
|
+
readonly #connection: () => AkanSqlClient;
|
|
34
|
+
#seq = 0;
|
|
35
|
+
|
|
36
|
+
constructor(runId: string, connection: () => AkanSqlClient) {
|
|
37
|
+
this.runId = runId;
|
|
38
|
+
this.#connection = connection;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Written on the caller's connection, so inside its transaction the entry commits or rolls back with the row. */
|
|
42
|
+
async append(change: Omit<MigrationChange, "runId" | "seq">) {
|
|
43
|
+
const seq = this.#seq + 1;
|
|
44
|
+
await this.#connection()
|
|
45
|
+
.prepare(
|
|
46
|
+
`INSERT INTO "${MigrationTables.change}" ("runId", "seq", "tableName", "docId", "op", "before", "after") VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
|
47
|
+
)
|
|
48
|
+
.run(
|
|
49
|
+
this.runId,
|
|
50
|
+
seq,
|
|
51
|
+
change.table,
|
|
52
|
+
change.id,
|
|
53
|
+
change.op,
|
|
54
|
+
JSON.stringify(change.before),
|
|
55
|
+
JSON.stringify(change.after),
|
|
56
|
+
);
|
|
57
|
+
this.#seq = seq;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
static async count(connection: AkanSqlClient, runId: string) {
|
|
61
|
+
const row = await connection
|
|
62
|
+
.prepare(`SELECT COUNT(*) AS "count" FROM "${MigrationTables.change}" WHERE "runId" = ?`)
|
|
63
|
+
.get<{ count: number | string }>(runId);
|
|
64
|
+
return Number(row?.count ?? 0);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Newest first, the order a rollback undoes them in: up to `limit` changes, from the newest or under seq `below`. */
|
|
68
|
+
static async page(connection: AkanSqlClient, runId: string, below: number | null, limit: number) {
|
|
69
|
+
const rows = await connection
|
|
70
|
+
.prepare(
|
|
71
|
+
`SELECT "runId", "seq", "tableName", "docId", "op", "before", "after" FROM "${MigrationTables.change}" WHERE "runId" = ?${below === null ? "" : ` AND "seq" < ?`} ORDER BY "seq" DESC LIMIT ${Math.trunc(limit)}`,
|
|
72
|
+
)
|
|
73
|
+
.all<MigrationChangeRow>(...(below === null ? [runId] : [runId, below]));
|
|
74
|
+
return rows.map(
|
|
75
|
+
(row): MigrationChange => ({
|
|
76
|
+
runId: row.runId,
|
|
77
|
+
seq: Number(row.seq),
|
|
78
|
+
table: row.tableName,
|
|
79
|
+
id: row.docId,
|
|
80
|
+
op: row.op,
|
|
81
|
+
before: JSON.parse(row.before) as Record<string, DocSlot>,
|
|
82
|
+
after: JSON.parse(row.after) as Record<string, DocSlot>,
|
|
83
|
+
}),
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { MigrationChange } from "./migrationChangeLog";
|
|
2
|
+
import type { MigrationRevertOutcome, MigrationTable } from "./migrationTable";
|
|
3
|
+
|
|
4
|
+
export interface MigrationSkip {
|
|
5
|
+
table: string;
|
|
6
|
+
id: string;
|
|
7
|
+
seq: number;
|
|
8
|
+
reason: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* What a rollback walks with `for await`: the run's changes newest first, read a page at a time, each reverted or
|
|
13
|
+
* skipped with a reason the report shows.
|
|
14
|
+
*/
|
|
15
|
+
export class MigrationChanges implements AsyncIterable<MigrationChange> {
|
|
16
|
+
static readonly pageSize = 500;
|
|
17
|
+
readonly skipped: MigrationSkip[] = [];
|
|
18
|
+
reverted = 0;
|
|
19
|
+
readonly #page: (below: number | null, limit: number) => Promise<MigrationChange[]>;
|
|
20
|
+
readonly #table: (name: string) => MigrationTable;
|
|
21
|
+
readonly #from: number | null;
|
|
22
|
+
#reached: number | null;
|
|
23
|
+
|
|
24
|
+
/** `from`: a seq a rollback cut short got down to, so walking resumes under it. */
|
|
25
|
+
constructor(
|
|
26
|
+
page: (below: number | null, limit: number) => Promise<MigrationChange[]>,
|
|
27
|
+
table: (name: string) => MigrationTable,
|
|
28
|
+
from: number | null = null,
|
|
29
|
+
) {
|
|
30
|
+
this.#page = page;
|
|
31
|
+
this.#table = table;
|
|
32
|
+
this.#from = from;
|
|
33
|
+
this.#reached = from;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async *[Symbol.asyncIterator]() {
|
|
37
|
+
let below = this.#from;
|
|
38
|
+
for (;;) {
|
|
39
|
+
const page = await this.#page(below, MigrationChanges.pageSize);
|
|
40
|
+
yield* page;
|
|
41
|
+
const last = page.at(-1);
|
|
42
|
+
if (!last || page.length < MigrationChanges.pageSize) return;
|
|
43
|
+
below = last.seq;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** The oldest change `revertAll` has finished with; every newer one is reverted or skipped. */
|
|
48
|
+
get reached() {
|
|
49
|
+
return this.#reached;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Undone only if the row still holds what the change wrote; a row edited since is skipped and reported. */
|
|
53
|
+
async revert(change: MigrationChange): Promise<MigrationRevertOutcome> {
|
|
54
|
+
const outcome = await this.#table(change.table).revert(change);
|
|
55
|
+
if (outcome === "reverted") this.reverted++;
|
|
56
|
+
else this.skip(change, outcome === "missing" ? "row no longer exists" : "row changed since the migration");
|
|
57
|
+
return outcome;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
skip(change: MigrationChange, reason: string) {
|
|
61
|
+
this.skipped.push({ table: change.table, id: change.id, seq: change.seq, reason });
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async revertAll() {
|
|
65
|
+
for await (const change of this) {
|
|
66
|
+
await this.revert(change);
|
|
67
|
+
this.#reached = change.seq;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { parseArgs } from "node:util";
|
|
2
|
+
import { MigrationError, type MigrationErrorCode } from "./migrationError";
|
|
3
|
+
import type { MigrationListItem, MigrationRunner } from "./migrationRunner";
|
|
4
|
+
|
|
5
|
+
export const migrationActions = ["list", "plan", "apply", "verify", "rollback"] as const;
|
|
6
|
+
export type MigrationAction = (typeof migrationActions)[number];
|
|
7
|
+
const migrationOptions = ["param", "expect", "actor", "items"] as const;
|
|
8
|
+
type MigrationOption = (typeof migrationOptions)[number];
|
|
9
|
+
|
|
10
|
+
export interface MigrationArgs {
|
|
11
|
+
action: MigrationAction;
|
|
12
|
+
target: string;
|
|
13
|
+
params: Record<string, string>;
|
|
14
|
+
expect: string | null;
|
|
15
|
+
actor: string | null;
|
|
16
|
+
items: number | undefined;
|
|
17
|
+
json: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** The last line `ops migrate --json` prints: what akasys records, keyed by `ok` and `code`. */
|
|
21
|
+
export interface MigrationCommandResult {
|
|
22
|
+
ok: boolean;
|
|
23
|
+
action: MigrationAction | null;
|
|
24
|
+
code?: MigrationErrorCode;
|
|
25
|
+
error?: string;
|
|
26
|
+
runId?: string | null;
|
|
27
|
+
[key: string]: unknown;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export class MigrationCommand {
|
|
31
|
+
static readonly #usageCodes = new Set<MigrationErrorCode>(["usage", "invalidParam", "notFound"]);
|
|
32
|
+
static readonly #optionsOf: { [action in MigrationAction]: readonly MigrationOption[] } = {
|
|
33
|
+
list: [],
|
|
34
|
+
plan: ["param", "items", "actor"],
|
|
35
|
+
apply: ["param", "expect", "actor"],
|
|
36
|
+
verify: ["param", "actor"],
|
|
37
|
+
rollback: ["actor"],
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
static usageOf(invokedAs = "ops migrate") {
|
|
41
|
+
return [
|
|
42
|
+
"Usage:",
|
|
43
|
+
` ${invokedAs} list [--json]`,
|
|
44
|
+
` ${invokedAs} plan <id> [--param <name>=<value>]... [--items <n>] [--actor <id>] [--json]`,
|
|
45
|
+
` ${invokedAs} apply <id> [--param <name>=<value>]... [--expect <planHash>] [--actor <id>] [--json]`,
|
|
46
|
+
` ${invokedAs} verify <id> [--param <name>=<value>]... [--actor <id>] [--json]`,
|
|
47
|
+
` ${invokedAs} rollback <applyRunId|id> [--actor <id>] [--json]`,
|
|
48
|
+
].join("\n");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
static jsonOf(argv: string[]) {
|
|
52
|
+
return argv.some((arg) => arg === "--json" || arg.startsWith("--json="));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
static parse(argv: string[], invokedAs?: string): MigrationArgs {
|
|
56
|
+
const usage = MigrationCommand.usageOf(invokedAs);
|
|
57
|
+
const { values, positionals } = MigrationCommand.#parseArgs(argv, usage);
|
|
58
|
+
const [name = "list", target = "", ...extra] = positionals;
|
|
59
|
+
if (!migrationActions.includes(name as MigrationAction))
|
|
60
|
+
throw new MigrationError("usage", `Unknown action "${name}"\n${usage}`);
|
|
61
|
+
const action = name as MigrationAction;
|
|
62
|
+
if (action === "list" ? target : !target)
|
|
63
|
+
throw new MigrationError("usage", `${action} ${target ? "takes no id" : "needs an id"}\n${usage}`);
|
|
64
|
+
if (extra.length) throw new MigrationError("usage", `Unexpected arguments: ${extra.join(" ")}`);
|
|
65
|
+
const refused = migrationOptions.find(
|
|
66
|
+
(option) => values[option] !== undefined && !MigrationCommand.#optionsOf[action].includes(option),
|
|
67
|
+
);
|
|
68
|
+
if (refused) throw new MigrationError("usage", `${action} takes no --${refused}\n${usage}`);
|
|
69
|
+
if (values.items !== undefined && !/^\d+$/.test(values.items))
|
|
70
|
+
throw new MigrationError("usage", "--items takes a whole number");
|
|
71
|
+
return {
|
|
72
|
+
action,
|
|
73
|
+
target,
|
|
74
|
+
params: MigrationCommand.#params(values.param ?? []),
|
|
75
|
+
expect: values.expect ?? null,
|
|
76
|
+
actor: values.actor ?? null,
|
|
77
|
+
items: values.items === undefined ? undefined : Number(values.items),
|
|
78
|
+
json: values.json,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
static async run(runner: MigrationRunner, args: MigrationArgs): Promise<MigrationCommandResult> {
|
|
83
|
+
const { action, target, params, expect, actor, items } = args;
|
|
84
|
+
try {
|
|
85
|
+
if (action === "list") return { ok: true, action, migrations: await runner.list() };
|
|
86
|
+
if (action === "plan") return { ok: true, action, ...(await runner.plan(target, params, { actor, items })) };
|
|
87
|
+
if (action === "rollback") return { ok: true, action, ...(await runner.rollback(target, { actor })) };
|
|
88
|
+
const result =
|
|
89
|
+
action === "apply"
|
|
90
|
+
? await runner.apply(target, params, { expect, actor })
|
|
91
|
+
: await runner.verify(target, params, { actor });
|
|
92
|
+
if (!result.problems.length) return { ok: true, action, ...result };
|
|
93
|
+
return {
|
|
94
|
+
ok: false,
|
|
95
|
+
action,
|
|
96
|
+
code: "verifyFailed",
|
|
97
|
+
error: MigrationError.remaining(result.problems.length),
|
|
98
|
+
...result,
|
|
99
|
+
};
|
|
100
|
+
} catch (error) {
|
|
101
|
+
return MigrationCommand.failure(action, error);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
static failure(action: MigrationAction | null, error: unknown): MigrationCommandResult {
|
|
106
|
+
return {
|
|
107
|
+
ok: false,
|
|
108
|
+
action,
|
|
109
|
+
code: MigrationError.codeOf(error),
|
|
110
|
+
error: MigrationError.messageOf(error),
|
|
111
|
+
runId: error instanceof MigrationError ? error.runId : null,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
static exitCode(result: MigrationCommandResult) {
|
|
116
|
+
if (result.ok) return 0;
|
|
117
|
+
if (result.code === "verifyFailed") return 3;
|
|
118
|
+
return result.code && MigrationCommand.#usageCodes.has(result.code) ? 2 : 1;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
static async print(result: MigrationCommandResult, json: boolean) {
|
|
122
|
+
const text = `${MigrationCommand.render(result, json)}\n`;
|
|
123
|
+
await new Promise<void>((resolve) => process.stdout.write(text, () => resolve()));
|
|
124
|
+
return MigrationCommand.exitCode(result);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
static render(result: MigrationCommandResult, json: boolean) {
|
|
128
|
+
if (json) return JSON.stringify(result);
|
|
129
|
+
if (result.ok && result.action === "list")
|
|
130
|
+
return MigrationCommand.#renderList(result.migrations as MigrationListItem[]);
|
|
131
|
+
return JSON.stringify(result, null, 2);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
static #renderList(items: MigrationListItem[]) {
|
|
135
|
+
if (!items.length) return "No migration in script/migration/";
|
|
136
|
+
return items
|
|
137
|
+
.map((item) => {
|
|
138
|
+
const note = item.checksumMismatch ? " (applied from another version of the script)" : "";
|
|
139
|
+
const head = `${item.status.padEnd(8)} ${item.id} ${item.title ?? `cannot load: ${item.error}`}${note}`;
|
|
140
|
+
const params = item.params.map(
|
|
141
|
+
(param) =>
|
|
142
|
+
`--param ${param.name}=<${param.type}>${param.required ? "" : "default" in param ? ` (default ${JSON.stringify(param.default)})` : " (optional)"}`,
|
|
143
|
+
);
|
|
144
|
+
return [head, ...params.map((line) => ` ${line}`)].join("\n");
|
|
145
|
+
})
|
|
146
|
+
.join("\n");
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
static #parseArgs(argv: string[], usage: string) {
|
|
150
|
+
try {
|
|
151
|
+
return parseArgs({
|
|
152
|
+
args: argv,
|
|
153
|
+
allowPositionals: true,
|
|
154
|
+
options: {
|
|
155
|
+
param: { type: "string", multiple: true },
|
|
156
|
+
expect: { type: "string" },
|
|
157
|
+
actor: { type: "string" },
|
|
158
|
+
items: { type: "string" },
|
|
159
|
+
json: { type: "boolean", default: false },
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
} catch (error) {
|
|
163
|
+
throw new MigrationError("usage", `${MigrationError.messageOf(error)}\n${usage}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
static #params(pairs: string[]) {
|
|
168
|
+
const params: Record<string, string> = {};
|
|
169
|
+
for (const pair of pairs) {
|
|
170
|
+
const at = pair.indexOf("=");
|
|
171
|
+
const name = at > 0 ? pair.slice(0, at) : "";
|
|
172
|
+
if (!/^[A-Za-z][A-Za-z0-9_]*$/.test(name))
|
|
173
|
+
throw new MigrationError("usage", `--param takes <name>=<value>, not "${pair}"`);
|
|
174
|
+
if (Object.hasOwn(params, name)) throw new MigrationError("usage", `--param ${name} is given twice`);
|
|
175
|
+
params[name] = pair.slice(at + 1);
|
|
176
|
+
}
|
|
177
|
+
return params;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { Logger } from "akanjs/common";
|
|
2
|
+
import type { AkanSqlClient, SqlDialect } from "akanjs/service";
|
|
3
|
+
import type { AkanServer } from "../akanServer";
|
|
4
|
+
import type { MigrationScope } from "./migrationScope";
|
|
5
|
+
import { MigrationTable } from "./migrationTable";
|
|
6
|
+
|
|
7
|
+
export type MigrationGet = AkanServer["get"];
|
|
8
|
+
|
|
9
|
+
export interface MigrationContextOption<Params> {
|
|
10
|
+
id: string;
|
|
11
|
+
params: Params;
|
|
12
|
+
logger: Logger;
|
|
13
|
+
get: MigrationGet;
|
|
14
|
+
scope: MigrationScope;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export class MigrationContext<Params = Record<string, unknown>> {
|
|
18
|
+
readonly id: string;
|
|
19
|
+
readonly params: Params;
|
|
20
|
+
readonly logger: Logger;
|
|
21
|
+
/** A service, signal or adaptor of the booted server, as `server.get` resolves it. */
|
|
22
|
+
readonly get: MigrationGet;
|
|
23
|
+
readonly #scope: MigrationScope;
|
|
24
|
+
readonly #tables = new Map<string, MigrationTable>();
|
|
25
|
+
|
|
26
|
+
constructor({ id, params, logger, get, scope }: MigrationContextOption<Params>) {
|
|
27
|
+
this.id = id;
|
|
28
|
+
this.params = params;
|
|
29
|
+
this.logger = logger;
|
|
30
|
+
this.get = get;
|
|
31
|
+
this.#scope = scope;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Rows of the model table `refName` as stored, whatever its model declares now. */
|
|
35
|
+
readonly table = (refName: string) => {
|
|
36
|
+
const existing = this.#tables.get(refName);
|
|
37
|
+
if (existing) return existing;
|
|
38
|
+
const table = new MigrationTable(refName, this.#scope);
|
|
39
|
+
this.#tables.set(refName, table);
|
|
40
|
+
return table;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
readonly createId = () => this.#scope.createId();
|
|
44
|
+
|
|
45
|
+
/** The connection the run writes through, inside its transaction when it has one. */
|
|
46
|
+
get sql(): AkanSqlClient {
|
|
47
|
+
return this.#scope.connection();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
get dialect(): SqlDialect {
|
|
51
|
+
return this.#scope.dialect;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { PromiseOrObject } from "akanjs/base";
|
|
2
|
+
import type { FieldToValue, ParamFieldType } from "akanjs/constant";
|
|
3
|
+
import type { MigrationChanges } from "./migrationChanges";
|
|
4
|
+
import type { MigrationContext } from "./migrationContext";
|
|
5
|
+
import { type MigrationParamOption, MigrationParams, type MigrationParamValue } from "./migrationParams";
|
|
6
|
+
import { MigrationScope } from "./migrationScope";
|
|
7
|
+
|
|
8
|
+
export interface MigrationPlan<Item = unknown> {
|
|
9
|
+
/** What a person approving the run reads before it writes anything. */
|
|
10
|
+
summary: Record<string, unknown>;
|
|
11
|
+
/** The decisions `apply` carries out; hashed with the params, so a changed one refuses an approved apply. */
|
|
12
|
+
items?: Item[];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface MigrationSettings {
|
|
16
|
+
/** `false` commits as it goes, each `rewrite` batch with where it got to: for runs too long for one transaction. */
|
|
17
|
+
transaction: boolean;
|
|
18
|
+
batchSize: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
type MigrationStage<Params, Result> = (ctx: MigrationContext<Params>) => PromiseOrObject<Result>;
|
|
22
|
+
|
|
23
|
+
export class MigrationDefinition<Params = Record<never, never>, Plan extends MigrationPlan = MigrationPlan> {
|
|
24
|
+
|
|
25
|
+
static readonly #marker = Symbol.for("akan.migrationDefinition");
|
|
26
|
+
static readonly defaultSettings: MigrationSettings = { transaction: true, batchSize: 500 };
|
|
27
|
+
readonly title: string;
|
|
28
|
+
readonly params = new MigrationParams();
|
|
29
|
+
settings: MigrationSettings = { ...MigrationDefinition.defaultSettings };
|
|
30
|
+
planStage: MigrationStage<Params, Plan> | null = null;
|
|
31
|
+
applyStage: ((ctx: MigrationContext<Params>, plan: Plan) => PromiseOrObject<void>) | null = null;
|
|
32
|
+
verifyStage: MigrationStage<Params, string[]> | null = null;
|
|
33
|
+
rollbackStage: ((ctx: MigrationContext<Params>, changes: MigrationChanges) => PromiseOrObject<void>) | null = null;
|
|
34
|
+
|
|
35
|
+
constructor(title: string) {
|
|
36
|
+
this.title = title;
|
|
37
|
+
Object.defineProperty(this, MigrationDefinition.#marker, { value: true });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static is(value: unknown): value is MigrationDefinition<Record<string, unknown>> {
|
|
41
|
+
return (
|
|
42
|
+
!!value && typeof value === "object" && (value as Record<symbol, unknown>)[MigrationDefinition.#marker] === true
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
param<
|
|
47
|
+
Name extends string,
|
|
48
|
+
Type extends ParamFieldType,
|
|
49
|
+
const Option extends MigrationParamOption<FieldToValue<Type>> = Record<never, never>,
|
|
50
|
+
>(name: Name, type: Type, option?: Option) {
|
|
51
|
+
this.params.declare({ ...option, name, type });
|
|
52
|
+
return this as unknown as MigrationDefinition<Params & { [K in Name]: MigrationParamValue<Type, Option> }, Plan>;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Reads only, and returns the report a person approves; `apply` recomputes it inside its own transaction. */
|
|
56
|
+
plan<NextPlan extends MigrationPlan>(fn: MigrationStage<Params, NextPlan>) {
|
|
57
|
+
const next = this as unknown as MigrationDefinition<Params, NextPlan>;
|
|
58
|
+
next.planStage = fn;
|
|
59
|
+
return next;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
apply(fn: (ctx: MigrationContext<Params>, plan: Plan) => PromiseOrObject<void>) {
|
|
63
|
+
this.applyStage = fn;
|
|
64
|
+
return this;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Runs right after apply commits; each string is one problem, and none means the data is as intended. */
|
|
68
|
+
verify(fn: MigrationStage<Params, string[]>) {
|
|
69
|
+
this.verifyStage = fn;
|
|
70
|
+
return this;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Replaces the default rollback, which reverts every logged change whose row still holds what it wrote. */
|
|
74
|
+
rollback(fn: (ctx: MigrationContext<Params>, changes: MigrationChanges) => PromiseOrObject<void>) {
|
|
75
|
+
this.rollbackStage = fn;
|
|
76
|
+
return this;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
config(settings: Partial<MigrationSettings>) {
|
|
80
|
+
if (settings.batchSize !== undefined) MigrationScope.assertBatchSize(settings.batchSize);
|
|
81
|
+
this.settings = { ...this.settings, ...settings };
|
|
82
|
+
return this;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** A data migration in `script/migration/<yyyyMMddHHmm>_<name>.ts`, exported as the file's default. */
|
|
87
|
+
export const migration = (title: string) => new MigrationDefinition(title);
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export type MigrationErrorCode =
|
|
2
|
+
| "usage"
|
|
3
|
+
| "notFound"
|
|
4
|
+
| "invalidParam"
|
|
5
|
+
| "locked"
|
|
6
|
+
| "alreadyApplied"
|
|
7
|
+
| "notApplied"
|
|
8
|
+
| "planChanged"
|
|
9
|
+
| "verifyFailed"
|
|
10
|
+
| "failed";
|
|
11
|
+
|
|
12
|
+
/** A refusal or failure whose `code` the JSON result carries, so a caller decides by it rather than by the message. */
|
|
13
|
+
export class MigrationError extends Error {
|
|
14
|
+
readonly code: MigrationErrorCode;
|
|
15
|
+
/** The ledger run the failure was recorded on, when it got that far. */
|
|
16
|
+
runId: string | null = null;
|
|
17
|
+
|
|
18
|
+
constructor(code: MigrationErrorCode, message: string, options?: { cause?: unknown }) {
|
|
19
|
+
super(message, options);
|
|
20
|
+
this.name = "MigrationError";
|
|
21
|
+
this.code = code;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
static codeOf(error: unknown): MigrationErrorCode {
|
|
25
|
+
return error instanceof MigrationError ? error.code : "failed";
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
static messageOf(error: unknown) {
|
|
29
|
+
return error instanceof Error ? error.message : String(error);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** What a verify that found `problemNum` problems reports. */
|
|
33
|
+
static remaining(problemNum: number) {
|
|
34
|
+
return problemNum === 1 ? "1 problem remains" : `${problemNum} problems remain`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
static recorded(error: unknown, runId: string) {
|
|
38
|
+
const recorded =
|
|
39
|
+
error instanceof MigrationError
|
|
40
|
+
? error
|
|
41
|
+
: new MigrationError("failed", MigrationError.messageOf(error), { cause: error });
|
|
42
|
+
recorded.runId = runId;
|
|
43
|
+
return recorded;
|
|
44
|
+
}
|
|
45
|
+
}
|