@appwarden/middleware 3.4.1 → 3.4.3

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/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  [![GitHub](https://img.shields.io/badge/GitHub-appwarden%2Fmiddleware-181717?logo=github&logoColor=white)](https://github.com/appwarden/middleware)
5
5
  [![npm version](https://img.shields.io/npm/v/@appwarden/middleware.svg)](https://www.npmjs.com/package/@appwarden/middleware)
6
6
  [![npm provenance](https://img.shields.io/badge/npm-provenance-green)](https://docs.npmjs.com/generating-provenance-statements)
7
- ![Test Coverage](https://img.shields.io/badge/coverage-91.52%25-brightgreen)
7
+ ![Test Coverage](https://img.shields.io/badge/coverage-91.55%25-brightgreen)
8
8
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
9
9
 
10
10
  ## Core Features
@@ -0,0 +1,6 @@
1
+ // src/utils/get-now.ts
2
+ var getNowMs = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
3
+
4
+ export {
5
+ getNowMs
6
+ };
@@ -0,0 +1,11 @@
1
+ // src/utils/is-response-like.ts
2
+ var isResponseLike = (value) => {
3
+ if (!value || typeof value !== "object") return false;
4
+ const candidate = value;
5
+ const headers = candidate.headers;
6
+ return !!(headers && typeof headers === "object" && typeof headers.has === "function" && typeof headers.set === "function" && typeof headers.get === "function");
7
+ };
8
+
9
+ export {
10
+ isResponseLike
11
+ };
@@ -1,6 +1,12 @@
1
+ import {
2
+ isResponseLike
3
+ } from "../chunk-XFG6SUSV.js";
1
4
  import {
2
5
  useContentSecurityPolicy
3
6
  } from "../chunk-AXWJZE7U.js";
7
+ import {
8
+ getNowMs
9
+ } from "../chunk-X7WZVYQS.js";
4
10
  import {
5
11
  validateConfig
6
12
  } from "../chunk-MNGMTDH3.js";
@@ -40,7 +46,6 @@ var AstroCloudflareConfigSchema = z.object({
40
46
  });
41
47
 
42
48
  // src/adapters/astro-cloudflare.ts
43
- var getNowMs = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
44
49
  function createAppwardenMiddleware(configFn) {
45
50
  return async (context, next) => {
46
51
  const startTime = getNowMs();
@@ -96,7 +101,7 @@ function createAppwardenMiddleware(configFn) {
96
101
  }
97
102
  debugFn("Website is unlocked");
98
103
  const response = await next();
99
- if (config.contentSecurityPolicy) {
104
+ if (config.contentSecurityPolicy && isResponseLike(response)) {
100
105
  debugFn("Applying CSP middleware");
101
106
  const cspContext = {
102
107
  request,
@@ -119,7 +124,7 @@ function createAppwardenMiddleware(configFn) {
119
124
  debugFn(`Middleware executed in ${elapsed}ms`);
120
125
  return response;
121
126
  } catch (error) {
122
- if (error instanceof Response) {
127
+ if (isResponseLike(error)) {
123
128
  throw error;
124
129
  }
125
130
  console.error(
@@ -1,3 +1,6 @@
1
+ import {
2
+ getNowMs
3
+ } from "../chunk-X7WZVYQS.js";
1
4
  import {
2
5
  validateConfig
3
6
  } from "../chunk-MNGMTDH3.js";
@@ -52,7 +55,6 @@ var NextJsCloudflareConfigSchema = z.object({
52
55
  });
53
56
 
54
57
  // src/adapters/nextjs-cloudflare.ts
55
- var getNowMs = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
56
58
  function createAppwardenMiddleware(configFn) {
57
59
  return async (request, _event) => {
58
60
  const startTime = getNowMs();
@@ -1,6 +1,12 @@
1
+ import {
2
+ isResponseLike
3
+ } from "../chunk-XFG6SUSV.js";
1
4
  import {
2
5
  useContentSecurityPolicy
3
6
  } from "../chunk-AXWJZE7U.js";
7
+ import {
8
+ getNowMs
9
+ } from "../chunk-X7WZVYQS.js";
4
10
  import {
5
11
  validateConfig
6
12
  } from "../chunk-MNGMTDH3.js";
@@ -42,7 +48,6 @@ var ReactRouterCloudflareConfigSchema = z.object({
42
48
  var cloudflareContextSymbol = /* @__PURE__ */ Symbol.for(
43
49
  "@appwarden/middleware:cloudflare"
44
50
  );
45
- var getNowMs = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
46
51
  function getCloudflareContext(context) {
47
52
  if (context?.cloudflare) {
48
53
  return context.cloudflare;
@@ -106,7 +111,7 @@ function createAppwardenMiddleware(configFn) {
106
111
  }
107
112
  debugFn("Website is unlocked");
108
113
  const response = await next();
109
- if (config.contentSecurityPolicy && response instanceof Response) {
114
+ if (config.contentSecurityPolicy && isResponseLike(response)) {
110
115
  debugFn("Applying CSP middleware");
111
116
  const cspContext = {
112
117
  request,
@@ -129,7 +134,7 @@ function createAppwardenMiddleware(configFn) {
129
134
  debugFn(`Middleware executed in ${elapsed}ms`);
130
135
  return response;
131
136
  } catch (error) {
132
- if (error instanceof Response) {
137
+ if (isResponseLike(error)) {
133
138
  throw error;
134
139
  }
135
140
  console.error(
@@ -29,48 +29,55 @@ interface TanStackStartAppwardenConfig {
29
29
  * This allows dynamic configuration based on environment variables.
30
30
  */
31
31
  type TanStackStartConfigFn = (cloudflare: TanStackStartCloudflareContext) => TanStackStartAppwardenConfig;
32
+ /**
33
+ * The result returned by the `next()` function in TanStack Start request middleware.
34
+ *
35
+ * Mirrors the internal `RequestServerResult` interface from `@tanstack/start-client-core`
36
+ * without importing from an unstable internal package path.
37
+ */
38
+ interface TanStackStartNextResult {
39
+ request: Request;
40
+ pathname: string;
41
+ context: Record<string, unknown>;
42
+ response: Response;
43
+ }
44
+ /**
45
+ * The `next()` function passed to TanStack Start request middleware.
46
+ *
47
+ * Mirrors the internal `RequestServerNextFn` signature.
48
+ */
49
+ type TanStackStartNextFn = (options?: {
50
+ context?: Record<string, unknown>;
51
+ }) => Promise<TanStackStartNextResult>;
32
52
  /**
33
53
  * TanStack Start middleware server callback arguments.
34
- * This matches the shape of arguments passed to createMiddleware().server().
54
+ *
55
+ * Mirrors the official TanStack Start `RequestServerOptions` interface, with
56
+ * an additional optional `cloudflare` context property for Cloudflare
57
+ * Workers deployments.
35
58
  */
36
59
  interface TanStackStartMiddlewareArgs {
37
60
  request: Request;
38
- next: () => Promise<unknown>;
61
+ pathname: string;
39
62
  context: {
40
63
  cloudflare?: TanStackStartCloudflareContext;
41
64
  [key: string]: unknown;
42
65
  };
66
+ next: TanStackStartNextFn;
67
+ serverFnMeta?: unknown;
43
68
  }
44
69
  /**
45
70
  * TanStack Start middleware function signature.
46
- * This matches the return type of createMiddleware().server().
71
+ *
72
+ * Mirrors the official TanStack Start `RequestServerFn` type used for
73
+ * request middleware server functions.
47
74
  */
48
- type TanStackStartMiddlewareFunction = (args: TanStackStartMiddlewareArgs) => Promise<unknown>;
75
+ type TanStackStartMiddlewareFunction = (args: TanStackStartMiddlewareArgs) => Promise<TanStackStartNextResult | Response>;
49
76
  /**
50
- * Creates an Appwarden middleware function for TanStack Start.
51
- *
52
- * This middleware checks if the site is locked and throws a redirect to the lock page if so.
53
- * It should be added to the `requestMiddleware` array in your `src/start.ts` file.
54
- *
55
- * @example
56
- * ```typescript
57
- * // src/start.ts
58
- * import { createStart } from "@tanstack/react-start"
59
- * import { createAppwardenMiddleware } from "@appwarden/middleware/tanstack-start"
60
- *
61
- * const appwardenMiddleware = createAppwardenMiddleware(({ env }) => ({
62
- * lockPageSlug: env.APPWARDEN_LOCK_PAGE_SLUG,
63
- * appwardenApiToken: env.APPWARDEN_API_TOKEN,
64
- * }))
65
- *
66
- * export const startInstance = createStart(() => ({
67
- * requestMiddleware: [appwardenMiddleware],
68
- * }))
69
- * ```
70
77
  *
71
78
  * @param configFn - A function that receives the Cloudflare context and returns the config
72
79
  * @returns A TanStack Start middleware function
73
80
  */
74
81
  declare function createAppwardenMiddleware(configFn: TanStackStartConfigFn): TanStackStartMiddlewareFunction;
75
82
 
76
- export { type TanStackStartAppwardenConfig, type TanStackStartCloudflareContext, type TanStackStartConfigFn, type TanStackStartMiddlewareArgs, type TanStackStartMiddlewareFunction, createAppwardenMiddleware };
83
+ export { type TanStackStartAppwardenConfig, type TanStackStartCloudflareContext, type TanStackStartConfigFn, type TanStackStartMiddlewareArgs, type TanStackStartMiddlewareFunction, type TanStackStartNextFn, type TanStackStartNextResult, createAppwardenMiddleware };
@@ -1,6 +1,12 @@
1
+ import {
2
+ isResponseLike
3
+ } from "../chunk-XFG6SUSV.js";
1
4
  import {
2
5
  useContentSecurityPolicy
3
6
  } from "../chunk-AXWJZE7U.js";
7
+ import {
8
+ getNowMs
9
+ } from "../chunk-X7WZVYQS.js";
4
10
  import {
5
11
  validateConfig
6
12
  } from "../chunk-MNGMTDH3.js";
@@ -39,9 +45,8 @@ var TanStackStartCloudflareConfigSchema = z.object({
39
45
  });
40
46
 
41
47
  // src/adapters/tanstack-start-cloudflare.ts
42
- var getNowMs = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
43
48
  function createAppwardenMiddleware(configFn) {
44
- return async (args) => {
49
+ const middleware = async (args) => {
45
50
  const startTime = getNowMs();
46
51
  const { request, next, context } = args;
47
52
  try {
@@ -49,7 +54,7 @@ function createAppwardenMiddleware(configFn) {
49
54
  if (!cloudflare) {
50
55
  console.error(
51
56
  printMessage(
52
- "Cloudflare context not found. Ensure running on Cloudflare Workers with proper context setup."
57
+ "Cloudflare context not found in TanStack Start context. Ensure your Register type includes the cloudflare context, or pass it manually in the middleware wrapper."
53
58
  )
54
59
  );
55
60
  return next();
@@ -76,7 +81,7 @@ function createAppwardenMiddleware(configFn) {
76
81
  debugFn("Already on lock page - skipping");
77
82
  return next();
78
83
  }
79
- const result = await checkLockStatus({
84
+ const lockStatus = await checkLockStatus({
80
85
  request,
81
86
  appwardenApiToken: config.appwardenApiToken,
82
87
  appwardenApiHostname: config.appwardenApiHostname,
@@ -84,14 +89,15 @@ function createAppwardenMiddleware(configFn) {
84
89
  lockPageSlug: config.lockPageSlug,
85
90
  waitUntil: (fn) => cloudflare.ctx.waitUntil(fn)
86
91
  });
87
- if (result.isLocked) {
92
+ if (lockStatus.isLocked) {
88
93
  const lockPageUrl = buildLockPageUrl(config.lockPageSlug, request.url);
89
94
  debugFn(`Website is locked - redirecting to ${lockPageUrl.pathname}`);
90
95
  throw createRedirect(lockPageUrl);
91
96
  }
92
97
  debugFn("Website is unlocked");
93
- const response = await next();
94
- if (config.contentSecurityPolicy && response instanceof Response) {
98
+ const result = await next();
99
+ const { response } = result;
100
+ if (config.contentSecurityPolicy && isResponseLike(response)) {
95
101
  debugFn("Applying CSP middleware");
96
102
  const cspContext = {
97
103
  request,
@@ -108,13 +114,16 @@ function createAppwardenMiddleware(configFn) {
108
114
  );
109
115
  const elapsed2 = Math.round(getNowMs() - startTime);
110
116
  debugFn(`Middleware executed in ${elapsed2}ms`);
111
- return cspContext.response;
117
+ return {
118
+ ...result,
119
+ response: cspContext.response
120
+ };
112
121
  }
113
122
  const elapsed = Math.round(getNowMs() - startTime);
114
123
  debugFn(`Middleware executed in ${elapsed}ms`);
115
- return response;
124
+ return result;
116
125
  } catch (error) {
117
- if (error instanceof Response) {
126
+ if (isResponseLike(error)) {
118
127
  throw error;
119
128
  }
120
129
  console.error(
@@ -125,6 +134,7 @@ function createAppwardenMiddleware(configFn) {
125
134
  return next();
126
135
  }
127
136
  };
137
+ return middleware;
128
138
  }
129
139
  export {
130
140
  createAppwardenMiddleware
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appwarden/middleware",
3
- "version": "3.4.1",
3
+ "version": "3.4.3",
4
4
  "description": "Instantly shut off access your app deployed on Cloudflare or Vercel",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -65,6 +65,7 @@
65
65
  "peerDependencies": {
66
66
  "@astrojs/cloudflare": ">=11.0.0",
67
67
  "@opennextjs/cloudflare": ">=1.16.6",
68
+ "@tanstack/start": "^1.120.20",
68
69
  "@vercel/functions": ">=1.0.0",
69
70
  "astro": ">=4.0.0",
70
71
  "next": ">=14"
@@ -82,6 +83,9 @@
82
83
  "@opennextjs/cloudflare": {
83
84
  "optional": true
84
85
  },
86
+ "@tanstack/start": {
87
+ "optional": true
88
+ },
85
89
  "@vercel/functions": {
86
90
  "optional": true
87
91
  }
@@ -106,10 +110,13 @@
106
110
  "wrangler@>=4.0.0 <4.59.1": ">=4.59.1",
107
111
  "qs@>=6.7.0 <=6.14.1": ">=6.14.2",
108
112
  "devalue@<=5.6.2": ">=5.6.3",
109
- "minimatch@<10.2.1": ">=10.2.1",
113
+ "minimatch@<10.2.1": ">=10.2.3",
110
114
  "tar@<7.5.8": ">=7.5.8",
111
115
  "ajv@>=7.0.0-alpha.0 <8.18.0": ">=8.18.0",
112
- "rollup@>=4.0.0 <4.59.0": ">=4.59.0"
116
+ "rollup@>=4.0.0 <4.59.0": ">=4.59.0",
117
+ "h3@<=1.15.4": ">=1.15.5",
118
+ "js-yaml@<3.14.2": ">=3.14.2",
119
+ "fast-xml-parser@<5.3.8": ">=5.3.8"
113
120
  }
114
121
  }
115
122
  }