or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

document-management.mdevent-system.mdindex.mdposition-tracking.mdshared-data-types.mdsnapshot-system.mdsynchronization.mdtransaction-system.mdundo-redo-system.mdxml-types.md

transaction-system.mddocs/

0

# Transaction System

1

2

Atomic change batching for consistent updates and coordinated event handling. The transaction system ensures that multiple operations are executed atomically and that all observers are notified consistently.

3

4

## Capabilities

5

6

### Transaction Class

7

8

Represents a single atomic change context that groups multiple operations together.

9

10

```typescript { .api }

11

/**

12

* Transaction context for atomic operations

13

*/

14

class Transaction {

15

/** Document this transaction operates on */

16

readonly doc: Doc;

17

18

/** Origin identifier for this transaction */

19

readonly origin: any;

20

21

/** Whether this transaction originated locally */

22

readonly local: boolean;

23

24

/** Set of items deleted in this transaction */

25

readonly deleteSet: DeleteSet;

26

27

/** Document state before transaction began */

28

readonly beforeState: Map<number, number>;

29

30

/** Document state after transaction completes */

31

readonly afterState: Map<number, number>;

32

33

/** Map of changed types to their changed keys/indices */

34

readonly changed: Map<AbstractType<YEvent<any>>, Set<string | null>>;

35

36

/** Map of parent types that will emit events */

37

readonly changedParentTypes: Map<AbstractType<YEvent<any>>, Array<YEvent<any>>>;

38

39

/** Transaction metadata */

40

readonly meta: Map<any, any>;

41

42

/** Subdocuments added during transaction */

43

readonly subdocsAdded: Set<Doc>;

44

45

/** Subdocuments removed during transaction */

46

readonly subdocsRemoved: Set<Doc>;

47

48

/** Subdocuments loaded during transaction */

49

readonly subdocsLoaded: Set<Doc>;

50

}

51

```

52

53

### Transaction Function

54

55

Execute operations within a transaction context.

56

57

```typescript { .api }

58

/**

59

* Execute a function within a transaction context

60

* @param doc - Document to operate on

61

* @param f - Function to execute within the transaction

62

* @param origin - Optional origin identifier for the transaction

63

* @returns Result of the function execution

64

*/

65

function transact<T>(doc: Doc, f: (transaction: Transaction) => T, origin?: any): T;

66

```

67

68

**Usage Examples:**

69

70

```typescript

71

import * as Y from "yjs";

72

73

const doc = new Y.Doc();

74

const yarray = doc.getArray("items");

75

const ymap = doc.getMap("metadata");

76

77

// Basic transaction

78

Y.transact(doc, (transaction) => {

79

yarray.push(["item1", "item2"]);

80

ymap.set("count", yarray.length);

81

82

// Access transaction properties

83

console.log("Transaction origin:", transaction.origin);

84

console.log("Changed types:", transaction.changed.size);

85

});

86

87

// Transaction with origin

88

Y.transact(doc, () => {

89

yarray.delete(0, 1);

90

}, "user-delete");

91

92

// Transaction returning a value

93

const result = Y.transact(doc, () => {

94

yarray.push(["new-item"]);

95

return yarray.length;

96

}, "add-item");

97

```

98

99

### Document Transaction Method

100

101

The Doc class also provides a transaction method for convenience.

102

103

```typescript { .api }

104

/**

105

* Execute a function within a transaction on this document

106

* @param f - Function to execute within the transaction

107

* @param origin - Optional origin identifier for the transaction

108

* @returns Result of the function execution

109

*/

110

transact<T>(f: (transaction: Transaction) => T, origin?: any): T;

111

```

112

113

**Usage Examples:**

114

115

```typescript

116

import * as Y from "yjs";

117

118

const doc = new Y.Doc();

119

const yarray = doc.getArray("items");

120

121

// Using doc.transact method

122

doc.transact(() => {

123

yarray.push(["item1", "item2", "item3"]);

124

}, "batch-insert");

125

126

// Accessing transaction in observers

127

yarray.observe((event, transaction) => {

128

console.log("Array changed in transaction:", transaction.origin);

129

console.log("Local change:", transaction.local);

130

});

131

```

132

133

### Transaction Lifecycle Events

134

135

Documents emit events during transaction lifecycle for advanced use cases.

136

137

```typescript { .api }

138

/**

139

* Transaction lifecycle events

140

*/

141

interface TransactionEvents {

142

/** Fired before transaction begins */

143

beforeTransaction: (transaction: Transaction, doc: Doc) => void;

144

145

/** Fired after transaction completes but before observers */

146

afterTransaction: (transaction: Transaction, doc: Doc) => void;

147

148

/** Fired before observer functions are called */

149

beforeObserverCalls: (transaction: Transaction, doc: Doc) => void;

150

151

/** Fired after all observer functions complete */

152

afterObserverCalls: (transaction: Transaction, doc: Doc) => void;

153

}

154

```

