@graview/core 0.1.20 → 0.1.22

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 (196) hide show
  1. package/README.md +28 -0
  2. package/dist/blocks.d.ts +3 -0
  3. package/dist/blocks.d.ts.map +1 -1
  4. package/dist/blocks.js +2 -0
  5. package/dist/blocks.js.map +1 -1
  6. package/dist/capabilities.js +1 -1
  7. package/dist/capabilities.js.map +1 -1
  8. package/dist/cli/check/computed.d.ts +4 -2
  9. package/dist/cli/check/computed.d.ts.map +1 -1
  10. package/dist/cli/check/computed.js +7 -4
  11. package/dist/cli/check/computed.js.map +1 -1
  12. package/dist/cli/check/lenses.d.ts.map +1 -1
  13. package/dist/cli/check/lenses.js +4 -2
  14. package/dist/cli/check/lenses.js.map +1 -1
  15. package/dist/cli/check/policy.d.ts.map +1 -1
  16. package/dist/cli/check/policy.js +12 -4
  17. package/dist/cli/check/policy.js.map +1 -1
  18. package/dist/cli/check/relations.d.ts +0 -11
  19. package/dist/cli/check/relations.d.ts.map +1 -1
  20. package/dist/cli/check/relations.js +21 -46
  21. package/dist/cli/check/relations.js.map +1 -1
  22. package/dist/cli/check/views.d.ts.map +1 -1
  23. package/dist/cli/check/views.js +3 -2
  24. package/dist/cli/check/views.js.map +1 -1
  25. package/dist/cli/check.d.ts.map +1 -1
  26. package/dist/cli/check.js +1 -2
  27. package/dist/cli/check.js.map +1 -1
  28. package/dist/cli/describe.d.ts.map +1 -1
  29. package/dist/cli/describe.js +23 -2
  30. package/dist/cli/describe.js.map +1 -1
  31. package/dist/cli/doctor.d.ts +34 -0
  32. package/dist/cli/doctor.d.ts.map +1 -0
  33. package/dist/cli/doctor.js +346 -0
  34. package/dist/cli/doctor.js.map +1 -0
  35. package/dist/cli/document-schema.d.ts +6 -0
  36. package/dist/cli/document-schema.d.ts.map +1 -0
  37. package/dist/cli/document-schema.js +55 -0
  38. package/dist/cli/document-schema.js.map +1 -0
  39. package/dist/cli/index.d.ts +3 -1
  40. package/dist/cli/index.d.ts.map +1 -1
  41. package/dist/cli/index.js +41 -2
  42. package/dist/cli/index.js.map +1 -1
  43. package/dist/cli/types.d.ts +12 -0
  44. package/dist/cli/types.d.ts.map +1 -0
  45. package/dist/cli/types.js +95 -0
  46. package/dist/cli/types.js.map +1 -0
  47. package/dist/conformance/fixtures.d.ts.map +1 -1
  48. package/dist/conformance/fixtures.js +6 -3
  49. package/dist/conformance/fixtures.js.map +1 -1
  50. package/dist/describe.d.ts +3 -1
  51. package/dist/describe.d.ts.map +1 -1
  52. package/dist/describe.js +9 -0
  53. package/dist/describe.js.map +1 -1
  54. package/dist/document/block-context.d.ts +50 -0
  55. package/dist/document/block-context.d.ts.map +1 -0
  56. package/dist/document/block-context.js +69 -0
  57. package/dist/document/block-context.js.map +1 -0
  58. package/dist/document/blocks.d.ts +24 -10
  59. package/dist/document/blocks.d.ts.map +1 -1
  60. package/dist/document/blocks.js +50 -39
  61. package/dist/document/blocks.js.map +1 -1
  62. package/dist/document/compile-checked.d.ts.map +1 -1
  63. package/dist/document/compile-checked.js +6 -3
  64. package/dist/document/compile-checked.js.map +1 -1
  65. package/dist/document/compile.d.ts +1 -1
  66. package/dist/document/compile.d.ts.map +1 -1
  67. package/dist/document/compile.js +8 -3
  68. package/dist/document/compile.js.map +1 -1
  69. package/dist/document/compiled.d.ts +2 -0
  70. package/dist/document/compiled.d.ts.map +1 -1
  71. package/dist/document/compiled.js +31 -27
  72. package/dist/document/compiled.js.map +1 -1
  73. package/dist/document/computed-values.d.ts +6 -1
  74. package/dist/document/computed-values.d.ts.map +1 -1
  75. package/dist/document/computed-values.js +7 -4
  76. package/dist/document/computed-values.js.map +1 -1
  77. package/dist/document/computed.d.ts +21 -0
  78. package/dist/document/computed.d.ts.map +1 -1
  79. package/dist/document/computed.js +54 -4
  80. package/dist/document/computed.js.map +1 -1
  81. package/dist/document/describe-place.d.ts +15 -0
  82. package/dist/document/describe-place.d.ts.map +1 -1
  83. package/dist/document/describe-place.js +33 -28
  84. package/dist/document/describe-place.js.map +1 -1
  85. package/dist/document/diff.d.ts.map +1 -1
  86. package/dist/document/diff.js +22 -0
  87. package/dist/document/diff.js.map +1 -1
  88. package/dist/document/edit.d.ts.map +1 -1
  89. package/dist/document/edit.js +34 -0
  90. package/dist/document/edit.js.map +1 -1
  91. package/dist/document/expr/evaluate.d.ts +7 -1
  92. package/dist/document/expr/evaluate.d.ts.map +1 -1
  93. package/dist/document/expr/evaluate.js +19 -5
  94. package/dist/document/expr/evaluate.js.map +1 -1
  95. package/dist/document/expr/index.d.ts +1 -1
  96. package/dist/document/expr/index.d.ts.map +1 -1
  97. package/dist/document/expr/index.js +1 -1
  98. package/dist/document/expr/index.js.map +1 -1
  99. package/dist/document/expr/parse.js +1 -1
  100. package/dist/document/expr/parse.js.map +1 -1
  101. package/dist/document/fact-values.d.ts +21 -0
  102. package/dist/document/fact-values.d.ts.map +1 -0
  103. package/dist/document/fact-values.js +24 -0
  104. package/dist/document/fact-values.js.map +1 -0
  105. package/dist/document/facts-and-roles.d.ts +17 -0
  106. package/dist/document/facts-and-roles.d.ts.map +1 -0
  107. package/dist/document/facts-and-roles.js +75 -0
  108. package/dist/document/facts-and-roles.js.map +1 -0
  109. package/dist/document/resolve-for.d.ts +29 -0
  110. package/dist/document/resolve-for.d.ts.map +1 -0
  111. package/dist/document/resolve-for.js +23 -0
  112. package/dist/document/resolve-for.js.map +1 -0
  113. package/dist/document/respell.js +2 -2
  114. package/dist/document/respell.js.map +1 -1
  115. package/dist/document/rule-line.d.ts.map +1 -1
  116. package/dist/document/rule-line.js +6 -2
  117. package/dist/document/rule-line.js.map +1 -1
  118. package/dist/document/rules.d.ts.map +1 -1
  119. package/dist/document/rules.js +5 -1
  120. package/dist/document/rules.js.map +1 -1
  121. package/dist/document/schema.d.ts +8 -0
  122. package/dist/document/schema.d.ts.map +1 -1
  123. package/dist/document/schema.js +20 -3
  124. package/dist/document/schema.js.map +1 -1
  125. package/dist/document/to-document.d.ts.map +1 -1
  126. package/dist/document/to-document.js +2 -0
  127. package/dist/document/to-document.js.map +1 -1
  128. package/dist/document/views.d.ts +15 -1
  129. package/dist/document/views.d.ts.map +1 -1
  130. package/dist/document/views.js +82 -34
  131. package/dist/document/views.js.map +1 -1
  132. package/dist/document.schema.json +1655 -0
  133. package/dist/index.d.ts +1 -9
  134. package/dist/index.d.ts.map +1 -1
  135. package/dist/index.js +2 -5
  136. package/dist/index.js.map +1 -1
  137. package/dist/invariants/engine.d.ts +13 -0
  138. package/dist/invariants/engine.d.ts.map +1 -1
  139. package/dist/invariants/engine.js +16 -1
  140. package/dist/invariants/engine.js.map +1 -1
  141. package/dist/invariants/types.d.ts +7 -4
  142. package/dist/invariants/types.d.ts.map +1 -1
  143. package/dist/lines.d.ts +23 -3
  144. package/dist/lines.d.ts.map +1 -1
  145. package/dist/lines.js +38 -6
  146. package/dist/lines.js.map +1 -1
  147. package/dist/places.d.ts.map +1 -1
  148. package/dist/places.js +1 -1
  149. package/dist/places.js.map +1 -1
  150. package/dist/scaffold/project.d.ts.map +1 -1
  151. package/dist/scaffold/project.js +5 -0
  152. package/dist/scaffold/project.js.map +1 -1
  153. package/dist/schema/define-node.d.ts.map +1 -1
  154. package/dist/schema/define-node.js +6 -4
  155. package/dist/schema/define-node.js.map +1 -1
  156. package/dist/schema/schema.d.ts +10 -2
  157. package/dist/schema/schema.d.ts.map +1 -1
  158. package/dist/schema/schema.js +4 -1
  159. package/dist/schema/schema.js.map +1 -1
  160. package/dist/seen.d.ts.map +1 -1
  161. package/dist/seen.js +5 -2
  162. package/dist/seen.js.map +1 -1
  163. package/dist/snapshot.d.ts +67 -0
  164. package/dist/snapshot.d.ts.map +1 -0
  165. package/dist/snapshot.js +181 -0
  166. package/dist/snapshot.js.map +1 -0
  167. package/dist/store.d.ts +32 -2
  168. package/dist/store.d.ts.map +1 -1
  169. package/dist/store.js +48 -35
  170. package/dist/store.js.map +1 -1
  171. package/dist/sync/engine.d.ts +93 -9
  172. package/dist/sync/engine.d.ts.map +1 -1
  173. package/dist/sync/engine.js +357 -48
  174. package/dist/sync/engine.js.map +1 -1
  175. package/dist/sync/index.d.ts +11 -0
  176. package/dist/sync/index.d.ts.map +1 -0
  177. package/dist/sync/index.js +15 -0
  178. package/dist/sync/index.js.map +1 -0
  179. package/dist/sync/mcp.d.ts +124 -0
  180. package/dist/sync/mcp.d.ts.map +1 -0
  181. package/dist/sync/mcp.js +247 -0
  182. package/dist/sync/mcp.js.map +1 -0
  183. package/dist/sync/types.d.ts +35 -0
  184. package/dist/sync/types.d.ts.map +1 -1
  185. package/dist/sync/types.js.map +1 -1
  186. package/dist/testing.d.ts +30 -0
  187. package/dist/testing.d.ts.map +1 -1
  188. package/dist/testing.js +38 -0
  189. package/dist/testing.js.map +1 -1
  190. package/dist/typed.d.ts +267 -0
  191. package/dist/typed.d.ts.map +1 -0
  192. package/dist/typed.js +35 -0
  193. package/dist/typed.js.map +1 -0
  194. package/dist/version.d.ts +1 -1
  195. package/dist/version.js +1 -1
  196. package/package.json +16 -3
