@fairfox/polly 0.71.0 → 0.73.0

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 (45) hide show
  1. package/dist/src/client/index.js +2 -2
  2. package/dist/src/client/index.js.map +2 -2
  3. package/dist/src/elysia/index.js +464 -4
  4. package/dist/src/elysia/index.js.map +6 -4
  5. package/dist/src/peer.d.ts +2 -0
  6. package/dist/src/peer.js +468 -4
  7. package/dist/src/peer.js.map +8 -5
  8. package/dist/src/polly-ui/ActionInput.d.ts +12 -2
  9. package/dist/src/polly-ui/ActionSelect.d.ts +36 -0
  10. package/dist/src/polly-ui/Button.d.ts +4 -0
  11. package/dist/src/polly-ui/Cluster.d.ts +36 -0
  12. package/dist/src/polly-ui/Code.d.ts +18 -0
  13. package/dist/src/polly-ui/Surface.d.ts +12 -1
  14. package/dist/src/polly-ui/Text.d.ts +43 -0
  15. package/dist/src/polly-ui/index.css +320 -194
  16. package/dist/src/polly-ui/index.d.ts +5 -1
  17. package/dist/src/polly-ui/index.js +533 -284
  18. package/dist/src/polly-ui/index.js.map +14 -8
  19. package/dist/src/polly-ui/internal/dispatch-action.d.ts +13 -0
  20. package/dist/src/polly-ui/internal/passthrough.d.ts +25 -0
  21. package/dist/src/polly-ui/markdown.js +3 -3
  22. package/dist/src/polly-ui/markdown.js.map +2 -2
  23. package/dist/src/polly-ui/styles.css +345 -194
  24. package/dist/src/polly-ui/theme.css +1 -0
  25. package/dist/src/shared/lib/peer-repo-server.d.ts +18 -0
  26. package/dist/src/shared/lib/sweep-sealed.d.ts +111 -0
  27. package/dist/tools/quality/src/cli.js +6 -2
  28. package/dist/tools/quality/src/cli.js.map +3 -3
  29. package/dist/tools/quality/src/index.js +6 -2
  30. package/dist/tools/quality/src/index.js.map +3 -3
  31. package/dist/tools/test/src/browser/run.js +89 -49
  32. package/dist/tools/test/src/browser/run.js.map +6 -5
  33. package/dist/tools/test/src/browser/runner-core.d.ts +32 -0
  34. package/dist/tools/test/src/e2e-mesh/index.js +193 -171
  35. package/dist/tools/test/src/e2e-mesh/index.js.map +4 -4
  36. package/dist/tools/test/src/visual/index.js +270 -251
  37. package/dist/tools/test/src/visual/index.js.map +5 -5
  38. package/dist/tools/verify/specs/tla/MeshSeed.cfg +27 -0
  39. package/dist/tools/verify/specs/tla/MeshSeed.tla +179 -0
  40. package/dist/tools/verify/specs/tla/README.md +11 -1
  41. package/dist/tools/verify/src/cli.js +136 -51
  42. package/dist/tools/verify/src/cli.js.map +9 -7
  43. package/dist/tools/visualize/src/cli.js +72 -2
  44. package/dist/tools/visualize/src/cli.js.map +5 -5
  45. package/package.json +3 -2
