@fluxbase/sdk 0.0.1-rc.41 → 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 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
- console.log("[Fluxbase Realtime] Acknowledged:", message);
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, and HTTP method
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 endpoint = `/api/v1/functions/${functionName}/invoke`;
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
- * Create a new edge function
1917
+ * List all public edge functions
1904
1918
  *
1905
- * @param request - Function configuration and code
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.create({
1911
- * name: 'my-function',
1912
- * code: 'export default async function handler(req) { return { hello: "world" } }',
1913
- * enabled: true
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 create(request) {
1929
+ async list() {
1918
1930
  try {
1919
- const data = await this.fetch.post("/api/v1/functions", request);
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
- * List all edge functions
1938
+ * Get details of a specific edge function
1927
1939
  *
1928
- * @returns Promise resolving to { data, error } tuple with array of functions
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.list()
1945
+ * const { data, error } = await client.functions.get('my-function')
1933
1946
  * if (data) {
1934
- * console.log('Functions:', data.map(f => f.name))
1947
+ * console.log('Function version:', data.version)
1935
1948
  * }
1936
1949
  * ```
1937
1950
  */
1938
- async list() {
1951
+ async get(name) {
1939
1952
  try {
1940
- const data = await this.fetch.get("/api/v1/functions");
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
- * Get details of a specific edge function
1967
+ * Submit a new job for execution
1948
1968
  *
1949
- * @param name - Function name
1950
- * @returns Promise resolving to { data, error } tuple with function metadata
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
- * const { data, error } = await client.functions.get('my-function')
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('Function version:', data.version)
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 get(name) {
1999
+ async submit(jobName, payload, options) {
1961
2000
  try {
1962
- const data = await this.fetch.get(`/api/v1/functions/${name}`);
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
- * Update an existing edge function
2013
+ * Get status and details of a specific job
1970
2014
  *
1971
- * @param name - Function name
1972
- * @param updates - Fields to update
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.functions.update('my-function', {
1978
- * enabled: false,
1979
- * description: 'Updated description'
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 update(name, updates) {
2061
+ async list(filters) {
1984
2062
  try {
1985
- const data = await this.fetch.put(`/api/v1/functions/${name}`, updates);
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
- * Delete an edge function
2078
+ * Cancel a pending or running job
1993
2079
  *
1994
- * @param name - Function name
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 { data, error } = await client.functions.delete('my-function')
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 delete(name) {
2092
+ async cancel(jobId) {
2003
2093
  try {
2004
- await this.fetch.delete(`/api/v1/functions/${name}`);
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
- * Get execution history for an edge function
2101
+ * Retry a failed job
2012
2102
  *
2013
- * @param name - Function name
2014
- * @param limit - Maximum number of executions to return (optional)
2015
- * @returns Promise resolving to { data, error } tuple with execution records
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.functions.getExecutions('my-function', 10)
2020
- * if (data) {
2021
- * data.forEach(exec => {
2022
- * console.log(`${exec.executed_at}: ${exec.status} (${exec.duration_ms}ms)`)
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 getExecutions(name, limit) {
2117
+ async retry(jobId) {
2028
2118
  try {
2029
- const params = limit ? `?limit=${limit}` : "";
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;