@fayz-ai/core 0.7.0 → 0.7.1
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/dist/index.cjs +135 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +125 -1
- package/dist/index.js.map +1 -1
- package/dist/phone/index.d.ts +28 -0
- package/dist/phone/index.d.ts.map +1 -0
- package/dist/seo/index.d.ts +27 -0
- package/dist/seo/index.d.ts.map +1 -0
- package/dist/types/payment.d.ts +38 -0
- package/dist/types/payment.d.ts.map +1 -0
- package/package.json +2 -2
- package/src/index.ts +11 -0
- package/src/phone/index.ts +85 -0
- package/src/seo/index.ts +128 -0
- package/src/types/payment.ts +44 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/seo/index.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAA;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,mFAAmF;IACnF,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;CACxC;AAED,8CAA8C;AAC9C,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAED,mEAAmE;AACnE,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AA8BD,oFAAoF;AACpF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA0BhD;AAED,uEAAuE;AACvE,wBAAgB,MAAM,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAO9C;AAID,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,gEAAgE;AAChE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAWjF;AAED,+CAA+C;AAC/C,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzG"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export type PaymentMethod = 'pix' | (string & {});
|
|
2
|
+
export type ChargeStatus = 'pending' | 'paid' | 'expired' | 'failed';
|
|
3
|
+
export interface CreateChargeInput {
|
|
4
|
+
/** Amount in the currency's major unit (e.g. 220.00 = R$ 220,00). */
|
|
5
|
+
amount: number;
|
|
6
|
+
/** ISO 4217 currency code, e.g. 'BRL'. */
|
|
7
|
+
currency: string;
|
|
8
|
+
method: PaymentMethod;
|
|
9
|
+
/** Human-readable description (statement/receipt). */
|
|
10
|
+
description?: string;
|
|
11
|
+
/** The booking/order this charge settles, for reconciliation. */
|
|
12
|
+
orderId?: string;
|
|
13
|
+
/** Payer contact, when known (name/email/phone). */
|
|
14
|
+
customer?: {
|
|
15
|
+
name?: string;
|
|
16
|
+
email?: string;
|
|
17
|
+
phone?: string;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export interface PixCharge {
|
|
21
|
+
chargeId: string;
|
|
22
|
+
status: ChargeStatus;
|
|
23
|
+
amount: number;
|
|
24
|
+
currency: string;
|
|
25
|
+
/** QR image payload. For Pix this is the BR Code string encoded into the QR. */
|
|
26
|
+
pixQrCode: string;
|
|
27
|
+
/** "Copia e cola" — the raw Pix BR Code the payer pastes into their bank app. */
|
|
28
|
+
pixCopyPaste: string;
|
|
29
|
+
/** ISO datetime the charge/QR expires. */
|
|
30
|
+
expiresAt: string;
|
|
31
|
+
}
|
|
32
|
+
export interface PaymentProvider {
|
|
33
|
+
/** Create a charge and return its payable artifacts (Pix QR + copia-e-cola). */
|
|
34
|
+
createCharge(input: CreateChargeInput): Promise<PixCharge>;
|
|
35
|
+
/** Current status of a charge (polled by the UI, or driven by a webhook later). */
|
|
36
|
+
getChargeStatus(chargeId: string): Promise<ChargeStatus>;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=payment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payment.d.ts","sourceRoot":"","sources":["../../src/types/payment.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAA;AAEjD,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAA;AAEpE,MAAM,WAAW,iBAAiB;IAChC,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAA;IACd,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,aAAa,CAAA;IACrB,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,oDAAoD;IACpD,QAAQ,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAC7D;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,YAAY,CAAA;IACpB,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAA;IACjB,iFAAiF;IACjF,YAAY,EAAE,MAAM,CAAA;IACpB,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,gFAAgF;IAChF,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,SAAS,CAAC,CAAA;IAC1D,mFAAmF;IACnF,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;CACzD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fayz-ai/core",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "Fayz SDK core — data providers, entity system, plugin runtime, i18n, routing",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
"dependencies": {
|
|
80
80
|
"@supabase/supabase-js": "^2.45.0",
|
|
81
81
|
"zustand": "^4.5.0",
|
|
82
|
-
"@fayz-ai/sdk": "^0.6.
|
|
82
|
+
"@fayz-ai/sdk": "^0.6.7"
|
|
83
83
|
},
|
|
84
84
|
"devDependencies": {
|
|
85
85
|
"@types/react": "^18.3.0",
|
package/src/index.ts
CHANGED
|
@@ -18,6 +18,17 @@ export { createArchetypeProvider } from './data/archetype'
|
|
|
18
18
|
export { withCache } from './data/cached'
|
|
19
19
|
export { resolveDataProvider } from './data/resolve'
|
|
20
20
|
export { createSafeDataProvider } from './plugin/createSafeDataProvider'
|
|
21
|
+
export {
|
|
22
|
+
COUNTRIES, DEFAULT_COUNTRY, getCountry, unmaskPhone, maskPhone, maskDigitCount,
|
|
23
|
+
} from './phone'
|
|
24
|
+
export type { CountryDef } from './phone'
|
|
25
|
+
export type {
|
|
26
|
+
PaymentProvider, PaymentMethod, ChargeStatus, CreateChargeInput, PixCharge,
|
|
27
|
+
} from './types/payment'
|
|
28
|
+
export {
|
|
29
|
+
useSeo, applySeo, absoluteUrl, seoOrigin, breadcrumbJsonLd, organizationJsonLd,
|
|
30
|
+
} from './seo'
|
|
31
|
+
export type { SeoConfig, BreadcrumbItem } from './seo'
|
|
21
32
|
export type { DataProvider, CrudQuery, CrudResult, SupabaseProviderConfig, FayzApiProviderConfig } from './data/index'
|
|
22
33
|
|
|
23
34
|
// Tenant context (runtime DI for the data layer)
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Reusable phone / country helpers (SDK-level — shared by any plugin that
|
|
3
|
+
// collects a phone number: booking, CRM, forms, auth…). Provides the country
|
|
4
|
+
// list (flag + dial code + national mask) and mask/unmask utilities.
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
|
|
7
|
+
export interface CountryDef {
|
|
8
|
+
/** ISO 3166-1 alpha-2 code, e.g. 'BR'. */
|
|
9
|
+
iso2: string
|
|
10
|
+
/** Localized-ish display name. */
|
|
11
|
+
name: string
|
|
12
|
+
/** International dial code including '+', e.g. '+55'. */
|
|
13
|
+
dial: string
|
|
14
|
+
/** Flag emoji (derived from iso2). */
|
|
15
|
+
flag: string
|
|
16
|
+
/** National number mask; '#' = one digit. e.g. '(##) #####-####'. */
|
|
17
|
+
mask: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Derive a flag emoji from an ISO2 code via regional indicator symbols. */
|
|
21
|
+
function flagOf(iso2: string): string {
|
|
22
|
+
return iso2
|
|
23
|
+
.toUpperCase()
|
|
24
|
+
.replace(/[^A-Z]/g, '')
|
|
25
|
+
.split('')
|
|
26
|
+
.map((c) => String.fromCodePoint(0x1f1e6 + c.charCodeAt(0) - 65))
|
|
27
|
+
.join('')
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const RAW: Omit<CountryDef, 'flag'>[] = [
|
|
31
|
+
{ iso2: 'BR', name: 'Brasil', dial: '+55', mask: '(##) #####-####' },
|
|
32
|
+
{ iso2: 'US', name: 'Estados Unidos', dial: '+1', mask: '(###) ###-####' },
|
|
33
|
+
{ iso2: 'PT', name: 'Portugal', dial: '+351', mask: '### ### ###' },
|
|
34
|
+
{ iso2: 'AR', name: 'Argentina', dial: '+54', mask: '(##) ####-####' },
|
|
35
|
+
{ iso2: 'ES', name: 'Espanha', dial: '+34', mask: '### ### ###' },
|
|
36
|
+
{ iso2: 'MX', name: 'México', dial: '+52', mask: '## #### ####' },
|
|
37
|
+
{ iso2: 'GB', name: 'Reino Unido', dial: '+44', mask: '##### ######' },
|
|
38
|
+
{ iso2: 'FR', name: 'França', dial: '+33', mask: '# ## ## ## ##' },
|
|
39
|
+
{ iso2: 'DE', name: 'Alemanha', dial: '+49', mask: '#### #######' },
|
|
40
|
+
{ iso2: 'IT', name: 'Itália', dial: '+39', mask: '### #######' },
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
export const COUNTRIES: CountryDef[] = RAW.map((c) => ({ ...c, flag: flagOf(c.iso2) }))
|
|
44
|
+
|
|
45
|
+
export const DEFAULT_COUNTRY = 'BR'
|
|
46
|
+
|
|
47
|
+
const BY_ISO = new Map(COUNTRIES.map((c) => [c.iso2, c]))
|
|
48
|
+
|
|
49
|
+
/** Look up a country by ISO2 (falls back to the default). */
|
|
50
|
+
export function getCountry(iso2: string | undefined): CountryDef {
|
|
51
|
+
return (iso2 && BY_ISO.get(iso2.toUpperCase())) || BY_ISO.get(DEFAULT_COUNTRY)!
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Keep only digit characters. */
|
|
55
|
+
export function unmaskPhone(value: string): string {
|
|
56
|
+
return (value || '').replace(/\D/g, '')
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Apply a '#'-placeholder mask to a raw string, consuming its digits. Extra
|
|
61
|
+
* digits beyond the mask are dropped; partial input masks progressively.
|
|
62
|
+
*
|
|
63
|
+
* maskPhone('11987654321', '(##) #####-####') -> '(11) 98765-4321'
|
|
64
|
+
*/
|
|
65
|
+
export function maskPhone(value: string, mask: string): string {
|
|
66
|
+
const digits = unmaskPhone(value)
|
|
67
|
+
let out = ''
|
|
68
|
+
let di = 0
|
|
69
|
+
for (const ch of mask) {
|
|
70
|
+
if (di >= digits.length) break
|
|
71
|
+
if (ch === '#') {
|
|
72
|
+
out += digits[di++]
|
|
73
|
+
} else {
|
|
74
|
+
out += ch
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return out
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Count how many digits a mask expects. */
|
|
81
|
+
export function maskDigitCount(mask: string): number {
|
|
82
|
+
let n = 0
|
|
83
|
+
for (const ch of mask) if (ch === '#') n++
|
|
84
|
+
return n
|
|
85
|
+
}
|
package/src/seo/index.ts
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { useEffect } from 'react'
|
|
2
|
+
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// Generic, domain-agnostic SEO / structured-data head manager (SDK-level).
|
|
5
|
+
// ANY surface (blog, booking, reviews, product, landing) uses `useSeo` to set
|
|
6
|
+
// <title>, meta description, canonical, OpenGraph/Twitter cards and JSON-LD per
|
|
7
|
+
// route. Domain plugins build their own schema.org objects (BlogPosting,
|
|
8
|
+
// Product, Event…) and pass them via `jsonLd` — the mechanics live here once.
|
|
9
|
+
//
|
|
10
|
+
// NOTE: a SPA still benefits from SSR/prerendering for the strongest SEO — that
|
|
11
|
+
// is the real upgrade; this covers everything achievable client-side.
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
const MANAGED = 'data-fayz-seo'
|
|
15
|
+
|
|
16
|
+
export interface SeoConfig {
|
|
17
|
+
title: string
|
|
18
|
+
description?: string
|
|
19
|
+
canonical?: string
|
|
20
|
+
image?: string
|
|
21
|
+
type?: 'website' | 'article' | (string & {})
|
|
22
|
+
siteName?: string
|
|
23
|
+
/** One or more JSON-LD objects injected as <script type="application/ld+json">. */
|
|
24
|
+
jsonLd?: Array<Record<string, unknown>>
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Current page origin (empty during SSR). */
|
|
28
|
+
export function seoOrigin(): string {
|
|
29
|
+
return typeof window !== 'undefined' ? window.location.origin : ''
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Build an absolute URL from a path, using the current origin. */
|
|
33
|
+
export function absoluteUrl(path: string): string {
|
|
34
|
+
return `${seoOrigin()}${path.startsWith('/') ? path : `/${path}`}`
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function upsertMeta(attr: 'name' | 'property', key: string, content: string) {
|
|
38
|
+
if (!content) return
|
|
39
|
+
let el = document.head.querySelector<HTMLMetaElement>(`meta[${attr}="${key}"]`)
|
|
40
|
+
if (!el) {
|
|
41
|
+
el = document.createElement('meta')
|
|
42
|
+
el.setAttribute(attr, key)
|
|
43
|
+
el.setAttribute(MANAGED, '')
|
|
44
|
+
document.head.appendChild(el)
|
|
45
|
+
}
|
|
46
|
+
el.setAttribute('content', content)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function upsertLink(rel: string, href: string) {
|
|
50
|
+
if (!href) return
|
|
51
|
+
let el = document.head.querySelector<HTMLLinkElement>(`link[rel="${rel}"]`)
|
|
52
|
+
if (!el) {
|
|
53
|
+
el = document.createElement('link')
|
|
54
|
+
el.setAttribute('rel', rel)
|
|
55
|
+
el.setAttribute(MANAGED, '')
|
|
56
|
+
document.head.appendChild(el)
|
|
57
|
+
}
|
|
58
|
+
el.setAttribute('href', href)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function clearManaged() {
|
|
62
|
+
document.head.querySelectorAll(`[${MANAGED}]`).forEach((el) => el.remove())
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Imperatively apply SEO tags (used by useSeo; exported for non-React callers). */
|
|
66
|
+
export function applySeo(config: SeoConfig): void {
|
|
67
|
+
if (typeof document === 'undefined') return
|
|
68
|
+
clearManaged()
|
|
69
|
+
document.title = config.title
|
|
70
|
+
upsertMeta('name', 'description', config.description ?? '')
|
|
71
|
+
if (config.canonical) upsertLink('canonical', config.canonical)
|
|
72
|
+
|
|
73
|
+
upsertMeta('property', 'og:title', config.title)
|
|
74
|
+
upsertMeta('property', 'og:description', config.description ?? '')
|
|
75
|
+
upsertMeta('property', 'og:type', config.type === 'article' ? 'article' : 'website')
|
|
76
|
+
if (config.canonical) upsertMeta('property', 'og:url', config.canonical)
|
|
77
|
+
if (config.image) upsertMeta('property', 'og:image', config.image)
|
|
78
|
+
if (config.siteName) upsertMeta('property', 'og:site_name', config.siteName)
|
|
79
|
+
|
|
80
|
+
upsertMeta('name', 'twitter:card', config.image ? 'summary_large_image' : 'summary')
|
|
81
|
+
upsertMeta('name', 'twitter:title', config.title)
|
|
82
|
+
upsertMeta('name', 'twitter:description', config.description ?? '')
|
|
83
|
+
if (config.image) upsertMeta('name', 'twitter:image', config.image)
|
|
84
|
+
|
|
85
|
+
for (const obj of config.jsonLd ?? []) {
|
|
86
|
+
const script = document.createElement('script')
|
|
87
|
+
script.type = 'application/ld+json'
|
|
88
|
+
script.setAttribute(MANAGED, '')
|
|
89
|
+
script.text = JSON.stringify(obj)
|
|
90
|
+
document.head.appendChild(script)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Apply SEO head tags for the current route; cleans up on unmount. */
|
|
95
|
+
export function useSeo(config: SeoConfig): void {
|
|
96
|
+
const key = JSON.stringify(config)
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
applySeo(config)
|
|
99
|
+
return () => clearManaged()
|
|
100
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
101
|
+
}, [key])
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// --- Generic schema.org builders (reusable across plugins) -----------------
|
|
105
|
+
|
|
106
|
+
export interface BreadcrumbItem {
|
|
107
|
+
name: string
|
|
108
|
+
url: string
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** schema.org BreadcrumbList from an ordered list of crumbs. */
|
|
112
|
+
export function breadcrumbJsonLd(items: BreadcrumbItem[]): Record<string, unknown> {
|
|
113
|
+
return {
|
|
114
|
+
'@context': 'https://schema.org',
|
|
115
|
+
'@type': 'BreadcrumbList',
|
|
116
|
+
itemListElement: items.map((c, i) => ({
|
|
117
|
+
'@type': 'ListItem',
|
|
118
|
+
position: i + 1,
|
|
119
|
+
name: c.name,
|
|
120
|
+
item: c.url,
|
|
121
|
+
})),
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** schema.org Organization publisher block. */
|
|
126
|
+
export function organizationJsonLd(name: string, extra?: Record<string, unknown>): Record<string, unknown> {
|
|
127
|
+
return { '@type': 'Organization', name, ...extra }
|
|
128
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Payment provider contract (SDK-level, gateway-agnostic). A booking/checkout
|
|
3
|
+
// flow declares "collect X" and calls createCharge; the concrete provider (mock
|
|
4
|
+
// Pix now, MercadoPago/Stripe later) decides HOW. Kept in core so any plugin can
|
|
5
|
+
// depend on the interface without depending on a payments plugin.
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
|
|
8
|
+
export type PaymentMethod = 'pix' | (string & {})
|
|
9
|
+
|
|
10
|
+
export type ChargeStatus = 'pending' | 'paid' | 'expired' | 'failed'
|
|
11
|
+
|
|
12
|
+
export interface CreateChargeInput {
|
|
13
|
+
/** Amount in the currency's major unit (e.g. 220.00 = R$ 220,00). */
|
|
14
|
+
amount: number
|
|
15
|
+
/** ISO 4217 currency code, e.g. 'BRL'. */
|
|
16
|
+
currency: string
|
|
17
|
+
method: PaymentMethod
|
|
18
|
+
/** Human-readable description (statement/receipt). */
|
|
19
|
+
description?: string
|
|
20
|
+
/** The booking/order this charge settles, for reconciliation. */
|
|
21
|
+
orderId?: string
|
|
22
|
+
/** Payer contact, when known (name/email/phone). */
|
|
23
|
+
customer?: { name?: string; email?: string; phone?: string }
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface PixCharge {
|
|
27
|
+
chargeId: string
|
|
28
|
+
status: ChargeStatus
|
|
29
|
+
amount: number
|
|
30
|
+
currency: string
|
|
31
|
+
/** QR image payload. For Pix this is the BR Code string encoded into the QR. */
|
|
32
|
+
pixQrCode: string
|
|
33
|
+
/** "Copia e cola" — the raw Pix BR Code the payer pastes into their bank app. */
|
|
34
|
+
pixCopyPaste: string
|
|
35
|
+
/** ISO datetime the charge/QR expires. */
|
|
36
|
+
expiresAt: string
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface PaymentProvider {
|
|
40
|
+
/** Create a charge and return its payable artifacts (Pix QR + copia-e-cola). */
|
|
41
|
+
createCharge(input: CreateChargeInput): Promise<PixCharge>
|
|
42
|
+
/** Current status of a charge (polled by the UI, or driven by a webhook later). */
|
|
43
|
+
getChargeStatus(chargeId: string): Promise<ChargeStatus>
|
|
44
|
+
}
|