vector-framework 1.0.0 → 1.2.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.
Files changed (104) hide show
  1. package/README.md +87 -634
  2. package/dist/auth/protected.d.ts.map +1 -1
  3. package/dist/auth/protected.js.map +1 -1
  4. package/dist/cache/manager.d.ts +5 -2
  5. package/dist/cache/manager.d.ts.map +1 -1
  6. package/dist/cache/manager.js +21 -12
  7. package/dist/cache/manager.js.map +1 -1
  8. package/dist/cli/index.js +60 -126
  9. package/dist/cli/index.js.map +1 -1
  10. package/dist/cli/option-resolution.d.ts +4 -0
  11. package/dist/cli/option-resolution.d.ts.map +1 -0
  12. package/dist/cli/option-resolution.js +28 -0
  13. package/dist/cli/option-resolution.js.map +1 -0
  14. package/dist/cli.js +2774 -599
  15. package/dist/constants/index.d.ts +3 -0
  16. package/dist/constants/index.d.ts.map +1 -1
  17. package/dist/constants/index.js +6 -0
  18. package/dist/constants/index.js.map +1 -1
  19. package/dist/core/config-loader.d.ts +2 -2
  20. package/dist/core/config-loader.d.ts.map +1 -1
  21. package/dist/core/config-loader.js +18 -18
  22. package/dist/core/config-loader.js.map +1 -1
  23. package/dist/core/router.d.ts +41 -15
  24. package/dist/core/router.d.ts.map +1 -1
  25. package/dist/core/router.js +465 -150
  26. package/dist/core/router.js.map +1 -1
  27. package/dist/core/server.d.ts +17 -3
  28. package/dist/core/server.d.ts.map +1 -1
  29. package/dist/core/server.js +274 -33
  30. package/dist/core/server.js.map +1 -1
  31. package/dist/core/vector.d.ts +9 -8
  32. package/dist/core/vector.d.ts.map +1 -1
  33. package/dist/core/vector.js +40 -32
  34. package/dist/core/vector.js.map +1 -1
  35. package/dist/dev/route-generator.d.ts.map +1 -1
  36. package/dist/dev/route-generator.js.map +1 -1
  37. package/dist/dev/route-scanner.d.ts +1 -1
  38. package/dist/dev/route-scanner.d.ts.map +1 -1
  39. package/dist/dev/route-scanner.js +37 -43
  40. package/dist/dev/route-scanner.js.map +1 -1
  41. package/dist/http.d.ts +14 -14
  42. package/dist/http.d.ts.map +1 -1
  43. package/dist/http.js +84 -84
  44. package/dist/http.js.map +1 -1
  45. package/dist/index.d.ts +3 -3
  46. package/dist/index.js +1314 -8
  47. package/dist/index.mjs +1314 -8
  48. package/dist/middleware/manager.d.ts +1 -1
  49. package/dist/middleware/manager.d.ts.map +1 -1
  50. package/dist/middleware/manager.js +4 -0
  51. package/dist/middleware/manager.js.map +1 -1
  52. package/dist/openapi/docs-ui.d.ts +2 -0
  53. package/dist/openapi/docs-ui.d.ts.map +1 -0
  54. package/dist/openapi/docs-ui.js +1313 -0
  55. package/dist/openapi/docs-ui.js.map +1 -0
  56. package/dist/openapi/generator.d.ts +12 -0
  57. package/dist/openapi/generator.d.ts.map +1 -0
  58. package/dist/openapi/generator.js +273 -0
  59. package/dist/openapi/generator.js.map +1 -0
  60. package/dist/types/index.d.ts +70 -11
  61. package/dist/types/index.d.ts.map +1 -1
  62. package/dist/types/standard-schema.d.ts +118 -0
  63. package/dist/types/standard-schema.d.ts.map +1 -0
  64. package/dist/types/standard-schema.js +2 -0
  65. package/dist/types/standard-schema.js.map +1 -0
  66. package/dist/utils/cors.d.ts +13 -0
  67. package/dist/utils/cors.d.ts.map +1 -0
  68. package/dist/utils/cors.js +89 -0
  69. package/dist/utils/cors.js.map +1 -0
  70. package/dist/utils/path.d.ts +7 -0
  71. package/dist/utils/path.d.ts.map +1 -1
  72. package/dist/utils/path.js +14 -3
  73. package/dist/utils/path.js.map +1 -1
  74. package/dist/utils/schema-validation.d.ts +31 -0
  75. package/dist/utils/schema-validation.d.ts.map +1 -0
  76. package/dist/utils/schema-validation.js +77 -0
  77. package/dist/utils/schema-validation.js.map +1 -0
  78. package/dist/utils/validation.d.ts.map +1 -1
  79. package/dist/utils/validation.js +1 -0
  80. package/dist/utils/validation.js.map +1 -1
  81. package/package.json +24 -19
  82. package/src/auth/protected.ts +3 -13
  83. package/src/cache/manager.ts +25 -30
  84. package/src/cli/index.ts +62 -141
  85. package/src/cli/option-resolution.ts +40 -0
  86. package/src/constants/index.ts +7 -0
  87. package/src/core/config-loader.ts +20 -22
  88. package/src/core/router.ts +535 -155
  89. package/src/core/server.ts +354 -45
  90. package/src/core/vector.ts +71 -61
  91. package/src/dev/route-generator.ts +1 -3
  92. package/src/dev/route-scanner.ts +38 -51
  93. package/src/http.ts +117 -187
  94. package/src/index.ts +3 -3
  95. package/src/middleware/manager.ts +8 -11
  96. package/src/openapi/assets/tailwindcdn.js +83 -0
  97. package/src/openapi/docs-ui.ts +1317 -0
  98. package/src/openapi/generator.ts +359 -0
  99. package/src/types/index.ts +104 -17
  100. package/src/types/standard-schema.ts +147 -0
  101. package/src/utils/cors.ts +101 -0
  102. package/src/utils/path.ts +19 -4
  103. package/src/utils/schema-validation.ts +123 -0
  104. package/src/utils/validation.ts +1 -0
