@fluxbase/sdk 2026.1.8 → 2026.1.9-rc.1

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
@@ -1428,8 +1428,9 @@ var RealtimeChannel = class {
1428
1428
  this.presenceCallbacks = /* @__PURE__ */ new Map();
1429
1429
  this.broadcastCallbacks = /* @__PURE__ */ new Map();
1430
1430
  this.executionLogCallbacks = /* @__PURE__ */ new Set();
1431
- this.subscriptionConfig = null;
1432
- this.subscriptionId = null;
1431
+ this.subscriptionConfigs = [];
1432
+ this.subscriptionIds = /* @__PURE__ */ new Map();
1433
+ // "schema.table" -> subscription_id
1433
1434
  this.executionLogConfig = null;
1434
1435
  this._presenceState = {};
1435
1436
  this.myPresenceKey = null;
@@ -1458,13 +1459,15 @@ var RealtimeChannel = class {
1458
1459
  on(event, configOrCallback, callback) {
1459
1460
  if (event === "postgres_changes" && typeof configOrCallback !== "function") {
1460
1461
  const config = configOrCallback;
1461
- this.subscriptionConfig = config;
1462
1462
  const actualCallback = callback;
1463
- const eventType = config.event;
1464
- if (!this.callbacks.has(eventType)) {
1465
- this.callbacks.set(eventType, /* @__PURE__ */ new Set());
1463
+ let entry = this.subscriptionConfigs.find(
1464
+ (e) => e.config.schema === config.schema && e.config.table === config.table && e.config.event === config.event && e.config.filter === config.filter
1465
+ );
1466
+ if (!entry) {
1467
+ entry = { config, callbacks: /* @__PURE__ */ new Set() };
1468
+ this.subscriptionConfigs.push(entry);
1466
1469
  }
1467
- this.callbacks.get(eventType).add(actualCallback);
1470
+ entry.callbacks.add(actualCallback);
1468
1471
  } else if (event === "broadcast" && typeof configOrCallback !== "function") {
1469
1472
  const config = configOrCallback;
1470
1473
  const actualCallback = callback;
@@ -1535,11 +1538,20 @@ var RealtimeChannel = class {
1535
1538
  this.shouldReconnect = false;
1536
1539
  return new Promise((resolve) => {
1537
1540
  if (this.ws) {
1538
- this.sendMessage({
1539
- type: "unsubscribe",
1540
- channel: this.channelName,
1541
- subscription_id: this.subscriptionId || void 0
1542
- });
1541
+ if (this.subscriptionIds.size > 0) {
1542
+ for (const subId of this.subscriptionIds.values()) {
1543
+ this.sendMessage({
1544
+ type: "unsubscribe",
1545
+ channel: this.channelName,
1546
+ subscription_id: subId
1547
+ });
1548
+ }
1549
+ } else {
1550
+ this.sendMessage({
1551
+ type: "unsubscribe",
1552
+ channel: this.channelName
1553
+ });
1554
+ }
1543
1555
  const startTime = Date.now();
1544
1556
  const maxWait = timeout || 5e3;
1545
1557
  const checkDisconnect = () => {
@@ -1774,14 +1786,20 @@ var RealtimeChannel = class {
1774
1786
  }
1775
1787
  };
1776
1788
  this.sendMessage(logSubscribeMessage);
1789
+ } else if (this.subscriptionConfigs.length > 0) {
1790
+ for (const entry of this.subscriptionConfigs) {
1791
+ const subscribeMessage = {
1792
+ type: "subscribe",
1793
+ channel: this.channelName,
1794
+ config: entry.config
1795
+ };
1796
+ this.sendMessage(subscribeMessage);
1797
+ }
1777
1798
  } else {
1778
1799
  const subscribeMessage = {
1779
1800
  type: "subscribe",
1780
1801
  channel: this.channelName
1781
1802
  };
1782
- if (this.subscriptionConfig) {
1783
- subscribeMessage.config = this.subscriptionConfig;
1784
- }
1785
1803
  this.sendMessage(subscribeMessage);
1786
1804
  }
1787
1805
  this.startHeartbeat();
@@ -1861,18 +1879,29 @@ var RealtimeChannel = class {
1861
1879
  this.pendingAcks.delete("access_token");
1862
1880
  }
1863
1881
  console.log("[Fluxbase Realtime] Token updated successfully");
1864
- } else {
1865
- if (payload.subscription_id) {
1866
- this.subscriptionId = payload.subscription_id;
1867
- console.log("[Fluxbase Realtime] Subscription ID received:", this.subscriptionId);
1882
+ } else if (payload.subscription_id) {
1883
+ const schema = payload.schema || "public";
1884
+ const table = payload.table || "";
1885
+ if (table) {
1886
+ this.subscriptionIds.set(`${schema}.${table}`, payload.subscription_id);
1887
+ console.log("[Fluxbase Realtime] Subscription ID received for", `${schema}.${table}:`, payload.subscription_id);
1868
1888
  } else {
1869
- console.log("[Fluxbase Realtime] Acknowledged:", message);
1889
+ console.log("[Fluxbase Realtime] Subscription ID received:", payload.subscription_id);
1870
1890
  }
1891
+ } else {
1892
+ console.log("[Fluxbase Realtime] Acknowledged:", message);
1871
1893
  }
1872
1894
  } else {
1873
1895
  if (message.payload && typeof message.payload === "object" && "subscription_id" in message.payload) {
1874
- this.subscriptionId = message.payload.subscription_id;
1875
- console.log("[Fluxbase Realtime] Subscription ID received:", this.subscriptionId);
1896
+ const payload = message.payload;
1897
+ const schema = payload.schema || "public";
1898
+ const table = payload.table || "";
1899
+ if (table) {
1900
+ this.subscriptionIds.set(`${schema}.${table}`, payload.subscription_id);
1901
+ console.log("[Fluxbase Realtime] Subscription ID received for", `${schema}.${table}:`, payload.subscription_id);
1902
+ } else {
1903
+ console.log("[Fluxbase Realtime] Subscription ID received:", payload.subscription_id);
1904
+ }
1876
1905
  } else {
1877
1906
  console.log("[Fluxbase Realtime] Acknowledged:", message);
1878
1907
  }
@@ -1966,6 +1995,21 @@ var RealtimeChannel = class {
1966
1995
  old: payload.old_record || payload.old || {},
1967
1996
  errors: payload.errors || null
1968
1997
  };
1998
+ for (const entry of this.subscriptionConfigs) {
1999
+ const c = entry.config;
2000
+ const schemaMatch = !c.schema || c.schema === supabasePayload.schema;
2001
+ const tableMatch = !c.table || c.table === supabasePayload.table;
2002
+ const eventMatch = c.event === "*" || c.event === supabasePayload.eventType;
2003
+ if (schemaMatch && tableMatch && eventMatch) {
2004
+ entry.callbacks.forEach((cb) => {
2005
+ try {
2006
+ cb(supabasePayload);
2007
+ } catch (err) {
2008
+ console.error("[Fluxbase Realtime] Error in postgres_changes callback:", err);
2009
+ }
2010
+ });
2011
+ }
2012
+ }
1969
2013
  const callbacks = this.callbacks.get(supabasePayload.eventType);
1970
2014
  if (callbacks) {
1971
2015
  callbacks.forEach((callback) => callback(supabasePayload));
@@ -8890,6 +8934,168 @@ var FluxbaseAdminStorage = class {
8890
8934
  }
8891
8935
  };
8892
8936
 
8937
+ // src/admin-realtime.ts
8938
+ var FluxbaseAdminRealtime = class {
8939
+ constructor(fetch2) {
8940
+ this.fetch = fetch2;
8941
+ }
8942
+ /**
8943
+ * Enable realtime on a table
8944
+ *
8945
+ * Creates the necessary database triggers to broadcast changes to WebSocket subscribers.
8946
+ * Also sets REPLICA IDENTITY FULL to include old values in UPDATE/DELETE events.
8947
+ *
8948
+ * @param table - Table name to enable realtime on
8949
+ * @param options - Optional configuration
8950
+ * @returns Promise resolving to EnableRealtimeResponse
8951
+ *
8952
+ * @example
8953
+ * ```typescript
8954
+ * // Enable realtime on products table (all events)
8955
+ * await client.admin.realtime.enableRealtime('products')
8956
+ *
8957
+ * // Enable on a specific schema
8958
+ * await client.admin.realtime.enableRealtime('orders', {
8959
+ * schema: 'sales'
8960
+ * })
8961
+ *
8962
+ * // Enable specific events only
8963
+ * await client.admin.realtime.enableRealtime('audit_log', {
8964
+ * events: ['INSERT'] // Only broadcast inserts
8965
+ * })
8966
+ *
8967
+ * // Exclude large columns from notifications
8968
+ * await client.admin.realtime.enableRealtime('posts', {
8969
+ * exclude: ['content', 'raw_html'] // Skip these in payload
8970
+ * })
8971
+ * ```
8972
+ */
8973
+ async enableRealtime(table, options) {
8974
+ const request = {
8975
+ schema: options?.schema ?? "public",
8976
+ table,
8977
+ events: options?.events,
8978
+ exclude: options?.exclude
8979
+ };
8980
+ return await this.fetch.post(
8981
+ "/api/v1/admin/realtime/tables",
8982
+ request
8983
+ );
8984
+ }
8985
+ /**
8986
+ * Disable realtime on a table
8987
+ *
8988
+ * Removes the realtime trigger from a table. Existing subscribers will stop
8989
+ * receiving updates for this table.
8990
+ *
8991
+ * @param schema - Schema name
8992
+ * @param table - Table name
8993
+ * @returns Promise resolving to success message
8994
+ *
8995
+ * @example
8996
+ * ```typescript
8997
+ * await client.admin.realtime.disableRealtime('public', 'products')
8998
+ * console.log('Realtime disabled')
8999
+ * ```
9000
+ */
9001
+ async disableRealtime(schema, table) {
9002
+ return await this.fetch.delete(
9003
+ `/api/v1/admin/realtime/tables/${encodeURIComponent(schema)}/${encodeURIComponent(table)}`
9004
+ );
9005
+ }
9006
+ /**
9007
+ * List all realtime-enabled tables
9008
+ *
9009
+ * Returns a list of all tables that have realtime enabled, along with their
9010
+ * configuration (events, excluded columns, etc.).
9011
+ *
9012
+ * @param options - Optional filter options
9013
+ * @returns Promise resolving to ListRealtimeTablesResponse
9014
+ *
9015
+ * @example
9016
+ * ```typescript
9017
+ * // List all enabled tables
9018
+ * const { tables, count } = await client.admin.realtime.listTables()
9019
+ * console.log(`${count} tables have realtime enabled`)
9020
+ *
9021
+ * tables.forEach(t => {
9022
+ * console.log(`${t.schema}.${t.table}: ${t.events.join(', ')}`)
9023
+ * })
9024
+ *
9025
+ * // Include disabled tables
9026
+ * const all = await client.admin.realtime.listTables({ includeDisabled: true })
9027
+ * ```
9028
+ */
9029
+ async listTables(options) {
9030
+ const params = options?.includeDisabled ? "?enabled=false" : "";
9031
+ return await this.fetch.get(
9032
+ `/api/v1/admin/realtime/tables${params}`
9033
+ );
9034
+ }
9035
+ /**
9036
+ * Get realtime status for a specific table
9037
+ *
9038
+ * Returns the realtime configuration for a table, including whether it's enabled,
9039
+ * which events are tracked, and which columns are excluded.
9040
+ *
9041
+ * @param schema - Schema name
9042
+ * @param table - Table name
9043
+ * @returns Promise resolving to RealtimeTableStatus
9044
+ *
9045
+ * @example
9046
+ * ```typescript
9047
+ * const status = await client.admin.realtime.getStatus('public', 'products')
9048
+ *
9049
+ * if (status.realtime_enabled) {
9050
+ * console.log('Events:', status.events.join(', '))
9051
+ * console.log('Excluded:', status.excluded_columns?.join(', ') || 'none')
9052
+ * } else {
9053
+ * console.log('Realtime not enabled')
9054
+ * }
9055
+ * ```
9056
+ */
9057
+ async getStatus(schema, table) {
9058
+ return await this.fetch.get(
9059
+ `/api/v1/admin/realtime/tables/${encodeURIComponent(schema)}/${encodeURIComponent(table)}`
9060
+ );
9061
+ }
9062
+ /**
9063
+ * Update realtime configuration for a table
9064
+ *
9065
+ * Modifies the events or excluded columns for a realtime-enabled table
9066
+ * without recreating the trigger.
9067
+ *
9068
+ * @param schema - Schema name
9069
+ * @param table - Table name
9070
+ * @param config - New configuration
9071
+ * @returns Promise resolving to success message
9072
+ *
9073
+ * @example
9074
+ * ```typescript
9075
+ * // Change which events are tracked
9076
+ * await client.admin.realtime.updateConfig('public', 'products', {
9077
+ * events: ['INSERT', 'UPDATE'] // Stop tracking deletes
9078
+ * })
9079
+ *
9080
+ * // Update excluded columns
9081
+ * await client.admin.realtime.updateConfig('public', 'posts', {
9082
+ * exclude: ['raw_content', 'search_vector']
9083
+ * })
9084
+ *
9085
+ * // Clear excluded columns
9086
+ * await client.admin.realtime.updateConfig('public', 'posts', {
9087
+ * exclude: [] // Include all columns again
9088
+ * })
9089
+ * ```
9090
+ */
9091
+ async updateConfig(schema, table, config) {
9092
+ return await this.fetch.patch(
9093
+ `/api/v1/admin/realtime/tables/${encodeURIComponent(schema)}/${encodeURIComponent(table)}`,
9094
+ config
9095
+ );
9096
+ }
9097
+ };
9098
+
8893
9099
  // src/admin.ts
8894
9100
  var FluxbaseAdmin = class {
8895
9101
  constructor(fetch2) {
@@ -8907,6 +9113,7 @@ var FluxbaseAdmin = class {
8907
9113
  this.ai = new FluxbaseAdminAI(fetch2);
8908
9114
  this.rpc = new FluxbaseAdminRPC(fetch2);
8909
9115
  this.storage = new FluxbaseAdminStorage(fetch2);
9116
+ this.realtime = new FluxbaseAdminRealtime(fetch2);
8910
9117
  }
8911
9118
  /**
8912
9119
  * Set admin authentication token
@@ -11935,6 +12142,7 @@ exports.FluxbaseAdminFunctions = FluxbaseAdminFunctions;
11935
12142
  exports.FluxbaseAdminJobs = FluxbaseAdminJobs;
11936
12143
  exports.FluxbaseAdminMigrations = FluxbaseAdminMigrations;
11937
12144
  exports.FluxbaseAdminRPC = FluxbaseAdminRPC;
12145
+ exports.FluxbaseAdminRealtime = FluxbaseAdminRealtime;
11938
12146
  exports.FluxbaseAdminStorage = FluxbaseAdminStorage;
11939
12147
  exports.FluxbaseAuth = FluxbaseAuth;
11940
12148
  exports.FluxbaseBranching = FluxbaseBranching;