@symbiote-native/auth-session 0.0.0-stage → 0.1.1

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.
Files changed (179) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +157 -2
  3. package/build/angular/index.d.ts +2 -0
  4. package/build/angular/index.js +3 -0
  5. package/build/angular/use-auth-request.d.ts +7 -0
  6. package/build/angular/use-auth-request.js +11 -0
  7. package/build/core/auth-request-controllers.d.ts +44 -0
  8. package/build/core/auth-request-controllers.js +122 -0
  9. package/build/core/auth-request-hooks.d.ts +67 -0
  10. package/build/core/auth-request-hooks.js +75 -0
  11. package/build/core/auth-request.d.ts +29 -0
  12. package/build/core/auth-request.js +161 -0
  13. package/build/core/auth-request.types.d.ts +46 -0
  14. package/build/core/auth-request.types.js +23 -0
  15. package/build/core/auth-session.d.ts +10 -0
  16. package/build/core/auth-session.js +37 -0
  17. package/build/core/auth-session.types.d.ts +27 -0
  18. package/build/core/auth-session.types.js +1 -0
  19. package/build/core/base64.d.ts +1 -0
  20. package/build/core/base64.js +28 -0
  21. package/build/core/discovery.d.ts +57 -0
  22. package/build/core/discovery.js +29 -0
  23. package/build/core/errors.d.ts +29 -0
  24. package/build/core/errors.js +74 -0
  25. package/build/core/fetch.d.ts +15 -0
  26. package/build/core/fetch.js +40 -0
  27. package/build/core/index.d.ts +24 -0
  28. package/build/core/index.js +14 -0
  29. package/build/core/pkce.d.ts +9 -0
  30. package/build/core/pkce.js +41 -0
  31. package/build/core/prompt-string.d.ts +2 -0
  32. package/build/core/prompt-string.js +5 -0
  33. package/build/core/providers/facebook.d.ts +16 -0
  34. package/build/core/providers/facebook.js +43 -0
  35. package/build/core/providers/google-exchange-controller.d.ts +10 -0
  36. package/build/core/providers/google-exchange-controller.js +73 -0
  37. package/build/core/providers/google.d.ts +22 -0
  38. package/build/core/providers/google.js +52 -0
  39. package/build/core/providers/provider-hook-setup.d.ts +19 -0
  40. package/build/core/providers/provider-hook-setup.js +78 -0
  41. package/build/core/providers/provider-utils.d.ts +2 -0
  42. package/build/core/providers/provider-utils.js +8 -0
  43. package/build/core/providers/provider.types.d.ts +5 -0
  44. package/build/core/providers/provider.types.js +1 -0
  45. package/build/core/query-params.d.ts +5 -0
  46. package/build/core/query-params.js +12 -0
  47. package/build/core/session-result.d.ts +6 -0
  48. package/build/core/session-result.js +4 -0
  49. package/build/core/token-request.d.ts +89 -0
  50. package/build/core/token-request.js +328 -0
  51. package/build/core/token-request.types.d.ts +52 -0
  52. package/build/core/token-request.types.js +14 -0
  53. package/build/react/index.d.ts +3 -0
  54. package/build/react/index.js +2 -0
  55. package/build/react/use-auth-request.d.ts +20 -0
  56. package/build/react/use-auth-request.js +52 -0
  57. package/build/solid/index.d.ts +2 -0
  58. package/build/solid/index.js +2 -0
  59. package/build/solid/use-auth-request.d.ts +6 -0
  60. package/build/solid/use-auth-request.js +10 -0
  61. package/build/svelte/index.d.ts +2 -0
  62. package/build/svelte/index.js +2 -0
  63. package/build/svelte/use-auth-request.svelte.d.ts +28 -0
  64. package/build/svelte/use-auth-request.svelte.js +11 -0
  65. package/build/vue/index.d.ts +2 -0
  66. package/build/vue/index.js +2 -0
  67. package/build/vue/use-auth-request.d.ts +7 -0
  68. package/build/vue/use-auth-request.js +12 -0
  69. package/build-ngc/angular/index.d.ts +2 -0
  70. package/build-ngc/angular/index.js +4 -0
  71. package/build-ngc/angular/index.js.map +1 -0
  72. package/build-ngc/angular/use-auth-request.d.ts +7 -0
  73. package/build-ngc/angular/use-auth-request.js +12 -0
  74. package/build-ngc/angular/use-auth-request.js.map +1 -0
  75. package/build-ngc/core/auth-request-controllers.d.ts +44 -0
  76. package/build-ngc/core/auth-request-controllers.js +123 -0
  77. package/build-ngc/core/auth-request-controllers.js.map +1 -0
  78. package/build-ngc/core/auth-request-hooks.d.ts +67 -0
  79. package/build-ngc/core/auth-request-hooks.js +76 -0
  80. package/build-ngc/core/auth-request-hooks.js.map +1 -0
  81. package/build-ngc/core/auth-request.d.ts +29 -0
  82. package/build-ngc/core/auth-request.js +162 -0
  83. package/build-ngc/core/auth-request.js.map +1 -0
  84. package/build-ngc/core/auth-request.types.d.ts +46 -0
  85. package/build-ngc/core/auth-request.types.js +24 -0
  86. package/build-ngc/core/auth-request.types.js.map +1 -0
  87. package/build-ngc/core/auth-session.d.ts +10 -0
  88. package/build-ngc/core/auth-session.js +38 -0
  89. package/build-ngc/core/auth-session.js.map +1 -0
  90. package/build-ngc/core/auth-session.types.d.ts +27 -0
  91. package/build-ngc/core/auth-session.types.js +2 -0
  92. package/build-ngc/core/auth-session.types.js.map +1 -0
  93. package/build-ngc/core/base64.d.ts +1 -0
  94. package/build-ngc/core/base64.js +29 -0
  95. package/build-ngc/core/base64.js.map +1 -0
  96. package/build-ngc/core/discovery.d.ts +57 -0
  97. package/build-ngc/core/discovery.js +30 -0
  98. package/build-ngc/core/discovery.js.map +1 -0
  99. package/build-ngc/core/errors.d.ts +29 -0
  100. package/build-ngc/core/errors.js +75 -0
  101. package/build-ngc/core/errors.js.map +1 -0
  102. package/build-ngc/core/fetch.d.ts +15 -0
  103. package/build-ngc/core/fetch.js +41 -0
  104. package/build-ngc/core/fetch.js.map +1 -0
  105. package/build-ngc/core/index.d.ts +24 -0
  106. package/build-ngc/core/index.js +15 -0
  107. package/build-ngc/core/index.js.map +1 -0
  108. package/build-ngc/core/pkce.d.ts +9 -0
  109. package/build-ngc/core/pkce.js +42 -0
  110. package/build-ngc/core/pkce.js.map +1 -0
  111. package/build-ngc/core/prompt-string.d.ts +2 -0
  112. package/build-ngc/core/prompt-string.js +6 -0
  113. package/build-ngc/core/prompt-string.js.map +1 -0
  114. package/build-ngc/core/providers/facebook.d.ts +16 -0
  115. package/build-ngc/core/providers/facebook.js +44 -0
  116. package/build-ngc/core/providers/facebook.js.map +1 -0
  117. package/build-ngc/core/providers/google-exchange-controller.d.ts +10 -0
  118. package/build-ngc/core/providers/google-exchange-controller.js +74 -0
  119. package/build-ngc/core/providers/google-exchange-controller.js.map +1 -0
  120. package/build-ngc/core/providers/google.d.ts +22 -0
  121. package/build-ngc/core/providers/google.js +53 -0
  122. package/build-ngc/core/providers/google.js.map +1 -0
  123. package/build-ngc/core/providers/provider-hook-setup.d.ts +19 -0
  124. package/build-ngc/core/providers/provider-hook-setup.js +79 -0
  125. package/build-ngc/core/providers/provider-hook-setup.js.map +1 -0
  126. package/build-ngc/core/providers/provider-utils.d.ts +2 -0
  127. package/build-ngc/core/providers/provider-utils.js +9 -0
  128. package/build-ngc/core/providers/provider-utils.js.map +1 -0
  129. package/build-ngc/core/providers/provider.types.d.ts +5 -0
  130. package/build-ngc/core/providers/provider.types.js +2 -0
  131. package/build-ngc/core/providers/provider.types.js.map +1 -0
  132. package/build-ngc/core/query-params.d.ts +5 -0
  133. package/build-ngc/core/query-params.js +13 -0
  134. package/build-ngc/core/query-params.js.map +1 -0
  135. package/build-ngc/core/session-result.d.ts +6 -0
  136. package/build-ngc/core/session-result.js +5 -0
  137. package/build-ngc/core/session-result.js.map +1 -0
  138. package/build-ngc/core/token-request.d.ts +89 -0
  139. package/build-ngc/core/token-request.js +329 -0
  140. package/build-ngc/core/token-request.js.map +1 -0
  141. package/build-ngc/core/token-request.types.d.ts +52 -0
  142. package/build-ngc/core/token-request.types.js +15 -0
  143. package/build-ngc/core/token-request.types.js.map +1 -0
  144. package/package.json +151 -3
  145. package/src/angular/index.ts +11 -0
  146. package/src/angular/use-auth-request.ts +30 -0
  147. package/src/core/auth-request-controllers.ts +233 -0
  148. package/src/core/auth-request-hooks.ts +342 -0
  149. package/src/core/auth-request.ts +199 -0
  150. package/src/core/auth-request.types.ts +55 -0
  151. package/src/core/auth-session.ts +63 -0
  152. package/src/core/auth-session.types.ts +29 -0
  153. package/src/core/base64.ts +33 -0
  154. package/src/core/discovery.ts +102 -0
  155. package/src/core/errors.ts +102 -0
  156. package/src/core/fetch.ts +71 -0
  157. package/src/core/index.ts +97 -0
  158. package/src/core/pkce.ts +60 -0
  159. package/src/core/prompt-string.ts +8 -0
  160. package/src/core/providers/facebook.ts +66 -0
  161. package/src/core/providers/google-exchange-controller.ts +117 -0
  162. package/src/core/providers/google.ts +81 -0
  163. package/src/core/providers/provider-hook-setup.ts +117 -0
  164. package/src/core/providers/provider-utils.ts +18 -0
  165. package/src/core/providers/provider.types.ts +6 -0
  166. package/src/core/query-params.ts +20 -0
  167. package/src/core/session-result.ts +15 -0
  168. package/src/core/token-request.ts +452 -0
  169. package/src/core/token-request.types.ts +60 -0
  170. package/src/react/index.ts +11 -0
  171. package/src/react/use-auth-request.ts +151 -0
  172. package/src/solid/index.ts +10 -0
  173. package/src/solid/use-auth-request.ts +24 -0
  174. package/src/svelte/index.ts +10 -0
  175. package/src/svelte/svelte-ambient.d.ts +3 -0
  176. package/src/svelte/svelte-compile.test-helper.ts +7 -0
  177. package/src/svelte/use-auth-request.svelte.ts +22 -0
  178. package/src/vue/index.ts +10 -0
  179. package/src/vue/use-auth-request.ts +38 -0
