@appwarden/middleware 3.8.0 → 3.9.0

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-92%25-brightgreen)
7
+ ![Test Coverage](https://img.shields.io/badge/coverage-92.72%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
@@ -39,11 +39,13 @@ The path or route (for example, `/maintenance`) to redirect users to when the do
39
39
  This should be a working page on your site, such as a maintenance or status page, that
40
40
  explains why the website is temporarily unavailable.
41
41
 
42
- ### `contentSecurityPolicy`
42
+ ### `contentSecurityPolicy` (optional)
43
43
 
44
- Controls the [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) headers that Appwarden adds.
44
+ Controls the [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) headers that Appwarden adds. This configuration is optional—if not provided, no CSP header will be applied.
45
45
 
46
- - `mode` (optional) controls how the CSP is applied:
46
+ When provided, both `mode` and `directives` are required:
47
+
48
+ - `mode` controls how the CSP is applied:
47
49
  - `"disabled"` – no CSP header is sent.
48
50
  - `"report-only"` – sends the `Content-Security-Policy-Report-Only` header so violations are
49
51
  reported (for example in the browser console) but not blocked.
@@ -52,7 +54,7 @@ Controls the [Content Security Policy](https://developer.mozilla.org/en-US/docs/
52
54
  When developing or iterating on your CSP, we recommend starting with `"report-only"` so you can
53
55
  identify and fix violations before switching to `"enforced"`.
54
56
 
55
- - `directives` (optional) is an object whose keys are CSP directive names and whose values are
57
+ - `directives` is an object whose keys are CSP directive names and whose values are
56
58
  arrays of allowed sources. For example:
57
59
 
58
60
  ```ts
@@ -60,6 +62,7 @@ Controls the [Content Security Policy](https://developer.mozilla.org/en-US/docs/
60
62
  mode: "enforced",
61
63
  directives: {
62
64
  "script-src": ["'self'", "{{nonce}}"],
65
+ "style-src": ["'self'", "{{nonce}}"],
63
66
  },
64
67
  }
65
68
  ```
@@ -108,7 +111,7 @@ The **Universal Middleware** (`@appwarden/middleware/cloudflare`) is the recomme
108
111
  import { createAppwardenMiddleware } from "@appwarden/middleware/cloudflare"
109
112
 
110
113
  const appwardenHandler = createAppwardenMiddleware((cloudflare) => ({
111
- debug: cloudflare.env.DEBUG === "true",
114
+ debug: cloudflare.env.DEBUG,
112
115
  lockPageSlug: cloudflare.env.LOCK_PAGE_SLUG,
113
116
  appwardenApiToken: cloudflare.env.APPWARDEN_API_TOKEN,
114
117
  contentSecurityPolicy: {
@@ -142,12 +145,12 @@ import { createAppwardenMiddleware } from "@appwarden/middleware/cloudflare/astr
142
145
  const appwarden = createAppwardenMiddleware((cloudflare) => ({
143
146
  lockPageSlug: cloudflare.env.APPWARDEN_LOCK_PAGE_SLUG,
144
147
  appwardenApiToken: cloudflare.env.APPWARDEN_API_TOKEN,
145
- debug: cloudflare.env.APPWARDEN_DEBUG === "true",
148
+ debug: cloudflare.env.DEBUG,
146
149
  contentSecurityPolicy: {
147
- mode: "enforced",
150
+ // See Configuration > contentSecurityPolicy section for details
151
+ mode: "report-only",
148
152
  directives: {
149
- "script-src": ["'self'", "{{nonce}}"],
150
- "style-src": ["'self'", "{{nonce}}"],
153
+ "default-src": ["'self'"],
151
154
  },
152
155
  },
153
156
  }))
@@ -159,55 +162,59 @@ See the [Astro + Cloudflare guide](https://appwarden.io/docs/guides/astro-cloudf
159
162
 
160
163
  ##### React Router on Cloudflare
161
164
 
165
+ - Set `future.v8_middleware: true` in your `react-router.config.ts` file
166
+
162
167
  ```ts
163
168
  // app/root.tsx
169
+ import { env } from "cloudflare:workers"
164
170
  import { createAppwardenMiddleware } from "@appwarden/middleware/cloudflare/react-router"
165
171
 
166
- export const unstable_middleware = [
167
- createAppwardenMiddleware(({ env }) => ({
172
+ export const middleware = [
173
+ createAppwardenMiddleware(() => ({
168
174
  lockPageSlug: env.APPWARDEN_LOCK_PAGE_SLUG,
169
175
  appwardenApiToken: env.APPWARDEN_API_TOKEN,
170
176
  // "debug" can be a string or boolean; the schema will normalize it
171
- debug: env.APPWARDEN_DEBUG,
177
+ debug: env.DEBUG,
172
178
  // "directives" can be a JSON string or an object; the schema will parse it
173
179
  contentSecurityPolicy: {
174
- mode: "enforced",
175
- directives: env.APPWARDEN_CSP_DIRECTIVES,
180
+ // See Configuration > contentSecurityPolicy section for details
181
+ mode: "report-only",
182
+ directives: {
183
+ "default-src": ["'self'"],
184
+ },
176
185
  },
177
186
  })),
178
187
  ]
179
188
  ```
180
189
 
181
- See the [React Router + Cloudflare guide](https://appwarden.io/docs/guides/react-router-cloudflare) for full usage and context setup.
190
+ See the [React Router + Cloudflare guide](https://appwarden.io/docs/guides/react-router-cloudflare) for more details.
182
191
 
183
192
  ##### TanStack Start on Cloudflare
184
193
 
185
194
  ```ts
186
195
  // start.ts
187
196
  import { createMiddleware } from "@tanstack/start"
188
- import { env, waitUntil } from "cloudflare:workers"
197
+ import { env } from "cloudflare:workers"
189
198
  import { createAppwardenMiddleware } from "@appwarden/middleware/cloudflare/tanstack-start"
190
199
 
191
- const appwardenMiddleware = createAppwardenMiddleware(({ env }) => ({
192
- lockPageSlug: env.APPWARDEN_LOCK_PAGE_SLUG,
193
- appwardenApiToken: env.APPWARDEN_API_TOKEN,
194
- debug: env.APPWARDEN_DEBUG, // Accepts string or boolean
195
- contentSecurityPolicy: {
196
- mode: "enforced",
197
- directives: {
198
- "script-src": ["'self'", "{{nonce}}"],
199
- "style-src": ["'self'", "{{nonce}}"],
200
+ const appwardenMiddleware = createMiddleware().server(
201
+ createAppwardenMiddleware(() => ({
202
+ lockPageSlug: env.APPWARDEN_LOCK_PAGE_SLUG,
203
+ appwardenApiToken: env.APPWARDEN_API_TOKEN,
204
+ debug: env.DEBUG, // Accepts string or boolean
205
+ contentSecurityPolicy: {
206
+ // See Configuration > contentSecurityPolicy section for details
207
+ mode: "report-only",
208
+ directives: {
209
+ "default-src": ["'self'"],
210
+ },
200
211
  },
201
- },
202
- }))
212
+ })),
213
+ )
203
214
 
204
- export default createMiddleware().server(async ({ next, request }) => {
205
- return await appwardenMiddleware({
206
- request,
207
- next,
208
- context: { env, waitUntil },
209
- })
210
- })
215
+ export const startInstance = createStart(() => ({
216
+ requestMiddleware: [appwardenMiddleware],
217
+ }))
211
218
  ```
212
219
 
213
220
  See the [TanStack Start + Cloudflare guide](https://appwarden.io/docs/guides/tanstack-start-cloudflare) for more details.
@@ -225,13 +232,13 @@ export const config = {
225
232
  export default createAppwardenMiddleware((cloudflare) => ({
226
233
  lockPageSlug: cloudflare.env.APPWARDEN_LOCK_PAGE_SLUG,
227
234
  appwardenApiToken: cloudflare.env.APPWARDEN_API_TOKEN,
228
- debug: cloudflare.env.APPWARDEN_DEBUG === "true",
235
+ debug: cloudflare.env.DEBUG,
229
236
  // Headers-only CSP (no HTML rewriting, no nonce support; do not use `{{nonce}}` here)
230
237
  contentSecurityPolicy: {
231
- mode: "report-only",
238
+ // See Configuration > contentSecurityPolicy section for details
239
+ mode: "enforced",
232
240
  directives: {
233
- "script-src": ["'self'"],
234
- "style-src": ["'self'", "'unsafe-inline'"],
241
+ "default-src": ["'self'"],
235
242
  },
236
243
  },
237
244
  }))
@@ -246,25 +253,22 @@ To use Appwarden as Vercel Edge Middleware, use the `@appwarden/middleware/verce
246
253
  ```ts
247
254
  // middleware.ts (Next.js app on Vercel)
248
255
  import { createAppwardenMiddleware } from "@appwarden/middleware/vercel"
249
- import type { VercelMiddlewareFunction } from "@appwarden/middleware/vercel"
250
-
251
- const appwardenMiddleware: VercelMiddlewareFunction = createAppwardenMiddleware(
252
- {
253
- // Edge Config or Upstash KV URL
254
- cacheUrl: process.env.APPWARDEN_CACHE_URL!,
255
- // Required when using Vercel Edge Config
256
- vercelApiToken: process.env.APPWARDEN_VERCEL_API_TOKEN!,
257
- appwardenApiToken: process.env.APPWARDEN_API_TOKEN!,
258
- lockPageSlug: "/maintenance",
259
- contentSecurityPolicy: {
260
- mode: "report-only",
261
- directives: {
262
- "script-src": ["'self'"],
263
- "style-src": ["'self'", "'unsafe-inline'"],
264
- },
256
+
257
+ const appwardenMiddleware = createAppwardenMiddleware({
258
+ // Edge Config or Upstash KV URL
259
+ cacheUrl: process.env.APPWARDEN_CACHE_URL!,
260
+ // Required when using Vercel Edge Config
261
+ vercelApiToken: process.env.APPWARDEN_VERCEL_API_TOKEN!,
262
+ appwardenApiToken: process.env.APPWARDEN_API_TOKEN!,
263
+ lockPageSlug: "/maintenance",
264
+ contentSecurityPolicy: {
265
+ // See Configuration > contentSecurityPolicy section for details
266
+ mode: "report-only",
267
+ directives: {
268
+ "default-src": ["'self'"],
265
269
  },
266
270
  },
267
- )
271
+ })
268
272
 
269
273
  export default appwardenMiddleware
270
274
  ```
@@ -293,7 +297,6 @@ Contributions are welcome! Please feel free to submit a Pull Request.
293
297
  - `fix: resolve issue with X`
294
298
  - `docs: update README`
295
299
  - `chore: update dependencies`
296
- - `refactor: improve code structure`
297
300
  - `test: add tests for feature X`
298
301
  4. Push to the branch (`git push origin feature/amazing-feature`)
299
302
  5. Open a Pull Request
@@ -1,17 +1,17 @@
1
1
  import {
2
2
  MemoryCache,
3
3
  debug
4
- } from "./chunk-EPJ4ZVO6.js";
4
+ } from "./chunk-Z7FIMIZS.js";
5
5
  import {
6
6
  APPWARDEN_CACHE_KEY,
7
7
  APPWARDEN_TEST_ROUTE
8
- } from "./chunk-HCGLR3Z3.js";
8
+ } from "./chunk-UIIYORBW.js";
9
9
  import {
10
10
  deleteEdgeValue,
11
11
  getLockValue,
12
12
  store,
13
13
  syncEdgeValue
14
- } from "./chunk-GK6JL5NZ.js";
14
+ } from "./chunk-QGXPAVOA.js";
15
15
 
16
16
  // src/core/check-lock-status.ts
17
17
  var createContext = async (config) => {
@@ -116,8 +116,7 @@ var AppwardenApiTokenSchema = z.string().refine((val) => !!val, { message: "appw
116
116
  var LockValue = z.object({
117
117
  isLocked: z.number(),
118
118
  isLockedTest: z.number(),
119
- lastCheck: z.number(),
120
- code: z.string()
119
+ lastCheck: z.number()
121
120
  });
122
121
 
123
122
  // src/utils/errors.ts
@@ -160,8 +159,7 @@ var getLockValue = async (context) => {
160
159
  let cacheResponse, lockValue = {
161
160
  isLocked: 0,
162
161
  isLockedTest: 0,
163
- lastCheck: Date.now(),
164
- code: ""
162
+ lastCheck: Date.now()
165
163
  };
166
164
  switch (context.provider) {
167
165
  case "cloudflare-cache": {
@@ -259,7 +257,7 @@ var syncEdgeValue = async (context) => {
259
257
  const apiHostname = context.appwardenApiHostname ?? DEFAULT_API_HOSTNAME;
260
258
  context.debug(`GET ${apiHostname}`);
261
259
  try {
262
- const response = await fetch(new URL("/v1/status/check", apiHostname), {
260
+ const response = await fetch(new URL("/v1/appwarden/status", apiHostname), {
263
261
  method: "POST",
264
262
  headers: { "content-type": "application/json" },
265
263
  body: JSON.stringify({
@@ -57,10 +57,10 @@ var CSPModeSchema = z2.union([
57
57
  z2.literal("disabled"),
58
58
  z2.literal("report-only"),
59
59
  z2.literal("enforced")
60
- ]).optional().default("disabled");
60
+ ]);
61
61
  var UseCSPInputSchema = z2.object({
62
62
  mode: CSPModeSchema,
63
- directives: CSPDirectivesSchema.optional().refine(
63
+ directives: CSPDirectivesSchema.refine(
64
64
  (val) => {
65
65
  try {
66
66
  if (typeof val === "string") {
@@ -75,13 +75,7 @@ var UseCSPInputSchema = z2.object({
75
75
  ).transform(
76
76
  (val) => typeof val === "string" ? JSON.parse(val) : val
77
77
  )
78
- }).refine(
79
- (values) => (
80
- // validate that directives are provided when the mode is "report-only" or "enforced"
81
- ["report-only", "enforced"].includes(values.mode) ? !!values.directives : true
82
- ),
83
- { path: ["directives"], message: "DirectivesRequired" /* DirectivesRequired */ }
84
- );
78
+ });
85
79
 
86
80
  export {
87
81
  LOCKDOWN_TEST_EXPIRY_MS,
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  UseCSPInputSchema,
3
3
  isHTMLResponse
4
- } from "./chunk-HCGLR3Z3.js";
4
+ } from "./chunk-UIIYORBW.js";
5
5
  import {
6
6
  makeCSPHeader
7
- } from "./chunk-GK6JL5NZ.js";
7
+ } from "./chunk-QGXPAVOA.js";
8
8
 
9
9
  // src/middlewares/use-content-security-policy.ts
10
10
  var AppendAttribute = (attribute, nonce) => ({
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  LOCKDOWN_TEST_EXPIRY_MS
3
- } from "./chunk-HCGLR3Z3.js";
3
+ } from "./chunk-UIIYORBW.js";
4
4
  import {
5
5
  printMessage
6
- } from "./chunk-GK6JL5NZ.js";
6
+ } from "./chunk-QGXPAVOA.js";
7
7
 
8
8
  // src/utils/build-lock-page-url.ts
9
9
  function normalizeLockPageSlug(lockPageSlug) {