@topgunbuild/server 0.3.0 → 0.4.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/index.d.mts +643 -3
- package/dist/index.d.ts +643 -3
- package/dist/index.js +2272 -285
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2024 -32
- package/dist/index.mjs.map +1 -1
- package/package.json +12 -11
- package/LICENSE +0 -97
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as _topgunbuild_core from '@topgunbuild/core';
|
|
2
|
+
import { Timestamp, LWWRecord, ORMapRecord, Principal, EventJournalImpl, EventJournalConfig, JournalEvent, PermissionPolicy, ConsistencyLevel, ReplicationConfig, LWWMap, ORMap, PermissionType, MigrationConfig, MigrationStatus, MigrationMetrics, PartitionMap, PartitionInfo, PartitionChange, ReplicationLag, ReplicationHealth, ReplicationResult, EntryProcessorDef, EntryProcessorResult, HLC, MergeRejection, ConflictResolverDef, MergeContext, MergeResult } from '@topgunbuild/core';
|
|
2
3
|
import { WebSocket } from 'ws';
|
|
3
|
-
import {
|
|
4
|
+
import { Pool, PoolConfig } from 'pg';
|
|
4
5
|
import pino from 'pino';
|
|
5
6
|
import { EventEmitter } from 'events';
|
|
6
7
|
|
|
@@ -1671,6 +1672,116 @@ type CoalescingPreset = keyof typeof coalescingPresets;
|
|
|
1671
1672
|
*/
|
|
1672
1673
|
declare function getCoalescingPreset(preset: CoalescingPreset): CoalescingWriterOptions;
|
|
1673
1674
|
|
|
1675
|
+
/**
|
|
1676
|
+
* Export options for streaming journal events.
|
|
1677
|
+
*/
|
|
1678
|
+
interface ExportOptions {
|
|
1679
|
+
/** Start from this sequence (inclusive) */
|
|
1680
|
+
fromSequence?: bigint;
|
|
1681
|
+
/** End at this sequence (inclusive) */
|
|
1682
|
+
toSequence?: bigint;
|
|
1683
|
+
/** Filter by map name */
|
|
1684
|
+
mapName?: string;
|
|
1685
|
+
/** Filter by event types */
|
|
1686
|
+
types?: ('PUT' | 'UPDATE' | 'DELETE')[];
|
|
1687
|
+
}
|
|
1688
|
+
/**
|
|
1689
|
+
* Configuration for EventJournalService.
|
|
1690
|
+
*/
|
|
1691
|
+
interface EventJournalServiceConfig extends EventJournalConfig {
|
|
1692
|
+
/** PostgreSQL connection pool */
|
|
1693
|
+
pool: Pool;
|
|
1694
|
+
/** Table name for journal storage */
|
|
1695
|
+
tableName?: string;
|
|
1696
|
+
/** Batch size for persistence */
|
|
1697
|
+
persistBatchSize?: number;
|
|
1698
|
+
/** Interval for periodic persistence (ms) */
|
|
1699
|
+
persistIntervalMs?: number;
|
|
1700
|
+
}
|
|
1701
|
+
/**
|
|
1702
|
+
* Default configuration for EventJournalService.
|
|
1703
|
+
*/
|
|
1704
|
+
declare const DEFAULT_JOURNAL_SERVICE_CONFIG: Omit<EventJournalServiceConfig, 'pool'>;
|
|
1705
|
+
/**
|
|
1706
|
+
* Server-side Event Journal Service with PostgreSQL persistence.
|
|
1707
|
+
* Extends EventJournalImpl to add durable storage.
|
|
1708
|
+
*/
|
|
1709
|
+
declare class EventJournalService extends EventJournalImpl {
|
|
1710
|
+
private readonly pool;
|
|
1711
|
+
private readonly tableName;
|
|
1712
|
+
private readonly persistBatchSize;
|
|
1713
|
+
private readonly persistIntervalMs;
|
|
1714
|
+
private pendingPersist;
|
|
1715
|
+
private persistTimer?;
|
|
1716
|
+
private isPersisting;
|
|
1717
|
+
private isInitialized;
|
|
1718
|
+
private isLoadingFromStorage;
|
|
1719
|
+
constructor(config: EventJournalServiceConfig);
|
|
1720
|
+
/**
|
|
1721
|
+
* Initialize the journal service, creating table if needed.
|
|
1722
|
+
*/
|
|
1723
|
+
initialize(): Promise<void>;
|
|
1724
|
+
/**
|
|
1725
|
+
* Persist pending events to PostgreSQL.
|
|
1726
|
+
*/
|
|
1727
|
+
persistToStorage(): Promise<void>;
|
|
1728
|
+
/**
|
|
1729
|
+
* Load journal events from PostgreSQL on startup.
|
|
1730
|
+
*/
|
|
1731
|
+
loadFromStorage(): Promise<void>;
|
|
1732
|
+
/**
|
|
1733
|
+
* Export events as NDJSON stream.
|
|
1734
|
+
*/
|
|
1735
|
+
exportStream(options?: ExportOptions): ReadableStream<string>;
|
|
1736
|
+
/**
|
|
1737
|
+
* Get events for a specific map.
|
|
1738
|
+
*/
|
|
1739
|
+
getMapEvents(mapName: string, fromSeq?: bigint): JournalEvent[];
|
|
1740
|
+
/**
|
|
1741
|
+
* Query events from PostgreSQL with filters.
|
|
1742
|
+
*/
|
|
1743
|
+
queryFromStorage(options?: {
|
|
1744
|
+
mapName?: string;
|
|
1745
|
+
key?: string;
|
|
1746
|
+
types?: ('PUT' | 'UPDATE' | 'DELETE')[];
|
|
1747
|
+
fromSequence?: bigint;
|
|
1748
|
+
toSequence?: bigint;
|
|
1749
|
+
fromDate?: Date;
|
|
1750
|
+
toDate?: Date;
|
|
1751
|
+
limit?: number;
|
|
1752
|
+
offset?: number;
|
|
1753
|
+
}): Promise<JournalEvent[]>;
|
|
1754
|
+
/**
|
|
1755
|
+
* Count events matching filters.
|
|
1756
|
+
*/
|
|
1757
|
+
countFromStorage(options?: {
|
|
1758
|
+
mapName?: string;
|
|
1759
|
+
types?: ('PUT' | 'UPDATE' | 'DELETE')[];
|
|
1760
|
+
fromDate?: Date;
|
|
1761
|
+
toDate?: Date;
|
|
1762
|
+
}): Promise<number>;
|
|
1763
|
+
/**
|
|
1764
|
+
* Cleanup old events based on retention policy.
|
|
1765
|
+
*/
|
|
1766
|
+
cleanupOldEvents(retentionDays: number): Promise<number>;
|
|
1767
|
+
/**
|
|
1768
|
+
* Start the periodic persistence timer.
|
|
1769
|
+
*/
|
|
1770
|
+
private startPersistTimer;
|
|
1771
|
+
/**
|
|
1772
|
+
* Stop the periodic persistence timer.
|
|
1773
|
+
*/
|
|
1774
|
+
private stopPersistTimer;
|
|
1775
|
+
/**
|
|
1776
|
+
* Dispose resources and persist remaining events.
|
|
1777
|
+
*/
|
|
1778
|
+
dispose(): void;
|
|
1779
|
+
/**
|
|
1780
|
+
* Get pending persist count (for monitoring).
|
|
1781
|
+
*/
|
|
1782
|
+
getPendingPersistCount(): number;
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1674
1785
|
interface ServerCoordinatorConfig {
|
|
1675
1786
|
port: number;
|
|
1676
1787
|
nodeId: string;
|
|
@@ -1743,6 +1854,10 @@ interface ServerCoordinatorConfig {
|
|
|
1743
1854
|
defaultConsistency?: ConsistencyLevel;
|
|
1744
1855
|
/** Replication configuration */
|
|
1745
1856
|
replicationConfig?: Partial<ReplicationConfig>;
|
|
1857
|
+
/** Enable event journal for audit/CDC (default: false) */
|
|
1858
|
+
eventJournalEnabled?: boolean;
|
|
1859
|
+
/** Event journal configuration */
|
|
1860
|
+
eventJournalConfig?: Partial<Omit<EventJournalServiceConfig, 'pool'>>;
|
|
1746
1861
|
}
|
|
1747
1862
|
declare class ServerCoordinator {
|
|
1748
1863
|
private httpServer;
|
|
@@ -1782,6 +1897,12 @@ declare class ServerCoordinator {
|
|
|
1782
1897
|
private eventPayloadPool;
|
|
1783
1898
|
private taskletScheduler;
|
|
1784
1899
|
private writeAckManager;
|
|
1900
|
+
private counterHandler;
|
|
1901
|
+
private entryProcessorHandler;
|
|
1902
|
+
private conflictResolverHandler;
|
|
1903
|
+
private eventJournalService?;
|
|
1904
|
+
private journalSubscriptions;
|
|
1905
|
+
private readonly _nodeId;
|
|
1785
1906
|
private _actualPort;
|
|
1786
1907
|
private _actualClusterPort;
|
|
1787
1908
|
private _readyPromise;
|
|
@@ -1831,6 +1952,11 @@ declare class ServerCoordinator {
|
|
|
1831
1952
|
* Called when partition topology changes (node join/leave/failover).
|
|
1832
1953
|
*/
|
|
1833
1954
|
private broadcastPartitionMap;
|
|
1955
|
+
/**
|
|
1956
|
+
* Notify a client about a merge rejection (Phase 5.05).
|
|
1957
|
+
* Finds the client by node ID and sends MERGE_REJECTED message.
|
|
1958
|
+
*/
|
|
1959
|
+
private notifyMergeRejection;
|
|
1834
1960
|
private broadcast;
|
|
1835
1961
|
/**
|
|
1836
1962
|
* === OPTIMIZATION 2 & 3: Batched Broadcast with Serialization Caching ===
|
|
@@ -3048,4 +3174,518 @@ declare class ClusterCoordinator extends EventEmitter {
|
|
|
3048
3174
|
private setupEventHandlers;
|
|
3049
3175
|
}
|
|
3050
3176
|
|
|
3051
|
-
|
|
3177
|
+
/**
|
|
3178
|
+
* Configuration for the processor sandbox.
|
|
3179
|
+
*/
|
|
3180
|
+
interface ProcessorSandboxConfig {
|
|
3181
|
+
/** Memory limit in MB per isolate */
|
|
3182
|
+
memoryLimitMb: number;
|
|
3183
|
+
/** Execution timeout in milliseconds */
|
|
3184
|
+
timeoutMs: number;
|
|
3185
|
+
/** Maximum number of cached isolates */
|
|
3186
|
+
maxCachedIsolates: number;
|
|
3187
|
+
/** Enable strict code validation */
|
|
3188
|
+
strictValidation: boolean;
|
|
3189
|
+
}
|
|
3190
|
+
/**
|
|
3191
|
+
* Default sandbox configuration.
|
|
3192
|
+
*/
|
|
3193
|
+
declare const DEFAULT_SANDBOX_CONFIG: ProcessorSandboxConfig;
|
|
3194
|
+
/**
|
|
3195
|
+
* Sandbox for executing entry processor code securely.
|
|
3196
|
+
*
|
|
3197
|
+
* Uses isolated-vm for production environments with:
|
|
3198
|
+
* - Memory limits to prevent memory bombs
|
|
3199
|
+
* - CPU limits via timeout to prevent infinite loops
|
|
3200
|
+
* - No I/O access (no require, fs, net, etc.)
|
|
3201
|
+
* - Minimal exposed globals (only value, key, args)
|
|
3202
|
+
*
|
|
3203
|
+
* Falls back to Node.js vm module for development/testing
|
|
3204
|
+
* when isolated-vm is not available.
|
|
3205
|
+
*/
|
|
3206
|
+
declare class ProcessorSandbox {
|
|
3207
|
+
private config;
|
|
3208
|
+
private isolateCache;
|
|
3209
|
+
private scriptCache;
|
|
3210
|
+
private fallbackScriptCache;
|
|
3211
|
+
private disposed;
|
|
3212
|
+
constructor(config?: Partial<ProcessorSandboxConfig>);
|
|
3213
|
+
/**
|
|
3214
|
+
* Execute an entry processor in the sandbox.
|
|
3215
|
+
*
|
|
3216
|
+
* @param processor The processor definition (name, code, args)
|
|
3217
|
+
* @param value The current value for the key (or undefined)
|
|
3218
|
+
* @param key The key being processed
|
|
3219
|
+
* @returns Result containing success status, result, and new value
|
|
3220
|
+
*/
|
|
3221
|
+
execute<V, R>(processor: EntryProcessorDef<V, R>, value: V | undefined, key: string): Promise<EntryProcessorResult<R>>;
|
|
3222
|
+
/**
|
|
3223
|
+
* Execute processor in isolated-vm (secure production mode).
|
|
3224
|
+
*/
|
|
3225
|
+
private executeInIsolate;
|
|
3226
|
+
/**
|
|
3227
|
+
* Execute processor in fallback VM (less secure, for development).
|
|
3228
|
+
*/
|
|
3229
|
+
private executeInFallback;
|
|
3230
|
+
/**
|
|
3231
|
+
* Get or create an isolate for a processor.
|
|
3232
|
+
*/
|
|
3233
|
+
private getOrCreateIsolate;
|
|
3234
|
+
/**
|
|
3235
|
+
* Get or compile a script for a processor.
|
|
3236
|
+
*/
|
|
3237
|
+
private getOrCompileScript;
|
|
3238
|
+
/**
|
|
3239
|
+
* Clear script cache for a specific processor (e.g., when code changes).
|
|
3240
|
+
*/
|
|
3241
|
+
clearCache(processorName?: string): void;
|
|
3242
|
+
/**
|
|
3243
|
+
* Check if using secure isolated-vm mode.
|
|
3244
|
+
*/
|
|
3245
|
+
isSecureMode(): boolean;
|
|
3246
|
+
/**
|
|
3247
|
+
* Get current cache sizes.
|
|
3248
|
+
*/
|
|
3249
|
+
getCacheStats(): {
|
|
3250
|
+
isolates: number;
|
|
3251
|
+
scripts: number;
|
|
3252
|
+
fallbackScripts: number;
|
|
3253
|
+
};
|
|
3254
|
+
/**
|
|
3255
|
+
* Dispose of all isolates and clear caches.
|
|
3256
|
+
*/
|
|
3257
|
+
dispose(): void;
|
|
3258
|
+
}
|
|
3259
|
+
|
|
3260
|
+
/**
|
|
3261
|
+
* Configuration for the EntryProcessorHandler.
|
|
3262
|
+
*/
|
|
3263
|
+
interface EntryProcessorHandlerConfig {
|
|
3264
|
+
/** HLC instance for timestamp generation */
|
|
3265
|
+
hlc: HLC;
|
|
3266
|
+
/** Optional sandbox configuration override */
|
|
3267
|
+
sandboxConfig?: Partial<ProcessorSandboxConfig>;
|
|
3268
|
+
}
|
|
3269
|
+
/**
|
|
3270
|
+
* Server-side handler for Entry Processor execution.
|
|
3271
|
+
*
|
|
3272
|
+
* Responsibilities:
|
|
3273
|
+
* - Validate incoming processor definitions
|
|
3274
|
+
* - Execute processors in sandboxed environment
|
|
3275
|
+
* - Update map state atomically
|
|
3276
|
+
* - Return results with new values for client cache sync
|
|
3277
|
+
*/
|
|
3278
|
+
declare class EntryProcessorHandler {
|
|
3279
|
+
private sandbox;
|
|
3280
|
+
private hlc;
|
|
3281
|
+
constructor(config: EntryProcessorHandlerConfig);
|
|
3282
|
+
/**
|
|
3283
|
+
* Execute a processor on a single key atomically.
|
|
3284
|
+
*
|
|
3285
|
+
* @param map The LWWMap to operate on
|
|
3286
|
+
* @param key The key to process
|
|
3287
|
+
* @param processorDef The processor definition (will be validated)
|
|
3288
|
+
* @returns Result with success status, processor result, and new value
|
|
3289
|
+
*/
|
|
3290
|
+
executeOnKey<V, R>(map: LWWMap<string, V>, key: string, processorDef: unknown): Promise<{
|
|
3291
|
+
result: EntryProcessorResult<R>;
|
|
3292
|
+
timestamp?: Timestamp;
|
|
3293
|
+
}>;
|
|
3294
|
+
/**
|
|
3295
|
+
* Execute a processor on multiple keys.
|
|
3296
|
+
*
|
|
3297
|
+
* Each key is processed sequentially to ensure atomicity per-key.
|
|
3298
|
+
* For parallel execution across keys, use multiple calls.
|
|
3299
|
+
*
|
|
3300
|
+
* @param map The LWWMap to operate on
|
|
3301
|
+
* @param keys The keys to process
|
|
3302
|
+
* @param processorDef The processor definition
|
|
3303
|
+
* @returns Map of key -> result
|
|
3304
|
+
*/
|
|
3305
|
+
executeOnKeys<V, R>(map: LWWMap<string, V>, keys: string[], processorDef: unknown): Promise<{
|
|
3306
|
+
results: Map<string, EntryProcessorResult<R>>;
|
|
3307
|
+
timestamps: Map<string, Timestamp>;
|
|
3308
|
+
}>;
|
|
3309
|
+
/**
|
|
3310
|
+
* Execute a processor on all entries matching a predicate.
|
|
3311
|
+
*
|
|
3312
|
+
* WARNING: This can be expensive for large maps.
|
|
3313
|
+
*
|
|
3314
|
+
* @param map The LWWMap to operate on
|
|
3315
|
+
* @param processorDef The processor definition
|
|
3316
|
+
* @param predicateCode Optional predicate code to filter entries
|
|
3317
|
+
* @returns Map of key -> result for processed entries
|
|
3318
|
+
*/
|
|
3319
|
+
executeOnEntries<V, R>(map: LWWMap<string, V>, processorDef: unknown, predicateCode?: string): Promise<{
|
|
3320
|
+
results: Map<string, EntryProcessorResult<R>>;
|
|
3321
|
+
timestamps: Map<string, Timestamp>;
|
|
3322
|
+
}>;
|
|
3323
|
+
/**
|
|
3324
|
+
* Check if sandbox is in secure mode (using isolated-vm).
|
|
3325
|
+
*/
|
|
3326
|
+
isSecureMode(): boolean;
|
|
3327
|
+
/**
|
|
3328
|
+
* Get sandbox cache statistics.
|
|
3329
|
+
*/
|
|
3330
|
+
getCacheStats(): {
|
|
3331
|
+
isolates: number;
|
|
3332
|
+
scripts: number;
|
|
3333
|
+
fallbackScripts: number;
|
|
3334
|
+
};
|
|
3335
|
+
/**
|
|
3336
|
+
* Clear sandbox cache.
|
|
3337
|
+
*/
|
|
3338
|
+
clearCache(processorName?: string): void;
|
|
3339
|
+
/**
|
|
3340
|
+
* Dispose of the handler and its sandbox.
|
|
3341
|
+
*/
|
|
3342
|
+
dispose(): void;
|
|
3343
|
+
}
|
|
3344
|
+
|
|
3345
|
+
/**
|
|
3346
|
+
* Configuration for ConflictResolverService.
|
|
3347
|
+
*/
|
|
3348
|
+
interface ConflictResolverServiceConfig {
|
|
3349
|
+
/** Maximum resolvers per map */
|
|
3350
|
+
maxResolversPerMap: number;
|
|
3351
|
+
/** Enable sandboxed code execution (requires isolated-vm) */
|
|
3352
|
+
enableSandboxedResolvers: boolean;
|
|
3353
|
+
/** Default timeout for resolver execution in milliseconds */
|
|
3354
|
+
resolverTimeoutMs: number;
|
|
3355
|
+
}
|
|
3356
|
+
/**
|
|
3357
|
+
* Default service configuration.
|
|
3358
|
+
*/
|
|
3359
|
+
declare const DEFAULT_CONFLICT_RESOLVER_CONFIG: ConflictResolverServiceConfig;
|
|
3360
|
+
/**
|
|
3361
|
+
* Service for managing and executing conflict resolvers.
|
|
3362
|
+
*
|
|
3363
|
+
* Resolvers are executed in priority order (highest first).
|
|
3364
|
+
* The first resolver that returns a non-'local' action wins.
|
|
3365
|
+
* If all resolvers return 'local', LWW is used as fallback.
|
|
3366
|
+
*
|
|
3367
|
+
* ## Design Decisions
|
|
3368
|
+
*
|
|
3369
|
+
* ### In-Memory Storage
|
|
3370
|
+
* Resolvers are stored in memory only (not persisted to database).
|
|
3371
|
+
* This is intentional - resolvers represent application logic that should
|
|
3372
|
+
* be registered by clients on connection. Benefits:
|
|
3373
|
+
* - Simpler architecture without resolver schema migrations
|
|
3374
|
+
* - Clients control their own conflict resolution logic
|
|
3375
|
+
* - Natural cleanup when client disconnects
|
|
3376
|
+
*
|
|
3377
|
+
* ### Permission Model
|
|
3378
|
+
* Resolver registration requires PUT permission on the target map.
|
|
3379
|
+
* This aligns with the principle that if you can write to a map,
|
|
3380
|
+
* you can define how your writes are resolved. For stricter control,
|
|
3381
|
+
* implement custom permission checks in ServerCoordinator.
|
|
3382
|
+
*
|
|
3383
|
+
* ### Deletion Handling
|
|
3384
|
+
* Deletions (tombstones with null value) are passed through resolvers
|
|
3385
|
+
* with `remoteValue: null`. This allows resolvers like IMMUTABLE or
|
|
3386
|
+
* OWNER_ONLY to protect against unauthorized deletions.
|
|
3387
|
+
*/
|
|
3388
|
+
declare class ConflictResolverService {
|
|
3389
|
+
private resolvers;
|
|
3390
|
+
private sandbox;
|
|
3391
|
+
private config;
|
|
3392
|
+
private onRejectionCallback?;
|
|
3393
|
+
private disposed;
|
|
3394
|
+
constructor(sandbox: ProcessorSandbox, config?: Partial<ConflictResolverServiceConfig>);
|
|
3395
|
+
/**
|
|
3396
|
+
* Set callback for merge rejections.
|
|
3397
|
+
*/
|
|
3398
|
+
onRejection(callback: (rejection: MergeRejection) => void): void;
|
|
3399
|
+
/**
|
|
3400
|
+
* Register a resolver for a map.
|
|
3401
|
+
*
|
|
3402
|
+
* @param mapName The map this resolver applies to
|
|
3403
|
+
* @param resolver The resolver definition
|
|
3404
|
+
* @param registeredBy Optional client ID that registered this resolver
|
|
3405
|
+
*/
|
|
3406
|
+
register<V>(mapName: string, resolver: ConflictResolverDef<V>, registeredBy?: string): void;
|
|
3407
|
+
/**
|
|
3408
|
+
* Unregister a resolver.
|
|
3409
|
+
*
|
|
3410
|
+
* @param mapName The map name
|
|
3411
|
+
* @param resolverName The resolver name to unregister
|
|
3412
|
+
* @param clientId Optional - only unregister if registered by this client
|
|
3413
|
+
*/
|
|
3414
|
+
unregister(mapName: string, resolverName: string, clientId?: string): boolean;
|
|
3415
|
+
/**
|
|
3416
|
+
* Resolve a merge conflict using registered resolvers.
|
|
3417
|
+
*
|
|
3418
|
+
* @param context The merge context
|
|
3419
|
+
* @returns The merge result
|
|
3420
|
+
*/
|
|
3421
|
+
resolve<V>(context: MergeContext<V>): Promise<MergeResult<V>>;
|
|
3422
|
+
/**
|
|
3423
|
+
* List registered resolvers.
|
|
3424
|
+
*
|
|
3425
|
+
* @param mapName Optional - filter by map name
|
|
3426
|
+
*/
|
|
3427
|
+
list(mapName?: string): Array<{
|
|
3428
|
+
mapName: string;
|
|
3429
|
+
name: string;
|
|
3430
|
+
priority?: number;
|
|
3431
|
+
keyPattern?: string;
|
|
3432
|
+
registeredBy?: string;
|
|
3433
|
+
}>;
|
|
3434
|
+
/**
|
|
3435
|
+
* Check if a map has any registered resolvers.
|
|
3436
|
+
*/
|
|
3437
|
+
hasResolvers(mapName: string): boolean;
|
|
3438
|
+
/**
|
|
3439
|
+
* Get the number of registered resolvers.
|
|
3440
|
+
*/
|
|
3441
|
+
get size(): number;
|
|
3442
|
+
/**
|
|
3443
|
+
* Clear all registered resolvers.
|
|
3444
|
+
*
|
|
3445
|
+
* @param mapName Optional - only clear resolvers for specific map
|
|
3446
|
+
*/
|
|
3447
|
+
clear(mapName?: string): void;
|
|
3448
|
+
/**
|
|
3449
|
+
* Clear resolvers registered by a specific client.
|
|
3450
|
+
*/
|
|
3451
|
+
clearByClient(clientId: string): number;
|
|
3452
|
+
/**
|
|
3453
|
+
* Dispose the service.
|
|
3454
|
+
*/
|
|
3455
|
+
dispose(): void;
|
|
3456
|
+
/**
|
|
3457
|
+
* Match a key against a glob-like pattern.
|
|
3458
|
+
* Supports * (any chars) and ? (single char).
|
|
3459
|
+
*/
|
|
3460
|
+
private matchKeyPattern;
|
|
3461
|
+
/**
|
|
3462
|
+
* Compile sandboxed resolver code.
|
|
3463
|
+
*/
|
|
3464
|
+
private compileSandboxed;
|
|
3465
|
+
}
|
|
3466
|
+
|
|
3467
|
+
/**
|
|
3468
|
+
* Configuration for MapWithResolver.
|
|
3469
|
+
*/
|
|
3470
|
+
interface MapWithResolverConfig {
|
|
3471
|
+
/** Map name */
|
|
3472
|
+
name: string;
|
|
3473
|
+
/** Node ID for HLC */
|
|
3474
|
+
nodeId: string;
|
|
3475
|
+
/** Conflict resolver service */
|
|
3476
|
+
resolverService: ConflictResolverService;
|
|
3477
|
+
/** Callback for merge rejections */
|
|
3478
|
+
onRejection?: (rejection: MergeRejection) => void;
|
|
3479
|
+
}
|
|
3480
|
+
/**
|
|
3481
|
+
* Result of setWithResolver operation.
|
|
3482
|
+
*/
|
|
3483
|
+
interface SetWithResolverResult<V> {
|
|
3484
|
+
/** Whether the value was applied */
|
|
3485
|
+
applied: boolean;
|
|
3486
|
+
/** The merge result */
|
|
3487
|
+
result: MergeResult<V>;
|
|
3488
|
+
/** The final record if applied */
|
|
3489
|
+
record?: LWWRecord<V>;
|
|
3490
|
+
}
|
|
3491
|
+
/**
|
|
3492
|
+
* Extended LWWMap that supports custom conflict resolvers.
|
|
3493
|
+
*
|
|
3494
|
+
* This wrapper delegates merge operations to ConflictResolverService,
|
|
3495
|
+
* allowing custom business logic to intercept and modify merge behavior.
|
|
3496
|
+
*/
|
|
3497
|
+
declare class MapWithResolver<K extends string, V> {
|
|
3498
|
+
private map;
|
|
3499
|
+
private resolverService;
|
|
3500
|
+
private mapName;
|
|
3501
|
+
private hlc;
|
|
3502
|
+
private onRejection?;
|
|
3503
|
+
constructor(config: MapWithResolverConfig);
|
|
3504
|
+
/**
|
|
3505
|
+
* Get the map name.
|
|
3506
|
+
*/
|
|
3507
|
+
get name(): string;
|
|
3508
|
+
/**
|
|
3509
|
+
* Get the underlying LWWMap.
|
|
3510
|
+
*/
|
|
3511
|
+
get rawMap(): LWWMap<K, V>;
|
|
3512
|
+
/**
|
|
3513
|
+
* Get a value by key.
|
|
3514
|
+
*/
|
|
3515
|
+
get(key: K): V | undefined;
|
|
3516
|
+
/**
|
|
3517
|
+
* Get the full record for a key.
|
|
3518
|
+
*/
|
|
3519
|
+
getRecord(key: K): LWWRecord<V> | undefined;
|
|
3520
|
+
/**
|
|
3521
|
+
* Get the timestamp for a key.
|
|
3522
|
+
*/
|
|
3523
|
+
getTimestamp(key: K): Timestamp | undefined;
|
|
3524
|
+
/**
|
|
3525
|
+
* Set a value locally (no resolver).
|
|
3526
|
+
* Use for server-initiated writes.
|
|
3527
|
+
*/
|
|
3528
|
+
set(key: K, value: V, ttlMs?: number): LWWRecord<V>;
|
|
3529
|
+
/**
|
|
3530
|
+
* Set a value with conflict resolution.
|
|
3531
|
+
* Use for client-initiated writes.
|
|
3532
|
+
*
|
|
3533
|
+
* @param key The key to set
|
|
3534
|
+
* @param value The new value
|
|
3535
|
+
* @param timestamp The client's timestamp
|
|
3536
|
+
* @param remoteNodeId The client's node ID
|
|
3537
|
+
* @param auth Optional authentication context
|
|
3538
|
+
* @returns Result containing applied status and merge result
|
|
3539
|
+
*/
|
|
3540
|
+
setWithResolver(key: K, value: V, timestamp: Timestamp, remoteNodeId: string, auth?: MergeContext['auth']): Promise<SetWithResolverResult<V>>;
|
|
3541
|
+
/**
|
|
3542
|
+
* Remove a key.
|
|
3543
|
+
*/
|
|
3544
|
+
remove(key: K): LWWRecord<V>;
|
|
3545
|
+
/**
|
|
3546
|
+
* Standard merge without resolver (for sync operations).
|
|
3547
|
+
*/
|
|
3548
|
+
merge(key: K, record: LWWRecord<V>): boolean;
|
|
3549
|
+
/**
|
|
3550
|
+
* Merge with resolver support.
|
|
3551
|
+
* Equivalent to setWithResolver but takes a full record.
|
|
3552
|
+
*/
|
|
3553
|
+
mergeWithResolver(key: K, record: LWWRecord<V>, remoteNodeId: string, auth?: MergeContext['auth']): Promise<SetWithResolverResult<V>>;
|
|
3554
|
+
/**
|
|
3555
|
+
* Clear all data.
|
|
3556
|
+
*/
|
|
3557
|
+
clear(): void;
|
|
3558
|
+
/**
|
|
3559
|
+
* Get map size.
|
|
3560
|
+
*/
|
|
3561
|
+
get size(): number;
|
|
3562
|
+
/**
|
|
3563
|
+
* Iterate over entries.
|
|
3564
|
+
*/
|
|
3565
|
+
entries(): IterableIterator<[K, V]>;
|
|
3566
|
+
/**
|
|
3567
|
+
* Get all keys.
|
|
3568
|
+
*/
|
|
3569
|
+
allKeys(): IterableIterator<K>;
|
|
3570
|
+
/**
|
|
3571
|
+
* Subscribe to changes.
|
|
3572
|
+
*/
|
|
3573
|
+
onChange(callback: () => void): () => void;
|
|
3574
|
+
/**
|
|
3575
|
+
* Get MerkleTree for sync.
|
|
3576
|
+
*/
|
|
3577
|
+
getMerkleTree(): _topgunbuild_core.MerkleTree;
|
|
3578
|
+
/**
|
|
3579
|
+
* Prune old tombstones.
|
|
3580
|
+
*/
|
|
3581
|
+
prune(olderThan: Timestamp): K[];
|
|
3582
|
+
}
|
|
3583
|
+
|
|
3584
|
+
/**
|
|
3585
|
+
* Configuration for ConflictResolverHandler.
|
|
3586
|
+
*/
|
|
3587
|
+
interface ConflictResolverHandlerConfig {
|
|
3588
|
+
/** Node ID for identifying server-side resolvers */
|
|
3589
|
+
nodeId: string;
|
|
3590
|
+
/** Optional sandbox configuration override */
|
|
3591
|
+
sandboxConfig?: Partial<ProcessorSandboxConfig>;
|
|
3592
|
+
/** Optional resolver service configuration */
|
|
3593
|
+
resolverConfig?: Partial<ConflictResolverServiceConfig>;
|
|
3594
|
+
}
|
|
3595
|
+
/**
|
|
3596
|
+
* Result of merge operation with resolver.
|
|
3597
|
+
*/
|
|
3598
|
+
interface MergeWithResolverResult<V> {
|
|
3599
|
+
/** Whether the merge was applied */
|
|
3600
|
+
applied: boolean;
|
|
3601
|
+
/** The merge result details */
|
|
3602
|
+
result: MergeResult<V>;
|
|
3603
|
+
/** The final record if applied */
|
|
3604
|
+
record?: LWWRecord<V>;
|
|
3605
|
+
/** Rejection details if rejected */
|
|
3606
|
+
rejection?: MergeRejection;
|
|
3607
|
+
}
|
|
3608
|
+
/**
|
|
3609
|
+
* Server-side handler for Conflict Resolver operations.
|
|
3610
|
+
*
|
|
3611
|
+
* Responsibilities:
|
|
3612
|
+
* - Manage conflict resolver registrations
|
|
3613
|
+
* - Execute resolvers during merge operations
|
|
3614
|
+
* - Provide merge rejection notifications
|
|
3615
|
+
*/
|
|
3616
|
+
declare class ConflictResolverHandler {
|
|
3617
|
+
private sandbox;
|
|
3618
|
+
private resolverService;
|
|
3619
|
+
/** Reserved for future use (server-side resolver identification) */
|
|
3620
|
+
private readonly nodeId;
|
|
3621
|
+
private rejectionListeners;
|
|
3622
|
+
constructor(config: ConflictResolverHandlerConfig);
|
|
3623
|
+
/**
|
|
3624
|
+
* Register a conflict resolver for a map.
|
|
3625
|
+
*
|
|
3626
|
+
* @param mapName The map name
|
|
3627
|
+
* @param resolver The resolver definition
|
|
3628
|
+
* @param clientId Optional client ID that registered this resolver
|
|
3629
|
+
*/
|
|
3630
|
+
registerResolver<V>(mapName: string, resolver: ConflictResolverDef<V>, clientId?: string): void;
|
|
3631
|
+
/**
|
|
3632
|
+
* Unregister a conflict resolver.
|
|
3633
|
+
*
|
|
3634
|
+
* @param mapName The map name
|
|
3635
|
+
* @param resolverName The resolver name
|
|
3636
|
+
* @param clientId Optional - only unregister if registered by this client
|
|
3637
|
+
*/
|
|
3638
|
+
unregisterResolver(mapName: string, resolverName: string, clientId?: string): boolean;
|
|
3639
|
+
/**
|
|
3640
|
+
* List registered resolvers.
|
|
3641
|
+
*
|
|
3642
|
+
* @param mapName Optional - filter by map name
|
|
3643
|
+
*/
|
|
3644
|
+
listResolvers(mapName?: string): Array<{
|
|
3645
|
+
mapName: string;
|
|
3646
|
+
name: string;
|
|
3647
|
+
priority?: number;
|
|
3648
|
+
keyPattern?: string;
|
|
3649
|
+
}>;
|
|
3650
|
+
/**
|
|
3651
|
+
* Apply a merge with conflict resolution.
|
|
3652
|
+
*
|
|
3653
|
+
* Deletions (tombstones) are also passed through resolvers to allow
|
|
3654
|
+
* protection via IMMUTABLE, OWNER_ONLY, or similar resolvers.
|
|
3655
|
+
* If no custom resolvers are registered, deletions use standard LWW.
|
|
3656
|
+
*
|
|
3657
|
+
* @param map The LWWMap to merge into
|
|
3658
|
+
* @param mapName The map name (for resolver lookup)
|
|
3659
|
+
* @param key The key being merged
|
|
3660
|
+
* @param record The incoming record
|
|
3661
|
+
* @param remoteNodeId The source node ID
|
|
3662
|
+
* @param auth Optional authentication context
|
|
3663
|
+
*/
|
|
3664
|
+
mergeWithResolver<V>(map: LWWMap<string, V>, mapName: string, key: string, record: LWWRecord<V>, remoteNodeId: string, auth?: MergeContext['auth']): Promise<MergeWithResolverResult<V>>;
|
|
3665
|
+
/**
|
|
3666
|
+
* Check if a map has custom resolvers registered.
|
|
3667
|
+
*/
|
|
3668
|
+
hasResolvers(mapName: string): boolean;
|
|
3669
|
+
/**
|
|
3670
|
+
* Add a listener for merge rejections.
|
|
3671
|
+
*/
|
|
3672
|
+
onRejection(listener: (rejection: MergeRejection) => void): () => void;
|
|
3673
|
+
/**
|
|
3674
|
+
* Clear resolvers registered by a specific client.
|
|
3675
|
+
*/
|
|
3676
|
+
clearByClient(clientId: string): number;
|
|
3677
|
+
/**
|
|
3678
|
+
* Get the number of registered resolvers.
|
|
3679
|
+
*/
|
|
3680
|
+
get resolverCount(): number;
|
|
3681
|
+
/**
|
|
3682
|
+
* Check if sandbox is in secure mode.
|
|
3683
|
+
*/
|
|
3684
|
+
isSecureMode(): boolean;
|
|
3685
|
+
/**
|
|
3686
|
+
* Dispose of the handler.
|
|
3687
|
+
*/
|
|
3688
|
+
dispose(): void;
|
|
3689
|
+
}
|
|
3690
|
+
|
|
3691
|
+
export { BufferPool, type BufferPoolConfig, type BufferPoolStats, type ClusterConfig, ClusterCoordinator, type ClusterCoordinatorConfig, type ClusterCoordinatorEvents, ClusterManager, type ClusterMember, type ClusterMessage, type CoalescingPreset, type CoalescingWriterMetrics, type CoalescingWriterOptions, ConflictResolverHandler, type ConflictResolverHandlerConfig, ConflictResolverService, type ConflictResolverServiceConfig, type ConnectionContext, ConnectionRateLimiter, DEFAULT_CLUSTER_COORDINATOR_CONFIG, DEFAULT_CONFLICT_RESOLVER_CONFIG, DEFAULT_JOURNAL_SERVICE_CONFIG, DEFAULT_LAG_TRACKER_CONFIG, DEFAULT_SANDBOX_CONFIG, EntryProcessorHandler, type EntryProcessorHandlerConfig, EventJournalService, type EventJournalServiceConfig, type ExportOptions, FilterTasklet, ForEachTasklet, type IInterceptor, type IServerStorage, IteratorTasklet, type IteratorTaskletConfig, type LagInfo, LagTracker, type LagTrackerConfig, LockManager, type Logger, MapTasklet, MapWithResolver, type MapWithResolverConfig, MemoryServerAdapter, type MergeWithResolverResult, MigrationManager, type NativeModuleStatus, type NativeStats, type ORMapTombstones, type ORMapValue, ObjectPool, type ObjectPoolConfig, type ObjectPoolStats, type OpContext, type PartitionDistribution, PartitionService, type PartitionServiceConfig, type PartitionServiceEvents, type PooledEventPayload, type PooledMessage, type PooledRecord, type PooledTimestamp, PostgresAdapter, type PostgresAdapterOptions, ProcessorSandbox, type ProcessorSandboxConfig, type ProgressState, RateLimitInterceptor, type RateLimiterConfig, type RateLimiterStats, ReduceTasklet, ReplicationPipeline, SecurityManager, ServerCoordinator, type ServerCoordinatorConfig, type ServerOp, type SetWithResolverResult, type StorageValue, type Tasklet, TaskletScheduler, type TaskletSchedulerConfig, type TaskletSchedulerStats, TimestampInterceptor, coalescingPresets, createEventPayloadPool, createMessagePool, createRecordPool, createTimestampPool, getCoalescingPreset, getGlobalBufferPool, getGlobalEventPayloadPool, getGlobalMessagePool, getGlobalRecordPool, getGlobalTimestampPool, getNativeModuleStatus, getNativeStats, logNativeStatus, logger, setGlobalBufferPool, setGlobalEventPayloadPool, setGlobalMessagePool, setGlobalRecordPool, setGlobalTimestampPool };
|