gsd-agent 1.0.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/README.md +221 -0
- package/bin/cli.js +313 -0
- package/dist/auth-flow.d.ts +50 -0
- package/dist/auth-flow.d.ts.map +1 -0
- package/dist/auth-flow.js +233 -0
- package/dist/auth-flow.js.map +1 -0
- package/dist/auth.d.ts +42 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +117 -0
- package/dist/auth.js.map +1 -0
- package/dist/command-executor.d.ts +44 -0
- package/dist/command-executor.d.ts.map +1 -0
- package/dist/command-executor.js +193 -0
- package/dist/command-executor.js.map +1 -0
- package/dist/command-executor.test.d.ts +8 -0
- package/dist/command-executor.test.d.ts.map +1 -0
- package/dist/command-executor.test.js +87 -0
- package/dist/command-executor.test.js.map +1 -0
- package/dist/command-queue.d.ts +44 -0
- package/dist/command-queue.d.ts.map +1 -0
- package/dist/command-queue.js +184 -0
- package/dist/command-queue.js.map +1 -0
- package/dist/command-queue.test.d.ts +7 -0
- package/dist/command-queue.test.d.ts.map +1 -0
- package/dist/command-queue.test.js +220 -0
- package/dist/command-queue.test.js.map +1 -0
- package/dist/config.d.ts +25 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +103 -0
- package/dist/config.js.map +1 -0
- package/dist/conflict-resolver.d.ts +43 -0
- package/dist/conflict-resolver.d.ts.map +1 -0
- package/dist/conflict-resolver.js +91 -0
- package/dist/conflict-resolver.js.map +1 -0
- package/dist/conflict-resolver.test.d.ts +7 -0
- package/dist/conflict-resolver.test.d.ts.map +1 -0
- package/dist/conflict-resolver.test.js +123 -0
- package/dist/conflict-resolver.test.js.map +1 -0
- package/dist/discovery.d.ts +59 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +180 -0
- package/dist/discovery.js.map +1 -0
- package/dist/discovery.test.d.ts +8 -0
- package/dist/discovery.test.d.ts.map +1 -0
- package/dist/discovery.test.js +132 -0
- package/dist/discovery.test.js.map +1 -0
- package/dist/hash.d.ts +20 -0
- package/dist/hash.d.ts.map +1 -0
- package/dist/hash.js +35 -0
- package/dist/hash.js.map +1 -0
- package/dist/hash.test.d.ts +7 -0
- package/dist/hash.test.d.ts.map +1 -0
- package/dist/hash.test.js +58 -0
- package/dist/hash.test.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +202 -0
- package/dist/index.js.map +1 -0
- package/dist/integration.test.d.ts +8 -0
- package/dist/integration.test.d.ts.map +1 -0
- package/dist/integration.test.js +37 -0
- package/dist/integration.test.js.map +1 -0
- package/dist/logger.d.ts +68 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +159 -0
- package/dist/logger.js.map +1 -0
- package/dist/output-streamer.d.ts +27 -0
- package/dist/output-streamer.d.ts.map +1 -0
- package/dist/output-streamer.js +71 -0
- package/dist/output-streamer.js.map +1 -0
- package/dist/output-streamer.test.d.ts +7 -0
- package/dist/output-streamer.test.d.ts.map +1 -0
- package/dist/output-streamer.test.js +90 -0
- package/dist/output-streamer.test.js.map +1 -0
- package/dist/realtime-subscriber.d.ts +63 -0
- package/dist/realtime-subscriber.d.ts.map +1 -0
- package/dist/realtime-subscriber.js +201 -0
- package/dist/realtime-subscriber.js.map +1 -0
- package/dist/realtime-subscriber.test.d.ts +7 -0
- package/dist/realtime-subscriber.test.d.ts.map +1 -0
- package/dist/realtime-subscriber.test.js +183 -0
- package/dist/realtime-subscriber.test.js.map +1 -0
- package/dist/reconnection-manager.d.ts +88 -0
- package/dist/reconnection-manager.d.ts.map +1 -0
- package/dist/reconnection-manager.js +229 -0
- package/dist/reconnection-manager.js.map +1 -0
- package/dist/reconnection-manager.test.d.ts +8 -0
- package/dist/reconnection-manager.test.d.ts.map +1 -0
- package/dist/reconnection-manager.test.js +151 -0
- package/dist/reconnection-manager.test.js.map +1 -0
- package/dist/remote-sync-handler.d.ts +61 -0
- package/dist/remote-sync-handler.d.ts.map +1 -0
- package/dist/remote-sync-handler.js +197 -0
- package/dist/remote-sync-handler.js.map +1 -0
- package/dist/remote-sync-handler.test.d.ts +7 -0
- package/dist/remote-sync-handler.test.d.ts.map +1 -0
- package/dist/remote-sync-handler.test.js +212 -0
- package/dist/remote-sync-handler.test.js.map +1 -0
- package/dist/retry.d.ts +35 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +63 -0
- package/dist/retry.js.map +1 -0
- package/dist/retry.test.d.ts +5 -0
- package/dist/retry.test.d.ts.map +1 -0
- package/dist/retry.test.js +84 -0
- package/dist/retry.test.js.map +1 -0
- package/dist/storage-client.d.ts +69 -0
- package/dist/storage-client.d.ts.map +1 -0
- package/dist/storage-client.js +168 -0
- package/dist/storage-client.js.map +1 -0
- package/dist/storage-client.test.d.ts +7 -0
- package/dist/storage-client.test.d.ts.map +1 -0
- package/dist/storage-client.test.js +126 -0
- package/dist/storage-client.test.js.map +1 -0
- package/dist/supabase.d.ts +82 -0
- package/dist/supabase.d.ts.map +1 -0
- package/dist/supabase.js +341 -0
- package/dist/supabase.js.map +1 -0
- package/dist/supabase.test.d.ts +7 -0
- package/dist/supabase.test.d.ts.map +1 -0
- package/dist/supabase.test.js +273 -0
- package/dist/supabase.test.js.map +1 -0
- package/dist/sync-engine.d.ts +84 -0
- package/dist/sync-engine.d.ts.map +1 -0
- package/dist/sync-engine.js +251 -0
- package/dist/sync-engine.js.map +1 -0
- package/dist/sync-engine.test.d.ts +7 -0
- package/dist/sync-engine.test.d.ts.map +1 -0
- package/dist/sync-engine.test.js +241 -0
- package/dist/sync-engine.test.js.map +1 -0
- package/dist/sync-state.d.ts +82 -0
- package/dist/sync-state.d.ts.map +1 -0
- package/dist/sync-state.js +145 -0
- package/dist/sync-state.js.map +1 -0
- package/dist/sync-state.test.d.ts +7 -0
- package/dist/sync-state.test.d.ts.map +1 -0
- package/dist/sync-state.test.js +129 -0
- package/dist/sync-state.test.js.map +1 -0
- package/dist/types.d.ts +148 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/types.test.d.ts +7 -0
- package/dist/types.test.d.ts.map +1 -0
- package/dist/types.test.js +73 -0
- package/dist/types.test.js.map +1 -0
- package/dist/watcher.d.ts +55 -0
- package/dist/watcher.d.ts.map +1 -0
- package/dist/watcher.js +214 -0
- package/dist/watcher.js.map +1 -0
- package/dist/watcher.test.d.ts +8 -0
- package/dist/watcher.test.d.ts.map +1 -0
- package/dist/watcher.test.js +164 -0
- package/dist/watcher.test.js.map +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote-sync-handler.test.js","sourceRoot":"","sources":["../src/remote-sync-handler.test.ts"],"names":[],"mappings":"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"}
|
package/dist/retry.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exponential backoff retry logic
|
|
3
|
+
*
|
|
4
|
+
* Provides retry functionality with exponential backoff for failed operations.
|
|
5
|
+
* Used for network errors and rate limit recovery.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Retry options
|
|
9
|
+
*/
|
|
10
|
+
export interface RetryOptions {
|
|
11
|
+
/** Maximum number of retry attempts (default: 3) */
|
|
12
|
+
maxAttempts?: number;
|
|
13
|
+
/** Initial delay in milliseconds (default: 1000) */
|
|
14
|
+
initialDelay?: number;
|
|
15
|
+
/** Maximum delay in milliseconds (default: 60000) */
|
|
16
|
+
maxDelay?: number;
|
|
17
|
+
/** Delay multiplier for exponential backoff (default: 2) */
|
|
18
|
+
multiplier?: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Retry a function with exponential backoff
|
|
22
|
+
*
|
|
23
|
+
* Attempts the operation up to maxAttempts times, with exponentially
|
|
24
|
+
* increasing delays between attempts. Delays are capped at maxDelay.
|
|
25
|
+
*
|
|
26
|
+
* Special handling for rate limit errors: uses longer initial delay (5000ms)
|
|
27
|
+
* if error message contains "tenant_events" or "too_many_joins".
|
|
28
|
+
*
|
|
29
|
+
* @param fn - Async function to retry
|
|
30
|
+
* @param options - Retry configuration options
|
|
31
|
+
* @returns Result of successful operation
|
|
32
|
+
* @throws Last error if all attempts fail
|
|
33
|
+
*/
|
|
34
|
+
export declare function retryWithBackoff<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
|
|
35
|
+
//# sourceMappingURL=retry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,oDAAoD;IACpD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,oDAAoD;IACpD,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,4DAA4D;IAC5D,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAUD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,gBAAgB,CAAC,CAAC,EACtC,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC,CAAC,CAAC,CA2CZ"}
|
package/dist/retry.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exponential backoff retry logic
|
|
3
|
+
*
|
|
4
|
+
* Provides retry functionality with exponential backoff for failed operations.
|
|
5
|
+
* Used for network errors and rate limit recovery.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Sleep for specified milliseconds
|
|
9
|
+
* @param ms - Milliseconds to sleep
|
|
10
|
+
*/
|
|
11
|
+
function sleep(ms) {
|
|
12
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Retry a function with exponential backoff
|
|
16
|
+
*
|
|
17
|
+
* Attempts the operation up to maxAttempts times, with exponentially
|
|
18
|
+
* increasing delays between attempts. Delays are capped at maxDelay.
|
|
19
|
+
*
|
|
20
|
+
* Special handling for rate limit errors: uses longer initial delay (5000ms)
|
|
21
|
+
* if error message contains "tenant_events" or "too_many_joins".
|
|
22
|
+
*
|
|
23
|
+
* @param fn - Async function to retry
|
|
24
|
+
* @param options - Retry configuration options
|
|
25
|
+
* @returns Result of successful operation
|
|
26
|
+
* @throws Last error if all attempts fail
|
|
27
|
+
*/
|
|
28
|
+
export async function retryWithBackoff(fn, options) {
|
|
29
|
+
const maxAttempts = options?.maxAttempts ?? 3;
|
|
30
|
+
const initialDelay = options?.initialDelay ?? 1000;
|
|
31
|
+
const maxDelay = options?.maxDelay ?? 60000;
|
|
32
|
+
const multiplier = options?.multiplier ?? 2;
|
|
33
|
+
let delay = initialDelay;
|
|
34
|
+
let lastError;
|
|
35
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
36
|
+
try {
|
|
37
|
+
return await fn();
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
lastError = error;
|
|
41
|
+
// If this was the last attempt, throw the error
|
|
42
|
+
if (attempt === maxAttempts) {
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
// Check for rate limit errors and use longer delay
|
|
46
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
47
|
+
const isRateLimitError = errorMessage.includes('tenant_events') ||
|
|
48
|
+
errorMessage.includes('too_many_joins');
|
|
49
|
+
if (isRateLimitError && attempt === 1) {
|
|
50
|
+
delay = 5000; // Use longer initial delay for rate limit errors
|
|
51
|
+
}
|
|
52
|
+
// Log retry attempt
|
|
53
|
+
console.error(`Retry attempt ${attempt}/${maxAttempts} after ${delay}ms delay`);
|
|
54
|
+
// Wait before retrying
|
|
55
|
+
await sleep(delay);
|
|
56
|
+
// Exponential backoff with cap
|
|
57
|
+
delay = Math.min(delay * multiplier, maxDelay);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// This should never be reached, but TypeScript needs it
|
|
61
|
+
throw lastError;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=retry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.js","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAgBH;;;GAGG;AACH,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAA;AACxD,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,EAAoB,EACpB,OAAsB;IAEtB,MAAM,WAAW,GAAG,OAAO,EAAE,WAAW,IAAI,CAAC,CAAA;IAC7C,MAAM,YAAY,GAAG,OAAO,EAAE,YAAY,IAAI,IAAI,CAAA;IAClD,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,KAAK,CAAA;IAC3C,MAAM,UAAU,GAAG,OAAO,EAAE,UAAU,IAAI,CAAC,CAAA;IAE3C,IAAI,KAAK,GAAG,YAAY,CAAA;IACxB,IAAI,SAAc,CAAA;IAElB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC;QACxD,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,EAAE,CAAA;QACnB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,SAAS,GAAG,KAAK,CAAA;YAEjB,gDAAgD;YAChD,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;gBAC5B,MAAM,KAAK,CAAA;YACb,CAAC;YAED,mDAAmD;YACnD,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YAC3E,MAAM,gBAAgB,GACpB,YAAY,CAAC,QAAQ,CAAC,eAAe,CAAC;gBACtC,YAAY,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAA;YAEzC,IAAI,gBAAgB,IAAI,OAAO,KAAK,CAAC,EAAE,CAAC;gBACtC,KAAK,GAAG,IAAI,CAAA,CAAC,iDAAiD;YAChE,CAAC;YAED,oBAAoB;YACpB,OAAO,CAAC,KAAK,CAAC,iBAAiB,OAAO,IAAI,WAAW,UAAU,KAAK,UAAU,CAAC,CAAA;YAE/E,uBAAuB;YACvB,MAAM,KAAK,CAAC,KAAK,CAAC,CAAA;YAElB,+BAA+B;YAC/B,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,UAAU,EAAE,QAAQ,CAAC,CAAA;QAChD,CAAC;IACH,CAAC;IAED,wDAAwD;IACxD,MAAM,SAAS,CAAA;AACjB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.test.d.ts","sourceRoot":"","sources":["../src/retry.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for exponential backoff retry logic
|
|
3
|
+
*/
|
|
4
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
5
|
+
import { retryWithBackoff } from './retry.js';
|
|
6
|
+
describe('retryWithBackoff', () => {
|
|
7
|
+
it('succeeds on first attempt - no retries', async () => {
|
|
8
|
+
const fn = vi.fn().mockResolvedValue('success');
|
|
9
|
+
const result = await retryWithBackoff(fn);
|
|
10
|
+
expect(result).toBe('success');
|
|
11
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
12
|
+
});
|
|
13
|
+
it('fails twice, succeeds on third - returns result', async () => {
|
|
14
|
+
const fn = vi.fn()
|
|
15
|
+
.mockRejectedValueOnce(new Error('fail 1'))
|
|
16
|
+
.mockRejectedValueOnce(new Error('fail 2'))
|
|
17
|
+
.mockResolvedValueOnce('success');
|
|
18
|
+
const result = await retryWithBackoff(fn, { initialDelay: 10 });
|
|
19
|
+
expect(result).toBe('success');
|
|
20
|
+
expect(fn).toHaveBeenCalledTimes(3);
|
|
21
|
+
});
|
|
22
|
+
it('fails all attempts - throws last error', async () => {
|
|
23
|
+
const fn = vi.fn()
|
|
24
|
+
.mockRejectedValueOnce(new Error('fail 1'))
|
|
25
|
+
.mockRejectedValueOnce(new Error('fail 2'))
|
|
26
|
+
.mockRejectedValueOnce(new Error('fail 3'));
|
|
27
|
+
await expect(retryWithBackoff(fn, { maxAttempts: 3, initialDelay: 10 })).rejects.toThrow('fail 3');
|
|
28
|
+
expect(fn).toHaveBeenCalledTimes(3);
|
|
29
|
+
});
|
|
30
|
+
it('exponential backoff - delays are 1s, 2s, 4s', async () => {
|
|
31
|
+
const fn = vi.fn()
|
|
32
|
+
.mockRejectedValueOnce(new Error('fail 1'))
|
|
33
|
+
.mockRejectedValueOnce(new Error('fail 2'))
|
|
34
|
+
.mockRejectedValueOnce(new Error('fail 3'))
|
|
35
|
+
.mockResolvedValueOnce('success');
|
|
36
|
+
const startTime = Date.now();
|
|
37
|
+
await retryWithBackoff(fn, {
|
|
38
|
+
maxAttempts: 4,
|
|
39
|
+
initialDelay: 100,
|
|
40
|
+
multiplier: 2
|
|
41
|
+
});
|
|
42
|
+
const elapsed = Date.now() - startTime;
|
|
43
|
+
// Should have waited approximately 100 + 200 + 400 = 700ms
|
|
44
|
+
// Allow some tolerance for execution time
|
|
45
|
+
expect(elapsed).toBeGreaterThanOrEqual(600);
|
|
46
|
+
expect(elapsed).toBeLessThan(1000);
|
|
47
|
+
expect(fn).toHaveBeenCalledTimes(4);
|
|
48
|
+
});
|
|
49
|
+
it('max delay cap - delays do not exceed maxDelay', async () => {
|
|
50
|
+
const fn = vi.fn()
|
|
51
|
+
.mockRejectedValueOnce(new Error('fail 1'))
|
|
52
|
+
.mockRejectedValueOnce(new Error('fail 2'))
|
|
53
|
+
.mockRejectedValueOnce(new Error('fail 3'))
|
|
54
|
+
.mockResolvedValueOnce('success');
|
|
55
|
+
const startTime = Date.now();
|
|
56
|
+
await retryWithBackoff(fn, {
|
|
57
|
+
maxAttempts: 4,
|
|
58
|
+
initialDelay: 100,
|
|
59
|
+
maxDelay: 150, // Cap at 150ms
|
|
60
|
+
multiplier: 2
|
|
61
|
+
});
|
|
62
|
+
const elapsed = Date.now() - startTime;
|
|
63
|
+
// Should have waited approximately 100 + 150 + 150 = 400ms (capped)
|
|
64
|
+
// Allow some tolerance for execution time
|
|
65
|
+
expect(elapsed).toBeGreaterThanOrEqual(350);
|
|
66
|
+
expect(elapsed).toBeLessThan(600);
|
|
67
|
+
expect(fn).toHaveBeenCalledTimes(4);
|
|
68
|
+
});
|
|
69
|
+
it('rate limit error uses longer initial delay', async () => {
|
|
70
|
+
const fn = vi.fn()
|
|
71
|
+
.mockRejectedValueOnce(new Error('tenant_events rate limit'))
|
|
72
|
+
.mockResolvedValueOnce('success');
|
|
73
|
+
const startTime = Date.now();
|
|
74
|
+
await retryWithBackoff(fn, {
|
|
75
|
+
maxAttempts: 2,
|
|
76
|
+
initialDelay: 100 // Will be overridden to 5000ms for rate limit
|
|
77
|
+
});
|
|
78
|
+
const elapsed = Date.now() - startTime;
|
|
79
|
+
// Should have waited approximately 5000ms for rate limit error
|
|
80
|
+
expect(elapsed).toBeGreaterThanOrEqual(4900);
|
|
81
|
+
expect(fn).toHaveBeenCalledTimes(2);
|
|
82
|
+
}, 10000);
|
|
83
|
+
});
|
|
84
|
+
//# sourceMappingURL=retry.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.test.js","sourceRoot":"","sources":["../src/retry.test.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAE7C,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;QACtD,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAA;QAE/C,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,EAAE,CAAC,CAAA;QAEzC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QAC9B,MAAM,CAAC,EAAE,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAA;IACrC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;QAC/D,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE;aACf,qBAAqB,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC;aAC1C,qBAAqB,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC;aAC1C,qBAAqB,CAAC,SAAS,CAAC,CAAA;QAEnC,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,CAAA;QAE/D,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QAC9B,MAAM,CAAC,EAAE,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAA;IACrC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;QACtD,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE;aACf,qBAAqB,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC;aAC1C,qBAAqB,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC;aAC1C,qBAAqB,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAA;QAE7C,MAAM,MAAM,CACV,gBAAgB,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,CAAC,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,CAC3D,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;QAE3B,MAAM,CAAC,EAAE,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAA;IACrC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE;aACf,qBAAqB,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC;aAC1C,qBAAqB,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC;aAC1C,qBAAqB,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC;aAC1C,qBAAqB,CAAC,SAAS,CAAC,CAAA;QAEnC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QAE5B,MAAM,gBAAgB,CAAC,EAAE,EAAE;YACzB,WAAW,EAAE,CAAC;YACd,YAAY,EAAE,GAAG;YACjB,UAAU,EAAE,CAAC;SACd,CAAC,CAAA;QAEF,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAA;QAEtC,2DAA2D;QAC3D,0CAA0C;QAC1C,MAAM,CAAC,OAAO,CAAC,CAAC,sBAAsB,CAAC,GAAG,CAAC,CAAA;QAC3C,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAA;QAClC,MAAM,CAAC,EAAE,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAA;IACrC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC7D,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE;aACf,qBAAqB,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC;aAC1C,qBAAqB,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC;aAC1C,qBAAqB,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC;aAC1C,qBAAqB,CAAC,SAAS,CAAC,CAAA;QAEnC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QAE5B,MAAM,gBAAgB,CAAC,EAAE,EAAE;YACzB,WAAW,EAAE,CAAC;YACd,YAAY,EAAE,GAAG;YACjB,QAAQ,EAAE,GAAG,EAAE,eAAe;YAC9B,UAAU,EAAE,CAAC;SACd,CAAC,CAAA;QAEF,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAA;QAEtC,oEAAoE;QACpE,0CAA0C;QAC1C,MAAM,CAAC,OAAO,CAAC,CAAC,sBAAsB,CAAC,GAAG,CAAC,CAAA;QAC3C,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAA;QACjC,MAAM,CAAC,EAAE,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAA;IACrC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC1D,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE;aACf,qBAAqB,CAAC,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;aAC5D,qBAAqB,CAAC,SAAS,CAAC,CAAA;QAEnC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QAE5B,MAAM,gBAAgB,CAAC,EAAE,EAAE;YACzB,WAAW,EAAE,CAAC;YACd,YAAY,EAAE,GAAG,CAAC,8CAA8C;SACjE,CAAC,CAAA;QAEF,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAA;QAEtC,+DAA+D;QAC/D,MAAM,CAAC,OAAO,CAAC,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAA;QAC5C,MAAM,CAAC,EAAE,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAA;IACrC,CAAC,EAAE,KAAK,CAAC,CAAA;AACX,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Supabase Storage client for large file operations
|
|
3
|
+
*
|
|
4
|
+
* Handles upload, download, and deletion of files larger than 200KB.
|
|
5
|
+
* Files are stored in the 'gsd-files' bucket with workspace_id/file_path keys.
|
|
6
|
+
*/
|
|
7
|
+
import type { SupabaseClient as SupabaseJsClient } from '@supabase/supabase-js';
|
|
8
|
+
import type { Logger } from './logger.js';
|
|
9
|
+
/**
|
|
10
|
+
* Operation result with optional storage URL or content
|
|
11
|
+
*/
|
|
12
|
+
export interface StorageOperationResult {
|
|
13
|
+
success: boolean;
|
|
14
|
+
error?: string;
|
|
15
|
+
storage_url?: string;
|
|
16
|
+
content?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Storage client for large file operations
|
|
20
|
+
*/
|
|
21
|
+
export declare class StorageClient {
|
|
22
|
+
private client;
|
|
23
|
+
private logger;
|
|
24
|
+
private bucketName;
|
|
25
|
+
constructor(client: SupabaseJsClient, logger: Logger);
|
|
26
|
+
/**
|
|
27
|
+
* Upload file to Supabase Storage
|
|
28
|
+
* @param workspace_id - Workspace identifier
|
|
29
|
+
* @param file_path - File path relative to workspace root
|
|
30
|
+
* @param content - File content as string
|
|
31
|
+
* @returns Operation result with storage URL
|
|
32
|
+
*/
|
|
33
|
+
uploadFile(workspace_id: string, file_path: string, content: string): Promise<StorageOperationResult>;
|
|
34
|
+
/**
|
|
35
|
+
* Download file from Supabase Storage
|
|
36
|
+
* @param storage_url - Storage URL to download from
|
|
37
|
+
* @returns Operation result with file content
|
|
38
|
+
*/
|
|
39
|
+
downloadFile(storage_url: string): Promise<StorageOperationResult>;
|
|
40
|
+
/**
|
|
41
|
+
* Delete file from Supabase Storage
|
|
42
|
+
* @param workspace_id - Workspace identifier
|
|
43
|
+
* @param file_path - File path relative to workspace root
|
|
44
|
+
* @returns Operation result
|
|
45
|
+
*/
|
|
46
|
+
deleteFile(workspace_id: string, file_path: string): Promise<StorageOperationResult>;
|
|
47
|
+
/**
|
|
48
|
+
* Get bucket information for debugging
|
|
49
|
+
* @returns Bucket name and policy info
|
|
50
|
+
*/
|
|
51
|
+
getBucketInfo(): {
|
|
52
|
+
bucketName: string;
|
|
53
|
+
policy: string;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Extract storage key from storage URL
|
|
57
|
+
* @param storage_url - Full storage URL
|
|
58
|
+
* @returns Storage key (workspace_id/file_path) or null if invalid
|
|
59
|
+
*/
|
|
60
|
+
private extractStorageKey;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Factory function to create StorageClient
|
|
64
|
+
* @param client - Supabase JS client
|
|
65
|
+
* @param logger - Logger instance
|
|
66
|
+
* @returns StorageClient instance
|
|
67
|
+
*/
|
|
68
|
+
export declare function createStorageClient(client: SupabaseJsClient, logger: Logger): StorageClient;
|
|
69
|
+
//# sourceMappingURL=storage-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage-client.d.ts","sourceRoot":"","sources":["../src/storage-client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,IAAI,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAC/E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,UAAU,CAAc;gBAEpB,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM;IAKpD;;;;;;OAMG;IACG,UAAU,CACd,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,sBAAsB,CAAC;IAyClC;;;;OAIG;IACG,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC;IA0CxE;;;;;OAKG;IACG,UAAU,CACd,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,sBAAsB,CAAC;IA6BlC;;;OAGG;IACH,aAAa,IAAI;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE;IAOvD;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;CAS1B;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,MAAM,GACb,aAAa,CAEf"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Supabase Storage client for large file operations
|
|
3
|
+
*
|
|
4
|
+
* Handles upload, download, and deletion of files larger than 200KB.
|
|
5
|
+
* Files are stored in the 'gsd-files' bucket with workspace_id/file_path keys.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Storage client for large file operations
|
|
9
|
+
*/
|
|
10
|
+
export class StorageClient {
|
|
11
|
+
client;
|
|
12
|
+
logger;
|
|
13
|
+
bucketName = 'gsd-files';
|
|
14
|
+
constructor(client, logger) {
|
|
15
|
+
this.client = client;
|
|
16
|
+
this.logger = logger;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Upload file to Supabase Storage
|
|
20
|
+
* @param workspace_id - Workspace identifier
|
|
21
|
+
* @param file_path - File path relative to workspace root
|
|
22
|
+
* @param content - File content as string
|
|
23
|
+
* @returns Operation result with storage URL
|
|
24
|
+
*/
|
|
25
|
+
async uploadFile(workspace_id, file_path, content) {
|
|
26
|
+
try {
|
|
27
|
+
// Build storage key: workspace_id/file_path
|
|
28
|
+
const storageKey = `${workspace_id}/${file_path}`;
|
|
29
|
+
// Upload to Storage bucket
|
|
30
|
+
const { data, error } = await this.client.storage
|
|
31
|
+
.from(this.bucketName)
|
|
32
|
+
.upload(storageKey, content, {
|
|
33
|
+
contentType: 'text/plain',
|
|
34
|
+
upsert: true
|
|
35
|
+
});
|
|
36
|
+
if (error) {
|
|
37
|
+
const message = `Failed to upload file to Storage: ${error.message}`;
|
|
38
|
+
this.logger.error(message, { workspace_id, file_path, error });
|
|
39
|
+
return { success: false, error: message };
|
|
40
|
+
}
|
|
41
|
+
// Get public URL for the uploaded file
|
|
42
|
+
const { data: urlData } = this.client.storage
|
|
43
|
+
.from(this.bucketName)
|
|
44
|
+
.getPublicUrl(storageKey);
|
|
45
|
+
this.logger.debug('Uploaded file to Storage', {
|
|
46
|
+
workspace_id,
|
|
47
|
+
file_path,
|
|
48
|
+
storage_url: urlData.publicUrl
|
|
49
|
+
});
|
|
50
|
+
return {
|
|
51
|
+
success: true,
|
|
52
|
+
storage_url: urlData.publicUrl
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
const message = `Failed to upload file to Storage: ${error}`;
|
|
57
|
+
this.logger.error(message, { workspace_id, file_path, error });
|
|
58
|
+
return { success: false, error: message };
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Download file from Supabase Storage
|
|
63
|
+
* @param storage_url - Storage URL to download from
|
|
64
|
+
* @returns Operation result with file content
|
|
65
|
+
*/
|
|
66
|
+
async downloadFile(storage_url) {
|
|
67
|
+
try {
|
|
68
|
+
// Extract storage key from URL
|
|
69
|
+
// URL format: https://[project].supabase.co/storage/v1/object/public/gsd-files/workspace-id/file-path
|
|
70
|
+
const storageKey = this.extractStorageKey(storage_url);
|
|
71
|
+
if (!storageKey) {
|
|
72
|
+
const message = `Invalid storage URL format: ${storage_url}`;
|
|
73
|
+
this.logger.error(message, { storage_url });
|
|
74
|
+
return { success: false, error: message };
|
|
75
|
+
}
|
|
76
|
+
// Download from Storage
|
|
77
|
+
const { data, error } = await this.client.storage
|
|
78
|
+
.from(this.bucketName)
|
|
79
|
+
.download(storageKey);
|
|
80
|
+
if (error) {
|
|
81
|
+
const message = `Failed to download file from Storage: ${error.message}`;
|
|
82
|
+
this.logger.error(message, { storage_url, error });
|
|
83
|
+
return { success: false, error: message };
|
|
84
|
+
}
|
|
85
|
+
// Convert Blob to string
|
|
86
|
+
const content = await data.text();
|
|
87
|
+
this.logger.debug('Downloaded file from Storage', {
|
|
88
|
+
storage_url,
|
|
89
|
+
size: content.length
|
|
90
|
+
});
|
|
91
|
+
return {
|
|
92
|
+
success: true,
|
|
93
|
+
content
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
const message = `Failed to download file from Storage: ${error}`;
|
|
98
|
+
this.logger.error(message, { storage_url, error });
|
|
99
|
+
return { success: false, error: message };
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Delete file from Supabase Storage
|
|
104
|
+
* @param workspace_id - Workspace identifier
|
|
105
|
+
* @param file_path - File path relative to workspace root
|
|
106
|
+
* @returns Operation result
|
|
107
|
+
*/
|
|
108
|
+
async deleteFile(workspace_id, file_path) {
|
|
109
|
+
try {
|
|
110
|
+
// Build storage key: workspace_id/file_path
|
|
111
|
+
const storageKey = `${workspace_id}/${file_path}`;
|
|
112
|
+
// Remove from Storage bucket
|
|
113
|
+
const { error } = await this.client.storage
|
|
114
|
+
.from(this.bucketName)
|
|
115
|
+
.remove([storageKey]);
|
|
116
|
+
if (error) {
|
|
117
|
+
const message = `Failed to delete file from Storage: ${error.message}`;
|
|
118
|
+
this.logger.error(message, { workspace_id, file_path, error });
|
|
119
|
+
return { success: false, error: message };
|
|
120
|
+
}
|
|
121
|
+
this.logger.debug('Deleted file from Storage', {
|
|
122
|
+
workspace_id,
|
|
123
|
+
file_path
|
|
124
|
+
});
|
|
125
|
+
return { success: true };
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
const message = `Failed to delete file from Storage: ${error}`;
|
|
129
|
+
this.logger.error(message, { workspace_id, file_path, error });
|
|
130
|
+
return { success: false, error: message };
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Get bucket information for debugging
|
|
135
|
+
* @returns Bucket name and policy info
|
|
136
|
+
*/
|
|
137
|
+
getBucketInfo() {
|
|
138
|
+
return {
|
|
139
|
+
bucketName: this.bucketName,
|
|
140
|
+
policy: 'RLS policy restricts access to workspace owners (configured in Supabase dashboard)'
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Extract storage key from storage URL
|
|
145
|
+
* @param storage_url - Full storage URL
|
|
146
|
+
* @returns Storage key (workspace_id/file_path) or null if invalid
|
|
147
|
+
*/
|
|
148
|
+
extractStorageKey(storage_url) {
|
|
149
|
+
try {
|
|
150
|
+
// Match pattern: .../gsd-files/workspace-id/file-path
|
|
151
|
+
const match = storage_url.match(/\/gsd-files\/(.+)$/);
|
|
152
|
+
return match ? match[1] : null;
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Factory function to create StorageClient
|
|
161
|
+
* @param client - Supabase JS client
|
|
162
|
+
* @param logger - Logger instance
|
|
163
|
+
* @returns StorageClient instance
|
|
164
|
+
*/
|
|
165
|
+
export function createStorageClient(client, logger) {
|
|
166
|
+
return new StorageClient(client, logger);
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=storage-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage-client.js","sourceRoot":"","sources":["../src/storage-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage-client.test.d.ts","sourceRoot":"","sources":["../src/storage-client.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for StorageClient
|
|
3
|
+
*
|
|
4
|
+
* Covers upload, download, and delete operations for large files in Supabase Storage.
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
7
|
+
import { createStorageClient } from './storage-client.js';
|
|
8
|
+
describe('StorageClient', () => {
|
|
9
|
+
let mockSupabaseClient;
|
|
10
|
+
let mockLogger;
|
|
11
|
+
let storageClient;
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
// Mock Supabase Storage API
|
|
14
|
+
mockSupabaseClient = {
|
|
15
|
+
storage: {
|
|
16
|
+
from: vi.fn().mockReturnValue({
|
|
17
|
+
upload: vi.fn(),
|
|
18
|
+
download: vi.fn(),
|
|
19
|
+
remove: vi.fn(),
|
|
20
|
+
getPublicUrl: vi.fn()
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
// Mock logger
|
|
25
|
+
mockLogger = {
|
|
26
|
+
error: vi.fn(),
|
|
27
|
+
warn: vi.fn(),
|
|
28
|
+
info: vi.fn(),
|
|
29
|
+
debug: vi.fn()
|
|
30
|
+
};
|
|
31
|
+
storageClient = createStorageClient(mockSupabaseClient, mockLogger);
|
|
32
|
+
});
|
|
33
|
+
describe('uploadFile', () => {
|
|
34
|
+
it('should upload content to gsd-files bucket with workspace_id/file_path key', async () => {
|
|
35
|
+
const workspace_id = 'workspace-123';
|
|
36
|
+
const file_path = '.planning/STATE.md';
|
|
37
|
+
const content = 'test content';
|
|
38
|
+
const mockBucket = mockSupabaseClient.storage.from();
|
|
39
|
+
mockBucket.upload.mockResolvedValue({ data: { path: 'workspace-123/.planning/STATE.md' }, error: null });
|
|
40
|
+
mockBucket.getPublicUrl.mockReturnValue({ data: { publicUrl: 'https://storage.example.com/workspace-123/.planning/STATE.md' } });
|
|
41
|
+
const result = await storageClient.uploadFile(workspace_id, file_path, content);
|
|
42
|
+
expect(mockSupabaseClient.storage.from).toHaveBeenCalledWith('gsd-files');
|
|
43
|
+
expect(mockBucket.upload).toHaveBeenCalledWith('workspace-123/.planning/STATE.md', content, { contentType: 'text/plain', upsert: true });
|
|
44
|
+
expect(result.success).toBe(true);
|
|
45
|
+
});
|
|
46
|
+
it('should return storage URL on success', async () => {
|
|
47
|
+
const workspace_id = 'workspace-123';
|
|
48
|
+
const file_path = '.planning/STATE.md';
|
|
49
|
+
const content = 'test content';
|
|
50
|
+
const expectedUrl = 'https://storage.example.com/workspace-123/.planning/STATE.md';
|
|
51
|
+
const mockBucket = mockSupabaseClient.storage.from();
|
|
52
|
+
mockBucket.upload.mockResolvedValue({ data: { path: 'workspace-123/.planning/STATE.md' }, error: null });
|
|
53
|
+
mockBucket.getPublicUrl.mockReturnValue({ data: { publicUrl: expectedUrl } });
|
|
54
|
+
const result = await storageClient.uploadFile(workspace_id, file_path, content);
|
|
55
|
+
expect(result.success).toBe(true);
|
|
56
|
+
expect(result.storage_url).toBe(expectedUrl);
|
|
57
|
+
});
|
|
58
|
+
it('should return error on upload failure', async () => {
|
|
59
|
+
const workspace_id = 'workspace-123';
|
|
60
|
+
const file_path = '.planning/STATE.md';
|
|
61
|
+
const content = 'test content';
|
|
62
|
+
const mockBucket = mockSupabaseClient.storage.from();
|
|
63
|
+
mockBucket.upload.mockResolvedValue({ data: null, error: { message: 'Upload failed' } });
|
|
64
|
+
const result = await storageClient.uploadFile(workspace_id, file_path, content);
|
|
65
|
+
expect(result.success).toBe(false);
|
|
66
|
+
expect(result.error).toContain('Upload failed');
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
describe('downloadFile', () => {
|
|
70
|
+
it('should fetch content from storage URL', async () => {
|
|
71
|
+
const storage_url = 'https://storage.example.com/gsd-files/workspace-123/.planning/STATE.md';
|
|
72
|
+
const expectedContent = 'downloaded content';
|
|
73
|
+
const mockBucket = mockSupabaseClient.storage.from();
|
|
74
|
+
const mockBlob = {
|
|
75
|
+
text: vi.fn().mockResolvedValue(expectedContent)
|
|
76
|
+
};
|
|
77
|
+
mockBucket.download.mockResolvedValue({ data: mockBlob, error: null });
|
|
78
|
+
const result = await storageClient.downloadFile(storage_url);
|
|
79
|
+
expect(mockSupabaseClient.storage.from).toHaveBeenCalledWith('gsd-files');
|
|
80
|
+
expect(mockBucket.download).toHaveBeenCalledWith('workspace-123/.planning/STATE.md');
|
|
81
|
+
expect(result.success).toBe(true);
|
|
82
|
+
});
|
|
83
|
+
it('should return file content as string', async () => {
|
|
84
|
+
const storage_url = 'https://storage.example.com/gsd-files/workspace-123/.planning/STATE.md';
|
|
85
|
+
const expectedContent = 'downloaded content';
|
|
86
|
+
const mockBucket = mockSupabaseClient.storage.from();
|
|
87
|
+
const mockBlob = {
|
|
88
|
+
text: vi.fn().mockResolvedValue(expectedContent)
|
|
89
|
+
};
|
|
90
|
+
mockBucket.download.mockResolvedValue({ data: mockBlob, error: null });
|
|
91
|
+
const result = await storageClient.downloadFile(storage_url);
|
|
92
|
+
expect(result.success).toBe(true);
|
|
93
|
+
expect(result.content).toBe(expectedContent);
|
|
94
|
+
});
|
|
95
|
+
it('should return error on download failure', async () => {
|
|
96
|
+
const storage_url = 'https://storage.example.com/gsd-files/workspace-123/.planning/STATE.md';
|
|
97
|
+
const mockBucket = mockSupabaseClient.storage.from();
|
|
98
|
+
mockBucket.download.mockResolvedValue({ data: null, error: { message: 'Download failed' } });
|
|
99
|
+
const result = await storageClient.downloadFile(storage_url);
|
|
100
|
+
expect(result.success).toBe(false);
|
|
101
|
+
expect(result.error).toContain('Download failed');
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
describe('deleteFile', () => {
|
|
105
|
+
it('should remove file from storage bucket', async () => {
|
|
106
|
+
const workspace_id = 'workspace-123';
|
|
107
|
+
const file_path = '.planning/STATE.md';
|
|
108
|
+
const mockBucket = mockSupabaseClient.storage.from();
|
|
109
|
+
mockBucket.remove.mockResolvedValue({ data: [{ name: 'workspace-123/.planning/STATE.md' }], error: null });
|
|
110
|
+
const result = await storageClient.deleteFile(workspace_id, file_path);
|
|
111
|
+
expect(mockSupabaseClient.storage.from).toHaveBeenCalledWith('gsd-files');
|
|
112
|
+
expect(mockBucket.remove).toHaveBeenCalledWith(['workspace-123/.planning/STATE.md']);
|
|
113
|
+
expect(result.success).toBe(true);
|
|
114
|
+
});
|
|
115
|
+
it('should return error on delete failure', async () => {
|
|
116
|
+
const workspace_id = 'workspace-123';
|
|
117
|
+
const file_path = '.planning/STATE.md';
|
|
118
|
+
const mockBucket = mockSupabaseClient.storage.from();
|
|
119
|
+
mockBucket.remove.mockResolvedValue({ data: null, error: { message: 'Delete failed' } });
|
|
120
|
+
const result = await storageClient.deleteFile(workspace_id, file_path);
|
|
121
|
+
expect(result.success).toBe(false);
|
|
122
|
+
expect(result.error).toContain('Delete failed');
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
//# sourceMappingURL=storage-client.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage-client.test.js","sourceRoot":"","sources":["../src/storage-client.test.ts"],"names":[],"mappings":"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"}
|