package/src/cli/index.ts CHANGED
@@ -1,54 +1,57 @@
1
1
  #!/usr/bin/env bun
2
2
 
3
- import { watch } from "node:fs";
4
- import { parseArgs } from "node:util";
5
- import { getVectorInstance } from "../core/vector";
6
- import { ConfigLoader } from "../core/config-loader";
3
+ import { watch } from 'node:fs';
4
+ import { parseArgs } from 'node:util';
5
+ import { getVectorInstance } from '../core/vector';
6
+ import { ConfigLoader } from '../core/config-loader';
7
+ import { resolveHost, resolvePort, resolveRoutesDir } from './option-resolution';
7
8
 
8
9
  // Compatibility layer for both Node and Bun
9
- const args =
10
- typeof Bun !== "undefined" ? Bun.argv.slice(2) : process.argv.slice(2);
10
+ const args = typeof Bun !== 'undefined' ? Bun.argv.slice(2) : process.argv.slice(2);
11
11
 
12
12
  const { values, positionals } = parseArgs({
13
13
  args,
14
14
  options: {
15
15
  port: {
16
- type: "string",
17
- short: "p",
18
- default: "3000",
16
+ type: 'string',
17
+ short: 'p',
18
+ default: '3000',
19
19
  },
20
20
  host: {
21
- type: "string",
22
- short: "h",
23
- default: "localhost",
21
+ type: 'string',
22
+ short: 'h',
23
+ default: 'localhost',
24
24
  },
25
25
  routes: {
26
- type: "string",
27
- short: "r",
28
- default: "./routes",
26
+ type: 'string',
27
+ short: 'r',
28
+ default: './routes',
29
29
  },
30
30
  watch: {
31
- type: "boolean",
32
- short: "w",
31
+ type: 'boolean',
32
+ short: 'w',
33
33
  default: true,
34
34
  },
35
35
  cors: {
36
- type: "boolean",
36
+ type: 'boolean',
37
37
  default: true,
38
38
  },
39
39
  config: {
40
- type: "string",
41
- short: "c",
40
+ type: 'string',
41
+ short: 'c',
42
42
  },
43
43
  },
44
44
  strict: true,
45
45
  allowPositionals: true,
46
46
  });
47
47
 
48
- const command = positionals[0] || "dev";
48
+ const command = positionals[0] || 'dev';
49
+ const hasRoutesOption = args.some((arg) => arg === '--routes' || arg === '-r' || arg.startsWith('--routes='));
50
+ const hasHostOption = args.some((arg) => arg === '--host' || arg === '-h' || arg.startsWith('--host='));
51
+ const hasPortOption = args.some((arg) => arg === '--port' || arg === '-p' || arg.startsWith('--port='));
49
52
 
