@thewhateverapp/platform 0.13.10 → 0.13.11
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/dist/ai/index.d.ts.map +1 -1
- package/dist/ai/index.js +8 -3
- package/dist/ai/index.js.map +1 -1
- package/dist/ai/mock-provider.d.ts +16 -0
- package/dist/ai/mock-provider.d.ts.map +1 -0
- package/dist/ai/mock-provider.js +50 -0
- package/dist/ai/mock-provider.js.map +1 -0
- package/dist/ai/providers/index.d.ts +2 -0
- package/dist/ai/providers/index.d.ts.map +1 -1
- package/dist/ai/providers/index.js +2 -0
- package/dist/ai/providers/index.js.map +1 -1
- package/dist/ai/providers/three-tier-ai.d.ts +35 -0
- package/dist/ai/providers/three-tier-ai.d.ts.map +1 -0
- package/dist/ai/providers/three-tier-ai.js +43 -0
- package/dist/ai/providers/three-tier-ai.js.map +1 -0
- package/dist/ai/providers.d.ts +1 -0
- package/dist/ai/providers.d.ts.map +1 -1
- package/dist/ai/providers.js +2 -0
- package/dist/ai/providers.js.map +1 -1
- package/dist/database/index.d.ts.map +1 -1
- package/dist/database/index.js +11 -29
- package/dist/database/index.js.map +1 -1
- package/dist/database/mock-provider.d.ts +10 -0
- package/dist/database/mock-provider.d.ts.map +1 -0
- package/dist/database/mock-provider.js +145 -0
- package/dist/database/mock-provider.js.map +1 -0
- package/dist/database/providers/index.d.ts +1 -0
- package/dist/database/providers/index.d.ts.map +1 -1
- package/dist/database/providers/index.js +1 -0
- package/dist/database/providers/index.js.map +1 -1
- package/dist/database/providers/three-tier-db.d.ts +33 -0
- package/dist/database/providers/three-tier-db.d.ts.map +1 -0
- package/dist/database/providers/three-tier-db.js +105 -0
- package/dist/database/providers/three-tier-db.js.map +1 -0
- package/dist/keyspace/index.d.ts.map +1 -1
- package/dist/keyspace/index.js +8 -3
- package/dist/keyspace/index.js.map +1 -1
- package/dist/keyspace/mock-provider.d.ts +31 -0
- package/dist/keyspace/mock-provider.d.ts.map +1 -0
- package/dist/keyspace/mock-provider.js +328 -0
- package/dist/keyspace/mock-provider.js.map +1 -0
- package/dist/keyspace/providers/index.d.ts +1 -0
- package/dist/keyspace/providers/index.d.ts.map +1 -1
- package/dist/keyspace/providers/index.js +1 -0
- package/dist/keyspace/providers/index.js.map +1 -1
- package/dist/keyspace/providers/three-tier-keyspace.d.ts +42 -0
- package/dist/keyspace/providers/three-tier-keyspace.d.ts.map +1 -0
- package/dist/keyspace/providers/three-tier-keyspace.js +106 -0
- package/dist/keyspace/providers/three-tier-keyspace.js.map +1 -0
- package/dist/kv/index.js +10 -10
- package/dist/kv/index.js.map +1 -1
- package/dist/kv/providers/index.d.ts +1 -0
- package/dist/kv/providers/index.d.ts.map +1 -1
- package/dist/kv/providers/index.js +1 -0
- package/dist/kv/providers/index.js.map +1 -1
- package/dist/kv/providers/three-tier-kv.d.ts +44 -0
- package/dist/kv/providers/three-tier-kv.d.ts.map +1 -0
- package/dist/kv/providers/three-tier-kv.js +69 -0
- package/dist/kv/providers/three-tier-kv.js.map +1 -0
- package/dist/providers/three-tier-provider.d.ts +77 -0
- package/dist/providers/three-tier-provider.d.ts.map +1 -0
- package/dist/providers/three-tier-provider.js +165 -0
- package/dist/providers/three-tier-provider.js.map +1 -0
- package/dist/r2/index.d.ts.map +1 -1
- package/dist/r2/index.js +11 -24
- package/dist/r2/index.js.map +1 -1
- package/dist/r2/mock-provider.d.ts +23 -0
- package/dist/r2/mock-provider.d.ts.map +1 -0
- package/dist/r2/mock-provider.js +161 -0
- package/dist/r2/mock-provider.js.map +1 -0
- package/dist/r2/providers/index.d.ts +1 -0
- package/dist/r2/providers/index.d.ts.map +1 -1
- package/dist/r2/providers/index.js +1 -0
- package/dist/r2/providers/index.js.map +1 -1
- package/dist/r2/providers/three-tier-r2.d.ts +43 -0
- package/dist/r2/providers/three-tier-r2.d.ts.map +1 -0
- package/dist/r2/providers/three-tier-r2.js +82 -0
- package/dist/r2/providers/three-tier-r2.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Three-Tier Provider System
|
|
3
|
+
*
|
|
4
|
+
* Provides a unified fallback chain for platform services:
|
|
5
|
+
* 1. Production - Real Cloudflare bindings (KV, D1, R2)
|
|
6
|
+
* 2. Preview via Proxy - HTTP proxy to skeleton worker
|
|
7
|
+
* 3. Mock/In-Memory - Fallback when skeleton not ready
|
|
8
|
+
*
|
|
9
|
+
* This ensures graceful degradation during the first ~60 seconds of tile generation
|
|
10
|
+
* when the skeleton deployment might return 530 errors or not be ready yet.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Provider mode enum
|
|
14
|
+
*/
|
|
15
|
+
export var ProviderMode;
|
|
16
|
+
(function (ProviderMode) {
|
|
17
|
+
ProviderMode["Production"] = "production";
|
|
18
|
+
ProviderMode["PreviewProxy"] = "preview-proxy";
|
|
19
|
+
ProviderMode["Mock"] = "mock";
|
|
20
|
+
})(ProviderMode || (ProviderMode = {}));
|
|
21
|
+
/**
|
|
22
|
+
* Check if an error indicates the skeleton deployment isn't ready
|
|
23
|
+
*/
|
|
24
|
+
export function isSkeletonNotReadyError(error) {
|
|
25
|
+
if (!(error instanceof Error))
|
|
26
|
+
return false;
|
|
27
|
+
const message = error.message.toLowerCase();
|
|
28
|
+
// 530 errors indicate the Worker isn't ready yet
|
|
29
|
+
if (message.includes('530'))
|
|
30
|
+
return true;
|
|
31
|
+
// Network errors during initial deployment
|
|
32
|
+
if (message.includes('fetch failed') || message.includes('network error'))
|
|
33
|
+
return true;
|
|
34
|
+
// Connection refused during deployment
|
|
35
|
+
if (message.includes('econnrefused') || message.includes('connection refused'))
|
|
36
|
+
return true;
|
|
37
|
+
// Timeout errors
|
|
38
|
+
if (message.includes('timeout'))
|
|
39
|
+
return true;
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Three-tier provider base class
|
|
44
|
+
*
|
|
45
|
+
* Implements the three-tier fallback logic:
|
|
46
|
+
* 1. Use production if available
|
|
47
|
+
* 2. Use preview proxy if available, fall back to mock on skeleton errors
|
|
48
|
+
* 3. Use mock as final fallback
|
|
49
|
+
*/
|
|
50
|
+
export class ThreeTierProvider {
|
|
51
|
+
production;
|
|
52
|
+
previewProxy;
|
|
53
|
+
mock;
|
|
54
|
+
debug;
|
|
55
|
+
currentMode;
|
|
56
|
+
skeletonFailed = false;
|
|
57
|
+
failureCount = 0;
|
|
58
|
+
maxFailures = 3;
|
|
59
|
+
constructor(config) {
|
|
60
|
+
this.production = config.production;
|
|
61
|
+
this.previewProxy = config.previewProxy;
|
|
62
|
+
this.mock = config.mock;
|
|
63
|
+
this.debug = config.debug ?? false;
|
|
64
|
+
// Determine initial mode
|
|
65
|
+
if (this.production) {
|
|
66
|
+
this.currentMode = ProviderMode.Production;
|
|
67
|
+
this.log('Initialized in PRODUCTION mode');
|
|
68
|
+
}
|
|
69
|
+
else if (this.previewProxy) {
|
|
70
|
+
this.currentMode = ProviderMode.PreviewProxy;
|
|
71
|
+
this.log('Initialized in PREVIEW PROXY mode with mock fallback');
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
this.currentMode = ProviderMode.Mock;
|
|
75
|
+
this.log('Initialized in MOCK mode');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
log(message, ...args) {
|
|
79
|
+
if (this.debug) {
|
|
80
|
+
console.log(`[ThreeTierProvider:${this.currentMode}] ${message}`, ...args);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Get the appropriate provider based on current mode and fallback logic
|
|
85
|
+
*/
|
|
86
|
+
getProvider() {
|
|
87
|
+
// If in production mode, always use production
|
|
88
|
+
if (this.currentMode === ProviderMode.Production) {
|
|
89
|
+
return this.production;
|
|
90
|
+
}
|
|
91
|
+
// If in preview proxy mode and skeleton has failed, use mock
|
|
92
|
+
if (this.currentMode === ProviderMode.PreviewProxy && this.skeletonFailed) {
|
|
93
|
+
this.log('Using MOCK (skeleton previously failed)');
|
|
94
|
+
return this.mock;
|
|
95
|
+
}
|
|
96
|
+
// If in preview proxy mode, use proxy
|
|
97
|
+
if (this.currentMode === ProviderMode.PreviewProxy && this.previewProxy) {
|
|
98
|
+
return this.previewProxy;
|
|
99
|
+
}
|
|
100
|
+
// Default to mock
|
|
101
|
+
return this.mock;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Execute an operation with automatic fallback
|
|
105
|
+
*/
|
|
106
|
+
async execute(operation, fn) {
|
|
107
|
+
// If in production mode, no fallback needed
|
|
108
|
+
if (this.currentMode === ProviderMode.Production) {
|
|
109
|
+
return fn(this.production);
|
|
110
|
+
}
|
|
111
|
+
// If skeleton already failed or in mock mode, use mock directly
|
|
112
|
+
if (this.skeletonFailed || this.currentMode === ProviderMode.Mock) {
|
|
113
|
+
this.log(`${operation}: Using mock`);
|
|
114
|
+
return fn(this.mock);
|
|
115
|
+
}
|
|
116
|
+
// Try preview proxy with fallback to mock
|
|
117
|
+
try {
|
|
118
|
+
this.log(`${operation}: Trying preview proxy`);
|
|
119
|
+
return await fn(this.previewProxy);
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
// Check if this is a skeleton-not-ready error
|
|
123
|
+
if (isSkeletonNotReadyError(error)) {
|
|
124
|
+
this.failureCount++;
|
|
125
|
+
console.warn(`[ThreeTierProvider] ${operation}: Skeleton not ready (attempt ${this.failureCount}/${this.maxFailures}), falling back to mock:`, error instanceof Error ? error.message : error);
|
|
126
|
+
// After max failures, mark skeleton as failed
|
|
127
|
+
if (this.failureCount >= this.maxFailures) {
|
|
128
|
+
this.skeletonFailed = true;
|
|
129
|
+
console.warn(`[ThreeTierProvider] Skeleton marked as unavailable after ${this.maxFailures} failures`);
|
|
130
|
+
}
|
|
131
|
+
// Fall back to mock
|
|
132
|
+
this.log(`${operation}: Using mock fallback`);
|
|
133
|
+
return fn(this.mock);
|
|
134
|
+
}
|
|
135
|
+
// For other errors, re-throw (don't mask genuine errors)
|
|
136
|
+
throw error;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Get the current provider mode
|
|
141
|
+
*/
|
|
142
|
+
getMode() {
|
|
143
|
+
if (this.currentMode === ProviderMode.Production) {
|
|
144
|
+
return ProviderMode.Production;
|
|
145
|
+
}
|
|
146
|
+
if (this.skeletonFailed) {
|
|
147
|
+
return ProviderMode.Mock;
|
|
148
|
+
}
|
|
149
|
+
return this.currentMode;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Check if skeleton has failed
|
|
153
|
+
*/
|
|
154
|
+
isSkeletonFailed() {
|
|
155
|
+
return this.skeletonFailed;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Reset skeleton failure state (for testing)
|
|
159
|
+
*/
|
|
160
|
+
resetSkeletonState() {
|
|
161
|
+
this.skeletonFailed = false;
|
|
162
|
+
this.failureCount = 0;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=three-tier-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"three-tier-provider.js","sourceRoot":"","sources":["../../src/providers/three-tier-provider.ts"],"names":[],"mappings":"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"}
|
package/dist/r2/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/r2/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAKrF,mBAAmB,SAAS,CAAC;AAE7B;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CACxB,GAAG,CAAC,EAAE,cAAc,GAAG;IAAE,GAAG,EAAE,oBAAoB,CAAA;CAAE,GAAG,oBAAoB,GAC1E,eAAe,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/r2/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAKrF,mBAAmB,SAAS,CAAC;AAE7B;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CACxB,GAAG,CAAC,EAAE,cAAc,GAAG;IAAE,GAAG,EAAE,oBAAoB,CAAA;CAAE,GAAG,oBAAoB,GAC1E,eAAe,CAyCjB;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,oBAAoB,GAAG,eAAe,CAexE"}
|
package/dist/r2/index.js
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
* }
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
|
-
import { CloudflareR2,
|
|
28
|
+
import { CloudflareR2, ThreeTierR2 } from './providers';
|
|
29
29
|
import { getPlatformEnv, isPlatformEnvConfigured } from '../env';
|
|
30
30
|
/**
|
|
31
31
|
* Get a storage instance for the current request
|
|
@@ -62,31 +62,18 @@ export function getStorage(req) {
|
|
|
62
62
|
if (!env) {
|
|
63
63
|
throw new Error('No environment found in request. Ensure you are running in edge runtime.');
|
|
64
64
|
}
|
|
65
|
-
//
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
65
|
+
// Use three-tier provider system
|
|
66
|
+
const config = {
|
|
67
|
+
production: env.STORAGE,
|
|
68
|
+
publicUrl: env.STORAGE_PUBLIC_URL,
|
|
69
|
+
previewProxy: env.__STORAGE_HTTP_PROXY__,
|
|
70
|
+
debug: true,
|
|
71
|
+
};
|
|
72
|
+
// If no production binding and no preview proxy, throw error
|
|
73
|
+
if (!config.production && !config.previewProxy) {
|
|
73
74
|
throw new Error('No R2 bucket binding found. Add an R2 bucket binding named "STORAGE" to your wrangler.jsonc');
|
|
74
75
|
}
|
|
75
|
-
|
|
76
|
-
const provider = env.STORAGE_PROVIDER || 'r2';
|
|
77
|
-
switch (provider) {
|
|
78
|
-
case 'r2':
|
|
79
|
-
return new CloudflareR2(env.STORAGE, env.STORAGE_PUBLIC_URL);
|
|
80
|
-
case 's3':
|
|
81
|
-
// Future: AWS S3 implementation
|
|
82
|
-
throw new Error('AWS S3 provider not yet implemented. Use STORAGE_PROVIDER=r2 or remove STORAGE_PROVIDER.');
|
|
83
|
-
case 'backblaze':
|
|
84
|
-
// Future: Backblaze B2 implementation
|
|
85
|
-
throw new Error('Backblaze B2 provider not yet implemented. Use STORAGE_PROVIDER=r2 or remove STORAGE_PROVIDER.');
|
|
86
|
-
default:
|
|
87
|
-
console.warn(`Unknown STORAGE_PROVIDER: ${provider}. Falling back to Cloudflare R2.`);
|
|
88
|
-
return new CloudflareR2(env.STORAGE, env.STORAGE_PUBLIC_URL);
|
|
89
|
-
}
|
|
76
|
+
return new ThreeTierR2(config);
|
|
90
77
|
}
|
|
91
78
|
/**
|
|
92
79
|
* Create a storage instance directly (for advanced usage)
|
package/dist/r2/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/r2/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAGH,OAAO,EAAE,YAAY,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/r2/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAGH,OAAO,EAAE,YAAY,EAAE,WAAW,EAAmD,MAAM,aAAa,CAAC;AACzG,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,QAAQ,CAAC;AAKjE;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,UAAU,CACxB,GAA2E;IAE3E,IAAI,GAAqC,CAAC;IAE1C,2DAA2D;IAC3D,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,IAAI,CAAC,uBAAuB,EAAE,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CACb,6EAA6E;gBAC3E,qHAAqH,CACxH,CAAC;QACJ,CAAC;QACD,GAAG,GAAG,cAAc,EAA0B,CAAC;IACjD,CAAC;SAAM,IAAI,KAAK,IAAI,GAAG,EAAE,CAAC;QACxB,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;IAChB,CAAC;SAAM,IAAI,SAAS,IAAI,GAAG,EAAE,CAAC;QAC5B,oBAAoB;QACpB,GAAG,GAAG,GAA2B,CAAC;IACpC,CAAC;SAAM,CAAC;QACN,GAAG,GAAI,GAAW,CAAC,GAAG,CAAC;IACzB,CAAC;IAED,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,0EAA0E,CAAC,CAAC;IAC9F,CAAC;IAED,iCAAiC;IACjC,MAAM,MAAM,GAAsB;QAChC,UAAU,EAAE,GAAG,CAAC,OAAO;QACvB,SAAS,EAAE,GAAG,CAAC,kBAAkB;QACjC,YAAY,EAAE,GAAG,CAAC,sBAAwD;QAC1E,KAAK,EAAE,IAAI;KACZ,CAAC;IAEF,6DAA6D;IAC7D,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;QAC/C,MAAM,IAAI,KAAK,CACb,6FAA6F,CAC9F,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;AACjC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAAC,GAAyB;IACrD,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;IACjD,CAAC;IAED,MAAM,QAAQ,GAAG,GAAG,CAAC,gBAAgB,IAAI,IAAI,CAAC;IAE9C,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,IAAI;YACP,OAAO,IAAI,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,kBAAkB,CAAC,CAAC;QAE/D;YACE,OAAO,CAAC,IAAI,CAAC,6BAA6B,QAAQ,kCAAkC,CAAC,CAAC;YACtF,OAAO,IAAI,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,kBAAkB,CAAC,CAAC;IACjE,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple in-memory mock R2 storage provider
|
|
3
|
+
* Implements StorageProvider interface for preview/testing
|
|
4
|
+
*/
|
|
5
|
+
import type { StorageProvider, StorageObject, StorageMetadata, ListOptions, ListResult, PutOptions, PutResult, GetOptions } from './types';
|
|
6
|
+
export declare class MockR2Provider implements StorageProvider {
|
|
7
|
+
private objects;
|
|
8
|
+
private debug;
|
|
9
|
+
constructor(config?: {
|
|
10
|
+
debug?: boolean;
|
|
11
|
+
});
|
|
12
|
+
private log;
|
|
13
|
+
put(key: string, value: ArrayBuffer | ReadableStream | Blob | string, options?: PutOptions): Promise<PutResult>;
|
|
14
|
+
get(key: string, options?: GetOptions): Promise<StorageObject | null>;
|
|
15
|
+
delete(key: string): Promise<void>;
|
|
16
|
+
deleteMany(keys: string[]): Promise<void>;
|
|
17
|
+
head(key: string): Promise<StorageMetadata | null>;
|
|
18
|
+
list(options?: ListOptions): Promise<ListResult>;
|
|
19
|
+
exists(key: string): Promise<boolean>;
|
|
20
|
+
copy(sourceKey: string, destinationKey: string): Promise<void>;
|
|
21
|
+
getPublicUrl(key: string): string;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=mock-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock-provider.d.ts","sourceRoot":"","sources":["../../src/r2/mock-provider.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACV,eAAe,EACf,aAAa,EACb,eAAe,EACf,WAAW,EACX,UAAU,EACV,UAAU,EACV,SAAS,EACT,UAAU,EACX,MAAM,SAAS,CAAC;AAWjB,qBAAa,cAAe,YAAW,eAAe;IACpD,OAAO,CAAC,OAAO,CAA6C;IAC5D,OAAO,CAAC,KAAK,CAAU;gBAEX,MAAM,GAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAO;IAI5C,OAAO,CAAC,GAAG;IAML,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,cAAc,GAAG,IAAI,GAAG,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC;IAiD/G,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAwBrE,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKlC,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAOzC,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAkBlD,IAAI,CAAC,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IAmChD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKrC,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAepE,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;CAKlC"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple in-memory mock R2 storage provider
|
|
3
|
+
* Implements StorageProvider interface for preview/testing
|
|
4
|
+
*/
|
|
5
|
+
export class MockR2Provider {
|
|
6
|
+
objects = new Map();
|
|
7
|
+
debug;
|
|
8
|
+
constructor(config = {}) {
|
|
9
|
+
this.debug = config.debug ?? false;
|
|
10
|
+
}
|
|
11
|
+
log(message, ...args) {
|
|
12
|
+
if (this.debug) {
|
|
13
|
+
console.log(`[MockR2] ${message}`, ...args);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
async put(key, value, options) {
|
|
17
|
+
this.log('PUT', key, options);
|
|
18
|
+
// Convert value to ArrayBuffer
|
|
19
|
+
let buffer;
|
|
20
|
+
if (typeof value === 'string') {
|
|
21
|
+
buffer = new TextEncoder().encode(value).buffer;
|
|
22
|
+
}
|
|
23
|
+
else if (value instanceof Blob) {
|
|
24
|
+
buffer = await value.arrayBuffer();
|
|
25
|
+
}
|
|
26
|
+
else if (value instanceof ReadableStream) {
|
|
27
|
+
// Read stream to buffer
|
|
28
|
+
const reader = value.getReader();
|
|
29
|
+
const chunks = [];
|
|
30
|
+
while (true) {
|
|
31
|
+
const { done, value: chunk } = await reader.read();
|
|
32
|
+
if (done)
|
|
33
|
+
break;
|
|
34
|
+
chunks.push(chunk);
|
|
35
|
+
}
|
|
36
|
+
const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0);
|
|
37
|
+
const combined = new Uint8Array(totalLength);
|
|
38
|
+
let offset = 0;
|
|
39
|
+
for (const chunk of chunks) {
|
|
40
|
+
combined.set(chunk, offset);
|
|
41
|
+
offset += chunk.length;
|
|
42
|
+
}
|
|
43
|
+
buffer = combined.buffer;
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
buffer = value;
|
|
47
|
+
}
|
|
48
|
+
const obj = {
|
|
49
|
+
key,
|
|
50
|
+
value: buffer,
|
|
51
|
+
metadata: options?.customMetadata,
|
|
52
|
+
contentType: options?.metadata?.contentType,
|
|
53
|
+
uploaded: new Date(),
|
|
54
|
+
size: buffer.byteLength,
|
|
55
|
+
};
|
|
56
|
+
this.objects.set(key, obj);
|
|
57
|
+
return {
|
|
58
|
+
key,
|
|
59
|
+
etag: `mock-etag-${Date.now()}`,
|
|
60
|
+
size: buffer.byteLength,
|
|
61
|
+
versionId: `mock-version-${Date.now()}`,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
async get(key, options) {
|
|
65
|
+
this.log('GET', key, options);
|
|
66
|
+
const obj = this.objects.get(key);
|
|
67
|
+
if (!obj) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
key: obj.key,
|
|
72
|
+
body: new ReadableStream({
|
|
73
|
+
start(controller) {
|
|
74
|
+
controller.enqueue(new Uint8Array(obj.value));
|
|
75
|
+
controller.close();
|
|
76
|
+
},
|
|
77
|
+
}),
|
|
78
|
+
size: obj.size,
|
|
79
|
+
etag: `mock-etag-${obj.uploaded.getTime()}`,
|
|
80
|
+
uploaded: obj.uploaded,
|
|
81
|
+
httpMetadata: obj.contentType ? { contentType: obj.contentType } : {},
|
|
82
|
+
metadata: obj.metadata,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
async delete(key) {
|
|
86
|
+
this.log('DELETE', key);
|
|
87
|
+
this.objects.delete(key);
|
|
88
|
+
}
|
|
89
|
+
async deleteMany(keys) {
|
|
90
|
+
this.log('DELETE_MANY', keys);
|
|
91
|
+
for (const key of keys) {
|
|
92
|
+
this.objects.delete(key);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async head(key) {
|
|
96
|
+
this.log('HEAD', key);
|
|
97
|
+
const obj = this.objects.get(key);
|
|
98
|
+
if (!obj) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
key: obj.key,
|
|
103
|
+
size: obj.size,
|
|
104
|
+
etag: `mock-etag-${obj.uploaded.getTime()}`,
|
|
105
|
+
uploaded: obj.uploaded,
|
|
106
|
+
httpMetadata: obj.contentType ? { contentType: obj.contentType } : {},
|
|
107
|
+
metadata: obj.metadata,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
async list(options) {
|
|
111
|
+
this.log('LIST', options);
|
|
112
|
+
let keys = Array.from(this.objects.keys());
|
|
113
|
+
// Filter by prefix
|
|
114
|
+
if (options?.prefix) {
|
|
115
|
+
keys = keys.filter((key) => key.startsWith(options.prefix));
|
|
116
|
+
}
|
|
117
|
+
// Apply limit
|
|
118
|
+
const limit = options?.limit || 1000;
|
|
119
|
+
const truncated = keys.length > limit;
|
|
120
|
+
keys = keys.slice(0, limit);
|
|
121
|
+
// Get metadata for each key
|
|
122
|
+
const objects = keys.map((key) => {
|
|
123
|
+
const obj = this.objects.get(key);
|
|
124
|
+
return {
|
|
125
|
+
key: obj.key,
|
|
126
|
+
size: obj.size,
|
|
127
|
+
etag: `mock-etag-${obj.uploaded.getTime()}`,
|
|
128
|
+
uploaded: obj.uploaded,
|
|
129
|
+
httpMetadata: obj.contentType ? { contentType: obj.contentType } : undefined,
|
|
130
|
+
metadata: obj.metadata,
|
|
131
|
+
};
|
|
132
|
+
});
|
|
133
|
+
return {
|
|
134
|
+
objects,
|
|
135
|
+
truncated,
|
|
136
|
+
cursor: truncated ? keys[keys.length - 1] : undefined,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
async exists(key) {
|
|
140
|
+
this.log('EXISTS', key);
|
|
141
|
+
return this.objects.has(key);
|
|
142
|
+
}
|
|
143
|
+
async copy(sourceKey, destinationKey) {
|
|
144
|
+
this.log('COPY', sourceKey, '->', destinationKey);
|
|
145
|
+
const obj = this.objects.get(sourceKey);
|
|
146
|
+
if (!obj) {
|
|
147
|
+
throw new Error(`Source key not found: ${sourceKey}`);
|
|
148
|
+
}
|
|
149
|
+
this.objects.set(destinationKey, {
|
|
150
|
+
...obj,
|
|
151
|
+
key: destinationKey,
|
|
152
|
+
uploaded: new Date(),
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
getPublicUrl(key) {
|
|
156
|
+
this.log('GET_PUBLIC_URL', key);
|
|
157
|
+
// Return a mock public URL
|
|
158
|
+
return `https://mock-r2.storage/${key}`;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=mock-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock-provider.js","sourceRoot":"","sources":["../../src/r2/mock-provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/r2/providers/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/r2/providers/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACvE,OAAO,EAAE,WAAW,EAAE,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/r2/providers/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAA2B,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/r2/providers/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAA2B,MAAM,iBAAiB,CAAC;AACvE,OAAO,EAAE,WAAW,EAA0B,MAAM,iBAAiB,CAAC;AAEtE,oBAAoB;AACpB,oCAAoC;AACpC,gDAAgD"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Three-Tier R2 Storage Provider
|
|
3
|
+
*
|
|
4
|
+
* Implements the three-tier fallback system:
|
|
5
|
+
* 1. Production - Real Cloudflare R2 binding
|
|
6
|
+
* 2. Preview via Proxy - HTTP proxy to skeleton worker
|
|
7
|
+
* 3. Mock/In-Memory - Fallback when skeleton not ready
|
|
8
|
+
*/
|
|
9
|
+
import type { StorageProvider, StorageObject, StorageMetadata, ListOptions, ListResult, PutOptions, PutResult, GetOptions } from '../types';
|
|
10
|
+
import { type HTTPProxyR2Options } from './http-proxy-r2';
|
|
11
|
+
/**
|
|
12
|
+
* Three-tier R2 configuration
|
|
13
|
+
*/
|
|
14
|
+
export interface ThreeTierR2Config {
|
|
15
|
+
/** Production R2 binding (if available) */
|
|
16
|
+
production?: R2Bucket;
|
|
17
|
+
/** Public URL for production storage */
|
|
18
|
+
publicUrl?: string;
|
|
19
|
+
/** Preview proxy configuration (if in preview mode) */
|
|
20
|
+
previewProxy?: HTTPProxyR2Options;
|
|
21
|
+
/** Debug logging */
|
|
22
|
+
debug?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Three-Tier R2 Storage Provider
|
|
26
|
+
*
|
|
27
|
+
* Automatically selects between production, preview proxy, and mock based on availability
|
|
28
|
+
* and skeleton deployment readiness.
|
|
29
|
+
*/
|
|
30
|
+
export declare class ThreeTierR2 implements StorageProvider {
|
|
31
|
+
private provider;
|
|
32
|
+
constructor(config: ThreeTierR2Config);
|
|
33
|
+
put(key: string, value: ArrayBuffer | ReadableStream | Blob | string, options?: PutOptions): Promise<PutResult>;
|
|
34
|
+
get(key: string, options?: GetOptions): Promise<StorageObject | null>;
|
|
35
|
+
delete(key: string): Promise<void>;
|
|
36
|
+
deleteMany(keys: string[]): Promise<void>;
|
|
37
|
+
head(key: string): Promise<StorageMetadata | null>;
|
|
38
|
+
list(options?: ListOptions): Promise<ListResult>;
|
|
39
|
+
exists(key: string): Promise<boolean>;
|
|
40
|
+
copy(sourceKey: string, destinationKey: string): Promise<void>;
|
|
41
|
+
getPublicUrl(key: string): string;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=three-tier-r2.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"three-tier-r2.d.ts","sourceRoot":"","sources":["../../../src/r2/providers/three-tier-r2.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EACV,eAAe,EACf,aAAa,EACb,eAAe,EACf,WAAW,EACX,UAAU,EACV,UAAU,EACV,SAAS,EACT,UAAU,EACX,MAAM,UAAU,CAAC;AAElB,OAAO,EAAe,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAIvE;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,2CAA2C;IAC3C,UAAU,CAAC,EAAE,QAAQ,CAAC;IACtB,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAClC,oBAAoB;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;GAKG;AACH,qBAAa,WAAY,YAAW,eAAe;IACjD,OAAO,CAAC,QAAQ,CAAqC;gBAEzC,MAAM,EAAE,iBAAiB;IAiB/B,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,cAAc,GAAG,IAAI,GAAG,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC;IAI/G,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAIrE,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlC,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzC,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAIlD,IAAI,CAAC,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IAIhD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIrC,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpE,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;CAoBlC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Three-Tier R2 Storage Provider
|
|
3
|
+
*
|
|
4
|
+
* Implements the three-tier fallback system:
|
|
5
|
+
* 1. Production - Real Cloudflare R2 binding
|
|
6
|
+
* 2. Preview via Proxy - HTTP proxy to skeleton worker
|
|
7
|
+
* 3. Mock/In-Memory - Fallback when skeleton not ready
|
|
8
|
+
*/
|
|
9
|
+
import { CloudflareR2 } from './cloudflare-r2';
|
|
10
|
+
import { HTTPProxyR2 } from './http-proxy-r2';
|
|
11
|
+
import { MockR2Provider } from '../mock-provider';
|
|
12
|
+
import { ThreeTierProvider } from '../../providers/three-tier-provider';
|
|
13
|
+
/**
|
|
14
|
+
* Three-Tier R2 Storage Provider
|
|
15
|
+
*
|
|
16
|
+
* Automatically selects between production, preview proxy, and mock based on availability
|
|
17
|
+
* and skeleton deployment readiness.
|
|
18
|
+
*/
|
|
19
|
+
export class ThreeTierR2 {
|
|
20
|
+
provider;
|
|
21
|
+
constructor(config) {
|
|
22
|
+
const production = config.production
|
|
23
|
+
? new CloudflareR2(config.production, config.publicUrl)
|
|
24
|
+
: undefined;
|
|
25
|
+
const previewProxy = config.previewProxy
|
|
26
|
+
? new HTTPProxyR2(config.previewProxy)
|
|
27
|
+
: undefined;
|
|
28
|
+
const mock = new MockR2Provider({ debug: config.debug });
|
|
29
|
+
this.provider = new ThreeTierProvider({
|
|
30
|
+
production,
|
|
31
|
+
previewProxy,
|
|
32
|
+
mock,
|
|
33
|
+
debug: config.debug,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
async put(key, value, options) {
|
|
37
|
+
return this.provider.execute('PUT', (storage) => storage.put(key, value, options));
|
|
38
|
+
}
|
|
39
|
+
async get(key, options) {
|
|
40
|
+
return this.provider.execute('GET', (storage) => storage.get(key, options));
|
|
41
|
+
}
|
|
42
|
+
async delete(key) {
|
|
43
|
+
return this.provider.execute('DELETE', (storage) => storage.delete(key));
|
|
44
|
+
}
|
|
45
|
+
async deleteMany(keys) {
|
|
46
|
+
return this.provider.execute('DELETE_MANY', (storage) => storage.deleteMany(keys));
|
|
47
|
+
}
|
|
48
|
+
async head(key) {
|
|
49
|
+
return this.provider.execute('HEAD', (storage) => storage.head(key));
|
|
50
|
+
}
|
|
51
|
+
async list(options) {
|
|
52
|
+
return this.provider.execute('LIST', (storage) => storage.list(options));
|
|
53
|
+
}
|
|
54
|
+
async exists(key) {
|
|
55
|
+
return this.provider.execute('EXISTS', (storage) => storage.exists(key));
|
|
56
|
+
}
|
|
57
|
+
async copy(sourceKey, destinationKey) {
|
|
58
|
+
return this.provider.execute('COPY', (storage) => storage.copy(sourceKey, destinationKey));
|
|
59
|
+
}
|
|
60
|
+
getPublicUrl(key) {
|
|
61
|
+
// For public URL, we can't use async execute, so we need to get the provider synchronously
|
|
62
|
+
// In preview mode with skeleton not ready, return mock URL
|
|
63
|
+
// In production, delegate to the production provider
|
|
64
|
+
try {
|
|
65
|
+
// Try to get the current mode
|
|
66
|
+
const mode = this.provider.getMode();
|
|
67
|
+
if (mode === 'production') {
|
|
68
|
+
// Get production provider - this is a bit hacky but necessary for sync method
|
|
69
|
+
const config = this.provider;
|
|
70
|
+
const production = config.production;
|
|
71
|
+
if (production?.getPublicUrl) {
|
|
72
|
+
return production.getPublicUrl(key);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch (e) {
|
|
77
|
+
// If anything fails, return mock URL
|
|
78
|
+
}
|
|
79
|
+
return `https://mock-r2.storage/${key}`;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=three-tier-r2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"three-tier-r2.js","sourceRoot":"","sources":["../../../src/r2/providers/three-tier-r2.ts"],"names":[],"mappings":"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"}
|