From c54091917eab81eb9ae38b2039cb76fcbba879c4 Mon Sep 17 00:00:00 2001 From: R3D347HR4Y Date: Sun, 1 Jun 2025 00:26:35 +0200 Subject: [PATCH] Added all --- README.md | 53 +++++++++++- package.json | 47 +++++++++++ src/client.ts | 48 +++++++++++ src/index.ts | 122 +++++++++++++++++++++++++++ src/types.ts | 223 ++++++++++++++++++++++++++++++++++++++++++++++++++ tsconfig.json | 17 ++++ 6 files changed, 508 insertions(+), 2 deletions(-) create mode 100644 package.json create mode 100644 src/client.ts create mode 100644 src/index.ts create mode 100644 src/types.ts create mode 100644 tsconfig.json diff --git a/README.md b/README.md index 9dc1074..6e7c837 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,52 @@ -# PayForPress-Server-SDK +# PayForPress Node.js SDK -Official Server side SDK for PayForPress \ No newline at end of file +Official Node.js SDK for PayForPress API - An onboarding, paywall and payment solution for online media. + +## Installation + +```bash +npm install payforpress-node-sdk +``` + +## Quick Start + +```typescript +import { PayForPress } from 'payforpress-node-sdk'; + +// Initialize the SDK with your API key +const pfp = new PayForPress({ + apiKey: 'your-api-key-here' +}); + +// Example: Get user information +async function getUser() { + try { + const user = await pfp.users.get({ email: 'user@example.com' }); + console.log('User:', user); + } catch (error) { + console.error('Error:', error); + } +} +``` + +## Features + +- User Management +- Article Management +- Payment Processing +- Analytics +- Appearance Settings +- Targeting Rules +- Organization Settings + +## API Documentation + +For detailed API documentation, please visit our [API Documentation](https://payforpress.gitbook.io/payforpress/api-pfp-connect/api-pfp-connect). + +## Security + +This SDK is designed to be used on the server-side only. Never expose your API key in client-side code. + +## License + +MIT diff --git a/package.json b/package.json new file mode 100644 index 0000000..01dccb1 --- /dev/null +++ b/package.json @@ -0,0 +1,47 @@ +{ + "name": "payforpress-node-sdk", + "version": "1.0.0", + "description": "Official Node.js Server SDK for PayForPress API - An onboarding, paywall and payment solution for online media", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "build": "tsc", + "test": "jest", + "lint": "eslint src/**/*.ts", + "format": "prettier --write \"src/**/*.ts\"", + "prepare": "npm run build" + }, + "keywords": [ + "payforpress", + "paywall", + "onboarding", + "payment", + "micropayment", + "applepay", + "googlepay", + "paypal", + "stripe", + "media", + "api", + "sdk" + ], + "author": "PayForPress", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://gitea.reduav.eu/PayForPress/PayForPress-Server-SDK" + }, + "dependencies": { + "axios": "^1.6.7" + }, + "devDependencies": { + "@types/node": "^20.11.19", + "@typescript-eslint/eslint-plugin": "^7.0.1", + "@typescript-eslint/parser": "^7.0.1", + "eslint": "^8.56.0", + "jest": "^29.7.0", + "prettier": "^3.2.5", + "ts-jest": "^29.1.2", + "typescript": "^5.3.3" + } +} diff --git a/src/client.ts b/src/client.ts new file mode 100644 index 0000000..d275fa2 --- /dev/null +++ b/src/client.ts @@ -0,0 +1,48 @@ +import axios, { AxiosInstance, AxiosRequestConfig } from 'axios'; +import { PayForPressConfig, Error } from './types'; + +export class PayForPressClient { + private client: AxiosInstance; + private config: PayForPressConfig; + + constructor(config: PayForPressConfig) { + this.config = config; + this.client = axios.create({ + baseURL: config.baseUrl || 'https://payfor.press/api/v3', + headers: { + 'pfp-api-key': config.apiKey, + 'Content-Type': 'application/json' + } + }); + + // Add response interceptor for error handling + this.client.interceptors.response.use( + (response) => response.data, + (error) => { + if (error.response) { + throw error.response.data; + } + throw { + success: false, + message: error.message || 'An unexpected error occurred' + } as Error; + } + ); + } + + protected async post(endpoint: string, data?: any, config?: AxiosRequestConfig): Promise { + return this.client.post(endpoint, data, config); + } + + protected async get(endpoint: string, params?: any, config?: AxiosRequestConfig): Promise { + return this.client.get(endpoint, { ...config, params }); + } + + protected async put(endpoint: string, data?: any, config?: AxiosRequestConfig): Promise { + return this.client.put(endpoint, data, config); + } + + protected async delete(endpoint: string, config?: AxiosRequestConfig): Promise { + return this.client.delete(endpoint, config); + } +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..a7843c6 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,122 @@ +import { + PayForPressConfig, + UserResponse, + UserUpdate, + SearchParams, + ArticleResponse, + ArticlesResponse, + ArticleFilters, + AppearanceSchema, + TargetingSchema, + SettingsResponse, + OrganizationDetails, + PaymentResponse, + PaymentCreateParams, + PaymentSearchParams, + PaymentsResponse, + Article +} from './types'; +import { PayForPressClient } from './client'; + +export class PayForPress extends PayForPressClient { + constructor(config: PayForPressConfig) { + super(config); + } + + // User Management + async getUser(params: { email?: string; id?: string }): Promise { + return this.post('/users/get', params); + } + + async createUser(user: UserUpdate): Promise { + return this.post('/users/create', user); + } + + async updateUser(id: string, user: UserUpdate): Promise { + return this.post('/users/update', { id, newProps: user }); + } + + async deleteUser(id: string): Promise<{ success: boolean; message: string }> { + return this.post('/users/delete', { id }); + } + + async searchUsers( + params: SearchParams + ): Promise<{ success: boolean; users: any[]; total: number }> { + return this.post('/users/search', params); + } + + // Article Management + async getArticle( + params: { id?: string; url?: string } | ArticleFilters + ): Promise { + return this.post('/articles/get', params); + } + + async createArticle(url: string): Promise { + return this.post('/articles/create', { url }); + } + + async updateArticle(id: string, article: Partial
): Promise { + return this.post('/articles/update', { id, ...article }); + } + + async deleteArticle(id: string): Promise<{ success: boolean }> { + return this.post('/articles/delete', { id }); + } + + // Appearance Settings + async getAppearance(): Promise<{ success: boolean; appearance: AppearanceSchema }> { + return this.post('/appearance/get'); + } + + async updateAppearance( + appearance: AppearanceSchema + ): Promise<{ success: boolean; appearance: AppearanceSchema }> { + return this.post('/appearance/update', appearance); + } + + // Targeting Settings + async getTargeting(): Promise<{ targeting: TargetingSchema }> { + return this.post('/targeting/get'); + } + + async updateTargeting( + targeting: TargetingSchema + ): Promise<{ message: string; targeting: TargetingSchema }> { + return this.post('/targeting/update', { targeting }); + } + + // Organization Settings + async getSettings(): Promise { + return this.post('/settings/get'); + } + + async updateSettings(settings: OrganizationDetails): Promise { + return this.post('/settings/update', settings); + } + + // Payment Management + async createPayment(params: PaymentCreateParams): Promise { + return this.post('/payments/create', params); + } + + async getPayment(id: string): Promise { + return this.post('/payments/get', { id }); + } + + async searchPayments(params: PaymentSearchParams): Promise { + return this.post('/payments/search', params); + } + + // Analytics + async getAnalytics(params: { + type: 'get' | 'search'; + startDate?: string; + endDate?: string; + }): Promise<{ success: boolean; data: any }> { + return this.post('/analytics', params); + } +} + +export * from './types'; diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..c56e88a --- /dev/null +++ b/src/types.ts @@ -0,0 +1,223 @@ +export interface PayForPressConfig { + apiKey: string; + baseUrl?: string; +} + +export interface Error { + success: boolean; + message: string; +} + +export interface User { + email: string; + phone?: string; + id: string; + metadata?: Record; +} + +export interface UserUpdate { + email?: string; + phone?: string; + name?: string; + metadata?: Record; +} + +export interface UserResponse { + success: boolean; + user: User; + message?: string; +} + +export interface SearchParams { + skip?: number; + limit?: number; + value?: string; + field?: string; + operator?: '==' | '!=' | '>' | '<' | '>=' | '<=' | '~' | '!~'; + order?: 'asc' | 'desc'; +} + +export interface Article { + id: string; + url: string; + title?: string; + author_name?: string; + price?: number; + high_value?: boolean; + org?: string; + created_at?: string; + updated_at?: string; +} + +export interface ArticleResponse { + success: boolean; + article: Article; + message?: string; +} + +export interface ArticlesResponse { + success: boolean; + articles: Article[]; + message?: string; +} + +export interface ArticleFilters { + skip?: number; + limit?: number; + search?: string; + sort?: 'created_at' | 'updated_at' | 'title' | 'price'; + order?: 'asc' | 'desc'; +} + +export interface AppearanceSchema { + primaryColor?: string; + theme?: 'dark' | 'light' | 'system'; + large?: boolean; + borderRadius?: number; + margin?: number; + horizontalAlignment?: 'left' | 'center' | 'right'; + verticalAlignment?: 'top' | 'center' | 'bottom'; + inject?: boolean; + injectSelector?: string; + injectStyle?: string; + prepend?: boolean; + injectDelay?: number; + backgroundColor?: string; + paywallMode?: boolean; + deleteSelector?: string; +} + +export interface GraphNode { + variable: + | 'time' + | 'device' + | 'url' + | 'referrer' + | 'country' + | 'browser' + | 'loggedIn' + | 'firstTimeSessions' + | 'recurringLoadOfArticle' + | 'visitedUrls' + | 'highValue' + | 'elementPresent' + | 'alreadyPayforPress' + | 'mobileConnection' + | 'isp' + | 'proxy' + | 'hosting' + | 'continent'; + matchingType: + | '=' + | 'startsWith' + | 'endsWith' + | 'contains' + | 'notContains' + | '!=' + | 'in' + | 'notIn' + | '>' + | '<' + | '>=' + | '<=' + | 'between' + | 'notBetween' + | 'selectorMatches' + | 'selectorNotMatches' + | 'regex'; + value: + | string + | number + | boolean + | string[] + | { + hourStart: number; + minuteStart: number; + hourEnd: number; + minuteEnd: number; + }; + true: 'showPayForPress' | 'hidePayForPress' | 'excludeUser' | 'default' | 'addCondition'; + false: 'showPayForPress' | 'hidePayForPress' | 'excludeUser' | 'default' | 'addCondition'; + trueNode?: GraphNode; + falseNode?: GraphNode; +} + +export interface TargetingVariable { + key: string; + keep?: boolean; + type?: 'string' | 'number' | 'boolean' | 'array'; + value: any; + id?: string; +} + +export interface TargetingSchema { + showForAll?: boolean; + defaultShow?: boolean; + variables?: TargetingVariable[]; + graph?: GraphNode[]; +} + +export interface OrganizationDetails { + allowBuyArticle?: boolean; + allowHighValueArticlesInPass?: boolean; + allowHighValueArticlesInSubscription?: boolean; + allowMonthlyPass?: boolean; + allowSubscription?: boolean; + allowTimePass?: boolean; + blockAds?: boolean; + discountAfterOne?: number; + icon?: string; + keepOriginalNavBar?: boolean; + logoUrl?: string; + monthlyPassPrice?: number; + onboardingStep?: string; + postPayment?: boolean; + priceForHighValueArticles?: number; + pricePerArticle?: number; + removeSelectors?: string; + subscriptionPrice?: number; + timePassLength?: string; + timePassPrice?: number; +} + +export interface SettingsResponse { + details: OrganizationDetails; +} + +export interface Payment { + id: string; + amountCents: number; + article?: string; + buyer: string; + expires_at: string; + renews: boolean; + transaction_date: string; + type: 'article' | 'pass' | 'subscription'; +} + +export interface PaymentResponse { + success: boolean; + purchase: Payment; +} + +export interface PaymentsResponse { + success: boolean; + purchases: Payment[]; +} + +export interface PaymentCreateParams { + user_id: string; + purchase_type: 'article' | 'pass' | 'subscription'; + amountCents: number; + currency?: 'eur'; + expires_at: string; +} + +export interface PaymentSearchParams { + user_id?: string; + type?: 'article' | 'pass' | 'subscription'; + before?: string; + after?: string; + limit?: number; + skip?: number; +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..85dbb4b --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "es2020", + "module": "commonjs", + "declaration": true, + "outDir": "./dist", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "**/*.test.ts"] +}