@@ -0,0 +1,111 @@
1
+ /**
2
+ * `sweepSealed` — storage-adapter garbage collection of sealed mesh-doc
3
+ * bytes (polly#121).
4
+ *
5
+ * When a consumer compacts a `$meshState` document it seeds a fresh
6
+ * successor and leaves an in-band sentinel in the old document. polly's
7
+ * {@link RedirectDetector} follows that sentinel so live wrappers rebind
8
+ * transparently — but the old document's bytes then sit in storage
9
+ * forever, because nothing removes them.
10
+ *
11
+ * `sweepSealed` is that missing GC step. polly owns the walk, the
12
+ * open-handle gate, the age window, the dry-run report and the byte
13
+ * removal. The consumer owns the sentinel shape — it is the very
14
+ * document the consumer's {@link RedirectDetector} already inspects —
15
+ * supplied here as the {@link SweepSealedOptions.isSealed} predicate.
16
+ * polly deliberately does not define a canonical sentinel format: that
17
+ * would compete with the one consumers' detectors already read.
18
+ *
19
+ * polly never runs this on a timer. The consumer calls it explicitly.
20
+ *
21
+ * ## Redirect-index-not-yet-synced hazard
22
+ *
23
+ * A peer whose redirect index (`mesh:document-index`) has not yet synced
24
+ * may still reach for a sealed document by its *old* docId. If the sweep
25
+ * has just removed that document's bytes, the peer gets a
26
+ * missing-document error instead of a redirect. Two gates bound the risk,
27
+ * and the caller must size them deliberately:
28
+ *
29
+ * - `olderThan` — only documents sealed longer ago than this window are
30
+ * swept. Make it comfortably larger than the worst-case time a peer
31
+ * can stay offline-then-resync, so any peer that could still hold the
32
+ * old docId has had the redirect delivered.
33
+ * - the open-handle gate — a document with a live handle on the supplied
34
+ * `repo` is never swept, regardless of age.
35
+ *
36
+ * Neither gate can see a peer that is currently offline; `olderThan` is
37
+ * the only protection there. Choose it conservatively.
38
+ */
39
+ import type { DocumentId, Repo, StorageAdapterInterface } from "@automerge/automerge-repo/slim";
40
+ export interface SweepSealedOptions {
41
+ /** The Repo whose storage is swept. Its open handles gate removal. */
42
+ repo: Repo;
43
+ /** The storage adapter backing {@link repo}. */
44
+ storage: StorageAdapterInterface;
45
+ /**
46
+ * Predicate that recognises a sealed document. Given a materialised
47
+ * document, returns the epoch-ms timestamp at which it was sealed, or
48
+ * `undefined` if the document is not sealed.
49
+ *
50
+ * This is the same document the consumer's {@link RedirectDetector}
51
+ * inspects: the consumer owns the sentinel shape, polly never defines
52
+ * it. The returned timestamp feeds both the {@link olderThan} filter
53
+ * and the dry-run report.
54
+ */
55
+ isSealed: (doc: unknown) => number | undefined;
56
+ /** Sweep only documents sealed more than this many milliseconds ago. */
57
+ olderThan: number;
58
+ /**
59
+ * The candidate documents to consider. When omitted, the sweep
60
+ * enumerates the whole adapter via `storage.loadRange([])`.
61
+ *
62
+ * That whole-adapter enumeration works for the IndexedDB and
63
+ * in-memory adapters but **not** the NodeFS adapter, whose `loadRange`
64
+ * requires at least a documentId prefix. Server-side callers should
65
+ * use {@link PeerRepoServer.sweepSealed}, which enumerates the
66
+ * filesystem and supplies this list; per-document `loadRange` then
67
+ * works on every adapter.
68
+ */
69
+ documentIds?: Iterable<string>;
70
+ /** When true, report candidates without removing anything. */
71
+ dryRun?: boolean;
72
+ /** Clock source, injectable for tests. Defaults to {@link Date.now}. */
73
+ now?: () => number;
74
+ }
75
+ /** A document removed by the sweep — or, under `dryRun`, that would be. */
76
+ export interface SweptDoc {
77
+ documentId: DocumentId;
78
+ /** Epoch-ms the document was sealed, as reported by `isSealed`. */
79
+ sealedAt: number;
80
+ /** Total bytes across the document's storage chunks. */
81
+ byteSize: number;
82
+ }
83
+ /** Why a sealed document was left in place rather than swept. */
84
+ export type KeptReason = "open-handle" | "too-recent";
85
+ /** A sealed document the sweep deliberately did not remove. */
86
+ export interface KeptDoc {
87
+ documentId: DocumentId;
88
+ reason: KeptReason;
89
+ }
90
+ export interface SweepResult {
91
+ /** Documents removed — or, under `dryRun`, that would be removed. */
92
+ swept: SweptDoc[];
93
+ /** Sealed documents deliberately left in place, with the reason. */
94
+ kept: KeptDoc[];
95
+ /** Echoes the `dryRun` flag the sweep ran under. */
96
+ dryRun: boolean;
97
+ }
98
+ /**
99
+ * Garbage-collect sealed mesh-doc bytes from a Repo's storage adapter.
100
+ *
101
+ * Walks every candidate document, materialises it, and asks
102
+ * {@link SweepSealedOptions.isSealed} whether it is sealed. A sealed
103
+ * document is removed only when it has no open handle on the Repo *and*
104
+ * was sealed longer ago than `olderThan`; otherwise it is reported under
105
+ * `kept` with the reason. Unsealed documents are never touched and never
106
+ * reported. With `dryRun`, candidates are reported but nothing is removed.
107
+ *
108
+ * See the module doc comment for the redirect-index-not-yet-synced
109
+ * hazard that `olderThan` and the open-handle gate exist to bound.
110
+ */
111
+ export declare function sweepSealed(options: SweepSealedOptions): Promise<SweepResult>;
@@ -33,7 +33,11 @@ var DEFAULT_SHARED_COMPONENT_RULES = [
33
33
  element: "<textarea>",
34
34
  replacement: '<ActionInput variant="multi">'
35
35
  },
36
- { pattern: /<select[\s>]/, element: "<select>", replacement: "<Select>" },
36
+ {
37
+ pattern: /<select[\s>]/,
38
+ element: "<select>",
39
+ replacement: "<Select> or <ActionSelect>"
40
+ },
37
41
  { pattern: /<form[\s>]/, element: "<form>", replacement: "<ActionForm>" },
38
42
  { pattern: /<dialog[\s>]/, element: "<dialog>", replacement: "<Modal>" }
39
43
  ];
@@ -3046,4 +3050,4 @@ switch (subcommand) {
3046
3050
  }
3047
3051
  process.exit(exitCode);
3048
3052
 
3049
- //# debugId=C337428BF011F4B264756E2164756E21
3053
+ //# debugId=BE14883E9B3EB87B64756E2164756E21