klaim 1.7.51 → 1.8.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,55 @@
1
+ name: Manual Minor Update & Release
2
+
3
+ on:
4
+ workflow_dispatch:
5
+
6
+ jobs:
7
+ update-and-release-minor:
8
+ runs-on: ubuntu-latest
9
+ permissions:
10
+ id-token: write
11
+ contents: write
12
+ packages: write
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ with:
16
+ fetch-depth: 0
17
+ token: ${{ secrets.GITHUB_TOKEN }}
18
+
19
+ - name: Setup Node.js
20
+ uses: actions/setup-node@v4
21
+ with:
22
+ node-version: '20'
23
+ registry-url: 'https://registry.npmjs.org'
24
+
25
+ - name: Configure NPM Authentication
26
+ run: |
27
+ echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > .npmrc
28
+ npm whoami
29
+ env:
30
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
31
+
32
+ - name: Configure Git
33
+ run: |
34
+ git config --global user.email "github-actions[bot]@users.noreply.github.com"
35
+ git config --global user.name "GitHub Actions Bot"
36
+
37
+ - name: Install dependencies
38
+ run: npm install
39
+
40
+ - name: Update ALL dependencies
41
+ run: |
42
+ npx npm-check-updates -u
43
+ npm install
44
+
45
+ - name: Test and build
46
+ run: |
47
+ npm run test
48
+ npm run build
49
+
50
+ - name: Release Minor
51
+ run: npm run release:minor
52
+ env:
53
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
54
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
55
+ NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
package/README.md CHANGED
@@ -37,10 +37,10 @@
37
37
  - **Retry Mechanism**: Automatically retry failed requests to enhance reliability.
38
38
  - **TypeScript Support**: Fully typed for enhanced code quality and developer experience.
39
39
  - **Response Validation**: Validate responses using schemas for increased reliability and consistency.
40
+ - **Pagination**: Handle paginated requests easily with support for both page and offset based pagination.
40
41
 
41
42
  ## ⌛ Next features
42
43
 
43
- - Pagination (Version: 1.8)
44
44
  - Rate Limiting (Version: 1.9)
45
45
  - Login (Version: 1.10)
46
46
  - Time Out (Version: 1.11)
@@ -73,55 +73,57 @@ import {Api, Route} from 'klaim';
73
73
 
74
74
  // Your simple Todo type
75
75
  type Todo = {
76
- userId: number;
77
- id: number;
78
- title: string;
79
- completed: boolean;
76
+ userId: number;
77
+ id: number;
78
+ title: string;
79
+ completed: boolean;
80
80
  };
81
81
 
82
82
  // Create a new API with the name "hello" and the base URL "https://jsonplaceholder.typicode.com/"
83
83
  Api.create("hello", "https://jsonplaceholder.typicode.com/", () => {
84
- // Define routes for the API
85
- Route.get<Todo[]>("listTodos", "todos");
86
- Route.get<Todo>("getTodo", "todos/[id]");
87
- Route.post<Todo>("addTodo", "todos");
84
+ // Define routes for the API
85
+ Route.get<Todo[]>("listTodos", "todos");
86
+ Route.get<Todo>("getTodo", "todos/[id]");
87
+ Route.post<Todo>("addTodo", "todos");
88
88
  });
89
89
  ```
90
90
 
91
91
  ### Route Definition
92
92
 
93
- Routes represent endpoints in your API and can be defined with different HTTP methods. Routes can include parameters and custom configurations:
93
+ Routes represent endpoints in your API and can be defined with different HTTP methods. Routes can include parameters and
94
+ custom configurations:
94
95
 
95
96
  ```typescript
96
97
  Api.create("api", "https://api.example.com", () => {
97
- // Basic GET route
98
- Route.get("listUsers", "/users");
99
-
100
- // GET route with URL parameter
101
- Route.get("getUser", "/users/[id]");
102
-
103
- // POST route with custom headers and body
104
- Route.post("createUser", "/users", {
105
- "Content-Type": "application/json"
106
- }, { userId: 1, name: "John Doe" });
107
-
108
- // PUT route with parameter
109
- Route.put("updateUser", "/users/[id]");
110
-
111
- // DELETE route
112
- Route.delete("deleteUser", "/users/[id]");
113
-
114
- // PATCH route
115
- Route.patch("updateUserStatus", "/users/[id]/status");
116
-
117
- // OPTIONS route
118
- Route.options("userOptions", "/users");
98
+ // Basic GET route
99
+ Route.get("listUsers", "/users");
100
+
101
+ // GET route with URL parameter
102
+ Route.get("getUser", "/users/[id]");
103
+
104
+ // POST route with custom headers and body
105
+ Route.post("createUser", "/users", {
106
+ "Content-Type": "application/json"
107
+ }, {userId: 1, name: "John Doe"});
108
+
109
+ // PUT route with parameter
110
+ Route.put("updateUser", "/users/[id]");
111
+
112
+ // DELETE route
113
+ Route.delete("deleteUser", "/users/[id]");
114
+
115
+ // PATCH route
116
+ Route.patch("updateUserStatus", "/users/[id]/status");
117
+
118
+ // OPTIONS route
119
+ Route.options("userOptions", "/users");
119
120
  });
