@pipeline-builder/api-core 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.
Files changed (77) hide show
  1. package/README.md +3 -3
  2. package/lib/errors/app-errors.d.ts +0 -4
  3. package/lib/errors/app-errors.js +1 -8
  4. package/lib/helpers/restore-helpers.d.ts +3 -3
  5. package/lib/helpers/restore-helpers.js +4 -4
  6. package/lib/helpers/sse-helpers.d.ts +8 -1
  7. package/lib/helpers/sse-helpers.js +11 -3
  8. package/lib/middleware/auth.d.ts +174 -43
  9. package/lib/middleware/auth.js +384 -179
  10. package/lib/middleware/index.d.ts +1 -0
  11. package/lib/middleware/index.js +2 -1
  12. package/lib/middleware/route-table.d.ts +104 -0
  13. package/lib/middleware/route-table.js +230 -0
  14. package/lib/middleware/step-up.d.ts +48 -16
  15. package/lib/middleware/step-up.js +74 -36
  16. package/lib/services/api-key-exchange.d.ts +25 -0
  17. package/lib/services/api-key-exchange.js +219 -0
  18. package/lib/services/cache-service.d.ts +11 -26
  19. package/lib/services/cache-service.js +20 -74
  20. package/lib/services/compliance-event-subscriber.d.ts +5 -4
  21. package/lib/services/compliance-event-subscriber.js +8 -6
  22. package/lib/services/durable-event-bus.d.ts +22 -39
  23. package/lib/services/durable-event-bus.js +95 -43
  24. package/lib/services/env-redis.d.ts +27 -0
  25. package/lib/services/env-redis.js +63 -1
  26. package/lib/services/http-client.d.ts +10 -15
  27. package/lib/services/http-client.js +32 -27
  28. package/lib/services/index.d.ts +3 -0
  29. package/lib/services/index.js +4 -1
  30. package/lib/services/jwks-cache.d.ts +102 -0
  31. package/lib/services/jwks-cache.js +222 -0
  32. package/lib/services/quota.js +12 -4
  33. package/lib/services/remote-audit-client.d.ts +1 -1
  34. package/lib/services/remote-audit-client.js +32 -1
  35. package/lib/services/scheduler.d.ts +2 -3
  36. package/lib/services/scheduler.js +2 -2
  37. package/lib/services/service-boot.d.ts +4 -2
  38. package/lib/services/service-boot.js +7 -3
  39. package/lib/services/service-keys.d.ts +83 -0
  40. package/lib/services/service-keys.js +354 -0
  41. package/lib/services/sse-ticket-store.d.ts +55 -22
  42. package/lib/services/sse-ticket-store.js +122 -79
  43. package/lib/services/token-revocation.js +30 -18
  44. package/lib/testing/route-coverage.d.ts +64 -0
  45. package/lib/testing/route-coverage.js +183 -0
  46. package/lib/testing/service-tokens.d.ts +66 -0
  47. package/lib/testing/service-tokens.js +137 -0
  48. package/lib/testing/tier-mock.d.ts +2 -2
  49. package/lib/testing/tier-mock.js +3 -3
  50. package/lib/testing/user-tokens.d.ts +75 -0
  51. package/lib/testing/user-tokens.js +115 -0
  52. package/lib/types/catalog-metadata.d.ts +0 -2
  53. package/lib/types/catalog-metadata.js +1 -3
  54. package/lib/types/common.d.ts +103 -4
  55. package/lib/types/common.js +11 -1
  56. package/lib/types/error-codes.d.ts +15 -0
  57. package/lib/types/error-codes.js +22 -1
  58. package/lib/types/permissions.d.ts +35 -1
  59. package/lib/types/permissions.js +72 -2
  60. package/lib/utils/api-key.d.ts +34 -0
  61. package/lib/utils/api-key.js +75 -0
  62. package/lib/utils/env.d.ts +0 -2
  63. package/lib/utils/env.js +1 -6
  64. package/lib/utils/index.d.ts +4 -0
  65. package/lib/utils/index.js +5 -1
  66. package/lib/utils/jwk.d.ts +98 -0
  67. package/lib/utils/jwk.js +139 -0
  68. package/lib/utils/logger.d.ts +30 -1
  69. package/lib/utils/logger.js +74 -27
  70. package/lib/utils/secret-encryption.d.ts +7 -2
  71. package/lib/utils/secret-encryption.js +47 -4
  72. package/lib/utils/secret-rotation.d.ts +17 -0
  73. package/lib/utils/secret-rotation.js +54 -0
  74. package/lib/utils/sensitive-patterns.d.ts +49 -0
  75. package/lib/utils/sensitive-patterns.js +149 -0
  76. package/lib/validation/common-schemas.js +5 -4
  77. package/package.json +20 -1
