@appwarden/middleware 1.0.19 → 1.1.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.
@@ -1,10 +1,15 @@
1
1
  import {
2
+ APPWARDEN_CACHE_KEY,
2
3
  APPWARDEN_TEST_ROUTE,
3
4
  LockValue,
4
5
  MemoryCache,
6
+ UseCSPInputSchema,
5
7
  debug,
6
- printMessage
7
- } from "./chunk-D55SBZQF.js";
8
+ getErrors,
9
+ printMessage,
10
+ removedHeaders,
11
+ renderLockPage
12
+ } from "./chunk-WVVSYKJM.js";
8
13
 
9
14
  // src/utils/cloudflare/cloudflare-cache.ts
10
15
  var store = {
@@ -52,11 +57,6 @@ var updateCacheValue = async (context, cacheKey, value, cacheExpirationSeconds)
52
57
  };
53
58
  var clearCache = (context, cacheKey) => context.cache.delete(cacheKey);
54
59
 
55
- // src/utils/cloudflare/create-response.ts
56
- var createResponse = (body, status) => new Response(body, {
57
- status
58
- });
59
-
60
60
  // src/utils/cloudflare/delete-edge-value.ts
61
61
  var deleteEdgeValue = async (context) => {
62
62
  try {
@@ -123,6 +123,45 @@ var getLockValue = async (context) => {
123
123
  }
124
124
  };
125
125
 
126
+ // src/utils/cloudflare/insert-errors-logs.ts
127
+ var insertErrorLogs = async (context, error) => new HTMLRewriter().on("body", {
128
+ element: (elem) => {
129
+ elem.append(
130
+ `<script>
131
+ ${getErrors(error).map((err) => `console.error(\`${printMessage(err)}\`)`).join("\n")}
132
+ </script>`,
133
+ { html: true }
134
+ );
135
+ }
136
+ }).transform(await fetch(context.request));
137
+
138
+ // src/utils/cloudflare/make-csp-header.ts
139
+ var addNonce = (value, cspNonce) => value.replace("{{nonce}}", `'nonce-${cspNonce}'`);
140
+ var makeCSPHeader = (cspNonce, directives, mode) => {
141
+ const namesSeen = /* @__PURE__ */ new Set(), result = [];
142
+ Object.entries(directives ?? {}).forEach(([originalName, value]) => {
143
+ const name = originalName.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
144
+ if (namesSeen.has(name)) {
145
+ throw new Error(`${originalName} is specified more than once`);
146
+ }
147
+ namesSeen.add(name);
148
+ if (Array.isArray(value)) {
149
+ value = addNonce(value.join(" "), cspNonce);
150
+ } else if (value === true) {
151
+ value = "";
152
+ }
153
+ if (value) {
154
+ result.push(`${name} ${addNonce(value, cspNonce)}`);
155
+ } else if (value !== false) {
156
+ result.push(name);
157
+ }
158
+ });
159
+ return [
160
+ mode === "enforced" ? "Content-Security-Policy" : "Content-Security-Policy-Report-Only",
161
+ result.join("; ")
162
+ ];
163
+ };
164
+
126
165
  // src/utils/cloudflare/sync-edge-value.ts
127
166
  var APIError = class extends Error {
128
167
  constructor(message) {
@@ -131,7 +170,7 @@ var APIError = class extends Error {
131
170
  }
132
171
  };
133
172
  var syncEdgeValue = async (context) => {
134
- debug(`syncing with api ${"https://bot-gateway.appwarden.io"}`);
173
+ debug(`syncing with api`);
135
174
  try {
136
175
  const response = await fetch(new URL("/v1/status/check", "https://bot-gateway.appwarden.io"), {
137
176
  method: "POST",
@@ -178,6 +217,47 @@ var syncEdgeValue = async (context) => {
178
217
  }
179
218
  };
180
219
 
220
+ // src/middlewares/use-content-security-policy.ts
221
+ var AppendAttribute = (attribute, nonce) => ({
222
+ element: function(element) {
223
+ element.setAttribute(attribute, nonce);
224
+ }
225
+ });
226
+ var useContentSecurityPolicy = (input) => {
227
+ const parsedInput = UseCSPInputSchema.safeParse(input);
228
+ if (!parsedInput.success) {
229
+ throw parsedInput.error;
230
+ }
231
+ const config = parsedInput.data;
232
+ return async (context, next) => {
233
+ await next();
234
+ const { response } = context;
235
+ if (
236
+ // if the csp is disabled
237
+ !["enforced", "report-only"].includes(config.mode)
238
+ ) {
239
+ debug(printMessage("csp is disabled"));
240
+ return;
241
+ }
242
+ if (response.headers.has("Content-Type") && !response.headers.get("Content-Type")?.includes("text/html")) {
243
+ return;
244
+ }
245
+ const cspNonce = btoa(crypto.getRandomValues(new Uint32Array(2)).toString());
246
+ const [cspHeaderName, cspHeaderValue] = makeCSPHeader(
247
+ cspNonce,
248
+ config.directives,
249
+ config.mode
250
+ );
251
+ const nextResponse = new Response(response.body, response);
252
+ nextResponse.headers.set(cspHeaderName, cspHeaderValue);
253
+ nextResponse.headers.set("content-type", "text/html; charset=utf-8");
254
+ removedHeaders.forEach((name) => {
255
+ nextResponse.headers.delete(name);
256
+ });
257
+ context.response = new HTMLRewriter().on("style", AppendAttribute("nonce", cspNonce)).on("script", AppendAttribute("nonce", cspNonce)).transform(nextResponse);
258
+ };
259
+ };
260
+
181
261
  // src/handlers/maybe-quarantine.ts
182
262
  var resolveLockValue = async (context, options) => {
183
263
  const { lockValue, shouldDeleteEdgeValue } = await getLockValue(context);
@@ -223,10 +303,56 @@ var handleResetCache = async (keyName, provider, edgeCache, request) => {
223
303
  }
224
304
  };
225
305
 
306
+ // src/middlewares/use-appwarden.ts
307
+ var useAppwarden = (input) => async (context, next) => {
308
+ await next();
309
+ const { request, response } = context;
310
+ try {
311
+ const requestUrl = new URL(request.url);
312
+ const provider = "cloudflare-cache";
313
+ const keyName = APPWARDEN_CACHE_KEY;
314
+ const edgeCache = store.json(
315
+ {
316
+ serviceOrigin: requestUrl.origin,
317
+ cache: await caches.open("appwarden:lock")
318
+ },
319
+ keyName
320
+ );
321
+ if (isResetCacheRequest(request)) {
322
+ await handleResetCache(keyName, provider, edgeCache, request);
323
+ return;
324
+ }
325
+ const isHTMLRequest = response.headers.get("Content-Type")?.includes("text/html");
326
+ if (isHTMLRequest) {
327
+ const innerContext = {
328
+ keyName,
329
+ request,
330
+ edgeCache,
331
+ requestUrl,
332
+ provider,
333
+ debug: input.debug,
334
+ lockPageSlug: input.lockPageSlug,
335
+ appwardenApiToken: input.appwardenApiToken,
336
+ waitUntil: (fn) => context.waitUntil(fn)
337
+ };
338
+ await maybeQuarantine(innerContext, {
339
+ onLocked: async () => {
340
+ context.response = await renderLockPage(innerContext);
341
+ }
342
+ });
343
+ }
344
+ } catch (e) {
345
+ const message = "Appwarden encountered an unknown error. Please contact Appwarden support at https://appwarden.io/join-community.";
346
+ console.error(
347
+ printMessage(
348
+ e instanceof Error ? `${message} - ${e.message}` : message
349
+ )
350
+ );
351
+ }
352
+ };
353
+
226
354
  export {
227
- store,
228
- createResponse,
229
- maybeQuarantine,
230
- isResetCacheRequest,
231
- handleResetCache
355
+ insertErrorLogs,
356
+ useAppwarden,
357
+ useContentSecurityPolicy
232
358
  };
@@ -1,20 +1,78 @@
1
1
  // src/constants.ts
2
2
  var LOCKDOWN_TEST_EXPIRY_MS = 5 * 60 * 1e3;
3
3
  var removedHeaders = ["X-Powered-By", "Server"];
4
- var securityHeaders = [
5
- ["Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload"],
6
- ["X-Frame-Options", "DENY"],
7
- ["X-XSS-Protection", "1; mode=block"],
8
- ["X-Content-Type-Options", "nosniff"],
9
- ["Referrer-Policy", "no-referrer, strict-origin-when-cross-origin"],
10
- ["X-DNS-Prefetch-Control", "on"]
11
- ];
12
4
  var errors = { badCacheConnection: "BAD_CACHE_CONNECTION" };
13
5
  var globalErrors = [errors.badCacheConnection];
14
6
  var APPWARDEN_TEST_ROUTE = "_appwarden/test";
7
+ var APPWARDEN_CACHE_KEY = "appwarden-lock";
15
8
 
16
- // src/schemas/vercel.ts
17
- import { z as z4 } from "zod";
9
+ // src/utils/is-cache-url.ts
10
+ var getEdgeConfigId = (value = "") => isValidCacheUrl.edgeConfig(value) ? new URL(value).pathname.replace("/", "") : void 0;
11
+ var isCacheUrl = {
12
+ edgeConfig: (value = "") => value.includes("edge-config.vercel.com"),
13
+ upstash: (value = "") => value.includes(".upstash.io")
14
+ };
15
+ var isValidCacheUrl = {
16
+ edgeConfig: (value = "") => {
17
+ try {
18
+ const url = new URL(value);
19
+ return url.hostname === "edge-config.vercel.com" && url.pathname.startsWith("/ecfg_") && url.searchParams.has("token");
20
+ } catch (error) {
21
+ return false;
22
+ }
23
+ },
24
+ upstash: (value = "") => {
25
+ try {
26
+ const url = new URL(value);
27
+ return ["redis:", "rediss:"].includes(url.protocol) && url.hostname.endsWith("upstash.io") && url.password;
28
+ } catch (error) {
29
+ return false;
30
+ }
31
+ }
32
+ };
33
+
34
+ // src/schemas/use-content-security-policy.ts
35
+ import { z as z8 } from "zod";
36
+
37
+ // src/types/csp.ts
38
+ import { z } from "zod";
39
+ var stringySchema = z.union([z.array(z.string()), z.string(), z.boolean()]);
40
+ var ContentSecurityPolicySchema = z.object({
41
+ "default-src": stringySchema.optional(),
42
+ "script-src": stringySchema.optional(),
43
+ "style-src": stringySchema.optional(),
44
+ "img-src": stringySchema.optional(),
45
+ "connect-src": stringySchema.optional(),
46
+ "font-src": stringySchema.optional(),
47
+ "object-src": stringySchema.optional(),
48
+ "media-src": stringySchema.optional(),
49
+ "frame-src": stringySchema.optional(),
50
+ sandbox: stringySchema.optional(),
51
+ "report-uri": stringySchema.optional(),
52
+ "child-src": stringySchema.optional(),
53
+ "form-action": stringySchema.optional(),
54
+ "frame-ancestors": stringySchema.optional(),
55
+ "plugin-types": stringySchema.optional(),
56
+ "base-uri": stringySchema.optional(),
57
+ "report-to": stringySchema.optional(),
58
+ "worker-src": stringySchema.optional(),
59
+ "manifest-src": stringySchema.optional(),
60
+ "prefetch-src": stringySchema.optional(),
61
+ "navigate-to": stringySchema.optional(),
62
+ "require-sri-for": stringySchema.optional(),
63
+ "block-all-mixed-content": stringySchema.optional(),
64
+ "upgrade-insecure-requests": stringySchema.optional(),
65
+ "trusted-types": stringySchema.optional(),
66
+ "require-trusted-types-for": stringySchema.optional()
67
+ });
68
+
69
+ // src/types/middleware.ts
70
+ import { z as z2 } from "zod";
71
+ var MiddlewareNextSchema = z2.union([
72
+ z2.void(),
73
+ z2.null(),
74
+ z2.promise(z2.union([z2.void(), z2.null()]))
75
+ ]);
18
76
 
19
77
  // src/utils/debug.ts
20
78
  var debug = (...msg) => {
@@ -23,6 +81,39 @@ var debug = (...msg) => {
23
81
  }
24
82
  };
25
83
 
84
+ // src/utils/errors.ts
85
+ var errorsMap = {
86
+ mode: '`CSP_MODE` must be one of "disabled", "report-only", or "enforced"',
87
+ directives: {
88
+ ["DirectivesRequired" /* DirectivesRequired */]: '`CSP_DIRECTIVES` must be provided when `CSP_MODE` is "report-only" or "enforced"',
89
+ ["DirectivesBadParse" /* DirectivesBadParse */]: "Failed to parse `CSP_DIRECTIVES`. Is it a valid JSON string?"
90
+ },
91
+ appwardenApiToken: "Please provide a valid `appwardenApiToken`. Learn more at https://appwarden.com/docs/api-tokens."
92
+ };
93
+ var getErrors = (error) => {
94
+ const matches = [];
95
+ const errors2 = [...Object.entries(error.flatten().fieldErrors)];
96
+ for (const issue of error.issues) {
97
+ errors2.push(
98
+ ...Object.entries(
99
+ "returnTypeError" in issue ? issue.returnTypeError.flatten().fieldErrors : {}
100
+ )
101
+ );
102
+ }
103
+ for (const [field, maybeSchemaErrorKey] of errors2) {
104
+ let match = errorsMap[field];
105
+ if (match) {
106
+ if (match instanceof Object) {
107
+ if (maybeSchemaErrorKey) {
108
+ match = match[maybeSchemaErrorKey[0]];
109
+ }
110
+ }
111
+ matches.push(match);
112
+ }
113
+ }
114
+ return matches;
115
+ };
116
+
26
117
  // src/utils/memory-cache.ts
27
118
  var MemoryCache = class {
28
119
  cache = /* @__PURE__ */ new Map();
@@ -67,19 +158,23 @@ var MemoryCache = class {
67
158
  };
68
159
 
69
160
  // src/utils/print-message.ts
70
- var printMessage = (message) => `[@appwarden/middleware] ${message}`;
161
+ var addSlashes = (str) => str.replace(/[\\"'`]/g, "\\$&").replace(/\u0000/g, "\\0");
162
+ var printMessage = (message) => `[@appwarden/middleware] ${addSlashes(message)}`;
71
163
 
72
164
  // src/utils/vercel/delete-edge-value.ts
73
165
  var deleteEdgeValue = async ({
74
166
  keyName,
75
167
  provider,
76
- connectionString,
77
- edgeConfigId,
168
+ cacheUrl,
78
169
  vercelApiToken
79
170
  }) => {
80
171
  try {
81
172
  switch (provider) {
82
173
  case "edge-config": {
174
+ const edgeConfigId = getEdgeConfigId(cacheUrl);
175
+ if (!edgeConfigId) {
176
+ throw new Error("Failed to parse `edgeConfigId`");
177
+ }
83
178
  const res = await fetch(
84
179
  `https://api.vercel.com/v1/edge-config/${edgeConfigId}/items`,
85
180
  {
@@ -111,9 +206,9 @@ var deleteEdgeValue = async ({
111
206
  break;
112
207
  }
113
208
  case "upstash": {
114
- const [url, token] = connectionString.split("@");
209
+ const { hostname, password } = new URL(cacheUrl);
115
210
  const { Redis } = await import("@upstash/redis");
116
- const redis = new Redis({ url, token });
211
+ const redis = new Redis({ url: `https://${hostname}`, token: password });
117
212
  await redis.del(keyName);
118
213
  break;
119
214
  }
@@ -129,11 +224,14 @@ var deleteEdgeValue = async ({
129
224
  };
130
225
 
131
226
  // src/schemas/cloudflare.ts
132
- import { z as z2 } from "zod";
227
+ import { z as z5 } from "zod";
228
+
229
+ // src/schemas/use-appwarden.ts
230
+ import { z as z4 } from "zod";
133
231
 
134
232
  // src/schemas/helpers.ts
135
- import { z } from "zod";
136
- var BoolOrStringSchema = z.union([z.string(), z.boolean()]).optional();
233
+ import { z as z3 } from "zod";
234
+ var BoolOrStringSchema = z3.union([z3.string(), z3.boolean()]).optional();
137
235
  var BooleanSchema = BoolOrStringSchema.transform((val) => {
138
236
  if (val === "true" || val === true) {
139
237
  return true;
@@ -142,38 +240,77 @@ var BooleanSchema = BoolOrStringSchema.transform((val) => {
142
240
  }
143
241
  throw new Error("Invalid value");
144
242
  });
145
- var BaseOutputConfigSchema = z.object({
146
- debug: BooleanSchema.default(false),
147
- appwardenApiToken: z.string().refine((appwardenApiToken) => !!appwardenApiToken, {
148
- message: printMessage(
149
- "Please provide a valid `appwardenApiToken`. Learn more at https://appwarden.com/docs/api-tokens."
150
- ),
151
- path: ["appwardenApiToken"]
152
- }),
153
- lockPageSlug: z.string()
243
+ var LockValue = z3.object({
244
+ isLocked: z3.number(),
245
+ isLockedTest: z3.number(),
246
+ lastCheck: z3.number(),
247
+ code: z3.string()
154
248
  });
155
- var LockValue = z.object({
156
- isLocked: z.number(),
157
- isLockedTest: z.number(),
158
- lastCheck: z.number(),
159
- code: z.string()
249
+
250
+ // src/schemas/use-appwarden.ts
251
+ var UseAppwardenInputSchema = z4.object({
252
+ debug: BooleanSchema.default(false),
253
+ lockPageSlug: z4.string(),
254
+ appwardenApiToken: z4.string().refine((val) => !!val, { path: ["appwardenApiToken"] })
160
255
  });
161
256
 
162
257
  // src/schemas/cloudflare.ts
163
- var ConfigOutputSchema = BaseOutputConfigSchema.extend({
164
- middleware: z2.object({ before: z2.custom().array().default([]) }).default({})
165
- });
166
- var ConfigFnInputSchema = z2.function().args(z2.custom()).returns(
167
- ConfigOutputSchema.extend({
168
- debug: BoolOrStringSchema
258
+ var ConfigFnInputSchema = z5.function().args(z5.custom()).returns(
259
+ UseAppwardenInputSchema.extend({
260
+ middleware: z5.object({ before: z5.custom().array().default([]) }).default({})
169
261
  })
170
262
  );
171
- var CloudflareConfigFnOutputSchema = z2.function().args(z2.custom()).returns(ConfigOutputSchema);
172
263
 
173
264
  // src/schemas/nextjs.ts
174
- import { z as z3 } from "zod";
175
- var ConfigOutputSchema2 = BaseOutputConfigSchema;
176
- var NextJsConfigFnOutputSchema = z3.function().args(z3.custom()).returns(ConfigOutputSchema2);
265
+ import { z as z6 } from "zod";
266
+ var NextJsConfigFnOutputSchema = z6.function().args(z6.custom()).returns(UseAppwardenInputSchema);
267
+
268
+ // src/schemas/vercel.ts
269
+ import { z as z7 } from "zod";
270
+ var BaseNextJsConfigSchema = z7.object({
271
+ cacheUrl: z7.string(),
272
+ appwardenApiToken: z7.string(),
273
+ vercelApiToken: z7.string().optional(),
274
+ lockPageSlug: z7.string().default("").transform((val) => val.replace(/^\/?/, "/"))
275
+ });
276
+ var AppwardenConfigSchema = BaseNextJsConfigSchema.refine(
277
+ (data) => isCacheUrl.edgeConfig(data.cacheUrl) || isCacheUrl.upstash(data.cacheUrl),
278
+ {
279
+ message: printMessage(
280
+ "Provided `cacheUrl` is not recognized. Please provide a Vercel Edge Config or Upstash KV url."
281
+ ),
282
+ path: ["cacheUrl"]
283
+ }
284
+ ).refine(
285
+ (data) => isCacheUrl.edgeConfig(data.cacheUrl) ? isValidCacheUrl.edgeConfig(data.cacheUrl) : true,
286
+ {
287
+ message: printMessage(
288
+ "Provided Vercel Edge Config `cacheUrl` is not valid. Please provide a valid Vercel Edge Config url."
289
+ ),
290
+ path: ["cacheUrl"]
291
+ }
292
+ ).refine(
293
+ (data) => isCacheUrl.upstash(data.cacheUrl) ? isValidCacheUrl.upstash(data.cacheUrl) : true,
294
+ {
295
+ message: printMessage(
296
+ "Provided Upstash KV `cacheUrl` is not valid. Please provide a valid Upstash KV url."
297
+ ),
298
+ path: ["cacheUrl"]
299
+ }
300
+ ).refine(
301
+ (data) => isCacheUrl.edgeConfig(data.cacheUrl) ? !!data.vercelApiToken : true,
302
+ {
303
+ message: printMessage(
304
+ "The `vercelApiToken` option is required when using Vercel Edge Config"
305
+ ),
306
+ path: ["vercelApiToken"]
307
+ }
308
+ ).refine((data) => !!data.appwardenApiToken, {
309
+ message: printMessage(
310
+ "Please provide a valid `appwardenApiToken`. Learn more at https://appwarden.com/docs/api-tokens."
311
+ ),
312
+ path: ["appwardenApiToken"]
313
+ });
177
314
 
178
315
  // src/utils/vercel/get-lock-value.ts
179
316
  var getLockValue = async (context) => {
@@ -188,17 +325,22 @@ var getLockValue = async (context) => {
188
325
  switch (context.provider) {
189
326
  case "edge-config": {
190
327
  const { createClient } = await import("@vercel/edge-config");
191
- const edgeConfig = createClient(context.connectionString);
328
+ const edgeConfig = createClient(context.cacheUrl);
192
329
  serializedValue = await edgeConfig.get(
193
330
  context.keyName
194
331
  );
195
332
  break;
196
333
  }
197
334
  case "upstash": {
198
- const [url, token] = context.connectionString.split("@");
335
+ const { hostname, password } = new URL(context.cacheUrl);
199
336
  const { Redis } = await import("@upstash/redis");
200
- const redis = new Redis({ url, token });
201
- const redisValue = await redis.get(context.keyName);
337
+ const redis = new Redis({
338
+ url: `https://${hostname}`,
339
+ token: password
340
+ });
341
+ const redisValue = await redis.get(
342
+ context.keyName
343
+ );
202
344
  serializedValue = redisValue === null ? void 0 : redisValue;
203
345
  break;
204
346
  }
@@ -209,7 +351,9 @@ var getLockValue = async (context) => {
209
351
  return { lockValue: void 0 };
210
352
  }
211
353
  try {
212
- lockValue = LockValue.parse(JSON.parse(serializedValue));
354
+ lockValue = LockValue.parse(
355
+ typeof serializedValue === "string" ? JSON.parse(serializedValue) : serializedValue
356
+ );
213
357
  } catch (error) {
214
358
  console.error(
215
359
  printMessage(
@@ -241,19 +385,17 @@ var APIError = class extends Error {
241
385
  }
242
386
  };
243
387
  var syncEdgeValue = async (context) => {
244
- debug("syncing with api");
388
+ debug(`syncing with api`);
245
389
  try {
246
390
  const response = await fetch(new URL("/v1/status/check", "https://bot-gateway.appwarden.io"), {
247
391
  method: "POST",
248
392
  headers: { "content-type": "application/json" },
249
393
  body: JSON.stringify({
250
394
  service: "vercel",
251
- provider: context.provider,
395
+ cacheUrl: context.cacheUrl,
252
396
  fqdn: context.requestUrl.hostname,
253
- edgeConfigId: context.edgeConfigId ?? "",
254
397
  vercelApiToken: context.vercelApiToken ?? "",
255
- appwardenApiToken: context.appwardenApiToken,
256
- connectionString: context.connectionString
398
+ appwardenApiToken: context.appwardenApiToken
257
399
  })
258
400
  });
259
401
  if (response.status !== 200) {
@@ -325,85 +467,55 @@ var renderLockPage = (context) => fetch(new URL(context.lockPageSlug, context.re
325
467
  }
326
468
  });
327
469
 
328
- // src/schemas/vercel.ts
329
- var MiddlewareSchema = z4.custom(
330
- (val) => typeof val === "function"
331
- );
332
- var BaseNextJsConfigSchema = z4.object({
333
- provider: z4.enum(["upstash", "edge-config"]),
334
- lockPageSlug: z4.string(),
335
- connectionString: z4.string(),
336
- edgeConfigId: z4.string().optional(),
337
- vercelApiToken: z4.string().optional(),
338
- appwardenApiToken: z4.string()
339
- });
340
- var AppwardenConfigSchema = BaseNextJsConfigSchema.refine(
341
- (data) => !!data.appwardenApiToken,
342
- {
343
- message: printMessage(
344
- "Please provide a valid `appwardenApiToken`. Learn more at https://appwarden.com/docs/api-tokens."
345
- ),
346
- path: ["appwardenApiToken"]
347
- }
348
- ).refine(
349
- (data) => {
350
- return data.provider === "upstash" && data.connectionString.includes("upstash.io") || data.provider === "edge-config" && data.connectionString.includes("edge-config.vercel.com");
351
- },
352
- {
353
- message: printMessage(
354
- "Invalid connection string for the selected `provider`"
355
- ),
356
- path: ["connectionString"]
357
- }
358
- ).refine(
359
- (data) => {
360
- return data.provider === "upstash" && data.connectionString.includes("upstash") || data.provider === "edge-config" && data.connectionString.includes("edge-config");
361
- },
362
- {
363
- message: printMessage(
364
- "Invalid connection string for the selected `provider`"
365
- ),
366
- path: ["connectionString"]
367
- }
368
- ).refine(
369
- (data) => {
370
- if (data.provider === "edge-config") {
371
- return !!data.vercelApiToken;
372
- }
373
- return true;
374
- },
375
- {
376
- message: printMessage("Missing vercelApiToken when provider=edge-config"),
377
- path: ["vercelApiToken"]
378
- }
379
- ).refine(
380
- (data) => {
381
- if (data.provider === "edge-config") {
382
- return !!data.edgeConfigId;
383
- }
384
- return true;
385
- },
386
- {
387
- message: printMessage(
388
- "Missing `edgeConfigId` when `provider=edge-config`"
389
- ),
390
- path: ["edgeConfigId"]
391
- }
470
+ // src/schemas/use-content-security-policy.ts
471
+ var CSPDirectivesSchema = z8.union([
472
+ z8.string(),
473
+ ContentSecurityPolicySchema
474
+ ]);
475
+ var CSPModeSchema = z8.literal("disabled").or(z8.literal("report-only")).or(z8.literal("enforced")).optional().default("disabled");
476
+ var UseCSPInputSchema = z8.object({
477
+ mode: CSPModeSchema,
478
+ directives: CSPDirectivesSchema.optional().refine(
479
+ (val) => {
480
+ try {
481
+ if (typeof val === "string") {
482
+ JSON.parse(val);
483
+ }
484
+ return true;
485
+ } catch (error) {
486
+ return false;
487
+ }
488
+ },
489
+ { message: "DirectivesBadParse" /* DirectivesBadParse */ }
490
+ ).transform(
491
+ (val) => typeof val === "string" ? JSON.parse(val) : val
492
+ )
493
+ }).refine(
494
+ (values) => (
495
+ // validate that directives are provided when the mode is "report-only" or "enforced"
496
+ ["report-only", "enforced"].includes(values.mode) && values.directives
497
+ ),
498
+ { path: ["directives"], message: "DirectivesRequired" /* DirectivesRequired */ }
392
499
  );
393
500
 
394
501
  export {
395
502
  LOCKDOWN_TEST_EXPIRY_MS,
396
503
  removedHeaders,
397
- securityHeaders,
398
504
  globalErrors,
399
505
  APPWARDEN_TEST_ROUTE,
506
+ APPWARDEN_CACHE_KEY,
400
507
  debug,
508
+ getErrors,
401
509
  MemoryCache,
510
+ getEdgeConfigId,
511
+ isCacheUrl,
512
+ isValidCacheUrl,
402
513
  printMessage,
403
- BoolOrStringSchema,
404
514
  LockValue,
405
- CloudflareConfigFnOutputSchema,
406
- NextJsConfigFnOutputSchema,
515
+ ConfigFnInputSchema,
516
+ CSPDirectivesSchema,
517
+ CSPModeSchema,
518
+ UseCSPInputSchema,
407
519
  BaseNextJsConfigSchema,
408
520
  AppwardenConfigSchema,
409
521
  syncEdgeValue,