120
121
  ```
121
122
 
122
123
  ### Groups
123
124
 
124
- Klaim provides powerful grouping capabilities for both APIs and routes. Groups can be used to organize related elements, share configuration, and maintain a clean structure in your application.
125
+ Klaim provides powerful grouping capabilities for both APIs and routes. Groups can be used to organize related elements,
126
+ share configuration, and maintain a clean structure in your application.
125
127
 
126
128
  #### API Groups
127
129
 
@@ -132,21 +134,21 @@ import {Group, Api, Route} from 'klaim';
132
134
 
133
135
  // Create a group for user-related services
134
136
  Group.create("userServices", () => {
135
- // Authentication API
136
- Api.create("auth", "https://auth.example.com", () => {
137
- Route.post("login", "/login");
138
- Route.post("register", "/register");
139
- });
140
-
141
- // User Management API
142
- Api.create("users", "https://users.example.com", () => {
143
- Route.get("list", "/users");
144
- Route.get("getOne", "/users/[id]");
145
- });
137
+ // Authentication API
138
+ Api.create("auth", "https://auth.example.com", () => {
139
+ Route.post("login", "/login");
140
+ Route.post("register", "/register");
141
+ });
142
+
143
+ // User Management API
144
+ Api.create("users", "https://users.example.com", () => {
145
+ Route.get("list", "/users");
146
+ Route.get("getOne", "/users/[id]");
147
+ });
146
148
  }).withRetry(3); // Apply retry mechanism to all APIs in the group
147
149
 
148
150
  // Access grouped APIs
149
- await Klaim.userServices.auth.login({}, { username: "user", password: "pass" });
151
+ await Klaim.userServices.auth.login({}, {username: "user", password: "pass"});
150
152
  await Klaim.userServices.users.list();
151
153
  ```
152
154
 
@@ -156,23 +158,23 @@ Organize routes within an API into logical groups:
156
158
 
157
159
  ```typescript
158
160
  Api.create("hello", "https://api.example.com/", () => {
159
- // Group user-related routes
160
- Group.create("users", () => {
161
- Route.get<User[]>("list", "/users");
162
- Route.get<User>("getOne", "/users/[id]");
163
- Route.post<User>("create", "/users");
164
- }).withCache(60); // Cache all user routes for 60 seconds
165
-
166
- // Group product-related routes
167
- Group.create("products", () => {
168
- Route.get("list", "/products");
169
- Route.get("getOne", "/products/[id]");
170
- });
161
+ // Group user-related routes
162
+ Group.create("users", () => {
163
+ Route.get<User[]>("list", "/users");
164
+ Route.get<User>("getOne", "/users/[id]");
165
+ Route.post<User>("create", "/users");
166
+ }).withCache(60); // Cache all user routes for 60 seconds
167
+
168
+ // Group product-related routes
169
+ Group.create("products", () => {
170
+ Route.get("list", "/products");
171
+ Route.get("getOne", "/products/[id]");
172
+ });
171
173
  });
172
174
 
173
175
  // Use grouped routes
174
176
  const users = await Klaim.hello.users.list();
175
- const product = await Klaim.hello.products.getOne({ id: 1 });
177
+ const product = await Klaim.hello.products.getOne({id: 1});
176
178
  ```
177
179
 
178
180
  #### Nested Groups
@@ -181,32 +183,32 @@ Create complex hierarchies with nested groups:
181
183
 
182
184
  ```typescript
183
185
  Group.create("services", () => {
184
- // Internal services group
185
- Group.create("internal", () => {
186
- Api.create("logs", "https://logs.internal.example.com", () => {
187
- Route.post("write", "/logs");
188
- });
189
-
190
- Api.create("metrics", "https://metrics.internal.example.com", () => {
191
- Route.post("track", "/metrics");
192
- });
193
- }).withRetry(5); // More retries for internal services
194
-
195
- // External services group
196
- Group.create("external", () => {
197
- Api.create("weather", "https://api.weather.com", () => {
198
- Route.get("forecast", "/forecast/[city]");
199
- });
200
-
201
- Api.create("geocoding", "https://api.geocoding.com", () => {
202
- Route.get("search", "/search/[query]");
203
- });
204
- }).withCache(300); // Cache external services longer
186
+ // Internal services group
187
+ Group.create("internal", () => {
188
+ Api.create("logs", "https://logs.internal.example.com", () => {
189
+ Route.post("write", "/logs");
190
+ });
191
+
192
+ Api.create("metrics", "https://metrics.internal.example.com", () => {
193
+ Route.post("track", "/metrics");
194
+ });
195
+ }).withRetry(5); // More retries for internal services
196
+
197
+ // External services group
198
+ Group.create("external", () => {
199
+ Api.create("weather", "https://api.weather.com", () => {
200
+ Route.get("forecast", "/forecast/[city]");
201
+ });
202
+
203
+ Api.create("geocoding", "https://api.geocoding.com", () => {
204
+ Route.get("search", "/search/[query]");
205
+ });
206
+ }).withCache(300); // Cache external services longer
205
207
  });
206
208
 
207
209
  // Access nested groups
208
- await Klaim.services.internal.logs.write({}, { message: "Log entry" });
209
- await Klaim.services.external.weather.forecast({ city: "Paris" });
210
+ await Klaim.services.internal.logs.write({}, {message: "Log entry"});
211
+ await Klaim.services.external.weather.forecast({city: "Paris"});
210
212
  ```
