@geekapps/billing-fastify 0.1.0 → 0.3.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/README.md +62 -0
- package/dist/index.d.ts +275 -3
- package/dist/index.js +143 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -48,3 +48,65 @@ await client.customers.create({ name: "...", email: "..." });
|
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
O `mode` (dev/prod) é configurado uma única vez ao instanciar o cliente — nenhum método individual precisa recebê-lo novamente.
|
|
51
|
+
|
|
52
|
+
## Cobrança avulsa simples (sempre cartão)
|
|
53
|
+
|
|
54
|
+
`charges.charge` cobra direto no cartão padrão já salvo do cliente; se ele ainda não tiver um, retorna uma URL de checkout para cadastrar o cartão e pagar.
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
const result = await client.charges.charge(customerId, 5000); // R$ 50,00
|
|
58
|
+
|
|
59
|
+
if (!result.charged_off_session) {
|
|
60
|
+
// abra result.checkout_url em uma nova aba para o cliente cadastrar o cartão
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Assinatura de plano (checkout + confirmação + status)
|
|
65
|
+
|
|
66
|
+
Fluxo público (cliente final anônimo, ainda sem `Customer` cadastrado — coleta nome/e-mail no checkout):
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
const { checkout_url, checkout_token, management_token } = await client.plans.checkout(planId, {
|
|
70
|
+
customer: { name, email },
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// redirecione o cliente para checkout_url, depois confirme o pagamento:
|
|
74
|
+
const status = await client.checkout.waitUntilPaid(checkout_token);
|
|
75
|
+
|
|
76
|
+
// guarde management_token — a qualquer momento depois, verifique se a assinatura
|
|
77
|
+
// segue ativa e qual item ela cobre (rota pública, sem autenticação):
|
|
78
|
+
const subStatus = await client.subscriptions.checkByToken(management_token);
|
|
79
|
+
if (subStatus.subscription.active) {
|
|
80
|
+
console.log("cobrando", subStatus.item.name);
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Fluxo simplificado (autenticado, o `Customer` já existe na sua org — sem formulário de nome/e-mail):
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
const { checkout_url } = await client.plans.checkoutPlan(planId, customerId);
|
|
88
|
+
// redirecione o cliente para checkout_url; ele paga e volta para sua URL de retorno
|
|
89
|
+
|
|
90
|
+
// depois que o cliente volta:
|
|
91
|
+
const { active, item } = await client.plans.confirmPlanSubscription(planId, customerId);
|
|
92
|
+
if (active) {
|
|
93
|
+
// ativa o plano real no seu sistema
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Plano avulso (sem página pública)
|
|
98
|
+
|
|
99
|
+
Planos normalmente nascem junto com uma `BillingPlanPage` (`POST /billing-plan-pages`), mas também podem ser criados sozinhos — útil para o fluxo simplificado acima, onde você não precisa de uma página de preços hospedada:
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
const plan = await client.plans.create({
|
|
103
|
+
item_id: itemId,
|
|
104
|
+
interval: "MONTHLY",
|
|
105
|
+
// plan_page_id omitido — plano fica avulso
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// depois, se quiser, vincule a uma página existente:
|
|
109
|
+
await client.plans.attachToPage(plan.id, pageId);
|
|
110
|
+
// ou desvincule de novo:
|
|
111
|
+
await client.plans.detachFromPage(plan.id);
|
|
112
|
+
```
|
package/dist/index.d.ts
CHANGED
|
@@ -76,6 +76,23 @@ interface Charge {
|
|
|
76
76
|
}
|
|
77
77
|
interface CreateChargeResult extends Charge {
|
|
78
78
|
}
|
|
79
|
+
interface QuickChargeInput {
|
|
80
|
+
customer_id: string;
|
|
81
|
+
/** Valor em centavos. */
|
|
82
|
+
amount: number;
|
|
83
|
+
currency?: string;
|
|
84
|
+
description?: string;
|
|
85
|
+
metadata?: Record<string, unknown>;
|
|
86
|
+
}
|
|
87
|
+
interface QuickChargeResult {
|
|
88
|
+
/** true quando o cartão salvo do cliente foi cobrado direto (sem fricção) — nesse
|
|
89
|
+
* caso `checkout_url` vem `null` e `charge.status` já reflete o resultado (PAID ou
|
|
90
|
+
* PROCESSING). false quando o cliente ainda não tem cartão salvo (ou o cartão salvo
|
|
91
|
+
* falhou) — abra `checkout_url` para ele cadastrar o cartão e completar o pagamento. */
|
|
92
|
+
charged_off_session: boolean;
|
|
93
|
+
checkout_url: string | null;
|
|
94
|
+
charge: Charge;
|
|
95
|
+
}
|
|
79
96
|
interface CustomerInput {
|
|
80
97
|
name: string;
|
|
81
98
|
email: string;
|
|
@@ -115,11 +132,20 @@ type BillingRecurringInterval = "WEEKLY" | "MONTHLY" | "QUARTERLY" | "YEARLY";
|
|
|
115
132
|
type BillingRecurringStatus = "ACTIVE" | "TRIALING" | "PAST_DUE" | "PAUSED" | "CANCELLED" | "EXPIRED";
|
|
116
133
|
type ProrationPolicy = "IMMEDIATE" | "AT_RENEWAL";
|
|
117
134
|
interface CreateBillingPlanInput {
|
|
118
|
-
|
|
135
|
+
/** Página de planos (BillingPlanPage) à qual este plano pertence — opcional: omita para
|
|
136
|
+
* criar um plano avulso, sem página pública, usado no fluxo simplificado de
|
|
137
|
+
* checkout/confirmação (`checkoutPlan`/`confirmPlanSubscription`). */
|
|
138
|
+
plan_page_id?: string;
|
|
139
|
+
/** Item de catálogo (BillingItem) do qual nome/preço são copiados na criação. */
|
|
140
|
+
item_id: string;
|
|
141
|
+
name?: string;
|
|
119
142
|
description?: string;
|
|
120
|
-
amount
|
|
143
|
+
amount?: number;
|
|
121
144
|
currency?: string;
|
|
122
145
|
interval: BillingRecurringInterval;
|
|
146
|
+
/** Preço cobrado no ciclo anual (cents) — quando presente, habilita a opção de
|
|
147
|
+
* cobrança anual (`billing_period: "annual"`) no checkout público deste plano. */
|
|
148
|
+
annual_amount?: number;
|
|
123
149
|
features?: string[];
|
|
124
150
|
limits?: Record<string, string | number>;
|
|
125
151
|
return_url?: string;
|
|
@@ -128,11 +154,15 @@ interface CreateBillingPlanInput {
|
|
|
128
154
|
interface BillingPlanSummary {
|
|
129
155
|
id: string;
|
|
130
156
|
org_id: string;
|
|
157
|
+
/** null quando o plano é avulso (sem página pública). */
|
|
158
|
+
plan_page_id: string | null;
|
|
159
|
+
item_id: string;
|
|
131
160
|
name: string;
|
|
132
161
|
description: string | null;
|
|
133
162
|
amount: number;
|
|
134
163
|
currency: string;
|
|
135
164
|
interval: BillingRecurringInterval;
|
|
165
|
+
annual_amount: number | null;
|
|
136
166
|
features: string[] | null;
|
|
137
167
|
limits: Record<string, string | number> | null;
|
|
138
168
|
active: boolean;
|
|
@@ -141,6 +171,104 @@ interface BillingPlanSummary {
|
|
|
141
171
|
created_at: string;
|
|
142
172
|
updated_at: string;
|
|
143
173
|
}
|
|
174
|
+
/** Plano como retornado pelas rotas públicas (`/public/orgs/:slug/billing-plans` e
|
|
175
|
+
* `/public/orgs/:slug/plan-pages/:pageSlug`) — subconjunto de campos, sem dados internos
|
|
176
|
+
* (org_id, stripe ids, etc), pensado para renderizar uma página de preços. */
|
|
177
|
+
interface PublicBillingPlan {
|
|
178
|
+
id: string;
|
|
179
|
+
name: string;
|
|
180
|
+
description: string | null;
|
|
181
|
+
amount: number;
|
|
182
|
+
currency: string;
|
|
183
|
+
interval: BillingRecurringInterval;
|
|
184
|
+
annual_amount: number | null;
|
|
185
|
+
features: string[] | null;
|
|
186
|
+
return_url: string | null;
|
|
187
|
+
}
|
|
188
|
+
interface PublicPlanBranding {
|
|
189
|
+
logo_url: string | null;
|
|
190
|
+
background_color: string | null;
|
|
191
|
+
card_background_color: string | null;
|
|
192
|
+
card_border_color: string | null;
|
|
193
|
+
accent_color: string | null;
|
|
194
|
+
headline: string | null;
|
|
195
|
+
subheadline: string | null;
|
|
196
|
+
cta_label: string | null;
|
|
197
|
+
}
|
|
198
|
+
interface PublicOrganization {
|
|
199
|
+
id: string;
|
|
200
|
+
name: string;
|
|
201
|
+
slug: string;
|
|
202
|
+
avatar_url: string | null;
|
|
203
|
+
}
|
|
204
|
+
interface ListPublicPlansResult {
|
|
205
|
+
organization: PublicOrganization;
|
|
206
|
+
branding: PublicPlanBranding;
|
|
207
|
+
plans: PublicBillingPlan[];
|
|
208
|
+
}
|
|
209
|
+
interface GetPublicPlanPageResult extends ListPublicPlansResult {
|
|
210
|
+
page: {
|
|
211
|
+
id: string;
|
|
212
|
+
slug: string;
|
|
213
|
+
title: string;
|
|
214
|
+
description: string | null;
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
type BillingPeriod = "monthly" | "annual";
|
|
218
|
+
interface PlanCheckoutCustomerInput {
|
|
219
|
+
name: string;
|
|
220
|
+
email: string;
|
|
221
|
+
tax_id?: string;
|
|
222
|
+
phone?: string;
|
|
223
|
+
}
|
|
224
|
+
interface PlanCheckoutInput {
|
|
225
|
+
customer: PlanCheckoutCustomerInput;
|
|
226
|
+
/** Para onde redirecionar o cliente após a confirmação do pagamento. */
|
|
227
|
+
return_url?: string;
|
|
228
|
+
/** Cobrar no ciclo mensal (padrão) ou anual — anual só é aceito se o plano tiver
|
|
229
|
+
* `annual_amount` configurado, senão a API retorna 422. */
|
|
230
|
+
billing_period?: BillingPeriod;
|
|
231
|
+
}
|
|
232
|
+
interface PlanCheckoutResult {
|
|
233
|
+
checkout_token: string;
|
|
234
|
+
/** URL hospedada da Geekapps para o cliente completar o pagamento — abra em uma nova
|
|
235
|
+
* aba/WebView ou redirecione o navegador do cliente para cá. */
|
|
236
|
+
checkout_url: string;
|
|
237
|
+
subscription_id: string;
|
|
238
|
+
/** Token permanente — guarde-o (associado ao seu usuário) para depois checar se a
|
|
239
|
+
* assinatura está ativa e qual item ela cobre via `subscriptions.checkByToken`. */
|
|
240
|
+
management_token: string;
|
|
241
|
+
}
|
|
242
|
+
/** Resultado de `plans.checkoutPlan` (`POST /billing-plans/:id/checkout-for-customer`) —
|
|
243
|
+
* mesma forma de `PlanCheckoutResult`, mas para um `Customer` já existente na sua org
|
|
244
|
+
* (fluxo autenticado, sem formulário de nome/e-mail). */
|
|
245
|
+
interface CheckoutForCustomerResult {
|
|
246
|
+
checkout_token: string;
|
|
247
|
+
checkout_url: string;
|
|
248
|
+
subscription_id: string;
|
|
249
|
+
management_token: string;
|
|
250
|
+
}
|
|
251
|
+
/** Resultado de `plans.confirmPlanSubscription` (`GET /billing-plans/:id/subscription-status`) —
|
|
252
|
+
* a assinatura mais recente de um customer_id para um plano específico. */
|
|
253
|
+
interface PlanSubscriptionStatusResult {
|
|
254
|
+
subscription: {
|
|
255
|
+
id: string;
|
|
256
|
+
status: BillingRecurringStatus;
|
|
257
|
+
/** true quando status é ACTIVE, TRIALING ou PAST_DUE. */
|
|
258
|
+
active: boolean;
|
|
259
|
+
cancel_at_period_end: boolean;
|
|
260
|
+
current_period_end: string | null;
|
|
261
|
+
};
|
|
262
|
+
item: SubscriptionItemSummary;
|
|
263
|
+
plan: SubscriptionPlanSummary | null;
|
|
264
|
+
}
|
|
265
|
+
type CheckoutSessionStatus = "PENDING" | "PROCESSING" | "PAID" | "FAILED" | "EXPIRED" | "REFUNDED" | "CANCELLED";
|
|
266
|
+
interface CheckoutStatusResult {
|
|
267
|
+
status: CheckoutSessionStatus;
|
|
268
|
+
paid_at: string | null;
|
|
269
|
+
provider_url: string | null;
|
|
270
|
+
return_url: string | null;
|
|
271
|
+
}
|
|
144
272
|
interface Subscription {
|
|
145
273
|
id: string;
|
|
146
274
|
org_id: string;
|
|
@@ -156,6 +284,43 @@ interface Subscription {
|
|
|
156
284
|
created_at: string;
|
|
157
285
|
updated_at: string;
|
|
158
286
|
}
|
|
287
|
+
/** Item que a assinatura cobre no momento — snapshot atual, atualizado a cada troca
|
|
288
|
+
* de plano (não referencia o item do plano original se ele já foi trocado). */
|
|
289
|
+
interface SubscriptionItemSummary {
|
|
290
|
+
id: string;
|
|
291
|
+
name: string;
|
|
292
|
+
amount: number;
|
|
293
|
+
currency: string;
|
|
294
|
+
}
|
|
295
|
+
interface SubscriptionPlanSummary {
|
|
296
|
+
id: string;
|
|
297
|
+
item_id: string;
|
|
298
|
+
name: string;
|
|
299
|
+
amount: number;
|
|
300
|
+
currency: string;
|
|
301
|
+
interval: BillingRecurringInterval;
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Resultado de `subscriptions.checkByToken` / `GET /public/plan-management/:token` —
|
|
305
|
+
* pensado para responder exatamente "esta assinatura está ativa? de qual item?" sem
|
|
306
|
+
* exigir login nem credenciais de service account, tanto no seu backend quanto
|
|
307
|
+
* diretamente do client-side do seu app (o token não expõe nada sensível).
|
|
308
|
+
*/
|
|
309
|
+
interface SubscriptionStatusResult {
|
|
310
|
+
subscription: {
|
|
311
|
+
id: string;
|
|
312
|
+
status: BillingRecurringStatus;
|
|
313
|
+
/** true quando status é ACTIVE, TRIALING ou PAST_DUE — o atalho que a maioria dos
|
|
314
|
+
* apps quer pra decidir se libera acesso ou não. */
|
|
315
|
+
active: boolean;
|
|
316
|
+
cancel_at_period_end: boolean;
|
|
317
|
+
current_period_end: string | null;
|
|
318
|
+
};
|
|
319
|
+
/** Item que está sendo cobrado atualmente nesta assinatura. */
|
|
320
|
+
item: SubscriptionItemSummary;
|
|
321
|
+
plan: SubscriptionPlanSummary | null;
|
|
322
|
+
available_plans: SubscriptionPlanSummary[];
|
|
323
|
+
}
|
|
159
324
|
interface CreateOrderInput {
|
|
160
325
|
amount?: number;
|
|
161
326
|
currency?: string;
|
|
@@ -190,6 +355,20 @@ declare class ChargesResource {
|
|
|
190
355
|
* acompanhar até que estejam prontos.
|
|
191
356
|
*/
|
|
192
357
|
create(input: CreateChargeInput): Promise<CreateChargeResult>;
|
|
358
|
+
/**
|
|
359
|
+
* Cobrança avulsa simples, sempre em cartão — cobra direto no cartão padrão já
|
|
360
|
+
* salvo do cliente (sem fricção nenhuma). Se ele ainda não tiver um cartão salvo,
|
|
361
|
+
* retorna `checkout_url` para você abrir (ex: nova aba) e o cliente cadastrar o
|
|
362
|
+
* cartão e pagar.
|
|
363
|
+
*
|
|
364
|
+
* ```ts
|
|
365
|
+
* const result = await client.charges.charge(customerId, 5000); // R$ 50,00
|
|
366
|
+
* if (!result.charged_off_session) {
|
|
367
|
+
* window.open(result.checkout_url!, "_blank");
|
|
368
|
+
* }
|
|
369
|
+
* ```
|
|
370
|
+
*/
|
|
371
|
+
charge(customerId: string, amountCents: number, options?: Omit<QuickChargeInput, "customer_id" | "amount">): Promise<QuickChargeResult>;
|
|
193
372
|
get(id: string): Promise<Charge>;
|
|
194
373
|
getStatus(id: string): Promise<{
|
|
195
374
|
status: Charge["status"];
|
|
@@ -198,6 +377,30 @@ declare class ChargesResource {
|
|
|
198
377
|
refund(id: string): Promise<Charge>;
|
|
199
378
|
}
|
|
200
379
|
|
|
380
|
+
interface WaitUntilPaidOptions {
|
|
381
|
+
/** Intervalo entre tentativas, em ms. Default: 2000. */
|
|
382
|
+
intervalMs?: number;
|
|
383
|
+
/** Tempo máximo de espera antes de desistir, em ms. Default: 5 minutos. */
|
|
384
|
+
timeoutMs?: number;
|
|
385
|
+
}
|
|
386
|
+
declare class CheckoutResource {
|
|
387
|
+
private readonly http;
|
|
388
|
+
constructor(http: HttpClient);
|
|
389
|
+
/** Consulta o status atual de uma cobrança/checkout pelo `checkout_token` retornado
|
|
390
|
+
* por `plans.checkout()` (ou qualquer outro fluxo de cobrança do SDK). Sincroniza com
|
|
391
|
+
* o provedor de pagamento sob o capô quando ainda está PENDING. */
|
|
392
|
+
getStatus(checkoutToken: string): Promise<CheckoutStatusResult>;
|
|
393
|
+
/**
|
|
394
|
+
* Faz polling de `getStatus` até o pagamento ser confirmado (ou falhar/expirar) — é
|
|
395
|
+
* a forma recomendada de confirmar, depois de redirecionar o cliente para a
|
|
396
|
+
* `checkout_url`, que a assinatura realmente foi paga antes de liberar acesso.
|
|
397
|
+
*
|
|
398
|
+
* Resolve quando o status deixa de ser PENDING/PROCESSING. Lança um erro se o tempo
|
|
399
|
+
* limite (`timeoutMs`) for atingido antes disso.
|
|
400
|
+
*/
|
|
401
|
+
waitUntilPaid(checkoutToken: string, options?: WaitUntilPaidOptions): Promise<CheckoutStatusResult>;
|
|
402
|
+
}
|
|
403
|
+
|
|
201
404
|
declare class CustomersResource {
|
|
202
405
|
private readonly http;
|
|
203
406
|
constructor(http: HttpClient);
|
|
@@ -248,14 +451,82 @@ declare class PlansResource {
|
|
|
248
451
|
/** Não há hard-delete de planos (assinaturas existentes ainda referenciam) — para
|
|
249
452
|
* remover um plano do catálogo público, arquive-o. */
|
|
250
453
|
archive(id: string): Promise<BillingPlanSummary>;
|
|
454
|
+
/** Vincula um plano avulso a uma página de planos existente (mesma org). */
|
|
455
|
+
attachToPage(planId: string, pageId: string): Promise<BillingPlanSummary>;
|
|
456
|
+
/** Desvincula um plano da sua página, tornando-o avulso (sem página pública). */
|
|
457
|
+
detachFromPage(planId: string): Promise<BillingPlanSummary>;
|
|
458
|
+
/**
|
|
459
|
+
* Fluxo simplificado de assinatura para um `Customer` já cadastrado na sua org
|
|
460
|
+
* (autenticado, sem formulário de nome/e-mail): cria a assinatura + cobrança inicial e
|
|
461
|
+
* retorna a URL de checkout hospedada.
|
|
462
|
+
*
|
|
463
|
+
* ```ts
|
|
464
|
+
* const { checkout_url } = await client.plans.checkoutPlan(planId, customerId);
|
|
465
|
+
* // redirecione o cliente para checkout_url; ele paga e volta para sua URL de retorno
|
|
466
|
+
*
|
|
467
|
+
* // depois que o cliente volta:
|
|
468
|
+
* const { active, item } = await client.plans.confirmPlanSubscription(planId, customerId);
|
|
469
|
+
* if (active) {
|
|
470
|
+
* // ativa o plano real no seu sistema
|
|
471
|
+
* }
|
|
472
|
+
* ```
|
|
473
|
+
*/
|
|
474
|
+
checkoutPlan(planId: string, customerId: string): Promise<CheckoutForCustomerResult>;
|
|
475
|
+
/** Verifica se um `Customer` tem uma assinatura ativa deste plano (a mais recente),
|
|
476
|
+
* contraparte de `checkoutPlan` no fluxo simplificado autenticado. */
|
|
477
|
+
confirmPlanSubscription(planId: string, customerId: string): Promise<PlanSubscriptionStatusResult>;
|
|
478
|
+
/** Lista os planos ativos de uma org pelo slug público — página fixa legada, sem
|
|
479
|
+
* suporte a múltiplas páginas. Prefira `getPublicPage` para orgs com várias páginas. */
|
|
480
|
+
listPublic(orgSlug: string): Promise<ListPublicPlansResult>;
|
|
481
|
+
/** Busca uma página de planos pública específica pelo slug da org + slug da página. */
|
|
482
|
+
getPublicPage(orgSlug: string, pageSlug: string): Promise<GetPublicPlanPageResult>;
|
|
483
|
+
/**
|
|
484
|
+
* Inicia a assinatura de um plano para um cliente final: cria (ou reaproveita) o
|
|
485
|
+
* `Customer` pelo e-mail, cria a `Subscription` e retorna uma URL de checkout hospedada
|
|
486
|
+
* pela Geekapps para o cliente confirmar o pagamento.
|
|
487
|
+
*
|
|
488
|
+
* Fluxo típico:
|
|
489
|
+
* ```ts
|
|
490
|
+
* const { checkout_url, checkout_token } = await client.plans.checkout(planId, {
|
|
491
|
+
* customer: { name, email },
|
|
492
|
+
* });
|
|
493
|
+
* // redirecione o cliente (ou abra checkout_url em uma WebView/nova aba)
|
|
494
|
+
* window.location.href = checkout_url;
|
|
495
|
+
*
|
|
496
|
+
* // depois do retorno, confirme se realmente foi pago:
|
|
497
|
+
* const { status } = await client.checkout.waitUntilPaid(checkout_token);
|
|
498
|
+
* if (status === "PAID") { /* liberar acesso *\/ }
|
|
499
|
+
* ```
|
|
500
|
+
*
|
|
501
|
+
* Não requer autenticação — pode ser chamado a partir do backend do dev sem token de
|
|
502
|
+
* service account, ou do próprio SDK server-side usando qualquer token válido.
|
|
503
|
+
*/
|
|
504
|
+
checkout(planId: string, input: PlanCheckoutInput): Promise<PlanCheckoutResult>;
|
|
251
505
|
}
|
|
252
506
|
|
|
253
507
|
declare class SubscriptionsResource {
|
|
254
508
|
private readonly http;
|
|
255
509
|
constructor(http: HttpClient);
|
|
510
|
+
/** Requer autenticação (service account) — lista todas as assinaturas da sua org. */
|
|
256
511
|
list(): Promise<Subscription[]>;
|
|
512
|
+
/** Requer autenticação (service account). */
|
|
257
513
|
get(id: string): Promise<Subscription>;
|
|
514
|
+
/** Requer autenticação (service account). */
|
|
258
515
|
cancel(id: string): Promise<Subscription>;
|
|
516
|
+
/**
|
|
517
|
+
* Verifica se uma assinatura está ativa e qual item ela cobre, usando o
|
|
518
|
+
* `management_token` retornado por `plans.checkout()` — rota pública, sem
|
|
519
|
+
* autenticação, segura para chamar tanto do seu backend quanto (via fetch direto,
|
|
520
|
+
* sem o SDK) do client-side do seu app.
|
|
521
|
+
*
|
|
522
|
+
* ```ts
|
|
523
|
+
* const status = await client.subscriptions.checkByToken(managementToken);
|
|
524
|
+
* if (status.subscription.active) {
|
|
525
|
+
* console.log("cobrando", status.item.name);
|
|
526
|
+
* }
|
|
527
|
+
* ```
|
|
528
|
+
*/
|
|
529
|
+
checkByToken(managementToken: string): Promise<SubscriptionStatusResult>;
|
|
259
530
|
}
|
|
260
531
|
|
|
261
532
|
interface BillingClientOptions extends Omit<HttpClientOptions, "baseUrl"> {
|
|
@@ -264,6 +535,7 @@ interface BillingClientOptions extends Omit<HttpClientOptions, "baseUrl"> {
|
|
|
264
535
|
declare class BillingClient {
|
|
265
536
|
private readonly http;
|
|
266
537
|
readonly charges: ChargesResource;
|
|
538
|
+
readonly checkout: CheckoutResource;
|
|
267
539
|
readonly customers: CustomersResource;
|
|
268
540
|
readonly items: ItemsResource;
|
|
269
541
|
readonly orders: OrdersResource;
|
|
@@ -332,4 +604,4 @@ declare module "fastify" {
|
|
|
332
604
|
}
|
|
333
605
|
declare const _default: FastifyPluginAsync<BillingPluginOptions>;
|
|
334
606
|
|
|
335
|
-
export { BillingApiError, BillingClient, type BillingClientOptions, type BillingItem, type BillingPlanSummary, type BillingPluginOptions, type BillingRecurringInterval, type BillingRecurringStatus, type Charge, type ChargeStatus, ChargesResource, type CreateBillingPlanInput, type CreateChargeInput, type CreateChargeResult, type CreateOrderInput, type CreateOrderResult, type Customer, type CustomerInput, CustomersResource, HttpClient, type HttpClientOptions, type ItemInput, ItemsResource, OrdersResource, type PaymentMethod, PlansResource, type ProrationPolicy, type ServiceAccountOptions, ServiceAccountTokenProvider, type Subscription, SubscriptionsResource, type TokenResolver, _default as billingPlugin, createServiceAccountToken };
|
|
607
|
+
export { BillingApiError, BillingClient, type BillingClientOptions, type BillingItem, type BillingPeriod, type BillingPlanSummary, type BillingPluginOptions, type BillingRecurringInterval, type BillingRecurringStatus, type Charge, type ChargeStatus, ChargesResource, type CheckoutForCustomerResult, CheckoutResource, type CheckoutSessionStatus, type CheckoutStatusResult, type CreateBillingPlanInput, type CreateChargeInput, type CreateChargeResult, type CreateOrderInput, type CreateOrderResult, type Customer, type CustomerInput, CustomersResource, type GetPublicPlanPageResult, HttpClient, type HttpClientOptions, type ItemInput, ItemsResource, type ListPublicPlansResult, OrdersResource, type PaymentMethod, type PlanCheckoutCustomerInput, type PlanCheckoutInput, type PlanCheckoutResult, type PlanSubscriptionStatusResult, PlansResource, type ProrationPolicy, type PublicBillingPlan, type PublicOrganization, type PublicPlanBranding, type QuickChargeInput, type QuickChargeResult, type ServiceAccountOptions, ServiceAccountTokenProvider, type Subscription, type SubscriptionItemSummary, type SubscriptionPlanSummary, type SubscriptionStatusResult, SubscriptionsResource, type TokenResolver, type WaitUntilPaidOptions, _default as billingPlugin, createServiceAccountToken };
|
package/dist/index.js
CHANGED
|
@@ -220,6 +220,26 @@ var ChargesResource = class {
|
|
|
220
220
|
create(input) {
|
|
221
221
|
return this.http.post("/charges", input);
|
|
222
222
|
}
|
|
223
|
+
/**
|
|
224
|
+
* Cobrança avulsa simples, sempre em cartão — cobra direto no cartão padrão já
|
|
225
|
+
* salvo do cliente (sem fricção nenhuma). Se ele ainda não tiver um cartão salvo,
|
|
226
|
+
* retorna `checkout_url` para você abrir (ex: nova aba) e o cliente cadastrar o
|
|
227
|
+
* cartão e pagar.
|
|
228
|
+
*
|
|
229
|
+
* ```ts
|
|
230
|
+
* const result = await client.charges.charge(customerId, 5000); // R$ 50,00
|
|
231
|
+
* if (!result.charged_off_session) {
|
|
232
|
+
* window.open(result.checkout_url!, "_blank");
|
|
233
|
+
* }
|
|
234
|
+
* ```
|
|
235
|
+
*/
|
|
236
|
+
charge(customerId, amountCents, options) {
|
|
237
|
+
return this.http.post("/charges/quick", {
|
|
238
|
+
customer_id: customerId,
|
|
239
|
+
amount: amountCents,
|
|
240
|
+
...options
|
|
241
|
+
});
|
|
242
|
+
}
|
|
223
243
|
get(id) {
|
|
224
244
|
return this.http.get(`/charges/${id}`);
|
|
225
245
|
}
|
|
@@ -234,6 +254,42 @@ var ChargesResource = class {
|
|
|
234
254
|
}
|
|
235
255
|
};
|
|
236
256
|
|
|
257
|
+
// src/resources/checkout.ts
|
|
258
|
+
var CheckoutResource = class {
|
|
259
|
+
constructor(http) {
|
|
260
|
+
this.http = http;
|
|
261
|
+
}
|
|
262
|
+
/** Consulta o status atual de uma cobrança/checkout pelo `checkout_token` retornado
|
|
263
|
+
* por `plans.checkout()` (ou qualquer outro fluxo de cobrança do SDK). Sincroniza com
|
|
264
|
+
* o provedor de pagamento sob o capô quando ainda está PENDING. */
|
|
265
|
+
getStatus(checkoutToken) {
|
|
266
|
+
return this.http.get(`/checkout/${checkoutToken}/status`);
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Faz polling de `getStatus` até o pagamento ser confirmado (ou falhar/expirar) — é
|
|
270
|
+
* a forma recomendada de confirmar, depois de redirecionar o cliente para a
|
|
271
|
+
* `checkout_url`, que a assinatura realmente foi paga antes de liberar acesso.
|
|
272
|
+
*
|
|
273
|
+
* Resolve quando o status deixa de ser PENDING/PROCESSING. Lança um erro se o tempo
|
|
274
|
+
* limite (`timeoutMs`) for atingido antes disso.
|
|
275
|
+
*/
|
|
276
|
+
async waitUntilPaid(checkoutToken, options = {}) {
|
|
277
|
+
const intervalMs = options.intervalMs ?? 2e3;
|
|
278
|
+
const timeoutMs = options.timeoutMs ?? 5 * 60 * 1e3;
|
|
279
|
+
const deadline = Date.now() + timeoutMs;
|
|
280
|
+
for (; ; ) {
|
|
281
|
+
const result = await this.getStatus(checkoutToken);
|
|
282
|
+
if (result.status !== "PENDING" && result.status !== "PROCESSING") {
|
|
283
|
+
return result;
|
|
284
|
+
}
|
|
285
|
+
if (Date.now() >= deadline) {
|
|
286
|
+
throw new Error(`Tempo limite excedido aguardando confirma\xE7\xE3o de pagamento (checkout_token=${checkoutToken}).`);
|
|
287
|
+
}
|
|
288
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
|
|
237
293
|
// src/resources/customers.ts
|
|
238
294
|
var CustomersResource = class {
|
|
239
295
|
constructor(http) {
|
|
@@ -316,6 +372,72 @@ var PlansResource = class {
|
|
|
316
372
|
archive(id) {
|
|
317
373
|
return this.http.patch(`/billing-plans/${id}`, { active: false });
|
|
318
374
|
}
|
|
375
|
+
/** Vincula um plano avulso a uma página de planos existente (mesma org). */
|
|
376
|
+
attachToPage(planId, pageId) {
|
|
377
|
+
return this.http.patch(`/billing-plans/${planId}`, { plan_page_id: pageId });
|
|
378
|
+
}
|
|
379
|
+
/** Desvincula um plano da sua página, tornando-o avulso (sem página pública). */
|
|
380
|
+
detachFromPage(planId) {
|
|
381
|
+
return this.http.patch(`/billing-plans/${planId}`, { plan_page_id: null });
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Fluxo simplificado de assinatura para um `Customer` já cadastrado na sua org
|
|
385
|
+
* (autenticado, sem formulário de nome/e-mail): cria a assinatura + cobrança inicial e
|
|
386
|
+
* retorna a URL de checkout hospedada.
|
|
387
|
+
*
|
|
388
|
+
* ```ts
|
|
389
|
+
* const { checkout_url } = await client.plans.checkoutPlan(planId, customerId);
|
|
390
|
+
* // redirecione o cliente para checkout_url; ele paga e volta para sua URL de retorno
|
|
391
|
+
*
|
|
392
|
+
* // depois que o cliente volta:
|
|
393
|
+
* const { active, item } = await client.plans.confirmPlanSubscription(planId, customerId);
|
|
394
|
+
* if (active) {
|
|
395
|
+
* // ativa o plano real no seu sistema
|
|
396
|
+
* }
|
|
397
|
+
* ```
|
|
398
|
+
*/
|
|
399
|
+
checkoutPlan(planId, customerId) {
|
|
400
|
+
return this.http.post(`/billing-plans/${planId}/checkout-for-customer`, { customer_id: customerId });
|
|
401
|
+
}
|
|
402
|
+
/** Verifica se um `Customer` tem uma assinatura ativa deste plano (a mais recente),
|
|
403
|
+
* contraparte de `checkoutPlan` no fluxo simplificado autenticado. */
|
|
404
|
+
confirmPlanSubscription(planId, customerId) {
|
|
405
|
+
return this.http.get(`/billing-plans/${planId}/subscription-status?customer_id=${encodeURIComponent(customerId)}`);
|
|
406
|
+
}
|
|
407
|
+
// ─── Rotas públicas (sem auth — usadas para montar sua própria página de preços) ──
|
|
408
|
+
/** Lista os planos ativos de uma org pelo slug público — página fixa legada, sem
|
|
409
|
+
* suporte a múltiplas páginas. Prefira `getPublicPage` para orgs com várias páginas. */
|
|
410
|
+
listPublic(orgSlug) {
|
|
411
|
+
return this.http.get(`/public/orgs/${orgSlug}/billing-plans`);
|
|
412
|
+
}
|
|
413
|
+
/** Busca uma página de planos pública específica pelo slug da org + slug da página. */
|
|
414
|
+
getPublicPage(orgSlug, pageSlug) {
|
|
415
|
+
return this.http.get(`/public/orgs/${orgSlug}/plan-pages/${pageSlug}`);
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Inicia a assinatura de um plano para um cliente final: cria (ou reaproveita) o
|
|
419
|
+
* `Customer` pelo e-mail, cria a `Subscription` e retorna uma URL de checkout hospedada
|
|
420
|
+
* pela Geekapps para o cliente confirmar o pagamento.
|
|
421
|
+
*
|
|
422
|
+
* Fluxo típico:
|
|
423
|
+
* ```ts
|
|
424
|
+
* const { checkout_url, checkout_token } = await client.plans.checkout(planId, {
|
|
425
|
+
* customer: { name, email },
|
|
426
|
+
* });
|
|
427
|
+
* // redirecione o cliente (ou abra checkout_url em uma WebView/nova aba)
|
|
428
|
+
* window.location.href = checkout_url;
|
|
429
|
+
*
|
|
430
|
+
* // depois do retorno, confirme se realmente foi pago:
|
|
431
|
+
* const { status } = await client.checkout.waitUntilPaid(checkout_token);
|
|
432
|
+
* if (status === "PAID") { /* liberar acesso *\/ }
|
|
433
|
+
* ```
|
|
434
|
+
*
|
|
435
|
+
* Não requer autenticação — pode ser chamado a partir do backend do dev sem token de
|
|
436
|
+
* service account, ou do próprio SDK server-side usando qualquer token válido.
|
|
437
|
+
*/
|
|
438
|
+
checkout(planId, input) {
|
|
439
|
+
return this.http.post(`/public/billing-plans/${planId}/checkout`, input);
|
|
440
|
+
}
|
|
319
441
|
};
|
|
320
442
|
|
|
321
443
|
// src/resources/subscriptions.ts
|
|
@@ -323,15 +445,34 @@ var SubscriptionsResource = class {
|
|
|
323
445
|
constructor(http) {
|
|
324
446
|
this.http = http;
|
|
325
447
|
}
|
|
448
|
+
/** Requer autenticação (service account) — lista todas as assinaturas da sua org. */
|
|
326
449
|
list() {
|
|
327
450
|
return this.http.get("/billing-subscriptions");
|
|
328
451
|
}
|
|
452
|
+
/** Requer autenticação (service account). */
|
|
329
453
|
get(id) {
|
|
330
454
|
return this.http.get(`/billing-subscriptions/${id}`);
|
|
331
455
|
}
|
|
456
|
+
/** Requer autenticação (service account). */
|
|
332
457
|
cancel(id) {
|
|
333
458
|
return this.http.patch(`/billing-subscriptions/${id}/cancel`);
|
|
334
459
|
}
|
|
460
|
+
/**
|
|
461
|
+
* Verifica se uma assinatura está ativa e qual item ela cobre, usando o
|
|
462
|
+
* `management_token` retornado por `plans.checkout()` — rota pública, sem
|
|
463
|
+
* autenticação, segura para chamar tanto do seu backend quanto (via fetch direto,
|
|
464
|
+
* sem o SDK) do client-side do seu app.
|
|
465
|
+
*
|
|
466
|
+
* ```ts
|
|
467
|
+
* const status = await client.subscriptions.checkByToken(managementToken);
|
|
468
|
+
* if (status.subscription.active) {
|
|
469
|
+
* console.log("cobrando", status.item.name);
|
|
470
|
+
* }
|
|
471
|
+
* ```
|
|
472
|
+
*/
|
|
473
|
+
checkByToken(managementToken) {
|
|
474
|
+
return this.http.get(`/public/plan-management/${managementToken}`);
|
|
475
|
+
}
|
|
335
476
|
};
|
|
336
477
|
|
|
337
478
|
// src/client.ts
|
|
@@ -339,6 +480,7 @@ var BillingClient = class {
|
|
|
339
480
|
constructor(options) {
|
|
340
481
|
this.http = new HttpClient(options);
|
|
341
482
|
this.charges = new ChargesResource(this.http);
|
|
483
|
+
this.checkout = new CheckoutResource(this.http);
|
|
342
484
|
this.customers = new CustomersResource(this.http);
|
|
343
485
|
this.items = new ItemsResource(this.http);
|
|
344
486
|
this.orders = new OrdersResource(this.http);
|
|
@@ -444,6 +586,7 @@ export {
|
|
|
444
586
|
BillingApiError,
|
|
445
587
|
BillingClient,
|
|
446
588
|
ChargesResource,
|
|
589
|
+
CheckoutResource,
|
|
447
590
|
CustomersResource,
|
|
448
591
|
HttpClient,
|
|
449
592
|
ItemsResource,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../node_modules/.bun/fastify-plugin@6.0.0/node_modules/fastify-plugin/lib/getPluginName.js","../../../node_modules/.bun/fastify-plugin@6.0.0/node_modules/fastify-plugin/lib/toCamelCase.js","../../../node_modules/.bun/fastify-plugin@6.0.0/node_modules/fastify-plugin/index.js","../src/errors.ts","../src/http.ts","../src/resources/charges.ts","../src/resources/customers.ts","../src/resources/items.ts","../src/resources/orders.ts","../src/resources/plans.ts","../src/resources/subscriptions.ts","../src/client.ts","../src/plugin.ts","../src/service-account.ts"],"sourcesContent":["'use strict'\n\nconst fpStackTracePattern = /at\\s(?:.*\\.)?plugin\\s.*\\n\\s*(.*)/\nconst fileNamePattern = /(\\w*(\\.\\w*)*)\\..*/\n\nmodule.exports = function getPluginName (fn) {\n if (fn.name.length > 0) return fn.name\n\n const stackTraceLimit = Error.stackTraceLimit\n Error.stackTraceLimit = 10\n try {\n throw new Error('anonymous function')\n } catch (e) {\n Error.stackTraceLimit = stackTraceLimit\n return extractPluginName(e.stack)\n }\n}\n\nfunction extractPluginName (stack) {\n const m = stack.match(fpStackTracePattern)\n\n // get last section of path and match for filename\n return m ? m[1].split(/[/\\\\]/).slice(-1)[0].match(fileNamePattern)[1] : 'anonymous'\n}\nmodule.exports.extractPluginName = extractPluginName\n","'use strict'\n\nmodule.exports = function toCamelCase (name) {\n if (name[0] === '@') {\n name = name.slice(1).replace('/', '-')\n }\n return name.replace(/-(.)/g, function (match, g1) {\n return g1.toUpperCase()\n })\n}\n","'use strict'\n\nconst getPluginName = require('./lib/getPluginName')\nconst toCamelCase = require('./lib/toCamelCase')\n\nlet count = 0\n\nfunction plugin (fn, options = {}) {\n let autoName = false\n\n if (fn.default !== undefined) {\n // Support for 'export default' behaviour in transpiled ECMAScript module\n fn = fn.default\n }\n\n if (typeof fn !== 'function') {\n throw new TypeError(\n `fastify-plugin expects a function, instead got a '${typeof fn}'`\n )\n }\n\n if (typeof options === 'string') {\n options = {\n fastify: options\n }\n }\n\n if (\n typeof options !== 'object' ||\n Array.isArray(options) ||\n options === null\n ) {\n throw new TypeError('The options object should be an object')\n }\n\n if (options.fastify !== undefined && typeof options.fastify !== 'string') {\n throw new TypeError(`fastify-plugin expects a version string, instead got '${typeof options.fastify}'`)\n }\n\n if (!options.name) {\n autoName = true\n options.name = getPluginName(fn) + '-auto-' + count++\n }\n\n fn[Symbol.for('skip-override')] = options.encapsulate !== true\n fn[Symbol.for('fastify.display-name')] = options.name\n fn[Symbol.for('plugin-meta')] = options\n\n // Faux modules support\n if (!fn.default) {\n fn.default = fn\n }\n\n // TypeScript support for named imports\n // See https://github.com/fastify/fastify/issues/2404 for more details\n // The type definitions would have to be update to match this.\n const camelCase = toCamelCase(options.name)\n if (!autoName && !fn[camelCase]) {\n fn[camelCase] = fn\n }\n\n return fn\n}\n\nmodule.exports = plugin\nmodule.exports.default = plugin\nmodule.exports.fastifyPlugin = plugin\n","export class BillingApiError extends Error {\n constructor(\n public readonly status: number,\n message: string,\n public readonly detail?: string,\n ) {\n super(detail ? `${message}: ${detail}` : message);\n this.name = \"BillingApiError\";\n }\n\n get isNotFound() {\n return this.status === 404;\n }\n\n get isUnauthorized() {\n return this.status === 401;\n }\n\n get isForbidden() {\n return this.status === 403;\n }\n\n get isRateLimited() {\n return this.status === 429;\n }\n\n get isValidationError() {\n return this.status === 400 || this.status === 422;\n }\n}\n","import { BillingApiError } from \"./errors.js\";\n\nexport type TokenResolver = string | (() => string | Promise<string>);\n\nexport interface HttpClientOptions {\n baseUrl: string;\n token: TokenResolver;\n organizationId?: string | (() => string | Promise<string>);\n /**\n * Ambiente de billing (dev/prod) — enviado via header x-billing-mode em toda chamada\n * feita por esta instância. Defina uma vez aqui; os métodos individuais (charges.create,\n * customers.list, etc) nunca precisam recebê-lo de novo. Default: \"prod\".\n */\n mode?: string | (() => string | Promise<string>);\n}\n\nconst DEFAULT_MODE = \"prod\";\n\nexport class HttpClient {\n private readonly baseUrl: string;\n private readonly token: TokenResolver;\n private readonly organizationId?: string | (() => string | Promise<string>);\n private readonly mode: string | (() => string | Promise<string>);\n\n constructor(options: HttpClientOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, \"\");\n this.token = options.token;\n this.organizationId = options.organizationId;\n this.mode = options.mode ?? DEFAULT_MODE;\n }\n\n private async resolveToken(): Promise<string> {\n return typeof this.token === \"function\" ? await this.token() : this.token;\n }\n\n private async resolveOrgId(): Promise<string | undefined> {\n if (!this.organizationId) return undefined;\n return typeof this.organizationId === \"function\"\n ? await this.organizationId()\n : this.organizationId;\n }\n\n private async resolveMode(): Promise<string> {\n return typeof this.mode === \"function\" ? await this.mode() : this.mode;\n }\n\n async request<T = unknown>(\n method: string,\n path: string,\n body?: unknown,\n ): Promise<T> {\n const token = await this.resolveToken();\n const orgId = await this.resolveOrgId();\n const mode = await this.resolveMode();\n\n const res = await fetch(`${this.baseUrl}${path}`, {\n method,\n headers: {\n Authorization: `Bearer ${token}`,\n ...(body !== undefined ? { \"Content-Type\": \"application/json\" } : {}),\n ...(orgId ? { \"x-org-id\": orgId } : {}),\n \"x-billing-mode\": mode,\n },\n ...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n });\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({})) as {\n error?: string;\n message?: string;\n };\n throw new BillingApiError(\n res.status,\n err.error ?? err.message ?? `HTTP ${res.status}`,\n );\n }\n\n if (res.status === 202 || res.status === 204) {\n if (res.status === 204) return undefined as T;\n return res.json().catch(() => undefined) as Promise<T>;\n }\n return res.json() as Promise<T>;\n }\n\n get<T>(path: string) {\n return this.request<T>(\"GET\", path);\n }\n\n post<T>(path: string, body?: unknown) {\n return this.request<T>(\"POST\", path, body);\n }\n\n put<T>(path: string, body?: unknown) {\n return this.request<T>(\"PUT\", path, body);\n }\n\n patch<T>(path: string, body?: unknown) {\n return this.request<T>(\"PATCH\", path, body);\n }\n\n delete<T = void>(path: string) {\n return this.request<T>(\"DELETE\", path);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { Charge, CreateChargeInput, CreateChargeResult } from \"../types.js\";\n\nexport class ChargesResource {\n constructor(private readonly http: HttpClient) {}\n\n list(params?: { installment_group_id?: string }): Promise<Charge[]> {\n const qs = params?.installment_group_id\n ? `?installment_group_id=${encodeURIComponent(params.installment_group_id)}`\n : \"\";\n return this.http.get<Charge[]>(`/charges${qs}`);\n }\n\n /**\n * Cria uma cobrança (PIX, boleto ou cartão). A geração de fato acontece de forma\n * assíncrona no backend — a resposta volta com a charge em PENDING, sem os campos\n * do método (QR code, boleto, etc) ainda preenchidos. Use `get`/`getStatus` para\n * acompanhar até que estejam prontos.\n */\n create(input: CreateChargeInput): Promise<CreateChargeResult> {\n return this.http.post<CreateChargeResult>(\"/charges\", input);\n }\n\n get(id: string): Promise<Charge> {\n return this.http.get<Charge>(`/charges/${id}`);\n }\n\n getStatus(id: string): Promise<{ status: Charge[\"status\"] }> {\n return this.http.get(`/charges/${id}/status`);\n }\n\n cancel(id: string): Promise<Charge> {\n return this.http.patch<Charge>(`/charges/${id}/cancel`);\n }\n\n refund(id: string): Promise<Charge> {\n return this.http.post<Charge>(`/charges/${id}/refund`);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { Customer, CustomerInput } from \"../types.js\";\n\nexport class CustomersResource {\n constructor(private readonly http: HttpClient) {}\n\n list(): Promise<Customer[]> {\n return this.http.get<Customer[]>(\"/customers\");\n }\n\n create(input: CustomerInput): Promise<Customer> {\n return this.http.post<Customer>(\"/customers\", input);\n }\n\n get(id: string): Promise<Customer> {\n return this.http.get<Customer>(`/customers/${id}`);\n }\n\n update(id: string, input: Partial<CustomerInput>): Promise<Customer> {\n return this.http.patch<Customer>(`/customers/${id}`, input);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { BillingItem } from \"../types.js\";\n\nexport interface ItemInput {\n name: string;\n description?: string;\n amount: number;\n currency?: string;\n}\n\nexport class ItemsResource {\n constructor(private readonly http: HttpClient) {}\n\n list(): Promise<BillingItem[]> {\n return this.http.get<BillingItem[]>(\"/items\");\n }\n\n create(input: ItemInput): Promise<BillingItem> {\n return this.http.post<BillingItem>(\"/items\", input);\n }\n\n get(id: string): Promise<BillingItem> {\n return this.http.get<BillingItem>(`/items/${id}`);\n }\n\n update(id: string, input: Partial<ItemInput>): Promise<BillingItem> {\n return this.http.patch<BillingItem>(`/items/${id}`, input);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { CreateOrderInput, CreateOrderResult } from \"../types.js\";\n\nexport class OrdersResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Cria um pedido parcelado (parcelamento real via cobranças avulsas agendadas,\n * não assinatura). Retorna o `client_secret` da 1ª parcela para o front-end\n * confirmar via Stripe Elements — as parcelas seguintes são cobradas\n * automaticamente pelo backend no cartão salvo.\n */\n create(input: CreateOrderInput): Promise<CreateOrderResult> {\n return this.http.post<CreateOrderResult>(\"/orders\", input);\n }\n\n list(): Promise<unknown[]> {\n return this.http.get(\"/orders\");\n }\n\n get(id: string): Promise<unknown> {\n return this.http.get(`/orders/${id}`);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { BillingPlanSummary, CreateBillingPlanInput } from \"../types.js\";\n\nexport class PlansResource {\n constructor(private readonly http: HttpClient) {}\n\n list(): Promise<BillingPlanSummary[]> {\n return this.http.get<BillingPlanSummary[]>(\"/billing-plans\");\n }\n\n get(id: string): Promise<BillingPlanSummary> {\n return this.http.get<BillingPlanSummary>(`/billing-plans/${id}`);\n }\n\n create(input: CreateBillingPlanInput): Promise<BillingPlanSummary> {\n return this.http.post<BillingPlanSummary>(\"/billing-plans\", input);\n }\n\n update(id: string, input: Partial<CreateBillingPlanInput> & { active?: boolean }): Promise<BillingPlanSummary> {\n return this.http.patch<BillingPlanSummary>(`/billing-plans/${id}`, input);\n }\n\n /** Não há hard-delete de planos (assinaturas existentes ainda referenciam) — para\n * remover um plano do catálogo público, arquive-o. */\n archive(id: string): Promise<BillingPlanSummary> {\n return this.http.patch<BillingPlanSummary>(`/billing-plans/${id}`, { active: false });\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { Subscription } from \"../types.js\";\n\nexport class SubscriptionsResource {\n constructor(private readonly http: HttpClient) {}\n\n list(): Promise<Subscription[]> {\n return this.http.get<Subscription[]>(\"/billing-subscriptions\");\n }\n\n get(id: string): Promise<Subscription> {\n return this.http.get<Subscription>(`/billing-subscriptions/${id}`);\n }\n\n cancel(id: string): Promise<Subscription> {\n return this.http.patch<Subscription>(`/billing-subscriptions/${id}/cancel`);\n }\n}\n","import { HttpClient, type HttpClientOptions } from \"./http.js\";\nimport { ChargesResource } from \"./resources/charges.js\";\nimport { CustomersResource } from \"./resources/customers.js\";\nimport { ItemsResource } from \"./resources/items.js\";\nimport { OrdersResource } from \"./resources/orders.js\";\nimport { PlansResource } from \"./resources/plans.js\";\nimport { SubscriptionsResource } from \"./resources/subscriptions.js\";\n\nexport interface BillingClientOptions\n extends Omit<HttpClientOptions, \"baseUrl\"> {\n baseUrl?: string;\n}\n\nexport class BillingClient {\n private readonly http: HttpClient;\n\n readonly charges: ChargesResource;\n readonly customers: CustomersResource;\n readonly items: ItemsResource;\n readonly orders: OrdersResource;\n readonly plans: PlansResource;\n readonly subscriptions: SubscriptionsResource;\n\n constructor(options: HttpClientOptions) {\n this.http = new HttpClient(options);\n\n this.charges = new ChargesResource(this.http);\n this.customers = new CustomersResource(this.http);\n this.items = new ItemsResource(this.http);\n this.orders = new OrdersResource(this.http);\n this.plans = new PlansResource(this.http);\n this.subscriptions = new SubscriptionsResource(this.http);\n }\n}\n","import type { FastifyInstance, FastifyPluginAsync } from \"fastify\";\nimport fp from \"fastify-plugin\";\nimport { BillingClient } from \"./client.js\";\nimport { ServiceAccountTokenProvider, type ServiceAccountOptions } from \"./service-account.js\";\n\nexport interface BillingPluginOptions {\n /** Geekapps Billing API base URL */\n baseUrl: string;\n /** Service account credentials — required */\n serviceAccount: ServiceAccountOptions;\n /** Ambiente de billing (dev/prod). Default: \"prod\". */\n mode?: string;\n}\n\ndeclare module \"fastify\" {\n interface FastifyInstance {\n billingClient: BillingClient;\n }\n}\n\nconst billingPlugin: FastifyPluginAsync<BillingPluginOptions> = async (\n fastify: FastifyInstance,\n options: BillingPluginOptions,\n) => {\n const tokenProvider = new ServiceAccountTokenProvider(options.serviceAccount);\n\n const client = new BillingClient({\n baseUrl: options.baseUrl,\n token: () => tokenProvider.getToken(),\n organizationId: () => tokenProvider.getOrganizationId() as Promise<string>,\n mode: options.mode,\n });\n\n fastify.decorate(\"billingClient\", client);\n};\n\nexport default fp(billingPlugin, {\n fastify: \">=4.0.0\",\n name: \"@geekapps/billing-fastify\",\n});\n","import type { TokenResolver } from \"./http.js\";\n\nexport interface ServiceAccountOptions {\n /** Geekapps Auth issuer base URL (e.g. https://accounts-api.geekapps.com.br) */\n issuerUrl: string;\n clientId: string;\n clientSecret: string;\n /** Seconds before expiry to proactively refresh. Defaults to 30. */\n refreshBeforeExpirySeconds?: number;\n}\n\ninterface CachedToken {\n value: string;\n expiresAt: number; // ms epoch\n organizationId: string | undefined;\n}\n\nfunction decodeJwtPayload(token: string): Record<string, unknown> {\n try {\n const [, payload] = token.split(\".\");\n if (!payload) return {};\n const json = Buffer.from(payload, \"base64url\").toString(\"utf-8\");\n return JSON.parse(json) as Record<string, unknown>;\n } catch {\n return {};\n }\n}\n\n/**\n * Fetches a short-lived token from the Geekapps Auth service using\n * client_credentials grant and caches it until near expiry.\n *\n * The organizationId claim is extracted automatically from the JWT payload.\n */\nexport class ServiceAccountTokenProvider {\n private readonly issuerUrl: string;\n private readonly clientId: string;\n private readonly clientSecret: string;\n private readonly refreshBeforeMs: number;\n private cached: CachedToken | null = null;\n private inflight: Promise<CachedToken> | null = null;\n\n constructor(options: ServiceAccountOptions) {\n this.issuerUrl = options.issuerUrl.replace(/\\/$/, \"\");\n this.clientId = options.clientId;\n this.clientSecret = options.clientSecret;\n this.refreshBeforeMs = (options.refreshBeforeExpirySeconds ?? 30) * 1000;\n }\n\n private async ensureFresh(): Promise<CachedToken> {\n const now = Date.now();\n\n if (this.cached && this.cached.expiresAt - now > this.refreshBeforeMs) {\n return this.cached;\n }\n\n if (this.inflight) return this.inflight;\n\n this.inflight = this.fetchToken().finally(() => {\n this.inflight = null;\n });\n\n return this.inflight;\n }\n\n /** Returns a valid access token. */\n getToken(): Promise<string> {\n return this.ensureFresh().then((c) => c.value);\n }\n\n /** Returns the organizationId embedded in the service account JWT. */\n getOrganizationId(): Promise<string | undefined> {\n return this.ensureFresh().then((c) => c.organizationId);\n }\n\n private async fetchToken(): Promise<CachedToken> {\n const credentials = Buffer.from(`${this.clientId}:${this.clientSecret}`).toString(\"base64\");\n\n const res = await fetch(`${this.issuerUrl}/auth/token`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Basic ${credentials}`,\n },\n body: JSON.stringify({ grant_type: \"service_account\" }),\n });\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({})) as { error?: string };\n throw new Error(\n `ServiceAccount token fetch failed (${res.status}): ${err.error ?? \"unknown error\"}`,\n );\n }\n\n const data = await res.json() as { access_token: string; expires_in?: number };\n\n const claims = decodeJwtPayload(data.access_token);\n const organizationId =\n typeof claims.organizationId === \"string\" ? claims.organizationId :\n typeof claims.organization_id === \"string\" ? claims.organization_id :\n undefined;\n\n const expiresInMs = (data.expires_in ?? 420) * 1000;\n this.cached = {\n value: data.access_token,\n expiresAt: Date.now() + expiresInMs,\n organizationId,\n };\n\n return this.cached;\n }\n\n /** Returns this provider as a TokenResolver to pass directly to BillingClient. */\n asTokenResolver(): TokenResolver {\n return () => this.getToken();\n }\n}\n\n/** Convenience factory. Returns a TokenResolver ready for use in BillingClient. */\nexport function createServiceAccountToken(\n options: ServiceAccountOptions,\n): TokenResolver {\n return new ServiceAccountTokenProvider(options).asTokenResolver();\n}\n"],"mappings":"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","names":["fp"]}
|
|
1
|
+
{"version":3,"sources":["../../../node_modules/.bun/fastify-plugin@6.0.0/node_modules/fastify-plugin/lib/getPluginName.js","../../../node_modules/.bun/fastify-plugin@6.0.0/node_modules/fastify-plugin/lib/toCamelCase.js","../../../node_modules/.bun/fastify-plugin@6.0.0/node_modules/fastify-plugin/index.js","../src/errors.ts","../src/http.ts","../src/resources/charges.ts","../src/resources/checkout.ts","../src/resources/customers.ts","../src/resources/items.ts","../src/resources/orders.ts","../src/resources/plans.ts","../src/resources/subscriptions.ts","../src/client.ts","../src/plugin.ts","../src/service-account.ts"],"sourcesContent":["'use strict'\n\nconst fpStackTracePattern = /at\\s(?:.*\\.)?plugin\\s.*\\n\\s*(.*)/\nconst fileNamePattern = /(\\w*(\\.\\w*)*)\\..*/\n\nmodule.exports = function getPluginName (fn) {\n if (fn.name.length > 0) return fn.name\n\n const stackTraceLimit = Error.stackTraceLimit\n Error.stackTraceLimit = 10\n try {\n throw new Error('anonymous function')\n } catch (e) {\n Error.stackTraceLimit = stackTraceLimit\n return extractPluginName(e.stack)\n }\n}\n\nfunction extractPluginName (stack) {\n const m = stack.match(fpStackTracePattern)\n\n // get last section of path and match for filename\n return m ? m[1].split(/[/\\\\]/).slice(-1)[0].match(fileNamePattern)[1] : 'anonymous'\n}\nmodule.exports.extractPluginName = extractPluginName\n","'use strict'\n\nmodule.exports = function toCamelCase (name) {\n if (name[0] === '@') {\n name = name.slice(1).replace('/', '-')\n }\n return name.replace(/-(.)/g, function (match, g1) {\n return g1.toUpperCase()\n })\n}\n","'use strict'\n\nconst getPluginName = require('./lib/getPluginName')\nconst toCamelCase = require('./lib/toCamelCase')\n\nlet count = 0\n\nfunction plugin (fn, options = {}) {\n let autoName = false\n\n if (fn.default !== undefined) {\n // Support for 'export default' behaviour in transpiled ECMAScript module\n fn = fn.default\n }\n\n if (typeof fn !== 'function') {\n throw new TypeError(\n `fastify-plugin expects a function, instead got a '${typeof fn}'`\n )\n }\n\n if (typeof options === 'string') {\n options = {\n fastify: options\n }\n }\n\n if (\n typeof options !== 'object' ||\n Array.isArray(options) ||\n options === null\n ) {\n throw new TypeError('The options object should be an object')\n }\n\n if (options.fastify !== undefined && typeof options.fastify !== 'string') {\n throw new TypeError(`fastify-plugin expects a version string, instead got '${typeof options.fastify}'`)\n }\n\n if (!options.name) {\n autoName = true\n options.name = getPluginName(fn) + '-auto-' + count++\n }\n\n fn[Symbol.for('skip-override')] = options.encapsulate !== true\n fn[Symbol.for('fastify.display-name')] = options.name\n fn[Symbol.for('plugin-meta')] = options\n\n // Faux modules support\n if (!fn.default) {\n fn.default = fn\n }\n\n // TypeScript support for named imports\n // See https://github.com/fastify/fastify/issues/2404 for more details\n // The type definitions would have to be update to match this.\n const camelCase = toCamelCase(options.name)\n if (!autoName && !fn[camelCase]) {\n fn[camelCase] = fn\n }\n\n return fn\n}\n\nmodule.exports = plugin\nmodule.exports.default = plugin\nmodule.exports.fastifyPlugin = plugin\n","export class BillingApiError extends Error {\n constructor(\n public readonly status: number,\n message: string,\n public readonly detail?: string,\n ) {\n super(detail ? `${message}: ${detail}` : message);\n this.name = \"BillingApiError\";\n }\n\n get isNotFound() {\n return this.status === 404;\n }\n\n get isUnauthorized() {\n return this.status === 401;\n }\n\n get isForbidden() {\n return this.status === 403;\n }\n\n get isRateLimited() {\n return this.status === 429;\n }\n\n get isValidationError() {\n return this.status === 400 || this.status === 422;\n }\n}\n","import { BillingApiError } from \"./errors.js\";\n\nexport type TokenResolver = string | (() => string | Promise<string>);\n\nexport interface HttpClientOptions {\n baseUrl: string;\n token: TokenResolver;\n organizationId?: string | (() => string | Promise<string>);\n /**\n * Ambiente de billing (dev/prod) — enviado via header x-billing-mode em toda chamada\n * feita por esta instância. Defina uma vez aqui; os métodos individuais (charges.create,\n * customers.list, etc) nunca precisam recebê-lo de novo. Default: \"prod\".\n */\n mode?: string | (() => string | Promise<string>);\n}\n\nconst DEFAULT_MODE = \"prod\";\n\nexport class HttpClient {\n private readonly baseUrl: string;\n private readonly token: TokenResolver;\n private readonly organizationId?: string | (() => string | Promise<string>);\n private readonly mode: string | (() => string | Promise<string>);\n\n constructor(options: HttpClientOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, \"\");\n this.token = options.token;\n this.organizationId = options.organizationId;\n this.mode = options.mode ?? DEFAULT_MODE;\n }\n\n private async resolveToken(): Promise<string> {\n return typeof this.token === \"function\" ? await this.token() : this.token;\n }\n\n private async resolveOrgId(): Promise<string | undefined> {\n if (!this.organizationId) return undefined;\n return typeof this.organizationId === \"function\"\n ? await this.organizationId()\n : this.organizationId;\n }\n\n private async resolveMode(): Promise<string> {\n return typeof this.mode === \"function\" ? await this.mode() : this.mode;\n }\n\n async request<T = unknown>(\n method: string,\n path: string,\n body?: unknown,\n ): Promise<T> {\n const token = await this.resolveToken();\n const orgId = await this.resolveOrgId();\n const mode = await this.resolveMode();\n\n const res = await fetch(`${this.baseUrl}${path}`, {\n method,\n headers: {\n Authorization: `Bearer ${token}`,\n ...(body !== undefined ? { \"Content-Type\": \"application/json\" } : {}),\n ...(orgId ? { \"x-org-id\": orgId } : {}),\n \"x-billing-mode\": mode,\n },\n ...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n });\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({})) as {\n error?: string;\n message?: string;\n };\n throw new BillingApiError(\n res.status,\n err.error ?? err.message ?? `HTTP ${res.status}`,\n );\n }\n\n if (res.status === 202 || res.status === 204) {\n if (res.status === 204) return undefined as T;\n return res.json().catch(() => undefined) as Promise<T>;\n }\n return res.json() as Promise<T>;\n }\n\n get<T>(path: string) {\n return this.request<T>(\"GET\", path);\n }\n\n post<T>(path: string, body?: unknown) {\n return this.request<T>(\"POST\", path, body);\n }\n\n put<T>(path: string, body?: unknown) {\n return this.request<T>(\"PUT\", path, body);\n }\n\n patch<T>(path: string, body?: unknown) {\n return this.request<T>(\"PATCH\", path, body);\n }\n\n delete<T = void>(path: string) {\n return this.request<T>(\"DELETE\", path);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { Charge, CreateChargeInput, CreateChargeResult, QuickChargeInput, QuickChargeResult } from \"../types.js\";\n\nexport class ChargesResource {\n constructor(private readonly http: HttpClient) {}\n\n list(params?: { installment_group_id?: string }): Promise<Charge[]> {\n const qs = params?.installment_group_id\n ? `?installment_group_id=${encodeURIComponent(params.installment_group_id)}`\n : \"\";\n return this.http.get<Charge[]>(`/charges${qs}`);\n }\n\n /**\n * Cria uma cobrança (PIX, boleto ou cartão). A geração de fato acontece de forma\n * assíncrona no backend — a resposta volta com a charge em PENDING, sem os campos\n * do método (QR code, boleto, etc) ainda preenchidos. Use `get`/`getStatus` para\n * acompanhar até que estejam prontos.\n */\n create(input: CreateChargeInput): Promise<CreateChargeResult> {\n return this.http.post<CreateChargeResult>(\"/charges\", input);\n }\n\n /**\n * Cobrança avulsa simples, sempre em cartão — cobra direto no cartão padrão já\n * salvo do cliente (sem fricção nenhuma). Se ele ainda não tiver um cartão salvo,\n * retorna `checkout_url` para você abrir (ex: nova aba) e o cliente cadastrar o\n * cartão e pagar.\n *\n * ```ts\n * const result = await client.charges.charge(customerId, 5000); // R$ 50,00\n * if (!result.charged_off_session) {\n * window.open(result.checkout_url!, \"_blank\");\n * }\n * ```\n */\n charge(customerId: string, amountCents: number, options?: Omit<QuickChargeInput, \"customer_id\" | \"amount\">): Promise<QuickChargeResult> {\n return this.http.post<QuickChargeResult>(\"/charges/quick\", {\n customer_id: customerId,\n amount: amountCents,\n ...options,\n });\n }\n\n get(id: string): Promise<Charge> {\n return this.http.get<Charge>(`/charges/${id}`);\n }\n\n getStatus(id: string): Promise<{ status: Charge[\"status\"] }> {\n return this.http.get(`/charges/${id}/status`);\n }\n\n cancel(id: string): Promise<Charge> {\n return this.http.patch<Charge>(`/charges/${id}/cancel`);\n }\n\n refund(id: string): Promise<Charge> {\n return this.http.post<Charge>(`/charges/${id}/refund`);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { CheckoutStatusResult } from \"../types.js\";\n\nexport interface WaitUntilPaidOptions {\n /** Intervalo entre tentativas, em ms. Default: 2000. */\n intervalMs?: number;\n /** Tempo máximo de espera antes de desistir, em ms. Default: 5 minutos. */\n timeoutMs?: number;\n}\n\nexport class CheckoutResource {\n constructor(private readonly http: HttpClient) {}\n\n /** Consulta o status atual de uma cobrança/checkout pelo `checkout_token` retornado\n * por `plans.checkout()` (ou qualquer outro fluxo de cobrança do SDK). Sincroniza com\n * o provedor de pagamento sob o capô quando ainda está PENDING. */\n getStatus(checkoutToken: string): Promise<CheckoutStatusResult> {\n return this.http.get<CheckoutStatusResult>(`/checkout/${checkoutToken}/status`);\n }\n\n /**\n * Faz polling de `getStatus` até o pagamento ser confirmado (ou falhar/expirar) — é\n * a forma recomendada de confirmar, depois de redirecionar o cliente para a\n * `checkout_url`, que a assinatura realmente foi paga antes de liberar acesso.\n *\n * Resolve quando o status deixa de ser PENDING/PROCESSING. Lança um erro se o tempo\n * limite (`timeoutMs`) for atingido antes disso.\n */\n async waitUntilPaid(checkoutToken: string, options: WaitUntilPaidOptions = {}): Promise<CheckoutStatusResult> {\n const intervalMs = options.intervalMs ?? 2000;\n const timeoutMs = options.timeoutMs ?? 5 * 60 * 1000;\n const deadline = Date.now() + timeoutMs;\n\n for (;;) {\n const result = await this.getStatus(checkoutToken);\n if (result.status !== \"PENDING\" && result.status !== \"PROCESSING\") {\n return result;\n }\n if (Date.now() >= deadline) {\n throw new Error(`Tempo limite excedido aguardando confirmação de pagamento (checkout_token=${checkoutToken}).`);\n }\n await new Promise((resolve) => setTimeout(resolve, intervalMs));\n }\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { Customer, CustomerInput } from \"../types.js\";\n\nexport class CustomersResource {\n constructor(private readonly http: HttpClient) {}\n\n list(): Promise<Customer[]> {\n return this.http.get<Customer[]>(\"/customers\");\n }\n\n create(input: CustomerInput): Promise<Customer> {\n return this.http.post<Customer>(\"/customers\", input);\n }\n\n get(id: string): Promise<Customer> {\n return this.http.get<Customer>(`/customers/${id}`);\n }\n\n update(id: string, input: Partial<CustomerInput>): Promise<Customer> {\n return this.http.patch<Customer>(`/customers/${id}`, input);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { BillingItem } from \"../types.js\";\n\nexport interface ItemInput {\n name: string;\n description?: string;\n amount: number;\n currency?: string;\n}\n\nexport class ItemsResource {\n constructor(private readonly http: HttpClient) {}\n\n list(): Promise<BillingItem[]> {\n return this.http.get<BillingItem[]>(\"/items\");\n }\n\n create(input: ItemInput): Promise<BillingItem> {\n return this.http.post<BillingItem>(\"/items\", input);\n }\n\n get(id: string): Promise<BillingItem> {\n return this.http.get<BillingItem>(`/items/${id}`);\n }\n\n update(id: string, input: Partial<ItemInput>): Promise<BillingItem> {\n return this.http.patch<BillingItem>(`/items/${id}`, input);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { CreateOrderInput, CreateOrderResult } from \"../types.js\";\n\nexport class OrdersResource {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Cria um pedido parcelado (parcelamento real via cobranças avulsas agendadas,\n * não assinatura). Retorna o `client_secret` da 1ª parcela para o front-end\n * confirmar via Stripe Elements — as parcelas seguintes são cobradas\n * automaticamente pelo backend no cartão salvo.\n */\n create(input: CreateOrderInput): Promise<CreateOrderResult> {\n return this.http.post<CreateOrderResult>(\"/orders\", input);\n }\n\n list(): Promise<unknown[]> {\n return this.http.get(\"/orders\");\n }\n\n get(id: string): Promise<unknown> {\n return this.http.get(`/orders/${id}`);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type {\n BillingPlanSummary,\n CheckoutForCustomerResult,\n CreateBillingPlanInput,\n GetPublicPlanPageResult,\n ListPublicPlansResult,\n PlanCheckoutInput,\n PlanCheckoutResult,\n PlanSubscriptionStatusResult,\n} from \"../types.js\";\n\nexport class PlansResource {\n constructor(private readonly http: HttpClient) {}\n\n list(): Promise<BillingPlanSummary[]> {\n return this.http.get<BillingPlanSummary[]>(\"/billing-plans\");\n }\n\n get(id: string): Promise<BillingPlanSummary> {\n return this.http.get<BillingPlanSummary>(`/billing-plans/${id}`);\n }\n\n create(input: CreateBillingPlanInput): Promise<BillingPlanSummary> {\n return this.http.post<BillingPlanSummary>(\"/billing-plans\", input);\n }\n\n update(id: string, input: Partial<CreateBillingPlanInput> & { active?: boolean }): Promise<BillingPlanSummary> {\n return this.http.patch<BillingPlanSummary>(`/billing-plans/${id}`, input);\n }\n\n /** Não há hard-delete de planos (assinaturas existentes ainda referenciam) — para\n * remover um plano do catálogo público, arquive-o. */\n archive(id: string): Promise<BillingPlanSummary> {\n return this.http.patch<BillingPlanSummary>(`/billing-plans/${id}`, { active: false });\n }\n\n /** Vincula um plano avulso a uma página de planos existente (mesma org). */\n attachToPage(planId: string, pageId: string): Promise<BillingPlanSummary> {\n return this.http.patch<BillingPlanSummary>(`/billing-plans/${planId}`, { plan_page_id: pageId });\n }\n\n /** Desvincula um plano da sua página, tornando-o avulso (sem página pública). */\n detachFromPage(planId: string): Promise<BillingPlanSummary> {\n return this.http.patch<BillingPlanSummary>(`/billing-plans/${planId}`, { plan_page_id: null });\n }\n\n /**\n * Fluxo simplificado de assinatura para um `Customer` já cadastrado na sua org\n * (autenticado, sem formulário de nome/e-mail): cria a assinatura + cobrança inicial e\n * retorna a URL de checkout hospedada.\n *\n * ```ts\n * const { checkout_url } = await client.plans.checkoutPlan(planId, customerId);\n * // redirecione o cliente para checkout_url; ele paga e volta para sua URL de retorno\n *\n * // depois que o cliente volta:\n * const { active, item } = await client.plans.confirmPlanSubscription(planId, customerId);\n * if (active) {\n * // ativa o plano real no seu sistema\n * }\n * ```\n */\n checkoutPlan(planId: string, customerId: string): Promise<CheckoutForCustomerResult> {\n return this.http.post<CheckoutForCustomerResult>(`/billing-plans/${planId}/checkout-for-customer`, { customer_id: customerId });\n }\n\n /** Verifica se um `Customer` tem uma assinatura ativa deste plano (a mais recente),\n * contraparte de `checkoutPlan` no fluxo simplificado autenticado. */\n confirmPlanSubscription(planId: string, customerId: string): Promise<PlanSubscriptionStatusResult> {\n return this.http.get<PlanSubscriptionStatusResult>(`/billing-plans/${planId}/subscription-status?customer_id=${encodeURIComponent(customerId)}`);\n }\n\n // ─── Rotas públicas (sem auth — usadas para montar sua própria página de preços) ──\n\n /** Lista os planos ativos de uma org pelo slug público — página fixa legada, sem\n * suporte a múltiplas páginas. Prefira `getPublicPage` para orgs com várias páginas. */\n listPublic(orgSlug: string): Promise<ListPublicPlansResult> {\n return this.http.get<ListPublicPlansResult>(`/public/orgs/${orgSlug}/billing-plans`);\n }\n\n /** Busca uma página de planos pública específica pelo slug da org + slug da página. */\n getPublicPage(orgSlug: string, pageSlug: string): Promise<GetPublicPlanPageResult> {\n return this.http.get<GetPublicPlanPageResult>(`/public/orgs/${orgSlug}/plan-pages/${pageSlug}`);\n }\n\n /**\n * Inicia a assinatura de um plano para um cliente final: cria (ou reaproveita) o\n * `Customer` pelo e-mail, cria a `Subscription` e retorna uma URL de checkout hospedada\n * pela Geekapps para o cliente confirmar o pagamento.\n *\n * Fluxo típico:\n * ```ts\n * const { checkout_url, checkout_token } = await client.plans.checkout(planId, {\n * customer: { name, email },\n * });\n * // redirecione o cliente (ou abra checkout_url em uma WebView/nova aba)\n * window.location.href = checkout_url;\n *\n * // depois do retorno, confirme se realmente foi pago:\n * const { status } = await client.checkout.waitUntilPaid(checkout_token);\n * if (status === \"PAID\") { /* liberar acesso *\\/ }\n * ```\n *\n * Não requer autenticação — pode ser chamado a partir do backend do dev sem token de\n * service account, ou do próprio SDK server-side usando qualquer token válido.\n */\n checkout(planId: string, input: PlanCheckoutInput): Promise<PlanCheckoutResult> {\n return this.http.post<PlanCheckoutResult>(`/public/billing-plans/${planId}/checkout`, input);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { Subscription, SubscriptionStatusResult } from \"../types.js\";\n\nexport class SubscriptionsResource {\n constructor(private readonly http: HttpClient) {}\n\n /** Requer autenticação (service account) — lista todas as assinaturas da sua org. */\n list(): Promise<Subscription[]> {\n return this.http.get<Subscription[]>(\"/billing-subscriptions\");\n }\n\n /** Requer autenticação (service account). */\n get(id: string): Promise<Subscription> {\n return this.http.get<Subscription>(`/billing-subscriptions/${id}`);\n }\n\n /** Requer autenticação (service account). */\n cancel(id: string): Promise<Subscription> {\n return this.http.patch<Subscription>(`/billing-subscriptions/${id}/cancel`);\n }\n\n /**\n * Verifica se uma assinatura está ativa e qual item ela cobre, usando o\n * `management_token` retornado por `plans.checkout()` — rota pública, sem\n * autenticação, segura para chamar tanto do seu backend quanto (via fetch direto,\n * sem o SDK) do client-side do seu app.\n *\n * ```ts\n * const status = await client.subscriptions.checkByToken(managementToken);\n * if (status.subscription.active) {\n * console.log(\"cobrando\", status.item.name);\n * }\n * ```\n */\n checkByToken(managementToken: string): Promise<SubscriptionStatusResult> {\n return this.http.get<SubscriptionStatusResult>(`/public/plan-management/${managementToken}`);\n }\n}\n","import { HttpClient, type HttpClientOptions } from \"./http.js\";\nimport { ChargesResource } from \"./resources/charges.js\";\nimport { CheckoutResource } from \"./resources/checkout.js\";\nimport { CustomersResource } from \"./resources/customers.js\";\nimport { ItemsResource } from \"./resources/items.js\";\nimport { OrdersResource } from \"./resources/orders.js\";\nimport { PlansResource } from \"./resources/plans.js\";\nimport { SubscriptionsResource } from \"./resources/subscriptions.js\";\n\nexport interface BillingClientOptions\n extends Omit<HttpClientOptions, \"baseUrl\"> {\n baseUrl?: string;\n}\n\nexport class BillingClient {\n private readonly http: HttpClient;\n\n readonly charges: ChargesResource;\n readonly checkout: CheckoutResource;\n readonly customers: CustomersResource;\n readonly items: ItemsResource;\n readonly orders: OrdersResource;\n readonly plans: PlansResource;\n readonly subscriptions: SubscriptionsResource;\n\n constructor(options: HttpClientOptions) {\n this.http = new HttpClient(options);\n\n this.charges = new ChargesResource(this.http);\n this.checkout = new CheckoutResource(this.http);\n this.customers = new CustomersResource(this.http);\n this.items = new ItemsResource(this.http);\n this.orders = new OrdersResource(this.http);\n this.plans = new PlansResource(this.http);\n this.subscriptions = new SubscriptionsResource(this.http);\n }\n}\n","import type { FastifyInstance, FastifyPluginAsync } from \"fastify\";\nimport fp from \"fastify-plugin\";\nimport { BillingClient } from \"./client.js\";\nimport { ServiceAccountTokenProvider, type ServiceAccountOptions } from \"./service-account.js\";\n\nexport interface BillingPluginOptions {\n /** Geekapps Billing API base URL */\n baseUrl: string;\n /** Service account credentials — required */\n serviceAccount: ServiceAccountOptions;\n /** Ambiente de billing (dev/prod). Default: \"prod\". */\n mode?: string;\n}\n\ndeclare module \"fastify\" {\n interface FastifyInstance {\n billingClient: BillingClient;\n }\n}\n\nconst billingPlugin: FastifyPluginAsync<BillingPluginOptions> = async (\n fastify: FastifyInstance,\n options: BillingPluginOptions,\n) => {\n const tokenProvider = new ServiceAccountTokenProvider(options.serviceAccount);\n\n const client = new BillingClient({\n baseUrl: options.baseUrl,\n token: () => tokenProvider.getToken(),\n organizationId: () => tokenProvider.getOrganizationId() as Promise<string>,\n mode: options.mode,\n });\n\n fastify.decorate(\"billingClient\", client);\n};\n\nexport default fp(billingPlugin, {\n fastify: \">=4.0.0\",\n name: \"@geekapps/billing-fastify\",\n});\n","import type { TokenResolver } from \"./http.js\";\n\nexport interface ServiceAccountOptions {\n /** Geekapps Auth issuer base URL (e.g. https://accounts-api.geekapps.com.br) */\n issuerUrl: string;\n clientId: string;\n clientSecret: string;\n /** Seconds before expiry to proactively refresh. Defaults to 30. */\n refreshBeforeExpirySeconds?: number;\n}\n\ninterface CachedToken {\n value: string;\n expiresAt: number; // ms epoch\n organizationId: string | undefined;\n}\n\nfunction decodeJwtPayload(token: string): Record<string, unknown> {\n try {\n const [, payload] = token.split(\".\");\n if (!payload) return {};\n const json = Buffer.from(payload, \"base64url\").toString(\"utf-8\");\n return JSON.parse(json) as Record<string, unknown>;\n } catch {\n return {};\n }\n}\n\n/**\n * Fetches a short-lived token from the Geekapps Auth service using\n * client_credentials grant and caches it until near expiry.\n *\n * The organizationId claim is extracted automatically from the JWT payload.\n */\nexport class ServiceAccountTokenProvider {\n private readonly issuerUrl: string;\n private readonly clientId: string;\n private readonly clientSecret: string;\n private readonly refreshBeforeMs: number;\n private cached: CachedToken | null = null;\n private inflight: Promise<CachedToken> | null = null;\n\n constructor(options: ServiceAccountOptions) {\n this.issuerUrl = options.issuerUrl.replace(/\\/$/, \"\");\n this.clientId = options.clientId;\n this.clientSecret = options.clientSecret;\n this.refreshBeforeMs = (options.refreshBeforeExpirySeconds ?? 30) * 1000;\n }\n\n private async ensureFresh(): Promise<CachedToken> {\n const now = Date.now();\n\n if (this.cached && this.cached.expiresAt - now > this.refreshBeforeMs) {\n return this.cached;\n }\n\n if (this.inflight) return this.inflight;\n\n this.inflight = this.fetchToken().finally(() => {\n this.inflight = null;\n });\n\n return this.inflight;\n }\n\n /** Returns a valid access token. */\n getToken(): Promise<string> {\n return this.ensureFresh().then((c) => c.value);\n }\n\n /** Returns the organizationId embedded in the service account JWT. */\n getOrganizationId(): Promise<string | undefined> {\n return this.ensureFresh().then((c) => c.organizationId);\n }\n\n private async fetchToken(): Promise<CachedToken> {\n const credentials = Buffer.from(`${this.clientId}:${this.clientSecret}`).toString(\"base64\");\n\n const res = await fetch(`${this.issuerUrl}/auth/token`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Basic ${credentials}`,\n },\n body: JSON.stringify({ grant_type: \"service_account\" }),\n });\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({})) as { error?: string };\n throw new Error(\n `ServiceAccount token fetch failed (${res.status}): ${err.error ?? \"unknown error\"}`,\n );\n }\n\n const data = await res.json() as { access_token: string; expires_in?: number };\n\n const claims = decodeJwtPayload(data.access_token);\n const organizationId =\n typeof claims.organizationId === \"string\" ? claims.organizationId :\n typeof claims.organization_id === \"string\" ? claims.organization_id :\n undefined;\n\n const expiresInMs = (data.expires_in ?? 420) * 1000;\n this.cached = {\n value: data.access_token,\n expiresAt: Date.now() + expiresInMs,\n organizationId,\n };\n\n return this.cached;\n }\n\n /** Returns this provider as a TokenResolver to pass directly to BillingClient. */\n asTokenResolver(): TokenResolver {\n return () => this.getToken();\n }\n}\n\n/** Convenience factory. Returns a TokenResolver ready for use in BillingClient. */\nexport function createServiceAccountToken(\n options: ServiceAccountOptions,\n): TokenResolver {\n return new ServiceAccountTokenProvider(options).asTokenResolver();\n}\n"],"mappings":"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","names":["fp"]}
|