auxilium 1.0.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/README.md +374 -0
- package/dist/http.d.ts +91 -0
- package/dist/http.js +105 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/common.d.ts +5 -0
- package/dist/interfaces/common.js +3 -0
- package/dist/interfaces/common.js.map +1 -0
- package/dist/interfaces/index.d.ts +2 -0
- package/dist/interfaces/index.js +19 -0
- package/dist/interfaces/index.js.map +1 -0
- package/dist/interfaces/logger.d.ts +11 -0
- package/dist/interfaces/logger.js +3 -0
- package/dist/interfaces/logger.js.map +1 -0
- package/dist/priorityQueue.d.ts +43 -0
- package/dist/priorityQueue.js +99 -0
- package/dist/priorityQueue.js.map +1 -0
- package/dist/queue.d.ts +39 -0
- package/dist/queue.js +69 -0
- package/dist/queue.js.map +1 -0
- package/dist/stack.d.ts +38 -0
- package/dist/stack.js +57 -0
- package/dist/stack.js.map +1 -0
- package/dist/utils/array.d.ts +104 -0
- package/dist/utils/array.js +203 -0
- package/dist/utils/array.js.map +1 -0
- package/dist/utils/async.d.ts +52 -0
- package/dist/utils/async.js +127 -0
- package/dist/utils/async.js.map +1 -0
- package/dist/utils/compare.d.ts +91 -0
- package/dist/utils/compare.js +180 -0
- package/dist/utils/compare.js.map +1 -0
- package/dist/utils/csv.d.ts +31 -0
- package/dist/utils/csv.js +57 -0
- package/dist/utils/csv.js.map +1 -0
- package/dist/utils/date.d.ts +83 -0
- package/dist/utils/date.js +179 -0
- package/dist/utils/date.js.map +1 -0
- package/dist/utils/id.d.ts +5 -0
- package/dist/utils/id.js +27 -0
- package/dist/utils/id.js.map +1 -0
- package/dist/utils/index.d.ts +11 -0
- package/dist/utils/index.js +28 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/json.d.ts +10 -0
- package/dist/utils/json.js +29 -0
- package/dist/utils/json.js.map +1 -0
- package/dist/utils/logger.d.ts +71 -0
- package/dist/utils/logger.js +160 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/number.d.ts +38 -0
- package/dist/utils/number.js +90 -0
- package/dist/utils/number.js.map +1 -0
- package/dist/utils/object.d.ts +57 -0
- package/dist/utils/object.js +107 -0
- package/dist/utils/object.js.map +1 -0
- package/dist/utils/string.d.ts +45 -0
- package/dist/utils/string.js +90 -0
- package/dist/utils/string.js.map +1 -0
- package/package.json +94 -0
package/README.md
ADDED
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
# auxilium
|
|
2
|
+
|
|
3
|
+
A small, framework‑agnostic utility toolkit for everyday JavaScript/TypeScript work.
|
|
4
|
+
Includes string/array/number/object helpers, async utilities, date helpers, a structured logger, and basic data structures (queue, stack, priority queue).
|
|
5
|
+
|
|
6
|
+
*Auxilium* (Latin: "help/assistance") — a collection of practical utilities for modern JavaScript/TypeScript development.
|
|
7
|
+
|
|
8
|
+
```ts
|
|
9
|
+
import * as aux from 'auxilium';
|
|
10
|
+
import { Queue } from 'auxilium/queue';
|
|
11
|
+
import { Stack } from 'auxilium/stack';
|
|
12
|
+
import { PriorityQueue } from 'auxilium/priority-queue';
|
|
13
|
+
import { createClient, buildQuery, withAbort } from 'auxilium';
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install auxilium
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## String utilities
|
|
23
|
+
|
|
24
|
+
Source: `src/utils/string.ts`
|
|
25
|
+
|
|
26
|
+
- **`trim(text)`** – safely trims, treating `null`/`undefined` as `''`.
|
|
27
|
+
- **`toLower(text)` / `toUpper(text)`** – lower/upper‑case after trimming.
|
|
28
|
+
- **`isEmpty(text)`** – `true` if empty or only whitespace.
|
|
29
|
+
- **`capitalize(text)`** – `"hello WORLD"` → `"Hello world"`.
|
|
30
|
+
- **`slug(text)`** – URL‑friendly slug, `"Hello World!"` → `"hello-world"`.
|
|
31
|
+
- **`includes(text, search)`** – safe wrapper around `String.prototype.includes`.
|
|
32
|
+
- **`startsWith(text, prefix)`** – safe wrapper around `startsWith`.
|
|
33
|
+
- **`endsWith(text, suffix)`** – safe wrapper around `endsWith`.
|
|
34
|
+
- **`words(text)`** – splits on whitespace, collapsing multiples.
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
trim(' hi '); // 'hi'
|
|
38
|
+
capitalize('hELLO'); // 'Hello'
|
|
39
|
+
slug('Hello World!'); // 'hello-world'
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Number utilities
|
|
43
|
+
|
|
44
|
+
Source: `src/utils/number.ts`
|
|
45
|
+
|
|
46
|
+
- **`clamp(value, min, max)`** – clamps into `[min, max]` (NaN → `min`).
|
|
47
|
+
- **`toNumber(value, fallback?)`** – safe `Number()` with fallback.
|
|
48
|
+
- **`between(value, min, max)`** – inclusive range check.
|
|
49
|
+
- **`round(value, decimals?)`** – round to N decimals.
|
|
50
|
+
- **`floor(value, decimals?)`** – floor to N decimals.
|
|
51
|
+
- **`ceil(value, decimals?)`** – ceil to N decimals.
|
|
52
|
+
- **`randomInt(min, max)`** – random integer in `[min, max]`.
|
|
53
|
+
- **`sum(numbers)`** – sum of an array.
|
|
54
|
+
- **`avg(numbers)`** – average, `0` for empty.
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
clamp(15, 0, 10); // 10
|
|
58
|
+
between(5, 0, 10); // true
|
|
59
|
+
round(1.2345, 2); // 1.23
|
|
60
|
+
randomInt(1, 6); // 1..6
|
|
61
|
+
avg([1, 2, 3, 4]); // 2.5
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Array utilities
|
|
65
|
+
|
|
66
|
+
Source: `src/utils/array.ts`
|
|
67
|
+
|
|
68
|
+
- **`uniq(items)`** – unique items, first occurrence wins.
|
|
69
|
+
- **`chunk(items, size)`** – splits into chunks.
|
|
70
|
+
- **`compact(items)`** – removes `null`/`undefined`/`false` (keeps `0` and `''`).
|
|
71
|
+
- **`flat(items)`** – flattens one level.
|
|
72
|
+
- **`first(items)` / `last(items)`** – first/last item or `undefined`.
|
|
73
|
+
- **`groupBy(objects, key)`** – group array of objects by a key.
|
|
74
|
+
- **`partition(items, predicate)`** – `[matches, nonMatches]`.
|
|
75
|
+
- **`intersect(a, b)`** – items in both arrays.
|
|
76
|
+
- **`difference(a, b)`** – items in `a` that are not in `b`.
|
|
77
|
+
- **`uniqueBy(items, keyFn)`** – unique items by computed key.
|
|
78
|
+
- **`sortBy(items, selector, direction?)`** – returns a new array sorted by a selector (`'asc'`/`'desc'`, default `'asc'`).
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
uniq([1, 2, 2, 3]); // [1, 2, 3]
|
|
82
|
+
chunk([1, 2, 3, 4, 5], 2); // [[1,2],[3,4],[5]]
|
|
83
|
+
|
|
84
|
+
const users = [
|
|
85
|
+
{ id: 1, role: 'admin' },
|
|
86
|
+
{ id: 2, role: 'user' },
|
|
87
|
+
{ id: 3, role: 'admin' },
|
|
88
|
+
];
|
|
89
|
+
|
|
90
|
+
groupBy(users, 'role');
|
|
91
|
+
// { admin: [...], user: [...] }
|
|
92
|
+
|
|
93
|
+
partition([1,2,3,4], n => n % 2 === 0);
|
|
94
|
+
// [[2,4],[1,3]]
|
|
95
|
+
|
|
96
|
+
sortBy(users, u => u.age);
|
|
97
|
+
sortBy(users, u => u.name.toLowerCase(), 'desc');
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Object utilities
|
|
101
|
+
|
|
102
|
+
Source: `src/utils/object.ts`
|
|
103
|
+
|
|
104
|
+
- **`merge(a, b)`** – shallow merge, `b` overrides `a`.
|
|
105
|
+
- **`get(obj, path, fallback?)`** – safe deep property access (`'a.b.c'`).
|
|
106
|
+
- **`isEmptyObject(value)`** – own enumerable keys length is `0`.
|
|
107
|
+
- **`pick(obj, keys)`** – new object with only selected keys.
|
|
108
|
+
- **`omit(obj, keys)`** – new object without selected keys.
|
|
109
|
+
- **`keys(obj)`** – typed keys array.
|
|
110
|
+
- **`values(obj)`** – typed values array.
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
merge({ a: 1, b: 2 }, { b: 3 }); // { a:1, b:3 }
|
|
114
|
+
get({ a: { b: 1 } }, 'a.b'); // 1
|
|
115
|
+
pick(user, ['id', 'name']);
|
|
116
|
+
omit(user, ['password']);
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Async utilities
|
|
120
|
+
|
|
121
|
+
Source: `src/utils/async.ts`
|
|
122
|
+
|
|
123
|
+
- **`sleep(ms)`** – Promise that resolves after `ms`.
|
|
124
|
+
- **`handlePromise(fn)`** – wraps any async function and returns `{ success, data, error }`, auto-unwrapping `.data` when present (e.g. axios).
|
|
125
|
+
- **`timeout(promise, ms)`** – reject if promise doesn’t settle in `ms`.
|
|
126
|
+
- **`debounce(fn, delay)`** – debounced function wrapper.
|
|
127
|
+
- **`throttle(fn, interval)`** – throttled function wrapper.
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
await sleep(500);
|
|
131
|
+
|
|
132
|
+
const usersResult = await handlePromise(() =>
|
|
133
|
+
axios.get('/api/users')
|
|
134
|
+
);
|
|
135
|
+
// usersResult.data is axiosResponse.data
|
|
136
|
+
|
|
137
|
+
const onSearch = debounce(q => doSearch(q), 300);
|
|
138
|
+
const onScroll = throttle(() => console.log('scroll'), 100);
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## HTTP / API utilities
|
|
142
|
+
|
|
143
|
+
Source: `src/http.ts`
|
|
144
|
+
|
|
145
|
+
- **`buildQuery(params)`** – builds a query string from a flat object.
|
|
146
|
+
- **`withAbort()`** – returns `{ signal, abort }` using `AbortController`.
|
|
147
|
+
- **`createClient(options)`** – creates a small HTTP client on top of fetch + `handlePromise`.
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
import { createClient } from 'toolkit';
|
|
151
|
+
|
|
152
|
+
const api = createClient({
|
|
153
|
+
baseUrl: 'https://api.example.com',
|
|
154
|
+
headers: { 'X-App': 'toolkit' },
|
|
155
|
+
getAuthToken: () => localStorage.getItem('token')
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// GET /users?active=true
|
|
159
|
+
const users = await api.get('/users', {
|
|
160
|
+
query: { active: true }
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// POST /users with JSON body
|
|
164
|
+
const newUser = await api.post('/users', { name: 'Alice' });
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Date utilities
|
|
168
|
+
|
|
169
|
+
Source: `src/utils/date.ts`
|
|
170
|
+
|
|
171
|
+
- **`now()`** – `new Date()`.
|
|
172
|
+
- **`nowIso()` / `utcIso()`** – ISO time in UTC.
|
|
173
|
+
- **`formatDate(date, format)`** – formats a date using preset formats like `'yyyy-MM-dd'`, `'yyyy-MM-dd HH:mm:ss'`, `'MM/dd/yyyy'`, etc.
|
|
174
|
+
- **`formatUtc(date, options?)`** – formatted UTC string.
|
|
175
|
+
- **`formatTz(date, timeZone, options?)`** – formatted string for IANA timezone, e.g. `"Asia/Kolkata"`.
|
|
176
|
+
- **`addDays(date, days)`**, **`addMonths(date, months)`**, **`addYears(date, years)`**.
|
|
177
|
+
- **`getYear(date)`**, **`getMonth(date)`** (1–12), **`getDaysInMonth(date)`**.
|
|
178
|
+
- **`getTodayDate()`** – today's date in `YYYY-MM-DD` format (UTC).
|
|
179
|
+
- **`getYesterdayDate()`** – yesterday's date in `YYYY-MM-DD` format (UTC).
|
|
180
|
+
- **`startOfDay(date)`** – midnight for that day.
|
|
181
|
+
- **`isBefore(a, b)`** – true if `a < b`.
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
utcIso(); // "2026-02-19T13:30:00.000Z"
|
|
185
|
+
formatDate(new Date(), 'yyyy-MM-dd'); // "2026-02-19"
|
|
186
|
+
formatDate(new Date(), 'yyyy-MM-dd HH:mm:ss'); // "2026-02-19 14:30:45"
|
|
187
|
+
formatDate(new Date(), 'MM/dd/yyyy'); // "02/19/2026"
|
|
188
|
+
formatTz(new Date(), 'Asia/Kolkata');
|
|
189
|
+
addMonths(new Date(), 1);
|
|
190
|
+
getDaysInMonth(new Date());
|
|
191
|
+
getTodayDate(); // "2026-02-19"
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## JSON utilities
|
|
195
|
+
|
|
196
|
+
Source: `src/utils/json.ts`
|
|
197
|
+
|
|
198
|
+
- **`parseJson(text)`** – safe `JSON.parse`, returns `undefined` on error.
|
|
199
|
+
- **`stringifyJson(value, replacer?, space?)`** – safe `JSON.stringify`, returns `undefined` on error.
|
|
200
|
+
|
|
201
|
+
```ts
|
|
202
|
+
parseJson('{"a":1}'); // { a:1 }
|
|
203
|
+
parseJson('{bad}'); // undefined
|
|
204
|
+
stringifyJson({ a: 1 }); // '{"a":1}'
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## CSV utilities
|
|
208
|
+
|
|
209
|
+
Source: `src/utils/csv.ts`
|
|
210
|
+
|
|
211
|
+
- **`escapeCsv(value)`** – escapes a single value for use in a CSV cell (quotes, commas, newlines).
|
|
212
|
+
- **`convertToCsv(data, headers)`** – converts an array of objects to a CSV string with labeled headers.
|
|
213
|
+
|
|
214
|
+
```ts
|
|
215
|
+
const data = [
|
|
216
|
+
{ id: 1, name: 'Alice' },
|
|
217
|
+
{ id: 2, name: 'Bob' }
|
|
218
|
+
];
|
|
219
|
+
|
|
220
|
+
const headers = [
|
|
221
|
+
{ key: 'id', label: 'ID' },
|
|
222
|
+
{ key: 'name', label: 'Name' }
|
|
223
|
+
];
|
|
224
|
+
|
|
225
|
+
const csv = convertToCsv(data, headers);
|
|
226
|
+
// ID,Name\r\n1,Alice\r\n2,Bob\r\n
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## Comparison utilities
|
|
230
|
+
|
|
231
|
+
Source: `src/utils/compare.ts`
|
|
232
|
+
|
|
233
|
+
Safely compares any two values, handling numbers, strings, objects, and mixed types.
|
|
234
|
+
|
|
235
|
+
- **`compare(a, b, key?)`** – returns `-1` if `a < b`, `0` if `a === b`, `1` if `a > b`.
|
|
236
|
+
- **`isEqual(a, b, key?)`** / **`eq(a, b, key?)`** – safely checks if two values are equal.
|
|
237
|
+
- **`isLessThan(a, b, key?)`** / **`lt(a, b, key?)`** – checks if `a < b`.
|
|
238
|
+
- **`isGreaterThan(a, b, key?)`** / **`gt(a, b, key?)`** – checks if `a > b`.
|
|
239
|
+
- **`isLessThanOrEqual(a, b, key?)`** / **`lte(a, b, key?)`** – checks if `a <= b`.
|
|
240
|
+
- **`isGreaterThanOrEqual(a, b, key?)`** / **`gte(a, b, key?)`** – checks if `a >= b`.
|
|
241
|
+
|
|
242
|
+
The `key` parameter can be a property name or a function to extract the value to compare from objects.
|
|
243
|
+
|
|
244
|
+
```ts
|
|
245
|
+
compare(5, 10); // -1
|
|
246
|
+
compare('apple', 'banana'); // -1
|
|
247
|
+
compare('5', 5); // 0 (coerced)
|
|
248
|
+
|
|
249
|
+
const users = [
|
|
250
|
+
{ id: 1, age: 25 },
|
|
251
|
+
{ id: 2, age: 30 }
|
|
252
|
+
];
|
|
253
|
+
|
|
254
|
+
compare(users[0], users[1], 'age'); // -1
|
|
255
|
+
eq(users[0], users[1], u => u.age); // false
|
|
256
|
+
lt({ value: 5 }, { value: 10 }, 'value'); // true
|
|
257
|
+
gt(10, 5); // true
|
|
258
|
+
lte(5, 5); // true
|
|
259
|
+
gte(10, 5); // true
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
## ID utility
|
|
263
|
+
|
|
264
|
+
Source: `src/utils/id.ts`
|
|
265
|
+
|
|
266
|
+
- **`id(length = 16)`** – random alphanumeric ID, using `crypto.getRandomValues` when available, otherwise `Math.random`.
|
|
267
|
+
|
|
268
|
+
```ts
|
|
269
|
+
id(); // e.g. 'f3Gk9P...'
|
|
270
|
+
id(8); // shorter id
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
## Logger
|
|
274
|
+
|
|
275
|
+
Source: `src/utils/logger.ts`
|
|
276
|
+
|
|
277
|
+
The logger prints colored, timestamped logs and returns a structured `LogEntry` for each call.
|
|
278
|
+
|
|
279
|
+
- **`log(message, data?, meta?)`** – info level.
|
|
280
|
+
- **`log.info(...)`**, **`log.success(...)`**, **`log.warn(...)`**, **`log.error(...)`** – level helpers.
|
|
281
|
+
- **`log.withColor(color, message, data?, meta?)`** – custom color (`'red'`, `'green'`, `'yellow'`, `'blue'`, `'magenta'`, `'cyan'`, `'white'`, `'gray'`).
|
|
282
|
+
|
|
283
|
+
```ts
|
|
284
|
+
import { log } from 'toolkit';
|
|
285
|
+
|
|
286
|
+
log('Server started', { port: 3000 });
|
|
287
|
+
log.success('User created', { id: 1 });
|
|
288
|
+
log.warn('Slow response', { ms: 1200 }, { context: 'GET /api/users' });
|
|
289
|
+
log.error('Failed to save', new Error('DB error'));
|
|
290
|
+
log.withColor('magenta', 'Custom log', { foo: 'bar' });
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
## Data structures
|
|
294
|
+
|
|
295
|
+
### Queue – `toolkit/queue`
|
|
296
|
+
|
|
297
|
+
Source: `src/queue.ts`
|
|
298
|
+
|
|
299
|
+
```ts
|
|
300
|
+
import { Queue } from 'toolkit/queue';
|
|
301
|
+
|
|
302
|
+
const q = new Queue<number>();
|
|
303
|
+
q.enqueue(1);
|
|
304
|
+
q.enqueue(2);
|
|
305
|
+
q.dequeue(); // 1
|
|
306
|
+
q.peek(); // 2
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
API:
|
|
310
|
+
|
|
311
|
+
- `enqueue(item)`
|
|
312
|
+
- `dequeue()` → `T | undefined`
|
|
313
|
+
- `peek()` → `T | undefined`
|
|
314
|
+
- `length` (getter)
|
|
315
|
+
- `isEmpty()`
|
|
316
|
+
- `clear()`
|
|
317
|
+
|
|
318
|
+
### Stack – `toolkit/stack`
|
|
319
|
+
|
|
320
|
+
Source: `src/stack.ts`
|
|
321
|
+
|
|
322
|
+
```ts
|
|
323
|
+
import { Stack } from 'toolkit/stack';
|
|
324
|
+
|
|
325
|
+
const s = new Stack<number>();
|
|
326
|
+
s.push(1);
|
|
327
|
+
s.push(2);
|
|
328
|
+
s.pop(); // 2
|
|
329
|
+
s.peek(); // 1
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
API:
|
|
333
|
+
|
|
334
|
+
- `push(item)`
|
|
335
|
+
- `pop()` → `T | undefined`
|
|
336
|
+
- `peek()` → `T | undefined`
|
|
337
|
+
- `length` (getter)
|
|
338
|
+
- `isEmpty()`
|
|
339
|
+
- `clear()`
|
|
340
|
+
|
|
341
|
+
### PriorityQueue – `toolkit/priority-queue`
|
|
342
|
+
|
|
343
|
+
Source: `src/priorityQueue.ts`
|
|
344
|
+
|
|
345
|
+
```ts
|
|
346
|
+
import { PriorityQueue } from 'toolkit/priority-queue';
|
|
347
|
+
|
|
348
|
+
const pq = new PriorityQueue<number>(); // min-heap by default
|
|
349
|
+
pq.enqueue(3);
|
|
350
|
+
pq.enqueue(1);
|
|
351
|
+
pq.enqueue(2);
|
|
352
|
+
pq.dequeue(); // 1
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
API:
|
|
356
|
+
|
|
357
|
+
- `constructor(compare?: (a, b) => number)` – custom comparison function.
|
|
358
|
+
- `enqueue(item)`
|
|
359
|
+
- `dequeue()` → `T | undefined`
|
|
360
|
+
- `peek()` → `T | undefined`
|
|
361
|
+
- `length` (getter)
|
|
362
|
+
- `isEmpty()`
|
|
363
|
+
- `clear()`
|
|
364
|
+
|
|
365
|
+
## Testing
|
|
366
|
+
|
|
367
|
+
The package includes a very small runtime smoke test:
|
|
368
|
+
|
|
369
|
+
```bash
|
|
370
|
+
npm test
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
This builds the TypeScript sources and runs `test/basic.mjs` against the compiled output in `dist/`.
|
|
374
|
+
|
package/dist/http.d.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { NexusResult } from './interfaces';
|
|
2
|
+
import { UnwrapData } from './utils/async';
|
|
3
|
+
/**
|
|
4
|
+
* Supported HTTP methods for the built-in client.
|
|
5
|
+
*/
|
|
6
|
+
export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
7
|
+
/**
|
|
8
|
+
* Allowed query parameter value types.
|
|
9
|
+
*/
|
|
10
|
+
export type QueryValue = string | number | boolean | null | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* Flat query parameter object.
|
|
13
|
+
*/
|
|
14
|
+
export type QueryParams = Record<string, QueryValue>;
|
|
15
|
+
/**
|
|
16
|
+
* Options for creating an HTTP client.
|
|
17
|
+
*/
|
|
18
|
+
export interface CreateClientOptions {
|
|
19
|
+
baseUrl?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Default headers applied to every request.
|
|
22
|
+
*/
|
|
23
|
+
headers?: Record<string, string>;
|
|
24
|
+
/**
|
|
25
|
+
* Optional function that returns the current auth token (e.g. JWT).
|
|
26
|
+
* When provided, an Authorization header will be added as:
|
|
27
|
+
* `Authorization: Bearer <token>`.
|
|
28
|
+
*/
|
|
29
|
+
getAuthToken?: () => string | null | undefined;
|
|
30
|
+
}
|
|
31
|
+
export interface RequestOptions {
|
|
32
|
+
method?: HttpMethod;
|
|
33
|
+
path: string;
|
|
34
|
+
query?: QueryParams;
|
|
35
|
+
/**
|
|
36
|
+
* JSON-serializable body for non-GET requests.
|
|
37
|
+
*/
|
|
38
|
+
body?: unknown;
|
|
39
|
+
headers?: Record<string, string>;
|
|
40
|
+
signal?: AbortSignal;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Simple HTTP client interface built on top of fetch and handlePromise.
|
|
44
|
+
* All methods return a NexusResult<UnwrapData<T>> where common { data } envelopes are unwrapped.
|
|
45
|
+
*/
|
|
46
|
+
export interface HttpClient {
|
|
47
|
+
request<T = unknown>(options: RequestOptions): Promise<NexusResult<UnwrapData<T>>>;
|
|
48
|
+
get<T = unknown>(path: string, opts?: Omit<RequestOptions, 'method' | 'path' | 'body'>): Promise<NexusResult<UnwrapData<T>>>;
|
|
49
|
+
post<T = unknown>(path: string, body?: unknown, opts?: Omit<RequestOptions, 'method' | 'path' | 'body'>): Promise<NexusResult<UnwrapData<T>>>;
|
|
50
|
+
put<T = unknown>(path: string, body?: unknown, opts?: Omit<RequestOptions, 'method' | 'path' | 'body'>): Promise<NexusResult<UnwrapData<T>>>;
|
|
51
|
+
patch<T = unknown>(path: string, body?: unknown, opts?: Omit<RequestOptions, 'method' | 'path' | 'body'>): Promise<NexusResult<UnwrapData<T>>>;
|
|
52
|
+
delete<T = unknown>(path: string, opts?: Omit<RequestOptions, 'method' | 'path' | 'body'>): Promise<NexusResult<UnwrapData<T>>>;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Builds a query string from a flat object of params.
|
|
56
|
+
* Skips keys with null/undefined values.
|
|
57
|
+
*/
|
|
58
|
+
export declare function buildQuery(params: QueryParams | null | undefined): string;
|
|
59
|
+
export interface AbortHandle {
|
|
60
|
+
signal: AbortSignal;
|
|
61
|
+
abort: () => void;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Creates an AbortController wrapper that exposes { signal, abort }.
|
|
65
|
+
* Useful for wiring into fetch or other APIs that accept AbortSignal.
|
|
66
|
+
*/
|
|
67
|
+
export declare function withAbort(): AbortHandle;
|
|
68
|
+
/**
|
|
69
|
+
* Creates a small HTTP client on top of fetch + handlePromise.
|
|
70
|
+
* - Supports base URL and default headers
|
|
71
|
+
* - Automatically stringifies JSON bodies and parses JSON responses
|
|
72
|
+
* - Optionally injects an Authorization Bearer token via getAuthToken
|
|
73
|
+
*
|
|
74
|
+
* Note: relies on the global fetch API being available (Node 18+ or browser).
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* const api = createClient({
|
|
78
|
+
* baseUrl: 'https://api.example.com',
|
|
79
|
+
* headers: { 'X-App': 'toolkit' },
|
|
80
|
+
* getAuthToken: () => localStorage.getItem('token')
|
|
81
|
+
* });
|
|
82
|
+
*
|
|
83
|
+
* // GET /users?active=true
|
|
84
|
+
* const users = await api.get('/users', {
|
|
85
|
+
* query: { active: true }
|
|
86
|
+
* });
|
|
87
|
+
*
|
|
88
|
+
* // POST /users with JSON body
|
|
89
|
+
* const newUser = await api.post('/users', { name: 'Alice' });
|
|
90
|
+
*/
|
|
91
|
+
export declare function createClient(options?: CreateClientOptions): HttpClient;
|
package/dist/http.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildQuery = buildQuery;
|
|
4
|
+
exports.withAbort = withAbort;
|
|
5
|
+
exports.createClient = createClient;
|
|
6
|
+
const async_1 = require("./utils/async");
|
|
7
|
+
/**
|
|
8
|
+
* Builds a query string from a flat object of params.
|
|
9
|
+
* Skips keys with null/undefined values.
|
|
10
|
+
*/
|
|
11
|
+
function buildQuery(params) {
|
|
12
|
+
if (!params)
|
|
13
|
+
return '';
|
|
14
|
+
const searchParams = new URLSearchParams();
|
|
15
|
+
for (const [key, value] of Object.entries(params)) {
|
|
16
|
+
if (value === null || value === undefined)
|
|
17
|
+
continue;
|
|
18
|
+
searchParams.append(key, String(value));
|
|
19
|
+
}
|
|
20
|
+
const qs = searchParams.toString();
|
|
21
|
+
return qs ? `?${qs}` : '';
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Creates an AbortController wrapper that exposes { signal, abort }.
|
|
25
|
+
* Useful for wiring into fetch or other APIs that accept AbortSignal.
|
|
26
|
+
*/
|
|
27
|
+
function withAbort() {
|
|
28
|
+
const controller = new AbortController();
|
|
29
|
+
return {
|
|
30
|
+
signal: controller.signal,
|
|
31
|
+
abort: () => controller.abort()
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Creates a small HTTP client on top of fetch + handlePromise.
|
|
36
|
+
* - Supports base URL and default headers
|
|
37
|
+
* - Automatically stringifies JSON bodies and parses JSON responses
|
|
38
|
+
* - Optionally injects an Authorization Bearer token via getAuthToken
|
|
39
|
+
*
|
|
40
|
+
* Note: relies on the global fetch API being available (Node 18+ or browser).
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* const api = createClient({
|
|
44
|
+
* baseUrl: 'https://api.example.com',
|
|
45
|
+
* headers: { 'X-App': 'toolkit' },
|
|
46
|
+
* getAuthToken: () => localStorage.getItem('token')
|
|
47
|
+
* });
|
|
48
|
+
*
|
|
49
|
+
* // GET /users?active=true
|
|
50
|
+
* const users = await api.get('/users', {
|
|
51
|
+
* query: { active: true }
|
|
52
|
+
* });
|
|
53
|
+
*
|
|
54
|
+
* // POST /users with JSON body
|
|
55
|
+
* const newUser = await api.post('/users', { name: 'Alice' });
|
|
56
|
+
*/
|
|
57
|
+
function createClient(options = {}) {
|
|
58
|
+
const { baseUrl = '', headers: defaultHeaders = {}, getAuthToken } = options;
|
|
59
|
+
const doRequest = async (opts) => {
|
|
60
|
+
var _a;
|
|
61
|
+
const url = `${baseUrl}${opts.path}${buildQuery(opts.query)}`;
|
|
62
|
+
const headers = {
|
|
63
|
+
...defaultHeaders,
|
|
64
|
+
...opts.headers
|
|
65
|
+
};
|
|
66
|
+
const token = getAuthToken?.();
|
|
67
|
+
if (token) {
|
|
68
|
+
headers.Authorization = `Bearer ${token}`;
|
|
69
|
+
}
|
|
70
|
+
const init = {
|
|
71
|
+
method: opts.method ?? 'GET',
|
|
72
|
+
headers,
|
|
73
|
+
signal: opts.signal
|
|
74
|
+
};
|
|
75
|
+
if (opts.body !== undefined && init.method !== 'GET') {
|
|
76
|
+
init.body = JSON.stringify(opts.body);
|
|
77
|
+
if (!init.headers) {
|
|
78
|
+
init.headers = {};
|
|
79
|
+
}
|
|
80
|
+
(_a = init.headers)['Content-Type'] ?? (_a['Content-Type'] = 'application/json');
|
|
81
|
+
}
|
|
82
|
+
const res = await fetch(url, init);
|
|
83
|
+
const contentType = res.headers.get('content-type') ?? '';
|
|
84
|
+
if (!res.ok) {
|
|
85
|
+
const text = await res.text().catch(() => '');
|
|
86
|
+
const errorMessage = text || `${res.status} ${res.statusText}`;
|
|
87
|
+
throw new Error(errorMessage);
|
|
88
|
+
}
|
|
89
|
+
if (contentType.includes('application/json')) {
|
|
90
|
+
return (await res.json());
|
|
91
|
+
}
|
|
92
|
+
// For non-JSON responses, return text
|
|
93
|
+
return (await res.text());
|
|
94
|
+
};
|
|
95
|
+
const request = (opts) => (0, async_1.handlePromise)(() => doRequest(opts));
|
|
96
|
+
return {
|
|
97
|
+
request,
|
|
98
|
+
get: (path, opts) => request({ ...(opts ?? {}), method: 'GET', path }),
|
|
99
|
+
post: (path, body, opts) => request({ ...(opts ?? {}), method: 'POST', path, body }),
|
|
100
|
+
put: (path, body, opts) => request({ ...(opts ?? {}), method: 'PUT', path, body }),
|
|
101
|
+
patch: (path, body, opts) => request({ ...(opts ?? {}), method: 'PATCH', path, body }),
|
|
102
|
+
delete: (path, opts) => request({ ...(opts ?? {}), method: 'DELETE', path })
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=http.js.map
|
package/dist/http.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./interfaces"), exports);
|
|
18
|
+
__exportStar(require("./utils"), exports);
|
|
19
|
+
__exportStar(require("./http"), exports);
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,+CAA6B;AAC7B,0CAAwB;AACxB,yCAAuB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"common.js","sourceRoot":"","sources":["../../src/interfaces/common.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./common"), exports);
|
|
18
|
+
__exportStar(require("./logger"), exports);
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/interfaces/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAyB;AACzB,2CAAyB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/interfaces/logger.ts"],"names":[],"mappings":""}
|