211
213
 
212
214
  #### Group Configuration
@@ -215,22 +217,22 @@ Groups can share configuration among all their members:
215
217
 
216
218
  ```typescript
217
219
  Group.create("apis", () => {
218
- Api.create("service1", "https://api1.example.com", () => {
219
- Route.get("test", "/test");
220
- });
221
-
222
- Api.create("service2", "https://api2.example.com", () => {
223
- Route.get("test", "/test");
224
- });
220
+ Api.create("service1", "https://api1.example.com", () => {
221
+ Route.get("test", "/test");
222
+ });
223
+
224
+ Api.create("service2", "https://api2.example.com", () => {
225
+ Route.get("test", "/test");
226
+ });
225
227
  })
226
- .withCache(60) // Enable caching for all APIs
227
- .withRetry(3) // Enable retries for all APIs
228
- .before(({ config }) => { // Add authentication for all APIs
229
- config.headers.Authorization = `Bearer ${getToken()}`;
230
- })
231
- .after(({ data }) => { // Process all responses
232
- logResponse(data);
233
- });
228
+ .withCache(60) // Enable caching for all APIs
229
+ .withRetry(3) // Enable retries for all APIs
230
+ .before(({config}) => { // Add authentication for all APIs
231
+ config.headers.Authorization = `Bearer ${getToken()}`;
232
+ })
233
+ .after(({data}) => { // Process all responses
234
+ logResponse(data);
235
+ });
234
236
  ```
235
237
 
236
238
  ### Request Handling
@@ -258,16 +260,16 @@ and `after` middleware to process responses:
258
260
 
259
261
  ```typescript
260
262
  Api.create("hello", "https://jsonplaceholder.typicode.com/", () => {
261
- // With before middleware
262
- Route.get<Todo>("getRandomTodo", "todos")
263
- .before(({url}) => {
264
- const random = Math.floor(Math.random() * 10) + 1;
265
- return {url: `${url}/${random}`};
266
- });
267
-
268
- // With after middleware
269
- Route.get<Todo>("getFirstTodo", "todos")
270
- .after(({data: [first]}) => ({data: first}));
263
+ // With before middleware
264
+ Route.get<Todo>("getRandomTodo", "todos")
265
+ .before(({url}) => {
266
+ const random = Math.floor(Math.random() * 10) + 1;
267
+ return {url: `${url}/${random}`};
268
+ });
269
+
270
+ // With after middleware
271
+ Route.get<Todo>("getFirstTodo", "todos")
272
+ .after(({data: [first]}) => ({data: first}));
271
273
  });
272
274
  ```
273
275
 
@@ -281,7 +283,7 @@ import {Hook} from 'klaim';
281
283
 
282
284
  // Subscribe to the "hello.getFirstTodo" hook
283
285
  Hook.subscribe("hello.getFirstTodo", ({url}) => {
284
- console.log(`Requesting ${url}`);
286
+ console.log(`Requesting ${url}`);
285
287
  });
286
288
  ```
287
289
 
@@ -296,14 +298,14 @@ You can enable caching on individual routes:
296
298
 
297
299
  ```typescript
298
300
  Api.create("hello", "https://jsonplaceholder.typicode.com/", () => {
299
- // Get a list of todos with default cache duration (20 seconds)
300
- Route.get<Todo[]>("listTodos", "todos").withCache();
301
+ // Get a list of todos with default cache duration (20 seconds)
302
+ Route.get<Todo[]>("listTodos", "todos").withCache();
301
303
 
302
- // Get a specific todo by id with custom cache duration (300 seconds)
303
- Route.get<Todo>("getTodo", "todos/[id]").withCache(300);
304
+ // Get a specific todo by id with custom cache duration (300 seconds)
305
+ Route.get<Todo>("getTodo", "todos/[id]").withCache(300);
304
306
 
305
- // Add a new todo (no cache)
306
- Route.post<Todo>("addTodo", "todos");
307
+ // Add a new todo (no cache)
308
+ Route.post<Todo>("addTodo", "todos");
307
309
  });
308
310
  ```
309
311
 
@@ -315,10 +317,10 @@ You can also enable caching for all routes defined within an API:
315
317
 
316
318
  ```typescript
317
319
  Api.create("hello", "https://jsonplaceholder.typicode.com/", () => {
318
- // Define routes for the API
319
- Route.get<Todo[]>("listTodos", "todos");
320
- Route.get<Todo>("getTodo", "todos/[id]");
321
- Route.post<Todo>("addTodo", "todos");
320
+ // Define routes for the API
321
+ Route.get<Todo[]>("listTodos", "todos");
322
+ Route.get<Todo>("getTodo", "todos/[id]");
323
+ Route.post<Todo>("addTodo", "todos");
322
324
  }).withCache(); // Enable default cache duration (20 seconds) for all routes
323
325
  ```
324
326
 
@@ -333,14 +335,14 @@ Enable retry on individual routes:
333
335
 
334
336
  ```typescript
