@azure/web-pubsub-express 1.0.6-alpha.20240528.1 → 1.0.6-alpha.20240814.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/dist/commonjs/cloudEventsDispatcher.d.ts +15 -0
- package/dist/commonjs/cloudEventsDispatcher.d.ts.map +1 -0
- package/dist/commonjs/cloudEventsDispatcher.js +281 -0
- package/dist/commonjs/cloudEventsDispatcher.js.map +1 -0
- package/dist/commonjs/cloudEventsProtocols.d.ts +238 -0
- package/dist/commonjs/cloudEventsProtocols.d.ts.map +1 -0
- package/dist/commonjs/cloudEventsProtocols.js +5 -0
- package/dist/commonjs/cloudEventsProtocols.js.map +1 -0
- package/dist/commonjs/index.d.ts +3 -0
- package/dist/commonjs/index.d.ts.map +1 -0
- package/dist/{index.js → commonjs/index.js} +2 -2
- package/dist/commonjs/index.js.map +1 -0
- package/dist/commonjs/logger.d.ts +7 -0
- package/dist/commonjs/logger.d.ts.map +1 -0
- package/dist/commonjs/logger.js +13 -0
- package/dist/commonjs/logger.js.map +1 -0
- package/dist/commonjs/package.json +3 -0
- package/dist/commonjs/tsdoc-metadata.json +11 -0
- package/dist/commonjs/utils.d.ts +6 -0
- package/dist/commonjs/utils.d.ts.map +1 -0
- package/dist/commonjs/utils.js +59 -0
- package/dist/commonjs/utils.js.map +1 -0
- package/dist/commonjs/webPubSubEventHandler.d.ts +47 -0
- package/dist/commonjs/webPubSubEventHandler.d.ts.map +1 -0
- package/dist/commonjs/webPubSubEventHandler.js +78 -0
- package/dist/commonjs/webPubSubEventHandler.js.map +1 -0
- package/dist/esm/cloudEventsDispatcher.d.ts +15 -0
- package/dist/esm/cloudEventsDispatcher.d.ts.map +1 -0
- package/{dist-esm/src → dist/esm}/cloudEventsDispatcher.js +3 -3
- package/dist/esm/cloudEventsDispatcher.js.map +1 -0
- package/dist/esm/cloudEventsProtocols.d.ts +238 -0
- package/dist/esm/cloudEventsProtocols.d.ts.map +1 -0
- package/dist/esm/index.d.ts +3 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +5 -0
- package/{dist-esm/src → dist/esm}/index.js.map +1 -1
- package/dist/esm/logger.d.ts +7 -0
- package/dist/esm/logger.d.ts.map +1 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/utils.d.ts +6 -0
- package/dist/esm/utils.d.ts.map +1 -0
- package/{dist-esm/src → dist/esm}/utils.js.map +1 -1
- package/dist/esm/webPubSubEventHandler.d.ts +47 -0
- package/dist/esm/webPubSubEventHandler.d.ts.map +1 -0
- package/{dist-esm/src → dist/esm}/webPubSubEventHandler.js +1 -1
- package/dist/esm/webPubSubEventHandler.js.map +1 -0
- package/package.json +43 -28
- package/dist/index.js.map +0 -1
- package/dist-esm/samples-dev/server.js +0 -32
- package/dist-esm/samples-dev/server.js.map +0 -1
- package/dist-esm/src/cloudEventsDispatcher.js.map +0 -1
- package/dist-esm/src/index.js +0 -5
- package/dist-esm/src/webPubSubEventHandler.js.map +0 -1
- package/dist-esm/test/connect.spec.js +0 -179
- package/dist-esm/test/connect.spec.js.map +0 -1
- package/dist-esm/test/connected.spec.js +0 -85
- package/dist-esm/test/connected.spec.js.map +0 -1
- package/dist-esm/test/ctor.spec.js +0 -27
- package/dist-esm/test/ctor.spec.js.map +0 -1
- package/dist-esm/test/disconnected.spec.js +0 -85
- package/dist-esm/test/disconnected.spec.js.map +0 -1
- package/dist-esm/test/user.spec.js +0 -300
- package/dist-esm/test/user.spec.js.map +0 -1
- package/dist-esm/test/validate.spec.js +0 -51
- package/dist-esm/test/validate.spec.js.map +0 -1
- /package/{dist-esm/src → dist/esm}/cloudEventsProtocols.js +0 -0
- /package/{dist-esm/src → dist/esm}/cloudEventsProtocols.js.map +0 -0
- /package/{dist-esm/src → dist/esm}/logger.js +0 -0
- /package/{dist-esm/src → dist/esm}/logger.js.map +0 -0
- /package/{dist-esm/src → dist/esm}/utils.js +0 -0
- /package/{types → dist}/web-pubsub-express.d.ts +0 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
+
import type { WebPubSubEventHandlerOptions } from "./cloudEventsProtocols.js";
|
|
3
|
+
/**
|
|
4
|
+
* @internal
|
|
5
|
+
*/
|
|
6
|
+
export declare class CloudEventsDispatcher {
|
|
7
|
+
private hub;
|
|
8
|
+
private eventHandler?;
|
|
9
|
+
private readonly _allowAll;
|
|
10
|
+
private readonly _allowedOrigins;
|
|
11
|
+
constructor(hub: string, eventHandler?: WebPubSubEventHandlerOptions | undefined);
|
|
12
|
+
handlePreflight(req: IncomingMessage, res: ServerResponse): boolean;
|
|
13
|
+
handleRequest(request: IncomingMessage, response: ServerResponse): Promise<boolean>;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=cloudEventsDispatcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudEventsDispatcher.d.ts","sourceRoot":"","sources":["../../src/cloudEventsDispatcher.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAI5D,OAAO,KAAK,EASV,4BAA4B,EAC7B,MAAM,2BAA2B,CAAC;AAyKnC;;GAEG;AACH,qBAAa,qBAAqB;IAI9B,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,YAAY,CAAC;IAJvB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiB;IAC3C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqB;gBAE3C,GAAG,EAAE,MAAM,EACX,YAAY,CAAC,EAAE,4BAA4B,YAAA;IAa9C,eAAe,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO;IAoB7D,aAAa,CAAC,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC;CAyGjG"}
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (c) Microsoft Corporation.
|
|
3
|
+
// Licensed under the MIT license.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.CloudEventsDispatcher = void 0;
|
|
6
|
+
const tslib_1 = require("tslib");
|
|
7
|
+
const utils = tslib_1.__importStar(require("./utils.js"));
|
|
8
|
+
const node_url_1 = require("node:url");
|
|
9
|
+
const logger_js_1 = require("./logger.js");
|
|
10
|
+
var EventType;
|
|
11
|
+
(function (EventType) {
|
|
12
|
+
EventType[EventType["Connect"] = 0] = "Connect";
|
|
13
|
+
EventType[EventType["Connected"] = 1] = "Connected";
|
|
14
|
+
EventType[EventType["Disconnected"] = 2] = "Disconnected";
|
|
15
|
+
EventType[EventType["UserEvent"] = 3] = "UserEvent";
|
|
16
|
+
})(EventType || (EventType = {}));
|
|
17
|
+
function getConnectResponseHandler(connectRequest, response) {
|
|
18
|
+
const states = connectRequest.context.states;
|
|
19
|
+
let modified = false;
|
|
20
|
+
const handler = {
|
|
21
|
+
setState(name, value) {
|
|
22
|
+
states[name] = value;
|
|
23
|
+
modified = true;
|
|
24
|
+
},
|
|
25
|
+
success(res) {
|
|
26
|
+
response.statusCode = 200;
|
|
27
|
+
if (modified) {
|
|
28
|
+
response.setHeader("ce-connectionState", utils.toBase64JsonString(states));
|
|
29
|
+
}
|
|
30
|
+
if (res === undefined) {
|
|
31
|
+
response.end();
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
response.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
35
|
+
response.end(JSON.stringify(res));
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
fail(code, detail) {
|
|
39
|
+
response.statusCode = code;
|
|
40
|
+
response.end(detail !== null && detail !== void 0 ? detail : "");
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
return handler;
|
|
44
|
+
}
|
|
45
|
+
function getUserEventResponseHandler(userRequest, response) {
|
|
46
|
+
const states = userRequest.context.states;
|
|
47
|
+
let modified = false;
|
|
48
|
+
const handler = {
|
|
49
|
+
setState(name, value) {
|
|
50
|
+
modified = true;
|
|
51
|
+
states[name] = value;
|
|
52
|
+
},
|
|
53
|
+
success(data, dataType) {
|
|
54
|
+
response.statusCode = 200;
|
|
55
|
+
if (modified) {
|
|
56
|
+
response.setHeader("ce-connectionState", utils.toBase64JsonString(states));
|
|
57
|
+
}
|
|
58
|
+
switch (dataType) {
|
|
59
|
+
case "json":
|
|
60
|
+
response.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
61
|
+
break;
|
|
62
|
+
case "text":
|
|
63
|
+
response.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
64
|
+
break;
|
|
65
|
+
default:
|
|
66
|
+
response.setHeader("Content-Type", "application/octet-stream");
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
response.end(data !== null && data !== void 0 ? data : "");
|
|
70
|
+
},
|
|
71
|
+
fail(code, detail) {
|
|
72
|
+
response.statusCode = code;
|
|
73
|
+
response.end(detail !== null && detail !== void 0 ? detail : "");
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
return handler;
|
|
77
|
+
}
|
|
78
|
+
function getContext(request, origin) {
|
|
79
|
+
const context = {
|
|
80
|
+
signature: utils.getHttpHeader(request, "ce-signature"),
|
|
81
|
+
userId: utils.getHttpHeader(request, "ce-userid"),
|
|
82
|
+
hub: utils.getHttpHeader(request, "ce-hub"),
|
|
83
|
+
connectionId: utils.getHttpHeader(request, "ce-connectionid"),
|
|
84
|
+
eventName: utils.getHttpHeader(request, "ce-eventname"),
|
|
85
|
+
origin: origin,
|
|
86
|
+
states: utils.fromBase64JsonString(utils.getHttpHeader(request, "ce-connectionstate")),
|
|
87
|
+
};
|
|
88
|
+
// TODO: validation
|
|
89
|
+
return context;
|
|
90
|
+
}
|
|
91
|
+
function tryGetWebPubSubEvent(req) {
|
|
92
|
+
// check ce-type to see if it is a valid WebPubSub CloudEvent request
|
|
93
|
+
const prefix = "azure.webpubsub.";
|
|
94
|
+
const connect = "azure.webpubsub.sys.connect";
|
|
95
|
+
const connected = "azure.webpubsub.sys.connected";
|
|
96
|
+
const disconnectd = "azure.webpubsub.sys.disconnected";
|
|
97
|
+
const userPrefix = "azure.webpubsub.user.";
|
|
98
|
+
const type = utils.getHttpHeader(req, "ce-type");
|
|
99
|
+
if (!(type === null || type === void 0 ? void 0 : type.startsWith(prefix))) {
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
if (type.startsWith(userPrefix)) {
|
|
103
|
+
return EventType.UserEvent;
|
|
104
|
+
}
|
|
105
|
+
switch (type) {
|
|
106
|
+
case connect:
|
|
107
|
+
return EventType.Connect;
|
|
108
|
+
case connected:
|
|
109
|
+
return EventType.Connected;
|
|
110
|
+
case disconnectd:
|
|
111
|
+
return EventType.Disconnected;
|
|
112
|
+
default:
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function isWebPubSubRequest(req) {
|
|
117
|
+
return utils.getHttpHeader(req, "ce-awpsversion") !== undefined;
|
|
118
|
+
}
|
|
119
|
+
async function readUserEventRequest(request, origin) {
|
|
120
|
+
const contentTypeheader = utils.getHttpHeader(request, "content-type");
|
|
121
|
+
if (contentTypeheader === undefined) {
|
|
122
|
+
return undefined;
|
|
123
|
+
}
|
|
124
|
+
const contentType = contentTypeheader.split(";")[0].trim();
|
|
125
|
+
switch (contentType) {
|
|
126
|
+
case "application/octet-stream":
|
|
127
|
+
return {
|
|
128
|
+
context: getContext(request, origin),
|
|
129
|
+
data: await utils.readRequestBody(request),
|
|
130
|
+
dataType: "binary",
|
|
131
|
+
};
|
|
132
|
+
case "application/json":
|
|
133
|
+
return {
|
|
134
|
+
context: getContext(request, origin),
|
|
135
|
+
data: JSON.parse((await utils.readRequestBody(request)).toString()),
|
|
136
|
+
dataType: "json",
|
|
137
|
+
};
|
|
138
|
+
case "text/plain":
|
|
139
|
+
return {
|
|
140
|
+
context: getContext(request, origin),
|
|
141
|
+
data: (await utils.readRequestBody(request)).toString(),
|
|
142
|
+
dataType: "text",
|
|
143
|
+
};
|
|
144
|
+
default:
|
|
145
|
+
return undefined;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
async function readSystemEventRequest(request, origin) {
|
|
149
|
+
const body = (await utils.readRequestBody(request)).toString();
|
|
150
|
+
const parsedRequest = JSON.parse(body);
|
|
151
|
+
parsedRequest.context = getContext(request, origin);
|
|
152
|
+
return parsedRequest;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* @internal
|
|
156
|
+
*/
|
|
157
|
+
class CloudEventsDispatcher {
|
|
158
|
+
constructor(hub, eventHandler) {
|
|
159
|
+
this.hub = hub;
|
|
160
|
+
this.eventHandler = eventHandler;
|
|
161
|
+
this._allowAll = true;
|
|
162
|
+
this._allowedOrigins = [];
|
|
163
|
+
if (Array.isArray(eventHandler)) {
|
|
164
|
+
throw new Error("Unexpected WebPubSubEventHandlerOptions");
|
|
165
|
+
}
|
|
166
|
+
if ((eventHandler === null || eventHandler === void 0 ? void 0 : eventHandler.allowedEndpoints) !== undefined) {
|
|
167
|
+
this._allowedOrigins = eventHandler.allowedEndpoints.map((endpoint) => new node_url_1.URL(endpoint).host.toLowerCase());
|
|
168
|
+
this._allowAll = false;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
handlePreflight(req, res) {
|
|
172
|
+
if (!isWebPubSubRequest(req)) {
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
const origin = utils.getHttpHeader(req, "webhook-request-origin");
|
|
176
|
+
if (origin === undefined) {
|
|
177
|
+
logger_js_1.logger.warning("Expecting webhook-request-origin header.");
|
|
178
|
+
res.statusCode = 400;
|
|
179
|
+
}
|
|
180
|
+
else if (this._allowAll) {
|
|
181
|
+
res.setHeader("WebHook-Allowed-Origin", "*");
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
// service to do the check
|
|
185
|
+
res.setHeader("WebHook-Allowed-Origin", this._allowedOrigins);
|
|
186
|
+
}
|
|
187
|
+
res.end();
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
async handleRequest(request, response) {
|
|
191
|
+
var _a, _b, _c, _d;
|
|
192
|
+
if (!isWebPubSubRequest(request)) {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
// check if it is a valid WebPubSub cloud events
|
|
196
|
+
const origin = utils.getHttpHeader(request, "webhook-request-origin");
|
|
197
|
+
if (origin === undefined) {
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
const eventType = tryGetWebPubSubEvent(request);
|
|
201
|
+
if (eventType === undefined) {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
// check if hub matches
|
|
205
|
+
const hub = utils.getHttpHeader(request, "ce-hub");
|
|
206
|
+
if ((hub === null || hub === void 0 ? void 0 : hub.toUpperCase()) !== this.hub.toUpperCase()) {
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
// No need to read body if handler is not specified
|
|
210
|
+
switch (eventType) {
|
|
211
|
+
case EventType.Connect:
|
|
212
|
+
if (!((_a = this.eventHandler) === null || _a === void 0 ? void 0 : _a.handleConnect)) {
|
|
213
|
+
response.end();
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
216
|
+
break;
|
|
217
|
+
case EventType.Connected:
|
|
218
|
+
if (!((_b = this.eventHandler) === null || _b === void 0 ? void 0 : _b.onConnected)) {
|
|
219
|
+
response.end();
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
break;
|
|
223
|
+
case EventType.Disconnected:
|
|
224
|
+
if (!((_c = this.eventHandler) === null || _c === void 0 ? void 0 : _c.onDisconnected)) {
|
|
225
|
+
response.end();
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
break;
|
|
229
|
+
case EventType.UserEvent:
|
|
230
|
+
if (!((_d = this.eventHandler) === null || _d === void 0 ? void 0 : _d.handleUserEvent)) {
|
|
231
|
+
response.end();
|
|
232
|
+
return true;
|
|
233
|
+
}
|
|
234
|
+
break;
|
|
235
|
+
default:
|
|
236
|
+
logger_js_1.logger.warning(`Unknown EventType ${eventType}`);
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
switch (eventType) {
|
|
240
|
+
case EventType.Connect: {
|
|
241
|
+
const connectRequest = await readSystemEventRequest(request, origin);
|
|
242
|
+
// service passes out query property, assign it to queries
|
|
243
|
+
connectRequest.queries = connectRequest.query;
|
|
244
|
+
logger_js_1.logger.verbose(connectRequest);
|
|
245
|
+
this.eventHandler.handleConnect(connectRequest, getConnectResponseHandler(connectRequest, response));
|
|
246
|
+
return true;
|
|
247
|
+
}
|
|
248
|
+
case EventType.Connected: {
|
|
249
|
+
// for unblocking events, we responds to the service as early as possible
|
|
250
|
+
response.end();
|
|
251
|
+
const connectedRequest = await readSystemEventRequest(request, origin);
|
|
252
|
+
logger_js_1.logger.verbose(connectedRequest);
|
|
253
|
+
this.eventHandler.onConnected(connectedRequest);
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
case EventType.Disconnected: {
|
|
257
|
+
// for unblocking events, we responds to the service as early as possible
|
|
258
|
+
response.end();
|
|
259
|
+
const disconnectedRequest = await readSystemEventRequest(request, origin);
|
|
260
|
+
logger_js_1.logger.verbose(disconnectedRequest);
|
|
261
|
+
this.eventHandler.onDisconnected(disconnectedRequest);
|
|
262
|
+
return true;
|
|
263
|
+
}
|
|
264
|
+
case EventType.UserEvent: {
|
|
265
|
+
const userRequest = await readUserEventRequest(request, origin);
|
|
266
|
+
if (userRequest === undefined) {
|
|
267
|
+
logger_js_1.logger.warning(`Unsupported content type ${utils.getHttpHeader(request, "content-type")}`);
|
|
268
|
+
return false;
|
|
269
|
+
}
|
|
270
|
+
logger_js_1.logger.verbose(userRequest);
|
|
271
|
+
this.eventHandler.handleUserEvent(userRequest, getUserEventResponseHandler(userRequest, response));
|
|
272
|
+
return true;
|
|
273
|
+
}
|
|
274
|
+
default:
|
|
275
|
+
logger_js_1.logger.warning(`Unknown EventType ${eventType}`);
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
exports.CloudEventsDispatcher = CloudEventsDispatcher;
|
|
281
|
+
//# sourceMappingURL=cloudEventsDispatcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudEventsDispatcher.js","sourceRoot":"","sources":["../../src/cloudEventsDispatcher.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\nimport * as utils from \"./utils.js\";\nimport { IncomingMessage, ServerResponse } from \"node:http\";\nimport { URL } from \"node:url\";\nimport { logger } from \"./logger.js\";\n\nimport type {\n ConnectRequest,\n ConnectResponse,\n ConnectedRequest,\n ConnectionContext,\n ConnectResponseHandler,\n DisconnectedRequest,\n UserEventRequest,\n UserEventResponseHandler,\n WebPubSubEventHandlerOptions,\n} from \"./cloudEventsProtocols.js\";\n\nenum EventType {\n Connect,\n Connected,\n Disconnected,\n UserEvent,\n}\n\nfunction getConnectResponseHandler(\n connectRequest: ConnectRequest,\n response: ServerResponse,\n): ConnectResponseHandler {\n const states: Record<string, any> = connectRequest.context.states;\n let modified = false;\n const handler = {\n setState(name: string, value: unknown): void {\n states[name] = value;\n modified = true;\n },\n success(res?: ConnectResponse): void {\n response.statusCode = 200;\n if (modified) {\n response.setHeader(\"ce-connectionState\", utils.toBase64JsonString(states));\n }\n if (res === undefined) {\n response.end();\n } else {\n response.setHeader(\"Content-Type\", \"application/json; charset=utf-8\");\n response.end(JSON.stringify(res));\n }\n },\n fail(code: 400 | 401 | 500, detail?: string): void {\n response.statusCode = code;\n response.end(detail ?? \"\");\n },\n };\n\n return handler;\n}\n\nfunction getUserEventResponseHandler(\n userRequest: UserEventRequest,\n response: ServerResponse,\n): UserEventResponseHandler {\n const states: Record<string, any> = userRequest.context.states;\n let modified = false;\n const handler = {\n setState(name: string, value: unknown): void {\n modified = true;\n states[name] = value;\n },\n success(data?: string | ArrayBuffer, dataType?: \"binary\" | \"text\" | \"json\"): void {\n response.statusCode = 200;\n if (modified) {\n response.setHeader(\"ce-connectionState\", utils.toBase64JsonString(states));\n }\n\n switch (dataType) {\n case \"json\":\n response.setHeader(\"Content-Type\", \"application/json; charset=utf-8\");\n break;\n case \"text\":\n response.setHeader(\"Content-Type\", \"text/plain; charset=utf-8\");\n break;\n default:\n response.setHeader(\"Content-Type\", \"application/octet-stream\");\n break;\n }\n response.end(data ?? \"\");\n },\n fail(code: 400 | 401 | 500, detail?: string): void {\n response.statusCode = code;\n response.end(detail ?? \"\");\n },\n };\n return handler;\n}\n\nfunction getContext(request: IncomingMessage, origin: string): ConnectionContext {\n const context = {\n signature: utils.getHttpHeader(request, \"ce-signature\"),\n userId: utils.getHttpHeader(request, \"ce-userid\"),\n hub: utils.getHttpHeader(request, \"ce-hub\")!,\n connectionId: utils.getHttpHeader(request, \"ce-connectionid\")!,\n eventName: utils.getHttpHeader(request, \"ce-eventname\")!,\n origin: origin,\n states: utils.fromBase64JsonString(utils.getHttpHeader(request, \"ce-connectionstate\")),\n };\n\n // TODO: validation\n return context;\n}\n\nfunction tryGetWebPubSubEvent(req: IncomingMessage): EventType | undefined {\n // check ce-type to see if it is a valid WebPubSub CloudEvent request\n const prefix = \"azure.webpubsub.\";\n const connect = \"azure.webpubsub.sys.connect\";\n const connected = \"azure.webpubsub.sys.connected\";\n const disconnectd = \"azure.webpubsub.sys.disconnected\";\n const userPrefix = \"azure.webpubsub.user.\";\n const type = utils.getHttpHeader(req, \"ce-type\");\n if (!type?.startsWith(prefix)) {\n return undefined;\n }\n if (type.startsWith(userPrefix)) {\n return EventType.UserEvent;\n }\n switch (type) {\n case connect:\n return EventType.Connect;\n case connected:\n return EventType.Connected;\n case disconnectd:\n return EventType.Disconnected;\n default:\n return undefined;\n }\n}\n\nfunction isWebPubSubRequest(req: IncomingMessage): boolean {\n return utils.getHttpHeader(req, \"ce-awpsversion\") !== undefined;\n}\n\nasync function readUserEventRequest(\n request: IncomingMessage,\n origin: string,\n): Promise<UserEventRequest | undefined> {\n const contentTypeheader = utils.getHttpHeader(request, \"content-type\");\n if (contentTypeheader === undefined) {\n return undefined;\n }\n\n const contentType = contentTypeheader.split(\";\")[0].trim();\n\n switch (contentType) {\n case \"application/octet-stream\":\n return {\n context: getContext(request, origin),\n data: await utils.readRequestBody(request),\n dataType: \"binary\",\n };\n case \"application/json\":\n return {\n context: getContext(request, origin),\n data: JSON.parse((await utils.readRequestBody(request)).toString()),\n dataType: \"json\",\n };\n case \"text/plain\":\n return {\n context: getContext(request, origin),\n data: (await utils.readRequestBody(request)).toString(),\n dataType: \"text\",\n };\n default:\n return undefined;\n }\n}\n\nasync function readSystemEventRequest<T extends { context: ConnectionContext }>(\n request: IncomingMessage,\n origin: string,\n): Promise<T> {\n const body = (await utils.readRequestBody(request)).toString();\n const parsedRequest = JSON.parse(body) as T;\n parsedRequest.context = getContext(request, origin);\n return parsedRequest;\n}\n\n/**\n * @internal\n */\nexport class CloudEventsDispatcher {\n private readonly _allowAll: boolean = true;\n private readonly _allowedOrigins: Array<string> = [];\n constructor(\n private hub: string,\n private eventHandler?: WebPubSubEventHandlerOptions,\n ) {\n if (Array.isArray(eventHandler)) {\n throw new Error(\"Unexpected WebPubSubEventHandlerOptions\");\n }\n if (eventHandler?.allowedEndpoints !== undefined) {\n this._allowedOrigins = eventHandler.allowedEndpoints.map((endpoint) =>\n new URL(endpoint).host.toLowerCase(),\n );\n this._allowAll = false;\n }\n }\n\n public handlePreflight(req: IncomingMessage, res: ServerResponse): boolean {\n if (!isWebPubSubRequest(req)) {\n return false;\n }\n const origin = utils.getHttpHeader(req, \"webhook-request-origin\");\n\n if (origin === undefined) {\n logger.warning(\"Expecting webhook-request-origin header.\");\n res.statusCode = 400;\n } else if (this._allowAll) {\n res.setHeader(\"WebHook-Allowed-Origin\", \"*\");\n } else {\n // service to do the check\n res.setHeader(\"WebHook-Allowed-Origin\", this._allowedOrigins);\n }\n\n res.end();\n return true;\n }\n\n public async handleRequest(request: IncomingMessage, response: ServerResponse): Promise<boolean> {\n if (!isWebPubSubRequest(request)) {\n return false;\n }\n\n // check if it is a valid WebPubSub cloud events\n const origin = utils.getHttpHeader(request, \"webhook-request-origin\");\n if (origin === undefined) {\n return false;\n }\n\n const eventType = tryGetWebPubSubEvent(request);\n if (eventType === undefined) {\n return false;\n }\n\n // check if hub matches\n const hub = utils.getHttpHeader(request, \"ce-hub\");\n if (hub?.toUpperCase() !== this.hub.toUpperCase()) {\n return false;\n }\n\n // No need to read body if handler is not specified\n switch (eventType) {\n case EventType.Connect:\n if (!this.eventHandler?.handleConnect) {\n response.end();\n return true;\n }\n break;\n case EventType.Connected:\n if (!this.eventHandler?.onConnected) {\n response.end();\n return true;\n }\n break;\n case EventType.Disconnected:\n if (!this.eventHandler?.onDisconnected) {\n response.end();\n return true;\n }\n break;\n case EventType.UserEvent:\n if (!this.eventHandler?.handleUserEvent) {\n response.end();\n return true;\n }\n break;\n default:\n logger.warning(`Unknown EventType ${eventType}`);\n return false;\n }\n\n switch (eventType) {\n case EventType.Connect: {\n const connectRequest = await readSystemEventRequest<ConnectRequest>(request, origin);\n // service passes out query property, assign it to queries\n connectRequest.queries = connectRequest.query;\n logger.verbose(connectRequest);\n\n this.eventHandler.handleConnect!(\n connectRequest,\n getConnectResponseHandler(connectRequest, response),\n );\n return true;\n }\n case EventType.Connected: {\n // for unblocking events, we responds to the service as early as possible\n response.end();\n const connectedRequest = await readSystemEventRequest<ConnectedRequest>(request, origin);\n logger.verbose(connectedRequest);\n this.eventHandler.onConnected!(connectedRequest);\n return true;\n }\n case EventType.Disconnected: {\n // for unblocking events, we responds to the service as early as possible\n response.end();\n const disconnectedRequest = await readSystemEventRequest<DisconnectedRequest>(\n request,\n origin,\n );\n logger.verbose(disconnectedRequest);\n this.eventHandler.onDisconnected!(disconnectedRequest);\n return true;\n }\n case EventType.UserEvent: {\n const userRequest = await readUserEventRequest(request, origin);\n if (userRequest === undefined) {\n logger.warning(\n `Unsupported content type ${utils.getHttpHeader(request, \"content-type\")}`,\n );\n return false;\n }\n logger.verbose(userRequest);\n this.eventHandler.handleUserEvent!(\n userRequest,\n getUserEventResponseHandler(userRequest, response),\n );\n return true;\n }\n default:\n logger.warning(`Unknown EventType ${eventType}`);\n return false;\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Response of the connect event.
|
|
3
|
+
*/
|
|
4
|
+
export interface ConnectResponse {
|
|
5
|
+
/**
|
|
6
|
+
* Set the groups the connection would like to join.
|
|
7
|
+
*/
|
|
8
|
+
groups?: string[];
|
|
9
|
+
/**
|
|
10
|
+
* Set the roles the connection belongs to.
|
|
11
|
+
*/
|
|
12
|
+
roles?: string[];
|
|
13
|
+
/**
|
|
14
|
+
* Set the userId for the connection.
|
|
15
|
+
*/
|
|
16
|
+
userId?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Set the subprotocol for the connection to complete WebSocket handshake.
|
|
19
|
+
*/
|
|
20
|
+
subprotocol?: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The connection context representing the client WebSocket connection.
|
|
24
|
+
*/
|
|
25
|
+
export interface ConnectionContext {
|
|
26
|
+
/**
|
|
27
|
+
* The hub the connection belongs to.
|
|
28
|
+
*/
|
|
29
|
+
hub: string;
|
|
30
|
+
/**
|
|
31
|
+
* The Id of the connection.
|
|
32
|
+
*/
|
|
33
|
+
connectionId: string;
|
|
34
|
+
/**
|
|
35
|
+
* The event name of this CloudEvents request.
|
|
36
|
+
*/
|
|
37
|
+
eventName: string;
|
|
38
|
+
/**
|
|
39
|
+
* The origin this CloudEvents request comes from.
|
|
40
|
+
*/
|
|
41
|
+
origin: string;
|
|
42
|
+
/**
|
|
43
|
+
* The user id of the connection.
|
|
44
|
+
*/
|
|
45
|
+
userId?: string;
|
|
46
|
+
/**
|
|
47
|
+
* The subprotocol of this connection.
|
|
48
|
+
*/
|
|
49
|
+
subprotocol?: string;
|
|
50
|
+
/**
|
|
51
|
+
* Get the additional states for the connection, such states are perserved throughout the lifetime of the connection.
|
|
52
|
+
*/
|
|
53
|
+
states: Record<string, any>;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Request for the connect event.
|
|
57
|
+
*/
|
|
58
|
+
export interface ConnectRequest {
|
|
59
|
+
/**
|
|
60
|
+
* The context of current CloudEvents request.
|
|
61
|
+
*/
|
|
62
|
+
context: ConnectionContext;
|
|
63
|
+
/**
|
|
64
|
+
* The claims that the client WebSocket connection has when it connects.
|
|
65
|
+
*/
|
|
66
|
+
claims?: Record<string, string[]>;
|
|
67
|
+
/**
|
|
68
|
+
* The query that the client WebSocket connection has when it connects.
|
|
69
|
+
* @deprecated Please use queries instead.
|
|
70
|
+
*/
|
|
71
|
+
query?: Record<string, string[]>;
|
|
72
|
+
/**
|
|
73
|
+
* The queries that the client WebSocket connection has when it connects.
|
|
74
|
+
*/
|
|
75
|
+
queries?: Record<string, string[]>;
|
|
76
|
+
/**
|
|
77
|
+
* The headers that the client WebSocket connection has when it connects.
|
|
78
|
+
*/
|
|
79
|
+
headers?: Record<string, string[]>;
|
|
80
|
+
/**
|
|
81
|
+
* The subprotocols that the client WebSocket connection uses to do handshake.
|
|
82
|
+
*/
|
|
83
|
+
subprotocols?: string[];
|
|
84
|
+
/**
|
|
85
|
+
* The client certificate info that the client WebSocket connection uses to connect.
|
|
86
|
+
*/
|
|
87
|
+
clientCertificates?: Certificate[];
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* The client certificate.
|
|
91
|
+
*/
|
|
92
|
+
export interface Certificate {
|
|
93
|
+
/**
|
|
94
|
+
* The thumbprint of the certificate.
|
|
95
|
+
*/
|
|
96
|
+
thumbprint: string;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Request for the connected event.
|
|
100
|
+
*/
|
|
101
|
+
export interface ConnectedRequest {
|
|
102
|
+
/**
|
|
103
|
+
* The context of current CloudEvents request.
|
|
104
|
+
*/
|
|
105
|
+
context: ConnectionContext;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Request for the user event.
|
|
109
|
+
*/
|
|
110
|
+
export type UserEventRequest = {
|
|
111
|
+
/**
|
|
112
|
+
* The context of current CloudEvents request.
|
|
113
|
+
*/
|
|
114
|
+
context: ConnectionContext;
|
|
115
|
+
/**
|
|
116
|
+
* The content data.
|
|
117
|
+
*/
|
|
118
|
+
data: string;
|
|
119
|
+
/**
|
|
120
|
+
* The type of the data.
|
|
121
|
+
*/
|
|
122
|
+
dataType: "text";
|
|
123
|
+
} | {
|
|
124
|
+
/**
|
|
125
|
+
* The context of current CloudEvents request.
|
|
126
|
+
*/
|
|
127
|
+
context: ConnectionContext;
|
|
128
|
+
/**
|
|
129
|
+
* The content data, when data type is `json`, the data is the result of JSON.parse, so the type of the data depends on user scenarios
|
|
130
|
+
*/
|
|
131
|
+
data: unknown;
|
|
132
|
+
/**
|
|
133
|
+
* The type of the data.
|
|
134
|
+
*/
|
|
135
|
+
dataType: "json";
|
|
136
|
+
} | {
|
|
137
|
+
/**
|
|
138
|
+
* The context of current CloudEvents request.
|
|
139
|
+
*/
|
|
140
|
+
context: ConnectionContext;
|
|
141
|
+
/**
|
|
142
|
+
* The content data.
|
|
143
|
+
*/
|
|
144
|
+
data: ArrayBuffer;
|
|
145
|
+
/**
|
|
146
|
+
* The type of the data.
|
|
147
|
+
*/
|
|
148
|
+
dataType: "binary";
|
|
149
|
+
};
|
|
150
|
+
/**
|
|
151
|
+
* Request for the disconnected event.
|
|
152
|
+
*/
|
|
153
|
+
export interface DisconnectedRequest {
|
|
154
|
+
/**
|
|
155
|
+
* The context of current CloudEvents request.
|
|
156
|
+
*/
|
|
157
|
+
context: ConnectionContext;
|
|
158
|
+
/**
|
|
159
|
+
* The reason that the connection disconnects.
|
|
160
|
+
*/
|
|
161
|
+
reason?: string;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* The handler to set connect event response
|
|
165
|
+
*/
|
|
166
|
+
export interface ConnectResponseHandler {
|
|
167
|
+
/**
|
|
168
|
+
* Set the state of the connection
|
|
169
|
+
* @param name - The name of the state
|
|
170
|
+
* @param value - The value of the state
|
|
171
|
+
*/
|
|
172
|
+
setState(name: string, value: unknown): void;
|
|
173
|
+
/**
|
|
174
|
+
* Return success response to the service.
|
|
175
|
+
* @param response - The response for the connect event.
|
|
176
|
+
*/
|
|
177
|
+
success(response?: ConnectResponse): void;
|
|
178
|
+
/**
|
|
179
|
+
* Return failed response and the service will reject the client WebSocket connection.
|
|
180
|
+
* @param code - Code can be 400 user error, 401 unauthorized and 500 server error.
|
|
181
|
+
* @param detail - The detail of the error.
|
|
182
|
+
*/
|
|
183
|
+
fail(code: 400 | 401 | 500, detail?: string): void;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* The handler to set user event response
|
|
187
|
+
*/
|
|
188
|
+
export interface UserEventResponseHandler {
|
|
189
|
+
/**
|
|
190
|
+
* Set the state of the connection
|
|
191
|
+
* @param name - The name of the state
|
|
192
|
+
* @param value - The value of the state
|
|
193
|
+
*/
|
|
194
|
+
setState(name: string, value: unknown): void;
|
|
195
|
+
/**
|
|
196
|
+
* Return success response with data to be delivered to the client WebSocket connection.
|
|
197
|
+
* @param data - The payload data to be returned to the client. Stringify the message if it is a JSON object.
|
|
198
|
+
* @param dataType - The type of the payload data.
|
|
199
|
+
*/
|
|
200
|
+
success(data?: string | ArrayBuffer, dataType?: "binary" | "text" | "json"): void;
|
|
201
|
+
/**
|
|
202
|
+
* Return failed response and the service will close the client WebSocket connection.
|
|
203
|
+
* @param code - Code can be 400 user error, 401 unauthorized and 500 server error.
|
|
204
|
+
* @param detail - The detail of the error.
|
|
205
|
+
*/
|
|
206
|
+
fail(code: 400 | 401 | 500, detail?: string): void;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* The options for the CloudEvents handler.
|
|
210
|
+
*/
|
|
211
|
+
export interface WebPubSubEventHandlerOptions {
|
|
212
|
+
/**
|
|
213
|
+
* Custom serving path for the path of the CloudEvents handler.
|
|
214
|
+
*/
|
|
215
|
+
path?: string;
|
|
216
|
+
/**
|
|
217
|
+
* Handle 'connect' event, the service waits for the response to proceed.
|
|
218
|
+
*/
|
|
219
|
+
handleConnect?: (connectRequest: ConnectRequest, connectResponse: ConnectResponseHandler) => void;
|
|
220
|
+
/**
|
|
221
|
+
* Handle user events, the service waits for the response to proceed.
|
|
222
|
+
*/
|
|
223
|
+
handleUserEvent?: (userEventRequest: UserEventRequest, userEventResponse: UserEventResponseHandler) => void;
|
|
224
|
+
/**
|
|
225
|
+
* Event trigger for "connected" unblocking event. This is an unblocking event and the service does not wait for the response.
|
|
226
|
+
*/
|
|
227
|
+
onConnected?: (connectedRequest: ConnectedRequest) => void;
|
|
228
|
+
/**
|
|
229
|
+
*
|
|
230
|
+
* Event triggers for "disconnected" unblocking event. This is an unblocking event and the service does not wait for the response.
|
|
231
|
+
*/
|
|
232
|
+
onDisconnected?: (disconnectedRequest: DisconnectedRequest) => void;
|
|
233
|
+
/**
|
|
234
|
+
* If not specified, by default allow all the endpoints, otherwise only allow specified endpoints
|
|
235
|
+
*/
|
|
236
|
+
allowedEndpoints?: string[];
|
|
237
|
+
}
|
|
238
|
+
//# sourceMappingURL=cloudEventsProtocols.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudEventsProtocols.d.ts","sourceRoot":"","sources":["../../src/cloudEventsProtocols.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudEventsProtocols.js","sourceRoot":"","sources":["../../src/cloudEventsProtocols.ts"],"names":[],"mappings":";AAAA,uCAAuC;AACvC,kCAAkC","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT license.\n\n/**\n * Response of the connect event.\n */\nexport interface ConnectResponse {\n /**\n * Set the groups the connection would like to join.\n */\n groups?: string[];\n /**\n * Set the roles the connection belongs to.\n */\n roles?: string[];\n /**\n * Set the userId for the connection.\n */\n userId?: string;\n /**\n * Set the subprotocol for the connection to complete WebSocket handshake.\n */\n subprotocol?: string;\n}\n\n/**\n * The connection context representing the client WebSocket connection.\n */\nexport interface ConnectionContext {\n /**\n * The hub the connection belongs to.\n */\n hub: string;\n /**\n * The Id of the connection.\n */\n connectionId: string;\n /**\n * The event name of this CloudEvents request.\n */\n eventName: string;\n /**\n * The origin this CloudEvents request comes from.\n */\n origin: string;\n /**\n * The user id of the connection.\n */\n userId?: string;\n /**\n * The subprotocol of this connection.\n */\n subprotocol?: string;\n /**\n * Get the additional states for the connection, such states are perserved throughout the lifetime of the connection.\n */\n states: Record<string, any>;\n}\n\n/**\n * Request for the connect event.\n */\nexport interface ConnectRequest {\n /**\n * The context of current CloudEvents request.\n */\n context: ConnectionContext;\n /**\n * The claims that the client WebSocket connection has when it connects.\n */\n claims?: Record<string, string[]>;\n /**\n * The query that the client WebSocket connection has when it connects.\n * @deprecated Please use queries instead.\n */\n query?: Record<string, string[]>;\n /**\n * The queries that the client WebSocket connection has when it connects.\n */\n queries?: Record<string, string[]>;\n /**\n * The headers that the client WebSocket connection has when it connects.\n */\n headers?: Record<string, string[]>;\n /**\n * The subprotocols that the client WebSocket connection uses to do handshake.\n */\n subprotocols?: string[];\n /**\n * The client certificate info that the client WebSocket connection uses to connect.\n */\n clientCertificates?: Certificate[];\n}\n\n/**\n * The client certificate.\n */\nexport interface Certificate {\n /**\n * The thumbprint of the certificate.\n */\n thumbprint: string;\n}\n\n/**\n * Request for the connected event.\n */\nexport interface ConnectedRequest {\n /**\n * The context of current CloudEvents request.\n */\n context: ConnectionContext;\n}\n\n/**\n * Request for the user event.\n */\nexport type UserEventRequest =\n | {\n /**\n * The context of current CloudEvents request.\n */\n context: ConnectionContext;\n\n /**\n * The content data.\n */\n data: string;\n /**\n * The type of the data.\n */\n dataType: \"text\";\n }\n | {\n /**\n * The context of current CloudEvents request.\n */\n context: ConnectionContext;\n\n /**\n * The content data, when data type is `json`, the data is the result of JSON.parse, so the type of the data depends on user scenarios\n */\n data: unknown;\n\n /**\n * The type of the data.\n */\n dataType: \"json\";\n }\n | {\n /**\n * The context of current CloudEvents request.\n */\n context: ConnectionContext;\n\n /**\n * The content data.\n */\n data: ArrayBuffer;\n /**\n * The type of the data.\n */\n dataType: \"binary\";\n };\n\n/**\n * Request for the disconnected event.\n */\nexport interface DisconnectedRequest {\n /**\n * The context of current CloudEvents request.\n */\n context: ConnectionContext;\n /**\n * The reason that the connection disconnects.\n */\n reason?: string;\n}\n\n/**\n * The handler to set connect event response\n */\nexport interface ConnectResponseHandler {\n /**\n * Set the state of the connection\n * @param name - The name of the state\n * @param value - The value of the state\n */\n setState(name: string, value: unknown): void;\n /**\n * Return success response to the service.\n * @param response - The response for the connect event.\n */\n success(response?: ConnectResponse): void;\n /**\n * Return failed response and the service will reject the client WebSocket connection.\n * @param code - Code can be 400 user error, 401 unauthorized and 500 server error.\n * @param detail - The detail of the error.\n */\n fail(code: 400 | 401 | 500, detail?: string): void;\n}\n\n/**\n * The handler to set user event response\n */\nexport interface UserEventResponseHandler {\n /**\n * Set the state of the connection\n * @param name - The name of the state\n * @param value - The value of the state\n */\n setState(name: string, value: unknown): void;\n /**\n * Return success response with data to be delivered to the client WebSocket connection.\n * @param data - The payload data to be returned to the client. Stringify the message if it is a JSON object.\n * @param dataType - The type of the payload data.\n */\n success(data?: string | ArrayBuffer, dataType?: \"binary\" | \"text\" | \"json\"): void;\n /**\n * Return failed response and the service will close the client WebSocket connection.\n * @param code - Code can be 400 user error, 401 unauthorized and 500 server error.\n * @param detail - The detail of the error.\n */\n fail(code: 400 | 401 | 500, detail?: string): void;\n}\n\n/**\n * The options for the CloudEvents handler.\n */\nexport interface WebPubSubEventHandlerOptions {\n /**\n * Custom serving path for the path of the CloudEvents handler.\n */\n path?: string;\n\n /**\n * Handle 'connect' event, the service waits for the response to proceed.\n */\n handleConnect?: (connectRequest: ConnectRequest, connectResponse: ConnectResponseHandler) => void;\n\n /**\n * Handle user events, the service waits for the response to proceed.\n */\n handleUserEvent?: (\n userEventRequest: UserEventRequest,\n userEventResponse: UserEventResponseHandler,\n ) => void;\n\n /**\n * Event trigger for \"connected\" unblocking event. This is an unblocking event and the service does not wait for the response.\n */\n onConnected?: (connectedRequest: ConnectedRequest) => void;\n\n /**\n *\n * Event triggers for \"disconnected\" unblocking event. This is an unblocking event and the service does not wait for the response.\n */\n onDisconnected?: (disconnectedRequest: DisconnectedRequest) => void;\n\n /**\n * If not specified, by default allow all the endpoints, otherwise only allow specified endpoints\n */\n allowedEndpoints?: string[];\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,cAAc,2BAA2B,CAAC"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var
|
|
5
|
+
var node_url = require('node:url');
|
|
6
6
|
var logger$1 = require('@azure/logger');
|
|
7
7
|
|
|
8
8
|
// Copyright (c) Microsoft Corporation.
|
|
@@ -226,7 +226,7 @@ class CloudEventsDispatcher {
|
|
|
226
226
|
throw new Error("Unexpected WebPubSubEventHandlerOptions");
|
|
227
227
|
}
|
|
228
228
|
if ((eventHandler === null || eventHandler === void 0 ? void 0 : eventHandler.allowedEndpoints) !== undefined) {
|
|
229
|
-
this._allowedOrigins = eventHandler.allowedEndpoints.map((endpoint) => new
|
|
229
|
+
this._allowedOrigins = eventHandler.allowedEndpoints.map((endpoint) => new node_url.URL(endpoint).host.toLowerCase());
|
|
230
230
|
this._allowAll = false;
|
|
231
231
|
}
|
|
232
232
|
}
|