@fluxbase/sdk 0.0.1-rc.40 → 0.0.1-rc.42
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/index.cjs +1360 -56
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1423 -70
- package/dist/index.d.ts +1423 -70
- package/dist/index.js +1357 -57
- package/dist/index.js.map +1 -1
- package/package.json +10 -1
package/dist/index.cjs
CHANGED
|
@@ -901,6 +901,7 @@ var RealtimeChannel = class {
|
|
|
901
901
|
this.presenceCallbacks = /* @__PURE__ */ new Map();
|
|
902
902
|
this.broadcastCallbacks = /* @__PURE__ */ new Map();
|
|
903
903
|
this.subscriptionConfig = null;
|
|
904
|
+
this.subscriptionId = null;
|
|
904
905
|
this._presenceState = {};
|
|
905
906
|
this.myPresenceKey = null;
|
|
906
907
|
this.reconnectAttempts = 0;
|
|
@@ -990,7 +991,8 @@ var RealtimeChannel = class {
|
|
|
990
991
|
if (this.ws) {
|
|
991
992
|
this.sendMessage({
|
|
992
993
|
type: "unsubscribe",
|
|
993
|
-
channel: this.channelName
|
|
994
|
+
channel: this.channelName,
|
|
995
|
+
subscription_id: this.subscriptionId || void 0
|
|
994
996
|
});
|
|
995
997
|
const startTime = Date.now();
|
|
996
998
|
const maxWait = timeout || 5e3;
|
|
@@ -1249,7 +1251,12 @@ var RealtimeChannel = class {
|
|
|
1249
1251
|
ackHandler.resolve(message.status || "ok");
|
|
1250
1252
|
}
|
|
1251
1253
|
} else {
|
|
1252
|
-
|
|
1254
|
+
if (message.payload && typeof message.payload === "object" && "subscription_id" in message.payload) {
|
|
1255
|
+
this.subscriptionId = message.payload.subscription_id;
|
|
1256
|
+
console.log("[Fluxbase Realtime] Subscription ID received:", this.subscriptionId);
|
|
1257
|
+
} else {
|
|
1258
|
+
console.log("[Fluxbase Realtime] Acknowledged:", message);
|
|
1259
|
+
}
|
|
1253
1260
|
}
|
|
1254
1261
|
break;
|
|
1255
1262
|
case "error":
|
|
@@ -1846,16 +1853,22 @@ var FluxbaseFunctions = class {
|
|
|
1846
1853
|
* This method is fully compatible with Supabase's functions.invoke() API.
|
|
1847
1854
|
*
|
|
1848
1855
|
* @param functionName - The name of the function to invoke
|
|
1849
|
-
* @param options - Invocation options including body, headers,
|
|
1856
|
+
* @param options - Invocation options including body, headers, HTTP method, and namespace
|
|
1850
1857
|
* @returns Promise resolving to { data, error } tuple
|
|
1851
1858
|
*
|
|
1852
1859
|
* @example
|
|
1853
1860
|
* ```typescript
|
|
1854
|
-
* // Simple invocation
|
|
1861
|
+
* // Simple invocation (uses first matching function by namespace alphabetically)
|
|
1855
1862
|
* const { data, error } = await client.functions.invoke('hello', {
|
|
1856
1863
|
* body: { name: 'World' }
|
|
1857
1864
|
* })
|
|
1858
1865
|
*
|
|
1866
|
+
* // Invoke a specific namespace's function
|
|
1867
|
+
* const { data, error } = await client.functions.invoke('hello', {
|
|
1868
|
+
* body: { name: 'World' },
|
|
1869
|
+
* namespace: 'my-app'
|
|
1870
|
+
* })
|
|
1871
|
+
*
|
|
1859
1872
|
* // With GET method
|
|
1860
1873
|
* const { data, error } = await client.functions.invoke('get-data', {
|
|
1861
1874
|
* method: 'GET'
|
|
@@ -1874,7 +1887,8 @@ var FluxbaseFunctions = class {
|
|
|
1874
1887
|
const method = options?.method || "POST";
|
|
1875
1888
|
const headers = options?.headers || {};
|
|
1876
1889
|
const body = options?.body;
|
|
1877
|
-
const
|
|
1890
|
+
const namespace = options?.namespace;
|
|
1891
|
+
const endpoint = namespace ? `/api/v1/functions/${functionName}/invoke?namespace=${encodeURIComponent(namespace)}` : `/api/v1/functions/${functionName}/invoke`;
|
|
1878
1892
|
let response;
|
|
1879
1893
|
switch (method) {
|
|
1880
1894
|
case "GET":
|
|
@@ -1900,136 +1914,209 @@ var FluxbaseFunctions = class {
|
|
|
1900
1914
|
}
|
|
1901
1915
|
}
|
|
1902
1916
|
/**
|
|
1903
|
-
*
|
|
1917
|
+
* List all public edge functions
|
|
1904
1918
|
*
|
|
1905
|
-
* @
|
|
1906
|
-
* @returns Promise resolving to { data, error } tuple with created function metadata
|
|
1919
|
+
* @returns Promise resolving to { data, error } tuple with array of public functions
|
|
1907
1920
|
*
|
|
1908
1921
|
* @example
|
|
1909
1922
|
* ```typescript
|
|
1910
|
-
* const { data, error } = await client.functions.
|
|
1911
|
-
*
|
|
1912
|
-
*
|
|
1913
|
-
*
|
|
1914
|
-
* })
|
|
1923
|
+
* const { data, error } = await client.functions.list()
|
|
1924
|
+
* if (data) {
|
|
1925
|
+
* console.log('Functions:', data.map(f => f.name))
|
|
1926
|
+
* }
|
|
1915
1927
|
* ```
|
|
1916
1928
|
*/
|
|
1917
|
-
async
|
|
1929
|
+
async list() {
|
|
1918
1930
|
try {
|
|
1919
|
-
const data = await this.fetch.
|
|
1931
|
+
const data = await this.fetch.get("/api/v1/functions");
|
|
1920
1932
|
return { data, error: null };
|
|
1921
1933
|
} catch (error) {
|
|
1922
1934
|
return { data: null, error };
|
|
1923
1935
|
}
|
|
1924
1936
|
}
|
|
1925
1937
|
/**
|
|
1926
|
-
*
|
|
1938
|
+
* Get details of a specific edge function
|
|
1927
1939
|
*
|
|
1928
|
-
* @
|
|
1940
|
+
* @param name - Function name
|
|
1941
|
+
* @returns Promise resolving to { data, error } tuple with function metadata
|
|
1929
1942
|
*
|
|
1930
1943
|
* @example
|
|
1931
1944
|
* ```typescript
|
|
1932
|
-
* const { data, error } = await client.functions.
|
|
1945
|
+
* const { data, error } = await client.functions.get('my-function')
|
|
1933
1946
|
* if (data) {
|
|
1934
|
-
* console.log('
|
|
1947
|
+
* console.log('Function version:', data.version)
|
|
1935
1948
|
* }
|
|
1936
1949
|
* ```
|
|
1937
1950
|
*/
|
|
1938
|
-
async
|
|
1951
|
+
async get(name) {
|
|
1939
1952
|
try {
|
|
1940
|
-
const data = await this.fetch.get(
|
|
1953
|
+
const data = await this.fetch.get(`/api/v1/functions/${name}`);
|
|
1941
1954
|
return { data, error: null };
|
|
1942
1955
|
} catch (error) {
|
|
1943
1956
|
return { data: null, error };
|
|
1944
1957
|
}
|
|
1945
1958
|
}
|
|
1959
|
+
};
|
|
1960
|
+
|
|
1961
|
+
// src/jobs.ts
|
|
1962
|
+
var FluxbaseJobs = class {
|
|
1963
|
+
constructor(fetch2) {
|
|
1964
|
+
this.fetch = fetch2;
|
|
1965
|
+
}
|
|
1946
1966
|
/**
|
|
1947
|
-
*
|
|
1967
|
+
* Submit a new job for execution
|
|
1948
1968
|
*
|
|
1949
|
-
* @param
|
|
1950
|
-
* @
|
|
1969
|
+
* @param jobName - Name of the job function to execute
|
|
1970
|
+
* @param payload - Job input data
|
|
1971
|
+
* @param options - Additional options (priority, namespace, scheduled time)
|
|
1972
|
+
* @returns Promise resolving to { data, error } tuple with submitted job details
|
|
1951
1973
|
*
|
|
1952
1974
|
* @example
|
|
1953
1975
|
* ```typescript
|
|
1954
|
-
*
|
|
1976
|
+
* // Submit a simple job
|
|
1977
|
+
* const { data, error } = await client.jobs.submit('send-email', {
|
|
1978
|
+
* to: 'user@example.com',
|
|
1979
|
+
* subject: 'Hello',
|
|
1980
|
+
* body: 'Welcome!'
|
|
1981
|
+
* })
|
|
1982
|
+
*
|
|
1955
1983
|
* if (data) {
|
|
1956
|
-
* console.log('
|
|
1984
|
+
* console.log('Job submitted:', data.id)
|
|
1985
|
+
* console.log('Status:', data.status)
|
|
1957
1986
|
* }
|
|
1987
|
+
*
|
|
1988
|
+
* // Submit with priority
|
|
1989
|
+
* const { data } = await client.jobs.submit('high-priority-task', payload, {
|
|
1990
|
+
* priority: 10
|
|
1991
|
+
* })
|
|
1992
|
+
*
|
|
1993
|
+
* // Schedule for later
|
|
1994
|
+
* const { data } = await client.jobs.submit('scheduled-task', payload, {
|
|
1995
|
+
* scheduled: '2025-01-01T00:00:00Z'
|
|
1996
|
+
* })
|
|
1958
1997
|
* ```
|
|
1959
1998
|
*/
|
|
1960
|
-
async
|
|
1999
|
+
async submit(jobName, payload, options) {
|
|
1961
2000
|
try {
|
|
1962
|
-
const
|
|
2001
|
+
const request = {
|
|
2002
|
+
job_name: jobName,
|
|
2003
|
+
payload,
|
|
2004
|
+
...options
|
|
2005
|
+
};
|
|
2006
|
+
const data = await this.fetch.post("/api/v1/jobs/submit", request);
|
|
1963
2007
|
return { data, error: null };
|
|
1964
2008
|
} catch (error) {
|
|
1965
2009
|
return { data: null, error };
|
|
1966
2010
|
}
|
|
1967
2011
|
}
|
|
1968
2012
|
/**
|
|
1969
|
-
*
|
|
2013
|
+
* Get status and details of a specific job
|
|
1970
2014
|
*
|
|
1971
|
-
* @param
|
|
1972
|
-
* @
|
|
1973
|
-
* @returns Promise resolving to { data, error } tuple with updated function metadata
|
|
2015
|
+
* @param jobId - Job ID
|
|
2016
|
+
* @returns Promise resolving to { data, error } tuple with job details
|
|
1974
2017
|
*
|
|
1975
2018
|
* @example
|
|
1976
2019
|
* ```typescript
|
|
1977
|
-
* const { data, error } = await client.
|
|
1978
|
-
*
|
|
1979
|
-
*
|
|
2020
|
+
* const { data: job, error } = await client.jobs.get('550e8400-e29b-41d4-a716-446655440000')
|
|
2021
|
+
*
|
|
2022
|
+
* if (job) {
|
|
2023
|
+
* console.log('Status:', job.status)
|
|
2024
|
+
* console.log('Progress:', job.progress_percent + '%')
|
|
2025
|
+
* console.log('Result:', job.result)
|
|
2026
|
+
* console.log('Logs:', job.logs)
|
|
2027
|
+
* }
|
|
2028
|
+
* ```
|
|
2029
|
+
*/
|
|
2030
|
+
async get(jobId) {
|
|
2031
|
+
try {
|
|
2032
|
+
const data = await this.fetch.get(`/api/v1/jobs/${jobId}`);
|
|
2033
|
+
return { data, error: null };
|
|
2034
|
+
} catch (error) {
|
|
2035
|
+
return { data: null, error };
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2038
|
+
/**
|
|
2039
|
+
* List jobs submitted by the current user
|
|
2040
|
+
*
|
|
2041
|
+
* @param filters - Optional filters (status, namespace, limit, offset)
|
|
2042
|
+
* @returns Promise resolving to { data, error } tuple with array of jobs
|
|
2043
|
+
*
|
|
2044
|
+
* @example
|
|
2045
|
+
* ```typescript
|
|
2046
|
+
* // List all your jobs
|
|
2047
|
+
* const { data: jobs, error } = await client.jobs.list()
|
|
2048
|
+
*
|
|
2049
|
+
* // Filter by status
|
|
2050
|
+
* const { data: running } = await client.jobs.list({
|
|
2051
|
+
* status: 'running'
|
|
2052
|
+
* })
|
|
2053
|
+
*
|
|
2054
|
+
* // Paginate
|
|
2055
|
+
* const { data: page } = await client.jobs.list({
|
|
2056
|
+
* limit: 20,
|
|
2057
|
+
* offset: 40
|
|
1980
2058
|
* })
|
|
1981
2059
|
* ```
|
|
1982
2060
|
*/
|
|
1983
|
-
async
|
|
2061
|
+
async list(filters) {
|
|
1984
2062
|
try {
|
|
1985
|
-
const
|
|
2063
|
+
const params = new URLSearchParams();
|
|
2064
|
+
if (filters?.status) params.append("status", filters.status);
|
|
2065
|
+
if (filters?.namespace) params.append("namespace", filters.namespace);
|
|
2066
|
+
if (filters?.limit) params.append("limit", filters.limit.toString());
|
|
2067
|
+
if (filters?.offset) params.append("offset", filters.offset.toString());
|
|
2068
|
+
const queryString = params.toString();
|
|
2069
|
+
const data = await this.fetch.get(
|
|
2070
|
+
`/api/v1/jobs${queryString ? `?${queryString}` : ""}`
|
|
2071
|
+
);
|
|
1986
2072
|
return { data, error: null };
|
|
1987
2073
|
} catch (error) {
|
|
1988
2074
|
return { data: null, error };
|
|
1989
2075
|
}
|
|
1990
2076
|
}
|
|
1991
2077
|
/**
|
|
1992
|
-
*
|
|
2078
|
+
* Cancel a pending or running job
|
|
1993
2079
|
*
|
|
1994
|
-
* @param
|
|
2080
|
+
* @param jobId - Job ID to cancel
|
|
1995
2081
|
* @returns Promise resolving to { data, error } tuple
|
|
1996
2082
|
*
|
|
1997
2083
|
* @example
|
|
1998
2084
|
* ```typescript
|
|
1999
|
-
* const {
|
|
2085
|
+
* const { error } = await client.jobs.cancel('550e8400-e29b-41d4-a716-446655440000')
|
|
2086
|
+
*
|
|
2087
|
+
* if (!error) {
|
|
2088
|
+
* console.log('Job cancelled successfully')
|
|
2089
|
+
* }
|
|
2000
2090
|
* ```
|
|
2001
2091
|
*/
|
|
2002
|
-
async
|
|
2092
|
+
async cancel(jobId) {
|
|
2003
2093
|
try {
|
|
2004
|
-
await this.fetch.
|
|
2094
|
+
await this.fetch.post(`/api/v1/jobs/${jobId}/cancel`, {});
|
|
2005
2095
|
return { data: null, error: null };
|
|
2006
2096
|
} catch (error) {
|
|
2007
2097
|
return { data: null, error };
|
|
2008
2098
|
}
|
|
2009
2099
|
}
|
|
2010
2100
|
/**
|
|
2011
|
-
*
|
|
2101
|
+
* Retry a failed job
|
|
2012
2102
|
*
|
|
2013
|
-
*
|
|
2014
|
-
*
|
|
2015
|
-
* @
|
|
2103
|
+
* Creates a new job execution with the same parameters
|
|
2104
|
+
*
|
|
2105
|
+
* @param jobId - Job ID to retry
|
|
2106
|
+
* @returns Promise resolving to { data, error } tuple with new job
|
|
2016
2107
|
*
|
|
2017
2108
|
* @example
|
|
2018
2109
|
* ```typescript
|
|
2019
|
-
* const { data, error } = await client.
|
|
2020
|
-
*
|
|
2021
|
-
*
|
|
2022
|
-
*
|
|
2023
|
-
* })
|
|
2110
|
+
* const { data: newJob, error } = await client.jobs.retry('550e8400-e29b-41d4-a716-446655440000')
|
|
2111
|
+
*
|
|
2112
|
+
* if (newJob) {
|
|
2113
|
+
* console.log('Job retried, new ID:', newJob.id)
|
|
2024
2114
|
* }
|
|
2025
2115
|
* ```
|
|
2026
2116
|
*/
|
|
2027
|
-
async
|
|
2117
|
+
async retry(jobId) {
|
|
2028
2118
|
try {
|
|
2029
|
-
const
|
|
2030
|
-
const data = await this.fetch.get(
|
|
2031
|
-
`/api/v1/functions/${name}/executions${params}`
|
|
2032
|
-
);
|
|
2119
|
+
const data = await this.fetch.post(`/api/v1/jobs/${jobId}/retry`, {});
|
|
2033
2120
|
return { data, error: null };
|
|
2034
2121
|
} catch (error) {
|
|
2035
2122
|
return { data: null, error };
|
|
@@ -3854,6 +3941,1215 @@ var FluxbaseManagement = class {
|
|
|
3854
3941
|
}
|
|
3855
3942
|
};
|
|
3856
3943
|
|
|
3944
|
+
// src/admin-functions.ts
|
|
3945
|
+
var FluxbaseAdminFunctions = class {
|
|
3946
|
+
constructor(fetch2) {
|
|
3947
|
+
this.fetch = fetch2;
|
|
3948
|
+
}
|
|
3949
|
+
/**
|
|
3950
|
+
* Create a new edge function
|
|
3951
|
+
*
|
|
3952
|
+
* @param request - Function configuration and code
|
|
3953
|
+
* @returns Promise resolving to { data, error } tuple with created function metadata
|
|
3954
|
+
*
|
|
3955
|
+
* @example
|
|
3956
|
+
* ```typescript
|
|
3957
|
+
* const { data, error } = await client.admin.functions.create({
|
|
3958
|
+
* name: 'my-function',
|
|
3959
|
+
* code: 'export default async function handler(req) { return { hello: "world" } }',
|
|
3960
|
+
* enabled: true
|
|
3961
|
+
* })
|
|
3962
|
+
* ```
|
|
3963
|
+
*/
|
|
3964
|
+
async create(request) {
|
|
3965
|
+
try {
|
|
3966
|
+
const data = await this.fetch.post(
|
|
3967
|
+
"/api/v1/functions",
|
|
3968
|
+
request
|
|
3969
|
+
);
|
|
3970
|
+
return { data, error: null };
|
|
3971
|
+
} catch (error) {
|
|
3972
|
+
return { data: null, error };
|
|
3973
|
+
}
|
|
3974
|
+
}
|
|
3975
|
+
/**
|
|
3976
|
+
* List all namespaces that have edge functions
|
|
3977
|
+
*
|
|
3978
|
+
* @returns Promise resolving to { data, error } tuple with array of namespace strings
|
|
3979
|
+
*
|
|
3980
|
+
* @example
|
|
3981
|
+
* ```typescript
|
|
3982
|
+
* const { data, error } = await client.admin.functions.listNamespaces()
|
|
3983
|
+
* if (data) {
|
|
3984
|
+
* console.log('Available namespaces:', data)
|
|
3985
|
+
* }
|
|
3986
|
+
* ```
|
|
3987
|
+
*/
|
|
3988
|
+
async listNamespaces() {
|
|
3989
|
+
try {
|
|
3990
|
+
const response = await this.fetch.get(
|
|
3991
|
+
"/api/v1/admin/functions/namespaces"
|
|
3992
|
+
);
|
|
3993
|
+
return { data: response.namespaces || ["default"], error: null };
|
|
3994
|
+
} catch (error) {
|
|
3995
|
+
return { data: null, error };
|
|
3996
|
+
}
|
|
3997
|
+
}
|
|
3998
|
+
/**
|
|
3999
|
+
* List all edge functions (admin view)
|
|
4000
|
+
*
|
|
4001
|
+
* @param namespace - Optional namespace filter (if not provided, lists all public functions)
|
|
4002
|
+
* @returns Promise resolving to { data, error } tuple with array of functions
|
|
4003
|
+
*
|
|
4004
|
+
* @example
|
|
4005
|
+
* ```typescript
|
|
4006
|
+
* // List all public functions
|
|
4007
|
+
* const { data, error } = await client.admin.functions.list()
|
|
4008
|
+
*
|
|
4009
|
+
* // List functions in a specific namespace
|
|
4010
|
+
* const { data, error } = await client.admin.functions.list('my-namespace')
|
|
4011
|
+
* if (data) {
|
|
4012
|
+
* console.log('Functions:', data.map(f => f.name))
|
|
4013
|
+
* }
|
|
4014
|
+
* ```
|
|
4015
|
+
*/
|
|
4016
|
+
async list(namespace) {
|
|
4017
|
+
try {
|
|
4018
|
+
const params = namespace ? `?namespace=${namespace}` : "";
|
|
4019
|
+
const data = await this.fetch.get(
|
|
4020
|
+
`/api/v1/functions${params}`
|
|
4021
|
+
);
|
|
4022
|
+
return { data, error: null };
|
|
4023
|
+
} catch (error) {
|
|
4024
|
+
return { data: null, error };
|
|
4025
|
+
}
|
|
4026
|
+
}
|
|
4027
|
+
/**
|
|
4028
|
+
* Get details of a specific edge function
|
|
4029
|
+
*
|
|
4030
|
+
* @param name - Function name
|
|
4031
|
+
* @returns Promise resolving to { data, error } tuple with function metadata
|
|
4032
|
+
*
|
|
4033
|
+
* @example
|
|
4034
|
+
* ```typescript
|
|
4035
|
+
* const { data, error } = await client.admin.functions.get('my-function')
|
|
4036
|
+
* if (data) {
|
|
4037
|
+
* console.log('Function version:', data.version)
|
|
4038
|
+
* }
|
|
4039
|
+
* ```
|
|
4040
|
+
*/
|
|
4041
|
+
async get(name) {
|
|
4042
|
+
try {
|
|
4043
|
+
const data = await this.fetch.get(
|
|
4044
|
+
`/api/v1/functions/${name}`
|
|
4045
|
+
);
|
|
4046
|
+
return { data, error: null };
|
|
4047
|
+
} catch (error) {
|
|
4048
|
+
return { data: null, error };
|
|
4049
|
+
}
|
|
4050
|
+
}
|
|
4051
|
+
/**
|
|
4052
|
+
* Update an existing edge function
|
|
4053
|
+
*
|
|
4054
|
+
* @param name - Function name
|
|
4055
|
+
* @param updates - Fields to update
|
|
4056
|
+
* @returns Promise resolving to { data, error } tuple with updated function metadata
|
|
4057
|
+
*
|
|
4058
|
+
* @example
|
|
4059
|
+
* ```typescript
|
|
4060
|
+
* const { data, error } = await client.admin.functions.update('my-function', {
|
|
4061
|
+
* enabled: false,
|
|
4062
|
+
* description: 'Updated description'
|
|
4063
|
+
* })
|
|
4064
|
+
* ```
|
|
4065
|
+
*/
|
|
4066
|
+
async update(name, updates) {
|
|
4067
|
+
try {
|
|
4068
|
+
const data = await this.fetch.put(
|
|
4069
|
+
`/api/v1/functions/${name}`,
|
|
4070
|
+
updates
|
|
4071
|
+
);
|
|
4072
|
+
return { data, error: null };
|
|
4073
|
+
} catch (error) {
|
|
4074
|
+
return { data: null, error };
|
|
4075
|
+
}
|
|
4076
|
+
}
|
|
4077
|
+
/**
|
|
4078
|
+
* Delete an edge function
|
|
4079
|
+
*
|
|
4080
|
+
* @param name - Function name
|
|
4081
|
+
* @returns Promise resolving to { data, error } tuple
|
|
4082
|
+
*
|
|
4083
|
+
* @example
|
|
4084
|
+
* ```typescript
|
|
4085
|
+
* const { data, error } = await client.admin.functions.delete('my-function')
|
|
4086
|
+
* ```
|
|
4087
|
+
*/
|
|
4088
|
+
async delete(name) {
|
|
4089
|
+
try {
|
|
4090
|
+
await this.fetch.delete(`/api/v1/functions/${name}`);
|
|
4091
|
+
return { data: null, error: null };
|
|
4092
|
+
} catch (error) {
|
|
4093
|
+
return { data: null, error };
|
|
4094
|
+
}
|
|
4095
|
+
}
|
|
4096
|
+
/**
|
|
4097
|
+
* Get execution history for an edge function
|
|
4098
|
+
*
|
|
4099
|
+
* @param name - Function name
|
|
4100
|
+
* @param limit - Maximum number of executions to return (optional)
|
|
4101
|
+
* @returns Promise resolving to { data, error } tuple with execution records
|
|
4102
|
+
*
|
|
4103
|
+
* @example
|
|
4104
|
+
* ```typescript
|
|
4105
|
+
* const { data, error } = await client.admin.functions.getExecutions('my-function', 10)
|
|
4106
|
+
* if (data) {
|
|
4107
|
+
* data.forEach(exec => {
|
|
4108
|
+
* console.log(`${exec.executed_at}: ${exec.status} (${exec.duration_ms}ms)`)
|
|
4109
|
+
* })
|
|
4110
|
+
* }
|
|
4111
|
+
* ```
|
|
4112
|
+
*/
|
|
4113
|
+
async getExecutions(name, limit) {
|
|
4114
|
+
try {
|
|
4115
|
+
const params = limit ? `?limit=${limit}` : "";
|
|
4116
|
+
const data = await this.fetch.get(
|
|
4117
|
+
`/api/v1/functions/${name}/executions${params}`
|
|
4118
|
+
);
|
|
4119
|
+
return { data, error: null };
|
|
4120
|
+
} catch (error) {
|
|
4121
|
+
return { data: null, error };
|
|
4122
|
+
}
|
|
4123
|
+
}
|
|
4124
|
+
/**
|
|
4125
|
+
* Sync multiple functions to a namespace
|
|
4126
|
+
*
|
|
4127
|
+
* Bulk create/update/delete functions in a specific namespace. This is useful for
|
|
4128
|
+
* deploying functions from your application to Fluxbase in Kubernetes or other
|
|
4129
|
+
* container environments.
|
|
4130
|
+
*
|
|
4131
|
+
* Requires service_role or admin authentication.
|
|
4132
|
+
*
|
|
4133
|
+
* @param options - Sync configuration including namespace, functions, and options
|
|
4134
|
+
* @returns Promise resolving to { data, error } tuple with sync results
|
|
4135
|
+
*
|
|
4136
|
+
* @example
|
|
4137
|
+
* ```typescript
|
|
4138
|
+
* // Sync functions to "payment-service" namespace
|
|
4139
|
+
* const { data, error } = await client.admin.functions.sync({
|
|
4140
|
+
* namespace: 'payment-service',
|
|
4141
|
+
* functions: [
|
|
4142
|
+
* {
|
|
4143
|
+
* name: 'process-payment',
|
|
4144
|
+
* code: 'export default async function handler(req) { ... }',
|
|
4145
|
+
* enabled: true,
|
|
4146
|
+
* allow_net: true
|
|
4147
|
+
* },
|
|
4148
|
+
* {
|
|
4149
|
+
* name: 'refund-payment',
|
|
4150
|
+
* code: 'export default async function handler(req) { ... }',
|
|
4151
|
+
* enabled: true
|
|
4152
|
+
* }
|
|
4153
|
+
* ],
|
|
4154
|
+
* options: {
|
|
4155
|
+
* delete_missing: true // Remove functions not in this list
|
|
4156
|
+
* }
|
|
4157
|
+
* })
|
|
4158
|
+
*
|
|
4159
|
+
* if (data) {
|
|
4160
|
+
* console.log(`Synced: ${data.summary.created} created, ${data.summary.updated} updated`)
|
|
4161
|
+
* }
|
|
4162
|
+
*
|
|
4163
|
+
* // Dry run to preview changes
|
|
4164
|
+
* const { data, error } = await client.admin.functions.sync({
|
|
4165
|
+
* namespace: 'myapp',
|
|
4166
|
+
* functions: [...],
|
|
4167
|
+
* options: { dry_run: true }
|
|
4168
|
+
* })
|
|
4169
|
+
* ```
|
|
4170
|
+
*/
|
|
4171
|
+
async sync(options) {
|
|
4172
|
+
try {
|
|
4173
|
+
const data = await this.fetch.post(
|
|
4174
|
+
"/api/v1/admin/functions/sync",
|
|
4175
|
+
options
|
|
4176
|
+
);
|
|
4177
|
+
return { data, error: null };
|
|
4178
|
+
} catch (error) {
|
|
4179
|
+
return { data: null, error };
|
|
4180
|
+
}
|
|
4181
|
+
}
|
|
4182
|
+
};
|
|
4183
|
+
|
|
4184
|
+
// src/admin-migrations.ts
|
|
4185
|
+
var FluxbaseAdminMigrations = class {
|
|
4186
|
+
constructor(fetch2) {
|
|
4187
|
+
this.localMigrations = /* @__PURE__ */ new Map();
|
|
4188
|
+
this.fetch = fetch2;
|
|
4189
|
+
}
|
|
4190
|
+
/**
|
|
4191
|
+
* Register a migration locally for smart sync
|
|
4192
|
+
*
|
|
4193
|
+
* Call this method to register migrations in your application code.
|
|
4194
|
+
* When you call sync(), only new or changed migrations will be sent to the server.
|
|
4195
|
+
*
|
|
4196
|
+
* @param migration - Migration definition
|
|
4197
|
+
* @returns { error } tuple (always succeeds unless validation fails)
|
|
4198
|
+
*
|
|
4199
|
+
* @example
|
|
4200
|
+
* ```typescript
|
|
4201
|
+
* // In your app initialization
|
|
4202
|
+
* const { error: err1 } = client.admin.migrations.register({
|
|
4203
|
+
* name: '001_create_users_table',
|
|
4204
|
+
* namespace: 'myapp',
|
|
4205
|
+
* up_sql: 'CREATE TABLE app.users (...)',
|
|
4206
|
+
* down_sql: 'DROP TABLE app.users',
|
|
4207
|
+
* description: 'Initial users table'
|
|
4208
|
+
* })
|
|
4209
|
+
*
|
|
4210
|
+
* const { error: err2 } = client.admin.migrations.register({
|
|
4211
|
+
* name: '002_add_posts_table',
|
|
4212
|
+
* namespace: 'myapp',
|
|
4213
|
+
* up_sql: 'CREATE TABLE app.posts (...)',
|
|
4214
|
+
* down_sql: 'DROP TABLE app.posts'
|
|
4215
|
+
* })
|
|
4216
|
+
*
|
|
4217
|
+
* // Sync all registered migrations
|
|
4218
|
+
* await client.admin.migrations.sync()
|
|
4219
|
+
* ```
|
|
4220
|
+
*/
|
|
4221
|
+
register(migration) {
|
|
4222
|
+
try {
|
|
4223
|
+
if (!migration.name || !migration.up_sql) {
|
|
4224
|
+
return {
|
|
4225
|
+
error: new Error("Migration name and up_sql are required")
|
|
4226
|
+
};
|
|
4227
|
+
}
|
|
4228
|
+
const key = `${migration.namespace || "default"}:${migration.name}`;
|
|
4229
|
+
this.localMigrations.set(key, migration);
|
|
4230
|
+
return { error: null };
|
|
4231
|
+
} catch (error) {
|
|
4232
|
+
return { error };
|
|
4233
|
+
}
|
|
4234
|
+
}
|
|
4235
|
+
/**
|
|
4236
|
+
* Trigger schema refresh which will restart the server
|
|
4237
|
+
* Handles the restart gracefully by waiting for the server to come back online
|
|
4238
|
+
*
|
|
4239
|
+
* @private
|
|
4240
|
+
*/
|
|
4241
|
+
async triggerSchemaRefreshWithRestart() {
|
|
4242
|
+
console.log("Triggering schema refresh (server will restart)...");
|
|
4243
|
+
try {
|
|
4244
|
+
const response = await this.fetch.post(
|
|
4245
|
+
"/api/v1/admin/schema/refresh",
|
|
4246
|
+
{}
|
|
4247
|
+
);
|
|
4248
|
+
console.log("Server restart initiated:", response.message || "Schema refresh in progress");
|
|
4249
|
+
} catch (error) {
|
|
4250
|
+
const isConnectionError = error.message?.includes("fetch failed") || error.message?.includes("ECONNREFUSED") || error.message?.includes("ECONNRESET") || error.code === "ECONNREFUSED" || error.code === "ECONNRESET";
|
|
4251
|
+
if (!isConnectionError) {
|
|
4252
|
+
throw error;
|
|
4253
|
+
}
|
|
4254
|
+
console.log("Connection dropped (expected during restart)...");
|
|
4255
|
+
}
|
|
4256
|
+
console.log("Waiting 6 seconds for server to restart...");
|
|
4257
|
+
await this.sleep(6e3);
|
|
4258
|
+
const maxAttempts = 5;
|
|
4259
|
+
const baseDelay = 1e3;
|
|
4260
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
4261
|
+
try {
|
|
4262
|
+
await this.fetch.get("/health");
|
|
4263
|
+
console.log("Server is back online and ready");
|
|
4264
|
+
return;
|
|
4265
|
+
} catch (error) {
|
|
4266
|
+
const isLastAttempt = attempt === maxAttempts;
|
|
4267
|
+
if (isLastAttempt) {
|
|
4268
|
+
throw new Error(
|
|
4269
|
+
`Server did not come back online after ${maxAttempts} attempts. Please check server logs and try again.`
|
|
4270
|
+
);
|
|
4271
|
+
}
|
|
4272
|
+
const delay = baseDelay * Math.pow(2, attempt - 1);
|
|
4273
|
+
console.log(`Server not ready yet, retrying in ${delay}ms... (attempt ${attempt}/${maxAttempts})`);
|
|
4274
|
+
await this.sleep(delay);
|
|
4275
|
+
}
|
|
4276
|
+
}
|
|
4277
|
+
}
|
|
4278
|
+
/**
|
|
4279
|
+
* Helper function to sleep for a given duration
|
|
4280
|
+
* @private
|
|
4281
|
+
*/
|
|
4282
|
+
sleep(ms) {
|
|
4283
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
4284
|
+
}
|
|
4285
|
+
/**
|
|
4286
|
+
* Smart sync all registered migrations
|
|
4287
|
+
*
|
|
4288
|
+
* Automatically determines which migrations need to be created or updated by:
|
|
4289
|
+
* 1. Fetching existing migrations from the server
|
|
4290
|
+
* 2. Comparing content hashes to detect changes
|
|
4291
|
+
* 3. Only sending new or changed migrations
|
|
4292
|
+
*
|
|
4293
|
+
* After successful sync, can optionally auto-apply new migrations and refresh
|
|
4294
|
+
* the server's schema cache.
|
|
4295
|
+
*
|
|
4296
|
+
* @param options - Sync options
|
|
4297
|
+
* @returns Promise resolving to { data, error } tuple with sync results
|
|
4298
|
+
*
|
|
4299
|
+
* @example
|
|
4300
|
+
* ```typescript
|
|
4301
|
+
* // Basic sync (idempotent - safe to call on every app startup)
|
|
4302
|
+
* const { data, error } = await client.admin.migrations.sync()
|
|
4303
|
+
* if (data) {
|
|
4304
|
+
* console.log(`Created: ${data.summary.created}, Updated: ${data.summary.updated}`)
|
|
4305
|
+
* }
|
|
4306
|
+
*
|
|
4307
|
+
* // Sync with auto-apply (applies new migrations automatically)
|
|
4308
|
+
* const { data, error } = await client.admin.migrations.sync({
|
|
4309
|
+
* auto_apply: true
|
|
4310
|
+
* })
|
|
4311
|
+
*
|
|
4312
|
+
* // Dry run to preview changes without applying
|
|
4313
|
+
* const { data, error } = await client.admin.migrations.sync({
|
|
4314
|
+
* dry_run: true
|
|
4315
|
+
* })
|
|
4316
|
+
* ```
|
|
4317
|
+
*/
|
|
4318
|
+
async sync(options = {}) {
|
|
4319
|
+
try {
|
|
4320
|
+
const byNamespace = /* @__PURE__ */ new Map();
|
|
4321
|
+
for (const migration of this.localMigrations.values()) {
|
|
4322
|
+
const ns = migration.namespace || "default";
|
|
4323
|
+
if (!byNamespace.has(ns)) {
|
|
4324
|
+
byNamespace.set(ns, []);
|
|
4325
|
+
}
|
|
4326
|
+
byNamespace.get(ns).push(migration);
|
|
4327
|
+
}
|
|
4328
|
+
const results = [];
|
|
4329
|
+
const errors = [];
|
|
4330
|
+
for (const [namespace, migrations] of byNamespace) {
|
|
4331
|
+
try {
|
|
4332
|
+
const result = await this.fetch.post(
|
|
4333
|
+
"/api/v1/admin/migrations/sync",
|
|
4334
|
+
{
|
|
4335
|
+
namespace,
|
|
4336
|
+
migrations: migrations.map((m) => ({
|
|
4337
|
+
name: m.name,
|
|
4338
|
+
description: m.description,
|
|
4339
|
+
up_sql: m.up_sql,
|
|
4340
|
+
down_sql: m.down_sql
|
|
4341
|
+
})),
|
|
4342
|
+
options: {
|
|
4343
|
+
update_if_changed: options.update_if_changed ?? true,
|
|
4344
|
+
auto_apply: options.auto_apply ?? false,
|
|
4345
|
+
dry_run: options.dry_run ?? false
|
|
4346
|
+
}
|
|
4347
|
+
}
|
|
4348
|
+
);
|
|
4349
|
+
results.push(result);
|
|
4350
|
+
} catch (error) {
|
|
4351
|
+
const err = error;
|
|
4352
|
+
if (err.status === 422 && err.details) {
|
|
4353
|
+
results.push(err.details);
|
|
4354
|
+
errors.push(err);
|
|
4355
|
+
} else {
|
|
4356
|
+
throw error;
|
|
4357
|
+
}
|
|
4358
|
+
}
|
|
4359
|
+
}
|
|
4360
|
+
const combined = {
|
|
4361
|
+
message: results.map((r) => r.message).join("; "),
|
|
4362
|
+
namespace: Array.from(byNamespace.keys()).join(", "),
|
|
4363
|
+
summary: {
|
|
4364
|
+
created: results.reduce((sum, r) => sum + r.summary.created, 0),
|
|
4365
|
+
updated: results.reduce((sum, r) => sum + r.summary.updated, 0),
|
|
4366
|
+
unchanged: results.reduce((sum, r) => sum + r.summary.unchanged, 0),
|
|
4367
|
+
skipped: results.reduce((sum, r) => sum + r.summary.skipped, 0),
|
|
4368
|
+
applied: results.reduce((sum, r) => sum + r.summary.applied, 0),
|
|
4369
|
+
errors: results.reduce((sum, r) => sum + r.summary.errors, 0)
|
|
4370
|
+
},
|
|
4371
|
+
details: {
|
|
4372
|
+
created: results.flatMap((r) => r.details.created),
|
|
4373
|
+
updated: results.flatMap((r) => r.details.updated),
|
|
4374
|
+
unchanged: results.flatMap((r) => r.details.unchanged),
|
|
4375
|
+
skipped: results.flatMap((r) => r.details.skipped),
|
|
4376
|
+
applied: results.flatMap((r) => r.details.applied),
|
|
4377
|
+
errors: results.flatMap((r) => r.details.errors)
|
|
4378
|
+
},
|
|
4379
|
+
dry_run: options.dry_run ?? false,
|
|
4380
|
+
warnings: results.flatMap((r) => r.warnings || [])
|
|
4381
|
+
};
|
|
4382
|
+
const hasChanges = combined.summary.created > 0 || combined.summary.updated > 0;
|
|
4383
|
+
if (!combined.dry_run && hasChanges) {
|
|
4384
|
+
try {
|
|
4385
|
+
await this.triggerSchemaRefreshWithRestart();
|
|
4386
|
+
} catch (refreshError) {
|
|
4387
|
+
console.warn("Schema refresh completed with warnings:", refreshError);
|
|
4388
|
+
}
|
|
4389
|
+
}
|
|
4390
|
+
if (errors.length > 0 || combined.summary.errors > 0) {
|
|
4391
|
+
const error = new Error(combined.message);
|
|
4392
|
+
error.syncResult = combined;
|
|
4393
|
+
error.details = combined.details.errors;
|
|
4394
|
+
return { data: combined, error };
|
|
4395
|
+
}
|
|
4396
|
+
return { data: combined, error: null };
|
|
4397
|
+
} catch (error) {
|
|
4398
|
+
return { data: null, error };
|
|
4399
|
+
}
|
|
4400
|
+
}
|
|
4401
|
+
/**
|
|
4402
|
+
* Create a new migration
|
|
4403
|
+
*
|
|
4404
|
+
* @param request - Migration configuration
|
|
4405
|
+
* @returns Promise resolving to { data, error } tuple with created migration
|
|
4406
|
+
*
|
|
4407
|
+
* @example
|
|
4408
|
+
* ```typescript
|
|
4409
|
+
* const { data, error } = await client.admin.migrations.create({
|
|
4410
|
+
* namespace: 'myapp',
|
|
4411
|
+
* name: '001_create_users',
|
|
4412
|
+
* up_sql: 'CREATE TABLE app.users (id UUID PRIMARY KEY, email TEXT)',
|
|
4413
|
+
* down_sql: 'DROP TABLE app.users',
|
|
4414
|
+
* description: 'Create users table'
|
|
4415
|
+
* })
|
|
4416
|
+
* ```
|
|
4417
|
+
*/
|
|
4418
|
+
async create(request) {
|
|
4419
|
+
try {
|
|
4420
|
+
const data = await this.fetch.post("/api/v1/admin/migrations", request);
|
|
4421
|
+
return { data, error: null };
|
|
4422
|
+
} catch (error) {
|
|
4423
|
+
return { data: null, error };
|
|
4424
|
+
}
|
|
4425
|
+
}
|
|
4426
|
+
/**
|
|
4427
|
+
* List migrations in a namespace
|
|
4428
|
+
*
|
|
4429
|
+
* @param namespace - Migration namespace (default: 'default')
|
|
4430
|
+
* @param status - Filter by status: 'pending', 'applied', 'failed', 'rolled_back'
|
|
4431
|
+
* @returns Promise resolving to { data, error } tuple with migrations array
|
|
4432
|
+
*
|
|
4433
|
+
* @example
|
|
4434
|
+
* ```typescript
|
|
4435
|
+
* // List all migrations
|
|
4436
|
+
* const { data, error } = await client.admin.migrations.list('myapp')
|
|
4437
|
+
*
|
|
4438
|
+
* // List only pending migrations
|
|
4439
|
+
* const { data, error } = await client.admin.migrations.list('myapp', 'pending')
|
|
4440
|
+
* ```
|
|
4441
|
+
*/
|
|
4442
|
+
async list(namespace = "default", status) {
|
|
4443
|
+
try {
|
|
4444
|
+
const params = new URLSearchParams({ namespace });
|
|
4445
|
+
if (status) params.append("status", status);
|
|
4446
|
+
const data = await this.fetch.get(
|
|
4447
|
+
`/api/v1/admin/migrations?${params.toString()}`
|
|
4448
|
+
);
|
|
4449
|
+
return { data, error: null };
|
|
4450
|
+
} catch (error) {
|
|
4451
|
+
return { data: null, error };
|
|
4452
|
+
}
|
|
4453
|
+
}
|
|
4454
|
+
/**
|
|
4455
|
+
* Get details of a specific migration
|
|
4456
|
+
*
|
|
4457
|
+
* @param name - Migration name
|
|
4458
|
+
* @param namespace - Migration namespace (default: 'default')
|
|
4459
|
+
* @returns Promise resolving to { data, error } tuple with migration details
|
|
4460
|
+
*
|
|
4461
|
+
* @example
|
|
4462
|
+
* ```typescript
|
|
4463
|
+
* const { data, error } = await client.admin.migrations.get('001_create_users', 'myapp')
|
|
4464
|
+
* ```
|
|
4465
|
+
*/
|
|
4466
|
+
async get(name, namespace = "default") {
|
|
4467
|
+
try {
|
|
4468
|
+
const params = new URLSearchParams({ namespace });
|
|
4469
|
+
const data = await this.fetch.get(
|
|
4470
|
+
`/api/v1/admin/migrations/${name}?${params.toString()}`
|
|
4471
|
+
);
|
|
4472
|
+
return { data, error: null };
|
|
4473
|
+
} catch (error) {
|
|
4474
|
+
return { data: null, error };
|
|
4475
|
+
}
|
|
4476
|
+
}
|
|
4477
|
+
/**
|
|
4478
|
+
* Update a migration (only if status is pending)
|
|
4479
|
+
*
|
|
4480
|
+
* @param name - Migration name
|
|
4481
|
+
* @param updates - Fields to update
|
|
4482
|
+
* @param namespace - Migration namespace (default: 'default')
|
|
4483
|
+
* @returns Promise resolving to { data, error } tuple with updated migration
|
|
4484
|
+
*
|
|
4485
|
+
* @example
|
|
4486
|
+
* ```typescript
|
|
4487
|
+
* const { data, error } = await client.admin.migrations.update(
|
|
4488
|
+
* '001_create_users',
|
|
4489
|
+
* { description: 'Updated description' },
|
|
4490
|
+
* 'myapp'
|
|
4491
|
+
* )
|
|
4492
|
+
* ```
|
|
4493
|
+
*/
|
|
4494
|
+
async update(name, updates, namespace = "default") {
|
|
4495
|
+
try {
|
|
4496
|
+
const params = new URLSearchParams({ namespace });
|
|
4497
|
+
const data = await this.fetch.put(
|
|
4498
|
+
`/api/v1/admin/migrations/${name}?${params.toString()}`,
|
|
4499
|
+
updates
|
|
4500
|
+
);
|
|
4501
|
+
return { data, error: null };
|
|
4502
|
+
} catch (error) {
|
|
4503
|
+
return { data: null, error };
|
|
4504
|
+
}
|
|
4505
|
+
}
|
|
4506
|
+
/**
|
|
4507
|
+
* Delete a migration (only if status is pending)
|
|
4508
|
+
*
|
|
4509
|
+
* @param name - Migration name
|
|
4510
|
+
* @param namespace - Migration namespace (default: 'default')
|
|
4511
|
+
* @returns Promise resolving to { data, error } tuple
|
|
4512
|
+
*
|
|
4513
|
+
* @example
|
|
4514
|
+
* ```typescript
|
|
4515
|
+
* const { data, error } = await client.admin.migrations.delete('001_create_users', 'myapp')
|
|
4516
|
+
* ```
|
|
4517
|
+
*/
|
|
4518
|
+
async delete(name, namespace = "default") {
|
|
4519
|
+
try {
|
|
4520
|
+
const params = new URLSearchParams({ namespace });
|
|
4521
|
+
await this.fetch.delete(`/api/v1/admin/migrations/${name}?${params.toString()}`);
|
|
4522
|
+
return { data: null, error: null };
|
|
4523
|
+
} catch (error) {
|
|
4524
|
+
return { data: null, error };
|
|
4525
|
+
}
|
|
4526
|
+
}
|
|
4527
|
+
/**
|
|
4528
|
+
* Apply a specific migration
|
|
4529
|
+
*
|
|
4530
|
+
* @param name - Migration name
|
|
4531
|
+
* @param namespace - Migration namespace (default: 'default')
|
|
4532
|
+
* @returns Promise resolving to { data, error } tuple with result message
|
|
4533
|
+
*
|
|
4534
|
+
* @example
|
|
4535
|
+
* ```typescript
|
|
4536
|
+
* const { data, error } = await client.admin.migrations.apply('001_create_users', 'myapp')
|
|
4537
|
+
* if (data) {
|
|
4538
|
+
* console.log(data.message) // "Migration applied successfully"
|
|
4539
|
+
* }
|
|
4540
|
+
* ```
|
|
4541
|
+
*/
|
|
4542
|
+
async apply(name, namespace = "default") {
|
|
4543
|
+
try {
|
|
4544
|
+
const data = await this.fetch.post(
|
|
4545
|
+
`/api/v1/admin/migrations/${name}/apply`,
|
|
4546
|
+
{ namespace }
|
|
4547
|
+
);
|
|
4548
|
+
return { data, error: null };
|
|
4549
|
+
} catch (error) {
|
|
4550
|
+
return { data: null, error };
|
|
4551
|
+
}
|
|
4552
|
+
}
|
|
4553
|
+
/**
|
|
4554
|
+
* Rollback a specific migration
|
|
4555
|
+
*
|
|
4556
|
+
* @param name - Migration name
|
|
4557
|
+
* @param namespace - Migration namespace (default: 'default')
|
|
4558
|
+
* @returns Promise resolving to { data, error } tuple with result message
|
|
4559
|
+
*
|
|
4560
|
+
* @example
|
|
4561
|
+
* ```typescript
|
|
4562
|
+
* const { data, error } = await client.admin.migrations.rollback('001_create_users', 'myapp')
|
|
4563
|
+
* ```
|
|
4564
|
+
*/
|
|
4565
|
+
async rollback(name, namespace = "default") {
|
|
4566
|
+
try {
|
|
4567
|
+
const data = await this.fetch.post(
|
|
4568
|
+
`/api/v1/admin/migrations/${name}/rollback`,
|
|
4569
|
+
{ namespace }
|
|
4570
|
+
);
|
|
4571
|
+
return { data, error: null };
|
|
4572
|
+
} catch (error) {
|
|
4573
|
+
return { data: null, error };
|
|
4574
|
+
}
|
|
4575
|
+
}
|
|
4576
|
+
/**
|
|
4577
|
+
* Apply all pending migrations in order
|
|
4578
|
+
*
|
|
4579
|
+
* @param namespace - Migration namespace (default: 'default')
|
|
4580
|
+
* @returns Promise resolving to { data, error } tuple with applied/failed counts
|
|
4581
|
+
*
|
|
4582
|
+
* @example
|
|
4583
|
+
* ```typescript
|
|
4584
|
+
* const { data, error } = await client.admin.migrations.applyPending('myapp')
|
|
4585
|
+
* if (data) {
|
|
4586
|
+
* console.log(`Applied: ${data.applied.length}, Failed: ${data.failed.length}`)
|
|
4587
|
+
* }
|
|
4588
|
+
* ```
|
|
4589
|
+
*/
|
|
4590
|
+
async applyPending(namespace = "default") {
|
|
4591
|
+
try {
|
|
4592
|
+
const data = await this.fetch.post("/api/v1/admin/migrations/apply-pending", { namespace });
|
|
4593
|
+
return { data, error: null };
|
|
4594
|
+
} catch (error) {
|
|
4595
|
+
return { data: null, error };
|
|
4596
|
+
}
|
|
4597
|
+
}
|
|
4598
|
+
/**
|
|
4599
|
+
* Get execution history for a migration
|
|
4600
|
+
*
|
|
4601
|
+
* @param name - Migration name
|
|
4602
|
+
* @param namespace - Migration namespace (default: 'default')
|
|
4603
|
+
* @param limit - Maximum number of executions to return (default: 50, max: 100)
|
|
4604
|
+
* @returns Promise resolving to { data, error } tuple with execution records
|
|
4605
|
+
*
|
|
4606
|
+
* @example
|
|
4607
|
+
* ```typescript
|
|
4608
|
+
* const { data, error } = await client.admin.migrations.getExecutions(
|
|
4609
|
+
* '001_create_users',
|
|
4610
|
+
* 'myapp',
|
|
4611
|
+
* 10
|
|
4612
|
+
* )
|
|
4613
|
+
* if (data) {
|
|
4614
|
+
* data.forEach(exec => {
|
|
4615
|
+
* console.log(`${exec.executed_at}: ${exec.action} - ${exec.status}`)
|
|
4616
|
+
* })
|
|
4617
|
+
* }
|
|
4618
|
+
* ```
|
|
4619
|
+
*/
|
|
4620
|
+
async getExecutions(name, namespace = "default", limit = 50) {
|
|
4621
|
+
try {
|
|
4622
|
+
const params = new URLSearchParams({ namespace, limit: limit.toString() });
|
|
4623
|
+
const data = await this.fetch.get(
|
|
4624
|
+
`/api/v1/admin/migrations/${name}/executions?${params.toString()}`
|
|
4625
|
+
);
|
|
4626
|
+
return { data, error: null };
|
|
4627
|
+
} catch (error) {
|
|
4628
|
+
return { data: null, error };
|
|
4629
|
+
}
|
|
4630
|
+
}
|
|
4631
|
+
};
|
|
4632
|
+
|
|
4633
|
+
// src/admin-jobs.ts
|
|
4634
|
+
var esbuild = null;
|
|
4635
|
+
async function loadEsbuild() {
|
|
4636
|
+
if (esbuild) return true;
|
|
4637
|
+
try {
|
|
4638
|
+
esbuild = await import('esbuild');
|
|
4639
|
+
return true;
|
|
4640
|
+
} catch {
|
|
4641
|
+
return false;
|
|
4642
|
+
}
|
|
4643
|
+
}
|
|
4644
|
+
var FluxbaseAdminJobs = class _FluxbaseAdminJobs {
|
|
4645
|
+
constructor(fetch2) {
|
|
4646
|
+
this.fetch = fetch2;
|
|
4647
|
+
}
|
|
4648
|
+
/**
|
|
4649
|
+
* Create a new job function
|
|
4650
|
+
*
|
|
4651
|
+
* @param request - Job function configuration and code
|
|
4652
|
+
* @returns Promise resolving to { data, error } tuple with created job function metadata
|
|
4653
|
+
*
|
|
4654
|
+
* @example
|
|
4655
|
+
* ```typescript
|
|
4656
|
+
* const { data, error } = await client.admin.jobs.create({
|
|
4657
|
+
* name: 'process-data',
|
|
4658
|
+
* code: 'export async function handler(req) { return { success: true } }',
|
|
4659
|
+
* enabled: true,
|
|
4660
|
+
* timeout_seconds: 300
|
|
4661
|
+
* })
|
|
4662
|
+
* ```
|
|
4663
|
+
*/
|
|
4664
|
+
async create(request) {
|
|
4665
|
+
try {
|
|
4666
|
+
const data = await this.fetch.post(
|
|
4667
|
+
"/api/v1/admin/jobs/functions",
|
|
4668
|
+
request
|
|
4669
|
+
);
|
|
4670
|
+
return { data, error: null };
|
|
4671
|
+
} catch (error) {
|
|
4672
|
+
return { data: null, error };
|
|
4673
|
+
}
|
|
4674
|
+
}
|
|
4675
|
+
/**
|
|
4676
|
+
* List all namespaces that have job functions
|
|
4677
|
+
*
|
|
4678
|
+
* @returns Promise resolving to { data, error } tuple with array of namespace strings
|
|
4679
|
+
*
|
|
4680
|
+
* @example
|
|
4681
|
+
* ```typescript
|
|
4682
|
+
* const { data, error } = await client.admin.jobs.listNamespaces()
|
|
4683
|
+
* if (data) {
|
|
4684
|
+
* console.log('Available namespaces:', data)
|
|
4685
|
+
* }
|
|
4686
|
+
* ```
|
|
4687
|
+
*/
|
|
4688
|
+
async listNamespaces() {
|
|
4689
|
+
try {
|
|
4690
|
+
const response = await this.fetch.get(
|
|
4691
|
+
"/api/v1/admin/jobs/namespaces"
|
|
4692
|
+
);
|
|
4693
|
+
return { data: response.namespaces || ["default"], error: null };
|
|
4694
|
+
} catch (error) {
|
|
4695
|
+
return { data: null, error };
|
|
4696
|
+
}
|
|
4697
|
+
}
|
|
4698
|
+
/**
|
|
4699
|
+
* List all job functions (admin view)
|
|
4700
|
+
*
|
|
4701
|
+
* @param namespace - Optional namespace filter
|
|
4702
|
+
* @returns Promise resolving to { data, error } tuple with array of job functions
|
|
4703
|
+
*
|
|
4704
|
+
* @example
|
|
4705
|
+
* ```typescript
|
|
4706
|
+
* const { data, error } = await client.admin.jobs.list('default')
|
|
4707
|
+
* if (data) {
|
|
4708
|
+
* console.log('Job functions:', data.map(f => f.name))
|
|
4709
|
+
* }
|
|
4710
|
+
* ```
|
|
4711
|
+
*/
|
|
4712
|
+
async list(namespace) {
|
|
4713
|
+
try {
|
|
4714
|
+
const params = namespace ? `?namespace=${namespace}` : "";
|
|
4715
|
+
const data = await this.fetch.get(
|
|
4716
|
+
`/api/v1/admin/jobs/functions${params}`
|
|
4717
|
+
);
|
|
4718
|
+
return { data, error: null };
|
|
4719
|
+
} catch (error) {
|
|
4720
|
+
return { data: null, error };
|
|
4721
|
+
}
|
|
4722
|
+
}
|
|
4723
|
+
/**
|
|
4724
|
+
* Get details of a specific job function
|
|
4725
|
+
*
|
|
4726
|
+
* @param namespace - Namespace
|
|
4727
|
+
* @param name - Job function name
|
|
4728
|
+
* @returns Promise resolving to { data, error } tuple with job function metadata
|
|
4729
|
+
*
|
|
4730
|
+
* @example
|
|
4731
|
+
* ```typescript
|
|
4732
|
+
* const { data, error } = await client.admin.jobs.get('default', 'process-data')
|
|
4733
|
+
* if (data) {
|
|
4734
|
+
* console.log('Job function version:', data.version)
|
|
4735
|
+
* }
|
|
4736
|
+
* ```
|
|
4737
|
+
*/
|
|
4738
|
+
async get(namespace, name) {
|
|
4739
|
+
try {
|
|
4740
|
+
const data = await this.fetch.get(
|
|
4741
|
+
`/api/v1/admin/jobs/functions/${namespace}/${name}`
|
|
4742
|
+
);
|
|
4743
|
+
return { data, error: null };
|
|
4744
|
+
} catch (error) {
|
|
4745
|
+
return { data: null, error };
|
|
4746
|
+
}
|
|
4747
|
+
}
|
|
4748
|
+
/**
|
|
4749
|
+
* Update an existing job function
|
|
4750
|
+
*
|
|
4751
|
+
* @param namespace - Namespace
|
|
4752
|
+
* @param name - Job function name
|
|
4753
|
+
* @param updates - Fields to update
|
|
4754
|
+
* @returns Promise resolving to { data, error } tuple with updated job function metadata
|
|
4755
|
+
*
|
|
4756
|
+
* @example
|
|
4757
|
+
* ```typescript
|
|
4758
|
+
* const { data, error } = await client.admin.jobs.update('default', 'process-data', {
|
|
4759
|
+
* enabled: false,
|
|
4760
|
+
* timeout_seconds: 600
|
|
4761
|
+
* })
|
|
4762
|
+
* ```
|
|
4763
|
+
*/
|
|
4764
|
+
async update(namespace, name, updates) {
|
|
4765
|
+
try {
|
|
4766
|
+
const data = await this.fetch.put(
|
|
4767
|
+
`/api/v1/admin/jobs/functions/${namespace}/${name}`,
|
|
4768
|
+
updates
|
|
4769
|
+
);
|
|
4770
|
+
return { data, error: null };
|
|
4771
|
+
} catch (error) {
|
|
4772
|
+
return { data: null, error };
|
|
4773
|
+
}
|
|
4774
|
+
}
|
|
4775
|
+
/**
|
|
4776
|
+
* Delete a job function
|
|
4777
|
+
*
|
|
4778
|
+
* @param namespace - Namespace
|
|
4779
|
+
* @param name - Job function name
|
|
4780
|
+
* @returns Promise resolving to { data, error } tuple
|
|
4781
|
+
*
|
|
4782
|
+
* @example
|
|
4783
|
+
* ```typescript
|
|
4784
|
+
* const { data, error } = await client.admin.jobs.delete('default', 'process-data')
|
|
4785
|
+
* ```
|
|
4786
|
+
*/
|
|
4787
|
+
async delete(namespace, name) {
|
|
4788
|
+
try {
|
|
4789
|
+
await this.fetch.delete(
|
|
4790
|
+
`/api/v1/admin/jobs/functions/${namespace}/${name}`
|
|
4791
|
+
);
|
|
4792
|
+
return { data: null, error: null };
|
|
4793
|
+
} catch (error) {
|
|
4794
|
+
return { data: null, error };
|
|
4795
|
+
}
|
|
4796
|
+
}
|
|
4797
|
+
/**
|
|
4798
|
+
* List all jobs (executions) across all namespaces (admin view)
|
|
4799
|
+
*
|
|
4800
|
+
* @param filters - Optional filters (status, namespace, limit, offset)
|
|
4801
|
+
* @returns Promise resolving to { data, error } tuple with array of jobs
|
|
4802
|
+
*
|
|
4803
|
+
* @example
|
|
4804
|
+
* ```typescript
|
|
4805
|
+
* const { data, error } = await client.admin.jobs.listJobs({
|
|
4806
|
+
* status: 'running',
|
|
4807
|
+
* namespace: 'default',
|
|
4808
|
+
* limit: 50
|
|
4809
|
+
* })
|
|
4810
|
+
* if (data) {
|
|
4811
|
+
* data.forEach(job => {
|
|
4812
|
+
* console.log(`${job.job_name}: ${job.status}`)
|
|
4813
|
+
* })
|
|
4814
|
+
* }
|
|
4815
|
+
* ```
|
|
4816
|
+
*/
|
|
4817
|
+
async listJobs(filters) {
|
|
4818
|
+
try {
|
|
4819
|
+
const params = new URLSearchParams();
|
|
4820
|
+
if (filters?.status) params.append("status", filters.status);
|
|
4821
|
+
if (filters?.namespace) params.append("namespace", filters.namespace);
|
|
4822
|
+
if (filters?.limit) params.append("limit", filters.limit.toString());
|
|
4823
|
+
if (filters?.offset) params.append("offset", filters.offset.toString());
|
|
4824
|
+
const queryString = params.toString();
|
|
4825
|
+
const data = await this.fetch.get(
|
|
4826
|
+
`/api/v1/admin/jobs/queue${queryString ? `?${queryString}` : ""}`
|
|
4827
|
+
);
|
|
4828
|
+
return { data, error: null };
|
|
4829
|
+
} catch (error) {
|
|
4830
|
+
return { data: null, error };
|
|
4831
|
+
}
|
|
4832
|
+
}
|
|
4833
|
+
/**
|
|
4834
|
+
* Get details of a specific job (execution)
|
|
4835
|
+
*
|
|
4836
|
+
* @param jobId - Job ID
|
|
4837
|
+
* @returns Promise resolving to { data, error } tuple with job details
|
|
4838
|
+
*
|
|
4839
|
+
* @example
|
|
4840
|
+
* ```typescript
|
|
4841
|
+
* const { data, error } = await client.admin.jobs.getJob('550e8400-e29b-41d4-a716-446655440000')
|
|
4842
|
+
* if (data) {
|
|
4843
|
+
* console.log(`Job ${data.job_name}: ${data.status}`)
|
|
4844
|
+
* }
|
|
4845
|
+
* ```
|
|
4846
|
+
*/
|
|
4847
|
+
async getJob(jobId) {
|
|
4848
|
+
try {
|
|
4849
|
+
const data = await this.fetch.get(`/api/v1/admin/jobs/queue/${jobId}`);
|
|
4850
|
+
return { data, error: null };
|
|
4851
|
+
} catch (error) {
|
|
4852
|
+
return { data: null, error };
|
|
4853
|
+
}
|
|
4854
|
+
}
|
|
4855
|
+
/**
|
|
4856
|
+
* Cancel a running or pending job
|
|
4857
|
+
*
|
|
4858
|
+
* @param jobId - Job ID
|
|
4859
|
+
* @returns Promise resolving to { data, error } tuple
|
|
4860
|
+
*
|
|
4861
|
+
* @example
|
|
4862
|
+
* ```typescript
|
|
4863
|
+
* const { data, error } = await client.admin.jobs.cancel('550e8400-e29b-41d4-a716-446655440000')
|
|
4864
|
+
* ```
|
|
4865
|
+
*/
|
|
4866
|
+
async cancel(jobId) {
|
|
4867
|
+
try {
|
|
4868
|
+
await this.fetch.post(`/api/v1/admin/jobs/queue/${jobId}/cancel`, {});
|
|
4869
|
+
return { data: null, error: null };
|
|
4870
|
+
} catch (error) {
|
|
4871
|
+
return { data: null, error };
|
|
4872
|
+
}
|
|
4873
|
+
}
|
|
4874
|
+
/**
|
|
4875
|
+
* Terminate a running job immediately
|
|
4876
|
+
*
|
|
4877
|
+
* @param jobId - Job ID
|
|
4878
|
+
* @returns Promise resolving to { data, error } tuple
|
|
4879
|
+
*
|
|
4880
|
+
* @example
|
|
4881
|
+
* ```typescript
|
|
4882
|
+
* const { data, error } = await client.admin.jobs.terminate('550e8400-e29b-41d4-a716-446655440000')
|
|
4883
|
+
* ```
|
|
4884
|
+
*/
|
|
4885
|
+
async terminate(jobId) {
|
|
4886
|
+
try {
|
|
4887
|
+
await this.fetch.post(`/api/v1/admin/jobs/queue/${jobId}/terminate`, {});
|
|
4888
|
+
return { data: null, error: null };
|
|
4889
|
+
} catch (error) {
|
|
4890
|
+
return { data: null, error };
|
|
4891
|
+
}
|
|
4892
|
+
}
|
|
4893
|
+
/**
|
|
4894
|
+
* Retry a failed job
|
|
4895
|
+
*
|
|
4896
|
+
* @param jobId - Job ID
|
|
4897
|
+
* @returns Promise resolving to { data, error } tuple with new job
|
|
4898
|
+
*
|
|
4899
|
+
* @example
|
|
4900
|
+
* ```typescript
|
|
4901
|
+
* const { data, error } = await client.admin.jobs.retry('550e8400-e29b-41d4-a716-446655440000')
|
|
4902
|
+
* ```
|
|
4903
|
+
*/
|
|
4904
|
+
async retry(jobId) {
|
|
4905
|
+
try {
|
|
4906
|
+
const data = await this.fetch.post(
|
|
4907
|
+
`/api/v1/admin/jobs/queue/${jobId}/retry`,
|
|
4908
|
+
{}
|
|
4909
|
+
);
|
|
4910
|
+
return { data, error: null };
|
|
4911
|
+
} catch (error) {
|
|
4912
|
+
return { data: null, error };
|
|
4913
|
+
}
|
|
4914
|
+
}
|
|
4915
|
+
/**
|
|
4916
|
+
* Get job statistics
|
|
4917
|
+
*
|
|
4918
|
+
* @param namespace - Optional namespace filter
|
|
4919
|
+
* @returns Promise resolving to { data, error } tuple with job stats
|
|
4920
|
+
*
|
|
4921
|
+
* @example
|
|
4922
|
+
* ```typescript
|
|
4923
|
+
* const { data, error } = await client.admin.jobs.getStats('default')
|
|
4924
|
+
* if (data) {
|
|
4925
|
+
* console.log(`Pending: ${data.pending}, Running: ${data.running}`)
|
|
4926
|
+
* }
|
|
4927
|
+
* ```
|
|
4928
|
+
*/
|
|
4929
|
+
async getStats(namespace) {
|
|
4930
|
+
try {
|
|
4931
|
+
const params = namespace ? `?namespace=${namespace}` : "";
|
|
4932
|
+
const data = await this.fetch.get(
|
|
4933
|
+
`/api/v1/admin/jobs/stats${params}`
|
|
4934
|
+
);
|
|
4935
|
+
return { data, error: null };
|
|
4936
|
+
} catch (error) {
|
|
4937
|
+
return { data: null, error };
|
|
4938
|
+
}
|
|
4939
|
+
}
|
|
4940
|
+
/**
|
|
4941
|
+
* List active workers
|
|
4942
|
+
*
|
|
4943
|
+
* @returns Promise resolving to { data, error } tuple with array of workers
|
|
4944
|
+
*
|
|
4945
|
+
* @example
|
|
4946
|
+
* ```typescript
|
|
4947
|
+
* const { data, error } = await client.admin.jobs.listWorkers()
|
|
4948
|
+
* if (data) {
|
|
4949
|
+
* data.forEach(worker => {
|
|
4950
|
+
* console.log(`Worker ${worker.id}: ${worker.current_jobs} jobs`)
|
|
4951
|
+
* })
|
|
4952
|
+
* }
|
|
4953
|
+
* ```
|
|
4954
|
+
*/
|
|
4955
|
+
async listWorkers() {
|
|
4956
|
+
try {
|
|
4957
|
+
const data = await this.fetch.get(
|
|
4958
|
+
"/api/v1/admin/jobs/workers"
|
|
4959
|
+
);
|
|
4960
|
+
return { data, error: null };
|
|
4961
|
+
} catch (error) {
|
|
4962
|
+
return { data: null, error };
|
|
4963
|
+
}
|
|
4964
|
+
}
|
|
4965
|
+
/**
|
|
4966
|
+
* Sync multiple job functions to a namespace
|
|
4967
|
+
*
|
|
4968
|
+
* Can sync from:
|
|
4969
|
+
* 1. Filesystem (if no jobs provided) - loads from configured jobs directory
|
|
4970
|
+
* 2. API payload (if jobs array provided) - syncs provided job specifications
|
|
4971
|
+
*
|
|
4972
|
+
* Requires service_role or admin authentication.
|
|
4973
|
+
*
|
|
4974
|
+
* @param options - Sync options including namespace and optional jobs array
|
|
4975
|
+
* @returns Promise resolving to { data, error } tuple with sync results
|
|
4976
|
+
*
|
|
4977
|
+
* @example
|
|
4978
|
+
* ```typescript
|
|
4979
|
+
* // Sync from filesystem
|
|
4980
|
+
* const { data, error } = await client.admin.jobs.sync({ namespace: 'default' })
|
|
4981
|
+
*
|
|
4982
|
+
* // Sync with pre-bundled code (client-side bundling)
|
|
4983
|
+
* const bundled = await FluxbaseAdminJobs.bundleCode({ code: myJobCode })
|
|
4984
|
+
* const { data, error } = await client.admin.jobs.sync({
|
|
4985
|
+
* namespace: 'default',
|
|
4986
|
+
* functions: [{
|
|
4987
|
+
* name: 'my-job',
|
|
4988
|
+
* code: bundled.code,
|
|
4989
|
+
* is_pre_bundled: true,
|
|
4990
|
+
* original_code: myJobCode,
|
|
4991
|
+
* }],
|
|
4992
|
+
* options: {
|
|
4993
|
+
* delete_missing: true, // Remove jobs not in this sync
|
|
4994
|
+
* dry_run: false, // Preview changes without applying
|
|
4995
|
+
* }
|
|
4996
|
+
* })
|
|
4997
|
+
*
|
|
4998
|
+
* if (data) {
|
|
4999
|
+
* console.log(`Synced: ${data.summary.created} created, ${data.summary.updated} updated`)
|
|
5000
|
+
* }
|
|
5001
|
+
* ```
|
|
5002
|
+
*/
|
|
5003
|
+
async sync(options) {
|
|
5004
|
+
try {
|
|
5005
|
+
const syncOptions = typeof options === "string" ? { namespace: options } : options;
|
|
5006
|
+
const data = await this.fetch.post(
|
|
5007
|
+
"/api/v1/admin/jobs/sync",
|
|
5008
|
+
{
|
|
5009
|
+
namespace: syncOptions.namespace,
|
|
5010
|
+
jobs: syncOptions.functions,
|
|
5011
|
+
options: {
|
|
5012
|
+
delete_missing: syncOptions.options?.delete_missing ?? false,
|
|
5013
|
+
dry_run: syncOptions.options?.dry_run ?? false
|
|
5014
|
+
}
|
|
5015
|
+
}
|
|
5016
|
+
);
|
|
5017
|
+
return { data, error: null };
|
|
5018
|
+
} catch (error) {
|
|
5019
|
+
return { data: null, error };
|
|
5020
|
+
}
|
|
5021
|
+
}
|
|
5022
|
+
/**
|
|
5023
|
+
* Sync job functions with automatic client-side bundling
|
|
5024
|
+
*
|
|
5025
|
+
* This is a convenience method that bundles all job code using esbuild
|
|
5026
|
+
* before sending to the server. Requires esbuild as a peer dependency.
|
|
5027
|
+
*
|
|
5028
|
+
* @param options - Sync options including namespace and jobs array
|
|
5029
|
+
* @param bundleOptions - Optional bundling configuration
|
|
5030
|
+
* @returns Promise resolving to { data, error } tuple with sync results
|
|
5031
|
+
*
|
|
5032
|
+
* @example
|
|
5033
|
+
* ```typescript
|
|
5034
|
+
* const { data, error } = await client.admin.jobs.syncWithBundling({
|
|
5035
|
+
* namespace: 'default',
|
|
5036
|
+
* functions: [
|
|
5037
|
+
* { name: 'process-data', code: processDataCode },
|
|
5038
|
+
* { name: 'send-email', code: sendEmailCode },
|
|
5039
|
+
* ],
|
|
5040
|
+
* options: { delete_missing: true }
|
|
5041
|
+
* })
|
|
5042
|
+
* ```
|
|
5043
|
+
*/
|
|
5044
|
+
async syncWithBundling(options, bundleOptions) {
|
|
5045
|
+
if (!options.functions || options.functions.length === 0) {
|
|
5046
|
+
return this.sync(options);
|
|
5047
|
+
}
|
|
5048
|
+
const hasEsbuild = await loadEsbuild();
|
|
5049
|
+
if (!hasEsbuild) {
|
|
5050
|
+
return {
|
|
5051
|
+
data: null,
|
|
5052
|
+
error: new Error(
|
|
5053
|
+
"esbuild is required for client-side bundling. Install it with: npm install esbuild"
|
|
5054
|
+
)
|
|
5055
|
+
};
|
|
5056
|
+
}
|
|
5057
|
+
try {
|
|
5058
|
+
const bundledFunctions = await Promise.all(
|
|
5059
|
+
options.functions.map(async (fn) => {
|
|
5060
|
+
if (fn.is_pre_bundled) {
|
|
5061
|
+
return fn;
|
|
5062
|
+
}
|
|
5063
|
+
const bundled = await _FluxbaseAdminJobs.bundleCode({
|
|
5064
|
+
code: fn.code,
|
|
5065
|
+
...bundleOptions
|
|
5066
|
+
});
|
|
5067
|
+
return {
|
|
5068
|
+
...fn,
|
|
5069
|
+
code: bundled.code,
|
|
5070
|
+
original_code: fn.code,
|
|
5071
|
+
is_pre_bundled: true
|
|
5072
|
+
};
|
|
5073
|
+
})
|
|
5074
|
+
);
|
|
5075
|
+
return this.sync({
|
|
5076
|
+
...options,
|
|
5077
|
+
functions: bundledFunctions
|
|
5078
|
+
});
|
|
5079
|
+
} catch (error) {
|
|
5080
|
+
return { data: null, error };
|
|
5081
|
+
}
|
|
5082
|
+
}
|
|
5083
|
+
/**
|
|
5084
|
+
* Bundle job code using esbuild (client-side)
|
|
5085
|
+
*
|
|
5086
|
+
* Transforms and bundles TypeScript/JavaScript code into a single file
|
|
5087
|
+
* that can be executed by the Fluxbase jobs runtime.
|
|
5088
|
+
*
|
|
5089
|
+
* Requires esbuild as a peer dependency.
|
|
5090
|
+
*
|
|
5091
|
+
* @param options - Bundle options including source code
|
|
5092
|
+
* @returns Promise resolving to bundled code
|
|
5093
|
+
* @throws Error if esbuild is not available
|
|
5094
|
+
*
|
|
5095
|
+
* @example
|
|
5096
|
+
* ```typescript
|
|
5097
|
+
* const bundled = await FluxbaseAdminJobs.bundleCode({
|
|
5098
|
+
* code: `
|
|
5099
|
+
* import { helper } from './utils'
|
|
5100
|
+
* export async function handler(req) {
|
|
5101
|
+
* return helper(req.payload)
|
|
5102
|
+
* }
|
|
5103
|
+
* `,
|
|
5104
|
+
* minify: true,
|
|
5105
|
+
* })
|
|
5106
|
+
*
|
|
5107
|
+
* // Use bundled code in sync
|
|
5108
|
+
* await client.admin.jobs.sync({
|
|
5109
|
+
* namespace: 'default',
|
|
5110
|
+
* functions: [{
|
|
5111
|
+
* name: 'my-job',
|
|
5112
|
+
* code: bundled.code,
|
|
5113
|
+
* is_pre_bundled: true,
|
|
5114
|
+
* }]
|
|
5115
|
+
* })
|
|
5116
|
+
* ```
|
|
5117
|
+
*/
|
|
5118
|
+
static async bundleCode(options) {
|
|
5119
|
+
const hasEsbuild = await loadEsbuild();
|
|
5120
|
+
if (!hasEsbuild || !esbuild) {
|
|
5121
|
+
throw new Error(
|
|
5122
|
+
"esbuild is required for bundling. Install it with: npm install esbuild"
|
|
5123
|
+
);
|
|
5124
|
+
}
|
|
5125
|
+
const result = await esbuild.build({
|
|
5126
|
+
stdin: {
|
|
5127
|
+
contents: options.code,
|
|
5128
|
+
loader: "ts",
|
|
5129
|
+
resolveDir: process.cwd?.() || "/"
|
|
5130
|
+
},
|
|
5131
|
+
bundle: true,
|
|
5132
|
+
write: false,
|
|
5133
|
+
format: "esm",
|
|
5134
|
+
platform: "neutral",
|
|
5135
|
+
target: "esnext",
|
|
5136
|
+
minify: options.minify ?? false,
|
|
5137
|
+
sourcemap: options.sourcemap ? "inline" : false,
|
|
5138
|
+
external: options.external ?? [],
|
|
5139
|
+
// Preserve handler export
|
|
5140
|
+
treeShaking: true
|
|
5141
|
+
});
|
|
5142
|
+
const output = result.outputFiles?.[0];
|
|
5143
|
+
if (!output) {
|
|
5144
|
+
throw new Error("Bundling failed: no output generated");
|
|
5145
|
+
}
|
|
5146
|
+
return {
|
|
5147
|
+
code: output.text,
|
|
5148
|
+
sourceMap: options.sourcemap ? output.text : void 0
|
|
5149
|
+
};
|
|
5150
|
+
}
|
|
5151
|
+
};
|
|
5152
|
+
|
|
3857
5153
|
// src/admin.ts
|
|
3858
5154
|
var FluxbaseAdmin = class {
|
|
3859
5155
|
constructor(fetch2) {
|
|
@@ -3865,6 +5161,9 @@ var FluxbaseAdmin = class {
|
|
|
3865
5161
|
this.impersonation = new ImpersonationManager(fetch2);
|
|
3866
5162
|
this.management = new FluxbaseManagement(fetch2);
|
|
3867
5163
|
this.emailTemplates = new EmailTemplateManager(fetch2);
|
|
5164
|
+
this.functions = new FluxbaseAdminFunctions(fetch2);
|
|
5165
|
+
this.jobs = new FluxbaseAdminJobs(fetch2);
|
|
5166
|
+
this.migrations = new FluxbaseAdminMigrations(fetch2);
|
|
3868
5167
|
}
|
|
3869
5168
|
/**
|
|
3870
5169
|
* Set admin authentication token
|
|
@@ -5061,6 +6360,7 @@ var FluxbaseClient = class {
|
|
|
5061
6360
|
);
|
|
5062
6361
|
this.storage = new FluxbaseStorage(this.fetch);
|
|
5063
6362
|
this.functions = new FluxbaseFunctions(this.fetch);
|
|
6363
|
+
this.jobs = new FluxbaseJobs(this.fetch);
|
|
5064
6364
|
this.admin = new FluxbaseAdmin(this.fetch);
|
|
5065
6365
|
this.management = new FluxbaseManagement(this.fetch);
|
|
5066
6366
|
this.settings = new SettingsClient(this.fetch);
|
|
@@ -5233,10 +6533,14 @@ exports.AuthSettingsManager = AuthSettingsManager;
|
|
|
5233
6533
|
exports.DDLManager = DDLManager;
|
|
5234
6534
|
exports.EmailTemplateManager = EmailTemplateManager;
|
|
5235
6535
|
exports.FluxbaseAdmin = FluxbaseAdmin;
|
|
6536
|
+
exports.FluxbaseAdminFunctions = FluxbaseAdminFunctions;
|
|
6537
|
+
exports.FluxbaseAdminJobs = FluxbaseAdminJobs;
|
|
6538
|
+
exports.FluxbaseAdminMigrations = FluxbaseAdminMigrations;
|
|
5236
6539
|
exports.FluxbaseAuth = FluxbaseAuth;
|
|
5237
6540
|
exports.FluxbaseClient = FluxbaseClient;
|
|
5238
6541
|
exports.FluxbaseFetch = FluxbaseFetch;
|
|
5239
6542
|
exports.FluxbaseFunctions = FluxbaseFunctions;
|
|
6543
|
+
exports.FluxbaseJobs = FluxbaseJobs;
|
|
5240
6544
|
exports.FluxbaseManagement = FluxbaseManagement;
|
|
5241
6545
|
exports.FluxbaseOAuth = FluxbaseOAuth;
|
|
5242
6546
|
exports.FluxbaseRealtime = FluxbaseRealtime;
|