vorma 0.85.0-pre.12 → 0.85.0-pre.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/.dist/vorma/core/_index.d.ts +6 -4
  2. package/.dist/vorma/core/_index.d.ts.map +1 -1
  3. package/.dist/vorma/core/_index.js +29 -13
  4. package/.dist/vorma/core/_index.js.map +1 -1
  5. package/.dist/vorma/tsx/preact/preact.d.ts +1 -0
  6. package/.dist/vorma/tsx/preact/preact.d.ts.map +1 -1
  7. package/.dist/vorma/tsx/react/react.d.ts +1 -0
  8. package/.dist/vorma/tsx/react/react.d.ts.map +1 -1
  9. package/.dist/vorma/tsx/remix/remix.d.ts +1 -0
  10. package/.dist/vorma/tsx/remix/remix.d.ts.map +1 -1
  11. package/.dist/vorma/tsx/solid/solid.d.ts +1 -0
  12. package/.dist/vorma/tsx/solid/solid.d.ts.map +1 -1
  13. package/package.json +1 -1
  14. package/vorma/core/ccc_effect_experiment_notes.md +4 -0
  15. package/vorma/core/create_client_core.ts +49 -14
  16. package/vorma/core/create_client_core_effect.ts +16 -14
  17. package/vorma/core/effect_runtime/client_contract.ts +4 -4
  18. package/vorma/core/effect_runtime/client_kernel_assembly.ts +1 -0
  19. package/vorma/core/effect_runtime/client_navigation_services.ts +6 -2
  20. package/vorma/core/effect_runtime/client_session.ts +57 -0
  21. package/vorma/core/effect_runtime/index.ts +1 -0
  22. package/vorma/core/effect_runtime/revalidation_coordinator.ts +56 -24
  23. package/vorma/core/effect_runtime/route_revalidator.ts +6 -3
  24. package/vorma/core/effect_runtime/submit_manager.ts +35 -11
  25. package/vorma/core/effect_runtime/work_indicator.ts +13 -6
  26. package/vorma/core/effect_runtime/work_state_actor.ts +25 -5
  27. package/vorma/core/make_link_props.ts +16 -0
  28. package/vorma/core/types.ts +1 -0
  29. package/vorma/core/ui_adapter_core.ts +1 -0
  30. package/vorma/create/package.json +1 -1
@@ -19,6 +19,7 @@ type LinkPropsBase = {
19
19
  visitOnPointerDown?: boolean;
20
20
  replace?: boolean;
21
21
  scrollToTop?: boolean;
22
+ skipWorkIndicator?: boolean;
22
23
  };
23
24
  //#endregion
24
25
  //#region vorma/tsx/preact/preact.d.ts
@@ -1 +1 @@
1
- {"version":3,"file":"preact.d.ts","names":[],"sources":["../../../../vorma/core/types.ts","../../../../vorma/tsx/preact/preact.tsx"],"mappings":";;;;;KAqFY,uBAAA;EAET,IAAA;EACA,aAAA;EACA,WAAA;AAAA;EAGA,IAAA;EACA,aAAA;EACA,WAAA;AAAA;AAAA,KAGS,aAAA;EACX,QAAA;EACA,eAAA;EACA,mBAAA,GAAsB,uBAAA;EACtB,kBAAA;EACA,OAAA;EACA,WAAA;AAAA;;;KCjBI,wBAAA,WAAmC,SAAA,IACvC,oBAAA,CAAqB,aAAA;EACpB,gBAAA,GAAmB,OAAA,CAClB,IAAA,CAAK,cAAA,CAAe,iBAAA,IAAqB,aAAA;EAE1C,YAAA,GAAe,gBAAA,CAAe,CAAA;AAAA;AAAA,iBAGhB,iBAAA,WAA4B,SAAA,CAAA,CAC3C,UAAA,EAAY,CAAA,EACZ,OAAA,GAAU,wBAAA,CAAyB,CAAA,IACjC,WAAA,CAAY,CAAA,EAAG,GAAA,CAAI,OAAA,EAAS,cAAA,CAAe,iBAAA"}
1
+ {"version":3,"file":"preact.d.ts","names":[],"sources":["../../../../vorma/core/types.ts","../../../../vorma/tsx/preact/preact.tsx"],"mappings":";;;;;KAqFY,uBAAA;EAET,IAAA;EACA,aAAA;EACA,WAAA;AAAA;EAGA,IAAA;EACA,aAAA;EACA,WAAA;AAAA;AAAA,KAGS,aAAA;EACX,QAAA;EACA,eAAA;EACA,mBAAA,GAAsB,uBAAA;EACtB,kBAAA;EACA,OAAA;EACA,WAAA;EACA,iBAAA;AAAA;;;KClBI,wBAAA,WAAmC,SAAA,IACvC,oBAAA,CAAqB,aAAA;EACpB,gBAAA,GAAmB,OAAA,CAClB,IAAA,CAAK,cAAA,CAAe,iBAAA,IAAqB,aAAA;EAE1C,YAAA,GAAe,gBAAA,CAAe,CAAA;AAAA;AAAA,iBAGhB,iBAAA,WAA4B,SAAA,CAAA,CAC3C,UAAA,EAAY,CAAA,EACZ,OAAA,GAAU,wBAAA,CAAyB,CAAA,IACjC,WAAA,CAAY,CAAA,EAAG,GAAA,CAAI,OAAA,EAAS,cAAA,CAAe,iBAAA"}
@@ -18,6 +18,7 @@ type LinkPropsBase = {
18
18
  visitOnPointerDown?: boolean;
19
19
  replace?: boolean;
20
20
  scrollToTop?: boolean;
21
+ skipWorkIndicator?: boolean;
21
22
  };
