@e-techsolutions/e-baas-sdk 1.2.2 → 1.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.esm.js CHANGED
@@ -32,8 +32,7 @@ class HttpClient {
32
32
  baseURL: this.baseURL,
33
33
  timeout: config.timeout || 10000,
34
34
  headers: {
35
- 'Content-Type': 'application/json',
36
- 'apikey': this.apiKey,
35
+ apikey: this.apiKey,
37
36
  ...config.headers,
38
37
  },
39
38
  });
@@ -42,6 +41,18 @@ class HttpClient {
42
41
  setupInterceptors() {
43
42
  // Request interceptor
44
43
  this.client.interceptors.request.use((config) => {
44
+ const isFormData = typeof FormData !== 'undefined' && config.data instanceof FormData;
45
+ const headers = config.headers ?? {};
46
+ if (isFormData) {
47
+ delete headers['Content-Type'];
48
+ delete headers['content-type'];
49
+ }
50
+ else if (config.data && typeof config.data === 'object' && !(config.data instanceof ArrayBuffer)) {
51
+ if (!('Content-Type' in headers) && !('content-type' in headers)) {
52
+ headers['Content-Type'] = 'application/json';
53
+ }
54
+ }
55
+ config.headers = headers;
45
56
  return config;
46
57
  }, (error) => {
47
58
  return Promise.reject(new EBaaSError('Request failed', 0, error));
@@ -850,246 +861,344 @@ class DatabaseClient {
850
861
  }
851
862
  }
852
863
 
864
+ const STORAGE_BASE_PATH$1 = '/storage/v1';
853
865
  class StorageBucket {
854
- constructor(httpClient, bucketId) {
866
+ constructor(httpClient, bucketId, workspaceId) {
855
867
  this.httpClient = httpClient;
856
868
  this.bucketId = bucketId;
869
+ this.workspaceId = workspaceId;
870
+ }
871
+ setWorkspaceId(workspaceId) {
872
+ this.workspaceId = workspaceId;
873
+ }
874
+ getWorkspaceHeaders() {
875
+ if (!this.workspaceId) {
876
+ throw new EBaaSError('Workspace ID is required for storage operations', 400);
877
+ }
878
+ return {
879
+ 'x-workspace-id': this.workspaceId,
880
+ };
881
+ }
882
+ normalizePath(path) {
883
+ return path
884
+ .trim()
885
+ .replace(/^\/+/, '')
886
+ .replace(/\/+$/, '')
887
+ .replace(/\/+/g, '/');
888
+ }
889
+ encodePath(path) {
890
+ const normalized = this.normalizePath(path);
891
+ return normalized
892
+ .split('/')
893
+ .filter(Boolean)
894
+ .map((segment) => encodeURIComponent(segment))
895
+ .join('/');
896
+ }
897
+ extractPathParts(path) {
898
+ const normalized = this.normalizePath(path);
899
+ if (!normalized) {
900
+ throw new EBaaSError('Path must include the file name', 400);
901
+ }
902
+ const segments = normalized.split('/').filter(Boolean);
903
+ if (segments.length === 0) {
904
+ throw new EBaaSError('Path must include the file name', 400);
905
+ }
906
+ const fileName = segments.pop();
907
+ const directory = segments.length ? segments.join('/') : undefined;
908
+ return { fileName, directory };
909
+ }
910
+ serializeTransform(transform) {
911
+ if (!transform) {
912
+ return undefined;
913
+ }
914
+ const parts = Object.entries(transform)
915
+ .filter(([, value]) => value !== undefined && value !== null)
916
+ .map(([key, value]) => `${key}=${value}`);
917
+ return parts.length ? parts.join(',') : undefined;
918
+ }
919
+ appendFileToFormData(formData, file, fileName, contentType) {
920
+ if (file instanceof File) {
921
+ if (file.name !== fileName) {
922
+ formData.append('file', file, fileName);
923
+ }
924
+ else {
925
+ formData.append('file', file);
926
+ }
927
+ return;
928
+ }
929
+ if (file instanceof Blob) {
930
+ formData.append('file', file, fileName);
931
+ return;
932
+ }
933
+ if (file instanceof ArrayBuffer) {
934
+ formData.append('file', new Blob([file], { type: contentType ?? 'application/octet-stream' }), fileName);
935
+ return;
936
+ }
937
+ if (typeof file === 'string') {
938
+ formData.append('file', new Blob([file], { type: contentType ?? 'text/plain' }), fileName);
939
+ return;
940
+ }
941
+ throw new EBaaSError('Unsupported file type for upload', 400);
857
942
  }
858
943
  async upload(path, file, options) {
859
944
  try {
945
+ const headers = this.getWorkspaceHeaders();
946
+ const normalizedPath = this.normalizePath(path);
947
+ const { fileName, directory } = this.extractPathParts(normalizedPath);
860
948
  const formData = new FormData();
861
- if (file instanceof File) {
862
- formData.append('file', file);
863
- }
864
- else if (file instanceof Blob) {
865
- formData.append('file', file, path);
866
- }
867
- else if (file instanceof ArrayBuffer) {
868
- formData.append('file', new Blob([file]), path);
949
+ this.appendFileToFormData(formData, file, fileName, options?.contentType);
950
+ if (directory) {
951
+ formData.append('path', directory);
869
952
  }
870
- else if (typeof file === 'string') {
871
- formData.append('file', new Blob([file], { type: 'text/plain' }), path);
872
- }
873
- formData.append('path', path);
874
953
  if (options?.cacheControl) {
875
954
  formData.append('cacheControl', options.cacheControl);
876
955
  }
956
+ if (options?.metadata) {
957
+ formData.append('metadata', JSON.stringify(options.metadata));
958
+ }
877
959
  if (options?.contentType) {
878
960
  formData.append('contentType', options.contentType);
879
961
  }
880
- if (options?.metadata) {
881
- formData.append('metadata', JSON.stringify(options.metadata));
962
+ if (options?.expiresIn) {
963
+ formData.append('expiresIn', String(options.expiresIn));
882
964
  }
883
- const url = `/storage/buckets/${this.bucketId}/files${options?.upsert ? '?upsert=true' : ''}`;
884
- const response = await this.httpClient.post(url, formData, {
885
- headers: {
886
- 'Content-Type': 'multipart/form-data'
887
- }
965
+ if (options?.upsert) {
966
+ formData.append('overwrite', 'true');
967
+ }
968
+ const encodedPath = this.encodePath(normalizedPath);
969
+ const response = await this.httpClient.post(`${STORAGE_BASE_PATH$1}/object/${this.bucketId}/${encodedPath}`, formData, {
970
+ headers,
888
971
  });
889
972
  return {
890
973
  data: response.data,
891
- error: null
974
+ error: null,
892
975
  };
893
976
  }
894
977
  catch (error) {
895
978
  return {
896
979
  data: null,
897
- error: error instanceof EBaaSError ? error : new EBaaSError(error instanceof Error ? error.message : 'Failed to upload file', 0, error)
980
+ error: error instanceof EBaaSError
981
+ ? error
982
+ : new EBaaSError(error instanceof Error ? error.message : 'Failed to upload file', 0, error),
898
983
  };
899
984
  }
900
985
  }
901
986
  async download(path, options) {
902
987
  try {
903
- const params = new URLSearchParams();
904
- if (options?.transform) {
905
- Object.entries(options.transform).forEach(([key, value]) => {
906
- if (value !== undefined) {
907
- params.append(key, String(value));
908
- }
909
- });
910
- }
911
- const url = `/storage/buckets/${this.bucketId}/files/${path}${params.toString() ? `?${params.toString()}` : ''}`;
912
- const response = await this.httpClient.get(url, {
913
- responseType: 'blob'
988
+ const headers = this.getWorkspaceHeaders();
989
+ const normalizedPath = this.normalizePath(path);
990
+ const encodedPath = this.encodePath(normalizedPath);
991
+ const transformString = this.serializeTransform(options?.transform);
992
+ const query = transformString ? `?transform=${encodeURIComponent(transformString)}` : '';
993
+ const response = await this.httpClient.get(`${STORAGE_BASE_PATH$1}/object/authenticated/${this.bucketId}/${encodedPath}${query}`, {
994
+ responseType: 'blob',
995
+ headers,
914
996
  });
915
997
  return {
916
998
  data: response.data,
917
- error: null
999
+ error: null,
918
1000
  };
919
1001
  }
920
1002
  catch (error) {
921
1003
  return {
922
1004
  data: null,
923
- error: error instanceof EBaaSError ? error : new EBaaSError(error instanceof Error ? error.message : 'Failed to download file', 0, error)
1005
+ error: error instanceof EBaaSError
1006
+ ? error
1007
+ : new EBaaSError(error instanceof Error ? error.message : 'Failed to download file', 0, error),
924
1008
  };
925
1009
  }
926
1010
  }
927
1011
  async list(prefix, options) {
928
1012
  try {
1013
+ const headers = this.getWorkspaceHeaders();
929
1014
  const params = new URLSearchParams();
930
1015
  if (prefix) {
931
- params.append('prefix', prefix);
1016
+ const normalizedPrefix = prefix.replace(/^\/+/, '');
1017
+ if (normalizedPrefix) {
1018
+ params.append('prefix', normalizedPrefix);
1019
+ }
932
1020
  }
933
1021
  if (options?.limit) {
934
1022
  params.append('limit', String(options.limit));
935
1023
  }
936
1024
  if (options?.offset) {
937
- params.append('offset', String(options.offset));
938
- }
939
- if (options?.sortBy) {
940
- params.append('sortBy', JSON.stringify(options.sortBy));
1025
+ params.append('offset', options.offset);
941
1026
  }
942
1027
  if (options?.search) {
943
1028
  params.append('search', options.search);
944
1029
  }
945
- const url = `/storage/buckets/${this.bucketId}/files${params.toString() ? `?${params.toString()}` : ''}`;
946
- const response = await this.httpClient.get(url);
1030
+ if (options?.sortBy && options.sortBy.length > 0) {
1031
+ const sortValue = options.sortBy
1032
+ .map((item) => {
1033
+ const order = item.order ?? 'asc';
1034
+ return `${item.column}:${order}`;
1035
+ })
1036
+ .join(',');
1037
+ params.append('sortBy', sortValue);
1038
+ }
1039
+ const query = params.toString();
1040
+ const response = await this.httpClient.get(`${STORAGE_BASE_PATH$1}/object/list/${this.bucketId}${query ? `?${query}` : ''}`, {
1041
+ headers,
1042
+ });
947
1043
  return {
948
1044
  data: response.data,
949
- error: null
1045
+ error: null,
950
1046
  };
951
1047
  }
952
1048
  catch (error) {
953
1049
  return {
954
1050
  data: null,
955
- error: error instanceof EBaaSError ? error : new EBaaSError(error instanceof Error ? error.message : 'Failed to list files', 0, error)
1051
+ error: error instanceof EBaaSError
1052
+ ? error
1053
+ : new EBaaSError(error instanceof Error ? error.message : 'Failed to list files', 0, error),
956
1054
  };
957
1055
  }
958
1056
  }
959
1057
  async remove(paths) {
960
1058
  try {
961
- const response = await this.httpClient.delete(`/storage/buckets/${this.bucketId}/files`, {
962
- data: { paths }
963
- });
1059
+ const headers = this.getWorkspaceHeaders();
1060
+ for (const path of paths) {
1061
+ const normalizedPath = this.normalizePath(path);
1062
+ const encodedPath = this.encodePath(normalizedPath);
1063
+ await this.httpClient.delete(`${STORAGE_BASE_PATH$1}/object/${this.bucketId}/${encodedPath}`, {
1064
+ headers,
1065
+ });
1066
+ }
964
1067
  return {
965
- data: response.data,
966
- error: null
1068
+ data: { message: 'Files removed successfully' },
1069
+ error: null,
967
1070
  };
968
1071
  }
969
1072
  catch (error) {
970
1073
  return {
971
1074
  data: null,
972
- error: error instanceof EBaaSError ? error : new EBaaSError(error instanceof Error ? error.message : 'Failed to remove files', 0, error)
1075
+ error: error instanceof EBaaSError
1076
+ ? error
1077
+ : new EBaaSError(error instanceof Error ? error.message : 'Failed to remove files', 0, error),
973
1078
  };
974
1079
  }
975
1080
  }
976
- async move(fromPath, toPath) {
977
- try {
978
- const response = await this.httpClient.post(`/storage/buckets/${this.bucketId}/files/move`, {
979
- sourceKey: fromPath,
980
- destinationKey: toPath
981
- });
982
- return {
983
- data: response.data,
984
- error: null
985
- };
986
- }
987
- catch (error) {
988
- return {
989
- data: null,
990
- error: error instanceof EBaaSError ? error : new EBaaSError(error instanceof Error ? error.message : 'Failed to move file', 0, error)
991
- };
992
- }
1081
+ async move(_fromPath, _toPath) {
1082
+ return {
1083
+ data: null,
1084
+ error: new EBaaSError('Move operation is not supported by the current E-BaaS backend', 501),
1085
+ };
993
1086
  }
994
- async copy(fromPath, toPath) {
995
- try {
996
- const response = await this.httpClient.post(`/storage/buckets/${this.bucketId}/files/copy`, {
997
- sourceKey: fromPath,
998
- destinationKey: toPath
999
- });
1000
- return {
1001
- data: response.data,
1002
- error: null
1003
- };
1004
- }
1005
- catch (error) {
1006
- return {
1007
- data: null,
1008
- error: error instanceof EBaaSError ? error : new EBaaSError(error instanceof Error ? error.message : 'Failed to copy file', 0, error)
1009
- };
1010
- }
1087
+ async copy(_fromPath, _toPath) {
1088
+ return {
1089
+ data: null,
1090
+ error: new EBaaSError('Copy operation is not supported by the current E-BaaS backend', 501),
1091
+ };
1011
1092
  }
1012
1093
  async createSignedUrl(path, expiresIn, options) {
1013
1094
  try {
1014
- const response = await this.httpClient.post(`/storage/buckets/${this.bucketId}/files/${path}/sign`, {
1015
- expiresIn,
1016
- ...options
1095
+ const headers = this.getWorkspaceHeaders();
1096
+ const normalizedPath = this.normalizePath(path);
1097
+ const response = await this.httpClient.post(`${STORAGE_BASE_PATH$1}/object/sign`, {
1098
+ bucketName: this.bucketId,
1099
+ filePath: normalizedPath,
1100
+ operation: options?.operation ?? 'download',
1101
+ expiresIn: options?.expiresIn ?? expiresIn,
1102
+ }, {
1103
+ headers,
1017
1104
  });
1018
1105
  return {
1019
1106
  data: response.data,
1020
- error: null
1107
+ error: null,
1021
1108
  };
1022
1109
  }
1023
1110
  catch (error) {
1024
1111
  return {
1025
1112
  data: null,
1026
- error: error instanceof EBaaSError ? error : new EBaaSError(error instanceof Error ? error.message : 'Failed to create signed URL', 0, error)
1113
+ error: error instanceof EBaaSError
1114
+ ? error
1115
+ : new EBaaSError(error instanceof Error ? error.message : 'Failed to create signed URL', 0, error),
1027
1116
  };
1028
1117
  }
1029
1118
  }
1030
1119
  getPublicUrl(path, options) {
1120
+ const baseUrl = this.httpClient.baseURL;
1121
+ if (!baseUrl) {
1122
+ throw new EBaaSError('HTTP client base URL is not configured', 400);
1123
+ }
1124
+ if (!this.workspaceId) {
1125
+ throw new EBaaSError('Workspace ID is required to generate public URLs', 400);
1126
+ }
1127
+ const normalizedPath = this.normalizePath(path);
1128
+ const encodedPath = this.encodePath(normalizedPath);
1031
1129
  const params = new URLSearchParams();
1032
- if (options?.transform) {
1033
- Object.entries(options.transform).forEach(([key, value]) => {
1034
- if (value !== undefined) {
1035
- params.append(key, String(value));
1036
- }
1037
- });
1130
+ params.append('workspaceId', this.workspaceId);
1131
+ const transformString = this.serializeTransform(options?.transform);
1132
+ if (transformString) {
1133
+ params.append('transform', transformString);
1038
1134
  }
1039
- const baseUrl = this.httpClient['baseURL'] || '';
1040
- const publicUrl = `${baseUrl}/storage/buckets/${this.bucketId}/files/${path}${params.toString() ? `?${params.toString()}` : ''}`;
1135
+ const publicUrl = `${baseUrl.replace(/\/+$/, '')}${STORAGE_BASE_PATH$1}/object/public/${this.bucketId}/${encodedPath}`;
1136
+ const query = params.toString();
1041
1137
  return {
1042
1138
  data: {
1043
- publicUrl
1044
- }
1139
+ publicUrl: query ? `${publicUrl}?${query}` : publicUrl,
1140
+ },
1045
1141
  };
1046
1142
  }
1047
- async getFileInfo(path) {
1048
- try {
1049
- const response = await this.httpClient.get(`/storage/buckets/${this.bucketId}/files/${path}/info`);
1050
- return {
1051
- data: response.data,
1052
- error: null
1053
- };
1054
- }
1055
- catch (error) {
1056
- return {
1057
- data: null,
1058
- error: error instanceof EBaaSError ? error : new EBaaSError(error instanceof Error ? error.message : 'Failed to get file info', 0, error)
1059
- };
1060
- }
1143
+ async getFileInfo(_path) {
1144
+ return {
1145
+ data: null,
1146
+ error: new EBaaSError('File info retrieval is not supported by the current E-BaaS backend', 501),
1147
+ };
1061
1148
  }
1062
- async updateFileMetadata(path, metadata) {
1063
- try {
1064
- const response = await this.httpClient.put(`/storage/buckets/${this.bucketId}/files/${path}/metadata`, {
1065
- metadata
1066
- });
1067
- return {
1068
- data: response.data,
1069
- error: null
1070
- };
1071
- }
1072
- catch (error) {
1073
- return {
1074
- data: null,
1075
- error: error instanceof EBaaSError ? error : new EBaaSError(error instanceof Error ? error.message : 'Failed to update file metadata', 0, error)
1076
- };
1077
- }
1149
+ async updateFileMetadata(_path, _metadata) {
1150
+ return {
1151
+ data: null,
1152
+ error: new EBaaSError('Updating file metadata is not supported by the current E-BaaS backend', 501),
1153
+ };
1078
1154
  }
1079
1155
  }
1080
1156
 
1157
+ const STORAGE_BASE_PATH = '/storage/v1';
1081
1158
  class StorageClient {
1082
- constructor(httpClient) {
1159
+ constructor(httpClient, workspaceId) {
1083
1160
  this.httpClient = httpClient;
1161
+ this.workspaceId = workspaceId;
1084
1162
  }
1085
1163
  from(bucketId) {
1086
- return new StorageBucket(this.httpClient, bucketId);
1164
+ return new StorageBucket(this.httpClient, bucketId, this.workspaceId);
1165
+ }
1166
+ setWorkspaceId(workspaceId) {
1167
+ this.workspaceId = workspaceId;
1168
+ }
1169
+ getWorkspaceHeaders() {
1170
+ if (!this.workspaceId) {
1171
+ throw new EBaaSError('Workspace ID is required for storage operations', 400);
1172
+ }
1173
+ return {
1174
+ 'x-workspace-id': this.workspaceId,
1175
+ };
1176
+ }
1177
+ mapBucketOptions(options) {
1178
+ if (!options) {
1179
+ return {};
1180
+ }
1181
+ const visibility = options.visibility ?? (options.public ? 'public' : undefined);
1182
+ const maxFileSize = options.maxFileSize ?? options.fileSizeLimit;
1183
+ const enableVersioning = options.enableVersioning ?? options.versioningEnabled;
1184
+ return {
1185
+ visibility,
1186
+ description: options.description,
1187
+ allowedMimeTypes: options.allowedMimeTypes,
1188
+ maxFileSize,
1189
+ enableVersioning,
1190
+ enableCors: options.enableCors,
1191
+ corsOrigins: options.corsOrigins,
1192
+ };
1087
1193
  }
1088
1194
  async createBucket(id, options) {
1089
1195
  try {
1090
- const response = await this.httpClient.post('/storage/buckets', {
1091
- id,
1092
- ...options
1196
+ const payload = {
1197
+ name: id,
1198
+ ...this.mapBucketOptions(options),
1199
+ };
1200
+ const response = await this.httpClient.post(`${STORAGE_BASE_PATH}/buckets`, payload, {
1201
+ headers: this.getWorkspaceHeaders(),
1093
1202
  });
1094
1203
  return {
1095
1204
  data: response.data,
@@ -1105,7 +1214,9 @@ class StorageClient {
1105
1214
  }
1106
1215
  async getBucket(id) {
1107
1216
  try {
1108
- const response = await this.httpClient.get(`/storage/buckets/${id}`);
1217
+ const response = await this.httpClient.get(`${STORAGE_BASE_PATH}/buckets/${id}`, {
1218
+ headers: this.getWorkspaceHeaders(),
1219
+ });
1109
1220
  return {
1110
1221
  data: response.data,
1111
1222
  error: null
@@ -1120,7 +1231,9 @@ class StorageClient {
1120
1231
  }
1121
1232
  async listBuckets() {
1122
1233
  try {
1123
- const response = await this.httpClient.get('/storage/buckets');
1234
+ const response = await this.httpClient.get(`${STORAGE_BASE_PATH}/buckets`, {
1235
+ headers: this.getWorkspaceHeaders(),
1236
+ });
1124
1237
  return {
1125
1238
  data: response.data,
1126
1239
  error: null
@@ -1135,7 +1248,10 @@ class StorageClient {
1135
1248
  }
1136
1249
  async updateBucket(id, options) {
1137
1250
  try {
1138
- const response = await this.httpClient.put(`/storage/buckets/${id}`, options);
1251
+ const payload = this.mapBucketOptions(options);
1252
+ const response = await this.httpClient.put(`${STORAGE_BASE_PATH}/buckets/${id}`, payload, {
1253
+ headers: this.getWorkspaceHeaders(),
1254
+ });
1139
1255
  return {
1140
1256
  data: response.data,
1141
1257
  error: null
@@ -1150,7 +1266,9 @@ class StorageClient {
1150
1266
  }
1151
1267
  async deleteBucket(id) {
1152
1268
  try {
1153
- const response = await this.httpClient.delete(`/storage/buckets/${id}`);
1269
+ const response = await this.httpClient.delete(`${STORAGE_BASE_PATH}/buckets/${id}`, {
1270
+ headers: this.getWorkspaceHeaders(),
1271
+ });
1154
1272
  return {
1155
1273
  data: response.data,
1156
1274
  error: null
@@ -1165,7 +1283,9 @@ class StorageClient {
1165
1283
  }
1166
1284
  async getUsage() {
1167
1285
  try {
1168
- const response = await this.httpClient.get('/storage/usage');
1286
+ const response = await this.httpClient.get(`${STORAGE_BASE_PATH}/usage`, {
1287
+ headers: this.getWorkspaceHeaders(),
1288
+ });
1169
1289
  return {
1170
1290
  data: response.data,
1171
1291
  error: null
@@ -1996,7 +2116,7 @@ class EBaaSClient {
1996
2116
  // Initialize all modules
1997
2117
  this.auth = new AuthClient(this.httpClient, options?.database?.workspaceId);
1998
2118
  this.database = new DatabaseClient(this.httpClient, options?.database?.workspaceId, options?.rest?.url);
1999
- this.storage = new StorageClient(this.httpClient);
2119
+ this.storage = new StorageClient(this.httpClient, options?.database?.workspaceId);
2000
2120
  this.realtime = new RealtimeClient(supabaseUrl, supabaseKey, options?.realtime);
2001
2121
  this.functions = new FunctionsClient(this.httpClient);
2002
2122
  // Initialize custom database detection if enabled
@@ -2041,6 +2161,7 @@ class EBaaSClient {
2041
2161
  async setWorkspaceId(workspaceId) {
2042
2162
  this.auth.setWorkspaceId(workspaceId);
2043
2163
  this.database.setWorkspaceId(workspaceId);
2164
+ this.storage.setWorkspaceId(workspaceId);
2044
2165
  // Se auto-detecção estiver habilitada, re-detecta configuração para o novo workspace
2045
2166
  if (this.options?.database?.autoDetectCustomDatabase) {
2046
2167
  await this.database.initialize();