@appwarden/middleware 3.12.0 → 3.13.1

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-95.28%25-brightgreen)
7
+ ![Test Coverage](https://img.shields.io/badge/coverage-94.02%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
@@ -320,6 +320,12 @@ Please review our [security policy](SECURITY.md) for details on how we handle vu
320
320
 
321
321
  This package is published with npm trusted publishers, to prevent npm token exfiltration, and provenance enabled, which provides a verifiable link between the published package and its source code. For more information, see [npm provenance documentation](https://docs.npmjs.com/generating-provenance-statements).
322
322
 
323
+ ## Versioning & dependencies
324
+
325
+ - This project uses Conventional Commits and automated release tooling to keep versions and the changelog up to date.
326
+ - Patch releases may include bug fixes and internal maintenance or dependency updates (for example, Cloudflare Workers types, Wrangler, and GitHub Action tooling). New features are shipped in minor releases.
327
+ - See `CHANGELOG.md` for the complete release history.
328
+
323
329
  ## License
324
330
 
325
331
  This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
@@ -2,12 +2,12 @@ import {
2
2
  MemoryCache,
3
3
  debug,
4
4
  printMessage
5
- } from "./chunk-HTSD4WPC.js";
5
+ } from "./chunk-U7E4KM2B.js";
6
6
  import {
7
7
  APPWARDEN_CACHE_KEY,
8
8
  APPWARDEN_TEST_ROUTE,
9
9
  LockValue
10
- } from "./chunk-Z7P4QVEY.js";
10
+ } from "./chunk-OIEAURS7.js";
11
11
 
12
12
  // src/utils/cloudflare/cloudflare-cache.ts
