rwsdk 0.1.16 → 0.1.17
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/dist/lib/$.d.mts +8 -0
- package/dist/lib/$.mjs +5 -0
- package/dist/lib/compileTsModule.d.mts +1 -0
- package/dist/lib/compileTsModule.mjs +27 -0
- package/dist/lib/constants.d.mts +4 -0
- package/dist/lib/constants.mjs +6 -0
- package/dist/lib/findWranglerConfig.d.mts +1 -0
- package/dist/lib/findWranglerConfig.mjs +12 -0
- package/dist/lib/getShortName.d.mts +1 -0
- package/dist/lib/getShortName.mjs +2 -0
- package/dist/lib/getSrcPaths.d.ts +15 -0
- package/dist/lib/getSrcPaths.js +80 -0
- package/dist/lib/hasPkgScript.d.mts +1 -0
- package/dist/lib/hasPkgScript.mjs +9 -0
- package/dist/lib/jsonUtils.d.mts +28 -0
- package/dist/lib/jsonUtils.mjs +167 -0
- package/dist/lib/setupEnvFiles.d.mts +4 -0
- package/dist/lib/setupEnvFiles.mjs +31 -0
- package/dist/lib/smokeTests/artifacts.d.mts +10 -0
- package/dist/lib/smokeTests/artifacts.mjs +164 -0
- package/dist/lib/smokeTests/browser.d.mts +48 -0
- package/dist/lib/smokeTests/browser.mjs +1041 -0
- package/dist/lib/smokeTests/cleanup.d.mts +5 -0
- package/dist/lib/smokeTests/cleanup.mjs +214 -0
- package/dist/lib/smokeTests/codeUpdates.d.mts +8 -0
- package/dist/lib/smokeTests/codeUpdates.mjs +229 -0
- package/dist/lib/smokeTests/constants.d.mts +5 -0
- package/dist/lib/smokeTests/constants.mjs +10 -0
- package/dist/lib/smokeTests/development.d.mts +11 -0
- package/dist/lib/smokeTests/development.mjs +209 -0
- package/dist/lib/smokeTests/environment.d.mts +14 -0
- package/dist/lib/smokeTests/environment.mjs +163 -0
- package/dist/lib/smokeTests/release.d.mts +61 -0
- package/dist/lib/smokeTests/release.mjs +526 -0
- package/dist/lib/smokeTests/reporting.d.mts +13 -0
- package/dist/lib/smokeTests/reporting.mjs +355 -0
- package/dist/lib/smokeTests/runSmokeTests.d.mts +5 -0
- package/dist/lib/smokeTests/runSmokeTests.mjs +144 -0
- package/dist/lib/smokeTests/state.d.mts +48 -0
- package/dist/lib/smokeTests/state.mjs +57 -0
- package/dist/lib/smokeTests/templates/SmokeTest.template.d.ts +1 -0
- package/dist/lib/smokeTests/templates/SmokeTest.template.js +81 -0
- package/dist/lib/smokeTests/templates/SmokeTestClient.template.d.ts +1 -0
- package/dist/lib/smokeTests/templates/SmokeTestClient.template.js +159 -0
- package/dist/lib/smokeTests/templates/smokeTestFunctions.template.d.ts +1 -0
- package/dist/lib/smokeTests/templates/smokeTestFunctions.template.js +19 -0
- package/dist/lib/smokeTests/types.d.mts +75 -0
- package/dist/lib/smokeTests/types.mjs +1 -0
- package/dist/lib/smokeTests/utils.d.mts +15 -0
- package/dist/lib/smokeTests/utils.mjs +147 -0
- package/dist/llms/index.d.ts +3 -0
- package/dist/llms/index.js +35 -0
- package/dist/llms/rules/interruptors.d.ts +1 -0
- package/dist/llms/rules/interruptors.js +243 -0
- package/dist/llms/rules/middleware.d.ts +1 -0
- package/dist/llms/rules/middleware.js +71 -0
- package/dist/llms/rules/react.d.ts +1 -0
- package/dist/llms/rules/react.js +106 -0
- package/dist/llms/rules/request-response.d.ts +1 -0
- package/dist/llms/rules/request-response.js +209 -0
- package/dist/runtime/client.d.ts +17 -0
- package/dist/runtime/client.js +74 -0
- package/dist/runtime/clientNavigation.d.ts +4 -0
- package/dist/runtime/clientNavigation.js +53 -0
- package/dist/runtime/clientNavigation.test.d.ts +1 -0
- package/dist/runtime/clientNavigation.test.js +55 -0
- package/dist/runtime/constants.d.ts +1 -0
- package/dist/runtime/constants.js +1 -0
- package/dist/runtime/entries/auth.d.ts +1 -0
- package/dist/runtime/entries/auth.js +1 -0
- package/dist/runtime/entries/client.d.ts +4 -0
- package/dist/runtime/entries/client.js +4 -0
- package/dist/runtime/entries/clientSSR.d.ts +1 -0
- package/dist/runtime/entries/clientSSR.js +1 -0
- package/dist/runtime/entries/navigation.d.ts +1 -0
- package/dist/runtime/entries/navigation.js +1 -0
- package/dist/runtime/entries/no-react-server.d.ts +0 -0
- package/dist/runtime/entries/no-react-server.js +2 -0
- package/dist/runtime/entries/react-server-only.d.ts +0 -0
- package/dist/runtime/entries/react-server-only.js +2 -0
- package/dist/runtime/entries/router.d.ts +2 -0
- package/dist/runtime/entries/router.js +2 -0
- package/dist/runtime/entries/ssr.d.ts +1 -0
- package/dist/runtime/entries/ssr.js +1 -0
- package/dist/runtime/entries/worker.d.ts +9 -0
- package/dist/runtime/entries/worker.js +9 -0
- package/dist/runtime/error.d.ts +6 -0
- package/dist/runtime/error.js +8 -0
- package/dist/runtime/imports/ClientOnly.d.ts +3 -0
- package/dist/runtime/imports/ClientOnly.js +8 -0
- package/dist/runtime/imports/client.d.ts +4 -0
- package/dist/runtime/imports/client.js +33 -0
- package/dist/runtime/imports/ssr.d.ts +5 -0
- package/dist/runtime/imports/ssr.js +20 -0
- package/dist/runtime/imports/worker.d.ts +5 -0
- package/dist/runtime/imports/worker.js +22 -0
- package/dist/runtime/lib/auth/index.d.ts +1 -0
- package/dist/runtime/lib/auth/index.js +1 -0
- package/dist/runtime/lib/auth/session.d.ts +50 -0
- package/dist/runtime/lib/auth/session.js +148 -0
- package/dist/runtime/lib/db/DOWorkerDialect.d.ts +29 -0
- package/dist/runtime/lib/db/DOWorkerDialect.js +66 -0
- package/dist/runtime/lib/db/SqliteDurableObject.d.ts +14 -0
- package/dist/runtime/lib/db/SqliteDurableObject.js +42 -0
- package/dist/runtime/lib/db/createDb.d.ts +2 -0
- package/dist/runtime/lib/db/createDb.js +33 -0
- package/dist/runtime/lib/db/index.d.ts +4 -0
- package/dist/runtime/lib/db/index.js +3 -0
- package/dist/runtime/lib/db/migrations.d.ts +23 -0
- package/dist/runtime/lib/db/migrations.js +34 -0
- package/dist/runtime/lib/db/typeInference/assert.d.ts +2 -0
- package/dist/runtime/lib/db/typeInference/assert.js +1 -0
- package/dist/runtime/lib/db/typeInference/builders/alterColumn.d.ts +27 -0
- package/dist/runtime/lib/db/typeInference/builders/alterColumn.js +1 -0
- package/dist/runtime/lib/db/typeInference/builders/alterTable.d.ts +53 -0
- package/dist/runtime/lib/db/typeInference/builders/alterTable.js +1 -0
- package/dist/runtime/lib/db/typeInference/builders/columnDefinition.d.ts +26 -0
- package/dist/runtime/lib/db/typeInference/builders/columnDefinition.js +1 -0
- package/dist/runtime/lib/db/typeInference/builders/createTable.d.ts +49 -0
- package/dist/runtime/lib/db/typeInference/builders/createTable.js +1 -0
- package/dist/runtime/lib/db/typeInference/builders/createView.d.ts +17 -0
- package/dist/runtime/lib/db/typeInference/builders/createView.js +1 -0
- package/dist/runtime/lib/db/typeInference/builders/dropTable.d.ts +11 -0
- package/dist/runtime/lib/db/typeInference/builders/dropTable.js +1 -0
- package/dist/runtime/lib/db/typeInference/builders/dropView.d.ts +12 -0
- package/dist/runtime/lib/db/typeInference/builders/dropView.js +1 -0
- package/dist/runtime/lib/db/typeInference/builders/schema.d.ts +24 -0
- package/dist/runtime/lib/db/typeInference/builders/schema.js +1 -0
- package/dist/runtime/lib/db/typeInference/database.d.ts +27 -0
- package/dist/runtime/lib/db/typeInference/database.js +1 -0
- package/dist/runtime/lib/db/typeInference/typetests/alterTable.typetest.d.ts +1 -0
- package/dist/runtime/lib/db/typeInference/typetests/alterTable.typetest.js +360 -0
- package/dist/runtime/lib/db/typeInference/typetests/createTable.typetest.d.ts +1 -0
- package/dist/runtime/lib/db/typeInference/typetests/createTable.typetest.js +33 -0
- package/dist/runtime/lib/db/typeInference/typetests/dropTable.typetest.d.ts +1 -0
- package/dist/runtime/lib/db/typeInference/typetests/dropTable.typetest.js +143 -0
- package/dist/runtime/lib/db/typeInference/typetests/print.d.ts +3 -0
- package/dist/runtime/lib/db/typeInference/typetests/print.js +1 -0
- package/dist/runtime/lib/db/typeInference/typetests/testUtils.d.ts +2 -0
- package/dist/runtime/lib/db/typeInference/typetests/testUtils.js +1 -0
- package/dist/runtime/lib/db/typeInference/typetests/typeInference.typetest.d.ts +1 -0
- package/dist/runtime/lib/db/typeInference/typetests/typeInference.typetest.js +17 -0
- package/dist/runtime/lib/db/typeInference/utils.d.ts +82 -0
- package/dist/runtime/lib/db/typeInference/utils.js +2 -0
- package/dist/runtime/lib/debug.d.ts +2 -0
- package/dist/runtime/lib/debug.js +36 -0
- package/dist/runtime/lib/links.d.ts +14 -0
- package/dist/runtime/lib/links.js +38 -0
- package/dist/runtime/lib/realtime/client.d.ts +7 -0
- package/dist/runtime/lib/realtime/client.js +166 -0
- package/dist/runtime/lib/realtime/constants.d.ts +1 -0
- package/dist/runtime/lib/realtime/constants.js +1 -0
- package/dist/runtime/lib/realtime/durableObject.d.ts +29 -0
- package/dist/runtime/lib/realtime/durableObject.js +187 -0
- package/dist/runtime/lib/realtime/renderRealtimeClients.d.ts +7 -0
- package/dist/runtime/lib/realtime/renderRealtimeClients.js +6 -0
- package/dist/runtime/lib/realtime/shared.d.ts +10 -0
- package/dist/runtime/lib/realtime/shared.js +10 -0
- package/dist/runtime/lib/realtime/validateUpgradeRequest.d.ts +6 -0
- package/dist/runtime/lib/realtime/validateUpgradeRequest.js +29 -0
- package/dist/runtime/lib/realtime/worker.d.ts +3 -0
- package/dist/runtime/lib/realtime/worker.js +16 -0
- package/dist/runtime/lib/router.d.ts +56 -0
- package/dist/runtime/lib/router.js +210 -0
- package/dist/runtime/lib/router.test.d.ts +1 -0
- package/dist/runtime/lib/router.test.js +58 -0
- package/dist/runtime/lib/streams/consumeEventStream.d.ts +4 -0
- package/dist/runtime/lib/streams/consumeEventStream.js +13 -0
- package/dist/runtime/lib/turnstile/TurnstileScript.d.ts +1 -0
- package/dist/runtime/lib/turnstile/TurnstileScript.js +2 -0
- package/dist/runtime/lib/turnstile/turnstile.d.ts +3 -0
- package/dist/runtime/lib/turnstile/turnstile.js +3 -0
- package/dist/runtime/lib/turnstile/useTurnstile.d.ts +4 -0
- package/dist/runtime/lib/turnstile/useTurnstile.js +23 -0
- package/dist/runtime/lib/turnstile/verifyTurnstileToken.d.ts +4 -0
- package/dist/runtime/lib/turnstile/verifyTurnstileToken.js +15 -0
- package/dist/runtime/lib/utils.d.ts +1 -0
- package/dist/runtime/lib/utils.js +1 -0
- package/dist/runtime/register/client.d.ts +1 -0
- package/dist/runtime/register/client.js +5 -0
- package/dist/runtime/register/ssr.d.ts +3 -0
- package/dist/runtime/register/ssr.js +26 -0
- package/dist/runtime/register/worker.d.ts +4 -0
- package/dist/runtime/register/worker.js +42 -0
- package/dist/runtime/render/createClientManifest.d.ts +1 -0
- package/dist/runtime/render/createClientManifest.js +7 -0
- package/dist/runtime/render/createModuleMap.d.ts +1 -0
- package/dist/runtime/render/createModuleMap.js +13 -0
- package/dist/runtime/render/injectRSCPayload.d.ts +3 -0
- package/dist/runtime/render/injectRSCPayload.js +79 -0
- package/dist/runtime/render/renderRscThenableToHtmlStream.d.ts +9 -0
- package/dist/runtime/render/renderRscThenableToHtmlStream.js +49 -0
- package/dist/runtime/render/renderToRscStream.d.ts +5 -0
- package/dist/runtime/render/renderToRscStream.js +46 -0
- package/dist/runtime/render/renderToStream.d.ts +9 -0
- package/dist/runtime/render/renderToStream.js +27 -0
- package/dist/runtime/render/renderToString.d.ts +7 -0
- package/dist/runtime/render/renderToString.js +26 -0
- package/dist/runtime/render/transformRscToHtmlStream.d.ts +8 -0
- package/dist/runtime/render/transformRscToHtmlStream.js +19 -0
- package/dist/runtime/requestInfo/types.d.ts +11 -0
- package/dist/runtime/requestInfo/types.js +1 -0
- package/dist/runtime/requestInfo/worker.d.ts +5 -0
- package/dist/runtime/requestInfo/worker.js +33 -0
- package/dist/runtime/script.d.ts +5 -0
- package/dist/runtime/script.js +8 -0
- package/dist/runtime/ssrBridge.d.ts +2 -0
- package/dist/runtime/ssrBridge.js +11 -0
- package/dist/runtime/worker.d.ts +18 -0
- package/dist/runtime/worker.js +173 -0
- package/dist/scripts/__sdk.d.mts +1 -0
- package/dist/scripts/__sdk.mjs +14 -0
- package/dist/scripts/build-vendor-bundles.d.mts +1 -0
- package/dist/scripts/build-vendor-bundles.mjs +92 -0
- package/dist/scripts/debug-sync.d.mts +6 -0
- package/dist/scripts/debug-sync.mjs +224 -0
- package/dist/scripts/dev-init.d.mts +1 -0
- package/dist/scripts/dev-init.mjs +25 -0
- package/dist/scripts/ensure-deploy-env.d.mts +1 -0
- package/dist/scripts/ensure-deploy-env.mjs +271 -0
- package/dist/scripts/ensure-env.d.mts +1 -0
- package/dist/scripts/ensure-env.mjs +9 -0
- package/dist/scripts/migrate-new.d.mts +1 -0
- package/dist/scripts/migrate-new.mjs +51 -0
- package/dist/scripts/smoke-test.d.mts +1 -0
- package/dist/scripts/smoke-test.mjs +166 -0
- package/dist/scripts/worker-run.d.mts +1 -0
- package/dist/scripts/worker-run.mjs +82 -0
- package/dist/vite/aliasByEnvPlugin.d.mts +2 -0
- package/dist/vite/aliasByEnvPlugin.mjs +11 -0
- package/dist/vite/asyncSetupPlugin.d.mts +6 -0
- package/dist/vite/asyncSetupPlugin.mjs +23 -0
- package/dist/vite/checkIsUsingPrisma.d.mts +6 -0
- package/dist/vite/checkIsUsingPrisma.mjs +18 -0
- package/dist/vite/configPlugin.d.mts +9 -0
- package/dist/vite/configPlugin.mjs +169 -0
- package/dist/vite/copyPrismaWasmPlugin.d.mts +4 -0
- package/dist/vite/copyPrismaWasmPlugin.mjs +32 -0
- package/dist/vite/createDirectiveLookupPlugin.d.mts +21 -0
- package/dist/vite/createDirectiveLookupPlugin.mjs +231 -0
- package/dist/vite/customReactBuildPlugin.d.mts +4 -0
- package/dist/vite/customReactBuildPlugin.mjs +61 -0
- package/dist/vite/devServerTimingPlugin.d.mts +2 -0
- package/dist/vite/devServerTimingPlugin.mjs +24 -0
- package/dist/vite/directivesPlugin.d.mts +6 -0
- package/dist/vite/directivesPlugin.mjs +200 -0
- package/dist/vite/ensureAliasArray.d.mts +2 -0
- package/dist/vite/ensureAliasArray.mjs +17 -0
- package/dist/vite/findSpecifiers.d.mts +31 -0
- package/dist/vite/findSpecifiers.mjs +230 -0
- package/dist/vite/findSsrSpecifiers.d.mts +11 -0
- package/dist/vite/findSsrSpecifiers.mjs +67 -0
- package/dist/vite/hasDirective.d.mts +7 -0
- package/dist/vite/hasDirective.mjs +54 -0
- package/dist/vite/hasOwnCloudflareVitePlugin.d.mts +3 -0
- package/dist/vite/hasOwnCloudflareVitePlugin.mjs +14 -0
- package/dist/vite/index.d.mts +1 -0
- package/dist/vite/index.mjs +1 -0
- package/dist/vite/injectHmrPreambleJsxPlugin.d.mts +2 -0
- package/dist/vite/injectHmrPreambleJsxPlugin.mjs +22 -0
- package/dist/vite/injectVitePreamblePlugin.d.mts +4 -0
- package/dist/vite/injectVitePreamblePlugin.mjs +23 -0
- package/dist/vite/invalidateCacheIfPrismaClientChanged.d.mts +3 -0
- package/dist/vite/invalidateCacheIfPrismaClientChanged.mjs +27 -0
- package/dist/vite/invalidateModule.d.mts +6 -0
- package/dist/vite/invalidateModule.mjs +30 -0
- package/dist/vite/miniflareHMRPlugin.d.mts +10 -0
- package/dist/vite/miniflareHMRPlugin.mjs +209 -0
- package/dist/vite/miniflarePlugin.d.mts +9 -0
- package/dist/vite/miniflarePlugin.mjs +135 -0
- package/dist/vite/moveStaticAssetsPlugin.d.mts +4 -0
- package/dist/vite/moveStaticAssetsPlugin.mjs +12 -0
- package/dist/vite/normalizeModulePath.d.mts +1 -0
- package/dist/vite/normalizeModulePath.mjs +13 -0
- package/dist/vite/prismaPlugin.d.mts +4 -0
- package/dist/vite/prismaPlugin.mjs +43 -0
- package/dist/vite/reactConditionsResolverPlugin.d.mts +16 -0
- package/dist/vite/reactConditionsResolverPlugin.mjs +179 -0
- package/dist/vite/redwoodPlugin.d.mts +12 -0
- package/dist/vite/redwoodPlugin.mjs +105 -0
- package/dist/vite/requestUtils.d.mts +6 -0
- package/dist/vite/requestUtils.mjs +35 -0
- package/dist/vite/setupEnvFiles.d.mts +4 -0
- package/dist/vite/setupEnvFiles.mjs +31 -0
- package/dist/vite/ssrBridgePlugin.d.mts +7 -0
- package/dist/vite/ssrBridgePlugin.mjs +137 -0
- package/dist/vite/transformClientComponents.d.mts +12 -0
- package/dist/vite/transformClientComponents.mjs +116 -0
- package/dist/vite/transformClientComponents.test.d.mts +1 -0
- package/dist/vite/transformClientComponents.test.mjs +264 -0
- package/dist/vite/transformJsxScriptTagsPlugin.d.mts +8 -0
- package/dist/vite/transformJsxScriptTagsPlugin.mjs +315 -0
- package/dist/vite/transformJsxScriptTagsPlugin.test.d.mts +1 -0
- package/dist/vite/transformJsxScriptTagsPlugin.test.mjs +334 -0
- package/dist/vite/transformServerFunctions.d.mts +16 -0
- package/dist/vite/transformServerFunctions.mjs +296 -0
- package/dist/vite/transformServerFunctions.test.d.mts +1 -0
- package/dist/vite/transformServerFunctions.test.mjs +124 -0
- package/dist/vite/useClientLookupPlugin.d.mts +5 -0
- package/dist/vite/useClientLookupPlugin.mjs +15 -0
- package/dist/vite/useClientPlugin.d.mts +8 -0
- package/dist/vite/useClientPlugin.mjs +295 -0
- package/dist/vite/useClientPlugin.test.d.mts +1 -0
- package/dist/vite/useClientPlugin.test.mjs +1204 -0
- package/dist/vite/useServerLookupPlugin.d.mts +5 -0
- package/dist/vite/useServerLookupPlugin.mjs +15 -0
- package/dist/vite/useServerPlugin.d.mts +1 -0
- package/dist/vite/useServerPlugin.mjs +1 -0
- package/dist/vite/virtualPlugin.d.mts +2 -0
- package/dist/vite/virtualPlugin.mjs +18 -0
- package/dist/vite/vitePreamblePlugin.d.mts +1 -0
- package/dist/vite/vitePreamblePlugin.mjs +11 -0
- package/dist/worker/__ssr_bridge.js +8947 -0
- package/dist/worker/__ssr_bridge.js.map +1 -0
- package/package.json +1 -1
- package/dist/vite/invalidateClientModule.d.mts +0 -2
- package/dist/vite/invalidateClientModule.mjs +0 -8
- package/dist/vite/invalidateModule copy.d.mts +0 -2
- package/dist/vite/invalidateModule copy.mjs +0 -14
- package/dist/vite/invalidateSSRModule.d.mts +0 -2
- package/dist/vite/invalidateSSRModule.mjs +0 -7
- package/dist/vite/mode.d.mts +0 -5
- package/dist/vite/mode.mjs +0 -25
- package/dist/vite/modePlugin.d.mts +0 -2
- package/dist/vite/modePlugin.mjs +0 -10
- /package/dist/vite/{isJsFile.d.ts → isJsFile.d.mts} +0 -0
- /package/dist/vite/{isJsFile.js → isJsFile.mjs} +0 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
export function getSmokeTestTemplate(skipClient = false) {
|
|
2
|
+
return `
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { RequestInfo } from "rwsdk/worker";
|
|
5
|
+
${skipClient ? "" : 'import { SmokeTestClient } from "./__SmokeTestClient";'}
|
|
6
|
+
import { getSmokeTestTimestamp } from "./__smokeTestFunctions";
|
|
7
|
+
|
|
8
|
+
export const SmokeTestInfo: React.FC = async () => {
|
|
9
|
+
const currentTime = Date.now();
|
|
10
|
+
let status = "error";
|
|
11
|
+
let timestamp = 0;
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
const result = await getSmokeTestTimestamp();
|
|
15
|
+
status = result.status || "error";
|
|
16
|
+
timestamp = result.timestamp;
|
|
17
|
+
} catch (error) {
|
|
18
|
+
console.error("Smoke test failed:", error);
|
|
19
|
+
status = "error";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div
|
|
24
|
+
id="smoke-test-container"
|
|
25
|
+
data-testid="health-status"
|
|
26
|
+
data-status={status}
|
|
27
|
+
data-timestamp={timestamp}
|
|
28
|
+
data-server-timestamp={currentTime}
|
|
29
|
+
style={{
|
|
30
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
31
|
+
margin: "20px",
|
|
32
|
+
padding: "15px",
|
|
33
|
+
border: "1px solid #ddd",
|
|
34
|
+
borderRadius: "4px",
|
|
35
|
+
background: "#f9f9f9",
|
|
36
|
+
}}
|
|
37
|
+
>
|
|
38
|
+
<h2
|
|
39
|
+
style={{
|
|
40
|
+
color: status === "ok" ? "#0c9" : "#f44",
|
|
41
|
+
margin: "0 0 10px 0",
|
|
42
|
+
}}
|
|
43
|
+
>
|
|
44
|
+
Smoke Test: {status}
|
|
45
|
+
</h2>
|
|
46
|
+
<div
|
|
47
|
+
id="smoke-test-result"
|
|
48
|
+
>
|
|
49
|
+
Server Timestamp: {timestamp}
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
{/* HMR Testing Marker - Do not modify this comment */}
|
|
53
|
+
<div
|
|
54
|
+
id="server-hmr-marker"
|
|
55
|
+
data-testid="server-hmr-marker"
|
|
56
|
+
data-hmr-text="original"
|
|
57
|
+
data-hmr-timestamp={Date.now()}
|
|
58
|
+
>
|
|
59
|
+
Server Component HMR: <span>Original Text</span>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<details style={{ marginTop: "10px" }}>
|
|
63
|
+
<summary>Details</summary>
|
|
64
|
+
<pre
|
|
65
|
+
style={{
|
|
66
|
+
background: "#f5f5f5",
|
|
67
|
+
padding: "10px",
|
|
68
|
+
borderRadius: "4px",
|
|
69
|
+
fontSize: "12px",
|
|
70
|
+
overflow: "auto",
|
|
71
|
+
}}
|
|
72
|
+
>
|
|
73
|
+
{JSON.stringify({ currentTime, serverTimestamp: timestamp, status }, null, 2)}
|
|
74
|
+
</pre>
|
|
75
|
+
</details>
|
|
76
|
+
|
|
77
|
+
${!skipClient ? "<SmokeTestClient/>" : ""}
|
|
78
|
+
</div>
|
|
79
|
+
);
|
|
80
|
+
};`;
|
|
81
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getSmokeTestClientTemplate(): string;
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
export function getSmokeTestClientTemplate() {
|
|
2
|
+
return `"use client";
|
|
3
|
+
|
|
4
|
+
import React, { useState } from "react";
|
|
5
|
+
import { smokeTestAction } from "./__smokeTestFunctions";
|
|
6
|
+
|
|
7
|
+
interface SmokeTestStatus {
|
|
8
|
+
status: string;
|
|
9
|
+
verificationPassed: boolean;
|
|
10
|
+
timestamp: number;
|
|
11
|
+
rawResult?: unknown;
|
|
12
|
+
error?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface SmokeTestResponse {
|
|
16
|
+
status: string;
|
|
17
|
+
timestamp?: number;
|
|
18
|
+
[key: string]: unknown;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const SmokeTestClient: React.FC = () => {
|
|
22
|
+
const [loading, setLoading] = useState(false);
|
|
23
|
+
const [lastCheck, setLastCheck] = useState<SmokeTestStatus | null>(null);
|
|
24
|
+
|
|
25
|
+
const runSmokeTest = async () => {
|
|
26
|
+
setLoading(true);
|
|
27
|
+
const clientTimestamp = Date.now();
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
// Update the server timestamp with our client timestamp
|
|
31
|
+
const result = await smokeTestAction(clientTimestamp);
|
|
32
|
+
const status = result.status || "error";
|
|
33
|
+
const verificationPassed = result.timestamp === clientTimestamp;
|
|
34
|
+
|
|
35
|
+
setLastCheck({
|
|
36
|
+
status,
|
|
37
|
+
verificationPassed,
|
|
38
|
+
timestamp: clientTimestamp,
|
|
39
|
+
rawResult: result,
|
|
40
|
+
});
|
|
41
|
+
} catch (error) {
|
|
42
|
+
setLastCheck({
|
|
43
|
+
status: "error",
|
|
44
|
+
verificationPassed: false,
|
|
45
|
+
timestamp: clientTimestamp,
|
|
46
|
+
error: error instanceof Error ? error.message : String(error),
|
|
47
|
+
});
|
|
48
|
+
} finally {
|
|
49
|
+
setLoading(false);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<div
|
|
55
|
+
className="smoke-test-client"
|
|
56
|
+
style={{
|
|
57
|
+
margin: "20px 0",
|
|
58
|
+
padding: "15px",
|
|
59
|
+
border: "1px solid #ddd",
|
|
60
|
+
borderRadius: "4px",
|
|
61
|
+
background: "#f9f9f9",
|
|
62
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
63
|
+
}}
|
|
64
|
+
>
|
|
65
|
+
<h3>Manual Smoke Test</h3>
|
|
66
|
+
<button
|
|
67
|
+
data-testid="refresh-health"
|
|
68
|
+
onClick={runSmokeTest}
|
|
69
|
+
disabled={loading}
|
|
70
|
+
style={{
|
|
71
|
+
padding: "8px 16px",
|
|
72
|
+
background: loading ? "#ccc" : "#0070f3",
|
|
73
|
+
color: "white",
|
|
74
|
+
border: "none",
|
|
75
|
+
borderRadius: "4px",
|
|
76
|
+
cursor: loading ? "not-allowed" : "pointer",
|
|
77
|
+
fontWeight: "bold",
|
|
78
|
+
}}
|
|
79
|
+
>
|
|
80
|
+
{loading ? "Checking..." : "Run Smoke Test"}
|
|
81
|
+
</button>
|
|
82
|
+
|
|
83
|
+
{/* HMR Testing Marker - Do not modify this comment */}
|
|
84
|
+
<div
|
|
85
|
+
id="client-hmr-marker"
|
|
86
|
+
data-testid="client-hmr-marker"
|
|
87
|
+
data-hmr-text="original"
|
|
88
|
+
data-hmr-timestamp={Date.now()}
|
|
89
|
+
>
|
|
90
|
+
Client Component HMR: <span>Original Text</span>
|
|
91
|
+
</div>
|
|
92
|
+
|
|
93
|
+
{lastCheck && (
|
|
94
|
+
<div style={{ marginTop: "15px" }}>
|
|
95
|
+
<div
|
|
96
|
+
style={{
|
|
97
|
+
padding: "10px",
|
|
98
|
+
borderRadius: "4px",
|
|
99
|
+
background: lastCheck.status === "ok" ? "#e6f7ee" : "#ffeded",
|
|
100
|
+
border: \`1px solid \${
|
|
101
|
+
lastCheck.status === "ok" ? "#0c9" : "#f44"
|
|
102
|
+
}\`,
|
|
103
|
+
}}
|
|
104
|
+
>
|
|
105
|
+
<h4
|
|
106
|
+
style={{
|
|
107
|
+
margin: "0 0 10px 0",
|
|
108
|
+
color: lastCheck.status === "ok" ? "#0c9" : "#f44",
|
|
109
|
+
}}
|
|
110
|
+
>
|
|
111
|
+
Status: {lastCheck.status}
|
|
112
|
+
</h4>
|
|
113
|
+
<p>
|
|
114
|
+
Server timestamp updated to: {lastCheck.timestamp}
|
|
115
|
+
</p>
|
|
116
|
+
<p>
|
|
117
|
+
Timestamp verification:{" "}
|
|
118
|
+
{lastCheck.verificationPassed ? "Passed ✅" : "Failed ⚠️"}
|
|
119
|
+
</p>
|
|
120
|
+
{lastCheck.error && (
|
|
121
|
+
<p style={{ color: "#f44" }}>Error: {lastCheck.error}</p>
|
|
122
|
+
)}
|
|
123
|
+
<details style={{ marginTop: "10px" }}>
|
|
124
|
+
<summary>Raw Result</summary>
|
|
125
|
+
<pre
|
|
126
|
+
style={{
|
|
127
|
+
background: "#f5f5f5",
|
|
128
|
+
padding: "10px",
|
|
129
|
+
borderRadius: "4px",
|
|
130
|
+
fontSize: "12px",
|
|
131
|
+
overflow: "auto",
|
|
132
|
+
}}
|
|
133
|
+
>
|
|
134
|
+
{JSON.stringify(
|
|
135
|
+
{
|
|
136
|
+
timestamp: lastCheck.timestamp,
|
|
137
|
+
result: lastCheck.rawResult,
|
|
138
|
+
verificationPassed: lastCheck.verificationPassed,
|
|
139
|
+
},
|
|
140
|
+
null,
|
|
141
|
+
2
|
|
142
|
+
)}
|
|
143
|
+
</pre>
|
|
144
|
+
</details>
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
147
|
+
)}
|
|
148
|
+
|
|
149
|
+
<div
|
|
150
|
+
id="smoke-test-client-timestamp"
|
|
151
|
+
data-client-timestamp={lastCheck?.timestamp ?? ""}
|
|
152
|
+
data-status={lastCheck?.status ?? ""}
|
|
153
|
+
data-verified={lastCheck?.verificationPassed ? "true" : "false"}
|
|
154
|
+
style={{ display: "none" }}
|
|
155
|
+
/>
|
|
156
|
+
</div>
|
|
157
|
+
);
|
|
158
|
+
};`;
|
|
159
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getSmokeTestFunctionsTemplate(): string;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function getSmokeTestFunctionsTemplate() {
|
|
2
|
+
return `"use server";
|
|
3
|
+
|
|
4
|
+
// Module-level variable to store the timestamp set by client
|
|
5
|
+
// Initialize with a fixed value to verify initial server render
|
|
6
|
+
let serverTimestamp: number = 23;
|
|
7
|
+
|
|
8
|
+
// Function to retrieve the current server timestamp
|
|
9
|
+
export async function getSmokeTestTimestamp(): Promise<{ timestamp: number, status: string }> {
|
|
10
|
+
return { timestamp: serverTimestamp, status: "ok" };
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function smokeTestAction(timestamp: number): Promise<unknown> {
|
|
14
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
15
|
+
serverTimestamp = timestamp;
|
|
16
|
+
return { status: "ok", timestamp };
|
|
17
|
+
}
|
|
18
|
+
`;
|
|
19
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { WriteStream } from "fs";
|
|
2
|
+
export interface SmokeTestResult {
|
|
3
|
+
status: string;
|
|
4
|
+
verificationPassed: boolean;
|
|
5
|
+
timestamp?: number;
|
|
6
|
+
rawResult?: unknown;
|
|
7
|
+
error?: string;
|
|
8
|
+
serverTimestamp?: number;
|
|
9
|
+
clientTimestamp?: number;
|
|
10
|
+
}
|
|
11
|
+
export interface SmokeTestOptions {
|
|
12
|
+
customPath?: string;
|
|
13
|
+
skipDev?: boolean;
|
|
14
|
+
skipRelease?: boolean;
|
|
15
|
+
skipClient?: boolean;
|
|
16
|
+
projectDir?: string;
|
|
17
|
+
artifactDir?: string;
|
|
18
|
+
keep?: boolean;
|
|
19
|
+
headless?: boolean;
|
|
20
|
+
sync?: boolean;
|
|
21
|
+
ci?: boolean;
|
|
22
|
+
bail?: boolean;
|
|
23
|
+
copyProject?: boolean;
|
|
24
|
+
realtime?: boolean;
|
|
25
|
+
skipHmr?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export interface TestResources {
|
|
28
|
+
tempDirCleanup?: () => Promise<void>;
|
|
29
|
+
workerName?: string;
|
|
30
|
+
originalCwd: string;
|
|
31
|
+
targetDir?: string;
|
|
32
|
+
workerCreatedDuringTest: boolean;
|
|
33
|
+
stopDev?: () => Promise<void>;
|
|
34
|
+
resourceUniqueKey: string;
|
|
35
|
+
}
|
|
36
|
+
export interface StreamCapturer {
|
|
37
|
+
stdoutLogFile: WriteStream | null;
|
|
38
|
+
stderrLogFile: WriteStream | null;
|
|
39
|
+
combinedLogFile: WriteStream | null;
|
|
40
|
+
originalStdoutWrite: (chunk: Uint8Array | string, encoding?: BufferEncoding, callback?: (error?: Error | null) => void) => boolean;
|
|
41
|
+
originalStderrWrite: (chunk: Uint8Array | string, encoding?: BufferEncoding, callback?: (error?: Error | null) => void) => boolean;
|
|
42
|
+
start: (artifactDir: string) => void;
|
|
43
|
+
stop: () => void;
|
|
44
|
+
}
|
|
45
|
+
export interface TestStatus {
|
|
46
|
+
dev: {
|
|
47
|
+
overall: string;
|
|
48
|
+
initialServerSide: string;
|
|
49
|
+
initialClientSide: string;
|
|
50
|
+
initialServerRenderCheck: string;
|
|
51
|
+
realtimeUpgrade: string;
|
|
52
|
+
realtimeServerSide: string;
|
|
53
|
+
realtimeClientSide: string;
|
|
54
|
+
realtimeServerRenderCheck: string;
|
|
55
|
+
initialServerHmr: string;
|
|
56
|
+
initialClientHmr: string;
|
|
57
|
+
realtimeServerHmr: string;
|
|
58
|
+
realtimeClientHmr: string;
|
|
59
|
+
};
|
|
60
|
+
production: {
|
|
61
|
+
overall: string;
|
|
62
|
+
releaseCommand: string;
|
|
63
|
+
initialServerSide: string;
|
|
64
|
+
initialClientSide: string;
|
|
65
|
+
initialServerRenderCheck: string;
|
|
66
|
+
realtimeUpgrade: string;
|
|
67
|
+
realtimeServerSide: string;
|
|
68
|
+
realtimeClientSide: string;
|
|
69
|
+
realtimeServerRenderCheck: string;
|
|
70
|
+
initialServerHmr: string;
|
|
71
|
+
initialClientHmr: string;
|
|
72
|
+
realtimeServerHmr: string;
|
|
73
|
+
realtimeClientHmr: string;
|
|
74
|
+
};
|
|
75
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { log } from "./constants.mjs";
|
|
2
|
+
export { log };
|
|
3
|
+
export declare function isRunningInCI(ciFlag?: boolean): boolean;
|
|
4
|
+
/**
|
|
5
|
+
* Handles test failure by logging the error and initiating teardown
|
|
6
|
+
*/
|
|
7
|
+
export declare function fail(error: unknown, exitCode?: number, step?: string): Promise<never>;
|
|
8
|
+
/**
|
|
9
|
+
* Handles resource teardown and exits the process with appropriate exit code
|
|
10
|
+
*/
|
|
11
|
+
export declare function teardown(): Promise<void>;
|
|
12
|
+
/**
|
|
13
|
+
* Formats the path suffix from a custom path
|
|
14
|
+
*/
|
|
15
|
+
export declare function formatPathSuffix(customPath?: string): string;
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { setTimeout } from "node:timers/promises";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { log } from "./constants.mjs";
|
|
4
|
+
import { mkdirp } from "fs-extra";
|
|
5
|
+
import { state } from "./state.mjs";
|
|
6
|
+
import { generateFinalReport } from "./reporting.mjs";
|
|
7
|
+
import { cleanupResources } from "./cleanup.mjs";
|
|
8
|
+
// Re-export log from constants
|
|
9
|
+
export { log };
|
|
10
|
+
// Helper function to detect if running in CI environment
|
|
11
|
+
export function isRunningInCI(ciFlag = false) {
|
|
12
|
+
return (ciFlag ||
|
|
13
|
+
!!process.env.CI ||
|
|
14
|
+
!!process.env.GITHUB_ACTIONS ||
|
|
15
|
+
!!process.env.GITLAB_CI ||
|
|
16
|
+
!!process.env.CIRCLECI);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Handles test failure by logging the error and initiating teardown
|
|
20
|
+
*/
|
|
21
|
+
export async function fail(error, exitCode = 1, step) {
|
|
22
|
+
state.exitCode = exitCode;
|
|
23
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
24
|
+
console.error(`❌ Smoke test failed: ${msg}`);
|
|
25
|
+
log("Test failed with error: %O", error);
|
|
26
|
+
// Record the failure if a step is provided
|
|
27
|
+
if (step) {
|
|
28
|
+
// Determine the environment context if not explicitly in the step name
|
|
29
|
+
let enhancedStep = step;
|
|
30
|
+
if (!step.toLowerCase().includes("development") &&
|
|
31
|
+
!step.toLowerCase().includes("production") &&
|
|
32
|
+
!step.toLowerCase().includes("dev server")) {
|
|
33
|
+
// For server/client side tests with phase info, add environment context
|
|
34
|
+
const isInReleasePhase = state.failures.some((f) => f.step.includes("Release Command") ||
|
|
35
|
+
f.step.includes("Release Test")) || state.options.skipDev; // If dev is skipped, we're in release phase
|
|
36
|
+
if (isInReleasePhase) {
|
|
37
|
+
enhancedStep = `Production - ${step}`;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
enhancedStep = `Development - ${step}`;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
state.failures.push({
|
|
44
|
+
step: enhancedStep,
|
|
45
|
+
error: msg,
|
|
46
|
+
details: error instanceof Error && error.stack ? error.stack : undefined,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
// Ensure artifactDir exists if it's defined but hasn't been created yet
|
|
50
|
+
if (state.options.artifactDir) {
|
|
51
|
+
try {
|
|
52
|
+
// Create the main artifacts directory and reports subdirectory if they don't exist
|
|
53
|
+
await mkdirp(state.options.artifactDir);
|
|
54
|
+
await mkdirp(join(state.options.artifactDir, "reports"));
|
|
55
|
+
log("Ensured artifact directories exist before teardown");
|
|
56
|
+
}
|
|
57
|
+
catch (dirError) {
|
|
58
|
+
log("Error ensuring artifact directories exist: %O", dirError);
|
|
59
|
+
// Non-fatal, continue to teardown
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
// Generate a report before starting teardown to ensure we have at least one report
|
|
64
|
+
await generateFinalReport();
|
|
65
|
+
// Then proceed with teardown
|
|
66
|
+
await teardown();
|
|
67
|
+
}
|
|
68
|
+
catch (teardownError) {
|
|
69
|
+
// If teardown itself fails, log the error
|
|
70
|
+
console.error(`Error during teardown: ${teardownError instanceof Error ? teardownError.message : String(teardownError)}`);
|
|
71
|
+
// Set a short timeout to allow any pending operations to complete
|
|
72
|
+
await setTimeout(500);
|
|
73
|
+
}
|
|
74
|
+
// Set a short delay to allow report to be written
|
|
75
|
+
await setTimeout(500);
|
|
76
|
+
return process.exit(exitCode);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Handles resource teardown and exits the process with appropriate exit code
|
|
80
|
+
*/
|
|
81
|
+
export async function teardown() {
|
|
82
|
+
// Prevent multiple teardowns running simultaneously
|
|
83
|
+
if (state.isTearingDown) {
|
|
84
|
+
log("Teardown already in progress, skipping duplicate call");
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
state.isTearingDown = true;
|
|
88
|
+
log("Starting teardown process with exit code: %d", state.exitCode);
|
|
89
|
+
try {
|
|
90
|
+
// First, generate a report, before any cleanup happens
|
|
91
|
+
// This ensures we have at least some report even if cleanup fails
|
|
92
|
+
await generateFinalReport();
|
|
93
|
+
// Then try to cleanup resources
|
|
94
|
+
try {
|
|
95
|
+
await cleanupResources(state.resources, state.options);
|
|
96
|
+
log("Resource cleanup completed successfully");
|
|
97
|
+
}
|
|
98
|
+
catch (cleanupError) {
|
|
99
|
+
log("Error during resource cleanup: %O", cleanupError);
|
|
100
|
+
console.error(`Error during resource cleanup: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`);
|
|
101
|
+
// Add this error to our failures list
|
|
102
|
+
state.failures.push({
|
|
103
|
+
step: "Resource Cleanup",
|
|
104
|
+
error: cleanupError instanceof Error
|
|
105
|
+
? cleanupError.message
|
|
106
|
+
: String(cleanupError),
|
|
107
|
+
details: cleanupError instanceof Error && cleanupError.stack
|
|
108
|
+
? cleanupError.stack
|
|
109
|
+
: undefined,
|
|
110
|
+
});
|
|
111
|
+
// Set exit code to 1 if it wasn't already set
|
|
112
|
+
if (state.exitCode === 0)
|
|
113
|
+
state.exitCode = 1;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
log("Error during teardown: %O", error);
|
|
118
|
+
console.error(`Error during teardown: ${error instanceof Error ? error.message : String(error)}`);
|
|
119
|
+
// Set exit code to 1 if it wasn't already set
|
|
120
|
+
if (state.exitCode === 0)
|
|
121
|
+
state.exitCode = 1;
|
|
122
|
+
// Try generating report even if an error occurred
|
|
123
|
+
try {
|
|
124
|
+
await generateFinalReport();
|
|
125
|
+
}
|
|
126
|
+
catch (reportError) {
|
|
127
|
+
console.error("Failed to generate report after teardown error:", reportError);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
finally {
|
|
131
|
+
// Make sure log capturing is stopped before exiting
|
|
132
|
+
log("Log capturing stopped during teardown");
|
|
133
|
+
process.exit(state.exitCode);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Formats the path suffix from a custom path
|
|
138
|
+
*/
|
|
139
|
+
export function formatPathSuffix(customPath) {
|
|
140
|
+
const suffix = customPath
|
|
141
|
+
? customPath.startsWith("/")
|
|
142
|
+
? customPath
|
|
143
|
+
: `/${customPath}`
|
|
144
|
+
: "";
|
|
145
|
+
log("Formatted path suffix: %s", suffix);
|
|
146
|
+
return suffix;
|
|
147
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { interruptors } from "./rules/interruptors.js";
|
|
2
|
+
import { middleware } from "./rules/middleware.js";
|
|
3
|
+
import { react } from "./rules/react.js";
|
|
4
|
+
import { requestResponse } from "./rules/request-response.js";
|
|
5
|
+
const rules = [
|
|
6
|
+
{
|
|
7
|
+
name: "rwsdk-interruptors",
|
|
8
|
+
description: "RedwoodSDK: Request Interruptors",
|
|
9
|
+
rule: interruptors,
|
|
10
|
+
alwaysApply: false,
|
|
11
|
+
globs: ["worker.tsx", "src/app/**/routes.ts", "src/app/**/*/routes.ts"],
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
name: "rwsdk-middleware",
|
|
15
|
+
description: "RedwoodSDK: Middleware",
|
|
16
|
+
rule: middleware,
|
|
17
|
+
alwaysApply: false,
|
|
18
|
+
globs: ["worker.tsx", "middleware.ts", "middleware.tsx"],
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: "rwsdk-react",
|
|
22
|
+
description: "RedwoodSDK: React, React Server Components, and React Server Functions Rules",
|
|
23
|
+
rule: react,
|
|
24
|
+
alwaysApply: false,
|
|
25
|
+
globs: ["src/app/**/*/*.tsx", "Document.tsx"],
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: "rwsdk-request-response",
|
|
29
|
+
description: "RedwoodSDK: Request handling and responses",
|
|
30
|
+
rule: requestResponse,
|
|
31
|
+
alwaysApply: false,
|
|
32
|
+
globs: ["worker.tsc", "src/app/**/routes.ts", "src/app/**/*/routes.ts"],
|
|
33
|
+
},
|
|
34
|
+
];
|
|
35
|
+
export default rules;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const interruptors = "\n\n# RedwoodSDK: Request Interruptors\n\nYou're an expert at Cloudflare, TypeScript, and building web apps with RedwoodSDK. Generate high quality **RedwoodSDK interruptors** (middleware functions) that adhere to the following best practices:\n\n## Guidelines\n\n1. Create focused, single-responsibility interruptors\n2. Organize interruptors in dedicated files (e.g., `interruptors.ts`, `interceptors.ts`, or `middleware.ts`)\n3. Compose interruptors to create more complex validation chains\n4. Use typed parameters and return values\n5. Include clear error handling and user feedback\n\n## What are Interruptors?\n\nInterruptors are middleware functions that run before your route handlers. They can:\n\n- Validate user authentication and authorization\n- Transform request data\n- Validate inputs\n- Rate limit requests\n- Log activity\n- Redirect users based on conditions\n- Short-circuit request handling with early responses\n\n## Example Templates\n\n### Basic Interruptor Structure\n\n```tsx\nasync function myInterruptor({ request, params, ctx }) {\n // Perform checks or transformations here\n\n // Return modified context to pass to the next interruptor or handler\n ctx.someAddedData = \"value\";\n\n // OR return a Response to short-circuit the request\n // return new Response('Unauthorized', { status: 401 });\n}\n```\n\n### Authentication Interruptors\n\n```tsx\nexport async function requireAuth({ request, ctx }) {\n if (!ctx.user) {\n return new Response(null, {\n status: 302,\n headers: { Location: \"/user/login\" },\n });\n }\n}\n\nexport async function requireAdmin({ request, ctx }) {\n if (!ctx?.user?.isAdmin) {\n return new Response(null, {\n status: 302,\n headers: { Location: \"/user/login\" },\n });\n }\n}\n```\n\n### Input Validation Interruptor\n\n```tsx\nimport { z } from \"zod\";\n\n// Create a reusable validator interruptor\nexport function validateInput(schema) {\n return async function validateInputInterruptor({ request, ctx }) {\n try {\n const data = await request.json();\n const validated = (ctx.data = schema.parse(data));\n } catch (error) {\n return Response.json(\n { error: \"Validation failed\", details: error.errors },\n { status: 400 },\n );\n }\n };\n}\n\n// Usage example with a Zod schema\nconst userSchema = z.object({\n name: z.string().min(2),\n email: z.string().email(),\n age: z.number().min(18).optional(),\n});\n\nexport const validateUser = validateInput(userSchema);\n```\n\n### Logging Interruptor\n\n```tsx\nexport async function logRequests({ request, ctx }) {\n const start = Date.now();\n\n // Add a function to the context that will log when called\n ctx.logCompletion: (response) => {\n const duration = Date.now() - start;\n const status = response.status;\n console.log(\n `${request.method} ${request.url} - ${status} (${duration}ms)`,\n );\n },\n };\n}\n\n// Usage in a route handler\nroute('/', [\n logRequests,\n async ({request, ctx}) => {\n // Call the logging function\n ctx.logCompletion(response);\n return Response.json({ success: true });;\n },\n]);\n```\n\n### Composing Multiple Interruptors\n\n```tsx\nimport { route } from \"rwsdk/router\";\nimport {\n requireAuth,\n validateUser,\n apiRateLimit,\n logRequests,\n} from \"@/app/interruptors\";\n\n// Combine multiple interruptors\nroute(\"/api/users\", [\n logRequests, // Log all requests\n requireAuth, // Ensure user is authenticated\n validateUser, // Validate user input\n async ({ request, ctx }) => {\n // Handler receives validated data and session from interruptors\n const newUser = await db.user.create({\n data: {\n /* ... */,\n createdBy: ctx.user.userId,\n },\n });\n\n return Response.json(newUser, { status: 201 });\n },\n ],\n});\n```\n\n### Role-Based Access Control\n\n```tsx\nimport { getSession } from \"rwsdk/auth\";\n\n// Create a function that generates role-based interruptors\nexport function hasRole(allowedRoles) {\n return async function hasRoleInterruptor({ request, ctx }) {\n const session = await getSession(request);\n\n if (!session) {\n return Response.redirect(\"/login\");\n }\n\n if (!allowedRoles.includes(session.role)) {\n return Response.json({ error: \"Unauthorized\" }, { status: 403 });\n }\n\n return { ...ctx, session };\n };\n}\n\n// Create specific role-based interruptors\nexport const isAdmin = hasRole([\"ADMIN\"]);\nexport const isEditor = hasRole([\"ADMIN\", \"EDITOR\"]);\nexport const isUser = hasRole([\"ADMIN\", \"EDITOR\", \"USER\"]);\n```\n\n### Organization with Co-located Interruptors\n\nCreate a file at `./src/app/interruptors.ts`:\n\n```tsx\nimport { getSession } from \"rwsdk/auth\";\n\n// Authentication interruptors\nexport async function requireAuth({ request, ctx }) {\n const session = await getSession(request);\n\n if (!session) {\n return Response.redirect(\"/login\");\n }\n\n return { ...ctx, session };\n}\n\n// Role-based interruptors\nexport function hasRole(allowedRoles) {\n return async function hasRoleInterruptor({ request, ctx }) {\n const session = await getSession(request);\n\n if (!session) {\n return Response.redirect(\"/login\");\n }\n\n if (!allowedRoles.includes(session.role)) {\n return Response.json({ error: \"Unauthorized\" }, { status: 403 });\n }\n\n return { ...ctx, session };\n };\n}\n\nexport const isAdmin = hasRole([\"ADMIN\"]);\nexport const isEditor = hasRole([\"ADMIN\", \"EDITOR\"]);\n\n// Other common interruptors\nexport async function logRequests({ request, ctx }) {\n console.log(`${request.method} ${request.url}`);\n return ctx;\n}\n```\n\nThen import these interruptors in your route files:\n\n```tsx\n// src/app/pages/admin/routes.ts\nimport { route } from \"rwsdk/router\";\nimport { isAdmin, logRequests } from \"@/app/interruptors\";\n\nimport { AdminDashboard } from \"./AdminDashboard\";\nimport { UserManagement } from \"./UserManagement\";\n\nexport const routes = [\n route(\"/\", [isAdmin, logRequests, AdminDashboard]),\n route(\"/users\", [isAdmin, logRequests, UserManagement]),\n];\n```\n\n";
|