@pipeline-builder/api-server 4.1.3 → 4.1.5
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/README.md +1 -1
- package/lib/api/app-factory.d.ts +8 -3
- package/lib/api/app-factory.js +78 -96
- package/lib/api/check-quota.js +16 -5
- package/lib/api/idempotency-middleware.d.ts +1 -1
- package/lib/api/idempotency-middleware.js +15 -2
- package/lib/api/index.d.ts +1 -1
- package/lib/api/index.js +2 -2
- package/lib/api/meter-quota.js +12 -3
- package/lib/api/metrics.d.ts +9 -0
- package/lib/api/metrics.js +23 -1
- package/lib/api/middleware-factory.js +2 -2
- package/lib/api/quota-helpers.d.ts +7 -8
- package/lib/api/quota-helpers.js +9 -8
- package/lib/api/rate-limit-by-org.js +19 -25
- package/lib/api/rate-limit-store.d.ts +16 -0
- package/lib/api/rate-limit-store.js +39 -0
- package/lib/api/request-types.d.ts +1 -1
- package/lib/api/request-types.js +7 -2
- package/lib/api/server.js +23 -2
- package/lib/http/index.d.ts +0 -1
- package/lib/http/index.js +1 -2
- package/lib/http/sse-connection-manager.d.ts +59 -29
- package/lib/http/sse-connection-manager.js +89 -42
- package/lib/http/sse-relay.d.ts +16 -5
- package/lib/http/sse-relay.js +46 -18
- package/lib/http/sse-ticket-channel.d.ts +4 -2
- package/lib/http/sse-ticket-channel.js +13 -10
- package/package.json +5 -6
- package/lib/api/middleware.d.ts +0 -1
- package/lib/api/middleware.js +0 -8
- package/lib/http/sse-ticket-store.d.ts +0 -75
- package/lib/http/sse-ticket-store.js +0 -160
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// Copyright 2026 Pipeline Builder Contributors
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
import { sendError, ErrorCode,
|
|
3
|
+
import { sendError, ErrorCode, verifyServicePrincipal } from '@pipeline-builder/api-core';
|
|
4
4
|
import rateLimit, { ipKeyGenerator } from 'express-rate-limit';
|
|
5
|
-
|
|
5
|
+
import { createSharedRateLimitStore } from './rate-limit-store.js';
|
|
6
6
|
/**
|
|
7
7
|
* Per-ORGANIZATION rate limiter for a specific hot/expensive route, keyed on the
|
|
8
8
|
* VERIFIED auth org — the complement to the coarse global per-IP limiter in
|
|
@@ -29,11 +29,18 @@ export function rateLimitByOrg(opts) {
|
|
|
29
29
|
legacyHeaders: false,
|
|
30
30
|
// Exempt cryptographically-verified internal service callers (signed JWT).
|
|
31
31
|
skip: (req) => verifyServicePrincipal(req),
|
|
32
|
-
//
|
|
33
|
-
|
|
34
|
-
//
|
|
35
|
-
//
|
|
32
|
+
// Redis store failure degrades to "not limited", never a 500 on the route.
|
|
33
|
+
passOnStoreError: true,
|
|
34
|
+
// Bucket by VERIFIED identity (set by requireAuth), NOT the spoofable
|
|
35
|
+
// `x-org-id` header. An ORG SERVICE ACCOUNT gets its OWN bucket rather than
|
|
36
|
+
// its org's: automation is exactly the traffic shape that would otherwise
|
|
37
|
+
// drain the window its org's people share, and the plan requires machine
|
|
38
|
+
// rate limits to be keyed per account. Falls back to a normalized client-IP
|
|
39
|
+
// bucket when unauthenticated so pre-auth traffic is still bounded.
|
|
40
|
+
// Namespaced (`sa:`/`org:`/`ip:`) so no two id spaces can collide.
|
|
36
41
|
keyGenerator: (req) => {
|
|
42
|
+
if (req.user?.principalType === 'service_account' && req.user.sub)
|
|
43
|
+
return `sa:${req.user.sub}`;
|
|
37
44
|
const orgId = req.user?.organizationId;
|
|
38
45
|
return orgId ? `org:${orgId.toLowerCase()}` : `ip:${ipKeyGenerator(req.ip || 'anon', 64)}`;
|
|
39
46
|
},
|
|
@@ -41,24 +48,11 @@ export function rateLimitByOrg(opts) {
|
|
|
41
48
|
sendError(res, 429, message ?? `Too many ${name} requests, please slow down.`, ErrorCode.RATE_LIMIT_EXCEEDED);
|
|
42
49
|
},
|
|
43
50
|
};
|
|
44
|
-
// Shared
|
|
45
|
-
//
|
|
46
|
-
//
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
try {
|
|
50
|
-
const require = safeCreateRequire(import.meta.url);
|
|
51
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
52
|
-
const { RedisStore } = require('rate-limit-redis');
|
|
53
|
-
options.store = new RedisStore({
|
|
54
|
-
prefix: `rl:${name}:`,
|
|
55
|
-
sendCommand: (...args) => redis.call(...args),
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
catch {
|
|
59
|
-
logger.warn('Redis store unavailable; per-org limiter falls back to in-memory', { name });
|
|
60
|
-
}
|
|
61
|
-
}
|
|
51
|
+
// Shared cross-replica store (one process-wide Redis connection) when Redis is
|
|
52
|
+
// configured, else per-process memory. Namespaced by service AND limiter name so
|
|
53
|
+
// distinct limiters — or same-named limiters in different services — never
|
|
54
|
+
// share a counter.
|
|
55
|
+
options.store = createSharedRateLimitStore(`${process.env.SERVICE_NAME || 'api'}:${name}`);
|
|
62
56
|
return rateLimit(options);
|
|
63
57
|
}
|
|
64
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
58
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmF0ZS1saW1pdC1ieS1vcmcuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYXBpL3JhdGUtbGltaXQtYnktb3JnLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFFdEMsT0FBTyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUUxRixPQUFPLFNBQVMsRUFBRSxFQUFFLGNBQWMsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQy9ELE9BQU8sRUFBRSwwQkFBMEIsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBY25FOzs7Ozs7Ozs7Ozs7Ozs7O0dBZ0JHO0FBQ0gsTUFBTSxVQUFVLGNBQWMsQ0FBQyxJQUF5QjtJQUN0RCxNQUFNLEVBQUUsSUFBSSxFQUFFLEdBQUcsRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLEdBQUcsSUFBSSxDQUFDO0lBRTlDLE1BQU0sT0FBTyxHQUFvQztRQUMvQyxHQUFHO1FBQ0gsUUFBUTtRQUNSLGVBQWUsRUFBRSxJQUFJO1FBQ3JCLGFBQWEsRUFBRSxLQUFLO1FBQ3BCLDJFQUEyRTtRQUMzRSxJQUFJLEVBQUUsQ0FBQyxHQUFZLEVBQUUsRUFBRSxDQUFDLHNCQUFzQixDQUFDLEdBQUcsQ0FBQztRQUNuRCwyRUFBMkU7UUFDM0UsZ0JBQWdCLEVBQUUsSUFBSTtRQUN0QixzRUFBc0U7UUFDdEUsNEVBQTRFO1FBQzVFLDBFQUEwRTtRQUMxRSx5RUFBeUU7UUFDekUsNEVBQTRFO1FBQzVFLG9FQUFvRTtRQUNwRSxtRUFBbUU7UUFDbkUsWUFBWSxFQUFFLENBQUMsR0FBWSxFQUFVLEVBQUU7WUFDckMsSUFBSSxHQUFHLENBQUMsSUFBSSxFQUFFLGFBQWEsS0FBSyxpQkFBaUIsSUFBSSxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUc7Z0JBQUUsT0FBTyxNQUFNLEdBQUcsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7WUFDL0YsTUFBTSxLQUFLLEdBQUcsR0FBRyxDQUFDLElBQUksRUFBRSxjQUFjLENBQUM7WUFDdkMsT0FBTyxLQUFLLENBQUMsQ0FBQyxDQUFDLE9BQU8sS0FBSyxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLE1BQU0sY0FBYyxDQUFDLEdBQUcsQ0FBQyxFQUFFLElBQUksTUFBTSxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUM7UUFDN0YsQ0FBQztRQUNELE9BQU8sRUFBRSxDQUFDLElBQWEsRUFBRSxHQUFhLEVBQVEsRUFBRTtZQUM5QyxTQUFTLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxPQUFPLElBQUksWUFBWSxJQUFJLDhCQUE4QixFQUFFLFNBQVMsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO1FBQ2hILENBQUM7S0FDRixDQUFDO0lBRUYsK0VBQStFO0lBQy9FLGlGQUFpRjtJQUNqRiwyRUFBMkU7SUFDM0UsbUJBQW1CO0lBQ25CLE9BQU8sQ0FBQyxLQUFLLEdBQUcsMEJBQTBCLENBQUMsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLFlBQVksSUFBSSxLQUFLLElBQUksSUFBSSxFQUFFLENBQUMsQ0FBQztJQUUzRixPQUFPLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQztBQUM1QixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCB7IHNlbmRFcnJvciwgRXJyb3JDb2RlLCB2ZXJpZnlTZXJ2aWNlUHJpbmNpcGFsIH0gZnJvbSAnQHBpcGVsaW5lLWJ1aWxkZXIvYXBpLWNvcmUnO1xuaW1wb3J0IHR5cGUgeyBSZXF1ZXN0LCBSZXNwb25zZSB9IGZyb20gJ2V4cHJlc3MnO1xuaW1wb3J0IHJhdGVMaW1pdCwgeyBpcEtleUdlbmVyYXRvciB9IGZyb20gJ2V4cHJlc3MtcmF0ZS1saW1pdCc7XG5pbXBvcnQgeyBjcmVhdGVTaGFyZWRSYXRlTGltaXRTdG9yZSB9IGZyb20gJy4vcmF0ZS1saW1pdC1zdG9yZS5qcyc7XG5cbi8qKiBDb25maWcgZm9yIGEge0BsaW5rIHJhdGVMaW1pdEJ5T3JnfSBsaW1pdGVyLiAqL1xuZXhwb3J0IGludGVyZmFjZSBPcmdSYXRlTGltaXRPcHRpb25zIHtcbiAgLyoqIFVuaXF1ZSBuYW1lIOKAlCBuYW1lc3BhY2VzIHRoZSBSZWRpcyBidWNrZXQgKyBsYWJlbHMgbG9ncy4gKi9cbiAgbmFtZTogc3RyaW5nO1xuICAvKiogTWF4IHJlcXVlc3RzIHBlciB3aW5kb3cgcGVyIG9yZyAob3IgcGVyIGNsaWVudCBJUCB3aGVuIHVuYXV0aGVudGljYXRlZCkuICovXG4gIG1heDogbnVtYmVyO1xuICAvKiogV2luZG93IGxlbmd0aCBpbiBtcy4gKi9cbiAgd2luZG93TXM6IG51bWJlcjtcbiAgLyoqIE9wdGlvbmFsIDQyOSBtZXNzYWdlIG92ZXJyaWRlLiAqL1xuICBtZXNzYWdlPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIFBlci1PUkdBTklaQVRJT04gcmF0ZSBsaW1pdGVyIGZvciBhIHNwZWNpZmljIGhvdC9leHBlbnNpdmUgcm91dGUsIGtleWVkIG9uIHRoZVxuICogVkVSSUZJRUQgYXV0aCBvcmcg4oCUIHRoZSBjb21wbGVtZW50IHRvIHRoZSBjb2Fyc2UgZ2xvYmFsIHBlci1JUCBsaW1pdGVyIGluXG4gKiBgY3JlYXRlQXBwYCAod2hpY2ggYSB3aG9sZSBvcmcgYmVoaW5kIG9uZSBOQVQgc2hhcmVzLCBhbmQgYSBkaXN0cmlidXRlZFxuICogYXR0YWNrZXIgc3ByZWFkcyBhY3Jvc3MgSVAgYnVja2V0cyB0byBldmFkZSkuXG4gKlxuICogTVVTVCBiZSBtb3VudGVkIEFGVEVSIGByZXF1aXJlQXV0aGAgc28gYHJlcS51c2VyLm9yZ2FuaXphdGlvbklkYCBpcyBwb3B1bGF0ZWQ7XG4gKiBhbiB1bmF1dGhlbnRpY2F0ZWQgY2FsbGVyIGZhbGxzIGJhY2sgdG8gYSBjbGllbnQtSVAgYnVja2V0IChuZXZlciBhIHNwb29mYWJsZVxuICogaGVhZGVyKSBzbyBpdCBzdGF5cyBib3VuZGVkLiBWZXJpZmllZCBpbnRlcm5hbCBzZXJ2aWNlIHByaW5jaXBhbHMgYXJlIGV4ZW1wdFxuICogKHRoZXkgY2FycnkgYSBzaWduZWQgc2VydmljZSBKV1QpLiBVc2VzIHRoZSBzaGFyZWQgZW52IFJlZGlzIHN0b3JlXG4gKiAoY3Jvc3MtcmVwbGljYSwgbmFtZXNwYWNlZCBieSBgbmFtZWApIHdoZW4gY29uZmlndXJlZCwgZWxzZSBpbi1tZW1vcnkuXG4gKlxuICogQGV4YW1wbGVcbiAqICAgcm91dGVyLnBvc3QoJy8nLCAuLi5jcmVhdGVBdXRoZW50aWNhdGVkV2l0aE9yZ1JvdXRlKCksIHJlcXVpcmVQZXJtaXNzaW9uKCdtZXNzYWdlczp3cml0ZScpLFxuICogICAgIHJhdGVMaW1pdEJ5T3JnKHsgbmFtZTogJ21lc3NhZ2Utc2VuZCcsIG1heDogNjAsIHdpbmRvd01zOiA2MF8wMDAgfSksXG4gKiAgICAgd2l0aFJvdXRlKGhhbmRsZXIpKTtcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJhdGVMaW1pdEJ5T3JnKG9wdHM6IE9yZ1JhdGVMaW1pdE9wdGlvbnMpIHtcbiAgY29uc3QgeyBuYW1lLCBtYXgsIHdpbmRvd01zLCBtZXNzYWdlIH0gPSBvcHRzO1xuXG4gIGNvbnN0IG9wdGlvbnM6IFBhcmFtZXRlcnM8dHlwZW9mIHJhdGVMaW1pdD5bMF0gPSB7XG4gICAgbWF4LFxuICAgIHdpbmRvd01zLFxuICAgIHN0YW5kYXJkSGVhZGVyczogdHJ1ZSxcbiAgICBsZWdhY3lIZWFkZXJzOiBmYWxzZSxcbiAgICAvLyBFeGVtcHQgY3J5cHRvZ3JhcGhpY2FsbHktdmVyaWZpZWQgaW50ZXJuYWwgc2VydmljZSBjYWxsZXJzIChzaWduZWQgSldUKS5cbiAgICBza2lwOiAocmVxOiBSZXF1ZXN0KSA9PiB2ZXJpZnlTZXJ2aWNlUHJpbmNpcGFsKHJlcSksXG4gICAgLy8gUmVkaXMgc3RvcmUgZmFpbHVyZSBkZWdyYWRlcyB0byBcIm5vdCBsaW1pdGVkXCIsIG5ldmVyIGEgNTAwIG9uIHRoZSByb3V0ZS5cbiAgICBwYXNzT25TdG9yZUVycm9yOiB0cnVlLFxuICAgIC8vIEJ1Y2tldCBieSBWRVJJRklFRCBpZGVudGl0eSAoc2V0IGJ5IHJlcXVpcmVBdXRoKSwgTk9UIHRoZSBzcG9vZmFibGVcbiAgICAvLyBgeC1vcmctaWRgIGhlYWRlci4gQW4gT1JHIFNFUlZJQ0UgQUNDT1VOVCBnZXRzIGl0cyBPV04gYnVja2V0IHJhdGhlciB0aGFuXG4gICAgLy8gaXRzIG9yZydzOiBhdXRvbWF0aW9uIGlzIGV4YWN0bHkgdGhlIHRyYWZmaWMgc2hhcGUgdGhhdCB3b3VsZCBvdGhlcndpc2VcbiAgICAvLyBkcmFpbiB0aGUgd2luZG93IGl0cyBvcmcncyBwZW9wbGUgc2hhcmUsIGFuZCB0aGUgcGxhbiByZXF1aXJlcyBtYWNoaW5lXG4gICAgLy8gcmF0ZSBsaW1pdHMgdG8gYmUga2V5ZWQgcGVyIGFjY291bnQuIEZhbGxzIGJhY2sgdG8gYSBub3JtYWxpemVkIGNsaWVudC1JUFxuICAgIC8vIGJ1Y2tldCB3aGVuIHVuYXV0aGVudGljYXRlZCBzbyBwcmUtYXV0aCB0cmFmZmljIGlzIHN0aWxsIGJvdW5kZWQuXG4gICAgLy8gTmFtZXNwYWNlZCAoYHNhOmAvYG9yZzpgL2BpcDpgKSBzbyBubyB0d28gaWQgc3BhY2VzIGNhbiBjb2xsaWRlLlxuICAgIGtleUdlbmVyYXRvcjogKHJlcTogUmVxdWVzdCk6IHN0cmluZyA9PiB7XG4gICAgICBpZiAocmVxLnVzZXI/LnByaW5jaXBhbFR5cGUgPT09ICdzZXJ2aWNlX2FjY291bnQnICYmIHJlcS51c2VyLnN1YikgcmV0dXJuIGBzYToke3JlcS51c2VyLnN1Yn1gO1xuICAgICAgY29uc3Qgb3JnSWQgPSByZXEudXNlcj8ub3JnYW5pemF0aW9uSWQ7XG4gICAgICByZXR1cm4gb3JnSWQgPyBgb3JnOiR7b3JnSWQudG9Mb3dlckNhc2UoKX1gIDogYGlwOiR7aXBLZXlHZW5lcmF0b3IocmVxLmlwIHx8ICdhbm9uJywgNjQpfWA7XG4gICAgfSxcbiAgICBoYW5kbGVyOiAoX3JlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSk6IHZvaWQgPT4ge1xuICAgICAgc2VuZEVycm9yKHJlcywgNDI5LCBtZXNzYWdlID8/IGBUb28gbWFueSAke25hbWV9IHJlcXVlc3RzLCBwbGVhc2Ugc2xvdyBkb3duLmAsIEVycm9yQ29kZS5SQVRFX0xJTUlUX0VYQ0VFREVEKTtcbiAgICB9LFxuICB9O1xuXG4gIC8vIFNoYXJlZCBjcm9zcy1yZXBsaWNhIHN0b3JlIChvbmUgcHJvY2Vzcy13aWRlIFJlZGlzIGNvbm5lY3Rpb24pIHdoZW4gUmVkaXMgaXNcbiAgLy8gY29uZmlndXJlZCwgZWxzZSBwZXItcHJvY2VzcyBtZW1vcnkuIE5hbWVzcGFjZWQgYnkgc2VydmljZSBBTkQgbGltaXRlciBuYW1lIHNvXG4gIC8vIGRpc3RpbmN0IGxpbWl0ZXJzIOKAlCBvciBzYW1lLW5hbWVkIGxpbWl0ZXJzIGluIGRpZmZlcmVudCBzZXJ2aWNlcyDigJQgbmV2ZXJcbiAgLy8gc2hhcmUgYSBjb3VudGVyLlxuICBvcHRpb25zLnN0b3JlID0gY3JlYXRlU2hhcmVkUmF0ZUxpbWl0U3RvcmUoYCR7cHJvY2Vzcy5lbnYuU0VSVklDRV9OQU1FIHx8ICdhcGknfToke25hbWV9YCk7XG5cbiAgcmV0dXJuIHJhdGVMaW1pdChvcHRpb25zKTtcbn1cbiJdfQ==
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Store } from 'express-rate-limit';
|
|
2
|
+
/**
|
|
3
|
+
* A cross-replica rate-limit store under `rl:<namespace>:`, or `undefined` when
|
|
4
|
+
* Redis isn't configured (express-rate-limit then uses its per-process memory
|
|
5
|
+
* store, which is right for a single replica).
|
|
6
|
+
*
|
|
7
|
+
* Without a shared store every limit is really `max × replicas`, and weakest
|
|
8
|
+
* exactly when an HPA has scaled out under load. Use a namespace unique to the
|
|
9
|
+
* service AND limiter, so separate limiters never share a counter. Pair it with
|
|
10
|
+
* `passOnStoreError: true`: a Redis outage then lets requests through instead of
|
|
11
|
+
* failing them. A store whose scripts can't load at startup (Redis not yet
|
|
12
|
+
* connected) is tolerated by express-rate-limit and reloads on first use.
|
|
13
|
+
*/
|
|
14
|
+
export declare function createSharedRateLimitStore(namespace: string): Store | undefined;
|
|
15
|
+
/** Test-only: forget the memoized client. */
|
|
16
|
+
export declare function __resetSharedRateLimitStoreForTests(): void;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { createEnvRedisClient, createLogger, safeCreateRequire } from '@pipeline-builder/api-core';
|
|
4
|
+
const logger = createLogger('rate-limit-store');
|
|
5
|
+
/** One Redis connection for every rate limiter in the process.
|
|
6
|
+
* undefined = not built yet; null = Redis not configured. */
|
|
7
|
+
let client;
|
|
8
|
+
/**
|
|
9
|
+
* A cross-replica rate-limit store under `rl:<namespace>:`, or `undefined` when
|
|
10
|
+
* Redis isn't configured (express-rate-limit then uses its per-process memory
|
|
11
|
+
* store, which is right for a single replica).
|
|
12
|
+
*
|
|
13
|
+
* Without a shared store every limit is really `max × replicas`, and weakest
|
|
14
|
+
* exactly when an HPA has scaled out under load. Use a namespace unique to the
|
|
15
|
+
* service AND limiter, so separate limiters never share a counter. Pair it with
|
|
16
|
+
* `passOnStoreError: true`: a Redis outage then lets requests through instead of
|
|
17
|
+
* failing them. A store whose scripts can't load at startup (Redis not yet
|
|
18
|
+
* connected) is tolerated by express-rate-limit and reloads on first use.
|
|
19
|
+
*/
|
|
20
|
+
export function createSharedRateLimitStore(namespace) {
|
|
21
|
+
if (client === undefined)
|
|
22
|
+
client = createEnvRedisClient('rate-limit');
|
|
23
|
+
if (!client)
|
|
24
|
+
return undefined;
|
|
25
|
+
const redis = client;
|
|
26
|
+
const require = safeCreateRequire(import.meta.url);
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
28
|
+
const { RedisStore } = require('rate-limit-redis');
|
|
29
|
+
logger.debug('Shared rate-limit store created', { namespace });
|
|
30
|
+
return new RedisStore({
|
|
31
|
+
prefix: `rl:${namespace}:`,
|
|
32
|
+
sendCommand: (...args) => redis.call(...args),
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
/** Test-only: forget the memoized client. */
|
|
36
|
+
export function __resetSharedRateLimitStoreForTests() {
|
|
37
|
+
client = undefined;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmF0ZS1saW1pdC1zdG9yZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hcGkvcmF0ZS1saW1pdC1zdG9yZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxZQUFZLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUduRyxNQUFNLE1BQU0sR0FBRyxZQUFZLENBQUMsa0JBQWtCLENBQUMsQ0FBQztBQUloRDs4REFDOEQ7QUFDOUQsSUFBSSxNQUF3QyxDQUFDO0FBRTdDOzs7Ozs7Ozs7OztHQVdHO0FBQ0gsTUFBTSxVQUFVLDBCQUEwQixDQUFDLFNBQWlCO0lBQzFELElBQUksTUFBTSxLQUFLLFNBQVM7UUFBRSxNQUFNLEdBQUcsb0JBQW9CLENBQWdCLFlBQVksQ0FBQyxDQUFDO0lBQ3JGLElBQUksQ0FBQyxNQUFNO1FBQUUsT0FBTyxTQUFTLENBQUM7SUFDOUIsTUFBTSxLQUFLLEdBQUcsTUFBTSxDQUFDO0lBQ3JCLE1BQU0sT0FBTyxHQUFHLGlCQUFpQixDQUFDLE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ25ELGlFQUFpRTtJQUNqRSxNQUFNLEVBQUUsVUFBVSxFQUFFLEdBQUcsT0FBTyxDQUFDLGtCQUFrQixDQUE4QyxDQUFDO0lBQ2hHLE1BQU0sQ0FBQyxLQUFLLENBQUMsaUNBQWlDLEVBQUUsRUFBRSxTQUFTLEVBQUUsQ0FBQyxDQUFDO0lBQy9ELE9BQU8sSUFBSSxVQUFVLENBQUM7UUFDcEIsTUFBTSxFQUFFLE1BQU0sU0FBUyxHQUFHO1FBQzFCLFdBQVcsRUFBRSxDQUFDLEdBQUcsSUFBYyxFQUFFLEVBQUUsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEdBQUcsSUFBSSxDQUFDO0tBQ3hELENBQUMsQ0FBQztBQUNMLENBQUM7QUFFRCw2Q0FBNkM7QUFDN0MsTUFBTSxVQUFVLG1DQUFtQztJQUNqRCxNQUFNLEdBQUcsU0FBUyxDQUFDO0FBQ3JCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuaW1wb3J0IHsgY3JlYXRlRW52UmVkaXNDbGllbnQsIGNyZWF0ZUxvZ2dlciwgc2FmZUNyZWF0ZVJlcXVpcmUgfSBmcm9tICdAcGlwZWxpbmUtYnVpbGRlci9hcGktY29yZSc7XG5pbXBvcnQgdHlwZSB7IFN0b3JlIH0gZnJvbSAnZXhwcmVzcy1yYXRlLWxpbWl0JztcblxuY29uc3QgbG9nZ2VyID0gY3JlYXRlTG9nZ2VyKCdyYXRlLWxpbWl0LXN0b3JlJyk7XG5cbnR5cGUgQ29tbWFuZENsaWVudCA9IHsgY2FsbDogKC4uLmFyZ3M6IHN0cmluZ1tdKSA9PiBQcm9taXNlPHVua25vd24+IH07XG5cbi8qKiBPbmUgUmVkaXMgY29ubmVjdGlvbiBmb3IgZXZlcnkgcmF0ZSBsaW1pdGVyIGluIHRoZSBwcm9jZXNzLlxuICogIHVuZGVmaW5lZCA9IG5vdCBidWlsdCB5ZXQ7IG51bGwgPSBSZWRpcyBub3QgY29uZmlndXJlZC4gKi9cbmxldCBjbGllbnQ6IENvbW1hbmRDbGllbnQgfCBudWxsIHwgdW5kZWZpbmVkO1xuXG4vKipcbiAqIEEgY3Jvc3MtcmVwbGljYSByYXRlLWxpbWl0IHN0b3JlIHVuZGVyIGBybDo8bmFtZXNwYWNlPjpgLCBvciBgdW5kZWZpbmVkYCB3aGVuXG4gKiBSZWRpcyBpc24ndCBjb25maWd1cmVkIChleHByZXNzLXJhdGUtbGltaXQgdGhlbiB1c2VzIGl0cyBwZXItcHJvY2VzcyBtZW1vcnlcbiAqIHN0b3JlLCB3aGljaCBpcyByaWdodCBmb3IgYSBzaW5nbGUgcmVwbGljYSkuXG4gKlxuICogV2l0aG91dCBhIHNoYXJlZCBzdG9yZSBldmVyeSBsaW1pdCBpcyByZWFsbHkgYG1heCDDlyByZXBsaWNhc2AsIGFuZCB3ZWFrZXN0XG4gKiBleGFjdGx5IHdoZW4gYW4gSFBBIGhhcyBzY2FsZWQgb3V0IHVuZGVyIGxvYWQuIFVzZSBhIG5hbWVzcGFjZSB1bmlxdWUgdG8gdGhlXG4gKiBzZXJ2aWNlIEFORCBsaW1pdGVyLCBzbyBzZXBhcmF0ZSBsaW1pdGVycyBuZXZlciBzaGFyZSBhIGNvdW50ZXIuIFBhaXIgaXQgd2l0aFxuICogYHBhc3NPblN0b3JlRXJyb3I6IHRydWVgOiBhIFJlZGlzIG91dGFnZSB0aGVuIGxldHMgcmVxdWVzdHMgdGhyb3VnaCBpbnN0ZWFkIG9mXG4gKiBmYWlsaW5nIHRoZW0uIEEgc3RvcmUgd2hvc2Ugc2NyaXB0cyBjYW4ndCBsb2FkIGF0IHN0YXJ0dXAgKFJlZGlzIG5vdCB5ZXRcbiAqIGNvbm5lY3RlZCkgaXMgdG9sZXJhdGVkIGJ5IGV4cHJlc3MtcmF0ZS1saW1pdCBhbmQgcmVsb2FkcyBvbiBmaXJzdCB1c2UuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVTaGFyZWRSYXRlTGltaXRTdG9yZShuYW1lc3BhY2U6IHN0cmluZyk6IFN0b3JlIHwgdW5kZWZpbmVkIHtcbiAgaWYgKGNsaWVudCA9PT0gdW5kZWZpbmVkKSBjbGllbnQgPSBjcmVhdGVFbnZSZWRpc0NsaWVudDxDb21tYW5kQ2xpZW50PigncmF0ZS1saW1pdCcpO1xuICBpZiAoIWNsaWVudCkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgY29uc3QgcmVkaXMgPSBjbGllbnQ7XG4gIGNvbnN0IHJlcXVpcmUgPSBzYWZlQ3JlYXRlUmVxdWlyZShpbXBvcnQubWV0YS51cmwpO1xuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXJlcXVpcmUtaW1wb3J0c1xuICBjb25zdCB7IFJlZGlzU3RvcmUgfSA9IHJlcXVpcmUoJ3JhdGUtbGltaXQtcmVkaXMnKSBhcyB7IFJlZGlzU3RvcmU6IG5ldyAobzogdW5rbm93bikgPT4gU3RvcmUgfTtcbiAgbG9nZ2VyLmRlYnVnKCdTaGFyZWQgcmF0ZS1saW1pdCBzdG9yZSBjcmVhdGVkJywgeyBuYW1lc3BhY2UgfSk7XG4gIHJldHVybiBuZXcgUmVkaXNTdG9yZSh7XG4gICAgcHJlZml4OiBgcmw6JHtuYW1lc3BhY2V9OmAsXG4gICAgc2VuZENvbW1hbmQ6ICguLi5hcmdzOiBzdHJpbmdbXSkgPT4gcmVkaXMuY2FsbCguLi5hcmdzKSxcbiAgfSk7XG59XG5cbi8qKiBUZXN0LW9ubHk6IGZvcmdldCB0aGUgbWVtb2l6ZWQgY2xpZW50LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIF9fcmVzZXRTaGFyZWRSYXRlTGltaXRTdG9yZUZvclRlc3RzKCk6IHZvaWQge1xuICBjbGllbnQgPSB1bmRlZmluZWQ7XG59XG4iXX0=
|
|
@@ -23,7 +23,7 @@ export interface RequestContext {
|
|
|
23
23
|
requestId: string;
|
|
24
24
|
/** Identity from headers */
|
|
25
25
|
identity: RequestIdentity;
|
|
26
|
-
/** Logging function
|
|
26
|
+
/** Logging function: logger always, plus the SSE log stream when the service enables it */
|
|
27
27
|
log: RequestLogger;
|
|
28
28
|
}
|
|
29
29
|
/**
|
package/lib/api/request-types.js
CHANGED
|
@@ -49,12 +49,17 @@ export function createRequestContext(req, sseManager) {
|
|
|
49
49
|
logger.info(message, meta);
|
|
50
50
|
break;
|
|
51
51
|
}
|
|
52
|
+
// Only a service that serves a log stream (createApp `logStream: true`)
|
|
53
|
+
// pushes the line to SSE — otherwise every log line of every service would
|
|
54
|
+
// be serialized, written and relayed across Redis for no subscriber.
|
|
52
55
|
// The Winston call above is redacted by the logger's `redactFormat`, but the
|
|
53
56
|
// SSE frame bypasses the logger entirely — apply the SAME key-pattern
|
|
54
57
|
// redaction to `data` before it's pushed to the client so a secret in the
|
|
55
58
|
// log payload (e.g. an accidental `token`/`password` field) isn't streamed
|
|
56
59
|
// out over the build-log SSE channel.
|
|
57
|
-
sseManager.
|
|
60
|
+
if (sseManager.logStreamEnabled) {
|
|
61
|
+
sseManager.send(requestId, type, message, redactSensitive(data));
|
|
62
|
+
}
|
|
58
63
|
};
|
|
59
64
|
return {
|
|
60
65
|
requestId,
|
|
@@ -62,4 +67,4 @@ export function createRequestContext(req, sseManager) {
|
|
|
62
67
|
log,
|
|
63
68
|
};
|
|
64
69
|
}
|
|
65
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
70
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVxdWVzdC10eXBlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hcGkvcmVxdWVzdC10eXBlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDLE9BQU8sRUFBRSxXQUFXLEVBQUUsWUFBWSxFQUFFLGVBQWUsRUFBMEMsTUFBTSw0QkFBNEIsQ0FBQztBQUVoSSxPQUFPLEVBQUUsRUFBRSxJQUFJLElBQUksRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUNsQyxPQUFPLEVBQUUsVUFBVSxFQUFxQixNQUFNLG1DQUFtQyxDQUFDO0FBY2xGLE1BQU0sTUFBTSxHQUFHLFlBQVksQ0FBQyxZQUFZLENBQUMsQ0FBQztBQW1CMUM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F5Qkc7QUFDSCxNQUFNLFVBQVUsb0JBQW9CLENBQ2xDLEdBQVksRUFDWixVQUFzQjtJQUV0QixNQUFNLFFBQVEsR0FBRyxXQUFXLENBQUMsR0FBa0IsQ0FBQyxDQUFDO0lBQ2pELG1FQUFtRTtJQUNuRSx5REFBeUQ7SUFDekQsTUFBTSxTQUFTLEdBQUcsR0FBRyxDQUFDLFNBQVMsSUFBSSxRQUFRLENBQUMsU0FBUyxJQUFJLElBQUksRUFBRSxDQUFDO0lBRWhFLGdEQUFnRDtJQUNoRCxNQUFNLEdBQUcsR0FBa0IsQ0FBQyxJQUFJLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxFQUFFO1FBQ2pELE1BQU0sSUFBSSxHQUFHLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRSxRQUFRLENBQUMsS0FBSyxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsQ0FBQztRQUM5RCxRQUFRLElBQUksRUFBRSxDQUFDO1lBQ2IsS0FBSyxPQUFPO2dCQUNWLE1BQU0sQ0FBQyxLQUFLLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxDQUFDO2dCQUM1QixNQUFNO1lBQ1IsS0FBSyxNQUFNO2dCQUNULE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxDQUFDO2dCQUMzQixNQUFNO1lBQ1I7Z0JBQ0UsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUM7Z0JBQzNCLE1BQU07UUFDVixDQUFDO1FBQ0Qsd0VBQXdFO1FBQ3hFLDJFQUEyRTtRQUMzRSxxRUFBcUU7UUFDckUsNkVBQTZFO1FBQzdFLHNFQUFzRTtRQUN0RSwwRUFBMEU7UUFDMUUsMkVBQTJFO1FBQzNFLHNDQUFzQztRQUN0QyxJQUFJLFVBQVUsQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1lBQ2hDLFVBQVUsQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsZUFBZSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7UUFDbkUsQ0FBQztJQUNILENBQUMsQ0FBQztJQUVGLE9BQU87UUFDTCxTQUFTO1FBQ1QsUUFBUTtRQUNSLEdBQUc7S0FDSixDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgeyBnZXRJZGVudGl0eSwgY3JlYXRlTG9nZ2VyLCByZWRhY3RTZW5zaXRpdmUsIHR5cGUgUmVxdWVzdElkZW50aXR5LCB0eXBlIEh0dHBSZXF1ZXN0IH0gZnJvbSAnQHBpcGVsaW5lLWJ1aWxkZXIvYXBpLWNvcmUnO1xuaW1wb3J0IHR5cGUgeyBSZXF1ZXN0IH0gZnJvbSAnZXhwcmVzcyc7XG5pbXBvcnQgeyB2NyBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XG5pbXBvcnQgeyBTU0VNYW5hZ2VyLCB0eXBlIFNTRUV2ZW50VHlwZSB9IGZyb20gJy4uL2h0dHAvc3NlLWNvbm5lY3Rpb24tbWFuYWdlci5qcyc7XG5cbi8vIENvbnNvbGlkYXRlZCBFeHByZXNzIFJlcXVlc3QgYXVnbWVudGF0aW9uc1xuZGVjbGFyZSBnbG9iYWwge1xuICBuYW1lc3BhY2UgRXhwcmVzcyB7XG4gICAgaW50ZXJmYWNlIFJlcXVlc3Qge1xuICAgICAgLyoqIFVuaXF1ZSByZXF1ZXN0IElEIChzZXQgYnkgYXBwLWZhY3RvcnkgbWlkZGxld2FyZSkgKi9cbiAgICAgIHJlcXVlc3RJZD86IHN0cmluZztcbiAgICAgIC8qKiBSZXF1ZXN0IGNvbnRleHQgd2l0aCBpZGVudGl0eSwgbG9nZ2luZywgYW5kIFNTRSAqL1xuICAgICAgY29udGV4dD86IFJlcXVlc3RDb250ZXh0O1xuICAgIH1cbiAgfVxufVxuXG5jb25zdCBsb2dnZXIgPSBjcmVhdGVMb2dnZXIoJ2FwaS1zZXJ2ZXInKTtcblxuLyoqXG4gKiBSZXF1ZXN0IGxvZ2dlciBmdW5jdGlvbiB0eXBlXG4gKi9cbmV4cG9ydCB0eXBlIFJlcXVlc3RMb2dnZXIgPSAodHlwZTogU1NFRXZlbnRUeXBlLCBtZXNzYWdlOiBzdHJpbmcsIGRhdGE/OiB1bmtub3duKSA9PiB2b2lkO1xuXG4vKipcbiAqIFJlcXVlc3QgY29udGV4dCB3aXRoIGlkZW50aXR5IGFuZCBsb2dnaW5nXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmVxdWVzdENvbnRleHQge1xuICAvKiogVW5pcXVlIHJlcXVlc3QgSUQgKi9cbiAgcmVxdWVzdElkOiBzdHJpbmc7XG4gIC8qKiBJZGVudGl0eSBmcm9tIGhlYWRlcnMgKi9cbiAgaWRlbnRpdHk6IFJlcXVlc3RJZGVudGl0eTtcbiAgLyoqIExvZ2dpbmcgZnVuY3Rpb246IGxvZ2dlciBhbHdheXMsIHBsdXMgdGhlIFNTRSBsb2cgc3RyZWFtIHdoZW4gdGhlIHNlcnZpY2UgZW5hYmxlcyBpdCAqL1xuICBsb2c6IFJlcXVlc3RMb2dnZXI7XG59XG5cbi8qKlxuICogQ3JlYXRlIGEgcmVxdWVzdCBjb250ZXh0IHdpdGggaWRlbnRpdHkgYW5kIGxvZ2dpbmdcbiAqXG4gKiBDcmVhdGVzIGEgbG9nZ2VyIHRoYXQgb3V0cHV0cyB0byBib3RoIGNvbnNvbGUgYW5kIFNTRS5cbiAqXG4gKiBAcGFyYW0gcmVxIC0gRXhwcmVzcyByZXF1ZXN0XG4gKiBAcGFyYW0gc3NlTWFuYWdlciAtIFNTRSBtYW5hZ2VyIGZvciByZWFsLXRpbWUgbG9nc1xuICogQHJldHVybnMgUmVxdWVzdCBjb250ZXh0IHdpdGggaWRlbnRpdHkgYW5kIGxvZ2dlclxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBhcHAucG9zdCgnL2FwaS9yZXNvdXJjZScsIHJlcXVpcmVBdXRoLCBhc3luYyAocmVxLCByZXMpID0+IHtcbiAqICAgY29uc3QgY3R4ID0gY3JlYXRlUmVxdWVzdENvbnRleHQocmVxLCBzc2VNYW5hZ2VyKTtcbiAqXG4gKiAgIGN0eC5sb2coJ0lORk8nLCAnUHJvY2Vzc2luZyByZXF1ZXN0JywgeyBkYXRhOiByZXEuYm9keSB9KTtcbiAqXG4gKiAgIGlmICghY3R4LmlkZW50aXR5Lm9yZ0lkKSB7XG4gKiAgICAgY3R4LmxvZygnRVJST1InLCAnTWlzc2luZyBvcmdhbml6YXRpb24gSUQnKTtcbiAqICAgICByZXR1cm4gc2VuZEJhZFJlcXVlc3QocmVzLCAneC1vcmctaWQgaGVhZGVyIHJlcXVpcmVkJyk7XG4gKiAgIH1cbiAqXG4gKiAgIC8vIFByb2Nlc3MgcmVxdWVzdC4uLlxuICogICBjdHgubG9nKCdDT01QTEVURUQnLCAnUmVxdWVzdCBwcm9jZXNzZWQgc3VjY2Vzc2Z1bGx5Jyk7XG4gKiB9KTtcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlUmVxdWVzdENvbnRleHQoXG4gIHJlcTogUmVxdWVzdCxcbiAgc3NlTWFuYWdlcjogU1NFTWFuYWdlcixcbik6IFJlcXVlc3RDb250ZXh0IHtcbiAgY29uc3QgaWRlbnRpdHkgPSBnZXRJZGVudGl0eShyZXEgYXMgSHR0cFJlcXVlc3QpO1xuICAvLyBQcmVmZXIgdGhlIGFscmVhZHktcGFyc2VkIHJlcXVlc3RJZCBmcm9tIGFwcC1mYWN0b3J5IG1pZGRsZXdhcmUsXG4gIC8vIGZhbGwgYmFjayB0byBpZGVudGl0eSBoZWFkZXIsIHRoZW4gZ2VuZXJhdGUgYSBuZXcgb25lLlxuICBjb25zdCByZXF1ZXN0SWQgPSByZXEucmVxdWVzdElkIHx8IGlkZW50aXR5LnJlcXVlc3RJZCB8fCB1dWlkKCk7XG5cbiAgLy8gQ3JlYXRlIGxvZ2dlciB0aGF0IG91dHB1dHMgdG8gV2luc3RvbiBhbmQgU1NFXG4gIGNvbnN0IGxvZzogUmVxdWVzdExvZ2dlciA9ICh0eXBlLCBtZXNzYWdlLCBkYXRhKSA9PiB7XG4gICAgY29uc3QgbWV0YSA9IHsgcmVxdWVzdElkLCBvcmdJZDogaWRlbnRpdHkub3JnSWQsIHR5cGUsIGRhdGEgfTtcbiAgICBzd2l0Y2ggKHR5cGUpIHtcbiAgICAgIGNhc2UgJ0VSUk9SJzpcbiAgICAgICAgbG9nZ2VyLmVycm9yKG1lc3NhZ2UsIG1ldGEpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ1dBUk4nOlxuICAgICAgICBsb2dnZXIud2FybihtZXNzYWdlLCBtZXRhKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICBsb2dnZXIuaW5mbyhtZXNzYWdlLCBtZXRhKTtcbiAgICAgICAgYnJlYWs7XG4gICAgfVxuICAgIC8vIE9ubHkgYSBzZXJ2aWNlIHRoYXQgc2VydmVzIGEgbG9nIHN0cmVhbSAoY3JlYXRlQXBwIGBsb2dTdHJlYW06IHRydWVgKVxuICAgIC8vIHB1c2hlcyB0aGUgbGluZSB0byBTU0Ug4oCUIG90aGVyd2lzZSBldmVyeSBsb2cgbGluZSBvZiBldmVyeSBzZXJ2aWNlIHdvdWxkXG4gICAgLy8gYmUgc2VyaWFsaXplZCwgd3JpdHRlbiBhbmQgcmVsYXllZCBhY3Jvc3MgUmVkaXMgZm9yIG5vIHN1YnNjcmliZXIuXG4gICAgLy8gVGhlIFdpbnN0b24gY2FsbCBhYm92ZSBpcyByZWRhY3RlZCBieSB0aGUgbG9nZ2VyJ3MgYHJlZGFjdEZvcm1hdGAsIGJ1dCB0aGVcbiAgICAvLyBTU0UgZnJhbWUgYnlwYXNzZXMgdGhlIGxvZ2dlciBlbnRpcmVseSDigJQgYXBwbHkgdGhlIFNBTUUga2V5LXBhdHRlcm5cbiAgICAvLyByZWRhY3Rpb24gdG8gYGRhdGFgIGJlZm9yZSBpdCdzIHB1c2hlZCB0byB0aGUgY2xpZW50IHNvIGEgc2VjcmV0IGluIHRoZVxuICAgIC8vIGxvZyBwYXlsb2FkIChlLmcuIGFuIGFjY2lkZW50YWwgYHRva2VuYC9gcGFzc3dvcmRgIGZpZWxkKSBpc24ndCBzdHJlYW1lZFxuICAgIC8vIG91dCBvdmVyIHRoZSBidWlsZC1sb2cgU1NFIGNoYW5uZWwuXG4gICAgaWYgKHNzZU1hbmFnZXIubG9nU3RyZWFtRW5hYmxlZCkge1xuICAgICAgc3NlTWFuYWdlci5zZW5kKHJlcXVlc3RJZCwgdHlwZSwgbWVzc2FnZSwgcmVkYWN0U2Vuc2l0aXZlKGRhdGEpKTtcbiAgICB9XG4gIH07XG5cbiAgcmV0dXJuIHtcbiAgICByZXF1ZXN0SWQsXG4gICAgaWRlbnRpdHksXG4gICAgbG9nLFxuICB9O1xufVxuIl19
|
package/lib/api/server.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Copyright 2026 Pipeline Builder Contributors
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
import { Server } from 'http';
|
|
4
|
-
import { createLogger, errorMessage, installCrashHandlers } from '@pipeline-builder/api-core';
|
|
4
|
+
import { buildRouteTable, createLogger, errorMessage, installCrashHandlers, resolveRedisConnection, summarizeRouteTable } from '@pipeline-builder/api-core';
|
|
5
5
|
import { Config } from '@pipeline-builder/pipeline-core';
|
|
6
6
|
import { getConnection, closeConnection } from '@pipeline-builder/pipeline-data';
|
|
7
7
|
import { setReady, isReady } from './readiness.js';
|
|
@@ -113,6 +113,22 @@ export async function startServer(app, options = {}) {
|
|
|
113
113
|
const port = options.port ?? serverConfig.port;
|
|
114
114
|
// Validate auth configuration at server startup (not during CDK synthesis)
|
|
115
115
|
Config.validateAuth();
|
|
116
|
+
// Fail fast if this service has no internal signing key of its own, or no
|
|
117
|
+
// public bundle to verify its peers with (#14). Without them it would mint
|
|
118
|
+
// tokens on an EPHEMERAL in-process key that no peer accepts, and reject every
|
|
119
|
+
// peer's token — i.e. silently lose all service-to-service traffic. Checked
|
|
120
|
+
// HERE rather than in `createApp` because it is a property of the running
|
|
121
|
+
// deployment, not of the app object: route-table builders and test suites
|
|
122
|
+
// assemble an app without ever signing anything.
|
|
123
|
+
for (const envVar of ['SERVICE_SIGNING_KEY_FILE', 'SERVICE_KEY_BUNDLE_FILE']) {
|
|
124
|
+
if (!process.env[envVar]) {
|
|
125
|
+
throw new Error(`${envVar} environment variable is required (generate with deploy/bin/service-signing-keys.sh). Set it before starting the server.`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// Fail fast on an unusable Redis configuration (throws RedisConfigError) — a
|
|
129
|
+
// Redis client is created lazily on first use, so without this a bad config
|
|
130
|
+
// would surface as request-time errors instead of a failed start.
|
|
131
|
+
resolveRedisConnection();
|
|
116
132
|
logger.info(`Starting ${name}...`);
|
|
117
133
|
// Mark NotReady synchronously, BEFORE the port opens, so no request slips
|
|
118
134
|
// through the readiness guard before the supervisor has run. The supervisor
|
|
@@ -214,6 +230,11 @@ export async function startServer(app, options = {}) {
|
|
|
214
230
|
* ```
|
|
215
231
|
*/
|
|
216
232
|
export function runServer(app, options = {}) {
|
|
233
|
+
// Route table of the fully assembled app (see api-core's route-table.ts): the
|
|
234
|
+
// same introspection the per-service coverage test asserts on, logged once at
|
|
235
|
+
// boot so an ungated or unaudited write route is visible in the running
|
|
236
|
+
// service, not only in CI.
|
|
237
|
+
logger.info('Route table built', summarizeRouteTable(buildRouteTable(app)));
|
|
217
238
|
// Last-resort fault handlers for the production entrypoint: an unhandled
|
|
218
239
|
// rejection / uncaught exception is logged (not silently fatal) then the
|
|
219
240
|
// process exits for the orchestrator to restart. No-op under NODE_ENV=test.
|
|
@@ -231,4 +252,4 @@ export function runServer(app, options = {}) {
|
|
|
231
252
|
process.exit(1);
|
|
232
253
|
});
|
|
233
254
|
}
|
|
234
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FwaS9zZXJ2ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0QyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzlCLE9BQU8sRUFBRSxZQUFZLEVBQUUsWUFBWSxFQUFFLG9CQUFvQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDOUYsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ3pELE9BQU8sRUFBRSxhQUFhLEVBQUUsZUFBZSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFFakYsT0FBTyxFQUFFLFFBQVEsRUFBRSxPQUFPLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNuRCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQy9DLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUUvRCxNQUFNLE1BQU0sR0FBRyxZQUFZLENBQUMsUUFBUSxDQUFDLENBQUM7QUFFdEMsTUFBTSxLQUFLLEdBQUcsQ0FBQyxFQUFVLEVBQWlCLEVBQUUsQ0FBQyxJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO0FBRS9GLDhFQUE4RTtBQUM5RSw2RUFBNkU7QUFDN0UsNkVBQTZFO0FBQzdFLHlDQUF5QztBQUN6QyxNQUFNLG1CQUFtQixHQUFHLElBQUksQ0FBQztBQUNqQyxNQUFNLGtCQUFrQixHQUFHLEtBQUssQ0FBQztBQUNqQyxNQUFNLHlCQUF5QixHQUFHLFFBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLDZCQUE2QixJQUFJLE9BQU8sRUFBRSxFQUFFLENBQUMsQ0FBQztBQUVyRzs7Ozs7Ozs7Ozs7OztHQWFHO0FBQ0gsS0FBSyxVQUFVLHFCQUFxQixD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QUN4Qyw0RUFBNEU7UUFDNUUsMkVBQTJFO1FBQzNFLDRFQUE0RTtRQUM1RSxxRUFBcUU7UUFDckUsNkVBQTZFO1FBQzdFLE1BQU0sQ0FBQyxLQUFLLENBQUMsd0JBQXdCLEVBQUU7WUFDckMsS0FBSyxFQUFFLEtBQUssWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUM7WUFDN0QsS0FBSyxFQUFFLEtBQUssWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLFNBQVM7U0FDeEQsQ0FBQyxDQUFDO1FBQ0gsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNsQixDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuaW1wb3J0IHsgU2VydmVyIH0gZnJvbSAnaHR0cCc7XG5pbXBvcnQgeyBjcmVhdGVMb2dnZXIsIGVycm9yTWVzc2FnZSwgaW5zdGFsbENyYXNoSGFuZGxlcnMgfSBmcm9tICdAcGlwZWxpbmUtYnVpbGRlci9hcGktY29yZSc7XG5pbXBvcnQgeyBDb25maWcgfSBmcm9tICdAcGlwZWxpbmUtYnVpbGRlci9waXBlbGluZS1jb3JlJztcbmltcG9ydCB7IGdldENvbm5lY3Rpb24sIGNsb3NlQ29ubmVjdGlvbiB9IGZyb20gJ0BwaXBlbGluZS1idWlsZGVyL3BpcGVsaW5lLWRhdGEnO1xuaW1wb3J0IHR5cGUgeyBFeHByZXNzIH0gZnJvbSAnZXhwcmVzcyc7XG5pbXBvcnQgeyBzZXRSZWFkeSwgaXNSZWFkeSB9IGZyb20gJy4vcmVhZGluZXNzLmpzJztcbmltcG9ydCB7IHNodXRkb3duVHJhY2luZyB9IGZyb20gJy4vdHJhY2luZy5qcyc7XG5pbXBvcnQgeyBTU0VNYW5hZ2VyIH0gZnJvbSAnLi4vaHR0cC9zc2UtY29ubmVjdGlvbi1tYW5hZ2VyLmpzJztcblxuY29uc3QgbG9nZ2VyID0gY3JlYXRlTG9nZ2VyKCdzZXJ2ZXInKTtcblxuY29uc3Qgc2xlZXAgPSAobXM6IG51bWJlcik6IFByb21pc2U8dm9pZD4gPT4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgbXMpKTtcblxuLy8gRGVwZW5kZW5jeS1zdXBlcnZpc29yIGNhZGVuY2UuIEluaXRpYWwgY29ubmVjdCByZXRyaWVzIHdpdGggY2FwcGVkIGJhY2tvZmY7XG4vLyBvbmNlIGNvbm5lY3RlZCwgcmUtY2hlY2tzIGF0IGEgc3RlYWR5IGludGVydmFsIHNvIGEgbGF0ZXIgb3V0YWdlIGZsaXBzIHRoZVxuLy8gc2VydmljZSBOb3RSZWFkeSAoZHJhaW5pbmcgdHJhZmZpYykgYW5kIGEgcmVjb3ZlcnkgZmxpcHMgaXQgYmFjayDigJQgd2l0aG91dFxuLy8gZXZlciBleGl0aW5nIC8gcmVzdGFydGluZyB0aGUgcHJvY2Vzcy5cbmNvbnN0IFJFQURZX1JFVFJZX0JBU0VfTVMgPSAxMDAwO1xuY29uc3QgUkVBRFlfUkVUUllfTUFYX01TID0gMTAwMDA7XG5jb25zdCBSRUFEWV9NT05JVE9SX0lOVEVSVkFMX01TID0gcGFyc2VJbnQocHJvY2Vzcy5lbnYuUkVBRElORVNTX01PTklUT1JfSU5URVJWQUxfTVMgfHwgJzE1MDAwJywgMTApO1xuXG4vKipcbiAqIEVzdGFibGlzaCBhbmQgY29udGludW91c2x5IG1vbml0b3IgdGhlIHNlcnZpY2UncyBkYXRhc3RvcmUgZGVwZW5kZW5jeSxcbiAqIGZsaXBwaW5nIHJlYWRpbmVzcyBzdGF0ZSBpbnN0ZWFkIG9mIGNyYXNoLWxvb3BpbmcuXG4gKlxuICogLSBFc3RhYmxpc2ggcGhhc2U6IHJldHJ5IGBvbkJlZm9yZVN0YXJ0YCAoZS5nLiBjb25uZWN0TW9uZ28pIHdpdGggY2FwcGVkXG4gKiAgIGJhY2tvZmYgdW50aWwgaXQgc3VjY2VlZHMg4oCUIGEgY29sZCBkYXRhc3RvcmUgbXVzdCBuZXZlciBleGl0IHRoZSBwcm9jZXNzLlxuICogLSBNb25pdG9yIHBoYXNlOiBwb2xsIGB0ZXN0RGF0YWJhc2VgIGZvciB0aGUgbGlmZSBvZiB0aGUgcHJvY2VzczsgZmxpcFxuICogICByZWFkeS9Ob3RSZWFkeSBvbiB0cmFuc2l0aW9ucy4gV2hpbGUgTm90UmVhZHkgdGhlIHJlYWRpbmVzcyBndWFyZCA1MDNzXG4gKiAgIGJ1c2luZXNzIHRyYWZmaWMgYW5kIG9yY2hlc3RyYXRvciByZWFkaW5lc3MgcHJvYmVzIGRyYWluIHRoZSBpbnN0YW5jZS5cbiAqXG4gKiBSdW5zIGluIHRoZSBiYWNrZ3JvdW5kICh0aGUgSFRUUCBzZXJ2ZXIgaXMgYWxyZWFkeSBsaXN0ZW5pbmcpLiBTdG9wcyB3aGVuXG4gKiBgYWJvcnRlZCgpYCByZXR1cm5zIHRydWUgKGdyYWNlZnVsIHNodXRkb3duKSwgc28gaXQgbmV2ZXIga2VlcHMgYSBjbG9zaW5nXG4gKiBwcm9jZXNzIGFsaXZlLlxuICovXG5hc3luYyBmdW5jdGlvbiBzdXBlcnZpc2VEZXBlbmRlbmNpZXMoXG4gIG5hbWU6IHN0cmluZyxcbiAgb25CZWZvcmVTdGFydDogKCgpID0+IFByb21pc2U8dm9pZD4pIHwgdW5kZWZpbmVkLFxuICB0ZXN0RGF0YWJhc2U6ICgoKSA9PiBQcm9taXNlPGJvb2xlYW4+KSB8IGZhbHNlIHwgdW5kZWZpbmVkLFxuICBhYm9ydGVkOiAoKSA9PiBib29sZWFuLFxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGlmIChvbkJlZm9yZVN0YXJ0KSB7XG4gICAgbGV0IGRlbGF5ID0gUkVBRFlfUkVUUllfQkFTRV9NUztcbiAgICB3aGlsZSAoIWFib3J0ZWQoKSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgb25CZWZvcmVTdGFydCgpO1xuICAgICAgICBicmVhaztcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGxvZ2dlci53YXJuKGAke25hbWV9OiBkZXBlbmRlbmN5IGluaXQgZmFpbGVkLCByZXRyeWluZyBpbiAke2RlbGF5fW1zYCwgeyBlcnJvcjogZXJyb3JNZXNzYWdlKGVycm9yKSB9KTtcbiAgICAgICAgYXdhaXQgc2xlZXAoZGVsYXkpO1xuICAgICAgICBkZWxheSA9IE1hdGgubWluKGRlbGF5ICogMiwgUkVBRFlfUkVUUllfTUFYX01TKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvLyBObyBkYXRhc3RvcmUgdG8gZ2F0ZSBvbiDihpIgcmVhZHkgYXMgc29vbiBhcyB3ZSBhcmUgbGlzdGVuaW5nLlxuICBpZiAodGVzdERhdGFiYXNlID09PSBmYWxzZSkge1xuICAgIHNldFJlYWR5KHRydWUpO1xuICAgIGxvZ2dlci5pbmZvKGAke25hbWV9IHJlYWR5IChubyBkYXRhc3RvcmUgZGVwZW5kZW5jeSlgKTtcbiAgICByZXR1cm47XG4gIH1cblxuICBjb25zdCBwcm9iZSA9IHRlc3REYXRhYmFzZSA/PyAoKCkgPT4gZ2V0Q29ubmVjdGlvbigpLnRlc3RDb25uZWN0aW9uKCkpO1xuICBsZXQgd2FpdERlbGF5ID0gUkVBRFlfUkVUUllfQkFTRV9NUztcbiAgd2hpbGUgKCFhYm9ydGVkKCkpIHtcbiAgICBsZXQgb2sgPSBmYWxzZTtcbiAgICB0cnkge1xuICAgICAgb2sgPSBhd2FpdCBwcm9iZSgpO1xuICAgIH0gY2F0Y2gge1xuICAgICAgb2sgPSBmYWxzZTtcbiAgICB9XG5cbiAgICBpZiAob2sgJiYgIWlzUmVhZHkoKSkge1xuICAgICAgc2V0UmVhZHkodHJ1ZSk7XG4gICAgICB3YWl0RGVsYXkgPSBSRUFEWV9SRVRSWV9CQVNFX01TO1xuICAgICAgbG9nZ2VyLmluZm8oYCR7bmFtZX0gcmVhZHkg4oCUIGRlcGVuZGVuY2llcyBjb25uZWN0ZWRgKTtcbiAgICB9IGVsc2UgaWYgKCFvayAmJiBpc1JlYWR5KCkpIHtcbiAgICAgIHNldFJlYWR5KGZhbHNlKTtcbiAgICAgIGxvZ2dlci53YXJuKGAke25hbWV9IGRlZ3JhZGVkIOKAlCBkZXBlbmRlbmN5IGNoZWNrIGZhaWxpbmcgKG5vdyBOb3RSZWFkeSlgKTtcbiAgICB9XG5cbiAgICAvLyBTdGVhZHkgY2FkZW5jZSBvbmNlIHJlYWR5OyBmYXN0ZXIgYmFja29mZiB3aGlsZSB3YWl0aW5nIHNvIHdlIGZsaXAgdG9cbiAgICAvLyByZWFkeSBwcm9tcHRseSB3aGVuIHRoZSBkYXRhc3RvcmUgY29tZXMgdXAuXG4gICAgaWYgKGlzUmVhZHkoKSkge1xuICAgICAgYXdhaXQgc2xlZXAoUkVBRFlfTU9OSVRPUl9JTlRFUlZBTF9NUyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGF3YWl0IHNsZWVwKHdhaXREZWxheSk7XG4gICAgICB3YWl0RGVsYXkgPSBNYXRoLm1pbih3YWl0RGVsYXkgKiAyLCBSRUFEWV9SRVRSWV9NQVhfTVMpO1xuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIE9wdGlvbnMgZm9yIHN0YXJ0aW5nIGEgc2VydmVyXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU3RhcnRTZXJ2ZXJPcHRpb25zIHtcbiAgLyoqIFNlcnZpY2UgbmFtZSBmb3IgbG9nZ2luZyAqL1xuICBuYW1lPzogc3RyaW5nO1xuICAvKiogUG9ydCB0byBsaXN0ZW4gb24gKGRlZmF1bHQ6IGZyb20gY29uZmlnKSAqL1xuICBwb3J0PzogbnVtYmVyO1xuICAvKiogU1NFIG1hbmFnZXIgZm9yIGdyYWNlZnVsIHNodXRkb3duICovXG4gIHNzZU1hbmFnZXI/OiBTU0VNYW5hZ2VyO1xuICAvKiogU2h1dGRvd24gdGltZW91dCBpbiBtaWxsaXNlY29uZHMgKGRlZmF1bHQ6IDE1MDAwKSAqL1xuICBzaHV0ZG93blRpbWVvdXRNcz86IG51bWJlcjtcbiAgLyoqIENhbGxiYWNrIGFmdGVyIHNlcnZlciBzdGFydHMgKi9cbiAgb25TdGFydD86IChwb3J0OiBudW1iZXIpID0+IHZvaWQ7XG4gIC8qKiBDYWxsYmFjayBiZWZvcmUgc2h1dGRvd24gKi9cbiAgb25TaHV0ZG93bj86ICgpID0+IFByb21pc2U8dm9pZD47XG4gIC8qKiBSdW5zIGJlZm9yZSBkYXRhYmFzZSBjaGVjayAoZS5nLiwgaW5pdGlhbGl6ZSBleHRlcm5hbCBjb25uZWN0aW9ucykgKi9cbiAgb25CZWZvcmVTdGFydD86ICgpID0+IFByb21pc2U8dm9pZD47XG4gIC8qKiBDdXN0b20gZGF0YWJhc2UgaGVhbHRoIGNoZWNrLCBvciBmYWxzZSB0byBza2lwLiBEZWZhdWx0OiBQb3N0Z3JlU1FMIHRlc3RDb25uZWN0aW9uICovXG4gIHRlc3REYXRhYmFzZT86ICgoKSA9PiBQcm9taXNlPGJvb2xlYW4+KSB8IGZhbHNlO1xuICAvKiogQ3VzdG9tIGRhdGFiYXNlIGNsb3NlLCBvciBmYWxzZSB0byBza2lwLiBEZWZhdWx0OiBQb3N0Z3JlU1FMIGNsb3NlQ29ubmVjdGlvbiAqL1xuICBjbG9zZURhdGFiYXNlPzogKCgpID0+IFByb21pc2U8dm9pZD4pIHwgZmFsc2U7XG59XG5cbi8qKlxuICogUmVzdWx0IG9mIHN0YXJ0aW5nIGEgc2VydmVyXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU3RhcnRTZXJ2ZXJSZXN1bHQge1xuICAvKiogSFRUUCBzZXJ2ZXIgaW5zdGFuY2UgKi9cbiAgc2VydmVyOiBTZXJ2ZXI7XG4gIC8qKiBQb3J0IHRoZSBzZXJ2ZXIgaXMgbGlzdGVuaW5nIG9uICovXG4gIHBvcnQ6IG51bWJlcjtcbiAgLyoqIEZ1bmN0aW9uIHRvIG1hbnVhbGx5IHRyaWdnZXIgc2h1dGRvd24gKi9cbiAgc2h1dGRvd246ICgpID0+IFByb21pc2U8dm9pZD47XG59XG5cbi8qKlxuICogU3RhcnQgYW4gRXhwcmVzcyBzZXJ2ZXIgd2l0aCBncmFjZWZ1bCBzaHV0ZG93biBoYW5kbGluZ1xuICpcbiAqIEZlYXR1cmVzOlxuICogLSBBdXRvbWF0aWMgZGF0YWJhc2UgY29ubmVjdGlvbiB0ZXN0aW5nXG4gKiAtIEdyYWNlZnVsIHNodXRkb3duIG9uIFNJR0lOVC9TSUdURVJNXG4gKiAtIFNTRSBjb25uZWN0aW9uIGNsZWFudXBcbiAqIC0gQ29uZmlndXJhYmxlIHNodXRkb3duIHRpbWVvdXRcbiAqXG4gKiBAcGFyYW0gYXBwIC0gRXhwcmVzcyBhcHBsaWNhdGlvblxuICogQHBhcmFtIG9wdGlvbnMgLSBTZXJ2ZXIgb3B0aW9uc1xuICogQHJldHVybnMgU2VydmVyIGluc3RhbmNlIGFuZCBjb250cm9sIGZ1bmN0aW9uc1xuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjb25zdCB7IGFwcCwgc3NlTWFuYWdlciB9ID0gY3JlYXRlQXBwKCk7XG4gKlxuICogYXBwLnBvc3QoJy9hcGkvcmVzb3VyY2UnLCByZXF1aXJlQXV0aCwgaGFuZGxlcik7XG4gKlxuICogYXdhaXQgc3RhcnRTZXJ2ZXIoYXBwLCB7XG4gKiAgIG5hbWU6ICdNeSBNaWNyb3NlcnZpY2UnLFxuICogICBzc2VNYW5hZ2VyLFxuICogICBvblN0YXJ0OiAocG9ydCkgPT4gY29uc29sZS5sb2coYExpc3RlbmluZyBvbiAke3BvcnR9YCksXG4gKiB9KTtcbiAqIGBgYFxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc3RhcnRTZXJ2ZXIoXG4gIGFwcDogRXhwcmVzcyxcbiAgb3B0aW9uczogU3RhcnRTZXJ2ZXJPcHRpb25zID0ge30sXG4pOiBQcm9taXNlPFN0YXJ0U2VydmVyUmVzdWx0PiB7XG4gIGNvbnN0IHNlcnZlckNvbmZpZyA9IENvbmZpZy5nZXQoJ3NlcnZlcicpO1xuICBjb25zdCB7XG4gICAgbmFtZSA9ICdNaWNyb3NlcnZpY2UnLFxuICAgIHNzZU1hbmFnZXIsXG4gICAgc2h1dGRvd25UaW1lb3V0TXMgPSAxNTAwMCxcbiAgICBvblN0YXJ0LFxuICAgIG9uU2h1dGRvd24sXG4gICAgb25CZWZvcmVTdGFydCxcbiAgICB0ZXN0RGF0YWJhc2UsXG4gICAgY2xvc2VEYXRhYmFzZSxcbiAgfSA9IG9wdGlvbnM7XG4gIGNvbnN0IHBvcnQgPSBvcHRpb25zLnBvcnQgPz8gc2VydmVyQ29uZmlnLnBvcnQ7XG5cbiAgLy8gVmFsaWRhdGUgYXV0aCBjb25maWd1cmF0aW9uIGF0IHNlcnZlciBzdGFydHVwIChub3QgZHVyaW5nIENESyBzeW50aGVzaXMpXG4gIENvbmZpZy52YWxpZGF0ZUF1dGgoKTtcblxuICBsb2dnZXIuaW5mbyhgU3RhcnRpbmcgJHtuYW1lfS4uLmApO1xuXG4gIC8vIE1hcmsgTm90UmVhZHkgc3luY2hyb25vdXNseSwgQkVGT1JFIHRoZSBwb3J0IG9wZW5zLCBzbyBubyByZXF1ZXN0IHNsaXBzXG4gIC8vIHRocm91Z2ggdGhlIHJlYWRpbmVzcyBndWFyZCBiZWZvcmUgdGhlIHN1cGVydmlzb3IgaGFzIHJ1bi4gVGhlIHN1cGVydmlzb3JcbiAgLy8gZmxpcHMgaXQgdHJ1ZSBvbmNlIGRlcGVuZGVuY2llcyBjb25uZWN0LlxuICBzZXRSZWFkeShmYWxzZSk7XG5cbiAgLy8gTGlzdGVuIEZJUlNULiBQcmV2aW91c2x5IHRoZSBwcm9jZXNzIHRlc3RlZCB0aGUgREIgYW5kIGBwcm9jZXNzLmV4aXQoMSlgJ2RcbiAgLy8gb24gZmFpbHVyZSAodG8gYmUgcmVzdGFydGVkKSwgc28gZHVyaW5nIGEgY29sZC1EQiBzdGFtcGVkZSBzZXJ2aWNlc1xuICAvLyBjcmFzaC1sb29wZWQgYW5kIG5ldmVyIGV2ZW4gb3BlbmVkIHRoZWlyIHBvcnQuIE5vdyB3ZSBvcGVuIHRoZSBwb3J0XG4gIC8vIGltbWVkaWF0ZWx5IOKAlCAvaGVhbHRoIChsaXZlbmVzcyksIC9yZWFkeSAocmVhZGluZXNzKSBhbmQgdGhlIHJlYWRpbmVzc1xuICAvLyBndWFyZCBhbGwgcmVzcG9uZCBhdCBvbmNlIOKAlCBhbmQgZXN0YWJsaXNoICsgbW9uaXRvciB0aGUgZGF0YXN0b3JlIGluIHRoZVxuICAvLyBiYWNrZ3JvdW5kLCByZXBvcnRpbmcgTm90UmVhZHkgdW50aWwgaXQgY29ubmVjdHMgaW5zdGVhZCBvZiBleGl0aW5nLlxuICBjb25zdCBzZXJ2ZXIgPSBhcHAubGlzdGVuKHBvcnQsICgpID0+IHtcbiAgICBsb2dnZXIuaW5mbyhgJHtuYW1lfSBsaXN0ZW5pbmcgb24gcG9ydDogJHtwb3J0fWApO1xuICAgIGxvZ2dlci5pbmZvKGBQbGF0Zm9ybSBVUkw6ICR7c2VydmVyQ29uZmlnLnBsYXRmb3JtVXJsfWApO1xuICAgIG9uU3RhcnQ/Lihwb3J0KTtcbiAgfSk7XG5cbiAgLy8gU2h1dGRvd24gaGFuZGxlciAoZ3VhcmRlZCBhZ2FpbnN0IGNvbmN1cnJlbnQgc2lnbmFscylcbiAgbGV0IHNodXR0aW5nRG93biA9IGZhbHNlO1xuXG4gIC8vIEJhY2tncm91bmQgZGVwZW5kZW5jeSBzdXBlcnZpc29yIOKAlCBlc3RhYmxpc2hlZCArIG1vbml0b3JlZCBhZnRlciBsaXN0ZW4sXG4gIC8vIHN0b3BwZWQgb24gc2h1dGRvd24gc28gaXQgbmV2ZXIga2VlcHMgYSBjbG9zaW5nIHByb2Nlc3MgYWxpdmUuIEd1YXJkIHRoZVxuICAvLyBmbG9hdGluZyBwcm9taXNlOiBldmVyeSBleHBlY3RlZCBmYWlsdXJlIGlzIGhhbmRsZWQgaW5zaWRlLCBzbyBhIHJlamVjdGlvblxuICAvLyBoZXJlIG1lYW5zIGEgcHJvZ3JhbW1pbmcgZXJyb3Ig4oCUIGxvZyBpdCBhbmQgbGVhdmUgdGhlIHNlcnZpY2UgTm90UmVhZHlcbiAgLy8gcmF0aGVyIHRoYW4gbGV0dGluZyBpdCBiZWNvbWUgYW4gdW5oYW5kbGVkUmVqZWN0aW9uIHRoYXQgY3Jhc2gtZXhpdHMgdGhlXG4gIC8vIHByb2Nlc3MgKHdoaWNoIHdvdWxkIGRlZmVhdCB0aGUgd2hvbGUgXCJuZXZlciBleGl0IG9uIGRlcGVuZGVuY3kgdHJvdWJsZVwiXG4gIC8vIGdvYWwpLlxuICBzdXBlcnZpc2VEZXBlbmRlbmNpZXMobmFtZSwgb25CZWZvcmVTdGFydCwgdGVzdERhdGFiYXNlLCAoKSA9PiBzaHV0dGluZ0Rvd24pLmNhdGNoKChlcnJvcikgPT4ge1xuICAgIGxvZ2dlci5lcnJvcignRGVwZW5kZW5jeSBzdXBlcnZpc29yIGNyYXNoZWQ7IHNlcnZpY2Ugd2lsbCByZW1haW4gTm90UmVhZHknLCB7IGVycm9yOiBlcnJvck1lc3NhZ2UoZXJyb3IpIH0pO1xuICB9KTtcblxuICBjb25zdCBzaHV0ZG93biA9IGFzeW5jIChzaWduYWw/OiBzdHJpbmcpID0+IHtcbiAgICBpZiAoc2h1dHRpbmdEb3duKSByZXR1cm47XG4gICAgc2h1dHRpbmdEb3duID0gdHJ1ZTtcblxuICAgIGlmIChzaWduYWwpIHtcbiAgICAgIGxvZ2dlci5pbmZvKGAke3NpZ25hbH0gcmVjZWl2ZWQsIHNodXR0aW5nIGRvd24gZ3JhY2VmdWxseS4uLmApO1xuICAgIH1cblxuICAgIC8vIEN1c3RvbSBzaHV0ZG93biBjYWxsYmFja1xuICAgIGlmIChvblNodXRkb3duKSB7XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCBvblNodXRkb3duKCk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBsb2dnZXIuZXJyb3IoJ0Vycm9yIGluIG9uU2h1dGRvd24gY2FsbGJhY2snLCB7IGVycm9yIH0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIENsb3NlIFNTRSBjb25uZWN0aW9uc1xuICAgIGlmIChzc2VNYW5hZ2VyKSB7XG4gICAgICBzc2VNYW5hZ2VyLnNodXRkb3duKCk7XG4gICAgICBsb2dnZXIuaW5mbygnU1NFIGNvbm5lY3Rpb25zIGNsb3NlZCcpO1xuICAgIH1cblxuICAgIC8vIENsb3NlIEhUVFAgc2VydmVyXG4gICAgc2VydmVyLmNsb3NlKGFzeW5jICgpID0+IHtcbiAgICAgIGxvZ2dlci5pbmZvKCdIVFRQIHNlcnZlciBjbG9zZWQnKTtcblxuICAgICAgLy8gU2h1dGRvd24gT3BlblRlbGVtZXRyeSB0cmFjaW5nXG4gICAgICBhd2FpdCBzaHV0ZG93blRyYWNpbmcoKS5jYXRjaChlcnIgPT4gbG9nZ2VyLmVycm9yKCdFcnJvciBzaHV0dGluZyBkb3duIHRyYWNpbmcnLCB7IGVycm9yOiBlcnIgfSkpO1xuXG4gICAgICAvLyBDbG9zZSBkYXRhYmFzZSBjb25uZWN0aW9uXG4gICAgICBpZiAoY2xvc2VEYXRhYmFzZSAhPT0gZmFsc2UpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBpZiAoY2xvc2VEYXRhYmFzZSkge1xuICAgICAgICAgICAgYXdhaXQgY2xvc2VEYXRhYmFzZSgpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBhd2FpdCBjbG9zZUNvbm5lY3Rpb24oKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgbG9nZ2VyLmluZm8oJ0RhdGFiYXNlIGNvbm5lY3Rpb24gY2xvc2VkJyk7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgbG9nZ2VyLmVycm9yKCdFcnJvciBjbG9zaW5nIGRhdGFiYXNlJywgeyBlcnJvciB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBwcm9jZXNzLmV4aXQoMCk7XG4gICAgfSk7XG5cbiAgICAvLyBGb3JjZSBzaHV0ZG93biBhZnRlciB0aW1lb3V0XG4gICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICBsb2dnZXIuZXJyb3IoJ0ZvcmNlZCBzaHV0ZG93biBhZnRlciB0aW1lb3V0Jyk7XG4gICAgICBwcm9jZXNzLmV4aXQoMSk7XG4gICAgfSwgc2h1dGRvd25UaW1lb3V0TXMpLnVucmVmKCk7XG4gIH07XG5cbiAgLy8gUmVnaXN0ZXIgc2lnbmFsIGhhbmRsZXJzXG4gIHByb2Nlc3Mub25jZSgnU0lHSU5UJywgKCkgPT4gdm9pZCBzaHV0ZG93bignU0lHSU5UJykpO1xuICBwcm9jZXNzLm9uY2UoJ1NJR1RFUk0nLCAoKSA9PiB2b2lkIHNodXRkb3duKCdTSUdURVJNJykpO1xuXG4gIHJldHVybiB7XG4gICAgc2VydmVyLFxuICAgIHBvcnQsXG4gICAgc2h1dGRvd246ICgpID0+IHNodXRkb3duKCksXG4gIH07XG59XG5cbi8qKlxuICogU2ltcGxlIHNlcnZlciBzdGFydCB3cmFwcGVyIHdpdGggZXJyb3IgaGFuZGxpbmdcbiAqXG4gKiBAcGFyYW0gYXBwIC0gRXhwcmVzcyBhcHBsaWNhdGlvblxuICogQHBhcmFtIG9wdGlvbnMgLSBTZXJ2ZXIgb3B0aW9uc1xuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjb25zdCB7IGFwcCwgc3NlTWFuYWdlciB9ID0gY3JlYXRlQXBwKCk7XG4gKiBhcHAucG9zdCgnL2FwaS9yZXNvdXJjZScsIGhhbmRsZXIpO1xuICpcbiAqIHZvaWQgcnVuU2VydmVyKGFwcCwgeyBuYW1lOiAnTXkgU2VydmljZScsIHNzZU1hbmFnZXIgfSk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJ1blNlcnZlcihhcHA6IEV4cHJlc3MsIG9wdGlvbnM6IFN0YXJ0U2VydmVyT3B0aW9ucyA9IHt9KTogdm9pZCB7XG4gIC8vIExhc3QtcmVzb3J0IGZhdWx0IGhhbmRsZXJzIGZvciB0aGUgcHJvZHVjdGlvbiBlbnRyeXBvaW50OiBhbiB1bmhhbmRsZWRcbiAgLy8gcmVqZWN0aW9uIC8gdW5jYXVnaHQgZXhjZXB0aW9uIGlzIGxvZ2dlZCAobm90IHNpbGVudGx5IGZhdGFsKSB0aGVuIHRoZVxuICAvLyBwcm9jZXNzIGV4aXRzIGZvciB0aGUgb3JjaGVzdHJhdG9yIHRvIHJlc3RhcnQuIE5vLW9wIHVuZGVyIE5PREVfRU5WPXRlc3QuXG4gIGluc3RhbGxDcmFzaEhhbmRsZXJzKGxvZ2dlcik7XG4gIHN0YXJ0U2VydmVyKGFwcCwgb3B0aW9ucykuY2F0Y2goKGVycm9yKSA9PiB7XG4gICAgLy8gc3RhcnRTZXJ2ZXIgbm93IGxpc3RlbnMtZmlyc3QgYW5kIHN1cGVydmlzZXMgdGhlIERCIGluIHRoZSBiYWNrZ3JvdW5kLCBzb1xuICAgIC8vIGl0IG9ubHkgcmVqZWN0cyBvbiBhIGdlbnVpbmVseSBmYXRhbCBTRVRVUCBlcnJvciAoaW52YWxpZCBhdXRoIGNvbmZpZywgYVxuICAgIC8vIGZhaWxlZCBvblN0YXJ0LCB0aGUgcG9ydCBhbHJlYWR5IGluIHVzZSkuIExvZyBtZXNzYWdlICsgc3RhY2sgZXhwbGljaXRseTpcbiAgICAvLyBhbiBFcnJvciBpbiB3aW5zdG9uIG1ldGFkYXRhIHNlcmlhbGl6ZXMgdG8gYHt9YCAobWVzc2FnZS9zdGFjayBhcmVcbiAgICAvLyBub24tZW51bWVyYWJsZSksIHdoaWNoIHdvdWxkIG90aGVyd2lzZSBoaWRlIHRoZSBjYXVzZSBiZWhpbmQgYHtlcnJvcjp7fX1gLlxuICAgIGxvZ2dlci5lcnJvcignRmFpbGVkIHRvIHN0YXJ0IHNlcnZlcicsIHtcbiAgICAgIGVycm9yOiBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvciksXG4gICAgICBzdGFjazogZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLnN0YWNrIDogdW5kZWZpbmVkLFxuICAgIH0pO1xuICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgfSk7XG59XG4iXX0=
|
|
255
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FwaS9zZXJ2ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0QyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzlCLE9BQU8sRUFBRSxlQUFlLEVBQUUsWUFBWSxFQUFFLFlBQVksRUFBRSxvQkFBb0IsRUFBRSxzQkFBc0IsRUFBRSxtQkFBbUIsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQzVKLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUN6RCxPQUFPLEVBQUUsYUFBYSxFQUFFLGVBQWUsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBRWpGLE9BQU8sRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDbkQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUMvQyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sbUNBQW1DLENBQUM7QUFFL0QsTUFBTSxNQUFNLEdBQUcsWUFBWSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBRXRDLE1BQU0sS0FBSyxHQUFHLENBQUMsRUFBVSxFQUFpQixFQUFFLENBQUMsSUFBSSxPQUFPLENBQUMsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLFVBQVUsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQztBQUUvRiw4RUFBOEU7QUFDOUUsNkVBQTZFO0FBQzdFLDZFQUE2RTtBQUM3RSx5Q0FBeUM7QUFDekMsTUFBTSxtQkFBbUIsR0FBRyxJQUFJLENBQUM7QUFDakMsTUFBTSxrQkFBa0IsR0FBRyxLQUFLLENBQUM7QUFDakMsTUFBTSx5QkFBeUIsR0FBRyxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyw2QkFBNkIsSUFBSSxPQUFPLEVBQUUsRUFBRSxDQUFDLENBQUM7QUFFckc7Ozs7Ozs7Ozs7Ozs7R0FhRztBQUNILEtBQUssVUFBVSxxQkFBcUIsQ0FDbEMsSUFBWSxFQUNaLGFBQWdELEVBQ2hELFlBQTBELEVBQzFELE9BQXNCO0lBRXRCLElBQUksYUFBYSxFQUFFLENBQUM7UUFDbEIsSUFBSSxLQUFLLEdBQUcsbUJBQW1CLENBQUM7UUFDaEMsT0FBTyxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUM7WUFDbEIsSUFBSSxDQUFDO2dCQUNILE1BQU0sYUFBYSxFQUFFLENBQUM7Z0JBQ3RCLE1BQU07WUFDUixDQUFDO1lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztnQkFDZixNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsSUFBSSx5Q0FBeUMsS0FBSyxJQUFJLEVBQUUsRUFBRSxLQUFLLEVBQUUsWUFBWSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQztnQkFDdkcsTUFBTSxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUM7Z0JBQ25CLEtBQUssR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssR0FBRyxDQUFDLEVBQUUsa0JBQWtCLENBQUMsQ0FBQztZQUNsRCxDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFFRCwrREFBK0Q7SUFDL0QsSUFBSSxZQUFZLEtBQUssS0FBSyxFQUFFLENBQUM7UUFDM0IsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ2YsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLElBQUksa0NBQWtDLENBQUMsQ0FBQztRQUN2RCxPQUFPO0lBQ1QsQ0FBQztJQUVELE1BQU0sS0FBSyxHQUFHLFlBQVksSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLGFBQWEsRUFBRSxDQUFDLGNBQWMsRUFBRSxDQUFDLENBQUM7SUFDdkUsSUFBSSxTQUFTLEdBQUcsbUJBQW1CLENBQUM7SUFDcEMsT0FBTyxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUM7UUFDbEIsSUFBSSxFQUFFLEdBQUcsS0FBSyxDQUFDO1FBQ2YsSUFBSSxDQUFDO1lBQ0gsRUFBRSxHQUFHLE1BQU0sS0FBSyxFQUFFLENBQUM7UUFDckIsQ0FBQztRQUFDLE1BQU0sQ0FBQztZQUNQLEVBQUUsR0FBRyxLQUFLLENBQUM7UUFDYixDQUFDO1FBRUQsSUFBSSxFQUFFLElBQUksQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDO1lBQ3JCLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUNmLFNBQVMsR0FBRyxtQkFBbUIsQ0FBQztZQUNoQyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsSUFBSSxpQ0FBaUMsQ0FBQyxDQUFDO1FBQ3hELENBQUM7YUFBTSxJQUFJLENBQUMsRUFBRSxJQUFJLE9BQU8sRUFBRSxFQUFFLENBQUM7WUFDNUIsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ2hCLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxJQUFJLHFEQUFxRCxDQUFDLENBQUM7UUFDNUUsQ0FBQztRQUVELHdFQUF3RTtRQUN4RSw4Q0FBOEM7UUFDOUMsSUFBSSxPQUFPLEVBQUUsRUFBRSxDQUFDO1lBQ2QsTUFBTSxLQUFLLENBQUMseUJBQXlCLENBQUMsQ0FBQztRQUN6QyxDQUFDO2FBQU0sQ0FBQztZQUNOLE1BQU0sS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1lBQ3ZCLFNBQVMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLFNBQVMsR0FBRyxDQUFDLEVBQUUsa0JBQWtCLENBQUMsQ0FBQztRQUMxRCxDQUFDO0lBQ0gsQ0FBQztBQUNILENBQUM7QUFzQ0Q7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F5Qkc7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLFdBQVcsQ0FDL0IsR0FBWSxFQUNaLE9BQU8sR0FBdUIsRUFBRTtJQUVoQyxNQUFNLFlBQVksR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQzFDLE1BQU0sRUFDSixJQUFJLEdBQUcsY0FBYyxFQUNyQixVQUFVLEVBQ1YsaUJBQWlCLEdBQUcsS0FBSyxFQUN6QixPQUFPLEVBQ1AsVUFBVSxFQUNWLGFBQWEsRUFDYixZQUFZLEVBQ1osYUFBYSxHQUNkLEdBQUcsT0FBTyxDQUFDO0lBQ1osTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLElBQUksSUFBSSxZQUFZLENBQUMsSUFBSSxDQUFDO0lBRS9DLDJFQUEyRTtJQUMzRSxNQUFNLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDdEIsMEVBQTBFO0lBQzFFLDJFQUEyRTtJQUMzRSwrRUFBK0U7SUFDL0UsNEVBQTRFO0lBQzVFLDBFQUEwRTtJQUMxRSwwRUFBMEU7SUFDMUUsaURBQWlEO0lBQ2pELEtBQUssTUFBTSxNQUFNLElBQUksQ0FBQywwQkFBMEIsRUFBRSx5QkFBeUIsQ0FBVSxFQUFFLENBQUM7UUFDdEYsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztZQUN6QixNQUFNLElBQUksS0FBSyxDQUFDLEdBQUcsTUFBTSwwSEFBMEgsQ0FBQyxDQUFDO1FBQ3ZKLENBQUM7SUFDSCxDQUFDO0lBQ0QsNkVBQTZFO0lBQzdFLDRFQUE0RTtJQUM1RSxrRUFBa0U7SUFDbEUsc0JBQXNCLEVBQUUsQ0FBQztJQUV6QixNQUFNLENBQUMsSUFBSSxDQUFDLFlBQVksSUFBSSxLQUFLLENBQUMsQ0FBQztJQUVuQywwRUFBMEU7SUFDMUUsNEVBQTRFO0lBQzVFLDJDQUEyQztJQUMzQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUM7SUFFaEIsNkVBQTZFO0lBQzdFLHNFQUFzRTtJQUN0RSxzRUFBc0U7SUFDdEUseUVBQXlFO0lBQ3pFLDJFQUEyRTtJQUMzRSx1RUFBdUU7SUFDdkUsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQyxJQUFJLEVBQUUsR0FBRyxFQUFFO1FBQ25DLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxJQUFJLHVCQUF1QixJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBQ2xELE1BQU0sQ0FBQyxJQUFJLENBQUMsaUJBQWlCLFlBQVksQ0FBQyxXQUFXLEVBQUUsQ0FBQyxDQUFDO1FBQ3pELE9BQU8sRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2xCLENBQUMsQ0FBQyxDQUFDO0lBRUgsd0RBQXdEO0lBQ3hELElBQUksWUFBWSxHQUFHLEtBQUssQ0FBQztJQUV6QiwyRUFBMkU7SUFDM0UsMkVBQTJFO0lBQzNFLDZFQUE2RTtJQUM3RSx5RUFBeUU7SUFDekUsMkVBQTJFO0lBQzNFLDJFQUEyRTtJQUMzRSxTQUFTO0lBQ1QscUJBQXFCLENBQUMsSUFBSSxFQUFFLGFBQWEsRUFBRSxZQUFZLEVBQUUsR0FBRyxFQUFFLENBQUMsWUFBWSxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUU7UUFDM0YsTUFBTSxDQUFDLEtBQUssQ0FBQyw2REFBNkQsRUFBRSxFQUFFLEtBQUssRUFBRSxZQUFZLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzlHLENBQUMsQ0FBQyxDQUFDO0lBRUgsTUFBTSxRQUFRLEdBQUcsS0FBSyxFQUFFLE1BQWUsRUFBRSxFQUFFO1FBQ3pDLElBQUksWUFBWTtZQUFFLE9BQU87UUFDekIsWUFBWSxHQUFHLElBQUksQ0FBQztRQUVwQixJQUFJLE1BQU0sRUFBRSxDQUFDO1lBQ1gsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLE1BQU0sd0NBQXdDLENBQUMsQ0FBQztRQUNqRSxDQUFDO1FBRUQsMkJBQTJCO1FBQzNCLElBQUksVUFBVSxFQUFFLENBQUM7WUFDZixJQUFJLENBQUM7Z0JBQ0gsTUFBTSxVQUFVLEVBQUUsQ0FBQztZQUNyQixDQUFDO1lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztnQkFDZixNQUFNLENBQUMsS0FBSyxDQUFDLDhCQUE4QixFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztZQUMxRCxDQUFDO1FBQ0gsQ0FBQztRQUVELHdCQUF3QjtRQUN4QixJQUFJLFVBQVUsRUFBRSxDQUFDO1lBQ2YsVUFBVSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ3RCLE1BQU0sQ0FBQyxJQUFJLENBQUMsd0JBQXdCLENBQUMsQ0FBQztRQUN4QyxDQUFDO1FBRUQsb0JBQW9CO1FBQ3BCLE1BQU0sQ0FBQyxLQUFLLENBQUMsS0FBSyxJQUFJLEVBQUU7WUFDdEIsTUFBTSxDQUFDLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO1lBRWxDLGlDQUFpQztZQUNqQyxNQUFNLGVBQWUsRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsNkJBQTZCLEVBQUUsRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDO1lBRWxHLDRCQUE0QjtZQUM1QixJQUFJLGFBQWEsS0FBSyxLQUFLLEVBQUUsQ0FBQztnQkFDNUIsSUFBSSxDQUFDO29CQUNILElBQUksYUFBYSxFQUFFLENBQUM7d0JBQ2xCLE1BQU0sYUFBYSxFQUFFLENBQUM7b0JBQ3hCLENBQUM7eUJBQU0sQ0FBQzt3QkFDTixNQUFNLGVBQWUsRUFBRSxDQUFDO29CQUMxQixDQUFDO29CQUNELE1BQU0sQ0FBQyxJQUFJLENBQUMsNEJBQTRCLENBQUMsQ0FBQztnQkFDNUMsQ0FBQztnQkFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO29CQUNmLE1BQU0sQ0FBQyxLQUFLLENBQUMsd0JBQXdCLEVBQUUsRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDO2dCQUNwRCxDQUFDO1lBQ0gsQ0FBQztZQUVELE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDbEIsQ0FBQyxDQUFDLENBQUM7UUFFSCwrQkFBK0I7UUFDL0IsVUFBVSxDQUFDLEdBQUcsRUFBRTtZQUNkLE1BQU0sQ0FBQyxLQUFLLENBQUMsK0JBQStCLENBQUMsQ0FBQztZQUM5QyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ2xCLENBQUMsRUFBRSxpQkFBaUIsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ2hDLENBQUMsQ0FBQztJQUVGLDJCQUEyQjtJQUMzQixPQUFPLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxHQUFHLEVBQUUsQ0FBQyxLQUFLLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDO0lBQ3RELE9BQU8sQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLEdBQUcsRUFBRSxDQUFDLEtBQUssUUFBUSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUM7SUFFeEQsT0FBTztRQUNMLE1BQU07UUFDTixJQUFJO1FBQ0osUUFBUSxFQUFFLEdBQUcsRUFBRSxDQUFDLFFBQVEsRUFBRTtLQUMzQixDQUFDO0FBQ0osQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7O0dBYUc7QUFDSCxNQUFNLFVBQVUsU0FBUyxDQUFDLEdBQVksRUFBRSxPQUFPLEdBQXVCLEVBQUU7SUFDdEUsOEVBQThFO0lBQzlFLDhFQUE4RTtJQUM5RSx3RUFBd0U7SUFDeEUsMkJBQTJCO0lBQzNCLE1BQU0sQ0FBQyxJQUFJLENBQUMsbUJBQW1CLEVBQUUsbUJBQW1CLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUU1RSx5RUFBeUU7SUFDekUseUVBQXlFO0lBQ3pFLDRFQUE0RTtJQUM1RSxvQkFBb0IsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUM3QixXQUFXLENBQUMsR0FBRyxFQUFFLE9BQU8sQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFO1FBQ3hDLDRFQUE0RTtRQUM1RSwyRUFBMkU7UUFDM0UsNEVBQTRFO1FBQzVFLHFFQUFxRTtRQUNyRSw2RUFBNkU7UUFDN0UsTUFBTSxDQUFDLEtBQUssQ0FBQyx3QkFBd0IsRUFBRTtZQUNyQyxLQUFLLEVBQUUsS0FBSyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQztZQUM3RCxLQUFLLEVBQUUsS0FBSyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsU0FBUztTQUN4RCxDQUFDLENBQUM7UUFDSCxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ2xCLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgeyBTZXJ2ZXIgfSBmcm9tICdodHRwJztcbmltcG9ydCB7IGJ1aWxkUm91dGVUYWJsZSwgY3JlYXRlTG9nZ2VyLCBlcnJvck1lc3NhZ2UsIGluc3RhbGxDcmFzaEhhbmRsZXJzLCByZXNvbHZlUmVkaXNDb25uZWN0aW9uLCBzdW1tYXJpemVSb3V0ZVRhYmxlIH0gZnJvbSAnQHBpcGVsaW5lLWJ1aWxkZXIvYXBpLWNvcmUnO1xuaW1wb3J0IHsgQ29uZmlnIH0gZnJvbSAnQHBpcGVsaW5lLWJ1aWxkZXIvcGlwZWxpbmUtY29yZSc7XG5pbXBvcnQgeyBnZXRDb25uZWN0aW9uLCBjbG9zZUNvbm5lY3Rpb24gfSBmcm9tICdAcGlwZWxpbmUtYnVpbGRlci9waXBlbGluZS1kYXRhJztcbmltcG9ydCB0eXBlIHsgRXhwcmVzcyB9IGZyb20gJ2V4cHJlc3MnO1xuaW1wb3J0IHsgc2V0UmVhZHksIGlzUmVhZHkgfSBmcm9tICcuL3JlYWRpbmVzcy5qcyc7XG5pbXBvcnQgeyBzaHV0ZG93blRyYWNpbmcgfSBmcm9tICcuL3RyYWNpbmcuanMnO1xuaW1wb3J0IHsgU1NFTWFuYWdlciB9IGZyb20gJy4uL2h0dHAvc3NlLWNvbm5lY3Rpb24tbWFuYWdlci5qcyc7XG5cbmNvbnN0IGxvZ2dlciA9IGNyZWF0ZUxvZ2dlcignc2VydmVyJyk7XG5cbmNvbnN0IHNsZWVwID0gKG1zOiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+ID0+IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIG1zKSk7XG5cbi8vIERlcGVuZGVuY3ktc3VwZXJ2aXNvciBjYWRlbmNlLiBJbml0aWFsIGNvbm5lY3QgcmV0cmllcyB3aXRoIGNhcHBlZCBiYWNrb2ZmO1xuLy8gb25jZSBjb25uZWN0ZWQsIHJlLWNoZWNrcyBhdCBhIHN0ZWFkeSBpbnRlcnZhbCBzbyBhIGxhdGVyIG91dGFnZSBmbGlwcyB0aGVcbi8vIHNlcnZpY2UgTm90UmVhZHkgKGRyYWluaW5nIHRyYWZmaWMpIGFuZCBhIHJlY292ZXJ5IGZsaXBzIGl0IGJhY2sg4oCUIHdpdGhvdXRcbi8vIGV2ZXIgZXhpdGluZyAvIHJlc3RhcnRpbmcgdGhlIHByb2Nlc3MuXG5jb25zdCBSRUFEWV9SRVRSWV9CQVNFX01TID0gMTAwMDtcbmNvbnN0IFJFQURZX1JFVFJZX01BWF9NUyA9IDEwMDAwO1xuY29uc3QgUkVBRFlfTU9OSVRPUl9JTlRFUlZBTF9NUyA9IHBhcnNlSW50KHByb2Nlc3MuZW52LlJFQURJTkVTU19NT05JVE9SX0lOVEVSVkFMX01TIHx8ICcxNTAwMCcsIDEwKTtcblxuLyoqXG4gKiBFc3RhYmxpc2ggYW5kIGNvbnRpbnVvdXNseSBtb25pdG9yIHRoZSBzZXJ2aWNlJ3MgZGF0YXN0b3JlIGRlcGVuZGVuY3ksXG4gKiBmbGlwcGluZyByZWFkaW5lc3Mgc3RhdGUgaW5zdGVhZCBvZiBjcmFzaC1sb29waW5nLlxuICpcbiAqIC0gRXN0YWJsaXNoIHBoYXNlOiByZXRyeSBgb25CZWZvcmVTdGFydGAgKGUuZy4gY29ubmVjdE1vbmdvKSB3aXRoIGNhcHBlZFxuICogICBiYWNrb2ZmIHVudGlsIGl0IHN1Y2NlZWRzIOKAlCBhIGNvbGQgZGF0YXN0b3JlIG11c3QgbmV2ZXIgZXhpdCB0aGUgcHJvY2Vzcy5cbiAqIC0gTW9uaXRvciBwaGFzZTogcG9sbCBgdGVzdERhdGFiYXNlYCBmb3IgdGhlIGxpZmUgb2YgdGhlIHByb2Nlc3M7IGZsaXBcbiAqICAgcmVhZHkvTm90UmVhZHkgb24gdHJhbnNpdGlvbnMuIFdoaWxlIE5vdFJlYWR5IHRoZSByZWFkaW5lc3MgZ3VhcmQgNTAzc1xuICogICBidXNpbmVzcyB0cmFmZmljIGFuZCBvcmNoZXN0cmF0b3IgcmVhZGluZXNzIHByb2JlcyBkcmFpbiB0aGUgaW5zdGFuY2UuXG4gKlxuICogUnVucyBpbiB0aGUgYmFja2dyb3VuZCAodGhlIEhUVFAgc2VydmVyIGlzIGFscmVhZHkgbGlzdGVuaW5nKS4gU3RvcHMgd2hlblxuICogYGFib3J0ZWQoKWAgcmV0dXJucyB0cnVlIChncmFjZWZ1bCBzaHV0ZG93biksIHNvIGl0IG5ldmVyIGtlZXBzIGEgY2xvc2luZ1xuICogcHJvY2VzcyBhbGl2ZS5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gc3VwZXJ2aXNlRGVwZW5kZW5jaWVzKFxuICBuYW1lOiBzdHJpbmcsXG4gIG9uQmVmb3JlU3RhcnQ6ICgoKSA9PiBQcm9taXNlPHZvaWQ+KSB8IHVuZGVmaW5lZCxcbiAgdGVzdERhdGFiYXNlOiAoKCkgPT4gUHJvbWlzZTxib29sZWFuPikgfCBmYWxzZSB8IHVuZGVmaW5lZCxcbiAgYWJvcnRlZDogKCkgPT4gYm9vbGVhbixcbik6IFByb21pc2U8dm9pZD4ge1xuICBpZiAob25CZWZvcmVTdGFydCkge1xuICAgIGxldCBkZWxheSA9IFJFQURZX1JFVFJZX0JBU0VfTVM7XG4gICAgd2hpbGUgKCFhYm9ydGVkKCkpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IG9uQmVmb3JlU3RhcnQoKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBsb2dnZXIud2FybihgJHtuYW1lfTogZGVwZW5kZW5jeSBpbml0IGZhaWxlZCwgcmV0cnlpbmcgaW4gJHtkZWxheX1tc2AsIHsgZXJyb3I6IGVycm9yTWVzc2FnZShlcnJvcikgfSk7XG4gICAgICAgIGF3YWl0IHNsZWVwKGRlbGF5KTtcbiAgICAgICAgZGVsYXkgPSBNYXRoLm1pbihkZWxheSAqIDIsIFJFQURZX1JFVFJZX01BWF9NUyk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gTm8gZGF0YXN0b3JlIHRvIGdhdGUgb24g4oaSIHJlYWR5IGFzIHNvb24gYXMgd2UgYXJlIGxpc3RlbmluZy5cbiAgaWYgKHRlc3REYXRhYmFzZSA9PT0gZmFsc2UpIHtcbiAgICBzZXRSZWFkeSh0cnVlKTtcbiAgICBsb2dnZXIuaW5mbyhgJHtuYW1lfSByZWFkeSAobm8gZGF0YXN0b3JlIGRlcGVuZGVuY3kpYCk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgY29uc3QgcHJvYmUgPSB0ZXN0RGF0YWJhc2UgPz8gKCgpID0+IGdldENvbm5lY3Rpb24oKS50ZXN0Q29ubmVjdGlvbigpKTtcbiAgbGV0IHdhaXREZWxheSA9IFJFQURZX1JFVFJZX0JBU0VfTVM7XG4gIHdoaWxlICghYWJvcnRlZCgpKSB7XG4gICAgbGV0IG9rID0gZmFsc2U7XG4gICAgdHJ5IHtcbiAgICAgIG9rID0gYXdhaXQgcHJvYmUoKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIG9rID0gZmFsc2U7XG4gICAgfVxuXG4gICAgaWYgKG9rICYmICFpc1JlYWR5KCkpIHtcbiAgICAgIHNldFJlYWR5KHRydWUpO1xuICAgICAgd2FpdERlbGF5ID0gUkVBRFlfUkVUUllfQkFTRV9NUztcbiAgICAgIGxvZ2dlci5pbmZvKGAke25hbWV9IHJlYWR5IOKAlCBkZXBlbmRlbmNpZXMgY29ubmVjdGVkYCk7XG4gICAgfSBlbHNlIGlmICghb2sgJiYgaXNSZWFkeSgpKSB7XG4gICAgICBzZXRSZWFkeShmYWxzZSk7XG4gICAgICBsb2dnZXIud2FybihgJHtuYW1lfSBkZWdyYWRlZCDigJQgZGVwZW5kZW5jeSBjaGVjayBmYWlsaW5nIChub3cgTm90UmVhZHkpYCk7XG4gICAgfVxuXG4gICAgLy8gU3RlYWR5IGNhZGVuY2Ugb25jZSByZWFkeTsgZmFzdGVyIGJhY2tvZmYgd2hpbGUgd2FpdGluZyBzbyB3ZSBmbGlwIHRvXG4gICAgLy8gcmVhZHkgcHJvbXB0bHkgd2hlbiB0aGUgZGF0YXN0b3JlIGNvbWVzIHVwLlxuICAgIGlmIChpc1JlYWR5KCkpIHtcbiAgICAgIGF3YWl0IHNsZWVwKFJFQURZX01PTklUT1JfSU5URVJWQUxfTVMpO1xuICAgIH0gZWxzZSB7XG4gICAgICBhd2FpdCBzbGVlcCh3YWl0RGVsYXkpO1xuICAgICAgd2FpdERlbGF5ID0gTWF0aC5taW4od2FpdERlbGF5ICogMiwgUkVBRFlfUkVUUllfTUFYX01TKTtcbiAgICB9XG4gIH1cbn1cblxuLyoqXG4gKiBPcHRpb25zIGZvciBzdGFydGluZyBhIHNlcnZlclxuICovXG5leHBvcnQgaW50ZXJmYWNlIFN0YXJ0U2VydmVyT3B0aW9ucyB7XG4gIC8qKiBTZXJ2aWNlIG5hbWUgZm9yIGxvZ2dpbmcgKi9cbiAgbmFtZT86IHN0cmluZztcbiAgLyoqIFBvcnQgdG8gbGlzdGVuIG9uIChkZWZhdWx0OiBmcm9tIGNvbmZpZykgKi9cbiAgcG9ydD86IG51bWJlcjtcbiAgLyoqIFNTRSBtYW5hZ2VyIGZvciBncmFjZWZ1bCBzaHV0ZG93biAqL1xuICBzc2VNYW5hZ2VyPzogU1NFTWFuYWdlcjtcbiAgLyoqIFNodXRkb3duIHRpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIChkZWZhdWx0OiAxNTAwMCkgKi9cbiAgc2h1dGRvd25UaW1lb3V0TXM/OiBudW1iZXI7XG4gIC8qKiBDYWxsYmFjayBhZnRlciBzZXJ2ZXIgc3RhcnRzICovXG4gIG9uU3RhcnQ/OiAocG9ydDogbnVtYmVyKSA9PiB2b2lkO1xuICAvKiogQ2FsbGJhY2sgYmVmb3JlIHNodXRkb3duICovXG4gIG9uU2h1dGRvd24/OiAoKSA9PiBQcm9taXNlPHZvaWQ+O1xuICAvKiogUnVucyBiZWZvcmUgZGF0YWJhc2UgY2hlY2sgKGUuZy4sIGluaXRpYWxpemUgZXh0ZXJuYWwgY29ubmVjdGlvbnMpICovXG4gIG9uQmVmb3JlU3RhcnQ/OiAoKSA9PiBQcm9taXNlPHZvaWQ+O1xuICAvKiogQ3VzdG9tIGRhdGFiYXNlIGhlYWx0aCBjaGVjaywgb3IgZmFsc2UgdG8gc2tpcC4gRGVmYXVsdDogUG9zdGdyZVNRTCB0ZXN0Q29ubmVjdGlvbiAqL1xuICB0ZXN0RGF0YWJhc2U/OiAoKCkgPT4gUHJvbWlzZTxib29sZWFuPikgfCBmYWxzZTtcbiAgLyoqIEN1c3RvbSBkYXRhYmFzZSBjbG9zZSwgb3IgZmFsc2UgdG8gc2tpcC4gRGVmYXVsdDogUG9zdGdyZVNRTCBjbG9zZUNvbm5lY3Rpb24gKi9cbiAgY2xvc2VEYXRhYmFzZT86ICgoKSA9PiBQcm9taXNlPHZvaWQ+KSB8IGZhbHNlO1xufVxuXG4vKipcbiAqIFJlc3VsdCBvZiBzdGFydGluZyBhIHNlcnZlclxuICovXG5leHBvcnQgaW50ZXJmYWNlIFN0YXJ0U2VydmVyUmVzdWx0IHtcbiAgLyoqIEhUVFAgc2VydmVyIGluc3RhbmNlICovXG4gIHNlcnZlcjogU2VydmVyO1xuICAvKiogUG9ydCB0aGUgc2VydmVyIGlzIGxpc3RlbmluZyBvbiAqL1xuICBwb3J0OiBudW1iZXI7XG4gIC8qKiBGdW5jdGlvbiB0byBtYW51YWxseSB0cmlnZ2VyIHNodXRkb3duICovXG4gIHNodXRkb3duOiAoKSA9PiBQcm9taXNlPHZvaWQ+O1xufVxuXG4vKipcbiAqIFN0YXJ0IGFuIEV4cHJlc3Mgc2VydmVyIHdpdGggZ3JhY2VmdWwgc2h1dGRvd24gaGFuZGxpbmdcbiAqXG4gKiBGZWF0dXJlczpcbiAqIC0gQXV0b21hdGljIGRhdGFiYXNlIGNvbm5lY3Rpb24gdGVzdGluZ1xuICogLSBHcmFjZWZ1bCBzaHV0ZG93biBvbiBTSUdJTlQvU0lHVEVSTVxuICogLSBTU0UgY29ubmVjdGlvbiBjbGVhbnVwXG4gKiAtIENvbmZpZ3VyYWJsZSBzaHV0ZG93biB0aW1lb3V0XG4gKlxuICogQHBhcmFtIGFwcCAtIEV4cHJlc3MgYXBwbGljYXRpb25cbiAqIEBwYXJhbSBvcHRpb25zIC0gU2VydmVyIG9wdGlvbnNcbiAqIEByZXR1cm5zIFNlcnZlciBpbnN0YW5jZSBhbmQgY29udHJvbCBmdW5jdGlvbnNcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogY29uc3QgeyBhcHAsIHNzZU1hbmFnZXIgfSA9IGNyZWF0ZUFwcCgpO1xuICpcbiAqIGFwcC5wb3N0KCcvYXBpL3Jlc291cmNlJywgcmVxdWlyZUF1dGgsIGhhbmRsZXIpO1xuICpcbiAqIGF3YWl0IHN0YXJ0U2VydmVyKGFwcCwge1xuICogICBuYW1lOiAnTXkgTWljcm9zZXJ2aWNlJyxcbiAqICAgc3NlTWFuYWdlcixcbiAqICAgb25TdGFydDogKHBvcnQpID0+IGNvbnNvbGUubG9nKGBMaXN0ZW5pbmcgb24gJHtwb3J0fWApLFxuICogfSk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHN0YXJ0U2VydmVyKFxuICBhcHA6IEV4cHJlc3MsXG4gIG9wdGlvbnM6IFN0YXJ0U2VydmVyT3B0aW9ucyA9IHt9LFxuKTogUHJvbWlzZTxTdGFydFNlcnZlclJlc3VsdD4ge1xuICBjb25zdCBzZXJ2ZXJDb25maWcgPSBDb25maWcuZ2V0KCdzZXJ2ZXInKTtcbiAgY29uc3Qge1xuICAgIG5hbWUgPSAnTWljcm9zZXJ2aWNlJyxcbiAgICBzc2VNYW5hZ2VyLFxuICAgIHNodXRkb3duVGltZW91dE1zID0gMTUwMDAsXG4gICAgb25TdGFydCxcbiAgICBvblNodXRkb3duLFxuICAgIG9uQmVmb3JlU3RhcnQsXG4gICAgdGVzdERhdGFiYXNlLFxuICAgIGNsb3NlRGF0YWJhc2UsXG4gIH0gPSBvcHRpb25zO1xuICBjb25zdCBwb3J0ID0gb3B0aW9ucy5wb3J0ID8/IHNlcnZlckNvbmZpZy5wb3J0O1xuXG4gIC8vIFZhbGlkYXRlIGF1dGggY29uZmlndXJhdGlvbiBhdCBzZXJ2ZXIgc3RhcnR1cCAobm90IGR1cmluZyBDREsgc3ludGhlc2lzKVxuICBDb25maWcudmFsaWRhdGVBdXRoKCk7XG4gIC8vIEZhaWwgZmFzdCBpZiB0aGlzIHNlcnZpY2UgaGFzIG5vIGludGVybmFsIHNpZ25pbmcga2V5IG9mIGl0cyBvd24sIG9yIG5vXG4gIC8vIHB1YmxpYyBidW5kbGUgdG8gdmVyaWZ5IGl0cyBwZWVycyB3aXRoICgjMTQpLiBXaXRob3V0IHRoZW0gaXQgd291bGQgbWludFxuICAvLyB0b2tlbnMgb24gYW4gRVBIRU1FUkFMIGluLXByb2Nlc3Mga2V5IHRoYXQgbm8gcGVlciBhY2NlcHRzLCBhbmQgcmVqZWN0IGV2ZXJ5XG4gIC8vIHBlZXIncyB0b2tlbiDigJQgaS5lLiBzaWxlbnRseSBsb3NlIGFsbCBzZXJ2aWNlLXRvLXNlcnZpY2UgdHJhZmZpYy4gQ2hlY2tlZFxuICAvLyBIRVJFIHJhdGhlciB0aGFuIGluIGBjcmVhdGVBcHBgIGJlY2F1c2UgaXQgaXMgYSBwcm9wZXJ0eSBvZiB0aGUgcnVubmluZ1xuICAvLyBkZXBsb3ltZW50LCBub3Qgb2YgdGhlIGFwcCBvYmplY3Q6IHJvdXRlLXRhYmxlIGJ1aWxkZXJzIGFuZCB0ZXN0IHN1aXRlc1xuICAvLyBhc3NlbWJsZSBhbiBhcHAgd2l0aG91dCBldmVyIHNpZ25pbmcgYW55dGhpbmcuXG4gIGZvciAoY29uc3QgZW52VmFyIG9mIFsnU0VSVklDRV9TSUdOSU5HX0tFWV9GSUxFJywgJ1NFUlZJQ0VfS0VZX0JVTkRMRV9GSUxFJ10gYXMgY29uc3QpIHtcbiAgICBpZiAoIXByb2Nlc3MuZW52W2VudlZhcl0pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgJHtlbnZWYXJ9IGVudmlyb25tZW50IHZhcmlhYmxlIGlzIHJlcXVpcmVkIChnZW5lcmF0ZSB3aXRoIGRlcGxveS9iaW4vc2VydmljZS1zaWduaW5nLWtleXMuc2gpLiBTZXQgaXQgYmVmb3JlIHN0YXJ0aW5nIHRoZSBzZXJ2ZXIuYCk7XG4gICAgfVxuICB9XG4gIC8vIEZhaWwgZmFzdCBvbiBhbiB1bnVzYWJsZSBSZWRpcyBjb25maWd1cmF0aW9uICh0aHJvd3MgUmVkaXNDb25maWdFcnJvcikg4oCUIGFcbiAgLy8gUmVkaXMgY2xpZW50IGlzIGNyZWF0ZWQgbGF6aWx5IG9uIGZpcnN0IHVzZSwgc28gd2l0aG91dCB0aGlzIGEgYmFkIGNvbmZpZ1xuICAvLyB3b3VsZCBzdXJmYWNlIGFzIHJlcXVlc3QtdGltZSBlcnJvcnMgaW5zdGVhZCBvZiBhIGZhaWxlZCBzdGFydC5cbiAgcmVzb2x2ZVJlZGlzQ29ubmVjdGlvbigpO1xuXG4gIGxvZ2dlci5pbmZvKGBTdGFydGluZyAke25hbWV9Li4uYCk7XG5cbiAgLy8gTWFyayBOb3RSZWFkeSBzeW5jaHJvbm91c2x5LCBCRUZPUkUgdGhlIHBvcnQgb3BlbnMsIHNvIG5vIHJlcXVlc3Qgc2xpcHNcbiAgLy8gdGhyb3VnaCB0aGUgcmVhZGluZXNzIGd1YXJkIGJlZm9yZSB0aGUgc3VwZXJ2aXNvciBoYXMgcnVuLiBUaGUgc3VwZXJ2aXNvclxuICAvLyBmbGlwcyBpdCB0cnVlIG9uY2UgZGVwZW5kZW5jaWVzIGNvbm5lY3QuXG4gIHNldFJlYWR5KGZhbHNlKTtcblxuICAvLyBMaXN0ZW4gRklSU1QuIFByZXZpb3VzbHkgdGhlIHByb2Nlc3MgdGVzdGVkIHRoZSBEQiBhbmQgYHByb2Nlc3MuZXhpdCgxKWAnZFxuICAvLyBvbiBmYWlsdXJlICh0byBiZSByZXN0YXJ0ZWQpLCBzbyBkdXJpbmcgYSBjb2xkLURCIHN0YW1wZWRlIHNlcnZpY2VzXG4gIC8vIGNyYXNoLWxvb3BlZCBhbmQgbmV2ZXIgZXZlbiBvcGVuZWQgdGhlaXIgcG9ydC4gTm93IHdlIG9wZW4gdGhlIHBvcnRcbiAgLy8gaW1tZWRpYXRlbHkg4oCUIC9oZWFsdGggKGxpdmVuZXNzKSwgL3JlYWR5IChyZWFkaW5lc3MpIGFuZCB0aGUgcmVhZGluZXNzXG4gIC8vIGd1YXJkIGFsbCByZXNwb25kIGF0IG9uY2Ug4oCUIGFuZCBlc3RhYmxpc2ggKyBtb25pdG9yIHRoZSBkYXRhc3RvcmUgaW4gdGhlXG4gIC8vIGJhY2tncm91bmQsIHJlcG9ydGluZyBOb3RSZWFkeSB1bnRpbCBpdCBjb25uZWN0cyBpbnN0ZWFkIG9mIGV4aXRpbmcuXG4gIGNvbnN0IHNlcnZlciA9IGFwcC5saXN0ZW4ocG9ydCwgKCkgPT4ge1xuICAgIGxvZ2dlci5pbmZvKGAke25hbWV9IGxpc3RlbmluZyBvbiBwb3J0OiAke3BvcnR9YCk7XG4gICAgbG9nZ2VyLmluZm8oYFBsYXRmb3JtIFVSTDogJHtzZXJ2ZXJDb25maWcucGxhdGZvcm1Vcmx9YCk7XG4gICAgb25TdGFydD8uKHBvcnQpO1xuICB9KTtcblxuICAvLyBTaHV0ZG93biBoYW5kbGVyIChndWFyZGVkIGFnYWluc3QgY29uY3VycmVudCBzaWduYWxzKVxuICBsZXQgc2h1dHRpbmdEb3duID0gZmFsc2U7XG5cbiAgLy8gQmFja2dyb3VuZCBkZXBlbmRlbmN5IHN1cGVydmlzb3Ig4oCUIGVzdGFibGlzaGVkICsgbW9uaXRvcmVkIGFmdGVyIGxpc3RlbixcbiAgLy8gc3RvcHBlZCBvbiBzaHV0ZG93biBzbyBpdCBuZXZlciBrZWVwcyBhIGNsb3NpbmcgcHJvY2VzcyBhbGl2ZS4gR3VhcmQgdGhlXG4gIC8vIGZsb2F0aW5nIHByb21pc2U6IGV2ZXJ5IGV4cGVjdGVkIGZhaWx1cmUgaXMgaGFuZGxlZCBpbnNpZGUsIHNvIGEgcmVqZWN0aW9uXG4gIC8vIGhlcmUgbWVhbnMgYSBwcm9ncmFtbWluZyBlcnJvciDigJQgbG9nIGl0IGFuZCBsZWF2ZSB0aGUgc2VydmljZSBOb3RSZWFkeVxuICAvLyByYXRoZXIgdGhhbiBsZXR0aW5nIGl0IGJlY29tZSBhbiB1bmhhbmRsZWRSZWplY3Rpb24gdGhhdCBjcmFzaC1leGl0cyB0aGVcbiAgLy8gcHJvY2VzcyAod2hpY2ggd291bGQgZGVmZWF0IHRoZSB3aG9sZSBcIm5ldmVyIGV4aXQgb24gZGVwZW5kZW5jeSB0cm91YmxlXCJcbiAgLy8gZ29hbCkuXG4gIHN1cGVydmlzZURlcGVuZGVuY2llcyhuYW1lLCBvbkJlZm9yZVN0YXJ0LCB0ZXN0RGF0YWJhc2UsICgpID0+IHNodXR0aW5nRG93bikuY2F0Y2goKGVycm9yKSA9PiB7XG4gICAgbG9nZ2VyLmVycm9yKCdEZXBlbmRlbmN5IHN1cGVydmlzb3IgY3Jhc2hlZDsgc2VydmljZSB3aWxsIHJlbWFpbiBOb3RSZWFkeScsIHsgZXJyb3I6IGVycm9yTWVzc2FnZShlcnJvcikgfSk7XG4gIH0pO1xuXG4gIGNvbnN0IHNodXRkb3duID0gYXN5bmMgKHNpZ25hbD86IHN0cmluZykgPT4ge1xuICAgIGlmIChzaHV0dGluZ0Rvd24pIHJldHVybjtcbiAgICBzaHV0dGluZ0Rvd24gPSB0cnVlO1xuXG4gICAgaWYgKHNpZ25hbCkge1xuICAgICAgbG9nZ2VyLmluZm8oYCR7c2lnbmFsfSByZWNlaXZlZCwgc2h1dHRpbmcgZG93biBncmFjZWZ1bGx5Li4uYCk7XG4gICAgfVxuXG4gICAgLy8gQ3VzdG9tIHNodXRkb3duIGNhbGxiYWNrXG4gICAgaWYgKG9uU2h1dGRvd24pIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IG9uU2h1dGRvd24oKTtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGxvZ2dlci5lcnJvcignRXJyb3IgaW4gb25TaHV0ZG93biBjYWxsYmFjaycsIHsgZXJyb3IgfSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gQ2xvc2UgU1NFIGNvbm5lY3Rpb25zXG4gICAgaWYgKHNzZU1hbmFnZXIpIHtcbiAgICAgIHNzZU1hbmFnZXIuc2h1dGRvd24oKTtcbiAgICAgIGxvZ2dlci5pbmZvKCdTU0UgY29ubmVjdGlvbnMgY2xvc2VkJyk7XG4gICAgfVxuXG4gICAgLy8gQ2xvc2UgSFRUUCBzZXJ2ZXJcbiAgICBzZXJ2ZXIuY2xvc2UoYXN5bmMgKCkgPT4ge1xuICAgICAgbG9nZ2VyLmluZm8oJ0hUVFAgc2VydmVyIGNsb3NlZCcpO1xuXG4gICAgICAvLyBTaHV0ZG93biBPcGVuVGVsZW1ldHJ5IHRyYWNpbmdcbiAgICAgIGF3YWl0IHNodXRkb3duVHJhY2luZygpLmNhdGNoKGVyciA9PiBsb2dnZXIuZXJyb3IoJ0Vycm9yIHNodXR0aW5nIGRvd24gdHJhY2luZycsIHsgZXJyb3I6IGVyciB9KSk7XG5cbiAgICAgIC8vIENsb3NlIGRhdGFiYXNlIGNvbm5lY3Rpb25cbiAgICAgIGlmIChjbG9zZURhdGFiYXNlICE9PSBmYWxzZSkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGlmIChjbG9zZURhdGFiYXNlKSB7XG4gICAgICAgICAgICBhd2FpdCBjbG9zZURhdGFiYXNlKCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGF3YWl0IGNsb3NlQ29ubmVjdGlvbigpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBsb2dnZXIuaW5mbygnRGF0YWJhc2UgY29ubmVjdGlvbiBjbG9zZWQnKTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICBsb2dnZXIuZXJyb3IoJ0Vycm9yIGNsb3NpbmcgZGF0YWJhc2UnLCB7IGVycm9yIH0pO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHByb2Nlc3MuZXhpdCgwKTtcbiAgICB9KTtcblxuICAgIC8vIEZvcmNlIHNodXRkb3duIGFmdGVyIHRpbWVvdXRcbiAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIGxvZ2dlci5lcnJvcignRm9yY2VkIHNodXRkb3duIGFmdGVyIHRpbWVvdXQnKTtcbiAgICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgICB9LCBzaHV0ZG93blRpbWVvdXRNcykudW5yZWYoKTtcbiAgfTtcblxuICAvLyBSZWdpc3RlciBzaWduYWwgaGFuZGxlcnNcbiAgcHJvY2Vzcy5vbmNlKCdTSUdJTlQnLCAoKSA9PiB2b2lkIHNodXRkb3duKCdTSUdJTlQnKSk7XG4gIHByb2Nlc3Mub25jZSgnU0lHVEVSTScsICgpID0+IHZvaWQgc2h1dGRvd24oJ1NJR1RFUk0nKSk7XG5cbiAgcmV0dXJuIHtcbiAgICBzZXJ2ZXIsXG4gICAgcG9ydCxcbiAgICBzaHV0ZG93bjogKCkgPT4gc2h1dGRvd24oKSxcbiAgfTtcbn1cblxuLyoqXG4gKiBTaW1wbGUgc2VydmVyIHN0YXJ0IHdyYXBwZXIgd2l0aCBlcnJvciBoYW5kbGluZ1xuICpcbiAqIEBwYXJhbSBhcHAgLSBFeHByZXNzIGFwcGxpY2F0aW9uXG4gKiBAcGFyYW0gb3B0aW9ucyAtIFNlcnZlciBvcHRpb25zXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IHsgYXBwLCBzc2VNYW5hZ2VyIH0gPSBjcmVhdGVBcHAoKTtcbiAqIGFwcC5wb3N0KCcvYXBpL3Jlc291cmNlJywgaGFuZGxlcik7XG4gKlxuICogdm9pZCBydW5TZXJ2ZXIoYXBwLCB7IG5hbWU6ICdNeSBTZXJ2aWNlJywgc3NlTWFuYWdlciB9KTtcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gcnVuU2VydmVyKGFwcDogRXhwcmVzcywgb3B0aW9uczogU3RhcnRTZXJ2ZXJPcHRpb25zID0ge30pOiB2b2lkIHtcbiAgLy8gUm91dGUgdGFibGUgb2YgdGhlIGZ1bGx5IGFzc2VtYmxlZCBhcHAgKHNlZSBhcGktY29yZSdzIHJvdXRlLXRhYmxlLnRzKTogdGhlXG4gIC8vIHNhbWUgaW50cm9zcGVjdGlvbiB0aGUgcGVyLXNlcnZpY2UgY292ZXJhZ2UgdGVzdCBhc3NlcnRzIG9uLCBsb2dnZWQgb25jZSBhdFxuICAvLyBib290IHNvIGFuIHVuZ2F0ZWQgb3IgdW5hdWRpdGVkIHdyaXRlIHJvdXRlIGlzIHZpc2libGUgaW4gdGhlIHJ1bm5pbmdcbiAgLy8gc2VydmljZSwgbm90IG9ubHkgaW4gQ0kuXG4gIGxvZ2dlci5pbmZvKCdSb3V0ZSB0YWJsZSBidWlsdCcsIHN1bW1hcml6ZVJvdXRlVGFibGUoYnVpbGRSb3V0ZVRhYmxlKGFwcCkpKTtcblxuICAvLyBMYXN0LXJlc29ydCBmYXVsdCBoYW5kbGVycyBmb3IgdGhlIHByb2R1Y3Rpb24gZW50cnlwb2ludDogYW4gdW5oYW5kbGVkXG4gIC8vIHJlamVjdGlvbiAvIHVuY2F1Z2h0IGV4Y2VwdGlvbiBpcyBsb2dnZWQgKG5vdCBzaWxlbnRseSBmYXRhbCkgdGhlbiB0aGVcbiAgLy8gcHJvY2VzcyBleGl0cyBmb3IgdGhlIG9yY2hlc3RyYXRvciB0byByZXN0YXJ0LiBOby1vcCB1bmRlciBOT0RFX0VOVj10ZXN0LlxuICBpbnN0YWxsQ3Jhc2hIYW5kbGVycyhsb2dnZXIpO1xuICBzdGFydFNlcnZlcihhcHAsIG9wdGlvbnMpLmNhdGNoKChlcnJvcikgPT4ge1xuICAgIC8vIHN0YXJ0U2VydmVyIG5vdyBsaXN0ZW5zLWZpcnN0IGFuZCBzdXBlcnZpc2VzIHRoZSBEQiBpbiB0aGUgYmFja2dyb3VuZCwgc29cbiAgICAvLyBpdCBvbmx5IHJlamVjdHMgb24gYSBnZW51aW5lbHkgZmF0YWwgU0VUVVAgZXJyb3IgKGludmFsaWQgYXV0aCBjb25maWcsIGFcbiAgICAvLyBmYWlsZWQgb25TdGFydCwgdGhlIHBvcnQgYWxyZWFkeSBpbiB1c2UpLiBMb2cgbWVzc2FnZSArIHN0YWNrIGV4cGxpY2l0bHk6XG4gICAgLy8gYW4gRXJyb3IgaW4gd2luc3RvbiBtZXRhZGF0YSBzZXJpYWxpemVzIHRvIGB7fWAgKG1lc3NhZ2Uvc3RhY2sgYXJlXG4gICAgLy8gbm9uLWVudW1lcmFibGUpLCB3aGljaCB3b3VsZCBvdGhlcndpc2UgaGlkZSB0aGUgY2F1c2UgYmVoaW5kIGB7ZXJyb3I6e319YC5cbiAgICBsb2dnZXIuZXJyb3IoJ0ZhaWxlZCB0byBzdGFydCBzZXJ2ZXInLCB7XG4gICAgICBlcnJvcjogZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpLFxuICAgICAgc3RhY2s6IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5zdGFjayA6IHVuZGVmaW5lZCxcbiAgICB9KTtcbiAgICBwcm9jZXNzLmV4aXQoMSk7XG4gIH0pO1xufVxuIl19
|
package/lib/http/index.d.ts
CHANGED
package/lib/http/index.js
CHANGED
|
@@ -2,6 +2,5 @@
|
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
export * from './sse-connection-manager.js';
|
|
4
4
|
export * from './sse-ticket-channel.js';
|
|
5
|
-
export * from './sse-ticket-store.js';
|
|
6
5
|
export * from './sse-relay.js';
|
|
7
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
6
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaHR0cC9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDLGNBQWMsNkJBQTZCLENBQUM7QUFDNUMsY0FBYyx5QkFBeUIsQ0FBQztBQUN4QyxjQUFjLGdCQUFnQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmV4cG9ydCAqIGZyb20gJy4vc3NlLWNvbm5lY3Rpb24tbWFuYWdlci5qcyc7XG5leHBvcnQgKiBmcm9tICcuL3NzZS10aWNrZXQtY2hhbm5lbC5qcyc7XG5leHBvcnQgKiBmcm9tICcuL3NzZS1yZWxheS5qcyc7XG4iXX0=
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { type SseTicketStore } from '@pipeline-builder/api-core';
|
|
1
2
|
import type { Response } from 'express';
|
|
2
3
|
import type { SSERelay } from './sse-relay.js';
|
|
3
|
-
import { type SSEStreamTicketStore } from './sse-ticket-store.js';
|
|
4
4
|
/**
|
|
5
5
|
* Event types for SSE logging
|
|
6
6
|
*/
|
|
@@ -55,42 +55,51 @@ export interface SSEManagerOptions {
|
|
|
55
55
|
*/
|
|
56
56
|
maxClientsPerOrg?: number;
|
|
57
57
|
/**
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
* once reached.
|
|
58
|
+
* Cap on live log-stream tickets across the process, for the DEFAULT
|
|
59
|
+
* in-memory ticket store. Defaults to 1000 from `SSE_MAX_TOTAL_TICKETS`.
|
|
60
|
+
* Ignored when `ticketStore` is injected (the store carries its own caps).
|
|
62
61
|
*/
|
|
63
62
|
maxTotalTickets?: number;
|
|
64
63
|
/**
|
|
65
|
-
* Per-org cap on live
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* once reached.
|
|
64
|
+
* Per-org cap on live log-stream tickets, for the DEFAULT in-memory ticket
|
|
65
|
+
* store. Defaults to 10 from `SSE_MAX_TICKETS_PER_ORG`. Ignored when
|
|
66
|
+
* `ticketStore` is injected.
|
|
69
67
|
*/
|
|
70
68
|
maxTicketsPerOrg?: number;
|
|
71
|
-
/** Ticket TTL in ms (default: `SSE_TICKET_TTL_MS` from api-core). */
|
|
69
|
+
/** Ticket TTL in ms for the default store (default: `SSE_TICKET_TTL_MS` from api-core). */
|
|
72
70
|
ticketTtlMs?: number;
|
|
73
71
|
/**
|
|
74
|
-
* Ticket + stream-ownership backend
|
|
75
|
-
* single
|
|
76
|
-
* `
|
|
77
|
-
*
|
|
78
|
-
* (a different service) can bind ownership that this service reads.
|
|
72
|
+
* Ticket + stream-ownership backend for the subject-bound log stream. Defaults
|
|
73
|
+
* to an in-memory store (single replica only), built on first use. Inject an
|
|
74
|
+
* api-core `createEnvSseTicketStore(...)` so mint/redeem and stream ownership
|
|
75
|
+
* work across pods.
|
|
79
76
|
*/
|
|
80
|
-
ticketStore?:
|
|
77
|
+
ticketStore?: SseTicketStore;
|
|
78
|
+
/**
|
|
79
|
+
* Whether this service streams per-request logs (`ctx.log` frames keyed by
|
|
80
|
+
* requestId, the `/logs` channel). Default false: `ctx.log` then only writes
|
|
81
|
+
* to the logger, so a service that never serves a log stream doesn't push
|
|
82
|
+
* every log line through SSE (and over Redis).
|
|
83
|
+
*/
|
|
84
|
+
logStream?: boolean;
|
|
81
85
|
/**
|
|
82
86
|
* TTL for a stream-ownership binding (default: `SSE_STREAM_OWNER_TTL_MS` env or
|
|
83
87
|
* 1h). Long enough to outlive a build; the producer re-binds as needed.
|
|
84
88
|
*/
|
|
85
89
|
streamOwnerTtlMs?: number;
|
|
86
90
|
/**
|
|
87
|
-
* Cross-pod fan-out bus for `send()`/`broadcast()
|
|
88
|
-
* delivery is LOCAL-ONLY
|
|
89
|
-
*
|
|
90
|
-
* EventSource attached on a DIFFERENT pod. Degrades to local-only automatically
|
|
91
|
-
* when Redis is unset (the factory returns null) or during a Redis outage.
|
|
91
|
+
* Cross-pod fan-out bus for `send()`/`broadcast()`, wired at construction.
|
|
92
|
+
* When omitted (and no `relayFactory` is enabled) delivery is LOCAL-ONLY.
|
|
93
|
+
* Degrades to local-only during a Redis outage.
|
|
92
94
|
*/
|
|
93
95
|
relay?: SSERelay;
|
|
96
|
+
/**
|
|
97
|
+
* Builds the relay on demand — see {@link SSEManager.enableRelay}. Lets a
|
|
98
|
+
* service open a relay connection only when it actually has a streaming
|
|
99
|
+
* channel (the log stream, or an org-keyed channel). Returning null (Redis
|
|
100
|
+
* not configured) keeps local-only delivery.
|
|
101
|
+
*/
|
|
102
|
+
relayFactory?: () => SSERelay | null;
|
|
94
103
|
}
|
|
95
104
|
/**
|
|
96
105
|
* A build-log stream subject id: either a dashed UUID (api-server's `uuid()`)
|
|
@@ -141,10 +150,10 @@ export declare class SSEManager {
|
|
|
141
150
|
* map mirrors `clients[].orgId` counts at all times. Orgs reach zero are
|
|
142
151
|
* deleted to keep the map bounded. */
|
|
143
152
|
private orgClientCounts;
|
|
144
|
-
/**
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
private
|
|
153
|
+
/** Injected ticket + stream-ownership backend, or the lazily built in-memory default. */
|
|
154
|
+
private ticketStoreInstance?;
|
|
155
|
+
/** True when this manager built its ticket store (so shutdown stops it). */
|
|
156
|
+
private ownsTicketStore;
|
|
148
157
|
private readonly maxClientsPerRequest;
|
|
149
158
|
private readonly maxTotalClients;
|
|
150
159
|
private readonly maxClientsPerOrg;
|
|
@@ -155,10 +164,22 @@ export declare class SSEManager {
|
|
|
155
164
|
private readonly clientTimeoutMs;
|
|
156
165
|
private cleanupInterval;
|
|
157
166
|
/** Cross-pod fan-out bus (undefined ⇒ local-only delivery). */
|
|
158
|
-
private
|
|
167
|
+
private relay?;
|
|
168
|
+
private readonly relayFactory?;
|
|
169
|
+
/** Whether `ctx.log` frames are streamed (see {@link SSEManagerOptions.logStream}). */
|
|
170
|
+
readonly logStreamEnabled: boolean;
|
|
159
171
|
/** This manager instance's id — tags relayed frames so we ignore our own echo. */
|
|
160
172
|
private readonly nodeId;
|
|
161
173
|
constructor(options?: SSEManagerOptions);
|
|
174
|
+
private attachRelay;
|
|
175
|
+
/**
|
|
176
|
+
* Turn on cross-pod delivery using the configured `relayFactory`. Idempotent;
|
|
177
|
+
* a no-op when a relay is already wired or no factory was given, and when the
|
|
178
|
+
* factory returns null (Redis not configured → local-only delivery).
|
|
179
|
+
*/
|
|
180
|
+
enableRelay(): void;
|
|
181
|
+
/** The ticket store, building the in-memory default on first use. */
|
|
182
|
+
private get ticketStore();
|
|
162
183
|
/**
|
|
163
184
|
* Handle a frame received from another pod via the relay. We already delivered
|
|
164
185
|
* our OWN frames to local clients before publishing, so ignore our echo. A
|
|
@@ -221,8 +242,8 @@ export declare class SSEManager {
|
|
|
221
242
|
* wiring not yet present), minting falls back to binding the ticket to the
|
|
222
243
|
* caller's own org, preserving current behavior.
|
|
223
244
|
*
|
|
224
|
-
* Bounded by
|
|
225
|
-
*
|
|
245
|
+
* Bounded by the ticket store's live-ticket caps (total and per org). An
|
|
246
|
+
* ownership lookup the store can't answer is refused as `capacity`.
|
|
226
247
|
*
|
|
227
248
|
* @param orgId - Owning org (normalized internally via normalizeOrgId).
|
|
228
249
|
* @param requestId - The build-log stream subject this ticket authorizes.
|
|
@@ -259,9 +280,18 @@ export declare class SSEManager {
|
|
|
259
280
|
* @param res - Express Response object
|
|
260
281
|
* @param orgId - Authenticated org id (optional). When set, enforces the
|
|
261
282
|
* per-org cap and the counter is decremented on disconnect/cleanup.
|
|
283
|
+
* @param maxClientsForSubject - Per-subject cap override (default
|
|
284
|
+
* `maxClientsPerRequest`). An org-keyed channel's subject IS the org, so it
|
|
285
|
+
* must not inherit the small per-build-request cap — see {@link addOrgClient}.
|
|
262
286
|
* @returns true if client was added, false if rejected (limit reached)
|
|
263
287
|
*/
|
|
264
|
-
addClient(requestId: string, res: Response, orgId?: string): boolean;
|
|
288
|
+
addClient(requestId: string, res: Response, orgId?: string, maxClientsForSubject?: number): boolean;
|
|
289
|
+
/**
|
|
290
|
+
* Attach a client to an ORG-keyed stream (the org is the subject). Counts
|
|
291
|
+
* against the per-org cap, and the org — not the per-request cap — bounds how
|
|
292
|
+
* many streams share the subject.
|
|
293
|
+
*/
|
|
294
|
+
addOrgClient(orgId: string, res: Response): boolean;
|
|
265
295
|
/** Drop one from the per-org counter. Idempotent: a counter at 0 stays at 0
|
|
266
296
|
* and the org key is removed from the map. */
|
|
267
297
|
private decrementOrgCount;
|