13
13
  var store = {
@@ -5,10 +5,13 @@ var globalErrors = [errors.badCacheConnection];
5
5
  var APPWARDEN_TEST_ROUTE = "/_appwarden/test";
6
6
  var APPWARDEN_HEARTBEAT_ROUTE = "/_appwarden/heartbeat";
7
7
  var HEARTBEAT_CONTRACT_VERSION = 1;
8
+ var HEARTBEAT_VERSION_MAX_LENGTH = 128;
8
9
  var HEARTBEAT_CONFIG_ERROR_MAX_COUNT = 10;
9
10
  var HEARTBEAT_CONFIG_ERROR_MAX_PATH_DEPTH = 10;
10
11
  var HEARTBEAT_CONFIG_ERROR_MAX_CODE_LENGTH = 100;
11
12
  var HEARTBEAT_CONFIG_ERROR_MAX_MESSAGE_LENGTH = 500;
13
+ var HEARTBEAT_CONFIG_ERRORS_MAX_SERIALIZED_BYTES = 12 * 1024;
14
+ var HEARTBEAT_RESPONSE_BODY_MAX_SERIALIZED_BYTES = 32 * 1024;
12
15
  var HEARTBEAT_CONFIG_ERROR_MAX_PATH_SEGMENT_LENGTH = 100;
13
16
  var APPWARDEN_CACHE_KEY = "appwarden-lock";
14
17
  var HEARTBEAT_SERVICE_VALUES = [
@@ -36,13 +39,78 @@ var HEARTBEAT_SERVICES = {
36
39
  VERCEL
37
40
  };
38
41
 
42
+ // src/types/heartbeat.ts
43
+ import { z } from "zod";
44
+ function getSerializedJsonByteLength(value) {
45
+ return new TextEncoder().encode(JSON.stringify(value)).length;
46
+ }
47
+ function getHeartbeatResponseBodyByteBudgetIssue() {
48
+ return {
49
+ code: z.ZodIssueCode.custom,
50
+ message: `Serialized heartbeat response body must be at most ${HEARTBEAT_RESPONSE_BODY_MAX_SERIALIZED_BYTES} bytes`,
51
+ path: []
52
+ };
53
+ }
54
+ function getHeartbeatResponseBodySerializationIssue() {
55
+ return {
56
+ code: z.ZodIssueCode.custom,
57
+ message: "Heartbeat response body must be JSON-serializable",
58
+ path: []
59
+ };
60
+ }
61
+ var HeartbeatConfigErrorPathSegmentSchema = z.union([
62
+ z.string().max(HEARTBEAT_CONFIG_ERROR_MAX_PATH_SEGMENT_LENGTH),
63
+ z.number().int().nonnegative()
64
+ ]);
65
+ var HeartbeatConfigErrorSchema = z.object({
66
+ path: z.array(HeartbeatConfigErrorPathSegmentSchema).max(HEARTBEAT_CONFIG_ERROR_MAX_PATH_DEPTH),
67
+ code: z.string().min(1).max(HEARTBEAT_CONFIG_ERROR_MAX_CODE_LENGTH),
68
+ message: z.string().min(1).max(HEARTBEAT_CONFIG_ERROR_MAX_MESSAGE_LENGTH)
69
+ }).strict();
70
+ var HeartbeatConfigErrorsSchema = z.array(HeartbeatConfigErrorSchema).max(HEARTBEAT_CONFIG_ERROR_MAX_COUNT).superRefine((configErrors, ctx) => {
71
+ if (getSerializedJsonByteLength(configErrors) > HEARTBEAT_CONFIG_ERRORS_MAX_SERIALIZED_BYTES) {
72
+ ctx.addIssue({
73
+ code: z.ZodIssueCode.custom,
74
+ message: `Serialized configErrors payload must be at most ${HEARTBEAT_CONFIG_ERRORS_MAX_SERIALIZED_BYTES} bytes`
75
+ });
76
+ }
77
+ });
78
+ var HeartbeatResponseBodySchema = z.object({
79
+ app: z.literal("appwarden"),
80
+ kind: z.literal("heartbeat"),
81
+ status: z.literal("ok"),
82
+ contractVersion: z.literal(HEARTBEAT_CONTRACT_VERSION),
83
+ service: z.enum(HEARTBEAT_SERVICE_VALUES),
84
+ version: z.string().min(1).max(HEARTBEAT_VERSION_MAX_LENGTH),
85
+ configErrors: HeartbeatConfigErrorsSchema
86
+ }).strict().superRefine((body, ctx) => {
87
+ if (getSerializedJsonByteLength(body) > HEARTBEAT_RESPONSE_BODY_MAX_SERIALIZED_BYTES) {
88
+ ctx.addIssue({
89
+ code: z.ZodIssueCode.custom,
90
+ message: `Serialized heartbeat response body must be at most ${HEARTBEAT_RESPONSE_BODY_MAX_SERIALIZED_BYTES} bytes`
91
+ });
92
+ }
93
+ });
94
+ function validateHeartbeatResponseBody(value) {
95
+ let serializedJsonByteLength;
96
+ try {
97
+ serializedJsonByteLength = getSerializedJsonByteLength(value);
98
+ } catch {
99
+ throw new z.ZodError([getHeartbeatResponseBodySerializationIssue()]);
100
+ }
101
+ if (serializedJsonByteLength > HEARTBEAT_RESPONSE_BODY_MAX_SERIALIZED_BYTES) {
102
+ throw new z.ZodError([getHeartbeatResponseBodyByteBudgetIssue()]);
103
+ }
104
+ return HeartbeatResponseBodySchema.parse(value);
105
+ }
106
+
39
107
  // src/schemas/use-content-security-policy.ts
40
- import { z as z3 } from "zod";
108
+ import { z as z4 } from "zod";
41
109
 
42
110
  // src/types/csp.ts
43
- import { z } from "zod";
44
- var stringySchema = z.union([z.array(z.string()), z.string(), z.boolean()]);
45
- var ContentSecurityPolicySchema = z.object({
111
+ import { z as z2 } from "zod";
112
+ var stringySchema = z2.union([z2.array(z2.string()), z2.string(), z2.boolean()]);
113
+ var ContentSecurityPolicySchema = z2.object({
46
114
  "default-src": stringySchema.optional(),
47
115
  "script-src": stringySchema.optional(),
48
116
  "style-src": stringySchema.optional(),
@@ -72,8 +140,8 @@ var ContentSecurityPolicySchema = z.object({
72
140
  });
73
141
 
74
142
  // src/schemas/helpers.ts
75
- import { z as z2 } from "zod";
76
- var BoolOrStringSchema = z2.union([z2.string(), z2.boolean()]).optional();
143
+ import { z as z3 } from "zod";
144
+ var BoolOrStringSchema = z3.union([z3.string(), z3.boolean()]).optional();
77
145
  var BooleanSchema = BoolOrStringSchema.transform((val) => {
78
146
  if (val === "true" || val === true) {
79
147
  return true;
@@ -82,29 +150,29 @@ var BooleanSchema = BoolOrStringSchema.transform((val) => {
82
150
  }
83
151
  throw new Error("Invalid value");
84
152
  });
85
- var AppwardenApiTokenSchema = z2.string().refine((val) => !!val, { message: "appwardenApiToken is required" });
86
- var AppwardenApiHostnameSchema = z2.string().url({
153
+ var AppwardenApiTokenSchema = z3.string().refine((val) => !!val, { message: "appwardenApiToken is required" });
154
+ var AppwardenApiHostnameSchema = z3.string().url({
87
155
  message: "Invalid `appwardenApiHostname`. Please provide an absolute URL (e.g. https://api.appwarden.io)."
88
156
  }).refine((value) => value.startsWith("https://"), {
89
157
  message: "`appwardenApiHostname` must use the https:// scheme (e.g. https://api.appwarden.io)."
90
158
  });
91
- var LockValue = z2.object({
92
- isLocked: z2.number(),
93
- isLockedTest: z2.number(),
94
- lastCheck: z2.number()
159
+ var LockValue = z3.object({
160
+ isLocked: z3.number(),
161
+ isLockedTest: z3.number(),
162
+ lastCheck: z3.number()
95
163
  });
96
164
 
97
165
  // src/schemas/use-content-security-policy.ts
98
- var CSPDirectivesSchema = z3.union([
99
- z3.string(),
166
+ var CSPDirectivesSchema = z4.union([
167
+ z4.string(),
100
168
  ContentSecurityPolicySchema
101
169
  ]);
102
- var CSPModeSchema = z3.union([
103
- z3.literal("disabled"),
104
- z3.literal("report-only"),
105
- z3.literal("enforced")
170
+ var CSPModeSchema = z4.union([
171
+ z4.literal("disabled"),
172
+ z4.literal("report-only"),
173
+ z4.literal("enforced")
106
174
  ]);
107
- var UseCSPInputSchema = z3.object({
175
+ var UseCSPInputSchema = z4.object({
108
176
  mode: CSPModeSchema,
109
177
  directives: CSPDirectivesSchema.refine(
110
178
  (val) => {
@@ -130,17 +198,24 @@ export {
130
198
  APPWARDEN_TEST_ROUTE,
131
199
  APPWARDEN_HEARTBEAT_ROUTE,
132
200
  HEARTBEAT_CONTRACT_VERSION,
201
+ HEARTBEAT_VERSION_MAX_LENGTH,
133
202
  HEARTBEAT_CONFIG_ERROR_MAX_COUNT,
134
203
  HEARTBEAT_CONFIG_ERROR_MAX_PATH_DEPTH,
135
204
  HEARTBEAT_CONFIG_ERROR_MAX_CODE_LENGTH,
136
205
  HEARTBEAT_CONFIG_ERROR_MAX_MESSAGE_LENGTH,
206
+ HEARTBEAT_CONFIG_ERRORS_MAX_SERIALIZED_BYTES,
207
+ HEARTBEAT_RESPONSE_BODY_MAX_SERIALIZED_BYTES,
137
208
  HEARTBEAT_CONFIG_ERROR_MAX_PATH_SEGMENT_LENGTH,
138
209
  APPWARDEN_CACHE_KEY,
210
+ HEARTBEAT_SERVICE_VALUES,
139
211
  HEARTBEAT_SERVICES,
140
212
  BooleanSchema,
141
213
  AppwardenApiTokenSchema,
142
214
  AppwardenApiHostnameSchema,
143
215
  LockValue,
216
+ HeartbeatConfigErrorSchema,
217
+ HeartbeatResponseBodySchema,
218
+ validateHeartbeatResponseBody,
144
219
  CSPDirectivesSchema,
145
220
  CSPModeSchema,
146
221
  UseCSPInputSchema
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  isHTMLResponse,
3
3
  makeCSPHeader
4
- } from "./chunk-HTSD4WPC.js";
4
+ } from "./chunk-U7E4KM2B.js";
5
5
  import {
6
6
  UseCSPInputSchema
7
- } from "./chunk-Z7P4QVEY.js";
7
+ } from "./chunk-OIEAURS7.js";
8
8
 
9
9
  // src/middlewares/use-content-security-policy.ts
10
10
  var AppendAttribute = (attribute, nonce) => ({
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  useContentSecurityPolicy
3
- } from "./chunk-ILIYP3TG.js";
3
+ } from "./chunk-Q5LVKCWK.js";
4
4
 
5
5
  // src/utils/apply-content-security-policy-to-response.ts
6
6
  var applyContentSecurityPolicyToResponse = async ({
@@ -1,13 +1,16 @@
1
1
  import {
2
2
  APPWARDEN_HEARTBEAT_ROUTE,
3
+ HEARTBEAT_CONFIG_ERRORS_MAX_SERIALIZED_BYTES,
3
4
  HEARTBEAT_CONFIG_ERROR_MAX_CODE_LENGTH,
4
5
  HEARTBEAT_CONFIG_ERROR_MAX_COUNT,
5
6
  HEARTBEAT_CONFIG_ERROR_MAX_MESSAGE_LENGTH,
6
7
  HEARTBEAT_CONFIG_ERROR_MAX_PATH_DEPTH,
7
8
  HEARTBEAT_CONFIG_ERROR_MAX_PATH_SEGMENT_LENGTH,
8
9
  HEARTBEAT_CONTRACT_VERSION,
9
- LOCKDOWN_TEST_EXPIRY_MS
10
- } from "./chunk-Z7P4QVEY.js";
10
+ HEARTBEAT_RESPONSE_BODY_MAX_SERIALIZED_BYTES,
11
+ LOCKDOWN_TEST_EXPIRY_MS,
12
+ validateHeartbeatResponseBody
13
+ } from "./chunk-OIEAURS7.js";
11
14
 
12
15
  // src/utils/build-lock-page-url.ts
13
16
  function normalizeLockPageSlug(lockPageSlug) {
@@ -119,9 +122,14 @@ var MemoryCache = class {
119
122
  };
120
123
 
121
124
  // src/version.ts
122
- var MIDDLEWARE_VERSION = "3.11.6";
125
+ var MIDDLEWARE_VERSION = "3.13.0";
123
126
 
124
127
  // src/utils/heartbeat.ts
128
+ var DEFAULT_HEARTBEAT_CONFIG_ERROR_CODE = "custom";
129
+ var DEFAULT_HEARTBEAT_CONFIG_ERROR_MESSAGE = "Appwarden configuration validation failed";
130
+ var HEARTBEAT_CONSTRUCTION_FAILURE_BODY = JSON.stringify({
131
+ error: "appwarden_heartbeat_construction_failed"
132
+ });
125
133
  function createSanitizedMessage(code, path) {
126
134
  const fieldName = path.length > 0 ? path[path.length - 1] : "field";
127
135
  switch (code) {
@@ -159,39 +167,80 @@ function createSanitizedMessage(code, path) {
159
167
  return `Validation error for ${fieldName}`;
160
168
  }
161
169
  }
170
+ function truncateWithEllipsis(value, maxLength) {
171
+ if (value.length <= maxLength) {
172
+ return value;
173
+ }
174
+ if (maxLength <= 3) {
175
+ return value.substring(0, maxLength);
176
+ }
177
+ return value.substring(0, maxLength - 3) + "...";
178
+ }
179
+ function sanitizePathSegment(segment) {
180
+ if (typeof segment === "number" && Number.isFinite(segment)) {
181
+ return Number.isSafeInteger(segment) ? Math.max(0, segment) : Math.max(0, Math.trunc(segment));
182
+ }
183
+ return truncateWithEllipsis(
184
+ typeof segment === "string" ? segment : String(segment),
185
+ HEARTBEAT_CONFIG_ERROR_MAX_PATH_SEGMENT_LENGTH
186
+ );
187
+ }
162
188
  function sanitizePath(path) {
163
189
  const truncatedPath = path.slice(0, HEARTBEAT_CONFIG_ERROR_MAX_PATH_DEPTH);
164
- return truncatedPath.map((segment) => {
165
- if (typeof segment === "string" && segment.length > HEARTBEAT_CONFIG_ERROR_MAX_PATH_SEGMENT_LENGTH) {
166
- return segment.substring(
167
- 0,
168
- HEARTBEAT_CONFIG_ERROR_MAX_PATH_SEGMENT_LENGTH - 3
169
- ) + "...";
170
- }
171
- return segment;
172
- });
190
+ return truncatedPath.map(sanitizePathSegment);
173
191
  }
174
192
  function truncateMessage(message) {
175
- if (message.length <= HEARTBEAT_CONFIG_ERROR_MAX_MESSAGE_LENGTH) {
176
- return message;
193
+ return truncateWithEllipsis(
194
+ message,
195
+ HEARTBEAT_CONFIG_ERROR_MAX_MESSAGE_LENGTH
196
+ );
197
+ }
198
+ function truncateCode(code) {
199
+ return truncateWithEllipsis(code, HEARTBEAT_CONFIG_ERROR_MAX_CODE_LENGTH);
200
+ }
201
+ function normalizeNonEmptyString(value, fallback, truncate) {
202
+ const normalizedValue = truncate(value.trim());
203
+ if (normalizedValue.length > 0) {
204
+ return normalizedValue;
177
205
  }
178
- return message.substring(0, HEARTBEAT_CONFIG_ERROR_MAX_MESSAGE_LENGTH - 3) + "...";
206
+ return truncate(fallback);
207
+ }
208
+ function getSerializedJsonByteLength(value) {
209
+ return new TextEncoder().encode(JSON.stringify(value)).length;
210
+ }
211
+ function isConfigErrorsWithinByteBudget(configErrors) {
212
+ return getSerializedJsonByteLength(configErrors) <= HEARTBEAT_CONFIG_ERRORS_MAX_SERIALIZED_BYTES;
213
+ }
214
+ function isResponseBodyWithinByteBudget(body) {
215
+ return getSerializedJsonByteLength(body) <= HEARTBEAT_RESPONSE_BODY_MAX_SERIALIZED_BYTES;
179
216
  }
180
217
  function createHeartbeatConfigError(path, code, message) {
181
218
  return {
182
219
  path: sanitizePath(path),
183
- code: code.substring(0, HEARTBEAT_CONFIG_ERROR_MAX_CODE_LENGTH),
184
- message: truncateMessage(message)
220
+ code: normalizeNonEmptyString(
221
+ code,
222
+ DEFAULT_HEARTBEAT_CONFIG_ERROR_CODE,
223
+ truncateCode
224
+ ),
225
+ message: normalizeNonEmptyString(
226
+ message,
227
+ DEFAULT_HEARTBEAT_CONFIG_ERROR_MESSAGE,
228
+ truncateMessage
229
+ )
185
230
  };
186
231
  }
187
232
  function normalizeHeartbeatConfigErrors(configErrors) {
188
- return configErrors.slice(0, HEARTBEAT_CONFIG_ERROR_MAX_COUNT).map(
233
+ const normalizedConfigErrors = configErrors.slice(0, HEARTBEAT_CONFIG_ERROR_MAX_COUNT).map(
189
234
  (configError) => createHeartbeatConfigError(
190
235
  configError.path,
191
236
  configError.code,
192
237
  configError.message
193
238
  )
194
239
  );
240
+ while (normalizedConfigErrors.length > 0 && !isConfigErrorsWithinByteBudget(normalizedConfigErrors)) {
241
+ normalizedConfigErrors.pop();
242
+ }
243
+ return normalizedConfigErrors;
195
244
  }
196
245
  function sanitizeConfigErrors(error) {
197
246
  if (!error) {
@@ -213,30 +262,48 @@ function sanitizeConfigErrors(error) {
213
262
  return errors;
214
263
  }
215
264
  function createHeartbeatResponseBody(service, configErrors = []) {
216
- return {
265
+ const normalizedConfigErrors = normalizeHeartbeatConfigErrors(configErrors);
266
+ const body = {
217
267
  app: "appwarden",
218
268
  kind: "heartbeat",
219
269
  status: "ok",
220
270
  contractVersion: HEARTBEAT_CONTRACT_VERSION,
221
271
  service,
222
272
  version: MIDDLEWARE_VERSION,
223
- configErrors: normalizeHeartbeatConfigErrors(configErrors)
273
+ configErrors: normalizedConfigErrors
224
274
  };
275
+ while (body.configErrors.length > 0 && !isResponseBodyWithinByteBudget(body)) {
276
+ body.configErrors.pop();
277
+ }
278
+ return validateHeartbeatResponseBody(body);
225
279
  }
226
- function createHeartbeatResponse(service, configErrors = []) {
227
- const body = createHeartbeatResponseBody(service, configErrors);
228
- return new Response(JSON.stringify(body), {
229
- status: 200,
280
+ function createHeartbeatConstructionFailureResponse() {
281
+ return new Response(HEARTBEAT_CONSTRUCTION_FAILURE_BODY, {
282
+ status: 500,
230
283
  headers: {
231
284
  "content-type": "application/json",
232
- "cache-control": "no-store",
233
- "x-appwarden-heartbeat": "1",
234
- "x-appwarden-contract-version": String(HEARTBEAT_CONTRACT_VERSION),
235
- "x-appwarden-service": service,
236
- "x-appwarden-version": MIDDLEWARE_VERSION
285
+ "cache-control": "no-store"
237
286
  }
238
287
  });
239
288
  }
289
+ function createHeartbeatResponse(service, configErrors = []) {
290
+ try {
291
+ const body = createHeartbeatResponseBody(service, configErrors);
292
+ return new Response(JSON.stringify(body), {
293
+ status: 200,
294
+ headers: {
295
+ "content-type": "application/json",
296
+ "cache-control": "no-store",
297
+ "x-appwarden-heartbeat": "1",
298
+ "x-appwarden-contract-version": String(HEARTBEAT_CONTRACT_VERSION),
299
+ "x-appwarden-service": service,
300
+ "x-appwarden-version": MIDDLEWARE_VERSION
301
+ }
302
+ });
303
+ } catch {
304
+ return createHeartbeatConstructionFailureResponse();
305
+ }
306
+ }
240
307
  function isHeartbeatRoute(url) {
241
308
  return url.pathname === APPWARDEN_HEARTBEAT_ROUTE;
242
309
  }
@@ -3,7 +3,7 @@ import {
3
3
  AppwardenApiTokenSchema,
4
4
  BooleanSchema,
5
5
  UseCSPInputSchema
6
- } from "./chunk-Z7P4QVEY.js";
6
+ } from "./chunk-OIEAURS7.js";
7
7
 
8
8
  // src/schemas/use-appwarden.ts
9
9
  import { z } from "zod";
@@ -270,8 +270,8 @@ declare const AstroCloudflareConfigSchema: z.ZodObject<{
270
270
  };
271
271
  }>>>;
272
272
  }, "strip", z.ZodTypeAny, {
273
- lockPageSlug: string;
274
273
  debug: boolean;
274
+ lockPageSlug: string;
275
275
  appwardenApiToken: string;
276
276
  contentSecurityPolicy?: {
277
277
  mode: "disabled" | "report-only" | "enforced";
@@ -308,6 +308,7 @@ declare const AstroCloudflareConfigSchema: z.ZodObject<{
308
308
  }, {
309
309
  lockPageSlug: string;
310
310
  appwardenApiToken: string;
311
+ debug?: string | boolean | undefined;
311
312
  contentSecurityPolicy?: {
312
313
  mode: "disabled" | "report-only" | "enforced";
313
314
  directives: string | {
@@ -339,7 +340,6 @@ declare const AstroCloudflareConfigSchema: z.ZodObject<{
339
340
  "require-trusted-types-for"?: string | boolean | string[] | undefined;
340
341
  };
341
342
  } | undefined;
342
- debug?: string | boolean | undefined;
343
343
  appwardenApiHostname?: string | undefined;
344
344
  }>;
345
345
  type AstroCloudflareConfig = z.infer<typeof AstroCloudflareConfigSchema>;
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  applyContentSecurityPolicyToResponse,
3
3
  isResponseLike
4
- } from "../chunk-M2YVPCTG.js";
5
- import "../chunk-ILIYP3TG.js";
4
+ } from "../chunk-QM56445N.js";
5
+ import "../chunk-Q5LVKCWK.js";
6
6
  import {
7
7
  getNowMs,
8
8
  logElapsed
9
9
  } from "../chunk-G6BMPIYD.js";
10
10
  import {
11
11
  checkLockStatus
12
- } from "../chunk-EXGUJ5XK.js";
12
+ } from "../chunk-CVOSFBOE.js";
13
13
  import {
14
14
  TEMPORARY_REDIRECT_STATUS,
15
15
  buildLockPageUrl,
@@ -22,14 +22,14 @@ import {
22
22
  isOnLockPage,
23
23
  printMessage,
24
24
  sanitizeConfigErrors
25
- } from "../chunk-HTSD4WPC.js";
25
+ } from "../chunk-U7E4KM2B.js";
26
26
  import {
27
27
  AppwardenApiHostnameSchema,
28
28
  AppwardenApiTokenSchema,
29
29
  BooleanSchema,
30
30
  HEARTBEAT_SERVICES,
31
31
  UseCSPInputSchema
32
- } from "../chunk-Z7P4QVEY.js";
32
+ } from "../chunk-OIEAURS7.js";
33
33
 
34
34
  // src/adapters/astro-cloudflare.ts
35
35
  import { waitUntil } from "cloudflare:workers";
@@ -329,8 +329,8 @@ declare const NextJsCloudflareConfigSchema: z.ZodObject<{
329
329
  };
330
330
  }>>>;
331
331
  }, "strip", z.ZodTypeAny, {
332
- lockPageSlug: string;
333
332
  debug: boolean;
333
+ lockPageSlug: string;
334
334
  appwardenApiToken: string;
335
335
  contentSecurityPolicy?: {
336
336
  mode: "disabled" | "report-only" | "enforced";
@@ -367,6 +367,7 @@ declare const NextJsCloudflareConfigSchema: z.ZodObject<{
367
367
  }, {
368
368
  lockPageSlug: string;
369
369
  appwardenApiToken: string;
370
+ debug?: string | boolean | undefined;
370
371
  contentSecurityPolicy?: {
371
372
  mode: "disabled" | "report-only" | "enforced";
372
373
  directives: string | {
@@ -398,7 +399,6 @@ declare const NextJsCloudflareConfigSchema: z.ZodObject<{
398
399
  "require-trusted-types-for"?: string | boolean | string[] | undefined;
399
400
  };
400
401
  } | undefined;
401
- debug?: string | boolean | undefined;
402
402
  appwardenApiHostname?: string | undefined;
403
403
  }>;
404
404
  type NextJsCloudflareConfig = z.infer<typeof NextJsCloudflareConfigSchema>;
@@ -7,7 +7,7 @@ import {
7
7
  } from "../chunk-G6BMPIYD.js";
8
8
  import {
9
9
  checkLockStatus
10
- } from "../chunk-EXGUJ5XK.js";
10
+ } from "../chunk-CVOSFBOE.js";
11
11
  import {
12
12
  TEMPORARY_REDIRECT_STATUS,
13
13
  buildLockPageUrl,
@@ -20,14 +20,14 @@ import {
20
20
  makeCSPHeader,
21
21
  printMessage,
22
22
  sanitizeConfigErrors
23
- } from "../chunk-HTSD4WPC.js";
23
+ } from "../chunk-U7E4KM2B.js";
24
24
  import {
25
25
  AppwardenApiHostnameSchema,
26
26
  AppwardenApiTokenSchema,
27
27
  BooleanSchema,
28
28
  HEARTBEAT_SERVICES,
29
29
  UseCSPInputSchema
30
- } from "../chunk-Z7P4QVEY.js";
30
+ } from "../chunk-OIEAURS7.js";
31
31
 
32
32
  // src/adapters/nextjs-cloudflare.ts
33
33
  import { getCloudflareContext } from "@opennextjs/cloudflare";
@@ -268,8 +268,8 @@ declare const ReactRouterCloudflareConfigSchema: z.ZodObject<{
268
268
  };
269
269
  }>>>;
270
270
  }, "strip", z.ZodTypeAny, {
271
- lockPageSlug: string;
272
271
  debug: boolean;
272
+ lockPageSlug: string;
273
273
  appwardenApiToken: string;
274
274
  contentSecurityPolicy?: {
275
275
  mode: "disabled" | "report-only" | "enforced";
@@ -306,6 +306,7 @@ declare const ReactRouterCloudflareConfigSchema: z.ZodObject<{
306
306
  }, {
307
307
  lockPageSlug: string;
308
308
  appwardenApiToken: string;
309
+ debug?: string | boolean | undefined;
309
310
  contentSecurityPolicy?: {
310
311
  mode: "disabled" | "report-only" | "enforced";
311
312
  directives: string | {
@@ -337,7 +338,6 @@ declare const ReactRouterCloudflareConfigSchema: z.ZodObject<{
337
338
  "require-trusted-types-for"?: string | boolean | string[] | undefined;
338
339
  };
339
340
  } | undefined;
340
- debug?: string | boolean | undefined;
341
341
  appwardenApiHostname?: string | undefined;
342
342
  }>;
343
343
  type ReactRouterCloudflareConfig = z.infer<typeof ReactRouterCloudflareConfigSchema>;
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  applyContentSecurityPolicyToResponse,
3
3
  isResponseLike
4
- } from "../chunk-M2YVPCTG.js";
5
- import "../chunk-ILIYP3TG.js";
4
+ } from "../chunk-QM56445N.js";
5
+ import "../chunk-Q5LVKCWK.js";
6
6
  import {
7
7
  getNowMs,
8
8
  logElapsed
9
9
  } from "../chunk-G6BMPIYD.js";
10
10
  import {
11
11
  checkLockStatus
12
- } from "../chunk-EXGUJ5XK.js";
12
+ } from "../chunk-CVOSFBOE.js";
13
13
  import {
14
14
  buildLockPageUrl,
15
15
  createHeartbeatConfigError,
@@ -21,14 +21,14 @@ import {
21
21
  isOnLockPage,
22
22
  printMessage,
23
23
  sanitizeConfigErrors
24
- } from "../chunk-HTSD4WPC.js";
24
+ } from "../chunk-U7E4KM2B.js";
25
25
  import {
26
26
  AppwardenApiHostnameSchema,
27
27
  AppwardenApiTokenSchema,
28
28
  BooleanSchema,
29
29
  HEARTBEAT_SERVICES,
30
30
  UseCSPInputSchema
31
- } from "../chunk-Z7P4QVEY.js";
31
+ } from "../chunk-OIEAURS7.js";
32
32
 
33
33
  // src/adapters/react-router-cloudflare.ts
34
34
  import { waitUntil } from "cloudflare:workers";
@@ -268,8 +268,8 @@ declare const TanStackStartCloudflareConfigSchema: z.ZodObject<{
268
268
  };
269
269
  }>>>;
270
270
  }, "strip", z.ZodTypeAny, {
271
- lockPageSlug: string;
272
271
  debug: boolean;
272
+ lockPageSlug: string;
273
273
  appwardenApiToken: string;
274
274
  contentSecurityPolicy?: {
275
275
  mode: "disabled" | "report-only" | "enforced";
@@ -306,6 +306,7 @@ declare const TanStackStartCloudflareConfigSchema: z.ZodObject<{
306
306
  }, {
307
307
  lockPageSlug: string;
308
308
  appwardenApiToken: string;
309
+ debug?: string | boolean | undefined;
309
310
  contentSecurityPolicy?: {
310
311
  mode: "disabled" | "report-only" | "enforced";
311
312
  directives: string | {
@@ -337,7 +338,6 @@ declare const TanStackStartCloudflareConfigSchema: z.ZodObject<{
337
338
  "require-trusted-types-for"?: string | boolean | string[] | undefined;
338
339
  };
339
340
  } | undefined;
340
- debug?: string | boolean | undefined;
341
341
  appwardenApiHostname?: string | undefined;
342
342
  }>;
343
343
  type TanStackStartCloudflareConfig = z.infer<typeof TanStackStartCloudflareConfigSchema>;
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  applyContentSecurityPolicyToResponse,
3
3
  isResponseLike
4
- } from "../chunk-M2YVPCTG.js";
5
- import "../chunk-ILIYP3TG.js";
4
+ } from "../chunk-QM56445N.js";
5
+ import "../chunk-Q5LVKCWK.js";
6
6
  import {
7
7
  getNowMs,
8
8
  logElapsed
9
9
  } from "../chunk-G6BMPIYD.js";
10
10
  import {
11
11
  checkLockStatus
12
- } from "../chunk-EXGUJ5XK.js";
12
+ } from "../chunk-CVOSFBOE.js";
13
13
  import {
14
14
  buildLockPageUrl,
15
15
  createHeartbeatConfigError,
@@ -21,14 +21,14 @@ import {
21
21
  isOnLockPage,
22
22
  printMessage,
23
23
  sanitizeConfigErrors
24
- } from "../chunk-HTSD4WPC.js";
24
+ } from "../chunk-U7E4KM2B.js";
25
25
  import {
26
26
  AppwardenApiHostnameSchema,
27
27
  AppwardenApiTokenSchema,
28
28
  BooleanSchema,
29
29
  HEARTBEAT_SERVICES,
30
30
  UseCSPInputSchema
31
- } from "../chunk-Z7P4QVEY.js";
31
+ } from "../chunk-OIEAURS7.js";
32
32
 
33
33
  // src/adapters/tanstack-start-cloudflare.ts
34
34
  import { waitUntil } from "cloudflare:workers";
package/cloudflare.js CHANGED
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  UseAppwardenInputSchema,
3
3
  lockPageSlugRefinement
4
- } from "./chunk-6YCNCR22.js";
4
+ } from "./chunk-UBWPR24M.js";
5
5
  import {
6
6
  getErrors
7
7
  } from "./chunk-NV7K5PRA.js";
8
8
  import {
9
9
  useContentSecurityPolicy
10
- } from "./chunk-ILIYP3TG.js";
10
+ } from "./chunk-Q5LVKCWK.js";
11
11
  import {
12
12
  checkLockStatus
13
- } from "./chunk-EXGUJ5XK.js";
13
+ } from "./chunk-CVOSFBOE.js";
14
14
  import {
15
15
  buildLockPageUrl,
16
16
  createHeartbeatConfigError,
@@ -22,10 +22,10 @@ import {
22
22
  isOnLockPage,
23
23
  printMessage,
24
24
  sanitizeConfigErrors
25
- } from "./chunk-HTSD4WPC.js";
25
+ } from "./chunk-U7E4KM2B.js";
26
26
  import {
27
27
  HEARTBEAT_SERVICES
28
- } from "./chunk-Z7P4QVEY.js";
28
+ } from "./chunk-OIEAURS7.js";
29
29
 
30
30
  // src/runners/appwarden-on-cloudflare.ts
31
31
  import { ZodError } from "zod";
package/index.d.ts CHANGED
@@ -2,7 +2,156 @@ export { B as Bindings, C as CSPDirectivesSchema, a as CSPModeSchema, M as Middl
2
2
  import { z } from 'zod';
3
3
 
4
4
  declare const LOCKDOWN_TEST_EXPIRY_MS: number;
5
+ declare const APPWARDEN_HEARTBEAT_ROUTE = "/_appwarden/heartbeat";
6
+ declare const HEARTBEAT_CONTRACT_VERSION: 1;
7
+ declare const HEARTBEAT_VERSION_MAX_LENGTH = 128;
8
+ /**
9
+ * Maximum number of public heartbeat config errors.
10
+ * Prevents unbounded response sizes.
11
+ */
12
+ declare const HEARTBEAT_CONFIG_ERROR_MAX_COUNT = 10;
13
+ /**
14
+ * Maximum path depth for public heartbeat config errors.
15
+ * Prevents deeply nested paths from being exposed.
16
+ */
17
+ declare const HEARTBEAT_CONFIG_ERROR_MAX_PATH_DEPTH = 10;
18
+ /**
19
+ * Maximum length for public heartbeat config error codes.
20
+ * Keeps error codes within the contract bounds.
21
+ */
22
+ declare const HEARTBEAT_CONFIG_ERROR_MAX_CODE_LENGTH = 100;
23
+ /**
24
+ * Maximum length for public heartbeat config error messages.
25
+ * Prevents excessively long messages from being exposed.
26
+ */
27
+ declare const HEARTBEAT_CONFIG_ERROR_MAX_MESSAGE_LENGTH = 500;
28
+ declare const HEARTBEAT_CONFIG_ERRORS_MAX_SERIALIZED_BYTES: number;
29
+ declare const HEARTBEAT_RESPONSE_BODY_MAX_SERIALIZED_BYTES: number;
30
+ /**
31
+ * Maximum length for individual public heartbeat config error path segments.
32
+ * Prevents excessively long path segments from being exposed.
33
+ */
34
+ declare const HEARTBEAT_CONFIG_ERROR_MAX_PATH_SEGMENT_LENGTH = 100;
5
35
  declare const APPWARDEN_CACHE_KEY: "appwarden-lock";
36
+ declare const HEARTBEAT_SERVICE_VALUES: readonly ["cloudflare", "cloudflare-astro", "cloudflare-react-router", "cloudflare-tanstack-start", "cloudflare-nextjs", "vercel"];
37
+ /**
38
+ * Service identifiers for different middleware adapters.
39
+ * These are hardcoded per adapter bundle.
40
+ */
41
+ declare const HEARTBEAT_SERVICES: {
42
+ readonly CLOUDFLARE: "cloudflare";
43
+ readonly CLOUDFLARE_ASTRO: "cloudflare-astro";
44
+ readonly CLOUDFLARE_REACT_ROUTER: "cloudflare-react-router";
45
+ readonly CLOUDFLARE_TANSTACK_START: "cloudflare-tanstack-start";
46
+ readonly CLOUDFLARE_NEXTJS: "cloudflare-nextjs";
47
+ readonly VERCEL: "vercel";
48
+ };
49
+
50
+ /**
51
+ * Service identifiers for different middleware adapters.
52
+ * These are hardcoded per adapter bundle.
53
+ */
54
+ type HeartbeatService = (typeof HEARTBEAT_SERVICE_VALUES)[number];
55
+ /**
56
+ * Schema for validating heartbeat config errors.
57
+ * Ensures errors are bounded and sanitized.
58
+ */
59
+ declare const HeartbeatConfigErrorSchema: z.ZodObject<{
60
+ path: z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodNumber]>, "many">;
61
+ code: z.ZodString;
62
+ message: z.ZodString;
63
+ }, "strict", z.ZodTypeAny, {
64
+ message: string;
65
+ code: string;
66
+ path: (string | number)[];
67
+ }, {
68
+ message: string;
69
+ code: string;
70
+ path: (string | number)[];
71
+ }>;
72
+ type HeartbeatConfigError = z.infer<typeof HeartbeatConfigErrorSchema>;
73
+ /**
74
+ * Schema for validating the heartbeat response body.
75
+ */
76
+ declare const HeartbeatResponseBodySchema: z.ZodEffects<z.ZodObject<{
77
+ app: z.ZodLiteral<"appwarden">;
78
+ kind: z.ZodLiteral<"heartbeat">;
79
+ status: z.ZodLiteral<"ok">;
80
+ contractVersion: z.ZodLiteral<1>;
81
+ service: z.ZodEnum<["cloudflare", "cloudflare-astro", "cloudflare-react-router", "cloudflare-tanstack-start", "cloudflare-nextjs", "vercel"]>;
82
+ version: z.ZodString;
83
+ configErrors: z.ZodEffects<z.ZodArray<z.ZodObject<{
84
+ path: z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodNumber]>, "many">;
85
+ code: z.ZodString;
86
+ message: z.ZodString;
87
+ }, "strict", z.ZodTypeAny, {
88
+ message: string;
89
+ code: string;
90
+ path: (string | number)[];
91
+ }, {
92
+ message: string;
93
+ code: string;
94
+ path: (string | number)[];
95
+ }>, "many">, {
96
+ message: string;
97
+ code: string;
98
+ path: (string | number)[];
99
+ }[], {
100
+ message: string;
101
+ code: string;
102
+ path: (string | number)[];
103
+ }[]>;
104
+ }, "strict", z.ZodTypeAny, {
105
+ status: "ok";
106
+ app: "appwarden";
107
+ kind: "heartbeat";
108
+ contractVersion: 1;
109
+ service: "cloudflare" | "cloudflare-astro" | "cloudflare-react-router" | "cloudflare-tanstack-start" | "cloudflare-nextjs" | "vercel";
110
+ version: string;
111
+ configErrors: {
112
+ message: string;
113
+ code: string;
114
+ path: (string | number)[];
115
+ }[];
116
+ }, {
117
+ status: "ok";
118
+ app: "appwarden";
119
+ kind: "heartbeat";
120
+ contractVersion: 1;
121
+ service: "cloudflare" | "cloudflare-astro" | "cloudflare-react-router" | "cloudflare-tanstack-start" | "cloudflare-nextjs" | "vercel";
122
+ version: string;
123
+ configErrors: {
124
+ message: string;
125
+ code: string;
126
+ path: (string | number)[];
127
+ }[];
128
+ }>, {
129
+ status: "ok";
130
+ app: "appwarden";
131
+ kind: "heartbeat";
132
+ contractVersion: 1;
133
+ service: "cloudflare" | "cloudflare-astro" | "cloudflare-react-router" | "cloudflare-tanstack-start" | "cloudflare-nextjs" | "vercel";
134
+ version: string;
135
+ configErrors: {
136
+ message: string;
137
+ code: string;
138
+ path: (string | number)[];
139
+ }[];
140
+ }, {
141
+ status: "ok";
142
+ app: "appwarden";
143
+ kind: "heartbeat";
144
+ contractVersion: 1;
145
+ service: "cloudflare" | "cloudflare-astro" | "cloudflare-react-router" | "cloudflare-tanstack-start" | "cloudflare-nextjs" | "vercel";
146
+ version: string;
147
+ configErrors: {
148
+ message: string;
149
+ code: string;
150
+ path: (string | number)[];
151
+ }[];
152
+ }>;
153
+ type HeartbeatResponseBody = z.infer<typeof HeartbeatResponseBodySchema>;
154
+ declare function validateHeartbeatResponseBody(value: unknown): HeartbeatResponseBody;
6
155
 
7
156
  /**
8
157
  * Extracts the Edge Config ID from a valid Edge Config URL
@@ -787,4 +936,4 @@ declare const LockValue: z.ZodObject<{
787
936
  }>;
788
937
  type LockValueType = z.infer<typeof LockValue>;
789
938
 
790
- export { APPWARDEN_CACHE_KEY, LOCKDOWN_TEST_EXPIRY_MS, type LockValueType, UseAppwardenInputSchema, getEdgeConfigId, isCacheUrl, isValidCacheUrl };
939
+ export { APPWARDEN_CACHE_KEY, APPWARDEN_HEARTBEAT_ROUTE, HEARTBEAT_CONFIG_ERRORS_MAX_SERIALIZED_BYTES, HEARTBEAT_CONFIG_ERROR_MAX_CODE_LENGTH, HEARTBEAT_CONFIG_ERROR_MAX_COUNT, HEARTBEAT_CONFIG_ERROR_MAX_MESSAGE_LENGTH, HEARTBEAT_CONFIG_ERROR_MAX_PATH_DEPTH, HEARTBEAT_CONFIG_ERROR_MAX_PATH_SEGMENT_LENGTH, HEARTBEAT_CONTRACT_VERSION, HEARTBEAT_RESPONSE_BODY_MAX_SERIALIZED_BYTES, HEARTBEAT_SERVICES, HEARTBEAT_SERVICE_VALUES, HEARTBEAT_VERSION_MAX_LENGTH, type HeartbeatConfigError, HeartbeatConfigErrorSchema, type HeartbeatResponseBody, HeartbeatResponseBodySchema, type HeartbeatService, LOCKDOWN_TEST_EXPIRY_MS, type LockValueType, UseAppwardenInputSchema, getEdgeConfigId, isCacheUrl, isValidCacheUrl, validateHeartbeatResponseBody };
package/index.js CHANGED
@@ -5,20 +5,50 @@ import {
5
5
  } from "./chunk-QEFORWCW.js";
6
6
  import {
7
7
  UseAppwardenInputSchema
8
- } from "./chunk-6YCNCR22.js";
8
+ } from "./chunk-UBWPR24M.js";
9
9
  import {
10
10
  APPWARDEN_CACHE_KEY,
11
+ APPWARDEN_HEARTBEAT_ROUTE,
11
12
  CSPDirectivesSchema,
12
13
  CSPModeSchema,
13
- LOCKDOWN_TEST_EXPIRY_MS
14
- } from "./chunk-Z7P4QVEY.js";
14
+ HEARTBEAT_CONFIG_ERRORS_MAX_SERIALIZED_BYTES,
15
+ HEARTBEAT_CONFIG_ERROR_MAX_CODE_LENGTH,
16
+ HEARTBEAT_CONFIG_ERROR_MAX_COUNT,
17
+ HEARTBEAT_CONFIG_ERROR_MAX_MESSAGE_LENGTH,
18
+ HEARTBEAT_CONFIG_ERROR_MAX_PATH_DEPTH,
19
+ HEARTBEAT_CONFIG_ERROR_MAX_PATH_SEGMENT_LENGTH,
20
+ HEARTBEAT_CONTRACT_VERSION,
21
+ HEARTBEAT_RESPONSE_BODY_MAX_SERIALIZED_BYTES,
22
+ HEARTBEAT_SERVICES,
23
+ HEARTBEAT_SERVICE_VALUES,
24
+ HEARTBEAT_VERSION_MAX_LENGTH,
25
+ HeartbeatConfigErrorSchema,
26
+ HeartbeatResponseBodySchema,
27
+ LOCKDOWN_TEST_EXPIRY_MS,
28
+ validateHeartbeatResponseBody
29
+ } from "./chunk-OIEAURS7.js";
15
30
  export {
16
31
  APPWARDEN_CACHE_KEY,
32
+ APPWARDEN_HEARTBEAT_ROUTE,
17
33
  CSPDirectivesSchema,
18
34
  CSPModeSchema,
35
+ HEARTBEAT_CONFIG_ERRORS_MAX_SERIALIZED_BYTES,
36
+ HEARTBEAT_CONFIG_ERROR_MAX_CODE_LENGTH,
37
+ HEARTBEAT_CONFIG_ERROR_MAX_COUNT,
38
+ HEARTBEAT_CONFIG_ERROR_MAX_MESSAGE_LENGTH,
39
+ HEARTBEAT_CONFIG_ERROR_MAX_PATH_DEPTH,
40
+ HEARTBEAT_CONFIG_ERROR_MAX_PATH_SEGMENT_LENGTH,
41
+ HEARTBEAT_CONTRACT_VERSION,
42
+ HEARTBEAT_RESPONSE_BODY_MAX_SERIALIZED_BYTES,
43
+ HEARTBEAT_SERVICES,
44
+ HEARTBEAT_SERVICE_VALUES,
45
+ HEARTBEAT_VERSION_MAX_LENGTH,
46
+ HeartbeatConfigErrorSchema,
47
+ HeartbeatResponseBodySchema,
19
48
  LOCKDOWN_TEST_EXPIRY_MS,
20
49
  UseAppwardenInputSchema,
21
50
  getEdgeConfigId,
22
51
  isCacheUrl,
23
- isValidCacheUrl
52
+ isValidCacheUrl,
53
+ validateHeartbeatResponseBody
24
54
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appwarden/middleware",
3
- "version": "3.12.0",
3
+ "version": "3.13.1",
4
4
  "description": "Instantly disable all user interaction with your app deployed on Cloudflare or Vercel",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -58,7 +58,7 @@
58
58
  "node": ">=24"
59
59
  },
60
60
  "dependencies": {
61
- "@upstash/redis": "^1.36.3",
61
+ "@upstash/redis": "^1.36.4",
62
62
  "@vercel/edge-config": "^1.4.3",
63
63
  "zod": "^3.25.76"
64
64
  },
package/vercel.js CHANGED
@@ -20,7 +20,7 @@ import {
20
20
  makeCSPHeader,
21
21
  printMessage,
22
22
  sanitizeConfigErrors
23
- } from "./chunk-HTSD4WPC.js";
23
+ } from "./chunk-U7E4KM2B.js";
24
24
  import {
25
25
  APPWARDEN_CACHE_KEY,
26
26
  AppwardenApiHostnameSchema,
@@ -30,7 +30,7 @@ import {
30
30
  LockValue,
31
31
  errors,
32
32
  globalErrors
33
- } from "./chunk-Z7P4QVEY.js";
33
+ } from "./chunk-OIEAURS7.js";
34
34
 
35
35
  // src/runners/appwarden-on-vercel.ts
36
36
  import { waitUntil } from "@vercel/functions";