@umituz/web-cloudflare 1.4.3 → 1.4.5
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 +24 -29
- package/package.json +6 -5
- package/src/config/patterns.ts +43 -24
- package/src/domain/entities/analytics.entity.ts +18 -35
- package/src/domain/entities/d1.entity.ts +27 -0
- package/src/domain/entities/image.entity.ts +27 -27
- package/src/domain/entities/kv.entity.ts +20 -17
- package/src/domain/entities/r2.entity.ts +49 -0
- package/src/domain/entities/worker.entity.ts +35 -0
- package/src/domains/analytics/entities/index.ts +47 -0
- package/src/domains/analytics/index.ts +13 -0
- package/src/{infrastructure/services/analytics → domains/analytics/services}/analytics.service.ts +1 -1
- package/src/{infrastructure/services/analytics → domains/analytics/services}/index.ts +1 -0
- package/src/domains/analytics/types/index.ts +5 -0
- package/src/domains/analytics/types/service.interface.ts +12 -0
- package/src/domains/images/entities/index.ts +48 -0
- package/src/domains/images/index.ts +13 -0
- package/src/{infrastructure/services/images → domains/images/services}/images.service.ts +3 -3
- package/src/{infrastructure/services/images → domains/images/services}/index.ts +1 -0
- package/src/domains/images/types/index.ts +5 -0
- package/src/domains/images/types/service.interface.ts +13 -0
- package/src/domains/kv/entities/index.ts +34 -0
- package/src/domains/kv/index.ts +13 -0
- package/src/{infrastructure/services/kv → domains/kv/services}/index.ts +1 -0
- package/src/{infrastructure/services/kv → domains/kv/services}/kv.service.ts +2 -2
- package/src/domains/kv/types/index.ts +5 -0
- package/src/domains/kv/types/service.interface.ts +13 -0
- package/src/domains/workers/entities/index.ts +1 -1
- package/src/domains/workflows/entities/index.ts +60 -0
- package/src/domains/workflows/index.ts +10 -0
- package/src/domains/workflows/services/index.ts +6 -0
- package/src/{infrastructure/services/workflows/index.ts → domains/workflows/services/workflows.service.ts} +1 -1
- package/src/domains/wrangler/entities/index.ts +2 -2
- package/src/domains/wrangler/services/wrangler.service.ts +16 -8
- package/src/domains/wrangler/types/service.interface.ts +2 -2
- package/src/index.ts +4 -4
- package/src/infrastructure/middleware/auth.ts +118 -0
- package/src/infrastructure/middleware/cache.ts +95 -0
- package/src/infrastructure/middleware/cors.ts +95 -0
- package/src/infrastructure/middleware/index.ts +20 -3
- package/src/infrastructure/middleware/rate-limit.ts +105 -0
- package/src/infrastructure/router/index.ts +26 -4
- package/src/infrastructure/utils/helpers.ts +25 -11
- package/src/infrastructure/utils/utils.util.ts +3 -2
package/src/{infrastructure/services/analytics → domains/analytics/services}/analytics.service.ts
RENAMED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @description Cloudflare Web Analytics operations
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import type { AnalyticsEvent, AnalyticsPageviewEvent, AnalyticsCustomEvent, AnalyticsData } from "
|
|
6
|
+
import type { AnalyticsEvent, AnalyticsPageviewEvent, AnalyticsCustomEvent, AnalyticsData } from "../entities";
|
|
7
7
|
import type { IAnalyticsService } from "../../../domain/interfaces/services.interface";
|
|
8
8
|
|
|
9
9
|
export interface AnalyticsClientOptions {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analytics Service Interface
|
|
3
|
+
* @description Abstract interface for Analytics operations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { AnalyticsEvent, AnalyticsData } from '../entities';
|
|
7
|
+
|
|
8
|
+
export interface IAnalyticsService {
|
|
9
|
+
trackEvent(event: AnalyticsEvent): Promise<void>;
|
|
10
|
+
trackPageview(url: string, title: string, referrer?: string): Promise<void>;
|
|
11
|
+
getAnalytics(): Promise<AnalyticsData>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Image Entity
|
|
3
|
+
* @description Cloudflare Images configuration and types
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface ImageConfig {
|
|
7
|
+
readonly account: string;
|
|
8
|
+
readonly customDomain?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface ImageVariant {
|
|
12
|
+
readonly variant: string;
|
|
13
|
+
readonly width?: number;
|
|
14
|
+
readonly height?: number;
|
|
15
|
+
readonly fit?: "scale-down" | "contain" | "cover" | "crop" | "pad";
|
|
16
|
+
readonly format?: "jpeg" | "png" | "gif" | "webp" | "avif";
|
|
17
|
+
readonly quality?: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ImageUploadResult {
|
|
21
|
+
readonly id: string;
|
|
22
|
+
readonly filename: string;
|
|
23
|
+
readonly uploaded: Date;
|
|
24
|
+
readonly variants: readonly string[];
|
|
25
|
+
readonly requireSignedURLs: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface ImageUploadOptions {
|
|
29
|
+
readonly metadata?: Record<string, string>;
|
|
30
|
+
readonly requireSignedURLs?: boolean;
|
|
31
|
+
readonly variants?: readonly ImageVariant[];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface ImageTransformation {
|
|
35
|
+
readonly width?: number;
|
|
36
|
+
readonly height?: number;
|
|
37
|
+
readonly fit?: "scale-down" | "contain" | "cover" | "crop" | "pad";
|
|
38
|
+
readonly format?: "jpeg" | "png" | "gif" | "webp" | "avif";
|
|
39
|
+
readonly quality?: number;
|
|
40
|
+
readonly rotate?: number;
|
|
41
|
+
readonly flip?: boolean;
|
|
42
|
+
readonly flop?: boolean;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface SignedURL {
|
|
46
|
+
readonly url: string;
|
|
47
|
+
readonly expiresAt: Date;
|
|
48
|
+
}
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
* @description Cloudflare Images operations
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import type { ImageUploadResult, ImageUploadOptions, ImageTransformation, SignedURL } from "
|
|
6
|
+
import type { ImageUploadResult, ImageUploadOptions, ImageTransformation, SignedURL } from "../entities";
|
|
7
7
|
import type { IImageService } from "../../../domain/interfaces/services.interface";
|
|
8
|
-
import { validationUtils, transformUtils } from "
|
|
9
|
-
import { MAX_IMAGE_SIZE, ALLOWED_IMAGE_TYPES } from "
|
|
8
|
+
import { validationUtils, transformUtils } from "../../../infrastructure/utils";
|
|
9
|
+
import { MAX_IMAGE_SIZE, ALLOWED_IMAGE_TYPES } from "../../../infrastructure/constants";
|
|
10
10
|
|
|
11
11
|
export interface ImagesClientOptions {
|
|
12
12
|
readonly accountId: string;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Images Service Interface
|
|
3
|
+
* @description Abstract interface for Images operations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { ImageUploadResult, ImageUploadOptions, SignedURL, ImageTransformation } from '../entities';
|
|
7
|
+
|
|
8
|
+
export interface IImageService {
|
|
9
|
+
upload(file: File | Blob, options?: ImageUploadOptions): Promise<ImageUploadResult>;
|
|
10
|
+
getSignedURL(imageId: string, expiresIn?: number): Promise<SignedURL>;
|
|
11
|
+
getTransformedURL(imageId: string, transform: ImageTransformation): Promise<string>;
|
|
12
|
+
delete(imageId: string): Promise<boolean>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KV Entity
|
|
3
|
+
* @description Cloudflare KV configuration and types
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface KVNamespaceConfig {
|
|
7
|
+
readonly namespace: string;
|
|
8
|
+
readonly ttl?: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface KVEntry<T = unknown> {
|
|
12
|
+
readonly key: string;
|
|
13
|
+
readonly value: T;
|
|
14
|
+
readonly metadata?: Record<string, unknown>;
|
|
15
|
+
readonly expiration?: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface KVListOptions {
|
|
19
|
+
readonly limit?: number;
|
|
20
|
+
readonly cursor?: string;
|
|
21
|
+
readonly prefix?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface KVListResult {
|
|
25
|
+
readonly keys: readonly KVKey[];
|
|
26
|
+
readonly list_complete: boolean;
|
|
27
|
+
readonly cursor?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface KVKey {
|
|
31
|
+
readonly name: string;
|
|
32
|
+
readonly metadata?: Record<string, unknown>;
|
|
33
|
+
readonly expiration?: number;
|
|
34
|
+
}
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* @description Cloudflare KV key-value storage operations
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import type { KVEntry, KVListOptions, KVListResult } from "
|
|
6
|
+
import type { KVEntry, KVListOptions, KVListResult } from "../entities";
|
|
7
7
|
import type { IKVService } from "../../../domain/interfaces/services.interface";
|
|
8
|
-
import { validationUtils, cacheUtils } from "
|
|
8
|
+
import { validationUtils, cacheUtils } from "../../../infrastructure/utils";
|
|
9
9
|
|
|
10
10
|
export interface KVCacheOptions {
|
|
11
11
|
readonly namespace: string;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KV Service Interface
|
|
3
|
+
* @description Abstract interface for KV storage operations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { KVListOptions, KVListResult } from '../entities';
|
|
7
|
+
|
|
8
|
+
export interface IKVService {
|
|
9
|
+
get<T>(key: string): Promise<T | null>;
|
|
10
|
+
put<T>(key: string, value: T, options?: { ttl?: number }): Promise<void>;
|
|
11
|
+
delete(key: string): Promise<boolean>;
|
|
12
|
+
list(options?: KVListOptions): Promise<KVListResult>;
|
|
13
|
+
}
|
|
@@ -11,7 +11,7 @@ export interface WorkerResponse extends Response {
|
|
|
11
11
|
waitUntil?: (promise: Promise<unknown>) => void;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
export interface
|
|
14
|
+
export interface CloudflareWorkerConfig {
|
|
15
15
|
readonly name: string;
|
|
16
16
|
readonly routes?: string[];
|
|
17
17
|
readonly schedule?: string;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflows Domain Entities
|
|
3
|
+
* @description Workflow orchestration entities for Cloudflare Workers
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Workflow step definition
|
|
8
|
+
*/
|
|
9
|
+
export interface WorkflowStep {
|
|
10
|
+
id: string;
|
|
11
|
+
name: string;
|
|
12
|
+
handler: string;
|
|
13
|
+
timeout?: number;
|
|
14
|
+
retryPolicy?: {
|
|
15
|
+
maxAttempts: number;
|
|
16
|
+
backoffMultiplier: number;
|
|
17
|
+
initialDelay: number;
|
|
18
|
+
maxDelay: number;
|
|
19
|
+
};
|
|
20
|
+
dependencies?: string[];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Workflow definition
|
|
25
|
+
*/
|
|
26
|
+
export interface WorkflowDefinition {
|
|
27
|
+
id: string;
|
|
28
|
+
name: string;
|
|
29
|
+
description?: string;
|
|
30
|
+
steps: WorkflowStep[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Workflow execution state
|
|
35
|
+
*/
|
|
36
|
+
export interface WorkflowExecution {
|
|
37
|
+
id: string;
|
|
38
|
+
workflowId: string;
|
|
39
|
+
status: 'pending' | 'running' | 'completed' | 'failed';
|
|
40
|
+
currentStep?: string;
|
|
41
|
+
startedAt: number;
|
|
42
|
+
completedAt?: number;
|
|
43
|
+
input: unknown;
|
|
44
|
+
output?: unknown;
|
|
45
|
+
error?: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Workflow config
|
|
50
|
+
*/
|
|
51
|
+
export interface CloudflareWorkflowConfig {
|
|
52
|
+
enabled: boolean;
|
|
53
|
+
maxExecutionTime: number;
|
|
54
|
+
defaultRetries: number;
|
|
55
|
+
workflows?: Record<string, WorkflowDefinition>;
|
|
56
|
+
storage?: 'kv' | 'd1';
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Type alias for compatibility
|
|
60
|
+
export type WorkflowConfig = CloudflareWorkflowConfig;
|
|
@@ -132,9 +132,9 @@ export interface WorkerVersionInfo {
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
/**
|
|
135
|
-
*
|
|
135
|
+
* Wrangler analytics data
|
|
136
136
|
*/
|
|
137
|
-
export interface
|
|
137
|
+
export interface WranglerAnalyticsData {
|
|
138
138
|
requests?: number;
|
|
139
139
|
errors?: number;
|
|
140
140
|
statusCodes?: Record<string, number>;
|
|
@@ -118,6 +118,14 @@ export class WranglerService implements IWranglerService {
|
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
+
/**
|
|
122
|
+
* Convert string result to void result
|
|
123
|
+
*/
|
|
124
|
+
private asVoidResult(result: WranglerResult<string>): WranglerResult<void> {
|
|
125
|
+
const { data, ...rest } = result;
|
|
126
|
+
return rest;
|
|
127
|
+
}
|
|
128
|
+
|
|
121
129
|
// ==================== Authentication ====================
|
|
122
130
|
|
|
123
131
|
async login(options?: WranglerCommandOptions): Promise<WranglerResult<AuthInfo>> {
|
|
@@ -132,7 +140,7 @@ export class WranglerService implements IWranglerService {
|
|
|
132
140
|
}
|
|
133
141
|
|
|
134
142
|
async logout(options?: WranglerCommandOptions): Promise<WranglerResult<void>> {
|
|
135
|
-
return this.execute(['logout'], options);
|
|
143
|
+
return this.asVoidResult(await this.execute(['logout'], options));
|
|
136
144
|
}
|
|
137
145
|
|
|
138
146
|
async whoami(options?: WranglerCommandOptions): Promise<WranglerResult<AuthInfo>> {
|
|
@@ -158,7 +166,7 @@ export class WranglerService implements IWranglerService {
|
|
|
158
166
|
if (template) {
|
|
159
167
|
args.push('--template', template);
|
|
160
168
|
}
|
|
161
|
-
return this.execute(args, options);
|
|
169
|
+
return this.asVoidResult(await this.execute(args, options));
|
|
162
170
|
}
|
|
163
171
|
|
|
164
172
|
async dev(
|
|
@@ -237,7 +245,7 @@ export class WranglerService implements IWranglerService {
|
|
|
237
245
|
value: string,
|
|
238
246
|
options?: WranglerCommandOptions
|
|
239
247
|
): Promise<WranglerResult<void>> {
|
|
240
|
-
return this.execute(['kv:key', 'put', '--namespace-id', namespaceId, key, value], options);
|
|
248
|
+
return this.asVoidResult(await this.execute(['kv:key', 'put', '--namespace-id', namespaceId, key, value], options));
|
|
241
249
|
}
|
|
242
250
|
|
|
243
251
|
async kvKeyGet(
|
|
@@ -253,7 +261,7 @@ export class WranglerService implements IWranglerService {
|
|
|
253
261
|
key: string,
|
|
254
262
|
options?: WranglerCommandOptions
|
|
255
263
|
): Promise<WranglerResult<void>> {
|
|
256
|
-
return this.execute(['kv:key', 'delete', '--namespace-id', namespaceId, key], options);
|
|
264
|
+
return this.asVoidResult(await this.execute(['kv:key', 'delete', '--namespace-id', namespaceId, key], options));
|
|
257
265
|
}
|
|
258
266
|
|
|
259
267
|
// ==================== R2 Operations ====================
|
|
@@ -289,7 +297,7 @@ export class WranglerService implements IWranglerService {
|
|
|
289
297
|
bucketName: string,
|
|
290
298
|
options?: WranglerCommandOptions
|
|
291
299
|
): Promise<WranglerResult<void>> {
|
|
292
|
-
return this.execute(['r2', 'bucket', 'delete', bucketName], options);
|
|
300
|
+
return this.asVoidResult(await this.execute(['r2', 'bucket', 'delete', bucketName], options));
|
|
293
301
|
}
|
|
294
302
|
|
|
295
303
|
async r2ObjectPut(
|
|
@@ -298,7 +306,7 @@ export class WranglerService implements IWranglerService {
|
|
|
298
306
|
file: string,
|
|
299
307
|
options?: WranglerCommandOptions
|
|
300
308
|
): Promise<WranglerResult<void>> {
|
|
301
|
-
return this.execute(['r2', 'object', 'put', bucketName, key, '--file', file], options);
|
|
309
|
+
return this.asVoidResult(await this.execute(['r2', 'object', 'put', bucketName, key, '--file', file], options));
|
|
302
310
|
}
|
|
303
311
|
|
|
304
312
|
// ==================== D1 Operations ====================
|
|
@@ -412,7 +420,7 @@ export class WranglerService implements IWranglerService {
|
|
|
412
420
|
secretName: string,
|
|
413
421
|
options?: WranglerCommandOptions
|
|
414
422
|
): Promise<WranglerResult<void>> {
|
|
415
|
-
return this.execute(['secret', 'delete', secretName], options);
|
|
423
|
+
return this.asVoidResult(await this.execute(['secret', 'delete', secretName], options));
|
|
416
424
|
}
|
|
417
425
|
|
|
418
426
|
// ==================== Monitoring ====================
|
|
@@ -446,7 +454,7 @@ export class WranglerService implements IWranglerService {
|
|
|
446
454
|
versionId: string,
|
|
447
455
|
options?: WranglerCommandOptions
|
|
448
456
|
): Promise<WranglerResult<void>> {
|
|
449
|
-
return this.execute(['versions', 'rollback', '--version-id', versionId], options);
|
|
457
|
+
return this.asVoidResult(await this.execute(['versions', 'rollback', '--version-id', versionId], options));
|
|
450
458
|
}
|
|
451
459
|
|
|
452
460
|
// ==================== Generic Command Execution ====================
|
package/src/index.ts
CHANGED
|
@@ -31,10 +31,10 @@ export * from "./domains/workers";
|
|
|
31
31
|
export * from "./domains/ai-gateway";
|
|
32
32
|
export * from "./domains/r2";
|
|
33
33
|
export * from "./domains/d1";
|
|
34
|
-
export * from "./
|
|
35
|
-
export * from "./
|
|
36
|
-
export * from "./
|
|
37
|
-
export * from "./
|
|
34
|
+
export * from "./domains/kv";
|
|
35
|
+
export * from "./domains/images";
|
|
36
|
+
export * from "./domains/analytics";
|
|
37
|
+
export * from "./domains/workflows";
|
|
38
38
|
|
|
39
39
|
// Infrastructure - Router, Middleware, Utils
|
|
40
40
|
export * from "./infrastructure/router";
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth Middleware
|
|
3
|
+
* @description Authentication middleware for Cloudflare Workers
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface AuthConfig {
|
|
7
|
+
enabled: boolean;
|
|
8
|
+
type: 'bearer' | 'apikey' | 'basic';
|
|
9
|
+
token?: string;
|
|
10
|
+
apiKeyHeader?: string;
|
|
11
|
+
apiKeyValue?: string;
|
|
12
|
+
username?: string;
|
|
13
|
+
password?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Require authentication
|
|
18
|
+
*/
|
|
19
|
+
export async function requireAuth(
|
|
20
|
+
request: Request,
|
|
21
|
+
config: AuthConfig
|
|
22
|
+
): Promise<Response | null> {
|
|
23
|
+
if (!config.enabled) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const authHeader = request.headers.get('Authorization');
|
|
28
|
+
|
|
29
|
+
if (!authHeader) {
|
|
30
|
+
return new Response(
|
|
31
|
+
JSON.stringify({ error: 'Missing authorization header' }),
|
|
32
|
+
{
|
|
33
|
+
status: 401,
|
|
34
|
+
headers: { 'Content-Type': 'application/json' },
|
|
35
|
+
}
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
switch (config.type) {
|
|
40
|
+
case 'bearer':
|
|
41
|
+
if (!authHeader.startsWith('Bearer ')) {
|
|
42
|
+
return new Response(
|
|
43
|
+
JSON.stringify({ error: 'Invalid authorization type' }),
|
|
44
|
+
{
|
|
45
|
+
status: 401,
|
|
46
|
+
headers: { 'Content-Type': 'application/json' },
|
|
47
|
+
}
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
const token = authHeader.substring(7);
|
|
51
|
+
if (token !== config.token) {
|
|
52
|
+
return new Response(
|
|
53
|
+
JSON.stringify({ error: 'Invalid token' }),
|
|
54
|
+
{
|
|
55
|
+
status: 401,
|
|
56
|
+
headers: { 'Content-Type': 'application/json' },
|
|
57
|
+
}
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
break;
|
|
61
|
+
|
|
62
|
+
case 'apikey':
|
|
63
|
+
const apiKey = request.headers.get(config.apiKeyHeader || 'X-API-Key');
|
|
64
|
+
if (apiKey !== config.apiKeyValue) {
|
|
65
|
+
return new Response(
|
|
66
|
+
JSON.stringify({ error: 'Invalid API key' }),
|
|
67
|
+
{
|
|
68
|
+
status: 401,
|
|
69
|
+
headers: { 'Content-Type': 'application/json' },
|
|
70
|
+
}
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
break;
|
|
74
|
+
|
|
75
|
+
case 'basic':
|
|
76
|
+
if (!authHeader.startsWith('Basic ')) {
|
|
77
|
+
return new Response(
|
|
78
|
+
JSON.stringify({ error: 'Invalid authorization type' }),
|
|
79
|
+
{
|
|
80
|
+
status: 401,
|
|
81
|
+
headers: { 'Content-Type': 'application/json' },
|
|
82
|
+
}
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
const credentials = atob(authHeader.substring(6));
|
|
86
|
+
const [username, password] = credentials.split(':');
|
|
87
|
+
if (username !== config.username || password !== config.password) {
|
|
88
|
+
return new Response(
|
|
89
|
+
JSON.stringify({ error: 'Invalid credentials' }),
|
|
90
|
+
{
|
|
91
|
+
status: 401,
|
|
92
|
+
headers: { 'Content-Type': 'application/json' },
|
|
93
|
+
}
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Add user context to request
|
|
104
|
+
*/
|
|
105
|
+
export function addUserContext(request: Request, user: {
|
|
106
|
+
id: string;
|
|
107
|
+
[key: string]: unknown;
|
|
108
|
+
}): Request {
|
|
109
|
+
const headers = new Headers(request.headers);
|
|
110
|
+
headers.set('X-User-ID', user.id);
|
|
111
|
+
headers.set('X-User-Context', JSON.stringify(user));
|
|
112
|
+
|
|
113
|
+
return new Request(request.url, {
|
|
114
|
+
method: request.method,
|
|
115
|
+
headers,
|
|
116
|
+
body: request.body,
|
|
117
|
+
});
|
|
118
|
+
}
|