155

156

**Usage Examples:**

157

158

```typescript

159

import * as Y from "yjs";

160

161

const doc = new Y.Doc();

162

163

// Listen to transaction lifecycle

164

doc.on("beforeTransaction", (transaction) => {

165

console.log("Transaction starting:", transaction.origin);

166

transaction.meta.set("startTime", Date.now());

167

});

168

169

doc.on("afterTransaction", (transaction) => {

170

const duration = Date.now() - transaction.meta.get("startTime");

171

console.log(`Transaction completed in ${duration}ms`);

172

});

173

174

doc.on("beforeObserverCalls", (transaction) => {

175

console.log("About to call observers for:", Array.from(transaction.changed.keys()));

176

});

177

178

doc.on("afterObserverCalls", (transaction) => {

179

console.log("All observers completed");

180

});

181

```

182

183

### Advanced Transaction Patterns

184

185

**Conditional Operations:**

186

187

```typescript

188

import * as Y from "yjs";

189

190

const doc = new Y.Doc();

191

const yarray = doc.getArray("items");

192

193

// Conditional operations within transaction

194

doc.transact((transaction) => {

195

if (yarray.length === 0) {

196

yarray.push(["initial-item"]);

197

}

198

199

// Check if this is a local change

200

if (transaction.local) {

201

yarray.push(["local-change-marker"]);

202

}

203

}, "conditional-update");

204

```

205

206

**Cross-Type Operations:**

207

208

```typescript

209

import * as Y from "yjs";

210

211

const doc = new Y.Doc();

212

const tasks = doc.getArray("tasks");

213

const metadata = doc.getMap("metadata");

214

215

// Coordinate changes across multiple types

216

doc.transact(() => {

217

tasks.push([{ id: 1, title: "New Task", completed: false }]);

218

metadata.set("lastTaskId", 1);

219

metadata.set("taskCount", tasks.length);

220

metadata.set("lastModified", new Date().toISOString());

221

}, "add-task");

222

```

223

224

**Transaction Metadata:**

225

226

```typescript

227

import * as Y from "yjs";

228

229

const doc = new Y.Doc();

230

const ytext = doc.getText("document");

231

232

// Using transaction metadata

233

doc.on("beforeTransaction", (transaction) => {

234

transaction.meta.set("user", "alice");

235

transaction.meta.set("timestamp", Date.now());

236

});

237

238

ytext.observe((event, transaction) => {

239

const user = transaction.meta.get("user");

240

const timestamp = transaction.meta.get("timestamp");

241

console.log(`Text changed by ${user} at ${timestamp}`);

242

});

243

244

doc.transact(() => {

245

ytext.insert(0, "Hello World!");

246

}, "text-insert");

247

```

248

249

**Nested Transactions:**

250

251

```typescript

252

import * as Y from "yjs";

253

254

const doc = new Y.Doc();

255

const yarray = doc.getArray("items");

256

257

// Note: Nested transact calls are flattened into single transaction

258

doc.transact(() => {

259

yarray.push(["item1"]);

260

261

// This doesn't create a nested transaction - operations are merged

262

doc.transact(() => {

263

yarray.push(["item2"]);

264

});

265

266

yarray.push(["item3"]);

267

}, "batch-operation");

268

269

// All three push operations happen in single transaction

270

```

271

272

### Transaction Performance Considerations

273

274

**Batching Operations:**

275

276

```typescript

277

import * as Y from "yjs";

278

279

const doc = new Y.Doc();

280

const yarray = doc.getArray("items");

281

282

// Inefficient: Multiple separate transactions

283

for (let i = 0; i < 1000; i++) {

284

yarray.push([`item-${i}`]);

285

}

286

287

// Efficient: Single transaction for bulk operations

288

doc.transact(() => {

289

for (let i = 0; i < 1000; i++) {

290

yarray.push([`item-${i}`]);

291

}

292

}, "bulk-insert");

293

```

294

295

**Observer Optimization:**

296

297

```typescript

298

import * as Y from "yjs";

299

300

const doc = new Y.Doc();

301

const yarray = doc.getArray("items");

302

303

yarray.observe((event) => {

304

// This fires once per transaction, not once per operation

305

console.log("Array changed, operations:", event.changes.delta.length);

306

});

307

308

doc.transact(() => {

309

yarray.push(["item1"]);

310

yarray.push(["item2"]);

311

yarray.push(["item3"]);

312

// Observer fires once with all changes

313

});

314

```