react-runtime-pipe 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.
Files changed (42) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +624 -0
  3. package/build/action/compose.d.ts +7 -0
  4. package/build/action/defineAction.d.ts +2 -0
  5. package/build/action/executeAction.d.ts +6 -0
  6. package/build/action/index.d.ts +4 -0
  7. package/build/action/types.d.ts +48 -0
  8. package/build/action/utils.d.ts +1 -0
  9. package/build/app/container.d.ts +17 -0
  10. package/build/app/createApp.d.ts +21 -0
  11. package/build/app/index.d.ts +3 -0
  12. package/build/app/plugin.d.ts +10 -0
  13. package/build/cjs/index.js +1 -0
  14. package/build/cjs/middleware/index.js +1 -0
  15. package/build/cjs/plugin/index.js +1 -0
  16. package/build/cjs/react/index.js +1 -0
  17. package/build/esm/index.js +1 -0
  18. package/build/esm/middleware/index.js +1 -0
  19. package/build/esm/plugin/index.js +1 -0
  20. package/build/esm/react/index.js +1 -0
  21. package/build/index.d.ts +2 -0
  22. package/build/middleware/abort.d.ts +2 -0
  23. package/build/middleware/auth.d.ts +2 -0
  24. package/build/middleware/cache.d.ts +2 -0
  25. package/build/middleware/event.d.ts +2 -0
  26. package/build/middleware/index.d.ts +7 -0
  27. package/build/middleware/logger.d.ts +2 -0
  28. package/build/middleware/retry.d.ts +2 -0
  29. package/build/middleware/timing.d.ts +2 -0
  30. package/build/plugin/authPlugin.d.ts +2 -0
  31. package/build/plugin/cachePlugin.d.ts +2 -0
  32. package/build/plugin/devtoolsPlugin.d.ts +4 -0
  33. package/build/plugin/eventPlugin.d.ts +3 -0
  34. package/build/plugin/index.d.ts +6 -0
  35. package/build/plugin/loggerPlugin.d.ts +2 -0
  36. package/build/plugin/loggerPlusPlugin.d.ts +2 -0
  37. package/build/react/index.d.ts +4 -0
  38. package/build/react/provider.d.ts +7 -0
  39. package/build/react/useAction.d.ts +10 -0
  40. package/build/react/useEventBus.d.ts +2 -0
  41. package/build/react/useService.d.ts +2 -0
  42. package/package.json +130 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Delpi.Kye
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,624 @@
1
+ # ⚡ react-runtime-pipe
2
+
3
+ [![NPM](https://img.shields.io/npm/v/react-runtime-pipe.svg)](https://www.npmjs.com/package/react-runtime-pipe) ![Downloads](https://img.shields.io/npm/dt/react-runtime-pipe.svg) ![Bundle Size](https://img.shields.io/bundlephobia/minzip/react-runtime-pipe)
4
+
5
+ [LIVE EXAMPLE](https://codesandbox.io/p/sandbox/ps2sp8)
6
+
7
+ 🚀 A backend-inspired execution runtime for React applications.
8
+
9
+ > Build scalable frontend systems using middleware pipelines, typed actions, dependency injection, runtime context, plugins, orchestration, and event-driven execution.
10
+
11
+ ---
12
+
13
+ # Installation
14
+
15
+ ```bash
16
+ npm install react-runtime-pipe
17
+ ```
18
+
19
+ # What is react-runtime-pipe?
20
+
21
+ `react-runtime-pipe` is a lightweight runtime for executing backend-style logic in React applications.
22
+
23
+ It brings concepts like middleware, dependency injection, and orchestration into frontend code.
24
+
25
+ It provides:
26
+
27
+ - typed action execution
28
+ - middleware pipelines
29
+ - dependency injection
30
+ - runtime context
31
+ - plugins and event system
32
+ - retry and cancellation support
33
+
34
+ without enforcing any specific state management approach.
35
+
36
+ ---
37
+
38
+ # Why react-runtime-pipe?
39
+
40
+ Frontend apps often become hard to scale as logic spreads across components and async flows become inconsistent.
41
+
42
+ Common problems:
43
+
44
+ - business logic inside UI components
45
+ - duplicated async logic
46
+ - scattered dependencies
47
+ - tightly coupled side effects
48
+ - inconsistent orchestration
49
+
50
+ react-runtime-pipe solves this by introducing a structured execution layer:
51
+
52
+ - predictable execution flow
53
+ - composable middleware
54
+ - centralized orchestration
55
+ - backend-like architecture in frontend
56
+ - framework-agnostic design
57
+
58
+ ---
59
+
60
+ # Features
61
+
62
+ - ⚡ Runtime-first architecture
63
+ - 🧩 Middleware pipeline
64
+ - 🔌 Plugin system
65
+ - 🧠 Typed execution context
66
+ - 🛡 Action lifecycle hooks
67
+ - ♻️ Retry orchestration
68
+ - 📦 Dependency injection container
69
+ - 📡 Event bus system
70
+ - 📝 Full TypeScript inference
71
+ - 🚦 Abort/cancellation support
72
+ - 💾 Scoped execution cache
73
+ - ⚛️ React integration
74
+ - 🧱 Framework agnostic core
75
+
76
+ ---
77
+
78
+ # Mental Model
79
+
80
+ ```text
81
+ UI Event
82
+
83
+ useAction()
84
+
85
+ createExecutionContext()
86
+
87
+ Plugins
88
+
89
+ Middleware Pipeline
90
+
91
+ Action Handler
92
+
93
+ Service Layer
94
+
95
+ Event Bus
96
+
97
+ UI Update
98
+ ```
99
+
100
+ ---
101
+
102
+ # Quick Start
103
+
104
+ ## Create App
105
+
106
+ ```ts
107
+ // app.ts
108
+ import { createApp } from 'react-runtime-pipe'
109
+ import { loggerPlugin } from 'react-runtime-pipe/plugin'
110
+
111
+ import { ApiService } from './services/api'
112
+ import { ApiServiceToken } from './tokens'
113
+
114
+ export const app = createApp({
115
+ services: [
116
+ {
117
+ token: ApiServiceToken,
118
+ useValue: new ApiService(),
119
+ },
120
+ ],
121
+ })
122
+
123
+ app.plugin(loggerPlugin)
124
+
125
+ ```
126
+
127
+ ---
128
+
129
+ ## Define Action
130
+
131
+ ```ts
132
+ import { defineAction } from 'react-runtime-pipe'
133
+ import { globalEvents } from 'react-runtime-pipe/react'
134
+ import { logger, retry } from 'react-runtime-pipe/middleware'
135
+
136
+ import { ApiServiceToken } from './tokens'
137
+
138
+ export const saveUserAction = defineAction({
139
+ name: 'save-user',
140
+
141
+ middleware: [logger, retry(3)],
142
+
143
+ async handler({ input, context }) {
144
+ context.logger.info('saving user', input)
145
+
146
+ const api = context.container.resolve(ApiServiceToken)
147
+
148
+ const user = await api.saveUser(input)
149
+
150
+ // context.events.$emit('user:saved', user)
151
+ globalEvents.$emit('user:saved', user)
152
+
153
+ return {
154
+ success: true,
155
+ user,
156
+ }
157
+ },
158
+ })
159
+ ```
160
+
161
+ ---
162
+
163
+ ## Service Implementation
164
+
165
+ ```ts
166
+ // api.ts
167
+ import { createRequestId } from 'react-runtime-pipe'
168
+
169
+ export class ApiService {
170
+ async saveUser(input: any) {
171
+ await new Promise((resolve) => {
172
+ setTimeout(resolve, 500)
173
+ })
174
+
175
+ return {
176
+ id: createRequestId(),
177
+ input,
178
+ }
179
+ }
180
+ }
181
+ ```
182
+
183
+ ---
184
+
185
+ ## Tokens
186
+
187
+ ```ts
188
+ // tokens.ts
189
+ import { createToken } from 'react-runtime-pipe'
190
+
191
+ import type { ApiService } from './services/api'
192
+
193
+ export const ApiServiceToken =
194
+ createToken<ApiService>('ApiService')
195
+ ```
196
+
197
+ ---
198
+
199
+ ## React Usage
200
+
201
+ ```tsx
202
+ // Root.tsx
203
+ import React from 'react'
204
+
205
+ import {
206
+ useAction,
207
+ useEventBus,
208
+ globalEvents,
209
+ } from 'react-runtime-pipe/react'
210
+
211
+ import { saveUserAction } from './saveUser'
212
+
213
+ export function Root() {
214
+ const saveUser = useAction(saveUserAction)
215
+
216
+ useEventBus(
217
+ 'user:saved',
218
+ () => {
219
+ alert('User saved successfully!')
220
+ },
221
+ globalEvents,
222
+ )
223
+
224
+ return (
225
+ <div>
226
+ <button
227
+ disabled={saveUser.loading}
228
+ onClick={() => {
229
+ saveUser.execute({
230
+ name: 'Tung',
231
+ })
232
+ }}
233
+ >
234
+ {saveUser.loading
235
+ ? 'Saving...'
236
+ : 'Save User'}
237
+ </button>
238
+
239
+ {saveUser.error ? (
240
+ <pre>{String(saveUser.error)}</pre>
241
+ ) : null}
242
+ </div>
243
+ )
244
+ }
245
+ ```
246
+
247
+ ---
248
+
249
+ ## Bootstrap
250
+
251
+ ```tsx
252
+ // main.tsx
253
+ import React from 'react'
254
+ import ReactDOM from 'react-dom/client'
255
+
256
+ import { RuntimeProvider } from 'react-runtime-pipe/react'
257
+
258
+ import { Root } from './Root'
259
+ import { app } from './app'
260
+
261
+ async function bootstrap() {
262
+ await app.run()
263
+
264
+ const rootElement =
265
+ document.getElementById('root')
266
+
267
+ if (!rootElement) {
268
+ throw new Error(
269
+ 'Root element #root not found',
270
+ )
271
+ }
272
+
273
+ ReactDOM.createRoot(rootElement).render(
274
+ <React.StrictMode>
275
+ <RuntimeProvider app={app}>
276
+ <App />
277
+ </RuntimeProvider>
278
+ </React.StrictMode>,
279
+ )
280
+ }
281
+
282
+ bootstrap()
283
+ ```
284
+
285
+ ---
286
+
287
+ # Dependency Injection
288
+
289
+ ```ts
290
+ import { createApp, createToken } from 'react-runtime-pipe'
291
+
292
+ class ApiService {
293
+ async saveUser() {}
294
+ }
295
+
296
+ const ApiServiceToken = createToken<ApiService>('ApiService')
297
+
298
+ const app = createApp({
299
+ services: [
300
+ {
301
+ token: ApiServiceToken,
302
+ useFactory: () =>
303
+ new ApiService(),
304
+ },
305
+ ],
306
+ })
307
+ ```
308
+
309
+ ---
310
+
311
+ ## Service Injection in Actions
312
+
313
+ ```ts
314
+ import { defineAction } from 'react-runtime-pipe'
315
+
316
+ import { ApiServiceToken } from './tokens'
317
+
318
+ export const saveUserAction =
319
+ defineAction({
320
+ name: 'save-user',
321
+
322
+ async handler({
323
+ input,
324
+ context,
325
+ }) {
326
+ const api =
327
+ context.container.resolve(
328
+ ApiServiceToken,
329
+ )
330
+
331
+ return api.saveUser(input)
332
+ },
333
+ })
334
+ ```
335
+
336
+ ---
337
+
338
+ ## useService hook
339
+
340
+ ```tsx
341
+ import { useService } from 'react-runtime-pipe/react'
342
+
343
+ import { ApiServiceToken } from './tokens'
344
+
345
+ export function UserPage() {
346
+ const api = useService(ApiServiceToken)
347
+
348
+ return null
349
+ }
350
+ ```
351
+
352
+ ---
353
+
354
+ # Runtime Context
355
+
356
+ | Property | Description |
357
+ |---------------|--------------------------|
358
+ | ctx.requestId | execution request id |
359
+ | ctx.signal | abort signal |
360
+ | ctx.logger | runtime logger |
361
+ | ctx.container | dependency container |
362
+ | ctx.events | execution event bus |
363
+ | ctx.cache | scoped execution cache |
364
+ | ctx.auth | authenticated user state |
365
+
366
+ ---
367
+
368
+ # Event Bus
369
+
370
+ ## Emit Event
371
+
372
+ ```ts
373
+ globalEvents.$emit(
374
+ 'user:saved',
375
+ user,
376
+ )
377
+ ```
378
+
379
+ ---
380
+
381
+ ## Listen To Event
382
+
383
+ ```ts
384
+ useEventBus(
385
+ 'user:saved',
386
+ (payload) => {
387
+ console.log(payload)
388
+ },
389
+ globalEvents,
390
+ )
391
+ ```
392
+
393
+ ---
394
+
395
+ # Middleware
396
+
397
+ Middleware in `react-runtime-pipe` allows you to intercept and control the execution flow of an action.
398
+
399
+ Here is a simple example: **Abort Middleware** — used to stop execution if the request has been cancelled.
400
+
401
+ ```ts
402
+ import type { Middleware } from 'react-runtime-pipe'
403
+
404
+ export const abortMiddleware: Middleware = async ({
405
+ context,
406
+ next,
407
+ }) => {
408
+ // check before executing the handler
409
+ context.throwIfAborted()
410
+
411
+ const result = await next()
412
+
413
+ // check after the handler finishes
414
+ context.throwIfAborted()
415
+
416
+ return result
417
+ }
418
+ ```
419
+
420
+ This middleware ensures that if the user triggers an abort (e.g. cancels a request or unmounts a component), the action is immediately stopped both before and after execution.
421
+
422
+ ---
423
+
424
+ # Plugins
425
+
426
+ ```ts
427
+ import type { Plugin } from 'react-runtime-pipe'
428
+
429
+ const analyticsPlugin: Plugin = {
430
+ name: 'analytics',
431
+
432
+ setup({ app }) {
433
+ console.log('plugin setup')
434
+ },
435
+ }
436
+
437
+ app.plugin(analyticsPlugin)
438
+ ```
439
+
440
+ ---
441
+
442
+ # React Runtime Provider
443
+
444
+ ```tsx
445
+ import { RuntimeProvider } from 'react-runtime-pipe/react'
446
+
447
+ import { app } from './app'
448
+
449
+ export function Root() {
450
+ return (
451
+ <RuntimeProvider app={app}>
452
+ <App />
453
+ </RuntimeProvider>
454
+ )
455
+ }
456
+ ```
457
+
458
+ ---
459
+
460
+ # Action Lifecycle
461
+
462
+ ```text
463
+ useAction.execute()
464
+
465
+ createExecutionContext()
466
+
467
+ composeMiddleware()
468
+
469
+ executeHandler()
470
+
471
+ emitEvents()
472
+
473
+ returnResult()
474
+ ```
475
+
476
+ ---
477
+
478
+ # Execution Cache
479
+
480
+ ```ts
481
+ const cacheKey = 'user:1'
482
+
483
+ if (ctx.cache.has(cacheKey)) {
484
+ return ctx.cache.get(cacheKey)
485
+ }
486
+
487
+ const user = await api.getUser()
488
+
489
+ ctx.cache.set(cacheKey, user)
490
+
491
+ return user
492
+ ```
493
+
494
+ ---
495
+
496
+ # Abort Support
497
+
498
+ ```ts
499
+ ctx.throwIfAborted()
500
+ ```
501
+
502
+ ```ts
503
+ ctx.signal.addEventListener(
504
+ 'abort',
505
+ () => {
506
+ console.log('cancelled')
507
+ },
508
+ )
509
+ ```
510
+
511
+ ---
512
+
513
+ # Full Example
514
+
515
+ ```ts
516
+ import { defineAction } from 'react-runtime-pipe'
517
+
518
+ import {
519
+ logger,
520
+ retry,
521
+ auth,
522
+ } from 'react-runtime-pipe/middleware'
523
+
524
+ import { ApiServiceToken } from './tokens'
525
+
526
+ import { globalEvents } from './events'
527
+
528
+ export const saveUserAction =
529
+ defineAction({
530
+ name: 'save-user',
531
+
532
+ middleware: [
533
+ auth,
534
+ logger,
535
+ retry(),
536
+ ],
537
+
538
+ async handler({
539
+ input,
540
+ context,
541
+ }) {
542
+ const api =
543
+ context.container.resolve(
544
+ ApiServiceToken,
545
+ )
546
+
547
+ const user =
548
+ await api.saveUser(input)
549
+
550
+ globalEvents.$emit(
551
+ 'user:saved',
552
+ user,
553
+ )
554
+
555
+ return {
556
+ success: true,
557
+ user,
558
+ }
559
+ },
560
+ })
561
+ ```
562
+
563
+ ---
564
+
565
+ # Comparison
566
+
567
+ | Createria | Redux | React Query | react-runtime-pipe |
568
+ | -------------------- | ------ | ------------ | ------------------ |
569
+ | Middleware Pipeline | ✅ | ❌ | ✅ |
570
+ | Dependency Injection | ❌ | ❌ | ✅ |
571
+ | Runtime Context | ❌ | ❌ | ✅ |
572
+ | Event Bus | ❌ | ❌ | ✅ |
573
+ | Orchestration Layer | ❌ | ⚠️ | ✅ |
574
+ | Service Execution | ❌ | ⚠️ | ✅ |
575
+ | Plugin System | ❌ | ❌ | ✅ |
576
+
577
+ ---
578
+
579
+ # Philosophy
580
+
581
+ ```text
582
+ You control:
583
+ - middleware
584
+ - plugins
585
+ - orchestration
586
+ - architecture
587
+ - services
588
+
589
+ react-runtime-pipe controls:
590
+ - execution
591
+ - lifecycle
592
+ - context
593
+ - typing
594
+ - pipelines
595
+ ```
596
+
597
+ ---
598
+
599
+ # Design
600
+
601
+ - Explicit execution
602
+ - Composition over inheritance
603
+ - Backend-inspired architecture
604
+ - Runtime-first design
605
+ - Framework-agnostic core
606
+ - Deterministic orchestration
607
+
608
+ ---
609
+
610
+ # When to Use
611
+
612
+ - Large React applications
613
+ - Complex async flows
614
+ - Plugin-based frontends
615
+ - Runtime orchestration systems
616
+ - Event-driven UI architecture
617
+ - Shared business execution layers
618
+ - Backend/frontend unified patterns
619
+
620
+ ---
621
+
622
+ # License
623
+
624
+ MIT
@@ -0,0 +1,7 @@
1
+ import type { Middleware, RuntimeContext } from './types';
2
+ export declare function composeMiddleware<TInput, TResult>(params: {
3
+ middleware: Middleware<TInput, TResult>[];
4
+ execute(): Promise<TResult>;
5
+ input: TInput;
6
+ context: RuntimeContext;
7
+ }): Promise<TResult>;
@@ -0,0 +1,2 @@
1
+ import type { RuntimeAction } from './types';
2
+ export declare function defineAction<TInput, TResult>(action: RuntimeAction<TInput, TResult>): RuntimeAction<TInput, TResult>;
@@ -0,0 +1,6 @@
1
+ import type { RuntimeAction, RuntimeContext } from './types';
2
+ export declare function executeAction<TInput, TResult>(params: {
3
+ action: RuntimeAction<TInput, TResult>;
4
+ input: TInput;
5
+ context: RuntimeContext;
6
+ }): Promise<TResult>;
@@ -0,0 +1,4 @@
1
+ export * from './defineAction';
2
+ export * from './executeAction';
3
+ export * from './types';
4
+ export * from './utils';
@@ -0,0 +1,48 @@
1
+ import { createEventBus } from 'eventbus-z';
2
+ import type { RuntimeContainer } from '../app/container';
3
+ export type RuntimeLogger = {
4
+ info(message: string, meta?: unknown): void;
5
+ error(message: string, meta?: unknown): void;
6
+ };
7
+ export type RuntimeEventBus = ReturnType<typeof createEventBus>;
8
+ export type GlobalEventBus = ReturnType<typeof createEventBus>;
9
+ export type TypedRuntimeEventBus<TEvents extends Record<string, any[]>> = {
10
+ $emit<K extends keyof TEvents>(event: K, ...args: TEvents[K]): void;
11
+ $on<K extends keyof TEvents>(event: K, listener: (...args: TEvents[K]) => void): () => void;
12
+ $off?<K extends keyof TEvents>(event: K, listener?: (...args: TEvents[K]) => void): void;
13
+ $once?<K extends keyof TEvents>(event: K, listener: (...args: TEvents[K]) => void): void;
14
+ };
15
+ export type RuntimeContext = {
16
+ requestId: string;
17
+ signal: AbortSignal;
18
+ container: RuntimeContainer;
19
+ logger: RuntimeLogger;
20
+ events: RuntimeEventBus;
21
+ globalEvents?: GlobalEventBus;
22
+ cache: Map<string, unknown>;
23
+ auth?: {
24
+ userId: string;
25
+ };
26
+ throwIfAborted(): void;
27
+ };
28
+ export type ActionNext<TResult> = () => Promise<TResult>;
29
+ export type Middleware<TInput = unknown, TResult = unknown> = (params: {
30
+ input: TInput;
31
+ context: RuntimeContext;
32
+ next: ActionNext<TResult>;
33
+ }) => Promise<TResult>;
34
+ export type ActionHandler<TInput, TResult> = (params: {
35
+ input: TInput;
36
+ context: RuntimeContext;
37
+ }) => Promise<TResult>;
38
+ export type RuntimeAction<TInput, TResult> = {
39
+ name: string;
40
+ middleware?: Middleware<TInput, TResult>[];
41
+ retry?: {
42
+ attempts: number;
43
+ };
44
+ handler: ActionHandler<TInput, TResult>;
45
+ };
46
+ export type RuntimeSystem = {
47
+ globalEvents: GlobalEventBus;
48
+ };
@@ -0,0 +1 @@
1
+ export declare function createRequestId(): string;
@@ -0,0 +1,17 @@
1
+ export type Token<T = any> = symbol & {
2
+ __type?: T;
3
+ };
4
+ export declare function createToken<T>(description: string): Token<T>;
5
+ type Scope = 'singleton' | 'scoped';
6
+ type Provider<T> = {
7
+ scope?: Scope;
8
+ useValue?: T;
9
+ useFactory?: () => T;
10
+ };
11
+ export type RuntimeContainer = ReturnType<typeof createContainer>;
12
+ export declare function createContainer(): {
13
+ register<T>(token: Token<T>, provider: Provider<T>): void;
14
+ resolve<T>(token: Token<T>): T;
15
+ has<T>(token: Token<T>): boolean;
16
+ };
17
+ export {};
@@ -0,0 +1,21 @@
1
+ import { createContainer, type Token } from './container';
2
+ import type { Middleware, RuntimeContext } from '../action/types';
3
+ import type { Plugin } from './plugin';
4
+ export type ServiceProvider<T = any> = {
5
+ token: Token<T>;
6
+ useValue: T;
7
+ };
8
+ export type CreateAppOptions = {
9
+ services?: ServiceProvider[];
10
+ };
11
+ export type RuntimeApp = {
12
+ container: ReturnType<typeof createContainer>;
13
+ readonly plugins: Plugin[];
14
+ readonly middlewares: Middleware[];
15
+ initialized: boolean;
16
+ createContext(): Promise<Partial<RuntimeContext>>;
17
+ plugin(plugin: Plugin): RuntimeApp;
18
+ use(middleware: Middleware): RuntimeApp;
19
+ run(): Promise<void>;
20
+ };
21
+ export declare function createApp(options?: CreateAppOptions): RuntimeApp;
@@ -0,0 +1,3 @@
1
+ export * from './container';
2
+ export * from './createApp';
3
+ export * from './plugin';
@@ -0,0 +1,10 @@
1
+ import type { RuntimeContext } from '../action/types';
2
+ import type { RuntimeApp } from './createApp';
3
+ export type PluginContext = {
4
+ app: RuntimeApp;
5
+ };
6
+ export type Plugin = {
7
+ name: string;
8
+ setup?(context: PluginContext): void;
9
+ createContext?(): Promise<Partial<RuntimeContext>>;
10
+ };
@@ -0,0 +1 @@
1
+ "use strict";function e(){const e=new Map,t=new Map;return{register(n,r){t.set(n,r),r.useValue&&e.set(n,r.useValue)},resolve(n){if(e.has(n))return e.get(n);const r=t.get(n);if(!r)throw Error("Missing dependency: "+(n+""));if(r.useFactory){const t=r.useFactory();return"scoped"!==r.scope&&e.set(n,t),t}return r.useValue},has:e=>t.has(e)}}async function t(e){const{middleware:t,execute:n,input:r,context:o}=e;return async function e(c){const s=t[c];if(!s)return n();let i=!1;return s({input:r,context:o,next:async()=>{if(i)throw Error("next() already called");return i=!0,e(c+1)}})}(0)}exports.createApp=function(t={}){const n=e(),r=[],o=[];for(const e of t.services??[])n.register(e.token,{useValue:e.useValue});const c={container:n,plugins:r,middlewares:o,initialized:!1,async createContext(){let e={};for(const t of r){if(!t.createContext)continue;const n=await t.createContext();e={...e,...n}}return e},plugin:e=>(r.push(e),c),use:e=>(o.push(e),c),async run(){if(!c.initialized){c.initialized=!0;for(const e of r)await(e.setup?.({app:c}))}}};return c},exports.createContainer=e,exports.createRequestId=function(){return Array.from({length:16},()=>Math.floor(16*Math.random()).toString(16)).join("")},exports.createToken=function(e){return Symbol(e)},exports.defineAction=function(e){return e},exports.executeAction=async function(e){const{action:n,input:r,context:o}=e,c=n.retry?.attempts??1;let s;for(let e=0;e<c;e++)try{return await t({middleware:n.middleware??[],input:r,context:o,execute:async()=>(o.throwIfAborted(),n.handler({input:r,context:o}))})}catch(e){s=e}throw s};
@@ -0,0 +1 @@
1
+ "use strict";function e(){return"undefined"!=typeof performance?performance.now():Date.now()}exports.abortMiddleware=async({context:e,next:t})=>{e.throwIfAborted();const r=await t();return e.throwIfAborted(),r},exports.auth=function(){return async({context:e,next:t})=>{if(!e.auth?.userId)throw Error("Unauthorized");return t()}},exports.cacheMiddleware=async({context:e,next:t})=>{const r=e.requestId,o=e.cache.get(r);if(o)return e.logger.info("[cache:hit]",{key:r}),o;const n=await t();return e.cache.set(r,n),e.logger.info("[cache:set]",{key:r}),n},exports.eventMiddleware=async({context:e,next:t})=>{e.events?.$emit("action:start",{requestId:e.requestId});try{const r=await t();return e.events?.$emit("action:success",{requestId:e.requestId}),r}catch(t){throw e.events?.$emit("action:error",{requestId:e.requestId,error:t}),t}},exports.logger=async({context:e,input:t,next:r})=>{const o="undefined"!=typeof performance?performance.now():Date.now();e.logger.info("[action:start]",{requestId:e.requestId,input:t});try{const t=await r(),n="undefined"!=typeof performance?performance.now():Date.now();return e.logger.info("[action:success]",{requestId:e.requestId,duration:n-o}),t}catch(t){const r="undefined"!=typeof performance?performance.now():Date.now();throw e.logger.error("[action:error]",{requestId:e.requestId,duration:r-o,error:t instanceof Error?t.message:t}),t}},exports.retry=function(e=3){return async({context:t,next:r})=>{let o;for(let n=1;n<=e;n++)try{t.logger.info("[retry:attempt]",{requestId:t.requestId,attempt:n,max:e}),t.throwIfAborted();const o=await r();return n>1&&t.logger.info("[retry:success-after-retry]",{requestId:t.requestId,attempt:n}),o}catch(e){o=e,t.logger.error("[retry:fail]",{requestId:t.requestId,attempt:n,error:e}),t.events.$emit("retry:fail",{requestId:t.requestId,attempt:n,error:e})}throw t.logger.error("[retry:exhausted]",{requestId:t.requestId,attempts:e,error:o}),o}},exports.timing=async({context:t,next:r})=>{const o=e(),n=t.requestId;t.logger.info("[timing:start]",{requestId:n});try{const s=await r(),a=e()-o;return t.logger.info("[timing:success]",{requestId:n,duration:a}),t.events.$emit("timing",{requestId:n,duration:a}),s}catch(r){const s=e()-o;throw t.logger.error("[timing:error]",{requestId:n,duration:s,error:r}),r}};
@@ -0,0 +1 @@
1
+ "use strict";const e={name:"auth",createContext:async()=>({auth:await Promise.resolve({userId:"user_123"})})},t={name:"cache",createContext:async()=>({cache:new Map})},s="__EVENT_BUS_GLOBAL_SCOPE__",o=()=>(()=>{const e=(()=>{if("undefined"!=typeof window){try{if(window.top)return window.top.location.href,window.top}catch(e){}return window}return"undefined"!=typeof globalThis?globalThis:{}})();return e[s]||Object.defineProperty(e,s,{value:{},writable:!1,enumerable:!1,configurable:!1}),e[s]})(),c="evtBusZxp_scopeZxp",n="globalZxp_defaultName",a=(e,t=n)=>{const s=`${c}__${t}`;return e[s]||(e[s]=new Map),e[s]},i="eventBusRegister_"+c,r=(e,t,s)=>{var o;if(!t||"function"!=typeof s.callback)throw Error("Event name and callback are required");const c=null!==(o=s.scopeName)&&void 0!==o?o:n,r=a(e,c);r.has(t)||r.set(t,new Set);const l=r.get(t);s.single&&l.clear(),l.forEach(e=>{e.callback===s.callback&&l.delete(e)}),l.add(Object.assign({},s)),((e,t,s=n)=>{var o;const c=null!==(o=e[i])&&void 0!==o?o:{};c[s]||(c[s]=new Set),c[s].add(t),e[i]=c})(e,t,c)};function l(e,t){let s=-1;const o=c=>{if(c<=s)return;s=c;const i=e._middlewares[c];i?i(t,()=>o(c+1)):((e,t,s=n,...o)=>{const c=a(e,s).get(t);if(!c)return;const i=Date.now();c.forEach(e=>{e.once&&e.emitted||e.timeCached&&e.timeEffect&&i-e.timeEffect<e.timeCached||(e.callback(...o),e.emitted=!0,e.timeEffect=i)})})(e._scope,t.name,t.scopeName,...t.args)};o(0)}class h{constructor(e=o()){this._middlewares=[],this._isBatching=!1,this._queue=[],this.$use=e=>{this._middlewares.push(e)},this.$batch=e=>{this._isBatching=!0;try{e()}finally{this._isBatching=!1,function(e){const t=e._queue;for(let s=0;s<t.length;s++)l(e,t[s]);t.length=0}(this)}},this.$once=(e,t)=>{r(this._scope,e,{callback:t,once:!0})},this.$on=(e,t)=>{r(this._scope,e,{callback:t,single:!0})},this.$onMultiple=(e,t)=>{r(this._scope,e,{callback:t})},this.$onCached=(e,t,s=100)=>{r(this._scope,e,{callback:t,single:!0,timeCached:s})},this.$onCachedMultiple=(e,t,s=100)=>{r(this._scope,e,{callback:t,timeCached:s})},this.$emit=(e,...t)=>{const s={scopeName:n,name:e,args:t};this._isBatching?this._queue.push(s):l(this,s)},this.$off=(e,t)=>{const s=a(this._scope,n),o=s.get(e);o&&(t?o.forEach(e=>{e.callback===t&&o.delete(e)}):s.delete(e))},this.$offAll=e=>{a(this._scope,n).delete(e)},this.$destroy=()=>{!function(e){Object.keys(e).forEach(t=>{delete e[t]})}(this._scope)},this.$clearEventAcrossScopes=e=>{const t=(()=>{var e;return null!==(e=this._scope[i])&&void 0!==e?e:{}})();Object.keys(t).forEach(s=>{var o;(null===(o=t[s])||void 0===o?void 0:o.has(e))&&a(this._scope,s).delete(e)})},this.$scopeEmit=(e,t,...s)=>{const o={scopeName:e,name:t,args:s};this._isBatching?this._queue.push(o):l(this,o)},this.$scopeOn=(e,t,s)=>{r(this._scope,t,{callback:s,single:!0,scopeName:e})},this.$scopeOnce=(e,t,s)=>{r(this._scope,t,{callback:s,once:!0,scopeName:e})},this.$scopeOnMultiple=(e,t,s)=>{r(this._scope,t,{callback:s,scopeName:e})},this.$scopeOnCached=(e,t,s,o=100)=>{r(this._scope,t,{callback:s,single:!0,timeCached:o,scopeName:e})},this.$scopeOnCachedMultiple=(e,t,s,o=100)=>{r(this._scope,t,{callback:s,timeCached:o,scopeName:e})},this.$scopeOff=(e,t,s)=>{const o=a(this._scope,e),c=o.get(t);c&&(s?c.forEach(e=>{e.callback===s&&c.delete(e)}):o.delete(t))},this.$scopeOffAll=(e,t)=>{a(this._scope,e).delete(t)},this._scope=e}}function p(e,t){return new h(Object.create(null))}const u=p(),{$once:d,$on:f,$off:g,$offAll:m,$emit:$,$onCached:_,$onMultiple:b,$onCachedMultiple:w,$clearEventAcrossScopes:v,$destroy:y,$scopeOn:E,$scopeOnce:x,$scopeOnMultiple:O,$scopeOnCached:C,$scopeOnCachedMultiple:k,$scopeEmit:q,$scopeOff:I,$scopeOffAll:N}=u,M=p(),B={name:"event",createContext:async()=>({globalEvents:M}),setup({app:e}){e.use(async({context:e,next:t})=>{const s=e.globalEvents;s.$emit("action:start",{requestId:e.requestId});try{const o=await t();return s.$emit("action:success",{requestId:e.requestId}),o}catch(t){throw s.$emit("action:error",{requestId:e.requestId,error:t}),t}})}},P={name:"logger",createContext:async()=>({logger:{info:console.log,error:console.error}})},A={name:"logger",setup({app:e}){e.use(async({context:e,next:t})=>{const s="undefined"!=typeof performance?performance.now():Date.now(),o=e.requestId;e.logger.info("[action:start]",{requestId:o});const c=e.globalEvents;c?.$emit?.("action:start",{requestId:o});try{const n=await t(),a="undefined"!=typeof performance?performance.now():Date.now();return e.logger.info("[action:success]",{requestId:o,duration:a-s}),c?.$emit?.("action:success",{requestId:o,duration:a-s}),n}catch(t){const n="undefined"!=typeof performance?performance.now():Date.now();throw e.logger.error("[action:error]",{requestId:o,duration:n-s,error:t}),c?.$emit?.("action:error",{requestId:o,error:t}),t}})},createContext:async()=>({logger:{info:console.log,error:console.error},globalEvents:p()})};exports.authPlugin=e,exports.cachePlugin=t,exports.devtoolsPlugin=e=>({name:"devtools",setup({app:t}){e.enabled&&t.use(async({context:e,next:t})=>await t())}}),exports.eventPlugin=B,exports.globalEvents=M,exports.loggerAdvancePlugin=A,exports.loggerPlugin=P;
@@ -0,0 +1 @@
1
+ "use strict";var e=require("react/jsx-runtime"),t=require("react");const c=t.createContext(null);function n(){const e=t.useContext(c);if(!e)throw Error("Missing RuntimeProvider");return e}const o="__EVENT_BUS_GLOBAL_SCOPE__",s=()=>(()=>{const e=(()=>{if("undefined"!=typeof window){try{if(window.top)return window.top.location.href,window.top}catch(e){}return window}return"undefined"!=typeof globalThis?globalThis:{}})();return e[o]||Object.defineProperty(e,o,{value:{},writable:!1,enumerable:!1,configurable:!1}),e[o]})(),i="evtBusZxp_scopeZxp",r="globalZxp_defaultName",a=(e,t=r)=>{const c=`${i}__${t}`;return e[c]||(e[c]=new Map),e[c]},l="eventBusRegister_"+i,u=(e,t,c)=>{var n;if(!t||"function"!=typeof c.callback)throw Error("Event name and callback are required");const o=null!==(n=c.scopeName)&&void 0!==n?n:r,s=a(e,o);s.has(t)||s.set(t,new Set);const i=s.get(t);c.single&&i.clear(),i.forEach(e=>{e.callback===c.callback&&i.delete(e)}),i.add(Object.assign({},c)),((e,t,c=r)=>{var n;const o=null!==(n=e[l])&&void 0!==n?n:{};o[c]||(o[c]=new Set),o[c].add(t),e[l]=o})(e,t,o)};function h(e,t){let c=-1;const n=o=>{if(o<=c)return;c=o;const s=e._middlewares[o];s?s(t,()=>n(o+1)):((e,t,c=r,...n)=>{const o=a(e,c).get(t);if(!o)return;const s=Date.now();o.forEach(e=>{e.once&&e.emitted||e.timeCached&&e.timeEffect&&s-e.timeEffect<e.timeCached||(e.callback(...n),e.emitted=!0,e.timeEffect=s)})})(e._scope,t.name,t.scopeName,...t.args)};n(0)}class p{constructor(e=s()){this._middlewares=[],this._isBatching=!1,this._queue=[],this.$use=e=>{this._middlewares.push(e)},this.$batch=e=>{this._isBatching=!0;try{e()}finally{this._isBatching=!1,function(e){const t=e._queue;for(let c=0;c<t.length;c++)h(e,t[c]);t.length=0}(this)}},this.$once=(e,t)=>{u(this._scope,e,{callback:t,once:!0})},this.$on=(e,t)=>{u(this._scope,e,{callback:t,single:!0})},this.$onMultiple=(e,t)=>{u(this._scope,e,{callback:t})},this.$onCached=(e,t,c=100)=>{u(this._scope,e,{callback:t,single:!0,timeCached:c})},this.$onCachedMultiple=(e,t,c=100)=>{u(this._scope,e,{callback:t,timeCached:c})},this.$emit=(e,...t)=>{const c={scopeName:r,name:e,args:t};this._isBatching?this._queue.push(c):h(this,c)},this.$off=(e,t)=>{const c=a(this._scope,r),n=c.get(e);n&&(t?n.forEach(e=>{e.callback===t&&n.delete(e)}):c.delete(e))},this.$offAll=e=>{a(this._scope,r).delete(e)},this.$destroy=()=>{!function(e){Object.keys(e).forEach(t=>{delete e[t]})}(this._scope)},this.$clearEventAcrossScopes=e=>{const t=(()=>{var e;return null!==(e=this._scope[l])&&void 0!==e?e:{}})();Object.keys(t).forEach(c=>{var n;(null===(n=t[c])||void 0===n?void 0:n.has(e))&&a(this._scope,c).delete(e)})},this.$scopeEmit=(e,t,...c)=>{const n={scopeName:e,name:t,args:c};this._isBatching?this._queue.push(n):h(this,n)},this.$scopeOn=(e,t,c)=>{u(this._scope,t,{callback:c,single:!0,scopeName:e})},this.$scopeOnce=(e,t,c)=>{u(this._scope,t,{callback:c,once:!0,scopeName:e})},this.$scopeOnMultiple=(e,t,c)=>{u(this._scope,t,{callback:c,scopeName:e})},this.$scopeOnCached=(e,t,c,n=100)=>{u(this._scope,t,{callback:c,single:!0,timeCached:n,scopeName:e})},this.$scopeOnCachedMultiple=(e,t,c,n=100)=>{u(this._scope,t,{callback:c,timeCached:n,scopeName:e})},this.$scopeOff=(e,t,c)=>{const n=a(this._scope,e),o=n.get(t);o&&(c?o.forEach(e=>{e.callback===c&&o.delete(e)}):n.delete(t))},this.$scopeOffAll=(e,t)=>{a(this._scope,e).delete(t)},this._scope=e}}function d(e,t){return new p(Object.create(null))}const f=d(),{$once:m,$on:_,$off:$,$offAll:b,$emit:g,$onCached:w,$onMultiple:v,$onCachedMultiple:x,$clearEventAcrossScopes:E,$destroy:y,$scopeOn:O,$scopeOnce:k,$scopeOnMultiple:C,$scopeOnCached:M,$scopeOnCachedMultiple:A,$scopeEmit:N,$scopeOff:B,$scopeOffAll:S}=f;async function j(e){const{middleware:t,execute:c,input:n,context:o}=e;return async function e(s){const i=t[s];if(!i)return c();let r=!1;return i({input:n,context:o,next:async()=>{if(r)throw Error("next() already called");return r=!0,e(s+1)}})}(0)}const q=d();exports.RuntimeProvider=function(t){return e.jsx(c.Provider,{value:t.app,children:t.children})},exports.globalEvents=q,exports.useAction=function(e){const c=n(),o=t.useRef(null),[s,i]=t.useState(!1),[r,a]=t.useState(null),l=t.useMemo(()=>d(),[]);return{execute:async function(t){i(!0),a(null);const n=new AbortController;o.current=n;try{const o=await(c.createContext?.()),s=await async function(e){const{action:t,input:c,context:n}=e,o=t.retry?.attempts??1;let s;for(let e=0;e<o;e++)try{return await j({middleware:t.middleware??[],input:c,context:n,execute:async()=>(n.throwIfAborted(),t.handler({input:c,context:n}))})}catch(e){s=e}throw s}({action:e,input:t,context:{requestId:Array.from({length:16},()=>Math.floor(16*Math.random()).toString(16)).join(""),signal:n.signal,container:c.container,cache:new Map,events:l,logger:{info:console.log,error:console.error},throwIfAborted(){if(n.signal.aborted)throw Error("Action aborted")},...o}});return s}catch(e){throw a(e),e}finally{i(!1),o.current=null}},abort:function(){o.current?.abort()},loading:s,error:r,events:l,globalEvents:q}},exports.useEventBus=function(e,c,n=f){const o=t.useRef(c);o.current=c,t.useEffect(()=>{const t=(...e)=>{o.current(...e)};return n.$on(e,t),()=>{n.$off(e,t)}},[e,n])},exports.useRuntime=n,exports.useService=function(e){return n().container.resolve(e)};
@@ -0,0 +1 @@
1
+ function t(t){return Symbol(t)}function e(){const t=new Map,e=new Map;return{register(n,r){e.set(n,r),r.useValue&&t.set(n,r.useValue)},resolve(n){if(t.has(n))return t.get(n);const r=e.get(n);if(!r)throw Error("Missing dependency: "+(n+""));if(r.useFactory){const e=r.useFactory();return"scoped"!==r.scope&&t.set(n,e),e}return r.useValue},has:t=>e.has(t)}}function n(t={}){const n=e(),r=[],o=[];for(const e of t.services??[])n.register(e.token,{useValue:e.useValue});const i={container:n,plugins:r,middlewares:o,initialized:!1,async createContext(){let t={};for(const e of r){if(!e.createContext)continue;const n=await e.createContext();t={...t,...n}}return t},plugin:t=>(r.push(t),i),use:t=>(o.push(t),i),async run(){if(!i.initialized){i.initialized=!0;for(const t of r)await(t.setup?.({app:i}))}}};return i}function r(t){return t}async function o(t){const{middleware:e,execute:n,input:r,context:o}=t;return async function t(i){const c=e[i];if(!c)return n();let u=!1;return c({input:r,context:o,next:async()=>{if(u)throw Error("next() already called");return u=!0,t(i+1)}})}(0)}async function i(t){const{action:e,input:n,context:r}=t,i=e.retry?.attempts??1;let c;for(let t=0;t<i;t++)try{return await o({middleware:e.middleware??[],input:n,context:r,execute:async()=>(r.throwIfAborted(),e.handler({input:n,context:r}))})}catch(t){c=t}throw c}function c(){return Array.from({length:16},()=>Math.floor(16*Math.random()).toString(16)).join("")}export{n as createApp,e as createContainer,c as createRequestId,t as createToken,r as defineAction,i as executeAction};
@@ -0,0 +1 @@
1
+ const e=async({context:e,next:t})=>{e.throwIfAborted();const r=await t();return e.throwIfAborted(),r};function t(){return async({context:e,next:t})=>{if(!e.auth?.userId)throw Error("Unauthorized");return t()}}const r=async({context:e,next:t})=>{const r=e.requestId,n=e.cache.get(r);if(n)return e.logger.info("[cache:hit]",{key:r}),n;const o=await t();return e.cache.set(r,o),e.logger.info("[cache:set]",{key:r}),o},n=async({context:e,next:t})=>{e.events?.$emit("action:start",{requestId:e.requestId});try{const r=await t();return e.events?.$emit("action:success",{requestId:e.requestId}),r}catch(t){throw e.events?.$emit("action:error",{requestId:e.requestId,error:t}),t}},o=async({context:e,input:t,next:r})=>{const n="undefined"!=typeof performance?performance.now():Date.now();e.logger.info("[action:start]",{requestId:e.requestId,input:t});try{const t=await r(),o="undefined"!=typeof performance?performance.now():Date.now();return e.logger.info("[action:success]",{requestId:e.requestId,duration:o-n}),t}catch(t){const r="undefined"!=typeof performance?performance.now():Date.now();throw e.logger.error("[action:error]",{requestId:e.requestId,duration:r-n,error:t instanceof Error?t.message:t}),t}};function s(e=3){return async({context:t,next:r})=>{let n;for(let o=1;o<=e;o++)try{t.logger.info("[retry:attempt]",{requestId:t.requestId,attempt:o,max:e}),t.throwIfAborted();const n=await r();return o>1&&t.logger.info("[retry:success-after-retry]",{requestId:t.requestId,attempt:o}),n}catch(e){n=e,t.logger.error("[retry:fail]",{requestId:t.requestId,attempt:o,error:e}),t.events.$emit("retry:fail",{requestId:t.requestId,attempt:o,error:e})}throw t.logger.error("[retry:exhausted]",{requestId:t.requestId,attempts:e,error:n}),n}}function c(){return"undefined"!=typeof performance?performance.now():Date.now()}const a=async({context:e,next:t})=>{const r=c(),n=e.requestId;e.logger.info("[timing:start]",{requestId:n});try{const o=await t(),s=c()-r;return e.logger.info("[timing:success]",{requestId:n,duration:s}),e.events.$emit("timing",{requestId:n,duration:s}),o}catch(t){const o=c()-r;throw e.logger.error("[timing:error]",{requestId:n,duration:o,error:t}),t}};export{e as abortMiddleware,t as auth,r as cacheMiddleware,n as eventMiddleware,o as logger,s as retry,a as timing};
@@ -0,0 +1 @@
1
+ const e={name:"auth",createContext:async()=>({auth:await Promise.resolve({userId:"user_123"})})},t={name:"cache",createContext:async()=>({cache:new Map})},s=e=>({name:"devtools",setup({app:t}){e.enabled&&t.use(async({context:e,next:t})=>await t())}}),c="__EVENT_BUS_GLOBAL_SCOPE__",o=()=>(()=>{const e=(()=>{if("undefined"!=typeof window){try{if(window.top)return window.top.location.href,window.top}catch(e){}return window}return"undefined"!=typeof globalThis?globalThis:{}})();return e[c]||Object.defineProperty(e,c,{value:{},writable:!1,enumerable:!1,configurable:!1}),e[c]})(),n="evtBusZxp_scopeZxp",a="globalZxp_defaultName",i=(e,t=a)=>{const s=`${n}__${t}`;return e[s]||(e[s]=new Map),e[s]},r="eventBusRegister_"+n,l=(e,t,s)=>{var c;if(!t||"function"!=typeof s.callback)throw Error("Event name and callback are required");const o=null!==(c=s.scopeName)&&void 0!==c?c:a,n=i(e,o);n.has(t)||n.set(t,new Set);const l=n.get(t);s.single&&l.clear(),l.forEach(e=>{e.callback===s.callback&&l.delete(e)}),l.add(Object.assign({},s)),((e,t,s=a)=>{var c;const o=null!==(c=e[r])&&void 0!==c?c:{};o[s]||(o[s]=new Set),o[s].add(t),e[r]=o})(e,t,o)};function h(e,t){let s=-1;const c=o=>{if(o<=s)return;s=o;const n=e._middlewares[o];n?n(t,()=>c(o+1)):((e,t,s=a,...c)=>{const o=i(e,s).get(t);if(!o)return;const n=Date.now();o.forEach(e=>{e.once&&e.emitted||e.timeCached&&e.timeEffect&&n-e.timeEffect<e.timeCached||(e.callback(...c),e.emitted=!0,e.timeEffect=n)})})(e._scope,t.name,t.scopeName,...t.args)};c(0)}class p{constructor(e=o()){this._middlewares=[],this._isBatching=!1,this._queue=[],this.$use=e=>{this._middlewares.push(e)},this.$batch=e=>{this._isBatching=!0;try{e()}finally{this._isBatching=!1,function(e){const t=e._queue;for(let s=0;s<t.length;s++)h(e,t[s]);t.length=0}(this)}},this.$once=(e,t)=>{l(this._scope,e,{callback:t,once:!0})},this.$on=(e,t)=>{l(this._scope,e,{callback:t,single:!0})},this.$onMultiple=(e,t)=>{l(this._scope,e,{callback:t})},this.$onCached=(e,t,s=100)=>{l(this._scope,e,{callback:t,single:!0,timeCached:s})},this.$onCachedMultiple=(e,t,s=100)=>{l(this._scope,e,{callback:t,timeCached:s})},this.$emit=(e,...t)=>{const s={scopeName:a,name:e,args:t};this._isBatching?this._queue.push(s):h(this,s)},this.$off=(e,t)=>{const s=i(this._scope,a),c=s.get(e);c&&(t?c.forEach(e=>{e.callback===t&&c.delete(e)}):s.delete(e))},this.$offAll=e=>{i(this._scope,a).delete(e)},this.$destroy=()=>{!function(e){Object.keys(e).forEach(t=>{delete e[t]})}(this._scope)},this.$clearEventAcrossScopes=e=>{const t=(()=>{var e;return null!==(e=this._scope[r])&&void 0!==e?e:{}})();Object.keys(t).forEach(s=>{var c;(null===(c=t[s])||void 0===c?void 0:c.has(e))&&i(this._scope,s).delete(e)})},this.$scopeEmit=(e,t,...s)=>{const c={scopeName:e,name:t,args:s};this._isBatching?this._queue.push(c):h(this,c)},this.$scopeOn=(e,t,s)=>{l(this._scope,t,{callback:s,single:!0,scopeName:e})},this.$scopeOnce=(e,t,s)=>{l(this._scope,t,{callback:s,once:!0,scopeName:e})},this.$scopeOnMultiple=(e,t,s)=>{l(this._scope,t,{callback:s,scopeName:e})},this.$scopeOnCached=(e,t,s,c=100)=>{l(this._scope,t,{callback:s,single:!0,timeCached:c,scopeName:e})},this.$scopeOnCachedMultiple=(e,t,s,c=100)=>{l(this._scope,t,{callback:s,timeCached:c,scopeName:e})},this.$scopeOff=(e,t,s)=>{const c=i(this._scope,e),o=c.get(t);o&&(s?o.forEach(e=>{e.callback===s&&o.delete(e)}):c.delete(t))},this.$scopeOffAll=(e,t)=>{i(this._scope,e).delete(t)},this._scope=e}}function u(e,t){return new p(Object.create(null))}const d=u(),{$once:f,$on:m,$off:$,$offAll:g,$emit:_,$onCached:b,$onMultiple:w,$onCachedMultiple:y,$clearEventAcrossScopes:v,$destroy:E,$scopeOn:O,$scopeOnce:C,$scopeOnMultiple:k,$scopeOnCached:q,$scopeOnCachedMultiple:x,$scopeEmit:I,$scopeOff:N,$scopeOffAll:M}=d,B=u(),A={name:"event",createContext:async()=>({globalEvents:B}),setup({app:e}){e.use(async({context:e,next:t})=>{const s=e.globalEvents;s.$emit("action:start",{requestId:e.requestId});try{const c=await t();return s.$emit("action:success",{requestId:e.requestId}),c}catch(t){throw s.$emit("action:error",{requestId:e.requestId,error:t}),t}})}},S={name:"logger",createContext:async()=>({logger:{info:console.log,error:console.error}})},j={name:"logger",setup({app:e}){e.use(async({context:e,next:t})=>{const s="undefined"!=typeof performance?performance.now():Date.now(),c=e.requestId;e.logger.info("[action:start]",{requestId:c});const o=e.globalEvents;o?.$emit?.("action:start",{requestId:c});try{const n=await t(),a="undefined"!=typeof performance?performance.now():Date.now();return e.logger.info("[action:success]",{requestId:c,duration:a-s}),o?.$emit?.("action:success",{requestId:c,duration:a-s}),n}catch(t){const n="undefined"!=typeof performance?performance.now():Date.now();throw e.logger.error("[action:error]",{requestId:c,duration:n-s,error:t}),o?.$emit?.("action:error",{requestId:c,error:t}),t}})},createContext:async()=>({logger:{info:console.log,error:console.error},globalEvents:u()})};export{e as authPlugin,t as cachePlugin,s as devtoolsPlugin,A as eventPlugin,B as globalEvents,j as loggerAdvancePlugin,S as loggerPlugin};
@@ -0,0 +1 @@
1
+ import{jsx as e}from"react/jsx-runtime";import t,{createContext as c,useContext as n,useRef as o,useState as s,useMemo as i}from"react";const r=c(null);function a(t){return e(r.Provider,{value:t.app,children:t.children})}function l(){const e=n(r);if(!e)throw Error("Missing RuntimeProvider");return e}const h="__EVENT_BUS_GLOBAL_SCOPE__",u=()=>(()=>{const e=(()=>{if("undefined"!=typeof window){try{if(window.top)return window.top.location.href,window.top}catch(e){}return window}return"undefined"!=typeof globalThis?globalThis:{}})();return e[h]||Object.defineProperty(e,h,{value:{},writable:!1,enumerable:!1,configurable:!1}),e[h]})(),p="evtBusZxp_scopeZxp",f="globalZxp_defaultName",d=(e,t=f)=>{const c=`${p}__${t}`;return e[c]||(e[c]=new Map),e[c]},m="eventBusRegister_"+p,_=(e,t,c)=>{var n;if(!t||"function"!=typeof c.callback)throw Error("Event name and callback are required");const o=null!==(n=c.scopeName)&&void 0!==n?n:f,s=d(e,o);s.has(t)||s.set(t,new Set);const i=s.get(t);c.single&&i.clear(),i.forEach(e=>{e.callback===c.callback&&i.delete(e)}),i.add(Object.assign({},c)),((e,t,c=f)=>{var n;const o=null!==(n=e[m])&&void 0!==n?n:{};o[c]||(o[c]=new Set),o[c].add(t),e[m]=o})(e,t,o)};function $(e,t){let c=-1;const n=o=>{if(o<=c)return;c=o;const s=e._middlewares[o];s?s(t,()=>n(o+1)):((e,t,c=f,...n)=>{const o=d(e,c).get(t);if(!o)return;const s=Date.now();o.forEach(e=>{e.once&&e.emitted||e.timeCached&&e.timeEffect&&s-e.timeEffect<e.timeCached||(e.callback(...n),e.emitted=!0,e.timeEffect=s)})})(e._scope,t.name,t.scopeName,...t.args)};n(0)}class b{constructor(e=u()){this._middlewares=[],this._isBatching=!1,this._queue=[],this.$use=e=>{this._middlewares.push(e)},this.$batch=e=>{this._isBatching=!0;try{e()}finally{this._isBatching=!1,function(e){const t=e._queue;for(let c=0;c<t.length;c++)$(e,t[c]);t.length=0}(this)}},this.$once=(e,t)=>{_(this._scope,e,{callback:t,once:!0})},this.$on=(e,t)=>{_(this._scope,e,{callback:t,single:!0})},this.$onMultiple=(e,t)=>{_(this._scope,e,{callback:t})},this.$onCached=(e,t,c=100)=>{_(this._scope,e,{callback:t,single:!0,timeCached:c})},this.$onCachedMultiple=(e,t,c=100)=>{_(this._scope,e,{callback:t,timeCached:c})},this.$emit=(e,...t)=>{const c={scopeName:f,name:e,args:t};this._isBatching?this._queue.push(c):$(this,c)},this.$off=(e,t)=>{const c=d(this._scope,f),n=c.get(e);n&&(t?n.forEach(e=>{e.callback===t&&n.delete(e)}):c.delete(e))},this.$offAll=e=>{d(this._scope,f).delete(e)},this.$destroy=()=>{!function(e){Object.keys(e).forEach(t=>{delete e[t]})}(this._scope)},this.$clearEventAcrossScopes=e=>{const t=(()=>{var e;return null!==(e=this._scope[m])&&void 0!==e?e:{}})();Object.keys(t).forEach(c=>{var n;(null===(n=t[c])||void 0===n?void 0:n.has(e))&&d(this._scope,c).delete(e)})},this.$scopeEmit=(e,t,...c)=>{const n={scopeName:e,name:t,args:c};this._isBatching?this._queue.push(n):$(this,n)},this.$scopeOn=(e,t,c)=>{_(this._scope,t,{callback:c,single:!0,scopeName:e})},this.$scopeOnce=(e,t,c)=>{_(this._scope,t,{callback:c,once:!0,scopeName:e})},this.$scopeOnMultiple=(e,t,c)=>{_(this._scope,t,{callback:c,scopeName:e})},this.$scopeOnCached=(e,t,c,n=100)=>{_(this._scope,t,{callback:c,single:!0,timeCached:n,scopeName:e})},this.$scopeOnCachedMultiple=(e,t,c,n=100)=>{_(this._scope,t,{callback:c,timeCached:n,scopeName:e})},this.$scopeOff=(e,t,c)=>{const n=d(this._scope,e),o=n.get(t);o&&(c?o.forEach(e=>{e.callback===c&&o.delete(e)}):n.delete(t))},this.$scopeOffAll=(e,t)=>{d(this._scope,e).delete(t)},this._scope=e}}function g(e,t){return new b(Object.create(null))}const w=g(),{$once:y,$on:E,$off:v,$offAll:O,$emit:k,$onCached:x,$onMultiple:C,$onCachedMultiple:M,$clearEventAcrossScopes:A,$destroy:N,$scopeOn:B,$scopeOnce:j,$scopeOnMultiple:S,$scopeOnCached:q,$scopeOnCachedMultiple:P,$scopeEmit:I,$scopeOff:R,$scopeOffAll:T}=w;async function Z(e){const{middleware:t,execute:c,input:n,context:o}=e;return async function e(s){const i=t[s];if(!i)return c();let r=!1;return i({input:n,context:o,next:async()=>{if(r)throw Error("next() already called");return r=!0,e(s+1)}})}(0)}const L=g();function D(e){const t=l(),c=o(null),[n,r]=s(!1),[a,h]=s(null),u=i(()=>g(),[]);return{execute:async function(n){r(!0),h(null);const o=new AbortController;c.current=o;try{const c=await(t.createContext?.()),s=await async function(e){const{action:t,input:c,context:n}=e,o=t.retry?.attempts??1;let s;for(let e=0;e<o;e++)try{return await Z({middleware:t.middleware??[],input:c,context:n,execute:async()=>(n.throwIfAborted(),t.handler({input:c,context:n}))})}catch(e){s=e}throw s}({action:e,input:n,context:{requestId:Array.from({length:16},()=>Math.floor(16*Math.random()).toString(16)).join(""),signal:o.signal,container:t.container,cache:new Map,events:u,logger:{info:console.log,error:console.error},throwIfAborted(){if(o.signal.aborted)throw Error("Action aborted")},...c}});return s}catch(e){throw h(e),e}finally{r(!1),c.current=null}},abort:function(){c.current?.abort()},loading:n,error:a,events:u,globalEvents:L}}function G(e,c,n=w){const o=t.useRef(c);o.current=c,t.useEffect(()=>{const t=(...e)=>{o.current(...e)};return n.$on(e,t),()=>{n.$off(e,t)}},[e,n])}function U(e){return l().container.resolve(e)}export{a as RuntimeProvider,L as globalEvents,D as useAction,G as useEventBus,l as useRuntime,U as useService};
@@ -0,0 +1,2 @@
1
+ export * from './app';
2
+ export * from './action';
@@ -0,0 +1,2 @@
1
+ import type { Middleware } from '../action/types';
2
+ export declare const abortMiddleware: Middleware;
@@ -0,0 +1,2 @@
1
+ import type { Middleware } from '../action/types';
2
+ export declare function auth<TInput, TResult>(): Middleware<TInput, TResult>;
@@ -0,0 +1,2 @@
1
+ import type { Middleware } from '../action/types';
2
+ export declare const cacheMiddleware: Middleware;
@@ -0,0 +1,2 @@
1
+ import type { Middleware } from '../action/types';
2
+ export declare const eventMiddleware: Middleware;
@@ -0,0 +1,7 @@
1
+ export * from './abort';
2
+ export * from './auth';
3
+ export * from './cache';
4
+ export * from './event';
5
+ export * from './logger';
6
+ export * from './retry';
7
+ export * from './timing';
@@ -0,0 +1,2 @@
1
+ import type { Middleware } from '../action/types';
2
+ export declare const logger: Middleware;
@@ -0,0 +1,2 @@
1
+ import type { Middleware } from '../action/types';
2
+ export declare function retry<TInput, TResult>(count?: number): Middleware<TInput, TResult>;
@@ -0,0 +1,2 @@
1
+ import type { Middleware } from '../action/types';
2
+ export declare const timing: Middleware;
@@ -0,0 +1,2 @@
1
+ import type { Plugin } from '../app/plugin';
2
+ export declare const authPlugin: Plugin;
@@ -0,0 +1,2 @@
1
+ import type { Plugin } from '../app/plugin';
2
+ export declare const cachePlugin: Plugin;
@@ -0,0 +1,4 @@
1
+ import type { Plugin } from '../app/plugin';
2
+ export declare const devtoolsPlugin: (options: {
3
+ enabled: boolean;
4
+ }) => Plugin;
@@ -0,0 +1,3 @@
1
+ import type { Plugin } from '../app/plugin';
2
+ export declare const globalEvents: import("eventbus-z").GlobalBus<Record<string, any[]>, false>;
3
+ export declare const eventPlugin: Plugin;
@@ -0,0 +1,6 @@
1
+ export * from './authPlugin';
2
+ export * from './cachePlugin';
3
+ export * from './devtoolsPlugin';
4
+ export * from './eventPlugin';
5
+ export * from './loggerPlugin';
6
+ export * from './loggerPlusPlugin';
@@ -0,0 +1,2 @@
1
+ import type { Plugin } from '../app/plugin';
2
+ export declare const loggerPlugin: Plugin;
@@ -0,0 +1,2 @@
1
+ import type { Plugin } from '../app/plugin';
2
+ export declare const loggerAdvancePlugin: Plugin;
@@ -0,0 +1,4 @@
1
+ export * from './provider';
2
+ export * from './useAction';
3
+ export * from './useEventBus';
4
+ export * from './useService';
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ import type { RuntimeApp } from '../app/createApp';
3
+ export declare function RuntimeProvider(props: {
4
+ app: RuntimeApp;
5
+ children: React.ReactNode;
6
+ }): import("react/jsx-runtime").JSX.Element;
7
+ export declare function useRuntime(): RuntimeApp;
@@ -0,0 +1,10 @@
1
+ import type { RuntimeAction } from '../action/types';
2
+ export declare const globalEvents: import("eventbus-z").GlobalBus<Record<string, any[]>, false>;
3
+ export declare function useAction<TInput, TResult>(action: RuntimeAction<TInput, TResult>): {
4
+ execute: (input: TInput) => Promise<TResult>;
5
+ abort: () => void;
6
+ loading: boolean;
7
+ error: unknown;
8
+ events: import("eventbus-z").GlobalBus<Record<string, any[]>, false>;
9
+ globalEvents: import("eventbus-z").GlobalBus<Record<string, any[]>, false>;
10
+ };
@@ -0,0 +1,2 @@
1
+ import type { RuntimeEventBus } from '../action/types';
2
+ export declare function useEventBus(name: string, callback: (...args: any[]) => void, bus?: RuntimeEventBus): void;
@@ -0,0 +1,2 @@
1
+ import type { Token } from '../app/container';
2
+ export declare function useService<T>(token: Token<T>): T;
package/package.json ADDED
@@ -0,0 +1,130 @@
1
+ {
2
+ "name": "react-runtime-pipe",
3
+ "version": "0.1.0",
4
+ "description": "A backend-style runtime for React with middleware, DI, plugins, and structured action execution.",
5
+ "license": "MIT",
6
+ "author": "Delpi.Kye",
7
+ "sideEffects": false,
8
+ "type": "module",
9
+ "main": "./build/cjs/index.cjs",
10
+ "module": "./build/esm/index.js",
11
+ "types": "./build/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./build/index.d.ts",
15
+ "import": "./build/esm/index.js",
16
+ "require": "./build/cjs/index.cjs"
17
+ },
18
+ "./react": {
19
+ "types": "./build/react/index.d.ts",
20
+ "import": "./build/esm/react/index.js",
21
+ "require": "./build/cjs/react/index.js"
22
+ },
23
+ "./middleware": {
24
+ "types": "./build/middleware/index.d.ts",
25
+ "import": "./build/esm/middleware/index.js",
26
+ "require": "./build/cjs/middleware/index.js"
27
+ },
28
+ "./plugin": {
29
+ "types": "./build/plugin/index.d.ts",
30
+ "import": "./build/esm/plugin/index.js",
31
+ "require": "./build/cjs/plugin/index.js"
32
+ }
33
+ },
34
+ "files": [
35
+ "build",
36
+ "README.md",
37
+ "LICENSE"
38
+ ],
39
+ "scripts": {
40
+ "clean": "rimraf build",
41
+ "build": "rollup -c",
42
+ "cb": "npm run clean && npm run build",
43
+ "lint": "eslint \"src/**/*.{ts,tsx}\"",
44
+ "lint:fix": "eslint \"src/**/*.{ts,tsx}\" --fix",
45
+ "typecheck": "tsc --noEmit",
46
+ "prepublishOnly": "npm run clean && npm run lint && npm run typecheck && npm run build"
47
+ },
48
+ "repository": {
49
+ "type": "git",
50
+ "url": "git+https://github.com/delpikye-v/react-runtime-pipe.git"
51
+ },
52
+ "homepage": "https://github.com/delpikye-v/react-runtime-pipe#readme",
53
+ "bugs": {
54
+ "url": "https://github.com/delpikye-v/react-runtime-pipe/issues"
55
+ },
56
+ "funding": {
57
+ "type": "github",
58
+ "url": "https://github.com/sponsors/delpikye-v"
59
+ },
60
+ "keywords": [
61
+ "react",
62
+ "react-runtime",
63
+ "runtime",
64
+ "execution-runtime",
65
+ "execution-engine",
66
+ "action-runtime",
67
+ "middleware",
68
+ "middleware-pipeline",
69
+ "plugin-system",
70
+ "dependency-injection",
71
+ "di-container",
72
+ "orchestration",
73
+ "event-driven",
74
+ "event-bus",
75
+ "frontend-runtime",
76
+ "react-architecture",
77
+ "systems-design",
78
+ "runtime-context",
79
+ "typed-actions",
80
+ "typescript",
81
+ "frontend-framework",
82
+ "headless-runtime",
83
+ "async-flow",
84
+ "workflow-engine",
85
+ "react-hooks",
86
+ "react-state",
87
+ "react-patterns",
88
+ "state-orchestration",
89
+ "frontend-infrastructure",
90
+ "app-runtime",
91
+ "framework-agnostic"
92
+ ],
93
+ "peerDependencies": {
94
+ "react": "^18 || ^19",
95
+ "react-dom": "^18 || ^19"
96
+ },
97
+ "dependencies": {
98
+ "eventbus-z": "^2.4.0"
99
+ },
100
+ "devDependencies": {
101
+ "@rollup/plugin-commonjs": "^25.0.7",
102
+ "@rollup/plugin-json": "^6.1.0",
103
+ "@rollup/plugin-node-resolve": "^15.2.3",
104
+ "@rollup/plugin-terser": "^0.4.4",
105
+ "@types/node": "^25.5.0",
106
+ "@types/react": "^18.2.38",
107
+ "@types/react-dom": "^18.2.15",
108
+ "@typescript-eslint/eslint-plugin": "^6.21.0",
109
+ "@typescript-eslint/parser": "^6.21.0",
110
+ "eslint": "^8.57.1",
111
+ "eslint-config-prettier": "^10.1.8",
112
+ "eslint-plugin-import": "^2.32.0",
113
+ "eslint-plugin-prettier": "^5.5.5",
114
+ "eslint-plugin-simple-import-sort": "^13.0.0",
115
+ "eslint-plugin-unused-imports": "^4.4.1",
116
+ "prettier": "^3.8.1",
117
+ "react": "^18.2.0",
118
+ "react-dom": "^18.2.0",
119
+ "rimraf": "^5.0.5",
120
+ "rollup": "^4.12.0",
121
+ "rollup-plugin-peer-deps-external": "^2.2.4",
122
+ "rollup-plugin-typescript2": "^0.37.0",
123
+ "tslib": "^2.8.1",
124
+ "tsx": "^4.21.0",
125
+ "typescript": "^5.3.3"
126
+ },
127
+ "engines": {
128
+ "node": ">=18"
129
+ }
130
+ }