@holo-js/security 0.2.6 → 0.3.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.
@@ -1,8 +1,9 @@
1
- // src/contracts.ts
2
1
  import {
3
2
  normalizeCorsConfig,
4
3
  normalizeSecurityConfig
5
- } from "@holo-js/config";
4
+ } from "./chunk-WDTNP5YU.mjs";
5
+
6
+ // src/contracts.ts
6
7
  var SecurityCsrfError = class extends Error {
7
8
  status = 419;
8
9
  constructor(message = "CSRF token mismatch.") {
@@ -3,13 +3,16 @@ import {
3
3
  SecurityRateLimitError,
4
4
  ip,
5
5
  limit
6
- } from "./chunk-EWQKJSFA.mjs";
6
+ } from "./chunk-AGICNQRJ.mjs";
7
+ import {
8
+ normalizeCorsConfig,
9
+ normalizeSecurityConfig
10
+ } from "./chunk-WDTNP5YU.mjs";
7
11
 
8
12
  // src/csrf.ts
9
13
  import { createHmac, randomBytes, timingSafeEqual } from "crypto";
10
14
 
11
15
  // src/runtime.ts
12
- import { normalizeCorsConfig, normalizeSecurityConfig } from "@holo-js/config";
13
16
  function getSecurityRuntimeState() {
14
17
  const runtime = globalThis;
15
18
  runtime.__holoSecurityRuntime__ ??= {};
@@ -46,6 +49,12 @@ var securityRuntimeInternals = {
46
49
  getSecurityRuntimeState
47
50
  };
48
51
 
52
+ // src/proxy.ts
53
+ function shouldTrustProxyHeaders() {
54
+ const trustedProxy = typeof process !== "undefined" ? process.env.HOLO_SECURITY_TRUST_PROXY?.trim().toLowerCase() : void 0;
55
+ return trustedProxy === "1" || trustedProxy === "true" || trustedProxy === "yes" || trustedProxy === "on";
56
+ }
57
+
49
58
  // src/rate-limit.ts
50
59
  function encodeBucketPart(value) {
51
60
  return encodeURIComponent(value);
@@ -79,10 +88,6 @@ function normalizeResolvedLimiterKey(value, label) {
79
88
  }
80
89
  throw new TypeError(`[@holo-js/security] ${label} must resolve a non-empty string key.`);
81
90
  }
82
- function shouldTrustProxyHeaders() {
83
- const trustedProxy = typeof process !== "undefined" ? process.env.HOLO_SECURITY_TRUST_PROXY?.trim().toLowerCase() : void 0;
84
- return trustedProxy === "1" || trustedProxy === "true" || trustedProxy === "yes" || trustedProxy === "on";
85
- }
86
91
  async function defaultRateLimitKey(request) {
87
92
  const runtimeDefaultKey = await getSecurityRuntime().defaultKeyResolver?.(request);
88
93
  if (typeof runtimeDefaultKey !== "undefined" && runtimeDefaultKey !== null) {
@@ -205,7 +210,7 @@ function serializeCookie(name, value, options = {}) {
205
210
  }
206
211
  function isSafeMethod(method) {
207
212
  const normalized = method.trim().toUpperCase();
208
- return normalized === "GET" || normalized === "HEAD" || normalized === "OPTIONS" || normalized === "TRACE";
213
+ return normalized === "GET" || normalized === "HEAD" || normalized === "OPTIONS";
209
214
  }
210
215
  function escapeRegex(value) {
211
216
  return value.replace(/[|\\{}()[\]^$+?.]/g, "\\$&");
@@ -240,7 +245,7 @@ function getForwardedProto(request) {
240
245
  return void 0;
241
246
  }
242
247
  function isSecureRequest(request) {
243
- return getForwardedProto(request) === "https" || new URL(request.url).protocol === "https:";
248
+ return new URL(request.url).protocol === "https:" || shouldTrustProxyHeaders() && getForwardedProto(request) === "https";
244
249
  }
245
250
  function createCsrfToken() {
246
251
  return randomBytes(32).toString("base64url");
@@ -577,7 +582,6 @@ var corsInternals = {
577
582
 
578
583
  // src/store.ts
579
584
  import { resolve } from "path";
580
- import { normalizeSecurityConfig as normalizeSecurityConfig2 } from "@holo-js/config";
581
585
 
582
586
  // src/drivers/file.ts
583
587
  import { createHash, randomUUID } from "crypto";
@@ -1091,7 +1095,7 @@ function isNormalizedSecurityConfig(config) {
1091
1095
  return typeof candidate.rateLimit?.memory?.driver === "string" && candidate.rateLimit.memory.driver === "memory" && typeof candidate.rateLimit.file?.path === "string" && typeof candidate.rateLimit.redis?.host === "string" && typeof candidate.rateLimit.redis.port === "number" && typeof candidate.rateLimit.redis.db === "number" && typeof candidate.rateLimit.redis.connection === "string" && typeof candidate.rateLimit.redis.prefix === "string" && typeof candidate.rateLimit.limiters === "object";
1092
1096
  }
1093
1097
  function normalizeStoreConfig(config) {
1094
- return isNormalizedSecurityConfig(config) ? config : normalizeSecurityConfig2(config);
1098
+ return isNormalizedSecurityConfig(config) ? config : normalizeSecurityConfig(config);
1095
1099
  }
1096
1100
  function createRateLimitStoreFromConfig(config, options = {}) {
1097
1101
  const normalized = normalizeStoreConfig(config);
@@ -1116,7 +1120,6 @@ var securityStoreInternals = {
1116
1120
  };
1117
1121
 
1118
1122
  // src/index.ts
1119
- import { defineSecurityConfig } from "@holo-js/config";
1120
1123
  var security = Object.freeze({
1121
1124
  configureSecurityRuntime,
1122
1125
  getSecurityRuntime,
@@ -1166,6 +1169,5 @@ export {
1166
1169
  redisRateLimitDriverInternals,
1167
1170
  createRateLimitStoreFromConfig,
1168
1171
  securityStoreInternals,
1169
- src_default,
1170
- defineSecurityConfig
1172
+ src_default
1171
1173
  };
@@ -0,0 +1,235 @@
1
+ // src/config.ts
2
+ import {
3
+ DEFAULT_REDIS_DB,
4
+ DEFAULT_REDIS_HOST,
5
+ DEFAULT_REDIS_PORT,
6
+ resolveNormalizedRedisConnection
7
+ } from "@holo-js/kernel";
8
+ import { registerConfigNormalizer } from "@holo-js/config/registry";
9
+ var DEFAULT_CORS_PATHS = Object.freeze(["/api/*"]);
10
+ var DEFAULT_CORS_METHODS = Object.freeze(["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]);
11
+ var DEFAULT_CORS_HEADERS = Object.freeze(["Content-Type", "Authorization", "X-CSRF-TOKEN", "X-Requested-With"]);
12
+ var DEFAULT_CORS_MAX_AGE = 7200;
13
+ var holoCorsDefaults = Object.freeze({
14
+ paths: DEFAULT_CORS_PATHS,
15
+ origins: Object.freeze([]),
16
+ methods: DEFAULT_CORS_METHODS,
17
+ headers: DEFAULT_CORS_HEADERS,
18
+ credentials: false,
19
+ maxAge: DEFAULT_CORS_MAX_AGE,
20
+ statefulDomains: Object.freeze([])
21
+ });
22
+ var DEFAULT_SECURITY_CSRF_FIELD = "_token";
23
+ var DEFAULT_SECURITY_CSRF_HEADER = "X-CSRF-TOKEN";
24
+ var DEFAULT_SECURITY_CSRF_COOKIE = "XSRF-TOKEN";
25
+ var DEFAULT_SECURITY_RATE_LIMIT_DRIVER = "memory";
26
+ var DEFAULT_SECURITY_RATE_LIMIT_FILE_PATH = "./storage/framework/rate-limits";
27
+ var DEFAULT_SECURITY_RATE_LIMIT_REDIS_CONNECTION = "default";
28
+ var DEFAULT_SECURITY_RATE_LIMIT_REDIS_PREFIX = "holo:rate-limit:";
29
+ var DEFAULT_SECURITY_CSRF_CONFIG = Object.freeze({
30
+ enabled: false,
31
+ field: DEFAULT_SECURITY_CSRF_FIELD,
32
+ header: DEFAULT_SECURITY_CSRF_HEADER,
33
+ cookie: DEFAULT_SECURITY_CSRF_COOKIE,
34
+ except: Object.freeze([])
35
+ });
36
+ var DEFAULT_SECURITY_RATE_LIMIT_CONFIG = Object.freeze({
37
+ driver: DEFAULT_SECURITY_RATE_LIMIT_DRIVER,
38
+ memory: Object.freeze({
39
+ driver: "memory"
40
+ }),
41
+ file: Object.freeze({
42
+ path: DEFAULT_SECURITY_RATE_LIMIT_FILE_PATH
43
+ }),
44
+ redis: Object.freeze({
45
+ host: DEFAULT_REDIS_HOST,
46
+ port: DEFAULT_REDIS_PORT,
47
+ password: void 0,
48
+ username: void 0,
49
+ db: DEFAULT_REDIS_DB,
50
+ connection: DEFAULT_SECURITY_RATE_LIMIT_REDIS_CONNECTION,
51
+ prefix: DEFAULT_SECURITY_RATE_LIMIT_REDIS_PREFIX
52
+ }),
53
+ limiters: Object.freeze({})
54
+ });
55
+ var holoSecurityDefaults = Object.freeze({
56
+ csrf: DEFAULT_SECURITY_CSRF_CONFIG,
57
+ rateLimit: DEFAULT_SECURITY_RATE_LIMIT_CONFIG
58
+ });
59
+ function parseScopedInteger(value, fallback, namespace, label, options = {}) {
60
+ const normalized = typeof value === "undefined" ? fallback : typeof value === "number" ? value : value.trim() ? Number(value.trim()) : Number.NaN;
61
+ if (!Number.isFinite(normalized) || !Number.isInteger(normalized)) throw new Error(`[${namespace}] ${label} must be an integer.`);
62
+ if (typeof options.minimum === "number" && normalized < options.minimum) throw new Error(`[${namespace}] ${label} must be greater than or equal to ${options.minimum}.`);
63
+ return normalized;
64
+ }
65
+ function normalizeScopedName(value, namespace, label) {
66
+ const normalized = value?.trim();
67
+ if (!normalized) throw new Error(`[${namespace}] ${label} must be a non-empty string.`);
68
+ return normalized;
69
+ }
70
+ function parseSecurityInteger(value, fallback, label, options = {}) {
71
+ return parseScopedInteger(value, fallback, "Holo Security", label, options);
72
+ }
73
+ function normalizeSecurityName(value, label) {
74
+ return normalizeScopedName(value, "Holo Security", label);
75
+ }
76
+ function normalizeSecurityOptionalString(value) {
77
+ const normalized = value?.trim();
78
+ return normalized || void 0;
79
+ }
80
+ function normalizeCorsStringList(values, defaults, label) {
81
+ if (!values) {
82
+ return defaults;
83
+ }
84
+ return Object.freeze(values.map((value, index) => {
85
+ const normalized = value.trim();
86
+ if (!normalized) {
87
+ throw new Error(`[Holo CORS] ${label} entry at index ${index} must be a non-empty string.`);
88
+ }
89
+ return normalized;
90
+ }));
91
+ }
92
+ function normalizeCorsMethods(values) {
93
+ return Object.freeze(normalizeCorsStringList(values, DEFAULT_CORS_METHODS, "methods").map((value) => value.toUpperCase()));
94
+ }
95
+ function normalizeCorsMaxAge(value) {
96
+ return parseSecurityInteger(value ?? DEFAULT_CORS_MAX_AGE, DEFAULT_CORS_MAX_AGE, "cors maxAge", {
97
+ minimum: 0
98
+ });
99
+ }
100
+ function normalizeCorsConfig(config = {}) {
101
+ return Object.freeze({
102
+ paths: normalizeCorsStringList(config.paths, DEFAULT_CORS_PATHS, "paths"),
103
+ origins: normalizeCorsStringList(config.origins, holoCorsDefaults.origins, "origins"),
104
+ methods: normalizeCorsMethods(config.methods),
105
+ headers: normalizeCorsStringList(config.headers, DEFAULT_CORS_HEADERS, "headers"),
106
+ credentials: config.credentials ?? holoCorsDefaults.credentials,
107
+ maxAge: normalizeCorsMaxAge(config.maxAge),
108
+ statefulDomains: normalizeCorsStringList(config.statefulDomains, holoCorsDefaults.statefulDomains, "statefulDomains")
109
+ });
110
+ }
111
+ function normalizeSecurityLimiter(name, config) {
112
+ const key = typeof config.key === "function" ? config.key : void 0;
113
+ if (typeof config.key !== "undefined" && typeof config.key !== "function") {
114
+ throw new Error(`[Holo Security] rate limiter "${name}" key resolver must be a function when provided.`);
115
+ }
116
+ return Object.freeze({
117
+ name,
118
+ maxAttempts: parseSecurityInteger(config.maxAttempts, 0, `rate limiter "${name}" maxAttempts`, {
119
+ minimum: 1
120
+ }),
121
+ decaySeconds: parseSecurityInteger(config.decaySeconds, 0, `rate limiter "${name}" decaySeconds`, {
122
+ minimum: 1
123
+ }),
124
+ ...key ? { key } : {}
125
+ });
126
+ }
127
+ function normalizeSecurityRateLimitConfig(config, redisConfig) {
128
+ const driver = normalizeSecurityOptionalString(config?.driver) || DEFAULT_SECURITY_RATE_LIMIT_DRIVER;
129
+ if (driver !== "memory" && driver !== "file" && driver !== "redis") {
130
+ throw new Error(`[Holo Security] Unsupported rate limit driver "${driver}".`);
131
+ }
132
+ const file = config?.file ?? {};
133
+ const redis = config?.redis ?? {};
134
+ const limiters = !config?.limiters || Object.keys(config.limiters).length === 0 ? holoSecurityDefaults.rateLimit.limiters : Object.freeze(Object.fromEntries(Object.entries(config.limiters).map(([name, limiter]) => {
135
+ const normalizedName = normalizeSecurityName(name, "Rate limiter name");
136
+ return [normalizedName, normalizeSecurityLimiter(normalizedName, limiter)];
137
+ })));
138
+ return Object.freeze({
139
+ driver,
140
+ memory: Object.freeze({
141
+ driver: "memory"
142
+ }),
143
+ file: Object.freeze({
144
+ path: normalizeSecurityOptionalString(file.path) || DEFAULT_SECURITY_RATE_LIMIT_FILE_PATH
145
+ }),
146
+ redis: Object.freeze((() => {
147
+ const connectionName = normalizeSecurityOptionalString(redis.connection) || redisConfig?.default || DEFAULT_SECURITY_RATE_LIMIT_REDIS_CONNECTION;
148
+ const resolvedConnection = redisConfig ? resolveNormalizedRedisConnection(
149
+ redisConfig,
150
+ connectionName,
151
+ "Security rate-limit Redis connection"
152
+ ) : driver === "redis" ? (() => {
153
+ throw new Error(
154
+ `[@holo-js/security] Rate-limit Redis config references shared connection "${connectionName}" without top-level Redis config.`
155
+ );
156
+ })() : {
157
+ name: connectionName,
158
+ host: DEFAULT_REDIS_HOST,
159
+ port: DEFAULT_REDIS_PORT,
160
+ password: void 0,
161
+ username: void 0,
162
+ db: DEFAULT_REDIS_DB
163
+ };
164
+ return {
165
+ ...typeof resolvedConnection.url === "undefined" ? {} : { url: resolvedConnection.url },
166
+ ...typeof resolvedConnection.clusters === "undefined" ? {} : { clusters: resolvedConnection.clusters },
167
+ host: resolvedConnection.host,
168
+ port: resolvedConnection.port,
169
+ password: resolvedConnection.password,
170
+ username: resolvedConnection.username,
171
+ db: resolvedConnection.db,
172
+ connection: resolvedConnection.name,
173
+ prefix: normalizeSecurityOptionalString(redis.prefix) || DEFAULT_SECURITY_RATE_LIMIT_REDIS_PREFIX
174
+ };
175
+ })()),
176
+ limiters
177
+ });
178
+ }
179
+ function normalizeSecurityConfig(config = {}, redisConfig) {
180
+ const csrf = typeof config.csrf === "boolean" ? { enabled: config.csrf } : config.csrf ?? {};
181
+ const except = csrf.except ? Object.freeze(csrf.except.map((value, index) => {
182
+ const normalized = value.trim();
183
+ if (!normalized) {
184
+ throw new Error(`[Holo Security] csrf except entry at index ${index} must be a non-empty string.`);
185
+ }
186
+ return normalized;
187
+ })) : DEFAULT_SECURITY_CSRF_CONFIG.except;
188
+ return Object.freeze({
189
+ csrf: Object.freeze({
190
+ enabled: csrf.enabled ?? DEFAULT_SECURITY_CSRF_CONFIG.enabled,
191
+ field: normalizeSecurityOptionalString(csrf.field) || DEFAULT_SECURITY_CSRF_FIELD,
192
+ header: normalizeSecurityOptionalString(csrf.header) || DEFAULT_SECURITY_CSRF_HEADER,
193
+ cookie: normalizeSecurityOptionalString(csrf.cookie) || DEFAULT_SECURITY_CSRF_COOKIE,
194
+ except
195
+ }),
196
+ rateLimit: normalizeSecurityRateLimitConfig(config.rateLimit, redisConfig)
197
+ });
198
+ }
199
+ function defineSecurityConfig(config) {
200
+ return Object.freeze({ ...config });
201
+ }
202
+ function defineCorsConfig(config) {
203
+ return Object.freeze({ ...config });
204
+ }
205
+ registerConfigNormalizer({
206
+ name: "cors",
207
+ normalize: normalizeCorsConfig
208
+ });
209
+ registerConfigNormalizer({
210
+ name: "security",
211
+ dependencies: ["redis"],
212
+ normalize(config, context) {
213
+ return normalizeSecurityConfig(config, context.has("redis") ? context.get("redis") : void 0);
214
+ }
215
+ });
216
+
217
+ export {
218
+ DEFAULT_CORS_PATHS,
219
+ DEFAULT_CORS_METHODS,
220
+ DEFAULT_CORS_HEADERS,
221
+ DEFAULT_CORS_MAX_AGE,
222
+ holoCorsDefaults,
223
+ DEFAULT_SECURITY_CSRF_FIELD,
224
+ DEFAULT_SECURITY_CSRF_HEADER,
225
+ DEFAULT_SECURITY_CSRF_COOKIE,
226
+ DEFAULT_SECURITY_RATE_LIMIT_DRIVER,
227
+ DEFAULT_SECURITY_RATE_LIMIT_FILE_PATH,
228
+ DEFAULT_SECURITY_RATE_LIMIT_REDIS_CONNECTION,
229
+ DEFAULT_SECURITY_RATE_LIMIT_REDIS_PREFIX,
230
+ holoSecurityDefaults,
231
+ normalizeCorsConfig,
232
+ normalizeSecurityConfig,
233
+ defineSecurityConfig,
234
+ defineCorsConfig
235
+ };
package/dist/client.d.ts CHANGED
@@ -1,5 +1,6 @@
1
+ import './config.js';
1
2
  import { SecurityClientConfig } from './contracts.js';
2
- import '@holo-js/config';
3
+ import '@holo-js/kernel';
3
4
 
4
5
  declare function getDefaultSecurityClientConfig(): SecurityClientConfig;
5
6
  declare function readSecurityClientConfigFromCookies(cookieHeader: string | null | undefined): SecurityClientConfig | undefined;
@@ -0,0 +1,136 @@
1
+ import { NormalizedHoloRedisClusterNodeConfig, NormalizedHoloRedisConfig, HoloRedisClusterNodeConfig } from '@holo-js/kernel';
2
+
3
+ interface HoloCorsConfig {
4
+ readonly paths?: readonly string[];
5
+ readonly origins?: readonly string[];
6
+ readonly methods?: readonly string[];
7
+ readonly headers?: readonly string[];
8
+ readonly credentials?: boolean;
9
+ readonly maxAge?: number | string;
10
+ readonly statefulDomains?: readonly string[];
11
+ }
12
+ declare module '@holo-js/config' {
13
+ interface HoloConfigRegistry {
14
+ cors: NormalizedHoloCorsConfig;
15
+ security: NormalizedHoloSecurityConfig;
16
+ }
17
+ }
18
+ interface NormalizedHoloCorsConfig {
19
+ readonly paths: readonly string[];
20
+ readonly origins: readonly string[];
21
+ readonly methods: readonly string[];
22
+ readonly headers: readonly string[];
23
+ readonly credentials: boolean;
24
+ readonly maxAge: number;
25
+ readonly statefulDomains: readonly string[];
26
+ }
27
+ type SecurityRateLimitDriver = 'memory' | 'file' | 'redis';
28
+ interface HoloSecurityCsrfConfig {
29
+ readonly enabled?: boolean;
30
+ readonly field?: string;
31
+ readonly header?: string;
32
+ readonly cookie?: string;
33
+ readonly except?: readonly string[];
34
+ }
35
+ interface NormalizedHoloSecurityCsrfConfig {
36
+ readonly enabled: boolean;
37
+ readonly field: string;
38
+ readonly header: string;
39
+ readonly cookie: string;
40
+ readonly except: readonly string[];
41
+ }
42
+ interface SecurityRateLimitContext<TValues extends Readonly<Record<string, unknown>> | undefined = Readonly<Record<string, unknown>> | undefined> {
43
+ readonly request: Request;
44
+ readonly values?: TValues;
45
+ }
46
+ interface SecurityRateLimitKeyResolver<TValues extends Readonly<Record<string, unknown>> | undefined = Readonly<Record<string, unknown>> | undefined> {
47
+ (context: SecurityRateLimitContext<TValues>): string | Promise<string>;
48
+ }
49
+ interface SecurityLimiterConfig<TValues extends Readonly<Record<string, unknown>> | undefined = Readonly<Record<string, unknown>> | undefined> {
50
+ readonly maxAttempts: number | string;
51
+ readonly decaySeconds: number | string;
52
+ readonly key?: SecurityRateLimitKeyResolver<TValues>;
53
+ }
54
+ interface NormalizedSecurityLimiterConfig<TValues extends Readonly<Record<string, unknown>> | undefined = Readonly<Record<string, unknown>> | undefined> {
55
+ readonly name: string;
56
+ readonly maxAttempts: number;
57
+ readonly decaySeconds: number;
58
+ readonly key?: SecurityRateLimitKeyResolver<TValues>;
59
+ }
60
+ interface SecurityRateLimitMemoryConfig {
61
+ readonly driver?: 'memory';
62
+ }
63
+ interface SecurityRateLimitFileConfig {
64
+ readonly path?: string;
65
+ }
66
+ interface SecurityRateLimitRedisConnectionConfig {
67
+ readonly url?: string;
68
+ readonly clusters?: readonly HoloRedisClusterNodeConfig[];
69
+ readonly host?: string;
70
+ readonly port?: number | string;
71
+ readonly password?: string;
72
+ readonly username?: string;
73
+ readonly db?: number | string;
74
+ }
75
+ interface SecurityRateLimitRedisConfig {
76
+ readonly connection?: string;
77
+ readonly prefix?: string;
78
+ }
79
+ interface HoloSecurityRateLimitConfig {
80
+ readonly driver?: SecurityRateLimitDriver;
81
+ readonly memory?: SecurityRateLimitMemoryConfig;
82
+ readonly file?: SecurityRateLimitFileConfig;
83
+ readonly redis?: SecurityRateLimitRedisConfig;
84
+ readonly limiters?: Readonly<Record<string, SecurityLimiterConfig>>;
85
+ }
86
+ interface NormalizedSecurityRateLimitMemoryConfig {
87
+ readonly driver: 'memory';
88
+ }
89
+ interface NormalizedSecurityRateLimitFileConfig {
90
+ readonly path: string;
91
+ }
92
+ interface NormalizedSecurityRateLimitRedisConfig {
93
+ readonly url?: string;
94
+ readonly clusters?: readonly NormalizedHoloRedisClusterNodeConfig[];
95
+ readonly host: string;
96
+ readonly port: number;
97
+ readonly password?: string;
98
+ readonly username?: string;
99
+ readonly db: number;
100
+ readonly connection: string;
101
+ readonly prefix: string;
102
+ }
103
+ interface NormalizedHoloSecurityRateLimitConfig {
104
+ readonly driver: SecurityRateLimitDriver;
105
+ readonly memory: NormalizedSecurityRateLimitMemoryConfig;
106
+ readonly file: NormalizedSecurityRateLimitFileConfig;
107
+ readonly redis: NormalizedSecurityRateLimitRedisConfig;
108
+ readonly limiters: Readonly<Record<string, NormalizedSecurityLimiterConfig>>;
109
+ }
110
+ interface HoloSecurityConfig {
111
+ readonly csrf?: boolean | HoloSecurityCsrfConfig;
112
+ readonly rateLimit?: HoloSecurityRateLimitConfig;
113
+ }
114
+ interface NormalizedHoloSecurityConfig {
115
+ readonly csrf: NormalizedHoloSecurityCsrfConfig;
116
+ readonly rateLimit: NormalizedHoloSecurityRateLimitConfig;
117
+ }
118
+ declare const DEFAULT_CORS_PATHS: readonly ["/api/*"];
119
+ declare const DEFAULT_CORS_METHODS: readonly ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"];
120
+ declare const DEFAULT_CORS_HEADERS: readonly ["Content-Type", "Authorization", "X-CSRF-TOKEN", "X-Requested-With"];
121
+ declare const DEFAULT_CORS_MAX_AGE = 7200;
122
+ declare const holoCorsDefaults: Readonly<NormalizedHoloCorsConfig>;
123
+ declare const DEFAULT_SECURITY_CSRF_FIELD = "_token";
124
+ declare const DEFAULT_SECURITY_CSRF_HEADER = "X-CSRF-TOKEN";
125
+ declare const DEFAULT_SECURITY_CSRF_COOKIE = "XSRF-TOKEN";
126
+ declare const DEFAULT_SECURITY_RATE_LIMIT_DRIVER: SecurityRateLimitDriver;
127
+ declare const DEFAULT_SECURITY_RATE_LIMIT_FILE_PATH = "./storage/framework/rate-limits";
128
+ declare const DEFAULT_SECURITY_RATE_LIMIT_REDIS_CONNECTION = "default";
129
+ declare const DEFAULT_SECURITY_RATE_LIMIT_REDIS_PREFIX = "holo:rate-limit:";
130
+ declare const holoSecurityDefaults: Readonly<NormalizedHoloSecurityConfig>;
131
+ declare function normalizeCorsConfig(config?: HoloCorsConfig): NormalizedHoloCorsConfig;
132
+ declare function normalizeSecurityConfig(config?: HoloSecurityConfig, redisConfig?: NormalizedHoloRedisConfig): NormalizedHoloSecurityConfig;
133
+ declare function defineSecurityConfig<TConfig extends HoloSecurityConfig>(config: TConfig): Readonly<TConfig>;
134
+ declare function defineCorsConfig<TConfig extends HoloCorsConfig>(config: TConfig): Readonly<TConfig>;
135
+
136
+ export { DEFAULT_CORS_HEADERS, DEFAULT_CORS_MAX_AGE, DEFAULT_CORS_METHODS, DEFAULT_CORS_PATHS, DEFAULT_SECURITY_CSRF_COOKIE, DEFAULT_SECURITY_CSRF_FIELD, DEFAULT_SECURITY_CSRF_HEADER, DEFAULT_SECURITY_RATE_LIMIT_DRIVER, DEFAULT_SECURITY_RATE_LIMIT_FILE_PATH, DEFAULT_SECURITY_RATE_LIMIT_REDIS_CONNECTION, DEFAULT_SECURITY_RATE_LIMIT_REDIS_PREFIX, type HoloCorsConfig, type HoloSecurityConfig, type HoloSecurityCsrfConfig, type HoloSecurityRateLimitConfig, type NormalizedHoloCorsConfig, type NormalizedHoloSecurityConfig, type NormalizedHoloSecurityCsrfConfig, type NormalizedHoloSecurityRateLimitConfig, type NormalizedSecurityLimiterConfig, type NormalizedSecurityRateLimitFileConfig, type NormalizedSecurityRateLimitMemoryConfig, type NormalizedSecurityRateLimitRedisConfig, type SecurityLimiterConfig, type SecurityRateLimitContext, type SecurityRateLimitDriver, type SecurityRateLimitFileConfig, type SecurityRateLimitKeyResolver, type SecurityRateLimitMemoryConfig, type SecurityRateLimitRedisConfig, type SecurityRateLimitRedisConnectionConfig, defineCorsConfig, defineSecurityConfig, holoCorsDefaults, holoSecurityDefaults, normalizeCorsConfig, normalizeSecurityConfig };
@@ -0,0 +1,38 @@
1
+ import {
2
+ DEFAULT_CORS_HEADERS,
3
+ DEFAULT_CORS_MAX_AGE,
4
+ DEFAULT_CORS_METHODS,
5
+ DEFAULT_CORS_PATHS,
6
+ DEFAULT_SECURITY_CSRF_COOKIE,
7
+ DEFAULT_SECURITY_CSRF_FIELD,
8
+ DEFAULT_SECURITY_CSRF_HEADER,
9
+ DEFAULT_SECURITY_RATE_LIMIT_DRIVER,
10
+ DEFAULT_SECURITY_RATE_LIMIT_FILE_PATH,
11
+ DEFAULT_SECURITY_RATE_LIMIT_REDIS_CONNECTION,
12
+ DEFAULT_SECURITY_RATE_LIMIT_REDIS_PREFIX,
13
+ defineCorsConfig,
14
+ defineSecurityConfig,
15
+ holoCorsDefaults,
16
+ holoSecurityDefaults,
17
+ normalizeCorsConfig,
18
+ normalizeSecurityConfig
19
+ } from "./chunk-WDTNP5YU.mjs";
20
+ export {
21
+ DEFAULT_CORS_HEADERS,
22
+ DEFAULT_CORS_MAX_AGE,
23
+ DEFAULT_CORS_METHODS,
24
+ DEFAULT_CORS_PATHS,
25
+ DEFAULT_SECURITY_CSRF_COOKIE,
26
+ DEFAULT_SECURITY_CSRF_FIELD,
27
+ DEFAULT_SECURITY_CSRF_HEADER,
28
+ DEFAULT_SECURITY_RATE_LIMIT_DRIVER,
29
+ DEFAULT_SECURITY_RATE_LIMIT_FILE_PATH,
30
+ DEFAULT_SECURITY_RATE_LIMIT_REDIS_CONNECTION,
31
+ DEFAULT_SECURITY_RATE_LIMIT_REDIS_PREFIX,
32
+ defineCorsConfig,
33
+ defineSecurityConfig,
34
+ holoCorsDefaults,
35
+ holoSecurityDefaults,
36
+ normalizeCorsConfig,
37
+ normalizeSecurityConfig
38
+ };
@@ -1,5 +1,6 @@
1
- import { HoloSecurityConfig, NormalizedHoloSecurityConfig, HoloCorsConfig, NormalizedHoloCorsConfig, SecurityRateLimitFileConfig, SecurityRateLimitMemoryConfig, SecurityRateLimitRedisConfig, SecurityLimiterConfig, SecurityRateLimitKeyResolver } from '@holo-js/config';
2
- export { HoloCorsConfig, HoloSecurityConfig, HoloSecurityCsrfConfig, HoloSecurityRateLimitConfig, NormalizedHoloCorsConfig, NormalizedHoloSecurityConfig, NormalizedHoloSecurityCsrfConfig, NormalizedHoloSecurityRateLimitConfig, NormalizedSecurityLimiterConfig, SecurityLimiterConfig, SecurityRateLimitContext, SecurityRateLimitDriver, SecurityRateLimitFileConfig, SecurityRateLimitKeyResolver, SecurityRateLimitMemoryConfig, SecurityRateLimitRedisConfig } from '@holo-js/config';
1
+ import { HoloSecurityConfig, NormalizedHoloSecurityConfig, HoloCorsConfig, NormalizedHoloCorsConfig, SecurityRateLimitFileConfig, SecurityRateLimitMemoryConfig, SecurityRateLimitRedisConfig, SecurityLimiterConfig, SecurityRateLimitKeyResolver } from './config.js';
2
+ export { HoloSecurityCsrfConfig, HoloSecurityRateLimitConfig, NormalizedHoloSecurityCsrfConfig, NormalizedHoloSecurityRateLimitConfig, NormalizedSecurityLimiterConfig, SecurityRateLimitContext, SecurityRateLimitDriver } from './config.js';
3
+ import '@holo-js/kernel';
3
4
 
4
5
  interface SecurityRuntimeBindings {
5
6
  readonly config: HoloSecurityConfig | NormalizedHoloSecurityConfig;
@@ -141,4 +142,4 @@ declare const securityInternals: {
141
142
  normalizeLimiterAttempts: typeof normalizeLimiterAttempts;
142
143
  };
143
144
 
144
- export { type SecurityClearRateLimitOptions, type SecurityClientConfig, type SecurityCorsFacade, SecurityCsrfError, type SecurityCsrfFacade, type SecurityCsrfField, type SecurityCsrfInput, type SecurityDefaultRateLimitKeyResolver, type SecurityProtectOptions, type SecurityRateLimitBucketSnapshot, type SecurityRateLimitCallOptions, SecurityRateLimitError, type SecurityRateLimitHitResult, type SecurityRateLimitRedisDriverAdapter, type SecurityRateLimitStore, type SecurityRateLimitStoreFactoryOptions, type SecurityRuntimeBindings, type SecurityRuntimeFacade, createFileRateLimitStoreConfig, createMemoryRateLimitStoreConfig, createRedisRateLimitStoreConfig, defineRateLimiter, defineSecurityRuntimeBindings, ip, limit, securityInternals };
145
+ export { HoloCorsConfig, HoloSecurityConfig, NormalizedHoloCorsConfig, NormalizedHoloSecurityConfig, type SecurityClearRateLimitOptions, type SecurityClientConfig, type SecurityCorsFacade, SecurityCsrfError, type SecurityCsrfFacade, type SecurityCsrfField, type SecurityCsrfInput, type SecurityDefaultRateLimitKeyResolver, SecurityLimiterConfig, type SecurityProtectOptions, type SecurityRateLimitBucketSnapshot, type SecurityRateLimitCallOptions, SecurityRateLimitError, SecurityRateLimitFileConfig, type SecurityRateLimitHitResult, SecurityRateLimitKeyResolver, SecurityRateLimitMemoryConfig, SecurityRateLimitRedisConfig, type SecurityRateLimitRedisDriverAdapter, type SecurityRateLimitStore, type SecurityRateLimitStoreFactoryOptions, type SecurityRuntimeBindings, type SecurityRuntimeFacade, createFileRateLimitStoreConfig, createMemoryRateLimitStoreConfig, createRedisRateLimitStoreConfig, defineRateLimiter, defineSecurityRuntimeBindings, ip, limit, securityInternals };
@@ -9,7 +9,8 @@ import {
9
9
  ip,
10
10
  limit,
11
11
  securityInternals
12
- } from "./chunk-EWQKJSFA.mjs";
12
+ } from "./chunk-AGICNQRJ.mjs";
13
+ import "./chunk-WDTNP5YU.mjs";
13
14
  export {
14
15
  SecurityCsrfError,
15
16
  SecurityRateLimitError,
@@ -1,5 +1,6 @@
1
- import { NormalizedSecurityRateLimitRedisConfig } from '@holo-js/config';
1
+ import { NormalizedSecurityRateLimitRedisConfig } from '../config.js';
2
2
  import { SecurityRateLimitRedisDriverAdapter } from '../contracts.js';
3
+ import '@holo-js/kernel';
3
4
 
4
5
  interface SecurityRedisAdapterOptions {
5
6
  readonly now?: () => Date;
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import * as _holo_js_config from '@holo-js/config';
2
- import { NormalizedHoloCorsConfig, NormalizedSecurityLimiterConfig, HoloSecurityConfig, NormalizedHoloSecurityConfig } from '@holo-js/config';
3
- export { HoloCorsConfig, HoloSecurityConfig, HoloSecurityCsrfConfig, HoloSecurityRateLimitConfig, NormalizedHoloCorsConfig, NormalizedHoloSecurityConfig, NormalizedHoloSecurityCsrfConfig, NormalizedHoloSecurityRateLimitConfig, NormalizedSecurityLimiterConfig, SecurityLimiterConfig, SecurityRateLimitContext, SecurityRateLimitDriver, SecurityRateLimitFileConfig, SecurityRateLimitKeyResolver, SecurityRateLimitMemoryConfig, SecurityRateLimitRedisConfig, defineSecurityConfig } from '@holo-js/config';
1
+ import { NormalizedHoloCorsConfig, NormalizedSecurityLimiterConfig, HoloSecurityConfig, NormalizedHoloSecurityConfig, SecurityRateLimitKeyResolver, SecurityLimiterConfig } from './config.js';
2
+ export { HoloCorsConfig, HoloSecurityCsrfConfig, HoloSecurityRateLimitConfig, NormalizedHoloSecurityCsrfConfig, NormalizedHoloSecurityRateLimitConfig, SecurityRateLimitContext, SecurityRateLimitDriver, SecurityRateLimitFileConfig, SecurityRateLimitMemoryConfig, SecurityRateLimitRedisConfig, defineCorsConfig, defineSecurityConfig, holoCorsDefaults, holoSecurityDefaults, normalizeCorsConfig, normalizeSecurityConfig } from './config.js';
4
3
  import { SecurityCsrfField, SecurityCsrfInput, SecurityProtectOptions, SecurityClearRateLimitOptions, SecurityRateLimitCallOptions, SecurityRateLimitHitResult, SecurityRateLimitStore, SecurityRateLimitStoreFactoryOptions, SecurityRateLimitRedisDriverAdapter, SecurityRuntimeBindings, SecurityRuntimeFacade, ip } from './contracts.js';
5
4
  export { SecurityClientConfig, SecurityCorsFacade, SecurityCsrfError, SecurityCsrfFacade, SecurityDefaultRateLimitKeyResolver, SecurityRateLimitBucketSnapshot, SecurityRateLimitError, createFileRateLimitStoreConfig, createMemoryRateLimitStoreConfig, createRedisRateLimitStoreConfig, defineRateLimiter, defineSecurityRuntimeBindings, limit, securityInternals } from './contracts.js';
5
+ import '@holo-js/kernel';
6
6
 
7
7
  declare function parseCookieHeader(header: string | null | undefined): Readonly<Record<string, string>>;
8
8
  declare function serializeCookie(name: string, value: string, options?: {
@@ -235,17 +235,17 @@ declare const security: Readonly<{
235
235
  perMinute(maxAttempts: number): {
236
236
  readonly maxAttempts: number;
237
237
  readonly decaySeconds: number;
238
- by(key: _holo_js_config.SecurityRateLimitKeyResolver<Readonly<Record<string, unknown>> | undefined>): _holo_js_config.SecurityLimiterConfig<Readonly<Record<string, unknown>> | undefined>;
239
- define(): _holo_js_config.SecurityLimiterConfig<Readonly<Record<string, unknown>> | undefined>;
238
+ by(key: SecurityRateLimitKeyResolver<Readonly<Record<string, unknown>> | undefined>): SecurityLimiterConfig<Readonly<Record<string, unknown>> | undefined>;
239
+ define(): SecurityLimiterConfig<Readonly<Record<string, unknown>> | undefined>;
240
240
  };
241
241
  perHour(maxAttempts: number): {
242
242
  readonly maxAttempts: number;
243
243
  readonly decaySeconds: number;
244
- by(key: _holo_js_config.SecurityRateLimitKeyResolver<Readonly<Record<string, unknown>> | undefined>): _holo_js_config.SecurityLimiterConfig<Readonly<Record<string, unknown>> | undefined>;
245
- define(): _holo_js_config.SecurityLimiterConfig<Readonly<Record<string, unknown>> | undefined>;
244
+ by(key: SecurityRateLimitKeyResolver<Readonly<Record<string, unknown>> | undefined>): SecurityLimiterConfig<Readonly<Record<string, unknown>> | undefined>;
245
+ define(): SecurityLimiterConfig<Readonly<Record<string, unknown>> | undefined>;
246
246
  };
247
247
  }>;
248
248
  ip: typeof ip;
249
249
  }>;
250
250
 
251
- export { SecurityClearRateLimitOptions, SecurityCsrfField, SecurityCsrfInput, SecurityProtectOptions, SecurityRateLimitCallOptions, SecurityRateLimitHitResult, SecurityRateLimitRedisDriverAdapter, SecurityRateLimitStore, SecurityRateLimitStoreFactoryOptions, SecurityRuntimeBindings, SecurityRuntimeFacade, SecurityRuntimeNotConfiguredError, apply as applyCors, clearRateLimit, configureSecurityRuntime, cors, corsInternals, headers as createCorsHeaders, preflight as createCorsPreflightResponse, cookie as createCsrfCookie, field as createCsrfField, input as createCsrfInput, token as createCsrfToken, createFileRateLimitStore, createMemoryRateLimitStore, createRateLimitStoreFromConfig, createRedisRateLimitStore, csrf, csrfInternals, security as default, defaultRateLimitKey, fileRateLimitDriverInternals, getSecurityRuntime, getSecurityRuntimeBindings, ip, isSecureRequest, memoryRateLimitDriverInternals, protect, rateLimit, rateLimitInternals, redisRateLimitDriverInternals, resetSecurityRuntime, securityRuntimeInternals, securityStoreInternals, verify as verifyCsrfRequest };
251
+ export { HoloSecurityConfig, NormalizedHoloCorsConfig, NormalizedHoloSecurityConfig, NormalizedSecurityLimiterConfig, SecurityClearRateLimitOptions, SecurityCsrfField, SecurityCsrfInput, SecurityLimiterConfig, SecurityProtectOptions, SecurityRateLimitCallOptions, SecurityRateLimitHitResult, SecurityRateLimitKeyResolver, SecurityRateLimitRedisDriverAdapter, SecurityRateLimitStore, SecurityRateLimitStoreFactoryOptions, SecurityRuntimeBindings, SecurityRuntimeFacade, SecurityRuntimeNotConfiguredError, apply as applyCors, clearRateLimit, configureSecurityRuntime, cors, corsInternals, headers as createCorsHeaders, preflight as createCorsPreflightResponse, cookie as createCsrfCookie, field as createCsrfField, input as createCsrfInput, token as createCsrfToken, createFileRateLimitStore, createMemoryRateLimitStore, createRateLimitStoreFromConfig, createRedisRateLimitStore, csrf, csrfInternals, security as default, defaultRateLimitKey, fileRateLimitDriverInternals, getSecurityRuntime, getSecurityRuntimeBindings, ip, isSecureRequest, memoryRateLimitDriverInternals, protect, rateLimit, rateLimitInternals, redisRateLimitDriverInternals, resetSecurityRuntime, securityRuntimeInternals, securityStoreInternals, verify as verifyCsrfRequest };
package/dist/index.mjs CHANGED
@@ -13,7 +13,6 @@ import {
13
13
  csrf,
14
14
  csrfInternals,
15
15
  defaultRateLimitKey,
16
- defineSecurityConfig,
17
16
  field,
18
17
  fileRateLimitDriverInternals,
19
18
  getSecurityRuntime,
@@ -33,7 +32,7 @@ import {
33
32
  src_default,
34
33
  token,
35
34
  verify
36
- } from "./chunk-QGBGZ2GI.mjs";
35
+ } from "./chunk-NKKBOLDI.mjs";
37
36
  import {
38
37
  SecurityCsrfError,
39
38
  SecurityRateLimitError,
@@ -45,7 +44,15 @@ import {
45
44
  ip,
46
45
  limit,
47
46
  securityInternals
48
- } from "./chunk-EWQKJSFA.mjs";
47
+ } from "./chunk-AGICNQRJ.mjs";
48
+ import {
49
+ defineCorsConfig,
50
+ defineSecurityConfig,
51
+ holoCorsDefaults,
52
+ holoSecurityDefaults,
53
+ normalizeCorsConfig,
54
+ normalizeSecurityConfig
55
+ } from "./chunk-WDTNP5YU.mjs";
49
56
  export {
50
57
  SecurityCsrfError,
51
58
  SecurityRateLimitError,
@@ -72,16 +79,21 @@ export {
72
79
  csrfInternals,
73
80
  src_default as default,
74
81
  defaultRateLimitKey,
82
+ defineCorsConfig,
75
83
  defineRateLimiter,
76
84
  defineSecurityConfig,
77
85
  defineSecurityRuntimeBindings,
78
86
  fileRateLimitDriverInternals,
79
87
  getSecurityRuntime,
80
88
  getSecurityRuntimeBindings,
89
+ holoCorsDefaults,
90
+ holoSecurityDefaults,
81
91
  ip,
82
92
  isSecureRequest,
83
93
  limit,
84
94
  memoryRateLimitDriverInternals,
95
+ normalizeCorsConfig,
96
+ normalizeSecurityConfig,
85
97
  protect,
86
98
  rateLimit,
87
99
  rateLimitInternals,
@@ -4,7 +4,7 @@ import {
4
4
  getSecurityRuntime,
5
5
  isSecureRequest,
6
6
  protect
7
- } from "../chunk-QGBGZ2GI.mjs";
7
+ } from "../chunk-NKKBOLDI.mjs";
8
8
  import {
9
9
  SECURITY_CLIENT_CONFIG_COOKIE,
10
10
  createSecurityClientConfig,
@@ -12,7 +12,8 @@ import {
12
12
  } from "../chunk-FUOZWKHK.mjs";
13
13
  import {
14
14
  SecurityCsrfError
15
- } from "../chunk-EWQKJSFA.mjs";
15
+ } from "../chunk-AGICNQRJ.mjs";
16
+ import "../chunk-WDTNP5YU.mjs";
16
17
 
17
18
  // src/next/server.ts
18
19
  function isSafeMethod(method) {
@@ -64,6 +65,12 @@ async function issueCsrfCookie(request) {
64
65
  }
65
66
  function csrfProtection() {
66
67
  return async (request) => {
68
+ if (request.method.trim().toUpperCase() === "TRACE") {
69
+ return new Response("Method Not Allowed", {
70
+ status: 405,
71
+ headers: { Allow: "GET, HEAD, OPTIONS, POST, PUT, PATCH, DELETE" }
72
+ });
73
+ }
67
74
  try {
68
75
  await protect(request);
69
76
  } catch (error) {
@@ -4,7 +4,7 @@ import {
4
4
  getSecurityRuntime,
5
5
  isSecureRequest,
6
6
  protect
7
- } from "../chunk-QGBGZ2GI.mjs";
7
+ } from "../chunk-NKKBOLDI.mjs";
8
8
  import {
9
9
  SECURITY_CLIENT_CONFIG_COOKIE,
10
10
  createSecurityClientConfig,
@@ -12,7 +12,8 @@ import {
12
12
  } from "../chunk-FUOZWKHK.mjs";
13
13
  import {
14
14
  SecurityCsrfError
15
- } from "../chunk-EWQKJSFA.mjs";
15
+ } from "../chunk-AGICNQRJ.mjs";
16
+ import "../chunk-WDTNP5YU.mjs";
16
17
 
17
18
  // src/nuxt/server.ts
18
19
  import {
@@ -83,6 +84,12 @@ async function issueCsrfCookie(event, request) {
83
84
  }
84
85
  function csrfProtection() {
85
86
  return defineEventHandler(async (event) => {
87
+ if (getMethod(event).trim().toUpperCase() === "TRACE") {
88
+ return new Response("Method Not Allowed", {
89
+ status: 405,
90
+ headers: { Allow: "GET, HEAD, OPTIONS, POST, PUT, PATCH, DELETE" }
91
+ });
92
+ }
86
93
  const request = await createRequest(event);
87
94
  try {
88
95
  await protect(request);
@@ -97,6 +104,7 @@ function csrfProtection() {
97
104
  throw error;
98
105
  }
99
106
  await issueCsrfCookie(event, request);
107
+ return void 0;
100
108
  });
101
109
  }
102
110
  var nuxtSecurityInternals = {
@@ -3,7 +3,7 @@ import {
3
3
  getSecurityRuntime,
4
4
  isSecureRequest,
5
5
  protect
6
- } from "../chunk-QGBGZ2GI.mjs";
6
+ } from "../chunk-NKKBOLDI.mjs";
7
7
  import {
8
8
  SECURITY_CLIENT_CONFIG_COOKIE,
9
9
  createSecurityClientConfig,
@@ -11,7 +11,8 @@ import {
11
11
  } from "../chunk-FUOZWKHK.mjs";
12
12
  import {
13
13
  SecurityCsrfError
14
- } from "../chunk-EWQKJSFA.mjs";
14
+ } from "../chunk-AGICNQRJ.mjs";
15
+ import "../chunk-WDTNP5YU.mjs";
15
16
 
16
17
  // src/sveltekit/server.ts
17
18
  function isSafeMethod(method) {
@@ -47,6 +48,12 @@ function createCsrfErrorResponse(error) {
47
48
  }
48
49
  function csrfProtection() {
49
50
  return async ({ event, resolve }) => {
51
+ if (event.request.method.trim().toUpperCase() === "TRACE") {
52
+ return new Response("Method Not Allowed", {
53
+ status: 405,
54
+ headers: { Allow: "GET, HEAD, OPTIONS, POST, PUT, PATCH, DELETE" }
55
+ });
56
+ }
50
57
  try {
51
58
  await protect(event.request);
52
59
  } catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@holo-js/security",
3
- "version": "0.2.6",
3
+ "version": "0.3.1",
4
4
  "description": "Holo-JS Framework - CSRF and rate-limit contracts, config, and runtime seams",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -10,6 +10,11 @@
10
10
  "import": "./dist/index.mjs",
11
11
  "default": "./dist/index.mjs"
12
12
  },
13
+ "./config": {
14
+ "types": "./dist/config.d.ts",
15
+ "import": "./dist/config.mjs",
16
+ "default": "./dist/config.mjs"
17
+ },
13
18
  "./client": {
14
19
  "types": "./dist/client.d.ts",
15
20
  "import": "./dist/client.mjs",
@@ -53,7 +58,8 @@
53
58
  "test": "vitest --run --coverage"
54
59
  },
55
60
  "dependencies": {
56
- "@holo-js/config": "^0.2.6"
61
+ "@holo-js/config": "^0.3.1",
62
+ "@holo-js/kernel": "^0.3.1"
57
63
  },
58
64
  "peerDependencies": {
59
65
  "h3": "^1.15.11",