@@ -0,0 +1,11 @@
1
+ export { googleCalendar, googleCalendarMapping } from "./google-calendar.js";
2
+ export type { Fetcher, GoogleCalendarOptions } from "./google-calendar.js";
3
+ export { syncConflictInvariant, SYNC_CONFLICTS } from "./conflict.js";
4
+ export type { SyncConflictOptions } from "./conflict.js";
5
+ export { SyncEngine } from "./engine.js";
6
+ export type { SettledConflict, SyncOptions, SyncReport } from "./engine.js";
7
+ export { allowTools, doorClient, mcpClient, mcpDoor, mcpRemote, ownHost, sameOrigin } from "./mcp.js";
8
+ export type { DoorHeaders, DoorRequest, DoorResponse, McpClientOptions, McpDoorOptions, McpRemoteOptions, ToolCall } from "./mcp.js";
9
+ export { EMPTY_SYNC_STATE, systemAuthor } from "./types.js";
10
+ export type { ConflictPolicy, RemoteAck, RemoteChange, RemoteLink, RemoteSystem, RemoteWrite, ResourceMapping, SyncConflict, SyncMapping, SyncState, } from "./types.js";
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7E,YAAY,EAAE,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC3E,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACtE,YAAY,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC5E,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtG,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,gBAAgB,EAAE,cAAc,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACrI,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC5D,YAAY,EACV,cAAc,EACd,SAAS,EACT,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,WAAW,EACX,eAAe,EACf,YAAY,EACZ,WAAW,EACX,SAAS,GACV,MAAM,YAAY,CAAC"}
@@ -0,0 +1,15 @@
1
+ /*
2
+ * `@graview/core/sync` — two-way sync on the op log: the engine, its
3
+ * mappings, the conflict invariant, and the transports (Google Calendar, a
4
+ * tool server over MCP).
5
+ *
6
+ * An entry of its own, not part of `@graview/core`: a hosted page imports the
7
+ * main entry up front and draws without ever syncing, so the engine and its
8
+ * transports are reached only by a host that runs one.
9
+ */
10
+ export { googleCalendar, googleCalendarMapping } from "./google-calendar.js";
11
+ export { syncConflictInvariant, SYNC_CONFLICTS } from "./conflict.js";
12
+ export { SyncEngine } from "./engine.js";
13
+ export { allowTools, doorClient, mcpClient, mcpDoor, mcpRemote, ownHost, sameOrigin } from "./mcp.js";
14
+ export { EMPTY_SYNC_STATE, systemAuthor } from "./types.js";
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAE7E,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEtE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtG,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,124 @@
1
+ import type { RemoteChange, RemoteSystem, RemoteWrite } from "./types.js";
2
+ /**
3
+ * A REMOTE THAT SPEAKS MCP — the tools another system already serves, called
4
+ * by name, as the sync's transport.
5
+ *
6
+ * Three pieces, each usable alone. `mcpClient` calls a streamable-HTTP MCP
7
+ * endpoint (a session, JSON or an event stream back, one retry when the
8
+ * server forgot the session) and only the tools it was allowed. `mcpDoor` is
9
+ * the narrow way a page reaches it: a server route that holds the token,
10
+ * answers only its own origin's JSON, and passes only the allowed tools —
11
+ * and `doorClient` is the page's side of it. `mcpRemote` turns calls into a
12
+ * `RemoteSystem` the engine runs.
13
+ *
14
+ * Nothing here imports a `node:` builtin: the client runs in Node or a page,
15
+ * and the door takes any request and response shaped like Node's.
16
+ */
17
+ /** Calls one tool by name and resolves to what it answered: its text, parsed as JSON when it is JSON. */
18
+ export type ToolCall = (name: string, args: Record<string, unknown>) => Promise<unknown>;
19
+ type Fetch = (input: string, init?: RequestInit) => Promise<Response>;
20
+ /**
21
+ * THE TOOLS A SYNC MAY CALL, and the sentence for one it may not. A sync
22
+ * needs a handful of a server's tools; every other one stays out of reach,
23
+ * whoever asks.
24
+ */
25
+ export declare function allowTools(names: Iterable<string>): (name: string) => string | undefined;
26
+ export interface McpClientOptions {
27
+ /** The server's MCP endpoint. */
28
+ readonly url: string;
29
+ /** The tools this client may call; any other is refused before it is sent. */
30
+ readonly allow: Iterable<string>;
31
+ /** Headers each request carries — a token read when it is needed, never handed to a page. */
32
+ readonly headers?: () => Record<string, string> | Promise<Record<string, string>>;
33
+ readonly fetch?: Fetch;
34
+ /** Who is calling, as `initialize` says it. */
35
+ readonly clientInfo?: {
36
+ readonly name: string;
37
+ readonly version: string;
38
+ };
39
+ }
40
+ /** Calls an MCP server's tools over streamable HTTP. */
41
+ export declare function mcpClient(options: McpClientOptions): ToolCall;
42
+ /** The headers a door reads, as Node's `IncomingMessage` has them. */
43
+ export type DoorHeaders = Readonly<Record<string, string | readonly string[] | undefined>>;
44
+ /**
45
+ * WHETHER A HOST IS THIS MACHINE AS A PAGE NAMES IT: `localhost`, a
46
+ * `*.localhost` name or an IP address — or one of `hosts`, the names the
47
+ * server was told it answers to. A page on a name of its own that it
48
+ * rebinds to this machine sends its own name as the Host, and the browser
49
+ * agrees with it about the origin; the name is what gives it away.
50
+ */
51
+ export declare function ownHost(host: string | undefined, hosts?: Iterable<string>): boolean;
52
+ /**
53
+ * WHETHER A REQUEST CAME FROM THIS SERVER'S OWN PAGES: no `Sec-Fetch-Site`
54
+ * other than same-origin (or none, for curl), an `Origin`, when there is
55
+ * one, naming this host, and a host that is this machine (`ownHost`). A page
56
+ * on another origin can fire a request at a local server; it cannot make the
57
+ * browser say it came from here. Every door answers this the same way: the
58
+ * dev server's doors (`@graview/ship/dev`) ask this too.
59
+ */
60
+ export declare function sameOrigin(headers: DoorHeaders, hosts?: Iterable<string>): boolean;
61
+ /** A request and a response, as Node's `http` (and Vite's and Connect's middleware) hands them. */
62
+ export interface DoorRequest {
63
+ readonly method?: string;
64
+ readonly url?: string;
65
+ readonly headers: DoorHeaders;
66
+ on(event: "data", listener: (chunk: unknown) => void): unknown;
67
+ on(event: "end", listener: () => void): unknown;
68
+ }
69
+ export interface DoorResponse {
70
+ statusCode: number;
71
+ setHeader(name: string, value: string): unknown;
72
+ end(body: string): unknown;
73
+ }
74
+ export interface McpDoorOptions {
75
+ /** Where the door answers. Default `/graview/mcp`. */
76
+ readonly path?: string;
77
+ /** What reaches the server — usually an `mcpClient` holding the token. */
78
+ readonly call: ToolCall;
79
+ /** The tools a page may ask for through the door. */
80
+ readonly allow: Iterable<string>;
81
+ /** Host names the server answers to besides this machine's own (`ownHost`). */
82
+ readonly hosts?: Iterable<string>;
83
+ /** The most a request may send, in bytes. Default 1 MB. */
84
+ readonly limit?: number;
85
+ }
86
+ /**
87
+ * THE DOOR A PAGE REACHES A TOOL SERVER THROUGH, as server middleware.
88
+ *
89
+ * The page never holds the token and never names the endpoint: it posts
90
+ * `{ name, arguments }` here and gets `{ ok, result | error }` back. What
91
+ * passes is as narrow as the sync needs — a POST, `application/json`, from
92
+ * this server's own origin, naming an allowed tool — and every refusal says
93
+ * which of those it was.
94
+ */
95
+ export declare function mcpDoor(options: McpDoorOptions): (request: DoorRequest, response: DoorResponse, next: () => void) => void;
96
+ /** The page's side of an `mcpDoor`: the same calls, posted to the door on this page's own origin. */
97
+ export declare function doorClient(options?: {
98
+ readonly path?: string;
99
+ readonly base?: string;
100
+ readonly fetch?: Fetch;
101
+ }): ToolCall;
102
+ export interface McpRemoteOptions {
103
+ /** Names the remote. */
104
+ readonly name: string;
105
+ /** How a call reaches the tools: `mcpClient` in Node, `doorClient` in a page. */
106
+ readonly call: ToolCall;
107
+ /** Everything that changed since `cursor`, read with the tools. */
108
+ pull(call: ToolCall, cursor?: string): Promise<{
109
+ readonly changes: readonly RemoteChange[];
110
+ readonly cursor: string;
111
+ }>;
112
+ /**
113
+ * One write, made with the tools, and the version it produced. Whatever it
114
+ * throws is that write's refusal, in its own words; the rest still go.
115
+ */
116
+ push(call: ToolCall, write: RemoteWrite): Promise<{
117
+ readonly id: string;
118
+ readonly version: string;
119
+ }>;
120
+ }
121
+ /** A `RemoteSystem` over a tool server: one write at a time, each refused alone. */
122
+ export declare function mcpRemote(options: McpRemoteOptions): RemoteSystem;
123
+ export {};
124
+ //# sourceMappingURL=mcp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/sync/mcp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,247 @@
1
+ /**
2
+ * THE TOOLS A SYNC MAY CALL, and the sentence for one it may not. A sync
3
+ * needs a handful of a server's tools; every other one stays out of reach,
4
+ * whoever asks.
5
+ */
6
+ export function allowTools(names) {
7
+ const allowed = [...new Set(names)];
8
+ return (name) => allowed.includes(name) ? undefined : `${name} is not a tool this sync uses (it uses ${allowed.join(", ")}).`;
9
+ }
10
+ /** A JSON-RPC answer, from a JSON body or the last `data:` line of an event stream. */
11
+ async function readAnswer(response) {
12
+ const text = await response.text();
13
+ if (response.headers.get("content-type")?.includes("text/event-stream")) {
14
+ const data = text
15
+ .split("\n")
16
+ .filter((line) => line.startsWith("data:"))
17
+ .map((line) => line.slice(5).trim())
18
+ .filter(Boolean);
19
+ return data.length > 0 ? JSON.parse(data[data.length - 1]) : {};
20
+ }
21
+ return text ? JSON.parse(text) : {};
22
+ }
23
+ /** Calls an MCP server's tools over streamable HTTP. */
24
+ export function mcpClient(options) {
25
+ const send = options.fetch ?? ((input, init) => fetch(input, init));
26
+ const refuse = allowTools(options.allow);
27
+ let session;
28
+ let opening;
29
+ let id = 0;
30
+ const headers = async (extra = {}) => ({
31
+ "content-type": "application/json",
32
+ accept: "application/json, text/event-stream",
33
+ ...(await options.headers?.()),
34
+ ...(session ? { "mcp-session-id": session } : {}),
35
+ ...extra,
36
+ });
37
+ const open = async () => {
38
+ const init = await send(options.url, {
39
+ method: "POST",
40
+ headers: await headers(),
41
+ body: JSON.stringify({
42
+ jsonrpc: "2.0",
43
+ id: ++id,
44
+ method: "initialize",
45
+ params: { protocolVersion: "2024-11-05", capabilities: {}, clientInfo: options.clientInfo ?? { name: "graview-sync", version: "1" } },
46
+ }),
47
+ });
48
+ if (!init.ok)
49
+ throw new Error(`The MCP server answered ${init.status} when the sync introduced itself.`);
50
+ const opened = init.headers.get("mcp-session-id") ?? undefined;
51
+ await init.text();
52
+ await send(options.url, {
53
+ method: "POST",
54
+ headers: await headers(opened ? { "mcp-session-id": opened } : {}),
55
+ body: JSON.stringify({ jsonrpc: "2.0", method: "notifications/initialized" }),
56
+ });
57
+ return opened;
58
+ };
59
+ const call = async (name, args, retry) => {
60
+ const refusal = refuse(name);
61
+ if (refusal)
62
+ throw new Error(refusal);
63
+ if (session === undefined)
64
+ session = await (opening ??= open().finally(() => (opening = undefined)));
65
+ const response = await send(options.url, {
66
+ method: "POST",
67
+ headers: await headers(),
68
+ body: JSON.stringify({ jsonrpc: "2.0", id: ++id, method: "tools/call", params: { name, arguments: args } }),
69
+ });
70
+ if ((response.status === 404 || response.status === 400) && retry && session !== undefined) {
71
+ // The server restarted and forgot the session: open another, once.
72
+ session = undefined;
73
+ await response.text();
74
+ return call(name, args, false);
75
+ }
76
+ if (!response.ok)
77
+ throw new Error(`The MCP server answered ${response.status} to ${name}.`);
78
+ const answer = await readAnswer(response);
79
+ if (answer.error)
80
+ throw new Error(answer.error.message ?? `The MCP server refused ${name}.`);
81
+ const text = answer.result?.content?.find((part) => part.type === "text")?.text ?? "";
82
+ if (answer.result?.isError)
83
+ throw new Error(text || `${name} failed.`);
84
+ try {
85
+ return JSON.parse(text);
86
+ }
87
+ catch {
88
+ return text;
89
+ }
90
+ };
91
+ return (name, args) => call(name, args, true);
92
+ }
93
+ /**
94
+ * WHETHER A HOST IS THIS MACHINE AS A PAGE NAMES IT: `localhost`, a
95
+ * `*.localhost` name or an IP address — or one of `hosts`, the names the
96
+ * server was told it answers to. A page on a name of its own that it
97
+ * rebinds to this machine sends its own name as the Host, and the browser
98
+ * agrees with it about the origin; the name is what gives it away.
99
+ */
100
+ export function ownHost(host, hosts = []) {
101
+ if (host === undefined)
102
+ return true;
103
+ let name;
104
+ try {
105
+ name = new URL(`http://${host}`).hostname.toLowerCase();
106
+ }
107
+ catch {
108
+ return false;
109
+ }
110
+ if (name === "localhost" || name.endsWith(".localhost") || /^\d{1,3}(\.\d{1,3}){3}$/.test(name) || name.startsWith("["))
111
+ return true;
112
+ for (const allowed of hosts)
113
+ if (allowed.toLowerCase() === name)
114
+ return true;
115
+ return false;
116
+ }
117
+ /**
118
+ * WHETHER A REQUEST CAME FROM THIS SERVER'S OWN PAGES: no `Sec-Fetch-Site`
119
+ * other than same-origin (or none, for curl), an `Origin`, when there is
120
+ * one, naming this host, and a host that is this machine (`ownHost`). A page
121
+ * on another origin can fire a request at a local server; it cannot make the
122
+ * browser say it came from here. Every door answers this the same way: the
123
+ * dev server's doors (`@graview/ship/dev`) ask this too.
124
+ */
125
+ export function sameOrigin(headers, hosts) {
126
+ const site = headers["sec-fetch-site"];
127
+ if (typeof site === "string" && site !== "same-origin" && site !== "none")
128
+ return false;
129
+ const host = headers["host"];
130
+ if (!ownHost(typeof host === "string" ? host : undefined, hosts))
131
+ return false;
132
+ const origin = headers["origin"];
133
+ if (typeof origin !== "string")
134
+ return true;
135
+ try {
136
+ return new URL(origin).host === host;
137
+ }
138
+ catch {
139
+ return false;
140
+ }
141
+ }
142
+ /**
143
+ * THE DOOR A PAGE REACHES A TOOL SERVER THROUGH, as server middleware.
144
+ *
145
+ * The page never holds the token and never names the endpoint: it posts
146
+ * `{ name, arguments }` here and gets `{ ok, result | error }` back. What
147
+ * passes is as narrow as the sync needs — a POST, `application/json`, from
148
+ * this server's own origin, naming an allowed tool — and every refusal says
149
+ * which of those it was.
150
+ */
151
+ export function mcpDoor(options) {
152
+ const path = options.path ?? "/graview/mcp";
153
+ const refuse = allowTools(options.allow);
154
+ const hosts = options.hosts ? [...options.hosts] : undefined;
155
+ const limit = options.limit ?? 1_000_000;
156
+ const answer = (response, status, body) => {
157
+ response.statusCode = status;
158
+ response.setHeader("content-type", "application/json");
159
+ response.end(JSON.stringify(body));
160
+ };
161
+ return (request, response, next) => {
162
+ if ((request.url ?? "").split("?")[0] !== path)
163
+ return next();
164
+ if (request.method !== "POST")
165
+ return answer(response, 405, { ok: false, error: "Refused: the door takes a POST." });
166
+ if (!sameOrigin(request.headers, hosts))
167
+ return answer(response, 403, { ok: false, error: "Refused: not from this page's own origin." });
168
+ const type = request.headers["content-type"];
169
+ // The media type itself: one a page on another site may send unasked (`text/plain; x=application/json`) is not JSON.
170
+ if (typeof type !== "string" || type.split(";")[0].trim().toLowerCase() !== "application/json") {
171
+ return answer(response, 415, { ok: false, error: "Refused: send application/json." });
172
+ }
173
+ const decoder = new TextDecoder();
174
+ let text = "";
175
+ let size = 0;
176
+ let over = false;
177
+ request.on("data", (chunk) => {
178
+ if (over)
179
+ return;
180
+ const bytes = typeof chunk === "string" ? new TextEncoder().encode(chunk) : chunk;
181
+ size += bytes.byteLength;
182
+ if (size > limit) {
183
+ over = true;
184
+ return answer(response, 413, { ok: false, error: `Refused: more than ${limit} bytes.` });
185
+ }
186
+ text += decoder.decode(bytes, { stream: true });
187
+ });
188
+ request.on("end", () => {
189
+ if (over)
190
+ return;
191
+ text += decoder.decode();
192
+ void (async () => {
193
+ let asked;
194
+ try {
195
+ asked = JSON.parse(text || "{}");
196
+ }
197
+ catch {
198
+ return answer(response, 400, { ok: false, error: "Refused: the body is not JSON." });
199
+ }
200
+ if (typeof asked.name !== "string")
201
+ return answer(response, 400, { ok: false, error: "Refused: name the tool." });
202
+ const refusal = refuse(asked.name);
203
+ if (refusal)
204
+ return answer(response, 403, { ok: false, error: `Refused: ${refusal}` });
205
+ try {
206
+ const args = asked.arguments && typeof asked.arguments === "object" ? asked.arguments : {};
207
+ answer(response, 200, { ok: true, result: await options.call(asked.name, args) });
208
+ }
209
+ catch (error) {
210
+ answer(response, 200, { ok: false, error: error instanceof Error ? error.message : String(error) });
211
+ }
212
+ })();
213
+ });
214
+ };
215
+ }
216
+ /** The page's side of an `mcpDoor`: the same calls, posted to the door on this page's own origin. */
217
+ export function doorClient(options = {}) {
218
+ const send = options.fetch ?? ((input, init) => fetch(input, init));
219
+ const at = `${options.base ?? ""}${options.path ?? "/graview/mcp"}`;
220
+ return async (name, args) => {
221
+ const response = await send(at, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ name, arguments: args }) });
222
+ const body = (await response.json().catch(() => ({ ok: false, error: `The door answered ${response.status}.` })));
223
+ if (!body.ok)
224
+ throw new Error(body.error ?? `The door refused ${name}.`);
225
+ return body.result;
226
+ };
227
+ }
228
+ /** A `RemoteSystem` over a tool server: one write at a time, each refused alone. */
229
+ export function mcpRemote(options) {
230
+ return {
231
+ name: options.name,
232
+ pull: (cursor) => options.pull(options.call, cursor),
233
+ async push(writes) {
234
+ const acks = [];
235
+ for (const write of writes) {
236
+ try {
237
+ acks.push({ localId: write.localId, ...(await options.push(options.call, write)) });
238
+ }
239
+ catch (error) {
240
+ acks.push({ localId: write.localId, id: write.id ?? "", version: "", error: error instanceof Error ? error.message : String(error) });
241
+ }
242
+ }
243
+ return acks;
244
+ },
245
+ };
246
+ }
247
+ //# sourceMappingURL=mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/sync/mcp.ts"],"names":[],"mappings":"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"}
@@ -43,6 +43,27 @@ export interface ResourceMapping {
43
43
  */
44
44
  readonly encode?: Readonly<Record<string, (value: unknown, node: Record<string, unknown>) => unknown>>;
45
45
  readonly decode?: Readonly<Record<string, (value: unknown) => unknown>>;
46
+ /**
47
+ * THE REMOTE OWNS THESE. Inbound changes land; nothing here is ever sent,
48
+ * and a local act that would write a record of the kind is refused with
49
+ * `because` once the engine guards the store (`SyncEngine.guard`), and the
50
+ * store's `permits` stops offering it — the
51
+ * sentence a person reads, so it names who does own it ("sourcevision:
52
+ * re-run the analysis to change the zones").
53
+ */
54
+ readonly readonly?: boolean;
55
+ /** Why a read-only resource is not written from here, as a person reads it. */
56
+ readonly because?: string;
57
+ /**
58
+ * OUR FIELD THAT HOLDS THE REMOTE'S VERSION of a record, when the graph
59
+ * was made from the remote (a projection, an import, a seed). A node that
60
+ * carries one and has no link is linked at it when the engine is made, so
61
+ * the first run pushes nothing it did not have to and an unchanged pull
62
+ * is an echo, not news.
63
+ */
64
+ readonly version?: string;
65
+ /** Our field that holds the remote's id, for those links. Absent: the node's own id. */
66
+ readonly remoteId?: string;
46
67
  }
