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