@atom-forge/rpc 0.3.2
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/LICENSE +28 -0
- package/README.en.md +612 -0
- package/README.hu.md +613 -0
- package/README.llm.md +343 -0
- package/README.md +25 -0
- package/dist/client/client-context.d.ts +45 -0
- package/dist/client/client-context.js +48 -0
- package/dist/client/create-client.d.ts +9 -0
- package/dist/client/create-client.js +277 -0
- package/dist/client/logger.d.ts +6 -0
- package/dist/client/logger.js +41 -0
- package/dist/client/middleware.d.ts +6 -0
- package/dist/client/middleware.js +7 -0
- package/dist/client/rpc-response.d.ts +27 -0
- package/dist/client/rpc-response.js +46 -0
- package/dist/client/types.d.ts +151 -0
- package/dist/client/types.js +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +7 -0
- package/dist/server/create-handler.d.ts +18 -0
- package/dist/server/create-handler.js +210 -0
- package/dist/server/errors.d.ts +10 -0
- package/dist/server/errors.js +14 -0
- package/dist/server/middleware.d.ts +22 -0
- package/dist/server/middleware.js +39 -0
- package/dist/server/rpc.d.ts +65 -0
- package/dist/server/rpc.js +49 -0
- package/dist/server/server-context.d.ts +79 -0
- package/dist/server/server-context.js +86 -0
- package/dist/server/types.d.ts +30 -0
- package/dist/server/types.js +1 -0
- package/dist/util/constants.d.ts +1 -0
- package/dist/util/constants.js +1 -0
- package/dist/util/cookies.d.ts +22 -0
- package/dist/util/cookies.js +54 -0
- package/dist/util/pipeline.d.ts +23 -0
- package/dist/util/pipeline.js +22 -0
- package/dist/util/string.d.ts +6 -0
- package/dist/util/string.js +11 -0
- package/dist/util/types.d.ts +5 -0
- package/dist/util/types.js +1 -0
- package/package.json +38 -0
package/README.llm.md
ADDED
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
# Rpc — LLM Reference
|
|
2
|
+
|
|
3
|
+
Rpc is a full-stack TypeScript RPC framework. **Framework-agnostic** — works with SvelteKit, Next.js, Nuxt, Express, Hono, and any runtime that supports the Web API `Request`/`Response`. It provides end-to-end type safety between server and client using MessagePack as the primary transport protocol.
|
|
4
|
+
|
|
5
|
+
## Package
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @atom-forge/rpc
|
|
9
|
+
pnpm add @atom-forge/rpc
|
|
10
|
+
yarn add @atom-forge/rpc
|
|
11
|
+
bun add @atom-forge/rpc
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Exports
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
import { createClient, makeClientMiddleware, clientLogger, RpcResponse } from '@atom-forge/rpc'; // client
|
|
18
|
+
import { createCoreHandler, flattenApiDefinition, rpc, rpcFactory, makeServerMiddleware } from '@atom-forge/rpc'; // server
|
|
19
|
+
import { z } from 'zod'; // install zod as a peer dependency in your project
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Server
|
|
25
|
+
|
|
26
|
+
### Defining endpoints
|
|
27
|
+
|
|
28
|
+
Use the `rpc` singleton (or a typed instance from `rpcFactory<CTX>()`) to define endpoints:
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
rpc.query(async (args, ctx) => result) // GET /path?args=<msgpack+base64>
|
|
32
|
+
rpc.get(async (args, ctx) => result) // GET /path?key=value (plain strings)
|
|
33
|
+
rpc.command(async (args, ctx) => result) // POST /path (body: msgpack or JSON)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Add Zod validation (import `z` from `zod` directly):
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
rpc.zod({ id: z.number(), name: z.string() }).query(...)
|
|
40
|
+
rpc.zod({ ... }).command(...)
|
|
41
|
+
rpc.zod({ ... }).get(...)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Add server middleware:
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
rpc.middleware(mw).query(...)
|
|
48
|
+
rpc.middleware(mw).command(...)
|
|
49
|
+
rpc.middleware(mw).zod({ ... }).command(...)
|
|
50
|
+
rpc.middleware(mw).on(existingObject) // attach to any object/group
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### `flattenApiDefinition` + `createCoreHandler`
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
const endpointMap = flattenApiDefinition(apiObject);
|
|
57
|
+
|
|
58
|
+
const handle = createCoreHandler(endpointMap, {
|
|
59
|
+
createServerContext?: (args, request: Request, adapterContext: TAdapter) => ServerContext<TAdapter>
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// handle signature:
|
|
63
|
+
// (request: Request, routeInfo: { path: string }, adapterContext?: TAdapter) => Promise<Response>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
- Accepted HTTP methods: `GET` for `query`/`get`, `POST` for `command`.
|
|
67
|
+
- Accepted `Content-Type` for POST: `application/msgpack` (default), `application/json`, `multipart/form-data`. Unknown → `415`.
|
|
68
|
+
- `adapterContext` is passed through as `ctx.adapterContext` in every handler.
|
|
69
|
+
|
|
70
|
+
### Framework adapter wiring
|
|
71
|
+
|
|
72
|
+
**SvelteKit** — route file `src/routes/rpc/[...path]/+server.ts`:
|
|
73
|
+
```typescript
|
|
74
|
+
const handle = createCoreHandler(flattenApiDefinition(api));
|
|
75
|
+
export const GET = (event) => handle(event.request, { path: event.params.path }, event);
|
|
76
|
+
export const POST = GET;
|
|
77
|
+
// ctx.adapterContext === RequestEvent
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**SvelteKit** — alternative via `src/hooks.server.ts` (no route file needed):
|
|
81
|
+
```typescript
|
|
82
|
+
const handleRpc = createCoreHandler(flattenApiDefinition(api));
|
|
83
|
+
export const handle = async ({ event, resolve }) => {
|
|
84
|
+
if (event.url.pathname.startsWith('/rpc/')) {
|
|
85
|
+
return handleRpc(event.request, { path: event.url.pathname.slice('/rpc/'.length) }, event);
|
|
86
|
+
}
|
|
87
|
+
return resolve(event);
|
|
88
|
+
};
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Next.js App Router** — `app/rpc/[...path]/route.ts`:
|
|
92
|
+
```typescript
|
|
93
|
+
const handle = createCoreHandler(flattenApiDefinition(api));
|
|
94
|
+
export async function GET(request: Request, { params }: { params: Promise<{ path: string[] }> }) {
|
|
95
|
+
const { path } = await params; // params is a Promise in Next.js 15+
|
|
96
|
+
return handle(request, { path: path.join('.') }, { request, params });
|
|
97
|
+
}
|
|
98
|
+
export const POST = GET;
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Nuxt 3** — `server/routes/rpc/[...path].ts`:
|
|
102
|
+
```typescript
|
|
103
|
+
import { getRouterParam, toWebRequest } from 'h3';
|
|
104
|
+
const handle = createCoreHandler(flattenApiDefinition(api));
|
|
105
|
+
export default defineEventHandler(async (event) => {
|
|
106
|
+
return handle(toWebRequest(event), { path: getRouterParam(event, 'path') ?? '' }, event);
|
|
107
|
+
});
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**Express**:
|
|
111
|
+
```typescript
|
|
112
|
+
const handle = createCoreHandler(flattenApiDefinition(api));
|
|
113
|
+
app.all('/rpc/:path', async (req, res) => {
|
|
114
|
+
const request = new Request(`${req.protocol}://${req.get('host')}${req.originalUrl}`,
|
|
115
|
+
{ method: req.method, headers: req.headers as any, body: req.method !== 'GET' ? req : null });
|
|
116
|
+
const response = await handle(request, { path: req.params.path }, { req, res });
|
|
117
|
+
res.status(response.status);
|
|
118
|
+
response.headers.forEach((v, k) => res.setHeader(k, v));
|
|
119
|
+
res.send(Buffer.from(await response.arrayBuffer()));
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**Hono**:
|
|
124
|
+
```typescript
|
|
125
|
+
const handle = createCoreHandler(flattenApiDefinition(api));
|
|
126
|
+
app.all('/rpc/:path', (c) => handle(c.req.raw, { path: c.req.param('path') }, c));
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### `rpcFactory`
|
|
130
|
+
|
|
131
|
+
Creates a typed `rpc` instance bound to a custom context type:
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
const rpc = rpcFactory<AppContext>();
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### `makeServerMiddleware`
|
|
138
|
+
|
|
139
|
+
> ⚠️ Always `return await next()` — omitting the `return` silently drops the handler's result.
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
const mw = makeServerMiddleware(
|
|
143
|
+
async (ctx, next) => {
|
|
144
|
+
// early exit without calling next() is valid:
|
|
145
|
+
// ctx.status.unauthorized(); return { error: '...' };
|
|
146
|
+
return await next(); // ✅ must return
|
|
147
|
+
},
|
|
148
|
+
{ isAdmin: (ctx) => (ctx.adapterContext as RequestEvent).locals.user?.role === 'admin' }
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
// Accessor functions are attached to the middleware function object itself:
|
|
152
|
+
const api = {
|
|
153
|
+
admin: {
|
|
154
|
+
deletePost: rpc.middleware(mw).command(async ({ id }, ctx) => {
|
|
155
|
+
if (!mw.isAdmin(ctx)) { ctx.status.forbidden(); return { error: 'Admin only' }; }
|
|
156
|
+
}),
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### `ServerContext<TAdapter>` — `ctx` properties
|
|
162
|
+
|
|
163
|
+
| Property | Type | Description |
|
|
164
|
+
|---|---|---|
|
|
165
|
+
| `ctx.request` | `Request` | Standard Web API Request object |
|
|
166
|
+
| `ctx.adapterContext` | `TAdapter` | Framework-specific context (e.g. `RequestEvent`, Hono `Context`) |
|
|
167
|
+
| `ctx.args` | `Map<string, any>` | Parsed request arguments |
|
|
168
|
+
| `ctx.getArgs()` | `() => Record<string, any>` | Args as plain object |
|
|
169
|
+
| `ctx.cookies` | `CookieManager` | `get(name)`, `set(name, value, opts?)`, `delete(name, opts?)`, `getAll()` |
|
|
170
|
+
| `ctx.headers.request` | `Headers` | Incoming request headers |
|
|
171
|
+
| `ctx.headers.response` | `Headers` | Mutable outgoing response headers |
|
|
172
|
+
| `ctx.cache.set(n)` | `(seconds: number) => void` | Set `Cache-Control` max-age (GET only) |
|
|
173
|
+
| `ctx.cache.get()` | `() => number` | Get current cache value |
|
|
174
|
+
| `ctx.status.set(n)` | `(code: number) => void` | Set response status code |
|
|
175
|
+
| `ctx.status.<shortcut>()` | `() => void` | e.g. `notFound()`, `unauthorized()`, `created()` |
|
|
176
|
+
| `ctx.env` | `Map<string\|symbol, any>` | Shared state across middlewares |
|
|
177
|
+
| `ctx.elapsedTime` | `number` | ms since context was created |
|
|
178
|
+
|
|
179
|
+
**All status shortcuts:** `continue`, `switchingProtocols`, `processing`, `ok`, `created`, `accepted`, `noContent`, `resetContent`, `partialContent`, `multipleChoices`, `movedPermanently`, `found`, `seeOther`, `notModified`, `temporaryRedirect`, `permanentRedirect`, `badRequest`, `unauthorized`, `paymentRequired`, `forbidden`, `notFound`, `methodNotAllowed`, `notAcceptable`, `conflict`, `gone`, `lengthRequired`, `preconditionFailed`, `payloadTooLarge`, `uriTooLong`, `badContent`, `rangeNotSatisfiable`, `expectationFailed`, `tooManyRequests`, `serverError`, `notImplemented`, `badGateway`, `serviceUnavailable`, `gatewayTimeout`, `httpVersionNotSupported`.
|
|
180
|
+
|
|
181
|
+
### Response headers sent by the server
|
|
182
|
+
|
|
183
|
+
| Header | When |
|
|
184
|
+
|---|---|
|
|
185
|
+
| `x-atom-forge-rpc-exec-time` | Always — server-side execution time in ms |
|
|
186
|
+
| `Content-Type` | `application/msgpack` or `application/json` (based on `Accept` header) |
|
|
187
|
+
| `Cache-Control` | Only on GET when `ctx.cache.set(n)` was called |
|
|
188
|
+
| `Set-Cookie` | When `ctx.cookies.set()` or `ctx.cookies.delete()` is called |
|
|
189
|
+
|
|
190
|
+
### Zod validation errors
|
|
191
|
+
|
|
192
|
+
Zod failures are returned as application-level errors (status `200 OK`):
|
|
193
|
+
|
|
194
|
+
- Body: `{ "atomforge.rpc.error": "INVALID_ARGUMENT", issues: ZodIssue[] }`
|
|
195
|
+
|
|
196
|
+
### Error helpers
|
|
197
|
+
|
|
198
|
+
Return these from handlers to signal application-level errors. All produce a `200 OK` response with the `atomforge.rpc.error` key set.
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
return rpc.error.invalidArgument({ message: 'Title too short' }) // code: "INVALID_ARGUMENT"
|
|
202
|
+
return rpc.error.permissionDenied({ message: 'Admins only' }) // code: "PERMISSION_DENIED"
|
|
203
|
+
return rpc.error.internalError() // code: "INTERNAL_ERROR", auto correlationId
|
|
204
|
+
return rpc.error.make('POST_ALREADY_EXISTS', 'Already exists', { slug: post.slug }) // custom
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Client
|
|
210
|
+
|
|
211
|
+
### `createClient`
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
const [api, cfg] = createClient<typeof apiDefinition>(
|
|
215
|
+
baseUrl: string = '/api'
|
|
216
|
+
);
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
- `api`: recursive proxy matching the server API shape. Use `typeof api` (the server-side api object) as the generic.
|
|
220
|
+
- `cfg`: middleware configuration proxy.
|
|
221
|
+
|
|
222
|
+
### Calling endpoints
|
|
223
|
+
|
|
224
|
+
Every call returns a `RpcResponse`. Use `isOK()` / `isError()` to branch:
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
const res = await api.posts.list.$query(args, options?)
|
|
228
|
+
const res = await api.posts.create.$command(args, options?)
|
|
229
|
+
const res = await api.posts.getById.$get(args, options?)
|
|
230
|
+
|
|
231
|
+
if (res.isOK()) {
|
|
232
|
+
const data = res.result // typed success data
|
|
233
|
+
} else if (res.isError('INVALID_ARGUMENT')) {
|
|
234
|
+
console.log(res.result) // error details
|
|
235
|
+
} else if (res.isError('HTTP:401')) {
|
|
236
|
+
// transport-level error
|
|
237
|
+
} else {
|
|
238
|
+
console.log(res.status, res.result)
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### `RpcResponse<TSuccess, TError>`
|
|
243
|
+
|
|
244
|
+
| Member | Description |
|
|
245
|
+
|---|---|
|
|
246
|
+
| `res.isOK()` | `true` if the call succeeded |
|
|
247
|
+
| `res.isError(code?)` | `true` if error; optional specific code check |
|
|
248
|
+
| `res.status` / `res.getStatus()` | `'OK'` on success, error code string otherwise |
|
|
249
|
+
| `res.result` / `res.getResult()` | Typed success data or error details |
|
|
250
|
+
| `res.ctx` / `res.getCtx()` | The full `ClientContext` for this call |
|
|
251
|
+
|
|
252
|
+
**Error code format:**
|
|
253
|
+
- Application-level errors: `'INVALID_ARGUMENT'`, `'PERMISSION_DENIED'`, `'NOT_FOUND'`, etc.
|
|
254
|
+
- Transport errors: `'HTTP:401'`, `'HTTP:404'`, `'HTTP:500'`, etc.
|
|
255
|
+
- Network errors: `'NETWORK_ERROR'`
|
|
256
|
+
|
|
257
|
+
### `CallOptions`
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
type CallOptions = {
|
|
261
|
+
abortSignal?: AbortSignal;
|
|
262
|
+
onProgress?: (p: { loaded: number; total: number; percent: number; phase: 'upload' | 'download' }) => void;
|
|
263
|
+
headers?: Headers;
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
- When `onProgress` is provided, the request uses **XHR** instead of `fetch`.
|
|
268
|
+
|
|
269
|
+
### File uploads
|
|
270
|
+
|
|
271
|
+
Pass `File` or `File[]` as an argument value in a `$command` call. Rpc automatically switches to `multipart/form-data`. For arrays, suffix the key with `[]`:
|
|
272
|
+
|
|
273
|
+
```typescript
|
|
274
|
+
await api.media.upload.$command({ 'files[]': fileArray });
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### `ClientContext` properties
|
|
278
|
+
|
|
279
|
+
| Property | Type | Description |
|
|
280
|
+
|---|---|---|
|
|
281
|
+
| `ctx.result` | `T \| undefined` | The typed result |
|
|
282
|
+
| `ctx.response` | `Response \| undefined` | The raw Response object |
|
|
283
|
+
| `ctx.path` | `string[]` | Request path segments |
|
|
284
|
+
| `ctx.args` | `Map<string, any>` | Arguments map |
|
|
285
|
+
| `ctx.getArgs()` | `() => Record<string, any>` | Args as plain object |
|
|
286
|
+
| `ctx.rpcType` | `'query' \| 'command' \| 'get'` | RPC method type |
|
|
287
|
+
| `ctx.elapsedTime` | `number` | ms since context was created |
|
|
288
|
+
| `ctx.env` | `Map<string\|symbol, any>` | Shared state across middlewares |
|
|
289
|
+
| `ctx.abortSignal` | `AbortSignal \| undefined` | The abort signal if provided |
|
|
290
|
+
| `ctx.onProgress` | `OnProgress \| undefined` | The progress callback if provided |
|
|
291
|
+
| `ctx.request.headers` | `Headers` | Outgoing request headers |
|
|
292
|
+
|
|
293
|
+
### Applying client middleware
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
cfg.$ = mw // global (all routes)
|
|
297
|
+
cfg.posts.$ = mw // all endpoints under /posts
|
|
298
|
+
cfg.posts.create = mw // single endpoint /posts/create
|
|
299
|
+
cfg.posts.create = [mw1, mw2] // multiple middlewares
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### `clientLogger`
|
|
303
|
+
|
|
304
|
+
Built-in debug middleware. Logs path, args, result, timing, and HTTP status to the browser console.
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
const [api, cfg] = createClient<typeof apiDefinition>('/rpc');
|
|
308
|
+
cfg.$ = clientLogger('/rpc'); // baseUrl must match createClient's baseUrl
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### `makeClientMiddleware`
|
|
312
|
+
|
|
313
|
+
> ⚠️ Always `return await next()` — omitting the `return` silently drops the response.
|
|
314
|
+
|
|
315
|
+
```typescript
|
|
316
|
+
const mw = makeClientMiddleware(async (ctx, next) => {
|
|
317
|
+
// before request
|
|
318
|
+
const result = await next(); // ✅ must return
|
|
319
|
+
// after request — ctx.result is available
|
|
320
|
+
return result;
|
|
321
|
+
});
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
## Protocol details
|
|
327
|
+
|
|
328
|
+
| RPC type | HTTP method | Args encoding | Body |
|
|
329
|
+
|---|---|---|---|
|
|
330
|
+
| `get` | GET | `?key=value` (plain strings) | — |
|
|
331
|
+
| `query` | GET | `?args=<base64url(msgpack(args))>` | — |
|
|
332
|
+
| `command` (no files) | POST | — | `msgpack(args)` or `JSON(args)` |
|
|
333
|
+
| `command` (with files) | POST | — | `multipart/form-data` (args blob + file parts) |
|
|
334
|
+
|
|
335
|
+
Response body is `msgpack` by default. Send `Accept: application/json` to get JSON instead.
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
## URL format
|
|
340
|
+
|
|
341
|
+
Client-side calls generate dot-separated, fully kebab-case paths. For example, `api.posts.getById.$query(...)` maps to `/rpc/posts.get-by-id`.
|
|
342
|
+
|
|
343
|
+
Use `[...path]` (catch-all) in your framework's router so the dot-separated path is treated as a single segment. With Next.js (array params), join with `.`: `params.path.join('.')`.
|
package/README.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# @atom-forge/rpc
|
|
2
|
+
|
|
3
|
+
Type-safe RPC framework for TypeScript with Zod validation and middleware support. Framework-agnostic — works with SvelteKit, Next.js, Nuxt, Express, Hono, and any runtime that supports the Web API `Request`/`Response`.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install @atom-forge/rpc
|
|
7
|
+
pnpm add @atom-forge/rpc
|
|
8
|
+
yarn add @atom-forge/rpc
|
|
9
|
+
bun add @atom-forge/rpc
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Documentation
|
|
13
|
+
|
|
14
|
+
- [English](README.en.md)
|
|
15
|
+
- [Hungarian](README.hu.md)
|
|
16
|
+
- [LLM Reference](README.llm.md)
|
|
17
|
+
|
|
18
|
+
## License
|
|
19
|
+
|
|
20
|
+
AtomForge — Patron License. Copyright (c) 2024-present Elvis Szabo.
|
|
21
|
+
|
|
22
|
+
- **Non-commercial use** (personal projects, open source, non-profits): free of charge.
|
|
23
|
+
- **Commercial use** (for-profit, SaaS, client work): requires an active [GitHub Sponsors](https://github.com/sponsors/atom-forge) subscription. The license is perpetual for projects started during the active support period.
|
|
24
|
+
|
|
25
|
+
See the [LICENSE](./LICENSE) file for the full license text.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { CallOptions, OnProgress } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Represents the context for a client-side operation, holding metadata and options related to the operation.
|
|
4
|
+
* @internal
|
|
5
|
+
*/
|
|
6
|
+
export declare class ClientContext<RESULT = any> {
|
|
7
|
+
/** A Map of custom environment variables relevant to the client context. */
|
|
8
|
+
readonly env: Map<string | symbol, any>;
|
|
9
|
+
/** An object with methods to set and get cache duration. */
|
|
10
|
+
readonly abortSignal?: AbortSignal;
|
|
11
|
+
/** An object with methods to set and get cache duration. */
|
|
12
|
+
readonly onProgress?: OnProgress;
|
|
13
|
+
/** A Map object representing arguments passed to the server */
|
|
14
|
+
readonly args: Map<string, any>;
|
|
15
|
+
/** The request path segments */
|
|
16
|
+
readonly path: string[];
|
|
17
|
+
protected _headers: Headers;
|
|
18
|
+
protected _response?: Response;
|
|
19
|
+
/** The result of the operation */
|
|
20
|
+
result?: RESULT;
|
|
21
|
+
/** The response */
|
|
22
|
+
get response(): Response | undefined;
|
|
23
|
+
/** The request */
|
|
24
|
+
readonly request: {
|
|
25
|
+
headers: Headers;
|
|
26
|
+
};
|
|
27
|
+
/** The RPC type */
|
|
28
|
+
readonly rpcType: "command" | "query" | "get";
|
|
29
|
+
private readonly start;
|
|
30
|
+
/** Indicates the time elapsed since the creation of the ClientContext instance */
|
|
31
|
+
get elapsedTime(): number;
|
|
32
|
+
/**
|
|
33
|
+
* Creates a new ClientContext instance.
|
|
34
|
+
* @param path - The path segments of the RPC method.
|
|
35
|
+
* @param args - The arguments to be passed to the RPC method.
|
|
36
|
+
* @param rpcType - The type of the RPC call (command, query, or get).
|
|
37
|
+
* @param options - Optional configuration for the call.
|
|
38
|
+
*/
|
|
39
|
+
constructor(path: string[], args: Record<string, any> | undefined, rpcType: "command" | "query" | "get", options?: CallOptions);
|
|
40
|
+
getArgs(): Record<string, any>;
|
|
41
|
+
}
|
|
42
|
+
/** @internal */
|
|
43
|
+
export declare class WritableClientContext extends ClientContext {
|
|
44
|
+
_response: Response | undefined;
|
|
45
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents the context for a client-side operation, holding metadata and options related to the operation.
|
|
3
|
+
* @internal
|
|
4
|
+
*/
|
|
5
|
+
export class ClientContext {
|
|
6
|
+
/** The response */
|
|
7
|
+
get response() {
|
|
8
|
+
return this._response;
|
|
9
|
+
}
|
|
10
|
+
/** Indicates the time elapsed since the creation of the ClientContext instance */
|
|
11
|
+
get elapsedTime() {
|
|
12
|
+
return performance.now() - this.start;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Creates a new ClientContext instance.
|
|
16
|
+
* @param path - The path segments of the RPC method.
|
|
17
|
+
* @param args - The arguments to be passed to the RPC method.
|
|
18
|
+
* @param rpcType - The type of the RPC call (command, query, or get).
|
|
19
|
+
* @param options - Optional configuration for the call.
|
|
20
|
+
*/
|
|
21
|
+
constructor(path, args, rpcType, options = {}) {
|
|
22
|
+
/** A Map of custom environment variables relevant to the client context. */
|
|
23
|
+
this.env = new Map();
|
|
24
|
+
this.start = performance.now();
|
|
25
|
+
this.rpcType = rpcType;
|
|
26
|
+
this.path = path;
|
|
27
|
+
this.args = new Map(Object.entries(args || {}));
|
|
28
|
+
const _headers = options.headers ? options.headers : new Headers();
|
|
29
|
+
_headers.set("accept", "application/msgpack");
|
|
30
|
+
this.request = {
|
|
31
|
+
get headers() {
|
|
32
|
+
return _headers;
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
this._headers = _headers;
|
|
36
|
+
this.abortSignal = options.abortSignal;
|
|
37
|
+
this.onProgress = options.onProgress;
|
|
38
|
+
}
|
|
39
|
+
getArgs() {
|
|
40
|
+
const obj = {};
|
|
41
|
+
for (const [key, value] of this.args)
|
|
42
|
+
obj[key] = value;
|
|
43
|
+
return obj;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/** @internal */
|
|
47
|
+
export class WritableClientContext extends ClientContext {
|
|
48
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ApiClientDefinition, MiddlewareConfig } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Creates an API client and a corresponding middleware configuration object.
|
|
4
|
+
*
|
|
5
|
+
* @template T
|
|
6
|
+
* @param {string} [baseUrl='/api'] - The base URL for the API client.
|
|
7
|
+
* @returns {[ApiClientDefinition<T>, MiddlewareConfig<T>]} A tuple containing the API client and the middleware config object.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createClient<T>(baseUrl?: string): [ApiClientDefinition<T>, MiddlewareConfig<T>];
|