supaapps-api-kit-client 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.
@@ -0,0 +1,30 @@
1
+ name: Build
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - '**'
7
+ pull_request:
8
+ branches:
9
+ - '**'
10
+
11
+ jobs:
12
+ build:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - name: Checkout code
16
+ uses: actions/checkout@v2
17
+
18
+ - name: Use Node.js
19
+ uses: actions/setup-node@v3
20
+ with:
21
+ node-version: lts/*
22
+ registry-url: 'https://registry.npmjs.org'
23
+
24
+ - name: Install dependencies
25
+ run: npm install
26
+
27
+ - name: Build
28
+ run: npm run build
29
+ env:
30
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -0,0 +1,30 @@
1
+ name: Publish to NPM
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ jobs:
9
+ build:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - name: Checkout code
13
+ uses: actions/checkout@v2
14
+
15
+ - name: Use Node.js
16
+ uses: actions/setup-node@v3
17
+ with:
18
+ node-version: lts/*
19
+ registry-url: 'https://registry.npmjs.org'
20
+
21
+ - name: Install dependencies
22
+ run: npm install
23
+
24
+ - name: Build
25
+ run: npm run build
26
+
27
+ - name: Publish to npm
28
+ run: npm publish
29
+ env:
30
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
package/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ MIT License
2
+
3
+ Notice: While this software is open-source under the MIT License, the "Supaapps" name, branding, and logo are proprietary and copyrighted by Supaapps GmbH. Any use, reproduction, or distribution of the "Supaapps" brand assets without explicit permission is strictly prohibited.
4
+
5
+ Copyright (c) 2024 Supaapps GmbH
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in all
15
+ copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,127 @@
1
+ # supaapps-api-kit-client
2
+
3
+ A versatile, type-safe API client designed for TypeScript applications. It simplifies making HTTP requests and handling responses with built-in support for authorization and automatic handling of unauthorized access scenarios.
4
+
5
+ ## Features
6
+
7
+ - **Type Safety**: Leverages TypeScript for ensuring type safety in requests and responses.
8
+ - **Authorization Support**: Automatically includes authorization tokens in requests.
9
+ - **Customizable Unauthorized Access Handling**: Executes a callback function when encountering a 401 Unauthorized response, allowing for custom reaction strategies such as redirecting to a login page.
10
+ - **Simplified API Requests**: Offers methods for common HTTP requests (`GET`, `POST`, `PUT`, `PATCH`, `DELETE`) with a straightforward, promise-based API.
11
+
12
+ ## Installation
13
+
14
+ Install the package using npm:
15
+
16
+ ```bash
17
+ npm install supaapps-api-kit-client
18
+ # or
19
+ yarn add supaapps-api-kit-client
20
+ ```
21
+
22
+ ## Setup
23
+
24
+ Before making any requests, initialize the `ApiKitClient` with your API's base URL, an authorization token, and a callback function for handling unauthorized access.
25
+
26
+
27
+ ```ts
28
+ import { ApiKitClient } from 'supaapps-api-kit-client';
29
+
30
+ const BASE_URL = 'https://api.example.com'
31
+
32
+ const authTokenCallback = () => {
33
+ // Implement authToken logic here
34
+ };
35
+
36
+ const unauthorizationCallback = () => {
37
+ // Implement redirection to login page here
38
+ };
39
+
40
+ ApiKitClient.initialize(BASE_URL, authTokenCallback, unauthorizationCallback);
41
+ ```
42
+
43
+ ## Making Requests
44
+
45
+ Use the `ApiKitClient` instance to make API requests. Here are some examples:
46
+
47
+ ### Fetching Data
48
+
49
+ Fetch a list of resources:
50
+
51
+ ```ts
52
+ interface User {
53
+ id: number;
54
+ name: string;
55
+ email: string;
56
+ }
57
+
58
+ ApiKitClient.get<User[]>('/users')
59
+ .then(response => console.log(response.data)) // Expected to be of type User[]
60
+ .catch(error => console.error(error));
61
+ ```
62
+
63
+ Fetch a single resource:
64
+
65
+ ```ts
66
+ ApiKitClient.getOne<User>('/users/1')
67
+ .then(response => console.log(response.data)) // Expected to be of type User
68
+ .catch(error => console.error(error));
69
+ ```
70
+
71
+ Fetch a paginated resource:
72
+
73
+ ```ts
74
+ ApiKitClient.getPaginated<User>('/users')
75
+ .then(response => console.log(response)) // Expected to be of type PaginatedResponse<User>
76
+ .catch(error => console.error(error));
77
+ ```
78
+
79
+ ### Creating Data
80
+
81
+ ```ts
82
+ // Create a new user
83
+ const newUser: User = {
84
+ id: 1,
85
+ name: 'John Doe',
86
+ email: 'john@example.com',
87
+ };
88
+
89
+ ApiKitClient.post<User>('/users', newUser)
90
+ .then(response => console.log(response.data)) // Expected to be of type User
91
+ .catch(error => console.error(error));
92
+ ```
93
+
94
+ ### Updating Data
95
+
96
+ ```ts
97
+ // Update a user's information
98
+ const updatedUser: User = {
99
+ id: 1,
100
+ name: 'Jane Doe',
101
+ email: 'jane@example.com',
102
+ };
103
+
104
+ const updatedUser2: User = {
105
+ name: 'Jane Doe',
106
+ };
107
+
108
+ ApiKitClient.put<User>('/users/1', updatedUser)
109
+ .then(response => console.log(response.data)) // Expected to be of type User
110
+ .catch(error => console.error(error));
111
+
112
+ ApiKitClient.patch<User>('/users/1', updatedUser2)
113
+ .then(response => console.log(response.data)) // Expected to be of type User
114
+ .catch(error => console.error(error));
115
+ ```
116
+
117
+ ### Deleting Data
118
+
119
+ ```ts
120
+ // Delete a user
121
+ ApiKitClient.delete('/users/1')
122
+ .then(() => console.log('User deleted'))
123
+ .catch(error => console.error(error));
124
+ ```
125
+
126
+ ## Handling Unauthorized Access
127
+ The unauthorized access callback provided during initialization will be called automatically for any request that receives a 401 Unauthorized response, allowing you to handle such scenarios globally (e.g., redirecting the user to a login page).
@@ -0,0 +1,20 @@
1
+ import { AxiosResponse } from 'axios';
2
+ import { PaginatedResponse } from './types';
3
+ type UnauthorizationCallback = () => void;
4
+ type AuthTokenCallback = () => Promise<string>;
5
+ export declare class ApiKitClient {
6
+ private static instance;
7
+ private static authTokenCallback;
8
+ private static unauthorizationCallback;
9
+ static initialize(baseURL: string, authTokenCallback: AuthTokenCallback, unauthorizationCallback?: UnauthorizationCallback): void;
10
+ private static setupInterceptors;
11
+ private static checkInitialization;
12
+ static get<T>(endpoint: string, params?: URLSearchParams): Promise<AxiosResponse<T>>;
13
+ static getOne<T>(endpoint: string, params?: URLSearchParams): Promise<AxiosResponse<T>>;
14
+ static getPaginated<T>(endpoint: string, params?: URLSearchParams): Promise<AxiosResponse<PaginatedResponse<T>>>;
15
+ static post<T>(endpoint: string, data: T): Promise<AxiosResponse<T>>;
16
+ static put<T>(endpoint: string, data: T): Promise<AxiosResponse<T>>;
17
+ static patch<T>(endpoint: string, data: T): Promise<AxiosResponse<T>>;
18
+ static delete<T>(endpoint: string): Promise<AxiosResponse<T>>;
19
+ }
20
+ export {};
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.ApiKitClient = void 0;
13
+ const axios_1 = require("axios");
14
+ class ApiKitClient {
15
+ static initialize(baseURL, authTokenCallback, unauthorizationCallback) {
16
+ this.authTokenCallback = authTokenCallback;
17
+ this.unauthorizationCallback = unauthorizationCallback;
18
+ this.instance = axios_1.default.create({ baseURL });
19
+ this.setupInterceptors();
20
+ }
21
+ static setupInterceptors() {
22
+ this.instance.interceptors.request.use((config) => __awaiter(this, void 0, void 0, function* () {
23
+ if (this.authTokenCallback) {
24
+ const authToken = yield this.authTokenCallback();
25
+ config.headers.Authorization = `Bearer ${authToken}`;
26
+ }
27
+ return config;
28
+ }));
29
+ this.instance.interceptors.response.use((response) => response, (error) => {
30
+ var _a;
31
+ if (((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 401 && this.unauthorizationCallback) {
32
+ this.unauthorizationCallback();
33
+ }
34
+ return Promise.reject(error);
35
+ });
36
+ }
37
+ static checkInitialization() {
38
+ if (!this.instance) {
39
+ throw new Error("ApiKitClient has not been initialized. Please call ApiKitClient.initialize() before making requests.");
40
+ }
41
+ }
42
+ static get(endpoint, params) {
43
+ return __awaiter(this, void 0, void 0, function* () {
44
+ this.checkInitialization();
45
+ return this.instance.get(endpoint, { params });
46
+ });
47
+ }
48
+ static getOne(endpoint, params) {
49
+ return __awaiter(this, void 0, void 0, function* () {
50
+ this.checkInitialization();
51
+ return this.instance.get(endpoint, { params });
52
+ });
53
+ }
54
+ static getPaginated(endpoint, params) {
55
+ return __awaiter(this, void 0, void 0, function* () {
56
+ this.checkInitialization();
57
+ return this.instance.get(endpoint, { params });
58
+ });
59
+ }
60
+ static post(endpoint, data) {
61
+ return __awaiter(this, void 0, void 0, function* () {
62
+ this.checkInitialization();
63
+ return this.instance.post(endpoint, data);
64
+ });
65
+ }
66
+ static put(endpoint, data) {
67
+ return __awaiter(this, void 0, void 0, function* () {
68
+ this.checkInitialization();
69
+ return this.instance.put(endpoint, data);
70
+ });
71
+ }
72
+ static patch(endpoint, data) {
73
+ return __awaiter(this, void 0, void 0, function* () {
74
+ this.checkInitialization();
75
+ return this.instance.patch(endpoint, data);
76
+ });
77
+ }
78
+ static delete(endpoint) {
79
+ return __awaiter(this, void 0, void 0, function* () {
80
+ this.checkInitialization();
81
+ return this.instance.delete(endpoint);
82
+ });
83
+ }
84
+ }
85
+ exports.ApiKitClient = ApiKitClient;
@@ -0,0 +1 @@
1
+ export { ApiKitClient } from './ApiKitClient';
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ApiKitClient = void 0;
4
+ var ApiKitClient_1 = require("./ApiKitClient");
5
+ Object.defineProperty(exports, "ApiKitClient", { enumerable: true, get: function () { return ApiKitClient_1.ApiKitClient; } });
@@ -0,0 +1,20 @@
1
+ export interface PaginationLink {
2
+ url: string | null;
3
+ label: string;
4
+ active: boolean;
5
+ }
6
+ export interface PaginatedResponse<T> {
7
+ current_page: number;
8
+ data: T[];
9
+ first_page_url: string;
10
+ from: number;
11
+ last_page: number;
12
+ last_page_url: string;
13
+ links: PaginationLink[];
14
+ next_page_url: string | null;
15
+ path: string;
16
+ per_page: number;
17
+ prev_page_url: string | null;
18
+ to: number;
19
+ total: number;
20
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "supaapps-api-kit-client",
3
+ "version": "0.1.0",
4
+ "description": "A versatile, type-safe API kit client designed for TypeScript applications.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "test": "echo \"Error: no test specified\" && exit 1",
9
+ "build": "tsc"
10
+ },
11
+ "author": "Supaapps GmbH",
12
+ "license": "MIT",
13
+ "dependencies": {
14
+ "axios": "^1.6.7"
15
+ },
16
+ "devDependencies": {
17
+ "@types/axios": "^0.14.0",
18
+ "@types/node": "^20.11.17",
19
+ "typescript": "^5.3.3"
20
+ }
21
+ }
@@ -0,0 +1,78 @@
1
+ import axios, { AxiosInstance, AxiosResponse, AxiosError } from 'axios';
2
+ import { PaginatedResponse } from './types';
3
+
4
+ type UnauthorizationCallback = () => void;
5
+ type AuthTokenCallback = () => Promise<string>;
6
+
7
+ export class ApiKitClient {
8
+ private static instance: AxiosInstance;
9
+ private static authTokenCallback: AuthTokenCallback;
10
+ private static unauthorizationCallback: UnauthorizationCallback;
11
+
12
+ public static initialize(baseURL: string, authTokenCallback: AuthTokenCallback, unauthorizationCallback?: UnauthorizationCallback): void {
13
+ this.authTokenCallback = authTokenCallback;
14
+ this.unauthorizationCallback = unauthorizationCallback;
15
+
16
+ this.instance = axios.create({ baseURL });
17
+
18
+ this.setupInterceptors();
19
+ }
20
+
21
+ private static setupInterceptors(): void {
22
+ this.instance.interceptors.request.use(async (config) => {
23
+ if (this.authTokenCallback) {
24
+ const authToken = await this.authTokenCallback();
25
+ config.headers.Authorization = `Bearer ${authToken}`;
26
+ }
27
+ return config;
28
+ });
29
+
30
+ this.instance.interceptors.response.use((response: AxiosResponse) => response, (error: AxiosError) => {
31
+ if (error.response?.status === 401 && this.unauthorizationCallback) {
32
+ this.unauthorizationCallback();
33
+ }
34
+ return Promise.reject(error);
35
+ });
36
+ }
37
+
38
+ private static checkInitialization(): void {
39
+ if (!this.instance) {
40
+ throw new Error("ApiKitClient has not been initialized. Please call ApiKitClient.initialize() before making requests.");
41
+ }
42
+ }
43
+
44
+ public static async get<T>(endpoint: string, params?: URLSearchParams): Promise<AxiosResponse<T>> {
45
+ this.checkInitialization();
46
+ return this.instance!.get<T>(endpoint, { params });
47
+ }
48
+
49
+ public static async getOne<T>(endpoint: string, params?: URLSearchParams): Promise<AxiosResponse<T>> {
50
+ this.checkInitialization();
51
+ return this.instance!.get<T>(endpoint, { params });
52
+ }
53
+
54
+ public static async getPaginated<T>(endpoint: string, params?: URLSearchParams): Promise<AxiosResponse<PaginatedResponse<T>>> {
55
+ this.checkInitialization();
56
+ return this.instance!.get<PaginatedResponse<T>>(endpoint, { params });
57
+ }
58
+
59
+ public static async post<T>(endpoint: string, data: T): Promise<AxiosResponse<T>> {
60
+ this.checkInitialization();
61
+ return this.instance!.post<T>(endpoint, data);
62
+ }
63
+
64
+ public static async put<T>(endpoint: string, data: T): Promise<AxiosResponse<T>> {
65
+ this.checkInitialization();
66
+ return this.instance!.put<T>(endpoint, data);
67
+ }
68
+
69
+ public static async patch<T>(endpoint: string, data: T): Promise<AxiosResponse<T>> {
70
+ this.checkInitialization();
71
+ return this.instance!.patch<T>(endpoint, data);
72
+ }
73
+
74
+ public static async delete<T>(endpoint: string): Promise<AxiosResponse<T>> {
75
+ this.checkInitialization();
76
+ return this.instance!.delete<T>(endpoint);
77
+ }
78
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export { ApiKitClient } from './ApiKitClient';
package/src/types.ts ADDED
@@ -0,0 +1,21 @@
1
+ export interface PaginationLink {
2
+ url: string | null;
3
+ label: string;
4
+ active: boolean;
5
+ }
6
+
7
+ export interface PaginatedResponse<T> {
8
+ current_page: number;
9
+ data: T[];
10
+ first_page_url: string;
11
+ from: number;
12
+ last_page: number;
13
+ last_page_url: string;
14
+ links: PaginationLink[];
15
+ next_page_url: string | null;
16
+ path: string;
17
+ per_page: number;
18
+ prev_page_url: string | null;
19
+ to: number;
20
+ total: number;
21
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "compilerOptions": {
3
+ "outDir": "./dist",
4
+ "declaration": true,
5
+ "module": "commonjs",
6
+ "target": "ES6"
7
+ },
8
+ "include": ["src/**/*.ts"]
9
+ }