overmux 0.0.8 → 0.0.9

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.
Files changed (29) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/bin.js +58 -20
  3. package/dist/bin.js.map +1 -1
  4. package/dist/docs/100-introduction/300-why-i-built-overmux.md +1 -1
  5. package/dist/docs/200-getting-started/200-install-overmux-desktop.md +13 -0
  6. package/dist/docs/400-reference/500-server/100-resources.md +25 -0
  7. package/dist/docs/400-reference/500-server/500-api.md +4 -2
  8. package/dist/docs/400-reference/600-client/010-commands.md +0 -29
  9. package/dist/exports/client.d.ts +1 -1
  10. package/dist/exports/client.d.ts.map +1 -1
  11. package/dist/exports/client.js +89 -25
  12. package/dist/exports/client.js.map +1 -1
  13. package/dist/exports/{index-Cz3xkCa4.d.ts → index-Dk11nKIv.d.ts} +2 -2
  14. package/dist/exports/index-Dk11nKIv.d.ts.map +1 -0
  15. package/dist/exports/index.d.ts +1 -1
  16. package/dist/exports/index.js.map +1 -1
  17. package/dist/internal/server/coordinator/server-child.js +75 -22
  18. package/dist/internal/server/coordinator/server-child.js.map +1 -1
  19. package/docs/100-introduction/300-why-i-built-overmux.md +1 -1
  20. package/docs/200-getting-started/200-install-overmux-desktop.md +13 -0
  21. package/docs/400-reference/500-server/100-resources.md +25 -0
  22. package/docs/400-reference/500-server/500-api.md +4 -2
  23. package/docs/400-reference/600-client/010-commands.md +0 -29
  24. package/package.json +1 -1
  25. package/src/internal/client/overmux-react.ts +121 -27
  26. package/src/internal/server/runtime/runtime-resources.ts +99 -20
  27. package/src/internal/server/websocket-connection.ts +27 -2
  28. package/src/public/config.ts +1 -1
  29. package/dist/exports/index-Cz3xkCa4.d.ts.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # overmux
2
2
 
