tempest-react-sdk 0.60.0 → 0.62.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/README.md +9 -7
- package/dist/components/ImageCropper/ImageCropper.module.cjs.map +1 -1
- package/dist/components/ImageCropper/ImageCropper.module.js.map +1 -1
- package/dist/components/PasswordInput/PasswordInput.module.cjs.map +1 -1
- package/dist/components/PasswordInput/PasswordInput.module.js.map +1 -1
- package/dist/components/PinInput/PinInput.module.cjs.map +1 -1
- package/dist/components/PinInput/PinInput.module.js.map +1 -1
- package/dist/sse/create-event-stream.cjs +1 -1
- package/dist/sse/create-event-stream.cjs.map +1 -1
- package/dist/sse/create-event-stream.js +32 -27
- package/dist/sse/create-event-stream.js.map +1 -1
- package/dist/sse/use-event-stream.cjs.map +1 -1
- package/dist/sse/use-event-stream.js.map +1 -1
- package/dist/styles/ImageCropper.css +3 -3
- package/dist/styles/PasswordInput.css +1 -1
- package/dist/styles/PinInput.css +1 -1
- package/dist/styles/base.css +1 -1
- package/dist/styles/core.css +3 -3
- package/dist/styles/forms.css +5 -5
- package/dist/styles/scoped.css +1 -1
- package/dist/styles/tokens.css +2 -2
- package/dist/styles.css +1 -1
- package/dist/tempest-react-sdk.d.ts +180 -21
- package/dist/utils/dev-mode.cjs.map +1 -1
- package/dist/utils/dev-mode.js.map +1 -1
- package/dist/utils/json-frame.cjs +1 -1
- package/dist/utils/json-frame.cjs.map +1 -1
- package/dist/utils/json-frame.js +33 -14
- package/dist/utils/json-frame.js.map +1 -1
- package/dist/utils/schema-like.cjs +2 -0
- package/dist/utils/schema-like.cjs.map +1 -0
- package/dist/utils/schema-like.js +43 -0
- package/dist/utils/schema-like.js.map +1 -0
- package/dist/ws/create-web-socket.cjs +1 -1
- package/dist/ws/create-web-socket.cjs.map +1 -1
- package/dist/ws/create-web-socket.js +54 -38
- package/dist/ws/create-web-socket.js.map +1 -1
- package/dist/ws/use-web-socket.cjs +1 -1
- package/dist/ws/use-web-socket.cjs.map +1 -1
- package/dist/ws/use-web-socket.js +5 -3
- package/dist/ws/use-web-socket.js.map +1 -1
- package/package.json +1 -1
|
@@ -3236,6 +3236,34 @@ export declare interface CreateEventStreamOptions<T> {
|
|
|
3236
3236
|
* kept, with a one-time warning in development builds.
|
|
3237
3237
|
*/
|
|
3238
3238
|
onParseError?: (error: unknown, raw: string) => void;
|
|
3239
|
+
/**
|
|
3240
|
+
* Schema every decoded frame must satisfy, from zod, valibot, arktype or
|
|
3241
|
+
* anything else exposing `~standard` or `.safeParse`.
|
|
3242
|
+
*
|
|
3243
|
+
* Without it nothing changes: the payload reaches `onMessage` announced as
|
|
3244
|
+
* `T` on the strength of the type argument alone, which is a promise about
|
|
3245
|
+
* the server that TypeScript cannot keep. With it, a frame that does not
|
|
3246
|
+
* match is **not** delivered — the same rule `onParseError` already follows —
|
|
3247
|
+
* and `onValidationError` hears why. The value delivered is the schema's
|
|
3248
|
+
* output, so coercions and defaults are honoured.
|
|
3249
|
+
*
|
|
3250
|
+
* When `parser` is also supplied, it decodes first and the schema validates
|
|
3251
|
+
* what it returned.
|
|
3252
|
+
*
|
|
3253
|
+
* The validation must be synchronous. A frame is decoded inside the
|
|
3254
|
+
* `message` handler and delivered from it, so an async schema would deliver
|
|
3255
|
+
* frames in whatever order their validations settled; that case is reported
|
|
3256
|
+
* through `onValidationError` instead of awaited.
|
|
3257
|
+
*/
|
|
3258
|
+
schema?: SchemaLike<T>;
|
|
3259
|
+
/**
|
|
3260
|
+
* A frame was decoded but the `schema` refused it, so it was dropped.
|
|
3261
|
+
*
|
|
3262
|
+
* The one signal that does not depend on how the app's bundler resolves
|
|
3263
|
+
* `process`: the one-time development warning behind `onParseError` needs
|
|
3264
|
+
* `isDevBuild()` to be able to answer, and this callback is the app's own.
|
|
3265
|
+
*/
|
|
3266
|
+
onValidationError?: (issues: SchemaIssue[], raw: string) => void;
|
|
3239
3267
|
onOpen?: () => void;
|
|
3240
3268
|
onMessage?: (message: EventStreamMessage<T>) => void;
|
|
3241
3269
|
onError?: (error: Event) => void;
|
|
@@ -4420,6 +4448,37 @@ export declare interface CreateWebSocketOptions<T> {
|
|
|
4420
4448
|
* kept, with a one-time warning in development builds.
|
|
4421
4449
|
*/
|
|
4422
4450
|
onParseError?: (error: unknown, raw: string) => void;
|
|
4451
|
+
/**
|
|
4452
|
+
* Schema every decoded frame must satisfy, from zod, valibot, arktype or
|
|
4453
|
+
* anything else exposing `~standard` or `.safeParse`.
|
|
4454
|
+
*
|
|
4455
|
+
* Without it nothing changes: the payload reaches `onMessage` announced as
|
|
4456
|
+
* `T` on the strength of the type argument alone, which is a promise about
|
|
4457
|
+
* the server that TypeScript cannot keep. With it, a frame that does not
|
|
4458
|
+
* match is **not** delivered — the same rule `onParseError` already follows —
|
|
4459
|
+
* and `onValidationError` hears why. The value delivered is the schema's
|
|
4460
|
+
* output, so coercions and defaults are honoured.
|
|
4461
|
+
*
|
|
4462
|
+
* When `parser` is also supplied, it decodes first and the schema validates
|
|
4463
|
+
* what it returned.
|
|
4464
|
+
*
|
|
4465
|
+
* A server ping is still answered when the schema drops it: the heartbeat is
|
|
4466
|
+
* the transport's contract with the server, not the app's with its payload,
|
|
4467
|
+
* and a socket that stops sending `pong` is closed with `4408` once per
|
|
4468
|
+
* timeout. The validation itself must be synchronous — a frame is decoded
|
|
4469
|
+
* inside the `message` handler and delivered from it, so an async schema
|
|
4470
|
+
* would deliver frames in whatever order their validations settled; that
|
|
4471
|
+
* case is reported through `onValidationError` instead of awaited.
|
|
4472
|
+
*/
|
|
4473
|
+
schema?: SchemaLike<T>;
|
|
4474
|
+
/**
|
|
4475
|
+
* A frame was decoded but the `schema` refused it, so it was dropped.
|
|
4476
|
+
*
|
|
4477
|
+
* The one signal that does not depend on how the app's bundler resolves
|
|
4478
|
+
* `process`: the one-time development warning behind `onParseError` needs
|
|
4479
|
+
* `isDevBuild()` to be able to answer, and this callback is the app's own.
|
|
4480
|
+
*/
|
|
4481
|
+
onValidationError?: (issues: SchemaIssue[], raw: string) => void;
|
|
4423
4482
|
onOpen?: (event: Event) => void;
|
|
4424
4483
|
onMessage?: (message: WebSocketMessage<T>) => void;
|
|
4425
4484
|
onClose?: (event: CloseEvent) => void;
|
|
@@ -5732,7 +5791,7 @@ export declare interface EventStreamController {
|
|
|
5732
5791
|
export declare interface EventStreamMessage<T> {
|
|
5733
5792
|
/** Server-named event (default `"message"`). */
|
|
5734
5793
|
event: string;
|
|
5735
|
-
/** Parsed payload — JSON-decoded when possible, raw string otherwise. */
|
|
5794
|
+
/** Parsed payload — validated when `schema` is set, JSON-decoded when possible, raw string otherwise. */
|
|
5736
5795
|
data: T;
|
|
5737
5796
|
/** Server-supplied id, if any. */
|
|
5738
5797
|
id?: string;
|
|
@@ -7454,6 +7513,11 @@ export declare function isStandalone(): boolean;
|
|
|
7454
7513
|
*/
|
|
7455
7514
|
export declare function isString(value: unknown): value is string;
|
|
7456
7515
|
|
|
7516
|
+
/** A path segment as Standard Schema reports it: a key, or an object holding one. */
|
|
7517
|
+
declare type IssuePathSegment = PropertyKey | {
|
|
7518
|
+
readonly key: PropertyKey;
|
|
7519
|
+
};
|
|
7520
|
+
|
|
7457
7521
|
/** True when `value` is a finite latitude in `[-90, 90]`. */
|
|
7458
7522
|
export declare function isValidLatitude(value: number): boolean;
|
|
7459
7523
|
|
|
@@ -10882,6 +10946,12 @@ export declare interface RatingStarsProps {
|
|
|
10882
10946
|
className?: string;
|
|
10883
10947
|
}
|
|
10884
10948
|
|
|
10949
|
+
/** One issue as either supported shape reports it. */
|
|
10950
|
+
declare interface RawIssue {
|
|
10951
|
+
readonly message: string;
|
|
10952
|
+
readonly path?: readonly IssuePathSegment[] | undefined;
|
|
10953
|
+
}
|
|
10954
|
+
|
|
10885
10955
|
/**
|
|
10886
10956
|
* Pick the readable foreground for a background, by contrast ratio.
|
|
10887
10957
|
*
|
|
@@ -11617,6 +11687,19 @@ export declare interface SafeAreaProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
11617
11687
|
children?: ReactNode;
|
|
11618
11688
|
}
|
|
11619
11689
|
|
|
11690
|
+
/** A schema exposing zod's `.safeParse`, including versions older than `~standard`. */
|
|
11691
|
+
export declare interface SafeParseSchemaLike<T> {
|
|
11692
|
+
readonly safeParse: (value: unknown) => {
|
|
11693
|
+
readonly success: true;
|
|
11694
|
+
readonly data: T;
|
|
11695
|
+
} | {
|
|
11696
|
+
readonly success: false;
|
|
11697
|
+
readonly error: {
|
|
11698
|
+
readonly issues: readonly RawIssue[];
|
|
11699
|
+
};
|
|
11700
|
+
};
|
|
11701
|
+
}
|
|
11702
|
+
|
|
11620
11703
|
/**
|
|
11621
11704
|
* Divide the video caps by the size of the room.
|
|
11622
11705
|
*
|
|
@@ -11720,6 +11803,36 @@ export declare interface SchedulerProps extends Omit<HTMLAttributes<HTMLDivEleme
|
|
|
11720
11803
|
now?: Date;
|
|
11721
11804
|
}
|
|
11722
11805
|
|
|
11806
|
+
/**
|
|
11807
|
+
* The SDK's answer to "the caller handed me a schema" — one normalizer behind
|
|
11808
|
+
* every option that takes one.
|
|
11809
|
+
*
|
|
11810
|
+
* Internal, and imported by path rather than through the `utils` barrel: the
|
|
11811
|
+
* function exists so `decodeFrame` and anything else that validates a payload
|
|
11812
|
+
* share one reading of the two shapes below, not so consumers can call it. The
|
|
11813
|
+
* types are public, because an option typed `SchemaLike<T>` is a name the
|
|
11814
|
+
* consumer has to be able to write down.
|
|
11815
|
+
*
|
|
11816
|
+
* Two shapes are accepted on purpose:
|
|
11817
|
+
*
|
|
11818
|
+
* - [Standard Schema](https://standardschema.dev) (`~standard`), which zod
|
|
11819
|
+
* (>=3.24), valibot and arktype all implement, so the SDK validates against
|
|
11820
|
+
* any of them without depending on one;
|
|
11821
|
+
* - `.safeParse`, because the SDK's own zod range starts at `^3.23.0`, which
|
|
11822
|
+
* predates `~standard`, and because it is the method every zod user already
|
|
11823
|
+
* knows.
|
|
11824
|
+
*/
|
|
11825
|
+
/** One field-level complaint from a schema validation. */
|
|
11826
|
+
export declare interface SchemaIssue {
|
|
11827
|
+
/** Dotted path to the offending field, or `"<root>"` for the value itself. */
|
|
11828
|
+
path: string;
|
|
11829
|
+
/** What the validator said was wrong. */
|
|
11830
|
+
message: string;
|
|
11831
|
+
}
|
|
11832
|
+
|
|
11833
|
+
/** Anything the SDK can validate a payload against. */
|
|
11834
|
+
export declare type SchemaLike<T> = StandardSchemaLike<T> | SafeParseSchemaLike<T>;
|
|
11835
|
+
|
|
11723
11836
|
/** Lifecycle of a screen share. */
|
|
11724
11837
|
export declare type ScreenCaptureStatus = "idle" | "requesting" | "sharing" | "error";
|
|
11725
11838
|
|
|
@@ -11912,13 +12025,13 @@ export declare function setAudioOutput(element: HTMLMediaElement | null, sinkId:
|
|
|
11912
12025
|
* the SDK routes through it — `grep -rn "dev-mode" src/` for the current list,
|
|
11913
12026
|
* which an enumeration written here would only drift away from.
|
|
11914
12027
|
*
|
|
11915
|
-
* {@link setDevBuild} is public, because
|
|
11916
|
-
*
|
|
12028
|
+
* {@link setDevBuild} is public, because a context nothing compiles cannot be
|
|
12029
|
+
* detected from the inside. See its doc for when that is.
|
|
11917
12030
|
*/
|
|
11918
12031
|
/**
|
|
11919
12032
|
* Tell the SDK whether the app around it was built for development.
|
|
11920
12033
|
*
|
|
11921
|
-
* Call it once, at bootstrap, from a
|
|
12034
|
+
* Call it once, at bootstrap, from a context {@link isDevBuild} cannot read:
|
|
11922
12035
|
*
|
|
11923
12036
|
* ```ts
|
|
11924
12037
|
* import { setDevBuild } from "tempest-react-sdk";
|
|
@@ -11926,20 +12039,29 @@ export declare function setAudioOutput(element: HTMLMediaElement | null, sinkId:
|
|
|
11926
12039
|
* setDevBuild(import.meta.env.DEV);
|
|
11927
12040
|
* ```
|
|
11928
12041
|
*
|
|
11929
|
-
* **
|
|
11930
|
-
*
|
|
11931
|
-
*
|
|
11932
|
-
*
|
|
11933
|
-
*
|
|
11934
|
-
*
|
|
11935
|
-
*
|
|
11936
|
-
*
|
|
11937
|
-
*
|
|
11938
|
-
*
|
|
11939
|
-
*
|
|
11940
|
-
*
|
|
11941
|
-
*
|
|
11942
|
-
*
|
|
12042
|
+
* **When you need it.** Not for an ordinary Vite, webpack, Rspack or Parcel
|
|
12043
|
+
* app: all of them substitute `process.env.NODE_ENV` while building the app, so
|
|
12044
|
+
* the automatic read already answers correctly there — measured for Vite 5
|
|
12045
|
+
* through 8 in {@link isDevBuild}, whose doc carries the table. What is left is
|
|
12046
|
+
* the context nothing compiles or nothing configures:
|
|
12047
|
+
*
|
|
12048
|
+
* - code no bundler transformed — a raw service-worker script registered as a
|
|
12049
|
+
* file of its own, a plain `<script type="module">`;
|
|
12050
|
+
* - a staging or QA build that never sets `NODE_ENV=production`, where the
|
|
12051
|
+
* automatic answer is `true` and `parseResponse` would put the raw response
|
|
12052
|
+
* payload in an error string seen by real users. `setDevBuild(false)` closes
|
|
12053
|
+
* that;
|
|
12054
|
+
* - a test that wants the other branch, and puts it back on the way out.
|
|
12055
|
+
*
|
|
12056
|
+
* `import.meta.env.DEV` cannot be read by the SDK on your behalf, which is why
|
|
12057
|
+
* the signal is a parameter: Vite would replace it while building *this
|
|
12058
|
+
* package*, and the published artifact would ship the constant.
|
|
12059
|
+
*
|
|
12060
|
+
* The default stays `false` when the read throws. `parseResponse` puts the raw
|
|
12061
|
+
* response payload in its message when this is on, so guessing `true` in a
|
|
12062
|
+
* context that cannot prove it leaks a payload into a production error string.
|
|
12063
|
+
* Silence is the safe default; the report is one line away for anyone who wants
|
|
12064
|
+
* it.
|
|
11943
12065
|
*
|
|
11944
12066
|
* Passing `undefined` clears the override and returns to automatic detection,
|
|
11945
12067
|
* which is what a test that set it should do on the way out.
|
|
@@ -11948,8 +12070,8 @@ export declare function setAudioOutput(element: HTMLMediaElement | null, sinkId:
|
|
|
11948
12070
|
* `undefined` to go back to detecting it.
|
|
11949
12071
|
*
|
|
11950
12072
|
* @example
|
|
11951
|
-
* //
|
|
11952
|
-
* setDevBuild(
|
|
12073
|
+
* // A service worker, or any context no bundler transformed
|
|
12074
|
+
* setDevBuild(false);
|
|
11953
12075
|
*
|
|
11954
12076
|
* @example
|
|
11955
12077
|
* // A test that flips it, and puts it back
|
|
@@ -12621,6 +12743,23 @@ export declare const STALE_TIME: {
|
|
|
12621
12743
|
readonly INFINITE: number;
|
|
12622
12744
|
};
|
|
12623
12745
|
|
|
12746
|
+
/** A schema exposing the [Standard Schema](https://standardschema.dev) interface. */
|
|
12747
|
+
export declare interface StandardSchemaLike<T> {
|
|
12748
|
+
readonly "~standard": {
|
|
12749
|
+
readonly validate: (value: unknown) => {
|
|
12750
|
+
readonly value: T;
|
|
12751
|
+
readonly issues?: undefined;
|
|
12752
|
+
} | {
|
|
12753
|
+
readonly issues: readonly RawIssue[];
|
|
12754
|
+
} | Promise<{
|
|
12755
|
+
readonly value: T;
|
|
12756
|
+
readonly issues?: undefined;
|
|
12757
|
+
} | {
|
|
12758
|
+
readonly issues: readonly RawIssue[];
|
|
12759
|
+
}>;
|
|
12760
|
+
};
|
|
12761
|
+
}
|
|
12762
|
+
|
|
12624
12763
|
/**
|
|
12625
12764
|
* KPI card. Dashboard widget showing a label + big value + optional
|
|
12626
12765
|
* delta/trend and hint.
|
|
@@ -14648,12 +14787,28 @@ export declare function useEventListener<K extends keyof HTMLElementEventMap>(ev
|
|
|
14648
14787
|
* tied to the component (and the `url`/`enabled` dependencies); the stream
|
|
14649
14788
|
* closes on unmount.
|
|
14650
14789
|
*
|
|
14790
|
+
* Pass `schema` to have every frame validated before it reaches `onMessage`,
|
|
14791
|
+
* instead of trusting the type argument: without it `data` is announced as `T`
|
|
14792
|
+
* on the strength of the generic alone, which is a promise about the server
|
|
14793
|
+
* that TypeScript cannot keep. It is read when the stream opens, so declare it
|
|
14794
|
+
* outside the component rather than building one inline per render.
|
|
14795
|
+
*
|
|
14651
14796
|
* @example
|
|
14652
14797
|
* useEventStream<Notification>(`${API}/notifications/stream`, {
|
|
14653
14798
|
* enabled: !!user,
|
|
14654
14799
|
* withCredentials: true,
|
|
14655
14800
|
* onMessage: ({ data }) => addNotification(data),
|
|
14656
14801
|
* });
|
|
14802
|
+
*
|
|
14803
|
+
* @example
|
|
14804
|
+
* // Validated: a frame that does not match never reaches `onMessage`
|
|
14805
|
+
* const notificationSchema = z.object({ id: z.string(), message: z.string() });
|
|
14806
|
+
*
|
|
14807
|
+
* useEventStream<Notification>(`${API}/notifications/stream`, {
|
|
14808
|
+
* schema: notificationSchema,
|
|
14809
|
+
* onValidationError: (issues) => logger.warn("stream drift", { issues }),
|
|
14810
|
+
* onMessage: ({ data }) => addNotification(data),
|
|
14811
|
+
* });
|
|
14657
14812
|
*/
|
|
14658
14813
|
export declare function useEventStream<T = unknown>(url: string, options?: UseEventStreamOptions<T>): UseEventStreamResult<T>;
|
|
14659
14814
|
|
|
@@ -16803,6 +16958,10 @@ export { useWatch }
|
|
|
16803
16958
|
* baked into the connection, so changing one reopens it with the new value
|
|
16804
16959
|
* rather than being silently ignored.
|
|
16805
16960
|
*
|
|
16961
|
+
* `schema` is read when the socket opens, so declare it outside the component
|
|
16962
|
+
* (or memoize it): a schema built inline is a new object on every render, and
|
|
16963
|
+
* the one in force is whichever existed at the last open.
|
|
16964
|
+
*
|
|
16806
16965
|
* @param url - Full ws:// or wss:// URL.
|
|
16807
16966
|
* @param options - Connection configuration and callbacks.
|
|
16808
16967
|
* @returns Status, last frame, and the `send` / `reconnect` controls.
|
|
@@ -17717,7 +17876,7 @@ export declare interface WebSocketController {
|
|
|
17717
17876
|
export declare type WebSocketLostReason = "rejected" | "exhausted";
|
|
17718
17877
|
|
|
17719
17878
|
export declare interface WebSocketMessage<T> {
|
|
17720
|
-
/** Parsed payload — JSON-decoded when possible, raw string otherwise. */
|
|
17879
|
+
/** Parsed payload — validated when `schema` is set, JSON-decoded when possible, raw string otherwise. */
|
|
17721
17880
|
data: T;
|
|
17722
17881
|
/** The original `MessageEvent`. */
|
|
17723
17882
|
raw: MessageEvent;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-mode.cjs","names":[],"sources":["../../src/utils/dev-mode.ts"],"sourcesContent":["/**\n * {@link isDevBuild} stays internal, imported by path (`../utils/dev-mode`)\n * rather than through the `utils` barrel: re-exporting it would make a one-line\n * env read part of the package's public API, with the semver weight that\n * carries, for something no consumer asked for. Every dev-only diagnostic in\n * the SDK routes through it — `grep -rn \"dev-mode\" src/` for the current list,\n * which an enumeration written here would only drift away from.\n *\n * {@link setDevBuild} is public, because
|
|
1
|
+
{"version":3,"file":"dev-mode.cjs","names":[],"sources":["../../src/utils/dev-mode.ts"],"sourcesContent":["/**\n * {@link isDevBuild} stays internal, imported by path (`../utils/dev-mode`)\n * rather than through the `utils` barrel: re-exporting it would make a one-line\n * env read part of the package's public API, with the semver weight that\n * carries, for something no consumer asked for. Every dev-only diagnostic in\n * the SDK routes through it — `grep -rn \"dev-mode\" src/` for the current list,\n * which an enumeration written here would only drift away from.\n *\n * {@link setDevBuild} is public, because a context nothing compiles cannot be\n * detected from the inside. See its doc for when that is.\n */\n\n/**\n * Whether the consuming app was built for development.\n *\n * Reads `process.env.NODE_ENV`, which every supported bundler replaces with a\n * literal **while building the app** — Vite included. That last word is a\n * correction: this doc used to claim Vite substitutes neither half, so every\n * dev-only diagnostic in the SDK was unreachable under `vite dev`. Measured on\n * 2026-09-07 with 0.61.0 installed into a probe app, both from a packed tarball\n * (a real copy under `node_modules`, which Vite pre-bundles) and from a `file:`\n * link (a symlink it does not), reading back the module the dev server actually\n * served:\n *\n * | Vite | `vite dev` | `vite build` |\n * | --- | --- | --- |\n * | 5.4.21, 6.4.3, 7.3.6 | folded to `true` | folded to `false` |\n * | 8.2.2 | `\"development\" !== \"production\"` | folded to `false` |\n *\n * So this answers correctly in a Vite app on its own, in development and in\n * production, pre-bundled or served through the dev server's transform. The\n * wrong belief survived releases because nobody read the served module — the\n * expression is not substituted in a *browser console*, which is where it is\n * natural to go looking.\n *\n * `import.meta.env.DEV` still cannot be used here: Vite would replace it while\n * building *this package*, so the published artifact would carry the constant\n * and every guard behind it would be dead code no app could switch back on.\n *\n * The expression is written out in full, and the failure is caught rather than\n * guarded against. A `typeof process === \"undefined\"` check would read as the\n * careful version and quietly break the environments that work: substitution\n * replaces the member expression `process.env.NODE_ENV` and nothing else, so\n * the guard would return early in front of a literal that had already been\n * swapped in. The identifier itself never exists at runtime — `typeof process`\n * is `\"undefined\"` in the page, measured in the same probe — which is exactly\n * why the read is wrapped in `try` instead.\n *\n * Returns `false` when the read throws, which is the context nothing\n * transformed: a raw service-worker script, a plain `<script type=\"module\">`, a\n * bundler substituting nothing. Staying quiet there is deliberate — a dev-only\n * warning that cannot prove it is in development is better silent than shouting\n * in someone's production console.\n *\n * {@link setDevBuild} overrides all of it and is checked first.\n *\n * @returns Whether development-only diagnostics should run.\n *\n * @example\n * if (isDevBuild()) console.warn(\"[my-app] this prop combination does nothing\");\n *\n * @tempest-limits empty-catch — the only thing the read can throw is the\n * environment answering \"not defined\", which is the return value, not an error\n * worth reporting. Logging it would print on every call in exactly the context\n * that has nowhere to print.\n */\nlet configuredDevBuild: boolean | undefined;\n\n/**\n * Tell the SDK whether the app around it was built for development.\n *\n * Call it once, at bootstrap, from a context {@link isDevBuild} cannot read:\n *\n * ```ts\n * import { setDevBuild } from \"tempest-react-sdk\";\n *\n * setDevBuild(import.meta.env.DEV);\n * ```\n *\n * **When you need it.** Not for an ordinary Vite, webpack, Rspack or Parcel\n * app: all of them substitute `process.env.NODE_ENV` while building the app, so\n * the automatic read already answers correctly there — measured for Vite 5\n * through 8 in {@link isDevBuild}, whose doc carries the table. What is left is\n * the context nothing compiles or nothing configures:\n *\n * - code no bundler transformed — a raw service-worker script registered as a\n * file of its own, a plain `<script type=\"module\">`;\n * - a staging or QA build that never sets `NODE_ENV=production`, where the\n * automatic answer is `true` and `parseResponse` would put the raw response\n * payload in an error string seen by real users. `setDevBuild(false)` closes\n * that;\n * - a test that wants the other branch, and puts it back on the way out.\n *\n * `import.meta.env.DEV` cannot be read by the SDK on your behalf, which is why\n * the signal is a parameter: Vite would replace it while building *this\n * package*, and the published artifact would ship the constant.\n *\n * The default stays `false` when the read throws. `parseResponse` puts the raw\n * response payload in its message when this is on, so guessing `true` in a\n * context that cannot prove it leaks a payload into a production error string.\n * Silence is the safe default; the report is one line away for anyone who wants\n * it.\n *\n * Passing `undefined` clears the override and returns to automatic detection,\n * which is what a test that set it should do on the way out.\n *\n * @param value - `true` for a development build, `false` for production,\n * `undefined` to go back to detecting it.\n *\n * @example\n * // A service worker, or any context no bundler transformed\n * setDevBuild(false);\n *\n * @example\n * // A test that flips it, and puts it back\n * afterEach(() => setDevBuild(undefined));\n */\nexport function setDevBuild(value: boolean | undefined): void {\n configuredDevBuild = value;\n}\n\nexport function isDevBuild(): boolean {\n if (configuredDevBuild !== undefined) return configuredDevBuild;\n try {\n return process.env.NODE_ENV !== \"production\";\n } catch {\n return false;\n }\n}\n"],"mappings":"AAkEA,IAAI,EAmDJ,SAAgB,EAAY,EAAkC,CAC1D,EAAqB,CACzB,CAEA,SAAgB,GAAsB,CAClC,GAAI,IAAuB,IAAA,GAAW,OAAO,EAC7C,GAAI,CACA,OAAA,QAAA,IAAA,WAAgC,YACpC,MAAQ,CACJ,MAAO,EACX,CACJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-mode.js","names":[],"sources":["../../src/utils/dev-mode.ts"],"sourcesContent":["/**\n * {@link isDevBuild} stays internal, imported by path (`../utils/dev-mode`)\n * rather than through the `utils` barrel: re-exporting it would make a one-line\n * env read part of the package's public API, with the semver weight that\n * carries, for something no consumer asked for. Every dev-only diagnostic in\n * the SDK routes through it — `grep -rn \"dev-mode\" src/` for the current list,\n * which an enumeration written here would only drift away from.\n *\n * {@link setDevBuild} is public, because
|
|
1
|
+
{"version":3,"file":"dev-mode.js","names":[],"sources":["../../src/utils/dev-mode.ts"],"sourcesContent":["/**\n * {@link isDevBuild} stays internal, imported by path (`../utils/dev-mode`)\n * rather than through the `utils` barrel: re-exporting it would make a one-line\n * env read part of the package's public API, with the semver weight that\n * carries, for something no consumer asked for. Every dev-only diagnostic in\n * the SDK routes through it — `grep -rn \"dev-mode\" src/` for the current list,\n * which an enumeration written here would only drift away from.\n *\n * {@link setDevBuild} is public, because a context nothing compiles cannot be\n * detected from the inside. See its doc for when that is.\n */\n\n/**\n * Whether the consuming app was built for development.\n *\n * Reads `process.env.NODE_ENV`, which every supported bundler replaces with a\n * literal **while building the app** — Vite included. That last word is a\n * correction: this doc used to claim Vite substitutes neither half, so every\n * dev-only diagnostic in the SDK was unreachable under `vite dev`. Measured on\n * 2026-09-07 with 0.61.0 installed into a probe app, both from a packed tarball\n * (a real copy under `node_modules`, which Vite pre-bundles) and from a `file:`\n * link (a symlink it does not), reading back the module the dev server actually\n * served:\n *\n * | Vite | `vite dev` | `vite build` |\n * | --- | --- | --- |\n * | 5.4.21, 6.4.3, 7.3.6 | folded to `true` | folded to `false` |\n * | 8.2.2 | `\"development\" !== \"production\"` | folded to `false` |\n *\n * So this answers correctly in a Vite app on its own, in development and in\n * production, pre-bundled or served through the dev server's transform. The\n * wrong belief survived releases because nobody read the served module — the\n * expression is not substituted in a *browser console*, which is where it is\n * natural to go looking.\n *\n * `import.meta.env.DEV` still cannot be used here: Vite would replace it while\n * building *this package*, so the published artifact would carry the constant\n * and every guard behind it would be dead code no app could switch back on.\n *\n * The expression is written out in full, and the failure is caught rather than\n * guarded against. A `typeof process === \"undefined\"` check would read as the\n * careful version and quietly break the environments that work: substitution\n * replaces the member expression `process.env.NODE_ENV` and nothing else, so\n * the guard would return early in front of a literal that had already been\n * swapped in. The identifier itself never exists at runtime — `typeof process`\n * is `\"undefined\"` in the page, measured in the same probe — which is exactly\n * why the read is wrapped in `try` instead.\n *\n * Returns `false` when the read throws, which is the context nothing\n * transformed: a raw service-worker script, a plain `<script type=\"module\">`, a\n * bundler substituting nothing. Staying quiet there is deliberate — a dev-only\n * warning that cannot prove it is in development is better silent than shouting\n * in someone's production console.\n *\n * {@link setDevBuild} overrides all of it and is checked first.\n *\n * @returns Whether development-only diagnostics should run.\n *\n * @example\n * if (isDevBuild()) console.warn(\"[my-app] this prop combination does nothing\");\n *\n * @tempest-limits empty-catch — the only thing the read can throw is the\n * environment answering \"not defined\", which is the return value, not an error\n * worth reporting. Logging it would print on every call in exactly the context\n * that has nowhere to print.\n */\nlet configuredDevBuild: boolean | undefined;\n\n/**\n * Tell the SDK whether the app around it was built for development.\n *\n * Call it once, at bootstrap, from a context {@link isDevBuild} cannot read:\n *\n * ```ts\n * import { setDevBuild } from \"tempest-react-sdk\";\n *\n * setDevBuild(import.meta.env.DEV);\n * ```\n *\n * **When you need it.** Not for an ordinary Vite, webpack, Rspack or Parcel\n * app: all of them substitute `process.env.NODE_ENV` while building the app, so\n * the automatic read already answers correctly there — measured for Vite 5\n * through 8 in {@link isDevBuild}, whose doc carries the table. What is left is\n * the context nothing compiles or nothing configures:\n *\n * - code no bundler transformed — a raw service-worker script registered as a\n * file of its own, a plain `<script type=\"module\">`;\n * - a staging or QA build that never sets `NODE_ENV=production`, where the\n * automatic answer is `true` and `parseResponse` would put the raw response\n * payload in an error string seen by real users. `setDevBuild(false)` closes\n * that;\n * - a test that wants the other branch, and puts it back on the way out.\n *\n * `import.meta.env.DEV` cannot be read by the SDK on your behalf, which is why\n * the signal is a parameter: Vite would replace it while building *this\n * package*, and the published artifact would ship the constant.\n *\n * The default stays `false` when the read throws. `parseResponse` puts the raw\n * response payload in its message when this is on, so guessing `true` in a\n * context that cannot prove it leaks a payload into a production error string.\n * Silence is the safe default; the report is one line away for anyone who wants\n * it.\n *\n * Passing `undefined` clears the override and returns to automatic detection,\n * which is what a test that set it should do on the way out.\n *\n * @param value - `true` for a development build, `false` for production,\n * `undefined` to go back to detecting it.\n *\n * @example\n * // A service worker, or any context no bundler transformed\n * setDevBuild(false);\n *\n * @example\n * // A test that flips it, and puts it back\n * afterEach(() => setDevBuild(undefined));\n */\nexport function setDevBuild(value: boolean | undefined): void {\n configuredDevBuild = value;\n}\n\nexport function isDevBuild(): boolean {\n if (configuredDevBuild !== undefined) return configuredDevBuild;\n try {\n return process.env.NODE_ENV !== \"production\";\n } catch {\n return false;\n }\n}\n"],"mappings":";AAkEA,IAAI;AAmDJ,SAAgB,EAAY,GAAkC;CAC1D,IAAqB;AACzB;AAEA,SAAgB,IAAsB;CAClC,IAAI,MAAuB,KAAA,GAAW,OAAO;CAC7C,IAAI;EACA,OAAA,QAAA,IAAA,aAAgC;CACpC,QAAQ;EACJ,OAAO;CACX;AACJ"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("./dev-mode.cjs");var
|
|
1
|
+
const e=require("./dev-mode.cjs"),t=require("./schema-like.cjs");var n=new Set;function r(t){e.isDevBuild()&&!n.has(t)&&(n.add(t),console.warn(`[tempest-react-sdk] ${t}: a frame was not valid JSON, so the raw string is being delivered as if it were your message type. Pass \`parser\` to decode it, or \`onParseError\` to drop it and handle the failure. This warning appears once.`))}function i(t,r){let i=`${t}:schema`;if(!e.isDevBuild()||n.has(i))return;n.add(i);let a=r.map(e=>`${e.path}: ${e.message}`).join(`; `);console.warn(`[tempest-react-sdk] ${t}: a frame did not match \`schema\` and was dropped (${a}). Pass \`onValidationError\` to handle it yourself. This warning appears once.`)}function a(e,n,a){let{parser:o,onParseError:s,schema:c,onValidationError:l}=a;function u(r){if(!c)return{delivered:!0,data:r};let a=t.validateWithSchema(c,r);return a.ok?{delivered:!0,data:a.data}:(l?l(a.issues,e):i(n,a.issues),{delivered:!1,data:void 0})}if(o)return u(o(e));let d;try{d=JSON.parse(e)}catch(t){return s?(s(t,e),{delivered:!1,data:void 0}):c?u(e):(r(n),{delivered:!0,data:e})}return u(d)}exports.decodeFrame=a;
|
|
2
2
|
//# sourceMappingURL=json-frame.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-frame.cjs","names":[],"sources":["../../src/utils/json-frame.ts"],"sourcesContent":["import { isDevBuild } from \"./dev-mode\";\n\n/**\n * The one decoder behind `createWebSocket`, `useWebSocket` and\n * `createEventStream`.\n *\n * Internal, and imported by path rather than through the `utils` barrel: it\n * exists so the three transports share one answer to \"the frame is not JSON\",\n * not so consumers can call it.\n *\n * That question used to have three identical copies of the same wrong answer —\n * `return raw as unknown as T`, which hands the consumer a `string` announced as\n * `T`. The failure never surfaced at the parse; it surfaced later, on the first\n * `message.id`, with nothing left to say the frame had not been JSON.\n */\n\n/** Outcome of decoding one frame. */\nexport interface DecodedFrame<T> {\n /** Whether the message should reach `onMessage`. */\n delivered: boolean;\n /** The decoded payload. Only meaningful when `delivered` is `true`. */\n data: T;\n}\n\nconst warned = new Set<string>();\n\n/**\n * Warn once per transport that a frame arrived which was not JSON.\n *\n * Once, because a stream sending text frames sends many, and a console line per\n * frame buries the one that mattered. Development builds only.\n *\n * @param transport - Label used in the message, e.g. `\"createWebSocket\"`.\n * @returns Nothing.\n */\nfunction warnOnce(transport: string): void {\n if (!isDevBuild() || warned.has(transport)) return;\n warned.add(transport);\n console.warn(\n `[tempest-react-sdk] ${transport}: a frame was not valid JSON, so the raw string is ` +\n `being delivered as if it were your message type. Pass \\`parser\\` to decode it, or ` +\n `\\`onParseError\\` to drop it and handle the failure. This warning appears once.`,\n );\n}\n\n/**\n * Decode one frame, reporting whether it should be delivered.\n *\n * A caller-supplied `parser` owns the frame completely
|
|
1
|
+
{"version":3,"file":"json-frame.cjs","names":[],"sources":["../../src/utils/json-frame.ts"],"sourcesContent":["import { isDevBuild } from \"./dev-mode\";\nimport { validateWithSchema, type SchemaIssue, type SchemaLike } from \"./schema-like\";\n\n/**\n * The one decoder behind `createWebSocket`, `useWebSocket` and\n * `createEventStream`.\n *\n * Internal, and imported by path rather than through the `utils` barrel: it\n * exists so the three transports share one answer to \"the frame is not JSON\",\n * not so consumers can call it.\n *\n * That question used to have three identical copies of the same wrong answer —\n * `return raw as unknown as T`, which hands the consumer a `string` announced as\n * `T`. The failure never surfaced at the parse; it surfaced later, on the first\n * `message.id`, with nothing left to say the frame had not been JSON.\n */\n\n/** Outcome of decoding one frame. */\nexport interface DecodedFrame<T> {\n /** Whether the message should reach `onMessage`. */\n delivered: boolean;\n /** The decoded payload. Only meaningful when `delivered` is `true`. */\n data: T;\n}\n\n/** How one frame should be turned into `T`, and who hears about failures. */\nexport interface DecodeFrameOptions<T> {\n /** Caller-supplied decoder, which owns the frame completely. */\n parser?: (raw: string) => T;\n /** Caller-supplied handler for a frame that is not valid JSON. */\n onParseError?: (error: unknown, raw: string) => void;\n /** Caller-supplied schema the decoded payload must satisfy. */\n schema?: SchemaLike<T>;\n /** Caller-supplied handler for a payload the schema refused. */\n onValidationError?: (issues: SchemaIssue[], raw: string) => void;\n}\n\nconst warned = new Set<string>();\n\n/**\n * Warn once per transport that a frame arrived which was not JSON.\n *\n * Once, because a stream sending text frames sends many, and a console line per\n * frame buries the one that mattered. Development builds only.\n *\n * @param transport - Label used in the message, e.g. `\"createWebSocket\"`.\n * @returns Nothing.\n */\nfunction warnOnce(transport: string): void {\n if (!isDevBuild() || warned.has(transport)) return;\n warned.add(transport);\n console.warn(\n `[tempest-react-sdk] ${transport}: a frame was not valid JSON, so the raw string is ` +\n `being delivered as if it were your message type. Pass \\`parser\\` to decode it, or ` +\n `\\`onParseError\\` to drop it and handle the failure. This warning appears once.`,\n );\n}\n\n/**\n * Warn once per transport that a frame was dropped by the schema.\n *\n * A dropped frame with no `onValidationError` is otherwise completely silent —\n * the stream looks healthy and the payload simply never arrives, which is the\n * hardest shape of failure to notice. Development builds only, once, for the\n * same reason as {@link warnOnce}.\n *\n * @param transport - Label used in the message, e.g. `\"createEventStream\"`.\n * @param issues - The issues the schema reported, summarized into the message.\n * @returns Nothing.\n */\nfunction warnValidationOnce(transport: string, issues: SchemaIssue[]): void {\n const key = `${transport}:schema`;\n if (!isDevBuild() || warned.has(key)) return;\n warned.add(key);\n const summary = issues.map((issue) => `${issue.path}: ${issue.message}`).join(\"; \");\n console.warn(\n `[tempest-react-sdk] ${transport}: a frame did not match \\`schema\\` and was dropped ` +\n `(${summary}). Pass \\`onValidationError\\` to handle it yourself. This warning ` +\n `appears once.`,\n );\n}\n\n/**\n * Decode one frame, reporting whether it should be delivered.\n *\n * A caller-supplied `parser` owns the frame completely: its result is delivered\n * as it is, or validated when a `schema` was also supplied — decoding text,\n * binary-as-base64 or a protocol of its own is the point of that option.\n *\n * Without one, the frame is parsed as JSON. When that throws:\n *\n * - with `onParseError`, the callback fires and the frame is **not** delivered,\n * because a consumer that asked to hear about failures did not ask to also\n * receive the broken frame;\n * - with `schema` and no `onParseError`, the raw string goes to the schema,\n * which refuses it — a caller who asked for validation never receives an\n * unvalidated payload, and a frame the server sent empty is exactly this case;\n * - with neither, the raw string is delivered as `T` — the behaviour every\n * version before this one had, kept so nothing breaks — and development builds\n * warn once that it happened.\n *\n * With a `schema`, a payload the schema refuses is not delivered, and\n * `onValidationError` hears the issues. The value delivered is the schema's\n * **output**, so a schema that coerces or defaults is honoured.\n *\n * @param raw - The frame body as text.\n * @param transport - Label used in the development warnings.\n * @param options - Caller-supplied decoder, schema and failure handlers.\n * @returns Whether to deliver, and the payload.\n */\nexport function decodeFrame<T>(\n raw: string,\n transport: string,\n options: DecodeFrameOptions<T>,\n): DecodedFrame<T> {\n const { parser, onParseError, schema, onValidationError } = options;\n\n /**\n * Put one decoded payload through the schema, when there is one.\n *\n * @param value - The payload as parsing produced it.\n * @returns Whether to deliver, and the payload the consumer should see.\n */\n function gate(value: unknown): DecodedFrame<T> {\n if (!schema) return { delivered: true, data: value as T };\n const result = validateWithSchema(schema, value);\n if (result.ok) return { delivered: true, data: result.data };\n if (onValidationError) onValidationError(result.issues, raw);\n else warnValidationOnce(transport, result.issues);\n return { delivered: false, data: undefined as T };\n }\n\n if (parser) return gate(parser(raw));\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (error) {\n if (onParseError) {\n onParseError(error, raw);\n return { delivered: false, data: undefined as T };\n }\n if (schema) return gate(raw);\n warnOnce(transport);\n return { delivered: true, data: raw as unknown as T };\n }\n return gate(parsed);\n}\n\n/**\n * Forget which transports have already warned.\n *\n * Exists for tests, which would otherwise see the first case swallow the\n * warning for every case after it.\n *\n * @returns Nothing.\n */\nexport function resetFrameWarnings(): void {\n warned.clear();\n}\n"],"mappings":"iEAqCA,IAAM,EAAS,IAAI,IAWnB,SAAS,EAAS,EAAyB,CAClC,EAAA,WAAW,GAAK,GAAO,IAAI,CAAS,IACzC,EAAO,IAAI,CAAS,EACpB,QAAQ,KACJ,uBAAuB,EAAU,oNAGrC,EACJ,CAcA,SAAS,EAAmB,EAAmB,EAA6B,CACxE,IAAM,EAAM,GAAG,EAAU,SACzB,GAAI,CAAC,EAAA,WAAW,GAAK,EAAO,IAAI,CAAG,EAAG,OACtC,EAAO,IAAI,CAAG,EACd,IAAM,EAAU,EAAO,IAAK,GAAU,GAAG,EAAM,KAAK,IAAI,EAAM,SAAS,CAAC,CAAC,KAAK,IAAI,EAClF,QAAQ,KACJ,uBAAuB,EAAU,sDACzB,EAAQ,gFAEpB,CACJ,CA8BA,SAAgB,EACZ,EACA,EACA,EACe,CACf,GAAM,CAAE,SAAQ,eAAc,SAAQ,qBAAsB,EAQ5D,SAAS,EAAK,EAAiC,CAC3C,GAAI,CAAC,EAAQ,MAAO,CAAE,UAAW,GAAM,KAAM,CAAW,EACxD,IAAM,EAAS,EAAA,mBAAmB,EAAQ,CAAK,EAI/C,OAHI,EAAO,GAAW,CAAE,UAAW,GAAM,KAAM,EAAO,IAAK,GACvD,EAAmB,EAAkB,EAAO,OAAQ,CAAG,EACtD,EAAmB,EAAW,EAAO,MAAM,EACzC,CAAE,UAAW,GAAO,KAAM,IAAA,EAAe,EACpD,CAEA,GAAI,EAAQ,OAAO,EAAK,EAAO,CAAG,CAAC,EACnC,IAAI,EACJ,GAAI,CACA,EAAS,KAAK,MAAM,CAAG,CAC3B,OAAS,EAAO,CAOZ,OANI,GACA,EAAa,EAAO,CAAG,EAChB,CAAE,UAAW,GAAO,KAAM,IAAA,EAAe,GAEhD,EAAe,EAAK,CAAG,GAC3B,EAAS,CAAS,EACX,CAAE,UAAW,GAAM,KAAM,CAAoB,EACxD,CACA,OAAO,EAAK,CAAM,CACtB"}
|
package/dist/utils/json-frame.js
CHANGED
|
@@ -1,30 +1,49 @@
|
|
|
1
1
|
import { isDevBuild as e } from "./dev-mode.js";
|
|
2
|
+
import { validateWithSchema as t } from "./schema-like.js";
|
|
2
3
|
//#region src/utils/json-frame.ts
|
|
3
|
-
var
|
|
4
|
-
function
|
|
5
|
-
e() && !
|
|
4
|
+
var n = /* @__PURE__ */ new Set();
|
|
5
|
+
function r(t) {
|
|
6
|
+
e() && !n.has(t) && (n.add(t), console.warn(`[tempest-react-sdk] ${t}: a frame was not valid JSON, so the raw string is being delivered as if it were your message type. Pass \`parser\` to decode it, or \`onParseError\` to drop it and handle the failure. This warning appears once.`));
|
|
6
7
|
}
|
|
7
|
-
function
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
function i(t, r) {
|
|
9
|
+
let i = `${t}:schema`;
|
|
10
|
+
if (!e() || n.has(i)) return;
|
|
11
|
+
n.add(i);
|
|
12
|
+
let a = r.map((e) => `${e.path}: ${e.message}`).join("; ");
|
|
13
|
+
console.warn(`[tempest-react-sdk] ${t}: a frame did not match \`schema\` and was dropped (${a}). Pass \`onValidationError\` to handle it yourself. This warning appears once.`);
|
|
14
|
+
}
|
|
15
|
+
function a(e, n, a) {
|
|
16
|
+
let { parser: o, onParseError: s, schema: c, onValidationError: l } = a;
|
|
17
|
+
function u(r) {
|
|
18
|
+
if (!c) return {
|
|
14
19
|
delivered: !0,
|
|
15
|
-
data:
|
|
20
|
+
data: r
|
|
16
21
|
};
|
|
22
|
+
let a = t(c, r);
|
|
23
|
+
return a.ok ? {
|
|
24
|
+
delivered: !0,
|
|
25
|
+
data: a.data
|
|
26
|
+
} : (l ? l(a.issues, e) : i(n, a.issues), {
|
|
27
|
+
delivered: !1,
|
|
28
|
+
data: void 0
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
if (o) return u(o(e));
|
|
32
|
+
let d;
|
|
33
|
+
try {
|
|
34
|
+
d = JSON.parse(e);
|
|
17
35
|
} catch (t) {
|
|
18
|
-
return
|
|
36
|
+
return s ? (s(t, e), {
|
|
19
37
|
delivered: !1,
|
|
20
38
|
data: void 0
|
|
21
|
-
}) : (n
|
|
39
|
+
}) : c ? u(e) : (r(n), {
|
|
22
40
|
delivered: !0,
|
|
23
41
|
data: e
|
|
24
42
|
});
|
|
25
43
|
}
|
|
44
|
+
return u(d);
|
|
26
45
|
}
|
|
27
46
|
//#endregion
|
|
28
|
-
export {
|
|
47
|
+
export { a as decodeFrame };
|
|
29
48
|
|
|
30
49
|
//# sourceMappingURL=json-frame.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-frame.js","names":[],"sources":["../../src/utils/json-frame.ts"],"sourcesContent":["import { isDevBuild } from \"./dev-mode\";\n\n/**\n * The one decoder behind `createWebSocket`, `useWebSocket` and\n * `createEventStream`.\n *\n * Internal, and imported by path rather than through the `utils` barrel: it\n * exists so the three transports share one answer to \"the frame is not JSON\",\n * not so consumers can call it.\n *\n * That question used to have three identical copies of the same wrong answer —\n * `return raw as unknown as T`, which hands the consumer a `string` announced as\n * `T`. The failure never surfaced at the parse; it surfaced later, on the first\n * `message.id`, with nothing left to say the frame had not been JSON.\n */\n\n/** Outcome of decoding one frame. */\nexport interface DecodedFrame<T> {\n /** Whether the message should reach `onMessage`. */\n delivered: boolean;\n /** The decoded payload. Only meaningful when `delivered` is `true`. */\n data: T;\n}\n\nconst warned = new Set<string>();\n\n/**\n * Warn once per transport that a frame arrived which was not JSON.\n *\n * Once, because a stream sending text frames sends many, and a console line per\n * frame buries the one that mattered. Development builds only.\n *\n * @param transport - Label used in the message, e.g. `\"createWebSocket\"`.\n * @returns Nothing.\n */\nfunction warnOnce(transport: string): void {\n if (!isDevBuild() || warned.has(transport)) return;\n warned.add(transport);\n console.warn(\n `[tempest-react-sdk] ${transport}: a frame was not valid JSON, so the raw string is ` +\n `being delivered as if it were your message type. Pass \\`parser\\` to decode it, or ` +\n `\\`onParseError\\` to drop it and handle the failure. This warning appears once.`,\n );\n}\n\n/**\n * Decode one frame, reporting whether it should be delivered.\n *\n * A caller-supplied `parser` owns the frame completely
|
|
1
|
+
{"version":3,"file":"json-frame.js","names":[],"sources":["../../src/utils/json-frame.ts"],"sourcesContent":["import { isDevBuild } from \"./dev-mode\";\nimport { validateWithSchema, type SchemaIssue, type SchemaLike } from \"./schema-like\";\n\n/**\n * The one decoder behind `createWebSocket`, `useWebSocket` and\n * `createEventStream`.\n *\n * Internal, and imported by path rather than through the `utils` barrel: it\n * exists so the three transports share one answer to \"the frame is not JSON\",\n * not so consumers can call it.\n *\n * That question used to have three identical copies of the same wrong answer —\n * `return raw as unknown as T`, which hands the consumer a `string` announced as\n * `T`. The failure never surfaced at the parse; it surfaced later, on the first\n * `message.id`, with nothing left to say the frame had not been JSON.\n */\n\n/** Outcome of decoding one frame. */\nexport interface DecodedFrame<T> {\n /** Whether the message should reach `onMessage`. */\n delivered: boolean;\n /** The decoded payload. Only meaningful when `delivered` is `true`. */\n data: T;\n}\n\n/** How one frame should be turned into `T`, and who hears about failures. */\nexport interface DecodeFrameOptions<T> {\n /** Caller-supplied decoder, which owns the frame completely. */\n parser?: (raw: string) => T;\n /** Caller-supplied handler for a frame that is not valid JSON. */\n onParseError?: (error: unknown, raw: string) => void;\n /** Caller-supplied schema the decoded payload must satisfy. */\n schema?: SchemaLike<T>;\n /** Caller-supplied handler for a payload the schema refused. */\n onValidationError?: (issues: SchemaIssue[], raw: string) => void;\n}\n\nconst warned = new Set<string>();\n\n/**\n * Warn once per transport that a frame arrived which was not JSON.\n *\n * Once, because a stream sending text frames sends many, and a console line per\n * frame buries the one that mattered. Development builds only.\n *\n * @param transport - Label used in the message, e.g. `\"createWebSocket\"`.\n * @returns Nothing.\n */\nfunction warnOnce(transport: string): void {\n if (!isDevBuild() || warned.has(transport)) return;\n warned.add(transport);\n console.warn(\n `[tempest-react-sdk] ${transport}: a frame was not valid JSON, so the raw string is ` +\n `being delivered as if it were your message type. Pass \\`parser\\` to decode it, or ` +\n `\\`onParseError\\` to drop it and handle the failure. This warning appears once.`,\n );\n}\n\n/**\n * Warn once per transport that a frame was dropped by the schema.\n *\n * A dropped frame with no `onValidationError` is otherwise completely silent —\n * the stream looks healthy and the payload simply never arrives, which is the\n * hardest shape of failure to notice. Development builds only, once, for the\n * same reason as {@link warnOnce}.\n *\n * @param transport - Label used in the message, e.g. `\"createEventStream\"`.\n * @param issues - The issues the schema reported, summarized into the message.\n * @returns Nothing.\n */\nfunction warnValidationOnce(transport: string, issues: SchemaIssue[]): void {\n const key = `${transport}:schema`;\n if (!isDevBuild() || warned.has(key)) return;\n warned.add(key);\n const summary = issues.map((issue) => `${issue.path}: ${issue.message}`).join(\"; \");\n console.warn(\n `[tempest-react-sdk] ${transport}: a frame did not match \\`schema\\` and was dropped ` +\n `(${summary}). Pass \\`onValidationError\\` to handle it yourself. This warning ` +\n `appears once.`,\n );\n}\n\n/**\n * Decode one frame, reporting whether it should be delivered.\n *\n * A caller-supplied `parser` owns the frame completely: its result is delivered\n * as it is, or validated when a `schema` was also supplied — decoding text,\n * binary-as-base64 or a protocol of its own is the point of that option.\n *\n * Without one, the frame is parsed as JSON. When that throws:\n *\n * - with `onParseError`, the callback fires and the frame is **not** delivered,\n * because a consumer that asked to hear about failures did not ask to also\n * receive the broken frame;\n * - with `schema` and no `onParseError`, the raw string goes to the schema,\n * which refuses it — a caller who asked for validation never receives an\n * unvalidated payload, and a frame the server sent empty is exactly this case;\n * - with neither, the raw string is delivered as `T` — the behaviour every\n * version before this one had, kept so nothing breaks — and development builds\n * warn once that it happened.\n *\n * With a `schema`, a payload the schema refuses is not delivered, and\n * `onValidationError` hears the issues. The value delivered is the schema's\n * **output**, so a schema that coerces or defaults is honoured.\n *\n * @param raw - The frame body as text.\n * @param transport - Label used in the development warnings.\n * @param options - Caller-supplied decoder, schema and failure handlers.\n * @returns Whether to deliver, and the payload.\n */\nexport function decodeFrame<T>(\n raw: string,\n transport: string,\n options: DecodeFrameOptions<T>,\n): DecodedFrame<T> {\n const { parser, onParseError, schema, onValidationError } = options;\n\n /**\n * Put one decoded payload through the schema, when there is one.\n *\n * @param value - The payload as parsing produced it.\n * @returns Whether to deliver, and the payload the consumer should see.\n */\n function gate(value: unknown): DecodedFrame<T> {\n if (!schema) return { delivered: true, data: value as T };\n const result = validateWithSchema(schema, value);\n if (result.ok) return { delivered: true, data: result.data };\n if (onValidationError) onValidationError(result.issues, raw);\n else warnValidationOnce(transport, result.issues);\n return { delivered: false, data: undefined as T };\n }\n\n if (parser) return gate(parser(raw));\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (error) {\n if (onParseError) {\n onParseError(error, raw);\n return { delivered: false, data: undefined as T };\n }\n if (schema) return gate(raw);\n warnOnce(transport);\n return { delivered: true, data: raw as unknown as T };\n }\n return gate(parsed);\n}\n\n/**\n * Forget which transports have already warned.\n *\n * Exists for tests, which would otherwise see the first case swallow the\n * warning for every case after it.\n *\n * @returns Nothing.\n */\nexport function resetFrameWarnings(): void {\n warned.clear();\n}\n"],"mappings":";;;AAqCA,IAAM,oBAAS,IAAI,IAAY;AAW/B,SAAS,EAAS,GAAyB;CACnC,AAAC,EAAW,KAAK,GAAO,IAAI,CAAS,MACzC,EAAO,IAAI,CAAS,GACpB,QAAQ,KACJ,uBAAuB,EAAU,oNAGrC;AACJ;AAcA,SAAS,EAAmB,GAAmB,GAA6B;CACxE,IAAM,IAAM,GAAG,EAAU;CACzB,IAAI,CAAC,EAAW,KAAK,EAAO,IAAI,CAAG,GAAG;CACtC,EAAO,IAAI,CAAG;CACd,IAAM,IAAU,EAAO,KAAK,MAAU,GAAG,EAAM,KAAK,IAAI,EAAM,SAAS,CAAC,CAAC,KAAK,IAAI;CAClF,QAAQ,KACJ,uBAAuB,EAAU,sDACzB,EAAQ,gFAEpB;AACJ;AA8BA,SAAgB,EACZ,GACA,GACA,GACe;CACf,IAAM,EAAE,WAAQ,iBAAc,WAAQ,yBAAsB;CAQ5D,SAAS,EAAK,GAAiC;EAC3C,IAAI,CAAC,GAAQ,OAAO;GAAE,WAAW;GAAM,MAAM;EAAW;EACxD,IAAM,IAAS,EAAmB,GAAQ,CAAK;EAI/C,OAHI,EAAO,KAAW;GAAE,WAAW;GAAM,MAAM,EAAO;EAAK,KACvD,IAAmB,EAAkB,EAAO,QAAQ,CAAG,IACtD,EAAmB,GAAW,EAAO,MAAM,GACzC;GAAE,WAAW;GAAO,MAAM,KAAA;EAAe;CACpD;CAEA,IAAI,GAAQ,OAAO,EAAK,EAAO,CAAG,CAAC;CACnC,IAAI;CACJ,IAAI;EACA,IAAS,KAAK,MAAM,CAAG;CAC3B,SAAS,GAAO;EAOZ,OANI,KACA,EAAa,GAAO,CAAG,GAChB;GAAE,WAAW;GAAO,MAAM,KAAA;EAAe,KAEhD,IAAe,EAAK,CAAG,KAC3B,EAAS,CAAS,GACX;GAAE,WAAW;GAAM,MAAM;EAAoB;CACxD;CACA,OAAO,EAAK,CAAM;AACtB"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e={path:`<root>`,message:`the schema validated asynchronously, and a frame is decoded synchronously — there is nowhere to await it. Use a synchronous schema, or validate inside your own handler.`};function t(e){return!e||e.length===0?`<root>`:e.map(e=>String(typeof e==`object`&&e?e.key:e)).join(`.`)}function n(e){return{path:t(e.path),message:e.message}}function r(t,r){if(`~standard`in t){let i=t[`~standard`].validate(r);if(typeof i.then==`function`)return{ok:!1,issues:[e]};let a=i;return a.issues?{ok:!1,issues:a.issues.map(n)}:{ok:!0,data:a.value}}let i=t.safeParse(r);return i.success?{ok:!0,data:i.data}:{ok:!1,issues:i.error.issues.map(n)}}exports.validateWithSchema=r;
|
|
2
|
+
//# sourceMappingURL=schema-like.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-like.cjs","names":[],"sources":["../../src/utils/schema-like.ts"],"sourcesContent":["/**\n * The SDK's answer to \"the caller handed me a schema\" — one normalizer behind\n * every option that takes one.\n *\n * Internal, and imported by path rather than through the `utils` barrel: the\n * function exists so `decodeFrame` and anything else that validates a payload\n * share one reading of the two shapes below, not so consumers can call it. The\n * types are public, because an option typed `SchemaLike<T>` is a name the\n * consumer has to be able to write down.\n *\n * Two shapes are accepted on purpose:\n *\n * - [Standard Schema](https://standardschema.dev) (`~standard`), which zod\n * (>=3.24), valibot and arktype all implement, so the SDK validates against\n * any of them without depending on one;\n * - `.safeParse`, because the SDK's own zod range starts at `^3.23.0`, which\n * predates `~standard`, and because it is the method every zod user already\n * knows.\n */\n\n/** One field-level complaint from a schema validation. */\nexport interface SchemaIssue {\n /** Dotted path to the offending field, or `\"<root>\"` for the value itself. */\n path: string;\n /** What the validator said was wrong. */\n message: string;\n}\n\n/** A path segment as Standard Schema reports it: a key, or an object holding one. */\ntype IssuePathSegment = PropertyKey | { readonly key: PropertyKey };\n\n/** One issue as either supported shape reports it. */\ninterface RawIssue {\n readonly message: string;\n readonly path?: readonly IssuePathSegment[] | undefined;\n}\n\n/** A schema exposing the [Standard Schema](https://standardschema.dev) interface. */\nexport interface StandardSchemaLike<T> {\n readonly \"~standard\": {\n readonly validate: (\n value: unknown,\n ) =>\n | { readonly value: T; readonly issues?: undefined }\n | { readonly issues: readonly RawIssue[] }\n | Promise<\n | { readonly value: T; readonly issues?: undefined }\n | { readonly issues: readonly RawIssue[] }\n >;\n };\n}\n\n/** A schema exposing zod's `.safeParse`, including versions older than `~standard`. */\nexport interface SafeParseSchemaLike<T> {\n readonly safeParse: (\n value: unknown,\n ) =>\n | { readonly success: true; readonly data: T }\n | { readonly success: false; readonly error: { readonly issues: readonly RawIssue[] } };\n}\n\n/** Anything the SDK can validate a payload against. */\nexport type SchemaLike<T> = StandardSchemaLike<T> | SafeParseSchemaLike<T>;\n\n/** Outcome of validating one value against a {@link SchemaLike}. */\nexport type SchemaValidation<T> = { ok: true; data: T } | { ok: false; issues: SchemaIssue[] };\n\n/**\n * The issue reported when a schema answers asynchronously.\n *\n * A frame is decoded inside the transport's `message` handler and delivered from\n * it, so there is nowhere to await: awaiting would deliver frames in whatever\n * order their validations settled, which is worse than refusing. Reported as a\n * validation failure rather than thrown, so it arrives through the same\n * `onValidationError` the caller already registered.\n */\nconst ASYNC_ISSUE: SchemaIssue = {\n path: \"<root>\",\n message:\n \"the schema validated asynchronously, and a frame is decoded synchronously — \" +\n \"there is nowhere to await it. Use a synchronous schema, or validate inside your \" +\n \"own handler.\",\n};\n\n/**\n * Format a Standard Schema issue path as a dotted string.\n *\n * @param path - The reported path, if any.\n * @returns The dotted path, or `\"<root>\"` when the value itself is at fault.\n */\nfunction formatPath(path: readonly IssuePathSegment[] | undefined): string {\n if (!path || path.length === 0) return \"<root>\";\n return path\n .map((segment) =>\n typeof segment === \"object\" && segment !== null ? String(segment.key) : String(segment),\n )\n .join(\".\");\n}\n\n/**\n * Normalize one issue from either supported shape.\n *\n * @param issue - The issue as the validator reported it.\n * @returns The issue with a dotted path.\n */\nfunction toIssue(issue: RawIssue): SchemaIssue {\n return { path: formatPath(issue.path), message: issue.message };\n}\n\n/**\n * Validate a value against a schema, whichever of the two shapes it has.\n *\n * @param schema - A Standard Schema or a `.safeParse` schema.\n * @param value - The value to validate.\n * @returns The validated output, or the issues explaining why it was refused.\n */\nexport function validateWithSchema<T>(schema: SchemaLike<T>, value: unknown): SchemaValidation<T> {\n if (\"~standard\" in schema) {\n const result = schema[\"~standard\"].validate(value);\n if (typeof (result as { then?: unknown }).then === \"function\") {\n return { ok: false, issues: [ASYNC_ISSUE] };\n }\n const settled = result as\n | { readonly value: T; readonly issues?: undefined }\n | { readonly issues: readonly RawIssue[] };\n if (settled.issues) return { ok: false, issues: settled.issues.map(toIssue) };\n return { ok: true, data: settled.value };\n }\n const result = schema.safeParse(value);\n if (result.success) return { ok: true, data: result.data };\n return { ok: false, issues: result.error.issues.map(toIssue) };\n}\n"],"mappings":"AA4EA,IAAM,EAA2B,CAC7B,KAAM,SACN,QACI,0KAGR,EAQA,SAAS,EAAW,EAAuD,CAEvE,MADI,CAAC,GAAQ,EAAK,SAAW,EAAU,SAChC,EACF,IAAK,GACgD,OAAlD,OAAO,GAAY,UAAY,EAA0B,EAAQ,IAAc,CAAO,CAC1F,CAAC,CACA,KAAK,GAAG,CACjB,CAQA,SAAS,EAAQ,EAA8B,CAC3C,MAAO,CAAE,KAAM,EAAW,EAAM,IAAI,EAAG,QAAS,EAAM,OAAQ,CAClE,CASA,SAAgB,EAAsB,EAAuB,EAAqC,CAC9F,GAAI,cAAe,EAAQ,CACvB,IAAM,EAAS,EAAO,YAAY,CAAC,SAAS,CAAK,EACjD,GAAI,OAAQ,EAA8B,MAAS,WAC/C,MAAO,CAAE,GAAI,GAAO,OAAQ,CAAC,CAAW,CAAE,EAE9C,IAAM,EAAU,EAIhB,OADI,EAAQ,OAAe,CAAE,GAAI,GAAO,OAAQ,EAAQ,OAAO,IAAI,CAAO,CAAE,EACrE,CAAE,GAAI,GAAM,KAAM,EAAQ,KAAM,CAC3C,CACA,IAAM,EAAS,EAAO,UAAU,CAAK,EAErC,OADI,EAAO,QAAgB,CAAE,GAAI,GAAM,KAAM,EAAO,IAAK,EAClD,CAAE,GAAI,GAAO,OAAQ,EAAO,MAAM,OAAO,IAAI,CAAO,CAAE,CACjE"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
//#region src/utils/schema-like.ts
|
|
2
|
+
var e = {
|
|
3
|
+
path: "<root>",
|
|
4
|
+
message: "the schema validated asynchronously, and a frame is decoded synchronously — there is nowhere to await it. Use a synchronous schema, or validate inside your own handler."
|
|
5
|
+
};
|
|
6
|
+
function t(e) {
|
|
7
|
+
return !e || e.length === 0 ? "<root>" : e.map((e) => String(typeof e == "object" && e ? e.key : e)).join(".");
|
|
8
|
+
}
|
|
9
|
+
function n(e) {
|
|
10
|
+
return {
|
|
11
|
+
path: t(e.path),
|
|
12
|
+
message: e.message
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function r(t, r) {
|
|
16
|
+
if ("~standard" in t) {
|
|
17
|
+
let i = t["~standard"].validate(r);
|
|
18
|
+
if (typeof i.then == "function") return {
|
|
19
|
+
ok: !1,
|
|
20
|
+
issues: [e]
|
|
21
|
+
};
|
|
22
|
+
let a = i;
|
|
23
|
+
return a.issues ? {
|
|
24
|
+
ok: !1,
|
|
25
|
+
issues: a.issues.map(n)
|
|
26
|
+
} : {
|
|
27
|
+
ok: !0,
|
|
28
|
+
data: a.value
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
let i = t.safeParse(r);
|
|
32
|
+
return i.success ? {
|
|
33
|
+
ok: !0,
|
|
34
|
+
data: i.data
|
|
35
|
+
} : {
|
|
36
|
+
ok: !1,
|
|
37
|
+
issues: i.error.issues.map(n)
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
export { r as validateWithSchema };
|
|
42
|
+
|
|
43
|
+
//# sourceMappingURL=schema-like.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-like.js","names":[],"sources":["../../src/utils/schema-like.ts"],"sourcesContent":["/**\n * The SDK's answer to \"the caller handed me a schema\" — one normalizer behind\n * every option that takes one.\n *\n * Internal, and imported by path rather than through the `utils` barrel: the\n * function exists so `decodeFrame` and anything else that validates a payload\n * share one reading of the two shapes below, not so consumers can call it. The\n * types are public, because an option typed `SchemaLike<T>` is a name the\n * consumer has to be able to write down.\n *\n * Two shapes are accepted on purpose:\n *\n * - [Standard Schema](https://standardschema.dev) (`~standard`), which zod\n * (>=3.24), valibot and arktype all implement, so the SDK validates against\n * any of them without depending on one;\n * - `.safeParse`, because the SDK's own zod range starts at `^3.23.0`, which\n * predates `~standard`, and because it is the method every zod user already\n * knows.\n */\n\n/** One field-level complaint from a schema validation. */\nexport interface SchemaIssue {\n /** Dotted path to the offending field, or `\"<root>\"` for the value itself. */\n path: string;\n /** What the validator said was wrong. */\n message: string;\n}\n\n/** A path segment as Standard Schema reports it: a key, or an object holding one. */\ntype IssuePathSegment = PropertyKey | { readonly key: PropertyKey };\n\n/** One issue as either supported shape reports it. */\ninterface RawIssue {\n readonly message: string;\n readonly path?: readonly IssuePathSegment[] | undefined;\n}\n\n/** A schema exposing the [Standard Schema](https://standardschema.dev) interface. */\nexport interface StandardSchemaLike<T> {\n readonly \"~standard\": {\n readonly validate: (\n value: unknown,\n ) =>\n | { readonly value: T; readonly issues?: undefined }\n | { readonly issues: readonly RawIssue[] }\n | Promise<\n | { readonly value: T; readonly issues?: undefined }\n | { readonly issues: readonly RawIssue[] }\n >;\n };\n}\n\n/** A schema exposing zod's `.safeParse`, including versions older than `~standard`. */\nexport interface SafeParseSchemaLike<T> {\n readonly safeParse: (\n value: unknown,\n ) =>\n | { readonly success: true; readonly data: T }\n | { readonly success: false; readonly error: { readonly issues: readonly RawIssue[] } };\n}\n\n/** Anything the SDK can validate a payload against. */\nexport type SchemaLike<T> = StandardSchemaLike<T> | SafeParseSchemaLike<T>;\n\n/** Outcome of validating one value against a {@link SchemaLike}. */\nexport type SchemaValidation<T> = { ok: true; data: T } | { ok: false; issues: SchemaIssue[] };\n\n/**\n * The issue reported when a schema answers asynchronously.\n *\n * A frame is decoded inside the transport's `message` handler and delivered from\n * it, so there is nowhere to await: awaiting would deliver frames in whatever\n * order their validations settled, which is worse than refusing. Reported as a\n * validation failure rather than thrown, so it arrives through the same\n * `onValidationError` the caller already registered.\n */\nconst ASYNC_ISSUE: SchemaIssue = {\n path: \"<root>\",\n message:\n \"the schema validated asynchronously, and a frame is decoded synchronously — \" +\n \"there is nowhere to await it. Use a synchronous schema, or validate inside your \" +\n \"own handler.\",\n};\n\n/**\n * Format a Standard Schema issue path as a dotted string.\n *\n * @param path - The reported path, if any.\n * @returns The dotted path, or `\"<root>\"` when the value itself is at fault.\n */\nfunction formatPath(path: readonly IssuePathSegment[] | undefined): string {\n if (!path || path.length === 0) return \"<root>\";\n return path\n .map((segment) =>\n typeof segment === \"object\" && segment !== null ? String(segment.key) : String(segment),\n )\n .join(\".\");\n}\n\n/**\n * Normalize one issue from either supported shape.\n *\n * @param issue - The issue as the validator reported it.\n * @returns The issue with a dotted path.\n */\nfunction toIssue(issue: RawIssue): SchemaIssue {\n return { path: formatPath(issue.path), message: issue.message };\n}\n\n/**\n * Validate a value against a schema, whichever of the two shapes it has.\n *\n * @param schema - A Standard Schema or a `.safeParse` schema.\n * @param value - The value to validate.\n * @returns The validated output, or the issues explaining why it was refused.\n */\nexport function validateWithSchema<T>(schema: SchemaLike<T>, value: unknown): SchemaValidation<T> {\n if (\"~standard\" in schema) {\n const result = schema[\"~standard\"].validate(value);\n if (typeof (result as { then?: unknown }).then === \"function\") {\n return { ok: false, issues: [ASYNC_ISSUE] };\n }\n const settled = result as\n | { readonly value: T; readonly issues?: undefined }\n | { readonly issues: readonly RawIssue[] };\n if (settled.issues) return { ok: false, issues: settled.issues.map(toIssue) };\n return { ok: true, data: settled.value };\n }\n const result = schema.safeParse(value);\n if (result.success) return { ok: true, data: result.data };\n return { ok: false, issues: result.error.issues.map(toIssue) };\n}\n"],"mappings":";AA4EA,IAAM,IAA2B;CAC7B,MAAM;CACN,SACI;AAGR;AAQA,SAAS,EAAW,GAAuD;CAEvE,OADI,CAAC,KAAQ,EAAK,WAAW,IAAU,WAChC,EACF,KAAK,MACgD,OAAlD,OAAO,KAAY,YAAY,IAA0B,EAAQ,MAAc,CAAO,CAC1F,CAAC,CACA,KAAK,GAAG;AACjB;AAQA,SAAS,EAAQ,GAA8B;CAC3C,OAAO;EAAE,MAAM,EAAW,EAAM,IAAI;EAAG,SAAS,EAAM;CAAQ;AAClE;AASA,SAAgB,EAAsB,GAAuB,GAAqC;CAC9F,IAAI,eAAe,GAAQ;EACvB,IAAM,IAAS,EAAO,YAAY,CAAC,SAAS,CAAK;EACjD,IAAI,OAAQ,EAA8B,QAAS,YAC/C,OAAO;GAAE,IAAI;GAAO,QAAQ,CAAC,CAAW;EAAE;EAE9C,IAAM,IAAU;EAIhB,OADI,EAAQ,SAAe;GAAE,IAAI;GAAO,QAAQ,EAAQ,OAAO,IAAI,CAAO;EAAE,IACrE;GAAE,IAAI;GAAM,MAAM,EAAQ;EAAM;CAC3C;CACA,IAAM,IAAS,EAAO,UAAU,CAAK;CAErC,OADI,EAAO,UAAgB;EAAE,IAAI;EAAM,MAAM,EAAO;CAAK,IAClD;EAAE,IAAI;EAAO,QAAQ,EAAO,MAAM,OAAO,IAAI,CAAO;CAAE;AACjE"}
|