From 08da4dcd58c837a2c56d4799e1545fe122b7a0f9 Mon Sep 17 00:00:00 2001 From: Filipp Sher Date: Mon, 16 Sep 2024 17:59:06 +0300 Subject: [PATCH] Feature/split ext code (#22) * chore: implement monorepo * feat: refactor interfaces in blinks-core and blinks packages, adjust naming, extend imports * chore: minor cleanup * chore: after merge fixes and adjustments * chore: addressing PR comments, move stylePreset to blinks package (rename to theme) * docs: update readme with updated prop * chore: rename theme to stylePreset to avoid breaking change * docs: revert docs --- bun.lockb | Bin 387336 -> 389296 bytes package.json | 59 +--- packages/blinks-core/package.json | 56 ++++ .../blinks-core/src/BlinkContainer.tsx | 273 ++++++------------ .../blinks-core/src}/api/Action/Action.ts | 4 +- .../AbstractActionComponent.ts | 2 +- .../ButtonActionComponent.ts | 0 .../action-components/FormActionComponent.ts | 0 .../MultiValueActionComponent.ts | 0 .../SingleValueActionComponent.ts | 0 .../api/Action/action-components/guards.ts | 0 .../api/Action/action-components/index.ts | 0 .../src}/api/Action/action-supportability.ts | 0 .../blinks-core/src}/api/Action/index.ts | 0 .../blinks-core/src}/api/ActionCallbacks.ts | 0 .../blinks-core/src}/api/ActionConfig.ts | 8 +- .../blinks-core/src}/api/ActionsRegistry.ts | 12 +- .../blinks-core/src}/api/actions-spec.ts | 0 .../blinks-core/src}/api/index.ts | 0 .../blinks-core/src}/api/solana-pay-spec.ts | 0 packages/blinks-core/src/index.ts | 3 + .../blinks-core/src}/utils/caip-2.ts | 0 .../blinks-core/src}/utils/constants.ts | 1 - .../src}/utils/dependency-versions.ts | 0 packages/blinks-core/src/utils/index.ts | 5 + .../src}/utils/interstitial-url.ts | 0 .../blinks-core/src}/utils/proxify.ts | 0 .../blinks-core/src/utils}/security.ts | 4 +- .../blinks-core/src}/utils/type-guards.ts | 0 .../blinks-core/src}/utils/url-mapper.ts | 0 .../api/Action/action-supportability.spec.ts | 0 .../test}/api/action-registry.spec.ts | 5 +- .../test}/utils/dependency-versions.spec.ts | 0 .../test}/utils/interstitial-url.spec.ts | 2 +- .../test}/utils/url-mapper.spec.ts | 5 +- packages/blinks-core/tsconfig.json | 27 ++ packages/blinks-core/tsup.config.ts | 19 ++ packages/blinks/package.json | 76 +++++ {src => packages/blinks/src}/ext/index.ts | 0 {src => packages/blinks/src}/ext/twitter.tsx | 21 +- {src => packages/blinks/src}/hooks/index.ts | 0 .../blinks/src}/hooks/solana/index.ts | 0 .../solana/useActionSolanaWalletAdapter.ts | 2 +- .../blinks/src}/hooks/useAction.ts | 8 +- .../src}/hooks/useActionRegistryInterval.ts | 2 +- {src => packages/blinks/src}/index.css | 0 packages/blinks/src/index.ts | 3 + .../blinks/src/ui/BaseBlinkLayout.tsx | 99 +++---- packages/blinks/src/ui/Blink.tsx | 37 +++ packages/blinks/src/ui/index.ts | 2 + .../blinks/src/ui/internal}/Badge.tsx | 0 .../blinks/src/ui/internal}/Button.tsx | 0 .../blinks/src/ui/internal}/Checkbox.tsx | 0 .../blinks/src/ui/internal}/Radio.tsx | 0 .../blinks/src/ui/internal}/Snackbar.tsx | 0 .../hooks/useLayoutPropNormalizer.tsx | 146 ++++++++++ .../src/ui/internal}/icons/CalendarIcon.tsx | 0 .../src/ui/internal}/icons/CheckIcon.tsx | 0 .../ui/internal}/icons/CheckboxCheckIcon.tsx | 0 .../src/ui/internal}/icons/ConfigIcon.tsx | 3 +- .../src/ui/internal}/icons/EmailIcon.tsx | 0 .../internal}/icons/ExclamationShieldIcon.tsx | 0 .../src/ui/internal}/icons/InfoShieldIcon.tsx | 0 .../src/ui/internal}/icons/LinkIcon.tsx | 0 .../src/ui/internal}/icons/NumberIcon.tsx | 0 .../src/ui/internal}/icons/SpinnerDots.tsx | 0 .../blinks/src/ui/internal}/icons/index.ts | 1 + .../src/ui/internal}/inputs/ActionButton.tsx | 0 .../internal}/inputs/ActionCheckboxGroup.tsx | 0 .../ui/internal}/inputs/ActionDateInput.tsx | 0 .../ui/internal}/inputs/ActionEmailInput.tsx | 0 .../ui/internal}/inputs/ActionNumberInput.tsx | 0 .../ui/internal}/inputs/ActionRadioGroup.tsx | 0 .../src/ui/internal}/inputs/ActionSelect.tsx | 0 .../ui/internal}/inputs/ActionTextArea.tsx | 0 .../ui/internal}/inputs/ActionTextInput.tsx | 0 .../ui/internal}/inputs/ActionUrlInput.tsx | 0 .../internal}/inputs/BaseInputContainer.tsx | 0 .../blinks/src/ui/internal}/inputs/index.ts | 2 + .../blinks/src/ui/internal}/inputs/types.ts | 2 +- .../blinks/src/ui/internal}/inputs/utils.ts | 0 packages/blinks/src/ui/types.ts | 1 + .../blinks/tailwind.config.js | 0 .../blinks/tsconfig.json | 0 .../blinks/tsup.config.ts | 0 src/index.ts | 5 - src/shared/index.ts | 1 - src/ui/index.ts | 2 - src/utils/index.ts | 2 - 89 files changed, 566 insertions(+), 334 deletions(-) create mode 100644 packages/blinks-core/package.json rename src/ui/ActionContainer.tsx => packages/blinks-core/src/BlinkContainer.tsx (70%) rename {src => packages/blinks-core/src}/api/Action/Action.ts (98%) rename {src => packages/blinks-core/src}/api/Action/action-components/AbstractActionComponent.ts (96%) rename {src => packages/blinks-core/src}/api/Action/action-components/ButtonActionComponent.ts (100%) rename {src => packages/blinks-core/src}/api/Action/action-components/FormActionComponent.ts (100%) rename {src => packages/blinks-core/src}/api/Action/action-components/MultiValueActionComponent.ts (100%) rename {src => packages/blinks-core/src}/api/Action/action-components/SingleValueActionComponent.ts (100%) rename {src => packages/blinks-core/src}/api/Action/action-components/guards.ts (100%) rename {src => packages/blinks-core/src}/api/Action/action-components/index.ts (100%) rename {src => packages/blinks-core/src}/api/Action/action-supportability.ts (100%) rename {src => packages/blinks-core/src}/api/Action/index.ts (100%) rename {src => packages/blinks-core/src}/api/ActionCallbacks.ts (100%) rename {src => packages/blinks-core/src}/api/ActionConfig.ts (94%) rename {src => packages/blinks-core/src}/api/ActionsRegistry.ts (95%) rename {src => packages/blinks-core/src}/api/actions-spec.ts (100%) rename {src => packages/blinks-core/src}/api/index.ts (100%) rename {src => packages/blinks-core/src}/api/solana-pay-spec.ts (100%) create mode 100644 packages/blinks-core/src/index.ts rename {src => packages/blinks-core/src}/utils/caip-2.ts (100%) rename {src => packages/blinks-core/src}/utils/constants.ts (68%) rename {src => packages/blinks-core/src}/utils/dependency-versions.ts (100%) create mode 100644 packages/blinks-core/src/utils/index.ts rename {src => packages/blinks-core/src}/utils/interstitial-url.ts (100%) rename {src => packages/blinks-core/src}/utils/proxify.ts (100%) rename {src/shared => packages/blinks-core/src/utils}/security.ts (86%) rename {src => packages/blinks-core/src}/utils/type-guards.ts (100%) rename {src => packages/blinks-core/src}/utils/url-mapper.ts (100%) rename {test => packages/blinks-core/test}/api/Action/action-supportability.spec.ts (100%) rename {test => packages/blinks-core/test}/api/action-registry.spec.ts (98%) rename {test => packages/blinks-core/test}/utils/dependency-versions.spec.ts (100%) rename {test => packages/blinks-core/test}/utils/interstitial-url.spec.ts (98%) rename {test => packages/blinks-core/test}/utils/url-mapper.spec.ts (99%) create mode 100644 packages/blinks-core/tsconfig.json create mode 100644 packages/blinks-core/tsup.config.ts create mode 100644 packages/blinks/package.json rename {src => packages/blinks/src}/ext/index.ts (100%) rename {src => packages/blinks/src}/ext/twitter.tsx (95%) rename {src => packages/blinks/src}/hooks/index.ts (100%) rename {src => packages/blinks/src}/hooks/solana/index.ts (100%) rename {src => packages/blinks/src}/hooks/solana/useActionSolanaWalletAdapter.ts (96%) rename {src => packages/blinks/src}/hooks/useAction.ts (94%) rename {src => packages/blinks/src}/hooks/useActionRegistryInterval.ts (85%) rename {src => packages/blinks/src}/index.css (100%) create mode 100644 packages/blinks/src/index.ts rename src/ui/ActionLayout.tsx => packages/blinks/src/ui/BaseBlinkLayout.tsx (78%) create mode 100644 packages/blinks/src/ui/Blink.tsx create mode 100644 packages/blinks/src/ui/index.ts rename {src/ui => packages/blinks/src/ui/internal}/Badge.tsx (100%) rename {src/ui => packages/blinks/src/ui/internal}/Button.tsx (100%) rename {src/ui => packages/blinks/src/ui/internal}/Checkbox.tsx (100%) rename {src/ui => packages/blinks/src/ui/internal}/Radio.tsx (100%) rename {src/ui => packages/blinks/src/ui/internal}/Snackbar.tsx (100%) create mode 100644 packages/blinks/src/ui/internal/hooks/useLayoutPropNormalizer.tsx rename {src/ui => packages/blinks/src/ui/internal}/icons/CalendarIcon.tsx (100%) rename {src/ui => packages/blinks/src/ui/internal}/icons/CheckIcon.tsx (100%) rename {src/ui => packages/blinks/src/ui/internal}/icons/CheckboxCheckIcon.tsx (100%) rename {src/ui => packages/blinks/src/ui/internal}/icons/ConfigIcon.tsx (95%) rename {src/ui => packages/blinks/src/ui/internal}/icons/EmailIcon.tsx (100%) rename {src/ui => packages/blinks/src/ui/internal}/icons/ExclamationShieldIcon.tsx (100%) rename {src/ui => packages/blinks/src/ui/internal}/icons/InfoShieldIcon.tsx (100%) rename {src/ui => packages/blinks/src/ui/internal}/icons/LinkIcon.tsx (100%) rename {src/ui => packages/blinks/src/ui/internal}/icons/NumberIcon.tsx (100%) rename {src/ui => packages/blinks/src/ui/internal}/icons/SpinnerDots.tsx (100%) rename {src/ui => packages/blinks/src/ui/internal}/icons/index.ts (84%) rename {src/ui => packages/blinks/src/ui/internal}/inputs/ActionButton.tsx (100%) rename {src/ui => packages/blinks/src/ui/internal}/inputs/ActionCheckboxGroup.tsx (100%) rename {src/ui => packages/blinks/src/ui/internal}/inputs/ActionDateInput.tsx (100%) rename {src/ui => packages/blinks/src/ui/internal}/inputs/ActionEmailInput.tsx (100%) rename {src/ui => packages/blinks/src/ui/internal}/inputs/ActionNumberInput.tsx (100%) rename {src/ui => packages/blinks/src/ui/internal}/inputs/ActionRadioGroup.tsx (100%) rename {src/ui => packages/blinks/src/ui/internal}/inputs/ActionSelect.tsx (100%) rename {src/ui => packages/blinks/src/ui/internal}/inputs/ActionTextArea.tsx (100%) rename {src/ui => packages/blinks/src/ui/internal}/inputs/ActionTextInput.tsx (100%) rename {src/ui => packages/blinks/src/ui/internal}/inputs/ActionUrlInput.tsx (100%) rename {src/ui => packages/blinks/src/ui/internal}/inputs/BaseInputContainer.tsx (100%) rename {src/ui => packages/blinks/src/ui/internal}/inputs/index.ts (79%) rename {src/ui => packages/blinks/src/ui/internal}/inputs/types.ts (95%) rename {src/ui => packages/blinks/src/ui/internal}/inputs/utils.ts (100%) create mode 100644 packages/blinks/src/ui/types.ts rename tailwind.config.js => packages/blinks/tailwind.config.js (100%) rename tsconfig.json => packages/blinks/tsconfig.json (100%) rename tsup.config.ts => packages/blinks/tsup.config.ts (100%) delete mode 100644 src/index.ts delete mode 100644 src/shared/index.ts delete mode 100644 src/ui/index.ts delete mode 100644 src/utils/index.ts diff --git a/bun.lockb b/bun.lockb index a1b65beeb86f2baf5695f38798a9bda6861e599b..5bc6c495e78f9f5173defef0e78ab41aac62abe3 100755 GIT binary patch delta 80333 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%0DWMK6yu`9-D7S@I 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≠%R=W);q%V@l&mAgq7b<#mjpcKeg6V^HRe# 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%0D-uPej5WiBg5uM+Cn;UEL+I4i`3p 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", - "react-dom": ">=18" - }, - "dependencies": { - "clsx": "^2.1.1", - "nanoid": "^5.0.7" } } diff --git a/packages/blinks-core/package.json b/packages/blinks-core/package.json new file mode 100644 index 00000000..7c1e4075 --- /dev/null +++ b/packages/blinks-core/package.json @@ -0,0 +1,56 @@ +{ + "name": "@dialectlabs/blinks-core", + "version": "0.10.0", + "license": "Apache-2.0", + "private": false, + "sideEffects": true, + "type": "module", + "repository": { + "type": "git", + "url": "https://github.com/dialectlabs/blinks" + }, + "scripts": { + "build": "tsup-node", + "dev": "tsup-node --watch" + }, + "main": "dist/index.cjs", + "module": "dist/index.js", + "types": "dist/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.js", + "require": "./dist/index.cjs", + "types": "./dist/index.d.ts" + } + }, + "files": [ + "dist" + ], + "devDependencies": { + "@solana/actions-spec": "~2.2.0", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@typescript-eslint/eslint-plugin": "^7.16.1", + "@typescript-eslint/parser": "^7.16.1", + "autoprefixer": "^10.4.19", + "eslint": "^8.57.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-react": "^7.34.4", + "eslint-plugin-react-hooks": "^4.6.2", + "postcss": "^8.4.39", + "postcss-prefix-selector": "^1.16.1", + "prettier": "^3.3.3", + "prettier-plugin-organize-imports": "^4.0.0", + "prettier-plugin-tailwindcss": "^0.6.5", + "tailwindcss": "^3.4.3", + "tsup": "^8.2.0", + "typescript": "^5.5.3" + }, + "peerDependencies": { + "react": ">=18" + }, + "dependencies": { + "@solana/web3.js": "^1.95.1", + "nanoid": "^5.0.7" + } +} \ No newline at end of file diff --git a/src/ui/ActionContainer.tsx b/packages/blinks-core/src/BlinkContainer.tsx similarity index 70% rename from src/ui/ActionContainer.tsx rename to packages/blinks-core/src/BlinkContainer.tsx index f428c9dc..e23d371a 100644 --- a/src/ui/ActionContainer.tsx +++ b/packages/blinks-core/src/BlinkContainer.tsx @@ -1,4 +1,10 @@ -import { useEffect, useMemo, useReducer, useState } from 'react'; +import { + type ComponentType, + useEffect, + useMemo, + useReducer, + useState, +} from 'react'; import { AbstractActionComponent, Action, @@ -6,32 +12,63 @@ import { type ActionContext, type ActionPostResponse, type ActionSupportability, - ButtonActionComponent, - type ExtendedActionState, FormActionComponent, getExtendedActionState, getExtendedInterstitialState, getExtendedWebsiteState, - isParameterSelectable, - isPatternAllowed, mergeActionStates, MultiValueActionComponent, + type SecurityActionState, SingleValueActionComponent, -} from '../api'; -import { checkSecurity, type SecurityLevel } from '../shared'; -import { isInterstitial } from '../utils/interstitial-url.ts'; +} from './api'; +import { checkSecurity, isInterstitial, type SecurityLevel } from './utils'; import { isPostRequestError, isSignTransactionError, -} from '../utils/type-guards.ts'; -import { - ActionLayout, - type Disclaimer, - DisclaimerType, - type StylePreset, -} from './ActionLayout'; +} from './utils/type-guards.ts'; + +export type BlinkSecurityState = SecurityActionState; + +export enum DisclaimerType { + BLOCKED = 'blocked', + UNKNOWN = 'unknown', +} + +export type Disclaimer = + | { + type: DisclaimerType.BLOCKED; + ignorable: boolean; + hidden: boolean; + onSkip: () => void; + } + | { + type: DisclaimerType.UNKNOWN; + ignorable: boolean; + }; + +export interface BlinkCaption { + type: 'success' | 'error'; + text: string; +} + +export interface BaseBlinkLayoutProps { + id?: string; + securityState: BlinkSecurityState; + action: Action; + websiteUrl?: string | null; + websiteText?: string | null; + disclaimer?: Disclaimer | null; + caption?: BlinkCaption | null; + executeFn: ( + component: AbstractActionComponent, + params?: Record, + ) => Promise; + executionStatus: ExecutionStatus; + executingAction?: AbstractActionComponent | null; + supportability: ActionSupportability; +} -type ExecutionStatus = +export type ExecutionStatus = | 'blocked' | 'checking-supportability' | 'idle' @@ -39,7 +76,7 @@ type ExecutionStatus = | 'success' | 'error'; -interface ExecutionState { +export interface ExecutionState { status: ExecutionStatus; checkingSupportability?: boolean; executingAction?: AbstractActionComponent | null; @@ -47,7 +84,7 @@ interface ExecutionState { successMessage?: string | null; } -enum ExecutionType { +export enum ExecutionType { CHECK_SUPPORTABILITY = 'CHECK_SUPPORTABILITY', INITIATE = 'INITIATE', FINISH = 'FINISH', @@ -138,35 +175,14 @@ const executionReducer = ( } }; -const buttonVariantMap: Record< - ExecutionStatus, - 'default' | 'error' | 'success' -> = { - 'checking-supportability': 'default', - blocked: 'default', - idle: 'default', - executing: 'default', - success: 'success', - error: 'error', -}; - -const buttonLabelMap: Record = { - 'checking-supportability': 'Loading', - blocked: null, - idle: null, - executing: 'Executing', - success: 'Completed', - error: 'Failed', -}; - type ActionStateWithOrigin = | { - action: ExtendedActionState; + action: SecurityActionState; origin?: never; } | { - action: ExtendedActionState; - origin: ExtendedActionState; + action: SecurityActionState; + origin: SecurityActionState; originType: Source; }; @@ -208,34 +224,29 @@ const checkSecurityFromActionState = ( : true; }; -const SOFT_LIMIT_BUTTONS = 10; -const SOFT_LIMIT_INPUTS = 3; -const SOFT_LIMIT_FORM_INPUTS = 10; - const DEFAULT_SECURITY_LEVEL: SecurityLevel = 'only-trusted'; type Source = 'websites' | 'interstitials' | 'actions'; type NormalizedSecurityLevel = Record; +export interface BlinkContainerProps { + action: Action; + websiteUrl?: string | null; + websiteText?: string | null; + callbacks?: Partial; + securityLevel?: SecurityLevel | NormalizedSecurityLevel; + Layout: ComponentType; +} + // overall flow: check-supportability -> idle/block -> executing -> success/error or chain -export const ActionContainer = ({ +export const BlinkContainer = ({ action: initialAction, websiteUrl, websiteText, callbacks, securityLevel = DEFAULT_SECURITY_LEVEL, - stylePreset = 'default', - Experimental__ActionLayout = ActionLayout, -}: { - action: Action; - websiteUrl?: string | null; - websiteText?: string | null; - callbacks?: Partial; - securityLevel?: SecurityLevel | NormalizedSecurityLevel; - stylePreset?: StylePreset; - // please do not use it yet, better api is coming.. - Experimental__ActionLayout?: typeof ActionLayout; -}) => { + Layout, +}: BlinkContainerProps) => { const [action, setAction] = useState(initialAction); const normalizedSecurityLevel: NormalizedSecurityLevel = useMemo(() => { if (typeof securityLevel === 'string') { @@ -262,7 +273,7 @@ export const ActionContainer = ({ mergeActionStates( ...([actionState.action, actionState.origin].filter( Boolean, - ) as ExtendedActionState[]), + ) as SecurityActionState[]), ), [actionState], ); @@ -361,47 +372,6 @@ export const ActionContainer = ({ checkSupportability(action); }, [action, executionState.status, overallState, isPassingSecurityCheck]); - const buttons = useMemo( - () => - action?.actions - .filter((it) => it instanceof ButtonActionComponent) - .filter((it) => - executionState.executingAction - ? executionState.executingAction === it - : true, - ) - .toSpliced(SOFT_LIMIT_BUTTONS) ?? [], - [action, executionState.executingAction], - ); - const inputs = useMemo( - () => - action?.actions - .filter( - (it) => - it instanceof SingleValueActionComponent || - it instanceof MultiValueActionComponent, - ) - .filter((it) => - executionState.executingAction - ? executionState.executingAction === it - : true, - ) - .toSpliced(SOFT_LIMIT_INPUTS) ?? [], - [action, executionState.executingAction], - ); - const form = useMemo(() => { - const [formComponent] = - action?.actions - .filter((it) => it instanceof FormActionComponent) - .filter((it) => - executionState.executingAction - ? executionState.executingAction === it - : true, - ) ?? []; - - return formComponent; - }, [action, executionState.executingAction]); - const execute = async ( component: AbstractActionComponent, params?: Record, @@ -517,69 +487,6 @@ export const ActionContainer = ({ } }; - const asButtonProps = (it: ButtonActionComponent) => { - return { - text: buttonLabelMap[executionState.status] ?? it.label, - loading: - executionState.status === 'executing' && - it === executionState.executingAction, - disabled: - action.disabled || - action.type === 'completed' || - executionState.status !== 'idle', - variant: - buttonVariantMap[ - action.type === 'completed' ? 'success' : executionState.status - ], - onClick: (params?: Record) => - execute(it.parentComponent ?? it, params), - }; - }; - - const asInputProps = ( - it: SingleValueActionComponent | MultiValueActionComponent, - { placement }: { placement: 'form' | 'standalone' } = { - placement: 'standalone', - }, - ) => { - return { - type: it.parameter.type ?? 'text', - placeholder: it.parameter.label, - disabled: - action.disabled || - action.type === 'completed' || - executionState.status !== 'idle', - name: it.parameter.name, - required: it.parameter.required, - min: it.parameter.min, - max: it.parameter.max, - pattern: - it instanceof SingleValueActionComponent && - isPatternAllowed(it.parameter) - ? it.parameter.pattern - : undefined, - options: isParameterSelectable(it.parameter) - ? it.parameter.options - : undefined, - description: it.parameter.patternDescription, - button: - placement === 'standalone' - ? asButtonProps(it.toButtonActionComponent()) - : undefined, - }; - }; - - const asFormProps = (it: FormActionComponent) => { - return { - button: asButtonProps(it.toButtonActionComponent()), - inputs: it.parameters.toSpliced(SOFT_LIMIT_FORM_INPUTS).map((parameter) => - asInputProps(it.toInputActionComponent(parameter.name), { - placement: 'form', - }), - ), - }; - }; - const disclaimer: Disclaimer | null = useMemo(() => { if (overallState === 'malicious') { return { @@ -602,24 +509,32 @@ export const ActionContainer = ({ return null; }, [executionState.status, isPassingSecurityCheck, overallState]); + const blinkCaption: BlinkCaption | null = useMemo(() => { + if (executionState.status === 'error') { + return { type: 'error', text: executionState.errorMessage ?? '' }; + } + + if (executionState.status === 'success') { + return { type: 'success', text: executionState.successMessage ?? '' }; + } + + return null; + }, [ + executionState.status, + executionState.errorMessage, + executionState.successMessage, + ]); + return ( - asButtonProps(button))} - inputs={inputs.map((input) => asInputProps(input))} - form={form ? asFormProps(form) : undefined} + action={action} + caption={blinkCaption} + executionStatus={executionState.status} + executingAction={executionState.executingAction} + executeFn={execute} disclaimer={disclaimer} supportability={supportability} id={action.id} diff --git a/src/api/Action/Action.ts b/packages/blinks-core/src/api/Action/Action.ts similarity index 98% rename from src/api/Action/Action.ts rename to packages/blinks-core/src/api/Action/Action.ts index f4f55771..78029ee6 100644 --- a/src/api/Action/Action.ts +++ b/packages/blinks-core/src/api/Action/Action.ts @@ -1,6 +1,6 @@ import { nanoid } from 'nanoid'; -import { isUrlSameOrigin } from '../../shared'; -import { proxify, proxifyImage } from '../../utils/proxify.ts'; +import { proxify, proxifyImage } from '../../utils'; +import { isUrlSameOrigin } from '../../utils/security.ts'; import type { ActionAdapter } from '../ActionConfig.ts'; import type { ActionParameterType, diff --git a/src/api/Action/action-components/AbstractActionComponent.ts b/packages/blinks-core/src/api/Action/action-components/AbstractActionComponent.ts similarity index 96% rename from src/api/Action/action-components/AbstractActionComponent.ts rename to packages/blinks-core/src/api/Action/action-components/AbstractActionComponent.ts index f93c2cad..86a62fbd 100644 --- a/src/api/Action/action-components/AbstractActionComponent.ts +++ b/packages/blinks-core/src/api/Action/action-components/AbstractActionComponent.ts @@ -1,4 +1,4 @@ -import { proxify } from '../../../utils/proxify.ts'; +import { proxify } from '../../../utils'; import type { ActionError, ActionPostRequest, diff --git a/src/api/Action/action-components/ButtonActionComponent.ts b/packages/blinks-core/src/api/Action/action-components/ButtonActionComponent.ts similarity index 100% rename from src/api/Action/action-components/ButtonActionComponent.ts rename to packages/blinks-core/src/api/Action/action-components/ButtonActionComponent.ts diff --git a/src/api/Action/action-components/FormActionComponent.ts b/packages/blinks-core/src/api/Action/action-components/FormActionComponent.ts similarity index 100% rename from src/api/Action/action-components/FormActionComponent.ts rename to packages/blinks-core/src/api/Action/action-components/FormActionComponent.ts diff --git a/src/api/Action/action-components/MultiValueActionComponent.ts b/packages/blinks-core/src/api/Action/action-components/MultiValueActionComponent.ts similarity index 100% rename from src/api/Action/action-components/MultiValueActionComponent.ts rename to packages/blinks-core/src/api/Action/action-components/MultiValueActionComponent.ts diff --git a/src/api/Action/action-components/SingleValueActionComponent.ts b/packages/blinks-core/src/api/Action/action-components/SingleValueActionComponent.ts similarity index 100% rename from src/api/Action/action-components/SingleValueActionComponent.ts rename to packages/blinks-core/src/api/Action/action-components/SingleValueActionComponent.ts diff --git a/src/api/Action/action-components/guards.ts b/packages/blinks-core/src/api/Action/action-components/guards.ts similarity index 100% rename from src/api/Action/action-components/guards.ts rename to packages/blinks-core/src/api/Action/action-components/guards.ts diff --git a/src/api/Action/action-components/index.ts b/packages/blinks-core/src/api/Action/action-components/index.ts similarity index 100% rename from src/api/Action/action-components/index.ts rename to packages/blinks-core/src/api/Action/action-components/index.ts diff --git a/src/api/Action/action-supportability.ts b/packages/blinks-core/src/api/Action/action-supportability.ts similarity index 100% rename from src/api/Action/action-supportability.ts rename to packages/blinks-core/src/api/Action/action-supportability.ts diff --git a/src/api/Action/index.ts b/packages/blinks-core/src/api/Action/index.ts similarity index 100% rename from src/api/Action/index.ts rename to packages/blinks-core/src/api/Action/index.ts diff --git a/src/api/ActionCallbacks.ts b/packages/blinks-core/src/api/ActionCallbacks.ts similarity index 100% rename from src/api/ActionCallbacks.ts rename to packages/blinks-core/src/api/ActionCallbacks.ts diff --git a/src/api/ActionConfig.ts b/packages/blinks-core/src/api/ActionConfig.ts similarity index 94% rename from src/api/ActionConfig.ts rename to packages/blinks-core/src/api/ActionConfig.ts index 03dcdf06..76fdf72f 100644 --- a/src/api/ActionConfig.ts +++ b/packages/blinks-core/src/api/ActionConfig.ts @@ -1,7 +1,9 @@ import { Connection } from '@solana/web3.js'; -import { type Action } from './Action'; -import { AbstractActionComponent } from './Action/action-components'; -import { DEFAULT_SUPPORTED_BLOCKCHAIN_IDS } from './Action/action-supportability.ts'; +import { + type Action, + AbstractActionComponent, + DEFAULT_SUPPORTED_BLOCKCHAIN_IDS, +} from './Action'; export interface ActionContext { originalUrl: string; diff --git a/src/api/ActionsRegistry.ts b/packages/blinks-core/src/api/ActionsRegistry.ts similarity index 95% rename from src/api/ActionsRegistry.ts rename to packages/blinks-core/src/api/ActionsRegistry.ts index b8baa60d..24ec59bd 100644 --- a/src/api/ActionsRegistry.ts +++ b/packages/blinks-core/src/api/ActionsRegistry.ts @@ -140,11 +140,11 @@ export interface RegisteredEntity { state: 'trusted' | 'malicious'; } -export type ExtendedActionState = RegisteredEntity['state'] | 'unknown'; +export type SecurityActionState = RegisteredEntity['state'] | 'unknown'; export const mergeActionStates = ( - ...states: ExtendedActionState[] -): ExtendedActionState => { + ...states: SecurityActionState[] +): SecurityActionState => { if (states.includes('malicious')) { return 'malicious'; } @@ -158,7 +158,7 @@ export const mergeActionStates = ( export const getExtendedActionState = ( actionOrUrl: Action | string, -): ExtendedActionState => { +): SecurityActionState => { return ( ActionsRegistry.getInstance().lookup( typeof actionOrUrl === 'string' ? actionOrUrl : actionOrUrl.url, @@ -167,7 +167,7 @@ export const getExtendedActionState = ( ); }; -export const getExtendedWebsiteState = (url: string): ExtendedActionState => { +export const getExtendedWebsiteState = (url: string): SecurityActionState => { return ( ActionsRegistry.getInstance().lookup(url, 'website')?.state ?? 'unknown' ); @@ -175,7 +175,7 @@ export const getExtendedWebsiteState = (url: string): ExtendedActionState => { export const getExtendedInterstitialState = ( url: string, -): ExtendedActionState => { +): SecurityActionState => { return ( ActionsRegistry.getInstance().lookup(url, 'interstitial')?.state ?? 'unknown' diff --git a/src/api/actions-spec.ts b/packages/blinks-core/src/api/actions-spec.ts similarity index 100% rename from src/api/actions-spec.ts rename to packages/blinks-core/src/api/actions-spec.ts diff --git a/src/api/index.ts b/packages/blinks-core/src/api/index.ts similarity index 100% rename from src/api/index.ts rename to packages/blinks-core/src/api/index.ts diff --git a/src/api/solana-pay-spec.ts b/packages/blinks-core/src/api/solana-pay-spec.ts similarity index 100% rename from src/api/solana-pay-spec.ts rename to packages/blinks-core/src/api/solana-pay-spec.ts diff --git a/packages/blinks-core/src/index.ts b/packages/blinks-core/src/index.ts new file mode 100644 index 00000000..51b61abb --- /dev/null +++ b/packages/blinks-core/src/index.ts @@ -0,0 +1,3 @@ +export * from './api'; +export * from './BlinkContainer'; +export * from './utils'; diff --git a/src/utils/caip-2.ts b/packages/blinks-core/src/utils/caip-2.ts similarity index 100% rename from src/utils/caip-2.ts rename to packages/blinks-core/src/utils/caip-2.ts diff --git a/src/utils/constants.ts b/packages/blinks-core/src/utils/constants.ts similarity index 68% rename from src/utils/constants.ts rename to packages/blinks-core/src/utils/constants.ts index 413fe615..3ca3cba1 100644 --- a/src/utils/constants.ts +++ b/packages/blinks-core/src/utils/constants.ts @@ -1,2 +1 @@ -export const noop = () => {}; export const SOLANA_ACTION_PREFIX = /^(solana-action:|solana:)/; diff --git a/src/utils/dependency-versions.ts b/packages/blinks-core/src/utils/dependency-versions.ts similarity index 100% rename from src/utils/dependency-versions.ts rename to packages/blinks-core/src/utils/dependency-versions.ts diff --git a/packages/blinks-core/src/utils/index.ts b/packages/blinks-core/src/utils/index.ts new file mode 100644 index 00000000..3ccbb43c --- /dev/null +++ b/packages/blinks-core/src/utils/index.ts @@ -0,0 +1,5 @@ +export { BlockchainIds } from './caip-2.ts'; +export * from './interstitial-url.ts'; +export { proxify, proxifyImage, setProxyUrl } from './proxify'; +export { checkSecurity, type SecurityLevel } from './security'; +export * from './url-mapper.ts'; diff --git a/src/utils/interstitial-url.ts b/packages/blinks-core/src/utils/interstitial-url.ts similarity index 100% rename from src/utils/interstitial-url.ts rename to packages/blinks-core/src/utils/interstitial-url.ts diff --git a/src/utils/proxify.ts b/packages/blinks-core/src/utils/proxify.ts similarity index 100% rename from src/utils/proxify.ts rename to packages/blinks-core/src/utils/proxify.ts diff --git a/src/shared/security.ts b/packages/blinks-core/src/utils/security.ts similarity index 86% rename from src/shared/security.ts rename to packages/blinks-core/src/utils/security.ts index 49bb6d5b..0ebc293d 100644 --- a/src/shared/security.ts +++ b/packages/blinks-core/src/utils/security.ts @@ -1,9 +1,9 @@ -import type { ExtendedActionState } from '../api'; +import type { SecurityActionState } from '../api'; export type SecurityLevel = 'only-trusted' | 'non-malicious' | 'all'; export const checkSecurity = ( - state: ExtendedActionState, + state: SecurityActionState, securityLevel: SecurityLevel, ): boolean => { switch (securityLevel) { diff --git a/src/utils/type-guards.ts b/packages/blinks-core/src/utils/type-guards.ts similarity index 100% rename from src/utils/type-guards.ts rename to packages/blinks-core/src/utils/type-guards.ts diff --git a/src/utils/url-mapper.ts b/packages/blinks-core/src/utils/url-mapper.ts similarity index 100% rename from src/utils/url-mapper.ts rename to packages/blinks-core/src/utils/url-mapper.ts diff --git a/test/api/Action/action-supportability.spec.ts b/packages/blinks-core/test/api/Action/action-supportability.spec.ts similarity index 100% rename from test/api/Action/action-supportability.spec.ts rename to packages/blinks-core/test/api/Action/action-supportability.spec.ts diff --git a/test/api/action-registry.spec.ts b/packages/blinks-core/test/api/action-registry.spec.ts similarity index 98% rename from test/api/action-registry.spec.ts rename to packages/blinks-core/test/api/action-registry.spec.ts index 3dbb8730..d3dd3fca 100644 --- a/test/api/action-registry.spec.ts +++ b/packages/blinks-core/test/api/action-registry.spec.ts @@ -1,8 +1,5 @@ import { describe, expect, test } from 'bun:test'; -import { - ActionsRegistry, - type ActionsRegistryConfig, -} from '../../src/api/ActionsRegistry.ts'; +import { ActionsRegistry, type ActionsRegistryConfig } from '../../src'; describe('ActionsRegistry', () => { describe('actions lookup', () => { diff --git a/test/utils/dependency-versions.spec.ts b/packages/blinks-core/test/utils/dependency-versions.spec.ts similarity index 100% rename from test/utils/dependency-versions.spec.ts rename to packages/blinks-core/test/utils/dependency-versions.spec.ts diff --git a/test/utils/interstitial-url.spec.ts b/packages/blinks-core/test/utils/interstitial-url.spec.ts similarity index 98% rename from test/utils/interstitial-url.spec.ts rename to packages/blinks-core/test/utils/interstitial-url.spec.ts index 44814c46..6d97893a 100644 --- a/test/utils/interstitial-url.spec.ts +++ b/packages/blinks-core/test/utils/interstitial-url.spec.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from 'bun:test'; -import { isInterstitial } from '../../src/utils/interstitial-url.ts'; +import { isInterstitial } from '../../src'; describe('isInterstitialUrl', () => { test('should return true and decode the action URL for a valid interstitial URL with solana-action: prefix (URL-encoded)', () => { diff --git a/test/utils/url-mapper.spec.ts b/packages/blinks-core/test/utils/url-mapper.spec.ts similarity index 99% rename from test/utils/url-mapper.spec.ts rename to packages/blinks-core/test/utils/url-mapper.spec.ts index e6da2945..a5b7d90b 100644 --- a/test/utils/url-mapper.spec.ts +++ b/packages/blinks-core/test/utils/url-mapper.spec.ts @@ -1,8 +1,5 @@ import { describe, expect, test } from 'bun:test'; -import { - ActionsURLMapper, - type ActionsJsonConfig, -} from '../../src/utils/url-mapper.ts'; +import { ActionsURLMapper, type ActionsJsonConfig } from '../../src'; describe('ActionsURLMapper', () => { describe('Exact match rules', () => { diff --git a/packages/blinks-core/tsconfig.json b/packages/blinks-core/tsconfig.json new file mode 100644 index 00000000..238655f2 --- /dev/null +++ b/packages/blinks-core/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + // Enable latest features + "lib": ["ESNext", "DOM"], + "target": "ESNext", + "module": "ESNext", + "moduleDetection": "force", + "jsx": "react-jsx", + "allowJs": true, + + // Bundler mode + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + + // Best practices + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, + + // Some stricter flags (disabled by default) + "noUnusedLocals": false, + "noUnusedParameters": false, + "noPropertyAccessFromIndexSignature": false + } +} diff --git a/packages/blinks-core/tsup.config.ts b/packages/blinks-core/tsup.config.ts new file mode 100644 index 00000000..c95691fb --- /dev/null +++ b/packages/blinks-core/tsup.config.ts @@ -0,0 +1,19 @@ +import { defineConfig, type Options } from 'tsup'; + +const commonCfg: Partial = { + splitting: true, + sourcemap: false, + clean: true, + format: ['cjs', 'esm'], + target: ['esnext'], +}; + +export default defineConfig([ + { + ...commonCfg, + entry: ['src/index.ts'], + dts: { + entry: ['src/index.ts'], + }, + }, +]); diff --git a/packages/blinks/package.json b/packages/blinks/package.json new file mode 100644 index 00000000..08990d35 --- /dev/null +++ b/packages/blinks/package.json @@ -0,0 +1,76 @@ +{ + "name": "@dialectlabs/blinks", + "version": "0.9.3", + "license": "Apache-2.0", + "private": false, + "sideEffects": true, + "type": "module", + "repository": { + "type": "git", + "url": "https://github.com/dialectlabs/blinks" + }, + "scripts": { + "build": "tsup-node", + "dev": "tsup-node --watch" + }, + "main": "dist/index.cjs", + "module": "dist/index.js", + "types": "dist/index.d.ts", + "exports": { + "./ext/twitter": { + "import": "./dist/ext/twitter.js", + "require": "./dist/ext/twitter.cjs", + "types": "./dist/ext/twitter.d.ts" + }, + "./hooks": { + "import": "./dist/hooks/index.js", + "require": "./dist/hooks/index.cjs", + "types": "./dist/hooks/index.d.ts" + }, + "./hooks/solana": { + "import": "./dist/hooks/solana/index.js", + "require": "./dist/hooks/solana/index.cjs", + "types": "./dist/hooks/solana/index.d.ts" + }, + ".": { + "import": "./dist/index.js", + "require": "./dist/index.cjs", + "types": "./dist/index.d.ts" + }, + "./index.css": "./dist/index.css" + }, + "files": [ + "dist" + ], + "devDependencies": { + "@solana/actions-spec": "~2.2.0", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@typescript-eslint/eslint-plugin": "^7.16.1", + "@typescript-eslint/parser": "^7.16.1", + "autoprefixer": "^10.4.19", + "eslint": "^8.57.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-react": "^7.34.4", + "eslint-plugin-react-hooks": "^4.6.2", + "postcss": "^8.4.39", + "postcss-prefix-selector": "^1.16.1", + "prettier": "^3.3.3", + "prettier-plugin-organize-imports": "^4.0.0", + "prettier-plugin-tailwindcss": "^0.6.5", + "tailwindcss": "^3.4.3", + "tsup": "^8.2.0", + "typescript": "^5.5.3" + }, + "peerDependencies": { + "@solana/wallet-adapter-react": "^0.15.0", + "@solana/wallet-adapter-react-ui": "^0.9.0", + "@solana/web3.js": "^1.95.1", + "react": ">=18", + "react-dom": ">=18" + }, + "dependencies": { + "clsx": "^2.1.1", + "@dialectlabs/blinks-core": "0.10.0" + } +} diff --git a/src/ext/index.ts b/packages/blinks/src/ext/index.ts similarity index 100% rename from src/ext/index.ts rename to packages/blinks/src/ext/index.ts diff --git a/src/ext/twitter.tsx b/packages/blinks/src/ext/twitter.tsx similarity index 95% rename from src/ext/twitter.tsx rename to packages/blinks/src/ext/twitter.tsx index 1f6b669b..90c08c75 100644 --- a/src/ext/twitter.tsx +++ b/packages/blinks/src/ext/twitter.tsx @@ -1,24 +1,27 @@ -import { createRoot } from 'react-dom/client'; import { Action, type ActionAdapter, type ActionCallbacksConfig, + type ActionsJsonConfig, ActionsRegistry, type ActionSupportStrategy, + ActionsURLMapper, + checkSecurity, defaultActionSupportStrategy, getExtendedActionState, getExtendedInterstitialState, getExtendedWebsiteState, -} from '../api'; -import { checkSecurity, type SecurityLevel } from '../shared'; -import { ActionContainer, type StylePreset } from '../ui'; -import { noop } from '../utils/constants'; -import { isInterstitial } from '../utils/interstitial-url.ts'; -import { proxify } from '../utils/proxify.ts'; -import { type ActionsJsonConfig, ActionsURLMapper } from '../utils/url-mapper'; + isInterstitial, + proxify, + type SecurityLevel, +} from '@dialectlabs/blinks-core'; +import { createRoot } from 'react-dom/client'; +import { Blink, type StylePreset } from '../ui'; type ObserverSecurityLevel = SecurityLevel; +const noop = () => {}; + export interface ObserverOptions { // trusted > unknown > malicious securityLevel: @@ -241,7 +244,7 @@ function createAction({ actionRoot.render(

e.stopPropagation()}> - { ignore = true; }; - }, [actionApiUrl, isRegistryLoaded]); + }, [actionApiUrl, isRegistryLoaded, supportStrategy]); useEffect(() => { action?.setAdapter(adapter); diff --git a/src/hooks/useActionRegistryInterval.ts b/packages/blinks/src/hooks/useActionRegistryInterval.ts similarity index 85% rename from src/hooks/useActionRegistryInterval.ts rename to packages/blinks/src/hooks/useActionRegistryInterval.ts index 037c17e9..e7adaf86 100644 --- a/src/hooks/useActionRegistryInterval.ts +++ b/packages/blinks/src/hooks/useActionRegistryInterval.ts @@ -1,6 +1,6 @@ 'use client'; +import { ActionsRegistry } from '@dialectlabs/blinks-core'; import { useEffect, useState } from 'react'; -import { ActionsRegistry } from '../api'; export function useActionsRegistryInterval() { const [isRegistryLoaded, setRegistryLoaded] = useState(false); diff --git a/src/index.css b/packages/blinks/src/index.css similarity index 100% rename from src/index.css rename to packages/blinks/src/index.css diff --git a/packages/blinks/src/index.ts b/packages/blinks/src/index.ts new file mode 100644 index 00000000..f85dc0b9 --- /dev/null +++ b/packages/blinks/src/index.ts @@ -0,0 +1,3 @@ +export * from '@dialectlabs/blinks-core'; + +export * from './ui'; diff --git a/src/ui/ActionLayout.tsx b/packages/blinks/src/ui/BaseBlinkLayout.tsx similarity index 78% rename from src/ui/ActionLayout.tsx rename to packages/blinks/src/ui/BaseBlinkLayout.tsx index 6cd6ef7b..6b42deb7 100644 --- a/src/ui/ActionLayout.tsx +++ b/packages/blinks/src/ui/BaseBlinkLayout.tsx @@ -1,55 +1,48 @@ +import { + type ActionSupportability, + type Disclaimer, + DisclaimerType, + type SecurityActionState, +} from '@dialectlabs/blinks-core'; import clsx from 'clsx'; import { type ReactNode, useState } from 'react'; -import type { ActionSupportability, ExtendedActionState } from '../api'; -import { Badge } from './Badge.tsx'; -import { Snackbar } from './Snackbar.tsx'; -import { ExclamationShieldIcon, InfoShieldIcon, LinkIcon } from './icons'; -import ConfigIcon from './icons/ConfigIcon.tsx'; +import { Badge } from './internal/Badge.tsx'; +import { Snackbar } from './internal/Snackbar.tsx'; +import { + ConfigIcon, + ExclamationShieldIcon, + InfoShieldIcon, + LinkIcon, +} from './internal/icons'; import { ActionButton, + ActionCheckboxGroup, ActionDateInput, ActionEmailInput, ActionNumberInput, ActionRadioGroup, ActionSelect, + ActionTextArea, ActionTextInput, ActionUrlInput, -} from './inputs'; -import { ActionCheckboxGroup } from './inputs/ActionCheckboxGroup.tsx'; -import { ActionTextArea } from './inputs/ActionTextArea.tsx'; -import type { BaseButtonProps, BaseInputProps } from './inputs/types.ts'; +} from './internal/inputs'; +import type { + BaseButtonProps, + BaseInputProps, +} from './internal/inputs/types.ts'; +import type { StylePreset } from './types.ts'; -type ActionType = ExtendedActionState; type ButtonProps = BaseButtonProps; type InputProps = BaseInputProps; -export type StylePreset = 'default' | 'x-dark' | 'x-light' | 'custom'; - -export enum DisclaimerType { - BLOCKED = 'blocked', - UNKNOWN = 'unknown', -} - -export type Disclaimer = - | { - type: DisclaimerType.BLOCKED; - ignorable: boolean; - hidden: boolean; - onSkip: () => void; - } - | { - type: DisclaimerType.UNKNOWN; - ignorable: boolean; - }; - -const stylePresetClassMap: Record = { +const themeClassMap: Record = { default: 'dial-light', 'x-dark': 'x-dark', 'x-light': 'x-light', custom: 'custom', }; -interface LayoutProps { +export interface InnerLayoutProps { stylePreset?: StylePreset; image?: string; error?: string | null; @@ -57,7 +50,7 @@ interface LayoutProps { websiteUrl?: string | null; websiteText?: string | null; disclaimer?: Disclaimer | null; - type: ActionType; + securityState: SecurityActionState; title: string; description: string; buttons?: ButtonProps[]; @@ -105,7 +98,7 @@ const NotSupportedBlock = ({
@@ -157,7 +150,7 @@ const DisclaimerBlock = ({

{ignorable && onSkip && (