@pipeline-builder/api-core 3.3.10 → 3.3.12
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 +16 -6
- package/lib/index.d.ts +4 -3
- package/lib/index.js +5 -4
- package/lib/middleware/auth.d.ts +25 -3
- package/lib/middleware/auth.js +53 -14
- package/lib/routes/health.d.ts +17 -23
- package/lib/routes/health.js +58 -52
- package/lib/types/common.d.ts +7 -2
- package/lib/types/common.js +2 -2
- package/lib/types/index.d.ts +0 -1
- package/lib/types/index.js +1 -2
- package/lib/types/quota-tiers.d.ts +8 -1
- package/lib/types/quota-tiers.js +11 -5
- package/package.json +1 -1
- package/lib/types/billing.d.ts +0 -47
- package/lib/types/billing.js +0 -5
package/README.md
CHANGED
|
@@ -7,11 +7,17 @@ Core server-side utilities shared by every backend service in [Pipeline Builder]
|
|
|
7
7
|
## Key Exports
|
|
8
8
|
|
|
9
9
|
### Authentication Middleware
|
|
10
|
-
- `requireAuth` — JWT authentication middleware
|
|
11
|
-
- `
|
|
12
|
-
- `
|
|
13
|
-
- `
|
|
14
|
-
- `
|
|
10
|
+
- `requireAuth` — JWT authentication middleware (also accepts `RequireAuthOptions` for `allowOrgHeaderOverride` on internal-service routes)
|
|
11
|
+
- `requireAdmin`, `requireSystemAdmin` — role gates (admin/owner; system-org admin/owner)
|
|
12
|
+
- `requireFeature` — feature-flag gate
|
|
13
|
+
- `isSystemOrg`, `isSystemAdmin`, `isServicePrincipal` — authorization checks (last one is true when `req.user.sub` starts with `service:`)
|
|
14
|
+
- `resolveAccessModifier(req, requested)` — coerces `requested='public'` to `'private'` unless caller is admin/owner
|
|
15
|
+
|
|
16
|
+
### Service-to-Service Tokens
|
|
17
|
+
- `signServiceToken({ serviceName, orgId?, orgName?, ttlSeconds? })` — mints a short-lived JWT identifying the calling service. Default TTL 5 minutes.
|
|
18
|
+
- `getServiceAuthHeader(opts)` — convenience wrapper returning `Bearer <token>` for direct use in fetch/axios headers.
|
|
19
|
+
|
|
20
|
+
Tokens satisfy the standard `requireAuth` middleware unmodified (sub: `service:<name>`, role: `owner`, type: `access`). Use for inter-service HTTP calls (billing → message renewals, platform → billing on register, etc.).
|
|
15
21
|
|
|
16
22
|
### Request/Response Utilities
|
|
17
23
|
- `sendSuccess`, `sendError`, `sendBadRequest`, `sendInternalError`, `sendPaginated`, `sendPaginatedNested`
|
|
@@ -40,7 +46,11 @@ Core server-side utilities shared by every backend service in [Pipeline Builder]
|
|
|
40
46
|
|
|
41
47
|
### Quota Service
|
|
42
48
|
- `QuotaService` (type), `createQuotaService` — Quota enforcement client
|
|
43
|
-
- `QuotaType
|
|
49
|
+
- `QuotaType` — `'plugins' | 'pipelines' | 'apiCalls' | 'aiCalls'`
|
|
50
|
+
- `QuotaCheckResult`, `QuotaTier`, `QUOTA_TIERS`, `getTierLimits` — Quota domain types and tier presets
|
|
51
|
+
|
|
52
|
+
### Health Endpoints
|
|
53
|
+
- `createHealthRouter({ serviceName, version?, checkDependencies? })` — registers `GET /health` (liveness; always 200 unless process is dead) and `GET /ready` (readiness; 503 when any dependency is `'disconnected'`). Use as Kubernetes/ECS liveness + readiness probes respectively.
|
|
44
54
|
|
|
45
55
|
## License
|
|
46
56
|
|
package/lib/index.d.ts
CHANGED
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
* Core API utilities shared across all services.
|
|
5
5
|
*
|
|
6
6
|
* **Middleware**
|
|
7
|
-
* - requireAuth,
|
|
8
|
-
* - isSystemOrg, isSystemAdmin — authorization helpers
|
|
7
|
+
* - requireAuth, requireAdmin, requireSystemAdmin, requireFeature — JWT authentication
|
|
8
|
+
* - isSystemOrg, isSystemAdmin, isServicePrincipal — authorization helpers
|
|
9
|
+
* - signServiceToken, getServiceAuthHeader — inter-service JWT minting
|
|
9
10
|
*
|
|
10
11
|
* **Types**
|
|
11
12
|
* - ErrorCode, ErrorCodeStatus — standardized error code enum and status mapping
|
|
@@ -13,7 +14,7 @@
|
|
|
13
14
|
* - ServiceConfig, RequestOptions, HttpResponse — HTTP client types
|
|
14
15
|
* - QuotaType, QuotaCheckResult — quota service types
|
|
15
16
|
* - PipelineType, ComputeType, AccessModifier — pipeline domain types
|
|
16
|
-
* - FeatureFlags
|
|
17
|
+
* - FeatureFlags — feature flag types
|
|
17
18
|
*
|
|
18
19
|
* **Utilities**
|
|
19
20
|
* - createLogger — Winston-based structured logger factory
|
package/lib/index.js
CHANGED
|
@@ -22,8 +22,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
22
22
|
* Core API utilities shared across all services.
|
|
23
23
|
*
|
|
24
24
|
* **Middleware**
|
|
25
|
-
* - requireAuth,
|
|
26
|
-
* - isSystemOrg, isSystemAdmin — authorization helpers
|
|
25
|
+
* - requireAuth, requireAdmin, requireSystemAdmin, requireFeature — JWT authentication
|
|
26
|
+
* - isSystemOrg, isSystemAdmin, isServicePrincipal — authorization helpers
|
|
27
|
+
* - signServiceToken, getServiceAuthHeader — inter-service JWT minting
|
|
27
28
|
*
|
|
28
29
|
* **Types**
|
|
29
30
|
* - ErrorCode, ErrorCodeStatus — standardized error code enum and status mapping
|
|
@@ -31,7 +32,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
31
32
|
* - ServiceConfig, RequestOptions, HttpResponse — HTTP client types
|
|
32
33
|
* - QuotaType, QuotaCheckResult — quota service types
|
|
33
34
|
* - PipelineType, ComputeType, AccessModifier — pipeline domain types
|
|
34
|
-
* - FeatureFlags
|
|
35
|
+
* - FeatureFlags — feature flag types
|
|
35
36
|
*
|
|
36
37
|
* **Utilities**
|
|
37
38
|
* - createLogger — Winston-based structured logger factory
|
|
@@ -83,4 +84,4 @@ __exportStar(require("./errors"), exports);
|
|
|
83
84
|
__exportStar(require("./validation"), exports);
|
|
84
85
|
// OpenAPI
|
|
85
86
|
__exportStar(require("./openapi"), exports);
|
|
86
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
87
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7Ozs7Ozs7Ozs7Ozs7Ozs7QUFFdEM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBK0NHO0FBRUgsUUFBUTtBQUNSLDBDQUF3QjtBQUV4QixZQUFZO0FBQ1osOENBQTRCO0FBRTVCLFFBQVE7QUFDUiwwQ0FBd0I7QUFFeEIsVUFBVTtBQUNWLDRDQUEwQjtBQUUxQixXQUFXO0FBQ1gsNkNBQTJCO0FBRTNCLGFBQWE7QUFDYiwrQ0FBNkI7QUFFN0IsU0FBUztBQUNULDJDQUF5QjtBQUV6QixTQUFTO0FBQ1QsMkNBQXlCO0FBRXpCLGFBQWE7QUFDYiwrQ0FBNkI7QUFFN0IsVUFBVTtBQUNWLDRDQUEwQiIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG4vKipcbiAqIEBtb2R1bGUgQHBpcGVsaW5lLWJ1aWxkZXIvYXBpLWNvcmVcbiAqXG4gKiBDb3JlIEFQSSB1dGlsaXRpZXMgc2hhcmVkIGFjcm9zcyBhbGwgc2VydmljZXMuXG4gKlxuICogKipNaWRkbGV3YXJlKipcbiAqIC0gcmVxdWlyZUF1dGgsIHJlcXVpcmVBZG1pbiwgcmVxdWlyZVN5c3RlbUFkbWluLCByZXF1aXJlRmVhdHVyZSDigJQgSldUIGF1dGhlbnRpY2F0aW9uXG4gKiAtIGlzU3lzdGVtT3JnLCBpc1N5c3RlbUFkbWluLCBpc1NlcnZpY2VQcmluY2lwYWwg4oCUIGF1dGhvcml6YXRpb24gaGVscGVyc1xuICogLSBzaWduU2VydmljZVRva2VuLCBnZXRTZXJ2aWNlQXV0aEhlYWRlciDigJQgaW50ZXItc2VydmljZSBKV1QgbWludGluZ1xuICpcbiAqICoqVHlwZXMqKlxuICogLSBFcnJvckNvZGUsIEVycm9yQ29kZVN0YXR1cyDigJQgc3RhbmRhcmRpemVkIGVycm9yIGNvZGUgZW51bSBhbmQgc3RhdHVzIG1hcHBpbmdcbiAqIC0gUmVxdWVzdElkZW50aXR5IOKAlCBwYXJzZWQgSldUIGlkZW50aXR5XG4gKiAtIFNlcnZpY2VDb25maWcsIFJlcXVlc3RPcHRpb25zLCBIdHRwUmVzcG9uc2Ug4oCUIEhUVFAgY2xpZW50IHR5cGVzXG4gKiAtIFF1b3RhVHlwZSwgUXVvdGFDaGVja1Jlc3VsdCDigJQgcXVvdGEgc2VydmljZSB0eXBlc1xuICogLSBQaXBlbGluZVR5cGUsIENvbXB1dGVUeXBlLCBBY2Nlc3NNb2RpZmllciDigJQgcGlwZWxpbmUgZG9tYWluIHR5cGVzXG4gKiAtIEZlYXR1cmVGbGFncyDigJQgZmVhdHVyZSBmbGFnIHR5cGVzXG4gKlxuICogKipVdGlsaXRpZXMqKlxuICogLSBjcmVhdGVMb2dnZXIg4oCUIFdpbnN0b24tYmFzZWQgc3RydWN0dXJlZCBsb2dnZXIgZmFjdG9yeVxuICogLSBzZW5kU3VjY2Vzcywgc2VuZEVycm9yLCBzZW5kUGFnaW5hdGVkLCBzZW5kQmFkUmVxdWVzdCwgc2VuZEludGVybmFsRXJyb3Ig4oCUIEhUVFAgcmVzcG9uc2UgaGVscGVyc1xuICogLSBnZXRQYXJhbSwgZ2V0UmVxdWlyZWRQYXJhbSwgZ2V0UGFyYW1zLCBnZXRPcmdJZCwgZ2V0QXV0aEhlYWRlciDigJQgcmVxdWVzdCBwYXJhbWV0ZXIgZXh0cmFjdGlvblxuICogLSBwYXJzZVF1ZXJ5Qm9vbGVhbiwgcGFyc2VRdWVyeUludCwgcGFyc2VRdWVyeVN0cmluZyDigJQgcXVlcnkgc3RyaW5nIHBhcnNpbmdcbiAqIC0gZ2V0SWRlbnRpdHksIHZhbGlkYXRlSWRlbnRpdHkg4oCUIGlkZW50aXR5IGV4dHJhY3Rpb24gZnJvbSByZXF1ZXN0c1xuICogLSBlcnJvck1lc3NhZ2Ug4oCUIHNhZmUgZXJyb3ItdG8tc3RyaW5nIGNvbnZlcnNpb25cbiAqXG4gKiAqKkNvbnN0YW50cyoqXG4gKiAtIEhUVFAgc3RhdHVzIGNvZGVzLCBBSSBwcm92aWRlciBpZGVudGlmaWVycywgdGltZSBjb25zdGFudHNcbiAqXG4gKiAqKlNlcnZpY2VzKipcbiAqIC0gSW50ZXJuYWxIdHRwQ2xpZW50LCBjcmVhdGVTYWZlQ2xpZW50IOKAlCBpbnRlcm5hbCBzZXJ2aWNlLXRvLXNlcnZpY2UgSFRUUCBjbGllbnRcbiAqIC0gY3JlYXRlUXVvdGFTZXJ2aWNlIOKAlCBxdW90YSBlbmZvcmNlbWVudCBjbGllbnQgZmFjdG9yeVxuICogLSBDYWNoZVNlcnZpY2Ug4oCUIGluLW1lbW9yeSBUVEwgY2FjaGVcbiAqIC0gQ29tcGxpYW5jZUNsaWVudCDigJQgY29tcGxpYW5jZSBzZXJ2aWNlIGNsaWVudFxuICogLSBFbnRpdHlFdmVudEVtaXR0ZXIg4oCUIGRvbWFpbiBldmVudCBwdWIvc3ViXG4gKlxuICogKipFcnJvcnMqKlxuICogLSBBcHBFcnJvciwgTm90Rm91bmRFcnJvciwgRm9yYmlkZGVuRXJyb3Ig4oCUIHR5cGVkIEhUVFAgZXJyb3IgY2xhc3Nlc1xuICpcbiAqICoqVmFsaWRhdGlvbioqXG4gKiAtIFpvZC1iYXNlZCByZXF1ZXN0IHZhbGlkYXRpb24gc2NoZW1hcyBhbmQgbWlkZGxld2FyZVxuICpcbiAqICoqUm91dGVzKipcbiAqIC0gSGVhbHRoIGNoZWNrIHJvdXRlIGZhY3RvcnlcbiAqXG4gKiAqKk9wZW5BUEkqKlxuICogLSBTY2hlbWEgcmVnaXN0cnkgYW5kIHNwZWMgZ2VuZXJhdGlvblxuICovXG5cbi8vIFR5cGVzXG5leHBvcnQgKiBmcm9tICcuL3R5cGVzJztcblxuLy8gQ29uc3RhbnRzXG5leHBvcnQgKiBmcm9tICcuL2NvbnN0YW50cyc7XG5cbi8vIFV0aWxzXG5leHBvcnQgKiBmcm9tICcuL3V0aWxzJztcblxuLy8gSGVscGVyc1xuZXhwb3J0ICogZnJvbSAnLi9oZWxwZXJzJztcblxuLy8gU2VydmljZXNcbmV4cG9ydCAqIGZyb20gJy4vc2VydmljZXMnO1xuXG4vLyBNaWRkbGV3YXJlXG5leHBvcnQgKiBmcm9tICcuL21pZGRsZXdhcmUnO1xuXG4vLyBSb3V0ZXNcbmV4cG9ydCAqIGZyb20gJy4vcm91dGVzJztcblxuLy8gRXJyb3JzXG5leHBvcnQgKiBmcm9tICcuL2Vycm9ycyc7XG5cbi8vIFZhbGlkYXRpb25cbmV4cG9ydCAqIGZyb20gJy4vdmFsaWRhdGlvbic7XG5cbi8vIE9wZW5BUElcbmV4cG9ydCAqIGZyb20gJy4vb3BlbmFwaSc7XG4iXX0=
|
package/lib/middleware/auth.d.ts
CHANGED
|
@@ -16,8 +16,6 @@ export interface RequireAuthOptions {
|
|
|
16
16
|
/** JWT auth middleware. Use directly or call with options. */
|
|
17
17
|
export declare function requireAuth(req: Request, res: Response, next: NextFunction): void;
|
|
18
18
|
export declare function requireAuth(options?: RequireAuthOptions): (req: Request, res: Response, next: NextFunction) => void;
|
|
19
|
-
/** Requires organization membership. Use after requireAuth. */
|
|
20
|
-
export declare function requireOrganization(req: Request, res: Response, next: NextFunction): void;
|
|
21
19
|
/**
|
|
22
20
|
* Requires admin role. Use after requireAuth.
|
|
23
21
|
* Permits users whose per-org role is 'admin' or 'owner'.
|
|
@@ -46,5 +44,29 @@ export declare function requireSystemAdmin(req: Request, res: Response, next: Ne
|
|
|
46
44
|
* System org users always pass (all features enabled).
|
|
47
45
|
*/
|
|
48
46
|
export declare function requireFeature(feature: string): (req: Request, res: Response, next: NextFunction) => void;
|
|
49
|
-
/**
|
|
47
|
+
/**
|
|
48
|
+
* Resolve the effective access modifier for an entity being created/updated.
|
|
49
|
+
* 'public' is permitted for any admin or owner role (system admins create
|
|
50
|
+
* catalog-wide public entities; org admins create org-wide public entities).
|
|
51
|
+
* Everyone else (member role, no role) gets 'private'.
|
|
52
|
+
*/
|
|
50
53
|
export declare function resolveAccessModifier(req: Request, requested: string | undefined): 'public' | 'private';
|
|
54
|
+
export interface ServiceTokenOptions {
|
|
55
|
+
/** Calling service identifier (e.g. 'billing', 'platform'). Embedded as `sub: service:<name>`. */
|
|
56
|
+
serviceName: string;
|
|
57
|
+
/** Active org context for the call. Use the target tenant's org ID, or 'system' for system-wide ops. */
|
|
58
|
+
orgId?: string;
|
|
59
|
+
/** Active org name. Defaults to orgId. */
|
|
60
|
+
orgName?: string;
|
|
61
|
+
/** TTL in seconds (default 300). */
|
|
62
|
+
ttlSeconds?: number;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Mint a JWT identifying the calling service. Used for inter-service HTTP calls.
|
|
66
|
+
* The token satisfies `requireAuth` and (when orgId is present) `requireOrganization`.
|
|
67
|
+
*/
|
|
68
|
+
export declare function signServiceToken(opts: ServiceTokenOptions): string;
|
|
69
|
+
/** Convenience: returns a `Bearer <token>` header value for fetch/axios calls. */
|
|
70
|
+
export declare function getServiceAuthHeader(opts: ServiceTokenOptions): string;
|
|
71
|
+
/** True when `req.user.sub` was issued by `signServiceToken` (i.e. starts with `service:`). */
|
|
72
|
+
export declare function isServicePrincipal(req: Request): boolean;
|
package/lib/middleware/auth.js
CHANGED
|
@@ -7,7 +7,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
8
|
exports.SYSTEM_ORG_ID = void 0;
|
|
9
9
|
exports.requireAuth = requireAuth;
|
|
10
|
-
exports.requireOrganization = requireOrganization;
|
|
11
10
|
exports.requireAdmin = requireAdmin;
|
|
12
11
|
exports.isSystemOrgId = isSystemOrgId;
|
|
13
12
|
exports.isSystemOrg = isSystemOrg;
|
|
@@ -15,6 +14,9 @@ exports.isSystemAdmin = isSystemAdmin;
|
|
|
15
14
|
exports.requireSystemAdmin = requireSystemAdmin;
|
|
16
15
|
exports.requireFeature = requireFeature;
|
|
17
16
|
exports.resolveAccessModifier = resolveAccessModifier;
|
|
17
|
+
exports.signServiceToken = signServiceToken;
|
|
18
|
+
exports.getServiceAuthHeader = getServiceAuthHeader;
|
|
19
|
+
exports.isServicePrincipal = isServicePrincipal;
|
|
18
20
|
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
19
21
|
const http_status_1 = require("../constants/http-status");
|
|
20
22
|
const error_codes_1 = require("../types/error-codes");
|
|
@@ -89,16 +91,6 @@ function _requireAuth(options, req, res, next) {
|
|
|
89
91
|
return (0, response_1.sendError)(res, http_status_1.HttpStatus.UNAUTHORIZED, 'Authentication failed', error_codes_1.ErrorCode.UNAUTHORIZED);
|
|
90
92
|
}
|
|
91
93
|
}
|
|
92
|
-
/** Requires organization membership. Use after requireAuth. */
|
|
93
|
-
function requireOrganization(req, res, next) {
|
|
94
|
-
if (!req.user) {
|
|
95
|
-
return (0, response_1.sendError)(res, http_status_1.HttpStatus.UNAUTHORIZED, 'Authentication required', error_codes_1.ErrorCode.UNAUTHORIZED);
|
|
96
|
-
}
|
|
97
|
-
if (!req.user.organizationId) {
|
|
98
|
-
return (0, response_1.sendError)(res, http_status_1.HttpStatus.BAD_REQUEST, 'Organization membership required', error_codes_1.ErrorCode.ORG_MISMATCH);
|
|
99
|
-
}
|
|
100
|
-
next();
|
|
101
|
-
}
|
|
102
94
|
/**
|
|
103
95
|
* Requires admin role. Use after requireAuth.
|
|
104
96
|
* Permits users whose per-org role is 'admin' or 'owner'.
|
|
@@ -161,11 +153,58 @@ function requireFeature(feature) {
|
|
|
161
153
|
next();
|
|
162
154
|
};
|
|
163
155
|
}
|
|
164
|
-
/**
|
|
156
|
+
/**
|
|
157
|
+
* Resolve the effective access modifier for an entity being created/updated.
|
|
158
|
+
* 'public' is permitted for any admin or owner role (system admins create
|
|
159
|
+
* catalog-wide public entities; org admins create org-wide public entities).
|
|
160
|
+
* Everyone else (member role, no role) gets 'private'.
|
|
161
|
+
*/
|
|
165
162
|
function resolveAccessModifier(req, requested) {
|
|
166
|
-
if (requested === 'public' &&
|
|
163
|
+
if (requested === 'public' && (req.user?.role === 'admin' || req.user?.role === 'owner')) {
|
|
167
164
|
return 'public';
|
|
168
165
|
}
|
|
169
166
|
return 'private';
|
|
170
167
|
}
|
|
171
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9taWRkbGV3YXJlL2F1dGgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7Ozs7OztBQTJEdEMsa0NBYUM7QUF1REQsa0RBY0M7QUFNRCxvQ0FjQztBQVdELHNDQUVDO0FBRUQsa0NBR0M7QUFNRCxzQ0FFQztBQUdELGdEQWFDO0FBT0Qsd0NBbUJDO0FBR0Qsc0RBS0M7QUExT0QsZ0VBQStCO0FBQy9CLDBEQUFzRDtBQUV0RCxzREFBaUQ7QUFDakQsOENBQW1EO0FBQ25ELDRDQUErQztBQUMvQyxnREFBOEM7QUFFOUMsTUFBTSxNQUFNLEdBQUcsSUFBQSxxQkFBWSxFQUFDLGlCQUFpQixDQUFDLENBQUM7QUFFL0MsNERBQTREO0FBQzVELElBQUksVUFBOEIsQ0FBQztBQUNuQyxJQUFJLHFCQUFxQixHQUFHLENBQUMsQ0FBQztBQUM5QixNQUFNLDhCQUE4QixHQUFHLE9BQU8sQ0FBQyxDQUFDLFlBQVk7QUFFNUQsU0FBUyxZQUFZO0lBQ25CLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztJQUN2QixJQUFJLENBQUMsVUFBVSxJQUFJLEdBQUcsR0FBRyxxQkFBcUIsR0FBRyw4QkFBOEIsRUFBRSxDQUFDO1FBQ2hGLE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDO1FBQ3RDLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNaLE1BQU0sQ0FBQyxLQUFLLENBQUMsNENBQTRDLENBQUMsQ0FBQztZQUMzRCxNQUFNLElBQUksS0FBSyxDQUFDLDZDQUE2QyxDQUFDLENBQUM7UUFDakUsQ0FBQztRQUNELElBQUksVUFBVSxJQUFJLFVBQVUsS0FBSyxNQUFNLEVBQUUsQ0FBQztZQUN4QyxNQUFNLENBQUMsSUFBSSxDQUFDLG9CQUFvQixDQUFDLENBQUM7UUFDcEMsQ0FBQztRQUNELFVB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LENBQUMsR0FBWSxFQUFFLFNBQTZCO0lBQy9FLElBQUksU0FBUyxLQUFLLFFBQVEsSUFBSSxhQUFhLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUNqRCxPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDO0lBQ0QsT0FBTyxTQUFTLENBQUM7QUFDbkIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgeyBSZXF1ZXN0LCBSZXNwb25zZSwgTmV4dEZ1bmN0aW9uIH0gZnJvbSAnZXhwcmVzcyc7XG5pbXBvcnQgand0IGZyb20gJ2pzb253ZWJ0b2tlbic7XG5pbXBvcnQgeyBIdHRwU3RhdHVzIH0gZnJvbSAnLi4vY29uc3RhbnRzL2h0dHAtc3RhdHVzJztcbmltcG9ydCB7IEp3dFBheWxvYWQgfSBmcm9tICcuLi90eXBlcy9jb21tb24nO1xuaW1wb3J0IHsgRXJyb3JDb2RlIH0gZnJvbSAnLi4vdHlwZXMvZXJyb3ItY29kZXMnO1xuaW1wb3J0IHsgZ2V0SGVhZGVyU3RyaW5nIH0gZnJvbSAnLi4vdXRpbHMvaGVhZGVycyc7XG5pbXBvcnQgeyBjcmVhdGVMb2dnZXIgfSBmcm9tICcuLi91dGlscy9sb2dnZXInO1xuaW1wb3J0IHsgc2VuZEVycm9yIH0gZnJvbSAnLi4vdXRpbHMvcmVzcG9uc2UnO1xuXG5jb25zdCBsb2dnZXIgPSBjcmVhdGVMb2dnZXIoJ2F1dGgtbWlkZGxld2FyZScpO1xuXG4vKiogQ2FjaGVkIEpXVCBzZWNyZXQgd2l0aCBwZXJpb2RpYyByZWZyZXNoIGZyb20gZW52IHZhci4gKi9cbmxldCBfand0U2VjcmV0OiBzdHJpbmcgfCB1bmRlZmluZWQ7XG5sZXQgX2p3dFNlY3JldFJlZnJlc2hlZEF0ID0gMDtcbmNvbnN0IEpXVF9TRUNSRVRfUkVGUkVTSF9JTlRFUlZBTF9NUyA9IDMwMF8wMDA7IC8vIDUgbWludXRlc1xuXG5mdW5jdGlvbiBnZXRKd3RTZWNyZXQoKTogc3RyaW5nIHtcbiAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKTtcbiAgaWYgKCFfand0U2VjcmV0IHx8IG5vdyAtIF9qd3RTZWNyZXRSZWZyZXNoZWRBdCA+IEpXVF9TRUNSRVRfUkVGUkVTSF9JTlRFUlZBTF9NUykge1xuICAgIGNvbnN0IHNlY3JldCA9IHByb2Nlc3MuZW52LkpXVF9TRUNSRVQ7XG4gICAgaWYgKCFzZWNyZXQpIHtcbiAgICAgIGxvZ2dlci5lcnJvcignSldUX1NFQ1JFVCBlbnZpcm9ubWVudCB2YXJpYWJsZSBpcyBub3Qgc2V0Jyk7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0pXVF9TRUNSRVQgZW52aXJvbm1lbnQgdmFyaWFibGUgaXMgcmVxdWlyZWQnKTtcbiAgICB9XG4gICAgaWYgKF9qd3RTZWNyZXQgJiYgX2p3dFNlY3JldCAhPT0gc2VjcmV0KSB7XG4gICAgICBsb2dnZXIuaW5mbygnSldUIHNlY3JldCByb3RhdGVkJyk7XG4gICAgfVxuICAgIF9qd3RTZWNyZXQgPSBzZWNyZXQ7XG4gICAgX2p3dFNlY3JldFJlZnJlc2hlZEF0ID0gbm93O1xuICB9XG4gIHJldHVybiBfand0U2VjcmV0O1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFJlcXVpcmVBdXRoT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBBbGxvdyB4LW9yZy1pZC94LW9yZy1uYW1lIGhlYWRlcnMgdG8gb3ZlcnJpZGUgdGhlIEpXVCdzIG9yZ2FuaXphdGlvbiBmaWVsZHMuXG4gICAqXG4gICAqICoqU0VDVVJJVFkgV0FSTklORzoqKiBXaGVuIGVuYWJsZWQsIGEgY2FsbGVyIGNhbiBzZXQgYHgtb3JnLWlkYCB0byBBTllcbiAgICogb3JnYW5pemF0aW9uIElELCBlZmZlY3RpdmVseSBpbXBlcnNvbmF0aW5nIHRoYXQgb3JnLiBUaGlzIE1VU1Qgb25seSBiZVxuICAgKiB1c2VkIG9uIHJvdXRlcyB0aGF0IGFyZTpcbiAgICogICAxLiBJbnRlcm5hbCBzZXJ2aWNlLXRvLXNlcnZpY2Ugcm91dGVzIChub3QgZXhwb3NlZCB0byBlbmQgdXNlcnMpXG4gICAqICAgMi4gQmVoaW5kIG5ldHdvcmsgaXNvbGF0aW9uIChjb250YWluZXIgbmV0d29yaywgVlBDLCBldGMuKVxuICAgKlxuICAgKiBORVZFUiBlbmFibGUgdGhpcyBvbiB1c2VyLWZhY2luZyBBUEkgcm91dGVzLiBJZiB1bnN1cmUsIGxlYXZlIGl0IGRpc2FibGVkLlxuICAgKi9cbiAgYWxsb3dPcmdIZWFkZXJPdmVycmlkZT86IGJvb2xlYW47XG59XG5cbi8qKiBKV1QgYXV0aCBtaWRkbGV3YXJlLiBVc2UgZGlyZWN0bHkgb3IgY2FsbCB3aXRoIG9wdGlvbnMuICovXG5leHBvcnQgZnVuY3Rpb24gcmVxdWlyZUF1dGgoXG4gIHJlcTogUmVxdWVzdCxcbiAgcmVzOiBSZXNwb25zZSxcbiAgbmV4dDogTmV4dEZ1bmN0aW9uLFxuKTogdm9pZDtcbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlQXV0aChcbiAgb3B0aW9ucz86IFJlcXVpcmVBdXRoT3B0aW9ucyxcbik6IChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UsIG5leHQ6IE5leHRGdW5jdGlvbikgPT4gdm9pZDtcbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlQXV0aChcbiAgcmVxT3JPcHRpb25zPzogUmVxdWVzdCB8IFJlcXVpcmVBdXRoT3B0aW9ucyxcbiAgcmVzPzogUmVzcG9uc2UsXG4gIG5leHQ/OiBOZXh0RnVuY3Rpb24sXG4pOiB2b2lkIHwgKChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UsIG5leHQ6IE5leHRGdW5jdGlvbikgPT4gdm9pZCkge1xuICBpZiAocmVxT3JPcHRpb25zICYmIHJlcyAmJiBuZXh0ICYmICdoZWFkZXJzJyBpbiByZXFPck9wdGlvbnMpIHtcbiAgICByZXR1cm4gX3JlcXVpcmVBdXRoKHt9LCByZXFPck9wdGlvbnMgYXMgUmVxdWVzdCwgcmVzLCBuZXh0KTtcbiAgfVxuXG4gIGNvbnN0IG9wdGlvbnMgPSAocmVxT3JPcHRpb25zIGFzIFJlcXVpcmVBdXRoT3B0aW9ucykgfHwge307XG4gIHJldHVybiAocmVxOiBSZXF1ZXN0LCByZXNJbm5lcjogUmVzcG9uc2UsIG5leHRJbm5lcjogTmV4dEZ1bmN0aW9uKSA9PiB7XG4gICAgX3JlcXVpcmVBdXRoKG9wdGlvbnMsIHJlcSwgcmVzSW5uZXIsIG5leHRJbm5lcik7XG4gIH07XG59XG5cbmZ1bmN0aW9uIF9yZXF1aXJlQXV0aChcbiAgb3B0aW9uczogUmVxdWlyZUF1dGhPcHRpb25zLFxuICByZXE6IFJlcXVlc3QsXG4gIHJlczogUmVzcG9uc2UsXG4gIG5leHQ6IE5leHRGdW5jdGlvbixcbik6IHZvaWQge1xuICBjb25zdCBhdXRoSGVhZGVyID0gcmVxLmhlYWRlcnMuYXV0aG9yaXphdGlvbjtcblxuICBpZiAoIWF1dGhIZWFkZXIpIHtcbiAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdBdXRob3JpemF0aW9uIGhlYWRlciByZXF1aXJlZCcsIEVycm9yQ29kZS5UT0tFTl9NSVNTSU5HKTtcbiAgfVxuXG4gIGNvbnN0IHBhcnRzID0gYXV0aEhlYWRlci5zcGxpdCgnICcpO1xuICBpZiAocGFydHMubGVuZ3RoICE9PSAyIHx8IHBhcnRzWzBdICE9PSAnQmVhcmVyJykge1xuICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ0ludmFsaWQgYXV0aG9yaXphdGlvbiBmb3JtYXQuIFVzZTogQmVhcmVyIDx0b2tlbj4nLCBFcnJvckNvZGUuVE9LRU5fSU5WQUxJRCk7XG4gIH1cblxuICB0cnkge1xuICAgIGNvbnN0IGRlY29kZWQgPSBqd3QudmVyaWZ5KHBhcnRzWzFdLCBnZXRKd3RTZWNyZXQoKSkgYXMgSnd0UGF5bG9hZDtcblxuICAgIGlmIChkZWNvZGVkLnR5cGUgIT09ICdhY2Nlc3MnKSB7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdPbmx5IGFjY2VzcyB0b2tlbnMgY2FuIGJlIHVzZWQgZm9yIEFQSSByZXF1ZXN0cycsIEVycm9yQ29kZS5UT0tFTl9JTlZBTElEKTtcbiAgICB9XG5cbiAgICBpZiAoIWRlY29kZWQuc3ViIHx8ICFkZWNvZGVkLnJvbGUpIHtcbiAgICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ1Rva2VuIG1pc3NpbmcgcmVxdWlyZWQgZmllbGRzJywgRXJyb3JDb2RlLlRPS0VOX0lOVkFMSUQpO1xuICAgIH1cblxuICAgIHJlcS51c2VyID0geyAuLi5kZWNvZGVkIH07XG5cbiAgICBpZiAob3B0aW9ucy5hbGxvd09yZ0hlYWRlck92ZXJyaWRlKSB7XG4gICAgICBjb25zdCBoZWFkZXJPcmdJZCA9IGdldEhlYWRlclN0cmluZyhyZXEuaGVhZGVyc1sneC1vcmctaWQnXSk7XG4gICAgICBjb25zdCBoZWFkZXJPcmdOYW1lID0gZ2V0SGVhZGVyU3RyaW5nKHJlcS5oZWFkZXJzWyd4LW9yZy1uYW1lJ10pO1xuICAgICAgaWYgKGhlYWRlck9yZ0lkKSByZXEudXNlci5vcmdhbml6YXRpb25JZCA9IGhlYWRlck9yZ0lkO1xuICAgICAgaWYgKGhlYWRlck9yZ05hbWUpIHJlcS51c2VyLm9yZ2FuaXphdGlvbk5hbWUgPSBoZWFkZXJPcmdOYW1lO1xuICAgIH1cblxuICAgIG5leHQoKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBqd3QuVG9rZW5FeHBpcmVkRXJyb3IpIHtcbiAgICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ1Rva2VuIGhhcyBleHBpcmVkJywgRXJyb3JDb2RlLlRPS0VOX0VYUElSRUQpO1xuICAgIH1cblxuICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIGp3dC5Kc29uV2ViVG9rZW5FcnJvcikge1xuICAgICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuVU5BVVRIT1JJWkVELCAnSW52YWxpZCB0b2tlbicsIEVycm9yQ29kZS5UT0tFTl9JTlZBTElEKTtcbiAgICB9XG5cbiAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdBdXRoZW50aWNhdGlvbiBmYWlsZWQnLCBFcnJvckNvZGUuVU5BVVRIT1JJWkVEKTtcbiAgfVxufVxuXG5cbi8qKiBSZXF1aXJlcyBvcmdhbml6YXRpb24gbWVtYmVyc2hpcC4gVXNlIGFmdGVyIHJlcXVpcmVBdXRoLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVPcmdhbml6YXRpb24oXG4gIHJlcTogUmVxdWVzdCxcbiAgcmVzOiBSZXNwb25zZSxcbiAgbmV4dDogTmV4dEZ1bmN0aW9uLFxuKTogdm9pZCB7XG4gIGlmICghcmVxLnVzZXIpIHtcbiAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdBdXRoZW50aWNhdGlvbiByZXF1aXJlZCcsIEVycm9yQ29kZS5VTkFVVEhPUklaRUQpO1xuICB9XG5cbiAgaWYgKCFyZXEudXNlci5vcmdhbml6YXRpb25JZCkge1xuICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLkJBRF9SRVFVRVNULCAnT3JnYW5pemF0aW9uIG1lbWJlcnNoaXAgcmVxdWlyZWQnLCBFcnJvckNvZGUuT1JHX01JU01BVENIKTtcbiAgfVxuXG4gIG5leHQoKTtcbn1cblxuLyoqXG4gKiBSZXF1aXJlcyBhZG1pbiByb2xlLiBVc2UgYWZ0ZXIgcmVxdWlyZUF1dGguXG4gKiBQZXJtaXRzIHVzZXJzIHdob3NlIHBlci1vcmcgcm9sZSBpcyAnYWRtaW4nIG9yICdvd25lcicuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlQWRtaW4oXG4gIHJlcTogUmVxdWVzdCxcbiAgcmVzOiBSZXNwb25zZSxcbiAgbmV4dDogTmV4dEZ1bmN0aW9uLFxuKTogdm9pZCB7XG4gIGlmICghcmVxLnVzZXIpIHtcbiAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdBdXRoZW50aWNhdGlvbiByZXF1aXJlZCcsIEVycm9yQ29kZS5VTkFVVEhPUklaRUQpO1xuICB9XG5cbiAgaWYgKHJlcS51c2VyLnJvbGUgIT09ICdhZG1pbicgJiYgcmVxLnVzZXIucm9sZSAhPT0gJ293bmVyJykge1xuICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLkZPUkJJRERFTiwgJ0FkbWluIGFjY2VzcyByZXF1aXJlZCcsIEVycm9yQ29kZS5JTlNVRkZJQ0lFTlRfUEVSTUlTU0lPTlMpO1xuICB9XG5cbiAgbmV4dCgpO1xufVxuXG4vKiogT3JnYW5pemF0aW9uIElEL25hbWUgdGhhdCBpZGVudGlmaWVzIHRoZSBzeXN0ZW0gKHN1cGVyLWFkbWluKSB0ZW5hbnQuICovXG5leHBvcnQgY29uc3QgU1lTVEVNX09SR19JRCA9IChwcm9jZXNzLmVudi5TWVNURU1fT1JHX0lEIHx8ICdzeXN0ZW0nKS50b0xvd2VyQ2FzZSgpO1xuXG4vKipcbiAqIENoZWNrIGlmIGFuIG9yZ0lkIG9yIG9yZ05hbWUgbWF0Y2hlcyB0aGUgc3lzdGVtIG9yZy5cbiAqIFVzZSB0aGlzIGluc3RlYWQgb2YgY29tcGFyaW5nIGRpcmVjdGx5IGFnYWluc3QgU1lTVEVNX09SR19JRCxcbiAqIGJlY2F1c2UgdGhlIEpXVCBvcmdJZCBpcyBhIGRhdGFiYXNlIElEIChlLmcuIE1vbmdvREIgT2JqZWN0SWQpXG4gKiB3aGlsZSBTWVNURU1fT1JHX0lEIGlzIHRoZSB3ZWxsLWtub3duIG5hbWUgXCJzeXN0ZW1cIi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzU3lzdGVtT3JnSWQob3JnSWQ/OiBzdHJpbmcsIG9yZ05hbWU/OiBzdHJpbmcpOiBib29sZWFuIHtcbiAgcmV0dXJuIG9yZ0lkPy50b0xvd2VyQ2FzZSgpID09PSBTWVNURU1fT1JHX0lEIHx8IG9yZ05hbWU/LnRvTG93ZXJDYXNlKCkgPT09IFNZU1RFTV9PUkdfSUQ7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBpc1N5c3RlbU9yZyhyZXE6IFJlcXVlc3QpOiBib29sZWFuIHtcbiAgaWYgKCFyZXEudXNlcikgcmV0dXJuIGZhbHNlO1xuICByZXR1cm4gaXNTeXN0ZW1PcmdJZChyZXEudXNlci5vcmdhbml6YXRpb25JZCwgcmVxLnVzZXIub3JnYW5pemF0aW9uTmFtZSk7XG59XG5cbi8qKlxuICogQ2hlY2sgaWYgdGhlIHJlcXVlc3QgaXMgZnJvbSBhIHN5c3RlbSBhZG1pbi5cbiAqIEEgc3lzdGVtIGFkbWluIGhhcyBwZXItb3JnIHJvbGUgJ2FkbWluJyBvciAnb3duZXInIGluIHRoZSBzeXN0ZW0gb3JnYW5pemF0aW9uLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNTeXN0ZW1BZG1pbihyZXE6IFJlcXVlc3QpOiBib29sZWFuIHtcbiAgcmV0dXJuIChyZXEudXNlcj8ucm9sZSA9PT0gJ2FkbWluJyB8fCByZXEudXNlcj8ucm9sZSA9PT0gJ293bmVyJykgJiYgaXNTeXN0ZW1PcmcocmVxKTtcbn1cblxuLyoqIFJlcXVpcmVzIHN5c3RlbSBhZG1pbiAoYWRtaW4gcm9sZSArIHN5c3RlbSBvcmdhbml6YXRpb24pLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVTeXN0ZW1BZG1pbihcbiAgcmVxOiBSZXF1ZXN0LFxuICByZXM6IFJlc3BvbnNlLFxuICBuZXh0OiBOZXh0RnVuY3Rpb24sXG4pOiB2b2lkIHtcbiAgaWYgKCFpc1N5c3RlbUFkbWluKHJlcSkpIHtcbiAgICByZXR1cm4gc2VuZEVycm9yKFxuICAgICAgcmVzLCBIdHRwU3RhdHVzLkZPUkJJRERFTixcbiAgICAgICdBY2Nlc3MgZGVuaWVkLiBPbmx5IHN5c3RlbSBhZG1pbmlzdHJhdG9ycyBjYW4gcGVyZm9ybSB0aGlzIGFjdGlvbi4nLFxuICAgICAgRXJyb3JDb2RlLklOU1VGRklDSUVOVF9QRVJNSVNTSU9OUyxcbiAgICApO1xuICB9XG4gIG5leHQoKTtcbn1cblxuLyoqXG4gKiBSZXF1aXJlIGEgc3BlY2lmaWMgZmVhdHVyZSBmbGFnLiBVc2UgYWZ0ZXIgcmVxdWlyZUF1dGguXG4gKiBDaGVja3MgdGhlIGBmZWF0dXJlc2AgYXJyYXkgaW4gdGhlIEpXVCBwYXlsb2FkIChzZXQgYXQgdG9rZW4gaXNzdWFuY2UpLlxuICogU3lzdGVtIG9yZyB1c2VycyBhbHdheXMgcGFzcyAoYWxsIGZlYXR1cmVzIGVuYWJsZWQpLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVxdWlyZUZlYXR1cmUoZmVhdHVyZTogc3RyaW5nKSB7XG4gIHJldHVybiAocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlLCBuZXh0OiBOZXh0RnVuY3Rpb24pOiB2b2lkID0+IHtcbiAgICBpZiAoIXJlcS51c2VyKSB7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdBdXRoZW50aWNhdGlvbiByZXF1aXJlZCcsIEVycm9yQ29kZS5VTkFVVEhPUklaRUQpO1xuICAgIH1cblxuICAgIC8vIFN5c3RlbSBvcmcgYWx3YXlzIGhhcyBhbGwgZmVhdHVyZXNcbiAgICBpZiAoaXNTeXN0ZW1PcmcocmVxKSkgcmV0dXJuIG5leHQoKTtcblxuICAgIGlmICghcmVxLnVzZXIuZmVhdHVyZXM/LmluY2x1ZGVzKGZlYXR1cmUpKSB7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKFxuICAgICAgICByZXMsIEh0dHBTdGF0dXMuRk9SQklEREVOLFxuICAgICAgICBgVGhpcyBmZWF0dXJlIHJlcXVpcmVzIGEgaGlnaGVyIHBsYW4gKCR7ZmVhdHVyZX0pYCxcbiAgICAgICAgRXJyb3JDb2RlLklOU1VGRklDSUVOVF9QRVJNSVNTSU9OUyxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgbmV4dCgpO1xuICB9O1xufVxuXG4vKiogT25seSBzeXN0ZW0gYWRtaW5zIGNhbiBzZXQgYWNjZXNzIHRvICdwdWJsaWMnOyBldmVyeW9uZSBlbHNlIGdldHMgJ3ByaXZhdGUnLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVBY2Nlc3NNb2RpZmllcihyZXE6IFJlcXVlc3QsIHJlcXVlc3RlZDogc3RyaW5nIHwgdW5kZWZpbmVkKTogJ3B1YmxpYycgfCAncHJpdmF0ZScge1xuICBpZiAocmVxdWVzdGVkID09PSAncHVibGljJyAmJiBpc1N5c3RlbUFkbWluKHJlcSkpIHtcbiAgICByZXR1cm4gJ3B1YmxpYyc7XG4gIH1cbiAgcmV0dXJuICdwcml2YXRlJztcbn1cbiJdfQ==
|
|
168
|
+
// ---------------------------------------------------------------------------
|
|
169
|
+
// Service-to-service tokens
|
|
170
|
+
//
|
|
171
|
+
// Inter-service HTTP calls (billing → message, platform → compliance, etc.)
|
|
172
|
+
// need to satisfy the same `requireAuth` middleware as user requests.
|
|
173
|
+
// `signServiceToken` mints a short-lived JWT signed with the shared
|
|
174
|
+
// JWT_SECRET, identifying the calling service via `sub: 'service:<name>'`.
|
|
175
|
+
// `requireAuth` accepts these tokens transparently — they pass `decoded.sub`
|
|
176
|
+
// and `decoded.role` checks, and downstream `requireOrganization` /
|
|
177
|
+
// `requireAdmin` rely on the org/role embedded in the token.
|
|
178
|
+
//
|
|
179
|
+
// Tokens default to 5-minute TTL — long enough to survive a backend hop,
|
|
180
|
+
// short enough that a leaked token is low-value.
|
|
181
|
+
// ---------------------------------------------------------------------------
|
|
182
|
+
const DEFAULT_SERVICE_TOKEN_TTL_SECONDS = 300;
|
|
183
|
+
/**
|
|
184
|
+
* Mint a JWT identifying the calling service. Used for inter-service HTTP calls.
|
|
185
|
+
* The token satisfies `requireAuth` and (when orgId is present) `requireOrganization`.
|
|
186
|
+
*/
|
|
187
|
+
function signServiceToken(opts) {
|
|
188
|
+
const payload = {
|
|
189
|
+
sub: `service:${opts.serviceName}`,
|
|
190
|
+
username: `${opts.serviceName}-service`,
|
|
191
|
+
email: `${opts.serviceName}@internal`,
|
|
192
|
+
role: 'owner',
|
|
193
|
+
isAdmin: true,
|
|
194
|
+
type: 'access',
|
|
195
|
+
organizationId: opts.orgId,
|
|
196
|
+
organizationName: opts.orgName ?? opts.orgId,
|
|
197
|
+
};
|
|
198
|
+
return jsonwebtoken_1.default.sign(payload, getJwtSecret(), {
|
|
199
|
+
expiresIn: opts.ttlSeconds ?? DEFAULT_SERVICE_TOKEN_TTL_SECONDS,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
/** Convenience: returns a `Bearer <token>` header value for fetch/axios calls. */
|
|
203
|
+
function getServiceAuthHeader(opts) {
|
|
204
|
+
return `Bearer ${signServiceToken(opts)}`;
|
|
205
|
+
}
|
|
206
|
+
/** True when `req.user.sub` was issued by `signServiceToken` (i.e. starts with `service:`). */
|
|
207
|
+
function isServicePrincipal(req) {
|
|
208
|
+
return req.user?.sub?.startsWith('service:') ?? false;
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9taWRkbGV3YXJlL2F1dGgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7Ozs7OztBQTJEdEMsa0NBYUM7QUF5REQsb0NBY0M7QUFXRCxzQ0FFQztBQUVELGtDQUdDO0FBTUQsc0NBRUM7QUFHRCxnREFhQztBQU9ELHdDQW1CQztBQVFELHNEQUtDO0FBa0NELDRDQWNDO0FBR0Qsb0RBRUM7QUFHRCxnREFFQztBQXZSRCxnRUFBK0I7QUFDL0IsMERBQXNEO0FBRXRELHNEQUFpRDtBQUNqRCw4Q0FBbUQ7QUFDbkQsNENBQStDO0FBQy9DLGdEQUE4QztBQUU5QyxNQUFNLE1BQU0sR0FBRyxJQUFBLHFCQUFZLEVBQUMsaUJBQWlCLENBQUMsQ0FBQztBQUUvQyw0REFBNEQ7QUFDNUQsSUFBSSxVQUE4QixDQUFDO0FBQ25DLElBQUkscUJBQXFCLEdBQUcsQ0FBQyxDQUFDO0FBQzlCLE1BQU0sOEJBQThCLEdBQUcsT0FBTyxDQUFDLENBQUMsWUFBWTtBQUU1RCxTQUFTLFlBQVk7SUFDbkIsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO0lBQ3ZCLElBQUksQ0FBQyxVQUFVLElBQUksR0FBRyxHQUFHLHFCQUFxQixHQUFHLDhCQUE4QixFQUFFLENBQUM7UUFDaEYsTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUM7UUFDdEMsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ1osTUFBTSxDQUFDLEtBQUssQ0FBQyw0Q0FBNEMsQ0FBQyxDQUFDO1lBQzNELE1BQU0sSUFBSSxLQUFLLENBQUMsNkNBQTZDLENBQUMsQ0FBQztRQUNqRSxDQUFDO1FBQ0QsSUFBSSxVQUFVLElBQUksVUFBVSxLQUFLLE1BQU0sRUFBRSxDQUFDO1lBQ3hDLE1BQU0sQ0FBQyxJQUFJLENBQUMsb0JBQW9CLENBQUMs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QUFDakQsOEVBQThFO0FBRTlFLE1BQU0saUNBQWlDLEdBQUcsR0FBRyxDQUFDO0FBYTlDOzs7R0FHRztBQUNILFNBQWdCLGdCQUFnQixDQUFDLElBQXlCO0lBQ3hELE1BQU0sT0FBTyxHQUFlO1FBQzFCLEdBQUcsRUFBRSxXQUFXLElBQUksQ0FBQyxXQUFXLEVBQUU7UUFDbEMsUUFBUSxFQUFFLEdBQUcsSUFBSSxDQUFDLFdBQVcsVUFBVTtRQUN2QyxLQUFLLEVBQUUsR0FBRyxJQUFJLENBQUMsV0FBVyxXQUFXO1FBQ3JDLElBQUksRUFBRSxPQUFPO1FBQ2IsT0FBTyxFQUFFLElBQUk7UUFDYixJQUFJLEVBQUUsUUFBUTtRQUNkLGNBQWMsRUFBRSxJQUFJLENBQUMsS0FBSztRQUMxQixnQkFBZ0IsRUFBRSxJQUFJLENBQUMsT0FBTyxJQUFJLElBQUksQ0FBQyxLQUFLO0tBQzdDLENBQUM7SUFDRixPQUFPLHNCQUFHLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxZQUFZLEVBQUUsRUFBRTtRQUN2QyxTQUFTLEVBQUUsSUFBSSxDQUFDLFVBQVUsSUFBSSxpQ0FBaUM7S0FDaEUsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQUVELGtGQUFrRjtBQUNsRixTQUFnQixvQkFBb0IsQ0FBQyxJQUF5QjtJQUM1RCxPQUFPLFVBQVUsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztBQUM1QyxDQUFDO0FBRUQsK0ZBQStGO0FBQy9GLFNBQWdCLGtCQUFrQixDQUFDLEdBQVk7SUFDN0MsT0FBTyxHQUFHLENBQUMsSUFBSSxFQUFFLEdBQUcsRUFBRSxVQUFVLENBQUMsVUFBVSxDQUFDLElBQUksS0FBSyxDQUFDO0FBQ3hELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuaW1wb3J0IHsgUmVxdWVzdCwgUmVzcG9uc2UsIE5leHRGdW5jdGlvbiB9IGZyb20gJ2V4cHJlc3MnO1xuaW1wb3J0IGp3dCBmcm9tICdqc29ud2VidG9rZW4nO1xuaW1wb3J0IHsgSHR0cFN0YXR1cyB9IGZyb20gJy4uL2NvbnN0YW50cy9odHRwLXN0YXR1cyc7XG5pbXBvcnQgeyBKd3RQYXlsb2FkIH0gZnJvbSAnLi4vdHlwZXMvY29tbW9uJztcbmltcG9ydCB7IEVycm9yQ29kZSB9IGZyb20gJy4uL3R5cGVzL2Vycm9yLWNvZGVzJztcbmltcG9ydCB7IGdldEhlYWRlclN0cmluZyB9IGZyb20gJy4uL3V0aWxzL2hlYWRlcnMnO1xuaW1wb3J0IHsgY3JlYXRlTG9nZ2VyIH0gZnJvbSAnLi4vdXRpbHMvbG9nZ2VyJztcbmltcG9ydCB7IHNlbmRFcnJvciB9IGZyb20gJy4uL3V0aWxzL3Jlc3BvbnNlJztcblxuY29uc3QgbG9nZ2VyID0gY3JlYXRlTG9nZ2VyKCdhdXRoLW1pZGRsZXdhcmUnKTtcblxuLyoqIENhY2hlZCBKV1Qgc2VjcmV0IHdpdGggcGVyaW9kaWMgcmVmcmVzaCBmcm9tIGVudiB2YXIuICovXG5sZXQgX2p3dFNlY3JldDogc3RyaW5nIHwgdW5kZWZpbmVkO1xubGV0IF9qd3RTZWNyZXRSZWZyZXNoZWRBdCA9IDA7XG5jb25zdCBKV1RfU0VDUkVUX1JFRlJFU0hfSU5URVJWQUxfTVMgPSAzMDBfMDAwOyAvLyA1IG1pbnV0ZXNcblxuZnVuY3Rpb24gZ2V0Snd0U2VjcmV0KCk6IHN0cmluZyB7XG4gIGNvbnN0IG5vdyA9IERhdGUubm93KCk7XG4gIGlmICghX2p3dFNlY3JldCB8fCBub3cgLSBfand0U2VjcmV0UmVmcmVzaGVkQXQgPiBKV1RfU0VDUkVUX1JFRlJFU0hfSU5URVJWQUxfTVMpIHtcbiAgICBjb25zdCBzZWNyZXQgPSBwcm9jZXNzLmVudi5KV1RfU0VDUkVUO1xuICAgIGlmICghc2VjcmV0KSB7XG4gICAgICBsb2dnZXIuZXJyb3IoJ0pXVF9TRUNSRVQgZW52aXJvbm1lbnQgdmFyaWFibGUgaXMgbm90IHNldCcpO1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdKV1RfU0VDUkVUIGVudmlyb25tZW50IHZhcmlhYmxlIGlzIHJlcXVpcmVkJyk7XG4gICAgfVxuICAgIGlmIChfand0U2VjcmV0ICYmIF9qd3RTZWNyZXQgIT09IHNlY3JldCkge1xuICAgICAgbG9nZ2VyLmluZm8oJ0pXVCBzZWNyZXQgcm90YXRlZCcpO1xuICAgIH1cbiAgICBfand0U2VjcmV0ID0gc2VjcmV0O1xuICAgIF9qd3RTZWNyZXRSZWZyZXNoZWRBdCA9IG5vdztcbiAgfVxuICByZXR1cm4gX2p3dFNlY3JldDtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBSZXF1aXJlQXV0aE9wdGlvbnMge1xuICAvKipcbiAgICogQWxsb3cgeC1vcmctaWQveC1vcmctbmFtZSBoZWFkZXJzIHRvIG92ZXJyaWRlIHRoZSBKV1QncyBvcmdhbml6YXRpb24gZmllbGRzLlxuICAgKlxuICAgKiAqKlNFQ1VSSVRZIFdBUk5JTkc6KiogV2hlbiBlbmFibGVkLCBhIGNhbGxlciBjYW4gc2V0IGB4LW9yZy1pZGAgdG8gQU5ZXG4gICAqIG9yZ2FuaXphdGlvbiBJRCwgZWZmZWN0aXZlbHkgaW1wZXJzb25hdGluZyB0aGF0IG9yZy4gVGhpcyBNVVNUIG9ubHkgYmVcbiAgICogdXNlZCBvbiByb3V0ZXMgdGhhdCBhcmU6XG4gICAqICAgMS4gSW50ZXJuYWwgc2VydmljZS10by1zZXJ2aWNlIHJvdXRlcyAobm90IGV4cG9zZWQgdG8gZW5kIHVzZXJzKVxuICAgKiAgIDIuIEJlaGluZCBuZXR3b3JrIGlzb2xhdGlvbiAoY29udGFpbmVyIG5ldHdvcmssIFZQQywgZXRjLilcbiAgICpcbiAgICogTkVWRVIgZW5hYmxlIHRoaXMgb24gdXNlci1mYWNpbmcgQVBJIHJvdXRlcy4gSWYgdW5zdXJlLCBsZWF2ZSBpdCBkaXNhYmxlZC5cbiAgICovXG4gIGFsbG93T3JnSGVhZGVyT3ZlcnJpZGU/OiBib29sZWFuO1xufVxuXG4vKiogSldUIGF1dGggbWlkZGxld2FyZS4gVXNlIGRpcmVjdGx5IG9yIGNhbGwgd2l0aCBvcHRpb25zLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVBdXRoKFxuICByZXE6IFJlcXVlc3QsXG4gIHJlczogUmVzcG9uc2UsXG4gIG5leHQ6IE5leHRGdW5jdGlvbixcbik6IHZvaWQ7XG5leHBvcnQgZnVuY3Rpb24gcmVxdWlyZUF1dGgoXG4gIG9wdGlvbnM/OiBSZXF1aXJlQXV0aE9wdGlvbnMsXG4pOiAocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlLCBuZXh0OiBOZXh0RnVuY3Rpb24pID0+IHZvaWQ7XG5leHBvcnQgZnVuY3Rpb24gcmVxdWlyZUF1dGgoXG4gIHJlcU9yT3B0aW9ucz86IFJlcXVlc3QgfCBSZXF1aXJlQXV0aE9wdGlvbnMsXG4gIHJlcz86IFJlc3BvbnNlLFxuICBuZXh0PzogTmV4dEZ1bmN0aW9uLFxuKTogdm9pZCB8ICgocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlLCBuZXh0OiBOZXh0RnVuY3Rpb24pID0+IHZvaWQpIHtcbiAgaWYgKHJlcU9yT3B0aW9ucyAmJiByZXMgJiYgbmV4dCAmJiAnaGVhZGVycycgaW4gcmVxT3JPcHRpb25zKSB7XG4gICAgcmV0dXJuIF9yZXF1aXJlQXV0aCh7fSwgcmVxT3JPcHRpb25zIGFzIFJlcXVlc3QsIHJlcywgbmV4dCk7XG4gIH1cblxuICBjb25zdCBvcHRpb25zID0gKHJlcU9yT3B0aW9ucyBhcyBSZXF1aXJlQXV0aE9wdGlvbnMpIHx8IHt9O1xuICByZXR1cm4gKHJlcTogUmVxdWVzdCwgcmVzSW5uZXI6IFJlc3BvbnNlLCBuZXh0SW5uZXI6IE5leHRGdW5jdGlvbikgPT4ge1xuICAgIF9yZXF1aXJlQXV0aChvcHRpb25zLCByZXEsIHJlc0lubmVyLCBuZXh0SW5uZXIpO1xuICB9O1xufVxuXG5mdW5jdGlvbiBfcmVxdWlyZUF1dGgoXG4gIG9wdGlvbnM6IFJlcXVpcmVBdXRoT3B0aW9ucyxcbiAgcmVxOiBSZXF1ZXN0LFxuICByZXM6IFJlc3BvbnNlLFxuICBuZXh0OiBOZXh0RnVuY3Rpb24sXG4pOiB2b2lkIHtcbiAgY29uc3QgYXV0aEhlYWRlciA9IHJlcS5oZWFkZXJzLmF1dGhvcml6YXRpb247XG5cbiAgaWYgKCFhdXRoSGVhZGVyKSB7XG4gICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuVU5BVVRIT1JJWkVELCAnQXV0aG9yaXphdGlvbiBoZWFkZXIgcmVxdWlyZWQnLCBFcnJvckNvZGUuVE9LRU5fTUlTU0lORyk7XG4gIH1cblxuICBjb25zdCBwYXJ0cyA9IGF1dGhIZWFkZXIuc3BsaXQoJyAnKTtcbiAgaWYgKHBhcnRzLmxlbmd0aCAhPT0gMiB8fCBwYXJ0c1swXSAhPT0gJ0JlYXJlcicpIHtcbiAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdJbnZhbGlkIGF1dGhvcml6YXRpb24gZm9ybWF0LiBVc2U6IEJlYXJlciA8dG9rZW4+JywgRXJyb3JDb2RlLlRPS0VOX0lOVkFMSUQpO1xuICB9XG5cbiAgdHJ5IHtcbiAgICBjb25zdCBkZWNvZGVkID0gand0LnZlcmlmeShwYXJ0c1sxXSwgZ2V0Snd0U2VjcmV0KCkpIGFzIEp3dFBheWxvYWQ7XG5cbiAgICBpZiAoZGVjb2RlZC50eXBlICE9PSAnYWNjZXNzJykge1xuICAgICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuVU5BVVRIT1JJWkVELCAnT25seSBhY2Nlc3MgdG9rZW5zIGNhbiBiZSB1c2VkIGZvciBBUEkgcmVxdWVzdHMnLCBFcnJvckNvZGUuVE9LRU5fSU5WQUxJRCk7XG4gICAgfVxuXG4gICAgaWYgKCFkZWNvZGVkLnN1YiB8fCAhZGVjb2RlZC5yb2xlKSB7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdUb2tlbiBtaXNzaW5nIHJlcXVpcmVkIGZpZWxkcycsIEVycm9yQ29kZS5UT0tFTl9JTlZBTElEKTtcbiAgICB9XG5cbiAgICByZXEudXNlciA9IHsgLi4uZGVjb2RlZCB9O1xuXG4gICAgaWYgKG9wdGlvbnMuYWxsb3dPcmdIZWFkZXJPdmVycmlkZSkge1xuICAgICAgY29uc3QgaGVhZGVyT3JnSWQgPSBnZXRIZWFkZXJTdHJpbmcocmVxLmhlYWRlcnNbJ3gtb3JnLWlkJ10pO1xuICAgICAgY29uc3QgaGVhZGVyT3JnTmFtZSA9IGdldEhlYWRlclN0cmluZyhyZXEuaGVhZGVyc1sneC1vcmctbmFtZSddKTtcbiAgICAgIGlmIChoZWFkZXJPcmdJZCkgcmVxLnVzZXIub3JnYW5pemF0aW9uSWQgPSBoZWFkZXJPcmdJZDtcbiAgICAgIGlmIChoZWFkZXJPcmdOYW1lKSByZXEudXNlci5vcmdhbml6YXRpb25OYW1lID0gaGVhZGVyT3JnTmFtZTtcbiAgICB9XG5cbiAgICBuZXh0KCk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgaWYgKGVycm9yIGluc3RhbmNlb2Ygand0LlRva2VuRXhwaXJlZEVycm9yKSB7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdUb2tlbiBoYXMgZXhwaXJlZCcsIEVycm9yQ29kZS5UT0tFTl9FWFBJUkVEKTtcbiAgICB9XG5cbiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBqd3QuSnNvbldlYlRva2VuRXJyb3IpIHtcbiAgICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ0ludmFsaWQgdG9rZW4nLCBFcnJvckNvZGUuVE9LRU5fSU5WQUxJRCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuVU5BVVRIT1JJWkVELCAnQXV0aGVudGljYXRpb24gZmFpbGVkJywgRXJyb3JDb2RlLlVOQVVUSE9SSVpFRCk7XG4gIH1cbn1cblxuLyoqXG4gKiBSZXF1aXJlcyBhZG1pbiByb2xlLiBVc2UgYWZ0ZXIgcmVxdWlyZUF1dGguXG4gKiBQZXJtaXRzIHVzZXJzIHdob3NlIHBlci1vcmcgcm9sZSBpcyAnYWRtaW4nIG9yICdvd25lcicuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlQWRtaW4oXG4gIHJlcTogUmVxdWVzdCxcbiAgcmVzOiBSZXNwb25zZSxcbiAgbmV4dDogTmV4dEZ1bmN0aW9uLFxuKTogdm9pZCB7XG4gIGlmICghcmVxLnVzZXIpIHtcbiAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdBdXRoZW50aWNhdGlvbiByZXF1aXJlZCcsIEVycm9yQ29kZS5VTkFVVEhPUklaRUQpO1xuICB9XG5cbiAgaWYgKHJlcS51c2VyLnJvbGUgIT09ICdhZG1pbicgJiYgcmVxLnVzZXIucm9sZSAhPT0gJ293bmVyJykge1xuICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLkZPUkJJRERFTiwgJ0FkbWluIGFjY2VzcyByZXF1aXJlZCcsIEVycm9yQ29kZS5JTlNVRkZJQ0lFTlRfUEVSTUlTU0lPTlMpO1xuICB9XG5cbiAgbmV4dCgpO1xufVxuXG4vKiogT3JnYW5pemF0aW9uIElEL25hbWUgdGhhdCBpZGVudGlmaWVzIHRoZSBzeXN0ZW0gKHN1cGVyLWFkbWluKSB0ZW5hbnQuICovXG5leHBvcnQgY29uc3QgU1lTVEVNX09SR19JRCA9IChwcm9jZXNzLmVudi5TWVNURU1fT1JHX0lEIHx8ICdzeXN0ZW0nKS50b0xvd2VyQ2FzZSgpO1xuXG4vKipcbiAqIENoZWNrIGlmIGFuIG9yZ0lkIG9yIG9yZ05hbWUgbWF0Y2hlcyB0aGUgc3lzdGVtIG9yZy5cbiAqIFVzZSB0aGlzIGluc3RlYWQgb2YgY29tcGFyaW5nIGRpcmVjdGx5IGFnYWluc3QgU1lTVEVNX09SR19JRCxcbiAqIGJlY2F1c2UgdGhlIEpXVCBvcmdJZCBpcyBhIGRhdGFiYXNlIElEIChlLmcuIE1vbmdvREIgT2JqZWN0SWQpXG4gKiB3aGlsZSBTWVNURU1fT1JHX0lEIGlzIHRoZSB3ZWxsLWtub3duIG5hbWUgXCJzeXN0ZW1cIi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzU3lzdGVtT3JnSWQob3JnSWQ/OiBzdHJpbmcsIG9yZ05hbWU/OiBzdHJpbmcpOiBib29sZWFuIHtcbiAgcmV0dXJuIG9yZ0lkPy50b0xvd2VyQ2FzZSgpID09PSBTWVNURU1fT1JHX0lEIHx8IG9yZ05hbWU/LnRvTG93ZXJDYXNlKCkgPT09IFNZU1RFTV9PUkdfSUQ7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBpc1N5c3RlbU9yZyhyZXE6IFJlcXVlc3QpOiBib29sZWFuIHtcbiAgaWYgKCFyZXEudXNlcikgcmV0dXJuIGZhbHNlO1xuICByZXR1cm4gaXNTeXN0ZW1PcmdJZChyZXEudXNlci5vcmdhbml6YXRpb25JZCwgcmVxLnVzZXIub3JnYW5pemF0aW9uTmFtZSk7XG59XG5cbi8qKlxuICogQ2hlY2sgaWYgdGhlIHJlcXVlc3QgaXMgZnJvbSBhIHN5c3RlbSBhZG1pbi5cbiAqIEEgc3lzdGVtIGFkbWluIGhhcyBwZXItb3JnIHJvbGUgJ2FkbWluJyBvciAnb3duZXInIGluIHRoZSBzeXN0ZW0gb3JnYW5pemF0aW9uLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNTeXN0ZW1BZG1pbihyZXE6IFJlcXVlc3QpOiBib29sZWFuIHtcbiAgcmV0dXJuIChyZXEudXNlcj8ucm9sZSA9PT0gJ2FkbWluJyB8fCByZXEudXNlcj8ucm9sZSA9PT0gJ293bmVyJykgJiYgaXNTeXN0ZW1PcmcocmVxKTtcbn1cblxuLyoqIFJlcXVpcmVzIHN5c3RlbSBhZG1pbiAoYWRtaW4gcm9sZSArIHN5c3RlbSBvcmdhbml6YXRpb24pLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVTeXN0ZW1BZG1pbihcbiAgcmVxOiBSZXF1ZXN0LFxuICByZXM6IFJlc3BvbnNlLFxuICBuZXh0OiBOZXh0RnVuY3Rpb24sXG4pOiB2b2lkIHtcbiAgaWYgKCFpc1N5c3RlbUFkbWluKHJlcSkpIHtcbiAgICByZXR1cm4gc2VuZEVycm9yKFxuICAgICAgcmVzLCBIdHRwU3RhdHVzLkZPUkJJRERFTixcbiAgICAgICdBY2Nlc3MgZGVuaWVkLiBPbmx5IHN5c3RlbSBhZG1pbmlzdHJhdG9ycyBjYW4gcGVyZm9ybSB0aGlzIGFjdGlvbi4nLFxuICAgICAgRXJyb3JDb2RlLklOU1VGRklDSUVOVF9QRVJNSVNTSU9OUyxcbiAgICApO1xuICB9XG4gIG5leHQoKTtcbn1cblxuLyoqXG4gKiBSZXF1aXJlIGEgc3BlY2lmaWMgZmVhdHVyZSBmbGFnLiBVc2UgYWZ0ZXIgcmVxdWlyZUF1dGguXG4gKiBDaGVja3MgdGhlIGBmZWF0dXJlc2AgYXJyYXkgaW4gdGhlIEpXVCBwYXlsb2FkIChzZXQgYXQgdG9rZW4gaXNzdWFuY2UpLlxuICogU3lzdGVtIG9yZyB1c2VycyBhbHdheXMgcGFzcyAoYWxsIGZlYXR1cmVzIGVuYWJsZWQpLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVxdWlyZUZlYXR1cmUoZmVhdHVyZTogc3RyaW5nKSB7XG4gIHJldHVybiAocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlLCBuZXh0OiBOZXh0RnVuY3Rpb24pOiB2b2lkID0+IHtcbiAgICBpZiAoIXJlcS51c2VyKSB7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5VTkFVVEhPUklaRUQsICdBdXRoZW50aWNhdGlvbiByZXF1aXJlZCcsIEVycm9yQ29kZS5VTkFVVEhPUklaRUQpO1xuICAgIH1cblxuICAgIC8vIFN5c3RlbSBvcmcgYWx3YXlzIGhhcyBhbGwgZmVhdHVyZXNcbiAgICBpZiAoaXNTeXN0ZW1PcmcocmVxKSkgcmV0dXJuIG5leHQoKTtcblxuICAgIGlmICghcmVxLnVzZXIuZmVhdHVyZXM/LmluY2x1ZGVzKGZlYXR1cmUpKSB7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKFxuICAgICAgICByZXMsIEh0dHBTdGF0dXMuRk9SQklEREVOLFxuICAgICAgICBgVGhpcyBmZWF0dXJlIHJlcXVpcmVzIGEgaGlnaGVyIHBsYW4gKCR7ZmVhdHVyZX0pYCxcbiAgICAgICAgRXJyb3JDb2RlLklOU1VGRklDSUVOVF9QRVJNSVNTSU9OUyxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgbmV4dCgpO1xuICB9O1xufVxuXG4vKipcbiAqIFJlc29sdmUgdGhlIGVmZmVjdGl2ZSBhY2Nlc3MgbW9kaWZpZXIgZm9yIGFuIGVudGl0eSBiZWluZyBjcmVhdGVkL3VwZGF0ZWQuXG4gKiAncHVibGljJyBpcyBwZXJtaXR0ZWQgZm9yIGFueSBhZG1pbiBvciBvd25lciByb2xlIChzeXN0ZW0gYWRtaW5zIGNyZWF0ZVxuICogY2F0YWxvZy13aWRlIHB1YmxpYyBlbnRpdGllczsgb3JnIGFkbWlucyBjcmVhdGUgb3JnLXdpZGUgcHVibGljIGVudGl0aWVzKS5cbiAqIEV2ZXJ5b25lIGVsc2UgKG1lbWJlciByb2xlLCBubyByb2xlKSBnZXRzICdwcml2YXRlJy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVBY2Nlc3NNb2RpZmllcihyZXE6IFJlcXVlc3QsIHJlcXVlc3RlZDogc3RyaW5nIHwgdW5kZWZpbmVkKTogJ3B1YmxpYycgfCAncHJpdmF0ZScge1xuICBpZiAocmVxdWVzdGVkID09PSAncHVibGljJyAmJiAocmVxLnVzZXI/LnJvbGUgPT09ICdhZG1pbicgfHwgcmVxLnVzZXI/LnJvbGUgPT09ICdvd25lcicpKSB7XG4gICAgcmV0dXJuICdwdWJsaWMnO1xuICB9XG4gIHJldHVybiAncHJpdmF0ZSc7XG59XG5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gU2VydmljZS10by1zZXJ2aWNlIHRva2Vuc1xuLy9cbi8vIEludGVyLXNlcnZpY2UgSFRUUCBjYWxscyAoYmlsbGluZyDihpIgbWVzc2FnZSwgcGxhdGZvcm0g4oaSIGNvbXBsaWFuY2UsIGV0Yy4pXG4vLyBuZWVkIHRvIHNhdGlzZnkgdGhlIHNhbWUgYHJlcXVpcmVBdXRoYCBtaWRkbGV3YXJlIGFzIHVzZXIgcmVxdWVzdHMuXG4vLyBgc2lnblNlcnZpY2VUb2tlbmAgbWludHMgYSBzaG9ydC1saXZlZCBKV1Qgc2lnbmVkIHdpdGggdGhlIHNoYXJlZFxuLy8gSldUX1NFQ1JFVCwgaWRlbnRpZnlpbmcgdGhlIGNhbGxpbmcgc2VydmljZSB2aWEgYHN1YjogJ3NlcnZpY2U6PG5hbWU+J2AuXG4vLyBgcmVxdWlyZUF1dGhgIGFjY2VwdHMgdGhlc2UgdG9rZW5zIHRyYW5zcGFyZW50bHkg4oCUIHRoZXkgcGFzcyBgZGVjb2RlZC5zdWJgXG4vLyBhbmQgYGRlY29kZWQucm9sZWAgY2hlY2tzLCBhbmQgZG93bnN0cmVhbSBgcmVxdWlyZU9yZ2FuaXphdGlvbmAgL1xuLy8gYHJlcXVpcmVBZG1pbmAgcmVseSBvbiB0aGUgb3JnL3JvbGUgZW1iZWRkZWQgaW4gdGhlIHRva2VuLlxuLy9cbi8vIFRva2VucyBkZWZhdWx0IHRvIDUtbWludXRlIFRUTCDigJQgbG9uZyBlbm91Z2ggdG8gc3Vydml2ZSBhIGJhY2tlbmQgaG9wLFxuLy8gc2hvcnQgZW5vdWdoIHRoYXQgYSBsZWFrZWQgdG9rZW4gaXMgbG93LXZhbHVlLlxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbmNvbnN0IERFRkFVTFRfU0VSVklDRV9UT0tFTl9UVExfU0VDT05EUyA9IDMwMDtcblxuZXhwb3J0IGludGVyZmFjZSBTZXJ2aWNlVG9rZW5PcHRpb25zIHtcbiAgLyoqIENhbGxpbmcgc2VydmljZSBpZGVudGlmaWVyIChlLmcuICdiaWxsaW5nJywgJ3BsYXRmb3JtJykuIEVtYmVkZGVkIGFzIGBzdWI6IHNlcnZpY2U6PG5hbWU+YC4gKi9cbiAgc2VydmljZU5hbWU6IHN0cmluZztcbiAgLyoqIEFjdGl2ZSBvcmcgY29udGV4dCBmb3IgdGhlIGNhbGwuIFVzZSB0aGUgdGFyZ2V0IHRlbmFudCdzIG9yZyBJRCwgb3IgJ3N5c3RlbScgZm9yIHN5c3RlbS13aWRlIG9wcy4gKi9cbiAgb3JnSWQ/OiBzdHJpbmc7XG4gIC8qKiBBY3RpdmUgb3JnIG5hbWUuIERlZmF1bHRzIHRvIG9yZ0lkLiAqL1xuICBvcmdOYW1lPzogc3RyaW5nO1xuICAvKiogVFRMIGluIHNlY29uZHMgKGRlZmF1bHQgMzAwKS4gKi9cbiAgdHRsU2Vjb25kcz86IG51bWJlcjtcbn1cblxuLyoqXG4gKiBNaW50IGEgSldUIGlkZW50aWZ5aW5nIHRoZSBjYWxsaW5nIHNlcnZpY2UuIFVzZWQgZm9yIGludGVyLXNlcnZpY2UgSFRUUCBjYWxscy5cbiAqIFRoZSB0b2tlbiBzYXRpc2ZpZXMgYHJlcXVpcmVBdXRoYCBhbmQgKHdoZW4gb3JnSWQgaXMgcHJlc2VudCkgYHJlcXVpcmVPcmdhbml6YXRpb25gLlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2lnblNlcnZpY2VUb2tlbihvcHRzOiBTZXJ2aWNlVG9rZW5PcHRpb25zKTogc3RyaW5nIHtcbiAgY29uc3QgcGF5bG9hZDogSnd0UGF5bG9hZCA9IHtcbiAgICBzdWI6IGBzZXJ2aWNlOiR7b3B0cy5zZXJ2aWNlTmFtZX1gLFxuICAgIHVzZXJuYW1lOiBgJHtvcHRzLnNlcnZpY2VOYW1lfS1zZXJ2aWNlYCxcbiAgICBlbWFpbDogYCR7b3B0cy5zZXJ2aWNlTmFtZX1AaW50ZXJuYWxgLFxuICAgIHJvbGU6ICdvd25lcicsXG4gICAgaXNBZG1pbjogdHJ1ZSxcbiAgICB0eXBlOiAnYWNjZXNzJyxcbiAgICBvcmdhbml6YXRpb25JZDogb3B0cy5vcmdJZCxcbiAgICBvcmdhbml6YXRpb25OYW1lOiBvcHRzLm9yZ05hbWUgPz8gb3B0cy5vcmdJZCxcbiAgfTtcbiAgcmV0dXJuIGp3dC5zaWduKHBheWxvYWQsIGdldEp3dFNlY3JldCgpLCB7XG4gICAgZXhwaXJlc0luOiBvcHRzLnR0bFNlY29uZHMgPz8gREVGQVVMVF9TRVJWSUNFX1RPS0VOX1RUTF9TRUNPTkRTLFxuICB9KTtcbn1cblxuLyoqIENvbnZlbmllbmNlOiByZXR1cm5zIGEgYEJlYXJlciA8dG9rZW4+YCBoZWFkZXIgdmFsdWUgZm9yIGZldGNoL2F4aW9zIGNhbGxzLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFNlcnZpY2VBdXRoSGVhZGVyKG9wdHM6IFNlcnZpY2VUb2tlbk9wdGlvbnMpOiBzdHJpbmcge1xuICByZXR1cm4gYEJlYXJlciAke3NpZ25TZXJ2aWNlVG9rZW4ob3B0cyl9YDtcbn1cblxuLyoqIFRydWUgd2hlbiBgcmVxLnVzZXIuc3ViYCB3YXMgaXNzdWVkIGJ5IGBzaWduU2VydmljZVRva2VuYCAoaS5lLiBzdGFydHMgd2l0aCBgc2VydmljZTpgKS4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1NlcnZpY2VQcmluY2lwYWwocmVxOiBSZXF1ZXN0KTogYm9vbGVhbiB7XG4gIHJldHVybiByZXEudXNlcj8uc3ViPy5zdGFydHNXaXRoKCdzZXJ2aWNlOicpID8/IGZhbHNlO1xufVxuIl19
|
package/lib/routes/health.d.ts
CHANGED
|
@@ -11,37 +11,31 @@ export interface HealthCheckOptions {
|
|
|
11
11
|
checkDependencies?: () => Promise<Record<string, 'connected' | 'disconnected' | 'unknown'>>;
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
14
|
-
*
|
|
14
|
+
* Liveness handler — returns 200 as long as the process is alive enough to
|
|
15
|
+
* respond. Dependency status is reported in the body as informational, but a
|
|
16
|
+
* disconnected dependency does NOT fail the probe (use /ready for that).
|
|
15
17
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* ```typescript
|
|
21
|
-
* app.get('/health', createHealthCheck({
|
|
22
|
-
* serviceName: 'get-plugin',
|
|
23
|
-
* version: '1.0.0',
|
|
24
|
-
* checkDependencies: async () => ({
|
|
25
|
-
* database: dbConnection.isConnected() ? 'connected' : 'disconnected',
|
|
26
|
-
* }),
|
|
27
|
-
* }));
|
|
28
|
-
* ```
|
|
18
|
+
* Use as the Kubernetes / ECS LIVENESS probe — it should only fail when the
|
|
19
|
+
* process is genuinely stuck and needs to be restarted.
|
|
29
20
|
*/
|
|
30
21
|
export declare function createHealthCheck(options: HealthCheckOptions): (_req: Request, res: Response) => Promise<void>;
|
|
31
22
|
/**
|
|
32
|
-
*
|
|
23
|
+
* Readiness handler — returns 503 if any dependency is `disconnected` (or
|
|
24
|
+
* the dependency check itself threw). Returns 200 only when the service is
|
|
25
|
+
* fully ready to serve traffic.
|
|
33
26
|
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
27
|
+
* Use as the Kubernetes / ECS READINESS probe — when this fails, the
|
|
28
|
+
* orchestrator stops routing traffic to this pod but does NOT restart it.
|
|
29
|
+
*/
|
|
30
|
+
export declare function createReadinessCheck(options: HealthCheckOptions): (_req: Request, res: Response) => Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Create a health/readiness router exposing:
|
|
33
|
+
* - GET /health — liveness (always 200 unless process is dead)
|
|
34
|
+
* - GET /ready — readiness (503 if dependencies are disconnected)
|
|
36
35
|
*
|
|
37
36
|
* @example
|
|
38
37
|
* ```typescript
|
|
39
|
-
*
|
|
40
|
-
* serviceName: 'get-plugin',
|
|
41
|
-
* });
|
|
42
|
-
*
|
|
43
|
-
* app.use(healthRouter);
|
|
44
|
-
* // Endpoint available at GET /health
|
|
38
|
+
* app.use(createHealthRouter({ serviceName: 'plugin' }));
|
|
45
39
|
* ```
|
|
46
40
|
*/
|
|
47
41
|
export declare function createHealthRouter(options: HealthCheckOptions): Router;
|
package/lib/routes/health.js
CHANGED
|
@@ -3,79 +3,85 @@
|
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
5
|
exports.createHealthCheck = createHealthCheck;
|
|
6
|
+
exports.createReadinessCheck = createReadinessCheck;
|
|
6
7
|
exports.createHealthRouter = createHealthRouter;
|
|
7
8
|
const express_1 = require("express");
|
|
8
9
|
const response_1 = require("../utils/response");
|
|
9
10
|
const startTime = Date.now();
|
|
10
11
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
* Build a HealthCheckResponse + collect dependency status.
|
|
13
|
+
* Shared between /health (liveness) and /ready (readiness).
|
|
14
|
+
*/
|
|
15
|
+
async function buildHealthResponse(options) {
|
|
16
|
+
const { serviceName, version, checkDependencies } = options;
|
|
17
|
+
const response = {
|
|
18
|
+
status: 'healthy',
|
|
19
|
+
service: serviceName,
|
|
20
|
+
timestamp: new Date().toISOString(),
|
|
21
|
+
uptime: Math.floor((Date.now() - startTime) / 1000),
|
|
22
|
+
};
|
|
23
|
+
if (version)
|
|
24
|
+
response.version = version;
|
|
25
|
+
if (!checkDependencies) {
|
|
26
|
+
return { response, hasDisconnected: false, checkFailed: false };
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
response.dependencies = await checkDependencies();
|
|
30
|
+
const hasDisconnected = Object.values(response.dependencies).some((status) => status === 'disconnected');
|
|
31
|
+
return { response, hasDisconnected, checkFailed: false };
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
response.dependencies = { check: 'disconnected' };
|
|
35
|
+
return { response, hasDisconnected: true, checkFailed: true };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Liveness handler — returns 200 as long as the process is alive enough to
|
|
40
|
+
* respond. Dependency status is reported in the body as informational, but a
|
|
41
|
+
* disconnected dependency does NOT fail the probe (use /ready for that).
|
|
15
42
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* app.get('/health', createHealthCheck({
|
|
19
|
-
* serviceName: 'get-plugin',
|
|
20
|
-
* version: '1.0.0',
|
|
21
|
-
* checkDependencies: async () => ({
|
|
22
|
-
* database: dbConnection.isConnected() ? 'connected' : 'disconnected',
|
|
23
|
-
* }),
|
|
24
|
-
* }));
|
|
25
|
-
* ```
|
|
43
|
+
* Use as the Kubernetes / ECS LIVENESS probe — it should only fail when the
|
|
44
|
+
* process is genuinely stuck and needs to be restarted.
|
|
26
45
|
*/
|
|
27
46
|
function createHealthCheck(options) {
|
|
28
47
|
return async (_req, res) => {
|
|
29
|
-
const {
|
|
30
|
-
const response = {
|
|
31
|
-
status: 'healthy',
|
|
32
|
-
service: serviceName,
|
|
33
|
-
timestamp: new Date().toISOString(),
|
|
34
|
-
uptime: Math.floor((Date.now() - startTime) / 1000),
|
|
35
|
-
};
|
|
36
|
-
if (version) {
|
|
37
|
-
response.version = version;
|
|
38
|
-
}
|
|
39
|
-
if (checkDependencies) {
|
|
40
|
-
try {
|
|
41
|
-
response.dependencies = await checkDependencies();
|
|
42
|
-
// Mark as unhealthy if any dependency is disconnected
|
|
43
|
-
const hasDisconnected = Object.values(response.dependencies).some((status) => status === 'disconnected');
|
|
44
|
-
if (hasDisconnected) {
|
|
45
|
-
response.status = 'unhealthy';
|
|
46
|
-
(0, response_1.sendError)(res, 503, 'Service unhealthy', undefined, response);
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
catch (error) {
|
|
51
|
-
response.status = 'unhealthy';
|
|
52
|
-
response.dependencies = { check: 'disconnected' };
|
|
53
|
-
(0, response_1.sendError)(res, 503, 'Service unhealthy', undefined, response);
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
48
|
+
const { response } = await buildHealthResponse(options);
|
|
57
49
|
(0, response_1.sendSuccess)(res, 200, response);
|
|
58
50
|
};
|
|
59
51
|
}
|
|
60
52
|
/**
|
|
61
|
-
*
|
|
53
|
+
* Readiness handler — returns 503 if any dependency is `disconnected` (or
|
|
54
|
+
* the dependency check itself threw). Returns 200 only when the service is
|
|
55
|
+
* fully ready to serve traffic.
|
|
62
56
|
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
57
|
+
* Use as the Kubernetes / ECS READINESS probe — when this fails, the
|
|
58
|
+
* orchestrator stops routing traffic to this pod but does NOT restart it.
|
|
59
|
+
*/
|
|
60
|
+
function createReadinessCheck(options) {
|
|
61
|
+
return async (_req, res) => {
|
|
62
|
+
const { response, hasDisconnected } = await buildHealthResponse(options);
|
|
63
|
+
if (hasDisconnected) {
|
|
64
|
+
response.status = 'unhealthy';
|
|
65
|
+
(0, response_1.sendError)(res, 503, 'Service not ready', undefined, response);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
(0, response_1.sendSuccess)(res, 200, response);
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Create a health/readiness router exposing:
|
|
73
|
+
* - GET /health — liveness (always 200 unless process is dead)
|
|
74
|
+
* - GET /ready — readiness (503 if dependencies are disconnected)
|
|
65
75
|
*
|
|
66
76
|
* @example
|
|
67
77
|
* ```typescript
|
|
68
|
-
*
|
|
69
|
-
* serviceName: 'get-plugin',
|
|
70
|
-
* });
|
|
71
|
-
*
|
|
72
|
-
* app.use(healthRouter);
|
|
73
|
-
* // Endpoint available at GET /health
|
|
78
|
+
* app.use(createHealthRouter({ serviceName: 'plugin' }));
|
|
74
79
|
* ```
|
|
75
80
|
*/
|
|
76
81
|
function createHealthRouter(options) {
|
|
77
82
|
const router = (0, express_1.Router)();
|
|
78
83
|
router.get('/health', createHealthCheck(options));
|
|
84
|
+
router.get('/ready', createReadinessCheck(options));
|
|
79
85
|
return router;
|
|
80
86
|
}
|
|
81
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
87
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGVhbHRoLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3JvdXRlcy9oZWFsdGgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7O0FBOER0Qyw4Q0FLQztBQVVELG9EQVVDO0FBWUQsZ0RBS0M7QUF0R0QscUNBQW9EO0FBRXBELGdEQUEyRDtBQUUzRCxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7QUFjN0I7OztHQUdHO0FBQ0gsS0FBSyxVQUFVLG1CQUFtQixDQUFDLE9BQTJCO0lBSzVELE1BQU0sRUFBRSxXQUFXLEVBQUUsT0FBTyxFQUFFLGlCQUFpQixFQUFFLEdBQUcsT0FBTyxDQUFDO0lBQzVELE1BQU0sUUFBUSxHQUF3QjtRQUNwQyxNQUFNLEVBQUUsU0FBUztRQUNqQixPQUFPLEVBQUUsV0FBVztRQUNwQixTQUFTLEVBQUUsSUFBSSxJQUFJLEVBQUUsQ0FBQyxXQUFXLEVBQUU7UUFDbkMsTUFBTSxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsU0FBUyxDQUFDLEdBQUcsSUFBSSxDQUFDO0tBQ3BELENBQUM7SUFDRixJQUFJLE9BQU87UUFBRSxRQUFRLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQztJQUV4QyxJQUFJLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztRQUN2QixPQUFPLEVBQUUsUUFBUSxFQUFFLGVBQWUsRUFBRSxLQUFLLEVBQUUsV0FBVyxFQUFFLEtBQUssRUFBRSxDQUFDO0lBQ2xFLENBQUM7SUFFRCxJQUFJLENBQUM7UUFDSCxRQUFRLENBQUMsWUFBWSxHQUFHLE1BQU0saUJBQWlCLEVBQUUsQ0FBQztRQUNsRCxNQUFNLGVBQWUsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUMsQ0FBQyxJQUFJLENBQy9ELENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxNQUFNLEtBQUssY0FBYyxDQUN0QyxDQUFDO1FBQ0YsT0FBTyxFQUFFLFFBQVEsRUFBRSxlQUFlLEVBQUUsV0FBVyxFQUFFLEtBQUssRUFBRSxDQUFDO0lBQzNELENBQUM7SUFBQyxNQUFNLENBQUM7UUFDUCxRQUFRLENBQUMsWUFBWSxHQUFHLEVBQUUsS0FBSyxFQUFFLGNBQWMsRUFBRSxDQUFDO1FBQ2xELE9BQU8sRUFBRSxRQUFRLEVBQUUsZUFBZSxFQUFFLElBQUksRUFBRSxXQUFXLEVBQUUsSUFBSSxFQUFFLENBQUM7SUFDaEUsQ0FBQztBQUNILENBQUM7QUFFRDs7Ozs7OztHQU9HO0FBQ0gsU0FBZ0IsaUJBQWlCLENBQUMsT0FBMkI7SUFDM0QsT0FBTyxLQUFLLEVBQUUsSUFBYSxFQUFFLEdBQWEsRUFBaUIsRUFBRTtRQUMzRCxNQUFNLEVBQUUsUUFBUSxFQUFFLEdBQUcsTUFBTSxtQkFBbUIsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN4RCxJQUFBLHNCQUFXLEVBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxRQUFRLENBQUMsQ0FBQztJQUNsQyxDQUFDLENBQUM7QUFDSixDQUFDO0FBRUQ7Ozs7Ozs7R0FPRztBQUNILFNBQWdCLG9CQUFvQixDQUFDLE9BQTJCO0lBQzlELE9BQU8sS0FBSyxFQUFFLElBQWEsRUFBRSxHQUFhLEVBQWlCLEVBQUU7UUFDM0QsTUFBTSxFQUFFLFFBQVEsRUFBRSxlQUFlLEVBQUUsR0FBRyxNQUFNLG1CQUFtQixDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3pFLElBQUksZUFBZSxFQUFFLENBQUM7WUFDcEIsUUFBUSxDQUFDLE1BQU0sR0FBRyxXQUFXLENBQUM7WUFDOUIsSUFBQSxvQkFBUyxFQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsbUJBQW1CLEVBQUUsU0FBUyxFQUFFLFFBQVEsQ0FBQyxDQUFDO1lBQzlELE9BQU87UUFDVCxDQUFDO1FBQ0QsSUFBQSxzQkFBVyxFQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFDbEMsQ0FBQyxDQUFDO0FBQ0osQ0FBQztBQUVEOzs7Ozs7Ozs7R0FTRztBQUNILFNBQWdCLGtCQUFrQixDQUFDLE9BQTJCO0lBQzVELE1BQU0sTUFBTSxHQUFHLElBQUEsZ0JBQU0sR0FBRSxDQUFDO0lBQ3hCLE1BQU0sQ0FBQyxHQUFHLENBQUMsU0FBUyxFQUFFLGlCQUFpQixDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUM7SUFDbEQsTUFBTSxDQUFDLEdBQUcsQ0FBQyxRQUFRLEVBQUUsb0JBQW9CLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQztJQUNwRCxPQUFPLE1BQU0sQ0FBQztBQUNoQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCB7IFJlcXVlc3QsIFJlc3BvbnNlLCBSb3V0ZXIgfSBmcm9tICdleHByZXNzJztcbmltcG9ydCB7IEhlYWx0aENoZWNrUmVzcG9uc2UgfSBmcm9tICcuLi90eXBlcy9jb21tb24nO1xuaW1wb3J0IHsgc2VuZFN1Y2Nlc3MsIHNlbmRFcnJvciB9IGZyb20gJy4uL3V0aWxzL3Jlc3BvbnNlJztcblxuY29uc3Qgc3RhcnRUaW1lID0gRGF0ZS5ub3coKTtcblxuLyoqXG4gKiBPcHRpb25zIGZvciBoZWFsdGggY2hlY2sgZW5kcG9pbnQuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSGVhbHRoQ2hlY2tPcHRpb25zIHtcbiAgLyoqIFNlcnZpY2UgbmFtZSAqL1xuICBzZXJ2aWNlTmFtZTogc3RyaW5nO1xuICAvKiogU2VydmljZSB2ZXJzaW9uIChvcHRpb25hbCkgKi9cbiAgdmVyc2lvbj86IHN0cmluZztcbiAgLyoqIEN1c3RvbSBoZWFsdGggY2hlY2sgZnVuY3Rpb24gZm9yIGRlcGVuZGVuY2llcyAqL1xuICBjaGVja0RlcGVuZGVuY2llcz86ICgpID0+IFByb21pc2U8UmVjb3JkPHN0cmluZywgJ2Nvbm5lY3RlZCcgfCAnZGlzY29ubmVjdGVkJyB8ICd1bmtub3duJz4+O1xufVxuXG4vKipcbiAqIEJ1aWxkIGEgSGVhbHRoQ2hlY2tSZXNwb25zZSArIGNvbGxlY3QgZGVwZW5kZW5jeSBzdGF0dXMuXG4gKiBTaGFyZWQgYmV0d2VlbiAvaGVhbHRoIChsaXZlbmVzcykgYW5kIC9yZWFkeSAocmVhZGluZXNzKS5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gYnVpbGRIZWFsdGhSZXNwb25zZShvcHRpb25zOiBIZWFsdGhDaGVja09wdGlvbnMpOiBQcm9taXNlPHtcbiAgcmVzcG9uc2U6IEhlYWx0aENoZWNrUmVzcG9uc2U7XG4gIGhhc0Rpc2Nvbm5lY3RlZDogYm9vbGVhbjtcbiAgY2hlY2tGYWlsZWQ6IGJvb2xlYW47XG59PiB7XG4gIGNvbnN0IHsgc2VydmljZU5hbWUsIHZlcnNpb24sIGNoZWNrRGVwZW5kZW5jaWVzIH0gPSBvcHRpb25zO1xuICBjb25zdCByZXNwb25zZTogSGVhbHRoQ2hlY2tSZXNwb25zZSA9IHtcbiAgICBzdGF0dXM6ICdoZWFsdGh5JyxcbiAgICBzZXJ2aWNlOiBzZXJ2aWNlTmFtZSxcbiAgICB0aW1lc3RhbXA6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSxcbiAgICB1cHRpbWU6IE1hdGguZmxvb3IoKERhdGUubm93KCkgLSBzdGFydFRpbWUpIC8gMTAwMCksXG4gIH07XG4gIGlmICh2ZXJzaW9uKSByZXNwb25zZS52ZXJzaW9uID0gdmVyc2lvbjtcblxuICBpZiAoIWNoZWNrRGVwZW5kZW5jaWVzKSB7XG4gICAgcmV0dXJuIHsgcmVzcG9uc2UsIGhhc0Rpc2Nvbm5lY3RlZDogZmFsc2UsIGNoZWNrRmFpbGVkOiBmYWxzZSB9O1xuICB9XG5cbiAgdHJ5IHtcbiAgICByZXNwb25zZS5kZXBlbmRlbmNpZXMgPSBhd2FpdCBjaGVja0RlcGVuZGVuY2llcygpO1xuICAgIGNvbnN0IGhhc0Rpc2Nvbm5lY3RlZCA9IE9iamVjdC52YWx1ZXMocmVzcG9uc2UuZGVwZW5kZW5jaWVzKS5zb21lKFxuICAgICAgKHN0YXR1cykgPT4gc3RhdHVzID09PSAnZGlzY29ubmVjdGVkJyxcbiAgICApO1xuICAgIHJldHVybiB7IHJlc3BvbnNlLCBoYXNEaXNjb25uZWN0ZWQsIGNoZWNrRmFpbGVkOiBmYWxzZSB9O1xuICB9IGNhdGNoIHtcbiAgICByZXNwb25zZS5kZXBlbmRlbmNpZXMgPSB7IGNoZWNrOiAnZGlzY29ubmVjdGVkJyB9O1xuICAgIHJldHVybiB7IHJlc3BvbnNlLCBoYXNEaXNjb25uZWN0ZWQ6IHRydWUsIGNoZWNrRmFpbGVkOiB0cnVlIH07XG4gIH1cbn1cblxuLyoqXG4gKiBMaXZlbmVzcyBoYW5kbGVyIOKAlCByZXR1cm5zIDIwMCBhcyBsb25nIGFzIHRoZSBwcm9jZXNzIGlzIGFsaXZlIGVub3VnaCB0b1xuICogcmVzcG9uZC4gRGVwZW5kZW5jeSBzdGF0dXMgaXMgcmVwb3J0ZWQgaW4gdGhlIGJvZHkgYXMgaW5mb3JtYXRpb25hbCwgYnV0IGFcbiAqIGRpc2Nvbm5lY3RlZCBkZXBlbmRlbmN5IGRvZXMgTk9UIGZhaWwgdGhlIHByb2JlICh1c2UgL3JlYWR5IGZvciB0aGF0KS5cbiAqXG4gKiBVc2UgYXMgdGhlIEt1YmVybmV0ZXMgLyBFQ1MgTElWRU5FU1MgcHJvYmUg4oCUIGl0IHNob3VsZCBvbmx5IGZhaWwgd2hlbiB0aGVcbiAqIHByb2Nlc3MgaXMgZ2VudWluZWx5IHN0dWNrIGFuZCBuZWVkcyB0byBiZSByZXN0YXJ0ZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVIZWFsdGhDaGVjayhvcHRpb25zOiBIZWFsdGhDaGVja09wdGlvbnMpIHtcbiAgcmV0dXJuIGFzeW5jIChfcmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgY29uc3QgeyByZXNwb25zZSB9ID0gYXdhaXQgYnVpbGRIZWFsdGhSZXNwb25zZShvcHRpb25zKTtcbiAgICBzZW5kU3VjY2VzcyhyZXMsIDIwMCwgcmVzcG9uc2UpO1xuICB9O1xufVxuXG4vKipcbiAqIFJlYWRpbmVzcyBoYW5kbGVyIOKAlCByZXR1cm5zIDUwMyBpZiBhbnkgZGVwZW5kZW5jeSBpcyBgZGlzY29ubmVjdGVkYCAob3JcbiAqIHRoZSBkZXBlbmRlbmN5IGNoZWNrIGl0c2VsZiB0aHJldykuIFJldHVybnMgMjAwIG9ubHkgd2hlbiB0aGUgc2VydmljZSBpc1xuICogZnVsbHkgcmVhZHkgdG8gc2VydmUgdHJhZmZpYy5cbiAqXG4gKiBVc2UgYXMgdGhlIEt1YmVybmV0ZXMgLyBFQ1MgUkVBRElORVNTIHByb2JlIOKAlCB3aGVuIHRoaXMgZmFpbHMsIHRoZVxuICogb3JjaGVzdHJhdG9yIHN0b3BzIHJvdXRpbmcgdHJhZmZpYyB0byB0aGlzIHBvZCBidXQgZG9lcyBOT1QgcmVzdGFydCBpdC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVJlYWRpbmVzc0NoZWNrKG9wdGlvbnM6IEhlYWx0aENoZWNrT3B0aW9ucykge1xuICByZXR1cm4gYXN5bmMgKF9yZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UpOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgICBjb25zdCB7IHJlc3BvbnNlLCBoYXNEaXNjb25uZWN0ZWQgfSA9IGF3YWl0IGJ1aWxkSGVhbHRoUmVzcG9uc2Uob3B0aW9ucyk7XG4gICAgaWYgKGhhc0Rpc2Nvbm5lY3RlZCkge1xuICAgICAgcmVzcG9uc2Uuc3RhdHVzID0gJ3VuaGVhbHRoeSc7XG4gICAgICBzZW5kRXJyb3IocmVzLCA1MDMsICdTZXJ2aWNlIG5vdCByZWFkeScsIHVuZGVmaW5lZCwgcmVzcG9uc2UpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBzZW5kU3VjY2VzcyhyZXMsIDIwMCwgcmVzcG9uc2UpO1xuICB9O1xufVxuXG4vKipcbiAqIENyZWF0ZSBhIGhlYWx0aC9yZWFkaW5lc3Mgcm91dGVyIGV4cG9zaW5nOlxuICogLSBHRVQgL2hlYWx0aCDigJQgbGl2ZW5lc3MgKGFsd2F5cyAyMDAgdW5sZXNzIHByb2Nlc3MgaXMgZGVhZClcbiAqIC0gR0VUIC9yZWFkeSAg4oCUIHJlYWRpbmVzcyAoNTAzIGlmIGRlcGVuZGVuY2llcyBhcmUgZGlzY29ubmVjdGVkKVxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBhcHAudXNlKGNyZWF0ZUhlYWx0aFJvdXRlcih7IHNlcnZpY2VOYW1lOiAncGx1Z2luJyB9KSk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUhlYWx0aFJvdXRlcihvcHRpb25zOiBIZWFsdGhDaGVja09wdGlvbnMpOiBSb3V0ZXIge1xuICBjb25zdCByb3V0ZXIgPSBSb3V0ZXIoKTtcbiAgcm91dGVyLmdldCgnL2hlYWx0aCcsIGNyZWF0ZUhlYWx0aENoZWNrKG9wdGlvbnMpKTtcbiAgcm91dGVyLmdldCgnL3JlYWR5JywgY3JlYXRlUmVhZGluZXNzQ2hlY2sob3B0aW9ucykpO1xuICByZXR1cm4gcm91dGVyO1xufVxuIl19
|
package/lib/types/common.d.ts
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Quota type identifiers.
|
|
3
|
+
*
|
|
4
|
+
* - `plugins` / `pipelines` — count of created entities
|
|
5
|
+
* - `apiCalls` — generic API call count (read-heavy paths)
|
|
6
|
+
* - `aiCalls` — AI provider invocations (counted separately because each call
|
|
7
|
+
* has external dollar cost; sized smaller than apiCalls per tier)
|
|
3
8
|
*/
|
|
4
|
-
export type QuotaType = 'plugins' | 'pipelines' | 'apiCalls';
|
|
9
|
+
export type QuotaType = 'plugins' | 'pipelines' | 'apiCalls' | 'aiCalls';
|
|
5
10
|
/**
|
|
6
11
|
* Valid quota type values.
|
|
7
12
|
*/
|
|
8
|
-
export declare const VALID_QUOTA_TYPES: readonly ["plugins", "pipelines", "apiCalls"];
|
|
13
|
+
export declare const VALID_QUOTA_TYPES: readonly ["plugins", "pipelines", "apiCalls", "aiCalls"];
|
|
9
14
|
/**
|
|
10
15
|
* Type guard to check if a value is a valid QuotaType.
|
|
11
16
|
*
|
package/lib/types/common.js
CHANGED
|
@@ -8,7 +8,7 @@ exports.validateQuotaType = validateQuotaType;
|
|
|
8
8
|
/**
|
|
9
9
|
* Valid quota type values.
|
|
10
10
|
*/
|
|
11
|
-
exports.VALID_QUOTA_TYPES = ['plugins', 'pipelines', 'apiCalls'];
|
|
11
|
+
exports.VALID_QUOTA_TYPES = ['plugins', 'pipelines', 'apiCalls', 'aiCalls'];
|
|
12
12
|
/**
|
|
13
13
|
* Type guard to check if a value is a valid QuotaType.
|
|
14
14
|
*
|
|
@@ -50,4 +50,4 @@ function validateQuotaType(value, fieldName = 'quotaType') {
|
|
|
50
50
|
}
|
|
51
51
|
return value;
|
|
52
52
|
}
|
|
53
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
53
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tbW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3R5cGVzL2NvbW1vbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsK0NBQStDO0FBQy9DLHNDQUFzQzs7O0FBOEJ0Qyw0Q0FFQztBQXFCRCw4Q0FPQztBQWhERDs7R0FFRztBQUNVLFFBQUEsaUJBQWlCLEdBQUcsQ0FBQyxTQUFTLEVBQUUsV0FBVyxFQUFFLFVBQVUsRUFBRSxTQUFTLENBQVUsQ0FBQztBQUUxRjs7Ozs7Ozs7Ozs7O0dBWUc7QUFDSCxTQUFnQixnQkFBZ0IsQ0FBQyxLQUFjO0lBQzdDLE9BQU8sT0FBTyxLQUFLLEtBQUssUUFBUSxJQUFJLHlCQUFpQixDQUFDLFFBQVEsQ0FBQyxLQUFrQixDQUFDLENBQUM7QUFDckYsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FrQkc7QUFDSCxTQUFnQixpQkFBaUIsQ0FBQyxLQUFjLEVBQUUsU0FBUyxHQUFHLFdBQVc7SUFDdkUsSUFBSSxDQUFDLGdCQUFnQixDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDN0IsTUFBTSxJQUFJLEtBQUssQ0FDYixXQUFXLFNBQVMsTUFBTSxLQUFLLHNCQUFzQix5QkFBaUIsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FDcEYsQ0FBQztJQUNKLENBQUM7SUFDRCxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuLyoqXG4gKiBRdW90YSB0eXBlIGlkZW50aWZpZXJzLlxuICpcbiAqIC0gYHBsdWdpbnNgIC8gYHBpcGVsaW5lc2Ag4oCUIGNvdW50IG9mIGNyZWF0ZWQgZW50aXRpZXNcbiAqIC0gYGFwaUNhbGxzYCDigJQgZ2VuZXJpYyBBUEkgY2FsbCBjb3VudCAocmVhZC1oZWF2eSBwYXRocylcbiAqIC0gYGFpQ2FsbHNgIOKAlCBBSSBwcm92aWRlciBpbnZvY2F0aW9ucyAoY291bnRlZCBzZXBhcmF0ZWx5IGJlY2F1c2UgZWFjaCBjYWxsXG4gKiAgIGhhcyBleHRlcm5hbCBkb2xsYXIgY29zdDsgc2l6ZWQgc21hbGxlciB0aGFuIGFwaUNhbGxzIHBlciB0aWVyKVxuICovXG5leHBvcnQgdHlwZSBRdW90YVR5cGUgPSAncGx1Z2lucycgfCAncGlwZWxpbmVzJyB8ICdhcGlDYWxscycgfCAnYWlDYWxscyc7XG5cbi8qKlxuICogVmFsaWQgcXVvdGEgdHlwZSB2YWx1ZXMuXG4gKi9cbmV4cG9ydCBjb25zdCBWQUxJRF9RVU9UQV9UWVBFUyA9IFsncGx1Z2lucycsICdwaXBlbGluZXMnLCAnYXBpQ2FsbHMnLCAnYWlDYWxscyddIGFzIGNvbnN0O1xuXG4vKipcbiAqIFR5cGUgZ3VhcmQgdG8gY2hlY2sgaWYgYSB2YWx1ZSBpcyBhIHZhbGlkIFF1b3RhVHlwZS5cbiAqXG4gKiBAcGFyYW0gdmFsdWUgLSBWYWx1ZSB0byBjaGVja1xuICogQHJldHVybnMgVHJ1ZSBpZiB2YWx1ZSBpcyBhIHZhbGlkIFF1b3RhVHlwZVxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBpZiAoaXNWYWxpZFF1b3RhVHlwZShyZXEuYm9keS5xdW90YVR5cGUpKSB7XG4gKiAgIC8vIHF1b3RhVHlwZSBpcyBndWFyYW50ZWVkIHRvIGJlIFF1b3RhVHlwZVxuICogfVxuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1ZhbGlkUXVvdGFUeXBlKHZhbHVlOiB1bmtub3duKTogdmFsdWUgaXMgUXVvdGFUeXBlIHtcbiAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgJiYgVkFMSURfUVVPVEFfVFlQRVMuaW5jbHVkZXModmFsdWUgYXMgUXVvdGFUeXBlKTtcbn1cblxuLyoqXG4gKiBWYWxpZGF0ZSBhbmQgYXNzZXJ0IHRoYXQgYSB2YWx1ZSBpcyBhIHZhbGlkIFF1b3RhVHlwZS5cbiAqIFRocm93cyBhbiBlcnJvciBpZiB2YWxpZGF0aW9uIGZhaWxzLlxuICpcbiAqIEBwYXJhbSB2YWx1ZSAtIFZhbHVlIHRvIHZhbGlkYXRlXG4gKiBAcGFyYW0gZmllbGROYW1lIC0gTmFtZSBvZiB0aGUgZmllbGQgYmVpbmcgdmFsaWRhdGVkIChmb3IgZXJyb3IgbWVzc2FnZXMpXG4gKiBAcmV0dXJucyBUaGUgdmFsaWRhdGVkIFF1b3RhVHlwZVxuICogQHRocm93cyBFcnJvciBpZiB2YWx1ZSBpcyBub3QgYSB2YWxpZCBRdW90YVR5cGVcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogdHJ5IHtcbiAqICAgY29uc3QgcXVvdGFUeXBlID0gdmFsaWRhdGVRdW90YVR5cGUocmVxLmJvZHkucXVvdGFUeXBlLCAncXVvdGFUeXBlJyk7XG4gKiAgIC8vIFVzZSBxdW90YVR5cGUgc2FmZWx5XG4gKiB9IGNhdGNoIChlcnIpIHtcbiAqICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIDQwMCwgZXJyLm1lc3NhZ2UpO1xuICogfVxuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB2YWxpZGF0ZVF1b3RhVHlwZSh2YWx1ZTogdW5rbm93biwgZmllbGROYW1lID0gJ3F1b3RhVHlwZScpOiBRdW90YVR5cGUge1xuICBpZiAoIWlzVmFsaWRRdW90YVR5cGUodmFsdWUpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYEludmFsaWQgJHtmaWVsZE5hbWV9OiBcIiR7dmFsdWV9XCIuIE11c3QgYmUgb25lIG9mOiAke1ZBTElEX1FVT1RBX1RZUEVTLmpvaW4oJywgJyl9YCxcbiAgICApO1xuICB9XG4gIHJldHVybiB2YWx1ZTtcbn1cblxuLyoqXG4gKiBSZXN1bHQgZnJvbSBxdW90YSBjaGVjayBvcGVyYXRpb24uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUXVvdGFDaGVja1Jlc3VsdCB7XG4gIC8qKiBXaGV0aGVyIHRoZSByZXF1ZXN0IGlzIGFsbG93ZWQgKi9cbiAgYWxsb3dlZDogYm9vbGVhbjtcbiAgLyoqIE1heGltdW0gcXVvdGEgbGltaXQgKC0xIGZvciB1bmxpbWl0ZWQpICovXG4gIGxpbWl0OiBudW1iZXI7XG4gIC8qKiBDdXJyZW50IHVzYWdlIGNvdW50ICovXG4gIHVzZWQ6IG51bWJlcjtcbiAgLyoqIFJlbWFpbmluZyBxdW90YSAoLTEgZm9yIHVubGltaXRlZCkgKi9cbiAgcmVtYWluaW5nOiBudW1iZXI7XG4gIC8qKiBJU08gdGltZXN0YW1wIHdoZW4gcXVvdGEgcmVzZXRzICovXG4gIHJlc2V0QXQ6IHN0cmluZztcbiAgLyoqIFdoZXRoZXIgcXVvdGEgaXMgdW5saW1pdGVkICovXG4gIHVubGltaXRlZDogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBRdW90YSBpbmZvcm1hdGlvbiBmb3IgZXJyb3IgcmVzcG9uc2VzLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFF1b3RhSW5mbyB7XG4gIHR5cGU6IFF1b3RhVHlwZTtcbiAgbGltaXQ6IG51bWJlcjtcbiAgdXNlZDogbnVtYmVyO1xuICByZW1haW5pbmc6IG51bWJlcjtcbn1cblxuLyoqXG4gKiBTdGFuZGFyZCBBUEkgc3VjY2VzcyByZXNwb25zZS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBBcGlTdWNjZXNzUmVzcG9uc2U8VCA9IHVua25vd24+IHtcbiAgc3VjY2VzczogdHJ1ZTtcbiAgc3RhdHVzQ29kZTogbnVtYmVyO1xuICBkYXRhPzogVDtcbiAgbWVzc2FnZT86IHN0cmluZztcbn1cblxuLyoqXG4gKiBTdGFuZGFyZCBBUEkgZXJyb3IgcmVzcG9uc2UuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQXBpRXJyb3JSZXNwb25zZSB7XG4gIHN1Y2Nlc3M6IGZhbHNlO1xuICBzdGF0dXNDb2RlOiBudW1iZXI7XG4gIG1lc3NhZ2U6IHN0cmluZztcbiAgY29kZT86IHN0cmluZztcbiAgZGV0YWlscz86IHVua25vd247XG4gIHF1b3RhPzogUXVvdGFJbmZvO1xufVxuXG4vKipcbiAqIENvbWJpbmVkIEFQSSByZXNwb25zZSB0eXBlLlxuICovXG5leHBvcnQgdHlwZSBBcGlSZXNwb25zZTxUID0gdW5rbm93bj4gPSBBcGlTdWNjZXNzUmVzcG9uc2U8VD4gfCBBcGlFcnJvclJlc3BvbnNlO1xuXG4vKipcbiAqIEpXVCBwYXlsb2FkIGZyb20gYWNjZXNzIHRva2Vucy5cbiAqXG4gKiBVc2VycyBjYW4gYmVsb25nIHRvIG11bHRpcGxlIG9yZ2FuaXphdGlvbnMuIFRoZSB0b2tlbiBpcyBzY29wZWQgdG8gb25lXG4gKiBhY3RpdmUgb3JnYW5pemF0aW9uIGF0IGEgdGltZS4gVGhlIGByb2xlYCBmaWVsZCBpcyB0aGUgdXNlcidzIHBlci1vcmdcbiAqIHJvbGUgaW4gdGhhdCBvcmdhbml6YXRpb24gKGZyb20gdGhlIFVzZXJPcmdhbml6YXRpb24ganVuY3Rpb24gY29sbGVjdGlvbiksXG4gKiBhbmQgYGlzQWRtaW5gIGlzIGRlcml2ZWQgYXMgYHJvbGUgPT09ICdhZG1pbicgfHwgcm9sZSA9PT0gJ293bmVyJ2AuXG4gKlxuICogVXNlIGBQT1NUIC9hdXRoL3N3aXRjaC1vcmdgIHRvIGNoYW5nZSB0aGUgYWN0aXZlIG9yZ2FuaXphdGlvbiwgd2hpY2hcbiAqIHJlLWlzc3VlcyB0b2tlbnMgd2l0aCB0aGUgbmV3IG9yZydzIHJvbGUgYW5kIGNvbnRleHQuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSnd0UGF5bG9hZCB7XG4gIC8qKiBVc2VyIElEIChzdWJqZWN0KSAqL1xuICBzdWI6IHN0cmluZztcbiAgLyoqIFVzZXJuYW1lICovXG4gIHVzZXJuYW1lOiBzdHJpbmc7XG4gIC8qKiBVc2VyIGVtYWlsICovXG4gIGVtYWlsOiBzdHJpbmc7XG4gIC8qKiBQZXItb3JnIHJvbGUgaW4gdGhlIGFjdGl2ZSBvcmdhbml6YXRpb24gKCdvd25lcicgfCAnYWRtaW4nIHwgJ21lbWJlcicpLiBOb3QgYSBnbG9iYWwgcm9sZS4gKi9cbiAgcm9sZTogJ293bmVyJyB8ICdhZG1pbicgfCAnbWVtYmVyJztcbiAgLyoqIERlcml2ZWQ6IHRydWUgd2hlbiByb2xlIGlzICdhZG1pbicgb3IgJ293bmVyJyBpbiB0aGUgYWN0aXZlIG9yZ2FuaXphdGlvbiAqL1xuICBpc0FkbWluPzogYm9vbGVhbjtcbiAgLyoqIE9yZ2FuaXphdGlvbidzIHF1b3RhIHRpZXIgKCdkZXZlbG9wZXInIHwgJ3BybycgfCAndW5saW1pdGVkJykgKi9cbiAgdGllcj86IHN0cmluZztcbiAgLyoqIFJlc29sdmVkIGZlYXR1cmUgZmxhZ3MgZm9yIHRoaXMgdXNlci9vcmcgKi9cbiAgZmVhdHVyZXM/OiBzdHJpbmdbXTtcbiAgLyoqIEFjdGl2ZSBvcmdhbml6YXRpb24gSUQgKGZyb20gVXNlck9yZ2FuaXphdGlvbiBtZW1iZXJzaGlwKSAqL1xuICBvcmdhbml6YXRpb25JZD86IHN0cmluZztcbiAgLyoqIEFjdGl2ZSBvcmdhbml6YXRpb24gbmFtZSAqL1xuICBvcmdhbml6YXRpb25OYW1lPzogc3RyaW5nO1xuICAvKiogVG9rZW4gdHlwZSAqL1xuICB0eXBlOiAnYWNjZXNzJyB8ICdyZWZyZXNoJztcbiAgLyoqIElzc3VlZCBhdCB0aW1lc3RhbXAgKi9cbiAgaWF0PzogbnVtYmVyO1xuICAvKiogRXhwaXJhdGlvbiB0aW1lc3RhbXAgKi9cbiAgZXhwPzogbnVtYmVyO1xufVxuXG4vKipcbiAqIEV4dGVuZGVkIEV4cHJlc3MgUmVxdWVzdCB3aXRoIHVzZXIgcHJvcGVydHkuXG4gKi9cbmRlY2xhcmUgZ2xvYmFsIHtcbiAgbmFtZXNwYWNlIEV4cHJlc3Mge1xuICAgIGludGVyZmFjZSBSZXF1ZXN0IHtcbiAgICAgIHVzZXI/OiBKd3RQYXlsb2FkO1xuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIFNlcnZpY2UgY29uZmlndXJhdGlvbiBmb3IgaW50ZXJuYWwgSFRUUCBjbGllbnQuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU2VydmljZUNvbmZpZyB7XG4gIC8qKiBTZXJ2aWNlIGhvc3RuYW1lICovXG4gIGhvc3Q6IHN0cmluZztcbiAgLyoqIFNlcnZpY2UgcG9ydCAqL1xuICBwb3J0OiBudW1iZXI7XG4gIC8qKiBSZXF1ZXN0IHRpbWVvdXQgaW4gbWlsbGlzZWNvbmRzICovXG4gIHRpbWVvdXQ/OiBudW1iZXI7XG59XG5cbi8qKlxuICogSGVhbHRoIGNoZWNrIHJlc3BvbnNlLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEhlYWx0aENoZWNrUmVzcG9uc2Uge1xuICBzdGF0dXM6ICdoZWFsdGh5JyB8ICd1bmhlYWx0aHknO1xuICBzZXJ2aWNlOiBzdHJpbmc7XG4gIHRpbWVzdGFtcDogc3RyaW5nO1xuICB1cHRpbWU6IG51bWJlcjtcbiAgdmVyc2lvbj86IHN0cmluZztcbiAgZGVwZW5kZW5jaWVzPzogUmVjb3JkPHN0cmluZywgJ2Nvbm5lY3RlZCcgfCAnZGlzY29ubmVjdGVkJyB8ICd1bmtub3duJz47XG59XG4iXX0=
|
package/lib/types/index.d.ts
CHANGED
package/lib/types/index.js
CHANGED
|
@@ -21,6 +21,5 @@ __exportStar(require("./common"), exports);
|
|
|
21
21
|
__exportStar(require("./pipeline"), exports);
|
|
22
22
|
__exportStar(require("./http"), exports);
|
|
23
23
|
__exportStar(require("./quota-tiers"), exports);
|
|
24
|
-
__exportStar(require("./billing"), exports);
|
|
25
24
|
__exportStar(require("./feature-flags"), exports);
|
|
26
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
25
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdHlwZXMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7Ozs7Ozs7Ozs7Ozs7Ozs7QUFFdEMsZ0RBQThCO0FBQzlCLDJDQUF5QjtBQUN6Qiw2Q0FBMkI7QUFDM0IseUNBQXVCO0FBQ3ZCLGdEQUE4QjtBQUM5QixrREFBZ0MiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuZXhwb3J0ICogZnJvbSAnLi9lcnJvci1jb2Rlcyc7XG5leHBvcnQgKiBmcm9tICcuL2NvbW1vbic7XG5leHBvcnQgKiBmcm9tICcuL3BpcGVsaW5lJztcbmV4cG9ydCAqIGZyb20gJy4vaHR0cCc7XG5leHBvcnQgKiBmcm9tICcuL3F1b3RhLXRpZXJzJztcbmV4cG9ydCAqIGZyb20gJy4vZmVhdHVyZS1mbGFncyc7XG4iXX0=
|
|
@@ -5,13 +5,20 @@ export interface QuotaTierLimits {
|
|
|
5
5
|
plugins: number;
|
|
6
6
|
pipelines: number;
|
|
7
7
|
apiCalls: number;
|
|
8
|
+
aiCalls: number;
|
|
8
9
|
}
|
|
9
10
|
/** Full preset for a single tier (label + limits). */
|
|
10
11
|
export interface QuotaTierPreset {
|
|
11
12
|
label: string;
|
|
12
13
|
limits: QuotaTierLimits;
|
|
13
14
|
}
|
|
14
|
-
/**
|
|
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
|
+
*/
|
|
15
22
|
export declare const QUOTA_TIERS: Record<QuotaTier, QuotaTierPreset>;
|
|
16
23
|
/** All valid tier names. */
|
|
17
24
|
export declare const VALID_TIERS: readonly QuotaTier[];
|
package/lib/types/quota-tiers.js
CHANGED
|
@@ -5,11 +5,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
5
5
|
exports.DEFAULT_TIER = exports.VALID_TIERS = exports.QUOTA_TIERS = void 0;
|
|
6
6
|
exports.isValidTier = isValidTier;
|
|
7
7
|
exports.getTierLimits = getTierLimits;
|
|
8
|
-
/**
|
|
8
|
+
/**
|
|
9
|
+
* Preset limits for each tier. -1 means unlimited.
|
|
10
|
+
*
|
|
11
|
+
* AI calls are sized much smaller than `apiCalls` because each call has
|
|
12
|
+
* external provider cost (~$0.01–$0.10/call). Developer tier allows light
|
|
13
|
+
* exploration (100/period); Pro lifts to 5000; Unlimited is uncapped.
|
|
14
|
+
*/
|
|
9
15
|
exports.QUOTA_TIERS = {
|
|
10
|
-
developer: { label: 'Developer', limits: { plugins: 100, pipelines: 10, apiCalls: -1 } },
|
|
11
|
-
pro: { label: 'Pro', limits: { plugins: 1000, pipelines: 100, apiCalls: -1 } },
|
|
12
|
-
unlimited: { label: 'Unlimited', limits: { plugins: -1, pipelines: -1, apiCalls: -1 } },
|
|
16
|
+
developer: { label: 'Developer', limits: { plugins: 100, pipelines: 10, apiCalls: -1, aiCalls: 100 } },
|
|
17
|
+
pro: { label: 'Pro', limits: { plugins: 1000, pipelines: 100, apiCalls: -1, aiCalls: 5000 } },
|
|
18
|
+
unlimited: { label: 'Unlimited', limits: { plugins: -1, pipelines: -1, apiCalls: -1, aiCalls: -1 } },
|
|
13
19
|
};
|
|
14
20
|
/** All valid tier names. */
|
|
15
21
|
exports.VALID_TIERS = Object.keys(exports.QUOTA_TIERS);
|
|
@@ -23,4 +29,4 @@ function isValidTier(value) {
|
|
|
23
29
|
function getTierLimits(tier) {
|
|
24
30
|
return isValidTier(tier) ? exports.QUOTA_TIERS[tier].limits : exports.QUOTA_TIERS.developer.limits;
|
|
25
31
|
}
|
|
26
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
32
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicXVvdGEtdGllcnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdHlwZXMvcXVvdGEtdGllcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7OztBQXVDdEMsa0NBRUM7QUFHRCxzQ0FFQztBQTNCRDs7Ozs7O0dBTUc7QUFDVSxRQUFBLFdBQVcsR0FBdUM7SUFDN0QsU0FBUyxFQUFFLEVBQUUsS0FBSyxFQUFFLFdBQVcsRUFBRSxNQUFNLEVBQUUsRUFBRSxPQUFPLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBRSxFQUFFLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQyxFQUFFLE9BQU8sRUFBRSxHQUFHLEVBQUUsRUFBRTtJQUN0RyxHQUFHLEVBQUUsRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLEdBQUcsRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxFQUFFO0lBQzdGLFNBQVMsRUFBRSxFQUFFLEtBQUssRUFBRSxXQUFXLEVBQUUsTUFBTSxFQUFFLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQyxFQUFFLFNBQVMsRUFBRSxDQUFDLENBQUMsRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQyxFQUFFLEVBQUU7Q0FDckcsQ0FBQztBQUVGLDRCQUE0QjtBQUNmLFFBQUEsV0FBVyxHQUF5QixNQUFNLENBQUMsSUFBSSxDQUFDLG1CQUFXLENBQWdCLENBQUM7QUFFekYsa0RBQWtEO0FBQ3JDLFFBQUEsWUFBWSxHQUFjLFdBQVcsQ0FBQztBQUVuRCxtREFBbUQ7QUFDbkQsU0FBZ0IsV0FBVyxDQUFDLEtBQWE7SUFDdkMsT0FBTyxLQUFLLElBQUksbUJBQVcsQ0FBQztBQUM5QixDQUFDO0FBRUQseUVBQXlFO0FBQ3pFLFNBQWdCLGFBQWEsQ0FBQyxJQUFZO0lBQ3hDLE9BQU8sV0FBVyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxtQkFBVyxDQUFDLElBQUksQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsbUJBQVcsQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDO0FBQ3JGLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuLyoqIEF2YWlsYWJsZSBxdW90YSB0aWVyIGlkZW50aWZpZXJzLiAqL1xuZXhwb3J0IHR5cGUgUXVvdGFUaWVyID0gJ2RldmVsb3BlcicgfCAncHJvJyB8ICd1bmxpbWl0ZWQnO1xuXG4vKiogTGltaXQgdmFsdWVzIGZvciBlYWNoIHF1b3RhIHR5cGUgd2l0aGluIGEgdGllci4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUXVvdGFUaWVyTGltaXRzIHtcbiAgcGx1Z2luczogbnVtYmVyO1xuICBwaXBlbGluZXM6IG51bWJlcjtcbiAgYXBpQ2FsbHM6IG51bWJlcjtcbiAgYWlDYWxsczogbnVtYmVyO1xufVxuXG4vKiogRnVsbCBwcmVzZXQgZm9yIGEgc2luZ2xlIHRpZXIgKGxhYmVsICsgbGltaXRzKS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUXVvdGFUaWVyUHJlc2V0IHtcbiAgbGFiZWw6IHN0cmluZztcbiAgbGltaXRzOiBRdW90YVRpZXJMaW1pdHM7XG59XG5cbi8qKlxuICogUHJlc2V0IGxpbWl0cyBmb3IgZWFjaCB0aWVyLiAtMSBtZWFucyB1bmxpbWl0ZWQuXG4gKlxuICogQUkgY2FsbHMgYXJlIHNpemVkIG11Y2ggc21hbGxlciB0aGFuIGBhcGlDYWxsc2AgYmVjYXVzZSBlYWNoIGNhbGwgaGFzXG4gKiBleHRlcm5hbCBwcm92aWRlciBjb3N0ICh+JDAuMDHigJMkMC4xMC9jYWxsKS4gRGV2ZWxvcGVyIHRpZXIgYWxsb3dzIGxpZ2h0XG4gKiBleHBsb3JhdGlvbiAoMTAwL3BlcmlvZCk7IFBybyBsaWZ0cyB0byA1MDAwOyBVbmxpbWl0ZWQgaXMgdW5jYXBwZWQuXG4gKi9cbmV4cG9ydCBjb25zdCBRVU9UQV9USUVSUzogUmVjb3JkPFF1b3RhVGllciwgUXVvdGFUaWVyUHJlc2V0PiA9IHtcbiAgZGV2ZWxvcGVyOiB7IGxhYmVsOiAnRGV2ZWxvcGVyJywgbGltaXRzOiB7IHBsdWdpbnM6IDEwMCwgcGlwZWxpbmVzOiAxMCwgYXBpQ2FsbHM6IC0xLCBhaUNhbGxzOiAxMDAgfSB9LFxuICBwcm86IHsgbGFiZWw6ICdQcm8nLCBsaW1pdHM6IHsgcGx1Z2luczogMTAwMCwgcGlwZWxpbmVzOiAxMDAsIGFwaUNhbGxzOiAtMSwgYWlDYWxsczogNTAwMCB9IH0sXG4gIHVubGltaXRlZDogeyBsYWJlbDogJ1VubGltaXRlZCcsIGxpbWl0czogeyBwbHVnaW5zOiAtMSwgcGlwZWxpbmVzOiAtMSwgYXBpQ2FsbHM6IC0xLCBhaUNhbGxzOiAtMSB9IH0sXG59O1xuXG4vKiogQWxsIHZhbGlkIHRpZXIgbmFtZXMuICovXG5leHBvcnQgY29uc3QgVkFMSURfVElFUlM6IHJlYWRvbmx5IFF1b3RhVGllcltdID0gT2JqZWN0LmtleXMoUVVPVEFfVElFUlMpIGFzIFF1b3RhVGllcltdO1xuXG4vKiogRGVmYXVsdCB0aWVyIGFzc2lnbmVkIHRvIG5ldyBvcmdhbml6YXRpb25zLiAqL1xuZXhwb3J0IGNvbnN0IERFRkFVTFRfVElFUjogUXVvdGFUaWVyID0gJ2RldmVsb3Blcic7XG5cbi8qKiBDaGVjayB3aGV0aGVyIGEgc3RyaW5nIGlzIGEgdmFsaWQgUXVvdGFUaWVyLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzVmFsaWRUaWVyKHZhbHVlOiBzdHJpbmcpOiB2YWx1ZSBpcyBRdW90YVRpZXIge1xuICByZXR1cm4gdmFsdWUgaW4gUVVPVEFfVElFUlM7XG59XG5cbi8qKiBHZXQgdGhlIGRlZmF1bHQgbGltaXRzIGZvciBhIGdpdmVuIHRpZXIgKGZhbGxzIGJhY2sgdG8gZGV2ZWxvcGVyKS4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRUaWVyTGltaXRzKHRpZXI6IHN0cmluZyk6IFF1b3RhVGllckxpbWl0cyB7XG4gIHJldHVybiBpc1ZhbGlkVGllcih0aWVyKSA/IFFVT1RBX1RJRVJTW3RpZXJdLmxpbWl0cyA6IFFVT1RBX1RJRVJTLmRldmVsb3Blci5saW1pdHM7XG59XG4iXX0=
|
package/package.json
CHANGED
package/lib/types/billing.d.ts
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import type { QuotaTier } from './quota-tiers';
|
|
2
|
-
/** Billing interval for subscriptions. */
|
|
3
|
-
export type BillingInterval = 'monthly' | 'annual';
|
|
4
|
-
/** Subscription lifecycle status. */
|
|
5
|
-
export type SubscriptionStatus = 'active' | 'canceled' | 'past_due' | 'trialing' | 'incomplete';
|
|
6
|
-
/** Payment transaction status. */
|
|
7
|
-
export type PaymentStatus = 'succeeded' | 'pending' | 'failed' | 'refunded';
|
|
8
|
-
/** Billing event types for audit logging. */
|
|
9
|
-
export type BillingEventType = 'subscription_created' | 'subscription_updated' | 'subscription_canceled' | 'subscription_reactivated' | 'plan_changed' | 'interval_changed' | 'payment_succeeded' | 'payment_failed';
|
|
10
|
-
/** Price definition for a plan (in cents). */
|
|
11
|
-
export interface PlanPrices {
|
|
12
|
-
monthly: number;
|
|
13
|
-
annual: number;
|
|
14
|
-
}
|
|
15
|
-
/** Plan definition returned by the billing API. */
|
|
16
|
-
export interface PlanDefinition {
|
|
17
|
-
id: string;
|
|
18
|
-
name: string;
|
|
19
|
-
description: string;
|
|
20
|
-
tier: QuotaTier;
|
|
21
|
-
prices: PlanPrices;
|
|
22
|
-
features: string[];
|
|
23
|
-
isDefault: boolean;
|
|
24
|
-
sortOrder: number;
|
|
25
|
-
}
|
|
26
|
-
/** Subscription info returned by the billing API. */
|
|
27
|
-
export interface SubscriptionInfo {
|
|
28
|
-
id: string;
|
|
29
|
-
orgId: string;
|
|
30
|
-
planId: string;
|
|
31
|
-
status: SubscriptionStatus;
|
|
32
|
-
interval: BillingInterval;
|
|
33
|
-
currentPeriodStart: string;
|
|
34
|
-
currentPeriodEnd: string;
|
|
35
|
-
cancelAtPeriodEnd: boolean;
|
|
36
|
-
createdAt: string;
|
|
37
|
-
updatedAt: string;
|
|
38
|
-
}
|
|
39
|
-
/** Billing event info returned by the admin API. */
|
|
40
|
-
export interface BillingEventInfo {
|
|
41
|
-
id: string;
|
|
42
|
-
orgId: string;
|
|
43
|
-
subscriptionId?: string;
|
|
44
|
-
type: BillingEventType;
|
|
45
|
-
details: Record<string, unknown>;
|
|
46
|
-
createdAt: string;
|
|
47
|
-
}
|
package/lib/types/billing.js
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// Copyright 2026 Pipeline Builder Contributors
|
|
3
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmlsbGluZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90eXBlcy9iaWxsaW5nLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCB0eXBlIHsgUXVvdGFUaWVyIH0gZnJvbSAnLi9xdW90YS10aWVycyc7XG5cbi8qKiBCaWxsaW5nIGludGVydmFsIGZvciBzdWJzY3JpcHRpb25zLiAqL1xuZXhwb3J0IHR5cGUgQmlsbGluZ0ludGVydmFsID0gJ21vbnRobHknIHwgJ2FubnVhbCc7XG5cbi8qKiBTdWJzY3JpcHRpb24gbGlmZWN5Y2xlIHN0YXR1cy4gKi9cbmV4cG9ydCB0eXBlIFN1YnNjcmlwdGlvblN0YXR1cyA9ICdhY3RpdmUnIHwgJ2NhbmNlbGVkJyB8ICdwYXN0X2R1ZScgfCAndHJpYWxpbmcnIHwgJ2luY29tcGxldGUnO1xuXG4vKiogUGF5bWVudCB0cmFuc2FjdGlvbiBzdGF0dXMuICovXG5leHBvcnQgdHlwZSBQYXltZW50U3RhdHVzID0gJ3N1Y2NlZWRlZCcgfCAncGVuZGluZycgfCAnZmFpbGVkJyB8ICdyZWZ1bmRlZCc7XG5cbi8qKiBCaWxsaW5nIGV2ZW50IHR5cGVzIGZvciBhdWRpdCBsb2dnaW5nLiAqL1xuZXhwb3J0IHR5cGUgQmlsbGluZ0V2ZW50VHlwZSA9XG4gIHwgJ3N1YnNjcmlwdGlvbl9jcmVhdGVkJ1xuICB8ICdzdWJzY3JpcHRpb25fdXBkYXRlZCdcbiAgfCAnc3Vic2NyaXB0aW9uX2NhbmNlbGVkJ1xuICB8ICdzdWJzY3JpcHRpb25fcmVhY3RpdmF0ZWQnXG4gIHwgJ3BsYW5fY2hhbmdlZCdcbiAgfCAnaW50ZXJ2YWxfY2hhbmdlZCdcbiAgfCAncGF5bWVudF9zdWNjZWVkZWQnXG4gIHwgJ3BheW1lbnRfZmFpbGVkJztcblxuLyoqIFByaWNlIGRlZmluaXRpb24gZm9yIGEgcGxhbiAoaW4gY2VudHMpLiAqL1xuZXhwb3J0IGludGVyZmFjZSBQbGFuUHJpY2VzIHtcbiAgbW9udGhseTogbnVtYmVyO1xuICBhbm51YWw6IG51bWJlcjtcbn1cblxuLyoqIFBsYW4gZGVmaW5pdGlvbiByZXR1cm5lZCBieSB0aGUgYmlsbGluZyBBUEkuICovXG5leHBvcnQgaW50ZXJmYWNlIFBsYW5EZWZpbml0aW9uIHtcbiAgaWQ6IHN0cmluZztcbiAgbmFtZTogc3RyaW5nO1xuICBkZXNjcmlwdGlvbjogc3RyaW5nO1xuICB0aWVyOiBRdW90YVRpZXI7XG4gIHByaWNlczogUGxhblByaWNlcztcbiAgZmVhdHVyZXM6IHN0cmluZ1tdO1xuICBpc0RlZmF1bHQ6IGJvb2xlYW47XG4gIHNvcnRPcmRlcjogbnVtYmVyO1xufVxuXG4vKiogU3Vic2NyaXB0aW9uIGluZm8gcmV0dXJuZWQgYnkgdGhlIGJpbGxpbmcgQVBJLiAqL1xuZXhwb3J0IGludGVyZmFjZSBTdWJzY3JpcHRpb25JbmZvIHtcbiAgaWQ6IHN0cmluZztcbiAgb3JnSWQ6IHN0cmluZztcbiAgcGxhbklkOiBzdHJpbmc7XG4gIHN0YXR1czogU3Vic2NyaXB0aW9uU3RhdHVzO1xuICBpbnRlcnZhbDogQmlsbGluZ0ludGVydmFsO1xuICBjdXJyZW50UGVyaW9kU3RhcnQ6IHN0cmluZztcbiAgY3VycmVudFBlcmlvZEVuZDogc3RyaW5nO1xuICBjYW5jZWxBdFBlcmlvZEVuZDogYm9vbGVhbjtcbiAgY3JlYXRlZEF0OiBzdHJpbmc7XG4gIHVwZGF0ZWRBdDogc3RyaW5nO1xufVxuXG4vKiogQmlsbGluZyBldmVudCBpbmZvIHJldHVybmVkIGJ5IHRoZSBhZG1pbiBBUEkuICovXG5leHBvcnQgaW50ZXJmYWNlIEJpbGxpbmdFdmVudEluZm8ge1xuICBpZDogc3RyaW5nO1xuICBvcmdJZDogc3RyaW5nO1xuICBzdWJzY3JpcHRpb25JZD86IHN0cmluZztcbiAgdHlwZTogQmlsbGluZ0V2ZW50VHlwZTtcbiAgZGV0YWlsczogUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gIGNyZWF0ZWRBdDogc3RyaW5nO1xufVxuIl19
|