@fluxbase/sdk 0.0.1-rc.41 → 0.0.1-rc.43

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