@b9g/platform 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +109 -0
- package/src/adapter-registry.d.ts +53 -0
- package/src/adapter-registry.js +71 -0
- package/src/base-platform.d.ts +50 -0
- package/src/base-platform.js +114 -0
- package/src/detection.d.ts +36 -0
- package/src/detection.js +126 -0
- package/src/directory-storage.d.ts +41 -0
- package/src/directory-storage.js +78 -0
- package/src/filesystem.d.ts +8 -0
- package/src/filesystem.js +10 -0
- package/src/index.d.ts +14 -0
- package/src/index.js +62 -0
- package/src/registry.d.ts +31 -0
- package/src/registry.js +74 -0
- package/src/service-worker.d.ts +149 -0
- package/src/service-worker.js +183 -0
- package/src/types.d.ts +239 -0
- package/src/types.js +36 -0
- package/src/utils.d.ts +33 -0
- package/src/utils.js +139 -0
package/src/types.d.ts
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core Platform interface and configuration types for Shovel deployment adapters
|
|
3
|
+
*/
|
|
4
|
+
import type { CacheStorage } from "@b9g/cache/cache-storage";
|
|
5
|
+
export { loadCacheAdapter, loadFilesystemAdapter, resolveCacheAdapter, resolveFilesystemAdapter, CACHE_ALIASES, FILESYSTEM_ALIASES, } from "./adapter-registry.js";
|
|
6
|
+
export { BasePlatform } from "./base-platform.js";
|
|
7
|
+
export { detectRuntime, detectDevelopmentPlatform, detectPlatforms, getBestPlatformDetection, resolvePlatform, createPlatform, displayPlatformInfo, } from "./detection.js";
|
|
8
|
+
/**
|
|
9
|
+
* Cache backend configuration
|
|
10
|
+
* Type can be a blessed alias or full package name
|
|
11
|
+
*/
|
|
12
|
+
export interface CacheBackendConfig {
|
|
13
|
+
/** Cache backend type - blessed alias (memory, redis, kv) or package name (@custom/cache) */
|
|
14
|
+
type?: string;
|
|
15
|
+
/** Maximum number of entries (for memory/LRU caches) */
|
|
16
|
+
maxEntries?: number;
|
|
17
|
+
/** Time-to-live in milliseconds or string format (e.g., '5m', '1h') */
|
|
18
|
+
ttl?: number | string;
|
|
19
|
+
/** Directory for filesystem cache */
|
|
20
|
+
dir?: string;
|
|
21
|
+
/** Redis connection string */
|
|
22
|
+
url?: string;
|
|
23
|
+
/** Custom cache factory function */
|
|
24
|
+
factory?: () => any;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Cache configuration for different cache types
|
|
28
|
+
*/
|
|
29
|
+
export interface CacheConfig {
|
|
30
|
+
/** Page/HTML cache configuration */
|
|
31
|
+
pages?: CacheBackendConfig;
|
|
32
|
+
/** API response cache configuration */
|
|
33
|
+
api?: CacheBackendConfig;
|
|
34
|
+
/** Static file cache configuration */
|
|
35
|
+
static?: CacheBackendConfig;
|
|
36
|
+
/** Custom named caches */
|
|
37
|
+
[name: string]: CacheBackendConfig | undefined;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Static file serving configuration
|
|
41
|
+
*/
|
|
42
|
+
export interface StaticConfig {
|
|
43
|
+
/** Public URL path prefix */
|
|
44
|
+
publicPath?: string;
|
|
45
|
+
/** Output directory for built assets */
|
|
46
|
+
outputDir?: string;
|
|
47
|
+
/** Asset manifest file path */
|
|
48
|
+
manifest?: string;
|
|
49
|
+
/** Development mode (serve from source) */
|
|
50
|
+
dev?: boolean;
|
|
51
|
+
/** Source directory for development */
|
|
52
|
+
sourceDir?: string;
|
|
53
|
+
/** Cache configuration for static files */
|
|
54
|
+
cache?: {
|
|
55
|
+
name?: string;
|
|
56
|
+
ttl?: string | number;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* CORS configuration
|
|
61
|
+
*/
|
|
62
|
+
export interface CorsConfig {
|
|
63
|
+
/** Allowed origins */
|
|
64
|
+
origin?: boolean | string | string[] | RegExp | ((origin: string) => boolean);
|
|
65
|
+
/** Allowed methods */
|
|
66
|
+
methods?: string[];
|
|
67
|
+
/** Allowed headers */
|
|
68
|
+
allowedHeaders?: string[];
|
|
69
|
+
/** Exposed headers */
|
|
70
|
+
exposedHeaders?: string[];
|
|
71
|
+
/** Allow credentials */
|
|
72
|
+
credentials?: boolean;
|
|
73
|
+
/** Preflight cache duration */
|
|
74
|
+
maxAge?: number;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Filesystem adapter configuration
|
|
78
|
+
*/
|
|
79
|
+
export interface FilesystemConfig {
|
|
80
|
+
/** Filesystem adapter type - blessed alias (memory, s3, r2) or package name (@custom/fs) */
|
|
81
|
+
type?: string;
|
|
82
|
+
/** Region for cloud storage */
|
|
83
|
+
region?: string;
|
|
84
|
+
/** Access credentials */
|
|
85
|
+
credentials?: {
|
|
86
|
+
accessKeyId?: string;
|
|
87
|
+
secretAccessKey?: string;
|
|
88
|
+
token?: string;
|
|
89
|
+
};
|
|
90
|
+
/** Additional adapter-specific options */
|
|
91
|
+
[key: string]: any;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Platform configuration from CLI flags
|
|
95
|
+
*/
|
|
96
|
+
export interface PlatformConfig {
|
|
97
|
+
/** Cache configuration */
|
|
98
|
+
caches?: CacheConfig;
|
|
99
|
+
/** Filesystem adapter configuration */
|
|
100
|
+
filesystem?: FilesystemConfig;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Server options for platform implementations
|
|
104
|
+
*/
|
|
105
|
+
export interface ServerOptions {
|
|
106
|
+
/** Port to listen on */
|
|
107
|
+
port?: number;
|
|
108
|
+
/** Host to bind to */
|
|
109
|
+
host?: string;
|
|
110
|
+
/** Hostname for URL generation */
|
|
111
|
+
hostname?: string;
|
|
112
|
+
/** Enable compression */
|
|
113
|
+
compression?: boolean;
|
|
114
|
+
/** CORS configuration */
|
|
115
|
+
cors?: CorsConfig;
|
|
116
|
+
/** Custom headers to add to all responses */
|
|
117
|
+
headers?: Record<string, string>;
|
|
118
|
+
/** Request timeout in milliseconds */
|
|
119
|
+
timeout?: number;
|
|
120
|
+
/** Development mode settings */
|
|
121
|
+
development?: {
|
|
122
|
+
/** Enable hot reloading */
|
|
123
|
+
hotReload?: boolean;
|
|
124
|
+
/** Source maps support */
|
|
125
|
+
sourceMaps?: boolean;
|
|
126
|
+
/** Verbose logging */
|
|
127
|
+
verbose?: boolean;
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Request handler function (Web Fetch API compatible)
|
|
132
|
+
*/
|
|
133
|
+
export type Handler = (request: Request, context?: any) => Promise<Response> | Response;
|
|
134
|
+
/**
|
|
135
|
+
* ServiceWorker entrypoint options
|
|
136
|
+
*/
|
|
137
|
+
export interface ServiceWorkerOptions {
|
|
138
|
+
/** Enable hot reloading */
|
|
139
|
+
hotReload?: boolean;
|
|
140
|
+
/** Cache configuration to pass to platform event */
|
|
141
|
+
caches?: CacheConfig;
|
|
142
|
+
/** Additional context to provide */
|
|
143
|
+
context?: any;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* ServiceWorker instance returned by platform
|
|
147
|
+
*/
|
|
148
|
+
export interface ServiceWorkerInstance {
|
|
149
|
+
/** The ServiceWorker runtime */
|
|
150
|
+
runtime: any;
|
|
151
|
+
/** Handle HTTP request */
|
|
152
|
+
handleRequest(request: Request): Promise<Response>;
|
|
153
|
+
/** Install the ServiceWorker */
|
|
154
|
+
install(): Promise<void>;
|
|
155
|
+
/** Activate the ServiceWorker */
|
|
156
|
+
activate(): Promise<void>;
|
|
157
|
+
/** Collect routes for static generation */
|
|
158
|
+
collectStaticRoutes(outDir: string, baseUrl?: string): Promise<string[]>;
|
|
159
|
+
/** Check if ready to handle requests */
|
|
160
|
+
readonly ready: boolean;
|
|
161
|
+
/** Dispose of resources */
|
|
162
|
+
dispose(): Promise<void>;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Server instance returned by platform.createServer()
|
|
166
|
+
*/
|
|
167
|
+
export interface Server {
|
|
168
|
+
/** Start listening for requests */
|
|
169
|
+
listen(): Promise<void> | void;
|
|
170
|
+
/** Stop the server */
|
|
171
|
+
close(): Promise<void> | void;
|
|
172
|
+
/** Get server URL */
|
|
173
|
+
url?: string;
|
|
174
|
+
/** Platform-specific server instance */
|
|
175
|
+
instance?: any;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Platform interface - ServiceWorker entrypoint loader for JavaScript runtimes
|
|
179
|
+
*
|
|
180
|
+
* The core responsibility: "Take a ServiceWorker-style app file and make it run in this environment"
|
|
181
|
+
*/
|
|
182
|
+
export interface Platform {
|
|
183
|
+
/**
|
|
184
|
+
* Platform name for identification
|
|
185
|
+
*/
|
|
186
|
+
readonly name: string;
|
|
187
|
+
/**
|
|
188
|
+
* Build artifacts filesystem (install-time only)
|
|
189
|
+
* Available during install handlers to copy built files to runtime storage
|
|
190
|
+
*/
|
|
191
|
+
readonly distDir: FileSystemDirectoryHandle;
|
|
192
|
+
/**
|
|
193
|
+
* THE MAIN JOB - Load and run a ServiceWorker-style entrypoint
|
|
194
|
+
* This is where all the platform-specific complexity lives
|
|
195
|
+
*/
|
|
196
|
+
loadServiceWorker(entrypoint: string, options?: ServiceWorkerOptions): Promise<ServiceWorkerInstance>;
|
|
197
|
+
/**
|
|
198
|
+
* SUPPORTING UTILITY - Create cache storage with platform-optimized backends
|
|
199
|
+
* Automatically selects optimal cache types when not specified:
|
|
200
|
+
* - Node.js: filesystem for persistence, memory for API
|
|
201
|
+
* - Cloudflare: KV for persistence, memory for fast access
|
|
202
|
+
* - Bun: filesystem with optimized writes
|
|
203
|
+
*/
|
|
204
|
+
createCaches(config?: CacheConfig): Promise<CacheStorage>;
|
|
205
|
+
/**
|
|
206
|
+
* SUPPORTING UTILITY - Create server instance for this platform
|
|
207
|
+
*/
|
|
208
|
+
createServer(handler: Handler, options?: ServerOptions): Server;
|
|
209
|
+
/**
|
|
210
|
+
* SUPPORTING UTILITY - Get filesystem root for bucket/container name
|
|
211
|
+
* Maps directly to cloud storage buckets (S3, R2) or local directories
|
|
212
|
+
* @param bucketName - The bucket/container/directory name
|
|
213
|
+
*/
|
|
214
|
+
getFileSystemRoot(bucketName: string): Promise<FileSystemDirectoryHandle>;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Platform detection result
|
|
218
|
+
*/
|
|
219
|
+
export interface PlatformDetection {
|
|
220
|
+
/** Detected platform name */
|
|
221
|
+
platform: string;
|
|
222
|
+
/** Confidence level (0-1) */
|
|
223
|
+
confidence: number;
|
|
224
|
+
/** Detection reasons */
|
|
225
|
+
reasons: string[];
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Platform registry for auto-detection
|
|
229
|
+
*/
|
|
230
|
+
export interface PlatformRegistry {
|
|
231
|
+
/** Register a platform implementation */
|
|
232
|
+
register(name: string, platform: Platform): void;
|
|
233
|
+
/** Get platform by name */
|
|
234
|
+
get(name: string): Platform | undefined;
|
|
235
|
+
/** Detect current platform */
|
|
236
|
+
detect(): PlatformDetection;
|
|
237
|
+
/** Get all registered platforms */
|
|
238
|
+
list(): string[];
|
|
239
|
+
}
|
package/src/types.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/// <reference types="./types.d.ts" />
|
|
2
|
+
// src/types.ts
|
|
3
|
+
import {
|
|
4
|
+
loadCacheAdapter,
|
|
5
|
+
loadFilesystemAdapter,
|
|
6
|
+
resolveCacheAdapter,
|
|
7
|
+
resolveFilesystemAdapter,
|
|
8
|
+
CACHE_ALIASES,
|
|
9
|
+
FILESYSTEM_ALIASES
|
|
10
|
+
} from "./adapter-registry.js";
|
|
11
|
+
import { BasePlatform } from "./base-platform.js";
|
|
12
|
+
import {
|
|
13
|
+
detectRuntime,
|
|
14
|
+
detectDevelopmentPlatform,
|
|
15
|
+
detectPlatforms,
|
|
16
|
+
getBestPlatformDetection,
|
|
17
|
+
resolvePlatform,
|
|
18
|
+
createPlatform,
|
|
19
|
+
displayPlatformInfo
|
|
20
|
+
} from "./detection.js";
|
|
21
|
+
export {
|
|
22
|
+
BasePlatform,
|
|
23
|
+
CACHE_ALIASES,
|
|
24
|
+
FILESYSTEM_ALIASES,
|
|
25
|
+
createPlatform,
|
|
26
|
+
detectDevelopmentPlatform,
|
|
27
|
+
detectPlatforms,
|
|
28
|
+
detectRuntime,
|
|
29
|
+
displayPlatformInfo,
|
|
30
|
+
getBestPlatformDetection,
|
|
31
|
+
loadCacheAdapter,
|
|
32
|
+
loadFilesystemAdapter,
|
|
33
|
+
resolveCacheAdapter,
|
|
34
|
+
resolveFilesystemAdapter,
|
|
35
|
+
resolvePlatform
|
|
36
|
+
};
|
package/src/utils.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for platform implementations
|
|
3
|
+
*/
|
|
4
|
+
import type { CacheBackendConfig } from "./types.js";
|
|
5
|
+
/**
|
|
6
|
+
* Parse TTL string to milliseconds
|
|
7
|
+
*/
|
|
8
|
+
export declare function parseTTL(ttl: string | number | undefined): number | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* Merge cache configurations with defaults
|
|
11
|
+
*/
|
|
12
|
+
export declare function mergeCacheConfig(userConfig: CacheBackendConfig | undefined, defaults: Partial<CacheBackendConfig>): CacheBackendConfig;
|
|
13
|
+
/**
|
|
14
|
+
* Validate cache backend configuration
|
|
15
|
+
*/
|
|
16
|
+
export declare function validateCacheConfig(config: CacheBackendConfig): void;
|
|
17
|
+
/**
|
|
18
|
+
* Create CORS headers from configuration
|
|
19
|
+
*/
|
|
20
|
+
export declare function createCorsHeaders(corsConfig: any, // CorsConfig but avoiding circular import
|
|
21
|
+
request: Request): Headers;
|
|
22
|
+
/**
|
|
23
|
+
* Merge headers from multiple sources
|
|
24
|
+
*/
|
|
25
|
+
export declare function mergeHeaders(...headerSources: (Headers | Record<string, string> | undefined)[]): Headers;
|
|
26
|
+
/**
|
|
27
|
+
* Check if request is a preflight CORS request
|
|
28
|
+
*/
|
|
29
|
+
export declare function isPreflightRequest(request: Request): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Create a preflight response
|
|
32
|
+
*/
|
|
33
|
+
export declare function createPreflightResponse(corsConfig: any, request: Request): Response;
|
package/src/utils.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/// <reference types="./utils.d.ts" />
|
|
2
|
+
// src/utils.ts
|
|
3
|
+
function parseTTL(ttl) {
|
|
4
|
+
if (typeof ttl === "number") {
|
|
5
|
+
return ttl;
|
|
6
|
+
}
|
|
7
|
+
if (typeof ttl !== "string") {
|
|
8
|
+
return void 0;
|
|
9
|
+
}
|
|
10
|
+
const match = ttl.match(/^(\d+)\s*(ms|s|m|h|d)?$/);
|
|
11
|
+
if (!match) {
|
|
12
|
+
throw new Error(
|
|
13
|
+
`Invalid TTL format: ${ttl}. Use format like '5m', '1h', '30s'`
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
const value = parseInt(match[1], 10);
|
|
17
|
+
const unit = match[2] || "ms";
|
|
18
|
+
const multipliers = {
|
|
19
|
+
ms: 1,
|
|
20
|
+
s: 1e3,
|
|
21
|
+
m: 60 * 1e3,
|
|
22
|
+
h: 60 * 60 * 1e3,
|
|
23
|
+
d: 24 * 60 * 60 * 1e3
|
|
24
|
+
};
|
|
25
|
+
return value * multipliers[unit];
|
|
26
|
+
}
|
|
27
|
+
function mergeCacheConfig(userConfig, defaults) {
|
|
28
|
+
return {
|
|
29
|
+
type: "memory",
|
|
30
|
+
...defaults,
|
|
31
|
+
...userConfig
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function validateCacheConfig(config) {
|
|
35
|
+
const validTypes = ["memory", "filesystem", "redis", "kv", "custom"];
|
|
36
|
+
if (!validTypes.includes(config.type)) {
|
|
37
|
+
throw new Error(
|
|
38
|
+
`Invalid cache type '${config.type}'. Must be one of: ${validTypes.join(", ")}`
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
if (config.type === "filesystem" && !config.dir) {
|
|
42
|
+
throw new Error("Filesystem cache requires a directory (dir) option");
|
|
43
|
+
}
|
|
44
|
+
if (config.type === "redis" && !config.url) {
|
|
45
|
+
throw new Error("Redis cache requires a connection URL (url) option");
|
|
46
|
+
}
|
|
47
|
+
if (config.type === "custom" && !config.factory) {
|
|
48
|
+
throw new Error("Custom cache requires a factory function");
|
|
49
|
+
}
|
|
50
|
+
if (config.maxEntries !== void 0 && config.maxEntries <= 0) {
|
|
51
|
+
throw new Error("maxEntries must be a positive number");
|
|
52
|
+
}
|
|
53
|
+
if (config.ttl !== void 0) {
|
|
54
|
+
try {
|
|
55
|
+
parseTTL(config.ttl);
|
|
56
|
+
} catch (error) {
|
|
57
|
+
throw new Error(`Invalid TTL configuration: ${error.message}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function createCorsHeaders(corsConfig, request) {
|
|
62
|
+
const headers = new Headers();
|
|
63
|
+
if (!corsConfig) {
|
|
64
|
+
return headers;
|
|
65
|
+
}
|
|
66
|
+
const origin = request.headers.get("origin");
|
|
67
|
+
if (corsConfig.origin === true) {
|
|
68
|
+
headers.set("Access-Control-Allow-Origin", "*");
|
|
69
|
+
} else if (typeof corsConfig.origin === "string") {
|
|
70
|
+
headers.set("Access-Control-Allow-Origin", corsConfig.origin);
|
|
71
|
+
} else if (Array.isArray(corsConfig.origin)) {
|
|
72
|
+
if (origin && corsConfig.origin.includes(origin)) {
|
|
73
|
+
headers.set("Access-Control-Allow-Origin", origin);
|
|
74
|
+
}
|
|
75
|
+
} else if (corsConfig.origin instanceof RegExp) {
|
|
76
|
+
if (origin && corsConfig.origin.test(origin)) {
|
|
77
|
+
headers.set("Access-Control-Allow-Origin", origin);
|
|
78
|
+
}
|
|
79
|
+
} else if (typeof corsConfig.origin === "function") {
|
|
80
|
+
if (origin && corsConfig.origin(origin)) {
|
|
81
|
+
headers.set("Access-Control-Allow-Origin", origin);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (corsConfig.methods) {
|
|
85
|
+
headers.set("Access-Control-Allow-Methods", corsConfig.methods.join(", "));
|
|
86
|
+
}
|
|
87
|
+
if (corsConfig.allowedHeaders) {
|
|
88
|
+
headers.set(
|
|
89
|
+
"Access-Control-Allow-Headers",
|
|
90
|
+
corsConfig.allowedHeaders.join(", ")
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
if (corsConfig.exposedHeaders) {
|
|
94
|
+
headers.set(
|
|
95
|
+
"Access-Control-Expose-Headers",
|
|
96
|
+
corsConfig.exposedHeaders.join(", ")
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
if (corsConfig.credentials) {
|
|
100
|
+
headers.set("Access-Control-Allow-Credentials", "true");
|
|
101
|
+
}
|
|
102
|
+
if (corsConfig.maxAge !== void 0) {
|
|
103
|
+
headers.set("Access-Control-Max-Age", corsConfig.maxAge.toString());
|
|
104
|
+
}
|
|
105
|
+
return headers;
|
|
106
|
+
}
|
|
107
|
+
function mergeHeaders(...headerSources) {
|
|
108
|
+
const result = new Headers();
|
|
109
|
+
for (const source of headerSources) {
|
|
110
|
+
if (!source)
|
|
111
|
+
continue;
|
|
112
|
+
if (source instanceof Headers) {
|
|
113
|
+
for (const [key, value] of source.entries()) {
|
|
114
|
+
result.set(key, value);
|
|
115
|
+
}
|
|
116
|
+
} else {
|
|
117
|
+
for (const [key, value] of Object.entries(source)) {
|
|
118
|
+
result.set(key, value);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
124
|
+
function isPreflightRequest(request) {
|
|
125
|
+
return request.method === "OPTIONS" && request.headers.has("access-control-request-method");
|
|
126
|
+
}
|
|
127
|
+
function createPreflightResponse(corsConfig, request) {
|
|
128
|
+
const headers = createCorsHeaders(corsConfig, request);
|
|
129
|
+
return new Response(null, { status: 204, headers });
|
|
130
|
+
}
|
|
131
|
+
export {
|
|
132
|
+
createCorsHeaders,
|
|
133
|
+
createPreflightResponse,
|
|
134
|
+
isPreflightRequest,
|
|
135
|
+
mergeCacheConfig,
|
|
136
|
+
mergeHeaders,
|
|
137
|
+
parseTTL,
|
|
138
|
+
validateCacheConfig
|
|
139
|
+
};
|