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

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
@@ -850,246 +850,344 @@ class DatabaseClient {
850
850
  }
851
851
  }
852
852
 
853
+ const STORAGE_BASE_PATH$1 = '/storage/v1';
853
854
  class StorageBucket {
854
- constructor(httpClient, bucketId) {
855
+ constructor(httpClient, bucketId, workspaceId) {
855
856
  this.httpClient = httpClient;
856
857
  this.bucketId = bucketId;
858
+ this.workspaceId = workspaceId;
859
+ }
860
+ setWorkspaceId(workspaceId) {
861
+ this.workspaceId = workspaceId;
862
+ }
863
+ getWorkspaceHeaders() {
864
+ if (!this.workspaceId) {
865
+ throw new EBaaSError('Workspace ID is required for storage operations', 400);
866
+ }
867
+ return {
868
+ 'x-workspace-id': this.workspaceId,
869
+ };
870
+ }
871
+ normalizePath(path) {
872
+ return path
873
+ .trim()
874
+ .replace(/^\/+/, '')
875
+ .replace(/\/+$/, '')
876
+ .replace(/\/+/g, '/');
877
+ }
878
+ encodePath(path) {
879
+ const normalized = this.normalizePath(path);
880
+ return normalized
881
+ .split('/')
882
+ .filter(Boolean)
883
+ .map((segment) => encodeURIComponent(segment))
884
+ .join('/');
885
+ }
886
+ extractPathParts(path) {
887
+ const normalized = this.normalizePath(path);
888
+ if (!normalized) {
889
+ throw new EBaaSError('Path must include the file name', 400);
890
+ }
891
+ const segments = normalized.split('/').filter(Boolean);
892
+ if (segments.length === 0) {
893
+ throw new EBaaSError('Path must include the file name', 400);
894
+ }
895
+ const fileName = segments.pop();
896
+ const directory = segments.length ? segments.join('/') : undefined;
897
+ return { fileName, directory };
898
+ }
899
+ serializeTransform(transform) {
900
+ if (!transform) {
901
+ return undefined;
902
+ }
903
+ const parts = Object.entries(transform)
904
+ .filter(([, value]) => value !== undefined && value !== null)
905
+ .map(([key, value]) => `${key}=${value}`);
906
+ return parts.length ? parts.join(',') : undefined;
907
+ }
908
+ appendFileToFormData(formData, file, fileName, contentType) {
909
+ if (file instanceof File) {
910
+ if (file.name !== fileName) {
911
+ formData.append('file', file, fileName);
912
+ }
913
+ else {
914
+ formData.append('file', file);
915
+ }
916
+ return;
917
+ }
918
+ if (file instanceof Blob) {
919
+ formData.append('file', file, fileName);
920
+ return;
921
+ }
922
+ if (file instanceof ArrayBuffer) {
923
+ formData.append('file', new Blob([file], { type: contentType ?? 'application/octet-stream' }), fileName);
924
+ return;
925
+ }
926
+ if (typeof file === 'string') {
927
+ formData.append('file', new Blob([file], { type: contentType ?? 'text/plain' }), fileName);
928
+ return;
929
+ }
930
+ throw new EBaaSError('Unsupported file type for upload', 400);
857
931
  }
858
932
  async upload(path, file, options) {
859
933
  try {
934
+ const headers = this.getWorkspaceHeaders();
935
+ const normalizedPath = this.normalizePath(path);
936
+ const { fileName, directory } = this.extractPathParts(normalizedPath);
860
937
  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);
938
+ this.appendFileToFormData(formData, file, fileName, options?.contentType);
939
+ if (directory) {
940
+ formData.append('path', directory);
869
941
  }
870
- else if (typeof file === 'string') {
871
- formData.append('file', new Blob([file], { type: 'text/plain' }), path);
872
- }
873
- formData.append('path', path);
874
942
  if (options?.cacheControl) {
875
943
  formData.append('cacheControl', options.cacheControl);
876
944
  }
945
+ if (options?.metadata) {
946
+ formData.append('metadata', JSON.stringify(options.metadata));
947
+ }
877
948
  if (options?.contentType) {
878
949
  formData.append('contentType', options.contentType);
879
950
  }
880
- if (options?.metadata) {
881
- formData.append('metadata', JSON.stringify(options.metadata));
951
+ if (options?.expiresIn) {
952
+ formData.append('expiresIn', String(options.expiresIn));
882
953
  }
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
- }
954
+ if (options?.upsert) {
955
+ formData.append('overwrite', 'true');
956
+ }
957
+ const encodedPath = this.encodePath(normalizedPath);
958
+ const response = await this.httpClient.post(`${STORAGE_BASE_PATH$1}/object/${this.bucketId}/${encodedPath}`, formData, {
959
+ headers,
888
960
  });
889
961
  return {
890
962
  data: response.data,
891
- error: null
963
+ error: null,
892
964
  };
893
965
  }
894
966
  catch (error) {
895
967
  return {
896
968
  data: null,
897
- error: error instanceof EBaaSError ? error : new EBaaSError(error instanceof Error ? error.message : 'Failed to upload file', 0, error)
969
+ error: error instanceof EBaaSError
970
+ ? error
971
+ : new EBaaSError(error instanceof Error ? error.message : 'Failed to upload file', 0, error),
898
972
  };
899
973
  }
900
974
  }
901
975
  async download(path, options) {
902
976
  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'
977
+ const headers = this.getWorkspaceHeaders();
978
+ const normalizedPath = this.normalizePath(path);
979
+ const encodedPath = this.encodePath(normalizedPath);
980
+ const transformString = this.serializeTransform(options?.transform);
981
+ const query = transformString ? `?transform=${encodeURIComponent(transformString)}` : '';
982
+ const response = await this.httpClient.get(`${STORAGE_BASE_PATH$1}/object/authenticated/${this.bucketId}/${encodedPath}${query}`, {
983
+ responseType: 'blob',
984
+ headers,
914
985
  });
915
986
  return {
916
987
  data: response.data,
917
- error: null
988
+ error: null,
918
989
  };
919
990
  }
920
991
  catch (error) {
921
992
  return {
922
993
  data: null,
923
- error: error instanceof EBaaSError ? error : new EBaaSError(error instanceof Error ? error.message : 'Failed to download file', 0, error)
994
+ error: error instanceof EBaaSError
995
+ ? error
996
+ : new EBaaSError(error instanceof Error ? error.message : 'Failed to download file', 0, error),
924
997
  };
925
998
  }
926
999
  }
