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