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