@appwarden/middleware 1.5.1 → 1.6.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.
@@ -0,0 +1,60 @@
1
+ import { NextRequest, NextFetchEvent, NextResponse } from 'next/server';
2
+
3
+ /**
4
+ * Cloudflare runtime context provided by @opennextjs/cloudflare.
5
+ * This is the shape of the context returned by getCloudflareContext().
6
+ */
7
+ interface NextJsCloudflareRuntime {
8
+ env: CloudflareEnv;
9
+ ctx: ExecutionContext;
10
+ }
11
+ /**
12
+ * Configuration for the Appwarden middleware.
13
+ */
14
+ interface NextJsCloudflareAppwardenConfig {
15
+ /** The slug/path of the lock page to redirect to when the site is locked */
16
+ lockPageSlug: string;
17
+ /** The Appwarden API token for authentication */
18
+ appwardenApiToken: string;
19
+ /** Optional custom API hostname (defaults to https://api.appwarden.io) */
20
+ appwardenApiHostname?: string;
21
+ /** Enable debug logging */
22
+ debug?: boolean;
23
+ }
24
+ /**
25
+ * Configuration function that receives the Cloudflare runtime and returns the config.
26
+ * This allows dynamic configuration based on environment variables.
27
+ */
28
+ type NextJsCloudflareConfigFn = (runtime: NextJsCloudflareRuntime) => NextJsCloudflareAppwardenConfig;
29
+ /**
30
+ * Next.js middleware function signature.
31
+ * Compatible with both middleware.ts and proxy.ts (Next.js 16+).
32
+ */
33
+ type NextJsMiddlewareFunction = (request: NextRequest, event?: NextFetchEvent) => Promise<NextResponse>;
34
+ /**
35
+ * Creates an Appwarden middleware function for Next.js on Cloudflare.
36
+ *
37
+ * This middleware checks if the site is locked and redirects to the lock page if so.
38
+ * It uses @opennextjs/cloudflare to access Cloudflare bindings and context.
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * // middleware.ts (or proxy.ts for Next.js 16+)
43
+ * import { createAppwardenMiddleware } from "@appwarden/middleware/opennext-cloudflare"
44
+ *
45
+ * export const config = {
46
+ * matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
47
+ * }
48
+ *
49
+ * export default createAppwardenMiddleware(({ env }) => ({
50
+ * lockPageSlug: env.APPWARDEN_LOCK_PAGE_SLUG,
51
+ * appwardenApiToken: env.APPWARDEN_API_TOKEN,
52
+ * }))
53
+ * ```
54
+ *
55
+ * @param configFn - A function that receives the Cloudflare runtime and returns the config
56
+ * @returns A Next.js middleware function
57
+ */
58
+ declare function createAppwardenMiddleware(configFn: NextJsCloudflareConfigFn): NextJsMiddlewareFunction;
59
+
60
+ export { type NextJsCloudflareAppwardenConfig, type NextJsCloudflareConfigFn, type NextJsCloudflareRuntime, type NextJsMiddlewareFunction, createAppwardenMiddleware };
@@ -0,0 +1,77 @@
1
+ import {
2
+ TEMPORARY_REDIRECT_STATUS,
3
+ buildLockPageUrl
4
+ } from "../chunk-N6AUTMZO.js";
5
+ import {
6
+ validateConfig
7
+ } from "../chunk-6PUA5YXP.js";
8
+ import {
9
+ checkLockStatus
10
+ } from "../chunk-5DEXVBY6.js";
11
+ import {
12
+ AppwardenApiTokenSchema,
13
+ BooleanSchema
14
+ } from "../chunk-B5IE7V77.js";
15
+ import {
16
+ isHTMLRequest,
17
+ printMessage
18
+ } from "../chunk-7UTT3M2S.js";
19
+
20
+ // src/adapters/nextjs-cloudflare.ts
21
+ import {
22
+ NextResponse
23
+ } from "next/server";
24
+
25
+ // src/schemas/nextjs-cloudflare.ts
26
+ import { z } from "zod";
27
+ var NextJsCloudflareConfigSchema = z.object({
28
+ /** The slug/path of the lock page to redirect to when the site is locked */
29
+ lockPageSlug: z.string(),
30
+ /** The Appwarden API token for authentication */
31
+ appwardenApiToken: AppwardenApiTokenSchema,
32
+ /** Optional custom API hostname (defaults to https://api.appwarden.io) */
33
+ appwardenApiHostname: z.string().optional(),
34
+ /** Enable debug logging */
35
+ debug: BooleanSchema.default(false)
36
+ });
37
+
38
+ // src/adapters/nextjs-cloudflare.ts
39
+ function createAppwardenMiddleware(configFn) {
40
+ return async (request, _event) => {
41
+ try {
42
+ const { getCloudflareContext } = await import("@opennextjs/cloudflare");
43
+ const { env, ctx } = await getCloudflareContext();
44
+ if (!isHTMLRequest(request)) {
45
+ return NextResponse.next();
46
+ }
47
+ const config = configFn({ env, ctx });
48
+ const hasError = validateConfig(config, NextJsCloudflareConfigSchema);
49
+ if (hasError) {
50
+ return NextResponse.next();
51
+ }
52
+ const result = await checkLockStatus({
53
+ request,
54
+ appwardenApiToken: config.appwardenApiToken,
55
+ appwardenApiHostname: config.appwardenApiHostname,
56
+ debug: config.debug,
57
+ lockPageSlug: config.lockPageSlug,
58
+ waitUntil: (fn) => ctx.waitUntil(fn)
59
+ });
60
+ if (result.isLocked) {
61
+ const lockPageUrl = buildLockPageUrl(config.lockPageSlug, request.url);
62
+ return NextResponse.redirect(lockPageUrl, TEMPORARY_REDIRECT_STATUS);
63
+ }
64
+ return NextResponse.next();
65
+ } catch (error) {
66
+ console.error(
67
+ printMessage(
68
+ `Unhandled error: ${error instanceof Error ? error.message : String(error)}`
69
+ )
70
+ );
71
+ return NextResponse.next();
72
+ }
73
+ };
74
+ }
75
+ export {
76
+ createAppwardenMiddleware
77
+ };
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Cloudflare context provided by React Router on Cloudflare Workers.
3
+ * This is the shape of `context.cloudflare` in React Router loaders/actions.
4
+ */
5
+ interface CloudflareContext {
6
+ env: CloudflareEnv;
7
+ ctx: ExecutionContext;
8
+ }
9
+ /**
10
+ * Configuration for the Appwarden middleware.
11
+ */
12
+ interface ReactRouterAppwardenConfig {
13
+ /** The slug/path of the lock page to redirect to when the site is locked */
14
+ lockPageSlug: string;
15
+ /** The Appwarden API token for authentication */
16
+ appwardenApiToken: string;
17
+ /** Optional custom API hostname (defaults to https://api.appwarden.io) */
18
+ appwardenApiHostname?: string;
19
+ /** Enable debug logging */
20
+ debug?: boolean;
21
+ }
22
+ /**
23
+ * Configuration function that receives the Cloudflare context and returns the config.
24
+ * This allows dynamic configuration based on environment variables.
25
+ */
26
+ type ReactRouterConfigFn = (cloudflare: CloudflareContext) => ReactRouterAppwardenConfig;
27
+ /**
28
+ * React Router middleware function signature.
29
+ * This matches the unstable_middleware export type in React Router v7.
30
+ */
31
+ interface ReactRouterMiddlewareArgs {
32
+ request: Request;
33
+ params: Record<string, string | undefined>;
34
+ context: {
35
+ cloudflare: CloudflareContext;
36
+ };
37
+ }
38
+ type ReactRouterMiddlewareFunction = (args: ReactRouterMiddlewareArgs, next: () => Promise<unknown>) => Promise<unknown>;
39
+ /**
40
+ * Creates an Appwarden middleware function for React Router.
41
+ *
42
+ * This middleware checks if the site is locked and redirects to the lock page if so.
43
+ * It should be exported from your root route (root.tsx) to protect all routes.
44
+ *
45
+ * @example
46
+ * ```typescript
47
+ * // app/root.tsx
48
+ * import { createAppwardenMiddleware } from "@appwarden/middleware/react-router"
49
+ *
50
+ * export const unstable_middleware = [
51
+ * createAppwardenMiddleware(({ env }) => ({
52
+ * lockPageSlug: env.APPWARDEN_LOCK_PAGE_SLUG,
53
+ * appwardenApiToken: env.APPWARDEN_API_TOKEN,
54
+ * })),
55
+ * ]
56
+ * ```
57
+ *
58
+ * @param configFn - A function that receives the Cloudflare context and returns the config
59
+ * @returns A React Router middleware function
60
+ */
61
+ declare function createAppwardenMiddleware(configFn: ReactRouterConfigFn): ReactRouterMiddlewareFunction;
62
+
63
+ export { type CloudflareContext, type ReactRouterAppwardenConfig, type ReactRouterConfigFn, type ReactRouterMiddlewareArgs, type ReactRouterMiddlewareFunction, createAppwardenMiddleware };
@@ -0,0 +1,83 @@
1
+ import {
2
+ buildLockPageUrl,
3
+ createRedirect
4
+ } from "../chunk-N6AUTMZO.js";
5
+ import {
6
+ validateConfig
7
+ } from "../chunk-6PUA5YXP.js";
8
+ import {
9
+ checkLockStatus
10
+ } from "../chunk-5DEXVBY6.js";
11
+ import {
12
+ AppwardenApiTokenSchema,
13
+ BooleanSchema
14
+ } from "../chunk-B5IE7V77.js";
15
+ import {
16
+ isHTMLRequest,
17
+ printMessage
18
+ } from "../chunk-7UTT3M2S.js";
19
+
20
+ // src/schemas/react-router-cloudflare.ts
21
+ import { z } from "zod";
22
+ var ReactRouterCloudflareConfigSchema = z.object({
23
+ /** The slug/path of the lock page to redirect to when the site is locked */
24
+ lockPageSlug: z.string(),
25
+ /** The Appwarden API token for authentication */
26
+ appwardenApiToken: AppwardenApiTokenSchema,
27
+ /** Optional custom API hostname (defaults to https://api.appwarden.io) */
28
+ appwardenApiHostname: z.string().optional(),
29
+ /** Enable debug logging */
30
+ debug: BooleanSchema.default(false)
31
+ });
32
+
33
+ // src/adapters/react-router-cloudflare.ts
34
+ function createAppwardenMiddleware(configFn) {
35
+ return async (args, next) => {
36
+ const { request, context } = args;
37
+ try {
38
+ const cloudflare = context.cloudflare;
39
+ if (!cloudflare) {
40
+ console.error(
41
+ printMessage(
42
+ "Cloudflare context not found. Make sure you're running on Cloudflare Workers."
43
+ )
44
+ );
45
+ return next();
46
+ }
47
+ if (!isHTMLRequest(request)) {
48
+ return next();
49
+ }
50
+ const config = configFn(cloudflare);
51
+ const hasError = validateConfig(config, ReactRouterCloudflareConfigSchema);
52
+ if (hasError) {
53
+ return next();
54
+ }
55
+ const result = await checkLockStatus({
56
+ request,
57
+ appwardenApiToken: config.appwardenApiToken,
58
+ appwardenApiHostname: config.appwardenApiHostname,
59
+ debug: config.debug,
60
+ lockPageSlug: config.lockPageSlug,
61
+ waitUntil: (fn) => cloudflare.ctx.waitUntil(fn)
62
+ });
63
+ if (result.isLocked) {
64
+ const lockPageUrl = buildLockPageUrl(config.lockPageSlug, request.url);
65
+ throw createRedirect(lockPageUrl);
66
+ }
67
+ return next();
68
+ } catch (error) {
69
+ if (error instanceof Response) {
70
+ throw error;
71
+ }
72
+ console.error(
73
+ printMessage(
74
+ `Unhandled error: ${error instanceof Error ? error.message : String(error)}`
75
+ )
76
+ );
77
+ return next();
78
+ }
79
+ };
80
+ }
81
+ export {
82
+ createAppwardenMiddleware
83
+ };
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Cloudflare context provided by TanStack Start on Cloudflare Workers.
3
+ * This is the shape of the cloudflare context available in middleware.
4
+ */
5
+ interface TanStackStartCloudflareContext {
6
+ env: CloudflareEnv;
7
+ ctx: ExecutionContext;
8
+ }
9
+ /**
10
+ * Configuration for the Appwarden middleware.
11
+ */
12
+ interface TanStackStartAppwardenConfig {
13
+ /** The slug/path of the lock page to redirect to when the site is locked */
14
+ lockPageSlug: string;
15
+ /** The Appwarden API token for authentication */
16
+ appwardenApiToken: string;
17
+ /** Optional custom API hostname (defaults to https://api.appwarden.io) */
18
+ appwardenApiHostname?: string;
19
+ /** Enable debug logging */
20
+ debug?: boolean;
21
+ }
22
+ /**
23
+ * Configuration function that receives the Cloudflare context and returns the config.
24
+ * This allows dynamic configuration based on environment variables.
25
+ */
26
+ type TanStackStartConfigFn = (cloudflare: TanStackStartCloudflareContext) => TanStackStartAppwardenConfig;
27
+ /**
28
+ * TanStack Start middleware server callback arguments.
29
+ * This matches the shape of arguments passed to createMiddleware().server().
30
+ */
31
+ interface TanStackStartMiddlewareArgs {
32
+ request: Request;
33
+ next: () => Promise<unknown>;
34
+ context: {
35
+ cloudflare?: TanStackStartCloudflareContext;
36
+ [key: string]: unknown;
37
+ };
38
+ }
39
+ /**
40
+ * TanStack Start middleware function signature.
41
+ * This matches the return type of createMiddleware().server().
42
+ */
43
+ type TanStackStartMiddlewareFunction = (args: TanStackStartMiddlewareArgs) => Promise<unknown>;
44
+ /**
45
+ * Creates an Appwarden middleware function for TanStack Start.
46
+ *
47
+ * This middleware checks if the site is locked and throws a redirect to the lock page if so.
48
+ * It should be added to the `requestMiddleware` array in your `src/start.ts` file.
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * // src/start.ts
53
+ * import { createStart } from "@tanstack/react-start"
54
+ * import { createAppwardenMiddleware } from "@appwarden/middleware/tanstack-start"
55
+ *
56
+ * const appwardenMiddleware = createAppwardenMiddleware(({ env }) => ({
57
+ * lockPageSlug: env.APPWARDEN_LOCK_PAGE_SLUG,
58
+ * appwardenApiToken: env.APPWARDEN_API_TOKEN,
59
+ * }))
60
+ *
61
+ * export const startInstance = createStart(() => ({
62
+ * requestMiddleware: [appwardenMiddleware],
63
+ * }))
64
+ * ```
65
+ *
66
+ * @param configFn - A function that receives the Cloudflare context and returns the config
67
+ * @returns A TanStack Start middleware function
68
+ */
69
+ declare function createAppwardenMiddleware(configFn: TanStackStartConfigFn): TanStackStartMiddlewareFunction;
70
+
71
+ export { type TanStackStartAppwardenConfig, type TanStackStartCloudflareContext, type TanStackStartConfigFn, type TanStackStartMiddlewareArgs, type TanStackStartMiddlewareFunction, createAppwardenMiddleware };
@@ -0,0 +1,86 @@
1
+ import {
2
+ buildLockPageUrl,
3
+ createRedirect
4
+ } from "../chunk-N6AUTMZO.js";
5
+ import {
6
+ validateConfig
7
+ } from "../chunk-6PUA5YXP.js";
8
+ import {
9
+ checkLockStatus
10
+ } from "../chunk-5DEXVBY6.js";
11
+ import {
12
+ AppwardenApiTokenSchema,
13
+ BooleanSchema
14
+ } from "../chunk-B5IE7V77.js";
15
+ import {
16
+ isHTMLRequest,
17
+ printMessage
18
+ } from "../chunk-7UTT3M2S.js";
19
+
20
+ // src/schemas/tanstack-start-cloudflare.ts
21
+ import { z } from "zod";
22
+ var TanStackStartCloudflareConfigSchema = z.object({
23
+ /** The slug/path of the lock page to redirect to when the site is locked */
24
+ lockPageSlug: z.string(),
25
+ /** The Appwarden API token for authentication */
26
+ appwardenApiToken: AppwardenApiTokenSchema,
27
+ /** Optional custom API hostname (defaults to https://api.appwarden.io) */
28
+ appwardenApiHostname: z.string().optional(),
29
+ /** Enable debug logging */
30
+ debug: BooleanSchema.default(false)
31
+ });
32
+
33
+ // src/adapters/tanstack-start-cloudflare.ts
34
+ function createAppwardenMiddleware(configFn) {
35
+ return async (args) => {
36
+ const { request, next, context } = args;
37
+ try {
38
+ const cloudflare = context.cloudflare;
39
+ if (!cloudflare) {
40
+ console.error(
41
+ printMessage(
42
+ "Cloudflare context not found. Ensure running on Cloudflare Workers with proper context setup."
43
+ )
44
+ );
45
+ return next();
46
+ }
47
+ if (!isHTMLRequest(request)) {
48
+ return next();
49
+ }
50
+ const config = configFn(cloudflare);
51
+ const hasError = validateConfig(
52
+ config,
53
+ TanStackStartCloudflareConfigSchema
54
+ );
55
+ if (hasError) {
56
+ return next();
57
+ }
58
+ const result = await checkLockStatus({
59
+ request,
60
+ appwardenApiToken: config.appwardenApiToken,
61
+ appwardenApiHostname: config.appwardenApiHostname,
62
+ debug: config.debug,
63
+ lockPageSlug: config.lockPageSlug,
64
+ waitUntil: (fn) => cloudflare.ctx.waitUntil(fn)
65
+ });
66
+ if (result.isLocked) {
67
+ const lockPageUrl = buildLockPageUrl(config.lockPageSlug, request.url);
68
+ throw createRedirect(lockPageUrl);
69
+ }
70
+ return next();
71
+ } catch (error) {
72
+ if (error instanceof Response) {
73
+ throw error;
74
+ }
75
+ console.error(
76
+ printMessage(
77
+ `Unhandled error: ${error instanceof Error ? error.message : String(error)}`
78
+ )
79
+ );
80
+ return next();
81
+ }
82
+ };
83
+ }
84
+ export {
85
+ createAppwardenMiddleware
86
+ };
package/cloudflare.d.ts CHANGED
@@ -1,17 +1,8 @@
1
- import { B as Bindings } from './cloudflare-0sboFQGC.js';
1
+ import { M as Middleware, B as Bindings } from './use-content-security-policy-Bh2qDCKv.js';
2
+ export { u as useContentSecurityPolicy } from './use-content-security-policy-Bh2qDCKv.js';
2
3
  import { z } from 'zod';
