@pipeline-builder/api-core 4.1.13 → 4.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. package/README.md +3 -2
  2. package/lib/constants/index.d.ts +0 -1
  3. package/lib/constants/index.js +1 -2
  4. package/lib/errors/app-errors.d.ts +8 -3
  5. package/lib/errors/app-errors.js +10 -5
  6. package/lib/helpers/access-helpers.d.ts +4 -6
  7. package/lib/helpers/access-helpers.js +6 -8
  8. package/lib/helpers/index.d.ts +3 -3
  9. package/lib/helpers/index.js +4 -4
  10. package/lib/helpers/org-hierarchy-http.d.ts +11 -10
  11. package/lib/helpers/org-hierarchy-http.js +24 -35
  12. package/lib/helpers/org-hierarchy.d.ts +37 -3
  13. package/lib/helpers/org-hierarchy.js +45 -4
  14. package/lib/helpers/restore-helpers.d.ts +44 -24
  15. package/lib/helpers/restore-helpers.js +41 -52
  16. package/lib/helpers/sse-helpers.d.ts +29 -7
  17. package/lib/helpers/sse-helpers.js +36 -9
  18. package/lib/index.d.ts +16 -14
  19. package/lib/index.js +17 -15
  20. package/lib/middleware/assurance.d.ts +116 -0
  21. package/lib/middleware/assurance.js +176 -0
  22. package/lib/middleware/auth.d.ts +5 -427
  23. package/lib/middleware/auth.js +36 -789
  24. package/lib/middleware/ecosystem-guard.d.ts +47 -0
  25. package/lib/middleware/ecosystem-guard.js +60 -0
  26. package/lib/middleware/index.d.ts +11 -4
  27. package/lib/middleware/index.js +12 -5
  28. package/lib/middleware/jwt-verify.d.ts +52 -0
  29. package/lib/middleware/jwt-verify.js +105 -0
  30. package/lib/middleware/permission-gates.d.ts +133 -0
  31. package/lib/middleware/permission-gates.js +260 -0
  32. package/lib/middleware/revocation.d.ts +96 -0
  33. package/lib/middleware/revocation.js +162 -0
  34. package/lib/middleware/route-table.d.ts +11 -0
  35. package/lib/middleware/route-table.js +4 -1
  36. package/lib/middleware/service-tokens.d.ts +83 -0
  37. package/lib/middleware/service-tokens.js +158 -0
  38. package/lib/middleware/step-up.d.ts +2 -2
  39. package/lib/middleware/step-up.js +8 -7
  40. package/lib/middleware/system-org.d.ts +20 -0
  41. package/lib/middleware/system-org.js +25 -0
  42. package/lib/openapi/routes/plugin-routes.js +133 -10
  43. package/lib/openapi/schema-registry.js +2 -5
  44. package/lib/routes/index.d.ts +1 -1
  45. package/lib/routes/index.js +2 -2
  46. package/lib/services/api-key-exchange.js +7 -5
  47. package/lib/services/audit-spool.d.ts +34 -10
  48. package/lib/services/audit-spool.js +75 -34
  49. package/lib/services/cache-service.d.ts +7 -0
  50. package/lib/services/cache-service.js +1 -1
  51. package/lib/services/circuit-breaker.d.ts +14 -1
  52. package/lib/services/circuit-breaker.js +36 -10
  53. package/lib/services/compliance-client.d.ts +10 -2
  54. package/lib/services/compliance-client.js +17 -10
  55. package/lib/services/compliance-event-subscriber.js +6 -6
  56. package/lib/services/durable-event-bus.js +8 -11
  57. package/lib/services/ecosystem-notify-client.d.ts +32 -0
  58. package/lib/services/ecosystem-notify-client.js +71 -0
  59. package/lib/services/env-redis.d.ts +4 -1
  60. package/lib/services/env-redis.js +32 -3
  61. package/lib/services/http-client.d.ts +19 -0
  62. package/lib/services/http-client.js +98 -19
  63. package/lib/services/index.d.ts +25 -24
  64. package/lib/services/index.js +25 -22
  65. package/lib/services/jwks-cache.js +5 -4
  66. package/lib/services/leader-lock.d.ts +22 -5
  67. package/lib/services/leader-lock.js +61 -6
  68. package/lib/services/quota.d.ts +9 -4
  69. package/lib/services/quota.js +34 -40
  70. package/lib/services/remote-audit-client.d.ts +28 -32
  71. package/lib/services/remote-audit-client.js +166 -49
  72. package/lib/services/retry-forever.js +5 -11
  73. package/lib/services/retry-strategy.d.ts +1 -1
  74. package/lib/services/retry-strategy.js +5 -4
  75. package/lib/services/scheduler.d.ts +8 -3
  76. package/lib/services/scheduler.js +17 -5
  77. package/lib/services/service-boot.d.ts +14 -13
  78. package/lib/services/service-boot.js +18 -15
  79. package/lib/services/service-keys.d.ts +1 -1
  80. package/lib/services/service-keys.js +12 -18
  81. package/lib/services/sse-ticket-store.d.ts +9 -1
  82. package/lib/services/sse-ticket-store.js +24 -9
  83. package/lib/services/system-notification.d.ts +27 -0
  84. package/lib/services/system-notification.js +50 -0
  85. package/lib/services/token-revocation.d.ts +50 -1
  86. package/lib/services/token-revocation.js +103 -3
  87. package/lib/types/audit-events.d.ts +6 -6
  88. package/lib/types/audit-events.js +1 -1
  89. package/lib/types/common.d.ts +32 -13
  90. package/lib/types/common.js +2 -1
  91. package/lib/types/ecosystem-notifications.d.ts +142 -0
  92. package/lib/types/ecosystem-notifications.js +210 -0
  93. package/lib/types/ecosystem.d.ts +77 -0
  94. package/lib/types/ecosystem.js +119 -0
  95. package/lib/types/error-codes.d.ts +81 -0
  96. package/lib/types/error-codes.js +108 -1
  97. package/lib/types/feature-flags.d.ts +21 -1
  98. package/lib/types/feature-flags.js +36 -2
  99. package/lib/types/index.d.ts +14 -9
  100. package/lib/types/index.js +15 -10
  101. package/lib/types/permissions.d.ts +46 -8
  102. package/lib/types/permissions.js +75 -12
  103. package/lib/types/plugin-catalog.d.ts +35 -0
  104. package/lib/types/plugin-catalog.js +39 -0
  105. package/lib/types/plugin-health.d.ts +102 -0
  106. package/lib/types/plugin-health.js +184 -0
  107. package/lib/types/quota-tiers.d.ts +15 -0
  108. package/lib/types/quota-tiers.js +23 -3
  109. package/lib/types/wire-vocabulary.d.ts +102 -0
  110. package/lib/types/wire-vocabulary.js +94 -0
  111. package/lib/utils/alias-resolver.js +2 -2
  112. package/lib/utils/audit.d.ts +5 -2
  113. package/lib/utils/audit.js +6 -3
  114. package/lib/utils/compliance-attributes.js +3 -4
  115. package/lib/utils/concurrency.d.ts +7 -0
  116. package/lib/utils/concurrency.js +13 -1
  117. package/lib/utils/env.d.ts +3 -4
  118. package/lib/utils/env.js +4 -5
  119. package/lib/utils/identity.d.ts +13 -4
  120. package/lib/utils/identity.js +18 -10
  121. package/lib/utils/index.d.ts +13 -10
  122. package/lib/utils/index.js +13 -10
  123. package/lib/utils/jwk.d.ts +4 -0
  124. package/lib/utils/jwk.js +13 -1
  125. package/lib/utils/logger.d.ts +1 -1
  126. package/lib/utils/logger.js +1 -1
  127. package/lib/utils/object.d.ts +11 -0
  128. package/lib/utils/object.js +24 -1
  129. package/lib/utils/params.d.ts +8 -22
  130. package/lib/utils/params.js +15 -43
  131. package/lib/utils/plugin-compliance.d.ts +98 -0
  132. package/lib/utils/plugin-compliance.js +78 -0
  133. package/lib/utils/proof-of-work.d.ts +69 -0
  134. package/lib/utils/proof-of-work.js +139 -0
  135. package/lib/utils/response.d.ts +16 -6
  136. package/lib/utils/response.js +18 -15
  137. package/lib/utils/retention.d.ts +17 -0
  138. package/lib/utils/retention.js +30 -0
  139. package/lib/utils/secret-encryption.d.ts +7 -7
  140. package/lib/utils/secret-encryption.js +9 -10
  141. package/lib/utils/secret-rotation.js +2 -2
  142. package/lib/utils/sensitive-patterns.js +4 -5
  143. package/lib/utils/service-registry.d.ts +15 -0
  144. package/lib/utils/service-registry.js +24 -0
  145. package/lib/utils/ssrf.d.ts +11 -2
  146. package/lib/utils/ssrf.js +112 -33
  147. package/lib/validation/ai-schemas.js +3 -2
  148. package/lib/validation/common-schemas.d.ts +0 -9
  149. package/lib/validation/common-schemas.js +1 -7
  150. package/lib/validation/dockerfile-static.d.ts +26 -0
  151. package/lib/validation/dockerfile-static.js +210 -0
  152. package/lib/validation/index.d.ts +13 -4
  153. package/lib/validation/index.js +14 -5
  154. package/lib/validation/message-schemas.js +6 -4
  155. package/lib/validation/pipeline-schemas.d.ts +8 -2
  156. package/lib/validation/pipeline-schemas.js +30 -4
  157. package/lib/validation/plugin-base-images.d.ts +20 -0
  158. package/lib/validation/plugin-base-images.js +17 -0
  159. package/lib/validation/plugin-catalog-detect.d.ts +86 -0
  160. package/lib/validation/plugin-catalog-detect.js +237 -0
  161. package/lib/validation/plugin-catalog-metadata.d.ts +141 -0
  162. package/lib/validation/plugin-catalog-metadata.js +162 -0
  163. package/lib/validation/plugin-heuristics.d.ts +41 -0
  164. package/lib/validation/plugin-heuristics.js +211 -0
  165. package/lib/validation/plugin-lint.d.ts +18 -0
  166. package/lib/validation/plugin-lint.js +136 -0
  167. package/lib/validation/plugin-name-confusable.d.ts +15 -0
  168. package/lib/validation/plugin-name-confusable.js +81 -0
  169. package/lib/validation/plugin-schemas.d.ts +40 -26
  170. package/lib/validation/plugin-schemas.js +26 -23
  171. package/lib/validation/plugin-spec-schema.d.ts +112 -0
  172. package/lib/validation/plugin-spec-schema.js +163 -0
  173. package/lib/validation/plugin-template-contract.d.ts +64 -0
  174. package/lib/validation/plugin-template-contract.js +113 -0
  175. package/package.json +69 -4
  176. package/lib/testing/mock-api-core.d.ts +0 -150
  177. package/lib/testing/mock-api-core.js +0 -246
  178. package/lib/testing/mock-drizzle.d.ts +0 -6
  179. package/lib/testing/mock-drizzle.js +0 -57
  180. package/lib/testing/route-coverage.d.ts +0 -64
  181. package/lib/testing/route-coverage.js +0 -183
  182. package/lib/testing/service-tokens.d.ts +0 -66
  183. package/lib/testing/service-tokens.js +0 -137
  184. package/lib/testing/tier-mock.d.ts +0 -44
  185. package/lib/testing/tier-mock.js +0 -65
  186. package/lib/testing/user-tokens.d.ts +0 -75
  187. package/lib/testing/user-tokens.js +0 -115