47
68
  export interface SyncMapping {
48
69
  /** Names the system, and appears as the author of every inbound change. */
@@ -106,6 +127,13 @@ export interface SyncState {
106
127
  readonly links: Readonly<Record<string, RemoteLink>>;
107
128
  /** Writes that have not reached the remote yet. */
108
129
  readonly outbox: readonly RemoteWrite[];
130
+ /**
131
+ * Conflicts waiting for somebody to choose (the `report` policy). A field
132
+ * held here is not sent until `resolve` says which side stands.
133
+ */
134
+ readonly conflicts?: readonly SyncConflict[];
135
+ /** Records the remote deleted that were kept here: no longer linked, and not sent again as new. */
136
+ readonly gone?: readonly string[];
109
137
  }
110
138
  export interface RemoteLink {
111
139
  readonly resource: string;
@@ -122,6 +150,13 @@ export interface RemoteLink {
122
150
  export declare const EMPTY_SYNC_STATE: SyncState;
123
151
  /** The author every inbound change is attributed to. */
124
152
  export declare function systemAuthor(system: string): Author;
153
+ /**
154
+ * WHAT A CONFLICT BECOMES, decided once for the engine: `report` holds both
155
+ * sides and sends neither until somebody chooses (`resolve`); `theirs` takes
156
+ * the remote's value through the ordinary inbound act; `ours` keeps ours and
157
+ * sends it. Every one of them is said in the report.
158
+ */
159
+ export type ConflictPolicy = "report" | "theirs" | "ours";
125
160
  /** One field, changed on both sides since the last time they agreed. */
126
161
  export interface SyncConflict {
127
162
  readonly localId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/sync/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/sync/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/sync/types.ts"],"names":[],"mappings":"AAoIA,MAAM,CAAC,MAAM,gBAAgB,GAAc,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;AAErE,wDAAwD;AACxD,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC;AACxC,CAAC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/sync/types.ts"],"names":[],"mappings":"AAgKA,MAAM,CAAC,MAAM,gBAAgB,GAAc,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;AAErE,wDAAwD;AACxD,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC;AACxC,CAAC"}
package/dist/testing.d.ts CHANGED
@@ -1,5 +1,8 @@
1
1
  import { type GraviewApp } from "./app.js";
2
2
  import type { GraphSnapshot } from "./graph/types.js";
3
+ import type { AnySchema } from "./schema/schema.js";
4
+ import { Store } from "./store.js";
5
+ import { type Finding as DocumentFinding } from "./document/findings.js";
3
6
  /**
4
7
  * A DECLARATION BUILT TO BE AWKWARD.
5
8
  *
@@ -66,4 +69,31 @@ export interface AwkwardGraphOptions {
66
69
  readonly fill?: Readonly<Record<string, unknown>>;
67
70
  }
68
71
  export declare function awkwardGraph(app: GraviewApp, options?: number | AwkwardGraphOptions): GraphSnapshot;
72
+ /**
73
+ * A PRODUCT'S DOCUMENT AND SEED, COMPILED FROM WHERE THEY LIVE.
74
+ *
75
+ * A product whose declaration is a document (n-dx's emitted one, a hosted
76
+ * app's) tested it by copying it into `tests/fixtures` and holding the copy
77
+ * to the original with a drift test of its own. Read from its path instead,
78
+ * there is no copy to drift: the document compiled with the checker (a
79
+ * refusal throws, saying every finding), the seed read beside it, and a
80
+ * fresh store over both — the app's own acts, rules and policy, in memory —
81
+ * each time `store()` is asked. Paths are relative to the working
82
+ * directory, or a `file:` URL (`new URL("../app.graview.json", import.meta.url)`).
83
+ */
84
+ export interface DocumentFiles {
85
+ readonly app: GraviewApp;
86
+ /** The document as read. */
87
+ readonly document: unknown;
88
+ /** The seed as read, when one was named. */
89
+ readonly seed?: GraphSnapshot;
90
+ /** What the checker said of a document it compiled: warnings and notes. */
91
+ readonly findings: readonly DocumentFinding[];
92
+ /** A fresh store over the seed, every call. */
93
+ store(): Store<AnySchema>;
94
+ }
95
+ export declare function compileDocumentFiles(document: string | URL, options?: {
96
+ readonly seed?: string | URL;
97
+ readonly today?: () => string;
98
+ }): DocumentFiles;
69
99
  //# sourceMappingURL=testing.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AACA,OAAO,EAAa,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAMtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,WAAW,cAAc;IAC7B,4EAA4E;IAC5E,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,iFAAiF;IACjF,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,sEAAsE;IACtE,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B,6EAA6E;IAC7E,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACpC;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AA6CD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,OAAO,GAAE,cAAmB,GAAG,UAAU,CAyEnE;AA6CD;;;;;;;;GAQG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACnD;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,UAAU,EAAE,OAAO,GAAE,MAAM,GAAG,mBAAwB,GAAG,aAAa,CA+BvG"}
1
+ {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAGA,OAAO,EAAa,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAMtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGnC,OAAO,EAAe,KAAK,OAAO,IAAI,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEtF;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,WAAW,cAAc;IAC7B,4EAA4E;IAC5E,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,iFAAiF;IACjF,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,sEAAsE;IACtE,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B,6EAA6E;IAC7E,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACpC;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AA6CD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,OAAO,GAAE,cAAmB,GAAG,UAAU,CAyEnE;AA6CD;;;;;;;;GAQG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACnD;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,UAAU,EAAE,OAAO,GAAE,MAAM,GAAG,mBAAwB,GAAG,aAAa,CA+BvG;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC;IACzB,4BAA4B;IAC5B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,4CAA4C;IAC5C,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC;IAC9B,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,SAAS,eAAe,EAAE,CAAC;IAC9C,+CAA+C;IAC/C,KAAK,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC;CAC3B;AAcD,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,GAAG,EAAE,OAAO,GAAE;IAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,MAAM,CAAA;CAAO,GAAG,aAAa,CAoBzJ"}
package/dist/testing.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { resolve as resolvePath } from "node:path";
1
3
  import { z } from "zod";
2
4
  import { defineApp } from "./app.js";
3
5
  import { declareInstallation } from "./installation.js";
@@ -5,6 +7,10 @@ import { bindSchema } from "./bind.js";
5
7
  import { nodeRef } from "./mutations/node-ref.js";
6
8
  import { createSchema } from "./schema/schema.js";
7
9
  import { defineNode } from "./schema/define-node.js";
10
+ import { Store } from "./store.js";
11
+ import { readSnapshot } from "./snapshot.js";
12
+ import { compileDocument } from "./document/compile-checked.js";
13
+ import { sayFindings } from "./document/findings.js";
8
14
  /* Plurals of the length a real domain has. The district row breaks on these
9
15
  and never on "Jobs", which is why the examples never found it. */
10
16
  const LONG = [
@@ -193,4 +199,36 @@ export function awkwardGraph(app, options = {}) {
193
199
  }
194
200
  return { nodes: nodes, edges: [] };
195
201
  }
202
+ const readJsonAt = (path) => JSON.parse(readFileSync(typeof path === "string" ? resolvePath(process.cwd(), path) : path, "utf8"));
203
+ /** A seed as `serve --seed` reads it: the snapshot's line format, or an old `{ nodes, edges }` file. */
204
+ function readSeed(path) {
205
+ const text = readFileSync(typeof path === "string" ? resolvePath(process.cwd(), path) : path, "utf8");
206
+ try {
207
+ return readSnapshot(text).snapshot;
208
+ }
209
+ catch {
210
+ throw new Error(`${String(path)} is not a graph snapshot: it needs "nodes" and "edges" arrays, or a snapshot header line.`);
211
+ }
212
+ }
213
+ export function compileDocumentFiles(document, options = {}) {
214
+ const read = readJsonAt(document);
215
+ const compiled = compileDocument(read, options.today ? { today: options.today } : {});
216
+ if (!compiled.ok)
217
+ throw new Error(`${String(document)} does not compile:\n${sayFindings(compiled.findings)}`);
218
+ const app = compiled.app;
219
+ const seed = options.seed === undefined ? undefined : readSeed(options.seed);
220
+ return {
221
+ app,
222
+ document: read,
223
+ ...(seed ? { seed } : {}),
224
+ findings: compiled.findings,
225
+ store: () => new Store({
226
+ schema: app.schema,
227
+ mutations: (app.mutations ?? []),
228
+ invariants: (app.invariants ?? []),
229
+ ...(seed ? { snapshot: structuredClone(seed) } : {}),
230
+ ...(app.policy ? { policy: app.policy } : {}),
231
+ }),
232
+ };
233
+ }
196
234
  //# sourceMappingURL=testing.js.map