apps 0.0.1-beta.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 (135) hide show
  1. package/README.md +191 -0
  2. package/check-publish.mjs +10 -0
  3. package/framework-reference.json +1 -0
  4. package/js/chunk-22WRQZT7.js +389 -0
  5. package/js/chunk-2OTCEKL2.js +29480 -0
  6. package/js/chunk-36DNRFZQ.js +34 -0
  7. package/js/chunk-3ANFZFCV.js +1799 -0
  8. package/js/chunk-7JXHF5IF.js +138 -0
  9. package/js/chunk-BCSNKUAC.js +0 -0
  10. package/js/chunk-BKVL7XAJ.js +47 -0
  11. package/js/chunk-BPEFS4YF.js +1323 -0
  12. package/js/chunk-C24KEZXR.js +59 -0
  13. package/js/chunk-D6BKYP2L.js +877 -0
  14. package/js/chunk-EP6AEUZO.js +19 -0
  15. package/js/chunk-HP7E42X6.js +1719 -0
  16. package/js/chunk-KWTCHVLT.js +284 -0
  17. package/js/chunk-LOKGDT6B.js +28 -0
  18. package/js/chunk-MLKGABMK.js +9 -0
  19. package/js/chunk-OWD2YICM.js +2486 -0
  20. package/js/chunk-Q2FD5IBM.js +899 -0
  21. package/js/chunk-R6JMJSVT.js +590 -0
  22. package/js/chunk-SBKHUC5L.js +56 -0
  23. package/js/chunk-VFUZI3NY.js +75 -0
  24. package/js/chunk-W7Q5EOTS.js +4375 -0
  25. package/js/chunk-WIDTG42X.js +171 -0
  26. package/js/chunk-X3YBZCJW.js +246 -0
  27. package/js/chunk-YDR4CPJA.js +2357 -0
  28. package/js/client.js +1023 -0
  29. package/js/contracts.js +163 -0
  30. package/js/effect.js +44 -0
  31. package/js/graphql.js +392 -0
  32. package/js/host.js +193 -0
  33. package/js/index.js +284 -0
  34. package/js/mcp/effect.js +23 -0
  35. package/js/mcp/stdio.js +123 -0
  36. package/js/mcp.js +37 -0
  37. package/js/openapi.js +246 -0
  38. package/js/operations/approval.js +9 -0
  39. package/js/react.js +37 -0
  40. package/js/storage/facet.js +546 -0
  41. package/js/ui/auth/contracts.js +19 -0
  42. package/js/ui/auth.js +28 -0
  43. package/js/ui/contracts.js +24 -0
  44. package/js/ui/serving.js +286 -0
  45. package/package.json +116 -0
  46. package/runtime.json +1 -0
  47. package/types/app-data/src/contracts/database.d.ts +193 -0
  48. package/types/app-data/src/implementation/cursor.d.ts +10 -0
  49. package/types/app-data/src/implementation/index-key.d.ts +7 -0
  50. package/types/app-data/src/implementation/promise.d.ts +68 -0
  51. package/types/app-data/src/implementation/range.d.ts +8 -0
  52. package/types/app-data/src/implementation/schema.d.ts +33 -0
  53. package/types/app-data/src/implementation/sqlite.d.ts +11 -0
  54. package/types/app-data/src/index.d.ts +4 -0
  55. package/types/apps/src/approval.d.ts +10 -0
  56. package/types/apps/src/client.d.ts +5 -0
  57. package/types/apps/src/contracts/app.d.ts +58 -0
  58. package/types/apps/src/contracts/approval.d.ts +14 -0
  59. package/types/apps/src/contracts/context.d.ts +25 -0
  60. package/types/apps/src/contracts/elicitation.d.ts +86 -0
  61. package/types/apps/src/contracts/graphql.d.ts +102 -0
  62. package/types/apps/src/contracts/host.d.ts +568 -0
  63. package/types/apps/src/contracts/http.d.ts +20 -0
  64. package/types/apps/src/contracts/live.d.ts +26 -0
  65. package/types/apps/src/contracts/mcp.d.ts +93 -0
  66. package/types/apps/src/contracts/openapi.d.ts +105 -0
  67. package/types/apps/src/contracts/operations.d.ts +30 -0
  68. package/types/apps/src/contracts/optimistic.d.ts +22 -0
  69. package/types/apps/src/contracts/provider.d.ts +96 -0
  70. package/types/apps/src/contracts/schedules.d.ts +51 -0
  71. package/types/apps/src/contracts/schema.d.ts +20 -0
  72. package/types/apps/src/contracts/storage.d.ts +68 -0
  73. package/types/apps/src/contracts/tools.d.ts +11 -0
  74. package/types/apps/src/contracts/ui-auth.d.ts +28 -0
  75. package/types/apps/src/contracts/ui.d.ts +90 -0
  76. package/types/apps/src/contracts/webhook-protocol.d.ts +102 -0
  77. package/types/apps/src/contracts/webhooks.d.ts +53 -0
  78. package/types/apps/src/contracts/workflows.d.ts +277 -0
  79. package/types/apps/src/effect.d.ts +10 -0
  80. package/types/apps/src/facet.d.ts +5 -0
  81. package/types/apps/src/graphql.d.ts +10 -0
  82. package/types/apps/src/host.d.ts +16 -0
  83. package/types/apps/src/implementation/account-operations.d.ts +32 -0
  84. package/types/apps/src/implementation/app.d.ts +40 -0
  85. package/types/apps/src/implementation/authoring.d.ts +12 -0
  86. package/types/apps/src/implementation/elicitation.d.ts +103 -0
  87. package/types/apps/src/implementation/graphql.d.ts +5 -0
  88. package/types/apps/src/implementation/host.d.ts +3 -0
  89. package/types/apps/src/implementation/http.d.ts +5 -0
  90. package/types/apps/src/implementation/live.d.ts +18 -0
  91. package/types/apps/src/implementation/mcp-call.d.ts +19 -0
  92. package/types/apps/src/implementation/mcp-client.d.ts +50 -0
  93. package/types/apps/src/implementation/mcp-stdio.d.ts +4 -0
  94. package/types/apps/src/implementation/mcp-tools.d.ts +6 -0
  95. package/types/apps/src/implementation/mcp.d.ts +4 -0
  96. package/types/apps/src/implementation/openapi-request.d.ts +11 -0
  97. package/types/apps/src/implementation/openapi.d.ts +5 -0
  98. package/types/apps/src/implementation/operations.d.ts +65 -0
  99. package/types/apps/src/implementation/optimistic.d.ts +30 -0
  100. package/types/apps/src/implementation/protocol-operations.d.ts +24 -0
  101. package/types/apps/src/implementation/provider.d.ts +16 -0
  102. package/types/apps/src/implementation/query-commit.d.ts +10 -0
  103. package/types/apps/src/implementation/schedules.d.ts +16 -0
  104. package/types/apps/src/implementation/schema.d.ts +93 -0
  105. package/types/apps/src/implementation/storage.d.ts +13 -0
  106. package/types/apps/src/implementation/ui-auth.d.ts +13 -0
  107. package/types/apps/src/implementation/ui-client.d.ts +16 -0
  108. package/types/apps/src/implementation/ui-errors.d.ts +2 -0
  109. package/types/apps/src/implementation/ui-serving.d.ts +16 -0
  110. package/types/apps/src/implementation/ui-watch.d.ts +2 -0
  111. package/types/apps/src/implementation/webhooks.d.ts +29 -0
  112. package/types/apps/src/implementation/workflow-context.d.ts +8 -0
  113. package/types/apps/src/implementation/workflow-rpc.d.ts +5 -0
  114. package/types/apps/src/implementation/workflows.d.ts +27 -0
  115. package/types/apps/src/index.d.ts +58 -0
  116. package/types/apps/src/mcp-stdio.d.ts +8 -0
  117. package/types/apps/src/mcp.d.ts +10 -0
  118. package/types/apps/src/openapi.d.ts +10 -0
  119. package/types/apps/src/react.d.ts +7 -0
  120. package/types/apps/src/ui-auth.d.ts +3 -0
  121. package/types/apps/src/ui-serving.d.ts +3 -0
  122. package/types/telemetry/src/browser-operations.d.ts +16 -0
  123. package/types/telemetry/src/browser-performance.d.ts +11 -0
  124. package/types/telemetry/src/browser-request-timing.d.ts +2 -0
  125. package/types/telemetry/src/browser.d.ts +27 -0
  126. package/types/telemetry/src/config.d.ts +83 -0
  127. package/types/telemetry/src/context.d.ts +14 -0
  128. package/types/telemetry/src/index.d.ts +9 -0
  129. package/types/telemetry/src/layer.d.ts +7 -0
  130. package/types/telemetry/src/measurements.d.ts +8 -0
  131. package/types/telemetry/src/pending-span.d.ts +7 -0
  132. package/types/telemetry/src/relay.d.ts +28 -0
  133. package/types/telemetry/src/span-attributes.d.ts +29 -0
  134. package/types/telemetry/src/trace-context.d.ts +20 -0
  135. package/types/telemetry/src/transport.d.ts +6 -0
