authorgravatar for gabe@editmypodcast.agencyGabe Fletcher <gabe@editmypodcast.agency> 2026-08-07 00:14:50-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-08-06 21:14:50-07:00
logae7b27de824e890f2cdfc85018fc9301e7d45022
tree41805d63f3272ede48240845d7cfa8f89bdac793
parent6b73b3defe1dfb365de3b7bbb97ca56a26b50a43
signature Signed by PGP key B5690EEEBB952194

fix: prevent reconnect loops during server stalls (#5561)

Co-authored-by: t3-turbo-simulation <simulation@t3turbo.local> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Theo Browne <me@t3.gg>

13 files changed, 637 insertions(+), 235 deletions(-)

apps/server/src/process/externalLauncher.test.ts+61
......@@ -7,6 +7,7 @@ import * as Layer from "effect/Layer";
77import * as Path from "effect/Path";
88import * as Sink from "effect/Sink";
99import * as Stream from "effect/Stream";
10import * as TestClock from "effect/testing/TestClock";
1011import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";
1112
1213import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
......@@ -155,6 +156,66 @@ it.effect("discovers editors through the service API", () =>
155156 }).pipe(Effect.scoped, Effect.provide(NodeServices.layer)),
156157);
157158
159it.effect("memoizes editor discovery and refreshes after the cache window", () => {
160 let statCalls = 0;
161 const fileInfo = { type: "File" } as FileSystem.File.Info;
162 const launcherLayer = ExternalLauncher.layer.pipe(
163 Layer.provide(
164 Layer.mergeAll(
165 FileSystem.layerNoop({
166 stat: () =>
167 Effect.sync(() => {
168 statCalls += 1;
169 return fileInfo;
170 }),
171 }),
172 Path.layer,
173 Layer.succeed(
174 ChildProcessSpawner.ChildProcessSpawner,
175 ChildProcessSpawner.make(() => Effect.sync(() => makeMockDetachedHandle())),
176 ),
177 ),
178 ),
179 );
180
181 return Effect.gen(function* () {
182 const launcher = yield* ExternalLauncher.ExternalLauncher;
183
184 const first = yield* launcher.resolveAvailableEditors();
185 assert.equal(first.includes("vscode"), true);
186 const statCallsAfterFirstScan = statCalls;
187 assert.isAbove(statCallsAfterFirstScan, 0);
188
189 // Past the shared command-resolution cache TTL (30s) but within the
190 // discovery cache window: the memoized set is reused without any scan.
191 yield* TestClock.adjust("31 seconds");
192 const second = yield* launcher.resolveAvailableEditors();
193 assert.deepEqual([...second], [...first]);
194 assert.equal(statCalls, statCallsAfterFirstScan);
195
196 // Past the discovery cache window the next call rescans.
197 yield* TestClock.adjust("30 seconds");
198 yield* launcher.resolveAvailableEditors();
199 assert.isAbove(statCalls, statCallsAfterFirstScan);
200 }).pipe(
201 Effect.provide(
202 Layer.mergeAll(
203 launcherLayer,
204 Layer.succeed(HostProcessPlatform, "win32"),
205 ConfigProvider.layer(
206 ConfigProvider.fromEnv({
207 env: {
208 PATH: "C:\\t3-editor-discovery-cache-test",
209 PATHEXT: ".COM;.EXE;.BAT;.CMD",
210 },
211 }),
212 ),
213 TestClock.layer(),
214 ),
215 ),
216 );
217});
218
158219it.effect("rejects unknown editors through the service API", () =>
159220 Effect.gen(function* () {
160221 const launcher = yield* ExternalLauncher.ExternalLauncher;
apps/server/src/process/externalLauncher.ts+12-1
......@@ -298,6 +298,12 @@ const resolveAvailableEditors = Effect.fn("externalLauncher.resolveAvailableEdit
298298 return yield* buildAvailableEditors(platform, env);
299299});
300300
301// Editor discovery walks PATH for every known editor and runs for every
302// client connect (the server config embeds the available editors). Memoize
303// the discovered set for a bounded window so repeat connects skip even the
304// per-command cache lookups in @t3tools/shared/shell.
305const EDITOR_DISCOVERY_CACHE_TTL = "60 seconds";
306
301307/**
302308 * ExternalLauncher - Service tag for browser/editor launch operations.
303309 */
......@@ -443,8 +449,13 @@ export const make = Effect.gen(function* () {
443449 Effect.provideService(Path.Path, path),
444450 );
445451
452 const cachedAvailableEditors = yield* Effect.cachedWithTTL(
453 provideCommandResolutionServices(resolveAvailableEditors()),
454 EDITOR_DISCOVERY_CACHE_TTL,
455 );
456
446457 return ExternalLauncher.of({
447 resolveAvailableEditors: () => provideCommandResolutionServices(resolveAvailableEditors()),
458 resolveAvailableEditors: () => cachedAvailableEditors,
448459 launchBrowser: (target) =>
449460 launchBrowser(target).pipe(
450461 Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner),
apps/web/src/components/ChatView.tsx+10-1
......@@ -4732,12 +4732,21 @@ function ChatViewContent(props: ChatViewProps) {
47324732 isSendBusy ||
47334733 isConnecting ||
47344734 threadDetailLoading ||
4735 activeEnvironmentUnavailable ||
47364735 sendInFlightRef.current
47374736 ) {
47384737 notifyDirectAnnotationAttached();
47394738 return;
47404739 }
4740 if (activeEnvironmentUnavailable) {
4741 toastManager.add(
4742 stackedThreadToast({
4743 type: "warning",
4744 title: "Not connected: message not sent",
4745 description: "Reconnecting to the environment. Try again once it is connected.",
4746 }),
4747 );
4748 return;
4749 }
47414750 if (activePendingProgress) {
47424751 if (directAnnotation) {
47434752 notifyDirectAnnotationAttached();
packages/client-runtime/src/connection/supervisor.test.ts+89-23
......@@ -248,7 +248,7 @@ describe("EnvironmentSupervisor", () => {
248248 const firstAttempt = spans.find((span) => span.name === "relay.connection.attempt");
249249 expect(firstAttempt).toBeDefined();
250250
251 yield* TestClock.adjust("1 second");
251 yield* TestClock.adjust("3 seconds");
252252 yield* awaitState(supervisor.state, (state) => state.phase === "connected");
253253
254254 const attempts = spans.filter((span) => span.name === "relay.connection.attempt");
......@@ -358,7 +358,7 @@ describe("EnvironmentSupervisor", () => {
358358 );
359359 expect(yield* Ref.get(harness.prepareCount)).toBe(1);
360360
361 for (const [index, delay] of [1_000, 2_000, 4_000, 8_000, 16_000, 16_000].entries()) {
361 for (const [index, delay] of [3_000, 4_000, 8_000, 16_000, 16_000, 16_000].entries()) {
362362 yield* TestClock.adjust(delay);
363363 yield* eventuallyState(
364364 supervisor.state,
......@@ -384,7 +384,7 @@ describe("EnvironmentSupervisor", () => {
384384 supervisor.state,
385385 (state) => state.phase === "backoff" && state.attempt === 1,
386386 );
387 yield* TestClock.adjust("1 second");
387 yield* TestClock.adjust("3 seconds");
388388
389389 const retrying = yield* awaitState(
390390 supervisor.state,
......@@ -489,7 +489,7 @@ describe("EnvironmentSupervisor", () => {
489489 },
490490 });
491491
492 yield* TestClock.adjust("1 second");
492 yield* TestClock.adjust("3 seconds");
493493 yield* awaitState(supervisor.state, (state) => state.phase === "connected");
494494 expect(yield* Ref.get(harness.prepareCount)).toBe(2);
495495 }).pipe(Effect.provide(TestClock.layer())),
......@@ -526,7 +526,7 @@ describe("EnvironmentSupervisor", () => {
526526 supervisor.state,
527527 (state) => state.phase === "backoff" && state.attempt === 1,
528528 );
529 yield* TestClock.adjust("1 second");
529 yield* TestClock.adjust("3 seconds");
530530 yield* eventuallyState(
531531 supervisor.state,
532532 (state) => state.phase === "backoff" && state.attempt === 2,
......@@ -539,7 +539,7 @@ describe("EnvironmentSupervisor", () => {
539539 );
540540 expect(yield* Ref.get(harness.prepareCount)).toBe(3);
541541
542 yield* TestClock.adjust("999 millis");
542 yield* TestClock.adjust("2999 millis");
543543 expect(yield* Ref.get(harness.prepareCount)).toBe(3);
544544 yield* TestClock.adjust("1 milli");
545545 yield* eventuallyState(
......@@ -588,7 +588,7 @@ describe("EnvironmentSupervisor", () => {
588588 supervisor.state,
589589 (state) => state.phase === "backoff" && state.attempt === 1,
590590 );
591 yield* TestClock.adjust("1 second");
591 yield* TestClock.adjust("3 seconds");
592592 yield* awaitState(
593593 supervisor.state,
594594 (state) => state.phase === "blocked" && state.attempt === 2,
......@@ -703,7 +703,7 @@ describe("EnvironmentSupervisor", () => {
703703 );
704704 expect(Option.isNone(yield* SubscriptionRef.get(supervisor.prepared))).toBe(true);
705705
706 yield* TestClock.adjust("1 second");
706 yield* TestClock.adjust("3 seconds");
707707 yield* awaitState(
708708 supervisor.state,
709709 (state) => state.phase === "connected" && state.generation === 2,
......@@ -728,7 +728,7 @@ describe("EnvironmentSupervisor", () => {
728728 (state) => state.phase === "backoff" && state.attempt === 1,
729729 );
730730
731 yield* TestClock.adjust("1 second");
731 yield* TestClock.adjust("3 seconds");
732732 yield* awaitState(
733733 supervisor.state,
734734 (state) => state.phase === "connected" && state.generation === 2,
......@@ -741,7 +741,7 @@ describe("EnvironmentSupervisor", () => {
741741
742742 expect(secondFailure.retryAt).not.toBeNull();
743743
744 yield* TestClock.adjust("1 second");
744 yield* TestClock.adjust("3 seconds");
745745 expect(yield* Ref.get(harness.sessionCount)).toBe(2);
746746
747747 yield* TestClock.adjust("1 second");
......@@ -766,7 +766,7 @@ describe("EnvironmentSupervisor", () => {
766766 supervisor.state,
767767 (state) => state.phase === "backoff" && state.attempt === 1,
768768 );
769 yield* TestClock.adjust("1 second");
769 yield* TestClock.adjust("3 seconds");
770770 yield* awaitState(
771771 supervisor.state,
772772 (state) => state.phase === "connected" && state.generation === 2,
......@@ -805,7 +805,7 @@ describe("EnvironmentSupervisor", () => {
805805 supervisor.state,
806806 (state) => state.phase === "backoff" && state.attempt === 1,
807807 );
808 yield* TestClock.adjust("1 second");
808 yield* TestClock.adjust("3 seconds");
809809 yield* awaitState(
810810 supervisor.state,
811811 (state) => state.phase === "connected" && state.generation === 2 && state.attempt === 2,
......@@ -834,7 +834,7 @@ describe("EnvironmentSupervisor", () => {
834834 supervisor.state,
835835 (state) => state.phase === "backoff" && state.attempt === 1,
836836 );
837 yield* TestClock.adjust("1 second");
837 yield* TestClock.adjust("3 seconds");
838838 yield* awaitState(
839839 supervisor.state,
840840 (state) => state.phase === "connecting" && state.attempt === 2,
......@@ -925,9 +925,14 @@ describe("EnvironmentSupervisor", () => {
925925 }),
926926 );
927927
928 it.effect("reconnects when the foreground liveness probe fails", () =>
928 it.effect("reconnects immediately when the foreground liveness probe fails", () =>
929929 Effect.gen(function* () {
930 const allowReconnect = yield* Deferred.make<void>();
930931 const harness = yield* makeHarness({
932 prepare: (attempt) =>
933 attempt === 2
934 ? Deferred.await(allowReconnect).pipe(Effect.as(PREPARED_CONNECTION))
935 : Effect.succeed(PREPARED_CONNECTION),
931936 probe: (attempt) =>
932937 attempt === 1 ? Effect.fail(transient("The live session is stale.")) : Effect.void,
933938 });
......@@ -937,15 +942,77 @@ describe("EnvironmentSupervisor", () => {
937942
938943 yield* awaitState(supervisor.state, (state) => state.phase === "connected");
939944 yield* harness.wake("application-active");
940 yield* awaitState(supervisor.state, (state) => state.phase === "backoff");
941 yield* TestClock.adjust("1 second");
945 const reconnecting = yield* awaitState(
946 supervisor.state,
947 (state) => state.phase === "connecting",
948 );
949 expect(reconnecting.attempt).toBe(1);
950 expect(Option.isNone(yield* SubscriptionRef.get(supervisor.session))).toBe(true);
951
952 // No TestClock advance: a failed wake probe skips the first backoff rung.
953 yield* Deferred.succeed(allowReconnect, undefined);
954 yield* awaitState(
955 supervisor.state,
956 (state) => state.phase === "connected" && state.generation === 2 && state.attempt === 1,
957 );
958
959 expect(yield* Ref.get(harness.sessionCount)).toBe(2);
960 expect(yield* Ref.get(harness.releaseCount)).toBe(1);
961 }).pipe(Effect.provide(TestClock.layer())),
962 );
963
964 it.effect("keeps normal backoff when a reconnect after a failed wake probe also fails", () =>
965 Effect.gen(function* () {
966 const harness = yield* makeHarness({
967 prepare: (attempt) =>
968 attempt === 2 ? Effect.fail(transient()) : Effect.succeed(PREPARED_CONNECTION),
969 probe: (attempt) =>
970 attempt === 1 ? Effect.fail(transient("The live session is stale.")) : Effect.void,
971 });
972 const supervisor = yield* EnvironmentSupervisor.make(TARGET_ENTRY, {
973 initiallyDesired: true,
974 }).pipe(Effect.provide(harness.dependencies));
975
976 yield* awaitState(supervisor.state, (state) => state.phase === "connected");
977 yield* harness.wake("application-active");
978 // The immediate follow-up attempt fails: only the first attempt after
979 // the wake probe skips the ladder, so this failure backs off normally.
980 yield* awaitState(
981 supervisor.state,
982 (state) => state.phase === "backoff" && state.attempt === 1,
983 );
984 yield* TestClock.adjust("2999 millis");
985 expect(yield* Ref.get(harness.prepareCount)).toBe(2);
986 yield* TestClock.adjust("1 milli");
942987 yield* eventuallyState(
943988 supervisor.state,
944989 (state) => state.phase === "connected" && state.generation === 2,
945990 );
946991
992 expect(yield* Ref.get(harness.prepareCount)).toBe(3);
993 }).pipe(Effect.provide(TestClock.layer())),
994 );
995
996 it.effect("uses the full tolerance window for a stalled desktop foreground probe", () =>
997 Effect.gen(function* () {
998 const harness = yield* makeHarness({
999 probe: (attempt) => (attempt === 1 ? Effect.never : Effect.void),
1000 });
1001 const supervisor = yield* EnvironmentSupervisor.make(TARGET_ENTRY, {
1002 initiallyDesired: true,
1003 }).pipe(Effect.provide(harness.dependencies));
1004
1005 yield* awaitState(supervisor.state, (state) => state.phase === "connected");
1006 yield* harness.wake("application-active");
1007 yield* TestClock.adjust("14999 millis");
1008 expect(yield* Ref.get(harness.sessionCount)).toBe(1);
1009 yield* TestClock.adjust("1 milli");
1010 yield* awaitState(
1011 supervisor.state,
1012 (state) => state.phase === "connected" && state.generation === 2 && state.attempt === 1,
1013 );
1014
9471015 expect(yield* Ref.get(harness.sessionCount)).toBe(2);
948 expect(yield* Ref.get(harness.releaseCount)).toBe(1);
9491016 }).pipe(Effect.provide(TestClock.layer())),
9501017 );
9511018
......@@ -961,15 +1028,14 @@ describe("EnvironmentSupervisor", () => {
9611028 yield* awaitState(supervisor.state, (state) => state.phase === "connected");
9621029 yield* harness.wake("application-active-probe");
9631030 yield* TestClock.adjust("3 seconds");
1031 // The timed-out wake probe reconnects immediately without a backoff
1032 // sleep: no further clock advance is needed.
9641033 yield* awaitState(
9651034 supervisor.state,
966 (state) => state.phase === "backoff" && state.lastFailure?.reason === "timeout",
967 );
968 yield* TestClock.adjust("1 second");
969 yield* eventuallyState(
970 supervisor.state,
971 (state) => state.phase === "connected" && state.generation === 2,
1035 (state) => state.phase === "connected" && state.generation === 2 && state.attempt === 1,
9721036 );
1037
1038 expect(yield* Ref.get(harness.sessionCount)).toBe(2);
9731039 }).pipe(Effect.provide(TestClock.layer())),
9741040 );
9751041
packages/client-runtime/src/connection/supervisor.ts+21-1
......@@ -29,7 +29,7 @@ import * as RpcSession from "../rpc/session.ts";
2929import { safeErrorLogAttributes } from "../errors/safeLog.ts";
3030import * as ConnectionWakeups from "./wakeups.ts";
3131
32const RETRY_DELAYS_MS = [1_000, 2_000, 4_000, 8_000, 16_000] as const;
32const RETRY_DELAYS_MS = [3_000, 4_000, 8_000, 16_000] as const;
3333const CONNECTION_ESTABLISHMENT_TIMEOUT = "15 seconds";
3434const CONNECTION_PROBE_TIMEOUT = "15 seconds";
3535const MOBILE_CONNECTION_PROBE_TIMEOUT = "3 seconds";
......@@ -232,6 +232,10 @@ export const make = Effect.fn("EnvironmentSupervisor.make")(function* (
232232 const intent = yield* Ref.make(initialIntent);
233233 const signals = yield* Queue.unbounded<SupervisorSignal>();
234234 const resetRetryState = yield* Ref.make(false);
235 // Set when a foreground wake probe fails or times out: the user is actively
236 // returning to the app on a dead transport, so the follow-up reconnect skips
237 // the first backoff rung instead of sleeping.
238 const wakeProbeFailed = yield* Ref.make(false);
235239 const state = yield* SubscriptionRef.make<SupervisorConnectionState>(
236240 !initialIntent.desired
237241 ? availableState(initialIntent, 0)
......@@ -441,6 +445,9 @@ export const make = Effect.fn("EnvironmentSupervisor.make")(function* (
441445 ),
442446 );
443447 if (probeEvent._tag === "ProbeCompleted") {
448 if (Exit.isFailure(probeEvent.exit)) {
449 yield* Ref.set(wakeProbeFailed, true);
450 }
444451 yield* probeEvent.exit;
445452 break;
446453 }
......@@ -673,6 +680,9 @@ export const make = Effect.fn("EnvironmentSupervisor.make")(function* (
673680 const outcome: AttemptOutcome = yield* Effect.scoped(
674681 runAttempt(attempt, nextGeneration, latestFailure, pendingRetry),
675682 );
683 // Consumed on every iteration so a stale marker can never leak into a
684 // later, unrelated failure.
685 const failedWakeProbe = yield* Ref.getAndSet(wakeProbeFailed, false);
676686 if (outcome.established) {
677687 generation = nextGeneration;
678688 if (outcome.stable) {
......@@ -709,6 +719,16 @@ export const make = Effect.fn("EnvironmentSupervisor.make")(function* (
709719 continue;
710720 }
711721
722 if (failedWakeProbe) {
723 // The wake probe found a dead transport while the user is returning to
724 // the app, so reconnect immediately instead of sleeping the first
725 // backoff rung. Only this first attempt skips the ladder; if it fails
726 // too, normal backoff resumes.
727 resetRetryLadder();
728 yield* setState(connectingState(yield* Ref.get(intent), generation, 1, error));
729 continue;
730 }
731
712732 failureCount += 1;
713733 const delayMs = retryDelayMs(failureCount - 1);
714734 pendingRetry = Option.map(attemptSpan, (previousAttempt) => ({
packages/client-runtime/src/rpc/session.test.ts+27
......@@ -287,6 +287,33 @@ describe("RpcSessionFactory", () => {
287287 }),
288288 );
289289
290 it.effect("tolerates two missed pong windows before closing the session", () =>
291 Effect.gen(function* () {
292 const { factory, sockets } = yield* makeFactory();
293 const session = yield* factory.connect(PREPARED);
294 const readyFiber = yield* Effect.forkChild(session.ready);
295 const closedFiber = yield* Effect.forkChild(Effect.flip(session.closed));
296 const socket = yield* awaitSocket(sockets);
297
298 socket.open();
299 yield* completeInitialConfig(socket);
300 yield* Fiber.join(readyFiber);
301
302 yield* TestClock.adjust("15 seconds");
303 expect(closedFiber.pollUnsafe()).toBeUndefined();
304 expect(socket.sent.slice(1).map((request) => decodeJson(request))).toEqual([
305 { _tag: "Ping" },
306 { _tag: "Ping" },
307 { _tag: "Ping" },
308 ]);
309
310 yield* TestClock.adjust("5 seconds");
311 const error = yield* Fiber.join(closedFiber);
312 expect(error).toBeInstanceOf(ConnectionTransientError);
313 expect(error).toMatchObject({ reason: "transport" });
314 }).pipe(Effect.scoped, Effect.provide(TestClock.layer())),
315 );
316
290317 it.effect("reaches ready when a newer server sends unknown config members", () =>
291318 Effect.gen(function* () {
292319 const { factory, sockets } = yield* makeFactory();
packages/client-runtime/src/state/shell-sync.test.ts+70-55
......@@ -150,34 +150,34 @@ describe("environment shell synchronization", () => {
150150 }),
151151 );
152152
153 it.effect("replaces a warm shell cache with an authoritative HTTP snapshot", () =>
153 it.effect("requests a full socket snapshot when the HTTP refresh fails", () =>
154154 Effect.gen(function* () {
155155 const cachedSnapshot: OrchestrationShellSnapshot = {
156156 snapshotSequence: 5,
157157 projects: [],
158 threads: [{ id: "stale-thread" } as never],
158 threads: [{ id: "cached-thread" } as never],
159159 updatedAt: "2026-06-06T00:00:00.000Z",
160160 };
161 const httpSnapshot: OrchestrationShellSnapshot = {
161 const resetSnapshot: OrchestrationShellSnapshot = {
162162 ...cachedSnapshot,
163 snapshotSequence: 9,
163 snapshotSequence: 9_999,
164164 threads: [],
165165 updatedAt: "2026-06-07T00:00:00.000Z",
166166 };
167167 const events = yield* Queue.unbounded<OrchestrationShellStreamItem>();
168 const capturedAfterSequence = yield* SubscriptionRef.make<number | undefined>(undefined);
169 const capturedCompletionMarker = yield* Ref.make<boolean | undefined>(undefined);
170 const loaderCalls = yield* SubscriptionRef.make(0);
168 const wakeups = yield* Queue.unbounded<ConnectionWakeups.ConnectionWakeup>();
169 const subscribeInputs = yield* Queue.unbounded<{
170 readonly afterSequence?: number;
171 readonly requestCompletionMarker?: boolean;
172 }>();
173 const loaderCalls = yield* Ref.make(0);
171174 const client = {
172175 [ORCHESTRATION_WS_METHODS.subscribeShell]: (input: {
173176 readonly afterSequence?: number;
174177 readonly requestCompletionMarker?: boolean;
175178 }) =>
176179 Stream.unwrap(
177 Ref.set(capturedCompletionMarker, input.requestCompletionMarker).pipe(
178 Effect.andThen(SubscriptionRef.set(capturedAfterSequence, input.afterSequence)),
179 Effect.as(Stream.fromQueue(events)),
180 ),
180 Queue.offer(subscribeInputs, input).pipe(Effect.as(Stream.fromQueue(events))),
181181 ),
182182 } as unknown as WsRpcProtocolClient;
183183 const supervisorState = yield* SubscriptionRef.make(AVAILABLE_CONNECTION_STATE);
......@@ -208,57 +208,66 @@ describe("environment shell synchronization", () => {
208208 clear: () => Effect.void,
209209 });
210210 const snapshotLoader = ShellSnapshotLoader.of({
211 load: () =>
212 SubscriptionRef.update(loaderCalls, (count) => count + 1).pipe(
213 Effect.as(Option.some(httpSnapshot)),
214 ),
211 load: () => Ref.update(loaderCalls, (count) => count + 1).pipe(Effect.as(Option.none())),
215212 });
216213 const shellState = yield* makeEnvironmentShellState().pipe(
217214 Effect.provideService(EnvironmentSupervisor.EnvironmentSupervisor, supervisor),
218215 Effect.provideService(Persistence.EnvironmentCacheStore, cache),
219216 Effect.provideService(ShellSnapshotLoader, snapshotLoader),
217 Effect.provideService(
218 ConnectionWakeups.ConnectionWakeups,
219 ConnectionWakeups.ConnectionWakeups.of({ changes: Stream.fromQueue(wakeups) }),
220 ),
220221 );
221222
222 // Wait until the subscription is established from the warm cache.
223 yield* SubscriptionRef.changes(capturedAfterSequence).pipe(
224 Stream.filter((value) => value !== undefined),
225 Stream.runHead,
226 );
227
228 expect(yield* SubscriptionRef.get(capturedAfterSequence)).toBe(9);
229 expect(yield* Ref.get(capturedCompletionMarker)).toBe(true);
230 expect(yield* SubscriptionRef.get(loaderCalls)).toBe(1);
223 const subscribeInput = yield* Queue.take(subscribeInputs);
224 expect(subscribeInput.afterSequence).toBeUndefined();
225 expect(subscribeInput.requestCompletionMarker).toBe(true);
226 expect(yield* Ref.get(loaderCalls)).toBe(1);
231227 const synchronizing = yield* SubscriptionRef.get(shellState);
232228 expect(synchronizing.status).toBe("synchronizing");
233 expect(Option.getOrThrow(synchronizing.snapshot)).toEqual(httpSnapshot);
229 expect(Option.getOrThrow(synchronizing.snapshot)).toEqual(cachedSnapshot);
234230
231 yield* Queue.offer(events, { kind: "snapshot", snapshot: resetSnapshot });
235232 yield* Queue.offer(events, { kind: "synchronized" });
236233 yield* SubscriptionRef.changes(shellState).pipe(
237234 Stream.filter((value) => value.status === "live"),
238235 Stream.runHead,
239236 );
237
238 const live = yield* SubscriptionRef.get(shellState);
239 expect(Option.getOrThrow(live.snapshot)).toEqual(resetSnapshot);
240 expect(yield* Ref.get(loaderCalls)).toBe(1);
241
242 yield* Queue.offer(wakeups, "application-active");
243 const resumedInput = yield* Queue.take(subscribeInputs);
244 expect(resumedInput.afterSequence).toBe(resetSnapshot.snapshotSequence);
245 expect(resumedInput.requestCompletionMarker).toBe(true);
246 expect(yield* Ref.get(loaderCalls)).toBe(1);
240247 }),
241248 );
242249
243 it.effect("refreshes the authoritative shell snapshot when the app becomes active", () =>
250 it.effect("resubscribes from the in-memory shell cursor when the app becomes active", () =>
244251 Effect.gen(function* () {
245252 const events = yield* Queue.unbounded<OrchestrationShellStreamItem>();
246253 const wakeups = yield* Queue.unbounded<ConnectionWakeups.ConnectionWakeup>();
247254 const loaderCalls = yield* Ref.make(0);
248 const subscriptionCount = yield* Ref.make(0);
255 const capturedAfterSequences = yield* Ref.make<ReadonlyArray<number | undefined>>([]);
249256 const client = {
250 [ORCHESTRATION_WS_METHODS.subscribeShell]: () =>
257 [ORCHESTRATION_WS_METHODS.subscribeShell]: (input: { readonly afterSequence?: number }) =>
251258 Stream.unwrap(
252 Ref.update(subscriptionCount, (count) => count + 1).pipe(
253 Effect.as(Stream.fromQueue(events)),
254 ),
259 Ref.update(capturedAfterSequences, (captured) => [
260 ...captured,
261 input.afterSequence,
262 ]).pipe(Effect.as(Stream.fromQueue(events))),
255263 ),
256264 } as unknown as WsRpcProtocolClient;
257265 const supervisorState = yield* SubscriptionRef.make(AVAILABLE_CONNECTION_STATE);
266 const activeSession = yield* SubscriptionRef.make(Option.some(session(client)));
258267 const supervisor = EnvironmentSupervisor.EnvironmentSupervisor.of({
259268 target: TARGET,
260269 state: supervisorState,
261 session: yield* SubscriptionRef.make(Option.some(session(client))),
270 session: activeSession,
262271 prepared: yield* SubscriptionRef.make(Option.some(PREPARED)),
263272 connect: Effect.void,
264273 disconnect: Effect.void,
......@@ -296,54 +305,60 @@ describe("environment shell synchronization", () => {
296305 ),
297306 );
298307
299 yield* SubscriptionRef.changes(shellState).pipe(
300 Stream.filter(
301 (value) =>
302 value.status === "synchronizing" &&
303 Option.isSome(value.snapshot) &&
304 value.snapshot.value.snapshotSequence === 10,
305 ),
306 Stream.runHead,
307 );
308 // A new session starts from an authoritative HTTP snapshot.
309 for (let attempt = 0; attempt < 100; attempt += 1) {
310 if ((yield* Ref.get(capturedAfterSequences)).length >= 1) break;
311 yield* Effect.yieldNow;
312 }
313 expect(yield* Ref.get(capturedAfterSequences)).toEqual([10]);
308314 yield* Queue.offer(events, { kind: "synchronized" });
309315 yield* SubscriptionRef.changes(shellState).pipe(
310316 Stream.filter((value) => value.status === "live"),
311317 Stream.runHead,
312318 );
313319
314 yield* Queue.offer(wakeups, "application-active");
320 // A newer snapshot arrives on the stream and advances the cursor.
321 yield* Queue.offer(events, {
322 kind: "snapshot",
323 snapshot: { ...LIVE_SHELL_SNAPSHOT, snapshotSequence: 40 },
324 });
315325 yield* SubscriptionRef.changes(shellState).pipe(
316326 Stream.filter(
317 (value) =>
318 value.status === "synchronizing" &&
319 Option.isSome(value.snapshot) &&
320 value.snapshot.value.snapshotSequence === 20,
327 (value) => Option.isSome(value.snapshot) && value.snapshot.value.snapshotSequence === 40,
321328 ),
322329 Stream.runHead,
323330 );
324331
332 yield* Queue.offer(wakeups, "application-active");
325333 for (let attempt = 0; attempt < 100; attempt += 1) {
326 if ((yield* Ref.get(subscriptionCount)) >= 2) break;
334 if ((yield* Ref.get(capturedAfterSequences)).length >= 2) break;
327335 yield* Effect.yieldNow;
328336 }
329
330 expect(yield* Ref.get(loaderCalls)).toBe(2);
331 expect(yield* Ref.get(subscriptionCount)).toBe(2);
337 expect(yield* Ref.get(capturedAfterSequences)).toEqual([10, 40]);
338 yield* Queue.offer(events, { kind: "synchronized" });
332339
333340 yield* Queue.offer(wakeups, "application-active-probe");
334341 for (let attempt = 0; attempt < 100; attempt += 1) {
335 if ((yield* Ref.get(subscriptionCount)) >= 3) break;
342 if ((yield* Ref.get(capturedAfterSequences)).length >= 3) break;
336343 yield* Effect.yieldNow;
337344 }
338 expect(yield* Ref.get(loaderCalls)).toBe(3);
339 expect(yield* Ref.get(subscriptionCount)).toBe(3);
345 expect(yield* Ref.get(capturedAfterSequences)).toEqual([10, 40, 40]);
340346
341347 yield* Queue.offer(wakeups, "application-active-reconnect");
342348 for (let attempt = 0; attempt < 10; attempt += 1) {
343349 yield* Effect.yieldNow;
344350 }
345 expect(yield* Ref.get(loaderCalls)).toBe(3);
346 expect(yield* Ref.get(subscriptionCount)).toBe(3);
351 expect((yield* Ref.get(capturedAfterSequences)).length).toBe(3);
352 expect(yield* Ref.get(loaderCalls)).toBe(1);
353
354 // Replacing the session performs another authoritative refresh.
355 yield* SubscriptionRef.set(activeSession, Option.some(session(client)));
356 for (let attempt = 0; attempt < 100; attempt += 1) {
357 if ((yield* Ref.get(capturedAfterSequences)).length >= 4) break;
358 yield* Effect.yieldNow;
359 }
360 expect(yield* Ref.get(capturedAfterSequences)).toEqual([10, 40, 40, 20]);
361 expect(yield* Ref.get(loaderCalls)).toBe(2);
347362 }),
348363 );
349364});
packages/client-runtime/src/state/shell.ts+55-22
......@@ -21,6 +21,7 @@ import * as ConnectionWakeups from "../connection/wakeups.ts";
2121import { safeErrorLogAttributes } from "../errors/safeLog.ts";
2222import { EnvironmentCacheStore } from "../platform/persistence.ts";
2323import { subscribeDynamic } from "../rpc/client.ts";
24import type { RpcSession } from "../rpc/session.ts";
2425import { ShellSnapshotLoader } from "./shellSnapshotHttp.ts";
2526import { applyShellStreamEvent } from "./shellReducer.ts";
2627import type { EnvironmentCatalogState } from "./connections.ts";
......@@ -71,6 +72,8 @@ export const makeEnvironmentShellState = Effect.fn("EnvironmentShellState.make")
7172 error: Option.none(),
7273 });
7374 const awaitingCompletion = yield* Ref.make(false);
75 const lastAuthoritativeSession = yield* Ref.make<RpcSession | null>(null);
76 const activeSubscriptionSession = yield* Ref.make<RpcSession | null>(null);
7477 const persistence = yield* Queue.sliding<OrchestrationShellSnapshot>(1);
7578
7679 const persist = Effect.fn("EnvironmentShellState.persist")(function* (
......@@ -166,6 +169,12 @@ export const makeEnvironmentShellState = Effect.fn("EnvironmentShellState.make")
166169 status: waiting ? "synchronizing" : "live",
167170 error: Option.none(),
168171 });
172 if (item.kind === "snapshot") {
173 const session = yield* Ref.get(activeSubscriptionSession);
174 if (session !== null) {
175 yield* Ref.set(lastAuthoritativeSession, session);
176 }
177 }
169178 yield* Queue.offer(persistence, nextSnapshot);
170179 });
171180
......@@ -180,6 +189,7 @@ export const makeEnvironmentShellState = Effect.fn("EnvironmentShellState.make")
180189 subscribeDynamic(
181190 ORCHESTRATION_WS_METHODS.subscribeShell,
182191 Effect.fn("EnvironmentShellState.makeSubscribeInput")(function* (session) {
192 yield* Ref.set(activeSubscriptionSession, session);
183193 const supportsCompletionMarker = yield* session.initialConfig.pipe(
184194 Effect.map((config) => config.shellResumeCompletionMarker === true),
185195 Effect.orElseSucceed(() => false),
......@@ -187,30 +197,53 @@ export const makeEnvironmentShellState = Effect.fn("EnvironmentShellState.make")
187197 yield* Ref.set(awaitingCompletion, supportsCompletionMarker);
188198 yield* setSynchronizing;
189199
190 const prepared = yield* SubscriptionRef.get(supervisor.prepared).pipe(
191 Effect.flatMap(
192 Option.match({
193 onSome: Effect.succeed,
194 onNone: () =>
195 SubscriptionRef.changes(supervisor.prepared).pipe(
196 Stream.filter(Option.isSome),
197 Stream.map((value) => value.value),
198 Stream.runHead,
199 Effect.map(Option.getOrThrow),
200 ),
201 }),
202 ),
203 );
204 const httpSnapshot = yield* snapshotLoader.load(prepared);
205 if (Option.isSome(httpSnapshot)) {
206 yield* applyItem({ kind: "snapshot", snapshot: httpSnapshot.value });
207 return {
208 afterSequence: httpSnapshot.value.snapshotSequence,
209 ...(supportsCompletionMarker ? { requestCompletionMarker: true as const } : {}),
210 };
200 // Foreground resubscriptions on the same live session can resume from
201 // the in-memory cursor. A new session reloads the authoritative HTTP
202 // snapshot so a valid cursor cannot preserve incomplete cached data.
203 const hasAuthoritativeSnapshot = (yield* Ref.get(lastAuthoritativeSession)) === session;
204 let canResume = hasAuthoritativeSnapshot;
205 let current = yield* SubscriptionRef.get(state);
206 if (!hasAuthoritativeSnapshot || Option.isNone(current.snapshot)) {
207 const prepared = yield* SubscriptionRef.get(supervisor.prepared).pipe(
208 Effect.flatMap(
209 Option.match({
210 onSome: Effect.succeed,
211 onNone: () =>
212 SubscriptionRef.changes(supervisor.prepared).pipe(
213 Stream.filter(Option.isSome),
214 Stream.map((value) => value.value),
215 Stream.runHead,
216 Effect.map(Option.getOrThrow),
217 ),
218 }),
219 ),
220 );
221 const httpSnapshot = yield* snapshotLoader.load(prepared);
222 if (Option.isSome(httpSnapshot)) {
223 yield* applyItem({ kind: "snapshot", snapshot: httpSnapshot.value });
224 canResume = true;
225 current = yield* SubscriptionRef.get(state);
226 }
211227 }
212228
213 return supportsCompletionMarker ? { requestCompletionMarker: true as const } : {};
229 // If the authoritative refresh failed, omit the cached cursor so the
230 // socket fallback sends a complete snapshot for this new session.
231 if (!canResume || Option.isNone(current.snapshot)) {
232 return supportsCompletionMarker ? { requestCompletionMarker: true as const } : {};
233 }
234 if (!supportsCompletionMarker) {
235 // Without a completion marker there is no synchronized signal for a
236 // resumed subscription, so report live immediately, like threads.
237 yield* SubscriptionRef.update(state, (value) => ({
238 ...value,
239 status: "live" as const,
240 error: Option.none(),
241 }));
242 }
243 return {
244 afterSequence: current.snapshot.value.snapshotSequence,
245 ...(supportsCompletionMarker ? { requestCompletionMarker: true as const } : {}),
246 };
214247 }),
215248 {
216249 onExpectedFailure: (cause) => setStreamError(Cause.squash(cause)),
packages/shared/src/observability.test.ts+26
......@@ -21,6 +21,7 @@ import {
2121 makeTraceSink,
2222 type TraceRecord,
2323 type TraceSinkFlushStats,
24 truncateTraceAttributes,
2425} from "./observability.ts";
2526
2627describe("errorTag", () => {
......@@ -111,6 +112,31 @@ const makeTestLayer = (tracePath: string) =>
111112
112113const nodeServicesIt = it.layer(NodeServices.layer);
113114
115describe("truncateTraceAttributes", () => {
116 it("clamps oversized strings at any depth without mutating the input", () => {
117 const stack = "s".repeat(2_000);
118 const attributes = {
119 "db.query.text": "q".repeat(2_000),
120 short: "ok",
121 error: { name: "Error", stack, nested: ["a".repeat(2_000)] },
122 };
123 const truncated = truncateTraceAttributes(attributes);
124
125 assert.equal((truncated["db.query.text"] as string).length, 200 + "…[truncated]".length);
126 assert.equal(truncated["short"], "ok");
127 const error = truncated["error"] as { stack: string; nested: Array<string> };
128 assert.equal(error.stack.length, 500 + "…[truncated]".length);
129 assert.equal(error.nested[0]?.length, 500 + "…[truncated]".length);
130 // Input is untouched: the live span's attributes are shared.
131 assert.equal(attributes.error.stack, stack);
132 });
133
134 it("returns the same reference when nothing exceeds the limits", () => {
135 const attributes = { short: "ok", nested: { fine: "also ok" } };
136 assert.equal(truncateTraceAttributes(attributes), attributes);
137 });
138});
139
114140describe("observability", () => {
115141 it("normalizes circular arrays, maps, and sets without recursing forever", () => {
116142 const array: Array<unknown> = ["alpha"];
packages/shared/src/observability.ts+60-3
......@@ -248,6 +248,61 @@ function formatTraceExit(exit: Exit.Exit<unknown, unknown>): EffectTraceRecord["
248248 };
249249}
250250
251const TRACE_ATTRIBUTE_MAX_LENGTH = 500;
252const TRACE_ATTRIBUTE_TRUNCATED_LENGTH = 200;
253const TRACE_ATTRIBUTE_TRUNCATION_SUFFIX = "…[truncated]";
254const ALWAYS_TRUNCATED_TRACE_ATTRIBUTES: ReadonlySet<string> = new Set(["db.query.text"]);
255
256// Clamps strings nested inside already-normalized attribute values (arrays and
257// plain objects from normalizeJsonValue, e.g. an Error's `stack`). Returns the
258// input reference when nothing was clamped.
259function truncateNestedValue(value: unknown): unknown {
260 if (typeof value === "string") {
261 return value.length <= TRACE_ATTRIBUTE_MAX_LENGTH
262 ? value
263 : `${value.slice(0, TRACE_ATTRIBUTE_MAX_LENGTH)}${TRACE_ATTRIBUTE_TRUNCATION_SUFFIX}`;
264 }
265 if (Array.isArray(value)) {
266 const truncated = value.map(truncateNestedValue);
267 return truncated.some((entry, index) => entry !== value[index]) ? truncated : value;
268 }
269 if (isPlainObject(value)) {
270 let truncated: Record<string, unknown> | undefined;
271 for (const [key, entry] of Object.entries(value)) {
272 const next = truncateNestedValue(entry);
273 if (next === entry) continue;
274 truncated ??= { ...value };
275 truncated[key] = next;
276 }
277 return truncated ?? value;
278 }
279 return value;
280}
281
282/**
283 * Clamps oversized attribute values on the serialized trace record so the file
284 * sink stays small, including strings nested inside arrays and objects (e.g.
285 * error stacks). Returns a new record when anything was clamped; never
286 * mutates the input (the live span's attributes are shared with other tracers).
287 */
288export function truncateTraceAttributes(attributes: TraceAttributes): TraceAttributes {
289 let truncated: Record<string, unknown> | undefined;
290 for (const [key, value] of Object.entries(attributes)) {
291 if (typeof value === "string" && ALWAYS_TRUNCATED_TRACE_ATTRIBUTES.has(key)) {
292 if (value.length <= TRACE_ATTRIBUTE_TRUNCATED_LENGTH) continue;
293 truncated ??= { ...attributes };
294 truncated[key] =
295 `${value.slice(0, TRACE_ATTRIBUTE_TRUNCATED_LENGTH)}${TRACE_ATTRIBUTE_TRUNCATION_SUFFIX}`;
296 continue;
297 }
298 const next = truncateNestedValue(value);
299 if (next === value) continue;
300 truncated ??= { ...attributes };
301 truncated[key] = next;
302 }
303 return truncated ?? attributes;
304}
305
251306export function spanToTraceRecord(span: SerializableSpan): EffectTraceRecord {
252307 const status = span.status as Extract<Tracer.SpanStatus, { _tag: "Ended" }>;
253308 const parentSpanId = Option.getOrUndefined(span.parent)?.spanId;
......@@ -263,16 +318,18 @@ export function spanToTraceRecord(span: SerializableSpan): EffectTraceRecord {
263318 startTimeUnixNano: String(status.startTime),
264319 endTimeUnixNano: String(status.endTime),
265320 durationMs: Number(status.endTime - status.startTime) / 1_000_000,
266 attributes: compactTraceAttributes(Object.fromEntries(span.attributes)),
321 attributes: truncateTraceAttributes(
322 compactTraceAttributes(Object.fromEntries(span.attributes)),
323 ),
267324 events: span.events.map(([name, startTime, attributes]) => ({
268325 name,
269326 timeUnixNano: String(startTime),
270 attributes: compactTraceAttributes(attributes),
327 attributes: truncateTraceAttributes(compactTraceAttributes(attributes)),
271328 })),
272329 links: span.links.map((link) => ({
273330 traceId: link.span.traceId,
274331 spanId: link.span.spanId,
275 attributes: compactTraceAttributes(link.attributes),
332 attributes: truncateTraceAttributes(compactTraceAttributes(link.attributes)),
276333 })),
277334 exit: formatTraceExit(status.exit),
278335 };
packages/shared/src/shell.ts+65
......@@ -3,6 +3,7 @@ import * as NodeOS from "node:os";
33import * as NodePath from "node:path";
44import * as NodeChildProcess from "node:child_process";
55import * as NodeFS from "node:fs";
6import * as Clock from "effect/Clock";
67import * as Data from "effect/Data";
78import * as Effect from "effect/Effect";
89import * as FileSystem from "effect/FileSystem";
......@@ -491,6 +492,54 @@ function resolveCommandCandidates(
491492 return Array.from(new Set(candidates));
492493}
493494
495// Session bootstrap resolves the same commands over and over, each PATH scan
496// costing hundreds of 'shell.isExecutableFile' filesystem probes (tens of
497// thousands per connect). Memoize the scan outcome per
498// (platform, PATH, PATHEXT, command) for a short window: repeat scans hit the
499// cache while any change to the search environment invalidates immediately.
500// Explicit-path resolution is never cached - callers probe paths they have
501// just written (e.g. managed binary installs). A "not-found" outcome is also
502// cached for the TTL, so a just-installed binary can stay invisible for up to
503// 30s unless resolved by explicit path.
504// TTL expiry uses the monotonic clock (Clock.currentTimeNanos) so backward
505// wall-clock adjustments cannot keep expired entries alive.
506const COMMAND_RESOLUTION_CACHE_TTL_NANOS = 30_000_000_000n;
507const COMMAND_RESOLUTION_CACHE_MAX_ENTRIES = 512;
508const COMMAND_RESOLUTION_CACHE_KEY_SEPARATOR = String.fromCharCode(0);
509
510interface CommandResolutionCacheEntry {
511 readonly resolvedPath: string | null;
512 readonly expiresAtNanos: bigint;
513}
514
515// The cache lives in the Effect environment (like HostProcessPlatform above)
516// so tests and embedders can provide an isolated instance; the default is a
517// single process-wide map shared by all consumers.
518export const CommandResolutionCache = Context.Reference<Map<string, CommandResolutionCacheEntry>>(
519 "@t3tools/shared/shell/CommandResolutionCache",
520 {
521 defaultValue: () => new Map(),
522 },
523);
524
525function cacheCommandResolution(
526 cache: Map<string, CommandResolutionCacheEntry>,
527 cacheKey: string,
528 resolvedPath: string | null,
529 nowNanos: bigint,
530): void {
531 if (cache.size >= COMMAND_RESOLUTION_CACHE_MAX_ENTRIES) {
532 const oldestKey = cache.keys().next().value;
533 if (oldestKey !== undefined) {
534 cache.delete(oldestKey);
535 }
536 }
537 cache.set(cacheKey, {
538 resolvedPath,
539 expiresAtNanos: nowNanos + COMMAND_RESOLUTION_CACHE_TTL_NANOS,
540 });
541}
542
494543const isExecutableFile = Effect.fn("shell.isExecutableFile")(function* (
495544 filePath: string,
496545 platform: NodeJS.Platform,
......@@ -538,6 +587,20 @@ const resolveCommandPathForPlatform = Effect.fn("shell.resolveCommandPathForPlat
538587 if (pathValue.length === 0) {
539588 return yield* new CommandResolutionError({ command, reason: "not-found" });
540589 }
590
591 const cacheKey = [platform, pathValue, windowsPathExtensions.join(";"), command].join(
592 COMMAND_RESOLUTION_CACHE_KEY_SEPARATOR,
593 );
594 const cache = yield* CommandResolutionCache;
595 const nowNanos = yield* Clock.currentTimeNanos;
596 const cached = cache.get(cacheKey);
597 if (cached !== undefined && cached.expiresAtNanos > nowNanos) {
598 if (cached.resolvedPath === null) {
599 return yield* new CommandResolutionError({ command, reason: "not-found" });
600 }
601 return cached.resolvedPath;
602 }
603
541604 const pathEntries: string[] = [];
542605 for (const entry of pathValue.split(pathDelimiterForPlatform(platform))) {
543606 const pathEntry = stripWrappingQuotes(entry.trim());
......@@ -550,10 +613,12 @@ const resolveCommandPathForPlatform = Effect.fn("shell.resolveCommandPathForPlat
550613 for (const candidate of commandCandidates) {
551614 const candidatePath = path.join(pathEntry, candidate);
552615 if (yield* isExecutableFile(candidatePath, platform, windowsPathExtensions)) {
616 cacheCommandResolution(cache, cacheKey, candidatePath, nowNanos);
553617 return candidatePath;
554618 }
555619 }
556620 }
621 cacheCommandResolution(cache, cacheKey, null, nowNanos);
557622 return yield* new CommandResolutionError({ command, reason: "not-found" });
558623});
559624
patches/effect@4.0.0-beta.103.patch+17-6
......@@ -278,32 +278,43 @@ index b536d0a..12ffac0 100644
278278 }).pipe(Effect.flatMap(() => Effect.fail(new Socket.SocketError({
279279 reason: new Socket.SocketCloseError({
280280 code: 1000
281@@ -687,20 +716,20 @@ export const makeProtocolSocket = options => Protocol.make(Effect.fnUntraced(fun
281@@ -687,20 +716,28 @@ export const makeProtocolSocket = options => Protocol.make(Effect.fnUntraced(fun
282282 };
283283 }));
284284 const defaultRetryPolicy = /*#__PURE__*/Schedule.min([/*#__PURE__*/Schedule.exponential(500, 1.5), /*#__PURE__*/Schedule.spaced(5000)]);
285285-const makePinger = /*#__PURE__*/Effect.fnUntraced(function* (writePing) {
286286+const makePinger = /*#__PURE__*/Effect.fnUntraced(function* (writePing, hooks) {
287287 let recievedPong = true;
288+ let missedPongs = 0;
288289 const latch = Latch.makeUnsafe();
289290 const reset = () => {
290291 recievedPong = true;
292+ missedPongs = 0;
291293 latch.closeUnsafe();
292294 };
293295- const onPong = () => {
294+ const onPong = Effect.sync(() => {
295 recievedPong = true;
296- recievedPong = true;
296297- };
298+ const onPong = Effect.sync(() => {
299+ recievedPong = true;
300+ missedPongs = 0;
297301+ }).pipe(Effect.andThen(hooks?.onPong ?? Effect.void));
298302 yield* Effect.suspend(() => {
299 if (!recievedPong) return latch.open;
300 recievedPong = false;
303- if (!recievedPong) return latch.open;
304- recievedPong = false;
301305- return writePing;
306+ if (!recievedPong) {
307+ missedPongs += 1;
308+ if (missedPongs >= 3) return latch.open;
309+ return (hooks?.onPing ?? Effect.void).pipe(Effect.andThen(writePing));
310+ }
311+ recievedPong = false;
312+ missedPongs = 0;
302313+ return (hooks?.onPing ?? Effect.void).pipe(Effect.andThen(writePing));
303314 }).pipe(Effect.delay("5 seconds"), Effect.ignore, Effect.forever, Effect.interruptible, Effect.forkScoped);
304315 return {
305316 timeout: latch.await,
306@@ -843,6 +872,11 @@ export const makeProtocolWorker = options => Protocol.make(Effect.fnUntraced(fun
317@@ -843,6 +880,11 @@ export const makeProtocolWorker = options => Protocol.make(Effect.fnUntraced(fun
307318 * @since 4.0.0
308319 */
309320 export const layerProtocolWorker = /*#__PURE__*/flow(makeProtocolWorker, /*#__PURE__*/Layer.effect(Protocol));
pnpm-lock.yaml+124-123
......@@ -76,7 +76,7 @@ patchedDependencies:
7676 '@pierre/diffs@1.3.0-beta.10': 7ef7cb0cbabb17c15cdb137554068b36f15f6f5265e73fb51452aa3380db91aa
7777 '@react-native-menu/menu@2.0.0': 5ea3ae4bf1d9baf5443b65c269bb09621c27a68d556f713778f37b1e8d46aaae
7878 '@react-navigation/native-stack@7.17.6': c7fc101b78d434904425e5a24c22fb0042298dec6f807250486e784f3c717273
79 effect@4.0.0-beta.103: a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9
79 effect@4.0.0-beta.103: af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6
8080 expo-modules-jsi@56.0.10: 9170f8074ae4e35a0a086e756c8f815794fd3abe51eac67ca3ba02804225ec1f
8181 react-native-gesture-handler@2.31.2: 808eb26f9e57cf4945efd3985af4d9c764da6f91f4c9764433cc868602bbf4d3
8282 react-native-keyboard-controller@1.21.13: 20be72c84d74253acdcfefbc6defe36dc396944f1a44cab2bdd0e3cd572ae008
......@@ -116,7 +116,7 @@ importers:
116116 version: 0.0.3
117117 '@effect/platform-node':
118118 specifier: 4.0.0-beta.103
119 version: 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(ioredis@5.11.0)(utf-8-validate@6.0.6)
119 version: 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(ioredis@5.11.0)(utf-8-validate@6.0.6)
120120 '@t3tools/client-runtime':
121121 specifier: workspace:*
122122 version: link:../../packages/client-runtime
......@@ -134,7 +134,7 @@ importers:
134134 version: link:../../packages/tailscale
135135 effect:
136136 specifier: 4.0.0-beta.103
137 version: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
137 version: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
138138 electron:
139139 specifier: 41.5.0
140140 version: 41.5.0
......@@ -153,7 +153,7 @@ importers:
153153 devDependencies:
154154 '@effect/vitest':
155155 specifier: 4.0.0-beta.103
156 version: 4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
156 version: 4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
157157 '@types/node':
158158 specifier: 24.12.4
159159 version: 24.12.4
......@@ -199,7 +199,7 @@ importers:
199199 version: 4.1.2(expo-auth-session@56.0.14(expo@56.0.12)(react-native@0.85.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(expo-constants@56.0.18)(expo-crypto@56.0.4(expo@56.0.12))(expo-secure-store@56.0.4(expo@56.0.12))(expo-web-browser@56.0.5(expo@56.0.12)(react-native@0.85.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)))(expo@56.0.12)(react-dom@19.2.3(react@19.2.3))(react-native@0.85.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)(typescript@6.0.3)
200200 '@effect/atom-react':
201201 specifier: 4.0.0-beta.103
202 version: 4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(react@19.2.3)(scheduler@0.27.0)
202 version: 4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(react@19.2.3)(scheduler@0.27.0)
203203 '@expo-google-fonts/dm-sans':
204204 specifier: ^0.4.2
205205 version: 0.4.2
......@@ -274,7 +274,7 @@ importers:
274274 version: 8.0.3
275275 effect:
276276 specifier: 4.0.0-beta.103
277 version: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
277 version: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
278278 expo:
279279 specifier: ~56.0.12
280280 version: 56.0.12(8895228379997a2a064f9644cda56ed0)
......@@ -422,7 +422,7 @@ importers:
422422 devDependencies:
423423 '@effect/vitest':
424424 specifier: 4.0.0-beta.103
425 version: 4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
425 version: 4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
426426 '@pierre/trees':
427427 specifier: 1.0.0-beta.4
428428 version: 1.0.0-beta.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
......@@ -446,16 +446,16 @@ importers:
446446 version: 0.3.170(@anthropic-ai/sdk@0.93.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(zod@4.4.3)
447447 '@effect/platform-bun':
448448 specifier: 4.0.0-beta.103
449 version: 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(utf-8-validate@6.0.6)
449 version: 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(utf-8-validate@6.0.6)
450450 '@effect/platform-node':
451451 specifier: 4.0.0-beta.103
452 version: 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(ioredis@5.11.0)(utf-8-validate@6.0.6)
452 version: 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(ioredis@5.11.0)(utf-8-validate@6.0.6)
453453 '@effect/platform-node-shared':
454454 specifier: 4.0.0-beta.103
455 version: 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(utf-8-validate@6.0.6)
455 version: 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(utf-8-validate@6.0.6)
456456 '@effect/sql-sqlite-bun':
457457 specifier: 4.0.0-beta.103
458 version: 4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
458 version: 4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
459459 '@ff-labs/fff-node':
460460 specifier: 0.9.4
461461 version: 0.9.4(patch_hash=2b16019ce7ab61aec6478dd02f79ef468cc1d5c51e9d00764f7d2ab8167210c8)
......@@ -467,7 +467,7 @@ importers:
467467 version: 1.3.0-beta.10(patch_hash=7ef7cb0cbabb17c15cdb137554068b36f15f6f5265e73fb51452aa3380db91aa)(@shikijs/themes@4.3.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
468468 effect:
469469 specifier: 4.0.0-beta.103
470 version: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
470 version: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
471471 node-pty:
472472 specifier: ^1.1.0
473473 version: 1.1.0
......@@ -477,7 +477,7 @@ importers:
477477 devDependencies:
478478 '@effect/vitest':
479479 specifier: 4.0.0-beta.103
480 version: 4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
480 version: 4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
481481 '@t3tools/contracts':
482482 specifier: workspace:*
483483 version: link:../../packages/contracts
......@@ -531,7 +531,7 @@ importers:
531531 version: 3.2.2(react@19.2.6)
532532 '@effect/atom-react':
533533 specifier: 4.0.0-beta.103
534 version: 4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(react@19.2.6)(scheduler@0.27.0)
534 version: 4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(react@19.2.6)(scheduler@0.27.0)
535535 '@formkit/auto-animate':
536536 specifier: ^0.9.0
537537 version: 0.9.0
......@@ -567,7 +567,7 @@ importers:
567567 version: 0.7.1
568568 effect:
569569 specifier: 4.0.0-beta.103
570 version: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
570 version: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
571571 jose:
572572 specifier: 'catalog:'
573573 version: 6.2.2
......@@ -607,10 +607,10 @@ importers:
607607 devDependencies:
608608 '@effect/platform-node':
609609 specifier: 4.0.0-beta.103
610 version: 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(ioredis@5.11.0)(utf-8-validate@6.0.6)
610 version: 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(ioredis@5.11.0)(utf-8-validate@6.0.6)
611611 '@effect/vitest':
612612 specifier: 4.0.0-beta.103
613 version: 4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
613 version: 4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
614614 '@rolldown/plugin-babel':
615615 specifier: ^0.2.0
616616 version: 0.2.3(@babel/core@7.29.7)(@babel/plugin-transform-runtime@7.29.7(@babel/core@7.29.7))(@babel/runtime@7.29.7)(@voidzero-dev/vite-plus-core@0.2.2(@types/node@24.12.4)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(typescript@6.0.3)(unrun@0.2.39)(yaml@2.9.0))(rolldown@1.1.5)
......@@ -658,7 +658,7 @@ importers:
658658 version: 3.14.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
659659 '@effect/sql-pg':
660660 specifier: 4.0.0-beta.103
661 version: 4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
661 version: 4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
662662 '@noble/curves':
663663 specifier: 'catalog:'
664664 version: 1.9.1
......@@ -676,23 +676,23 @@ importers:
676676 version: link:../../packages/shared
677677 alchemy:
678678 specifier: 2.0.0-beta.65
679 version: 2.0.0-beta.65(a455401069e1fee89f31a277c51247f6)
679 version: 2.0.0-beta.65(75567d8add6e3362e26fe00f83a97bee)
680680 drizzle-orm:
681681 specifier: 1.0.0-rc.4
682 version: 1.0.0-rc.4(@cloudflare/workers-types@4.20260604.1)(@effect/sql-d1@4.0.0-beta.101(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)))(@effect/sql-pg@4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)))(@effect/sql-sqlite-bun@4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)))(@libsql/client@0.17.3(bufferutil@4.1.0)(utf-8-validate@6.0.6))(bun-types@1.3.14)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(expo-sqlite@56.0.5(expo@56.0.12)(react-native@0.85.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6))(mysql2@3.22.4(@types/node@24.12.4))(pg@8.21.0)(zod@4.4.3)
682 version: 1.0.0-rc.4(@cloudflare/workers-types@4.20260604.1)(@effect/sql-d1@4.0.0-beta.101(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)))(@effect/sql-pg@4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)))(@effect/sql-sqlite-bun@4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)))(@libsql/client@0.17.3(bufferutil@4.1.0)(utf-8-validate@6.0.6))(bun-types@1.3.14)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(expo-sqlite@56.0.5(expo@56.0.12)(react-native@0.85.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6))(mysql2@3.22.4(@types/node@24.12.4))(pg@8.21.0)(zod@4.4.3)
683683 effect:
684684 specifier: 4.0.0-beta.103
685 version: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
685 version: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
686686 devDependencies:
687687 '@cloudflare/workers-types':
688688 specifier: ^4.20260601.1
689689 version: 4.20260604.1
690690 '@effect/platform-node':
691691 specifier: 4.0.0-beta.103
692 version: 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(ioredis@5.11.0)(utf-8-validate@6.0.6)
692 version: 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(ioredis@5.11.0)(utf-8-validate@6.0.6)
693693 '@effect/vitest':
694694 specifier: 4.0.0-beta.103
695 version: 4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
695 version: 4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
696696 '@types/node':
697697 specifier: 24.12.4
698698 version: 24.12.4
......@@ -710,17 +710,17 @@ importers:
710710 dependencies:
711711 '@effect/platform-node':
712712 specifier: 4.0.0-beta.103
713 version: 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(ioredis@5.11.0)(utf-8-validate@6.0.6)
713 version: 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(ioredis@5.11.0)(utf-8-validate@6.0.6)
714714 '@oxlint/plugins':
715715 specifier: ^1.63.0
716716 version: 1.68.0
717717 effect:
718718 specifier: 4.0.0-beta.103
719 version: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
719 version: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
720720 devDependencies:
721721 '@effect/vitest':
722722 specifier: 4.0.0-beta.103
723 version: 4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
723 version: 4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
724724 vite-plus:
725725 specifier: 'catalog:'
726726 version: 0.2.2(@types/node@24.12.4)(bufferutil@4.1.0)(esbuild@0.28.1)(jiti@2.7.0)(msw@2.12.11(@types/node@24.12.4)(typescript@6.0.3))(terser@5.48.0)(typescript@6.0.3)(unrun@0.2.39)(utf-8-validate@6.0.6)(yaml@2.9.0)
......@@ -735,11 +735,11 @@ importers:
735735 version: link:../shared
736736 effect:
737737 specifier: 4.0.0-beta.103
738 version: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
738 version: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
739739 devDependencies:
740740 '@effect/vitest':
741741 specifier: 4.0.0-beta.103
742 version: 4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
742 version: 4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
743743 vite-plus:
744744 specifier: 'catalog:'
745745 version: 0.2.2(@types/node@24.12.4)(bufferutil@4.1.0)(esbuild@0.28.1)(jiti@2.7.0)(msw@2.12.11(@types/node@24.12.4)(typescript@6.0.3))(terser@5.48.0)(typescript@6.0.3)(unrun@0.2.39)(utf-8-validate@6.0.6)(yaml@2.9.0)
......@@ -748,11 +748,11 @@ importers:
748748 dependencies:
749749 effect:
750750 specifier: 4.0.0-beta.103
751 version: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
751 version: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
752752 devDependencies:
753753 '@effect/vitest':
754754 specifier: 4.0.0-beta.103
755 version: 4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
755 version: 4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
756756 vite-plus:
757757 specifier: 'catalog:'
758758 version: 0.2.2(@types/node@24.12.4)(bufferutil@4.1.0)(esbuild@0.28.1)(jiti@2.7.0)(msw@2.12.11(@types/node@24.12.4)(typescript@6.0.3))(terser@5.48.0)(typescript@6.0.3)(unrun@0.2.39)(utf-8-validate@6.0.6)(yaml@2.9.0)
......@@ -761,17 +761,17 @@ importers:
761761 dependencies:
762762 effect:
763763 specifier: 4.0.0-beta.103
764 version: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
764 version: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
765765 devDependencies:
766766 '@effect/openapi-generator':
767767 specifier: 'catalog:'
768 version: 4.0.0-beta.103(@effect/platform-node@4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(ioredis@5.11.0)(utf-8-validate@6.0.6))(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
768 version: 4.0.0-beta.103(@effect/platform-node@4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(ioredis@5.11.0)(utf-8-validate@6.0.6))(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
769769 '@effect/platform-node':
770770 specifier: 4.0.0-beta.103
771 version: 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(ioredis@5.11.0)(utf-8-validate@6.0.6)
771 version: 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(ioredis@5.11.0)(utf-8-validate@6.0.6)
772772 '@effect/vitest':
773773 specifier: 4.0.0-beta.103
774 version: 4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
774 version: 4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
775775 '@types/node':
776776 specifier: 24.12.4
777777 version: 24.12.4
......@@ -783,17 +783,17 @@ importers:
783783 dependencies:
784784 effect:
785785 specifier: 4.0.0-beta.103
786 version: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
786 version: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
787787 devDependencies:
788788 '@effect/openapi-generator':
789789 specifier: 'catalog:'
790 version: 4.0.0-beta.103(@effect/platform-node@4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(ioredis@5.11.0)(utf-8-validate@6.0.6))(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
790 version: 4.0.0-beta.103(@effect/platform-node@4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(ioredis@5.11.0)(utf-8-validate@6.0.6))(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
791791 '@effect/platform-node':
792792 specifier: 4.0.0-beta.103
793 version: 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(ioredis@5.11.0)(utf-8-validate@6.0.6)
793 version: 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(ioredis@5.11.0)(utf-8-validate@6.0.6)
794794 '@effect/vitest':
795795 specifier: 4.0.0-beta.103
796 version: 4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
796 version: 4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
797797 '@types/node':
798798 specifier: 24.12.4
799799 version: 24.12.4
......@@ -814,7 +814,7 @@ importers:
814814 version: link:../contracts
815815 effect:
816816 specifier: 4.0.0-beta.103
817 version: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
817 version: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
818818 jose:
819819 specifier: 'catalog:'
820820 version: 6.2.2
......@@ -824,10 +824,10 @@ importers:
824824 devDependencies:
825825 '@effect/platform-node':
826826 specifier: 4.0.0-beta.103
827 version: 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(ioredis@5.11.0)(utf-8-validate@6.0.6)
827 version: 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(ioredis@5.11.0)(utf-8-validate@6.0.6)
828828 '@effect/vitest':
829829 specifier: 4.0.0-beta.103
830 version: 4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
830 version: 4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
831831 '@types/node':
832832 specifier: 24.12.4
833833 version: 24.12.4
......@@ -845,14 +845,14 @@ importers:
845845 version: link:../shared
846846 effect:
847847 specifier: 4.0.0-beta.103
848 version: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
848 version: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
849849 devDependencies:
850850 '@effect/platform-node':
851851 specifier: 4.0.0-beta.103
852 version: 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(ioredis@5.11.0)(utf-8-validate@6.0.6)
852 version: 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(ioredis@5.11.0)(utf-8-validate@6.0.6)
853853 '@effect/vitest':
854854 specifier: 4.0.0-beta.103
855 version: 4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
855 version: 4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
856856 '@types/node':
857857 specifier: 24.12.4
858858 version: 24.12.4
......@@ -864,17 +864,17 @@ importers:
864864 dependencies:
865865 '@effect/platform-node':
866866 specifier: 4.0.0-beta.103
867 version: 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(ioredis@5.11.0)(utf-8-validate@6.0.6)
867 version: 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(ioredis@5.11.0)(utf-8-validate@6.0.6)
868868 '@t3tools/shared':
869869 specifier: workspace:*
870870 version: link:../shared
871871 effect:
872872 specifier: 4.0.0-beta.103
873 version: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
873 version: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
874874 devDependencies:
875875 '@effect/vitest':
876876 specifier: 4.0.0-beta.103
877 version: 4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
877 version: 4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
878878 '@types/node':
879879 specifier: 24.12.4
880880 version: 24.12.4
......@@ -886,7 +886,7 @@ importers:
886886 dependencies:
887887 '@effect/platform-node':
888888 specifier: 4.0.0-beta.103
889 version: 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(ioredis@5.11.0)(utf-8-validate@6.0.6)
889 version: 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(ioredis@5.11.0)(utf-8-validate@6.0.6)
890890 '@t3tools/contracts':
891891 specifier: workspace:*
892892 version: link:../packages/contracts
......@@ -898,7 +898,7 @@ importers:
898898 version: link:../packages/tailscale
899899 effect:
900900 specifier: 4.0.0-beta.103
901 version: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
901 version: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
902902 pngjs:
903903 specifier: 7.0.0
904904 version: 7.0.0
......@@ -908,7 +908,7 @@ importers:
908908 devDependencies:
909909 '@effect/vitest':
910910 specifier: 4.0.0-beta.103
911 version: 4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
911 version: 4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
912912 '@types/pngjs':
913913 specifier: 6.0.5
914914 version: 6.0.5
......@@ -5947,6 +5947,7 @@ packages:
59475947
59485948 crypto-js@4.2.0:
59495949 resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==}
5950 deprecated: Active development of CryptoJS has been discontinued. This library is no longer maintained.
59505951
59515952 css-select@5.2.2:
59525953 resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==}
......@@ -11640,24 +11641,24 @@ snapshots:
1164011641
1164111642 '@cloudflare/workers-types@5.20260726.1': {}
1164211643
11643 '@distilled.cloud/aws@0.30.2(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))':
11644 '@distilled.cloud/aws@0.30.2(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))':
1164411645 dependencies:
1164511646 '@aws-crypto/crc32': 5.2.0
1164611647 '@aws-crypto/util': 5.2.0
1164711648 '@aws-sdk/credential-providers': 3.1062.0
1164811649 '@aws-sdk/types': 3.973.10
11649 '@distilled.cloud/core': 0.30.2(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
11650 '@distilled.cloud/core': 0.30.2(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
1165011651 '@smithy/shared-ini-file-loader': 4.5.6
1165111652 '@smithy/types': 4.14.3
1165211653 '@smithy/util-base64': 4.4.6
1165311654 aws4fetch: 1.0.20
11654 effect: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
11655 effect: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
1165511656 fast-xml-parser: 5.8.0
1165611657
11657 '@distilled.cloud/axiom@0.30.2(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))':
11658 '@distilled.cloud/axiom@0.30.2(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))':
1165811659 dependencies:
11659 '@distilled.cloud/core': 0.30.2(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
11660 effect: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
11660 '@distilled.cloud/core': 0.30.2(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
11661 effect: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
1166111662
1166211663 '@distilled.cloud/cloudflare-rolldown-plugin@0.13.10(@voidzero-dev/vite-plus-core@0.2.2(@types/node@24.12.4)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(typescript@6.0.3)(unrun@0.2.39)(yaml@2.9.0))(rolldown@1.1.5)(workerd@1.20260704.1)':
1166311664 dependencies:
......@@ -11670,48 +11671,48 @@ snapshots:
1167011671 transitivePeerDependencies:
1167111672 - workerd
1167211673
11673 '@distilled.cloud/cloudflare-runtime@0.13.10(@distilled.cloud/cloudflare@0.30.2(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)))(@effect/platform-bun@4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(utf-8-validate@6.0.6))(@effect/platform-node@4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(ioredis@5.11.0)(utf-8-validate@6.0.6))(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))':
11674 '@distilled.cloud/cloudflare-runtime@0.13.10(@distilled.cloud/cloudflare@0.30.2(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)))(@effect/platform-bun@4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(utf-8-validate@6.0.6))(@effect/platform-node@4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(ioredis@5.11.0)(utf-8-validate@6.0.6))(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))':
1167411675 dependencies:
1167511676 '@alchemy.run/node-utils': 0.0.5
11676 '@distilled.cloud/cloudflare': 0.30.2(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
11677 effect: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
11677 '@distilled.cloud/cloudflare': 0.30.2(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
11678 effect: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
1167811679 workerd: 1.20260704.1
1167911680 optionalDependencies:
11680 '@effect/platform-bun': 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(utf-8-validate@6.0.6)
11681 '@effect/platform-node': 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(ioredis@5.11.0)(utf-8-validate@6.0.6)
11681 '@effect/platform-bun': 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(utf-8-validate@6.0.6)
11682 '@effect/platform-node': 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(ioredis@5.11.0)(utf-8-validate@6.0.6)
1168211683
11683 '@distilled.cloud/cloudflare-vite-plugin@0.13.10(8bf551e378e9cbc11f8bf1003fbc14a8)':
11684 '@distilled.cloud/cloudflare-vite-plugin@0.13.10(f97c3167f1a1990dddb83bff73e575e5)':
1168411685 dependencies:
11685 '@distilled.cloud/cloudflare': 0.30.2(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
11686 '@distilled.cloud/cloudflare': 0.30.2(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
1168611687 '@distilled.cloud/cloudflare-rolldown-plugin': 0.13.10(@voidzero-dev/vite-plus-core@0.2.2(@types/node@24.12.4)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(typescript@6.0.3)(unrun@0.2.39)(yaml@2.9.0))(rolldown@1.1.5)(workerd@1.20260704.1)
11687 '@distilled.cloud/cloudflare-runtime': 0.13.10(@distilled.cloud/cloudflare@0.30.2(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)))(@effect/platform-bun@4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(utf-8-validate@6.0.6))(@effect/platform-node@4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(ioredis@5.11.0)(utf-8-validate@6.0.6))(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
11688 effect: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
11688 '@distilled.cloud/cloudflare-runtime': 0.13.10(@distilled.cloud/cloudflare@0.30.2(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)))(@effect/platform-bun@4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(utf-8-validate@6.0.6))(@effect/platform-node@4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(ioredis@5.11.0)(utf-8-validate@6.0.6))(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
11689 effect: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
1168911690 vite: '@voidzero-dev/vite-plus-core@0.2.2(@types/node@24.12.4)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(typescript@6.0.3)(unrun@0.2.39)(yaml@2.9.0)'
1169011691 optionalDependencies:
11691 '@effect/platform-bun': 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(utf-8-validate@6.0.6)
11692 '@effect/platform-node': 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(ioredis@5.11.0)(utf-8-validate@6.0.6)
11692 '@effect/platform-bun': 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(utf-8-validate@6.0.6)
11693 '@effect/platform-node': 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(ioredis@5.11.0)(utf-8-validate@6.0.6)
1169311694 transitivePeerDependencies:
1169411695 - rolldown
1169511696 - workerd
1169611697
11697 '@distilled.cloud/cloudflare@0.30.2(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))':
11698 '@distilled.cloud/cloudflare@0.30.2(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))':
1169811699 dependencies:
11699 '@distilled.cloud/core': 0.30.2(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
11700 effect: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
11700 '@distilled.cloud/core': 0.30.2(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
11701 effect: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
1170111702
11702 '@distilled.cloud/core@0.30.2(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))':
11703 '@distilled.cloud/core@0.30.2(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))':
1170311704 dependencies:
11704 effect: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
11705 effect: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
1170511706
11706 '@distilled.cloud/neon@0.30.2(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))':
11707 '@distilled.cloud/neon@0.30.2(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))':
1170711708 dependencies:
11708 '@distilled.cloud/core': 0.30.2(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
11709 effect: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
11709 '@distilled.cloud/core': 0.30.2(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
11710 effect: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
1171011711
11711 '@distilled.cloud/planetscale@0.30.2(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))':
11712 '@distilled.cloud/planetscale@0.30.2(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))':
1171211713 dependencies:
11713 '@distilled.cloud/core': 0.30.2(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
11714 effect: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
11714 '@distilled.cloud/core': 0.30.2(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
11715 effect: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
1171511716
1171611717 '@dnd-kit/accessibility@3.1.1(react@19.2.6)':
1171711718 dependencies:
......@@ -11747,47 +11748,47 @@ snapshots:
1174711748
1174811749 '@drizzle-team/brocli@0.12.0': {}
1174911750
11750 '@effect/atom-react@4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(react@19.2.3)(scheduler@0.27.0)':
11751 '@effect/atom-react@4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(react@19.2.3)(scheduler@0.27.0)':
1175111752 dependencies:
11752 effect: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
11753 effect: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
1175311754 react: 19.2.3
1175411755 scheduler: 0.27.0
1175511756
11756 '@effect/atom-react@4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(react@19.2.6)(scheduler@0.27.0)':
11757 '@effect/atom-react@4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(react@19.2.6)(scheduler@0.27.0)':
1175711758 dependencies:
11758 effect: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
11759 effect: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
1175911760 react: 19.2.6
1176011761 scheduler: 0.27.0
1176111762
11762 '@effect/openapi-generator@4.0.0-beta.103(@effect/platform-node@4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(ioredis@5.11.0)(utf-8-validate@6.0.6))(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))':
11763 '@effect/openapi-generator@4.0.0-beta.103(@effect/platform-node@4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(ioredis@5.11.0)(utf-8-validate@6.0.6))(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))':
1176311764 dependencies:
11764 '@effect/platform-node': 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(ioredis@5.11.0)(utf-8-validate@6.0.6)
11765 effect: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
11765 '@effect/platform-node': 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(ioredis@5.11.0)(utf-8-validate@6.0.6)
11766 effect: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
1176611767 swagger2openapi: 7.0.8
1176711768 transitivePeerDependencies:
1176811769 - encoding
1176911770
11770 '@effect/platform-bun@4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(utf-8-validate@6.0.6)':
11771 '@effect/platform-bun@4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(utf-8-validate@6.0.6)':
1177111772 dependencies:
11772 '@effect/platform-node-shared': 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(utf-8-validate@6.0.6)
11773 effect: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
11773 '@effect/platform-node-shared': 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(utf-8-validate@6.0.6)
11774 effect: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
1177411775 transitivePeerDependencies:
1177511776 - bufferutil
1177611777 - utf-8-validate
1177711778
11778 '@effect/platform-node-shared@4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(utf-8-validate@6.0.6)':
11779 '@effect/platform-node-shared@4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(utf-8-validate@6.0.6)':
1177911780 dependencies:
1178011781 '@types/ws': 8.18.1
11781 effect: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
11782 effect: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
1178211783 ws: 8.21.0(bufferutil@4.1.0)(utf-8-validate@6.0.6)
1178311784 transitivePeerDependencies:
1178411785 - bufferutil
1178511786 - utf-8-validate
1178611787
11787 '@effect/platform-node@4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(ioredis@5.11.0)(utf-8-validate@6.0.6)':
11788 '@effect/platform-node@4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(ioredis@5.11.0)(utf-8-validate@6.0.6)':
1178811789 dependencies:
11789 '@effect/platform-node-shared': 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(utf-8-validate@6.0.6)
11790 effect: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
11790 '@effect/platform-node-shared': 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(utf-8-validate@6.0.6)
11791 effect: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
1179111792 ioredis: 5.11.0
1179211793 mime: 4.1.0
1179311794 undici: 8.9.0
......@@ -11795,14 +11796,14 @@ snapshots:
1179511796 - bufferutil
1179611797 - utf-8-validate
1179711798
11798 '@effect/sql-d1@4.0.0-beta.101(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))':
11799 '@effect/sql-d1@4.0.0-beta.101(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))':
1179911800 dependencies:
1180011801 '@cloudflare/workers-types': 5.20260726.1
11801 effect: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
11802 effect: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
1180211803
11803 '@effect/sql-pg@4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))':
11804 '@effect/sql-pg@4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))':
1180411805 dependencies:
11805 effect: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
11806 effect: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
1180611807 pg: 8.22.0
1180711808 pg-connection-string: 2.14.0
1180811809 pg-cursor: 2.21.0(pg@8.22.0)
......@@ -11811,9 +11812,9 @@ snapshots:
1181111812 transitivePeerDependencies:
1181211813 - pg-native
1181311814
11814 '@effect/sql-sqlite-bun@4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))':
11815 '@effect/sql-sqlite-bun@4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))':
1181511816 dependencies:
11816 effect: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
11817 effect: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
1181711818
1181811819 '@effect/tsgo-darwin-arm64@0.13.2':
1181911820 optional: true
......@@ -11846,9 +11847,9 @@ snapshots:
1184611847 '@effect/tsgo-win32-arm64': 0.13.2
1184711848 '@effect/tsgo-win32-x64': 0.13.2
1184811849
11849 '@effect/vitest@4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))':
11850 '@effect/vitest@4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))':
1185011851 dependencies:
11851 effect: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
11852 effect: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
1185211853
1185311854 '@egjs/hammerjs@2.0.17':
1185411855 dependencies:
......@@ -15350,22 +15351,22 @@ snapshots:
1535015351 json-schema-traverse: 1.0.0
1535115352 require-from-string: 2.0.2
1535215353
15353 alchemy@2.0.0-beta.65(a455401069e1fee89f31a277c51247f6):
15354 alchemy@2.0.0-beta.65(75567d8add6e3362e26fe00f83a97bee):
1535415355 dependencies:
1535515356 '@alchemy.run/node-utils': 0.0.5
1535615357 '@aws-sdk/credential-providers': 3.1062.0
1535715358 '@clack/prompts': 0.11.0
15358 '@distilled.cloud/aws': 0.30.2(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
15359 '@distilled.cloud/axiom': 0.30.2(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
15360 '@distilled.cloud/cloudflare': 0.30.2(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
15359 '@distilled.cloud/aws': 0.30.2(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
15360 '@distilled.cloud/axiom': 0.30.2(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
15361 '@distilled.cloud/cloudflare': 0.30.2(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
1536115362 '@distilled.cloud/cloudflare-rolldown-plugin': 0.13.10(@voidzero-dev/vite-plus-core@0.2.2(@types/node@24.12.4)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(typescript@6.0.3)(unrun@0.2.39)(yaml@2.9.0))(rolldown@1.1.5)(workerd@1.20260704.1)
15362 '@distilled.cloud/cloudflare-runtime': 0.13.10(@distilled.cloud/cloudflare@0.30.2(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)))(@effect/platform-bun@4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(utf-8-validate@6.0.6))(@effect/platform-node@4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(ioredis@5.11.0)(utf-8-validate@6.0.6))(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
15363 '@distilled.cloud/cloudflare-vite-plugin': 0.13.10(8bf551e378e9cbc11f8bf1003fbc14a8)
15364 '@distilled.cloud/core': 0.30.2(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
15365 '@distilled.cloud/neon': 0.30.2(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
15366 '@distilled.cloud/planetscale': 0.30.2(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
15367 '@effect/sql-d1': 4.0.0-beta.101(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
15368 '@effect/vitest': 4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
15363 '@distilled.cloud/cloudflare-runtime': 0.13.10(@distilled.cloud/cloudflare@0.30.2(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)))(@effect/platform-bun@4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(utf-8-validate@6.0.6))(@effect/platform-node@4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(ioredis@5.11.0)(utf-8-validate@6.0.6))(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
15364 '@distilled.cloud/cloudflare-vite-plugin': 0.13.10(f97c3167f1a1990dddb83bff73e575e5)
15365 '@distilled.cloud/core': 0.30.2(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
15366 '@distilled.cloud/neon': 0.30.2(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
15367 '@distilled.cloud/planetscale': 0.30.2(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
15368 '@effect/sql-d1': 4.0.0-beta.101(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
15369 '@effect/vitest': 4.0.0-beta.103(patch_hash=a16b1e870d8c29e4a98b17cc4c638a4ff471753d8ca3487f78a22b759caf951b)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
1536915370 '@libsql/client': 0.17.3(bufferutil@4.1.0)(utf-8-validate@6.0.6)
1537015371 '@octokit/rest': 22.0.1
1537115372 '@octokit/webhooks': 14.2.0
......@@ -15375,7 +15376,7 @@ snapshots:
1537515376 '@types/aws-lambda': 8.10.161
1537615377 aws4fetch: 1.0.20
1537715378 capnweb: 0.6.1
15378 effect: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
15379 effect: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
1537915380 fast-glob: 3.3.3
1538015381 fast-xml-parser: 5.8.0
1538115382 ink: 6.8.0(@types/react@19.2.16)(bufferutil@4.1.0)(react-devtools-core@6.1.5(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react@19.2.6)(utf-8-validate@6.0.6)
......@@ -15391,11 +15392,11 @@ snapshots:
1539115392 undici: 7.27.1
1539215393 yaml: 2.9.0
1539315394 optionalDependencies:
15394 '@effect/platform-bun': 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(utf-8-validate@6.0.6)
15395 '@effect/platform-node': 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(ioredis@5.11.0)(utf-8-validate@6.0.6)
15396 '@effect/sql-pg': 4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
15395 '@effect/platform-bun': 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(utf-8-validate@6.0.6)
15396 '@effect/platform-node': 4.0.0-beta.103(bufferutil@4.1.0)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(ioredis@5.11.0)(utf-8-validate@6.0.6)
15397 '@effect/sql-pg': 4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
1539715398 drizzle-kit: 1.0.0-rc.4
15398 drizzle-orm: 1.0.0-rc.4(@cloudflare/workers-types@4.20260604.1)(@effect/sql-d1@4.0.0-beta.101(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)))(@effect/sql-pg@4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)))(@effect/sql-sqlite-bun@4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)))(@libsql/client@0.17.3(bufferutil@4.1.0)(utf-8-validate@6.0.6))(bun-types@1.3.14)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(expo-sqlite@56.0.5(expo@56.0.12)(react-native@0.85.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6))(mysql2@3.22.4(@types/node@24.12.4))(pg@8.21.0)(zod@4.4.3)
15399 drizzle-orm: 1.0.0-rc.4(@cloudflare/workers-types@4.20260604.1)(@effect/sql-d1@4.0.0-beta.101(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)))(@effect/sql-pg@4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)))(@effect/sql-sqlite-bun@4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)))(@libsql/client@0.17.3(bufferutil@4.1.0)(utf-8-validate@6.0.6))(bun-types@1.3.14)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(expo-sqlite@56.0.5(expo@56.0.12)(react-native@0.85.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6))(mysql2@3.22.4(@types/node@24.12.4))(pg@8.21.0)(zod@4.4.3)
1539915400 vite: '@voidzero-dev/vite-plus-core@0.2.2(@types/node@24.12.4)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(typescript@6.0.3)(unrun@0.2.39)(yaml@2.9.0)'
1540015401 ws: 8.21.0(bufferutil@4.1.0)(utf-8-validate@6.0.6)
1540115402 transitivePeerDependencies:
......@@ -16418,15 +16419,15 @@ snapshots:
1641816419 get-tsconfig: 4.14.0
1641916420 jiti: 2.7.0
1642016421
16421 drizzle-orm@1.0.0-rc.4(@cloudflare/workers-types@4.20260604.1)(@effect/sql-d1@4.0.0-beta.101(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)))(@effect/sql-pg@4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)))(@effect/sql-sqlite-bun@4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)))(@libsql/client@0.17.3(bufferutil@4.1.0)(utf-8-validate@6.0.6))(bun-types@1.3.14)(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))(expo-sqlite@56.0.5(expo@56.0.12)(react-native@0.85.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6))(mysql2@3.22.4(@types/node@24.12.4))(pg@8.21.0)(zod@4.4.3):
16422 drizzle-orm@1.0.0-rc.4(@cloudflare/workers-types@4.20260604.1)(@effect/sql-d1@4.0.0-beta.101(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)))(@effect/sql-pg@4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)))(@effect/sql-sqlite-bun@4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)))(@libsql/client@0.17.3(bufferutil@4.1.0)(utf-8-validate@6.0.6))(bun-types@1.3.14)(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))(expo-sqlite@56.0.5(expo@56.0.12)(react-native@0.85.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6))(mysql2@3.22.4(@types/node@24.12.4))(pg@8.21.0)(zod@4.4.3):
1642216423 optionalDependencies:
1642316424 '@cloudflare/workers-types': 4.20260604.1
16424 '@effect/sql-d1': 4.0.0-beta.101(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
16425 '@effect/sql-pg': 4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
16426 '@effect/sql-sqlite-bun': 4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9))
16425 '@effect/sql-d1': 4.0.0-beta.101(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
16426 '@effect/sql-pg': 4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
16427 '@effect/sql-sqlite-bun': 4.0.0-beta.103(effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6))
1642716428 '@libsql/client': 0.17.3(bufferutil@4.1.0)(utf-8-validate@6.0.6)
1642816429 bun-types: 1.3.14
16429 effect: 4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9)
16430 effect: 4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6)
1643016431 expo-sqlite: 56.0.5(expo@56.0.12)(react-native@0.85.3(@babel/core@7.29.7)(@react-native/metro-config@0.85.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6)
1643116432 mysql2: 3.22.4(@types/node@24.12.4)
1643216433 pg: 8.21.0
......@@ -16446,7 +16447,7 @@ snapshots:
1644616447
1644716448 ee-first@1.1.1: {}
1644816449
16449 effect@4.0.0-beta.103(patch_hash=a18f963109656ddbeb2a99ca45f942ecf54830986259eb01ce6a970421c9c6a9):
16450 effect@4.0.0-beta.103(patch_hash=af36b7948b6f9c56623074662b51dade5699880c1a7c71245de73e13c3185fb6):
1645016451 dependencies:
1645116452 '@standard-schema/spec': 1.1.0
1645216453 fast-check: 4.9.0