stitchkit 0.89.0 → 0.90.1

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 (65) hide show
  1. package/CHANGELOG.md +102 -0
  2. package/dist/agent-runtime/coding-tool-refusals.d.ts +31 -10
  3. package/dist/agent-runtime/coding-tool-refusals.d.ts.map +1 -1
  4. package/dist/agent-runtime/spill.d.ts.map +1 -1
  5. package/dist/agent-runtime-coding-tools.js +4 -4
  6. package/dist/agent-runtime-harness.js +5 -5
  7. package/dist/agent-runtime-sandbox.js +5 -5
  8. package/dist/agent-runtime.js +17 -29
  9. package/dist/application/watch-hub.d.ts +24 -2
  10. package/dist/application/watch-hub.d.ts.map +1 -1
  11. package/dist/application-grammy.js +1 -1
  12. package/dist/application.js +103 -13
  13. package/dist/cli.js +7 -7
  14. package/dist/contract/errors.d.ts +3 -0
  15. package/dist/contract/errors.d.ts.map +1 -1
  16. package/dist/contract/index.js +2 -2
  17. package/dist/{index-qmgs7y68.js → index-1txvygak.js} +1 -1
  18. package/dist/{index-8c3a7m4g.js → index-2hrfpw2c.js} +1 -1
  19. package/dist/{index-7evdsyez.js → index-2hryh65w.js} +1 -1
  20. package/dist/index-2na0qrfn.js +214 -0
  21. package/dist/{index-zyvby92n.js → index-44ht2790.js} +2 -2
  22. package/dist/{index-27gm3d6g.js → index-6q3zjwaz.js} +2 -2
  23. package/dist/{index-mnm4qp0p.js → index-79hb1wyh.js} +3 -3
  24. package/dist/{index-apn8repm.js → index-7gqx71yd.js} +2 -2
  25. package/dist/{index-7601qfg1.js → index-8dph3pw6.js} +4 -4
  26. package/dist/{index-90d7h2cr.js → index-bg8ypxzn.js} +3 -3
  27. package/dist/{index-vchzar7e.js → index-db51n3xr.js} +5 -5
  28. package/dist/{index-hw2chdvy.js → index-f475yj00.js} +1 -1
  29. package/dist/{index-q3ve2d1k.js → index-gbqjt8jz.js} +3 -3
  30. package/dist/index-gte38nbm.js +101 -0
  31. package/dist/{index-cp20z0n6.js → index-j7q0xj6d.js} +7 -55
  32. package/dist/{index-2bxcmqkb.js → index-kazec06k.js} +1 -1
  33. package/dist/{index-0w9abg87.js → index-scs3f1eg.js} +3 -0
  34. package/dist/{index-31jw8fjq.js → index-wb15909q.js} +1 -1
  35. package/dist/{index-p18f59zy.js → index-z78bjcxj.js} +1 -1
  36. package/dist/{index-t7fkyxcr.js → index-zkcqhxx8.js} +1 -1
  37. package/dist/index.js +6 -6
  38. package/dist/live/watch-client.d.ts +2 -1
  39. package/dist/live/watch-client.d.ts.map +1 -1
  40. package/dist/live/watch-contract.d.ts +70 -4
  41. package/dist/live/watch-contract.d.ts.map +1 -1
  42. package/dist/live/watch-delta.d.ts +110 -0
  43. package/dist/live/watch-delta.d.ts.map +1 -0
  44. package/dist/live.d.ts +2 -1
  45. package/dist/live.d.ts.map +1 -1
  46. package/dist/live.js +56 -4
  47. package/dist/node.js +6 -6
  48. package/dist/observability/changes.d.ts +55 -0
  49. package/dist/observability/changes.d.ts.map +1 -0
  50. package/dist/observability/index.d.ts +2 -0
  51. package/dist/observability/index.d.ts.map +1 -1
  52. package/dist/observability/index.js +130 -3
  53. package/dist/observability/spool.d.ts +53 -0
  54. package/dist/observability/spool.d.ts.map +1 -0
  55. package/dist/primitives.js +2 -2
  56. package/dist/remote.js +5 -5
  57. package/dist/server/index.js +8 -8
  58. package/dist/testing.js +6 -6
  59. package/dist/tool-invoker.js +6 -6
  60. package/dist/tools.js +11 -11
  61. package/dist/tracking.js +2 -2
  62. package/llms-full.txt +156 -15
  63. package/package.json +1 -1
  64. package/dist/index-dre2ywck.js +0 -48
  65. package/dist/index-gskm1k5a.js +0 -50
@@ -11,7 +11,7 @@ import {
11
11
  } from "./index-3z73fh2c.js";
12
12
  import {
13
13
  AppError
14
- } from "./index-0w9abg87.js";
14
+ } from "./index-scs3f1eg.js";
15
15
 
16
16
  // src/application/kernel.ts