22
23
  //#endregion
23
24
  //#region vorma/tsx/react/react.d.ts
@@ -1 +1 @@
1
- {"version":3,"file":"react.d.ts","names":[],"sources":["../../../../vorma/core/types.ts","../../../../vorma/tsx/react/react.tsx"],"mappings":";;;;KAqFY,uBAAA;EAET,IAAA;EACA,aAAA;EACA,WAAA;AAAA;EAGA,IAAA;EACA,aAAA;EACA,WAAA;AAAA;AAAA,KAGS,aAAA;EACX,QAAA;EACA,eAAA;EACA,mBAAA,GAAsB,uBAAA;EACtB,kBAAA;EACA,OAAA;EACA,WAAA;AAAA;;;KClBI,wBAAA,WAAmC,SAAA,IACvC,oBAAA,CAAqB,aAAA;EACpB,gBAAA,GAAmB,OAAA,CAClB,IAAA,CAAK,cAAA,QAAsB,aAAA;EAE5B,YAAA,GAAe,gBAAA,CAAe,CAAA;AAAA;AAAA,iBAGhB,iBAAA,WAA4B,SAAA,CAAA,CAC3C,UAAA,EAAY,CAAA,EACZ,OAAA,GAAU,wBAAA,CAAyB,CAAA,IACjC,WAAA,CAAY,CAAA,EAAG,GAAA,CAAI,OAAA,EAAS,cAAA"}
1
+ {"version":3,"file":"react.d.ts","names":[],"sources":["../../../../vorma/core/types.ts","../../../../vorma/tsx/react/react.tsx"],"mappings":";;;;KAqFY,uBAAA;EAET,IAAA;EACA,aAAA;EACA,WAAA;AAAA;EAGA,IAAA;EACA,aAAA;EACA,WAAA;AAAA;AAAA,KAGS,aAAA;EACX,QAAA;EACA,eAAA;EACA,mBAAA,GAAsB,uBAAA;EACtB,kBAAA;EACA,OAAA;EACA,WAAA;EACA,iBAAA;AAAA;;;KCnBI,wBAAA,WAAmC,SAAA,IACvC,oBAAA,CAAqB,aAAA;EACpB,gBAAA,GAAmB,OAAA,CAClB,IAAA,CAAK,cAAA,QAAsB,aAAA;EAE5B,YAAA,GAAe,gBAAA,CAAe,CAAA;AAAA;AAAA,iBAGhB,iBAAA,WAA4B,SAAA,CAAA,CAC3C,UAAA,EAAY,CAAA,EACZ,OAAA,GAAU,wBAAA,CAAyB,CAAA,IACjC,WAAA,CAAY,CAAA,EAAG,GAAA,CAAI,OAAA,EAAS,cAAA"}
@@ -18,6 +18,7 @@ type LinkPropsBase = {
18
18
  visitOnPointerDown?: boolean;
19
19
  replace?: boolean;
20
20
  scrollToTop?: boolean;
21
+ skipWorkIndicator?: boolean;
21
22
  };
22
23
  //#endregion
23
24
  //#region vorma/tsx/remix/remix.d.ts
