@fluxbase/sdk 0.0.1-rc.14 → 0.0.1-rc.16

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
@@ -604,22 +604,55 @@ var RealtimeChannel = class {
604
604
  }
605
605
  /**
606
606
  * Subscribe to the channel
607
+ * @param callback - Optional status callback (Supabase-compatible)
608
+ * @param _timeout - Optional timeout in milliseconds (currently unused)
607
609
  */
608
- subscribe() {
610
+ subscribe(callback, _timeout) {
609
611
  this.connect();
612
+ if (callback) {
613
+ const checkConnection = () => {
614
+ if (this.ws && this.ws.readyState === WebSocket.OPEN) {
615
+ callback("SUBSCRIBED");
616
+ } else if (this.ws && this.ws.readyState === WebSocket.CLOSED) {
617
+ callback("CHANNEL_ERROR", new Error("Failed to connect"));
618
+ } else {
619
+ setTimeout(checkConnection, 100);
620
+ }
621
+ };
622
+ setTimeout(checkConnection, 100);
623
+ }
610
624
  return this;
611
625
  }
612
626
  /**
613
627
  * Unsubscribe from the channel
614
- */
615
- unsubscribe() {
616
- if (this.ws) {
617
- this.send({
618
- type: "unsubscribe",
619
- channel: this.channelName
620
- });
621
- this.disconnect();
622
- }
628
+ * @param timeout - Optional timeout in milliseconds
629
+ * @returns Promise resolving to status string (Supabase-compatible)
630
+ */
631
+ async unsubscribe(timeout) {
632
+ return new Promise((resolve) => {
633
+ if (this.ws) {
634
+ this.send({
635
+ type: "unsubscribe",
636
+ channel: this.channelName
637
+ });
638
+ const startTime = Date.now();
639
+ const maxWait = timeout || 5e3;
640
+ const checkDisconnect = () => {
641
+ if (!this.ws || this.ws.readyState === WebSocket.CLOSED) {
642
+ this.disconnect();
643
+ resolve("ok");
644
+ } else if (Date.now() - startTime > maxWait) {
645
+ this.disconnect();
646
+ resolve("timed out");
647
+ } else {
648
+ setTimeout(checkDisconnect, 100);
649
+ }
650
+ };
651
+ setTimeout(checkDisconnect, 100);
652
+ } else {
653
+ resolve("ok");
654
+ }
655
+ });
623
656
  }
624
657
  /**
625
658
  * Internal: Connect to WebSocket
@@ -708,13 +741,22 @@ var RealtimeChannel = class {
708
741
  * Internal: Handle broadcast message
709
742
  */
710
743
  handleBroadcast(payload) {
711
- const callbacks = this.callbacks.get(payload.type);
744
+ const supabasePayload = {
745
+ eventType: payload.type || payload.eventType,
746
+ schema: payload.schema,
747
+ table: payload.table,
748
+ commit_timestamp: payload.timestamp || payload.commit_timestamp || (/* @__PURE__ */ new Date()).toISOString(),
749
+ new: payload.new_record || payload.new || {},
750
+ old: payload.old_record || payload.old || {},
751
+ errors: payload.errors || null
752
+ };
753
+ const callbacks = this.callbacks.get(supabasePayload.eventType);
712
754
  if (callbacks) {
713
- callbacks.forEach((callback) => callback(payload));
755
+ callbacks.forEach((callback) => callback(supabasePayload));
714
756
  }
715
757
  const wildcardCallbacks = this.callbacks.get("*");
716
758
  if (wildcardCallbacks) {
717
- wildcardCallbacks.forEach((callback) => callback(payload));
759
+ wildcardCallbacks.forEach((callback) => callback(supabasePayload));
718
760
  }
719
761
  }
720
762
  /**
@@ -744,7 +786,9 @@ var RealtimeChannel = class {
744
786
  }
745
787
  this.reconnectAttempts++;
746
788
  const delay = this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1);
747
- console.log(`[Fluxbase Realtime] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`);
789
+ console.log(
790
+ `[Fluxbase Realtime] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`
791
+ );
748
792
  setTimeout(() => {
749
793
  this.connect();
750
794
  }, delay);
@@ -812,7 +856,7 @@ var StorageBucket = class {
812
856
  if (options?.upsert !== void 0) {
813
857
  formData.append("upsert", String(options.upsert));
814
858
  }
815
- const data = await this.fetch.request(
859
+ const response = await this.fetch.request(
816
860
  `/api/v1/storage/${this.bucketName}/${path}`,
817
861
  {
818
862
  method: "POST",
@@ -821,7 +865,14 @@ var StorageBucket = class {
821
865
  // Let browser set Content-Type for FormData
822
866
  }
823
867
  );
824
- return { data, error: null };
868
+ return {
869
+ data: {
870
+ id: response.id || response.key || path,
871
+ path,
872
+ fullPath: `${this.bucketName}/${path}`
873
+ },
874
+ error: null
875
+ };
825
876
  } catch (error) {
826
877
  return { data: null, error };
827
878
  }
@@ -849,13 +900,24 @@ var StorageBucket = class {
849
900
  }
850
901
  /**
851
902
  * List files in the bucket
852
- * @param options - List options (prefix, limit, offset)
903
+ * Supports both Supabase-style list(path, options) and Fluxbase-style list(options)
904
+ * @param pathOrOptions - The folder path or list options
905
+ * @param maybeOptions - List options when first param is a path
853
906
  */
854
- async list(options) {
907
+ async list(pathOrOptions, maybeOptions) {
855
908
  try {
856
909
  const params = new URLSearchParams();
857
- if (options?.prefix) {
858
- params.set("prefix", options.prefix);
910
+ let prefix;
911
+ let options;
912
+ if (typeof pathOrOptions === "string") {
913
+ prefix = pathOrOptions;
914
+ options = maybeOptions;
915
+ } else {
916
+ options = pathOrOptions;
917
+ prefix = options?.prefix;
918
+ }
919
+ if (prefix) {
920
+ params.set("prefix", prefix);
859
921
  }
860
922
  if (options?.limit) {
861
923
  params.set("limit", String(options.limit));
@@ -865,8 +927,17 @@ var StorageBucket = class {
865
927
  }
866
928
  const queryString = params.toString();
867
929
  const path = `/api/v1/storage/${this.bucketName}${queryString ? `?${queryString}` : ""}`;
868
- const data = await this.fetch.get(path);
869
- return { data: data.files || [], error: null };
930
+ const response = await this.fetch.get(path);
931
+ const files = (response.files || []).map((file) => ({
932
+ name: file.key || file.name,
933
+ id: file.id,
934
+ bucket_id: file.bucket || this.bucketName,
935
+ created_at: file.last_modified || file.created_at,
936
+ updated_at: file.updated_at,
937
+ last_accessed_at: file.last_accessed_at,
938
+ metadata: file.metadata
939
+ }));
940
+ return { data: files, error: null };
870
941
  } catch (error) {
871
942
  return { data: null, error };
872
943
  }
@@ -877,10 +948,15 @@ var StorageBucket = class {
877
948
  */
878
949
  async remove(paths) {
879
950
  try {
951
+ const removedFiles = [];
880
952
  for (const path of paths) {
881
953
  await this.fetch.delete(`/api/v1/storage/${this.bucketName}/${path}`);
954
+ removedFiles.push({
955
+ name: path,
956
+ bucket_id: this.bucketName
957
+ });
882
958
  }
883
- return { data: null, error: null };
959
+ return { data: removedFiles, error: null };
884
960
  } catch (error) {
885
961
  return { data: null, error };
886
962
  }
@@ -917,14 +993,17 @@ var StorageBucket = class {
917
993
  */
918
994
  async move(fromPath, toPath) {
919
995
  try {
920
- const data = await this.fetch.post(
996
+ await this.fetch.post(
921
997
  `/api/v1/storage/${this.bucketName}/move`,
922
998
  {
923
999
  from_path: fromPath,
924
1000
  to_path: toPath
925
1001
  }
926
1002
  );
927
- return { data, error: null };
1003
+ return {
1004
+ data: { message: "Successfully moved" },
1005
+ error: null
1006
+ };
928
1007
  } catch (error) {
929
1008
  return { data: null, error };
930
1009
  }
@@ -936,14 +1015,17 @@ var StorageBucket = class {
936
1015
  */
937
1016
  async copy(fromPath, toPath) {
938
1017
  try {
939
- const data = await this.fetch.post(
1018
+ await this.fetch.post(
940
1019
  `/api/v1/storage/${this.bucketName}/copy`,
941
1020
  {
942
1021
  from_path: fromPath,
943
1022
  to_path: toPath
944
1023
  }
945
1024
  );
946
- return { data, error: null };
1025
+ return {
1026
+ data: { path: toPath },
1027
+ error: null
1028
+ };
947
1029
  } catch (error) {
948
1030
  return { data: null, error };
949
1031
  }
@@ -1026,7 +1108,7 @@ var FluxbaseStorage = class {
1026
1108
  async createBucket(bucketName) {
1027
1109
  try {
1028
1110
  await this.fetch.post(`/api/v1/storage/buckets/${bucketName}`);
1029
- return { data: null, error: null };
1111
+ return { data: { name: bucketName }, error: null };
1030
1112
  } catch (error) {
1031
1113
  return { data: null, error };
1032
1114
  }
@@ -1038,7 +1120,7 @@ var FluxbaseStorage = class {
1038
1120
  async deleteBucket(bucketName) {
1039
1121
  try {
1040
1122
  await this.fetch.delete(`/api/v1/storage/buckets/${bucketName}`);
1041
- return { data: null, error: null };
1123
+ return { data: { message: "Successfully deleted" }, error: null };
1042
1124
  } catch (error) {
1043
1125
  return { data: null, error };
1044
1126
  }
@@ -1055,13 +1137,13 @@ var FluxbaseStorage = class {
1055
1137
  return { data: null, error: listError };
1056
1138
  }
1057
1139
  if (objects && objects.length > 0) {
1058
- const paths = objects.map((obj) => obj.key);
1140
+ const paths = objects.map((obj) => obj.name);
1059
1141
  const { error: removeError } = await bucket.remove(paths);
1060
1142
  if (removeError) {
1061
1143
  return { data: null, error: removeError };
1062
1144
  }
1063
1145
  }
1064
- return { data: null, error: null };
1146
+ return { data: { message: "Successfully emptied" }, error: null };
1065
1147
  } catch (error) {
1066
1148
  return { data: null, error };
1067
1149
  }
@@ -1095,6 +1177,208 @@ var FluxbaseStorage = class {
1095
1177
  }
1096
1178
  };
1097
1179
 
1180
+ // src/functions.ts
1181
+ var FluxbaseFunctions = class {
1182
+ constructor(fetch2) {
1183
+ this.fetch = fetch2;
1184
+ }
1185
+ /**
1186
+ * Invoke an edge function
1187
+ *
1188
+ * This method is fully compatible with Supabase's functions.invoke() API.
1189
+ *
1190
+ * @param functionName - The name of the function to invoke
1191
+ * @param options - Invocation options including body, headers, and HTTP method
1192
+ * @returns Promise resolving to { data, error } tuple
1193
+ *
1194
+ * @example
1195
+ * ```typescript
1196
+ * // Simple invocation
1197
+ * const { data, error } = await client.functions.invoke('hello', {
1198
+ * body: { name: 'World' }
1199
+ * })
1200
+ *
1201
+ * // With GET method
1202
+ * const { data, error } = await client.functions.invoke('get-data', {
1203
+ * method: 'GET'
1204
+ * })
1205
+ *
1206
+ * // With custom headers
1207
+ * const { data, error } = await client.functions.invoke('api-proxy', {
1208
+ * body: { query: 'search' },
1209
+ * headers: { 'Authorization': 'Bearer token' },
1210
+ * method: 'POST'
1211
+ * })
1212
+ * ```
1213
+ */
1214
+ async invoke(functionName, options) {
1215
+ try {
1216
+ const method = options?.method || "POST";
1217
+ const headers = options?.headers || {};
1218
+ const body = options?.body;
1219
+ const endpoint = `/api/v1/functions/${functionName}/invoke`;
1220
+ let response;
1221
+ switch (method) {
1222
+ case "GET":
1223
+ response = await this.fetch.get(endpoint, { headers });
1224
+ break;
1225
+ case "DELETE":
1226
+ response = await this.fetch.delete(endpoint, { headers });
1227
+ break;
1228
+ case "PUT":
1229
+ response = await this.fetch.put(endpoint, body, { headers });
1230
+ break;
1231
+ case "PATCH":
1232
+ response = await this.fetch.patch(endpoint, body, { headers });
1233
+ break;
1234
+ case "POST":
1235
+ default:
1236
+ response = await this.fetch.post(endpoint, body, { headers });
1237
+ break;
1238
+ }
1239
+ return { data: response, error: null };
1240
+ } catch (error) {
1241
+ return { data: null, error };
1242
+ }
1243
+ }
1244
+ /**
1245
+ * Create a new edge function
1246
+ *
1247
+ * @param request - Function configuration and code
1248
+ * @returns Promise resolving to { data, error } tuple with created function metadata
1249
+ *
1250
+ * @example
1251
+ * ```typescript
1252
+ * const { data, error } = await client.functions.create({
1253
+ * name: 'my-function',
1254
+ * code: 'export default async function handler(req) { return { hello: "world" } }',
1255
+ * enabled: true
1256
+ * })
1257
+ * ```
1258
+ */
1259
+ async create(request) {
1260
+ try {
1261
+ const data = await this.fetch.post("/api/v1/functions", request);
1262
+ return { data, error: null };
1263
+ } catch (error) {
1264
+ return { data: null, error };
1265
+ }
1266
+ }
1267
+ /**
1268
+ * List all edge functions
1269
+ *
1270
+ * @returns Promise resolving to { data, error } tuple with array of functions
1271
+ *
1272
+ * @example
1273
+ * ```typescript
1274
+ * const { data, error } = await client.functions.list()
1275
+ * if (data) {
1276
+ * console.log('Functions:', data.map(f => f.name))
1277
+ * }
1278
+ * ```
1279
+ */
1280
+ async list() {
1281
+ try {
1282
+ const data = await this.fetch.get("/api/v1/functions");
1283
+ return { data, error: null };
1284
+ } catch (error) {
1285
+ return { data: null, error };
1286
+ }
1287
+ }
1288
+ /**
1289
+ * Get details of a specific edge function
1290
+ *
1291
+ * @param name - Function name
1292
+ * @returns Promise resolving to { data, error } tuple with function metadata
1293
+ *
1294
+ * @example
1295
+ * ```typescript
1296
+ * const { data, error } = await client.functions.get('my-function')
1297
+ * if (data) {
1298
+ * console.log('Function version:', data.version)
1299
+ * }
1300
+ * ```
1301
+ */
1302
+ async get(name) {
1303
+ try {
1304
+ const data = await this.fetch.get(`/api/v1/functions/${name}`);
1305
+ return { data, error: null };
1306
+ } catch (error) {
1307
+ return { data: null, error };
1308
+ }
1309
+ }
1310
+ /**
1311
+ * Update an existing edge function
1312
+ *
1313
+ * @param name - Function name
1314
+ * @param updates - Fields to update
1315
+ * @returns Promise resolving to { data, error } tuple with updated function metadata
1316
+ *
1317
+ * @example
1318
+ * ```typescript
1319
+ * const { data, error } = await client.functions.update('my-function', {
1320
+ * enabled: false,
1321
+ * description: 'Updated description'
1322
+ * })
1323
+ * ```
1324
+ */
1325
+ async update(name, updates) {
1326
+ try {
1327
+ const data = await this.fetch.put(`/api/v1/functions/${name}`, updates);
1328
+ return { data, error: null };
1329
+ } catch (error) {
1330
+ return { data: null, error };
1331
+ }
1332
+ }
1333
+ /**
1334
+ * Delete an edge function
1335
+ *
1336
+ * @param name - Function name
1337
+ * @returns Promise resolving to { data, error } tuple
1338
+ *
1339
+ * @example
1340
+ * ```typescript
1341
+ * const { data, error } = await client.functions.delete('my-function')
1342
+ * ```
1343
+ */
1344
+ async delete(name) {
1345
+ try {
1346
+ await this.fetch.delete(`/api/v1/functions/${name}`);
1347
+ return { data: null, error: null };
1348
+ } catch (error) {
1349
+ return { data: null, error };
1350
+ }
1351
+ }
1352
+ /**
1353
+ * Get execution history for an edge function
1354
+ *
1355
+ * @param name - Function name
1356
+ * @param limit - Maximum number of executions to return (optional)
1357
+ * @returns Promise resolving to { data, error } tuple with execution records
1358
+ *
1359
+ * @example
1360
+ * ```typescript
1361
+ * const { data, error } = await client.functions.getExecutions('my-function', 10)
1362
+ * if (data) {
1363
+ * data.forEach(exec => {
1364
+ * console.log(`${exec.executed_at}: ${exec.status} (${exec.duration_ms}ms)`)
1365
+ * })
1366
+ * }
1367
+ * ```
1368
+ */
1369
+ async getExecutions(name, limit) {
1370
+ try {
1371
+ const params = limit ? `?limit=${limit}` : "";
1372
+ const data = await this.fetch.get(
1373
+ `/api/v1/functions/${name}/executions${params}`
1374
+ );
1375
+ return { data, error: null };
1376
+ } catch (error) {
1377
+ return { data: null, error };
1378
+ }
1379
+ }
1380
+ };
1381
+
1098
1382
  // src/settings.ts
1099
1383
  var SystemSettingsManager = class {
1100
1384
  constructor(fetch2) {
@@ -3684,8 +3968,12 @@ var FluxbaseClient = class {
3684
3968
  if (options.auth?.token) {
3685
3969
  this.fetch.setAuthToken(options.auth.token);
3686
3970
  }
3687
- this.realtime = new FluxbaseRealtime(options.url, options.auth?.token || null);
3971
+ this.realtime = new FluxbaseRealtime(
3972
+ options.url,
3973
+ options.auth?.token || null
3974
+ );
3688
3975
  this.storage = new FluxbaseStorage(this.fetch);
3976
+ this.functions = new FluxbaseFunctions(this.fetch);
3689
3977
  this.admin = new FluxbaseAdmin(this.fetch);
3690
3978
  this.management = new FluxbaseManagement(this.fetch);
3691
3979
  this.setupAuthSync();
@@ -3740,7 +4028,10 @@ var FluxbaseClient = class {
3740
4028
  */
3741
4029
  async rpc(functionName, params) {
3742
4030
  try {
3743
- const data = await this.fetch.post(`/api/v1/rpc/${functionName}`, params || {});
4031
+ const data = await this.fetch.post(
4032
+ `/api/v1/rpc/${functionName}`,
4033
+ params || {}
4034
+ );
3744
4035
  return { data, error: null };
3745
4036
  } catch (error) {
3746
4037
  return { data: null, error };
@@ -3780,6 +4071,36 @@ var FluxbaseClient = class {
3780
4071
  this.fetch.setAuthToken(token);
3781
4072
  this.realtime.setToken(token);
3782
4073
  }
4074
+ /**
4075
+ * Create or get a realtime channel (Supabase-compatible alias)
4076
+ *
4077
+ * This is a convenience method that delegates to client.realtime.channel().
4078
+ * Both patterns work identically:
4079
+ * - client.channel('room-1') - Supabase-style
4080
+ * - client.realtime.channel('room-1') - Fluxbase-style
4081
+ *
4082
+ * @param name - Channel name
4083
+ * @returns RealtimeChannel instance
4084
+ *
4085
+ * @example
4086
+ * ```typescript
4087
+ * // Supabase-compatible usage
4088
+ * const channel = client.channel('room-1')
4089
+ * .on('postgres_changes', {
4090
+ * event: '*',
4091
+ * schema: 'public',
4092
+ * table: 'messages'
4093
+ * }, (payload) => {
4094
+ * console.log('Change:', payload)
4095
+ * })
4096
+ * .subscribe()
4097
+ * ```
4098
+ *
4099
+ * @category Realtime
4100
+ */
4101
+ channel(name) {
4102
+ return this.realtime.channel(name);
4103
+ }
3783
4104
  /**
3784
4105
  * Get the internal HTTP client
3785
4106
  *
@@ -3812,6 +4133,7 @@ exports.FluxbaseAdmin = FluxbaseAdmin;
3812
4133
  exports.FluxbaseAuth = FluxbaseAuth;
3813
4134
  exports.FluxbaseClient = FluxbaseClient;
3814
4135
  exports.FluxbaseFetch = FluxbaseFetch;
4136
+ exports.FluxbaseFunctions = FluxbaseFunctions;
3815
4137
  exports.FluxbaseManagement = FluxbaseManagement;
3816
4138
  exports.FluxbaseOAuth = FluxbaseOAuth;
3817
4139
  exports.FluxbaseRealtime = FluxbaseRealtime;