@fluojs/slack 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.ko.md +246 -0
- package/README.md +246 -0
- package/dist/channel.d.ts +24 -0
- package/dist/channel.d.ts.map +1 -0
- package/dist/channel.js +59 -0
- package/dist/errors.d.ts +19 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +29 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/module.d.ts +49 -0
- package/dist/module.d.ts.map +1 -0
- package/dist/module.js +133 -0
- package/dist/service.d.ts +79 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +261 -0
- package/dist/status.d.ts +27 -0
- package/dist/status.d.ts.map +1 -0
- package/dist/status.js +82 -0
- package/dist/tokens.d.ts +10 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +6 -0
- package/dist/types.d.ts +246 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/dist/webhook.d.ts +19 -0
- package/dist/webhook.d.ts.map +1 -0
- package/dist/webhook.js +166 -0
- package/package.json +54 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { SlackConfigurationError, SlackMessageValidationError, SlackTransportError } from './errors.js';
|
|
2
|
+
export { SlackChannel } from './channel.js';
|
|
3
|
+
export { SlackModule, createSlackProviders } from './module.js';
|
|
4
|
+
export { SlackService } from './service.js';
|
|
5
|
+
export { createSlackPlatformStatusSnapshot } from './status.js';
|
|
6
|
+
export { SLACK, SLACK_CHANNEL } from './tokens.js';
|
|
7
|
+
export { createSlackWebhookTransport } from './webhook.js';
|
package/dist/module.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Provider } from '@fluojs/di';
|
|
2
|
+
import { type ModuleType } from '@fluojs/runtime';
|
|
3
|
+
import type { SlackAsyncModuleOptions, SlackModuleOptions } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Creates Slack providers for manual module composition.
|
|
6
|
+
*
|
|
7
|
+
* @param options Static Slack module options including explicit transport wiring.
|
|
8
|
+
* @returns Provider definitions equivalent to {@link SlackModule.forRoot} wiring.
|
|
9
|
+
*/
|
|
10
|
+
export declare function createSlackProviders(options: SlackModuleOptions): Provider[];
|
|
11
|
+
/** Runtime module entrypoint for Slack delivery and notifications integration. */
|
|
12
|
+
export declare class SlackModule {
|
|
13
|
+
/**
|
|
14
|
+
* Registers Slack providers using static options.
|
|
15
|
+
*
|
|
16
|
+
* @param options Static Slack module options including transport wiring and optional template rendering behavior.
|
|
17
|
+
* @returns A global module definition that exports {@link SlackService}, {@link SlackChannel}, and compatibility tokens.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* SlackModule.forRoot({
|
|
22
|
+
* transport: createSlackWebhookTransport({ webhookUrl: 'https://hooks.slack.com/services/...' }),
|
|
23
|
+
* });
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
static forRoot(options: SlackModuleOptions): ModuleType;
|
|
27
|
+
/**
|
|
28
|
+
* Registers Slack providers from an async DI factory.
|
|
29
|
+
*
|
|
30
|
+
* @param options Async module options that resolve Slack transport and renderer configuration through DI.
|
|
31
|
+
* @returns A global module definition that memoizes async option resolution per module instance.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* SlackModule.forRootAsync({
|
|
36
|
+
* inject: [ConfigService],
|
|
37
|
+
* useFactory: (config) => ({
|
|
38
|
+
* defaultChannel: config.slack.channel,
|
|
39
|
+
* transport: createSlackWebhookTransport({
|
|
40
|
+
* fetch: config.runtime.fetch,
|
|
41
|
+
* webhookUrl: config.slack.webhookUrl,
|
|
42
|
+
* }),
|
|
43
|
+
* }),
|
|
44
|
+
* });
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
static forRootAsync(options: SlackAsyncModuleOptions): ModuleType;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAMhE,OAAO,KAAK,EAGV,uBAAuB,EACvB,kBAAkB,EAGnB,MAAM,YAAY,CAAC;AA0DpB;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,kBAAkB,GAAG,QAAQ,EAAE,CAK5E;AAsCD,kFAAkF;AAClF,qBAAa,WAAW;IACtB;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,kBAAkB,GAAG,UAAU;IAIvD;;;;;;;;;;;;;;;;;;;OAmBG;IACH,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,uBAAuB,GAAG,UAAU;CAGlE"}
|
package/dist/module.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { defineModule } from '@fluojs/runtime';
|
|
2
|
+
import { SlackConfigurationError } from './errors.js';
|
|
3
|
+
import { SlackChannel } from './channel.js';
|
|
4
|
+
import { SlackService } from './service.js';
|
|
5
|
+
import { SLACK, SLACK_CHANNEL, SLACK_OPTIONS } from './tokens.js';
|
|
6
|
+
function normalizeOptionalString(value) {
|
|
7
|
+
const trimmed = value?.trim();
|
|
8
|
+
return trimmed && trimmed.length > 0 ? trimmed : undefined;
|
|
9
|
+
}
|
|
10
|
+
function isTransportFactory(value) {
|
|
11
|
+
return typeof value === 'object' && value !== null && 'create' in value;
|
|
12
|
+
}
|
|
13
|
+
function normalizeSlackModuleOptions(options) {
|
|
14
|
+
if (!options.transport) {
|
|
15
|
+
throw new SlackConfigurationError('SlackModule requires an explicit `transport` to be configured.');
|
|
16
|
+
}
|
|
17
|
+
const transport = options.transport;
|
|
18
|
+
const createTransport = isTransportFactory(transport) ? async () => transport.create() : async () => transport;
|
|
19
|
+
return {
|
|
20
|
+
defaultChannel: normalizeOptionalString(options.defaultChannel),
|
|
21
|
+
notifications: {
|
|
22
|
+
channel: normalizeOptionalString(options.notifications?.channel) ?? 'slack'
|
|
23
|
+
},
|
|
24
|
+
renderer: options.renderer,
|
|
25
|
+
transport: {
|
|
26
|
+
create: createTransport,
|
|
27
|
+
kind: isTransportFactory(transport) ? normalizeOptionalString(transport.kind) ?? 'custom-factory' : 'custom-instance',
|
|
28
|
+
ownsResources: isTransportFactory(transport) ? transport.ownsResources ?? true : false
|
|
29
|
+
},
|
|
30
|
+
verifyOnModuleInit: options.verifyOnModuleInit ?? false
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function createSlackRuntimeProviders(optionsProvider) {
|
|
34
|
+
return [optionsProvider, SlackService, SlackChannel, {
|
|
35
|
+
inject: [SlackService],
|
|
36
|
+
provide: SLACK,
|
|
37
|
+
useFactory: service => ({
|
|
38
|
+
send: (message, options) => service.send(message, options),
|
|
39
|
+
sendMany: (messages, options) => service.sendMany(messages, options),
|
|
40
|
+
sendNotification: (notification, options) => service.sendNotification(notification, options)
|
|
41
|
+
})
|
|
42
|
+
}, {
|
|
43
|
+
inject: [SlackChannel],
|
|
44
|
+
provide: SLACK_CHANNEL,
|
|
45
|
+
useFactory: channel => channel
|
|
46
|
+
}];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Creates Slack providers for manual module composition.
|
|
51
|
+
*
|
|
52
|
+
* @param options Static Slack module options including explicit transport wiring.
|
|
53
|
+
* @returns Provider definitions equivalent to {@link SlackModule.forRoot} wiring.
|
|
54
|
+
*/
|
|
55
|
+
export function createSlackProviders(options) {
|
|
56
|
+
return createSlackRuntimeProviders({
|
|
57
|
+
provide: SLACK_OPTIONS,
|
|
58
|
+
useValue: normalizeSlackModuleOptions(options)
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
function buildSlackModule(options) {
|
|
62
|
+
class SlackRootModuleDefinition {}
|
|
63
|
+
return defineModule(SlackRootModuleDefinition, {
|
|
64
|
+
exports: [SlackService, SlackChannel, SLACK, SLACK_CHANNEL],
|
|
65
|
+
global: true,
|
|
66
|
+
providers: createSlackProviders(options)
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
function buildSlackModuleAsync(options) {
|
|
70
|
+
class SlackAsyncModuleDefinition {}
|
|
71
|
+
const factory = options.useFactory;
|
|
72
|
+
let cachedResult;
|
|
73
|
+
const memoizedFactory = (...deps) => {
|
|
74
|
+
if (!cachedResult) {
|
|
75
|
+
cachedResult = Promise.resolve(factory(...deps)).then(resolved => normalizeSlackModuleOptions(resolved));
|
|
76
|
+
}
|
|
77
|
+
return cachedResult;
|
|
78
|
+
};
|
|
79
|
+
return defineModule(SlackAsyncModuleDefinition, {
|
|
80
|
+
exports: [SlackService, SlackChannel, SLACK, SLACK_CHANNEL],
|
|
81
|
+
global: true,
|
|
82
|
+
providers: createSlackRuntimeProviders({
|
|
83
|
+
inject: options.inject,
|
|
84
|
+
provide: SLACK_OPTIONS,
|
|
85
|
+
scope: 'singleton',
|
|
86
|
+
useFactory: (...deps) => memoizedFactory(...deps)
|
|
87
|
+
})
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Runtime module entrypoint for Slack delivery and notifications integration. */
|
|
92
|
+
export class SlackModule {
|
|
93
|
+
/**
|
|
94
|
+
* Registers Slack providers using static options.
|
|
95
|
+
*
|
|
96
|
+
* @param options Static Slack module options including transport wiring and optional template rendering behavior.
|
|
97
|
+
* @returns A global module definition that exports {@link SlackService}, {@link SlackChannel}, and compatibility tokens.
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```ts
|
|
101
|
+
* SlackModule.forRoot({
|
|
102
|
+
* transport: createSlackWebhookTransport({ webhookUrl: 'https://hooks.slack.com/services/...' }),
|
|
103
|
+
* });
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
static forRoot(options) {
|
|
107
|
+
return buildSlackModule(options);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Registers Slack providers from an async DI factory.
|
|
112
|
+
*
|
|
113
|
+
* @param options Async module options that resolve Slack transport and renderer configuration through DI.
|
|
114
|
+
* @returns A global module definition that memoizes async option resolution per module instance.
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```ts
|
|
118
|
+
* SlackModule.forRootAsync({
|
|
119
|
+
* inject: [ConfigService],
|
|
120
|
+
* useFactory: (config) => ({
|
|
121
|
+
* defaultChannel: config.slack.channel,
|
|
122
|
+
* transport: createSlackWebhookTransport({
|
|
123
|
+
* fetch: config.runtime.fetch,
|
|
124
|
+
* webhookUrl: config.slack.webhookUrl,
|
|
125
|
+
* }),
|
|
126
|
+
* }),
|
|
127
|
+
* });
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
static forRootAsync(options) {
|
|
131
|
+
return buildSlackModuleAsync(options);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { OnApplicationShutdown, OnModuleInit } from '@fluojs/runtime';
|
|
2
|
+
import type { NormalizedSlackModuleOptions, Slack, SlackMessage, SlackNotificationDispatchRequest, SlackSendBatchResult, SlackSendManyOptions, SlackSendOptions, SlackSendResult } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Injectable Slack delivery service for standalone and notifications-backed usage.
|
|
5
|
+
*
|
|
6
|
+
* @remarks
|
|
7
|
+
* The service stays transport-agnostic at the shared package boundary, consumes only
|
|
8
|
+
* explicitly injected {@link SlackTransport} contracts, and translates
|
|
9
|
+
* `@fluojs/notifications` envelopes into concrete Slack messages.
|
|
10
|
+
*/
|
|
11
|
+
export declare class SlackService implements Slack, OnModuleInit, OnApplicationShutdown {
|
|
12
|
+
private readonly options;
|
|
13
|
+
private lifecycleState;
|
|
14
|
+
private resolvedTransport;
|
|
15
|
+
private transportPromise;
|
|
16
|
+
constructor(options: NormalizedSlackModuleOptions);
|
|
17
|
+
onApplicationShutdown(): Promise<void>;
|
|
18
|
+
onModuleInit(): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Creates a platform status snapshot for the active Slack transport wiring.
|
|
21
|
+
*
|
|
22
|
+
* @returns A structured snapshot describing lifecycle state, resource ownership, and notifications integration details.
|
|
23
|
+
*/
|
|
24
|
+
createPlatformStatusSnapshot(): import("./status.js").SlackPlatformStatusSnapshot;
|
|
25
|
+
/**
|
|
26
|
+
* Sends one Slack message directly through the configured transport.
|
|
27
|
+
*
|
|
28
|
+
* @param message Caller-supplied Slack message with text and/or block content.
|
|
29
|
+
* @param options Optional abort signal propagated to the transport.
|
|
30
|
+
* @returns A normalized delivery receipt describing the transport response.
|
|
31
|
+
* @throws {SlackMessageValidationError} When the resolved message does not include Slack-visible content.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* await slack.send({
|
|
36
|
+
* channel: '#ops',
|
|
37
|
+
* text: 'Deploy finished successfully.',
|
|
38
|
+
* });
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
send(message: SlackMessage, options?: SlackSendOptions): Promise<SlackSendResult>;
|
|
42
|
+
/**
|
|
43
|
+
* Sends multiple Slack messages in input order with optional tolerant failure handling.
|
|
44
|
+
*
|
|
45
|
+
* @param messages Ordered message list to deliver through the configured transport.
|
|
46
|
+
* @param options Optional tolerant batch controls such as `continueOnError`.
|
|
47
|
+
* @returns A batch summary containing successes and any captured failures.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```ts
|
|
51
|
+
* const result = await slack.sendMany(messages, { continueOnError: true });
|
|
52
|
+
* console.log(result.succeeded, result.failed);
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
sendMany(messages: readonly SlackMessage[], options?: SlackSendManyOptions): Promise<SlackSendBatchResult>;
|
|
56
|
+
/**
|
|
57
|
+
* Converts one notifications foundation request into a concrete Slack delivery.
|
|
58
|
+
*
|
|
59
|
+
* @param notification Shared notification envelope interpreted by the Slack package.
|
|
60
|
+
* @param options Optional abort signal propagated to rendering and transport work.
|
|
61
|
+
* @returns A normalized delivery receipt for the resulting Slack message.
|
|
62
|
+
* @throws {SlackMessageValidationError} When the notification cannot resolve one target channel or any Slack-visible content.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```ts
|
|
66
|
+
* await slack.sendNotification({
|
|
67
|
+
* channel: 'slack',
|
|
68
|
+
* payload: { text: 'Deploy finished successfully.' },
|
|
69
|
+
* recipients: ['#ops'],
|
|
70
|
+
* });
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
sendNotification(notification: SlackNotificationDispatchRequest, options?: SlackSendOptions): Promise<SlackSendResult>;
|
|
74
|
+
private ensureTransport;
|
|
75
|
+
private normalizeMessage;
|
|
76
|
+
private resolveNotificationChannel;
|
|
77
|
+
private renderNotification;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAK3E,OAAO,KAAK,EAEV,4BAA4B,EAC5B,KAAK,EACL,YAAY,EACZ,gCAAgC,EAChC,oBAAoB,EAEpB,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,EAGhB,MAAM,YAAY,CAAC;AAqBpB;;;;;;;GAOG;AACH,qBACa,YAAa,YAAW,KAAK,EAAE,YAAY,EAAE,qBAAqB;IAKjE,OAAO,CAAC,QAAQ,CAAC,OAAO;IAJpC,OAAO,CAAC,cAAc,CAAmF;IACzG,OAAO,CAAC,iBAAiB,CAA6B;IACtD,OAAO,CAAC,gBAAgB,CAAsC;gBAEjC,OAAO,EAAE,4BAA4B;IAE5D,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAetC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBnC;;;;OAIG;IACH,4BAA4B;IAW5B;;;;;;;;;;;;;;;OAeG;IACG,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,eAAe,CAAC;IAqB3F;;;;;;;;;;;;OAYG;IACG,QAAQ,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,EAAE,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IA6BpH;;;;;;;;;;;;;;;;OAgBG;IACG,gBAAgB,CACpB,YAAY,EAAE,gCAAgC,EAC9C,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,eAAe,CAAC;YA6Bb,eAAe;IAe7B,OAAO,CAAC,gBAAgB;IAkBxB,OAAO,CAAC,0BAA0B;YAkBpB,kBAAkB;CAejC"}
|
package/dist/service.js
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
let _initClass;
|
|
2
|
+
function _applyDecs(e, t, n, r, o, i) { var a, c, u, s, f, l, p, d = Symbol.metadata || Symbol.for("Symbol.metadata"), m = Object.defineProperty, h = Object.create, y = [h(null), h(null)], v = t.length; function g(t, n, r) { return function (o, i) { n && (i = o, o = e); for (var a = 0; a < t.length; a++) i = t[a].apply(o, r ? [i] : []); return r ? i : o; }; } function b(e, t, n, r) { if ("function" != typeof e && (r || void 0 !== e)) throw new TypeError(t + " must " + (n || "be") + " a function" + (r ? "" : " or undefined")); return e; } function applyDec(e, t, n, r, o, i, u, s, f, l, p) { function d(e) { if (!p(e)) throw new TypeError("Attempted to access private element on non-instance"); } var h = [].concat(t[0]), v = t[3], w = !u, D = 1 === o, S = 3 === o, j = 4 === o, E = 2 === o; function I(t, n, r) { return function (o, i) { return n && (i = o, o = e), r && r(o), P[t].call(o, i); }; } if (!w) { var P = {}, k = [], F = S ? "get" : j || D ? "set" : "value"; if (f ? (l || D ? P = { get: _setFunctionName(function () { return v(this); }, r, "get"), set: function (e) { t[4](this, e); } } : P[F] = v, l || _setFunctionName(P[F], r, E ? "" : F)) : l || (P = Object.getOwnPropertyDescriptor(e, r)), !l && !f) { if ((c = y[+s][r]) && 7 !== (c ^ o)) throw Error("Decorating two elements with the same name (" + P[F].name + ") is not supported yet"); y[+s][r] = o < 3 ? 1 : o; } } for (var N = e, O = h.length - 1; O >= 0; O -= n ? 2 : 1) { var T = b(h[O], "A decorator", "be", !0), z = n ? h[O - 1] : void 0, A = {}, H = { kind: ["field", "accessor", "method", "getter", "setter", "class"][o], name: r, metadata: a, addInitializer: function (e, t) { if (e.v) throw new TypeError("attempted to call addInitializer after decoration was finished"); b(t, "An initializer", "be", !0), i.push(t); }.bind(null, A) }; if (w) c = T.call(z, N, H), A.v = 1, b(c, "class decorators", "return") && (N = c);else if (H.static = s, H.private = f, c = H.access = { has: f ? p.bind() : function (e) { return r in e; } }, j || (c.get = f ? E ? function (e) { return d(e), P.value; } : I("get", 0, d) : function (e) { return e[r]; }), E || S || (c.set = f ? I("set", 0, d) : function (e, t) { e[r] = t; }), N = T.call(z, D ? { get: P.get, set: P.set } : P[F], H), A.v = 1, D) { if ("object" == typeof N && N) (c = b(N.get, "accessor.get")) && (P.get = c), (c = b(N.set, "accessor.set")) && (P.set = c), (c = b(N.init, "accessor.init")) && k.unshift(c);else if (void 0 !== N) throw new TypeError("accessor decorators must return an object with get, set, or init properties or undefined"); } else b(N, (l ? "field" : "method") + " decorators", "return") && (l ? k.unshift(N) : P[F] = N); } return o < 2 && u.push(g(k, s, 1), g(i, s, 0)), l || w || (f ? D ? u.splice(-1, 0, I("get", s), I("set", s)) : u.push(E ? P[F] : b.call.bind(P[F])) : m(e, r, P)), N; } function w(e) { return m(e, d, { configurable: !0, enumerable: !0, value: a }); } return void 0 !== i && (a = i[d]), a = h(null == a ? null : a), f = [], l = function (e) { e && f.push(g(e)); }, p = function (t, r) { for (var i = 0; i < n.length; i++) { var a = n[i], c = a[1], l = 7 & c; if ((8 & c) == t && !l == r) { var p = a[2], d = !!a[3], m = 16 & c; applyDec(t ? e : e.prototype, a, m, d ? "#" + p : _toPropertyKey(p), l, l < 2 ? [] : t ? s = s || [] : u = u || [], f, !!t, d, r, t && d ? function (t) { return _checkInRHS(t) === e; } : o); } } }, p(8, 0), p(0, 0), p(8, 1), p(0, 1), l(u), l(s), c = f, v || w(e), { e: c, get c() { var n = []; return v && [w(e = applyDec(e, [t], r, e.name, 5, n)), g(n, 1)]; } }; }
|
|
3
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
4
|
+
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
5
|
+
function _setFunctionName(e, t, n) { "symbol" == typeof t && (t = (t = t.description) ? "[" + t + "]" : ""); try { Object.defineProperty(e, "name", { configurable: !0, value: n ? n + " " + t : t }); } catch (e) {} return e; }
|
|
6
|
+
function _checkInRHS(e) { if (Object(e) !== e) throw TypeError("right-hand side of 'in' should be an object, got " + (null !== e ? typeof e : "null")); return e; }
|
|
7
|
+
import { Inject } from '@fluojs/core';
|
|
8
|
+
import { SlackMessageValidationError } from './errors.js';
|
|
9
|
+
import { createSlackPlatformStatusSnapshot } from './status.js';
|
|
10
|
+
import { SLACK_OPTIONS } from './tokens.js';
|
|
11
|
+
function createAbortError() {
|
|
12
|
+
const error = new Error('Slack delivery was aborted.');
|
|
13
|
+
error.name = 'AbortError';
|
|
14
|
+
return error;
|
|
15
|
+
}
|
|
16
|
+
function normalizeOptionalString(value) {
|
|
17
|
+
const trimmed = value?.trim();
|
|
18
|
+
return trimmed && trimmed.length > 0 ? trimmed : undefined;
|
|
19
|
+
}
|
|
20
|
+
function assertMessageContent(message) {
|
|
21
|
+
if (!message.text && message.blocks.length === 0 && message.attachments.length === 0) {
|
|
22
|
+
throw new SlackMessageValidationError('Slack messages require `text`, `blocks`, or `attachments` content.');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Injectable Slack delivery service for standalone and notifications-backed usage.
|
|
28
|
+
*
|
|
29
|
+
* @remarks
|
|
30
|
+
* The service stays transport-agnostic at the shared package boundary, consumes only
|
|
31
|
+
* explicitly injected {@link SlackTransport} contracts, and translates
|
|
32
|
+
* `@fluojs/notifications` envelopes into concrete Slack messages.
|
|
33
|
+
*/
|
|
34
|
+
let _SlackService;
|
|
35
|
+
class SlackService {
|
|
36
|
+
static {
|
|
37
|
+
[_SlackService, _initClass] = _applyDecs(this, [Inject(SLACK_OPTIONS)], []).c;
|
|
38
|
+
}
|
|
39
|
+
lifecycleState = 'created';
|
|
40
|
+
resolvedTransport;
|
|
41
|
+
transportPromise;
|
|
42
|
+
constructor(options) {
|
|
43
|
+
this.options = options;
|
|
44
|
+
}
|
|
45
|
+
async onApplicationShutdown() {
|
|
46
|
+
this.lifecycleState = 'stopping';
|
|
47
|
+
try {
|
|
48
|
+
if (this.resolvedTransport && this.options.transport.ownsResources && this.resolvedTransport.close) {
|
|
49
|
+
await this.resolvedTransport.close();
|
|
50
|
+
}
|
|
51
|
+
this.lifecycleState = 'stopped';
|
|
52
|
+
} catch {
|
|
53
|
+
this.lifecycleState = 'failed';
|
|
54
|
+
throw new Error('Slack transport failed to close cleanly.');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async onModuleInit() {
|
|
58
|
+
this.lifecycleState = 'starting';
|
|
59
|
+
try {
|
|
60
|
+
const transport = await this.ensureTransport();
|
|
61
|
+
if (this.options.verifyOnModuleInit && transport.verify) {
|
|
62
|
+
await transport.verify();
|
|
63
|
+
}
|
|
64
|
+
this.lifecycleState = 'ready';
|
|
65
|
+
} catch {
|
|
66
|
+
this.lifecycleState = 'failed';
|
|
67
|
+
throw new Error('Slack transport failed to initialize.');
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Creates a platform status snapshot for the active Slack transport wiring.
|
|
73
|
+
*
|
|
74
|
+
* @returns A structured snapshot describing lifecycle state, resource ownership, and notifications integration details.
|
|
75
|
+
*/
|
|
76
|
+
createPlatformStatusSnapshot() {
|
|
77
|
+
return createSlackPlatformStatusSnapshot({
|
|
78
|
+
channelName: this.options.notifications.channel,
|
|
79
|
+
defaultChannelConfigured: this.options.defaultChannel !== undefined,
|
|
80
|
+
lifecycleState: this.lifecycleState,
|
|
81
|
+
ownsTransportResources: this.options.transport.ownsResources,
|
|
82
|
+
transportKind: this.options.transport.kind,
|
|
83
|
+
verifiedOnModuleInit: this.options.verifyOnModuleInit
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Sends one Slack message directly through the configured transport.
|
|
89
|
+
*
|
|
90
|
+
* @param message Caller-supplied Slack message with text and/or block content.
|
|
91
|
+
* @param options Optional abort signal propagated to the transport.
|
|
92
|
+
* @returns A normalized delivery receipt describing the transport response.
|
|
93
|
+
* @throws {SlackMessageValidationError} When the resolved message does not include Slack-visible content.
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```ts
|
|
97
|
+
* await slack.send({
|
|
98
|
+
* channel: '#ops',
|
|
99
|
+
* text: 'Deploy finished successfully.',
|
|
100
|
+
* });
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
async send(message, options = {}) {
|
|
104
|
+
if (options.signal?.aborted) {
|
|
105
|
+
throw createAbortError();
|
|
106
|
+
}
|
|
107
|
+
const transport = await this.ensureTransport();
|
|
108
|
+
const normalized = this.normalizeMessage(message);
|
|
109
|
+
assertMessageContent(normalized);
|
|
110
|
+
const result = await transport.send(normalized, options);
|
|
111
|
+
return {
|
|
112
|
+
channel: result.channel ?? normalized.channel,
|
|
113
|
+
messageTs: result.messageTs,
|
|
114
|
+
metadata: result.metadata,
|
|
115
|
+
ok: result.ok ?? true,
|
|
116
|
+
response: result.response,
|
|
117
|
+
statusCode: result.statusCode,
|
|
118
|
+
warnings: result.warnings ?? []
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Sends multiple Slack messages in input order with optional tolerant failure handling.
|
|
124
|
+
*
|
|
125
|
+
* @param messages Ordered message list to deliver through the configured transport.
|
|
126
|
+
* @param options Optional tolerant batch controls such as `continueOnError`.
|
|
127
|
+
* @returns A batch summary containing successes and any captured failures.
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```ts
|
|
131
|
+
* const result = await slack.sendMany(messages, { continueOnError: true });
|
|
132
|
+
* console.log(result.succeeded, result.failed);
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
async sendMany(messages, options = {}) {
|
|
136
|
+
const results = [];
|
|
137
|
+
const failures = [];
|
|
138
|
+
for (const message of messages) {
|
|
139
|
+
try {
|
|
140
|
+
results.push(await this.send(message, options));
|
|
141
|
+
} catch (error) {
|
|
142
|
+
const failure = {
|
|
143
|
+
error: error instanceof Error ? error : new Error('Slack delivery failed.'),
|
|
144
|
+
message
|
|
145
|
+
};
|
|
146
|
+
if (!(options.continueOnError ?? false)) {
|
|
147
|
+
throw failure.error;
|
|
148
|
+
}
|
|
149
|
+
failures.push(failure);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return {
|
|
153
|
+
failed: failures.length,
|
|
154
|
+
failures,
|
|
155
|
+
results,
|
|
156
|
+
succeeded: results.length
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Converts one notifications foundation request into a concrete Slack delivery.
|
|
162
|
+
*
|
|
163
|
+
* @param notification Shared notification envelope interpreted by the Slack package.
|
|
164
|
+
* @param options Optional abort signal propagated to rendering and transport work.
|
|
165
|
+
* @returns A normalized delivery receipt for the resulting Slack message.
|
|
166
|
+
* @throws {SlackMessageValidationError} When the notification cannot resolve one target channel or any Slack-visible content.
|
|
167
|
+
*
|
|
168
|
+
* @example
|
|
169
|
+
* ```ts
|
|
170
|
+
* await slack.sendNotification({
|
|
171
|
+
* channel: 'slack',
|
|
172
|
+
* payload: { text: 'Deploy finished successfully.' },
|
|
173
|
+
* recipients: ['#ops'],
|
|
174
|
+
* });
|
|
175
|
+
* ```
|
|
176
|
+
*/
|
|
177
|
+
async sendNotification(notification, options = {}) {
|
|
178
|
+
const payload = notification.payload;
|
|
179
|
+
const rendered = await this.renderNotification(notification);
|
|
180
|
+
return this.send({
|
|
181
|
+
attachments: payload.attachments ?? rendered?.attachments,
|
|
182
|
+
blocks: payload.blocks ?? rendered?.blocks,
|
|
183
|
+
channel: this.resolveNotificationChannel(notification),
|
|
184
|
+
iconEmoji: payload.iconEmoji,
|
|
185
|
+
iconUrl: payload.iconUrl,
|
|
186
|
+
metadata: {
|
|
187
|
+
...(payload.metadata ?? {}),
|
|
188
|
+
...(notification.metadata ?? {}),
|
|
189
|
+
...(notification.subject ? {
|
|
190
|
+
subject: notification.subject
|
|
191
|
+
} : {}),
|
|
192
|
+
...(notification.template ? {
|
|
193
|
+
template: notification.template
|
|
194
|
+
} : {})
|
|
195
|
+
},
|
|
196
|
+
mrkdwn: payload.mrkdwn,
|
|
197
|
+
replyBroadcast: payload.replyBroadcast,
|
|
198
|
+
text: payload.text ?? rendered?.text ?? notification.subject,
|
|
199
|
+
threadTs: payload.threadTs,
|
|
200
|
+
unfurlLinks: payload.unfurlLinks,
|
|
201
|
+
unfurlMedia: payload.unfurlMedia,
|
|
202
|
+
username: payload.username
|
|
203
|
+
}, options);
|
|
204
|
+
}
|
|
205
|
+
async ensureTransport() {
|
|
206
|
+
if (this.resolvedTransport) {
|
|
207
|
+
return this.resolvedTransport;
|
|
208
|
+
}
|
|
209
|
+
if (!this.transportPromise) {
|
|
210
|
+
this.transportPromise = this.options.transport.create().then(transport => {
|
|
211
|
+
this.resolvedTransport = transport;
|
|
212
|
+
return transport;
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
return this.transportPromise;
|
|
216
|
+
}
|
|
217
|
+
normalizeMessage(message) {
|
|
218
|
+
return {
|
|
219
|
+
attachments: message.attachments ?? [],
|
|
220
|
+
blocks: message.blocks ?? [],
|
|
221
|
+
channel: normalizeOptionalString(message.channel) ?? this.options.defaultChannel,
|
|
222
|
+
iconEmoji: normalizeOptionalString(message.iconEmoji),
|
|
223
|
+
iconUrl: normalizeOptionalString(message.iconUrl),
|
|
224
|
+
metadata: message.metadata,
|
|
225
|
+
mrkdwn: message.mrkdwn,
|
|
226
|
+
replyBroadcast: message.replyBroadcast,
|
|
227
|
+
text: normalizeOptionalString(message.text),
|
|
228
|
+
threadTs: normalizeOptionalString(message.threadTs),
|
|
229
|
+
unfurlLinks: message.unfurlLinks,
|
|
230
|
+
unfurlMedia: message.unfurlMedia,
|
|
231
|
+
username: normalizeOptionalString(message.username)
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
resolveNotificationChannel(notification) {
|
|
235
|
+
const payloadChannel = normalizeOptionalString(notification.payload.channel);
|
|
236
|
+
if (payloadChannel) {
|
|
237
|
+
return payloadChannel;
|
|
238
|
+
}
|
|
239
|
+
const recipients = notification.recipients?.map(entry => entry.trim()).filter(entry => entry.length > 0) ?? [];
|
|
240
|
+
if (recipients.length > 1) {
|
|
241
|
+
throw new SlackMessageValidationError('Slack notifications accept exactly one target channel per dispatch. Use `sendMany(...)` for fan-out delivery.');
|
|
242
|
+
}
|
|
243
|
+
return recipients[0] ?? this.options.defaultChannel;
|
|
244
|
+
}
|
|
245
|
+
async renderNotification(notification) {
|
|
246
|
+
if (!notification.template || !this.options.renderer) {
|
|
247
|
+
return undefined;
|
|
248
|
+
}
|
|
249
|
+
return this.options.renderer.render({
|
|
250
|
+
locale: notification.locale,
|
|
251
|
+
metadata: notification.metadata,
|
|
252
|
+
payload: notification.payload,
|
|
253
|
+
subject: notification.subject,
|
|
254
|
+
template: notification.template
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
static {
|
|
258
|
+
_initClass();
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
export { _SlackService as SlackService };
|
package/dist/status.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { PlatformHealthReport, PlatformReadinessReport, PlatformSnapshot } from '@fluojs/runtime';
|
|
2
|
+
/** Resolved Slack lifecycle state used for diagnostics and health checks. */
|
|
3
|
+
export type SlackLifecycleState = 'created' | 'starting' | 'ready' | 'stopping' | 'stopped' | 'failed';
|
|
4
|
+
/** Input required to describe the package health/readiness contract. */
|
|
5
|
+
export interface SlackStatusAdapterInput {
|
|
6
|
+
channelName: string;
|
|
7
|
+
defaultChannelConfigured: boolean;
|
|
8
|
+
lifecycleState: SlackLifecycleState;
|
|
9
|
+
ownsTransportResources: boolean;
|
|
10
|
+
transportKind: string;
|
|
11
|
+
verifiedOnModuleInit: boolean;
|
|
12
|
+
}
|
|
13
|
+
/** Structured snapshot returned by {@link createSlackPlatformStatusSnapshot}. */
|
|
14
|
+
export interface SlackPlatformStatusSnapshot {
|
|
15
|
+
details: Record<string, unknown>;
|
|
16
|
+
health: PlatformHealthReport;
|
|
17
|
+
ownership: PlatformSnapshot['ownership'];
|
|
18
|
+
readiness: PlatformReadinessReport;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Creates a health/readiness snapshot for the Slack delivery layer.
|
|
22
|
+
*
|
|
23
|
+
* @param input Lifecycle and ownership details derived from the active Slack module wiring.
|
|
24
|
+
* @returns A structured snapshot suitable for status endpoints and operational diagnostics.
|
|
25
|
+
*/
|
|
26
|
+
export declare function createSlackPlatformStatusSnapshot(input: SlackStatusAdapterInput): SlackPlatformStatusSnapshot;
|
|
27
|
+
//# sourceMappingURL=status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../src/status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEvG,6EAA6E;AAC7E,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,UAAU,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEvG,wEAAwE;AACxE,MAAM,WAAW,uBAAuB;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,wBAAwB,EAAE,OAAO,CAAC;IAClC,cAAc,EAAE,mBAAmB,CAAC;IACpC,sBAAsB,EAAE,OAAO,CAAC;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,oBAAoB,EAAE,OAAO,CAAC;CAC/B;AAED,iFAAiF;AACjF,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,MAAM,EAAE,oBAAoB,CAAC;IAC7B,SAAS,EAAE,gBAAgB,CAAC,WAAW,CAAC,CAAC;IACzC,SAAS,EAAE,uBAAuB,CAAC;CACpC;AA6DD;;;;;GAKG;AACH,wBAAgB,iCAAiC,CAAC,KAAK,EAAE,uBAAuB,GAAG,2BAA2B,CAiB7G"}
|
package/dist/status.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/** Resolved Slack lifecycle state used for diagnostics and health checks. */
|
|
2
|
+
|
|
3
|
+
/** Input required to describe the package health/readiness contract. */
|
|
4
|
+
|
|
5
|
+
/** Structured snapshot returned by {@link createSlackPlatformStatusSnapshot}. */
|
|
6
|
+
|
|
7
|
+
function createReadiness(input) {
|
|
8
|
+
if (input.lifecycleState === 'ready') {
|
|
9
|
+
return {
|
|
10
|
+
critical: true,
|
|
11
|
+
status: 'ready'
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
if (input.lifecycleState === 'starting') {
|
|
15
|
+
return {
|
|
16
|
+
critical: true,
|
|
17
|
+
reason: 'Slack transport is still starting.',
|
|
18
|
+
status: 'degraded'
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
if (input.lifecycleState === 'stopping' || input.lifecycleState === 'stopped') {
|
|
22
|
+
return {
|
|
23
|
+
critical: true,
|
|
24
|
+
reason: 'Slack transport is shutting down or already stopped.',
|
|
25
|
+
status: 'not-ready'
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
if (input.lifecycleState === 'failed') {
|
|
29
|
+
return {
|
|
30
|
+
critical: true,
|
|
31
|
+
reason: 'Slack transport failed to initialize.',
|
|
32
|
+
status: 'not-ready'
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
critical: true,
|
|
37
|
+
reason: 'Slack transport has not started yet.',
|
|
38
|
+
status: 'not-ready'
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function createHealth(input) {
|
|
42
|
+
if (input.lifecycleState === 'failed' || input.lifecycleState === 'stopped') {
|
|
43
|
+
return {
|
|
44
|
+
reason: 'Slack transport is unavailable.',
|
|
45
|
+
status: 'unhealthy'
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
if (input.lifecycleState === 'created' || input.lifecycleState === 'starting' || input.lifecycleState === 'stopping') {
|
|
49
|
+
return {
|
|
50
|
+
reason: 'Slack transport is transitioning lifecycle state.',
|
|
51
|
+
status: 'degraded'
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
status: 'healthy'
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Creates a health/readiness snapshot for the Slack delivery layer.
|
|
61
|
+
*
|
|
62
|
+
* @param input Lifecycle and ownership details derived from the active Slack module wiring.
|
|
63
|
+
* @returns A structured snapshot suitable for status endpoints and operational diagnostics.
|
|
64
|
+
*/
|
|
65
|
+
export function createSlackPlatformStatusSnapshot(input) {
|
|
66
|
+
return {
|
|
67
|
+
details: {
|
|
68
|
+
channelName: input.channelName,
|
|
69
|
+
defaultChannelConfigured: input.defaultChannelConfigured,
|
|
70
|
+
dependencies: ['notifications.channel', 'slack.transport'],
|
|
71
|
+
lifecycleState: input.lifecycleState,
|
|
72
|
+
transportKind: input.transportKind,
|
|
73
|
+
verifiedOnModuleInit: input.verifiedOnModuleInit
|
|
74
|
+
},
|
|
75
|
+
health: createHealth(input),
|
|
76
|
+
ownership: {
|
|
77
|
+
externallyManaged: !input.ownsTransportResources,
|
|
78
|
+
ownsResources: input.ownsTransportResources
|
|
79
|
+
},
|
|
80
|
+
readiness: createReadiness(input)
|
|
81
|
+
};
|
|
82
|
+
}
|
package/dist/tokens.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Token } from '@fluojs/core';
|
|
2
|
+
import type { NotificationChannel } from '@fluojs/notifications';
|
|
3
|
+
import type { NormalizedSlackModuleOptions, Slack, SlackNotificationDispatchRequest } from './types.js';
|
|
4
|
+
/** Compatibility token for the facade returned by {@link SlackModule.forRoot}. */
|
|
5
|
+
export declare const SLACK: Token<Slack>;
|
|
6
|
+
/** Injection token for the channel implementation consumed by `@fluojs/notifications`. */
|
|
7
|
+
export declare const SLACK_CHANNEL: Token<NotificationChannel<SlackNotificationDispatchRequest>>;
|
|
8
|
+
/** Injection token for normalized Slack module options consumed internally by providers. */
|
|
9
|
+
export declare const SLACK_OPTIONS: Token<NormalizedSlackModuleOptions>;
|
|
10
|
+
//# sourceMappingURL=tokens.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAEjE,OAAO,KAAK,EAAE,4BAA4B,EAAE,KAAK,EAAE,gCAAgC,EAAE,MAAM,YAAY,CAAC;AAExG,kFAAkF;AAClF,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,KAAK,CAA4B,CAAC;AAC5D,0FAA0F;AAC1F,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,mBAAmB,CAAC,gCAAgC,CAAC,CAAoC,CAAC;AAC5H,4FAA4F;AAC5F,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,4BAA4B,CAAoC,CAAC"}
|