@almadar/workspace 0.11.11 → 0.11.13

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.
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Regression test for the create:false / create mint race (2026-09-04 Kura
3
+ * first-open defect).
4
+ *
5
+ * `openWorkspace({ create: false, ... })` is a "pure read" only when the
6
+ * local cache already has the workspace. When it misses locally but a
7
+ * `restore` backend yields files, `resolveLifecycle`'s restore branch mints
8
+ * a fresh session dir via `mintSessionDir` — the same directory-creating
9
+ * path a concurrent `create` (default) call takes. Before the fix,
10
+ * `create:false` bypassed the in-flight dedupe map entirely, so a
11
+ * `GET .../git/history` (`create:false`) racing a `GET .../files`
12
+ * (`create`) on first open both missed `findLocalWorkspaceDir`, both
13
+ * restored, and two workspace directories were minted for one
14
+ * (userId, appId).
15
+ *
16
+ * After the fix, both paths share one in-flight map keyed by
17
+ * (backend, userId, appId): whichever call resolves first wins, and the
18
+ * other awaits it instead of minting its own directory.
19
+ */
20
+ export {};
package/dist/index.js CHANGED
@@ -2511,28 +2511,32 @@ function openWorkspaceCacheKey(opts) {
2511
2511
  const backendTag = opts.backend === "memory" ? "memory" : "local";
2512
2512
  return `${backendTag}:${opts.userId}:${opts.appId}`;
2513
2513
  }
2514
+ function registerInFlightOpen(key, opts) {
2515
+ const pending = (async () => {
2516
+ try {
2517
+ const ws = await openWorkspaceInternal(opts);
2518
+ if (ws === null) openWorkspaceInFlight.delete(key);
2519
+ return ws;
2520
+ } catch (err) {
2521
+ openWorkspaceInFlight.delete(key);
2522
+ throw err;
2523
+ }
2524
+ })();
2525
+ openWorkspaceInFlight.set(key, pending);
2526
+ return pending;
2527
+ }
2514
2528
  async function openWorkspace(opts) {
2515
- if (opts.create === false) {
2529
+ const key = openWorkspaceCacheKey(opts);
2530
+ if (key === null) {
2516
2531
  return openWorkspaceInternal(opts);
2517
2532
  }
2518
- const key = openWorkspaceCacheKey(opts);
2519
- if (key !== null) {
2533
+ for (; ; ) {
2520
2534
  const cached = openWorkspaceInFlight.get(key);
2521
- if (cached) return cached;
2522
- const pending = (async () => {
2523
- try {
2524
- const ws = await openWorkspaceInternal(opts);
2525
- if (ws === null) throw new Error("openWorkspace: null resolution without create:false");
2526
- return ws;
2527
- } catch (err) {
2528
- openWorkspaceInFlight.delete(key);
2529
- throw err;
2530
- }
2531
- })();
2532
- openWorkspaceInFlight.set(key, pending);
2533
- return pending;
2535
+ if (!cached) return registerInFlightOpen(key, opts);
2536
+ const result = await cached;
2537
+ if (result !== null) return result;
2538
+ if (opts.create === false) return null;
2534
2539
  }
2535
- return openWorkspaceInternal(opts);
2536
2540
  }
2537
2541
  var WORKSPACE_OWNED_ENTRIES = /* @__PURE__ */ new Set([".almadar", "orbitals", "schema.orb", ".git", ".gitignore"]);
2538
2542
  async function guardForeignMintTarget(backend, workDir) {