nexabase-console 2.0.3 → 2.0.5

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.
@@ -29,7 +29,7 @@ class NexaApp {
29
29
  }
30
30
  this.endpoint = config.endpoint || defaultEndpoint;
31
31
  // Transport
32
- this.httpClient = new HttpClient_1.HttpClient(this.endpoint, () => this.authService ? this.authService.getToken() : this.token);
32
+ this.httpClient = new HttpClient_1.HttpClient(this.endpoint, () => (this.authService ? this.authService.getToken() : this.token), this.projectId, this.token);
33
33
  this.client = this.httpClient.getAxiosInstance();
34
34
  this.sseClient = new SSEClient_1.SSEClient(this.projectId, this.endpoint);
35
35
  // Auth & Persistence
package/dist/auth/Auth.js CHANGED
@@ -165,9 +165,9 @@ class Auth {
165
165
  return this.refreshPromise;
166
166
  }
167
167
  async refreshAccessToken(refreshToken) {
168
- const endpoint = this.emulatorUrl || `/api/project/${this.projectId}/auth/token/refresh`;
168
+ const endpoint = this.emulatorUrl || `/api/auth/token/refresh`;
169
169
  try {
170
- const res = await this.client.post(endpoint, { refreshToken });
170
+ const res = await this.client.post(endpoint, { refreshToken, projectId: this.projectId });
171
171
  const session = res.data;
172
172
  this.currentSession = session;
173
173
  await this.persistence.saveSession(session);
@@ -203,8 +203,8 @@ class Auth {
203
203
  // --- Email & Password Auth ---
204
204
  async createUserWithEmailAndPassword(email, password, name) {
205
205
  try {
206
- const endpoint = this.emulatorUrl || `/api/project/${this.projectId}/auth/register`;
207
- const res = await this.client.post(endpoint, { email, password, name });
206
+ const endpoint = this.emulatorUrl || `/api/auth/register`;
207
+ const res = await this.client.post(endpoint, { email, password, name, projectId: this.projectId });
208
208
  const session = res.data;
209
209
  this.currentSession = session;
210
210
  await this.persistence.saveSession(session);
@@ -218,8 +218,8 @@ class Auth {
218
218
  }
219
219
  async signInWithEmailAndPassword(email, password) {
220
220
  try {
221
- const endpoint = this.emulatorUrl || `/api/project/${this.projectId}/auth/login`;
222
- const res = await this.client.post(endpoint, { email, password });
221
+ const endpoint = this.emulatorUrl || `/api/auth/login`;
222
+ const res = await this.client.post(endpoint, { email, password, projectId: this.projectId });
223
223
  const session = res.data;
224
224
  this.currentSession = session;
225
225
  await this.persistence.saveSession(session);
@@ -234,8 +234,8 @@ class Auth {
234
234
  // --- OTP Auth ---
235
235
  async sendOtp(email) {
236
236
  try {
237
- const endpoint = this.emulatorUrl || `/api/project/${this.projectId}/auth/otp/send`;
238
- const res = await this.client.post(endpoint, { email });
237
+ const endpoint = this.emulatorUrl || `/api/auth/otp/send`;
238
+ const res = await this.client.post(endpoint, { email, projectId: this.projectId });
239
239
  return res.data;
240
240
  }
241
241
  catch (err) {
@@ -244,8 +244,8 @@ class Auth {
244
244
  }
245
245
  async signInWithOtp(email, otp) {
246
246
  try {
247
- const endpoint = this.emulatorUrl || `/api/project/${this.projectId}/auth/otp/login`;
248
- const res = await this.client.post(endpoint, { email, otp });
247
+ const endpoint = this.emulatorUrl || `/api/auth/otp/login`;
248
+ const res = await this.client.post(endpoint, { email, otp, projectId: this.projectId });
249
249
  const session = res.data;
250
250
  this.currentSession = session;
251
251
  await this.persistence.saveSession(session);
@@ -260,8 +260,8 @@ class Auth {
260
260
  // --- Password Reset & Verification ---
261
261
  async sendPasswordResetEmail(email) {
262
262
  try {
263
- const endpoint = this.emulatorUrl || `/api/project/${this.projectId}/auth/password-reset/send`;
264
- const res = await this.client.post(endpoint, { email });
263
+ const endpoint = this.emulatorUrl || `/api/auth/password-reset/send`;
264
+ const res = await this.client.post(endpoint, { email, projectId: this.projectId });
265
265
  return res.data;
266
266
  }
267
267
  catch (err) {
@@ -270,8 +270,8 @@ class Auth {
270
270
  }
271
271
  async confirmPasswordReset(code, newPassword) {
272
272
  try {
273
- const endpoint = this.emulatorUrl || `/api/project/${this.projectId}/auth/password-reset/confirm`;
274
- const res = await this.client.post(endpoint, { code, newPassword });
273
+ const endpoint = this.emulatorUrl || `/api/auth/password-reset/confirm`;
274
+ const res = await this.client.post(endpoint, { code, newPassword, projectId: this.projectId });
275
275
  return res.data;
276
276
  }
277
277
  catch (err) {
@@ -281,8 +281,8 @@ class Auth {
281
281
  async sendEmailVerification() {
282
282
  const token = await this.getIdToken();
283
283
  try {
284
- const endpoint = this.emulatorUrl || `/api/project/${this.projectId}/auth/email/send-verification`;
285
- const res = await this.client.post(endpoint, {}, {
284
+ const endpoint = this.emulatorUrl || `/api/auth/email/send-verification`;
285
+ const res = await this.client.post(endpoint, { projectId: this.projectId }, {
286
286
  headers: { Authorization: `Bearer ${token}` }
287
287
  });
288
288
  return res.data;
@@ -295,8 +295,8 @@ class Auth {
295
295
  async updateProfile(update) {
296
296
  const token = await this.getIdToken();
297
297
  try {
298
- const endpoint = this.emulatorUrl || `/api/project/${this.projectId}/auth/profile`;
299
- const res = await this.client.patch(endpoint, update, {
298
+ const endpoint = this.emulatorUrl || `/api/auth/profile`;
299
+ const res = await this.client.patch(endpoint, { ...update, projectId: this.projectId }, {
300
300
  headers: { Authorization: `Bearer ${token}` }
301
301
  });
302
302
  const updatedUser = res.data;
@@ -314,8 +314,8 @@ class Auth {
314
314
  async updatePassword(newPassword) {
315
315
  const token = await this.getIdToken();
316
316
  try {
317
- const endpoint = this.emulatorUrl || `/api/project/${this.projectId}/auth/password/update`;
318
- await this.client.post(endpoint, { newPassword }, {
317
+ const endpoint = this.emulatorUrl || `/api/auth/password/update`;
318
+ await this.client.post(endpoint, { newPassword, projectId: this.projectId }, {
319
319
  headers: { Authorization: `Bearer ${token}` }
320
320
  });
321
321
  }
@@ -326,9 +326,10 @@ class Auth {
326
326
  async deleteUser() {
327
327
  const token = await this.getIdToken();
328
328
  try {
329
- const endpoint = this.emulatorUrl || `/api/project/${this.projectId}/auth/user/delete`;
329
+ const endpoint = this.emulatorUrl || `/api/auth/user/delete`;
330
330
  await this.client.delete(endpoint, {
331
- headers: { Authorization: `Bearer ${token}` }
331
+ headers: { Authorization: `Bearer ${token}` },
332
+ data: { projectId: this.projectId }
332
333
  });
333
334
  await this.signOut();
334
335
  }
@@ -340,8 +341,8 @@ class Auth {
340
341
  async revokeSession(sessionId) {
341
342
  const token = await this.getIdToken();
342
343
  try {
343
- const endpoint = this.emulatorUrl || `/api/project/${this.projectId}/auth/session/revoke`;
344
- await this.client.post(endpoint, { sessionId }, {
344
+ const endpoint = this.emulatorUrl || `/api/auth/session/revoke`;
345
+ await this.client.post(endpoint, { sessionId, projectId: this.projectId }, {
345
346
  headers: { Authorization: `Bearer ${token}` }
346
347
  });
347
348
  }
@@ -352,8 +353,8 @@ class Auth {
352
353
  async revokeAllSessions() {
353
354
  const token = await this.getIdToken();
354
355
  try {
355
- const endpoint = this.emulatorUrl || `/api/project/${this.projectId}/auth/session/revoke-all`;
356
- await this.client.post(endpoint, {}, {
356
+ const endpoint = this.emulatorUrl || `/api/auth/session/revoke-all`;
357
+ await this.client.post(endpoint, { projectId: this.projectId }, {
357
358
  headers: { Authorization: `Bearer ${token}` }
358
359
  });
359
360
  await this.signOut();
@@ -368,8 +369,8 @@ class Auth {
368
369
  this.currentSession = null;
369
370
  if (oldSession) {
370
371
  try {
371
- const endpoint = this.emulatorUrl || `/api/project/${this.projectId}/auth/logout`;
372
- await this.client.post(endpoint, { refreshToken: oldSession.refreshToken });
372
+ const endpoint = this.emulatorUrl || `/api/auth/logout`;
373
+ await this.client.post(endpoint, { refreshToken: oldSession.refreshToken, projectId: this.projectId });
373
374
  }
374
375
  catch {
375
376
  // Non-blocking logout network failure
@@ -0,0 +1,8 @@
1
+ import { StorageErrorCode } from './types';
2
+ export declare class NexaStorageError extends Error {
3
+ code: StorageErrorCode;
4
+ status?: number;
5
+ retryable: boolean;
6
+ cause?: any;
7
+ constructor(code: StorageErrorCode, message: string, status?: number, retryable?: boolean, cause?: any);
8
+ }
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NexaStorageError = void 0;
4
+ class NexaStorageError extends Error {
5
+ constructor(code, message, status, retryable = false, cause) {
6
+ super(message);
7
+ this.name = 'NexaStorageError';
8
+ this.code = code;
9
+ this.status = status;
10
+ this.retryable = retryable;
11
+ this.cause = cause;
12
+ }
13
+ }
14
+ exports.NexaStorageError = NexaStorageError;
@@ -1,9 +1,16 @@
1
1
  import { AxiosInstance } from 'axios';
2
+ import { UploadMetadata, StorageMetadata } from './types';
2
3
  import { UploadOptions } from '../types/index';
4
+ import { UploadTask } from './UploadTask';
5
+ import { IStorageReference } from './StorageReference';
3
6
  export declare class Storage {
4
7
  private projectId;
5
8
  private client;
9
+ emulatorUrl?: string;
6
10
  constructor(projectId: string, client: AxiosInstance);
11
+ ref(path: string): IStorageReference;
12
+ refFromURL(url: string): IStorageReference;
13
+ createUploadTask(path: string, file: File | Blob, metadata?: UploadMetadata): UploadTask;
7
14
  uploadFile(path: string, file: File | Blob, options?: UploadOptions): Promise<{
8
15
  url: string;
9
16
  path: string;
@@ -13,5 +20,9 @@ export declare class Storage {
13
20
  success: boolean;
14
21
  message?: string;
15
22
  }>;
23
+ getMetadata(path: string): Promise<StorageMetadata>;
24
+ updateMetadata(path: string, metadata: Partial<StorageMetadata>): Promise<StorageMetadata>;
25
+ list(path: string, options?: any): Promise<any>;
16
26
  }
17
27
  export declare const getStorage: (app: any) => Storage;
28
+ export declare const connectStorageEmulator: (storage: Storage, host: string, port: number) => void;
@@ -1,32 +1,36 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getStorage = exports.Storage = void 0;
3
+ exports.connectStorageEmulator = exports.getStorage = exports.Storage = void 0;
4
4
  const UploadTask_1 = require("./UploadTask");
5
- const NexaError_1 = require("../errors/NexaError");
5
+ const NexaStorageError_1 = require("./NexaStorageError");
6
+ const StorageReference_1 = require("./StorageReference");
6
7
  class Storage {
7
8
  constructor(projectId, client) {
8
9
  this.projectId = projectId;
9
10
  this.client = client;
10
11
  }
11
- async uploadFile(path, file, options) {
12
- try {
13
- const uploadTask = new UploadTask_1.UploadTask(path, file, options);
14
- const formData = new FormData();
15
- formData.append('file', file);
16
- formData.append('path', path);
17
- const res = await this.client.post(`/api/project/${this.projectId}/storage/upload`, formData, {
18
- onUploadProgress: (progressEvent) => {
19
- if (progressEvent.total) {
20
- const percent = Math.round((progressEvent.loaded * 100) / progressEvent.total);
21
- uploadTask.notifyProgress(percent);
22
- }
23
- }
24
- });
25
- return res.data;
26
- }
27
- catch (err) {
28
- throw (0, NexaError_1.toNexaError)(err);
12
+ ref(path) {
13
+ return new StorageReference_1.StorageReferenceImpl(path, this);
14
+ }
15
+ refFromURL(url) {
16
+ const match = url.match(/storage\/([^?]*)/);
17
+ if (match && match[1]) {
18
+ return this.ref(decodeURIComponent(match[1]));
29
19
  }
20
+ throw new NexaStorageError_1.NexaStorageError('storage/invalid-path', 'Invalid storage URL');
21
+ }
22
+ createUploadTask(path, file, metadata) {
23
+ const task = new UploadTask_1.UploadTask(this.projectId, this.client, path, file, metadata);
24
+ task.ref = this.ref(path);
25
+ return task;
26
+ }
27
+ // Legacy upload logic
28
+ async uploadFile(path, file, options) {
29
+ const task = this.createUploadTask(path, file);
30
+ task.options = options;
31
+ await task;
32
+ const url = await this.getDownloadURL(path);
33
+ return { url, path };
30
34
  }
31
35
  async getDownloadURL(path) {
32
36
  try {
@@ -34,7 +38,10 @@ class Storage {
34
38
  return res.data.url;
35
39
  }
36
40
  catch (err) {
37
- throw (0, NexaError_1.toNexaError)(err);
41
+ if (err.response) {
42
+ throw new NexaStorageError_1.NexaStorageError(err.response.data?.error?.code || 'storage/server-error', err.response.data?.error?.message || err.message);
43
+ }
44
+ throw new NexaStorageError_1.NexaStorageError('storage/network-error', err.message);
38
45
  }
39
46
  }
40
47
  async deleteFile(path) {
@@ -43,7 +50,43 @@ class Storage {
43
50
  return res.data;
44
51
  }
45
52
  catch (err) {
46
- throw (0, NexaError_1.toNexaError)(err);
53
+ if (err.response) {
54
+ throw new NexaStorageError_1.NexaStorageError(err.response.data?.error?.code || 'storage/server-error', err.response.data?.error?.message || err.message);
55
+ }
56
+ throw new NexaStorageError_1.NexaStorageError('storage/network-error', err.message);
57
+ }
58
+ }
59
+ async getMetadata(path) {
60
+ try {
61
+ const res = await this.client.get(`/api/project/${this.projectId}/storage/metadata?path=${encodeURIComponent(path)}`);
62
+ return res.data;
63
+ }
64
+ catch (err) {
65
+ if (err.response)
66
+ throw new NexaStorageError_1.NexaStorageError(err.response.data?.error?.code || 'storage/server-error', err.response.data?.error?.message || err.message);
67
+ throw new NexaStorageError_1.NexaStorageError('storage/network-error', err.message);
68
+ }
69
+ }
70
+ async updateMetadata(path, metadata) {
71
+ try {
72
+ const res = await this.client.put(`/api/project/${this.projectId}/storage/metadata?path=${encodeURIComponent(path)}`, metadata);
73
+ return res.data;
74
+ }
75
+ catch (err) {
76
+ if (err.response)
77
+ throw new NexaStorageError_1.NexaStorageError(err.response.data?.error?.code || 'storage/server-error', err.response.data?.error?.message || err.message);
78
+ throw new NexaStorageError_1.NexaStorageError('storage/network-error', err.message);
79
+ }
80
+ }
81
+ async list(path, options) {
82
+ try {
83
+ const res = await this.client.get(`/api/project/${this.projectId}/storage/list?path=${encodeURIComponent(path)}`);
84
+ return res.data;
85
+ }
86
+ catch (err) {
87
+ if (err.response)
88
+ throw new NexaStorageError_1.NexaStorageError(err.response.data?.error?.code || 'storage/server-error', err.response.data?.error?.message || err.message);
89
+ throw new NexaStorageError_1.NexaStorageError('storage/network-error', err.message);
47
90
  }
48
91
  }
49
92
  }
@@ -55,3 +98,15 @@ const getStorage = (app) => {
55
98
  throw new Error('Invalid NexaApp instance provided to getStorage()');
56
99
  };
57
100
  exports.getStorage = getStorage;
101
+ const connectStorageEmulator = (storage, host, port) => {
102
+ if (storage.emulatorUrl) {
103
+ throw new Error('Emulator already connected.');
104
+ }
105
+ storage.emulatorUrl = `http://${host}:${port}`;
106
+ // Modify the axios client inside storage to point to emulator
107
+ const client = storage.client;
108
+ if (client) {
109
+ client.defaults.baseURL = storage.emulatorUrl;
110
+ }
111
+ };
112
+ exports.connectStorageEmulator = connectStorageEmulator;
@@ -1,29 +1,47 @@
1
- import { StorageReference as IStorageReference, UploadOptions } from '../types/index';
2
1
  import { Storage } from './Storage';
3
- export declare class StorageReferenceImpl implements IStorageReference {
2
+ import { UploadTask } from './UploadTask';
3
+ import { UploadMetadata, StorageMetadata } from './types';
4
+ import { UploadOptions } from '../types/index';
5
+ export interface IStorageReference {
4
6
  path: string;
5
- private storage;
6
- constructor(path: string, storage: Storage);
7
- upload(file: File | Blob, options?: UploadOptions): Promise<{
7
+ put(file: File | Blob, metadata?: UploadMetadata): UploadTask;
8
+ putString(data: string, format?: string, metadata?: UploadMetadata): UploadTask;
9
+ getDownloadURL(): Promise<string>;
10
+ getMetadata(): Promise<StorageMetadata>;
11
+ updateMetadata(metadata: Partial<StorageMetadata>): Promise<StorageMetadata>;
12
+ delete(): Promise<{
13
+ success: boolean;
14
+ message?: string;
15
+ }>;
16
+ listAll(): Promise<any>;
17
+ list(options?: any): Promise<any>;
18
+ upload?: (file: File | Blob, options?: UploadOptions) => Promise<{
8
19
  url: string;
9
20
  path: string;
10
21
  }>;
22
+ }
23
+ export declare class StorageReferenceImpl implements IStorageReference {
24
+ path: string;
25
+ private storage;
26
+ constructor(path: string, storage: Storage);
27
+ put(file: File | Blob, metadata?: UploadMetadata): UploadTask;
28
+ putString(data: string, format?: string, metadata?: UploadMetadata): UploadTask;
11
29
  getDownloadURL(): Promise<string>;
30
+ getMetadata(): Promise<StorageMetadata>;
31
+ updateMetadata(metadata: Partial<StorageMetadata>): Promise<StorageMetadata>;
12
32
  delete(): Promise<{
13
33
  success: boolean;
14
34
  message?: string;
15
35
  }>;
36
+ listAll(): Promise<any>;
37
+ list(options?: any): Promise<any>;
38
+ upload(file: File | Blob, options?: UploadOptions): Promise<{
39
+ url: string;
40
+ path: string;
41
+ }>;
16
42
  }
17
- export declare const storageRef: (storage: Storage, path: string) => IStorageReference;
18
43
  export declare const ref: (storage: Storage, path: string) => IStorageReference;
19
- export declare const uploadBytes: (storageRef: IStorageReference, file: File | Blob, options?: UploadOptions) => Promise<{
20
- url: string;
21
- path: string;
22
- }>;
23
- export declare const uploadBytesResumable: (storageRef: IStorageReference, file: File | Blob, options?: UploadOptions) => Promise<{
24
- url: string;
25
- path: string;
26
- }>;
44
+ export declare const uploadBytes: (storageRef: IStorageReference, file: File | Blob, metadata?: UploadMetadata) => Promise<any>;
27
45
  export declare const getDownloadURL: (storageRef: IStorageReference) => Promise<string>;
28
46
  export declare const deleteObject: (storageRef: IStorageReference) => Promise<{
29
47
  success: boolean;
@@ -1,52 +1,72 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.deleteObject = exports.getDownloadURL = exports.uploadBytesResumable = exports.uploadBytes = exports.ref = exports.storageRef = exports.StorageReferenceImpl = void 0;
3
+ exports.deleteObject = exports.getDownloadURL = exports.uploadBytes = exports.ref = exports.StorageReferenceImpl = void 0;
4
4
  class StorageReferenceImpl {
5
5
  constructor(path, storage) {
6
6
  this.path = path;
7
7
  this.storage = storage;
8
8
  }
9
- async upload(file, options) {
10
- return this.storage.uploadFile(this.path, file, options);
9
+ put(file, metadata) {
10
+ return this.storage.createUploadTask(this.path, file, metadata);
11
+ }
12
+ putString(data, format = 'raw', metadata) {
13
+ let blob;
14
+ if (format === 'base64') {
15
+ const byteCharacters = atob(data);
16
+ const byteNumbers = new Array(byteCharacters.length);
17
+ for (let i = 0; i < byteCharacters.length; i++) {
18
+ byteNumbers[i] = byteCharacters.charCodeAt(i);
19
+ }
20
+ const byteArray = new Uint8Array(byteNumbers);
21
+ blob = new Blob([byteArray]);
22
+ }
23
+ else {
24
+ blob = new Blob([data]);
25
+ }
26
+ return this.put(blob, metadata);
11
27
  }
12
- async getDownloadURL() {
28
+ getDownloadURL() {
13
29
  return this.storage.getDownloadURL(this.path);
14
30
  }
15
- async delete() {
31
+ getMetadata() {
32
+ return this.storage.getMetadata(this.path);
33
+ }
34
+ updateMetadata(metadata) {
35
+ return this.storage.updateMetadata(this.path, metadata);
36
+ }
37
+ delete() {
16
38
  return this.storage.deleteFile(this.path);
17
39
  }
40
+ listAll() {
41
+ return this.storage.list(this.path);
42
+ }
43
+ list(options) {
44
+ return this.storage.list(this.path, options);
45
+ }
46
+ // Legacy for backward compatibility
47
+ async upload(file, options) {
48
+ const task = this.put(file, options);
49
+ task.options = options; // Inject legacy options
50
+ await task;
51
+ const url = await this.getDownloadURL();
52
+ return { url, path: this.path };
53
+ }
18
54
  }
19
55
  exports.StorageReferenceImpl = StorageReferenceImpl;
20
- const storageRef = (storage, path) => {
21
- return new StorageReferenceImpl(path, storage);
22
- };
23
- exports.storageRef = storageRef;
24
56
  const ref = (storage, path) => {
25
57
  return new StorageReferenceImpl(path, storage);
26
58
  };
27
59
  exports.ref = ref;
28
- const uploadBytes = async (storageRef, file, options) => {
29
- if (storageRef.upload) {
30
- return storageRef.upload(file, options);
31
- }
32
- throw new Error('Invalid storage reference');
60
+ const uploadBytes = async (storageRef, file, metadata) => {
61
+ const task = storageRef.put(file, metadata);
62
+ return await task;
33
63
  };
34
64
  exports.uploadBytes = uploadBytes;
35
- const uploadBytesResumable = (storageRef, file, options) => {
36
- return (0, exports.uploadBytes)(storageRef, file, options);
37
- };
38
- exports.uploadBytesResumable = uploadBytesResumable;
39
65
  const getDownloadURL = async (storageRef) => {
40
- if (storageRef.getDownloadURL) {
41
- return storageRef.getDownloadURL();
42
- }
43
- throw new Error('Invalid storage reference');
66
+ return storageRef.getDownloadURL();
44
67
  };
45
68
  exports.getDownloadURL = getDownloadURL;
46
69
  const deleteObject = async (storageRef) => {
47
- if (storageRef.delete) {
48
- return storageRef.delete();
49
- }
50
- throw new Error('Invalid storage reference');
70
+ return storageRef.delete();
51
71
  };
52
72
  exports.deleteObject = deleteObject;
@@ -1,10 +1,37 @@
1
+ import { AxiosInstance } from 'axios';
2
+ import { UploadMetadata, UploadTaskSnapshot } from './types';
1
3
  import { UploadOptions } from '../types/index';
2
- export declare class UploadTask {
4
+ import { NexaStorageError } from './NexaStorageError';
5
+ export declare class UploadTask implements PromiseLike<UploadTaskSnapshot> {
3
6
  private file;
4
7
  private path;
5
- private options?;
6
- constructor(path: string, file: File | Blob, options?: UploadOptions);
7
- getFile(): File | Blob;
8
- getPath(): string;
9
- notifyProgress(percent: number): void;
8
+ options?: UploadOptions;
9
+ private metadata?;
10
+ private client;
11
+ private projectId;
12
+ private state;
13
+ private bytesTransferred;
14
+ private totalBytes;
15
+ private sessionUrl;
16
+ private abortController;
17
+ private listeners;
18
+ private errorListeners;
19
+ private completeListeners;
20
+ private _promise;
21
+ ref: any;
22
+ constructor(projectId: string, client: AxiosInstance, path: string, file: File | Blob, metadata?: UploadMetadata, options?: UploadOptions);
23
+ on(event: 'state_changed', nextOrObserver?: ((snapshot: UploadTaskSnapshot) => void) | {
24
+ next?: (s: UploadTaskSnapshot) => void;
25
+ error?: (e: NexaStorageError) => void;
26
+ complete?: () => void;
27
+ }, error?: (error: NexaStorageError) => void, complete?: () => void): () => void;
28
+ private startPromise;
29
+ then<TResult1 = UploadTaskSnapshot, TResult2 = never>(onfulfilled?: ((value: UploadTaskSnapshot) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
30
+ catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | null): Promise<UploadTaskSnapshot | TResult>;
31
+ private _executeUpload;
32
+ pause(): void;
33
+ resume(): void;
34
+ cancel(): void;
35
+ getSnapshot(): UploadTaskSnapshot;
36
+ private notify;
10
37
  }
@@ -1,21 +1,140 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.UploadTask = void 0;
4
+ const NexaStorageError_1 = require("./NexaStorageError");
4
5
  class UploadTask {
5
- constructor(path, file, options) {
6
+ constructor(projectId, client, path, file, metadata, options) {
7
+ this.state = 'running';
8
+ this.bytesTransferred = 0;
9
+ this.totalBytes = 0;
10
+ this.sessionUrl = null;
11
+ this.listeners = [];
12
+ this.errorListeners = [];
13
+ this.completeListeners = [];
14
+ this._promise = null;
15
+ this.projectId = projectId;
16
+ this.client = client;
6
17
  this.path = path;
7
18
  this.file = file;
19
+ this.metadata = metadata;
8
20
  this.options = options;
21
+ this.totalBytes = file.size;
22
+ this.abortController = new AbortController();
9
23
  }
10
- getFile() {
11
- return this.file;
24
+ on(event, nextOrObserver, error, complete) {
25
+ if (typeof nextOrObserver === 'function') {
26
+ this.listeners.push(nextOrObserver);
27
+ if (error)
28
+ this.errorListeners.push(error);
29
+ if (complete)
30
+ this.completeListeners.push(complete);
31
+ }
32
+ else if (nextOrObserver) {
33
+ if (nextOrObserver.next)
34
+ this.listeners.push(nextOrObserver.next);
35
+ if (nextOrObserver.error)
36
+ this.errorListeners.push(nextOrObserver.error);
37
+ if (nextOrObserver.complete)
38
+ this.completeListeners.push(nextOrObserver.complete);
39
+ }
40
+ // Auto start if not started
41
+ this.startPromise();
42
+ return () => {
43
+ this.listeners = [];
44
+ this.errorListeners = [];
45
+ this.completeListeners = [];
46
+ };
47
+ }
48
+ startPromise() {
49
+ if (!this._promise) {
50
+ this._promise = this._executeUpload();
51
+ }
52
+ return this._promise;
53
+ }
54
+ then(onfulfilled, onrejected) {
55
+ return this.startPromise().then(onfulfilled, onrejected);
56
+ }
57
+ catch(onrejected) {
58
+ return this.startPromise().catch(onrejected);
59
+ }
60
+ async _executeUpload() {
61
+ try {
62
+ this.state = 'running';
63
+ this.notify();
64
+ const sessionRes = await this.client.post(`/api/project/${this.projectId}/storage/upload/session`, {
65
+ path: this.path,
66
+ metadata: {
67
+ contentType: this.file.type,
68
+ ...this.metadata
69
+ }
70
+ }, { signal: this.abortController.signal });
71
+ this.sessionUrl = sessionRes.data.sessionUrl;
72
+ const uploadRes = await this.client.put(this.sessionUrl, this.file, {
73
+ headers: {
74
+ 'Content-Type': 'application/octet-stream',
75
+ 'x-upload-final': 'true'
76
+ },
77
+ signal: this.abortController.signal,
78
+ onUploadProgress: (progressEvent) => {
79
+ if (progressEvent.total) {
80
+ this.bytesTransferred = progressEvent.loaded;
81
+ this.notify();
82
+ }
83
+ }
84
+ });
85
+ this.state = 'success';
86
+ this.bytesTransferred = this.totalBytes;
87
+ const finalSnapshot = this.getSnapshot();
88
+ finalSnapshot.metadata = uploadRes.data.metadata;
89
+ this.notify();
90
+ this.completeListeners.forEach(cb => cb());
91
+ return finalSnapshot;
92
+ }
93
+ catch (err) {
94
+ this.state = 'error';
95
+ let nexaErr = new NexaStorageError_1.NexaStorageError('storage/network-error', err.message);
96
+ if (err.response) {
97
+ nexaErr = new NexaStorageError_1.NexaStorageError(err.response.data?.error?.code || 'storage/server-error', err.response.data?.error?.message || err.message, err.response.status);
98
+ }
99
+ this.errorListeners.forEach(cb => cb(nexaErr));
100
+ throw nexaErr;
101
+ }
102
+ }
103
+ pause() {
104
+ if (this.state === 'running') {
105
+ this.state = 'paused';
106
+ this.notify();
107
+ }
108
+ }
109
+ resume() {
110
+ if (this.state === 'paused') {
111
+ this.state = 'running';
112
+ this.notify();
113
+ }
114
+ }
115
+ cancel() {
116
+ if (this.state === 'running' || this.state === 'paused') {
117
+ this.state = 'canceled';
118
+ this.abortController.abort();
119
+ this.notify();
120
+ const err = new NexaStorageError_1.NexaStorageError('storage/canceled', 'Upload canceled');
121
+ this.errorListeners.forEach(cb => cb(err));
122
+ }
12
123
  }
13
- getPath() {
14
- return this.path;
124
+ getSnapshot() {
125
+ return {
126
+ bytesTransferred: this.bytesTransferred,
127
+ totalBytes: this.totalBytes,
128
+ state: this.state,
129
+ task: this,
130
+ ref: this.ref
131
+ };
15
132
  }
16
- notifyProgress(percent) {
17
- if (this.options && this.options.onProgress) {
18
- this.options.onProgress(percent);
133
+ notify() {
134
+ const snap = this.getSnapshot();
135
+ this.listeners.forEach(cb => cb(snap));
136
+ if (this.options?.onProgress) {
137
+ this.options.onProgress(Math.round((snap.bytesTransferred / snap.totalBytes) * 100));
19
138
  }
20
139
  }
21
140
  }
@@ -0,0 +1,36 @@
1
+ export type StorageErrorCode = 'storage/unauthenticated' | 'storage/unauthorized' | 'storage/object-not-found' | 'storage/object-already-exists' | 'storage/invalid-path' | 'storage/invalid-file' | 'storage/invalid-metadata' | 'storage/invalid-checksum' | 'storage/quota-exceeded' | 'storage/upload-session-expired' | 'storage/retry-limit-exceeded' | 'storage/canceled' | 'storage/conflict' | 'storage/network-error' | 'storage/server-error';
2
+ export interface StorageMetadata {
3
+ name: string;
4
+ bucket: string;
5
+ generation: string;
6
+ metageneration: string;
7
+ fullPath: string;
8
+ size: number;
9
+ timeCreated: string;
10
+ updated: string;
11
+ md5Hash?: string;
12
+ cacheControl?: string;
13
+ contentDisposition?: string;
14
+ contentEncoding?: string;
15
+ contentLanguage?: string;
16
+ contentType?: string;
17
+ customMetadata?: Record<string, string>;
18
+ }
19
+ export interface UploadMetadata {
20
+ md5Hash?: string;
21
+ cacheControl?: string;
22
+ contentDisposition?: string;
23
+ contentEncoding?: string;
24
+ contentLanguage?: string;
25
+ contentType?: string;
26
+ customMetadata?: Record<string, string>;
27
+ }
28
+ export type TaskState = 'running' | 'paused' | 'success' | 'canceled' | 'error';
29
+ export interface UploadTaskSnapshot {
30
+ bytesTransferred: number;
31
+ totalBytes: number;
32
+ state: TaskState;
33
+ metadata?: StorageMetadata;
34
+ task: any;
35
+ ref: any;
36
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -2,7 +2,9 @@ import { AxiosInstance } from 'axios';
2
2
  export declare class HttpClient {
3
3
  private client;
4
4
  private getToken;
5
- constructor(endpoint: string, getTokenFn: () => string | null);
5
+ private projectId?;
6
+ private apiKey?;
7
+ constructor(endpoint: string, getTokenFn: () => string | null, projectId?: string, apiKey?: string | null);
6
8
  getAxiosInstance(): AxiosInstance;
7
9
  setBaseURL(url: string): void;
8
10
  }
@@ -6,18 +6,28 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.HttpClient = void 0;
7
7
  const axios_1 = __importDefault(require("axios"));
8
8
  class HttpClient {
9
- constructor(endpoint, getTokenFn) {
9
+ constructor(endpoint, getTokenFn, projectId, apiKey) {
10
10
  this.getToken = getTokenFn;
11
+ this.projectId = projectId;
12
+ this.apiKey = apiKey;
11
13
  this.client = axios_1.default.create({
12
14
  baseURL: endpoint,
13
- timeout: 6000
15
+ timeout: 10000
14
16
  });
15
17
  this.client.interceptors.request.use((req) => {
16
18
  const activeToken = this.getToken();
17
19
  if (activeToken) {
18
20
  req.headers.Authorization = `Bearer ${activeToken}`;
21
+ }
22
+ if (this.apiKey) {
23
+ req.headers['x-api-key'] = this.apiKey;
24
+ }
25
+ else if (activeToken) {
19
26
  req.headers['x-api-key'] = activeToken;
20
27
  }
28
+ if (this.projectId) {
29
+ req.headers['x-project-id'] = this.projectId;
30
+ }
21
31
  if (typeof FormData !== 'undefined' && req.data instanceof FormData) {
22
32
  if (req.headers) {
23
33
  delete req.headers['Content-Type'];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexabase-console",
3
- "version": "2.0.3",
3
+ "version": "2.0.5",
4
4
  "description": "SDK Client resmi untuk NexaBase: Platform Sinkronisasi NoSQL, Realtime, File Storage, & Autentikasi Offline-First.",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",