@pixpilot/supabase-functions-client 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Pixpilot
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,363 @@
1
+ # @pixpilot/supabase-functions-client
2
+
3
+ A lightweight, type-safe wrapper around the Supabase Edge Functions client with structured error handling, automatic error message extraction, and chainable response helpers.
4
+
5
+ ---
6
+
7
+ ## Installation
8
+
9
+ ```sh
10
+ pnpm add @pixpilot/supabase-functions-client @supabase/supabase-js
11
+ ```
12
+
13
+ ---
14
+
15
+ ## Quick Start
16
+
17
+ ```typescript
18
+ import { FunctionsClient } from '@pixpilot/supabase-functions-client';
19
+ import { createClient } from '@supabase/supabase-js';
20
+
21
+ const supabase = createClient('https://your-project.supabase.co', 'your-anon-key');
22
+
23
+ // Wrap the Supabase client once
24
+ const functionsClient = new FunctionsClient(supabase);
25
+ ```
26
+
27
+ ---
28
+
29
+ ## API
30
+
31
+ ### `FunctionsClient`
32
+
33
+ ```typescript
34
+ class FunctionsClient {
35
+ constructor(supabaseClient: SupabaseClient);
36
+
37
+ invoke<RequestBody = void, ResponseData = any>(
38
+ functionName: string,
39
+ options?: FunctionInvokeOptions<RequestBody>,
40
+ ): Promise<ResponseData>;
41
+
42
+ handleInvoke<T>(
43
+ invokeCall: () => Promise<T>,
44
+ onSuccess: (data: T) => Promise<void> | void,
45
+ onError: (error: EdgeFunctionError) => Promise<void> | void,
46
+ context?: string,
47
+ ): Promise<void>;
48
+
49
+ /** @deprecated Use handleInvoke instead. */
50
+ handleResponse<T>(
51
+ result: FunctionsResponse<T>,
52
+ onSuccess: (data: T) => Promise<void> | void,
53
+ onError: (error: string, code?: string, details?: unknown) => Promise<void> | void,
54
+ context?: string,
55
+ ): Promise<void>;
56
+ }
57
+ ```
58
+
59
+ ---
60
+
61
+ ## Usage Patterns
62
+
63
+ ### 1. `invoke` – Direct Try/Catch (Recommended)
64
+
65
+ `invoke` either returns data on success or **throws** an `EdgeFunctionError`
66
+ (or `EdgeFunctionNoDataError`) on failure.
67
+
68
+ ```typescript
69
+ import {
70
+ EdgeFunctionError,
71
+ EdgeFunctionNoDataError,
72
+ FunctionsClient,
73
+ } from '@pixpilot/supabase-functions-client';
74
+
75
+ interface ProcessJobRequest {
76
+ jobContent: string;
77
+ jobUrl: string;
78
+ }
79
+
80
+ interface ProcessJobResponse {
81
+ jobId: string;
82
+ status: string;
83
+ }
84
+
85
+ try {
86
+ /*
87
+ * RequestBody type is inferred, ResponseData is explicit.
88
+ * Because ProcessJobRequest has required properties, `body` is required
89
+ * in the second argument – TypeScript will enforce this.
90
+ */
91
+ const job = await functionsClient.invoke<ProcessJobRequest, ProcessJobResponse>(
92
+ 'process-job',
93
+ { body: { jobContent: htmlContent, jobUrl: url } },
94
+ );
95
+
96
+ console.log('Job created:', job.jobId);
97
+ } catch (error) {
98
+ if (error instanceof EdgeFunctionNoDataError) {
99
+ console.error('Function returned no data for:', error.functionName);
100
+ } else if (error instanceof EdgeFunctionError) {
101
+ console.error('Function failed:', error.message);
102
+ if (error.code) console.error('Error code:', error.code);
103
+ if (error.details) console.error('Details:', error.details);
104
+ } else {
105
+ throw error; // Re-throw unexpected errors
106
+ }
107
+ }
108
+ ```
109
+
110
+ #### Void body (no request body)
111
+
112
+ When `RequestBody` is `void` or omitted, the options argument is optional and
113
+ `body` is not allowed:
114
+
115
+ ```typescript
116
+ interface HealthCheckResponse {
117
+ status: 'ok' | 'degraded';
118
+ timestamp: string;
119
+ }
120
+
121
+ // No second argument needed
122
+ const health = await functionsClient.invoke<void, HealthCheckResponse>('health-check');
123
+ console.log('Status:', health.status);
124
+ ```
125
+
126
+ #### All-optional body
127
+
128
+ When every property of `RequestBody` is optional, the options argument is also
129
+ optional:
130
+
131
+ ```typescript
132
+ interface SearchRequest {
133
+ query?: string;
134
+ limit?: number;
135
+ }
136
+
137
+ interface SearchResponse {
138
+ results: string[];
139
+ }
140
+
141
+ // Can omit options entirely
142
+ const results = await functionsClient.invoke<SearchRequest, SearchResponse>('search');
143
+
144
+ // Or pass a partial body
145
+ const filtered = await functionsClient.invoke<SearchRequest, SearchResponse>('search', {
146
+ body: { query: 'typescript', limit: 10 },
147
+ });
148
+ ```
149
+
150
+ ---
151
+
152
+ ### 2. `handleInvoke` – Callback Pattern
153
+
154
+ Use `handleInvoke` when you want clean success/error callbacks without a
155
+ try/catch block. Uncaught non-`EdgeFunctionError` exceptions are re-thrown.
156
+
157
+ ```typescript
158
+ await functionsClient.handleInvoke(
159
+ // The function call
160
+ () =>
161
+ functionsClient.invoke<ProcessJobRequest, ProcessJobResponse>('process-job', {
162
+ body: { jobContent: htmlContent, jobUrl: url },
163
+ }),
164
+
165
+ // Success handler
166
+ (job) => {
167
+ console.log('Job created:', job.jobId);
168
+ showSuccessNotification(job);
169
+ },
170
+
171
+ // Error handler – receives an EdgeFunctionError
172
+ (error) => {
173
+ console.error('Function failed:', error.message);
174
+ if (error.code === 'QUOTA_EXCEEDED') {
175
+ showQuotaWarning();
176
+ } else {
177
+ showErrorNotification(error.message);
178
+ }
179
+ },
180
+
181
+ // Optional context label – included in log output
182
+ 'Process Job',
183
+ );
184
+ ```
185
+
186
+ ---
187
+
188
+ ### 3. `handleResponse` – Legacy Callback Pattern _(deprecated)_
189
+
190
+ This method takes a `FunctionsResponse` object (the old `{data, error}` shape)
191
+ and dispatches to one of two callbacks. Prefer `handleInvoke` for new code.
192
+
193
+ ```typescript
194
+ const result: FunctionsResponse<ProcessJobResponse> = {
195
+ data: { jobId: '123', status: 'pending' },
196
+ error: null,
197
+ };
198
+
199
+ await functionsClient.handleResponse(
200
+ result,
201
+ // onSuccess
202
+ (job) => {
203
+ console.log('Job created:', job.jobId);
204
+ },
205
+ // onError
206
+ (errorMessage, errorCode, details) => {
207
+ console.error('Function failed:', errorMessage);
208
+ if (errorCode) console.error('Error code:', errorCode);
209
+ },
210
+ );
211
+ ```
212
+
213
+ ---
214
+
215
+ ## Error Classes
216
+
217
+ ### `EdgeFunctionError`
218
+
219
+ The base error class for all Edge Function failures.
220
+
221
+ ```typescript
222
+ class EdgeFunctionError extends Error {
223
+ /** Name of the Edge Function that failed */
224
+ readonly functionName: string;
225
+
226
+ /** Optional machine-readable error code from the function response */
227
+ readonly code?: string;
228
+
229
+ /** Additional structured details from the function response */
230
+ readonly details?: unknown;
231
+ }
232
+ ```
233
+
234
+ ### `EdgeFunctionNoDataError`
235
+
236
+ Extends `EdgeFunctionError`. Thrown when the function call succeeds (HTTP 2xx)
237
+ but returns no data.
238
+
239
+ ```typescript
240
+ class EdgeFunctionNoDataError extends EdgeFunctionError {
241
+ // message: 'No data received from Edge Function.'
242
+ }
243
+ ```
244
+
245
+ ### `instanceof` Checks
246
+
247
+ ```typescript
248
+ import {
249
+ EdgeFunctionError,
250
+ EdgeFunctionNoDataError,
251
+ } from '@pixpilot/supabase-functions-client';
252
+
253
+ try {
254
+ const data = await functionsClient.invoke('my-function');
255
+ } catch (error) {
256
+ if (error instanceof EdgeFunctionNoDataError) {
257
+ // Successful HTTP call but empty body
258
+ console.log('No data from:', error.functionName);
259
+ } else if (error instanceof EdgeFunctionError) {
260
+ // HTTP error OR network error
261
+ console.log(`${error.functionName} failed: ${error.message}`);
262
+ if (error.code) console.log('Code:', error.code);
263
+ }
264
+ }
265
+ ```
266
+
267
+ ---
268
+
269
+ ## Automatic Error Message Extraction
270
+
271
+ When an Edge Function returns a non-2xx response, the client automatically
272
+ parses the JSON body and extracts the human-readable message. The resolution
273
+ order is:
274
+
275
+ 1. `body.error` field
276
+ 2. `body.message` field
277
+ 3. HTTP error message (fallback)
278
+
279
+ Edge Functions should return a structured error body:
280
+
281
+ ```typescript
282
+ // From your Edge Function (Deno / Node):
283
+ return new Response(
284
+ JSON.stringify({
285
+ error: 'User not found', // → EdgeFunctionError.message
286
+ code: 'USER_NOT_FOUND', // → EdgeFunctionError.code
287
+ details: { userId: 123 }, // → EdgeFunctionError.details
288
+ }),
289
+ { status: 404, headers: { 'Content-Type': 'application/json' } },
290
+ );
291
+ ```
292
+
293
+ ---
294
+
295
+ ## Nested `ApiResponse` Unwrapping
296
+
297
+ If your Edge Function wraps data in a `{ data, message }` envelope, the client
298
+ automatically unwraps it:
299
+
300
+ ```typescript
301
+ // Edge Function returns:
302
+ // { data: { jobId: '123' }, message: 'Success' }
303
+
304
+ // invoke() returns the inner data directly:
305
+ const job = await functionsClient.invoke<void, ProcessJobResponse>('process-job');
306
+ // job === { jobId: '123' }
307
+ ```
308
+
309
+ ---
310
+
311
+ ## Exported Types
312
+
313
+ | Type | Description |
314
+ | ------------------------------------ | ---------------------------------------------------------------------- |
315
+ | `EdgeFunctionErrorResponse` | Shape of the error JSON returned by Edge Functions |
316
+ | `FunctionsResponse<T>` | Legacy `{ data, error, code, details }` response envelope |
317
+ | `FunctionInvokeOptions<RequestBody>` | Options passed to `invoke()`, body requirement adapts to `RequestBody` |
318
+ | `InvokeOptions<RequestBody>` | Determines whether options are required or optional |
319
+ | `RequiredKeys<T>` | Utility: extracts required keys from a type |
320
+ | `HasRequiredProperties<T>` | Utility: `true` if `T` has at least one required key |
321
+
322
+ ---
323
+
324
+ ## Migration from Direct `supabase.functions.invoke`
325
+
326
+ **Before:**
327
+
328
+ ```typescript
329
+ const result = await supabase.functions.invoke<ProcessJobResponse>('process-job', {
330
+ body: { jobContent, jobUrl },
331
+ });
332
+
333
+ if (result.error) {
334
+ if (result.error instanceof FunctionsHttpError) {
335
+ // Manual JSON parsing, error code extraction...
336
+ }
337
+ return null;
338
+ }
339
+
340
+ return result.data ?? undefined;
341
+ ```
342
+
343
+ **After:**
344
+
345
+ ```typescript
346
+ try {
347
+ return await functionsClient.invoke<ProcessJobRequest, ProcessJobResponse>(
348
+ 'process-job',
349
+ { body: { jobContent, jobUrl } },
350
+ );
351
+ } catch (error) {
352
+ if (error instanceof EdgeFunctionError) {
353
+ console.error('Failed:', error.message, error.code);
354
+ }
355
+ return null;
356
+ }
357
+ ```
358
+
359
+ ---
360
+
361
+ ## License
362
+
363
+ MIT
@@ -0,0 +1,71 @@
1
+ import type { SupabaseClient } from '@supabase/supabase-js';
2
+ import type { FunctionInvokeOptions, FunctionsResponse, RequiredKeys } from './types';
3
+ /**
4
+ * Custom error class for Edge Function errors
5
+ * Allows for instanceof checks and provides structured error information
6
+ */
7
+ export declare class EdgeFunctionError extends Error {
8
+ readonly code?: string | undefined;
9
+ readonly details?: unknown;
10
+ readonly functionName: string;
11
+ constructor(message: string, functionName: string, code?: string, details?: unknown);
12
+ }
13
+ /**
14
+ * Error thrown when Edge Function returns no data
15
+ */
16
+ export declare class EdgeFunctionNoDataError extends EdgeFunctionError {
17
+ constructor(functionName: string);
18
+ }
19
+ /**
20
+ * Enhanced Supabase Functions client with better error handling
21
+ * Provides a wrapper around Supabase Edge Functions with:
22
+ * - Automatic custom error message extraction
23
+ * - Type-safe responses
24
+ * - Consistent error handling
25
+ * - Generic typing support
26
+ */
27
+ export declare class FunctionsClient {
28
+ private supabase;
29
+ constructor(supabaseClient: SupabaseClient);
30
+ /**
31
+ * Invoke a Supabase Edge Function with enhanced error handling
32
+ * Throws EdgeFunctionError on failure, returns data on success
33
+ *
34
+ * @param functionName - The name of the Edge Function to invoke
35
+ * @param args - Function invocation options (optional if RequestBody has no required properties)
36
+ * @returns Promise<ResponseData> - The response data on success
37
+ * @throws {EdgeFunctionError} When the function fails or returns an error
38
+ * @throws {EdgeFunctionNoDataError} When the function succeeds but returns no data
39
+ */
40
+ invoke<RequestBody = void, ResponseData = any>(functionName: string, ...args: RequiredKeys<RequestBody> extends never ? [options?: FunctionInvokeOptions<RequestBody>] : [options: FunctionInvokeOptions<RequestBody>]): Promise<ResponseData>;
41
+ /**
42
+ * Helper method for handling function invocations with UI feedback
43
+ * Use this to wrap invoke calls and handle errors gracefully
44
+ *
45
+ * @param invokeCall - A function that calls invoke and returns the result
46
+ * @param onSuccess - Callback for successful responses
47
+ * @param onError - Callback for error responses
48
+ * @param context - Additional context for logging
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * await functionsClient.handleInvoke(
53
+ * () => functionsClient.invoke<JobData>('process-job', options),
54
+ * (data) => {
55
+ * // Handle success
56
+ * console.log('Job processed:', data);
57
+ * },
58
+ * (error) => {
59
+ * // Handle error
60
+ * showErrorMessage(error.message);
61
+ * }
62
+ * );
63
+ * ```
64
+ */
65
+ handleInvoke<T>(invokeCall: () => Promise<T>, onSuccess: (data: T) => Promise<void> | void, onError: (error: EdgeFunctionError) => Promise<void> | void, context?: string): Promise<void>;
66
+ /**
67
+ * @deprecated Use handleInvoke instead. This method is kept for backward compatibility.
68
+ * Helper method for handling function responses with UI feedback
69
+ */
70
+ handleResponse<T>(result: FunctionsResponse<T>, onSuccess: (data: T) => Promise<void> | void, onError: (error: string, code?: string, details?: unknown) => Promise<void> | void, context?: string): Promise<void>;
71
+ }
@@ -0,0 +1,177 @@
1
+ import { FunctionsHttpError } from '@supabase/supabase-js';
2
+ /**
3
+ * Custom error class for Edge Function errors
4
+ * Allows for instanceof checks and provides structured error information
5
+ */
6
+ export class EdgeFunctionError extends Error {
7
+ code;
8
+ details;
9
+ functionName;
10
+ constructor(message, functionName, code, details) {
11
+ super(message);
12
+ this.name = 'EdgeFunctionError';
13
+ this.functionName = functionName;
14
+ this.code = code;
15
+ this.details = details;
16
+ }
17
+ }
18
+ /**
19
+ * Error thrown when Edge Function returns no data
20
+ */
21
+ export class EdgeFunctionNoDataError extends EdgeFunctionError {
22
+ constructor(functionName) {
23
+ super('No data received from Edge Function.', functionName);
24
+ this.name = 'EdgeFunctionNoDataError';
25
+ }
26
+ }
27
+ /**
28
+ * Enhanced Supabase Functions client with better error handling
29
+ * Provides a wrapper around Supabase Edge Functions with:
30
+ * - Automatic custom error message extraction
31
+ * - Type-safe responses
32
+ * - Consistent error handling
33
+ * - Generic typing support
34
+ */
35
+ export class FunctionsClient {
36
+ supabase;
37
+ constructor(supabaseClient) {
38
+ this.supabase = supabaseClient;
39
+ }
40
+ /**
41
+ * Invoke a Supabase Edge Function with enhanced error handling
42
+ * Throws EdgeFunctionError on failure, returns data on success
43
+ *
44
+ * @param functionName - The name of the Edge Function to invoke
45
+ * @param args - Function invocation options (optional if RequestBody has no required properties)
46
+ * @returns Promise<ResponseData> - The response data on success
47
+ * @throws {EdgeFunctionError} When the function fails or returns an error
48
+ * @throws {EdgeFunctionNoDataError} When the function succeeds but returns no data
49
+ */
50
+ async invoke(functionName, ...args) {
51
+ const options = args[0];
52
+ try {
53
+ const result = await this.supabase.functions.invoke(functionName,
54
+ // eslint-disable-next-line ts/no-unsafe-argument
55
+ options);
56
+ // Handle error cases
57
+ if (result.error != null) {
58
+ console.error(`Edge Function '${functionName}' error:`, result.error);
59
+ // Handle FunctionsHttpError to extract custom error message
60
+ if (result.error instanceof FunctionsHttpError) {
61
+ try {
62
+ // The context property contains the Response object
63
+ const response = result.error.context;
64
+ const errorResponse = (await response.json());
65
+ const customErrorMessage = errorResponse.error ?? errorResponse.message ?? result.error.message;
66
+ throw new EdgeFunctionError(customErrorMessage, functionName, errorResponse.code, errorResponse.details);
67
+ }
68
+ catch (parseError) {
69
+ if (parseError instanceof EdgeFunctionError) {
70
+ throw parseError;
71
+ }
72
+ console.error(`Failed to parse error response from '${functionName}':`, parseError);
73
+ throw new EdgeFunctionError(result.error.message, functionName);
74
+ }
75
+ }
76
+ else {
77
+ // Handle other error types
78
+ const errorMessage = 'message' in result.error
79
+ ? result.error.message
80
+ : 'An unknown error occurred.';
81
+ throw new EdgeFunctionError(errorMessage, functionName);
82
+ }
83
+ }
84
+ // Handle success case
85
+ if (result.data == null) {
86
+ throw new EdgeFunctionNoDataError(functionName);
87
+ }
88
+ // Check if the response follows the ApiResponse structure with nested data
89
+ if (typeof result.data === 'object' &&
90
+ result.data !== null &&
91
+ 'data' in result.data &&
92
+ 'message' in result.data) {
93
+ // Extract the actual data from the nested structure
94
+ const apiResponse = result.data;
95
+ return apiResponse.data;
96
+ }
97
+ // If it's not nested, return as is
98
+ return result.data;
99
+ }
100
+ catch (error) {
101
+ // Re-throw EdgeFunctionError instances
102
+ if (error instanceof EdgeFunctionError) {
103
+ throw error;
104
+ }
105
+ console.error(`Unexpected error invoking Edge Function '${functionName}':`, error);
106
+ const errorMessage = error instanceof Error
107
+ ? error.message
108
+ : `An unexpected error occurred while invoking '${functionName}'.`;
109
+ throw new EdgeFunctionError(errorMessage, functionName);
110
+ }
111
+ }
112
+ /**
113
+ * Helper method for handling function invocations with UI feedback
114
+ * Use this to wrap invoke calls and handle errors gracefully
115
+ *
116
+ * @param invokeCall - A function that calls invoke and returns the result
117
+ * @param onSuccess - Callback for successful responses
118
+ * @param onError - Callback for error responses
119
+ * @param context - Additional context for logging
120
+ *
121
+ * @example
122
+ * ```typescript
123
+ * await functionsClient.handleInvoke(
124
+ * () => functionsClient.invoke<JobData>('process-job', options),
125
+ * (data) => {
126
+ * // Handle success
127
+ * console.log('Job processed:', data);
128
+ * },
129
+ * (error) => {
130
+ * // Handle error
131
+ * showErrorMessage(error.message);
132
+ * }
133
+ * );
134
+ * ```
135
+ */
136
+ async handleInvoke(invokeCall, onSuccess, onError, context) {
137
+ try {
138
+ const data = await invokeCall();
139
+ await onSuccess(data);
140
+ }
141
+ catch (error) {
142
+ if (error instanceof EdgeFunctionError) {
143
+ const contextStr = context != null && context.length > 0 ? ` (${context})` : '';
144
+ console.error(`Function error${contextStr}:`, error.message);
145
+ if (error.code != null && error.code.length > 0) {
146
+ console.error(`Error code${contextStr}:`, error.code);
147
+ }
148
+ await onError(error);
149
+ }
150
+ else {
151
+ // Re-throw unexpected errors
152
+ throw error;
153
+ }
154
+ }
155
+ }
156
+ /**
157
+ * @deprecated Use handleInvoke instead. This method is kept for backward compatibility.
158
+ * Helper method for handling function responses with UI feedback
159
+ */
160
+ async handleResponse(result, onSuccess, onError, context) {
161
+ if (result.error != null) {
162
+ const contextStr = context != null && context.length > 0 ? ` (${context})` : '';
163
+ console.error(`Function error${contextStr}:`, result.error);
164
+ if (result.code != null && result.code.length > 0) {
165
+ console.error(`Error code${contextStr}:`, result.code);
166
+ }
167
+ await onError(result.error, result.code, result.details);
168
+ }
169
+ else if (result.data != null) {
170
+ await onSuccess(result.data);
171
+ }
172
+ else {
173
+ // This shouldn't happen with our implementation, but just in case
174
+ await onError('Unexpected response: no data or error received.');
175
+ }
176
+ }
177
+ }
@@ -0,0 +1,2 @@
1
+ export * from './functions-client';
2
+ export * from './types';
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export * from './functions-client';
2
+ export * from './types';
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Custom error response interface from Edge Functions
3
+ */
4
+ export interface EdgeFunctionErrorResponse {
5
+ error?: string;
6
+ message?: string;
7
+ code?: string;
8
+ details?: any;
9
+ }
10
+ /**
11
+ * Enhanced function response with better error handling
12
+ */
13
+ export interface FunctionsResponse<T> {
14
+ data: T | null;
15
+ error: string | null;
16
+ code?: string;
17
+ details?: any;
18
+ message?: string;
19
+ }
20
+ /**
21
+ * Utility to extract required keys from a type
22
+ */
23
+ export type RequiredKeys<T> = {
24
+ [K in keyof T]-?: Record<string, never> extends {
25
+ [P in K]: T[K];
26
+ } ? never : K;
27
+ }[keyof T];
28
+ /**
29
+ * Check if type has required keys
30
+ */
31
+ export type HasRequiredProperties<T> = RequiredKeys<T> extends never ? false : true;
32
+ /**
33
+ * Function invocation options with conditional body requirement.
34
+ *
35
+ * - When `RequestBody` is `void | undefined`, the body option is not present.
36
+ * - When `RequestBody` has all-optional properties, `body` is optional.
37
+ * - When `RequestBody` has at least one required property, `body` is required.
38
+ */
39
+ export type FunctionInvokeOptions<RequestBody> = RequestBody extends void | undefined ? {
40
+ headers?: Record<string, string>;
41
+ method?: 'POST' | 'GET' | 'PUT' | 'PATCH' | 'DELETE';
42
+ signal?: AbortSignal;
43
+ } : HasRequiredProperties<RequestBody> extends true ? {
44
+ headers?: Record<string, string>;
45
+ method?: 'POST' | 'GET' | 'PUT' | 'PATCH' | 'DELETE';
46
+ body: RequestBody;
47
+ signal?: AbortSignal;
48
+ } : {
49
+ headers?: Record<string, string>;
50
+ method?: 'POST' | 'GET' | 'PUT' | 'PATCH' | 'DELETE';
51
+ body?: RequestBody;
52
+ signal?: AbortSignal;
53
+ };
54
+ /**
55
+ * Determines whether the `options` parameter to `invoke()` is required or
56
+ * optional based on the shape of `RequestBody`.
57
+ *
58
+ * - If `RequestBody` is `void | undefined`, options are optional.
59
+ * - If `RequestBody` has no required properties, options are optional.
60
+ * - If `RequestBody` has required properties, options are required.
61
+ */
62
+ export type InvokeOptions<RequestBody> = RequestBody extends void | undefined ? FunctionInvokeOptions<RequestBody> | undefined : RequiredKeys<RequestBody> extends never ? FunctionInvokeOptions<RequestBody> | undefined : FunctionInvokeOptions<RequestBody>;
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@pixpilot/supabase-functions-client",
3
+ "type": "module",
4
+ "version": "0.2.0",
5
+ "description": "A client library for Supabase Functions, providing a simple and efficient way to interact with serverless functions deployed on the Supabase platform.",
6
+ "author": "m.doaie <m.doaie@hotmail.com>",
7
+ "license": "MIT",
8
+ "homepage": "https://github.com/pixpilot/supabase-toolkit",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/pixpilot/supabase-toolkit.git",
12
+ "directory": "packages/supabase-functions-client"
13
+ },
14
+ "bugs": {
15
+ "url": "https://github.com/pixpilot/supabase-toolkit/issues"
16
+ },
17
+ "keywords": [],
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.js",
22
+ "require": "./dist/index.cjs"
23
+ }
24
+ },
25
+ "files": [
26
+ "dist"
27
+ ],
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "peerDependencies": {
32
+ "@supabase/supabase-js": "^2.75.0"
33
+ },
34
+ "devDependencies": {
35
+ "@supabase/supabase-js": "^2.75.0",
36
+ "@types/node": "^22.18.10",
37
+ "eslint": "^9.37.0",
38
+ "typescript": "^5.9.3",
39
+ "@internal/eslint-config": "0.3.0",
40
+ "@internal/prettier-config": "0.0.1",
41
+ "@internal/tsdown-config": "0.1.0",
42
+ "@internal/vitest-config": "0.1.0",
43
+ "@internal/tsconfig": "0.1.0"
44
+ },
45
+ "prettier": "@internal/prettier-config",
46
+ "scripts": {
47
+ "clean": "git clean -xdf .cache .turbo dist",
48
+ "clean:all": "pnpm clean && git clean -xdf node_modules",
49
+ "build": "pnpm run clean && tsc -p tsconfig.build.json",
50
+ "build:watch": "pnpm run clean && tsc -p tsconfig.build.json --watch",
51
+ "test": "vitest --run --passWithNoTests",
52
+ "test:watch": "vitest --watch",
53
+ "test:ui": "vitest --ui",
54
+ "test:coverage": "vitest --coverage",
55
+ "typecheck": "tsc --noEmit",
56
+ "lint": "eslint",
57
+ "format": "prettier --check . --ignore-path ../../.gitignore --ignore-path ../../.prettierignore"
58
+ },
59
+ "main": "./dist/index.cjs",
60
+ "module": "./dist/index.js",
61
+ "types": "./dist/index.d.ts"
62
+ }