@@ -0,0 +1,139 @@
1
+ // Copyright 2026 Pipeline Builder Contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * JWK primitives for the ASYMMETRIC user-token chain.
5
+ *
6
+ * Every token that speaks for a PERSON (access, refresh, step-up, and the
7
+ * short-lived token an opaque access key is exchanged for) is signed by
8
+ * **platform alone**, with ES256 and a `kid`, and verified by everyone else
9
+ * against the public keys platform publishes at `/.well-known/jwks.json`. No
10
+ * service holds a key that can mint a user token any more.
11
+ *
12
+ * Only Node's `crypto` is used — `createPublicKey`/`export` already speak JWK,
13
+ * so nothing here needs a JOSE library.
14
+ *
15
+ * Internal SERVICE tokens (`principalType: 'service'`) are ES256 too, signed by
16
+ * the CALLING service with its own key (#14, `services/service-keys.ts`). Both
17
+ * chains therefore share these primitives, and a bearer token is routed by which
18
+ * key set owns its `kid` rather than by its algorithm — see `middleware/auth.ts`.
19
+ */
20
+ import crypto, {} from 'crypto';
21
+ /** The ONLY algorithm a user token may be signed with. */
22
+ export const USER_TOKEN_ALGORITHM = 'ES256';
23
+ /** The curve ES256 pins (`ECDSA_NIST_P256` / `prime256v1` / `ECC_NIST_P256` in KMS terms). */
24
+ export const USER_TOKEN_CURVE = 'P-256';
25
+ /** Path the public key set is served from (platform mounts it; nginx proxies it). */
26
+ export const JWKS_PATH = '/.well-known/jwks.json';
27
+ /**
28
+ * Decode a JWT's header WITHOUT verifying anything. Returns `null` for anything
29
+ * that is not a three-part token with a JSON object header — the caller then
30
+ * rejects, so this never widens what is accepted.
31
+ */
32
+ export function decodeJwtHeader(token) {
33
+ const parts = token.split('.');
34
+ if (parts.length !== 3 || !parts[0])
35
+ return null;
36
+ try {
37
+ const header = JSON.parse(Buffer.from(parts[0], 'base64url').toString('utf-8'));
38
+ if (!header || typeof header !== 'object' || Array.isArray(header))
39
+ return null;
40
+ return header;
41
+ }
42
+ catch {
43
+ return null;
44
+ }
45
+ }
46
+ /**
47
+ * The RFC 7638 thumbprint of an EC public key, base64url-encoded — used as the
48
+ * `kid` everywhere.
49
+ *
50
+ * Deriving the id FROM the key (rather than naming keys by hand, or by their KMS
51
+ * ARN) means the same key always publishes under the same `kid` whatever signer
52
+ * holds it, a rotated-in key can never collide with the one it replaces, and no
53
+ * AWS account id ever reaches a token or the public JWKS.
54
+ *
55
+ * The hashed form is the canonical JSON of exactly `crv`, `kty`, `x`, `y`, in
56
+ * lexicographic order and with no whitespace — the spec's required members for
57
+ * an EC key.
58
+ */
59
+ export function jwkThumbprint(jwk) {
60
+ const canonical = JSON.stringify({ crv: jwk.crv, kty: jwk.kty, x: jwk.x, y: jwk.y });
61
+ return crypto.createHash('sha256').update(canonical).digest('base64url');
62
+ }
63
+ /**
64
+ * Project an EC P-256 public key onto the published JWK shape, with its
65
+ * thumbprint as `kid`. Throws when the key is not a P-256 EC key — a signer
66
+ * configured with the wrong key type must fail at boot, not mint tokens nobody
67
+ * can verify.
68
+ */
69
+ export function publicJwkFrom(key) {
70
+ const exported = key.export({ format: 'jwk' });
71
+ if (exported.kty !== 'EC' || exported.crv !== USER_TOKEN_CURVE || !exported.x || !exported.y) {
72
+ throw new Error(`Token signing key must be an EC ${USER_TOKEN_CURVE} public key (got ${exported.kty ?? 'unknown'}/${exported.crv ?? 'unknown'})`);
73
+ }
74
+ const base = { kty: 'EC', crv: USER_TOKEN_CURVE, x: exported.x, y: exported.y };
75
+ return { ...base, kid: jwkThumbprint(base), use: 'sig', alg: 'ES256' };
76
+ }
77
+ /**
78
+ * Turn a published JWK back into a verification key. Throws for anything that is
79
+ * not an ES256-usable P-256 key, so a JWKS document with a surprise entry
80
+ * (a future RSA key, a `use: 'enc'` key) can never be pressed into verifying a
81
+ * user token.
82
+ */
83
+ export function publicKeyFromJwk(jwk) {
84
+ if (jwk.kty !== 'EC' || jwk.crv !== USER_TOKEN_CURVE) {
85
+ throw new Error(`Unsupported JWKS entry: ${jwk.kty}/${jwk.crv}`);
86
+ }
87
+ if (jwk.use !== undefined && jwk.use !== 'sig')
88
+ throw new Error('JWKS entry is not a signing key');
89
+ if (jwk.alg !== undefined && jwk.alg !== USER_TOKEN_ALGORITHM)
90
+ throw new Error(`JWKS entry algorithm is not ${USER_TOKEN_ALGORITHM}`);
91
+ return crypto.createPublicKey({ key: { kty: 'EC', crv: jwk.crv, x: jwk.x, y: jwk.y }, format: 'jwk' });
92
+ }
93
+ /** True when `value` is shaped like the JWKS document (keys array of objects). */
94
+ export function isJwksDocument(value) {
95
+ return !!value
96
+ && typeof value === 'object'
97
+ && Array.isArray(value.keys)
98
+ && value.keys.every((k) => !!k && typeof k === 'object');
99
+ }
100
+ /**
101
+ * Convert an ECDSA signature from ASN.1 DER (what AWS KMS returns) to the raw
102
+ * fixed-width `r || s` JOSE form a JWT carries.
103
+ *
104
+ * DER is `SEQUENCE { INTEGER r, INTEGER s }` with both integers minimally
105
+ * encoded and sign-padded; JOSE wants each coordinate left-zero-padded to
106
+ * exactly the curve size (32 bytes for P-256). Getting this wrong produces
107
+ * tokens that verify nowhere, so it is strict: any structural surprise throws.
108
+ */
109
+ export function derToJoseSignature(der, coordinateBytes = 32) {
110
+ if (der[0] !== 0x30)
111
+ throw new Error('Malformed DER signature: expected SEQUENCE');
112
+ // Length byte(s): short form (<0x80) or long form (0x81 for a 1-byte length).
113
+ let offset = 1;
114
+ if (der[offset] === 0x81)
115
+ offset += 2;
116
+ else if (der[offset] < 0x80)
117
+ offset += 1;
118
+ else
119
+ throw new Error('Malformed DER signature: unsupported length encoding');
120
+ const readInt = () => {
121
+ if (der[offset] !== 0x02)
122
+ throw new Error('Malformed DER signature: expected INTEGER');
123
+ const len = der[offset + 1];
124
+ const start = offset + 2;
125
+ offset = start + len;
126
+ let value = der.subarray(start, offset);
127
+ // Strip the sign-padding byte DER adds when the high bit is set…
128
+ while (value.length > coordinateBytes && value[0] === 0x00)
129
+ value = value.subarray(1);
130
+ if (value.length > coordinateBytes)
131
+ throw new Error('Malformed DER signature: coordinate too large');
132
+ // …then left-pad back out to the fixed curve width JOSE requires.
133
+ return Buffer.concat([Buffer.alloc(coordinateBytes - value.length), value]);
134
+ };
135
+ const r = readInt();
136
+ const s = readInt();
137
+ return Buffer.concat([r, s]);
138
+ }
139
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiandrLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3V0aWxzL2p3ay50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDOzs7Ozs7Ozs7Ozs7Ozs7O0dBZ0JHO0FBRUgsT0FBTyxNQUFNLEVBQUUsRUFBa0IsTUFBTSxRQUFRLENBQUM7QUFFaEQsMERBQTBEO0FBQzFELE1BQU0sQ0FBQyxNQUFNLG9CQUFvQixHQUFHLE9BQU8sQ0FBQztBQUU1Qyw4RkFBOEY7QUFDOUYsTUFBTSxDQUFDLE1BQU0sZ0JBQWdCLEdBQUcsT0FBTyxDQUFDO0FBRXhDLHFGQUFxRjtBQUNyRixNQUFNLENBQUMsTUFBTSxTQUFTLEdBQUcsd0JBQXdCLENBQUM7QUE0QmxEOzs7O0dBSUc7QUFDSCxNQUFNLFVBQVUsZUFBZSxDQUFDLEtBQWE7SUFDM0MsTUFBTSxLQUFLLEdBQUcsS0FBSyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUMvQixJQUFJLEtBQUssQ0FBQyxNQUFNLEtBQUssQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztRQUFFLE9BQU8sSUFBSSxDQUFDO0lBQ2pELElBQUksQ0FBQztRQUNILE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsV0FBVyxDQUFDLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFZLENBQUM7UUFDM0YsSUFBSSxDQUFDLE1BQU0sSUFBSSxPQUFPLE1BQU0sS0FBSyxRQUFRLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUM7WUFBRSxPQUFPLElBQUksQ0FBQztRQUNoRixPQUFPLE1BQW1CLENBQUM7SUFDN0IsQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNQLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztBQUNILENBQUM7QUFFRDs7Ozs7Ozs7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LEtBQUssQ0FBQyxNQUFNLEdBQUcsZUFBZTtZQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsK0NBQStDLENBQUMsQ0FBQztRQUNyRyxrRUFBa0U7UUFDbEUsT0FBTyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxlQUFlLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQyxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUM7SUFDOUUsQ0FBQyxDQUFDO0lBRUYsTUFBTSxDQUFDLEdBQUcsT0FBTyxFQUFFLENBQUM7SUFDcEIsTUFBTSxDQUFDLEdBQUcsT0FBTyxFQUFFLENBQUM7SUFDcEIsT0FBTyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDL0IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG4vKipcbiAqIEpXSyBwcmltaXRpdmVzIGZvciB0aGUgQVNZTU1FVFJJQyB1c2VyLXRva2VuIGNoYWluLlxuICpcbiAqIEV2ZXJ5IHRva2VuIHRoYXQgc3BlYWtzIGZvciBhIFBFUlNPTiAoYWNjZXNzLCByZWZyZXNoLCBzdGVwLXVwLCBhbmQgdGhlXG4gKiBzaG9ydC1saXZlZCB0b2tlbiBhbiBvcGFxdWUgYWNjZXNzIGtleSBpcyBleGNoYW5nZWQgZm9yKSBpcyBzaWduZWQgYnlcbiAqICoqcGxhdGZvcm0gYWxvbmUqKiwgd2l0aCBFUzI1NiBhbmQgYSBga2lkYCwgYW5kIHZlcmlmaWVkIGJ5IGV2ZXJ5b25lIGVsc2VcbiAqIGFnYWluc3QgdGhlIHB1YmxpYyBrZXlzIHBsYXRmb3JtIHB1Ymxpc2hlcyBhdCBgLy53ZWxsLWtub3duL2p3a3MuanNvbmAuIE5vXG4gKiBzZXJ2aWNlIGhvbGRzIGEga2V5IHRoYXQgY2FuIG1pbnQgYSB1c2VyIHRva2VuIGFueSBtb3JlLlxuICpcbiAqIE9ubHkgTm9kZSdzIGBjcnlwdG9gIGlzIHVzZWQg4oCUIGBjcmVhdGVQdWJsaWNLZXlgL2BleHBvcnRgIGFscmVhZHkgc3BlYWsgSldLLFxuICogc28gbm90aGluZyBoZXJlIG5lZWRzIGEgSk9TRSBsaWJyYXJ5LlxuICpcbiAqIEludGVybmFsIFNFUlZJQ0UgdG9rZW5zIChgcHJpbmNpcGFsVHlwZTogJ3NlcnZpY2UnYCkgYXJlIEVTMjU2IHRvbywgc2lnbmVkIGJ5XG4gKiB0aGUgQ0FMTElORyBzZXJ2aWNlIHdpdGggaXRzIG93biBrZXkgKCMxNCwgYHNlcnZpY2VzL3NlcnZpY2Uta2V5cy50c2ApLiBCb3RoXG4gKiBjaGFpbnMgdGhlcmVmb3JlIHNoYXJlIHRoZXNlIHByaW1pdGl2ZXMsIGFuZCBhIGJlYXJlciB0b2tlbiBpcyByb3V0ZWQgYnkgd2hpY2hcbiAqIGtleSBzZXQgb3ducyBpdHMgYGtpZGAgcmF0aGVyIHRoYW4gYnkgaXRzIGFsZ29yaXRobSDigJQgc2VlIGBtaWRkbGV3YXJlL2F1dGgudHNgLlxuICovXG5cbmltcG9ydCBjcnlwdG8sIHsgdHlwZSBLZXlPYmplY3QgfSBmcm9tICdjcnlwdG8nO1xuXG4vKiogVGhlIE9OTFkgYWxnb3JpdGhtIGEgdXNlciB0b2tlbiBtYXkgYmUgc2lnbmVkIHdpdGguICovXG5leHBvcnQgY29uc3QgVVNFUl9UT0tFTl9BTEdPUklUSE0gPSAnRVMyNTYnO1xuXG4vKiogVGhlIGN1cnZlIEVTMjU2IHBpbnMgKGBFQ0RTQV9OSVNUX1AyNTZgIC8gYHByaW1lMjU2djFgIC8gYEVDQ19OSVNUX1AyNTZgIGluIEtNUyB0ZXJtcykuICovXG5leHBvcnQgY29uc3QgVVNFUl9UT0tFTl9DVVJWRSA9ICdQLTI1Nic7XG5cbi8qKiBQYXRoIHRoZSBwdWJsaWMga2V5IHNldCBpcyBzZXJ2ZWQgZnJvbSAocGxhdGZvcm0gbW91bnRzIGl0OyBuZ2lueCBwcm94aWVzIGl0KS4gKi9cbmV4cG9ydCBjb25zdCBKV0tTX1BBVEggPSAnLy53ZWxsLWtub3duL2p3a3MuanNvbic7XG5cbi8qKiBPbmUgcHVibGlzaGVkIEVDIHB1YmxpYyBrZXkuICovXG5leHBvcnQgaW50ZXJmYWNlIFB1YmxpY0p3ayB7XG4gIGt0eTogJ0VDJztcbiAgY3J2OiAnUC0yNTYnO1xuICAvKiogYmFzZTY0dXJsIFggY29vcmRpbmF0ZS4gKi9cbiAgeDogc3RyaW5nO1xuICAvKiogYmFzZTY0dXJsIFkgY29vcmRpbmF0ZS4gKi9cbiAgeTogc3RyaW5nO1xuICAvKiogUkZDIDc2MzggdGh1bWJwcmludCDigJQgc3RhYmxlIGZvciB0aGUga2V5LCBzbyByb3RhdGlvbiBpcyBhIGBraWRgIGNoYW5nZS4gKi9cbiAga2lkOiBzdHJpbmc7XG4gIHVzZTogJ3NpZyc7XG4gIGFsZzogJ0VTMjU2Jztcbn1cblxuLyoqIFRoZSBkb2N1bWVudCBzZXJ2ZWQgYXQge0BsaW5rIEpXS1NfUEFUSH0uICovXG5leHBvcnQgaW50ZXJmYWNlIEp3a3NEb2N1bWVudCB7XG4gIGtleXM6IFB1YmxpY0p3a1tdO1xufVxuXG4vKiogVGhlIGhlYWRlciBmaWVsZHMgYSB2ZXJpZmllciBuZWVkcyBiZWZvcmUgaXQgY2FuIHBpY2sgYSBrZXkuICovXG5leHBvcnQgaW50ZXJmYWNlIEp3dEhlYWRlciB7XG4gIGFsZz86IHN0cmluZztcbiAga2lkPzogc3RyaW5nO1xuICB0eXA/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogRGVjb2RlIGEgSldUJ3MgaGVhZGVyIFdJVEhPVVQgdmVyaWZ5aW5nIGFueXRoaW5nLiBSZXR1cm5zIGBudWxsYCBmb3IgYW55dGhpbmdcbiAqIHRoYXQgaXMgbm90IGEgdGhyZWUtcGFydCB0b2tlbiB3aXRoIGEgSlNPTiBvYmplY3QgaGVhZGVyIOKAlCB0aGUgY2FsbGVyIHRoZW5cbiAqIHJlamVjdHMsIHNvIHRoaXMgbmV2ZXIgd2lkZW5zIHdoYXQgaXMgYWNjZXB0ZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBkZWNvZGVKd3RIZWFkZXIodG9rZW46IHN0cmluZyk6IEp3dEhlYWRlciB8IG51bGwge1xuICBjb25zdCBwYXJ0cyA9IHRva2VuLnNwbGl0KCcuJyk7XG4gIGlmIChwYXJ0cy5sZW5ndGggIT09IDMgfHwgIXBhcnRzWzBdKSByZXR1cm4gbnVsbDtcbiAgdHJ5IHtcbiAgICBjb25zdCBoZWFkZXIgPSBKU09OLnBhcnNlKEJ1ZmZlci5mcm9tKHBhcnRzWzBdLCAnYmFzZTY0dXJsJykudG9TdHJpbmcoJ3V0Zi04JykpIGFzIHVua25vd247XG4gICAgaWYgKCFoZWFkZXIgfHwgdHlwZW9mIGhlYWRlciAhPT0gJ29iamVjdCcgfHwgQXJyYXkuaXNBcnJheShoZWFkZXIpKSByZXR1cm4gbnVsbDtcbiAgICByZXR1cm4gaGVhZGVyIGFzIEp3dEhlYWRlcjtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cbn1cblxuLyoqXG4gKiBUaGUgUkZDIDc2MzggdGh1bWJwcmludCBvZiBhbiBFQyBwdWJsaWMga2V5LCBiYXNlNjR1cmwtZW5jb2RlZCDigJQgdXNlZCBhcyB0aGVcbiAqIGBraWRgIGV2ZXJ5d2hlcmUuXG4gKlxuICogRGVyaXZpbmcgdGhlIGlkIEZST00gdGhlIGtleSAocmF0aGVyIHRoYW4gbmFtaW5nIGtleXMgYnkgaGFuZCwgb3IgYnkgdGhlaXIgS01TXG4gKiBBUk4pIG1lYW5zIHRoZSBzYW1lIGtleSBhbHdheXMgcHVibGlzaGVzIHVuZGVyIHRoZSBzYW1lIGBraWRgIHdoYXRldmVyIHNpZ25lclxuICogaG9sZHMgaXQsIGEgcm90YXRlZC1pbiBrZXkgY2FuIG5ldmVyIGNvbGxpZGUgd2l0aCB0aGUgb25lIGl0IHJlcGxhY2VzLCBhbmQgbm9cbiAqIEFXUyBhY2NvdW50IGlkIGV2ZXIgcmVhY2hlcyBhIHRva2VuIG9yIHRoZSBwdWJsaWMgSldLUy5cbiAqXG4gKiBUaGUgaGFzaGVkIGZvcm0gaXMgdGhlIGNhbm9uaWNhbCBKU09OIG9mIGV4YWN0bHkgYGNydmAsIGBrdHlgLCBgeGAsIGB5YCwgaW5cbiAqIGxleGljb2dyYXBoaWMgb3JkZXIgYW5kIHdpdGggbm8gd2hpdGVzcGFjZSDigJQgdGhlIHNwZWMncyByZXF1aXJlZCBtZW1iZXJzIGZvclxuICogYW4gRUMga2V5LlxuICovXG5leHBvcnQgZnVuY3Rpb24gandrVGh1bWJwcmludChqd2s6IHsgY3J2OiBzdHJpbmc7IGt0eTogc3RyaW5nOyB4OiBzdHJpbmc7IHk6IHN0cmluZyB9KTogc3RyaW5nIHtcbiAgY29uc3QgY2Fub25pY2FsID0gSlNPTi5zdHJpbmdpZnkoeyBjcnY6IGp3ay5jcnYsIGt0eTogandrLmt0eSwgeDogandrLngsIHk6IGp3ay55IH0pO1xuICByZXR1cm4gY3J5cHRvLmNyZWF0ZUhhc2goJ3NoYTI1NicpLnVwZGF0ZShjYW5vbmljYWwpLmRpZ2VzdCgnYmFzZTY0dXJsJyk7XG59XG5cbi8qKlxuICogUHJvamVjdCBhbiBFQyBQLTI1NiBwdWJsaWMga2V5IG9udG8gdGhlIHB1Ymxpc2hlZCBKV0sgc2hhcGUsIHdpdGggaXRzXG4gKiB0aHVtYnByaW50IGFzIGBraWRgLiBUaHJvd3Mgd2hlbiB0aGUga2V5IGlzIG5vdCBhIFAtMjU2IEVDIGtleSDigJQgYSBzaWduZXJcbiAqIGNvbmZpZ3VyZWQgd2l0aCB0aGUgd3Jvbmcga2V5IHR5cGUgbXVzdCBmYWlsIGF0IGJvb3QsIG5vdCBtaW50IHRva2VucyBub2JvZHlcbiAqIGNhbiB2ZXJpZnkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwdWJsaWNKd2tGcm9tKGtleTogS2V5T2JqZWN0KTogUHVibGljSndrIHtcbiAgY29uc3QgZXhwb3J0ZWQgPSBrZXkuZXhwb3J0KHsgZm9ybWF0OiAnandrJyB9KSBhcyB7IGt0eT86IHN0cmluZzsgY3J2Pzogc3RyaW5nOyB4Pzogc3RyaW5nOyB5Pzogc3RyaW5nIH07XG4gIGlmIChleHBvcnRlZC5rdHkgIT09ICdFQycgfHwgZXhwb3J0ZWQuY3J2ICE9PSBVU0VSX1RPS0VOX0NVUlZFIHx8ICFleHBvcnRlZC54IHx8ICFleHBvcnRlZC55KSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBUb2tlbiBzaWduaW5nIGtleSBtdXN0IGJlIGFuIEVDICR7VVNFUl9UT0tFTl9DVVJWRX0gcHVibGljIGtleSAoZ290ICR7ZXhwb3J0ZWQua3R5ID8/ICd1bmtub3duJ30vJHtleHBvcnRlZC5jcnYgPz8gJ3Vua25vd24nfSlgKTtcbiAgfVxuICBjb25zdCBiYXNlID0geyBrdHk6ICdFQycgYXMgY29uc3QsIGNydjogVVNFUl9UT0tFTl9DVVJWRSBhcyAnUC0yNTYnLCB4OiBleHBvcnRlZC54LCB5OiBleHBvcnRlZC55IH07XG4gIHJldHVybiB7IC4uLmJhc2UsIGtpZDogandrVGh1bWJwcmludChiYXNlKSwgdXNlOiAnc2lnJywgYWxnOiAnRVMyNTYnIH07XG59XG5cbi8qKlxuICogVHVybiBhIHB1Ymxpc2hlZCBKV0sgYmFjayBpbnRvIGEgdmVyaWZpY2F0aW9uIGtleS4gVGhyb3dzIGZvciBhbnl0aGluZyB0aGF0IGlzXG4gKiBub3QgYW4gRVMyNTYtdXNhYmxlIFAtMjU2IGtleSwgc28gYSBKV0tTIGRvY3VtZW50IHdpdGggYSBzdXJwcmlzZSBlbnRyeVxuICogKGEgZnV0dXJlIFJTQSBrZXksIGEgYHVzZTogJ2VuYydgIGtleSkgY2FuIG5ldmVyIGJlIHByZXNzZWQgaW50byB2ZXJpZnlpbmcgYVxuICogdXNlciB0b2tlbi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHB1YmxpY0tleUZyb21Kd2soandrOiBQdWJsaWNKd2spOiBLZXlPYmplY3Qge1xuICBpZiAoandrLmt0eSAhPT0gJ0VDJyB8fCBqd2suY3J2ICE9PSBVU0VSX1RPS0VOX0NVUlZFKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBVbnN1cHBvcnRlZCBKV0tTIGVudHJ5OiAke2p3ay5rdHl9LyR7andrLmNydn1gKTtcbiAgfVxuICBpZiAoandrLnVzZSAhPT0gdW5kZWZpbmVkICYmIGp3ay51c2UgIT09ICdzaWcnKSB0aHJvdyBuZXcgRXJyb3IoJ0pXS1MgZW50cnkgaXMgbm90IGEgc2lnbmluZyBrZXknKTtcbiAgaWYgKGp3ay5hbGcgIT09IHVuZGVmaW5lZCAmJiBqd2suYWxnICE9PSBVU0VSX1RPS0VOX0FMR09SSVRITSkgdGhyb3cgbmV3IEVycm9yKGBKV0tTIGVudHJ5IGFsZ29yaXRobSBpcyBub3QgJHtVU0VSX1RPS0VOX0FMR09SSVRITX1gKTtcbiAgcmV0dXJuIGNyeXB0by5jcmVhdGVQdWJsaWNLZXkoeyBrZXk6IHsga3R5OiAnRUMnLCBjcnY6IGp3ay5jcnYsIHg6IGp3ay54LCB5OiBqd2sueSB9LCBmb3JtYXQ6ICdqd2snIH0pO1xufVxuXG4vKiogVHJ1ZSB3aGVuIGB2YWx1ZWAgaXMgc2hhcGVkIGxpa2UgdGhlIEpXS1MgZG9jdW1lbnQgKGtleXMgYXJyYXkgb2Ygb2JqZWN0cykuICovXG5leHBvcnQgZnVuY3Rpb24gaXNKd2tzRG9jdW1lbnQodmFsdWU6IHVua25vd24pOiB2YWx1ZSBpcyBKd2tzRG9jdW1lbnQge1xuICByZXR1cm4gISF2YWx1ZVxuICAgICYmIHR5cGVvZiB2YWx1ZSA9PT0gJ29iamVjdCdcbiAgICAmJiBBcnJheS5pc0FycmF5KCh2YWx1ZSBhcyB7IGtleXM/OiB1bmtub3duIH0pLmtleXMpXG4gICAgJiYgKHZhbHVlIGFzIHsga2V5czogdW5rbm93bltdIH0pLmtleXMuZXZlcnkoKGspID0+ICEhayAmJiB0eXBlb2YgayA9PT0gJ29iamVjdCcpO1xufVxuXG4vKipcbiAqIENvbnZlcnQgYW4gRUNEU0Egc2lnbmF0dXJlIGZyb20gQVNOLjEgREVSICh3aGF0IEFXUyBLTVMgcmV0dXJucykgdG8gdGhlIHJhd1xuICogZml4ZWQtd2lkdGggYHIgfHwgc2AgSk9TRSBmb3JtIGEgSldUIGNhcnJpZXMuXG4gKlxuICogREVSIGlzIGBTRVFVRU5DRSB7IElOVEVHRVIgciwgSU5URUdFUiBzIH1gIHdpdGggYm90aCBpbnRlZ2VycyBtaW5pbWFsbHlcbiAqIGVuY29kZWQgYW5kIHNpZ24tcGFkZGVkOyBKT1NFIHdhbnRzIGVhY2ggY29vcmRpbmF0ZSBsZWZ0LXplcm8tcGFkZGVkIHRvXG4gKiBleGFjdGx5IHRoZSBjdXJ2ZSBzaXplICgzMiBieXRlcyBmb3IgUC0yNTYpLiBHZXR0aW5nIHRoaXMgd3JvbmcgcHJvZHVjZXNcbiAqIHRva2VucyB0aGF0IHZlcmlmeSBub3doZXJlLCBzbyBpdCBpcyBzdHJpY3Q6IGFueSBzdHJ1Y3R1cmFsIHN1cnByaXNlIHRocm93cy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRlclRvSm9zZVNpZ25hdHVyZShkZXI6IEJ1ZmZlciwgY29vcmRpbmF0ZUJ5dGVzID0gMzIpOiBCdWZmZXIge1xuICBpZiAoZGVyWzBdICE9PSAweDMwKSB0aHJvdyBuZXcgRXJyb3IoJ01hbGZvcm1lZCBERVIgc2lnbmF0dXJlOiBleHBlY3RlZCBTRVFVRU5DRScpO1xuICAvLyBMZW5ndGggYnl0ZShzKTogc2hvcnQgZm9ybSAoPDB4ODApIG9yIGxvbmcgZm9ybSAoMHg4MSBmb3IgYSAxLWJ5dGUgbGVuZ3RoKS5cbiAgbGV0IG9mZnNldCA9IDE7XG4gIGlmIChkZXJbb2Zmc2V0XSA9PT0gMHg4MSkgb2Zmc2V0ICs9IDI7XG4gIGVsc2UgaWYgKGRlcltvZmZzZXRdIDwgMHg4MCkgb2Zmc2V0ICs9IDE7XG4gIGVsc2UgdGhyb3cgbmV3IEVycm9yKCdNYWxmb3JtZWQgREVSIHNpZ25hdHVyZTogdW5zdXBwb3J0ZWQgbGVuZ3RoIGVuY29kaW5nJyk7XG5cbiAgY29uc3QgcmVhZEludCA9ICgpOiBCdWZmZXIgPT4ge1xuICAgIGlmIChkZXJbb2Zmc2V0XSAhPT0gMHgwMikgdGhyb3cgbmV3IEVycm9yKCdNYWxmb3JtZWQgREVSIHNpZ25hdHVyZTogZXhwZWN0ZWQgSU5URUdFUicpO1xuICAgIGNvbnN0IGxlbiA9IGRlcltvZmZzZXQgKyAxXTtcbiAgICBjb25zdCBzdGFydCA9IG9mZnNldCArIDI7XG4gICAgb2Zmc2V0ID0gc3RhcnQgKyBsZW47XG4gICAgbGV0IHZhbHVlID0gZGVyLnN1YmFycmF5KHN0YXJ0LCBvZmZzZXQpO1xuICAgIC8vIFN0cmlwIHRoZSBzaWduLXBhZGRpbmcgYnl0ZSBERVIgYWRkcyB3aGVuIHRoZSBoaWdoIGJpdCBpcyBzZXTigKZcbiAgICB3aGlsZSAodmFsdWUubGVuZ3RoID4gY29vcmRpbmF0ZUJ5dGVzICYmIHZhbHVlWzBdID09PSAweDAwKSB2YWx1ZSA9IHZhbHVlLnN1YmFycmF5KDEpO1xuICAgIGlmICh2YWx1ZS5sZW5ndGggPiBjb29yZGluYXRlQnl0ZXMpIHRocm93IG5ldyBFcnJvcignTWFsZm9ybWVkIERFUiBzaWduYXR1cmU6IGNvb3JkaW5hdGUgdG9vIGxhcmdlJyk7XG4gICAgLy8g4oCmdGhlbiBsZWZ0LXBhZCBiYWNrIG91dCB0byB0aGUgZml4ZWQgY3VydmUgd2lkdGggSk9TRSByZXF1aXJlcy5cbiAgICByZXR1cm4gQnVmZmVyLmNvbmNhdChbQnVmZmVyLmFsbG9jKGNvb3JkaW5hdGVCeXRlcyAtIHZhbHVlLmxlbmd0aCksIHZhbHVlXSk7XG4gIH07XG5cbiAgY29uc3QgciA9IHJlYWRJbnQoKTtcbiAgY29uc3QgcyA9IHJlYWRJbnQoKTtcbiAgcmV0dXJuIEJ1ZmZlci5jb25jYXQoW3IsIHNdKTtcbn1cbiJdfQ==
@@ -1,4 +1,30 @@
1
1
  import winston from 'winston';
2
+ /**
3
+ * Per-request identity stamped onto every log entry, so log lines can be
4
+ * attributed to the org that caused them.
5
+ *
6
+ * `orgId` is the tenancy key for the Logs surface: promtail routes each line to
7
+ * its org's Loki tenant from this field (see `docs/plans/frontend-logs.md`). A
8
+ * line written outside a request scope (startup, background worker, migration)
9
+ * has no org and lands in the sysadmin-only `_infra` tenant — fail-closed.
10
+ */
11
+ export interface LogContext {
12
+ orgId?: string;
13
+ userId?: string;
14
+ }
15
+ type LogContextProvider = () => LogContext | undefined;
16
+ /**
17
+ * Register the source of per-entry {@link LogContext}.
18
+ *
19
+ * A registration hook rather than a direct import because the request scope
20
+ * lives in `pipeline-data`'s AsyncLocalStorage, and `pipeline-data` depends on
21
+ * this package — importing it here would invert the dependency. `api-server`'s
22
+ * tenant-context module owns the single call, which covers every service that
23
+ * mounts `withTenantContext` (platform included).
24
+ *
25
+ * Pass `undefined` to unregister (tests).
26
+ */
27
+ export declare function setLogContextProvider(fn: LogContextProvider | undefined): void;
2
28
  /**
3
29
  * Redact sensitive values from an ARBITRARY payload using the same key-pattern
4
30
  * rules the Winston `redactFormat` applies to log metadata. Use this for
@@ -30,7 +56,10 @@ export declare function redactSensitive(value: unknown): unknown;
30
56
  * logger.error('Database error', { error: err.message });
31
57
  * ```
32
58
  */
33
- export declare function createLogger(serviceName: string): winston.Logger;
59
+ /** The logger `createLogger` returns. Exported so consumers can annotate exported
60
+ * loggers without depending on winston themselves. */
61
+ export type Logger = winston.Logger;
62
+ export declare function createLogger(serviceName: string): Logger;
34
63
  /**
35
64
  * Default logger instance (service name from SERVICE_NAME env var or 'api').
36
65
  */
@@ -2,6 +2,7 @@
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
  import winston from 'winston';
4
4
  import { safeCreateRequire } from './safe-require.js';
5
+ import { SENSITIVE_KEY_PATTERN, REDACTED, maskLine } from './sensitive-patterns.js';
5
6
  const { combine, timestamp, printf, colorize, errors, json } = winston.format;
6
7
  // ESM has no global `require`; safeCreateRequire enables the synchronous,
7
8
  // OPTIONAL lazy-load of @opentelemetry/api in getCurrentTraceId() below — a
@@ -48,14 +49,47 @@ const traceIdFormat = winston.format((info) => {
48
49
  info.trace_id = traceId;
49
50
  return info;
50
51
  })();
52
+ let logContextProvider;
51
53
  /**
52
- * Keys that should never appear in logs. Match is case-insensitive and
53
- * anchored substring — `Authorization`, `auth_header`, `MY_PASSWORD` all hit.
54
- * Add a new term here only if you've seen real-world leakage; over-redaction
55
- * makes incident debugging harder.
54
+ * Register the source of per-entry {@link LogContext}.
55
+ *
56
+ * A registration hook rather than a direct import because the request scope
57
+ * lives in `pipeline-data`'s AsyncLocalStorage, and `pipeline-data` depends on
58
+ * this package — importing it here would invert the dependency. `api-server`'s
59
+ * tenant-context module owns the single call, which covers every service that
60
+ * mounts `withTenantContext` (platform included).
61
+ *
62
+ * Pass `undefined` to unregister (tests).
56
63
  */
57
- const SENSITIVE_KEY_PATTERN = /password|secret|bearer|api[_-]?key|cookie|token|^auth(orization|_header)?$|stripe[_-]?(key|secret)|mongo(db)?[_-]?uri/i;
58
- const REDACTED = '[REDACTED]';
64
+ export function setLogContextProvider(fn) {
65
+ logContextProvider = fn;
66
+ }
67
+ /** Winston format stamping the ambient {@link LogContext}. Never throws: a
68
+ * provider that blows up must not take down logging. An entry that already
69
+ * carries an explicit `orgId` (a call site logging about ANOTHER org) keeps it
70
+ * — the ambient value never overwrites a deliberate one. */
71
+ const logContextFormat = winston.format((info) => {
72
+ if (!logContextProvider)
73
+ return info;
74
+ let ctx;
75
+ try {
76
+ ctx = logContextProvider();
77
+ }
78
+ catch {
79
+ return info;
80
+ }
81
+ if (!ctx)
82
+ return info;
83
+ if (ctx.orgId && info.orgId === undefined)
84
+ info.orgId = ctx.orgId;
85
+ if (ctx.userId && info.userId === undefined)
86
+ info.userId = ctx.userId;
87
+ return info;
88
+ })();
89
+ // `SENSITIVE_KEY_PATTERN` (keys) and `maskLine` (secret-shaped values) both come
90
+ // from `sensitive-patterns.ts`, so the logger, platform's log-read path and the
91
+ // generated promtail `replace` stages mask the same things. See that module's
92
+ // header for why ingest-time masking is the authoritative layer.
59
93
  function redactDeep(value, depth = 0) {
60
94
  // Cap depth so a malicious / pathological circular object can't lock the logger.
61
95
  // Degrade to a placeholder rather than the raw subtree: returning `value` here
@@ -96,7 +130,12 @@ export function redactSensitive(value) {
96
130
  * (`Symbol.for('level')`, `Symbol.for('message')`, `Symbol.for('splat')`) survive
97
131
  * — rebuilding a fresh object via `Object.entries`/spread silently strips them,
98
132
  * which makes the Console transport drop every entry without warning. */
99
- const PRESERVED_KEYS = new Set(['level', 'message', 'timestamp', 'service', 'trace_id']);
133
+ /** Keys the redactor must leave alone. `orgId`/`userId` are load-bearing: promtail
134
+ * routes a line to its Loki tenant by `orgId`, so redacting it would misfile the
135
+ * line into the sysadmin-only `_infra` tenant instead of the org's. Listed here
136
+ * (not merely "doesn't match the pattern today") so a future pattern edit can't
137
+ * silently break log tenancy. */
138
+ const PRESERVED_KEYS = new Set(['level', 'message', 'timestamp', 'service', 'trace_id', 'orgId', 'userId']);
100
139
  const redactFormat = winston.format((info) => {
101
140
  for (const key of Object.keys(info)) {
102
141
  if (PRESERVED_KEYS.has(key))
@@ -111,26 +150,28 @@ const redactFormat = winston.format((info) => {
111
150
  return info;
112
151
  })();
113
152
  /**
114
- * Create a logger instance for a service.
153
+ * Winston format that masks secret-shaped VALUES in the rendered message and in
154
+ * any string metadata.
115
155
  *
116
- * When LOG_FORMAT=json (default), outputs structured JSON for Loki ingestion:
117
- * {"level":"info","message":"Server started","service":"pipeline","timestamp":"..."}
118
- *
119
- * When LOG_FORMAT=text, outputs colorized human-readable format:
120
- * 2026-02-13T10:30:00.000Z info [pipeline] Server started
121
- *
122
- * @param serviceName - Name of the service for log identification
123
- * @returns Configured Winston logger instance
124
- *
125
- * @example
126
- * ```typescript
127
- * import { createLogger } from '@pipeline-builder/api-core';
128
- *
129
- * const logger = createLogger('get-plugin');
130
- * logger.info('Server started', { port: 3000 });
131
- * logger.error('Database error', { error: err.message });
132
- * ```
156
+ * `redactFormat` above only masks values whose KEY looks sensitive. That misses
157
+ * a secret embedded in free text — `logger.info('POST /x?token=abc')` — which
158
+ * matters more than it looks: promtail's `output: { source: msg }` stage makes
159
+ * the message string the entire shipped log line, so an unmasked message is an
160
+ * unmasked log. Mutates in place to preserve winston's Symbol-keyed internals,
161
+ * exactly as `redactFormat` does.
133
162
  */
163
+ const maskFormat = winston.format((info) => {
164
+ if (typeof info.message === 'string')
165
+ info.message = maskLine(info.message);
166
+ for (const key of Object.keys(info)) {
167
+ if (key === 'message')
168
+ continue;
169
+ const value = info[key];
170
+ if (typeof value === 'string')
171
+ info[key] = maskLine(value);
172
+ }
173
+ return info;
174
+ })();
134
175
  export function createLogger(serviceName) {
135
176
  const logLevel = process.env.LOG_LEVEL || 'info';
136
177
  const logFormat = process.env.LOG_FORMAT || 'json';
@@ -140,12 +181,18 @@ export function createLogger(serviceName) {
140
181
  }
141
182
  const useJson = logFormat !== 'text';
142
183
  // Order matters: redact BEFORE serialization so masked keys never reach
143
- // the output. trace_id is stamped first so it survives redaction.
184
+ // the output. trace_id and the org/user context are stamped first so they
185
+ // survive redaction (both are in PRESERVED_KEYS), then `maskFormat` scrubs
186
+ // secret-shaped VALUES out of the rendered message — the key-based
187
+ // `redactFormat` only covers metadata keys, and after promtail's
188
+ // `output: source: msg` rewrite the shipped line IS the message string.
144
189
  const baseFormats = [
145
190
  errors({ stack: true }),
146
191
  timestamp({ format: 'YYYY-MM-DDTHH:mm:ss.SSSZ' }),
147
192
  traceIdFormat,
193
+ logContextFormat,
148
194
  redactFormat,
195
+ maskFormat,
149
196
  ];
150
197
  if (useJson) {
151
198
  return winston.createLogger({
@@ -171,4 +218,4 @@ export function createLogger(serviceName) {
171
218
  */
172
219
  export const logger = createLogger(process.env.SERVICE_NAME || 'api');
173
220
  export default logger;
174
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9nZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3V0aWxzL2xvZ2dlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDLE9BQU8sT0FBTyxNQUFNLFNBQVMsQ0FBQztBQUM5QixPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUV0RCxNQUFNLEVBQUUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDO0FBRTlFLDBFQUEwRTtBQUMxRSw0RUFBNEU7QUFDNUUsNkVBQTZFO0FBQzdFLHVEQUF1RDtBQUN2RCxNQUFNLE9BQU8sR0FBRyxpQkFBaUIsQ0FBQyxPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztBQUVuRDs7R0FFRztBQUNILE1BQU0sYUFBYSxHQUFHLE1BQU0sQ0FBQyxDQUFDLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLEdBQUcsSUFBSSxFQUFFLEVBQUUsRUFBRTtJQUMvRSxNQUFNLFdBQVcsR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDLElBQUksT0FBTyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztJQUNsRCxNQUFNLE9BQU8sR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsSUFBSSxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztJQUMzRSxPQUFPLEdBQUcsU0FBUyxJQUFJLEtBQUssSUFBSSxXQUFXLElBQUksT0FBTyxHQUFHLE9BQU8sRUFBRSxDQUFDO0FBQ3JFLENBQUMsQ0FBQyxDQUFDO0FBRUg7Ozs7R0FJRztBQUNILElBQUksUUFBZ0gsQ0FBQztBQUNySCxT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QUFXLEVBQUUsRUFBRSxPQUFPLEVBQUUsV0FBVyxFQUFFO1lBQ3JDLE1BQU0sRUFBRSxPQUFPLENBQUMsR0FBRyxXQUFXLEVBQUUsSUFBSSxFQUFFLENBQUM7WUFDdkMsVUFBVSxFQUFFLENBQUMsSUFBSSxPQUFPLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxDQUFDO1NBQy9DLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRCxPQUFPLE9BQU8sQ0FBQyxZQUFZLENBQUM7UUFDMUIsS0FBSyxFQUFFLFFBQVE7UUFDZixXQUFXLEVBQUUsRUFBRSxPQUFPLEVBQUUsV0FBVyxFQUFFO1FBQ3JDLE1BQU0sRUFBRSxPQUFPLENBQUMsR0FBRyxXQUFXLENBQUM7UUFDL0IsVUFBVSxFQUFFO1lBQ1YsSUFBSSxPQUFPLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQztnQkFDN0IsTUFBTSxFQUFFLE9BQU8sQ0FBQyxRQUFRLEVBQUUsRUFBRSxhQUFhLENBQUM7YUFDM0MsQ0FBQztTQUNIO0tBQ0YsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQUVEOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sTUFBTSxHQUFHLFlBQVksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLFlBQVksSUFBSSxLQUFLLENBQUMsQ0FBQztBQUV0RSxlQUFlLE1BQU0sQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgd2luc3RvbiBmcm9tICd3aW5zdG9uJztcbmltcG9ydCB7IHNhZmVDcmVhdGVSZXF1aXJlIH0gZnJvbSAnLi9zYWZlLXJlcXVpcmUuanMnO1xuXG5jb25zdCB7IGNvbWJpbmUsIHRpbWVzdGFtcCwgcHJpbnRmLCBjb2xvcml6ZSwgZXJyb3JzLCBqc29uIH0gPSB3aW5zdG9uLmZvcm1hdDtcblxuLy8gRVNNIGhhcyBubyBnbG9iYWwgYHJlcXVpcmVgOyBzYWZlQ3JlYXRlUmVxdWlyZSBlbmFibGVzIHRoZSBzeW5jaHJvbm91cyxcbi8vIE9QVElPTkFMIGxhenktbG9hZCBvZiBAb3BlbnRlbGVtZXRyeS9hcGkgaW4gZ2V0Q3VycmVudFRyYWNlSWQoKSBiZWxvdyDigJQgYVxuLy8gd2luc3RvbiBmb3JtYXQgY2FsbGJhY2sgbXVzdCBzdGF5IHN5bmNocm9ub3VzLCBzbyBhIGR5bmFtaWMgaW1wb3J0KCkgd29uJ3Rcbi8vIHdvcmsgdGhlcmUuIChDSlMtYnVuZGxlIHNhZmUg4oCUIHNlZSBzYWZlLXJlcXVpcmUudHMuKVxuY29uc3QgcmVxdWlyZSA9IHNhZmVDcmVhdGVSZXF1aXJlKGltcG9ydC5tZXRhLnVybCk7XG5cbi8qKlxuICogQ3VzdG9tIGxvZyBmb3JtYXQgZm9yIGh1bWFuLXJlYWRhYmxlIGNvbnNvbGUgb3V0cHV0LlxuICovXG5jb25zdCBjb25zb2xlRm9ybWF0ID0gcHJpbnRmKCh7IGxldmVsLCBtZXNzYWdlLCB0aW1lc3RhbXAsIHNlcnZpY2UsIC4uLm1ldGEgfSkgPT4ge1xuICBjb25zdCBzZXJ2aWNlTmFtZSA9IHNlcnZpY2UgPyBgWyR7c2VydmljZX1dYCA6ICcnO1xuICBjb25zdCBtZXRhU3RyID0gT2JqZWN0LmtleXMobWV0YSkubGVuZ3RoID8gYCAke0pTT04uc3RyaW5naWZ5KG1ldGEpfWAgOiAnJztcbiAgcmV0dXJuIGAke3RpbWVzdGFtcH0gJHtsZXZlbH0gJHtzZXJ2aWNlTmFtZX0gJHttZXNzYWdlfSR7bWV0YVN0cn1gO1xufSk7XG5cbi8qKlxuICogTGF6eSBsb29rdXAgb2YgT3BlblRlbGVtZXRyeSB0cmFjZSBJRC4gUmV0dXJucyB1bmRlZmluZWQgd2hlbiB0cmFjaW5nXG4gKiBpc24ndCBpbml0aWFsaXplZCBvciBAb3BlbnRlbGVtZXRyeS9hcGkgaXNuJ3QgaW5zdGFsbGVkIOKAlCBuZXZlciB0aHJvd3MuXG4gKiBDaGVhcDogYSBzaW5nbGUgcHJvcGVydHkgcmVhZCBhZnRlciB0aGUgZmlyc3Qgc3VjY2Vzc2Z1bCBsb29rdXAuXG4gKi9cbmxldCBfb3RlbEFwaTogeyB0cmFjZT86IHsgZ2V0QWN0aXZlU3BhbigpOiB7IHNwYW5Db250ZXh0KCk6IHsgdHJhY2VJZDogc3RyaW5nIH0gfSB8IHVuZGVmaW5lZCB9IH0gfCBudWxsIHwgdW5kZWZpbmVkO1xuZnVuY3Rpb24gZ2V0Q3VycmVudFRyYWNlSWQoKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgaWYgKF9vdGVsQXBpID09PSB1bmRlZmluZWQpIHtcbiAgICB0cnkge1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1yZXF1aXJlLWltcG9ydHNcbiAgICAgIF9vdGVsQXBpID0gcmVxdWlyZSgnQG9wZW50ZWxlbWV0cnkvYXBpJyk7XG4gICAgfSBjYXRjaCB7XG4gICAgICBfb3RlbEFwaSA9IG51bGw7XG4gICAgfVxuICB9XG4gIGlmICghX290ZWxBcGkpIHJldHVybiB1bmRlZmluZWQ7XG4gIHRyeSB7XG4gICAgcmV0dXJuIF9vdGVsQXBpLnRyYWNlPy5nZXRBY3RpdmVTcGFuKCk/LnNwYW5Db250ZXh0KCkudHJhY2VJZDtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxufVxuXG4vKiogV2luc3RvbiBmb3JtYXQgdGhhdCBzdGFtcHMgYHRyYWNlX2lkYCBvbiBldmVyeSBlbnRyeSB3aGVuIGFuIE9UZWwgc3BhbiBpcyBhY3RpdmUuICovXG5jb25zdCB0cmFjZUlkRm9ybWF0ID0gd2luc3Rvbi5mb3JtYXQoKGluZm8pID0+IHtcbiAgY29uc3QgdHJhY2VJZCA9IGdldEN1cnJlbnRUcmFjZUlkKCk7XG4gIGlmICh0cmFjZUlkKSBpbmZvLnRyYWNlX2lkID0gdHJhY2VJZDtcbiAgcmV0dXJuIGluZm87XG59KSgpO1xuXG4vKipcbiAqIEtleXMgdGhhdCBzaG91bGQgbmV2ZXIgYXBwZWFyIGluIGxvZ3MuIE1hdGNoIGlzIGNhc2UtaW5zZW5zaXRpdmUgYW5kXG4gKiBhbmNob3JlZCBzdWJzdHJpbmcg4oCUIGBBdXRob3JpemF0aW9uYCwgYGF1dGhfaGVhZGVyYCwgYE1ZX1BBU1NXT1JEYCBhbGwgaGl0LlxuICogQWRkIGEgbmV3IHRlcm0gaGVyZSBvbmx5IGlmIHlvdSd2ZSBzZWVuIHJlYWwtd29ybGQgbGVha2FnZTsgb3Zlci1yZWRhY3Rpb25cbiAqIG1ha2VzIGluY2lkZW50IGRlYnVnZ2luZyBoYXJkZXIuXG4gKi9cbmNvbnN0IFNFTlNJVElWRV9LRVlfUEFUVEVSTiA9IC9wYXNzd29yZHxzZWNyZXR8YmVhcmVyfGFwaVtfLV0/a2V5fGNvb2tpZXx0b2tlbnxeYXV0aChvcml6YXRpb258X2hlYWRlcik/JHxzdHJpcGVbXy1dPyhrZXl8c2VjcmV0KXxtb25nbyhkYik/W18tXT91cmkvaTtcbmNvbnN0IFJFREFDVEVEID0gJ1tSRURBQ1RFRF0nO1xuXG5mdW5jdGlvbiByZWRhY3REZWVwKHZhbHVlOiB1bmtub3duLCBkZXB0aCA9IDApOiB1bmtub3duIHtcbiAgLy8gQ2FwIGRlcHRoIHNvIGEgbWFsaWNpb3VzIC8gcGF0aG9sb2dpY2FsIGNpcmN1bGFyIG9iamVjdCBjYW4ndCBsb2NrIHRoZSBsb2dnZXIuXG4gIC8vIERlZ3JhZGUgdG8gYSBwbGFjZWhvbGRlciByYXRoZXIgdGhhbiB0aGUgcmF3IHN1YnRyZWU6IHJldHVybmluZyBgdmFsdWVgIGhlcmVcbiAgLy8gd291bGQgbG9nIGEgc2VjcmV0LWtleWVkIGZpZWxkIG5lc3RlZCBkZWVwZXIgdGhhbiB0aGUgY2FwIGluIGNsZWFydGV4dC5cbiAgaWYgKGRlcHRoID4gNikgcmV0dXJuICdbVFJVTkNBVEVEXSc7XG4gIGlmICh2YWx1ZSA9PSBudWxsIHx8IHR5cGVvZiB2YWx1ZSAhPT0gJ29iamVjdCcpIHJldHVybiB2YWx1ZTtcbiAgaWYgKEFycmF5LmlzQXJyYXkodmFsdWUpKSByZXR1cm4gdmFsdWUubWFwKCh2KSA9PiByZWRhY3REZWVwKHYsIGRlcHRoICsgMSkpO1xuICBjb25zdCBvdXQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0ge307XG4gIGZvciAoY29uc3QgW2ssIHZdIG9mIE9iamVjdC5lbnRyaWVzKHZhbHVlIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KSkge1xuICAgIGlmIChTRU5TSVRJVkVfS0VZX1BBVFRFUk4udGVzdChrKSkge1xuICAgICAgb3V0W2tdID0gUkVEQUNURUQ7XG4gICAgfSBlbHNlIHtcbiAgICAgIG91dFtrXSA9IHJlZGFjdERlZXAodiwgZGVwdGggKyAxKTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIG91dDtcbn1cblxuLyoqXG4gKiBSZWRhY3Qgc2Vuc2l0aXZlIHZhbHVlcyBmcm9tIGFuIEFSQklUUkFSWSBwYXlsb2FkIHVzaW5nIHRoZSBzYW1lIGtleS1wYXR0ZXJuXG4gKiBydWxlcyB0aGUgV2luc3RvbiBgcmVkYWN0Rm9ybWF0YCBhcHBsaWVzIHRvIGxvZyBtZXRhZGF0YS4gVXNlIHRoaXMgZm9yXG4gKiBwYXlsb2FkcyB0aGF0IHJlYWNoIGFuIG91dHB1dCBjaGFubmVsIE9VVFNJREUgdGhlIGxvZ2dlciDigJQgZS5nLiBhbiBTU0UgZnJhbWVcbiAqIHB1c2hlZCBzdHJhaWdodCB0byBhIGNsaWVudCDigJQgc28gYSBgcGFzc3dvcmRgL2B0b2tlbmAvYHNlY3JldGAgZmllbGQgaXNcbiAqIG1hc2tlZCB0aGVyZSB0b28uIEEgdG9wLWxldmVsIHNlbnNpdGl2ZSBrZXkgaXMgbWFza2VkOyBuZXN0ZWQgb2JqZWN0cy9hcnJheXNcbiAqIGFyZSB3YWxrZWQgKGRlcHRoLWNhcHBlZCkgZXhhY3RseSBhcyBpbiB0aGUgbG9nZ2VyLiBSZXR1cm5zIGEgcmVkYWN0ZWQgQ09QWTtcbiAqIHByaW1pdGl2ZXMgcGFzcyB0aHJvdWdoIHVuY2hhbmdlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlZGFjdFNlbnNpdGl2ZSh2YWx1ZTogdW5rbm93bik6IHVua25vd24ge1xuICBpZiAodmFsdWUgPT0gbnVsbCB8fCB0eXBlb2YgdmFsdWUgIT09ICdvYmplY3QnKSByZXR1cm4gdmFsdWU7XG4gIHJldHVybiByZWRhY3REZWVwKHZhbHVlKTtcbn1cblxuLyoqIFdpbnN0b24gZm9ybWF0IHRoYXQgbWFza3MgdmFsdWVzIGZvciBzZW5zaXRpdmUtbG9va2luZyBrZXlzIChQSUkgLyBzZWNyZXRzKS5cbiAqIE11dGF0ZXMgYGluZm9gIGluIHBsYWNlIHNvIHdpbnN0b24ncyBpbnRlcm5hbCBTeW1ib2wta2V5ZWQgcHJvcGVydGllc1xuICogKGBTeW1ib2wuZm9yKCdsZXZlbCcpYCwgYFN5bWJvbC5mb3IoJ21lc3NhZ2UnKWAsIGBTeW1ib2wuZm9yKCdzcGxhdCcpYCkgc3Vydml2ZVxuICog4oCUIHJlYnVpbGRpbmcgYSBmcmVzaCBvYmplY3QgdmlhIGBPYmplY3QuZW50cmllc2Avc3ByZWFkIHNpbGVudGx5IHN0cmlwcyB0aGVtLFxuICogd2hpY2ggbWFrZXMgdGhlIENvbnNvbGUgdHJhbnNwb3J0IGRyb3AgZXZlcnkgZW50cnkgd2l0aG91dCB3YXJuaW5nLiAqL1xuY29uc3QgUFJFU0VSVkVEX0tFWVMgPSBuZXcgU2V0KFsnbGV2ZWwnLCAnbWVzc2FnZScsICd0aW1lc3RhbXAnLCAnc2VydmljZScsICd0cmFjZV9pZCddKTtcbmNvbnN0IHJlZGFjdEZvcm1hdCA9IHdpbnN0b24uZm9ybWF0KChpbmZvKSA9PiB7XG4gIGZvciAoY29uc3Qga2V5IG9mIE9iamVjdC5rZXlzKGluZm8pKSB7XG4gICAgaWYgKFBSRVNFUlZFRF9LRVlTLmhhcyhrZXkpKSBjb250aW51ZTtcbiAgICBpZiAoU0VOU0lUSVZFX0tFWV9QQVRURVJOLnRlc3Qoa2V5KSkge1xuICAgICAgaW5mb1trZXldID0gUkVEQUNURUQ7XG4gICAgfSBlbHNlIHtcbiAgICAgIGluZm9ba2V5XSA9IHJlZGFjdERlZXAoaW5mb1trZXldKTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGluZm87XG59KSgpO1xuXG4vKipcbiAqIENyZWF0ZSBhIGxvZ2dlciBpbnN0YW5jZSBmb3IgYSBzZXJ2aWNlLlxuICpcbiAqIFdoZW4gTE9HX0ZPUk1BVD1qc29uIChkZWZhdWx0KSwgb3V0cHV0cyBzdHJ1Y3R1cmVkIEpTT04gZm9yIExva2kgaW5nZXN0aW9uOlxuICogICB7XCJsZXZlbFwiOlwiaW5mb1wiLFwibWVzc2FnZVwiOlwiU2VydmVyIHN0YXJ0ZWRcIixcInNlcnZpY2VcIjpcInBpcGVsaW5lXCIsXCJ0aW1lc3RhbXBcIjpcIi4uLlwifVxuICpcbiAqIFdoZW4gTE9HX0ZPUk1BVD10ZXh0LCBvdXRwdXRzIGNvbG9yaXplZCBodW1hbi1yZWFkYWJsZSBmb3JtYXQ6XG4gKiAgIDIwMjYtMDItMTNUMTA6MzA6MDAuMDAwWiBpbmZvIFtwaXBlbGluZV0gU2VydmVyIHN0YXJ0ZWRcbiAqXG4gKiBAcGFyYW0gc2VydmljZU5hbWUgLSBOYW1lIG9mIHRoZSBzZXJ2aWNlIGZvciBsb2cgaWRlbnRpZmljYXRpb25cbiAqIEByZXR1cm5zIENvbmZpZ3VyZWQgV2luc3RvbiBsb2dnZXIgaW5zdGFuY2VcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogaW1wb3J0IHsgY3JlYXRlTG9nZ2VyIH0gZnJvbSAnQHBpcGVsaW5lLWJ1aWxkZXIvYXBpLWNvcmUnO1xuICpcbiAqIGNvbnN0IGxvZ2dlciA9IGNyZWF0ZUxvZ2dlcignZ2V0LXBsdWdpbicpO1xuICogbG9nZ2VyLmluZm8oJ1NlcnZlciBzdGFydGVkJywgeyBwb3J0OiAzMDAwIH0pO1xuICogbG9nZ2VyLmVycm9yKCdEYXRhYmFzZSBlcnJvcicsIHsgZXJyb3I6IGVyci5tZXNzYWdlIH0pO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVMb2dnZXIoc2VydmljZU5hbWU6IHN0cmluZyk6IHdpbnN0b24uTG9nZ2VyIHtcbiAgY29uc3QgbG9nTGV2ZWwgPSBwcm9jZXNzLmVudi5MT0dfTEVWRUwgfHwgJ2luZm8nO1xuICBjb25zdCBsb2dGb3JtYXQgPSBwcm9jZXNzLmVudi5MT0dfRk9STUFUIHx8ICdqc29uJztcbiAgaWYgKGxvZ0Zvcm1hdCAhPT0gJ2pzb24nICYmIGxvZ0Zvcm1hdCAhPT0gJ3RleHQnKSB7XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWNvbnNvbGUgLS0gc3RhcnR1cCB3YXJuaW5nIGJlZm9yZSBsb2dnZXIgaXMgYXZhaWxhYmxlXG4gICAgY29uc29sZS53YXJuKGBJbnZhbGlkIExPR19GT1JNQVQ9XCIke2xvZ0Zvcm1hdH1cIiwgZXhwZWN0ZWQgXCJqc29uXCIgb3IgXCJ0ZXh0XCIuIERlZmF1bHRpbmcgdG8gXCJqc29uXCIuYCk7XG4gIH1cbiAgY29uc3QgdXNlSnNvbiA9IGxvZ0Zvcm1hdCAhPT0gJ3RleHQnO1xuXG4gIC8vIE9yZGVyIG1hdHRlcnM6IHJlZGFjdCBCRUZPUkUgc2VyaWFsaXphdGlvbiBzbyBtYXNrZWQga2V5cyBuZXZlciByZWFjaFxuICAvLyB0aGUgb3V0cHV0LiB0cmFjZV9pZCBpcyBzdGFtcGVkIGZpcnN0IHNvIGl0IHN1cnZpdmVzIHJlZGFjdGlvbi5cbiAgY29uc3QgYmFzZUZvcm1hdHMgPSBbXG4gICAgZXJyb3JzKHsgc3RhY2s6IHRydWUgfSksXG4gICAgdGltZXN0YW1wKHsgZm9ybWF0OiAnWVlZWS1NTS1ERFRISDptbTpzcy5TU1NaJyB9KSxcbiAgICB0cmFjZUlkRm9ybWF0LFxuICAgIHJlZGFjdEZvcm1hdCxcbiAgXTtcblxuICBpZiAodXNlSnNvbikge1xuICAgIHJldHVybiB3aW5zdG9uLmNyZWF0ZUxvZ2dlcih7XG4gICAgICBsZXZlbDogbG9nTGV2ZWwsXG4gICAgICBkZWZhdWx0TWV0YTogeyBzZXJ2aWNlOiBzZXJ2aWNlTmFtZSB9LFxuICAgICAgZm9ybWF0OiBjb21iaW5lKC4uLmJhc2VGb3JtYXRzLCBqc29uKCkpLFxuICAgICAgdHJhbnNwb3J0czogW25ldyB3aW5zdG9uLnRyYW5zcG9ydHMuQ29uc29sZSgpXSxcbiAgICB9KTtcbiAgfVxuXG4gIHJldHVybiB3aW5zdG9uLmNyZWF0ZUxvZ2dlcih7XG4gICAgbGV2ZWw6IGxvZ0xldmVsLFxuICAgIGRlZmF1bHRNZXRhOiB7IHNlcnZpY2U6IHNlcnZpY2VOYW1lIH0sXG4gICAgZm9ybWF0OiBjb21iaW5lKC4uLmJhc2VGb3JtYXRzKSxcbiAgICB0cmFuc3BvcnRzOiBbXG4gICAgICBuZXcgd2luc3Rvbi50cmFuc3BvcnRzLkNvbnNvbGUoe1xuICAgICAgICBmb3JtYXQ6IGNvbWJpbmUoY29sb3JpemUoKSwgY29uc29sZUZvcm1hdCksXG4gICAgICB9KSxcbiAgICBdLFxuICB9KTtcbn1cblxuLyoqXG4gKiBEZWZhdWx0IGxvZ2dlciBpbnN0YW5jZSAoc2VydmljZSBuYW1lIGZyb20gU0VSVklDRV9OQU1FIGVudiB2YXIgb3IgJ2FwaScpLlxuICovXG5leHBvcnQgY29uc3QgbG9nZ2VyID0gY3JlYXRlTG9nZ2VyKHByb2Nlc3MuZW52LlNFUlZJQ0VfTkFNRSB8fCAnYXBpJyk7XG5cbmV4cG9ydCBkZWZhdWx0IGxvZ2dlcjtcbiJdfQ==
221
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9nZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3V0aWxzL2xvZ2dlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDLE9BQU8sT0FBTyxNQUFNLFNBQVMsQ0FBQztBQUM5QixPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUN0RCxPQUFPLEVBQUUscUJBQXFCLEVBQUUsUUFBUSxFQUFFLFFBQVEsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBRXBGLE1BQU0sRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUM7QUFFOUUsMEVBQTBFO0FBQzFFLDRFQUE0RTtBQUM1RSw2RUFBNkU7QUFDN0UsdURBQXVEO0FBQ3ZELE1BQU0sT0FBTyxHQUFHLGlCQUFpQixDQUFDLE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0FBRW5EOztHQUVHO0FBQ0gsTUFBTSxhQUFhLEdBQUcsTUFBTSxDQUFDLENBQUMsRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLFNBQVMsRUFBRSxPQUFPLEVBQUUsR0FBRyxJQUFJLEVBQUUsRUFBRSxFQUFFO0lBQy9FLE1BQU0sV0FBVyxHQUFHLE9BQU8sQ0FBQyxDQUFDLENBQUMsSUFBSSxPQUFPLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0lBQ2xELE1BQU0sT0FBTyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxJQUFJLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0lBQzNFLE9BQU8sR0FBRyxTQUFTLElBQUksS0FBSyxJQUFJLFdBQVcsSUFBSSxPQUFPLEdBQUcsT0FBTyxFQUFFLENB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QWUsTUFBTSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCB3aW5zdG9uIGZyb20gJ3dpbnN0b24nO1xuaW1wb3J0IHsgc2FmZUNyZWF0ZVJlcXVpcmUgfSBmcm9tICcuL3NhZmUtcmVxdWlyZS5qcyc7XG5pbXBvcnQgeyBTRU5TSVRJVkVfS0VZX1BBVFRFUk4sIFJFREFDVEVELCBtYXNrTGluZSB9IGZyb20gJy4vc2Vuc2l0aXZlLXBhdHRlcm5zLmpzJztcblxuY29uc3QgeyBjb21iaW5lLCB0aW1lc3RhbXAsIHByaW50ZiwgY29sb3JpemUsIGVycm9ycywganNvbiB9ID0gd2luc3Rvbi5mb3JtYXQ7XG5cbi8vIEVTTSBoYXMgbm8gZ2xvYmFsIGByZXF1aXJlYDsgc2FmZUNyZWF0ZVJlcXVpcmUgZW5hYmxlcyB0aGUgc3luY2hyb25vdXMsXG4vLyBPUFRJT05BTCBsYXp5LWxvYWQgb2YgQG9wZW50ZWxlbWV0cnkvYXBpIGluIGdldEN1cnJlbnRUcmFjZUlkKCkgYmVsb3cg4oCUIGFcbi8vIHdpbnN0b24gZm9ybWF0IGNhbGxiYWNrIG11c3Qgc3RheSBzeW5jaHJvbm91cywgc28gYSBkeW5hbWljIGltcG9ydCgpIHdvbid0XG4vLyB3b3JrIHRoZXJlLiAoQ0pTLWJ1bmRsZSBzYWZlIOKAlCBzZWUgc2FmZS1yZXF1aXJlLnRzLilcbmNvbnN0IHJlcXVpcmUgPSBzYWZlQ3JlYXRlUmVxdWlyZShpbXBvcnQubWV0YS51cmwpO1xuXG4vKipcbiAqIEN1c3RvbSBsb2cgZm9ybWF0IGZvciBodW1hbi1yZWFkYWJsZSBjb25zb2xlIG91dHB1dC5cbiAqL1xuY29uc3QgY29uc29sZUZvcm1hdCA9IHByaW50ZigoeyBsZXZlbCwgbWVzc2FnZSwgdGltZXN0YW1wLCBzZXJ2aWNlLCAuLi5tZXRhIH0pID0+IHtcbiAgY29uc3Qgc2VydmljZU5hbWUgPSBzZXJ2aWNlID8gYFske3NlcnZpY2V9XWAgOiAnJztcbiAgY29uc3QgbWV0YVN0ciA9IE9iamVjdC5rZXlzKG1ldGEpLmxlbmd0aCA/IGAgJHtKU09OLnN0cmluZ2lmeShtZXRhKX1gIDogJyc7XG4gIHJldHVybiBgJHt0aW1lc3RhbXB9ICR7bGV2ZWx9ICR7c2VydmljZU5hbWV9ICR7bWVzc2FnZX0ke21ldGFTdHJ9YDtcbn0pO1xuXG4vKipcbiAqIExhenkgbG9va3VwIG9mIE9wZW5UZWxlbWV0cnkgdHJhY2UgSUQuIFJldHVybnMgdW5kZWZpbmVkIHdoZW4gdHJhY2luZ1xuICogaXNuJ3QgaW5pdGlhbGl6ZWQgb3IgQG9wZW50ZWxlbWV0cnkvYXBpIGlzbid0IGluc3RhbGxlZCDigJQgbmV2ZXIgdGhyb3dzLlxuICogQ2hlYXA6IGEgc2luZ2xlIHByb3BlcnR5IHJlYWQgYWZ0ZXIgdGhlIGZpcnN0IHN1Y2Nlc3NmdWwgbG9va3VwLlxuICovXG5sZXQgX290ZWxBcGk6IHsgdHJhY2U/OiB7IGdldEFjdGl2ZVNwYW4oKTogeyBzcGFuQ29udGV4dCgpOiB7IHRyYWNlSWQ6IHN0cmluZyB9IH0gfCB1bmRlZmluZWQgfSB9IHwgbnVsbCB8IHVuZGVmaW5lZDtcbmZ1bmN0aW9uIGdldEN1cnJlbnRUcmFjZUlkKCk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGlmIChfb3RlbEFwaSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgdHJ5IHtcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tcmVxdWlyZS1pbXBvcnRzXG4gICAgICBfb3RlbEFwaSA9IHJlcXVpcmUoJ0BvcGVudGVsZW1ldHJ5L2FwaScpO1xuICAgIH0gY2F0Y2gge1xuICAgICAgX290ZWxBcGkgPSBudWxsO1xuICAgIH1cbiAgfVxuICBpZiAoIV9vdGVsQXBpKSByZXR1cm4gdW5kZWZpbmVkO1xuICB0cnkge1xuICAgIHJldHVybiBfb3RlbEFwaS50cmFjZT8uZ2V0QWN0aXZlU3BhbigpPy5zcGFuQ29udGV4dCgpLnRyYWNlSWQ7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbn1cblxuLyoqIFdpbnN0b24gZm9ybWF0IHRoYXQgc3RhbXBzIGB0cmFjZV9pZGAgb24gZXZlcnkgZW50cnkgd2hlbiBhbiBPVGVsIHNwYW4gaXMgYWN0aXZlLiAqL1xuY29uc3QgdHJhY2VJZEZvcm1hdCA9IHdpbnN0b24uZm9ybWF0KChpbmZvKSA9PiB7XG4gIGNvbnN0IHRyYWNlSWQgPSBnZXRDdXJyZW50VHJhY2VJZCgpO1xuICBpZiAodHJhY2VJZCkgaW5mby50cmFjZV9pZCA9IHRyYWNlSWQ7XG4gIHJldHVybiBpbmZvO1xufSkoKTtcblxuLyoqXG4gKiBQZXItcmVxdWVzdCBpZGVudGl0eSBzdGFtcGVkIG9udG8gZXZlcnkgbG9nIGVudHJ5LCBzbyBsb2cgbGluZXMgY2FuIGJlXG4gKiBhdHRyaWJ1dGVkIHRvIHRoZSBvcmcgdGhhdCBjYXVzZWQgdGhlbS5cbiAqXG4gKiBgb3JnSWRgIGlzIHRoZSB0ZW5hbmN5IGtleSBmb3IgdGhlIExvZ3Mgc3VyZmFjZTogcHJvbXRhaWwgcm91dGVzIGVhY2ggbGluZSB0b1xuICogaXRzIG9yZydzIExva2kgdGVuYW50IGZyb20gdGhpcyBmaWVsZCAoc2VlIGBkb2NzL3BsYW5zL2Zyb250ZW5kLWxvZ3MubWRgKS4gQVxuICogbGluZSB3cml0dGVuIG91dHNpZGUgYSByZXF1ZXN0IHNjb3BlIChzdGFydHVwLCBiYWNrZ3JvdW5kIHdvcmtlciwgbWlncmF0aW9uKVxuICogaGFzIG5vIG9yZyBhbmQgbGFuZHMgaW4gdGhlIHN5c2FkbWluLW9ubHkgYF9pbmZyYWAgdGVuYW50IOKAlCBmYWlsLWNsb3NlZC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBMb2dDb250ZXh0IHtcbiAgb3JnSWQ/OiBzdHJpbmc7XG4gIHVzZXJJZD86IHN0cmluZztcbn1cblxudHlwZSBMb2dDb250ZXh0UHJvdmlkZXIgPSAoKSA9PiBMb2dDb250ZXh0IHwgdW5kZWZpbmVkO1xuXG5sZXQgbG9nQ29udGV4dFByb3ZpZGVyOiBMb2dDb250ZXh0UHJvdmlkZXIgfCB1bmRlZmluZWQ7XG5cbi8qKlxuICogUmVnaXN0ZXIgdGhlIHNvdXJjZSBvZiBwZXItZW50cnkge0BsaW5rIExvZ0NvbnRleHR9LlxuICpcbiAqIEEgcmVnaXN0cmF0aW9uIGhvb2sgcmF0aGVyIHRoYW4gYSBkaXJlY3QgaW1wb3J0IGJlY2F1c2UgdGhlIHJlcXVlc3Qgc2NvcGVcbiAqIGxpdmVzIGluIGBwaXBlbGluZS1kYXRhYCdzIEFzeW5jTG9jYWxTdG9yYWdlLCBhbmQgYHBpcGVsaW5lLWRhdGFgIGRlcGVuZHMgb25cbiAqIHRoaXMgcGFja2FnZSDigJQgaW1wb3J0aW5nIGl0IGhlcmUgd291bGQgaW52ZXJ0IHRoZSBkZXBlbmRlbmN5LiBgYXBpLXNlcnZlcmAnc1xuICogdGVuYW50LWNvbnRleHQgbW9kdWxlIG93bnMgdGhlIHNpbmdsZSBjYWxsLCB3aGljaCBjb3ZlcnMgZXZlcnkgc2VydmljZSB0aGF0XG4gKiBtb3VudHMgYHdpdGhUZW5hbnRDb250ZXh0YCAocGxhdGZvcm0gaW5jbHVkZWQpLlxuICpcbiAqIFBhc3MgYHVuZGVmaW5lZGAgdG8gdW5yZWdpc3RlciAodGVzdHMpLlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2V0TG9nQ29udGV4dFByb3ZpZGVyKGZuOiBMb2dDb250ZXh0UHJvdmlkZXIgfCB1bmRlZmluZWQpOiB2b2lkIHtcbiAgbG9nQ29udGV4dFByb3ZpZGVyID0gZm47XG59XG5cbi8qKiBXaW5zdG9uIGZvcm1hdCBzdGFtcGluZyB0aGUgYW1iaWVudCB7QGxpbmsgTG9nQ29udGV4dH0uIE5ldmVyIHRocm93czogYVxuICogIHByb3ZpZGVyIHRoYXQgYmxvd3MgdXAgbXVzdCBub3QgdGFrZSBkb3duIGxvZ2dpbmcuIEFuIGVudHJ5IHRoYXQgYWxyZWFkeVxuICogIGNhcnJpZXMgYW4gZXhwbGljaXQgYG9yZ0lkYCAoYSBjYWxsIHNpdGUgbG9nZ2luZyBhYm91dCBBTk9USEVSIG9yZykga2VlcHMgaXRcbiAqICDigJQgdGhlIGFtYmllbnQgdmFsdWUgbmV2ZXIgb3ZlcndyaXRlcyBhIGRlbGliZXJhdGUgb25lLiAqL1xuY29uc3QgbG9nQ29udGV4dEZvcm1hdCA9IHdpbnN0b24uZm9ybWF0KChpbmZvKSA9PiB7XG4gIGlmICghbG9nQ29udGV4dFByb3ZpZGVyKSByZXR1cm4gaW5mbztcbiAgbGV0IGN0eDogTG9nQ29udGV4dCB8IHVuZGVmaW5lZDtcbiAgdHJ5IHtcbiAgICBjdHggPSBsb2dDb250ZXh0UHJvdmlkZXIoKTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIGluZm87XG4gIH1cbiAgaWYgKCFjdHgpIHJldHVybiBpbmZvO1xuICBpZiAoY3R4Lm9yZ0lkICYmIGluZm8ub3JnSWQgPT09IHVuZGVmaW5lZCkgaW5mby5vcmdJZCA9IGN0eC5vcmdJZDtcbiAgaWYgKGN0eC51c2VySWQgJiYgaW5mby51c2VySWQgPT09IHVuZGVmaW5lZCkgaW5mby51c2VySWQgPSBjdHgudXNlcklkO1xuICByZXR1cm4gaW5mbztcbn0pKCk7XG5cbi8vIGBTRU5TSVRJVkVfS0VZX1BBVFRFUk5gIChrZXlzKSBhbmQgYG1hc2tMaW5lYCAoc2VjcmV0LXNoYXBlZCB2YWx1ZXMpIGJvdGggY29tZVxuLy8gZnJvbSBgc2Vuc2l0aXZlLXBhdHRlcm5zLnRzYCwgc28gdGhlIGxvZ2dlciwgcGxhdGZvcm0ncyBsb2ctcmVhZCBwYXRoIGFuZCB0aGVcbi8vIGdlbmVyYXRlZCBwcm9tdGFpbCBgcmVwbGFjZWAgc3RhZ2VzIG1hc2sgdGhlIHNhbWUgdGhpbmdzLiBTZWUgdGhhdCBtb2R1bGUnc1xuLy8gaGVhZGVyIGZvciB3aHkgaW5nZXN0LXRpbWUgbWFza2luZyBpcyB0aGUgYXV0aG9yaXRhdGl2ZSBsYXllci5cblxuZnVuY3Rpb24gcmVkYWN0RGVlcCh2YWx1ZTogdW5rbm93biwgZGVwdGggPSAwKTogdW5rbm93biB7XG4gIC8vIENhcCBkZXB0aCBzbyBhIG1hbGljaW91cyAvIHBhdGhvbG9naWNhbCBjaXJjdWxhciBvYmplY3QgY2FuJ3QgbG9jayB0aGUgbG9nZ2VyLlxuICAvLyBEZWdyYWRlIHRvIGEgcGxhY2Vob2xkZXIgcmF0aGVyIHRoYW4gdGhlIHJhdyBzdWJ0cmVlOiByZXR1cm5pbmcgYHZhbHVlYCBoZXJlXG4gIC8vIHdvdWxkIGxvZyBhIHNlY3JldC1rZXllZCBmaWVsZCBuZXN0ZWQgZGVlcGVyIHRoYW4gdGhlIGNhcCBpbiBjbGVhcnRleHQuXG4gIGlmIChkZXB0aCA+IDYpIHJldHVybiAnW1RSVU5DQVRFRF0nO1xuICBpZiAodmFsdWUgPT0gbnVsbCB8fCB0eXBlb2YgdmFsdWUgIT09ICdvYmplY3QnKSByZXR1cm4gdmFsdWU7XG4gIGlmIChBcnJheS5pc0FycmF5KHZhbHVlKSkgcmV0dXJuIHZhbHVlLm1hcCgodikgPT4gcmVkYWN0RGVlcCh2LCBkZXB0aCArIDEpKTtcbiAgY29uc3Qgb3V0OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHt9O1xuICBmb3IgKGNvbnN0IFtrLCB2XSBvZiBPYmplY3QuZW50cmllcyh2YWx1ZSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPikpIHtcbiAgICBpZiAoU0VOU0lUSVZFX0tFWV9QQVRURVJOLnRlc3QoaykpIHtcbiAgICAgIG91dFtrXSA9IFJFREFDVEVEO1xuICAgIH0gZWxzZSB7XG4gICAgICBvdXRba10gPSByZWRhY3REZWVwKHYsIGRlcHRoICsgMSk7XG4gICAgfVxuICB9XG4gIHJldHVybiBvdXQ7XG59XG5cbi8qKlxuICogUmVkYWN0IHNlbnNpdGl2ZSB2YWx1ZXMgZnJvbSBhbiBBUkJJVFJBUlkgcGF5bG9hZCB1c2luZyB0aGUgc2FtZSBrZXktcGF0dGVyblxuICogcnVsZXMgdGhlIFdpbnN0b24gYHJlZGFjdEZvcm1hdGAgYXBwbGllcyB0byBsb2cgbWV0YWRhdGEuIFVzZSB0aGlzIGZvclxuICogcGF5bG9hZHMgdGhhdCByZWFjaCBhbiBvdXRwdXQgY2hhbm5lbCBPVVRTSURFIHRoZSBsb2dnZXIg4oCUIGUuZy4gYW4gU1NFIGZyYW1lXG4gKiBwdXNoZWQgc3RyYWlnaHQgdG8gYSBjbGllbnQg4oCUIHNvIGEgYHBhc3N3b3JkYC9gdG9rZW5gL2BzZWNyZXRgIGZpZWxkIGlzXG4gKiBtYXNrZWQgdGhlcmUgdG9vLiBBIHRvcC1sZXZlbCBzZW5zaXRpdmUga2V5IGlzIG1hc2tlZDsgbmVzdGVkIG9iamVjdHMvYXJyYXlzXG4gKiBhcmUgd2Fsa2VkIChkZXB0aC1jYXBwZWQpIGV4YWN0bHkgYXMgaW4gdGhlIGxvZ2dlci4gUmV0dXJucyBhIHJlZGFjdGVkIENPUFk7XG4gKiBwcmltaXRpdmVzIHBhc3MgdGhyb3VnaCB1bmNoYW5nZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWRhY3RTZW5zaXRpdmUodmFsdWU6IHVua25vd24pOiB1bmtub3duIHtcbiAgaWYgKHZhbHVlID09IG51bGwgfHwgdHlwZW9mIHZhbHVlICE9PSAnb2JqZWN0JykgcmV0dXJuIHZhbHVlO1xuICByZXR1cm4gcmVkYWN0RGVlcCh2YWx1ZSk7XG59XG5cbi8qKiBXaW5zdG9uIGZvcm1hdCB0aGF0IG1hc2tzIHZhbHVlcyBmb3Igc2Vuc2l0aXZlLWxvb2tpbmcga2V5cyAoUElJIC8gc2VjcmV0cykuXG4gKiBNdXRhdGVzIGBpbmZvYCBpbiBwbGFjZSBzbyB3aW5zdG9uJ3MgaW50ZXJuYWwgU3ltYm9sLWtleWVkIHByb3BlcnRpZXNcbiAqIChgU3ltYm9sLmZvcignbGV2ZWwnKWAsIGBTeW1ib2wuZm9yKCdtZXNzYWdlJylgLCBgU3ltYm9sLmZvcignc3BsYXQnKWApIHN1cnZpdmVcbiAqIOKAlCByZWJ1aWxkaW5nIGEgZnJlc2ggb2JqZWN0IHZpYSBgT2JqZWN0LmVudHJpZXNgL3NwcmVhZCBzaWxlbnRseSBzdHJpcHMgdGhlbSxcbiAqIHdoaWNoIG1ha2VzIHRoZSBDb25zb2xlIHRyYW5zcG9ydCBkcm9wIGV2ZXJ5IGVudHJ5IHdpdGhvdXQgd2FybmluZy4gKi9cbi8qKiBLZXlzIHRoZSByZWRhY3RvciBtdXN0IGxlYXZlIGFsb25lLiBgb3JnSWRgL2B1c2VySWRgIGFyZSBsb2FkLWJlYXJpbmc6IHByb210YWlsXG4gKiAgcm91dGVzIGEgbGluZSB0byBpdHMgTG9raSB0ZW5hbnQgYnkgYG9yZ0lkYCwgc28gcmVkYWN0aW5nIGl0IHdvdWxkIG1pc2ZpbGUgdGhlXG4gKiAgbGluZSBpbnRvIHRoZSBzeXNhZG1pbi1vbmx5IGBfaW5mcmFgIHRlbmFudCBpbnN0ZWFkIG9mIHRoZSBvcmcncy4gTGlzdGVkIGhlcmVcbiAqICAobm90IG1lcmVseSBcImRvZXNuJ3QgbWF0Y2ggdGhlIHBhdHRlcm4gdG9kYXlcIikgc28gYSBmdXR1cmUgcGF0dGVybiBlZGl0IGNhbid0XG4gKiAgc2lsZW50bHkgYnJlYWsgbG9nIHRlbmFuY3kuICovXG5jb25zdCBQUkVTRVJWRURfS0VZUyA9IG5ldyBTZXQoWydsZXZlbCcsICdtZXNzYWdlJywgJ3RpbWVzdGFtcCcsICdzZXJ2aWNlJywgJ3RyYWNlX2lkJywgJ29yZ0lkJywgJ3VzZXJJZCddKTtcbmNvbnN0IHJlZGFjdEZvcm1hdCA9IHdpbnN0b24uZm9ybWF0KChpbmZvKSA9PiB7XG4gIGZvciAoY29uc3Qga2V5IG9mIE9iamVjdC5rZXlzKGluZm8pKSB7XG4gICAgaWYgKFBSRVNFUlZFRF9LRVlTLmhhcyhrZXkpKSBjb250aW51ZTtcbiAgICBpZiAoU0VOU0lUSVZFX0tFWV9QQVRURVJOLnRlc3Qoa2V5KSkge1xuICAgICAgaW5mb1trZXldID0gUkVEQUNURUQ7XG4gICAgfSBlbHNlIHtcbiAgICAgIGluZm9ba2V5XSA9IHJlZGFjdERlZXAoaW5mb1trZXldKTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGluZm87XG59KSgpO1xuXG4vKipcbiAqIFdpbnN0b24gZm9ybWF0IHRoYXQgbWFza3Mgc2VjcmV0LXNoYXBlZCBWQUxVRVMgaW4gdGhlIHJlbmRlcmVkIG1lc3NhZ2UgYW5kIGluXG4gKiBhbnkgc3RyaW5nIG1ldGFkYXRhLlxuICpcbiAqIGByZWRhY3RGb3JtYXRgIGFib3ZlIG9ubHkgbWFza3MgdmFsdWVzIHdob3NlIEtFWSBsb29rcyBzZW5zaXRpdmUuIFRoYXQgbWlzc2VzXG4gKiBhIHNlY3JldCBlbWJlZGRlZCBpbiBmcmVlIHRleHQg4oCUIGBsb2dnZXIuaW5mbygnUE9TVCAveD90b2tlbj1hYmMnKWAg4oCUIHdoaWNoXG4gKiBtYXR0ZXJzIG1vcmUgdGhhbiBpdCBsb29rczogcHJvbXRhaWwncyBgb3V0cHV0OiB7IHNvdXJjZTogbXNnIH1gIHN0YWdlIG1ha2VzXG4gKiB0aGUgbWVzc2FnZSBzdHJpbmcgdGhlIGVudGlyZSBzaGlwcGVkIGxvZyBsaW5lLCBzbyBhbiB1bm1hc2tlZCBtZXNzYWdlIGlzIGFuXG4gKiB1bm1hc2tlZCBsb2cuIE11dGF0ZXMgaW4gcGxhY2UgdG8gcHJlc2VydmUgd2luc3RvbidzIFN5bWJvbC1rZXllZCBpbnRlcm5hbHMsXG4gKiBleGFjdGx5IGFzIGByZWRhY3RGb3JtYXRgIGRvZXMuXG4gKi9cbmNvbnN0IG1hc2tGb3JtYXQgPSB3aW5zdG9uLmZvcm1hdCgoaW5mbykgPT4ge1xuICBpZiAodHlwZW9mIGluZm8ubWVzc2FnZSA9PT0gJ3N0cmluZycpIGluZm8ubWVzc2FnZSA9IG1hc2tMaW5lKGluZm8ubWVzc2FnZSk7XG4gIGZvciAoY29uc3Qga2V5IG9mIE9iamVjdC5rZXlzKGluZm8pKSB7XG4gICAgaWYgKGtleSA9PT0gJ21lc3NhZ2UnKSBjb250aW51ZTtcbiAgICBjb25zdCB2YWx1ZSA9IGluZm9ba2V5XTtcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJykgaW5mb1trZXldID0gbWFza0xpbmUodmFsdWUpO1xuICB9XG4gIHJldHVybiBpbmZvO1xufSkoKTtcblxuLyoqXG4gKiBDcmVhdGUgYSBsb2dnZXIgaW5zdGFuY2UgZm9yIGEgc2VydmljZS5cbiAqXG4gKiBXaGVuIExPR19GT1JNQVQ9anNvbiAoZGVmYXVsdCksIG91dHB1dHMgc3RydWN0dXJlZCBKU09OIGZvciBMb2tpIGluZ2VzdGlvbjpcbiAqICAge1wibGV2ZWxcIjpcImluZm9cIixcIm1lc3NhZ2VcIjpcIlNlcnZlciBzdGFydGVkXCIsXCJzZXJ2aWNlXCI6XCJwaXBlbGluZVwiLFwidGltZXN0YW1wXCI6XCIuLi5cIn1cbiAqXG4gKiBXaGVuIExPR19GT1JNQVQ9dGV4dCwgb3V0cHV0cyBjb2xvcml6ZWQgaHVtYW4tcmVhZGFibGUgZm9ybWF0OlxuICogICAyMDI2LTAyLTEzVDEwOjMwOjAwLjAwMFogaW5mbyBbcGlwZWxpbmVdIFNlcnZlciBzdGFydGVkXG4gKlxuICogQHBhcmFtIHNlcnZpY2VOYW1lIC0gTmFtZSBvZiB0aGUgc2VydmljZSBmb3IgbG9nIGlkZW50aWZpY2F0aW9uXG4gKiBAcmV0dXJucyBDb25maWd1cmVkIFdpbnN0b24gbG9nZ2VyIGluc3RhbmNlXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGltcG9ydCB7IGNyZWF0ZUxvZ2dlciB9IGZyb20gJ0BwaXBlbGluZS1idWlsZGVyL2FwaS1jb3JlJztcbiAqXG4gKiBjb25zdCBsb2dnZXIgPSBjcmVhdGVMb2dnZXIoJ2dldC1wbHVnaW4nKTtcbiAqIGxvZ2dlci5pbmZvKCdTZXJ2ZXIgc3RhcnRlZCcsIHsgcG9ydDogMzAwMCB9KTtcbiAqIGxvZ2dlci5lcnJvcignRGF0YWJhc2UgZXJyb3InLCB7IGVycm9yOiBlcnIubWVzc2FnZSB9KTtcbiAqIGBgYFxuICovXG4vKiogVGhlIGxvZ2dlciBgY3JlYXRlTG9nZ2VyYCByZXR1cm5zLiBFeHBvcnRlZCBzbyBjb25zdW1lcnMgY2FuIGFubm90YXRlIGV4cG9ydGVkXG4gKiAgbG9nZ2VycyB3aXRob3V0IGRlcGVuZGluZyBvbiB3aW5zdG9uIHRoZW1zZWx2ZXMuICovXG5leHBvcnQgdHlwZSBMb2dnZXIgPSB3aW5zdG9uLkxvZ2dlcjtcblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUxvZ2dlcihzZXJ2aWNlTmFtZTogc3RyaW5nKTogTG9nZ2VyIHtcbiAgY29uc3QgbG9nTGV2ZWwgPSBwcm9jZXNzLmVudi5MT0dfTEVWRUwgfHwgJ2luZm8nO1xuICBjb25zdCBsb2dGb3JtYXQgPSBwcm9jZXNzLmVudi5MT0dfRk9STUFUIHx8ICdqc29uJztcbiAgaWYgKGxvZ0Zvcm1hdCAhPT0gJ2pzb24nICYmIGxvZ0Zvcm1hdCAhPT0gJ3RleHQnKSB7XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWNvbnNvbGUgLS0gc3RhcnR1cCB3YXJuaW5nIGJlZm9yZSBsb2dnZXIgaXMgYXZhaWxhYmxlXG4gICAgY29uc29sZS53YXJuKGBJbnZhbGlkIExPR19GT1JNQVQ9XCIke2xvZ0Zvcm1hdH1cIiwgZXhwZWN0ZWQgXCJqc29uXCIgb3IgXCJ0ZXh0XCIuIERlZmF1bHRpbmcgdG8gXCJqc29uXCIuYCk7XG4gIH1cbiAgY29uc3QgdXNlSnNvbiA9IGxvZ0Zvcm1hdCAhPT0gJ3RleHQnO1xuXG4gIC8vIE9yZGVyIG1hdHRlcnM6IHJlZGFjdCBCRUZPUkUgc2VyaWFsaXphdGlvbiBzbyBtYXNrZWQga2V5cyBuZXZlciByZWFjaFxuICAvLyB0aGUgb3V0cHV0LiB0cmFjZV9pZCBhbmQgdGhlIG9yZy91c2VyIGNvbnRleHQgYXJlIHN0YW1wZWQgZmlyc3Qgc28gdGhleVxuICAvLyBzdXJ2aXZlIHJlZGFjdGlvbiAoYm90aCBhcmUgaW4gUFJFU0VSVkVEX0tFWVMpLCB0aGVuIGBtYXNrRm9ybWF0YCBzY3J1YnNcbiAgLy8gc2VjcmV0LXNoYXBlZCBWQUxVRVMgb3V0IG9mIHRoZSByZW5kZXJlZCBtZXNzYWdlIOKAlCB0aGUga2V5LWJhc2VkXG4gIC8vIGByZWRhY3RGb3JtYXRgIG9ubHkgY292ZXJzIG1ldGFkYXRhIGtleXMsIGFuZCBhZnRlciBwcm9tdGFpbCdzXG4gIC8vIGBvdXRwdXQ6IHNvdXJjZTogbXNnYCByZXdyaXRlIHRoZSBzaGlwcGVkIGxpbmUgSVMgdGhlIG1lc3NhZ2Ugc3RyaW5nLlxuICBjb25zdCBiYXNlRm9ybWF0cyA9IFtcbiAgICBlcnJvcnMoeyBzdGFjazogdHJ1ZSB9KSxcbiAgICB0aW1lc3RhbXAoeyBmb3JtYXQ6ICdZWVlZLU1NLUREVEhIOm1tOnNzLlNTU1onIH0pLFxuICAgIHRyYWNlSWRGb3JtYXQsXG4gICAgbG9nQ29udGV4dEZvcm1hdCxcbiAgICByZWRhY3RGb3JtYXQsXG4gICAgbWFza0Zvcm1hdCxcbiAgXTtcblxuICBpZiAodXNlSnNvbikge1xuICAgIHJldHVybiB3aW5zdG9uLmNyZWF0ZUxvZ2dlcih7XG4gICAgICBsZXZlbDogbG9nTGV2ZWwsXG4gICAgICBkZWZhdWx0TWV0YTogeyBzZXJ2aWNlOiBzZXJ2aWNlTmFtZSB9LFxuICAgICAgZm9ybWF0OiBjb21iaW5lKC4uLmJhc2VGb3JtYXRzLCBqc29uKCkpLFxuICAgICAgdHJhbnNwb3J0czogW25ldyB3aW5zdG9uLnRyYW5zcG9ydHMuQ29uc29sZSgpXSxcbiAgICB9KTtcbiAgfVxuXG4gIHJldHVybiB3aW5zdG9uLmNyZWF0ZUxvZ2dlcih7XG4gICAgbGV2ZWw6IGxvZ0xldmVsLFxuICAgIGRlZmF1bHRNZXRhOiB7IHNlcnZpY2U6IHNlcnZpY2VOYW1lIH0sXG4gICAgZm9ybWF0OiBjb21iaW5lKC4uLmJhc2VGb3JtYXRzKSxcbiAgICB0cmFuc3BvcnRzOiBbXG4gICAgICBuZXcgd2luc3Rvbi50cmFuc3BvcnRzLkNvbnNvbGUoe1xuICAgICAgICBmb3JtYXQ6IGNvbWJpbmUoY29sb3JpemUoKSwgY29uc29sZUZvcm1hdCksXG4gICAgICB9KSxcbiAgICBdLFxuICB9KTtcbn1cblxuLyoqXG4gKiBEZWZhdWx0IGxvZ2dlciBpbnN0YW5jZSAoc2VydmljZSBuYW1lIGZyb20gU0VSVklDRV9OQU1FIGVudiB2YXIgb3IgJ2FwaScpLlxuICovXG5leHBvcnQgY29uc3QgbG9nZ2VyID0gY3JlYXRlTG9nZ2VyKHByb2Nlc3MuZW52LlNFUlZJQ0VfTkFNRSB8fCAnYXBpJyk7XG5cbmV4cG9ydCBkZWZhdWx0IGxvZ2dlcjtcbiJdfQ==
@@ -67,7 +67,9 @@ export declare class KmsKeyProvider implements KeyProvider {
67
67
  * one. Triggers lazy initialization on first access, same as the internal
68
68
  * callers below. */
69
69
  export declare function getDefaultKeyProvider(): KeyProvider;
70
- /** Reset the cached default provider for tests that mutate `process.env`. */
70
+ /** Read the rotation-fallback provider (null outside a master-key rotation). */
71
+ export declare function getPreviousKeyProvider(): KeyProvider | null;
72
+ /** Reset the cached default (and previous) provider for tests that mutate `process.env`. */
71
73
  export declare function resetDefaultKeyProvider(): void;
72
74
  /** Replace the default provider services that opt into KMS call this
73
75
  * once at startup with a warmed-up `KmsKeyProvider`. */
@@ -181,8 +183,11 @@ export declare function encryptSecret(plaintext: string, orgId: string, provider
181
183
  *
182
184
  * Callers handle the throw masking the failure as `null` would hide
183
185
  * silent corruption / wrong-org reads.
186
+ *
187
+ * `previous` (default: `SECRET_ENCRYPTION_KEY_PREVIOUS`, when set) is tried
188
+ * only after the primary key fails, and only for kid-less blobs.
184
189
  */
185
- export declare function decryptSecret(blob: EncryptedBlob, orgId: string, provider?: KeyProvider): Promise<string>;
190
+ export declare function decryptSecret(blob: EncryptedBlob, orgId: string, provider?: KeyProvider, previous?: KeyProvider | null): Promise<string>;
186
191
  /**
187
192
  * Type guard handy for model layers that hold a column whose value may be
188
193
  * either a clear-text string (legacy / unencrypted) OR an encrypted blob