@kiwa-test/component 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/index.cjs +494 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +147 -1
- package/dist/index.d.ts +147 -1
- package/dist/index.js +465 -1
- package/dist/index.js.map +1 -1
- package/package.json +18 -12
package/dist/index.d.ts
CHANGED
|
@@ -531,4 +531,150 @@ declare const buildCard: ComponentRender<CardArgs>;
|
|
|
531
531
|
/** 全 component の render function を 1 record にまとめる (test 一括登録用)。 */
|
|
532
532
|
declare const componentFixtures: Record<string, ComponentRender<Record<string, unknown>>>;
|
|
533
533
|
|
|
534
|
-
|
|
534
|
+
/**
|
|
535
|
+
* Advanced component semantics — target-neutral axis SSOT.
|
|
536
|
+
*
|
|
537
|
+
* The component package spans Storybook 8, Playwright Component Testing, and
|
|
538
|
+
* Chromatic. These helpers model the observable semantics without importing
|
|
539
|
+
* any of those runtimes, so the same axis can be replayed against each target.
|
|
540
|
+
*/
|
|
541
|
+
type ComponentTarget = 'storybook8' | 'playwright-ct' | 'chromatic';
|
|
542
|
+
type ComponentAxis = 'rsc-harness' | 'streaming-ssr' | 'view-transitions' | 'form-action-advanced';
|
|
543
|
+
type NeutralEventName = 'rsc.render_started' | 'rsc.suspense_boundary' | 'rsc.html_chunk_streamed' | 'rsc.render_completed' | 'ssr.suspense_pending' | 'ssr.error_boundary_captured' | 'ssr.progressive_hydration_started' | 'ssr.selective_hydration_completed' | 'transition.element_started' | 'transition.element_finished' | 'transition.document_started' | 'transition.animation_asserted' | 'form.status_pending' | 'form.optimistic_applied' | 'form.progressive_enhanced' | 'form.action_resolved';
|
|
544
|
+
interface AxisStep<TState extends string> {
|
|
545
|
+
neutralEvent: NeutralEventName;
|
|
546
|
+
providerEvent: string;
|
|
547
|
+
state: TState;
|
|
548
|
+
amountCents: number;
|
|
549
|
+
metadata: Record<string, string | number | boolean>;
|
|
550
|
+
}
|
|
551
|
+
declare function providerEventName(target: ComponentTarget, neutral: NeutralEventName): string;
|
|
552
|
+
|
|
553
|
+
type RscHarnessState = 'idle' | 'rendering' | 'suspended' | 'streaming' | 'completed' | 'errored';
|
|
554
|
+
interface RscHarnessSession {
|
|
555
|
+
target: ComponentTarget;
|
|
556
|
+
componentId: string;
|
|
557
|
+
state: RscHarnessState;
|
|
558
|
+
chunks: string[];
|
|
559
|
+
suspenseFallback: string | null;
|
|
560
|
+
history: AxisStep<RscHarnessState>[];
|
|
561
|
+
error: string | null;
|
|
562
|
+
}
|
|
563
|
+
declare function startRscHarness(input: {
|
|
564
|
+
target: ComponentTarget;
|
|
565
|
+
componentId: string;
|
|
566
|
+
suspenseFallback?: string;
|
|
567
|
+
}): RscHarnessSession;
|
|
568
|
+
declare function beginRscRender(session: RscHarnessSession): AxisStep<RscHarnessState>;
|
|
569
|
+
declare function enterSuspenseBoundary(session: RscHarnessSession, fallback?: string): AxisStep<RscHarnessState>;
|
|
570
|
+
declare function streamHtmlChunk(session: RscHarnessSession, chunk: string): AxisStep<RscHarnessState>;
|
|
571
|
+
declare function completeRscRender(session: RscHarnessSession): AxisStep<RscHarnessState>;
|
|
572
|
+
declare function failRscRender(session: RscHarnessSession, error: Error | string): AxisStep<RscHarnessState>;
|
|
573
|
+
|
|
574
|
+
type StreamingSsrState = 'idle' | 'suspense-pending' | 'error-captured' | 'progressive-hydrating' | 'selective-hydrated';
|
|
575
|
+
interface StreamingSsrSession {
|
|
576
|
+
target: ComponentTarget;
|
|
577
|
+
routeId: string;
|
|
578
|
+
state: StreamingSsrState;
|
|
579
|
+
pendingBoundaries: Set<string>;
|
|
580
|
+
hydratedBoundaries: Set<string>;
|
|
581
|
+
errors: Array<{
|
|
582
|
+
boundaryId: string;
|
|
583
|
+
message: string;
|
|
584
|
+
}>;
|
|
585
|
+
history: AxisStep<StreamingSsrState>[];
|
|
586
|
+
}
|
|
587
|
+
declare function startStreamingSsr(input: {
|
|
588
|
+
target: ComponentTarget;
|
|
589
|
+
routeId: string;
|
|
590
|
+
}): StreamingSsrSession;
|
|
591
|
+
declare function markSuspensePending(session: StreamingSsrSession, boundaryId: string): AxisStep<StreamingSsrState>;
|
|
592
|
+
declare function captureErrorBoundary(session: StreamingSsrSession, input: {
|
|
593
|
+
boundaryId: string;
|
|
594
|
+
error: Error | string;
|
|
595
|
+
recoverable?: boolean;
|
|
596
|
+
}): AxisStep<StreamingSsrState>;
|
|
597
|
+
declare function startProgressiveHydration(session: StreamingSsrSession, boundaryId: string): AxisStep<StreamingSsrState>;
|
|
598
|
+
declare function completeSelectiveHydration(session: StreamingSsrSession, boundaryId: string): AxisStep<StreamingSsrState>;
|
|
599
|
+
|
|
600
|
+
type ViewTransitionState = 'idle' | 'element-transitioning' | 'document-transitioning' | 'asserted' | 'finished';
|
|
601
|
+
interface ViewTransitionSession {
|
|
602
|
+
target: ComponentTarget;
|
|
603
|
+
transitionId: string;
|
|
604
|
+
state: ViewTransitionState;
|
|
605
|
+
activeElements: Set<string>;
|
|
606
|
+
documentTransition: string | null;
|
|
607
|
+
assertions: string[];
|
|
608
|
+
history: AxisStep<ViewTransitionState>[];
|
|
609
|
+
}
|
|
610
|
+
declare function startViewTransitionSession(input: {
|
|
611
|
+
target: ComponentTarget;
|
|
612
|
+
transitionId: string;
|
|
613
|
+
}): ViewTransitionSession;
|
|
614
|
+
declare function startElementTransition(session: ViewTransitionSession, input: {
|
|
615
|
+
elementId: string;
|
|
616
|
+
from: string;
|
|
617
|
+
to: string;
|
|
618
|
+
}): AxisStep<ViewTransitionState>;
|
|
619
|
+
declare function finishElementTransition(session: ViewTransitionSession, elementId: string): AxisStep<ViewTransitionState>;
|
|
620
|
+
declare function startDocumentTransition(session: ViewTransitionSession, input: {
|
|
621
|
+
name: string;
|
|
622
|
+
fromUrl: string;
|
|
623
|
+
toUrl: string;
|
|
624
|
+
}): AxisStep<ViewTransitionState>;
|
|
625
|
+
declare function assertAnimation(session: ViewTransitionSession, input: {
|
|
626
|
+
assertionId: string;
|
|
627
|
+
durationMs: number;
|
|
628
|
+
easing?: string;
|
|
629
|
+
}): AxisStep<ViewTransitionState>;
|
|
630
|
+
|
|
631
|
+
type FormActionState = 'idle' | 'pending' | 'optimistic' | 'enhanced' | 'resolved' | 'rejected';
|
|
632
|
+
interface FormActionSession<TForm extends Record<string, unknown> = Record<string, unknown>> {
|
|
633
|
+
target: ComponentTarget;
|
|
634
|
+
formId: string;
|
|
635
|
+
state: FormActionState;
|
|
636
|
+
form: TForm;
|
|
637
|
+
optimisticPatches: Array<Partial<TForm>>;
|
|
638
|
+
enhanced: boolean;
|
|
639
|
+
history: AxisStep<FormActionState>[];
|
|
640
|
+
error: string | null;
|
|
641
|
+
}
|
|
642
|
+
declare function startFormActionSession<TForm extends Record<string, unknown>>(input: {
|
|
643
|
+
target: ComponentTarget;
|
|
644
|
+
formId: string;
|
|
645
|
+
initial: TForm;
|
|
646
|
+
}): FormActionSession<TForm>;
|
|
647
|
+
declare function markFormStatusPending<TForm extends Record<string, unknown>>(session: FormActionSession<TForm>, submitter: string): AxisStep<FormActionState>;
|
|
648
|
+
declare function applyOptimisticUpdate<TForm extends Record<string, unknown>>(session: FormActionSession<TForm>, patch: Partial<TForm>): AxisStep<FormActionState>;
|
|
649
|
+
declare function enableProgressiveEnhancement<TForm extends Record<string, unknown>>(session: FormActionSession<TForm>, input: {
|
|
650
|
+
method?: 'post' | 'get';
|
|
651
|
+
actionUrl: string;
|
|
652
|
+
}): AxisStep<FormActionState>;
|
|
653
|
+
declare function resolveFormAction<TForm extends Record<string, unknown>>(session: FormActionSession<TForm>, result: Partial<TForm>): AxisStep<FormActionState>;
|
|
654
|
+
declare function rejectFormAction<TForm extends Record<string, unknown>>(session: FormActionSession<TForm>, error: Error | string): AxisStep<FormActionState>;
|
|
655
|
+
|
|
656
|
+
interface FidelityRow {
|
|
657
|
+
provider: ComponentTarget;
|
|
658
|
+
axis: ComponentAxis;
|
|
659
|
+
neutralEvents: NeutralEventName[];
|
|
660
|
+
providerEvents: string[];
|
|
661
|
+
}
|
|
662
|
+
interface FidelityCoverage {
|
|
663
|
+
providers: ComponentTarget[];
|
|
664
|
+
axes: ComponentAxis[];
|
|
665
|
+
rows: FidelityRow[];
|
|
666
|
+
}
|
|
667
|
+
declare const COMPONENT_AXIS_TO_EVENTS: Record<ComponentAxis, NeutralEventName[]>;
|
|
668
|
+
declare function collectFidelityCoverage(providers?: ComponentTarget[]): FidelityCoverage;
|
|
669
|
+
|
|
670
|
+
type KiwaTestMode = 'mock' | 'real';
|
|
671
|
+
interface ResolvedMode {
|
|
672
|
+
mode: KiwaTestMode;
|
|
673
|
+
provider: ComponentTarget;
|
|
674
|
+
reason: 'default-mock' | 'kiwa-mode-real' | 'missing-key' | 'invalid-mode';
|
|
675
|
+
}
|
|
676
|
+
declare function resolveMode(provider: ComponentTarget, env?: Record<string, string | undefined>): ResolvedMode;
|
|
677
|
+
declare function resolveAllModes(env?: Record<string, string | undefined>): ResolvedMode[];
|
|
678
|
+
declare function assertMode(provider: ComponentTarget, expected: KiwaTestMode, env?: Record<string, string | undefined>): void;
|
|
679
|
+
|
|
680
|
+
export { type A11yViolation, type AxisStep, type ButtonArgs, COMPONENT_AXIS_TO_EVENTS, type CanvasElement, type CardArgs, type ChromaticConfig, type ChromaticVisualMock, type ComponentAxis, type ComponentLocator, type ComponentProvider, type ComponentRender, type ComponentTarget, type FidelityCoverage, type FidelityRow, type FormActionSession, type FormActionState, type FormArgs, type FormField, type InputArgs, type KiwaTestMode, type MockEvent, type MockNode, type ModalArgs, type NeutralEventName, type NodeLocator, type NodeOptions, type PlayContext, type PlaywrightCTMock, type ResolvedMode, type RscHarnessSession, type RscHarnessState, type StoryEntry, type StoryMeta, type StoryMountResult, type StoryObj, type StoryParameters, type StoryPlayResult, type StoryRegistry, type StreamingSsrSession, type StreamingSsrState, type ViewTransitionSession, type ViewTransitionState, type VisualBaseline, type VisualDiff, type VisualReviewAction, type VisualReviewEntry, addHandler, appendChild, applyOptimisticUpdate, assertAnimation, assertMode, beginRscRender, buildButton, buildCard, buildForm, buildInput, buildModal, captureErrorBoundary, collectFidelityCoverage, completeRscRender, completeSelectiveHydration, componentFixtures, createCanvas, createChromaticVisualMock, createNode, createPlaywrightCTMock, createStoryRegistry, enableProgressiveEnhancement, enterSuspenseBoundary, failRscRender, findByRole, findByText, finishElementTransition, fireEvent, hashMarkup, markFormStatusPending, markSuspensePending, providerEventName, query, rejectFormAction, renderMarkup, resolveAllModes, resolveFormAction, resolveMode, startDocumentTransition, startElementTransition, startFormActionSession, startProgressiveHydration, startRscHarness, startStreamingSsr, startViewTransitionSession, streamHtmlChunk };
|
package/dist/index.js
CHANGED
|
@@ -733,25 +733,489 @@ var componentFixtures = {
|
|
|
733
733
|
Modal: buildModal,
|
|
734
734
|
Card: buildCard
|
|
735
735
|
};
|
|
736
|
+
|
|
737
|
+
// src/semantics/types.ts
|
|
738
|
+
var dialect = {
|
|
739
|
+
storybook8: {
|
|
740
|
+
"rsc.render_started": "storybook.play.start",
|
|
741
|
+
"rsc.suspense_boundary": "storybook.suspense.fallback",
|
|
742
|
+
"rsc.html_chunk_streamed": "storybook.stream.chunk",
|
|
743
|
+
"rsc.render_completed": "storybook.play.done",
|
|
744
|
+
"ssr.suspense_pending": "storybook.suspense.pending",
|
|
745
|
+
"ssr.error_boundary_captured": "storybook.error.boundary",
|
|
746
|
+
"ssr.progressive_hydration_started": "storybook.hydration.progressive",
|
|
747
|
+
"ssr.selective_hydration_completed": "storybook.hydration.selective",
|
|
748
|
+
"transition.element_started": "storybook.transition.element.start",
|
|
749
|
+
"transition.element_finished": "storybook.transition.element.finish",
|
|
750
|
+
"transition.document_started": "storybook.transition.document.start",
|
|
751
|
+
"transition.animation_asserted": "storybook.animation.assert",
|
|
752
|
+
"form.status_pending": "storybook.form.pending",
|
|
753
|
+
"form.optimistic_applied": "storybook.form.optimistic",
|
|
754
|
+
"form.progressive_enhanced": "storybook.form.enhanced",
|
|
755
|
+
"form.action_resolved": "storybook.form.resolved"
|
|
756
|
+
},
|
|
757
|
+
"playwright-ct": {
|
|
758
|
+
"rsc.render_started": "pwct.mount.rsc.start",
|
|
759
|
+
"rsc.suspense_boundary": "pwct.locator.suspense.fallback",
|
|
760
|
+
"rsc.html_chunk_streamed": "pwct.response.chunk",
|
|
761
|
+
"rsc.render_completed": "pwct.mount.rsc.done",
|
|
762
|
+
"ssr.suspense_pending": "pwct.suspense.pending",
|
|
763
|
+
"ssr.error_boundary_captured": "pwct.error.boundary",
|
|
764
|
+
"ssr.progressive_hydration_started": "pwct.hydration.progressive",
|
|
765
|
+
"ssr.selective_hydration_completed": "pwct.hydration.selective",
|
|
766
|
+
"transition.element_started": "pwct.transition.element.start",
|
|
767
|
+
"transition.element_finished": "pwct.transition.element.finish",
|
|
768
|
+
"transition.document_started": "pwct.transition.document.start",
|
|
769
|
+
"transition.animation_asserted": "pwct.animation.assert",
|
|
770
|
+
"form.status_pending": "pwct.form.pending",
|
|
771
|
+
"form.optimistic_applied": "pwct.form.optimistic",
|
|
772
|
+
"form.progressive_enhanced": "pwct.form.enhanced",
|
|
773
|
+
"form.action_resolved": "pwct.form.resolved"
|
|
774
|
+
},
|
|
775
|
+
chromatic: {
|
|
776
|
+
"rsc.render_started": "chromatic.capture.rsc.start",
|
|
777
|
+
"rsc.suspense_boundary": "chromatic.capture.suspense",
|
|
778
|
+
"rsc.html_chunk_streamed": "chromatic.capture.chunk",
|
|
779
|
+
"rsc.render_completed": "chromatic.capture.rsc.done",
|
|
780
|
+
"ssr.suspense_pending": "chromatic.suspense.pending",
|
|
781
|
+
"ssr.error_boundary_captured": "chromatic.error.snapshot",
|
|
782
|
+
"ssr.progressive_hydration_started": "chromatic.hydration.progressive",
|
|
783
|
+
"ssr.selective_hydration_completed": "chromatic.hydration.selective",
|
|
784
|
+
"transition.element_started": "chromatic.transition.element.start",
|
|
785
|
+
"transition.element_finished": "chromatic.transition.element.finish",
|
|
786
|
+
"transition.document_started": "chromatic.transition.document.start",
|
|
787
|
+
"transition.animation_asserted": "chromatic.animation.assert",
|
|
788
|
+
"form.status_pending": "chromatic.form.pending",
|
|
789
|
+
"form.optimistic_applied": "chromatic.form.optimistic",
|
|
790
|
+
"form.progressive_enhanced": "chromatic.form.enhanced",
|
|
791
|
+
"form.action_resolved": "chromatic.form.resolved"
|
|
792
|
+
}
|
|
793
|
+
};
|
|
794
|
+
function providerEventName(target, neutral) {
|
|
795
|
+
return dialect[target][neutral] ?? neutral;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
// src/semantics/rsc-harness.ts
|
|
799
|
+
function startRscHarness(input) {
|
|
800
|
+
if (input.componentId.length === 0) {
|
|
801
|
+
throw new Error("startRscHarness: componentId must not be empty");
|
|
802
|
+
}
|
|
803
|
+
return {
|
|
804
|
+
target: input.target,
|
|
805
|
+
componentId: input.componentId,
|
|
806
|
+
state: "idle",
|
|
807
|
+
chunks: [],
|
|
808
|
+
suspenseFallback: input.suspenseFallback ?? null,
|
|
809
|
+
history: [],
|
|
810
|
+
error: null
|
|
811
|
+
};
|
|
812
|
+
}
|
|
813
|
+
function beginRscRender(session) {
|
|
814
|
+
if (session.state !== "idle") {
|
|
815
|
+
throw new Error(`beginRscRender: session is ${session.state}, not idle`);
|
|
816
|
+
}
|
|
817
|
+
session.state = "rendering";
|
|
818
|
+
return emit(session, "rsc.render_started", { componentId: session.componentId });
|
|
819
|
+
}
|
|
820
|
+
function enterSuspenseBoundary(session, fallback = session.suspenseFallback ?? '<template data-suspense="pending"></template>') {
|
|
821
|
+
if (session.state !== "rendering") {
|
|
822
|
+
throw new Error(`enterSuspenseBoundary: session is ${session.state}, not rendering`);
|
|
823
|
+
}
|
|
824
|
+
session.state = "suspended";
|
|
825
|
+
session.suspenseFallback = fallback;
|
|
826
|
+
return emit(session, "rsc.suspense_boundary", { fallback });
|
|
827
|
+
}
|
|
828
|
+
function streamHtmlChunk(session, chunk) {
|
|
829
|
+
if (session.state !== "rendering" && session.state !== "suspended" && session.state !== "streaming") {
|
|
830
|
+
throw new Error(`streamHtmlChunk: session is ${session.state}, cannot stream`);
|
|
831
|
+
}
|
|
832
|
+
if (chunk.length === 0) {
|
|
833
|
+
throw new Error("streamHtmlChunk: chunk must not be empty");
|
|
834
|
+
}
|
|
835
|
+
session.state = "streaming";
|
|
836
|
+
session.chunks.push(chunk);
|
|
837
|
+
return emit(session, "rsc.html_chunk_streamed", {
|
|
838
|
+
chunk,
|
|
839
|
+
chunkIndex: session.chunks.length - 1,
|
|
840
|
+
bytes: chunk.length
|
|
841
|
+
});
|
|
842
|
+
}
|
|
843
|
+
function completeRscRender(session) {
|
|
844
|
+
if (session.state !== "rendering" && session.state !== "suspended" && session.state !== "streaming") {
|
|
845
|
+
throw new Error(`completeRscRender: session is ${session.state}, cannot complete`);
|
|
846
|
+
}
|
|
847
|
+
session.state = "completed";
|
|
848
|
+
return emit(session, "rsc.render_completed", {
|
|
849
|
+
chunkCount: session.chunks.length,
|
|
850
|
+
html: session.chunks.join("")
|
|
851
|
+
});
|
|
852
|
+
}
|
|
853
|
+
function failRscRender(session, error) {
|
|
854
|
+
if (session.state === "completed") {
|
|
855
|
+
throw new Error("failRscRender: completed session cannot fail");
|
|
856
|
+
}
|
|
857
|
+
session.state = "errored";
|
|
858
|
+
session.error = typeof error === "string" ? error : error.message;
|
|
859
|
+
return emit(session, "ssr.error_boundary_captured", {
|
|
860
|
+
componentId: session.componentId,
|
|
861
|
+
error: session.error
|
|
862
|
+
});
|
|
863
|
+
}
|
|
864
|
+
function emit(session, neutralEvent, metadata) {
|
|
865
|
+
const step = {
|
|
866
|
+
neutralEvent,
|
|
867
|
+
providerEvent: providerEventName(session.target, neutralEvent),
|
|
868
|
+
state: session.state,
|
|
869
|
+
amountCents: 0,
|
|
870
|
+
metadata: { target: session.target, ...metadata }
|
|
871
|
+
};
|
|
872
|
+
session.history.push(step);
|
|
873
|
+
return step;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
// src/semantics/streaming-ssr.ts
|
|
877
|
+
function startStreamingSsr(input) {
|
|
878
|
+
if (input.routeId.length === 0) {
|
|
879
|
+
throw new Error("startStreamingSsr: routeId must not be empty");
|
|
880
|
+
}
|
|
881
|
+
return {
|
|
882
|
+
target: input.target,
|
|
883
|
+
routeId: input.routeId,
|
|
884
|
+
state: "idle",
|
|
885
|
+
pendingBoundaries: /* @__PURE__ */ new Set(),
|
|
886
|
+
hydratedBoundaries: /* @__PURE__ */ new Set(),
|
|
887
|
+
errors: [],
|
|
888
|
+
history: []
|
|
889
|
+
};
|
|
890
|
+
}
|
|
891
|
+
function markSuspensePending(session, boundaryId) {
|
|
892
|
+
assertBoundaryId(boundaryId);
|
|
893
|
+
session.state = "suspense-pending";
|
|
894
|
+
session.pendingBoundaries.add(boundaryId);
|
|
895
|
+
return emit2(session, "ssr.suspense_pending", { boundaryId, pendingCount: session.pendingBoundaries.size });
|
|
896
|
+
}
|
|
897
|
+
function captureErrorBoundary(session, input) {
|
|
898
|
+
assertBoundaryId(input.boundaryId);
|
|
899
|
+
const message = typeof input.error === "string" ? input.error : input.error.message;
|
|
900
|
+
session.state = "error-captured";
|
|
901
|
+
session.errors.push({ boundaryId: input.boundaryId, message });
|
|
902
|
+
if (input.recoverable === false) {
|
|
903
|
+
session.pendingBoundaries.delete(input.boundaryId);
|
|
904
|
+
}
|
|
905
|
+
return emit2(session, "ssr.error_boundary_captured", {
|
|
906
|
+
boundaryId: input.boundaryId,
|
|
907
|
+
message,
|
|
908
|
+
recoverable: input.recoverable ?? true
|
|
909
|
+
});
|
|
910
|
+
}
|
|
911
|
+
function startProgressiveHydration(session, boundaryId) {
|
|
912
|
+
assertBoundaryId(boundaryId);
|
|
913
|
+
if (!session.pendingBoundaries.has(boundaryId)) {
|
|
914
|
+
throw new Error(`startProgressiveHydration: ${boundaryId} is not pending`);
|
|
915
|
+
}
|
|
916
|
+
session.state = "progressive-hydrating";
|
|
917
|
+
return emit2(session, "ssr.progressive_hydration_started", { boundaryId });
|
|
918
|
+
}
|
|
919
|
+
function completeSelectiveHydration(session, boundaryId) {
|
|
920
|
+
assertBoundaryId(boundaryId);
|
|
921
|
+
if (!session.pendingBoundaries.has(boundaryId)) {
|
|
922
|
+
throw new Error(`completeSelectiveHydration: ${boundaryId} is not pending`);
|
|
923
|
+
}
|
|
924
|
+
session.pendingBoundaries.delete(boundaryId);
|
|
925
|
+
session.hydratedBoundaries.add(boundaryId);
|
|
926
|
+
session.state = "selective-hydrated";
|
|
927
|
+
return emit2(session, "ssr.selective_hydration_completed", {
|
|
928
|
+
boundaryId,
|
|
929
|
+
hydratedCount: session.hydratedBoundaries.size,
|
|
930
|
+
remainingPending: session.pendingBoundaries.size
|
|
931
|
+
});
|
|
932
|
+
}
|
|
933
|
+
function assertBoundaryId(boundaryId) {
|
|
934
|
+
if (boundaryId.length === 0) {
|
|
935
|
+
throw new Error("boundaryId must not be empty");
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
function emit2(session, neutralEvent, metadata) {
|
|
939
|
+
const step = {
|
|
940
|
+
neutralEvent,
|
|
941
|
+
providerEvent: providerEventName(session.target, neutralEvent),
|
|
942
|
+
state: session.state,
|
|
943
|
+
amountCents: 0,
|
|
944
|
+
metadata: { target: session.target, routeId: session.routeId, ...metadata }
|
|
945
|
+
};
|
|
946
|
+
session.history.push(step);
|
|
947
|
+
return step;
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
// src/semantics/view-transitions.ts
|
|
951
|
+
function startViewTransitionSession(input) {
|
|
952
|
+
if (input.transitionId.length === 0) {
|
|
953
|
+
throw new Error("startViewTransitionSession: transitionId must not be empty");
|
|
954
|
+
}
|
|
955
|
+
return {
|
|
956
|
+
target: input.target,
|
|
957
|
+
transitionId: input.transitionId,
|
|
958
|
+
state: "idle",
|
|
959
|
+
activeElements: /* @__PURE__ */ new Set(),
|
|
960
|
+
documentTransition: null,
|
|
961
|
+
assertions: [],
|
|
962
|
+
history: []
|
|
963
|
+
};
|
|
964
|
+
}
|
|
965
|
+
function startElementTransition(session, input) {
|
|
966
|
+
if (input.elementId.length === 0) {
|
|
967
|
+
throw new Error("startElementTransition: elementId must not be empty");
|
|
968
|
+
}
|
|
969
|
+
session.state = "element-transitioning";
|
|
970
|
+
session.activeElements.add(input.elementId);
|
|
971
|
+
return emit3(session, "transition.element_started", input);
|
|
972
|
+
}
|
|
973
|
+
function finishElementTransition(session, elementId) {
|
|
974
|
+
if (!session.activeElements.has(elementId)) {
|
|
975
|
+
throw new Error(`finishElementTransition: ${elementId} is not active`);
|
|
976
|
+
}
|
|
977
|
+
session.activeElements.delete(elementId);
|
|
978
|
+
session.state = session.activeElements.size === 0 ? "finished" : "element-transitioning";
|
|
979
|
+
return emit3(session, "transition.element_finished", {
|
|
980
|
+
elementId,
|
|
981
|
+
remaining: session.activeElements.size
|
|
982
|
+
});
|
|
983
|
+
}
|
|
984
|
+
function startDocumentTransition(session, input) {
|
|
985
|
+
if (input.name.length === 0) {
|
|
986
|
+
throw new Error("startDocumentTransition: name must not be empty");
|
|
987
|
+
}
|
|
988
|
+
session.state = "document-transitioning";
|
|
989
|
+
session.documentTransition = input.name;
|
|
990
|
+
return emit3(session, "transition.document_started", input);
|
|
991
|
+
}
|
|
992
|
+
function assertAnimation(session, input) {
|
|
993
|
+
if (input.durationMs < 0) {
|
|
994
|
+
throw new Error("assertAnimation: durationMs must be >= 0");
|
|
995
|
+
}
|
|
996
|
+
session.state = "asserted";
|
|
997
|
+
session.assertions.push(input.assertionId);
|
|
998
|
+
return emit3(session, "transition.animation_asserted", {
|
|
999
|
+
assertionId: input.assertionId,
|
|
1000
|
+
durationMs: input.durationMs,
|
|
1001
|
+
easing: input.easing ?? "linear"
|
|
1002
|
+
});
|
|
1003
|
+
}
|
|
1004
|
+
function emit3(session, neutralEvent, metadata) {
|
|
1005
|
+
const step = {
|
|
1006
|
+
neutralEvent,
|
|
1007
|
+
providerEvent: providerEventName(session.target, neutralEvent),
|
|
1008
|
+
state: session.state,
|
|
1009
|
+
amountCents: 0,
|
|
1010
|
+
metadata: { target: session.target, transitionId: session.transitionId, ...metadata }
|
|
1011
|
+
};
|
|
1012
|
+
session.history.push(step);
|
|
1013
|
+
return step;
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
// src/semantics/form-action-advanced.ts
|
|
1017
|
+
function startFormActionSession(input) {
|
|
1018
|
+
if (input.formId.length === 0) {
|
|
1019
|
+
throw new Error("startFormActionSession: formId must not be empty");
|
|
1020
|
+
}
|
|
1021
|
+
return {
|
|
1022
|
+
target: input.target,
|
|
1023
|
+
formId: input.formId,
|
|
1024
|
+
state: "idle",
|
|
1025
|
+
form: { ...input.initial },
|
|
1026
|
+
optimisticPatches: [],
|
|
1027
|
+
enhanced: false,
|
|
1028
|
+
history: [],
|
|
1029
|
+
error: null
|
|
1030
|
+
};
|
|
1031
|
+
}
|
|
1032
|
+
function markFormStatusPending(session, submitter) {
|
|
1033
|
+
if (session.state === "pending") {
|
|
1034
|
+
throw new Error("markFormStatusPending: form is already pending");
|
|
1035
|
+
}
|
|
1036
|
+
session.state = "pending";
|
|
1037
|
+
return emit4(session, "form.status_pending", { submitter });
|
|
1038
|
+
}
|
|
1039
|
+
function applyOptimisticUpdate(session, patch) {
|
|
1040
|
+
if (session.state !== "pending" && session.state !== "optimistic") {
|
|
1041
|
+
throw new Error(`applyOptimisticUpdate: session is ${session.state}, not pending`);
|
|
1042
|
+
}
|
|
1043
|
+
session.state = "optimistic";
|
|
1044
|
+
session.optimisticPatches.push(patch);
|
|
1045
|
+
session.form = { ...session.form, ...patch };
|
|
1046
|
+
return emit4(session, "form.optimistic_applied", {
|
|
1047
|
+
patchKeys: Object.keys(patch).join(","),
|
|
1048
|
+
patchCount: session.optimisticPatches.length
|
|
1049
|
+
});
|
|
1050
|
+
}
|
|
1051
|
+
function enableProgressiveEnhancement(session, input) {
|
|
1052
|
+
if (input.actionUrl.length === 0) {
|
|
1053
|
+
throw new Error("enableProgressiveEnhancement: actionUrl must not be empty");
|
|
1054
|
+
}
|
|
1055
|
+
session.enhanced = true;
|
|
1056
|
+
session.state = "enhanced";
|
|
1057
|
+
return emit4(session, "form.progressive_enhanced", {
|
|
1058
|
+
method: input.method ?? "post",
|
|
1059
|
+
actionUrl: input.actionUrl
|
|
1060
|
+
});
|
|
1061
|
+
}
|
|
1062
|
+
function resolveFormAction(session, result) {
|
|
1063
|
+
if (session.state === "idle") {
|
|
1064
|
+
throw new Error("resolveFormAction: action was not submitted");
|
|
1065
|
+
}
|
|
1066
|
+
session.state = "resolved";
|
|
1067
|
+
session.form = { ...session.form, ...result };
|
|
1068
|
+
return emit4(session, "form.action_resolved", {
|
|
1069
|
+
resultKeys: Object.keys(result).join(","),
|
|
1070
|
+
enhanced: session.enhanced
|
|
1071
|
+
});
|
|
1072
|
+
}
|
|
1073
|
+
function rejectFormAction(session, error) {
|
|
1074
|
+
if (session.state === "resolved") {
|
|
1075
|
+
throw new Error("rejectFormAction: resolved action cannot reject");
|
|
1076
|
+
}
|
|
1077
|
+
session.state = "rejected";
|
|
1078
|
+
session.error = typeof error === "string" ? error : error.message;
|
|
1079
|
+
return emit4(session, "form.action_resolved", {
|
|
1080
|
+
rejected: true,
|
|
1081
|
+
error: session.error
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1084
|
+
function emit4(session, neutralEvent, metadata) {
|
|
1085
|
+
const step = {
|
|
1086
|
+
neutralEvent,
|
|
1087
|
+
providerEvent: providerEventName(session.target, neutralEvent),
|
|
1088
|
+
state: session.state,
|
|
1089
|
+
amountCents: 0,
|
|
1090
|
+
metadata: { target: session.target, formId: session.formId, ...metadata }
|
|
1091
|
+
};
|
|
1092
|
+
session.history.push(step);
|
|
1093
|
+
return step;
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
// src/semantics/fidelity.ts
|
|
1097
|
+
var COMPONENT_AXIS_TO_EVENTS = {
|
|
1098
|
+
"rsc-harness": [
|
|
1099
|
+
"rsc.render_started",
|
|
1100
|
+
"rsc.suspense_boundary",
|
|
1101
|
+
"rsc.html_chunk_streamed",
|
|
1102
|
+
"rsc.render_completed"
|
|
1103
|
+
],
|
|
1104
|
+
"streaming-ssr": [
|
|
1105
|
+
"ssr.suspense_pending",
|
|
1106
|
+
"ssr.error_boundary_captured",
|
|
1107
|
+
"ssr.progressive_hydration_started",
|
|
1108
|
+
"ssr.selective_hydration_completed"
|
|
1109
|
+
],
|
|
1110
|
+
"view-transitions": [
|
|
1111
|
+
"transition.element_started",
|
|
1112
|
+
"transition.element_finished",
|
|
1113
|
+
"transition.document_started",
|
|
1114
|
+
"transition.animation_asserted"
|
|
1115
|
+
],
|
|
1116
|
+
"form-action-advanced": [
|
|
1117
|
+
"form.status_pending",
|
|
1118
|
+
"form.optimistic_applied",
|
|
1119
|
+
"form.progressive_enhanced",
|
|
1120
|
+
"form.action_resolved"
|
|
1121
|
+
]
|
|
1122
|
+
};
|
|
1123
|
+
function collectFidelityCoverage(providers = ["storybook8", "playwright-ct", "chromatic"]) {
|
|
1124
|
+
const axes = Object.keys(COMPONENT_AXIS_TO_EVENTS);
|
|
1125
|
+
const rows = [];
|
|
1126
|
+
for (const provider of providers) {
|
|
1127
|
+
for (const axis of axes) {
|
|
1128
|
+
const neutralEvents = COMPONENT_AXIS_TO_EVENTS[axis];
|
|
1129
|
+
rows.push({
|
|
1130
|
+
provider,
|
|
1131
|
+
axis,
|
|
1132
|
+
neutralEvents,
|
|
1133
|
+
providerEvents: neutralEvents.map((event) => providerEventName(provider, event))
|
|
1134
|
+
});
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
return { providers, axes, rows };
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
// src/real-driver.ts
|
|
1141
|
+
var TARGET_KEY_ENV = {
|
|
1142
|
+
storybook8: "STORYBOOK_URL",
|
|
1143
|
+
"playwright-ct": "PLAYWRIGHT_CT_URL",
|
|
1144
|
+
chromatic: "CHROMATIC_TOKEN"
|
|
1145
|
+
};
|
|
1146
|
+
function resolveMode(provider, env = process.env) {
|
|
1147
|
+
const rawMode = env.KIWA_MODE?.toLowerCase();
|
|
1148
|
+
if (rawMode !== void 0 && rawMode !== "real" && rawMode !== "mock") {
|
|
1149
|
+
return { provider, mode: "mock", reason: "invalid-mode" };
|
|
1150
|
+
}
|
|
1151
|
+
if (rawMode !== "real") {
|
|
1152
|
+
return { provider, mode: "mock", reason: "default-mock" };
|
|
1153
|
+
}
|
|
1154
|
+
const keyValue = env[TARGET_KEY_ENV[provider]];
|
|
1155
|
+
if (typeof keyValue !== "string" || keyValue.length === 0) {
|
|
1156
|
+
return { provider, mode: "mock", reason: "missing-key" };
|
|
1157
|
+
}
|
|
1158
|
+
return { provider, mode: "real", reason: "kiwa-mode-real" };
|
|
1159
|
+
}
|
|
1160
|
+
function resolveAllModes(env = process.env) {
|
|
1161
|
+
const providers = ["storybook8", "playwright-ct", "chromatic"];
|
|
1162
|
+
return providers.map((provider) => resolveMode(provider, env));
|
|
1163
|
+
}
|
|
1164
|
+
function assertMode(provider, expected, env = process.env) {
|
|
1165
|
+
const resolved = resolveMode(provider, env);
|
|
1166
|
+
if (resolved.mode !== expected) {
|
|
1167
|
+
throw new Error(
|
|
1168
|
+
`expected ${provider} in ${expected} mode but resolved ${resolved.mode} (${resolved.reason})`
|
|
1169
|
+
);
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
736
1172
|
export {
|
|
1173
|
+
COMPONENT_AXIS_TO_EVENTS,
|
|
737
1174
|
addHandler,
|
|
738
1175
|
appendChild,
|
|
1176
|
+
applyOptimisticUpdate,
|
|
1177
|
+
assertAnimation,
|
|
1178
|
+
assertMode,
|
|
1179
|
+
beginRscRender,
|
|
739
1180
|
buildButton,
|
|
740
1181
|
buildCard,
|
|
741
1182
|
buildForm,
|
|
742
1183
|
buildInput,
|
|
743
1184
|
buildModal,
|
|
1185
|
+
captureErrorBoundary,
|
|
1186
|
+
collectFidelityCoverage,
|
|
1187
|
+
completeRscRender,
|
|
1188
|
+
completeSelectiveHydration,
|
|
744
1189
|
componentFixtures,
|
|
745
1190
|
createCanvas,
|
|
746
1191
|
createChromaticVisualMock,
|
|
747
1192
|
createNode,
|
|
748
1193
|
createPlaywrightCTMock,
|
|
749
1194
|
createStoryRegistry,
|
|
1195
|
+
enableProgressiveEnhancement,
|
|
1196
|
+
enterSuspenseBoundary,
|
|
1197
|
+
failRscRender,
|
|
750
1198
|
findByRole,
|
|
751
1199
|
findByText,
|
|
1200
|
+
finishElementTransition,
|
|
752
1201
|
fireEvent,
|
|
753
1202
|
hashMarkup,
|
|
1203
|
+
markFormStatusPending,
|
|
1204
|
+
markSuspensePending,
|
|
1205
|
+
providerEventName,
|
|
754
1206
|
query,
|
|
755
|
-
|
|
1207
|
+
rejectFormAction,
|
|
1208
|
+
renderMarkup,
|
|
1209
|
+
resolveAllModes,
|
|
1210
|
+
resolveFormAction,
|
|
1211
|
+
resolveMode,
|
|
1212
|
+
startDocumentTransition,
|
|
1213
|
+
startElementTransition,
|
|
1214
|
+
startFormActionSession,
|
|
1215
|
+
startProgressiveHydration,
|
|
1216
|
+
startRscHarness,
|
|
1217
|
+
startStreamingSsr,
|
|
1218
|
+
startViewTransitionSession,
|
|
1219
|
+
streamHtmlChunk
|
|
756
1220
|
};
|
|
757
1221
|
//# sourceMappingURL=index.js.map
|