@@ -1 +1 @@
1
- {"version":3,"file":"remix.d.ts","names":[],"sources":["../../../../vorma/core/types.ts","../../../../vorma/tsx/remix/remix.tsx"],"mappings":"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"}
1
+ {"version":3,"file":"remix.d.ts","names":[],"sources":["../../../../vorma/core/types.ts","../../../../vorma/tsx/remix/remix.tsx"],"mappings":"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"}
@@ -18,6 +18,7 @@ type LinkPropsBase = {
18
18
  visitOnPointerDown?: boolean;
19
19
  replace?: boolean;
20
20
  scrollToTop?: boolean;
21
+ skipWorkIndicator?: boolean;
21
22
  };
22
23
  //#endregion
23
24
  //#region vorma/tsx/solid/solid.d.ts
@@ -1 +1 @@
1
- {"version":3,"file":"solid.d.ts","names":[],"sources":["../../../../vorma/core/types.ts","../../../../vorma/tsx/solid/solid.tsx"],"mappings":";;;;KAqFY,uBAAA;EAET,IAAA;EACA,aAAA;EACA,WAAA;AAAA;EAGA,IAAA;EACA,aAAA;EACA,WAAA;AAAA;AAAA,KAGS,aAAA;EACX,QAAA;EACA,eAAA;EACA,mBAAA,GAAsB,uBAAA;EACtB,kBAAA;EACA,OAAA;EACA,WAAA;AAAA;;;KCfI,wBAAA,WAAmC,SAAA,IACvC,oBAAA,CAAqB,SAAA;EACpB,gBAAA,GAAmB,OAAA,CAClB,IAAA,CACC,GAAA,CAAI,oBAAA,CAAqB,iBAAA,IAAqB,aAAA;EAIhD,YAAA,GAAe,gBAAA,CAAe,CAAA;AAAA;AAAA,iBAGhB,iBAAA,WAA4B,SAAA,CAAA,CAC3C,UAAA,EAAY,CAAA,EACZ,OAAA,GAAU,wBAAA,CAAyB,CAAA,IACjC,WAAA,CACF,CAAA,EACA,GAAA,CAAI,OAAA,EACJ,GAAA,CAAI,oBAAA,CAAqB,iBAAA"}
1
+ {"version":3,"file":"solid.d.ts","names":[],"sources":["../../../../vorma/core/types.ts","../../../../vorma/tsx/solid/solid.tsx"],"mappings":";;;;KAqFY,uBAAA;EAET,IAAA;EACA,aAAA;EACA,WAAA;AAAA;EAGA,IAAA;EACA,aAAA;EACA,WAAA;AAAA;AAAA,KAGS,aAAA;EACX,QAAA;EACA,eAAA;EACA,mBAAA,GAAsB,uBAAA;EACtB,kBAAA;EACA,OAAA;EACA,WAAA;EACA,iBAAA;AAAA;;;KChBI,wBAAA,WAAmC,SAAA,IACvC,oBAAA,CAAqB,SAAA;EACpB,gBAAA,GAAmB,OAAA,CAClB,IAAA,CACC,GAAA,CAAI,oBAAA,CAAqB,iBAAA,IAAqB,aAAA;EAIhD,YAAA,GAAe,gBAAA,CAAe,CAAA;AAAA;AAAA,iBAGhB,iBAAA,WAA4B,SAAA,CAAA,CAC3C,UAAA,EAAY,CAAA,EACZ,OAAA,GAAU,wBAAA,CAAyB,CAAA,IACjC,WAAA,CACF,CAAA,EACA,GAAA,CAAI,OAAA,EACJ,GAAA,CAAI,oBAAA,CAAqB,iBAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vorma",
3
- "version": "0.85.0-pre.12",
3
+ "version": "0.85.0-pre.13",
4
4
  "description": "Vorma seeks to be the world's most straightforward web framework.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -213,6 +213,10 @@ main app API into an Effect doctrine test.
213
213
  - Current-route movement is now kernel behavior. Hash-only movement, optional
214
214
  history replacement, scroll intent, history commits, and route-position
215
215
  publication moved out of the shell and into the Effect kernel.
216
+ - Active kernel replacement now goes through `client_session` instead of a
217
+ module-level shutdown callback. The session owns the active kernel handle,
218
+ closes the previous handle during replacement, and can shut down a specific
219
+ handle only if it is still active.
216
220
  - The compatibility pressure test has expanded beyond `create_client_core` into
217
221
  split runners for `router.test.ts`, `router_revalidation.test.ts`, and
218
222
  `router_submit.test.ts`. Keeping those runners split matters because the
@@ -130,10 +130,10 @@ export type WorkIndicator = {
130
130
  };
131
131
 
132
132
  export type WorkIndicatorOptions = {
133
- show: () => void;
134
- hide: () => void;
135
- showDelayMS?: number;
136
- hideDelayMS?: number;
133
+ start: () => void;
134
+ stop: () => void;
135
+ startDelayMS?: number;
136
+ stopDelayMS?: number;
137
137
  skipNavigations?: boolean;
138
138
  skipAPIRequests?: boolean;
139
139
  skipRevalidations?: boolean;
@@ -411,13 +411,16 @@ function create_work_indicator(): WorkIndicatorController {
411
411
  if (!latest_options || active_tokens.size === 0 || visible) {
412
412
  return;
413
413
  }
414
- latest_options.show();
414
+ latest_options.start();
415
415
  visible = true;
416
- }, current_options.showDelayMS ?? 12);
416
+ }, current_options.startDelayMS ?? 12);
417
417
  return;
