@backstage/plugin-events-backend 0.0.0-nightly-20221115024001
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/CHANGELOG.md +35 -0
- package/README.md +210 -0
- package/alpha/package.json +6 -0
- package/config.d.ts +28 -0
- package/dist/index.alpha.d.ts +65 -0
- package/dist/index.beta.d.ts +60 -0
- package/dist/index.cjs.js +255 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +60 -0
- package/package.json +48 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# @backstage/plugin-events-backend
|
|
2
|
+
|
|
3
|
+
## 0.0.0-nightly-20221115024001
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- dc9da28abd: Support events received via HTTP endpoints at plugin-events-backend.
|
|
8
|
+
|
|
9
|
+
The plugin provides an event publisher `HttpPostIngressEventPublisher`
|
|
10
|
+
which will allow you to receive events via
|
|
11
|
+
HTTP endpoints `POST /api/events/http/{topic}`
|
|
12
|
+
and will publish these to the used event broker.
|
|
13
|
+
|
|
14
|
+
Using a provided custom validator, you can participate in the decision
|
|
15
|
+
which events are accepted, e.g. by verifying the source of the request.
|
|
16
|
+
|
|
17
|
+
Please find more information at
|
|
18
|
+
https://github.com/backstage/backstage/tree/master/plugins/events-backend/README.md.
|
|
19
|
+
|
|
20
|
+
- 7bbd2403a1: Adds a new backend plugin plugin-events-backend for managing events.
|
|
21
|
+
|
|
22
|
+
plugin-events-node exposes interfaces which can be used by modules.
|
|
23
|
+
|
|
24
|
+
plugin-events-backend-test-utils provides utilities which can be used while writing tests e.g. for modules.
|
|
25
|
+
|
|
26
|
+
Please find more information at
|
|
27
|
+
https://github.com/backstage/backstage/tree/master/plugins/events-backend/README.md.
|
|
28
|
+
|
|
29
|
+
### Patch Changes
|
|
30
|
+
|
|
31
|
+
- Updated dependencies
|
|
32
|
+
- @backstage/backend-common@0.0.0-nightly-20221115024001
|
|
33
|
+
- @backstage/plugin-events-node@0.0.0-nightly-20221115024001
|
|
34
|
+
- @backstage/backend-plugin-api@0.0.0-nightly-20221115024001
|
|
35
|
+
- @backstage/config@0.0.0-nightly-20221115024001
|
package/README.md
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# events-backend
|
|
2
|
+
|
|
3
|
+
Welcome to the events-backend backend plugin!
|
|
4
|
+
|
|
5
|
+
This plugin provides the wiring of all extension points
|
|
6
|
+
for managing events as defined by [plugin-events-node](../events-node)
|
|
7
|
+
including backend plugin `EventsPlugin` and `EventsBackend`.
|
|
8
|
+
|
|
9
|
+
Additionally, it uses a simple in-memory implementation for
|
|
10
|
+
the `EventBroker` by default which you can replace with a more sophisticated
|
|
11
|
+
implementation of your choice as you need (e.g., via module).
|
|
12
|
+
|
|
13
|
+
Some of these (non-exhaustive) may provide added persistence,
|
|
14
|
+
or use external systems like AWS EventBridge, AWS SNS, Kafka, etc.
|
|
15
|
+
|
|
16
|
+
By default, the plugin ships with support to receive events via HTTP endpoints
|
|
17
|
+
`POST /api/events/http/{topic}` and will publish these
|
|
18
|
+
to the used event broker.
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# From your Backstage root directory
|
|
24
|
+
yarn add --cwd packages/backend @backstage/plugin-events-backend
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Add a file [`packages/backend/src/plugins/events.ts`](../../packages/backend/src/plugins/events.ts)
|
|
28
|
+
to your Backstage project.
|
|
29
|
+
|
|
30
|
+
There, you can add all publishers, subscribers, etc. you want.
|
|
31
|
+
|
|
32
|
+
Additionally, add the events plugin to your backend.
|
|
33
|
+
|
|
34
|
+
```diff
|
|
35
|
+
// packages/backend/src/index.ts
|
|
36
|
+
// [...]
|
|
37
|
+
+import events from './plugins/events';
|
|
38
|
+
// [...]
|
|
39
|
+
+ const eventsEnv = useHotMemoize(module, () => createEnv('events'));
|
|
40
|
+
// [...]
|
|
41
|
+
+ apiRouter.use('/events', await events(eventsEnv, []));
|
|
42
|
+
// [...]
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### With Event-based Entity Providers
|
|
46
|
+
|
|
47
|
+
In case you use event-based `EntityProviders`,
|
|
48
|
+
you may need something like the following:
|
|
49
|
+
|
|
50
|
+
```diff
|
|
51
|
+
// packages/backend/src/index.ts
|
|
52
|
+
- apiRouter.use('/events', await events(eventsEnv, []));
|
|
53
|
+
+ apiRouter.use('/events', await events(eventsEnv, eventBasedEntityProviders));
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
as well as a file
|
|
57
|
+
[`packages/backend/src/plugins/catalogEventBasedProviders.ts`](../../packages/backend/src/plugins/catalogEventBasedProviders.ts)
|
|
58
|
+
which contains event-based entity providers.
|
|
59
|
+
|
|
60
|
+
In case you don't have this dependency added yet:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# From your Backstage root directory
|
|
64
|
+
yarn add --cwd packages/backend @backstage/plugin-events-backend
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
```diff
|
|
68
|
+
// packages/backend/src/plugins/catalog.ts
|
|
69
|
+
import { CatalogBuilder } from '@backstage/plugin-catalog-backend';
|
|
70
|
+
+import { EntityProvider } from '@backstage/plugin-catalog-node';
|
|
71
|
+
import { ScaffolderEntitiesProcessor } from '@backstage/plugin-scaffolder-backend';
|
|
72
|
+
import { Router } from 'express';
|
|
73
|
+
import { PluginEnvironment } from '../types';
|
|
74
|
+
|
|
75
|
+
export default async function createPlugin(
|
|
76
|
+
env: PluginEnvironment,
|
|
77
|
+
+ providers?: Array<EntityProvider>,
|
|
78
|
+
): Promise<Router> {
|
|
79
|
+
const builder = await CatalogBuilder.create(env);
|
|
80
|
+
builder.addProcessor(new ScaffolderEntitiesProcessor());
|
|
81
|
+
+ builder.addEntityProvider(providers ?? []);
|
|
82
|
+
const { processingEngine, router } = await builder.build();
|
|
83
|
+
await processingEngine.start();
|
|
84
|
+
return router;
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Configuration
|
|
89
|
+
|
|
90
|
+
In order to create HTTP endpoints to receive events for a certain
|
|
91
|
+
topic, you need to add them at your configuration:
|
|
92
|
+
|
|
93
|
+
```yaml
|
|
94
|
+
events:
|
|
95
|
+
http:
|
|
96
|
+
topics:
|
|
97
|
+
- bitbucketCloud
|
|
98
|
+
- github
|
|
99
|
+
- whatever
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Only those topics added to the configuration will result in
|
|
103
|
+
available endpoints.
|
|
104
|
+
|
|
105
|
+
The example above would result in the following endpoints:
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
POST /api/events/http/bitbucketCloud
|
|
109
|
+
POST /api/events/http/github
|
|
110
|
+
POST /api/events/http/whatever
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
You may want to use these for webhooks by SCM providers
|
|
114
|
+
in combination with suitable event subscribers.
|
|
115
|
+
|
|
116
|
+
However, it is not limited to these use cases.
|
|
117
|
+
|
|
118
|
+
## Use Cases
|
|
119
|
+
|
|
120
|
+
### Custom Event Broker
|
|
121
|
+
|
|
122
|
+
Example using the `EventsBackend`:
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
new EventsBackend(env.logger)
|
|
126
|
+
.setEventBroker(yourEventBroker)
|
|
127
|
+
// [...]
|
|
128
|
+
.start();
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Example using a module:
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
import { eventsExtensionPoint } from '@backstage/plugin-events-node';
|
|
135
|
+
|
|
136
|
+
// [...]
|
|
137
|
+
|
|
138
|
+
export const yourModuleEventsModule = createBackendModule({
|
|
139
|
+
pluginId: 'events',
|
|
140
|
+
moduleId: 'yourModule',
|
|
141
|
+
register(env) {
|
|
142
|
+
// [...]
|
|
143
|
+
env.registerInit({
|
|
144
|
+
deps: {
|
|
145
|
+
// [...]
|
|
146
|
+
events: eventsExtensionPoint,
|
|
147
|
+
// [...]
|
|
148
|
+
},
|
|
149
|
+
async init({ /* ... */ events /*, ... */ }) {
|
|
150
|
+
// [...]
|
|
151
|
+
const yourEventBroker = new YourEventBroker();
|
|
152
|
+
// [...]
|
|
153
|
+
events.setEventBroker(yourEventBroker);
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Request Validator
|
|
161
|
+
|
|
162
|
+
Example using the `EventsBackend`:
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
const http = HttpPostIngressEventPublisher.fromConfig({
|
|
166
|
+
config: env.config,
|
|
167
|
+
ingresses: {
|
|
168
|
+
yourTopic: {
|
|
169
|
+
validator: yourValidator,
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
logger: env.logger,
|
|
173
|
+
router: httpRouter,
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
await new EventsBackend(env.logger)
|
|
177
|
+
.addPublishers(http)
|
|
178
|
+
// [...]
|
|
179
|
+
.start();
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Example using a module:
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
import { eventsExtensionPoint } from '@backstage/plugin-events-node';
|
|
186
|
+
|
|
187
|
+
// [...]
|
|
188
|
+
|
|
189
|
+
export const yourModuleEventsModule = createBackendModule({
|
|
190
|
+
pluginId: 'events',
|
|
191
|
+
moduleId: 'yourModule',
|
|
192
|
+
register(env) {
|
|
193
|
+
// [...]
|
|
194
|
+
env.registerInit({
|
|
195
|
+
deps: {
|
|
196
|
+
// [...]
|
|
197
|
+
events: eventsExtensionPoint,
|
|
198
|
+
// [...]
|
|
199
|
+
},
|
|
200
|
+
async init({ /* ... */ events /*, ... */ }) {
|
|
201
|
+
// [...]
|
|
202
|
+
events.addHttpPostIngress({
|
|
203
|
+
topic: 'your-topic',
|
|
204
|
+
validator: yourValidator,
|
|
205
|
+
});
|
|
206
|
+
},
|
|
207
|
+
});
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
```
|
package/config.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2022 The Backstage Authors
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
export interface Config {
|
|
18
|
+
events?: {
|
|
19
|
+
http?: {
|
|
20
|
+
/**
|
|
21
|
+
* Topics for which a route has to be registered
|
|
22
|
+
* at which we can receive events via HTTP POST requests
|
|
23
|
+
* (i.e. received from webhooks).
|
|
24
|
+
*/
|
|
25
|
+
topics?: string[];
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Backstage backend plugin "events" that provides the event management.
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { BackendFeature } from '@backstage/backend-plugin-api';
|
|
8
|
+
import { Config } from '@backstage/config';
|
|
9
|
+
import { EventBroker } from '@backstage/plugin-events-node';
|
|
10
|
+
import { EventPublisher } from '@backstage/plugin-events-node';
|
|
11
|
+
import { EventSubscriber } from '@backstage/plugin-events-node';
|
|
12
|
+
import express from 'express';
|
|
13
|
+
import { HttpPostIngressOptions } from '@backstage/plugin-events-node';
|
|
14
|
+
import { Logger } from 'winston';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* A builder that helps wire up all component parts of the event management.
|
|
18
|
+
*
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
export declare class EventsBackend {
|
|
22
|
+
private eventBroker;
|
|
23
|
+
private publishers;
|
|
24
|
+
private subscribers;
|
|
25
|
+
constructor(logger: Logger);
|
|
26
|
+
setEventBroker(eventBroker: EventBroker): EventsBackend;
|
|
27
|
+
addPublishers(...publishers: Array<EventPublisher | Array<EventPublisher>>): EventsBackend;
|
|
28
|
+
addSubscribers(...subscribers: Array<EventSubscriber | Array<EventSubscriber>>): EventsBackend;
|
|
29
|
+
/**
|
|
30
|
+
* Wires up and returns all component parts of the event management.
|
|
31
|
+
*/
|
|
32
|
+
start(): Promise<void>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Events plugin
|
|
37
|
+
*
|
|
38
|
+
* @alpha
|
|
39
|
+
*/
|
|
40
|
+
export declare const eventsPlugin: (options?: undefined) => BackendFeature;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Publishes events received from their origin (e.g., webhook events from an SCM system)
|
|
44
|
+
* via HTTP POST endpoint and passes the request body as event payload to the registered subscribers.
|
|
45
|
+
*
|
|
46
|
+
* @public
|
|
47
|
+
*/
|
|
48
|
+
export declare class HttpPostIngressEventPublisher implements EventPublisher {
|
|
49
|
+
private logger;
|
|
50
|
+
private eventBroker?;
|
|
51
|
+
static fromConfig(env: {
|
|
52
|
+
config: Config;
|
|
53
|
+
ingresses?: {
|
|
54
|
+
[topic: string]: Omit<HttpPostIngressOptions, 'topic'>;
|
|
55
|
+
};
|
|
56
|
+
logger: Logger;
|
|
57
|
+
router: express.Router;
|
|
58
|
+
}): HttpPostIngressEventPublisher;
|
|
59
|
+
private constructor();
|
|
60
|
+
setEventBroker(eventBroker: EventBroker): Promise<void>;
|
|
61
|
+
private createRouter;
|
|
62
|
+
private addRouteForTopic;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export { }
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Backstage backend plugin "events" that provides the event management.
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { BackendFeature } from '@backstage/backend-plugin-api';
|
|
8
|
+
import { Config } from '@backstage/config';
|
|
9
|
+
import { EventBroker } from '@backstage/plugin-events-node';
|
|
10
|
+
import { EventPublisher } from '@backstage/plugin-events-node';
|
|
11
|
+
import { EventSubscriber } from '@backstage/plugin-events-node';
|
|
12
|
+
import express from 'express';
|
|
13
|
+
import { HttpPostIngressOptions } from '@backstage/plugin-events-node';
|
|
14
|
+
import { Logger } from 'winston';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* A builder that helps wire up all component parts of the event management.
|
|
18
|
+
*
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
export declare class EventsBackend {
|
|
22
|
+
private eventBroker;
|
|
23
|
+
private publishers;
|
|
24
|
+
private subscribers;
|
|
25
|
+
constructor(logger: Logger);
|
|
26
|
+
setEventBroker(eventBroker: EventBroker): EventsBackend;
|
|
27
|
+
addPublishers(...publishers: Array<EventPublisher | Array<EventPublisher>>): EventsBackend;
|
|
28
|
+
addSubscribers(...subscribers: Array<EventSubscriber | Array<EventSubscriber>>): EventsBackend;
|
|
29
|
+
/**
|
|
30
|
+
* Wires up and returns all component parts of the event management.
|
|
31
|
+
*/
|
|
32
|
+
start(): Promise<void>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* Excluded from this release type: eventsPlugin */
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Publishes events received from their origin (e.g., webhook events from an SCM system)
|
|
39
|
+
* via HTTP POST endpoint and passes the request body as event payload to the registered subscribers.
|
|
40
|
+
*
|
|
41
|
+
* @public
|
|
42
|
+
*/
|
|
43
|
+
export declare class HttpPostIngressEventPublisher implements EventPublisher {
|
|
44
|
+
private logger;
|
|
45
|
+
private eventBroker?;
|
|
46
|
+
static fromConfig(env: {
|
|
47
|
+
config: Config;
|
|
48
|
+
ingresses?: {
|
|
49
|
+
[topic: string]: Omit<HttpPostIngressOptions, 'topic'>;
|
|
50
|
+
};
|
|
51
|
+
logger: Logger;
|
|
52
|
+
router: express.Router;
|
|
53
|
+
}): HttpPostIngressEventPublisher;
|
|
54
|
+
private constructor();
|
|
55
|
+
setEventBroker(eventBroker: EventBroker): Promise<void>;
|
|
56
|
+
private createRouter;
|
|
57
|
+
private addRouteForTopic;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export { }
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
6
|
+
var pluginEventsNode = require('@backstage/plugin-events-node');
|
|
7
|
+
var Router = require('express-promise-router');
|
|
8
|
+
var backendCommon = require('@backstage/backend-common');
|
|
9
|
+
var express = require('express');
|
|
10
|
+
|
|
11
|
+
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
12
|
+
|
|
13
|
+
var Router__default = /*#__PURE__*/_interopDefaultLegacy(Router);
|
|
14
|
+
var express__default = /*#__PURE__*/_interopDefaultLegacy(express);
|
|
15
|
+
|
|
16
|
+
class InMemoryEventBroker {
|
|
17
|
+
constructor(logger) {
|
|
18
|
+
this.logger = logger;
|
|
19
|
+
this.subscribers = {};
|
|
20
|
+
}
|
|
21
|
+
async publish(params) {
|
|
22
|
+
var _a;
|
|
23
|
+
this.logger.debug(
|
|
24
|
+
`Event received: topic=${params.topic}, metadata=${JSON.stringify(
|
|
25
|
+
params.metadata
|
|
26
|
+
)}, payload=${JSON.stringify(params.eventPayload)}`
|
|
27
|
+
);
|
|
28
|
+
const subscribed = (_a = this.subscribers[params.topic]) != null ? _a : [];
|
|
29
|
+
subscribed.forEach((subscriber) => subscriber.onEvent(params));
|
|
30
|
+
}
|
|
31
|
+
subscribe(...subscribers) {
|
|
32
|
+
subscribers.flat().forEach((subscriber) => {
|
|
33
|
+
subscriber.supportsEventTopics().forEach((topic) => {
|
|
34
|
+
var _a;
|
|
35
|
+
this.subscribers[topic] = (_a = this.subscribers[topic]) != null ? _a : [];
|
|
36
|
+
this.subscribers[topic].push(subscriber);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
class EventsBackend {
|
|
43
|
+
constructor(logger) {
|
|
44
|
+
this.publishers = [];
|
|
45
|
+
this.subscribers = [];
|
|
46
|
+
this.eventBroker = new InMemoryEventBroker(logger);
|
|
47
|
+
}
|
|
48
|
+
setEventBroker(eventBroker) {
|
|
49
|
+
this.eventBroker = eventBroker;
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
addPublishers(...publishers) {
|
|
53
|
+
this.publishers.push(...publishers.flat());
|
|
54
|
+
return this;
|
|
55
|
+
}
|
|
56
|
+
addSubscribers(...subscribers) {
|
|
57
|
+
this.subscribers.push(...subscribers.flat());
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
async start() {
|
|
61
|
+
this.eventBroker.subscribe(this.subscribers);
|
|
62
|
+
this.publishers.forEach(
|
|
63
|
+
(publisher) => publisher.setEventBroker(this.eventBroker)
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
var __accessCheck$1 = (obj, member, msg) => {
|
|
69
|
+
if (!member.has(obj))
|
|
70
|
+
throw TypeError("Cannot " + msg);
|
|
71
|
+
};
|
|
72
|
+
var __privateGet$1 = (obj, member, getter) => {
|
|
73
|
+
__accessCheck$1(obj, member, "read from private field");
|
|
74
|
+
return getter ? getter.call(obj) : member.get(obj);
|
|
75
|
+
};
|
|
76
|
+
var __privateAdd$1 = (obj, member, value) => {
|
|
77
|
+
if (member.has(obj))
|
|
78
|
+
throw TypeError("Cannot add the same private member more than once");
|
|
79
|
+
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
80
|
+
};
|
|
81
|
+
var __privateSet$1 = (obj, member, value, setter) => {
|
|
82
|
+
__accessCheck$1(obj, member, "write to private field");
|
|
83
|
+
setter ? setter.call(obj, value) : member.set(obj, value);
|
|
84
|
+
return value;
|
|
85
|
+
};
|
|
86
|
+
var _rejectionDetails;
|
|
87
|
+
class RequestValidationContextImpl {
|
|
88
|
+
constructor() {
|
|
89
|
+
__privateAdd$1(this, _rejectionDetails, void 0);
|
|
90
|
+
}
|
|
91
|
+
reject(details) {
|
|
92
|
+
var _a, _b;
|
|
93
|
+
__privateSet$1(this, _rejectionDetails, {
|
|
94
|
+
status: (_a = details == null ? void 0 : details.status) != null ? _a : 403,
|
|
95
|
+
payload: (_b = details == null ? void 0 : details.payload) != null ? _b : {}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
wasRejected() {
|
|
99
|
+
return __privateGet$1(this, _rejectionDetails) !== void 0;
|
|
100
|
+
}
|
|
101
|
+
get rejectionDetails() {
|
|
102
|
+
return __privateGet$1(this, _rejectionDetails);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
_rejectionDetails = new WeakMap();
|
|
106
|
+
|
|
107
|
+
class HttpPostIngressEventPublisher {
|
|
108
|
+
constructor(logger, router, ingresses) {
|
|
109
|
+
this.logger = logger;
|
|
110
|
+
router.use(this.createRouter(ingresses));
|
|
111
|
+
}
|
|
112
|
+
static fromConfig(env) {
|
|
113
|
+
var _a, _b;
|
|
114
|
+
const topics = (_a = env.config.getOptionalStringArray("events.http.topics")) != null ? _a : [];
|
|
115
|
+
const ingresses = (_b = env.ingresses) != null ? _b : {};
|
|
116
|
+
topics.forEach((topic) => {
|
|
117
|
+
if (!ingresses[topic]) {
|
|
118
|
+
ingresses[topic] = {};
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
return new HttpPostIngressEventPublisher(env.logger, env.router, ingresses);
|
|
122
|
+
}
|
|
123
|
+
async setEventBroker(eventBroker) {
|
|
124
|
+
this.eventBroker = eventBroker;
|
|
125
|
+
}
|
|
126
|
+
createRouter(ingresses) {
|
|
127
|
+
const router = Router__default["default"]();
|
|
128
|
+
router.use(express__default["default"].json());
|
|
129
|
+
Object.keys(ingresses).forEach(
|
|
130
|
+
(topic) => this.addRouteForTopic(router, topic, ingresses[topic].validator)
|
|
131
|
+
);
|
|
132
|
+
router.use(backendCommon.errorHandler());
|
|
133
|
+
return router;
|
|
134
|
+
}
|
|
135
|
+
addRouteForTopic(router, topic, validator) {
|
|
136
|
+
const path = `/${topic}`;
|
|
137
|
+
router.post(path, async (request, response) => {
|
|
138
|
+
const context = new RequestValidationContextImpl();
|
|
139
|
+
await (validator == null ? void 0 : validator(request, context));
|
|
140
|
+
if (context.wasRejected()) {
|
|
141
|
+
response.status(context.rejectionDetails.status).json(context.rejectionDetails.payload);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const eventPayload = request.body;
|
|
145
|
+
await this.eventBroker.publish({
|
|
146
|
+
topic,
|
|
147
|
+
eventPayload,
|
|
148
|
+
metadata: request.headers
|
|
149
|
+
});
|
|
150
|
+
response.status(202).json({ status: "accepted" });
|
|
151
|
+
});
|
|
152
|
+
this.logger.info(`Registered /api/events/http${path} to receive events`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
var __accessCheck = (obj, member, msg) => {
|
|
157
|
+
if (!member.has(obj))
|
|
158
|
+
throw TypeError("Cannot " + msg);
|
|
159
|
+
};
|
|
160
|
+
var __privateGet = (obj, member, getter) => {
|
|
161
|
+
__accessCheck(obj, member, "read from private field");
|
|
162
|
+
return getter ? getter.call(obj) : member.get(obj);
|
|
163
|
+
};
|
|
164
|
+
var __privateAdd = (obj, member, value) => {
|
|
165
|
+
if (member.has(obj))
|
|
166
|
+
throw TypeError("Cannot add the same private member more than once");
|
|
167
|
+
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
168
|
+
};
|
|
169
|
+
var __privateSet = (obj, member, value, setter) => {
|
|
170
|
+
__accessCheck(obj, member, "write to private field");
|
|
171
|
+
setter ? setter.call(obj, value) : member.set(obj, value);
|
|
172
|
+
return value;
|
|
173
|
+
};
|
|
174
|
+
var _eventBroker, _httpPostIngresses, _publishers, _subscribers;
|
|
175
|
+
class EventsExtensionPointImpl {
|
|
176
|
+
constructor() {
|
|
177
|
+
__privateAdd(this, _eventBroker, void 0);
|
|
178
|
+
__privateAdd(this, _httpPostIngresses, []);
|
|
179
|
+
__privateAdd(this, _publishers, []);
|
|
180
|
+
__privateAdd(this, _subscribers, []);
|
|
181
|
+
}
|
|
182
|
+
setEventBroker(eventBroker) {
|
|
183
|
+
__privateSet(this, _eventBroker, eventBroker);
|
|
184
|
+
}
|
|
185
|
+
addPublishers(...publishers) {
|
|
186
|
+
__privateGet(this, _publishers).push(...publishers.flat());
|
|
187
|
+
}
|
|
188
|
+
addSubscribers(...subscribers) {
|
|
189
|
+
__privateGet(this, _subscribers).push(...subscribers.flat());
|
|
190
|
+
}
|
|
191
|
+
addHttpPostIngress(options) {
|
|
192
|
+
__privateGet(this, _httpPostIngresses).push(options);
|
|
193
|
+
}
|
|
194
|
+
get eventBroker() {
|
|
195
|
+
return __privateGet(this, _eventBroker);
|
|
196
|
+
}
|
|
197
|
+
get publishers() {
|
|
198
|
+
return __privateGet(this, _publishers);
|
|
199
|
+
}
|
|
200
|
+
get subscribers() {
|
|
201
|
+
return __privateGet(this, _subscribers);
|
|
202
|
+
}
|
|
203
|
+
get httpPostIngresses() {
|
|
204
|
+
return __privateGet(this, _httpPostIngresses);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
_eventBroker = new WeakMap();
|
|
208
|
+
_httpPostIngresses = new WeakMap();
|
|
209
|
+
_publishers = new WeakMap();
|
|
210
|
+
_subscribers = new WeakMap();
|
|
211
|
+
const eventsPlugin = backendPluginApi.createBackendPlugin({
|
|
212
|
+
id: "events",
|
|
213
|
+
register(env) {
|
|
214
|
+
const extensionPoint = new EventsExtensionPointImpl();
|
|
215
|
+
env.registerExtensionPoint(pluginEventsNode.eventsExtensionPoint, extensionPoint);
|
|
216
|
+
env.registerInit({
|
|
217
|
+
deps: {
|
|
218
|
+
config: backendPluginApi.configServiceRef,
|
|
219
|
+
httpRouter: backendPluginApi.httpRouterServiceRef,
|
|
220
|
+
logger: backendPluginApi.loggerServiceRef
|
|
221
|
+
},
|
|
222
|
+
async init({ config, httpRouter, logger }) {
|
|
223
|
+
const winstonLogger = backendPluginApi.loggerToWinstonLogger(logger);
|
|
224
|
+
const eventsRouter = Router__default["default"]();
|
|
225
|
+
const router = Router__default["default"]();
|
|
226
|
+
eventsRouter.use("/http", router);
|
|
227
|
+
const ingresses = Object.fromEntries(
|
|
228
|
+
extensionPoint.httpPostIngresses.map((ingress) => [
|
|
229
|
+
ingress.topic,
|
|
230
|
+
ingress
|
|
231
|
+
])
|
|
232
|
+
);
|
|
233
|
+
const http = HttpPostIngressEventPublisher.fromConfig({
|
|
234
|
+
config,
|
|
235
|
+
logger: winstonLogger,
|
|
236
|
+
router,
|
|
237
|
+
ingresses
|
|
238
|
+
});
|
|
239
|
+
if (!extensionPoint.eventBroker) {
|
|
240
|
+
extensionPoint.setEventBroker(new InMemoryEventBroker(winstonLogger));
|
|
241
|
+
}
|
|
242
|
+
extensionPoint.eventBroker.subscribe(extensionPoint.subscribers);
|
|
243
|
+
[extensionPoint.publishers, http].flat().forEach(
|
|
244
|
+
(publisher) => publisher.setEventBroker(extensionPoint.eventBroker)
|
|
245
|
+
);
|
|
246
|
+
httpRouter.use(eventsRouter);
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
exports.EventsBackend = EventsBackend;
|
|
253
|
+
exports.HttpPostIngressEventPublisher = HttpPostIngressEventPublisher;
|
|
254
|
+
exports.eventsPlugin = eventsPlugin;
|
|
255
|
+
//# sourceMappingURL=index.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":["../src/service/InMemoryEventBroker.ts","../src/service/EventsBackend.ts","../src/service/http/validation/RequestValidationContextImpl.ts","../src/service/http/HttpPostIngressEventPublisher.ts","../src/service/EventsPlugin.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n EventBroker,\n EventParams,\n EventSubscriber,\n} from '@backstage/plugin-events-node';\nimport { Logger } from 'winston';\n\n/**\n * In-memory event broker which will pass the event to all registered subscribers\n * interested in it.\n * Events will not be persisted in any form.\n */\n// TODO(pjungermann): add prom metrics? (see plugins/catalog-backend/src/util/metrics.ts, etc.)\nexport class InMemoryEventBroker implements EventBroker {\n constructor(private readonly logger: Logger) {}\n\n private readonly subscribers: {\n [topic: string]: EventSubscriber[];\n } = {};\n\n async publish(params: EventParams): Promise<void> {\n this.logger.debug(\n `Event received: topic=${params.topic}, metadata=${JSON.stringify(\n params.metadata,\n )}, payload=${JSON.stringify(params.eventPayload)}`,\n );\n\n const subscribed = this.subscribers[params.topic] ?? [];\n subscribed.forEach(subscriber => subscriber.onEvent(params));\n }\n\n subscribe(\n ...subscribers: Array<EventSubscriber | Array<EventSubscriber>>\n ): void {\n subscribers.flat().forEach(subscriber => {\n subscriber.supportsEventTopics().forEach(topic => {\n this.subscribers[topic] = this.subscribers[topic] ?? [];\n this.subscribers[topic].push(subscriber);\n });\n });\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n EventBroker,\n EventPublisher,\n EventSubscriber,\n} from '@backstage/plugin-events-node';\nimport { Logger } from 'winston';\nimport { InMemoryEventBroker } from './InMemoryEventBroker';\n\n/**\n * A builder that helps wire up all component parts of the event management.\n *\n * @public\n */\nexport class EventsBackend {\n private eventBroker: EventBroker;\n private publishers: EventPublisher[] = [];\n private subscribers: EventSubscriber[] = [];\n\n constructor(logger: Logger) {\n this.eventBroker = new InMemoryEventBroker(logger);\n }\n\n setEventBroker(eventBroker: EventBroker): EventsBackend {\n this.eventBroker = eventBroker;\n return this;\n }\n\n addPublishers(\n ...publishers: Array<EventPublisher | Array<EventPublisher>>\n ): EventsBackend {\n this.publishers.push(...publishers.flat());\n return this;\n }\n\n addSubscribers(\n ...subscribers: Array<EventSubscriber | Array<EventSubscriber>>\n ): EventsBackend {\n this.subscribers.push(...subscribers.flat());\n return this;\n }\n\n /**\n * Wires up and returns all component parts of the event management.\n */\n async start(): Promise<void> {\n this.eventBroker.subscribe(this.subscribers);\n this.publishers.forEach(publisher =>\n publisher.setEventBroker(this.eventBroker),\n );\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n RequestRejectionDetails,\n RequestValidationContext,\n} from '@backstage/plugin-events-node';\n\nexport class RequestValidationContextImpl implements RequestValidationContext {\n #rejectionDetails: RequestRejectionDetails | undefined;\n\n reject(details?: Partial<RequestRejectionDetails>): void {\n this.#rejectionDetails = {\n status: details?.status ?? 403,\n payload: details?.payload ?? {},\n };\n }\n\n wasRejected(): boolean {\n return this.#rejectionDetails !== undefined;\n }\n\n get rejectionDetails() {\n return this.#rejectionDetails;\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { errorHandler } from '@backstage/backend-common';\nimport { Config } from '@backstage/config';\nimport {\n EventBroker,\n EventPublisher,\n HttpPostIngressOptions,\n RequestValidator,\n} from '@backstage/plugin-events-node';\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { Logger } from 'winston';\nimport { RequestValidationContextImpl } from './validation';\n\n/**\n * Publishes events received from their origin (e.g., webhook events from an SCM system)\n * via HTTP POST endpoint and passes the request body as event payload to the registered subscribers.\n *\n * @public\n */\n// TODO(pjungermann): add prom metrics? (see plugins/catalog-backend/src/util/metrics.ts, etc.)\nexport class HttpPostIngressEventPublisher implements EventPublisher {\n private eventBroker?: EventBroker;\n\n static fromConfig(env: {\n config: Config;\n ingresses?: { [topic: string]: Omit<HttpPostIngressOptions, 'topic'> };\n logger: Logger;\n router: express.Router;\n }): HttpPostIngressEventPublisher {\n const topics =\n env.config.getOptionalStringArray('events.http.topics') ?? [];\n\n const ingresses = env.ingresses ?? {};\n topics.forEach(topic => {\n // don't overwrite topic settings\n // (e.g., added at the config as well as argument)\n if (!ingresses[topic]) {\n ingresses[topic] = {};\n }\n });\n\n return new HttpPostIngressEventPublisher(env.logger, env.router, ingresses);\n }\n\n private constructor(\n private logger: Logger,\n router: express.Router,\n ingresses: { [topic: string]: Omit<HttpPostIngressOptions, 'topic'> },\n ) {\n router.use(this.createRouter(ingresses));\n }\n\n async setEventBroker(eventBroker: EventBroker): Promise<void> {\n this.eventBroker = eventBroker;\n }\n\n private createRouter(ingresses: {\n [topic: string]: Omit<HttpPostIngressOptions, 'topic'>;\n }): express.Router {\n const router = Router();\n router.use(express.json());\n\n Object.keys(ingresses).forEach(topic =>\n this.addRouteForTopic(router, topic, ingresses[topic].validator),\n );\n\n router.use(errorHandler());\n return router;\n }\n\n private addRouteForTopic(\n router: express.Router,\n topic: string,\n validator?: RequestValidator,\n ): void {\n const path = `/${topic}`;\n\n router.post(path, async (request, response) => {\n const context = new RequestValidationContextImpl();\n await validator?.(request, context);\n if (context.wasRejected()) {\n response\n .status(context.rejectionDetails!.status)\n .json(context.rejectionDetails!.payload);\n return;\n }\n\n const eventPayload = request.body;\n await this.eventBroker!.publish({\n topic,\n eventPayload,\n metadata: request.headers,\n });\n\n response.status(202).json({ status: 'accepted' });\n });\n\n // TODO(pjungermann): We don't really know the externally defined path prefix here,\n // however it is more useful for users to have it. Is there a better way?\n this.logger.info(`Registered /api/events/http${path} to receive events`);\n }\n}\n","/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n configServiceRef,\n createBackendPlugin,\n httpRouterServiceRef,\n loggerServiceRef,\n loggerToWinstonLogger,\n} from '@backstage/backend-plugin-api';\nimport {\n EventBroker,\n EventPublisher,\n EventSubscriber,\n eventsExtensionPoint,\n EventsExtensionPoint,\n HttpPostIngressOptions,\n} from '@backstage/plugin-events-node';\nimport { InMemoryEventBroker } from './InMemoryEventBroker';\nimport Router from 'express-promise-router';\nimport { HttpPostIngressEventPublisher } from './http';\n\nclass EventsExtensionPointImpl implements EventsExtensionPoint {\n #eventBroker: EventBroker | undefined;\n #httpPostIngresses: HttpPostIngressOptions[] = [];\n #publishers: EventPublisher[] = [];\n #subscribers: EventSubscriber[] = [];\n\n setEventBroker(eventBroker: EventBroker): void {\n this.#eventBroker = eventBroker;\n }\n\n addPublishers(\n ...publishers: Array<EventPublisher | Array<EventPublisher>>\n ): void {\n this.#publishers.push(...publishers.flat());\n }\n\n addSubscribers(\n ...subscribers: Array<EventSubscriber | Array<EventSubscriber>>\n ): void {\n this.#subscribers.push(...subscribers.flat());\n }\n\n addHttpPostIngress(options: HttpPostIngressOptions) {\n this.#httpPostIngresses.push(options);\n }\n\n get eventBroker() {\n return this.#eventBroker;\n }\n\n get publishers() {\n return this.#publishers;\n }\n\n get subscribers() {\n return this.#subscribers;\n }\n\n get httpPostIngresses() {\n return this.#httpPostIngresses;\n }\n}\n\n/**\n * Events plugin\n *\n * @alpha\n */\nexport const eventsPlugin = createBackendPlugin({\n id: 'events',\n register(env) {\n const extensionPoint = new EventsExtensionPointImpl();\n env.registerExtensionPoint(eventsExtensionPoint, extensionPoint);\n\n env.registerInit({\n deps: {\n config: configServiceRef,\n httpRouter: httpRouterServiceRef,\n logger: loggerServiceRef,\n },\n async init({ config, httpRouter, logger }) {\n const winstonLogger = loggerToWinstonLogger(logger);\n const eventsRouter = Router();\n const router = Router();\n eventsRouter.use('/http', router);\n\n const ingresses = Object.fromEntries(\n extensionPoint.httpPostIngresses.map(ingress => [\n ingress.topic,\n ingress as Omit<HttpPostIngressOptions, 'topic'>,\n ]),\n );\n\n const http = HttpPostIngressEventPublisher.fromConfig({\n config,\n logger: winstonLogger,\n router,\n ingresses,\n });\n\n if (!extensionPoint.eventBroker) {\n extensionPoint.setEventBroker(new InMemoryEventBroker(winstonLogger));\n }\n\n extensionPoint.eventBroker!.subscribe(extensionPoint.subscribers);\n [extensionPoint.publishers, http]\n .flat()\n .forEach(publisher =>\n publisher.setEventBroker(extensionPoint.eventBroker!),\n );\n\n httpRouter.use(eventsRouter);\n },\n });\n },\n});\n"],"names":["__privateAdd","__privateSet","__privateGet","Router","express","errorHandler","createBackendPlugin","eventsExtensionPoint","configServiceRef","httpRouterServiceRef","loggerServiceRef","loggerToWinstonLogger"],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Backstage backend plugin "events" that provides the event management.
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { BackendFeature } from '@backstage/backend-plugin-api';
|
|
8
|
+
import { Config } from '@backstage/config';
|
|
9
|
+
import { EventBroker } from '@backstage/plugin-events-node';
|
|
10
|
+
import { EventPublisher } from '@backstage/plugin-events-node';
|
|
11
|
+
import { EventSubscriber } from '@backstage/plugin-events-node';
|
|
12
|
+
import express from 'express';
|
|
13
|
+
import { HttpPostIngressOptions } from '@backstage/plugin-events-node';
|
|
14
|
+
import { Logger } from 'winston';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* A builder that helps wire up all component parts of the event management.
|
|
18
|
+
*
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
export declare class EventsBackend {
|
|
22
|
+
private eventBroker;
|
|
23
|
+
private publishers;
|
|
24
|
+
private subscribers;
|
|
25
|
+
constructor(logger: Logger);
|
|
26
|
+
setEventBroker(eventBroker: EventBroker): EventsBackend;
|
|
27
|
+
addPublishers(...publishers: Array<EventPublisher | Array<EventPublisher>>): EventsBackend;
|
|
28
|
+
addSubscribers(...subscribers: Array<EventSubscriber | Array<EventSubscriber>>): EventsBackend;
|
|
29
|
+
/**
|
|
30
|
+
* Wires up and returns all component parts of the event management.
|
|
31
|
+
*/
|
|
32
|
+
start(): Promise<void>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* Excluded from this release type: eventsPlugin */
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Publishes events received from their origin (e.g., webhook events from an SCM system)
|
|
39
|
+
* via HTTP POST endpoint and passes the request body as event payload to the registered subscribers.
|
|
40
|
+
*
|
|
41
|
+
* @public
|
|
42
|
+
*/
|
|
43
|
+
export declare class HttpPostIngressEventPublisher implements EventPublisher {
|
|
44
|
+
private logger;
|
|
45
|
+
private eventBroker?;
|
|
46
|
+
static fromConfig(env: {
|
|
47
|
+
config: Config;
|
|
48
|
+
ingresses?: {
|
|
49
|
+
[topic: string]: Omit<HttpPostIngressOptions, 'topic'>;
|
|
50
|
+
};
|
|
51
|
+
logger: Logger;
|
|
52
|
+
router: express.Router;
|
|
53
|
+
}): HttpPostIngressEventPublisher;
|
|
54
|
+
private constructor();
|
|
55
|
+
setEventBroker(eventBroker: EventBroker): Promise<void>;
|
|
56
|
+
private createRouter;
|
|
57
|
+
private addRouteForTopic;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export { }
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@backstage/plugin-events-backend",
|
|
3
|
+
"version": "0.0.0-nightly-20221115024001",
|
|
4
|
+
"main": "dist/index.cjs.js",
|
|
5
|
+
"types": "dist/index.d.ts",
|
|
6
|
+
"license": "Apache-2.0",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public",
|
|
9
|
+
"alphaTypes": "dist/index.alpha.d.ts",
|
|
10
|
+
"main": "dist/index.cjs.js",
|
|
11
|
+
"types": "dist/index.d.ts"
|
|
12
|
+
},
|
|
13
|
+
"backstage": {
|
|
14
|
+
"role": "backend-plugin"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"start": "backstage-cli package start",
|
|
18
|
+
"build": "backstage-cli package build --experimental-type-build",
|
|
19
|
+
"lint": "backstage-cli package lint",
|
|
20
|
+
"test": "backstage-cli package test",
|
|
21
|
+
"clean": "backstage-cli package clean",
|
|
22
|
+
"prepack": "backstage-cli package prepack",
|
|
23
|
+
"postpack": "backstage-cli package postpack"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@backstage/backend-common": "^0.0.0-nightly-20221115024001",
|
|
27
|
+
"@backstage/backend-plugin-api": "^0.0.0-nightly-20221115024001",
|
|
28
|
+
"@backstage/config": "^0.0.0-nightly-20221115024001",
|
|
29
|
+
"@backstage/plugin-events-node": "^0.0.0-nightly-20221115024001",
|
|
30
|
+
"@types/express": "^4.17.6",
|
|
31
|
+
"express": "^4.17.1",
|
|
32
|
+
"express-promise-router": "^4.1.0",
|
|
33
|
+
"winston": "^3.2.1"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@backstage/backend-common": "^0.0.0-nightly-20221115024001",
|
|
37
|
+
"@backstage/backend-test-utils": "^0.0.0-nightly-20221115024001",
|
|
38
|
+
"@backstage/cli": "^0.0.0-nightly-20221115024001",
|
|
39
|
+
"@backstage/plugin-events-backend-test-utils": "^0.0.0-nightly-20221115024001",
|
|
40
|
+
"supertest": "^6.1.3"
|
|
41
|
+
},
|
|
42
|
+
"files": [
|
|
43
|
+
"alpha",
|
|
44
|
+
"config.d.ts",
|
|
45
|
+
"dist"
|
|
46
|
+
],
|
|
47
|
+
"configSchema": "config.d.ts"
|
|
48
|
+
}
|