@fluxbase/sdk 0.0.1-rc.106 → 0.0.1-rc.108

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
@@ -476,7 +476,14 @@ var FluxbaseAuth = class {
476
476
  */
477
477
  async signIn(credentials) {
478
478
  return wrapAsync(async () => {
479
- const response = await this.fetch.post("/api/v1/auth/signin", credentials);
479
+ const requestBody = {
480
+ email: credentials.email,
481
+ password: credentials.password
482
+ };
483
+ if (credentials.captchaToken) {
484
+ requestBody.captcha_token = credentials.captchaToken;
485
+ }
486
+ const response = await this.fetch.post("/api/v1/auth/signin", requestBody);
480
487
  if ("requires_2fa" in response && response.requires_2fa) {
481
488
  return response;
482
489
  }
@@ -511,6 +518,9 @@ var FluxbaseAuth = class {
511
518
  if (credentials.options?.data) {
512
519
  requestBody.user_metadata = credentials.options.data;
513
520
  }
521
+ if (credentials.captchaToken) {
522
+ requestBody.captcha_token = credentials.captchaToken;
523
+ }
514
524
  const response = await this.fetch.post(
515
525
  "/api/v1/auth/signup",
516
526
  requestBody
@@ -526,6 +536,16 @@ var FluxbaseAuth = class {
526
536
  return { user: response.user, session: null };
527
537
  });
528
538
  }
539
+ /**
540
+ * Get CAPTCHA configuration from the server
541
+ * Use this to determine which CAPTCHA provider to load and configure
542
+ * @returns Promise with CAPTCHA configuration (provider, site key, enabled endpoints)
543
+ */
544
+ async getCaptchaConfig() {
545
+ return wrapAsync(async () => {
546
+ return await this.fetch.get("/api/v1/auth/captcha/config");
547
+ });
548
+ }
529
549
  /**
530
550
  * Sign out the current user
531
551
  */
@@ -737,22 +757,29 @@ var FluxbaseAuth = class {
737
757
  * Send password reset email (Supabase-compatible)
738
758
  * Sends a password reset link to the provided email address
739
759
  * @param email - Email address to send reset link to
760
+ * @param options - Optional configuration including CAPTCHA token
740
761
  * @returns Promise with OTP-style response
741
762
  */
742
- async sendPasswordReset(email) {
763
+ async sendPasswordReset(email, options) {
743
764
  return wrapAsync(async () => {
744
- await this.fetch.post("/api/v1/auth/password/reset", { email });
765
+ const requestBody = { email };
766
+ if (options?.captchaToken) {
767
+ requestBody.captcha_token = options.captchaToken;
768
+ }
769
+ await this.fetch.post("/api/v1/auth/password/reset", requestBody);
745
770
  return { user: null, session: null };
746
771
  });
747
772
  }
748
773
  /**
749
774
  * Supabase-compatible alias for sendPasswordReset()
750
775
  * @param email - Email address to send reset link to
751
- * @param _options - Optional redirect configuration (currently not used)
776
+ * @param options - Optional redirect and CAPTCHA configuration
752
777
  * @returns Promise with OTP-style response
753
778
  */
754
- async resetPasswordForEmail(email, _options) {
755
- return this.sendPasswordReset(email);
779
+ async resetPasswordForEmail(email, options) {
780
+ return this.sendPasswordReset(email, {
781
+ captchaToken: options?.captchaToken
782
+ });
756
783
  }
757
784
  /**
758
785
  * Verify password reset token
@@ -801,10 +828,14 @@ var FluxbaseAuth = class {
801
828
  */
802
829
  async sendMagicLink(email, options) {
803
830
  return wrapAsync(async () => {
804
- await this.fetch.post("/api/v1/auth/magiclink", {
831
+ const requestBody = {
805
832
  email,
806
833
  redirect_to: options?.redirect_to
807
- });
834
+ };
835
+ if (options?.captchaToken) {
836
+ requestBody.captcha_token = options.captchaToken;
837
+ }
838
+ await this.fetch.post("/api/v1/auth/magiclink", requestBody);
808
839
  return { user: null, session: null };
809
840
  });
810
841
  }
@@ -1047,6 +1078,139 @@ var FluxbaseAuth = class {
1047
1078
  return { user: session.user, session };
1048
1079
  });
1049
1080
  }
1081
+ // ==========================================================================
1082
+ // SAML SSO Methods
1083
+ // ==========================================================================
1084
+ /**
1085
+ * Get list of available SAML SSO providers
1086
+ * @returns Promise with list of configured SAML providers
1087
+ *
1088
+ * @example
1089
+ * ```typescript
1090
+ * const { data, error } = await client.auth.getSAMLProviders()
1091
+ * if (!error) {
1092
+ * console.log('Available providers:', data.providers)
1093
+ * }
1094
+ * ```
1095
+ */
1096
+ async getSAMLProviders() {
1097
+ return wrapAsync(async () => {
1098
+ return await this.fetch.get(
1099
+ "/api/v1/auth/saml/providers"
1100
+ );
1101
+ });
1102
+ }
1103
+ /**
1104
+ * Get SAML login URL for a specific provider
1105
+ * Use this to redirect the user to the IdP for authentication
1106
+ * @param provider - SAML provider name/ID
1107
+ * @param options - Optional login configuration
1108
+ * @returns Promise with SAML login URL
1109
+ *
1110
+ * @example
1111
+ * ```typescript
1112
+ * const { data, error } = await client.auth.getSAMLLoginUrl('okta')
1113
+ * if (!error) {
1114
+ * window.location.href = data.url
1115
+ * }
1116
+ * ```
1117
+ */
1118
+ async getSAMLLoginUrl(provider, options) {
1119
+ return wrapAsync(async () => {
1120
+ const params = new URLSearchParams();
1121
+ if (options?.redirectUrl) {
1122
+ params.append("redirect_url", options.redirectUrl);
1123
+ }
1124
+ const queryString = params.toString();
1125
+ const url = queryString ? `/api/v1/auth/saml/login/${provider}?${queryString}` : `/api/v1/auth/saml/login/${provider}`;
1126
+ const response = await this.fetch.get(url);
1127
+ return response;
1128
+ });
1129
+ }
1130
+ /**
1131
+ * Initiate SAML login and redirect to IdP
1132
+ * This is a convenience method that redirects the user to the SAML IdP
1133
+ * @param provider - SAML provider name/ID
1134
+ * @param options - Optional login configuration
1135
+ * @returns Promise with provider and URL (browser will redirect)
1136
+ *
1137
+ * @example
1138
+ * ```typescript
1139
+ * // In browser, this will redirect to the SAML IdP
1140
+ * await client.auth.signInWithSAML('okta')
1141
+ * ```
1142
+ */
1143
+ async signInWithSAML(provider, options) {
1144
+ return wrapAsync(async () => {
1145
+ const result = await this.getSAMLLoginUrl(provider, options);
1146
+ if (result.error) {
1147
+ throw result.error;
1148
+ }
1149
+ const url = result.data.url;
1150
+ if (typeof window !== "undefined") {
1151
+ window.location.href = url;
1152
+ } else {
1153
+ throw new Error(
1154
+ "signInWithSAML can only be called in a browser environment"
1155
+ );
1156
+ }
1157
+ return { provider, url };
1158
+ });
1159
+ }
1160
+ /**
1161
+ * Handle SAML callback after IdP authentication
1162
+ * Call this from your SAML callback page to complete authentication
1163
+ * @param samlResponse - Base64-encoded SAML response from the ACS endpoint
1164
+ * @param provider - SAML provider name (optional, extracted from RelayState)
1165
+ * @returns Promise with user and session
1166
+ *
1167
+ * @example
1168
+ * ```typescript
1169
+ * // In your SAML callback page
1170
+ * const urlParams = new URLSearchParams(window.location.search)
1171
+ * const samlResponse = urlParams.get('SAMLResponse')
1172
+ *
1173
+ * if (samlResponse) {
1174
+ * const { data, error } = await client.auth.handleSAMLCallback(samlResponse)
1175
+ * if (!error) {
1176
+ * console.log('Logged in:', data.user)
1177
+ * }
1178
+ * }
1179
+ * ```
1180
+ */
1181
+ async handleSAMLCallback(samlResponse, provider) {
1182
+ return wrapAsync(async () => {
1183
+ const response = await this.fetch.post(
1184
+ "/api/v1/auth/saml/acs",
1185
+ {
1186
+ saml_response: samlResponse,
1187
+ provider
1188
+ }
1189
+ );
1190
+ const session = {
1191
+ ...response,
1192
+ expires_at: Date.now() + response.expires_in * 1e3
1193
+ };
1194
+ this.setSessionInternal(session);
1195
+ return { user: session.user, session };
1196
+ });
1197
+ }
1198
+ /**
1199
+ * Get SAML Service Provider metadata for a specific provider configuration
1200
+ * Use this when configuring your IdP to download the SP metadata XML
1201
+ * @param provider - SAML provider name/ID
1202
+ * @returns Promise with SP metadata URL
1203
+ *
1204
+ * @example
1205
+ * ```typescript
1206
+ * const metadataUrl = client.auth.getSAMLMetadataUrl('okta')
1207
+ * // Share this URL with your IdP administrator
1208
+ * ```
1209
+ */
1210
+ getSAMLMetadataUrl(provider) {
1211
+ const baseUrl = this.fetch["baseUrl"];
1212
+ return `${baseUrl}/api/v1/auth/saml/metadata/${provider}`;
1213
+ }
1050
1214
  /**
1051
1215
  * Internal: Set the session and persist it
1052
1216
  */
@@ -2785,17 +2949,114 @@ var StorageBucket = class {
2785
2949
  const publicUrl = `${this.fetch["baseUrl"]}/api/v1/storage/${this.bucketName}/${path}`;
2786
2950
  return { data: { publicUrl } };
2787
2951
  }
2952
+ /**
2953
+ * Build query string from transform options
2954
+ * @private
2955
+ */
2956
+ buildTransformQuery(transform) {
2957
+ const params = new URLSearchParams();
2958
+ if (transform.width !== void 0 && transform.width > 0) {
2959
+ params.set("w", String(transform.width));
2960
+ }
2961
+ if (transform.height !== void 0 && transform.height > 0) {
2962
+ params.set("h", String(transform.height));
2963
+ }
2964
+ if (transform.format) {
2965
+ params.set("fmt", transform.format);
2966
+ }
2967
+ if (transform.quality !== void 0 && transform.quality > 0) {
2968
+ params.set("q", String(transform.quality));
2969
+ }
2970
+ if (transform.fit) {
2971
+ params.set("fit", transform.fit);
2972
+ }
2973
+ return params.toString();
2974
+ }
2975
+ /**
2976
+ * Get a public URL for a file with image transformations applied
2977
+ * Only works for image files (JPEG, PNG, WebP, GIF, AVIF, etc.)
2978
+ *
2979
+ * @param path - The file path
2980
+ * @param transform - Transformation options (width, height, format, quality, fit)
2981
+ *
2982
+ * @example
2983
+ * ```typescript
2984
+ * // Get a 300x200 WebP thumbnail
2985
+ * const url = storage.from('images').getTransformUrl('photo.jpg', {
2986
+ * width: 300,
2987
+ * height: 200,
2988
+ * format: 'webp',
2989
+ * quality: 85,
2990
+ * fit: 'cover'
2991
+ * });
2992
+ *
2993
+ * // Get a resized image maintaining aspect ratio
2994
+ * const url = storage.from('images').getTransformUrl('photo.jpg', {
2995
+ * width: 800,
2996
+ * format: 'webp'
2997
+ * });
2998
+ * ```
2999
+ */
3000
+ getTransformUrl(path, transform) {
3001
+ const baseUrl = `${this.fetch["baseUrl"]}/api/v1/storage/${this.bucketName}/${path}`;
3002
+ const queryString = this.buildTransformQuery(transform);
3003
+ return queryString ? `${baseUrl}?${queryString}` : baseUrl;
3004
+ }
2788
3005
  /**
2789
3006
  * Create a signed URL for temporary access to a file
3007
+ * Optionally include image transformation parameters
3008
+ *
2790
3009
  * @param path - The file path
2791
- * @param options - Signed URL options
3010
+ * @param options - Signed URL options including expiration and transforms
3011
+ *
3012
+ * @example
3013
+ * ```typescript
3014
+ * // Simple signed URL (1 hour expiry)
3015
+ * const { data, error } = await storage.from('images').createSignedUrl('photo.jpg');
3016
+ *
3017
+ * // Signed URL with custom expiry
3018
+ * const { data, error } = await storage.from('images').createSignedUrl('photo.jpg', {
3019
+ * expiresIn: 7200 // 2 hours
3020
+ * });
3021
+ *
3022
+ * // Signed URL with image transformation
3023
+ * const { data, error } = await storage.from('images').createSignedUrl('photo.jpg', {
3024
+ * expiresIn: 3600,
3025
+ * transform: {
3026
+ * width: 400,
3027
+ * height: 300,
3028
+ * format: 'webp',
3029
+ * quality: 85,
3030
+ * fit: 'cover'
3031
+ * }
3032
+ * });
3033
+ * ```
2792
3034
  */
2793
3035
  async createSignedUrl(path, options) {
2794
3036
  try {
2795
3037
  const expiresIn = options?.expiresIn || 3600;
3038
+ const requestBody = { expires_in: expiresIn };
3039
+ if (options?.transform) {
3040
+ const transform = options.transform;
3041
+ if (transform.width !== void 0 && transform.width > 0) {
3042
+ requestBody.width = transform.width;
3043
+ }
3044
+ if (transform.height !== void 0 && transform.height > 0) {
3045
+ requestBody.height = transform.height;
3046
+ }
3047
+ if (transform.format) {
3048
+ requestBody.format = transform.format;
3049
+ }
3050
+ if (transform.quality !== void 0 && transform.quality > 0) {
3051
+ requestBody.quality = transform.quality;
3052
+ }
3053
+ if (transform.fit) {
3054
+ requestBody.fit = transform.fit;
3055
+ }
3056
+ }
2796
3057
  const data = await this.fetch.post(
2797
3058
  `/api/v1/storage/${this.bucketName}/sign/${path}`,
2798
- { expires_in: expiresIn }
3059
+ requestBody
2799
3060
  );
2800
3061
  return { data: { signedUrl: data.signed_url }, error: null };
2801
3062
  } catch (error) {
@@ -9203,6 +9464,239 @@ var FluxbaseVector = class {
9203
9464
  }
9204
9465
  };
9205
9466
 
9467
+ // src/graphql.ts
9468
+ var FluxbaseGraphQL = class {
9469
+ /**
9470
+ * Create a new GraphQL client
9471
+ * @param fetch - The HTTP client to use for requests
9472
+ */
9473
+ constructor(fetch2) {
9474
+ this.fetch = fetch2;
9475
+ }
9476
+ /**
9477
+ * Execute a GraphQL query
9478
+ *
9479
+ * @typeParam T - The expected response data type
9480
+ * @param query - The GraphQL query string
9481
+ * @param variables - Variables to pass to the query
9482
+ * @param options - Additional request options
9483
+ * @returns Promise resolving to the GraphQL response
9484
+ *
9485
+ * @example
9486
+ * ```typescript
9487
+ * interface UsersQuery {
9488
+ * users: Array<{ id: string; email: string }>
9489
+ * }
9490
+ *
9491
+ * const { data, errors } = await client.graphql.query<UsersQuery>(`
9492
+ * query {
9493
+ * users { id email }
9494
+ * }
9495
+ * `)
9496
+ *
9497
+ * if (data) {
9498
+ * console.log(data.users)
9499
+ * }
9500
+ * ```
9501
+ */
9502
+ async query(query, variables, options) {
9503
+ return this.execute(query, variables, void 0, options);
9504
+ }
9505
+ /**
9506
+ * Execute a GraphQL mutation
9507
+ *
9508
+ * @typeParam T - The expected response data type
9509
+ * @param mutation - The GraphQL mutation string
9510
+ * @param variables - Variables to pass to the mutation
9511
+ * @param options - Additional request options
9512
+ * @returns Promise resolving to the GraphQL response
9513
+ *
9514
+ * @example
9515
+ * ```typescript
9516
+ * interface CreateUserMutation {
9517
+ * insertUser: { id: string; email: string }
9518
+ * }
9519
+ *
9520
+ * const { data, errors } = await client.graphql.mutation<CreateUserMutation>(`
9521
+ * mutation CreateUser($data: UserInput!) {
9522
+ * insertUser(data: $data) {
9523
+ * id
9524
+ * email
9525
+ * }
9526
+ * }
9527
+ * `, { data: { email: 'user@example.com' } })
9528
+ * ```
9529
+ */
9530
+ async mutation(mutation, variables, options) {
9531
+ return this.execute(mutation, variables, void 0, options);
9532
+ }
9533
+ /**
9534
+ * Execute a GraphQL request with an operation name
9535
+ *
9536
+ * Use this when your query document contains multiple operations
9537
+ * and you need to specify which one to execute.
9538
+ *
9539
+ * @typeParam T - The expected response data type
9540
+ * @param query - The GraphQL document containing one or more operations
9541
+ * @param variables - Variables to pass to the operation
9542
+ * @param operationName - The name of the operation to execute
9543
+ * @param options - Additional request options
9544
+ * @returns Promise resolving to the GraphQL response
9545
+ *
9546
+ * @example
9547
+ * ```typescript
9548
+ * const { data } = await client.graphql.execute(`
9549
+ * query GetUser($id: ID!) {
9550
+ * user(id: $id) { id email }
9551
+ * }
9552
+ * query ListUsers {
9553
+ * users { id email }
9554
+ * }
9555
+ * `, { id: '123' }, 'GetUser')
9556
+ * ```
9557
+ */
9558
+ async execute(query, variables, operationName, options) {
9559
+ const body = { query };
9560
+ if (variables && Object.keys(variables).length > 0) {
9561
+ body.variables = variables;
9562
+ }
9563
+ if (operationName) {
9564
+ body.operationName = operationName;
9565
+ }
9566
+ const headers = {
9567
+ "Content-Type": "application/json",
9568
+ ...options?.headers
9569
+ };
9570
+ try {
9571
+ const response = await this.fetch.post(
9572
+ "/api/v1/graphql",
9573
+ body,
9574
+ { headers }
9575
+ );
9576
+ return response || { errors: [{ message: "No response received" }] };
9577
+ } catch (err) {
9578
+ const message = err instanceof Error ? err.message : "GraphQL request failed";
9579
+ return {
9580
+ errors: [{ message }]
9581
+ };
9582
+ }
9583
+ }
9584
+ /**
9585
+ * Fetch the GraphQL schema via introspection
9586
+ *
9587
+ * Returns the full schema information including types, fields, and directives.
9588
+ * Useful for tooling and documentation.
9589
+ *
9590
+ * @param options - Additional request options
9591
+ * @returns Promise resolving to the introspection result
9592
+ *
9593
+ * @example
9594
+ * ```typescript
9595
+ * const { data, errors } = await client.graphql.introspect()
9596
+ *
9597
+ * if (data) {
9598
+ * console.log('Types:', data.__schema.types.length)
9599
+ * }
9600
+ * ```
9601
+ */
9602
+ async introspect(options) {
9603
+ return this.query(INTROSPECTION_QUERY, void 0, options);
9604
+ }
9605
+ };
9606
+ var INTROSPECTION_QUERY = `
9607
+ query IntrospectionQuery {
9608
+ __schema {
9609
+ queryType { name }
9610
+ mutationType { name }
9611
+ subscriptionType { name }
9612
+ types {
9613
+ ...FullType
9614
+ }
9615
+ directives {
9616
+ name
9617
+ description
9618
+ locations
9619
+ args {
9620
+ ...InputValue
9621
+ }
9622
+ }
9623
+ }
9624
+ }
9625
+
9626
+ fragment FullType on __Type {
9627
+ kind
9628
+ name
9629
+ description
9630
+ fields(includeDeprecated: true) {
9631
+ name
9632
+ description
9633
+ args {
9634
+ ...InputValue
9635
+ }
9636
+ type {
9637
+ ...TypeRef
9638
+ }
9639
+ isDeprecated
9640
+ deprecationReason
9641
+ }
9642
+ inputFields {
9643
+ ...InputValue
9644
+ }
9645
+ interfaces {
9646
+ ...TypeRef
9647
+ }
9648
+ enumValues(includeDeprecated: true) {
9649
+ name
9650
+ description
9651
+ isDeprecated
9652
+ deprecationReason
9653
+ }
9654
+ possibleTypes {
9655
+ ...TypeRef
9656
+ }
9657
+ }
9658
+
9659
+ fragment InputValue on __InputValue {
9660
+ name
9661
+ description
9662
+ type { ...TypeRef }
9663
+ defaultValue
9664
+ }
9665
+
9666
+ fragment TypeRef on __Type {
9667
+ kind
9668
+ name
9669
+ ofType {
9670
+ kind
9671
+ name
9672
+ ofType {
9673
+ kind
9674
+ name
9675
+ ofType {
9676
+ kind
9677
+ name
9678
+ ofType {
9679
+ kind
9680
+ name
9681
+ ofType {
9682
+ kind
9683
+ name
9684
+ ofType {
9685
+ kind
9686
+ name
9687
+ ofType {
9688
+ kind
9689
+ name
9690
+ }
9691
+ }
9692
+ }
9693
+ }
9694
+ }
9695
+ }
9696
+ }
9697
+ }
9698
+ `;
9699
+
9206
9700
  // src/query-builder.ts
9207
9701
  var URL_LENGTH_THRESHOLD = 4096;
9208
9702
  var QueryBuilder = class {
@@ -10535,6 +11029,7 @@ var FluxbaseClient = class {
10535
11029
  const wsBaseUrl = fluxbaseUrl.replace(/^https?:/, wsProtocol + ":");
10536
11030
  this.ai = new FluxbaseAI(this.fetch, wsBaseUrl);
10537
11031
  this.vector = new FluxbaseVector(this.fetch);
11032
+ this.graphql = new FluxbaseGraphQL(this.fetch);
10538
11033
  const rpcInstance = new FluxbaseRPC(this.fetch);
10539
11034
  const rpcCallable = async (fn, params) => {
10540
11035
  const result = await rpcInstance.invoke(fn, params);
@@ -10801,6 +11296,7 @@ exports.FluxbaseAuth = FluxbaseAuth;
10801
11296
  exports.FluxbaseClient = FluxbaseClient;
10802
11297
  exports.FluxbaseFetch = FluxbaseFetch;
10803
11298
  exports.FluxbaseFunctions = FluxbaseFunctions;
11299
+ exports.FluxbaseGraphQL = FluxbaseGraphQL;
10804
11300
  exports.FluxbaseJobs = FluxbaseJobs;
10805
11301
  exports.FluxbaseManagement = FluxbaseManagement;
10806
11302
  exports.FluxbaseOAuth = FluxbaseOAuth;