diff --git a/.github/workflows/flowvault-internal-release.yml b/.github/workflows/flowvault-internal-release.yml
new file mode 100644
index 00000000..b1e65c12
--- /dev/null
+++ b/.github/workflows/flowvault-internal-release.yml
@@ -0,0 +1,27 @@
+name: Publish v3 module to the JFROG Artifactory
+on:
+ push:
+ tags-ignore:
+ - '*.*'
+ paths-ignore:
+ - "*.md"
+ branches:
+ - v3-release/*
+
+jobs:
+ build-and-deploy-v3:
+ uses: ./.github/workflows/shared-build-and-deploy.yml
+ with:
+ ref: ${{ github.ref_name }}
+ server-id: central
+ profile: jfrog
+ tag: 'internal'
+ module: 'flowvault'
+ secrets:
+ server-username: ${{ secrets.ARTIFACTORY_USERNAME }}
+ server-password: ${{ secrets.ARTIFACTORY_PASSWORD }}
+ gpg-key: ${{ secrets.JFROG_GPG_KEY }}
+ gpg-passphrase: ${{ secrets.JFROG_GPG_PASSPHRASE }}
+ skyflow-credentials: ${{ secrets.SKYFLOW_CREDENTIALS }}
+ test-expired-token: ${{ secrets.TEST_EXPIRED_TOKEN }}
+ test-reusable-token: ${{ secrets.TEST_REUSABLE_TOKEN }}
\ No newline at end of file
diff --git a/.github/workflows/shared-build-and-deploy.yml b/.github/workflows/shared-build-and-deploy.yml
index 13fd1b5b..9d885190 100644
--- a/.github/workflows/shared-build-and-deploy.yml
+++ b/.github/workflows/shared-build-and-deploy.yml
@@ -21,6 +21,13 @@ on:
description: 'Release Tag'
required: true
type: string
+
+ module:
+ description: 'Module to build and publish'
+ required: false
+ type: string
+ default: ''
+
secrets:
server-username:
required: true
@@ -57,10 +64,10 @@ jobs:
java-version: "11"
distribution: "adopt"
server-id: ${{ inputs.server-id }}
- server-username: SERVER_USERNAME
- server-password: SERVER_PASSWORD
+ server-username: ${{ secrets.server-username }}
+ server-password: ${{ secrets.server-password }}
gpg-private-key: ${{ secrets.gpg-key }} # Value of the GPG private key to import
- gpg-passphrase: GPG_PASSPHRASE # env variable for GPG private key passphrase
+ gpg-passphrase: ${{ secrets.gpg-passphrase }} # env variable for GPG private key passphrase
- name: Resolve Branch for the Tagged Commit
id: resolve-branch
@@ -87,7 +94,7 @@ jobs:
if ${{ inputs.tag == 'internal' }}; then
./scripts/bump_version.sh "${{ steps.previoustag.outputs.tag }}" "$(git rev-parse --short "$GITHUB_SHA")"
else
- ./scripts/bump_version.sh "${{ steps.previoustag.outputs.tag }}"
+ ./scripts/bump_version.sh "${{ steps.previoustag.outputs.tag }}" "" "${{ inputs.module }}"
fi
- name: Commit changes
@@ -99,7 +106,7 @@ jobs:
git checkout ${{ env.branch_name }}
fi
- git add pom.xml
+ git add flowvault/pom.xml
if [[ "${{ inputs.tag }}" == "internal" ]]; then
git commit -m "[AUTOMATED] Private Release ${{ steps.previoustag.outputs.tag }}-dev-$(git rev-parse --short $GITHUB_SHA)"
git push origin ${{ github.ref_name }} -f
@@ -125,7 +132,12 @@ jobs:
json: ${{ secrets.TEST_CREDENTIALS_FILE_STRING }}
- name: Publish package
- run: mvn --batch-mode deploy -P ${{ inputs.profile }}
+ run: |
+ if [[ "${{ inputs.tag }}" == "internal" ]]; then
+ mvn --batch-mode -pl ${{ inputs.module }} -am deploy -P jfrog -DskipTests
+ elif [[ "${{ inputs.tag }}" == "beta" || "${{ inputs.tag }}" == "public" ]]; then
+ mvn --batch-mode -pl ${{ inputs.module }} -am deploy -P ${{ inputs.profile }} -DskipTests
+ fi
env:
SERVER_USERNAME: ${{ secrets.server-username }}
diff --git a/common/pom.xml b/common/pom.xml
new file mode 100644
index 00000000..72fff275
--- /dev/null
+++ b/common/pom.xml
@@ -0,0 +1,24 @@
+
+
+ 4.0.0
+
+ com.skyflow
+ skyflow
+ 1.0.0
+ ../pom.xml
+
+
+ common
+ 1.0.0
+ ${project.groupId}:${project.artifactId}
+
+
+
+ true
+ 8
+ 8
+ UTF-8
+
+
\ No newline at end of file
diff --git a/common/src/main/java/com/skyflow/BaseSkyflow.java b/common/src/main/java/com/skyflow/BaseSkyflow.java
new file mode 100644
index 00000000..2daff37b
--- /dev/null
+++ b/common/src/main/java/com/skyflow/BaseSkyflow.java
@@ -0,0 +1,205 @@
+package com.skyflow;
+
+import com.skyflow.config.BaseVaultConfig;
+import com.skyflow.config.Credentials;
+import com.skyflow.enums.LogLevel;
+import com.skyflow.errors.ErrorCode;
+import com.skyflow.errors.ErrorMessage;
+import com.skyflow.errors.SkyflowException;
+import com.skyflow.logs.ErrorLogs;
+import com.skyflow.logs.InfoLogs;
+import com.skyflow.utils.BaseUtils;
+import com.skyflow.utils.logger.LogUtil;
+import com.skyflow.utils.validations.BaseValidations;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+
+abstract class BaseSkyflow implements ISkyflow {
+ protected final BaseSkyflowClientBuilder builder;
+
+ protected BaseSkyflow(BaseSkyflowClientBuilder builder) {
+ this.builder = builder;
+ LogUtil.printInfoLog(InfoLogs.CLIENT_INITIALIZED.getLog());
+ }
+
+ protected abstract Self self();
+
+ public Self addVaultConfig(V vaultConfig) throws SkyflowException {
+ this.builder.addVaultConfigTemplate(vaultConfig);
+ return self();
+ }
+
+ public V getVaultConfig(String vaultId) {
+ return this.builder.vaultConfigMap.get(vaultId);
+ }
+
+ public Self updateVaultConfig(V vaultConfig) throws SkyflowException {
+ this.builder.updateVaultConfigTemplate(vaultConfig);
+ return self();
+ }
+
+ public Self removeVaultConfig(String vaultId) throws SkyflowException {
+ this.builder.removeVaultConfigTemplate(vaultId);
+ return self();
+ }
+
+ public Self updateSkyflowCredentials(Credentials credentials) throws SkyflowException {
+ this.builder.addSkyflowCredentialsTemplate(credentials);
+ return self();
+ }
+
+ public Self setLogLevel(LogLevel logLevel) {
+ this.builder.setLogLevel(logLevel);
+ return self();
+ }
+
+ public LogLevel getLogLevel() {
+ return this.builder.logLevel;
+ }
+
+ public VC vault() throws SkyflowException {
+ return resolveOrThrow(this.builder.vaultClientsMap, null, ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST, ErrorMessage.VaultIdNotInConfigList);
+ }
+
+ protected static T resolveOrThrow(Map map, String key,
+ ErrorLogs errorLog, ErrorMessage errorMessage) throws SkyflowException {
+ T value = key != null ? map.get(key) : map.values().stream().findFirst().orElse(null);
+ if (value == null) {
+ LogUtil.printErrorLog(errorLog.getLog());
+ throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), errorMessage.getMessage());
+ }
+ return value;
+ }
+
+ abstract static class BaseSkyflowClientBuilder {
+ protected final LinkedHashMap vaultConfigMap = new LinkedHashMap<>();
+ protected final LinkedHashMap vaultClientsMap = new LinkedHashMap<>();
+ protected Credentials skyflowCredentials;
+ protected LogLevel logLevel = LogLevel.ERROR;
+
+ protected BaseSkyflowClientBuilder() {
+ }
+
+ public BaseSkyflowClientBuilder addVaultConfig(V vaultConfig) throws SkyflowException {
+ addVaultConfigTemplate(vaultConfig);
+ return this;
+ }
+
+ public BaseSkyflowClientBuilder updateVaultConfig(V vaultConfig) throws SkyflowException {
+ updateVaultConfigTemplate(vaultConfig);
+ return this;
+ }
+
+ public BaseSkyflowClientBuilder removeVaultConfig(String vaultId) throws SkyflowException {
+ removeVaultConfigTemplate(vaultId);
+ return this;
+ }
+
+ public BaseSkyflowClientBuilder addSkyflowCredentials(Credentials credentials) throws SkyflowException {
+ addSkyflowCredentialsTemplate(credentials);
+ return this;
+ }
+
+ protected BaseSkyflowClientBuilder setLogLevel(LogLevel logLevel) {
+ this.logLevel = logLevel == null ? LogLevel.ERROR : logLevel;
+ LogUtil.setupLogger(this.logLevel);
+ LogUtil.printInfoLog(BaseUtils.parameterizedString(
+ InfoLogs.CURRENT_LOG_LEVEL.getLog(), String.valueOf(this.logLevel)
+ ));
+ return this;
+ }
+
+ protected final void addVaultConfigTemplate(V vaultConfig) throws SkyflowException {
+ LogUtil.printInfoLog(InfoLogs.VALIDATING_VAULT_CONFIG.getLog());
+ validateVaultConfig(vaultConfig);
+ V vaultConfigCopy = cloneVaultConfig(vaultConfig);
+ String vaultId = extractVaultId(vaultConfigCopy);
+ if (this.vaultClientsMap.containsKey(vaultId)) {
+ LogUtil.printErrorLog(BaseUtils.parameterizedString(
+ ErrorLogs.VAULT_CONFIG_EXISTS.getLog(), vaultId
+ ));
+ throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(),
+ ErrorMessage.VaultIdAlreadyInConfigList.getMessage());
+ }
+ this.vaultConfigMap.put(vaultId, vaultConfigCopy);
+ onVaultConfigAdded(vaultConfigCopy);
+ }
+
+ protected final void updateVaultConfigTemplate(V vaultConfig) throws SkyflowException {
+ LogUtil.printInfoLog(InfoLogs.VALIDATING_VAULT_CONFIG.getLog());
+ validateVaultConfig(vaultConfig);
+ String vaultId = extractVaultId(vaultConfig);
+ if (!this.vaultClientsMap.containsKey(vaultId)) {
+ LogUtil.printErrorLog(BaseUtils.parameterizedString(
+ ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST.getLog(), vaultId
+ ));
+ throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.VaultIdNotInConfigList.getMessage());
+ }
+ V previousConfig = this.vaultConfigMap.get(vaultId);
+ V merged = mergeVaultConfig(vaultConfig, previousConfig);
+ onVaultConfigUpdated(merged);
+ }
+
+ protected final void removeVaultConfigTemplate(String vaultId) throws SkyflowException {
+ if (!this.vaultClientsMap.containsKey(vaultId)) {
+ LogUtil.printErrorLog(BaseUtils.parameterizedString(ErrorLogs.VAULT_CONFIG_DOES_NOT_EXIST.getLog(), vaultId));
+ throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.VaultIdNotInConfigList.getMessage());
+ }
+ this.vaultClientsMap.remove(vaultId);
+ this.vaultConfigMap.remove(vaultId);
+ }
+
+ protected final void addSkyflowCredentialsTemplate(Credentials credentials) throws SkyflowException {
+ BaseValidations.validateCredentials(credentials);
+ Credentials credentialsCopy;
+ try {
+ credentialsCopy = (Credentials) credentials.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new RuntimeException(e);
+ }
+ this.skyflowCredentials = credentialsCopy;
+ onCredentialsUpdated(credentialsCopy);
+ }
+
+ protected abstract void validateVaultConfig(V vaultConfig) throws SkyflowException;
+
+ @SuppressWarnings("unchecked")
+ protected final V cloneVaultConfig(V vaultConfig) {
+ try {
+ return (V) vaultConfig.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected final String extractVaultId(V vaultConfig) {
+ return vaultConfig.getVaultId();
+ }
+
+ protected final V mergeVaultConfig(V incoming, V existing) {
+ if (incoming.getEnv() != null) {
+ existing.setEnv(incoming.getEnv());
+ }
+ if (incoming.getClusterId() != null) {
+ existing.setClusterId(incoming.getClusterId());
+ }
+ if (incoming.getCredentials() != null) {
+ try {
+ existing.setCredentials((Credentials) incoming.getCredentials().clone());
+ } catch (CloneNotSupportedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return existing;
+ }
+
+ protected abstract void onVaultConfigAdded(V vaultConfig) throws SkyflowException;
+
+ protected abstract void onVaultConfigUpdated(V updatedConfig) throws SkyflowException;
+
+ protected abstract void onCredentialsUpdated(Credentials credentials) throws SkyflowException;
+ }
+
+}
diff --git a/common/src/main/java/com/skyflow/BaseVaultClient.java b/common/src/main/java/com/skyflow/BaseVaultClient.java
new file mode 100644
index 00000000..7ca74cf4
--- /dev/null
+++ b/common/src/main/java/com/skyflow/BaseVaultClient.java
@@ -0,0 +1,113 @@
+package com.skyflow;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.skyflow.config.BaseCredentials;
+import com.skyflow.errors.ErrorCode;
+import com.skyflow.errors.ErrorMessage;
+import com.skyflow.errors.SkyflowException;
+import com.skyflow.logs.ErrorLogs;
+import com.skyflow.logs.InfoLogs;
+import com.skyflow.serviceaccount.util.Token;
+import com.skyflow.utils.BaseConstants;
+import com.skyflow.utils.BaseUtils;
+import com.skyflow.utils.logger.LogUtil;
+import com.skyflow.utils.validations.BaseValidations;
+import io.github.cdimascio.dotenv.Dotenv;
+import io.github.cdimascio.dotenv.DotenvException;
+import okhttp3.ConnectionPool;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Supplier;
+
+class BaseVaultClient {
+ protected V vaultConfig;
+ protected OkHttpClient sharedHttpClient;
+ protected String currentVaultURL;
+ protected BaseCredentials commonCredentials;
+ protected BaseCredentials finalCredentials;
+ protected String token;
+ protected String apiKey;
+
+ protected BaseVaultClient(V vaultConfig, BaseCredentials credentials) {
+ this.vaultConfig = vaultConfig;
+ this.commonCredentials = credentials;
+ }
+
+ protected V getVaultConfig() {
+ return vaultConfig;
+ }
+
+ protected OkHttpClient buildSharedHttpClient(Supplier tokenSupplier) {
+ return new OkHttpClient.Builder()
+ .connectionPool(new ConnectionPool(10, 1, TimeUnit.MINUTES))
+ .addInterceptor(chain -> {
+ Request requestWithAuth = chain.request().newBuilder()
+ .header("Authorization", "Bearer " + tokenSupplier.get())
+ .build();
+ return chain.proceed(requestWithAuth);
+ })
+ .build();
+ }
+
+ protected void prioritiseCredentials(BaseCredentials vaultSpecificCredentials) throws SkyflowException {
+ try {
+ BaseCredentials original = this.finalCredentials;
+ if (vaultSpecificCredentials != null) {
+ this.finalCredentials = vaultSpecificCredentials;
+ } else if (this.commonCredentials != null) {
+ this.finalCredentials = this.commonCredentials;
+ } else {
+ String sysCredentials = System.getenv(BaseConstants.ENV_CREDENTIALS_KEY_NAME);
+ if (sysCredentials == null) {
+ Dotenv dotenv = Dotenv.load();
+ sysCredentials = dotenv.get(BaseConstants.ENV_CREDENTIALS_KEY_NAME);
+ }
+ if (sysCredentials == null) {
+ throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyCredentials.getMessage());
+ } else {
+ this.finalCredentials = new BaseCredentials();
+ this.finalCredentials.setCredentialsString(sysCredentials);
+ }
+ }
+ if (original != null && !original.equals(this.finalCredentials)) {
+ token = null;
+ apiKey = null;
+ }
+ } catch (DotenvException e) {
+ throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyCredentials.getMessage());
+ } catch (SkyflowException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected void setBearerToken(BaseCredentials vaultSpecificCredentials) throws SkyflowException {
+ prioritiseCredentials(vaultSpecificCredentials);
+ BaseValidations.validateCredentials(this.finalCredentials);
+ if (this.finalCredentials.getApiKey() != null) {
+ LogUtil.printInfoLog(InfoLogs.USE_API_KEY.getLog());
+ token = this.finalCredentials.getApiKey();
+ } else if (token == null || token.trim().isEmpty()) {
+ token = BaseUtils.generateBearerToken(this.finalCredentials);
+ } else if (Token.isExpired(token)) {
+ LogUtil.printInfoLog(InfoLogs.BEARER_TOKEN_EXPIRED.getLog());
+ token = BaseUtils.generateBearerToken(this.finalCredentials);
+ } else {
+ LogUtil.printInfoLog(InfoLogs.REUSE_BEARER_TOKEN.getLog());
+ }
+ }
+
+ protected static SkyflowException wrapApiException(int statusCode, Throwable cause,
+ Map> headers,
+ Object responseBody, ErrorLogs errorLog) {
+ LogUtil.printErrorLog(errorLog.getLog());
+ Gson gson = new GsonBuilder().serializeNulls().create();
+ return new SkyflowException(statusCode, cause, headers, gson.toJson(responseBody));
+ }
+}
diff --git a/common/src/main/java/com/skyflow/ISkyflow.java b/common/src/main/java/com/skyflow/ISkyflow.java
new file mode 100644
index 00000000..55879a6c
--- /dev/null
+++ b/common/src/main/java/com/skyflow/ISkyflow.java
@@ -0,0 +1,20 @@
+package com.skyflow;
+
+import com.skyflow.enums.LogLevel;
+import com.skyflow.errors.SkyflowException;
+
+public interface ISkyflow {
+ Self addVaultConfig(V vaultConfig) throws SkyflowException;
+
+ Self updateVaultConfig(V vaultConfig) throws SkyflowException;
+
+ Self removeVaultConfig(String vaultId) throws SkyflowException;
+
+ Self updateSkyflowCredentials(C credentials) throws SkyflowException;
+
+ Self setLogLevel(LogLevel logLevel);
+
+ LogLevel getLogLevel();
+
+ VC vault() throws SkyflowException;
+}
diff --git a/src/main/java/com/skyflow/config/Credentials.java b/common/src/main/java/com/skyflow/config/BaseCredentials.java
similarity index 87%
rename from src/main/java/com/skyflow/config/Credentials.java
rename to common/src/main/java/com/skyflow/config/BaseCredentials.java
index c2594ef6..34b2c117 100644
--- a/src/main/java/com/skyflow/config/Credentials.java
+++ b/common/src/main/java/com/skyflow/config/BaseCredentials.java
@@ -3,18 +3,18 @@
import java.util.ArrayList;
import java.util.Map;
-public class Credentials {
+public class BaseCredentials implements Cloneable {
private String path;
private ArrayList roles;
- private Object context;
private String credentialsString;
private String token;
private String apiKey;
+ private Object context;
- public Credentials() {
+ public BaseCredentials() {
this.path = null;
- this.context = null;
this.credentialsString = null;
+ this.context = null;
}
public String getPath() {
@@ -33,18 +33,6 @@ public void setRoles(ArrayList roles) {
this.roles = roles;
}
- public Object getContext() {
- return context;
- }
-
- public void setContext(String context) {
- this.context = context;
- }
-
- public void setContext(Map context) {
- this.context = context;
- }
-
public String getCredentialsString() {
return credentialsString;
}
@@ -68,4 +56,20 @@ public String getApiKey() {
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
+ public Object getContext() {
+ return context;
+ }
+
+ public void setContext(String context) {
+ this.context = context;
+ }
+
+ public void setContext(Map context) {
+ this.context = context;
+ }
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
}
diff --git a/src/main/java/com/skyflow/config/VaultConfig.java b/common/src/main/java/com/skyflow/config/BaseVaultConfig.java
similarity index 71%
rename from src/main/java/com/skyflow/config/VaultConfig.java
rename to common/src/main/java/com/skyflow/config/BaseVaultConfig.java
index 4f61af2a..fb1a2a6b 100644
--- a/src/main/java/com/skyflow/config/VaultConfig.java
+++ b/common/src/main/java/com/skyflow/config/BaseVaultConfig.java
@@ -2,13 +2,13 @@
import com.skyflow.enums.Env;
-public class VaultConfig {
+public class BaseVaultConfig implements Cloneable {
private String vaultId;
private String clusterId;
private Env env;
private Credentials credentials;
- public VaultConfig() {
+ public BaseVaultConfig() {
this.vaultId = null;
this.clusterId = null;
this.env = Env.PROD;
@@ -46,4 +46,14 @@ public Credentials getCredentials() {
public void setCredentials(Credentials credentials) {
this.credentials = credentials;
}
+
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ BaseVaultConfig cloned = (BaseVaultConfig) super.clone();
+ if (this.credentials != null) {
+ cloned.credentials = (Credentials) this.credentials.clone();
+ }
+ return cloned;
+ }
+
}
diff --git a/common/src/main/java/com/skyflow/config/Credentials.java b/common/src/main/java/com/skyflow/config/Credentials.java
new file mode 100644
index 00000000..b0d6b888
--- /dev/null
+++ b/common/src/main/java/com/skyflow/config/Credentials.java
@@ -0,0 +1,7 @@
+package com.skyflow.config;
+
+public class Credentials extends BaseCredentials {
+ public Credentials() {
+ super();
+ }
+}
diff --git a/src/main/java/com/skyflow/enums/Env.java b/common/src/main/java/com/skyflow/enums/Env.java
similarity index 100%
rename from src/main/java/com/skyflow/enums/Env.java
rename to common/src/main/java/com/skyflow/enums/Env.java
diff --git a/src/main/java/com/skyflow/enums/LogLevel.java b/common/src/main/java/com/skyflow/enums/LogLevel.java
similarity index 100%
rename from src/main/java/com/skyflow/enums/LogLevel.java
rename to common/src/main/java/com/skyflow/enums/LogLevel.java
diff --git a/src/main/java/com/skyflow/errors/ErrorCode.java b/common/src/main/java/com/skyflow/errors/ErrorCode.java
similarity index 100%
rename from src/main/java/com/skyflow/errors/ErrorCode.java
rename to common/src/main/java/com/skyflow/errors/ErrorCode.java
diff --git a/common/src/main/java/com/skyflow/errors/ErrorMessage.java b/common/src/main/java/com/skyflow/errors/ErrorMessage.java
new file mode 100644
index 00000000..e3b5924b
--- /dev/null
+++ b/common/src/main/java/com/skyflow/errors/ErrorMessage.java
@@ -0,0 +1,210 @@
+package com.skyflow.errors;
+
+import com.skyflow.utils.SdkVersion;
+
+public enum ErrorMessage {
+ // Client initialization
+ VaultIdAlreadyInConfigList("%s0 Validation error. VaultId is present in an existing config. Specify a new vaultId in config."),
+ VaultIdNotInConfigList("%s0 Validation error. VaultId is missing from the config. Specify the vaultIds from configs."),
+ OnlySingleVaultConfigAllowed("%s0 Validation error. A vault config already exists. Cannot add another vault config."),
+ ConnectionIdAlreadyInConfigList("%s0 Validation error. ConnectionId is present in an existing config. Specify a connectionId in config."),
+ ConnectionIdNotInConfigList("%s0 Validation error. ConnectionId is missing from the config. Specify the connectionIds from configs."),
+ EmptyCredentials("%s0 Validation error. Invalid credentials. Credentials must not be empty."),
+ TableSpecifiedInRequestAndRecordObject("%s0 Validation error. Table name cannot be specified at both the request and record levels. Please specify the table name in only one place."),
+ UpsertTableRequestAtRecordLevel("%s0 Validation error. Table name should be present at each record level when upsert is present at record level."),
+ UpsertTableRequestAtRequestLevel("%s0 Validation error. Upsert should be present at each record level when table name is present at record level."),
+ TableNotSpecifiedInRequestAndRecordObject("%s0 Validation error. Table name is missing. Table name should be specified at one place either at the request level or record level. Please specify the table name at one place."),
+ // Vault config
+ InvalidVaultId("%s0 Initialization failed. Invalid vault ID. Specify a valid vault ID."),
+ EmptyVaultId("%s0 Initialization failed. Invalid vault ID. Vault ID must not be empty."),
+ InvalidClusterId("%s0 Initialization failed. Invalid cluster ID. Specify cluster ID."),
+ EmptyClusterId("%s0 Initialization failed. Invalid cluster ID. Specify a valid cluster ID."),
+ EmptyVaultUrl("%s0 Initialization failed. Vault URL is empty. Specify a valid vault URL."),
+ InvalidVaultUrlFormat("%s0 Initialization failed. Vault URL must start with 'https://'."),
+ EitherVaultUrlOrClusterIdRequired("%s0 Initialization failed. Specify either 'clusterId' or 'vaultURL'."),
+
+ // Connection config
+ InvalidConnectionId("%s0 Initialization failed. Invalid connection ID. Specify a valid connection ID."),
+ EmptyConnectionId("%s0 Initialization failed. Invalid connection ID. Connection ID must not be empty."),
+ InvalidConnectionUrl("%s0 Initialization failed. Invalid connection URL. Specify a valid connection URL."),
+ EmptyConnectionUrl("%s0 Initialization failed. Invalid connection URL. Connection URL must not be empty."),
+ InvalidConnectionUrlFormat("%s0 Initialization failed. Connection URL is not a valid URL. Specify a valid connection URL."),
+
+ // Credentials
+ MultipleTokenGenerationMeansPassed("%s0 Initialization failed. Invalid credentials. Specify only one from 'path', 'credentialsString', 'token' or 'apiKey'."),
+ NoTokenGenerationMeansPassed("%s0 Initialization failed. Invalid credentials. Specify any one from 'path', 'credentialsString', 'token' or 'apiKey'."),
+ EmptyCredentialFilePath("%s0 Initialization failed. Invalid credentials. Credentials file path must not be empty."),
+ EmptyCredentialsString("%s0 Initialization failed. Invalid credentials. Credentials string must not be empty."),
+ EmptyToken("%s0 Initialization failed. Invalid credentials. Token must not be empty."),
+ EmptyApikey("%s0 Initialization failed. Invalid credentials. Api key must not be empty."),
+ InvalidApikey("%s0 Initialization failed. Invalid credentials. Specify valid api key."),
+ EmptyRoles("%s0 Initialization failed. Invalid roles. Specify at least one role."),
+ EmptyRoleInRoles("%s0 Initialization failed. Invalid role. Specify a valid role."),
+ EmptyContext("%s0 Initialization failed. Invalid context. Specify a valid context."),
+ InvalidContextType("%s0 Initialization failed. Invalid context type. Specify context as a String or Map."),
+ InvalidContextMapKey("%s0 Initialization failed. Invalid key '%s1' in context map. Keys must contain only alphanumeric characters and underscores."),
+
+ // Bearer token generation
+ FileNotFound("%s0 Initialization failed. Credential file not found at %s1. Verify the file path."),
+ FileInvalidJson("%s0 Initialization failed. File at %s1 is not in valid JSON format. Verify the file contents."),
+ CredentialsStringInvalidJson("%s0 Initialization failed. Credentials string is not in valid JSON format. Verify the credentials string contents."),
+ InvalidCredentials("%s0 Initialization failed. Invalid credentials provided. Specify valid credentials."),
+ MissingPrivateKey("%s0 Initialization failed. Unable to read private key in credentials. Verify your private key."),
+ MissingClientId("%s0 Initialization failed. Unable to read client ID in credentials. Verify your client ID."),
+ MissingKeyId("%s0 Initialization failed. Unable to read key ID in credentials. Verify your key ID."),
+ MissingTokenUri("%s0 Initialization failed. Unable to read token URI in credentials. Verify your token URI."),
+ InvalidTokenUri("%s0 Initialization failed. Token URI in not a valid URL in credentials. Verify your token URI."),
+ JwtInvalidFormat("%s0 Initialization failed. Invalid private key format. Verify your credentials."),
+ InvalidAlgorithm("%s0 Initialization failed. Invalid algorithm to parse private key. Specify valid algorithm."),
+ InvalidKeySpec("%s0 Initialization failed. Unable to parse RSA private key. Verify your credentials."),
+ JwtDecodeError("%s0 Validation error. Invalid access token. Verify your credentials."),
+ MissingAccessToken("%s0 Validation error. Access token not present in the response from bearer token generation. Verify your credentials."),
+ MissingTokenType("%s0 Validation error. Token type not present in the response from bearer token generation. Verify your credentials."),
+ BearerTokenExpired("%s0 Validation error. Bearer token is invalid or expired. Please provide a valid bearer token."),
+
+ // Insert
+ TableKeyError("%s0 Validation error. 'table' key is missing from the payload. Specify a 'table' key."),
+ EmptyTable("%s0 Validation error. 'table' can't be empty. Specify a table."),
+ ValuesKeyError("%s0 Validation error. 'values' key is missing from the payload. Specify a 'values' key."),
+ EmptyRecords("%s0 Validation error. 'records' can't be empty. Specify records."),
+ EmptyKeyInRecords("%s0 Validation error. Invalid key in data in records. Specify a valid key."),
+ EmptyValueInRecords("%s0 Validation error. Invalid value in records. Specify a valid value."),
+ RecordsKeyError("%s0 Validation error. 'records' key is missing from the payload. Specify a 'records' key."),
+ EmptyValues("%s0 Validation error. 'values' can't be empty. Specify values."),
+ EmptyKeyInValues("%s0 Validation error. Invalid key in values. Specify a valid key."),
+ EmptyValueInValues("%s0 Validation error. Invalid value in values. Specify a valid value."),
+ TokensKeyError("%s0 Validation error. 'tokens' key is missing from the payload. Specify a 'tokens' key."),
+ EmptyTokens("%s0 Validation error. The 'tokens' field is empty. Specify tokens for one or more fields."),
+ EmptyKeyInTokens("%s0 Validation error. Invalid key tokens. Specify a valid key."),
+ EmptyValueInTokens("%s0 Validation error. Invalid value in tokens. Specify a valid value."),
+ EmptyUpsert("%s0 Validation error. 'upsert' key can't be empty. Specify an upsert column."),
+ EmptyUpsertValues("%s0 Validation error. Upsert column values can't be empty. Specify at least one upsert column."),
+ HomogenousNotSupportedWithUpsert("%s0 Validation error. 'homogenous' is not supported with 'upsert'. Specify either 'homogenous' or 'upsert'."),
+ TokensPassedForTokenModeDisable("%s0 Validation error. 'tokenMode' wasn't specified. Set 'tokenMode' to 'ENABLE' to insert tokens."),
+ NoTokensWithTokenMode("%s0 Validation error. Tokens weren't specified for records while 'tokenMode' was %s1. Specify tokens."),
+ MismatchOfFieldsAndTokens("%s0 Validation error. 'fields' and 'tokens' have different columns names. Verify that 'fields' and 'tokens' columns match."),
+ InsufficientTokensPassedForTokenModeEnableStrict("%s0 Validation error. 'tokenMode' is set to 'ENABLE_STRICT', but some fields are missing tokens. Specify tokens for all fields."),
+ BatchInsertPartialSuccess("%s0 Insert operation completed with partial success."),
+ BatchInsertFailure("%s0 Insert operation failed."),
+ RecordSizeExceedError("%s0 Maximum number of records exceeded. The limit is 10000."),
+
+ // Detokenize
+ InvalidDetokenizeData("%s0 Validation error. Invalid detokenize data. Specify valid detokenize data."),
+ EmptyDetokenizeData("%s0 Validation error. Invalid data tokens. Specify at least one data token."),
+ EmptyTokenInDetokenizeData("%s0 Validation error. Invalid data tokens. Specify a valid data token."),
+ TokensSizeExceedError("%s0 Maximum number of tokens exceeded. The limit is 10000."),
+
+ // Delete Tokens
+ DeleteTokensRequestNull("%s0 Validation error. DeleteTokensRequest object is null. Specify a valid DeleteTokensRequest object."),
+ EmptyDeleteTokensData("%s0 Validation error. Tokens list is empty. Specify at least one token to delete."),
+ EmptyTokenInDeleteTokensData("%s0 Validation error. Invalid token in delete tokens request. Specify a valid token."),
+ DeleteTokensSizeExceedError("%s0 Maximum number of tokens exceeded. The limit is 10000."),
+
+ // Get
+ IdsKeyError("%s0 Validation error. 'ids' key is missing from the payload. Specify an 'ids' key."),
+ EmptyIds("%s0 Validation error. 'ids' can't be empty. Specify at least one id."),
+ EmptyIdInIds("%s0 Validation error. Invalid id in 'ids'. Specify a valid id."),
+ EmptyFields("%s0 Validation error. Fields are empty in get payload. Specify at least one field."),
+ EmptyFieldInFields("%s0 Validation error. Invalid field in 'fields'. Specify a valid field."),
+ RedactionKeyError("%s0 Validation error. 'redaction' key is missing from the payload. Specify a 'redaction' key."),
+ RedactionWithTokensNotSupported("%s0 Validation error. 'redaction' can't be used when 'returnTokens' is specified. Remove 'redaction' from payload if 'returnTokens' is specified."),
+ TokensGetColumnNotSupported("%s0 Validation error. Column name and/or column values can't be used when 'returnTokens' is specified. Remove unique column values or 'returnTokens' from the payload."),
+ EmptyOffset("%s0 Validation error. 'offset' can't be empty. Specify an offset."),
+ EmptyLimit("%s0 Validation error. 'limit' can't be empty. Specify a limit."),
+ UniqueColumnOrIdsKeyError("%s0 Validation error. 'ids' or 'columnName' key is missing from the payload. Specify the ids or unique 'columnName' in payload."),
+ BothIdsAndColumnDetailsSpecified("%s0 Validation error. Both Skyflow IDs and column details can't be specified. Either specify Skyflow IDs or unique column details."),
+ ColumnNameKeyError("%s0 Validation error. 'columnName' isn't specified whereas 'columnValues' are specified. Either add 'columnName' or remove 'columnValues'."),
+ EmptyColumnName("%s0 Validation error. 'columnName' can't be empty. Specify a column name."),
+ ColumnValuesKeyErrorGet("%s0 Validation error. 'columnValues' aren't specified whereas 'columnName' is specified. Either add 'columnValues' or remove 'columnName'."),
+ EmptyColumnValues("%s0 Validation error. 'columnValues' can't be empty. Specify at least one column value"),
+ EmptyValueInColumnValues("%s0 Validation error. Invalid value in column values. Specify a valid column value."),
+
+ TokenKeyError("%s0 Validation error. 'token' key is missing from the payload. Specify a 'token' key."),
+ PartialSuccess("%s0 Validation error. Check 'SkyflowError.data' for details."),
+
+ // Update
+ DataKeyError("%s0 Validation error. 'data' key is missing from the payload. Specify a 'data' key."),
+ EmptyData("%s0 Validation error. 'data' can't be empty. Specify data."),
+ SkyflowIdKeyError("%s0 Validation error. 'skyflow_id' is missing from the data payload. Specify a 'skyflow_id'."),
+ InvalidSkyflowIdType("%s0 Validation error. Invalid type for 'skyflow_id' in data payload. Specify 'skyflow_id' as a string."),
+ EmptySkyflowId("%s0 Validation error. 'skyflow_id' can't be empty. Specify a skyflow id."),
+
+ // Query
+ QueryKeyError("%s0 Validation error. 'query' key is missing from the payload. Specify a 'query' key."),
+ EmptyQuery("%s0 Validation error. 'query' can't be empty. Specify a query"),
+
+ // Tokenize
+ ColumnValuesKeyErrorTokenize("%s0 Validation error. 'columnValues' key is missing from the payload. Specify a 'columnValues' key."),
+ EmptyColumnGroupInColumnValue("%s0 Validation error. Invalid column group in column value. Specify a valid column group."),
+ TokenizeRequestNull("%s0 Validation error. TokenizeRequest object is null. Specify a valid TokenizeRequest object."),
+ EmptyTokenizeData("%s0 Validation error. Tokenize data is empty. Specify at least one tokenize record."),
+ TokenizeRecordNull("%s0 Validation error. TokenizeRecord in the list is null. Specify a valid TokenizeRecord object."),
+ EmptyValueInTokenizeRecord("%s0 Validation error. Value in TokenizeRecord is null or empty. Specify a valid value."),
+ EmptyTokenGroupNamesInTokenizeRecord("%s0 Validation error. TokenGroupNames in TokenizeRecord is null or empty. Specify at least one token group name."),
+ EmptyTokenGroupNameInTokenizeRecord("%s0 Validation error. Token group name in TokenizeRecord is null or empty. Specify a valid token group name."),
+ TokenizeDataSizeExceedError("%s0 Maximum number of tokenize records exceeded. The limit is 10000."),
+
+ // Connection
+ InvalidRequestHeaders("%s0 Validation error. Request headers aren't valid. Specify valid request headers."),
+ EmptyRequestHeaders("%s0 Validation error. Request headers are empty. Specify valid request headers."),
+ InvalidPathParams("%s0 Validation error. Path parameters aren't valid. Specify valid path parameters."),
+ EmptyPathParams("%s0 Validation error. Path parameters are empty. Specify valid path parameters."),
+ InvalidQueryParams("%s0 Validation error. Query parameters aren't valid. Specify valid query parameters."),
+ EmptyQueryParams("%s0 Validation error. Query parameters are empty. Specify valid query parameters."),
+ InvalidRequestBody("%s0 Validation error. Invalid request body. Specify the request body as an object."),
+ EmptyRequestBody("%s0 Validation error. Request body can't be empty. Specify a valid request body."),
+
+ // File upload
+ ColumnNameKeyErrorFileUpload("%s0 Validation error. columnName is missing from the payload. Specify a columnName key."),
+ MissingFileSourceInUploadFileRequest("%s0 Validation error. Provide exactly one of filePath, base64, or fileObject."),
+ FileNameMustBeProvidedWithFileObject("%s0 Validation error. fileName must be provided when using fileObject."),
+ InvalidFileObject("%s0 Validation error. Invalid file object in file upload request. Specify a valid file object."),
+ InvalidBase64("%s0 Validation error. Invalid base64 string in file upload request. Specify a valid base64 string."),
+
+ // detect
+ InvalidTextInDeIdentify("%s0 Validation error. The text field is required and must be a non-empty string. Specify a valid text."),
+ InvalidTextInReIdentify("%s0 Validation error. The text field is required and must be a non-empty string. Specify a valid text."),
+
+ //Detect Files
+ InvalidNullFileInDeIdentifyFile("%s0 Validation error. The file field is required and must not be null. Specify a valid file object."),
+ InvalidFilePath("%s0 Validation error. The file path is invalid. Specify a valid file path."),
+ BothFileAndFilePathProvided("%s0 Validation error. Both file and filePath are provided. Specify either file object or filePath, not both."),
+ FileNotFoundToDeidentify("%s0 Validation error. The file to deidentify was not found at the specified path. Verify the file path and try again."),
+ FileNotReadableToDeidentify("%s0 Validation error. The file to deidentify is not readable. Check the file permissions and try again."),
+ InvalidPixelDensityToDeidentifyFile("%s0 Validation error. Should be a positive integer. Specify a valid pixel density."),
+ InvalidMaxResolution("%s0 Validation error. Should be a positive integer. Specify a valid max resolution."),
+ OutputDirectoryNotFound("%s0 Validation error. The output directory for deidentified files was not found at the specified path. Verify the output directory path and try again."),
+ InvalidPermission("%s0 Validation error. The output directory for deidentified files is not writable. Check the directory permissions and try again."),
+ InvalidWaitTime("%s0 Validation error. The wait time for deidentify file operation should be a positive integer. Specify a valid wait time."),
+ WaitTimeExceedsLimit("%s0 Validation error. The wait time for deidentify file operation exceeds the maximum limit of 64 seconds. Specify a wait time less than or equal to 60 seconds."),
+ InvalidOrEmptyRunId("%s0 Validation error. The run ID is invalid or empty. Specify a valid run ID."),
+ FailedToEncodeFile("%s0 Validation error. Failed to encode the file. Ensure the file is in a supported format and try again."),
+ FailedToDecodeFileFromResponse("%s0 Failed to decode the file from the response. Ensure the response is valid and try again."),
+ EmptyFileAndFilePathInDeIdentifyFile("%s0 Validation error. Both file and filePath are empty. Specify either file object or filePath, not both."),
+ VaultTokenFormatIsNotAllowedForFiles("%s0 Validation error. Vault token format is not allowed for deidentify file request."),
+ PollingForResultsFailed("%s0 API error. Polling for results failed. Unable to retrieve the deidentified file"),
+ FailedToSaveProcessedFile("%s0 Validation error. Failed to save the processed file. Ensure the output directory is valid and writable."),
+ InvalidAudioFileType("%s0 Validation error. The file type is not supported. Specify a valid file type mp3 or wav."),
+ // Generic
+ ErrorOccurred("%s0 API error. Error occurred."),
+
+ DetokenizeRequestNull("%s0 Validation error. DetokenizeRequest object is null. Specify a valid DetokenizeRequest object."),
+
+ NullTokenGroupRedactions("%s0 Validation error. TokenGroupRedaction in the list is null. Specify a valid TokenGroupRedactions object."),
+
+ NullRedactionInTokenGroup("%s0 Validation error. Redaction in TokenGroupRedactions is null or empty. Specify a valid redaction."),
+
+ NullTokenGroupNameInTokenGroup("%s0 Validation error. TokenGroupName in TokenGroupRedactions is null or empty. Specify a valid tokenGroupName."),
+ InvalidRecord("%s0 Validation error. InsertRecord object in the list is invalid. Specify a valid InsertRecord object."),
+ ;
+
+ private final String message;
+
+ ErrorMessage(String message) {
+ this.message = message;
+ }
+
+ public String getMessage() {
+ return message.replace("%s0", SdkVersion.getSdkPrefix());
+ }
+}
diff --git a/src/main/java/com/skyflow/errors/HttpStatus.java b/common/src/main/java/com/skyflow/errors/HttpStatus.java
similarity index 100%
rename from src/main/java/com/skyflow/errors/HttpStatus.java
rename to common/src/main/java/com/skyflow/errors/HttpStatus.java
diff --git a/common/src/main/java/com/skyflow/errors/SkyflowException.java b/common/src/main/java/com/skyflow/errors/SkyflowException.java
new file mode 100644
index 00000000..138fcc68
--- /dev/null
+++ b/common/src/main/java/com/skyflow/errors/SkyflowException.java
@@ -0,0 +1,135 @@
+package com.skyflow.errors;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import com.skyflow.utils.BaseConstants;
+
+import java.util.List;
+import java.util.Map;
+
+public class SkyflowException extends Exception {
+ private String requestId;
+ private Integer grpcCode;
+ private Integer httpCode;
+ private String message;
+ private String httpStatus;
+ private JsonArray details;
+ private JsonObject responseBody;
+
+ public SkyflowException(String message) {
+ super(message);
+ this.message = message;
+ }
+
+ public SkyflowException(Throwable cause) {
+ super(cause);
+ this.message = cause.getMessage();
+ }
+
+ public SkyflowException(String message, Throwable cause) {
+ super(message, cause);
+ this.message = message;
+ }
+
+ public SkyflowException(int code, String message) {
+ super(message);
+ this.httpCode = code;
+ this.message = message;
+ this.httpStatus = HttpStatus.BAD_REQUEST.getHttpStatus();
+ this.details = new JsonArray();
+ }
+
+ public SkyflowException(int httpCode, Throwable cause, Map> responseHeaders, String responseBody) {
+ super(cause);
+ this.httpCode = httpCode > 0 ? httpCode : 400;
+ try {
+ setRequestId(responseHeaders);
+ setResponseBody(responseBody, responseHeaders);
+ } catch (Exception e) {
+ this.httpStatus = HttpStatus.BAD_REQUEST.getHttpStatus();
+ String fullMessage = responseBody != null ? responseBody :
+ (cause.getLocalizedMessage() != null ? cause.getMessage() : ErrorMessage.ErrorOccurred.getMessage());
+ this.message = fullMessage.split("HTTP response code:")[0].trim();
+ }
+ }
+
+ private void setResponseBody(String responseBody, Map> responseHeaders) {
+ this.responseBody = JsonParser.parseString(responseBody).getAsJsonObject();
+ if (this.responseBody.get("error") != null) {
+ setGrpcCode();
+ setHttpStatus();
+ setMessage();
+ setDetails(responseHeaders);
+ }
+ }
+
+ public String getRequestId() {
+ return requestId;
+ }
+
+ private void setRequestId(Map> responseHeaders) {
+ List ids = responseHeaders.get(BaseConstants.REQUEST_ID_HEADER_KEY);
+ this.requestId = ids == null ? null : ids.get(0);
+ }
+
+ private void setMessage() {
+ JsonElement messageElement = ((JsonObject) responseBody.get("error")).get("message");
+ this.message = messageElement == null ? null : messageElement.getAsString();
+ }
+
+ private void setGrpcCode() {
+ JsonElement grpcElement = ((JsonObject) responseBody.get("error")).get("grpc_code");
+ this.grpcCode = grpcElement == null ? null : grpcElement.getAsInt();
+ }
+
+ private void setHttpStatus() {
+ JsonElement statusElement = ((JsonObject) responseBody.get("error")).get("http_status");
+ this.httpStatus = statusElement == null ? null : statusElement.getAsString();
+ }
+
+ public int getHttpCode() {
+ return httpCode;
+ }
+
+ public JsonArray getDetails() {
+ return details;
+ }
+
+ private void setDetails(Map> responseHeaders) {
+ JsonElement detailsElement = ((JsonObject) responseBody.get("error")).get("details");
+ List errorFromClientHeader = responseHeaders.get(BaseConstants.ERROR_FROM_CLIENT_HEADER_KEY);
+ if (detailsElement != null) {
+ this.details = detailsElement.getAsJsonArray();
+ }
+ if (errorFromClientHeader != null) {
+ this.details = this.details == null ? new JsonArray() : this.details;
+ String errorFromClient = errorFromClientHeader.get(0);
+ JsonObject detailObject = new JsonObject();
+ detailObject.addProperty("errorFromClient", errorFromClient);
+ this.details.add(detailObject);
+ }
+ }
+
+ public Integer getGrpcCode() {
+ return grpcCode;
+ }
+
+ public String getHttpStatus() {
+ return httpStatus;
+ }
+
+ @Override
+ public String getMessage() {
+ return message;
+ }
+
+ @Override
+ public String toString() {
+ return String.format(
+ "%n requestId: %s%n grpcCode: %s%n httpCode: %s%n httpStatus: %s%n message: %s%n details: %s",
+ this.requestId, this.grpcCode, this.httpCode, this.httpStatus, this.message, this.details
+ );
+ }
+}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/ApiClient.java b/common/src/main/java/com/skyflow/generated/auth/rest/ApiClient.java
new file mode 100644
index 00000000..a1dd3aae
--- /dev/null
+++ b/common/src/main/java/com/skyflow/generated/auth/rest/ApiClient.java
@@ -0,0 +1,29 @@
+/**
+ * This file was auto-generated by Fern from our API Definition.
+ */
+package com.skyflow.generated.auth.rest;
+
+import com.skyflow.generated.auth.rest.core.ClientOptions;
+import com.skyflow.generated.auth.rest.core.Suppliers;
+import com.skyflow.generated.auth.rest.resources.authentication.AuthenticationClient;
+
+import java.util.function.Supplier;
+
+public class ApiClient {
+ protected final ClientOptions clientOptions;
+
+ protected final Supplier authenticationClient;
+
+ public ApiClient(ClientOptions clientOptions) {
+ this.clientOptions = clientOptions;
+ this.authenticationClient = Suppliers.memoize(() -> new AuthenticationClient(clientOptions));
+ }
+
+ public AuthenticationClient authentication() {
+ return this.authenticationClient.get();
+ }
+
+ public static ApiClientBuilder builder() {
+ return new ApiClientBuilder();
+ }
+}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/ApiClientBuilder.java b/common/src/main/java/com/skyflow/generated/auth/rest/ApiClientBuilder.java
new file mode 100644
index 00000000..aed3ed24
--- /dev/null
+++ b/common/src/main/java/com/skyflow/generated/auth/rest/ApiClientBuilder.java
@@ -0,0 +1,67 @@
+/**
+ * This file was auto-generated by Fern from our API Definition.
+ */
+package com.skyflow.generated.auth.rest;
+
+import com.skyflow.generated.auth.rest.core.ClientOptions;
+import com.skyflow.generated.auth.rest.core.Environment;
+import okhttp3.OkHttpClient;
+
+public final class ApiClientBuilder {
+ private ClientOptions.Builder clientOptionsBuilder = ClientOptions.builder();
+
+ private String token = null;
+
+ private Environment environment = Environment.PRODUCTION;
+
+ /**
+ * Sets token
+ */
+ public ApiClientBuilder token(String token) {
+ this.token = token;
+ return this;
+ }
+
+ public ApiClientBuilder environment(Environment environment) {
+ this.environment = environment;
+ return this;
+ }
+
+ public ApiClientBuilder url(String url) {
+ this.environment = Environment.custom(url);
+ return this;
+ }
+
+ /**
+ * Sets the timeout (in seconds) for the client. Defaults to 60 seconds.
+ */
+ public ApiClientBuilder timeout(int timeout) {
+ this.clientOptionsBuilder.timeout(timeout);
+ return this;
+ }
+
+ /**
+ * Sets the maximum number of retries for the client. Defaults to 2 retries.
+ */
+ public ApiClientBuilder maxRetries(int maxRetries) {
+ this.clientOptionsBuilder.maxRetries(maxRetries);
+ return this;
+ }
+
+ /**
+ * Sets the underlying OkHttp client
+ */
+ public ApiClientBuilder httpClient(OkHttpClient httpClient) {
+ this.clientOptionsBuilder.httpClient(httpClient);
+ return this;
+ }
+
+ public ApiClient build() {
+ if (token == null) {
+ throw new RuntimeException("Please provide token");
+ }
+ this.clientOptionsBuilder.addHeader("Authorization", "Bearer " + this.token);
+ clientOptionsBuilder.environment(this.environment);
+ return new ApiClient(clientOptionsBuilder.build());
+ }
+}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/AsyncApiClient.java b/common/src/main/java/com/skyflow/generated/auth/rest/AsyncApiClient.java
new file mode 100644
index 00000000..748eb02e
--- /dev/null
+++ b/common/src/main/java/com/skyflow/generated/auth/rest/AsyncApiClient.java
@@ -0,0 +1,29 @@
+/**
+ * This file was auto-generated by Fern from our API Definition.
+ */
+package com.skyflow.generated.auth.rest;
+
+import com.skyflow.generated.auth.rest.core.ClientOptions;
+import com.skyflow.generated.auth.rest.core.Suppliers;
+import com.skyflow.generated.auth.rest.resources.authentication.AsyncAuthenticationClient;
+
+import java.util.function.Supplier;
+
+public class AsyncApiClient {
+ protected final ClientOptions clientOptions;
+
+ protected final Supplier authenticationClient;
+
+ public AsyncApiClient(ClientOptions clientOptions) {
+ this.clientOptions = clientOptions;
+ this.authenticationClient = Suppliers.memoize(() -> new AsyncAuthenticationClient(clientOptions));
+ }
+
+ public AsyncAuthenticationClient authentication() {
+ return this.authenticationClient.get();
+ }
+
+ public static AsyncApiClientBuilder builder() {
+ return new AsyncApiClientBuilder();
+ }
+}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/AsyncApiClientBuilder.java b/common/src/main/java/com/skyflow/generated/auth/rest/AsyncApiClientBuilder.java
new file mode 100644
index 00000000..2e30d45a
--- /dev/null
+++ b/common/src/main/java/com/skyflow/generated/auth/rest/AsyncApiClientBuilder.java
@@ -0,0 +1,67 @@
+/**
+ * This file was auto-generated by Fern from our API Definition.
+ */
+package com.skyflow.generated.auth.rest;
+
+import com.skyflow.generated.auth.rest.core.ClientOptions;
+import com.skyflow.generated.auth.rest.core.Environment;
+import okhttp3.OkHttpClient;
+
+public final class AsyncApiClientBuilder {
+ private ClientOptions.Builder clientOptionsBuilder = ClientOptions.builder();
+
+ private String token = null;
+
+ private Environment environment = Environment.PRODUCTION;
+
+ /**
+ * Sets token
+ */
+ public AsyncApiClientBuilder token(String token) {
+ this.token = token;
+ return this;
+ }
+
+ public AsyncApiClientBuilder environment(Environment environment) {
+ this.environment = environment;
+ return this;
+ }
+
+ public AsyncApiClientBuilder url(String url) {
+ this.environment = Environment.custom(url);
+ return this;
+ }
+
+ /**
+ * Sets the timeout (in seconds) for the client. Defaults to 60 seconds.
+ */
+ public AsyncApiClientBuilder timeout(int timeout) {
+ this.clientOptionsBuilder.timeout(timeout);
+ return this;
+ }
+
+ /**
+ * Sets the maximum number of retries for the client. Defaults to 2 retries.
+ */
+ public AsyncApiClientBuilder maxRetries(int maxRetries) {
+ this.clientOptionsBuilder.maxRetries(maxRetries);
+ return this;
+ }
+
+ /**
+ * Sets the underlying OkHttp client
+ */
+ public AsyncApiClientBuilder httpClient(OkHttpClient httpClient) {
+ this.clientOptionsBuilder.httpClient(httpClient);
+ return this;
+ }
+
+ public AsyncApiClient build() {
+ if (token == null) {
+ throw new RuntimeException("Please provide token");
+ }
+ this.clientOptionsBuilder.addHeader("Authorization", "Bearer " + this.token);
+ clientOptionsBuilder.environment(this.environment);
+ return new AsyncApiClient(clientOptionsBuilder.build());
+ }
+}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/ApiClientApiException.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/ApiClientApiException.java
new file mode 100644
index 00000000..53d67f0b
--- /dev/null
+++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/ApiClientApiException.java
@@ -0,0 +1,74 @@
+/**
+ * This file was auto-generated by Fern from our API Definition.
+ */
+package com.skyflow.generated.auth.rest.core;
+
+import okhttp3.Response;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This exception type will be thrown for any non-2XX API responses.
+ */
+public class ApiClientApiException extends ApiClientException {
+ /**
+ * The error code of the response that triggered the exception.
+ */
+ private final int statusCode;
+
+ /**
+ * The body of the response that triggered the exception.
+ */
+ private final Object body;
+
+ private final Map> headers;
+
+ public ApiClientApiException(String message, int statusCode, Object body) {
+ super(message);
+ this.statusCode = statusCode;
+ this.body = body;
+ this.headers = new HashMap<>();
+ }
+
+ public ApiClientApiException(String message, int statusCode, Object body, Response rawResponse) {
+ super(message);
+ this.statusCode = statusCode;
+ this.body = body;
+ this.headers = new HashMap<>();
+ rawResponse.headers().forEach(header -> {
+ String key = header.component1();
+ String value = header.component2();
+ this.headers.computeIfAbsent(key, _str -> new ArrayList<>()).add(value);
+ });
+ }
+
+ /**
+ * @return the statusCode
+ */
+ public int statusCode() {
+ return this.statusCode;
+ }
+
+ /**
+ * @return the body
+ */
+ public Object body() {
+ return this.body;
+ }
+
+ /**
+ * @return the headers
+ */
+ public Map> headers() {
+ return this.headers;
+ }
+
+ @Override
+ public String toString() {
+ return "ApiClientApiException{" + "message: " + getMessage() + ", statusCode: " + statusCode + ", body: " + body
+ + "}";
+ }
+}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/ApiClientException.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/ApiClientException.java
new file mode 100644
index 00000000..f08afa2e
--- /dev/null
+++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/ApiClientException.java
@@ -0,0 +1,17 @@
+/**
+ * This file was auto-generated by Fern from our API Definition.
+ */
+package com.skyflow.generated.auth.rest.core;
+
+/**
+ * This class serves as the base exception for all errors in the SDK.
+ */
+public class ApiClientException extends RuntimeException {
+ public ApiClientException(String message) {
+ super(message);
+ }
+
+ public ApiClientException(String message, Exception e) {
+ super(message, e);
+ }
+}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/ApiClientHttpResponse.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/ApiClientHttpResponse.java
new file mode 100644
index 00000000..8a28d22f
--- /dev/null
+++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/ApiClientHttpResponse.java
@@ -0,0 +1,38 @@
+/**
+ * This file was auto-generated by Fern from our API Definition.
+ */
+package com.skyflow.generated.auth.rest.core;
+
+import okhttp3.Response;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public final class ApiClientHttpResponse {
+
+ private final T body;
+
+ private final Map> headers;
+
+ public ApiClientHttpResponse(T body, Response rawResponse) {
+ this.body = body;
+
+ Map> headers = new HashMap<>();
+ rawResponse.headers().forEach(header -> {
+ String key = header.component1();
+ String value = header.component2();
+ headers.computeIfAbsent(key, _str -> new ArrayList<>()).add(value);
+ });
+ this.headers = headers;
+ }
+
+ public T body() {
+ return this.body;
+ }
+
+ public Map> headers() {
+ return headers;
+ }
+}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/ClientOptions.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/ClientOptions.java
new file mode 100644
index 00000000..4eee6b92
--- /dev/null
+++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/ClientOptions.java
@@ -0,0 +1,171 @@
+/**
+ * This file was auto-generated by Fern from our API Definition.
+ */
+package com.skyflow.generated.auth.rest.core;
+
+import okhttp3.OkHttpClient;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Supplier;
+
+public final class ClientOptions {
+ private final Environment environment;
+
+ private final Map headers;
+
+ private final Map> headerSuppliers;
+
+ private final OkHttpClient httpClient;
+
+ private final int timeout;
+
+ private ClientOptions(
+ Environment environment,
+ Map headers,
+ Map> headerSuppliers,
+ OkHttpClient httpClient,
+ int timeout) {
+ this.environment = environment;
+ this.headers = new HashMap<>();
+ this.headers.putAll(headers);
+ this.headers.putAll(new HashMap() {
+ {
+ put("X-Fern-Language", "JAVA");
+ put("X-Fern-SDK-Name", "com.skyflow.generated.rest.fern:api-sdk");
+ put("X-Fern-SDK-Version", "0.0.279");
+ }
+ });
+ this.headerSuppliers = headerSuppliers;
+ this.httpClient = httpClient;
+ this.timeout = timeout;
+ }
+
+ public Environment environment() {
+ return this.environment;
+ }
+
+ public Map headers(RequestOptions requestOptions) {
+ Map values = new HashMap<>(this.headers);
+ headerSuppliers.forEach((key, supplier) -> {
+ values.put(key, supplier.get());
+ });
+ if (requestOptions != null) {
+ values.putAll(requestOptions.getHeaders());
+ }
+ return values;
+ }
+
+ public int timeout(RequestOptions requestOptions) {
+ if (requestOptions == null) {
+ return this.timeout;
+ }
+ return requestOptions.getTimeout().orElse(this.timeout);
+ }
+
+ public OkHttpClient httpClient() {
+ return this.httpClient;
+ }
+
+ public OkHttpClient httpClientWithTimeout(RequestOptions requestOptions) {
+ if (requestOptions == null) {
+ return this.httpClient;
+ }
+ return this.httpClient
+ .newBuilder()
+ .callTimeout(requestOptions.getTimeout().get(), requestOptions.getTimeoutTimeUnit())
+ .connectTimeout(0, TimeUnit.SECONDS)
+ .writeTimeout(0, TimeUnit.SECONDS)
+ .readTimeout(0, TimeUnit.SECONDS)
+ .build();
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static final class Builder {
+ private Environment environment;
+
+ private final Map headers = new HashMap<>();
+
+ private final Map> headerSuppliers = new HashMap<>();
+
+ private int maxRetries = 2;
+
+ private Optional timeout = Optional.empty();
+
+ private OkHttpClient httpClient = null;
+
+ public Builder environment(Environment environment) {
+ this.environment = environment;
+ return this;
+ }
+
+ public Builder addHeader(String key, String value) {
+ this.headers.put(key, value);
+ return this;
+ }
+
+ public Builder addHeader(String key, Supplier value) {
+ this.headerSuppliers.put(key, value);
+ return this;
+ }
+
+ /**
+ * Override the timeout in seconds. Defaults to 60 seconds.
+ */
+ public Builder timeout(int timeout) {
+ this.timeout = Optional.of(timeout);
+ return this;
+ }
+
+ /**
+ * Override the timeout in seconds. Defaults to 60 seconds.
+ */
+ public Builder timeout(Optional timeout) {
+ this.timeout = timeout;
+ return this;
+ }
+
+ /**
+ * Override the maximum number of retries. Defaults to 2 retries.
+ */
+ public Builder maxRetries(int maxRetries) {
+ this.maxRetries = maxRetries;
+ return this;
+ }
+
+ public Builder httpClient(OkHttpClient httpClient) {
+ this.httpClient = httpClient;
+ return this;
+ }
+
+ public ClientOptions build() {
+ OkHttpClient.Builder httpClientBuilder =
+ this.httpClient != null ? this.httpClient.newBuilder() : new OkHttpClient.Builder();
+
+ if (this.httpClient != null) {
+ timeout.ifPresent(timeout -> httpClientBuilder
+ .callTimeout(timeout, TimeUnit.SECONDS)
+ .connectTimeout(0, TimeUnit.SECONDS)
+ .writeTimeout(0, TimeUnit.SECONDS)
+ .readTimeout(0, TimeUnit.SECONDS));
+ } else {
+ httpClientBuilder
+ .callTimeout(this.timeout.orElse(60), TimeUnit.SECONDS)
+ .connectTimeout(0, TimeUnit.SECONDS)
+ .writeTimeout(0, TimeUnit.SECONDS)
+ .readTimeout(0, TimeUnit.SECONDS)
+ .addInterceptor(new RetryInterceptor(this.maxRetries));
+ }
+
+ this.httpClient = httpClientBuilder.build();
+ this.timeout = Optional.of(httpClient.callTimeoutMillis() / 1000);
+
+ return new ClientOptions(environment, headers, headerSuppliers, httpClient, this.timeout.get());
+ }
+ }
+}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/DateTimeDeserializer.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/DateTimeDeserializer.java
new file mode 100644
index 00000000..dfa25a82
--- /dev/null
+++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/DateTimeDeserializer.java
@@ -0,0 +1,56 @@
+/**
+ * This file was auto-generated by Fern from our API Definition.
+ */
+package com.skyflow.generated.auth.rest.core;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+
+import java.io.IOException;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.OffsetDateTime;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalQueries;
+
+/**
+ * Custom deserializer that handles converting ISO8601 dates into {@link OffsetDateTime} objects.
+ */
+class DateTimeDeserializer extends JsonDeserializer {
+ private static final SimpleModule MODULE;
+
+ static {
+ MODULE = new SimpleModule().addDeserializer(OffsetDateTime.class, new DateTimeDeserializer());
+ }
+
+ /**
+ * Gets a module wrapping this deserializer as an adapter for the Jackson ObjectMapper.
+ *
+ * @return A {@link SimpleModule} to be plugged onto Jackson ObjectMapper.
+ */
+ public static SimpleModule getModule() {
+ return MODULE;
+ }
+
+ @Override
+ public OffsetDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException {
+ JsonToken token = parser.currentToken();
+ if (token == JsonToken.VALUE_NUMBER_INT) {
+ return OffsetDateTime.ofInstant(Instant.ofEpochSecond(parser.getValueAsLong()), ZoneOffset.UTC);
+ } else {
+ TemporalAccessor temporal = DateTimeFormatter.ISO_DATE_TIME.parseBest(
+ parser.getValueAsString(), OffsetDateTime::from, LocalDateTime::from);
+
+ if (temporal.query(TemporalQueries.offset()) == null) {
+ return LocalDateTime.from(temporal).atOffset(ZoneOffset.UTC);
+ } else {
+ return OffsetDateTime.from(temporal);
+ }
+ }
+ }
+}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/Environment.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/Environment.java
new file mode 100644
index 00000000..098667c0
--- /dev/null
+++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/Environment.java
@@ -0,0 +1,24 @@
+/**
+ * This file was auto-generated by Fern from our API Definition.
+ */
+package com.skyflow.generated.auth.rest.core;
+
+public final class Environment {
+ public static final Environment PRODUCTION = new Environment("https://manage.skyflowapis.com");
+
+ public static final Environment SANDBOX = new Environment("https://manage.skyflowapis-preview.com");
+
+ private final String url;
+
+ private Environment(String url) {
+ this.url = url;
+ }
+
+ public String getUrl() {
+ return this.url;
+ }
+
+ public static Environment custom(String url) {
+ return new Environment(url);
+ }
+}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/FileStream.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/FileStream.java
new file mode 100644
index 00000000..0e878ed3
--- /dev/null
+++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/FileStream.java
@@ -0,0 +1,61 @@
+/**
+ * This file was auto-generated by Fern from our API Definition.
+ */
+package com.skyflow.generated.auth.rest.core;
+
+import okhttp3.MediaType;
+import okhttp3.RequestBody;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.InputStream;
+import java.util.Objects;
+
+/**
+ * Represents a file stream with associated metadata for file uploads.
+ */
+public class FileStream {
+ private final InputStream inputStream;
+ private final String fileName;
+ private final MediaType contentType;
+
+ /**
+ * Constructs a FileStream with the given input stream and optional metadata.
+ *
+ * @param inputStream The input stream of the file content. Must not be null.
+ * @param fileName The name of the file, or null if unknown.
+ * @param contentType The MIME type of the file content, or null if unknown.
+ * @throws NullPointerException if inputStream is null
+ */
+ public FileStream(InputStream inputStream, @Nullable String fileName, @Nullable MediaType contentType) {
+ this.inputStream = Objects.requireNonNull(inputStream, "Input stream cannot be null");
+ this.fileName = fileName;
+ this.contentType = contentType;
+ }
+
+ public FileStream(InputStream inputStream) {
+ this(inputStream, null, null);
+ }
+
+ public InputStream getInputStream() {
+ return inputStream;
+ }
+
+ @Nullable
+ public String getFileName() {
+ return fileName;
+ }
+
+ @Nullable
+ public MediaType getContentType() {
+ return contentType;
+ }
+
+ /**
+ * Creates a RequestBody suitable for use with OkHttp client.
+ *
+ * @return A RequestBody instance representing this file stream.
+ */
+ public RequestBody toRequestBody() {
+ return new InputStreamRequestBody(contentType, inputStream);
+ }
+}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/InputStreamRequestBody.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/InputStreamRequestBody.java
new file mode 100644
index 00000000..a94faec9
--- /dev/null
+++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/InputStreamRequestBody.java
@@ -0,0 +1,80 @@
+/**
+ * This file was auto-generated by Fern from our API Definition.
+ */
+package com.skyflow.generated.auth.rest.core;
+
+import okhttp3.MediaType;
+import okhttp3.RequestBody;
+import okhttp3.internal.Util;
+import okio.BufferedSink;
+import okio.Okio;
+import okio.Source;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Objects;
+
+/**
+ * A custom implementation of OkHttp's RequestBody that wraps an InputStream.
+ * This class allows streaming of data from an InputStream directly to an HTTP request body,
+ * which is useful for file uploads or sending large amounts of data without loading it all into memory.
+ */
+public class InputStreamRequestBody extends RequestBody {
+ private final InputStream inputStream;
+ private final MediaType contentType;
+
+ /**
+ * Constructs an InputStreamRequestBody with the specified content type and input stream.
+ *
+ * @param contentType the MediaType of the content, or null if not known
+ * @param inputStream the InputStream containing the data to be sent
+ * @throws NullPointerException if inputStream is null
+ */
+ public InputStreamRequestBody(@Nullable MediaType contentType, InputStream inputStream) {
+ this.contentType = contentType;
+ this.inputStream = Objects.requireNonNull(inputStream, "inputStream == null");
+ }
+
+ /**
+ * Returns the content type of this request body.
+ *
+ * @return the MediaType of the content, or null if not specified
+ */
+ @Nullable
+ @Override
+ public MediaType contentType() {
+ return contentType;
+ }
+
+ /**
+ * Returns the content length of this request body, if known.
+ * This method attempts to determine the length using the InputStream's available() method,
+ * which may not always accurately reflect the total length of the stream.
+ *
+ * @return the content length, or -1 if the length is unknown
+ * @throws IOException if an I/O error occurs
+ */
+ @Override
+ public long contentLength() throws IOException {
+ return inputStream.available() == 0 ? -1 : inputStream.available();
+ }
+
+ /**
+ * Writes the content of the InputStream to the given BufferedSink.
+ * This method is responsible for transferring the data from the InputStream to the network request.
+ *
+ * @param sink the BufferedSink to write the content to
+ * @throws IOException if an I/O error occurs during writing
+ */
+ @Override
+ public void writeTo(BufferedSink sink) throws IOException {
+ Source source = null;
+ try {
+ source = Okio.source(inputStream);
+ sink.writeAll(source);
+ } finally {
+ Util.closeQuietly(Objects.requireNonNull(source));
+ }
+ }
+}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/MediaTypes.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/MediaTypes.java
new file mode 100644
index 00000000..d4374647
--- /dev/null
+++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/MediaTypes.java
@@ -0,0 +1,13 @@
+/**
+ * This file was auto-generated by Fern from our API Definition.
+ */
+package com.skyflow.generated.auth.rest.core;
+
+import okhttp3.MediaType;
+
+public final class MediaTypes {
+
+ public static final MediaType APPLICATION_JSON = MediaType.parse("application/json");
+
+ private MediaTypes() {}
+}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/Nullable.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/Nullable.java
new file mode 100644
index 00000000..efabe806
--- /dev/null
+++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/Nullable.java
@@ -0,0 +1,140 @@
+/**
+ * This file was auto-generated by Fern from our API Definition.
+ */
+package com.skyflow.generated.auth.rest.core;
+
+import java.util.Optional;
+import java.util.function.Function;
+
+public final class Nullable {
+
+ private final Either, Null> value;
+
+ private Nullable() {
+ this.value = Either.left(Optional.empty());
+ }
+
+ private Nullable(T value) {
+ if (value == null) {
+ this.value = Either.right(Null.INSTANCE);
+ } else {
+ this.value = Either.left(Optional.of(value));
+ }
+ }
+
+ public static Nullable ofNull() {
+ return new Nullable<>(null);
+ }
+
+ public static Nullable of(T value) {
+ return new Nullable<>(value);
+ }
+
+ public static Nullable empty() {
+ return new Nullable<>();
+ }
+
+ public static Nullable ofOptional(Optional value) {
+ if (value.isPresent()) {
+ return of(value.get());
+ } else {
+ return empty();
+ }
+ }
+
+ public boolean isNull() {
+ return this.value.isRight();
+ }
+
+ public boolean isEmpty() {
+ return this.value.isLeft() && !this.value.getLeft().isPresent();
+ }
+
+ public T get() {
+ if (this.isNull()) {
+ return null;
+ }
+
+ return this.value.getLeft().get();
+ }
+
+ public Nullable map(Function super T, ? extends U> mapper) {
+ if (this.isNull()) {
+ return Nullable.ofNull();
+ }
+
+ return Nullable.ofOptional(this.value.getLeft().map(mapper));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof Nullable)) {
+ return false;
+ }
+
+ if (((Nullable>) other).isNull() && this.isNull()) {
+ return true;
+ }
+
+ return this.value.getLeft().equals(((Nullable>) other).value.getLeft());
+ }
+
+ private static final class Either {
+ private L left = null;
+ private R right = null;
+
+ private Either(L left, R right) {
+ if (left != null && right != null) {
+ throw new IllegalArgumentException("Left and right argument cannot both be non-null.");
+ }
+
+ if (left == null && right == null) {
+ throw new IllegalArgumentException("Left and right argument cannot both be null.");
+ }
+
+ if (left != null) {
+ this.left = left;
+ }
+
+ if (right != null) {
+ this.right = right;
+ }
+ }
+
+ public static Either left(L left) {
+ return new Either<>(left, null);
+ }
+
+ public static Either right(R right) {
+ return new Either<>(null, right);
+ }
+
+ public boolean isLeft() {
+ return this.left != null;
+ }
+
+ public boolean isRight() {
+ return this.right != null;
+ }
+
+ public L getLeft() {
+ if (!this.isLeft()) {
+ throw new IllegalArgumentException("Cannot get left from right Either.");
+ }
+ return this.left;
+ }
+
+ public R getRight() {
+ if (!this.isRight()) {
+ throw new IllegalArgumentException("Cannot get right from left Either.");
+ }
+ return this.right;
+ }
+ }
+
+ private static final class Null {
+ private static final Null INSTANCE = new Null();
+
+ private Null() {}
+ }
+}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/NullableNonemptyFilter.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/NullableNonemptyFilter.java
new file mode 100644
index 00000000..dd32d66c
--- /dev/null
+++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/NullableNonemptyFilter.java
@@ -0,0 +1,19 @@
+/**
+ * This file was auto-generated by Fern from our API Definition.
+ */
+package com.skyflow.generated.auth.rest.core;
+
+import java.util.Optional;
+
+public final class NullableNonemptyFilter {
+ @Override
+ public boolean equals(Object o) {
+ boolean isOptionalEmpty = isOptionalEmpty(o);
+
+ return isOptionalEmpty;
+ }
+
+ private boolean isOptionalEmpty(Object o) {
+ return o instanceof Optional && !((Optional>) o).isPresent();
+ }
+}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/ObjectMappers.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/ObjectMappers.java
new file mode 100644
index 00000000..4997b3ca
--- /dev/null
+++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/ObjectMappers.java
@@ -0,0 +1,37 @@
+/**
+ * This file was auto-generated by Fern from our API Definition.
+ */
+package com.skyflow.generated.auth.rest.core;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.json.JsonMapper;
+import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+
+import java.io.IOException;
+
+public final class ObjectMappers {
+ public static final ObjectMapper JSON_MAPPER = JsonMapper.builder()
+ .addModule(new Jdk8Module())
+ .addModule(new JavaTimeModule())
+ .addModule(DateTimeDeserializer.getModule())
+ .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
+ .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
+ .build();
+
+ private ObjectMappers() {}
+
+ public static String stringify(Object o) {
+ try {
+ return JSON_MAPPER
+ .setSerializationInclusion(JsonInclude.Include.ALWAYS)
+ .writerWithDefaultPrettyPrinter()
+ .writeValueAsString(o);
+ } catch (IOException e) {
+ return o.getClass().getName() + "@" + Integer.toHexString(o.hashCode());
+ }
+ }
+}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/QueryStringMapper.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/QueryStringMapper.java
new file mode 100644
index 00000000..8b1f9f7e
--- /dev/null
+++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/QueryStringMapper.java
@@ -0,0 +1,139 @@
+/**
+ * This file was auto-generated by Fern from our API Definition.
+ */
+package com.skyflow.generated.auth.rest.core;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import okhttp3.HttpUrl;
+import okhttp3.MultipartBody;
+
+import java.util.*;
+
+public class QueryStringMapper {
+
+ private static final ObjectMapper MAPPER = ObjectMappers.JSON_MAPPER;
+
+ public static void addQueryParameter(HttpUrl.Builder httpUrl, String key, Object value, boolean arraysAsRepeats) {
+ JsonNode valueNode = MAPPER.valueToTree(value);
+
+ List> flat;
+ if (valueNode.isObject()) {
+ flat = flattenObject((ObjectNode) valueNode, arraysAsRepeats);
+ } else if (valueNode.isArray()) {
+ flat = flattenArray((ArrayNode) valueNode, "", arraysAsRepeats);
+ } else {
+ if (valueNode.isTextual()) {
+ httpUrl.addQueryParameter(key, valueNode.textValue());
+ } else {
+ httpUrl.addQueryParameter(key, valueNode.toString());
+ }
+ return;
+ }
+
+ for (Map.Entry field : flat) {
+ if (field.getValue().isTextual()) {
+ httpUrl.addQueryParameter(key + field.getKey(), field.getValue().textValue());
+ } else {
+ httpUrl.addQueryParameter(key + field.getKey(), field.getValue().toString());
+ }
+ }
+ }
+
+ public static void addFormDataPart(
+ MultipartBody.Builder multipartBody, String key, Object value, boolean arraysAsRepeats) {
+ JsonNode valueNode = MAPPER.valueToTree(value);
+
+ List> flat;
+ if (valueNode.isObject()) {
+ flat = flattenObject((ObjectNode) valueNode, arraysAsRepeats);
+ } else if (valueNode.isArray()) {
+ flat = flattenArray((ArrayNode) valueNode, "", arraysAsRepeats);
+ } else {
+ if (valueNode.isTextual()) {
+ multipartBody.addFormDataPart(key, valueNode.textValue());
+ } else {
+ multipartBody.addFormDataPart(key, valueNode.toString());
+ }
+ return;
+ }
+
+ for (Map.Entry field : flat) {
+ if (field.getValue().isTextual()) {
+ multipartBody.addFormDataPart(
+ key + field.getKey(), field.getValue().textValue());
+ } else {
+ multipartBody.addFormDataPart(
+ key + field.getKey(), field.getValue().toString());
+ }
+ }
+ }
+
+ public static List> flattenObject(ObjectNode object, boolean arraysAsRepeats) {
+ List> flat = new ArrayList<>();
+
+ Iterator> fields = object.fields();
+ while (fields.hasNext()) {
+ Map.Entry field = fields.next();
+
+ String key = "[" + field.getKey() + "]";
+
+ if (field.getValue().isObject()) {
+ List> flatField =
+ flattenObject((ObjectNode) field.getValue(), arraysAsRepeats);
+ addAll(flat, flatField, key);
+ } else if (field.getValue().isArray()) {
+ List> flatField =
+ flattenArray((ArrayNode) field.getValue(), key, arraysAsRepeats);
+ addAll(flat, flatField, "");
+ } else {
+ flat.add(new AbstractMap.SimpleEntry<>(key, field.getValue()));
+ }
+ }
+
+ return flat;
+ }
+
+ private static List> flattenArray(
+ ArrayNode array, String key, boolean arraysAsRepeats) {
+ List> flat = new ArrayList<>();
+
+ Iterator elements = array.elements();
+
+ int index = 0;
+ while (elements.hasNext()) {
+ JsonNode element = elements.next();
+
+ String indexKey = key + "[" + index + "]";
+
+ if (arraysAsRepeats) {
+ indexKey = key;
+ }
+
+ if (element.isObject()) {
+ List> flatField = flattenObject((ObjectNode) element, arraysAsRepeats);
+ addAll(flat, flatField, indexKey);
+ } else if (element.isArray()) {
+ List> flatField = flattenArray((ArrayNode) element, "", arraysAsRepeats);
+ addAll(flat, flatField, indexKey);
+ } else {
+ flat.add(new AbstractMap.SimpleEntry<>(indexKey, element));
+ }
+
+ index++;
+ }
+
+ return flat;
+ }
+
+ private static void addAll(
+ List> target, List> source, String prefix) {
+ for (Map.Entry entry : source) {
+ Map.Entry entryToAdd =
+ new AbstractMap.SimpleEntry<>(prefix + entry.getKey(), entry.getValue());
+ target.add(entryToAdd);
+ }
+ }
+}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/RequestOptions.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/RequestOptions.java
new file mode 100644
index 00000000..b70c02df
--- /dev/null
+++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/RequestOptions.java
@@ -0,0 +1,101 @@
+/**
+ * This file was auto-generated by Fern from our API Definition.
+ */
+package com.skyflow.generated.auth.rest.core;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Supplier;
+
+public final class RequestOptions {
+ private final String token;
+
+ private final Optional timeout;
+
+ private final TimeUnit timeoutTimeUnit;
+
+ private final Map headers;
+
+ private final Map> headerSuppliers;
+
+ private RequestOptions(
+ String token,
+ Optional timeout,
+ TimeUnit timeoutTimeUnit,
+ Map headers,
+ Map> headerSuppliers) {
+ this.token = token;
+ this.timeout = timeout;
+ this.timeoutTimeUnit = timeoutTimeUnit;
+ this.headers = headers;
+ this.headerSuppliers = headerSuppliers;
+ }
+
+ public Optional getTimeout() {
+ return timeout;
+ }
+
+ public TimeUnit getTimeoutTimeUnit() {
+ return timeoutTimeUnit;
+ }
+
+ public Map getHeaders() {
+ Map headers = new HashMap<>();
+ if (this.token != null) {
+ headers.put("Authorization", "Bearer " + this.token);
+ }
+ headers.putAll(this.headers);
+ this.headerSuppliers.forEach((key, supplier) -> {
+ headers.put(key, supplier.get());
+ });
+ return headers;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static final class Builder {
+ private String token = null;
+
+ private Optional timeout = Optional.empty();
+
+ private TimeUnit timeoutTimeUnit = TimeUnit.SECONDS;
+
+ private final Map headers = new HashMap<>();
+
+ private final Map> headerSuppliers = new HashMap<>();
+
+ public Builder token(String token) {
+ this.token = token;
+ return this;
+ }
+
+ public Builder timeout(Integer timeout) {
+ this.timeout = Optional.of(timeout);
+ return this;
+ }
+
+ public Builder timeout(Integer timeout, TimeUnit timeoutTimeUnit) {
+ this.timeout = Optional.of(timeout);
+ this.timeoutTimeUnit = timeoutTimeUnit;
+ return this;
+ }
+
+ public Builder addHeader(String key, String value) {
+ this.headers.put(key, value);
+ return this;
+ }
+
+ public Builder addHeader(String key, Supplier value) {
+ this.headerSuppliers.put(key, value);
+ return this;
+ }
+
+ public RequestOptions build() {
+ return new RequestOptions(token, timeout, timeoutTimeUnit, headers, headerSuppliers);
+ }
+ }
+}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/ResponseBodyInputStream.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/ResponseBodyInputStream.java
new file mode 100644
index 00000000..1d0a9110
--- /dev/null
+++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/ResponseBodyInputStream.java
@@ -0,0 +1,46 @@
+/**
+ * This file was auto-generated by Fern from our API Definition.
+ */
+package com.skyflow.generated.auth.rest.core;
+
+import okhttp3.Response;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+
+/**
+ * A custom InputStream that wraps the InputStream from the OkHttp Response and ensures that the
+ * OkHttp Response object is properly closed when the stream is closed.
+ *
+ * This class extends FilterInputStream and takes an OkHttp Response object as a parameter.
+ * It retrieves the InputStream from the Response and overrides the close method to close
+ * both the InputStream and the Response object, ensuring proper resource management and preventing
+ * premature closure of the underlying HTTP connection.
+ */
+public class ResponseBodyInputStream extends FilterInputStream {
+ private final Response response;
+
+ /**
+ * Constructs a ResponseBodyInputStream that wraps the InputStream from the given OkHttp
+ * Response object.
+ *
+ * @param response the OkHttp Response object from which the InputStream is retrieved
+ * @throws IOException if an I/O error occurs while retrieving the InputStream
+ */
+ public ResponseBodyInputStream(Response response) throws IOException {
+ super(response.body().byteStream());
+ this.response = response;
+ }
+
+ /**
+ * Closes the InputStream and the associated OkHttp Response object. This ensures that the
+ * underlying HTTP connection is properly closed after the stream is no longer needed.
+ *
+ * @throws IOException if an I/O error occurs
+ */
+ @Override
+ public void close() throws IOException {
+ super.close();
+ response.close(); // Ensure the response is closed when the stream is closed
+ }
+}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/ResponseBodyReader.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/ResponseBodyReader.java
new file mode 100644
index 00000000..f4dfb17b
--- /dev/null
+++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/ResponseBodyReader.java
@@ -0,0 +1,45 @@
+/**
+ * This file was auto-generated by Fern from our API Definition.
+ */
+package com.skyflow.generated.auth.rest.core;
+
+import okhttp3.Response;
+
+import java.io.FilterReader;
+import java.io.IOException;
+
+/**
+ * A custom Reader that wraps the Reader from the OkHttp Response and ensures that the
+ * OkHttp Response object is properly closed when the reader is closed.
+ *
+ * This class extends FilterReader and takes an OkHttp Response object as a parameter.
+ * It retrieves the Reader from the Response and overrides the close method to close
+ * both the Reader and the Response object, ensuring proper resource management and preventing
+ * premature closure of the underlying HTTP connection.
+ */
+public class ResponseBodyReader extends FilterReader {
+ private final Response response;
+
+ /**
+ * Constructs a ResponseBodyReader that wraps the Reader from the given OkHttp Response object.
+ *
+ * @param response the OkHttp Response object from which the Reader is retrieved
+ * @throws IOException if an I/O error occurs while retrieving the Reader
+ */
+ public ResponseBodyReader(Response response) throws IOException {
+ super(response.body().charStream());
+ this.response = response;
+ }
+
+ /**
+ * Closes the Reader and the associated OkHttp Response object. This ensures that the
+ * underlying HTTP connection is properly closed after the reader is no longer needed.
+ *
+ * @throws IOException if an I/O error occurs
+ */
+ @Override
+ public void close() throws IOException {
+ super.close();
+ response.close(); // Ensure the response is closed when the reader is closed
+ }
+}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/RetryInterceptor.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/RetryInterceptor.java
new file mode 100644
index 00000000..8344b974
--- /dev/null
+++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/RetryInterceptor.java
@@ -0,0 +1,79 @@
+/**
+ * This file was auto-generated by Fern from our API Definition.
+ */
+package com.skyflow.generated.auth.rest.core;
+
+import okhttp3.Interceptor;
+import okhttp3.Response;
+
+import java.io.IOException;
+import java.time.Duration;
+import java.util.Optional;
+import java.util.Random;
+
+public class RetryInterceptor implements Interceptor {
+
+ private static final Duration ONE_SECOND = Duration.ofSeconds(1);
+ private final ExponentialBackoff backoff;
+ private final Random random = new Random();
+
+ public RetryInterceptor(int maxRetries) {
+ this.backoff = new ExponentialBackoff(maxRetries);
+ }
+
+ @Override
+ public Response intercept(Chain chain) throws IOException {
+ Response response = chain.proceed(chain.request());
+
+ if (shouldRetry(response.code())) {
+ return retryChain(response, chain);
+ }
+
+ return response;
+ }
+
+ private Response retryChain(Response response, Chain chain) throws IOException {
+ Optional nextBackoff = this.backoff.nextBackoff();
+ while (nextBackoff.isPresent()) {
+ try {
+ Thread.sleep(nextBackoff.get().toMillis());
+ } catch (InterruptedException e) {
+ throw new IOException("Interrupted while trying request", e);
+ }
+ response.close();
+ response = chain.proceed(chain.request());
+ if (shouldRetry(response.code())) {
+ nextBackoff = this.backoff.nextBackoff();
+ } else {
+ return response;
+ }
+ }
+
+ return response;
+ }
+
+ private static boolean shouldRetry(int statusCode) {
+ return statusCode == 408 || statusCode == 429 || statusCode >= 500;
+ }
+
+ private final class ExponentialBackoff {
+
+ private final int maxNumRetries;
+
+ private int retryNumber = 0;
+
+ ExponentialBackoff(int maxNumRetries) {
+ this.maxNumRetries = maxNumRetries;
+ }
+
+ public Optional nextBackoff() {
+ retryNumber += 1;
+ if (retryNumber > maxNumRetries) {
+ return Optional.empty();
+ }
+
+ int upperBound = (int) Math.pow(2, retryNumber);
+ return Optional.of(ONE_SECOND.multipliedBy(random.nextInt(upperBound)));
+ }
+ }
+}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/Stream.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/Stream.java
new file mode 100644
index 00000000..4a984faa
--- /dev/null
+++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/Stream.java
@@ -0,0 +1,97 @@
+/**
+ * This file was auto-generated by Fern from our API Definition.
+ */
+package com.skyflow.generated.auth.rest.core;
+
+import java.io.Reader;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Scanner;
+
+/**
+ * The {@code Stream} class implements {@link Iterable} to provide a simple mechanism for reading and parsing
+ * objects of a given type from data streamed via a {@link Reader} using a specified delimiter.
+ *
+ * {@code Stream} assumes that data is being pushed to the provided {@link Reader} asynchronously and utilizes a
+ * {@code Scanner} to block during iteration if the next object is not available.
+ *
+ * @param The type of objects in the stream.
+ */
+public final class Stream implements Iterable {
+ /**
+ * The {@link Class} of the objects in the stream.
+ */
+ private final Class valueType;
+ /**
+ * The {@link Scanner} used for reading from the input stream and blocking when needed during iteration.
+ */
+ private final Scanner scanner;
+
+ /**
+ * Constructs a new {@code Stream} with the specified value type, reader, and delimiter.
+ *
+ * @param valueType The class of the objects in the stream.
+ * @param reader The reader that provides the streamed data.
+ * @param delimiter The delimiter used to separate elements in the stream.
+ */
+ public Stream(Class valueType, Reader reader, String delimiter) {
+ this.scanner = new Scanner(reader).useDelimiter(delimiter);
+ this.valueType = valueType;
+ }
+
+ /**
+ * Returns an iterator over the elements in this stream that blocks during iteration when the next object is
+ * not yet available.
+ *
+ * @return An iterator that can be used to traverse the elements in the stream.
+ */
+ @Override
+ public Iterator iterator() {
+ return new Iterator() {
+ /**
+ * Returns {@code true} if there are more elements in the stream.
+ *
+ * Will block and wait for input if the stream has not ended and the next object is not yet available.
+ *
+ * @return {@code true} if there are more elements, {@code false} otherwise.
+ */
+ @Override
+ public boolean hasNext() {
+ return scanner.hasNext();
+ }
+
+ /**
+ * Returns the next element in the stream.
+ *
+ * Will block and wait for input if the stream has not ended and the next object is not yet available.
+ *
+ * @return The next element in the stream.
+ * @throws NoSuchElementException If there are no more elements in the stream.
+ */
+ @Override
+ public T next() {
+ if (!scanner.hasNext()) {
+ throw new NoSuchElementException();
+ } else {
+ try {
+ T parsedResponse = ObjectMappers.JSON_MAPPER.readValue(
+ scanner.next().trim(), valueType);
+ return parsedResponse;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ /**
+ * Removing elements from {@code Stream} is not supported.
+ *
+ * @throws UnsupportedOperationException Always, as removal is not supported.
+ */
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/core/Suppliers.java b/common/src/main/java/com/skyflow/generated/auth/rest/core/Suppliers.java
new file mode 100644
index 00000000..d3ab5e53
--- /dev/null
+++ b/common/src/main/java/com/skyflow/generated/auth/rest/core/Suppliers.java
@@ -0,0 +1,23 @@
+/**
+ * This file was auto-generated by Fern from our API Definition.
+ */
+package com.skyflow.generated.auth.rest.core;
+
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
+
+public final class Suppliers {
+ private Suppliers() {}
+
+ public static Supplier memoize(Supplier delegate) {
+ AtomicReference value = new AtomicReference<>();
+ return () -> {
+ T val = value.get();
+ if (val == null) {
+ val = value.updateAndGet(cur -> cur == null ? Objects.requireNonNull(delegate.get()) : cur);
+ }
+ return val;
+ };
+ }
+}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/errors/BadRequestError.java b/common/src/main/java/com/skyflow/generated/auth/rest/errors/BadRequestError.java
new file mode 100644
index 00000000..4517200d
--- /dev/null
+++ b/common/src/main/java/com/skyflow/generated/auth/rest/errors/BadRequestError.java
@@ -0,0 +1,34 @@
+/**
+ * This file was auto-generated by Fern from our API Definition.
+ */
+package com.skyflow.generated.auth.rest.errors;
+
+import com.skyflow.generated.auth.rest.core.ApiClientApiException;
+import okhttp3.Response;
+
+import java.util.Map;
+
+public final class BadRequestError extends ApiClientApiException {
+ /**
+ * The body of the response that triggered the exception.
+ */
+ private final Map body;
+
+ public BadRequestError(Map body) {
+ super("BadRequestError", 400, body);
+ this.body = body;
+ }
+
+ public BadRequestError(Map body, Response rawResponse) {
+ super("BadRequestError", 400, body, rawResponse);
+ this.body = body;
+ }
+
+ /**
+ * @return the body
+ */
+ @Override
+ public Map body() {
+ return this.body;
+ }
+}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/errors/HttpStatus.java b/common/src/main/java/com/skyflow/generated/auth/rest/errors/HttpStatus.java
new file mode 100644
index 00000000..2e1c45d2
--- /dev/null
+++ b/common/src/main/java/com/skyflow/generated/auth/rest/errors/HttpStatus.java
@@ -0,0 +1,15 @@
+package com.skyflow.generated.auth.rest.errors;
+
+public enum HttpStatus {
+ BAD_REQUEST("Bad Request");
+
+ private final String httpStatus;
+
+ HttpStatus(String httpStatus) {
+ this.httpStatus = httpStatus;
+ }
+
+ public String getHttpStatus() {
+ return httpStatus;
+ }
+}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/errors/NotFoundError.java b/common/src/main/java/com/skyflow/generated/auth/rest/errors/NotFoundError.java
new file mode 100644
index 00000000..60a1771c
--- /dev/null
+++ b/common/src/main/java/com/skyflow/generated/auth/rest/errors/NotFoundError.java
@@ -0,0 +1,34 @@
+/**
+ * This file was auto-generated by Fern from our API Definition.
+ */
+package com.skyflow.generated.auth.rest.errors;
+
+import com.skyflow.generated.auth.rest.core.ApiClientApiException;
+import okhttp3.Response;
+
+import java.util.Map;
+
+public final class NotFoundError extends ApiClientApiException {
+ /**
+ * The body of the response that triggered the exception.
+ */
+ private final Map body;
+
+ public NotFoundError(Map body) {
+ super("NotFoundError", 404, body);
+ this.body = body;
+ }
+
+ public NotFoundError(Map body, Response rawResponse) {
+ super("NotFoundError", 404, body, rawResponse);
+ this.body = body;
+ }
+
+ /**
+ * @return the body
+ */
+ @Override
+ public Map body() {
+ return this.body;
+ }
+}
diff --git a/common/src/main/java/com/skyflow/generated/auth/rest/errors/UnauthorizedError.java b/common/src/main/java/com/skyflow/generated/auth/rest/errors/UnauthorizedError.java
new file mode 100644
index 00000000..42f1c624
--- /dev/null
+++ b/common/src/main/java/com/skyflow/generated/auth/rest/errors/UnauthorizedError.java
@@ -0,0 +1,34 @@
+/**
+ * This file was auto-generated by Fern from our API Definition.
+ */
+package com.skyflow.generated.auth.rest.errors;
+
+import com.skyflow.generated.auth.rest.core.ApiClientApiException;
+import okhttp3.Response;
+
+import java.util.Map;
+
+public final class UnauthorizedError extends ApiClientApiException {
+ /**
+ * The body of the response that triggered the exception.
+ */
+ private final Map body;
+
+ public UnauthorizedError(Map body) {
+ super("UnauthorizedError", 401, body);
+ this.body = body;
+ }
+
+ public UnauthorizedError(Map body, Response rawResponse) {
+ super("UnauthorizedError", 401, body, rawResponse);
+ this.body = body;
+ }
+
+ /**
+ * @return the body
+ */
+ @Override
+ public Map body() {
+ return this.body;
+ }
+}
diff --git a/src/main/java/com/skyflow/generated/rest/resources/authentication/AsyncAuthenticationClient.java b/common/src/main/java/com/skyflow/generated/auth/rest/resources/authentication/AsyncAuthenticationClient.java
similarity index 84%
rename from src/main/java/com/skyflow/generated/rest/resources/authentication/AsyncAuthenticationClient.java
rename to common/src/main/java/com/skyflow/generated/auth/rest/resources/authentication/AsyncAuthenticationClient.java
index 43ffab73..c742b239 100644
--- a/src/main/java/com/skyflow/generated/rest/resources/authentication/AsyncAuthenticationClient.java
+++ b/common/src/main/java/com/skyflow/generated/auth/rest/resources/authentication/AsyncAuthenticationClient.java
@@ -1,12 +1,13 @@
/**
* This file was auto-generated by Fern from our API Definition.
*/
-package com.skyflow.generated.rest.resources.authentication;
+package com.skyflow.generated.auth.rest.resources.authentication;
+
+import com.skyflow.generated.auth.rest.core.ClientOptions;
+import com.skyflow.generated.auth.rest.core.RequestOptions;
+import com.skyflow.generated.auth.rest.resources.authentication.requests.V1GetAuthTokenRequest;
+import com.skyflow.generated.auth.rest.types.V1GetAuthTokenResponse;
-import com.skyflow.generated.rest.core.ClientOptions;
-import com.skyflow.generated.rest.core.RequestOptions;
-import com.skyflow.generated.rest.resources.authentication.requests.V1GetAuthTokenRequest;
-import com.skyflow.generated.rest.types.V1GetAuthTokenResponse;
import java.util.concurrent.CompletableFuture;
public class AsyncAuthenticationClient {
diff --git a/src/main/java/com/skyflow/generated/rest/resources/authentication/AsyncRawAuthenticationClient.java b/common/src/main/java/com/skyflow/generated/auth/rest/resources/authentication/AsyncRawAuthenticationClient.java
similarity index 82%
rename from src/main/java/com/skyflow/generated/rest/resources/authentication/AsyncRawAuthenticationClient.java
rename to common/src/main/java/com/skyflow/generated/auth/rest/resources/authentication/AsyncRawAuthenticationClient.java
index eca4ab90..56a47dc0 100644
--- a/src/main/java/com/skyflow/generated/rest/resources/authentication/AsyncRawAuthenticationClient.java
+++ b/common/src/main/java/com/skyflow/generated/auth/rest/resources/authentication/AsyncRawAuthenticationClient.java
@@ -1,33 +1,22 @@
/**
* This file was auto-generated by Fern from our API Definition.
*/
-package com.skyflow.generated.rest.resources.authentication;
+package com.skyflow.generated.auth.rest.resources.authentication;
import com.fasterxml.jackson.core.JsonProcessingException;
-import com.skyflow.generated.rest.core.ApiClientApiException;
-import com.skyflow.generated.rest.core.ApiClientException;
-import com.skyflow.generated.rest.core.ApiClientHttpResponse;
-import com.skyflow.generated.rest.core.ClientOptions;
-import com.skyflow.generated.rest.core.MediaTypes;
-import com.skyflow.generated.rest.core.ObjectMappers;
-import com.skyflow.generated.rest.core.RequestOptions;
-import com.skyflow.generated.rest.errors.BadRequestError;
-import com.skyflow.generated.rest.errors.NotFoundError;
-import com.skyflow.generated.rest.errors.UnauthorizedError;
-import com.skyflow.generated.rest.resources.authentication.requests.V1GetAuthTokenRequest;
-import com.skyflow.generated.rest.types.V1GetAuthTokenResponse;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.skyflow.generated.auth.rest.core.*;
+import com.skyflow.generated.auth.rest.errors.BadRequestError;
+import com.skyflow.generated.auth.rest.errors.NotFoundError;
+import com.skyflow.generated.auth.rest.errors.UnauthorizedError;
+import com.skyflow.generated.auth.rest.resources.authentication.requests.V1GetAuthTokenRequest;
+import com.skyflow.generated.auth.rest.types.V1GetAuthTokenResponse;
+import okhttp3.*;
+import org.jetbrains.annotations.NotNull;
+
import java.io.IOException;
+import java.util.Map;
import java.util.concurrent.CompletableFuture;
-import okhttp3.Call;
-import okhttp3.Callback;
-import okhttp3.Headers;
-import okhttp3.HttpUrl;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.RequestBody;
-import okhttp3.Response;
-import okhttp3.ResponseBody;
-import org.jetbrains.annotations.NotNull;
public class AsyncRawAuthenticationClient {
protected final ClientOptions clientOptions;
@@ -88,17 +77,20 @@ public void onResponse(@NotNull Call call, @NotNull Response response) throws IO
switch (response.code()) {
case 400:
future.completeExceptionally(new BadRequestError(
- ObjectMappers.JSON_MAPPER.readValue(responseBodyString, Object.class),
+ ObjectMappers.JSON_MAPPER.readValue(
+ responseBodyString, new TypeReference