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.
- package/.dist/vorma/core/_index.d.ts +6 -4
- package/.dist/vorma/core/_index.d.ts.map +1 -1
- package/.dist/vorma/core/_index.js +29 -13
- package/.dist/vorma/core/_index.js.map +1 -1
- package/.dist/vorma/tsx/preact/preact.d.ts +1 -0
- package/.dist/vorma/tsx/preact/preact.d.ts.map +1 -1
- package/.dist/vorma/tsx/react/react.d.ts +1 -0
- package/.dist/vorma/tsx/react/react.d.ts.map +1 -1
- package/.dist/vorma/tsx/remix/remix.d.ts +1 -0
- package/.dist/vorma/tsx/remix/remix.d.ts.map +1 -1
- package/.dist/vorma/tsx/solid/solid.d.ts +1 -0
- package/.dist/vorma/tsx/solid/solid.d.ts.map +1 -1
- package/package.json +1 -1
- package/vorma/core/ccc_effect_experiment_notes.md +4 -0
- package/vorma/core/create_client_core.ts +49 -14
- package/vorma/core/create_client_core_effect.ts +16 -14
- package/vorma/core/effect_runtime/client_contract.ts +4 -4
- package/vorma/core/effect_runtime/client_kernel_assembly.ts +1 -0
- package/vorma/core/effect_runtime/client_navigation_services.ts +6 -2
- package/vorma/core/effect_runtime/client_session.ts +57 -0
- package/vorma/core/effect_runtime/index.ts +1 -0
- package/vorma/core/effect_runtime/revalidation_coordinator.ts +56 -24
- package/vorma/core/effect_runtime/route_revalidator.ts +6 -3
- package/vorma/core/effect_runtime/submit_manager.ts +35 -11
- package/vorma/core/effect_runtime/work_indicator.ts +13 -6
- package/vorma/core/effect_runtime/work_state_actor.ts +25 -5
- package/vorma/core/make_link_props.ts +16 -0
- package/vorma/core/types.ts +1 -0
- package/vorma/core/ui_adapter_core.ts +1 -0
- package/vorma/create/package.json +1 -1
|
@@ -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;;;
|
|
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"}
|
|
@@ -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;;;
|
|
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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remix.d.ts","names":[],"sources":["../../../../vorma/core/types.ts","../../../../vorma/tsx/remix/remix.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;;;
|
|
1
|
+
{"version":3,"file":"remix.d.ts","names":[],"sources":["../../../../vorma/core/types.ts","../../../../vorma/tsx/remix/remix.tsx"],"mappings":"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"}
|
|
@@ -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;;;
|
|
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
|
@@ -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
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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.
|
|
414
|
+
latest_options.start();
|
|
415
415
|
visible = true;
|
|
416
|
-
}, current_options.
|
|
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.
|
|
433
|
+
latest_options.stop();
|
|
431
434
|
visible = false;
|
|
432
|
-
}, current_options.
|
|
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.
|
|
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
|
|
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
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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: (
|
|
164
|
+
revalidate_api_request: (
|
|
165
|
+
route_revalidator,
|
|
166
|
+
revalidation_options,
|
|
167
|
+
) => {
|
|
164
168
|
return boot_revalidation_gate.request_or_defer(
|
|
165
|
-
route_revalidator.request(
|
|
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
|
-
|
|
255
|
-
|
|
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
|
-
|
|
287
|
-
|
|
288
|
-
|
|
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
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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(
|
|
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
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
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);
|