3
+ ## 0.0.9
4
+
5
+ ### Patch Changes
6
+
7
+ - [#22](https://github.com/richardgill/overmux/pull/22) [`26b2b78`](https://github.com/richardgill/overmux/commit/26b2b789932813bea670cfcc35d9c5fdbbfac193) Thanks [@richardgill](https://github.com/richardgill)! - Allow resource subscriptions to set up asynchronously, safely release cleanup returned after cancellation, and refresh subscribers after setup completes.
8
+
9
+ - [#17](https://github.com/richardgill/overmux/pull/17) [`405ec4c`](https://github.com/richardgill/overmux/commit/405ec4c250415a168766b7192dbb7c9c2e991ea9) Thanks [@richardgill](https://github.com/richardgill)! - Replace legacy Git source-control resources with independent read-only status and selected-file diff resources. Remove the Git React UI, including its views, navigation commands, stylesheet, and browser exports. Pi now owns the patch renderer it uses directly.
10
+
11
+ Preserve resource invalidations received during an active client read so subscribed views refresh after that read settles.
12
+
3
13
  ## 0.0.8
4
14
 
5
15
  ### Patch Changes
package/dist/bin.js CHANGED
@@ -2732,6 +2732,33 @@ var getInvalidatedResourceIds = (graph, resourceId) => {
2732
2732
  };
2733
2733
  //#endregion
2734
2734
  //#region src/internal/server/runtime/runtime-resources.ts
2735
+ var createSubscriptionLifetime = ({ entry, invalidationListeners, lifecycle, signal }) => {
2736
+ const controller = new AbortController();
2737
+ const subscriptionSignal = AbortSignal.any([lifecycle.requestSignal(signal), controller.signal]);
2738
+ subscriptionSignal.throwIfAborted();
2739
+ const registeredEntry = {
2740
+ ...entry,
2741
+ listener: () => {
2742
+ if (!subscriptionSignal.aborted) entry.listener();
2743
+ }
2744
+ };
2745
+ const disposers = [];
2746
+ const release = lifecycle.track(async () => {
2747
+ invalidationListeners.delete(registeredEntry);
2748
+ await lifecycle.disposeAll(disposers);
2749
+ }, subscriptionSignal);
2750
+ const dispose = () => {
2751
+ controller.abort(/* @__PURE__ */ new Error("Resource subscription closed"));
2752
+ return release();
2753
+ };
2754
+ invalidationListeners.add(registeredEntry);
2755
+ return {
2756
+ dispose,
2757
+ disposers,
2758
+ refresh: registeredEntry.listener,
2759
+ signal: subscriptionSignal
2760
+ };
2761
+ };
2735
2762
  var createRuntimeResources = ({ definitions, instance, lifecycle }) => {
2736
2763
  const graph = createResourceDependencyGraph(definitions);
2737
2764
  const invalidationListeners = /* @__PURE__ */ new Set();
@@ -2763,44 +2790,55 @@ var createRuntimeResources = ({ definitions, instance, lifecycle }) => {
2763
2790
  operationSignal.throwIfAborted();
2764
2791
  return definition.contract.output.parse(rawOutput);
2765
2792
  };
2766
- const activateWatchers = (id, rawInput, signal, activated, disposers) => {
2793
+ const activateSubscriptions = async (id, rawInput, signal, activated, disposers) => {
2794
+ signal.throwIfAborted();
2767
2795
  if (activated.has(id)) return;
2768
2796
  activated.add(id);
2769
2797
  const definition = definitions[id];
2770
2798
  const input = definition.contract.input.parse(rawInput);
2771
2799
  if (definition.kind === "subscription") {
2772
- const dispose = definition.subscribe(input, () => invalidateResource(id, input), context(signal));
2800
+ const dispose = await definition.subscribe(input, () => {
2801
+ if (!signal.aborted) invalidateResource(id, input);
2802
+ }, context(signal));
2773
2803
  if (typeof dispose !== "function") throw new Error(`Resource ${id} subscribe must return a disposer`);
2804
+ if (signal.aborted) {
2805
+ await dispose();
2806
+ signal.throwIfAborted();
2807
+ }
2774
2808
  disposers.push(dispose);
2775
2809
  return;
2776
2810
  }
2777
- if (definition.kind === "derived") graph.dependencies.get(id)?.forEach((dependencyId) => {
2778
- activateWatchers(dependencyId, rawInput, signal, activated, disposers);
2779
- });
2811
+ if (definition.kind === "derived") for (const dependencyId of graph.dependencies.get(id) ?? []) await activateSubscriptions(dependencyId, rawInput, signal, activated, disposers);
2780
2812
  };
2781
2813
  Object.keys(definitions).forEach((name) => {
2782
2814
  resources.set(name, {
2783
2815
  read: (input, signal) => read(name, input, signal),
2784
- subscribe: (rawInput, listener, signal) => {
2816
+ subscribe: async (rawInput, listener, signal) => {
2785
2817
  lifecycle.requestSignal(signal).throwIfAborted();
2786
- const entry = {
2787
- input: definitions[name].contract.input.parse(rawInput),
2788
- listener,
2789
- resourceId: name
2790
- };
2791
- const watcherDisposers = [];
2792
- invalidationListeners.add(entry);
2818
+ const subscription = createSubscriptionLifetime({
2819
+ entry: {
2820
+ input: definitions[name].contract.input.parse(rawInput),
2821
+ listener,
2822
+ resourceId: name
2823
+ },
2824
+ invalidationListeners,
2825
+ lifecycle,
2826
+ signal
2827
+ });
2793
2828
  try {
2794
- activateWatchers(name, rawInput, signal, /* @__PURE__ */ new Set(), watcherDisposers);
2829
+ await activateSubscriptions(name, rawInput, subscription.signal, /* @__PURE__ */ new Set(), subscription.disposers);
2830
+ subscription.signal.throwIfAborted();
2831
+ subscription.refresh();
2832
+ subscription.signal.throwIfAborted();
2833
+ return subscription.dispose;
2795
2834
  } catch (cause) {
2796
- invalidationListeners.delete(entry);
2797
- lifecycle.disposeAll(watcherDisposers).catch(() => void 0);
2835
+ try {
2836
+ await subscription.dispose();
2837
+ } catch (cleanupError) {
2838
+ throw new AggregateError([cause, cleanupError], "Resource subscription setup and cleanup failed");
2839
+ }
2798
2840
  throw cause;
2799
2841
  }
2800
- return lifecycle.track(async () => {
2801
- invalidationListeners.delete(entry);
2802
- await lifecycle.disposeAll(watcherDisposers);
2803
- }, signal);
2804
2842
  }
2805
2843
  });
2806
2844
  });