@pipeline-builder/api-core 3.4.36 → 3.4.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/lib/index.d.ts +2 -2
- package/lib/index.js +3 -3
- package/lib/middleware/auth.d.ts +9 -4
- package/lib/middleware/auth.js +16 -13
- package/lib/services/http-client.d.ts +5 -0
- package/lib/services/http-client.js +14 -1
- package/lib/services/index.d.ts +1 -0
- package/lib/services/index.js +2 -1
- package/lib/services/quota.d.ts +65 -1
- package/lib/services/quota.js +99 -3
- package/lib/services/remote-audit-client.d.ts +63 -0
- package/lib/services/remote-audit-client.js +67 -0
- package/lib/types/common.d.ts +37 -2
- package/lib/types/common.js +5 -2
- package/lib/types/feature-flags.d.ts +5 -5
- package/lib/types/feature-flags.js +9 -9
- package/lib/types/http.d.ts +4 -14
- package/lib/types/http.js +1 -1
- package/lib/types/quota-tiers.d.ts +13 -7
- package/lib/types/quota-tiers.js +54 -5
- package/lib/utils/identity.js +6 -6
- package/lib/utils/index.d.ts +3 -0
- package/lib/utils/index.js +4 -1
- package/lib/utils/metric-emitter.d.ts +36 -0
- package/lib/utils/metric-emitter.js +37 -0
- package/lib/utils/org-aws-credentials.d.ts +154 -0
- package/lib/utils/org-aws-credentials.js +159 -0
- package/lib/utils/secret-encryption.d.ts +205 -0
- package/lib/utils/secret-encryption.js +388 -0
- package/package.json +8 -5
|
@@ -53,19 +53,19 @@ exports.FEATURE_METADATA = {
|
|
|
53
53
|
/**
|
|
54
54
|
* Resolve a user's effective feature set.
|
|
55
55
|
*
|
|
56
|
-
* 1.
|
|
56
|
+
* 1. Sysadmins (isSuperAdmin) always get ALL features.
|
|
57
57
|
* 2. Start with the tier's default features.
|
|
58
58
|
* 3. Apply per-user overrides: `true` adds a feature, `false` removes it.
|
|
59
59
|
* 4. Invalid override keys are silently ignored.
|
|
60
60
|
*
|
|
61
61
|
* @param tier - The organization's quota tier
|
|
62
62
|
* @param featureOverrides - Per-user overrides (key = feature flag, value = enabled)
|
|
63
|
-
* @param
|
|
63
|
+
* @param isSuperAdmin - Whether the user has the global super-admin flag
|
|
64
64
|
* @returns Sorted array of enabled feature flags
|
|
65
65
|
*/
|
|
66
|
-
function resolveUserFeatures(tier, featureOverrides,
|
|
67
|
-
//
|
|
68
|
-
if (
|
|
66
|
+
function resolveUserFeatures(tier, featureOverrides, isSuperAdmin) {
|
|
67
|
+
// Sysadmins get everything regardless of tier.
|
|
68
|
+
if (isSuperAdmin)
|
|
69
69
|
return [...exports.ALL_FEATURE_FLAGS];
|
|
70
70
|
// Start with tier defaults
|
|
71
71
|
const features = new Set(exports.TIER_FEATURES[tier] ?? []);
|
|
@@ -91,11 +91,11 @@ function resolveUserFeatures(tier, featureOverrides, isSystemOrg) {
|
|
|
91
91
|
* @param tier - The organization's quota tier
|
|
92
92
|
* @param feature - The feature flag to check
|
|
93
93
|
* @param featureOverrides - Per-user overrides
|
|
94
|
-
* @param
|
|
94
|
+
* @param isSuperAdmin - Whether the user has the global super-admin flag
|
|
95
95
|
* @returns true if the feature is enabled
|
|
96
96
|
*/
|
|
97
|
-
function hasFeature(tier, feature, featureOverrides,
|
|
98
|
-
if (
|
|
97
|
+
function hasFeature(tier, feature, featureOverrides, isSuperAdmin) {
|
|
98
|
+
if (isSuperAdmin)
|
|
99
99
|
return true;
|
|
100
100
|
// Check override first
|
|
101
101
|
if (featureOverrides && feature in featureOverrides) {
|
|
@@ -104,4 +104,4 @@ function hasFeature(tier, feature, featureOverrides, isSystemOrg) {
|
|
|
104
104
|
// Fall back to tier default
|
|
105
105
|
return (exports.TIER_FEATURES[tier] ?? []).includes(feature);
|
|
106
106
|
}
|
|
107
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
107
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmVhdHVyZS1mbGFncy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90eXBlcy9mZWF0dXJlLWZsYWdzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDOzs7QUF3QnRDLGdEQUVDO0FBb0RELGtEQXlCQztBQVdELGdDQWVDO0FBbkhELGdFQUFnRTtBQUNuRCxRQUFBLGlCQUFpQixHQUEyQjtJQUN2RCxrQkFBa0I7SUFDbEIsZUFBZTtJQUNmLGlCQUFpQjtJQUNqQixxQkFBcUI7SUFDckIsV0FBVztDQUNaLENBQUM7QUFFRixxREFBcUQ7QUFDckQsU0FBZ0Isa0JBQWtCLENBQUMsS0FBYTtJQUM5QyxPQUFRLHlCQUF1QyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUNsRSxDQUFDO0FBRUQsMEJBQTBCO0FBRTFCLGlEQUFpRDtBQUNwQyxRQUFBLGFBQWEsR0FBOEM7SUFDdEUsU0FBUyxFQUFFLEVBQUU7SUFDYixHQUFHLEVBQUUsQ0FBQyxrQkFBa0IsRUFBRSxlQUFlLEVBQUUsaUJBQWlCLENBQUM7SUFDN0QsU0FBUyxFQUFFLENBQUMsR0FBRyx5QkFBaUIsQ0FBQztDQUNsQyxDQUFDO0FBRUYsaUNBQWlDO0FBRWpDLHFEQUFxRDtBQUN4QyxRQUFBLGdCQUFnQixHQUFnRTtJQUMzRixnQkFBZ0IsRUFBRTtRQUNoQixLQUFLLEVBQUUsa0JBQWtCO1FBQ3pCLFdBQVcsRUFBRSxzREFBc0Q7S0FDcEU7SUFDRCxhQUFhLEVBQUU7UUFDYixLQUFLLEVBQUUsZUFBZTtRQUN0QixXQUFXLEVBQUUsMkNBQTJDO0tBQ3pEO0lBQ0QsZUFBZSxFQUFFO1FBQ2YsS0FBSyxFQUFFLGlCQUFpQjtRQUN4QixXQUFXLEVBQUUsNERBQTREO0tBQzFFO0lBQ0QsbUJBQW1CLEVBQUU7UUFDbkIsS0FBSyxFQUFFLHFCQUFxQjtRQUM1QixXQUFXLEVBQUUsMkRBQTJEO0tBQ3pFO0lBQ0QsU0FBUyxFQUFFO1FBQ1QsS0FBSyxFQUFFLFdBQVc7UUFDbEIsV0FBVyxFQUFFLHFEQUFxRDtLQUNuRTtDQUNGLENBQUM7QUFFRixtQkFBbUI7QUFFbkI7Ozs7Ozs7Ozs7OztHQVlHO0FBQ0gsU0FBZ0IsbUJBQW1CLENBQ2pDLElBQWUsRUFDZixnQkFBaUQsRUFDakQsWUFBc0I7SUFFdEIsK0NBQStDO0lBQy9DLElBQUksWUFBWTtRQUFFLE9BQU8sQ0FBQyxHQUFHLHlCQUFpQixDQUFDLENBQUM7SUFFaEQsMkJBQTJCO0lBQzNCLE1BQU0sUUFBUSxHQUFHLElBQUksR0FBRyxDQUFjLHFCQUFhLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7SUFFakUsMkJBQTJCO0lBQzNCLElBQUksZ0JBQWdCLEVBQUUsQ0FBQztRQUNyQixLQUFLLE1BQU0sQ0FBQyxHQUFHLEVBQUUsT0FBTyxDQUFDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxFQUFFLENBQUM7WUFDOUQsSUFBSSxDQUFDLGtCQUFrQixDQUFDLEdBQUcsQ0FBQztnQkFBRSxTQUFTO1lBQ3ZDLElBQUksT0FBTyxFQUFFLENBQUM7Z0JBQ1osUUFBUSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUNwQixDQUFDO2lCQUFNLENBQUM7Z0JBQ04sUUFBUSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUN2QixDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFFRCw0QkFBNEI7SUFDNUIsT0FBTyx5QkFBaUIsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDeEQsQ0FBQztBQUVEOzs7Ozs7OztHQVFHO0FBQ0gsU0FBZ0IsVUFBVSxDQUN4QixJQUFlLEVBQ2YsT0FBb0IsRUFDcEIsZ0JBQWlELEVBQ2pELFlBQXNCO0lBRXRCLElBQUksWUFBWTtRQUFFLE9BQU8sSUFBSSxDQUFDO0lBRTlCLHVCQUF1QjtJQUN2QixJQUFJLGdCQUFnQixJQUFJLE9BQU8sSUFBSSxnQkFBZ0IsRUFBRSxDQUFDO1FBQ3BELE9BQU8sZ0JBQWdCLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDbkMsQ0FBQztJQUVELDRCQUE0QjtJQUM1QixPQUFPLENBQUMscUJBQWEsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLENBQUM7QUFDdkQsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgdHlwZSB7IFF1b3RhVGllciB9IGZyb20gJy4vcXVvdGEtdGllcnMnO1xuXG4vLyBGZWF0dXJlIGZsYWcgaWRlbnRpZmllcnNcblxuLyoqIENhbm9uaWNhbCBmZWF0dXJlIGZsYWcgaWRlbnRpZmllcnMuICovXG5leHBvcnQgdHlwZSBGZWF0dXJlRmxhZyA9XG4gIHwgJ3ByaW9yaXR5X3N1cHBvcnQnXG4gIHwgJ2N1c3RvbV9pbnRlZ3JhdGlvbnMnXG4gIHwgJ2FpX2dlbmVyYXRpb24nXG4gIHwgJ2J1bGtfb3BlcmF0aW9ucydcbiAgfCAnYXVkaXRfbG9nJztcblxuLyoqIEFsbCB2YWxpZCBmZWF0dXJlIGZsYWdzIChvcmRlciBkZXRlcm1pbmVzIGRpc3BsYXkgb3JkZXIpLiAqL1xuZXhwb3J0IGNvbnN0IEFMTF9GRUFUVVJFX0ZMQUdTOiByZWFkb25seSBGZWF0dXJlRmxhZ1tdID0gW1xuICAncHJpb3JpdHlfc3VwcG9ydCcsXG4gICdhaV9nZW5lcmF0aW9uJyxcbiAgJ2J1bGtfb3BlcmF0aW9ucycsXG4gICdjdXN0b21faW50ZWdyYXRpb25zJyxcbiAgJ2F1ZGl0X2xvZycsXG5dO1xuXG4vKiogQ2hlY2sgd2hldGhlciBhIHN0cmluZyBpcyBhIHZhbGlkIEZlYXR1cmVGbGFnLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzVmFsaWRGZWF0dXJlRmxhZyh2YWx1ZTogc3RyaW5nKTogdmFsdWUgaXMgRmVhdHVyZUZsYWcge1xuICByZXR1cm4gKEFMTF9GRUFUVVJFX0ZMQUdTIGFzIHJlYWRvbmx5IHN0cmluZ1tdKS5pbmNsdWRlcyh2YWx1ZSk7XG59XG5cbi8vIFRpZXItdG8tZmVhdHVyZSBtYXBwaW5nXG5cbi8qKiBGZWF0dXJlcyBlbmFibGVkIGJ5IGRlZmF1bHQgZm9yIGVhY2ggdGllci4gKi9cbmV4cG9ydCBjb25zdCBUSUVSX0ZFQVRVUkVTOiBSZWNvcmQ8UXVvdGFUaWVyLCByZWFkb25seSBGZWF0dXJlRmxhZ1tdPiA9IHtcbiAgZGV2ZWxvcGVyOiBbXSxcbiAgcHJvOiBbJ3ByaW9yaXR5X3N1cHBvcnQnLCAnYWlfZ2VuZXJhdGlvbicsICdidWxrX29wZXJhdGlvbnMnXSxcbiAgdW5saW1pdGVkOiBbLi4uQUxMX0ZFQVRVUkVfRkxBR1NdLFxufTtcblxuLy8gRmVhdHVyZSBtZXRhZGF0YSAoZm9yIGRpc3BsYXkpXG5cbi8qKiBIdW1hbi1yZWFkYWJsZSBtZXRhZGF0YSBmb3IgZWFjaCBmZWF0dXJlIGZsYWcuICovXG5leHBvcnQgY29uc3QgRkVBVFVSRV9NRVRBREFUQTogUmVjb3JkPEZlYXR1cmVGbGFnLCB7IGxhYmVsOiBzdHJpbmc7IGRlc2NyaXB0aW9uOiBzdHJpbmcgfT4gPSB7XG4gIHByaW9yaXR5X3N1cHBvcnQ6IHtcbiAgICBsYWJlbDogJ1ByaW9yaXR5IFN1cHBvcnQnLFxuICAgIGRlc2NyaXB0aW9uOiAnRmFzdGVyIHJlc3BvbnNlIHRpbWVzIGFuZCBkZWRpY2F0ZWQgc3VwcG9ydCBjaGFubmVscycsXG4gIH0sXG4gIGFpX2dlbmVyYXRpb246IHtcbiAgICBsYWJlbDogJ0FJIEdlbmVyYXRpb24nLFxuICAgIGRlc2NyaXB0aW9uOiAnQUktcG93ZXJlZCBwaXBlbGluZSBhbmQgcGx1Z2luIGdlbmVyYXRpb24nLFxuICB9LFxuICBidWxrX29wZXJhdGlvbnM6IHtcbiAgICBsYWJlbDogJ0J1bGsgT3BlcmF0aW9ucycsXG4gICAgZGVzY3JpcHRpb246ICdCYXRjaCBjcmVhdGUsIHVwZGF0ZSwgYW5kIGRlbGV0ZSBmb3IgcGlwZWxpbmVzIGFuZCBwbHVnaW5zJyxcbiAgfSxcbiAgY3VzdG9tX2ludGVncmF0aW9uczoge1xuICAgIGxhYmVsOiAnQ3VzdG9tIEludGVncmF0aW9ucycsXG4gICAgZGVzY3JpcHRpb246ICdDb25uZWN0IHRvIGV4dGVybmFsIHNlcnZpY2VzIGFuZCBjdXN0b20gd2ViaG9vayBlbmRwb2ludHMnLFxuICB9LFxuICBhdWRpdF9sb2c6IHtcbiAgICBsYWJlbDogJ0F1ZGl0IExvZycsXG4gICAgZGVzY3JpcHRpb246ICdEZXRhaWxlZCBhdWRpdCB0cmFpbCBvZiBhbGwgdXNlciBhbmQgc3lzdGVtIGFjdGlvbnMnLFxuICB9LFxufTtcblxuLy8gUmVzb2x1dGlvbiBsb2dpY1xuXG4vKipcbiAqIFJlc29sdmUgYSB1c2VyJ3MgZWZmZWN0aXZlIGZlYXR1cmUgc2V0LlxuICpcbiAqIDEuIFN5c2FkbWlucyAoaXNTdXBlckFkbWluKSBhbHdheXMgZ2V0IEFMTCBmZWF0dXJlcy5cbiAqIDIuIFN0YXJ0IHdpdGggdGhlIHRpZXIncyBkZWZhdWx0IGZlYXR1cmVzLlxuICogMy4gQXBwbHkgcGVyLXVzZXIgb3ZlcnJpZGVzOiBgdHJ1ZWAgYWRkcyBhIGZlYXR1cmUsIGBmYWxzZWAgcmVtb3ZlcyBpdC5cbiAqIDQuIEludmFsaWQgb3ZlcnJpZGUga2V5cyBhcmUgc2lsZW50bHkgaWdub3JlZC5cbiAqXG4gKiBAcGFyYW0gdGllciAtIFRoZSBvcmdhbml6YXRpb24ncyBxdW90YSB0aWVyXG4gKiBAcGFyYW0gZmVhdHVyZU92ZXJyaWRlcyAtIFBlci11c2VyIG92ZXJyaWRlcyAoa2V5ID0gZmVhdHVyZSBmbGFnLCB2YWx1ZSA9IGVuYWJsZWQpXG4gKiBAcGFyYW0gaXNTdXBlckFkbWluIC0gV2hldGhlciB0aGUgdXNlciBoYXMgdGhlIGdsb2JhbCBzdXBlci1hZG1pbiBmbGFnXG4gKiBAcmV0dXJucyBTb3J0ZWQgYXJyYXkgb2YgZW5hYmxlZCBmZWF0dXJlIGZsYWdzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlVXNlckZlYXR1cmVzKFxuICB0aWVyOiBRdW90YVRpZXIsXG4gIGZlYXR1cmVPdmVycmlkZXM/OiBSZWNvcmQ8c3RyaW5nLCBib29sZWFuPiB8IG51bGwsXG4gIGlzU3VwZXJBZG1pbj86IGJvb2xlYW4sXG4pOiBGZWF0dXJlRmxhZ1tdIHtcbiAgLy8gU3lzYWRtaW5zIGdldCBldmVyeXRoaW5nIHJlZ2FyZGxlc3Mgb2YgdGllci5cbiAgaWYgKGlzU3VwZXJBZG1pbikgcmV0dXJuIFsuLi5BTExfRkVBVFVSRV9GTEFHU107XG5cbiAgLy8gU3RhcnQgd2l0aCB0aWVyIGRlZmF1bHRzXG4gIGNvbnN0IGZlYXR1cmVzID0gbmV3IFNldDxGZWF0dXJlRmxhZz4oVElFUl9GRUFUVVJFU1t0aWVyXSA/PyBbXSk7XG5cbiAgLy8gQXBwbHkgcGVyLXVzZXIgb3ZlcnJpZGVzXG4gIGlmIChmZWF0dXJlT3ZlcnJpZGVzKSB7XG4gICAgZm9yIChjb25zdCBba2V5LCBlbmFibGVkXSBvZiBPYmplY3QuZW50cmllcyhmZWF0dXJlT3ZlcnJpZGVzKSkge1xuICAgICAgaWYgKCFpc1ZhbGlkRmVhdHVyZUZsYWcoa2V5KSkgY29udGludWU7XG4gICAgICBpZiAoZW5hYmxlZCkge1xuICAgICAgICBmZWF0dXJlcy5hZGQoa2V5KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGZlYXR1cmVzLmRlbGV0ZShrZXkpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8vIFJldHVybiBpbiBjYW5vbmljYWwgb3JkZXJcbiAgcmV0dXJuIEFMTF9GRUFUVVJFX0ZMQUdTLmZpbHRlcihmID0+IGZlYXR1cmVzLmhhcyhmKSk7XG59XG5cbi8qKlxuICogQ2hlY2sgaWYgYSBzcGVjaWZpYyBmZWF0dXJlIGlzIGVuYWJsZWQgZm9yIGEgdXNlci5cbiAqXG4gKiBAcGFyYW0gdGllciAtIFRoZSBvcmdhbml6YXRpb24ncyBxdW90YSB0aWVyXG4gKiBAcGFyYW0gZmVhdHVyZSAtIFRoZSBmZWF0dXJlIGZsYWcgdG8gY2hlY2tcbiAqIEBwYXJhbSBmZWF0dXJlT3ZlcnJpZGVzIC0gUGVyLXVzZXIgb3ZlcnJpZGVzXG4gKiBAcGFyYW0gaXNTdXBlckFkbWluIC0gV2hldGhlciB0aGUgdXNlciBoYXMgdGhlIGdsb2JhbCBzdXBlci1hZG1pbiBmbGFnXG4gKiBAcmV0dXJucyB0cnVlIGlmIHRoZSBmZWF0dXJlIGlzIGVuYWJsZWRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGhhc0ZlYXR1cmUoXG4gIHRpZXI6IFF1b3RhVGllcixcbiAgZmVhdHVyZTogRmVhdHVyZUZsYWcsXG4gIGZlYXR1cmVPdmVycmlkZXM/OiBSZWNvcmQ8c3RyaW5nLCBib29sZWFuPiB8IG51bGwsXG4gIGlzU3VwZXJBZG1pbj86IGJvb2xlYW4sXG4pOiBib29sZWFuIHtcbiAgaWYgKGlzU3VwZXJBZG1pbikgcmV0dXJuIHRydWU7XG5cbiAgLy8gQ2hlY2sgb3ZlcnJpZGUgZmlyc3RcbiAgaWYgKGZlYXR1cmVPdmVycmlkZXMgJiYgZmVhdHVyZSBpbiBmZWF0dXJlT3ZlcnJpZGVzKSB7XG4gICAgcmV0dXJuIGZlYXR1cmVPdmVycmlkZXNbZmVhdHVyZV07XG4gIH1cblxuICAvLyBGYWxsIGJhY2sgdG8gdGllciBkZWZhdWx0XG4gIHJldHVybiAoVElFUl9GRUFUVVJFU1t0aWVyXSA/PyBbXSkuaW5jbHVkZXMoZmVhdHVyZSk7XG59XG4iXX0=
|
package/lib/types/http.d.ts
CHANGED
|
@@ -15,23 +15,13 @@ export interface HttpRequest {
|
|
|
15
15
|
params: Record<string, string | string[] | undefined>;
|
|
16
16
|
/** Query parameters */
|
|
17
17
|
query: Record<string, unknown>;
|
|
18
|
-
/** Authenticated user (if present)
|
|
18
|
+
/** Authenticated user (if present). `sub` is the OIDC-standard subject
|
|
19
|
+
* (= user id); higher-level layers may attach additional fields, hence
|
|
20
|
+
* the index signature. */
|
|
19
21
|
user?: {
|
|
22
|
+
sub?: string;
|
|
20
23
|
organizationId?: string;
|
|
21
|
-
userId?: string;
|
|
22
24
|
role?: string;
|
|
23
25
|
[key: string]: unknown;
|
|
24
26
|
};
|
|
25
27
|
}
|
|
26
|
-
/**
|
|
27
|
-
* Generic HTTP response interface.
|
|
28
|
-
* Represents the minimal response shape needed by api-core utilities.
|
|
29
|
-
*/
|
|
30
|
-
export interface HttpResponse {
|
|
31
|
-
/** Set HTTP status code */
|
|
32
|
-
status(code: number): HttpResponse;
|
|
33
|
-
/** Send JSON response */
|
|
34
|
-
json(body: unknown): void;
|
|
35
|
-
/** Set response header */
|
|
36
|
-
setHeader(name: string, value: string | number): void;
|
|
37
|
-
}
|
package/lib/types/http.js
CHANGED
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
// Copyright 2026 Pipeline Builder Contributors
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHR0cC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90eXBlcy9odHRwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbi8qKlxuICogR2VuZXJpYyBIVFRQIGhlYWRlcnMgcmVwcmVzZW50YXRpb24uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSHR0cEhlYWRlcnMge1xuICBba2V5OiBzdHJpbmddOiBzdHJpbmcgfCBzdHJpbmdbXSB8IHVuZGVmaW5lZDtcbn1cblxuLyoqXG4gKiBHZW5lcmljIEhUVFAgcmVxdWVzdCBpbnRlcmZhY2UuXG4gKiBSZXByZXNlbnRzIHRoZSBtaW5pbWFsIHJlcXVlc3Qgc2hhcGUgbmVlZGVkIGJ5IGFwaS1jb3JlIHV0aWxpdGllcy5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBIdHRwUmVxdWVzdCB7XG4gIC8qKiBSZXF1ZXN0IGhlYWRlcnMgKi9cbiAgaGVhZGVyczogSHR0cEhlYWRlcnM7XG4gIC8qKiBSb3V0ZSBwYXJhbWV0ZXJzICovXG4gIHBhcmFtczogUmVjb3JkPHN0cmluZywgc3RyaW5nIHwgc3RyaW5nW10gfCB1bmRlZmluZWQ+
|
|
5
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHR0cC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90eXBlcy9odHRwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbi8qKlxuICogR2VuZXJpYyBIVFRQIGhlYWRlcnMgcmVwcmVzZW50YXRpb24uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSHR0cEhlYWRlcnMge1xuICBba2V5OiBzdHJpbmddOiBzdHJpbmcgfCBzdHJpbmdbXSB8IHVuZGVmaW5lZDtcbn1cblxuLyoqXG4gKiBHZW5lcmljIEhUVFAgcmVxdWVzdCBpbnRlcmZhY2UuXG4gKiBSZXByZXNlbnRzIHRoZSBtaW5pbWFsIHJlcXVlc3Qgc2hhcGUgbmVlZGVkIGJ5IGFwaS1jb3JlIHV0aWxpdGllcy5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBIdHRwUmVxdWVzdCB7XG4gIC8qKiBSZXF1ZXN0IGhlYWRlcnMgKi9cbiAgaGVhZGVyczogSHR0cEhlYWRlcnM7XG4gIC8qKiBSb3V0ZSBwYXJhbWV0ZXJzICovXG4gIHBhcmFtczogUmVjb3JkPHN0cmluZywgc3RyaW5nIHwgc3RyaW5nW10gfCB1bmRlZmluZWQ+O1xuICAvKiogUXVlcnkgcGFyYW1ldGVycyAqL1xuICBxdWVyeTogUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gIC8qKiBBdXRoZW50aWNhdGVkIHVzZXIgKGlmIHByZXNlbnQpLiBgc3ViYCBpcyB0aGUgT0lEQy1zdGFuZGFyZCBzdWJqZWN0XG4gICAqICAoPSB1c2VyIGlkKTsgaGlnaGVyLWxldmVsIGxheWVycyBtYXkgYXR0YWNoIGFkZGl0aW9uYWwgZmllbGRzLCBoZW5jZVxuICAgKiAgdGhlIGluZGV4IHNpZ25hdHVyZS4gKi9cbiAgdXNlcj86IHtcbiAgICBzdWI/OiBzdHJpbmc7XG4gICAgb3JnYW5pemF0aW9uSWQ/OiBzdHJpbmc7XG4gICAgcm9sZT86IHN0cmluZztcbiAgICBba2V5OiBzdHJpbmddOiB1bmtub3duO1xuICB9O1xufVxuXG4iXX0=
|
|
@@ -6,19 +6,25 @@ export interface QuotaTierLimits {
|
|
|
6
6
|
pipelines: number;
|
|
7
7
|
apiCalls: number;
|
|
8
8
|
aiCalls: number;
|
|
9
|
+
/**
|
|
10
|
+
* Aggregate registry storage cap in BYTES. Counted across every repo
|
|
11
|
+
* under the org's `org-{orgId}/` namespace. -1 means unlimited.
|
|
12
|
+
* push-gate reads this; the image-registry rejects token issuance for
|
|
13
|
+
* `push` scope when the org's measured usage exceeds the limit.
|
|
14
|
+
*/
|
|
15
|
+
storageBytes: number;
|
|
16
|
+
/** Count-quotas on the user-editable feature tables added to close per-org
|
|
17
|
+
* DoS via spam. -1 means unlimited. */
|
|
18
|
+
dashboards: number;
|
|
19
|
+
alertRules: number;
|
|
20
|
+
alertDestinations: number;
|
|
21
|
+
idpConfigs: number;
|
|
9
22
|
}
|
|
10
23
|
/** Full preset for a single tier (label + limits). */
|
|
11
24
|
export interface QuotaTierPreset {
|
|
12
25
|
label: string;
|
|
13
26
|
limits: QuotaTierLimits;
|
|
14
27
|
}
|
|
15
|
-
/**
|
|
16
|
-
* Preset limits for each tier. -1 means unlimited.
|
|
17
|
-
*
|
|
18
|
-
* AI calls are sized much smaller than `apiCalls` because each call has
|
|
19
|
-
* external provider cost (~$0.01–$0.10/call). Developer tier allows light
|
|
20
|
-
* exploration (100/period); Pro lifts to 5000; Unlimited is uncapped.
|
|
21
|
-
*/
|
|
22
28
|
export declare const QUOTA_TIERS: Record<QuotaTier, QuotaTierPreset>;
|
|
23
29
|
/** All valid tier names. */
|
|
24
30
|
export declare const VALID_TIERS: readonly QuotaTier[];
|
package/lib/types/quota-tiers.js
CHANGED
|
@@ -9,13 +9,62 @@ exports.getTierLimits = getTierLimits;
|
|
|
9
9
|
* Preset limits for each tier. -1 means unlimited.
|
|
10
10
|
*
|
|
11
11
|
* AI calls are sized much smaller than `apiCalls` because each call has
|
|
12
|
-
* external provider cost (~$0.01
|
|
12
|
+
* external provider cost (~$0.01$0.10/call). Developer tier allows light
|
|
13
13
|
* exploration (100/period); Pro lifts to 5000; Unlimited is uncapped.
|
|
14
|
+
*
|
|
15
|
+
* `storageBytes` is the aggregate registry cap per org. Sized
|
|
16
|
+
* around plugin-image realities: a typical plugin image is 200500 MB;
|
|
17
|
+
* Developer's 5 GB holds ~10 versions × ~500 MB, Pro's 100 GB covers a
|
|
18
|
+
* mature catalog. Operators can override per-org via the quota CRUD API.
|
|
14
19
|
*/
|
|
20
|
+
const GB = 1024 * 1024 * 1024;
|
|
15
21
|
exports.QUOTA_TIERS = {
|
|
16
|
-
developer: {
|
|
17
|
-
|
|
18
|
-
|
|
22
|
+
developer: {
|
|
23
|
+
label: 'Developer',
|
|
24
|
+
limits: {
|
|
25
|
+
plugins: 100,
|
|
26
|
+
pipelines: 10,
|
|
27
|
+
apiCalls: -1,
|
|
28
|
+
aiCalls: 100,
|
|
29
|
+
storageBytes: 5 * GB,
|
|
30
|
+
// Counts sized to "comfortably enough for one team, not a script spam":
|
|
31
|
+
// 20 dashboards covers ops + per-service drill-downs, 50 alert rules
|
|
32
|
+
// covers per-service alerts, 10 destinations covers Slack channels
|
|
33
|
+
// per team + a webhook fallback, 1 IdP config (you only have one).
|
|
34
|
+
dashboards: 20,
|
|
35
|
+
alertRules: 50,
|
|
36
|
+
alertDestinations: 10,
|
|
37
|
+
idpConfigs: 1,
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
pro: {
|
|
41
|
+
label: 'Pro',
|
|
42
|
+
limits: {
|
|
43
|
+
plugins: 1000,
|
|
44
|
+
pipelines: 100,
|
|
45
|
+
apiCalls: -1,
|
|
46
|
+
aiCalls: 5000,
|
|
47
|
+
storageBytes: 100 * GB,
|
|
48
|
+
dashboards: 200,
|
|
49
|
+
alertRules: 500,
|
|
50
|
+
alertDestinations: 50,
|
|
51
|
+
idpConfigs: 5,
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
unlimited: {
|
|
55
|
+
label: 'Unlimited',
|
|
56
|
+
limits: {
|
|
57
|
+
plugins: -1,
|
|
58
|
+
pipelines: -1,
|
|
59
|
+
apiCalls: -1,
|
|
60
|
+
aiCalls: -1,
|
|
61
|
+
storageBytes: -1,
|
|
62
|
+
dashboards: -1,
|
|
63
|
+
alertRules: -1,
|
|
64
|
+
alertDestinations: -1,
|
|
65
|
+
idpConfigs: -1,
|
|
66
|
+
},
|
|
67
|
+
},
|
|
19
68
|
};
|
|
20
69
|
/** All valid tier names. */
|
|
21
70
|
exports.VALID_TIERS = Object.keys(exports.QUOTA_TIERS);
|
|
@@ -29,4 +78,4 @@ function isValidTier(value) {
|
|
|
29
78
|
function getTierLimits(tier) {
|
|
30
79
|
return isValidTier(tier) ? exports.QUOTA_TIERS[tier].limits : exports.QUOTA_TIERS.developer.limits;
|
|
31
80
|
}
|
|
32
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
81
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicXVvdGEtdGllcnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdHlwZXMvcXVvdGEtdGllcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7OztBQXFHdEMsa0NBRUM7QUFHRCxzQ0FFQztBQTVFRDs7Ozs7Ozs7Ozs7R0FXRztBQUNILE1BQU0sRUFBRSxHQUFHLElBQUksR0FBRyxJQUFJLEdBQUcsSUFBSSxDQUFDO0FBQ2pCLFFBQUEsV0FBVyxHQUF1QztJQUM3RCxTQUFTLEVBQUU7UUFDVCxLQUFLLEVBQUUsV0FBVztRQUNsQixNQUFNLEVBQUU7WUFDTixPQUFPLEVBQUUsR0FBRztZQUNaLFNBQVMsRUFBRSxFQUFFO1lBQ2IsUUFBUSxFQUFFLENBQUMsQ0FBQztZQUNaLE9BQU8sRUFBRSxHQUFHO1lBQ1osWUFBWSxFQUFFLENBQUMsR0FBRyxFQUFFO1lBQ3BCLHdFQUF3RTtZQUN4RSxxRUFBcUU7WUFDckUsbUVBQW1FO1lBQ25FLG1FQUFtRTtZQUNuRSxVQUFVLEVBQUUsRUFBRTtZQUNkLFVBQVUsRUFBRSxFQUFFO1lBQ2QsaUJBQWlCLEVBQUUsRUFBRTtZQUNyQixVQUFVLEVBQUUsQ0FBQztTQUNkO0tBQ0Y7SUFDRCxHQUFHLEVBQUU7UUFDSCxLQUFLLEVBQUUsS0FBSztRQUNaLE1BQU0sRUFBRTtZQUNOLE9BQU8sRUFBRSxJQUFJO1lBQ2IsU0FBUyxFQUFFLEdBQUc7WUFDZCxRQUFRLEVBQUUsQ0FBQyxDQUFDO1lBQ1osT0FBTyxFQUFFLElBQUk7WUFDYixZQUFZLEVBQUUsR0FBRyxHQUFHLEVBQUU7WUFDdEIsVUFBVSxFQUFFLEdBQUc7WUFDZixVQUFVLEVBQUUsR0FBRztZQUNmLGlCQUFpQixFQUFFLEVBQUU7WUFDckIsVUFBVSxFQUFFLENBQUM7U0FDZDtLQUNGO0lBQ0QsU0FBUyxFQUFFO1FBQ1QsS0FBSyxFQUFFLFdBQVc7UUFDbEIsTUFBTSxFQUFFO1lBQ04sT0FBTyxFQUFFLENBQUMsQ0FBQztZQUNYLFNBQVMsRUFBRSxDQUFDLENBQUM7WUFDYixRQUFRLEVBQUUsQ0FBQyxDQUFDO1lBQ1osT0FBTyxFQUFFLENBQUMsQ0FBQztZQUNYLFlBQVksRUFBRSxDQUFDLENBQUM7WUFDaEIsVUFBVSxFQUFFLENBQUMsQ0FBQztZQUNkLFVBQVUsRUFBRSxDQUFDLENBQUM7WUFDZCxpQkFBaUIsRUFBRSxDQUFDLENBQUM7WUFDckIsVUFBVSxFQUFFLENBQUMsQ0FBQztTQUNmO0tBQ0Y7Q0FDRixDQUFDO0FBRUYsNEJBQTRCO0FBQ2YsUUFBQSxXQUFXLEdBQXlCLE1BQU0sQ0FBQyxJQUFJLENBQUMsbUJBQVcsQ0FBZ0IsQ0FBQztBQUV6RixrREFBa0Q7QUFDckMsUUFBQSxZQUFZLEdBQWMsV0FBVyxDQUFDO0FBRW5ELG1EQUFtRDtBQUNuRCxTQUFnQixXQUFXLENBQUMsS0FBYTtJQUN2QyxPQUFPLEtBQUssSUFBSSxtQkFBVyxDQUFDO0FBQzlCLENBQUM7QUFFRCx5RUFBeUU7QUFDekUsU0FBZ0IsYUFBYSxDQUFDLElBQVk7SUFDeEMsT0FBTyxXQUFXLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLG1CQUFXLENBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxDQUFBLENBQUMsQ0FBQyxtQkFBVyxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUM7QUFDcEYsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG4vKiogQXZhaWxhYmxlIHF1b3RhIHRpZXIgaWRlbnRpZmllcnMuICovXG5leHBvcnQgdHlwZSBRdW90YVRpZXIgPSAnZGV2ZWxvcGVyJyB8ICdwcm8nIHwgJ3VubGltaXRlZCc7XG5cbi8qKiBMaW1pdCB2YWx1ZXMgZm9yIGVhY2ggcXVvdGEgdHlwZSB3aXRoaW4gYSB0aWVyLiAqL1xuZXhwb3J0IGludGVyZmFjZSBRdW90YVRpZXJMaW1pdHMge1xuICBwbHVnaW5zOiBudW1iZXI7XG4gIHBpcGVsaW5lczogbnVtYmVyO1xuICBhcGlDYWxsczogbnVtYmVyO1xuICBhaUNhbGxzOiBudW1iZXI7XG4gIC8qKlxuICAgKiBBZ2dyZWdhdGUgcmVnaXN0cnkgc3RvcmFnZSBjYXAgaW4gQllURVMuIENvdW50ZWQgYWNyb3NzIGV2ZXJ5IHJlcG9cbiAgICogdW5kZXIgdGhlIG9yZydzIGBvcmcte29yZ0lkfS9gIG5hbWVzcGFjZS4gLTEgbWVhbnMgdW5saW1pdGVkLlxuICAgKiBwdXNoLWdhdGUgcmVhZHMgdGhpczsgdGhlIGltYWdlLXJlZ2lzdHJ5IHJlamVjdHMgdG9rZW4gaXNzdWFuY2UgZm9yXG4gICAqIGBwdXNoYCBzY29wZSB3aGVuIHRoZSBvcmcncyBtZWFzdXJlZCB1c2FnZSBleGNlZWRzIHRoZSBsaW1pdC5cbiAgICovXG4gIHN0b3JhZ2VCeXRlczogbnVtYmVyO1xuICAvKiogQ291bnQtcXVvdGFzIG9uIHRoZSB1c2VyLWVkaXRhYmxlIGZlYXR1cmUgdGFibGVzIGFkZGVkIHRvIGNsb3NlIHBlci1vcmdcbiAgICogIERvUyB2aWEgc3BhbS4gLTEgbWVhbnMgdW5saW1pdGVkLiAqL1xuICBkYXNoYm9hcmRzOiBudW1iZXI7XG4gIGFsZXJ0UnVsZXM6IG51bWJlcjtcbiAgYWxlcnREZXN0aW5hdGlvbnM6IG51bWJlcjtcbiAgaWRwQ29uZmlnczogbnVtYmVyO1xufVxuXG4vKiogRnVsbCBwcmVzZXQgZm9yIGEgc2luZ2xlIHRpZXIgKGxhYmVsICsgbGltaXRzKS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUXVvdGFUaWVyUHJlc2V0IHtcbiAgbGFiZWw6IHN0cmluZztcbiAgbGltaXRzOiBRdW90YVRpZXJMaW1pdHM7XG59XG5cbi8qKlxuICogUHJlc2V0IGxpbWl0cyBmb3IgZWFjaCB0aWVyLiAtMSBtZWFucyB1bmxpbWl0ZWQuXG4gKlxuICogQUkgY2FsbHMgYXJlIHNpemVkIG11Y2ggc21hbGxlciB0aGFuIGBhcGlDYWxsc2AgYmVjYXVzZSBlYWNoIGNhbGwgaGFzXG4gKiBleHRlcm5hbCBwcm92aWRlciBjb3N0ICh+JDAuMDEkMC4xMC9jYWxsKS4gRGV2ZWxvcGVyIHRpZXIgYWxsb3dzIGxpZ2h0XG4gKiBleHBsb3JhdGlvbiAoMTAwL3BlcmlvZCk7IFBybyBsaWZ0cyB0byA1MDAwOyBVbmxpbWl0ZWQgaXMgdW5jYXBwZWQuXG4gKlxuICogYHN0b3JhZ2VCeXRlc2AgaXMgdGhlIGFnZ3JlZ2F0ZSByZWdpc3RyeSBjYXAgcGVyIG9yZy4gU2l6ZWRcbiAqIGFyb3VuZCBwbHVnaW4taW1hZ2UgcmVhbGl0aWVzOiBhIHR5cGljYWwgcGx1Z2luIGltYWdlIGlzIDIwMDUwMCBNQjtcbiAqIERldmVsb3BlcidzIDUgR0IgaG9sZHMgfjEwIHZlcnNpb25zIMOXIH41MDAgTUIsIFBybydzIDEwMCBHQiBjb3ZlcnMgYVxuICogbWF0dXJlIGNhdGFsb2cuIE9wZXJhdG9ycyBjYW4gb3ZlcnJpZGUgcGVyLW9yZyB2aWEgdGhlIHF1b3RhIENSVUQgQVBJLlxuICovXG5jb25zdCBHQiA9IDEwMjQgKiAxMDI0ICogMTAyNDtcbmV4cG9ydCBjb25zdCBRVU9UQV9USUVSUzogUmVjb3JkPFF1b3RhVGllciwgUXVvdGFUaWVyUHJlc2V0PiA9IHtcbiAgZGV2ZWxvcGVyOiB7XG4gICAgbGFiZWw6ICdEZXZlbG9wZXInLFxuICAgIGxpbWl0czoge1xuICAgICAgcGx1Z2luczogMTAwLFxuICAgICAgcGlwZWxpbmVzOiAxMCxcbiAgICAgIGFwaUNhbGxzOiAtMSxcbiAgICAgIGFpQ2FsbHM6IDEwMCxcbiAgICAgIHN0b3JhZ2VCeXRlczogNSAqIEdCLFxuICAgICAgLy8gQ291bnRzIHNpemVkIHRvIFwiY29tZm9ydGFibHkgZW5vdWdoIGZvciBvbmUgdGVhbSwgbm90IGEgc2NyaXB0IHNwYW1cIjpcbiAgICAgIC8vIDIwIGRhc2hib2FyZHMgY292ZXJzIG9wcyArIHBlci1zZXJ2aWNlIGRyaWxsLWRvd25zLCA1MCBhbGVydCBydWxlc1xuICAgICAgLy8gY292ZXJzIHBlci1zZXJ2aWNlIGFsZXJ0cywgMTAgZGVzdGluYXRpb25zIGNvdmVycyBTbGFjayBjaGFubmVsc1xuICAgICAgLy8gcGVyIHRlYW0gKyBhIHdlYmhvb2sgZmFsbGJhY2ssIDEgSWRQIGNvbmZpZyAoeW91IG9ubHkgaGF2ZSBvbmUpLlxuICAgICAgZGFzaGJvYXJkczogMjAsXG4gICAgICBhbGVydFJ1bGVzOiA1MCxcbiAgICAgIGFsZXJ0RGVzdGluYXRpb25zOiAxMCxcbiAgICAgIGlkcENvbmZpZ3M6IDEsXG4gICAgfSxcbiAgfSxcbiAgcHJvOiB7XG4gICAgbGFiZWw6ICdQcm8nLFxuICAgIGxpbWl0czoge1xuICAgICAgcGx1Z2luczogMTAwMCxcbiAgICAgIHBpcGVsaW5lczogMTAwLFxuICAgICAgYXBpQ2FsbHM6IC0xLFxuICAgICAgYWlDYWxsczogNTAwMCxcbiAgICAgIHN0b3JhZ2VCeXRlczogMTAwICogR0IsXG4gICAgICBkYXNoYm9hcmRzOiAyMDAsXG4gICAgICBhbGVydFJ1bGVzOiA1MDAsXG4gICAgICBhbGVydERlc3RpbmF0aW9uczogNTAsXG4gICAgICBpZHBDb25maWdzOiA1LFxuICAgIH0sXG4gIH0sXG4gIHVubGltaXRlZDoge1xuICAgIGxhYmVsOiAnVW5saW1pdGVkJyxcbiAgICBsaW1pdHM6IHtcbiAgICAgIHBsdWdpbnM6IC0xLFxuICAgICAgcGlwZWxpbmVzOiAtMSxcbiAgICAgIGFwaUNhbGxzOiAtMSxcbiAgICAgIGFpQ2FsbHM6IC0xLFxuICAgICAgc3RvcmFnZUJ5dGVzOiAtMSxcbiAgICAgIGRhc2hib2FyZHM6IC0xLFxuICAgICAgYWxlcnRSdWxlczogLTEsXG4gICAgICBhbGVydERlc3RpbmF0aW9uczogLTEsXG4gICAgICBpZHBDb25maWdzOiAtMSxcbiAgICB9LFxuICB9LFxufTtcblxuLyoqIEFsbCB2YWxpZCB0aWVyIG5hbWVzLiAqL1xuZXhwb3J0IGNvbnN0IFZBTElEX1RJRVJTOiByZWFkb25seSBRdW90YVRpZXJbXSA9IE9iamVjdC5rZXlzKFFVT1RBX1RJRVJTKSBhcyBRdW90YVRpZXJbXTtcblxuLyoqIERlZmF1bHQgdGllciBhc3NpZ25lZCB0byBuZXcgb3JnYW5pemF0aW9ucy4gKi9cbmV4cG9ydCBjb25zdCBERUZBVUxUX1RJRVI6IFF1b3RhVGllciA9ICdkZXZlbG9wZXInO1xuXG4vKiogQ2hlY2sgd2hldGhlciBhIHN0cmluZyBpcyBhIHZhbGlkIFF1b3RhVGllci4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1ZhbGlkVGllcih2YWx1ZTogc3RyaW5nKTogdmFsdWUgaXMgUXVvdGFUaWVyIHtcbiAgcmV0dXJuIHZhbHVlIGluIFFVT1RBX1RJRVJTO1xufVxuXG4vKiogR2V0IHRoZSBkZWZhdWx0IGxpbWl0cyBmb3IgYSBnaXZlbiB0aWVyIChmYWxscyBiYWNrIHRvIGRldmVsb3BlcikuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0VGllckxpbWl0cyh0aWVyOiBzdHJpbmcpOiBRdW90YVRpZXJMaW1pdHMge1xuICByZXR1cm4gaXNWYWxpZFRpZXIodGllcikgPyBRVU9UQV9USUVSU1t0aWVyXS5saW1pdHM6IFFVT1RBX1RJRVJTLmRldmVsb3Blci5saW1pdHM7XG59XG4iXX0=
|
package/lib/utils/identity.js
CHANGED
|
@@ -31,14 +31,14 @@ const headers_1 = require("./headers");
|
|
|
31
31
|
* ```
|
|
32
32
|
*/
|
|
33
33
|
function getIdentity(req) {
|
|
34
|
-
// Prefer JWT-verified claims (req.user) over raw headers to prevent
|
|
35
|
-
// Headers are only used as fallback or for fields not in the
|
|
34
|
+
// Prefer JWT-verified claims (req.user) over raw headers to prevent
|
|
35
|
+
// spoofing. Headers are only used as fallback or for fields not in the
|
|
36
|
+
// JWT (e.g. requestId). The JWT payload uses `sub` for the user id per
|
|
37
|
+
// OIDC convention; that's our authoritative source.
|
|
36
38
|
const user = req.user;
|
|
37
39
|
return {
|
|
38
40
|
orgId: user?.organizationId || (0, headers_1.getHeaderString)(req.headers['x-org-id']),
|
|
39
|
-
userId: user?.sub
|
|
40
|
-
|| user?.userId
|
|
41
|
-
|| (0, headers_1.getHeaderString)(req.headers['x-user-id']),
|
|
41
|
+
userId: user?.sub || (0, headers_1.getHeaderString)(req.headers['x-user-id']),
|
|
42
42
|
requestId: (0, headers_1.getHeaderString)(req.headers['x-request-id']),
|
|
43
43
|
role: user?.role || (0, headers_1.getHeaderString)(req.headers['x-user-role']),
|
|
44
44
|
};
|
|
@@ -72,4 +72,4 @@ function validateIdentity(identity, required) {
|
|
|
72
72
|
missing,
|
|
73
73
|
};
|
|
74
74
|
}
|
|
75
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
75
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaWRlbnRpdHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvaWRlbnRpdHkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7O0FBNEN0QyxrQ0FZQztBQW1CRCw0Q0FnQkM7QUF6RkQsdUNBQTRDO0FBaUI1Qzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBd0JHO0FBQ0gsU0FBZ0IsV0FBVyxDQUFDLEdBQWdCO0lBQzFDLG9FQUFvRTtJQUNwRSx1RUFBdUU7SUFDdkUsdUVBQXVFO0lBQ3ZFLG9EQUFvRDtJQUNwRCxNQUFNLElBQUksR0FBRyxHQUFHLENBQUMsSUFBSSxDQUFDO0lBQ3RCLE9BQU87UUFDTCxLQUFLLEVBQUUsSUFBSSxFQUFFLGNBQWMsSUFBSSxJQUFBLHlCQUFlLEVBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUN2RSxNQUFNLEVBQUUsSUFBSSxFQUFFLEdBQUcsSUFBSSxJQUFBLHlCQUFlLEVBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUM5RCxTQUFTLEVBQUUsSUFBQSx5QkFBZSxFQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFDLENBQUM7UUFDdkQsSUFBSSxFQUFFLElBQUksRUFBRSxJQUFJLElBQUksSUFBQSx5QkFBZSxFQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLENBQUM7S0FDaEUsQ0FBQztBQUNKLENBQUM7QUFFRDs7Ozs7Ozs7Ozs7Ozs7OztHQWdCRztBQUNILFNBQWdCLGdCQUFnQixDQUM5QixRQUF5QixFQUN6QixRQUFtQztJQUVuQyxNQUFNLE9BQU8sR0FBYSxFQUFFLENBQUM7SUFFN0IsS0FBSyxNQUFNLEtBQUssSUFBSSxRQUFRLEVBQUUsQ0FBQztRQUM3QixJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDckIsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLEtBQUssQ0FBQyxPQUFPLENBQUMsVUFBVSxFQUFFLEtBQUssQ0FBQyxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUMsQ0FBQztRQUN0RSxDQUFDO0lBQ0gsQ0FBQztJQUVELE9BQU87UUFDTCxPQUFPLEVBQUUsT0FBTyxDQUFDLE1BQU0sS0FBSyxDQUFDO1FBQzdCLE9BQU87S0FDUixDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgeyBnZXRIZWFkZXJTdHJpbmcgfSBmcm9tICcuL2hlYWRlcnMnO1xuaW1wb3J0IHsgSHR0cFJlcXVlc3QgfSBmcm9tICcuLi90eXBlcy9odHRwJztcblxuLyoqXG4gKiBJZGVudGl0eSBpbmZvcm1hdGlvbiBleHRyYWN0ZWQgZnJvbSByZXF1ZXN0IGhlYWRlcnMuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmVxdWVzdElkZW50aXR5IHtcbiAgLyoqIE9yZ2FuaXphdGlvbiBJRCBmcm9tIHgtb3JnLWlkIGhlYWRlciAqL1xuICByZWFkb25seSBvcmdJZD86IHN0cmluZztcbiAgLyoqIFVzZXIgSUQgZnJvbSB4LXVzZXItaWQgaGVhZGVyICovXG4gIHJlYWRvbmx5IHVzZXJJZD86IHN0cmluZztcbiAgLyoqIFJlcXVlc3QgSUQgZnJvbSB4LXJlcXVlc3QtaWQgaGVhZGVyICovXG4gIHJlYWRvbmx5IHJlcXVlc3RJZD86IHN0cmluZztcbiAgLyoqIFVzZXIgcm9sZSBmcm9tIHgtdXNlci1yb2xlIGhlYWRlciAoZGVjb2RlZCBmcm9tIEpXVCkgKi9cbiAgcmVhZG9ubHkgcm9sZT86IHN0cmluZztcbn1cblxuLyoqXG4gKiBFeHRyYWN0IGlkZW50aXR5IGluZm9ybWF0aW9uIGZyb20gcmVxdWVzdCBoZWFkZXJzLlxuICpcbiAqIEV4dHJhY3RzIGNvbW1vbiBpZGVudGl0eSBoZWFkZXJzIHVzZWQgZm9yIG11bHRpLXRlbmFudCBhdXRoZW50aWNhdGlvbjpcbiAqIC0geC1vcmctaWQ6IE9yZ2FuaXphdGlvbiBpZGVudGlmaWVyXG4gKiAtIHgtdXNlci1pZDogVXNlciBpZGVudGlmaWVyXG4gKiAtIHgtcmVxdWVzdC1pZDogUmVxdWVzdCB0cmFjZSBpZGVudGlmaWVyXG4gKiAtIHgtdXNlci1yb2xlOiBVc2VyIHJvbGVcbiAqXG4gKiBAcGFyYW0gcmVxIC0gSFRUUCByZXF1ZXN0IG9iamVjdFxuICogQHJldHVybnMgSWRlbnRpdHkgb2JqZWN0IHdpdGggb3JnSWQsIHVzZXJJZCwgcmVxdWVzdElkLCBhbmQgcm9sZVxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBhcHAucG9zdCgnL2FwaS9yZXNvdXJjZScsIHJlcXVpcmVBdXRoLCBhc3luYyAocmVxLCByZXMpID0+IHtcbiAqICAgY29uc3QgaWRlbnRpdHkgPSBnZXRJZGVudGl0eShyZXEpO1xuICpcbiAqICAgaWYgKCFpZGVudGl0eS5vcmdJZCkge1xuICogICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCA0MDAsICd4LW9yZy1pZCBoZWFkZXIgcmVxdWlyZWQnKTtcbiAqICAgfVxuICpcbiAqICAgLy8gVXNlIGlkZW50aXR5Lm9yZ0lkLCBpZGVudGl0eS51c2VySWQsIGV0Yy5cbiAqIH0pO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRJZGVudGl0eShyZXE6IEh0dHBSZXF1ZXN0KTogUmVxdWVzdElkZW50aXR5IHtcbiAgLy8gUHJlZmVyIEpXVC12ZXJpZmllZCBjbGFpbXMgKHJlcS51c2VyKSBvdmVyIHJhdyBoZWFkZXJzIHRvIHByZXZlbnRcbiAgLy8gc3Bvb2ZpbmcuIEhlYWRlcnMgYXJlIG9ubHkgdXNlZCBhcyBmYWxsYmFjayBvciBmb3IgZmllbGRzIG5vdCBpbiB0aGVcbiAgLy8gSldUIChlLmcuIHJlcXVlc3RJZCkuIFRoZSBKV1QgcGF5bG9hZCB1c2VzIGBzdWJgIGZvciB0aGUgdXNlciBpZCBwZXJcbiAgLy8gT0lEQyBjb252ZW50aW9uOyB0aGF0J3Mgb3VyIGF1dGhvcml0YXRpdmUgc291cmNlLlxuICBjb25zdCB1c2VyID0gcmVxLnVzZXI7XG4gIHJldHVybiB7XG4gICAgb3JnSWQ6IHVzZXI/Lm9yZ2FuaXphdGlvbklkIHx8IGdldEhlYWRlclN0cmluZyhyZXEuaGVhZGVyc1sneC1vcmctaWQnXSksXG4gICAgdXNlcklkOiB1c2VyPy5zdWIgfHwgZ2V0SGVhZGVyU3RyaW5nKHJlcS5oZWFkZXJzWyd4LXVzZXItaWQnXSksXG4gICAgcmVxdWVzdElkOiBnZXRIZWFkZXJTdHJpbmcocmVxLmhlYWRlcnNbJ3gtcmVxdWVzdC1pZCddKSxcbiAgICByb2xlOiB1c2VyPy5yb2xlIHx8IGdldEhlYWRlclN0cmluZyhyZXEuaGVhZGVyc1sneC11c2VyLXJvbGUnXSksXG4gIH07XG59XG5cbi8qKlxuICogVmFsaWRhdGUgdGhhdCByZXF1aXJlZCBpZGVudGl0eSBmaWVsZHMgYXJlIHByZXNlbnQuXG4gKlxuICogQHBhcmFtIGlkZW50aXR5IC0gSWRlbnRpdHkgb2JqZWN0IHRvIHZhbGlkYXRlXG4gKiBAcGFyYW0gcmVxdWlyZWQgLSBBcnJheSBvZiByZXF1aXJlZCBmaWVsZCBuYW1lc1xuICogQHJldHVybnMgT2JqZWN0IHdpdGggaXNWYWxpZCBib29sZWFuIGFuZCBtaXNzaW5nIGZpZWxkcyBhcnJheVxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjb25zdCBpZGVudGl0eSA9IGdldElkZW50aXR5KHJlcSk7XG4gKiBjb25zdCB2YWxpZGF0aW9uID0gdmFsaWRhdGVJZGVudGl0eShpZGVudGl0eSwgWydvcmdJZCcsICd1c2VySWQnXSk7XG4gKlxuICogaWYgKCF2YWxpZGF0aW9uLmlzVmFsaWQpIHtcbiAqICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIDQwMCwgYE1pc3NpbmcgcmVxdWlyZWQgaGVhZGVyczogJHt2YWxpZGF0aW9uLm1pc3Npbmcuam9pbignLCAnKX1gKTtcbiAqIH1cbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVJZGVudGl0eShcbiAgaWRlbnRpdHk6IFJlcXVlc3RJZGVudGl0eSxcbiAgcmVxdWlyZWQ6IChrZXlvZiBSZXF1ZXN0SWRlbnRpdHkpW10sXG4pOiB7IGlzVmFsaWQ6IGJvb2xlYW47IG1pc3Npbmc6IHN0cmluZ1tdIH0ge1xuICBjb25zdCBtaXNzaW5nOiBzdHJpbmdbXSA9IFtdO1xuXG4gIGZvciAoY29uc3QgZmllbGQgb2YgcmVxdWlyZWQpIHtcbiAgICBpZiAoIWlkZW50aXR5W2ZpZWxkXSkge1xuICAgICAgbWlzc2luZy5wdXNoKGB4LSR7ZmllbGQucmVwbGFjZSgvKFtBLVpdKS9nLCAnLSQxJykudG9Mb3dlckNhc2UoKX1gKTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4ge1xuICAgIGlzVmFsaWQ6IG1pc3NpbmcubGVuZ3RoID09PSAwLFxuICAgIG1pc3NpbmcsXG4gIH07XG59XG4iXX0=
|
package/lib/utils/index.d.ts
CHANGED
package/lib/utils/index.js
CHANGED
|
@@ -25,4 +25,7 @@ __exportStar(require("./object"), exports);
|
|
|
25
25
|
__exportStar(require("./alias-resolver"), exports);
|
|
26
26
|
__exportStar(require("./concurrency"), exports);
|
|
27
27
|
__exportStar(require("./audit"), exports);
|
|
28
|
-
|
|
28
|
+
__exportStar(require("./secret-encryption"), exports);
|
|
29
|
+
__exportStar(require("./org-aws-credentials"), exports);
|
|
30
|
+
__exportStar(require("./metric-emitter"), exports);
|
|
31
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7Ozs7Ozs7Ozs7Ozs7Ozs7QUFFdEMsMkNBQXlCO0FBQ3pCLDZDQUEyQjtBQUMzQiwyQ0FBeUI7QUFDekIsNENBQTBCO0FBQzFCLDZDQUEyQjtBQUMzQiwyQ0FBeUI7QUFDekIsbURBQWlDO0FBQ2pDLGdEQUE4QjtBQUM5QiwwQ0FBd0I7QUFDeEIsc0RBQW9DO0FBQ3BDLHdEQUFzQztBQUN0QyxtREFBaUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuZXhwb3J0ICogZnJvbSAnLi9sb2dnZXInO1xuZXhwb3J0ICogZnJvbSAnLi9yZXNwb25zZSc7XG5leHBvcnQgKiBmcm9tICcuL3BhcmFtcyc7XG5leHBvcnQgKiBmcm9tICcuL2hlYWRlcnMnO1xuZXhwb3J0ICogZnJvbSAnLi9pZGVudGl0eSc7XG5leHBvcnQgKiBmcm9tICcuL29iamVjdCc7XG5leHBvcnQgKiBmcm9tICcuL2FsaWFzLXJlc29sdmVyJztcbmV4cG9ydCAqIGZyb20gJy4vY29uY3VycmVuY3knO1xuZXhwb3J0ICogZnJvbSAnLi9hdWRpdCc7XG5leHBvcnQgKiBmcm9tICcuL3NlY3JldC1lbmNyeXB0aW9uJztcbmV4cG9ydCAqIGZyb20gJy4vb3JnLWF3cy1jcmVkZW50aWFscyc7XG5leHBvcnQgKiBmcm9tICcuL21ldHJpYy1lbWl0dGVyJztcbiJdfQ==
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pluggable counter-emit shim.
|
|
3
|
+
*
|
|
4
|
+
* Background: several api-core primitives (quota client fail-open, future
|
|
5
|
+
* security-event hooks) want to record Prometheus counters when something
|
|
6
|
+
* notable happens. The actual `prom-client` Counter registration lives in
|
|
7
|
+
* api-server, and api-core must not depend on api-server (api-core is
|
|
8
|
+
* upstream — Express infrastructure imports it, not the other way around).
|
|
9
|
+
*
|
|
10
|
+
* This module is the seam. api-core code calls `emitCounter(name, labels)`;
|
|
11
|
+
* by default it's a no-op (tests, CLIs, environments without Prometheus).
|
|
12
|
+
* api-server's app-factory calls `setCounterEmitter(incCounter)` at startup
|
|
13
|
+
* so production processes start incrementing the real counter on the
|
|
14
|
+
* shared registry.
|
|
15
|
+
*
|
|
16
|
+
* Why a callback instead of an interface registered via DI? The call sites
|
|
17
|
+
* (quota fail-open, etc.) sit in deep helpers that never touch the Express
|
|
18
|
+
* context, so requiring a `metrics` parameter on every call would mean
|
|
19
|
+
* threading it through dozens of unrelated functions. A process-singleton
|
|
20
|
+
* callback is the simplest non-invasive option; the trade-off is one
|
|
21
|
+
* shared global, which is acceptable for a sink that's strictly write-only.
|
|
22
|
+
*/
|
|
23
|
+
/** Callable signature mirroring api-server's `incCounter`. */
|
|
24
|
+
export type CounterEmitter = (name: string, labels?: Record<string, string>, value?: number) => void;
|
|
25
|
+
/**
|
|
26
|
+
* Register the real counter implementation. Idempotent — the last call wins;
|
|
27
|
+
* typically called once at service startup from api-server.
|
|
28
|
+
*/
|
|
29
|
+
export declare function setCounterEmitter(fn: CounterEmitter): void;
|
|
30
|
+
/** Reset to the no-op emitter. For tests that want to clear any wiring. */
|
|
31
|
+
export declare function resetCounterEmitter(): void;
|
|
32
|
+
/**
|
|
33
|
+
* Record a counter event. Safe to call from any api-core module — if no
|
|
34
|
+
* emitter is wired, this is a no-op.
|
|
35
|
+
*/
|
|
36
|
+
export declare function emitCounter(name: string, labels?: Record<string, string>, value?: number): void;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.setCounterEmitter = setCounterEmitter;
|
|
6
|
+
exports.resetCounterEmitter = resetCounterEmitter;
|
|
7
|
+
exports.emitCounter = emitCounter;
|
|
8
|
+
let emitter = () => {
|
|
9
|
+
// Default no-op. api-server wires this to a real Prometheus counter at
|
|
10
|
+
// startup; until then, calls from api-core helpers are silently dropped
|
|
11
|
+
// (which is what we want in tests and CLIs that don't run a Prom server).
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Register the real counter implementation. Idempotent — the last call wins;
|
|
15
|
+
* typically called once at service startup from api-server.
|
|
16
|
+
*/
|
|
17
|
+
function setCounterEmitter(fn) {
|
|
18
|
+
emitter = fn;
|
|
19
|
+
}
|
|
20
|
+
/** Reset to the no-op emitter. For tests that want to clear any wiring. */
|
|
21
|
+
function resetCounterEmitter() {
|
|
22
|
+
emitter = () => undefined;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Record a counter event. Safe to call from any api-core module — if no
|
|
26
|
+
* emitter is wired, this is a no-op.
|
|
27
|
+
*/
|
|
28
|
+
function emitCounter(name, labels = {}, value = 1) {
|
|
29
|
+
try {
|
|
30
|
+
emitter(name, labels, value);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// Never let metric emission break the calling path. A misbehaving
|
|
34
|
+
// emitter shouldn't be able to take down quota checks (or anything else).
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWV0cmljLWVtaXR0ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvbWV0cmljLWVtaXR0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7O0FBc0N0Qyw4Q0FFQztBQUdELGtEQUVDO0FBTUQsa0NBT0M7QUE5QkQsSUFBSSxPQUFPLEdBQW1CLEdBQUcsRUFBRTtJQUNqQyx1RUFBdUU7SUFDdkUsd0VBQXdFO0lBQ3hFLDBFQUEwRTtBQUM1RSxDQUFDLENBQUM7QUFFRjs7O0dBR0c7QUFDSCxTQUFnQixpQkFBaUIsQ0FBQyxFQUFrQjtJQUNsRCxPQUFPLEdBQUcsRUFBRSxDQUFDO0FBQ2YsQ0FBQztBQUVELDJFQUEyRTtBQUMzRSxTQUFnQixtQkFBbUI7SUFDakMsT0FBTyxHQUFHLEdBQUcsRUFBRSxDQUFDLFNBQVMsQ0FBQztBQUM1QixDQUFDO0FBRUQ7OztHQUdHO0FBQ0gsU0FBZ0IsV0FBVyxDQUFDLElBQVksRUFBRSxTQUFpQyxFQUFFLEVBQUUsS0FBSyxHQUFHLENBQUM7SUFDdEYsSUFBSSxDQUFDO1FBQ0gsT0FBTyxDQUFDLElBQUksRUFBRSxNQUFNLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDL0IsQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNQLGtFQUFrRTtRQUNsRSwwRUFBMEU7SUFDNUUsQ0FBQztBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuLyoqXG4gKiBQbHVnZ2FibGUgY291bnRlci1lbWl0IHNoaW0uXG4gKlxuICogQmFja2dyb3VuZDogc2V2ZXJhbCBhcGktY29yZSBwcmltaXRpdmVzIChxdW90YSBjbGllbnQgZmFpbC1vcGVuLCBmdXR1cmVcbiAqIHNlY3VyaXR5LWV2ZW50IGhvb2tzKSB3YW50IHRvIHJlY29yZCBQcm9tZXRoZXVzIGNvdW50ZXJzIHdoZW4gc29tZXRoaW5nXG4gKiBub3RhYmxlIGhhcHBlbnMuIFRoZSBhY3R1YWwgYHByb20tY2xpZW50YCBDb3VudGVyIHJlZ2lzdHJhdGlvbiBsaXZlcyBpblxuICogYXBpLXNlcnZlciwgYW5kIGFwaS1jb3JlIG11c3Qgbm90IGRlcGVuZCBvbiBhcGktc2VydmVyIChhcGktY29yZSBpc1xuICogdXBzdHJlYW0g4oCUIEV4cHJlc3MgaW5mcmFzdHJ1Y3R1cmUgaW1wb3J0cyBpdCwgbm90IHRoZSBvdGhlciB3YXkgYXJvdW5kKS5cbiAqXG4gKiBUaGlzIG1vZHVsZSBpcyB0aGUgc2VhbS4gYXBpLWNvcmUgY29kZSBjYWxscyBgZW1pdENvdW50ZXIobmFtZSwgbGFiZWxzKWA7XG4gKiBieSBkZWZhdWx0IGl0J3MgYSBuby1vcCAodGVzdHMsIENMSXMsIGVudmlyb25tZW50cyB3aXRob3V0IFByb21ldGhldXMpLlxuICogYXBpLXNlcnZlcidzIGFwcC1mYWN0b3J5IGNhbGxzIGBzZXRDb3VudGVyRW1pdHRlcihpbmNDb3VudGVyKWAgYXQgc3RhcnR1cFxuICogc28gcHJvZHVjdGlvbiBwcm9jZXNzZXMgc3RhcnQgaW5jcmVtZW50aW5nIHRoZSByZWFsIGNvdW50ZXIgb24gdGhlXG4gKiBzaGFyZWQgcmVnaXN0cnkuXG4gKlxuICogV2h5IGEgY2FsbGJhY2sgaW5zdGVhZCBvZiBhbiBpbnRlcmZhY2UgcmVnaXN0ZXJlZCB2aWEgREk/IFRoZSBjYWxsIHNpdGVzXG4gKiAocXVvdGEgZmFpbC1vcGVuLCBldGMuKSBzaXQgaW4gZGVlcCBoZWxwZXJzIHRoYXQgbmV2ZXIgdG91Y2ggdGhlIEV4cHJlc3NcbiAqIGNvbnRleHQsIHNvIHJlcXVpcmluZyBhIGBtZXRyaWNzYCBwYXJhbWV0ZXIgb24gZXZlcnkgY2FsbCB3b3VsZCBtZWFuXG4gKiB0aHJlYWRpbmcgaXQgdGhyb3VnaCBkb3plbnMgb2YgdW5yZWxhdGVkIGZ1bmN0aW9ucy4gQSBwcm9jZXNzLXNpbmdsZXRvblxuICogY2FsbGJhY2sgaXMgdGhlIHNpbXBsZXN0IG5vbi1pbnZhc2l2ZSBvcHRpb247IHRoZSB0cmFkZS1vZmYgaXMgb25lXG4gKiBzaGFyZWQgZ2xvYmFsLCB3aGljaCBpcyBhY2NlcHRhYmxlIGZvciBhIHNpbmsgdGhhdCdzIHN0cmljdGx5IHdyaXRlLW9ubHkuXG4gKi9cblxuLyoqIENhbGxhYmxlIHNpZ25hdHVyZSBtaXJyb3JpbmcgYXBpLXNlcnZlcidzIGBpbmNDb3VudGVyYC4gKi9cbmV4cG9ydCB0eXBlIENvdW50ZXJFbWl0dGVyID0gKG5hbWU6IHN0cmluZywgbGFiZWxzPzogUmVjb3JkPHN0cmluZywgc3RyaW5nPiwgdmFsdWU/OiBudW1iZXIpID0+IHZvaWQ7XG5cbmxldCBlbWl0dGVyOiBDb3VudGVyRW1pdHRlciA9ICgpID0+IHtcbiAgLy8gRGVmYXVsdCBuby1vcC4gYXBpLXNlcnZlciB3aXJlcyB0aGlzIHRvIGEgcmVhbCBQcm9tZXRoZXVzIGNvdW50ZXIgYXRcbiAgLy8gc3RhcnR1cDsgdW50aWwgdGhlbiwgY2FsbHMgZnJvbSBhcGktY29yZSBoZWxwZXJzIGFyZSBzaWxlbnRseSBkcm9wcGVkXG4gIC8vICh3aGljaCBpcyB3aGF0IHdlIHdhbnQgaW4gdGVzdHMgYW5kIENMSXMgdGhhdCBkb24ndCBydW4gYSBQcm9tIHNlcnZlcikuXG59O1xuXG4vKipcbiAqIFJlZ2lzdGVyIHRoZSByZWFsIGNvdW50ZXIgaW1wbGVtZW50YXRpb24uIElkZW1wb3RlbnQg4oCUIHRoZSBsYXN0IGNhbGwgd2lucztcbiAqIHR5cGljYWxseSBjYWxsZWQgb25jZSBhdCBzZXJ2aWNlIHN0YXJ0dXAgZnJvbSBhcGktc2VydmVyLlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2V0Q291bnRlckVtaXR0ZXIoZm46IENvdW50ZXJFbWl0dGVyKTogdm9pZCB7XG4gIGVtaXR0ZXIgPSBmbjtcbn1cblxuLyoqIFJlc2V0IHRvIHRoZSBuby1vcCBlbWl0dGVyLiBGb3IgdGVzdHMgdGhhdCB3YW50IHRvIGNsZWFyIGFueSB3aXJpbmcuICovXG5leHBvcnQgZnVuY3Rpb24gcmVzZXRDb3VudGVyRW1pdHRlcigpOiB2b2lkIHtcbiAgZW1pdHRlciA9ICgpID0+IHVuZGVmaW5lZDtcbn1cblxuLyoqXG4gKiBSZWNvcmQgYSBjb3VudGVyIGV2ZW50LiBTYWZlIHRvIGNhbGwgZnJvbSBhbnkgYXBpLWNvcmUgbW9kdWxlIOKAlCBpZiBub1xuICogZW1pdHRlciBpcyB3aXJlZCwgdGhpcyBpcyBhIG5vLW9wLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZW1pdENvdW50ZXIobmFtZTogc3RyaW5nLCBsYWJlbHM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7fSwgdmFsdWUgPSAxKTogdm9pZCB7XG4gIHRyeSB7XG4gICAgZW1pdHRlcihuYW1lLCBsYWJlbHMsIHZhbHVlKTtcbiAgfSBjYXRjaCB7XG4gICAgLy8gTmV2ZXIgbGV0IG1ldHJpYyBlbWlzc2lvbiBicmVhayB0aGUgY2FsbGluZyBwYXRoLiBBIG1pc2JlaGF2aW5nXG4gICAgLy8gZW1pdHRlciBzaG91bGRuJ3QgYmUgYWJsZSB0byB0YWtlIGRvd24gcXVvdGEgY2hlY2tzIChvciBhbnl0aGluZyBlbHNlKS5cbiAgfVxufVxuIl19
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-org IAM role assumption for build / runtime AWS API calls.
|
|
3
|
+
*
|
|
4
|
+
* The shared posture for AWS calls today is "the service's IAM role, full
|
|
5
|
+
* blast radius across every org." The operator-side mitigation operators
|
|
6
|
+
* actually want is: each customer org gets its own IAM role in its own
|
|
7
|
+
* account; build/runtime AWS calls for that org `sts:AssumeRole` into the
|
|
8
|
+
* customer's role; a compromise of one org's role can't enumerate another
|
|
9
|
+
* org's S3 buckets / ECR repos.
|
|
10
|
+
*
|
|
11
|
+
* This module is the credential-provider primitive. It's pluggable on the
|
|
12
|
+
* org-config resolver so the same code path works whether config is read
|
|
13
|
+
* from Mongo, Postgres, or env vars. Callers receive a standard SDK v3
|
|
14
|
+
* `AwsCredentialIdentityProvider` and pass it to any SDK client
|
|
15
|
+
* (`new CodeBuildClient({ credentials })`, etc.).
|
|
16
|
+
*
|
|
17
|
+
* No global state — callers construct one `OrgAwsCredentialsManager` per
|
|
18
|
+
* process and `await manager.getCredentials(orgId)` before each AWS call.
|
|
19
|
+
* The returned provider handles credential refresh internally (the
|
|
20
|
+
* underlying `fromTemporaryCredentials` re-calls AssumeRole ~5 min before
|
|
21
|
+
* the temporary credentials expire), so call sites don't manage TTL.
|
|
22
|
+
*
|
|
23
|
+
* Safety properties:
|
|
24
|
+
* - `externalId` is plumbed through to AssumeRole. Operators bake this
|
|
25
|
+
* into the IAM trust policy as the "confused deputy" mitigation; this
|
|
26
|
+
* module never silently omits it.
|
|
27
|
+
* - Orgs without a configured role fall through to the supplied
|
|
28
|
+
* `fallback` provider (typically the SDK default chain). Mixed-mode
|
|
29
|
+
* deployments where some orgs have per-org roles and others use the
|
|
30
|
+
* shared role are explicitly supported.
|
|
31
|
+
* - `evict(orgId)` drops the cached provider so the next call re-resolves
|
|
32
|
+
* from the resolver — use after the operator changes an org's role.
|
|
33
|
+
*
|
|
34
|
+
* Integration pattern for AWS SDK clients:
|
|
35
|
+
*
|
|
36
|
+
* ```ts
|
|
37
|
+
* import { S3Client } from '@aws-sdk/client-s3';
|
|
38
|
+
* import { withOrgAwsCredentials } from '@pipeline-builder/api-core';
|
|
39
|
+
*
|
|
40
|
+
* const manager = new OrgAwsCredentialsManager({ resolver });
|
|
41
|
+
*
|
|
42
|
+
* async function s3ForOrg(orgId: string) {
|
|
43
|
+
* return withOrgAwsCredentials(manager, orgId, (creds) =>
|
|
44
|
+
* new S3Client({ credentials: creds, region: 'us-west-2' }));
|
|
45
|
+
* }
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* Today's codebase: no platform-side service makes AWS API calls scoped to
|
|
49
|
+
* a customer org (build runners use buildkitd; AWS Lambda handlers run in
|
|
50
|
+
* customer territory with their own IAM). This primitive is in place for
|
|
51
|
+
* when the architecture grows to add such call sites — per-org S3 buckets,
|
|
52
|
+
* per-org ECR repos, per-org CodeBuild projects — without forcing an
|
|
53
|
+
* insecure default.
|
|
54
|
+
*/
|
|
55
|
+
/** Structural shape of an AWS credential. Matches `@smithy/types#AwsCredentialIdentity`
|
|
56
|
+
* exactly — defined locally so api-core doesn't need to declare @smithy/types
|
|
57
|
+
* as a direct dep (it's a transitive of every AWS SDK client we use). */
|
|
58
|
+
export interface AwsCredentialIdentity {
|
|
59
|
+
accessKeyId: string;
|
|
60
|
+
secretAccessKey: string;
|
|
61
|
+
sessionToken?: string;
|
|
62
|
+
expiration?: Date;
|
|
63
|
+
credentialScope?: string;
|
|
64
|
+
accountId?: string;
|
|
65
|
+
}
|
|
66
|
+
/** Standard credential-provider callable. Matches `@smithy/types#AwsCredentialIdentityProvider`. */
|
|
67
|
+
export type AwsCredentialIdentityProvider = () => Promise<AwsCredentialIdentity>;
|
|
68
|
+
/** Operator-supplied per-org IAM role + region pinning. */
|
|
69
|
+
export interface OrgAwsConfig {
|
|
70
|
+
/** ARN of the role this org's build/runtime code should assume. */
|
|
71
|
+
assumeRoleArn: string;
|
|
72
|
+
/** External id baked into the role's trust policy (recommended). */
|
|
73
|
+
externalId?: string;
|
|
74
|
+
/** Region to use when the calling code doesn't pin one. */
|
|
75
|
+
region?: string;
|
|
76
|
+
/** AssumeRole session duration (seconds). AWS allows 900-43200; the
|
|
77
|
+
* effective ceiling is the role's `MaxSessionDuration`. Default 3600. */
|
|
78
|
+
sessionDurationSeconds?: number;
|
|
79
|
+
/** Session name embedded in CloudTrail. Useful for incident-response
|
|
80
|
+
* attribution. Default `pipeline-builder-<orgId>`. */
|
|
81
|
+
roleSessionName?: string;
|
|
82
|
+
}
|
|
83
|
+
/** Async resolver: orgId → config | null. Returning null means "this org
|
|
84
|
+
* has no per-org role; use the fallback provider." */
|
|
85
|
+
export type OrgAwsConfigResolver = (orgId: string) => Promise<OrgAwsConfig | null>;
|
|
86
|
+
/** Constructor options. */
|
|
87
|
+
export interface OrgAwsCredentialsManagerOptions {
|
|
88
|
+
resolver: OrgAwsConfigResolver;
|
|
89
|
+
/** Provider used for orgs whose resolver returns null. Default: the SDK
|
|
90
|
+
* default chain via `@aws-sdk/credential-providers#fromNodeProviderChain`. */
|
|
91
|
+
fallback?: AwsCredentialIdentityProvider;
|
|
92
|
+
/** Region passed to the inner STS client when the org config doesn't
|
|
93
|
+
* pin one. Default: `AWS_REGION` / `AWS_DEFAULT_REGION` env. */
|
|
94
|
+
region?: string;
|
|
95
|
+
/** STS endpoint override (LocalStack, VPC endpoint). Default: SDK default. */
|
|
96
|
+
endpoint?: string;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Per-process manager that resolves and caches per-org credential providers.
|
|
100
|
+
* One instance per service; share it across handlers.
|
|
101
|
+
*/
|
|
102
|
+
export declare class OrgAwsCredentialsManager {
|
|
103
|
+
private readonly resolver;
|
|
104
|
+
private readonly fallbackOverride?;
|
|
105
|
+
private readonly region?;
|
|
106
|
+
private readonly endpoint?;
|
|
107
|
+
private readonly cache;
|
|
108
|
+
private readonly inFlight;
|
|
109
|
+
/** Lazy default chain. Built once per manager so we don't import the
|
|
110
|
+
* credential-providers SDK in test environments that never touch the
|
|
111
|
+
* fallback path. */
|
|
112
|
+
private fallbackCache?;
|
|
113
|
+
constructor(opts: OrgAwsCredentialsManagerOptions);
|
|
114
|
+
/**
|
|
115
|
+
* Return an AwsCredentialIdentityProvider scoped to `orgId`. Pass the
|
|
116
|
+
* returned value into any SDK v3 client's `credentials` option.
|
|
117
|
+
*
|
|
118
|
+
* Concurrent first-touch callers share one resolver invocation; later
|
|
119
|
+
* calls hit the cache. The provider itself caches and refreshes
|
|
120
|
+
* AssumeRole-derived credentials internally.
|
|
121
|
+
*/
|
|
122
|
+
getCredentials(orgId: string): Promise<AwsCredentialIdentityProvider>;
|
|
123
|
+
/** Drop the cached provider for an org. Call after the operator rotates
|
|
124
|
+
* the role ARN or external id so the next request rebuilds. */
|
|
125
|
+
evict(orgId: string): void;
|
|
126
|
+
/** Drop every cached provider. Useful in tests; rarely in production. */
|
|
127
|
+
evictAll(): void;
|
|
128
|
+
private resolveAndBuild;
|
|
129
|
+
private getFallback;
|
|
130
|
+
private buildAssumeRoleProvider;
|
|
131
|
+
}
|
|
132
|
+
/** Convenience: directly resolve credentials for a single call. The manager
|
|
133
|
+
* doesn't cache when called this way — useful in CLIs / one-shot scripts. */
|
|
134
|
+
export declare function resolveOrgCredentialsOnce(orgId: string, resolver: OrgAwsConfigResolver): Promise<AwsCredentialIdentity>;
|
|
135
|
+
/**
|
|
136
|
+
* Adapter: resolve per-org credentials and construct an AWS SDK client
|
|
137
|
+
* pre-bound to them. The factory is async because credential resolution may
|
|
138
|
+
* need to make a network call (fetching org config + AssumeRole). Once
|
|
139
|
+
* resolved, the returned client is ready for normal SDK calls; the provider
|
|
140
|
+
* inside refreshes credentials automatically before they expire.
|
|
141
|
+
*
|
|
142
|
+
* Typical usage:
|
|
143
|
+
* ```ts
|
|
144
|
+
* const s3 = await withOrgAwsCredentials(manager, orgId, (creds) =>
|
|
145
|
+
* new S3Client({ credentials: creds, region: 'us-west-2' }));
|
|
146
|
+
* await s3.send(new ListObjectsV2Command({ Bucket: bucketFor(orgId) }));
|
|
147
|
+
* ```
|
|
148
|
+
*
|
|
149
|
+
* The factory is invoked exactly once per call — callers that need a
|
|
150
|
+
* long-lived client should cache the result themselves rather than rebuilding
|
|
151
|
+
* on every operation. (Re-resolving on every op is fine for cold paths and
|
|
152
|
+
* a wasted couple of object allocations on hot paths.)
|
|
153
|
+
*/
|
|
154
|
+
export declare function withOrgAwsCredentials<TClient>(manager: OrgAwsCredentialsManager, orgId: string, factory: (credentials: AwsCredentialIdentityProvider) => TClient): Promise<TClient>;
|