liqpay-nestjs 0.2.16 → 0.2.17

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.
Files changed (2) hide show
  1. package/README.md +338 -6
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,15 +1,347 @@
1
1
  # liqpay-nestjs
2
2
 
3
- To install dependencies:
3
+ NestJS module for LiqPay payments with DI-friendly configuration, signed checkout helpers, typed request and response models, and webhook callback parsing.
4
+
5
+ ## Features
6
+
7
+ - NestJS module with `forRoot` and `forRootAsync`
8
+ - `LiqpayService` with payment and webhook helpers
9
+ - Signed checkout URL and checkout form generation
10
+ - Typed payment status requests
11
+ - Callback signature validation and payload parsing
12
+ - Exported Zod schemas and TypeScript types from the package root
13
+
14
+ ## Requirements
15
+
16
+ - Node.js `>= 18`
17
+ - `@nestjs/common` `^10 || ^11`
18
+ - `@nestjs/core` `^10 || ^11`
19
+
20
+ ## Installation
4
21
 
5
22
  ```bash
6
- bun install
23
+ npm install liqpay-nestjs
7
24
  ```
8
25
 
9
- To run:
26
+ ## Quick Start
10
27
 
11
- ```bash
12
- bun run index.ts
28
+ ### Register the module
29
+
30
+ ```ts
31
+ import { Module } from '@nestjs/common'
32
+ import { LiqPayModule } from 'liqpay-nestjs'
33
+
34
+ @Module({
35
+ imports: [
36
+ LiqPayModule.forRoot({
37
+ publicKey: process.env.LIQPAY_PUBLIC_KEY!,
38
+ privateKey: process.env.LIQPAY_PRIVATE_KEY!,
39
+ resultUrl: 'https://example.com/payments/result',
40
+ serverUrl: 'https://example.com/payments/webhook',
41
+ isGlobal: true,
42
+ }),
43
+ ],
44
+ })
45
+ export class AppModule {}
46
+ ```
47
+
48
+ ### Register the module asynchronously
49
+
50
+ ```ts
51
+ import { Module } from '@nestjs/common'
52
+ import { ConfigModule, ConfigService } from '@nestjs/config'
53
+ import { LiqPayModule } from 'liqpay-nestjs'
54
+
55
+ @Module({
56
+ imports: [
57
+ ConfigModule.forRoot(),
58
+ LiqPayModule.forRootAsync({
59
+ imports: [ConfigModule],
60
+ inject: [ConfigService],
61
+ useFactory: (config: ConfigService) => ({
62
+ publicKey: config.getOrThrow<string>('LIQPAY_PUBLIC_KEY'),
63
+ privateKey: config.getOrThrow<string>('LIQPAY_PRIVATE_KEY'),
64
+ resultUrl: config.get<string>('LIQPAY_RESULT_URL'),
65
+ serverUrl: config.get<string>('LIQPAY_SERVER_URL'),
66
+ isGlobal: true,
67
+ }),
68
+ }),
69
+ ],
70
+ })
71
+ export class AppModule {}
13
72
  ```
14
73
 
15
- This project was created using `bun init` in bun v1.3.10. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
74
+ ### Inject and use `LiqpayService`
75
+
76
+ ```ts
77
+ import { Controller, Get, Query } from '@nestjs/common'
78
+ import { CheckoutRequest, LiqpayService } from 'liqpay-nestjs'
79
+
80
+ @Controller('payments')
81
+ export class PaymentsController {
82
+ constructor(private readonly liqpay: LiqpayService) {}
83
+
84
+ @Get('checkout-url')
85
+ getCheckoutUrl(@Query('orderId') orderId: string) {
86
+ const payload: CheckoutRequest = {
87
+ action: 'pay',
88
+ amount: 199,
89
+ currency: 'UAH',
90
+ description: 'Order payment',
91
+ orderId,
92
+ }
93
+
94
+ return {
95
+ url: this.liqpay.payments.getCheckoutUrl(payload),
96
+ }
97
+ }
98
+ }
99
+ ```
100
+
101
+ ## Typical Flow
102
+
103
+ 1. Register `LiqPayModule` with your public and private keys.
104
+ 2. Create a checkout URL or checkout form from a `CheckoutRequest`.
105
+ 3. Point `serverUrl` to a Nest endpoint that receives the LiqPay callback envelope.
106
+ 4. Parse the callback with `liqpay.webhooks.parseCheckoutCallback(...)`.
107
+ 5. Optionally confirm the final state with `liqpay.payments.getPaymentStatus(orderId)`.
108
+
109
+ ## Configuration
110
+
111
+ Both `LiqPayModule.forRoot(...)` and `LiqPayModule.forRootAsync(...)` resolve to the same options shape.
112
+
113
+ | Option | Type | Required | Description |
114
+ | ------------ | --------- | -------- | ------------------------------------------------------------------------------------ |
115
+ | `publicKey` | `string` | Yes | LiqPay public key. |
116
+ | `privateKey` | `string` | Yes | LiqPay private key used for request signing. |
117
+ | `resultUrl` | `string` | No | Default redirect URL after checkout. Can be overridden per request. |
118
+ | `serverUrl` | `string` | No | Default callback URL for LiqPay server notifications. Can be overridden per request. |
119
+ | `isGlobal` | `boolean` | No | Registers the Nest module as global when set to `true`. Defaults to `false`. |
120
+
121
+ The async registration path validates the resolved options at runtime and throws if `publicKey` or `privateKey` are missing or not strings.
122
+
123
+ ## LiqpayService API
124
+
125
+ `LiqpayService` exposes two sub-services:
126
+
127
+ - `payments`
128
+ - `webhooks`
129
+
130
+ ### `payments.getCheckoutUrl(payload)`
131
+
132
+ Builds a signed LiqPay checkout URL.
133
+
134
+ ```ts
135
+ const url = liqpay.payments.getCheckoutUrl({
136
+ action: 'pay',
137
+ amount: 100,
138
+ currency: 'UAH',
139
+ description: 'Order #123',
140
+ orderId: 'order-123',
141
+ })
142
+ ```
143
+
144
+ Notes:
145
+
146
+ - This is a pure helper and does not perform an HTTP request.
147
+ - The library signs the payload with the configured private key.
148
+ - `version` is always sent as `7`.
149
+ - `resultUrl` and `serverUrl` fall back to module-level defaults if omitted from the payload.
150
+
151
+ ### `payments.getCheckoutForm(payload, buttonText?, buttonColor?)`
152
+
153
+ Returns an HTML form string with LiqPay's `sdk-button` widget.
154
+
155
+ ```ts
156
+ const html = liqpay.payments.getCheckoutForm(
157
+ {
158
+ action: 'pay',
159
+ amount: 100,
160
+ currency: 'UAH',
161
+ description: 'Order #123',
162
+ orderId: 'order-123',
163
+ },
164
+ 'Pay now',
165
+ '#1f9d55',
166
+ )
167
+ ```
168
+
169
+ Defaults:
170
+
171
+ - `buttonText`: `Pay`
172
+ - `buttonColor`: `#77CC5D`
173
+
174
+ ### `payments.create(payload)`
175
+
176
+ Returns the normalized checkout payload together with the generated `checkoutUrl`.
177
+
178
+ ```ts
179
+ const checkout = liqpay.payments.create({
180
+ action: 'pay',
181
+ amount: 100,
182
+ currency: 'UAH',
183
+ description: 'Order #123',
184
+ orderId: 'order-123',
185
+ })
186
+
187
+ console.log(checkout.checkoutUrl)
188
+ ```
189
+
190
+ Use this when you want both the prepared payload and the final redirect URL without making a network call.
191
+
192
+ ### `payments.getPaymentStatus(orderId)`
193
+
194
+ Calls LiqPay's status API and returns `Promise<Result<PaymentStatusResponse>>`.
195
+
196
+ ```ts
197
+ const result = await liqpay.payments.getPaymentStatus('order-123')
198
+
199
+ if (result.error) {
200
+ console.error(result.error.code, result.error.description)
201
+ } else {
202
+ console.log(result.data.status)
203
+ console.log(result.data.amount)
204
+ console.log(result.data.orderId)
205
+ }
206
+ ```
207
+
208
+ You only pass `orderId`; the library builds the `status` request internally.
209
+
210
+ ### `webhooks.parseCheckoutCallback(envelope)`
211
+
212
+ Validates the callback signature, decodes the Base64 payload, and parses it into `Promise<Result<CheckoutCallback>>`.
213
+
214
+ ```ts
215
+ import { Body, Controller, Post } from '@nestjs/common'
216
+ import { LiqPayEnvelope, LiqpayService } from 'liqpay-nestjs'
217
+
218
+ @Controller('payments')
219
+ export class WebhookController {
220
+ constructor(private readonly liqpay: LiqpayService) {}
221
+
222
+ @Post('webhook')
223
+ async handleWebhook(@Body() envelope: LiqPayEnvelope) {
224
+ const result = await this.liqpay.webhooks.parseCheckoutCallback(envelope)
225
+
226
+ if (result.error) {
227
+ return { ok: false, error: result.error }
228
+ }
229
+
230
+ return { ok: true, callback: result.data }
231
+ }
232
+ }
233
+ ```
234
+
235
+ The expected envelope shape is:
236
+
237
+ ```ts
238
+ type LiqPayEnvelope = {
239
+ data: string
240
+ signature: string
241
+ }
242
+ ```
243
+
244
+ ## Request and Response Normalization
245
+
246
+ The library normalizes the most common application-facing models and handles LiqPay's wire format for you.
247
+
248
+ - Top-level checkout and status request fields use the expected TypeScript property names, for example `orderId`, `resultUrl`, `serverUrl`, and `senderFirstName`.
249
+ - Some nested LiqPay-specific helper objects keep the exact field names defined by their exported schemas. When in doubt, validate against the schema you are using.
250
+ - Outgoing requests are serialized into the format LiqPay expects.
251
+ - Callback and status responses are transformed back to camelCase.
252
+ - Dates, booleans, and several enum-backed fields are normalized where possible.
253
+ - Checkout signing always uses the module's configured public and private keys.
254
+
255
+ ## Minimal Checkout Payload
256
+
257
+ The smallest useful `CheckoutRequest` usually looks like this:
258
+
259
+ ```ts
260
+ import { CheckoutRequest } from 'liqpay-nestjs'
261
+
262
+ const payload: CheckoutRequest = {
263
+ action: 'pay',
264
+ amount: 100,
265
+ currency: 'UAH',
266
+ description: 'Order #123',
267
+ orderId: 'order-123',
268
+ }
269
+ ```
270
+
271
+ `CheckoutRequest` also supports many LiqPay-specific fields for advanced scenarios, including:
272
+
273
+ - recurring payments: `subscribe`, `subscribeDateStart`, `subscribePeriodicity`
274
+ - one-click and tokenized flows: `cardToken`, `customer`, `customerUserId`, `recurringbytoken`
275
+ - fiscalization: `rroInfo`, `dae`
276
+ - split payments: `splitRules`
277
+ - customer and sender metadata: `ip`, `senderFirstName`, `senderLastName`, `senderAddress`, and related fields
278
+
279
+ ## Schemas and Types
280
+
281
+ All public schemas and types are exported from the package root, so you can import them directly from `liqpay-nestjs`.
282
+
283
+ ```ts
284
+ import {
285
+ CheckoutCallback,
286
+ CheckoutCallbackSchema,
287
+ CheckoutRequest,
288
+ CheckoutRequestSchema,
289
+ PaymentStatusResponse,
290
+ PaymentStatusResponseSchema,
291
+ Result,
292
+ } from 'liqpay-nestjs'
293
+ ```
294
+
295
+ Main export groups:
296
+
297
+ - base: `LiqPayEnvelope`, `LiqPayEnvelopeSchema`, `Result<T>`, request and response base unions
298
+ - checkout: `CheckoutRequest`, `CheckoutRequestSchema`, `CheckoutCallback`, `CheckoutCallbackSchema`
299
+ - payment status: `PaymentStatusRequest`, `PaymentStatusRequestSchema`, `PaymentStatusResponse`, `PaymentStatusResponseSchema`
300
+ - common: `DetailAddenda`, `FiscalData`, `SplitRule` and their schemas
301
+ - enums: action, currency, language, paytype, payment status, version, and related schema exports
302
+ - error: LiqPay error response and error code schemas and types
303
+ - nest: `LiqPayModule`, `LiqpayService`, `LiqPayOptions`, `LiqPayAsyncOptions`, `LIQPAY_OPTIONS`
304
+
305
+ ### Validating your own DTOs with the exported schemas
306
+
307
+ ```ts
308
+ import { CheckoutRequestSchema, LiqpayService } from 'liqpay-nestjs'
309
+
310
+ const payload = CheckoutRequestSchema.parse(input)
311
+ const checkout = liqpay.payments.create(payload)
312
+ ```
313
+
314
+ This is useful if you want to validate incoming controller data before passing it to the service.
315
+
316
+ ## Result Contract and Error Handling
317
+
318
+ Methods that parse LiqPay responses use this result shape:
319
+
320
+ ```ts
321
+ type Result<T> =
322
+ | { data: T; error?: null }
323
+ | { data: null; error: { code: string; description: string } }
324
+ ```
325
+
326
+ The library can return:
327
+
328
+ - LiqPay provider errors parsed from `err_code` and `err_description`
329
+ - internal parsing or transport errors such as `invalid_signature`, `decode_error`, `validation_error`, `invalid_response`, and `http_error`
330
+
331
+ Always check `result.error` before using `result.data`.
332
+
333
+ ## Advanced Nest Exports
334
+
335
+ The package root also exports:
336
+
337
+ - `LIQPAY_OPTIONS`
338
+ - `createLiqpayOptionsProvider(...)`
339
+ - `createLiqpayAsyncOptionsProvider(...)`
340
+
341
+ These helpers are useful if you want to compose your own providers around the package token instead of using `LiqPayModule` directly.
342
+
343
+ ## Build
344
+
345
+ ```bash
346
+ npm run build
347
+ ```
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "liqpay-nestjs",
3
3
  "description": "LiqPay integration module for NestJS with support for payments, callbacks, and configuration via DI.",
4
- "version": "0.2.16",
4
+ "version": "0.2.17",
5
5
  "type": "commonjs",
6
6
  "module": "dist/index.js",
7
7
  "main": "dist/index.js",