From d9de3f1da7ad3cae880bd74a2b8446dd9d62b4ef Mon Sep 17 00:00:00 2001 From: Brian Muller Date: Fri, 26 Apr 2024 13:02:11 -0400 Subject: [PATCH] Update TS types (#23) * Update TS types * make the linter happy * Added misssing fields to the LoginOptions type * add typecheck to github actions * remove unecessary path updates * remove optional only installation in GA --- .github/workflows/ci.yml | 4 +- package.json | 3 +- packages/react/src/__tests__/index-test.js | 1 + packages/react/src/index.tsx | 25 +------ packages/react/src/profile_api_types.ts | 36 ---------- packages/vanilla/src/__tests__/index-test.ts | 13 ++-- packages/vanilla/src/common_api_types.ts | 29 -------- packages/vanilla/src/index.ts | 1 - packages/vanilla/src/types.ts | 74 ++++++++++++++++---- 9 files changed, 75 insertions(+), 111 deletions(-) delete mode 100644 packages/react/src/profile_api_types.ts delete mode 100644 packages/vanilla/src/common_api_types.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e68e9dc..c79d61c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,6 +17,8 @@ jobs: with: node-version: ${{ env.NODE_VERSION }} cache: pnpm - - run: pnpm install --no-optional + - run: pnpm install - run: pnpm lint - run: pnpm test + - run: pnpm build + - run: pnpm typecheck diff --git a/package.json b/package.json index 5b276a3..2dff5b8 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,8 @@ "scripts": { "build": "pnpm --filter '@parallelmarkets/*' build", "lint": "pnpm -r lint", - "test": "pnpm -r test" + "test": "pnpm -r test", + "typecheck": "pnpm -r typecheck" }, "keywords": [ "ParallelMarkets" diff --git a/packages/react/src/__tests__/index-test.js b/packages/react/src/__tests__/index-test.js index bc83d46..8001754 100644 --- a/packages/react/src/__tests__/index-test.js +++ b/packages/react/src/__tests__/index-test.js @@ -5,6 +5,7 @@ import React from 'react' import { ParallelProvider, PassportButton } from '../index' const ParallelMock = { + getProfile: (cb, _eb) => cb({}), getLoginStatus: (cb) => cb({}), subscribe: () => null, unsubscribe: () => null, diff --git a/packages/react/src/index.tsx b/packages/react/src/index.tsx index df8d36d..95a4ec1 100644 --- a/packages/react/src/index.tsx +++ b/packages/react/src/index.tsx @@ -1,11 +1,8 @@ import React, { PropsWithChildren, createContext, useContext, useEffect, useState } from 'react' import ButtonImg from './medium-passport-button.svg' -import { ParallelApiRecord, loadParallel } from '@parallelmarkets/vanilla' -import type { AuthCallbackResult, Parallel } from '@parallelmarkets/vanilla' -import { ProfileApiResponse } from './profile_api_types' - -export * from './profile_api_types' +import { loadParallel } from '@parallelmarkets/vanilla' +import type { AuthCallbackResult, ProfileApiResponse } from '@parallelmarkets/vanilla' type LoadParallelPromise = ReturnType type LoadParallelResult = Awaited> @@ -29,22 +26,6 @@ const isPromise = (thing: unknown): thing is PromiseLike => { return typeof (thing as PromiseLike)?.then === 'function' } -// The Embed API works with callback functions. This wrapper converts them to promises. -const promisifyApiCall = (parallel: Parallel, endpoint: string) => { - return () => { - // This promise resolves with the type of the API's Success Callback function's first Parameter - return new Promise((resolve, reject) => { - parallel.api( - endpoint, - (result) => { - resolve(result as ResultType) - }, - reject, - ) - }) - } -} - export const useParallel = () => { const { parallel: parallelPromise } = useContext(ParallelContext) const [parallel, setParallel] = useState(null) @@ -104,7 +85,7 @@ export const useParallel = () => { parallel, error, loginStatus, - getProfile: promisifyApiCall(parallel, '/profile'), + getProfile: new Promise(parallel.getProfile), login: parallel.login, logout: parallel.logout, } diff --git a/packages/react/src/profile_api_types.ts b/packages/react/src/profile_api_types.ts deleted file mode 100644 index ac2dc20..0000000 --- a/packages/react/src/profile_api_types.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { type BusinessType } from '@parallelmarkets/vanilla' - -// https://developer.parallelmarkets.com/docs/server/profile-api - -export type IndividualProfile = { - email: string | null - first_name: string - last_name: string -} - -export type BusinessProfile = { - name: string - business_type: BusinessType - primary_contact: IndividualProfile | null -} - -export type ProfileApiBaseResponse = { - id: string - user_id: string - user_profile: IndividualProfile - user_providing_for: 'self' | 'controlled-business' | 'other-individual' - access_expires_at: string | null - access_revoked_by: 'subject' | 'partner' | 'system' | null -} - -type ProfileApiIndividualResponse = ProfileApiBaseResponse & { - type: 'individual' - profile: IndividualProfile -} - -type ProfileApiBusinessResponse = ProfileApiBaseResponse & { - type: 'business' - profile: BusinessProfile -} - -export type ProfileApiResponse = ProfileApiIndividualResponse | ProfileApiBusinessResponse diff --git a/packages/vanilla/src/__tests__/index-test.ts b/packages/vanilla/src/__tests__/index-test.ts index eb1e4dd..e52e315 100644 --- a/packages/vanilla/src/__tests__/index-test.ts +++ b/packages/vanilla/src/__tests__/index-test.ts @@ -9,22 +9,23 @@ declare global { } global.window.Parallel = { - get _config() { - return window.config - }, init: ({ on_init, ...params }: ParallelConfig) => { window.config = params on_init?.() }, - api: () => null, + getLoginStatus: () => null, + getProfile: () => null, login: () => null, logout: () => null, + unsubscribe: () => null, subscribe: () => null, showButton: () => null, hideButton: () => null, - unsubscribe: () => null, - getLoginStatus: () => null, subscribeWithButton: () => null, + _appendLoadContext: () => null, + get _config() { + return window.config + }, } test('Configuration is set correctly', async () => { diff --git a/packages/vanilla/src/common_api_types.ts b/packages/vanilla/src/common_api_types.ts deleted file mode 100644 index 7154983..0000000 --- a/packages/vanilla/src/common_api_types.ts +++ /dev/null @@ -1,29 +0,0 @@ -export type EntityKind = 'individual' | 'business' - -export type Location = { - address_one: string - address_two: string | null - city: string - region: string | null - postal_code: string - state: string | null - country: string -} - -export type UserSession = { - maybe_anonymizing_proxy: boolean - country_code: string | null - region: string | null - city: string | null -} - -export type BusinessType = - | 'Public Charity' - | 'Private Foundation' - | 'S Corporation' - | 'C Corporation' - | 'Irrevocable Trust' - | 'Revocable Trust' - | 'Family Office' - | 'Limited Liability Company' - | 'Limited Partnership' diff --git a/packages/vanilla/src/index.ts b/packages/vanilla/src/index.ts index 936ce9c..d773bc2 100644 --- a/packages/vanilla/src/index.ts +++ b/packages/vanilla/src/index.ts @@ -1,7 +1,6 @@ import { Parallel, ParallelConfig } from './types' export * from './types' -export * from './common_api_types' const V2_URL = 'https://app.parallelmarkets.com/sdk/v2/parallel.js' let parallelPromise: Promise | undefined diff --git a/packages/vanilla/src/types.ts b/packages/vanilla/src/types.ts index ffea1a9..68376b1 100644 --- a/packages/vanilla/src/types.ts +++ b/packages/vanilla/src/types.ts @@ -1,4 +1,15 @@ -import { type BusinessType } from './common_api_types' +export type EntityKind = 'individual' | 'business' + +export type BusinessType = + | 'Public Charity' + | 'Private Foundation' + | 'S Corporation' + | 'C Corporation' + | 'Irrevocable Trust' + | 'Revocable Trust' + | 'Family Office' + | 'Limited Liability Company' + | 'Limited Partnership' /* eslint-disable @typescript-eslint/no-explicit-any */ type AuthResponse = { @@ -16,17 +27,19 @@ export type AuthCallbackResult = { errorDescription?: string } -// https://developer.parallelmarkets.com/docs/server/scopes -export type ParallelScope = 'profile' | 'accreditation_status' | 'identity' | 'blockchain' +// https://developer.parallelmarkets.com/docs/javascript/configuration#scopes +export type ParallelScope = 'profile' | 'accreditation_status' | 'identity' // https://developer.parallelmarkets.com/docs/javascript/configuration type EmbedParallelConfig = { flow_type: 'embed' embed_into_id: string } + type OverlayRedirectParallelConfig = { flow_type: 'overlay' | 'redirect' } + export type ParallelConfig = (EmbedParallelConfig | OverlayRedirectParallelConfig) & { client_id?: string environment?: 'production' | 'demo' @@ -40,21 +53,47 @@ export type ParallelConfig = (EmbedParallelConfig | OverlayRedirectParallelConfi raw_config?: Record } +export type IndividualProfile = { + email: string + first_name: string + last_name: string +} + +export type BusinessProfile = { + name: string + business_type: BusinessType + primary_contact: IndividualProfile +} + +export type ProfileApiResponse = { + id: string + type: EntityKind + profile: IndividualProfile | BusinessProfile + user_id: string + user_profile: IndividualProfile + user_providing_for: 'self' | 'controlled-business' | 'other-individual' + access_expires_at: string | null + access_revoked_by: 'subject' | 'partner' | 'system' | null + available_scopes: Array +} + +type GetProfileSuccessCallbackFunc = (_result: ProfileApiResponse) => void + +type GetProfileFailureCallbackFunc = (_result: { error: unknown }) => void + type AuthSuccessCallbackFunc = (_result: AuthCallbackResult) => void -type AuthFailureCallbackFunc = (_result: { error: unknown }) => void -// TODO: implement this -export type ParallelApiRecord = Record -export type ParallelApiSuccessCallback = (_response: ParallelApiRecord) => void -export type ParallelApiErrorCallback = (_reason: any) => void +type AuthFailureCallbackFunc = (_result: { error: unknown }) => void type SubscribeEvents = 'auth.login' | 'auth.logout' | 'auth.statusChange' | 'auth.authResponseChange' + type OAuthErrorCode = | 'invalid_request' | 'invalid_client' | 'invalid_grant' | 'unauthorized_client' | 'unsupported_grant_type' + type SubscriptionEvent = { status: 'not_authorized' | 'unknown' | 'connected' error?: OAuthErrorCode @@ -67,37 +106,42 @@ type SubscriptionEvent = { refresh_expires_in: number } } + type SubscriptionHandler = (_response: SubscriptionEvent) => void export interface LoginOptions { email?: string first_name?: string last_name?: string + external_id?: string expected_entity_id?: string expected_entity_type?: 'self' | BusinessType expected_business_name?: string partner_supporting?: string + ref_code?: string + redirect_uri_signature?: string + required_entity_id?: string } export interface Parallel { init(_options: ParallelConfig): void - _config: ParallelConfig + getLoginStatus: (_callback: AuthSuccessCallbackFunc) => void + getProfile: (_successFunc: GetProfileSuccessCallbackFunc, _errorFunc: GetProfileFailureCallbackFunc) => void login: (_options?: LoginOptions) => void logout: () => void - subscribeWithButton: (_successFunc: AuthSuccessCallbackFunc, _errorFunc: AuthFailureCallbackFunc) => void + unsubscribe: (_event: SubscribeEvents, _callback: SubscriptionHandler) => void + subscribe: (_event: SubscribeEvents, _callback: SubscriptionHandler) => void showButton: () => void hideButton: () => void - api: (_endpoint: string, _callback: ParallelApiSuccessCallback, _errback: ParallelApiErrorCallback) => void - subscribe: (_event: SubscribeEvents, _callback: SubscriptionHandler) => void - unsubscribe: (_event: SubscribeEvents, _callback: SubscriptionHandler) => void - getLoginStatus: (_callback: AuthSuccessCallbackFunc) => void + subscribeWithButton: (_successFunc: AuthSuccessCallbackFunc, _errorFunc: AuthFailureCallbackFunc) => void _appendLoadContext: (_context: string) => void + _config: ParallelConfig } declare global { interface Window { // parallel.js must be loaded directly from app.parallelmarkets.com/sdk/v2/parallel.js - // which places a `Paralell` object at the window level + // which places a `Parallel` object at the window level Parallel?: Parallel } }