nexabase-console 1.1.4 → 2.0.0

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.
Files changed (72) hide show
  1. package/README.md +33 -8
  2. package/dist/app/NexaApp.d.ts +63 -0
  3. package/dist/app/NexaApp.js +184 -0
  4. package/dist/app/initializeApp.d.ts +8 -0
  5. package/dist/app/initializeApp.js +27 -0
  6. package/dist/auth/Auth.d.ts +21 -0
  7. package/dist/auth/Auth.js +73 -0
  8. package/dist/auth/authTypes.d.ts +1 -0
  9. package/dist/auth/authTypes.js +2 -0
  10. package/dist/auth/persistence.d.ts +9 -0
  11. package/dist/auth/persistence.js +34 -0
  12. package/dist/errors/NexaError.d.ts +7 -0
  13. package/dist/errors/NexaError.js +61 -0
  14. package/dist/firestore/CollectionReference.d.ts +3 -0
  15. package/dist/firestore/CollectionReference.js +7 -0
  16. package/dist/firestore/DocumentReference.d.ts +3 -0
  17. package/dist/firestore/DocumentReference.js +22 -0
  18. package/dist/firestore/FieldPath.d.ts +7 -0
  19. package/dist/firestore/FieldPath.js +23 -0
  20. package/dist/firestore/FieldValue.d.ts +11 -0
  21. package/dist/firestore/FieldValue.js +21 -0
  22. package/dist/firestore/Firestore.d.ts +8 -0
  23. package/dist/firestore/Firestore.js +24 -0
  24. package/dist/firestore/GeoPoint.d.ts +10 -0
  25. package/dist/firestore/GeoPoint.js +22 -0
  26. package/dist/firestore/Query.d.ts +4 -0
  27. package/dist/firestore/Query.js +172 -0
  28. package/dist/firestore/Snapshot.d.ts +6 -0
  29. package/dist/firestore/Snapshot.js +126 -0
  30. package/dist/firestore/SnapshotManager.d.ts +9 -0
  31. package/dist/firestore/SnapshotManager.js +37 -0
  32. package/dist/firestore/Timestamp.d.ts +16 -0
  33. package/dist/firestore/Timestamp.js +36 -0
  34. package/dist/firestore/batch.d.ts +3 -0
  35. package/dist/firestore/batch.js +79 -0
  36. package/dist/firestore/queryConstraints.d.ts +9 -0
  37. package/dist/firestore/queryConstraints.js +31 -0
  38. package/dist/firestore/transaction.d.ts +5 -0
  39. package/dist/firestore/transaction.js +71 -0
  40. package/dist/firestore/writes.d.ts +15 -0
  41. package/dist/firestore/writes.js +146 -0
  42. package/dist/index.d.ts +34 -206
  43. package/dist/index.js +56 -1022
  44. package/dist/persistence/IndexedDB.d.ts +8 -0
  45. package/dist/persistence/IndexedDB.js +37 -0
  46. package/dist/persistence/LocalStore.d.ts +12 -0
  47. package/dist/persistence/LocalStore.js +78 -0
  48. package/dist/persistence/MutationQueue.d.ts +22 -0
  49. package/dist/persistence/MutationQueue.js +145 -0
  50. package/dist/realtime/RealtimeConnection.d.ts +7 -0
  51. package/dist/realtime/RealtimeConnection.js +19 -0
  52. package/dist/realtime/RealtimeDatabase.d.ts +10 -0
  53. package/dist/realtime/RealtimeDatabase.js +62 -0
  54. package/dist/storage/Storage.d.ts +12 -0
  55. package/dist/storage/Storage.js +41 -0
  56. package/dist/storage/StorageReference.d.ts +13 -0
  57. package/dist/storage/StorageReference.js +20 -0
  58. package/dist/storage/UploadTask.d.ts +10 -0
  59. package/dist/storage/UploadTask.js +22 -0
  60. package/dist/sync/ConflictResolver.d.ts +3 -0
  61. package/dist/sync/ConflictResolver.js +24 -0
  62. package/dist/sync/SyncEngine.d.ts +13 -0
  63. package/dist/sync/SyncEngine.js +47 -0
  64. package/dist/transport/HttpClient.d.ts +8 -0
  65. package/dist/transport/HttpClient.js +42 -0
  66. package/dist/transport/SSEClient.d.ts +15 -0
  67. package/dist/transport/SSEClient.js +96 -0
  68. package/dist/types/index.d.ts +150 -0
  69. package/dist/types/index.js +2 -0
  70. package/dist/utils/helpers.d.ts +7 -0
  71. package/dist/utils/helpers.js +124 -0
  72. package/package.json +1 -1
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.HttpClient = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ class HttpClient {
9
+ constructor(endpoint, getTokenFn) {
10
+ this.getToken = getTokenFn;
11
+ this.client = axios_1.default.create({
12
+ baseURL: endpoint,
13
+ timeout: 6000
14
+ });
15
+ this.client.interceptors.request.use((req) => {
16
+ const activeToken = this.getToken();
17
+ if (activeToken) {
18
+ req.headers.Authorization = `Bearer ${activeToken}`;
19
+ req.headers['x-api-key'] = activeToken;
20
+ }
21
+ if (typeof FormData !== 'undefined' && req.data instanceof FormData) {
22
+ if (req.headers) {
23
+ delete req.headers['Content-Type'];
24
+ delete req.headers['content-type'];
25
+ }
26
+ }
27
+ else {
28
+ if (req.data && req.headers && !req.headers['Content-Type'] && !req.headers['content-type']) {
29
+ req.headers['Content-Type'] = 'application/json';
30
+ }
31
+ }
32
+ return req;
33
+ });
34
+ }
35
+ getAxiosInstance() {
36
+ return this.client;
37
+ }
38
+ setBaseURL(url) {
39
+ this.client.defaults.baseURL = url;
40
+ }
41
+ }
42
+ exports.HttpClient = HttpClient;
@@ -0,0 +1,15 @@
1
+ export declare class SSEClient {
2
+ private projectId;
3
+ private sseUrl;
4
+ private sse;
5
+ private isListening;
6
+ private listeners;
7
+ constructor(projectId: string, sseUrl: string);
8
+ addListener(event: string, callback: (data: any) => void): () => void;
9
+ ensureConnected(): void;
10
+ checkCloseConnection(): void;
11
+ hasListeners(): boolean;
12
+ dispatch(event: string, data: any): void;
13
+ close(): void;
14
+ }
15
+ export { SSEClient as SSEManager };
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SSEManager = exports.SSEClient = void 0;
4
+ class SSEClient {
5
+ constructor(projectId, sseUrl) {
6
+ this.sse = null;
7
+ this.isListening = false;
8
+ this.listeners = new Map();
9
+ this.projectId = projectId;
10
+ this.sseUrl = sseUrl;
11
+ }
12
+ addListener(event, callback) {
13
+ if (!this.listeners.has(event)) {
14
+ this.listeners.set(event, new Set());
15
+ }
16
+ this.listeners.get(event).add(callback);
17
+ this.ensureConnected();
18
+ return () => {
19
+ const callbacks = this.listeners.get(event);
20
+ if (callbacks) {
21
+ callbacks.delete(callback);
22
+ if (callbacks.size === 0) {
23
+ this.listeners.delete(event);
24
+ }
25
+ }
26
+ this.checkCloseConnection();
27
+ };
28
+ }
29
+ ensureConnected() {
30
+ if (this.isListening || typeof window === 'undefined')
31
+ return;
32
+ this.isListening = true;
33
+ this.sse = new EventSource(`${this.sseUrl}/api/firestore/${this.projectId}/sse`);
34
+ this.sse.onopen = () => {
35
+ this.dispatch('open', null);
36
+ };
37
+ this.sse.onmessage = (event) => {
38
+ try {
39
+ const payload = JSON.parse(event.data);
40
+ this.dispatch(payload.event || 'message', payload.data || payload);
41
+ this.dispatch('all', payload);
42
+ }
43
+ catch (e) {
44
+ console.error('[SSEClient] Error parsing SSE payload:', e);
45
+ }
46
+ };
47
+ this.sse.onerror = (err) => {
48
+ this.dispatch('error', err);
49
+ if (this.sse) {
50
+ this.sse.close();
51
+ this.sse = null;
52
+ }
53
+ this.isListening = false;
54
+ if (this.hasListeners()) {
55
+ setTimeout(() => this.ensureConnected(), 3000);
56
+ }
57
+ };
58
+ }
59
+ checkCloseConnection() {
60
+ if (!this.hasListeners() && this.sse) {
61
+ this.sse.close();
62
+ this.sse = null;
63
+ this.isListening = false;
64
+ }
65
+ }
66
+ hasListeners() {
67
+ let count = 0;
68
+ this.listeners.forEach((set) => {
69
+ count += set.size;
70
+ });
71
+ return count > 0;
72
+ }
73
+ dispatch(event, data) {
74
+ const callbacks = this.listeners.get(event);
75
+ if (callbacks) {
76
+ callbacks.forEach((cb) => {
77
+ try {
78
+ cb(data);
79
+ }
80
+ catch (e) {
81
+ console.error(`[SSEClient] Error in listener for event ${event}:`, e);
82
+ }
83
+ });
84
+ }
85
+ }
86
+ close() {
87
+ if (this.sse) {
88
+ this.sse.close();
89
+ this.sse = null;
90
+ }
91
+ this.isListening = false;
92
+ this.listeners.clear();
93
+ }
94
+ }
95
+ exports.SSEClient = SSEClient;
96
+ exports.SSEManager = SSEClient;
@@ -0,0 +1,150 @@
1
+ import type { NexaApp } from '../app/NexaApp';
2
+ import type { FieldPath } from '../firestore/FieldPath';
3
+ export interface NexaConfig {
4
+ projectId: string;
5
+ apiKey?: string;
6
+ endpoint?: string;
7
+ enablePersistence?: boolean;
8
+ cacheStrategy?: 'network-first' | 'cache-first';
9
+ }
10
+ export interface User {
11
+ id: string;
12
+ email: string;
13
+ name?: string;
14
+ role?: string;
15
+ createdAt?: string;
16
+ [key: string]: any;
17
+ }
18
+ export interface AuthResponse {
19
+ token: string;
20
+ user: User;
21
+ expiresIn?: number;
22
+ }
23
+ export type WhereFilterOp = '<' | '<=' | '==' | '!=' | '>=' | '>' | 'array-contains' | 'array-contains-any' | 'in' | 'not-in';
24
+ export interface QueryConstraint {
25
+ type: 'where' | 'orderBy' | 'limit' | 'startAt' | 'startAfter' | 'endAt' | 'endBefore';
26
+ fieldPath?: string | FieldPath;
27
+ opStr?: WhereFilterOp | string;
28
+ value?: any;
29
+ directionStr?: 'asc' | 'desc';
30
+ limitValue?: number;
31
+ docSnapshot?: any;
32
+ }
33
+ export interface SnapshotMetadata {
34
+ readonly hasPendingWrites: boolean;
35
+ readonly fromCache: boolean;
36
+ }
37
+ export interface DocumentChange<T = any> {
38
+ type: 'added' | 'modified' | 'removed';
39
+ doc: QueryDocumentSnapshot<T>;
40
+ oldIndex: number;
41
+ newIndex: number;
42
+ }
43
+ export interface DocumentReference<T = any> {
44
+ type: 'document';
45
+ path: string;
46
+ db: NexaApp;
47
+ patch?: (data: Partial<T>) => Promise<any>;
48
+ }
49
+ export interface CollectionReference<T = any> {
50
+ type: 'collection';
51
+ path: string;
52
+ db: NexaApp;
53
+ }
54
+ export interface Query<T = any> {
55
+ type: 'query' | 'collection';
56
+ path: string;
57
+ db: NexaApp;
58
+ constraints?: QueryConstraint[];
59
+ }
60
+ export interface SnapshotOptions {
61
+ serverTimestamps?: 'estimate' | 'previous' | 'none';
62
+ }
63
+ export interface DocumentSnapshot<T = any> {
64
+ id: string;
65
+ ref: DocumentReference<T>;
66
+ metadata: SnapshotMetadata;
67
+ exists: () => boolean;
68
+ data: (options?: SnapshotOptions) => T | null;
69
+ get: (fieldPath: string | FieldPath) => any;
70
+ }
71
+ export interface QueryDocumentSnapshot<T = any> {
72
+ id: string;
73
+ ref: DocumentReference<T>;
74
+ metadata: SnapshotMetadata;
75
+ exists: () => boolean;
76
+ data: (options?: SnapshotOptions) => T;
77
+ get: (fieldPath: string | FieldPath) => any;
78
+ }
79
+ export interface QuerySnapshot<T = any> {
80
+ docs: QueryDocumentSnapshot<T>[];
81
+ forEach: (callback: (doc: QueryDocumentSnapshot<T>) => void) => void;
82
+ empty: boolean;
83
+ size: number;
84
+ metadata: SnapshotMetadata;
85
+ docChanges: () => DocumentChange<T>[];
86
+ }
87
+ export interface DatabaseReference {
88
+ path: string;
89
+ get: () => Promise<any>;
90
+ set: (data: any) => Promise<any>;
91
+ update: (data: any) => Promise<any>;
92
+ delete?: () => Promise<any>;
93
+ remove: () => Promise<any>;
94
+ onDataChanged?: (callback: (data: any) => void) => () => void;
95
+ onValue?: (callback: (data: any) => void) => () => void;
96
+ }
97
+ export interface UploadOptions {
98
+ contextType?: 'chat' | 'public_post';
99
+ contextId?: string;
100
+ fileId?: string;
101
+ onProgress?: (percent: number) => void;
102
+ }
103
+ export interface StorageReference {
104
+ path?: string;
105
+ name?: string;
106
+ fullPath?: string;
107
+ upload?: (file: File | Blob, options?: UploadOptions) => Promise<{
108
+ url: string;
109
+ path: string;
110
+ }>;
111
+ getDownloadURL?: () => Promise<string>;
112
+ put?: (file: File | Blob, options?: UploadOptions | ((percent: number) => void), onProgress?: (percent: number) => void) => Promise<{
113
+ url: string;
114
+ success: boolean;
115
+ fileId?: string;
116
+ proxyViewUrl?: string;
117
+ proxyDownloadUrl?: string;
118
+ metadata?: any;
119
+ }>;
120
+ delete?: () => Promise<{
121
+ success: boolean;
122
+ message?: string;
123
+ }>;
124
+ }
125
+ export interface WriteBatch {
126
+ set: (docRef: DocumentReference, data: any) => WriteBatch;
127
+ update: (docRef: DocumentReference, data: any) => WriteBatch;
128
+ patch: (docRef: DocumentReference, data: any) => WriteBatch;
129
+ delete: (docRef: DocumentReference) => WriteBatch;
130
+ commit: () => Promise<any>;
131
+ }
132
+ export interface OfflineJob {
133
+ id: string;
134
+ type: 'set' | 'update' | 'patch' | 'delete';
135
+ path: string;
136
+ data?: any;
137
+ idempotencyKey?: string;
138
+ timestamp?: number;
139
+ merge?: boolean;
140
+ state?: 'pending' | 'acknowledged' | 'rejected';
141
+ retryCount?: number;
142
+ lastError?: string;
143
+ }
144
+ export interface Transaction {
145
+ get: <T = any>(docRef: DocumentReference<T>) => Promise<DocumentSnapshot<T>>;
146
+ set: (docRef: DocumentReference, data: any) => Transaction;
147
+ update: (docRef: DocumentReference, data: any) => Transaction;
148
+ patch: (docRef: DocumentReference, data: any) => Transaction;
149
+ delete: (docRef: DocumentReference) => Transaction;
150
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,7 @@
1
+ import { FieldPath } from '../firestore/FieldPath';
2
+ import { DocumentChange } from '../types/index';
3
+ export declare function getNestedValue(obj: any, path: string | FieldPath, docId?: string): any;
4
+ export declare function deepEqual(a: any, b: any): boolean;
5
+ export declare function applyDataTransforms(existingData: any, updateData: any): any;
6
+ export declare function calculateDocChanges(oldDocs: any[], newDocs: any[]): DocumentChange[];
7
+ export declare function generateIdempotencyKey(): string;
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getNestedValue = getNestedValue;
4
+ exports.deepEqual = deepEqual;
5
+ exports.applyDataTransforms = applyDataTransforms;
6
+ exports.calculateDocChanges = calculateDocChanges;
7
+ exports.generateIdempotencyKey = generateIdempotencyKey;
8
+ const Timestamp_1 = require("../firestore/Timestamp");
9
+ function getNestedValue(obj, path, docId) {
10
+ if (!obj || !path)
11
+ return undefined;
12
+ const pathStr = typeof path === 'string' ? path : path.getPathString();
13
+ if (pathStr === '__name__') {
14
+ return docId || obj.id || obj.__name__;
15
+ }
16
+ return pathStr.split('.').reduce((prev, curr) => (prev ? prev[curr] : undefined), obj);
17
+ }
18
+ function deepEqual(a, b) {
19
+ if (a === b)
20
+ return true;
21
+ if (typeof a !== 'object' || a === null || typeof b !== 'object' || b === null)
22
+ return false;
23
+ if (typeof a.isEqual === 'function') {
24
+ return a.isEqual(b);
25
+ }
26
+ if (typeof b.isEqual === 'function') {
27
+ return b.isEqual(a);
28
+ }
29
+ if (Array.isArray(a)) {
30
+ if (!Array.isArray(b) || a.length !== b.length)
31
+ return false;
32
+ for (let i = 0; i < a.length; i++) {
33
+ if (!deepEqual(a[i], b[i]))
34
+ return false;
35
+ }
36
+ return true;
37
+ }
38
+ const keysA = Object.keys(a);
39
+ const keysB = Object.keys(b);
40
+ if (keysA.length !== keysB.length)
41
+ return false;
42
+ for (const key of keysA) {
43
+ if (!Object.prototype.hasOwnProperty.call(b, key) || !deepEqual(a[key], b[key]))
44
+ return false;
45
+ }
46
+ return true;
47
+ }
48
+ function applyDataTransforms(existingData, updateData) {
49
+ const result = { ...existingData };
50
+ const processNode = (obj, keyPath, value) => {
51
+ const current = keyPath[0];
52
+ if (keyPath.length === 1) {
53
+ if (value && typeof value === 'object' && value._isFieldValue) {
54
+ const fv = value;
55
+ if (fv.method === 'serverTimestamp') {
56
+ obj[current] = Timestamp_1.Timestamp.now();
57
+ }
58
+ else if (fv.method === 'increment') {
59
+ obj[current] = (typeof obj[current] === 'number' ? obj[current] : 0) + (fv.value || 1);
60
+ }
61
+ else if (fv.method === 'arrayUnion') {
62
+ const arr = Array.isArray(obj[current]) ? obj[current] : [];
63
+ obj[current] = [...new Set([...arr, ...(fv.value || [])])];
64
+ }
65
+ else if (fv.method === 'arrayRemove') {
66
+ const arr = Array.isArray(obj[current]) ? obj[current] : [];
67
+ const toRemove = new Set(fv.value || []);
68
+ obj[current] = arr.filter((x) => !toRemove.has(x));
69
+ }
70
+ else if (fv.method === 'deleteField') {
71
+ delete obj[current];
72
+ }
73
+ }
74
+ else if (value && typeof value === 'object' && !Array.isArray(value) && typeof value.isEqual !== 'function') {
75
+ if (!obj[current] || typeof obj[current] !== 'object')
76
+ obj[current] = {};
77
+ for (const [k, v] of Object.entries(value)) {
78
+ processNode(obj[current], [k], v);
79
+ }
80
+ }
81
+ else {
82
+ obj[current] = value;
83
+ }
84
+ }
85
+ else {
86
+ if (!obj[current] || typeof obj[current] !== 'object')
87
+ obj[current] = {};
88
+ processNode(obj[current], keyPath.slice(1), value);
89
+ }
90
+ };
91
+ for (const [key, val] of Object.entries(updateData)) {
92
+ processNode(result, key.split('.'), val);
93
+ }
94
+ return result;
95
+ }
96
+ function calculateDocChanges(oldDocs, newDocs) {
97
+ const changes = [];
98
+ const oldMap = new Map(oldDocs.map(d => [d.id, d]));
99
+ const newMap = new Map(newDocs.map(d => [d.id, d]));
100
+ oldDocs.forEach((oldDoc, oldIndex) => {
101
+ if (!newMap.has(oldDoc.id)) {
102
+ changes.push({ type: 'removed', doc: oldDoc.doc, oldIndex, newIndex: -1 });
103
+ }
104
+ });
105
+ newDocs.forEach((newDoc, newIndex) => {
106
+ const oldDoc = oldMap.get(newDoc.id);
107
+ if (!oldDoc) {
108
+ changes.push({ type: 'added', doc: newDoc.doc, oldIndex: -1, newIndex });
109
+ }
110
+ else {
111
+ if (!deepEqual(oldDoc.data, newDoc.data)) {
112
+ const oldIndex = oldDocs.findIndex(d => d.id === oldDoc.id);
113
+ changes.push({ type: 'modified', doc: newDoc.doc, oldIndex, newIndex });
114
+ }
115
+ }
116
+ });
117
+ return changes;
118
+ }
119
+ function generateIdempotencyKey() {
120
+ if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
121
+ return crypto.randomUUID();
122
+ }
123
+ return `nexa_idemp_${Date.now()}_${Math.random().toString(36).substring(2, 9)}_${Math.floor(Math.random() * 1000000)}`;
124
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexabase-console",
3
- "version": "1.1.4",
3
+ "version": "2.0.0",
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",