3
- import { M as Middleware } from './use-content-security-policy-D4ccKJVd.js';
4
- export { u as useContentSecurityPolicy } from './use-content-security-policy-D4ccKJVd.js';
5
4
 
6
- declare const ConfigFnInputSchema: z.ZodFunction<z.ZodTuple<[z.ZodType<{
7
- env: CloudflareEnv;
8
- cf: Record<string, unknown>;
9
- ctx: unknown;
10
- }, z.ZodTypeDef, {
11
- env: CloudflareEnv;
12
- cf: Record<string, unknown>;
13
- ctx: unknown;
14
- }>], z.ZodUnknown>, z.ZodEffects<z.ZodObject<{
5
+ declare const UseAppwardenInputSchema: z.ZodObject<{
15
6
  debug: z.ZodDefault<z.ZodEffects<z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodBoolean]>>, boolean, string | boolean | undefined>>;
16
7
  lockPageSlug: z.ZodOptional<z.ZodString>;
17
8
  multidomainConfig: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
@@ -23,20 +14,9 @@ declare const ConfigFnInputSchema: z.ZodFunction<z.ZodTuple<[z.ZodType<{
23
14
  }>>>;
24
15
  appwardenApiToken: z.ZodEffects<z.ZodString, string, string>;
25
16
  appwardenApiHostname: z.ZodOptional<z.ZodString>;
26
- } & {
27
- middleware: z.ZodDefault<z.ZodObject<{
28
- before: z.ZodDefault<z.ZodArray<z.ZodType<Middleware, z.ZodTypeDef, Middleware>, "many">>;
29
- }, "strip", z.ZodTypeAny, {
30
- before: Middleware[];
31
- }, {
32
- before?: Middleware[] | undefined;
33
- }>>;
34
17
  }, "strip", z.ZodTypeAny, {
35
18
  debug: boolean;
36
19
  appwardenApiToken: string;
37
- middleware: {
38
- before: Middleware[];
39
- };
40
20
  lockPageSlug?: string | undefined;
41
21
  multidomainConfig?: Record<string, {
42
22
  lockPageSlug: string;
@@ -44,18 +24,21 @@ declare const ConfigFnInputSchema: z.ZodFunction<z.ZodTuple<[z.ZodType<{
44
24
  appwardenApiHostname?: string | undefined;
45
25
  }, {
46
26
  appwardenApiToken: string;
47
- lockPageSlug?: string | undefined;
48
27
  debug?: string | boolean | undefined;
28
+ lockPageSlug?: string | undefined;
49
29
  multidomainConfig?: Record<string, {
50
30
  lockPageSlug: string;
51
31
  }> | undefined;
52
32
  appwardenApiHostname?: string | undefined;
53
- middleware?: {
54
- before?: Middleware[] | undefined;
55
- } | undefined;
56
- }>, any, any>>;
57
- type CloudflareConfigType = ReturnType<z.infer<typeof ConfigFnInputSchema>>;
33
+ }>;
34
+
35
+ type CloudflareConfigType = z.infer<typeof UseAppwardenInputSchema> & {
36
+ middleware: {
37
+ before: Middleware[];
38
+ after: Middleware[];
39
+ };
40
+ };
58
41
 
59
- declare const withAppwarden: (inputFn: CloudflareConfigType) => ExportedHandlerFetchHandler<Bindings>;
42
+ declare const createAppwardenMiddleware: (inputFn: CloudflareConfigType) => ExportedHandlerFetchHandler<Bindings>;
60
43
 
61
- export { withAppwarden };
44
+ export { createAppwardenMiddleware };