@voidhash/mimic 0.0.1-alpha.5 → 0.0.1-alpha.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voidhash/mimic",
3
- "version": "0.0.1-alpha.5",
3
+ "version": "0.0.1-alpha.6",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -19,7 +19,7 @@
19
19
  "typescript": "5.8.3",
20
20
  "vite-tsconfig-paths": "^5.1.4",
21
21
  "vitest": "^3.2.4",
22
- "@voidhash/tsconfig": "0.0.1-alpha.5"
22
+ "@voidhash/tsconfig": "0.0.1-alpha.6"
23
23
  },
24
24
  "peerDependencies": {
25
25
  "effect": "^3.19.12"
@@ -43,7 +43,7 @@ type InitState =
43
43
  /**
44
44
  * Listener for presence changes.
45
45
  */
46
- export interface PresenceListener<TData> {
46
+ export interface PresenceListener<_TData> {
47
47
  /** Called when any presence changes (self or others) */
48
48
  readonly onPresenceChange?: () => void;
49
49
  }
@@ -19,7 +19,7 @@ export class MimicClientError extends Error {
19
19
  * Error thrown when a transaction is rejected by the server.
20
20
  */
21
21
  export class TransactionRejectedError extends MimicClientError {
22
- readonly _tag = "TransactionRejectedError";
22
+ override readonly _tag = "TransactionRejectedError";
23
23
  readonly transaction: Transaction.Transaction;
24
24
  readonly reason: string;
25
25
 
@@ -35,7 +35,7 @@ export class TransactionRejectedError extends MimicClientError {
35
35
  * Error thrown when the transport is not connected.
36
36
  */
37
37
  export class NotConnectedError extends MimicClientError {
38
- readonly _tag = "NotConnectedError";
38
+ override readonly _tag = "NotConnectedError";
39
39
  constructor() {
40
40
  super("Transport is not connected");
41
41
  this.name = "NotConnectedError";
@@ -46,8 +46,8 @@ export class NotConnectedError extends MimicClientError {
46
46
  * Error thrown when connection to the server fails.
47
47
  */
48
48
  export class ConnectionError extends MimicClientError {
49
- readonly _tag = "ConnectionError";
50
- readonly cause?: Error;
49
+ override readonly _tag = "ConnectionError";
50
+ override readonly cause?: Error;
51
51
 
52
52
  constructor(message: string, cause?: Error) {
53
53
  super(message);
@@ -60,7 +60,7 @@ export class ConnectionError extends MimicClientError {
60
60
  * Error thrown when state drift is detected and cannot be recovered.
61
61
  */
62
62
  export class StateDriftError extends MimicClientError {
63
- readonly _tag = "StateDriftError";
63
+ override readonly _tag = "StateDriftError";
64
64
  readonly expectedVersion: number;
65
65
  readonly receivedVersion: number;
66
66
 
@@ -78,7 +78,7 @@ export class StateDriftError extends MimicClientError {
78
78
  * Error thrown when a pending transaction times out waiting for confirmation.
79
79
  */
80
80
  export class TransactionTimeoutError extends MimicClientError {
81
- readonly _tag = "TransactionTimeoutError";
81
+ override readonly _tag = "TransactionTimeoutError";
82
82
  readonly transaction: Transaction.Transaction;
83
83
  readonly timeoutMs: number;
84
84
 
@@ -96,7 +96,7 @@ export class TransactionTimeoutError extends MimicClientError {
96
96
  * Error thrown when rebasing operations fails.
97
97
  */
98
98
  export class RebaseError extends MimicClientError {
99
- readonly _tag = "RebaseError";
99
+ override readonly _tag = "RebaseError";
100
100
  readonly transactionId: string;
101
101
 
102
102
  constructor(transactionId: string, message: string) {
@@ -110,7 +110,7 @@ export class RebaseError extends MimicClientError {
110
110
  * Error thrown when the client document is in an invalid state.
111
111
  */
112
112
  export class InvalidStateError extends MimicClientError {
113
- readonly _tag = "InvalidStateError";
113
+ override readonly _tag = "InvalidStateError";
114
114
  constructor(message: string) {
115
115
  super(message);
116
116
  this.name = "InvalidStateError";
@@ -121,7 +121,7 @@ export class InvalidStateError extends MimicClientError {
121
121
  * Error thrown when WebSocket connection or communication fails.
122
122
  */
123
123
  export class WebSocketError extends MimicClientError {
124
- readonly _tag = "WebSocketError";
124
+ override readonly _tag = "WebSocketError";
125
125
  readonly code?: number;
126
126
  readonly reason?: string;
127
127
 
@@ -137,7 +137,7 @@ export class WebSocketError extends MimicClientError {
137
137
  * Error thrown when authentication fails.
138
138
  */
139
139
  export class AuthenticationError extends MimicClientError {
140
- readonly _tag = "AuthenticationError";
140
+ override readonly _tag = "AuthenticationError";
141
141
  constructor(message: string) {
142
142
  super(message);
143
143
  this.name = "AuthenticationError";
@@ -87,7 +87,7 @@ export class BooleanPrimitive<TDefined extends boolean = false> implements Primi
87
87
  };
88
88
  },
89
89
 
90
- applyOperation: (state: boolean | undefined, operation: Operation.Operation<any, any, any>): boolean => {
90
+ applyOperation: (_state: boolean | undefined, operation: Operation.Operation<any, any, any>): boolean => {
91
91
  if (operation.kind !== "boolean.set") {
92
92
  throw new ValidationError(`BooleanPrimitive cannot apply operation of kind: ${operation.kind}`);
93
93
  }
@@ -88,7 +88,7 @@ export class LiteralPrimitive<T extends LiteralValue, TDefined extends boolean =
88
88
  };
89
89
  },
90
90
 
91
- applyOperation: (state: T | undefined, operation: Operation.Operation<any, any, any>): T => {
91
+ applyOperation: (_state: T | undefined, operation: Operation.Operation<any, any, any>): T => {
92
92
  if (operation.kind !== "literal.set") {
93
93
  throw new ValidationError(`LiteralPrimitive cannot apply operation of kind: ${operation.kind}`);
94
94
  }
@@ -128,7 +128,7 @@ export class NumberPrimitive<TDefined extends boolean = false> implements Primit
128
128
  };
129
129
  },
130
130
 
131
- applyOperation: (state: number | undefined, operation: Operation.Operation<any, any, any>): number => {
131
+ applyOperation: (_state: number | undefined, operation: Operation.Operation<any, any, any>): number => {
132
132
  if (operation.kind !== "number.set") {
133
133
  throw new ValidationError(`NumberPrimitive cannot apply operation of kind: ${operation.kind}`);
134
134
  }
@@ -147,7 +147,7 @@ export class StringPrimitive<TDefined extends boolean = false> implements Primit
147
147
  };
148
148
  },
149
149
 
150
- applyOperation: (state: string | undefined, operation: Operation.Operation<any, any, any>): string => {
150
+ applyOperation: (_state: string | undefined, operation: Operation.Operation<any, any, any>): string => {
151
151
  if (!isCompatibleOperation(operation, this._opDefinitions)) {
152
152
  throw new ValidationError(`StringPrimitive cannot apply operation of kind: ${operation.kind}`);
153
153
  }
@@ -149,7 +149,7 @@ export class StructPrimitive<TFields extends Record<string, AnyPrimitive>, TDefi
149
149
 
150
150
  // Use a JavaScript Proxy to intercept field access
151
151
  return new globalThis.Proxy(base as StructProxy<TFields, TDefined>, {
152
- get: (target, prop, receiver) => {
152
+ get: (target, prop, _receiver) => {
153
153
  // Return base methods (get, set, toSnapshot)
154
154
  if (prop === "get") {
155
155
  return target.get;
@@ -175,7 +175,7 @@ export class StructPrimitive<TFields extends Record<string, AnyPrimitive>, TDefi
175
175
 
176
176
  return undefined;
177
177
  },
178
- has: (target, prop) => {
178
+ has: (_target, prop) => {
179
179
  if (prop === "get" || prop === "set" || prop === "toSnapshot") return true;
180
180
  if (typeof prop === "string" && prop in fields) return true;
181
181
  return false;
@@ -37,7 +37,7 @@ export interface TypedTreeNodeState<TNode extends AnyTreeNodePrimitive> {
37
37
  /**
38
38
  * The state type for trees - a flat array of nodes
39
39
  */
40
- export type TreeState<TRoot extends AnyTreeNodePrimitive> = readonly TreeNodeState[];
40
+ export type TreeState<_TRoot extends AnyTreeNodePrimitive> = readonly TreeNodeState[];
41
41
 
42
42
  /**
43
43
  * Helper to get children sorted by position
@@ -122,7 +122,7 @@ export interface TypedNodeProxy<TNode extends AnyTreeNodePrimitive> {
122
122
  /**
123
123
  * Node proxy with type narrowing capabilities
124
124
  */
125
- export interface TreeNodeProxyBase<TRoot extends AnyTreeNodePrimitive> {
125
+ export interface TreeNodeProxyBase<_TRoot extends AnyTreeNodePrimitive> {
126
126
  /** The node ID */
127
127
  readonly id: string;
128
128
  /** The node type (string) */
@@ -1,10 +1,4 @@
1
- import { Effect, Schema } from "effect";
2
- import * as OperationDefinition from "../OperationDefinition";
3
- import * as Operation from "../Operation";
4
- import * as OperationPath from "../OperationPath";
5
- import * as ProxyEnvironment from "../ProxyEnvironment";
6
- import * as Transform from "../Transform";
7
- import type { AnyPrimitive, InferState } from "../Primitive";
1
+ import type { InferState } from "../Primitive";
8
2
  import { StructPrimitive } from "./Struct";
9
3
 
10
4
  /**
@@ -12,6 +6,15 @@ import { StructPrimitive } from "./Struct";
12
6
  */
13
7
  const TreeNodeSelfSymbol = Symbol.for("TreeNode.Self");
14
8
 
9
+ /**
10
+ * Branded type for TreeNodeSelf - distinguishable at compile time
11
+ */
12
+ declare const SelfBrand: unique symbol;
13
+ export interface TreeNodeSelfType {
14
+ readonly _tag: "TreeNodeSelf";
15
+ readonly _brand: typeof SelfBrand;
16
+ }
17
+
15
18
  /**
16
19
  * Special placeholder for self-referential tree nodes.
17
20
  * Use this in the children array when a node type can contain itself.
@@ -20,11 +23,11 @@ const TreeNodeSelfSymbol = Symbol.for("TreeNode.Self");
20
23
  * ```typescript
21
24
  * const FolderNode = TreeNode("folder", {
22
25
  * data: Struct({ name: String() }),
23
- * children: [Self], // Folder can contain other folders
26
+ * children: [TreeNodeSelf], // Folder can contain other folders
24
27
  * });
25
28
  * ```
26
29
  */
27
- export const TreeNodeSelf = { _tag: "TreeNodeSelf", _symbol: TreeNodeSelfSymbol } as unknown as AnyTreeNodePrimitive;
30
+ export const TreeNodeSelf: TreeNodeSelfType = { _tag: "TreeNodeSelf", _symbol: TreeNodeSelfSymbol } as unknown as TreeNodeSelfType;
28
31
 
29
32
  /**
30
33
  * Check if a value is the Self placeholder
@@ -33,41 +36,57 @@ const isSelf = (value: unknown): boolean => {
33
36
  return typeof value === "object" && value !== null && "_symbol" in value && (value as any)._symbol === TreeNodeSelfSymbol;
34
37
  };
35
38
 
39
+ /**
40
+ * Type utility to resolve Self placeholders to the actual node type
41
+ */
42
+ type ResolveSelf<T, TSelf extends AnyTreeNodePrimitive> =
43
+ T extends TreeNodeSelfType ? TSelf : T;
44
+
45
+ /**
46
+ * Type utility to resolve all children in a tuple, replacing Self with the node type
47
+ */
48
+ type ResolveChildrenUnion<TChildren, TSelf extends AnyTreeNodePrimitive> =
49
+ TChildren extends readonly (infer U)[]
50
+ ? ResolveSelf<U, TSelf>
51
+ : never;
52
+
36
53
  /**
37
54
  * The type for children - either a direct array or a lazy function (for self-referential nodes).
38
- * Using `Function` type allows self-references without explicit type annotations.
39
55
  */
40
- // eslint-disable-next-line @typescript-eslint/ban-types
41
- export type TreeNodeChildren = readonly AnyTreeNodePrimitive[] | Function;
56
+ export type TreeNodeChildrenInput = readonly (AnyTreeNodePrimitive | TreeNodeSelfType)[] | (() => readonly (AnyTreeNodePrimitive | TreeNodeSelfType)[]);
42
57
 
43
58
  /**
44
59
  * Any TreeNodePrimitive type - used for generic constraints.
45
60
  */
46
- export type AnyTreeNodePrimitive = TreeNodePrimitive<string, StructPrimitive<any>>;
61
+ export type AnyTreeNodePrimitive = TreeNodePrimitive<string, StructPrimitive<any>, any>;
47
62
 
48
63
  /**
49
64
  * Infer the data state type from a TreeNodePrimitive
50
65
  */
51
66
  export type InferTreeNodeDataState<T extends AnyTreeNodePrimitive> =
52
- T extends TreeNodePrimitive<any, infer TData> ? InferState<TData> : never;
67
+ T extends TreeNodePrimitive<any, infer TData, any> ? InferState<TData> : never;
53
68
 
54
69
  /**
55
70
  * Infer the type literal from a TreeNodePrimitive
56
71
  */
57
72
  export type InferTreeNodeType<T extends AnyTreeNodePrimitive> =
58
- T extends TreeNodePrimitive<infer TType, any> ? TType : never;
73
+ T extends TreeNodePrimitive<infer TType, any, any> ? TType : never;
59
74
 
60
75
  /**
61
- * Infer the allowed children from a TreeNodePrimitive (resolved at runtime)
76
+ * Infer the allowed children from a TreeNodePrimitive
62
77
  */
63
- export type InferTreeNodeChildren<_T extends AnyTreeNodePrimitive> = AnyTreeNodePrimitive;
78
+ export type InferTreeNodeChildren<T> =
79
+ T extends TreeNodePrimitive<any, any, infer TChildren> ? TChildren : never;
64
80
 
65
81
  /**
66
82
  * Configuration for a TreeNode primitive
67
83
  */
68
- export interface TreeNodeConfig<TData extends StructPrimitive<any>> {
84
+ export interface TreeNodeConfig<
85
+ TData extends StructPrimitive<any>,
86
+ TChildren extends readonly (AnyTreeNodePrimitive | TreeNodeSelfType)[]
87
+ > {
69
88
  readonly data: TData;
70
- readonly children: TreeNodeChildren;
89
+ readonly children: TChildren | (() => TChildren);
71
90
  }
72
91
 
73
92
  /**
@@ -75,18 +94,20 @@ export interface TreeNodeConfig<TData extends StructPrimitive<any>> {
75
94
  */
76
95
  export class TreeNodePrimitive<
77
96
  TType extends string,
78
- TData extends StructPrimitive<any>
97
+ TData extends StructPrimitive<any>,
98
+ TChildren extends AnyTreeNodePrimitive = AnyTreeNodePrimitive
79
99
  > {
80
100
  readonly _tag = "TreeNodePrimitive" as const;
81
101
  readonly _Type!: TType;
82
102
  readonly _Data!: TData;
103
+ readonly _Children!: TChildren;
83
104
 
84
105
  private readonly _type: TType;
85
106
  private readonly _data: TData;
86
- private readonly _children: TreeNodeChildren;
107
+ private readonly _children: TreeNodeChildrenInput;
87
108
  private _resolvedChildren: readonly AnyTreeNodePrimitive[] | undefined;
88
109
 
89
- constructor(type: TType, config: TreeNodeConfig<TData>) {
110
+ constructor(type: TType, config: TreeNodeConfig<TData, readonly (AnyTreeNodePrimitive | TreeNodeSelfType)[]>) {
90
111
  this._type = type;
91
112
  this._data = config.data;
92
113
  this._children = config.children;
@@ -109,7 +130,7 @@ export class TreeNodePrimitive<
109
130
  ? (this._children as () => readonly AnyTreeNodePrimitive[])()
110
131
  : this._children;
111
132
  // Replace Self placeholders with this node
112
- this._resolvedChildren = resolved.map(child => isSelf(child) ? this : child);
133
+ this._resolvedChildren = resolved.map(child => isSelf(child) ? this : child) as readonly AnyTreeNodePrimitive[];
113
134
  }
114
135
  return this._resolvedChildren;
115
136
  }
@@ -123,10 +144,11 @@ export class TreeNodePrimitive<
123
144
  /** Creates a new TreeNodePrimitive with the given type and config */
124
145
  export const TreeNode = <
125
146
  TType extends string,
126
- TData extends StructPrimitive<any>
147
+ TData extends StructPrimitive<any>,
148
+ const TChildren extends readonly (AnyTreeNodePrimitive | TreeNodeSelfType)[]
127
149
  >(
128
150
  type: TType,
129
- config: TreeNodeConfig<TData>
130
- ): TreeNodePrimitive<TType, TData> =>
131
- new TreeNodePrimitive(type, config);
151
+ config: TreeNodeConfig<TData, TChildren>
152
+ ): TreeNodePrimitive<TType, TData, ResolveChildrenUnion<TChildren, TreeNodePrimitive<TType, TData, any>>> =>
153
+ new TreeNodePrimitive(type, config) as TreeNodePrimitive<TType, TData, ResolveChildrenUnion<TChildren, TreeNodePrimitive<TType, TData, any>>>;
132
154
 
@@ -33,7 +33,7 @@ export type InferUnionSnapshot<TVariants extends UnionVariants> = {
33
33
  /**
34
34
  * Proxy for accessing union variants
35
35
  */
36
- export interface UnionProxy<TVariants extends UnionVariants, TDiscriminator extends string, TDefined extends boolean = false> {
36
+ export interface UnionProxy<TVariants extends UnionVariants, _TDiscriminator extends string, TDefined extends boolean = false> {
37
37
  /** Gets the current union value */
38
38
  get(): MaybeUndefined<InferUnionState<TVariants>, TDefined>;
39
39
 
@@ -19,7 +19,7 @@ export class MimicServerError extends Error {
19
19
  * Error thrown when a transaction fails validation.
20
20
  */
21
21
  export class ValidationError extends MimicServerError {
22
- readonly _tag = "ValidationError";
22
+ override readonly _tag = "ValidationError";
23
23
  readonly transactionId: string;
24
24
 
25
25
  constructor(transactionId: string, message: string) {
@@ -33,7 +33,7 @@ export class ValidationError extends MimicServerError {
33
33
  * Error thrown when an operation is invalid for the current schema.
34
34
  */
35
35
  export class InvalidOperationError extends MimicServerError {
36
- readonly _tag = "InvalidOperationError";
36
+ override readonly _tag = "InvalidOperationError";
37
37
  readonly operationKind: string;
38
38
  readonly path: string;
39
39
 
@@ -49,9 +49,9 @@ export class InvalidOperationError extends MimicServerError {
49
49
  * Error thrown when an operation cannot be applied to the current state.
50
50
  */
51
51
  export class StateValidationError extends MimicServerError {
52
- readonly _tag = "StateValidationError";
52
+ override readonly _tag = "StateValidationError";
53
53
  readonly transactionId: string;
54
- readonly cause?: Error;
54
+ override readonly cause?: Error;
55
55
 
56
56
  constructor(transactionId: string, message: string, cause?: Error) {
57
57
  super(`Transaction ${transactionId} cannot be applied to current state: ${message}`);
@@ -65,7 +65,7 @@ export class StateValidationError extends MimicServerError {
65
65
  * Error thrown when attempting to apply an empty transaction.
66
66
  */
67
67
  export class EmptyTransactionError extends MimicServerError {
68
- readonly _tag = "EmptyTransactionError";
68
+ override readonly _tag = "EmptyTransactionError";
69
69
  readonly transactionId: string;
70
70
 
71
71
  constructor(transactionId: string) {
@@ -79,7 +79,7 @@ export class EmptyTransactionError extends MimicServerError {
79
79
  * Error thrown when a duplicate transaction is submitted.
80
80
  */
81
81
  export class DuplicateTransactionError extends MimicServerError {
82
- readonly _tag = "DuplicateTransactionError";
82
+ override readonly _tag = "DuplicateTransactionError";
83
83
  readonly transactionId: string;
84
84
 
85
85
  constructor(transactionId: string) {