@pipeline-builder/api-server 4.1.15 → 4.1.16

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.
@@ -1,6 +1,6 @@
1
1
  // Copyright 2026 Pipeline Builder Contributors
2
2
  // SPDX-License-Identifier: Apache-2.0
3
- import { createLogger } from '@pipeline-builder/api-core';
3
+ import { createLogger, envInt } from '@pipeline-builder/api-core';
4
4
  const logger = createLogger('mongo-connect');
5
5
  /**
6
6
  * Connect to MongoDB with sensible production-ready pool defaults and
@@ -32,10 +32,10 @@ export async function connectMongo(mongoose, uri) {
32
32
  logger.info('MongoDB reconnected');
33
33
  });
34
34
  }
35
- const maxPoolSize = parseInt(process.env.MONGO_MAX_POOL || '20', 10);
36
- const minPoolSize = parseInt(process.env.MONGO_MIN_POOL || '2', 10);
37
- const serverSelectionTimeoutMS = parseInt(process.env.MONGO_SERVER_SELECTION_MS || '5000', 10);
35
+ const maxPoolSize = envInt('MONGO_MAX_POOL', 20, { min: 1 });
36
+ const minPoolSize = envInt('MONGO_MIN_POOL', 2, { min: 0 });
37
+ const serverSelectionTimeoutMS = envInt('MONGO_SERVER_SELECTION_MS', 5000, { min: 1 });
38
38
  await mongoose.connect(uri, { maxPoolSize, minPoolSize, serverSelectionTimeoutMS });
39
39
  logger.info('MongoDB connection established', { maxPoolSize, minPoolSize, serverSelectionTimeoutMS });
40
40
  }
41
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9uZ28tY29ubmVjdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hcGkvbW9uZ28tY29ubmVjdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUUxRCxNQUFNLE1BQU0sR0FBRyxZQUFZLENBQUMsZUFBZSxDQUFDLENBQUM7QUFvQjdDOzs7Ozs7Ozs7OztHQVdHO0FBQ0gsSUFBSSxhQUFhLEdBQUcsS0FBSyxDQUFDO0FBRTFCLE1BQU0sQ0FBQyxLQUFLLFVBQVUsWUFBWSxDQUFDLFFBQXNCLEVBQUUsR0FBVztJQUNwRSxRQUFRLENBQUMsR0FBRyxDQUFDLGFBQWEsRUFBRSxJQUFJLENBQUMsQ0FBQztJQUVsQywwRUFBMEU7SUFDMUUsd0VBQXdFO0lBQ3hFLHdEQUF3RDtJQUN4RCxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7UUFDbkIsYUFBYSxHQUFHLElBQUksQ0FBQztRQUVyQixRQUFRLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxHQUFHLEVBQUUsRUFBRTtZQUN0QyxNQUFNLENBQUMsS0FBSyxDQUFDLDBCQUEwQixFQUFFLEVBQUUsS0FBSyxFQUFFLEdBQUcsRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUFDO1FBQ3BFLENBQUMsQ0FBQyxDQUFDO1FBRUgsUUFBUSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUMsY0FBYyxFQUFFLEdBQUcsRUFBRTtZQUMxQyxNQUFNLENBQUMsSUFBSSxDQUFDLHNCQUFzQixDQUFDLENBQUM7UUFDdEMsQ0FBQyxDQUFDLENBQUM7UUFFSCxRQUFRLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQyxhQUFhLEVBQUUsR0FBRyxFQUFFO1lBQ3pDLE1BQU0sQ0FBQyxJQUFJLENBQUMscUJBQXFCLENBQUMsQ0FBQztRQUNyQyxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRCxNQUFNLFdBQVcsR0FBRyxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxjQUFjLElBQUksSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQ3JFLE1BQU0sV0FBVyxHQUFHLFFBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLGNBQWMsSUFBSSxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDcEUsTUFBTSx3QkFBd0IsR0FBRyxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyx5QkFBeUIsSUFBSSxNQUFNLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFFL0YsTUFBTSxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxFQUFFLFdBQVcsRUFBRSxXQUFXLEVBQUUsd0JBQXdCLEVBQUUsQ0FBQyxDQUFDO0lBQ3BGLE1BQU0sQ0FBQyxJQUFJLENBQUMsZ0NBQWdDLEVBQUUsRUFBRSxXQUFXLEVBQUUsV0FBVyxFQUFFLHdCQUF3QixFQUFFLENBQUMsQ0FBQztBQUN4RyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCB7IGNyZWF0ZUxvZ2dlciB9IGZyb20gJ0BwaXBlbGluZS1idWlsZGVyL2FwaS1jb3JlJztcblxuY29uc3QgbG9nZ2VyID0gY3JlYXRlTG9nZ2VyKCdtb25nby1jb25uZWN0Jyk7XG5cbi8qKlxuICogTWluaW1hbCBzaGFwZSBvZiBtb25nb29zZSBhY2NlcHRlZCBieSBgY29ubmVjdE1vbmdvYC4gUGFzc2luZyB0aGUgcmVhbFxuICogbW9uZ29vc2Ugb2JqZWN0IHNhdGlzZmllcyBpdDsgYXBpLXNlcnZlciB0YWtlcyBtb25nb29zZSBhcyBhIHBhcmFtZXRlclxuICogKGRlcGVuZGVuY3kgaW5qZWN0aW9uKSBzbyBpdCBkb2Vzbid0IGhhdmUgdG8gZGVjbGFyZSBtb25nb29zZSBhcyBhXG4gKiBkZXBlbmRlbmN5IGl0c2VsZi5cbiAqL1xuaW50ZXJmYWNlIE1vbmdvb3NlTGlrZSB7XG4gIHNldChvcHRpb246IHN0cmluZywgdmFsdWU6IHVua25vd24pOiB1bmtub3duO1xuICBjb25uZWN0aW9uOiB7XG4gICAgb24oZXZlbnQ6IHN0cmluZywgbGlzdGVuZXI6IChlcnI/OiBFcnJvcikgPT4gdm9pZCk6IHVua25vd247XG4gIH07XG4gIGNvbm5lY3QodXJpOiBzdHJpbmcsIG9wdGlvbnM6IHtcbiAgICBtYXhQb29sU2l6ZTogbnVtYmVyO1xuICAgIG1pblBvb2xTaXplOiBudW1iZXI7XG4gICAgc2VydmVyU2VsZWN0aW9uVGltZW91dE1TOiBudW1iZXI7XG4gIH0pOiBQcm9taXNlPHVua25vd24+O1xufVxuXG4vKipcbiAqIENvbm5lY3QgdG8gTW9uZ29EQiB3aXRoIHNlbnNpYmxlIHByb2R1Y3Rpb24tcmVhZHkgcG9vbCBkZWZhdWx0cyBhbmRcbiAqIHN0YW5kYXJkIGV2ZW50LWhhbmRsZXIgd2lyaW5nIChlcnJvciAvIGRpc2Nvbm5lY3RlZCAvIHJlY29ubmVjdGVkKS5cbiAqXG4gKiBQb29sIHNpemluZyBpcyByZWFkIGZyb20gZW52IChgTU9OR09fTUFYX1BPT0xgLCBgTU9OR09fTUlOX1BPT0xgLFxuICogYE1PTkdPX1NFUlZFUl9TRUxFQ1RJT05fTVNgKS4gV2l0aG91dCB0aGVzZSB0aGUgZHJpdmVyIGRlZmF1bHQgb2ZcbiAqIGBtYXhQb29sU2l6ZT0xMDBgIGxldHMgYSBidXJzdCBleGhhdXN0IE1vbmdvJ3MgY29ubmVjdGlvbiBjZWlsaW5nXG4gKiBhY3Jvc3MgcmVwbGljYXMuIERlZmF1bHRzOiAyMCBtYXggLyAyIG1pbiAvIDVzIHNlcnZlciBzZWxlY3Rpb24uXG4gKlxuICogUGFzcyB0aGUgc2VydmljZSdzIG93biBtb25nb29zZSBpbnN0YW5jZSDigJQgYXBpLXNlcnZlciBkb2Vzbid0IGJ1bmRsZVxuICogbW9uZ29vc2UgaXRzZWxmLlxuICovXG5sZXQgaGFuZGxlcnNXaXJlZCA9IGZhbHNlO1xuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY29ubmVjdE1vbmdvKG1vbmdvb3NlOiBNb25nb29zZUxpa2UsIHVyaTogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gIG1vbmdvb3NlLnNldCgnc3RyaWN0UXVlcnknLCB0cnVlKTtcblxuICAvLyBXaXJlIHRoZSBjb25uZWN0aW9uIGV2ZW50IGhhbmRsZXJzIGV4YWN0bHkgb25jZS4gVGhlIHN0YXJ0dXAgc3VwZXJ2aXNvclxuICAvLyBtYXkgY2FsbCBjb25uZWN0TW9uZ28gcmVwZWF0ZWRseSAocmV0cnlpbmcgdW50aWwgTW9uZ28gaXMgcmVhY2hhYmxlKTtcbiAgLy8gcmUtcmVnaXN0ZXJpbmcgb24gZXZlcnkgYXR0ZW1wdCB3b3VsZCBsZWFrIGxpc3RlbmVycy5cbiAgaWYgKCFoYW5kbGVyc1dpcmVkKSB7XG4gICAgaGFuZGxlcnNXaXJlZCA9IHRydWU7XG5cbiAgICBtb25nb29zZS5jb25uZWN0aW9uLm9uKCdlcnJvcicsIChlcnIpID0+IHtcbiAgICAgIGxvZ2dlci5lcnJvcignTW9uZ29EQiBjb25uZWN0aW9uIGVycm9yJywgeyBlcnJvcjogZXJyPy5tZXNzYWdlIH0pO1xuICAgIH0pO1xuXG4gICAgbW9uZ29vc2UuY29ubmVjdGlvbi5vbignZGlzY29ubmVjdGVkJywgKCkgPT4ge1xuICAgICAgbG9nZ2VyLndhcm4oJ01vbmdvREIgZGlzY29ubmVjdGVkJyk7XG4gICAgfSk7XG5cbiAgICBtb25nb29zZS5jb25uZWN0aW9uLm9uKCdyZWNvbm5lY3RlZCcsICgpID0+IHtcbiAgICAgIGxvZ2dlci5pbmZvKCdNb25nb0RCIHJlY29ubmVjdGVkJyk7XG4gICAgfSk7XG4gIH1cblxuICBjb25zdCBtYXhQb29sU2l6ZSA9IHBhcnNlSW50KHByb2Nlc3MuZW52Lk1PTkdPX01BWF9QT09MIHx8ICcyMCcsIDEwKTtcbiAgY29uc3QgbWluUG9vbFNpemUgPSBwYXJzZUludChwcm9jZXNzLmVudi5NT05HT19NSU5fUE9PTCB8fCAnMicsIDEwKTtcbiAgY29uc3Qgc2VydmVyU2VsZWN0aW9uVGltZW91dE1TID0gcGFyc2VJbnQocHJvY2Vzcy5lbnYuTU9OR09fU0VSVkVSX1NFTEVDVElPTl9NUyB8fCAnNTAwMCcsIDEwKTtcblxuICBhd2FpdCBtb25nb29zZS5jb25uZWN0KHVyaSwgeyBtYXhQb29sU2l6ZSwgbWluUG9vbFNpemUsIHNlcnZlclNlbGVjdGlvblRpbWVvdXRNUyB9KTtcbiAgbG9nZ2VyLmluZm8oJ01vbmdvREIgY29ubmVjdGlvbiBlc3RhYmxpc2hlZCcsIHsgbWF4UG9vbFNpemUsIG1pblBvb2xTaXplLCBzZXJ2ZXJTZWxlY3Rpb25UaW1lb3V0TVMgfSk7XG59XG4iXX0=
41
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9uZ28tY29ubmVjdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hcGkvbW9uZ28tY29ubmVjdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFFbEUsTUFBTSxNQUFNLEdBQUcsWUFBWSxDQUFDLGVBQWUsQ0FBQyxDQUFDO0FBb0I3Qzs7Ozs7Ozs7Ozs7R0FXRztBQUNILElBQUksYUFBYSxHQUFHLEtBQUssQ0FBQztBQUUxQixNQUFNLENBQUMsS0FBSyxVQUFVLFlBQVksQ0FBQyxRQUFzQixFQUFFLEdBQVc7SUFDcEUsUUFBUSxDQUFDLEdBQUcsQ0FBQyxhQUFhLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFFbEMsMEVBQTBFO0lBQzFFLHdFQUF3RTtJQUN4RSx3REFBd0Q7SUFDeEQsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO1FBQ25CLGFBQWEsR0FBRyxJQUFJLENBQUM7UUFFckIsUUFBUSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLENBQUMsR0FBRyxFQUFFLEVBQUU7WUFDdEMsTUFBTSxDQUFDLEtBQUssQ0FBQywwQkFBMEIsRUFBRSxFQUFFLEtBQUssRUFBRSxHQUFHLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztRQUNwRSxDQUFDLENBQUMsQ0FBQztRQUVILFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLGNBQWMsRUFBRSxHQUFHLEVBQUU7WUFDMUMsTUFBTSxDQUFDLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxDQUFDO1FBQ3RDLENBQUMsQ0FBQyxDQUFDO1FBRUgsUUFBUSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUMsYUFBYSxFQUFFLEdBQUcsRUFBRTtZQUN6QyxNQUFNLENBQUMsSUFBSSxDQUFDLHFCQUFxQixDQUFDLENBQUM7UUFDckMsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQsTUFBTSxXQUFXLEdBQUcsTUFBTSxDQUFDLGdCQUFnQixFQUFFLEVBQUUsRUFBRSxFQUFFLEdBQUcsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzdELE1BQU0sV0FBVyxHQUFHLE1BQU0sQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDLEVBQUUsRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUM1RCxNQUFNLHdCQUF3QixHQUFHLE1BQU0sQ0FBQywyQkFBMkIsRUFBRSxJQUFJLEVBQUUsRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUV2RixNQUFNLFFBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLEVBQUUsV0FBVyxFQUFFLFdBQVcsRUFBRSx3QkFBd0IsRUFBRSxDQUFDLENBQUM7SUFDcEYsTUFBTSxDQUFDLElBQUksQ0FBQyxnQ0FBZ0MsRUFBRSxFQUFFLFdBQVcsRUFBRSxXQUFXLEVBQUUsd0JBQXdCLEVBQUUsQ0FBQyxDQUFDO0FBQ3hHLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuaW1wb3J0IHsgY3JlYXRlTG9nZ2VyLCBlbnZJbnQgfSBmcm9tICdAcGlwZWxpbmUtYnVpbGRlci9hcGktY29yZSc7XG5cbmNvbnN0IGxvZ2dlciA9IGNyZWF0ZUxvZ2dlcignbW9uZ28tY29ubmVjdCcpO1xuXG4vKipcbiAqIE1pbmltYWwgc2hhcGUgb2YgbW9uZ29vc2UgYWNjZXB0ZWQgYnkgYGNvbm5lY3RNb25nb2AuIFBhc3NpbmcgdGhlIHJlYWxcbiAqIG1vbmdvb3NlIG9iamVjdCBzYXRpc2ZpZXMgaXQ7IGFwaS1zZXJ2ZXIgdGFrZXMgbW9uZ29vc2UgYXMgYSBwYXJhbWV0ZXJcbiAqIChkZXBlbmRlbmN5IGluamVjdGlvbikgc28gaXQgZG9lc24ndCBoYXZlIHRvIGRlY2xhcmUgbW9uZ29vc2UgYXMgYVxuICogZGVwZW5kZW5jeSBpdHNlbGYuXG4gKi9cbmludGVyZmFjZSBNb25nb29zZUxpa2Uge1xuICBzZXQob3B0aW9uOiBzdHJpbmcsIHZhbHVlOiB1bmtub3duKTogdW5rbm93bjtcbiAgY29ubmVjdGlvbjoge1xuICAgIG9uKGV2ZW50OiBzdHJpbmcsIGxpc3RlbmVyOiAoZXJyPzogRXJyb3IpID0+IHZvaWQpOiB1bmtub3duO1xuICB9O1xuICBjb25uZWN0KHVyaTogc3RyaW5nLCBvcHRpb25zOiB7XG4gICAgbWF4UG9vbFNpemU6IG51bWJlcjtcbiAgICBtaW5Qb29sU2l6ZTogbnVtYmVyO1xuICAgIHNlcnZlclNlbGVjdGlvblRpbWVvdXRNUzogbnVtYmVyO1xuICB9KTogUHJvbWlzZTx1bmtub3duPjtcbn1cblxuLyoqXG4gKiBDb25uZWN0IHRvIE1vbmdvREIgd2l0aCBzZW5zaWJsZSBwcm9kdWN0aW9uLXJlYWR5IHBvb2wgZGVmYXVsdHMgYW5kXG4gKiBzdGFuZGFyZCBldmVudC1oYW5kbGVyIHdpcmluZyAoZXJyb3IgLyBkaXNjb25uZWN0ZWQgLyByZWNvbm5lY3RlZCkuXG4gKlxuICogUG9vbCBzaXppbmcgaXMgcmVhZCBmcm9tIGVudiAoYE1PTkdPX01BWF9QT09MYCwgYE1PTkdPX01JTl9QT09MYCxcbiAqIGBNT05HT19TRVJWRVJfU0VMRUNUSU9OX01TYCkuIFdpdGhvdXQgdGhlc2UgdGhlIGRyaXZlciBkZWZhdWx0IG9mXG4gKiBgbWF4UG9vbFNpemU9MTAwYCBsZXRzIGEgYnVyc3QgZXhoYXVzdCBNb25nbydzIGNvbm5lY3Rpb24gY2VpbGluZ1xuICogYWNyb3NzIHJlcGxpY2FzLiBEZWZhdWx0czogMjAgbWF4IC8gMiBtaW4gLyA1cyBzZXJ2ZXIgc2VsZWN0aW9uLlxuICpcbiAqIFBhc3MgdGhlIHNlcnZpY2UncyBvd24gbW9uZ29vc2UgaW5zdGFuY2Ug4oCUIGFwaS1zZXJ2ZXIgZG9lc24ndCBidW5kbGVcbiAqIG1vbmdvb3NlIGl0c2VsZi5cbiAqL1xubGV0IGhhbmRsZXJzV2lyZWQgPSBmYWxzZTtcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNvbm5lY3RNb25nbyhtb25nb29zZTogTW9uZ29vc2VMaWtlLCB1cmk6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICBtb25nb29zZS5zZXQoJ3N0cmljdFF1ZXJ5JywgdHJ1ZSk7XG5cbiAgLy8gV2lyZSB0aGUgY29ubmVjdGlvbiBldmVudCBoYW5kbGVycyBleGFjdGx5IG9uY2UuIFRoZSBzdGFydHVwIHN1cGVydmlzb3JcbiAgLy8gbWF5IGNhbGwgY29ubmVjdE1vbmdvIHJlcGVhdGVkbHkgKHJldHJ5aW5nIHVudGlsIE1vbmdvIGlzIHJlYWNoYWJsZSk7XG4gIC8vIHJlLXJlZ2lzdGVyaW5nIG9uIGV2ZXJ5IGF0dGVtcHQgd291bGQgbGVhayBsaXN0ZW5lcnMuXG4gIGlmICghaGFuZGxlcnNXaXJlZCkge1xuICAgIGhhbmRsZXJzV2lyZWQgPSB0cnVlO1xuXG4gICAgbW9uZ29vc2UuY29ubmVjdGlvbi5vbignZXJyb3InLCAoZXJyKSA9PiB7XG4gICAgICBsb2dnZXIuZXJyb3IoJ01vbmdvREIgY29ubmVjdGlvbiBlcnJvcicsIHsgZXJyb3I6IGVycj8ubWVzc2FnZSB9KTtcbiAgICB9KTtcblxuICAgIG1vbmdvb3NlLmNvbm5lY3Rpb24ub24oJ2Rpc2Nvbm5lY3RlZCcsICgpID0+IHtcbiAgICAgIGxvZ2dlci53YXJuKCdNb25nb0RCIGRpc2Nvbm5lY3RlZCcpO1xuICAgIH0pO1xuXG4gICAgbW9uZ29vc2UuY29ubmVjdGlvbi5vbigncmVjb25uZWN0ZWQnLCAoKSA9PiB7XG4gICAgICBsb2dnZXIuaW5mbygnTW9uZ29EQiByZWNvbm5lY3RlZCcpO1xuICAgIH0pO1xuICB9XG5cbiAgY29uc3QgbWF4UG9vbFNpemUgPSBlbnZJbnQoJ01PTkdPX01BWF9QT09MJywgMjAsIHsgbWluOiAxIH0pO1xuICBjb25zdCBtaW5Qb29sU2l6ZSA9IGVudkludCgnTU9OR09fTUlOX1BPT0wnLCAyLCB7IG1pbjogMCB9KTtcbiAgY29uc3Qgc2VydmVyU2VsZWN0aW9uVGltZW91dE1TID0gZW52SW50KCdNT05HT19TRVJWRVJfU0VMRUNUSU9OX01TJywgNTAwMCwgeyBtaW46IDEgfSk7XG5cbiAgYXdhaXQgbW9uZ29vc2UuY29ubmVjdCh1cmksIHsgbWF4UG9vbFNpemUsIG1pblBvb2xTaXplLCBzZXJ2ZXJTZWxlY3Rpb25UaW1lb3V0TVMgfSk7XG4gIGxvZ2dlci5pbmZvKCdNb25nb0RCIGNvbm5lY3Rpb24gZXN0YWJsaXNoZWQnLCB7IG1heFBvb2xTaXplLCBtaW5Qb29sU2l6ZSwgc2VydmVyU2VsZWN0aW9uVGltZW91dE1TIH0pO1xufVxuIl19
@@ -0,0 +1,52 @@
1
+ import { type QuotaReserveResult, type QuotaService, type QuotaType } from '@pipeline-builder/api-core';
2
+ import type { Response } from 'express';
3
+ /** The reserved quota slot, handed to the guarded body. */
4
+ export interface QuotaSlot {
5
+ /** Minted service token the reservation used — reuse it for the body's own S2S calls. */
6
+ readonly serviceAuth: string;
7
+ readonly reservation: QuotaReserveResult;
8
+ /**
9
+ * The reserved resource has been consumed (e.g. the AI provider started
10
+ * responding). From here on a failure KEEPS the slot — the cost was incurred.
11
+ */
12
+ markConsumed(): void;
13
+ /** Give the slot back now. Idempotent: refunds at most once. */
14
+ refund(): void;
15
+ }
16
+ export interface QuotaReservationOptions {
17
+ quotaService: QuotaService;
18
+ orgId: string;
19
+ type: QuotaType;
20
+ /** Signer of the quota service token. Defaults to this process (`SERVICE_NAME`). */
21
+ serviceName?: string;
22
+ logWarn: (message: string, data?: unknown) => void;
23
+ /** When set, a denied reservation is answered on it (429, or 503 when unconfirmable). */
24
+ res?: Response;
25
+ }
26
+ export type QuotaReservationOutcome<T> = {
27
+ status: 'denied';
28
+ reservation: QuotaReserveResult;
29
+ } | {
30
+ status: 'done';
31
+ value: T;
32
+ }
33
+ /** Only with an `onError` handler: the body threw and the handler answered. */
34
+ | {
35
+ status: 'failed';
36
+ error: unknown;
37
+ };
38
+ /**
39
+ * Reserve one quota slot, run `body`, and settle the slot by ONE rule:
40
+ * keep it once the resource was consumed; refund it if the body fails first.
41
+ *
42
+ * - Denied → `{ status: 'denied' }` (answered on `res` when given); `body` never runs.
43
+ * - `body` resolves → the slot is kept (unless `body` called `slot.refund()`).
44
+ * - `body` throws → refunded unless consumed — marked via `slot.markConsumed()`
45
+ * or signalled by the error itself carrying `providerContacted === true`
46
+ * (an AI round-trip that completed but produced nothing usable). The error is
47
+ * then passed to `onError`, or rethrown when there is none.
48
+ *
49
+ * The reserve and refund authenticate with a minted service token, never the
50
+ * end-user bearer: the quota increment endpoint rejects user principals.
51
+ */
52
+ export declare function withQuotaReservation<T>(opts: QuotaReservationOptions, body: (slot: QuotaSlot) => Promise<T>, onError?: (error: unknown) => void | Promise<void>): Promise<QuotaReservationOutcome<T>>;
@@ -0,0 +1,56 @@
1
+ // Copyright 2026 Pipeline Builder Contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { decrementQuota, getServiceAuthHeader, reserveQuota, sendQuotaReserveDenied, serviceIdentity, } from '@pipeline-builder/api-core';
4
+ /**
5
+ * Reserve one quota slot, run `body`, and settle the slot by ONE rule:
6
+ * keep it once the resource was consumed; refund it if the body fails first.
7
+ *
8
+ * - Denied → `{ status: 'denied' }` (answered on `res` when given); `body` never runs.
9
+ * - `body` resolves → the slot is kept (unless `body` called `slot.refund()`).
10
+ * - `body` throws → refunded unless consumed — marked via `slot.markConsumed()`
11
+ * or signalled by the error itself carrying `providerContacted === true`
12
+ * (an AI round-trip that completed but produced nothing usable). The error is
13
+ * then passed to `onError`, or rethrown when there is none.
14
+ *
15
+ * The reserve and refund authenticate with a minted service token, never the
16
+ * end-user bearer: the quota increment endpoint rejects user principals.
17
+ */
18
+ export async function withQuotaReservation(opts, body, onError) {
19
+ const { quotaService, orgId, type, logWarn } = opts;
20
+ const serviceAuth = getServiceAuthHeader({ serviceName: opts.serviceName ?? serviceIdentity(), orgId, role: 'member' });
21
+ // Reserve atomically BEFORE any work: two concurrent requests at the limit
22
+ // can't both pass.
23
+ const reservation = await reserveQuota(quotaService, orgId, type, serviceAuth);
24
+ if (reservation.exceeded) {
25
+ if (opts.res)
26
+ sendQuotaReserveDenied(opts.res, type, reservation);
27
+ return { status: 'denied', reservation };
28
+ }
29
+ let consumed = false;
30
+ let refunded = false;
31
+ const slot = {
32
+ serviceAuth,
33
+ reservation,
34
+ markConsumed: () => { consumed = true; },
35
+ refund: () => {
36
+ if (refunded)
37
+ return;
38
+ refunded = true;
39
+ // The reserved resetAt keeps a period rollover from being double-charged.
40
+ decrementQuota(quotaService, orgId, type, serviceAuth, logWarn, 1, reservation.quota.resetAt);
41
+ },
42
+ };
43
+ try {
44
+ return { status: 'done', value: await body(slot) };
45
+ }
46
+ catch (error) {
47
+ const errorSaysConsumed = error?.providerContacted === true;
48
+ if (!consumed && !errorSaysConsumed)
49
+ slot.refund();
50
+ if (!onError)
51
+ throw error;
52
+ await onError(error);
53
+ return { status: 'failed', error };
54
+ }
55
+ }
56
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicXVvdGEtcmVzZXJ2YXRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYXBpL3F1b3RhLXJlc2VydmF0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFFdEMsT0FBTyxFQUNMLGNBQWMsRUFDZCxvQkFBb0IsRUFDcEIsWUFBWSxFQUNaLHNCQUFzQixFQUN0QixlQUFlLEdBSWhCLE1BQU0sNEJBQTRCLENBQUM7QUFrQ3BDOzs7Ozs7Ozs7Ozs7O0dBYUc7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLG9CQUFvQixDQUN4QyxJQUE2QixFQUM3QixJQUFxQyxFQUNyQyxPQUFrRDtJQUVsRCxNQUFNLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLEdBQUcsSUFBSSxDQUFDO0lBQ3BELE1BQU0sV0FBVyxHQUFHLG9CQUFvQixDQUFDLEVBQUUsV0FBVyxFQUFFLElBQUksQ0FBQyxXQUFXLElBQUksZUFBZSxFQUFFLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDO0lBRXhILDJFQUEyRTtJQUMzRSxtQkFBbUI7SUFDbkIsTUFBTSxXQUFXLEdBQUcsTUFBTSxZQUFZLENBQUMsWUFBWSxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsV0FBVyxDQUFDLENBQUM7SUFDL0UsSUFBSSxXQUFXLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDekIsSUFBSSxJQUFJLENBQUMsR0FBRztZQUFFLHNCQUFzQixDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsSUFBSSxFQUFFLFdBQVcsQ0FBQyxDQUFDO1FBQ2xFLE9BQU8sRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLFdBQVcsRUFBRSxDQUFDO0lBQzNDLENBQUM7SUFFRCxJQUFJLFFBQVEsR0FBRyxLQUFLLENBQUM7SUFDckIsSUFBSSxRQUFRLEdBQUcsS0FBSyxDQUFDO0lBQ3JCLE1BQU0sSUFBSSxHQUFjO1FBQ3RCLFdBQVc7UUFDWCxXQUFXO1FBQ1gsWUFBWSxFQUFFLEdBQUcsRUFBRSxHQUFHLFFBQVEsR0FBRyxJQUFJLENBQUMsQ0FBQyxDQUFDO1FBQ3hDLE1BQU0sRUFBRSxHQUFHLEVBQUU7WUFDWCxJQUFJLFFBQVE7Z0JBQUUsT0FBTztZQUNyQixRQUFRLEdBQUcsSUFBSSxDQUFDO1lBQ2hCLDBFQUEwRTtZQUMxRSxjQUFjLENBQUMsWUFBWSxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsV0FBVyxFQUFFLE9BQU8sRUFBRSxDQUFDLEVBQUUsV0FBVyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNoRyxDQUFDO0tBQ0YsQ0FBQztJQUVGLElBQUksQ0FBQztRQUNILE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxNQUFNLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO0lBQ3JELENBQUM7SUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1FBQ2YsTUFBTSxpQkFBaUIsR0FBSSxLQUFnRCxFQUFFLGlCQUFpQixLQUFLLElBQUksQ0FBQztRQUN4RyxJQUFJLENBQUMsUUFBUSxJQUFJLENBQUMsaUJBQWlCO1lBQUUsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1FBQ25ELElBQUksQ0FBQyxPQUFPO1lBQUUsTUFBTSxLQUFLLENBQUM7UUFDMUIsTUFBTSxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDckIsT0FBTyxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLENBQUM7SUFDckMsQ0FBQztBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuaW1wb3J0IHtcbiAgZGVjcmVtZW50UXVvdGEsXG4gIGdldFNlcnZpY2VBdXRoSGVhZGVyLFxuICByZXNlcnZlUXVvdGEsXG4gIHNlbmRRdW90YVJlc2VydmVEZW5pZWQsXG4gIHNlcnZpY2VJZGVudGl0eSxcbiAgdHlwZSBRdW90YVJlc2VydmVSZXN1bHQsXG4gIHR5cGUgUXVvdGFTZXJ2aWNlLFxuICB0eXBlIFF1b3RhVHlwZSxcbn0gZnJvbSAnQHBpcGVsaW5lLWJ1aWxkZXIvYXBpLWNvcmUnO1xuaW1wb3J0IHR5cGUgeyBSZXNwb25zZSB9IGZyb20gJ2V4cHJlc3MnO1xuXG4vKiogVGhlIHJlc2VydmVkIHF1b3RhIHNsb3QsIGhhbmRlZCB0byB0aGUgZ3VhcmRlZCBib2R5LiAqL1xuZXhwb3J0IGludGVyZmFjZSBRdW90YVNsb3Qge1xuICAvKiogTWludGVkIHNlcnZpY2UgdG9rZW4gdGhlIHJlc2VydmF0aW9uIHVzZWQg4oCUIHJldXNlIGl0IGZvciB0aGUgYm9keSdzIG93biBTMlMgY2FsbHMuICovXG4gIHJlYWRvbmx5IHNlcnZpY2VBdXRoOiBzdHJpbmc7XG4gIHJlYWRvbmx5IHJlc2VydmF0aW9uOiBRdW90YVJlc2VydmVSZXN1bHQ7XG4gIC8qKlxuICAgKiBUaGUgcmVzZXJ2ZWQgcmVzb3VyY2UgaGFzIGJlZW4gY29uc3VtZWQgKGUuZy4gdGhlIEFJIHByb3ZpZGVyIHN0YXJ0ZWRcbiAgICogcmVzcG9uZGluZykuIEZyb20gaGVyZSBvbiBhIGZhaWx1cmUgS0VFUFMgdGhlIHNsb3Qg4oCUIHRoZSBjb3N0IHdhcyBpbmN1cnJlZC5cbiAgICovXG4gIG1hcmtDb25zdW1lZCgpOiB2b2lkO1xuICAvKiogR2l2ZSB0aGUgc2xvdCBiYWNrIG5vdy4gSWRlbXBvdGVudDogcmVmdW5kcyBhdCBtb3N0IG9uY2UuICovXG4gIHJlZnVuZCgpOiB2b2lkO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFF1b3RhUmVzZXJ2YXRpb25PcHRpb25zIHtcbiAgcXVvdGFTZXJ2aWNlOiBRdW90YVNlcnZpY2U7XG4gIG9yZ0lkOiBzdHJpbmc7XG4gIHR5cGU6IFF1b3RhVHlwZTtcbiAgLyoqIFNpZ25lciBvZiB0aGUgcXVvdGEgc2VydmljZSB0b2tlbi4gRGVmYXVsdHMgdG8gdGhpcyBwcm9jZXNzIChgU0VSVklDRV9OQU1FYCkuICovXG4gIHNlcnZpY2VOYW1lPzogc3RyaW5nO1xuICBsb2dXYXJuOiAobWVzc2FnZTogc3RyaW5nLCBkYXRhPzogdW5rbm93bikgPT4gdm9pZDtcbiAgLyoqIFdoZW4gc2V0LCBhIGRlbmllZCByZXNlcnZhdGlvbiBpcyBhbnN3ZXJlZCBvbiBpdCAoNDI5LCBvciA1MDMgd2hlbiB1bmNvbmZpcm1hYmxlKS4gKi9cbiAgcmVzPzogUmVzcG9uc2U7XG59XG5cbmV4cG9ydCB0eXBlIFF1b3RhUmVzZXJ2YXRpb25PdXRjb21lPFQ+ID1cbiAgfCB7IHN0YXR1czogJ2RlbmllZCc7IHJlc2VydmF0aW9uOiBRdW90YVJlc2VydmVSZXN1bHQgfVxuICB8IHsgc3RhdHVzOiAnZG9uZSc7IHZhbHVlOiBUIH1cbiAgLyoqIE9ubHkgd2l0aCBhbiBgb25FcnJvcmAgaGFuZGxlcjogdGhlIGJvZHkgdGhyZXcgYW5kIHRoZSBoYW5kbGVyIGFuc3dlcmVkLiAqL1xuICB8IHsgc3RhdHVzOiAnZmFpbGVkJzsgZXJyb3I6IHVua25vd24gfTtcblxuLyoqXG4gKiBSZXNlcnZlIG9uZSBxdW90YSBzbG90LCBydW4gYGJvZHlgLCBhbmQgc2V0dGxlIHRoZSBzbG90IGJ5IE9ORSBydWxlOlxuICoga2VlcCBpdCBvbmNlIHRoZSByZXNvdXJjZSB3YXMgY29uc3VtZWQ7IHJlZnVuZCBpdCBpZiB0aGUgYm9keSBmYWlscyBmaXJzdC5cbiAqXG4gKiAtIERlbmllZCDihpIgYHsgc3RhdHVzOiAnZGVuaWVkJyB9YCAoYW5zd2VyZWQgb24gYHJlc2Agd2hlbiBnaXZlbik7IGBib2R5YCBuZXZlciBydW5zLlxuICogLSBgYm9keWAgcmVzb2x2ZXMg4oaSIHRoZSBzbG90IGlzIGtlcHQgKHVubGVzcyBgYm9keWAgY2FsbGVkIGBzbG90LnJlZnVuZCgpYCkuXG4gKiAtIGBib2R5YCB0aHJvd3Mg4oaSIHJlZnVuZGVkIHVubGVzcyBjb25zdW1lZCDigJQgbWFya2VkIHZpYSBgc2xvdC5tYXJrQ29uc3VtZWQoKWBcbiAqICAgb3Igc2lnbmFsbGVkIGJ5IHRoZSBlcnJvciBpdHNlbGYgY2FycnlpbmcgYHByb3ZpZGVyQ29udGFjdGVkID09PSB0cnVlYFxuICogICAoYW4gQUkgcm91bmQtdHJpcCB0aGF0IGNvbXBsZXRlZCBidXQgcHJvZHVjZWQgbm90aGluZyB1c2FibGUpLiBUaGUgZXJyb3IgaXNcbiAqICAgdGhlbiBwYXNzZWQgdG8gYG9uRXJyb3JgLCBvciByZXRocm93biB3aGVuIHRoZXJlIGlzIG5vbmUuXG4gKlxuICogVGhlIHJlc2VydmUgYW5kIHJlZnVuZCBhdXRoZW50aWNhdGUgd2l0aCBhIG1pbnRlZCBzZXJ2aWNlIHRva2VuLCBuZXZlciB0aGVcbiAqIGVuZC11c2VyIGJlYXJlcjogdGhlIHF1b3RhIGluY3JlbWVudCBlbmRwb2ludCByZWplY3RzIHVzZXIgcHJpbmNpcGFscy5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHdpdGhRdW90YVJlc2VydmF0aW9uPFQ+KFxuICBvcHRzOiBRdW90YVJlc2VydmF0aW9uT3B0aW9ucyxcbiAgYm9keTogKHNsb3Q6IFF1b3RhU2xvdCkgPT4gUHJvbWlzZTxUPixcbiAgb25FcnJvcj86IChlcnJvcjogdW5rbm93bikgPT4gdm9pZCB8IFByb21pc2U8dm9pZD4sXG4pOiBQcm9taXNlPFF1b3RhUmVzZXJ2YXRpb25PdXRjb21lPFQ+PiB7XG4gIGNvbnN0IHsgcXVvdGFTZXJ2aWNlLCBvcmdJZCwgdHlwZSwgbG9nV2FybiB9ID0gb3B0cztcbiAgY29uc3Qgc2VydmljZUF1dGggPSBnZXRTZXJ2aWNlQXV0aEhlYWRlcih7IHNlcnZpY2VOYW1lOiBvcHRzLnNlcnZpY2VOYW1lID8/IHNlcnZpY2VJZGVudGl0eSgpLCBvcmdJZCwgcm9sZTogJ21lbWJlcicgfSk7XG5cbiAgLy8gUmVzZXJ2ZSBhdG9taWNhbGx5IEJFRk9SRSBhbnkgd29yazogdHdvIGNvbmN1cnJlbnQgcmVxdWVzdHMgYXQgdGhlIGxpbWl0XG4gIC8vIGNhbid0IGJvdGggcGFzcy5cbiAgY29uc3QgcmVzZXJ2YXRpb24gPSBhd2FpdCByZXNlcnZlUXVvdGEocXVvdGFTZXJ2aWNlLCBvcmdJZCwgdHlwZSwgc2VydmljZUF1dGgpO1xuICBpZiAocmVzZXJ2YXRpb24uZXhjZWVkZWQpIHtcbiAgICBpZiAob3B0cy5yZXMpIHNlbmRRdW90YVJlc2VydmVEZW5pZWQob3B0cy5yZXMsIHR5cGUsIHJlc2VydmF0aW9uKTtcbiAgICByZXR1cm4geyBzdGF0dXM6ICdkZW5pZWQnLCByZXNlcnZhdGlvbiB9O1xuICB9XG5cbiAgbGV0IGNvbnN1bWVkID0gZmFsc2U7XG4gIGxldCByZWZ1bmRlZCA9IGZhbHNlO1xuICBjb25zdCBzbG90OiBRdW90YVNsb3QgPSB7XG4gICAgc2VydmljZUF1dGgsXG4gICAgcmVzZXJ2YXRpb24sXG4gICAgbWFya0NvbnN1bWVkOiAoKSA9PiB7IGNvbnN1bWVkID0gdHJ1ZTsgfSxcbiAgICByZWZ1bmQ6ICgpID0+IHtcbiAgICAgIGlmIChyZWZ1bmRlZCkgcmV0dXJuO1xuICAgICAgcmVmdW5kZWQgPSB0cnVlO1xuICAgICAgLy8gVGhlIHJlc2VydmVkIHJlc2V0QXQga2VlcHMgYSBwZXJpb2Qgcm9sbG92ZXIgZnJvbSBiZWluZyBkb3VibGUtY2hhcmdlZC5cbiAgICAgIGRlY3JlbWVudFF1b3RhKHF1b3RhU2VydmljZSwgb3JnSWQsIHR5cGUsIHNlcnZpY2VBdXRoLCBsb2dXYXJuLCAxLCByZXNlcnZhdGlvbi5xdW90YS5yZXNldEF0KTtcbiAgICB9LFxuICB9O1xuXG4gIHRyeSB7XG4gICAgcmV0dXJuIHsgc3RhdHVzOiAnZG9uZScsIHZhbHVlOiBhd2FpdCBib2R5KHNsb3QpIH07XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgY29uc3QgZXJyb3JTYXlzQ29uc3VtZWQgPSAoZXJyb3IgYXMgeyBwcm92aWRlckNvbnRhY3RlZD86IHVua25vd24gfSB8IG51bGwpPy5wcm92aWRlckNvbnRhY3RlZCA9PT0gdHJ1ZTtcbiAgICBpZiAoIWNvbnN1bWVkICYmICFlcnJvclNheXNDb25zdW1lZCkgc2xvdC5yZWZ1bmQoKTtcbiAgICBpZiAoIW9uRXJyb3IpIHRocm93IGVycm9yO1xuICAgIGF3YWl0IG9uRXJyb3IoZXJyb3IpO1xuICAgIHJldHVybiB7IHN0YXR1czogJ2ZhaWxlZCcsIGVycm9yIH07XG4gIH1cbn1cbiJdfQ==
@@ -8,6 +8,16 @@ export interface OrgRateLimitOptions {
8
8
  windowMs: number;
9
9
  /** Optional 429 message override. */
10
10
  message?: string;
11
+ /**
12
+ * What one bucket is (default `org`):
13
+ * - `org` — the verified org (an org service account gets its own bucket);
14
+ * - `user` — the verified caller (`sub`), for per-person caps;
15
+ * - `ip` — the TRUSTED client IP (`req.ip`, resolved by the app's
16
+ * `trust proxy` setting — never a raw forwarding header), for
17
+ * per-address caps that a user can't reset by switching orgs.
18
+ * Every mode falls back to the client-IP bucket for an unauthenticated caller.
19
+ */
20
+ keyBy?: 'org' | 'user' | 'ip';
11
21
  }