package/js/client.js ADDED
@@ -0,0 +1,1023 @@
1
+ import {
2
+ AppUiApi,
3
+ HttpApiClient_exports,
4
+ UiContext,
5
+ UiDeploymentChanged,
6
+ UiFailed
7
+ } from "./chunk-3ANFZFCV.js";
8
+ import {
9
+ AsyncResult_exports,
10
+ AtomRegistry_exports,
11
+ Atom_exports,
12
+ queryResult
13
+ } from "./chunk-YDR4CPJA.js";
14
+ import "./chunk-D6BKYP2L.js";
15
+ import {
16
+ OtlpExporter_exports,
17
+ TraceContext,
18
+ externalTrace,
19
+ pendingSpan,
20
+ telemetryLayer,
21
+ traceLinks
22
+ } from "./chunk-OWD2YICM.js";
23
+ import {
24
+ FetchHttpClient_exports
25
+ } from "./chunk-VFUZI3NY.js";
26
+ import {
27
+ HttpClientError_exports
28
+ } from "./chunk-W7Q5EOTS.js";
29
+ import {
30
+ decoderOf
31
+ } from "./chunk-BPEFS4YF.js";
32
+ import {
33
+ StorageName
34
+ } from "./chunk-EP6AEUZO.js";
35
+ import {
36
+ JsonValue
37
+ } from "./chunk-36DNRFZQ.js";
38
+ import {
39
+ Cause_exports,
40
+ Clock_exports,
41
+ Context_exports,
42
+ Deferred_exports,
43
+ Effect_exports,
44
+ Exit_exports,
45
+ FiberSet_exports,
46
+ Layer_exports,
47
+ Logger_exports,
48
+ ManagedRuntime_exports,
49
+ Option_exports,
50
+ Schedule_exports,
51
+ Schema_exports,
52
+ Semaphore_exports,
53
+ Stream_exports,
54
+ Tracer_exports
55
+ } from "./chunk-2OTCEKL2.js";
56
+ import "./chunk-MLKGABMK.js";
57
+
58
+ // src/contracts/live.ts
59
+ var AppQueryFailed = class extends Schema_exports.TaggedError()("AppQueryFailed", {}) {
60
+ };
61
+
62
+ // src/implementation/live.ts
63
+ var queryReference = (name) => ({
64
+ name: Schema_exports.decodeUnknownSync(StorageName)(name),
65
+ kind: "query"
66
+ });
67
+ var mutationReference = (name) => ({
68
+ name: Schema_exports.decodeUnknownSync(StorageName)(name),
69
+ kind: "mutation"
70
+ });
71
+ var liveQueryAtom = (reference, input, options) => Atom_exports.make(
72
+ Stream_exports.unwrap(
73
+ Effect_exports.gen(function* () {
74
+ const parsed = yield* Schema_exports.decodeUnknownEffect(JsonValue)(input).pipe(
75
+ Effect_exports.mapError(() => new AppQueryFailed())
76
+ );
77
+ const iterable = yield* Effect_exports.tryPromise({
78
+ try: () => options.transport.subscribe({ name: reference.name, input: parsed }),
79
+ catch: () => new AppQueryFailed()
80
+ });
81
+ return Stream_exports.fromAsyncIterable(iterable, () => new AppQueryFailed()).pipe(
82
+ Stream_exports.mapEffect(
83
+ (value) => Schema_exports.decodeUnknownEffect(decoderOf(options.output))(value).pipe(
84
+ Effect_exports.mapError(() => new AppQueryFailed())
85
+ )
86
+ )
87
+ );
88
+ })
89
+ )
90
+ );
91
+
92
+ // ../telemetry/src/browser-request-timing.ts
93
+ var milliseconds = Schema_exports.Number.check(Schema_exports.isFinite(), Schema_exports.isGreaterThanOrEqualTo(0));
94
+ var Entry = Schema_exports.Struct({
95
+ name: Schema_exports.String,
96
+ startTime: milliseconds,
97
+ duration: milliseconds,
98
+ domainLookupStart: milliseconds,
99
+ domainLookupEnd: milliseconds,
100
+ connectStart: milliseconds,
101
+ connectEnd: milliseconds,
102
+ secureConnectionStart: milliseconds,
103
+ requestStart: milliseconds,
104
+ responseStart: milliseconds,
105
+ responseEnd: milliseconds,
106
+ deliveryType: Schema_exports.optional(Schema_exports.String),
107
+ transferSize: Schema_exports.optional(milliseconds),
108
+ decodedBodySize: Schema_exports.optional(milliseconds),
109
+ serverTiming: Schema_exports.Array(
110
+ Schema_exports.Struct({
111
+ name: Schema_exports.String,
112
+ description: Schema_exports.String,
113
+ duration: milliseconds
114
+ })
115
+ )
116
+ });
117
+ var decode = Schema_exports.decodeUnknownOption(Entry);
118
+ var browserRequestTiming = (entry, origin) => {
119
+ const parsed = decode(entry);
120
+ if (Option_exports.isNone(parsed)) return;
121
+ const value = parsed.value;
122
+ if (value.deliveryType === "cache" || value.transferSize === 0 && value.decodedBodySize !== void 0 && value.decodedBodySize > 0)
123
+ return;
124
+ if (!URL.canParse(value.name)) return;
125
+ const url = new URL(value.name);
126
+ if (url.origin !== origin || /\/api\/telemetry\/(traces|logs)\/?$/.test(url.pathname)) return;
127
+ const trace = value.serverTiming.find((timing) => timing.name === "executor-trace")?.description;
128
+ if (trace === void 0 || !/^[a-f0-9]{32}$/.test(trace)) return;
129
+ const attributes = {
130
+ "executor.trace_id": trace,
131
+ "browser.request.duration_ms": value.duration
132
+ };
133
+ const span = value.serverTiming.find((timing) => timing.name === "executor-span")?.description;
134
+ if (span !== void 0 && /^(?!0{16}$)[a-f0-9]{16}$/.test(span))
135
+ attributes["executor.span_id"] = span;
136
+ const sampled = value.serverTiming.find(
137
+ (timing) => timing.name === "executor-sampled"
138
+ )?.description;
139
+ if (sampled === "1" || sampled === "0") attributes["executor.trace_sampled"] = Number(sampled);
140
+ const ray = value.serverTiming.find((timing) => timing.name === "cf-ray")?.description;
141
+ if (ray !== void 0 && /^[a-f0-9]{16,32}(?:-[A-Z]{3})?$/i.test(ray))
142
+ attributes["cloudflare.ray_id"] = ray.replace(/-[A-Z]{3}$/i, "");
143
+ const phase = (name, start, end) => {
144
+ if (start > 0 && end >= start) attributes[`browser.request.${name}_ms`] = end - start;
145
+ };
146
+ phase("dns", value.domainLookupStart, value.domainLookupEnd);
147
+ phase("connection", value.connectStart, value.connectEnd);
148
+ phase("tls", value.secureConnectionStart, value.connectEnd);
149
+ phase("waiting_for_headers", value.requestStart, value.responseStart);
150
+ phase("body", value.responseStart, value.responseEnd);
151
+ if (value.responseStart > 0 && value.responseStart >= value.startTime)
152
+ attributes["browser.request.time_to_first_byte_ms"] = value.responseStart - value.startTime;
153
+ const handler = value.serverTiming.find((timing) => timing.name === "executor");
154
+ if (handler !== void 0) attributes["executor.handler.duration_ms"] = handler.duration;
155
+ return attributes;
156
+ };
157
+
158
+ // ../telemetry/src/browser-performance.ts
159
+ var layoutShift = Schema_exports.decodeUnknownOption(
160
+ Schema_exports.Struct({ value: Schema_exports.Number, hadRecentInput: Schema_exports.Boolean })
161
+ );
162
+ var eventTiming = Schema_exports.decodeUnknownOption(
163
+ Schema_exports.Struct({
164
+ interactionId: Schema_exports.Number,
165
+ processingStart: Schema_exports.Number,
166
+ processingEnd: Schema_exports.Number
167
+ })
168
+ );
169
+ var eventDurationThreshold = 104;
170
+ var observeBrowserPerformance = Effect_exports.gen(function* () {
171
+ const clock = window.performance;
172
+ if (clock === void 0 || typeof PerformanceObserver === "undefined") {
173
+ return {
174
+ flush: Effect_exports.void,
175
+ pause: Effect_exports.void,
176
+ resume: Effect_exports.void,
177
+ hide: Effect_exports.void,
178
+ restore: Effect_exports.void,
179
+ navigation: (_path) => Effect_exports.void
180
+ };
181
+ }
182
+ let pagePath = window.location.pathname;
183
+ const observers = /* @__PURE__ */ new Map();
184
+ const supported = /* @__PURE__ */ new Set();
185
+ let path = pagePath;
186
+ let generation = 0;
187
+ let since = 0;
188
+ let pageStart = 0;
189
+ let active = document.visibilityState !== "hidden";
190
+ let firstHidden = active ? Infinity : 0;
191
+ let connected = true;
192
+ let paint;
193
+ let largestPaint;
194
+ let lastPaint;
195
+ let lastLargestPaint;
196
+ let largestPaintFinished = false;
197
+ let cls = 0;
198
+ let lastCls;
199
+ let shiftWindowStart = 0;
200
+ let shiftWindowEnd = 0;
201
+ let shiftWindowValue = 0;
202
+ let longTasks = { count: 0, duration: 0, blocking: 0, max: 0 };
203
+ let interactions = { count: 0, duration: 0, inputDelay: 0, processing: 0 };
204
+ const run = yield* FiberSet_exports.makeRuntime();
205
+ const report = (name, attributes) => Effect_exports.logInfo(name).pipe(
206
+ Effect_exports.annotateLogs(attributes),
207
+ Effect_exports.withSpan(name, {
208
+ root: true,
209
+ attributes,
210
+ links: traceLinks(
211
+ {
212
+ traceId: attributes["executor.trace_id"],
213
+ spanId: attributes["executor.span_id"],
214
+ sampled: attributes["executor.trace_sampled"] === void 0 ? void 0 : attributes["executor.trace_sampled"] === 1
215
+ },
216
+ "request-timing"
217
+ )
218
+ })
219
+ );
220
+ const record = (entries) => {
221
+ for (const entry of entries) {
222
+ if (entry.startTime < pageStart) continue;
223
+ switch (entry.entryType) {
224
+ case "resource": {
225
+ const attributes = browserRequestTiming(entry, window.location.origin);
226
+ if (attributes !== void 0) run(report("ui.request.timing", attributes));
227
+ break;
228
+ }
229
+ case "paint":
230
+ if (entry.name === "first-contentful-paint" && entry.startTime < firstHidden) {
231
+ paint = entry.startTime;
232
+ }
233
+ break;
234
+ case "largest-contentful-paint":
235
+ if (!largestPaintFinished && entry.startTime < firstHidden) {
236
+ largestPaint = entry.startTime;
237
+ }
238
+ break;
239
+ case "layout-shift": {
240
+ const parsed = layoutShift(entry);
241
+ if (!active || Option_exports.isNone(parsed) || parsed.value.hadRecentInput) break;
242
+ const value = parsed.value.value;
243
+ if (!Number.isFinite(value) || value < 0) break;
244
+ if (shiftWindowValue > 0 && entry.startTime - shiftWindowEnd < 1e3 && entry.startTime - shiftWindowStart < 5e3) {
245
+ shiftWindowValue += value;
246
+ } else {
247
+ shiftWindowStart = entry.startTime;
248
+ shiftWindowValue = value;
249
+ }
250
+ shiftWindowEnd = entry.startTime;
251
+ cls = Math.max(cls, shiftWindowValue);
252
+ break;
253
+ }
254
+ case "longtask":
255
+ if (active) {
256
+ longTasks.count += 1;
257
+ longTasks.duration += entry.duration;
258
+ longTasks.blocking += Math.max(0, entry.duration - 50);
259
+ longTasks.max = Math.max(longTasks.max, entry.duration);
260
+ }
261
+ break;
262
+ case "event": {
263
+ const parsed = eventTiming(entry);
264
+ if (!active || Option_exports.isNone(parsed) || parsed.value.interactionId === 0) break;
265
+ interactions.count += 1;
266
+ interactions.duration = Math.max(interactions.duration, entry.duration);
267
+ interactions.inputDelay = Math.max(
268
+ interactions.inputDelay,
269
+ parsed.value.processingStart - entry.startTime
270
+ );
271
+ interactions.processing = Math.max(
272
+ interactions.processing,
273
+ parsed.value.processingEnd - parsed.value.processingStart
274
+ );
275
+ break;
276
+ }
277
+ }
278
+ }
279
+ };
280
+ const drain = () => {
281
+ for (const observer of observers.values()) record(observer.takeRecords());
282
+ };
283
+ const disconnect = () => {
284
+ for (const observer of observers.values()) observer.disconnect();
285
+ observers.clear();
286
+ };
287
+ const observe = (buffered) => {
288
+ for (const type of [
289
+ "paint",
290
+ "largest-contentful-paint",
291
+ "layout-shift",
292
+ "longtask",
293
+ "event",
294
+ "resource"
295
+ ]) {
296
+ if (!PerformanceObserver.supportedEntryTypes?.includes(type)) continue;
297
+ const observer = new PerformanceObserver((list) => record(list.getEntries()));
298
+ try {
299
+ observer.observe({
300
+ type,
301
+ buffered,
302
+ ...type === "event" ? { durationThreshold: eventDurationThreshold } : {}
303
+ });
304
+ supported.add(type);
305
+ observers.set(type, observer);
306
+ } catch {
307
+ observer.disconnect();
308
+ }
309
+ }
310
+ };
311
+ observe(true);
312
+ const flush = Effect_exports.gen(function* () {
313
+ drain();
314
+ const common = {
315
+ "browser.page.time_origin_ms": clock.timeOrigin,
316
+ "browser.page.restore_count": generation
317
+ };
318
+ const measurements = [];
319
+ const vital = (name, value, unit) => {
320
+ measurements.push({
321
+ name: "ui.performance.vital",
322
+ attributes: {
323
+ ...common,
324
+ "url.path": pagePath,
325
+ "browser.vital.name": name,
326
+ "browser.vital.value": value,
327
+ "browser.vital.unit": unit
328
+ }
329
+ });
330
+ };
331
+ if (paint !== void 0 && paint !== lastPaint) {
332
+ vital("FCP", paint, "ms");
333
+ lastPaint = paint;
334
+ }
335
+ if (largestPaint !== void 0 && largestPaint !== lastLargestPaint) {
336
+ vital("LCP", largestPaint, "ms");
337
+ lastLargestPaint = largestPaint;
338
+ }
339
+ if (supported.has("layout-shift") && (paint !== void 0 || generation > 0) && cls !== lastCls) {
340
+ vital("CLS", cls, "1");
341
+ lastCls = cls;
342
+ }
343
+ const now = clock.now();
344
+ const window2 = { ...common, "url.path": path, "browser.observation.duration_ms": now - since };
345
+ if (longTasks.count > 0) {
346
+ measurements.push({
347
+ name: "ui.performance.long-tasks",
348
+ attributes: {
349
+ ...window2,
350
+ "browser.long_task.count": longTasks.count,
351
+ "browser.long_task.duration_ms": longTasks.duration,
352
+ "browser.long_task.blocking_ms": longTasks.blocking,
353
+ "browser.long_task.max_duration_ms": longTasks.max
354
+ }
355
+ });
356
+ }
357
+ if (interactions.count > 0) {
358
+ measurements.push({
359
+ name: "ui.performance.interactions",
360
+ attributes: {
361
+ ...window2,
362
+ "browser.interaction.slow_event_count": interactions.count,
363
+ "browser.interaction.max_duration_ms": interactions.duration,
364
+ "browser.interaction.max_input_delay_ms": interactions.inputDelay,
365
+ "browser.interaction.max_processing_ms": interactions.processing,
366
+ "browser.interaction.duration_threshold_ms": eventDurationThreshold
367
+ }
368
+ });
369
+ }
370
+ since = now;
371
+ longTasks = { count: 0, duration: 0, blocking: 0, max: 0 };
372
+ interactions = { count: 0, duration: 0, inputDelay: 0, processing: 0 };
373
+ yield* Effect_exports.forEach(
374
+ measurements,
375
+ (measurement) => report(measurement.name, measurement.attributes)
376
+ );
377
+ });
378
+ const stopLargestPaint = () => {
379
+ drain();
380
+ largestPaintFinished = true;
381
+ observers.get("largest-contentful-paint")?.disconnect();
382
+ observers.delete("largest-contentful-paint");
383
+ };
384
+ window.addEventListener("keydown", stopLargestPaint, { capture: true });
385
+ window.addEventListener("pointerdown", stopLargestPaint, { capture: true });
386
+ yield* Effect_exports.addFinalizer(
387
+ () => flush.pipe(
388
+ Effect_exports.ensuring(
389
+ Effect_exports.sync(() => {
390
+ disconnect();
391
+ window.removeEventListener("keydown", stopLargestPaint, { capture: true });
392
+ window.removeEventListener("pointerdown", stopLargestPaint, { capture: true });
393
+ })
394
+ )
395
+ )
396
+ );
397
+ yield* report("ui.performance.support", {
398
+ "browser.performance.paint": supported.has("paint"),
399
+ "browser.performance.largest_contentful_paint": supported.has("largest-contentful-paint"),
400
+ "browser.performance.layout_shift": supported.has("layout-shift"),
401
+ "browser.performance.long_task": supported.has("longtask"),
402
+ "browser.performance.event_timing": supported.has("event")
403
+ });
404
+ yield* flush.pipe(Effect_exports.repeat(Schedule_exports.spaced("30 seconds")), Effect_exports.forkScoped);
405
+ return {
406
+ flush,
407
+ pause: Effect_exports.sync(() => {
408
+ drain();
409
+ firstHidden = Math.min(firstHidden, clock.now());
410
+ stopLargestPaint();
411
+ active = false;
412
+ }),
413
+ resume: Effect_exports.sync(() => {
414
+ drain();
415
+ active = connected;
416
+ since = clock.now();
417
+ }),
418
+ hide: Effect_exports.sync(() => {
419
+ drain();
420
+ connected = false;
421
+ active = false;
422
+ disconnect();
423
+ }),
424
+ restore: Effect_exports.sync(() => {
425
+ disconnect();
426
+ generation += 1;
427
+ pageStart = clock.now();
428
+ pagePath = window.location.pathname;
429
+ since = pageStart;
430
+ paint = lastPaint = largestPaint = lastLargestPaint = void 0;
431
+ largestPaintFinished = false;
432
+ cls = shiftWindowStart = shiftWindowEnd = shiftWindowValue = 0;
433
+ lastCls = void 0;
434
+ connected = true;
435
+ active = document.visibilityState !== "hidden";
436
+ firstHidden = active ? Infinity : pageStart;
437
+ longTasks = { count: 0, duration: 0, blocking: 0, max: 0 };
438
+ interactions = { count: 0, duration: 0, inputDelay: 0, processing: 0 };
439
+ observe(false);
440
+ }),
441
+ navigation: (nextPath) => flush.pipe(
442
+ Effect_exports.andThen(
443
+ Effect_exports.sync(() => {
444
+ path = nextPath;
445
+ })
446
+ )
447
+ )
448
+ };
449
+ });
450
+
451
+ // ../telemetry/src/browser-operations.ts
452
+ var BrowserOperationFailure = Schema_exports.Struct({
453
+ error_type: Schema_exports.Literals([
454
+ "BrowserDecodeFailed",
455
+ "BrowserTransportFailed",
456
+ "BrowserOperationFailed"
457
+ ]),
458
+ trace_id: TraceContext.fields.traceId,
459
+ span_id: TraceContext.fields.spanId,
460
+ page_id: Schema_exports.String
461
+ });
462
+ var ResponseTrace = Context_exports.Reference("telemetry/ResponseTrace", {
463
+ defaultValue: () => void 0
464
+ });
465
+
466
+ // ../telemetry/src/browser.ts
467
+ var BrowserTelemetry = class extends Context_exports.Service()("executor/BrowserTelemetry") {
468
+ };
469
+ var browserTelemetryLayer = (settings) => Layer_exports.unwrap(
470
+ settings.pipe(
471
+ Effect_exports.map(
472
+ (config) => Layer_exports.effect(
473
+ BrowserTelemetry,
474
+ Effect_exports.gen(function* () {
475
+ const flusher = yield* OtlpExporter_exports.Flusher;
476
+ const run = yield* FiberSet_exports.makeRuntime();
477
+ let navigation;
478
+ const performance = yield* observeBrowserPerformance;
479
+ const flush = performance.flush.pipe(
480
+ Effect_exports.andThen(flusher.flush),
481
+ Effect_exports.timeoutOption("2 seconds"),
482
+ Effect_exports.asVoid
483
+ );
484
+ const error = (name, value) => run(
485
+ Effect_exports.logError(Cause_exports.die(value)).pipe(
486
+ Effect_exports.andThen(Effect_exports.fail(value)),
487
+ Effect_exports.withSpan(name),
488
+ Effect_exports.ignore
489
+ )
490
+ );
491
+ const onError = (event) => error("ui.error", event.error ?? new Error(event.message));
492
+ const onRejection = (event) => error("ui.unhandled-rejection", event.reason);
493
+ const onHidden = () => {
494
+ run(
495
+ document.visibilityState === "hidden" ? performance.pause.pipe(Effect_exports.andThen(flush)) : performance.resume
496
+ );
497
+ };
498
+ const onHide = () => {
499
+ run(performance.hide.pipe(Effect_exports.andThen(flush)));
500
+ };
501
+ const onShow = (event) => {
502
+ if (event.persisted) run(performance.restore);
503
+ };
504
+ window.addEventListener("error", onError);
505
+ window.addEventListener("unhandledrejection", onRejection);
506
+ window.addEventListener("pagehide", onHide);
507
+ window.addEventListener("pageshow", onShow);
508
+ document.addEventListener("visibilitychange", onHidden);
509
+ yield* Effect_exports.addFinalizer(
510
+ () => Effect_exports.sync(() => {
511
+ window.removeEventListener("error", onError);
512
+ window.removeEventListener("unhandledrejection", onRejection);
513
+ window.removeEventListener("pagehide", onHide);
514
+ window.removeEventListener("pageshow", onShow);
515
+ document.removeEventListener("visibilitychange", onHidden);
516
+ })
517
+ );
518
+ return {
519
+ flush,
520
+ navigation: (event) => Effect_exports.sync(() => {
521
+ if (event.type === "end") {
522
+ if (navigation !== void 0) Deferred_exports.doneUnsafe(navigation, Effect_exports.void);
523
+ navigation = void 0;
524
+ return;
525
+ }
526
+ if (navigation !== void 0) Deferred_exports.doneUnsafe(navigation, Effect_exports.interrupt);
527
+ navigation = Deferred_exports.makeUnsafe();
528
+ run(
529
+ Deferred_exports.await(navigation).pipe(
530
+ Effect_exports.withSpan("ui.navigation", {
531
+ root: true,
532
+ attributes: { "url.path": event.path }
533
+ }),
534
+ Effect_exports.ignore
535
+ )
536
+ );
537
+ }).pipe(
538
+ Effect_exports.andThen(
539
+ event.type === "start" ? performance.navigation(event.path) : Effect_exports.void
540
+ )
541
+ )
542
+ };
543
+ })
544
+ ).pipe(
545
+ Layer_exports.provideMerge(telemetryLayer(config, "process", Logger_exports.consoleJson)),
546
+ Layer_exports.provide(
547
+ Layer_exports.succeed(FetchHttpClient_exports.RequestInit, {
548
+ keepalive: true,
549
+ credentials: "same-origin"
550
+ })
551
+ )
552
+ )
553
+ )
554
+ )
555
+ );
556
+ var makeBrowserTelemetry = (settings) => {
557
+ const layer = browserTelemetryLayer(settings);
558
+ const memoMap = Layer_exports.makeMemoMapUnsafe();
559
+ const runtime = ManagedRuntime_exports.make(layer, { memoMap });
560
+ const atoms = Atom_exports.context({ memoMap });
561
+ atoms.addGlobalLayer(layer);
562
+ return { runtime, atoms };
563
+ };
564
+ var browserSettings = (basePath, service) => Effect_exports.sync(() => ({
565
+ service,
566
+ clock: "system",
567
+ version: document.querySelector('meta[name="executor-build"]')?.content ?? "development",
568
+ environment: document.querySelector('meta[name="executor-environment"]')?.content ?? "development",
569
+ traces: { url: new URL(`${basePath}/traces`, window.location.origin).href },
570
+ logs: { url: new URL(`${basePath}/logs`, window.location.origin).href }
571
+ }));
572
+
573
+ // src/implementation/optimistic.ts
574
+ var canonical = (value) => Array.isArray(value) ? value.map(canonical) : value !== null && typeof value === "object" ? Object.fromEntries(
575
+ Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([key, item]) => [key, canonical(item)])
576
+ ) : value;
577
+ var keyOf = (name, input) => JSON.stringify([name, canonical(input)]);
578
+ var json = Schema_exports.decodeUnknownSync(JsonValue);
579
+ var makeOptimisticClient = (transport) => {
580
+ const registry = AtomRegistry_exports.make({ defaultIdleTTL: 0 });
581
+ const entries = /* @__PURE__ */ new Map();
582
+ const pending = /* @__PURE__ */ new Set();
583
+ const callers = /* @__PURE__ */ new Set();
584
+ const lock = Semaphore_exports.makeUnsafe(1);
585
+ let disposed = false;
586
+ let idle = true;
587
+ const project = () => {
588
+ let values = new Map(
589
+ [...entries].map(([key, entry]) => [
590
+ key,
591
+ Option_exports.getOrUndefined(AsyncResult_exports.value(entry.base))
592
+ ])
593
+ );
594
+ const changed = /* @__PURE__ */ new Set();
595
+ for (const update of pending) {
596
+ const next = new Map(values);
597
+ const touched = /* @__PURE__ */ new Set();
598
+ const store = {
599
+ getQuery: (reference, input) => {
600
+ return structuredClone(next.get(keyOf(reference.name, json(input))));
601
+ },
602
+ getAllQueries: (reference) => [...entries].filter(([, entry]) => entry.name === reference.name).map(([key, entry]) => ({
603
+ // SAFETY: input is validated JSON; the referenced operation and each query decoder bind these types.
604
+ input: structuredClone(entry.input),
605
+ value: structuredClone(next.get(key))
606
+ })),
607
+ setQuery: (reference, input, value) => {
608
+ const key = keyOf(reference.name, json(input));
609
+ const entry = entries.get(key);
610
+ if (entry !== void 0) {
611
+ next.set(key, structuredClone(entry.schema.parse(value)));
612
+ touched.add(key);
613
+ }
614
+ }
615
+ };
616
+ try {
617
+ const result = update.project(store);
618
+ if (result !== void 0)
619
+ throw new Error("Optimistic updates must be synchronous and return nothing.");
620
+ values = next;
621
+ for (const key of touched) changed.add(key);
622
+ } catch (error) {
623
+ update.invalid = true;
624
+ pending.delete(update);
625
+ if (!update.sent) Deferred_exports.doneUnsafe(update.result, Effect_exports.fail(error));
626
+ transport.reportProjectionError({
627
+ operationId: update.operationId,
628
+ name: update.name,
629
+ sent: update.sent
630
+ });
631
+ }
632
+ }
633
+ Atom_exports.batch(() => {
634
+ for (const [key, entry] of entries) {
635
+ registry.set(
636
+ entry.visible,
637
+ changed.has(key) ? AsyncResult_exports.isInitial(entry.base) ? AsyncResult_exports.success(values.get(key)) : AsyncResult_exports.map(entry.base, () => values.get(key)) : entry.base
638
+ );
639
+ }
640
+ });
641
+ };
642
+ const stop = (entry) => {
643
+ entry.generation++;
644
+ entry.stop?.();
645
+ entry.stop = void 0;
646
+ };
647
+ const start = (entry) => {
648
+ stop(entry);
649
+ const generation = entry.generation;
650
+ entry.stop = registry.subscribe(
651
+ transport.source(entry.name, entry.input, entry.schema),
652
+ (snapshot) => {
653
+ if (disposed || generation !== entry.generation || !idle || AsyncResult_exports.isInitial(snapshot))
654
+ return;
655
+ entry.base = snapshot;
656
+ project();
657
+ },
658
+ { immediate: true }
659
+ );
660
+ };
661
+ const reconcile = Effect_exports.gen(function* () {
662
+ for (const entry of entries.values()) entry.staged = void 0;
663
+ while (!disposed) {
664
+ const unread = [...entries.values()].filter((entry) => entry.staged === void 0);
665
+ if (unread.length === 0) break;
666
+ yield* Effect_exports.forEach(
667
+ unread,
668
+ (entry) => Effect_exports.gen(function* () {
669
+ yield* Effect_exports.raceFirst(
670
+ Effect_exports.gen(function* () {
671
+ const exit = yield* Effect_exports.exit(
672
+ transport.read(entry.name, entry.input, entry.schema).pipe(Effect_exports.timeout("30 seconds"))
673
+ );
674
+ entry.staged = Exit_exports.isSuccess(exit) ? AsyncResult_exports.success(exit.value) : AsyncResult_exports.failureWithPrevious(exit.cause, {
675
+ previous: Option_exports.some(entry.base)
676
+ });
677
+ }),
678
+ Deferred_exports.await(entry.released)
679
+ );
680
+ }),
681
+ { concurrency: "unbounded", discard: true }
682
+ );
683
+ }
684
+ for (const entry of entries.values()) {
685
+ if (entry.staged !== void 0) entry.base = entry.staged;
686
+ entry.staged = void 0;
687
+ }
688
+ });
689
+ const mutation = (reference, output, update) => {
690
+ const invoke = (input) => {
691
+ if (disposed) return Promise.reject(new Error("App client is disposed."));
692
+ let parsed;
693
+ let args;
694
+ try {
695
+ parsed = structuredClone(json(input));
696
+ args = structuredClone(input);
697
+ } catch (error) {
698
+ return Promise.reject(error);
699
+ }
700
+ const result = Deferred_exports.makeUnsafe();
701
+ const item = {
702
+ operationId: crypto.randomUUID(),
703
+ name: reference.name,
704
+ project: (store) => update?.(store, structuredClone(args)),
705
+ result,
706
+ sent: false,
707
+ invalid: false
708
+ };
709
+ callers.add(result);
710
+ pending.add(item);
711
+ project();
712
+ transport.fork(
713
+ lock.withPermits(1)(
714
+ Effect_exports.gen(function* () {
715
+ if (disposed || item.invalid) return;
716
+ idle = false;
717
+ for (const entry of entries.values()) stop(entry);
718
+ item.sent = true;
719
+ const exit = yield* Effect_exports.exit(
720
+ transport.write(reference.name, parsed, output).pipe(Effect_exports.annotateSpans("executor.operation.id", item.operationId))
721
+ );
722
+ Deferred_exports.doneUnsafe(result, exit);
723
+ callers.delete(result);
724
+ if (Exit_exports.isFailure(exit)) {
725
+ pending.delete(item);
726
+ project();
727
+ }
728
+ yield* reconcile;
729
+ pending.delete(item);
730
+ idle = true;
731
+ project();
732
+ for (const entry of entries.values()) start(entry);
733
+ })
734
+ ).pipe(
735
+ Effect_exports.ensuring(
736
+ Effect_exports.sync(() => {
737
+ callers.delete(result);
738
+ pending.delete(item);
739
+ })
740
+ ),
741
+ Effect_exports.ignore
742
+ )
743
+ );
744
+ return transport.run(Deferred_exports.await(result)).then((value) => output.parse(value));
745
+ };
746
+ return Object.assign(invoke, {
747
+ withOptimisticUpdate: (project2) => mutation(reference, output, project2)
748
+ });
749
+ };
750
+ return {
751
+ mutation: (reference, output) => mutation(reference, output),
752
+ /** Shares state across mounts; the last subscriber releases the stream and cache entry. */
753
+ queryAtom: (reference, input, output) => {
754
+ const parsed = structuredClone(json(input));
755
+ const key = keyOf(reference.name, parsed);
756
+ return Atom_exports.readable((get) => {
757
+ if (disposed) return AsyncResult_exports.failure(Cause_exports.fail(new Error("App client is disposed.")));
758
+ let entry = entries.get(key);
759
+ if (entry === void 0) {
760
+ entry = {
761
+ name: reference.name,
762
+ input: parsed,
763
+ schema: output,
764
+ visible: Atom_exports.make(AsyncResult_exports.initial()),
765
+ base: AsyncResult_exports.initial(),
766
+ staged: void 0,
767
+ stop: void 0,
768
+ generation: 0,
769
+ subscribers: 0,
770
+ released: Deferred_exports.makeUnsafe()
771
+ };
772
+ entries.set(key, entry);
773
+ if (idle) start(entry);
774
+ project();
775
+ }
776
+ const retained = entry;
777
+ retained.subscribers++;
778
+ const typed = (snapshot) => {
779
+ return snapshot;
780
+ };
781
+ const release = registry.subscribe(
782
+ retained.visible,
783
+ (snapshot) => get.setSelf(typed(snapshot))
784
+ );
785
+ get.addFinalizer(() => {
786
+ release();
787
+ retained.subscribers--;
788
+ if (retained.subscribers === 0) {
789
+ stop(retained);
790
+ entries.delete(key);
791
+ Deferred_exports.doneUnsafe(retained.released, Effect_exports.void);
792
+ }
793
+ });
794
+ return typed(registry.get(retained.visible));
795
+ }).pipe(Atom_exports.setIdleTTL(0));
796
+ },
797
+ /** Cancel callers and close streams; the transport owner then interrupts its fibers. */
798
+ dispose: () => {
799
+ disposed = true;
800
+ for (const entry of entries.values()) stop(entry);
801
+ for (const result of callers)
802
+ Deferred_exports.doneUnsafe(result, Effect_exports.fail(new Error("App client is disposed.")));
803
+ entries.clear();
804
+ pending.clear();
805
+ callers.clear();
806
+ registry.dispose();
807
+ }
808
+ };
809
+ };
810
+
811
+ // src/implementation/ui-client.ts
812
+ var createAppClient = () => {
813
+ const { runtime, atoms } = makeBrowserTelemetry(
814
+ browserSettings("/_executor/api/telemetry", "executor-app-web")
815
+ );
816
+ const browser = atoms(Layer_exports.empty);
817
+ const deploymentChanged = Effect_exports.sync(() => {
818
+ window.dispatchEvent(new Event("executor:deployment-changed"));
819
+ });
820
+ let pendingWrites = 0;
821
+ const beforeUnload = (event) => {
822
+ event.preventDefault();
823
+ event.returnValue = "";
824
+ };
825
+ const awaitWrite = (effect) => {
826
+ if (pendingWrites++ === 0) window.addEventListener("beforeunload", beforeUnload);
827
+ return runtime.runPromise(effect).finally(() => {
828
+ if (--pendingWrites === 0) window.removeEventListener("beforeunload", beforeUnload);
829
+ });
830
+ };
831
+ const onHide = (event) => {
832
+ if (!event.persisted) void dispose().catch((error) => console.error(error));
833
+ };
834
+ const dispose = async () => {
835
+ window.removeEventListener("pagehide", onHide);
836
+ window.removeEventListener("beforeunload", beforeUnload);
837
+ optimistic.dispose();
838
+ await runtime.dispose();
839
+ };
840
+ window.addEventListener("pagehide", onHide);
841
+ runtime.runFork(Effect_exports.void);
842
+ const context = Effect_exports.try({
843
+ try: () => document.getElementById("executor-context")?.textContent,
844
+ catch: () => new UiFailed({ reason: "unavailable" })
845
+ }).pipe(Effect_exports.flatMap(Schema_exports.decodeUnknownEffect(Schema_exports.fromJsonString(UiContext))));
846
+ const client = HttpApiClient_exports.make(AppUiApi).pipe(Effect_exports.provide(FetchHttpClient_exports.layer));
847
+ const payload = (name, input) => Effect_exports.gen(function* () {
848
+ return {
849
+ ...yield* context,
850
+ name,
851
+ input: yield* Schema_exports.decodeUnknownEffect(JsonValue)(input)
852
+ };
853
+ });
854
+ const request = (kind, name, input, output) => Effect_exports.gen(function* () {
855
+ const api = yield* client;
856
+ const value = yield* api.ui[kind]({ payload: yield* payload(name, input) });
857
+ return yield* Schema_exports.decodeUnknownEffect(decoderOf(output))(value);
858
+ }).pipe(
859
+ Effect_exports.tapErrorTag("UiDeploymentChanged", () => deploymentChanged),
860
+ Effect_exports.withSpan(`ui.app.${kind}`, { attributes: { "executor.operation.name": name } })
861
+ );
862
+ const source = (name, input, output) => browser.atom(
863
+ Stream_exports.suspend(() => {
864
+ let previous;
865
+ let attempts = 0;
866
+ return Stream_exports.unwrap(
867
+ Effect_exports.gen(function* () {
868
+ const attempt = attempts++;
869
+ const first = yield* pendingSpan("ui.app.first_result", {
870
+ attributes: {
871
+ "executor.operation.name": name,
872
+ "executor.subscription.attempt": attempt
873
+ },
874
+ links: previous === void 0 ? [] : [{ span: previous, attributes: { "executor.link.kind": "retry" } }]
875
+ });
876
+ previous = Tracer_exports.externalSpan({
877
+ traceId: first.span.traceId,
878
+ spanId: first.span.spanId,
879
+ sampled: first.span.sampled
880
+ });
881
+ const finish = (exit) => first.finish(exit).pipe(
882
+ Effect_exports.andThen(
883
+ Exit_exports.isFailure(exit) && !Cause_exports.hasInterrupts(exit.cause) ? Effect_exports.fail(new AppQueryFailed()).pipe(
884
+ Effect_exports.withSpan("ui.app.subscription.failure", {
885
+ parent: first.span,
886
+ attributes: {
887
+ "executor.operation.name": name,
888
+ "executor.subscription.attempt": attempt
889
+ }
890
+ }),
891
+ Effect_exports.ignore
892
+ ) : Effect_exports.void
893
+ )
894
+ );
895
+ const clock = yield* Clock_exports.Clock;
896
+ const started = clock.currentTimeMillisUnsafe();
897
+ const frames = yield* Effect_exports.gen(function* () {
898
+ const api = yield* client;
899
+ return yield* api.ui.subscribe({
900
+ payload: yield* payload(name, input)
901
+ });
902
+ }).pipe(
903
+ Effect_exports.withSpan("ui.app.subscribe", {
904
+ parent: first.span,
905
+ attributes: { "executor.operation.name": name }
906
+ }),
907
+ Effect_exports.onError((cause) => finish(Exit_exports.failCause(cause)))
908
+ );
909
+ let revision = 0;
910
+ return frames.pipe(
911
+ Stream_exports.timeout("45 seconds"),
912
+ Stream_exports.concat(Stream_exports.fail(new UiFailed({ reason: "unavailable" }))),
913
+ Stream_exports.filter((frame) => frame.type !== "heartbeat"),
914
+ Stream_exports.mapEffect((frame) => {
915
+ if (frame.type === "failure") return Effect_exports.fail(frame.error);
916
+ const server = externalTrace(frame.trace);
917
+ return Effect_exports.gen(function* () {
918
+ const value = yield* Schema_exports.decodeUnknownEffect(decoderOf(output))(
919
+ frame.value
920
+ ).pipe(Effect_exports.mapError(() => new UiFailed({ reason: "operation_failed" })));
921
+ const received = yield* Effect_exports.currentSpan;
922
+ const receivedAt = clock.currentTimeMillisUnsafe();
923
+ const currentRevision = revision++;
924
+ yield* Effect_exports.annotateCurrentSpan({
925
+ "executor.operation.name": name,
926
+ "executor.snapshot.revision": currentRevision,
927
+ "browser.query.elapsed_ms": receivedAt - started,
928
+ "executor.trace.context_valid": Option_exports.isSome(server)
929
+ });
930
+ yield* first.finish(Exit_exports.void);
931
+ let committed = false;
932
+ return {
933
+ value,
934
+ commit: () => {
935
+ if (committed) return;
936
+ committed = true;
937
+ const committedAt = clock.currentTimeMillisUnsafe();
938
+ runtime.runFork(
939
+ Effect_exports.void.pipe(
940
+ Effect_exports.withSpan("ui.app.result.commit", {
941
+ parent: received,
942
+ attributes: {
943
+ "executor.operation.name": name,
944
+ "executor.snapshot.revision": currentRevision,
945
+ "browser.query.elapsed_ms": committedAt - started,
946
+ "browser.query.receive_to_commit_ms": committedAt - receivedAt,
947
+ "browser.page.hidden": document.visibilityState === "hidden"
948
+ }
949
+ })
950
+ )
951
+ );
952
+ }
953
+ };
954
+ }).pipe(
955
+ Effect_exports.withSpan("ui.app.result.receive", {
956
+ parent: Option_exports.isSome(server) ? server.value : first.span,
957
+ kind: "consumer"
958
+ })
959
+ );
960
+ }),
961
+ Stream_exports.onExit(finish),
962
+ Stream_exports.provideService(Tracer_exports.ParentSpan, first.span)
963
+ );
964
+ })
965
+ ).pipe(
966
+ // Keep the last snapshot while the watcher replaces the document.
967
+ // Unmount or client disposal interrupts the deployment-change wait.
968
+ Stream_exports.catch(
969
+ (error) => Schema_exports.is(UiDeploymentChanged)(error) ? Stream_exports.unwrap(deploymentChanged.pipe(Effect_exports.as(Stream_exports.never))) : Stream_exports.fail(error)
970
+ ),
971
+ Stream_exports.retry(
972
+ Schedule_exports.spaced("1 second").pipe(
973
+ Schedule_exports.while(
974
+ ({ input: input2 }) => HttpClientError_exports.isHttpClientError(input2) || Cause_exports.isTimeoutError(input2) || Schema_exports.is(UiFailed)(input2)
975
+ )
976
+ )
977
+ )
978
+ );
979
+ })
980
+ ).pipe(Atom_exports.map(queryResult));
981
+ const optimistic = makeOptimisticClient({
982
+ source,
983
+ read: (name, input, output) => request("query", name, input, output),
984
+ write: (name, input, output) => request("mutate", name, input, output),
985
+ fork: (effect) => {
986
+ runtime.runFork(effect);
987
+ },
988
+ run: awaitWrite,
989
+ reportProjectionError: ({ operationId, name, sent }) => {
990
+ runtime.runFork(
991
+ Effect_exports.fail(new UiFailed({ reason: "operation_failed" })).pipe(
992
+ Effect_exports.withSpan("ui.optimistic.failure", {
993
+ attributes: {
994
+ "executor.operation.id": operationId,
995
+ "executor.operation.name": name,
996
+ "executor.optimistic.sent": sent
997
+ }
998
+ }),
999
+ Effect_exports.ignore
1000
+ )
1001
+ );
1002
+ }
1003
+ });
1004
+ return {
1005
+ /** Close this client when its page or embedding owner is removed. */
1006
+ dispose,
1007
+ /** Query this app once, with a runtime-validated response. Does not populate the mounted query cache. */
1008
+ query: (reference, input, output) => runtime.runPromise(request("query", reference.name, input, output)),
1009
+ /** Execute a write once in this client's queue. Success acknowledges the write; queries reconcile afterward. */
1010
+ mutate: (reference, input, output) => optimistic.mutation(reference, output)(input),
1011
+ /** Create a callable mutation with optional withOptimisticUpdate projections over mounted queries. */
1012
+ mutation: optimistic.mutation,
1013
+ /** Share a live query across mounts and reconcile optimistic changes against fresh server reads. */
1014
+ queryAtom: optimistic.queryAtom
1015
+ };
1016
+ };
1017
+ export {
1018
+ AppQueryFailed,
1019
+ createAppClient,
1020
+ liveQueryAtom,
1021
+ mutationReference,
1022
+ queryReference
1023
+ };