@parsrun/service 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.
- package/README.md +375 -0
- package/dist/client.d.ts +55 -0
- package/dist/client.js +1474 -0
- package/dist/client.js.map +1 -0
- package/dist/define.d.ts +82 -0
- package/dist/define.js +120 -0
- package/dist/define.js.map +1 -0
- package/dist/events/index.d.ts +285 -0
- package/dist/events/index.js +853 -0
- package/dist/events/index.js.map +1 -0
- package/dist/handler-CmiDUWZv.d.ts +204 -0
- package/dist/index-CVOAoJjZ.d.ts +268 -0
- package/dist/index.d.ts +46 -0
- package/dist/index.js +3589 -0
- package/dist/index.js.map +1 -0
- package/dist/resilience/index.d.ts +197 -0
- package/dist/resilience/index.js +387 -0
- package/dist/resilience/index.js.map +1 -0
- package/dist/rpc/index.d.ts +5 -0
- package/dist/rpc/index.js +1175 -0
- package/dist/rpc/index.js.map +1 -0
- package/dist/serialization/index.d.ts +37 -0
- package/dist/serialization/index.js +320 -0
- package/dist/serialization/index.js.map +1 -0
- package/dist/server-DFE8n2Sx.d.ts +106 -0
- package/dist/tracing/index.d.ts +406 -0
- package/dist/tracing/index.js +820 -0
- package/dist/tracing/index.js.map +1 -0
- package/dist/transports/cloudflare/index.d.ts +237 -0
- package/dist/transports/cloudflare/index.js +746 -0
- package/dist/transports/cloudflare/index.js.map +1 -0
- package/dist/types-n4LLSPQU.d.ts +473 -0
- package/package.json +91 -0
package/README.md
ADDED
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
# @parsrun/service
|
|
2
|
+
|
|
3
|
+
> Unified service layer for building microservices with RPC, Events, and Distributed Tracing.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **RPC Layer** - Type-safe request-response communication
|
|
8
|
+
- **Event Layer** - CloudEvents-compatible async messaging
|
|
9
|
+
- **Resilience** - Circuit breaker, bulkhead, retry, timeout
|
|
10
|
+
- **Tracing** - W3C Trace Context compatible distributed tracing
|
|
11
|
+
- **Multi-Transport** - Embedded, HTTP, Cloudflare (Workers, DO, Queues)
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm add @parsrun/service @parsrun/core
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
### Define a Service
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { defineService } from "@parsrun/service";
|
|
25
|
+
|
|
26
|
+
export const emailService = defineService({
|
|
27
|
+
name: "email",
|
|
28
|
+
version: "1.0.0",
|
|
29
|
+
queries: {
|
|
30
|
+
getTemplates: {
|
|
31
|
+
input: undefined,
|
|
32
|
+
output: { templates: "array" },
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
mutations: {
|
|
36
|
+
send: {
|
|
37
|
+
input: {
|
|
38
|
+
to: "string",
|
|
39
|
+
subject: "string",
|
|
40
|
+
html: "string",
|
|
41
|
+
},
|
|
42
|
+
output: {
|
|
43
|
+
success: "boolean",
|
|
44
|
+
messageId: "string?",
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
events: {
|
|
49
|
+
emits: {
|
|
50
|
+
"email.sent": {
|
|
51
|
+
data: { messageId: "string", to: "string" },
|
|
52
|
+
},
|
|
53
|
+
"email.failed": {
|
|
54
|
+
data: { error: "string", to: "string" },
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Use a Service (Client)
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
import { useService } from "@parsrun/service";
|
|
65
|
+
|
|
66
|
+
// Get service client
|
|
67
|
+
const email = useService("email");
|
|
68
|
+
|
|
69
|
+
// Make RPC calls
|
|
70
|
+
const result = await email.mutate("send", {
|
|
71
|
+
to: "user@example.com",
|
|
72
|
+
subject: "Hello",
|
|
73
|
+
html: "<p>Hello World</p>",
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Subscribe to events
|
|
77
|
+
email.on("email.sent", async (event) => {
|
|
78
|
+
console.log("Email sent:", event.data.messageId);
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Modules
|
|
83
|
+
|
|
84
|
+
### RPC
|
|
85
|
+
|
|
86
|
+
Request-response communication between services.
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
import {
|
|
90
|
+
RpcClient,
|
|
91
|
+
RpcServer,
|
|
92
|
+
createRpcClient,
|
|
93
|
+
createRpcServer,
|
|
94
|
+
EmbeddedTransport,
|
|
95
|
+
HttpTransport,
|
|
96
|
+
} from "@parsrun/service/rpc";
|
|
97
|
+
|
|
98
|
+
// Create server
|
|
99
|
+
const server = createRpcServer({
|
|
100
|
+
service: "email",
|
|
101
|
+
handlers: {
|
|
102
|
+
send: async (input, ctx) => {
|
|
103
|
+
// Handle request
|
|
104
|
+
return { success: true, messageId: "123" };
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// Create client
|
|
110
|
+
const client = createRpcClient({
|
|
111
|
+
service: "email",
|
|
112
|
+
transport: new EmbeddedTransport(server),
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// Call method
|
|
116
|
+
const result = await client.call("send", {
|
|
117
|
+
to: "user@example.com",
|
|
118
|
+
subject: "Hello",
|
|
119
|
+
html: "<p>Hello</p>",
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Events
|
|
124
|
+
|
|
125
|
+
Asynchronous event-driven communication.
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import {
|
|
129
|
+
EventEmitter,
|
|
130
|
+
createEventEmitter,
|
|
131
|
+
MemoryEventTransport,
|
|
132
|
+
createMemoryEventTransport,
|
|
133
|
+
} from "@parsrun/service/events";
|
|
134
|
+
|
|
135
|
+
// Create transport
|
|
136
|
+
const transport = createMemoryEventTransport();
|
|
137
|
+
|
|
138
|
+
// Create emitter
|
|
139
|
+
const emitter = createEventEmitter({
|
|
140
|
+
service: "email",
|
|
141
|
+
transport,
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// Emit event
|
|
145
|
+
await emitter.emit("email.sent", {
|
|
146
|
+
messageId: "123",
|
|
147
|
+
to: "user@example.com",
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// Subscribe to events
|
|
151
|
+
transport.subscribe("email.*", async (event, ctx) => {
|
|
152
|
+
console.log("Event received:", event.type, event.data);
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Resilience
|
|
157
|
+
|
|
158
|
+
Patterns for building resilient systems.
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
import {
|
|
162
|
+
CircuitBreaker,
|
|
163
|
+
Bulkhead,
|
|
164
|
+
withRetry,
|
|
165
|
+
withTimeout,
|
|
166
|
+
TimeoutExceededError,
|
|
167
|
+
} from "@parsrun/service/resilience";
|
|
168
|
+
|
|
169
|
+
// Circuit Breaker
|
|
170
|
+
const cb = new CircuitBreaker({
|
|
171
|
+
failureThreshold: 5,
|
|
172
|
+
resetTimeout: 30000,
|
|
173
|
+
successThreshold: 2,
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
const result = await cb.execute(async () => {
|
|
177
|
+
return await fetch("https://api.example.com/data");
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// Bulkhead (concurrency limiting)
|
|
181
|
+
const bulkhead = new Bulkhead({
|
|
182
|
+
maxConcurrent: 10,
|
|
183
|
+
maxQueue: 100,
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
await bulkhead.execute(async () => {
|
|
187
|
+
// Limited concurrent execution
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// Retry with backoff
|
|
191
|
+
const fetchWithRetry = withRetry(
|
|
192
|
+
async () => fetch("https://api.example.com/data"),
|
|
193
|
+
{
|
|
194
|
+
attempts: 3,
|
|
195
|
+
backoff: "exponential",
|
|
196
|
+
initialDelay: 100,
|
|
197
|
+
maxDelay: 5000,
|
|
198
|
+
shouldRetry: (error) => error.retryable !== false,
|
|
199
|
+
}
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
// Timeout
|
|
203
|
+
const fetchWithTimeout = withTimeout(
|
|
204
|
+
async () => fetch("https://api.example.com/data"),
|
|
205
|
+
5000
|
|
206
|
+
);
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Tracing
|
|
210
|
+
|
|
211
|
+
W3C Trace Context compatible distributed tracing.
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
import {
|
|
215
|
+
Tracer,
|
|
216
|
+
createTracer,
|
|
217
|
+
ConsoleExporter,
|
|
218
|
+
OtlpExporter,
|
|
219
|
+
} from "@parsrun/service/tracing";
|
|
220
|
+
|
|
221
|
+
// Create tracer
|
|
222
|
+
const tracer = createTracer({
|
|
223
|
+
serviceName: "email-service",
|
|
224
|
+
serviceVersion: "1.0.0",
|
|
225
|
+
exporter: new ConsoleExporter(),
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// Trace an operation
|
|
229
|
+
const result = await tracer.trace("send-email", async (span) => {
|
|
230
|
+
span?.attributes["email.to"] = "user@example.com";
|
|
231
|
+
// ... send email
|
|
232
|
+
return { success: true };
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
// Manual span management
|
|
236
|
+
const span = tracer.startSpan("process-webhook", { kind: "server" });
|
|
237
|
+
try {
|
|
238
|
+
// Process webhook
|
|
239
|
+
tracer.endSpan(span);
|
|
240
|
+
} catch (error) {
|
|
241
|
+
tracer.endSpan(span, error);
|
|
242
|
+
throw error;
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Cloudflare Transports
|
|
247
|
+
|
|
248
|
+
Native Cloudflare Workers integration.
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
import {
|
|
252
|
+
WorkerRpcTransport,
|
|
253
|
+
DurableObjectTransport,
|
|
254
|
+
QueueEventTransport,
|
|
255
|
+
} from "@parsrun/service/transports/cloudflare";
|
|
256
|
+
|
|
257
|
+
// Service Binding (Worker-to-Worker RPC)
|
|
258
|
+
const transport = new WorkerRpcTransport({
|
|
259
|
+
binding: env.EMAIL_SERVICE, // Service binding
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
// Durable Object RPC
|
|
263
|
+
const doTransport = new DurableObjectTransport({
|
|
264
|
+
namespace: env.EMAIL_DO,
|
|
265
|
+
idGenerator: (req) => req.tenantId,
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
// Queue-based Events
|
|
269
|
+
const queueTransport = new QueueEventTransport({
|
|
270
|
+
queue: env.EVENTS_QUEUE,
|
|
271
|
+
});
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## Configuration
|
|
275
|
+
|
|
276
|
+
```typescript
|
|
277
|
+
import { mergeConfig, createDevConfig, createProdConfig } from "@parsrun/service";
|
|
278
|
+
|
|
279
|
+
// Development config
|
|
280
|
+
const devConfig = createDevConfig({
|
|
281
|
+
resilience: {
|
|
282
|
+
circuitBreaker: { enabled: false }, // Disable for debugging
|
|
283
|
+
},
|
|
284
|
+
tracing: {
|
|
285
|
+
enabled: true,
|
|
286
|
+
sampler: "always", // Trace everything
|
|
287
|
+
},
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
// Production config
|
|
291
|
+
const prodConfig = createProdConfig({
|
|
292
|
+
resilience: {
|
|
293
|
+
circuitBreaker: {
|
|
294
|
+
failureThreshold: 5,
|
|
295
|
+
resetTimeout: 30000,
|
|
296
|
+
},
|
|
297
|
+
bulkhead: {
|
|
298
|
+
maxConcurrent: 100,
|
|
299
|
+
},
|
|
300
|
+
},
|
|
301
|
+
tracing: {
|
|
302
|
+
enabled: true,
|
|
303
|
+
sampler: { ratio: 0.1 }, // Sample 10% of requests
|
|
304
|
+
},
|
|
305
|
+
});
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
## Sub-path Imports
|
|
309
|
+
|
|
310
|
+
```typescript
|
|
311
|
+
// Main entry (everything)
|
|
312
|
+
import { defineService, useService } from "@parsrun/service";
|
|
313
|
+
|
|
314
|
+
// Specific modules
|
|
315
|
+
import { RpcClient, RpcServer } from "@parsrun/service/rpc";
|
|
316
|
+
import { EventEmitter, MemoryEventTransport } from "@parsrun/service/events";
|
|
317
|
+
import { CircuitBreaker, withRetry } from "@parsrun/service/resilience";
|
|
318
|
+
import { Tracer, createTracer } from "@parsrun/service/tracing";
|
|
319
|
+
import { jsonSerializer } from "@parsrun/service/serialization";
|
|
320
|
+
import { WorkerRpcTransport } from "@parsrun/service/transports/cloudflare";
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
## API Reference
|
|
324
|
+
|
|
325
|
+
### Core
|
|
326
|
+
|
|
327
|
+
| Export | Description |
|
|
328
|
+
|--------|-------------|
|
|
329
|
+
| `defineService(def)` | Define a service with queries, mutations, events |
|
|
330
|
+
| `useService(name, options?)` | Get a service client |
|
|
331
|
+
| `ServiceRegistry` | Manage multiple service instances |
|
|
332
|
+
|
|
333
|
+
### RPC
|
|
334
|
+
|
|
335
|
+
| Export | Description |
|
|
336
|
+
|--------|-------------|
|
|
337
|
+
| `RpcClient` | Client for making RPC calls |
|
|
338
|
+
| `RpcServer` | Server for handling RPC requests |
|
|
339
|
+
| `EmbeddedTransport` | In-process transport (testing/monolith) |
|
|
340
|
+
| `HttpTransport` | HTTP-based transport |
|
|
341
|
+
| `createHttpHandler(server)` | Create HTTP request handler |
|
|
342
|
+
|
|
343
|
+
### Events
|
|
344
|
+
|
|
345
|
+
| Export | Description |
|
|
346
|
+
|--------|-------------|
|
|
347
|
+
| `EventEmitter` | Emit CloudEvents-compatible events |
|
|
348
|
+
| `EventHandlerRegistry` | Register event handlers |
|
|
349
|
+
| `MemoryEventTransport` | In-memory transport |
|
|
350
|
+
| `GlobalEventBus` | Cross-service event bus |
|
|
351
|
+
| `DeadLetterQueue` | Store failed events |
|
|
352
|
+
|
|
353
|
+
### Resilience
|
|
354
|
+
|
|
355
|
+
| Export | Description |
|
|
356
|
+
|--------|-------------|
|
|
357
|
+
| `CircuitBreaker` | Fail fast when service is unhealthy |
|
|
358
|
+
| `Bulkhead` | Limit concurrent requests |
|
|
359
|
+
| `withRetry(fn, options)` | Retry failed operations |
|
|
360
|
+
| `withTimeout(fn, ms)` | Add timeout to operations |
|
|
361
|
+
| `TimeoutExceededError` | Timeout error class |
|
|
362
|
+
|
|
363
|
+
### Tracing
|
|
364
|
+
|
|
365
|
+
| Export | Description |
|
|
366
|
+
|--------|-------------|
|
|
367
|
+
| `Tracer` | Main tracing class |
|
|
368
|
+
| `createTraceContext()` | Create W3C trace context |
|
|
369
|
+
| `ConsoleExporter` | Export spans to console |
|
|
370
|
+
| `OtlpExporter` | Export spans to OTLP endpoint |
|
|
371
|
+
| `SpanAttributes` | Standard span attribute names |
|
|
372
|
+
|
|
373
|
+
## License
|
|
374
|
+
|
|
375
|
+
MIT
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { b as ServiceDefinition, w as ServiceClientOptions, x as ServiceClient, S as ServiceConfig } from './types-n4LLSPQU.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @parsrun/service - Service Client
|
|
5
|
+
* High-level client API for consuming services
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Create a service client
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* // Embedded mode (same process)
|
|
14
|
+
* const payments = useService('payments');
|
|
15
|
+
*
|
|
16
|
+
* // HTTP mode (remote service)
|
|
17
|
+
* const payments = useService('payments', {
|
|
18
|
+
* mode: 'http',
|
|
19
|
+
* baseUrl: 'https://payments.example.com',
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* // Cloudflare binding mode
|
|
23
|
+
* const payments = useService('payments', {
|
|
24
|
+
* mode: 'binding',
|
|
25
|
+
* binding: env.PAYMENTS,
|
|
26
|
+
* });
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
declare function useService<TDef extends ServiceDefinition = ServiceDefinition>(serviceName: string, options?: ServiceClientOptions): ServiceClient<TDef>;
|
|
30
|
+
/**
|
|
31
|
+
* Create a typed service client from a definition
|
|
32
|
+
*/
|
|
33
|
+
declare function useTypedService<TDef extends ServiceDefinition>(definition: TDef, options?: ServiceClientOptions): ServiceClient<TDef>;
|
|
34
|
+
/**
|
|
35
|
+
* Service registry for managing multiple service clients
|
|
36
|
+
*/
|
|
37
|
+
declare class ServiceRegistry {
|
|
38
|
+
private readonly clients;
|
|
39
|
+
private readonly config;
|
|
40
|
+
constructor(config?: ServiceConfig);
|
|
41
|
+
/**
|
|
42
|
+
* Get or create a service client
|
|
43
|
+
*/
|
|
44
|
+
get<TDef extends ServiceDefinition = ServiceDefinition>(serviceName: string, options?: ServiceClientOptions): ServiceClient<TDef>;
|
|
45
|
+
/**
|
|
46
|
+
* Close all clients
|
|
47
|
+
*/
|
|
48
|
+
closeAll(): Promise<void>;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Create a service registry
|
|
52
|
+
*/
|
|
53
|
+
declare function createServiceRegistry(config?: ServiceConfig): ServiceRegistry;
|
|
54
|
+
|
|
55
|
+
export { ServiceRegistry, createServiceRegistry, useService, useTypedService };
|