@forgerock/davinci-client 0.1.3
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 +354 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/lib/authorize.utils.d.ts +22 -0
- package/dist/lib/authorize.utils.d.ts.map +1 -0
- package/dist/lib/authorize.utils.js +23 -0
- package/dist/lib/client.store.d.ts +149 -0
- package/dist/lib/client.store.d.ts.map +1 -0
- package/dist/lib/client.store.js +131 -0
- package/dist/lib/client.store.utils.d.ts +46 -0
- package/dist/lib/client.store.utils.d.ts.map +1 -0
- package/dist/lib/client.store.utils.js +19 -0
- package/dist/lib/client.types.d.ts +9 -0
- package/dist/lib/client.types.d.ts.map +1 -0
- package/dist/lib/collector.types.d.ts +78 -0
- package/dist/lib/collector.types.d.ts.map +1 -0
- package/dist/lib/collector.utils.d.ts +54 -0
- package/dist/lib/collector.utils.d.ts.map +1 -0
- package/dist/lib/collector.utils.js +88 -0
- package/dist/lib/config.slice.d.ts +35 -0
- package/dist/lib/config.slice.d.ts.map +1 -0
- package/dist/lib/config.slice.js +40 -0
- package/dist/lib/config.types.d.ts +9 -0
- package/dist/lib/config.types.d.ts.map +1 -0
- package/dist/lib/davinci.api.d.ts +20 -0
- package/dist/lib/davinci.api.d.ts.map +1 -0
- package/dist/lib/davinci.api.js +172 -0
- package/dist/lib/davinci.types.d.ts +185 -0
- package/dist/lib/davinci.types.d.ts.map +1 -0
- package/dist/lib/davinci.utils.d.ts +18 -0
- package/dist/lib/davinci.utils.d.ts.map +1 -0
- package/dist/lib/davinci.utils.js +102 -0
- package/dist/lib/error.types.d.ts +6 -0
- package/dist/lib/error.types.d.ts.map +1 -0
- package/dist/lib/index.d.ts +3 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/node.reducer.d.ts +22 -0
- package/dist/lib/node.reducer.d.ts.map +1 -0
- package/dist/lib/node.reducer.js +31 -0
- package/dist/lib/node.slice.d.ts +134 -0
- package/dist/lib/node.slice.d.ts.map +1 -0
- package/dist/lib/node.slice.js +160 -0
- package/dist/lib/node.types.d.ts +109 -0
- package/dist/lib/node.types.d.ts.map +1 -0
- package/dist/lib/wellknown.api.d.ts +5 -0
- package/dist/lib/wellknown.api.d.ts.map +1 -0
- package/dist/lib/wellknown.api.js +15 -0
- package/dist/lib/wellknown.types.d.ts +38 -0
- package/dist/lib/wellknown.types.d.ts.map +1 -0
- package/dist/types.d.ts +23 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +36 -0
package/README.md
ADDED
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
## DaVinci Client
|
|
2
|
+
|
|
3
|
+
This is the DaVinci Client module for interacting with PingOne Application policies mapped to DaVinci flows. This module helps enable developers to write their own UI and UX for supporting DaVinci Flows within JavaScript "SPA" applications.
|
|
4
|
+
|
|
5
|
+
### Install and import
|
|
6
|
+
|
|
7
|
+
The DaVinci Client can be installed via npm:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm install @forgerock/davinci-client
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Then, import the `davinci` module as a named import:
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { davinci } from '@forgerock/davinci-client';
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Create & configure your DaVinci Client
|
|
20
|
+
|
|
21
|
+
Configure DaVinci Client with the following minimum, required properties:
|
|
22
|
+
|
|
23
|
+
1. `clientId`
|
|
24
|
+
2. `wellknown`
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
// Demo with example values
|
|
28
|
+
import { davinci } from '@forgerock/davinci';
|
|
29
|
+
|
|
30
|
+
const davinciClient = await davinci({
|
|
31
|
+
config: {
|
|
32
|
+
clientId: '726b47438-c41c-4d51-98b0-84a6b474350f9',
|
|
33
|
+
serverConfig: {
|
|
34
|
+
wellknown:
|
|
35
|
+
'https://auth.pingone.ca/02f919edfe-189a-4bc7-9d6c-a46b474347/as/.well-known/openid-configuration',
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
If you have a need for more than one client, say you need to use two or more different PingOne OIDC Applications, you can create two clients, but this should be a rare need.
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
// Demo with example values
|
|
45
|
+
import { davinci } from '@forgerock/davinci';
|
|
46
|
+
|
|
47
|
+
const firstDavinciClient = await davinci(/** config 1 **/);
|
|
48
|
+
const secondDavinciClient = await davinci(/** config 2 **/);
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Here's a full configuration interface:
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
// Demo with optional properties and example values
|
|
55
|
+
interface DaVinciConfig {
|
|
56
|
+
clientId: string; // required
|
|
57
|
+
responseType?: string; // optional; default value: 'code'
|
|
58
|
+
scope?: string; // optional; default value: 'openid'
|
|
59
|
+
serverConfig: {
|
|
60
|
+
timeout?: number; // optional; default value: ?? (NOT IMPLEMENTED)
|
|
61
|
+
wellknown: string; // required
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Start a DaVinci flow
|
|
67
|
+
|
|
68
|
+
Call the `start` method on the returned client API:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
let node = await davinciClient.start();
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
If the user is not authenticated, this will return a **normalized** `node` object from the initial response from DaVinci. The node will be one of four types:
|
|
75
|
+
|
|
76
|
+
1. `ContinueNode`
|
|
77
|
+
2. `SuccessNode`
|
|
78
|
+
3. `ErrorNode`
|
|
79
|
+
4. `FailureNode`
|
|
80
|
+
|
|
81
|
+
Below is a brief look at the "interface" or schema of this node object (some properties removed or abbreviated for brevity):
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
interface NodeState {
|
|
85
|
+
cache: {
|
|
86
|
+
key: string;
|
|
87
|
+
};
|
|
88
|
+
client: {
|
|
89
|
+
action: string;
|
|
90
|
+
description?: string;
|
|
91
|
+
name?: string;
|
|
92
|
+
collectors?: (SingleValueCollector | ActionCollector)[];
|
|
93
|
+
status: string;
|
|
94
|
+
};
|
|
95
|
+
error: null | {
|
|
96
|
+
code: string | number;
|
|
97
|
+
message?: string;
|
|
98
|
+
status: string;
|
|
99
|
+
};
|
|
100
|
+
httpStatus: number;
|
|
101
|
+
server: {
|
|
102
|
+
id?: string;
|
|
103
|
+
interactionId?: string;
|
|
104
|
+
interactionToken?: string;
|
|
105
|
+
eventName?: string;
|
|
106
|
+
session?: string;
|
|
107
|
+
status: string;
|
|
108
|
+
};
|
|
109
|
+
status: string;
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The `node` data is organized for clearer intention. Each response from DaVinci is saved in a cache, so the `cache.key` is to lookup the exact response from which this node was generated (more on this later).
|
|
114
|
+
|
|
115
|
+
The `server` prop just has the items necessary for building the request for the subsequent call to DaVinci, which should rarely be used by the application layer.
|
|
116
|
+
|
|
117
|
+
The `client` property is what the application developers will be using for their rendering instructions and data collection needs and status.
|
|
118
|
+
|
|
119
|
+
To detect the node type after receiving a response, it's best to have a `switch` or `if` condition checking the `status` property:
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
let node = await davinciClient.start();
|
|
123
|
+
|
|
124
|
+
switch (node.status) {
|
|
125
|
+
case 'continue':
|
|
126
|
+
return renderContinue();
|
|
127
|
+
case 'success':
|
|
128
|
+
return renderSuccess();
|
|
129
|
+
case 'error':
|
|
130
|
+
return renderError();
|
|
131
|
+
default: // Handle failure type
|
|
132
|
+
return renderFailure();
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Rendering the Collectors
|
|
137
|
+
|
|
138
|
+
When receiving a `ContinueNode`, it will contain an object called a `collector`. These are instruction to request information from a user or browser environment. There are two types of collectors: `SingleValueCollector` and `ActionCollector`. Their interface looks like this:
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
// This covers collectors, like username or password, that require a single value
|
|
142
|
+
export interface SingleValueCollector {
|
|
143
|
+
category: 'SingleValueCollector';
|
|
144
|
+
type: SingleValueCollectorTypes;
|
|
145
|
+
id: string;
|
|
146
|
+
name: string;
|
|
147
|
+
input: {
|
|
148
|
+
key: string;
|
|
149
|
+
value: string | number | boolean;
|
|
150
|
+
type: string;
|
|
151
|
+
};
|
|
152
|
+
output: {
|
|
153
|
+
key: string;
|
|
154
|
+
label: string;
|
|
155
|
+
type: string;
|
|
156
|
+
value: string;
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
// This is a collector that is associated with an "action" (aka button), like submit or
|
|
160
|
+
// initiating another flow, i.e. forgot password or register
|
|
161
|
+
export interface ActionCollector {
|
|
162
|
+
category: 'ActionCollector';
|
|
163
|
+
type: ActionCollectorTypes;
|
|
164
|
+
id: string;
|
|
165
|
+
name: string;
|
|
166
|
+
output: {
|
|
167
|
+
key: string;
|
|
168
|
+
label: string;
|
|
169
|
+
type: string;
|
|
170
|
+
url?: string;
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Although you can access the collectors via object "dot notation", we recommend using a dedicated method for getting the collectors specifically. This provides better typing and `undefined`/`null` handling.
|
|
176
|
+
|
|
177
|
+
To dynamically render the collectors as UI, the intention is to have a component for each collector type. When receiving a `node` from DaVinci, you will iterate through the array of collectors.
|
|
178
|
+
|
|
179
|
+
#### SingleValueCollector
|
|
180
|
+
|
|
181
|
+
Upon each collector in the array, some will need an `updater`, like the collectors in the category of `SingleValueCollector`:
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
// Example SingleValueCollector using the TextCollector
|
|
185
|
+
const collectors = davinci.collectors();
|
|
186
|
+
collectors.map((collector) => {
|
|
187
|
+
if (collector.type === 'TextCollector') {
|
|
188
|
+
renderTextCollector(collector, davinci.update(collector));
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Here, you can see the passing of the collector object along with its `update` method and the current `collector` as its argument.
|
|
194
|
+
|
|
195
|
+
Then, in the collector component, you would have something like this:
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
function renderTextCollector(collector, updater) {
|
|
199
|
+
// ... component logic
|
|
200
|
+
|
|
201
|
+
function onClick(event) {
|
|
202
|
+
updater(event.target.value);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// render code
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
It's worth noting that directly mutating the `node` object, `collectors` or any other properties will not alter the DaVinci Client's internal state. Internal data stored in the client is immutable and can only be updated using the provided APIs, not through property assignment.
|
|
210
|
+
|
|
211
|
+
#### SubmitCollector
|
|
212
|
+
|
|
213
|
+
The `SubmitCollector` is associated with the submission of the current node and its collected values, requesting the next step in the flow. This collector does not have an update-like function. The collector is just for rendering a button.
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
// Example SubmitCollector mapping
|
|
217
|
+
const collectors = davinci.collectors();
|
|
218
|
+
collectors.map((collector) => {
|
|
219
|
+
if (collector.type === 'SubmitCollector') {
|
|
220
|
+
renderSubmitCollector(
|
|
221
|
+
collector, // This is the only argument you will need to pass
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
We will cover the associated action related to this collector in the next section: Continuing a DaVinci Flow below.
|
|
228
|
+
|
|
229
|
+
#### FlowCollector (Changing a DaVinci flow)
|
|
230
|
+
|
|
231
|
+
If a user selects an alternative flow button, like Reset Password or Registration. This action is associated with a `FlowCollector`, which instructs the application to change from the current flow and start a new, different flow.
|
|
232
|
+
|
|
233
|
+
To do this, you call the `flow` method on the `davinciClient` passing the `key` property to identify the new flow. This returns a function you can call when the user interacts with it.
|
|
234
|
+
|
|
235
|
+
```ts
|
|
236
|
+
// Example FlowCollector mapping
|
|
237
|
+
const collectors = davinci.collectors();
|
|
238
|
+
collectors.map((collector) => {
|
|
239
|
+
if (collector.type === 'FlowCollector') {
|
|
240
|
+
renderFlowCollector(collector, davinciClient.flow(collector));
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
```ts
|
|
246
|
+
// Example FlowCollector Component
|
|
247
|
+
function renderFlowCollector(collector, startFlow) {
|
|
248
|
+
// ... component logic
|
|
249
|
+
|
|
250
|
+
function onClick(event) {
|
|
251
|
+
startFlow();
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// render code
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Continuing a DaVinci flow
|
|
259
|
+
|
|
260
|
+
After collecting the needed data, you proceed to the next node in the DaVinci flow by calling the `.next()` method on the same `davinci` client object. This can be the result of a user clicking on the button rendered from the `SubmitCollector`, from the "submit" event of the HTML form itself, or from programmatically triggering the submission in the application layer.
|
|
261
|
+
|
|
262
|
+
```ts
|
|
263
|
+
let nextStep = davinci.next();
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Note: There's no need to pass anything into the `next` method as the DaVinci Client internally stores the updated object needed for the server.
|
|
267
|
+
|
|
268
|
+
Once the server responds, you will receive the same "node" that will be one of the four types discussed above. You will want to do the same conditional checks to render the appropriate UI.
|
|
269
|
+
|
|
270
|
+
#### Handling an error
|
|
271
|
+
|
|
272
|
+
An "error" in the DaVinci Client is caused by data that can be fixed and resubmitted. A few examples are an email value with an invalid format or a new password that is too short. This is different than a `failure`, which cannot be resubmitted; the flow has to be restarted (this will be covered later in this document).
|
|
273
|
+
|
|
274
|
+
When an error is received, hold on to the reference of the previous `node` as you'll need it to re-render the form. Use the previous `node` to render the form, and the `error` information on the new `ErrorNode`. Once the data has been revised, call `.next()` as you did before.
|
|
275
|
+
|
|
276
|
+
### A completed DaVinci Flow
|
|
277
|
+
|
|
278
|
+
Once a flow is complete, it is of type `success` or `failure` and cannot be continued. Success means you have completed the flow and have received or updated a session and, usually, you have received an Authorization Code to complete an OAuth flow to collect an Access Token.
|
|
279
|
+
|
|
280
|
+
#### Handling success
|
|
281
|
+
|
|
282
|
+
When you receive a success node, you will likely want to use the Authorization Code and other client data in order to complete an OAuth flow. To do this, you can pick the Authorization Code and State out of the client object and use them to call the `TokenManager.getTokens()` method from the JavaScript SDK.
|
|
283
|
+
|
|
284
|
+
Here's a brief sample of what that might look like in pseudocode:
|
|
285
|
+
|
|
286
|
+
```ts
|
|
287
|
+
// ... other imports
|
|
288
|
+
|
|
289
|
+
import { Config, TokenManager } from '@forgerock/javascript-sdk';
|
|
290
|
+
|
|
291
|
+
// ... other config or initialization code
|
|
292
|
+
|
|
293
|
+
// This Config.set accepts the same config schema as the davinci function
|
|
294
|
+
Config.set(config);
|
|
295
|
+
|
|
296
|
+
const node = await davinciClient.next();
|
|
297
|
+
|
|
298
|
+
if (node.status === 'success') {
|
|
299
|
+
const clientInfo = davinciClient.getClient();
|
|
300
|
+
|
|
301
|
+
const code = clientInfo.authorization?.code || '';
|
|
302
|
+
const state = clientInfo.authorization?.state || '';
|
|
303
|
+
|
|
304
|
+
const tokens = await TokenManager.getTokens({ query: { code, state } });
|
|
305
|
+
// user now has session and OIDC tokens
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
#### Handling a failure
|
|
310
|
+
|
|
311
|
+
If you receive a `FailureNode`, you will not be able to continue and must restart a new DaVinci flow. Some examples of failures are DaVinci flow timeouts due to inactivity or server failures like a `5xx` type server error.
|
|
312
|
+
|
|
313
|
+
Here's what this looks like in code:
|
|
314
|
+
|
|
315
|
+
```ts
|
|
316
|
+
const node = await davinciClient.next();
|
|
317
|
+
|
|
318
|
+
if (node.status === 'failure') {
|
|
319
|
+
const error = davinciClient.getError();
|
|
320
|
+
renderError(error);
|
|
321
|
+
|
|
322
|
+
// ... user clicks button to restart flow
|
|
323
|
+
const freshNode = davinciClient.start();
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### Contributing guidelines
|
|
328
|
+
|
|
329
|
+
If you'd like to contribute to this project, below are the internal dependencies, conventions and patterns used in the project. Please familiarize yourself with these guidelines and reach out if you have any questions.
|
|
330
|
+
|
|
331
|
+
#### Runtime dependencies
|
|
332
|
+
|
|
333
|
+
The only runtime-dependency within this project is [Redux Toolkit (aka RTK)](https://redux-toolkit.js.org/introduction/getting-started) and its optional package [RTK Query](https://redux-toolkit.js.org/rtk-query/overview). These libraries act as the core to the library's network request, caching and state management functionality. Redux Toolkit's only dependency is `immer`, which is what provides the immutability feature without loss of ergonomics.
|
|
334
|
+
|
|
335
|
+
Regardless of the use of RTK, this implementation detail is to not leak out into the Public API used by the customer. This public API will be a thin abstraction that sits between the customer and the RTK implementation.
|
|
336
|
+
|
|
337
|
+
We use RTK in the following ways:
|
|
338
|
+
|
|
339
|
+
1. Network query management: RTK Query
|
|
340
|
+
2. Cache management: RTK Query
|
|
341
|
+
3. Transformation logic: RTK Slice & Reducers
|
|
342
|
+
4. Object access and type narrowing: RTK Selectors
|
|
343
|
+
5. Immutable state management: Immer from within RTK
|
|
344
|
+
|
|
345
|
+
#### Developer dependency
|
|
346
|
+
|
|
347
|
+
The most important "compile-time" dependency is [TypeScript](typescriptlang.org). This assists in static code analysis and enforces types to help with code insights, autocomplete and assisted refactoring.
|
|
348
|
+
|
|
349
|
+
#### Conventions and patterns
|
|
350
|
+
|
|
351
|
+
1. "Query API": this pattern is responsible for network requests to an API; handle error, success and failures; as well as cache the original response.
|
|
352
|
+
2. "Slice": state slices represent "normalized" data that simplifies responses and derived data.
|
|
353
|
+
3. "Reducers": these are simple functions that are specific to the Redex "pattern", used to transform or "map" one source of data to a target source.
|
|
354
|
+
4. "Utils": these are pure functions that are library agnostic, side-effect free.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAEhD,OAAO,EAAE,OAAO,EAAE,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Define the options for the authorization URL
|
|
3
|
+
* @param clientId The client ID of the application
|
|
4
|
+
* @param redirectUri The redirect URI of the application
|
|
5
|
+
* @param responseType The response type of the authorization request
|
|
6
|
+
* @param scope The scope of the authorization request
|
|
7
|
+
*/
|
|
8
|
+
export interface GetAuthorizationUrlOptions {
|
|
9
|
+
clientId: string;
|
|
10
|
+
login: 'redirect';
|
|
11
|
+
redirectUri: string;
|
|
12
|
+
responseType: string;
|
|
13
|
+
scope: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* @function createAuthorizeUrl - Create authorization URL for initial call to DaVinci
|
|
17
|
+
* @param baseUrl {string}
|
|
18
|
+
* @param options {GetAuthorizationUrlOptions}
|
|
19
|
+
* @returns {Promise<string>} - the authorization URL
|
|
20
|
+
*/
|
|
21
|
+
export declare function createAuthorizeUrl(authorizeUrl: string, options: GetAuthorizationUrlOptions): Promise<string>;
|
|
22
|
+
//# sourceMappingURL=authorize.utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authorize.utils.d.ts","sourceRoot":"","sources":["../../src/lib/authorize.utils.ts"],"names":[],"mappings":"AAMA;;;;;;GAMG;AACH,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,UAAU,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,MAAM,CAAC,CA+BjB"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ResponseType as l, PKCE as a } from "@forgerock/javascript-sdk";
|
|
2
|
+
import { generateAndStoreAuthUrlValues as d } from "@forgerock/javascript-sdk/src/oauth2-client/state-pkce";
|
|
3
|
+
async function h(r, e) {
|
|
4
|
+
const n = new URL(r).origin, [t, o] = d({
|
|
5
|
+
clientId: e.clientId,
|
|
6
|
+
login: e.login,
|
|
7
|
+
serverConfig: { baseUrl: n },
|
|
8
|
+
responseType: l.Code
|
|
9
|
+
}), s = await a.createChallenge(t.verifier), c = new URLSearchParams({
|
|
10
|
+
code_challenge: s,
|
|
11
|
+
code_challenge_method: "S256",
|
|
12
|
+
client_id: e.clientId,
|
|
13
|
+
redirect_uri: e.redirectUri,
|
|
14
|
+
response_mode: "pi.flow",
|
|
15
|
+
response_type: e.responseType,
|
|
16
|
+
scope: e.scope,
|
|
17
|
+
state: t.state
|
|
18
|
+
}), i = new URL(`${r}?${c.toString()}`);
|
|
19
|
+
return o(), i.toString();
|
|
20
|
+
}
|
|
21
|
+
export {
|
|
22
|
+
h as createAuthorizeUrl
|
|
23
|
+
};
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { DaVinciConfig } from './config.types.js';
|
|
2
|
+
import { DaVinciAction, DaVinciRequest } from './davinci.types.js';
|
|
3
|
+
import { SingleValueCollectors } from './collector.types.js';
|
|
4
|
+
import { InitFlow, Updater } from './client.types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Create a client function that returns a set of methods
|
|
7
|
+
* to interact with and normalize the DaVinci API.
|
|
8
|
+
*
|
|
9
|
+
* @function davinciClient - returns an "observable" client for DaVinci flows
|
|
10
|
+
* @param {ConfigurationOptions} options - the configuration options for the client
|
|
11
|
+
* @returns {Observable} - an observable client for DaVinci flows
|
|
12
|
+
*/
|
|
13
|
+
export declare function davinci({ config }: {
|
|
14
|
+
config: DaVinciConfig;
|
|
15
|
+
}): Promise<{
|
|
16
|
+
subscribe: (listener: () => void) => import('@reduxjs/toolkit').Unsubscribe;
|
|
17
|
+
/**
|
|
18
|
+
* @method flow - Method for initiating a new flow, different than current flow
|
|
19
|
+
* @param {DaVinciAction} action - the action to initiate the flow
|
|
20
|
+
* @returns {function} - an async function to call the flow
|
|
21
|
+
*/
|
|
22
|
+
flow: (action: DaVinciAction) => InitFlow;
|
|
23
|
+
/**
|
|
24
|
+
* @method next - Method for initiating the next node in the current flow
|
|
25
|
+
* @param {DaVinciRequest} args - the arguments to pass to the next
|
|
26
|
+
* @returns {Promise} - a promise that resolves to the next node
|
|
27
|
+
*/
|
|
28
|
+
next: (args?: DaVinciRequest) => Promise<import('./node.types.js').ContinueNode | import('./node.types.js').ErrorNode | import('./node.types.js').FailureNode | import('./node.types.js').StartNode | import('./node.types.js').SuccessNode | {
|
|
29
|
+
error: string;
|
|
30
|
+
cache: null;
|
|
31
|
+
client: {
|
|
32
|
+
status: "start";
|
|
33
|
+
};
|
|
34
|
+
server: {
|
|
35
|
+
status: "start";
|
|
36
|
+
};
|
|
37
|
+
status: "start";
|
|
38
|
+
}>;
|
|
39
|
+
/**
|
|
40
|
+
* @method start - Method for initiating a DaVinci flow
|
|
41
|
+
* @returns {Promise} - a promise that initiates a DaVinci flow and returns a node
|
|
42
|
+
*/
|
|
43
|
+
start: () => Promise<import('./node.types.js').ContinueNode | import('./node.types.js').ErrorNode | import('./node.types.js').FailureNode | import('./node.types.js').StartNode | import('./node.types.js').SuccessNode>;
|
|
44
|
+
/**
|
|
45
|
+
* @method update - Exclusive method for updating the current node with user provided values
|
|
46
|
+
* @param {SingleValueCollector} collector - the collector to update
|
|
47
|
+
* @returns {function} - an function to call for updating collector value
|
|
48
|
+
*/
|
|
49
|
+
update: (collector: SingleValueCollectors) => Updater;
|
|
50
|
+
/**
|
|
51
|
+
* @method client - Selector to get the node.client from state
|
|
52
|
+
* @returns {Node.client} - the client property from the current node
|
|
53
|
+
*/
|
|
54
|
+
getClient: () => {
|
|
55
|
+
action: string;
|
|
56
|
+
collectors: import('./node.types.js').Collectors[];
|
|
57
|
+
description?: string;
|
|
58
|
+
name?: string;
|
|
59
|
+
status: "continue";
|
|
60
|
+
} | {
|
|
61
|
+
status: "error";
|
|
62
|
+
} | {
|
|
63
|
+
status: "failure";
|
|
64
|
+
} | {
|
|
65
|
+
status: "start";
|
|
66
|
+
} | {
|
|
67
|
+
authorization?: {
|
|
68
|
+
code?: string;
|
|
69
|
+
state?: string;
|
|
70
|
+
};
|
|
71
|
+
status: "success";
|
|
72
|
+
} | null;
|
|
73
|
+
/**
|
|
74
|
+
* @method collectors - Selector to get the collectors from state
|
|
75
|
+
* @returns {Collector[]} - The collectors from the current node in state
|
|
76
|
+
*/
|
|
77
|
+
getCollectors: () => import('./node.types.js').Collectors[];
|
|
78
|
+
getError: () => import('./node.types.js').DaVinciError | null;
|
|
79
|
+
/**
|
|
80
|
+
* @method node - Selector to get the node from state
|
|
81
|
+
* @returns {Node} - the current node from state
|
|
82
|
+
*/
|
|
83
|
+
getNode: () => import('./node.types.js').ContinueNode | import('./node.types.js').ErrorNode | import('./node.types.js').FailureNode | import('./node.types.js').StartNode | import('./node.types.js').SuccessNode;
|
|
84
|
+
/**
|
|
85
|
+
* @method server - Selector to get the node.server from state
|
|
86
|
+
* @returns {Node.server} - the server property from the current node
|
|
87
|
+
*/
|
|
88
|
+
getServer: () => {
|
|
89
|
+
_links?: import('./davinci.types.js').Links;
|
|
90
|
+
id?: string;
|
|
91
|
+
interactionId?: string;
|
|
92
|
+
interactionToken?: string;
|
|
93
|
+
href?: string;
|
|
94
|
+
eventName?: string;
|
|
95
|
+
status: "continue";
|
|
96
|
+
} | {
|
|
97
|
+
_links?: import('./davinci.types.js').Links;
|
|
98
|
+
eventName?: string;
|
|
99
|
+
id?: string;
|
|
100
|
+
interactionId?: string;
|
|
101
|
+
interactionToken?: string;
|
|
102
|
+
status: "error";
|
|
103
|
+
} | {
|
|
104
|
+
_links?: import('./davinci.types.js').Links;
|
|
105
|
+
eventName?: string;
|
|
106
|
+
href?: string;
|
|
107
|
+
id?: string;
|
|
108
|
+
interactionId?: string;
|
|
109
|
+
interactionToken?: string;
|
|
110
|
+
status: "failure";
|
|
111
|
+
} | {
|
|
112
|
+
status: "start";
|
|
113
|
+
} | {
|
|
114
|
+
_links?: import('./davinci.types.js').Links;
|
|
115
|
+
eventName?: string;
|
|
116
|
+
id?: string;
|
|
117
|
+
interactionId?: string;
|
|
118
|
+
interactionToken?: string;
|
|
119
|
+
href?: string;
|
|
120
|
+
session?: string;
|
|
121
|
+
status: "success";
|
|
122
|
+
} | null;
|
|
123
|
+
/**
|
|
124
|
+
* Utilities to help query cached responses from server
|
|
125
|
+
*/
|
|
126
|
+
cache: {
|
|
127
|
+
getLatestResponse: () => ((state: import('@reduxjs/toolkit/query').RootState<{
|
|
128
|
+
flow: import('@reduxjs/toolkit/query').MutationDefinition<any, import('@reduxjs/toolkit/query').BaseQueryFn<string | import('@reduxjs/toolkit/query').FetchArgs, unknown, import('@reduxjs/toolkit/query').FetchBaseQueryError, {}, import('@reduxjs/toolkit/query').FetchBaseQueryMeta>, never, unknown, "davinci">;
|
|
129
|
+
next: import('@reduxjs/toolkit/query').MutationDefinition<any, import('@reduxjs/toolkit/query').BaseQueryFn<string | import('@reduxjs/toolkit/query').FetchArgs, unknown, import('@reduxjs/toolkit/query').FetchBaseQueryError, {}, import('@reduxjs/toolkit/query').FetchBaseQueryMeta>, never, unknown, "davinci">;
|
|
130
|
+
start: import('@reduxjs/toolkit/query').MutationDefinition<void, import('@reduxjs/toolkit/query').BaseQueryFn<string | import('@reduxjs/toolkit/query').FetchArgs, unknown, import('@reduxjs/toolkit/query').FetchBaseQueryError, {}, import('@reduxjs/toolkit/query').FetchBaseQueryMeta>, never, unknown, "davinci">;
|
|
131
|
+
}, never, "davinci">) => import('@reduxjs/toolkit/query').MutationResultSelectorResult<import('@reduxjs/toolkit/query').MutationDefinition<any, import('@reduxjs/toolkit/query').BaseQueryFn<string | import('@reduxjs/toolkit/query').FetchArgs, unknown, import('@reduxjs/toolkit/query').FetchBaseQueryError, {}, import('@reduxjs/toolkit/query').FetchBaseQueryMeta>, never, unknown, "davinci">>) | {
|
|
132
|
+
error: {
|
|
133
|
+
message: string;
|
|
134
|
+
type: string;
|
|
135
|
+
};
|
|
136
|
+
};
|
|
137
|
+
getResponseWithId: (requestId: string) => ((state: import('@reduxjs/toolkit/query').RootState<{
|
|
138
|
+
flow: import('@reduxjs/toolkit/query').MutationDefinition<any, import('@reduxjs/toolkit/query').BaseQueryFn<string | import('@reduxjs/toolkit/query').FetchArgs, unknown, import('@reduxjs/toolkit/query').FetchBaseQueryError, {}, import('@reduxjs/toolkit/query').FetchBaseQueryMeta>, never, unknown, "davinci">;
|
|
139
|
+
next: import('@reduxjs/toolkit/query').MutationDefinition<any, import('@reduxjs/toolkit/query').BaseQueryFn<string | import('@reduxjs/toolkit/query').FetchArgs, unknown, import('@reduxjs/toolkit/query').FetchBaseQueryError, {}, import('@reduxjs/toolkit/query').FetchBaseQueryMeta>, never, unknown, "davinci">;
|
|
140
|
+
start: import('@reduxjs/toolkit/query').MutationDefinition<void, import('@reduxjs/toolkit/query').BaseQueryFn<string | import('@reduxjs/toolkit/query').FetchArgs, unknown, import('@reduxjs/toolkit/query').FetchBaseQueryError, {}, import('@reduxjs/toolkit/query').FetchBaseQueryMeta>, never, unknown, "davinci">;
|
|
141
|
+
}, never, "davinci">) => import('@reduxjs/toolkit/query').MutationResultSelectorResult<import('@reduxjs/toolkit/query').MutationDefinition<any, import('@reduxjs/toolkit/query').BaseQueryFn<string | import('@reduxjs/toolkit/query').FetchArgs, unknown, import('@reduxjs/toolkit/query').FetchBaseQueryError, {}, import('@reduxjs/toolkit/query').FetchBaseQueryMeta>, never, unknown, "davinci">>) | {
|
|
142
|
+
error: {
|
|
143
|
+
message: string;
|
|
144
|
+
type: string;
|
|
145
|
+
};
|
|
146
|
+
};
|
|
147
|
+
};
|
|
148
|
+
}>;
|
|
149
|
+
//# sourceMappingURL=client.store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.store.d.ts","sourceRoot":"","sources":["../../src/lib/client.store.ts"],"names":[],"mappings":"AASA;;GAEG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAE3D;;;;;;;GAOG;AACH,wBAAsB,OAAO,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,aAAa,CAAA;CAAE;;IAyB/D;;;;OAIG;mBACY,aAAa,KAAG,QAAQ;IAevC;;;;OAIG;kBACiB,cAAc;;;;;;;;;;;IAclC;;;OAGG;;IAMH;;;;OAIG;wBACiB,qBAAqB,KAAG,OAAO;IA6CnD;;;OAGG;;;;;;;;;;;;;;;gBA9FgB,CAAC;iBAAqB,CAAC;;;;IAiG1C;;;OAGG;;;IAiBH;;;OAGG;;IAKH;;;OAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAMH;;OAEG;;;;;;;;;;;;uCAgB8B,MAAM;;;;;;;;;;;GAc1C"}
|