@nimbleflux/fluxbase-sdk 2026.3.6 → 2026.3.7-rc.2

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
@@ -7,6 +7,7 @@ var FluxbaseFetch = class {
7
7
  this.isRefreshing = false;
8
8
  this.refreshPromise = null;
9
9
  this.anonKey = null;
10
+ this.beforeRequestCallback = null;
10
11
  this.baseUrl = baseUrl.replace(/\/$/, "");
11
12
  this.defaultHeaders = {
12
13
  "Content-Type": "application/json",
@@ -22,6 +23,14 @@ var FluxbaseFetch = class {
22
23
  setRefreshTokenCallback(callback) {
23
24
  this.refreshTokenCallback = callback;
24
25
  }
26
+ /**
27
+ * Register a callback to be called before every request.
28
+ * The callback receives the headers object and can modify it in place.
29
+ * This is useful for dynamically injecting headers at request time.
30
+ */
31
+ setBeforeRequestCallback(callback) {
32
+ this.beforeRequestCallback = callback;
33
+ }
25
34
  /**
26
35
  * Set the anon key for fallback authentication
27
36
  * When setAuthToken(null) is called, the Authorization header will be
@@ -43,6 +52,18 @@ var FluxbaseFetch = class {
43
52
  delete this.defaultHeaders["Authorization"];
44
53
  }
45
54
  }
55
+ /**
56
+ * Set a custom header on all requests
57
+ */
58
+ setHeader(name, value) {
59
+ this.defaultHeaders[name] = value;
60
+ }
61
+ /**
62
+ * Remove a custom header
63
+ */
64
+ removeHeader(name) {
65
+ delete this.defaultHeaders[name];
66
+ }
46
67
  /**
47
68
  * Make an HTTP request
48
69
  */
@@ -55,15 +76,23 @@ var FluxbaseFetch = class {
55
76
  async requestInternal(path, options, isRetry) {
56
77
  const url = `${this.baseUrl}${path}`;
57
78
  const headers = { ...this.defaultHeaders, ...options.headers };
79
+ if (this.beforeRequestCallback) {
80
+ this.beforeRequestCallback(headers);
81
+ }
58
82
  const controller = new AbortController();
59
- const timeoutId = setTimeout(() => controller.abort(), options.timeout ?? this.timeout);
83
+ const timeoutId = setTimeout(
84
+ () => controller.abort(),
85
+ options.timeout ?? this.timeout
86
+ );
60
87
  if (this.debug) {
61
88
  console.log(`[Fluxbase SDK] ${options.method} ${url}`, options.body);
62
89
  }
63
90
  try {
64
91
  const isFormData = options.body && (options.body.constructor?.name === "FormData" || options.body instanceof FormData);
65
92
  const requestHeaders = isFormData ? Object.fromEntries(
66
- Object.entries(headers).filter(([key]) => key.toLowerCase() !== "content-type")
93
+ Object.entries(headers).filter(
94
+ ([key]) => key.toLowerCase() !== "content-type"
95
+ )
67
96
  ) : headers;
68
97
  const response = await fetch(url, {
69
98
  method: options.method,
@@ -159,7 +188,11 @@ var FluxbaseFetch = class {
159
188
  * POST request that returns response with headers (for POST-based queries with count)
160
189
  */
161
190
  async postWithHeaders(path, body, options = {}) {
162
- return this.requestWithHeaders(path, { ...options, method: "POST", body });
191
+ return this.requestWithHeaders(path, {
192
+ ...options,
193
+ method: "POST",
194
+ body
195
+ });
163
196
  }
164
197
  /**
165
198
  * Make an HTTP request and return response with headers
@@ -173,15 +206,23 @@ var FluxbaseFetch = class {
173
206
  async requestWithHeadersInternal(path, options, isRetry) {
174
207
  const url = `${this.baseUrl}${path}`;
175
208
  const headers = { ...this.defaultHeaders, ...options.headers };
209
+ if (this.beforeRequestCallback) {
210
+ this.beforeRequestCallback(headers);
211
+ }
176
212
  const controller = new AbortController();
177
- const timeoutId = setTimeout(() => controller.abort(), options.timeout ?? this.timeout);
213
+ const timeoutId = setTimeout(
214
+ () => controller.abort(),
215
+ options.timeout ?? this.timeout
216
+ );
178
217
  if (this.debug) {
179
218
  console.log(`[Fluxbase SDK] ${options.method} ${url}`, options.body);
180
219
  }
181
220
  try {
182
221
  const isFormData = options.body && (options.body.constructor?.name === "FormData" || options.body instanceof FormData);
183
222
  const requestHeaders = isFormData ? Object.fromEntries(
184
- Object.entries(headers).filter(([key]) => key.toLowerCase() !== "content-type")
223
+ Object.entries(headers).filter(
224
+ ([key]) => key.toLowerCase() !== "content-type"
225
+ )
185
226
  ) : headers;
186
227
  const response = await fetch(url, {
187
228
  method: options.method,
@@ -262,6 +303,9 @@ var FluxbaseFetch = class {
262
303
  async head(path, options = {}) {
263
304
  const url = `${this.baseUrl}${path}`;
264
305
  const headers = { ...this.defaultHeaders, ...options.headers };
306
+ if (this.beforeRequestCallback) {
307
+ this.beforeRequestCallback(headers);
308
+ }
265
309
  const response = await fetch(url, {
266
310
  method: "HEAD",
267
311
  headers
@@ -274,9 +318,15 @@ var FluxbaseFetch = class {
274
318
  async getBlob(path, options = {}) {
275
319
  const url = `${this.baseUrl}${path}`;
276
320
  const headers = { ...this.defaultHeaders, ...options.headers };
321
+ if (this.beforeRequestCallback) {
322
+ this.beforeRequestCallback(headers);
323
+ }
277
324
  delete headers["Content-Type"];
278
325
  const controller = new AbortController();
279
- const timeoutId = setTimeout(() => controller.abort(), options.timeout ?? this.timeout);
326
+ const timeoutId = setTimeout(
327
+ () => controller.abort(),
328
+ options.timeout ?? this.timeout
329
+ );
280
330
  if (this.debug) {
281
331
  console.log(`[Fluxbase SDK] GET (blob) ${url}`);
282
332
  }
@@ -5130,6 +5180,59 @@ var EmailSettingsManager = class {
5130
5180
  async setProvider(provider) {
5131
5181
  return await this.update({ provider });
5132
5182
  }
5183
+ // Tenant-scoped methods
5184
+ /**
5185
+ * Get tenant-level email settings (resolved through cascade)
5186
+ *
5187
+ * Returns email settings resolved for the current tenant context,
5188
+ * including source information for each field.
5189
+ *
5190
+ * @returns Promise resolving to TenantEmailProviderSettings
5191
+ */
5192
+ async getForTenant() {
5193
+ return await this.fetch.get(
5194
+ "/api/v1/admin/email/settings/tenant"
5195
+ );
5196
+ }
5197
+ /**
5198
+ * Update tenant-level email settings
5199
+ *
5200
+ * Only provided fields are updated. These override instance-level defaults.
5201
+ *
5202
+ * @param request - Settings to update
5203
+ * @returns Promise resolving to TenantEmailProviderSettings
5204
+ */
5205
+ async updateForTenant(request) {
5206
+ return await this.fetch.put(
5207
+ "/api/v1/admin/email/settings/tenant",
5208
+ request
5209
+ );
5210
+ }
5211
+ /**
5212
+ * Delete a tenant-level email setting override
5213
+ *
5214
+ * Removes the tenant override for a specific field, reverting to the instance default.
5215
+ *
5216
+ * @param field - The field name to remove the override for
5217
+ * @returns Promise resolving to TenantEmailProviderSettings
5218
+ */
5219
+ async deleteTenantOverride(field) {
5220
+ return await this.fetch.delete(
5221
+ `/api/v1/admin/email/settings/tenant/${field}`
5222
+ );
5223
+ }
5224
+ /**
5225
+ * Test tenant-level email configuration
5226
+ *
5227
+ * @param recipientEmail - Email address to send the test email to
5228
+ * @returns Promise resolving to TestEmailSettingsResponse
5229
+ */
5230
+ async testForTenant(recipientEmail) {
5231
+ return await this.fetch.post(
5232
+ "/api/v1/admin/email/settings/tenant/test",
5233
+ { recipient_email: recipientEmail }
5234
+ );
5235
+ }
5133
5236
  };
5134
5237
  var FluxbaseSettings = class {
5135
5238
  constructor(fetch2) {
@@ -6130,7 +6233,10 @@ var ClientKeysManager = class {
6130
6233
  * ```
6131
6234
  */
6132
6235
  async create(request) {
6133
- return await this.fetch.post("/api/v1/client-keys", request);
6236
+ return await this.fetch.post(
6237
+ "/api/v1/client-keys",
6238
+ request
6239
+ );
6134
6240
  }
6135
6241
  /**
6136
6242
  * List all client keys for the authenticated user
@@ -6180,7 +6286,10 @@ var ClientKeysManager = class {
6180
6286
  * ```
6181
6287
  */
6182
6288
  async update(keyId, updates) {
6183
- return await this.fetch.patch(`/api/v1/client-keys/${keyId}`, updates);
6289
+ return await this.fetch.patch(
6290
+ `/api/v1/client-keys/${keyId}`,
6291
+ updates
6292
+ );
6184
6293
  }
6185
6294
  /**
6186
6295
  * Revoke a client key
@@ -6197,7 +6306,10 @@ var ClientKeysManager = class {
6197
6306
  * ```
6198
6307
  */
6199
6308
  async revoke(keyId) {
6200
- return await this.fetch.post(`/api/v1/client-keys/${keyId}/revoke`, {});
6309
+ return await this.fetch.post(
6310
+ `/api/v1/client-keys/${keyId}/revoke`,
6311
+ {}
6312
+ );
6201
6313
  }
6202
6314
  /**
6203
6315
  * Delete a client key
@@ -6214,7 +6326,9 @@ var ClientKeysManager = class {
6214
6326
  * ```
6215
6327
  */
6216
6328
  async delete(keyId) {
6217
- return await this.fetch.delete(`/api/v1/client-keys/${keyId}`);
6329
+ return await this.fetch.delete(
6330
+ `/api/v1/client-keys/${keyId}`
6331
+ );
6218
6332
  }
6219
6333
  };
6220
6334
  var APIKeysManager = ClientKeysManager;
@@ -6289,7 +6403,10 @@ var WebhooksManager = class {
6289
6403
  * ```
6290
6404
  */
6291
6405
  async update(webhookId, updates) {
6292
- return await this.fetch.patch(`/api/v1/webhooks/${webhookId}`, updates);
6406
+ return await this.fetch.patch(
6407
+ `/api/v1/webhooks/${webhookId}`,
6408
+ updates
6409
+ );
6293
6410
  }
6294
6411
  /**
6295
6412
  * Delete a webhook
@@ -6304,7 +6421,9 @@ var WebhooksManager = class {
6304
6421
  * ```
6305
6422
  */
6306
6423
  async delete(webhookId) {
6307
- return await this.fetch.delete(`/api/v1/webhooks/${webhookId}`);
6424
+ return await this.fetch.delete(
6425
+ `/api/v1/webhooks/${webhookId}`
6426
+ );
6308
6427
  }
6309
6428
  /**
6310
6429
  * Test a webhook by sending a test payload
@@ -6324,7 +6443,10 @@ var WebhooksManager = class {
6324
6443
  * ```
6325
6444
  */
6326
6445
  async test(webhookId) {
6327
- return await this.fetch.post(`/api/v1/webhooks/${webhookId}/test`, {});
6446
+ return await this.fetch.post(
6447
+ `/api/v1/webhooks/${webhookId}/test`,
6448
+ {}
6449
+ );
6328
6450
  }
6329
6451
  /**
6330
6452
  * List webhook delivery history
@@ -6371,7 +6493,10 @@ var InvitationsManager = class {
6371
6493
  * ```
6372
6494
  */
6373
6495
  async create(request) {
6374
- return await this.fetch.post("/api/v1/admin/invitations", request);
6496
+ return await this.fetch.post(
6497
+ "/api/v1/admin/invitations",
6498
+ request
6499
+ );
6375
6500
  }
6376
6501
  /**
6377
6502
  * List all invitations (admin only)
@@ -6424,7 +6549,9 @@ var InvitationsManager = class {
6424
6549
  * ```
6425
6550
  */
6426
6551
  async validate(token) {
6427
- return await this.fetch.get(`/api/v1/invitations/${token}/validate`);
6552
+ return await this.fetch.get(
6553
+ `/api/v1/invitations/${token}/validate`
6554
+ );
6428
6555
  }
6429
6556
  /**
6430
6557
  * Accept an invitation and create a new user (public endpoint)
@@ -6446,7 +6573,10 @@ var InvitationsManager = class {
6446
6573
  * ```
6447
6574
  */
6448
6575
  async accept(token, request) {
6449
- return await this.fetch.post(`/api/v1/invitations/${token}/accept`, request);
6576
+ return await this.fetch.post(
6577
+ `/api/v1/invitations/${token}/accept`,
6578
+ request
6579
+ );
6450
6580
  }
6451
6581
  /**
6452
6582
  * Revoke an invitation (admin only)
@@ -6461,7 +6591,9 @@ var InvitationsManager = class {
6461
6591
  * ```
6462
6592
  */
6463
6593
  async revoke(token) {
6464
- return await this.fetch.delete(`/api/v1/admin/invitations/${token}`);
6594
+ return await this.fetch.delete(
6595
+ `/api/v1/admin/invitations/${token}`
6596
+ );
6465
6597
  }
6466
6598
  };
6467
6599
  var FluxbaseManagement = class {
@@ -9782,6 +9914,271 @@ var FluxbaseAdminRealtime = class {
9782
9914
  }
9783
9915
  };
9784
9916
 
9917
+ // src/admin-service-keys.ts
9918
+ var ServiceKeysManager = class {
9919
+ constructor(fetch2) {
9920
+ this.fetch = fetch2;
9921
+ }
9922
+ /**
9923
+ * List all service keys
9924
+ *
9925
+ * @returns List of service keys
9926
+ *
9927
+ * @example
9928
+ * ```typescript
9929
+ * const { data, error } = await client.admin.serviceKeys.list()
9930
+ * ```
9931
+ */
9932
+ async list() {
9933
+ try {
9934
+ const data = await this.fetch.get("/service-keys");
9935
+ return { data, error: null };
9936
+ } catch (error) {
9937
+ return { data: null, error };
9938
+ }
9939
+ }
9940
+ /**
9941
+ * Get a service key by ID
9942
+ *
9943
+ * @param id - Service key ID
9944
+ * @returns Service key details
9945
+ *
9946
+ * @example
9947
+ * ```typescript
9948
+ * const { data, error } = await client.admin.serviceKeys.get('key-id')
9949
+ * ```
9950
+ */
9951
+ async get(id) {
9952
+ try {
9953
+ const data = await this.fetch.get(`/service-keys/${id}`);
9954
+ return { data, error: null };
9955
+ } catch (error) {
9956
+ return { data: null, error };
9957
+ }
9958
+ }
9959
+ /**
9960
+ * Create a new service key
9961
+ *
9962
+ * The full key value is only returned once - store it securely!
9963
+ *
9964
+ * @param request - Key creation options
9965
+ * @returns Created key with full key value
9966
+ *
9967
+ * @example
9968
+ * ```typescript
9969
+ * const { data, error } = await client.admin.serviceKeys.create({
9970
+ * name: 'Production API Key',
9971
+ * key_type: 'service',
9972
+ * scopes: ['*'],
9973
+ * rate_limit_per_minute: 1000
9974
+ * })
9975
+ *
9976
+ * if (data) {
9977
+ * // Store data.key securely - it won't be shown again!
9978
+ * console.log('Key created:', data.key)
9979
+ * }
9980
+ * ```
9981
+ */
9982
+ async create(request) {
9983
+ try {
9984
+ const data = await this.fetch.post(
9985
+ "/service-keys",
9986
+ request
9987
+ );
9988
+ return { data, error: null };
9989
+ } catch (error) {
9990
+ return { data: null, error };
9991
+ }
9992
+ }
9993
+ /**
9994
+ * Update a service key
9995
+ *
9996
+ * @param id - Service key ID
9997
+ * @param request - Update options
9998
+ * @returns Updated key
9999
+ *
10000
+ * @example
10001
+ * ```typescript
10002
+ * const { data, error } = await client.admin.serviceKeys.update('key-id', {
10003
+ * name: 'New Name',
10004
+ * rate_limit_per_minute: 2000
10005
+ * })
10006
+ * ```
10007
+ */
10008
+ async update(id, request) {
10009
+ try {
10010
+ const data = await this.fetch.put(
10011
+ `/service-keys/${id}`,
10012
+ request
10013
+ );
10014
+ return { data, error: null };
10015
+ } catch (error) {
10016
+ return { data: null, error };
10017
+ }
10018
+ }
10019
+ /**
10020
+ * Delete a service key permanently
10021
+ *
10022
+ * @param id - Service key ID
10023
+ * @returns Success or error
10024
+ *
10025
+ * @example
10026
+ * ```typescript
10027
+ * const { error } = await client.admin.serviceKeys.delete('key-id')
10028
+ * ```
10029
+ */
10030
+ async delete(id) {
10031
+ try {
10032
+ await this.fetch.delete(`/service-keys/${id}`);
10033
+ return { error: null };
10034
+ } catch (error) {
10035
+ return { error };
10036
+ }
10037
+ }
10038
+ /**
10039
+ * Disable a service key (temporarily)
10040
+ *
10041
+ * @param id - Service key ID
10042
+ * @returns Success or error
10043
+ *
10044
+ * @example
10045
+ * ```typescript
10046
+ * const { error } = await client.admin.serviceKeys.disable('key-id')
10047
+ * ```
10048
+ */
10049
+ async disable(id) {
10050
+ try {
10051
+ await this.fetch.post(`/service-keys/${id}/disable`, {});
10052
+ return { error: null };
10053
+ } catch (error) {
10054
+ return { error };
10055
+ }
10056
+ }
10057
+ /**
10058
+ * Enable a disabled service key
10059
+ *
10060
+ * @param id - Service key ID
10061
+ * @returns Success or error
10062
+ *
10063
+ * @example
10064
+ * ```typescript
10065
+ * const { error } = await client.admin.serviceKeys.enable('key-id')
10066
+ * ```
10067
+ */
10068
+ async enable(id) {
10069
+ try {
10070
+ await this.fetch.post(`/service-keys/${id}/enable`, {});
10071
+ return { error: null };
10072
+ } catch (error) {
10073
+ return { error };
10074
+ }
10075
+ }
10076
+ /**
10077
+ * Revoke a service key permanently (emergency)
10078
+ *
10079
+ * Use for immediate revocation when a key is compromised.
10080
+ *
10081
+ * @param id - Service key ID
10082
+ * @param request - Revocation options
10083
+ * @returns Success or error
10084
+ *
10085
+ * @example
10086
+ * ```typescript
10087
+ * const { error } = await client.admin.serviceKeys.revoke('key-id', {
10088
+ * reason: 'Key was compromised'
10089
+ * })
10090
+ * ```
10091
+ */
10092
+ async revoke(id, request) {
10093
+ try {
10094
+ const body = request?.reason ? new URLSearchParams({ reason: request.reason }) : {};
10095
+ await this.fetch.post(`/service-keys/${id}/revoke`, body);
10096
+ return { error: null };
10097
+ } catch (error) {
10098
+ return { error };
10099
+ }
10100
+ }
10101
+ /**
10102
+ * Deprecate a service key (graceful rotation)
10103
+ *
10104
+ * Marks the key for removal but keeps it active during grace period.
10105
+ *
10106
+ * @param id - Service key ID
10107
+ * @param request - Deprecation options
10108
+ * @returns Deprecation details
10109
+ *
10110
+ * @example
10111
+ * ```typescript
10112
+ * const { data, error } = await client.admin.serviceKeys.deprecate('key-id', {
10113
+ * reason: 'Rotating to new key',
10114
+ * grace_period_hours: 48
10115
+ * })
10116
+ * ```
10117
+ */
10118
+ async deprecate(id, request) {
10119
+ try {
10120
+ const params = new URLSearchParams();
10121
+ if (request?.grace_period_hours) {
10122
+ params.set("grace_period_hours", String(request.grace_period_hours));
10123
+ }
10124
+ const body = request?.grace_period_hours ? Object.fromEntries(params) : {};
10125
+ const data = await this.fetch.post(`/service-keys/${id}/deprecate`, body);
10126
+ return { data, error: null };
10127
+ } catch (error) {
10128
+ return { data: null, error };
10129
+ }
10130
+ }
10131
+ /**
10132
+ * Rotate a service key (create replacement)
10133
+ *
10134
+ * Creates a new key with the same settings and deprecates the old one.
10135
+ * The new key is returned with its full value.
10136
+ *
10137
+ * @param id - Service key ID to rotate
10138
+ * @returns New key with full key value
10139
+ *
10140
+ * @example
10141
+ * ```typescript
10142
+ * const { data, error } = await client.admin.serviceKeys.rotate('old-key-id')
10143
+ *
10144
+ * if (data) {
10145
+ * console.log('New key:', data.key)
10146
+ * console.log('Old key deprecated at:', data.deprecated_at)
10147
+ * }
10148
+ * ```
10149
+ */
10150
+ async rotate(id) {
10151
+ try {
10152
+ const data = await this.fetch.post(
10153
+ `/service-keys/${id}/rotate`,
10154
+ {}
10155
+ );
10156
+ return { data, error: null };
10157
+ } catch (error) {
10158
+ return { data: null, error };
10159
+ }
10160
+ }
10161
+ /**
10162
+ * Get revocation history for a service key
10163
+ *
10164
+ * @param id - Service key ID
10165
+ * @returns Revocation history
10166
+ *
10167
+ * @example
10168
+ * ```typescript
10169
+ * const { data, error } = await client.admin.serviceKeys.getRevocationHistory('key-id')
10170
+ * ```
10171
+ */
10172
+ async getRevocationHistory(id) {
10173
+ try {
10174
+ const data = await this.fetch.get(`/service-keys/${id}/revocations`);
10175
+ return { data, error: null };
10176
+ } catch (error) {
10177
+ return { data: null, error };
10178
+ }
10179
+ }
10180
+ };
10181
+
9785
10182
  // src/admin.ts
9786
10183
  var FluxbaseAdmin = class {
9787
10184
  constructor(fetch2) {
@@ -9800,6 +10197,7 @@ var FluxbaseAdmin = class {
9800
10197
  this.rpc = new FluxbaseAdminRPC(fetch2);
9801
10198
  this.storage = new FluxbaseAdminStorage(fetch2);
9802
10199
  this.realtime = new FluxbaseAdminRealtime(fetch2);
10200
+ this.serviceKeys = new ServiceKeysManager(fetch2);
9803
10201
  }
9804
10202
  /**
9805
10203
  * Set admin authentication token
@@ -11624,6 +12022,228 @@ var FluxbaseBranching = class {
11624
12022
  }
11625
12023
  };
11626
12024
 
12025
+ // src/tenant.ts
12026
+ var FluxbaseTenant = class {
12027
+ constructor(fetch2) {
12028
+ this.fetch = fetch2;
12029
+ }
12030
+ /**
12031
+ * List all tenants (instance admin only)
12032
+ *
12033
+ * @returns Promise with tenants list or error
12034
+ *
12035
+ * @example
12036
+ * ```typescript
12037
+ * const { data, error } = await client.tenant.list()
12038
+ * ```
12039
+ */
12040
+ async list() {
12041
+ try {
12042
+ const data = await this.fetch.get("/tenants");
12043
+ return { data, error: null };
12044
+ } catch (error) {
12045
+ return { data: null, error };
12046
+ }
12047
+ }
12048
+ /**
12049
+ * List tenants the current user has access to
12050
+ *
12051
+ * @returns Promise with tenants and user's role in each
12052
+ *
12053
+ * @example
12054
+ * ```typescript
12055
+ * const { data, error } = await client.tenant.listMine()
12056
+ * // data: [{ id: '...', slug: 'acme', name: 'Acme', my_role: 'tenant_admin', status: 'active' }]
12057
+ * ```
12058
+ */
12059
+ async listMine() {
12060
+ try {
12061
+ const data = await this.fetch.get("/tenants/mine");
12062
+ return { data, error: null };
12063
+ } catch (error) {
12064
+ return { data: null, error };
12065
+ }
12066
+ }
12067
+ /**
12068
+ * Get a tenant by ID
12069
+ *
12070
+ * @param id - Tenant ID
12071
+ * @returns Promise with tenant details or error
12072
+ *
12073
+ * @example
12074
+ * ```typescript
12075
+ * const { data, error } = await client.tenant.get('tenant-id')
12076
+ * ```
12077
+ */
12078
+ async get(id) {
12079
+ try {
12080
+ const data = await this.fetch.get(`/tenants/${id}`);
12081
+ return { data, error: null };
12082
+ } catch (error) {
12083
+ return { data: null, error };
12084
+ }
12085
+ }
12086
+ /**
12087
+ * Create a new tenant (instance admin only)
12088
+ *
12089
+ * This creates a new isolated database for the tenant.
12090
+ *
12091
+ * @param options - Tenant creation options
12092
+ * @returns Promise with created tenant or error
12093
+ *
12094
+ * @example
12095
+ * ```typescript
12096
+ * const { data, error } = await client.tenant.create({
12097
+ * slug: 'acme-corp',
12098
+ * name: 'Acme Corporation',
12099
+ * metadata: { plan: 'enterprise' }
12100
+ * })
12101
+ * ```
12102
+ */
12103
+ async create(options) {
12104
+ try {
12105
+ const data = await this.fetch.post("/tenants", options);
12106
+ return { data, error: null };
12107
+ } catch (error) {
12108
+ return { data: null, error };
12109
+ }
12110
+ }
12111
+ /**
12112
+ * Update a tenant (tenant admin only)
12113
+ *
12114
+ * @param id - Tenant ID
12115
+ * @param options - Update options
12116
+ * @returns Promise with updated tenant or error
12117
+ *
12118
+ * @example
12119
+ * ```typescript
12120
+ * const { data, error } = await client.tenant.update('tenant-id', {
12121
+ * name: 'New Name'
12122
+ * })
12123
+ * ```
12124
+ */
12125
+ async update(id, options) {
12126
+ try {
12127
+ const data = await this.fetch.patch(`/tenants/${id}`, options);
12128
+ return { data, error: null };
12129
+ } catch (error) {
12130
+ return { data: null, error };
12131
+ }
12132
+ }
12133
+ /**
12134
+ * Delete a tenant (instance admin only)
12135
+ *
12136
+ * This permanently deletes the tenant's database and all its data.
12137
+ * Cannot delete the default tenant.
12138
+ *
12139
+ * @param id - Tenant ID
12140
+ * @returns Promise that resolves when deleted
12141
+ *
12142
+ * @example
12143
+ * ```typescript
12144
+ * const { error } = await client.tenant.delete('tenant-id')
12145
+ * ```
12146
+ */
12147
+ async delete(id) {
12148
+ try {
12149
+ await this.fetch.delete(`/tenants/${id}`);
12150
+ return { data: void 0, error: null };
12151
+ } catch (error) {
12152
+ return { data: null, error };
12153
+ }
12154
+ }
12155
+ /**
12156
+ * Migrate a tenant database to the latest schema (instance admin only)
12157
+ *
12158
+ * @param id - Tenant ID
12159
+ * @returns Promise with migration status or error
12160
+ *
12161
+ * @example
12162
+ * ```typescript
12163
+ * const { data, error } = await client.tenant.migrate('tenant-id')
12164
+ * // data: { status: 'migrated' }
12165
+ * ```
12166
+ */
12167
+ async migrate(id) {
12168
+ try {
12169
+ const data = await this.fetch.post(
12170
+ `/tenants/${id}/migrate`,
12171
+ {}
12172
+ );
12173
+ return { data, error: null };
12174
+ } catch (error) {
12175
+ return { data: null, error };
12176
+ }
12177
+ }
12178
+ /**
12179
+ * List admins of a tenant
12180
+ *
12181
+ * @param tenantId - Tenant ID
12182
+ * @returns Promise with admin list or error
12183
+ *
12184
+ * @example
12185
+ * ```typescript
12186
+ * const { data, error } = await client.tenant.listAdmins('tenant-id')
12187
+ * // data: [{ id: '...', tenant_id: '...', user_id: '...', email: 'admin@example.com' }]
12188
+ * ```
12189
+ */
12190
+ async listAdmins(tenantId) {
12191
+ try {
12192
+ const data = await this.fetch.get(
12193
+ `/tenants/${tenantId}/admins`
12194
+ );
12195
+ return { data, error: null };
12196
+ } catch (error) {
12197
+ return { data: null, error };
12198
+ }
12199
+ }
12200
+ /**
12201
+ * Assign an admin to a tenant (tenant admin only)
12202
+ *
12203
+ * @param tenantId - Tenant ID
12204
+ * @param options - Admin assignment options
12205
+ * @returns Promise with created assignment or error
12206
+ *
12207
+ * @example
12208
+ * ```typescript
12209
+ * const { data, error } = await client.tenant.assignAdmin('tenant-id', {
12210
+ * user_id: 'user-id'
12211
+ * })
12212
+ * ```
12213
+ */
12214
+ async assignAdmin(tenantId, options) {
12215
+ try {
12216
+ const data = await this.fetch.post(
12217
+ `/tenants/${tenantId}/admins`,
12218
+ options
12219
+ );
12220
+ return { data, error: null };
12221
+ } catch (error) {
12222
+ return { data: null, error };
12223
+ }
12224
+ }
12225
+ /**
12226
+ * Remove an admin from a tenant (tenant admin only)
12227
+ *
12228
+ * @param tenantId - Tenant ID
12229
+ * @param userId - User ID
12230
+ * @returns Promise that resolves when removed
12231
+ *
12232
+ * @example
12233
+ * ```typescript
12234
+ * const { error } = await client.tenant.removeAdmin('tenant-id', 'user-id')
12235
+ * ```
12236
+ */
12237
+ async removeAdmin(tenantId, userId) {
12238
+ try {
12239
+ await this.fetch.delete(`/tenants/${tenantId}/admins/${userId}`);
12240
+ return { data: void 0, error: null };
12241
+ } catch (error) {
12242
+ return { data: null, error };
12243
+ }
12244
+ }
12245
+ };
12246
+
11627
12247
  // src/query-builder.ts
11628
12248
  var URL_LENGTH_THRESHOLD = 4096;
11629
12249
  var QueryBuilder = class {
@@ -12915,7 +13535,7 @@ var SchemaQueryBuilder = class {
12915
13535
  };
12916
13536
 
12917
13537
  // src/client.ts
12918
- var FluxbaseClient = class {
13538
+ var FluxbaseClient = class _FluxbaseClient {
12919
13539
  /**
12920
13540
  * Create a new Fluxbase client instance
12921
13541
  *
@@ -12935,6 +13555,7 @@ var FluxbaseClient = class {
12935
13555
  constructor(fluxbaseUrl, fluxbaseKey, options) {
12936
13556
  this.fluxbaseUrl = fluxbaseUrl;
12937
13557
  this.fluxbaseKey = fluxbaseKey;
13558
+ this.options = options;
12938
13559
  const headers = {
12939
13560
  apikey: fluxbaseKey,
12940
13561
  Authorization: `Bearer ${fluxbaseKey}`,
@@ -12987,6 +13608,7 @@ var FluxbaseClient = class {
12987
13608
  waitForCompletion: rpcInstance.waitForCompletion.bind(rpcInstance)
12988
13609
  });
12989
13610
  this.rpc = rpcCallable;
13611
+ this.tenant = new FluxbaseTenant(this.fetch);
12990
13612
  this.setupAuthSync();
12991
13613
  }
12992
13614
  /**
@@ -13092,6 +13714,96 @@ var FluxbaseClient = class {
13092
13714
  this.fetch.setAuthToken(token);
13093
13715
  this.realtime.setAuth(token);
13094
13716
  }
13717
+ /**
13718
+ * Get the current tenant ID
13719
+ *
13720
+ * Returns the tenant ID from X-FB-Tenant header or JWT claim, or default tenant.
13721
+ *
13722
+ * @returns The current tenant ID, or undefined if not set
13723
+ *
13724
+ * @category Multi-Tenancy
13725
+ */
13726
+ getTenantId() {
13727
+ return this._tenantId;
13728
+ }
13729
+ /**
13730
+ * Set the tenant context for all subsequent requests
13731
+ *
13732
+ * This adds the X-FB-Tenant header to all HTTP requests and updates
13733
+ * the realtime connection to filter by tenant.
13734
+ *
13735
+ * @param tenantId - The tenant ID to use for scoping
13736
+ *
13737
+ * @example
13738
+ * ```typescript
13739
+ * // Switch to a specific tenant
13740
+ * client.setTenant('tenant-uuid-here')
13741
+ *
13742
+ * // All subsequent requests will be scoped to this tenant
13743
+ * const { data } = await client.from('users').select('*').execute()
13744
+ * ```
13745
+ *
13746
+ * @category Multi-Tenancy
13747
+ */
13748
+ setTenant(tenantId) {
13749
+ this._tenantId = tenantId;
13750
+ if (tenantId) {
13751
+ this.fetch.setHeader("X-FB-Tenant", tenantId);
13752
+ } else {
13753
+ this.fetch.removeHeader("X-FB-Tenant");
13754
+ }
13755
+ }
13756
+ /**
13757
+ * Register a callback that is called before every request.
13758
+ * The callback receives the headers object and can modify it in place.
13759
+ * This is useful for dynamically injecting headers at request time
13760
+ * (e.g., reading tenant context from an external store).
13761
+ *
13762
+ * The callback runs after static headers are merged, so it can override them.
13763
+ *
13764
+ * @param callback - A function that receives the headers object, or null to remove
13765
+ *
13766
+ * @category Advanced
13767
+ */
13768
+ setBeforeRequestCallback(callback) {
13769
+ this.fetch.setBeforeRequestCallback(callback);
13770
+ }
13771
+ /**
13772
+ * Create a new client scoped to a specific tenant
13773
+ *
13774
+ * This returns a new client instance with the tenant context set.
13775
+ * The original client is not modified.
13776
+ *
13777
+ * @param tenantId - The tenant ID to scope to
13778
+ * @returns A new FluxbaseClient instance scoped to the tenant
13779
+ *
13780
+ * @example
13781
+ * ```typescript
13782
+ * // Create a tenant-scoped client
13783
+ * const tenantClient = client.forTenant('tenant-uuid')
13784
+ *
13785
+ * // Use the scoped client for tenant-specific operations
13786
+ * const { data } = await tenantClient.from('users').select('*').execute()
13787
+ * ```
13788
+ *
13789
+ * @category Multi-Tenancy
13790
+ */
13791
+ forTenant(tenantId) {
13792
+ const options = {
13793
+ ...this.options,
13794
+ headers: {
13795
+ ...this.options?.headers,
13796
+ "X-FB-Tenant": tenantId
13797
+ }
13798
+ };
13799
+ const scopedClient = new _FluxbaseClient(
13800
+ this.fluxbaseUrl,
13801
+ this.fluxbaseKey,
13802
+ options
13803
+ );
13804
+ scopedClient._tenantId = tenantId;
13805
+ return scopedClient;
13806
+ }
13095
13807
  /**
13096
13808
  * Create or get a realtime channel (Supabase-compatible)
13097
13809
  *
@@ -13258,6 +13970,7 @@ exports.FluxbaseRPC = FluxbaseRPC;
13258
13970
  exports.FluxbaseRealtime = FluxbaseRealtime;
13259
13971
  exports.FluxbaseSettings = FluxbaseSettings;
13260
13972
  exports.FluxbaseStorage = FluxbaseStorage;
13973
+ exports.FluxbaseTenant = FluxbaseTenant;
13261
13974
  exports.FluxbaseVector = FluxbaseVector;
13262
13975
  exports.ImpersonationManager = ImpersonationManager;
13263
13976
  exports.InvitationsManager = InvitationsManager;
@@ -13266,6 +13979,7 @@ exports.QueryBuilder = QueryBuilder;
13266
13979
  exports.RealtimeChannel = RealtimeChannel;
13267
13980
  exports.SchemaQueryBuilder = SchemaQueryBuilder;
13268
13981
  exports.SecretsManager = SecretsManager;
13982
+ exports.ServiceKeysManager = ServiceKeysManager;
13269
13983
  exports.SettingsClient = SettingsClient;
13270
13984
  exports.StorageBucket = StorageBucket;
13271
13985
  exports.SystemSettingsManager = SystemSettingsManager;