(
input: RegisterDynamicClientInput,
options: DiscoveryRequestOptions = {},
)
| 540 | }; |
| 541 | |
| 542 | export const registerDynamicClient = ( |
| 543 | input: RegisterDynamicClientInput, |
| 544 | options: DiscoveryRequestOptions = {}, |
| 545 | ): Effect.Effect<OAuthClientInformation, OAuthDiscoveryError> => |
| 546 | Effect.gen(function* () { |
| 547 | yield* validateEndpointUrl( |
| 548 | input.registrationEndpoint, |
| 549 | "registration_endpoint", |
| 550 | options.endpointUrlPolicy, |
| 551 | ).pipe( |
| 552 | Effect.mapError( |
| 553 | (cause) => |
| 554 | new DcrTransport({ |
| 555 | detail: "registration_endpoint must use https: or loopback http:", |
| 556 | cause, |
| 557 | }), |
| 558 | ), |
| 559 | ); |
| 560 | |
| 561 | const headers: Record<string, string> = { |
| 562 | "content-type": "application/json", |
| 563 | accept: "application/json", |
| 564 | }; |
| 565 | if (input.initialAccessToken) { |
| 566 | headers.authorization = `Bearer ${input.initialAccessToken}`; |
| 567 | } |
| 568 | |
| 569 | let request = HttpClientRequest.post(input.registrationEndpoint).pipe( |
| 570 | HttpClientRequest.bodyJsonUnsafe(buildDcrBody(input.metadata)), |
| 571 | ); |
| 572 | for (const [name, value] of Object.entries(headers)) { |
| 573 | request = HttpClientRequest.setHeader(request, name, value); |
| 574 | } |
| 575 | |
| 576 | const response = yield* executeText( |
| 577 | request, |
| 578 | options, |
| 579 | "Dynamic Client Registration request failed", |
| 580 | ).pipe( |
| 581 | Effect.mapError( |
| 582 | (cause) => |
| 583 | new DcrTransport({ |
| 584 | detail: "Dynamic Client Registration request failed", |
| 585 | cause, |
| 586 | }), |
| 587 | ), |
| 588 | ); |
| 589 | |
| 590 | // Accept both 200 and 201 as success — RFC 7591 mandates 201, but |
| 591 | // Todoist (and others) return 200 OK with the client information body. |
| 592 | if (response.status !== 200 && response.status !== 201) { |
| 593 | return yield* interpretDcrFailure(response.status, response.body); |
| 594 | } |
| 595 | |
| 596 | return yield* decodeClientInformationJson(response.body).pipe( |
| 597 | Effect.mapError( |
| 598 | (err) => |
| 599 | new OAuthDiscoveryError({ |
no test coverage detected