@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 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
@@ -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 };