12
22
  /**
13
23
  * Per-ORGANIZATION rate limiter for a specific hot/expensive route, keyed on the
@@ -21,7 +21,7 @@ import { createSharedRateLimitStore } from './rate-limit-store.js';
21
21
  * withRoute(handler));
22
22
  */
23
23
  export function rateLimitByOrg(opts) {
24
- const { name, max, windowMs, message } = opts;
24
+ const { name, max, windowMs, message, keyBy = 'org' } = opts;
25
25
  const options = {
26
26
  max,
27
27
  windowMs,
@@ -39,10 +39,15 @@ export function rateLimitByOrg(opts) {
39
39
  // bucket when unauthenticated so pre-auth traffic is still bounded.
40
40
  // Namespaced (`sa:`/`org:`/`ip:`) so no two id spaces can collide.
41
41
  keyGenerator: (req) => {
42
+ const ip = `ip:${ipKeyGenerator(req.ip || 'anon', 64)}`;
43
+ if (keyBy === 'ip')
44
+ return ip;
45
+ if (keyBy === 'user')
46
+ return req.user?.sub ? `user:${req.user.sub}` : ip;
42
47
  if (req.user?.principalType === 'service_account' && req.user.sub)
43
48
  return `sa:${req.user.sub}`;
44
49
  const orgId = req.user?.organizationId;
45
- return orgId ? `org:${orgId.toLowerCase()}` : `ip:${ipKeyGenerator(req.ip || 'anon', 64)}`;
50
+ return orgId ? `org:${orgId.toLowerCase()}` : ip;
46
51
  },
47
52
  handler: (_req, res) => {
48
53
  sendError(res, 429, message ?? `Too many ${name} requests, please slow down.`, ErrorCode.RATE_LIMIT_EXCEEDED);
@@ -55,4 +60,4 @@ export function rateLimitByOrg(opts) {
55
60
  options.store = createSharedRateLimitStore(`${process.env.SERVICE_NAME || 'api'}:${name}`);
56
61
  return rateLimit(options);
57
62
  }
58
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmF0ZS1saW1pdC1ieS1vcmcuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYXBpL3JhdGUtbGltaXQtYnktb3JnLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFFdEMsT0FBTyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUUxRixPQUFPLFNBQVMsRUFBRSxFQUFFLGNBQWMsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQy9ELE9BQU8sRUFBRSwwQkFBMEIsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBY25FOzs7Ozs7Ozs7Ozs7Ozs7O0dBZ0JHO0FBQ0gsTUFBTSxVQUFVLGNBQWMsQ0FBQyxJQUF5QjtJQUN0RCxNQUFNLEVBQUUsSUFBSSxFQUFFLEdBQUcsRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLEdBQUcsSUFBSSxDQUFDO0lBRTlDLE1BQU0sT0FBTyxHQUFvQztRQUMvQyxHQUFHO1FBQ0gsUUFBUTtRQUNSLGVBQWUsRUFBRSxJQUFJO1FBQ3JCLGFBQWEsRUFBRSxLQUFLO1FBQ3BCLDJFQUEyRTtRQUMzRSxJQUFJLEVBQUUsQ0FBQyxHQUFZLEVBQUUsRUFBRSxDQUFDLHNCQUFzQixDQUFDLEdBQUcsQ0FBQztRQUNuRCwyRUFBMkU7UUFDM0UsZ0JBQWdCLEVBQUUsSUFBSTtRQUN0QixzRUFBc0U7UUFDdEUsNEVBQTRFO1FBQzVFLDBFQUEwRTtRQUMxRSx5RUFBeUU7UUFDekUsNEVBQTRFO1FBQzVFLG9FQUFvRTtRQUNwRSxtRUFBbUU7UUFDbkUsWUFBWSxFQUFFLENBQUMsR0FBWSxFQUFVLEVBQUU7WUFDckMsSUFBSSxHQUFHLENBQUMsSUFBSSxFQUFFLGFBQWEsS0FBSyxpQkFBaUIsSUFBSSxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUc7Z0JBQUUsT0FBTyxNQUFNLEdBQUcsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7WUFDL0YsTUFBTSxLQUFLLEdBQUcsR0FBRyxDQUFDLElBQUksRUFBRSxjQUFjLENBQUM7WUFDdkMsT0FBTyxLQUFLLENBQUMsQ0FBQyxDQUFDLE9BQU8sS0FBSyxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLE1BQU0sY0FBYyxDQUFDLEdBQUcsQ0FBQyxFQUFFLElBQUksTUFBTSxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUM7UUFDN0YsQ0FBQztRQUNELE9BQU8sRUFBRSxDQUFDLElBQWEsRUFBRSxHQUFhLEVBQVEsRUFBRTtZQUM5QyxTQUFTLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxPQUFPLElBQUksWUFBWSxJQUFJLDhCQUE4QixFQUFFLFNBQVMsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO1FBQ2hILENBQUM7S0FDRixDQUFDO0lBRUYsK0VBQStFO0lBQy9FLGlGQUFpRjtJQUNqRiwyRUFBMkU7SUFDM0UsbUJBQW1CO0lBQ25CLE9BQU8sQ0FBQyxLQUFLLEdBQUcsMEJBQTBCLENBQUMsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLFlBQVksSUFBSSxLQUFLLElBQUksSUFBSSxFQUFFLENBQUMsQ0FBQztJQUUzRixPQUFPLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQztBQUM1QixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCB7IHNlbmRFcnJvciwgRXJyb3JDb2RlLCB2ZXJpZnlTZXJ2aWNlUHJpbmNpcGFsIH0gZnJvbSAnQHBpcGVsaW5lLWJ1aWxkZXIvYXBpLWNvcmUnO1xuaW1wb3J0IHR5cGUgeyBSZXF1ZXN0LCBSZXNwb25zZSB9IGZyb20gJ2V4cHJlc3MnO1xuaW1wb3J0IHJhdGVMaW1pdCwgeyBpcEtleUdlbmVyYXRvciB9IGZyb20gJ2V4cHJlc3MtcmF0ZS1saW1pdCc7XG5pbXBvcnQgeyBjcmVhdGVTaGFyZWRSYXRlTGltaXRTdG9yZSB9IGZyb20gJy4vcmF0ZS1saW1pdC1zdG9yZS5qcyc7XG5cbi8qKiBDb25maWcgZm9yIGEge0BsaW5rIHJhdGVMaW1pdEJ5T3JnfSBsaW1pdGVyLiAqL1xuZXhwb3J0IGludGVyZmFjZSBPcmdSYXRlTGltaXRPcHRpb25zIHtcbiAgLyoqIFVuaXF1ZSBuYW1lIOKAlCBuYW1lc3BhY2VzIHRoZSBSZWRpcyBidWNrZXQgKyBsYWJlbHMgbG9ncy4gKi9cbiAgbmFtZTogc3RyaW5nO1xuICAvKiogTWF4IHJlcXVlc3RzIHBlciB3aW5kb3cgcGVyIG9yZyAob3IgcGVyIGNsaWVudCBJUCB3aGVuIHVuYXV0aGVudGljYXRlZCkuICovXG4gIG1heDogbnVtYmVyO1xuICAvKiogV2luZG93IGxlbmd0aCBpbiBtcy4gKi9cbiAgd2luZG93TXM6IG51bWJlcjtcbiAgLyoqIE9wdGlvbmFsIDQyOSBtZXNzYWdlIG92ZXJyaWRlLiAqL1xuICBtZXNzYWdlPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIFBlci1PUkdBTklaQVRJT04gcmF0ZSBsaW1pdGVyIGZvciBhIHNwZWNpZmljIGhvdC9leHBlbnNpdmUgcm91dGUsIGtleWVkIG9uIHRoZVxuICogVkVSSUZJRUQgYXV0aCBvcmcg4oCUIHRoZSBjb21wbGVtZW50IHRvIHRoZSBjb2Fyc2UgZ2xvYmFsIHBlci1JUCBsaW1pdGVyIGluXG4gKiBgY3JlYXRlQXBwYCAod2hpY2ggYSB3aG9sZSBvcmcgYmVoaW5kIG9uZSBOQVQgc2hhcmVzLCBhbmQgYSBkaXN0cmlidXRlZFxuICogYXR0YWNrZXIgc3ByZWFkcyBhY3Jvc3MgSVAgYnVja2V0cyB0byBldmFkZSkuXG4gKlxuICogTVVTVCBiZSBtb3VudGVkIEFGVEVSIGByZXF1aXJlQXV0aGAgc28gYHJlcS51c2VyLm9yZ2FuaXphdGlvbklkYCBpcyBwb3B1bGF0ZWQ7XG4gKiBhbiB1bmF1dGhlbnRpY2F0ZWQgY2FsbGVyIGZhbGxzIGJhY2sgdG8gYSBjbGllbnQtSVAgYnVja2V0IChuZXZlciBhIHNwb29mYWJsZVxuICogaGVhZGVyKSBzbyBpdCBzdGF5cyBib3VuZGVkLiBWZXJpZmllZCBpbnRlcm5hbCBzZXJ2aWNlIHByaW5jaXBhbHMgYXJlIGV4ZW1wdFxuICogKHRoZXkgY2FycnkgYSBzaWduZWQgc2VydmljZSBKV1QpLiBVc2VzIHRoZSBzaGFyZWQgZW52IFJlZGlzIHN0b3JlXG4gKiAoY3Jvc3MtcmVwbGljYSwgbmFtZXNwYWNlZCBieSBgbmFtZWApIHdoZW4gY29uZmlndXJlZCwgZWxzZSBpbi1tZW1vcnkuXG4gKlxuICogQGV4YW1wbGVcbiAqICAgcm91dGVyLnBvc3QoJy8nLCAuLi5jcmVhdGVBdXRoZW50aWNhdGVkV2l0aE9yZ1JvdXRlKCksIHJlcXVpcmVQZXJtaXNzaW9uKCdtZXNzYWdlczp3cml0ZScpLFxuICogICAgIHJhdGVMaW1pdEJ5T3JnKHsgbmFtZTogJ21lc3NhZ2Utc2VuZCcsIG1heDogNjAsIHdpbmRvd01zOiA2MF8wMDAgfSksXG4gKiAgICAgd2l0aFJvdXRlKGhhbmRsZXIpKTtcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJhdGVMaW1pdEJ5T3JnKG9wdHM6IE9yZ1JhdGVMaW1pdE9wdGlvbnMpIHtcbiAgY29uc3QgeyBuYW1lLCBtYXgsIHdpbmRvd01zLCBtZXNzYWdlIH0gPSBvcHRzO1xuXG4gIGNvbnN0IG9wdGlvbnM6IFBhcmFtZXRlcnM8dHlwZW9mIHJhdGVMaW1pdD5bMF0gPSB7XG4gICAgbWF4LFxuICAgIHdpbmRvd01zLFxuICAgIHN0YW5kYXJkSGVhZGVyczogdHJ1ZSxcbiAgICBsZWdhY3lIZWFkZXJzOiBmYWxzZSxcbiAgICAvLyBFeGVtcHQgY3J5cHRvZ3JhcGhpY2FsbHktdmVyaWZpZWQgaW50ZXJuYWwgc2VydmljZSBjYWxsZXJzIChzaWduZWQgSldUKS5cbiAgICBza2lwOiAocmVxOiBSZXF1ZXN0KSA9PiB2ZXJpZnlTZXJ2aWNlUHJpbmNpcGFsKHJlcSksXG4gICAgLy8gUmVkaXMgc3RvcmUgZmFpbHVyZSBkZWdyYWRlcyB0byBcIm5vdCBsaW1pdGVkXCIsIG5ldmVyIGEgNTAwIG9uIHRoZSByb3V0ZS5cbiAgICBwYXNzT25TdG9yZUVycm9yOiB0cnVlLFxuICAgIC8vIEJ1Y2tldCBieSBWRVJJRklFRCBpZGVudGl0eSAoc2V0IGJ5IHJlcXVpcmVBdXRoKSwgTk9UIHRoZSBzcG9vZmFibGVcbiAgICAvLyBgeC1vcmctaWRgIGhlYWRlci4gQW4gT1JHIFNFUlZJQ0UgQUNDT1VOVCBnZXRzIGl0cyBPV04gYnVja2V0IHJhdGhlciB0aGFuXG4gICAgLy8gaXRzIG9yZydzOiBhdXRvbWF0aW9uIGlzIGV4YWN0bHkgdGhlIHRyYWZmaWMgc2hhcGUgdGhhdCB3b3VsZCBvdGhlcndpc2VcbiAgICAvLyBkcmFpbiB0aGUgd2luZG93IGl0cyBvcmcncyBwZW9wbGUgc2hhcmUsIGFuZCB0aGUgcGxhbiByZXF1aXJlcyBtYWNoaW5lXG4gICAgLy8gcmF0ZSBsaW1pdHMgdG8gYmUga2V5ZWQgcGVyIGFjY291bnQuIEZhbGxzIGJhY2sgdG8gYSBub3JtYWxpemVkIGNsaWVudC1JUFxuICAgIC8vIGJ1Y2tldCB3aGVuIHVuYXV0aGVudGljYXRlZCBzbyBwcmUtYXV0aCB0cmFmZmljIGlzIHN0aWxsIGJvdW5kZWQuXG4gICAgLy8gTmFtZXNwYWNlZCAoYHNhOmAvYG9yZzpgL2BpcDpgKSBzbyBubyB0d28gaWQgc3BhY2VzIGNhbiBjb2xsaWRlLlxuICAgIGtleUdlbmVyYXRvcjogKHJlcTogUmVxdWVzdCk6IHN0cmluZyA9PiB7XG4gICAgICBpZiAocmVxLnVzZXI/LnByaW5jaXBhbFR5cGUgPT09ICdzZXJ2aWNlX2FjY291bnQnICYmIHJlcS51c2VyLnN1YikgcmV0dXJuIGBzYToke3JlcS51c2VyLnN1Yn1gO1xuICAgICAgY29uc3Qgb3JnSWQgPSByZXEudXNlcj8ub3JnYW5pemF0aW9uSWQ7XG4gICAgICByZXR1cm4gb3JnSWQgPyBgb3JnOiR7b3JnSWQudG9Mb3dlckNhc2UoKX1gIDogYGlwOiR7aXBLZXlHZW5lcmF0b3IocmVxLmlwIHx8ICdhbm9uJywgNjQpfWA7XG4gICAgfSxcbiAgICBoYW5kbGVyOiAoX3JlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSk6IHZvaWQgPT4ge1xuICAgICAgc2VuZEVycm9yKHJlcywgNDI5LCBtZXNzYWdlID8/IGBUb28gbWFueSAke25hbWV9IHJlcXVlc3RzLCBwbGVhc2Ugc2xvdyBkb3duLmAsIEVycm9yQ29kZS5SQVRFX0xJTUlUX0VYQ0VFREVEKTtcbiAgICB9LFxuICB9O1xuXG4gIC8vIFNoYXJlZCBjcm9zcy1yZXBsaWNhIHN0b3JlIChvbmUgcHJvY2Vzcy13aWRlIFJlZGlzIGNvbm5lY3Rpb24pIHdoZW4gUmVkaXMgaXNcbiAgLy8gY29uZmlndXJlZCwgZWxzZSBwZXItcHJvY2VzcyBtZW1vcnkuIE5hbWVzcGFjZWQgYnkgc2VydmljZSBBTkQgbGltaXRlciBuYW1lIHNvXG4gIC8vIGRpc3RpbmN0IGxpbWl0ZXJzIOKAlCBvciBzYW1lLW5hbWVkIGxpbWl0ZXJzIGluIGRpZmZlcmVudCBzZXJ2aWNlcyDigJQgbmV2ZXJcbiAgLy8gc2hhcmUgYSBjb3VudGVyLlxuICBvcHRpb25zLnN0b3JlID0gY3JlYXRlU2hhcmVkUmF0ZUxpbWl0U3RvcmUoYCR7cHJvY2Vzcy5lbnYuU0VSVklDRV9OQU1FIHx8ICdhcGknfToke25hbWV9YCk7XG5cbiAgcmV0dXJuIHJhdGVMaW1pdChvcHRpb25zKTtcbn1cbiJdfQ==
63
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmF0ZS1saW1pdC1ieS1vcmcuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYXBpL3JhdGUtbGltaXQtYnktb3JnLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFFdEMsT0FBTyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUUxRixPQUFPLFNBQVMsRUFBRSxFQUFFLGNBQWMsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQy9ELE9BQU8sRUFBRSwwQkFBMEIsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBd0JuRTs7Ozs7Ozs7Ozs7Ozs7OztHQWdCRztBQUNILE1BQU0sVUFBVSxjQUFjLENBQUMsSUFBeUI7SUFDdEQsTUFBTSxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxLQUFLLEdBQUcsS0FBSyxFQUFFLEdBQUcsSUFBSSxDQUFDO0lBRTdELE1BQU0sT0FBTyxHQUFvQztRQUMvQyxHQUFHO1FBQ0gsUUFBUTtRQUNSLGVBQWUsRUFBRSxJQUFJO1FBQ3JCLGFBQWEsRUFBRSxLQUFLO1FBQ3BCLDJFQUEyRTtRQUMzRSxJQUFJLEVBQUUsQ0FBQyxHQUFZLEVBQUUsRUFBRSxDQUFDLHNCQUFzQixDQUFDLEdBQUcsQ0FBQztRQUNuRCwyRUFBMkU7UUFDM0UsZ0JBQWdCLEVBQUUsSUFBSTtRQUN0QixzRUFBc0U7UUFDdEUsNEVBQTRFO1FBQzVFLDBFQUEwRTtRQUMxRSx5RUFBeUU7UUFDekUsNEVBQTRFO1FBQzVFLG9FQUFvRTtRQUNwRSxtRUFBbUU7UUFDbkUsWUFBWSxFQUFFLENBQUMsR0FBWSxFQUFVLEVBQUU7WUFDckMsTUFBTSxFQUFFLEdBQUcsTUFBTSxjQUFjLENBQUMsR0FBRyxDQUFDLEVBQUUsSUFBSSxNQUFNLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQztZQUN4RCxJQUFJLEtBQUssS0FBSyxJQUFJO2dCQUFFLE9BQU8sRUFBRSxDQUFDO1lBQzlCLElBQUksS0FBSyxLQUFLLE1BQU07Z0JBQUUsT0FBTyxHQUFHLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUMsUUFBUSxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7WUFDekUsSUFBSSxHQUFHLENBQUMsSUFBSSxFQUFFLGFBQWEsS0FBSyxpQkFBaUIsSUFBSSxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUc7Z0JBQUUsT0FBTyxNQUFNLEdBQUcsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7WUFDL0YsTUFBTSxLQUFLLEdBQUcsR0FBRyxDQUFDLElBQUksRUFBRSxjQUFjLENBQUM7WUFDdkMsT0FBTyxLQUFLLENBQUMsQ0FBQyxDQUFDLE9BQU8sS0FBSyxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUNuRCxDQUFDO1FBQ0QsT0FBTyxFQUFFLENBQUMsSUFBYSxFQUFFLEdBQWEsRUFBUSxFQUFFO1lBQzlDLFNBQVMsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLE9BQU8sSUFBSSxZQUFZLElBQUksOEJBQThCLEVBQUUsU0FBUyxDQUFDLG1CQUFtQixDQUFDLENBQUM7UUFDaEgsQ0FBQztLQUNGLENBQUM7SUFFRiwrRUFBK0U7SUFDL0UsaUZBQWlGO0lBQ2pGLDJFQUEyRTtJQUMzRSxtQkFBbUI7SUFDbkIsT0FBTyxDQUFDLEtBQUssR0FBRywwQkFBMEIsQ0FBQyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsWUFBWSxJQUFJLEtBQUssSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBRTNGLE9BQU8sU0FBUyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0FBQzVCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuaW1wb3J0IHsgc2VuZEVycm9yLCBFcnJvckNvZGUsIHZlcmlmeVNlcnZpY2VQcmluY2lwYWwgfSBmcm9tICdAcGlwZWxpbmUtYnVpbGRlci9hcGktY29yZSc7XG5pbXBvcnQgdHlwZSB7IFJlcXVlc3QsIFJlc3BvbnNlIH0gZnJvbSAnZXhwcmVzcyc7XG5pbXBvcnQgcmF0ZUxpbWl0LCB7IGlwS2V5R2VuZXJhdG9yIH0gZnJvbSAnZXhwcmVzcy1yYXRlLWxpbWl0JztcbmltcG9ydCB7IGNyZWF0ZVNoYXJlZFJhdGVMaW1pdFN0b3JlIH0gZnJvbSAnLi9yYXRlLWxpbWl0LXN0b3JlLmpzJztcblxuLyoqIENvbmZpZyBmb3IgYSB7QGxpbmsgcmF0ZUxpbWl0QnlPcmd9IGxpbWl0ZXIuICovXG5leHBvcnQgaW50ZXJmYWNlIE9yZ1JhdGVMaW1pdE9wdGlvbnMge1xuICAvKiogVW5pcXVlIG5hbWUg4oCUIG5hbWVzcGFjZXMgdGhlIFJlZGlzIGJ1Y2tldCArIGxhYmVscyBsb2dzLiAqL1xuICBuYW1lOiBzdHJpbmc7XG4gIC8qKiBNYXggcmVxdWVzdHMgcGVyIHdpbmRvdyBwZXIgb3JnIChvciBwZXIgY2xpZW50IElQIHdoZW4gdW5hdXRoZW50aWNhdGVkKS4gKi9cbiAgbWF4OiBudW1iZXI7XG4gIC8qKiBXaW5kb3cgbGVuZ3RoIGluIG1zLiAqL1xuICB3aW5kb3dNczogbnVtYmVyO1xuICAvKiogT3B0aW9uYWwgNDI5IG1lc3NhZ2Ugb3ZlcnJpZGUuICovXG4gIG1lc3NhZ2U/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBXaGF0IG9uZSBidWNrZXQgaXMgKGRlZmF1bHQgYG9yZ2ApOlxuICAgKiAgLSBgb3JnYCAg4oCUIHRoZSB2ZXJpZmllZCBvcmcgKGFuIG9yZyBzZXJ2aWNlIGFjY291bnQgZ2V0cyBpdHMgb3duIGJ1Y2tldCk7XG4gICAqICAtIGB1c2VyYCDigJQgdGhlIHZlcmlmaWVkIGNhbGxlciAoYHN1YmApLCBmb3IgcGVyLXBlcnNvbiBjYXBzO1xuICAgKiAgLSBgaXBgICAg4oCUIHRoZSBUUlVTVEVEIGNsaWVudCBJUCAoYHJlcS5pcGAsIHJlc29sdmVkIGJ5IHRoZSBhcHAnc1xuICAgKiAgICAgICAgICAgICBgdHJ1c3QgcHJveHlgIHNldHRpbmcg4oCUIG5ldmVyIGEgcmF3IGZvcndhcmRpbmcgaGVhZGVyKSwgZm9yXG4gICAqICAgICAgICAgICAgIHBlci1hZGRyZXNzIGNhcHMgdGhhdCBhIHVzZXIgY2FuJ3QgcmVzZXQgYnkgc3dpdGNoaW5nIG9yZ3MuXG4gICAqIEV2ZXJ5IG1vZGUgZmFsbHMgYmFjayB0byB0aGUgY2xpZW50LUlQIGJ1Y2tldCBmb3IgYW4gdW5hdXRoZW50aWNhdGVkIGNhbGxlci5cbiAgICovXG4gIGtleUJ5PzogJ29yZycgfCAndXNlcicgfCAnaXAnO1xufVxuXG4vKipcbiAqIFBlci1PUkdBTklaQVRJT04gcmF0ZSBsaW1pdGVyIGZvciBhIHNwZWNpZmljIGhvdC9leHBlbnNpdmUgcm91dGUsIGtleWVkIG9uIHRoZVxuICogVkVSSUZJRUQgYXV0aCBvcmcg4oCUIHRoZSBjb21wbGVtZW50IHRvIHRoZSBjb2Fyc2UgZ2xvYmFsIHBlci1JUCBsaW1pdGVyIGluXG4gKiBgY3JlYXRlQXBwYCAod2hpY2ggYSB3aG9sZSBvcmcgYmVoaW5kIG9uZSBOQVQgc2hhcmVzLCBhbmQgYSBkaXN0cmlidXRlZFxuICogYXR0YWNrZXIgc3ByZWFkcyBhY3Jvc3MgSVAgYnVja2V0cyB0byBldmFkZSkuXG4gKlxuICogTVVTVCBiZSBtb3VudGVkIEFGVEVSIGByZXF1aXJlQXV0aGAgc28gYHJlcS51c2VyLm9yZ2FuaXphdGlvbklkYCBpcyBwb3B1bGF0ZWQ7XG4gKiBhbiB1bmF1dGhlbnRpY2F0ZWQgY2FsbGVyIGZhbGxzIGJhY2sgdG8gYSBjbGllbnQtSVAgYnVja2V0IChuZXZlciBhIHNwb29mYWJsZVxuICogaGVhZGVyKSBzbyBpdCBzdGF5cyBib3VuZGVkLiBWZXJpZmllZCBpbnRlcm5hbCBzZXJ2aWNlIHByaW5jaXBhbHMgYXJlIGV4ZW1wdFxuICogKHRoZXkgY2FycnkgYSBzaWduZWQgc2VydmljZSBKV1QpLiBVc2VzIHRoZSBzaGFyZWQgZW52IFJlZGlzIHN0b3JlXG4gKiAoY3Jvc3MtcmVwbGljYSwgbmFtZXNwYWNlZCBieSBgbmFtZWApIHdoZW4gY29uZmlndXJlZCwgZWxzZSBpbi1tZW1vcnkuXG4gKlxuICogQGV4YW1wbGVcbiAqICAgcm91dGVyLnBvc3QoJy8nLCAuLi5jcmVhdGVBdXRoZW50aWNhdGVkV2l0aE9yZ1JvdXRlKCksIHJlcXVpcmVQZXJtaXNzaW9uKCdtZXNzYWdlczp3cml0ZScpLFxuICogICAgIHJhdGVMaW1pdEJ5T3JnKHsgbmFtZTogJ21lc3NhZ2Utc2VuZCcsIG1heDogNjAsIHdpbmRvd01zOiA2MF8wMDAgfSksXG4gKiAgICAgd2l0aFJvdXRlKGhhbmRsZXIpKTtcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJhdGVMaW1pdEJ5T3JnKG9wdHM6IE9yZ1JhdGVMaW1pdE9wdGlvbnMpIHtcbiAgY29uc3QgeyBuYW1lLCBtYXgsIHdpbmRvd01zLCBtZXNzYWdlLCBrZXlCeSA9ICdvcmcnIH0gPSBvcHRzO1xuXG4gIGNvbnN0IG9wdGlvbnM6IFBhcmFtZXRlcnM8dHlwZW9mIHJhdGVMaW1pdD5bMF0gPSB7XG4gICAgbWF4LFxuICAgIHdpbmRvd01zLFxuICAgIHN0YW5kYXJkSGVhZGVyczogdHJ1ZSxcbiAgICBsZWdhY3lIZWFkZXJzOiBmYWxzZSxcbiAgICAvLyBFeGVtcHQgY3J5cHRvZ3JhcGhpY2FsbHktdmVyaWZpZWQgaW50ZXJuYWwgc2VydmljZSBjYWxsZXJzIChzaWduZWQgSldUKS5cbiAgICBza2lwOiAocmVxOiBSZXF1ZXN0KSA9PiB2ZXJpZnlTZXJ2aWNlUHJpbmNpcGFsKHJlcSksXG4gICAgLy8gUmVkaXMgc3RvcmUgZmFpbHVyZSBkZWdyYWRlcyB0byBcIm5vdCBsaW1pdGVkXCIsIG5ldmVyIGEgNTAwIG9uIHRoZSByb3V0ZS5cbiAgICBwYXNzT25TdG9yZUVycm9yOiB0cnVlLFxuICAgIC8vIEJ1Y2tldCBieSBWRVJJRklFRCBpZGVudGl0eSAoc2V0IGJ5IHJlcXVpcmVBdXRoKSwgTk9UIHRoZSBzcG9vZmFibGVcbiAgICAvLyBgeC1vcmctaWRgIGhlYWRlci4gQW4gT1JHIFNFUlZJQ0UgQUNDT1VOVCBnZXRzIGl0cyBPV04gYnVja2V0IHJhdGhlciB0aGFuXG4gICAgLy8gaXRzIG9yZydzOiBhdXRvbWF0aW9uIGlzIGV4YWN0bHkgdGhlIHRyYWZmaWMgc2hhcGUgdGhhdCB3b3VsZCBvdGhlcndpc2VcbiAgICAvLyBkcmFpbiB0aGUgd2luZG93IGl0cyBvcmcncyBwZW9wbGUgc2hhcmUsIGFuZCB0aGUgcGxhbiByZXF1aXJlcyBtYWNoaW5lXG4gICAgLy8gcmF0ZSBsaW1pdHMgdG8gYmUga2V5ZWQgcGVyIGFjY291bnQuIEZhbGxzIGJhY2sgdG8gYSBub3JtYWxpemVkIGNsaWVudC1JUFxuICAgIC8vIGJ1Y2tldCB3aGVuIHVuYXV0aGVudGljYXRlZCBzbyBwcmUtYXV0aCB0cmFmZmljIGlzIHN0aWxsIGJvdW5kZWQuXG4gICAgLy8gTmFtZXNwYWNlZCAoYHNhOmAvYG9yZzpgL2BpcDpgKSBzbyBubyB0d28gaWQgc3BhY2VzIGNhbiBjb2xsaWRlLlxuICAgIGtleUdlbmVyYXRvcjogKHJlcTogUmVxdWVzdCk6IHN0cmluZyA9PiB7XG4gICAgICBjb25zdCBpcCA9IGBpcDoke2lwS2V5R2VuZXJhdG9yKHJlcS5pcCB8fCAnYW5vbicsIDY0KX1gO1xuICAgICAgaWYgKGtleUJ5ID09PSAnaXAnKSByZXR1cm4gaXA7XG4gICAgICBpZiAoa2V5QnkgPT09ICd1c2VyJykgcmV0dXJuIHJlcS51c2VyPy5zdWIgPyBgdXNlcjoke3JlcS51c2VyLnN1Yn1gIDogaXA7XG4gICAgICBpZiAocmVxLnVzZXI/LnByaW5jaXBhbFR5cGUgPT09ICdzZXJ2aWNlX2FjY291bnQnICYmIHJlcS51c2VyLnN1YikgcmV0dXJuIGBzYToke3JlcS51c2VyLnN1Yn1gO1xuICAgICAgY29uc3Qgb3JnSWQgPSByZXEudXNlcj8ub3JnYW5pemF0aW9uSWQ7XG4gICAgICByZXR1cm4gb3JnSWQgPyBgb3JnOiR7b3JnSWQudG9Mb3dlckNhc2UoKX1gIDogaXA7XG4gICAgfSxcbiAgICBoYW5kbGVyOiAoX3JlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSk6IHZvaWQgPT4ge1xuICAgICAgc2VuZEVycm9yKHJlcywgNDI5LCBtZXNzYWdlID8/IGBUb28gbWFueSAke25hbWV9IHJlcXVlc3RzLCBwbGVhc2Ugc2xvdyBkb3duLmAsIEVycm9yQ29kZS5SQVRFX0xJTUlUX0VYQ0VFREVEKTtcbiAgICB9LFxuICB9O1xuXG4gIC8vIFNoYXJlZCBjcm9zcy1yZXBsaWNhIHN0b3JlIChvbmUgcHJvY2Vzcy13aWRlIFJlZGlzIGNvbm5lY3Rpb24pIHdoZW4gUmVkaXMgaXNcbiAgLy8gY29uZmlndXJlZCwgZWxzZSBwZXItcHJvY2VzcyBtZW1vcnkuIE5hbWVzcGFjZWQgYnkgc2VydmljZSBBTkQgbGltaXRlciBuYW1lIHNvXG4gIC8vIGRpc3RpbmN0IGxpbWl0ZXJzIOKAlCBvciBzYW1lLW5hbWVkIGxpbWl0ZXJzIGluIGRpZmZlcmVudCBzZXJ2aWNlcyDigJQgbmV2ZXJcbiAgLy8gc2hhcmUgYSBjb3VudGVyLlxuICBvcHRpb25zLnN0b3JlID0gY3JlYXRlU2hhcmVkUmF0ZUxpbWl0U3RvcmUoYCR7cHJvY2Vzcy5lbnYuU0VSVklDRV9OQU1FIHx8ICdhcGknfToke25hbWV9YCk7XG5cbiAgcmV0dXJuIHJhdGVMaW1pdChvcHRpb25zKTtcbn1cbiJdfQ==
@@ -1,6 +1,6 @@
1
1
  import type { Request, Response, NextFunction } from 'express';
2
2
  /**
3
- * Create middleware that validates the request has an orgId in the identity headers.
3
+ * Create middleware that validates the request has a resolved tenant org (`ctx.identity.orgId`).
4
4
  *
5
5
  * @returns Express middleware
6
6
  *
@@ -3,7 +3,7 @@
3
3
  import { ErrorCode, sendError } from '@pipeline-builder/api-core';
4
4
  import { getContext } from './get-context.js';
5
5
  /**
6
- * Create middleware that validates the request has an orgId in the identity headers.
6
+ * Create middleware that validates the request has a resolved tenant org (`ctx.identity.orgId`).
7
7
  *
8
8
  * @returns Express middleware
9
9
  *
@@ -18,11 +18,11 @@ export function requireOrgId() {
18
18
  return (req, res, next) => {
19
19
  const ctx = getContext(req);
20
20
  if (!ctx.identity.orgId) {
21
- ctx.log('ERROR', 'Organization ID is missing from request headers');
22
- sendError(res, 400, 'Organization ID is required. Please provide x-org-id header.', ErrorCode.VALIDATION_ERROR);
21
+ ctx.log('ERROR', 'Organization ID is missing from the request identity');
22
+ sendError(res, 400, 'Organization ID is required: the caller has no active organization.', ErrorCode.VALIDATION_ERROR);
23
23
  return;
24
24
  }
25
25
  next();
26
26
  };
27
27
  }
28
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVxdWlyZS1vcmctaWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYXBpL3JlcXVpcmUtb3JnLWlkLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFFdEMsT0FBTyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUVsRSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFFOUM7Ozs7Ozs7Ozs7O0dBV0c7QUFDSCxNQUFNLFVBQVUsWUFBWTtJQUMxQixPQUFPLENBQUMsR0FBWSxFQUFFLEdBQWEsRUFBRSxJQUFrQixFQUFRLEVBQUU7UUFDL0QsTUFBTSxHQUFHLEdBQUcsVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBRTVCLElBQUksQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ3hCLEdBQUcsQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLGlEQUFpRCxDQUFDLENBQUM7WUFDcEUsU0FBUyxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsOERBQThELEVBQUUsU0FBUyxDQUFDLGdCQUFnQixDQUFDLENBQUM7WUFDaEgsT0FBTztRQUNULENBQUM7UUFFRCxJQUFJLEVBQUUsQ0FBQztJQUNULENBQUMsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuaW1wb3J0IHsgRXJyb3JDb2RlLCBzZW5kRXJyb3IgfSBmcm9tICdAcGlwZWxpbmUtYnVpbGRlci9hcGktY29yZSc7XG5pbXBvcnQgdHlwZSB7IFJlcXVlc3QsIFJlc3BvbnNlLCBOZXh0RnVuY3Rpb24gfSBmcm9tICdleHByZXNzJztcbmltcG9ydCB7IGdldENvbnRleHQgfSBmcm9tICcuL2dldC1jb250ZXh0LmpzJztcblxuLyoqXG4gKiBDcmVhdGUgbWlkZGxld2FyZSB0aGF0IHZhbGlkYXRlcyB0aGUgcmVxdWVzdCBoYXMgYW4gb3JnSWQgaW4gdGhlIGlkZW50aXR5IGhlYWRlcnMuXG4gKlxuICogQHJldHVybnMgRXhwcmVzcyBtaWRkbGV3YXJlXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IHsgYXBwLCBzc2VNYW5hZ2VyIH0gPSBjcmVhdGVBcHAoKTtcbiAqXG4gKiBhcHAuZ2V0KCcvcGlwZWxpbmVzJywgcmVxdWlyZUF1dGgsIHJlcXVpcmVPcmdJZCgpLCBoYW5kbGVyKTtcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVxdWlyZU9yZ0lkKCkge1xuICByZXR1cm4gKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSwgbmV4dDogTmV4dEZ1bmN0aW9uKTogdm9pZCA9PiB7XG4gICAgY29uc3QgY3R4ID0gZ2V0Q29udGV4dChyZXEpO1xuXG4gICAgaWYgKCFjdHguaWRlbnRpdHkub3JnSWQpIHtcbiAgICAgIGN0eC5sb2coJ0VSUk9SJywgJ09yZ2FuaXphdGlvbiBJRCBpcyBtaXNzaW5nIGZyb20gcmVxdWVzdCBoZWFkZXJzJyk7XG4gICAgICBzZW5kRXJyb3IocmVzLCA0MDAsICdPcmdhbml6YXRpb24gSUQgaXMgcmVxdWlyZWQuIFBsZWFzZSBwcm92aWRlIHgtb3JnLWlkIGhlYWRlci4nLCBFcnJvckNvZGUuVkFMSURBVElPTl9FUlJPUik7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgbmV4dCgpO1xuICB9O1xufVxuIl19
28
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVxdWlyZS1vcmctaWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYXBpL3JlcXVpcmUtb3JnLWlkLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFFdEMsT0FBTyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUVsRSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFFOUM7Ozs7Ozs7Ozs7O0dBV0c7QUFDSCxNQUFNLFVBQVUsWUFBWTtJQUMxQixPQUFPLENBQUMsR0FBWSxFQUFFLEdBQWEsRUFBRSxJQUFrQixFQUFRLEVBQUU7UUFDL0QsTUFBTSxHQUFHLEdBQUcsVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBRTVCLElBQUksQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ3hCLEdBQUcsQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLHNEQUFzRCxDQUFDLENBQUM7WUFDekUsU0FBUyxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUscUVBQXFFLEVBQUUsU0FBUyxDQUFDLGdCQUFnQixDQUFDLENBQUM7WUFDdkgsT0FBTztRQUNULENBQUM7UUFFRCxJQUFJLEVBQUUsQ0FBQztJQUNULENBQUMsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuaW1wb3J0IHsgRXJyb3JDb2RlLCBzZW5kRXJyb3IgfSBmcm9tICdAcGlwZWxpbmUtYnVpbGRlci9hcGktY29yZSc7XG5pbXBvcnQgdHlwZSB7IFJlcXVlc3QsIFJlc3BvbnNlLCBOZXh0RnVuY3Rpb24gfSBmcm9tICdleHByZXNzJztcbmltcG9ydCB7IGdldENvbnRleHQgfSBmcm9tICcuL2dldC1jb250ZXh0LmpzJztcblxuLyoqXG4gKiBDcmVhdGUgbWlkZGxld2FyZSB0aGF0IHZhbGlkYXRlcyB0aGUgcmVxdWVzdCBoYXMgYSByZXNvbHZlZCB0ZW5hbnQgb3JnIChgY3R4LmlkZW50aXR5Lm9yZ0lkYCkuXG4gKlxuICogQHJldHVybnMgRXhwcmVzcyBtaWRkbGV3YXJlXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IHsgYXBwLCBzc2VNYW5hZ2VyIH0gPSBjcmVhdGVBcHAoKTtcbiAqXG4gKiBhcHAuZ2V0KCcvcGlwZWxpbmVzJywgcmVxdWlyZUF1dGgsIHJlcXVpcmVPcmdJZCgpLCBoYW5kbGVyKTtcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVxdWlyZU9yZ0lkKCkge1xuICByZXR1cm4gKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSwgbmV4dDogTmV4dEZ1bmN0aW9uKTogdm9pZCA9PiB7XG4gICAgY29uc3QgY3R4ID0gZ2V0Q29udGV4dChyZXEpO1xuXG4gICAgaWYgKCFjdHguaWRlbnRpdHkub3JnSWQpIHtcbiAgICAgIGN0eC5sb2coJ0VSUk9SJywgJ09yZ2FuaXphdGlvbiBJRCBpcyBtaXNzaW5nIGZyb20gdGhlIHJlcXVlc3QgaWRlbnRpdHknKTtcbiAgICAgIHNlbmRFcnJvcihyZXMsIDQwMCwgJ09yZ2FuaXphdGlvbiBJRCBpcyByZXF1aXJlZDogdGhlIGNhbGxlciBoYXMgbm8gYWN0aXZlIG9yZ2FuaXphdGlvbi4nLCBFcnJvckNvZGUuVkFMSURBVElPTl9FUlJPUik7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgbmV4dCgpO1xuICB9O1xufVxuIl19
@@ -41,9 +41,7 @@ export function withRoute(handler, options = {}) {
41
41
  return async (req, res) => {
42
42
  const ctx = getContext(req);
43
43
  // `identity.orgId` is already normalized (trimmed + lowercased) once at
44
- // resolution in api-core's `getIdentity`, so the previously-duplicated
45
- // `.toLowerCase()` here is redundant — kept normalization at the single
46
- // source of truth instead. This value now matches the RLS GUC exactly.
44
+ // resolution in api-core's `getIdentity`, so it matches the RLS GUC exactly.
47
45
  const orgId = ctx.identity.orgId || '';
48
46
  const userId = ctx.identity.userId || '';
49
47
  if (requireOrgId && !orgId) {
@@ -65,7 +63,9 @@ export function withRoute(handler, options = {}) {
65
63
  const status = error.statusCode >= 400 && error.statusCode < 600
66
64
  ? error.statusCode
67
65
  : 500;
68
- return sendError(res, status, error.message, error.code);
66
+ return error.details === undefined
67
+ ? sendError(res, status, error.message, error.code)
68
+ : sendError(res, status, error.message, error.code, error.details);
69
69
  }
70
70
  // Unhandled error → 500. NEVER echo the raw message to the client: DB driver
71
71
  // errors carry the SQL + bound params, and CrudService deliberately lets them
@@ -81,4 +81,4 @@ export function withRoute(handler, options = {}) {
81
81
  }
82
82
  };
83
83
  }
84
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUtd3JhcHBlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hcGkvcm91dGUtd3JhcHBlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDLE9BQU8sRUFDTCxRQUFRLEVBQ1IsWUFBWSxFQUNaLGNBQWMsRUFDZCxTQUFTLEVBQ1QsY0FBYyxFQUNkLGlCQUFpQixFQUNqQixZQUFZLEdBQ2IsTUFBTSw0QkFBNEIsQ0FBQztBQUVwQyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFHOUMsTUFBTSxNQUFNLEdBQUcsWUFBWSxDQUFDLGVBQWUsQ0FBQyxDQUFDO0FBRTdDOzs7OztHQUtHO0FBQ0gsU0FBUyxlQUFlLENBQUMsS0FBYztJQUNyQyxJQUFJLEtBQUssWUFBWSxLQUFLLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsZUFBZSxDQUFDLEVBQUUsQ0FBQztRQUN4RSxPQUFPLEdBQUcsS0FBSyxDQUFDLElBQUksSUFBSSxtQkFBbUIseUJBQXlCLENBQUM7SUFDdkUsQ0FBQztJQUNELE9BQU8sWUFBWSxDQUFDLEtBQUssQ0FBQyxDQUFDO0FBQzdCLENBQUM7QUE4QkQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBb0JHO0FBQ0gsTUFBTSxVQUFVLFNBQVMsQ0FDdkIsT0FBNEMsRUFDNUMsT0FBTyxHQUFxQixFQUFFO0lBRTlCLE1BQU0sRUFBRSxZQUFZLEdBQUcsSUFBSSxFQUFFLEdBQUcsT0FBTyxDQUFDO0lBRXhDLE9BQU8sS0FBSyxFQUFFLEdBQVksRUFBRSxHQUFhLEVBQUUsRUFBRTtRQUMzQyxNQUFNLEdBQUcsR0FBRyxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDNUIsd0VBQXdFO1FBQ3hFLHVFQUF1RTtRQUN2RSx3RUFBd0U7UUFDeEUsdUVBQXVFO1FBQ3ZFLE1BQU0sS0FBSyxHQUFHLEdBQUcsQ0FBQyxRQUFRLENBQUMsS0FBSyxJQUFJLEVBQUUsQ0FBQztRQUN2QyxNQUFNLE1BQU0sR0FBRyxHQUFHLENBQUMsUUFBUSxDQUFDLE1BQU0sSUFBSSxFQUFFLENBQUM7UUFFekMsSUFBSSxZQUFZLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUMzQixPQUFPLGNBQWMsQ0FBQyxHQUFHLEVBQUUsNkJBQTZCLENBQUMsQ0FBQztRQUM1RCxDQUFDO1FBRUQsSUFBSSxDQUFDO1lBQ0gsTUFBTSxPQUFPLENBQUMsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztRQUNsRCxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLHNEQUFzRDtZQUN0RCxJQUFJLEdBQUcsQ0FBQyxXQUFXLEVBQUUsQ0FBQztnQkFDcEIsTUFBTSxDQUFDLEtBQUssQ0FBQyx5Q0FBeUMsRUFBRTtvQkFDdEQsU0FBUyxFQUFFLEdBQUcsQ0FBQyxTQUFTO29CQUN4QixLQUFLLEVBQUUsZUFBZSxDQUFDLEtBQUssQ0FBQztpQkFDOUIsQ0FBQyxDQUFDO2dCQUNILE9BQU87WUFDVCxDQUFDO1lBRUQsSUFBSSxLQUFLLFlBQVksUUFBUSxFQUFFLENBQUM7Z0JBQzlCLE1BQU0sTUFBTSxHQUFHLEtBQUssQ0FBQyxVQUFVLElBQUksR0FBRyxJQUFJLEtBQUssQ0FBQyxVQUFVLEdBQUcsR0FBRztvQkFDOUQsQ0FBQyxDQUFDLEtBQUssQ0FBQyxVQUFVO29CQUNsQixDQUFDLENBQUMsR0FBRyxDQUFDO2dCQUNSLE9BQU8sU0FBUyxDQUFDLEdBQUcsRUFBRSxNQUFNLEVBQUUsS0FBSyxDQUFDLE9BQU8sRUFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDM0QsQ0FBQztZQUVELDZFQUE2RTtZQUM3RSw4RUFBOEU7WUFDOUUsK0VBQStFO1lBQy9FLDhFQUE4RTtZQUM5RSxNQUFNLEVBQUUsR0FBRyxjQUFjLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDakMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUU7Z0JBQ2pDLFNBQVMsRUFBRSxHQUFHLENBQUMsU0FBUztnQkFDeEIsS0FBSyxFQUFFLGVBQWUsQ0FBQyxLQUFLLENBQUM7Z0JBQzdCLEdBQUcsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO2FBQzFDLENBQUMsQ0FBQztZQUNILE9BQU8saUJBQWlCLENBQUMsR0FBRyxFQUFFLHVCQUF1QixFQUFFLEVBQUUsU0FBUyxFQUFFLEdBQUcsQ0FBQyxTQUFTLEVBQUUsQ0FBQyxDQUFDO1FBQ3ZGLENBQUM7SUFDSCxDQUFDLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCB7XG4gIEFwcEVycm9yLFxuICBlcnJvck1lc3NhZ2UsXG4gIGV4dHJhY3REYkVycm9yLFxuICBzZW5kRXJyb3IsXG4gIHNlbmRCYWRSZXF1ZXN0LFxuICBzZW5kSW50ZXJuYWxFcnJvcixcbiAgY3JlYXRlTG9nZ2VyLFxufSBmcm9tICdAcGlwZWxpbmUtYnVpbGRlci9hcGktY29yZSc7XG5pbXBvcnQgdHlwZSB7IFJlcXVlc3QsIFJlc3BvbnNlLCBSZXF1ZXN0SGFuZGxlciB9IGZyb20gJ2V4cHJlc3MnO1xuaW1wb3J0IHsgZ2V0Q29udGV4dCB9IGZyb20gJy4vZ2V0LWNvbnRleHQuanMnO1xuaW1wb3J0IHR5cGUgeyBSZXF1ZXN0Q29udGV4dCB9IGZyb20gJy4vcmVxdWVzdC10eXBlcy5qcyc7XG5cbmNvbnN0IGxvZ2dlciA9IGNyZWF0ZUxvZ2dlcigncm91dGUtd3JhcHBlcicpO1xuXG4vKipcbiAqIEEgbG9nLXNhZmUgcmVuZGVyaW5nIG9mIGFuIHVua25vd24gZXJyb3IuIGRyaXp6bGUtb3JtJ3MgYERyaXp6bGVRdWVyeUVycm9yYFxuICogZW1iZWRzIHRoZSBmYWlsZWQgU1FMIHN0YXRlbWVudCBBTkQgdGhlIGJvdW5kIHBhcmFtZXRlciB2YWx1ZXMgKHJlYWwgZGF0YSkgaW5cbiAqIGl0cyBgLm1lc3NhZ2VgIChgRmFpbGVkIHF1ZXJ5OiA8c3FsPlxcbnBhcmFtczogPHZhbHVlcz5gKS4gTmV2ZXIgcHV0IHRoYXQgaW4gYVxuICogcmVzcG9uc2Ugb3IgYSBsb2cgbGluZSDigJQgY29sbGFwc2UgaXQgdG8gdGhlIGVycm9yIG5hbWUuIE90aGVyIGVycm9ycyBhcmUgc2FmZS5cbiAqL1xuZnVuY3Rpb24gc2FmZUVycm9yRm9yTG9nKGVycm9yOiB1bmtub3duKTogc3RyaW5nIHtcbiAgaWYgKGVycm9yIGluc3RhbmNlb2YgRXJyb3IgJiYgZXJyb3IubWVzc2FnZS5zdGFydHNXaXRoKCdGYWlsZWQgcXVlcnk6JykpIHtcbiAgICByZXR1cm4gYCR7ZXJyb3IubmFtZSB8fCAnRHJpenpsZVF1ZXJ5RXJyb3InfTogZGF0YWJhc2UgcXVlcnkgZmFpbGVkYDtcbiAgfVxuICByZXR1cm4gZXJyb3JNZXNzYWdlKGVycm9yKTtcbn1cblxuLyoqXG4gKiBDb250ZXh0IG9iamVjdCBwYXNzZWQgdG8gZXZlcnkgcm91dGUgaGFuZGxlciB3cmFwcGVkIHdpdGggYHdpdGhSb3V0ZSgpYC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBSb3V0ZUNvbnRleHQge1xuICAvKiogT3JpZ2luYWwgRXhwcmVzcyByZXF1ZXN0ICovXG4gIHJlcTogUmVxdWVzdDtcbiAgLyoqIE9yaWdpbmFsIEV4cHJlc3MgcmVzcG9uc2UgKi9cbiAgcmVzOiBSZXNwb25zZTtcbiAgLyoqIFJlcXVlc3QgY29udGV4dCB3aXRoIGlkZW50aXR5IGFuZCBsb2dnaW5nICovXG4gIGN0eDogUmVxdWVzdENvbnRleHQ7XG4gIC8qKiBMb3dlcmNhc2VkIG9yZ2FuaXphdGlvbiBJRCAoZ3VhcmFudGVlZCBub24tZW1wdHkgd2hlbiByZXF1aXJlT3JnSWQgaXMgdHJ1ZSkgKi9cbiAgb3JnSWQ6IHN0cmluZztcbiAgLyoqIFVzZXIgSUQgZnJvbSBKV1QgKGRlZmF1bHRzIHRvIGVtcHR5IHN0cmluZykgKi9cbiAgdXNlcklkOiBzdHJpbmc7XG59XG5cbi8qKlxuICogT3B0aW9ucyBmb3IgYHdpdGhSb3V0ZSgpYC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBXaXRoUm91dGVPcHRpb25zIHtcbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gcmVxdWlyZSBvcmdJZCBvbiB0aGUgcmVxdWVzdC5cbiAgICogV2hlbiB0cnVlIChkZWZhdWx0KSwgcmV0dXJucyA0MDAgaWYgb3JnSWQgaXMgbWlzc2luZy5cbiAgICogU2V0IHRvIGZhbHNlIGZvciByb3V0ZXMgdGhhdCBkb24ndCBuZWVkIG9yZyBjb250ZXh0LlxuICAgKi9cbiAgcmVxdWlyZU9yZ0lkPzogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBXcmFwIGFuIGFzeW5jIHJvdXRlIGhhbmRsZXIgd2l0aCBzdGFuZGFyZCBib2lsZXJwbGF0ZS5cbiAqXG4gKiBFeHRyYWN0cyBjb250ZXh0LCBvcmdJZCwgdXNlcklkIGZyb20gdGhlIHJlcXVlc3QsIHZhbGlkYXRlcyBvcmdJZCxcbiAqIGFuZCBjYXRjaGVzIGVycm9ycy4gVHlwZWQgYEFwcEVycm9yYCBzdWJjbGFzc2VzIGFyZSBhdXRvbWF0aWNhbGx5XG4gKiBtYXBwZWQgdG8gdGhlIGNvcnJlY3QgSFRUUCByZXNwb25zZS5cbiAqXG4gKiBAcGFyYW0gaGFuZGxlciAtIEFzeW5jIGZ1bmN0aW9uIHJlY2VpdmluZyBhIFJvdXRlQ29udGV4dFxuICogQHBhcmFtIG9wdGlvbnMgLSBDb25maWd1cmF0aW9uIG9wdGlvbnNcbiAqIEByZXR1cm5zIEV4cHJlc3MgUmVxdWVzdEhhbmRsZXJcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogcm91dGVyLmdldCgnLzppZCcsIHdpdGhSb3V0ZShhc3luYyAoeyByZXEsIHJlcywgY3R4LCBvcmdJZCB9KSA9PiB7XG4gKiAgIGNvbnN0IGlkID0gZ2V0UGFyYW0ocmVxLnBhcmFtcywgJ2lkJyk7XG4gKiAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBpcGVsaW5lU2VydmljZS5maW5kQnlJZChpZCwgb3JnSWQpO1xuICogICBpZiAoIXJlc3VsdCkgdGhyb3cgbmV3IE5vdEZvdW5kRXJyb3IoJ1BpcGVsaW5lIG5vdCBmb3VuZCcpO1xuICogICByZXR1cm4gc2VuZFN1Y2Nlc3MocmVzLCAyMDAsIHsgcGlwZWxpbmU6IHJlc3VsdCB9KTtcbiAqIH0pKTtcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gd2l0aFJvdXRlKFxuICBoYW5kbGVyOiAocmM6IFJvdXRlQ29udGV4dCkgPT4gUHJvbWlzZTx2b2lkPixcbiAgb3B0aW9uczogV2l0aFJvdXRlT3B0aW9ucyA9IHt9LFxuKTogUmVxdWVzdEhhbmRsZXIge1xuICBjb25zdCB7IHJlcXVpcmVPcmdJZCA9IHRydWUgfSA9IG9wdGlvbnM7XG5cbiAgcmV0dXJuIGFzeW5jIChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UpID0+IHtcbiAgICBjb25zdCBjdHggPSBnZXRDb250ZXh0KHJlcSk7XG4gICAgLy8gYGlkZW50aXR5Lm9yZ0lkYCBpcyBhbHJlYWR5IG5vcm1hbGl6ZWQgKHRyaW1tZWQgKyBsb3dlcmNhc2VkKSBvbmNlIGF0XG4gICAgLy8gcmVzb2x1dGlvbiBpbiBhcGktY29yZSdzIGBnZXRJZGVudGl0eWAsIHNvIHRoZSBwcmV2aW91c2x5LWR1cGxpY2F0ZWRcbiAgICAvLyBgLnRvTG93ZXJDYXNlKClgIGhlcmUgaXMgcmVkdW5kYW50IOKAlCBrZXB0IG5vcm1hbGl6YXRpb24gYXQgdGhlIHNpbmdsZVxuICAgIC8vIHNvdXJjZSBvZiB0cnV0aCBpbnN0ZWFkLiBUaGlzIHZhbHVlIG5vdyBtYXRjaGVzIHRoZSBSTFMgR1VDIGV4YWN0bHkuXG4gICAgY29uc3Qgb3JnSWQgPSBjdHguaWRlbnRpdHkub3JnSWQgfHwgJyc7XG4gICAgY29uc3QgdXNlcklkID0gY3R4LmlkZW50aXR5LnVzZXJJZCB8fCAnJztcblxuICAgIGlmIChyZXF1aXJlT3JnSWQgJiYgIW9yZ0lkKSB7XG4gICAgICByZXR1cm4gc2VuZEJhZFJlcXVlc3QocmVzLCAnT3JnYW5pemF0aW9uIElEIGlzIHJlcXVpcmVkJyk7XG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGhhbmRsZXIoeyByZXEsIHJlcywgY3R4LCBvcmdJZCwgdXNlcklkIH0pO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAvLyBEb24ndCBzZW5kIGFub3RoZXIgcmVzcG9uc2UgaWYgb25lIHdhcyBhbHJlYWR5IHNlbnRcbiAgICAgIGlmIChyZXMuaGVhZGVyc1NlbnQpIHtcbiAgICAgICAgbG9nZ2VyLmVycm9yKCdSb3V0ZSBoYW5kbGVyIGVycm9yIGFmdGVyIHJlc3BvbnNlIHNlbnQnLCB7XG4gICAgICAgICAgcmVxdWVzdElkOiBjdHgucmVxdWVzdElkLFxuICAgICAgICAgIGVycm9yOiBzYWZlRXJyb3JGb3JMb2coZXJyb3IpLFxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBBcHBFcnJvcikge1xuICAgICAgICBjb25zdCBzdGF0dXMgPSBlcnJvci5zdGF0dXNDb2RlID49IDQwMCAmJiBlcnJvci5zdGF0dXNDb2RlIDwgNjAwXG4gICAgICAgICAgPyBlcnJvci5zdGF0dXNDb2RlXG4gICAgICAgICAgOiA1MDA7XG4gICAgICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBzdGF0dXMsIGVycm9yLm1lc3NhZ2UsIGVycm9yLmNvZGUpO1xuICAgICAgfVxuXG4gICAgICAvLyBVbmhhbmRsZWQgZXJyb3Ig4oaSIDUwMC4gTkVWRVIgZWNobyB0aGUgcmF3IG1lc3NhZ2UgdG8gdGhlIGNsaWVudDogREIgZHJpdmVyXG4gICAgICAvLyBlcnJvcnMgY2FycnkgdGhlIFNRTCArIGJvdW5kIHBhcmFtcywgYW5kIENydWRTZXJ2aWNlIGRlbGliZXJhdGVseSBsZXRzIHRoZW1cbiAgICAgIC8vIHByb3BhZ2F0ZSBoZXJlLiBTZW5kIGEgZ2VuZXJpYyBtZXNzYWdlICsgcmVxdWVzdElkICh0byBjb3JyZWxhdGUgd2l0aCBsb2dzKSxcbiAgICAgIC8vIGFuZCBsb2cgb25seSBzYW5pdGl6ZWQgREIgbWV0YWRhdGEgKGNvZGUvY29uc3RyYWludC90YWJsZSDigJQgbm8gU1FML3BhcmFtcykuXG4gICAgICBjb25zdCBkYiA9IGV4dHJhY3REYkVycm9yKGVycm9yKTtcbiAgICAgIGN0eC5sb2coJ0VSUk9SJywgJ1JlcXVlc3QgZmFpbGVkJywge1xuICAgICAgICByZXF1ZXN0SWQ6IGN0eC5yZXF1ZXN0SWQsXG4gICAgICAgIGVycm9yOiBzYWZlRXJyb3JGb3JMb2coZXJyb3IpLFxuICAgICAgICAuLi4oT2JqZWN0LmtleXMoZGIpLmxlbmd0aCA/IHsgZGIgfSA6IHt9KSxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIHNlbmRJbnRlcm5hbEVycm9yKHJlcywgJ0ludGVybmFsIHNlcnZlciBlcnJvcicsIHsgcmVxdWVzdElkOiBjdHgucmVxdWVzdElkIH0pO1xuICAgIH1cbiAgfTtcbn1cbiJdfQ==
84
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUtd3JhcHBlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hcGkvcm91dGUtd3JhcHBlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDLE9BQU8sRUFDTCxRQUFRLEVBQ1IsWUFBWSxFQUNaLGNBQWMsRUFDZCxTQUFTLEVBQ1QsY0FBYyxFQUNkLGlCQUFpQixFQUNqQixZQUFZLEdBQ2IsTUFBTSw0QkFBNEIsQ0FBQztBQUVwQyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFHOUMsTUFBTSxNQUFNLEdBQUcsWUFBWSxDQUFDLGVBQWUsQ0FBQyxDQUFDO0FBRTdDOzs7OztHQUtHO0FBQ0gsU0FBUyxlQUFlLENBQUMsS0FBYztJQUNyQyxJQUFJLEtBQUssWUFBWSxLQUFLLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsZUFBZSxDQUFDLEVBQUUsQ0FBQztRQUN4RSxPQUFPLEdBQUcsS0FBSyxDQUFDLElBQUksSUFBSSxtQkFBbUIseUJBQXlCLENBQUM7SUFDdkUsQ0FBQztJQUNELE9BQU8sWUFBWSxDQUFDLEtBQUssQ0FBQyxDQUFDO0FBQzdCLENBQUM7QUE4QkQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBb0JHO0FBQ0gsTUFBTSxVQUFVLFNBQVMsQ0FDdkIsT0FBNEMsRUFDNUMsT0FBTyxHQUFxQixFQUFFO0lBRTlCLE1BQU0sRUFBRSxZQUFZLEdBQUcsSUFBSSxFQUFFLEdBQUcsT0FBTyxDQUFDO0lBRXhDLE9BQU8sS0FBSyxFQUFFLEdBQVksRUFBRSxHQUFhLEVBQUUsRUFBRTtRQUMzQyxNQUFNLEdBQUcsR0FBRyxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDNUIsd0VBQXdFO1FBQ3hFLDZFQUE2RTtRQUM3RSxNQUFNLEtBQUssR0FBRyxHQUFHLENBQUMsUUFBUSxDQUFDLEtBQUssSUFBSSxFQUFFLENBQUM7UUFDdkMsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLFFBQVEsQ0FBQyxNQUFNLElBQUksRUFBRSxDQUFDO1FBRXpDLElBQUksWUFBWSxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDM0IsT0FBTyxjQUFjLENBQUMsR0FBRyxFQUFFLDZCQUE2QixDQUFDLENBQUM7UUFDNUQsQ0FBQztRQUVELElBQUksQ0FBQztZQUNILE1BQU0sT0FBTyxDQUFDLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUM7UUFDbEQsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixzREFBc0Q7WUFDdEQsSUFBSSxHQUFHLENBQUMsV0FBVyxFQUFFLENBQUM7Z0JBQ3BCLE1BQU0sQ0FBQyxLQUFLLENBQUMseUNBQXlDLEVBQUU7b0JBQ3RELFNBQVMsRUFBRSxHQUFHLENBQUMsU0FBUztvQkFDeEIsS0FBSyxFQUFFLGVBQWUsQ0FBQyxLQUFLLENBQUM7aUJBQzlCLENBQUMsQ0FBQztnQkFDSCxPQUFPO1lBQ1QsQ0FBQztZQUVELElBQUksS0FBSyxZQUFZLFFBQVEsRUFBRSxDQUFDO2dCQUM5QixNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsVUFBVSxJQUFJLEdBQUcsSUFBSSxLQUFLLENBQUMsVUFBVSxHQUFHLEdBQUc7b0JBQzlELENBQUMsQ0FBQyxLQUFLLENBQUMsVUFBVTtvQkFDbEIsQ0FBQyxDQUFDLEdBQUcsQ0FBQztnQkFDUixPQUFPLEtBQUssQ0FBQyxPQUFPLEtBQUssU0FBUztvQkFDaEMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxHQUFHLEVBQUUsTUFBTSxFQUFFLEtBQUssQ0FBQyxPQUFPLEVBQUUsS0FBSyxDQUFDLElBQUksQ0FBQztvQkFDbkQsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxHQUFHLEVBQUUsTUFBTSxFQUFFLEtBQUssQ0FBQyxPQUFPLEVBQUUsS0FBSyxDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDdkUsQ0FBQztZQUVELDZFQUE2RTtZQUM3RSw4RUFBOEU7WUFDOUUsK0VBQStFO1lBQy9FLDhFQUE4RTtZQUM5RSxNQUFNLEVBQUUsR0FBRyxjQUFjLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDakMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUU7Z0JBQ2pDLFNBQVMsRUFBRSxHQUFHLENBQUMsU0FBUztnQkFDeEIsS0FBSyxFQUFFLGVBQWUsQ0FBQyxLQUFLLENBQUM7Z0JBQzdCLEdBQUcsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO2FBQzFDLENBQUMsQ0FBQztZQUNILE9BQU8saUJBQWlCLENBQUMsR0FBRyxFQUFFLHVCQUF1QixFQUFFLEVBQUUsU0FBUyxFQUFFLEdBQUcsQ0FBQyxTQUFTLEVBQUUsQ0FBQyxDQUFDO1FBQ3ZGLENBQUM7SUFDSCxDQUFDLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCB7XG4gIEFwcEVycm9yLFxuICBlcnJvck1lc3NhZ2UsXG4gIGV4dHJhY3REYkVycm9yLFxuICBzZW5kRXJyb3IsXG4gIHNlbmRCYWRSZXF1ZXN0LFxuICBzZW5kSW50ZXJuYWxFcnJvcixcbiAgY3JlYXRlTG9nZ2VyLFxufSBmcm9tICdAcGlwZWxpbmUtYnVpbGRlci9hcGktY29yZSc7XG5pbXBvcnQgdHlwZSB7IFJlcXVlc3QsIFJlc3BvbnNlLCBSZXF1ZXN0SGFuZGxlciB9IGZyb20gJ2V4cHJlc3MnO1xuaW1wb3J0IHsgZ2V0Q29udGV4dCB9IGZyb20gJy4vZ2V0LWNvbnRleHQuanMnO1xuaW1wb3J0IHR5cGUgeyBSZXF1ZXN0Q29udGV4dCB9IGZyb20gJy4vcmVxdWVzdC10eXBlcy5qcyc7XG5cbmNvbnN0IGxvZ2dlciA9IGNyZWF0ZUxvZ2dlcigncm91dGUtd3JhcHBlcicpO1xuXG4vKipcbiAqIEEgbG9nLXNhZmUgcmVuZGVyaW5nIG9mIGFuIHVua25vd24gZXJyb3IuIGRyaXp6bGUtb3JtJ3MgYERyaXp6bGVRdWVyeUVycm9yYFxuICogZW1iZWRzIHRoZSBmYWlsZWQgU1FMIHN0YXRlbWVudCBBTkQgdGhlIGJvdW5kIHBhcmFtZXRlciB2YWx1ZXMgKHJlYWwgZGF0YSkgaW5cbiAqIGl0cyBgLm1lc3NhZ2VgIChgRmFpbGVkIHF1ZXJ5OiA8c3FsPlxcbnBhcmFtczogPHZhbHVlcz5gKS4gTmV2ZXIgcHV0IHRoYXQgaW4gYVxuICogcmVzcG9uc2Ugb3IgYSBsb2cgbGluZSDigJQgY29sbGFwc2UgaXQgdG8gdGhlIGVycm9yIG5hbWUuIE90aGVyIGVycm9ycyBhcmUgc2FmZS5cbiAqL1xuZnVuY3Rpb24gc2FmZUVycm9yRm9yTG9nKGVycm9yOiB1bmtub3duKTogc3RyaW5nIHtcbiAgaWYgKGVycm9yIGluc3RhbmNlb2YgRXJyb3IgJiYgZXJyb3IubWVzc2FnZS5zdGFydHNXaXRoKCdGYWlsZWQgcXVlcnk6JykpIHtcbiAgICByZXR1cm4gYCR7ZXJyb3IubmFtZSB8fCAnRHJpenpsZVF1ZXJ5RXJyb3InfTogZGF0YWJhc2UgcXVlcnkgZmFpbGVkYDtcbiAgfVxuICByZXR1cm4gZXJyb3JNZXNzYWdlKGVycm9yKTtcbn1cblxuLyoqXG4gKiBDb250ZXh0IG9iamVjdCBwYXNzZWQgdG8gZXZlcnkgcm91dGUgaGFuZGxlciB3cmFwcGVkIHdpdGggYHdpdGhSb3V0ZSgpYC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBSb3V0ZUNvbnRleHQge1xuICAvKiogT3JpZ2luYWwgRXhwcmVzcyByZXF1ZXN0ICovXG4gIHJlcTogUmVxdWVzdDtcbiAgLyoqIE9yaWdpbmFsIEV4cHJlc3MgcmVzcG9uc2UgKi9cbiAgcmVzOiBSZXNwb25zZTtcbiAgLyoqIFJlcXVlc3QgY29udGV4dCB3aXRoIGlkZW50aXR5IGFuZCBsb2dnaW5nICovXG4gIGN0eDogUmVxdWVzdENvbnRleHQ7XG4gIC8qKiBMb3dlcmNhc2VkIG9yZ2FuaXphdGlvbiBJRCAoZ3VhcmFudGVlZCBub24tZW1wdHkgd2hlbiByZXF1aXJlT3JnSWQgaXMgdHJ1ZSkgKi9cbiAgb3JnSWQ6IHN0cmluZztcbiAgLyoqIFVzZXIgSUQgZnJvbSBKV1QgKGRlZmF1bHRzIHRvIGVtcHR5IHN0cmluZykgKi9cbiAgdXNlcklkOiBzdHJpbmc7XG59XG5cbi8qKlxuICogT3B0aW9ucyBmb3IgYHdpdGhSb3V0ZSgpYC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBXaXRoUm91dGVPcHRpb25zIHtcbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gcmVxdWlyZSBvcmdJZCBvbiB0aGUgcmVxdWVzdC5cbiAgICogV2hlbiB0cnVlIChkZWZhdWx0KSwgcmV0dXJucyA0MDAgaWYgb3JnSWQgaXMgbWlzc2luZy5cbiAgICogU2V0IHRvIGZhbHNlIGZvciByb3V0ZXMgdGhhdCBkb24ndCBuZWVkIG9yZyBjb250ZXh0LlxuICAgKi9cbiAgcmVxdWlyZU9yZ0lkPzogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBXcmFwIGFuIGFzeW5jIHJvdXRlIGhhbmRsZXIgd2l0aCBzdGFuZGFyZCBib2lsZXJwbGF0ZS5cbiAqXG4gKiBFeHRyYWN0cyBjb250ZXh0LCBvcmdJZCwgdXNlcklkIGZyb20gdGhlIHJlcXVlc3QsIHZhbGlkYXRlcyBvcmdJZCxcbiAqIGFuZCBjYXRjaGVzIGVycm9ycy4gVHlwZWQgYEFwcEVycm9yYCBzdWJjbGFzc2VzIGFyZSBhdXRvbWF0aWNhbGx5XG4gKiBtYXBwZWQgdG8gdGhlIGNvcnJlY3QgSFRUUCByZXNwb25zZS5cbiAqXG4gKiBAcGFyYW0gaGFuZGxlciAtIEFzeW5jIGZ1bmN0aW9uIHJlY2VpdmluZyBhIFJvdXRlQ29udGV4dFxuICogQHBhcmFtIG9wdGlvbnMgLSBDb25maWd1cmF0aW9uIG9wdGlvbnNcbiAqIEByZXR1cm5zIEV4cHJlc3MgUmVxdWVzdEhhbmRsZXJcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogcm91dGVyLmdldCgnLzppZCcsIHdpdGhSb3V0ZShhc3luYyAoeyByZXEsIHJlcywgY3R4LCBvcmdJZCB9KSA9PiB7XG4gKiAgIGNvbnN0IGlkID0gZ2V0UGFyYW0ocmVxLnBhcmFtcywgJ2lkJyk7XG4gKiAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBpcGVsaW5lU2VydmljZS5maW5kQnlJZChpZCwgb3JnSWQpO1xuICogICBpZiAoIXJlc3VsdCkgdGhyb3cgbmV3IE5vdEZvdW5kRXJyb3IoJ1BpcGVsaW5lIG5vdCBmb3VuZCcpO1xuICogICByZXR1cm4gc2VuZFN1Y2Nlc3MocmVzLCAyMDAsIHsgcGlwZWxpbmU6IHJlc3VsdCB9KTtcbiAqIH0pKTtcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gd2l0aFJvdXRlKFxuICBoYW5kbGVyOiAocmM6IFJvdXRlQ29udGV4dCkgPT4gUHJvbWlzZTx2b2lkPixcbiAgb3B0aW9uczogV2l0aFJvdXRlT3B0aW9ucyA9IHt9LFxuKTogUmVxdWVzdEhhbmRsZXIge1xuICBjb25zdCB7IHJlcXVpcmVPcmdJZCA9IHRydWUgfSA9IG9wdGlvbnM7XG5cbiAgcmV0dXJuIGFzeW5jIChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UpID0+IHtcbiAgICBjb25zdCBjdHggPSBnZXRDb250ZXh0KHJlcSk7XG4gICAgLy8gYGlkZW50aXR5Lm9yZ0lkYCBpcyBhbHJlYWR5IG5vcm1hbGl6ZWQgKHRyaW1tZWQgKyBsb3dlcmNhc2VkKSBvbmNlIGF0XG4gICAgLy8gcmVzb2x1dGlvbiBpbiBhcGktY29yZSdzIGBnZXRJZGVudGl0eWAsIHNvIGl0IG1hdGNoZXMgdGhlIFJMUyBHVUMgZXhhY3RseS5cbiAgICBjb25zdCBvcmdJZCA9IGN0eC5pZGVudGl0eS5vcmdJZCB8fCAnJztcbiAgICBjb25zdCB1c2VySWQgPSBjdHguaWRlbnRpdHkudXNlcklkIHx8ICcnO1xuXG4gICAgaWYgKHJlcXVpcmVPcmdJZCAmJiAhb3JnSWQpIHtcbiAgICAgIHJldHVybiBzZW5kQmFkUmVxdWVzdChyZXMsICdPcmdhbml6YXRpb24gSUQgaXMgcmVxdWlyZWQnKTtcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgYXdhaXQgaGFuZGxlcih7IHJlcSwgcmVzLCBjdHgsIG9yZ0lkLCB1c2VySWQgfSk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIC8vIERvbid0IHNlbmQgYW5vdGhlciByZXNwb25zZSBpZiBvbmUgd2FzIGFscmVhZHkgc2VudFxuICAgICAgaWYgKHJlcy5oZWFkZXJzU2VudCkge1xuICAgICAgICBsb2dnZXIuZXJyb3IoJ1JvdXRlIGhhbmRsZXIgZXJyb3IgYWZ0ZXIgcmVzcG9uc2Ugc2VudCcsIHtcbiAgICAgICAgICByZXF1ZXN0SWQ6IGN0eC5yZXF1ZXN0SWQsXG4gICAgICAgICAgZXJyb3I6IHNhZmVFcnJvckZvckxvZyhlcnJvciksXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIEFwcEVycm9yKSB7XG4gICAgICAgIGNvbnN0IHN0YXR1cyA9IGVycm9yLnN0YXR1c0NvZGUgPj0gNDAwICYmIGVycm9yLnN0YXR1c0NvZGUgPCA2MDBcbiAgICAgICAgICA/IGVycm9yLnN0YXR1c0NvZGVcbiAgICAgICAgICA6IDUwMDtcbiAgICAgICAgcmV0dXJuIGVycm9yLmRldGFpbHMgPT09IHVuZGVmaW5lZFxuICAgICAgICAgID8gc2VuZEVycm9yKHJlcywgc3RhdHVzLCBlcnJvci5tZXNzYWdlLCBlcnJvci5jb2RlKVxuICAgICAgICAgIDogc2VuZEVycm9yKHJlcywgc3RhdHVzLCBlcnJvci5tZXNzYWdlLCBlcnJvci5jb2RlLCBlcnJvci5kZXRhaWxzKTtcbiAgICAgIH1cblxuICAgICAgLy8gVW5oYW5kbGVkIGVycm9yIOKGkiA1MDAuIE5FVkVSIGVjaG8gdGhlIHJhdyBtZXNzYWdlIHRvIHRoZSBjbGllbnQ6IERCIGRyaXZlclxuICAgICAgLy8gZXJyb3JzIGNhcnJ5IHRoZSBTUUwgKyBib3VuZCBwYXJhbXMsIGFuZCBDcnVkU2VydmljZSBkZWxpYmVyYXRlbHkgbGV0cyB0aGVtXG4gICAgICAvLyBwcm9wYWdhdGUgaGVyZS4gU2VuZCBhIGdlbmVyaWMgbWVzc2FnZSArIHJlcXVlc3RJZCAodG8gY29ycmVsYXRlIHdpdGggbG9ncyksXG4gICAgICAvLyBhbmQgbG9nIG9ubHkgc2FuaXRpemVkIERCIG1ldGFkYXRhIChjb2RlL2NvbnN0cmFpbnQvdGFibGUg4oCUIG5vIFNRTC9wYXJhbXMpLlxuICAgICAgY29uc3QgZGIgPSBleHRyYWN0RGJFcnJvcihlcnJvcik7XG4gICAgICBjdHgubG9nKCdFUlJPUicsICdSZXF1ZXN0IGZhaWxlZCcsIHtcbiAgICAgICAgcmVxdWVzdElkOiBjdHgucmVxdWVzdElkLFxuICAgICAgICBlcnJvcjogc2FmZUVycm9yRm9yTG9nKGVycm9yKSxcbiAgICAgICAgLi4uKE9iamVjdC5rZXlzKGRiKS5sZW5ndGggPyB7IGRiIH0gOiB7fSksXG4gICAgICB9KTtcbiAgICAgIHJldHVybiBzZW5kSW50ZXJuYWxFcnJvcihyZXMsICdJbnRlcm5hbCBzZXJ2ZXIgZXJyb3InLCB7IHJlcXVlc3RJZDogY3R4LnJlcXVlc3RJZCB9KTtcbiAgICB9XG4gIH07XG59XG4iXX0=
package/lib/api/server.js CHANGED
@@ -1,21 +1,20 @@
1
1
  // Copyright 2026 Pipeline Builder Contributors
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
  import { Server } from 'http';
4
- import { buildRouteTable, createLogger, errorMessage, installCrashHandlers, nextBackoffMs, resolveRedisConnection, retryForever, summarizeRouteTable } from '@pipeline-builder/api-core';
4
+ import { buildRouteTable, createLogger, errorMessage, installCrashHandlers, nextBackoffMs, resolveRedisConnection, retryForever, summarizeRouteTable, sleep, envInt } 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';
8
8
  import { shutdownTracing } from './tracing.js';
9
9
  import { SSEManager } from '../http/sse-connection-manager.js';
10
10
  const logger = createLogger('server');
11
- const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
12
11
  // Dependency-supervisor cadence. Initial connect retries with capped backoff;
13
12
  // once connected, re-checks at a steady interval so a later outage flips the
14
13
  // service NotReady (draining traffic) and a recovery flips it back — without
15
14
  // ever exiting / restarting the process.
16
15
  const READY_RETRY_BASE_MS = 1000;
17
16
  const READY_RETRY_MAX_MS = 10000;
18
- const READY_MONITOR_INTERVAL_MS = parseInt(process.env.READINESS_MONITOR_INTERVAL_MS || '15000', 10);
17
+ const READY_MONITOR_INTERVAL_MS = envInt('READINESS_MONITOR_INTERVAL_MS', 15_000, { min: 1 });
19
18
  /**
20
19
  * Establish and continuously monitor the service's datastore dependency,
21
20
  * flipping readiness state instead of crash-looping.
@@ -41,6 +40,8 @@ async function superviseDependencies(name, onBeforeStart, testDatabase, aborted)
41
40
  }
42
41
  // No datastore to gate on → ready as soon as we are listening.
43
42
  if (testDatabase === false) {
43
+ if (aborted())
44
+ return; // shutdown began while we were initializing
44
45
  setReady(true);
45
46
  logger.info(`${name} ready (no datastore dependency)`);
46
47
  return;
@@ -55,6 +56,10 @@ async function superviseDependencies(name, onBeforeStart, testDatabase, aborted)
55
56
  catch {
56
57
  ok = false;
57
58
  }
59
+ // A probe that was in flight when shutdown began must not flip the
60
+ // draining instance back to ready.
61
+ if (aborted())
62
+ break;
58
63
  if (ok && !isReady()) {
59
64
  setReady(true);
60
65
  waitDelay = READY_RETRY_BASE_MS;
@@ -108,7 +113,7 @@ export async function startServer(app, options = {}) {
108
113
  // Validate auth configuration at server startup (not during CDK synthesis)
109
114
  Config.validateAuth();
110
115
  // Fail fast if this service has no internal signing key of its own, or no
111
- // public bundle to verify its peers with (#14). Without them it would mint
116
+ // public bundle to verify its peers with. Without them it would mint
112
117
  // tokens on an EPHEMERAL in-process key that no peer accepts, and reject every
113
118
  // peer's token — i.e. silently lose all service-to-service traffic. Checked
114
119
  // HERE rather than in `createApp` because it is a property of the running
@@ -155,9 +160,21 @@ export async function startServer(app, options = {}) {
155
160
  if (shuttingDown)
156
161
  return;
157
162
  shuttingDown = true;
163
+ // Drain FIRST: report NotReady before anything else, so the load balancer /
164
+ // readiness probe stops sending new work while the rest of shutdown runs.
165
+ // (Previously readiness stayed green through onShutdown, which could take
166
+ // seconds — new requests kept arriving at a process tearing itself down.)
167
+ setReady(false);
158
168
  if (signal) {
159
169
  logger.info(`${signal} received, shutting down gracefully...`);
160
170
  }
171
+ // Arm the force-exit BEFORE awaiting anything: a hung onShutdown (a stuck
172
+ // queue close, a Redis quit that never answers) would otherwise block forever
173
+ // with the timer never started, so the pod would ignore SIGTERM until SIGKILL.
174
+ setTimeout(() => {
175
+ logger.error('Forced shutdown after timeout');
176
+ process.exit(1);
177
+ }, shutdownTimeoutMs).unref();
161
178
  // Custom shutdown callback
162
179
  if (onShutdown) {
163
180
  try {
@@ -194,11 +211,6 @@ export async function startServer(app, options = {}) {
194
211
  }
195
212
  process.exit(0);
196
213
  });
197
- // Force shutdown after timeout
198
- setTimeout(() => {
199
- logger.error('Forced shutdown after timeout');
200
- process.exit(1);
201
- }, shutdownTimeoutMs).unref();
202
214
  };
203
215
  // Register signal handlers
204
216
  process.once('SIGINT', () => void shutdown('SIGINT'));
@@ -246,4 +258,4 @@ export function runServer(app, options = {}) {
246
258
  process.exit(1);
247
259
  });
248
260
  }
249
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FwaS9zZXJ2ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0QyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzlCLE9BQU8sRUFBRSxlQUFlLEVBQUUsWUFBWSxFQUFFLFlBQVksRUFBRSxvQkFBb0IsRUFBRSxhQUFhLEVBQUUsc0JBQXNCLEVBQUUsWUFBWSxFQUFFLG1CQUFtQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDekwsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ3pELE9BQU8sRUFBRSxhQUFhLEVBQUUsZUFBZSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFFakYsT0FBTyxFQUFFLFFBQVEsRUFBRSxPQUFPLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNuRCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQy9DLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUUvRCxNQUFNLE1BQU0sR0FBRyxZQUFZLENBQUMsUUFBUSxDQUFDLENBQUM7QUFFdEMsTUFBTSxLQUFLLEdBQUcsQ0FBQyxFQUFVLEVBQWlCLEVBQUUsQ0FBQyxJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO0FBRS9GLDhFQUE4RTtBQUM5RSw2RUFBNkU7QUFDN0UsNkVBQTZFO0FBQzdFLHlDQUF5QztBQUN6QyxNQUFNLG1CQUFtQixHQUFHLElBQUksQ0FBQztBQUNqQyxNQUFNLGtCQUFrQixHQUFHLEtBQUssQ0FBQztBQUNqQyxNQUFNLHlCQUF5QixHQUFHLFFBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLDZCQUE2QixJQUFJLE9BQU8sRUFBRSxFQUFFLENB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QUFRLEVBQUUsR0FBRyxFQUFFLENBQUMsUUFBUSxFQUFFO0tBQzNCLENBQUM7QUFDSixDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7R0FhRztBQUNILE1BQU0sVUFBVSxTQUFTLENBQUMsR0FBWSxFQUFFLE9BQU8sR0FBdUIsRUFBRTtJQUN0RSw4RUFBOEU7SUFDOUUsOEVBQThFO0lBQzlFLHdFQUF3RTtJQUN4RSwyQkFBMkI7SUFDM0IsTUFBTSxDQUFDLElBQUksQ0FBQyxtQkFBbUIsRUFBRSxtQkFBbUIsQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBRTVFLHlFQUF5RTtJQUN6RSx5RUFBeUU7SUFDekUsNEVBQTRFO0lBQzVFLG9CQUFvQixDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQzdCLFdBQVcsQ0FBQyxHQUFHLEVBQUUsT0FBTyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUU7UUFDeEMsNEVBQTRFO1FBQzVFLDJFQUEyRTtRQUMzRSw0RUFBNEU7UUFDNUUscUVBQXFFO1FBQ3JFLDZFQUE2RTtRQUM3RSxNQUFNLENBQUMsS0FBSyxDQUFDLHdCQUF3QixFQUFFO1lBQ3JDLEtBQUssRUFBRSxZQUFZLENBQUMsS0FBSyxDQUFDO1lBQzFCLEtBQUssRUFBRSxLQUFLLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxTQUFTO1NBQ3hELENBQUMsQ0FBQztRQUNILE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDbEIsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCB7IFNlcnZlciB9IGZyb20gJ2h0dHAnO1xuaW1wb3J0IHsgYnVpbGRSb3V0ZVRhYmxlLCBjcmVhdGVMb2dnZXIsIGVycm9yTWVzc2FnZSwgaW5zdGFsbENyYXNoSGFuZGxlcnMsIG5leHRCYWNrb2ZmTXMsIHJlc29sdmVSZWRpc0Nvbm5lY3Rpb24sIHJldHJ5Rm9yZXZlciwgc3VtbWFyaXplUm91dGVUYWJsZSB9IGZyb20gJ0BwaXBlbGluZS1idWlsZGVyL2FwaS1jb3JlJztcbmltcG9ydCB7IENvbmZpZyB9IGZyb20gJ0BwaXBlbGluZS1idWlsZGVyL3BpcGVsaW5lLWNvcmUnO1xuaW1wb3J0IHsgZ2V0Q29ubmVjdGlvbiwgY2xvc2VDb25uZWN0aW9uIH0gZnJvbSAnQHBpcGVsaW5lLWJ1aWxkZXIvcGlwZWxpbmUtZGF0YSc7XG5pbXBvcnQgdHlwZSB7IEV4cHJlc3MgfSBmcm9tICdleHByZXNzJztcbmltcG9ydCB7IHNldFJlYWR5LCBpc1JlYWR5IH0gZnJvbSAnLi9yZWFkaW5lc3MuanMnO1xuaW1wb3J0IHsgc2h1dGRvd25UcmFjaW5nIH0gZnJvbSAnLi90cmFjaW5nLmpzJztcbmltcG9ydCB7IFNTRU1hbmFnZXIgfSBmcm9tICcuLi9odHRwL3NzZS1jb25uZWN0aW9uLW1hbmFnZXIuanMnO1xuXG5jb25zdCBsb2dnZXIgPSBjcmVhdGVMb2dnZXIoJ3NlcnZlcicpO1xuXG5jb25zdCBzbGVlcCA9IChtczogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiA9PiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gc2V0VGltZW91dChyZXNvbHZlLCBtcykpO1xuXG4vLyBEZXBlbmRlbmN5LXN1cGVydmlzb3IgY2FkZW5jZS4gSW5pdGlhbCBjb25uZWN0IHJldHJpZXMgd2l0aCBjYXBwZWQgYmFja29mZjtcbi8vIG9uY2UgY29ubmVjdGVkLCByZS1jaGVja3MgYXQgYSBzdGVhZHkgaW50ZXJ2YWwgc28gYSBsYXRlciBvdXRhZ2UgZmxpcHMgdGhlXG4vLyBzZXJ2aWNlIE5vdFJlYWR5IChkcmFpbmluZyB0cmFmZmljKSBhbmQgYSByZWNvdmVyeSBmbGlwcyBpdCBiYWNrIOKAlCB3aXRob3V0XG4vLyBldmVyIGV4aXRpbmcgLyByZXN0YXJ0aW5nIHRoZSBwcm9jZXNzLlxuY29uc3QgUkVBRFlfUkVUUllfQkFTRV9NUyA9IDEwMDA7XG5jb25zdCBSRUFEWV9SRVRSWV9NQVhfTVMgPSAxMDAwMDtcbmNvbnN0IFJFQURZX01PTklUT1JfSU5URVJWQUxfTVMgPSBwYXJzZUludChwcm9jZXNzLmVudi5SRUFESU5FU1NfTU9OSVRPUl9JTlRFUlZBTF9NUyB8fCAnMTUwMDAnLCAxMCk7XG5cbi8qKlxuICogRXN0YWJsaXNoIGFuZCBjb250aW51b3VzbHkgbW9uaXRvciB0aGUgc2VydmljZSdzIGRhdGFzdG9yZSBkZXBlbmRlbmN5LFxuICogZmxpcHBpbmcgcmVhZGluZXNzIHN0YXRlIGluc3RlYWQgb2YgY3Jhc2gtbG9vcGluZy5cbiAqXG4gKiAtIEVzdGFibGlzaCBwaGFzZTogcmV0cnkgYG9uQmVmb3JlU3RhcnRgIChlLmcuIGNvbm5lY3RNb25nbykgd2l0aCBjYXBwZWRcbiAqICAgYmFja29mZiB1bnRpbCBpdCBzdWNjZWVkcyDigJQgYSBjb2xkIGRhdGFzdG9yZSBtdXN0IG5ldmVyIGV4aXQgdGhlIHByb2Nlc3MuXG4gKiAtIE1vbml0b3IgcGhhc2U6IHBvbGwgYHRlc3REYXRhYmFzZWAgZm9yIHRoZSBsaWZlIG9mIHRoZSBwcm9jZXNzOyBmbGlwXG4gKiAgIHJlYWR5L05vdFJlYWR5IG9uIHRyYW5zaXRpb25zLiBXaGlsZSBOb3RSZWFkeSB0aGUgcmVhZGluZXNzIGd1YXJkIDUwM3NcbiAqICAgYnVzaW5lc3MgdHJhZmZpYyBhbmQgb3JjaGVzdHJhdG9yIHJlYWRpbmVzcyBwcm9iZXMgZHJhaW4gdGhlIGluc3RhbmNlLlxuICpcbiAqIFJ1bnMgaW4gdGhlIGJhY2tncm91bmQgKHRoZSBIVFRQIHNlcnZlciBpcyBhbHJlYWR5IGxpc3RlbmluZykuIFN0b3BzIHdoZW5cbiAqIGBhYm9ydGVkKClgIHJldHVybnMgdHJ1ZSAoZ3JhY2VmdWwgc2h1dGRvd24pLCBzbyBpdCBuZXZlciBrZWVwcyBhIGNsb3NpbmdcbiAqIHByb2Nlc3MgYWxpdmUuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHN1cGVydmlzZURlcGVuZGVuY2llcyhcbiAgbmFtZTogc3RyaW5nLFxuICBvbkJlZm9yZVN0YXJ0OiAoKCkgPT4gUHJvbWlzZTx2b2lkPikgfCB1bmRlZmluZWQsXG4gIHRlc3REYXRhYmFzZTogKCgpID0+IFByb21pc2U8Ym9vbGVhbj4pIHwgZmFsc2UgfCB1bmRlZmluZWQsXG4gIGFib3J0ZWQ6ICgpID0+IGJvb2xlYW4sXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgaWYgKG9uQmVmb3JlU3RhcnQpIHtcbiAgICBhd2FpdCByZXRyeUZvcmV2ZXIob25CZWZvcmVTdGFydCwge1xuICAgICAgYmFzZU1zOiBSRUFEWV9SRVRSWV9CQVNFX01TLFxuICAgICAgbWF4TXM6IFJFQURZX1JFVFJZX01BWF9NUyxcbiAgICAgIG9uQXR0ZW1wdEZhaWxlZDogKGVycm9yLCBkZWxheU1zKSA9PiBsb2dnZXIud2FybihcbiAgICAgICAgYCR7bmFtZX06IGRlcGVuZGVuY3kgaW5pdCBmYWlsZWQsIHJldHJ5aW5nIGluICR7ZGVsYXlNc31tc2AsXG4gICAgICAgIHsgZXJyb3I6IGVycm9yTWVzc2FnZShlcnJvcikgfSxcbiAgICAgICksXG4gICAgICBzaG91bGRDb250aW51ZTogKCkgPT4gIWFib3J0ZWQoKSxcbiAgICB9KTtcbiAgfVxuXG4gIC8vIE5vIGRhdGFzdG9yZSB0byBnYXRlIG9uIOKGkiByZWFkeSBhcyBzb29uIGFzIHdlIGFyZSBsaXN0ZW5pbmcuXG4gIGlmICh0ZXN0RGF0YWJhc2UgPT09IGZhbHNlKSB7XG4gICAgc2V0UmVhZHkodHJ1ZSk7XG4gICAgbG9nZ2VyLmluZm8oYCR7bmFtZX0gcmVhZHkgKG5vIGRhdGFzdG9yZSBkZXBlbmRlbmN5KWApO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnN0IHByb2JlID0gdGVzdERhdGFiYXNlID8/ICgoKSA9PiBnZXRDb25uZWN0aW9uKCkudGVzdENvbm5lY3Rpb24oKSk7XG4gIGxldCB3YWl0RGVsYXkgPSBSRUFEWV9SRVRSWV9CQVNFX01TO1xuICB3aGlsZSAoIWFib3J0ZWQoKSkge1xuICAgIGxldCBvayA9IGZhbHNlO1xuICAgIHRyeSB7XG4gICAgICBvayA9IGF3YWl0IHByb2JlKCk7XG4gICAgfSBjYXRjaCB7XG4gICAgICBvayA9IGZhbHNlO1xuICAgIH1cblxuICAgIGlmIChvayAmJiAhaXNSZWFkeSgpKSB7XG4gICAgICBzZXRSZWFkeSh0cnVlKTtcbiAgICAgIHdhaXREZWxheSA9IFJFQURZX1JFVFJZX0JBU0VfTVM7XG4gICAgICBsb2dnZXIuaW5mbyhgJHtuYW1lfSByZWFkeSDigJQgZGVwZW5kZW5jaWVzIGNvbm5lY3RlZGApO1xuICAgIH0gZWxzZSBpZiAoIW9rICYmIGlzUmVhZHkoKSkge1xuICAgICAgc2V0UmVhZHkoZmFsc2UpO1xuICAgICAgbG9nZ2VyLndhcm4oYCR7bmFtZX0gZGVncmFkZWQg4oCUIGRlcGVuZGVuY3kgY2hlY2sgZmFpbGluZyAobm93IE5vdFJlYWR5KWApO1xuICAgIH1cblxuICAgIC8vIFN0ZWFkeSBjYWRlbmNlIG9uY2UgcmVhZHk7IGZhc3RlciBiYWNrb2ZmIHdoaWxlIHdhaXRpbmcgc28gd2UgZmxpcCB0b1xuICAgIC8vIHJlYWR5IHByb21wdGx5IHdoZW4gdGhlIGRhdGFzdG9yZSBjb21lcyB1cC5cbiAgICBpZiAoaXNSZWFkeSgpKSB7XG4gICAgICBhd2FpdCBzbGVlcChSRUFEWV9NT05JVE9SX0lOVEVSVkFMX01TKTtcbiAgICB9IGVsc2Uge1xuICAgICAgYXdhaXQgc2xlZXAod2FpdERlbGF5KTtcbiAgICAgIHdhaXREZWxheSA9IG5leHRCYWNrb2ZmTXMod2FpdERlbGF5LCBSRUFEWV9SRVRSWV9NQVhfTVMpO1xuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIE9wdGlvbnMgZm9yIHN0YXJ0aW5nIGEgc2VydmVyXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU3RhcnRTZXJ2ZXJPcHRpb25zIHtcbiAgLyoqIFNlcnZpY2UgbmFtZSBmb3IgbG9nZ2luZyAqL1xuICBuYW1lPzogc3RyaW5nO1xuICAvKiogUG9ydCB0byBsaXN0ZW4gb24gKGRlZmF1bHQ6IGZyb20gY29uZmlnKSAqL1xuICBwb3J0PzogbnVtYmVyO1xuICAvKiogU1NFIG1hbmFnZXIgZm9yIGdyYWNlZnVsIHNodXRkb3duICovXG4gIHNzZU1hbmFnZXI/OiBTU0VNYW5hZ2VyO1xuICAvKiogU2h1dGRvd24gdGltZW91dCBpbiBtaWxsaXNlY29uZHMgKGRlZmF1bHQ6IDE1MDAwKSAqL1xuICBzaHV0ZG93blRpbWVvdXRNcz86IG51bWJlcjtcbiAgLyoqIENhbGxiYWNrIGFmdGVyIHNlcnZlciBzdGFydHMgKi9cbiAgb25TdGFydD86IChwb3J0OiBudW1iZXIpID0+IHZvaWQ7XG4gIC8qKiBDYWxsYmFjayBiZWZvcmUgc2h1dGRvd24gKi9cbiAgb25TaHV0ZG93bj86ICgpID0+IFByb21pc2U8dm9pZD47XG4gIC8qKiBSdW5zIGJlZm9yZSBkYXRhYmFzZSBjaGVjayAoZS5nLiwgaW5pdGlhbGl6ZSBleHRlcm5hbCBjb25uZWN0aW9ucykgKi9cbiAgb25CZWZvcmVTdGFydD86ICgpID0+IFByb21pc2U8dm9pZD47XG4gIC8qKiBDdXN0b20gZGF0YWJhc2UgaGVhbHRoIGNoZWNrLCBvciBmYWxzZSB0byBza2lwLiBEZWZhdWx0OiBQb3N0Z3JlU1FMIHRlc3RDb25uZWN0aW9uICovXG4gIHRlc3REYXRhYmFzZT86ICgoKSA9PiBQcm9taXNlPGJvb2xlYW4+KSB8IGZhbHNlO1xuICAvKiogQ3VzdG9tIGRhdGFiYXNlIGNsb3NlLCBvciBmYWxzZSB0byBza2lwLiBEZWZhdWx0OiBQb3N0Z3JlU1FMIGNsb3NlQ29ubmVjdGlvbiAqL1xuICBjbG9zZURhdGFiYXNlPzogKCgpID0+IFByb21pc2U8dm9pZD4pIHwgZmFsc2U7XG59XG5cbi8qKlxuICogUmVzdWx0IG9mIHN0YXJ0aW5nIGEgc2VydmVyXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU3RhcnRTZXJ2ZXJSZXN1bHQge1xuICAvKiogSFRUUCBzZXJ2ZXIgaW5zdGFuY2UgKi9cbiAgc2VydmVyOiBTZXJ2ZXI7XG4gIC8qKiBQb3J0IHRoZSBzZXJ2ZXIgaXMgbGlzdGVuaW5nIG9uICovXG4gIHBvcnQ6IG51bWJlcjtcbiAgLyoqIEZ1bmN0aW9uIHRvIG1hbnVhbGx5IHRyaWdnZXIgc2h1dGRvd24gKi9cbiAgc2h1dGRvd246ICgpID0+IFByb21pc2U8dm9pZD47XG59XG5cbi8qKlxuICogU3RhcnQgYW4gRXhwcmVzcyBzZXJ2ZXIgd2l0aCBncmFjZWZ1bCBzaHV0ZG93biBoYW5kbGluZ1xuICpcbiAqIEZlYXR1cmVzOlxuICogLSBBdXRvbWF0aWMgZGF0YWJhc2UgY29ubmVjdGlvbiB0ZXN0aW5nXG4gKiAtIEdyYWNlZnVsIHNodXRkb3duIG9uIFNJR0lOVC9TSUdURVJNXG4gKiAtIFNTRSBjb25uZWN0aW9uIGNsZWFudXBcbiAqIC0gQ29uZmlndXJhYmxlIHNodXRkb3duIHRpbWVvdXRcbiAqXG4gKiBAcGFyYW0gYXBwIC0gRXhwcmVzcyBhcHBsaWNhdGlvblxuICogQHBhcmFtIG9wdGlvbnMgLSBTZXJ2ZXIgb3B0aW9uc1xuICogQHJldHVybnMgU2VydmVyIGluc3RhbmNlIGFuZCBjb250cm9sIGZ1bmN0aW9uc1xuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjb25zdCB7IGFwcCwgc3NlTWFuYWdlciB9ID0gY3JlYXRlQXBwKCk7XG4gKlxuICogYXBwLnBvc3QoJy9hcGkvcmVzb3VyY2UnLCByZXF1aXJlQXV0aCwgaGFuZGxlcik7XG4gKlxuICogYXdhaXQgc3RhcnRTZXJ2ZXIoYXBwLCB7XG4gKiAgIG5hbWU6ICdNeSBNaWNyb3NlcnZpY2UnLFxuICogICBzc2VNYW5hZ2VyLFxuICogICBvblN0YXJ0OiAocG9ydCkgPT4gY29uc29sZS5sb2coYExpc3RlbmluZyBvbiAke3BvcnR9YCksXG4gKiB9KTtcbiAqIGBgYFxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc3RhcnRTZXJ2ZXIoXG4gIGFwcDogRXhwcmVzcyxcbiAgb3B0aW9uczogU3RhcnRTZXJ2ZXJPcHRpb25zID0ge30sXG4pOiBQcm9taXNlPFN0YXJ0U2VydmVyUmVzdWx0PiB7XG4gIGNvbnN0IHNlcnZlckNvbmZpZyA9IENvbmZpZy5nZXQoJ3NlcnZlcicpO1xuICBjb25zdCB7XG4gICAgbmFtZSA9ICdNaWNyb3NlcnZpY2UnLFxuICAgIHNzZU1hbmFnZXIsXG4gICAgc2h1dGRvd25UaW1lb3V0TXMgPSAxNTAwMCxcbiAgICBvblN0YXJ0LFxuICAgIG9uU2h1dGRvd24sXG4gICAgb25CZWZvcmVTdGFydCxcbiAgICB0ZXN0RGF0YWJhc2UsXG4gICAgY2xvc2VEYXRhYmFzZSxcbiAgfSA9IG9wdGlvbnM7XG4gIGNvbnN0IHBvcnQgPSBvcHRpb25zLnBvcnQgPz8gc2VydmVyQ29uZmlnLnBvcnQ7XG5cbiAgLy8gVmFsaWRhdGUgYXV0aCBjb25maWd1cmF0aW9uIGF0IHNlcnZlciBzdGFydHVwIChub3QgZHVyaW5nIENESyBzeW50aGVzaXMpXG4gIENvbmZpZy52YWxpZGF0ZUF1dGgoKTtcbiAgLy8gRmFpbCBmYXN0IGlmIHRoaXMgc2VydmljZSBoYXMgbm8gaW50ZXJuYWwgc2lnbmluZyBrZXkgb2YgaXRzIG93biwgb3Igbm9cbiAgLy8gcHVibGljIGJ1bmRsZSB0byB2ZXJpZnkgaXRzIHBlZXJzIHdpdGggKCMxNCkuIFdpdGhvdXQgdGhlbSBpdCB3b3VsZCBtaW50XG4gIC8vIHRva2VucyBvbiBhbiBFUEhFTUVSQUwgaW4tcHJvY2VzcyBrZXkgdGhhdCBubyBwZWVyIGFjY2VwdHMsIGFuZCByZWplY3QgZXZlcnlcbiAgLy8gcGVlcidzIHRva2VuIOKAlCBpLmUuIHNpbGVudGx5IGxvc2UgYWxsIHNlcnZpY2UtdG8tc2VydmljZSB0cmFmZmljLiBDaGVja2VkXG4gIC8vIEhFUkUgcmF0aGVyIHRoYW4gaW4gYGNyZWF0ZUFwcGAgYmVjYXVzZSBpdCBpcyBhIHByb3BlcnR5IG9mIHRoZSBydW5uaW5nXG4gIC8vIGRlcGxveW1lbnQsIG5vdCBvZiB0aGUgYXBwIG9iamVjdDogcm91dGUtdGFibGUgYnVpbGRlcnMgYW5kIHRlc3Qgc3VpdGVzXG4gIC8vIGFzc2VtYmxlIGFuIGFwcCB3aXRob3V0IGV2ZXIgc2lnbmluZyBhbnl0aGluZy5cbiAgZm9yIChjb25zdCBlbnZWYXIgb2YgWydTRVJWSUNFX1NJR05JTkdfS0VZX0ZJTEUnLCAnU0VSVklDRV9LRVlfQlVORExFX0ZJTEUnXSBhcyBjb25zdCkge1xuICAgIGlmICghcHJvY2Vzcy5lbnZbZW52VmFyXSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGAke2VudlZhcn0gZW52aXJvbm1lbnQgdmFyaWFibGUgaXMgcmVxdWlyZWQgKGdlbmVyYXRlIHdpdGggZGVwbG95L2Jpbi9zZXJ2aWNlLXNpZ25pbmcta2V5cy5zaCkuIFNldCBpdCBiZWZvcmUgc3RhcnRpbmcgdGhlIHNlcnZlci5gKTtcbiAgICB9XG4gIH1cbiAgLy8gRmFpbCBmYXN0IG9uIGFuIHVudXNhYmxlIFJlZGlzIGNvbmZpZ3VyYXRpb24gKHRocm93cyBSZWRpc0NvbmZpZ0Vycm9yKSDigJQgYVxuICAvLyBSZWRpcyBjbGllbnQgaXMgY3JlYXRlZCBsYXppbHkgb24gZmlyc3QgdXNlLCBzbyB3aXRob3V0IHRoaXMgYSBiYWQgY29uZmlnXG4gIC8vIHdvdWxkIHN1cmZhY2UgYXMgcmVxdWVzdC10aW1lIGVycm9ycyBpbnN0ZWFkIG9mIGEgZmFpbGVkIHN0YXJ0LlxuICByZXNvbHZlUmVkaXNDb25uZWN0aW9uKCk7XG5cbiAgbG9nZ2VyLmluZm8oYFN0YXJ0aW5nICR7bmFtZX0uLi5gKTtcblxuICAvLyBNYXJrIE5vdFJlYWR5IHN5bmNocm9ub3VzbHksIEJFRk9SRSB0aGUgcG9ydCBvcGVucywgc28gbm8gcmVxdWVzdCBzbGlwc1xuICAvLyB0aHJvdWdoIHRoZSByZWFkaW5lc3MgZ3VhcmQgYmVmb3JlIHRoZSBzdXBlcnZpc29yIGhhcyBydW4uIFRoZSBzdXBlcnZpc29yXG4gIC8vIGZsaXBzIGl0IHRydWUgb25jZSBkZXBlbmRlbmNpZXMgY29ubmVjdC5cbiAgc2V0UmVhZHkoZmFsc2UpO1xuXG4gIC8vIExpc3RlbiBGSVJTVC4gUHJldmlvdXNseSB0aGUgcHJvY2VzcyB0ZXN0ZWQgdGhlIERCIGFuZCBgcHJvY2Vzcy5leGl0KDEpYCdkXG4gIC8vIG9uIGZhaWx1cmUgKHRvIGJlIHJlc3RhcnRlZCksIHNvIGR1cmluZyBhIGNvbGQtREIgc3RhbXBlZGUgc2VydmljZXNcbiAgLy8gY3Jhc2gtbG9vcGVkIGFuZCBuZXZlciBldmVuIG9wZW5lZCB0aGVpciBwb3J0LiBOb3cgd2Ugb3BlbiB0aGUgcG9ydFxuICAvLyBpbW1lZGlhdGVseSDigJQgL2hlYWx0aCAobGl2ZW5lc3MpLCAvcmVhZHkgKHJlYWRpbmVzcykgYW5kIHRoZSByZWFkaW5lc3NcbiAgLy8gZ3VhcmQgYWxsIHJlc3BvbmQgYXQgb25jZSDigJQgYW5kIGVzdGFibGlzaCArIG1vbml0b3IgdGhlIGRhdGFzdG9yZSBpbiB0aGVcbiAgLy8gYmFja2dyb3VuZCwgcmVwb3J0aW5nIE5vdFJlYWR5IHVudGlsIGl0IGNvbm5lY3RzIGluc3RlYWQgb2YgZXhpdGluZy5cbiAgY29uc3Qgc2VydmVyID0gYXBwLmxpc3Rlbihwb3J0LCAoKSA9PiB7XG4gICAgbG9nZ2VyLmluZm8oYCR7bmFtZX0gbGlzdGVuaW5nIG9uIHBvcnQ6ICR7cG9ydH1gKTtcbiAgICBsb2dnZXIuaW5mbyhgUGxhdGZvcm0gVVJMOiAke3NlcnZlckNvbmZpZy5wbGF0Zm9ybVVybH1gKTtcbiAgICBvblN0YXJ0Py4ocG9ydCk7XG4gIH0pO1xuXG4gIC8vIFNodXRkb3duIGhhbmRsZXIgKGd1YXJkZWQgYWdhaW5zdCBjb25jdXJyZW50IHNpZ25hbHMpXG4gIGxldCBzaHV0dGluZ0Rvd24gPSBmYWxzZTtcblxuICAvLyBCYWNrZ3JvdW5kIGRlcGVuZGVuY3kgc3VwZXJ2aXNvciDigJQgZXN0YWJsaXNoZWQgKyBtb25pdG9yZWQgYWZ0ZXIgbGlzdGVuLFxuICAvLyBzdG9wcGVkIG9uIHNodXRkb3duIHNvIGl0IG5ldmVyIGtlZXBzIGEgY2xvc2luZyBwcm9jZXNzIGFsaXZlLiBHdWFyZCB0aGVcbiAgLy8gZmxvYXRpbmcgcHJvbWlzZTogZXZlcnkgZXhwZWN0ZWQgZmFpbHVyZSBpcyBoYW5kbGVkIGluc2lkZSwgc28gYSByZWplY3Rpb25cbiAgLy8gaGVyZSBtZWFucyBhIHByb2dyYW1taW5nIGVycm9yIOKAlCBsb2cgaXQgYW5kIGxlYXZlIHRoZSBzZXJ2aWNlIE5vdFJlYWR5XG4gIC8vIHJhdGhlciB0aGFuIGxldHRpbmcgaXQgYmVjb21lIGFuIHVuaGFuZGxlZFJlamVjdGlvbiB0aGF0IGNyYXNoLWV4aXRzIHRoZVxuICAvLyBwcm9jZXNzICh3aGljaCB3b3VsZCBkZWZlYXQgdGhlIHdob2xlIFwibmV2ZXIgZXhpdCBvbiBkZXBlbmRlbmN5IHRyb3VibGVcIlxuICAvLyBnb2FsKS5cbiAgc3VwZXJ2aXNlRGVwZW5kZW5jaWVzKG5hbWUsIG9uQmVmb3JlU3RhcnQsIHRlc3REYXRhYmFzZSwgKCkgPT4gc2h1dHRpbmdEb3duKS5jYXRjaCgoZXJyb3IpID0+IHtcbiAgICBsb2dnZXIuZXJyb3IoJ0RlcGVuZGVuY3kgc3VwZXJ2aXNvciBjcmFzaGVkOyBzZXJ2aWNlIHdpbGwgcmVtYWluIE5vdFJlYWR5JywgeyBlcnJvcjogZXJyb3JNZXNzYWdlKGVycm9yKSB9KTtcbiAgfSk7XG5cbiAgY29uc3Qgc2h1dGRvd24gPSBhc3luYyAoc2lnbmFsPzogc3RyaW5nKSA9PiB7XG4gICAgaWYgKHNodXR0aW5nRG93bikgcmV0dXJuO1xuICAgIHNodXR0aW5nRG93biA9IHRydWU7XG5cbiAgICBpZiAoc2lnbmFsKSB7XG4gICAgICBsb2dnZXIuaW5mbyhgJHtzaWduYWx9IHJlY2VpdmVkLCBzaHV0dGluZyBkb3duIGdyYWNlZnVsbHkuLi5gKTtcbiAgICB9XG5cbiAgICAvLyBDdXN0b20gc2h1dGRvd24gY2FsbGJhY2tcbiAgICBpZiAob25TaHV0ZG93bikge1xuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgb25TaHV0ZG93bigpO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgbG9nZ2VyLmVycm9yKCdFcnJvciBpbiBvblNodXRkb3duIGNhbGxiYWNrJywgeyBlcnJvciB9KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBDbG9zZSBTU0UgY29ubmVjdGlvbnNcbiAgICBpZiAoc3NlTWFuYWdlcikge1xuICAgICAgc3NlTWFuYWdlci5zaHV0ZG93bigpO1xuICAgICAgbG9nZ2VyLmluZm8oJ1NTRSBjb25uZWN0aW9ucyBjbG9zZWQnKTtcbiAgICB9XG5cbiAgICAvLyBDbG9zZSBIVFRQIHNlcnZlclxuICAgIHNlcnZlci5jbG9zZShhc3luYyAoKSA9PiB7XG4gICAgICBsb2dnZXIuaW5mbygnSFRUUCBzZXJ2ZXIgY2xvc2VkJyk7XG5cbiAgICAgIC8vIFNodXRkb3duIE9wZW5UZWxlbWV0cnkgdHJhY2luZ1xuICAgICAgYXdhaXQgc2h1dGRvd25UcmFjaW5nKCkuY2F0Y2goZXJyID0+IGxvZ2dlci5lcnJvcignRXJyb3Igc2h1dHRpbmcgZG93biB0cmFjaW5nJywgeyBlcnJvcjogZXJyIH0pKTtcblxuICAgICAgLy8gQ2xvc2UgZGF0YWJhc2UgY29ubmVjdGlvblxuICAgICAgaWYgKGNsb3NlRGF0YWJhc2UgIT09IGZhbHNlKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgaWYgKGNsb3NlRGF0YWJhc2UpIHtcbiAgICAgICAgICAgIGF3YWl0IGNsb3NlRGF0YWJhc2UoKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgYXdhaXQgY2xvc2VDb25uZWN0aW9uKCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGxvZ2dlci5pbmZvKCdEYXRhYmFzZSBjb25uZWN0aW9uIGNsb3NlZCcpO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIGxvZ2dlci5lcnJvcignRXJyb3IgY2xvc2luZyBkYXRhYmFzZScsIHsgZXJyb3IgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcHJvY2Vzcy5leGl0KDApO1xuICAgIH0pO1xuXG4gICAgLy8gRm9yY2Ugc2h1dGRvd24gYWZ0ZXIgdGltZW91dFxuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgbG9nZ2VyLmVycm9yKCdGb3JjZWQgc2h1dGRvd24gYWZ0ZXIgdGltZW91dCcpO1xuICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgIH0sIHNodXRkb3duVGltZW91dE1zKS51bnJlZigpO1xuICB9O1xuXG4gIC8vIFJlZ2lzdGVyIHNpZ25hbCBoYW5kbGVyc1xuICBwcm9jZXNzLm9uY2UoJ1NJR0lOVCcsICgpID0+IHZvaWQgc2h1dGRvd24oJ1NJR0lOVCcpKTtcbiAgcHJvY2Vzcy5vbmNlKCdTSUdURVJNJywgKCkgPT4gdm9pZCBzaHV0ZG93bignU0lHVEVSTScpKTtcblxuICByZXR1cm4ge1xuICAgIHNlcnZlcixcbiAgICBwb3J0LFxuICAgIHNodXRkb3duOiAoKSA9PiBzaHV0ZG93bigpLFxuICB9O1xufVxuXG4vKipcbiAqIFNpbXBsZSBzZXJ2ZXIgc3RhcnQgd3JhcHBlciB3aXRoIGVycm9yIGhhbmRsaW5nXG4gKlxuICogQHBhcmFtIGFwcCAtIEV4cHJlc3MgYXBwbGljYXRpb25cbiAqIEBwYXJhbSBvcHRpb25zIC0gU2VydmVyIG9wdGlvbnNcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogY29uc3QgeyBhcHAsIHNzZU1hbmFnZXIgfSA9IGNyZWF0ZUFwcCgpO1xuICogYXBwLnBvc3QoJy9hcGkvcmVzb3VyY2UnLCBoYW5kbGVyKTtcbiAqXG4gKiB2b2lkIHJ1blNlcnZlcihhcHAsIHsgbmFtZTogJ015IFNlcnZpY2UnLCBzc2VNYW5hZ2VyIH0pO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBydW5TZXJ2ZXIoYXBwOiBFeHByZXNzLCBvcHRpb25zOiBTdGFydFNlcnZlck9wdGlvbnMgPSB7fSk6IHZvaWQge1xuICAvLyBSb3V0ZSB0YWJsZSBvZiB0aGUgZnVsbHkgYXNzZW1ibGVkIGFwcCAoc2VlIGFwaS1jb3JlJ3Mgcm91dGUtdGFibGUudHMpOiB0aGVcbiAgLy8gc2FtZSBpbnRyb3NwZWN0aW9uIHRoZSBwZXItc2VydmljZSBjb3ZlcmFnZSB0ZXN0IGFzc2VydHMgb24sIGxvZ2dlZCBvbmNlIGF0XG4gIC8vIGJvb3Qgc28gYW4gdW5nYXRlZCBvciB1bmF1ZGl0ZWQgd3JpdGUgcm91dGUgaXMgdmlzaWJsZSBpbiB0aGUgcnVubmluZ1xuICAvLyBzZXJ2aWNlLCBub3Qgb25seSBpbiBDSS5cbiAgbG9nZ2VyLmluZm8oJ1JvdXRlIHRhYmxlIGJ1aWx0Jywgc3VtbWFyaXplUm91dGVUYWJsZShidWlsZFJvdXRlVGFibGUoYXBwKSkpO1xuXG4gIC8vIExhc3QtcmVzb3J0IGZhdWx0IGhhbmRsZXJzIGZvciB0aGUgcHJvZHVjdGlvbiBlbnRyeXBvaW50OiBhbiB1bmhhbmRsZWRcbiAgLy8gcmVqZWN0aW9uIC8gdW5jYXVnaHQgZXhjZXB0aW9uIGlzIGxvZ2dlZCAobm90IHNpbGVudGx5IGZhdGFsKSB0aGVuIHRoZVxuICAvLyBwcm9jZXNzIGV4aXRzIGZvciB0aGUgb3JjaGVzdHJhdG9yIHRvIHJlc3RhcnQuIE5vLW9wIHVuZGVyIE5PREVfRU5WPXRlc3QuXG4gIGluc3RhbGxDcmFzaEhhbmRsZXJzKGxvZ2dlcik7XG4gIHN0YXJ0U2VydmVyKGFwcCwgb3B0aW9ucykuY2F0Y2goKGVycm9yKSA9PiB7XG4gICAgLy8gc3RhcnRTZXJ2ZXIgbm93IGxpc3RlbnMtZmlyc3QgYW5kIHN1cGVydmlzZXMgdGhlIERCIGluIHRoZSBiYWNrZ3JvdW5kLCBzb1xuICAgIC8vIGl0IG9ubHkgcmVqZWN0cyBvbiBhIGdlbnVpbmVseSBmYXRhbCBTRVRVUCBlcnJvciAoaW52YWxpZCBhdXRoIGNvbmZpZywgYVxuICAgIC8vIGZhaWxlZCBvblN0YXJ0LCB0aGUgcG9ydCBhbHJlYWR5IGluIHVzZSkuIExvZyBtZXNzYWdlICsgc3RhY2sgZXhwbGljaXRseTpcbiAgICAvLyBhbiBFcnJvciBpbiB3aW5zdG9uIG1ldGFkYXRhIHNlcmlhbGl6ZXMgdG8gYHt9YCAobWVzc2FnZS9zdGFjayBhcmVcbiAgICAvLyBub24tZW51bWVyYWJsZSksIHdoaWNoIHdvdWxkIG90aGVyd2lzZSBoaWRlIHRoZSBjYXVzZSBiZWhpbmQgYHtlcnJvcjp7fX1gLlxuICAgIGxvZ2dlci5lcnJvcignRmFpbGVkIHRvIHN0YXJ0IHNlcnZlcicsIHtcbiAgICAgIGVycm9yOiBlcnJvck1lc3NhZ2UoZXJyb3IpLFxuICAgICAgc3RhY2s6IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5zdGFjayA6IHVuZGVmaW5lZCxcbiAgICB9KTtcbiAgICBwcm9jZXNzLmV4aXQoMSk7XG4gIH0pO1xufVxuIl19
261
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FwaS9zZXJ2ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0QyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzlCLE9BQU8sRUFBRSxlQUFlLEVBQUUsWUFBWSxFQUFFLFlBQVksRUFBRSxvQkFBb0IsRUFBRSxhQUFhLEVBQUUsc0JBQXNCLEVBQUUsWUFBWSxFQUFFLG1CQUFtQixFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUN4TSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDekQsT0FBTyxFQUFFLGFBQWEsRUFBRSxlQUFlLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUVqRixPQUFPLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ25ELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDL0MsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBRS9ELE1BQU0sTUFBTSxHQUFHLFlBQVksQ0FBQyxRQUFRLENBQUMsQ0FBQztBQUd0Qyw4RUFBOEU7QUFDOUUsNkVBQTZFO0FBQzdFLDZFQUE2RTtBQUM3RSx5Q0FBeUM7QUFDekMsTUFBTSxtQkFBbUIsR0FBRyxJQUFJLENBQUM7QUFDakMsTUFBTSxrQkFBa0IsR0FBRyxLQUFLLENBQUM7QUFDakMsTUFBTSx5QkFBeUIsR0FBRyxNQUFNLENBQUMsK0JBQStCLEVBQUUsTUFBTSxFQUFFLEVBQUUsR0FBRyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7QUFFOUY7Ozs7Ozs7Ozs7Ozs7R0FhRztBQUNILEtBQUssVUFBVSxxQkFBcUIsQ0FDbEMsSUFBWSxFQUNaLGFBQWdELEVBQ2hELFlBQTBELEVBQzFELE9BQXNCO0lBRXRCLElB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Q0FBQyxTQUFTLEVBQUUsR0FBRyxFQUFFLENBQUMsS0FBSyxRQUFRLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQztJQUV4RCxPQUFPO1FBQ0wsTUFBTTtRQUNOLElBQUk7UUFDSixRQUFRLEVBQUUsR0FBRyxFQUFFLENBQUMsUUFBUSxFQUFFO0tBQzNCLENBQUM7QUFDSixDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7R0FhRztBQUNILE1BQU0sVUFBVSxTQUFTLENBQUMsR0FBWSxFQUFFLE9BQU8sR0FBdUIsRUFBRTtJQUN0RSw4RUFBOEU7SUFDOUUsOEVBQThFO0lBQzlFLHdFQUF3RTtJQUN4RSwyQkFBMkI7SUFDM0IsTUFBTSxDQUFDLElBQUksQ0FBQyxtQkFBbUIsRUFBRSxtQkFBbUIsQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBRTVFLHlFQUF5RTtJQUN6RSx5RUFBeUU7SUFDekUsNEVBQTRFO0lBQzVFLG9CQUFvQixDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQzdCLFdBQVcsQ0FBQyxHQUFHLEVBQUUsT0FBTyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUU7UUFDeEMsNEVBQTRFO1FBQzVFLDJFQUEyRTtRQUMzRSw0RUFBNEU7UUFDNUUscUVBQXFFO1FBQ3JFLDZFQUE2RTtRQUM3RSxNQUFNLENBQUMsS0FBSyxDQUFDLHdCQUF3QixFQUFFO1lBQ3JDLEtBQUssRUFBRSxZQUFZLENBQUMsS0FBSyxDQUFDO1lBQzFCLEtBQUssRUFBRSxLQUFLLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxTQUFTO1NBQ3hELENBQUMsQ0FBQztRQUNILE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDbEIsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCB7IFNlcnZlciB9IGZyb20gJ2h0dHAnO1xuaW1wb3J0IHsgYnVpbGRSb3V0ZVRhYmxlLCBjcmVhdGVMb2dnZXIsIGVycm9yTWVzc2FnZSwgaW5zdGFsbENyYXNoSGFuZGxlcnMsIG5leHRCYWNrb2ZmTXMsIHJlc29sdmVSZWRpc0Nvbm5lY3Rpb24sIHJldHJ5Rm9yZXZlciwgc3VtbWFyaXplUm91dGVUYWJsZSwgc2xlZXAsIGVudkludCB9IGZyb20gJ0BwaXBlbGluZS1idWlsZGVyL2FwaS1jb3JlJztcbmltcG9ydCB7IENvbmZpZyB9IGZyb20gJ0BwaXBlbGluZS1idWlsZGVyL3BpcGVsaW5lLWNvcmUnO1xuaW1wb3J0IHsgZ2V0Q29ubmVjdGlvbiwgY2xvc2VDb25uZWN0aW9uIH0gZnJvbSAnQHBpcGVsaW5lLWJ1aWxkZXIvcGlwZWxpbmUtZGF0YSc7XG5pbXBvcnQgdHlwZSB7IEV4cHJlc3MgfSBmcm9tICdleHByZXNzJztcbmltcG9ydCB7IHNldFJlYWR5LCBpc1JlYWR5IH0gZnJvbSAnLi9yZWFkaW5lc3MuanMnO1xuaW1wb3J0IHsgc2h1dGRvd25UcmFjaW5nIH0gZnJvbSAnLi90cmFjaW5nLmpzJztcbmltcG9ydCB7IFNTRU1hbmFnZXIgfSBmcm9tICcuLi9odHRwL3NzZS1jb25uZWN0aW9uLW1hbmFnZXIuanMnO1xuXG5jb25zdCBsb2dnZXIgPSBjcmVhdGVMb2dnZXIoJ3NlcnZlcicpO1xuXG5cbi8vIERlcGVuZGVuY3ktc3VwZXJ2aXNvciBjYWRlbmNlLiBJbml0aWFsIGNvbm5lY3QgcmV0cmllcyB3aXRoIGNhcHBlZCBiYWNrb2ZmO1xuLy8gb25jZSBjb25uZWN0ZWQsIHJlLWNoZWNrcyBhdCBhIHN0ZWFkeSBpbnRlcnZhbCBzbyBhIGxhdGVyIG91dGFnZSBmbGlwcyB0aGVcbi8vIHNlcnZpY2UgTm90UmVhZHkgKGRyYWluaW5nIHRyYWZmaWMpIGFuZCBhIHJlY292ZXJ5IGZsaXBzIGl0IGJhY2sg4oCUIHdpdGhvdXRcbi8vIGV2ZXIgZXhpdGluZyAvIHJlc3RhcnRpbmcgdGhlIHByb2Nlc3MuXG5jb25zdCBSRUFEWV9SRVRSWV9CQVNFX01TID0gMTAwMDtcbmNvbnN0IFJFQURZX1JFVFJZX01BWF9NUyA9IDEwMDAwO1xuY29uc3QgUkVBRFlfTU9OSVRPUl9JTlRFUlZBTF9NUyA9IGVudkludCgnUkVBRElORVNTX01PTklUT1JfSU5URVJWQUxfTVMnLCAxNV8wMDAsIHsgbWluOiAxIH0pO1xuXG4vKipcbiAqIEVzdGFibGlzaCBhbmQgY29udGludW91c2x5IG1vbml0b3IgdGhlIHNlcnZpY2UncyBkYXRhc3RvcmUgZGVwZW5kZW5jeSxcbiAqIGZsaXBwaW5nIHJlYWRpbmVzcyBzdGF0ZSBpbnN0ZWFkIG9mIGNyYXNoLWxvb3BpbmcuXG4gKlxuICogLSBFc3RhYmxpc2ggcGhhc2U6IHJldHJ5IGBvbkJlZm9yZVN0YXJ0YCAoZS5nLiBjb25uZWN0TW9uZ28pIHdpdGggY2FwcGVkXG4gKiAgIGJhY2tvZmYgdW50aWwgaXQgc3VjY2VlZHMg4oCUIGEgY29sZCBkYXRhc3RvcmUgbXVzdCBuZXZlciBleGl0IHRoZSBwcm9jZXNzLlxuICogLSBNb25pdG9yIHBoYXNlOiBwb2xsIGB0ZXN0RGF0YWJhc2VgIGZvciB0aGUgbGlmZSBvZiB0aGUgcHJvY2VzczsgZmxpcFxuICogICByZWFkeS9Ob3RSZWFkeSBvbiB0cmFuc2l0aW9ucy4gV2hpbGUgTm90UmVhZHkgdGhlIHJlYWRpbmVzcyBndWFyZCA1MDNzXG4gKiAgIGJ1c2luZXNzIHRyYWZmaWMgYW5kIG9yY2hlc3RyYXRvciByZWFkaW5lc3MgcHJvYmVzIGRyYWluIHRoZSBpbnN0YW5jZS5cbiAqXG4gKiBSdW5zIGluIHRoZSBiYWNrZ3JvdW5kICh0aGUgSFRUUCBzZXJ2ZXIgaXMgYWxyZWFkeSBsaXN0ZW5pbmcpLiBTdG9wcyB3aGVuXG4gKiBgYWJvcnRlZCgpYCByZXR1cm5zIHRydWUgKGdyYWNlZnVsIHNodXRkb3duKSwgc28gaXQgbmV2ZXIga2VlcHMgYSBjbG9zaW5nXG4gKiBwcm9jZXNzIGFsaXZlLlxuICovXG5hc3luYyBmdW5jdGlvbiBzdXBlcnZpc2VEZXBlbmRlbmNpZXMoXG4gIG5hbWU6IHN0cmluZyxcbiAgb25CZWZvcmVTdGFydDogKCgpID0+IFByb21pc2U8dm9pZD4pIHwgdW5kZWZpbmVkLFxuICB0ZXN0RGF0YWJhc2U6ICgoKSA9PiBQcm9taXNlPGJvb2xlYW4+KSB8IGZhbHNlIHwgdW5kZWZpbmVkLFxuICBhYm9ydGVkOiAoKSA9PiBib29sZWFuLFxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGlmIChvbkJlZm9yZVN0YXJ0KSB7XG4gICAgYXdhaXQgcmV0cnlGb3JldmVyKG9uQmVmb3JlU3RhcnQsIHtcbiAgICAgIGJhc2VNczogUkVBRFlfUkVUUllfQkFTRV9NUyxcbiAgICAgIG1heE1zOiBSRUFEWV9SRVRSWV9NQVhfTVMsXG4gICAgICBvbkF0dGVtcHRGYWlsZWQ6IChlcnJvciwgZGVsYXlNcykgPT4gbG9nZ2VyLndhcm4oXG4gICAgICAgIGAke25hbWV9OiBkZXBlbmRlbmN5IGluaXQgZmFpbGVkLCByZXRyeWluZyBpbiAke2RlbGF5TXN9bXNgLFxuICAgICAgICB7IGVycm9yOiBlcnJvck1lc3NhZ2UoZXJyb3IpIH0sXG4gICAgICApLFxuICAgICAgc2hvdWxkQ29udGludWU6ICgpID0+ICFhYm9ydGVkKCksXG4gICAgfSk7XG4gIH1cblxuICAvLyBObyBkYXRhc3RvcmUgdG8gZ2F0ZSBvbiDihpIgcmVhZHkgYXMgc29vbiBhcyB3ZSBhcmUgbGlzdGVuaW5nLlxuICBpZiAodGVzdERhdGFiYXNlID09PSBmYWxzZSkge1xuICAgIGlmIChhYm9ydGVkKCkpIHJldHVybjsgLy8gc2h1dGRvd24gYmVnYW4gd2hpbGUgd2Ugd2VyZSBpbml0aWFsaXppbmdcbiAgICBzZXRSZWFkeSh0cnVlKTtcbiAgICBsb2dnZXIuaW5mbyhgJHtuYW1lfSByZWFkeSAobm8gZGF0YXN0b3JlIGRlcGVuZGVuY3kpYCk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgY29uc3QgcHJvYmUgPSB0ZXN0RGF0YWJhc2UgPz8gKCgpID0+IGdldENvbm5lY3Rpb24oKS50ZXN0Q29ubmVjdGlvbigpKTtcbiAgbGV0IHdhaXREZWxheSA9IFJFQURZX1JFVFJZX0JBU0VfTVM7XG4gIHdoaWxlICghYWJvcnRlZCgpKSB7XG4gICAgbGV0IG9rID0gZmFsc2U7XG4gICAgdHJ5IHtcbiAgICAgIG9rID0gYXdhaXQgcHJvYmUoKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIG9rID0gZmFsc2U7XG4gICAgfVxuXG4gICAgLy8gQSBwcm9iZSB0aGF0IHdhcyBpbiBmbGlnaHQgd2hlbiBzaHV0ZG93biBiZWdhbiBtdXN0IG5vdCBmbGlwIHRoZVxuICAgIC8vIGRyYWluaW5nIGluc3RhbmNlIGJhY2sgdG8gcmVhZHkuXG4gICAgaWYgKGFib3J0ZWQoKSkgYnJlYWs7XG4gICAgaWYgKG9rICYmICFpc1JlYWR5KCkpIHtcbiAgICAgIHNldFJlYWR5KHRydWUpO1xuICAgICAgd2FpdERlbGF5ID0gUkVBRFlfUkVUUllfQkFTRV9NUztcbiAgICAgIGxvZ2dlci5pbmZvKGAke25hbWV9IHJlYWR5IOKAlCBkZXBlbmRlbmNpZXMgY29ubmVjdGVkYCk7XG4gICAgfSBlbHNlIGlmICghb2sgJiYgaXNSZWFkeSgpKSB7XG4gICAgICBzZXRSZWFkeShmYWxzZSk7XG4gICAgICBsb2dnZXIud2FybihgJHtuYW1lfSBkZWdyYWRlZCDigJQgZGVwZW5kZW5jeSBjaGVjayBmYWlsaW5nIChub3cgTm90UmVhZHkpYCk7XG4gICAgfVxuXG4gICAgLy8gU3RlYWR5IGNhZGVuY2Ugb25jZSByZWFkeTsgZmFzdGVyIGJhY2tvZmYgd2hpbGUgd2FpdGluZyBzbyB3ZSBmbGlwIHRvXG4gICAgLy8gcmVhZHkgcHJvbXB0bHkgd2hlbiB0aGUgZGF0YXN0b3JlIGNvbWVzIHVwLlxuICAgIGlmIChpc1JlYWR5KCkpIHtcbiAgICAgIGF3YWl0IHNsZWVwKFJFQURZX01PTklUT1JfSU5URVJWQUxfTVMpO1xuICAgIH0gZWxzZSB7XG4gICAgICBhd2FpdCBzbGVlcCh3YWl0RGVsYXkpO1xuICAgICAgd2FpdERlbGF5ID0gbmV4dEJhY2tvZmZNcyh3YWl0RGVsYXksIFJFQURZX1JFVFJZX01BWF9NUyk7XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogT3B0aW9ucyBmb3Igc3RhcnRpbmcgYSBzZXJ2ZXJcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTdGFydFNlcnZlck9wdGlvbnMge1xuICAvKiogU2VydmljZSBuYW1lIGZvciBsb2dnaW5nICovXG4gIG5hbWU/OiBzdHJpbmc7XG4gIC8qKiBQb3J0IHRvIGxpc3RlbiBvbiAoZGVmYXVsdDogZnJvbSBjb25maWcpICovXG4gIHBvcnQ/OiBudW1iZXI7XG4gIC8qKiBTU0UgbWFuYWdlciBmb3IgZ3JhY2VmdWwgc2h1dGRvd24gKi9cbiAgc3NlTWFuYWdlcj86IFNTRU1hbmFnZXI7XG4gIC8qKiBTaHV0ZG93biB0aW1lb3V0IGluIG1pbGxpc2Vjb25kcyAoZGVmYXVsdDogMTUwMDApICovXG4gIHNodXRkb3duVGltZW91dE1zPzogbnVtYmVyO1xuICAvKiogQ2FsbGJhY2sgYWZ0ZXIgc2VydmVyIHN0YXJ0cyAqL1xuICBvblN0YXJ0PzogKHBvcnQ6IG51bWJlcikgPT4gdm9pZDtcbiAgLyoqIENhbGxiYWNrIGJlZm9yZSBzaHV0ZG93biAqL1xuICBvblNodXRkb3duPzogKCkgPT4gUHJvbWlzZTx2b2lkPjtcbiAgLyoqIFJ1bnMgYmVmb3JlIGRhdGFiYXNlIGNoZWNrIChlLmcuLCBpbml0aWFsaXplIGV4dGVybmFsIGNvbm5lY3Rpb25zKSAqL1xuICBvbkJlZm9yZVN0YXJ0PzogKCkgPT4gUHJvbWlzZTx2b2lkPjtcbiAgLyoqIEN1c3RvbSBkYXRhYmFzZSBoZWFsdGggY2hlY2ssIG9yIGZhbHNlIHRvIHNraXAuIERlZmF1bHQ6IFBvc3RncmVTUUwgdGVzdENvbm5lY3Rpb24gKi9cbiAgdGVzdERhdGFiYXNlPzogKCgpID0+IFByb21pc2U8Ym9vbGVhbj4pIHwgZmFsc2U7XG4gIC8qKiBDdXN0b20gZGF0YWJhc2UgY2xvc2UsIG9yIGZhbHNlIHRvIHNraXAuIERlZmF1bHQ6IFBvc3RncmVTUUwgY2xvc2VDb25uZWN0aW9uICovXG4gIGNsb3NlRGF0YWJhc2U/OiAoKCkgPT4gUHJvbWlzZTx2b2lkPikgfCBmYWxzZTtcbn1cblxuLyoqXG4gKiBSZXN1bHQgb2Ygc3RhcnRpbmcgYSBzZXJ2ZXJcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTdGFydFNlcnZlclJlc3VsdCB7XG4gIC8qKiBIVFRQIHNlcnZlciBpbnN0YW5jZSAqL1xuICBzZXJ2ZXI6IFNlcnZlcjtcbiAgLyoqIFBvcnQgdGhlIHNlcnZlciBpcyBsaXN0ZW5pbmcgb24gKi9cbiAgcG9ydDogbnVtYmVyO1xuICAvKiogRnVuY3Rpb24gdG8gbWFudWFsbHkgdHJpZ2dlciBzaHV0ZG93biAqL1xuICBzaHV0ZG93bjogKCkgPT4gUHJvbWlzZTx2b2lkPjtcbn1cblxuLyoqXG4gKiBTdGFydCBhbiBFeHByZXNzIHNlcnZlciB3aXRoIGdyYWNlZnVsIHNodXRkb3duIGhhbmRsaW5nXG4gKlxuICogRmVhdHVyZXM6XG4gKiAtIEF1dG9tYXRpYyBkYXRhYmFzZSBjb25uZWN0aW9uIHRlc3RpbmdcbiAqIC0gR3JhY2VmdWwgc2h1dGRvd24gb24gU0lHSU5UL1NJR1RFUk1cbiAqIC0gU1NFIGNvbm5lY3Rpb24gY2xlYW51cFxuICogLSBDb25maWd1cmFibGUgc2h1dGRvd24gdGltZW91dFxuICpcbiAqIEBwYXJhbSBhcHAgLSBFeHByZXNzIGFwcGxpY2F0aW9uXG4gKiBAcGFyYW0gb3B0aW9ucyAtIFNlcnZlciBvcHRpb25zXG4gKiBAcmV0dXJucyBTZXJ2ZXIgaW5zdGFuY2UgYW5kIGNvbnRyb2wgZnVuY3Rpb25zXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IHsgYXBwLCBzc2VNYW5hZ2VyIH0gPSBjcmVhdGVBcHAoKTtcbiAqXG4gKiBhcHAucG9zdCgnL2FwaS9yZXNvdXJjZScsIHJlcXVpcmVBdXRoLCBoYW5kbGVyKTtcbiAqXG4gKiBhd2FpdCBzdGFydFNlcnZlcihhcHAsIHtcbiAqICAgbmFtZTogJ015IE1pY3Jvc2VydmljZScsXG4gKiAgIHNzZU1hbmFnZXIsXG4gKiAgIG9uU3RhcnQ6IChwb3J0KSA9PiBjb25zb2xlLmxvZyhgTGlzdGVuaW5nIG9uICR7cG9ydH1gKSxcbiAqIH0pO1xuICogYGBgXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzdGFydFNlcnZlcihcbiAgYXBwOiBFeHByZXNzLFxuICBvcHRpb25zOiBTdGFydFNlcnZlck9wdGlvbnMgPSB7fSxcbik6IFByb21pc2U8U3RhcnRTZXJ2ZXJSZXN1bHQ+IHtcbiAgY29uc3Qgc2VydmVyQ29uZmlnID0gQ29uZmlnLmdldCgnc2VydmVyJyk7XG4gIGNvbnN0IHtcbiAgICBuYW1lID0gJ01pY3Jvc2VydmljZScsXG4gICAgc3NlTWFuYWdlcixcbiAgICBzaHV0ZG93blRpbWVvdXRNcyA9IDE1MDAwLFxuICAgIG9uU3RhcnQsXG4gICAgb25TaHV0ZG93bixcbiAgICBvbkJlZm9yZVN0YXJ0LFxuICAgIHRlc3REYXRhYmFzZSxcbiAgICBjbG9zZURhdGFiYXNlLFxuICB9ID0gb3B0aW9ucztcbiAgY29uc3QgcG9ydCA9IG9wdGlvbnMucG9ydCA/PyBzZXJ2ZXJDb25maWcucG9ydDtcblxuICAvLyBWYWxpZGF0ZSBhdXRoIGNvbmZpZ3VyYXRpb24gYXQgc2VydmVyIHN0YXJ0dXAgKG5vdCBkdXJpbmcgQ0RLIHN5bnRoZXNpcylcbiAgQ29uZmlnLnZhbGlkYXRlQXV0aCgpO1xuICAvLyBGYWlsIGZhc3QgaWYgdGhpcyBzZXJ2aWNlIGhhcyBubyBpbnRlcm5hbCBzaWduaW5nIGtleSBvZiBpdHMgb3duLCBvciBub1xuICAvLyBwdWJsaWMgYnVuZGxlIHRvIHZlcmlmeSBpdHMgcGVlcnMgd2l0aC4gV2l0aG91dCB0aGVtIGl0IHdvdWxkIG1pbnRcbiAgLy8gdG9rZW5zIG9uIGFuIEVQSEVNRVJBTCBpbi1wcm9jZXNzIGtleSB0aGF0IG5vIHBlZXIgYWNjZXB0cywgYW5kIHJlamVjdCBldmVyeVxuICAvLyBwZWVyJ3MgdG9rZW4g4oCUIGkuZS4gc2lsZW50bHkgbG9zZSBhbGwgc2VydmljZS10by1zZXJ2aWNlIHRyYWZmaWMuIENoZWNrZWRcbiAgLy8gSEVSRSByYXRoZXIgdGhhbiBpbiBgY3JlYXRlQXBwYCBiZWNhdXNlIGl0IGlzIGEgcHJvcGVydHkgb2YgdGhlIHJ1bm5pbmdcbiAgLy8gZGVwbG95bWVudCwgbm90IG9mIHRoZSBhcHAgb2JqZWN0OiByb3V0ZS10YWJsZSBidWlsZGVycyBhbmQgdGVzdCBzdWl0ZXNcbiAgLy8gYXNzZW1ibGUgYW4gYXBwIHdpdGhvdXQgZXZlciBzaWduaW5nIGFueXRoaW5nLlxuICBmb3IgKGNvbnN0IGVudlZhciBvZiBbJ1NFUlZJQ0VfU0lHTklOR19LRVlfRklMRScsICdTRVJWSUNFX0tFWV9CVU5ETEVfRklMRSddIGFzIGNvbnN0KSB7XG4gICAgaWYgKCFwcm9jZXNzLmVudltlbnZWYXJdKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYCR7ZW52VmFyfSBlbnZpcm9ubWVudCB2YXJpYWJsZSBpcyByZXF1aXJlZCAoZ2VuZXJhdGUgd2l0aCBkZXBsb3kvYmluL3NlcnZpY2Utc2lnbmluZy1rZXlzLnNoKS4gU2V0IGl0IGJlZm9yZSBzdGFydGluZyB0aGUgc2VydmVyLmApO1xuICAgIH1cbiAgfVxuICAvLyBGYWlsIGZhc3Qgb24gYW4gdW51c2FibGUgUmVkaXMgY29uZmlndXJhdGlvbiAodGhyb3dzIFJlZGlzQ29uZmlnRXJyb3IpIOKAlCBhXG4gIC8vIFJlZGlzIGNsaWVudCBpcyBjcmVhdGVkIGxhemlseSBvbiBmaXJzdCB1c2UsIHNvIHdpdGhvdXQgdGhpcyBhIGJhZCBjb25maWdcbiAgLy8gd291bGQgc3VyZmFjZSBhcyByZXF1ZXN0LXRpbWUgZXJyb3JzIGluc3RlYWQgb2YgYSBmYWlsZWQgc3RhcnQuXG4gIHJlc29sdmVSZWRpc0Nvbm5lY3Rpb24oKTtcblxuICBsb2dnZXIuaW5mbyhgU3RhcnRpbmcgJHtuYW1lfS4uLmApO1xuXG4gIC8vIE1hcmsgTm90UmVhZHkgc3luY2hyb25vdXNseSwgQkVGT1JFIHRoZSBwb3J0IG9wZW5zLCBzbyBubyByZXF1ZXN0IHNsaXBzXG4gIC8vIHRocm91Z2ggdGhlIHJlYWRpbmVzcyBndWFyZCBiZWZvcmUgdGhlIHN1cGVydmlzb3IgaGFzIHJ1bi4gVGhlIHN1cGVydmlzb3JcbiAgLy8gZmxpcHMgaXQgdHJ1ZSBvbmNlIGRlcGVuZGVuY2llcyBjb25uZWN0LlxuICBzZXRSZWFkeShmYWxzZSk7XG5cbiAgLy8gTGlzdGVuIEZJUlNULiBQcmV2aW91c2x5IHRoZSBwcm9jZXNzIHRlc3RlZCB0aGUgREIgYW5kIGBwcm9jZXNzLmV4aXQoMSlgJ2RcbiAgLy8gb24gZmFpbHVyZSAodG8gYmUgcmVzdGFydGVkKSwgc28gZHVyaW5nIGEgY29sZC1EQiBzdGFtcGVkZSBzZXJ2aWNlc1xuICAvLyBjcmFzaC1sb29wZWQgYW5kIG5ldmVyIGV2ZW4gb3BlbmVkIHRoZWlyIHBvcnQuIE5vdyB3ZSBvcGVuIHRoZSBwb3J0XG4gIC8vIGltbWVkaWF0ZWx5IOKAlCAvaGVhbHRoIChsaXZlbmVzcyksIC9yZWFkeSAocmVhZGluZXNzKSBhbmQgdGhlIHJlYWRpbmVzc1xuICAvLyBndWFyZCBhbGwgcmVzcG9uZCBhdCBvbmNlIOKAlCBhbmQgZXN0YWJsaXNoICsgbW9uaXRvciB0aGUgZGF0YXN0b3JlIGluIHRoZVxuICAvLyBiYWNrZ3JvdW5kLCByZXBvcnRpbmcgTm90UmVhZHkgdW50aWwgaXQgY29ubmVjdHMgaW5zdGVhZCBvZiBleGl0aW5nLlxuICBjb25zdCBzZXJ2ZXIgPSBhcHAubGlzdGVuKHBvcnQsICgpID0+IHtcbiAgICBsb2dnZXIuaW5mbyhgJHtuYW1lfSBsaXN0ZW5pbmcgb24gcG9ydDogJHtwb3J0fWApO1xuICAgIGxvZ2dlci5pbmZvKGBQbGF0Zm9ybSBVUkw6ICR7c2VydmVyQ29uZmlnLnBsYXRmb3JtVXJsfWApO1xuICAgIG9uU3RhcnQ/Lihwb3J0KTtcbiAgfSk7XG5cbiAgLy8gU2h1dGRvd24gaGFuZGxlciAoZ3VhcmRlZCBhZ2FpbnN0IGNvbmN1cnJlbnQgc2lnbmFscylcbiAgbGV0IHNodXR0aW5nRG93biA9IGZhbHNlO1xuXG4gIC8vIEJhY2tncm91bmQgZGVwZW5kZW5jeSBzdXBlcnZpc29yIOKAlCBlc3RhYmxpc2hlZCArIG1vbml0b3JlZCBhZnRlciBsaXN0ZW4sXG4gIC8vIHN0b3BwZWQgb24gc2h1dGRvd24gc28gaXQgbmV2ZXIga2VlcHMgYSBjbG9zaW5nIHByb2Nlc3MgYWxpdmUuIEd1YXJkIHRoZVxuICAvLyBmbG9hdGluZyBwcm9taXNlOiBldmVyeSBleHBlY3RlZCBmYWlsdXJlIGlzIGhhbmRsZWQgaW5zaWRlLCBzbyBhIHJlamVjdGlvblxuICAvLyBoZXJlIG1lYW5zIGEgcHJvZ3JhbW1pbmcgZXJyb3Ig4oCUIGxvZyBpdCBhbmQgbGVhdmUgdGhlIHNlcnZpY2UgTm90UmVhZHlcbiAgLy8gcmF0aGVyIHRoYW4gbGV0dGluZyBpdCBiZWNvbWUgYW4gdW5oYW5kbGVkUmVqZWN0aW9uIHRoYXQgY3Jhc2gtZXhpdHMgdGhlXG4gIC8vIHByb2Nlc3MgKHdoaWNoIHdvdWxkIGRlZmVhdCB0aGUgd2hvbGUgXCJuZXZlciBleGl0IG9uIGRlcGVuZGVuY3kgdHJvdWJsZVwiXG4gIC8vIGdvYWwpLlxuICBzdXBlcnZpc2VEZXBlbmRlbmNpZXMobmFtZSwgb25CZWZvcmVTdGFydCwgdGVzdERhdGFiYXNlLCAoKSA9PiBzaHV0dGluZ0Rvd24pLmNhdGNoKChlcnJvcikgPT4ge1xuICAgIGxvZ2dlci5lcnJvcignRGVwZW5kZW5jeSBzdXBlcnZpc29yIGNyYXNoZWQ7IHNlcnZpY2Ugd2lsbCByZW1haW4gTm90UmVhZHknLCB7IGVycm9yOiBlcnJvck1lc3NhZ2UoZXJyb3IpIH0pO1xuICB9KTtcblxuICBjb25zdCBzaHV0ZG93biA9IGFzeW5jIChzaWduYWw/OiBzdHJpbmcpID0+IHtcbiAgICBpZiAoc2h1dHRpbmdEb3duKSByZXR1cm47XG4gICAgc2h1dHRpbmdEb3duID0gdHJ1ZTtcblxuICAgIC8vIERyYWluIEZJUlNUOiByZXBvcnQgTm90UmVhZHkgYmVmb3JlIGFueXRoaW5nIGVsc2UsIHNvIHRoZSBsb2FkIGJhbGFuY2VyIC9cbiAgICAvLyByZWFkaW5lc3MgcHJvYmUgc3RvcHMgc2VuZGluZyBuZXcgd29yayB3aGlsZSB0aGUgcmVzdCBvZiBzaHV0ZG93biBydW5zLlxuICAgIC8vIChQcmV2aW91c2x5IHJlYWRpbmVzcyBzdGF5ZWQgZ3JlZW4gdGhyb3VnaCBvblNodXRkb3duLCB3aGljaCBjb3VsZCB0YWtlXG4gICAgLy8gc2Vjb25kcyDigJQgbmV3IHJlcXVlc3RzIGtlcHQgYXJyaXZpbmcgYXQgYSBwcm9jZXNzIHRlYXJpbmcgaXRzZWxmIGRvd24uKVxuICAgIHNldFJlYWR5KGZhbHNlKTtcblxuICAgIGlmIChzaWduYWwpIHtcbiAgICAgIGxvZ2dlci5pbmZvKGAke3NpZ25hbH0gcmVjZWl2ZWQsIHNodXR0aW5nIGRvd24gZ3JhY2VmdWxseS4uLmApO1xuICAgIH1cblxuICAgIC8vIEFybSB0aGUgZm9yY2UtZXhpdCBCRUZPUkUgYXdhaXRpbmcgYW55dGhpbmc6IGEgaHVuZyBvblNodXRkb3duIChhIHN0dWNrXG4gICAgLy8gcXVldWUgY2xvc2UsIGEgUmVkaXMgcXVpdCB0aGF0IG5ldmVyIGFuc3dlcnMpIHdvdWxkIG90aGVyd2lzZSBibG9jayBmb3JldmVyXG4gICAgLy8gd2l0aCB0aGUgdGltZXIgbmV2ZXIgc3RhcnRlZCwgc28gdGhlIHBvZCB3b3VsZCBpZ25vcmUgU0lHVEVSTSB1bnRpbCBTSUdLSUxMLlxuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgbG9nZ2VyLmVycm9yKCdGb3JjZWQgc2h1dGRvd24gYWZ0ZXIgdGltZW91dCcpO1xuICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgIH0sIHNodXRkb3duVGltZW91dE1zKS51bnJlZigpO1xuXG4gICAgLy8gQ3VzdG9tIHNodXRkb3duIGNhbGxiYWNrXG4gICAgaWYgKG9uU2h1dGRvd24pIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IG9uU2h1dGRvd24oKTtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGxvZ2dlci5lcnJvcignRXJyb3IgaW4gb25TaHV0ZG93biBjYWxsYmFjaycsIHsgZXJyb3IgfSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gQ2xvc2UgU1NFIGNvbm5lY3Rpb25zXG4gICAgaWYgKHNzZU1hbmFnZXIpIHtcbiAgICAgIHNzZU1hbmFnZXIuc2h1dGRvd24oKTtcbiAgICAgIGxvZ2dlci5pbmZvKCdTU0UgY29ubmVjdGlvbnMgY2xvc2VkJyk7XG4gICAgfVxuXG4gICAgLy8gQ2xvc2UgSFRUUCBzZXJ2ZXJcbiAgICBzZXJ2ZXIuY2xvc2UoYXN5bmMgKCkgPT4ge1xuICAgICAgbG9nZ2VyLmluZm8oJ0hUVFAgc2VydmVyIGNsb3NlZCcpO1xuXG4gICAgICAvLyBTaHV0ZG93biBPcGVuVGVsZW1ldHJ5IHRyYWNpbmdcbiAgICAgIGF3YWl0IHNodXRkb3duVHJhY2luZygpLmNhdGNoKGVyciA9PiBsb2dnZXIuZXJyb3IoJ0Vycm9yIHNodXR0aW5nIGRvd24gdHJhY2luZycsIHsgZXJyb3I6IGVyciB9KSk7XG5cbiAgICAgIC8vIENsb3NlIGRhdGFiYXNlIGNvbm5lY3Rpb25cbiAgICAgIGlmIChjbG9zZURhdGFiYXNlICE9PSBmYWxzZSkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGlmIChjbG9zZURhdGFiYXNlKSB7XG4gICAgICAgICAgICBhd2FpdCBjbG9zZURhdGFiYXNlKCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGF3YWl0IGNsb3NlQ29ubmVjdGlvbigpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBsb2dnZXIuaW5mbygnRGF0YWJhc2UgY29ubmVjdGlvbiBjbG9zZWQnKTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICBsb2dnZXIuZXJyb3IoJ0Vycm9yIGNsb3NpbmcgZGF0YWJhc2UnLCB7IGVycm9yIH0pO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHByb2Nlc3MuZXhpdCgwKTtcbiAgICB9KTtcbiAgfTtcblxuICAvLyBSZWdpc3RlciBzaWduYWwgaGFuZGxlcnNcbiAgcHJvY2Vzcy5vbmNlKCdTSUdJTlQnLCAoKSA9PiB2b2lkIHNodXRkb3duKCdTSUdJTlQnKSk7XG4gIHByb2Nlc3Mub25jZSgnU0lHVEVSTScsICgpID0+IHZvaWQgc2h1dGRvd24oJ1NJR1RFUk0nKSk7XG5cbiAgcmV0dXJuIHtcbiAgICBzZXJ2ZXIsXG4gICAgcG9ydCxcbiAgICBzaHV0ZG93bjogKCkgPT4gc2h1dGRvd24oKSxcbiAgfTtcbn1cblxuLyoqXG4gKiBTaW1wbGUgc2VydmVyIHN0YXJ0IHdyYXBwZXIgd2l0aCBlcnJvciBoYW5kbGluZ1xuICpcbiAqIEBwYXJhbSBhcHAgLSBFeHByZXNzIGFwcGxpY2F0aW9uXG4gKiBAcGFyYW0gb3B0aW9ucyAtIFNlcnZlciBvcHRpb25zXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IHsgYXBwLCBzc2VNYW5hZ2VyIH0gPSBjcmVhdGVBcHAoKTtcbiAqIGFwcC5wb3N0KCcvYXBpL3Jlc291cmNlJywgaGFuZGxlcik7XG4gKlxuICogdm9pZCBydW5TZXJ2ZXIoYXBwLCB7IG5hbWU6ICdNeSBTZXJ2aWNlJywgc3NlTWFuYWdlciB9KTtcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gcnVuU2VydmVyKGFwcDogRXhwcmVzcywgb3B0aW9uczogU3RhcnRTZXJ2ZXJPcHRpb25zID0ge30pOiB2b2lkIHtcbiAgLy8gUm91dGUgdGFibGUgb2YgdGhlIGZ1bGx5IGFzc2VtYmxlZCBhcHAgKHNlZSBhcGktY29yZSdzIHJvdXRlLXRhYmxlLnRzKTogdGhlXG4gIC8vIHNhbWUgaW50cm9zcGVjdGlvbiB0aGUgcGVyLXNlcnZpY2UgY292ZXJhZ2UgdGVzdCBhc3NlcnRzIG9uLCBsb2dnZWQgb25jZSBhdFxuICAvLyBib290IHNvIGFuIHVuZ2F0ZWQgb3IgdW5hdWRpdGVkIHdyaXRlIHJvdXRlIGlzIHZpc2libGUgaW4gdGhlIHJ1bm5pbmdcbiAgLy8gc2VydmljZSwgbm90IG9ubHkgaW4gQ0kuXG4gIGxvZ2dlci5pbmZvKCdSb3V0ZSB0YWJsZSBidWlsdCcsIHN1bW1hcml6ZVJvdXRlVGFibGUoYnVpbGRSb3V0ZVRhYmxlKGFwcCkpKTtcblxuICAvLyBMYXN0LXJlc29ydCBmYXVsdCBoYW5kbGVycyBmb3IgdGhlIHByb2R1Y3Rpb24gZW50cnlwb2ludDogYW4gdW5oYW5kbGVkXG4gIC8vIHJlamVjdGlvbiAvIHVuY2F1Z2h0IGV4Y2VwdGlvbiBpcyBsb2dnZWQgKG5vdCBzaWxlbnRseSBmYXRhbCkgdGhlbiB0aGVcbiAgLy8gcHJvY2VzcyBleGl0cyBmb3IgdGhlIG9yY2hlc3RyYXRvciB0byByZXN0YXJ0LiBOby1vcCB1bmRlciBOT0RFX0VOVj10ZXN0LlxuICBpbnN0YWxsQ3Jhc2hIYW5kbGVycyhsb2dnZXIpO1xuICBzdGFydFNlcnZlcihhcHAsIG9wdGlvbnMpLmNhdGNoKChlcnJvcikgPT4ge1xuICAgIC8vIHN0YXJ0U2VydmVyIG5vdyBsaXN0ZW5zLWZpcnN0IGFuZCBzdXBlcnZpc2VzIHRoZSBEQiBpbiB0aGUgYmFja2dyb3VuZCwgc29cbiAgICAvLyBpdCBvbmx5IHJlamVjdHMgb24gYSBnZW51aW5lbHkgZmF0YWwgU0VUVVAgZXJyb3IgKGludmFsaWQgYXV0aCBjb25maWcsIGFcbiAgICAvLyBmYWlsZWQgb25TdGFydCwgdGhlIHBvcnQgYWxyZWFkeSBpbiB1c2UpLiBMb2cgbWVzc2FnZSArIHN0YWNrIGV4cGxpY2l0bHk6XG4gICAgLy8gYW4gRXJyb3IgaW4gd2luc3RvbiBtZXRhZGF0YSBzZXJpYWxpemVzIHRvIGB7fWAgKG1lc3NhZ2Uvc3RhY2sgYXJlXG4gICAgLy8gbm9uLWVudW1lcmFibGUpLCB3aGljaCB3b3VsZCBvdGhlcndpc2UgaGlkZSB0aGUgY2F1c2UgYmVoaW5kIGB7ZXJyb3I6e319YC5cbiAgICBsb2dnZXIuZXJyb3IoJ0ZhaWxlZCB0byBzdGFydCBzZXJ2ZXInLCB7XG4gICAgICBlcnJvcjogZXJyb3JNZXNzYWdlKGVycm9yKSxcbiAgICAgIHN0YWNrOiBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3Iuc3RhY2sgOiB1bmRlZmluZWQsXG4gICAgfSk7XG4gICAgcHJvY2Vzcy5leGl0KDEpO1xuICB9KTtcbn1cbiJdfQ==
@@ -2,9 +2,8 @@ import { type TenantContext } from '@pipeline-builder/pipeline-data';
2
2
  import type { Request, Response, NextFunction } from 'express';
3
3
  /**
4
4
  * Resolves the RLS tenant scope for a request. The default reads the CALLER's
5
- * authenticated identity org (`ctx.identity.orgId`, validated by requireOrgId) — NOT
6
- * `getOrgId(req)`, which prefers route params (the queried scope), the wrong tenant for
7
- * RLS. Services with a different request boundary supply their own resolver (e.g. platform
5
+ * authenticated identity org (`ctx.identity.orgId`, validated by requireOrgId) — never a
6
+ * route param, which names the QUERIED scope, the wrong tenant for RLS. Services with a different request boundary supply their own resolver (e.g. platform
8
7
  * sets the scope pre-auth from an unverified JWT peek so unauthenticated endpoints still
9
8
  * get a sane default).
10
9
  */
@@ -21,8 +20,8 @@ export type TenantScopeResolver = (req: Request) => TenantContext;
21
20
  * Default placement is AFTER `requireAuth` + `requireOrgId` (the route factories do this);
22
21
  * pass a custom `resolve` for a different boundary. A thrown resolver means tenant identity
23
22
  * could NOT be established (a wiring bug — this runs after auth) — we hard-FAIL the request
24
- * (500 via next(err)) rather than proceed. Proceeding would run queries with empty RLS GUCs;
25
- * under FORCE RLS that hides rows, but while RLS is in owner-bypass mode the app-layer WHERE
26
- * clause is the only tenant gate, so a scopeless request must not silently continue.
23
+ * (500 via next(err)) rather than proceed. Proceeding would run queries with empty RLS GUCs,
24
+ * which under FORCE RLS hide every row and refuse writes — a wiring bug surfacing as a
25
+ * silently empty result instead of an error.
27
26
  */
28
27
  export declare function withTenantContext(resolve?: TenantScopeResolver): (req: Request, _res: Response, next: NextFunction) => void;