@appwarden/middleware 3.3.0 → 3.4.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 +1 -1
- package/{chunk-PH77FI6C.js → chunk-3MKVGKH7.js} +16 -5
- package/{chunk-ZBYVJ3HA.js → chunk-G4RRFNHY.js} +12 -34
- package/{chunk-SUZPTFWY.js → chunk-QVRWMYGL.js} +29 -0
- package/{chunk-7AVYENM2.js → chunk-U3T4R5KZ.js} +1 -1
- package/{chunk-BYRGGUK7.js → chunk-YBWFEBZC.js} +7 -5
- package/cloudflare/astro.js +28 -9
- package/cloudflare/nextjs.js +27 -7
- package/cloudflare/react-router.js +28 -9
- package/cloudflare/tanstack-start.js +28 -9
- package/{cloudflare-LUT5TVEV.js → cloudflare-36BOGAYU.js} +1 -1
- package/cloudflare.d.ts +1 -1
- package/cloudflare.js +23 -11
- package/index.d.ts +1 -1
- package/index.js +2 -2
- package/package.json +1 -1
- package/{use-content-security-policy-CjlLe4yU.d.ts → use-content-security-policy-Dvc-oObb.d.ts} +1 -0
- package/vercel.d.ts +11 -0
- package/vercel.js +27 -8
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
[](https://github.com/appwarden/middleware)
|
|
5
5
|
[](https://www.npmjs.com/package/@appwarden/middleware)
|
|
6
6
|
[](https://docs.npmjs.com/generating-provenance-statements)
|
|
7
|
-

|
|
8
8
|
[](https://opensource.org/licenses/MIT)
|
|
9
9
|
|
|
10
10
|
## Core Features
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
-
MemoryCache
|
|
3
|
-
|
|
2
|
+
MemoryCache,
|
|
3
|
+
debug
|
|
4
|
+
} from "./chunk-QVRWMYGL.js";
|
|
4
5
|
import {
|
|
5
6
|
APPWARDEN_CACHE_KEY,
|
|
6
7
|
APPWARDEN_TEST_ROUTE
|
|
@@ -10,17 +11,19 @@ import {
|
|
|
10
11
|
getLockValue,
|
|
11
12
|
store,
|
|
12
13
|
syncEdgeValue
|
|
13
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-G4RRFNHY.js";
|
|
14
15
|
|
|
15
16
|
// src/core/check-lock-status.ts
|
|
16
17
|
var createContext = async (config) => {
|
|
17
18
|
const requestUrl = new URL(config.request.url);
|
|
18
19
|
const keyName = APPWARDEN_CACHE_KEY;
|
|
19
20
|
const provider = "cloudflare-cache";
|
|
21
|
+
const debugFn = debug(config.debug ?? false);
|
|
20
22
|
const edgeCache = store.json(
|
|
21
23
|
{
|
|
22
24
|
serviceOrigin: requestUrl.origin,
|
|
23
|
-
cache: await caches.open("appwarden:lock")
|
|
25
|
+
cache: await caches.open("appwarden:lock"),
|
|
26
|
+
debug: debugFn
|
|
24
27
|
},
|
|
25
28
|
keyName
|
|
26
29
|
);
|
|
@@ -30,7 +33,7 @@ var createContext = async (config) => {
|
|
|
30
33
|
edgeCache,
|
|
31
34
|
requestUrl,
|
|
32
35
|
provider,
|
|
33
|
-
debug:
|
|
36
|
+
debug: debugFn,
|
|
34
37
|
lockPageSlug: config.lockPageSlug,
|
|
35
38
|
appwardenApiToken: config.appwardenApiToken,
|
|
36
39
|
appwardenApiHostname: config.appwardenApiHostname,
|
|
@@ -39,7 +42,11 @@ var createContext = async (config) => {
|
|
|
39
42
|
};
|
|
40
43
|
var resolveLockStatus = async (context) => {
|
|
41
44
|
const { lockValue, shouldDeleteEdgeValue } = await getLockValue(context);
|
|
45
|
+
if (lockValue) {
|
|
46
|
+
context.debug("Lock value resolved from cache");
|
|
47
|
+
}
|
|
42
48
|
if (shouldDeleteEdgeValue) {
|
|
49
|
+
context.debug("Deleting corrupted cache value");
|
|
43
50
|
await deleteEdgeValue(context);
|
|
44
51
|
}
|
|
45
52
|
const isTestRoute = context.requestUrl.pathname === APPWARDEN_TEST_ROUTE;
|
|
@@ -56,9 +63,13 @@ var checkLockStatus = async (config) => {
|
|
|
56
63
|
let { isLocked, isTestLock, lockValue, wasDeleted } = await resolveLockStatus(context);
|
|
57
64
|
if (MemoryCache.isExpired(lockValue) || wasDeleted) {
|
|
58
65
|
if (!lockValue || wasDeleted || lockValue.isLocked) {
|
|
66
|
+
context.debug(
|
|
67
|
+
"Cache expired/missing/corrupted or site is locked - syncing with API synchronously"
|
|
68
|
+
);
|
|
59
69
|
await syncEdgeValue(context);
|
|
60
70
|
({ isLocked, isTestLock } = await resolveLockStatus(context));
|
|
61
71
|
} else {
|
|
72
|
+
context.debug("Cache expired but site unlocked - syncing in background");
|
|
62
73
|
config.waitUntil(syncEdgeValue(context));
|
|
63
74
|
}
|
|
64
75
|
}
|
|
@@ -1,27 +1,3 @@
|
|
|
1
|
-
// src/utils/debug.ts
|
|
2
|
-
var debug = (...msg) => {
|
|
3
|
-
if (true) {
|
|
4
|
-
const formatted = msg.map((m) => {
|
|
5
|
-
if (typeof m === "object" && m !== null) {
|
|
6
|
-
if (m instanceof Error) {
|
|
7
|
-
return m.stack ?? m.message;
|
|
8
|
-
}
|
|
9
|
-
try {
|
|
10
|
-
return JSON.stringify(m);
|
|
11
|
-
} catch {
|
|
12
|
-
try {
|
|
13
|
-
return String(m);
|
|
14
|
-
} catch {
|
|
15
|
-
return "[Unserializable value]";
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
return m;
|
|
20
|
-
});
|
|
21
|
-
console.log(...formatted);
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
|
|
25
1
|
// src/utils/cloudflare/cloudflare-cache.ts
|
|
26
2
|
var store = {
|
|
27
3
|
json: (context, cacheKey, options) => {
|
|
@@ -36,14 +12,14 @@ var store = {
|
|
|
36
12
|
var getCacheValue = async (context, cacheKey) => {
|
|
37
13
|
const match = await context.cache.match(cacheKey);
|
|
38
14
|
if (!match) {
|
|
39
|
-
debug(`[${cacheKey.pathname}] Cache MISS!`);
|
|
15
|
+
context.debug(`[${cacheKey.pathname}] Cache MISS!`);
|
|
40
16
|
return void 0;
|
|
41
17
|
}
|
|
42
|
-
debug(`[${cacheKey.pathname}] Cache MATCH!`);
|
|
18
|
+
context.debug(`[${cacheKey.pathname}] Cache MATCH!`);
|
|
43
19
|
return match;
|
|
44
20
|
};
|
|
45
21
|
var updateCacheValue = async (context, cacheKey, value, ttl) => {
|
|
46
|
-
debug(
|
|
22
|
+
context.debug(
|
|
47
23
|
"updating cache...",
|
|
48
24
|
cacheKey.href,
|
|
49
25
|
value,
|
|
@@ -285,9 +261,9 @@ var APIError = class extends Error {
|
|
|
285
261
|
};
|
|
286
262
|
var DEFAULT_API_HOSTNAME = "https://api.appwarden.io";
|
|
287
263
|
var syncEdgeValue = async (context) => {
|
|
288
|
-
|
|
264
|
+
const apiHostname = context.appwardenApiHostname ?? DEFAULT_API_HOSTNAME;
|
|
265
|
+
context.debug(`Fetching lock value from API: ${apiHostname}`);
|
|
289
266
|
try {
|
|
290
|
-
const apiHostname = context.appwardenApiHostname ?? DEFAULT_API_HOSTNAME;
|
|
291
267
|
const response = await fetch(new URL("/v1/status/check", apiHostname), {
|
|
292
268
|
method: "POST",
|
|
293
269
|
headers: { "content-type": "application/json" },
|
|
@@ -313,7 +289,10 @@ var syncEdgeValue = async (context) => {
|
|
|
313
289
|
const parsedValue = LockValue.omit({ lastCheck: true }).parse(
|
|
314
290
|
result.content
|
|
315
291
|
);
|
|
316
|
-
debug(
|
|
292
|
+
context.debug(
|
|
293
|
+
`API call to ${apiHostname} succeeded`,
|
|
294
|
+
`Lock status: ${parsedValue.isLocked ? "LOCKED" : "UNLOCKED"}`
|
|
295
|
+
);
|
|
317
296
|
await context.edgeCache.updateValue({
|
|
318
297
|
...parsedValue,
|
|
319
298
|
lastCheck: Date.now()
|
|
@@ -323,19 +302,18 @@ var syncEdgeValue = async (context) => {
|
|
|
323
302
|
}
|
|
324
303
|
}
|
|
325
304
|
} catch (e) {
|
|
326
|
-
const message =
|
|
305
|
+
const message = `API call to ${apiHostname} failed`;
|
|
327
306
|
console.error(
|
|
328
307
|
printMessage(
|
|
329
|
-
e instanceof APIError ? e.message : e instanceof Error ? `${message}
|
|
308
|
+
e instanceof APIError ? e.message : e instanceof Error ? `${message}: ${e.message}` : message
|
|
330
309
|
)
|
|
331
310
|
);
|
|
332
311
|
}
|
|
333
312
|
};
|
|
334
313
|
|
|
335
314
|
export {
|
|
336
|
-
debug,
|
|
337
|
-
getErrors,
|
|
338
315
|
printMessage,
|
|
316
|
+
getErrors,
|
|
339
317
|
BooleanSchema,
|
|
340
318
|
AppwardenApiTokenSchema,
|
|
341
319
|
LockValue,
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
LOCKDOWN_TEST_EXPIRY_MS
|
|
3
3
|
} from "./chunk-HCGLR3Z3.js";
|
|
4
|
+
import {
|
|
5
|
+
printMessage
|
|
6
|
+
} from "./chunk-G4RRFNHY.js";
|
|
4
7
|
|
|
5
8
|
// src/utils/build-lock-page-url.ts
|
|
6
9
|
function normalizeLockPageSlug(lockPageSlug) {
|
|
@@ -34,6 +37,31 @@ var createRedirect = (url) => {
|
|
|
34
37
|
});
|
|
35
38
|
};
|
|
36
39
|
|
|
40
|
+
// src/utils/debug.ts
|
|
41
|
+
var debug = (isDebug) => (...msg) => {
|
|
42
|
+
if (!isDebug) return;
|
|
43
|
+
const formatted = msg.map((m) => {
|
|
44
|
+
let content;
|
|
45
|
+
if (m instanceof Error) {
|
|
46
|
+
content = m.stack ?? m.message;
|
|
47
|
+
} else if (typeof m === "object" && m !== null) {
|
|
48
|
+
try {
|
|
49
|
+
content = JSON.stringify(m);
|
|
50
|
+
} catch {
|
|
51
|
+
try {
|
|
52
|
+
content = String(m);
|
|
53
|
+
} catch {
|
|
54
|
+
content = "[Unserializable value]";
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
} else {
|
|
58
|
+
content = String(m);
|
|
59
|
+
}
|
|
60
|
+
return printMessage(content);
|
|
61
|
+
});
|
|
62
|
+
console.log(...formatted);
|
|
63
|
+
};
|
|
64
|
+
|
|
37
65
|
// src/utils/memory-cache.ts
|
|
38
66
|
var MemoryCache = class {
|
|
39
67
|
cache = /* @__PURE__ */ new Map();
|
|
@@ -86,5 +114,6 @@ export {
|
|
|
86
114
|
isOnLockPage,
|
|
87
115
|
TEMPORARY_REDIRECT_STATUS,
|
|
88
116
|
createRedirect,
|
|
117
|
+
debug,
|
|
89
118
|
MemoryCache
|
|
90
119
|
};
|
|
@@ -3,10 +3,8 @@ import {
|
|
|
3
3
|
isHTMLResponse
|
|
4
4
|
} from "./chunk-HCGLR3Z3.js";
|
|
5
5
|
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
printMessage
|
|
9
|
-
} from "./chunk-ZBYVJ3HA.js";
|
|
6
|
+
makeCSPHeader
|
|
7
|
+
} from "./chunk-G4RRFNHY.js";
|
|
10
8
|
|
|
11
9
|
// src/middlewares/use-content-security-policy.ts
|
|
12
10
|
var AppendAttribute = (attribute, nonce) => ({
|
|
@@ -27,7 +25,7 @@ var useContentSecurityPolicy = (input) => {
|
|
|
27
25
|
// if the csp is disabled
|
|
28
26
|
!["enforced", "report-only"].includes(config.mode)
|
|
29
27
|
) {
|
|
30
|
-
debug(
|
|
28
|
+
context.debug("CSP is disabled");
|
|
31
29
|
return;
|
|
32
30
|
}
|
|
33
31
|
if (response.headers.has("Content-Type") && !isHTMLResponse(response)) {
|
|
@@ -39,6 +37,10 @@ var useContentSecurityPolicy = (input) => {
|
|
|
39
37
|
config.directives,
|
|
40
38
|
config.mode
|
|
41
39
|
);
|
|
40
|
+
context.debug(
|
|
41
|
+
`Applying CSP in ${config.mode} mode`,
|
|
42
|
+
`Directives: ${config.directives ? Object.keys(config.directives).join(", ") : "none"}`
|
|
43
|
+
);
|
|
42
44
|
const nextResponse = new Response(response.body, response);
|
|
43
45
|
nextResponse.headers.set(cspHeaderName, cspHeaderValue);
|
|
44
46
|
nextResponse.headers.set("content-type", "text/html; charset=utf-8");
|
package/cloudflare/astro.js
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
2
|
useContentSecurityPolicy
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-YBWFEBZC.js";
|
|
4
4
|
import {
|
|
5
5
|
validateConfig
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-U3T4R5KZ.js";
|
|
7
7
|
import {
|
|
8
8
|
checkLockStatus
|
|
9
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-3MKVGKH7.js";
|
|
10
10
|
import {
|
|
11
11
|
TEMPORARY_REDIRECT_STATUS,
|
|
12
12
|
buildLockPageUrl,
|
|
13
13
|
createRedirect,
|
|
14
|
+
debug,
|
|
14
15
|
isOnLockPage
|
|
15
|
-
} from "../chunk-
|
|
16
|
+
} from "../chunk-QVRWMYGL.js";
|
|
16
17
|
import {
|
|
17
18
|
UseCSPInputSchema,
|
|
18
19
|
isHTMLRequest
|
|
@@ -21,7 +22,7 @@ import {
|
|
|
21
22
|
AppwardenApiTokenSchema,
|
|
22
23
|
BooleanSchema,
|
|
23
24
|
printMessage
|
|
24
|
-
} from "../chunk-
|
|
25
|
+
} from "../chunk-G4RRFNHY.js";
|
|
25
26
|
|
|
26
27
|
// src/schemas/astro-cloudflare.ts
|
|
27
28
|
import { z } from "zod";
|
|
@@ -39,8 +40,10 @@ var AstroCloudflareConfigSchema = z.object({
|
|
|
39
40
|
});
|
|
40
41
|
|
|
41
42
|
// src/adapters/astro-cloudflare.ts
|
|
43
|
+
var getNowMs = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
42
44
|
function createAppwardenMiddleware(configFn) {
|
|
43
45
|
return async (context, next) => {
|
|
46
|
+
const startTime = getNowMs();
|
|
44
47
|
const { request } = context;
|
|
45
48
|
const locals = context.locals;
|
|
46
49
|
try {
|
|
@@ -53,15 +56,23 @@ function createAppwardenMiddleware(configFn) {
|
|
|
53
56
|
);
|
|
54
57
|
return next();
|
|
55
58
|
}
|
|
56
|
-
|
|
59
|
+
const config = configFn(runtime);
|
|
60
|
+
const debugFn = debug(config.debug ?? false);
|
|
61
|
+
const requestUrl = new URL(request.url);
|
|
62
|
+
const isHTML = isHTMLRequest(request);
|
|
63
|
+
debugFn(
|
|
64
|
+
`Appwarden middleware invoked for ${requestUrl.pathname}`,
|
|
65
|
+
`isHTML: ${isHTML}`
|
|
66
|
+
);
|
|
67
|
+
if (!isHTML) {
|
|
57
68
|
return next();
|
|
58
69
|
}
|
|
59
|
-
const config = configFn(runtime);
|
|
60
70
|
const hasError = validateConfig(config, AstroCloudflareConfigSchema);
|
|
61
71
|
if (hasError) {
|
|
62
72
|
return next();
|
|
63
73
|
}
|
|
64
74
|
if (isOnLockPage(config.lockPageSlug, request.url)) {
|
|
75
|
+
debugFn("Already on lock page - skipping");
|
|
65
76
|
return next();
|
|
66
77
|
}
|
|
67
78
|
const result = await checkLockStatus({
|
|
@@ -74,6 +85,7 @@ function createAppwardenMiddleware(configFn) {
|
|
|
74
85
|
});
|
|
75
86
|
if (result.isLocked) {
|
|
76
87
|
const lockPageUrl = buildLockPageUrl(config.lockPageSlug, request.url);
|
|
88
|
+
debugFn(`Site is locked - redirecting to ${lockPageUrl.pathname}`);
|
|
77
89
|
if (context.redirect) {
|
|
78
90
|
return context.redirect(
|
|
79
91
|
lockPageUrl.toString(),
|
|
@@ -82,13 +94,16 @@ function createAppwardenMiddleware(configFn) {
|
|
|
82
94
|
}
|
|
83
95
|
return createRedirect(lockPageUrl);
|
|
84
96
|
}
|
|
97
|
+
debugFn("Site is unlocked to origin");
|
|
85
98
|
const response = await next();
|
|
86
99
|
if (config.contentSecurityPolicy) {
|
|
100
|
+
debugFn("Applying CSP middleware");
|
|
87
101
|
const cspContext = {
|
|
88
102
|
request,
|
|
89
103
|
response,
|
|
90
|
-
hostname:
|
|
91
|
-
waitUntil: (fn) => runtime.ctx.waitUntil(fn)
|
|
104
|
+
hostname: requestUrl.hostname,
|
|
105
|
+
waitUntil: (fn) => runtime.ctx.waitUntil(fn),
|
|
106
|
+
debug: debugFn
|
|
92
107
|
};
|
|
93
108
|
await useContentSecurityPolicy(config.contentSecurityPolicy)(
|
|
94
109
|
cspContext,
|
|
@@ -96,8 +111,12 @@ function createAppwardenMiddleware(configFn) {
|
|
|
96
111
|
}
|
|
97
112
|
// no-op next
|
|
98
113
|
);
|
|
114
|
+
const elapsed2 = Math.round(getNowMs() - startTime);
|
|
115
|
+
debugFn(`Middleware executed in ${elapsed2}ms`);
|
|
99
116
|
return cspContext.response;
|
|
100
117
|
}
|
|
118
|
+
const elapsed = Math.round(getNowMs() - startTime);
|
|
119
|
+
debugFn(`Middleware executed in ${elapsed}ms`);
|
|
101
120
|
return response;
|
|
102
121
|
} catch (error) {
|
|
103
122
|
if (error instanceof Response) {
|
package/cloudflare/nextjs.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
validateConfig
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-U3T4R5KZ.js";
|
|
4
4
|
import {
|
|
5
5
|
checkLockStatus
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-3MKVGKH7.js";
|
|
7
7
|
import {
|
|
8
8
|
TEMPORARY_REDIRECT_STATUS,
|
|
9
9
|
buildLockPageUrl,
|
|
10
|
+
debug,
|
|
10
11
|
isOnLockPage
|
|
11
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-QVRWMYGL.js";
|
|
12
13
|
import {
|
|
13
14
|
UseCSPInputSchema,
|
|
14
15
|
isHTMLRequest
|
|
@@ -17,7 +18,7 @@ import {
|
|
|
17
18
|
AppwardenApiTokenSchema,
|
|
18
19
|
BooleanSchema,
|
|
19
20
|
printMessage
|
|
20
|
-
} from "../chunk-
|
|
21
|
+
} from "../chunk-G4RRFNHY.js";
|
|
21
22
|
|
|
22
23
|
// src/adapters/nextjs-cloudflare.ts
|
|
23
24
|
import {
|
|
@@ -51,20 +52,30 @@ var NextJsCloudflareConfigSchema = z.object({
|
|
|
51
52
|
});
|
|
52
53
|
|
|
53
54
|
// src/adapters/nextjs-cloudflare.ts
|
|
55
|
+
var getNowMs = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
54
56
|
function createAppwardenMiddleware(configFn) {
|
|
55
57
|
return async (request, _event) => {
|
|
58
|
+
const startTime = getNowMs();
|
|
56
59
|
try {
|
|
57
60
|
const { getCloudflareContext } = await import("@opennextjs/cloudflare");
|
|
58
61
|
const { env, ctx } = await getCloudflareContext();
|
|
59
|
-
|
|
62
|
+
const config = configFn({ env, ctx });
|
|
63
|
+
const debugFn = debug(config.debug ?? false);
|
|
64
|
+
const requestUrl = new URL(request.url);
|
|
65
|
+
const isHTML = isHTMLRequest(request);
|
|
66
|
+
debugFn(
|
|
67
|
+
`Appwarden middleware invoked for ${requestUrl.pathname}`,
|
|
68
|
+
`isHTML: ${isHTML}`
|
|
69
|
+
);
|
|
70
|
+
if (!isHTML) {
|
|
60
71
|
return NextResponse.next();
|
|
61
72
|
}
|
|
62
|
-
const config = configFn({ env, ctx });
|
|
63
73
|
const hasError = validateConfig(config, NextJsCloudflareConfigSchema);
|
|
64
74
|
if (hasError) {
|
|
65
75
|
return NextResponse.next();
|
|
66
76
|
}
|
|
67
77
|
if (isOnLockPage(config.lockPageSlug, request.url)) {
|
|
78
|
+
debugFn("Already on lock page - skipping");
|
|
68
79
|
return NextResponse.next();
|
|
69
80
|
}
|
|
70
81
|
const result = await checkLockStatus({
|
|
@@ -77,10 +88,15 @@ function createAppwardenMiddleware(configFn) {
|
|
|
77
88
|
});
|
|
78
89
|
if (result.isLocked) {
|
|
79
90
|
const lockPageUrl = buildLockPageUrl(config.lockPageSlug, request.url);
|
|
91
|
+
debugFn(`Site is locked - redirecting to ${lockPageUrl.pathname}`);
|
|
80
92
|
return NextResponse.redirect(lockPageUrl, TEMPORARY_REDIRECT_STATUS);
|
|
81
93
|
}
|
|
94
|
+
debugFn("Site is unlocked");
|
|
82
95
|
if (config.contentSecurityPolicy && config.contentSecurityPolicy.mode !== "disabled") {
|
|
83
|
-
|
|
96
|
+
debugFn(
|
|
97
|
+
`Applying CSP headers in ${config.contentSecurityPolicy.mode} mode`
|
|
98
|
+
);
|
|
99
|
+
const { makeCSPHeader } = await import("../cloudflare-36BOGAYU.js");
|
|
84
100
|
const [headerName, headerValue] = makeCSPHeader(
|
|
85
101
|
"",
|
|
86
102
|
config.contentSecurityPolicy.directives,
|
|
@@ -88,8 +104,12 @@ function createAppwardenMiddleware(configFn) {
|
|
|
88
104
|
);
|
|
89
105
|
const response = NextResponse.next();
|
|
90
106
|
response.headers.set(headerName, headerValue);
|
|
107
|
+
const elapsed2 = Math.round(getNowMs() - startTime);
|
|
108
|
+
debugFn(`Middleware executed in ${elapsed2}ms`);
|
|
91
109
|
return response;
|
|
92
110
|
}
|
|
111
|
+
const elapsed = Math.round(getNowMs() - startTime);
|
|
112
|
+
debugFn(`Middleware executed in ${elapsed}ms`);
|
|
93
113
|
return NextResponse.next();
|
|
94
114
|
} catch (error) {
|
|
95
115
|
console.error(
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
useContentSecurityPolicy
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-YBWFEBZC.js";
|
|
4
4
|
import {
|
|
5
5
|
validateConfig
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-U3T4R5KZ.js";
|
|
7
7
|
import {
|
|
8
8
|
checkLockStatus
|
|
9
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-3MKVGKH7.js";
|
|
10
10
|
import {
|
|
11
11
|
buildLockPageUrl,
|
|
12
12
|
createRedirect,
|
|
13
|
+
debug,
|
|
13
14
|
isOnLockPage
|
|
14
|
-
} from "../chunk-
|
|
15
|
+
} from "../chunk-QVRWMYGL.js";
|
|
15
16
|
import {
|
|
16
17
|
UseCSPInputSchema,
|
|
17
18
|
isHTMLRequest
|
|
@@ -20,7 +21,7 @@ import {
|
|
|
20
21
|
AppwardenApiTokenSchema,
|
|
21
22
|
BooleanSchema,
|
|
22
23
|
printMessage
|
|
23
|
-
} from "../chunk-
|
|
24
|
+
} from "../chunk-G4RRFNHY.js";
|
|
24
25
|
|
|
25
26
|
// src/schemas/react-router-cloudflare.ts
|
|
26
27
|
import { z } from "zod";
|
|
@@ -41,6 +42,7 @@ var ReactRouterCloudflareConfigSchema = z.object({
|
|
|
41
42
|
var cloudflareContextSymbol = /* @__PURE__ */ Symbol.for(
|
|
42
43
|
"@appwarden/middleware:cloudflare"
|
|
43
44
|
);
|
|
45
|
+
var getNowMs = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
44
46
|
function getCloudflareContext(context) {
|
|
45
47
|
if (context?.cloudflare) {
|
|
46
48
|
return context.cloudflare;
|
|
@@ -58,6 +60,7 @@ function getCloudflareContext(context) {
|
|
|
58
60
|
}
|
|
59
61
|
function createAppwardenMiddleware(configFn) {
|
|
60
62
|
return async (args, next) => {
|
|
63
|
+
const startTime = getNowMs();
|
|
61
64
|
const { request, context } = args;
|
|
62
65
|
try {
|
|
63
66
|
const cloudflare = getCloudflareContext(context);
|
|
@@ -69,15 +72,23 @@ function createAppwardenMiddleware(configFn) {
|
|
|
69
72
|
);
|
|
70
73
|
return next();
|
|
71
74
|
}
|
|
72
|
-
|
|
75
|
+
const config = configFn(cloudflare);
|
|
76
|
+
const debugFn = debug(config.debug ?? false);
|
|
77
|
+
const requestUrl = new URL(request.url);
|
|
78
|
+
const isHTML = isHTMLRequest(request);
|
|
79
|
+
debugFn(
|
|
80
|
+
`Appwarden middleware invoked for ${requestUrl.pathname}`,
|
|
81
|
+
`isHTML: ${isHTML}`
|
|
82
|
+
);
|
|
83
|
+
if (!isHTML) {
|
|
73
84
|
return next();
|
|
74
85
|
}
|
|
75
|
-
const config = configFn(cloudflare);
|
|
76
86
|
const hasError = validateConfig(config, ReactRouterCloudflareConfigSchema);
|
|
77
87
|
if (hasError) {
|
|
78
88
|
return next();
|
|
79
89
|
}
|
|
80
90
|
if (isOnLockPage(config.lockPageSlug, request.url)) {
|
|
91
|
+
debugFn("Already on lock page - skipping");
|
|
81
92
|
return next();
|
|
82
93
|
}
|
|
83
94
|
const result = await checkLockStatus({
|
|
@@ -90,15 +101,19 @@ function createAppwardenMiddleware(configFn) {
|
|
|
90
101
|
});
|
|
91
102
|
if (result.isLocked) {
|
|
92
103
|
const lockPageUrl = buildLockPageUrl(config.lockPageSlug, request.url);
|
|
104
|
+
debugFn(`Site is locked - redirecting to ${lockPageUrl.pathname}`);
|
|
93
105
|
throw createRedirect(lockPageUrl);
|
|
94
106
|
}
|
|
107
|
+
debugFn("Site is unlocked to origin");
|
|
95
108
|
const response = await next();
|
|
96
109
|
if (config.contentSecurityPolicy && response instanceof Response) {
|
|
110
|
+
debugFn("Applying CSP middleware");
|
|
97
111
|
const cspContext = {
|
|
98
112
|
request,
|
|
99
113
|
response,
|
|
100
|
-
hostname:
|
|
101
|
-
waitUntil: (fn) => cloudflare.ctx.waitUntil(fn)
|
|
114
|
+
hostname: requestUrl.hostname,
|
|
115
|
+
waitUntil: (fn) => cloudflare.ctx.waitUntil(fn),
|
|
116
|
+
debug: debugFn
|
|
102
117
|
};
|
|
103
118
|
await useContentSecurityPolicy(config.contentSecurityPolicy)(
|
|
104
119
|
cspContext,
|
|
@@ -106,8 +121,12 @@ function createAppwardenMiddleware(configFn) {
|
|
|
106
121
|
}
|
|
107
122
|
// no-op next
|
|
108
123
|
);
|
|
124
|
+
const elapsed2 = Math.round(getNowMs() - startTime);
|
|
125
|
+
debugFn(`Middleware executed in ${elapsed2}ms`);
|
|
109
126
|
return cspContext.response;
|
|
110
127
|
}
|
|
128
|
+
const elapsed = Math.round(getNowMs() - startTime);
|
|
129
|
+
debugFn(`Middleware executed in ${elapsed}ms`);
|
|
111
130
|
return response;
|
|
112
131
|
} catch (error) {
|
|
113
132
|
if (error instanceof Response) {
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
useContentSecurityPolicy
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-YBWFEBZC.js";
|
|
4
4
|
import {
|
|
5
5
|
validateConfig
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-U3T4R5KZ.js";
|
|
7
7
|
import {
|
|
8
8
|
checkLockStatus
|
|
9
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-3MKVGKH7.js";
|
|
10
10
|
import {
|
|
11
11
|
buildLockPageUrl,
|
|
12
12
|
createRedirect,
|
|
13
|
+
debug,
|
|
13
14
|
isOnLockPage
|
|
14
|
-
} from "../chunk-
|
|
15
|
+
} from "../chunk-QVRWMYGL.js";
|
|
15
16
|
import {
|
|
16
17
|
UseCSPInputSchema,
|
|
17
18
|
isHTMLRequest
|
|
@@ -20,7 +21,7 @@ import {
|
|
|
20
21
|
AppwardenApiTokenSchema,
|
|
21
22
|
BooleanSchema,
|
|
22
23
|
printMessage
|
|
23
|
-
} from "../chunk-
|
|
24
|
+
} from "../chunk-G4RRFNHY.js";
|
|
24
25
|
|
|
25
26
|
// src/schemas/tanstack-start-cloudflare.ts
|
|
26
27
|
import { z } from "zod";
|
|
@@ -38,8 +39,10 @@ var TanStackStartCloudflareConfigSchema = z.object({
|
|
|
38
39
|
});
|
|
39
40
|
|
|
40
41
|
// src/adapters/tanstack-start-cloudflare.ts
|
|
42
|
+
var getNowMs = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
41
43
|
function createAppwardenMiddleware(configFn) {
|
|
42
44
|
return async (args) => {
|
|
45
|
+
const startTime = getNowMs();
|
|
43
46
|
const { request, next, context } = args;
|
|
44
47
|
try {
|
|
45
48
|
const cloudflare = context.cloudflare;
|
|
@@ -51,10 +54,17 @@ function createAppwardenMiddleware(configFn) {
|
|
|
51
54
|
);
|
|
52
55
|
return next();
|
|
53
56
|
}
|
|
54
|
-
|
|
57
|
+
const config = configFn(cloudflare);
|
|
58
|
+
const debugFn = debug(config.debug ?? false);
|
|
59
|
+
const requestUrl = new URL(request.url);
|
|
60
|
+
const isHTML = isHTMLRequest(request);
|
|
61
|
+
debugFn(
|
|
62
|
+
`Appwarden middleware invoked for ${requestUrl.pathname}`,
|
|
63
|
+
`isHTML: ${isHTML}`
|
|
64
|
+
);
|
|
65
|
+
if (!isHTML) {
|
|
55
66
|
return next();
|
|
56
67
|
}
|
|
57
|
-
const config = configFn(cloudflare);
|
|
58
68
|
const hasError = validateConfig(
|
|
59
69
|
config,
|
|
60
70
|
TanStackStartCloudflareConfigSchema
|
|
@@ -63,6 +73,7 @@ function createAppwardenMiddleware(configFn) {
|
|
|
63
73
|
return next();
|
|
64
74
|
}
|
|
65
75
|
if (isOnLockPage(config.lockPageSlug, request.url)) {
|
|
76
|
+
debugFn("Already on lock page - skipping");
|
|
66
77
|
return next();
|
|
67
78
|
}
|
|
68
79
|
const result = await checkLockStatus({
|
|
@@ -75,15 +86,19 @@ function createAppwardenMiddleware(configFn) {
|
|
|
75
86
|
});
|
|
76
87
|
if (result.isLocked) {
|
|
77
88
|
const lockPageUrl = buildLockPageUrl(config.lockPageSlug, request.url);
|
|
89
|
+
debugFn(`Site is locked - redirecting to ${lockPageUrl.pathname}`);
|
|
78
90
|
throw createRedirect(lockPageUrl);
|
|
79
91
|
}
|
|
92
|
+
debugFn("Site is unlocked to origin");
|
|
80
93
|
const response = await next();
|
|
81
94
|
if (config.contentSecurityPolicy && response instanceof Response) {
|
|
95
|
+
debugFn("Applying CSP middleware");
|
|
82
96
|
const cspContext = {
|
|
83
97
|
request,
|
|
84
98
|
response,
|
|
85
|
-
hostname:
|
|
86
|
-
waitUntil: (fn) => cloudflare.ctx.waitUntil(fn)
|
|
99
|
+
hostname: requestUrl.hostname,
|
|
100
|
+
waitUntil: (fn) => cloudflare.ctx.waitUntil(fn),
|
|
101
|
+
debug: debugFn
|
|
87
102
|
};
|
|
88
103
|
await useContentSecurityPolicy(config.contentSecurityPolicy)(
|
|
89
104
|
cspContext,
|
|
@@ -91,8 +106,12 @@ function createAppwardenMiddleware(configFn) {
|
|
|
91
106
|
}
|
|
92
107
|
// no-op next
|
|
93
108
|
);
|
|
109
|
+
const elapsed2 = Math.round(getNowMs() - startTime);
|
|
110
|
+
debugFn(`Middleware executed in ${elapsed2}ms`);
|
|
94
111
|
return cspContext.response;
|
|
95
112
|
}
|
|
113
|
+
const elapsed = Math.round(getNowMs() - startTime);
|
|
114
|
+
debugFn(`Middleware executed in ${elapsed}ms`);
|
|
96
115
|
return response;
|
|
97
116
|
} catch (error) {
|
|
98
117
|
if (error instanceof Response) {
|
package/cloudflare.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { B as Bindings } from './use-content-security-policy-DUYpyUPy.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
export { u as useContentSecurityPolicy } from './use-content-security-policy-
|
|
3
|
+
export { u as useContentSecurityPolicy } from './use-content-security-policy-Dvc-oObb.js';
|
|
4
4
|
|
|
5
5
|
declare const UseAppwardenInputSchema: z.ZodObject<{
|
|
6
6
|
debug: z.ZodDefault<z.ZodEffects<z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodBoolean]>>, boolean, string | boolean | undefined>>;
|
package/cloudflare.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
useContentSecurityPolicy
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-YBWFEBZC.js";
|
|
4
4
|
import {
|
|
5
5
|
checkLockStatus
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-3MKVGKH7.js";
|
|
7
7
|
import {
|
|
8
8
|
buildLockPageUrl,
|
|
9
9
|
createRedirect,
|
|
10
|
+
debug,
|
|
10
11
|
isOnLockPage
|
|
11
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-QVRWMYGL.js";
|
|
12
13
|
import {
|
|
13
14
|
APPWARDEN_CACHE_KEY,
|
|
14
15
|
UseCSPInputSchema,
|
|
@@ -21,7 +22,7 @@ import {
|
|
|
21
22
|
insertErrorLogs,
|
|
22
23
|
printMessage,
|
|
23
24
|
store
|
|
24
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-G4RRFNHY.js";
|
|
25
26
|
|
|
26
27
|
// src/runners/appwarden-on-cloudflare.ts
|
|
27
28
|
import { ZodError } from "zod";
|
|
@@ -106,7 +107,8 @@ var useAppwarden = (input) => async (context, next) => {
|
|
|
106
107
|
const edgeCache = store.json(
|
|
107
108
|
{
|
|
108
109
|
serviceOrigin: requestUrl.origin,
|
|
109
|
-
cache: await caches.open("appwarden:lock")
|
|
110
|
+
cache: await caches.open("appwarden:lock"),
|
|
111
|
+
debug: context.debug
|
|
110
112
|
},
|
|
111
113
|
keyName
|
|
112
114
|
);
|
|
@@ -166,19 +168,29 @@ var useFetchOrigin = () => async (context, next) => {
|
|
|
166
168
|
var appwardenOnCloudflare = (inputFn) => async (request, env, ctx) => {
|
|
167
169
|
ctx.passThroughOnException();
|
|
168
170
|
const requestUrl = new URL(request.url);
|
|
171
|
+
const parsedInput = ConfigFnInputSchema.safeParse(inputFn);
|
|
172
|
+
if (!parsedInput.success) {
|
|
173
|
+
const tempContext = {
|
|
174
|
+
request,
|
|
175
|
+
hostname: requestUrl.hostname,
|
|
176
|
+
response: new Response("Unhandled response"),
|
|
177
|
+
waitUntil: (fn) => ctx.waitUntil(fn),
|
|
178
|
+
debug: () => {
|
|
179
|
+
}
|
|
180
|
+
// no-op debug for error case
|
|
181
|
+
};
|
|
182
|
+
return insertErrorLogs(tempContext, parsedInput.error);
|
|
183
|
+
}
|
|
184
|
+
const input = parsedInput.data({ env, ctx, cf: {} });
|
|
169
185
|
const context = {
|
|
170
186
|
request,
|
|
171
187
|
hostname: requestUrl.hostname,
|
|
172
188
|
response: new Response("Unhandled response"),
|
|
173
189
|
// https://developers.cloudflare.com/workers/observability/errors/#illegal-invocation-errors
|
|
174
|
-
waitUntil: (fn) => ctx.waitUntil(fn)
|
|
190
|
+
waitUntil: (fn) => ctx.waitUntil(fn),
|
|
191
|
+
debug: debug(input.debug ?? false)
|
|
175
192
|
};
|
|
176
|
-
const parsedInput = ConfigFnInputSchema.safeParse(inputFn);
|
|
177
|
-
if (!parsedInput.success) {
|
|
178
|
-
return insertErrorLogs(context, parsedInput.error);
|
|
179
|
-
}
|
|
180
193
|
try {
|
|
181
|
-
const input = parsedInput.data({ env, ctx, cf: {} });
|
|
182
194
|
const pipeline = [useAppwarden(input), useFetchOrigin()];
|
|
183
195
|
const cspConfig = input.multidomainConfig?.[requestUrl.hostname]?.contentSecurityPolicy;
|
|
184
196
|
if (cspConfig) {
|
package/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { B as Bindings, C as CSPDirectivesSchema, a as CSPModeSchema } from './use-content-security-policy-DUYpyUPy.js';
|
|
2
|
-
export { M as Middleware, u as useContentSecurityPolicy } from './use-content-security-policy-
|
|
2
|
+
export { M as Middleware, u as useContentSecurityPolicy } from './use-content-security-policy-Dvc-oObb.js';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
|
|
5
5
|
declare const LOCKDOWN_TEST_EXPIRY_MS: number;
|
package/index.js
CHANGED
|
@@ -5,14 +5,14 @@ import {
|
|
|
5
5
|
} from "./chunk-QEFORWCW.js";
|
|
6
6
|
import {
|
|
7
7
|
useContentSecurityPolicy
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-YBWFEBZC.js";
|
|
9
9
|
import {
|
|
10
10
|
APPWARDEN_CACHE_KEY,
|
|
11
11
|
CSPDirectivesSchema,
|
|
12
12
|
CSPModeSchema,
|
|
13
13
|
LOCKDOWN_TEST_EXPIRY_MS
|
|
14
14
|
} from "./chunk-HCGLR3Z3.js";
|
|
15
|
-
import "./chunk-
|
|
15
|
+
import "./chunk-G4RRFNHY.js";
|
|
16
16
|
export {
|
|
17
17
|
APPWARDEN_CACHE_KEY,
|
|
18
18
|
CSPDirectivesSchema,
|
package/package.json
CHANGED
package/{use-content-security-policy-CjlLe4yU.d.ts → use-content-security-policy-Dvc-oObb.d.ts}
RENAMED
|
@@ -6,6 +6,7 @@ interface MiddlewareContext {
|
|
|
6
6
|
request: Request;
|
|
7
7
|
response: Response;
|
|
8
8
|
waitUntil: ExecutionContext["waitUntil"];
|
|
9
|
+
debug: (...msg: any[]) => void;
|
|
9
10
|
}
|
|
10
11
|
type Middleware = (context: MiddlewareContext, next: () => MiddlewareNextSchemaType) => MiddlewareNextSchemaType;
|
|
11
12
|
declare const MiddlewareNextSchema: z.ZodUnion<[z.ZodVoid, z.ZodNull, z.ZodPromise<z.ZodUnion<[z.ZodVoid, z.ZodNull]>>]>;
|
package/vercel.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ declare const AppwardenConfigSchema: z.ZodEffects<z.ZodEffects<z.ZodEffects<z.Zo
|
|
|
4
4
|
cacheUrl: z.ZodString;
|
|
5
5
|
appwardenApiToken: z.ZodString;
|
|
6
6
|
vercelApiToken: z.ZodOptional<z.ZodString>;
|
|
7
|
+
debug: z.ZodOptional<z.ZodBoolean>;
|
|
7
8
|
lockPageSlug: z.ZodEffects<z.ZodDefault<z.ZodString>, string, string | undefined>;
|
|
8
9
|
contentSecurityPolicy: z.ZodOptional<z.ZodEffects<z.ZodObject<{
|
|
9
10
|
mode: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"disabled">, z.ZodLiteral<"report-only">, z.ZodLiteral<"enforced">]>>>;
|
|
@@ -376,6 +377,7 @@ declare const AppwardenConfigSchema: z.ZodEffects<z.ZodEffects<z.ZodEffects<z.Zo
|
|
|
376
377
|
lockPageSlug: string;
|
|
377
378
|
appwardenApiToken: string;
|
|
378
379
|
cacheUrl: string;
|
|
380
|
+
debug?: boolean | undefined;
|
|
379
381
|
contentSecurityPolicy?: {
|
|
380
382
|
mode: "disabled" | "report-only" | "enforced";
|
|
381
383
|
directives?: {
|
|
@@ -411,6 +413,7 @@ declare const AppwardenConfigSchema: z.ZodEffects<z.ZodEffects<z.ZodEffects<z.Zo
|
|
|
411
413
|
}, {
|
|
412
414
|
appwardenApiToken: string;
|
|
413
415
|
cacheUrl: string;
|
|
416
|
+
debug?: boolean | undefined;
|
|
414
417
|
lockPageSlug?: string | undefined;
|
|
415
418
|
contentSecurityPolicy?: {
|
|
416
419
|
mode?: "disabled" | "report-only" | "enforced" | undefined;
|
|
@@ -448,6 +451,7 @@ declare const AppwardenConfigSchema: z.ZodEffects<z.ZodEffects<z.ZodEffects<z.Zo
|
|
|
448
451
|
lockPageSlug: string;
|
|
449
452
|
appwardenApiToken: string;
|
|
450
453
|
cacheUrl: string;
|
|
454
|
+
debug?: boolean | undefined;
|
|
451
455
|
contentSecurityPolicy?: {
|
|
452
456
|
mode: "disabled" | "report-only" | "enforced";
|
|
453
457
|
directives?: {
|
|
@@ -483,6 +487,7 @@ declare const AppwardenConfigSchema: z.ZodEffects<z.ZodEffects<z.ZodEffects<z.Zo
|
|
|
483
487
|
}, {
|
|
484
488
|
appwardenApiToken: string;
|
|
485
489
|
cacheUrl: string;
|
|
490
|
+
debug?: boolean | undefined;
|
|
486
491
|
lockPageSlug?: string | undefined;
|
|
487
492
|
contentSecurityPolicy?: {
|
|
488
493
|
mode?: "disabled" | "report-only" | "enforced" | undefined;
|
|
@@ -520,6 +525,7 @@ declare const AppwardenConfigSchema: z.ZodEffects<z.ZodEffects<z.ZodEffects<z.Zo
|
|
|
520
525
|
lockPageSlug: string;
|
|
521
526
|
appwardenApiToken: string;
|
|
522
527
|
cacheUrl: string;
|
|
528
|
+
debug?: boolean | undefined;
|
|
523
529
|
contentSecurityPolicy?: {
|
|
524
530
|
mode: "disabled" | "report-only" | "enforced";
|
|
525
531
|
directives?: {
|
|
@@ -555,6 +561,7 @@ declare const AppwardenConfigSchema: z.ZodEffects<z.ZodEffects<z.ZodEffects<z.Zo
|
|
|
555
561
|
}, {
|
|
556
562
|
appwardenApiToken: string;
|
|
557
563
|
cacheUrl: string;
|
|
564
|
+
debug?: boolean | undefined;
|
|
558
565
|
lockPageSlug?: string | undefined;
|
|
559
566
|
contentSecurityPolicy?: {
|
|
560
567
|
mode?: "disabled" | "report-only" | "enforced" | undefined;
|
|
@@ -592,6 +599,7 @@ declare const AppwardenConfigSchema: z.ZodEffects<z.ZodEffects<z.ZodEffects<z.Zo
|
|
|
592
599
|
lockPageSlug: string;
|
|
593
600
|
appwardenApiToken: string;
|
|
594
601
|
cacheUrl: string;
|
|
602
|
+
debug?: boolean | undefined;
|
|
595
603
|
contentSecurityPolicy?: {
|
|
596
604
|
mode: "disabled" | "report-only" | "enforced";
|
|
597
605
|
directives?: {
|
|
@@ -627,6 +635,7 @@ declare const AppwardenConfigSchema: z.ZodEffects<z.ZodEffects<z.ZodEffects<z.Zo
|
|
|
627
635
|
}, {
|
|
628
636
|
appwardenApiToken: string;
|
|
629
637
|
cacheUrl: string;
|
|
638
|
+
debug?: boolean | undefined;
|
|
630
639
|
lockPageSlug?: string | undefined;
|
|
631
640
|
contentSecurityPolicy?: {
|
|
632
641
|
mode?: "disabled" | "report-only" | "enforced" | undefined;
|
|
@@ -664,6 +673,7 @@ declare const AppwardenConfigSchema: z.ZodEffects<z.ZodEffects<z.ZodEffects<z.Zo
|
|
|
664
673
|
lockPageSlug: string;
|
|
665
674
|
appwardenApiToken: string;
|
|
666
675
|
cacheUrl: string;
|
|
676
|
+
debug?: boolean | undefined;
|
|
667
677
|
contentSecurityPolicy?: {
|
|
668
678
|
mode: "disabled" | "report-only" | "enforced";
|
|
669
679
|
directives?: {
|
|
@@ -699,6 +709,7 @@ declare const AppwardenConfigSchema: z.ZodEffects<z.ZodEffects<z.ZodEffects<z.Zo
|
|
|
699
709
|
}, {
|
|
700
710
|
appwardenApiToken: string;
|
|
701
711
|
cacheUrl: string;
|
|
712
|
+
debug?: boolean | undefined;
|
|
702
713
|
lockPageSlug?: string | undefined;
|
|
703
714
|
contentSecurityPolicy?: {
|
|
704
715
|
mode?: "disabled" | "report-only" | "enforced" | undefined;
|
package/vercel.js
CHANGED
|
@@ -4,13 +4,14 @@ import {
|
|
|
4
4
|
} from "./chunk-QEFORWCW.js";
|
|
5
5
|
import {
|
|
6
6
|
validateConfig
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-U3T4R5KZ.js";
|
|
8
8
|
import {
|
|
9
9
|
MemoryCache,
|
|
10
10
|
TEMPORARY_REDIRECT_STATUS,
|
|
11
11
|
buildLockPageUrl,
|
|
12
|
+
debug,
|
|
12
13
|
isOnLockPage
|
|
13
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-QVRWMYGL.js";
|
|
14
15
|
import {
|
|
15
16
|
APPWARDEN_CACHE_KEY,
|
|
16
17
|
CSPDirectivesSchema,
|
|
@@ -21,10 +22,9 @@ import {
|
|
|
21
22
|
} from "./chunk-HCGLR3Z3.js";
|
|
22
23
|
import {
|
|
23
24
|
LockValue,
|
|
24
|
-
debug,
|
|
25
25
|
makeCSPHeader,
|
|
26
26
|
printMessage
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-G4RRFNHY.js";
|
|
28
28
|
|
|
29
29
|
// src/runners/appwarden-on-vercel.ts
|
|
30
30
|
import { waitUntil } from "@vercel/functions";
|
|
@@ -106,7 +106,7 @@ var APIError = class extends Error {
|
|
|
106
106
|
}
|
|
107
107
|
};
|
|
108
108
|
var syncEdgeValue = async (context) => {
|
|
109
|
-
debug(
|
|
109
|
+
context.debug("syncing with api");
|
|
110
110
|
try {
|
|
111
111
|
const response = await fetch(new URL("/v1/status/check", "https://api.appwarden.io"), {
|
|
112
112
|
method: "POST",
|
|
@@ -173,6 +173,7 @@ var BaseNextJsConfigSchema = z.object({
|
|
|
173
173
|
cacheUrl: z.string(),
|
|
174
174
|
appwardenApiToken: z.string(),
|
|
175
175
|
vercelApiToken: z.string().optional(),
|
|
176
|
+
debug: z.boolean().optional(),
|
|
176
177
|
lockPageSlug: z.string().default("").transform((val) => val.replace(/^\/?/, "/")),
|
|
177
178
|
contentSecurityPolicy: VercelCSPSchema.optional()
|
|
178
179
|
});
|
|
@@ -224,7 +225,6 @@ var AppwardenConfigSchema = BaseNextJsConfigSchema.refine(
|
|
|
224
225
|
});
|
|
225
226
|
|
|
226
227
|
// src/runners/appwarden-on-vercel.ts
|
|
227
|
-
debug("Instantiating isolate");
|
|
228
228
|
var memoryCache = new MemoryCache({ maxSize: 1 });
|
|
229
229
|
function safeWaitUntil(promise) {
|
|
230
230
|
try {
|
|
@@ -239,6 +239,7 @@ function createAppwardenMiddleware(config) {
|
|
|
239
239
|
return NextResponse.next();
|
|
240
240
|
}
|
|
241
241
|
const parsedConfig = AppwardenConfigSchema.parse(config);
|
|
242
|
+
const debugFn = debug(parsedConfig.debug ?? false);
|
|
242
243
|
const applyCspHeaders = (response) => {
|
|
243
244
|
const cspConfig = parsedConfig.contentSecurityPolicy;
|
|
244
245
|
if (cspConfig && ["enforced", "report-only"].includes(cspConfig.mode)) {
|
|
@@ -254,26 +255,38 @@ function createAppwardenMiddleware(config) {
|
|
|
254
255
|
try {
|
|
255
256
|
const requestUrl = new URL(request.url);
|
|
256
257
|
const isHTML = isHTMLRequest(request);
|
|
257
|
-
|
|
258
|
+
debugFn(
|
|
259
|
+
`Appwarden middleware invoked for ${requestUrl.pathname}`,
|
|
260
|
+
`isHTML: ${isHTML}`
|
|
261
|
+
);
|
|
258
262
|
if (!isHTML) {
|
|
263
|
+
debugFn("Non-HTML request detected - passing through");
|
|
259
264
|
return NextResponse.next();
|
|
260
265
|
}
|
|
261
266
|
if (!parsedConfig.lockPageSlug) {
|
|
267
|
+
debugFn("No lockPageSlug configured - passing through");
|
|
262
268
|
return NextResponse.next();
|
|
263
269
|
}
|
|
264
270
|
if (isOnLockPage(parsedConfig.lockPageSlug, request.url)) {
|
|
271
|
+
debugFn("Already on lock page - passing through");
|
|
265
272
|
return NextResponse.next();
|
|
266
273
|
}
|
|
267
274
|
const provider = isCacheUrl.edgeConfig(parsedConfig.cacheUrl) ? "edge-config" : "upstash";
|
|
275
|
+
debugFn(`Using provider: ${provider}`);
|
|
268
276
|
const cacheValue = memoryCache.get(APPWARDEN_CACHE_KEY);
|
|
269
277
|
const shouldRecheck = MemoryCache.isExpired(cacheValue);
|
|
270
278
|
if (!cacheValue || shouldRecheck) {
|
|
279
|
+
debugFn(
|
|
280
|
+
"Memory cache miss or expired - syncing edge value in background",
|
|
281
|
+
`shouldRecheck=${shouldRecheck}`
|
|
282
|
+
);
|
|
271
283
|
safeWaitUntil(
|
|
272
284
|
syncEdgeValue({
|
|
273
285
|
requestUrl,
|
|
274
286
|
cacheUrl: parsedConfig.cacheUrl,
|
|
275
287
|
appwardenApiToken: parsedConfig.appwardenApiToken,
|
|
276
|
-
vercelApiToken: parsedConfig.vercelApiToken
|
|
288
|
+
vercelApiToken: parsedConfig.vercelApiToken,
|
|
289
|
+
debug: debugFn
|
|
277
290
|
})
|
|
278
291
|
);
|
|
279
292
|
}
|
|
@@ -283,6 +296,7 @@ function createAppwardenMiddleware(config) {
|
|
|
283
296
|
provider
|
|
284
297
|
})).lockValue;
|
|
285
298
|
if (lockValue?.isLocked) {
|
|
299
|
+
debugFn("Site is locked - redirecting to lock page");
|
|
286
300
|
const lockPageUrl = buildLockPageUrl(
|
|
287
301
|
parsedConfig.lockPageSlug,
|
|
288
302
|
request.url
|
|
@@ -294,8 +308,13 @@ function createAppwardenMiddleware(config) {
|
|
|
294
308
|
return applyCspHeaders(redirectResponse);
|
|
295
309
|
}
|
|
296
310
|
const response = NextResponse.next();
|
|
311
|
+
debugFn("Site is not locked - passing through");
|
|
297
312
|
return applyCspHeaders(response);
|
|
298
313
|
} catch (e) {
|
|
314
|
+
debugFn(
|
|
315
|
+
"Error in Appwarden Vercel middleware",
|
|
316
|
+
e instanceof Error ? e.message : String(e)
|
|
317
|
+
);
|
|
299
318
|
const message = "Appwarden encountered an unknown error. Please contact Appwarden support at https://appwarden.io/join-community.";
|
|
300
319
|
if (e instanceof Error) {
|
|
301
320
|
if (!globalErrors.includes(e.message)) {
|