Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ jobs:
- name: Check if credentials are available
id: check-creds
run: |
if [ -z "${{ secrets.RAIACCEPT_TEST_USERNAME }}" ] || [ -z "${{ secrets.RAIACCEPT_TEST_PASSWORD }}" ]; then
if [ -z "${{ secrets.RAIACCEPT_TEST_USERNAME }}" ] || [ -z "${{ secrets.RAIACCEPT_TEST_PASSWORD }}" ] || [ -z "${{ secrets.RAIACCEPT_TEST_CERT_BASE64 }}" ] || [ -z "${{ secrets.RAIACCEPT_TEST_KEY_BASE64 }}" ]; then
echo "skip=true" >> $GITHUB_OUTPUT
echo "⚠️ Integration tests skipped: GitHub Secrets not configured"
echo "See .github/SETUP_CI.md for setup instructions"
Expand All @@ -69,4 +69,6 @@ jobs:
env:
RAIACCEPT_TEST_USERNAME: ${{ secrets.RAIACCEPT_TEST_USERNAME }}
RAIACCEPT_TEST_PASSWORD: ${{ secrets.RAIACCEPT_TEST_PASSWORD }}
RAIACCEPT_TEST_CERT_BASE64: ${{ secrets.RAIACCEPT_TEST_CERT_BASE64 }}
RAIACCEPT_TEST_KEY_BASE64: ${{ secrets.RAIACCEPT_TEST_KEY_BASE64 }}
run: npm run integration-tests
40 changes: 31 additions & 9 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,25 @@ npm install @smartbase-js/raiaccept-api-client
## Quick Start

