akanjs 2.2.4-rc.5 → 2.2.4
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/base.test.ts +135 -0
- package/base/base.ts +1 -1
- package/base/baseEnv.test.ts +146 -0
- package/base/primitiveRegistry.test.ts +127 -0
- package/base/primitiveRegistry.ts +10 -6
- package/base/symbols.test.ts +29 -0
- package/base/types.ts +4 -1
- package/base/utils.test.ts +30 -0
- package/build.ts +318 -0
- package/capacitor.base.config.test.ts +83 -0
- package/capacitor.base.config.ts +1 -1
- package/client/capacitor.ts +1 -1
- package/client/client.auth-storage.test.ts +210 -0
- package/client/client.decorators.test.ts +74 -0
- package/client/client.device.test.ts +181 -0
- package/client/client.page.test.tsx +175 -0
- package/client/client.pure.test.ts +146 -0
- package/client/client.router.test.ts +290 -0
- package/client/cookie.ts +4 -2
- package/client/createFont.ts +2 -2
- package/client/csrTypes.ts +8 -2
- package/client/makePageProto.tsx +10 -4
- package/client/router.ts +8 -3
- package/client/translator.ts +12 -4
- package/common/Logger.test.ts +45 -0
- package/common/Logger.ts +4 -1
- package/common/formatAndValidation.test.ts +61 -0
- package/common/formatNumber.ts +5 -2
- package/common/hmrPhase.ts +1 -1
- package/common/httpClient.test.ts +91 -0
- package/common/isValidDate.ts +3 -0
- package/common/objectPath.test.ts +108 -0
- package/common/routeConvention.test.ts +132 -0
- package/common/runtimeConfig.test.ts +84 -0
- package/constant/constant.test.ts +374 -0
- package/constant/fieldInfo.ts +3 -3
- package/constant/purify.ts +2 -1
- package/constant/types.ts +4 -0
- package/constant/via.ts +12 -6
- package/dictionary/dictionary.test.ts +352 -0
- package/document/databaseRegistry.ts +8 -0
- package/document/document.test.ts +698 -0
- package/document/into.ts +1 -0
- package/fetch/client/fetchClient.ts +6 -1
- package/fetch/client/httpClient.ts +2 -1
- package/fetch/fetch.test.ts +838 -0
- package/fetch/fetchType/appliedReturn.type.ts +1 -0
- package/fetch/fetchType/endpointFetch.type.ts +3 -0
- package/fetch/fetchType/sliceFetch.type.ts +8 -0
- package/fetch/requestStorage.ts +10 -2
- package/package.json +24 -67
- package/server/akanApp.test.ts +130 -0
- package/server/akanApp.ts +5 -2
- package/server/akanLib.ts +1 -0
- package/server/akanServer.test.ts +157 -0
- package/server/akanServer.ts +4 -3
- package/server/artifact/builderRpc.ts +2 -2
- package/server/artifact/ipcTypes.ts +4 -0
- package/server/artifact/routeClientCache.test.ts +265 -0
- package/server/artifact/routeSeedIndex.test.ts +56 -0
- package/server/artifact/routesManifest.test.ts +64 -0
- package/server/decorators.ts +1 -1
- package/server/di/diLifecycle.contract.test.ts +168 -0
- package/server/di/diLifecycle.ts +6 -3
- package/server/hmr/clientScript.ts +20 -2
- package/server/hmr/devHmrController.ts +4 -0
- package/server/logging/rotatingLogWriter.test.ts +119 -0
- package/server/processMetrics.test.ts +24 -0
- package/server/processMetricsCollector.ts +1 -1
- package/server/proxy/webProxyRunner.test.ts +66 -0
- package/server/resolver/database.resolver.ts +2 -2
- package/server/resolver/resolver.contract.fixture.ts +1 -0
- package/server/resolver/resolver.contract.test.ts +594 -0
- package/server/resolver/signal.resolver.ts +10 -2
- package/server/robots.test.ts +16 -0
- package/server/routeTree.test.tsx +198 -0
- package/server/routing/apiRouter.test.ts +136 -0
- package/server/routing/apiRouter.ts +4 -2
- package/server/rscClient.tsx +7 -1
- package/server/rscWorkerHost.ts +33 -11
- package/server/sitemap.test.ts +61 -0
- package/server/ssrFromRscRenderer.tsx +35 -3
- package/server/systemPages.test.tsx +93 -0
- package/server/types/react-server-dom-webpack.d.ts +7 -1
- package/server/vendor/react-dom-client.ts +1 -1
- package/server/vendor/react-dom.ts +3 -2
- package/server/vendor/react-jsx-dev-runtime.ts +1 -1
- package/server/vendor/react-jsx-runtime.ts +1 -1
- package/server/vendor/react-refresh-runtime.ts +2 -2
- package/server/vendor/react-server-dom-webpack-client-browser.ts +1 -1
- package/server/vendor/react.ts +9 -2
- package/server/vendor/scheduler.ts +3 -2
- package/server/webRouter.test.ts +49 -0
- package/server/webRouter.ts +3 -2
- package/service/adapt.ts +5 -1
- package/service/predefinedAdaptor/cache.adaptor.ts +2 -1
- package/service/predefinedAdaptor/compress.adaptor.test.ts +184 -0
- package/service/predefinedAdaptor/database.adaptor.ts +2 -2
- package/service/predefinedAdaptor/solidCache.adaptor.test.ts +107 -0
- package/service/predefinedAdaptor/solidSqlite.test.ts +457 -0
- package/service/predefinedAdaptor/solidSqlite.ts +2 -1
- package/service/predefinedAdaptor/websocket.adaptor.ts +15 -3
- package/service/serve.ts +7 -3
- package/service/service.test.ts +732 -0
- package/signal/base.signal.ts +1 -0
- package/signal/endpointInfo.ts +7 -0
- package/signal/intercept.ts +2 -0
- package/signal/middleware.ts +2 -1
- package/signal/serverSignal.ts +15 -1
- package/signal/signal.test.ts +892 -0
- package/signal/signalContext.ts +1 -1
- package/signal/signalRegistry.ts +5 -0
- package/signal/sliceInfo.ts +3 -0
- package/signal/trace.ts +11 -0
- package/signal/types.ts +11 -2
- package/store/action.ts +5 -3
- package/store/stateBuilder.test.ts +168 -0
- package/store/stateBuilder.ts +2 -0
- package/store/stateInfo.ts +2 -1
- package/store/store.test.ts +427 -0
- package/store/types.ts +1 -1
- package/test/playwright.config.base.ts +28 -5
- package/test/playwright.pageAgent.ts +1 -1
- package/test/sampleOf.ts +1 -1
- package/test/testServer.ts +1 -1
- package/tsconfig.json +5 -0
- package/ui/BottomSheet.tsx +1 -1
- package/ui/Clipboard.tsx +1 -1
- package/ui/Constant/schemaDoc.test.ts +113 -0
- package/ui/CsrImage.tsx +14 -3
- package/ui/Data/ListContainer.tsx +1 -1
- package/ui/Data/Pagination.tsx +1 -1
- package/ui/Data/QueryMaker.tsx +339 -0
- package/ui/Data/index.ts +1 -0
- package/ui/DatePicker.tsx +95 -1
- package/ui/Dialog/Modal.tsx +1 -1
- package/ui/DraggableList.tsx +5 -5
- package/ui/Field.tsx +3 -2
- package/ui/Image.tsx +3 -2
- package/ui/InfiniteScroll.test.tsx +155 -0
- package/ui/InfiniteScroll.tsx +1 -0
- package/ui/Input.tsx +8 -1
- package/ui/Layout/BottomTab.tsx +2 -2
- package/ui/Link/SsrLink.tsx +2 -1
- package/ui/Load/Page.tsx +1 -1
- package/ui/Load/PageCSR.tsx +1 -0
- package/ui/Load/Units.tsx +2 -1
- package/ui/Load/View.tsx +2 -1
- package/ui/Menu.tsx +8 -5
- package/ui/Model/EditModal.tsx +5 -2
- package/ui/Popconfirm.tsx +4 -2
- package/ui/ScreenNavigator.tsx +3 -2
- package/ui/Signal/Message.tsx +3 -2
- package/ui/Signal/PubSub.tsx +2 -0
- package/ui/Signal/Response.tsx +1 -1
- package/ui/Signal/WebSocket.tsx +11 -2
- package/ui/System/Client.tsx +41 -7
- package/ui/System/Common.test.ts +37 -0
- package/ui/System/Gtag.tsx +5 -2
- package/ui/System/Messages.tsx +2 -2
- package/ui/System/Reconnect.tsx +6 -5
- package/ui/System/Root.tsx +1 -0
- package/ui/System/SSR.tsx +7 -1
- package/ui/ToggleSelect.tsx +8 -3
- package/ui/Unauthorized.tsx +1 -1
- package/webkit/bootCsr.test.tsx +153 -0
- package/webkit/bootCsr.tsx +6 -3
- package/webkit/lazy.tsx +8 -1
- package/webkit/native.test.tsx +341 -0
- package/webkit/useCamera.tsx +1 -0
- package/webkit/useCodepush.tsx +9 -4
- package/webkit/useContact.tsx +1 -0
- package/webkit/useCsrValues.ts +10 -6
- package/webkit/useDebounce.ts +2 -2
- package/webkit/usePurchase.tsx +9 -5
- package/webkit/usePushNoti.tsx +1 -0
- package/webkit/webkit.test.tsx +531 -0
- package/types/base/base.d.ts +0 -53
- package/types/base/baseEnv.d.ts +0 -68
- package/types/base/index.d.ts +0 -6
- package/types/base/primitiveRegistry.d.ts +0 -134
- package/types/base/symbols.d.ts +0 -11
- package/types/base/types.d.ts +0 -68
- package/types/base/utils.d.ts +0 -4
- package/types/base.d.ts +0 -1
- package/types/capacitor.base.config.d.ts +0 -3
- package/types/client/capacitor.d.ts +0 -233
- package/types/client/clientRuntime.d.ts +0 -63
- package/types/client/cookie.d.ts +0 -33
- package/types/client/createFont.d.ts +0 -6
- package/types/client/csrTypes.d.ts +0 -262
- package/types/client/decorators.d.ts +0 -7
- package/types/client/device.d.ts +0 -41
- package/types/client/fetch.d.ts +0 -1
- package/types/client/index.d.ts +0 -14
- package/types/client/locale.d.ts +0 -5
- package/types/client/makePageProto.d.ts +0 -17002
- package/types/client/router.d.ts +0 -66
- package/types/client/rscNavigation.d.ts +0 -19
- package/types/client/storage.d.ts +0 -5
- package/types/client/translator.d.ts +0 -18
- package/types/client/types.d.ts +0 -145
- package/types/client/useClient.d.ts +0 -1
- package/types/client.d.ts +0 -1
- package/types/common/Logger.d.ts +0 -41
- package/types/common/applyMixins.d.ts +0 -3
- package/types/common/capitalize.d.ts +0 -2
- package/types/common/deepObjectify.d.ts +0 -4
- package/types/common/fileUpload.d.ts +0 -28
- package/types/common/formatNumber.d.ts +0 -1
- package/types/common/formatPhone.d.ts +0 -2
- package/types/common/getAllPropertyDescriptors.d.ts +0 -5
- package/types/common/hmrPhase.d.ts +0 -6
- package/types/common/httpClient.d.ts +0 -20
- package/types/common/index.d.ts +0 -29
- package/types/common/isDayjs.d.ts +0 -2
- package/types/common/isEmail.d.ts +0 -2
- package/types/common/isPhoneNumber.d.ts +0 -2
- package/types/common/isQueryEqual.d.ts +0 -1
- package/types/common/isValidDate.d.ts +0 -2
- package/types/common/jwtDecode.d.ts +0 -2
- package/types/common/localeConfig.d.ts +0 -11
- package/types/common/lowerlize.d.ts +0 -2
- package/types/common/mergeVersion.d.ts +0 -10
- package/types/common/objectify.d.ts +0 -1
- package/types/common/pathGet.d.ts +0 -1
- package/types/common/pathSet.d.ts +0 -3
- package/types/common/randomPick.d.ts +0 -1
- package/types/common/randomPicks.d.ts +0 -1
- package/types/common/routeConvention.d.ts +0 -35
- package/types/common/sleep.d.ts +0 -2
- package/types/common/splitVersion.d.ts +0 -11
- package/types/common/subRoute.d.ts +0 -7
- package/types/common/types.d.ts +0 -14
- package/types/common.d.ts +0 -1
- package/types/constant/constantRegistry.d.ts +0 -89
- package/types/constant/crystalize.d.ts +0 -4
- package/types/constant/deserialize.d.ts +0 -7
- package/types/constant/fieldInfo.d.ts +0 -153
- package/types/constant/getDefault.d.ts +0 -3
- package/types/constant/immerify.d.ts +0 -2
- package/types/constant/index.d.ts +0 -10
- package/types/constant/purify.d.ts +0 -12
- package/types/constant/serialize.d.ts +0 -11
- package/types/constant/types.d.ts +0 -77
- package/types/constant/via.d.ts +0 -52
- package/types/constant.d.ts +0 -1
- package/types/dictionary/base.dictionary.d.ts +0 -1
- package/types/dictionary/dictInfo.d.ts +0 -206
- package/types/dictionary/dictionary.d.ts +0 -11
- package/types/dictionary/index.d.ts +0 -4
- package/types/dictionary/locale.d.ts +0 -128
- package/types/dictionary/trans.d.ts +0 -82
- package/types/dictionary.d.ts +0 -1
- package/types/document/by.d.ts +0 -20
- package/types/document/dataLoader.d.ts +0 -36
- package/types/document/database.d.ts +0 -96
- package/types/document/databaseRegistry.d.ts +0 -36
- package/types/document/documentQuery.d.ts +0 -105
- package/types/document/documentSchema.d.ts +0 -33
- package/types/document/filterMeta.d.ts +0 -84
- package/types/document/index.d.ts +0 -11
- package/types/document/into.d.ts +0 -65
- package/types/document/loaderInfo.d.ts +0 -35
- package/types/document/schema.d.ts +0 -5
- package/types/document/types.d.ts +0 -36
- package/types/document.d.ts +0 -1
- package/types/fetch/client/fetchClient.d.ts +0 -78
- package/types/fetch/client/httpClient.d.ts +0 -39
- package/types/fetch/client/index.d.ts +0 -3
- package/types/fetch/client/wsClient.d.ts +0 -37
- package/types/fetch/client.d.ts +0 -1
- package/types/fetch/fetchType/appliedReturn.type.d.ts +0 -67
- package/types/fetch/fetchType/buildFetch.type.d.ts +0 -11
- package/types/fetch/fetchType/clientSignal.type.d.ts +0 -16
- package/types/fetch/fetchType/endpointFetch.type.d.ts +0 -29
- package/types/fetch/fetchType/index.d.ts +0 -5
- package/types/fetch/fetchType/sliceFetch.type.d.ts +0 -76
- package/types/fetch/fetchType.d.ts +0 -1
- package/types/fetch/index.d.ts +0 -4
- package/types/fetch/requestStorage.d.ts +0 -29
- package/types/fetch/serializer/fetch.serializer.d.ts +0 -14
- package/types/fetch/serializer/index.d.ts +0 -1
- package/types/fetch/serializer.d.ts +0 -1
- package/types/fetch/types.d.ts +0 -19
- package/types/fetch.d.ts +0 -1
- package/types/index.d.ts +0 -213
- package/types/server/akanApp.d.ts +0 -17
- package/types/server/akanAppHeaders.d.ts +0 -1
- package/types/server/akanLib.d.ts +0 -33
- package/types/server/akanOption.d.ts +0 -15
- package/types/server/akanServer.d.ts +0 -47
- package/types/server/artifact/builderRpc.d.ts +0 -42
- package/types/server/artifact/index.d.ts +0 -6
- package/types/server/artifact/ipcTypes.d.ts +0 -73
- package/types/server/artifact/manifestTypes.d.ts +0 -16
- package/types/server/artifact/routeClientCache.d.ts +0 -45
- package/types/server/artifact/routeSeedIndexStore.d.ts +0 -43
- package/types/server/artifact/routesManifestStore.d.ts +0 -16
- package/types/server/artifact.d.ts +0 -1
- package/types/server/decorators.d.ts +0 -6
- package/types/server/di/diLifecycle.d.ts +0 -45
- package/types/server/di/index.d.ts +0 -4
- package/types/server/di/predefinedAdaptor.d.ts +0 -33
- package/types/server/di/resolveAdaptorHierarchy.d.ts +0 -21
- package/types/server/di/resolveHierarchy.d.ts +0 -11
- package/types/server/di/resolveServiceHierarchy.d.ts +0 -13
- package/types/server/di/utils.d.ts +0 -14
- package/types/server/di.d.ts +0 -1
- package/types/server/hmr/changeBatch.d.ts +0 -13
- package/types/server/hmr/clientScript.d.ts +0 -1
- package/types/server/hmr/devHmrController.d.ts +0 -24
- package/types/server/hmr/index.d.ts +0 -4
- package/types/server/hmr/wsHub.d.ts +0 -45
- package/types/server/hmr.d.ts +0 -1
- package/types/server/imageOptimizer.d.ts +0 -12
- package/types/server/imageOptimizerError.d.ts +0 -4
- package/types/server/index.d.ts +0 -14
- package/types/server/lifecycle/shutdownManager.d.ts +0 -13
- package/types/server/logging/rotatingLogWriter.d.ts +0 -20
- package/types/server/processMetricsCollector.d.ts +0 -10
- package/types/server/proxy/akanResponse.d.ts +0 -7
- package/types/server/proxy/bunRequestFields.d.ts +0 -1
- package/types/server/proxy/hostBasePathWebProxy.d.ts +0 -6
- package/types/server/proxy/index.d.ts +0 -6
- package/types/server/proxy/localeWebProxy.d.ts +0 -5
- package/types/server/proxy/types.d.ts +0 -37
- package/types/server/proxy/webProxyRunner.d.ts +0 -7
- package/types/server/proxy.d.ts +0 -1
- package/types/server/resolver/database.resolver.d.ts +0 -6
- package/types/server/resolver/index.d.ts +0 -3
- package/types/server/resolver/service.resolver.d.ts +0 -7
- package/types/server/resolver/signal.resolver.d.ts +0 -29
- package/types/server/resolver.d.ts +0 -1
- package/types/server/robots.d.ts +0 -1
- package/types/server/routeElementComposer.d.ts +0 -41
- package/types/server/routeTreeBuilder.d.ts +0 -28
- package/types/server/routing/apiRouter.d.ts +0 -61
- package/types/server/rscClient.d.ts +0 -15
- package/types/server/rscWorker.d.ts +0 -3
- package/types/server/rscWorkerHost.d.ts +0 -83
- package/types/server/sitemap.d.ts +0 -13
- package/types/server/ssrFromRscRenderer.d.ts +0 -6
- package/types/server/ssrTypes.d.ts +0 -47
- package/types/server/systemPages.d.ts +0 -27
- package/types/server/types/react-server-dom-webpack.d.ts +0 -91
- package/types/server/types.d.ts +0 -67
- package/types/server/vendor/akanjs-base.d.ts +0 -1
- package/types/server/vendor/akanjs-common.d.ts +0 -1
- package/types/server/vendor/akanjs-constant.d.ts +0 -1
- package/types/server/vendor/akanjs-store.d.ts +0 -1
- package/types/server/vendor/react-dom-client.d.ts +0 -3
- package/types/server/vendor/react-dom.d.ts +0 -3
- package/types/server/vendor/react-jsx-dev-runtime.d.ts +0 -3
- package/types/server/vendor/react-jsx-runtime.d.ts +0 -3
- package/types/server/vendor/react-refresh-runtime.d.ts +0 -3
- package/types/server/vendor/react-server-dom-webpack-client-browser.d.ts +0 -3
- package/types/server/vendor/react.d.ts +0 -11
- package/types/server/vendor/scheduler.d.ts +0 -3
- package/types/server/webRouter.d.ts +0 -44
- package/types/server.d.ts +0 -1
- package/types/service/adapt.d.ts +0 -15
- package/types/service/base.service.d.ts +0 -18
- package/types/service/index.d.ts +0 -10
- package/types/service/injectInfo.d.ts +0 -102
- package/types/service/ipcTypes.d.ts +0 -194
- package/types/service/predefinedAdaptor/cache.adaptor.d.ts +0 -46
- package/types/service/predefinedAdaptor/compress.adaptor.d.ts +0 -22
- package/types/service/predefinedAdaptor/database.adaptor.d.ts +0 -329
- package/types/service/predefinedAdaptor/index.d.ts +0 -13
- package/types/service/predefinedAdaptor/logging.adaptor.d.ts +0 -20
- package/types/service/predefinedAdaptor/queue.adaptor.d.ts +0 -22
- package/types/service/predefinedAdaptor/role.adaptor.d.ts +0 -17
- package/types/service/predefinedAdaptor/schedule.adaptor.d.ts +0 -60
- package/types/service/predefinedAdaptor/solidCache.adaptor.d.ts +0 -25
- package/types/service/predefinedAdaptor/solidPubsub.adaptor.d.ts +0 -20
- package/types/service/predefinedAdaptor/solidQueue.adaptor.d.ts +0 -19
- package/types/service/predefinedAdaptor/solidSqlite.d.ts +0 -24
- package/types/service/predefinedAdaptor/sqlitePath.d.ts +0 -9
- package/types/service/predefinedAdaptor/storage.adaptor.d.ts +0 -80
- package/types/service/predefinedAdaptor/websocket.adaptor.d.ts +0 -49
- package/types/service/predefinedAdaptor.d.ts +0 -1
- package/types/service/serve.d.ts +0 -31
- package/types/service/serviceModule.d.ts +0 -50
- package/types/service/serviceRegistry.d.ts +0 -9
- package/types/service/types.d.ts +0 -55
- package/types/service.d.ts +0 -1
- package/types/signal/base.signal.d.ts +0 -41
- package/types/signal/endpoint.d.ts +0 -28
- package/types/signal/endpointInfo.d.ts +0 -77
- package/types/signal/exception.d.ts +0 -54786
- package/types/signal/guard.d.ts +0 -10
- package/types/signal/guards.d.ts +0 -10
- package/types/signal/index.d.ts +0 -19
- package/types/signal/intercept.d.ts +0 -17
- package/types/signal/internal.d.ts +0 -18
- package/types/signal/internalArg.d.ts +0 -31
- package/types/signal/internalInfo.d.ts +0 -45
- package/types/signal/middleware.d.ts +0 -51
- package/types/signal/serializer/fetch.serializer.d.ts +0 -14
- package/types/signal/serializer/index.d.ts +0 -1
- package/types/signal/serializer.d.ts +0 -1
- package/types/signal/serverSignal.d.ts +0 -36
- package/types/signal/signalContext.d.ts +0 -96
- package/types/signal/signalRegistry.d.ts +0 -49
- package/types/signal/slice.d.ts +0 -42
- package/types/signal/sliceInfo.d.ts +0 -51
- package/types/signal/trace.d.ts +0 -97
- package/types/signal/types.d.ts +0 -142
- package/types/signal.d.ts +0 -1
- package/types/store/action.d.ts +0 -145
- package/types/store/baseSt.d.ts +0 -412
- package/types/store/hooks.d.ts +0 -1
- package/types/store/index.d.ts +0 -8
- package/types/store/rootStore.d.ts +0 -22
- package/types/store/state.d.ts +0 -91
- package/types/store/stateBuilder.d.ts +0 -141
- package/types/store/stateInfo.d.ts +0 -23
- package/types/store/store.d.ts +0 -36
- package/types/store/storeInstance.d.ts +0 -38
- package/types/store/storeRegistry.d.ts +0 -13
- package/types/store/types.d.ts +0 -42
- package/types/store/withSelector.d.ts +0 -42
- package/types/store.d.ts +0 -1
- package/types/test/index.d.ts +0 -4
- package/types/test/playwright.config.base.d.ts +0 -9
- package/types/test/playwright.pageAgent.d.ts +0 -12
- package/types/test/sample.d.ts +0 -15
- package/types/test/sampleOf.d.ts +0 -5
- package/types/test/signalTest.preload.d.ts +0 -1
- package/types/test/signalTestRuntime.d.ts +0 -29
- package/types/test/testServer.d.ts +0 -26
- package/types/test.d.ts +0 -1
- package/types/ui/BottomSheet.d.ts +0 -13
- package/types/ui/Button.d.ts +0 -11
- package/types/ui/ClientSide.d.ts +0 -8
- package/types/ui/Clipboard.d.ts +0 -7
- package/types/ui/Constant/Doc.d.ts +0 -29
- package/types/ui/Constant/Mermaid.d.ts +0 -8
- package/types/ui/Constant/index.d.ts +0 -6
- package/types/ui/Constant/schemaDoc.d.ts +0 -84
- package/types/ui/Constant.d.ts +0 -1
- package/types/ui/Copy.d.ts +0 -10
- package/types/ui/CsrImage.d.ts +0 -18
- package/types/ui/Data/CardList.d.ts +0 -36
- package/types/ui/Data/Dashboard.d.ts +0 -11
- package/types/ui/Data/Insight.d.ts +0 -9
- package/types/ui/Data/Item.d.ts +0 -75
- package/types/ui/Data/ListContainer.d.ts +0 -49
- package/types/ui/Data/Pagination.d.ts +0 -9
- package/types/ui/Data/QueryMaker.d.ts +0 -8
- package/types/ui/Data/TableList.d.ts +0 -26
- package/types/ui/Data/index.d.ts +0 -9
- package/types/ui/Data/index_.d.ts +0 -8
- package/types/ui/Data.d.ts +0 -1
- package/types/ui/DatePicker.d.ts +0 -36
- package/types/ui/Dialog/Action.d.ts +0 -5
- package/types/ui/Dialog/Close.d.ts +0 -6
- package/types/ui/Dialog/Content.d.ts +0 -6
- package/types/ui/Dialog/Modal.d.ts +0 -9
- package/types/ui/Dialog/Provider.d.ts +0 -11
- package/types/ui/Dialog/Title.d.ts +0 -5
- package/types/ui/Dialog/Trigger.d.ts +0 -6
- package/types/ui/Dialog/context.d.ts +0 -10
- package/types/ui/Dialog/index.d.ts +0 -9
- package/types/ui/Dialog.d.ts +0 -1
- package/types/ui/DragAction.d.ts +0 -24
- package/types/ui/DraggableList.d.ts +0 -31
- package/types/ui/Dropdown.d.ts +0 -14
- package/types/ui/Empty.d.ts +0 -12
- package/types/ui/Field.d.ts +0 -411
- package/types/ui/FontFace.d.ts +0 -6
- package/types/ui/Image.d.ts +0 -49
- package/types/ui/InfiniteScroll.d.ts +0 -10
- package/types/ui/Input.d.ts +0 -95
- package/types/ui/KeyboardAvoiding.d.ts +0 -8
- package/types/ui/Layout/BottomAction.d.ts +0 -6
- package/types/ui/Layout/BottomInset.d.ts +0 -7
- package/types/ui/Layout/BottomTab.d.ts +0 -14
- package/types/ui/Layout/Header.d.ts +0 -8
- package/types/ui/Layout/LeftSider.d.ts +0 -9
- package/types/ui/Layout/Navbar.d.ts +0 -11
- package/types/ui/Layout/RightSider.d.ts +0 -10
- package/types/ui/Layout/Sider.d.ts +0 -7
- package/types/ui/Layout/Template.d.ts +0 -7
- package/types/ui/Layout/TopLeftAction.d.ts +0 -6
- package/types/ui/Layout/Unit.d.ts +0 -9
- package/types/ui/Layout/View.d.ts +0 -8
- package/types/ui/Layout/Zone.d.ts +0 -6
- package/types/ui/Layout/index.d.ts +0 -14
- package/types/ui/Layout.d.ts +0 -1
- package/types/ui/Link/Back.d.ts +0 -7
- package/types/ui/Link/Close.d.ts +0 -7
- package/types/ui/Link/CsrLink.d.ts +0 -2
- package/types/ui/Link/Lang.d.ts +0 -8
- package/types/ui/Link/SsrLink.d.ts +0 -2
- package/types/ui/Link/index.d.ts +0 -10
- package/types/ui/Link/types.d.ts +0 -42
- package/types/ui/Link.d.ts +0 -1
- package/types/ui/Load/Edit.d.ts +0 -4
- package/types/ui/Load/Edit_Client.d.ts +0 -27
- package/types/ui/Load/Page.d.ts +0 -15
- package/types/ui/Load/PageCSR.d.ts +0 -3
- package/types/ui/Load/Pagination.d.ts +0 -8
- package/types/ui/Load/Units.d.ts +0 -30
- package/types/ui/Load/View.d.ts +0 -22
- package/types/ui/Load/index.d.ts +0 -8
- package/types/ui/Load/index_.d.ts +0 -3
- package/types/ui/Load.d.ts +0 -1
- package/types/ui/Loading/Area.d.ts +0 -1
- package/types/ui/Loading/Button.d.ts +0 -7
- package/types/ui/Loading/Input.d.ts +0 -7
- package/types/ui/Loading/ProgressBar.d.ts +0 -6
- package/types/ui/Loading/Skeleton.d.ts +0 -7
- package/types/ui/Loading/Spin.d.ts +0 -7
- package/types/ui/Loading/index.d.ts +0 -8
- package/types/ui/Loading.d.ts +0 -1
- package/types/ui/Menu.d.ts +0 -26
- package/types/ui/Modal.d.ts +0 -19
- package/types/ui/Model/AdminPanel.d.ts +0 -31
- package/types/ui/Model/Edit.d.ts +0 -16
- package/types/ui/Model/EditModal.d.ts +0 -52
- package/types/ui/Model/EditWrapper.d.ts +0 -13
- package/types/ui/Model/LoadInit.d.ts +0 -10
- package/types/ui/Model/New.d.ts +0 -16
- package/types/ui/Model/NewWrapper.d.ts +0 -13
- package/types/ui/Model/NewWrapper_Client.d.ts +0 -13
- package/types/ui/Model/Remove.d.ts +0 -13
- package/types/ui/Model/RemoveWrapper.d.ts +0 -12
- package/types/ui/Model/SureToRemove.d.ts +0 -11
- package/types/ui/Model/View.d.ts +0 -19
- package/types/ui/Model/ViewEditModal.d.ts +0 -12
- package/types/ui/Model/ViewModal.d.ts +0 -14
- package/types/ui/Model/ViewWrapper.d.ts +0 -12
- package/types/ui/Model/index.d.ts +0 -16
- package/types/ui/Model/index_.d.ts +0 -14
- package/types/ui/Model.d.ts +0 -1
- package/types/ui/More.d.ts +0 -12
- package/types/ui/ObjectId.d.ts +0 -5
- package/types/ui/Pagination.d.ts +0 -20
- package/types/ui/Popconfirm.d.ts +0 -28
- package/types/ui/Portal.d.ts +0 -6
- package/types/ui/Radio.d.ts +0 -19
- package/types/ui/RecentTime.d.ts +0 -12
- package/types/ui/Refresh.d.ts +0 -7
- package/types/ui/ScreenNavigator.d.ts +0 -18
- package/types/ui/Select.d.ts +0 -43
- package/types/ui/Signal/Arg.d.ts +0 -78
- package/types/ui/Signal/Doc.d.ts +0 -33
- package/types/ui/Signal/Listener.d.ts +0 -9
- package/types/ui/Signal/Message.d.ts +0 -23
- package/types/ui/Signal/Object.d.ts +0 -20
- package/types/ui/Signal/PubSub.d.ts +0 -24
- package/types/ui/Signal/Request.d.ts +0 -8
- package/types/ui/Signal/Response.d.ts +0 -14
- package/types/ui/Signal/RestApi.d.ts +0 -40
- package/types/ui/Signal/WebSocket.d.ts +0 -11
- package/types/ui/Signal/index.d.ts +0 -18
- package/types/ui/Signal/makeExample.d.ts +0 -4
- package/types/ui/Signal/style.d.ts +0 -15
- package/types/ui/Signal.d.ts +0 -1
- package/types/ui/System/CSR.d.ts +0 -32
- package/types/ui/System/Client.d.ts +0 -47
- package/types/ui/System/Common.d.ts +0 -47
- package/types/ui/System/DevModeToggle.d.ts +0 -1
- package/types/ui/System/Gtag.d.ts +0 -4
- package/types/ui/System/Messages.d.ts +0 -1
- package/types/ui/System/Reconnect.d.ts +0 -1
- package/types/ui/System/Root.d.ts +0 -6
- package/types/ui/System/SSR.d.ts +0 -24
- package/types/ui/System/SelectLanguage.d.ts +0 -5
- package/types/ui/System/ThemeToggle.d.ts +0 -4
- package/types/ui/System/index.d.ts +0 -12
- package/types/ui/System.d.ts +0 -1
- package/types/ui/Tab/Menu.d.ts +0 -12
- package/types/ui/Tab/Menus.d.ts +0 -6
- package/types/ui/Tab/Panel.d.ts +0 -8
- package/types/ui/Tab/Provider.d.ts +0 -10
- package/types/ui/Tab/context.d.ts +0 -9
- package/types/ui/Tab/index.d.ts +0 -7
- package/types/ui/Tab.d.ts +0 -1
- package/types/ui/Table.d.ts +0 -41
- package/types/ui/ToggleSelect.d.ts +0 -33
- package/types/ui/Unauthorized.d.ts +0 -9
- package/types/ui/animated.d.ts +0 -5
- package/types/ui/fontCss.d.ts +0 -11
- package/types/ui/index.d.ts +0 -44
- package/types/ui.d.ts +0 -1
- package/types/webkit/bootCsr.d.ts +0 -16
- package/types/webkit/createRobotPage.d.ts +0 -15
- package/types/webkit/createSitemapPage.d.ts +0 -4
- package/types/webkit/index.d.ts +0 -17
- package/types/webkit/lazy.d.ts +0 -11
- package/types/webkit/types.d.ts +0 -7
- package/types/webkit/useCamera.d.ts +0 -19
- package/types/webkit/useCodepush.d.ts +0 -16
- package/types/webkit/useContact.d.ts +0 -11
- package/types/webkit/useCsrValues.d.ts +0 -30
- package/types/webkit/useDebounce.d.ts +0 -2
- package/types/webkit/useFetch.d.ts +0 -18
- package/types/webkit/useGeoLocation.d.ts +0 -8
- package/types/webkit/useHistory.d.ts +0 -23
- package/types/webkit/useInterval.d.ts +0 -2
- package/types/webkit/useLocation.d.ts +0 -8
- package/types/webkit/usePurchase.d.ts +0 -19
- package/types/webkit/usePushNoti.d.ts +0 -7
- package/types/webkit/useThrottle.d.ts +0 -2
- package/types/webkit.d.ts +0 -1
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import { renderToReadableStream } from "react-dom/server.browser";
|
|
3
|
+
import { RouteElementComposer } from "./routeElementComposer";
|
|
4
|
+
import { RouteTreeBuilder } from "./routeTreeBuilder";
|
|
5
|
+
|
|
6
|
+
async function renderToText(node: ReactNode): Promise<string> {
|
|
7
|
+
return new Response(await renderToReadableStream(node)).text();
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
describe("RouteTreeBuilder implicit locale", () => {
|
|
11
|
+
test("matches locale-prefixed routes while keeping special routes at root", () => {
|
|
12
|
+
const routes = new RouteTreeBuilder({
|
|
13
|
+
"./__root_layout.tsx": async () => ({ default: ({ children }: { children: ReactNode }) => children }),
|
|
14
|
+
"./foo.tsx": async () => ({ default: () => null }),
|
|
15
|
+
"./robots.txt.tsx": async () => ({ default: () => null }),
|
|
16
|
+
}).build();
|
|
17
|
+
|
|
18
|
+
const matched = RouteTreeBuilder.match("/ko/foo", routes);
|
|
19
|
+
expect(matched?.params).toEqual({ lang: "ko" });
|
|
20
|
+
expect(matched?.pathRoute.path).toBe("/:lang/foo");
|
|
21
|
+
expect(matched?.pathRoute.renderRootLayouts).toHaveLength(1);
|
|
22
|
+
|
|
23
|
+
const robots = RouteTreeBuilder.match("/robots.txt", routes);
|
|
24
|
+
expect(robots?.params).toEqual({});
|
|
25
|
+
expect(robots?.pathRoute.isSpecialRoute).toBe(true);
|
|
26
|
+
expect(robots?.pathRoute.renderRootLayouts).toHaveLength(0);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("uses the nearest route head without merging parents", async () => {
|
|
30
|
+
const prevBasePaths = process.env.AKAN_PUBLIC_BASE_PATHS;
|
|
31
|
+
process.env.AKAN_PUBLIC_BASE_PATHS = "foo";
|
|
32
|
+
try {
|
|
33
|
+
const routes = new RouteTreeBuilder({
|
|
34
|
+
"./__root_layout.tsx": async () => ({
|
|
35
|
+
default: ({ children }: { children: ReactNode }) => children,
|
|
36
|
+
head: "root",
|
|
37
|
+
}),
|
|
38
|
+
"./foo/__root_layout.tsx": async () => ({
|
|
39
|
+
default: ({ children }: { children: ReactNode }) => children,
|
|
40
|
+
head: "foo-root",
|
|
41
|
+
}),
|
|
42
|
+
"./foo/bar.tsx": async () => ({ default: () => null }),
|
|
43
|
+
"./foo/baz.tsx": async () => ({ default: () => null, head: "baz-page" }),
|
|
44
|
+
}).build();
|
|
45
|
+
|
|
46
|
+
const bar = RouteTreeBuilder.match("/ko/foo/bar", routes);
|
|
47
|
+
const baz = RouteTreeBuilder.match("/ko/foo/baz", routes);
|
|
48
|
+
expect(
|
|
49
|
+
bar &&
|
|
50
|
+
(await RouteElementComposer.resolveHead({ pathRoute: bar.pathRoute, params: bar.params, searchParams: {} })),
|
|
51
|
+
).toBe("foo-root");
|
|
52
|
+
expect(
|
|
53
|
+
baz &&
|
|
54
|
+
(await RouteElementComposer.resolveHead({ pathRoute: baz.pathRoute, params: baz.params, searchParams: {} })),
|
|
55
|
+
).toBe("baz-page");
|
|
56
|
+
} finally {
|
|
57
|
+
process.env.AKAN_PUBLIC_BASE_PATHS = prevBasePaths;
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test("supports route groups, repeated search params, and cached lazy modules", async () => {
|
|
62
|
+
let loadCount = 0;
|
|
63
|
+
const routes = new RouteTreeBuilder({
|
|
64
|
+
"./__root_layout.tsx": async () => ({ default: ({ children }: { children: ReactNode }) => children }),
|
|
65
|
+
"./(marketing)/about.tsx": async () => {
|
|
66
|
+
loadCount += 1;
|
|
67
|
+
return { default: () => null, head: "about" };
|
|
68
|
+
},
|
|
69
|
+
}).build();
|
|
70
|
+
const matched = RouteTreeBuilder.match("/ko/about", routes);
|
|
71
|
+
|
|
72
|
+
expect(matched?.pathRoute.path).toBe("/:lang/about");
|
|
73
|
+
expect(RouteTreeBuilder.parseSearchParams("?tag=a&tag=b&sort=latest")).toEqual({
|
|
74
|
+
tag: ["a", "b"],
|
|
75
|
+
sort: "latest",
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
expect(
|
|
79
|
+
matched &&
|
|
80
|
+
(await RouteElementComposer.resolveHead({
|
|
81
|
+
pathRoute: matched.pathRoute,
|
|
82
|
+
params: matched.params,
|
|
83
|
+
searchParams: {},
|
|
84
|
+
})),
|
|
85
|
+
).toBe("about");
|
|
86
|
+
expect(
|
|
87
|
+
matched &&
|
|
88
|
+
(await RouteElementComposer.resolveHead({
|
|
89
|
+
pathRoute: matched.pathRoute,
|
|
90
|
+
params: matched.params,
|
|
91
|
+
searchParams: {},
|
|
92
|
+
})),
|
|
93
|
+
).toBe("about");
|
|
94
|
+
expect(loadCount).toBe(1);
|
|
95
|
+
expect(RouteTreeBuilder.getCacheStats()).toMatchObject({
|
|
96
|
+
moduleCount: 2,
|
|
97
|
+
loadedModuleCount: 1,
|
|
98
|
+
cacheHits: 1,
|
|
99
|
+
cacheMisses: 1,
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test("rejects duplicate route patterns and unsupported page exports", () => {
|
|
104
|
+
expect(() =>
|
|
105
|
+
new RouteTreeBuilder({
|
|
106
|
+
"./users/[id].tsx": async () => ({ default: () => null }),
|
|
107
|
+
"./users/:id.tsx": async () => ({ default: () => null }),
|
|
108
|
+
}).build(),
|
|
109
|
+
).toThrow();
|
|
110
|
+
|
|
111
|
+
const routes = new RouteTreeBuilder({
|
|
112
|
+
"./bad.tsx": async () => ({ default: () => null, loader: () => null }) as never,
|
|
113
|
+
}).build();
|
|
114
|
+
const matched = RouteTreeBuilder.match("/ko/bad", routes);
|
|
115
|
+
|
|
116
|
+
expect(
|
|
117
|
+
matched &&
|
|
118
|
+
RouteElementComposer.resolveHead({ pathRoute: matched.pathRoute, params: matched.params, searchParams: {} }),
|
|
119
|
+
).rejects.toThrow('[route-convention] unsupported export "loader"');
|
|
120
|
+
|
|
121
|
+
const routesWithBadFallback = new RouteTreeBuilder({
|
|
122
|
+
"./bad-fallback.tsx": async () => ({ default: () => null, NotFound: () => null }) as never,
|
|
123
|
+
}).build();
|
|
124
|
+
const badFallback = RouteTreeBuilder.match("/ko/bad-fallback", routesWithBadFallback);
|
|
125
|
+
expect(
|
|
126
|
+
badFallback &&
|
|
127
|
+
RouteElementComposer.resolveHead({
|
|
128
|
+
pathRoute: badFallback.pathRoute,
|
|
129
|
+
params: badFallback.params,
|
|
130
|
+
searchParams: {},
|
|
131
|
+
}),
|
|
132
|
+
).rejects.toThrow('[route-convention] unsupported export "NotFound"');
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test("composes nearest layout NotFound and Error fallbacks", async () => {
|
|
136
|
+
const builder = new RouteTreeBuilder({
|
|
137
|
+
"./__root_layout.tsx": async () => ({
|
|
138
|
+
default: ({ children }: { children: ReactNode }) => <main>root:{children}</main>,
|
|
139
|
+
NotFound: ({ pathname }: { pathname: string }) => <p>root missing {pathname}</p>,
|
|
140
|
+
}),
|
|
141
|
+
"./docs/_layout.tsx": async () => ({
|
|
142
|
+
default: ({ children }: { children: ReactNode }) => <section>docs:{children}</section>,
|
|
143
|
+
NotFound: ({ pathname, params }: { pathname: string; params: Record<string, string> }) => (
|
|
144
|
+
<p>
|
|
145
|
+
docs missing {params.lang}:{pathname}
|
|
146
|
+
</p>
|
|
147
|
+
),
|
|
148
|
+
Error: ({ error }: { error?: unknown }) => (
|
|
149
|
+
<p>docs error {error instanceof Error ? error.message : "unknown"}</p>
|
|
150
|
+
),
|
|
151
|
+
}),
|
|
152
|
+
"./docs/guide.tsx": async () => ({ default: () => <article>guide</article> }),
|
|
153
|
+
});
|
|
154
|
+
const routes = builder.build();
|
|
155
|
+
const matched = RouteTreeBuilder.match("/ko/docs/guide", routes);
|
|
156
|
+
if (!matched) throw new Error("route did not match");
|
|
157
|
+
|
|
158
|
+
const notFound = await RouteElementComposer.composeFallback({
|
|
159
|
+
kind: "not-found",
|
|
160
|
+
route: matched.pathRoute,
|
|
161
|
+
params: matched.params,
|
|
162
|
+
searchParams: {},
|
|
163
|
+
pathname: "/ko/docs/guide",
|
|
164
|
+
});
|
|
165
|
+
const error = await RouteElementComposer.composeFallback({
|
|
166
|
+
kind: "error",
|
|
167
|
+
route: matched.pathRoute,
|
|
168
|
+
params: matched.params,
|
|
169
|
+
searchParams: {},
|
|
170
|
+
pathname: "/ko/docs/guide",
|
|
171
|
+
error: new Error("boom"),
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
const notFoundHtml = await renderToText(notFound);
|
|
175
|
+
const errorHtml = await renderToText(error);
|
|
176
|
+
expect(notFoundHtml).toContain("root:");
|
|
177
|
+
expect(notFoundHtml).toContain("docs:");
|
|
178
|
+
expect(notFoundHtml).toContain("docs missing");
|
|
179
|
+
expect(notFoundHtml).toContain("/ko/docs/guide");
|
|
180
|
+
expect(errorHtml).toContain("docs error");
|
|
181
|
+
expect(errorHtml).toContain("boom");
|
|
182
|
+
|
|
183
|
+
const unmatched = RouteTreeBuilder.matchFallback("/ko/docs/missing/path", builder.getFallbackRoutes());
|
|
184
|
+
expect(unmatched?.fallbackRoute.path).toBe("/:lang/docs");
|
|
185
|
+
const unmatchedNotFound =
|
|
186
|
+
unmatched &&
|
|
187
|
+
(await RouteElementComposer.composeFallback({
|
|
188
|
+
kind: "not-found",
|
|
189
|
+
route: unmatched.fallbackRoute,
|
|
190
|
+
params: unmatched.params,
|
|
191
|
+
searchParams: {},
|
|
192
|
+
pathname: "/ko/docs/missing/path",
|
|
193
|
+
}));
|
|
194
|
+
const unmatchedHtml = await renderToText(unmatchedNotFound);
|
|
195
|
+
expect(unmatchedHtml).toContain("docs missing");
|
|
196
|
+
expect(unmatchedHtml).toContain("/ko/docs/missing/path");
|
|
197
|
+
});
|
|
198
|
+
});
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { getDefaultInjectRegistry } from "akanjs/service";
|
|
2
|
+
import { AkanResponse, WebProxyRunner } from "../proxy";
|
|
3
|
+
import type { HttpRoutes, WebsocketRoutes } from "../types";
|
|
4
|
+
|
|
5
|
+
describe("ApiRouter.buildRoutes", () => {
|
|
6
|
+
test("keeps the global prefix by default", async () => {
|
|
7
|
+
process.env.AKAN_PUBLIC_APP_NAME = "test";
|
|
8
|
+
const { ApiRouter } = await import("./apiRouter");
|
|
9
|
+
const routes = ApiRouter.buildRoutes({
|
|
10
|
+
prefix: "/api",
|
|
11
|
+
websocketPrefix: "/ws",
|
|
12
|
+
routes: { "/admin/ping": () => new Response("ok") } as HttpRoutes,
|
|
13
|
+
renderEnvRoutes: {},
|
|
14
|
+
upgradeAppWs: () => false,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
expect(Object.keys(routes)).toContain("/api/admin/ping");
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test("allows selected endpoints to skip the global prefix", async () => {
|
|
21
|
+
process.env.AKAN_PUBLIC_APP_NAME = "test";
|
|
22
|
+
const { ApiRouter } = await import("./apiRouter");
|
|
23
|
+
const routes = ApiRouter.buildRoutes({
|
|
24
|
+
prefix: "/api",
|
|
25
|
+
websocketPrefix: "/ws",
|
|
26
|
+
routes: { "/sitemap.xml": () => new Response("ok") } as HttpRoutes,
|
|
27
|
+
routeOptions: { "/sitemap.xml": { globalPrefix: false } },
|
|
28
|
+
renderEnvRoutes: { "/*": () => new Response("fallback") } as HttpRoutes,
|
|
29
|
+
upgradeAppWs: () => false,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
expect(Object.keys(routes)).toContain("/sitemap.xml");
|
|
33
|
+
expect(Object.keys(routes)).not.toContain("/api/sitemap.xml");
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test("wraps only render routes with the web proxy runner", async () => {
|
|
37
|
+
process.env.AKAN_PUBLIC_APP_NAME = "test";
|
|
38
|
+
const { ApiRouter } = await import("./apiRouter");
|
|
39
|
+
class RewriteRenderProxy {
|
|
40
|
+
static refName = "rewriteRenderProxy";
|
|
41
|
+
use() {
|
|
42
|
+
return AkanResponse.rewrite("http://localhost/rendered", { request: { headers: { "x-proxy": "1" } } });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const routes = ApiRouter.buildRoutes({
|
|
46
|
+
prefix: "/api",
|
|
47
|
+
websocketPrefix: "/ws",
|
|
48
|
+
routes: { "/ping": () => Response.json("api") } as HttpRoutes,
|
|
49
|
+
renderEnvRoutes: {
|
|
50
|
+
"/*": (req) => Response.json({ url: req.url, proxy: req.headers.get("x-proxy") }),
|
|
51
|
+
} as HttpRoutes,
|
|
52
|
+
upgradeAppWs: () => false,
|
|
53
|
+
webProxyRunner: new WebProxyRunner([RewriteRenderProxy]),
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
expect(await (await (routes["/api/ping"] as () => Response)()).json()).toBe("api");
|
|
57
|
+
const renderResponse = await (routes["/*"] as (req: Request) => Response | Promise<Response>)(
|
|
58
|
+
new Request("http://localhost/dashboard"),
|
|
59
|
+
);
|
|
60
|
+
expect(await renderResponse.json()).toEqual({ url: "http://localhost/rendered", proxy: "1" });
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe("ApiRouter.buildWebsocketHandlers", () => {
|
|
65
|
+
test("dispatches app websocket messages and returns route errors", async () => {
|
|
66
|
+
process.env.AKAN_PUBLIC_APP_NAME = "test";
|
|
67
|
+
const { ApiRouter } = await import("./apiRouter");
|
|
68
|
+
const sent: string[] = [];
|
|
69
|
+
const loggerErrors: string[] = [];
|
|
70
|
+
const ws = {
|
|
71
|
+
data: {},
|
|
72
|
+
send: (message: string) => sent.push(message),
|
|
73
|
+
} as unknown as Bun.ServerWebSocket<unknown>;
|
|
74
|
+
const handlers = ApiRouter.buildWebsocketHandlers({
|
|
75
|
+
wsRoutes: {
|
|
76
|
+
echo: async (_ws, data, event) => ({ event, data }),
|
|
77
|
+
} as WebsocketRoutes,
|
|
78
|
+
registry: getDefaultInjectRegistry(),
|
|
79
|
+
hmrHub: null,
|
|
80
|
+
hmrState: null,
|
|
81
|
+
logger: { error: (message: string) => loggerErrors.push(message) } as never,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
await handlers.message?.(ws, JSON.stringify({ key: "echo", data: ["hello"] }));
|
|
85
|
+
const originalConsoleError = console.error;
|
|
86
|
+
console.error = () => undefined;
|
|
87
|
+
try {
|
|
88
|
+
await handlers.message?.(ws, JSON.stringify({ key: "missing", data: [] }));
|
|
89
|
+
} finally {
|
|
90
|
+
console.error = originalConsoleError;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
expect(JSON.parse(sent[0] ?? "{}")).toEqual({ event: "message", data: ["hello"] });
|
|
94
|
+
expect(JSON.parse(sent[1] ?? "{}").error).toBe('WebSocket route "missing" is not registered');
|
|
95
|
+
expect(loggerErrors).toEqual(['WebSocket route "missing" is not registered']);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test("keeps HMR websocket traffic separate from app signal routes", async () => {
|
|
99
|
+
process.env.AKAN_PUBLIC_APP_NAME = "test";
|
|
100
|
+
const { ApiRouter } = await import("./apiRouter");
|
|
101
|
+
const sent: string[] = [];
|
|
102
|
+
let attached = false;
|
|
103
|
+
let detached = false;
|
|
104
|
+
const ws = {
|
|
105
|
+
data: { kind: "akan-hmr" },
|
|
106
|
+
send: (message: string) => sent.push(message),
|
|
107
|
+
} as unknown as Bun.ServerWebSocket<unknown>;
|
|
108
|
+
const handlers = ApiRouter.buildWebsocketHandlers({
|
|
109
|
+
wsRoutes: {
|
|
110
|
+
hmrShouldNotRun: () => {
|
|
111
|
+
throw new Error("should not run");
|
|
112
|
+
},
|
|
113
|
+
} as WebsocketRoutes,
|
|
114
|
+
registry: getDefaultInjectRegistry(),
|
|
115
|
+
hmrHub: {
|
|
116
|
+
attach: () => {
|
|
117
|
+
attached = true;
|
|
118
|
+
},
|
|
119
|
+
detach: () => {
|
|
120
|
+
detached = true;
|
|
121
|
+
},
|
|
122
|
+
} as never,
|
|
123
|
+
hmrState: { state: { buildId: 7, cssAssets: {} } },
|
|
124
|
+
logger: { error: () => undefined } as never,
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
handlers.open?.(ws);
|
|
128
|
+
await handlers.message?.(ws, JSON.stringify({ key: "hmrShouldNotRun" }));
|
|
129
|
+
handlers.close?.(ws);
|
|
130
|
+
|
|
131
|
+
expect(attached).toBe(true);
|
|
132
|
+
expect(detached).toBe(true);
|
|
133
|
+
expect(JSON.parse(sent[0] ?? "{}")).toEqual({ type: "hello", buildId: 7, cssAssets: {} });
|
|
134
|
+
expect(sent).toHaveLength(1);
|
|
135
|
+
});
|
|
136
|
+
});
|
|
@@ -109,7 +109,9 @@ export class ApiRouter {
|
|
|
109
109
|
}: WebsocketHandlersInputs): Bun.WebSocketHandler<WsTaggedData> {
|
|
110
110
|
return {
|
|
111
111
|
open: (ws) => {
|
|
112
|
-
|
|
112
|
+
// HMR sockets live in a separate logical channel from the app's signal
|
|
113
|
+
// websockets. We tag them via `data.kind === "akan-hmr"` at upgrade
|
|
114
|
+
// time so the dispatcher can skip signal handling.
|
|
113
115
|
const data = ws.data as WsTaggedData | undefined;
|
|
114
116
|
if (data?.kind === "akan-hmr" && hmrHub && hmrState) {
|
|
115
117
|
hmrHub.attach(ws as unknown as Bun.ServerWebSocket<HmrWsData>);
|
|
@@ -126,7 +128,7 @@ export class ApiRouter {
|
|
|
126
128
|
},
|
|
127
129
|
message: async (ws, message) => {
|
|
128
130
|
const data = ws.data as WsTaggedData | undefined;
|
|
129
|
-
if (data?.kind === "akan-hmr") return;
|
|
131
|
+
if (data?.kind === "akan-hmr") return; // dev HMR is one-way (server→client)
|
|
130
132
|
try {
|
|
131
133
|
if (typeof message === "string") {
|
|
132
134
|
const msg = JSON.parse(message) as WebsocketReqData;
|
package/server/rscClient.tsx
CHANGED
|
@@ -67,7 +67,13 @@ async function fetchRsc(href: string, options: { buildId?: number } = {}): Promi
|
|
|
67
67
|
return { type: "redirected" };
|
|
68
68
|
}
|
|
69
69
|
if (!res.ok || !res.body) throw new Error(`[rscClient] RSC fetch failed ${res.status} ${res.statusText}`);
|
|
70
|
-
|
|
70
|
+
// Buffer the entire Flight payload before constructing the thenable. The root
|
|
71
|
+
// `use(thenable)` lives at the document root with no Suspense boundary above it
|
|
72
|
+
// (see Root / ssrFromRscRenderer), so any mid-render suspension during a client
|
|
73
|
+
// navigation transition has no fallback and can leave the transition stuck —
|
|
74
|
+
// committing only when a later navigation flushes the pending lane. Materializing
|
|
75
|
+
// the payload up front means all RSC rows are present and every referenced client
|
|
76
|
+
// module `import()` starts immediately, so the committed render does not suspend.
|
|
71
77
|
const buffer = await res.arrayBuffer();
|
|
72
78
|
const completeStream = new ReadableStream<Uint8Array>({
|
|
73
79
|
start(controller) {
|
package/server/rscWorkerHost.ts
CHANGED
|
@@ -98,7 +98,9 @@ export class RscWorker {
|
|
|
98
98
|
|
|
99
99
|
#status: WorkerStatus = "starting";
|
|
100
100
|
#killed = false;
|
|
101
|
-
|
|
101
|
+
// Render sends issued while the worker is starting / restarting are queued
|
|
102
|
+
// here and flushed on the next `ready`. Each closure re-checks `#pending` so
|
|
103
|
+
// cancelled streams don't forward a stale request to the new worker.
|
|
102
104
|
#queuedSends: Array<() => void> = [];
|
|
103
105
|
#restartAttempts = 0;
|
|
104
106
|
#restartCount = 0;
|
|
@@ -138,7 +140,9 @@ export class RscWorker {
|
|
|
138
140
|
|
|
139
141
|
render(req: Request): ReadableStream<Uint8Array> {
|
|
140
142
|
const requestId = crypto.randomUUID();
|
|
141
|
-
|
|
143
|
+
// Serialize headers so the worker can rebuild a Request mirror inside its
|
|
144
|
+
// own `requestStorage` scope. Without this, server components running in
|
|
145
|
+
// the worker cannot read cookies/auth headers of the incoming request.
|
|
142
146
|
const headers: Array<[string, string]> = [];
|
|
143
147
|
req.headers.forEach((value, key) => {
|
|
144
148
|
headers.push([key, value]);
|
|
@@ -152,7 +156,10 @@ export class RscWorker {
|
|
|
152
156
|
onError: (msg) => controller.error(new Error(msg)),
|
|
153
157
|
});
|
|
154
158
|
const send = () => {
|
|
155
|
-
|
|
159
|
+
// The stream may have been cancelled, or the worker may have died
|
|
160
|
+
// again between queueing and flushing — both cases drop silently
|
|
161
|
+
// (the pending entry is already gone / will be handled by the exit
|
|
162
|
+
// path).
|
|
156
163
|
if (!this.#pending.has(requestId)) return;
|
|
157
164
|
try {
|
|
158
165
|
this.#proc.send({ type: "render", requestId, url: req.url, method: req.method, headers });
|
|
@@ -305,6 +312,8 @@ export class RscWorker {
|
|
|
305
312
|
try {
|
|
306
313
|
this.#proc.send({ type: "updateCssAssets", cssAssets });
|
|
307
314
|
} catch {
|
|
315
|
+
// If the worker died mid-send we'll pick up the new value on the next
|
|
316
|
+
// `hello` after restart; nothing to do here.
|
|
308
317
|
}
|
|
309
318
|
}
|
|
310
319
|
|
|
@@ -320,10 +329,15 @@ export class RscWorker {
|
|
|
320
329
|
this.#cssAssets = input.cssAssets ?? this.#cssAssets;
|
|
321
330
|
this.#pagesBundleBuildId = input.buildId;
|
|
322
331
|
if (input.pagesBundlePath) this.#pagesBundlePath = input.pagesBundlePath;
|
|
323
|
-
|
|
332
|
+
// While restarting / starting, the new worker will pick up the latest
|
|
333
|
+
// `#clientManifest` / `#cssAssets` / `#pagesBundlePath` via the `init` reply
|
|
334
|
+
// to its first `hello`, so callers don't need to wait on an explicit
|
|
335
|
+
// `reloaded` ack.
|
|
324
336
|
if (this.#status !== "ready") return Promise.resolve();
|
|
325
337
|
return new Promise<void>((resolve, reject) => {
|
|
326
|
-
|
|
338
|
+
// If a previous reload was still in flight, supersede it — the latest
|
|
339
|
+
// build strictly implies the earlier one completed from the caller's
|
|
340
|
+
// perspective.
|
|
327
341
|
if (this.#pendingReload) this.#pendingReload.resolve();
|
|
328
342
|
this.#pendingReload = { resolve, reject, targetBuildId: input.buildId };
|
|
329
343
|
try {
|
|
@@ -372,7 +386,10 @@ export class RscWorker {
|
|
|
372
386
|
if (proc !== this.#proc) return;
|
|
373
387
|
switch (message.type) {
|
|
374
388
|
case "hello":
|
|
375
|
-
|
|
389
|
+
// Re-injecting `#clientManifest` / `#cssAssets` here is what makes crash
|
|
390
|
+
// recovery transparent: after a respawn the new worker's first act is
|
|
391
|
+
// to ask for config, and it receives the latest manifest the host has
|
|
392
|
+
// accumulated via `reload(...)`.
|
|
376
393
|
this.#proc.send({
|
|
377
394
|
type: "init",
|
|
378
395
|
clientManifest: this.#clientManifest,
|
|
@@ -417,7 +434,8 @@ export class RscWorker {
|
|
|
417
434
|
return;
|
|
418
435
|
case "error":
|
|
419
436
|
if (message.requestId === "__init__") {
|
|
420
|
-
|
|
437
|
+
// Init errors are surfaced on `ready` only for the very first spawn;
|
|
438
|
+
// subsequent restarts swallow them and let exponential backoff retry.
|
|
421
439
|
if (!this.#readyResolved) this.#rejectReady(new Error(String(message.message)));
|
|
422
440
|
else this.#logger.error(`[rsc] worker init error on restart: ${message.message}`);
|
|
423
441
|
return;
|
|
@@ -491,7 +509,9 @@ export class RscWorker {
|
|
|
491
509
|
}
|
|
492
510
|
|
|
493
511
|
#handleExit(proc: Bun.Subprocess<"ignore", "inherit", "inherit">, code: number | null): void {
|
|
494
|
-
|
|
512
|
+
// Stale exits from a proc we've already replaced can still fire if the
|
|
513
|
+
// old subprocess was slow to cleanup; ignore them so we don't
|
|
514
|
+
// double-schedule a restart.
|
|
495
515
|
if (proc !== this.#proc) return;
|
|
496
516
|
|
|
497
517
|
const err = new Error(`rsc worker exited with code ${code}`);
|
|
@@ -501,7 +521,8 @@ export class RscWorker {
|
|
|
501
521
|
this.#pendingReload.reject(err);
|
|
502
522
|
this.#pendingReload = null;
|
|
503
523
|
}
|
|
504
|
-
|
|
524
|
+
// Drop any sends that were queued against the dead worker. Callers own
|
|
525
|
+
// their streams and will see the `onError` above.
|
|
505
526
|
this.#queuedSends = [];
|
|
506
527
|
|
|
507
528
|
if (this.#killed) {
|
|
@@ -518,7 +539,7 @@ export class RscWorker {
|
|
|
518
539
|
this.#status = "stopped";
|
|
519
540
|
const msg = `[rsc] worker failed ${attempt} restarts; giving up. SSR will return errors until the server restarts.`;
|
|
520
541
|
this.#logger.error(msg);
|
|
521
|
-
|
|
542
|
+
// Surface a rejection on the initial `ready` if we never succeeded.
|
|
522
543
|
this.#rejectReady(new Error(msg));
|
|
523
544
|
return;
|
|
524
545
|
}
|
|
@@ -588,9 +609,10 @@ export class RscWorker {
|
|
|
588
609
|
const raw = fs.readFileSync(filePath, "utf8").trim();
|
|
589
610
|
if (!raw || raw === "max") continue;
|
|
590
611
|
const parsed = Number.parseInt(raw, 10);
|
|
591
|
-
|
|
612
|
+
// Ignore host-level sentinel values that are effectively unlimited.
|
|
592
613
|
if (Number.isFinite(parsed) && parsed > 0 && parsed < 1024 ** 5) return parsed;
|
|
593
614
|
} catch {
|
|
615
|
+
// cgroup files are best-effort; explicit env thresholds still work.
|
|
594
616
|
}
|
|
595
617
|
}
|
|
596
618
|
return null;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { createDefaultSitemapUrls, createSitemapXml, getSitemapBasePath } from "./sitemap";
|
|
2
|
+
|
|
3
|
+
describe("sitemap fallback helpers", () => {
|
|
4
|
+
const i18n = { defaultLocale: "en", locales: ["en", "ko"] };
|
|
5
|
+
|
|
6
|
+
test("creates escaped XML with unique sorted URLs", () => {
|
|
7
|
+
const xml = createSitemapXml(["https://example.com/b?x=1&y=2", "https://example.com/a", "https://example.com/a"]);
|
|
8
|
+
|
|
9
|
+
expect(xml).toContain("<loc>https://example.com/a</loc>");
|
|
10
|
+
expect(xml).toContain("<loc>https://example.com/b?x=1&y=2</loc>");
|
|
11
|
+
expect(xml.match(/<url>/g)).toHaveLength(2);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test("expands only static locale routes", () => {
|
|
15
|
+
const urls = createDefaultSitemapUrls({
|
|
16
|
+
origin: "https://example.com",
|
|
17
|
+
entries: [
|
|
18
|
+
{ routeId: "/:lang", pattern: "/:lang", seeds: [] },
|
|
19
|
+
{ routeId: "/:lang/about", pattern: "/:lang/about", seeds: [] },
|
|
20
|
+
{ routeId: "/:lang/post/:postId", pattern: "/:lang/post/:postId", seeds: [] },
|
|
21
|
+
{ routeId: "/robots.txt", pattern: "/robots.txt", seeds: [] },
|
|
22
|
+
],
|
|
23
|
+
i18n,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
expect(urls).toEqual([
|
|
27
|
+
"https://example.com/en",
|
|
28
|
+
"https://example.com/ko",
|
|
29
|
+
"https://example.com/en/about",
|
|
30
|
+
"https://example.com/ko/about",
|
|
31
|
+
]);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("uses base path only for filtering subroute sitemap entries", () => {
|
|
35
|
+
const urls = createDefaultSitemapUrls({
|
|
36
|
+
origin: "https://example.com/",
|
|
37
|
+
basePath: "akanjs",
|
|
38
|
+
entries: [
|
|
39
|
+
{ routeId: "/:lang/akanjs", pattern: "/:lang/akanjs", seeds: [] },
|
|
40
|
+
{ routeId: "/:lang/akanjs/about", pattern: "/:lang/akanjs/about", seeds: [] },
|
|
41
|
+
{ routeId: "/:lang/thin/about", pattern: "/:lang/thin/about", seeds: [] },
|
|
42
|
+
{ routeId: "/:lang/akanjs/post/:postId", pattern: "/:lang/akanjs/post/:postId", seeds: [] },
|
|
43
|
+
],
|
|
44
|
+
i18n,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
expect(urls).toEqual([
|
|
48
|
+
"https://example.com/en",
|
|
49
|
+
"https://example.com/ko",
|
|
50
|
+
"https://example.com/en/about",
|
|
51
|
+
"https://example.com/ko/about",
|
|
52
|
+
]);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("recognizes root and subroute sitemap paths", () => {
|
|
56
|
+
expect(getSitemapBasePath("/sitemap.xml", [])).toBeNull();
|
|
57
|
+
expect(getSitemapBasePath("/sitemap.xml", ["akanjs"])).toBeUndefined();
|
|
58
|
+
expect(getSitemapBasePath("/sitemap.xml", ["akanjs"], "akanjs")).toBe("akanjs");
|
|
59
|
+
expect(getSitemapBasePath("/akanjs/sitemap.xml", ["akanjs"], "akanjs")).toBeUndefined();
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -12,6 +12,11 @@ export class SsrFromRscRenderer {
|
|
|
12
12
|
ssrChunkCacheHitCount: 0,
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
+
// Inline bootstrap that runs as a classic script BEFORE any <script type="module">.
|
|
16
|
+
// - Installs the webpack runtime shims that react-server-dom-webpack/client.browser
|
|
17
|
+
// needs at module initialization time.
|
|
18
|
+
// - Creates a tiny queue so <script>self.__RSC_PUSH__(...)</script> tags
|
|
19
|
+
// emitted after the HTML shell can be buffered until rscClient picks them up.
|
|
15
20
|
static readonly #clientBootstrap = `(function(){
|
|
16
21
|
var registry = new Map();
|
|
17
22
|
function load(id) {
|
|
@@ -53,7 +58,8 @@ export class SsrFromRscRenderer {
|
|
|
53
58
|
}
|
|
54
59
|
|
|
55
60
|
async render(input: SsrFromRscInput): Promise<ReadableStream<Uint8Array>> {
|
|
56
|
-
|
|
61
|
+
// Split the RSC stream: one branch drives the server-side SSR render, the
|
|
62
|
+
// other is relayed to the client as inline <script> tags for hydration.
|
|
57
63
|
const [rscForSsr, rscForClient] = input.rscStream.tee();
|
|
58
64
|
|
|
59
65
|
const ssrNodeStream = Readable.fromWeb(rscForSsr as never);
|
|
@@ -97,6 +103,19 @@ export class SsrFromRscRenderer {
|
|
|
97
103
|
if (g.__rsc_ssr_shims_installed__) return;
|
|
98
104
|
g.__rsc_ssr_shims_installed__ = true;
|
|
99
105
|
|
|
106
|
+
// SSR-side webpack runtime shims. We use dynamic `import()` rather than
|
|
107
|
+
// `require()` because client component chunks may transitively use
|
|
108
|
+
// top-level await, which Bun's `require()` refuses to load.
|
|
109
|
+
//
|
|
110
|
+
// `chunks`/`id` entries in the ssrManifest are absolute filesystem paths
|
|
111
|
+
// to server-importable client chunks. These may differ from the browser
|
|
112
|
+
// chunks referenced by the Flight client manifest because the browser build
|
|
113
|
+
// can rely on import maps while this SSR pass is loaded directly by Bun.
|
|
114
|
+
// HMR cache-busting is filename-based: each rebuild emits a new
|
|
115
|
+
// content-hashed chunk filename, which means a new import
|
|
116
|
+
// specifier, which bypasses Bun's module cache naturally. The
|
|
117
|
+
// `?v=<digits>` stripping below is defensive for any caller that still
|
|
118
|
+
// appends a version query to keep the pre-existing registry keys stable.
|
|
100
119
|
const registry = new Map<string, Record<string, unknown>>();
|
|
101
120
|
g.__webpack_chunk_load__ = async (chunkId: string) => {
|
|
102
121
|
if (registry.has(chunkId)) {
|
|
@@ -187,7 +206,8 @@ export class SsrFromRscRenderer {
|
|
|
187
206
|
if (tail) controller.enqueue(encoder.encode(tail));
|
|
188
207
|
return;
|
|
189
208
|
}
|
|
190
|
-
|
|
209
|
+
// `<head>` never appeared — e.g. error shell. Emit buffered bytes
|
|
210
|
+
// verbatim so we don't swallow the document.
|
|
191
211
|
const tail = decoder.decode();
|
|
192
212
|
const rest = withHtmlTheme(buffered + tail);
|
|
193
213
|
if (rest) controller.enqueue(encoder.encode(rest));
|
|
@@ -200,10 +220,20 @@ export class SsrFromRscRenderer {
|
|
|
200
220
|
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
201
221
|
}
|
|
202
222
|
|
|
223
|
+
// React-server-dom-webpack/server emits a Flight hint of the form
|
|
224
|
+
// `:HL["<href>","stylesheet"]\n` for every `<link rel="stylesheet">` in the
|
|
225
|
+
// server tree. That string is forwarded verbatim to the browser which then
|
|
226
|
+
// calls `ReactDOM.preload(href, "stylesheet")`, creating an invalid
|
|
227
|
+
// `<link rel="preload" as="stylesheet">` (valid preload `as` is `"style"`).
|
|
228
|
+
// The SSR-side Fizz dispatcher happens to tolerate this, but Chromium logs
|
|
229
|
+
// `<link rel=preload> must have a valid "as" value`. Rewrite the hint for
|
|
230
|
+
// the browser-bound stream to use the spec-correct `"style"`; the SSR-bound
|
|
231
|
+
// tee is left untouched so we don't alter React's server behavior.
|
|
203
232
|
static #sanitizeFlightForClient(stream: ReadableStream<Uint8Array>): ReadableStream<Uint8Array> {
|
|
204
233
|
const decoder = new TextDecoder();
|
|
205
234
|
const encoder = new TextEncoder();
|
|
206
|
-
|
|
235
|
+
// Matches just the trailing `,"stylesheet"]` of an HL hint line. The href is
|
|
236
|
+
// left alone; only the `as` slot is rewritten.
|
|
207
237
|
const hlStylesheetRe = /(:HL\["[^"\\]*(?:\\.[^"\\]*)*",)"stylesheet"(\])/g;
|
|
208
238
|
|
|
209
239
|
return stream.pipeThrough(
|
|
@@ -253,6 +283,8 @@ export class SsrFromRscRenderer {
|
|
|
253
283
|
reader.releaseLock();
|
|
254
284
|
}
|
|
255
285
|
|
|
286
|
+
// Inline RSC scripts must not be interleaved with arbitrary HTML bytes:
|
|
287
|
+
// Fizz may split inside SVG path data or attributes, corrupting markup.
|
|
256
288
|
const rscReader = rscClientStream.getReader();
|
|
257
289
|
try {
|
|
258
290
|
while (true) {
|