tandem-editor 0.2.9 → 0.2.10

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.
@@ -9,7 +9,7 @@
9
9
  html, body, #root { height: 100%; }
10
10
  body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; }
11
11
  </style>
12
- <script type="module" crossorigin src="/assets/index-ChvL-huP.js"></script>
12
+ <script type="module" crossorigin src="/assets/index-CfGlbY9B.js"></script>
13
13
  </head>
14
14
  <body>
15
15
  <div id="root"></div>
@@ -228,6 +228,25 @@ var init_platform = __esm({
228
228
  import fs from "fs/promises";
229
229
  import path2 from "path";
230
230
  import * as Y2 from "yjs";
231
+ async function atomicWrite(sessionPath, content) {
232
+ const tmpPath = `${sessionPath}.tmp`;
233
+ await fs.writeFile(tmpPath, content, "utf-8");
234
+ for (let attempt = 0; attempt < RENAME_MAX_RETRIES; attempt++) {
235
+ try {
236
+ await fs.rename(tmpPath, sessionPath);
237
+ return;
238
+ } catch (err) {
239
+ const code = err.code;
240
+ if ((code === "EPERM" || code === "EACCES") && attempt < RENAME_MAX_RETRIES - 1) {
241
+ await new Promise((r) => setTimeout(r, RENAME_RETRY_BASE_MS * 2 ** attempt));
242
+ continue;
243
+ }
244
+ await fs.unlink(tmpPath).catch(() => {
245
+ });
246
+ throw err;
247
+ }
248
+ }
249
+ }
231
250
  function sessionKey(filePath) {
232
251
  return encodeURIComponent(filePath.replace(/\\/g, "/"));
233
252
  }
@@ -255,15 +274,7 @@ async function saveSession(filePath, format, doc) {
255
274
  sessionDirReady = true;
256
275
  }
257
276
  const sessionPath = path2.join(SESSION_DIR, `${key}.json`);
258
- const tmpPath = `${sessionPath}.tmp`;
259
- await fs.writeFile(tmpPath, JSON.stringify(data), "utf-8");
260
- try {
261
- await fs.rename(tmpPath, sessionPath);
262
- } catch (err) {
263
- await fs.unlink(tmpPath).catch(() => {
264
- });
265
- throw err;
266
- }
277
+ await atomicWrite(sessionPath, JSON.stringify(data));
267
278
  }
268
279
  async function loadSession(filePath) {
269
280
  const key = sessionKey(filePath);
@@ -334,15 +345,7 @@ async function saveCtrlSession(doc) {
334
345
  const ydocState = Buffer.from(state).toString("base64");
335
346
  const data = { ydocState, lastAccessed: Date.now() };
336
347
  const sessionPath = path2.join(SESSION_DIR, `${CTRL_SESSION_KEY}.json`);
337
- const tmpPath = `${sessionPath}.tmp`;
338
- await fs.writeFile(tmpPath, JSON.stringify(data), "utf-8");
339
- try {
340
- await fs.rename(tmpPath, sessionPath);
341
- } catch (err) {
342
- await fs.unlink(tmpPath).catch(() => {
343
- });
344
- throw err;
345
- }
348
+ await atomicWrite(sessionPath, JSON.stringify(data));
346
349
  }
347
350
  async function loadCtrlSession() {
348
351
  const sessionPath = path2.join(SESSION_DIR, `${CTRL_SESSION_KEY}.json`);
@@ -441,7 +444,7 @@ function stopAutoSave() {
441
444
  }
442
445
  autoSaveCallback = null;
443
446
  }
444
- var AUTO_SAVE_INTERVAL, sessionDirReady, CTRL_SESSION_KEY, autoSaveTimer, autoSaveCallback;
447
+ var AUTO_SAVE_INTERVAL, RENAME_MAX_RETRIES, RENAME_RETRY_BASE_MS, sessionDirReady, CTRL_SESSION_KEY, autoSaveTimer, autoSaveCallback;
445
448
  var init_manager = __esm({
446
449
  "src/server/session/manager.ts"() {
447
450
  "use strict";
@@ -449,6 +452,8 @@ var init_manager = __esm({
449
452
  init_constants();
450
453
  init_queue();
451
454
  AUTO_SAVE_INTERVAL = 60 * 1e3;
455
+ RENAME_MAX_RETRIES = 3;
456
+ RENAME_RETRY_BASE_MS = 50;
452
457
  sessionDirReady = false;
453
458
  CTRL_SESSION_KEY = CTRL_ROOM;
454
459
  autoSaveTimer = null;
@@ -2681,7 +2686,7 @@ import path4 from "path";
2681
2686
  function getAdapter(format) {
2682
2687
  return adapters[format] ?? plaintextAdapter;
2683
2688
  }
2684
- async function atomicWrite(filePath, content) {
2689
+ async function atomicWrite2(filePath, content) {
2685
2690
  const tempPath = path4.join(path4.dirname(filePath), `.tandem-tmp-${Date.now()}`);
2686
2691
  await fs2.writeFile(tempPath, content, "utf-8");
2687
2692
  await fs2.rename(tempPath, filePath);
@@ -3772,7 +3777,7 @@ async function convertToMarkdown(documentId, outputPath) {
3772
3777
  resolvedOutput = path7.join(sourceDir, `${baseName}.md`);
3773
3778
  }
3774
3779
  resolvedOutput = await findAvailablePath(resolvedOutput);
3775
- await atomicWrite(resolvedOutput, markdown);
3780
+ await atomicWrite2(resolvedOutput, markdown);
3776
3781
  try {
3777
3782
  const openResult = await openFileByPath(resolvedOutput);
3778
3783
  return {
@@ -4065,7 +4070,7 @@ function registerDocumentTools(server) {
4065
4070
  });
4066
4071
  }
4067
4072
  const output = adapter.save(r.doc);
4068
- await atomicWrite(r.filePath, output);
4073
+ await atomicWrite2(r.filePath, output);
4069
4074
  await saveSession(r.filePath, format, r.doc);
4070
4075
  const meta = r.doc.getMap(Y_MAP_DOCUMENT_META);
4071
4076
  r.doc.transact(() => meta.set(Y_MAP_SAVED_AT_VERSION, Date.now()), MCP_ORIGIN);