927
1000
  async list(prefix, options) {
928
1001
  try {
1002
+ const headers = this.getWorkspaceHeaders();
929
1003
  const params = new URLSearchParams();
930
1004
  if (prefix) {
931
- params.append('prefix', prefix);
1005
+ const normalizedPrefix = prefix.replace(/^\/+/, '');
1006
+ if (normalizedPrefix) {
1007
+ params.append('prefix', normalizedPrefix);
1008
+ }
932
1009
  }
933
1010
  if (options?.limit) {
934
1011
  params.append('limit', String(options.limit));
935
1012
  }
936
1013
  if (options?.offset) {
937
- params.append('offset', String(options.offset));
938
- }
939
- if (options?.sortBy) {
940
- params.append('sortBy', JSON.stringify(options.sortBy));
1014
+ params.append('offset', options.offset);
941
1015
  }
942
1016
  if (options?.search) {
943
1017
  params.append('search', options.search);
944
1018
  }
945
- const url = `/storage/buckets/${this.bucketId}/files${params.toString() ? `?${params.toString()}` : ''}`;
946
- const response = await this.httpClient.get(url);
1019
+ if (options?.sortBy && options.sortBy.length > 0) {
1020
+ const sortValue = options.sortBy
1021
+ .map((item) => {
1022
+ const order = item.order ?? 'asc';
1023
+ return `${item.column}:${order}`;
1024
+ })
1025
+ .join(',');
1026
+ params.append('sortBy', sortValue);
1027
+ }
1028
+ const query = params.toString();
1029
+ const response = await this.httpClient.get(`${STORAGE_BASE_PATH$1}/object/list/${this.bucketId}${query ? `?${query}` : ''}`, {
1030
+ headers,
1031
+ });
947
1032
  return {
948
1033
  data: response.data,
949
- error: null
1034
+ error: null,
950
1035
  };
951
1036
  }
952
1037
  catch (error) {
953
1038
  return {
954
1039
  data: null,
955
- error: error instanceof EBaaSError ? error : new EBaaSError(error instanceof Error ? error.message : 'Failed to list files', 0, error)
1040
+ error: error instanceof EBaaSError
1041
+ ? error
1042
+ : new EBaaSError(error instanceof Error ? error.message : 'Failed to list files', 0, error),
956
1043
  };
957
1044
  }
958
1045
  }
