libshv-js 3.17.0 → 3.20.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.
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isShvMap = exports.isMetaMap = exports.isIMap = exports.makeMetaMap = exports.makeIMap = exports.makeMap = exports.withOffset = exports.UInt = exports.RpcValueWithMetaData = exports.Double = exports.Decimal = exports.shvMapType = exports.typeName = void 0;
4
+ class UInt {
5
+ value;
6
+ constructor(u) {
7
+ if (u instanceof UInt) {
8
+ this.value = u.value;
9
+ return;
10
+ }
11
+ if (u < 0 || !Number.isInteger(u)) {
12
+ throw new Error(`Invalid value '${u}' for UInt must a positive integral number`);
13
+ }
14
+ this.value = u;
15
+ }
16
+ [Symbol.toPrimitive]() {
17
+ return this.value;
18
+ }
19
+ toString() {
20
+ return `${this.value.toString()}`;
21
+ }
22
+ }
23
+ exports.UInt = UInt;
24
+ class Double {
25
+ value;
26
+ constructor(u) {
27
+ this.value = u;
28
+ }
29
+ }
30
+ exports.Double = Double;
31
+ class Decimal {
32
+ mantisa;
33
+ exponent;
34
+ constructor(mantisa, exponent) {
35
+ if (!Number.isInteger(exponent)) {
36
+ throw new TypeError(`Decimal: exponent must be integral (${exponent})`);
37
+ }
38
+ this.mantisa = mantisa;
39
+ this.exponent = exponent;
40
+ }
41
+ }
42
+ exports.Decimal = Decimal;
43
+ const withOffset = (date, utcOffset) => {
44
+ const clonedDate = new Date(date);
45
+ clonedDate.utc_offset = utcOffset;
46
+ return clonedDate;
47
+ };
48
+ exports.withOffset = withOffset;
49
+ const shvMapType = Symbol('shvMapType');
50
+ exports.shvMapType = shvMapType;
51
+ const isShvMap = (x) => typeof x === 'object' && x[shvMapType] === 'map';
52
+ exports.isShvMap = isShvMap;
53
+ const isIMap = (x) => typeof x === 'object' && x[shvMapType] === 'imap';
54
+ exports.isIMap = isIMap;
55
+ const isMetaMap = (x) => typeof x === 'object' && x[shvMapType] === 'metamap';
56
+ exports.isMetaMap = isMetaMap;
57
+ const typeName = (x) => {
58
+ switch (true) {
59
+ case x === undefined: return 'Null';
60
+ case typeof x === 'boolean': return 'Bool';
61
+ case typeof x === 'string': return 'String';
62
+ case x instanceof ArrayBuffer: return 'Blob';
63
+ case x instanceof UInt: return 'UInt';
64
+ case typeof x === 'number': return 'Int';
65
+ case x instanceof Double: return 'Double';
66
+ case x instanceof Decimal: return 'Decimal';
67
+ case Array.isArray(x): return 'List';
68
+ case x instanceof Date: return 'Date';
69
+ case isShvMap(x): return 'ShvMap';
70
+ case isIMap(x): return 'IMap';
71
+ case isMetaMap(x): return 'MetaMap';
72
+ default: return '<unknown type>';
73
+ }
74
+ };
75
+ exports.typeName = typeName;
76
+ const makeMetaMap = (x = {}) => ({
77
+ ...x,
78
+ [shvMapType]: 'metamap',
79
+ });
80
+ exports.makeMetaMap = makeMetaMap;
81
+ const makeIMap = (x = {}) => ({
82
+ ...x,
83
+ [shvMapType]: 'imap',
84
+ });
85
+ exports.makeIMap = makeIMap;
86
+ const makeMap = (x = {}) => ({
87
+ ...x,
88
+ [shvMapType]: 'map',
89
+ });
90
+ exports.makeMap = makeMap;
91
+ class RpcValueWithMetaData {
92
+ meta;
93
+ value;
94
+ constructor(meta, value) {
95
+ this.meta = meta;
96
+ this.value = value;
97
+ /* nothing */
98
+ }
99
+ }
100
+ exports.RpcValueWithMetaData = RpcValueWithMetaData;
@@ -0,0 +1,91 @@
1
+ import { ComputedRef, Ref } from 'vue';
2
+ import { WsClient, WsClientOptionsLogin } from './ws-client';
3
+ import PKCE from 'js-pkce';
4
+ import * as z from './zod';
5
+ import { type shvMapType } from './rpcvalue';
6
+ import { RpcValue } from './rpcvalue';
7
+ type GlobalResourceOptions<ResourceType> = {
8
+ shvPath: string;
9
+ method: string;
10
+ validator: z.ZodType<ResourceType>;
11
+ signalName: string;
12
+ signalHandler: (param: RpcValue, resource: Ref<ResourceType | undefined>, reinit: () => void) => void;
13
+ };
14
+ type VueShvOptions = {
15
+ wsUri: string;
16
+ onRequest: WsClientOptionsLogin['onRequest'];
17
+ azureCodeRedirect?: string;
18
+ };
19
+ type ShvLocalStorage = {
20
+ azureAccessToken?: string;
21
+ azureRedirectTo?: string;
22
+ };
23
+ type ShvSessionStorage = {
24
+ shvLoginUser?: string;
25
+ shvLoginPassword?: string;
26
+ azureWorkflow?: z.infer<typeof OAuth2AzureWorkflowZod>;
27
+ };
28
+ declare const OAuth2AzureWorkflowZod: z.ZodCustom<{
29
+ type: "oauth2-azure";
30
+ authorizeUrl: string;
31
+ tokenUrl: string;
32
+ clientId: string;
33
+ scopes: string | string[];
34
+ } & {
35
+ [shvMapType]: "map";
36
+ }, {
37
+ type: "oauth2-azure";
38
+ authorizeUrl: string;
39
+ tokenUrl: string;
40
+ clientId: string;
41
+ scopes: string | string[];
42
+ } & {
43
+ [shvMapType]: "map";
44
+ }>;
45
+ export declare enum LoginFailureReason {
46
+ NoCredentials = 0,
47
+ AzureTimedOut = 1,
48
+ AzureUnsupported = 2,
49
+ CouldntLogin = 3,
50
+ LoggedOut = 4
51
+ }
52
+ type LoginFailure = {
53
+ reason: LoginFailureReason;
54
+ message?: string;
55
+ };
56
+ declare const makePkce: (oauthOptions: {
57
+ azureCodeRedirect: string;
58
+ clientId: string;
59
+ authorizeUrl: string;
60
+ tokenUrl: string;
61
+ scopes: string | string[];
62
+ }) => PKCE;
63
+ export { makePkce as azure };
64
+ export declare function useShv(options: VueShvOptions): {
65
+ azureAuth: (redirectTo?: string) => void;
66
+ azureHandlerError: Ref<string, string>;
67
+ connected: Ref<"connected" | "connecting" | "disconnected", "connected" | "connecting" | "disconnected">;
68
+ displayEmail: Ref<string, string>;
69
+ displayFullName: Ref<string, string>;
70
+ displayName: Ref<string, string>;
71
+ displayPhoto: Ref<string | undefined, string | undefined>;
72
+ displayShortName: Ref<string, string>;
73
+ getConnection: () => Promise<WsClient>;
74
+ handleAzureCode: () => Promise<string | void>;
75
+ logContents: Ref<string, string>;
76
+ loginFailure: Ref<LoginFailure | undefined, LoginFailure | undefined>;
77
+ makeGlobalResource: {
78
+ <ResourceType>(options: GlobalResourceOptions<ResourceType>): () => Ref<ResourceType | undefined>;
79
+ <ResourceType>(options: GlobalResourceOptions<ResourceType> & {
80
+ default: ResourceType;
81
+ }): () => ComputedRef<ResourceType>;
82
+ };
83
+ makeRpcCall: <ResultType>(shvPath: string, method: string, validator: z.ZodType<ResultType>) => () => Promise<Error | ResultType>;
84
+ makeRpcCallParam: <ResultType, ParamType extends RpcValue>(shvPath: string, method: string, _paramType: z.ZodType<ParamType>, validator: z.ZodType<ResultType>) => (param: ParamType) => Promise<Error | ResultType>;
85
+ rpcCall: (shvPath: string, method: string, params?: RpcValue) => Promise<Error | RpcValue>;
86
+ setShvCredentials: (userName: string, password: string) => void;
87
+ shvLocalStorage: import("@vueuse/shared").RemovableRef<ShvLocalStorage>;
88
+ shvLogout: () => void;
89
+ shvSessionStorage: import("@vueuse/shared").RemovableRef<ShvSessionStorage>;
90
+ };
91
+ export declare const fullReloadHandler: (_param: RpcValue, _resource: unknown, reinit: () => void) => void;
@@ -0,0 +1,424 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.fullReloadHandler = exports.azure = exports.LoginFailureReason = void 0;
40
+ exports.useShv = useShv;
41
+ const vue_1 = require("vue");
42
+ const ws_client_1 = require("./ws-client");
43
+ const core_1 = require("@vueuse/core");
44
+ const js_pkce_1 = __importDefault(require("js-pkce"));
45
+ const z = __importStar(require("./zod"));
46
+ const OAuth2AzureWorkflowZod = z.map({
47
+ type: z.literal('oauth2-azure'),
48
+ authorizeUrl: z.string(),
49
+ tokenUrl: z.string(),
50
+ clientId: z.string(),
51
+ scopes: z.string().or(z.array(z.string())),
52
+ });
53
+ var LoginFailureReason;
54
+ (function (LoginFailureReason) {
55
+ LoginFailureReason[LoginFailureReason["NoCredentials"] = 0] = "NoCredentials";
56
+ LoginFailureReason[LoginFailureReason["AzureTimedOut"] = 1] = "AzureTimedOut";
57
+ LoginFailureReason[LoginFailureReason["AzureUnsupported"] = 2] = "AzureUnsupported";
58
+ LoginFailureReason[LoginFailureReason["CouldntLogin"] = 3] = "CouldntLogin";
59
+ LoginFailureReason[LoginFailureReason["LoggedOut"] = 4] = "LoggedOut";
60
+ })(LoginFailureReason || (exports.LoginFailureReason = LoginFailureReason = {}));
61
+ const makePkce = (oauthOptions) => {
62
+ const pkce = new js_pkce_1.default({
63
+ client_id: oauthOptions.clientId,
64
+ redirect_uri: (() => {
65
+ const url = new URL(globalThis.location.href);
66
+ url.pathname = oauthOptions.azureCodeRedirect;
67
+ url.search = '';
68
+ return url.toString();
69
+ })(),
70
+ authorization_endpoint: oauthOptions.authorizeUrl,
71
+ token_endpoint: oauthOptions.tokenUrl,
72
+ requested_scopes: Array.isArray(oauthOptions.scopes) ? oauthOptions.scopes.join(' ') : oauthOptions.scopes,
73
+ });
74
+ return pkce;
75
+ };
76
+ exports.azure = makePkce;
77
+ function useShv(options) {
78
+ const shvLocalStorage = (0, core_1.useLocalStorage)('vue-shv', {});
79
+ const shvSessionStorage = (0, core_1.useSessionStorage)('vue-shv', {});
80
+ const displayName = (0, vue_1.ref)('Loading...');
81
+ const displayShortName = (0, vue_1.ref)('');
82
+ const displayFullName = (0, vue_1.ref)('');
83
+ const displayEmail = (0, vue_1.ref)('');
84
+ const displayPhoto = (0, vue_1.ref)();
85
+ const state = {
86
+ ws: undefined,
87
+ reconnectService: undefined,
88
+ };
89
+ const waitingForSocket = [];
90
+ const resetAzureToken = () => {
91
+ shvLocalStorage.value.azureAccessToken = undefined;
92
+ };
93
+ const azureAvailable = async () => {
94
+ const accessToken = shvLocalStorage.value.azureAccessToken;
95
+ if (accessToken === undefined) {
96
+ return LoginFailureReason.NoCredentials;
97
+ }
98
+ const resp = await fetch('https://graph.microsoft.com/v1.0/me', {
99
+ headers: {
100
+ Authorization: `Bearer ${accessToken}`,
101
+ },
102
+ });
103
+ const json = await resp.json();
104
+ if (typeof json === 'object' && json !== null) {
105
+ if ('displayName' in json && typeof json.displayName === 'string') {
106
+ displayName.value = json.displayName;
107
+ }
108
+ if ('givenName' in json && typeof json.givenName === 'string'
109
+ && 'surname' in json && typeof json.surname === 'string') {
110
+ const firstName = json.givenName;
111
+ const lastname = json.surname;
112
+ displayShortName.value = firstName.charAt(0) + lastname.charAt(0);
113
+ displayFullName.value = firstName + ' ' + lastname;
114
+ }
115
+ if ('mail' in json && typeof json.mail === 'string') {
116
+ displayEmail.value = json.mail;
117
+ }
118
+ }
119
+ const photo = await fetch('https://graph.microsoft.com/v1.0/me/photos/48x48/$value', {
120
+ headers: {
121
+ Authorization: `Bearer ${accessToken}`,
122
+ },
123
+ });
124
+ if (photo.ok) {
125
+ displayPhoto.value = URL.createObjectURL(await photo.blob());
126
+ }
127
+ if (!resp.ok) {
128
+ resetAzureToken();
129
+ }
130
+ return resp.ok ? 'azureAvailable' : LoginFailureReason.AzureTimedOut;
131
+ };
132
+ const debug = (...args) => {
133
+ logContents.value = logContents.value + args.join(' ') + '\n';
134
+ console.debug(...args);
135
+ };
136
+ const azureAuth = (redirectTo) => {
137
+ if (options.azureCodeRedirect === undefined) {
138
+ throw new Error('Azure redirect URL not set');
139
+ }
140
+ const { azureCodeRedirect } = options;
141
+ shvLocalStorage.value.azureRedirectTo = redirectTo ?? globalThis.location.pathname;
142
+ const noBrokerSupport = () => {
143
+ loginFailure.value = {
144
+ reason: LoginFailureReason.AzureUnsupported,
145
+ message: 'Broker does not support Azure',
146
+ };
147
+ };
148
+ state.ws = new ws_client_1.WsClient({
149
+ logDebug: debug,
150
+ wsUri: options.wsUri,
151
+ onWorkflows(workflows) {
152
+ if (!Array.isArray(workflows)) {
153
+ noBrokerSupport();
154
+ return;
155
+ }
156
+ for (const workflow of workflows) {
157
+ const parsedWorkflow = OAuth2AzureWorkflowZod.safeParse(workflow);
158
+ if (!parsedWorkflow.success) {
159
+ continue;
160
+ }
161
+ shvSessionStorage.value.azureWorkflow = parsedWorkflow.data;
162
+ globalThis.location.replace(makePkce({ ...parsedWorkflow.data, azureCodeRedirect }).authorizeUrl());
163
+ }
164
+ },
165
+ onWorkflowsFailed() {
166
+ noBrokerSupport();
167
+ },
168
+ });
169
+ };
170
+ const setShvCredentials = (userName, password) => {
171
+ shvLogout();
172
+ shvSessionStorage.value.shvLoginUser = userName;
173
+ shvSessionStorage.value.shvLoginPassword = password;
174
+ };
175
+ const rpcCall = async (shvPath, method, params) => {
176
+ const shv = await getConnection();
177
+ return shv.callRpcMethod(shvPath, method, params);
178
+ };
179
+ const makeRpcCall = (shvPath, method, validator) => async () => {
180
+ const resultOrError = await rpcCall(shvPath, method);
181
+ if (resultOrError instanceof Error) {
182
+ return resultOrError;
183
+ }
184
+ const parsed = validator.safeParse(resultOrError);
185
+ if (!parsed.success) {
186
+ return new Error(parsed.error.message);
187
+ }
188
+ return parsed.data;
189
+ };
190
+ const makeRpcCallParam = (shvPath, method, _paramType, validator) => async (param) => {
191
+ const resultOrError = await rpcCall(shvPath, method, param);
192
+ if (resultOrError instanceof Error) {
193
+ return resultOrError;
194
+ }
195
+ const parsed = validator.safeParse(resultOrError);
196
+ if (!parsed.success) {
197
+ return new Error(parsed.error.message);
198
+ }
199
+ return parsed.data;
200
+ };
201
+ const connected = (0, vue_1.ref)('disconnected');
202
+ const logContents = (0, vue_1.ref)('');
203
+ const shvLogout = () => {
204
+ resetAzureToken();
205
+ shvSessionStorage.value.shvLoginUser = undefined;
206
+ shvSessionStorage.value.shvLoginPassword = undefined;
207
+ for (const waiter of waitingForSocket) {
208
+ waiter.reject();
209
+ }
210
+ connected.value = 'disconnected';
211
+ waitingForSocket.length = 0;
212
+ state.ws?.close();
213
+ displayName.value = 'Logged out';
214
+ displayPhoto.value = undefined;
215
+ state.ws = undefined;
216
+ };
217
+ const loginFailure = (0, vue_1.ref)();
218
+ const getConnection = async () => {
219
+ if (connected.value === 'connected') {
220
+ return state.ws;
221
+ }
222
+ return new Promise((resolve, reject) => {
223
+ waitingForSocket.push({ resolve, reject });
224
+ if (connected.value === 'connecting') {
225
+ // We should try to connect only once at the same time.
226
+ return;
227
+ }
228
+ connected.value = 'connecting';
229
+ const doConnect = (user, password, loginType) => {
230
+ console.log('Connecting to', options.wsUri);
231
+ const makeLoginOptions = () => {
232
+ switch (loginType) {
233
+ case 'PLAIN':
234
+ return {
235
+ type: loginType,
236
+ user,
237
+ password,
238
+ };
239
+ case 'TOKEN':
240
+ return {
241
+ type: loginType,
242
+ token: `oauth2-azure:${password}`,
243
+ };
244
+ }
245
+ };
246
+ state.ws = new ws_client_1.WsClient({
247
+ login: makeLoginOptions(),
248
+ wsUri: options.wsUri,
249
+ timeout: 120_000,
250
+ logDebug: debug,
251
+ onConnected() {
252
+ for (const waiter of waitingForSocket) {
253
+ waiter.resolve(state.ws);
254
+ }
255
+ waitingForSocket.length = 0;
256
+ console.log('Connected to', options.wsUri);
257
+ connected.value = 'connected';
258
+ },
259
+ onConnectionFailure(error) {
260
+ console.error(`Failed to connect to: ${options.wsUri}`, error);
261
+ shvLogout();
262
+ loginFailure.value = {
263
+ reason: LoginFailureReason.CouldntLogin,
264
+ message: error.message,
265
+ };
266
+ },
267
+ onDisconnected() {
268
+ connected.value = 'disconnected';
269
+ const RECONNECT_INTERVAL = 3000;
270
+ if (shvLocalStorage.value.azureAccessToken !== undefined) {
271
+ console.log('Disconnected from', options.wsUri, 'reconnecting in', RECONNECT_INTERVAL, 'ms');
272
+ state.reconnectService = globalThis.setTimeout(async () => {
273
+ await getConnection();
274
+ }, RECONNECT_INTERVAL);
275
+ }
276
+ },
277
+ onRequest: options.onRequest,
278
+ });
279
+ };
280
+ const shvUser = shvSessionStorage.value.shvLoginUser;
281
+ const shvPassword = shvSessionStorage.value.shvLoginPassword;
282
+ if (shvUser !== undefined && shvPassword !== undefined) {
283
+ displayName.value = shvUser;
284
+ displayShortName.value = shvUser[0];
285
+ displayFullName.value = shvUser;
286
+ doConnect(shvUser, shvPassword, 'PLAIN');
287
+ return;
288
+ }
289
+ azureAvailable().then(isAzureAvailable => {
290
+ switch (isAzureAvailable) {
291
+ case LoginFailureReason.NoCredentials:
292
+ case LoginFailureReason.AzureTimedOut:
293
+ shvLogout();
294
+ loginFailure.value = {
295
+ reason: isAzureAvailable,
296
+ };
297
+ return;
298
+ case 'azureAvailable':
299
+ break;
300
+ }
301
+ const accessToken = shvLocalStorage.value.azureAccessToken;
302
+ if (accessToken !== undefined) {
303
+ doConnect('', accessToken, 'TOKEN');
304
+ }
305
+ }).catch((error) => {
306
+ console.error('Failed to fetch verify azure info, redirecting to the login page in 3 seconds', error);
307
+ setTimeout(() => {
308
+ loginFailure.value = {
309
+ reason: LoginFailureReason.CouldntLogin,
310
+ message: 'Failed to fetch verify azure info',
311
+ };
312
+ }, 3000);
313
+ });
314
+ });
315
+ };
316
+ function makeGlobalResource(options) {
317
+ const resource = (0, vue_1.ref)();
318
+ const resIdentifier = `${options.shvPath}:${options.method}`;
319
+ const resourceCall = makeRpcCall(options.shvPath, options.method, options.validator);
320
+ const refreshValue = async () => {
321
+ const newResource = await resourceCall();
322
+ if (newResource instanceof Error) {
323
+ return;
324
+ }
325
+ resource.value = newResource;
326
+ };
327
+ const initialize = async () => {
328
+ try {
329
+ await refreshValue();
330
+ const connection = await getConnection();
331
+ connection.subscribe(`Global-${resIdentifier}:`, options.shvPath, options.signalName, (_path, _method, param) => {
332
+ options.signalHandler(param, resource, async () => refreshValue().catch((error) => {
333
+ console.error(`Failed to initialize ${resIdentifier}`, error);
334
+ }));
335
+ });
336
+ }
337
+ catch (error) {
338
+ console.error(`Failed to initialize ${resIdentifier}`, error);
339
+ }
340
+ };
341
+ let initialized = false;
342
+ return () => {
343
+ if (!initialized) {
344
+ initialized = true;
345
+ (0, vue_1.watchEffect)(() => {
346
+ if (connected.value !== 'connected') {
347
+ return;
348
+ }
349
+ initialize().catch((error) => {
350
+ console.error(`Failed to initialize ${resIdentifier}`, error);
351
+ });
352
+ });
353
+ }
354
+ if ('default' in options) {
355
+ const defaultValue = options.default;
356
+ const withDefault = (0, vue_1.computed)(() => {
357
+ if (resource.value === undefined) {
358
+ return defaultValue;
359
+ }
360
+ return resource.value;
361
+ });
362
+ return withDefault;
363
+ }
364
+ return resource;
365
+ };
366
+ }
367
+ const azureHandlerError = (0, vue_1.ref)('');
368
+ const handleAzureCode = async () => {
369
+ if (shvSessionStorage.value.azureWorkflow === undefined) {
370
+ azureHandlerError.value = 'Azure error: no active login procedure';
371
+ return;
372
+ }
373
+ if (options.azureCodeRedirect === undefined) {
374
+ throw new Error('Azure redirect URL not set');
375
+ }
376
+ const { azureCodeRedirect } = options;
377
+ return makePkce({ ...shvSessionStorage.value.azureWorkflow, azureCodeRedirect }).exchangeForAccessToken(globalThis.location.href).then(resp => {
378
+ shvSessionStorage.value.azureWorkflow = undefined;
379
+ const token = resp.access_token;
380
+ if (token === undefined) {
381
+ azureHandlerError.value = 'Couldn\'t authenticate to Azure: unable to exchange access token';
382
+ return;
383
+ }
384
+ // Store the token and remove the code from the query params.
385
+ shvLogout();
386
+ shvLocalStorage.value.azureAccessToken = token;
387
+ const redirectTo = shvLocalStorage.value.azureRedirectTo;
388
+ if (redirectTo === undefined) {
389
+ azureHandlerError.value = 'Couldn\'t authenticate to Azure: no redirect URL';
390
+ return;
391
+ }
392
+ shvLocalStorage.value.azureRedirectTo = undefined;
393
+ return redirectTo;
394
+ }).catch((error) => {
395
+ azureHandlerError.value = `Couldn't authenticate to Azure: ${JSON.stringify(error)}`;
396
+ });
397
+ };
398
+ return {
399
+ azureAuth,
400
+ azureHandlerError,
401
+ connected,
402
+ displayEmail,
403
+ displayFullName,
404
+ displayName,
405
+ displayPhoto,
406
+ displayShortName,
407
+ getConnection,
408
+ handleAzureCode,
409
+ logContents,
410
+ loginFailure,
411
+ makeGlobalResource,
412
+ makeRpcCall,
413
+ makeRpcCallParam,
414
+ rpcCall,
415
+ setShvCredentials,
416
+ shvLocalStorage,
417
+ shvLogout,
418
+ shvSessionStorage,
419
+ };
420
+ }
421
+ const fullReloadHandler = (_param, _resource, reinit) => {
422
+ reinit();
423
+ };
424
+ exports.fullReloadHandler = fullReloadHandler;