@wodira/browser 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +140 -0
- package/dist/index.cjs +174 -0
- package/dist/index.d.ts +118 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +133 -0
- package/dist/types.d.ts +263 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/ui/components.d.ts +376 -0
- package/dist/ui/components.d.ts.map +1 -0
- package/dist/ui/events.d.ts +4 -0
- package/dist/ui/events.d.ts.map +1 -0
- package/dist/ui/i18n.d.ts +3 -0
- package/dist/ui/i18n.d.ts.map +1 -0
- package/dist/ui/index.d.ts +28 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +3309 -0
- package/dist/ui/styles.d.ts +2 -0
- package/dist/ui/styles.d.ts.map +1 -0
- package/dist/ui/validators.d.ts +21 -0
- package/dist/ui/validators.d.ts.map +1 -0
- package/package.json +57 -0
package/README.md
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# @wodira/browser
|
|
2
|
+
|
|
3
|
+
SDK frontend para publishable keys de WODira (`wpk_live_...`). Permite leer eventos/tarifas y crear sesiones de Stripe Checkout para inscripciones externas sin exponer una secret key.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
bun add @wodira/browser
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { createWodiraBrowserClient } from '@wodira/browser';
|
|
11
|
+
|
|
12
|
+
const wodira = createWodiraBrowserClient({ publishableKey: 'wpk_live_...' });
|
|
13
|
+
|
|
14
|
+
const session = await wodira.createRegistrationCheckoutSession({
|
|
15
|
+
eventId: 'event_...',
|
|
16
|
+
categoryId: 'cat_...',
|
|
17
|
+
purchaserEmail: 'buyer@example.com',
|
|
18
|
+
purchaserName: 'Buyer Name',
|
|
19
|
+
teamName: 'Team Name',
|
|
20
|
+
termsAccepted: true,
|
|
21
|
+
waiversAccepted: { waiver_123: true }, // si el evento tiene waivers requeridos
|
|
22
|
+
idempotencyKey: crypto.randomUUID(),
|
|
23
|
+
successUrl: 'https://organizador.com/gracias',
|
|
24
|
+
cancelUrl: 'https://organizador.com/cancelado',
|
|
25
|
+
athletes: [
|
|
26
|
+
{
|
|
27
|
+
fullname: 'Ada Lovelace',
|
|
28
|
+
idNumber: '12345678A',
|
|
29
|
+
email: 'ada@example.com',
|
|
30
|
+
phone: '+34600000000',
|
|
31
|
+
gender: 'FEMALE',
|
|
32
|
+
birthDate: '1990-01-01',
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
if (session.sessionUrl) window.location.href = session.sessionUrl;
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Las URLs de éxito/cancelación deben pertenecer a un origen permitido en la publishable key.
|
|
41
|
+
|
|
42
|
+
## Web Components: `@wodira/browser/ui`
|
|
43
|
+
|
|
44
|
+
`@wodira/browser/ui` incluye Web Components basados en Lit para incrustar el embudo de inscripción en webs de organizadores. Los componentes usan publishable keys, CSS variables y `::part()` para personalización visual.
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import { defineWodiraElements } from '@wodira/browser/ui';
|
|
48
|
+
|
|
49
|
+
defineWodiraElements();
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
```html
|
|
53
|
+
<wodira-checkout-flow
|
|
54
|
+
publishable-key="wpk_live_..."
|
|
55
|
+
event-id="event_..."
|
|
56
|
+
success-url="https://organizador.com/gracias"
|
|
57
|
+
cancel-url="https://organizador.com/cancelado"
|
|
58
|
+
></wodira-checkout-flow>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
También se puede montar por JS:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import { createWodiraCheckoutFlow } from '@wodira/browser/ui';
|
|
65
|
+
|
|
66
|
+
createWodiraCheckoutFlow(document.querySelector('#checkout')!, {
|
|
67
|
+
publishableKey: 'wpk_live_...',
|
|
68
|
+
eventId: 'event_...',
|
|
69
|
+
successUrl: 'https://organizador.com/gracias',
|
|
70
|
+
cancelUrl: 'https://organizador.com/cancelado',
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Componentes disponibles:
|
|
75
|
+
|
|
76
|
+
- `<wodira-event-list>`: lista eventos publicados.
|
|
77
|
+
- `<wodira-event-card>`: tarjeta de evento reutilizable.
|
|
78
|
+
- `<wodira-pricing-cards>`: categorías, precios, cupos y selección.
|
|
79
|
+
- `<wodira-registration-form>`: formulario de inscripción y creación de Stripe Checkout Session.
|
|
80
|
+
- `<wodira-checkout-flow>`: embudo completo evento → categoría → inscripción → Stripe Checkout.
|
|
81
|
+
|
|
82
|
+
Eventos DOM:
|
|
83
|
+
|
|
84
|
+
- `wodira:event-select`
|
|
85
|
+
- `wodira:category-select`
|
|
86
|
+
- `wodira:checkout-start`
|
|
87
|
+
- `wodira:checkout-created`
|
|
88
|
+
- `wodira:redirect`
|
|
89
|
+
- `wodira:error`
|
|
90
|
+
|
|
91
|
+
Personalización:
|
|
92
|
+
|
|
93
|
+
```css
|
|
94
|
+
wodira-checkout-flow {
|
|
95
|
+
--wodira-color-primary: #111827;
|
|
96
|
+
--wodira-color-accent: #f97316;
|
|
97
|
+
--wodira-radius: 18px;
|
|
98
|
+
--wodira-font-family: Inter, system-ui, sans-serif;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
wodira-checkout-flow::part(button) {
|
|
102
|
+
text-transform: uppercase;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
wodira-checkout-flow::part(card) {
|
|
106
|
+
border-width: 2px;
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Atributos principales: `publishable-key`, `base-url`, `event-id`, `success-url`, `cancel-url`, `locale` y `auto-redirect`.
|
|
111
|
+
|
|
112
|
+
### Production notes
|
|
113
|
+
|
|
114
|
+
- Los componentes hacen validación cliente antes de crear Checkout Session: comprador, atletas, campos obligatorios, términos y waivers requeridos.
|
|
115
|
+
- Si el evento expone suplementos activos, el formulario renderiza extras y selecciona automáticamente los obligatorios.
|
|
116
|
+
- El resumen de precio se recalcula con `getRegistrationSummary` cuando hay `purchaserEmail` válido, categoría y extras/promocode.
|
|
117
|
+
- `locale="en-US"` cambia los textos base a inglés; cualquier otro locale usa español por defecto y se usa para fecha/moneda.
|
|
118
|
+
- `auto-redirect` está activo por defecto; si se desactiva, escucha `wodira:checkout-created` o `wodira:redirect` para gestionar la navegación.
|
|
119
|
+
|
|
120
|
+
### CSS variables soportadas
|
|
121
|
+
|
|
122
|
+
| Variable | Uso |
|
|
123
|
+
| ---------------------------------------- | -------------------- |
|
|
124
|
+
| `--wodira-color-primary` | Botones principales |
|
|
125
|
+
| `--wodira-color-primary-contrast` | Texto sobre primario |
|
|
126
|
+
| `--wodira-color-accent` | Precios y foco |
|
|
127
|
+
| `--wodira-color-surface` | Tarjetas e inputs |
|
|
128
|
+
| `--wodira-color-muted` | Fondos secundarios |
|
|
129
|
+
| `--wodira-color-border` | Bordes |
|
|
130
|
+
| `--wodira-color-text` | Texto principal |
|
|
131
|
+
| `--wodira-color-text-muted` | Texto secundario |
|
|
132
|
+
| `--wodira-color-danger` | Errores |
|
|
133
|
+
| `--wodira-radius` / `--wodira-radius-sm` | Radios |
|
|
134
|
+
| `--wodira-space` | Espaciado base |
|
|
135
|
+
| `--wodira-font-family` | Tipografía |
|
|
136
|
+
| `--wodira-shadow` | Sombra de tarjetas |
|
|
137
|
+
|
|
138
|
+
### Parts principales
|
|
139
|
+
|
|
140
|
+
`card`, `event-card`, `pricing-card`, `registration-form`, `summary`, `button`, `input`, `select`, `textarea`, `checkbox`, `label`, `title`, `price`, `meta`, `hint`, `error`, `field-error`, `loader`, `empty`, `waiver`, `supplement`.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
function __accessProp(key) {
|
|
6
|
+
return this[key];
|
|
7
|
+
}
|
|
8
|
+
var __toCommonJS = (from) => {
|
|
9
|
+
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
10
|
+
if (entry)
|
|
11
|
+
return entry;
|
|
12
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (var key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(entry, key))
|
|
16
|
+
__defProp(entry, key, {
|
|
17
|
+
get: __accessProp.bind(from, key),
|
|
18
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
__moduleCache.set(from, entry);
|
|
22
|
+
return entry;
|
|
23
|
+
};
|
|
24
|
+
var __moduleCache;
|
|
25
|
+
var __returnValue = (v) => v;
|
|
26
|
+
function __exportSetter(name, newValue) {
|
|
27
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
28
|
+
}
|
|
29
|
+
var __export = (target, all) => {
|
|
30
|
+
for (var name in all)
|
|
31
|
+
__defProp(target, name, {
|
|
32
|
+
get: all[name],
|
|
33
|
+
enumerable: true,
|
|
34
|
+
configurable: true,
|
|
35
|
+
set: __exportSetter.bind(all, name)
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// src/index.ts
|
|
40
|
+
var exports_src = {};
|
|
41
|
+
__export(exports_src, {
|
|
42
|
+
createWodiraBrowserClient: () => createWodiraBrowserClient,
|
|
43
|
+
WodiraBrowserClient: () => WodiraBrowserClient,
|
|
44
|
+
WodiraBrowserApiError: () => WodiraBrowserApiError
|
|
45
|
+
});
|
|
46
|
+
module.exports = __toCommonJS(exports_src);
|
|
47
|
+
|
|
48
|
+
class WodiraBrowserApiError extends Error {
|
|
49
|
+
status;
|
|
50
|
+
statusText;
|
|
51
|
+
payload;
|
|
52
|
+
constructor(params) {
|
|
53
|
+
super(params.message);
|
|
54
|
+
this.name = "WodiraBrowserApiError";
|
|
55
|
+
this.status = params.status;
|
|
56
|
+
this.statusText = params.statusText;
|
|
57
|
+
this.payload = params.payload;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
var DEFAULT_BASE_URL = "https://api.wodira.app";
|
|
61
|
+
var BROWSER_API_PREFIX = "/external/v1/browser";
|
|
62
|
+
|
|
63
|
+
class WodiraBrowserClient {
|
|
64
|
+
publishableKey;
|
|
65
|
+
baseUrl;
|
|
66
|
+
fetcher;
|
|
67
|
+
headers;
|
|
68
|
+
constructor(options) {
|
|
69
|
+
if (!options.publishableKey?.trim()) {
|
|
70
|
+
throw new Error("WodiraBrowserClient requires a publishableKey.");
|
|
71
|
+
}
|
|
72
|
+
if (!options.publishableKey.startsWith("wpk_live_")) {
|
|
73
|
+
throw new Error("Wodira browser publishable keys must start with wpk_live_.");
|
|
74
|
+
}
|
|
75
|
+
this.publishableKey = options.publishableKey.trim();
|
|
76
|
+
this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
77
|
+
this.fetcher = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
78
|
+
this.headers = options.headers;
|
|
79
|
+
}
|
|
80
|
+
searchEvents(input = {}, signal) {
|
|
81
|
+
return this.request("/events/search", {
|
|
82
|
+
method: "POST",
|
|
83
|
+
body: input,
|
|
84
|
+
signal
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
getEvent(eventId, signal) {
|
|
88
|
+
return this.request(`/events/${encodeURIComponent(eventId)}`, { signal });
|
|
89
|
+
}
|
|
90
|
+
getPricingCards(eventId, signal) {
|
|
91
|
+
return this.request(`/events/${encodeURIComponent(eventId)}/pricing-cards`, { signal });
|
|
92
|
+
}
|
|
93
|
+
getRegistrationSummary(input, signal) {
|
|
94
|
+
return this.request("/checkout/registration/summary", {
|
|
95
|
+
method: "POST",
|
|
96
|
+
body: input,
|
|
97
|
+
signal
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
createRegistrationCheckoutSession(input, signal) {
|
|
101
|
+
return this.request("/checkout/registration/session", {
|
|
102
|
+
method: "POST",
|
|
103
|
+
body: serializeRegistrationInput(input),
|
|
104
|
+
signal
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
async request(path, options = {}) {
|
|
108
|
+
const headers = new Headers(this.headers);
|
|
109
|
+
headers.set("accept", "application/json");
|
|
110
|
+
headers.set("x-publishable-key", this.publishableKey);
|
|
111
|
+
const init = { method: options.method ?? "GET", headers };
|
|
112
|
+
if (options.signal)
|
|
113
|
+
init.signal = options.signal;
|
|
114
|
+
if (options.body !== undefined) {
|
|
115
|
+
headers.set("content-type", "application/json");
|
|
116
|
+
init.body = JSON.stringify(options.body);
|
|
117
|
+
}
|
|
118
|
+
const response = await this.fetcher(`${this.baseUrl}${BROWSER_API_PREFIX}${path}`, init);
|
|
119
|
+
if (!response.ok) {
|
|
120
|
+
const payload = await readResponsePayload(response);
|
|
121
|
+
throw new WodiraBrowserApiError({
|
|
122
|
+
status: response.status,
|
|
123
|
+
statusText: response.statusText,
|
|
124
|
+
message: extractErrorMessage(payload, response),
|
|
125
|
+
payload
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
const text = await response.text();
|
|
129
|
+
return text ? JSON.parse(text) : undefined;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function createWodiraBrowserClient(options) {
|
|
133
|
+
return new WodiraBrowserClient(options);
|
|
134
|
+
}
|
|
135
|
+
async function readResponsePayload(response) {
|
|
136
|
+
const text = await response.text();
|
|
137
|
+
if (!text)
|
|
138
|
+
return null;
|
|
139
|
+
try {
|
|
140
|
+
return JSON.parse(text);
|
|
141
|
+
} catch {
|
|
142
|
+
return text;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function extractErrorMessage(payload, response) {
|
|
146
|
+
if (typeof payload === "string")
|
|
147
|
+
return payload;
|
|
148
|
+
const message = payload?.message;
|
|
149
|
+
if (typeof message === "string")
|
|
150
|
+
return message;
|
|
151
|
+
if (Array.isArray(message))
|
|
152
|
+
return message.filter((item) => typeof item === "string").join(", ");
|
|
153
|
+
if (typeof payload?.error === "string")
|
|
154
|
+
return payload.error;
|
|
155
|
+
return `WODira browser API request failed with ${response.status} ${response.statusText}`;
|
|
156
|
+
}
|
|
157
|
+
function serializeRegistrationInput(input) {
|
|
158
|
+
return {
|
|
159
|
+
...input,
|
|
160
|
+
athletes: input.athletes.map(serializeAthleteInput),
|
|
161
|
+
...input.guestRegistrations ? {
|
|
162
|
+
guestRegistrations: input.guestRegistrations.map((guest) => ({
|
|
163
|
+
...guest,
|
|
164
|
+
athletes: guest.athletes.map(serializeAthleteInput)
|
|
165
|
+
}))
|
|
166
|
+
} : {}
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
function serializeAthleteInput(athlete) {
|
|
170
|
+
return {
|
|
171
|
+
...athlete,
|
|
172
|
+
birthDate: athlete.birthDate instanceof Date ? athlete.birthDate.toISOString().slice(0, 10) : athlete.birthDate
|
|
173
|
+
};
|
|
174
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import type { WodiraAthleteInput, WodiraCustomFieldInput, WodiraEvent, WodiraPaginatedResponse, WodiraPricingCardsResponse, WodiraSearchEventsInput } from './types';
|
|
2
|
+
export type * from './types';
|
|
3
|
+
export interface WodiraBrowserApiErrorPayload {
|
|
4
|
+
message?: unknown;
|
|
5
|
+
error?: unknown;
|
|
6
|
+
statusCode?: number;
|
|
7
|
+
[key: string]: unknown;
|
|
8
|
+
}
|
|
9
|
+
export declare class WodiraBrowserApiError extends Error {
|
|
10
|
+
readonly status: number;
|
|
11
|
+
readonly statusText: string;
|
|
12
|
+
readonly payload: WodiraBrowserApiErrorPayload | string | null;
|
|
13
|
+
constructor(params: {
|
|
14
|
+
status: number;
|
|
15
|
+
statusText: string;
|
|
16
|
+
message: string;
|
|
17
|
+
payload: WodiraBrowserApiErrorPayload | string | null;
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
export type WodiraBrowserFetch = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
|
21
|
+
export interface WodiraBrowserClientOptions {
|
|
22
|
+
publishableKey: string;
|
|
23
|
+
baseUrl?: string;
|
|
24
|
+
fetch?: WodiraBrowserFetch;
|
|
25
|
+
headers?: HeadersInit;
|
|
26
|
+
}
|
|
27
|
+
export interface WodiraGuestRegistrationSummaryInput {
|
|
28
|
+
categoryId: string;
|
|
29
|
+
selectedSupplementIds?: string[];
|
|
30
|
+
}
|
|
31
|
+
export interface WodiraRegistrationSummaryInput {
|
|
32
|
+
categoryId: string;
|
|
33
|
+
purchaserEmail: string;
|
|
34
|
+
promocode?: string;
|
|
35
|
+
selectedSupplementIds?: string[];
|
|
36
|
+
guestRegistrations?: WodiraGuestRegistrationSummaryInput[];
|
|
37
|
+
}
|
|
38
|
+
export interface WodiraBrowserAthleteInput extends WodiraAthleteInput {
|
|
39
|
+
phone: string;
|
|
40
|
+
idNumber: string;
|
|
41
|
+
}
|
|
42
|
+
export interface WodiraGuestRegistrationInput {
|
|
43
|
+
guestEmail: string;
|
|
44
|
+
guestName: string;
|
|
45
|
+
categoryId: string;
|
|
46
|
+
teamName: string;
|
|
47
|
+
club?: string;
|
|
48
|
+
athletes: WodiraBrowserAthleteInput[];
|
|
49
|
+
customFields?: WodiraCustomFieldInput[];
|
|
50
|
+
waiversAccepted?: Record<string, boolean>;
|
|
51
|
+
selectedSupplementIds?: string[];
|
|
52
|
+
}
|
|
53
|
+
export interface WodiraRegistrationCheckoutSessionInput extends WodiraRegistrationSummaryInput {
|
|
54
|
+
eventId: string;
|
|
55
|
+
teamName: string;
|
|
56
|
+
club?: string;
|
|
57
|
+
purchaserName: string;
|
|
58
|
+
athletes: WodiraBrowserAthleteInput[];
|
|
59
|
+
guestRegistrations?: WodiraGuestRegistrationInput[];
|
|
60
|
+
customFields?: WodiraCustomFieldInput[];
|
|
61
|
+
termsAccepted: boolean;
|
|
62
|
+
waiversAccepted?: Record<string, boolean>;
|
|
63
|
+
idempotencyKey?: string;
|
|
64
|
+
successUrl: string;
|
|
65
|
+
cancelUrl: string;
|
|
66
|
+
}
|
|
67
|
+
export interface WodiraAppliedCoupon {
|
|
68
|
+
code: string;
|
|
69
|
+
discount: number;
|
|
70
|
+
discountPercentage?: number;
|
|
71
|
+
description: string;
|
|
72
|
+
isAutomatic: boolean;
|
|
73
|
+
}
|
|
74
|
+
export interface WodiraRegistrationSummary {
|
|
75
|
+
categoryId: string;
|
|
76
|
+
categoryName: string;
|
|
77
|
+
categoryPrice: number;
|
|
78
|
+
subtotal: number;
|
|
79
|
+
couponDiscount?: number;
|
|
80
|
+
subtotalAfterDiscount: number;
|
|
81
|
+
productsTotal: number;
|
|
82
|
+
supplementsTotal: number;
|
|
83
|
+
applicationFee: number;
|
|
84
|
+
applicationFeePercentage: number;
|
|
85
|
+
processingFee: number;
|
|
86
|
+
total: number;
|
|
87
|
+
organizerReceives: number;
|
|
88
|
+
currency: string;
|
|
89
|
+
appliedCoupons: WodiraAppliedCoupon[];
|
|
90
|
+
guestRegistrations?: Array<{
|
|
91
|
+
categoryId: string;
|
|
92
|
+
categoryName: string;
|
|
93
|
+
categoryPrice: number;
|
|
94
|
+
supplementsTotal: number;
|
|
95
|
+
subtotal: number;
|
|
96
|
+
}>;
|
|
97
|
+
}
|
|
98
|
+
export interface WodiraRegistrationCheckoutSession {
|
|
99
|
+
sessionId: string | null;
|
|
100
|
+
sessionUrl: string | null;
|
|
101
|
+
orderId: string;
|
|
102
|
+
completed: boolean;
|
|
103
|
+
}
|
|
104
|
+
export declare class WodiraBrowserClient {
|
|
105
|
+
private readonly publishableKey;
|
|
106
|
+
private readonly baseUrl;
|
|
107
|
+
private readonly fetcher;
|
|
108
|
+
private readonly headers;
|
|
109
|
+
constructor(options: WodiraBrowserClientOptions);
|
|
110
|
+
searchEvents(input?: Omit<WodiraSearchEventsInput, 'status'>, signal?: AbortSignal): Promise<WodiraPaginatedResponse<WodiraEvent>>;
|
|
111
|
+
getEvent(eventId: string, signal?: AbortSignal): Promise<WodiraEvent>;
|
|
112
|
+
getPricingCards(eventId: string, signal?: AbortSignal): Promise<WodiraPricingCardsResponse>;
|
|
113
|
+
getRegistrationSummary(input: WodiraRegistrationSummaryInput, signal?: AbortSignal): Promise<WodiraRegistrationSummary>;
|
|
114
|
+
createRegistrationCheckoutSession(input: WodiraRegistrationCheckoutSessionInput, signal?: AbortSignal): Promise<WodiraRegistrationCheckoutSession>;
|
|
115
|
+
private request;
|
|
116
|
+
}
|
|
117
|
+
export declare function createWodiraBrowserClient(options: WodiraBrowserClientOptions): WodiraBrowserClient;
|
|
118
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
class WodiraBrowserApiError extends Error {
|
|
3
|
+
status;
|
|
4
|
+
statusText;
|
|
5
|
+
payload;
|
|
6
|
+
constructor(params) {
|
|
7
|
+
super(params.message);
|
|
8
|
+
this.name = "WodiraBrowserApiError";
|
|
9
|
+
this.status = params.status;
|
|
10
|
+
this.statusText = params.statusText;
|
|
11
|
+
this.payload = params.payload;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
var DEFAULT_BASE_URL = "https://api.wodira.app";
|
|
15
|
+
var BROWSER_API_PREFIX = "/external/v1/browser";
|
|
16
|
+
|
|
17
|
+
class WodiraBrowserClient {
|
|
18
|
+
publishableKey;
|
|
19
|
+
baseUrl;
|
|
20
|
+
fetcher;
|
|
21
|
+
headers;
|
|
22
|
+
constructor(options) {
|
|
23
|
+
if (!options.publishableKey?.trim()) {
|
|
24
|
+
throw new Error("WodiraBrowserClient requires a publishableKey.");
|
|
25
|
+
}
|
|
26
|
+
if (!options.publishableKey.startsWith("wpk_live_")) {
|
|
27
|
+
throw new Error("Wodira browser publishable keys must start with wpk_live_.");
|
|
28
|
+
}
|
|
29
|
+
this.publishableKey = options.publishableKey.trim();
|
|
30
|
+
this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
31
|
+
this.fetcher = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
32
|
+
this.headers = options.headers;
|
|
33
|
+
}
|
|
34
|
+
searchEvents(input = {}, signal) {
|
|
35
|
+
return this.request("/events/search", {
|
|
36
|
+
method: "POST",
|
|
37
|
+
body: input,
|
|
38
|
+
signal
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
getEvent(eventId, signal) {
|
|
42
|
+
return this.request(`/events/${encodeURIComponent(eventId)}`, { signal });
|
|
43
|
+
}
|
|
44
|
+
getPricingCards(eventId, signal) {
|
|
45
|
+
return this.request(`/events/${encodeURIComponent(eventId)}/pricing-cards`, { signal });
|
|
46
|
+
}
|
|
47
|
+
getRegistrationSummary(input, signal) {
|
|
48
|
+
return this.request("/checkout/registration/summary", {
|
|
49
|
+
method: "POST",
|
|
50
|
+
body: input,
|
|
51
|
+
signal
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
createRegistrationCheckoutSession(input, signal) {
|
|
55
|
+
return this.request("/checkout/registration/session", {
|
|
56
|
+
method: "POST",
|
|
57
|
+
body: serializeRegistrationInput(input),
|
|
58
|
+
signal
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
async request(path, options = {}) {
|
|
62
|
+
const headers = new Headers(this.headers);
|
|
63
|
+
headers.set("accept", "application/json");
|
|
64
|
+
headers.set("x-publishable-key", this.publishableKey);
|
|
65
|
+
const init = { method: options.method ?? "GET", headers };
|
|
66
|
+
if (options.signal)
|
|
67
|
+
init.signal = options.signal;
|
|
68
|
+
if (options.body !== undefined) {
|
|
69
|
+
headers.set("content-type", "application/json");
|
|
70
|
+
init.body = JSON.stringify(options.body);
|
|
71
|
+
}
|
|
72
|
+
const response = await this.fetcher(`${this.baseUrl}${BROWSER_API_PREFIX}${path}`, init);
|
|
73
|
+
if (!response.ok) {
|
|
74
|
+
const payload = await readResponsePayload(response);
|
|
75
|
+
throw new WodiraBrowserApiError({
|
|
76
|
+
status: response.status,
|
|
77
|
+
statusText: response.statusText,
|
|
78
|
+
message: extractErrorMessage(payload, response),
|
|
79
|
+
payload
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
const text = await response.text();
|
|
83
|
+
return text ? JSON.parse(text) : undefined;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function createWodiraBrowserClient(options) {
|
|
87
|
+
return new WodiraBrowserClient(options);
|
|
88
|
+
}
|
|
89
|
+
async function readResponsePayload(response) {
|
|
90
|
+
const text = await response.text();
|
|
91
|
+
if (!text)
|
|
92
|
+
return null;
|
|
93
|
+
try {
|
|
94
|
+
return JSON.parse(text);
|
|
95
|
+
} catch {
|
|
96
|
+
return text;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function extractErrorMessage(payload, response) {
|
|
100
|
+
if (typeof payload === "string")
|
|
101
|
+
return payload;
|
|
102
|
+
const message = payload?.message;
|
|
103
|
+
if (typeof message === "string")
|
|
104
|
+
return message;
|
|
105
|
+
if (Array.isArray(message))
|
|
106
|
+
return message.filter((item) => typeof item === "string").join(", ");
|
|
107
|
+
if (typeof payload?.error === "string")
|
|
108
|
+
return payload.error;
|
|
109
|
+
return `WODira browser API request failed with ${response.status} ${response.statusText}`;
|
|
110
|
+
}
|
|
111
|
+
function serializeRegistrationInput(input) {
|
|
112
|
+
return {
|
|
113
|
+
...input,
|
|
114
|
+
athletes: input.athletes.map(serializeAthleteInput),
|
|
115
|
+
...input.guestRegistrations ? {
|
|
116
|
+
guestRegistrations: input.guestRegistrations.map((guest) => ({
|
|
117
|
+
...guest,
|
|
118
|
+
athletes: guest.athletes.map(serializeAthleteInput)
|
|
119
|
+
}))
|
|
120
|
+
} : {}
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
function serializeAthleteInput(athlete) {
|
|
124
|
+
return {
|
|
125
|
+
...athlete,
|
|
126
|
+
birthDate: athlete.birthDate instanceof Date ? athlete.birthDate.toISOString().slice(0, 10) : athlete.birthDate
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
export {
|
|
130
|
+
createWodiraBrowserClient,
|
|
131
|
+
WodiraBrowserClient,
|
|
132
|
+
WodiraBrowserApiError
|
|
133
|
+
};
|