@cas-parser/connect 1.1.0
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/LICENSE +21 -0
- package/README.md +263 -0
- package/dist/PortfolioConnect.d.ts +5 -0
- package/dist/components/CDSLFetchMode.d.ts +13 -0
- package/dist/components/FetchMode.d.ts +12 -0
- package/dist/components/Modal.d.ts +12 -0
- package/dist/components/PortfolioConnectWidget.d.ts +14 -0
- package/dist/components/ShortcutLinks.d.ts +8 -0
- package/dist/components/UploadZone.d.ts +8 -0
- package/dist/imperative.d.ts +87 -0
- package/dist/index.cjs.js +1766 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.esm.js +1755 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/portfolio-connect.standalone.min.js +2 -0
- package/dist/portfolio-connect.standalone.min.js.map +1 -0
- package/dist/portfolio-connect.umd.js +1769 -0
- package/dist/portfolio-connect.umd.js.map +1 -0
- package/dist/portfolio-connect.umd.min.js +2 -0
- package/dist/portfolio-connect.umd.min.js.map +1 -0
- package/dist/types/index.d.ts +86 -0
- package/dist/utils/api.d.ts +57 -0
- package/package.json +84 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"portfolio-connect.umd.min.js","sources":["../src/components/Modal.tsx","../src/components/ShortcutLinks.tsx","../src/components/UploadZone.tsx","../src/components/FetchMode.tsx","../src/components/CDSLFetchMode.tsx","../src/components/PortfolioConnectWidget.tsx","../src/utils/api.ts","../src/PortfolioConnect.tsx","../src/imperative.tsx","../src/index.ts"],"sourcesContent":["import React, { useEffect, useRef } from 'react';\n\ninterface ModalProps {\n isOpen: boolean;\n onClose: () => void;\n onBack?: () => void; // Optional back handler\n showBackButton?: boolean; // Show back arrow instead of X\n children: React.ReactNode;\n width?: number;\n isSandbox?: boolean; // Show sandbox indicator\n}\n\nexport const Modal: React.FC<ModalProps> = ({ \n isOpen, \n onClose, \n onBack,\n showBackButton = false,\n children, \n width = 400,\n isSandbox = false,\n}) => {\n const overlayRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (isOpen) {\n document.body.style.overflow = 'hidden';\n } else {\n document.body.style.overflow = '';\n }\n return () => {\n document.body.style.overflow = '';\n };\n }, [isOpen]);\n\n if (!isOpen) return null;\n\n const handleOverlayClick = (e: React.MouseEvent) => {\n if (e.target === overlayRef.current) {\n onClose();\n }\n };\n\n const handleHeaderButtonClick = () => {\n if (showBackButton && onBack) {\n onBack();\n } else {\n onClose();\n }\n };\n\n return (\n <div\n ref={overlayRef}\n onClick={handleOverlayClick}\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n backgroundColor: 'rgba(0, 0, 0, 0.5)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n zIndex: 10000,\n padding: 16,\n }}\n >\n <div\n style={{\n backgroundColor: '#fff',\n borderRadius: 16,\n width: '100%',\n maxWidth: width,\n maxHeight: '90vh',\n overflow: 'auto',\n position: 'relative',\n boxShadow: '0 25px 80px rgba(0, 0, 0, 0.25)',\n }}\n >\n {/* Sandbox Banner */}\n {isSandbox && (\n <div style={{\n backgroundColor: '#fef3c7',\n borderBottom: '1px solid #fcd34d',\n padding: '6px 16px',\n fontSize: 12,\n fontWeight: 600,\n color: '#92400e',\n textAlign: 'center',\n borderTopLeftRadius: 16,\n borderTopRightRadius: 16,\n }}>\n 🧪 Sandbox Mode — Test data only\n </div>\n )}\n \n {/* Header button (Back or Close) */}\n <button\n onClick={handleHeaderButtonClick}\n style={{\n position: 'absolute',\n top: isSandbox ? 40 : 12,\n left: showBackButton ? 12 : 'auto',\n right: showBackButton ? 'auto' : 12,\n background: 'none',\n border: 'none',\n fontSize: showBackButton ? 20 : 28,\n cursor: 'pointer',\n color: '#6b7280',\n lineHeight: 1,\n padding: 8,\n zIndex: 1,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: 8,\n transition: 'background-color 0.15s',\n }}\n onMouseOver={(e) => e.currentTarget.style.backgroundColor = '#f3f4f6'}\n onMouseOut={(e) => e.currentTarget.style.backgroundColor = 'transparent'}\n aria-label={showBackButton ? 'Back' : 'Close'}\n >\n {showBackButton ? '←' : '×'}\n </button>\n {children}\n </div>\n </div>\n );\n};\n","import React from 'react';\nimport type { CASType } from '../types';\n\n// Search by sender emails - official CAS statement sources\nconst CAS_SENDERS = {\n 'CAMS_KFINTECH': ['donotreply@camsonline.com', 'samfs@kfintech.com'],\n 'CDSL': ['ecas@cdslstatement.com'],\n 'NSDL': ['nsdl-cas@nsdl.co.in'],\n};\n\n// Build search query for sender emails\nconst buildSearchQuery = (type?: CASType) => {\n const senders = type ? CAS_SENDERS[type] : Object.values(CAS_SENDERS).flat();\n const fromQuery = senders.map(s => `from:${s}`).join(' OR ');\n return `(${fromQuery}) has:attachment`;\n};\n\n// Official brand logos as inline SVG\nconst GmailLogo = () => (\n <svg width=\"20\" height=\"16\" viewBox=\"0 0 24 18\" fill=\"none\">\n <path d=\"M1.636 18H5.455V8.682L0 4.91V16.364C0 17.267.733 18 1.636 18z\" fill=\"#4285F4\"/>\n <path d=\"M18.545 18h3.819c.904 0 1.636-.732 1.636-1.636V4.91l-5.455 3.772V18z\" fill=\"#34A853\"/>\n <path d=\"M18.545 1.636V8.682L24 4.91v-1.91c0-2.022-2.309-3.175-3.927-1.963l-1.528 1.109z\" fill=\"#FBBC04\"/>\n <path d=\"M5.455 8.682V1.636l6.545 4.91 6.545-4.91v7.046L12 13.592 5.455 8.682z\" fill=\"#EA4335\"/>\n <path d=\"M0 2.999v1.91l5.455 3.773V1.636L3.927.527C2.31-.685 0 .468 0 2.999z\" fill=\"#C5221F\"/>\n </svg>\n);\n\nconst OutlookLogo = () => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 32 32\" fill=\"none\">\n <path d=\"M19.484 7.937v5.477l1.916 1.205a.489.489 0 00.21.063.489.489 0 00.229-.063l8.088-5.234a1.455 1.455 0 00-.741-1.448H19.484z\" fill=\"#0072C6\"/>\n <path d=\"M19.484 15.457l1.747 1.2a.522.522 0 00.543 0c-.3.181 8.073-5.378 8.073-5.378v10.795a1.474 1.474 0 01-1.474 1.474h-8.889V15.457z\" fill=\"#0072C6\"/>\n <path d=\"M10.44 12.932a1.927 1.927 0 00-1.384-.543 1.9 1.9 0 00-1.387.543 1.927 1.927 0 00-.543 1.384v3.086a1.927 1.927 0 00.543 1.384 1.864 1.864 0 001.384.543 1.927 1.927 0 001.387-.543 1.9 1.9 0 00.543-1.384v-3.086a1.927 1.927 0 00-.543-1.384z\" fill=\"#0072C6\"/>\n <path d=\"M18.044 5.116H8.044a1.474 1.474 0 00-1.474 1.474v1.209l6.3 4.5 5.174-3.15V6.59a1.474 1.474 0 00-1.474-1.474H8.044z\" fill=\"#0072C6\"/>\n <path d=\"M1.474 9.789h16.842v14.737H1.474A1.474 1.474 0 010 23.053V11.263a1.474 1.474 0 011.474-1.474z\" fill=\"#0072C6\"/>\n <ellipse cx=\"9.263\" cy=\"16.842\" rx=\"3.789\" ry=\"4.421\" stroke=\"#fff\" strokeWidth=\"1.5\" fill=\"none\"/>\n </svg>\n);\n\nconst YahooLogo = () => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 32 32\" fill=\"none\">\n <path d=\"M16 2C8.268 2 2 8.268 2 16s6.268 14 14 14 14-6.268 14-14S23.732 2 16 2z\" fill=\"#5C0DAC\"/>\n <path d=\"M22.287 10.5h-2.844l-3.118 6.066L13.178 10.5h-2.89l4.622 8.37v4.63h2.666v-4.63l4.711-8.37z\" fill=\"#fff\"/>\n </svg>\n);\n\n// Generate provider URLs based on selected CAS type\nconst getProviders = (selectedType?: CASType) => {\n const query = buildSearchQuery(selectedType);\n const encodedQuery = encodeURIComponent(query);\n \n return [\n {\n name: 'Gmail',\n Logo: GmailLogo,\n url: `https://mail.google.com/mail/u/0/#search/${encodedQuery}`\n },\n {\n name: 'Outlook',\n Logo: OutlookLogo,\n url: `https://outlook.live.com/mail/0/deeplink?version=20200615005&search=${encodedQuery}`\n },\n {\n name: 'Yahoo',\n Logo: YahooLogo,\n url: `https://mail.yahoo.com/d/search/keyword=${encodedQuery}`\n }\n ];\n};\n\ninterface ShortcutLinksProps {\n selectedType?: CASType;\n onSearchClick?: (provider: string) => void;\n}\n\nexport const ShortcutLinks: React.FC<ShortcutLinksProps> = ({ selectedType, onSearchClick }) => {\n const providers = getProviders(selectedType);\n \n return (\n <div style={{ marginBottom: 16 }}>\n <div style={{ \n fontSize: 12, \n color: '#6b7280', \n marginBottom: 10,\n fontWeight: 500 \n }}>\n Find statement in your inbox\n </div>\n <div style={{ \n display: 'grid', \n gridTemplateColumns: 'repeat(3, 1fr)', \n gap: 10 \n }}>\n {providers.map((provider) => (\n <a\n key={provider.name}\n href={provider.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n onClick={() => onSearchClick?.(provider.name)}\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n padding: 10,\n backgroundColor: '#f9fafb',\n borderRadius: 8,\n textDecoration: 'none',\n border: '1px solid #e5e7eb',\n transition: 'all 0.15s',\n cursor: 'pointer',\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = '#eff6ff';\n e.currentTarget.style.borderColor = '#2563eb';\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = '#f9fafb';\n e.currentTarget.style.borderColor = '#e5e7eb';\n }}\n >\n <provider.Logo />\n <span style={{ fontSize: 11, color: '#374151', fontWeight: 500, marginTop: 4 }}>\n {provider.name}\n </span>\n </a>\n ))}\n </div>\n </div>\n );\n};\n","import React, { useState, useRef, useCallback } from 'react';\n\ninterface UploadZoneProps {\n onFileSelect: (file: File, password: string) => void;\n isProcessing: boolean;\n progress: number;\n}\n\nexport const UploadZone: React.FC<UploadZoneProps> = ({ \n onFileSelect, \n isProcessing, \n progress \n}) => {\n const [file, setFile] = useState<File | null>(null);\n const [password, setPassword] = useState('');\n const [isDragOver, setIsDragOver] = useState(false);\n const inputRef = useRef<HTMLInputElement>(null);\n\n const handleDrop = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n setIsDragOver(false);\n const droppedFile = e.dataTransfer.files[0];\n if (droppedFile?.type === 'application/pdf') {\n setFile(droppedFile);\n }\n }, []);\n\n const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const selectedFile = e.target.files?.[0];\n if (selectedFile) {\n setFile(selectedFile);\n }\n };\n\n const handleSubmit = () => {\n if (file) {\n onFileSelect(file, password);\n }\n };\n\n if (isProcessing) {\n return (\n <div style={{ textAlign: 'center', padding: '50px 20px' }}>\n <div style={{ \n width: 56, \n height: 56, \n backgroundColor: '#eff6ff', \n borderRadius: '50%',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n margin: '0 auto 20px',\n }}>\n <svg width=\"28\" height=\"28\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#2563eb\" strokeWidth=\"2\">\n <path d=\"M21 12V7H5a2 2 0 0 1 0-4h14v4\"/>\n <path d=\"M3 5v14a2 2 0 0 0 2 2h16v-5\"/>\n <path d=\"M18 12a2 2 0 0 0 0 4h4v-4Z\"/>\n </svg>\n </div>\n <h3 style={{ margin: '0 0 8px', fontSize: 18, fontWeight: 600, color: '#1f2937' }}>\n Reading Your Investments\n </h3>\n <p style={{ color: '#6b7280', marginBottom: 24, fontSize: 14 }}>\n Extracting holdings, transactions & values...\n </p>\n <div style={{\n height: 6,\n backgroundColor: '#e5e7eb',\n borderRadius: 3,\n overflow: 'hidden',\n maxWidth: 240,\n margin: '0 auto',\n }}>\n <div style={{\n height: '100%',\n width: `${progress}%`,\n backgroundColor: '#2563eb',\n transition: 'width 0.3s ease',\n }} />\n </div>\n <div style={{ fontSize: 12, color: '#9ca3af', marginTop: 10 }}>\n {progress < 50 ? 'Uploading...' : progress < 90 ? 'Processing...' : 'Almost done!'}\n </div>\n </div>\n );\n }\n\n if (!file) {\n return (\n <div>\n <h3 style={{ fontSize: 18, fontWeight: 600, margin: '0 0 16px', color: '#1f2937' }}>\n Upload Your Statement\n </h3>\n <div\n onDragOver={(e) => { e.preventDefault(); setIsDragOver(true); }}\n onDragLeave={() => setIsDragOver(false)}\n onDrop={handleDrop}\n onClick={() => inputRef.current?.click()}\n style={{\n border: `2px dashed ${isDragOver ? '#2563eb' : '#d1d5db'}`,\n borderRadius: 12,\n padding: '36px 20px',\n textAlign: 'center',\n cursor: 'pointer',\n backgroundColor: isDragOver ? '#eff6ff' : '#f9fafb',\n transition: 'all 0.2s',\n }}\n >\n <input\n ref={inputRef}\n type=\"file\"\n accept=\".pdf\"\n onChange={handleFileChange}\n style={{ display: 'none' }}\n />\n <div style={{ marginBottom: 12 }}>\n <svg width=\"40\" height=\"40\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#9ca3af\" strokeWidth=\"1.5\">\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"/>\n <polyline points=\"14 2 14 8 20 8\"/>\n <line x1=\"16\" y1=\"13\" x2=\"8\" y2=\"13\"/>\n <line x1=\"16\" y1=\"17\" x2=\"8\" y2=\"17\"/>\n <polyline points=\"10 9 9 9 8 9\"/>\n </svg>\n </div>\n <p style={{ margin: 0, fontSize: 15, color: '#374151', fontWeight: 500 }}>\n Drop your CAS PDF here\n </p>\n <p style={{ margin: '6px 0 0', fontSize: 13, color: '#9ca3af' }}>\n or click to browse\n </p>\n </div>\n <div style={{ \n marginTop: 12, \n fontSize: 11, \n color: '#9ca3af', \n textAlign: 'center' \n }}>\n Supported: CAMS, KFintech, CDSL, NSDL statements\n </div>\n </div>\n );\n }\n\n return (\n <div>\n <h3 style={{ fontSize: 18, fontWeight: 600, margin: '0 0 16px', color: '#1f2937' }}>\n Enter Password\n </h3>\n \n {/* File preview */}\n <div style={{\n display: 'flex',\n alignItems: 'center',\n padding: 14,\n border: '1px solid #e5e7eb',\n borderRadius: 10,\n backgroundColor: '#f9fafb',\n marginBottom: 20,\n }}>\n <div style={{ \n width: 40, \n height: 40, \n backgroundColor: '#dbeafe', \n borderRadius: 8,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n marginRight: 12,\n }}>\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#2563eb\" strokeWidth=\"2\">\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"/>\n <polyline points=\"14 2 14 8 20 8\"/>\n </svg>\n </div>\n <div style={{ flex: 1, overflow: 'hidden' }}>\n <div style={{ \n fontWeight: 500, \n whiteSpace: 'nowrap', \n overflow: 'hidden', \n textOverflow: 'ellipsis',\n fontSize: 14,\n color: '#1f2937',\n }}>\n {file.name}\n </div>\n <div style={{ fontSize: 12, color: '#9ca3af' }}>\n {(file.size / 1024 / 1024).toFixed(2)} MB\n </div>\n </div>\n <button\n onClick={() => setFile(null)}\n style={{\n background: 'none',\n border: 'none',\n color: '#6b7280',\n cursor: 'pointer',\n fontSize: 13,\n textDecoration: 'underline',\n }}\n >\n Change\n </button>\n </div>\n\n {/* Password input */}\n <div style={{ marginBottom: 20 }}>\n <label style={{ \n display: 'block', \n marginBottom: 6, \n fontWeight: 500, \n fontSize: 13,\n color: '#374151',\n }}>\n PDF Password\n </label>\n <input\n type=\"password\"\n placeholder=\"Usually your PAN (e.g. ABCDE1234F)\"\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n style={{\n width: '100%',\n padding: '12px 14px',\n fontSize: 16,\n border: '1px solid #d1d5db',\n borderRadius: 8,\n boxSizing: 'border-box',\n }}\n />\n <div style={{ \n fontSize: 11, \n color: '#9ca3af', \n marginTop: 6,\n display: 'flex',\n gap: 16,\n }}>\n <span>Common passwords:</span>\n <span>PAN in CAPS</span>\n <span>DOB (DDMMYYYY)</span>\n </div>\n </div>\n\n <button\n onClick={handleSubmit}\n style={{\n width: '100%',\n padding: '16px 24px',\n fontSize: 16,\n fontWeight: 600,\n backgroundColor: '#2563eb',\n color: '#fff',\n border: 'none',\n borderRadius: 8,\n cursor: 'pointer',\n transition: 'background-color 0.2s',\n }}\n >\n Import Investments\n </button>\n </div>\n );\n};\n","import React, { useState, useEffect } from 'react';\n\ninterface FetchModeProps {\n prefill?: { pan?: string; email?: string };\n onSubmit: (pan: string, email: string) => Promise<void>;\n onBack: () => void;\n isLoading: boolean;\n}\n\nexport const FetchMode: React.FC<FetchModeProps> = ({ \n prefill, \n onSubmit, \n onBack,\n isLoading \n}) => {\n const [pan, setPan] = useState(prefill?.pan || '');\n const [email, setEmail] = useState(prefill?.email || '');\n const [error, setError] = useState('');\n\n useEffect(() => {\n if (prefill) {\n if (prefill.pan) setPan(prefill.pan);\n if (prefill.email) setEmail(prefill.email);\n }\n }, [prefill]);\n\n const validatePan = (value: string) => /^[A-Z]{5}[0-9]{4}[A-Z]{1}$/.test(value);\n const validateEmail = (value: string) => /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError('');\n\n const upperPan = pan.toUpperCase();\n if (!validatePan(upperPan)) {\n setError('Invalid PAN format (e.g. ABCDE1234F)');\n return;\n }\n if (!validateEmail(email)) {\n setError('Invalid email format');\n return;\n }\n\n try {\n await onSubmit(upperPan, email);\n } catch (err: any) {\n setError(err.message || 'Failed to submit request');\n }\n };\n\n if (isLoading) {\n return (\n <div style={{ \n textAlign: 'center', \n padding: '60px 20px',\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n }}>\n <div style={{ \n width: 48, \n height: 48, \n border: '3px solid #e5e7eb',\n borderTopColor: '#2563eb',\n borderRadius: '50%',\n animation: 'spin 1s linear infinite',\n marginBottom: 24,\n }} />\n <style>{`@keyframes spin { to { transform: rotate(360deg); } }`}</style>\n <h3 style={{ margin: 0, fontSize: 18, fontWeight: 600, color: '#1f2937' }}>\n Sending Request...\n </h3>\n <p style={{ color: '#6b7280', marginTop: 8, fontSize: 14 }}>\n You'll receive your statement via email shortly\n </p>\n </div>\n );\n }\n\n return (\n <div>\n <h2 style={{ fontSize: 20, fontWeight: 700, margin: '0 0 6px', color: '#1f2937' }}>\n Request CAS via Email\n </h2>\n <p style={{ fontSize: 14, color: '#6b7280', margin: '0 0 20px', lineHeight: 1.5 }}>\n KFintech will send your statement in 2-5 minutes\n </p>\n \n {/* Info box */}\n <div style={{\n backgroundColor: '#f9fafb',\n border: '1px solid #e5e7eb',\n borderRadius: 8,\n padding: 12,\n marginBottom: 20,\n fontSize: 12,\n color: '#6b7280',\n }}>\n <strong style={{ color: '#374151' }}>Note:</strong> Use the email registered with your mutual fund investments\n </div>\n\n <form onSubmit={handleSubmit}>\n <div style={{ marginBottom: 16 }}>\n <label style={{ \n display: 'block', \n fontSize: 13, \n fontWeight: 500, \n color: '#374151',\n marginBottom: 6,\n }}>\n PAN Number\n </label>\n <input\n type=\"text\"\n value={pan}\n onChange={(e) => setPan(e.target.value.toUpperCase())}\n placeholder=\"ABCDE1234F\"\n maxLength={10}\n style={{\n width: '100%',\n height: 46,\n padding: '0 14px',\n fontSize: 16,\n border: '1px solid #d1d5db',\n borderRadius: 8,\n boxSizing: 'border-box',\n textTransform: 'uppercase',\n }}\n />\n </div>\n\n <div style={{ marginBottom: 20 }}>\n <label style={{ \n display: 'block', \n fontSize: 13, \n fontWeight: 500, \n color: '#374151',\n marginBottom: 6,\n }}>\n Email Address\n </label>\n <input\n type=\"email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n placeholder=\"you@example.com\"\n style={{\n width: '100%',\n height: 46,\n padding: '0 14px',\n fontSize: 16,\n border: '1px solid #d1d5db',\n borderRadius: 8,\n boxSizing: 'border-box',\n }}\n />\n <div style={{ fontSize: 11, color: '#9ca3af', marginTop: 4 }}>\n Statement will be sent to this email\n </div>\n </div>\n\n {error && (\n <div style={{ \n color: '#dc2626', \n fontSize: 13, \n marginBottom: 16,\n padding: '10px 12px',\n backgroundColor: '#fef2f2',\n border: '1px solid #fecaca',\n borderRadius: 8,\n }}>\n {error}\n </div>\n )}\n\n <button\n type=\"submit\"\n style={{\n width: '100%',\n height: 50,\n fontSize: 16,\n fontWeight: 600,\n backgroundColor: '#2563eb',\n color: '#fff',\n border: 'none',\n borderRadius: 8,\n cursor: 'pointer',\n transition: 'background-color 0.2s',\n }}\n >\n Request Statement\n </button>\n\n <div style={{ textAlign: 'center', marginTop: 16 }}>\n <button\n type=\"button\"\n onClick={onBack}\n style={{\n background: 'none',\n border: 'none',\n color: '#6b7280',\n fontSize: 13,\n cursor: 'pointer',\n textDecoration: 'underline',\n }}\n >\n ← I already have my file\n </button>\n </div>\n </form>\n </div>\n );\n};\n","import React, { useState, useEffect } from 'react';\n\ntype Step = 'INPUT' | 'OTP' | 'LOADING' | 'SUCCESS' | 'ERROR';\n\ninterface CDSLFetchModeProps {\n prefill?: { pan?: string; boId?: string; dob?: string };\n onRequestOtp: (pan: string, boId: string, dob: string) => Promise<string>; // Returns session_id\n onVerifyOtp: (sessionId: string, otp: string, pan: string) => Promise<void>; // pan passed for statement password\n onBack: () => void;\n}\n\nexport const CDSLFetchMode: React.FC<CDSLFetchModeProps> = ({\n prefill,\n onRequestOtp,\n onVerifyOtp,\n onBack,\n}) => {\n const [step, setStep] = useState<Step>('INPUT');\n const [pan, setPan] = useState(prefill?.pan || '');\n const [boId, setBoId] = useState(prefill?.boId || '');\n const [dob, setDob] = useState(prefill?.dob || '');\n const [otp, setOtp] = useState('');\n const [sessionId, setSessionId] = useState('');\n const [error, setError] = useState('');\n const [isLoading, setIsLoading] = useState(false);\n\n useEffect(() => {\n if (prefill) {\n if (prefill.pan) setPan(prefill.pan);\n if (prefill.boId) setBoId(prefill.boId);\n if (prefill.dob) setDob(prefill.dob);\n }\n }, [prefill]);\n\n const validatePan = (value: string) => /^[A-Z]{5}[0-9]{4}[A-Z]{1}$/.test(value);\n const validateBoId = (value: string) => /^\\d{16}$/.test(value);\n const validateDob = (value: string) => /^\\d{4}-\\d{2}-\\d{2}$/.test(value);\n\n const handleRequestOtp = async (e: React.FormEvent) => {\n e.preventDefault();\n setError('');\n\n const upperPan = pan.toUpperCase();\n if (!validatePan(upperPan)) {\n setError('Invalid PAN format (e.g. ABCDE1234F)');\n return;\n }\n if (!validateBoId(boId)) {\n setError('BO ID must be 16 digits');\n return;\n }\n if (!validateDob(dob)) {\n setError('Date of birth must be YYYY-MM-DD');\n return;\n }\n\n setIsLoading(true);\n try {\n const sid = await onRequestOtp(upperPan, boId, dob);\n setSessionId(sid);\n setStep('OTP');\n } catch (err: any) {\n setError(err.message || 'Failed to request OTP');\n } finally {\n setIsLoading(false);\n }\n };\n\n const handleVerifyOtp = async (e: React.FormEvent) => {\n e.preventDefault();\n setError('');\n\n if (otp.length !== 4) {\n setError('Please enter the 4-digit OTP');\n return;\n }\n\n setIsLoading(true);\n setStep('LOADING');\n try {\n await onVerifyOtp(sessionId, otp, pan.toUpperCase()); // Pass PAN as password for parsing\n setStep('SUCCESS');\n } catch (err: any) {\n setError(err.message || 'Something went wrong. Please try again.');\n setStep('ERROR');\n setIsLoading(false);\n }\n };\n\n // Error state with retry\n if (step === 'ERROR') {\n return (\n <div style={{\n textAlign: 'center',\n padding: '40px 20px',\n }}>\n <div style={{\n width: 56,\n height: 56,\n backgroundColor: '#fef2f2',\n borderRadius: '50%',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n margin: '0 auto 20px',\n }}>\n <svg width=\"28\" height=\"28\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#dc2626\" strokeWidth=\"2\">\n <circle cx=\"12\" cy=\"12\" r=\"10\"/>\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"/>\n <line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"/>\n </svg>\n </div>\n <h3 style={{ margin: '0 0 8px', fontSize: 18, fontWeight: 600, color: '#1f2937' }}>\n Import Failed\n </h3>\n <p style={{ color: '#6b7280', fontSize: 14, margin: '0 0 24px', lineHeight: 1.5 }}>\n {error || 'Something went wrong while fetching your portfolio.'}\n </p>\n <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>\n <button\n onClick={() => { setStep('OTP'); setError(''); setOtp(''); }}\n style={{\n width: '100%',\n height: 46,\n fontSize: 15,\n fontWeight: 600,\n backgroundColor: '#2563eb',\n color: '#fff',\n border: 'none',\n borderRadius: 8,\n cursor: 'pointer',\n }}\n >\n Try Again\n </button>\n <button\n onClick={() => { setStep('INPUT'); setError(''); setOtp(''); }}\n style={{\n width: '100%',\n height: 46,\n fontSize: 15,\n fontWeight: 500,\n backgroundColor: '#fff',\n color: '#6b7280',\n border: '1px solid #e5e7eb',\n borderRadius: 8,\n cursor: 'pointer',\n }}\n >\n Start Over\n </button>\n </div>\n </div>\n );\n }\n\n // Loading state\n if (step === 'LOADING') {\n return (\n <div style={{\n textAlign: 'center',\n padding: '60px 20px',\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n }}>\n <div style={{\n width: 48,\n height: 48,\n border: '3px solid #e5e7eb',\n borderTopColor: '#2563eb',\n borderRadius: '50%',\n animation: 'spin 1s linear infinite',\n marginBottom: 24,\n }} />\n <style>{`@keyframes spin { to { transform: rotate(360deg); } }`}</style>\n <h3 style={{ margin: 0, fontSize: 18, fontWeight: 600, color: '#1f2937' }}>\n Importing Your Portfolio\n </h3>\n <p style={{ color: '#6b7280', marginTop: 8, fontSize: 14 }}>\n Securely fetching your holdings...\n </p>\n </div>\n );\n }\n\n // Success state\n if (step === 'SUCCESS') {\n return (\n <div style={{\n textAlign: 'center',\n padding: '40px 20px',\n }}>\n <div style={{\n width: 56,\n height: 56,\n backgroundColor: '#dcfce7',\n borderRadius: '50%',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n margin: '0 auto 20px',\n }}>\n <svg width=\"28\" height=\"28\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#16a34a\" strokeWidth=\"2.5\">\n <polyline points=\"20 6 9 17 4 12\"/>\n </svg>\n </div>\n <h3 style={{ margin: '0 0 8px', fontSize: 20, fontWeight: 600, color: '#1f2937' }}>\n Portfolio Imported!\n </h3>\n <p style={{ color: '#6b7280', fontSize: 14, margin: 0 }}>\n Your demat holdings are now available\n </p>\n </div>\n );\n }\n\n // OTP input step\n if (step === 'OTP') {\n return (\n <div>\n <h2 style={{ fontSize: 20, fontWeight: 700, margin: '0 0 6px', color: '#1f2937' }}>\n Verify OTP\n </h2>\n <p style={{ fontSize: 14, color: '#6b7280', margin: '0 0 20px', lineHeight: 1.5 }}>\n CDSL has sent an OTP to your registered mobile\n </p>\n\n <form onSubmit={handleVerifyOtp}>\n <div style={{ marginBottom: 20 }}>\n <label style={{\n display: 'block',\n fontSize: 13,\n fontWeight: 500,\n color: '#374151',\n marginBottom: 6,\n }}>\n OTP Code\n </label>\n <input\n type=\"text\"\n value={otp}\n onChange={(e) => setOtp(e.target.value.replace(/\\D/g, '').slice(0, 4))}\n placeholder=\"••••\"\n maxLength={4}\n autoFocus\n style={{\n width: '100%',\n height: 50,\n padding: '0 14px',\n fontSize: 20,\n fontWeight: 600,\n letterSpacing: 8,\n textAlign: 'center',\n border: '1px solid #d1d5db',\n borderRadius: 8,\n boxSizing: 'border-box',\n }}\n />\n </div>\n\n {error && (\n <div style={{\n color: '#dc2626',\n fontSize: 13,\n marginBottom: 16,\n padding: '10px 12px',\n backgroundColor: '#fef2f2',\n border: '1px solid #fecaca',\n borderRadius: 8,\n }}>\n {error}\n </div>\n )}\n\n <button\n type=\"submit\"\n disabled={isLoading}\n style={{\n width: '100%',\n height: 50,\n fontSize: 16,\n fontWeight: 600,\n backgroundColor: isLoading ? '#93c5fd' : '#2563eb',\n color: '#fff',\n border: 'none',\n borderRadius: 8,\n cursor: isLoading ? 'not-allowed' : 'pointer',\n }}\n >\n {isLoading ? 'Verifying...' : 'Import Portfolio'}\n </button>\n\n <div style={{ textAlign: 'center', marginTop: 16 }}>\n <button\n type=\"button\"\n onClick={() => { setStep('INPUT'); setError(''); }}\n style={{\n background: 'none',\n border: 'none',\n color: '#6b7280',\n fontSize: 13,\n cursor: 'pointer',\n textDecoration: 'underline',\n }}\n >\n ← Go back\n </button>\n </div>\n </form>\n </div>\n );\n }\n\n // Input step (default)\n return (\n <div>\n <h2 style={{ fontSize: 20, fontWeight: 700, margin: '0 0 6px', color: '#1f2937' }}>\n Import from CDSL\n </h2>\n <p style={{ fontSize: 14, color: '#6b7280', margin: '0 0 20px', lineHeight: 1.5 }}>\n Securely fetch your demat holdings\n </p>\n\n <div style={{\n backgroundColor: '#f9fafb',\n border: '1px solid #e5e7eb',\n borderRadius: 8,\n padding: 12,\n marginBottom: 20,\n fontSize: 12,\n color: '#6b7280',\n }}>\n <strong style={{ color: '#374151' }}>Where to find BO ID:</strong> Check your broker app under Demat Details, or any CDSL statement\n </div>\n\n <form onSubmit={handleRequestOtp}>\n <div style={{ marginBottom: 16 }}>\n <label style={{\n display: 'block',\n fontSize: 13,\n fontWeight: 500,\n color: '#374151',\n marginBottom: 6,\n }}>\n PAN Number\n </label>\n <input\n type=\"text\"\n value={pan}\n onChange={(e) => setPan(e.target.value.toUpperCase())}\n placeholder=\"ABCDE1234F\"\n maxLength={10}\n style={{\n width: '100%',\n height: 46,\n padding: '0 14px',\n fontSize: 16,\n border: '1px solid #d1d5db',\n borderRadius: 8,\n boxSizing: 'border-box',\n textTransform: 'uppercase',\n }}\n />\n </div>\n\n <div style={{ marginBottom: 16 }}>\n <label style={{\n display: 'block',\n fontSize: 13,\n fontWeight: 500,\n color: '#374151',\n marginBottom: 6,\n }}>\n BO ID (16 digits)\n </label>\n <input\n type=\"text\"\n value={boId}\n onChange={(e) => setBoId(e.target.value.replace(/\\D/g, '').slice(0, 16))}\n placeholder=\"1234567890123456\"\n maxLength={16}\n style={{\n width: '100%',\n height: 46,\n padding: '0 14px',\n fontSize: 16,\n border: '1px solid #d1d5db',\n borderRadius: 8,\n boxSizing: 'border-box',\n }}\n />\n </div>\n\n <div style={{ marginBottom: 20 }}>\n <label style={{\n display: 'block',\n fontSize: 13,\n fontWeight: 500,\n color: '#374151',\n marginBottom: 6,\n }}>\n Date of Birth\n </label>\n <input\n type=\"date\"\n value={dob}\n onChange={(e) => setDob(e.target.value)}\n style={{\n width: '100%',\n height: 46,\n padding: '0 14px',\n fontSize: 16,\n border: '1px solid #d1d5db',\n borderRadius: 8,\n boxSizing: 'border-box',\n }}\n />\n </div>\n\n {error && (\n <div style={{\n color: '#dc2626',\n fontSize: 13,\n marginBottom: 16,\n padding: '10px 12px',\n backgroundColor: '#fef2f2',\n border: '1px solid #fecaca',\n borderRadius: 8,\n }}>\n {error}\n </div>\n )}\n\n <button\n type=\"submit\"\n disabled={isLoading}\n style={{\n width: '100%',\n height: 50,\n fontSize: 16,\n fontWeight: 600,\n backgroundColor: isLoading ? '#93c5fd' : '#2563eb',\n color: '#fff',\n border: 'none',\n borderRadius: 8,\n cursor: isLoading ? 'not-allowed' : 'pointer',\n }}\n >\n {isLoading ? 'Requesting OTP...' : 'Request OTP'}\n </button>\n\n <div style={{ textAlign: 'center', marginTop: 16 }}>\n <button\n type=\"button\"\n onClick={onBack}\n style={{\n background: 'none',\n border: 'none',\n color: '#6b7280',\n fontSize: 13,\n cursor: 'pointer',\n textDecoration: 'underline',\n }}\n >\n ← I already have my file\n </button>\n </div>\n </form>\n </div>\n );\n};\n","import React, { useState, useEffect, useRef } from 'react';\nimport { Modal } from './Modal';\nimport { ShortcutLinks } from './ShortcutLinks';\nimport { UploadZone } from './UploadZone';\nimport { FetchMode } from './FetchMode';\nimport { CDSLFetchMode } from './CDSLFetchMode';\nimport { createApiClient, parseStatement, parseStatementFromUrl, generateCAS, cdslFetchRequestOtp, cdslFetchVerifyOtp } from '../utils/api';\nimport type { \n PortfolioConnectConfig, \n PortfolioType,\n ParsedData, \n PortfolioConnectEvent, \n PortfolioConnectError,\n BrokerInfo,\n // Backward compatible aliases used internally\n CASType,\n CASConnectEvent,\n CASConnectError,\n} from '../types';\n\nconst DEFAULT_LOGO_URL = 'https://casparser.in/assets/images/section-navigation01-image01.png';\nconst BROKER_LOGO_BASE = 'https://assets.smallcase.com/smallcase/assets/brokerLogo/small';\n\nconst CAS_PORTALS: Record<CASType, { name: string; url: string }> = {\n 'CAMS_KFINTECH': { name: 'KFintech', url: 'https://mfs.kfintech.com/investor/General/ConsolidatedAccountStatement' },\n 'CDSL': { name: 'CDSL', url: 'https://www.cdslindia.com/cas/logincas.aspx' },\n 'NSDL': { name: 'NSDL', url: 'https://nsdlcas.nsdl.com/' },\n};\n\n// Default broker list with logos (can be overridden via config.brokers)\nconst DEFAULT_BROKERS: BrokerInfo[] = ([\n { name: 'Zerodha', depository: 'CDSL' as const, logo: `${BROKER_LOGO_BASE}/kite.svg` },\n { name: 'Groww', depository: 'CDSL' as const, logo: `${BROKER_LOGO_BASE}/groww.svg` },\n { name: 'Angel One', depository: 'CDSL' as const, logo: `${BROKER_LOGO_BASE}/angelbroking.svg` },\n { name: 'Upstox', depository: 'CDSL' as const, logo: `${BROKER_LOGO_BASE}/upstox.svg` },\n { name: '5paisa', depository: 'CDSL' as const, logo: `${BROKER_LOGO_BASE}/fivepaisa.svg` },\n { name: 'Dhan', depository: 'CDSL' as const, logo: `${BROKER_LOGO_BASE}/dhan.svg` },\n { name: 'Alice Blue', depository: 'CDSL' as const, logo: `${BROKER_LOGO_BASE}/aliceblue.svg` },\n { name: 'Fisdom', depository: 'CDSL' as const, logo: `${BROKER_LOGO_BASE}/fisdom.svg` },\n { name: 'FundzBazar', depository: 'CDSL' as const, logo: `${BROKER_LOGO_BASE}/fundzbazar.svg` },\n { name: 'HDFC SKY', depository: 'CDSL' as const, logo: `${BROKER_LOGO_BASE}/hdfcsky.svg` },\n { name: 'ICICI Direct', depository: 'NSDL' as const, logo: `${BROKER_LOGO_BASE}/icici.svg` },\n { name: 'HDFC Securities', depository: 'NSDL' as const, logo: `${BROKER_LOGO_BASE}/hdfc.svg` },\n { name: 'Kotak Securities', depository: 'NSDL' as const, logo: `${BROKER_LOGO_BASE}/kotak.svg` },\n { name: 'SBI Securities', depository: 'NSDL' as const, logo: `${BROKER_LOGO_BASE}/sbi.svg` },\n { name: 'Motilal Oswal', depository: 'NSDL' as const, logo: `${BROKER_LOGO_BASE}/motilal.svg` },\n { name: 'IIFL Capital', depository: 'NSDL' as const, logo: `${BROKER_LOGO_BASE}/iifl.svg` },\n { name: 'Nuvama Wealth', depository: 'NSDL' as const, logo: `${BROKER_LOGO_BASE}/edelweiss.svg` },\n { name: 'Trustline', depository: 'NSDL' as const, logo: `${BROKER_LOGO_BASE}/trustline.svg` },\n { name: 'AxisDirect', depository: 'NSDL' as const, logo: `${BROKER_LOGO_BASE}/axis.svg` },\n]).sort((a, b) => a.name.localeCompare(b.name));\n\ninterface PortfolioConnectWidgetProps {\n isOpen: boolean;\n onClose: () => void;\n apiKey: string;\n apiBaseUrl?: string;\n config?: PortfolioConnectConfig;\n onSuccess: (data: ParsedData, metadata: any) => void;\n onError?: (error: PortfolioConnectError) => void;\n onEvent?: (event: PortfolioConnectEvent, metadata: any) => void;\n}\n\ntype WidgetMode = 'LOCATE' | 'MF_OPTIONS' | 'SELECT_BROKER' | 'DEMAT_OPTIONS' | 'UPLOAD' | 'FETCH' | 'CDSL_FETCH';\n\nexport const PortfolioConnectWidget: React.FC<PortfolioConnectWidgetProps> = ({\n isOpen,\n onClose,\n apiKey,\n apiBaseUrl,\n config = {},\n onSuccess,\n onError,\n onEvent,\n}) => {\n const [mode, setMode] = useState<WidgetMode>('LOCATE');\n const [selectedType, setSelectedType] = useState<CASType>('CAMS_KFINTECH');\n const [isProcessing, setIsProcessing] = useState(false);\n const [progress, setProgress] = useState(0);\n const [fetchLoading, setFetchLoading] = useState(false);\n const [lastError, setLastError] = useState<CASConnectError | null>(null);\n const [selectedBroker, setSelectedBroker] = useState<string | null>(null);\n \n // Use ref to avoid stale closure issues and prevent infinite loops\n const onEventRef = useRef(onEvent);\n onEventRef.current = onEvent;\n \n // Track progress interval for cleanup on unmount\n const progressIntervalRef = useRef<NodeJS.Timeout | null>(null);\n \n // Cleanup interval on unmount to prevent memory leaks\n useEffect(() => {\n return () => {\n if (progressIntervalRef.current) {\n clearInterval(progressIntervalRef.current);\n progressIntervalRef.current = null;\n }\n };\n }, []);\n\n const apiClient = createApiClient(apiKey, apiBaseUrl);\n\n const emitEvent = (event: CASConnectEvent, metadata: any = {}) => {\n onEventRef.current?.(event, { timestamp: Date.now(), ...metadata });\n };\n\n // Determine allowed types from config, default to all\n const allowedTypes = config.allowedTypes || ['CAMS_KFINTECH', 'CDSL', 'NSDL'];\n const showGenerator = config.enableGenerator && selectedType === 'CAMS_KFINTECH';\n const showCdslFetch = config.enableCdslFetch && selectedType === 'CDSL';\n const showShortcuts = config.showShortcuts !== false; // Default true\n const showPortalLinks = config.showPortalLinks !== false; // Default true\n\n useEffect(() => {\n if (isOpen) {\n // Always start at home (LOCATE) screen\n const firstType = allowedTypes[0] || 'CAMS_KFINTECH';\n setSelectedType(firstType);\n setMode('LOCATE');\n setIsProcessing(false);\n setProgress(0);\n setLastError(null); // Clear any previous errors\n emitEvent('WIDGET_OPENED');\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isOpen]);\n\n const handleClose = () => {\n emitEvent('WIDGET_CLOSED');\n onClose();\n };\n\n const handleModeSwitch = (newMode: WidgetMode) => {\n setMode(newMode);\n emitEvent('MODE_SWITCHED', { from: mode, to: newMode });\n };\n\n const handleBrokerSelect = (broker: BrokerInfo | null) => {\n if (broker) {\n setSelectedBroker(broker.name);\n setSelectedType(broker.depository);\n emitEvent('BROKER_SELECTED', { broker: broker.name, depository: broker.depository });\n // If CDSL and CDSL fetch is enabled, show options\n if (broker.depository === 'CDSL' && config.enableCdslFetch) {\n setMode('DEMAT_OPTIONS');\n } else {\n setMode('UPLOAD');\n }\n } else {\n // \"Other\" selected - let user choose depository manually\n setSelectedBroker('Other');\n }\n };\n\n const handleManualDepositorySelect = (depository: 'CDSL' | 'NSDL') => {\n setSelectedType(depository);\n emitEvent('BROKER_SELECTED', { broker: 'Other', depository });\n // If CDSL and CDSL fetch is enabled, show options\n if (depository === 'CDSL' && config.enableCdslFetch) {\n setMode('DEMAT_OPTIONS');\n } else {\n setMode('UPLOAD');\n }\n };\n\n const handleFileProcess = async (file: File, password: string) => {\n setIsProcessing(true);\n setProgress(10);\n emitEvent('UPLOAD_STARTED', { filename: file.name, size: file.size });\n\n progressIntervalRef.current = setInterval(() => {\n setProgress(prev => Math.min(prev + Math.random() * 10, 90));\n }, 500);\n\n try {\n const startTime = Date.now();\n const response = await parseStatement(\n apiClient,\n file,\n password,\n (percent) => setProgress(percent)\n );\n\n if (progressIntervalRef.current) {\n clearInterval(progressIntervalRef.current);\n progressIntervalRef.current = null;\n }\n setProgress(100);\n\n const metadata = {\n filename: file.name,\n parser_type: response.cas_author || 'AUTO',\n parse_duration_ms: Date.now() - startTime,\n };\n\n emitEvent('PARSE_SUCCESS', metadata);\n\n setTimeout(() => {\n onSuccess(response, metadata);\n handleClose();\n }, 500);\n\n } catch (error: any) {\n if (progressIntervalRef.current) {\n clearInterval(progressIntervalRef.current);\n progressIntervalRef.current = null;\n }\n setIsProcessing(false);\n setProgress(0);\n\n const casError: CASConnectError = {\n code: 'PARSE_ERROR',\n message: error.response?.data?.msg || error.message || 'Failed to parse statement',\n details: error.response?.data,\n };\n\n emitEvent('PARSE_ERROR', { error: casError });\n setLastError(casError); // Show error in widget, let user retry\n onError?.(casError);\n }\n };\n\n const handleRetry = () => {\n setLastError(null);\n setMode('UPLOAD');\n };\n\n const handleFetchSubmit = async (pan: string, email: string) => {\n setFetchLoading(true);\n emitEvent('GENERATOR_STARTED', { pan: pan.slice(0, 4) + '***' });\n\n try {\n // Pass generator config options (dateRange, password) if provided\n await generateCAS(apiClient, email, pan, config.generator);\n emitEvent('GENERATOR_SUCCESS');\n setFetchLoading(false);\n handleModeSwitch('LOCATE');\n } catch (error: any) {\n setFetchLoading(false);\n const casError: CASConnectError = {\n code: 'GENERATOR_ERROR',\n message: error.response?.data?.message || error.message || 'Failed to request statement',\n details: error.response?.data,\n };\n emitEvent('GENERATOR_ERROR', { error: casError });\n throw new Error(casError.message);\n }\n };\n\n // CDSL Fetch handlers\n const handleCdslRequestOtp = async (pan: string, boId: string, dob: string): Promise<string> => {\n emitEvent('CDSL_FETCH_STARTED', { pan: pan.slice(0, 4) + '***' });\n \n try {\n const response = await cdslFetchRequestOtp(apiClient, pan, boId, dob);\n emitEvent('CDSL_OTP_SENT', { session_id: response.session_id });\n return response.session_id;\n } catch (error: any) {\n const casError: CASConnectError = {\n code: 'CDSL_FETCH_ERROR',\n message: error.message || 'Failed to request OTP',\n details: error.response?.data,\n };\n emitEvent('CDSL_FETCH_ERROR', { error: casError });\n throw new Error(casError.message);\n }\n };\n\n const handleCdslVerifyOtp = async (sessionId: string, otp: string, pan: string): Promise<void> => {\n try {\n const response = await cdslFetchVerifyOtp(apiClient, sessionId, otp);\n emitEvent('CDSL_OTP_VERIFIED');\n \n // Files are ready - emit event with all file URLs for developer interception\n emitEvent('CDSL_FETCH_SUCCESS', { \n files: response.files,\n count: response.files.length,\n });\n \n // Auto-parse the most recent file (first in list) - PAN is the password\n await handleCdslAutoParse(response.files, pan);\n } catch (error: any) {\n const casError: CASConnectError = {\n code: 'CDSL_FETCH_ERROR',\n message: error.message || 'Failed to verify OTP',\n details: error.response?.data,\n };\n emitEvent('CDSL_FETCH_ERROR', { error: casError });\n throw new Error(casError.message);\n }\n };\n\n const handleCdslAutoParse = async (files: Array<{ filename: string; url: string }>, pan: string) => {\n if (!files || files.length === 0) {\n const casError: CASConnectError = {\n code: 'CDSL_FETCH_ERROR',\n message: 'No files returned from CDSL',\n };\n emitEvent('CDSL_FETCH_ERROR', { error: casError });\n onError?.(casError);\n return;\n }\n\n // Use the first (most recent) file\n const targetFile = files[0];\n setIsProcessing(true);\n setProgress(10);\n emitEvent('PARSE_STARTED', { filename: targetFile.filename, source: 'CDSL_FETCH' });\n\n try {\n const startTime = Date.now();\n \n // Parse via URL - smart parse API accepts pdf_url, PAN is the password\n const response = await parseStatementFromUrl(\n apiClient,\n targetFile.url,\n pan, // CDSL files are password protected with PAN\n (percent) => setProgress(percent)\n );\n\n setProgress(100);\n\n const metadata = {\n filename: targetFile.filename,\n parser_type: response.cas_author || 'CDSL',\n parse_duration_ms: Date.now() - startTime,\n source: 'CDSL_FETCH',\n all_files: files, // Include all file URLs for developer reference\n };\n\n emitEvent('PARSE_SUCCESS', metadata);\n\n setTimeout(() => {\n onSuccess(response, metadata);\n handleClose();\n }, 500);\n\n } catch (error: any) {\n setIsProcessing(false);\n setProgress(0);\n\n const casError: CASConnectError = {\n code: 'PARSE_ERROR',\n message: error.response?.data?.msg || error.message || 'Failed to parse CDSL statement',\n details: { ...error.response?.data, files },\n };\n\n emitEvent('PARSE_ERROR', { error: casError });\n onError?.(casError);\n }\n };\n\n const renderContent = () => {\n // Show error with retry option - don't crash the widget\n if (lastError) {\n return (\n <div style={{ textAlign: 'center', padding: '20px 0' }}>\n <div style={{ \n width: 56, \n height: 56, \n backgroundColor: '#fef2f2', \n borderRadius: '50%', \n display: 'flex', \n alignItems: 'center', \n justifyContent: 'center',\n margin: '0 auto 16px',\n }}>\n <svg width=\"28\" height=\"28\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#dc2626\" strokeWidth=\"2\">\n <circle cx=\"12\" cy=\"12\" r=\"10\"/>\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"/>\n <line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"/>\n </svg>\n </div>\n <h3 style={{ fontSize: 18, fontWeight: 600, color: '#111827', margin: '0 0 8px' }}>\n Something went wrong\n </h3>\n <p style={{ fontSize: 14, color: '#6b7280', margin: '0 0 20px', lineHeight: 1.5 }}>\n {lastError.message}\n </p>\n <div style={{ display: 'flex', gap: 12, justifyContent: 'center' }}>\n <button\n onClick={handleRetry}\n style={{\n padding: '12px 24px',\n fontSize: 14,\n fontWeight: 600,\n backgroundColor: '#2563eb',\n color: '#fff',\n border: 'none',\n borderRadius: 8,\n cursor: 'pointer',\n }}\n >\n Try Again\n </button>\n <button\n onClick={handleClose}\n style={{\n padding: '12px 24px',\n fontSize: 14,\n fontWeight: 500,\n backgroundColor: '#f3f4f6',\n color: '#374151',\n border: 'none',\n borderRadius: 8,\n cursor: 'pointer',\n }}\n >\n Close\n </button>\n </div>\n </div>\n );\n }\n\n if (mode === 'FETCH' && config.enableGenerator) {\n return (\n <FetchMode\n prefill={config.prefill}\n onSubmit={handleFetchSubmit}\n onBack={() => handleModeSwitch('LOCATE')}\n isLoading={fetchLoading}\n />\n );\n }\n\n if (mode === 'CDSL_FETCH' && config.enableCdslFetch) {\n return (\n <CDSLFetchMode\n prefill={config.prefill}\n onRequestOtp={handleCdslRequestOtp}\n onVerifyOtp={handleCdslVerifyOtp}\n onBack={() => handleModeSwitch('LOCATE')}\n />\n );\n }\n\n if (mode === 'UPLOAD') {\n const currentPortal = CAS_PORTALS[selectedType];\n return (\n <div>\n <UploadZone\n onFileSelect={handleFileProcess}\n isProcessing={isProcessing}\n progress={progress}\n />\n \n {/* Show shortcuts only on upload screen when relevant */}\n {showShortcuts && (\n <div style={{ marginTop: 16 }}>\n <ShortcutLinks \n selectedType={selectedType}\n onSearchClick={(provider) => emitEvent('SEARCH_CLICKED', { provider })} \n />\n </div>\n )}\n \n {/* Portal link */}\n {showPortalLinks && (\n <div style={{ marginTop: 16, textAlign: 'center' }}>\n <a\n href={currentPortal.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n onClick={() => emitEvent('PORTAL_CLICKED', { portal: selectedType })}\n style={{ textDecoration: 'none', color: '#6b7280', fontSize: 13 }}\n >\n Don't have your statement? <span style={{ color: '#2563eb' }}>Download from {currentPortal.name}</span>\n </a>\n </div>\n )}\n </div>\n );\n }\n\n // MF_OPTIONS mode - show upload or KFintech eCAS options\n if (mode === 'MF_OPTIONS') {\n return (\n <div>\n <div style={{ textAlign: 'center', marginBottom: 20 }}>\n <h3 style={{ fontSize: 18, fontWeight: 600, color: '#111827', margin: '0 0 8px' }}>\n Mutual Funds\n </h3>\n <p style={{ fontSize: 14, color: '#6b7280', margin: 0 }}>\n CAMS & KFintech consolidated statement\n </p>\n </div>\n <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>\n <button\n onClick={() => handleModeSwitch('UPLOAD')}\n style={{\n width: '100%',\n padding: '16px 20px',\n fontSize: 15,\n fontWeight: 600,\n backgroundColor: '#2563eb',\n color: '#fff',\n border: 'none',\n borderRadius: 12,\n cursor: 'pointer',\n textAlign: 'left',\n }}\n >\n <span style={{ display: 'block' }}>Upload Statement</span>\n <span style={{ fontSize: 12, fontWeight: 400, opacity: 0.85 }}>\n I have my CAS PDF file\n </span>\n </button>\n \n {config.enableGenerator && (\n <button\n onClick={() => handleModeSwitch('FETCH')}\n style={{\n width: '100%',\n padding: '16px 20px',\n fontSize: 15,\n fontWeight: 600,\n backgroundColor: '#fff',\n color: '#166534',\n border: '2px solid #bbf7d0',\n borderRadius: 12,\n cursor: 'pointer',\n textAlign: 'left',\n }}\n >\n <span style={{ display: 'block' }}>Request via Email</span>\n <span style={{ fontSize: 12, fontWeight: 400, color: '#6b7280' }}>\n Get CAS from KFintech\n </span>\n </button>\n )}\n </div>\n </div>\n );\n }\n\n // DEMAT_OPTIONS mode - show upload or CDSL fetch options (for CDSL only)\n if (mode === 'DEMAT_OPTIONS') {\n return (\n <div>\n <div style={{ textAlign: 'center', marginBottom: 20 }}>\n <h3 style={{ fontSize: 18, fontWeight: 600, color: '#111827', margin: '0 0 8px' }}>\n {selectedBroker ? `${selectedBroker} (CDSL)` : 'CDSL Demat'}\n </h3>\n <p style={{ fontSize: 14, color: '#6b7280', margin: 0 }}>\n How would you like to import?\n </p>\n </div>\n <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>\n <button\n onClick={() => handleModeSwitch('UPLOAD')}\n style={{\n width: '100%',\n padding: '16px 20px',\n fontSize: 15,\n fontWeight: 600,\n backgroundColor: '#2563eb',\n color: '#fff',\n border: 'none',\n borderRadius: 12,\n cursor: 'pointer',\n textAlign: 'left',\n }}\n >\n <span style={{ display: 'block' }}>Upload Statement</span>\n <span style={{ fontSize: 12, fontWeight: 400, opacity: 0.85 }}>\n I have my CDSL CAS PDF file\n </span>\n </button>\n \n <button\n onClick={() => handleModeSwitch('CDSL_FETCH')}\n style={{\n width: '100%',\n padding: '16px 20px',\n fontSize: 15,\n fontWeight: 600,\n backgroundColor: '#fff',\n color: '#1e40af',\n border: '2px solid #bfdbfe',\n borderRadius: 12,\n cursor: 'pointer',\n textAlign: 'left',\n }}\n >\n <span style={{ display: 'block' }}>Fetch from CDSL</span>\n <span style={{ fontSize: 12, fontWeight: 400, color: '#6b7280' }}>\n OTP verification required\n </span>\n </button>\n </div>\n </div>\n );\n }\n\n // SELECT_BROKER mode - for Stocks/Bonds/ETFs\n if (mode === 'SELECT_BROKER') {\n const showManualSelection = selectedBroker === 'Other';\n \n if (showManualSelection) {\n // Show CDSL/NSDL manual selection\n return (\n <div>\n <div style={{ textAlign: 'center', marginBottom: 20 }}>\n <h3 style={{ fontSize: 18, fontWeight: 600, color: '#111827', margin: '0 0 8px' }}>\n Select Your Depository\n </h3>\n <p style={{ fontSize: 14, color: '#6b7280', margin: 0 }}>\n Check your demat account statement to find your depository\n </p>\n </div>\n <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>\n <button\n onClick={() => handleManualDepositorySelect('CDSL')}\n style={{\n padding: '16px 20px',\n fontSize: 15,\n fontWeight: 600,\n backgroundColor: '#fff',\n color: '#111827',\n border: '2px solid #e5e7eb',\n borderRadius: 12,\n cursor: 'pointer',\n textAlign: 'left',\n }}\n >\n <span style={{ display: 'block' }}>CDSL</span>\n <span style={{ fontSize: 12, fontWeight: 400, color: '#6b7280' }}>\n Central Depository Services Limited\n </span>\n </button>\n <button\n onClick={() => handleManualDepositorySelect('NSDL')}\n style={{\n padding: '16px 20px',\n fontSize: 15,\n fontWeight: 600,\n backgroundColor: '#fff',\n color: '#111827',\n border: '2px solid #e5e7eb',\n borderRadius: 12,\n cursor: 'pointer',\n textAlign: 'left',\n }}\n >\n <span style={{ display: 'block' }}>NSDL</span>\n <span style={{ fontSize: 12, fontWeight: 400, color: '#6b7280' }}>\n National Securities Depository Limited\n </span>\n </button>\n </div>\n </div>\n );\n }\n \n // Show broker list - use config.brokers if provided, otherwise default\n const brokerList = config.brokers || DEFAULT_BROKERS;\n \n return (\n <div>\n <div style={{ textAlign: 'center', marginBottom: 20 }}>\n <h3 style={{ fontSize: 18, fontWeight: 600, color: '#111827', margin: '0 0 8px' }}>\n Select Your Broker\n </h3>\n <p style={{ fontSize: 14, color: '#6b7280', margin: 0 }}>\n We'll automatically detect your depository\n </p>\n </div>\n <div style={{ \n display: 'grid', \n gridTemplateColumns: 'repeat(2, 1fr)', \n gap: 10,\n maxHeight: 320,\n overflowY: 'auto',\n paddingRight: 4,\n }}>\n {brokerList.map((broker) => (\n <button\n key={broker.name}\n onClick={() => handleBrokerSelect(broker)}\n style={{\n padding: '10px 12px',\n fontSize: 13,\n fontWeight: 500,\n backgroundColor: '#fff',\n color: '#111827',\n border: '1.5px solid #e5e7eb',\n borderRadius: 10,\n cursor: 'pointer',\n textAlign: 'left',\n transition: 'all 0.15s',\n display: 'flex',\n alignItems: 'center',\n gap: 10,\n }}\n onMouseOver={(e) => {\n e.currentTarget.style.borderColor = '#2563eb';\n e.currentTarget.style.backgroundColor = '#f0f7ff';\n }}\n onMouseOut={(e) => {\n e.currentTarget.style.borderColor = '#e5e7eb';\n e.currentTarget.style.backgroundColor = '#fff';\n }}\n >\n {broker.logo && (\n <img \n src={broker.logo} \n alt={broker.name}\n style={{ width: 24, height: 24, objectFit: 'contain', flexShrink: 0 }}\n />\n )}\n <div style={{ minWidth: 0 }}>\n <span style={{ display: 'block', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{broker.name}</span>\n <span style={{ fontSize: 10, color: '#9ca3af' }}>{broker.depository}</span>\n </div>\n </button>\n ))}\n </div>\n <button\n onClick={() => {\n setSelectedBroker('Other');\n }}\n style={{\n width: '100%',\n marginTop: 12,\n padding: '12px',\n fontSize: 14,\n fontWeight: 500,\n backgroundColor: '#f9fafb',\n color: '#6b7280',\n border: '1.5px dashed #d1d5db',\n borderRadius: 10,\n cursor: 'pointer',\n }}\n >\n Other broker / I don't know\n </button>\n </div>\n );\n }\n\n // LOCATE mode (default)\n const logoUrl = config.logoUrl || DEFAULT_LOGO_URL;\n const currentPortal = CAS_PORTALS[selectedType];\n const title = config.title || 'Import Your Investments';\n const subtitle = config.subtitle || 'Mutual Funds, Stocks, Bonds — all in one place';\n\n // Check if MF and/or Demat are allowed\n const allowMutualFunds = allowedTypes.includes('CAMS_KFINTECH');\n const allowDemat = allowedTypes.includes('CDSL') || allowedTypes.includes('NSDL');\n \n return (\n <div>\n {/* Header with branding */}\n <div style={{ textAlign: 'center', marginBottom: 24 }}>\n <img \n src={logoUrl} \n alt=\"Logo\" \n style={{ width: 56, height: 56, marginBottom: 16, objectFit: 'contain' }}\n />\n <h2 style={{ fontSize: 22, fontWeight: 700, margin: 0, color: '#111827', letterSpacing: '-0.02em' }}>\n {title}\n </h2>\n <p style={{ color: '#6b7280', marginTop: 8, fontSize: 14, lineHeight: 1.5 }}>\n {subtitle}\n </p>\n </div>\n\n {/* Primary Options - Mutual Funds & Stocks */}\n <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>\n {/* Mutual Funds Option */}\n {allowMutualFunds && (\n <button\n onClick={() => {\n setSelectedType('CAMS_KFINTECH');\n setSelectedBroker(null);\n // If generator is enabled, show options; otherwise go directly to upload\n if (config.enableGenerator) {\n handleModeSwitch('MF_OPTIONS');\n } else {\n handleModeSwitch('UPLOAD');\n }\n }}\n style={{\n width: '100%',\n padding: '18px 20px',\n fontSize: 16,\n fontWeight: 600,\n backgroundColor: '#2563eb',\n color: '#fff',\n border: 'none',\n borderRadius: 12,\n cursor: 'pointer',\n textAlign: 'left',\n transition: 'all 0.2s',\n boxShadow: '0 4px 14px rgba(37, 99, 235, 0.25)',\n }}\n onMouseOver={(e) => { \n e.currentTarget.style.backgroundColor = '#1d4ed8';\n e.currentTarget.style.transform = 'translateY(-1px)';\n }}\n onMouseOut={(e) => { \n e.currentTarget.style.backgroundColor = '#2563eb';\n e.currentTarget.style.transform = 'translateY(0)';\n }}\n >\n <span style={{ display: 'block' }}>Mutual Funds</span>\n <span style={{ fontSize: 12, fontWeight: 400, opacity: 0.85 }}>\n CAMS & KFintech CAS\n </span>\n </button>\n )}\n\n {/* Stocks, Bonds, ETFs Option */}\n {allowDemat && (\n <button\n onClick={() => {\n setSelectedBroker(null);\n handleModeSwitch('SELECT_BROKER');\n }}\n style={{\n width: '100%',\n padding: '18px 20px',\n fontSize: 16,\n fontWeight: 600,\n backgroundColor: '#fff',\n color: '#111827',\n border: '2px solid #e5e7eb',\n borderRadius: 12,\n cursor: 'pointer',\n textAlign: 'left',\n transition: 'all 0.2s',\n }}\n onMouseOver={(e) => { \n e.currentTarget.style.borderColor = '#2563eb';\n e.currentTarget.style.backgroundColor = '#f0f7ff';\n }}\n onMouseOut={(e) => { \n e.currentTarget.style.borderColor = '#e5e7eb';\n e.currentTarget.style.backgroundColor = '#fff';\n }}\n >\n <span style={{ display: 'block' }}>Stocks, Bonds, ETFs</span>\n <span style={{ fontSize: 12, fontWeight: 400, color: '#6b7280' }}>\n Demat — CDSL & NSDL\n </span>\n </button>\n )}\n </div>\n </div>\n );\n };\n\n // Determine if we're in a sub-screen that should show back button\n const isSubScreen = mode !== 'LOCATE';\n const isSandbox = apiKey === 'sandbox-with-json-responses';\n\n const handleBack = () => {\n // Smart back navigation\n if (mode === 'UPLOAD') {\n if (selectedType === 'CAMS_KFINTECH' && config.enableGenerator) {\n setMode('MF_OPTIONS');\n } else if (selectedType === 'CDSL' && config.enableCdslFetch) {\n setMode('DEMAT_OPTIONS');\n } else if (selectedType === 'CDSL' || selectedType === 'NSDL') {\n setMode('SELECT_BROKER');\n } else {\n setMode('LOCATE');\n }\n } else if (mode === 'FETCH') {\n setMode('MF_OPTIONS');\n } else if (mode === 'CDSL_FETCH') {\n setMode('DEMAT_OPTIONS');\n } else if (mode === 'MF_OPTIONS' || mode === 'DEMAT_OPTIONS') {\n if (selectedType === 'CDSL' || selectedType === 'NSDL') {\n setMode('SELECT_BROKER');\n } else {\n setMode('LOCATE');\n }\n } else if (mode === 'SELECT_BROKER') {\n setMode('LOCATE');\n } else {\n setMode('LOCATE');\n }\n emitEvent('MODE_SWITCHED', { from: mode, to: 'LOCATE' });\n };\n\n return (\n <Modal \n isOpen={isOpen} \n onClose={handleClose} \n onBack={handleBack}\n showBackButton={isSubScreen}\n isSandbox={isSandbox}\n width={420}\n >\n <div style={{ padding: '28px 24px 20px' }}>\n {renderContent()}\n \n {/* Footer */}\n <div style={{ \n marginTop: 24, \n paddingTop: 16,\n borderTop: '1px solid #f3f4f6',\n textAlign: 'center',\n }}>\n <div style={{ fontSize: 11, color: '#9ca3af' }}>\n Encrypted • India-hosted\n </div>\n </div>\n </div>\n </Modal>\n );\n};\n","const DEFAULT_API_URL = 'https://portfolio-parser.api.casparser.in';\nconst DEFAULT_AUTH_URL = 'https://client-apis.casparser.in';\n\nexport interface ApiClient {\n baseUrl: string;\n apiKey: string;\n}\n\n/**\n * Creates an API client for making requests to CASParser API.\n * \n * @param accessToken - Your access token (get one at docs.casparser.in)\n * @param baseUrl - Optional custom API base URL\n * @returns API client instance\n */\nexport function createApiClient(accessToken: string, baseUrl?: string): ApiClient {\n return {\n baseUrl: baseUrl || DEFAULT_API_URL,\n apiKey: accessToken,\n };\n}\n\nexport interface AccessTokenResponse {\n access_token: string;\n token_type: 'api_key'; // Drop-in replacement for x-api-key header\n expires_in: number;\n}\n\n/**\n * Request a short-lived access token from the API key.\n * Use this on your backend to generate tokens for frontend use.\n * \n * @param apiKey - Your API key (do NOT expose this on frontend)\n * @param expiryMinutes - Token validity in minutes (max 60, default 60)\n * @param authUrl - Optional custom auth URL\n * @returns Access token response with SK_ prefixed token\n */\nexport async function requestAccessToken(\n apiKey: string,\n expiryMinutes: number = 60,\n authUrl?: string\n): Promise<AccessTokenResponse> {\n const url = authUrl || DEFAULT_AUTH_URL;\n \n const response = await fetch(`${url}/v1/access-token`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n body: JSON.stringify({\n expiry_minutes: Math.min(expiryMinutes, 60),\n }),\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n throw new Error(errorData.detail || errorData.message || 'Failed to get access token');\n }\n\n return response.json();\n}\n\n/**\n * Check if a token is an access token (SK_ prefix)\n */\nexport function isAccessToken(token: string): boolean {\n return token?.startsWith('SK_') || false;\n}\n\nexport async function parseStatement(\n client: ApiClient,\n file: File,\n password?: string,\n onProgress?: (percent: number) => void\n): Promise<any> {\n const formData = new FormData();\n formData.append('pdf_file', file);\n if (password) {\n formData.append('password', password);\n }\n\n // Simulate progress since fetch doesn't support upload progress natively\n if (onProgress) {\n onProgress(30);\n }\n\n const response = await fetch(`${client.baseUrl}/v4/smart/parse`, {\n method: 'POST',\n headers: {\n 'x-api-key': client.apiKey,\n 'Authorization': `Token ${client.apiKey}`,\n },\n body: formData,\n });\n\n if (onProgress) {\n onProgress(80);\n }\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n throw { response: { data: errorData }, message: errorData.msg || 'Request failed' };\n }\n\n return response.json();\n}\n\n/**\n * Parse a statement from a URL (used for CDSL fetch results)\n */\nexport async function parseStatementFromUrl(\n client: ApiClient,\n pdfUrl: string,\n password?: string,\n onProgress?: (percent: number) => void\n): Promise<any> {\n if (onProgress) {\n onProgress(30);\n }\n\n const body: Record<string, string> = { pdf_url: pdfUrl };\n if (password) {\n body.password = password;\n }\n\n const response = await fetch(`${client.baseUrl}/v4/smart/parse`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': client.apiKey,\n 'Authorization': `Token ${client.apiKey}`,\n },\n body: JSON.stringify(body),\n });\n\n if (onProgress) {\n onProgress(80);\n }\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n throw { response: { data: errorData }, message: errorData.msg || 'Request failed' };\n }\n\n return response.json();\n}\n\nexport interface GeneratorOptions {\n fromDate?: string;\n toDate?: string;\n password?: string;\n}\n\nexport async function generateCAS(\n client: ApiClient,\n email: string,\n pan: string,\n options?: GeneratorOptions\n): Promise<any> {\n // Format dates as YYYY-MM-DD per API spec\n const today = new Date();\n const toDate = options?.toDate || today.toISOString().split('T')[0];\n const fromDate = options?.fromDate || '2000-01-01';\n const password = options?.password || 'Abcdefghi12$';\n \n // Using the /v4/generate endpoint from portfolio-tracking\n const response = await fetch(`${client.baseUrl}/v4/generate`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': client.apiKey,\n 'Authorization': `Token ${client.apiKey}`,\n },\n body: JSON.stringify({\n email,\n pan_no: pan,\n from_date: fromDate,\n to_date: toDate,\n password,\n cas_authority: 'kfintech',\n }),\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n throw { response: { data: errorData }, message: errorData.msg || errorData.message || 'Request failed' };\n }\n\n return response.json();\n}\n\n// ============================================\n// CDSL Fetch API (2-step OTP flow)\n// ============================================\n\nexport interface CdslFetchResponse {\n status: string;\n session_id: string;\n msg: string;\n}\n\nexport interface CdslVerifyResponse {\n status: string;\n msg: string;\n files: Array<{ filename: string; url: string }>;\n}\n\nexport async function cdslFetchRequestOtp(\n client: ApiClient,\n pan: string,\n boId: string,\n dob: string\n): Promise<CdslFetchResponse> {\n const response = await fetch(`${client.baseUrl}/v4/cdsl/fetch`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': client.apiKey,\n 'Authorization': `Token ${client.apiKey}`,\n },\n body: JSON.stringify({\n pan: pan.toUpperCase(),\n bo_id: boId,\n dob,\n }),\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n throw { response: { data: errorData }, message: errorData.msg || 'Failed to request OTP' };\n }\n\n return response.json();\n}\n\nexport async function cdslFetchVerifyOtp(\n client: ApiClient,\n sessionId: string,\n otp: string,\n numPeriods: number = 6\n): Promise<CdslVerifyResponse> {\n const response = await fetch(`${client.baseUrl}/v4/cdsl/fetch/${sessionId}/verify`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': client.apiKey,\n 'Authorization': `Token ${client.apiKey}`,\n },\n body: JSON.stringify({\n otp,\n num_periods: numPeriods,\n }),\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n throw { response: { data: errorData }, message: errorData.msg || 'Failed to verify OTP' };\n }\n\n return response.json();\n}\n","import React, { useState, useCallback } from 'react';\nimport { PortfolioConnectWidget } from './components/PortfolioConnectWidget';\nimport type { PortfolioConnectProps, RenderProps } from './types';\n\nexport const PortfolioConnect: React.FC<PortfolioConnectProps> = ({\n accessToken,\n apiKey, // deprecated, use accessToken\n apiBaseUrl,\n config,\n onSuccess,\n onError,\n onExit,\n onEvent,\n children,\n}) => {\n const [isOpen, setIsOpen] = useState(false);\n \n // Support both accessToken (new) and apiKey (deprecated) - both work with x-api-key header\n const token = accessToken || apiKey;\n\n const open = useCallback(() => {\n setIsOpen(true);\n }, []);\n\n const handleClose = useCallback(() => {\n setIsOpen(false);\n onExit?.();\n }, [onExit]);\n\n const renderProps: RenderProps = {\n open,\n isReady: !!token,\n isOpen,\n };\n\n return (\n <>\n {children(renderProps)}\n <PortfolioConnectWidget\n isOpen={isOpen}\n onClose={handleClose}\n apiKey={token || ''}\n apiBaseUrl={apiBaseUrl}\n config={config}\n onSuccess={onSuccess}\n onError={onError}\n onEvent={onEvent}\n />\n </>\n );\n};\n\n// Backward compatibility alias\nexport const CASConnect = PortfolioConnect;\nexport default PortfolioConnect;\n","import React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport { PortfolioConnectWidget } from './components/PortfolioConnectWidget';\nimport type { PortfolioConnectConfig, ParsedData, ParseMetadata, PortfolioConnectError } from './types';\n\n/**\n * Configuration for the imperative open() API.\n * Used for non-React environments (Vanilla JS, Angular, Vue, etc.)\n */\nexport interface ImperativeConfig {\n /** Access token for authentication. Get yours at docs.casparser.in */\n accessToken?: string;\n /** @deprecated Use accessToken instead */\n apiKey?: string;\n /** Widget configuration options */\n config?: PortfolioConnectConfig;\n /** Called when widget is opened */\n onOpen?: () => void;\n /** Called for all widget events (useful for analytics) */\n onEvent?: (event: string, metadata: Record<string, any>) => void;\n}\n\n/**\n * Result returned from the open() promise\n */\nexport interface OpenResult {\n /** Parsed portfolio data */\n data: ParsedData;\n /** Parsing metadata (source, duration, etc.) */\n metadata: ParseMetadata;\n}\n\n/**\n * Handle returned from create() for manual control\n */\nexport interface WidgetHandle {\n /** Open the widget modal */\n open: () => void;\n /** Close the widget and cleanup */\n destroy: () => void;\n}\n\n// Track active widget instance for cleanup\nlet activeContainer: HTMLDivElement | null = null;\nlet activeRoot: ReactDOM.Root | null = null;\n\n/**\n * Cleanup any existing widget instance\n */\nfunction cleanup(): void {\n if (activeRoot) {\n activeRoot.unmount();\n activeRoot = null;\n }\n if (activeContainer && activeContainer.parentNode) {\n activeContainer.parentNode.removeChild(activeContainer);\n activeContainer = null;\n }\n}\n\n/**\n * Opens the Portfolio Connect widget and returns a promise that resolves with parsed data.\n * \n * This is the recommended API for non-React applications (Vanilla JS, Angular, Vue, etc.)\n * \n * @example\n * ```javascript\n * // Vanilla JS\n * document.getElementById('btn').onclick = async () => {\n * try {\n * const { data, metadata } = await PortfolioConnect.open({\n * apiKey: 'your_api_key',\n * config: { enableCdslFetch: true }\n * });\n * console.log('Portfolio data:', data);\n * } catch (error) {\n * if (error.message === 'Widget closed by user') {\n * console.log('User cancelled');\n * } else {\n * console.error('Error:', error);\n * }\n * }\n * };\n * ```\n * \n * @param config - Configuration options\n * @returns Promise that resolves with { data, metadata } on success, rejects on error/close\n */\nexport function open(config: ImperativeConfig): Promise<OpenResult> {\n return new Promise((resolve, reject) => {\n // Cleanup any existing instance\n cleanup();\n\n // Create container\n activeContainer = document.createElement('div');\n activeContainer.id = 'portfolio-connect-root';\n activeContainer.setAttribute('data-portfolio-connect', 'true');\n document.body.appendChild(activeContainer);\n\n // Create React root\n activeRoot = ReactDOM.createRoot(activeContainer);\n\n // Notify open\n config.onOpen?.();\n\n // Render widget\n activeRoot.render(\n React.createElement(PortfolioConnectWidget, {\n isOpen: true,\n apiKey: config.accessToken || config.apiKey || '',\n config: config.config,\n onSuccess: (data: ParsedData, metadata: ParseMetadata) => {\n cleanup();\n resolve({ data, metadata });\n },\n onClose: () => {\n cleanup();\n reject(new Error('Widget closed by user'));\n },\n onError: (error: PortfolioConnectError) => {\n cleanup();\n reject(error);\n },\n onEvent: config.onEvent,\n })\n );\n });\n}\n\n/**\n * Creates a widget handle for manual control.\n * Useful when you need to open/close the widget multiple times.\n * \n * @example\n * ```javascript\n * const widget = PortfolioConnect.create({\n * apiKey: 'your_api_key',\n * onSuccess: (data) => console.log(data),\n * });\n * \n * document.getElementById('open-btn').onclick = () => widget.open();\n * document.getElementById('close-btn').onclick = () => widget.destroy();\n * ```\n * \n * @param config - Configuration options including callbacks\n * @returns Handle with open() and destroy() methods\n */\nexport function create(config: ImperativeConfig & {\n onSuccess: (data: ParsedData, metadata: ParseMetadata) => void;\n onError?: (error: PortfolioConnectError) => void;\n onClose?: () => void;\n}): WidgetHandle {\n let container: HTMLDivElement | null = null;\n let root: ReactDOM.Root | null = null;\n let isOpen = false;\n\n function render(open: boolean): void {\n if (!container) {\n container = document.createElement('div');\n container.id = 'portfolio-connect-root';\n container.setAttribute('data-portfolio-connect', 'true');\n document.body.appendChild(container);\n root = ReactDOM.createRoot(container);\n }\n\n isOpen = open;\n\n root!.render(\n React.createElement(PortfolioConnectWidget, {\n isOpen: open,\n apiKey: config.accessToken || config.apiKey || '',\n config: config.config,\n onSuccess: (data: ParsedData, metadata: ParseMetadata) => {\n render(false);\n config.onSuccess(data, metadata);\n },\n onClose: () => {\n render(false);\n config.onClose?.();\n },\n onError: (error: PortfolioConnectError) => {\n render(false);\n config.onError?.(error);\n },\n onEvent: config.onEvent,\n })\n );\n }\n\n return {\n open: () => {\n config.onOpen?.();\n render(true);\n },\n destroy: () => {\n if (root) {\n root.unmount();\n root = null;\n }\n if (container && container.parentNode) {\n container.parentNode.removeChild(container);\n container = null;\n }\n isOpen = false;\n },\n };\n}\n","// Main exports - React components\nexport { PortfolioConnect, CASConnect } from './PortfolioConnect';\nexport { PortfolioConnectWidget } from './components/PortfolioConnectWidget';\nexport { requestAccessToken, isAccessToken } from './utils/api';\n\n// Imperative API for non-React users (Vanilla JS, Angular, Vue, etc.)\nexport { open, create } from './imperative';\nexport type { ImperativeConfig, OpenResult, WidgetHandle } from './imperative';\n\n// Backward compatibility alias\nexport { PortfolioConnectWidget as CASConnectWidget } from './components/PortfolioConnectWidget';\n\n// SDK Version\nexport const VERSION = '1.1.0';\nexport const SDK_NAME = 'Portfolio Connect';\n\n// Type exports (new names)\nexport type {\n PortfolioConnectProps,\n PortfolioConnectConfig,\n PortfolioType,\n PortfolioConnectError,\n PortfolioConnectEvent,\n ParsedData,\n InvestorInfo,\n ParseMetadata,\n EventMetadata,\n RenderProps,\n BrokerInfo,\n} from './types';\n\n// Backward compatibility type aliases\nexport type {\n CASConnectProps,\n CASConnectConfig,\n CASType,\n CASConnectError,\n CASConnectEvent,\n} from './types';\n"],"names":["Modal","isOpen","onClose","onBack","showBackButton","children","width","isSandbox","overlayRef","useRef","useEffect","document","body","style","overflow","React","createElement","ref","onClick","e","target","current","position","top","left","right","bottom","backgroundColor","display","alignItems","justifyContent","zIndex","padding","borderRadius","maxWidth","maxHeight","boxShadow","borderBottom","fontSize","fontWeight","color","textAlign","borderTopLeftRadius","borderTopRightRadius","background","border","cursor","lineHeight","transition","onMouseOver","currentTarget","onMouseOut","CAS_SENDERS","CAMS_KFINTECH","CDSL","NSDL","GmailLogo","height","viewBox","fill","d","OutlookLogo","cx","cy","rx","ry","stroke","strokeWidth","YahooLogo","getProviders","selectedType","query","type","Object","values","flat","map","s","join","encodedQuery","encodeURIComponent","name","Logo","url","ShortcutLinks","onSearchClick","providers","marginBottom","gridTemplateColumns","gap","provider","key","href","rel","flexDirection","textDecoration","onMouseEnter","borderColor","onMouseLeave","marginTop","UploadZone","onFileSelect","isProcessing","progress","file","setFile","useState","password","setPassword","isDragOver","setIsDragOver","inputRef","handleDrop","useCallback","preventDefault","droppedFile","dataTransfer","files","handleFileChange","selectedFile","margin","marginRight","points","flex","whiteSpace","textOverflow","size","toFixed","placeholder","value","onChange","boxSizing","onDragOver","onDragLeave","onDrop","click","accept","x1","y1","x2","y2","FetchMode","prefill","onSubmit","isLoading","pan","setPan","email","setEmail","error","setError","borderTopColor","animation","async","upperPan","toUpperCase","test","validateEmail","err","message","maxLength","textTransform","CDSLFetchMode","onRequestOtp","onVerifyOtp","step","setStep","boId","setBoId","dob","setDob","otp","setOtp","sessionId","setSessionId","setIsLoading","handleVerifyOtp","length","r","replace","slice","autoFocus","letterSpacing","disabled","validateBoId","validateDob","sid","BROKER_LOGO_BASE","CAS_PORTALS","DEFAULT_BROKERS","depository","logo","sort","a","b","localeCompare","PortfolioConnectWidget","apiKey","apiBaseUrl","config","onSuccess","onError","onEvent","mode","setMode","setSelectedType","setIsProcessing","setProgress","fetchLoading","setFetchLoading","lastError","setLastError","selectedBroker","setSelectedBroker","onEventRef","progressIntervalRef","clearInterval","apiClient","baseUrl","emitEvent","event","metadata","timestamp","Date","now","allowedTypes","enableGenerator","enableCdslFetch","showShortcuts","showPortalLinks","firstType","handleClose","handleModeSwitch","newMode","from","to","handleManualDepositorySelect","broker","handleFileProcess","filename","setInterval","prev","Math","min","random","startTime","response","client","onProgress","formData","FormData","append","fetch","method","headers","Authorization","ok","errorData","json","catch","data","msg","parseStatement","percent","parser_type","cas_author","parse_duration_ms","setTimeout","casError","code","details","handleRetry","handleFetchSubmit","options","today","toDate","toISOString","split","fromDate","JSON","stringify","pan_no","from_date","to_date","cas_authority","generateCAS","generator","Error","handleCdslRequestOtp","bo_id","cdslFetchRequestOtp","session_id","handleCdslVerifyOtp","numPeriods","num_periods","cdslFetchVerifyOtp","count","handleCdslAutoParse","targetFile","source","pdfUrl","pdf_url","parseStatementFromUrl","all_files","isSubScreen","currentPortal","portal","opacity","brokerList","brokers","overflowY","paddingRight","handleBrokerSelect","src","alt","objectFit","flexShrink","minWidth","logoUrl","title","subtitle","allowMutualFunds","includes","allowDemat","transform","renderContent","paddingTop","borderTop","PortfolioConnect","accessToken","onExit","setIsOpen","token","open","renderProps","isReady","Fragment","CASConnect","activeContainer","activeRoot","cleanup","unmount","parentNode","removeChild","container","root","render","id","setAttribute","appendChild","ReactDOM","createRoot","onOpen","destroy","startsWith","Promise","resolve","reject","expiryMinutes","authUrl","expiry_minutes","detail"],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
export type PortfolioType = 'CAMS_KFINTECH' | 'CDSL' | 'NSDL';
|
|
2
|
+
export type CASType = PortfolioType;
|
|
3
|
+
export interface BrokerInfo {
|
|
4
|
+
name: string;
|
|
5
|
+
depository: 'CDSL' | 'NSDL';
|
|
6
|
+
logo?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface PortfolioConnectConfig {
|
|
9
|
+
allowedTypes?: PortfolioType[];
|
|
10
|
+
enableGenerator?: boolean;
|
|
11
|
+
enableCdslFetch?: boolean;
|
|
12
|
+
showShortcuts?: boolean;
|
|
13
|
+
showPortalLinks?: boolean;
|
|
14
|
+
brokers?: BrokerInfo[];
|
|
15
|
+
prefill?: {
|
|
16
|
+
pan?: string;
|
|
17
|
+
email?: string;
|
|
18
|
+
phone?: string;
|
|
19
|
+
boId?: string;
|
|
20
|
+
dob?: string;
|
|
21
|
+
};
|
|
22
|
+
generator?: {
|
|
23
|
+
fromDate?: string;
|
|
24
|
+
toDate?: string;
|
|
25
|
+
password?: string;
|
|
26
|
+
};
|
|
27
|
+
logoUrl?: string;
|
|
28
|
+
title?: string;
|
|
29
|
+
subtitle?: string;
|
|
30
|
+
}
|
|
31
|
+
export type CASConnectConfig = PortfolioConnectConfig;
|
|
32
|
+
export interface PortfolioConnectProps {
|
|
33
|
+
/** Access token for authentication. Get yours at docs.casparser.in */
|
|
34
|
+
accessToken?: string;
|
|
35
|
+
/** @deprecated Use accessToken instead. Both work with x-api-key header. */
|
|
36
|
+
apiKey?: string;
|
|
37
|
+
apiBaseUrl?: string;
|
|
38
|
+
config?: PortfolioConnectConfig;
|
|
39
|
+
onSuccess: (data: ParsedData, metadata: ParseMetadata) => void;
|
|
40
|
+
onError?: (error: PortfolioConnectError) => void;
|
|
41
|
+
onExit?: () => void;
|
|
42
|
+
onEvent?: (event: PortfolioConnectEvent, metadata: EventMetadata) => void;
|
|
43
|
+
children: (props: RenderProps) => React.ReactNode;
|
|
44
|
+
}
|
|
45
|
+
export type CASConnectProps = PortfolioConnectProps;
|
|
46
|
+
export interface RenderProps {
|
|
47
|
+
open: () => void;
|
|
48
|
+
isReady: boolean;
|
|
49
|
+
isOpen: boolean;
|
|
50
|
+
}
|
|
51
|
+
export interface ParsedData {
|
|
52
|
+
cas_type: CASType;
|
|
53
|
+
status: 'success' | 'failed';
|
|
54
|
+
investor_info?: InvestorInfo;
|
|
55
|
+
folios?: any[];
|
|
56
|
+
holdings?: any[];
|
|
57
|
+
summary?: {
|
|
58
|
+
total_value: number;
|
|
59
|
+
as_on_date: string;
|
|
60
|
+
};
|
|
61
|
+
raw_response?: any;
|
|
62
|
+
}
|
|
63
|
+
export interface InvestorInfo {
|
|
64
|
+
name: string;
|
|
65
|
+
email?: string;
|
|
66
|
+
mobile?: string;
|
|
67
|
+
pan?: string;
|
|
68
|
+
address?: string;
|
|
69
|
+
}
|
|
70
|
+
export interface ParseMetadata {
|
|
71
|
+
filename: string;
|
|
72
|
+
parser_type: CASType;
|
|
73
|
+
parse_duration_ms: number;
|
|
74
|
+
}
|
|
75
|
+
export interface PortfolioConnectError {
|
|
76
|
+
code: string;
|
|
77
|
+
message: string;
|
|
78
|
+
details?: any;
|
|
79
|
+
}
|
|
80
|
+
export type CASConnectError = PortfolioConnectError;
|
|
81
|
+
export type PortfolioConnectEvent = 'WIDGET_OPENED' | 'WIDGET_CLOSED' | 'MODE_SWITCHED' | 'BROKER_SELECTED' | 'SEARCH_CLICKED' | 'PORTAL_CLICKED' | 'TYPE_CHANGED' | 'FILE_SELECTED' | 'FILE_REMOVED' | 'UPLOAD_STARTED' | 'UPLOAD_PROGRESS' | 'PARSE_STARTED' | 'PARSE_SUCCESS' | 'PARSE_ERROR' | 'GENERATOR_STARTED' | 'GENERATOR_SUCCESS' | 'GENERATOR_ERROR' | 'CDSL_FETCH_STARTED' | 'CDSL_OTP_SENT' | 'CDSL_OTP_VERIFIED' | 'CDSL_FETCH_SUCCESS' | 'CDSL_FETCH_ERROR';
|
|
82
|
+
export type CASConnectEvent = PortfolioConnectEvent;
|
|
83
|
+
export interface EventMetadata {
|
|
84
|
+
timestamp: number;
|
|
85
|
+
[key: string]: any;
|
|
86
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export interface ApiClient {
|
|
2
|
+
baseUrl: string;
|
|
3
|
+
apiKey: string;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Creates an API client for making requests to CASParser API.
|
|
7
|
+
*
|
|
8
|
+
* @param accessToken - Your access token (get one at docs.casparser.in)
|
|
9
|
+
* @param baseUrl - Optional custom API base URL
|
|
10
|
+
* @returns API client instance
|
|
11
|
+
*/
|
|
12
|
+
export declare function createApiClient(accessToken: string, baseUrl?: string): ApiClient;
|
|
13
|
+
export interface AccessTokenResponse {
|
|
14
|
+
access_token: string;
|
|
15
|
+
token_type: 'api_key';
|
|
16
|
+
expires_in: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Request a short-lived access token from the API key.
|
|
20
|
+
* Use this on your backend to generate tokens for frontend use.
|
|
21
|
+
*
|
|
22
|
+
* @param apiKey - Your API key (do NOT expose this on frontend)
|
|
23
|
+
* @param expiryMinutes - Token validity in minutes (max 60, default 60)
|
|
24
|
+
* @param authUrl - Optional custom auth URL
|
|
25
|
+
* @returns Access token response with SK_ prefixed token
|
|
26
|
+
*/
|
|
27
|
+
export declare function requestAccessToken(apiKey: string, expiryMinutes?: number, authUrl?: string): Promise<AccessTokenResponse>;
|
|
28
|
+
/**
|
|
29
|
+
* Check if a token is an access token (SK_ prefix)
|
|
30
|
+
*/
|
|
31
|
+
export declare function isAccessToken(token: string): boolean;
|
|
32
|
+
export declare function parseStatement(client: ApiClient, file: File, password?: string, onProgress?: (percent: number) => void): Promise<any>;
|
|
33
|
+
/**
|
|
34
|
+
* Parse a statement from a URL (used for CDSL fetch results)
|
|
35
|
+
*/
|
|
36
|
+
export declare function parseStatementFromUrl(client: ApiClient, pdfUrl: string, password?: string, onProgress?: (percent: number) => void): Promise<any>;
|
|
37
|
+
export interface GeneratorOptions {
|
|
38
|
+
fromDate?: string;
|
|
39
|
+
toDate?: string;
|
|
40
|
+
password?: string;
|
|
41
|
+
}
|
|
42
|
+
export declare function generateCAS(client: ApiClient, email: string, pan: string, options?: GeneratorOptions): Promise<any>;
|
|
43
|
+
export interface CdslFetchResponse {
|
|
44
|
+
status: string;
|
|
45
|
+
session_id: string;
|
|
46
|
+
msg: string;
|
|
47
|
+
}
|
|
48
|
+
export interface CdslVerifyResponse {
|
|
49
|
+
status: string;
|
|
50
|
+
msg: string;
|
|
51
|
+
files: Array<{
|
|
52
|
+
filename: string;
|
|
53
|
+
url: string;
|
|
54
|
+
}>;
|
|
55
|
+
}
|
|
56
|
+
export declare function cdslFetchRequestOtp(client: ApiClient, pan: string, boId: string, dob: string): Promise<CdslFetchResponse>;
|
|
57
|
+
export declare function cdslFetchVerifyOtp(client: ApiClient, sessionId: string, otp: string, numPeriods?: number): Promise<CdslVerifyResponse>;
|
package/package.json
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cas-parser/connect",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Portfolio Connect - Lightweight widget for importing Indian investment statements (MF, CDSL, NSDL). Works with React, Angular, Vue, and vanilla JS.",
|
|
5
|
+
"main": "dist/index.cjs.js",
|
|
6
|
+
"module": "dist/index.esm.js",
|
|
7
|
+
"unpkg": "dist/portfolio-connect.umd.min.js",
|
|
8
|
+
"jsdelivr": "dist/portfolio-connect.umd.min.js",
|
|
9
|
+
"types": "dist/index.d.ts",
|
|
10
|
+
"sideEffects": false,
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.esm.js",
|
|
15
|
+
"require": "./dist/index.cjs.js"
|
|
16
|
+
},
|
|
17
|
+
"./package.json": "./package.json"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist",
|
|
21
|
+
"README.md",
|
|
22
|
+
"LICENSE"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"dev": "next dev -p 3002",
|
|
26
|
+
"build": "npm run clean && rollup -c rollup.config.mjs",
|
|
27
|
+
"build:types": "tsc --emitDeclarationOnly --declaration --declarationDir dist",
|
|
28
|
+
"build:demo": "next build",
|
|
29
|
+
"clean": "rm -rf dist",
|
|
30
|
+
"prepublishOnly": "npm run build",
|
|
31
|
+
"size": "size-limit",
|
|
32
|
+
"lint": "eslint src --ext .ts,.tsx"
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"react": ">=17.0.0",
|
|
36
|
+
"react-dom": ">=17.0.0"
|
|
37
|
+
},
|
|
38
|
+
"peerDependenciesMeta": {
|
|
39
|
+
"react": {
|
|
40
|
+
"optional": true
|
|
41
|
+
},
|
|
42
|
+
"react-dom": {
|
|
43
|
+
"optional": true
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@rollup/plugin-commonjs": "^25.0.7",
|
|
48
|
+
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
49
|
+
"@rollup/plugin-replace": "^5.0.5",
|
|
50
|
+
"@rollup/plugin-typescript": "^11.1.6",
|
|
51
|
+
"@types/node": "^20.10.0",
|
|
52
|
+
"@types/react": "^18.2.0",
|
|
53
|
+
"@types/react-dom": "^18.2.0",
|
|
54
|
+
"next": "^14.0.0",
|
|
55
|
+
"react": "^18.2.0",
|
|
56
|
+
"react-dom": "^18.2.0",
|
|
57
|
+
"rollup": "^4.9.0",
|
|
58
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
59
|
+
"rollup-plugin-peer-deps-external": "^2.2.4",
|
|
60
|
+
"tslib": "^2.6.2",
|
|
61
|
+
"typescript": "^5.3.0"
|
|
62
|
+
},
|
|
63
|
+
"repository": {
|
|
64
|
+
"type": "git",
|
|
65
|
+
"url": "https://github.com/CASParser/cas-connect.git"
|
|
66
|
+
},
|
|
67
|
+
"keywords": [
|
|
68
|
+
"cas",
|
|
69
|
+
"casparser",
|
|
70
|
+
"mutual-funds",
|
|
71
|
+
"portfolio",
|
|
72
|
+
"fintech",
|
|
73
|
+
"sdk",
|
|
74
|
+
"widget",
|
|
75
|
+
"react-native",
|
|
76
|
+
"webview"
|
|
77
|
+
],
|
|
78
|
+
"author": "CASParser <sameer@casparser.in>",
|
|
79
|
+
"license": "MIT",
|
|
80
|
+
"bugs": {
|
|
81
|
+
"url": "https://github.com/CASParser/cas-connect/issues"
|
|
82
|
+
},
|
|
83
|
+
"homepage": "https://casparser.in/connect"
|
|
84
|
+
}
|