17
17
  import { z } from "zod";
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ import {
15
15
  createUrlBuilder,
16
16
  createUrlBuilders,
17
17
  parseNDJSON
18
- } from "./index-27gm3d6g.js";
18
+ } from "./index-6q3zjwaz.js";
19
19
  import {
20
20
  REALTIME_REJECTION_KEY,
21
21
  asRealtimeRejection,
@@ -23,7 +23,7 @@ import {
23
23
  isModuleNotFound,
24
24
  parseRealtimeRequestAcknowledgement,
25
25
  parseRealtimeRequestArguments
26
- } from "./index-apn8repm.js";
26
+ } from "./index-7gqx71yd.js";
27
27
  import {
28
28
  RealtimeRequestDisconnectedError,
29
29
  RealtimeRequestInvalidAcknowledgementError,
@@ -34,7 +34,7 @@ import {
34
34
  } from "./index-2qzskm8h.js";
35
35
  import {
36
36
  parseSSE
37
- } from "./index-qmgs7y68.js";
37
+ } from "./index-1txvygak.js";
38
38
  import {
39
39
  LiveStateControllerStatusSchema,
40
40
  LiveStatePhaseSchema,
@@ -49,7 +49,7 @@ import {
49
49
  import {
50
50
  formatZodError,
51
51
  zodIssues
52
- } from "./index-7evdsyez.js";
52
+ } from "./index-2hryh65w.js";
53
53
  import {
54
54
  ALL_TRANSPORTS,
55
55
  ContractStreamFrameSchema,
@@ -60,7 +60,7 @@ import {
60
60
  defineErrors,
61
61
  encodeCursor,
62
62
  paginatedSchema
63
- } from "./index-2bxcmqkb.js";
63
+ } from "./index-kazec06k.js";
64
64
  import {
65
65
  ManagedFilePathSchema,
66
66
  ManagedFileRefSchema
@@ -76,7 +76,7 @@ import {
76
76
  notFound,
77
77
  rateLimited,
78
78
  unauthorized
79
- } from "./index-0w9abg87.js";
79
+ } from "./index-scs3f1eg.js";
80
80
  import {
81
81
  childSpan,
82
82
  createTraceContext,
@@ -44,7 +44,7 @@
44
44
  * sense a rendering component can use.
45
45
  */
46
46
  import type { ContractDef, EndpointDef } from '../contract/define.js';
47
- import { WATCH_CLOSE, WATCH_OPEN, WATCH_STATE, WATCH_VALUE, type WatchKey, type WatchStateFrame, type WatchValueFrame } from './watch-contract.js';
47
+ import { WATCH_CLOSE, WATCH_OPEN, WATCH_STATE, WATCH_VALUE, type WatchHave, type WatchKey, type WatchStateFrame, type WatchValueFrame } from './watch-contract.js';
48
48
  export interface WatchListeners<TValue> {
49
49
  value(value: TValue): void;
50
50
  /** Phase and, when unhealthy, the read's own code and message. */
@@ -107,6 +107,7 @@ export interface WatchTransport {
107
107
  request(event: typeof WATCH_OPEN, payload: {
108
108
  key: WatchKey;
109
109
  args: unknown;
110
+ have?: WatchHave;
110
111
  }, options: {
111
112
  timeoutMs: number;
112
113
  }): Promise<{
@@ -1 +1 @@
1
- {"version":3,"file":"watch-client.d.ts","sourceRoot":"","sources":["../../src/live/watch-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"watch-client.d.ts","sourceRoot":"","sources":["../../src/live/watch-client.ts"],"names":[],"mappings":"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"}
@@ -26,6 +26,20 @@ export declare const WatchKeySchema: z.ZodReadonly<z.ZodObject<{
26
26
  digest: z.ZodString;
27
27
  }, z.core.$strict>>;
28
28
  export type WatchKey = z.infer<typeof WatchKeySchema>;
29
+ /**
30
+ * What a subscriber already holds, offered when it opens a key.
31
+ *
32
+ * Both halves are needed and neither is redundant. The revision says *which*
33
+ * answer it has; the fingerprint proves it is that answer and not a different
34
+ * one wearing the same number — revisions restart at zero when a hub restarts or
35
+ * a key is released and re-acquired, so a bare revision would let a client keep
36
+ * a value from a previous life of the source and be told it was current.
37
+ */
38
+ export declare const WatchHaveSchema: z.ZodReadonly<z.ZodObject<{
39
+ revision: z.ZodNumber;
40
+ fingerprint: z.ZodString;
41
+ }, z.core.$strict>>;
42
+ export type WatchHave = z.infer<typeof WatchHaveSchema>;
29
43
  export declare const WatchOpenSchema: z.ZodReadonly<z.ZodObject<{
30
44
  key: z.ZodReadonly<z.ZodObject<{
31
45
  service: z.ZodString;
@@ -33,20 +47,46 @@ export declare const WatchOpenSchema: z.ZodReadonly<z.ZodObject<{
33
47
  digest: z.ZodString;
34
48
  }, z.core.$strict>>;
35
49
  args: z.ZodUnknown;
50
+ have: z.ZodOptional<z.ZodReadonly<z.ZodObject<{
51
+ revision: z.ZodNumber;
52
+ fingerprint: z.ZodString;
53
+ }, z.core.$strict>>>;
36
54
  }, z.core.$strip>>;
37
55
  export declare const WatchAcceptedSchema: z.ZodReadonly<z.ZodObject<{
38
56
  accepted: z.ZodBoolean;
39
57
  reason: z.ZodOptional<z.ZodString>;
40
58
  }, z.core.$strict>>;
41
- export declare const WatchValueSchema: z.ZodReadonly<z.ZodObject<{
59
+ export declare const WatchValueSchema: z.ZodDiscriminatedUnion<[z.ZodReadonly<z.ZodObject<{
42
60
  key: z.ZodReadonly<z.ZodObject<{
43
61
  service: z.ZodString;
44
62
  action: z.ZodString;
45
63
  digest: z.ZodString;
46
64
  }, z.core.$strict>>;
47
65
  revision: z.ZodNumber;
66
+ fingerprint: z.ZodString;
67
+ kind: z.ZodLiteral<"full">;
48
68
  value: z.ZodUnknown;
49
- }, z.core.$strip>>;
69
+ }, z.core.$strip>>, z.ZodReadonly<z.ZodObject<{
70
+ key: z.ZodReadonly<z.ZodObject<{
71
+ service: z.ZodString;
72
+ action: z.ZodString;
73
+ digest: z.ZodString;
74
+ }, z.core.$strict>>;
75
+ revision: z.ZodNumber;
76
+ fingerprint: z.ZodString;
77
+ kind: z.ZodLiteral<"delta">;
78
+ base: z.ZodNumber;
79
+ delta: z.ZodType<import("./watch-delta.js").WatchDelta, unknown, z.core.$ZodTypeInternals<import("./watch-delta.js").WatchDelta, unknown>>;
80
+ }, z.core.$strip>>, z.ZodReadonly<z.ZodObject<{
81
+ key: z.ZodReadonly<z.ZodObject<{
82
+ service: z.ZodString;
83
+ action: z.ZodString;
84
+ digest: z.ZodString;
85
+ }, z.core.$strict>>;
86
+ revision: z.ZodNumber;
87
+ fingerprint: z.ZodString;
88
+ kind: z.ZodLiteral<"unchanged">;
89
+ }, z.core.$strip>>], "kind">;
50
90
  export declare const WatchStateSchema: z.ZodReadonly<z.ZodObject<{
51
91
  key: z.ZodReadonly<z.ZodObject<{
52
92
  service: z.ZodString;
@@ -88,15 +128,37 @@ export declare const WATCH_STATE = "stitchkit.watch.state";
88
128
  export declare const watchContract: {
89
129
  readonly serverToClient: {
90
130
  readonly "stitchkit.watch.value": {
91
- readonly args: z.ZodTuple<[z.ZodReadonly<z.ZodObject<{
131
+ readonly args: z.ZodTuple<[z.ZodDiscriminatedUnion<[z.ZodReadonly<z.ZodObject<{
92
132
  key: z.ZodReadonly<z.ZodObject<{
93
133
  service: z.ZodString;
94
134
  action: z.ZodString;
95
135
  digest: z.ZodString;
96
136
  }, z.core.$strict>>;
97
137
  revision: z.ZodNumber;
138
+ fingerprint: z.ZodString;
139
+ kind: z.ZodLiteral<"full">;
98
140
  value: z.ZodUnknown;
99
- }, z.core.$strip>>], null>;
141
+ }, z.core.$strip>>, z.ZodReadonly<z.ZodObject<{
142
+ key: z.ZodReadonly<z.ZodObject<{
143
+ service: z.ZodString;
144
+ action: z.ZodString;
145
+ digest: z.ZodString;
146
+ }, z.core.$strict>>;
147
+ revision: z.ZodNumber;
148
+ fingerprint: z.ZodString;
149
+ kind: z.ZodLiteral<"delta">;
150
+ base: z.ZodNumber;
151
+ delta: z.ZodType<import("./watch-delta.js").WatchDelta, unknown, z.core.$ZodTypeInternals<import("./watch-delta.js").WatchDelta, unknown>>;
152
+ }, z.core.$strip>>, z.ZodReadonly<z.ZodObject<{
153
+ key: z.ZodReadonly<z.ZodObject<{
154
+ service: z.ZodString;
155
+ action: z.ZodString;
156
+ digest: z.ZodString;
157
+ }, z.core.$strict>>;
158
+ revision: z.ZodNumber;
159
+ fingerprint: z.ZodString;
160
+ kind: z.ZodLiteral<"unchanged">;
161
+ }, z.core.$strip>>], "kind">], null>;
100
162
  };
101
163
  readonly "stitchkit.watch.state": {
102
164
  readonly args: z.ZodTuple<[z.ZodReadonly<z.ZodObject<{
@@ -135,6 +197,10 @@ export declare const watchContract: {
135
197
  digest: z.ZodString;
136
198
  }, z.core.$strict>>;
137
199
  args: z.ZodUnknown;
200
+ have: z.ZodOptional<z.ZodReadonly<z.ZodObject<{
201
+ revision: z.ZodNumber;
202
+ fingerprint: z.ZodString;
203
+ }, z.core.$strict>>>;
138
204
  }, z.core.$strip>>], null>;
139
205
  readonly ack: z.ZodReadonly<z.ZodObject<{
140
206
  accepted: z.ZodBoolean;
@@ -1 +1 @@
1
- {"version":3,"file":"watch-contract.d.ts","sourceRoot":"","sources":["../../src/live/watch-contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,2FAA2F;AAC3F,eAAO,MAAM,cAAc;;;;mBAkBd,CAAC;AACd,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD,eAAO,MAAM,eAAe;;;;;;;kBAAkE,CAAC;AAE/F,eAAO,MAAM,mBAAmB;;;mBAOnB,CAAC;AAEd,eAAO,MAAM,gBAAgB;;;;;;;;kBAUhB,CAAC;AAEd,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;kBAShB,CAAC;AAEd,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC/D,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE/D,eAAO,MAAM,UAAU,yBAAyB,CAAC;AACjD,eAAO,MAAM,WAAW,0BAA0B,CAAC;AACnD,eAAO,MAAM,WAAW,0BAA0B,CAAC;AACnD,eAAO,MAAM,WAAW,0BAA0B,CAAC;AAEnD;;;;;;GAMG;AACH,eAAO,MAAM,aAAa;;;qBAEL,IAAI;;;;;;;;;;;qBACJ,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAGL,IAAI;;;;;;;;qBAA8B,GAAG;;;;;;qBACpC,IAAI;;;;;;;;;CAKxB,CAAC;AAEF,wEAAwE;AACxE,wBAAgB,cAAc,CAAC,GAAG,EAAE,QAAQ,GAAG,MAAM,CAEpD"}
1
+ {"version":3,"file":"watch-contract.d.ts","sourceRoot":"","sources":["../../src/live/watch-contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,2FAA2F;AAC3F,eAAO,MAAM,cAAc;;;;mBAkBd,CAAC;AACd,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe;;;mBAGf,CAAC;AACd,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAExD,eAAO,MAAM,eAAe;;;;;;;;;;;kBAEf,CAAC;AAEd,eAAO,MAAM,mBAAmB;;;mBAOnB,CAAC;AA6Bd,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAmB3B,CAAC;AAEH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;kBAShB,CAAC;AAEd,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC/D,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE/D,eAAO,MAAM,UAAU,yBAAyB,CAAC;AACjD,eAAO,MAAM,WAAW,0BAA0B,CAAC;AACnD,eAAO,MAAM,WAAW,0BAA0B,CAAC;AACnD,eAAO,MAAM,WAAW,0BAA0B,CAAC;AAEnD;;;;;;GAMG;AACH,eAAO,MAAM,aAAa;;;qBAEL,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBACJ,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAGL,IAAI;;;;;;;;;;;;qBAA8B,GAAG;;;;;;qBACpC,IAAI;;;;;;;;;CAKxB,CAAC;AAEF,wEAAwE;AACxE,wBAAgB,cAAc,CAAC,GAAG,EAAE,QAAQ,GAAG,MAAM,CAEpD"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * The difference between two answers to the same watched read.
3
+ *
4
+ * A watched read publishes the whole value on every change. For a small answer
5
+ * that is the right thing — a difference has its own overhead, and below a few
6
+ * hundred bytes the difference is the larger message. For a large one it is not:
7
+ * the case this exists for is a ~75 KB list answer in which two timestamps move,
8
+ * republished every fifteen seconds, which is a megabyte of socket per
9
+ * subscriber per minute to carry a hundred bytes of news.
10
+ *
11
+ * ## What it is, and what it deliberately is not
12
+ *
13
+ * It is a *structural* difference over parsed JSON: objects by changed and
14
+ * removed key, arrays by runs copied from the previous value plus the elements
15
+ * that are genuinely new. It is not a text diff and not a patch format from
16
+ * elsewhere (JSON Patch, RFC 7386 merge patch): both of those lose the one
17
+ * property this has to keep — an array that shifted by one element must cost one
18
+ * op, not N. RFC 7386 additionally cannot express removing an array element or
19
+ * distinguish `null` from "delete", and a watched read's value is arbitrary
20
+ * application JSON where both are ordinary.
21
+ *
22
+ * ## The rule that makes it safe to use
23
+ *
24
+ * **A difference that is not smaller than the value is not sent.** Every caller
25
+ * measures — {@link deltaWins} — because a difference can be larger: a list that
26
+ * was replaced wholesale produces one `put` per element plus the framing. There
27
+ * is no shape of value for which sending the delta is the only option, so the
28
+ * failure mode of a bad diff is a wasted comparison, never a bigger frame.
29
+ *
30
+ * ## Fidelity
31
+ *
32
+ * `apply(previous, diff(previous, next))` reconstructs `next` exactly, for every
33
+ * value that survives `JSON.parse(JSON.stringify(x))` — which is every value a
34
+ * contract read can return, because it crossed a socket to get here. The
35
+ * property test over random pairs is the standing proof; it is a property rather
36
+ * than examples because the interesting inputs are the ones nobody thinks to
37
+ * write down.
38
+ *
39
+ * → the hub applies this per subscriber (`application/watch-hub`), the client
40
+ * reassembles (`live/watch-client`).
41
+ */
42
+ import { z } from 'zod';
43
+ /** One step of rebuilding an array from the previous one. */
44
+ export type WatchArrayOp =
45
+ /** Take `count` elements from the previous array starting at `from`. */
46
+ {
47
+ readonly o: 'copy';
48
+ readonly from: number;
49
+ readonly count: number;
50
+ }
51
+ /** Take the element at `from` and apply a difference to it. */
52
+ | {
53
+ readonly o: 'patch';
54
+ readonly from: number;
55
+ readonly d: WatchDelta;
56
+ }
57
+ /** An element with no counterpart in the previous array. */
58
+ | {
59
+ readonly o: 'put';
60
+ readonly v: unknown;
61
+ };
62
+ /** The difference between two values. */
63
+ export type WatchDelta =
64
+ /** Replace wholesale — the two values have nothing to share. */
65
+ {
66
+ readonly t: 'set';
67
+ readonly v: unknown;
68
+ } | {
69
+ readonly t: 'obj';
70
+ /** Per changed or added key, the difference to apply to it. */
71
+ readonly set?: Readonly<Record<string, WatchDelta>>;
72
+ /** Keys present before and gone now. */
73
+ readonly drop?: readonly string[];
74
+ } | {
75
+ readonly t: 'arr';
76
+ readonly ops: readonly WatchArrayOp[];
77
+ };
78
+ export declare const WatchDeltaSchema: z.ZodType<WatchDelta>;
79
+ export declare const WatchArrayOpSchema: z.ZodType<WatchArrayOp>;
80
+ /**
81
+ * The difference from `previous` to `next`, or `undefined` when they are equal.
82
+ *
83
+ * `undefined` is a real answer and the caller must handle it: a re-read that
84
+ * produced the same bytes has no news in it, and the hub already declines to
85
+ * publish one. It is returned rather than an empty delta so that "nothing
86
+ * changed" cannot be confused with "everything at the top level was replaced by
87
+ * an empty object".
88
+ */
89
+ export declare function diff(previous: unknown, next: unknown): WatchDelta | undefined;
90
+ /**
91
+ * Rebuild the new value from the old one and a difference.
92
+ *
93
+ * **Throws when the difference does not fit the value it was given.** That is
94
+ * the contract, and the reason it is not a tolerant merge: a difference applied
95
+ * to the wrong base produces a plausible object that is not what the server
96
+ * holds, and a watched read whose face is quietly wrong is the exact failure the
97
+ * revision and the fingerprint exist to prevent. The caller catches and
98
+ * resynchronises that one key.
99
+ */
100
+ export declare function apply(previous: unknown, delta: WatchDelta): unknown;
101
+ /**
102
+ * Whether sending the difference actually saves anything.
103
+ *
104
+ * Measured on the encoded length of both, because that is what crosses the
105
+ * socket — a delta with fewer *nodes* can still be the longer message once its
106
+ * framing is written out. Ties go to the value: identical cost, one fewer thing
107
+ * that can go wrong at the other end.
108
+ */
109
+ export declare function deltaWins(delta: WatchDelta, value: unknown): boolean;
110
+ //# sourceMappingURL=watch-delta.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch-delta.d.ts","sourceRoot":"","sources":["../../src/live/watch-delta.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,6DAA6D;AAC7D,MAAM,MAAM,YAAY;AACtB,wEAAwE;AACtE;IAAE,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE;AACvE,+DAA+D;GAC7D;IAAE,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,CAAC,EAAE,UAAU,CAAA;CAAE;AACxE,4DAA4D;GAC1D;IAAE,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAE/C,yCAAyC;AACzC,MAAM,MAAM,UAAU;AACpB,gEAAgE;AAC9D;IAAE,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAA;CAAE,GAC1C;IACE,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC;IAClB,+DAA+D;IAC/D,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;IACpD,wCAAwC;IACxC,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC,GACD;IAAE,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,SAAS,YAAY,EAAE,CAAA;CAAE,CAAC;AAEjE,eAAO,MAAM,gBAAgB,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAUzB,CAAC;AAE3B,eAAO,MAAM,kBAAkB,EAAE,CAAC,CAAC,OAAO,CAAC,YAAY,CAc3B,CAAC;AAiB7B;;;;;;;;GAQG;AACH,wBAAgB,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,CAK7E;AAwGD;;;;;;;;;GASG;AACH,wBAAgB,KAAK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAqCnE;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAEpE"}
package/dist/live.d.ts CHANGED
@@ -14,5 +14,6 @@
14
14
  */
15
15
  export { defineEvents, type EventDeliveryMode, type EventPayloads, type EventsConfig, type EventsDeclaration, type EventTopicDeclaration, type EventTopicRegistry, type EventTopicsOfMode, type PolicyDecision, toRealtimeContract, type UndecidedOutcome, type WireTopic, } from './live/events.js';
16
16
  export { createWatchClient, type RealtimeClientLike, type TypedWatchClient, type WatchClientConfig, type WatchHandle, type WatchInboundEvents, type WatchListeners, type WatchTransport, watchTransport, } from './live/watch-client.js';
17
- export { WATCH_CLOSE, WATCH_OPEN, WATCH_STATE, WATCH_VALUE, type WatchKey, WatchKeySchema, type WatchStateFrame, WatchStateSchema, type WatchValueFrame, WatchValueSchema, watchContract, watchKeyString, } from './live/watch-contract.js';
17
+ export { WATCH_CLOSE, WATCH_OPEN, WATCH_STATE, WATCH_VALUE, type WatchHave, WatchHaveSchema, type WatchKey, WatchKeySchema, type WatchStateFrame, WatchStateSchema, type WatchValueFrame, WatchValueSchema, watchContract, watchKeyString, } from './live/watch-contract.js';
18
+ export { apply as applyWatchDelta, deltaWins as watchDeltaWins, diff as watchDiff, type WatchArrayOp, WatchArrayOpSchema, type WatchDelta, WatchDeltaSchema, } from './live/watch-delta.js';
18
19
  //# sourceMappingURL=live.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"live.d.ts","sourceRoot":"","sources":["../src/live.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EACL,YAAY,EACZ,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,kBAAkB,EAClB,KAAK,gBAAgB,EACrB,KAAK,SAAS,GACf,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,iBAAiB,EACjB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,cAAc,GACf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,WAAW,EACX,UAAU,EACV,WAAW,EACX,WAAW,EACX,KAAK,QAAQ,EACb,cAAc,EACd,KAAK,eAAe,EACpB,gBAAgB,EAChB,KAAK,eAAe,EACpB,gBAAgB,EAChB,aAAa,EACb,cAAc,GACf,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"live.d.ts","sourceRoot":"","sources":["../src/live.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EACL,YAAY,EACZ,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,kBAAkB,EAClB,KAAK,gBAAgB,EACrB,KAAK,SAAS,GACf,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,iBAAiB,EACjB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,cAAc,GACf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,WAAW,EACX,UAAU,EACV,WAAW,EACX,WAAW,EACX,KAAK,SAAS,EACd,eAAe,EACf,KAAK,QAAQ,EACb,cAAc,EACd,KAAK,eAAe,EACpB,gBAAgB,EAChB,KAAK,eAAe,EACpB,gBAAgB,EAChB,aAAa,EACb,cAAc,GACf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,KAAK,IAAI,eAAe,EACxB,SAAS,IAAI,cAAc,EAC3B,IAAI,IAAI,SAAS,EACjB,KAAK,YAAY,EACjB,kBAAkB,EAClB,KAAK,UAAU,EACf,gBAAgB,GACjB,MAAM,oBAAoB,CAAC"}
package/dist/live.js CHANGED
@@ -3,12 +3,18 @@ import {
3
3
  WATCH_OPEN,
4
4
  WATCH_STATE,
5
5
  WATCH_VALUE,
6
+ WatchArrayOpSchema,
7
+ WatchDeltaSchema,
8
+ WatchHaveSchema,
6
9
  WatchKeySchema,
7
10
  WatchStateSchema,
8
11
  WatchValueSchema,
12
+ apply,
13
+ deltaWins,
14
+ diff,
9
15
  watchContract,
10
16
  watchKeyString
11
- } from "./index-dre2ywck.js";
17
+ } from "./index-2na0qrfn.js";
12
18
  import"./index-ywd0y6m1.js";
13
19
  import"./index-7gnkny4z.js";
14
20
  import {
@@ -79,17 +85,56 @@ function createWatchClient(contract, config) {
79
85
  for (const listener of [...entry.listeners])
80
86
  listener.state?.(state);
81
87
  }
88
+ function resynchronise(entry, message) {
89
+ entry.hasValue = false;
90
+ entry.value = undefined;
91
+ entry.revision = 0;
92
+ entry.fingerprint = undefined;
93
+ entry.opened = false;
94
+ publishState(entry, { key: entry.key, phase: "resync-required", message });
95
+ config.transport.emit(WATCH_CLOSE, { key: entry.key });
96
+ open(entry);
97
+ }
82
98
  config.transport.on(WATCH_VALUE, (frame) => {
83
99
  const entry = entries.get(watchKeyString(frame.key));
84
100
  if (!entry)
85
101
  return;
102
+ if (frame.kind === "unchanged") {
103
+ if (!entry.hasValue) {
104
+ resynchronise(entry, "the server confirmed a value this client does not hold");
105
+ return;
106
+ }
107
+ entry.revision = frame.revision;
108
+ entry.fingerprint = frame.fingerprint;
109
+ return;
110
+ }
86
111
  if (entry.hasValue && frame.revision <= entry.revision)
87
112
  return;
113
+ let value;
114
+ if (frame.kind === "full") {
115
+ value = frame.value;
116
+ } else {
117
+ if (!entry.hasValue || entry.revision !== frame.base) {
118
+ resynchronise(entry, `a difference against revision ${frame.base} arrived while holding ${entry.hasValue ? String(entry.revision) : "nothing"}`);
119
+ return;
120
+ }
121
+ try {
122
+ value = apply(entry.value, frame.delta);
123
+ } catch (error) {
124
+ resynchronise(entry, error instanceof Error ? error.message : String(error));
125
+ return;
126
+ }
127
+ if (argumentsDigest({ value }) !== frame.fingerprint) {
128
+ resynchronise(entry, "the rebuilt value did not match the fingerprint the server sent");
129
+ return;
130
+ }
131
+ }
88
132
  entry.revision = frame.revision;
89
- entry.value = frame.value;
133
+ entry.value = value;
134
+ entry.fingerprint = frame.fingerprint;
90
135
  entry.hasValue = true;
91
136
  for (const listener of [...entry.listeners])
92
- listener.value(frame.value);
137
+ listener.value(value);
93
138
  });
94
139
  config.transport.on(WATCH_STATE, (frame) => {
95
140
  const entry = entries.get(watchKeyString(frame.key));
@@ -142,7 +187,8 @@ function createWatchClient(contract, config) {
142
187
  return;
143
188
  entry.opened = true;
144
189
  try {
145
- const acknowledgement = await config.transport.request(WATCH_OPEN, { key: entry.key, args: entry.args }, { timeoutMs: openTimeoutMs });
190
+ const have = entry.hasValue && entry.fingerprint !== undefined ? { revision: entry.revision, fingerprint: entry.fingerprint } : undefined;
191
+ const acknowledgement = await config.transport.request(WATCH_OPEN, { key: entry.key, args: entry.args, ...have !== undefined && { have } }, { timeoutMs: openTimeoutMs });
146
192
  if (!acknowledgement.accepted) {
147
193
  const reason = acknowledgement.reason ?? "the server refused this watch";
148
194
  config.onRefused?.(entry.key, reason);
@@ -216,13 +262,19 @@ function createWatchClient(contract, config) {
216
262
  export {
217
263
  watchTransport,
218
264
  watchKeyString,
265
+ diff as watchDiff,
266
+ deltaWins as watchDeltaWins,
219
267
  watchContract,
220
268
  toRealtimeContract,
221
269
  defineEvents,
222
270
  createWatchClient,
271
+ apply as applyWatchDelta,
223
272
  WatchValueSchema,
224
273
  WatchStateSchema,
225
274
  WatchKeySchema,
275
+ WatchHaveSchema,
276
+ WatchDeltaSchema,
277
+ WatchArrayOpSchema,
226
278
  WATCH_VALUE,
227
279
  WATCH_STATE,
228
280
  WATCH_OPEN,
package/dist/node.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  createHandler,
6
6
  createSocketIOServer,
7
7
  createUnixClientTransport
8
- } from "./index-vchzar7e.js";
8
+ } from "./index-db51n3xr.js";
9
9
  import"./index-y91ry9h2.js";
10
10
  import {
11
11
  ShutdownOptionsSchema,
@@ -14,7 +14,7 @@ import {
14
14
  ShutdownStatusSchema,
15
15
  createServerLifecycle
16
16
  } from "./index-3z73fh2c.js";
17
- import"./index-apn8repm.js";
17
+ import"./index-7gqx71yd.js";
18
18
  import"./index-2qzskm8h.js";
19
19
  import {
20
20
  createImplement,
@@ -24,11 +24,11 @@ import {
24
24
  createScopedImplementRegistry,
25
25
  implement,
26
26
  implementRegistry
27
- } from "./index-p18f59zy.js";
27
+ } from "./index-z78bjcxj.js";
28
28
  import"./index-vsbzgd7b.js";
29
29
  import"./index-f9mb610r.js";
30
- import"./index-7evdsyez.js";
31
- import"./index-2bxcmqkb.js";
30
+ import"./index-2hryh65w.js";
31
+ import"./index-kazec06k.js";
32
32
  import"./index-6k1937bx.js";
33
33
  import {
34
34
  AppError,
@@ -39,7 +39,7 @@ import {
39
39
  notFound,
40
40
  rateLimited,
41
41
  unauthorized
42
- } from "./index-0w9abg87.js";
42
+ } from "./index-scs3f1eg.js";
43
43
  import"./index-zcgf3gqf.js";
44
44
  import"./index-kzfs85xp.js";
45
45
  import"./index-77fekveh.js";
@@ -0,0 +1,55 @@
1
+ /**
2
+ * "Write the calls that changed something" — one filter, not six.
3
+ *
4
+ * Every project that audits eventually writes this predicate, and measured
5
+ * across six sibling consumers they had written six different ones: one audited
6
+ * only tool calls, one excluded `/mcp`, and two disagreed with each other on
7
+ * `OPTIONS`. Nobody decided any of that. They each started from the one form the
8
+ * `RequestEvent.httpMethod` doc gives — `(event.httpMethod ?? event.method) !==
9
+ * 'GET'` — which is right about `GET` and silent about the other two verbs that
10
+ * change nothing, and filled the gap from memory.
11
+ *
12
+ * That is the duplicated observability layer ADR 0012 exists to end, one level
13
+ * further in: the module owns the machinery, the project owns the policy. A
14
+ * predicate over a normalised event is machinery.
15
+ *
16
+ * ## The two rules, and why they are in this order
17
+ *
18
+ * **A security outcome is written whatever the verb was.** A rejected read is
19
+ * the single most interesting row in an audit table — it is how an attempt to
20
+ * reach something shows up at all — and a filter that drops every `GET` drops
21
+ * exactly that. This rule is first because it is the one a hand-written filter
22
+ * loses: the author is thinking about writes, and a refused read is not a write.
23
+ *
24
+ * **Then reads are dropped and everything else is kept.** Not "writes are kept":
25
+ * an unknown verb is kept, because the failure modes are not symmetric. An extra
26
+ * row costs bytes; a missing row costs the answer to "who changed this", and it
27
+ * costs it silently and only later, when the question is finally asked.
28
+ */
29
+ import type { RequestEvent } from './event.js';
30
+ /**
31
+ * Whether this call is worth an audit row: it changed something, or it was
32
+ * refused for a reason the audit exists to record.
33
+ *
34
+ * Hand it to a sink as its `filter`:
35
+ *
36
+ * ```ts
37
+ * createObservability({
38
+ * request: { write: (event) => db.audit.create({ data: event }), filter: auditChanges },
39
+ * tools: { write: (event) => db.audit.create({ data: event }), filter: auditChanges },
40
+ * });
41
+ * ```
42
+ *
43
+ * One filter for both surfaces on purpose. A tool call carries its contract verb
44
+ * in `httpMethod` while its `method` is the literal `TOOL` (→ ADR 0030), so the
45
+ * same predicate reads a write the same way whether it arrived over HTTP, MCP or
46
+ * an agent — which is what keeps one audit table queryable across all three.
47
+ *
48
+ * Narrower or wider policy stays the project's: compose it.
49
+ *
50
+ * ```ts
51
+ * filter: (event) => auditChanges(event) && event.serviceName !== 'health',
52
+ * ```
53
+ */
54
+ export declare function auditChanges(event: RequestEvent): boolean;
55
+ //# sourceMappingURL=changes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"changes.d.ts","sourceRoot":"","sources":["../../src/observability/changes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAuB5C;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAIzD"}
@@ -8,9 +8,11 @@
8
8
  */
9
9
  export { createDimensionsProjector, createObservability, type DimensionsProjector, type DimensionsProjectorConfig, type HttpRequestCompletion, type HttpRequestObserver, type Observability, type ObservabilityConfig, type ObservabilityDrainBound, type ProjectedDimensions, type RequestEventSinkConfig, type RequestObservabilityConfig, type SinkDrop, type SinkDropReason, type SinkError, } from './audit.js';
10
10
  export { type BoundedLoggerBounds, type BoundedLoggerOptions, createBoundedLogger, DEFAULT_REDACT_PATHS, } from './bounded-logger.js';
11
+ export { auditChanges } from './changes.js';
11
12
  export { type DimensionCollision, getRequestContext, getTraceId, getUserId, type RequestContext, runWithRequestContext, type SetRequestDimensionsOptions, setRequestDimensions, setRequestEndpoint, setRequestError, setRequestUser, type WrapRequestContextOptions, wrapInRequestContext, } from './context.js';
12
13
  export type { RequestEvent } from './event.js';
13
14
  export { type JsonValue, measureSize, redact, type SanitizeOptions, type SizeMeasure, sanitizePayload, truncatePreview, } from './sanitize.js';
15
+ export { createSpooledSink, type SpooledSink, type SpooledSinkConfig, type SpoolRecovery, } from './spool.js';
14
16
  export { type ObservabilityDrainReport, ObservabilityDrainReportSchema, type ObservabilitySinkStatus, ObservabilitySinkStatusSchema, type ObservabilityStatus, ObservabilityStatusSchema, } from './status.js';
15
17
  export { childSpan, createTraceContext, formatTraceparent, parseTraceparent, resolvePropagationContext, resolveTraceContext, type TraceContext, } from './trace.js';
16
18
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/observability/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EACL,yBAAyB,EACzB,mBAAmB,EACnB,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACxB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,0BAA0B,EAC/B,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,SAAS,GACf,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,KAAK,kBAAkB,EACvB,iBAAiB,EACjB,UAAU,EACV,SAAS,EACT,KAAK,cAAc,EACnB,qBAAqB,EACrB,KAAK,2BAA2B,EAChC,oBAAoB,EACpB,kBAAkB,EAClB,eAAe,EACf,cAAc,EACd,KAAK,yBAAyB,EAC9B,oBAAoB,GACrB,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EACL,KAAK,SAAS,EACd,WAAW,EACX,MAAM,EACN,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,eAAe,EACf,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,KAAK,wBAAwB,EAC7B,8BAA8B,EAC9B,KAAK,uBAAuB,EAC5B,6BAA6B,EAC7B,KAAK,mBAAmB,EACxB,yBAAyB,GAC1B,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,SAAS,EACT,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,yBAAyB,EACzB,mBAAmB,EACnB,KAAK,YAAY,GAClB,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/observability/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EACL,yBAAyB,EACzB,mBAAmB,EACnB,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACxB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,0BAA0B,EAC/B,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,SAAS,GACf,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EACL,KAAK,kBAAkB,EACvB,iBAAiB,EACjB,UAAU,EACV,SAAS,EACT,KAAK,cAAc,EACnB,qBAAqB,EACrB,KAAK,2BAA2B,EAChC,oBAAoB,EACpB,kBAAkB,EAClB,eAAe,EACf,cAAc,EACd,KAAK,yBAAyB,EAC9B,oBAAoB,GACrB,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EACL,KAAK,SAAS,EACd,WAAW,EACX,MAAM,EACN,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,eAAe,EACf,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,iBAAiB,EACjB,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,aAAa,GACnB,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,KAAK,wBAAwB,EAC7B,8BAA8B,EAC9B,KAAK,uBAAuB,EAC5B,6BAA6B,EAC7B,KAAK,mBAAmB,EACxB,yBAAyB,GAC1B,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,SAAS,EACT,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,yBAAyB,EACzB,mBAAmB,EACnB,KAAK,YAAY,GAClB,MAAM,SAAS,CAAC"}