@structured-id/ui-core 4.3.1 → 4.4.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/package.json +2 -2
- package/src/composables/index.ts +1 -8
- package/src/composables/useGrpc.test.ts +9 -125
- package/src/composables/useGrpc.ts +11 -64
- package/src/index.ts +0 -2
- package/src/profile/components/SidLoginForm.test.ts +0 -1
- package/src/profile/components/SidLoginForm.vue +1 -4
- package/src/profile/composables/useAuth.test.ts +8 -7
- package/src/profile/composables/useAuth.ts +5 -3
- package/src/profile/composables/useAuthApi.opaque.test.ts +0 -1
- package/src/types/auth.ts +0 -26
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@structured-id/ui-core",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"@protobuf-ts/grpcweb-transport": "^2.11.1",
|
|
43
43
|
"@protobuf-ts/runtime": "^2.11.1",
|
|
44
44
|
"@protobuf-ts/runtime-rpc": "^2.11.1",
|
|
45
|
-
"@structured-id/proto": "^0.
|
|
45
|
+
"@structured-id/proto": "^0.4.1",
|
|
46
46
|
"@structured-world/structured-email-address-ts": "^0.0.22",
|
|
47
47
|
"@structured-world/structured-public-domains": "0.0.x",
|
|
48
48
|
"libphonenumber-js": "^1.13.15"
|
package/src/composables/index.ts
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
export {
|
|
2
|
-
useGrpc,
|
|
3
|
-
initGrpc,
|
|
4
|
-
getTransport,
|
|
5
|
-
closeTransport,
|
|
6
|
-
getTransportType,
|
|
7
|
-
type TransportType,
|
|
8
|
-
} from "./useGrpc";
|
|
1
|
+
export { useGrpc, initGrpc, getTransport, closeTransport } from "./useGrpc";
|
|
9
2
|
export {
|
|
10
3
|
initAccountApi,
|
|
11
4
|
getAccountTransport,
|
|
@@ -4,28 +4,8 @@ import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
|
4
4
|
// Mock modules BEFORE importing the module under test
|
|
5
5
|
// ---------------------------------------------------------------------------
|
|
6
6
|
|
|
7
|
-
const mockAdaptiveInit = vi
|
|
8
|
-
.fn<() => Promise<void>>()
|
|
9
|
-
.mockResolvedValue(undefined);
|
|
10
|
-
const mockAdaptiveClose = vi.fn();
|
|
11
|
-
const mockAdaptiveActiveTransport = vi
|
|
12
|
-
.fn<() => string>()
|
|
13
|
-
.mockReturnValue("grpc-web");
|
|
14
|
-
|
|
15
|
-
vi.mock("@structured-id/proto/transport", () => ({
|
|
16
|
-
// Constructor mocks are `function`s: they are called with `new`.
|
|
17
|
-
AdaptiveRpcTransport: vi.fn().mockImplementation(function () {
|
|
18
|
-
return {
|
|
19
|
-
init: mockAdaptiveInit,
|
|
20
|
-
close: mockAdaptiveClose,
|
|
21
|
-
get activeTransport() {
|
|
22
|
-
return mockAdaptiveActiveTransport();
|
|
23
|
-
},
|
|
24
|
-
};
|
|
25
|
-
}),
|
|
26
|
-
}));
|
|
27
|
-
|
|
28
7
|
vi.mock("@protobuf-ts/grpcweb-transport", () => ({
|
|
8
|
+
// Constructor mocks are `function`s: they are called with `new`.
|
|
29
9
|
GrpcWebFetchTransport: vi.fn().mockImplementation(function () {
|
|
30
10
|
return { type: "grpc-web-transport" };
|
|
31
11
|
}),
|
|
@@ -33,14 +13,7 @@ vi.mock("@protobuf-ts/grpcweb-transport", () => ({
|
|
|
33
13
|
|
|
34
14
|
// Import AFTER mocks
|
|
35
15
|
import { GrpcWebFetchTransport } from "@protobuf-ts/grpcweb-transport";
|
|
36
|
-
import {
|
|
37
|
-
import {
|
|
38
|
-
initGrpc,
|
|
39
|
-
getTransport,
|
|
40
|
-
closeTransport,
|
|
41
|
-
getTransportType,
|
|
42
|
-
useGrpc,
|
|
43
|
-
} from "./useGrpc";
|
|
16
|
+
import { initGrpc, getTransport, closeTransport, useGrpc } from "./useGrpc";
|
|
44
17
|
import type { GrpcConfig } from "../types/auth";
|
|
45
18
|
|
|
46
19
|
// ---------------------------------------------------------------------------
|
|
@@ -50,11 +23,12 @@ import type { GrpcConfig } from "../types/auth";
|
|
|
50
23
|
describe("useGrpc", () => {
|
|
51
24
|
beforeEach(() => {
|
|
52
25
|
vi.clearAllMocks();
|
|
53
|
-
// Reset transport state by calling close between tests
|
|
54
26
|
closeTransport();
|
|
55
27
|
});
|
|
56
28
|
|
|
57
|
-
describe("initGrpc
|
|
29
|
+
describe("initGrpc", () => {
|
|
30
|
+
// The BFF session cookie rides on every call, so credentials are always
|
|
31
|
+
// included; nothing else configures the transport.
|
|
58
32
|
it("creates GrpcWebFetchTransport with baseUrl and credentials", () => {
|
|
59
33
|
const config: GrpcConfig = { baseUrl: "https://api.sid.example.com" };
|
|
60
34
|
initGrpc(config);
|
|
@@ -63,75 +37,6 @@ describe("useGrpc", () => {
|
|
|
63
37
|
baseUrl: "https://api.sid.example.com",
|
|
64
38
|
fetchInit: { credentials: "include" },
|
|
65
39
|
});
|
|
66
|
-
expect(AdaptiveRpcTransport).not.toHaveBeenCalled();
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it("getTransportType returns grpc-web", () => {
|
|
70
|
-
initGrpc({ baseUrl: "https://api.sid.example.com" });
|
|
71
|
-
expect(getTransportType()).toBe("grpc-web");
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
describe("initGrpc — with WebTransport URL", () => {
|
|
76
|
-
it("creates AdaptiveRpcTransport with fetchInit credentials", () => {
|
|
77
|
-
const config: GrpcConfig = {
|
|
78
|
-
baseUrl: "https://api.sid.example.com",
|
|
79
|
-
webTransportUrl: "https://wt.api.sid.example.com",
|
|
80
|
-
};
|
|
81
|
-
initGrpc(config);
|
|
82
|
-
|
|
83
|
-
expect(AdaptiveRpcTransport).toHaveBeenCalledWith(
|
|
84
|
-
expect.objectContaining({
|
|
85
|
-
grpcWebUrl: "https://api.sid.example.com",
|
|
86
|
-
webTransportUrl: "https://wt.api.sid.example.com",
|
|
87
|
-
fetchInit: { credentials: "include" },
|
|
88
|
-
}),
|
|
89
|
-
);
|
|
90
|
-
expect(GrpcWebFetchTransport).not.toHaveBeenCalled();
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it("calls adaptive.init() non-blocking on creation", async () => {
|
|
94
|
-
initGrpc({
|
|
95
|
-
baseUrl: "https://api.sid.example.com",
|
|
96
|
-
webTransportUrl: "https://wt.api.sid.example.com",
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
// init() should be called (non-blocking fire-and-forget)
|
|
100
|
-
// Give microtasks time to run
|
|
101
|
-
await Promise.resolve();
|
|
102
|
-
expect(mockAdaptiveInit).toHaveBeenCalled();
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
it("passes all WebTransport options to AdaptiveRpcTransport", () => {
|
|
106
|
-
const onChange = vi.fn();
|
|
107
|
-
initGrpc({
|
|
108
|
-
baseUrl: "https://api.sid.example.com",
|
|
109
|
-
webTransportUrl: "https://wt.api.sid.example.com",
|
|
110
|
-
webTransportCertHash: "abcdef1234567890",
|
|
111
|
-
webTransportReconnectDelay: 3000,
|
|
112
|
-
onTransportChange: onChange,
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
expect(AdaptiveRpcTransport).toHaveBeenCalledWith(
|
|
116
|
-
expect.objectContaining({
|
|
117
|
-
grpcWebUrl: "https://api.sid.example.com",
|
|
118
|
-
webTransportUrl: "https://wt.api.sid.example.com",
|
|
119
|
-
webTransportCertHash: "abcdef1234567890",
|
|
120
|
-
reconnectDelay: 3000,
|
|
121
|
-
onTransportChange: onChange,
|
|
122
|
-
fetchInit: { credentials: "include" },
|
|
123
|
-
}),
|
|
124
|
-
);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
it("getTransportType delegates to AdaptiveRpcTransport.activeTransport", () => {
|
|
128
|
-
mockAdaptiveActiveTransport.mockReturnValue("webtransport");
|
|
129
|
-
initGrpc({
|
|
130
|
-
baseUrl: "https://api.sid.example.com",
|
|
131
|
-
webTransportUrl: "https://wt.api.sid.example.com",
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
expect(getTransportType()).toBe("webtransport");
|
|
135
40
|
});
|
|
136
41
|
});
|
|
137
42
|
|
|
@@ -142,8 +47,7 @@ describe("useGrpc", () => {
|
|
|
142
47
|
|
|
143
48
|
it("returns transport after initGrpc", () => {
|
|
144
49
|
initGrpc({ baseUrl: "https://api.sid.example.com" });
|
|
145
|
-
expect(
|
|
146
|
-
expect(getTransport()).toBeDefined();
|
|
50
|
+
expect(getTransport()).toEqual({ type: "grpc-web-transport" });
|
|
147
51
|
});
|
|
148
52
|
});
|
|
149
53
|
|
|
@@ -164,36 +68,16 @@ describe("useGrpc", () => {
|
|
|
164
68
|
expect(typeof composable.getTransport).toBe("function");
|
|
165
69
|
expect(typeof composable.initGrpc).toBe("function");
|
|
166
70
|
});
|
|
167
|
-
|
|
168
|
-
it("transport.value is null after closeTransport", () => {
|
|
169
|
-
initGrpc({ baseUrl: "https://api.sid.example.com" });
|
|
170
|
-
closeTransport();
|
|
171
|
-
const { transport } = useGrpc();
|
|
172
|
-
expect(transport.value).toBeNull();
|
|
173
|
-
});
|
|
174
71
|
});
|
|
175
72
|
|
|
176
73
|
describe("closeTransport", () => {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
baseUrl: "https://api.sid.example.com",
|
|
180
|
-
webTransportUrl: "https://wt.api.sid.example.com",
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
closeTransport();
|
|
184
|
-
expect(mockAdaptiveClose).toHaveBeenCalled();
|
|
185
|
-
});
|
|
186
|
-
|
|
74
|
+
// After close, the transport is gone: a later call must initialize
|
|
75
|
+
// again rather than reuse the old one.
|
|
187
76
|
it("resets transport to null (getTransport throws after close)", () => {
|
|
188
77
|
initGrpc({ baseUrl: "https://api.sid.example.com" });
|
|
189
78
|
closeTransport();
|
|
190
79
|
expect(() => getTransport()).toThrow("gRPC transport not initialized");
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
it("does not call close() on plain GrpcWebFetchTransport (no close method)", () => {
|
|
194
|
-
initGrpc({ baseUrl: "https://api.sid.example.com" });
|
|
195
|
-
// Should not throw even though GrpcWebFetchTransport has no close()
|
|
196
|
-
expect(() => closeTransport()).not.toThrow();
|
|
80
|
+
expect(useGrpc().transport.value).toBeNull();
|
|
197
81
|
});
|
|
198
82
|
});
|
|
199
83
|
});
|
|
@@ -2,67 +2,28 @@ import { GrpcWebFetchTransport } from "@protobuf-ts/grpcweb-transport";
|
|
|
2
2
|
import type { RpcTransport } from "@protobuf-ts/runtime-rpc";
|
|
3
3
|
import { ref, type Ref } from "vue";
|
|
4
4
|
import type { GrpcConfig } from "../types/auth";
|
|
5
|
-
import {
|
|
6
|
-
AdaptiveRpcTransport,
|
|
7
|
-
type TransportType,
|
|
8
|
-
} from "@structured-id/proto/transport";
|
|
9
5
|
|
|
10
|
-
/** Shared
|
|
6
|
+
/** Shared gRPC-web transport instance. */
|
|
11
7
|
let _transport: RpcTransport | null = null;
|
|
12
|
-
/** Separate reference to AdaptiveRpcTransport when active (avoids instanceof). */
|
|
13
|
-
let _adaptive: AdaptiveRpcTransport | null = null;
|
|
14
8
|
|
|
15
9
|
/**
|
|
16
|
-
* Initialize the gRPC transport. Call once at app startup.
|
|
10
|
+
* Initialize the gRPC-web transport. Call once at app startup.
|
|
17
11
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* WebTransport connection is attempted asynchronously (non-blocking).
|
|
21
|
-
*
|
|
22
|
-
* Without `config.webTransportUrl`, falls back to plain gRPC-web (same as before).
|
|
23
|
-
*
|
|
24
|
-
* After BFF migration (#536i-3): `credentials: "include"` is always set
|
|
25
|
-
* so the httpOnly BFF session cookie is sent with every gRPC-web request.
|
|
12
|
+
* `credentials: "include"` is always set so the httpOnly BFF session cookie
|
|
13
|
+
* is sent with every request.
|
|
26
14
|
*
|
|
27
15
|
* @example
|
|
28
16
|
* ```ts
|
|
29
|
-
* // gRPC-web only
|
|
30
17
|
* initGrpc({ baseUrl: 'https://api.example.com' })
|
|
31
|
-
*
|
|
32
|
-
* // With WebTransport failover
|
|
33
|
-
* initGrpc({
|
|
34
|
-
* baseUrl: 'https://api.example.com',
|
|
35
|
-
* webTransportUrl: 'https://wt.api.example.com',
|
|
36
|
-
* })
|
|
37
18
|
* ```
|
|
38
19
|
*/
|
|
39
20
|
export function initGrpc(config: GrpcConfig): void {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
onTransportChange: config.onTransportChange,
|
|
47
|
-
// Always include credentials so the BFF session cookie is attached.
|
|
48
|
-
// The BFF proxy exchanges the cookie for a Bearer token server-side.
|
|
49
|
-
fetchInit: { credentials: "include" },
|
|
50
|
-
});
|
|
51
|
-
// Attempt WebTransport connection in background — non-blocking.
|
|
52
|
-
adaptive.init().catch(() => {
|
|
53
|
-
// Silently falls back to gRPC-web if WebTransport is unavailable.
|
|
54
|
-
});
|
|
55
|
-
_adaptive = adaptive;
|
|
56
|
-
_transport = adaptive;
|
|
57
|
-
} else {
|
|
58
|
-
_adaptive = null;
|
|
59
|
-
_transport = new GrpcWebFetchTransport({
|
|
60
|
-
baseUrl: config.baseUrl,
|
|
61
|
-
// Always include credentials so the BFF session cookie is attached.
|
|
62
|
-
// The BFF proxy exchanges the cookie for a Bearer token server-side.
|
|
63
|
-
fetchInit: { credentials: "include" },
|
|
64
|
-
});
|
|
65
|
-
}
|
|
21
|
+
_transport = new GrpcWebFetchTransport({
|
|
22
|
+
baseUrl: config.baseUrl,
|
|
23
|
+
// The BFF proxy exchanges the session cookie for a Bearer token
|
|
24
|
+
// server-side.
|
|
25
|
+
fetchInit: { credentials: "include" },
|
|
26
|
+
});
|
|
66
27
|
}
|
|
67
28
|
|
|
68
29
|
/**
|
|
@@ -78,24 +39,12 @@ export function getTransport(): RpcTransport {
|
|
|
78
39
|
}
|
|
79
40
|
|
|
80
41
|
/**
|
|
81
|
-
*
|
|
82
|
-
* Call during app teardown if using WebTransport.
|
|
42
|
+
* Drop the shared transport; the next use needs `initGrpc()` again.
|
|
83
43
|
*/
|
|
84
44
|
export function closeTransport(): void {
|
|
85
|
-
_adaptive?.close();
|
|
86
|
-
_adaptive = null;
|
|
87
45
|
_transport = null;
|
|
88
46
|
}
|
|
89
47
|
|
|
90
|
-
/**
|
|
91
|
-
* Get the currently active transport type.
|
|
92
|
-
* Returns "grpc-web" if AdaptiveRpcTransport is not used or WebTransport
|
|
93
|
-
* is not available.
|
|
94
|
-
*/
|
|
95
|
-
export function getTransportType(): TransportType {
|
|
96
|
-
return _adaptive?.activeTransport ?? "grpc-web";
|
|
97
|
-
}
|
|
98
|
-
|
|
99
48
|
/**
|
|
100
49
|
* Vue composable for gRPC transport.
|
|
101
50
|
*
|
|
@@ -118,5 +67,3 @@ export function useGrpc() {
|
|
|
118
67
|
initGrpc,
|
|
119
68
|
};
|
|
120
69
|
}
|
|
121
|
-
|
|
122
|
-
export type { TransportType };
|
package/src/index.ts
CHANGED
|
@@ -175,7 +175,6 @@ const props = withDefaults(
|
|
|
175
175
|
password: string,
|
|
176
176
|
onStep?: (step: number) => void,
|
|
177
177
|
) => Promise<{
|
|
178
|
-
accessToken: string;
|
|
179
178
|
expiresIn: number;
|
|
180
179
|
sessionId?: string;
|
|
181
180
|
}>;
|
|
@@ -207,9 +206,7 @@ const props = withDefaults(
|
|
|
207
206
|
);
|
|
208
207
|
|
|
209
208
|
const emit = defineEmits<{
|
|
210
|
-
success: [
|
|
211
|
-
result: { accessToken: string; expiresIn: number; sessionId?: string },
|
|
212
|
-
];
|
|
209
|
+
success: [result: { expiresIn: number; sessionId?: string }];
|
|
213
210
|
error: [error: Error];
|
|
214
211
|
"forgot-password": [];
|
|
215
212
|
}>();
|
|
@@ -125,7 +125,6 @@ describe("createAuth prewarm", () => {
|
|
|
125
125
|
});
|
|
126
126
|
api.loginFinish.mockResolvedValue({
|
|
127
127
|
sessionId: "s",
|
|
128
|
-
accessToken: "t",
|
|
129
128
|
expiresIn: 60n,
|
|
130
129
|
});
|
|
131
130
|
});
|
|
@@ -173,10 +172,13 @@ describe("createAuth register", () => {
|
|
|
173
172
|
registrationResponse: RESPONSE,
|
|
174
173
|
history: wireContext(),
|
|
175
174
|
});
|
|
176
|
-
|
|
175
|
+
// An older server's answer, still carrying a Profile identifier the
|
|
176
|
+
// current message no longer has.
|
|
177
|
+
const fromOlderServer = {
|
|
177
178
|
profileId: "profile-uuid",
|
|
178
179
|
credentialId: "cred-uuid",
|
|
179
|
-
}
|
|
180
|
+
};
|
|
181
|
+
api.regFinish.mockResolvedValue(fromOlderServer);
|
|
180
182
|
});
|
|
181
183
|
|
|
182
184
|
it("runs the operation: start, evaluate, prove, finish with the proof", async () => {
|
|
@@ -650,7 +652,6 @@ describe("createAuth resetPassword", () => {
|
|
|
650
652
|
api.executeReset.mockResolvedValue({ registrationResponse: RESPONSE });
|
|
651
653
|
api.completeReset.mockResolvedValue({
|
|
652
654
|
sessionId: "sess-1",
|
|
653
|
-
accessToken: "jwt",
|
|
654
655
|
expiresIn: 3600,
|
|
655
656
|
});
|
|
656
657
|
});
|
|
@@ -686,9 +687,8 @@ describe("createAuth login", () => {
|
|
|
686
687
|
});
|
|
687
688
|
api.loginFinish.mockResolvedValue({
|
|
688
689
|
sessionId: "sess-1",
|
|
689
|
-
accessToken: "jwt",
|
|
690
690
|
expiresIn: BigInt(3600),
|
|
691
|
-
}
|
|
691
|
+
});
|
|
692
692
|
});
|
|
693
693
|
|
|
694
694
|
it("signs in with the Pallas client in two round trips", async () => {
|
|
@@ -713,9 +713,10 @@ describe("createAuth login", () => {
|
|
|
713
713
|
"server-state",
|
|
714
714
|
);
|
|
715
715
|
expect(steps).toEqual([1, 2, 3]);
|
|
716
|
+
// The result carries no credential: the browser holds the session
|
|
717
|
+
// cookie the answer set.
|
|
716
718
|
expect(result).toEqual({
|
|
717
719
|
sessionId: "sess-1",
|
|
718
|
-
accessToken: "jwt",
|
|
719
720
|
expiresIn: 3600,
|
|
720
721
|
});
|
|
721
722
|
});
|
|
@@ -33,10 +33,13 @@ import {
|
|
|
33
33
|
|
|
34
34
|
// ── Types ──
|
|
35
35
|
|
|
36
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* A sign-in's session, as the server issued it. The credential itself never
|
|
38
|
+
* reaches page code: a browser holds the session cookie the answer set.
|
|
39
|
+
*/
|
|
37
40
|
export interface LoginResult {
|
|
38
41
|
sessionId: string;
|
|
39
|
-
|
|
42
|
+
/** Seconds until the delivered credential expires. */
|
|
40
43
|
expiresIn: number;
|
|
41
44
|
}
|
|
42
45
|
|
|
@@ -540,7 +543,6 @@ export function createAuth(loadClient: ZkppClientLoader) {
|
|
|
540
543
|
);
|
|
541
544
|
return {
|
|
542
545
|
sessionId: finished.sessionId,
|
|
543
|
-
accessToken: finished.accessToken,
|
|
544
546
|
expiresIn: Number(finished.expiresIn),
|
|
545
547
|
};
|
|
546
548
|
}
|
|
@@ -71,7 +71,6 @@ describe("OPAQUE gRPC wrappers", () => {
|
|
|
71
71
|
it("sends principal, finalization, and serverLoginState", async () => {
|
|
72
72
|
const expected = {
|
|
73
73
|
sessionId: "sess-1",
|
|
74
|
-
accessToken: "jwt",
|
|
75
74
|
expiresIn: BigInt(3600),
|
|
76
75
|
};
|
|
77
76
|
mockOpaqueLoginFinish.mockResolvedValue({ response: expected });
|
package/src/types/auth.ts
CHANGED
|
@@ -29,30 +29,4 @@ export interface SessionInfo {
|
|
|
29
29
|
export interface GrpcConfig {
|
|
30
30
|
/** Base URL for gRPC-web transport (e.g., "https://api.example.com"). */
|
|
31
31
|
baseUrl: string;
|
|
32
|
-
/**
|
|
33
|
-
* @deprecated BFF mode always uses credentials: "include".
|
|
34
|
-
* This field is kept for API compatibility but has no effect.
|
|
35
|
-
*/
|
|
36
|
-
withCredentials?: boolean;
|
|
37
|
-
/**
|
|
38
|
-
* WebTransport server URL (e.g., "https://wt.api.example.com").
|
|
39
|
-
* When provided, AdaptiveRpcTransport is used with WebTransport as primary
|
|
40
|
-
* and gRPC-web as fallback. Omit to use gRPC-web only.
|
|
41
|
-
*/
|
|
42
|
-
webTransportUrl?: string;
|
|
43
|
-
/**
|
|
44
|
-
* SHA-256 certificate hash (hex string) for dev self-signed WebTransport certs.
|
|
45
|
-
* Only needed when connecting to servers with self-signed certificates.
|
|
46
|
-
*/
|
|
47
|
-
webTransportCertHash?: string;
|
|
48
|
-
/**
|
|
49
|
-
* Delay in milliseconds before attempting to reconnect WebTransport after failover.
|
|
50
|
-
* Defaults to 5000ms.
|
|
51
|
-
*/
|
|
52
|
-
webTransportReconnectDelay?: number;
|
|
53
|
-
/**
|
|
54
|
-
* Callback fired when the active transport changes between "webtransport" and "grpc-web".
|
|
55
|
-
* Use this to show transport status indicators in the UI.
|
|
56
|
-
*/
|
|
57
|
-
onTransportChange?: (transport: "webtransport" | "grpc-web") => void;
|
|
58
32
|
}
|