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,258 @@
|
|
|
1
|
+
import type { PromiseOrObject } from "akanjs/base";
|
|
2
|
+
import { sanitizeJson } from "akanjs/document";
|
|
3
|
+
import {
|
|
4
|
+
descriptorHash,
|
|
5
|
+
RawDocumentTable,
|
|
6
|
+
type RawFilter,
|
|
7
|
+
type RawFindOptions,
|
|
8
|
+
type TransferRow,
|
|
9
|
+
} from "akanjs/service";
|
|
10
|
+
import { DocPath, type DocSlot } from "./docPath";
|
|
11
|
+
import type { MigrationChange } from "./migrationChangeLog";
|
|
12
|
+
import { MigrationScope } from "./migrationScope";
|
|
13
|
+
|
|
14
|
+
/** A path to its new value; `undefined` removes the path. */
|
|
15
|
+
export type MigrationPatch = Record<string, unknown>;
|
|
16
|
+
|
|
17
|
+
export interface MigrationRewriteOption {
|
|
18
|
+
where?: RawFilter;
|
|
19
|
+
/** Removed rows are rewritten too unless this is `false`. */
|
|
20
|
+
withRemoved?: boolean;
|
|
21
|
+
batchSize?: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Why a logged change was left as it is; `reverted` means it was undone. */
|
|
25
|
+
export type MigrationRevertOutcome = "reverted" | "changed" | "missing";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* A model's rows as stored, whatever the model declares now. Every write records what it changed in the run's change
|
|
29
|
+
* log, in the same transaction, and leaves `updatedAt` alone: a migration reshapes data, it does not edit it.
|
|
30
|
+
*/
|
|
31
|
+
export class MigrationTable {
|
|
32
|
+
static readonly #baseColumns = new Set(["id", "createdAt", "updatedAt", "removedAt"]);
|
|
33
|
+
readonly name: string;
|
|
34
|
+
readonly #raw: RawDocumentTable;
|
|
35
|
+
readonly #scope: MigrationScope;
|
|
36
|
+
|
|
37
|
+
constructor(name: string, scope: MigrationScope) {
|
|
38
|
+
this.name = name;
|
|
39
|
+
this.#scope = scope;
|
|
40
|
+
this.#raw = new RawDocumentTable(name, () => scope.connection(), scope.dialect);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async find(where?: RawFilter, options?: RawFindOptions) {
|
|
44
|
+
await this.#scope.beat();
|
|
45
|
+
return await this.#raw.find(where, options);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async get(id: string) {
|
|
49
|
+
await this.#scope.beat();
|
|
50
|
+
return await this.#raw.get(id);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async count(where?: RawFilter, options?: Omit<RawFindOptions, "limit">) {
|
|
54
|
+
await this.#scope.beat();
|
|
55
|
+
return await this.#raw.count(where, options);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Returns whether anything changed: a value equal to the stored one is no change and is not logged. */
|
|
59
|
+
async set(id: string, patch: MigrationPatch) {
|
|
60
|
+
return await this.#write(id, (row) => this.#update(row, patch));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async unset(id: string, paths: string[]) {
|
|
64
|
+
return await this.set(id, Object.fromEntries(paths.map((path) => [path, undefined])));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** A soft removal, as the model's own `remove` makes. */
|
|
68
|
+
async remove(id: string) {
|
|
69
|
+
return await this.#write(id, (row) => (row.removedAt === null ? this.#update(row, {}, this.#scope.now()) : false));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async restore(id: string) {
|
|
73
|
+
return await this.#write(id, (row) => (row.removedAt === null ? false : this.#update(row, {}, null)));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** A new row; `doc` is its `_doc`, so `id` and the timestamps are not fields of it. */
|
|
77
|
+
async insert(
|
|
78
|
+
doc: Record<string, unknown>,
|
|
79
|
+
{ id, removedAt = null }: { id?: string; removedAt?: number | null } = {},
|
|
80
|
+
) {
|
|
81
|
+
this.#assertWritable();
|
|
82
|
+
const base = Object.keys(doc).find((key) => MigrationTable.#baseColumns.has(key));
|
|
83
|
+
if (base) throw new Error(`"${base}" is a column of ${this.name}, not a field of its _doc`);
|
|
84
|
+
return await this.#transaction(async () => await this.#insert(doc, id ?? this.#scope.createId(), removedAt));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** A new row holding the source's `_doc` with `patch` applied, removed if the source is. */
|
|
88
|
+
async copy(id: string, patch: MigrationPatch = {}) {
|
|
89
|
+
this.#assertWritable();
|
|
90
|
+
return await this.#transaction(async () => {
|
|
91
|
+
const source = await this.#raw.get(id);
|
|
92
|
+
if (!source) throw new Error(`${this.name} ${id} does not exist`);
|
|
93
|
+
const doc = structuredClone(source._doc);
|
|
94
|
+
MigrationTable.#apply(doc, patch);
|
|
95
|
+
return await this.#insert(doc, this.#scope.createId(), source.removedAt);
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* `fn` sees each row in id order and returns a patch, or nothing to leave the row be. Outside a transaction every
|
|
101
|
+
* batch commits with where it got to, so a run cut short resumes there; `fn` must still skip rows it already fixed.
|
|
102
|
+
*/
|
|
103
|
+
async rewrite(
|
|
104
|
+
fn: (row: TransferRow) => PromiseOrObject<MigrationPatch | null | undefined | false>,
|
|
105
|
+
{ where, withRemoved = true, batchSize = this.#scope.batchSize }: MigrationRewriteOption = {},
|
|
106
|
+
) {
|
|
107
|
+
this.#assertWritable();
|
|
108
|
+
MigrationScope.assertBatchSize(batchSize);
|
|
109
|
+
const signature = await descriptorHash({ where: where ?? null, withRemoved, fn: fn.toString() });
|
|
110
|
+
const { key, after: resumed } = this.#scope.nextRewrite(this.name, signature.slice(0, 12));
|
|
111
|
+
let after = resumed;
|
|
112
|
+
let scanned = 0;
|
|
113
|
+
let changed = 0;
|
|
114
|
+
for (;;) {
|
|
115
|
+
const rows = await this.#transaction(async () => {
|
|
116
|
+
const batch = await this.#raw.find(where, { after, limit: batchSize, withRemoved, lock: true });
|
|
117
|
+
for (const row of batch) {
|
|
118
|
+
scanned++;
|
|
119
|
+
const patch = await fn(structuredClone(row));
|
|
120
|
+
if (patch && (await this.#update(row, patch))) changed++;
|
|
121
|
+
}
|
|
122
|
+
const last = batch.at(-1);
|
|
123
|
+
if (last) await this.#scope.reach(key, last.id);
|
|
124
|
+
await this.#scope.beat();
|
|
125
|
+
return batch;
|
|
126
|
+
});
|
|
127
|
+
after = rows.at(-1)?.id ?? after;
|
|
128
|
+
if (rows.length < batchSize) break;
|
|
129
|
+
}
|
|
130
|
+
return { scanned, changed };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Undoes one logged change if the row still holds what the change wrote; a row already back where the change found
|
|
135
|
+
* it counts as undone, so a rollback cut short can run again.
|
|
136
|
+
*/
|
|
137
|
+
async revert(change: MigrationChange): Promise<MigrationRevertOutcome> {
|
|
138
|
+
this.#assertWritable();
|
|
139
|
+
if (change.op === "delete") throw new Error("A rollback's own deletes are final; restore a backup to undo them");
|
|
140
|
+
return await this.#transaction(async () => {
|
|
141
|
+
const row = await this.#raw.get(change.id, { lock: true });
|
|
142
|
+
if (change.op === "insert") {
|
|
143
|
+
if (!row) return "reverted";
|
|
144
|
+
if (!MigrationTable.#holds(row, change.after)) return "changed";
|
|
145
|
+
await this.#raw.delete(row.id);
|
|
146
|
+
await this.#scope.log?.append({
|
|
147
|
+
table: this.name,
|
|
148
|
+
id: row.id,
|
|
149
|
+
op: "delete",
|
|
150
|
+
before: { $doc: [row._doc], $removedAt: [row.removedAt] },
|
|
151
|
+
after: {},
|
|
152
|
+
});
|
|
153
|
+
return "reverted";
|
|
154
|
+
}
|
|
155
|
+
if (!row) return "missing";
|
|
156
|
+
if (MigrationTable.#holds(row, change.before)) return "reverted";
|
|
157
|
+
if (!MigrationTable.#holds(row, change.after)) return "changed";
|
|
158
|
+
const { $removedAt, ...docSlots } = change.before;
|
|
159
|
+
const removedSlot: DocSlot | undefined = $removedAt;
|
|
160
|
+
const patch = Object.fromEntries(
|
|
161
|
+
Object.entries(docSlots).map(([path, slot]) => [path, slot.length ? slot[0] : undefined]),
|
|
162
|
+
);
|
|
163
|
+
try {
|
|
164
|
+
MigrationTable.#apply(structuredClone(row._doc), patch);
|
|
165
|
+
} catch {
|
|
166
|
+
return "changed";
|
|
167
|
+
}
|
|
168
|
+
await this.#update(row, patch, removedSlot ? ((removedSlot[0] ?? null) as number | null) : undefined);
|
|
169
|
+
return "reverted";
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
async #transaction<T>(fn: () => Promise<T>) {
|
|
174
|
+
await this.#scope.beat();
|
|
175
|
+
return await this.#scope.transaction(fn);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
async #write(id: string, fn: (row: TransferRow) => Promise<boolean> | boolean) {
|
|
179
|
+
this.#assertWritable();
|
|
180
|
+
return await this.#transaction(async () => {
|
|
181
|
+
const row = await this.#raw.get(id, { lock: true });
|
|
182
|
+
if (!row) throw new Error(`${this.name} ${id} does not exist`);
|
|
183
|
+
return await fn(row);
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
async #update(row: TransferRow, patch: MigrationPatch, removedAt?: number | null) {
|
|
188
|
+
const paths = Object.keys(patch);
|
|
189
|
+
for (const path of paths) MigrationTable.#assertField(path);
|
|
190
|
+
DocPath.assertDisjoint(paths);
|
|
191
|
+
const doc = structuredClone(row._doc);
|
|
192
|
+
MigrationTable.#apply(doc, patch);
|
|
193
|
+
const before: Record<string, DocSlot> = {};
|
|
194
|
+
const after: Record<string, DocSlot> = {};
|
|
195
|
+
for (const anchor of DocPath.anchors(row._doc, paths)) {
|
|
196
|
+
const previous = DocPath.read(row._doc, anchor);
|
|
197
|
+
const next = DocPath.read(doc, anchor);
|
|
198
|
+
if (DocPath.same(previous, next)) continue;
|
|
199
|
+
before[anchor] = previous;
|
|
200
|
+
after[anchor] = next;
|
|
201
|
+
}
|
|
202
|
+
const nextRemovedAt = removedAt === undefined ? row.removedAt : removedAt;
|
|
203
|
+
if (nextRemovedAt !== row.removedAt) {
|
|
204
|
+
before.$removedAt = [row.removedAt];
|
|
205
|
+
after.$removedAt = [nextRemovedAt];
|
|
206
|
+
}
|
|
207
|
+
if (!Object.keys(after).length) return false;
|
|
208
|
+
await this.#raw.write(row.id, { _doc: doc, removedAt: nextRemovedAt });
|
|
209
|
+
await this.#scope.log?.append({ table: this.name, id: row.id, op: "update", before, after });
|
|
210
|
+
return true;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async #insert(doc: Record<string, unknown>, id: string, removedAt: number | null) {
|
|
214
|
+
const now = this.#scope.now();
|
|
215
|
+
const stored = (sanitizeJson(doc) ?? {}) as Record<string, unknown>;
|
|
216
|
+
await this.#raw.insert({ id, createdAt: now, updatedAt: now, removedAt, _doc: stored });
|
|
217
|
+
await this.#scope.log?.append({
|
|
218
|
+
table: this.name,
|
|
219
|
+
id,
|
|
220
|
+
op: "insert",
|
|
221
|
+
before: {},
|
|
222
|
+
after: { $doc: [stored], $removedAt: [removedAt] },
|
|
223
|
+
});
|
|
224
|
+
return id;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
#assertWritable() {
|
|
228
|
+
if (this.#scope.readOnly) throw new Error(`plan and verify only read; ${this.name} is written in apply`);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
static #apply(doc: Record<string, unknown>, patch: MigrationPatch) {
|
|
232
|
+
for (const [path, value] of Object.entries(patch)) {
|
|
233
|
+
MigrationTable.#assertField(path);
|
|
234
|
+
if (value === undefined) DocPath.remove(doc, path);
|
|
235
|
+
else DocPath.write(doc, path, value);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
static #holds(row: TransferRow, slots: Record<string, DocSlot>) {
|
|
240
|
+
return Object.entries(slots).every(
|
|
241
|
+
([path, slot]) =>
|
|
242
|
+
DocPath.same(MigrationTable.#slot(row, path), slot) &&
|
|
243
|
+
(slot.length > 0 || path.startsWith("$") || DocPath.hasParent(row._doc, path)),
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
static #slot(row: TransferRow, path: string): DocSlot {
|
|
248
|
+
if (path === "$removedAt") return [row.removedAt];
|
|
249
|
+
if (path === "$doc") return [row._doc];
|
|
250
|
+
return DocPath.read(row._doc, path);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
static #assertField(path: string) {
|
|
254
|
+
const root = path.split(".")[0] ?? "";
|
|
255
|
+
if (MigrationTable.#baseColumns.has(root) || root.startsWith("$"))
|
|
256
|
+
throw new Error(`"${path}" is not a field of _doc; remove and restore set removedAt`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Logger } from "akanjs/common";
|
|
2
|
+
import { DatabaseAdaptorRole } from "akanjs/service";
|
|
3
|
+
import type { AkanServer } from "../akanServer";
|
|
4
|
+
import { AppInfo } from "../ops/appInfo";
|
|
5
|
+
import {
|
|
6
|
+
type MigrationAction,
|
|
7
|
+
type MigrationArgs,
|
|
8
|
+
MigrationCommand,
|
|
9
|
+
type MigrationCommandResult,
|
|
10
|
+
} from "./migrationCommand";
|
|
11
|
+
import { MigrationError } from "./migrationError";
|
|
12
|
+
import { type MigrationEntry, MigrationRunner } from "./migrationRunner";
|
|
13
|
+
|
|
14
|
+
/** The migrations one build carries, as the generated `server.ts` lists them. */
|
|
15
|
+
export class Migrations {
|
|
16
|
+
readonly entries: MigrationEntry[];
|
|
17
|
+
|
|
18
|
+
constructor(entries: MigrationEntry[]) {
|
|
19
|
+
this.entries = [...entries].sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** On a started server: the runner writes through its database adaptor. */
|
|
23
|
+
runner(server: AkanServer) {
|
|
24
|
+
return new MigrationRunner(this.entries, {
|
|
25
|
+
database: server.get(DatabaseAdaptorRole),
|
|
26
|
+
get: server.get.bind(server),
|
|
27
|
+
buildId: AppInfo.build().buildId,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Boots `server` with no listener or schedule, runs one action, and prints its result last. Returns the exit code. */
|
|
32
|
+
async command(server: AkanServer, argv: string[], invokedAs?: string) {
|
|
33
|
+
let json = MigrationCommand.jsonOf(argv);
|
|
34
|
+
let action: MigrationAction | null = null;
|
|
35
|
+
let result: MigrationCommandResult;
|
|
36
|
+
try {
|
|
37
|
+
const args = MigrationCommand.parse(argv, invokedAs);
|
|
38
|
+
({ json, action } = args);
|
|
39
|
+
result = await this.#run(server, args);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
result = MigrationCommand.failure(action, error);
|
|
42
|
+
}
|
|
43
|
+
return await MigrationCommand.print(result, json);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async #run(server: AkanServer, args: MigrationArgs) {
|
|
47
|
+
await server.start({ listen: false, web: false, schedules: false });
|
|
48
|
+
try {
|
|
49
|
+
return await MigrationCommand.run(this.runner(server), args);
|
|
50
|
+
} finally {
|
|
51
|
+
|
|
52
|
+
await server.stop().catch((error: unknown) => {
|
|
53
|
+
new Logger("Migrations").error(`The server did not stop cleanly: ${MigrationError.messageOf(error)}`);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
package/server/ops/opsCommand.ts
CHANGED
|
@@ -1,23 +1,33 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { parseArgs } from "node:util";
|
|
4
|
+
import type { AkanServer } from "../akanServer";
|
|
5
|
+
import { MigrationCommand } from "../migration/migrationCommand";
|
|
6
|
+
import type { Migrations } from "../migration/migrations";
|
|
4
7
|
import { SnapshotRestore } from "./snapshotRestore";
|
|
5
8
|
import type { SnapshotSources } from "./snapshotTypes";
|
|
6
9
|
import { SqliteFiles } from "./sqliteFiles";
|
|
7
10
|
import { SqliteSnapshot } from "./sqliteSnapshot";
|
|
8
11
|
|
|
12
|
+
/** What `main.js` lends a command that needs the app itself: its server module, imported with a replica's env. */
|
|
13
|
+
export interface OpsHost {
|
|
14
|
+
importServer(): Promise<{ server?: AkanServer; migrations?: Migrations }>;
|
|
15
|
+
}
|
|
16
|
+
|
|
9
17
|
export class OpsCommand {
|
|
10
18
|
static readonly usage = [
|
|
11
19
|
"Usage:",
|
|
12
20
|
" bun main.js ops snapshot [--id <id>] [--out <dir>] [--include-solid] [--db <file>] [--solid-db <file>] [--json]",
|
|
13
21
|
" bun main.js ops restore <manifest.json> [--identity <file>] [--db <file>] [--solid-db <file>] [--force]",
|
|
22
|
+
" bun main.js ops migrate [list|plan|apply|verify|rollback] [<id>] [--param <name>=<value>]... [--expect <planHash>] [--items <n>] [--actor <id>] [--json]",
|
|
14
23
|
].join("\n");
|
|
15
24
|
|
|
16
|
-
static async run(argv: string[]): Promise<number> {
|
|
25
|
+
static async run(argv: string[], host?: OpsHost): Promise<number> {
|
|
17
26
|
const [command, ...rest] = argv;
|
|
18
27
|
try {
|
|
19
28
|
if (command === "snapshot") return await OpsCommand.#snapshot(rest);
|
|
20
29
|
if (command === "restore") return await OpsCommand.#restore(rest);
|
|
30
|
+
if (command === "migrate") return await OpsCommand.#migrate(rest, host);
|
|
21
31
|
process.stderr.write(`${OpsCommand.usage}\n`);
|
|
22
32
|
return 2;
|
|
23
33
|
} catch (error) {
|
|
@@ -78,6 +88,25 @@ export class OpsCommand {
|
|
|
78
88
|
return 0;
|
|
79
89
|
}
|
|
80
90
|
|
|
91
|
+
static async #migrate(argv: string[], host?: OpsHost) {
|
|
92
|
+
let app: { server: AkanServer; migrations: Migrations };
|
|
93
|
+
try {
|
|
94
|
+
app = await OpsCommand.#migratingApp(host);
|
|
95
|
+
} catch (error) {
|
|
96
|
+
|
|
97
|
+
return await MigrationCommand.print(MigrationCommand.failure(null, error), MigrationCommand.jsonOf(argv));
|
|
98
|
+
}
|
|
99
|
+
return await app.migrations.command(app.server, argv);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
static async #migratingApp(host?: OpsHost) {
|
|
103
|
+
if (!host) throw new Error("migrate boots the app's server, so it runs through main.js");
|
|
104
|
+
const { server, migrations } = await host.importServer();
|
|
105
|
+
if (!server?.start) throw new Error("server.js must export server");
|
|
106
|
+
if (!migrations) throw new Error("this build lists no migrations; build it with an akan that writes the manifest");
|
|
107
|
+
return { server, migrations };
|
|
108
|
+
}
|
|
109
|
+
|
|
81
110
|
static #sources(db?: string, solidDb?: string): SnapshotSources {
|
|
82
111
|
const fromEnv = SqliteFiles.fromEnv();
|
|
83
112
|
return {
|
|
@@ -85,7 +85,7 @@ export class CascadeRunner {
|
|
|
85
85
|
|
|
86
86
|
async #removeRef(edge: RefEdge, doc: Record<string, unknown>, seen: Set<string>) {
|
|
87
87
|
const value = doc[edge.key];
|
|
88
|
-
const ids = (Array.isArray(value) ? value : [value]).filter(
|
|
88
|
+
const ids = [...new Set(Array.isArray(value) ? value : [value])].filter(
|
|
89
89
|
(item): item is string => typeof item === "string" && !seen.has(`${edge.refName}:${item}`),
|
|
90
90
|
);
|
|
91
91
|
if (!ids.length) return;
|
|
@@ -94,8 +94,20 @@ export class CascadeRunner {
|
|
|
94
94
|
await service.__removeMany({ id: documentQueryHelper.oneOf(ids) });
|
|
95
95
|
return;
|
|
96
96
|
}
|
|
97
|
+
|
|
98
|
+
const live = new Set<string>();
|
|
99
|
+
for (let start = 0; start < ids.length; start += drainSize) {
|
|
100
|
+
const chunk = ids.slice(start, start + drainSize);
|
|
101
|
+
for (const id of await service.__listIds({ id: documentQueryHelper.oneOf(chunk) })) live.add(id);
|
|
102
|
+
}
|
|
97
103
|
|
|
98
|
-
for (const id of ids)
|
|
104
|
+
for (const id of ids) {
|
|
105
|
+
if (!live.has(id)) continue;
|
|
106
|
+
|
|
107
|
+
if (seen.has(`${edge.refName}:${id}`)) continue;
|
|
108
|
+
seen.add(`${edge.refName}:${id}`);
|
|
109
|
+
await service.__remove(id);
|
|
110
|
+
}
|
|
99
111
|
}
|
|
100
112
|
|
|
101
113
|
async #removeWith(edge: WithEdge, ownerRef: string, ownerId: string, seen: Set<string>) {
|
|
@@ -112,6 +124,7 @@ export class CascadeRunner {
|
|
|
112
124
|
let removed = 0;
|
|
113
125
|
for (const id of ids) {
|
|
114
126
|
if (seen.has(`${edge.refName}:${id}`)) continue;
|
|
127
|
+
seen.add(`${edge.refName}:${id}`);
|
|
115
128
|
await service.__remove(id);
|
|
116
129
|
removed += 1;
|
|
117
130
|
}
|
|
@@ -10,11 +10,10 @@ import {
|
|
|
10
10
|
ID,
|
|
11
11
|
INTERNAL_META,
|
|
12
12
|
Int,
|
|
13
|
-
PrimitiveRegistry,
|
|
14
13
|
type PromiseOrObject,
|
|
15
14
|
SLICE_META,
|
|
16
15
|
} from "akanjs/base";
|
|
17
|
-
import { capitalize,
|
|
16
|
+
import { capitalize, Logger } from "akanjs/common";
|
|
18
17
|
import {
|
|
19
18
|
type ConstantField,
|
|
20
19
|
deserialize,
|
|
@@ -23,8 +22,10 @@ import {
|
|
|
23
22
|
resolvePageSkip,
|
|
24
23
|
serialize,
|
|
25
24
|
} from "akanjs/constant";
|
|
25
|
+
import { DictionaryRegistry } from "akanjs/dictionary";
|
|
26
26
|
import { baseDocumentColumns, documentQueryHelper, getFilterSortByKey, type QueryFieldMap } from "akanjs/document";
|
|
27
27
|
import {
|
|
28
|
+
type AdaptorCls,
|
|
28
29
|
type AkanJob,
|
|
29
30
|
type AkanJobOptions,
|
|
30
31
|
type DocumentStore,
|
|
@@ -36,8 +37,8 @@ import {
|
|
|
36
37
|
} from "akanjs/service";
|
|
37
38
|
import { websocketRoomContract } from "../../common/websocketContract";
|
|
38
39
|
import { type Endpoint, type EndpointCls, sliceEndpoint } from "../../signal/endpoint";
|
|
40
|
+
import { EndpointErrorContract } from "../../signal/endpointErrorContract";
|
|
39
41
|
import type { EndpointInfo } from "../../signal/endpointInfo";
|
|
40
|
-
import { EndpointRateLimit } from "../../signal/endpointRateLimit";
|
|
41
42
|
import type { Internal, InternalCls } from "../../signal/internal";
|
|
42
43
|
import { Machine } from "../../signal/internalArg";
|
|
43
44
|
import type { InternalInfo } from "../../signal/internalInfo";
|
|
@@ -78,6 +79,7 @@ export class SignalResolver {
|
|
|
78
79
|
static readonly #coalescingRooms = new Set<string>();
|
|
79
80
|
static readonly #liveRoutes = new Map<string, { store: DocumentStore; route: LiveRoute }>();
|
|
80
81
|
static readonly #everyRowAsked = new Set<string>();
|
|
82
|
+
static readonly #websockets = new WeakMap<InjectRegistry, { key: AdaptorCls; websocket: WebsocketAdaptor }>();
|
|
81
83
|
|
|
82
84
|
static coalescesRoom(roomId: string): boolean {
|
|
83
85
|
const separator = roomId.indexOf("-");
|
|
@@ -645,6 +647,7 @@ export class SignalResolver {
|
|
|
645
647
|
const defaultPrefix = endpointCls.srv.cnst?.refName;
|
|
646
648
|
SignalResolver.#warnUnguarded(endpointMeta);
|
|
647
649
|
SignalResolver.#warnMachineKeyless(endpointMeta);
|
|
650
|
+
SignalResolver.#warnUndefinedErrors(endpointMeta);
|
|
648
651
|
Object.entries(endpointMeta).forEach(([key, endpointInfo]) => {
|
|
649
652
|
const path = endpointInfo.getRoutePath(key, defaultPrefix);
|
|
650
653
|
if (endpointInfo.signalOption.globalPrefix !== undefined) {
|
|
@@ -669,32 +672,7 @@ export class SignalResolver {
|
|
|
669
672
|
);
|
|
670
673
|
switch (endpointInfo.type) {
|
|
671
674
|
case "query":
|
|
672
|
-
SignalResolver.#mountHttpRoute(
|
|
673
|
-
routes,
|
|
674
|
-
path,
|
|
675
|
-
SignalResolver.#canUsePrimitiveQueryFastPath(key, endpointInfo, middleware)
|
|
676
|
-
? {
|
|
677
|
-
GET: async (req) => {
|
|
678
|
-
if (req.headers.get("authorization") || cookieHeaderHasAuthToken(req.headers.get("cookie")))
|
|
679
|
-
return await normalHttpHandler(req);
|
|
680
|
-
|
|
681
|
-
return await SignalContext.try(
|
|
682
|
-
endpoint,
|
|
683
|
-
endpointInfo,
|
|
684
|
-
key,
|
|
685
|
-
async () => {
|
|
686
|
-
const result = await endpointInfo.execFn?.call(endpoint);
|
|
687
|
-
return result instanceof Response ? result : Response.json(result);
|
|
688
|
-
},
|
|
689
|
-
{ trace: false },
|
|
690
|
-
);
|
|
691
|
-
},
|
|
692
|
-
}
|
|
693
|
-
: {
|
|
694
|
-
GET: normalHttpHandler,
|
|
695
|
-
},
|
|
696
|
-
key,
|
|
697
|
-
);
|
|
675
|
+
SignalResolver.#mountHttpRoute(routes, path, { GET: normalHttpHandler }, key);
|
|
698
676
|
break;
|
|
699
677
|
case "mutation":
|
|
700
678
|
SignalResolver.#mountHttpRoute(
|
|
@@ -826,6 +804,20 @@ export class SignalResolver {
|
|
|
826
804
|
`${open.join(", ")} declare${open.length === 1 ? "s" : ""} no guards, so anyone can call ${open.length === 1 ? "it" : "them"} over HTTP and WebSocket. Name the guards, or \`guards: [Public]\` to keep one open on purpose.`,
|
|
827
805
|
);
|
|
828
806
|
}
|
|
807
|
+
|
|
808
|
+
static #warnUndefinedErrors(endpointMeta: { [key: string]: EndpointInfo }) {
|
|
809
|
+
const declared = Object.entries(endpointMeta).flatMap(([key, endpointInfo]) =>
|
|
810
|
+
EndpointErrorContract.keysOf(endpointInfo.signalOption.errors).map((errorKey) => `${key} → ${errorKey}`),
|
|
811
|
+
);
|
|
812
|
+
if (!declared.length) return;
|
|
813
|
+
const known = new Set(DictionaryRegistry.getKeys());
|
|
814
|
+
if (!known.size) return;
|
|
815
|
+
const undefinedKeys = declared.filter((entry) => !known.has(entry.split(" → ")[1] ?? ""));
|
|
816
|
+
if (!undefinedKeys.length) return;
|
|
817
|
+
SignalResolver.logger.warn(
|
|
818
|
+
`${undefinedKeys.join(", ")}: declared in \`errors\`, defined in no dictionary's \`.error({})\`. Add the key, or drop it from the declaration.`,
|
|
819
|
+
);
|
|
820
|
+
}
|
|
829
821
|
static #warnMachineKeyless(endpointMeta: { [key: string]: EndpointInfo }) {
|
|
830
822
|
if (MachineToken.canVerify()) return;
|
|
831
823
|
const machineOnly = Object.entries(endpointMeta)
|
|
@@ -847,24 +839,6 @@ export class SignalResolver {
|
|
|
847
839
|
return select;
|
|
848
840
|
}
|
|
849
841
|
|
|
850
|
-
static #canUsePrimitiveQueryFastPath(
|
|
851
|
-
key: string,
|
|
852
|
-
endpointInfo: EndpointInfo,
|
|
853
|
-
middleware: Map<string, MiddlewareCls>,
|
|
854
|
-
) {
|
|
855
|
-
return (
|
|
856
|
-
process.env.AKAN_TRACE !== "1" &&
|
|
857
|
-
!EndpointRateLimit.budgetOf(key, endpointInfo) &&
|
|
858
|
-
endpointInfo.args.length === 0 &&
|
|
859
|
-
endpointInfo.internalArgs.length === 0 &&
|
|
860
|
-
(endpointInfo.signalOption.guards?.length ?? 0) === 0 &&
|
|
861
|
-
(endpointInfo.signalOption.middlewares?.length ?? 0) === 0 &&
|
|
862
|
-
[...middleware.values()].every((MiddlewareCls) => MiddlewareCls.refName === "AccountMiddleware") &&
|
|
863
|
-
endpointInfo.returns.arrDepth === 0 &&
|
|
864
|
-
PrimitiveRegistry.has(endpointInfo.returns.returnRef as Cls)
|
|
865
|
-
);
|
|
866
|
-
}
|
|
867
|
-
|
|
868
842
|
static async revalidateWsRooms(
|
|
869
843
|
ws: Bun.ServerWebSocket<any>,
|
|
870
844
|
registry: InjectRegistry,
|
|
@@ -912,17 +886,23 @@ export class SignalResolver {
|
|
|
912
886
|
if ((live?.syncHub.roomCount ?? 0) < liveRooms) SignalResolver.#roomReplay?.forget(roomId);
|
|
913
887
|
else SignalResolver.#roomReplay?.left(roomId);
|
|
914
888
|
}
|
|
889
|
+
|
|
915
890
|
static #getWebsocket(registry: InjectRegistry): WebsocketAdaptor {
|
|
891
|
+
const found = SignalResolver.#websockets.get(registry);
|
|
892
|
+
if (found && registry.adaptor.get(found.key) === (found.websocket as unknown)) return found.websocket;
|
|
893
|
+
const key = SignalResolver.#websocketKey(registry);
|
|
894
|
+
const websocket = key ? (registry.adaptor.get(key) as WebsocketAdaptor | undefined) : undefined;
|
|
895
|
+
if (!key || !websocket) throw new Error("WebSocket adaptor is not registered");
|
|
896
|
+
SignalResolver.#websockets.set(registry, { key, websocket });
|
|
897
|
+
return websocket;
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
static #websocketKey(registry: InjectRegistry): AdaptorCls | undefined {
|
|
901
|
+
if (registry.adaptor.has(WebsocketAdaptorRole)) return WebsocketAdaptorRole;
|
|
916
902
|
const roleProvider = [...registry.adaptorRole.entries()].find(
|
|
917
903
|
([role]) => role.refName === WebsocketAdaptorRole.refName,
|
|
918
904
|
)?.[1];
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
(roleProvider ? (registry.adaptor.get(roleProvider) as WebsocketAdaptor | undefined) : undefined) ??
|
|
922
|
-
([...registry.adaptor.entries()].find(([adaptorCls]) =>
|
|
923
|
-
["solidPubsub", "wsRedis"].includes(adaptorCls.refName),
|
|
924
|
-
)?.[1] as WebsocketAdaptor | undefined);
|
|
925
|
-
if (!websocket) throw new Error("WebSocket adaptor is not registered");
|
|
926
|
-
return websocket;
|
|
905
|
+
if (roleProvider && registry.adaptor.has(roleProvider)) return roleProvider;
|
|
906
|
+
return [...registry.adaptor.keys()].find((adaptorCls) => ["solidPubsub", "wsRedis"].includes(adaptorCls.refName));
|
|
927
907
|
}
|
|
928
908
|
}
|
package/server/routeState.ts
CHANGED
|
@@ -27,8 +27,6 @@ export interface AkanRouterStateV1 {
|
|
|
27
27
|
href: string;
|
|
28
28
|
routeId: string;
|
|
29
29
|
segments: AkanRouteSegmentState[];
|
|
30
|
-
/** The route's `.config({ transition })`, which the browser plays as a view transition on the way in and out. */
|
|
31
|
-
transition?: string;
|
|
32
30
|
}
|
|
33
31
|
|
|
34
32
|
export type AkanHeadSnapshotTag = "title" | "meta" | "link";
|
|
@@ -134,7 +132,6 @@ export function isAkanRouterStateV1(value: unknown): value is AkanRouterStateV1
|
|
|
134
132
|
(state.buildId === undefined || typeof state.buildId === "number") &&
|
|
135
133
|
typeof state.href === "string" &&
|
|
136
134
|
typeof state.routeId === "string" &&
|
|
137
|
-
(state.transition === undefined || typeof state.transition === "string") &&
|
|
138
135
|
Array.isArray(state.segments) &&
|
|
139
136
|
state.segments.every(isSegmentState)
|
|
140
137
|
);
|
|
@@ -210,12 +207,10 @@ export function createAkanRouterState({
|
|
|
210
207
|
pathRoute,
|
|
211
208
|
href,
|
|
212
209
|
buildId,
|
|
213
|
-
transition,
|
|
214
210
|
}: {
|
|
215
211
|
pathRoute: PathRoute;
|
|
216
212
|
href: string;
|
|
217
213
|
buildId?: number;
|
|
218
|
-
transition?: string;
|
|
219
214
|
}): AkanRouterStateV1 {
|
|
220
215
|
return {
|
|
221
216
|
version: AKAN_RSC_STATE_VERSION,
|
|
@@ -223,7 +218,6 @@ export function createAkanRouterState({
|
|
|
223
218
|
href,
|
|
224
219
|
routeId: pathRoute.path,
|
|
225
220
|
segments: createAkanRouteSegments(pathRoute),
|
|
226
|
-
...(transition && transition !== "none" ? { transition } : {}),
|
|
227
221
|
};
|
|
228
222
|
}
|
|
229
223
|
|