959
1046
  async remove(paths) {
960
1047
  try {
961
- const response = await this.httpClient.delete(`/storage/buckets/${this.bucketId}/files`, {
962
- data: { paths }
963
- });
1048
+ const headers = this.getWorkspaceHeaders();
1049
+ for (const path of paths) {
1050
+ const normalizedPath = this.normalizePath(path);
1051
+ const encodedPath = this.encodePath(normalizedPath);
1052
+ await this.httpClient.delete(`${STORAGE_BASE_PATH$1}/object/${this.bucketId}/${encodedPath}`, {
1053
+ headers,
1054
+ });
1055
+ }
964
1056
  return {
965
- data: response.data,
966
- error: null
1057
+ data: { message: 'Files removed successfully' },
1058
+ error: null,
967
1059
  };
968
1060
  }
969
1061
  catch (error) {
970
1062
  return {
971
1063
  data: null,
972
- error: error instanceof EBaaSError ? error : new EBaaSError(error instanceof Error ? error.message : 'Failed to remove files', 0, error)
1064
+ error: error instanceof EBaaSError
1065
+ ? error
1066
+ : new EBaaSError(error instanceof Error ? error.message : 'Failed to remove files', 0, error),
973
1067
  };
974
1068
  }
975
1069
  }
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
- }
1070
+ async move(_fromPath, _toPath) {
1071
+ return {
1072
+ data: null,
1073
+ error: new EBaaSError('Move operation is not supported by the current E-BaaS backend', 501),
1074
+ };
993
1075
  }
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
- }
1076
+ async copy(_fromPath, _toPath) {
1077
+ return {
1078
+ data: null,
1079
+ error: new EBaaSError('Copy operation is not supported by the current E-BaaS backend', 501),
1080
+ };
1011
1081
  }
1012
1082
  async createSignedUrl(path, expiresIn, options) {
1013
1083
  try {
1014
- const response = await this.httpClient.post(`/storage/buckets/${this.bucketId}/files/${path}/sign`, {
1015
- expiresIn,
1016
- ...options
1084
+ const headers = this.getWorkspaceHeaders();
1085
+ const normalizedPath = this.normalizePath(path);
1086
+ const response = await this.httpClient.post(`${STORAGE_BASE_PATH$1}/object/sign`, {
1087
+ bucketName: this.bucketId,
1088
+ filePath: normalizedPath,
1089
+ operation: options?.operation ?? 'download',
1090
+ expiresIn: options?.expiresIn ?? expiresIn,
1091
+ }, {
1092
+ headers,
1017
1093
  });
1018
1094
  return {
1019
1095
  data: response.data,
1020
- error: null
1096
+ error: null,
1021
1097
  };
1022
1098
  }
1023
1099
  catch (error) {
1024
1100
  return {
1025
1101
  data: null,
1026
- error: error instanceof EBaaSError ? error : new EBaaSError(error instanceof Error ? error.message : 'Failed to create signed URL', 0, error)
1102
+ error: error instanceof EBaaSError
1103
+ ? error
1104
+ : new EBaaSError(error instanceof Error ? error.message : 'Failed to create signed URL', 0, error),
1027
1105
  };
1028
1106
  }
1029
1107
  }
1030
1108
  getPublicUrl(path, options) {
1109
+ const baseUrl = this.httpClient.baseURL;
1110
+ if (!baseUrl) {
1111
+ throw new EBaaSError('HTTP client base URL is not configured', 400);
1112
+ }
1113
+ if (!this.workspaceId) {
1114
+ throw new EBaaSError('Workspace ID is required to generate public URLs', 400);
1115
+ }
1116
+ const normalizedPath = this.normalizePath(path);
1117
+ const encodedPath = this.encodePath(normalizedPath);
1031
1118
  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
- });
1119
+ params.append('workspaceId', this.workspaceId);
1120
+ const transformString = this.serializeTransform(options?.transform);
1121
+ if (transformString) {
1122
+ params.append('transform', transformString);
1038
1123
  }
1039
- const baseUrl = this.httpClient['baseURL'] || '';
1040
- const publicUrl = `${baseUrl}/storage/buckets/${this.bucketId}/files/${path}${params.toString() ? `?${params.toString()}` : ''}`;
1124
+ const publicUrl = `${baseUrl.replace(/\/+$/, '')}${STORAGE_BASE_PATH$1}/object/public/${this.bucketId}/${encodedPath}`;
1125
+ const query = params.toString();
1041
1126
  return {
1042
1127
  data: {
1043
- publicUrl
1044
- }
1128
+ publicUrl: query ? `${publicUrl}?${query}` : publicUrl,
1129
+ },
1045
1130
  };
