@owlmeans/client-payment 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/LICENSE +21 -0
- package/README.md +493 -0
- package/build/.gitkeep +0 -0
- package/build/consts.d.ts +3 -0
- package/build/consts.d.ts.map +1 -0
- package/build/consts.js +3 -0
- package/build/consts.js.map +1 -0
- package/build/index.d.ts +4 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +3 -0
- package/build/index.js.map +1 -0
- package/build/service.d.ts +5 -0
- package/build/service.d.ts.map +1 -0
- package/build/service.js +25 -0
- package/build/service.js.map +1 -0
- package/build/types.d.ts +2 -0
- package/build/types.d.ts.map +1 -0
- package/build/types.js +2 -0
- package/build/types.js.map +1 -0
- package/package.json +39 -0
- package/src/consts.ts +5 -0
- package/src/index.ts +4 -0
- package/src/service.ts +36 -0
- package/src/types.ts +2 -0
- package/tsconfig.json +16 -0
- package/tsconfig.tsbuildinfo +1 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 OwlMeans Common — Fullstack typescript framework
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
# @owlmeans/client-payment
|
|
2
|
+
|
|
3
|
+
The **@owlmeans/client-payment** package provides client-side payment functionality for OwlMeans Common Libraries, designed for fullstack microservices and microclients development with focus on security and proper authentication and authorization.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
This package serves as the client-side implementation of the OwlMeans payment system that:
|
|
8
|
+
|
|
9
|
+
- **Provides client-side payment services** with authentication integration
|
|
10
|
+
- **Implements shallow authentication** for payment identification
|
|
11
|
+
- **Integrates with client auth resources** for seamless user experience
|
|
12
|
+
- **Supports payment profile management** with local caching
|
|
13
|
+
- **Offers secure payment processing** with proper error handling
|
|
14
|
+
- **Enables payment workflow management** in client applications
|
|
15
|
+
|
|
16
|
+
## Core Concepts
|
|
17
|
+
|
|
18
|
+
### Client Payment Service
|
|
19
|
+
A client-side service that extends the base payment service with client-specific functionality, including integration with client authentication resources.
|
|
20
|
+
|
|
21
|
+
### Shallow Authentication
|
|
22
|
+
A lightweight authentication mechanism for payment operations that caches payment profile information locally to avoid repeated authentication requests.
|
|
23
|
+
|
|
24
|
+
### Payment Profile Integration
|
|
25
|
+
Seamless integration with user authentication to automatically manage payment profiles and user identification for payment operations.
|
|
26
|
+
|
|
27
|
+
### Local Caching
|
|
28
|
+
Payment profile information is cached locally using client auth resources to improve performance and user experience.
|
|
29
|
+
|
|
30
|
+
## API Reference
|
|
31
|
+
|
|
32
|
+
### Factory Functions
|
|
33
|
+
|
|
34
|
+
#### `makePaymentService(alias?): PaymentService`
|
|
35
|
+
|
|
36
|
+
Creates a client-side payment service with enhanced authentication capabilities.
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
import { makePaymentService } from '@owlmeans/client-payment'
|
|
40
|
+
|
|
41
|
+
const paymentService = makePaymentService('payments')
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Parameters:**
|
|
45
|
+
- `alias`: string (optional) - Service alias, defaults to `DEFAULT_ALIAS` from `@owlmeans/payment`
|
|
46
|
+
|
|
47
|
+
**Returns:** PaymentService instance with client-side enhancements
|
|
48
|
+
|
|
49
|
+
#### `appendPaymentService(context, alias?): Context`
|
|
50
|
+
|
|
51
|
+
Registers a payment service with a client context.
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import { appendPaymentService } from '@owlmeans/client-payment'
|
|
55
|
+
import { makeClientContext } from '@owlmeans/client-context'
|
|
56
|
+
|
|
57
|
+
const context = makeClientContext(config)
|
|
58
|
+
appendPaymentService(context, 'payments')
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**Parameters:**
|
|
62
|
+
- `context`: Client context instance
|
|
63
|
+
- `alias`: string (optional) - Service alias
|
|
64
|
+
|
|
65
|
+
**Returns:** Context with registered payment service
|
|
66
|
+
|
|
67
|
+
### Service Methods
|
|
68
|
+
|
|
69
|
+
The client payment service extends the base PaymentService with enhanced authentication:
|
|
70
|
+
|
|
71
|
+
#### `shallowAuthentication(token?): Promise<string>`
|
|
72
|
+
|
|
73
|
+
Performs lightweight authentication for payment operations with local caching.
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
const paymentService = context.service('payments')
|
|
77
|
+
|
|
78
|
+
// First call - authenticates and caches profile
|
|
79
|
+
const profileId = await paymentService.shallowAuthentication('auth-token')
|
|
80
|
+
|
|
81
|
+
// Subsequent calls - uses cached profile
|
|
82
|
+
const cachedProfileId = await paymentService.shallowAuthentication()
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Parameters:**
|
|
86
|
+
- `token`: string (optional) - Authentication token for initial authentication
|
|
87
|
+
|
|
88
|
+
**Returns:** Promise resolving to payment profile ID
|
|
89
|
+
|
|
90
|
+
**Behavior:**
|
|
91
|
+
- If `token` is provided: Authenticates using the token and caches the result
|
|
92
|
+
- If `token` is null: Attempts to use cached authentication data
|
|
93
|
+
- Throws `PaymentIdentificationError` if no cached data exists and no token provided
|
|
94
|
+
|
|
95
|
+
### Types
|
|
96
|
+
|
|
97
|
+
#### `PaymentService`
|
|
98
|
+
|
|
99
|
+
The payment service interface (re-exported from `@owlmeans/payment`).
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
export type { PaymentService } from '@owlmeans/payment'
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Constants
|
|
106
|
+
|
|
107
|
+
#### `DEFAULT_ALIAS`
|
|
108
|
+
|
|
109
|
+
Default alias for payment services (re-exported from `@owlmeans/payment`).
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
export { DEFAULT_ALIAS } from '@owlmeans/payment'
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
#### `SHALLOW_AUTH`
|
|
116
|
+
|
|
117
|
+
Local storage key for cached payment authentication data.
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
const SHALLOW_AUTH = 'payment:shallow-auth'
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Usage Examples
|
|
124
|
+
|
|
125
|
+
### Basic Payment Service Setup
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { makeClientContext, makeClientConfig } from '@owlmeans/client-context'
|
|
129
|
+
import { appendPaymentService } from '@owlmeans/client-payment'
|
|
130
|
+
import { AppType } from '@owlmeans/context'
|
|
131
|
+
|
|
132
|
+
// Create client context
|
|
133
|
+
const config = makeClientConfig(AppType.Frontend, 'ecommerce-app')
|
|
134
|
+
const context = makeClientContext(config)
|
|
135
|
+
|
|
136
|
+
// Add payment service
|
|
137
|
+
appendPaymentService(context, 'payments')
|
|
138
|
+
|
|
139
|
+
// Configure and initialize
|
|
140
|
+
context.configure()
|
|
141
|
+
await context.init()
|
|
142
|
+
|
|
143
|
+
// Use payment service
|
|
144
|
+
const paymentService = context.service('payments')
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Payment with Authentication
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
import { makePaymentService } from '@owlmeans/client-payment'
|
|
151
|
+
import { PaymentIdentificationError } from '@owlmeans/payment'
|
|
152
|
+
|
|
153
|
+
const paymentService = makePaymentService('payments')
|
|
154
|
+
|
|
155
|
+
try {
|
|
156
|
+
// First-time authentication
|
|
157
|
+
const profileId = await paymentService.shallowAuthentication(userAuthToken)
|
|
158
|
+
console.log('Payment profile:', profileId)
|
|
159
|
+
|
|
160
|
+
// Subsequent calls use cached data
|
|
161
|
+
const cachedProfileId = await paymentService.shallowAuthentication()
|
|
162
|
+
console.log('Cached profile:', cachedProfileId)
|
|
163
|
+
|
|
164
|
+
} catch (error) {
|
|
165
|
+
if (error instanceof PaymentIdentificationError) {
|
|
166
|
+
console.log('Payment identification failed:', error.message)
|
|
167
|
+
// Redirect to authentication
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### E-commerce Integration
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
import { appendPaymentService } from '@owlmeans/client-payment'
|
|
176
|
+
|
|
177
|
+
const setupEcommerceApp = async () => {
|
|
178
|
+
const context = makeClientContext(config)
|
|
179
|
+
|
|
180
|
+
// Register payment service
|
|
181
|
+
appendPaymentService(context, 'checkout')
|
|
182
|
+
|
|
183
|
+
await context.configure().init()
|
|
184
|
+
|
|
185
|
+
return context
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const processCheckout = async (context, items, userToken) => {
|
|
189
|
+
const paymentService = context.service('checkout')
|
|
190
|
+
|
|
191
|
+
try {
|
|
192
|
+
// Authenticate for payment
|
|
193
|
+
const profileId = await paymentService.shallowAuthentication(userToken)
|
|
194
|
+
|
|
195
|
+
// Process payment
|
|
196
|
+
const paymentRequest = {
|
|
197
|
+
profileId,
|
|
198
|
+
items,
|
|
199
|
+
total: items.reduce((sum, item) => sum + item.price, 0)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const result = await paymentService.processPayment(paymentRequest)
|
|
203
|
+
return result
|
|
204
|
+
|
|
205
|
+
} catch (error) {
|
|
206
|
+
console.error('Payment failed:', error)
|
|
207
|
+
throw error
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Subscription Service
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
import { makePaymentService } from '@owlmeans/client-payment'
|
|
216
|
+
|
|
217
|
+
const subscriptionService = makePaymentService('subscriptions')
|
|
218
|
+
|
|
219
|
+
const manageSubscription = async (userToken, subscriptionPlan) => {
|
|
220
|
+
try {
|
|
221
|
+
// Authenticate user for payment
|
|
222
|
+
const profileId = await subscriptionService.shallowAuthentication(userToken)
|
|
223
|
+
|
|
224
|
+
// Create subscription
|
|
225
|
+
const subscription = await subscriptionService.createSubscription({
|
|
226
|
+
profileId,
|
|
227
|
+
plan: subscriptionPlan,
|
|
228
|
+
recurring: true
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
console.log('Subscription created:', subscription.id)
|
|
232
|
+
return subscription
|
|
233
|
+
|
|
234
|
+
} catch (error) {
|
|
235
|
+
console.error('Subscription failed:', error)
|
|
236
|
+
throw error
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Later, manage existing subscription without re-authentication
|
|
241
|
+
const updateSubscription = async (subscriptionId, newPlan) => {
|
|
242
|
+
try {
|
|
243
|
+
// Use cached authentication
|
|
244
|
+
const profileId = await subscriptionService.shallowAuthentication()
|
|
245
|
+
|
|
246
|
+
const updated = await subscriptionService.updateSubscription(subscriptionId, {
|
|
247
|
+
plan: newPlan,
|
|
248
|
+
profileId
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
return updated
|
|
252
|
+
} catch (error) {
|
|
253
|
+
if (error instanceof PaymentIdentificationError) {
|
|
254
|
+
// Re-authentication required
|
|
255
|
+
console.log('Please re-authenticate for subscription changes')
|
|
256
|
+
}
|
|
257
|
+
throw error
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### Mobile App Integration
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
import { appendPaymentService } from '@owlmeans/client-payment'
|
|
266
|
+
|
|
267
|
+
const setupMobilePayments = async () => {
|
|
268
|
+
const context = makeClientContext(mobileConfig)
|
|
269
|
+
|
|
270
|
+
appendPaymentService(context, 'mobile-payments')
|
|
271
|
+
|
|
272
|
+
await context.configure().init()
|
|
273
|
+
|
|
274
|
+
const paymentService = context.service('mobile-payments')
|
|
275
|
+
|
|
276
|
+
// Setup payment handlers for mobile
|
|
277
|
+
const handlePurchase = async (productId, userToken) => {
|
|
278
|
+
try {
|
|
279
|
+
const profileId = await paymentService.shallowAuthentication(userToken)
|
|
280
|
+
|
|
281
|
+
const purchase = await paymentService.processMobilePurchase({
|
|
282
|
+
profileId,
|
|
283
|
+
productId,
|
|
284
|
+
platform: 'mobile'
|
|
285
|
+
})
|
|
286
|
+
|
|
287
|
+
// Handle successful purchase
|
|
288
|
+
await unlockPremiumFeatures(purchase)
|
|
289
|
+
|
|
290
|
+
} catch (error) {
|
|
291
|
+
// Handle payment error
|
|
292
|
+
showPaymentError(error)
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return handlePurchase
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Payment Status Tracking
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
import { makePaymentService } from '@owlmeans/client-payment'
|
|
304
|
+
|
|
305
|
+
const paymentService = makePaymentService('payment-tracker')
|
|
306
|
+
|
|
307
|
+
const trackPaymentStatus = async (paymentId, userToken) => {
|
|
308
|
+
try {
|
|
309
|
+
// Authenticate for payment tracking
|
|
310
|
+
const profileId = await paymentService.shallowAuthentication(userToken)
|
|
311
|
+
|
|
312
|
+
// Poll payment status
|
|
313
|
+
const checkStatus = async () => {
|
|
314
|
+
const status = await paymentService.getPaymentStatus(paymentId, profileId)
|
|
315
|
+
|
|
316
|
+
switch (status.state) {
|
|
317
|
+
case 'pending':
|
|
318
|
+
console.log('Payment is being processed...')
|
|
319
|
+
setTimeout(checkStatus, 5000) // Check again in 5 seconds
|
|
320
|
+
break
|
|
321
|
+
case 'completed':
|
|
322
|
+
console.log('Payment completed successfully!')
|
|
323
|
+
handlePaymentSuccess(status)
|
|
324
|
+
break
|
|
325
|
+
case 'failed':
|
|
326
|
+
console.log('Payment failed:', status.error)
|
|
327
|
+
handlePaymentFailure(status)
|
|
328
|
+
break
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
await checkStatus()
|
|
333
|
+
|
|
334
|
+
} catch (error) {
|
|
335
|
+
console.error('Payment tracking failed:', error)
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Error Handling
|
|
341
|
+
|
|
342
|
+
```typescript
|
|
343
|
+
import { PaymentIdentificationError } from '@owlmeans/payment'
|
|
344
|
+
import { makePaymentService } from '@owlmeans/client-payment'
|
|
345
|
+
|
|
346
|
+
const handlePaymentErrors = async (userToken, paymentData) => {
|
|
347
|
+
const paymentService = makePaymentService('error-handling')
|
|
348
|
+
|
|
349
|
+
try {
|
|
350
|
+
const profileId = await paymentService.shallowAuthentication(userToken)
|
|
351
|
+
const result = await paymentService.processPayment({ ...paymentData, profileId })
|
|
352
|
+
return result
|
|
353
|
+
|
|
354
|
+
} catch (error) {
|
|
355
|
+
if (error instanceof PaymentIdentificationError) {
|
|
356
|
+
// Authentication/identification specific error
|
|
357
|
+
switch (error.message) {
|
|
358
|
+
case 'record':
|
|
359
|
+
console.log('No cached payment profile found, please authenticate')
|
|
360
|
+
// Redirect to authentication flow
|
|
361
|
+
break
|
|
362
|
+
default:
|
|
363
|
+
console.log('Payment identification error:', error.message)
|
|
364
|
+
}
|
|
365
|
+
} else {
|
|
366
|
+
// Other payment errors
|
|
367
|
+
console.error('Payment processing error:', error)
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
throw error
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
## Integration Patterns
|
|
376
|
+
|
|
377
|
+
### With React Applications
|
|
378
|
+
|
|
379
|
+
```typescript
|
|
380
|
+
import React, { useContext, useEffect, useState } from 'react'
|
|
381
|
+
import { useContext as useOwlMeansContext } from '@owlmeans/client'
|
|
382
|
+
import { PaymentIdentificationError } from '@owlmeans/payment'
|
|
383
|
+
|
|
384
|
+
const PaymentProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
|
385
|
+
const context = useOwlMeansContext()
|
|
386
|
+
const [paymentService, setPaymentService] = useState(null)
|
|
387
|
+
|
|
388
|
+
useEffect(() => {
|
|
389
|
+
const service = context.service('payments')
|
|
390
|
+
setPaymentService(service)
|
|
391
|
+
}, [context])
|
|
392
|
+
|
|
393
|
+
return (
|
|
394
|
+
<PaymentContext.Provider value={paymentService}>
|
|
395
|
+
{children}
|
|
396
|
+
</PaymentContext.Provider>
|
|
397
|
+
)
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
const usePayment = () => {
|
|
401
|
+
const paymentService = useContext(PaymentContext)
|
|
402
|
+
const [isAuthenticated, setIsAuthenticated] = useState(false)
|
|
403
|
+
|
|
404
|
+
const authenticate = async (token: string) => {
|
|
405
|
+
try {
|
|
406
|
+
await paymentService.shallowAuthentication(token)
|
|
407
|
+
setIsAuthenticated(true)
|
|
408
|
+
} catch (error) {
|
|
409
|
+
setIsAuthenticated(false)
|
|
410
|
+
throw error
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
const processPayment = async (paymentData) => {
|
|
415
|
+
if (!isAuthenticated) {
|
|
416
|
+
throw new Error('Payment authentication required')
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
return await paymentService.processPayment(paymentData)
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
return { authenticate, processPayment, isAuthenticated }
|
|
423
|
+
}
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
### With State Management
|
|
427
|
+
|
|
428
|
+
```typescript
|
|
429
|
+
// Redux/Zustand store integration
|
|
430
|
+
const usePaymentStore = create((set, get) => ({
|
|
431
|
+
profileId: null,
|
|
432
|
+
isAuthenticated: false,
|
|
433
|
+
|
|
434
|
+
authenticate: async (token: string) => {
|
|
435
|
+
try {
|
|
436
|
+
const paymentService = get().paymentService
|
|
437
|
+
const profileId = await paymentService.shallowAuthentication(token)
|
|
438
|
+
|
|
439
|
+
set({ profileId, isAuthenticated: true })
|
|
440
|
+
return profileId
|
|
441
|
+
} catch (error) {
|
|
442
|
+
set({ profileId: null, isAuthenticated: false })
|
|
443
|
+
throw error
|
|
444
|
+
}
|
|
445
|
+
},
|
|
446
|
+
|
|
447
|
+
clearAuthentication: () => {
|
|
448
|
+
set({ profileId: null, isAuthenticated: false })
|
|
449
|
+
}
|
|
450
|
+
}))
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
## Security Considerations
|
|
454
|
+
|
|
455
|
+
### Authentication Management
|
|
456
|
+
- **Token Security** - Always handle authentication tokens securely
|
|
457
|
+
- **Profile Caching** - Cached payment profiles are stored locally and should be cleared on logout
|
|
458
|
+
- **Error Handling** - Properly handle authentication errors to prevent security leaks
|
|
459
|
+
|
|
460
|
+
### Payment Security
|
|
461
|
+
- **Shallow Authentication** - Provides lightweight authentication suitable for payment operations
|
|
462
|
+
- **Profile Validation** - Always validate payment profiles before processing payments
|
|
463
|
+
- **Error Messages** - Avoid exposing sensitive information in error messages
|
|
464
|
+
|
|
465
|
+
## Best Practices
|
|
466
|
+
|
|
467
|
+
1. **Handle authentication gracefully** - Always check for cached authentication before requiring re-authentication
|
|
468
|
+
2. **Clear cached data on logout** - Ensure payment profiles are cleared when users log out
|
|
469
|
+
3. **Implement proper error handling** - Handle `PaymentIdentificationError` specifically
|
|
470
|
+
4. **Use context registration** - Register payment services with application context for dependency injection
|
|
471
|
+
5. **Monitor payment status** - Implement proper payment status tracking and user feedback
|
|
472
|
+
|
|
473
|
+
## Error Handling
|
|
474
|
+
|
|
475
|
+
The package handles various error scenarios:
|
|
476
|
+
|
|
477
|
+
- **PaymentIdentificationError** - Thrown when payment profile identification fails
|
|
478
|
+
- **Authentication errors** - When cached authentication data is invalid or missing
|
|
479
|
+
- **Network errors** - When payment service communication fails
|
|
480
|
+
- **Context errors** - When service context is not properly configured
|
|
481
|
+
|
|
482
|
+
## Dependencies
|
|
483
|
+
|
|
484
|
+
This package depends on:
|
|
485
|
+
- `@owlmeans/payment` - Core payment functionality and types
|
|
486
|
+
- `@owlmeans/client-auth` - Client-side authentication resources
|
|
487
|
+
- `@owlmeans/context` - Context management and service registration
|
|
488
|
+
|
|
489
|
+
## Related Packages
|
|
490
|
+
|
|
491
|
+
- [`@owlmeans/payment`](../payment) - Core payment functionality
|
|
492
|
+
- [`@owlmeans/client-auth`](../client-auth) - Client-side authentication
|
|
493
|
+
- [`@owlmeans/client-context`](../client-context) - Client context management
|
package/build/.gitkeep
ADDED
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAEjD,eAAO,MAAM,YAAY,yBAAyB,CAAA"}
|
package/build/consts.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.js","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAEjD,MAAM,CAAC,MAAM,YAAY,GAAG,sBAAsB,CAAA"}
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,mBAAmB,YAAY,CAAA;AAC/B,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA"}
|
package/build/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { makePaymentService as makeService } from '@owlmeans/payment';
|
|
2
|
+
import type { appendPaymentService as appendService } from '@owlmeans/payment';
|
|
3
|
+
export declare const makePaymentService: typeof makeService;
|
|
4
|
+
export declare const appendPaymentService: typeof appendService;
|
|
5
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,IAAI,WAAW,EAA8B,MAAM,mBAAmB,CAAA;AACjG,OAAO,KAAK,EAAE,oBAAoB,IAAI,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAI9E,eAAO,MAAM,kBAAkB,EAAE,OAAO,WAwBvC,CAAA;AAED,eAAO,MAAM,oBAAoB,EAAE,OAAO,aACU,CAAA"}
|
package/build/service.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { AUTH_RESOURCE } from '@owlmeans/client-auth';
|
|
2
|
+
import { makePaymentService as makeService, PaymentIdentificationError } from '@owlmeans/payment';
|
|
3
|
+
import { assertContext } from '@owlmeans/context';
|
|
4
|
+
import { SHALLOW_AUTH } from './consts.js';
|
|
5
|
+
export const makePaymentService = alias => {
|
|
6
|
+
const service = makeService(alias);
|
|
7
|
+
const shallowAuthentication = service.shallowAuthentication;
|
|
8
|
+
service.shallowAuthentication = async (token) => {
|
|
9
|
+
const context = assertContext(service.ctx);
|
|
10
|
+
const authResource = context.resource(AUTH_RESOURCE);
|
|
11
|
+
if (token == null) {
|
|
12
|
+
const record = await authResource.load(SHALLOW_AUTH);
|
|
13
|
+
if (record == null || record.profileId == null) {
|
|
14
|
+
throw new PaymentIdentificationError('record');
|
|
15
|
+
}
|
|
16
|
+
return record.profileId;
|
|
17
|
+
}
|
|
18
|
+
const profileId = await shallowAuthentication(token);
|
|
19
|
+
await authResource.save({ id: SHALLOW_AUTH, profileId });
|
|
20
|
+
return profileId;
|
|
21
|
+
};
|
|
22
|
+
return service;
|
|
23
|
+
};
|
|
24
|
+
export const appendPaymentService = (context, alias) => context.registerService(makePaymentService(alias));
|
|
25
|
+
//# sourceMappingURL=service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACrD,OAAO,EAAE,kBAAkB,IAAI,WAAW,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAA;AAEjG,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE1C,MAAM,CAAC,MAAM,kBAAkB,GAAuB,KAAK,CAAC,EAAE;IAC5D,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,CAAC,CAAA;IAElC,MAAM,qBAAqB,GAAG,OAAO,CAAC,qBAAqB,CAAA;IAC3D,OAAO,CAAC,qBAAqB,GAAG,KAAK,EAAC,KAAK,EAAC,EAAE;QAC5C,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,CAAC,GAAG,CAAY,CAAA;QACrD,MAAM,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAqB,aAAa,CAAC,CAAA;QAExE,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;YAClB,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;YACpD,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM,CAAC,SAAS,IAAI,IAAI,EAAE,CAAC;gBAC/C,MAAM,IAAI,0BAA0B,CAAC,QAAQ,CAAC,CAAA;YAChD,CAAC;YAED,OAAO,MAAM,CAAC,SAAS,CAAA;QACzB,CAAC;QAED,MAAM,SAAS,GAAG,MAAM,qBAAqB,CAAC,KAAK,CAAC,CAAA;QACpD,MAAM,YAAY,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC,CAAA;QAExD,OAAO,SAAS,CAAA;IAClB,CAAC,CAAA;IAED,OAAO,OAAO,CAAA;AAChB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAyB,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAC3E,OAAO,CAAC,eAAe,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAA"}
|
package/build/types.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA"}
|
package/build/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@owlmeans/client-payment",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"build": "tsc -b",
|
|
7
|
+
"dev": "sleep 114 && nodemon -e ts,tsx,json --watch src --exec \"tsc -p ./tsconfig.json\"",
|
|
8
|
+
"watch": "tsc -b -w --preserveWatchOutput --pretty"
|
|
9
|
+
},
|
|
10
|
+
"main": "build/index.js",
|
|
11
|
+
"module": "build/index.js",
|
|
12
|
+
"types": "build/index.d.ts",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"import": "./build/index.js",
|
|
16
|
+
"require": "./build/index.js",
|
|
17
|
+
"default": "./build/index.js",
|
|
18
|
+
"module": "./build/index.js",
|
|
19
|
+
"types": "./build/index.d.ts"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@owlmeans/client-auth": "^0.1.0",
|
|
24
|
+
"@owlmeans/context": "^0.1.0",
|
|
25
|
+
"@owlmeans/payment": "^0.1.0"
|
|
26
|
+
},
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"react": "*"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/react": "^18.3.11",
|
|
32
|
+
"nodemon": "^3.1.7",
|
|
33
|
+
"typescript": "^5.6.3"
|
|
34
|
+
},
|
|
35
|
+
"private": false,
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
}
|
|
39
|
+
}
|
package/src/consts.ts
ADDED
package/src/index.ts
ADDED
package/src/service.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Context } from '@owlmeans/payment/utils'
|
|
2
|
+
import type { ClientAuthResource } from '@owlmeans/client-auth'
|
|
3
|
+
import { AUTH_RESOURCE } from '@owlmeans/client-auth'
|
|
4
|
+
import { makePaymentService as makeService, PaymentIdentificationError } from '@owlmeans/payment'
|
|
5
|
+
import type { appendPaymentService as appendService } from '@owlmeans/payment'
|
|
6
|
+
import { assertContext } from '@owlmeans/context'
|
|
7
|
+
import { SHALLOW_AUTH } from './consts.js'
|
|
8
|
+
|
|
9
|
+
export const makePaymentService: typeof makeService = alias => {
|
|
10
|
+
const service = makeService(alias)
|
|
11
|
+
|
|
12
|
+
const shallowAuthentication = service.shallowAuthentication
|
|
13
|
+
service.shallowAuthentication = async token => {
|
|
14
|
+
const context = assertContext(service.ctx) as Context
|
|
15
|
+
const authResource = context.resource<ClientAuthResource>(AUTH_RESOURCE)
|
|
16
|
+
|
|
17
|
+
if (token == null) {
|
|
18
|
+
const record = await authResource.load(SHALLOW_AUTH)
|
|
19
|
+
if (record == null || record.profileId == null) {
|
|
20
|
+
throw new PaymentIdentificationError('record')
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return record.profileId
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const profileId = await shallowAuthentication(token)
|
|
27
|
+
await authResource.save({ id: SHALLOW_AUTH, profileId })
|
|
28
|
+
|
|
29
|
+
return profileId
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return service
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const appendPaymentService: typeof appendService = (context, alias) =>
|
|
36
|
+
context.registerService(makePaymentService(alias))
|
package/src/types.ts
ADDED
package/tsconfig.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": [
|
|
3
|
+
"../tsconfig.default.json",
|
|
4
|
+
"../tsconfig.react.json",
|
|
5
|
+
],
|
|
6
|
+
"compilerOptions": {
|
|
7
|
+
"rootDir": "./src/", /* Specify the root folder within your source files. */
|
|
8
|
+
"outDir": "./build/", /* Specify an output folder for all emitted files. */
|
|
9
|
+
"moduleResolution": "Bundler"
|
|
10
|
+
},
|
|
11
|
+
"exclude": [
|
|
12
|
+
"./dist/**/*",
|
|
13
|
+
"./build/**/*",
|
|
14
|
+
"./*.ts"
|
|
15
|
+
]
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"root":["./src/consts.ts","./src/index.ts","./src/service.ts","./src/types.ts"],"version":"5.6.3"}
|