@@ -0,0 +1,233 @@
1
+ // Framework-agnostic halves of `useAutoDiscovery`, `useLoadedAuthRequest` and
2
+ // `useAuthRequestResult`. Each controller binds to an adapter's `createResourceHook`, and the value
3
+ // it hands back is a cell the adapter follows with its `createEventValueHook`
4
+
5
+ import type { IEventValueSource } from '@symbiote-native/engine';
6
+ import { createResourceController } from '@symbiote-native/engine';
7
+ import type {
8
+ IAuthDiscoveryDocument,
9
+ IAuthRequestConfig,
10
+ IAuthRequestPromptOptions,
11
+ } from './auth-request.types';
12
+ import type { IAuthSessionResult } from './auth-session.types';
13
+ import type { IDiscoveryDocument, IIssuerOrDiscovery } from './discovery';
14
+ import { resolveDiscoveryAsync } from './discovery';
15
+ import { createPromptString } from './prompt-string';
16
+
17
+ export const AUTH_CELL_CHANGE = 'change';
18
+
19
+ export type IAuthCell<T> = IEventValueSource<T, typeof AUTH_CELL_CHANGE> & {
20
+ getSnapshot: () => T;
21
+ };
22
+
23
+ type IWritableAuthCell<T> = IAuthCell<T> & { set: (value: T) => void };
24
+
25
+ export function createAuthCell<T>(initial: T): IWritableAuthCell<T> {
26
+ let value = initial;
27
+ const listeners = new Set<(next: T) => void>();
28
+ return {
29
+ getSnapshot: () => value,
30
+ set(next) {
31
+ value = next;
32
+ for (const listener of [...listeners]) listener(next);
33
+ },
34
+ addListener(_event, listener) {
35
+ listeners.add(listener);
36
+ return { remove: () => void listeners.delete(listener) };
37
+ },
38
+ };
39
+ }
40
+
41
+ /** What a request has to offer for a hook to load it and prompt with it */
42
+ export type ILoadableRequest = {
43
+ url: string | null;
44
+ codeVerifier?: string;
45
+ makeAuthUrlAsync: (discovery: IAuthDiscoveryDocument) => Promise<string>;
46
+ promptAsync: (
47
+ discovery: IAuthDiscoveryDocument,
48
+ options?: IAuthRequestPromptOptions,
49
+ ) => Promise<IAuthSessionResult>;
50
+ };
51
+
52
+ export type IAuthRequestClass<TRequest extends ILoadableRequest> = new (
53
+ config: IAuthRequestConfig,
54
+ ) => TRequest;
55
+
56
+ type ICellResourceController<TArgs extends unknown[], TValue> = {
57
+ resolve: (...args: TArgs) => IAuthCell<TValue>;
58
+ flushDispose: () => void;
59
+ dispose: () => void;
60
+ };
61
+
62
+ type IAutoDiscoveryResource = {
63
+ cell: IWritableAuthCell<IDiscoveryDocument | null>;
64
+ stop: () => void;
65
+ };
66
+
67
+ export function createAutoDiscoveryController(): ICellResourceController<
68
+ [IIssuerOrDiscovery],
69
+ IDiscoveryDocument | null
70
+ > {
71
+ const controller = createResourceController<
72
+ IIssuerOrDiscovery,
73
+ IAutoDiscoveryResource
74
+ >(
75
+ issuerOrDiscovery => {
76
+ const cell = createAuthCell<IDiscoveryDocument | null>(null);
77
+ let isAllowed = true;
78
+ void resolveDiscoveryAsync(issuerOrDiscovery).then(discovery => {
79
+ if (isAllowed) cell.set(discovery);
80
+ });
81
+ return {
82
+ cell,
83
+ stop: () => {
84
+ isAllowed = false;
85
+ },
86
+ };
87
+ },
88
+ resource => resource.stop(),
89
+ );
90
+ return {
91
+ resolve: issuerOrDiscovery => controller.resolve(issuerOrDiscovery).cell,
92
+ flushDispose: controller.flushDispose,
93
+ dispose: controller.dispose,
94
+ };
95
+ }
96
+
97
+ // Everything upstream lists as the effect's dependencies, folded to primitives
98
+ function loadedRequestKey(
99
+ config: IAuthRequestConfig,
100
+ discovery: IDiscoveryDocument | null,
101
+ ): string {
102
+ return JSON.stringify([
103
+ discovery?.authorizationEndpoint,
104
+ config.clientId,
105
+ config.redirectUri,
106
+ config.responseType,
107
+ config.clientSecret,
108
+ config.codeChallenge,
109
+ config.state,
110
+ config.usePKCE,
111
+ config.scopes?.join(' '),
112
+ createPromptString(config.prompt),
113
+ JSON.stringify(config.extraParams ?? {}),
114
+ ]);
115
+ }
116
+
117
+ type ILoadedRequestKey = {
118
+ key: string;
119
+ config: IAuthRequestConfig;
120
+ discovery: IDiscoveryDocument | null;
121
+ };
122
+
123
+ type ILoadedRequestResource<TRequest extends ILoadableRequest> = {
124
+ cell: IWritableAuthCell<TRequest | null>;
125
+ stop: () => void;
126
+ };
127
+
128
+ export function createLoadedRequestController<
129
+ TRequest extends ILoadableRequest = ILoadableRequest,
130
+ >(): {
131
+ resolve: (
132
+ config: IAuthRequestConfig,
133
+ discovery: IDiscoveryDocument | null,
134
+ RequestClass: IAuthRequestClass<TRequest>,
135
+ ) => IAuthCell<TRequest | null>;
136
+ flushDispose: () => void;
137
+ dispose: () => void;
138
+ } {
139
+ // The request that finished loading last, shown while a changed config reloads
140
+ let lastLoaded: TRequest | null = null;
141
+ let RequestClassInUse: IAuthRequestClass<TRequest> | null = null;
142
+
143
+ const controller = createResourceController<
144
+ ILoadedRequestKey,
145
+ ILoadedRequestResource<TRequest>
146
+ >(
147
+ ({ config, discovery }) => {
148
+ const cell = createAuthCell<TRequest | null>(lastLoaded);
149
+ let isMounted = true;
150
+ if (discovery && RequestClassInUse) {
151
+ const request = new RequestClassInUse(config);
152
+ void request.makeAuthUrlAsync(discovery).then(() => {
153
+ if (!isMounted) return;
154
+ lastLoaded = request;
155
+ cell.set(request);
156
+ });
157
+ }
158
+ return {
159
+ cell,
160
+ stop: () => {
161
+ isMounted = false;
162
+ },
163
+ };
164
+ },
165
+ resource => resource.stop(),
166
+ (a, b) => a.key === b.key,
167
+ );
168
+
169
+ return {
170
+ resolve(config, discovery, RequestClass) {
171
+ RequestClassInUse = RequestClass;
172
+ return controller.resolve({
173
+ key: loadedRequestKey(config, discovery),
174
+ config,
175
+ discovery,
176
+ }).cell;
177
+ },
178
+ flushDispose: controller.flushDispose,
179
+ dispose: controller.dispose,
180
+ };
181
+ }
182
+
183
+ export type IPromptMethod = (
184
+ options?: IAuthRequestPromptOptions,
185
+ ) => Promise<IAuthSessionResult>;
186
+
187
+ export type IRequestResultHolder = {
188
+ result: IAuthCell<IAuthSessionResult | null>;
189
+ promptAsync: IPromptMethod;
190
+ };
191
+
192
+ export function createRequestResultController(): {
193
+ resolve: (
194
+ request: ILoadableRequest | null,
195
+ discovery: IDiscoveryDocument | null,
196
+ customOptions?: IAuthRequestPromptOptions,
197
+ ) => IRequestResultHolder;
198
+ flushDispose: () => void;
199
+ dispose: () => void;
200
+ } {
201
+ const result = createAuthCell<IAuthSessionResult | null>(null);
202
+ let latest: {
203
+ request: ILoadableRequest | null;
204
+ discovery: IDiscoveryDocument | null;
205
+ customOptions: IAuthRequestPromptOptions;
206
+ } = { request: null, discovery: null, customOptions: {} };
207
+
208
+ // Reads the latest inputs when called, so one stable function serves every render
209
+ const promptAsync: IPromptMethod = async (options = {}) => {
210
+ const { request, discovery, customOptions } = latest;
211
+ if (!discovery || !request) {
212
+ throw new Error(
213
+ 'Cannot prompt to authenticate until the request has finished loading.',
214
+ );
215
+ }
216
+ const prompted = await request.promptAsync(discovery, {
217
+ ...customOptions,
218
+ ...options,
219
+ });
220
+ result.set(prompted);
221
+ return prompted;
222
+ };
223
+ const holder: IRequestResultHolder = { result, promptAsync };
224
+
225
+ return {
226
+ resolve(request, discovery, customOptions = {}) {
227
+ latest = { request, discovery, customOptions };
228
+ return holder;
229
+ },
230
+ flushDispose: () => undefined,
231
+ dispose: () => undefined,
232
+ };
233
+ }
@@ -0,0 +1,342 @@
1
+ // The auth request hooks written once for every adapter whose hooks take getters (Vue, Solid,
2
+ // Svelte, Angular), React keeps its own wiring. An adapter's boxes (`ShallowRef`, `Accessor`,
3
+ // `{ current }`, `Signal`) are type-level functions here, since one hook returns several box types
4
+
5
+ import { AuthRequest } from './auth-request';
6
+ import type {
7
+ IAuthCell,
8
+ IAuthRequestClass,
9
+ IPromptMethod,
10
+ } from './auth-request-controllers';
11
+ import {
12
+ AUTH_CELL_CHANGE,
13
+ createAutoDiscoveryController,
14
+ createLoadedRequestController,
15
+ createRequestResultController,
16
+ } from './auth-request-controllers';
17
+ import type {
18
+ IAuthRequestConfig,
19
+ IAuthRequestPromptOptions,
20
+ } from './auth-request.types';
21
+ import type {
22
+ IAuthSessionRedirectUriOptions,
23
+ IAuthSessionResult,
24
+ } from './auth-session.types';
25
+ import type { IDiscoveryDocument, IIssuerOrDiscovery } from './discovery';
26
+ import type {
27
+ FacebookAuthRequest,
28
+ IFacebookAuthRequestConfig,
29
+ } from './providers/facebook';
30
+ import {
31
+ discovery as facebookDiscovery,
32
+ FacebookAuthRequest as FacebookRequest,
33
+ } from './providers/facebook';
34
+ import { createGoogleExchangeController } from './providers/google-exchange-controller';
35
+ import type {
36
+ GoogleAuthRequest,
37
+ IGoogleAuthRequestConfig,
38
+ } from './providers/google';
39
+ import {
40
+ discovery as googleDiscovery,
41
+ GoogleAuthRequest as GoogleRequest,
42
+ } from './providers/google';
43
+ import {
44
+ resolveFacebookRequestSetup,
45
+ resolveGoogleRequestSetup,
46
+ toGoogleIdTokenConfig,
47
+ } from './providers/provider-hook-setup';
48
+
49
+ /** A type-level function, how an adapter says "its box of `T`" */
50
+ export interface IHkt {
51
+ readonly input: unknown;
52
+ readonly output: unknown;
53
+ }
54
+ export type IApply<F extends IHkt, T> = (F & { readonly input: T })['output'];
55
+
56
+ /** A plain getter, the argument shape of Solid, Svelte and Angular */
57
+ export interface IGetterKind extends IHkt {
58
+ readonly output: () => this['input'];
59
+ }
60
+
61
+ type IBoxed<T> = { readonly current: T };
62
+
63
+ /** A `{ current }` box, Svelte's result shape */
64
+ export interface IBoxedKind extends IHkt {
65
+ readonly output: IBoxed<this['input']>;
66
+ }
67
+
68
+ /** The argument half of a kit for adapters whose arguments are plain getters */
69
+ export const GETTER_ARGS = {
70
+ toGetter: <T>(arg: () => T): (() => T) => arg,
71
+ constant:
72
+ <T>(value: T): (() => T) =>
73
+ () =>
74
+ value,
75
+ };
76
+
77
+ type IDiscoveryValue = IDiscoveryDocument | null;
78
+ type IResultValue = IAuthSessionResult | null;
79
+
80
+ export type IAuthResourceController<TArgs extends unknown[], TResource> = {
81
+ resolve: (...args: TArgs) => TResource;
82
+ flushDispose: () => void;
83
+ dispose: () => void;
84
+ };
85
+
86
+ /** The adapter's own primitives the hooks are built from */
87
+ export type IAuthHooksKit<
88
+ FResource extends IHkt,
89
+ FValue extends IHkt,
90
+ FArg extends IHkt,
91
+ > = {
92
+ createResourceHook: <TArgs extends unknown[], TResource>(
93
+ createController: () => IAuthResourceController<TArgs, TResource>,
94
+ ) => (getArgs: () => TArgs) => IApply<FResource, TResource>;
95
+ readResource: <T>(box: IApply<FResource, T>) => T;
96
+ createEventValueHook: <TValue>(
97
+ event: typeof AUTH_CELL_CHANGE,
98
+ getValue: (source: IAuthCell<TValue>) => TValue,
99
+ ) => (getSource: () => IAuthCell<TValue>) => IApply<FValue, TValue>;
100
+ readValue: <T>(box: IApply<FValue, T>) => T;
101
+ /** Turns whatever the adapter accepts as an argument into a getter */
102
+ toGetter: <T>(arg: IApply<FArg, T>) => () => T;
103
+ /** Wraps a fixed value in the adapter's argument shape */
104
+ constant: <T>(value: T) => IApply<FArg, T>;
105
+ };
106
+
107
+ type IUseAuthRequestBoxes<
108
+ FValue extends IHkt,
109
+ TRequest extends AuthRequest,
110
+ > = readonly [
111
+ IApply<FValue, TRequest | null>,
112
+ IApply<FValue, IResultValue>,
113
+ IPromptMethod,
114
+ ];
115
+
116
+ type IAnyKit = IAuthHooksKit<IHkt, IHkt, IHkt>;
117
+
118
+ function readAuthCell<T>(cell: IAuthCell<T>): T {
119
+ return cell.getSnapshot();
120
+ }
121
+
122
+ function valueHook<
123
+ FResource extends IHkt,
124
+ FValue extends IHkt,
125
+ FArg extends IHkt,
126
+ T,
127
+ >(
128
+ kit: IAuthHooksKit<FResource, FValue, FArg>,
129
+ ): (getSource: () => IAuthCell<T>) => IApply<FValue, T> {
130
+ return kit.createEventValueHook<T>(AUTH_CELL_CHANGE, readAuthCell);
131
+ }
132
+
133
+ function discoveryOf<
134
+ FResource extends IHkt,
135
+ FValue extends IHkt,
136
+ FArg extends IHkt,
137
+ >(
138
+ kit: IAuthHooksKit<FResource, FValue, FArg>,
139
+ getIssuer: () => IIssuerOrDiscovery,
140
+ ): IApply<FValue, IDiscoveryValue> {
141
+ const cell = kit.createResourceHook(createAutoDiscoveryController)(() => [
142
+ getIssuer(),
143
+ ]);
144
+ return valueHook<FResource, FValue, FArg, IDiscoveryValue>(kit)(() =>
145
+ kit.readResource(cell),
146
+ );
147
+ }
148
+
149
+ function loadedRequestOf<
150
+ FResource extends IHkt,
151
+ FValue extends IHkt,
152
+ FArg extends IHkt,
153
+ TRequest extends AuthRequest,
154
+ >(
155
+ kit: IAuthHooksKit<FResource, FValue, FArg>,
156
+ getConfig: () => IAuthRequestConfig,
157
+ getDiscovery: () => IDiscoveryValue,
158
+ RequestClass: IAuthRequestClass<TRequest>,
159
+ ): IApply<FValue, TRequest | null> {
160
+ const useCell = kit.createResourceHook(() =>
161
+ createLoadedRequestController<TRequest>(),
162
+ );
163
+ const cell = useCell(() => [getConfig(), getDiscovery(), RequestClass]);
164
+ return valueHook<FResource, FValue, FArg, TRequest | null>(kit)(() =>
165
+ kit.readResource(cell),
166
+ );
167
+ }
168
+
169
+ function resultOf<
170
+ FResource extends IHkt,
171
+ FValue extends IHkt,
172
+ FArg extends IHkt,
173
+ >(
174
+ kit: IAuthHooksKit<FResource, FValue, FArg>,
175
+ getRequest: () => AuthRequest | null,
176
+ getDiscovery: () => IDiscoveryValue,
177
+ getOptions: () => IAuthRequestPromptOptions,
178
+ ): readonly [IApply<FValue, IResultValue>, IPromptMethod] {
179
+ const useHolder = kit.createResourceHook(createRequestResultController);
180
+ const holder = useHolder(() => [getRequest(), getDiscovery(), getOptions()]);
181
+ const result = valueHook<FResource, FValue, FArg, IResultValue>(kit)(
182
+ () => kit.readResource(holder).result,
183
+ );
184
+ return [result, options => kit.readResource(holder).promptAsync(options)];
185
+ }
186
+
187
+ function baseRequestOf<
188
+ FResource extends IHkt,
189
+ FValue extends IHkt,
190
+ FArg extends IHkt,
191
+ >(
192
+ kit: IAuthHooksKit<FResource, FValue, FArg>,
193
+ getConfig: () => IAuthRequestConfig,
194
+ getDiscovery: () => IDiscoveryValue,
195
+ ): IUseAuthRequestBoxes<FValue, AuthRequest> {
196
+ const request = loadedRequestOf(kit, getConfig, getDiscovery, AuthRequest);
197
+ const [result, promptAsync] = resultOf(
198
+ kit,
199
+ () => kit.readValue(request),
200
+ getDiscovery,
201
+ () => ({}),
202
+ );
203
+ return [request, result, promptAsync];
204
+ }
205
+
206
+ function googleRequestOf<
207
+ FResource extends IHkt,
208
+ FValue extends IHkt,
209
+ FArg extends IHkt,
210
+ >(
211
+ kit: IAuthHooksKit<FResource, FValue, FArg>,
212
+ getConfig: () => Partial<IGoogleAuthRequestConfig>,
213
+ getRedirectUriOptions: () => Partial<IAuthSessionRedirectUriOptions>,
214
+ ): IUseAuthRequestBoxes<FValue, GoogleAuthRequest> {
215
+ const getSetup = (): ReturnType<typeof resolveGoogleRequestSetup> =>
216
+ resolveGoogleRequestSetup(getConfig(), getRedirectUriOptions());
217
+ const request = loadedRequestOf(
218
+ kit,
219
+ () => getSetup().requestConfig,
220
+ () => googleDiscovery,
221
+ GoogleRequest,
222
+ );
223
+ const [result, promptAsync] = resultOf(
224
+ kit,
225
+ () => kit.readValue(request),
226
+ () => googleDiscovery,
227
+ () => ({}),
228
+ );
229
+ const useExchange = kit.createResourceHook(createGoogleExchangeController);
230
+ const exchanged = useExchange(() => [
231
+ kit.readValue(result),
232
+ kit.readValue(request),
233
+ getSetup().exchange,
234
+ ]);
235
+ const fullResult = valueHook<FResource, FValue, FArg, IResultValue>(kit)(() =>
236
+ kit.readResource(exchanged),
237
+ );
238
+ return [request, fullResult, promptAsync];
239
+ }
240
+
241
+ function facebookRequestOf<
242
+ FResource extends IHkt,
243
+ FValue extends IHkt,
244
+ FArg extends IHkt,
245
+ >(
246
+ kit: IAuthHooksKit<FResource, FValue, FArg>,
247
+ getConfig: () => Partial<IFacebookAuthRequestConfig>,
248
+ getRedirectUriOptions: () => Partial<IAuthSessionRedirectUriOptions>,
249
+ ): IUseAuthRequestBoxes<FValue, FacebookAuthRequest> {
250
+ const request = loadedRequestOf(
251
+ kit,
252
+ () => resolveFacebookRequestSetup(getConfig(), getRedirectUriOptions()),
253
+ () => facebookDiscovery,
254
+ FacebookRequest,
255
+ );
256
+ const [result, promptAsync] = resultOf(
257
+ kit,
258
+ () => kit.readValue(request),
259
+ () => facebookDiscovery,
260
+ () => ({}),
261
+ );
262
+ return [request, result, promptAsync];
263
+ }
264
+
265
+ export type IAuthRequestHooks<FValue extends IHkt, FArg extends IHkt> = {
266
+ useAutoDiscovery: (
267
+ issuerOrDiscovery: IApply<FArg, IIssuerOrDiscovery>,
268
+ ) => IApply<FValue, IDiscoveryValue>;
269
+ useLoadedAuthRequest: (
270
+ config: IApply<FArg, IAuthRequestConfig>,
271
+ discovery: IApply<FArg, IDiscoveryValue>,
272
+ RequestClass: IAuthRequestClass<AuthRequest>,
273
+ ) => IApply<FValue, AuthRequest | null>;
274
+ useAuthRequestResult: (
275
+ request: IApply<FArg, AuthRequest | null>,
276
+ discovery: IApply<FArg, IDiscoveryValue>,
277
+ customOptions?: IApply<FArg, IAuthRequestPromptOptions>,
278
+ ) => readonly [IApply<FValue, IResultValue>, IPromptMethod];
279
+ useAuthRequest: (
280
+ config: IApply<FArg, IAuthRequestConfig>,
281
+ discovery: IApply<FArg, IDiscoveryValue>,
282
+ ) => IUseAuthRequestBoxes<FValue, AuthRequest>;
283
+ useGoogleAuthRequest: (
284
+ config?: IApply<FArg, Partial<IGoogleAuthRequestConfig>>,
285
+ redirectUriOptions?: IApply<FArg, Partial<IAuthSessionRedirectUriOptions>>,
286
+ ) => IUseAuthRequestBoxes<FValue, GoogleAuthRequest>;
287
+ useGoogleIdTokenAuthRequest: (
288
+ config: IApply<FArg, Partial<IGoogleAuthRequestConfig>>,
289
+ redirectUriOptions?: IApply<FArg, Partial<IAuthSessionRedirectUriOptions>>,
290
+ ) => IUseAuthRequestBoxes<FValue, GoogleAuthRequest>;
291
+ useFacebookAuthRequest: (
292
+ config?: IApply<FArg, Partial<IFacebookAuthRequestConfig>>,
293
+ redirectUriOptions?: IApply<FArg, Partial<IAuthSessionRedirectUriOptions>>,
294
+ ) => IUseAuthRequestBoxes<FValue, FacebookAuthRequest>;
295
+ };
296
+
297
+ export function createAuthRequestHooks<
298
+ FResource extends IHkt,
299
+ FValue extends IHkt,
300
+ FArg extends IHkt,
301
+ >(
302
+ kit: IAuthHooksKit<FResource, FValue, FArg>,
303
+ ): IAuthRequestHooks<FValue, FArg> {
304
+ const noOptions = kit.constant<Partial<IAuthSessionRedirectUriOptions>>({});
305
+ return {
306
+ useAutoDiscovery: issuer => discoveryOf(kit, kit.toGetter(issuer)),
307
+ useLoadedAuthRequest: (config, discovery, RequestClass) =>
308
+ loadedRequestOf(
309
+ kit,
310
+ kit.toGetter(config),
311
+ kit.toGetter(discovery),
312
+ RequestClass,
313
+ ),
314
+ useAuthRequestResult: (
315
+ request,
316
+ discovery,
317
+ customOptions = kit.constant({}),
318
+ ) =>
319
+ resultOf(
320
+ kit,
321
+ kit.toGetter(request),
322
+ kit.toGetter(discovery),
323
+ kit.toGetter(customOptions),
324
+ ),
325
+ useAuthRequest: (config, discovery) =>
326
+ baseRequestOf(kit, kit.toGetter(config), kit.toGetter(discovery)),
327
+ useGoogleAuthRequest: (config = kit.constant({}), redirect = noOptions) =>
328
+ googleRequestOf(kit, kit.toGetter(config), kit.toGetter(redirect)),
329
+ useGoogleIdTokenAuthRequest: (config, redirect = noOptions) => {
330
+ const getConfig = kit.toGetter(config);
331
+ return googleRequestOf(
332
+ kit,
333
+ () => toGoogleIdTokenConfig(getConfig()),
334
+ kit.toGetter(redirect),
335
+ );
336
+ },
337
+ useFacebookAuthRequest: (config = kit.constant({}), redirect = noOptions) =>
338
+ facebookRequestOf(kit, kit.toGetter(config), kit.toGetter(redirect)),
339
+ };
340
+ }
341
+
342
+ export type { IAnyKit as IAuthHooksAnyKit };