50
53
  async function runDev() {
51
- const isDev = command === "dev";
54
+ const isDev = command === 'dev';
52
55
 
53
56
  let server: any = null;
54
57
  let vector: any = null;
@@ -57,21 +60,22 @@ async function runDev() {
57
60
  // Create a timeout promise that rejects after 10 seconds
58
61
  const timeoutPromise = new Promise<never>((_, reject) => {
59
62
  setTimeout(() => {
60
- reject(new Error("Server startup timed out (10s)"));
63
+ reject(new Error('Server startup timed out (10s)'));
61
64
  }, 10000);
62
65
  });
63
66
 
64
67
  // Create the actual server start promise
65
68
  const serverStartPromise = (async (): Promise<{ server: any; vector: any; config: any }> => {
66
- // Load configuration using ConfigLoader
67
- const configLoader = new ConfigLoader(values.config as string | undefined);
68
- const config = await configLoader.load();
69
-
70
- // Merge CLI options with loaded config
71
- // Only use CLI values if config doesn't have them
72
- config.port = config.port ?? Number.parseInt(values.port as string);
73
- config.hostname = config.hostname ?? (values.host as string);
74
- config.routesDir = config.routesDir ?? (values.routes as string);
69
+ const explicitConfigPath = values.config as string | undefined;
70
+ const configLoader = new ConfigLoader(explicitConfigPath);
71
+ const loadedConfig = await configLoader.load();
72
+ const config = { ...loadedConfig } as Record<string, any>;
73
+
74
+ // Merge CLI options with loaded config.
75
+ // Explicit --port/--host always override config values.
76
+ config.port = resolvePort(config.port, hasPortOption, values.port as string);
77
+ config.hostname = resolveHost(config.hostname, hasHostOption, values.host as string);
78
+ config.routesDir = resolveRoutesDir(config.routesDir, hasRoutesOption, values.routes as string);
75
79
  config.development = config.development ?? isDev;
76
80
  config.autoDiscover = true; // Always auto-discover routes
77
81
 
@@ -79,11 +83,11 @@ async function runDev() {
79
83
  // Only apply default CORS if config.cors is undefined (not set)
80
84
  if (config.cors === undefined && values.cors) {
81
85
  config.cors = {
82
- origin: "*",
86
+ origin: '*',
83
87
  credentials: true,
84
- allowHeaders: "Content-Type, Authorization",
85
- allowMethods: "GET, POST, PUT, PATCH, DELETE, OPTIONS",
86
- exposeHeaders: "Authorization",
88
+ allowHeaders: 'Content-Type, Authorization',
89
+ allowMethods: 'GET, POST, PUT, PATCH, DELETE, OPTIONS',
90
+ exposeHeaders: 'Authorization',
87
91
  maxAge: 86400,
88
92
  };
89
93
  }
@@ -108,15 +112,13 @@ async function runDev() {
108
112
 
109
113
  // Verify the server is actually running
110
114
  if (!server || !server.port) {
111
- throw new Error("Server started but is not responding correctly");
115
+ throw new Error('Server started but is not responding correctly');
112
116
  }
113
117
 
114
- const cyan = "\x1b[36m";
115
- const reset = "\x1b[0m";
118
+ const cyan = '\x1b[36m';
119
+ const reset = '\x1b[0m';
116
120
 
117
- console.log(
118
- `\nListening on ${cyan}http://${config.hostname}:${config.port}${reset}\n`
119
- );
121
+ console.log(`\nListening on ${cyan}http://${config.hostname}:${config.port}${reset}\n`);
120
122
 
121
123
  return { server, vector, config };
122
124
  })();
@@ -144,17 +146,14 @@ async function runDev() {
144
146
  const now = Date.now();
145
147
  if (isReloading || now - lastReloadTime < 1000) return;
146
148
 
149
+ const segments = filename ? filename.split(/[/\\]/) : [];
150
+ const excluded = segments.some((s) => ['node_modules', '.git', '.vector', 'dist'].includes(s));
147
151
  if (
148
152
  filename &&
149
- (filename.endsWith(".ts") ||
150
- filename.endsWith(".js") ||
151
- filename.endsWith(".json")) &&
152
- !filename.includes("node_modules") &&
153
- !filename.includes(".git") &&
154
- !filename.includes(".vector") && // Ignore generated files
155
- !filename.includes("dist") && // Ignore dist folder
156
- !filename.includes("bun.lockb") && // Ignore lock files
157
- !filename.endsWith(".generated.ts") // Ignore generated files
153
+ (filename.endsWith('.ts') || filename.endsWith('.js') || filename.endsWith('.json')) &&
154
+ !excluded &&
155
+ !filename.includes('bun.lockb') && // Ignore lock files
156
+ !filename.endsWith('.generated.ts') // Ignore generated files
158
157
  ) {
159
158
  // Track changed files
160
159
  changedFiles.add(filename);
@@ -181,24 +180,13 @@ async function runDev() {
181
180
  // Small delay to ensure file system operations complete
182
181
  await new Promise((resolve) => setTimeout(resolve, 100));
183
182
 
184
- // Clear module cache to ensure fresh imports
185
- // Note: Bun uses ESM and doesn't have require.cache
186
- // The Loader API will handle module reloading automatically
187
- if (typeof require !== 'undefined' && require.cache) {
188
- for (const key in require.cache) {
189
- if (!key.includes("node_modules")) {
190
- delete require.cache[key];
191
- }
192
- }
193
- }
194
-
195
183
  // Restart the server
196
184
  try {
197
185
  const result = await startServer();
198
186
  server = result.server;
199
187
  vector = result.vector;
200
188
  } catch (error: any) {
201
- console.error("\n[Reload Error]", error.message || error);
189
+ console.error('\n[Reload Error]', error.message || error);
202
190
  // Don't exit the process on reload failures, just continue watching
203
191
  } finally {
204
192
  // Reset flag immediately after reload completes
@@ -209,18 +197,18 @@ async function runDev() {
209
197
  }
210
198
  });
211
199
  } catch {
212
- const yellow = "\x1b[33m";
213
- const reset = "\x1b[0m";
200
+ const yellow = '\x1b[33m';
201
+ const reset = '\x1b[0m';
214
202
  console.warn(`${yellow}Warning: File watching not available${reset}`);
215
203
  }
216
204
  }
217
205
  } catch (error: any) {
218
- const red = "\x1b[31m";
219
- const reset = "\x1b[0m";
206
+ const red = '\x1b[31m';
207
+ const reset = '\x1b[0m';
220
208
 
221
209
  console.error(`\n${red}Error: ${error.message || error}${reset}\n`);
222
210
 
223
- if (error.stack && process.env.NODE_ENV === "development") {
211
+ if (error.stack && process.env.NODE_ENV === 'development') {
224
212
  console.error(error.stack);
225
213
  }
226
214
 
@@ -228,81 +216,15 @@ async function runDev() {
228
216
  }
229
217
  }
230
218
 
231
- async function runBuild() {
232
- try {
233
- const { RouteScanner } = await import("../dev/route-scanner");
234
- const { RouteGenerator } = await import("../dev/route-generator");
235
-
236
- // Step 1: Scan and generate routes
237
- const scanner = new RouteScanner(values.routes as string);
238
- const generator = new RouteGenerator();
239
-
240
- const routes = await scanner.scan();
241
- await generator.generate(routes);
242
-
243
- // Step 2: Build the application with Bun
244
- if (typeof Bun !== "undefined") {
245
- // Build the CLI as an executable
246
- const buildProcess = Bun.spawn([
247
- "bun",
248
- "build",
249
- "src/cli/index.ts",
250
- "--target",
251
- "bun",
252
- "--outfile",
253
- "dist/server.js",
254
- "--minify",
255
- ]);
256
-
257
- const exitCode = await buildProcess.exited;
258
- if (exitCode !== 0) {
259
- throw new Error(`Build failed with exit code ${exitCode}`);
260
- }
261
- } else {
262
- // For Node.js, use child_process
263
- const { spawnSync } = await import("child_process");
264
- const result = spawnSync(
265
- "bun",
266
- [
267
- "build",
268
- "src/cli/index.ts",
269
- "--target",
270
- "bun",
271
- "--outfile",
272
- "dist/server.js",
273
- "--minify",
274
- ],
275
- {
276
- stdio: "inherit",
277
- shell: true,
278
- }
279
- );
280
-
281
- if (result.status !== 0) {
282
- throw new Error(`Build failed with exit code ${result.status}`);
283
- }
284
- }
285
-
286
- console.log("\nBuild complete: dist/server.js\n");
287
- } catch (error: any) {
288
- const red = "\x1b[31m";
289
- const reset = "\x1b[0m";
290
- console.error(`\n${red}Error: ${error.message || error}${reset}\n`);
291
- process.exit(1);
292
- }
293
- }
294
-
295
219
  switch (command) {
296
- case "dev":
220
+ case 'dev':
297
221
  await runDev();
298
222
  break;
299
- case "build":
300
- await runBuild();
301
- break;
302
- case "start":
303
- process.env.NODE_ENV = "production";
223
+ case 'start': {
224
+ process.env.NODE_ENV = 'production';
304
225
  await runDev();
305
226
  break;
227
+ }
306
228
  default:
307
229
  console.error(`Unknown command: ${command}`);
308
230
  console.log(`
@@ -310,15 +232,14 @@ Usage: vector [command] [options]
310
232
 
311
233
  Commands:
312
234
  dev Start development server (default)
313
- build Build for production
314
235
  start Start production server
315
236
 
316
237
  Options:
317
238
  -p, --port <port> Port to listen on (default: 3000)
318
239
  -h, --host <host> Hostname to bind to (default: localhost)
319
- -r, --routes <dir> Routes directory (default: ./routes)
240
+ -r, --routes <dir> Routes directory (dev/start)
320
241
  -w, --watch Watch for file changes (default: true)
321
- -c, --config <path> Path to config file (default: vector.config.ts)
242
+ -c, --config <path> Path to config file (dev/start)
322
243
  --cors Enable CORS (default: true)
323
244
  `);
324
245
  process.exit(1);
@@ -0,0 +1,40 @@
1
+ export function resolveRoutesDir(
2
+ configRoutesDir: string | null | undefined,
3
+ hasRoutesOption: boolean,
4
+ cliRoutes: string
5
+ ): string {
6
+ if (hasRoutesOption) {
7
+ return cliRoutes;
8
+ }
9
+
10
+ return configRoutesDir ?? cliRoutes;
11
+ }
12
+
13
+ function parseAndValidatePort(value: unknown): number {
14
+ const parsed = typeof value === 'number' ? value : Number.parseInt(String(value), 10);
15
+
16
+ if (!Number.isInteger(parsed) || parsed < 0 || parsed > 65535) {
17
+ throw new Error(`Invalid port value: ${String(value)}`);
18
+ }
19
+
20
+ return parsed;
21
+ }
22
+
23
+ export function resolvePort(configPort: number | null | undefined, hasPortOption: boolean, cliPort: string): number {
24
+ if (hasPortOption) {
25
+ return parseAndValidatePort(cliPort);
26
+ }
27
+
28
+ const resolved = configPort ?? cliPort;
29
+ return parseAndValidatePort(resolved);
30
+ }
31
+
32
+ export function resolveHost(configHost: string | null | undefined, hasHostOption: boolean, cliHost: string): string {
33
+ const resolved = hasHostOption ? cliHost : (configHost ?? cliHost);
34
+
35
+ if (typeof resolved !== 'string' || resolved.length === 0) {
36
+ throw new Error(`Invalid host value: ${String(resolved)}`);
37
+ }
38
+
39
+ return resolved;
40
+ }
@@ -91,3 +91,10 @@ export const HTTP_METHODS = {
91
91
  OPTIONS: 'OPTIONS',
92
92
  HEAD: 'HEAD',
93
93
  } as const;
94
+
95
+ export const STATIC_RESPONSES: { NOT_FOUND: Response } = {
96
+ NOT_FOUND: new Response(JSON.stringify({ error: true, message: 'Not Found', statusCode: 404 }), {
97
+ status: 404,
98
+ headers: { 'content-type': 'application/json' },
99
+ }) as Response,
100
+ };
@@ -1,6 +1,6 @@
1
- import { existsSync } from "node:fs";
2
- import { resolve, isAbsolute } from "node:path";
3
- import { toFileUrl } from "../utils/path";
1
+ import { existsSync } from 'node:fs';
2
+ import { resolve, isAbsolute } from 'node:path';
3
+ import { toFileUrl } from '../utils/path';
4
4
  import type {
5
5
  CacheHandler,
6
6
  CorsOptions,
@@ -9,21 +9,19 @@ import type {
9
9
  VectorConfig,
10
10
  VectorConfigSchema,
11
11
  VectorTypes,
12
- } from "../types";
12
+ } from '../types';
13
13
 
14
14
  export class ConfigLoader<TTypes extends VectorTypes = DefaultVectorTypes> {
15
15
  private configPath: string;
16
16
  private config: VectorConfigSchema<TTypes> | null = null;
17
- private configSource: "user" | "default" = "default";
17
+ private configSource: 'user' | 'default' = 'default';
18
18
 
19
19
  constructor(configPath?: string) {
20
20
  // Use provided config path or default to vector.config.ts
21
- const path = configPath || "vector.config.ts";
21
+ const path = configPath || 'vector.config.ts';
22
22
 
23
23
  // Handle absolute vs relative paths
24
- this.configPath = isAbsolute(path)
25
- ? path
26
- : resolve(process.cwd(), path);
24
+ this.configPath = isAbsolute(path) ? path : resolve(process.cwd(), path);
27
25
  }
28
26
 
29
27
  async load(): Promise<VectorConfig<TTypes>> {
@@ -34,13 +32,11 @@ export class ConfigLoader<TTypes extends VectorTypes = DefaultVectorTypes> {
34
32
  const userConfigPath = toFileUrl(this.configPath);
35
33
  const userConfig = await import(userConfigPath);
36
34
  this.config = userConfig.default || userConfig;
37
- this.configSource = "user";
35
+ this.configSource = 'user';
38
36
  } catch (error: any) {
39
- const red = "\x1b[31m";
40
- const reset = "\x1b[0m";
41
- console.error(
42
- `${red}Error loading config: ${error.message || error}${reset}`
43
- );
37
+ const msg = error instanceof Error ? error.message : String(error);
38
+ console.error(`[Vector] Failed to load config from ${this.configPath}: ${msg}`);
39
+ console.error('[Vector] Server is using default configuration. Fix your config file and restart.');
44
40
  this.config = {};
45
41
  }
46
42
  } else {
@@ -52,7 +48,7 @@ export class ConfigLoader<TTypes extends VectorTypes = DefaultVectorTypes> {
52
48
  return await this.buildLegacyConfig();
53
49
  }
54
50
 
55
- getConfigSource(): "user" | "default" {
51
+ getConfigSource(): 'user' | 'default' {
56
52
  return this.configSource;
57
53
  }
58
54
 
@@ -65,8 +61,10 @@ export class ConfigLoader<TTypes extends VectorTypes = DefaultVectorTypes> {
65
61
  config.hostname = this.config.hostname;
66
62
  config.reusePort = this.config.reusePort;
67
63
  config.development = this.config.development;
68
- config.routesDir = this.config.routesDir || "./routes";
64
+ config.routesDir = this.config.routesDir || './routes';
69
65
  config.idleTimeout = this.config.idleTimeout;
66
+ config.defaults = this.config.defaults;
67
+ config.openapi = this.config.openapi;
70
68
  }
71
69
 
72
70
  // Always auto-discover routes
@@ -74,14 +72,14 @@ export class ConfigLoader<TTypes extends VectorTypes = DefaultVectorTypes> {
74
72
 
75
73
  // CORS configuration
76
74
  if (this.config?.cors) {
77
- if (typeof this.config.cors === "boolean") {
75
+ if (typeof this.config.cors === 'boolean') {
78
76
  config.cors = this.config.cors
79
77
  ? {
80
- origin: "*",
78
+ origin: '*',
81
79
  credentials: true,
82
- allowHeaders: "Content-Type, Authorization",
83
- allowMethods: "GET, POST, PUT, PATCH, DELETE, OPTIONS",
84
- exposeHeaders: "Authorization",
80
+ allowHeaders: 'Content-Type, Authorization',
81
+ allowMethods: 'GET, POST, PUT, PATCH, DELETE, OPTIONS',
82
+ exposeHeaders: 'Authorization',
85
83
  maxAge: 86400,
86
84
  }
87
85
  : undefined;