418
418
  }
419
419
 
420
420
  clear_show_timer();
421
+ if (!visible) {
422
+ return;
423
+ }
421
424
  if (hide_timer !== undefined) {
422
425
  return;
423
426
  }
@@ -427,9 +430,9 @@ function create_work_indicator(): WorkIndicatorController {
427
430
  if (!latest_options || active_tokens.size > 0) {
428
431
  return;
429
432
  }
430
- latest_options.hide();
433
+ latest_options.stop();
431
434
  visible = false;
432
- }, current_options.hideDelayMS ?? 12);
435
+ }, current_options.stopDelayMS ?? 12);
433
436
  }
434
437
 
435
438
  function begin(): () => void {
@@ -452,7 +455,7 @@ function create_work_indicator(): WorkIndicatorController {
452
455
  clear_show_timer();
453
456
  clear_hide_timer();
454
457
  if (visible && previous_options && previous_options !== next_options) {
455
- previous_options.hide();
458
+ previous_options.stop();
456
459
  visible = false;
457
460
  }
458
461
  options = next_options;
@@ -555,6 +558,7 @@ export function create_client_core(
555
558
  }
556
559
  | {
557
560
  kind: "revalidation";
561
+ skip_work_indicator?: boolean;
558
562
  }
559
563
  | {
560
564
  kind: "apiRequest";
@@ -592,6 +596,7 @@ export function create_client_core(
592
596
  kind: "reval";
593
597
  attempt: number;
594
598
  reason: RevalidationReason;
599
+ skip_work_indicator?: boolean;
595
600
  };
596
601
 
597
602
  type ActiveFetchIntent = NavFetchIntent | RevalidationFetchIntent;
@@ -677,6 +682,7 @@ export function create_client_core(
677
682
  // A fetch with seq > this value satisfies the demand.
678
683
  after_seq: number;
679
684
  reason: RevalidationReason;
685
+ skip_work_indicator?: boolean;
680
686
  waiters: RefreshWaiter[];
681
687
  };
682
688
 
@@ -2192,8 +2198,10 @@ export function create_client_core(
2192
2198
  reason: RevalidationReason,
2193
2199
  waiter?: RefreshWaiter,
2194
2200
  debounce?: boolean,
2201
+ skip_work_indicator?: boolean,
2195
2202
  ): void {
2196
- const waiters = refresh_demand()?.waiters ?? [];
2203
+ const previous_demand = refresh_demand();
2204
+ const waiters = previous_demand?.waiters ?? [];
2197
2205
  clear_refresh();
2198
2206
  if (waiter) {
2199
2207
  waiters.push(waiter);
@@ -2201,6 +2209,9 @@ export function create_client_core(
2201
2209
  const demand: RefreshDemand = {
2202
2210
  after_seq: next_seq(),
2203
2211
  reason,
2212
+ skip_work_indicator:
2213
+ (previous_demand?.skip_work_indicator ?? true) &&
2214
+ skip_work_indicator === true,
2204
2215
  waiters,
2205
2216
  };
2206
2217
 
@@ -2302,7 +2313,15 @@ export function create_client_core(
2302
2313
  const attempt = refresh.kind === "pending" ? refresh.attempt : 0;
2303
2314
  const reason =
2304
2315
  refresh.kind === "pending" ? refresh.demand.reason : "manual";
2305
- const f = start_fetch(url, { kind: "reval", attempt, reason }, true);
2316
+ const skip_work_indicator =
2317
+ refresh.kind === "pending"
2318
+ ? refresh.demand.skip_work_indicator
2319
+ : undefined;
2320
+ const f = start_fetch(
2321
+ url,
2322
+ { kind: "reval", attempt, reason, skip_work_indicator },
2323
+ true,
2324
+ );
2306
2325
 
2307
2326
  // Guard: discard if URL path changes during flight (hash-only changes
2308
2327
  // are OK; matches_without_hash on publish time handles it).
@@ -2591,14 +2610,24 @@ export function create_client_core(
2591
2610
  if (phase === "ready") {
2592
2611
  const waiter = make_deferred<RevalidationResult>();
2593
2612
  revalidation_promise = waiter.promise;
2594
- require_refresh("apiRequest", waiter);
2613
+ require_refresh(
2614
+ "apiRequest",
2615
+ waiter,
2616
+ undefined,
2617
+ options?.skipWorkIndicator,
2618
+ );
2595
2619
  maybe_revalidate();
2596
2620
  } else {
2597
2621
  // During boot, register refresh demand so post-boot
2598
2622
  // maybe_revalidate will fire. Do not attach a waiter;
2599
2623
  // the returned revalidationPromise stays resolved so initial
2600
2624
  // client loaders awaiting it do not deadlock.
2601
- require_refresh("apiRequest");
2625
+ require_refresh(
2626
+ "apiRequest",
2627
+ undefined,
2628
+ undefined,
2629
+ options?.skipWorkIndicator,
2630
+ );
2602
2631
  }
2603
2632
  }
2604
2633
 
@@ -2843,8 +2872,13 @@ export function create_client_core(
2843
2872
  refresh.kind === "retrying" ||
2844
2873
  (!active_will_refresh() && !active));
2845
2874
  if (active_fetch?.intent.kind === "reval" || pending_revalidation) {
2875
+ const revalidation_demand = refresh_demand();
2846
2876
  work.push({
2847
2877
  kind: "revalidation",
2878
+ skip_work_indicator:
2879
+ active_fetch?.intent.kind === "reval"
2880
+ ? active_fetch.intent.skip_work_indicator
2881
+ : revalidation_demand?.skip_work_indicator,
2848
2882
  });
2849
2883
  }
2850
2884
 
@@ -3065,7 +3099,8 @@ export function create_client_core(
3065
3099
  }
3066
3100
  if (
3067
3101
  work.kind === "revalidation" &&
3068
- options.skipRevalidations !== true
3102
+ options.skipRevalidations !== true &&
3103
+ !work.skip_work_indicator
3069
3104
  ) {
3070
3105
  active_for_vorma = true;
3071
3106
  break;
@@ -19,6 +19,7 @@ import {
19
19
  client_runtime_services_to_layer,
20
20
  make_client_runtime_services,
21
21
  } from "./effect_runtime/client_runtime_services.ts";
22
+ import { make_client_session } from "./effect_runtime/client_session.ts";
22
23
  import { type FocusRevalidator } from "./effect_runtime/focus_revalidator.ts";
23
24
  import type { SubmitResult } from "./effect_runtime/submit_manager.ts";
24
25
  import type { WorkIndicatorActivity } from "./effect_runtime/work_state_actor.ts";
@@ -27,7 +28,7 @@ import type { APIRouteKind, AppConfig, RevalidationResult } from "./types.ts";
27
28
  export const EFFECT_CLIENT_BUILD_ID_FIELD = "ClientBuildID";
28
29
  export const EFFECT_DEPLOYMENT_ID_FIELD = "DeploymentID";
29
30
 
30
- let effect_active_kernel_shutdown: (() => Promise<void>) | null = null;
31
+ const effect_client_session = Effect.runSync(make_client_session());
31
32
 
32
33
  export function create_client_core_effect(
33
34
  app_config: Omit<AppConfig, "__vormaViews" | "__vormaAPIRoutes">,
@@ -160,9 +161,15 @@ export function create_client_core_effect(
160
161
  on_provisional_route: (input) => {
161
162
  return boot_route_state.capture(input);
162
163
  },
163
- revalidate_api_request: (route_revalidator) => {
164
+ revalidate_api_request: (
165
+ route_revalidator,
166
+ revalidation_options,
167
+ ) => {
164
168
  return boot_revalidation_gate.request_or_defer(
165
- route_revalidator.request("apiRequest"),
169
+ route_revalidator.request(
170
+ "apiRequest",
171
+ revalidation_options,
172
+ ),
166
173
  );
167
174
  },
168
175
  use_view_transitions: Effect.sync(() => {
@@ -231,10 +238,6 @@ export function create_client_core_effect(
231
238
  const should_revalidate_after_boot = Effect.runSync(
232
239
  boot_revalidation_gate.finish_boot,
233
240
  );
234
- if (effect_active_kernel_shutdown) {
235
- await effect_active_kernel_shutdown();
236
- effect_active_kernel_shutdown = null;
237
- }
238
241
  kernel = next_kernel;
239
242
  focus_revalidator = null;
240
243
  Effect.runSync(boot_route_state.clear);
@@ -251,9 +254,9 @@ export function create_client_core_effect(
251
254
  }),
252
255
  ),
253
256
  );
254
- effect_active_kernel_shutdown = () => {
255
- return run_effect(next_kernel_handle.shutdown);
256
- };
257
+ await run_effect(
258
+ effect_client_session.replace_active(next_kernel_handle),
259
+ );
257
260
  if (options.revalidateOnWindowFocus) {
258
261
  const stale_ms =
259
262
  typeof options.revalidateOnWindowFocus === "object"
@@ -283,10 +286,9 @@ export function create_client_core_effect(
283
286
  ),
284
287
  );
285
288
  if (render_result._tag === "Left") {
286
- if (effect_active_kernel_shutdown) {
287
- await effect_active_kernel_shutdown();
288
- effect_active_kernel_shutdown = null;
289
- }
289
+ await run_effect(
290
+ effect_client_session.shutdown_if_active(next_kernel_handle),
291
+ );
290
292
  return R.err(String(render_result.left));
291
293
  }
292
294
  return R.ok(undefined);
@@ -99,10 +99,10 @@ export type WorkIndicator = {
99
99
  };
100
100
 
101
101
  export type WorkIndicatorOptions = {
102
- show: () => void;
103
- hide: () => void;
104
- showDelayMS?: number;
105
- hideDelayMS?: number;
102
+ start: () => void;
103
+ stop: () => void;
104
+ startDelayMS?: number;
105
+ stopDelayMS?: number;
106
106
  skipNavigations?: boolean;
107
107
  skipAPIRequests?: boolean;
108
108
  skipRevalidations?: boolean;
@@ -42,6 +42,7 @@ export type EffectClientKernelOptions = {
42
42
  }) => Effect.Effect<void>;
43
43
  revalidate_api_request: (
44
44
  route_revalidator: RouteRevalidator,
45
+ options?: { skipWorkIndicator?: boolean },
45
46
  ) => Effect.Effect<RevalidationResult>;
46
47
  use_view_transitions: Effect.Effect<boolean>;
47
48
  };
@@ -87,6 +87,7 @@ export type ClientNavigationServicesOptions = {
87
87
  on_client_redirect: (href: string) => Effect.Effect<void>;
88
88
  revalidate_api_request: (
89
89
  route_revalidator: RouteRevalidator,
90
+ options?: { skipWorkIndicator?: boolean },
90
91
  ) => Effect.Effect<RevalidationResult>;
91
92
  };
92
93
 
@@ -419,8 +420,11 @@ export function make_client_navigation_services(
419
420
  }
420
421
  return options.on_client_redirect(href);
421
422
  },
422
- revalidate: () => {
423
- return options.revalidate_api_request(route_revalidator);
423
+ revalidate: (_reason, revalidation_options) => {
424
+ return options.revalidate_api_request(
425
+ route_revalidator,
426
+ revalidation_options,
427
+ );
424
428
  },
425
429
  report_build_skew: (dispatch, response, default_behavior) => {
426
430
  return build_skew_reporter.report({
@@ -0,0 +1,57 @@
1
+ import { Effect, Ref } from "effect";
2
+ import type { EffectClientKernelHandle } from "./client_kernel_assembly.ts";
3
+
4
+ export type ClientSession = {
5
+ active_handle: Effect.Effect<EffectClientKernelHandle | null>;
6
+ replace_active: (handle: EffectClientKernelHandle) => Effect.Effect<void>;
7
+ shutdown_active: Effect.Effect<void>;
8
+ shutdown_if_active: (
9
+ handle: EffectClientKernelHandle,
10
+ ) => Effect.Effect<void>;
11
+ };
12
+
13
+ export function make_client_session(): Effect.Effect<ClientSession, never> {
14
+ return Effect.gen(function* () {
15
+ const active_ref = yield* Ref.make<EffectClientKernelHandle | null>(
16
+ null,
17
+ );
18
+ const shutdown_handle = (
19
+ handle: EffectClientKernelHandle | null,
20
+ ): Effect.Effect<void> => {
21
+ if (!handle) {
22
+ return Effect.void;
23
+ }
24
+ return handle.shutdown;
25
+ };
26
+ const shutdown_active = Ref.modify(active_ref, (active) => {
27
+ return [active, null];
28
+ }).pipe(Effect.flatMap(shutdown_handle));
29
+ const shutdown_if_active: ClientSession["shutdown_if_active"] = (
30
+ handle,
31
+ ) => {
32
+ return Ref.modify(active_ref, (active) => {
33
+ if (active !== handle) {
34
+ return [null, active];
35
+ }
36
+ return [active, null];
37
+ }).pipe(Effect.flatMap(shutdown_handle));
38
+ };
39
+ const replace_active: ClientSession["replace_active"] = (handle) => {
40
+ return Effect.gen(function* () {
41
+ const previous = yield* Ref.get(active_ref);
42
+ if (previous === handle) {
43
+ return;
44
+ }
45
+ yield* shutdown_handle(previous);
46
+ yield* Ref.set(active_ref, handle);
47
+ });
48
+ };
49
+
50
+ return {
51
+ active_handle: Ref.get(active_ref),
52
+ replace_active,
53
+ shutdown_active,
54
+ shutdown_if_active,
55
+ };
56
+ });
57
+ }
@@ -13,6 +13,7 @@ export * from "./client_kernel_resources.ts";
13
13
  export * from "./client_navigation_services.ts";
14
14
  export * from "./client_route_services.ts";
15
15
  export * from "./client_runtime_services.ts";
16
+ export * from "./client_session.ts";
16
17
  export * from "./focus_revalidator.ts";
17
18
  export * from "./module_runtime.ts";
18
19
  export * from "./navigation_actor.ts";
@@ -36,6 +36,7 @@ export type RevalidationAttemptInput = {
36
36
  seq: number;
37
37
  attempt: number;
38
38
  reason: RevalidationReason;
39
+ skipWorkIndicator: boolean;
39
40
  };
40
41
 
41
42
  export type RevalidationCoordinatorOptions = {
@@ -54,7 +55,7 @@ export type RevalidationCoordinatorOptions = {
54
55
  export type RevalidationCoordinator = {
55
56
  request: (
56
57
  reason: Exclude<RevalidationReason, "retry">,
57
- options?: { debounce?: boolean },
58
+ options?: { debounce?: boolean; skipWorkIndicator?: boolean },
58
59
  ) => Effect.Effect<RevalidationResult>;
59
60
  cancel: (result?: RevalidationResult) => Effect.Effect<void>;
60
61
  snapshot: Effect.Effect<RevalidationCoordinatorSnapshot>;
@@ -68,11 +69,13 @@ export type RevalidationCoordinatorSnapshot = {
68
69
  nextSeq: number;
69
70
  attempt: number;
70
71
  reason: RevalidationReason | null;
72
+ skipWorkIndicator: boolean;
71
73
  };
72
74
 
73
75
  type Waiter = {
74
76
  readonly afterSeq: number;
75
77
  readonly reason: Exclude<RevalidationReason, "retry">;
78
+ readonly skipWorkIndicator: boolean;
76
79
  readonly deferred: Deferred.Deferred<RevalidationResult>;
77
80
  };
78
81
 
@@ -80,12 +83,14 @@ type ActiveRun = {
80
83
  readonly seq: number;
81
84
  readonly attempt: number;
82
85
  readonly reason: RevalidationReason;
86
+ readonly skipWorkIndicator: boolean;
83
87
  readonly fiber: Fiber.RuntimeFiber<void, never>;
84
88
  };
85
89
 
86
90
  type SleepRun = {
87
91
  readonly attempt: number;
88
92
  readonly reason: RevalidationReason;
93
+ readonly skipWorkIndicator: boolean;
89
94
  readonly fiber: Fiber.RuntimeFiber<void, never>;
90
95
  };
91
96
 
@@ -101,6 +106,7 @@ type Command =
101
106
  readonly _tag: "Request";
102
107
  readonly reason: Exclude<RevalidationReason, "retry">;
103
108
  readonly debounce: boolean;
109
+ readonly skipWorkIndicator: boolean;
104
110
  readonly deferred: Deferred.Deferred<RevalidationResult>;
105
111
  }
106
112
  | {
@@ -157,6 +163,17 @@ export function make_revalidation_coordinator(
157
163
  );
158
164
  };
159
165
 
166
+ const skip_work_indicator_from_waiters = (
167
+ waiters: ReadonlyArray<Waiter>,
168
+ ): boolean => {
169
+ return (
170
+ waiters.length > 0 &&
171
+ waiters.every((waiter) => {
172
+ return waiter.skipWorkIndicator;
173
+ })
174
+ );
175
+ };
176
+
160
177
  const model_snapshot = (
161
178
  current: Model,
162
179
  ): RevalidationCoordinatorSnapshot => {
@@ -175,6 +192,10 @@ export function make_revalidation_coordinator(
175
192
  current.active?.attempt ?? current.sleeper?.attempt ?? 0,
176
193
  reason:
177
194
  current.active?.reason ?? current.sleeper?.reason ?? null,
195
+ skipWorkIndicator:
196
+ current.active?.skipWorkIndicator ??
197
+ current.sleeper?.skipWorkIndicator ??
198
+ false,
178
199
  };
179
200
  };
180
201
 
@@ -226,6 +247,7 @@ export function make_revalidation_coordinator(
226
247
  attempt: number,
227
248
  reason: RevalidationReason,
228
249
  delayMS: number,
250
+ skipWorkIndicator: boolean,
229
251
  ): Effect.Effect<SleepRun> => {
230
252
  return Effect.gen(function* () {
231
253
  const fiber = yield* Effect.forkDaemon(
@@ -243,7 +265,7 @@ export function make_revalidation_coordinator(
243
265
  Effect.asVoid,
244
266
  ),
245
267
  );
246
- return { attempt, reason, fiber };
268
+ return { attempt, reason, skipWorkIndicator, fiber };
247
269
  });
248
270
  };
249
271
 
@@ -257,6 +279,7 @@ export function make_revalidation_coordinator(
257
279
  1,
258
280
  reason,
259
281
  cfg.debounceMS,
282
+ skip_work_indicator_from_waiters(current.waiters),
260
283
  );
261
284
  yield* set_model({ ...current, sleeper });
262
285
  });
@@ -271,38 +294,43 @@ export function make_revalidation_coordinator(
271
294
  if (current.waiters.length === 0 || current.active) {
272
295
  return;
273
296
  }
297
+ const skipWorkIndicator = skip_work_indicator_from_waiters(
298
+ current.waiters,
299
+ );
274
300
  yield* cancel_sleep(current);
275
301
  const seq = current.nextSeq + 1;
276
302
  const fiber = yield* Effect.forkDaemon(
277
- options.run({ seq, attempt, reason }).pipe(
278
- Effect.andThen(
279
- Queue.offer(queue, {
280
- _tag: "AttemptSucceeded",
281
- seq,
303
+ options
304
+ .run({ seq, attempt, reason, skipWorkIndicator })
305
+ .pipe(
306
+ Effect.andThen(
307
+ Queue.offer(queue, {
308
+ _tag: "AttemptSucceeded",
309
+ seq,
310
+ }),
311
+ ),
312
+ Effect.catchTag("RevalidationBuildSkew", () => {
313
+ return Queue.offer(queue, {
314
+ _tag: "AttemptBuildSkew",
315
+ seq,
316
+ });
282
317
  }),
318
+ Effect.catchAll(() => {
319
+ return Queue.offer(queue, {
320
+ _tag: "AttemptFailed",
321
+ seq,
322
+ attempt,
323
+ reason,
324
+ });
325
+ }),
326
+ Effect.asVoid,
283
327
  ),
284
- Effect.catchTag("RevalidationBuildSkew", () => {
285
- return Queue.offer(queue, {
286
- _tag: "AttemptBuildSkew",
287
- seq,
288
- });
289
- }),
290
- Effect.catchAll(() => {
291
- return Queue.offer(queue, {
292
- _tag: "AttemptFailed",
293
- seq,
294
- attempt,
295
- reason,
296
- });
297
- }),
298
- Effect.asVoid,
299
- ),
300
328
  );
301
329
  yield* set_model({
302
330
  ...current,
303
331
  nextSeq: seq,
304
332
  sleeper: null,
305
- active: { seq, attempt, reason, fiber },
333
+ active: { seq, attempt, reason, skipWorkIndicator, fiber },
306
334
  });
307
335
  });
308
336
  };
@@ -377,6 +405,7 @@ export function make_revalidation_coordinator(
377
405
  attempt + 1,
378
406
  "retry",
379
407
  backoff_ms(attempt + 1),
408
+ skip_work_indicator_from_waiters(current.waiters),
380
409
  );
381
410
  yield* set_model({
382
411
  ...current,
@@ -400,6 +429,7 @@ export function make_revalidation_coordinator(
400
429
  {
401
430
  afterSeq,
402
431
  reason: command.reason,
432
+ skipWorkIndicator: command.skipWorkIndicator,
403
433
  deferred: command.deferred,
404
434
  },
405
435
  ],
@@ -498,6 +528,8 @@ export function make_revalidation_coordinator(
498
528
  _tag: "Request",
499
529
  reason,
500
530
  debounce: request_options?.debounce === true,
531
+ skipWorkIndicator:
532
+ request_options?.skipWorkIndicator === true,
501
533
  deferred: waiter,
502
534
  });
503
535
  return yield* Deferred.await(waiter);