@@ -1,150 +0,0 @@
1
- /**
2
- * Shared `@pipeline-builder/api-core` mock factory for ESM suites.
3
- *
4
- * WHY: every project kept its own `test/helpers/mock-api-core.ts` — twelve forks
5
- * of the same ~150-line file, ranging from 23 to 61 overridden keys against an
6
- * api-core barrel exporting ~357 symbols. Each fork re-declared the same logger
7
- * stub, the same `ErrorCode` proxy, the same error classes and the same
8
- * service-gate re-implementations, and each drifted independently.
9
- *
10
- * THE FIX: the shared parts live here, once. A project's helper keeps ONLY the
11
- * defaults that are genuinely project-specific (its tier fixtures, its compliance
12
- * client, its response helpers) and layers them on top:
13
- *
14
- * const actualApiCore = jest.requireActual('@pipeline-builder/api-core') as Record<string, unknown>;
15
- * export function apiCoreMock(overrides: Record<string, unknown> = {}) {
16
- * return baseApiCoreMock(actualApiCore, { ...projectDefaults, ...overrides });
17
- * }
18
- *
19
- * Both this module and the per-project helpers start from `requireActual`, so an
20
- * export ADDED to api-core is inherited automatically and can never again break a
21
- * suite with "does not provide an export named X".
22
- *
23
- * WHY IT LIVES IN api-core: the deep path
24
- * `@pipeline-builder/api-core/lib/testing/mock-api-core.js` is a different
25
- * specifier from the `@pipeline-builder/api-core` barrel, so a suite's module
26
- * mock does NOT intercept it — the factory can therefore read the real module
27
- * without recursing into its own mock. Same trick as `tier-mock.ts`.
28
- */
29
- import { jest } from '@jest/globals';
30
- /** Minimal Express-ish shapes the gate/response stubs below touch. */
31
- type MockRes = {
32
- status: (n: number) => {
33
- json: (b: unknown) => unknown;
34
- };
35
- };
36
- type Next = () => void;
37
- /** A bare `jest.fn()`, named so the emitted `.d.ts` stays portable (TS2883). */
38
- type MockFn = ReturnType<typeof jest.fn>;
39
- /** The winston double every suite asserts on: four spies, nothing else. */
40
- export interface MockLogger {
41
- info: MockFn;
42
- warn: MockFn;
43
- error: MockFn;
44
- debug: MockFn;
45
- }
46
- /** The 4-method winston stub every suite repeats; a fresh set of spies per call. */
47
- export declare const loggerMock: () => MockLogger;
48
- /** Mirrors api-core: `ErrorCode.ANY_CODE` resolves to the string `'ANY_CODE'`. */
49
- export declare const mockErrorCode: Record<string, string>;
50
- /** No-op guard: the default mock covers route wiring, not the permission gate. */
51
- export declare const passThroughMiddleware: (_req: unknown, _res: unknown, next: Next) => void;
52
- /** Mirrors api-core's `AppError` base (typed HTTP error: statusCode + code). */
53
- export declare class MockAppError extends Error {
54
- readonly statusCode: number;
55
- readonly code: string;
56
- constructor(statusCode: number, code: string, message?: string);
57
- }
58
- /** Mirrors api-core's NotFoundError (404 / NOT_FOUND). */
59
- export declare class MockNotFoundError extends MockAppError {
60
- constructor(message?: string);
61
- }
62
- /** Mirrors api-core's ConflictError (409 / CONFLICT). */
63
- export declare class MockConflictError extends MockAppError {
64
- constructor(message?: string);
65
- }
66
- /** Mirrors api-core's ForbiddenError (403 / INSUFFICIENT_PERMISSIONS). */
67
- export declare class MockForbiddenError extends MockAppError {
68
- constructor(message?: string);
69
- }
70
- /** Mirrors api-core's ValidationError (400 / VALIDATION_ERROR). */
71
- export declare class MockValidationError extends MockAppError {
72
- constructor(message?: string);
73
- }
74
- /**
75
- * Capability-aware stand-in for api-core's `requirePermission` /
76
- * `requireAllPermissions` gate factories. Mirrors the real gate's decision (minus
77
- * the denial-audit side effect): superadmin passes, otherwise the caller must
78
- * hold the permission(s); a miss is a 403 with the real message shape.
79
- *
80
- * `onAnonymous` picks what happens when there is no `req.user` at all: `'pass'`
81
- * (suites with no auth layer mounted) or `'401'` (suites that drive the gate).
82
- * `shape` picks the denial envelope the project's suites assert on.
83
- */
84
- export declare function mockPermissionGate(options?: {
85
- mode?: 'some' | 'every';
86
- allowService?: boolean;
87
- onAnonymous?: 'pass' | '401';
88
- shape?: 'error' | 'message';
89
- }): (...permissions: string[]) => (req: {
90
- user?: {
91
- isSuperAdmin?: boolean;
92
- permissions?: string[];
93
- sub?: string;
94
- };
95
- }, res: MockRes, next: Next) => unknown;
96
- /**
97
- * The defaults shared by every service / package mock: the logger stub, the
98
- * pagination constants, the inert scheduler / leader-lock / redis-audit wiring a
99
- * boot module links at load, and the error + cache shapes. A project layers its
100
- * own defaults on top by passing them in `overrides`.
101
- */
102
- export declare function serviceApiCoreDefaults(): Record<string, unknown>;
103
- /**
104
- * The audit / security wiring a service's boot module (`src/index.ts`,
105
- * `src/services/audit.ts`) links at load time. Inert by default: nothing asserts
106
- * on the registration, and pulling the real graph in would drag Redis + HTTP
107
- * clients into every route suite.
108
- */
109
- export declare function serviceAuditDefaults(): Record<string, unknown>;
110
- /**
111
- * Build an api-core mock namespace: REAL api-core, then the shared service
112
- * defaults, then `overrides` (a project's own defaults merged with the suite's).
113
- *
114
- * `actualApiCore` is supplied by the CALLER (`jest.requireActual(...)` at the top
115
- * of the project's `test/helpers/mock-api-core.ts`) rather than resolved here.
116
- * That is deliberate: `requireActual` on an ESM barrel only succeeds at a moment
117
- * when nothing else is mid-`import()` of it, and the project helper — a static
118
- * import of the test file, evaluated before any `await import(SUT)` — is the one
119
- * point where that always holds. Resolving it from inside this module (which
120
- * lives in the api-core package itself) races that import in some suites.
121
- */
122
- export declare function baseApiCoreMock(actualApiCore: Record<string, unknown>, overrides?: Record<string, unknown>): Record<string, unknown>;
123
- /**
124
- * Build an api-core mock namespace with NO service defaults — REAL api-core plus
125
- * the logger stub and `ErrorCode` proxy only. Platform uses this: it deliberately
126
- * keeps api-core's real pagination/report constants and supplies its own
127
- * (large) identity/tier/permission default set.
128
- */
129
- export declare function primitiveApiCoreMock(actualApiCore: Record<string, unknown>, overrides?: Record<string, unknown>): Record<string, unknown>;
130
- /**
131
- * Mirror api-core's `requireInternalService({ callers })`: refuse any user token,
132
- * then refuse a service whose name is not in the route's caller list. Resolved
133
- * from the MERGED mock (rather than inherited from `requireActual`) so it uses
134
- * the suite's `isServicePrincipal` / `serviceNameOf` / `sendError`, which the real
135
- * one closes over and would write past.
136
- */
137
- export declare function withInternalServiceGate(mock: Record<string, unknown>, overrides: Record<string, unknown>): Record<string, unknown>;
138
- /**
139
- * Mirror api-core's `requireServicePrincipal`: reject a non-service caller with a
140
- * 403 INSUFFICIENT_PERMISSIONS (an authorization refusal, not a 400), resolving
141
- * `isServicePrincipal` / `sendError` from the merged mock.
142
- */
143
- export declare function withServicePrincipalGate(mock: Record<string, unknown>, overrides: Record<string, unknown>): Record<string, unknown>;
144
- /**
145
- * `sendBadRequest` delegating to the (possibly-overridden) `sendError`, mirroring
146
- * the real implementation — so a suite spying on `sendError` also observes the
147
- * 400s routed through `sendBadRequest`.
148
- */
149
- export declare function withDelegatingSendBadRequest(mock: Record<string, unknown>, overrides: Record<string, unknown>): Record<string, unknown>;
150
- export {};
@@ -1,246 +0,0 @@
1
- // Copyright 2026 Pipeline Builder Contributors
2
- // SPDX-License-Identifier: Apache-2.0
3
- /**
4
- * Shared `@pipeline-builder/api-core` mock factory for ESM suites.
5
- *
6
- * WHY: every project kept its own `test/helpers/mock-api-core.ts` — twelve forks
7
- * of the same ~150-line file, ranging from 23 to 61 overridden keys against an
8
- * api-core barrel exporting ~357 symbols. Each fork re-declared the same logger
9
- * stub, the same `ErrorCode` proxy, the same error classes and the same
10
- * service-gate re-implementations, and each drifted independently.
11
- *
12
- * THE FIX: the shared parts live here, once. A project's helper keeps ONLY the
13
- * defaults that are genuinely project-specific (its tier fixtures, its compliance
14
- * client, its response helpers) and layers them on top:
15
- *
16
- * const actualApiCore = jest.requireActual('@pipeline-builder/api-core') as Record<string, unknown>;
17
- * export function apiCoreMock(overrides: Record<string, unknown> = {}) {
18
- * return baseApiCoreMock(actualApiCore, { ...projectDefaults, ...overrides });
19
- * }
20
- *
21
- * Both this module and the per-project helpers start from `requireActual`, so an
22
- * export ADDED to api-core is inherited automatically and can never again break a
23
- * suite with "does not provide an export named X".
24
- *
25
- * WHY IT LIVES IN api-core: the deep path
26
- * `@pipeline-builder/api-core/lib/testing/mock-api-core.js` is a different
27
- * specifier from the `@pipeline-builder/api-core` barrel, so a suite's module
28
- * mock does NOT intercept it — the factory can therefore read the real module
29
- * without recursing into its own mock. Same trick as `tier-mock.ts`.
30
- */
31
- import { jest } from '@jest/globals';
32
- /** The 4-method winston stub every suite repeats; a fresh set of spies per call. */
33
- export const loggerMock = () => ({
34
- info: jest.fn(),
35
- warn: jest.fn(),
36
- error: jest.fn(),
37
- debug: jest.fn(),
38
- });
39
- /** Mirrors api-core: `ErrorCode.ANY_CODE` resolves to the string `'ANY_CODE'`. */
40
- export const mockErrorCode = new Proxy({}, { get: (_t, key) => key });
41
- /** No-op guard: the default mock covers route wiring, not the permission gate. */
42
- export const passThroughMiddleware = (_req, _res, next) => next();
43
- /** Mirrors api-core's `AppError` base (typed HTTP error: statusCode + code). */
44
- export class MockAppError extends Error {
45
- statusCode;
46
- code;
47
- constructor(statusCode, code, message) {
48
- super(message);
49
- this.statusCode = statusCode;
50
- this.code = code;
51
- this.name = 'AppError';
52
- }
53
- }
54
- /** Mirrors api-core's NotFoundError (404 / NOT_FOUND). */
55
- export class MockNotFoundError extends MockAppError {
56
- constructor(message) {
57
- super(404, 'NOT_FOUND', message);
58
- this.name = 'NotFoundError';
59
- }
60
- }
61
- /** Mirrors api-core's ConflictError (409 / CONFLICT). */
62
- export class MockConflictError extends MockAppError {
63
- constructor(message) {
64
- super(409, 'CONFLICT', message);
65
- this.name = 'ConflictError';
66
- }
67
- }
68
- /** Mirrors api-core's ForbiddenError (403 / INSUFFICIENT_PERMISSIONS). */
69
- export class MockForbiddenError extends MockAppError {
70
- constructor(message) {
71
- super(403, 'INSUFFICIENT_PERMISSIONS', message);
72
- this.name = 'ForbiddenError';
73
- }
74
- }
75
- /** Mirrors api-core's ValidationError (400 / VALIDATION_ERROR). */
76
- export class MockValidationError extends MockAppError {
77
- constructor(message) {
78
- super(400, 'VALIDATION_ERROR', message);
79
- this.name = 'ValidationError';
80
- }
81
- }
82
- /**
83
- * Capability-aware stand-in for api-core's `requirePermission` /
84
- * `requireAllPermissions` gate factories. Mirrors the real gate's decision (minus
85
- * the denial-audit side effect): superadmin passes, otherwise the caller must
86
- * hold the permission(s); a miss is a 403 with the real message shape.
87
- *
88
- * `onAnonymous` picks what happens when there is no `req.user` at all: `'pass'`
89
- * (suites with no auth layer mounted) or `'401'` (suites that drive the gate).
90
- * `shape` picks the denial envelope the project's suites assert on.
91
- */
92
- export function mockPermissionGate(options = {}) {
93
- const { mode = 'some', allowService = false, onAnonymous = 'pass', shape = 'message' } = options;
94
- const joiner = mode === 'some' ? ' or ' : ' and ';
95
- const deny = (msg) => (shape === 'error' ? { error: msg } : { success: false, message: msg });
96
- return (...permissions) => {
97
- const gate = (req, res, next) => {
98
- const user = req?.user;
99
- if (!user)
100
- return onAnonymous === 'pass' ? next() : res.status(401).json({ error: 'Authentication required' });
101
- if (allowService && typeof user.sub === 'string' && user.sub.startsWith('service:'))
102
- return next();
103
- if (user.isSuperAdmin === true)
104
- return next();
105
- const held = Array.isArray(user.permissions) ? user.permissions : [];
106
- const ok = mode === 'some' ? permissions.some((p) => held.includes(p)) : permissions.every((p) => held.includes(p));
107
- if (ok)
108
- return next();
109
- return res.status(403).json(deny(`Missing required permission: ${permissions.join(joiner)}`));
110
- };
111
- // Tags let a wiring suite locate the gate layer in a router stack and assert
112
- // which flavour was mounted.
113
- gate.__permission = permissions.join(joiner);
114
- gate.__allowService = allowService;
115
- return gate;
116
- };
117
- }
118
- /**
119
- * The defaults shared by every service / package mock: the logger stub, the
120
- * pagination constants, the inert scheduler / leader-lock / redis-audit wiring a
121
- * boot module links at load, and the error + cache shapes. A project layers its
122
- * own defaults on top by passing them in `overrides`.
123
- */
124
- export function serviceApiCoreDefaults() {
125
- return {
126
- createLogger: loggerMock,
127
- MAX_PAGE_LIMIT: 1000,
128
- DEFAULT_PAGE_LIMIT: 100,
129
- closeLeaderLock: async () => undefined,
130
- loadAndRestore: async () => null,
131
- REPORT_INTERVALS: ['day', 'week', 'month'],
132
- scrubAwsIdentifiersFromString: (s) => s,
133
- scrubAwsIdentifiers: (v) => v,
134
- createScheduler: () => ({ start: () => undefined, stop: () => undefined }),
135
- createEnvRedisLock: () => null,
136
- requireStepUp: (_req, _res, next) => next(),
137
- SYSTEM_ORG_ID: '000000000000000000000001',
138
- ComputeType: { SMALL: 'SMALL', MEDIUM: 'MEDIUM', LARGE: 'LARGE', X2_LARGE: 'X2_LARGE' },
139
- PluginType: { CODE_BUILD_STEP: 'CodeBuildStep', SHELL_STEP: 'ShellStep', MANUAL_APPROVAL_STEP: 'ManualApprovalStep' },
140
- ErrorCode: mockErrorCode,
141
- errorMessage: (e) => (e instanceof Error ? e.message : String(e)),
142
- NotFoundError: MockNotFoundError,
143
- createCacheService: () => ({
144
- getOrSet: (_key, factory) => factory(),
145
- invalidatePattern: () => Promise.resolve(0),
146
- }),
147
- };
148
- }
149
- /**
150
- * The audit / security wiring a service's boot module (`src/index.ts`,
151
- * `src/services/audit.ts`) links at load time. Inert by default: nothing asserts
152
- * on the registration, and pulling the real graph in would drag Redis + HTTP
153
- * clients into every route suite.
154
- */
155
- export function serviceAuditDefaults() {
156
- return {
157
- createRemoteAuditClient: () => ({ record: jest.fn() }),
158
- createEnvRedisAuditSpool: () => null,
159
- createServiceAuditClient: () => ({ emit: jest.fn(), client: { record: jest.fn() } }),
160
- createRemoteAuditAccessor: () => ({ getAuditClient: () => ({ record: jest.fn() }), emit: jest.fn() }),
161
- setAuthzDenialAuditor: () => { },
162
- wireAuthzDenialAuditor: () => { },
163
- wireServiceSecurity: () => { },
164
- setTokenRevocationStore: () => { },
165
- createRedisTokenRevocationStore: () => ({ getCurrentVersion: async () => null }),
166
- createEnvRedisTokenRevocationStore: () => ({ getCurrentVersion: async () => null }),
167
- };
168
- }
169
- /**
170
- * Build an api-core mock namespace: REAL api-core, then the shared service
171
- * defaults, then `overrides` (a project's own defaults merged with the suite's).
172
- *
173
- * `actualApiCore` is supplied by the CALLER (`jest.requireActual(...)` at the top
174
- * of the project's `test/helpers/mock-api-core.ts`) rather than resolved here.
175
- * That is deliberate: `requireActual` on an ESM barrel only succeeds at a moment
176
- * when nothing else is mid-`import()` of it, and the project helper — a static
177
- * import of the test file, evaluated before any `await import(SUT)` — is the one
178
- * point where that always holds. Resolving it from inside this module (which
179
- * lives in the api-core package itself) races that import in some suites.
180
- */
181
- export function baseApiCoreMock(actualApiCore, overrides = {}) {
182
- return { ...actualApiCore, ...serviceApiCoreDefaults(), ...overrides };
183
- }
184
- /**
185
- * Build an api-core mock namespace with NO service defaults — REAL api-core plus
186
- * the logger stub and `ErrorCode` proxy only. Platform uses this: it deliberately
187
- * keeps api-core's real pagination/report constants and supplies its own
188
- * (large) identity/tier/permission default set.
189
- */
190
- export function primitiveApiCoreMock(actualApiCore, overrides = {}) {
191
- return { ...actualApiCore, createLogger: loggerMock, ErrorCode: mockErrorCode, ...overrides };
192
- }
193
- /**
194
- * Mirror api-core's `requireInternalService({ callers })`: refuse any user token,
195
- * then refuse a service whose name is not in the route's caller list. Resolved
196
- * from the MERGED mock (rather than inherited from `requireActual`) so it uses
197
- * the suite's `isServicePrincipal` / `serviceNameOf` / `sendError`, which the real
198
- * one closes over and would write past.
199
- */
200
- export function withInternalServiceGate(mock, overrides) {
201
- if (overrides.requireInternalService !== undefined)
202
- return mock;
203
- mock.requireInternalService = ({ callers }) => (req, res, next) => {
204
- const isSvc = mock.isServicePrincipal;
205
- const nameOf = mock.serviceNameOf;
206
- const caller = nameOf?.(req.user);
207
- if (isSvc?.(req) && caller && callers.includes(caller)) {
208
- next();
209
- return;
210
- }
211
- const sendError = mock.sendError;
212
- sendError(res, 403, 'Internal service calls only', 'INSUFFICIENT_PERMISSIONS');
213
- };
214
- return mock;
215
- }
216
- /**
217
- * Mirror api-core's `requireServicePrincipal`: reject a non-service caller with a
218
- * 403 INSUFFICIENT_PERMISSIONS (an authorization refusal, not a 400), resolving
219
- * `isServicePrincipal` / `sendError` from the merged mock.
220
- */
221
- export function withServicePrincipalGate(mock, overrides) {
222
- if (overrides.requireServicePrincipal !== undefined)
223
- return mock;
224
- mock.requireServicePrincipal = (req, res, next) => {
225
- const isSvc = mock.isServicePrincipal;
226
- if (isSvc?.(req)) {
227
- next();
228
- return;
229
- }
230
- const sendError = mock.sendError;
231
- sendError(res, 403, 'Internal service calls only', 'INSUFFICIENT_PERMISSIONS');
232
- };
233
- return mock;
234
- }
235
- /**
236
- * `sendBadRequest` delegating to the (possibly-overridden) `sendError`, mirroring
237
- * the real implementation — so a suite spying on `sendError` also observes the
238
- * 400s routed through `sendBadRequest`.
239
- */
240
- export function withDelegatingSendBadRequest(mock, overrides) {
241
- if ('sendBadRequest' in overrides)
242
- return mock;
243
- mock.sendBadRequest = (res, message, code) => mock.sendError(res, 400, message, code ?? mockErrorCode.VALIDATION_ERROR);
244
- return mock;
245
- }
246
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9jay1hcGktY29yZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90ZXN0aW5nL21vY2stYXBpLWNvcmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0Qzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBMkJHO0FBRUgsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLGVBQWUsQ0FBQztBQWlCckMsb0ZBQW9GO0FBQ3BGLE1BQU0sQ0FBQyxNQUFNLFVBQVUsR0FBRyxHQUFlLEVBQUUsQ0FBQyxDQUFDO0lBQzNDLElBQUksRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFO0lBQ2YsSUFBSSxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUU7SUFDZixLQUFLLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRTtJQUNoQixLQUFLLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRTtDQUNqQixDQUFDLENBQUM7QUFFSCxrRkFBa0Y7QUFDbEYsTUFBTSxDQUFDLE1BQU0sYUFBYSxHQUFHLElBQUksS0FBSyxDQUFDLEVBQUUsRUFBRSxFQUFFLEdBQUcsRUFBRSxDQUFDLEVBQUUsRUFBRSxHQUFHLEVBQUUsRUFBRSxDQUFDLEdBQUcsRUFBRSxDQUEyQixDQUFDO0FBRWhHLGtGQUFrRjtBQUNsRixNQUFNLENBQUMsTUFBTSxxQkFBcUIsR0FBRyxDQUFDLElBQWEsRUFBRSxJQUFhLEVBQUUsSUFBVSxFQUFRLEVBQUUsQ0FBQyxJQUFJLEVBQUUsQ0FBQztBQUVoRyxnRkFBZ0Y7QUFDaEYsTUFBTSxPQUFPLFlBQWEsU0FBUSxLQUFLO0lBQ1QsVUFBVTtJQUEwQixJQUFJO0lBQXBFLFlBQTRCLFVBQWtCLEVBQWtCLElBQVksRUFBRSxPQUFnQjtRQUM1RixLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7MEJBRFcsVUFBVTtvQkFBMEIsSUFBSTtRQUVsRSxJQUFJLENBQUMsSUFBSSxHQUFHLFVBQVUsQ0FBQztJQUN6QixD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QUUsR0FBWSxFQUFFLElBQVUsRUFBRSxFQUFFO1FBQ3hFLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxrQkFBMkQsQ0FBQztRQUMvRSxJQUFJLEtBQUssRUFBRSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDakIsSUFBSSxFQUFFLENBQUM7WUFDUCxPQUFPO1FBQ1QsQ0FBQztRQUNELE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxTQUFxRSxDQUFDO1FBQzdGLFNBQVMsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLDZCQUE2QixFQUFFLDBCQUEwQixDQUFDLENBQUM7SUFDakYsQ0FBQyxDQUFDO0lBQ0YsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSw0QkFBNEIsQ0FBQyxJQUE2QixFQUFFLFNBQWtDO0lBQzVHLElBQUksZ0JBQWdCLElBQUksU0FBUztRQUFFLE9BQU8sSUFBSSxDQUFDO0lBQy9DLElBQUksQ0FBQyxjQUFjLEdBQUcsQ0FBQyxHQUFZLEVBQUUsT0FBZSxFQUFFLElBQWEsRUFBRSxFQUFFLENBQ3BFLElBQUksQ0FBQyxTQUF1RSxDQUMzRSxHQUFHLEVBQUUsR0FBRyxFQUFFLE9BQU8sRUFBRSxJQUFJLElBQUksYUFBYSxDQUFDLGdCQUFnQixDQUFDLENBQUM7SUFDL0QsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbi8qKlxuICogU2hhcmVkIGBAcGlwZWxpbmUtYnVpbGRlci9hcGktY29yZWAgbW9jayBmYWN0b3J5IGZvciBFU00gc3VpdGVzLlxuICpcbiAqIFdIWTogZXZlcnkgcHJvamVjdCBrZXB0IGl0cyBvd24gYHRlc3QvaGVscGVycy9tb2NrLWFwaS1jb3JlLnRzYCDigJQgdHdlbHZlIGZvcmtzXG4gKiBvZiB0aGUgc2FtZSB+MTUwLWxpbmUgZmlsZSwgcmFuZ2luZyBmcm9tIDIzIHRvIDYxIG92ZXJyaWRkZW4ga2V5cyBhZ2FpbnN0IGFuXG4gKiBhcGktY29yZSBiYXJyZWwgZXhwb3J0aW5nIH4zNTcgc3ltYm9scy4gRWFjaCBmb3JrIHJlLWRlY2xhcmVkIHRoZSBzYW1lIGxvZ2dlclxuICogc3R1YiwgdGhlIHNhbWUgYEVycm9yQ29kZWAgcHJveHksIHRoZSBzYW1lIGVycm9yIGNsYXNzZXMgYW5kIHRoZSBzYW1lXG4gKiBzZXJ2aWNlLWdhdGUgcmUtaW1wbGVtZW50YXRpb25zLCBhbmQgZWFjaCBkcmlmdGVkIGluZGVwZW5kZW50bHkuXG4gKlxuICogVEhFIEZJWDogdGhlIHNoYXJlZCBwYXJ0cyBsaXZlIGhlcmUsIG9uY2UuIEEgcHJvamVjdCdzIGhlbHBlciBrZWVwcyBPTkxZIHRoZVxuICogZGVmYXVsdHMgdGhhdCBhcmUgZ2VudWluZWx5IHByb2plY3Qtc3BlY2lmaWMgKGl0cyB0aWVyIGZpeHR1cmVzLCBpdHMgY29tcGxpYW5jZVxuICogY2xpZW50LCBpdHMgcmVzcG9uc2UgaGVscGVycykgYW5kIGxheWVycyB0aGVtIG9uIHRvcDpcbiAqXG4gKiAgIGNvbnN0IGFjdHVhbEFwaUNvcmUgPSBqZXN0LnJlcXVpcmVBY3R1YWwoJ0BwaXBlbGluZS1idWlsZGVyL2FwaS1jb3JlJykgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gKiAgIGV4cG9ydCBmdW5jdGlvbiBhcGlDb3JlTW9jayhvdmVycmlkZXM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0ge30pIHtcbiAqICAgICByZXR1cm4gYmFzZUFwaUNvcmVNb2NrKGFjdHVhbEFwaUNvcmUsIHsgLi4ucHJvamVjdERlZmF1bHRzLCAuLi5vdmVycmlkZXMgfSk7XG4gKiAgIH1cbiAqXG4gKiBCb3RoIHRoaXMgbW9kdWxlIGFuZCB0aGUgcGVyLXByb2plY3QgaGVscGVycyBzdGFydCBmcm9tIGByZXF1aXJlQWN0dWFsYCwgc28gYW5cbiAqIGV4cG9ydCBBRERFRCB0byBhcGktY29yZSBpcyBpbmhlcml0ZWQgYXV0b21hdGljYWxseSBhbmQgY2FuIG5ldmVyIGFnYWluIGJyZWFrIGFcbiAqIHN1aXRlIHdpdGggXCJkb2VzIG5vdCBwcm92aWRlIGFuIGV4cG9ydCBuYW1lZCBYXCIuXG4gKlxuICogV0hZIElUIExJVkVTIElOIGFwaS1jb3JlOiB0aGUgZGVlcCBwYXRoXG4gKiBgQHBpcGVsaW5lLWJ1aWxkZXIvYXBpLWNvcmUvbGliL3Rlc3RpbmcvbW9jay1hcGktY29yZS5qc2AgaXMgYSBkaWZmZXJlbnRcbiAqIHNwZWNpZmllciBmcm9tIHRoZSBgQHBpcGVsaW5lLWJ1aWxkZXIvYXBpLWNvcmVgIGJhcnJlbCwgc28gYSBzdWl0ZSdzIG1vZHVsZVxuICogbW9jayBkb2VzIE5PVCBpbnRlcmNlcHQgaXQg4oCUIHRoZSBmYWN0b3J5IGNhbiB0aGVyZWZvcmUgcmVhZCB0aGUgcmVhbCBtb2R1bGVcbiAqIHdpdGhvdXQgcmVjdXJzaW5nIGludG8gaXRzIG93biBtb2NrLiBTYW1lIHRyaWNrIGFzIGB0aWVyLW1vY2sudHNgLlxuICovXG5cbmltcG9ydCB7IGplc3QgfSBmcm9tICdAamVzdC9nbG9iYWxzJztcblxuLyoqIE1pbmltYWwgRXhwcmVzcy1pc2ggc2hhcGVzIHRoZSBnYXRlL3Jlc3BvbnNlIHN0dWJzIGJlbG93IHRvdWNoLiAqL1xudHlwZSBNb2NrUmVzID0geyBzdGF0dXM6IChuOiBudW1iZXIpID0+IHsganNvbjogKGI6IHVua25vd24pID0+IHVua25vd24gfSB9O1xudHlwZSBOZXh0ID0gKCkgPT4gdm9pZDtcblxuLyoqIEEgYmFyZSBgamVzdC5mbigpYCwgbmFtZWQgc28gdGhlIGVtaXR0ZWQgYC5kLnRzYCBzdGF5cyBwb3J0YWJsZSAoVFMyODgzKS4gKi9cbnR5cGUgTW9ja0ZuID0gUmV0dXJuVHlwZTx0eXBlb2YgamVzdC5mbj47XG5cbi8qKiBUaGUgd2luc3RvbiBkb3VibGUgZXZlcnkgc3VpdGUgYXNzZXJ0cyBvbjogZm91ciBzcGllcywgbm90aGluZyBlbHNlLiAqL1xuZXhwb3J0IGludGVyZmFjZSBNb2NrTG9nZ2VyIHtcbiAgaW5mbzogTW9ja0ZuO1xuICB3YXJuOiBNb2NrRm47XG4gIGVycm9yOiBNb2NrRm47XG4gIGRlYnVnOiBNb2NrRm47XG59XG5cbi8qKiBUaGUgNC1tZXRob2Qgd2luc3RvbiBzdHViIGV2ZXJ5IHN1aXRlIHJlcGVhdHM7IGEgZnJlc2ggc2V0IG9mIHNwaWVzIHBlciBjYWxsLiAqL1xuZXhwb3J0IGNvbnN0IGxvZ2dlck1vY2sgPSAoKTogTW9ja0xvZ2dlciA9PiAoe1xuICBpbmZvOiBqZXN0LmZuKCksXG4gIHdhcm46IGplc3QuZm4oKSxcbiAgZXJyb3I6IGplc3QuZm4oKSxcbiAgZGVidWc6IGplc3QuZm4oKSxcbn0pO1xuXG4vKiogTWlycm9ycyBhcGktY29yZTogYEVycm9yQ29kZS5BTllfQ09ERWAgcmVzb2x2ZXMgdG8gdGhlIHN0cmluZyBgJ0FOWV9DT0RFJ2AuICovXG5leHBvcnQgY29uc3QgbW9ja0Vycm9yQ29kZSA9IG5ldyBQcm94eSh7fSwgeyBnZXQ6IChfdCwga2V5KSA9PiBrZXkgfSkgYXMgUmVjb3JkPHN0cmluZywgc3RyaW5nPjtcblxuLyoqIE5vLW9wIGd1YXJkOiB0aGUgZGVmYXVsdCBtb2NrIGNvdmVycyByb3V0ZSB3aXJpbmcsIG5vdCB0aGUgcGVybWlzc2lvbiBnYXRlLiAqL1xuZXhwb3J0IGNvbnN0IHBhc3NUaHJvdWdoTWlkZGxld2FyZSA9IChfcmVxOiB1bmtub3duLCBfcmVzOiB1bmtub3duLCBuZXh0OiBOZXh0KTogdm9pZCA9PiBuZXh0KCk7XG5cbi8qKiBNaXJyb3JzIGFwaS1jb3JlJ3MgYEFwcEVycm9yYCBiYXNlICh0eXBlZCBIVFRQIGVycm9yOiBzdGF0dXNDb2RlICsgY29kZSkuICovXG5leHBvcnQgY2xhc3MgTW9ja0FwcEVycm9yIGV4dGVuZHMgRXJyb3Ige1xuICBjb25zdHJ1Y3RvcihwdWJsaWMgcmVhZG9ubHkgc3RhdHVzQ29kZTogbnVtYmVyLCBwdWJsaWMgcmVhZG9ubHkgY29kZTogc3RyaW5nLCBtZXNzYWdlPzogc3RyaW5nKSB7XG4gICAgc3VwZXIobWVzc2FnZSk7XG4gICAgdGhpcy5uYW1lID0gJ0FwcEVycm9yJztcbiAgfVxufVxuXG4vKiogTWlycm9ycyBhcGktY29yZSdzIE5vdEZvdW5kRXJyb3IgKDQwNCAvIE5PVF9GT1VORCkuICovXG5leHBvcnQgY2xhc3MgTW9ja05vdEZvdW5kRXJyb3IgZXh0ZW5kcyBNb2NrQXBwRXJyb3Ige1xuICBjb25zdHJ1Y3RvcihtZXNzYWdlPzogc3RyaW5nKSB7XG4gICAgc3VwZXIoNDA0LCAnTk9UX0ZPVU5EJywgbWVzc2FnZSk7XG4gICAgdGhpcy5uYW1lID0gJ05vdEZvdW5kRXJyb3InO1xuICB9XG59XG5cbi8qKiBNaXJyb3JzIGFwaS1jb3JlJ3MgQ29uZmxpY3RFcnJvciAoNDA5IC8gQ09ORkxJQ1QpLiAqL1xuZXhwb3J0IGNsYXNzIE1vY2tDb25mbGljdEVycm9yIGV4dGVuZHMgTW9ja0FwcEVycm9yIHtcbiAgY29uc3RydWN0b3IobWVzc2FnZT86IHN0cmluZykge1xuICAgIHN1cGVyKDQwOSwgJ0NPTkZMSUNUJywgbWVzc2FnZSk7XG4gICAgdGhpcy5uYW1lID0gJ0NvbmZsaWN0RXJyb3InO1xuICB9XG59XG5cbi8qKiBNaXJyb3JzIGFwaS1jb3JlJ3MgRm9yYmlkZGVuRXJyb3IgKDQwMyAvIElOU1VGRklDSUVOVF9QRVJNSVNTSU9OUykuICovXG5leHBvcnQgY2xhc3MgTW9ja0ZvcmJpZGRlbkVycm9yIGV4dGVuZHMgTW9ja0FwcEVycm9yIHtcbiAgY29uc3RydWN0b3IobWVzc2FnZT86IHN0cmluZykge1xuICAgIHN1cGVyKDQwMywgJ0lOU1VGRklDSUVOVF9QRVJNSVNTSU9OUycsIG1lc3NhZ2UpO1xuICAgIHRoaXMubmFtZSA9ICdGb3JiaWRkZW5FcnJvcic7XG4gIH1cbn1cblxuLyoqIE1pcnJvcnMgYXBpLWNvcmUncyBWYWxpZGF0aW9uRXJyb3IgKDQwMCAvIFZBTElEQVRJT05fRVJST1IpLiAqL1xuZXhwb3J0IGNsYXNzIE1vY2tWYWxpZGF0aW9uRXJyb3IgZXh0ZW5kcyBNb2NrQXBwRXJyb3Ige1xuICBjb25zdHJ1Y3RvcihtZXNzYWdlPzogc3RyaW5nKSB7XG4gICAgc3VwZXIoNDAwLCAnVkFMSURBVElPTl9FUlJPUicsIG1lc3NhZ2UpO1xuICAgIHRoaXMubmFtZSA9ICdWYWxpZGF0aW9uRXJyb3InO1xuICB9XG59XG5cbi8qKlxuICogQ2FwYWJpbGl0eS1hd2FyZSBzdGFuZC1pbiBmb3IgYXBpLWNvcmUncyBgcmVxdWlyZVBlcm1pc3Npb25gIC9cbiAqIGByZXF1aXJlQWxsUGVybWlzc2lvbnNgIGdhdGUgZmFjdG9yaWVzLiBNaXJyb3JzIHRoZSByZWFsIGdhdGUncyBkZWNpc2lvbiAobWludXNcbiAqIHRoZSBkZW5pYWwtYXVkaXQgc2lkZSBlZmZlY3QpOiBzdXBlcmFkbWluIHBhc3Nlcywgb3RoZXJ3aXNlIHRoZSBjYWxsZXIgbXVzdFxuICogaG9sZCB0aGUgcGVybWlzc2lvbihzKTsgYSBtaXNzIGlzIGEgNDAzIHdpdGggdGhlIHJlYWwgbWVzc2FnZSBzaGFwZS5cbiAqXG4gKiBgb25Bbm9ueW1vdXNgIHBpY2tzIHdoYXQgaGFwcGVucyB3aGVuIHRoZXJlIGlzIG5vIGByZXEudXNlcmAgYXQgYWxsOiBgJ3Bhc3MnYFxuICogKHN1aXRlcyB3aXRoIG5vIGF1dGggbGF5ZXIgbW91bnRlZCkgb3IgYCc0MDEnYCAoc3VpdGVzIHRoYXQgZHJpdmUgdGhlIGdhdGUpLlxuICogYHNoYXBlYCBwaWNrcyB0aGUgZGVuaWFsIGVudmVsb3BlIHRoZSBwcm9qZWN0J3Mgc3VpdGVzIGFzc2VydCBvbi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1vY2tQZXJtaXNzaW9uR2F0ZShvcHRpb25zOiB7XG4gIG1vZGU/OiAnc29tZScgfCAnZXZlcnknO1xuICBhbGxvd1NlcnZpY2U/OiBib29sZWFuO1xuICBvbkFub255bW91cz86ICdwYXNzJyB8ICc0MDEnO1xuICBzaGFwZT86ICdlcnJvcicgfCAnbWVzc2FnZSc7XG59ID0ge30pIHtcbiAgY29uc3QgeyBtb2RlID0gJ3NvbWUnLCBhbGxvd1NlcnZpY2UgPSBmYWxzZSwgb25Bbm9ueW1vdXMgPSAncGFzcycsIHNoYXBlID0gJ21lc3NhZ2UnIH0gPSBvcHRpb25zO1xuICBjb25zdCBqb2luZXIgPSBtb2RlID09PSAnc29tZScgPyAnIG9yICcgOiAnIGFuZCAnO1xuICBjb25zdCBkZW55ID0gKG1zZzogc3RyaW5nKSA9PiAoc2hhcGUgPT09ICdlcnJvcicgPyB7IGVycm9yOiBtc2cgfSA6IHsgc3VjY2VzczogZmFsc2UsIG1lc3NhZ2U6IG1zZyB9KTtcbiAgcmV0dXJuICguLi5wZXJtaXNzaW9uczogc3RyaW5nW10pID0+IHtcbiAgICBjb25zdCBnYXRlID0gKHJlcTogeyB1c2VyPzogeyBpc1N1cGVyQWRtaW4/OiBib29sZWFuOyBwZXJtaXNzaW9ucz86IHN0cmluZ1tdOyBzdWI/OiBzdHJpbmcgfSB9LCByZXM6IE1vY2tSZXMsIG5leHQ6IE5leHQpOiB1bmtub3duID0+IHtcbiAgICAgIGNvbnN0IHVzZXIgPSByZXE/LnVzZXI7XG4gICAgICBpZiAoIXVzZXIpIHJldHVybiBvbkFub255bW91cyA9PT0gJ3Bhc3MnID8gbmV4dCgpIDogcmVzLnN0YXR1cyg0MDEpLmpzb24oeyBlcnJvcjogJ0F1dGhlbnRpY2F0aW9uIHJlcXVpcmVkJyB9KTtcbiAgICAgIGlmIChhbGxvd1NlcnZpY2UgJiYgdHlwZW9mIHVzZXIuc3ViID09PSAnc3RyaW5nJyAmJiB1c2VyLnN1Yi5zdGFydHNXaXRoKCdzZXJ2aWNlOicpKSByZXR1cm4gbmV4dCgpO1xuICAgICAgaWYgKHVzZXIuaXNTdXBlckFkbWluID09PSB0cnVlKSByZXR1cm4gbmV4dCgpO1xuICAgICAgY29uc3QgaGVsZCA9IEFycmF5LmlzQXJyYXkodXNlci5wZXJtaXNzaW9ucykgPyB1c2VyLnBlcm1pc3Npb25zIDogW107XG4gICAgICBjb25zdCBvayA9IG1vZGUgPT09ICdzb21lJyA/IHBlcm1pc3Npb25zLnNvbWUoKHApID0+IGhlbGQuaW5jbHVkZXMocCkpIDogcGVybWlzc2lvbnMuZXZlcnkoKHApID0+IGhlbGQuaW5jbHVkZXMocCkpO1xuICAgICAgaWYgKG9rKSByZXR1cm4gbmV4dCgpO1xuICAgICAgcmV0dXJuIHJlcy5zdGF0dXMoNDAzKS5qc29uKGRlbnkoYE1pc3NpbmcgcmVxdWlyZWQgcGVybWlzc2lvbjogJHtwZXJtaXNzaW9ucy5qb2luKGpvaW5lcil9YCkpO1xuICAgIH07XG4gICAgLy8gVGFncyBsZXQgYSB3aXJpbmcgc3VpdGUgbG9jYXRlIHRoZSBnYXRlIGxheWVyIGluIGEgcm91dGVyIHN0YWNrIGFuZCBhc3NlcnRcbiAgICAvLyB3aGljaCBmbGF2b3VyIHdhcyBtb3VudGVkLlxuICAgIChnYXRlIGFzIHVua25vd24gYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pLl9fcGVybWlzc2lvbiA9IHBlcm1pc3Npb25zLmpvaW4oam9pbmVyKTtcbiAgICAoZ2F0ZSBhcyB1bmtub3duIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KS5fX2FsbG93U2VydmljZSA9IGFsbG93U2VydmljZTtcbiAgICByZXR1cm4gZ2F0ZTtcbiAgfTtcbn1cblxuLyoqXG4gKiBUaGUgZGVmYXVsdHMgc2hhcmVkIGJ5IGV2ZXJ5IHNlcnZpY2UgLyBwYWNrYWdlIG1vY2s6IHRoZSBsb2dnZXIgc3R1YiwgdGhlXG4gKiBwYWdpbmF0aW9uIGNvbnN0YW50cywgdGhlIGluZXJ0IHNjaGVkdWxlciAvIGxlYWRlci1sb2NrIC8gcmVkaXMtYXVkaXQgd2lyaW5nIGFcbiAqIGJvb3QgbW9kdWxlIGxpbmtzIGF0IGxvYWQsIGFuZCB0aGUgZXJyb3IgKyBjYWNoZSBzaGFwZXMuIEEgcHJvamVjdCBsYXllcnMgaXRzXG4gKiBvd24gZGVmYXVsdHMgb24gdG9wIGJ5IHBhc3NpbmcgdGhlbSBpbiBgb3ZlcnJpZGVzYC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNlcnZpY2VBcGlDb3JlRGVmYXVsdHMoKTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4ge1xuICByZXR1cm4ge1xuICAgIGNyZWF0ZUxvZ2dlcjogbG9nZ2VyTW9jayxcbiAgICBNQVhfUEFHRV9MSU1JVDogMTAwMCxcbiAgICBERUZBVUxUX1BBR0VfTElNSVQ6IDEwMCxcbiAgICBjbG9zZUxlYWRlckxvY2s6IGFzeW5jICgpID0+IHVuZGVmaW5lZCxcbiAgICBsb2FkQW5kUmVzdG9yZTogYXN5bmMgKCkgPT4gbnVsbCxcbiAgICBSRVBPUlRfSU5URVJWQUxTOiBbJ2RheScsICd3ZWVrJywgJ21vbnRoJ10sXG4gICAgc2NydWJBd3NJZGVudGlmaWVyc0Zyb21TdHJpbmc6IChzOiBzdHJpbmcpID0+IHMsXG4gICAgc2NydWJBd3NJZGVudGlmaWVyczogPFQ+KHY6IFQpOiBUID0+IHYsXG4gICAgY3JlYXRlU2NoZWR1bGVyOiAoKSA9PiAoeyBzdGFydDogKCkgPT4gdW5kZWZpbmVkLCBzdG9wOiAoKSA9PiB1bmRlZmluZWQgfSksXG4gICAgY3JlYXRlRW52UmVkaXNMb2NrOiAoKSA9PiBudWxsLFxuICAgIHJlcXVpcmVTdGVwVXA6IChfcmVxOiB1bmtub3duLCBfcmVzOiB1bmtub3duLCBuZXh0OiBOZXh0KSA9PiBuZXh0KCksXG4gICAgU1lTVEVNX09SR19JRDogJzAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMScsXG4gICAgQ29tcHV0ZVR5cGU6IHsgU01BTEw6ICdTTUFMTCcsIE1FRElVTTogJ01FRElVTScsIExBUkdFOiAnTEFSR0UnLCBYMl9MQVJHRTogJ1gyX0xBUkdFJyB9LFxuICAgIFBsdWdpblR5cGU6IHsgQ09ERV9CVUlMRF9TVEVQOiAnQ29kZUJ1aWxkU3RlcCcsIFNIRUxMX1NURVA6ICdTaGVsbFN0ZXAnLCBNQU5VQUxfQVBQUk9WQUxfU1RFUDogJ01hbnVhbEFwcHJvdmFsU3RlcCcgfSxcbiAgICBFcnJvckNvZGU6IG1vY2tFcnJvckNvZGUsXG4gICAgZXJyb3JNZXNzYWdlOiAoZTogdW5rbm93bikgPT4gKGUgaW5zdGFuY2VvZiBFcnJvciA/IGUubWVzc2FnZSA6IFN0cmluZyhlKSksXG4gICAgTm90Rm91bmRFcnJvcjogTW9ja05vdEZvdW5kRXJyb3IsXG4gICAgY3JlYXRlQ2FjaGVTZXJ2aWNlOiAoKSA9PiAoe1xuICAgICAgZ2V0T3JTZXQ6IChfa2V5OiBzdHJpbmcsIGZhY3Rvcnk6ICgpID0+IFByb21pc2U8dW5rbm93bj4pID0+IGZhY3RvcnkoKSxcbiAgICAgIGludmFsaWRhdGVQYXR0ZXJuOiAoKSA9PiBQcm9taXNlLnJlc29sdmUoMCksXG4gICAgfSksXG4gIH07XG59XG5cbi8qKlxuICogVGhlIGF1ZGl0IC8gc2VjdXJpdHkgd2lyaW5nIGEgc2VydmljZSdzIGJvb3QgbW9kdWxlIChgc3JjL2luZGV4LnRzYCxcbiAqIGBzcmMvc2VydmljZXMvYXVkaXQudHNgKSBsaW5rcyBhdCBsb2FkIHRpbWUuIEluZXJ0IGJ5IGRlZmF1bHQ6IG5vdGhpbmcgYXNzZXJ0c1xuICogb24gdGhlIHJlZ2lzdHJhdGlvbiwgYW5kIHB1bGxpbmcgdGhlIHJlYWwgZ3JhcGggaW4gd291bGQgZHJhZyBSZWRpcyArIEhUVFBcbiAqIGNsaWVudHMgaW50byBldmVyeSByb3V0ZSBzdWl0ZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNlcnZpY2VBdWRpdERlZmF1bHRzKCk6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHtcbiAgcmV0dXJuIHtcbiAgICBjcmVhdGVSZW1vdGVBdWRpdENsaWVudDogKCkgPT4gKHsgcmVjb3JkOiBqZXN0LmZuKCkgfSksXG4gICAgY3JlYXRlRW52UmVkaXNBdWRpdFNwb29sOiAoKSA9PiBudWxsLFxuICAgIGNyZWF0ZVNlcnZpY2VBdWRpdENsaWVudDogKCkgPT4gKHsgZW1pdDogamVzdC5mbigpLCBjbGllbnQ6IHsgcmVjb3JkOiBqZXN0LmZuKCkgfSB9KSxcbiAgICBjcmVhdGVSZW1vdGVBdWRpdEFjY2Vzc29yOiAoKSA9PiAoeyBnZXRBdWRpdENsaWVudDogKCkgPT4gKHsgcmVjb3JkOiBqZXN0LmZuKCkgfSksIGVtaXQ6IGplc3QuZm4oKSB9KSxcbiAgICBzZXRBdXRoekRlbmlhbEF1ZGl0b3I6ICgpID0+IHt9LFxuICAgIHdpcmVBdXRoekRlbmlhbEF1ZGl0b3I6ICgpID0+IHt9LFxuICAgIHdpcmVTZXJ2aWNlU2VjdXJpdHk6ICgpID0+IHt9LFxuICAgIHNldFRva2VuUmV2b2NhdGlvblN0b3JlOiAoKSA9PiB7fSxcbiAgICBjcmVhdGVSZWRpc1Rva2VuUmV2b2NhdGlvblN0b3JlOiAoKSA9PiAoeyBnZXRDdXJyZW50VmVyc2lvbjogYXN5bmMgKCkgPT4gbnVsbCB9KSxcbiAgICBjcmVhdGVFbnZSZWRpc1Rva2VuUmV2b2NhdGlvblN0b3JlOiAoKSA9PiAoeyBnZXRDdXJyZW50VmVyc2lvbjogYXN5bmMgKCkgPT4gbnVsbCB9KSxcbiAgfTtcbn1cblxuLyoqXG4gKiBCdWlsZCBhbiBhcGktY29yZSBtb2NrIG5hbWVzcGFjZTogUkVBTCBhcGktY29yZSwgdGhlbiB0aGUgc2hhcmVkIHNlcnZpY2VcbiAqIGRlZmF1bHRzLCB0aGVuIGBvdmVycmlkZXNgIChhIHByb2plY3QncyBvd24gZGVmYXVsdHMgbWVyZ2VkIHdpdGggdGhlIHN1aXRlJ3MpLlxuICpcbiAqIGBhY3R1YWxBcGlDb3JlYCBpcyBzdXBwbGllZCBieSB0aGUgQ0FMTEVSIChgamVzdC5yZXF1aXJlQWN0dWFsKC4uLilgIGF0IHRoZSB0b3BcbiAqIG9mIHRoZSBwcm9qZWN0J3MgYHRlc3QvaGVscGVycy9tb2NrLWFwaS1jb3JlLnRzYCkgcmF0aGVyIHRoYW4gcmVzb2x2ZWQgaGVyZS5cbiAqIFRoYXQgaXMgZGVsaWJlcmF0ZTogYHJlcXVpcmVBY3R1YWxgIG9uIGFuIEVTTSBiYXJyZWwgb25seSBzdWNjZWVkcyBhdCBhIG1vbWVudFxuICogd2hlbiBub3RoaW5nIGVsc2UgaXMgbWlkLWBpbXBvcnQoKWAgb2YgaXQsIGFuZCB0aGUgcHJvamVjdCBoZWxwZXIg4oCUIGEgc3RhdGljXG4gKiBpbXBvcnQgb2YgdGhlIHRlc3QgZmlsZSwgZXZhbHVhdGVkIGJlZm9yZSBhbnkgYGF3YWl0IGltcG9ydChTVVQpYCDigJQgaXMgdGhlIG9uZVxuICogcG9pbnQgd2hlcmUgdGhhdCBhbHdheXMgaG9sZHMuIFJlc29sdmluZyBpdCBmcm9tIGluc2lkZSB0aGlzIG1vZHVsZSAod2hpY2hcbiAqIGxpdmVzIGluIHRoZSBhcGktY29yZSBwYWNrYWdlIGl0c2VsZikgcmFjZXMgdGhhdCBpbXBvcnQgaW4gc29tZSBzdWl0ZXMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBiYXNlQXBpQ29yZU1vY2soXG4gIGFjdHVhbEFwaUNvcmU6IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuICBvdmVycmlkZXM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0ge30sXG4pOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB7XG4gIHJldHVybiB7IC4uLmFjdHVhbEFwaUNvcmUsIC4uLnNlcnZpY2VBcGlDb3JlRGVmYXVsdHMoKSwgLi4ub3ZlcnJpZGVzIH07XG59XG5cbi8qKlxuICogQnVpbGQgYW4gYXBpLWNvcmUgbW9jayBuYW1lc3BhY2Ugd2l0aCBOTyBzZXJ2aWNlIGRlZmF1bHRzIOKAlCBSRUFMIGFwaS1jb3JlIHBsdXNcbiAqIHRoZSBsb2dnZXIgc3R1YiBhbmQgYEVycm9yQ29kZWAgcHJveHkgb25seS4gUGxhdGZvcm0gdXNlcyB0aGlzOiBpdCBkZWxpYmVyYXRlbHlcbiAqIGtlZXBzIGFwaS1jb3JlJ3MgcmVhbCBwYWdpbmF0aW9uL3JlcG9ydCBjb25zdGFudHMgYW5kIHN1cHBsaWVzIGl0cyBvd25cbiAqIChsYXJnZSkgaWRlbnRpdHkvdGllci9wZXJtaXNzaW9uIGRlZmF1bHQgc2V0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gcHJpbWl0aXZlQXBpQ29yZU1vY2soXG4gIGFjdHVhbEFwaUNvcmU6IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuICBvdmVycmlkZXM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0ge30sXG4pOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB7XG4gIHJldHVybiB7IC4uLmFjdHVhbEFwaUNvcmUsIGNyZWF0ZUxvZ2dlcjogbG9nZ2VyTW9jaywgRXJyb3JDb2RlOiBtb2NrRXJyb3JDb2RlLCAuLi5vdmVycmlkZXMgfTtcbn1cblxuLyoqXG4gKiBNaXJyb3IgYXBpLWNvcmUncyBgcmVxdWlyZUludGVybmFsU2VydmljZSh7IGNhbGxlcnMgfSlgOiByZWZ1c2UgYW55IHVzZXIgdG9rZW4sXG4gKiB0aGVuIHJlZnVzZSBhIHNlcnZpY2Ugd2hvc2UgbmFtZSBpcyBub3QgaW4gdGhlIHJvdXRlJ3MgY2FsbGVyIGxpc3QuIFJlc29sdmVkXG4gKiBmcm9tIHRoZSBNRVJHRUQgbW9jayAocmF0aGVyIHRoYW4gaW5oZXJpdGVkIGZyb20gYHJlcXVpcmVBY3R1YWxgKSBzbyBpdCB1c2VzXG4gKiB0aGUgc3VpdGUncyBgaXNTZXJ2aWNlUHJpbmNpcGFsYCAvIGBzZXJ2aWNlTmFtZU9mYCAvIGBzZW5kRXJyb3JgLCB3aGljaCB0aGUgcmVhbFxuICogb25lIGNsb3NlcyBvdmVyIGFuZCB3b3VsZCB3cml0ZSBwYXN0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gd2l0aEludGVybmFsU2VydmljZUdhdGUobW9jazogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sIG92ZXJyaWRlczogUmVjb3JkPHN0cmluZywgdW5rbm93bj4pOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB7XG4gIGlmIChvdmVycmlkZXMucmVxdWlyZUludGVybmFsU2VydmljZSAhPT0gdW5kZWZpbmVkKSByZXR1cm4gbW9jaztcbiAgbW9jay5yZXF1aXJlSW50ZXJuYWxTZXJ2aWNlID0gKHsgY2FsbGVycyB9OiB7IGNhbGxlcnM6IHJlYWRvbmx5IHN0cmluZ1tdIH0pID0+XG4gICAgKHJlcTogdW5rbm93biwgcmVzOiB1bmtub3duLCBuZXh0OiBOZXh0KSA9PiB7XG4gICAgICBjb25zdCBpc1N2YyA9IG1vY2suaXNTZXJ2aWNlUHJpbmNpcGFsIGFzICgocjogdW5rbm93bikgPT4gYm9vbGVhbikgfCB1bmRlZmluZWQ7XG4gICAgICBjb25zdCBuYW1lT2YgPSBtb2NrLnNlcnZpY2VOYW1lT2YgYXMgKChjOiB1bmtub3duKSA9PiBzdHJpbmcgfCB1bmRlZmluZWQpIHwgdW5kZWZpbmVkO1xuICAgICAgY29uc3QgY2FsbGVyID0gbmFtZU9mPy4oKHJlcSBhcyB7IHVzZXI/OiB1bmtub3duIH0pLnVzZXIpO1xuICAgICAgaWYgKGlzU3ZjPy4ocmVxKSAmJiBjYWxsZXIgJiYgY2FsbGVycy5pbmNsdWRlcyhjYWxsZXIpKSB7XG4gICAgICAgIG5leHQoKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgY29uc3Qgc2VuZEVycm9yID0gbW9jay5zZW5kRXJyb3IgYXMgKHI6IHVua25vd24sIHM6IG51bWJlciwgbTogc3RyaW5nLCBjOiBzdHJpbmcpID0+IHVua25vd247XG4gICAgICBzZW5kRXJyb3IocmVzLCA0MDMsICdJbnRlcm5hbCBzZXJ2aWNlIGNhbGxzIG9ubHknLCAnSU5TVUZGSUNJRU5UX1BFUk1JU1NJT05TJyk7XG4gICAgfTtcbiAgcmV0dXJuIG1vY2s7XG59XG5cbi8qKlxuICogTWlycm9yIGFwaS1jb3JlJ3MgYHJlcXVpcmVTZXJ2aWNlUHJpbmNpcGFsYDogcmVqZWN0IGEgbm9uLXNlcnZpY2UgY2FsbGVyIHdpdGggYVxuICogNDAzIElOU1VGRklDSUVOVF9QRVJNSVNTSU9OUyAoYW4gYXV0aG9yaXphdGlvbiByZWZ1c2FsLCBub3QgYSA0MDApLCByZXNvbHZpbmdcbiAqIGBpc1NlcnZpY2VQcmluY2lwYWxgIC8gYHNlbmRFcnJvcmAgZnJvbSB0aGUgbWVyZ2VkIG1vY2suXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB3aXRoU2VydmljZVByaW5jaXBhbEdhdGUobW9jazogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sIG92ZXJyaWRlczogUmVjb3JkPHN0cmluZywgdW5rbm93bj4pOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB7XG4gIGlmIChvdmVycmlkZXMucmVxdWlyZVNlcnZpY2VQcmluY2lwYWwgIT09IHVuZGVmaW5lZCkgcmV0dXJuIG1vY2s7XG4gIG1vY2sucmVxdWlyZVNlcnZpY2VQcmluY2lwYWwgPSAocmVxOiB1bmtub3duLCByZXM6IHVua25vd24sIG5leHQ6IE5leHQpID0+IHtcbiAgICBjb25zdCBpc1N2YyA9IG1vY2suaXNTZXJ2aWNlUHJpbmNpcGFsIGFzICgocjogdW5rbm93bikgPT4gYm9vbGVhbikgfCB1bmRlZmluZWQ7XG4gICAgaWYgKGlzU3ZjPy4ocmVxKSkge1xuICAgICAgbmV4dCgpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBzZW5kRXJyb3IgPSBtb2NrLnNlbmRFcnJvciBhcyAocjogdW5rbm93biwgczogbnVtYmVyLCBtOiBzdHJpbmcsIGM6IHN0cmluZykgPT4gdW5rbm93bjtcbiAgICBzZW5kRXJyb3IocmVzLCA0MDMsICdJbnRlcm5hbCBzZXJ2aWNlIGNhbGxzIG9ubHknLCAnSU5TVUZGSUNJRU5UX1BFUk1JU1NJT05TJyk7XG4gIH07XG4gIHJldHVybiBtb2NrO1xufVxuXG4vKipcbiAqIGBzZW5kQmFkUmVxdWVzdGAgZGVsZWdhdGluZyB0byB0aGUgKHBvc3NpYmx5LW92ZXJyaWRkZW4pIGBzZW5kRXJyb3JgLCBtaXJyb3JpbmdcbiAqIHRoZSByZWFsIGltcGxlbWVudGF0aW9uIOKAlCBzbyBhIHN1aXRlIHNweWluZyBvbiBgc2VuZEVycm9yYCBhbHNvIG9ic2VydmVzIHRoZVxuICogNDAwcyByb3V0ZWQgdGhyb3VnaCBgc2VuZEJhZFJlcXVlc3RgLlxuICovXG5leHBvcnQgZnVuY3Rpb24gd2l0aERlbGVnYXRpbmdTZW5kQmFkUmVxdWVzdChtb2NrOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiwgb3ZlcnJpZGVzOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPik6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHtcbiAgaWYgKCdzZW5kQmFkUmVxdWVzdCcgaW4gb3ZlcnJpZGVzKSByZXR1cm4gbW9jaztcbiAgbW9jay5zZW5kQmFkUmVxdWVzdCA9IChyZXM6IHVua25vd24sIG1lc3NhZ2U6IHN0cmluZywgY29kZT86IHN0cmluZykgPT5cbiAgICAobW9jay5zZW5kRXJyb3IgYXMgKHI6IHVua25vd24sIHM6IG51bWJlciwgbTogc3RyaW5nLCBjPzogc3RyaW5nKSA9PiB1bmtub3duKShcbiAgICAgIHJlcywgNDAwLCBtZXNzYWdlLCBjb2RlID8/IG1vY2tFcnJvckNvZGUuVkFMSURBVElPTl9FUlJPUik7XG4gIHJldHVybiBtb2NrO1xufVxuIl19
@@ -1,6 +0,0 @@
1
- /**
2
- * Build a `drizzle-orm` mock namespace: every real export, with `overrides`
3
- * spread last so a suite can swap an operator for an inspectable stub (or a
4
- * `jest.fn()` it asserts on) without having to enumerate the rest.
5
- */
6
- export declare function drizzleMock(overrides?: Record<string, unknown>): Record<string, unknown>;
@@ -1,57 +0,0 @@
1
- // Copyright 2026 Pipeline Builder Contributors
2
- // SPDX-License-Identifier: Apache-2.0
3
- /**
4
- * Shared `drizzle-orm` module mock for ESM suites.
5
- *
6
- * WHY: eighteen suites hand-wrote `jest.unstable_mockModule('drizzle-orm', () => ({ … }))`
7
- * with whatever operator subset they happened to need. `unstable_mockModule`
8
- * replaces the WHOLE namespace, so the moment production code reached for an
9
- * operator a suite had not listed (`desc` was present in 6 of the 18, absent in
10
- * 12) ESM linking failed with "does not provide an export named X" — a build
11
- * break with no relationship to the change that triggered it.
12
- *
13
- * THE FIX: start from the REAL module and overlay only what a suite asserts on.
14
- * A new drizzle export — or a new operator used by production code — is inherited
15
- * automatically, so the drift class is gone rather than merely re-synchronised.
16
- *
17
- * WHY IT LIVES IN api-core: every service already deep-imports test fixtures from
18
- * `@pipeline-builder/api-core/lib/testing/*` (see tier-mock.ts). The deep path is
19
- * NOT intercepted by a suite's `@pipeline-builder/api-core` module mock, so the
20
- * factory is safe to import from inside a suite that mocks the api-core barrel.
21
- *
22
- * USAGE:
23
- * import { drizzleMock } from '@pipeline-builder/api-core/lib/testing/mock-drizzle.js';
24
- * jest.unstable_mockModule('drizzle-orm', () => drizzleMock({
25
- * eq: (col: unknown, val: unknown) => ({ _kind: 'eq', col, val }),
26
- * }));
27
- *
28
- * The eslint `no-restricted-syntax` rule added in `.projenrc.ts` fails any suite
29
- * that goes back to an inline object literal here.
30
- */
31
- import { jest } from '@jest/globals';
32
- /**
33
- * The REAL drizzle-orm namespace, resolved LAZILY (and memoised) — evaluating it
34
- * at module load races the ESM loader when a suite's static import graph already
35
- * has drizzle in flight. `requireActual` bypasses the module mock, so this is
36
- * safe to call from inside the very factory that replaces it.
37
- */
38
- let actualDrizzleCache;
39
- try {
40
- actualDrizzleCache = jest.requireActual('drizzle-orm');
41
- }
42
- catch {
43
- actualDrizzleCache = undefined;
44
- }
45
- function actualDrizzle() {
46
- actualDrizzleCache ??= jest.requireActual('drizzle-orm');
47
- return actualDrizzleCache;
48
- }
49
- /**
50
- * Build a `drizzle-orm` mock namespace: every real export, with `overrides`
51
- * spread last so a suite can swap an operator for an inspectable stub (or a
52
- * `jest.fn()` it asserts on) without having to enumerate the rest.
53
- */
54
- export function drizzleMock(overrides = {}) {
55
- return { ...actualDrizzle(), ...overrides };
56
- }
57
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9jay1kcml6emxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3Rlc3RpbmcvbW9jay1kcml6emxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFFdEM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQTJCRztBQUVILE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFckM7Ozs7O0dBS0c7QUFDSCxJQUFJLGtCQUF1RCxDQUFDO0FBQzVELElBQUksQ0FBQztJQUNILGtCQUFrQixHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsYUFBYSxDQUE0QixDQUFDO0FBQ3BGLENBQUM7QUFBQyxNQUFNLENBQUM7SUFDUCxrQkFBa0IsR0FBRyxTQUFTLENBQUM7QUFDakMsQ0FBQztBQUNELFNBQVMsYUFBYTtJQUNwQixrQkFBa0IsS0FBSyxJQUFJLENBQUMsYUFBYSxDQUFDLGFBQWEsQ0FBNEIsQ0FBQztJQUNwRixPQUFPLGtCQUFrQixDQUFDO0FBQzVCLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsTUFBTSxVQUFVLFdBQVcsQ0FBQyxTQUFTLEdBQTRCLEVBQUU7SUFDakUsT0FBTyxFQUFFLEdBQUcsYUFBYSxFQUFFLEVBQUUsR0FBRyxTQUFTLEVBQUUsQ0FBQztBQUM5QyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbi8qKlxuICogU2hhcmVkIGBkcml6emxlLW9ybWAgbW9kdWxlIG1vY2sgZm9yIEVTTSBzdWl0ZXMuXG4gKlxuICogV0hZOiBlaWdodGVlbiBzdWl0ZXMgaGFuZC13cm90ZSBgamVzdC51bnN0YWJsZV9tb2NrTW9kdWxlKCdkcml6emxlLW9ybScsICgpID0+ICh7IOKApiB9KSlgXG4gKiB3aXRoIHdoYXRldmVyIG9wZXJhdG9yIHN1YnNldCB0aGV5IGhhcHBlbmVkIHRvIG5lZWQuIGB1bnN0YWJsZV9tb2NrTW9kdWxlYFxuICogcmVwbGFjZXMgdGhlIFdIT0xFIG5hbWVzcGFjZSwgc28gdGhlIG1vbWVudCBwcm9kdWN0aW9uIGNvZGUgcmVhY2hlZCBmb3IgYW5cbiAqIG9wZXJhdG9yIGEgc3VpdGUgaGFkIG5vdCBsaXN0ZWQgKGBkZXNjYCB3YXMgcHJlc2VudCBpbiA2IG9mIHRoZSAxOCwgYWJzZW50IGluXG4gKiAxMikgRVNNIGxpbmtpbmcgZmFpbGVkIHdpdGggXCJkb2VzIG5vdCBwcm92aWRlIGFuIGV4cG9ydCBuYW1lZCBYXCIg4oCUIGEgYnVpbGRcbiAqIGJyZWFrIHdpdGggbm8gcmVsYXRpb25zaGlwIHRvIHRoZSBjaGFuZ2UgdGhhdCB0cmlnZ2VyZWQgaXQuXG4gKlxuICogVEhFIEZJWDogc3RhcnQgZnJvbSB0aGUgUkVBTCBtb2R1bGUgYW5kIG92ZXJsYXkgb25seSB3aGF0IGEgc3VpdGUgYXNzZXJ0cyBvbi5cbiAqIEEgbmV3IGRyaXp6bGUgZXhwb3J0IOKAlCBvciBhIG5ldyBvcGVyYXRvciB1c2VkIGJ5IHByb2R1Y3Rpb24gY29kZSDigJQgaXMgaW5oZXJpdGVkXG4gKiBhdXRvbWF0aWNhbGx5LCBzbyB0aGUgZHJpZnQgY2xhc3MgaXMgZ29uZSByYXRoZXIgdGhhbiBtZXJlbHkgcmUtc3luY2hyb25pc2VkLlxuICpcbiAqIFdIWSBJVCBMSVZFUyBJTiBhcGktY29yZTogZXZlcnkgc2VydmljZSBhbHJlYWR5IGRlZXAtaW1wb3J0cyB0ZXN0IGZpeHR1cmVzIGZyb21cbiAqIGBAcGlwZWxpbmUtYnVpbGRlci9hcGktY29yZS9saWIvdGVzdGluZy8qYCAoc2VlIHRpZXItbW9jay50cykuIFRoZSBkZWVwIHBhdGggaXNcbiAqIE5PVCBpbnRlcmNlcHRlZCBieSBhIHN1aXRlJ3MgYEBwaXBlbGluZS1idWlsZGVyL2FwaS1jb3JlYCBtb2R1bGUgbW9jaywgc28gdGhlXG4gKiBmYWN0b3J5IGlzIHNhZmUgdG8gaW1wb3J0IGZyb20gaW5zaWRlIGEgc3VpdGUgdGhhdCBtb2NrcyB0aGUgYXBpLWNvcmUgYmFycmVsLlxuICpcbiAqIFVTQUdFOlxuICogICBpbXBvcnQgeyBkcml6emxlTW9jayB9IGZyb20gJ0BwaXBlbGluZS1idWlsZGVyL2FwaS1jb3JlL2xpYi90ZXN0aW5nL21vY2stZHJpenpsZS5qcyc7XG4gKiAgIGplc3QudW5zdGFibGVfbW9ja01vZHVsZSgnZHJpenpsZS1vcm0nLCAoKSA9PiBkcml6emxlTW9jayh7XG4gKiAgICAgZXE6IChjb2w6IHVua25vd24sIHZhbDogdW5rbm93bikgPT4gKHsgX2tpbmQ6ICdlcScsIGNvbCwgdmFsIH0pLFxuICogICB9KSk7XG4gKlxuICogVGhlIGVzbGludCBgbm8tcmVzdHJpY3RlZC1zeW50YXhgIHJ1bGUgYWRkZWQgaW4gYC5wcm9qZW5yYy50c2AgZmFpbHMgYW55IHN1aXRlXG4gKiB0aGF0IGdvZXMgYmFjayB0byBhbiBpbmxpbmUgb2JqZWN0IGxpdGVyYWwgaGVyZS5cbiAqL1xuXG5pbXBvcnQgeyBqZXN0IH0gZnJvbSAnQGplc3QvZ2xvYmFscyc7XG5cbi8qKlxuICogVGhlIFJFQUwgZHJpenpsZS1vcm0gbmFtZXNwYWNlLCByZXNvbHZlZCBMQVpJTFkgKGFuZCBtZW1vaXNlZCkg4oCUIGV2YWx1YXRpbmcgaXRcbiAqIGF0IG1vZHVsZSBsb2FkIHJhY2VzIHRoZSBFU00gbG9hZGVyIHdoZW4gYSBzdWl0ZSdzIHN0YXRpYyBpbXBvcnQgZ3JhcGggYWxyZWFkeVxuICogaGFzIGRyaXp6bGUgaW4gZmxpZ2h0LiBgcmVxdWlyZUFjdHVhbGAgYnlwYXNzZXMgdGhlIG1vZHVsZSBtb2NrLCBzbyB0aGlzIGlzXG4gKiBzYWZlIHRvIGNhbGwgZnJvbSBpbnNpZGUgdGhlIHZlcnkgZmFjdG9yeSB0aGF0IHJlcGxhY2VzIGl0LlxuICovXG5sZXQgYWN0dWFsRHJpenpsZUNhY2hlOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB8IHVuZGVmaW5lZDtcbnRyeSB7XG4gIGFjdHVhbERyaXp6bGVDYWNoZSA9IGplc3QucmVxdWlyZUFjdHVhbCgnZHJpenpsZS1vcm0nKSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbn0gY2F0Y2gge1xuICBhY3R1YWxEcml6emxlQ2FjaGUgPSB1bmRlZmluZWQ7XG59XG5mdW5jdGlvbiBhY3R1YWxEcml6emxlKCk6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHtcbiAgYWN0dWFsRHJpenpsZUNhY2hlID8/PSBqZXN0LnJlcXVpcmVBY3R1YWwoJ2RyaXp6bGUtb3JtJykgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gIHJldHVybiBhY3R1YWxEcml6emxlQ2FjaGU7XG59XG5cbi8qKlxuICogQnVpbGQgYSBgZHJpenpsZS1vcm1gIG1vY2sgbmFtZXNwYWNlOiBldmVyeSByZWFsIGV4cG9ydCwgd2l0aCBgb3ZlcnJpZGVzYFxuICogc3ByZWFkIGxhc3Qgc28gYSBzdWl0ZSBjYW4gc3dhcCBhbiBvcGVyYXRvciBmb3IgYW4gaW5zcGVjdGFibGUgc3R1YiAob3IgYVxuICogYGplc3QuZm4oKWAgaXQgYXNzZXJ0cyBvbikgd2l0aG91dCBoYXZpbmcgdG8gZW51bWVyYXRlIHRoZSByZXN0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gZHJpenpsZU1vY2sob3ZlcnJpZGVzOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHt9KTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4ge1xuICByZXR1cm4geyAuLi5hY3R1YWxEcml6emxlKCksIC4uLm92ZXJyaWRlcyB9O1xufVxuIl19
@@ -1,64 +0,0 @@
1
- import { type RouteTableEntry } from '../middleware/route-table.js';
2
- /** A rule a route is allowed not to satisfy, with the reason it is exempt. */
3
- export interface RouteCoverageException {
4
- /** HTTP method, or '*' for any. */
5
- method?: string;
6
- /** Exact route path, or a pattern matched against `METHOD /path`. */
7
- path: string | RegExp;
8
- /** Which rule is waived: the permission gate, the audit declaration, or both. */
9
- waive: 'permission' | 'audit' | 'all';
10
- /** Why this route can't carry the gate/audit. Required — no silent allowlisting. */
11
- reason: string;
12
- /**
13
- * Skip the staleness check for this entry. Only for the shared
14
- * {@link INFRA_ROUTE_EXCEPTIONS}, whose routes depend on per-service
15
- * `createApp` options (OpenAPI docs, log stream) — a service that doesn't
16
- * enable them would otherwise fail on an "unused" shared exception.
17
- */
18
- optional?: boolean;
19
- }
20
- /**
21
- * Exceptions every service inherits from `createApp`'s infrastructure routes:
22
- * unauthenticated probes, the service-principal-gated warm-up, the metrics
23
- * scrape endpoint, the OpenAPI docs, and the ticket-gated SSE log stream.
24
- */
25
- export declare const INFRA_ROUTE_EXCEPTIONS: readonly RouteCoverageException[];
26
- /** The outcome of a coverage check: what fails, and which exceptions went unused. */
27
- export interface RouteCoverageResult {
28
- /** One human-readable line per uncovered route (empty ⇒ full coverage). */
29
- violations: string[];
30
- /** Exceptions that waived nothing — stale entries to delete. */
31
- unusedExceptions: string[];
32
- }
33
- /** Check a service's route table against the coverage rules. */
34
- export declare function findRouteCoverageViolations(table: readonly RouteTableEntry[], exceptions?: readonly RouteCoverageException[]): RouteCoverageResult;
35
- /** One internal route a service declares, and the services allowed to call it. */
36
- export interface InternalRouteDeclaration {
37
- method: string;
38
- path: string;
39
- /** The `callers` passed to `requireInternalService` — also what the mesh policy names. */
40
- callers: string[];
41
- }
42
- /**
43
- * Check a service's INTERNAL routes (#14) against what it declares.
44
- *
45
- * The declaration is the single list a service maintains, and it is checked in
46
- * BOTH directions, so neither side can drift:
47
- *
48
- * - every declared route must exist and be gated by `requireInternalService`
49
- * with exactly the declared callers (and `requireAuth` before it);
50
- * - every route the table says is internal must be declared — so adding one
51
- * forces a visible change here, and the Istio `AuthorizationPolicy` that
52
- * names the same callers (`deploy/*​/k8s/istio-internal-routes.yaml`) has
53
- * one authoritative list to be reviewed against.
54
- */
55
- export declare function findInternalRouteViolations(table: readonly RouteTableEntry[], declared: readonly InternalRouteDeclaration[]): string[];
56
- /** Every audit action declared anywhere in a route table. */
57
- export declare function declaredAuditActions(table: readonly RouteTableEntry[]): string[];
58
- /**
59
- * Compare a service's route table to its checked-in copy under
60
- * `frontend/src/generated/route-table/` — the file the frontend's `can(...)`
61
- * tests read. Returns a diff message, or `null` when they match. Set
62
- * `UPDATE_ROUTE_TABLES=1` to rewrite the file after an intended route change.
63
- */
64
- export declare function compareRouteTableSnapshot(table: readonly RouteTableEntry[], file: string): string | null;