1046
1131
  }
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
- }
1132
+ async getFileInfo(_path) {
1133
+ return {
1134
+ data: null,
1135
+ error: new EBaaSError('File info retrieval is not supported by the current E-BaaS backend', 501),
1136
+ };
1061
1137
  }
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
- }
1138
+ async updateFileMetadata(_path, _metadata) {
1139
+ return {
1140
+ data: null,
1141
+ error: new EBaaSError('Updating file metadata is not supported by the current E-BaaS backend', 501),
1142
+ };
1078
1143
  }
1079
1144
  }
1080
1145
 
1146
+ const STORAGE_BASE_PATH = '/storage/v1';
1081
1147
  class StorageClient {
1082
- constructor(httpClient) {
1148
+ constructor(httpClient, workspaceId) {
1083
1149
  this.httpClient = httpClient;
1150
+ this.workspaceId = workspaceId;
1084
1151
  }
1085
1152
  from(bucketId) {
1086
- return new StorageBucket(this.httpClient, bucketId);
1153
+ return new StorageBucket(this.httpClient, bucketId, this.workspaceId);
1154
+ }
1155
+ setWorkspaceId(workspaceId) {
1156
+ this.workspaceId = workspaceId;
1157
+ }
1158
+ getWorkspaceHeaders() {
1159
+ if (!this.workspaceId) {
1160
+ throw new EBaaSError('Workspace ID is required for storage operations', 400);
1161
+ }
1162
+ return {
1163
+ 'x-workspace-id': this.workspaceId,
1164
+ };
1165
+ }
1166
+ mapBucketOptions(options) {
1167
+ if (!options) {
1168
+ return {};
1169
+ }
1170
+ const visibility = options.visibility ?? (options.public ? 'public' : undefined);
1171
+ const maxFileSize = options.maxFileSize ?? options.fileSizeLimit;
1172
+ const enableVersioning = options.enableVersioning ?? options.versioningEnabled;
1173
+ return {
1174
+ visibility,
1175
+ description: options.description,
1176
+ allowedMimeTypes: options.allowedMimeTypes,
1177
+ maxFileSize,
1178
+ enableVersioning,
1179
+ enableCors: options.enableCors,
1180
+ corsOrigins: options.corsOrigins,
1181
+ };
1087
1182
  }
1088
1183
  async createBucket(id, options) {
1089
1184
  try {
1090
- const response = await this.httpClient.post('/storage/buckets', {
1091
- id,
1092
- ...options
1185
+ const payload = {
1186
+ name: id,
1187
+ ...this.mapBucketOptions(options),
1188
+ };
1189
+ const response = await this.httpClient.post(`${STORAGE_BASE_PATH}/buckets`, payload, {
1190
+ headers: this.getWorkspaceHeaders(),
1093
1191
  });
1094
1192
  return {
1095
1193
  data: response.data,
@@ -1105,7 +1203,9 @@ class StorageClient {
1105
1203
  }
1106
1204
  async getBucket(id) {
1107
1205
  try {
1108
- const response = await this.httpClient.get(`/storage/buckets/${id}`);
1206
+ const response = await this.httpClient.get(`${STORAGE_BASE_PATH}/buckets/${id}`, {
1207
+ headers: this.getWorkspaceHeaders(),
1208
+ });
1109
1209
  return {
1110
1210
  data: response.data,
1111
1211
  error: null
@@ -1120,7 +1220,9 @@ class StorageClient {
1120
1220
  }
1121
1221
  async listBuckets() {
1122
1222
  try {
1123
- const response = await this.httpClient.get('/storage/buckets');
1223
+ const response = await this.httpClient.get(`${STORAGE_BASE_PATH}/buckets`, {
1224
+ headers: this.getWorkspaceHeaders(),
1225
+ });
1124
1226
  return {
1125
1227
  data: response.data,
1126
1228
  error: null
@@ -1135,7 +1237,10 @@ class StorageClient {
1135
1237
  }
1136
1238
  async updateBucket(id, options) {
1137
1239
  try {
1138
- const response = await this.httpClient.put(`/storage/buckets/${id}`, options);
1240
+ const payload = this.mapBucketOptions(options);
1241
+ const response = await this.httpClient.put(`${STORAGE_BASE_PATH}/buckets/${id}`, payload, {
1242
+ headers: this.getWorkspaceHeaders(),
1243
+ });
1139
1244
  return {
1140
1245
  data: response.data,
1141
1246
  error: null
@@ -1150,7 +1255,9 @@ class StorageClient {
1150
1255
  }
1151
1256
  async deleteBucket(id) {
1152
1257
  try {
1153
- const response = await this.httpClient.delete(`/storage/buckets/${id}`);
1258
+ const response = await this.httpClient.delete(`${STORAGE_BASE_PATH}/buckets/${id}`, {
1259
+ headers: this.getWorkspaceHeaders(),
1260
+ });
1154
1261
  return {
1155
1262
  data: response.data,
1156
1263
  error: null
@@ -1165,7 +1272,9 @@ class StorageClient {
1165
1272
  }
1166
1273
  async getUsage() {
1167
1274
  try {
1168
- const response = await this.httpClient.get('/storage/usage');
1275
+ const response = await this.httpClient.get(`${STORAGE_BASE_PATH}/usage`, {
1276
+ headers: this.getWorkspaceHeaders(),
1277
+ });
1169
1278
  return {
1170
1279
  data: response.data,
1171
1280
  error: null
@@ -1996,7 +2105,7 @@ class EBaaSClient {
1996
2105
  // Initialize all modules
1997
2106
  this.auth = new AuthClient(this.httpClient, options?.database?.workspaceId);
1998
2107
  this.database = new DatabaseClient(this.httpClient, options?.database?.workspaceId, options?.rest?.url);
1999
- this.storage = new StorageClient(this.httpClient);
2108
+ this.storage = new StorageClient(this.httpClient, options?.database?.workspaceId);
2000
2109
  this.realtime = new RealtimeClient(supabaseUrl, supabaseKey, options?.realtime);
2001
2110
  this.functions = new FunctionsClient(this.httpClient);
2002
2111
  // Initialize custom database detection if enabled
@@ -2041,6 +2150,7 @@ class EBaaSClient {
2041
2150
  async setWorkspaceId(workspaceId) {
2042
2151
  this.auth.setWorkspaceId(workspaceId);
2043
2152
  this.database.setWorkspaceId(workspaceId);
2153
+ this.storage.setWorkspaceId(workspaceId);
2044
2154
  // Se auto-detecção estiver habilitada, re-detecta configuração para o novo workspace
2045
2155
  if (this.options?.database?.autoDetectCustomDatabase) {
2046
2156
  await this.database.initialize();