@edgebasejs/adapter-d1 0.1.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.
- package/dist/adapter-d1/src/d1-adapter.d.ts +29 -0
- package/dist/adapter-d1/src/d1-adapter.d.ts.map +1 -0
- package/dist/adapter-d1/src/d1-adapter.js +36 -0
- package/dist/adapter-d1/src/d1-adapter.js.map +1 -0
- package/dist/adapter-d1/src/index.d.ts +3 -0
- package/dist/adapter-d1/src/index.d.ts.map +1 -0
- package/dist/adapter-d1/src/index.js +3 -0
- package/dist/adapter-d1/src/index.js.map +1 -0
- package/dist/adapter-d1/src/schema-to-sql.d.ts +18 -0
- package/dist/adapter-d1/src/schema-to-sql.d.ts.map +1 -0
- package/dist/adapter-d1/src/schema-to-sql.js +304 -0
- package/dist/adapter-d1/src/schema-to-sql.js.map +1 -0
- package/dist/core/src/access-rules/column-security.d.ts +80 -0
- package/dist/core/src/access-rules/column-security.d.ts.map +1 -0
- package/dist/core/src/access-rules/column-security.js +191 -0
- package/dist/core/src/access-rules/column-security.js.map +1 -0
- package/dist/core/src/access-rules/engine.d.ts +26 -0
- package/dist/core/src/access-rules/engine.d.ts.map +1 -0
- package/dist/core/src/access-rules/engine.js +76 -0
- package/dist/core/src/access-rules/engine.js.map +1 -0
- package/dist/core/src/access-rules/index.d.ts +3 -0
- package/dist/core/src/access-rules/index.d.ts.map +1 -0
- package/dist/core/src/access-rules/index.js +3 -0
- package/dist/core/src/access-rules/index.js.map +1 -0
- package/dist/core/src/audit/audit-manager.d.ts +108 -0
- package/dist/core/src/audit/audit-manager.d.ts.map +1 -0
- package/dist/core/src/audit/audit-manager.js +265 -0
- package/dist/core/src/audit/audit-manager.js.map +1 -0
- package/dist/core/src/auth/auth-service.d.ts +71 -0
- package/dist/core/src/auth/auth-service.d.ts.map +1 -0
- package/dist/core/src/auth/auth-service.js +177 -0
- package/dist/core/src/auth/auth-service.js.map +1 -0
- package/dist/core/src/auth/index.d.ts +4 -0
- package/dist/core/src/auth/index.d.ts.map +1 -0
- package/dist/core/src/auth/index.js +4 -0
- package/dist/core/src/auth/index.js.map +1 -0
- package/dist/core/src/encryption/encryption-manager.d.ts +97 -0
- package/dist/core/src/encryption/encryption-manager.d.ts.map +1 -0
- package/dist/core/src/encryption/encryption-manager.js +224 -0
- package/dist/core/src/encryption/encryption-manager.js.map +1 -0
- package/dist/core/src/index.d.ts +16 -0
- package/dist/core/src/index.d.ts.map +1 -0
- package/dist/core/src/index.js +16 -0
- package/dist/core/src/index.js.map +1 -0
- package/dist/core/src/realtime/change-notifier.d.ts +50 -0
- package/dist/core/src/realtime/change-notifier.d.ts.map +1 -0
- package/dist/core/src/realtime/change-notifier.js +145 -0
- package/dist/core/src/realtime/change-notifier.js.map +1 -0
- package/dist/core/src/realtime/message-types.d.ts +39 -0
- package/dist/core/src/realtime/message-types.d.ts.map +1 -0
- package/dist/core/src/realtime/message-types.js +5 -0
- package/dist/core/src/realtime/message-types.js.map +1 -0
- package/dist/core/src/realtime/subscription-manager.d.ts +67 -0
- package/dist/core/src/realtime/subscription-manager.d.ts.map +1 -0
- package/dist/core/src/realtime/subscription-manager.js +229 -0
- package/dist/core/src/realtime/subscription-manager.js.map +1 -0
- package/dist/core/src/search/search-manager.d.ts +93 -0
- package/dist/core/src/search/search-manager.d.ts.map +1 -0
- package/dist/core/src/search/search-manager.js +258 -0
- package/dist/core/src/search/search-manager.js.map +1 -0
- package/dist/core/src/storage/file-manager.d.ts +138 -0
- package/dist/core/src/storage/file-manager.d.ts.map +1 -0
- package/dist/core/src/storage/file-manager.js +224 -0
- package/dist/core/src/storage/file-manager.js.map +1 -0
- package/dist/core/src/sync/batch-processor.d.ts +97 -0
- package/dist/core/src/sync/batch-processor.d.ts.map +1 -0
- package/dist/core/src/sync/batch-processor.js +313 -0
- package/dist/core/src/sync/batch-processor.js.map +1 -0
- package/dist/core/src/sync/csv-processor.d.ts +66 -0
- package/dist/core/src/sync/csv-processor.d.ts.map +1 -0
- package/dist/core/src/sync/csv-processor.js +223 -0
- package/dist/core/src/sync/csv-processor.js.map +1 -0
- package/dist/core/src/sync/index.d.ts +3 -0
- package/dist/core/src/sync/index.d.ts.map +1 -0
- package/dist/core/src/sync/index.js +3 -0
- package/dist/core/src/sync/index.js.map +1 -0
- package/dist/core/src/sync/sync-engine.d.ts +68 -0
- package/dist/core/src/sync/sync-engine.d.ts.map +1 -0
- package/dist/core/src/sync/sync-engine.js +317 -0
- package/dist/core/src/sync/sync-engine.js.map +1 -0
- package/dist/core/src/sync/transaction-manager.d.ts +83 -0
- package/dist/core/src/sync/transaction-manager.d.ts.map +1 -0
- package/dist/core/src/sync/transaction-manager.js +227 -0
- package/dist/core/src/sync/transaction-manager.js.map +1 -0
- package/dist/core/src/webhooks/webhook-manager.d.ts +137 -0
- package/dist/core/src/webhooks/webhook-manager.d.ts.map +1 -0
- package/dist/core/src/webhooks/webhook-manager.js +334 -0
- package/dist/core/src/webhooks/webhook-manager.js.map +1 -0
- package/dist/shared-types/src/admin.d.ts +101 -0
- package/dist/shared-types/src/admin.d.ts.map +1 -0
- package/dist/shared-types/src/admin.js +3 -0
- package/dist/shared-types/src/admin.js.map +1 -0
- package/dist/shared-types/src/auth.d.ts +27 -0
- package/dist/shared-types/src/auth.d.ts.map +1 -0
- package/dist/shared-types/src/auth.js +2 -0
- package/dist/shared-types/src/auth.js.map +1 -0
- package/dist/shared-types/src/index.d.ts +5 -0
- package/dist/shared-types/src/index.d.ts.map +1 -0
- package/dist/shared-types/src/index.js +5 -0
- package/dist/shared-types/src/index.js.map +1 -0
- package/dist/shared-types/src/schema.d.ts +34 -0
- package/dist/shared-types/src/schema.d.ts.map +1 -0
- package/dist/shared-types/src/schema.js +2 -0
- package/dist/shared-types/src/schema.js.map +1 -0
- package/dist/shared-types/src/sync.d.ts +37 -0
- package/dist/shared-types/src/sync.d.ts.map +1 -0
- package/dist/shared-types/src/sync.js +2 -0
- package/dist/shared-types/src/sync.js.map +1 -0
- package/package.json +25 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { SyncRequest, SyncResponse, User } from '@edgebasejs/types';
|
|
2
|
+
import { ColumnSecurityManager } from '../access-rules/column-security';
|
|
3
|
+
import { EncryptionManager } from '../encryption/encryption-manager';
|
|
4
|
+
export interface SyncDatabase {
|
|
5
|
+
getOne(sql: string, params: any[]): Promise<any>;
|
|
6
|
+
getAll(sql: string, params: any[]): Promise<any[]>;
|
|
7
|
+
run(sql: string, params: any[]): Promise<any>;
|
|
8
|
+
batch(statements: Array<{
|
|
9
|
+
sql: string;
|
|
10
|
+
params?: any[];
|
|
11
|
+
}>): Promise<any[]>;
|
|
12
|
+
}
|
|
13
|
+
export interface EntitySchema {
|
|
14
|
+
accessRules?: any;
|
|
15
|
+
}
|
|
16
|
+
export interface ServerSyncOptions {
|
|
17
|
+
schemas: Map<string, EntitySchema>;
|
|
18
|
+
db: SyncDatabase;
|
|
19
|
+
user: User;
|
|
20
|
+
columnSecurity?: ColumnSecurityManager;
|
|
21
|
+
encryption?: EncryptionManager;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Server-side sync engine
|
|
25
|
+
*/
|
|
26
|
+
export declare class ServerSyncEngine {
|
|
27
|
+
private schemas;
|
|
28
|
+
private db;
|
|
29
|
+
private user;
|
|
30
|
+
private serverTimestamp;
|
|
31
|
+
private columnSecurity?;
|
|
32
|
+
private encryption?;
|
|
33
|
+
constructor(options: ServerSyncOptions);
|
|
34
|
+
/**
|
|
35
|
+
* Process sync request from client
|
|
36
|
+
*/
|
|
37
|
+
sync(request: SyncRequest): Promise<SyncResponse>;
|
|
38
|
+
/**
|
|
39
|
+
* Process changes from client
|
|
40
|
+
*/
|
|
41
|
+
private processClientChanges;
|
|
42
|
+
/**
|
|
43
|
+
* Apply a change to the database
|
|
44
|
+
*/
|
|
45
|
+
private applyChange;
|
|
46
|
+
/**
|
|
47
|
+
* Get server changes since last sync
|
|
48
|
+
*/
|
|
49
|
+
private getServerChanges;
|
|
50
|
+
/**
|
|
51
|
+
* Filter record columns based on column-level security
|
|
52
|
+
*/
|
|
53
|
+
private filterColumns;
|
|
54
|
+
/**
|
|
55
|
+
* Filter writable columns for client changes
|
|
56
|
+
*/
|
|
57
|
+
private filterWritableData;
|
|
58
|
+
/**
|
|
59
|
+
* Encrypt sensitive fields before storing
|
|
60
|
+
*/
|
|
61
|
+
private encryptData;
|
|
62
|
+
/**
|
|
63
|
+
* Decrypt sensitive fields after retrieving
|
|
64
|
+
*/
|
|
65
|
+
private decryptData;
|
|
66
|
+
}
|
|
67
|
+
export default ServerSyncEngine;
|
|
68
|
+
//# sourceMappingURL=sync-engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-engine.d.ts","sourceRoot":"","sources":["../../../../../core/src/sync/sync-engine.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAErE,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IACjD,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACnD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAC9C,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,GAAG,EAAE,CAAA;KAAE,CAAC,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;CAC3E;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,CAAC,EAAE,GAAG,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACnC,EAAE,EAAE,YAAY,CAAC;IACjB,IAAI,EAAE,IAAI,CAAC;IACX,cAAc,CAAC,EAAE,qBAAqB,CAAC;IACvC,UAAU,CAAC,EAAE,iBAAiB,CAAC;CAChC;AAED;;GAEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,EAAE,CAAe;IACzB,OAAO,CAAC,IAAI,CAAO;IACnB,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,cAAc,CAAC,CAAwB;IAC/C,OAAO,CAAC,UAAU,CAAC,CAAoB;gBAE3B,OAAO,EAAE,iBAAiB;IAStC;;OAEG;IACG,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IA0BvD;;OAEG;YACW,oBAAoB;IA0JlC;;OAEG;YACW,WAAW;IAsDzB;;OAEG;YACW,gBAAgB;IA6F9B;;OAEG;YACW,aAAa;IAQ3B;;OAEG;YACW,kBAAkB;IAYhC;;OAEG;YACW,WAAW;IAQzB;;OAEG;YACW,WAAW;CAO1B;AAED,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
// Server-side synchronization engine
|
|
2
|
+
import { AccessRulesEngine } from '../access-rules/engine';
|
|
3
|
+
/**
|
|
4
|
+
* Server-side sync engine
|
|
5
|
+
*/
|
|
6
|
+
export class ServerSyncEngine {
|
|
7
|
+
constructor(options) {
|
|
8
|
+
this.schemas = options.schemas;
|
|
9
|
+
this.db = options.db;
|
|
10
|
+
this.user = options.user;
|
|
11
|
+
this.serverTimestamp = Date.now();
|
|
12
|
+
this.columnSecurity = options.columnSecurity;
|
|
13
|
+
this.encryption = options.encryption;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Process sync request from client
|
|
17
|
+
*/
|
|
18
|
+
async sync(request) {
|
|
19
|
+
const response = {
|
|
20
|
+
serverTimestamp: this.serverTimestamp,
|
|
21
|
+
changes: [],
|
|
22
|
+
conflicts: [],
|
|
23
|
+
errors: [],
|
|
24
|
+
};
|
|
25
|
+
const appliedChangeKeys = new Set();
|
|
26
|
+
// Process client changes
|
|
27
|
+
if (request.changes && request.changes.length > 0) {
|
|
28
|
+
await this.processClientChanges(request.changes, response);
|
|
29
|
+
for (const change of response.changes) {
|
|
30
|
+
if (change.entity && change.id) {
|
|
31
|
+
appliedChangeKeys.add(`${change.entity}:${change.id}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// Get server changes since last sync
|
|
36
|
+
await this.getServerChanges(request.lastSyncTimestamp, response, appliedChangeKeys);
|
|
37
|
+
return response;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Process changes from client
|
|
41
|
+
*/
|
|
42
|
+
async processClientChanges(changes, response) {
|
|
43
|
+
for (const change of changes) {
|
|
44
|
+
try {
|
|
45
|
+
if (!change.entity) {
|
|
46
|
+
response.errors.push({
|
|
47
|
+
entity: change.entity,
|
|
48
|
+
id: change.id,
|
|
49
|
+
operation: change.operation,
|
|
50
|
+
error: 'Missing entity',
|
|
51
|
+
code: 'VALIDATION_ERROR',
|
|
52
|
+
});
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (!change.id) {
|
|
56
|
+
response.errors.push({
|
|
57
|
+
entity: change.entity,
|
|
58
|
+
id: change.id,
|
|
59
|
+
operation: change.operation,
|
|
60
|
+
error: 'Missing record id',
|
|
61
|
+
code: 'VALIDATION_ERROR',
|
|
62
|
+
});
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if ((change.operation === 'create' || change.operation === 'update') &&
|
|
66
|
+
(!change.data || typeof change.data !== 'object')) {
|
|
67
|
+
response.errors.push({
|
|
68
|
+
entity: change.entity,
|
|
69
|
+
id: change.id,
|
|
70
|
+
operation: change.operation,
|
|
71
|
+
error: 'Missing data',
|
|
72
|
+
code: 'VALIDATION_ERROR',
|
|
73
|
+
});
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
// Get schema for entity
|
|
77
|
+
const schema = this.schemas.get(change.entity);
|
|
78
|
+
if (!schema) {
|
|
79
|
+
response.errors.push({
|
|
80
|
+
entity: change.entity,
|
|
81
|
+
id: change.id,
|
|
82
|
+
operation: change.operation,
|
|
83
|
+
error: 'Unknown entity',
|
|
84
|
+
code: 'NOT_FOUND',
|
|
85
|
+
});
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
// Check access rules
|
|
89
|
+
const accessContext = {
|
|
90
|
+
user: this.user,
|
|
91
|
+
operation: change.operation,
|
|
92
|
+
data: change.data ?? {},
|
|
93
|
+
};
|
|
94
|
+
// Get existing data for update/delete operations
|
|
95
|
+
if (change.operation === 'update' || change.operation === 'delete') {
|
|
96
|
+
const existing = await this.db.getOne(`SELECT * FROM ${change.entity} WHERE id = ?`, [
|
|
97
|
+
change.id,
|
|
98
|
+
]);
|
|
99
|
+
if (existing) {
|
|
100
|
+
accessContext.existingData = existing;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// Evaluate access rules
|
|
104
|
+
const accessDecision = await AccessRulesEngine.evaluate(accessContext, schema.accessRules);
|
|
105
|
+
if (!accessDecision.allowed) {
|
|
106
|
+
response.errors.push({
|
|
107
|
+
entity: change.entity,
|
|
108
|
+
id: change.id,
|
|
109
|
+
operation: change.operation,
|
|
110
|
+
error: accessDecision.reason || 'Access denied',
|
|
111
|
+
code: 'ACCESS_DENIED',
|
|
112
|
+
});
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
// Filter writable columns for create/update operations
|
|
116
|
+
if (change.data && (change.operation === 'create' || change.operation === 'update')) {
|
|
117
|
+
const { filtered, rejected } = await this.filterWritableData(change.entity, change.data, accessContext.existingData);
|
|
118
|
+
if (rejected.length > 0) {
|
|
119
|
+
// Log rejected columns (optional: could add to response warnings)
|
|
120
|
+
console.warn(`Rejected columns for ${change.entity}:${change.id}:`, rejected);
|
|
121
|
+
}
|
|
122
|
+
// Use filtered data
|
|
123
|
+
change.data = filtered;
|
|
124
|
+
}
|
|
125
|
+
// Get current version
|
|
126
|
+
const metadata = await this.db.getOne('SELECT version FROM sync_metadata WHERE entity = ? AND record_id = ?', [change.entity, change.id]);
|
|
127
|
+
const currentVersion = metadata?.version || 0;
|
|
128
|
+
// Check for conflicts (version mismatch)
|
|
129
|
+
if (metadata && change.version !== currentVersion) {
|
|
130
|
+
// Get current data
|
|
131
|
+
const currentData = await this.db.getOne(`SELECT * FROM ${change.entity} WHERE id = ?`, [
|
|
132
|
+
change.id,
|
|
133
|
+
]);
|
|
134
|
+
response.conflicts.push({
|
|
135
|
+
entity: change.entity,
|
|
136
|
+
id: change.id,
|
|
137
|
+
clientVersion: change.version,
|
|
138
|
+
serverVersion: currentVersion,
|
|
139
|
+
serverData: currentData || {},
|
|
140
|
+
});
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
// Apply change to database
|
|
144
|
+
await this.applyChange(change, currentVersion + 1);
|
|
145
|
+
// Filter columns before sending back to client
|
|
146
|
+
const filteredData = change.data ? await this.filterColumns(change.entity, change.data) : {};
|
|
147
|
+
// Add to response changes
|
|
148
|
+
response.changes.push({
|
|
149
|
+
...change,
|
|
150
|
+
data: filteredData,
|
|
151
|
+
serverTimestamp: this.serverTimestamp,
|
|
152
|
+
version: currentVersion + 1,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
console.error('Error processing change:', error);
|
|
157
|
+
response.errors.push({
|
|
158
|
+
entity: change.entity,
|
|
159
|
+
id: change.id,
|
|
160
|
+
operation: change.operation,
|
|
161
|
+
error: error instanceof Error ? error.message : 'Processing failed',
|
|
162
|
+
code: 'VALIDATION_ERROR',
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Apply a change to the database
|
|
169
|
+
*/
|
|
170
|
+
async applyChange(change, version) {
|
|
171
|
+
const now = Date.now();
|
|
172
|
+
switch (change.operation) {
|
|
173
|
+
case 'create': {
|
|
174
|
+
// Insert record
|
|
175
|
+
const columns = ['id', ...Object.keys(change.data)];
|
|
176
|
+
const values = [change.id, ...Object.values(change.data)];
|
|
177
|
+
const placeholders = columns.map(() => '?').join(', ');
|
|
178
|
+
await this.db.run(`INSERT INTO ${change.entity} (${columns.join(', ')}) VALUES (${placeholders})`, values);
|
|
179
|
+
// Insert metadata
|
|
180
|
+
await this.db.run('INSERT OR REPLACE INTO sync_metadata (entity, record_id, version, updated_at) VALUES (?, ?, ?, ?)', [change.entity, change.id, version, now]);
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
case 'update': {
|
|
184
|
+
// Update record
|
|
185
|
+
const updates = Object.entries(change.data)
|
|
186
|
+
.map(([key]) => `${key} = ?`)
|
|
187
|
+
.join(', ');
|
|
188
|
+
const values = [...Object.values(change.data), change.id];
|
|
189
|
+
await this.db.run(`UPDATE ${change.entity} SET ${updates} WHERE id = ?`, values);
|
|
190
|
+
// Update metadata
|
|
191
|
+
await this.db.run('INSERT OR REPLACE INTO sync_metadata (entity, record_id, version, updated_at) VALUES (?, ?, ?, ?)', [change.entity, change.id, version, now]);
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
case 'delete': {
|
|
195
|
+
// Delete record
|
|
196
|
+
await this.db.run(`DELETE FROM ${change.entity} WHERE id = ?`, [change.id]);
|
|
197
|
+
// Mark as deleted in metadata
|
|
198
|
+
await this.db.run('INSERT OR REPLACE INTO sync_metadata (entity, record_id, version, updated_at, deleted_at) VALUES (?, ?, ?, ?, ?)', [change.entity, change.id, version, now, now]);
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Get server changes since last sync
|
|
205
|
+
*/
|
|
206
|
+
async getServerChanges(lastSyncTimestamp, response, appliedChangeKeys) {
|
|
207
|
+
if (!lastSyncTimestamp) {
|
|
208
|
+
// First sync - get all data
|
|
209
|
+
for (const entity of this.schemas.keys()) {
|
|
210
|
+
try {
|
|
211
|
+
const records = await this.db.getAll(`SELECT m.version, r.* FROM ${entity} r
|
|
212
|
+
LEFT JOIN sync_metadata m ON m.entity = ? AND m.record_id = r.id`, [entity]);
|
|
213
|
+
for (const record of records) {
|
|
214
|
+
if (appliedChangeKeys.has(`${entity}:${record.id}`)) {
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
const entitySchema = this.schemas.get(entity);
|
|
218
|
+
if (entitySchema?.accessRules?.read) {
|
|
219
|
+
const accessDecision = await AccessRulesEngine.evaluate({ user: this.user, operation: 'read', data: record }, entitySchema.accessRules);
|
|
220
|
+
if (!accessDecision.allowed) {
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
// Filter columns based on column-level security
|
|
225
|
+
const filteredData = await this.filterColumns(entity, record);
|
|
226
|
+
response.changes.push({
|
|
227
|
+
entity,
|
|
228
|
+
operation: 'create',
|
|
229
|
+
id: record.id,
|
|
230
|
+
data: filteredData,
|
|
231
|
+
serverTimestamp: this.serverTimestamp,
|
|
232
|
+
version: record.version || 1,
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
catch (error) {
|
|
237
|
+
console.error(`Error fetching records from ${entity}:`, error);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
// Get changes since last sync
|
|
243
|
+
for (const entity of this.schemas.keys()) {
|
|
244
|
+
try {
|
|
245
|
+
const records = await this.db.getAll(`SELECT m.version, m.deleted_at, m.record_id, r.* FROM sync_metadata m
|
|
246
|
+
LEFT JOIN ${entity} r ON r.id = m.record_id
|
|
247
|
+
WHERE m.entity = ? AND m.updated_at > ?`, [entity, lastSyncTimestamp]);
|
|
248
|
+
for (const record of records) {
|
|
249
|
+
const recordId = record.record_id || record.id;
|
|
250
|
+
if (appliedChangeKeys.has(`${entity}:${recordId}`)) {
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
const operation = record.deleted_at ? 'delete' : 'update';
|
|
254
|
+
const entitySchema = this.schemas.get(entity);
|
|
255
|
+
if (!record.deleted_at && entitySchema?.accessRules?.read) {
|
|
256
|
+
const accessDecision = await AccessRulesEngine.evaluate({ user: this.user, operation: 'read', data: record }, entitySchema.accessRules);
|
|
257
|
+
if (!accessDecision.allowed) {
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
// Filter columns based on column-level security
|
|
262
|
+
const filteredData = record.deleted_at ? {} : await this.filterColumns(entity, record);
|
|
263
|
+
response.changes.push({
|
|
264
|
+
entity,
|
|
265
|
+
operation: operation,
|
|
266
|
+
id: record.record_id || record.id,
|
|
267
|
+
data: filteredData,
|
|
268
|
+
serverTimestamp: this.serverTimestamp,
|
|
269
|
+
version: record.version || 1,
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
catch (error) {
|
|
274
|
+
console.error(`Error fetching changes from ${entity}:`, error);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Filter record columns based on column-level security
|
|
281
|
+
*/
|
|
282
|
+
async filterColumns(entity, data) {
|
|
283
|
+
if (!this.columnSecurity) {
|
|
284
|
+
return data; // No column security = return all data
|
|
285
|
+
}
|
|
286
|
+
return await this.columnSecurity.filterReadableColumns(entity, data, this.user);
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Filter writable columns for client changes
|
|
290
|
+
*/
|
|
291
|
+
async filterWritableData(entity, data, existingRecord) {
|
|
292
|
+
if (!this.columnSecurity) {
|
|
293
|
+
return { filtered: data, rejected: [] }; // No column security = allow all
|
|
294
|
+
}
|
|
295
|
+
return await this.columnSecurity.filterWritableColumns(entity, data, this.user, existingRecord);
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Encrypt sensitive fields before storing
|
|
299
|
+
*/
|
|
300
|
+
async encryptData(entity, data) {
|
|
301
|
+
if (!this.encryption) {
|
|
302
|
+
return data; // No encryption = return as is
|
|
303
|
+
}
|
|
304
|
+
return await this.encryption.encryptRecord(entity, data);
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Decrypt sensitive fields after retrieving
|
|
308
|
+
*/
|
|
309
|
+
async decryptData(entity, data) {
|
|
310
|
+
if (!this.encryption) {
|
|
311
|
+
return data; // No encryption = return as is
|
|
312
|
+
}
|
|
313
|
+
return await this.encryption.decryptRecord(entity, data);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
export default ServerSyncEngine;
|
|
317
|
+
//# sourceMappingURL=sync-engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-engine.js","sourceRoot":"","sources":["../../../../../core/src/sync/sync-engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { SyncDatabase } from './sync-engine';
|
|
2
|
+
import type { User } from '@edgebasejs/types';
|
|
3
|
+
export type IsolationLevel = 'READ_UNCOMMITTED' | 'READ_COMMITTED' | 'SERIALIZABLE';
|
|
4
|
+
export type TransactionStatus = 'active' | 'committed' | 'rolled_back' | 'expired';
|
|
5
|
+
export interface Transaction {
|
|
6
|
+
id: string;
|
|
7
|
+
userId: string;
|
|
8
|
+
status: TransactionStatus;
|
|
9
|
+
isolationLevel: IsolationLevel;
|
|
10
|
+
createdAt: number;
|
|
11
|
+
expiresAt: number;
|
|
12
|
+
completedAt?: number;
|
|
13
|
+
changes: TransactionChange[];
|
|
14
|
+
}
|
|
15
|
+
export interface TransactionChange {
|
|
16
|
+
id: string;
|
|
17
|
+
entity: string;
|
|
18
|
+
recordId: string;
|
|
19
|
+
operation: 'create' | 'update' | 'delete';
|
|
20
|
+
data: Record<string, any>;
|
|
21
|
+
version?: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Manages database transactions with ACID guarantees
|
|
25
|
+
* Handles begin, commit, and rollback operations
|
|
26
|
+
*/
|
|
27
|
+
export declare class TransactionManager {
|
|
28
|
+
private db;
|
|
29
|
+
private activeTransactions;
|
|
30
|
+
private readonly transactionTimeout;
|
|
31
|
+
private readonly maxRetries;
|
|
32
|
+
constructor(db: SyncDatabase);
|
|
33
|
+
/**
|
|
34
|
+
* Begin a new transaction
|
|
35
|
+
*/
|
|
36
|
+
begin(user: User, isolationLevel?: IsolationLevel): Promise<string>;
|
|
37
|
+
/**
|
|
38
|
+
* Add a change to a transaction
|
|
39
|
+
*/
|
|
40
|
+
addChange(transactionId: string, entity: string, recordId: string, operation: 'create' | 'update' | 'delete', data: Record<string, any>, version?: number): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Get a transaction by ID
|
|
43
|
+
*/
|
|
44
|
+
getTransaction(transactionId: string): Transaction | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* Commit a transaction
|
|
47
|
+
* Applies all changes atomically
|
|
48
|
+
*/
|
|
49
|
+
commit(transactionId: string): Promise<{
|
|
50
|
+
appliedCount: number;
|
|
51
|
+
errors: string[];
|
|
52
|
+
}>;
|
|
53
|
+
/**
|
|
54
|
+
* Rollback a transaction
|
|
55
|
+
* Reverts all changes
|
|
56
|
+
*/
|
|
57
|
+
rollback(transactionId: string): Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* Detect conflicts for a record
|
|
60
|
+
*/
|
|
61
|
+
private detectConflict;
|
|
62
|
+
/**
|
|
63
|
+
* Apply a single change to the database
|
|
64
|
+
*/
|
|
65
|
+
private applyChange;
|
|
66
|
+
/**
|
|
67
|
+
* Get all active transactions for a user
|
|
68
|
+
*/
|
|
69
|
+
getActiveTransactions(userId: string): Transaction[];
|
|
70
|
+
/**
|
|
71
|
+
* Cleanup expired transactions
|
|
72
|
+
*/
|
|
73
|
+
cleanup(): Promise<void>;
|
|
74
|
+
/**
|
|
75
|
+
* Get transaction statistics
|
|
76
|
+
*/
|
|
77
|
+
getStats(): {
|
|
78
|
+
activeTransactions: number;
|
|
79
|
+
committedTransactions: number;
|
|
80
|
+
rolledBackTransactions: number;
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=transaction-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transaction-manager.d.ts","sourceRoot":"","sources":["../../../../../core/src/sync/transaction-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAE9C,MAAM,MAAM,cAAc,GAAG,kBAAkB,GAAG,gBAAgB,GAAG,cAAc,CAAC;AACpF,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,WAAW,GAAG,aAAa,GAAG,SAAS,CAAC;AAEnF,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,iBAAiB,CAAC;IAC1B,cAAc,EAAE,cAAc,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,iBAAiB,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC1C,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,qBAAa,kBAAkB;IAKjB,OAAO,CAAC,EAAE;IAJtB,OAAO,CAAC,kBAAkB,CAAkC;IAC5D,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAU;IAC7C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAK;gBAEZ,EAAE,EAAE,YAAY;IAEpC;;OAEG;IACG,KAAK,CACT,IAAI,EAAE,IAAI,EACV,cAAc,GAAE,cAAiC,GAChD,OAAO,CAAC,MAAM,CAAC;IA4BlB;;OAEG;IACG,SAAS,CACb,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,EACzC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACzB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;IAsChB;;OAEG;IACH,cAAc,CAAC,aAAa,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAI9D;;;OAGG;IACG,MAAM,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAkExF;;;OAGG;IACG,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBpD;;OAEG;YACW,cAAc;IA8C5B;;OAEG;YACW,WAAW;IAwBzB;;OAEG;IACH,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,EAAE;IAMpD;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB9B;;OAEG;IACH,QAAQ,IAAI;QACV,kBAAkB,EAAE,MAAM,CAAC;QAC3B,qBAAqB,EAAE,MAAM,CAAC;QAC9B,sBAAsB,EAAE,MAAM,CAAC;KAChC;CAaF"}
|