@fluxbase/sdk 0.0.1-rc.45 → 0.0.1-rc.48

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
@@ -1917,6 +1917,127 @@ var StorageBucket = class {
1917
1917
  xhr.send(formData);
1918
1918
  });
1919
1919
  }
1920
+ /**
1921
+ * Upload a file using streaming for reduced memory usage.
1922
+ * This method bypasses FormData buffering and streams data directly to the server.
1923
+ * Ideal for large files where memory efficiency is important.
1924
+ *
1925
+ * @param path - The path/key for the file
1926
+ * @param stream - ReadableStream of the file data
1927
+ * @param size - The size of the file in bytes (required for Content-Length header)
1928
+ * @param options - Upload options
1929
+ *
1930
+ * @example
1931
+ * ```typescript
1932
+ * // Upload from a File's stream
1933
+ * const file = new File([...], 'large-video.mp4');
1934
+ * const { data, error } = await storage
1935
+ * .from('videos')
1936
+ * .uploadStream('video.mp4', file.stream(), file.size, {
1937
+ * contentType: 'video/mp4',
1938
+ * });
1939
+ *
1940
+ * // Upload from a fetch response stream
1941
+ * const response = await fetch('https://example.com/data.zip');
1942
+ * const size = parseInt(response.headers.get('content-length') || '0');
1943
+ * const { data, error } = await storage
1944
+ * .from('files')
1945
+ * .uploadStream('data.zip', response.body!, size, {
1946
+ * contentType: 'application/zip',
1947
+ * });
1948
+ * ```
1949
+ */
1950
+ async uploadStream(path, stream, size, options) {
1951
+ try {
1952
+ if (size <= 0) {
1953
+ return { data: null, error: new Error("size must be a positive number") };
1954
+ }
1955
+ const headers = {
1956
+ ...this.fetch["defaultHeaders"],
1957
+ "Content-Length": String(size)
1958
+ };
1959
+ if (options?.contentType) {
1960
+ headers["X-Storage-Content-Type"] = options.contentType;
1961
+ }
1962
+ if (options?.cacheControl) {
1963
+ headers["X-Storage-Cache-Control"] = options.cacheControl;
1964
+ }
1965
+ if (options?.metadata && Object.keys(options.metadata).length > 0) {
1966
+ headers["X-Storage-Metadata"] = JSON.stringify(options.metadata);
1967
+ }
1968
+ let bodyStream = stream;
1969
+ if (options?.onUploadProgress) {
1970
+ let uploadedBytes = 0;
1971
+ const progressCallback = options.onUploadProgress;
1972
+ const totalSize = size;
1973
+ const transformStream = new TransformStream({
1974
+ transform(chunk, controller) {
1975
+ uploadedBytes += chunk.byteLength;
1976
+ const percentage = Math.round(uploadedBytes / totalSize * 100);
1977
+ progressCallback({
1978
+ loaded: uploadedBytes,
1979
+ total: totalSize,
1980
+ percentage
1981
+ });
1982
+ controller.enqueue(chunk);
1983
+ }
1984
+ });
1985
+ bodyStream = stream.pipeThrough(transformStream);
1986
+ }
1987
+ const response = await fetch(
1988
+ `${this.fetch["baseUrl"]}/api/v1/storage/${this.bucketName}/stream/${path}`,
1989
+ {
1990
+ method: "POST",
1991
+ headers,
1992
+ body: bodyStream,
1993
+ signal: options?.signal,
1994
+ // @ts-expect-error - duplex is not yet in TypeScript's RequestInit type
1995
+ duplex: "half"
1996
+ }
1997
+ );
1998
+ if (!response.ok) {
1999
+ const errorData = await response.json().catch(() => ({ error: response.statusText }));
2000
+ throw new Error(errorData.error || `Upload failed: ${response.statusText}`);
2001
+ }
2002
+ const result = await response.json();
2003
+ return {
2004
+ data: {
2005
+ id: result.key || path,
2006
+ path,
2007
+ fullPath: `${this.bucketName}/${path}`
2008
+ },
2009
+ error: null
2010
+ };
2011
+ } catch (error) {
2012
+ return { data: null, error };
2013
+ }
2014
+ }
2015
+ /**
2016
+ * Upload a large file using streaming for reduced memory usage.
2017
+ * This is a convenience method that converts a File or Blob to a stream.
2018
+ *
2019
+ * @param path - The path/key for the file
2020
+ * @param file - The File or Blob to upload
2021
+ * @param options - Upload options
2022
+ *
2023
+ * @example
2024
+ * ```typescript
2025
+ * const file = new File([...], 'large-video.mp4');
2026
+ * const { data, error } = await storage
2027
+ * .from('videos')
2028
+ * .uploadLargeFile('video.mp4', file, {
2029
+ * contentType: 'video/mp4',
2030
+ * onUploadProgress: (p) => console.log(`${p.percentage}% complete`),
2031
+ * });
2032
+ * ```
2033
+ */
2034
+ async uploadLargeFile(path, file, options) {
2035
+ const opts = {
2036
+ ...options,
2037
+ contentType: options?.contentType || file.type || "application/octet-stream"
2038
+ };
2039
+ return this.uploadStream(path, file.stream(), file.size, opts);
2040
+ }
1920
2041
  async download(path, options) {
1921
2042
  try {
1922
2043
  const controller = new AbortController();
@@ -2548,7 +2669,7 @@ var FluxbaseJobs = class {
2548
2669
  *
2549
2670
  * @param jobName - Name of the job function to execute
2550
2671
  * @param payload - Job input data
2551
- * @param options - Additional options (priority, namespace, scheduled time)
2672
+ * @param options - Additional options (priority, namespace, scheduled time, onBehalfOf)
2552
2673
  * @returns Promise resolving to { data, error } tuple with submitted job details
2553
2674
  *
2554
2675
  * @example
@@ -2574,6 +2695,14 @@ var FluxbaseJobs = class {
2574
2695
  * const { data } = await client.jobs.submit('scheduled-task', payload, {
2575
2696
  * scheduled: '2025-01-01T00:00:00Z'
2576
2697
  * })
2698
+ *
2699
+ * // Submit on behalf of a user (service_role only)
2700
+ * const { data } = await serviceClient.jobs.submit('user-task', payload, {
2701
+ * onBehalfOf: {
2702
+ * user_id: 'user-uuid',
2703
+ * user_email: 'user@example.com'
2704
+ * }
2705
+ * })
2577
2706
  * ```
2578
2707
  */
2579
2708
  async submit(jobName, payload, options) {
@@ -2581,7 +2710,10 @@ var FluxbaseJobs = class {
2581
2710
  const request = {
2582
2711
  job_name: jobName,
2583
2712
  payload,
2584
- ...options
2713
+ priority: options?.priority,
2714
+ namespace: options?.namespace,
2715
+ scheduled: options?.scheduled,
2716
+ on_behalf_of: options?.onBehalfOf
2585
2717
  };
2586
2718
  const data = await this.fetch.post("/api/v1/jobs/submit", request);
2587
2719
  return { data, error: null };
@@ -3268,11 +3400,13 @@ var AppSettingsManager = class {
3268
3400
  * ```
3269
3401
  */
3270
3402
  async setSetting(key, value, options) {
3403
+ const wrappedValue = value !== null && typeof value === "object" && !Array.isArray(value) ? value : { value };
3271
3404
  try {
3272
3405
  return await this.fetch.put(
3273
3406
  `/api/v1/admin/settings/custom/${key}`,
3274
3407
  {
3275
- value,
3408
+ value: wrappedValue,
3409
+ value_type: options?.value_type || "json",
3276
3410
  description: options?.description,
3277
3411
  is_public: options?.is_public,
3278
3412
  is_secret: options?.is_secret
@@ -3284,7 +3418,7 @@ var AppSettingsManager = class {
3284
3418
  "/api/v1/admin/settings/custom",
3285
3419
  {
3286
3420
  key,
3287
- value,
3421
+ value: wrappedValue,
3288
3422
  value_type: options?.value_type || "json",
3289
3423
  description: options?.description,
3290
3424
  is_public: options?.is_public ?? false,
@@ -4522,8 +4656,146 @@ var FluxbaseManagement = class {
4522
4656
  }
4523
4657
  };
4524
4658
 
4659
+ // src/bundling.ts
4660
+ var esbuild = null;
4661
+ var fs = null;
4662
+ async function loadEsbuild() {
4663
+ if (esbuild) return true;
4664
+ try {
4665
+ esbuild = await import('esbuild');
4666
+ return true;
4667
+ } catch {
4668
+ return false;
4669
+ }
4670
+ }
4671
+ async function loadFs() {
4672
+ if (fs) return true;
4673
+ try {
4674
+ fs = await import('fs');
4675
+ return true;
4676
+ } catch {
4677
+ return false;
4678
+ }
4679
+ }
4680
+ var denoExternalPlugin = {
4681
+ name: "deno-external",
4682
+ setup(build) {
4683
+ build.onResolve({ filter: /^npm:/ }, (args) => ({
4684
+ path: args.path,
4685
+ external: true
4686
+ }));
4687
+ build.onResolve({ filter: /^https?:\/\// }, (args) => ({
4688
+ path: args.path,
4689
+ external: true
4690
+ }));
4691
+ build.onResolve({ filter: /^jsr:/ }, (args) => ({
4692
+ path: args.path,
4693
+ external: true
4694
+ }));
4695
+ }
4696
+ };
4697
+ async function loadImportMap(denoJsonPath) {
4698
+ const hasFs = await loadFs();
4699
+ if (!hasFs || !fs) {
4700
+ console.warn("fs module not available, cannot load import map");
4701
+ return null;
4702
+ }
4703
+ try {
4704
+ const content = fs.readFileSync(denoJsonPath, "utf-8");
4705
+ const config = JSON.parse(content);
4706
+ return config.imports || null;
4707
+ } catch (error) {
4708
+ console.warn(`Failed to load import map from ${denoJsonPath}:`, error);
4709
+ return null;
4710
+ }
4711
+ }
4712
+ async function bundleCode(options) {
4713
+ const hasEsbuild = await loadEsbuild();
4714
+ if (!hasEsbuild || !esbuild) {
4715
+ throw new Error(
4716
+ "esbuild is required for bundling. Install it with: npm install esbuild"
4717
+ );
4718
+ }
4719
+ const externals = [...options.external ?? []];
4720
+ const alias = {};
4721
+ if (options.importMap) {
4722
+ for (const [key, value] of Object.entries(options.importMap)) {
4723
+ if (value.startsWith("npm:")) {
4724
+ externals.push(key);
4725
+ } else if (value.startsWith("https://") || value.startsWith("http://")) {
4726
+ externals.push(key);
4727
+ } else if (value.startsWith("/") || value.startsWith("./") || value.startsWith("../")) {
4728
+ alias[key] = value;
4729
+ } else {
4730
+ externals.push(key);
4731
+ }
4732
+ }
4733
+ }
4734
+ const denoPlugin = {
4735
+ name: "deno-external",
4736
+ setup(build) {
4737
+ build.onResolve({ filter: /^npm:/ }, (args) => ({
4738
+ path: args.path,
4739
+ external: true
4740
+ }));
4741
+ build.onResolve({ filter: /^https?:\/\// }, (args) => ({
4742
+ path: args.path,
4743
+ external: true
4744
+ }));
4745
+ build.onResolve({ filter: /^jsr:/ }, (args) => ({
4746
+ path: args.path,
4747
+ external: true
4748
+ }));
4749
+ }
4750
+ };
4751
+ const resolveDir = options.baseDir || process.cwd?.() || "/";
4752
+ const buildOptions = {
4753
+ stdin: {
4754
+ contents: options.code,
4755
+ loader: "ts",
4756
+ resolveDir
4757
+ },
4758
+ // Set absWorkingDir for consistent path resolution
4759
+ absWorkingDir: resolveDir,
4760
+ bundle: true,
4761
+ write: false,
4762
+ format: "esm",
4763
+ // Use 'node' platform for better node_modules resolution (Deno supports Node APIs)
4764
+ platform: "node",
4765
+ target: "esnext",
4766
+ minify: options.minify ?? false,
4767
+ sourcemap: options.sourcemap ? "inline" : false,
4768
+ external: externals,
4769
+ plugins: [denoPlugin],
4770
+ // Preserve handler export
4771
+ treeShaking: true,
4772
+ // Resolve .ts, .js, .mjs extensions
4773
+ resolveExtensions: [".ts", ".tsx", ".js", ".mjs", ".json"],
4774
+ // ESM conditions for better module resolution
4775
+ conditions: ["import", "module"]
4776
+ };
4777
+ if (Object.keys(alias).length > 0) {
4778
+ buildOptions.alias = alias;
4779
+ }
4780
+ if (options.nodePaths && options.nodePaths.length > 0) {
4781
+ buildOptions.nodePaths = options.nodePaths;
4782
+ }
4783
+ if (options.define) {
4784
+ buildOptions.define = options.define;
4785
+ }
4786
+ const result = await esbuild.build(buildOptions);
4787
+ const output = result.outputFiles?.[0];
4788
+ if (!output) {
4789
+ throw new Error("Bundling failed: no output generated");
4790
+ }
4791
+ return {
4792
+ code: output.text,
4793
+ sourceMap: options.sourcemap ? output.text : void 0
4794
+ };
4795
+ }
4796
+
4525
4797
  // src/admin-functions.ts
4526
- var FluxbaseAdminFunctions = class {
4798
+ var FluxbaseAdminFunctions = class _FluxbaseAdminFunctions {
4527
4799
  constructor(fetch2) {
4528
4800
  this.fetch = fetch2;
4529
4801
  }
@@ -4760,6 +5032,111 @@ var FluxbaseAdminFunctions = class {
4760
5032
  return { data: null, error };
4761
5033
  }
4762
5034
  }
5035
+ /**
5036
+ * Sync edge functions with automatic client-side bundling
5037
+ *
5038
+ * This is a convenience method that bundles all function code using esbuild
5039
+ * before sending to the server. Requires esbuild as a peer dependency.
5040
+ *
5041
+ * @param options - Sync options including namespace and functions array
5042
+ * @param bundleOptions - Optional bundling configuration
5043
+ * @returns Promise resolving to { data, error } tuple with sync results
5044
+ *
5045
+ * @example
5046
+ * ```typescript
5047
+ * const { data, error } = await client.admin.functions.syncWithBundling({
5048
+ * namespace: 'default',
5049
+ * functions: [
5050
+ * { name: 'hello', code: helloCode },
5051
+ * { name: 'goodbye', code: goodbyeCode },
5052
+ * ],
5053
+ * options: { delete_missing: true }
5054
+ * })
5055
+ * ```
5056
+ */
5057
+ async syncWithBundling(options, bundleOptions) {
5058
+ if (!options.functions || options.functions.length === 0) {
5059
+ return this.sync(options);
5060
+ }
5061
+ const hasEsbuild = await loadEsbuild();
5062
+ if (!hasEsbuild) {
5063
+ return {
5064
+ data: null,
5065
+ error: new Error(
5066
+ "esbuild is required for client-side bundling. Install it with: npm install esbuild"
5067
+ )
5068
+ };
5069
+ }
5070
+ try {
5071
+ const bundledFunctions = await Promise.all(
5072
+ options.functions.map(async (fn) => {
5073
+ if (fn.is_pre_bundled) {
5074
+ return fn;
5075
+ }
5076
+ const bundled = await _FluxbaseAdminFunctions.bundleCode({
5077
+ // Apply global bundle options first
5078
+ ...bundleOptions,
5079
+ // Then override with per-function values (these take priority)
5080
+ code: fn.code,
5081
+ // Use function's sourceDir for resolving relative imports
5082
+ baseDir: fn.sourceDir || bundleOptions?.baseDir,
5083
+ // Use function's nodePaths for additional module resolution
5084
+ nodePaths: fn.nodePaths || bundleOptions?.nodePaths
5085
+ });
5086
+ return {
5087
+ ...fn,
5088
+ code: bundled.code,
5089
+ original_code: fn.code,
5090
+ is_pre_bundled: true
5091
+ };
5092
+ })
5093
+ );
5094
+ return this.sync({
5095
+ ...options,
5096
+ functions: bundledFunctions
5097
+ });
5098
+ } catch (error) {
5099
+ return { data: null, error };
5100
+ }
5101
+ }
5102
+ /**
5103
+ * Bundle function code using esbuild (client-side)
5104
+ *
5105
+ * Transforms and bundles TypeScript/JavaScript code into a single file
5106
+ * that can be executed by the Fluxbase edge functions runtime.
5107
+ *
5108
+ * Requires esbuild as a peer dependency.
5109
+ *
5110
+ * @param options - Bundle options including source code
5111
+ * @returns Promise resolving to bundled code
5112
+ * @throws Error if esbuild is not available
5113
+ *
5114
+ * @example
5115
+ * ```typescript
5116
+ * const bundled = await FluxbaseAdminFunctions.bundleCode({
5117
+ * code: `
5118
+ * import { helper } from './utils'
5119
+ * export default async function handler(req) {
5120
+ * return helper(req.body)
5121
+ * }
5122
+ * `,
5123
+ * minify: true,
5124
+ * })
5125
+ *
5126
+ * // Use bundled code in sync
5127
+ * await client.admin.functions.sync({
5128
+ * namespace: 'default',
5129
+ * functions: [{
5130
+ * name: 'my-function',
5131
+ * code: bundled.code,
5132
+ * is_pre_bundled: true,
5133
+ * }]
5134
+ * })
5135
+ * ```
5136
+ */
5137
+ static async bundleCode(options) {
5138
+ return bundleCode(options);
5139
+ }
4763
5140
  };
4764
5141
 
4765
5142
  // src/admin-migrations.ts
@@ -4960,8 +5337,8 @@ var FluxbaseAdminMigrations = class {
4960
5337
  dry_run: options.dry_run ?? false,
4961
5338
  warnings: results.flatMap((r) => r.warnings || [])
4962
5339
  };
4963
- const hasChanges = combined.summary.created > 0 || combined.summary.updated > 0;
4964
- if (!combined.dry_run && hasChanges) {
5340
+ const migrationsAppliedSuccessfully = combined.summary.applied > 0 && combined.summary.errors === 0;
5341
+ if (!combined.dry_run && migrationsAppliedSuccessfully) {
4965
5342
  try {
4966
5343
  await this.triggerSchemaRefreshWithRestart();
4967
5344
  } catch (refreshError) {
@@ -5212,16 +5589,6 @@ var FluxbaseAdminMigrations = class {
5212
5589
  };
5213
5590
 
5214
5591
  // src/admin-jobs.ts
5215
- var esbuild = null;
5216
- async function loadEsbuild() {
5217
- if (esbuild) return true;
5218
- try {
5219
- esbuild = await import('esbuild');
5220
- return true;
5221
- } catch {
5222
- return false;
5223
- }
5224
- }
5225
5592
  var FluxbaseAdminJobs = class _FluxbaseAdminJobs {
5226
5593
  constructor(fetch2) {
5227
5594
  this.fetch = fetch2;
@@ -5706,158 +6073,695 @@ var FluxbaseAdminJobs = class _FluxbaseAdminJobs {
5706
6073
  * ```
5707
6074
  */
5708
6075
  static async bundleCode(options) {
5709
- const hasEsbuild = await loadEsbuild();
5710
- if (!hasEsbuild || !esbuild) {
5711
- throw new Error(
5712
- "esbuild is required for bundling. Install it with: npm install esbuild"
5713
- );
5714
- }
5715
- const externals = [...options.external ?? []];
5716
- const alias = {};
5717
- if (options.importMap) {
5718
- for (const [key, value] of Object.entries(options.importMap)) {
5719
- if (value.startsWith("npm:")) {
5720
- externals.push(key);
5721
- } else if (value.startsWith("https://") || value.startsWith("http://")) {
5722
- externals.push(key);
5723
- } else if (value.startsWith("/") || value.startsWith("./") || value.startsWith("../")) {
5724
- alias[key] = value;
5725
- } else {
5726
- externals.push(key);
5727
- }
5728
- }
5729
- }
5730
- const denoExternalPlugin = {
5731
- name: "deno-external",
5732
- setup(build) {
5733
- build.onResolve({ filter: /^npm:/ }, (args) => ({
5734
- path: args.path,
5735
- external: true
5736
- }));
5737
- build.onResolve({ filter: /^https?:\/\// }, (args) => ({
5738
- path: args.path,
5739
- external: true
5740
- }));
5741
- build.onResolve({ filter: /^jsr:/ }, (args) => ({
5742
- path: args.path,
5743
- external: true
5744
- }));
5745
- }
5746
- };
5747
- const resolveDir = options.baseDir || process.cwd?.() || "/";
5748
- const buildOptions = {
5749
- stdin: {
5750
- contents: options.code,
5751
- loader: "ts",
5752
- resolveDir
5753
- },
5754
- // Set absWorkingDir for consistent path resolution
5755
- absWorkingDir: resolveDir,
5756
- bundle: true,
5757
- write: false,
5758
- format: "esm",
5759
- // Use 'node' platform for better node_modules resolution (Deno supports Node APIs)
5760
- platform: "node",
5761
- target: "esnext",
5762
- minify: options.minify ?? false,
5763
- sourcemap: options.sourcemap ? "inline" : false,
5764
- external: externals,
5765
- plugins: [denoExternalPlugin],
5766
- // Preserve handler export
5767
- treeShaking: true,
5768
- // Resolve .ts, .js, .mjs extensions
5769
- resolveExtensions: [".ts", ".tsx", ".js", ".mjs", ".json"],
5770
- // ESM conditions for better module resolution
5771
- conditions: ["import", "module"]
5772
- };
5773
- if (Object.keys(alias).length > 0) {
5774
- buildOptions.alias = alias;
5775
- }
5776
- if (options.nodePaths && options.nodePaths.length > 0) {
5777
- buildOptions.nodePaths = options.nodePaths;
5778
- }
5779
- if (options.define) {
5780
- buildOptions.define = options.define;
5781
- }
5782
- const result = await esbuild.build(buildOptions);
5783
- const output = result.outputFiles?.[0];
5784
- if (!output) {
5785
- throw new Error("Bundling failed: no output generated");
5786
- }
5787
- return {
5788
- code: output.text,
5789
- sourceMap: options.sourcemap ? output.text : void 0
5790
- };
6076
+ return bundleCode(options);
5791
6077
  }
5792
6078
  };
5793
6079
 
5794
- // src/admin.ts
5795
- var FluxbaseAdmin = class {
6080
+ // src/admin-ai.ts
6081
+ var FluxbaseAdminAI = class {
5796
6082
  constructor(fetch2) {
5797
- this.adminToken = null;
5798
6083
  this.fetch = fetch2;
5799
- this.settings = new FluxbaseSettings(fetch2);
5800
- this.ddl = new DDLManager(fetch2);
5801
- this.oauth = new FluxbaseOAuth(fetch2);
5802
- this.impersonation = new ImpersonationManager(fetch2);
5803
- this.management = new FluxbaseManagement(fetch2);
5804
- this.emailTemplates = new EmailTemplateManager(fetch2);
5805
- this.functions = new FluxbaseAdminFunctions(fetch2);
5806
- this.jobs = new FluxbaseAdminJobs(fetch2);
5807
- this.migrations = new FluxbaseAdminMigrations(fetch2);
5808
- }
5809
- /**
5810
- * Set admin authentication token
5811
- */
5812
- setToken(token) {
5813
- this.adminToken = token;
5814
- this.fetch.setAuthToken(token);
5815
- }
5816
- /**
5817
- * Get current admin token
5818
- */
5819
- getToken() {
5820
- return this.adminToken;
5821
- }
5822
- /**
5823
- * Clear admin token
5824
- */
5825
- clearToken() {
5826
- this.adminToken = null;
5827
- this.fetch.setAuthToken(null);
5828
6084
  }
5829
6085
  // ============================================================================
5830
- // Admin Authentication
6086
+ // CHATBOT MANAGEMENT
5831
6087
  // ============================================================================
5832
6088
  /**
5833
- * Check if initial admin setup is needed
6089
+ * List all chatbots (admin view)
5834
6090
  *
5835
- * @returns Setup status indicating if initial setup is required
6091
+ * @param namespace - Optional namespace filter
6092
+ * @returns Promise resolving to { data, error } tuple with array of chatbot summaries
5836
6093
  *
5837
6094
  * @example
5838
6095
  * ```typescript
5839
- * const status = await admin.getSetupStatus();
5840
- * if (status.needs_setup) {
5841
- * console.log('Initial setup required');
6096
+ * const { data, error } = await client.admin.ai.listChatbots()
6097
+ * if (data) {
6098
+ * console.log('Chatbots:', data.map(c => c.name))
5842
6099
  * }
5843
6100
  * ```
5844
6101
  */
5845
- async getSetupStatus() {
5846
- return wrapAsync(async () => {
5847
- return await this.fetch.get(
5848
- "/api/v1/admin/setup/status"
5849
- );
5850
- });
5851
- }
6102
+ async listChatbots(namespace) {
6103
+ try {
6104
+ const params = namespace ? `?namespace=${namespace}` : "";
6105
+ const response = await this.fetch.get(`/api/v1/admin/ai/chatbots${params}`);
6106
+ return { data: response.chatbots || [], error: null };
6107
+ } catch (error) {
6108
+ return { data: null, error };
6109
+ }
6110
+ }
6111
+ /**
6112
+ * Get details of a specific chatbot
6113
+ *
6114
+ * @param id - Chatbot ID
6115
+ * @returns Promise resolving to { data, error } tuple with chatbot details
6116
+ *
6117
+ * @example
6118
+ * ```typescript
6119
+ * const { data, error } = await client.admin.ai.getChatbot('uuid')
6120
+ * if (data) {
6121
+ * console.log('Chatbot:', data.name)
6122
+ * }
6123
+ * ```
6124
+ */
6125
+ async getChatbot(id) {
6126
+ try {
6127
+ const data = await this.fetch.get(
6128
+ `/api/v1/admin/ai/chatbots/${id}`
6129
+ );
6130
+ return { data, error: null };
6131
+ } catch (error) {
6132
+ return { data: null, error };
6133
+ }
6134
+ }
6135
+ /**
6136
+ * Enable or disable a chatbot
6137
+ *
6138
+ * @param id - Chatbot ID
6139
+ * @param enabled - Whether to enable or disable
6140
+ * @returns Promise resolving to { data, error } tuple with updated chatbot
6141
+ *
6142
+ * @example
6143
+ * ```typescript
6144
+ * const { data, error } = await client.admin.ai.toggleChatbot('uuid', true)
6145
+ * ```
6146
+ */
6147
+ async toggleChatbot(id, enabled) {
6148
+ try {
6149
+ const data = await this.fetch.put(
6150
+ `/api/v1/admin/ai/chatbots/${id}/toggle`,
6151
+ { enabled }
6152
+ );
6153
+ return { data, error: null };
6154
+ } catch (error) {
6155
+ return { data: null, error };
6156
+ }
6157
+ }
6158
+ /**
6159
+ * Delete a chatbot
6160
+ *
6161
+ * @param id - Chatbot ID
6162
+ * @returns Promise resolving to { data, error } tuple
6163
+ *
6164
+ * @example
6165
+ * ```typescript
6166
+ * const { data, error } = await client.admin.ai.deleteChatbot('uuid')
6167
+ * ```
6168
+ */
6169
+ async deleteChatbot(id) {
6170
+ try {
6171
+ await this.fetch.delete(`/api/v1/admin/ai/chatbots/${id}`);
6172
+ return { data: null, error: null };
6173
+ } catch (error) {
6174
+ return { data: null, error };
6175
+ }
6176
+ }
6177
+ /**
6178
+ * Sync chatbots from filesystem or API payload
6179
+ *
6180
+ * Can sync from:
6181
+ * 1. Filesystem (if no chatbots provided) - loads from configured chatbots directory
6182
+ * 2. API payload (if chatbots array provided) - syncs provided chatbot specifications
6183
+ *
6184
+ * Requires service_role or admin authentication.
6185
+ *
6186
+ * @param options - Sync options including namespace and optional chatbots array
6187
+ * @returns Promise resolving to { data, error } tuple with sync results
6188
+ *
6189
+ * @example
6190
+ * ```typescript
6191
+ * // Sync from filesystem
6192
+ * const { data, error } = await client.admin.ai.sync()
6193
+ *
6194
+ * // Sync with provided chatbot code
6195
+ * const { data, error } = await client.admin.ai.sync({
6196
+ * namespace: 'default',
6197
+ * chatbots: [{
6198
+ * name: 'sql-assistant',
6199
+ * code: myChatbotCode,
6200
+ * }],
6201
+ * options: {
6202
+ * delete_missing: false, // Don't remove chatbots not in this sync
6203
+ * dry_run: false, // Preview changes without applying
6204
+ * }
6205
+ * })
6206
+ *
6207
+ * if (data) {
6208
+ * console.log(`Synced: ${data.summary.created} created, ${data.summary.updated} updated`)
6209
+ * }
6210
+ * ```
6211
+ */
6212
+ async sync(options) {
6213
+ try {
6214
+ const data = await this.fetch.post(
6215
+ "/api/v1/admin/ai/chatbots/sync",
6216
+ {
6217
+ namespace: options?.namespace || "default",
6218
+ chatbots: options?.chatbots,
6219
+ options: {
6220
+ delete_missing: options?.options?.delete_missing ?? false,
6221
+ dry_run: options?.options?.dry_run ?? false
6222
+ }
6223
+ }
6224
+ );
6225
+ return { data, error: null };
6226
+ } catch (error) {
6227
+ return { data: null, error };
6228
+ }
6229
+ }
6230
+ // ============================================================================
6231
+ // PROVIDER MANAGEMENT
6232
+ // ============================================================================
6233
+ /**
6234
+ * List all AI providers
6235
+ *
6236
+ * @returns Promise resolving to { data, error } tuple with array of providers
6237
+ *
6238
+ * @example
6239
+ * ```typescript
6240
+ * const { data, error } = await client.admin.ai.listProviders()
6241
+ * if (data) {
6242
+ * console.log('Providers:', data.map(p => p.name))
6243
+ * }
6244
+ * ```
6245
+ */
6246
+ async listProviders() {
6247
+ try {
6248
+ const response = await this.fetch.get("/api/v1/admin/ai/providers");
6249
+ return { data: response.providers || [], error: null };
6250
+ } catch (error) {
6251
+ return { data: null, error };
6252
+ }
6253
+ }
6254
+ /**
6255
+ * Get details of a specific provider
6256
+ *
6257
+ * @param id - Provider ID
6258
+ * @returns Promise resolving to { data, error } tuple with provider details
6259
+ *
6260
+ * @example
6261
+ * ```typescript
6262
+ * const { data, error } = await client.admin.ai.getProvider('uuid')
6263
+ * if (data) {
6264
+ * console.log('Provider:', data.display_name)
6265
+ * }
6266
+ * ```
6267
+ */
6268
+ async getProvider(id) {
6269
+ try {
6270
+ const data = await this.fetch.get(
6271
+ `/api/v1/admin/ai/providers/${id}`
6272
+ );
6273
+ return { data, error: null };
6274
+ } catch (error) {
6275
+ return { data: null, error };
6276
+ }
6277
+ }
6278
+ /**
6279
+ * Create a new AI provider
6280
+ *
6281
+ * @param request - Provider configuration
6282
+ * @returns Promise resolving to { data, error } tuple with created provider
6283
+ *
6284
+ * @example
6285
+ * ```typescript
6286
+ * const { data, error } = await client.admin.ai.createProvider({
6287
+ * name: 'openai-main',
6288
+ * display_name: 'OpenAI (Main)',
6289
+ * provider_type: 'openai',
6290
+ * is_default: true,
6291
+ * config: {
6292
+ * api_key: 'sk-...',
6293
+ * model: 'gpt-4-turbo',
6294
+ * }
6295
+ * })
6296
+ * ```
6297
+ */
6298
+ async createProvider(request) {
6299
+ try {
6300
+ const data = await this.fetch.post(
6301
+ "/api/v1/admin/ai/providers",
6302
+ request
6303
+ );
6304
+ return { data, error: null };
6305
+ } catch (error) {
6306
+ return { data: null, error };
6307
+ }
6308
+ }
6309
+ /**
6310
+ * Update an existing AI provider
6311
+ *
6312
+ * @param id - Provider ID
6313
+ * @param updates - Fields to update
6314
+ * @returns Promise resolving to { data, error } tuple with updated provider
6315
+ *
6316
+ * @example
6317
+ * ```typescript
6318
+ * const { data, error } = await client.admin.ai.updateProvider('uuid', {
6319
+ * display_name: 'Updated Name',
6320
+ * config: {
6321
+ * api_key: 'new-key',
6322
+ * model: 'gpt-4-turbo',
6323
+ * },
6324
+ * enabled: true,
6325
+ * })
6326
+ * ```
6327
+ */
6328
+ async updateProvider(id, updates) {
6329
+ try {
6330
+ const data = await this.fetch.put(
6331
+ `/api/v1/admin/ai/providers/${id}`,
6332
+ updates
6333
+ );
6334
+ return { data, error: null };
6335
+ } catch (error) {
6336
+ return { data: null, error };
6337
+ }
6338
+ }
6339
+ /**
6340
+ * Set a provider as the default
6341
+ *
6342
+ * @param id - Provider ID
6343
+ * @returns Promise resolving to { data, error } tuple with updated provider
6344
+ *
6345
+ * @example
6346
+ * ```typescript
6347
+ * const { data, error } = await client.admin.ai.setDefaultProvider('uuid')
6348
+ * ```
6349
+ */
6350
+ async setDefaultProvider(id) {
6351
+ try {
6352
+ const data = await this.fetch.put(
6353
+ `/api/v1/admin/ai/providers/${id}/default`,
6354
+ {}
6355
+ );
6356
+ return { data, error: null };
6357
+ } catch (error) {
6358
+ return { data: null, error };
6359
+ }
6360
+ }
6361
+ /**
6362
+ * Delete a provider
6363
+ *
6364
+ * @param id - Provider ID
6365
+ * @returns Promise resolving to { data, error } tuple
6366
+ *
6367
+ * @example
6368
+ * ```typescript
6369
+ * const { data, error } = await client.admin.ai.deleteProvider('uuid')
6370
+ * ```
6371
+ */
6372
+ async deleteProvider(id) {
6373
+ try {
6374
+ await this.fetch.delete(`/api/v1/admin/ai/providers/${id}`);
6375
+ return { data: null, error: null };
6376
+ } catch (error) {
6377
+ return { data: null, error };
6378
+ }
6379
+ }
6380
+ };
6381
+
6382
+ // src/admin-rpc.ts
6383
+ var FluxbaseAdminRPC = class {
6384
+ constructor(fetch2) {
6385
+ this.fetch = fetch2;
6386
+ }
6387
+ // ============================================================================
6388
+ // PROCEDURE MANAGEMENT
6389
+ // ============================================================================
6390
+ /**
6391
+ * Sync RPC procedures from filesystem or API payload
6392
+ *
6393
+ * Can sync from:
6394
+ * 1. Filesystem (if no procedures provided) - loads from configured procedures directory
6395
+ * 2. API payload (if procedures array provided) - syncs provided procedure specifications
6396
+ *
6397
+ * Requires service_role or admin authentication.
6398
+ *
6399
+ * @param options - Sync options including namespace and optional procedures array
6400
+ * @returns Promise resolving to { data, error } tuple with sync results
6401
+ *
6402
+ * @example
6403
+ * ```typescript
6404
+ * // Sync from filesystem
6405
+ * const { data, error } = await client.admin.rpc.sync()
6406
+ *
6407
+ * // Sync with provided procedure code
6408
+ * const { data, error } = await client.admin.rpc.sync({
6409
+ * namespace: 'default',
6410
+ * procedures: [{
6411
+ * name: 'get-user-orders',
6412
+ * code: myProcedureSQL,
6413
+ * }],
6414
+ * options: {
6415
+ * delete_missing: false, // Don't remove procedures not in this sync
6416
+ * dry_run: false, // Preview changes without applying
6417
+ * }
6418
+ * })
6419
+ *
6420
+ * if (data) {
6421
+ * console.log(`Synced: ${data.summary.created} created, ${data.summary.updated} updated`)
6422
+ * }
6423
+ * ```
6424
+ */
6425
+ async sync(options) {
6426
+ try {
6427
+ const data = await this.fetch.post(
6428
+ "/api/v1/admin/rpc/sync",
6429
+ {
6430
+ namespace: options?.namespace || "default",
6431
+ procedures: options?.procedures,
6432
+ options: {
6433
+ delete_missing: options?.options?.delete_missing ?? false,
6434
+ dry_run: options?.options?.dry_run ?? false
6435
+ }
6436
+ }
6437
+ );
6438
+ return { data, error: null };
6439
+ } catch (error) {
6440
+ return { data: null, error };
6441
+ }
6442
+ }
6443
+ /**
6444
+ * List all RPC procedures (admin view)
6445
+ *
6446
+ * @param namespace - Optional namespace filter
6447
+ * @returns Promise resolving to { data, error } tuple with array of procedure summaries
6448
+ *
6449
+ * @example
6450
+ * ```typescript
6451
+ * const { data, error } = await client.admin.rpc.list()
6452
+ * if (data) {
6453
+ * console.log('Procedures:', data.map(p => p.name))
6454
+ * }
6455
+ * ```
6456
+ */
6457
+ async list(namespace) {
6458
+ try {
6459
+ const params = namespace ? `?namespace=${encodeURIComponent(namespace)}` : "";
6460
+ const response = await this.fetch.get(
6461
+ `/api/v1/admin/rpc/procedures${params}`
6462
+ );
6463
+ return { data: response.procedures || [], error: null };
6464
+ } catch (error) {
6465
+ return { data: null, error };
6466
+ }
6467
+ }
6468
+ /**
6469
+ * List all namespaces
6470
+ *
6471
+ * @returns Promise resolving to { data, error } tuple with array of namespace names
6472
+ *
6473
+ * @example
6474
+ * ```typescript
6475
+ * const { data, error } = await client.admin.rpc.listNamespaces()
6476
+ * if (data) {
6477
+ * console.log('Namespaces:', data)
6478
+ * }
6479
+ * ```
6480
+ */
6481
+ async listNamespaces() {
6482
+ try {
6483
+ const response = await this.fetch.get(
6484
+ "/api/v1/admin/rpc/namespaces"
6485
+ );
6486
+ return { data: response.namespaces || [], error: null };
6487
+ } catch (error) {
6488
+ return { data: null, error };
6489
+ }
6490
+ }
6491
+ /**
6492
+ * Get details of a specific RPC procedure
6493
+ *
6494
+ * @param namespace - Procedure namespace
6495
+ * @param name - Procedure name
6496
+ * @returns Promise resolving to { data, error } tuple with procedure details
6497
+ *
6498
+ * @example
6499
+ * ```typescript
6500
+ * const { data, error } = await client.admin.rpc.get('default', 'get-user-orders')
6501
+ * if (data) {
6502
+ * console.log('Procedure:', data.name)
6503
+ * console.log('SQL:', data.sql_query)
6504
+ * }
6505
+ * ```
6506
+ */
6507
+ async get(namespace, name) {
6508
+ try {
6509
+ const data = await this.fetch.get(
6510
+ `/api/v1/admin/rpc/procedures/${encodeURIComponent(namespace)}/${encodeURIComponent(name)}`
6511
+ );
6512
+ return { data, error: null };
6513
+ } catch (error) {
6514
+ return { data: null, error };
6515
+ }
6516
+ }
6517
+ /**
6518
+ * Update an RPC procedure
6519
+ *
6520
+ * @param namespace - Procedure namespace
6521
+ * @param name - Procedure name
6522
+ * @param updates - Fields to update
6523
+ * @returns Promise resolving to { data, error } tuple with updated procedure
6524
+ *
6525
+ * @example
6526
+ * ```typescript
6527
+ * const { data, error } = await client.admin.rpc.update('default', 'get-user-orders', {
6528
+ * enabled: false,
6529
+ * max_execution_time_seconds: 60,
6530
+ * })
6531
+ * ```
6532
+ */
6533
+ async update(namespace, name, updates) {
6534
+ try {
6535
+ const data = await this.fetch.put(
6536
+ `/api/v1/admin/rpc/procedures/${encodeURIComponent(namespace)}/${encodeURIComponent(name)}`,
6537
+ updates
6538
+ );
6539
+ return { data, error: null };
6540
+ } catch (error) {
6541
+ return { data: null, error };
6542
+ }
6543
+ }
6544
+ /**
6545
+ * Enable or disable an RPC procedure
6546
+ *
6547
+ * @param namespace - Procedure namespace
6548
+ * @param name - Procedure name
6549
+ * @param enabled - Whether to enable or disable
6550
+ * @returns Promise resolving to { data, error } tuple with updated procedure
6551
+ *
6552
+ * @example
6553
+ * ```typescript
6554
+ * const { data, error } = await client.admin.rpc.toggle('default', 'get-user-orders', true)
6555
+ * ```
6556
+ */
6557
+ async toggle(namespace, name, enabled) {
6558
+ return this.update(namespace, name, { enabled });
6559
+ }
6560
+ /**
6561
+ * Delete an RPC procedure
6562
+ *
6563
+ * @param namespace - Procedure namespace
6564
+ * @param name - Procedure name
6565
+ * @returns Promise resolving to { data, error } tuple
6566
+ *
6567
+ * @example
6568
+ * ```typescript
6569
+ * const { data, error } = await client.admin.rpc.delete('default', 'get-user-orders')
6570
+ * ```
6571
+ */
6572
+ async delete(namespace, name) {
6573
+ try {
6574
+ await this.fetch.delete(
6575
+ `/api/v1/admin/rpc/procedures/${encodeURIComponent(namespace)}/${encodeURIComponent(name)}`
6576
+ );
6577
+ return { data: null, error: null };
6578
+ } catch (error) {
6579
+ return { data: null, error };
6580
+ }
6581
+ }
6582
+ // ============================================================================
6583
+ // EXECUTION MONITORING
6584
+ // ============================================================================
6585
+ /**
6586
+ * List RPC executions with optional filters
6587
+ *
6588
+ * @param filters - Optional filters for namespace, procedure, status, user
6589
+ * @returns Promise resolving to { data, error } tuple with array of executions
6590
+ *
6591
+ * @example
6592
+ * ```typescript
6593
+ * // List all executions
6594
+ * const { data, error } = await client.admin.rpc.listExecutions()
6595
+ *
6596
+ * // List failed executions for a specific procedure
6597
+ * const { data, error } = await client.admin.rpc.listExecutions({
6598
+ * namespace: 'default',
6599
+ * procedure: 'get-user-orders',
6600
+ * status: 'failed',
6601
+ * })
6602
+ * ```
6603
+ */
6604
+ async listExecutions(filters) {
6605
+ try {
6606
+ const params = new URLSearchParams();
6607
+ if (filters?.namespace) params.set("namespace", filters.namespace);
6608
+ if (filters?.procedure) params.set("procedure_name", filters.procedure);
6609
+ if (filters?.status) params.set("status", filters.status);
6610
+ if (filters?.user_id) params.set("user_id", filters.user_id);
6611
+ if (filters?.limit) params.set("limit", filters.limit.toString());
6612
+ if (filters?.offset) params.set("offset", filters.offset.toString());
6613
+ const queryString = params.toString();
6614
+ const path = queryString ? `/api/v1/admin/rpc/executions?${queryString}` : "/api/v1/admin/rpc/executions";
6615
+ const response = await this.fetch.get(path);
6616
+ return { data: response.executions || [], error: null };
6617
+ } catch (error) {
6618
+ return { data: null, error };
6619
+ }
6620
+ }
6621
+ /**
6622
+ * Get details of a specific execution
6623
+ *
6624
+ * @param executionId - Execution ID
6625
+ * @returns Promise resolving to { data, error } tuple with execution details
6626
+ *
6627
+ * @example
6628
+ * ```typescript
6629
+ * const { data, error } = await client.admin.rpc.getExecution('execution-uuid')
6630
+ * if (data) {
6631
+ * console.log('Status:', data.status)
6632
+ * console.log('Duration:', data.duration_ms, 'ms')
6633
+ * }
6634
+ * ```
6635
+ */
6636
+ async getExecution(executionId) {
6637
+ try {
6638
+ const data = await this.fetch.get(
6639
+ `/api/v1/admin/rpc/executions/${encodeURIComponent(executionId)}`
6640
+ );
6641
+ return { data, error: null };
6642
+ } catch (error) {
6643
+ return { data: null, error };
6644
+ }
6645
+ }
6646
+ /**
6647
+ * Get execution logs for a specific execution
6648
+ *
6649
+ * @param executionId - Execution ID
6650
+ * @param afterLine - Optional line number to get logs after (for polling)
6651
+ * @returns Promise resolving to { data, error } tuple with execution logs
6652
+ *
6653
+ * @example
6654
+ * ```typescript
6655
+ * const { data, error } = await client.admin.rpc.getExecutionLogs('execution-uuid')
6656
+ * if (data) {
6657
+ * for (const log of data) {
6658
+ * console.log(`[${log.level}] ${log.message}`)
6659
+ * }
6660
+ * }
6661
+ * ```
6662
+ */
6663
+ async getExecutionLogs(executionId, afterLine) {
6664
+ try {
6665
+ const params = afterLine !== void 0 ? `?after=${afterLine}` : "";
6666
+ const response = await this.fetch.get(
6667
+ `/api/v1/admin/rpc/executions/${encodeURIComponent(executionId)}/logs${params}`
6668
+ );
6669
+ return { data: response.logs || [], error: null };
6670
+ } catch (error) {
6671
+ return { data: null, error };
6672
+ }
6673
+ }
6674
+ /**
6675
+ * Cancel a running execution
6676
+ *
6677
+ * @param executionId - Execution ID
6678
+ * @returns Promise resolving to { data, error } tuple with updated execution
6679
+ *
6680
+ * @example
6681
+ * ```typescript
6682
+ * const { data, error } = await client.admin.rpc.cancelExecution('execution-uuid')
6683
+ * ```
6684
+ */
6685
+ async cancelExecution(executionId) {
6686
+ try {
6687
+ const data = await this.fetch.post(
6688
+ `/api/v1/admin/rpc/executions/${encodeURIComponent(executionId)}/cancel`,
6689
+ {}
6690
+ );
6691
+ return { data, error: null };
6692
+ } catch (error) {
6693
+ return { data: null, error };
6694
+ }
6695
+ }
6696
+ };
6697
+
6698
+ // src/admin.ts
6699
+ var FluxbaseAdmin = class {
6700
+ constructor(fetch2) {
6701
+ this.adminToken = null;
6702
+ this.fetch = fetch2;
6703
+ this.settings = new FluxbaseSettings(fetch2);
6704
+ this.ddl = new DDLManager(fetch2);
6705
+ this.oauth = new FluxbaseOAuth(fetch2);
6706
+ this.impersonation = new ImpersonationManager(fetch2);
6707
+ this.management = new FluxbaseManagement(fetch2);
6708
+ this.emailTemplates = new EmailTemplateManager(fetch2);
6709
+ this.functions = new FluxbaseAdminFunctions(fetch2);
6710
+ this.jobs = new FluxbaseAdminJobs(fetch2);
6711
+ this.migrations = new FluxbaseAdminMigrations(fetch2);
6712
+ this.ai = new FluxbaseAdminAI(fetch2);
6713
+ this.rpc = new FluxbaseAdminRPC(fetch2);
6714
+ }
6715
+ /**
6716
+ * Set admin authentication token
6717
+ */
6718
+ setToken(token) {
6719
+ this.adminToken = token;
6720
+ this.fetch.setAuthToken(token);
6721
+ }
6722
+ /**
6723
+ * Get current admin token
6724
+ */
6725
+ getToken() {
6726
+ return this.adminToken;
6727
+ }
6728
+ /**
6729
+ * Clear admin token
6730
+ */
6731
+ clearToken() {
6732
+ this.adminToken = null;
6733
+ this.fetch.setAuthToken(null);
6734
+ }
6735
+ // ============================================================================
6736
+ // Admin Authentication
6737
+ // ============================================================================
6738
+ /**
6739
+ * Check if initial admin setup is needed
6740
+ *
6741
+ * @returns Setup status indicating if initial setup is required
6742
+ *
6743
+ * @example
6744
+ * ```typescript
6745
+ * const status = await admin.getSetupStatus();
6746
+ * if (status.needs_setup) {
6747
+ * console.log('Initial setup required');
6748
+ * }
6749
+ * ```
6750
+ */
6751
+ async getSetupStatus() {
6752
+ return wrapAsync(async () => {
6753
+ return await this.fetch.get(
6754
+ "/api/v1/admin/setup/status"
6755
+ );
6756
+ });
6757
+ }
5852
6758
  /**
5853
6759
  * Perform initial admin setup
5854
6760
  *
5855
6761
  * Creates the first admin user and completes initial setup.
5856
6762
  * This endpoint can only be called once.
5857
6763
  *
5858
- * @param email - Admin email address
5859
- * @param password - Admin password (minimum 12 characters)
5860
- * @param name - Admin display name
6764
+ * @param request - Setup request containing email, password, and name
5861
6765
  * @returns Authentication response with tokens
5862
6766
  *
5863
6767
  * @example
@@ -5887,8 +6791,7 @@ var FluxbaseAdmin = class {
5887
6791
  *
5888
6792
  * Authenticate as an admin user
5889
6793
  *
5890
- * @param email - Admin email
5891
- * @param password - Admin password
6794
+ * @param request - Login request containing email and password
5892
6795
  * @returns Authentication response with tokens
5893
6796
  *
5894
6797
  * @example
@@ -5915,7 +6818,7 @@ var FluxbaseAdmin = class {
5915
6818
  /**
5916
6819
  * Refresh admin access token
5917
6820
  *
5918
- * @param refreshToken - Refresh token
6821
+ * @param request - Refresh request containing the refresh token
5919
6822
  * @returns New access and refresh tokens
5920
6823
  *
5921
6824
  * @example
@@ -6016,121 +6919,494 @@ var FluxbaseAdmin = class {
6016
6919
  });
6017
6920
  }
6018
6921
  /**
6019
- * Get a user by ID
6020
- *
6021
- * Fetch a single user's details by their user ID
6922
+ * Get a user by ID
6923
+ *
6924
+ * Fetch a single user's details by their user ID
6925
+ *
6926
+ * @param userId - User ID to fetch
6927
+ * @param type - User type ('app' or 'dashboard')
6928
+ * @returns User details with metadata
6929
+ *
6930
+ * @example
6931
+ * ```typescript
6932
+ * // Get an app user
6933
+ * const user = await admin.getUserById('user-123');
6934
+ *
6935
+ * // Get a dashboard user
6936
+ * const dashboardUser = await admin.getUserById('admin-456', 'dashboard');
6937
+ * console.log('User email:', dashboardUser.email);
6938
+ * console.log('Last login:', dashboardUser.last_login_at);
6939
+ * ```
6940
+ */
6941
+ async getUserById(userId, type = "app") {
6942
+ return wrapAsync(async () => {
6943
+ const url = `/api/v1/admin/users/${userId}?type=${type}`;
6944
+ return await this.fetch.get(url);
6945
+ });
6946
+ }
6947
+ /**
6948
+ * Invite a new user
6949
+ *
6950
+ * Creates a new user and optionally sends an invitation email
6951
+ *
6952
+ * @param request - User invitation details
6953
+ * @param type - User type ('app' or 'dashboard')
6954
+ * @returns Created user and invitation details
6955
+ *
6956
+ * @example
6957
+ * ```typescript
6958
+ * const response = await admin.inviteUser({
6959
+ * email: 'newuser@example.com',
6960
+ * role: 'user',
6961
+ * send_email: true
6962
+ * });
6963
+ *
6964
+ * console.log('User invited:', response.user.email);
6965
+ * console.log('Invitation link:', response.invitation_link);
6966
+ * ```
6967
+ */
6968
+ async inviteUser(request, type = "app") {
6969
+ return wrapAsync(async () => {
6970
+ const url = `/api/v1/admin/users/invite?type=${type}`;
6971
+ return await this.fetch.post(url, request);
6972
+ });
6973
+ }
6974
+ /**
6975
+ * Delete a user
6976
+ *
6977
+ * Permanently deletes a user and all associated data
6978
+ *
6979
+ * @param userId - User ID to delete
6980
+ * @param type - User type ('app' or 'dashboard')
6981
+ * @returns Deletion confirmation
6982
+ *
6983
+ * @example
6984
+ * ```typescript
6985
+ * await admin.deleteUser('user-uuid');
6986
+ * console.log('User deleted');
6987
+ * ```
6988
+ */
6989
+ async deleteUser(userId, type = "app") {
6990
+ return wrapAsync(async () => {
6991
+ const url = `/api/v1/admin/users/${userId}?type=${type}`;
6992
+ return await this.fetch.delete(url);
6993
+ });
6994
+ }
6995
+ /**
6996
+ * Update user role
6997
+ *
6998
+ * Changes a user's role
6999
+ *
7000
+ * @param userId - User ID
7001
+ * @param role - New role
7002
+ * @param type - User type ('app' or 'dashboard')
7003
+ * @returns Updated user
7004
+ *
7005
+ * @example
7006
+ * ```typescript
7007
+ * const user = await admin.updateUserRole('user-uuid', 'admin');
7008
+ * console.log('User role updated:', user.role);
7009
+ * ```
7010
+ */
7011
+ async updateUserRole(userId, role, type = "app") {
7012
+ return wrapAsync(async () => {
7013
+ const url = `/api/v1/admin/users/${userId}/role?type=${type}`;
7014
+ return await this.fetch.patch(url, { role });
7015
+ });
7016
+ }
7017
+ /**
7018
+ * Reset user password
7019
+ *
7020
+ * Generates a new password for the user and optionally sends it via email
7021
+ *
7022
+ * @param userId - User ID
7023
+ * @param type - User type ('app' or 'dashboard')
7024
+ * @returns Reset confirmation message
7025
+ *
7026
+ * @example
7027
+ * ```typescript
7028
+ * const response = await admin.resetUserPassword('user-uuid');
7029
+ * console.log(response.message);
7030
+ * ```
7031
+ */
7032
+ async resetUserPassword(userId, type = "app") {
7033
+ return wrapAsync(async () => {
7034
+ const url = `/api/v1/admin/users/${userId}/reset-password?type=${type}`;
7035
+ return await this.fetch.post(url, {});
7036
+ });
7037
+ }
7038
+ };
7039
+
7040
+ // src/ai.ts
7041
+ var FluxbaseAIChat = class {
7042
+ constructor(options) {
7043
+ this.ws = null;
7044
+ this.reconnectCount = 0;
7045
+ this.pendingStartResolve = null;
7046
+ this.pendingStartReject = null;
7047
+ this.accumulatedContent = /* @__PURE__ */ new Map();
7048
+ this.options = {
7049
+ reconnectAttempts: 3,
7050
+ reconnectDelay: 1e3,
7051
+ ...options
7052
+ };
7053
+ }
7054
+ /**
7055
+ * Connect to the AI chat WebSocket
7056
+ *
7057
+ * @returns Promise that resolves when connected
7058
+ */
7059
+ async connect() {
7060
+ return new Promise((resolve, reject) => {
7061
+ const url = this.buildWsUrl();
7062
+ try {
7063
+ this.ws = new WebSocket(url);
7064
+ this.ws.onopen = () => {
7065
+ this.reconnectCount = 0;
7066
+ this.emitEvent({ type: "connected" });
7067
+ resolve();
7068
+ };
7069
+ this.ws.onmessage = (event) => {
7070
+ this.handleMessage(event.data);
7071
+ };
7072
+ this.ws.onclose = (event) => {
7073
+ this.emitEvent({ type: "disconnected" });
7074
+ this.handleClose(event);
7075
+ };
7076
+ this.ws.onerror = () => {
7077
+ reject(new Error("WebSocket connection failed"));
7078
+ };
7079
+ } catch (error) {
7080
+ reject(error);
7081
+ }
7082
+ });
7083
+ }
7084
+ /**
7085
+ * Disconnect from the AI chat WebSocket
7086
+ */
7087
+ disconnect() {
7088
+ if (this.ws) {
7089
+ this.ws.close();
7090
+ this.ws = null;
7091
+ }
7092
+ }
7093
+ /**
7094
+ * Check if connected
7095
+ */
7096
+ isConnected() {
7097
+ return this.ws?.readyState === WebSocket.OPEN;
7098
+ }
7099
+ /**
7100
+ * Start a new chat session with a chatbot
7101
+ *
7102
+ * @param chatbot - Chatbot name
7103
+ * @param namespace - Optional namespace (defaults to 'default')
7104
+ * @param conversationId - Optional conversation ID to resume
7105
+ * @param impersonateUserId - Optional user ID to impersonate (admin only)
7106
+ * @returns Promise resolving to conversation ID
7107
+ */
7108
+ async startChat(chatbot, namespace, conversationId, impersonateUserId) {
7109
+ return new Promise((resolve, reject) => {
7110
+ if (!this.isConnected()) {
7111
+ reject(new Error("Not connected to AI chat"));
7112
+ return;
7113
+ }
7114
+ this.pendingStartResolve = resolve;
7115
+ this.pendingStartReject = reject;
7116
+ const message = {
7117
+ type: "start_chat",
7118
+ chatbot,
7119
+ namespace: namespace || "default",
7120
+ conversation_id: conversationId,
7121
+ impersonate_user_id: impersonateUserId
7122
+ };
7123
+ this.ws.send(JSON.stringify(message));
7124
+ });
7125
+ }
7126
+ /**
7127
+ * Send a message in a conversation
7128
+ *
7129
+ * @param conversationId - Conversation ID
7130
+ * @param content - Message content
7131
+ */
7132
+ sendMessage(conversationId, content) {
7133
+ if (!this.isConnected()) {
7134
+ throw new Error("Not connected to AI chat");
7135
+ }
7136
+ this.accumulatedContent.set(conversationId, "");
7137
+ const message = {
7138
+ type: "message",
7139
+ conversation_id: conversationId,
7140
+ content
7141
+ };
7142
+ this.ws.send(JSON.stringify(message));
7143
+ }
7144
+ /**
7145
+ * Cancel an ongoing message generation
7146
+ *
7147
+ * @param conversationId - Conversation ID
7148
+ */
7149
+ cancel(conversationId) {
7150
+ if (!this.isConnected()) {
7151
+ throw new Error("Not connected to AI chat");
7152
+ }
7153
+ const message = {
7154
+ type: "cancel",
7155
+ conversation_id: conversationId
7156
+ };
7157
+ this.ws.send(JSON.stringify(message));
7158
+ }
7159
+ /**
7160
+ * Get the full accumulated response content for a conversation
7161
+ *
7162
+ * @param conversationId - Conversation ID
7163
+ * @returns Accumulated content string
7164
+ */
7165
+ getAccumulatedContent(conversationId) {
7166
+ return this.accumulatedContent.get(conversationId) || "";
7167
+ }
7168
+ buildWsUrl() {
7169
+ let url = this.options.wsUrl || "/ai/ws";
7170
+ if (this.options.token) {
7171
+ const separator = url.includes("?") ? "&" : "?";
7172
+ url = `${url}${separator}token=${encodeURIComponent(this.options.token)}`;
7173
+ }
7174
+ return url;
7175
+ }
7176
+ handleMessage(data) {
7177
+ try {
7178
+ const message = JSON.parse(data);
7179
+ const event = this.serverMessageToEvent(message);
7180
+ switch (message.type) {
7181
+ case "chat_started":
7182
+ if (this.pendingStartResolve && message.conversation_id) {
7183
+ this.pendingStartResolve(message.conversation_id);
7184
+ this.pendingStartResolve = null;
7185
+ this.pendingStartReject = null;
7186
+ }
7187
+ break;
7188
+ case "content":
7189
+ if (message.conversation_id && message.delta) {
7190
+ const current = this.accumulatedContent.get(message.conversation_id) || "";
7191
+ this.accumulatedContent.set(message.conversation_id, current + message.delta);
7192
+ this.options.onContent?.(message.delta, message.conversation_id);
7193
+ }
7194
+ break;
7195
+ case "progress":
7196
+ if (message.step && message.message && message.conversation_id) {
7197
+ this.options.onProgress?.(message.step, message.message, message.conversation_id);
7198
+ }
7199
+ break;
7200
+ case "query_result":
7201
+ if (message.conversation_id) {
7202
+ this.options.onQueryResult?.(
7203
+ message.query || "",
7204
+ message.summary || "",
7205
+ message.row_count || 0,
7206
+ message.data || [],
7207
+ message.conversation_id
7208
+ );
7209
+ }
7210
+ break;
7211
+ case "done":
7212
+ if (message.conversation_id) {
7213
+ this.options.onDone?.(message.usage, message.conversation_id);
7214
+ }
7215
+ break;
7216
+ case "error":
7217
+ if (this.pendingStartReject) {
7218
+ this.pendingStartReject(new Error(message.error || "Unknown error"));
7219
+ this.pendingStartResolve = null;
7220
+ this.pendingStartReject = null;
7221
+ }
7222
+ this.options.onError?.(message.error || "Unknown error", message.code, message.conversation_id);
7223
+ break;
7224
+ }
7225
+ this.emitEvent(event);
7226
+ } catch (error) {
7227
+ console.error("Failed to parse AI chat message:", error);
7228
+ }
7229
+ }
7230
+ serverMessageToEvent(message) {
7231
+ return {
7232
+ type: message.type,
7233
+ conversationId: message.conversation_id,
7234
+ chatbot: message.chatbot,
7235
+ step: message.step,
7236
+ message: message.message,
7237
+ delta: message.delta,
7238
+ query: message.query,
7239
+ summary: message.summary,
7240
+ rowCount: message.row_count,
7241
+ data: message.data,
7242
+ usage: message.usage,
7243
+ error: message.error,
7244
+ code: message.code
7245
+ };
7246
+ }
7247
+ emitEvent(event) {
7248
+ this.options.onEvent?.(event);
7249
+ }
7250
+ handleClose(_event) {
7251
+ if (this.options.reconnectAttempts && this.reconnectCount < this.options.reconnectAttempts) {
7252
+ this.reconnectCount++;
7253
+ setTimeout(() => {
7254
+ this.connect().catch(() => {
7255
+ });
7256
+ }, this.options.reconnectDelay);
7257
+ }
7258
+ }
7259
+ };
7260
+ var FluxbaseAI = class {
7261
+ constructor(fetch2, wsBaseUrl) {
7262
+ this.fetch = fetch2;
7263
+ this.wsBaseUrl = wsBaseUrl;
7264
+ }
7265
+ /**
7266
+ * List available chatbots (public, enabled)
6022
7267
  *
6023
- * @param userId - User ID to fetch
6024
- * @param type - User type ('app' or 'dashboard')
6025
- * @returns User details with metadata
7268
+ * @returns Promise resolving to { data, error } tuple with array of chatbot summaries
7269
+ */
7270
+ async listChatbots() {
7271
+ try {
7272
+ const response = await this.fetch.get(
7273
+ "/api/v1/ai/chatbots"
7274
+ );
7275
+ return { data: response.chatbots || [], error: null };
7276
+ } catch (error) {
7277
+ return { data: null, error };
7278
+ }
7279
+ }
7280
+ /**
7281
+ * Get details of a specific chatbot
6026
7282
  *
6027
- * @example
6028
- * ```typescript
6029
- * // Get an app user
6030
- * const user = await admin.getUserById('user-123');
7283
+ * @param id - Chatbot ID
7284
+ * @returns Promise resolving to { data, error } tuple with chatbot details
7285
+ */
7286
+ async getChatbot(id) {
7287
+ try {
7288
+ const data = await this.fetch.get(`/api/v1/ai/chatbots/${id}`);
7289
+ return { data, error: null };
7290
+ } catch (error) {
7291
+ return { data: null, error };
7292
+ }
7293
+ }
7294
+ /**
7295
+ * Create a new AI chat connection
6031
7296
  *
6032
- * // Get a dashboard user
6033
- * const dashboardUser = await admin.getUserById('admin-456', 'dashboard');
6034
- * console.log('User email:', dashboardUser.email);
6035
- * console.log('Last login:', dashboardUser.last_login_at);
6036
- * ```
7297
+ * @param options - Chat connection options
7298
+ * @returns FluxbaseAIChat instance
6037
7299
  */
6038
- async getUserById(userId, type = "app") {
6039
- return wrapAsync(async () => {
6040
- const url = `/api/v1/admin/users/${userId}?type=${type}`;
6041
- return await this.fetch.get(url);
7300
+ createChat(options) {
7301
+ return new FluxbaseAIChat({
7302
+ ...options,
7303
+ wsUrl: `${this.wsBaseUrl}/ai/ws`
6042
7304
  });
6043
7305
  }
6044
7306
  /**
6045
- * Invite a new user
6046
- *
6047
- * Creates a new user and optionally sends an invitation email
7307
+ * List the authenticated user's conversations
6048
7308
  *
6049
- * @param request - User invitation details
6050
- * @param type - User type ('app' or 'dashboard')
6051
- * @returns Created user and invitation details
7309
+ * @param options - Optional filters and pagination
7310
+ * @returns Promise resolving to { data, error } tuple with conversations
6052
7311
  *
6053
7312
  * @example
6054
7313
  * ```typescript
6055
- * const response = await admin.inviteUser({
6056
- * email: 'newuser@example.com',
6057
- * role: 'user',
6058
- * send_email: true
6059
- * });
7314
+ * // List all conversations
7315
+ * const { data, error } = await ai.listConversations()
6060
7316
  *
6061
- * console.log('User invited:', response.user.email);
6062
- * console.log('Invitation link:', response.invitation_link);
7317
+ * // Filter by chatbot
7318
+ * const { data, error } = await ai.listConversations({ chatbot: 'sql-assistant' })
7319
+ *
7320
+ * // With pagination
7321
+ * const { data, error } = await ai.listConversations({ limit: 20, offset: 0 })
6063
7322
  * ```
6064
7323
  */
6065
- async inviteUser(request, type = "app") {
6066
- return wrapAsync(async () => {
6067
- const url = `/api/v1/admin/users/invite?type=${type}`;
6068
- return await this.fetch.post(url, request);
6069
- });
7324
+ async listConversations(options) {
7325
+ try {
7326
+ const params = new URLSearchParams();
7327
+ if (options?.chatbot) params.set("chatbot", options.chatbot);
7328
+ if (options?.namespace) params.set("namespace", options.namespace);
7329
+ if (options?.limit !== void 0) params.set("limit", String(options.limit));
7330
+ if (options?.offset !== void 0) params.set("offset", String(options.offset));
7331
+ const queryString = params.toString();
7332
+ const path = `/api/v1/ai/conversations${queryString ? `?${queryString}` : ""}`;
7333
+ const response = await this.fetch.get(path);
7334
+ return { data: response, error: null };
7335
+ } catch (error) {
7336
+ return { data: null, error };
7337
+ }
6070
7338
  }
6071
7339
  /**
6072
- * Delete a user
6073
- *
6074
- * Permanently deletes a user and all associated data
7340
+ * Get a single conversation with all messages
6075
7341
  *
6076
- * @param userId - User ID to delete
6077
- * @param type - User type ('app' or 'dashboard')
6078
- * @returns Deletion confirmation
7342
+ * @param id - Conversation ID
7343
+ * @returns Promise resolving to { data, error } tuple with conversation detail
6079
7344
  *
6080
7345
  * @example
6081
7346
  * ```typescript
6082
- * await admin.deleteUser('user-uuid');
6083
- * console.log('User deleted');
7347
+ * const { data, error } = await ai.getConversation('conv-uuid-123')
7348
+ * if (data) {
7349
+ * console.log(`Title: ${data.title}`)
7350
+ * console.log(`Messages: ${data.messages.length}`)
7351
+ * }
6084
7352
  * ```
6085
7353
  */
6086
- async deleteUser(userId, type = "app") {
6087
- return wrapAsync(async () => {
6088
- const url = `/api/v1/admin/users/${userId}?type=${type}`;
6089
- return await this.fetch.delete(url);
6090
- });
7354
+ async getConversation(id) {
7355
+ try {
7356
+ const response = await this.fetch.get(
7357
+ `/api/v1/ai/conversations/${id}`
7358
+ );
7359
+ return { data: response, error: null };
7360
+ } catch (error) {
7361
+ return { data: null, error };
7362
+ }
6091
7363
  }
6092
7364
  /**
6093
- * Update user role
6094
- *
6095
- * Changes a user's role
7365
+ * Delete a conversation
6096
7366
  *
6097
- * @param userId - User ID
6098
- * @param role - New role
6099
- * @param type - User type ('app' or 'dashboard')
6100
- * @returns Updated user
7367
+ * @param id - Conversation ID
7368
+ * @returns Promise resolving to { error } (null on success)
6101
7369
  *
6102
7370
  * @example
6103
7371
  * ```typescript
6104
- * const user = await admin.updateUserRole('user-uuid', 'admin');
6105
- * console.log('User role updated:', user.role);
7372
+ * const { error } = await ai.deleteConversation('conv-uuid-123')
7373
+ * if (!error) {
7374
+ * console.log('Conversation deleted')
7375
+ * }
6106
7376
  * ```
6107
7377
  */
6108
- async updateUserRole(userId, role, type = "app") {
6109
- return wrapAsync(async () => {
6110
- const url = `/api/v1/admin/users/${userId}/role?type=${type}`;
6111
- return await this.fetch.patch(url, { role });
6112
- });
7378
+ async deleteConversation(id) {
7379
+ try {
7380
+ await this.fetch.delete(`/api/v1/ai/conversations/${id}`);
7381
+ return { error: null };
7382
+ } catch (error) {
7383
+ return { error };
7384
+ }
6113
7385
  }
6114
7386
  /**
6115
- * Reset user password
7387
+ * Update a conversation (currently supports title update only)
6116
7388
  *
6117
- * Generates a new password for the user and optionally sends it via email
6118
- *
6119
- * @param userId - User ID
6120
- * @param type - User type ('app' or 'dashboard')
6121
- * @returns Reset confirmation message
7389
+ * @param id - Conversation ID
7390
+ * @param updates - Fields to update
7391
+ * @returns Promise resolving to { data, error } tuple with updated conversation
6122
7392
  *
6123
7393
  * @example
6124
7394
  * ```typescript
6125
- * const response = await admin.resetUserPassword('user-uuid');
6126
- * console.log(response.message);
7395
+ * const { data, error } = await ai.updateConversation('conv-uuid-123', {
7396
+ * title: 'My custom conversation title'
7397
+ * })
6127
7398
  * ```
6128
7399
  */
6129
- async resetUserPassword(userId, type = "app") {
6130
- return wrapAsync(async () => {
6131
- const url = `/api/v1/admin/users/${userId}/reset-password?type=${type}`;
6132
- return await this.fetch.post(url, {});
6133
- });
7400
+ async updateConversation(id, updates) {
7401
+ try {
7402
+ const response = await this.fetch.patch(
7403
+ `/api/v1/ai/conversations/${id}`,
7404
+ updates
7405
+ );
7406
+ return { data: response, error: null };
7407
+ } catch (error) {
7408
+ return { data: null, error };
7409
+ }
6134
7410
  }
6135
7411
  };
6136
7412
 
@@ -6141,6 +7417,7 @@ var QueryBuilder = class {
6141
7417
  this.filters = [];
6142
7418
  this.orFilters = [];
6143
7419
  this.andFilters = [];
7420
+ this.betweenFilters = [];
6144
7421
  this.orderBys = [];
6145
7422
  this.singleRow = false;
6146
7423
  this.maybeSingleRow = false;
@@ -6360,8 +7637,20 @@ var QueryBuilder = class {
6360
7637
  * Generic filter method using PostgREST syntax (Supabase-compatible)
6361
7638
  * @example filter('name', 'in', '("Han","Yoda")')
6362
7639
  * @example filter('age', 'gte', '18')
7640
+ * @example filter('recorded_at', 'between', ['2024-01-01', '2024-01-10'])
7641
+ * @example filter('recorded_at', 'not.between', ['2024-01-01', '2024-01-10'])
6363
7642
  */
6364
7643
  filter(column, operator, value) {
7644
+ if (operator === "between" || operator === "not.between") {
7645
+ const [min, max] = this.validateBetweenValue(value, operator);
7646
+ this.betweenFilters.push({
7647
+ column,
7648
+ min,
7649
+ max,
7650
+ negated: operator === "not.between"
7651
+ });
7652
+ return this;
7653
+ }
6365
7654
  this.filters.push({ column, operator, value });
6366
7655
  return this;
6367
7656
  }
@@ -6382,6 +7671,33 @@ var QueryBuilder = class {
6382
7671
  this.filters.push({ column, operator: "ov", value });
6383
7672
  return this;
6384
7673
  }
7674
+ /**
7675
+ * Filter column value within an inclusive range (BETWEEN)
7676
+ * Generates: AND (column >= min AND column <= max)
7677
+ *
7678
+ * @param column - Column name to filter
7679
+ * @param min - Minimum value (inclusive)
7680
+ * @param max - Maximum value (inclusive)
7681
+ * @example between('recorded_at', '2024-01-01', '2024-01-10')
7682
+ * @example between('price', 10, 100)
7683
+ */
7684
+ between(column, min, max) {
7685
+ return this.filter(column, "between", [min, max]);
7686
+ }
7687
+ /**
7688
+ * Filter column value outside an inclusive range (NOT BETWEEN)
7689
+ * Generates: OR (column < min OR column > max)
7690
+ * Multiple notBetween calls on the same column AND together
7691
+ *
7692
+ * @param column - Column name to filter
7693
+ * @param min - Minimum value of excluded range
7694
+ * @param max - Maximum value of excluded range
7695
+ * @example notBetween('recorded_at', '2024-01-01', '2024-01-10')
7696
+ * @example notBetween('price', 0, 10) // Excludes items priced 0-10
7697
+ */
7698
+ notBetween(column, min, max) {
7699
+ return this.filter(column, "not.between", [min, max]);
7700
+ }
6385
7701
  // PostGIS Spatial Query Methods
6386
7702
  /**
6387
7703
  * Check if geometries intersect (PostGIS ST_Intersects)
@@ -6990,6 +8306,19 @@ var QueryBuilder = class {
6990
8306
  for (const andFilter of this.andFilters) {
6991
8307
  params.append("and", `(${andFilter})`);
6992
8308
  }
8309
+ for (const bf of this.betweenFilters) {
8310
+ const minFormatted = this.formatValue(bf.min);
8311
+ const maxFormatted = this.formatValue(bf.max);
8312
+ if (bf.negated) {
8313
+ params.append(
8314
+ "or",
8315
+ `(${bf.column}.lt.${minFormatted},${bf.column}.gt.${maxFormatted})`
8316
+ );
8317
+ } else {
8318
+ params.append(bf.column, `gte.${minFormatted}`);
8319
+ params.append(bf.column, `lte.${maxFormatted}`);
8320
+ }
8321
+ }
6993
8322
  if (this.groupByColumns && this.groupByColumns.length > 0) {
6994
8323
  params.append("group_by", this.groupByColumns.join(","));
6995
8324
  }
@@ -7029,6 +8358,34 @@ var QueryBuilder = class {
7029
8358
  }
7030
8359
  return String(value);
7031
8360
  }
8361
+ /**
8362
+ * Validate between filter value - must be array of exactly 2 elements
8363
+ * @throws Error if value is invalid
8364
+ */
8365
+ validateBetweenValue(value, operator) {
8366
+ if (!Array.isArray(value)) {
8367
+ throw new Error(
8368
+ `Invalid value for '${operator}' operator: expected array of [min, max], got ${typeof value}`
8369
+ );
8370
+ }
8371
+ if (value.length !== 2) {
8372
+ throw new Error(
8373
+ `Invalid value for '${operator}' operator: expected array with exactly 2 elements [min, max], got ${value.length} elements`
8374
+ );
8375
+ }
8376
+ const [min, max] = value;
8377
+ if (min === null || min === void 0) {
8378
+ throw new Error(
8379
+ `Invalid value for '${operator}' operator: min value cannot be null or undefined`
8380
+ );
8381
+ }
8382
+ if (max === null || max === void 0) {
8383
+ throw new Error(
8384
+ `Invalid value for '${operator}' operator: max value cannot be null or undefined`
8385
+ );
8386
+ }
8387
+ return [min, max];
8388
+ }
7032
8389
  /**
7033
8390
  * Parse the Content-Range header to extract the total count
7034
8391
  * Header format: "0-999/50000" or "* /50000" (when no rows returned)
@@ -7113,6 +8470,9 @@ var FluxbaseClient = class {
7113
8470
  this.admin = new FluxbaseAdmin(this.fetch);
7114
8471
  this.management = new FluxbaseManagement(this.fetch);
7115
8472
  this.settings = new SettingsClient(this.fetch);
8473
+ const wsProtocol = fluxbaseUrl.startsWith("https") ? "wss" : "ws";
8474
+ const wsBaseUrl = fluxbaseUrl.replace(/^https?:/, wsProtocol + ":");
8475
+ this.ai = new FluxbaseAI(this.fetch, wsBaseUrl);
7116
8476
  this.setupAuthSync();
7117
8477
  }
7118
8478
  /**
@@ -7173,38 +8533,6 @@ var FluxbaseClient = class {
7173
8533
  schema(schemaName) {
7174
8534
  return new SchemaQueryBuilder(this.fetch, schemaName);
7175
8535
  }
7176
- /**
7177
- * Call a PostgreSQL function (Remote Procedure Call)
7178
- *
7179
- * @param functionName - The name of the PostgreSQL function to call
7180
- * @param params - Optional parameters to pass to the function
7181
- * @returns Promise containing the function result or error
7182
- *
7183
- * @example
7184
- * ```typescript
7185
- * // Call a function without parameters
7186
- * const { data, error } = await client.rpc('get_total_users')
7187
- *
7188
- * // Call a function with parameters
7189
- * const { data, error } = await client.rpc('calculate_discount', {
7190
- * product_id: 123,
7191
- * coupon_code: 'SAVE20'
7192
- * })
7193
- * ```
7194
- *
7195
- * @category Database
7196
- */
7197
- async rpc(functionName, params) {
7198
- try {
7199
- const data = await this.fetch.post(
7200
- `/api/v1/rpc/${functionName}`,
7201
- params || {}
7202
- );
7203
- return { data, error: null };
7204
- } catch (error) {
7205
- return { data: null, error };
7206
- }
7207
- }
7208
8536
  /**
7209
8537
  * Sync auth state with realtime connections
7210
8538
  * @internal
@@ -7332,6 +8660,163 @@ function createClient(fluxbaseUrl, fluxbaseKey, options) {
7332
8660
  return new FluxbaseClient(url, key, options);
7333
8661
  }
7334
8662
 
7335
- 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, SchemaQueryBuilder, SettingsClient, StorageBucket, SystemSettingsManager, WebhooksManager, createClient };
8663
+ // src/rpc.ts
8664
+ var FluxbaseRPC = class {
8665
+ constructor(fetch2) {
8666
+ this.fetch = fetch2;
8667
+ }
8668
+ /**
8669
+ * List available RPC procedures (public, enabled)
8670
+ *
8671
+ * @param namespace - Optional namespace filter
8672
+ * @returns Promise resolving to { data, error } tuple with array of procedure summaries
8673
+ */
8674
+ async list(namespace) {
8675
+ try {
8676
+ const params = namespace ? `?namespace=${encodeURIComponent(namespace)}` : "";
8677
+ const response = await this.fetch.get(
8678
+ `/api/v1/rpc/procedures${params}`
8679
+ );
8680
+ return { data: response.procedures || [], error: null };
8681
+ } catch (error) {
8682
+ return { data: null, error };
8683
+ }
8684
+ }
8685
+ /**
8686
+ * Invoke an RPC procedure
8687
+ *
8688
+ * @param name - Procedure name
8689
+ * @param params - Optional parameters to pass to the procedure
8690
+ * @param options - Optional invocation options
8691
+ * @returns Promise resolving to { data, error } tuple with invocation response
8692
+ *
8693
+ * @example
8694
+ * ```typescript
8695
+ * // Synchronous invocation
8696
+ * const { data, error } = await fluxbase.rpc.invoke('get-user-orders', {
8697
+ * user_id: '123',
8698
+ * limit: 10
8699
+ * });
8700
+ * console.log(data.result); // Query results
8701
+ *
8702
+ * // Asynchronous invocation
8703
+ * const { data: asyncData } = await fluxbase.rpc.invoke('generate-report', {
8704
+ * year: 2024
8705
+ * }, { async: true });
8706
+ * console.log(asyncData.execution_id); // Use to poll status
8707
+ * ```
8708
+ */
8709
+ async invoke(name, params, options) {
8710
+ try {
8711
+ const namespace = options?.namespace || "default";
8712
+ const response = await this.fetch.post(
8713
+ `/api/v1/rpc/${encodeURIComponent(namespace)}/${encodeURIComponent(name)}`,
8714
+ {
8715
+ params,
8716
+ async: options?.async
8717
+ }
8718
+ );
8719
+ return { data: response, error: null };
8720
+ } catch (error) {
8721
+ return { data: null, error };
8722
+ }
8723
+ }
8724
+ /**
8725
+ * Get execution status (for async invocations or checking history)
8726
+ *
8727
+ * @param executionId - The execution ID returned from async invoke
8728
+ * @returns Promise resolving to { data, error } tuple with execution details
8729
+ *
8730
+ * @example
8731
+ * ```typescript
8732
+ * const { data, error } = await fluxbase.rpc.getStatus('execution-uuid');
8733
+ * if (data.status === 'completed') {
8734
+ * console.log('Result:', data.result);
8735
+ * } else if (data.status === 'running') {
8736
+ * console.log('Still running...');
8737
+ * }
8738
+ * ```
8739
+ */
8740
+ async getStatus(executionId) {
8741
+ try {
8742
+ const data = await this.fetch.get(
8743
+ `/api/v1/rpc/executions/${encodeURIComponent(executionId)}`
8744
+ );
8745
+ return { data, error: null };
8746
+ } catch (error) {
8747
+ return { data: null, error };
8748
+ }
8749
+ }
8750
+ /**
8751
+ * Get execution logs (for debugging and monitoring)
8752
+ *
8753
+ * @param executionId - The execution ID
8754
+ * @param afterLine - Optional line number to get logs after (for polling)
8755
+ * @returns Promise resolving to { data, error } tuple with execution logs
8756
+ *
8757
+ * @example
8758
+ * ```typescript
8759
+ * const { data: logs } = await fluxbase.rpc.getLogs('execution-uuid');
8760
+ * for (const log of logs) {
8761
+ * console.log(`[${log.level}] ${log.message}`);
8762
+ * }
8763
+ * ```
8764
+ */
8765
+ async getLogs(executionId, afterLine) {
8766
+ try {
8767
+ const params = afterLine !== void 0 ? `?after=${afterLine}` : "";
8768
+ const response = await this.fetch.get(
8769
+ `/api/v1/rpc/executions/${encodeURIComponent(executionId)}/logs${params}`
8770
+ );
8771
+ return { data: response.logs || [], error: null };
8772
+ } catch (error) {
8773
+ return { data: null, error };
8774
+ }
8775
+ }
8776
+ /**
8777
+ * Poll for execution completion with exponential backoff
8778
+ *
8779
+ * @param executionId - The execution ID to poll
8780
+ * @param options - Polling options
8781
+ * @returns Promise resolving to final execution state
8782
+ *
8783
+ * @example
8784
+ * ```typescript
8785
+ * const { data: result } = await fluxbase.rpc.invoke('long-task', {}, { async: true });
8786
+ * const { data: final } = await fluxbase.rpc.waitForCompletion(result.execution_id, {
8787
+ * maxWaitMs: 60000, // Wait up to 1 minute
8788
+ * onProgress: (exec) => console.log(`Status: ${exec.status}`)
8789
+ * });
8790
+ * console.log('Final result:', final.result);
8791
+ * ```
8792
+ */
8793
+ async waitForCompletion(executionId, options) {
8794
+ const maxWait = options?.maxWaitMs || 3e4;
8795
+ const initialInterval = options?.initialIntervalMs || 500;
8796
+ const maxInterval = options?.maxIntervalMs || 5e3;
8797
+ const startTime = Date.now();
8798
+ let interval = initialInterval;
8799
+ while (Date.now() - startTime < maxWait) {
8800
+ const { data: execution, error } = await this.getStatus(executionId);
8801
+ if (error) {
8802
+ return { data: null, error };
8803
+ }
8804
+ if (!execution) {
8805
+ return { data: null, error: new Error("Execution not found") };
8806
+ }
8807
+ if (options?.onProgress) {
8808
+ options.onProgress(execution);
8809
+ }
8810
+ if (execution.status === "completed" || execution.status === "failed" || execution.status === "cancelled" || execution.status === "timeout") {
8811
+ return { data: execution, error: null };
8812
+ }
8813
+ await new Promise((resolve) => setTimeout(resolve, interval));
8814
+ interval = Math.min(interval * 1.5, maxInterval);
8815
+ }
8816
+ return { data: null, error: new Error("Timeout waiting for execution to complete") };
8817
+ }
8818
+ };
8819
+
8820
+ export { APIKeysManager, AppSettingsManager, AuthSettingsManager, DDLManager, EmailTemplateManager, FluxbaseAI, FluxbaseAIChat, FluxbaseAdmin, FluxbaseAdminAI, FluxbaseAdminFunctions, FluxbaseAdminJobs, FluxbaseAdminMigrations, FluxbaseAdminRPC, FluxbaseAuth, FluxbaseClient, FluxbaseFetch, FluxbaseFunctions, FluxbaseJobs, FluxbaseManagement, FluxbaseOAuth, FluxbaseRPC, FluxbaseRealtime, FluxbaseSettings, FluxbaseStorage, ImpersonationManager, InvitationsManager, OAuthProviderManager, QueryBuilder, RealtimeChannel, SchemaQueryBuilder, SettingsClient, StorageBucket, SystemSettingsManager, WebhooksManager, bundleCode, createClient, denoExternalPlugin, loadImportMap };
7336
8821
  //# sourceMappingURL=index.js.map
7337
8822
  //# sourceMappingURL=index.js.map