@hello-bill/node 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/LICENSE +21 -0
- package/README.md +216 -0
- package/dist/express/index.d.cts +34 -0
- package/dist/express/index.d.ts +34 -0
- package/dist/express/index.js +1019 -0
- package/dist/express/index.js.map +1 -0
- package/dist/express/index.mjs +1016 -0
- package/dist/express/index.mjs.map +1 -0
- package/dist/hono/index.d.cts +37 -0
- package/dist/hono/index.d.ts +37 -0
- package/dist/hono/index.js +1036 -0
- package/dist/hono/index.js.map +1 -0
- package/dist/hono/index.mjs +1033 -0
- package/dist/hono/index.mjs.map +1 -0
- package/dist/index-BrfG82zs.d.cts +341 -0
- package/dist/index-EXetQn1f.d.ts +341 -0
- package/dist/index.d.cts +164 -0
- package/dist/index.d.ts +164 -0
- package/dist/index.js +1178 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1164 -0
- package/dist/index.mjs.map +1 -0
- package/dist/koa/index.d.cts +42 -0
- package/dist/koa/index.d.ts +42 -0
- package/dist/koa/index.js +1042 -0
- package/dist/koa/index.js.map +1 -0
- package/dist/koa/index.mjs +1039 -0
- package/dist/koa/index.mjs.map +1 -0
- package/dist/next/index.d.cts +60 -0
- package/dist/next/index.d.ts +60 -0
- package/dist/next/index.js +1092 -0
- package/dist/next/index.js.map +1 -0
- package/dist/next/index.mjs +1090 -0
- package/dist/next/index.mjs.map +1 -0
- package/dist/types/index.d.cts +51 -0
- package/dist/types/index.d.ts +51 -0
- package/dist/types/index.js +12 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/index.mjs +9 -0
- package/dist/types/index.mjs.map +1 -0
- package/dist/webhook/index.d.cts +2 -0
- package/dist/webhook/index.d.ts +2 -0
- package/dist/webhook/index.js +342 -0
- package/dist/webhook/index.js.map +1 -0
- package/dist/webhook/index.mjs +336 -0
- package/dist/webhook/index.mjs.map +1 -0
- package/dist/webhooks-DPpqf7d2.d.cts +751 -0
- package/dist/webhooks-DPpqf7d2.d.ts +751 -0
- package/package.json +164 -7
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import { aO as WebhookEvent, aC as SessionEmbedOpened, aB as SessionDetailsConfirmed, aE as SessionProductsSelected, aD as SessionLoaSigned, ay as SessionAccountCreated, aA as SessionAppInstalled, az as SessionAppDeferred, aJ as SubscriptionChanged, aG as SetupStatusChanged, a5 as MoveOutNotificationSent, a4 as MoveOutNotificationFailed, m as BankDetailsCollected, S as SessionPayload } from './webhooks-DPpqf7d2.js';
|
|
2
|
+
|
|
3
|
+
interface TokenStorage {
|
|
4
|
+
get(clientId: string): Promise<{
|
|
5
|
+
accessToken: string;
|
|
6
|
+
expiresAt: number;
|
|
7
|
+
} | null>;
|
|
8
|
+
set(clientId: string, value: {
|
|
9
|
+
accessToken: string;
|
|
10
|
+
expiresAt: number;
|
|
11
|
+
}): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
interface Logger {
|
|
14
|
+
debug(msg: string, meta?: Record<string, unknown>): void;
|
|
15
|
+
/**
|
|
16
|
+
* Optional — added for unhandled-variant and dedup-hit logs in the webhook
|
|
17
|
+
* receiver. Existing `Logger` literals (without `info`) continue to satisfy
|
|
18
|
+
* the interface because `info` is optional.
|
|
19
|
+
*/
|
|
20
|
+
info?(msg: string, meta?: Record<string, unknown>): void;
|
|
21
|
+
warn(msg: string, meta?: Record<string, unknown>): void;
|
|
22
|
+
error(msg: string, meta?: Record<string, unknown>): void;
|
|
23
|
+
}
|
|
24
|
+
interface TokenManagerOptions {
|
|
25
|
+
clientId: string;
|
|
26
|
+
clientSecret: string;
|
|
27
|
+
apiBaseUrl: string;
|
|
28
|
+
fetch?: typeof globalThis.fetch;
|
|
29
|
+
storage?: TokenStorage;
|
|
30
|
+
logger?: Logger;
|
|
31
|
+
/** Renew tokens this many ms before expiry. Default 30_000. */
|
|
32
|
+
refreshLeewayMs?: number;
|
|
33
|
+
/** Override `Date.now()` for tests. */
|
|
34
|
+
now?: () => number;
|
|
35
|
+
}
|
|
36
|
+
/** Default in-memory single-instance storage. */
|
|
37
|
+
declare class InMemoryTokenStorage implements TokenStorage {
|
|
38
|
+
private readonly map;
|
|
39
|
+
get(clientId: string): Promise<{
|
|
40
|
+
accessToken: string;
|
|
41
|
+
expiresAt: number;
|
|
42
|
+
} | null>;
|
|
43
|
+
set(clientId: string, value: {
|
|
44
|
+
accessToken: string;
|
|
45
|
+
expiresAt: number;
|
|
46
|
+
}): Promise<void>;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Manages partner client_credentials tokens with caching, leeway-based renewal,
|
|
50
|
+
* and single-flight refresh. Pluggable storage for multi-instance deployments.
|
|
51
|
+
*/
|
|
52
|
+
declare class TokenManager {
|
|
53
|
+
private readonly clientId;
|
|
54
|
+
private readonly clientSecret;
|
|
55
|
+
private readonly apiBaseUrl;
|
|
56
|
+
private readonly fetchImpl;
|
|
57
|
+
private readonly storage;
|
|
58
|
+
private readonly logger;
|
|
59
|
+
private readonly refreshLeewayMs;
|
|
60
|
+
private readonly now;
|
|
61
|
+
private inflight;
|
|
62
|
+
constructor(opts: TokenManagerOptions);
|
|
63
|
+
/** Returns a valid bearer token, refreshing if necessary. Single-flight on refresh. */
|
|
64
|
+
getAccessToken(): Promise<string>;
|
|
65
|
+
/** Forces invalidation of the cached token. Next `getAccessToken` will refresh. */
|
|
66
|
+
invalidate(): Promise<void>;
|
|
67
|
+
private fetchToken;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
interface VerifyWebhookOptions {
|
|
71
|
+
/** Replay window in seconds. Default 300. */
|
|
72
|
+
tolerance?: number;
|
|
73
|
+
/** Signature versions to accept. Default ['v1']. Use ['v1', 'v2'] during key rotation. */
|
|
74
|
+
supportedVersions?: ('v1' | 'v2')[];
|
|
75
|
+
/** Override `Date.now()` for tests. */
|
|
76
|
+
now?: () => number;
|
|
77
|
+
}
|
|
78
|
+
declare class WebhookVerificationError extends Error {
|
|
79
|
+
code: string;
|
|
80
|
+
constructor(message: string, code: string);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Verifies a HelloBill webhook delivery.
|
|
84
|
+
* Header format: `t=<unix>,v1=<hex>,v2=<hex>`.
|
|
85
|
+
* HMAC computed over `${t}.${rawBody}` (raw bytes — do not re-serialise).
|
|
86
|
+
*/
|
|
87
|
+
declare function verifyWebhook(rawBody: Buffer | string, signatureHeader: string, secret: string, opts?: VerifyWebhookOptions): WebhookEvent;
|
|
88
|
+
/**
|
|
89
|
+
* Verifies a HelloBill webhook delivery without parsing the payload.
|
|
90
|
+
* Returns `true` only if the timestamp is within tolerance AND at least one
|
|
91
|
+
* supported scheme verifies. Returns `false` for every other case (missing/
|
|
92
|
+
* malformed header, expired timestamp, no supported version, signature
|
|
93
|
+
* mismatch). Never throws on verification failure — callers route on the
|
|
94
|
+
* boolean. Re-throws non-verification errors (e.g. unexpected crypto failures).
|
|
95
|
+
*
|
|
96
|
+
* Unlike the throwing `verifyWebhook`, this function does NOT attempt to parse
|
|
97
|
+
* the body as JSON — signature verification is purely over the raw bytes.
|
|
98
|
+
* Callers that need the parsed event should call `verifyWebhook` directly or
|
|
99
|
+
* parse separately after calling this function.
|
|
100
|
+
*
|
|
101
|
+
* @param rawBody Raw request body bytes (NOT re-serialised JSON).
|
|
102
|
+
* @param signatureHeader Value of `X-HelloBill-Signature`.
|
|
103
|
+
* @param secret Partner-issued webhook secret (env `HELLOBILL_WEBHOOK_SECRET`).
|
|
104
|
+
* @param opts Optional `tolerance` (default 300s), `supportedVersions`
|
|
105
|
+
* (default `['v1']`), `now` (test injection).
|
|
106
|
+
*/
|
|
107
|
+
declare function verifyWebhookSignature(rawBody: Buffer | string, signatureHeader: string, secret: string, opts?: VerifyWebhookOptions): boolean;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Webhook idempotency dedupe store. Keyed on `WebhookEnvelope.id`.
|
|
111
|
+
*
|
|
112
|
+
* Default `InMemoryWebhookDedupeStore` is fine for single-process deployments
|
|
113
|
+
* (and unit tests). Multi-replica deployments MUST inject a shared backend
|
|
114
|
+
* (e.g. Redis SETEX, RDS `INSERT ... ON CONFLICT DO NOTHING`). Per spec §11.1
|
|
115
|
+
* line 2270: "Use the `id` field to deduplicate."
|
|
116
|
+
*/
|
|
117
|
+
interface WebhookDedupeStore {
|
|
118
|
+
/** Returns true if `id` has been recorded within its TTL. Never throws on miss. */
|
|
119
|
+
has(id: string): Promise<boolean> | boolean;
|
|
120
|
+
/** Records `id` with the given TTL in seconds. Idempotent on repeat calls. */
|
|
121
|
+
record(id: string, ttlSeconds: number): Promise<void> | void;
|
|
122
|
+
}
|
|
123
|
+
/** In-memory implementation. NOT durable across process restarts. Tests + single-proc deploys. */
|
|
124
|
+
declare class InMemoryWebhookDedupeStore implements WebhookDedupeStore {
|
|
125
|
+
private readonly now;
|
|
126
|
+
private readonly store;
|
|
127
|
+
constructor(now?: () => number);
|
|
128
|
+
has(id: string): Promise<boolean>;
|
|
129
|
+
record(id: string, ttlSeconds: number): Promise<void>;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Per-event runtime context passed to every typed handler. */
|
|
133
|
+
interface WebhookHandlerContext {
|
|
134
|
+
/**
|
|
135
|
+
* Logger guaranteed to have `info` defined — sourced from `withInfoFallback`
|
|
136
|
+
* at handler construction. Partner handlers may call `ctx.logger.info(...)`
|
|
137
|
+
* without a null-check regardless of what Logger literal was supplied.
|
|
138
|
+
*/
|
|
139
|
+
logger: Logger & {
|
|
140
|
+
info: (msg: string, meta?: Record<string, unknown>) => void;
|
|
141
|
+
};
|
|
142
|
+
headers: Record<string, string | string[] | undefined>;
|
|
143
|
+
deprecation: string | null;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Typed handlers — one per `WebhookEvent` variant. All optional; an
|
|
147
|
+
* unprovided variant logs at info (`unhandled_variant`) and the dispatcher
|
|
148
|
+
* still responds 2xx so HelloBill stops retrying.
|
|
149
|
+
*
|
|
150
|
+
* Handlers run async AFTER the route has already responded; throwing
|
|
151
|
+
* from a handler does NOT cause HelloBill to retry (a 2xx was already
|
|
152
|
+
* written). Errors are logged via `opts.logger?.error`.
|
|
153
|
+
*/
|
|
154
|
+
interface WebhookHandlers {
|
|
155
|
+
onSessionEmbedOpened?(event: SessionEmbedOpened, ctx: WebhookHandlerContext): Promise<void>;
|
|
156
|
+
onSessionDetailsConfirmed?(event: SessionDetailsConfirmed, ctx: WebhookHandlerContext): Promise<void>;
|
|
157
|
+
onSessionProductsSelected?(event: SessionProductsSelected, ctx: WebhookHandlerContext): Promise<void>;
|
|
158
|
+
onSessionLoaSigned?(event: SessionLoaSigned, ctx: WebhookHandlerContext): Promise<void>;
|
|
159
|
+
onSessionAccountCreated?(event: SessionAccountCreated, ctx: WebhookHandlerContext): Promise<void>;
|
|
160
|
+
onSessionAppInstalled?(event: SessionAppInstalled, ctx: WebhookHandlerContext): Promise<void>;
|
|
161
|
+
onSessionAppDeferred?(event: SessionAppDeferred, ctx: WebhookHandlerContext): Promise<void>;
|
|
162
|
+
onSubscriptionChanged?(event: SubscriptionChanged, ctx: WebhookHandlerContext): Promise<void>;
|
|
163
|
+
onSetupStatusChanged?(event: SetupStatusChanged, ctx: WebhookHandlerContext): Promise<void>;
|
|
164
|
+
onMoveOutNotificationSent?(event: MoveOutNotificationSent, ctx: WebhookHandlerContext): Promise<void>;
|
|
165
|
+
onMoveOutNotificationFailed?(event: MoveOutNotificationFailed, ctx: WebhookHandlerContext): Promise<void>;
|
|
166
|
+
onBankDetailsCollected?(event: BankDetailsCollected, ctx: WebhookHandlerContext): Promise<void>;
|
|
167
|
+
}
|
|
168
|
+
/** Options for the webhook route. Lives alongside `CreateHellobillHandlerOptions`. */
|
|
169
|
+
interface WebhookHandlerOptions {
|
|
170
|
+
/**
|
|
171
|
+
* Partner webhook secret. From `process.env.HELLOBILL_WEBHOOK_SECRET`.
|
|
172
|
+
* MUST be a non-empty string at `createWebhookHandler` call time — the
|
|
173
|
+
* factory throws synchronously on `null`/`undefined`/`''` so that an
|
|
174
|
+
* unset env var is caught immediately rather than silently 401ing every
|
|
175
|
+
* incoming webhook.
|
|
176
|
+
*/
|
|
177
|
+
webhookSecret: string;
|
|
178
|
+
/**
|
|
179
|
+
* Optional dedupe-store. Default: in-memory (single-process). Multi-replica
|
|
180
|
+
* deployments MUST supply a shared backend (Redis, RDS, etc.) — see README.
|
|
181
|
+
*/
|
|
182
|
+
dedupeStore?: WebhookDedupeStore;
|
|
183
|
+
/**
|
|
184
|
+
* Idempotency window in seconds. Default 86_400 (24h). Per spec §11.1 line 2270.
|
|
185
|
+
*/
|
|
186
|
+
dedupeTtlSeconds?: number;
|
|
187
|
+
/** Signature versions accepted. Default `['v1']`. Set to `['v1','v2']` during rotation. */
|
|
188
|
+
supportedVersions?: VerifyWebhookOptions['supportedVersions'];
|
|
189
|
+
/** Timestamp tolerance in seconds. Default 300. */
|
|
190
|
+
tolerance?: number;
|
|
191
|
+
/** Optional logger. Defaults to no-op. */
|
|
192
|
+
logger?: Logger;
|
|
193
|
+
/** Typed handlers — provide as many as you care about; missing ones log "unhandled". */
|
|
194
|
+
handlers?: WebhookHandlers;
|
|
195
|
+
/**
|
|
196
|
+
* Test injection for `Date.now()`. Applied to the signature timestamp AND,
|
|
197
|
+
* only when using the default `InMemoryWebhookDedupeStore`, the dedupe TTL
|
|
198
|
+
* clock. Partner-supplied `dedupeStore` instances MUST own their own clock
|
|
199
|
+
* injection — `opts.now` is NOT forwarded to a partner-supplied store.
|
|
200
|
+
*/
|
|
201
|
+
now?: () => number;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Creates the framework-agnostic webhook receive handler. Returns a function
|
|
205
|
+
* matching the same `HellobillRequest`/`HellobillResponse` shape used by the
|
|
206
|
+
* other routes on `HellobillHandlerSet` (see `core/handler.ts`).
|
|
207
|
+
*
|
|
208
|
+
* Throws synchronously if `opts.webhookSecret` is falsy — a missing or
|
|
209
|
+
* empty secret is caught early so that every incoming webhook does not
|
|
210
|
+
* silently 401 with no visible cause.
|
|
211
|
+
*
|
|
212
|
+
* The Express adapter wires this in alongside `session`/`loa`/etc.
|
|
213
|
+
*/
|
|
214
|
+
declare function createWebhookHandler(opts: WebhookHandlerOptions): (req: HellobillRequest, res: HellobillResponse) => Promise<void>;
|
|
215
|
+
|
|
216
|
+
interface HellobillRequest {
|
|
217
|
+
method: string;
|
|
218
|
+
url: string;
|
|
219
|
+
query: Record<string, string | string[] | undefined>;
|
|
220
|
+
body: unknown;
|
|
221
|
+
headers: Record<string, string | string[] | undefined>;
|
|
222
|
+
/**
|
|
223
|
+
* Path parameters extracted by the adapter's router and populated on the
|
|
224
|
+
* way in. Example: Express maps `:id` on `router.get('/sessions/:id', ...)`
|
|
225
|
+
* into `req.params.id`; the SDK Express adapter forwards that verbatim via
|
|
226
|
+
* `params: req.params`. Adapters that do not expose path parameters leave
|
|
227
|
+
* this field `undefined` for the 8 contractual routes and synthesise
|
|
228
|
+
* `params: { id }` only for the `/sessions/:id` branch.
|
|
229
|
+
*
|
|
230
|
+
* Optional. Backwards-compatible — adapters that pre-date this field
|
|
231
|
+
* type-check unchanged.
|
|
232
|
+
*/
|
|
233
|
+
params?: Record<string, string | undefined>;
|
|
234
|
+
/** Optional raw request body for webhook verification — populated by adapter. */
|
|
235
|
+
rawBody?: Buffer;
|
|
236
|
+
}
|
|
237
|
+
interface HellobillResponse {
|
|
238
|
+
status(code: number): HellobillResponse;
|
|
239
|
+
header(name: string, value: string): HellobillResponse;
|
|
240
|
+
json(body: unknown): void;
|
|
241
|
+
}
|
|
242
|
+
interface CreateHellobillHandlerOptions {
|
|
243
|
+
clientId: string;
|
|
244
|
+
clientSecret: string;
|
|
245
|
+
/** Partner API base URL, e.g. https://api.hellobill.app/api/v1 or http://localhost:4100. */
|
|
246
|
+
apiBaseUrl: string;
|
|
247
|
+
/**
|
|
248
|
+
* Called on POST /session to assemble the canonical SessionPayload from whatever
|
|
249
|
+
* the partner's host page sent. Receives the request unchanged and the resolved
|
|
250
|
+
* partner session (if configured, or null if `partnerSession` is absent).
|
|
251
|
+
*
|
|
252
|
+
* When `partnerSession` is configured, this function MUST source
|
|
253
|
+
* `customer.email` from the second argument — never from `req.body` —
|
|
254
|
+
* to prevent the browser from spoofing the email address.
|
|
255
|
+
*/
|
|
256
|
+
buildSessionPayload: (req: HellobillRequest, partnerSession: unknown | null) => Promise<SessionPayload> | SessionPayload;
|
|
257
|
+
/**
|
|
258
|
+
* Optional. Resolves the partner's authenticated server-side session from the
|
|
259
|
+
* incoming request. Result (if non-null) is passed to `buildSessionPayload`
|
|
260
|
+
* as the second argument.
|
|
261
|
+
*
|
|
262
|
+
* Returning `null` causes the middleware to return `401 auth.invalid_credentials`
|
|
263
|
+
* before invoking `buildSessionPayload` or calling the upstream API.
|
|
264
|
+
* Throwing causes a `500 internal.error` response and a warn-level log.
|
|
265
|
+
* When absent, `buildSessionPayload` is called with `null` as the second arg;
|
|
266
|
+
* the partner's `buildSessionPayload` is then solely responsible for any
|
|
267
|
+
* CSRF / origin / session checks.
|
|
268
|
+
*/
|
|
269
|
+
partnerSession?: (req: HellobillRequest) => Promise<unknown | null> | unknown | null;
|
|
270
|
+
/** Optional override for idempotency key generation. Defaults to crypto.randomUUID(). */
|
|
271
|
+
idempotencyKeyFactory?: () => string;
|
|
272
|
+
/** Optional token storage adapter for multi-instance deployments. Default: in-memory. */
|
|
273
|
+
tokenStorage?: TokenStorage;
|
|
274
|
+
/** Custom fetch implementation (for tests). Defaults to globalThis.fetch. */
|
|
275
|
+
fetch?: typeof globalThis.fetch;
|
|
276
|
+
/** Optional logger. Defaults to no-op. Receives safe (no-secret) log lines. */
|
|
277
|
+
logger?: Logger;
|
|
278
|
+
/**
|
|
279
|
+
* Per-attempt upstream request timeout in ms. Default 30_000 (30s). Each retry
|
|
280
|
+
* starts a fresh timeout. Network failures and timeouts are surfaced as a
|
|
281
|
+
* clean `internal.error` envelope.
|
|
282
|
+
*/
|
|
283
|
+
upstreamTimeoutMs?: number;
|
|
284
|
+
/**
|
|
285
|
+
* Optional webhook receiver configuration. When provided, exposes a
|
|
286
|
+
* `webhook` handler on `HellobillHandlerSet` that the Express adapter
|
|
287
|
+
* mounts at POST /webhooks. Omit to skip the route entirely.
|
|
288
|
+
*/
|
|
289
|
+
webhook?: WebhookHandlerOptions;
|
|
290
|
+
}
|
|
291
|
+
interface HellobillHandlerSet {
|
|
292
|
+
session: (req: HellobillRequest, res: HellobillResponse) => Promise<void>;
|
|
293
|
+
loa: (req: HellobillRequest, res: HellobillResponse) => Promise<void>;
|
|
294
|
+
bankDetails: {
|
|
295
|
+
submit: (req: HellobillRequest, res: HellobillResponse) => Promise<void>;
|
|
296
|
+
get: (req: HellobillRequest, res: HellobillResponse) => Promise<void>;
|
|
297
|
+
};
|
|
298
|
+
customers: (req: HellobillRequest, res: HellobillResponse) => Promise<void>;
|
|
299
|
+
status: (req: HellobillRequest, res: HellobillResponse) => Promise<void>;
|
|
300
|
+
products: (req: HellobillRequest, res: HellobillResponse) => Promise<void>;
|
|
301
|
+
property: (req: HellobillRequest, res: HellobillResponse) => Promise<void>;
|
|
302
|
+
/**
|
|
303
|
+
* Partner-side session recovery: list or fetch a single session by id.
|
|
304
|
+
* Both proxy the bearer-gated upstream endpoints without requiring a
|
|
305
|
+
* session_token — they are scoped to the partner's access_token.
|
|
306
|
+
*
|
|
307
|
+
* Query params on `list` pass through verbatim (including non-spec keys;
|
|
308
|
+
* upstream owns 400-on-unknown-filter semantics). The `get` handler reads
|
|
309
|
+
* the session id from `req.params.id`.
|
|
310
|
+
*
|
|
311
|
+
* Additive: not part of the v1.15 contract (spec §9.2.1). The reference SDK
|
|
312
|
+
* always includes them; partners may opt out by substituting a handler that
|
|
313
|
+
* returns 404.
|
|
314
|
+
*/
|
|
315
|
+
sessions: {
|
|
316
|
+
list: (req: HellobillRequest, res: HellobillResponse) => Promise<void>;
|
|
317
|
+
get: (req: HellobillRequest, res: HellobillResponse) => Promise<void>;
|
|
318
|
+
};
|
|
319
|
+
/**
|
|
320
|
+
* Proxies GET /partner/customers/:id/savings-summary.
|
|
321
|
+
* Reads customer_id from req.query.customer_id or req.params.id.
|
|
322
|
+
* Scoped to the partner's access_token — no session_token required.
|
|
323
|
+
*/
|
|
324
|
+
savingsSummary: (req: HellobillRequest, res: HellobillResponse) => Promise<void>;
|
|
325
|
+
/**
|
|
326
|
+
* Proxies GET /partner/sessions/:id/anyvan-slots.
|
|
327
|
+
* Reads session_id from req.query.session_id or req.params.id.
|
|
328
|
+
* Scoped to the partner's access_token — no session_token required.
|
|
329
|
+
*/
|
|
330
|
+
anyvanSlots: (req: HellobillRequest, res: HellobillResponse) => Promise<void>;
|
|
331
|
+
/**
|
|
332
|
+
* Optional webhook receiver. Present only when `opts.webhook` is supplied to
|
|
333
|
+
* `createHellobillHandler`. The Express adapter mounts POST /webhooks when
|
|
334
|
+
* this slot is defined, and omits the route when it is `undefined`.
|
|
335
|
+
*/
|
|
336
|
+
webhook?: (req: HellobillRequest, res: HellobillResponse) => Promise<void>;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
declare function createHellobillHandler(opts: CreateHellobillHandlerOptions): HellobillHandlerSet;
|
|
340
|
+
|
|
341
|
+
export { type CreateHellobillHandlerOptions as C, type HellobillHandlerSet as H, InMemoryTokenStorage as I, type Logger as L, type TokenStorage as T, type VerifyWebhookOptions as V, type WebhookDedupeStore as W, type HellobillRequest as a, type HellobillResponse as b, InMemoryWebhookDedupeStore as c, TokenManager as d, type TokenManagerOptions as e, type WebhookHandlerContext as f, type WebhookHandlerOptions as g, type WebhookHandlers as h, WebhookVerificationError as i, createHellobillHandler as j, createWebhookHandler as k, verifyWebhookSignature as l, verifyWebhook as v };
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { T as TokenStorage, L as Logger } from './index-BrfG82zs.cjs';
|
|
2
|
+
export { C as CreateHellobillHandlerOptions, H as HellobillHandlerSet, a as HellobillRequest, b as HellobillResponse, I as InMemoryTokenStorage, c as InMemoryWebhookDedupeStore, d as TokenManager, e as TokenManagerOptions, V as VerifyWebhookOptions, W as WebhookDedupeStore, f as WebhookHandlerContext, g as WebhookHandlerOptions, h as WebhookHandlers, i as WebhookVerificationError, j as createHellobillHandler, k as createWebhookHandler, v as verifyWebhook, l as verifyWebhookSignature } from './index-BrfG82zs.cjs';
|
|
3
|
+
import { R as RequestId, S as SessionPayload, a as SessionResponse, b as SessionGetResponse, P as ProductsQuery, c as ProductsResponse, d as PropertyDetailResponse, L as LoaListResponse, C as CreateCustomerInput, e as CustomerCreateResponse, f as CustomerId, g as CustomerStatusResponse, B as BankDetailsRequest, h as BankDetailsResponse } from './webhooks-DPpqf7d2.cjs';
|
|
4
|
+
export { A as Address, i as AddressObject, j as AddressesObject, k as ApiVersion, l as AppDeeplinks, m as BankDetailsCollected, n as BankDetailsConsent, o as BankDetailsObject, p as BankDetailsStatus, q as BillType, r as BreakdownCoverProduct, s as BroadbandProduct, t as BuildingStyle, u as BuildingType, v as CacheStatus, w as ClientMode, x as Consent, y as ContextEntry, z as CouncilTaxProduct, D as Customer, E as CustomerType, F as DataCompleteness, G as DiscoveryStatus, H as Email, I as EnergyProduct, J as Environment, K as EpcRating, M as FinalRead, N as FuelType, O as HeatingType, Q as HomeInsuranceProduct, T as IdempotencyKey, U as IsoDate, V as IsoDateTime, W as LoASignature, X as LoaId, Y as LoaRecord, Z as LocationRole, _ as MaskedSortCode, $ as Meters, a0 as MobileProduct, a1 as MoveIn, a2 as MoveObject, a3 as MoveOut, a4 as MoveOutNotificationFailed, a5 as MoveOutNotificationSent, a6 as MoveOutNotifyFlags, a7 as MoveOutReason, a8 as MoveOutStatus, a9 as NearbyPoi, aa as OccupantObject, ab as OccupantType, ac as OnboardingInfo, ad as OverallStatus, ae as Paginated, af as Person, ag as PhoneNumber, ah as Postcode, ai as Product, aj as ProductBase, ak as ProductCategory, al as ProductConfidence, am as ProductId, an as ProductSetup, ao as PropertyDetailObject, ap as PropertyLocation, aq as PropertyObject, ar as PropertyType, as as PropertyTypeCode, at as PropertyTypeSubcode, au as ProvidedFieldPath, av as SESSION_IDEMPOTENCY_TTL_MS, aw as SavingsSummaryResponse, ax as SelectedProduct, ay as SessionAccountCreated, az as SessionAppDeferred, aA as SessionAppInstalled, aB as SessionDetailsConfirmed, aC as SessionEmbedOpened, aD as SessionLoaSigned, aE as SessionProductsSelected, aF as SetupStatus, aG as SetupStatusChanged, aH as SignatureImage, aI as StoredBankDetails, aJ as SubscriptionChanged, aK as SubscriptionStatus, aL as TvLicenceProduct, aM as Url, aN as WaterProduct, aO as WebhookEvent, aP as WebhookEventBase, aQ as WebhookEventId, aR as WebhookEventType } from './webhooks-DPpqf7d2.cjs';
|
|
5
|
+
import { ErrorEnvelope } from './types/index.cjs';
|
|
6
|
+
export { AnyvanSlot, AnyvanSlotsResponse, ErrorCode, ErrorType, RETRYABLE_HTTP_STATUSES } from './types/index.cjs';
|
|
7
|
+
|
|
8
|
+
interface RetryOptions {
|
|
9
|
+
/** Max attempts including the first. Default 5. */
|
|
10
|
+
maxAttempts?: number;
|
|
11
|
+
/** Base delay in ms for exponential backoff. Default 1000. */
|
|
12
|
+
baseDelayMs?: number;
|
|
13
|
+
/** Cap on delay (ms). Default 16000. */
|
|
14
|
+
maxDelayMs?: number;
|
|
15
|
+
/** Override fetch (for tests). Defaults to globalThis.fetch. */
|
|
16
|
+
fetch?: typeof globalThis.fetch;
|
|
17
|
+
/** Override sleep (for tests). */
|
|
18
|
+
sleep?: (ms: number) => Promise<void>;
|
|
19
|
+
/** Random source for jitter (0..1). */
|
|
20
|
+
random?: () => number;
|
|
21
|
+
/**
|
|
22
|
+
* Optional pre-attempt hook. Resolves with `true` to swap in a refreshed token.
|
|
23
|
+
* Called once per attempt when the previous response indicated `auth.token_expired`.
|
|
24
|
+
*/
|
|
25
|
+
onTokenExpired?: () => Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Per-attempt request timeout in ms. If the fetch does not resolve within this
|
|
28
|
+
* window, it is aborted and treated as a retryable network error. Default 30_000.
|
|
29
|
+
*/
|
|
30
|
+
timeoutMs?: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Fetch with retry. Retries on retryable HTTP statuses honoring `Retry-After`,
|
|
34
|
+
* and invokes `onTokenExpired` once when the upstream returns `auth.token_expired`.
|
|
35
|
+
*/
|
|
36
|
+
declare function retryFetch(input: string | URL, init: RequestInit, opts?: RetryOptions): Promise<Response>;
|
|
37
|
+
|
|
38
|
+
/** Default idempotency key generator — UUID v4 via Node crypto. */
|
|
39
|
+
declare function defaultIdempotencyKey(): string;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Thrown when an upstream call returns a non-2xx response.
|
|
43
|
+
* Handlers catch and pass through the envelope verbatim to the caller.
|
|
44
|
+
*
|
|
45
|
+
* `headers` carries the upstream response headers so callers can read
|
|
46
|
+
* rate-limit budget (X-RateLimit-Remaining) and back-off hints (Retry-After)
|
|
47
|
+
* after retries are exhausted.
|
|
48
|
+
*/
|
|
49
|
+
declare class HellobillApiError extends Error {
|
|
50
|
+
readonly status: number;
|
|
51
|
+
readonly envelope: ErrorEnvelope | null;
|
|
52
|
+
readonly requestId: RequestId | undefined;
|
|
53
|
+
readonly headers: Headers | undefined;
|
|
54
|
+
constructor(status: number, envelope: ErrorEnvelope | null, requestId?: RequestId, headers?: Headers);
|
|
55
|
+
get code(): string | undefined;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
interface HelloBillPartnerOptions {
|
|
59
|
+
clientId: string;
|
|
60
|
+
clientSecret: string;
|
|
61
|
+
/**
|
|
62
|
+
* Partner API base URL. Defaults to the production endpoint.
|
|
63
|
+
* Override for sandbox proxies or local mock-api testing.
|
|
64
|
+
*/
|
|
65
|
+
apiBaseUrl?: string;
|
|
66
|
+
/** Optional token storage adapter for multi-instance deployments. Default: in-memory. */
|
|
67
|
+
tokenStorage?: TokenStorage;
|
|
68
|
+
/** Custom fetch implementation (for tests). Defaults to globalThis.fetch. */
|
|
69
|
+
fetch?: typeof globalThis.fetch;
|
|
70
|
+
/** Optional logger. Defaults to no-op. */
|
|
71
|
+
logger?: Logger;
|
|
72
|
+
/** Per-attempt upstream request timeout in ms. Default 30_000 (30s). */
|
|
73
|
+
upstreamTimeoutMs?: number;
|
|
74
|
+
/** Optional override for idempotency key generation. Defaults to crypto.randomUUID(). */
|
|
75
|
+
idempotencyKeyFactory?: () => string;
|
|
76
|
+
}
|
|
77
|
+
interface IdempotencyOptions {
|
|
78
|
+
idempotencyKey?: string;
|
|
79
|
+
}
|
|
80
|
+
interface SessionsListQuery {
|
|
81
|
+
email?: string;
|
|
82
|
+
postcode?: string;
|
|
83
|
+
created_after?: string;
|
|
84
|
+
created_before?: string;
|
|
85
|
+
status?: 'created' | 'customer_created' | 'expired';
|
|
86
|
+
cursor?: string;
|
|
87
|
+
limit?: number;
|
|
88
|
+
}
|
|
89
|
+
interface SessionsListResponse {
|
|
90
|
+
sessions: Array<{
|
|
91
|
+
session_id: string;
|
|
92
|
+
referral_id: string | null;
|
|
93
|
+
email: string;
|
|
94
|
+
postcode: string;
|
|
95
|
+
address_line_1: string;
|
|
96
|
+
status: string;
|
|
97
|
+
customer_id?: string;
|
|
98
|
+
created_at: string;
|
|
99
|
+
expires_at: string;
|
|
100
|
+
}>;
|
|
101
|
+
next_cursor: string | null;
|
|
102
|
+
}
|
|
103
|
+
interface LoaQuery {
|
|
104
|
+
product_ids: string[];
|
|
105
|
+
}
|
|
106
|
+
interface PropertyQuery {
|
|
107
|
+
force_refresh?: boolean;
|
|
108
|
+
}
|
|
109
|
+
declare class HelloBillPartner {
|
|
110
|
+
private readonly tokenManager;
|
|
111
|
+
private readonly apiBaseUrl;
|
|
112
|
+
private readonly fetchImpl;
|
|
113
|
+
private readonly logger;
|
|
114
|
+
private readonly upstreamTimeoutMs;
|
|
115
|
+
private readonly idempotencyKeyFactory;
|
|
116
|
+
readonly sessions: {
|
|
117
|
+
create: (payload: SessionPayload, opts?: IdempotencyOptions) => Promise<SessionResponse>;
|
|
118
|
+
list: (query?: SessionsListQuery) => Promise<SessionsListResponse>;
|
|
119
|
+
get: (sessionId: string) => Promise<SessionGetResponse>;
|
|
120
|
+
products: (sessionId: string, query?: ProductsQuery) => Promise<ProductsResponse>;
|
|
121
|
+
property: (sessionId: string, query?: PropertyQuery) => Promise<PropertyDetailResponse>;
|
|
122
|
+
loa: (sessionId: string, query: LoaQuery) => Promise<LoaListResponse>;
|
|
123
|
+
customers: (sessionId: string, payload: CreateCustomerInput, opts?: IdempotencyOptions) => Promise<CustomerCreateResponse>;
|
|
124
|
+
};
|
|
125
|
+
readonly customers: {
|
|
126
|
+
status: (customerId: CustomerId) => Promise<CustomerStatusResponse>;
|
|
127
|
+
};
|
|
128
|
+
readonly bankDetails: {
|
|
129
|
+
submit: (sessionId: string, payload: BankDetailsRequest, opts?: IdempotencyOptions) => Promise<BankDetailsResponse>;
|
|
130
|
+
get: (sessionId: string) => Promise<BankDetailsResponse>;
|
|
131
|
+
};
|
|
132
|
+
constructor(opts: HelloBillPartnerOptions);
|
|
133
|
+
/**
|
|
134
|
+
* Shared transport envelope: acquires a token, builds the request,
|
|
135
|
+
* delegates to callUpstream (which handles retries and token refresh),
|
|
136
|
+
* then throws HellobillApiError for any non-2xx response.
|
|
137
|
+
*/
|
|
138
|
+
private _call;
|
|
139
|
+
/** Maps SessionsListQuery to a plain string record for URLSearchParams. */
|
|
140
|
+
private _sessionsListQuery;
|
|
141
|
+
/**
|
|
142
|
+
* Maps ProductsQuery to a wire-safe string record.
|
|
143
|
+
* - categories: joined as a single CSV value (one URL param, not repeated keys)
|
|
144
|
+
* - booleans: true → 'true'; false → omitted (no falsy leakage onto the wire)
|
|
145
|
+
* - numbers: coerced to string
|
|
146
|
+
*/
|
|
147
|
+
private _productsQuery;
|
|
148
|
+
/** Maps PropertyQuery to a wire-safe string record. */
|
|
149
|
+
private _propertyQuery;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Builds the onboarding_info object for a product entry in the createCustomer request.
|
|
154
|
+
*
|
|
155
|
+
* Returns undefined when:
|
|
156
|
+
* - location is 'previous' (previous-address products have no standard onboarding fields)
|
|
157
|
+
* - category has no standard onboarding fields (mobile, tv_licence, home_insurance, breakdown_cover)
|
|
158
|
+
* - none of the canonical fields for the category are present in the supplied fields object
|
|
159
|
+
*
|
|
160
|
+
* Callers must omit the onboarding_info key entirely when this returns undefined.
|
|
161
|
+
*/
|
|
162
|
+
declare function buildOnboardingInfo(_productId: string, category: string, location: string, fields: Record<string, unknown>): Record<string, unknown> | undefined;
|
|
163
|
+
|
|
164
|
+
export { BankDetailsRequest, BankDetailsResponse, CreateCustomerInput, CustomerCreateResponse, CustomerId, CustomerStatusResponse, ErrorEnvelope, HelloBillPartner, type HelloBillPartnerOptions, HellobillApiError, type IdempotencyOptions, LoaListResponse, type LoaQuery, Logger, ProductsQuery, ProductsResponse, PropertyDetailResponse, type PropertyQuery, RequestId, type RetryOptions, SessionGetResponse, SessionPayload, SessionResponse, type SessionsListQuery, type SessionsListResponse, TokenStorage, buildOnboardingInfo, defaultIdempotencyKey, retryFetch };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { T as TokenStorage, L as Logger } from './index-EXetQn1f.js';
|
|
2
|
+
export { C as CreateHellobillHandlerOptions, H as HellobillHandlerSet, a as HellobillRequest, b as HellobillResponse, I as InMemoryTokenStorage, c as InMemoryWebhookDedupeStore, d as TokenManager, e as TokenManagerOptions, V as VerifyWebhookOptions, W as WebhookDedupeStore, f as WebhookHandlerContext, g as WebhookHandlerOptions, h as WebhookHandlers, i as WebhookVerificationError, j as createHellobillHandler, k as createWebhookHandler, v as verifyWebhook, l as verifyWebhookSignature } from './index-EXetQn1f.js';
|
|
3
|
+
import { R as RequestId, S as SessionPayload, a as SessionResponse, b as SessionGetResponse, P as ProductsQuery, c as ProductsResponse, d as PropertyDetailResponse, L as LoaListResponse, C as CreateCustomerInput, e as CustomerCreateResponse, f as CustomerId, g as CustomerStatusResponse, B as BankDetailsRequest, h as BankDetailsResponse } from './webhooks-DPpqf7d2.js';
|
|
4
|
+
export { A as Address, i as AddressObject, j as AddressesObject, k as ApiVersion, l as AppDeeplinks, m as BankDetailsCollected, n as BankDetailsConsent, o as BankDetailsObject, p as BankDetailsStatus, q as BillType, r as BreakdownCoverProduct, s as BroadbandProduct, t as BuildingStyle, u as BuildingType, v as CacheStatus, w as ClientMode, x as Consent, y as ContextEntry, z as CouncilTaxProduct, D as Customer, E as CustomerType, F as DataCompleteness, G as DiscoveryStatus, H as Email, I as EnergyProduct, J as Environment, K as EpcRating, M as FinalRead, N as FuelType, O as HeatingType, Q as HomeInsuranceProduct, T as IdempotencyKey, U as IsoDate, V as IsoDateTime, W as LoASignature, X as LoaId, Y as LoaRecord, Z as LocationRole, _ as MaskedSortCode, $ as Meters, a0 as MobileProduct, a1 as MoveIn, a2 as MoveObject, a3 as MoveOut, a4 as MoveOutNotificationFailed, a5 as MoveOutNotificationSent, a6 as MoveOutNotifyFlags, a7 as MoveOutReason, a8 as MoveOutStatus, a9 as NearbyPoi, aa as OccupantObject, ab as OccupantType, ac as OnboardingInfo, ad as OverallStatus, ae as Paginated, af as Person, ag as PhoneNumber, ah as Postcode, ai as Product, aj as ProductBase, ak as ProductCategory, al as ProductConfidence, am as ProductId, an as ProductSetup, ao as PropertyDetailObject, ap as PropertyLocation, aq as PropertyObject, ar as PropertyType, as as PropertyTypeCode, at as PropertyTypeSubcode, au as ProvidedFieldPath, av as SESSION_IDEMPOTENCY_TTL_MS, aw as SavingsSummaryResponse, ax as SelectedProduct, ay as SessionAccountCreated, az as SessionAppDeferred, aA as SessionAppInstalled, aB as SessionDetailsConfirmed, aC as SessionEmbedOpened, aD as SessionLoaSigned, aE as SessionProductsSelected, aF as SetupStatus, aG as SetupStatusChanged, aH as SignatureImage, aI as StoredBankDetails, aJ as SubscriptionChanged, aK as SubscriptionStatus, aL as TvLicenceProduct, aM as Url, aN as WaterProduct, aO as WebhookEvent, aP as WebhookEventBase, aQ as WebhookEventId, aR as WebhookEventType } from './webhooks-DPpqf7d2.js';
|
|
5
|
+
import { ErrorEnvelope } from './types/index.js';
|
|
6
|
+
export { AnyvanSlot, AnyvanSlotsResponse, ErrorCode, ErrorType, RETRYABLE_HTTP_STATUSES } from './types/index.js';
|
|
7
|
+
|
|
8
|
+
interface RetryOptions {
|
|
9
|
+
/** Max attempts including the first. Default 5. */
|
|
10
|
+
maxAttempts?: number;
|
|
11
|
+
/** Base delay in ms for exponential backoff. Default 1000. */
|
|
12
|
+
baseDelayMs?: number;
|
|
13
|
+
/** Cap on delay (ms). Default 16000. */
|
|
14
|
+
maxDelayMs?: number;
|
|
15
|
+
/** Override fetch (for tests). Defaults to globalThis.fetch. */
|
|
16
|
+
fetch?: typeof globalThis.fetch;
|
|
17
|
+
/** Override sleep (for tests). */
|
|
18
|
+
sleep?: (ms: number) => Promise<void>;
|
|
19
|
+
/** Random source for jitter (0..1). */
|
|
20
|
+
random?: () => number;
|
|
21
|
+
/**
|
|
22
|
+
* Optional pre-attempt hook. Resolves with `true` to swap in a refreshed token.
|
|
23
|
+
* Called once per attempt when the previous response indicated `auth.token_expired`.
|
|
24
|
+
*/
|
|
25
|
+
onTokenExpired?: () => Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Per-attempt request timeout in ms. If the fetch does not resolve within this
|
|
28
|
+
* window, it is aborted and treated as a retryable network error. Default 30_000.
|
|
29
|
+
*/
|
|
30
|
+
timeoutMs?: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Fetch with retry. Retries on retryable HTTP statuses honoring `Retry-After`,
|
|
34
|
+
* and invokes `onTokenExpired` once when the upstream returns `auth.token_expired`.
|
|
35
|
+
*/
|
|
36
|
+
declare function retryFetch(input: string | URL, init: RequestInit, opts?: RetryOptions): Promise<Response>;
|
|
37
|
+
|
|
38
|
+
/** Default idempotency key generator — UUID v4 via Node crypto. */
|
|
39
|
+
declare function defaultIdempotencyKey(): string;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Thrown when an upstream call returns a non-2xx response.
|
|
43
|
+
* Handlers catch and pass through the envelope verbatim to the caller.
|
|
44
|
+
*
|
|
45
|
+
* `headers` carries the upstream response headers so callers can read
|
|
46
|
+
* rate-limit budget (X-RateLimit-Remaining) and back-off hints (Retry-After)
|
|
47
|
+
* after retries are exhausted.
|
|
48
|
+
*/
|
|
49
|
+
declare class HellobillApiError extends Error {
|
|
50
|
+
readonly status: number;
|
|
51
|
+
readonly envelope: ErrorEnvelope | null;
|
|
52
|
+
readonly requestId: RequestId | undefined;
|
|
53
|
+
readonly headers: Headers | undefined;
|
|
54
|
+
constructor(status: number, envelope: ErrorEnvelope | null, requestId?: RequestId, headers?: Headers);
|
|
55
|
+
get code(): string | undefined;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
interface HelloBillPartnerOptions {
|
|
59
|
+
clientId: string;
|
|
60
|
+
clientSecret: string;
|
|
61
|
+
/**
|
|
62
|
+
* Partner API base URL. Defaults to the production endpoint.
|
|
63
|
+
* Override for sandbox proxies or local mock-api testing.
|
|
64
|
+
*/
|
|
65
|
+
apiBaseUrl?: string;
|
|
66
|
+
/** Optional token storage adapter for multi-instance deployments. Default: in-memory. */
|
|
67
|
+
tokenStorage?: TokenStorage;
|
|
68
|
+
/** Custom fetch implementation (for tests). Defaults to globalThis.fetch. */
|
|
69
|
+
fetch?: typeof globalThis.fetch;
|
|
70
|
+
/** Optional logger. Defaults to no-op. */
|
|
71
|
+
logger?: Logger;
|
|
72
|
+
/** Per-attempt upstream request timeout in ms. Default 30_000 (30s). */
|
|
73
|
+
upstreamTimeoutMs?: number;
|
|
74
|
+
/** Optional override for idempotency key generation. Defaults to crypto.randomUUID(). */
|
|
75
|
+
idempotencyKeyFactory?: () => string;
|
|
76
|
+
}
|
|
77
|
+
interface IdempotencyOptions {
|
|
78
|
+
idempotencyKey?: string;
|
|
79
|
+
}
|
|
80
|
+
interface SessionsListQuery {
|
|
81
|
+
email?: string;
|
|
82
|
+
postcode?: string;
|
|
83
|
+
created_after?: string;
|
|
84
|
+
created_before?: string;
|
|
85
|
+
status?: 'created' | 'customer_created' | 'expired';
|
|
86
|
+
cursor?: string;
|
|
87
|
+
limit?: number;
|
|
88
|
+
}
|
|
89
|
+
interface SessionsListResponse {
|
|
90
|
+
sessions: Array<{
|
|
91
|
+
session_id: string;
|
|
92
|
+
referral_id: string | null;
|
|
93
|
+
email: string;
|
|
94
|
+
postcode: string;
|
|
95
|
+
address_line_1: string;
|
|
96
|
+
status: string;
|
|
97
|
+
customer_id?: string;
|
|
98
|
+
created_at: string;
|
|
99
|
+
expires_at: string;
|
|
100
|
+
}>;
|
|
101
|
+
next_cursor: string | null;
|
|
102
|
+
}
|
|
103
|
+
interface LoaQuery {
|
|
104
|
+
product_ids: string[];
|
|
105
|
+
}
|
|
106
|
+
interface PropertyQuery {
|
|
107
|
+
force_refresh?: boolean;
|
|
108
|
+
}
|
|
109
|
+
declare class HelloBillPartner {
|
|
110
|
+
private readonly tokenManager;
|
|
111
|
+
private readonly apiBaseUrl;
|
|
112
|
+
private readonly fetchImpl;
|
|
113
|
+
private readonly logger;
|
|
114
|
+
private readonly upstreamTimeoutMs;
|
|
115
|
+
private readonly idempotencyKeyFactory;
|
|
116
|
+
readonly sessions: {
|
|
117
|
+
create: (payload: SessionPayload, opts?: IdempotencyOptions) => Promise<SessionResponse>;
|
|
118
|
+
list: (query?: SessionsListQuery) => Promise<SessionsListResponse>;
|
|
119
|
+
get: (sessionId: string) => Promise<SessionGetResponse>;
|
|
120
|
+
products: (sessionId: string, query?: ProductsQuery) => Promise<ProductsResponse>;
|
|
121
|
+
property: (sessionId: string, query?: PropertyQuery) => Promise<PropertyDetailResponse>;
|
|
122
|
+
loa: (sessionId: string, query: LoaQuery) => Promise<LoaListResponse>;
|
|
123
|
+
customers: (sessionId: string, payload: CreateCustomerInput, opts?: IdempotencyOptions) => Promise<CustomerCreateResponse>;
|
|
124
|
+
};
|
|
125
|
+
readonly customers: {
|
|
126
|
+
status: (customerId: CustomerId) => Promise<CustomerStatusResponse>;
|
|
127
|
+
};
|
|
128
|
+
readonly bankDetails: {
|
|
129
|
+
submit: (sessionId: string, payload: BankDetailsRequest, opts?: IdempotencyOptions) => Promise<BankDetailsResponse>;
|
|
130
|
+
get: (sessionId: string) => Promise<BankDetailsResponse>;
|
|
131
|
+
};
|
|
132
|
+
constructor(opts: HelloBillPartnerOptions);
|
|
133
|
+
/**
|
|
134
|
+
* Shared transport envelope: acquires a token, builds the request,
|
|
135
|
+
* delegates to callUpstream (which handles retries and token refresh),
|
|
136
|
+
* then throws HellobillApiError for any non-2xx response.
|
|
137
|
+
*/
|
|
138
|
+
private _call;
|
|
139
|
+
/** Maps SessionsListQuery to a plain string record for URLSearchParams. */
|
|
140
|
+
private _sessionsListQuery;
|
|
141
|
+
/**
|
|
142
|
+
* Maps ProductsQuery to a wire-safe string record.
|
|
143
|
+
* - categories: joined as a single CSV value (one URL param, not repeated keys)
|
|
144
|
+
* - booleans: true → 'true'; false → omitted (no falsy leakage onto the wire)
|
|
145
|
+
* - numbers: coerced to string
|
|
146
|
+
*/
|
|
147
|
+
private _productsQuery;
|
|
148
|
+
/** Maps PropertyQuery to a wire-safe string record. */
|
|
149
|
+
private _propertyQuery;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Builds the onboarding_info object for a product entry in the createCustomer request.
|
|
154
|
+
*
|
|
155
|
+
* Returns undefined when:
|
|
156
|
+
* - location is 'previous' (previous-address products have no standard onboarding fields)
|
|
157
|
+
* - category has no standard onboarding fields (mobile, tv_licence, home_insurance, breakdown_cover)
|
|
158
|
+
* - none of the canonical fields for the category are present in the supplied fields object
|
|
159
|
+
*
|
|
160
|
+
* Callers must omit the onboarding_info key entirely when this returns undefined.
|
|
161
|
+
*/
|
|
162
|
+
declare function buildOnboardingInfo(_productId: string, category: string, location: string, fields: Record<string, unknown>): Record<string, unknown> | undefined;
|
|
163
|
+
|
|
164
|
+
export { BankDetailsRequest, BankDetailsResponse, CreateCustomerInput, CustomerCreateResponse, CustomerId, CustomerStatusResponse, ErrorEnvelope, HelloBillPartner, type HelloBillPartnerOptions, HellobillApiError, type IdempotencyOptions, LoaListResponse, type LoaQuery, Logger, ProductsQuery, ProductsResponse, PropertyDetailResponse, type PropertyQuery, RequestId, type RetryOptions, SessionGetResponse, SessionPayload, SessionResponse, type SessionsListQuery, type SessionsListResponse, TokenStorage, buildOnboardingInfo, defaultIdempotencyKey, retryFetch };
|