@voidhash/mimic 0.0.1-alpha.7 → 0.0.1-alpha.8
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/.turbo/turbo-build.log +43 -15
- package/dist/Document-ChuFrTk1.cjs +571 -0
- package/dist/Document-CwiAFTIq.mjs +438 -0
- package/dist/Document-CwiAFTIq.mjs.map +1 -0
- package/dist/Presence-DKKP4v5X.d.cts +91 -0
- package/dist/Presence-DKKP4v5X.d.cts.map +1 -0
- package/dist/Presence-DdMVKcOv.mjs +110 -0
- package/dist/Presence-DdMVKcOv.mjs.map +1 -0
- package/dist/Presence-N8u7Eppr.d.mts +91 -0
- package/dist/Presence-N8u7Eppr.d.mts.map +1 -0
- package/dist/Presence-gWrmGBeu.cjs +126 -0
- package/dist/Primitive-BK7kfHJZ.d.cts +1165 -0
- package/dist/Primitive-BK7kfHJZ.d.cts.map +1 -0
- package/dist/Primitive-D1kdB6za.d.mts +1165 -0
- package/dist/Primitive-D1kdB6za.d.mts.map +1 -0
- package/dist/client/index.cjs +1456 -0
- package/dist/client/index.d.cts +692 -0
- package/dist/client/index.d.cts.map +1 -0
- package/dist/client/index.d.mts +692 -0
- package/dist/client/index.d.mts.map +1 -0
- package/dist/client/index.mjs +1413 -0
- package/dist/client/index.mjs.map +1 -0
- package/dist/index.cjs +224 -765
- package/dist/index.d.cts +5 -1152
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +5 -1152
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +69 -569
- package/dist/index.mjs.map +1 -1
- package/dist/server/index.cjs +191 -0
- package/dist/server/index.d.cts +148 -0
- package/dist/server/index.d.cts.map +1 -0
- package/dist/server/index.d.mts +148 -0
- package/dist/server/index.d.mts.map +1 -0
- package/dist/server/index.mjs +182 -0
- package/dist/server/index.mjs.map +1 -0
- package/package.json +16 -4
- package/src/primitives/Array.ts +25 -14
- package/src/primitives/Boolean.ts +29 -17
- package/src/primitives/Either.ts +30 -17
- package/src/primitives/Lazy.ts +16 -2
- package/src/primitives/Literal.ts +29 -18
- package/src/primitives/Number.ts +35 -24
- package/src/primitives/String.ts +36 -23
- package/src/primitives/Struct.ts +74 -26
- package/src/primitives/Tree.ts +30 -14
- package/src/primitives/Union.ts +21 -21
- package/src/primitives/shared.ts +27 -34
- package/tests/primitives/Array.test.ts +108 -0
- package/tests/primitives/Struct.test.ts +2 -2
- package/tests/primitives/Tree.test.ts +128 -0
- package/tsdown.config.ts +1 -1
- /package/dist/{chunk-C6wwvPpM.mjs → chunk-CLMFDpHK.mjs} +0 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
const require_Document = require('../Document-ChuFrTk1.cjs');
|
|
2
|
+
|
|
3
|
+
//#region src/server/ServerDocument.ts
|
|
4
|
+
var ServerDocument_exports = /* @__PURE__ */ require_Document.__export({ make: () => make });
|
|
5
|
+
/**
|
|
6
|
+
* Creates a new ServerDocument for the given schema.
|
|
7
|
+
*/
|
|
8
|
+
const make = (options) => {
|
|
9
|
+
const { schema, initialState, initialVersion = 0, onBroadcast, onRejection, maxTransactionHistory = 1e3 } = options;
|
|
10
|
+
let _document = require_Document.make(schema, { initial: initialState });
|
|
11
|
+
let _version = initialVersion;
|
|
12
|
+
const _processedTransactions = /* @__PURE__ */ new Set();
|
|
13
|
+
const _transactionOrder = [];
|
|
14
|
+
/**
|
|
15
|
+
* Records a transaction as processed, maintaining the history limit.
|
|
16
|
+
*/
|
|
17
|
+
const recordTransaction = (transactionId) => {
|
|
18
|
+
_processedTransactions.add(transactionId);
|
|
19
|
+
_transactionOrder.push(transactionId);
|
|
20
|
+
while (_transactionOrder.length > maxTransactionHistory) {
|
|
21
|
+
const oldest = _transactionOrder.shift();
|
|
22
|
+
if (oldest) _processedTransactions.delete(oldest);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Validates that the transaction can be applied to the current state.
|
|
27
|
+
* Creates a temporary document and attempts to apply the operations.
|
|
28
|
+
*/
|
|
29
|
+
const validateTransaction = (transaction) => {
|
|
30
|
+
if (require_Document.isEmpty(transaction)) return {
|
|
31
|
+
valid: false,
|
|
32
|
+
reason: "Transaction is empty"
|
|
33
|
+
};
|
|
34
|
+
if (_processedTransactions.has(transaction.id)) return {
|
|
35
|
+
valid: false,
|
|
36
|
+
reason: "Transaction has already been processed"
|
|
37
|
+
};
|
|
38
|
+
const currentState = _document.get();
|
|
39
|
+
const tempDoc = require_Document.make(schema, { initial: currentState });
|
|
40
|
+
try {
|
|
41
|
+
tempDoc.apply(transaction.ops);
|
|
42
|
+
return { valid: true };
|
|
43
|
+
} catch (error) {
|
|
44
|
+
return {
|
|
45
|
+
valid: false,
|
|
46
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
return {
|
|
51
|
+
schema,
|
|
52
|
+
get: () => {
|
|
53
|
+
return _document.get();
|
|
54
|
+
},
|
|
55
|
+
getVersion: () => {
|
|
56
|
+
return _version;
|
|
57
|
+
},
|
|
58
|
+
submit: (transaction) => {
|
|
59
|
+
const validation = validateTransaction(transaction);
|
|
60
|
+
if (!validation.valid) {
|
|
61
|
+
onRejection === null || onRejection === void 0 || onRejection(transaction.id, validation.reason);
|
|
62
|
+
return {
|
|
63
|
+
success: false,
|
|
64
|
+
reason: validation.reason
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
_document.apply(transaction.ops);
|
|
69
|
+
} catch (error) {
|
|
70
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
71
|
+
onRejection === null || onRejection === void 0 || onRejection(transaction.id, reason);
|
|
72
|
+
return {
|
|
73
|
+
success: false,
|
|
74
|
+
reason
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
_version += 1;
|
|
78
|
+
recordTransaction(transaction.id);
|
|
79
|
+
onBroadcast({
|
|
80
|
+
type: "transaction",
|
|
81
|
+
transaction,
|
|
82
|
+
version: _version
|
|
83
|
+
});
|
|
84
|
+
return {
|
|
85
|
+
success: true,
|
|
86
|
+
version: _version
|
|
87
|
+
};
|
|
88
|
+
},
|
|
89
|
+
getSnapshot: () => {
|
|
90
|
+
return {
|
|
91
|
+
type: "snapshot",
|
|
92
|
+
state: _document.get(),
|
|
93
|
+
version: _version
|
|
94
|
+
};
|
|
95
|
+
},
|
|
96
|
+
hasProcessed: (transactionId) => {
|
|
97
|
+
return _processedTransactions.has(transactionId);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
//#endregion
|
|
103
|
+
//#region src/server/errors.ts
|
|
104
|
+
/**
|
|
105
|
+
* Base error class for all mimic-server errors.
|
|
106
|
+
*/
|
|
107
|
+
var MimicServerError = class extends Error {
|
|
108
|
+
constructor(message) {
|
|
109
|
+
super(message);
|
|
110
|
+
require_Document._defineProperty(this, "_tag", "MimicServerError");
|
|
111
|
+
this.name = "MimicServerError";
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* Error thrown when a transaction fails validation.
|
|
116
|
+
*/
|
|
117
|
+
var ValidationError = class extends MimicServerError {
|
|
118
|
+
constructor(transactionId, message) {
|
|
119
|
+
super(`Transaction ${transactionId} validation failed: ${message}`);
|
|
120
|
+
require_Document._defineProperty(this, "_tag", "ValidationError");
|
|
121
|
+
require_Document._defineProperty(this, "transactionId", void 0);
|
|
122
|
+
this.name = "ValidationError";
|
|
123
|
+
this.transactionId = transactionId;
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* Error thrown when an operation is invalid for the current schema.
|
|
128
|
+
*/
|
|
129
|
+
var InvalidOperationError = class extends MimicServerError {
|
|
130
|
+
constructor(operationKind, path, message) {
|
|
131
|
+
super(`Invalid operation ${operationKind} at path "${path}": ${message}`);
|
|
132
|
+
require_Document._defineProperty(this, "_tag", "InvalidOperationError");
|
|
133
|
+
require_Document._defineProperty(this, "operationKind", void 0);
|
|
134
|
+
require_Document._defineProperty(this, "path", void 0);
|
|
135
|
+
this.name = "InvalidOperationError";
|
|
136
|
+
this.operationKind = operationKind;
|
|
137
|
+
this.path = path;
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
/**
|
|
141
|
+
* Error thrown when an operation cannot be applied to the current state.
|
|
142
|
+
*/
|
|
143
|
+
var StateValidationError = class extends MimicServerError {
|
|
144
|
+
constructor(transactionId, message, cause) {
|
|
145
|
+
super(`Transaction ${transactionId} cannot be applied to current state: ${message}`);
|
|
146
|
+
require_Document._defineProperty(this, "_tag", "StateValidationError");
|
|
147
|
+
require_Document._defineProperty(this, "transactionId", void 0);
|
|
148
|
+
require_Document._defineProperty(this, "cause", void 0);
|
|
149
|
+
this.name = "StateValidationError";
|
|
150
|
+
this.transactionId = transactionId;
|
|
151
|
+
this.cause = cause;
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
/**
|
|
155
|
+
* Error thrown when attempting to apply an empty transaction.
|
|
156
|
+
*/
|
|
157
|
+
var EmptyTransactionError = class extends MimicServerError {
|
|
158
|
+
constructor(transactionId) {
|
|
159
|
+
super(`Transaction ${transactionId} is empty and cannot be applied`);
|
|
160
|
+
require_Document._defineProperty(this, "_tag", "EmptyTransactionError");
|
|
161
|
+
require_Document._defineProperty(this, "transactionId", void 0);
|
|
162
|
+
this.name = "EmptyTransactionError";
|
|
163
|
+
this.transactionId = transactionId;
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
/**
|
|
167
|
+
* Error thrown when a duplicate transaction is submitted.
|
|
168
|
+
*/
|
|
169
|
+
var DuplicateTransactionError = class extends MimicServerError {
|
|
170
|
+
constructor(transactionId) {
|
|
171
|
+
super(`Transaction ${transactionId} has already been processed`);
|
|
172
|
+
require_Document._defineProperty(this, "_tag", "DuplicateTransactionError");
|
|
173
|
+
require_Document._defineProperty(this, "transactionId", void 0);
|
|
174
|
+
this.name = "DuplicateTransactionError";
|
|
175
|
+
this.transactionId = transactionId;
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
//#endregion
|
|
180
|
+
exports.DuplicateTransactionError = DuplicateTransactionError;
|
|
181
|
+
exports.EmptyTransactionError = EmptyTransactionError;
|
|
182
|
+
exports.InvalidOperationError = InvalidOperationError;
|
|
183
|
+
exports.MimicServerError = MimicServerError;
|
|
184
|
+
Object.defineProperty(exports, 'ServerDocument', {
|
|
185
|
+
enumerable: true,
|
|
186
|
+
get: function () {
|
|
187
|
+
return ServerDocument_exports;
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
exports.StateValidationError = StateValidationError;
|
|
191
|
+
exports.ValidationError = ValidationError;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { a as InferState, h as __export, n as AnyPrimitive, u as Transaction } from "../Primitive-BK7kfHJZ.cjs";
|
|
2
|
+
|
|
3
|
+
//#region src/server/ServerDocument.d.ts
|
|
4
|
+
declare namespace ServerDocument_d_exports {
|
|
5
|
+
export { ErrorMessage, ServerDocument, ServerDocumentOptions, ServerMessage, SnapshotMessage, SubmitResult, TransactionMessage, make };
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Message sent when broadcasting a committed transaction.
|
|
9
|
+
*/
|
|
10
|
+
interface TransactionMessage {
|
|
11
|
+
readonly type: "transaction";
|
|
12
|
+
readonly transaction: Transaction;
|
|
13
|
+
/** Server-assigned version number for ordering */
|
|
14
|
+
readonly version: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Message sent when a transaction is rejected.
|
|
18
|
+
*/
|
|
19
|
+
interface ErrorMessage {
|
|
20
|
+
readonly type: "error";
|
|
21
|
+
readonly transactionId: string;
|
|
22
|
+
readonly reason: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Message sent as a full state snapshot.
|
|
26
|
+
*/
|
|
27
|
+
interface SnapshotMessage {
|
|
28
|
+
readonly type: "snapshot";
|
|
29
|
+
readonly state: unknown;
|
|
30
|
+
readonly version: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Union of all server messages that can be broadcast.
|
|
34
|
+
*/
|
|
35
|
+
type ServerMessage = TransactionMessage | ErrorMessage | SnapshotMessage;
|
|
36
|
+
/**
|
|
37
|
+
* Result of submitting a transaction to the server.
|
|
38
|
+
*/
|
|
39
|
+
type SubmitResult = {
|
|
40
|
+
readonly success: true;
|
|
41
|
+
readonly version: number;
|
|
42
|
+
} | {
|
|
43
|
+
readonly success: false;
|
|
44
|
+
readonly reason: string;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Options for creating a ServerDocument.
|
|
48
|
+
*/
|
|
49
|
+
interface ServerDocumentOptions<TSchema extends AnyPrimitive> {
|
|
50
|
+
/** The schema defining the document structure */
|
|
51
|
+
readonly schema: TSchema;
|
|
52
|
+
/** Initial state (optional, will use schema defaults if not provided) */
|
|
53
|
+
readonly initialState?: InferState<TSchema>;
|
|
54
|
+
/** Initial version number (optional, defaults to 0) */
|
|
55
|
+
readonly initialVersion?: number;
|
|
56
|
+
/** Called when a transaction is successfully applied and should be broadcast */
|
|
57
|
+
readonly onBroadcast: (message: TransactionMessage) => void;
|
|
58
|
+
/** Called when a transaction is rejected (optional, for logging/metrics) */
|
|
59
|
+
readonly onRejection?: (transactionId: string, reason: string) => void;
|
|
60
|
+
/** Maximum number of processed transaction IDs to track for deduplication */
|
|
61
|
+
readonly maxTransactionHistory?: number;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* A ServerDocument maintains the authoritative state and processes client transactions.
|
|
65
|
+
*/
|
|
66
|
+
interface ServerDocument<TSchema extends AnyPrimitive> {
|
|
67
|
+
/** The schema defining this document's structure */
|
|
68
|
+
readonly schema: TSchema;
|
|
69
|
+
/** Returns the current authoritative state */
|
|
70
|
+
get(): InferState<TSchema> | undefined;
|
|
71
|
+
/** Returns the current version number */
|
|
72
|
+
getVersion(): number;
|
|
73
|
+
/**
|
|
74
|
+
* Submits a transaction for processing.
|
|
75
|
+
* Validates and applies the transaction if valid, or rejects it with a reason.
|
|
76
|
+
* @param transaction - The transaction to process
|
|
77
|
+
* @returns SubmitResult indicating success with version or failure with reason
|
|
78
|
+
*/
|
|
79
|
+
submit(transaction: Transaction): SubmitResult;
|
|
80
|
+
/**
|
|
81
|
+
* Returns a snapshot of the current state and version.
|
|
82
|
+
* Used to initialize new clients or resync after drift.
|
|
83
|
+
*/
|
|
84
|
+
getSnapshot(): SnapshotMessage;
|
|
85
|
+
/**
|
|
86
|
+
* Checks if a transaction has already been processed.
|
|
87
|
+
* @param transactionId - The transaction ID to check
|
|
88
|
+
*/
|
|
89
|
+
hasProcessed(transactionId: string): boolean;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Creates a new ServerDocument for the given schema.
|
|
93
|
+
*/
|
|
94
|
+
declare const make: <TSchema extends AnyPrimitive>(options: ServerDocumentOptions<TSchema>) => ServerDocument<TSchema>;
|
|
95
|
+
//#endregion
|
|
96
|
+
//#region src/server/errors.d.ts
|
|
97
|
+
/**
|
|
98
|
+
* Base error class for all mimic-server errors.
|
|
99
|
+
*/
|
|
100
|
+
declare class MimicServerError extends Error {
|
|
101
|
+
readonly _tag: string;
|
|
102
|
+
constructor(message: string);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Error thrown when a transaction fails validation.
|
|
106
|
+
*/
|
|
107
|
+
declare class ValidationError extends MimicServerError {
|
|
108
|
+
readonly _tag = "ValidationError";
|
|
109
|
+
readonly transactionId: string;
|
|
110
|
+
constructor(transactionId: string, message: string);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Error thrown when an operation is invalid for the current schema.
|
|
114
|
+
*/
|
|
115
|
+
declare class InvalidOperationError extends MimicServerError {
|
|
116
|
+
readonly _tag = "InvalidOperationError";
|
|
117
|
+
readonly operationKind: string;
|
|
118
|
+
readonly path: string;
|
|
119
|
+
constructor(operationKind: string, path: string, message: string);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Error thrown when an operation cannot be applied to the current state.
|
|
123
|
+
*/
|
|
124
|
+
declare class StateValidationError extends MimicServerError {
|
|
125
|
+
readonly _tag = "StateValidationError";
|
|
126
|
+
readonly transactionId: string;
|
|
127
|
+
readonly cause?: Error;
|
|
128
|
+
constructor(transactionId: string, message: string, cause?: Error);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Error thrown when attempting to apply an empty transaction.
|
|
132
|
+
*/
|
|
133
|
+
declare class EmptyTransactionError extends MimicServerError {
|
|
134
|
+
readonly _tag = "EmptyTransactionError";
|
|
135
|
+
readonly transactionId: string;
|
|
136
|
+
constructor(transactionId: string);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Error thrown when a duplicate transaction is submitted.
|
|
140
|
+
*/
|
|
141
|
+
declare class DuplicateTransactionError extends MimicServerError {
|
|
142
|
+
readonly _tag = "DuplicateTransactionError";
|
|
143
|
+
readonly transactionId: string;
|
|
144
|
+
constructor(transactionId: string);
|
|
145
|
+
}
|
|
146
|
+
//#endregion
|
|
147
|
+
export { DuplicateTransactionError, EmptyTransactionError, type ErrorMessage, InvalidOperationError, MimicServerError, ServerDocument_d_exports as ServerDocument, type ServerDocumentOptions, type ServerMessage, type SnapshotMessage, StateValidationError, type SubmitResult, type TransactionMessage, ValidationError };
|
|
148
|
+
//# sourceMappingURL=index.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/server/ServerDocument.ts","../../src/server/errors.ts"],"sourcesContent":[],"mappings":";;;;;;;;;UAWiB,kBAAA;;wBAEO;;;;;;AAFxB;AAUiB,UAAA,YAAA,CAAY;EASZ,SAAA,IAAA,EAAA,OAAe;EASpB,SAAA,aAAa,EAAA,MAAA;EAAG,SAAA,MAAA,EAAA,MAAA;;;;AAS5B;AAWiB,UA7BA,eAAA,CA6BqB;EAAiB,SAAA,IAAA,EAAA,UAAA;EAEpC,SAAA,KAAA,EAAA,OAAA;EAE4B,SAAA,OAAA,EAAA,MAAA;;;;AAc/C;AAAgD,KAtCpC,aAAA,GAAgB,kBAsCoB,GAtCC,YAsCD,GAtCgB,eAsChB;;;;AAgB1B,KA7CV,YAAA,GA6CU;EAA0B,SAAA,OAAA,EAAA,IAAA;EAM/B,SAAA,OAAA,EAAA,MAAA;CAAe,GAAA;EAgBnB,SAuJZ,OAAA,EAAA,KAAA;EAvJoC,SAAA,MAAA,EAAA,MAAA;CACJ;;;;AAChB,UA1DA,qBA0DA,CAAA,gBA1DsC,YA0DtC,CAAA,CAAA;;mBAxDE;;ECpDN,SAAA,YAAiB,CAAA,EDsDJ,UCtDiB,CDsDI,OCtDJ,CAAA;EAW9B;EAcA,SAAA,cAAA,CAAsB,EAAA,MAAA;EAgBtB;EAGe,SAAA,WAAA,EAAA,CAAA,OAAA,EDcM,kBCdN,EAAA,GAAA,IAAA;EAEkC;EALpB,SAAA,WAAA,CAAA,EAAA,CAAA,aAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,GAAA,IAAA;EAAgB;EAgB7C,SAAA,qBAAsB,CAAA,EAAA,MAAQ;AAc3C;;;;UDHiB,+BAA+B;;mBAE7B;;SAGV,WAAqB;;;;;;;;;sBAWR,cAA0B;;;;;iBAM/B;;;;;;;;;;cAgBJ,uBAAwB,uBAC1B,sBAAsB,aAC9B,eAAe;;;;;;cC5GL,gBAAA,SAAyB,KAAA;;;;;;;cAWzB,eAAA,SAAwB,gBAAA;;;EDTpB,WAAA,CAAA,aAAkB,EAAA,MAEX,EAAA,OAAA,EAAA,MAAuB;AAQ/C;AASA;AASA;;AAAiD,cCLpC,qBAAA,SAA8B,gBAAA,CDKM;EAAe,SAAA,IAAA,GAAA,uBAAA;EAAe,SAAA,aAAA,EAAA,MAAA;EASnE,SAAA,IAAA,EAAY,MAAA;EAWP,WAAA,CAAA,aAAqB,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,EAAA,OAAA,EAAA,MAAA;;;;;AAQJ,cCjBrB,oBAAA,SAA6B,gBAAA,CDiBR;EAAkB,SAAA,IAAA,GAAA,sBAAA;EAUnC,SAAA,aAAc,EAAA,MAAA;EAAiB,SAAA,KAAA,CAAA,ECxBpB,KDwBoB;EAE7B,WAAA,CAAA,aAAA,EAAA,MAAA,EAAA,OAAA,EAAA,MAAA,EAAA,KAAA,CAAA,ECxB2C,KDwB3C;;;;;AAoBF,cCjCJ,qBAAA,SAA8B,gBAAA,CDiC1B;EAAe,SAAA,IAAA,GAAA,uBAAA;EAgBnB,SAuJZ,aAAA,EAAA,MAAA;EAvJoC,WAAA,CAAA,aAAA,EAAA,MAAA;;;;;AAEpB,cCrCJ,yBAAA,SAAkC,gBAAA,CDqC9B;;;;AC5GjB"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { a as InferState, n as AnyPrimitive, u as Transaction } from "../Primitive-D1kdB6za.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/server/ServerDocument.d.ts
|
|
4
|
+
declare namespace ServerDocument_d_exports {
|
|
5
|
+
export { ErrorMessage, ServerDocument, ServerDocumentOptions, ServerMessage, SnapshotMessage, SubmitResult, TransactionMessage, make };
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Message sent when broadcasting a committed transaction.
|
|
9
|
+
*/
|
|
10
|
+
interface TransactionMessage {
|
|
11
|
+
readonly type: "transaction";
|
|
12
|
+
readonly transaction: Transaction;
|
|
13
|
+
/** Server-assigned version number for ordering */
|
|
14
|
+
readonly version: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Message sent when a transaction is rejected.
|
|
18
|
+
*/
|
|
19
|
+
interface ErrorMessage {
|
|
20
|
+
readonly type: "error";
|
|
21
|
+
readonly transactionId: string;
|
|
22
|
+
readonly reason: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Message sent as a full state snapshot.
|
|
26
|
+
*/
|
|
27
|
+
interface SnapshotMessage {
|
|
28
|
+
readonly type: "snapshot";
|
|
29
|
+
readonly state: unknown;
|
|
30
|
+
readonly version: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Union of all server messages that can be broadcast.
|
|
34
|
+
*/
|
|
35
|
+
type ServerMessage = TransactionMessage | ErrorMessage | SnapshotMessage;
|
|
36
|
+
/**
|
|
37
|
+
* Result of submitting a transaction to the server.
|
|
38
|
+
*/
|
|
39
|
+
type SubmitResult = {
|
|
40
|
+
readonly success: true;
|
|
41
|
+
readonly version: number;
|
|
42
|
+
} | {
|
|
43
|
+
readonly success: false;
|
|
44
|
+
readonly reason: string;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Options for creating a ServerDocument.
|
|
48
|
+
*/
|
|
49
|
+
interface ServerDocumentOptions<TSchema extends AnyPrimitive> {
|
|
50
|
+
/** The schema defining the document structure */
|
|
51
|
+
readonly schema: TSchema;
|
|
52
|
+
/** Initial state (optional, will use schema defaults if not provided) */
|
|
53
|
+
readonly initialState?: InferState<TSchema>;
|
|
54
|
+
/** Initial version number (optional, defaults to 0) */
|
|
55
|
+
readonly initialVersion?: number;
|
|
56
|
+
/** Called when a transaction is successfully applied and should be broadcast */
|
|
57
|
+
readonly onBroadcast: (message: TransactionMessage) => void;
|
|
58
|
+
/** Called when a transaction is rejected (optional, for logging/metrics) */
|
|
59
|
+
readonly onRejection?: (transactionId: string, reason: string) => void;
|
|
60
|
+
/** Maximum number of processed transaction IDs to track for deduplication */
|
|
61
|
+
readonly maxTransactionHistory?: number;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* A ServerDocument maintains the authoritative state and processes client transactions.
|
|
65
|
+
*/
|
|
66
|
+
interface ServerDocument<TSchema extends AnyPrimitive> {
|
|
67
|
+
/** The schema defining this document's structure */
|
|
68
|
+
readonly schema: TSchema;
|
|
69
|
+
/** Returns the current authoritative state */
|
|
70
|
+
get(): InferState<TSchema> | undefined;
|
|
71
|
+
/** Returns the current version number */
|
|
72
|
+
getVersion(): number;
|
|
73
|
+
/**
|
|
74
|
+
* Submits a transaction for processing.
|
|
75
|
+
* Validates and applies the transaction if valid, or rejects it with a reason.
|
|
76
|
+
* @param transaction - The transaction to process
|
|
77
|
+
* @returns SubmitResult indicating success with version or failure with reason
|
|
78
|
+
*/
|
|
79
|
+
submit(transaction: Transaction): SubmitResult;
|
|
80
|
+
/**
|
|
81
|
+
* Returns a snapshot of the current state and version.
|
|
82
|
+
* Used to initialize new clients or resync after drift.
|
|
83
|
+
*/
|
|
84
|
+
getSnapshot(): SnapshotMessage;
|
|
85
|
+
/**
|
|
86
|
+
* Checks if a transaction has already been processed.
|
|
87
|
+
* @param transactionId - The transaction ID to check
|
|
88
|
+
*/
|
|
89
|
+
hasProcessed(transactionId: string): boolean;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Creates a new ServerDocument for the given schema.
|
|
93
|
+
*/
|
|
94
|
+
declare const make: <TSchema extends AnyPrimitive>(options: ServerDocumentOptions<TSchema>) => ServerDocument<TSchema>;
|
|
95
|
+
//#endregion
|
|
96
|
+
//#region src/server/errors.d.ts
|
|
97
|
+
/**
|
|
98
|
+
* Base error class for all mimic-server errors.
|
|
99
|
+
*/
|
|
100
|
+
declare class MimicServerError extends Error {
|
|
101
|
+
readonly _tag: string;
|
|
102
|
+
constructor(message: string);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Error thrown when a transaction fails validation.
|
|
106
|
+
*/
|
|
107
|
+
declare class ValidationError extends MimicServerError {
|
|
108
|
+
readonly _tag = "ValidationError";
|
|
109
|
+
readonly transactionId: string;
|
|
110
|
+
constructor(transactionId: string, message: string);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Error thrown when an operation is invalid for the current schema.
|
|
114
|
+
*/
|
|
115
|
+
declare class InvalidOperationError extends MimicServerError {
|
|
116
|
+
readonly _tag = "InvalidOperationError";
|
|
117
|
+
readonly operationKind: string;
|
|
118
|
+
readonly path: string;
|
|
119
|
+
constructor(operationKind: string, path: string, message: string);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Error thrown when an operation cannot be applied to the current state.
|
|
123
|
+
*/
|
|
124
|
+
declare class StateValidationError extends MimicServerError {
|
|
125
|
+
readonly _tag = "StateValidationError";
|
|
126
|
+
readonly transactionId: string;
|
|
127
|
+
readonly cause?: Error;
|
|
128
|
+
constructor(transactionId: string, message: string, cause?: Error);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Error thrown when attempting to apply an empty transaction.
|
|
132
|
+
*/
|
|
133
|
+
declare class EmptyTransactionError extends MimicServerError {
|
|
134
|
+
readonly _tag = "EmptyTransactionError";
|
|
135
|
+
readonly transactionId: string;
|
|
136
|
+
constructor(transactionId: string);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Error thrown when a duplicate transaction is submitted.
|
|
140
|
+
*/
|
|
141
|
+
declare class DuplicateTransactionError extends MimicServerError {
|
|
142
|
+
readonly _tag = "DuplicateTransactionError";
|
|
143
|
+
readonly transactionId: string;
|
|
144
|
+
constructor(transactionId: string);
|
|
145
|
+
}
|
|
146
|
+
//#endregion
|
|
147
|
+
export { DuplicateTransactionError, EmptyTransactionError, type ErrorMessage, InvalidOperationError, MimicServerError, ServerDocument_d_exports as ServerDocument, type ServerDocumentOptions, type ServerMessage, type SnapshotMessage, StateValidationError, type SubmitResult, type TransactionMessage, ValidationError };
|
|
148
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/server/ServerDocument.ts","../../src/server/errors.ts"],"sourcesContent":[],"mappings":";;;;;;;;;UAWiB,kBAAA;;wBAEO;;;;;;;AAFP,UAUA,YAAA,CAVkB;EAUlB,SAAA,IAAA,EAAY,OAAA;EASZ,SAAA,aAAe,EAAA,MAAA;EASpB,SAAA,MAAA,EAAa,MAAA;;;;;AASb,UAlBK,eAAA,CAkBO;EAWP,SAAA,IAAA,EAAA,UAAqB;EAAiB,SAAA,KAAA,EAAA,OAAA;EAEpC,SAAA,OAAA,EAAA,MAAA;;;;;AAgBF,KAtCL,aAAA,GAAgB,kBAsCG,GAtCkB,YAsClB,GAtCiC,eAsCjC;;;;AAKtB,KAlCG,YAAA,GAkCH;EAWa,SAAA,OAAA,EAAA,IAAA;EAA0B,SAAA,OAAA,EAAA,MAAA;CAM/B,GAAA;EAAe,SAAA,OAAA,EAAA,KAAA;EAgBnB,SAuJZ,MAAA,EAAA,MAAA;CAvJoC;;;;AAElC,UA1Dc,qBA0Dd,CAAA,gBA1DoD,YA0DpD,CAAA,CAAA;EAAc;mBAxDE;;0BAEO,WAAqB;ECtDlC;EAWA,SAAA,cAAgB,CAAA,EAAA,MAAQ;EAcxB;EAgBA,SAAA,WAAA,EAAA,CAAqB,OAAA,EDiBA,kBCjBA,EAAA,GAAA,IAAA;EAGN;EAEkC,SAAA,WAAA,CAAA,EAAA,CAAA,aAAA,EAAA,MAAA,EAAA,MAAA,EAAA,MAAA,EAAA,GAAA,IAAA;EALpB;EAAgB,SAAA,qBAAA,CAAA,EAAA,MAAA;AAgB1D;AAcA;;;UDHiB,+BAA+B;;mBAE7B;;SAGV,WAAqB;;;;;;;;;sBAWR,cAA0B;;;;;iBAM/B;;;;;;;;;;cAgBJ,uBAAwB,uBAC1B,sBAAsB,aAC9B,eAAe;;;;;;cC5GL,gBAAA,SAAyB,KAAA;;;;;;;cAWzB,eAAA,SAAwB,gBAAA;;;;ADTrC;AAUA;AASA;AASA;AAA4B,cCLf,qBAAA,SAA8B,gBAAA,CDKf;EAAqB,SAAA,IAAA,GAAA,uBAAA;EAAe,SAAA,aAAA,EAAA,MAAA;EAAe,SAAA,IAAA,EAAA,MAAA;EASnE,WAAA,CAAA,aAAY,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,EAAA,OAAA,EAAA,MAAA;AAWxB;;;;AAI0B,cCbb,oBAAA,SAA6B,gBAAA,CDahB;EAIQ,SAAA,IAAA,GAAA,sBAAA;EAAkB,SAAA,aAAA,EAAA,MAAA;EAUnC,SAAA,KAAA,CAAA,ECxBW,KDwBG;EAAiB,WAAA,CAAA,aAAA,EAAA,MAAA,EAAA,OAAA,EAAA,MAAA,EAAA,KAAA,CAAA,ECtBc,KDsBd;;;;;AAgBA,cC3BnC,qBAAA,SAA8B,gBAAA,CD2BK;EAM/B,SAAA,IAAA,GAAA,uBAAA;EAAe,SAAA,aAAA,EAAA,MAAA;EAgBnB,WAuJZ,CAAA,aAAA,EAAA,MAAA;;;;;AArJE,cCrCU,yBAAA,SAAkC,gBAAA,CDqC5C;EAAc,SAAA,IAAA,GAAA,2BAAA"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { t as __export } from "../chunk-CLMFDpHK.mjs";
|
|
2
|
+
import { m as _defineProperty, n as make$1, o as isEmpty } from "../Document-CwiAFTIq.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/server/ServerDocument.ts
|
|
5
|
+
var ServerDocument_exports = /* @__PURE__ */ __export({ make: () => make });
|
|
6
|
+
/**
|
|
7
|
+
* Creates a new ServerDocument for the given schema.
|
|
8
|
+
*/
|
|
9
|
+
const make = (options) => {
|
|
10
|
+
const { schema, initialState, initialVersion = 0, onBroadcast, onRejection, maxTransactionHistory = 1e3 } = options;
|
|
11
|
+
let _document = make$1(schema, { initial: initialState });
|
|
12
|
+
let _version = initialVersion;
|
|
13
|
+
const _processedTransactions = /* @__PURE__ */ new Set();
|
|
14
|
+
const _transactionOrder = [];
|
|
15
|
+
/**
|
|
16
|
+
* Records a transaction as processed, maintaining the history limit.
|
|
17
|
+
*/
|
|
18
|
+
const recordTransaction = (transactionId) => {
|
|
19
|
+
_processedTransactions.add(transactionId);
|
|
20
|
+
_transactionOrder.push(transactionId);
|
|
21
|
+
while (_transactionOrder.length > maxTransactionHistory) {
|
|
22
|
+
const oldest = _transactionOrder.shift();
|
|
23
|
+
if (oldest) _processedTransactions.delete(oldest);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Validates that the transaction can be applied to the current state.
|
|
28
|
+
* Creates a temporary document and attempts to apply the operations.
|
|
29
|
+
*/
|
|
30
|
+
const validateTransaction = (transaction) => {
|
|
31
|
+
if (isEmpty(transaction)) return {
|
|
32
|
+
valid: false,
|
|
33
|
+
reason: "Transaction is empty"
|
|
34
|
+
};
|
|
35
|
+
if (_processedTransactions.has(transaction.id)) return {
|
|
36
|
+
valid: false,
|
|
37
|
+
reason: "Transaction has already been processed"
|
|
38
|
+
};
|
|
39
|
+
const currentState = _document.get();
|
|
40
|
+
const tempDoc = make$1(schema, { initial: currentState });
|
|
41
|
+
try {
|
|
42
|
+
tempDoc.apply(transaction.ops);
|
|
43
|
+
return { valid: true };
|
|
44
|
+
} catch (error) {
|
|
45
|
+
return {
|
|
46
|
+
valid: false,
|
|
47
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
return {
|
|
52
|
+
schema,
|
|
53
|
+
get: () => {
|
|
54
|
+
return _document.get();
|
|
55
|
+
},
|
|
56
|
+
getVersion: () => {
|
|
57
|
+
return _version;
|
|
58
|
+
},
|
|
59
|
+
submit: (transaction) => {
|
|
60
|
+
const validation = validateTransaction(transaction);
|
|
61
|
+
if (!validation.valid) {
|
|
62
|
+
onRejection === null || onRejection === void 0 || onRejection(transaction.id, validation.reason);
|
|
63
|
+
return {
|
|
64
|
+
success: false,
|
|
65
|
+
reason: validation.reason
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
_document.apply(transaction.ops);
|
|
70
|
+
} catch (error) {
|
|
71
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
72
|
+
onRejection === null || onRejection === void 0 || onRejection(transaction.id, reason);
|
|
73
|
+
return {
|
|
74
|
+
success: false,
|
|
75
|
+
reason
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
_version += 1;
|
|
79
|
+
recordTransaction(transaction.id);
|
|
80
|
+
onBroadcast({
|
|
81
|
+
type: "transaction",
|
|
82
|
+
transaction,
|
|
83
|
+
version: _version
|
|
84
|
+
});
|
|
85
|
+
return {
|
|
86
|
+
success: true,
|
|
87
|
+
version: _version
|
|
88
|
+
};
|
|
89
|
+
},
|
|
90
|
+
getSnapshot: () => {
|
|
91
|
+
return {
|
|
92
|
+
type: "snapshot",
|
|
93
|
+
state: _document.get(),
|
|
94
|
+
version: _version
|
|
95
|
+
};
|
|
96
|
+
},
|
|
97
|
+
hasProcessed: (transactionId) => {
|
|
98
|
+
return _processedTransactions.has(transactionId);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
//#endregion
|
|
104
|
+
//#region src/server/errors.ts
|
|
105
|
+
/**
|
|
106
|
+
* Base error class for all mimic-server errors.
|
|
107
|
+
*/
|
|
108
|
+
var MimicServerError = class extends Error {
|
|
109
|
+
constructor(message) {
|
|
110
|
+
super(message);
|
|
111
|
+
_defineProperty(this, "_tag", "MimicServerError");
|
|
112
|
+
this.name = "MimicServerError";
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
/**
|
|
116
|
+
* Error thrown when a transaction fails validation.
|
|
117
|
+
*/
|
|
118
|
+
var ValidationError = class extends MimicServerError {
|
|
119
|
+
constructor(transactionId, message) {
|
|
120
|
+
super(`Transaction ${transactionId} validation failed: ${message}`);
|
|
121
|
+
_defineProperty(this, "_tag", "ValidationError");
|
|
122
|
+
_defineProperty(this, "transactionId", void 0);
|
|
123
|
+
this.name = "ValidationError";
|
|
124
|
+
this.transactionId = transactionId;
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
/**
|
|
128
|
+
* Error thrown when an operation is invalid for the current schema.
|
|
129
|
+
*/
|
|
130
|
+
var InvalidOperationError = class extends MimicServerError {
|
|
131
|
+
constructor(operationKind, path, message) {
|
|
132
|
+
super(`Invalid operation ${operationKind} at path "${path}": ${message}`);
|
|
133
|
+
_defineProperty(this, "_tag", "InvalidOperationError");
|
|
134
|
+
_defineProperty(this, "operationKind", void 0);
|
|
135
|
+
_defineProperty(this, "path", void 0);
|
|
136
|
+
this.name = "InvalidOperationError";
|
|
137
|
+
this.operationKind = operationKind;
|
|
138
|
+
this.path = path;
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
/**
|
|
142
|
+
* Error thrown when an operation cannot be applied to the current state.
|
|
143
|
+
*/
|
|
144
|
+
var StateValidationError = class extends MimicServerError {
|
|
145
|
+
constructor(transactionId, message, cause) {
|
|
146
|
+
super(`Transaction ${transactionId} cannot be applied to current state: ${message}`);
|
|
147
|
+
_defineProperty(this, "_tag", "StateValidationError");
|
|
148
|
+
_defineProperty(this, "transactionId", void 0);
|
|
149
|
+
_defineProperty(this, "cause", void 0);
|
|
150
|
+
this.name = "StateValidationError";
|
|
151
|
+
this.transactionId = transactionId;
|
|
152
|
+
this.cause = cause;
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
/**
|
|
156
|
+
* Error thrown when attempting to apply an empty transaction.
|
|
157
|
+
*/
|
|
158
|
+
var EmptyTransactionError = class extends MimicServerError {
|
|
159
|
+
constructor(transactionId) {
|
|
160
|
+
super(`Transaction ${transactionId} is empty and cannot be applied`);
|
|
161
|
+
_defineProperty(this, "_tag", "EmptyTransactionError");
|
|
162
|
+
_defineProperty(this, "transactionId", void 0);
|
|
163
|
+
this.name = "EmptyTransactionError";
|
|
164
|
+
this.transactionId = transactionId;
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
/**
|
|
168
|
+
* Error thrown when a duplicate transaction is submitted.
|
|
169
|
+
*/
|
|
170
|
+
var DuplicateTransactionError = class extends MimicServerError {
|
|
171
|
+
constructor(transactionId) {
|
|
172
|
+
super(`Transaction ${transactionId} has already been processed`);
|
|
173
|
+
_defineProperty(this, "_tag", "DuplicateTransactionError");
|
|
174
|
+
_defineProperty(this, "transactionId", void 0);
|
|
175
|
+
this.name = "DuplicateTransactionError";
|
|
176
|
+
this.transactionId = transactionId;
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
//#endregion
|
|
181
|
+
export { DuplicateTransactionError, EmptyTransactionError, InvalidOperationError, MimicServerError, ServerDocument_exports as ServerDocument, StateValidationError, ValidationError };
|
|
182
|
+
//# sourceMappingURL=index.mjs.map
|