```javascript
import { RaiAcceptAPIApi, RaiAcceptService, HttpClient } from '@smartbase-js/raiaccept-api-client';
import { RaiAcceptService, HttpClient } from '@smartbase-js/raiaccept-api-client';

// Initialize client
const httpClient = new HttpClient();
const apiClient = new RaiAcceptAPIApi(httpClient);
const service = new RaiAcceptService(httpClient, cert, key);

// Authenticate
const accessToken = await RaiAcceptService.retrieveAccessTokenWithCredentials(
apiClient,
const authResult = await service.retrieveAccessTokenWithCredentials(
'username',
'password'
);
const accessToken = authResult?.accessToken;

// Step 1: Create order entry
const orderResponse = await apiClient.createOrderEntry(accessToken, orderRequest);
const orderResponse = await service.createOrderEntry(accessToken, orderRequest);
const orderIdentification = orderResponse.object.getOrderIdentification();

// Step 2: Create payment session for the order
const paymentSessionResponse = await apiClient.createPaymentSession(
const paymentSessionResponse = await service.createPaymentSession(
accessToken,
orderRequest,
orderIdentification
Expand All @@ -54,11 +54,13 @@ Main API client for interacting with RaiAccept services.
#### Constructor

```javascript
const apiClient = new RaiAcceptAPIApi(httpClient);
const apiClient = new RaiAcceptAPIApi(httpClient, cert, key);
```

**Parameters:**
- `httpClient` (HttpClient): HTTP client instance for making requests
- `cert` (string | Buffer): Client certificate for mTLS
- `key` (string | Buffer): Client private key for mTLS

#### Methods

Expand All @@ -70,12 +72,32 @@ Authenticate with username and password.
- `username` (string): Username
- `password` (string): Password

**Returns:** `Promise<Object>` - Authentication response with access token
**Returns:** `Promise<ApiResponse<AuthApiLoginOutput>>` - Authentication response with access token, refresh token, and expiration times

**Example:**
```javascript
const response = await apiClient.token('username', 'password');
const accessToken = response.object.getIdToken();
const authResult = response.object;
const accessToken = authResult?.accessToken;
const refreshToken = authResult?.refreshToken;
const accessTokenExpiresIn = authResult?.accessTokenExpiresIn;
const refreshTokenExpiresIn = authResult?.refreshTokenExpiresIn;
```

---

##### `tokenLogout(token)`

Logout with refresh token. Uses AUTH_URL; cert and key not required.

**Parameters:**
- `token` (string): Refresh token to logout

**Returns:** `Promise<boolean>` - True if logout successful (HTTP 200), false otherwise

**Example:**
```javascript
const success = await apiClient.tokenLogout(refreshToken);
```

---
Expand Down
14 changes: 11 additions & 3 deletions GETTING_STARTED.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,22 @@ const client = new RaiAcceptService(httpClient);
### 3. Authenticate

```javascript
const accessToken = await client.retrieveAccessTokenWithCredentials(
const authResult = await client.retrieveAccessTokenWithCredentials(
'your-username',
'your-password'
'your-password',
cert, // Client certificate for mTLS
key // Client private key for mTLS
);

if (!accessToken) {
if (!authResult) {
throw new Error('Authentication failed');
}

const accessToken = authResult.accessToken;
// You can also access:
// - authResult.accessTokenExpiresIn
// - authResult.refreshToken
// - authResult.refreshTokenExpiresIn
```

### 4. Create Your First Payment
Expand Down
22 changes: 16 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,13 @@ import { RaiAcceptService } from '@smartbase-js/raiaccept-api-client';
const service = new RaiAcceptService();

// Authenticate with your credentials
const accessToken = await service.retrieveAccessTokenWithCredentials(
const authResult = await service.retrieveAccessTokenWithCredentials(
'your-username', // Replace with your actual username
'your-password' // Replace with your actual password
'your-password', // Replace with your actual password
cert, // Client certificate for mTLS
key // Client private key for mTLS
);
const accessToken = authResult?.accessToken;

const response = await service.createOrderEntry(accessToken, orderRequest);
```
Expand All @@ -44,10 +47,13 @@ const httpClient = new HttpClient({
const service = new RaiAcceptService(httpClient);

// Authenticate
const accessToken = await service.retrieveAccessTokenWithCredentials(
const authResult = await service.retrieveAccessTokenWithCredentials(
'your-username',
'your-password'
'your-password',
cert, // Client certificate for mTLS
key // Client private key for mTLS
);
const accessToken = authResult?.accessToken;

// Create an order and payment session (two-step process)
const orderRequest = {
Expand Down Expand Up @@ -114,10 +120,14 @@ const client = new RaiAcceptService();
### Authentication

```typescript
const accessToken = await client.retrieveAccessTokenWithCredentials(
const authResult = await client.retrieveAccessTokenWithCredentials(
username,
password
password,
cert, // Client certificate for mTLS
key // Client private key for mTLS
);
const accessToken = authResult?.accessToken;
// Also available: authResult.refreshToken, authResult.accessTokenExpiresIn, authResult.refreshTokenExpiresIn
```

### Order Operations
Expand Down
29 changes: 20 additions & 9 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,13 @@ npm install

2. Update credentials in the examples:
```javascript
const accessToken = await RaiAcceptService.retrieveAccessTokenWithCredentials(
apiClient,
const authResult = await service.retrieveAccessTokenWithCredentials(
'your-username', // <- Replace with your credentials
'your-password' // <- Replace with your credentials
'your-password', // <- Replace with your credentials
cert, // <- Client certificate for mTLS
key // <- Client private key for mTLS
);
const accessToken = authResult?.accessToken;
```

3. Run the examples:
Expand All @@ -67,10 +69,13 @@ const app = express();
app.post('/api/create-payment', async (req, res) => {
// Create service and authenticate
const service = new RaiAcceptService();
const accessToken = await service.retrieveAccessTokenWithCredentials(
const authResult = await service.retrieveAccessTokenWithCredentials(
'your-username', // Replace with your actual credentials
'your-password' // Replace with your actual credentials
'your-password', // Replace with your actual credentials
cert, // Client certificate for mTLS
key // Client private key for mTLS
);
const accessToken = authResult?.accessToken;

// Step 1: Create order entry
const orderResponse = await service.createOrderEntry(accessToken, req.body);
Expand Down Expand Up @@ -99,10 +104,13 @@ import { RaiAcceptService } from '@smartbase-js/raiaccept-api-client';
export async function createPayment(orderData) {
// Create service and authenticate
const service = new RaiAcceptService();
const accessToken = await service.retrieveAccessTokenWithCredentials(
const authResult = await service.retrieveAccessTokenWithCredentials(
'your-username', // Replace with your actual credentials
'your-password' // Replace with your actual credentials
'your-password', // Replace with your actual credentials
cert, // Client certificate for mTLS
key // Client private key for mTLS
);
const accessToken = authResult?.accessToken;

// Step 1: Create order entry
const orderResponse = await service.createOrderEntry(accessToken, orderData);
Expand Down Expand Up @@ -131,10 +139,13 @@ import { RaiAcceptService } from '@smartbase-js/raiaccept-api-client';
export const handler = async (event) => {
// Create service and authenticate
const service = new RaiAcceptService();
const accessToken = await service.retrieveAccessTokenWithCredentials(
const authResult = await service.retrieveAccessTokenWithCredentials(
'your-username', // Replace with your actual credentials
'your-password' // Replace with your actual credentials
'your-password', // Replace with your actual credentials
cert, // Client certificate for mTLS
key // Client private key for mTLS
);
const accessToken = authResult?.accessToken;

const orderData = JSON.parse(event.body);

Expand Down
11 changes: 8 additions & 3 deletions examples/basic-usage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,20 @@ async function main(): Promise<void> {
try {
console.log('Creating service and authenticating...');

// Create service instance
const client = new RaiAcceptService();
// Load mTLS cert and key (from env, files, or secure storage)
const cert = process.env.RAIACCEPT_CERT || ''; // Replace with your cert
const key = process.env.RAIACCEPT_KEY || ''; // Replace with your key

// Create service instance with cert and key
const client = new RaiAcceptService(null, cert, key);

// Authenticate with your credentials
const accessToken = await client.retrieveAccessTokenWithCredentials(
const authResult = await client.retrieveAccessTokenWithCredentials(
'your-username', // Replace with your actual username
'your-password' // Replace with your actual password
);

const accessToken = authResult?.accessToken;
if (!accessToken) {
throw new Error('Authentication failed');
}
Expand Down
15 changes: 8 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 37 additions & 1 deletion src/HttpClient.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';
import https from 'https';

export interface Logger {
log(message: string, data?: any): void;
Expand All @@ -15,6 +16,8 @@ export interface HttpRequest {
url: string;
headers?: Record<string, string>;
body?: string;
cert?: string | Buffer;
key?: string | Buffer;
}

export interface HttpResponse {
Expand Down Expand Up @@ -51,6 +54,15 @@ export class HttpClient {
validateStatus: () => true, // Don't throw on any status
};

// Add mTLS certificate and key
if (request.cert && request.key) {
const httpsAgent = new https.Agent({
cert: request.cert,
key: request.key,
});
axiosConfig.httpsAgent = httpsAgent;
}

if (this.logger && !omitLogging) {
this.logger.log('Request:', this._sanitizeForLog(request));
}
Expand Down Expand Up @@ -79,19 +91,43 @@ export class HttpClient {
}
}

private static readonly SENSITIVE_BODY_KEYS = ['cert', 'key', 'username', 'password'];

/**
* Sanitize request for logging (hide sensitive headers)
* Sanitize request for logging (hide sensitive headers and body fields)
* @param request - Request object
* @returns Sanitized request
*/
private _sanitizeForLog(request: HttpRequest): HttpRequest {
const sanitized: HttpRequest = { ...request };

// Hide sensitive headers
if (sanitized.headers) {
sanitized.headers = { ...sanitized.headers };
if (sanitized.headers.Authorization) {
sanitized.headers.Authorization = 'HIDDEN';
}
}

// Hide cert and key
if (sanitized.cert) sanitized.cert = 'HIDDEN';
if (sanitized.key) sanitized.key = 'HIDDEN';

// Hide sensitive fields in request body (username, password, cert, key)
if (sanitized.body) {
try {
const parsed = JSON.parse(sanitized.body);
if (typeof parsed === 'object' && parsed !== null) {
for (const key of HttpClient.SENSITIVE_BODY_KEYS) {
if (key in parsed) parsed[key] = 'HIDDEN';
}
sanitized.body = JSON.stringify(parsed);
}
} catch {
// Not JSON, leave body as-is
}
}

return sanitized;
}
}
Loading