335
337
  Api.create("hello", "https://jsonplaceholder.typicode.com/", () => {
336
- // Get a list of todos with retry mechanism (default: 2)
337
- Route.get<Todo[]>("listTodos", "todos").withRetry();
338
+ // Get a list of todos with retry mechanism (default: 2)
339
+ Route.get<Todo[]>("listTodos", "todos").withRetry();
338
340
 
339
- // Get a specific todo by id with retry mechanism (specified to 5)
340
- Route.get<Todo>("getTodo", "todos/[id]").withRetry(5);
341
+ // Get a specific todo by id with retry mechanism (specified to 5)
342
+ Route.get<Todo>("getTodo", "todos/[id]").withRetry(5);
341
343
 
342
- // Add a new todo (no retry)
343
- Route.post<Todo>("addTodo", "todos");
344
+ // Add a new todo (no retry)
345
+ Route.post<Todo>("addTodo", "todos");
344
346
  });
345
347
  ```
346
348
 
@@ -350,10 +352,10 @@ Enable retry for all routes defined within an API:
350
352
 
351
353
  ```typescript
352
354
  Api.create("hello", "https://jsonplaceholder.typicode.com/", () => {
353
- // Define routes for the API
354
- Route.get<Todo[]>("listTodos", "todos");
355
- Route.get<Todo>("getTodo", "todos/[id]");
356
- Route.post<Todo>("addTodo", "todos");
355
+ // Define routes for the API
356
+ Route.get<Todo[]>("listTodos", "todos");
357
+ Route.get<Todo>("getTodo", "todos/[id]");
358
+ Route.post<Todo>("addTodo", "todos");
357
359
  }).withRetry();
358
360
  ```
359
361
 
@@ -376,15 +378,15 @@ import * as yup from 'yup';
376
378
 
377
379
  // Define the schema using Yup
378
380
  const todoSchema = yup.object().shape({
379
- userId: yup.number().required(),
380
- id: yup.number().min(1).max(10).required(),
381
- title: yup.string().required(),
382
- completed: yup.boolean().required()
381
+ userId: yup.number().required(),
382
+ id: yup.number().min(1).max(10).required(),
383
+ title: yup.string().required(),
384
+ completed: yup.boolean().required()
383
385
  });
384
386
 
385
387
  Api.create("hello", "https://jsonplaceholder.typicode.com/", () => {
386
- // Get a specific todo by id with validation
387
- Route.get<Todo>("getTodo", "todos/[id]").validate(todoSchema);
388
+ // Get a specific todo by id with validation
389
+ Route.get<Todo>("getTodo", "todos/[id]").validate(todoSchema);
388
390
  });
389
391
 
390
392
  // This request will fail because the id is out of range
@@ -394,6 +396,30 @@ const todoFail = await Klaim.hello.getTodo<Todo>({id: 15});
394
396
  const todo = await Klaim.hello.getTodo<Todo>({id: 1});
395
397
  ```
396
398
 
399
+ ### Pagination
400
+
401
+ Configure pagination for routes that require it:
402
+
403
+ ```typescript
404
+ // Basic usage with custom limit and offset parameter
405
+ Api.create("api", "https://api.example.com", () => {
406
+ Route.get("list", "/items").withPagination({
407
+ limit: 20, // Items per page
408
+ page: 1, // Default page number
409
+ pageParam: "offset", // Parameter name for page/offset or any other custom parameter
410
+ limitParam: "limit" // Parameter name for limit
411
+ }); // All options are optional
412
+ });
413
+
414
+ // Using paginated endpoints
415
+ const page1 = await Klaim.api.list(); // First page
416
+ const page2 = await Klaim.api.list(2); // Second page
417
+ const customPage = await Klaim.api.list(5); // Fifth page
418
+ ```
419
+
420
+ ⚠️ **Note**: The pagination feature simplifies your pagination parameters, but your API/backend needs to respond to these
421
+ parameters. Klaim does not handle the pagination logic, only the parameters management.
422
+
397
423
  ## 🔗 Links
398
424
 
