@fraqjs/fraq 0.3.2 → 0.4.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/dist/index.d.mts +38 -7
- package/dist/index.mjs +50 -3
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -5540,23 +5540,26 @@ declare namespace filter {
|
|
|
5540
5540
|
}
|
|
5541
5541
|
//#endregion
|
|
5542
5542
|
//#region src/core/logging.d.ts
|
|
5543
|
+
type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
5543
5544
|
interface LogMessage {
|
|
5544
|
-
level:
|
|
5545
|
+
level: LogLevel;
|
|
5545
5546
|
module: string;
|
|
5546
5547
|
message: string;
|
|
5547
5548
|
error?: unknown;
|
|
5548
5549
|
time: number;
|
|
5549
5550
|
}
|
|
5551
|
+
type LogHandler = (message: LogMessage) => void;
|
|
5550
5552
|
declare class Logger {
|
|
5551
5553
|
private readonly logHandler;
|
|
5552
5554
|
private readonly module;
|
|
5553
|
-
constructor(logHandler:
|
|
5555
|
+
constructor(logHandler: LogHandler, module: string);
|
|
5554
5556
|
private log;
|
|
5555
5557
|
debug(message: string): void;
|
|
5556
5558
|
info(message: string): void;
|
|
5557
5559
|
warn(message: string, error?: unknown): void;
|
|
5558
5560
|
error(message: string, error?: unknown): void;
|
|
5559
5561
|
}
|
|
5562
|
+
declare function combineLogHandlers(...handlers: LogHandler[]): LogHandler;
|
|
5560
5563
|
//#endregion
|
|
5561
5564
|
//#region src/core/service.d.ts
|
|
5562
5565
|
/** biome-ignore-all lint/suspicious/noExplicitAny: Service constructors may accept any arguments. */
|
|
@@ -5564,13 +5567,31 @@ type ServiceClass<T extends object = object> = abstract new (...args: any[]) =>
|
|
|
5564
5567
|
//#endregion
|
|
5565
5568
|
//#region src/core/plugin.d.ts
|
|
5566
5569
|
type ParameterList = Array<any>;
|
|
5567
|
-
|
|
5570
|
+
type Injection = Record<string, ServiceClass>;
|
|
5571
|
+
type InjectedServices<I extends Injection | undefined> = I extends Injection
|
|
5572
|
+
? { [K in keyof I]: InstanceType<I[K]> }
|
|
5573
|
+
: {};
|
|
5574
|
+
type OptionalInjectedServices<I extends Injection | undefined> = I extends Injection
|
|
5575
|
+
? { [K in keyof I]: InstanceType<I[K]> | undefined }
|
|
5576
|
+
: {};
|
|
5577
|
+
interface Plugin<
|
|
5578
|
+
T extends ParameterList,
|
|
5579
|
+
I extends Injection | undefined,
|
|
5580
|
+
OI extends Injection | undefined = undefined,
|
|
5581
|
+
> {
|
|
5568
5582
|
name: string;
|
|
5569
5583
|
requires?: readonly ServiceClass[];
|
|
5584
|
+
inject?: I;
|
|
5585
|
+
optionalRequires?: readonly ServiceClass[];
|
|
5586
|
+
optionalInject?: OI;
|
|
5570
5587
|
provides?: readonly ServiceClass[];
|
|
5571
|
-
apply(ctx: Context
|
|
5588
|
+
apply(ctx: Context & InjectedServices<I> & OptionalInjectedServices<OI>, ...args: T): void | Promise<void>;
|
|
5572
5589
|
}
|
|
5573
|
-
declare function definePlugin<
|
|
5590
|
+
declare function definePlugin<
|
|
5591
|
+
T extends ParameterList,
|
|
5592
|
+
I extends Injection | undefined,
|
|
5593
|
+
OI extends Injection | undefined,
|
|
5594
|
+
>(plugin: Plugin<T, I, OI>): Plugin<T, I, OI>;
|
|
5574
5595
|
//#endregion
|
|
5575
5596
|
//#region src/core/context.d.ts
|
|
5576
5597
|
interface ContextOptions {
|
|
@@ -5578,7 +5599,7 @@ interface ContextOptions {
|
|
|
5578
5599
|
initialDelayMs?: number;
|
|
5579
5600
|
maxDelayMs?: number;
|
|
5580
5601
|
};
|
|
5581
|
-
logHandler?:
|
|
5602
|
+
logHandler?: LogHandler;
|
|
5582
5603
|
}
|
|
5583
5604
|
interface ContextUrlOptions {
|
|
5584
5605
|
accessToken?: string;
|
|
@@ -5600,7 +5621,10 @@ declare class Context {
|
|
|
5600
5621
|
private isStarted;
|
|
5601
5622
|
private constructor();
|
|
5602
5623
|
on<K extends keyof EventMap>(type: K, handler: (event: EventMap[K]) => void | Promise<void>): void;
|
|
5603
|
-
install<T extends ParameterList
|
|
5624
|
+
install<T extends ParameterList, I extends Injection | undefined, OI extends Injection | undefined>(
|
|
5625
|
+
plugin: Plugin<T, I, OI>,
|
|
5626
|
+
...args: T
|
|
5627
|
+
): void;
|
|
5604
5628
|
provide<T extends object>(service: ServiceClass<T>, instance: T): void;
|
|
5605
5629
|
resolve<T extends object>(service: ServiceClass<T>): T;
|
|
5606
5630
|
tryResolve<T extends object>(service: ServiceClass<T>): T | undefined;
|
|
@@ -5610,6 +5634,9 @@ declare class Context {
|
|
|
5610
5634
|
private acceptsParentEvent;
|
|
5611
5635
|
private applyPlugins;
|
|
5612
5636
|
private sortPlugins;
|
|
5637
|
+
private collectPendingProvidedServices;
|
|
5638
|
+
private areRequiredServicesAvailable;
|
|
5639
|
+
private areOptionalServicesReady;
|
|
5613
5640
|
private collectAvailableServices;
|
|
5614
5641
|
private createUnresolvablePluginError;
|
|
5615
5642
|
private createProxyContextForPlugin;
|
|
@@ -5666,6 +5693,9 @@ export {
|
|
|
5666
5693
|
ContextUrlOptions,
|
|
5667
5694
|
EventMap,
|
|
5668
5695
|
Filter,
|
|
5696
|
+
Injection,
|
|
5697
|
+
LogHandler,
|
|
5698
|
+
LogLevel,
|
|
5669
5699
|
LogMessage,
|
|
5670
5700
|
Logger,
|
|
5671
5701
|
MilkyClient,
|
|
@@ -5676,6 +5706,7 @@ export {
|
|
|
5676
5706
|
Router,
|
|
5677
5707
|
type ServiceClass,
|
|
5678
5708
|
Session,
|
|
5709
|
+
combineLogHandlers,
|
|
5679
5710
|
createMilkyClient,
|
|
5680
5711
|
definePlugin,
|
|
5681
5712
|
filter,
|
package/dist/index.mjs
CHANGED
|
@@ -300,6 +300,11 @@ var Logger = class {
|
|
|
300
300
|
this.log("error", message, error);
|
|
301
301
|
}
|
|
302
302
|
};
|
|
303
|
+
function combineLogHandlers(...handlers) {
|
|
304
|
+
return (message) => {
|
|
305
|
+
for (const handler of handlers) handler(message);
|
|
306
|
+
};
|
|
307
|
+
}
|
|
303
308
|
//#endregion
|
|
304
309
|
//#region src/core/service.ts
|
|
305
310
|
function getServiceName(service) {
|
|
@@ -414,7 +419,10 @@ var Context = class Context {
|
|
|
414
419
|
const available = /* @__PURE__ */ new Set();
|
|
415
420
|
for (const service of this.collectAvailableServices()) available.add(service);
|
|
416
421
|
while (pending.length > 0) {
|
|
417
|
-
const
|
|
422
|
+
const availableByPendingPlugins = this.collectPendingProvidedServices(pending);
|
|
423
|
+
const requiredReadyIndex = pending.findIndex(({ plugin }) => this.areRequiredServicesAvailable(plugin, available));
|
|
424
|
+
const optionalReadyIndex = pending.findIndex(({ plugin }) => this.areRequiredServicesAvailable(plugin, available) && this.areOptionalServicesReady(plugin, available, availableByPendingPlugins));
|
|
425
|
+
const nextIndex = optionalReadyIndex === -1 ? requiredReadyIndex : optionalReadyIndex;
|
|
418
426
|
if (nextIndex === -1) throw this.createUnresolvablePluginError(pending, available);
|
|
419
427
|
const [next] = pending.splice(nextIndex, 1);
|
|
420
428
|
sorted.push(next);
|
|
@@ -422,6 +430,21 @@ var Context = class Context {
|
|
|
422
430
|
}
|
|
423
431
|
return sorted;
|
|
424
432
|
}
|
|
433
|
+
collectPendingProvidedServices(pending) {
|
|
434
|
+
const providedServices = /* @__PURE__ */ new Map();
|
|
435
|
+
for (const installedPlugin of pending) for (const service of installedPlugin.plugin.provides ?? []) providedServices.set(service, installedPlugin);
|
|
436
|
+
return providedServices;
|
|
437
|
+
}
|
|
438
|
+
areRequiredServicesAvailable(plugin, available) {
|
|
439
|
+
return (plugin.requires ?? []).every((service) => available.has(service));
|
|
440
|
+
}
|
|
441
|
+
areOptionalServicesReady(plugin, available, pendingProviders) {
|
|
442
|
+
return (plugin.optionalRequires ?? []).every((service) => {
|
|
443
|
+
if (available.has(service)) return true;
|
|
444
|
+
const pendingProvider = pendingProviders.get(service);
|
|
445
|
+
return pendingProvider === void 0 || pendingProvider.plugin === plugin;
|
|
446
|
+
});
|
|
447
|
+
}
|
|
425
448
|
collectAvailableServices() {
|
|
426
449
|
const services = [...this.services.keys()];
|
|
427
450
|
if (this.parent) services.push(...this.parent.collectAvailableServices());
|
|
@@ -445,15 +468,27 @@ var Context = class Context {
|
|
|
445
468
|
}
|
|
446
469
|
createProxyContextForPlugin(plugin) {
|
|
447
470
|
const proxyLogger = new Logger((message) => this.logHandler?.(message), plugin.name);
|
|
471
|
+
let proxyInjections;
|
|
472
|
+
if (plugin.inject) {
|
|
473
|
+
proxyInjections = {};
|
|
474
|
+
for (const [key, service] of Object.entries(plugin.inject)) proxyInjections[key] = this.resolve(service);
|
|
475
|
+
}
|
|
476
|
+
if (plugin.optionalInject) {
|
|
477
|
+
proxyInjections ??= {};
|
|
478
|
+
for (const [key, service] of Object.entries(plugin.optionalInject)) proxyInjections[key] = this.tryResolve(service);
|
|
479
|
+
}
|
|
448
480
|
return new Proxy(this, { get(target, prop) {
|
|
449
481
|
if (prop === "logger") return proxyLogger;
|
|
482
|
+
else if (proxyInjections && prop in proxyInjections) return proxyInjections[prop];
|
|
450
483
|
else return target[prop];
|
|
451
484
|
} });
|
|
452
485
|
}
|
|
453
486
|
async runEventStream() {
|
|
454
487
|
let reconnectDelay = this.initialReconnectDelayMs;
|
|
488
|
+
let reconnectAttempt = 1;
|
|
455
489
|
while (this.isStarted) {
|
|
456
490
|
try {
|
|
491
|
+
this.logger.debug(`Connecting event stream (attempt=${reconnectAttempt})`);
|
|
457
492
|
const subscription = await this.client.startEvents((event) => {
|
|
458
493
|
try {
|
|
459
494
|
this.eventBus.emit(event.event_type, event);
|
|
@@ -461,13 +496,17 @@ var Context = class Context {
|
|
|
461
496
|
this.logger.error("Error handling event stream event", error);
|
|
462
497
|
}
|
|
463
498
|
});
|
|
499
|
+
this.logger.info("Event stream connected");
|
|
464
500
|
reconnectDelay = this.initialReconnectDelayMs;
|
|
501
|
+
reconnectAttempt = 1;
|
|
465
502
|
await subscription.closed;
|
|
503
|
+
this.logger.warn(`Event stream disconnected; reconnecting in ${reconnectDelay}ms`);
|
|
466
504
|
} catch (error) {
|
|
467
|
-
this.logger.error(
|
|
505
|
+
this.logger.error(`Error connecting event stream; reconnecting in ${reconnectDelay}ms`, error);
|
|
468
506
|
}
|
|
469
507
|
await new Promise((resolve) => setTimeout(resolve, reconnectDelay));
|
|
470
508
|
reconnectDelay = Math.min(reconnectDelay * 2, this.maxReconnectDelayMs);
|
|
509
|
+
reconnectAttempt += 1;
|
|
471
510
|
}
|
|
472
511
|
}
|
|
473
512
|
createSession(message) {
|
|
@@ -604,6 +643,14 @@ let filter;
|
|
|
604
643
|
//#endregion
|
|
605
644
|
//#region src/core/plugin.ts
|
|
606
645
|
function definePlugin(plugin) {
|
|
646
|
+
if (plugin.inject) {
|
|
647
|
+
if (plugin.requires) throw new Error(`Plugin "${plugin.name}" cannot have both "requires" and "inject" properties.`);
|
|
648
|
+
plugin.requires = Object.values(plugin.inject);
|
|
649
|
+
}
|
|
650
|
+
if (plugin.optionalInject) {
|
|
651
|
+
if (plugin.optionalRequires) throw new Error(`Plugin "${plugin.name}" cannot have both "optionalRequires" and "optionalInject" properties.`);
|
|
652
|
+
plugin.optionalRequires = Object.values(plugin.optionalInject);
|
|
653
|
+
}
|
|
607
654
|
return plugin;
|
|
608
655
|
}
|
|
609
656
|
//#endregion
|
|
@@ -866,4 +913,4 @@ let param;
|
|
|
866
913
|
_param.segment = segment;
|
|
867
914
|
})(param || (param = {}));
|
|
868
915
|
//#endregion
|
|
869
|
-
export { Context, Logger, Parameter, Router, createMilkyClient, definePlugin, filter, milkyPackageVersion, milkyVersion, msg, param, seg };
|
|
916
|
+
export { Context, Logger, Parameter, Router, combineLogHandlers, createMilkyClient, definePlugin, filter, milkyPackageVersion, milkyVersion, msg, param, seg };
|