399
425
  - [NPM](https://www.npmjs.com/package/klaim)
package/deno.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antharuu/klaim",
3
- "version": "1.7.51",
3
+ "version": "1.8.0",
4
4
  "description": "Klaim is a lightweight TypeScript library designed to manage APIs and record requests, optimized for an optimal user experience.",
5
5
  "repository": {
6
6
  "type": "git",
package/dist/klaim.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";var R=Object.defineProperty;var v=(s,t,e)=>t in s?R(s,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):s[t]=e;var l=(s,t,e)=>v(s,typeof t!="symbol"?t+"":t,e);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function b(s){return s.replace(/([-_][a-z])/gi,t=>t.toUpperCase().replace("-","").replace("_","")).replace(/(^\w)/,t=>t.toLowerCase())}function K(s){return s.trim().replace(/^\/|\/$/g,"")}class C{constructor(t,e,a,r={}){l(this,"type");l(this,"name");l(this,"url");l(this,"headers");l(this,"parent");l(this,"method");l(this,"arguments",new Set);l(this,"schema");l(this,"callbacks",{before:null,after:null,call:null});l(this,"cache",!1);l(this,"retry",!1);this.type=t,this.name=b(e),this.name!==e&&console.warn(`Name "${e}" has been camelCased to "${this.name}"`),this.url=K(a),this.headers=r||{}}before(t){return this.callbacks.before=t,this}after(t){return this.callbacks.after=t,this}onCall(t){return this.callbacks.call=t,this}withCache(t=20){return this.cache=t,this}withRetry(t=2){return this.retry=t,this}}const p=class p{constructor(){l(this,"cache");this.cache=new Map}static get i(){return p._instance||(p._instance=new p),p._instance}set(t,e,a=0){const r=Date.now()+a;this.cache.set(t,{data:e,expiry:r})}has(t){const e=this.cache.get(t);return e?Date.now()>e.expiry?(this.cache.delete(t),!1):!0:!1}get(t){return this.has(t)?this.cache.get(t).data:null}};l(p,"_instance");let g=p;function N(s){let a=2166136261;for(let n=0;n<s.length;n++)a^=s.charCodeAt(n),a*=16777619;let r=(a>>>0).toString(16).padStart(8,"0");for(;r.length<32;)a^=r.charCodeAt(r.length%r.length),a*=16777619,r+=(a>>>0).toString(16).padStart(8,"0");return r.substring(0,32)}async function j(s,t,e){const a=`${s.toString()}${JSON.stringify(t)}`,r=N(a);if(g.i.has(r))return g.i.get(r);const c=await(await fetch(s,t)).json();return g.i.set(r,c,e),c}class E{static subscribe(t,e){this._callbacks.set(t,e)}static run(t){const e=this._callbacks.get(t);e&&e()}}l(E,"_callbacks",new Map);const m={};async function x(s,t,e={},a={}){const r=s.split(".");let n;for(let y=0;y<r.length;y++){const T=r[y];if(n=i.i.getApi(T),n)break}if(!t||!n||t.type!=="route"||n.type!=="api")throw new Error(`Invalid path: ${s}.${t.name}`);let c=O(`${n.url}/${t.url}`,t,e),o={};a&&t.method!=="GET"&&(o.body=JSON.stringify(a)),o.headers={"Content-Type":"application/json",...n.headers,...t.headers},o.method=t.method;const{beforeRoute:u,beforeApi:f,beforeUrl:d,beforeConfig:P}=U({route:t,api:n,url:c,config:o});c=d,o=P,i.updateElement(f),i.updateElement(u);let w=await G(n,t,c,o);t.schema&&"validate"in t.schema&&(w=await t.schema.validate(w));const{afterRoute:_,afterApi:F,afterData:S}=H({route:t,api:n,response:w,data:w});return i.updateElement(F),i.updateElement(_),E.run(`${n.name}.${t.name}`),S}async function D(s,t,e,a){return s?await j(t,e,a.cache):await(await fetch(t,e)).json()}async function G(s,t,e,a){var f,d;const r=s.cache||t.cache,n=t.retry||s.retry||0;let c,o=!1,u=0;for(;u<=n&&!o;)try{(f=t.callbacks)!=null&&f.call?t.callbacks.call({}):(d=s.callbacks)!=null&&d.call&&s.callbacks.call({}),c=await D(!!r,e,a,s),o=!0}catch(P){if(u++,u>n)throw P.message=`Failed to fetch ${e} after ${n} attempts`,P}return c}function O(s,t,e){let a=s;return t.arguments.forEach(r=>{if(e[r]===void 0)throw new Error(`Argument ${r} is missing`);a=a.replace(`[${r}]`,e[r])}),a}function U({route:s,api:t,url:e,config:a}){var n,c;const r=(c=(n=s.callbacks).before)==null?void 0:c.call(n,{route:s,api:t,url:e,config:a});return{beforeRoute:(r==null?void 0:r.route)||s,beforeApi:(r==null?void 0:r.api)||t,beforeUrl:(r==null?void 0:r.url)||e,beforeConfig:(r==null?void 0:r.config)||a}}function H({route:s,api:t,response:e,data:a}){var n,c;const r=(c=(n=s.callbacks).after)==null?void 0:c.call(n,{route:s,api:t,response:e,data:a});return{afterRoute:(r==null?void 0:r.route)||s,afterApi:(r==null?void 0:r.api)||t,afterResponse:(r==null?void 0:r.response)||e,afterData:(r==null?void 0:r.data)||a}}const h=class h{constructor(){l(this,"_elements",new Map);l(this,"_currentParent",null)}static get i(){return h._instance||(h._instance=new h),h._instance}registerElement(t){const e=this._currentParent;e&&(t.parent=this.getFullPath(e));const a=this.getElementKey(t);if(this._elements.set(a,t),t.type==="api"||t.type==="group"){let r=m;if(e){const n=this.getFullPath(e).split(".");for(const c of n)r[c]||(r[c]={}),r=r[c]}r[t.name]||(r[t.name]={})}}getCurrentParent(){return this._currentParent}setCurrentParent(t){const e=this._elements.get(t);if(!e||e.type!=="api"&&e.type!=="group")throw new Error(`Element ${t} not found or not a valid parent type`);this._currentParent=e}clearCurrentParent(){this._currentParent=null}registerRoute(t){if(!this._currentParent)throw new Error("No current parent set, use Route only inside Api or Group create callback");t.parent=this.getFullPath(this._currentParent);const e=this.getElementKey(t);this._elements.set(e,t),this.addToKlaimRoute(t)}addToKlaimRoute(t){if(!t.parent)return;let e=m;const a=t.parent.split(".");for(const r of a)e[r]||(e[r]={}),e=e[r];e[t.name]=function(r={},n={}){return x(t.parent,t,r,n)}}getElementKey(t){return t?t.parent?`${t.parent}.${t.name}`:t.name:""}getFullPath(t){if(!t)return"";if(!t.parent)return t.name;const e=[t.name];let a=t;for(;a.parent;){const r=this._elements.get(a.parent);if(!r)break;e.unshift(r.name),a=r}return e.join(".")}getRoute(t,e){return this._elements.get(`${t}.${e}`)}getChildren(t){const e=[];return this._elements.forEach(a=>{a.parent===t&&e.push(a)}),e}static updateElement(t){return h.i._elements.get(h.i.getElementKey(t))||t}getApi(t){const e=this._elements.get(t);if(!e){for(const[a,r]of this._elements.entries())if(r.type==="api"&&a.endsWith(`.${t}`))return r;return}return e.type==="api"?e:this.findApi(e)}findApi(t){if(!t||!t.parent)return;const e=t.parent.split(".");for(let a=e.length;a>=0;a--){const r=e.slice(0,a).join("."),n=this._elements.get(r);if((n==null?void 0:n.type)==="api")return n}}};l(h,"_instance");let i=h;class $ extends C{static create(t,e,a,r={}){const n=b(t);n!==t&&console.warn(`API name "${t}" has been camelCased to "${n}"`);const c=new $(n,e,r),o=i.i.getCurrentParent();i.i.registerElement(c);const u=o?i.i.getFullPath(o):"",f=u?`${u}.${n}`:n;return i.i.setCurrentParent(f),a(),o?i.i.setCurrentParent(i.i.getFullPath(o)):i.i.clearCurrentParent(),c}constructor(t,e,a={}){super("api",t,e,a)}}class k extends C{static create(t,e){const a=b(t),r=i.i.getCurrentParent(),n=r?i.i.getFullPath(r):"",c=n?`${n}.${a}`:a,o=new k(a,"");a!==t&&console.warn(`Group name "${t}" has been camelCased to "${a}"`),i.i.registerElement(o);const u=i.i.getCurrentParent();return i.i.setCurrentParent(c),e(),u?i.i.setCurrentParent(i.i.getFullPath(u)):i.i.clearCurrentParent(),o}constructor(t,e,a={}){super("group",t,e,a)}withCache(t=20){return super.withCache(t),i.i.getChildren(i.i.getFullPath(this)).forEach(e=>{e.cache||(e.cache=t)}),this}withRetry(t=2){return super.withRetry(t),i.i.getChildren(i.i.getFullPath(this)).forEach(e=>{e.retry||(e.retry=t)}),this}before(t){return super.before(t),i.i.getChildren(i.i.getFullPath(this)).forEach(e=>{e.callbacks.before||(e.callbacks.before=t)}),this}after(t){return super.after(t),i.i.getChildren(i.i.getFullPath(this)).forEach(e=>{e.callbacks.after||(e.callbacks.after=t)}),this}onCall(t){return super.onCall(t),i.i.getChildren(i.i.getFullPath(this)).forEach(e=>{e.callbacks.call||(e.callbacks.call=t)}),this}}class A extends C{constructor(t,e,a={},r="GET"){super("route",t,e,a),this.method=r,this.detectArguments()}static createRoute(t,e,a={},r){const n=new A(t,e,a,r);return i.i.registerRoute(n),n}static get(t,e,a={}){return this.createRoute(t,e,a,"GET")}static post(t,e,a={}){return this.createRoute(t,e,a,"POST")}static put(t,e,a={}){return this.createRoute(t,e,a,"PUT")}static delete(t,e,a={}){return this.createRoute(t,e,a,"DELETE")}static patch(t,e,a={}){return this.createRoute(t,e,a,"PATCH")}static options(t,e,a={}){return this.createRoute(t,e,a,"OPTIONS")}detectArguments(){const t=this.url.match(/\[([^\]]+)]/g);t&&t.forEach(e=>{const a=e.replace("[","").replace("]","");this.arguments.add(a)})}validate(t){return this.schema=t,this}}exports.Api=$;exports.Group=k;exports.Hook=E;exports.Klaim=m;exports.Registry=i;exports.Route=A;
1
+ "use strict";var O=Object.defineProperty;var U=(n,t,e)=>t in n?O(n,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):n[t]=e;var o=(n,t,e)=>U(n,typeof t!="symbol"?t+"":t,e);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function E(n){return n.replace(/([-_][a-z])/gi,t=>t.toUpperCase().replace("-","").replace("_","")).replace(/(^\w)/,t=>t.toLowerCase())}function D(n){return n.trim().replace(/^\/|\/$/g,"")}const j={page:1,pageParam:"page",limit:10,limitParam:"limit"};class ${constructor(t,e,a,r={}){o(this,"type");o(this,"name");o(this,"url");o(this,"headers");o(this,"parent");o(this,"method");o(this,"arguments",new Set);o(this,"schema");o(this,"pagination");o(this,"callbacks",{before:null,after:null,call:null});o(this,"cache",!1);o(this,"retry",!1);o(this,"withCache",(t=20)=>(this.cache=t,this));o(this,"withRetry",(t=2)=>(this.retry=t,this));this.type=t,this.name=E(e),this.name!==e&&console.warn(`Name "${e}" has been camelCased to "${this.name}"`),this.url=D(a),this.headers=r||{}}before(t){return this.callbacks.before=t,this}after(t){return this.callbacks.after=t,this}onCall(t){return this.callbacks.call=t,this}withPagination(t={}){return this.pagination={...j,...t},this}}const p=class p{constructor(){o(this,"cache");this.cache=new Map}static get i(){return p._instance||(p._instance=new p),p._instance}set(t,e,a=0){const r=Date.now()+a;this.cache.set(t,{data:e,expiry:r})}has(t){const e=this.cache.get(t);return e?Date.now()>e.expiry?(this.cache.delete(t),!1):!0:!1}get(t){return this.has(t)?this.cache.get(t).data:null}};o(p,"_instance");let d=p;function x(n){let a=2166136261;for(let i=0;i<n.length;i++)a^=n.charCodeAt(i),a*=16777619;let r=(a>>>0).toString(16).padStart(8,"0");for(;r.length<32;)a^=r.charCodeAt(r.length%r.length),a*=16777619,r+=(a>>>0).toString(16).padStart(8,"0");return r.substring(0,32)}async function H(n,t,e){const a=`${n.toString()}${JSON.stringify(t)}`,r=x(a);if(d.i.has(r))return d.i.get(r);const c=await(await fetch(n,t)).json();return d.i.set(r,c,e),c}class A{static subscribe(t,e){this._callbacks.set(t,e)}static run(t){const e=this._callbacks.get(t);e&&e()}}o(A,"_callbacks",new Map);const C={};function I(n,t){return async(...e)=>{if(t.pagination){const[i=0,c={},l={}]=e;return F(n,t,i,c,l)}const[a={},r={}]=e;return F(n,t,void 0,a,r)}}async function F(n,t,e,a={},r={}){const i=n.split(".");let c;for(let g=0;g<i.length;g++){const y=i[g];if(c=s.i.getApi(y),c)break}if(!t||!c||t.type!=="route"||c.type!=="api")throw new Error(`Invalid path: ${n}.${t.name}`);let l=W(`${c.url}/${t.url}`,t,a);if(t.pagination&&typeof e<"u"){const{pageParam:g="page",limit:y=10,limitParam:K="limit"}=t.pagination,b=new URLSearchParams;b.append(g,String(e)),b.append(K,String(y));const G=l.includes("?")?"&":"?";l=`${l}${G}${b.toString()}`}let u={};r&&t.method!=="GET"&&(u.body=JSON.stringify(r)),u.headers={"Content-Type":"application/json",...c.headers,...t.headers},u.method=t.method;const{beforeRoute:f,beforeApi:P,beforeUrl:m,beforeConfig:T}=J({route:t,api:c,url:l,config:u});l=m,u=T,s.updateElement(P),s.updateElement(f);let w=await M(c,t,l,u);t.schema&&"validate"in t.schema&&(w=await t.schema.validate(w));const{afterRoute:N,afterApi:R,afterData:v}=z({route:t,api:c,response:w,data:w});return s.updateElement(R),s.updateElement(N),A.run(`${c.name}.${t.name}`),v}async function L(n,t,e,a){return n?await H(t,e,a.cache):await(await fetch(t,e)).json()}async function M(n,t,e,a){var f,P;const r=n.cache||t.cache,i=t.retry||n.retry||0;let c,l=!1,u=0;for(;u<=i&&!l;)try{(f=t.callbacks)!=null&&f.call?t.callbacks.call({}):(P=n.callbacks)!=null&&P.call&&n.callbacks.call({}),c=await L(!!r,e,a,n),l=!0}catch(m){if(u++,u>i)throw m.message=`Failed to fetch ${e} after ${i} attempts`,m}return c}function W(n,t,e){let a=n;return t.arguments.forEach(r=>{if(e[r]===void 0)throw new Error(`Argument ${r} is missing`);a=a.replace(`[${r}]`,e[r])}),a}function J({route:n,api:t,url:e,config:a}){var i,c;const r=(c=(i=n.callbacks).before)==null?void 0:c.call(i,{route:n,api:t,url:e,config:a});return{beforeRoute:(r==null?void 0:r.route)||n,beforeApi:(r==null?void 0:r.api)||t,beforeUrl:(r==null?void 0:r.url)||e,beforeConfig:(r==null?void 0:r.config)||a}}function z({route:n,api:t,response:e,data:a}){var i,c;const r=(c=(i=n.callbacks).after)==null?void 0:c.call(i,{route:n,api:t,response:e,data:a});return{afterRoute:(r==null?void 0:r.route)||n,afterApi:(r==null?void 0:r.api)||t,afterResponse:(r==null?void 0:r.response)||e,afterData:(r==null?void 0:r.data)||a}}const h=class h{constructor(){o(this,"_elements",new Map);o(this,"_currentParent",null)}static get i(){return h._instance||(h._instance=new h),h._instance}registerElement(t){const e=this._currentParent;e&&(t.parent=this.getFullPath(e));const a=this.getElementKey(t);if(this._elements.set(a,t),t.type==="api"||t.type==="group"){let r=C;if(e){const i=this.getFullPath(e).split(".");for(const c of i)r[c]||(r[c]={}),r=r[c]}r[t.name]||(r[t.name]={})}}getCurrentParent(){return this._currentParent}setCurrentParent(t){const e=this._elements.get(t);if(!e||e.type!=="api"&&e.type!=="group")throw new Error(`Element ${t} not found or not a valid parent type`);this._currentParent=e}clearCurrentParent(){this._currentParent=null}registerRoute(t){if(!this._currentParent)throw new Error("No current parent set, use Route only inside Api or Group create callback");t.parent=this.getFullPath(this._currentParent);const e=this.getElementKey(t);this._elements.set(e,t),this.addToKlaimRoute(t)}addToKlaimRoute(t){if(!t.parent)return;let e=C;const a=t.parent.split(".");for(const r of a)e[r]||(e[r]={}),e=e[r];e[t.name]=I(t.parent,t)}getElementKey(t){return t?t.parent?`${t.parent}.${t.name}`:t.name:""}getFullPath(t){if(!t)return"";if(!t.parent)return t.name;const e=[t.name];let a=t;for(;a.parent;){const r=this._elements.get(a.parent);if(!r)break;e.unshift(r.name),a=r}return e.join(".")}getRoute(t,e){return this._elements.get(`${t}.${e}`)}getChildren(t){const e=[];return this._elements.forEach(a=>{a.parent===t&&e.push(a)}),e}static updateElement(t){return h.i._elements.get(h.i.getElementKey(t))||t}getApi(t){const e=this._elements.get(t);if(!e){for(const[a,r]of this._elements.entries())if(r.type==="api"&&a.endsWith(`.${t}`))return r;return}return e.type==="api"?e:this.findApi(e)}findApi(t){if(!t||!t.parent)return;const e=t.parent.split(".");for(let a=e.length;a>=0;a--){const r=e.slice(0,a).join("."),i=this._elements.get(r);if((i==null?void 0:i.type)==="api")return i}}};o(h,"_instance");let s=h;class k extends ${static create(t,e,a,r={}){const i=E(t);i!==t&&console.warn(`API name "${t}" has been camelCased to "${i}"`);const c=new k(i,e,r),l=s.i.getCurrentParent();s.i.registerElement(c);const u=l?s.i.getFullPath(l):"",f=u?`${u}.${i}`:i;return s.i.setCurrentParent(f),a(),l?s.i.setCurrentParent(s.i.getFullPath(l)):s.i.clearCurrentParent(),c}constructor(t,e,a={}){super("api",t,e,a)}}class S extends ${static create(t,e){const a=E(t),r=s.i.getCurrentParent(),i=r?s.i.getFullPath(r):"",c=i?`${i}.${a}`:a,l=new S(a,"");a!==t&&console.warn(`Group name "${t}" has been camelCased to "${a}"`),s.i.registerElement(l);const u=s.i.getCurrentParent();return s.i.setCurrentParent(c),e(),u?s.i.setCurrentParent(s.i.getFullPath(u)):s.i.clearCurrentParent(),l}constructor(t,e,a={}){super("group",t,e,a)}withCache(t=20){return super.withCache(t),s.i.getChildren(s.i.getFullPath(this)).forEach(e=>{e.cache||(e.cache=t)}),this}withRetry(t=2){return super.withRetry(t),s.i.getChildren(s.i.getFullPath(this)).forEach(e=>{e.retry||(e.retry=t)}),this}before(t){return super.before(t),s.i.getChildren(s.i.getFullPath(this)).forEach(e=>{e.callbacks.before||(e.callbacks.before=t)}),this}after(t){return super.after(t),s.i.getChildren(s.i.getFullPath(this)).forEach(e=>{e.callbacks.after||(e.callbacks.after=t)}),this}onCall(t){return super.onCall(t),s.i.getChildren(s.i.getFullPath(this)).forEach(e=>{e.callbacks.call||(e.callbacks.call=t)}),this}}class _ extends ${constructor(t,e,a={},r="GET"){super("route",t,e,a),this.method=r,this.detectArguments()}static createRoute(t,e,a={},r){const i=new _(t,e,a,r);return s.i.registerRoute(i),i}static get(t,e,a={}){return this.createRoute(t,e,a,"GET")}static post(t,e,a={}){return this.createRoute(t,e,a,"POST")}static put(t,e,a={}){return this.createRoute(t,e,a,"PUT")}static delete(t,e,a={}){return this.createRoute(t,e,a,"DELETE")}static patch(t,e,a={}){return this.createRoute(t,e,a,"PATCH")}static options(t,e,a={}){return this.createRoute(t,e,a,"OPTIONS")}detectArguments(){const t=this.url.match(/\[([^\]]+)]/g);t&&t.forEach(e=>{const a=e.replace("[","").replace("]","");this.arguments.add(a)})}validate(t){return this.schema=t,this}}exports.Api=k;exports.Group=S;exports.Hook=A;exports.Klaim=C;exports.Registry=s;exports.Route=_;