@pipeline-builder/api-core 3.1.0

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 (122) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +51 -0
  3. package/lib/constants/ai-providers.d.ts +41 -0
  4. package/lib/constants/ai-providers.js +88 -0
  5. package/lib/constants/http-status.d.ts +24 -0
  6. package/lib/constants/http-status.js +29 -0
  7. package/lib/constants/index.d.ts +3 -0
  8. package/lib/constants/index.js +22 -0
  9. package/lib/constants/time.d.ts +10 -0
  10. package/lib/constants/time.js +16 -0
  11. package/lib/errors/app-errors.d.ts +30 -0
  12. package/lib/errors/app-errors.js +62 -0
  13. package/lib/errors/index.d.ts +1 -0
  14. package/lib/errors/index.js +20 -0
  15. package/lib/helpers/access-helpers.d.ts +40 -0
  16. package/lib/helpers/access-helpers.js +56 -0
  17. package/lib/helpers/crud-helpers.d.ts +16 -0
  18. package/lib/helpers/crud-helpers.js +34 -0
  19. package/lib/helpers/index.d.ts +4 -0
  20. package/lib/helpers/index.js +23 -0
  21. package/lib/helpers/mask-helpers.d.ts +33 -0
  22. package/lib/helpers/mask-helpers.js +54 -0
  23. package/lib/helpers/sse-helpers.d.ts +13 -0
  24. package/lib/helpers/sse-helpers.js +40 -0
  25. package/lib/index.d.ts +57 -0
  26. package/lib/index.js +86 -0
  27. package/lib/middleware/auth.d.ts +50 -0
  28. package/lib/middleware/auth.js +171 -0
  29. package/lib/middleware/index.d.ts +1 -0
  30. package/lib/middleware/index.js +20 -0
  31. package/lib/openapi/extend-zod.d.ts +1 -0
  32. package/lib/openapi/extend-zod.js +8 -0
  33. package/lib/openapi/index.d.ts +2 -0
  34. package/lib/openapi/index.js +10 -0
  35. package/lib/openapi/registry.d.ts +17 -0
  36. package/lib/openapi/registry.js +42 -0
  37. package/lib/openapi/routes/billing-routes.d.ts +1 -0
  38. package/lib/openapi/routes/billing-routes.js +69 -0
  39. package/lib/openapi/routes/index.d.ts +5 -0
  40. package/lib/openapi/routes/index.js +22 -0
  41. package/lib/openapi/routes/message-routes.d.ts +1 -0
  42. package/lib/openapi/routes/message-routes.js +108 -0
  43. package/lib/openapi/routes/pipeline-routes.d.ts +1 -0
  44. package/lib/openapi/routes/pipeline-routes.js +90 -0
  45. package/lib/openapi/routes/plugin-routes.d.ts +1 -0
  46. package/lib/openapi/routes/plugin-routes.js +99 -0
  47. package/lib/openapi/routes/quota-routes.d.ts +1 -0
  48. package/lib/openapi/routes/quota-routes.js +65 -0
  49. package/lib/openapi/schema-registry.d.ts +25 -0
  50. package/lib/openapi/schema-registry.js +95 -0
  51. package/lib/routes/health.d.ts +47 -0
  52. package/lib/routes/health.js +81 -0
  53. package/lib/routes/index.d.ts +1 -0
  54. package/lib/routes/index.js +20 -0
  55. package/lib/services/admin-audit.d.ts +13 -0
  56. package/lib/services/admin-audit.js +31 -0
  57. package/lib/services/cache-service.d.ts +108 -0
  58. package/lib/services/cache-service.js +212 -0
  59. package/lib/services/compliance-client.d.ts +46 -0
  60. package/lib/services/compliance-client.js +102 -0
  61. package/lib/services/compliance-event-subscriber.d.ts +11 -0
  62. package/lib/services/compliance-event-subscriber.js +60 -0
  63. package/lib/services/compliance-queue.d.ts +11 -0
  64. package/lib/services/compliance-queue.js +38 -0
  65. package/lib/services/entity-events.d.ts +44 -0
  66. package/lib/services/entity-events.js +63 -0
  67. package/lib/services/http-client.d.ts +108 -0
  68. package/lib/services/http-client.js +285 -0
  69. package/lib/services/index.d.ts +10 -0
  70. package/lib/services/index.js +40 -0
  71. package/lib/services/quota.d.ts +59 -0
  72. package/lib/services/quota.js +137 -0
  73. package/lib/services/retry-strategy.d.ts +74 -0
  74. package/lib/services/retry-strategy.js +127 -0
  75. package/lib/types/billing.d.ts +47 -0
  76. package/lib/types/billing.js +5 -0
  77. package/lib/types/common.d.ts +161 -0
  78. package/lib/types/common.js +53 -0
  79. package/lib/types/error-codes.d.ts +38 -0
  80. package/lib/types/error-codes.js +77 -0
  81. package/lib/types/feature-flags.d.ts +38 -0
  82. package/lib/types/feature-flags.js +107 -0
  83. package/lib/types/http.d.ts +37 -0
  84. package/lib/types/http.js +5 -0
  85. package/lib/types/index.d.ts +7 -0
  86. package/lib/types/index.js +26 -0
  87. package/lib/types/pipeline.d.ts +70 -0
  88. package/lib/types/pipeline.js +44 -0
  89. package/lib/types/quota-tiers.d.ts +23 -0
  90. package/lib/types/quota-tiers.js +26 -0
  91. package/lib/utils/alias-resolver.d.ts +16 -0
  92. package/lib/utils/alias-resolver.js +49 -0
  93. package/lib/utils/headers.d.ts +18 -0
  94. package/lib/utils/headers.js +24 -0
  95. package/lib/utils/identity.d.ts +61 -0
  96. package/lib/utils/identity.js +75 -0
  97. package/lib/utils/index.d.ts +7 -0
  98. package/lib/utils/index.js +26 -0
  99. package/lib/utils/logger.d.ts +28 -0
  100. package/lib/utils/logger.js +77 -0
  101. package/lib/utils/object.d.ts +13 -0
  102. package/lib/utils/object.js +21 -0
  103. package/lib/utils/params.d.ts +89 -0
  104. package/lib/utils/params.js +148 -0
  105. package/lib/utils/response.d.ts +142 -0
  106. package/lib/utils/response.js +237 -0
  107. package/lib/validation/ai-schemas.d.ts +61 -0
  108. package/lib/validation/ai-schemas.js +81 -0
  109. package/lib/validation/common-schemas.d.ts +72 -0
  110. package/lib/validation/common-schemas.js +58 -0
  111. package/lib/validation/index.d.ts +6 -0
  112. package/lib/validation/index.js +25 -0
  113. package/lib/validation/message-schemas.d.ts +79 -0
  114. package/lib/validation/message-schemas.js +42 -0
  115. package/lib/validation/middleware.d.ts +60 -0
  116. package/lib/validation/middleware.js +77 -0
  117. package/lib/validation/pipeline-schemas.d.ts +135 -0
  118. package/lib/validation/pipeline-schemas.js +85 -0
  119. package/lib/validation/plugin-schemas.d.ts +127 -0
  120. package/lib/validation/plugin-schemas.js +84 -0
  121. package/openapi.yaml +292 -0
  122. package/package.json +127 -0
@@ -0,0 +1,40 @@
1
+ import type { Request, Response } from 'express';
2
+ /**
3
+ * Apply access control to a filter object.
4
+ *
5
+ * Non-system-admins are restricted to 'private' (org-scoped) resources.
6
+ * System admins see all access modifiers.
7
+ *
8
+ * @param filter - Query filter to modify
9
+ * @param req - Express request (used to check admin status)
10
+ * @returns Filter with accessModifier applied for non-admins
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * const effectiveFilter = applyAccessControl(filter, req);
15
+ * const results = await service.find(effectiveFilter, orgId);
16
+ * ```
17
+ */
18
+ export declare function applyAccessControl<T extends {
19
+ accessModifier?: string;
20
+ }>(filter: T, req: Request): T;
21
+ /**
22
+ * Check whether a non-admin user may modify a public resource.
23
+ *
24
+ * Returns `true` if the request may proceed. Returns `false` and sends
25
+ * a 403 response if the user lacks permission.
26
+ *
27
+ * @param req - Express request
28
+ * @param res - Express response
29
+ * @param resource - Resource with an accessModifier field
30
+ * @returns `true` if access is allowed, `false` if blocked (response already sent)
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * if (!requirePublicAccess(req, res, pipeline)) return;
35
+ * await pipelineService.delete(id, orgId, userId);
36
+ * ```
37
+ */
38
+ export declare function requirePublicAccess(req: Request, res: Response, resource: {
39
+ accessModifier?: string;
40
+ }): boolean;
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ // Copyright 2026 Pipeline Builder Contributors
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.applyAccessControl = applyAccessControl;
6
+ exports.requirePublicAccess = requirePublicAccess;
7
+ const auth_1 = require("../middleware/auth");
8
+ const error_codes_1 = require("../types/error-codes");
9
+ const pipeline_1 = require("../types/pipeline");
10
+ const response_1 = require("../utils/response");
11
+ /**
12
+ * Apply access control to a filter object.
13
+ *
14
+ * Non-system-admins are restricted to 'private' (org-scoped) resources.
15
+ * System admins see all access modifiers.
16
+ *
17
+ * @param filter - Query filter to modify
18
+ * @param req - Express request (used to check admin status)
19
+ * @returns Filter with accessModifier applied for non-admins
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * const effectiveFilter = applyAccessControl(filter, req);
24
+ * const results = await service.find(effectiveFilter, orgId);
25
+ * ```
26
+ */
27
+ function applyAccessControl(filter, req) {
28
+ return !(0, auth_1.isSystemAdmin)(req)
29
+ ? { ...filter, accessModifier: pipeline_1.AccessModifier.PRIVATE }
30
+ : filter;
31
+ }
32
+ /**
33
+ * Check whether a non-admin user may modify a public resource.
34
+ *
35
+ * Returns `true` if the request may proceed. Returns `false` and sends
36
+ * a 403 response if the user lacks permission.
37
+ *
38
+ * @param req - Express request
39
+ * @param res - Express response
40
+ * @param resource - Resource with an accessModifier field
41
+ * @returns `true` if access is allowed, `false` if blocked (response already sent)
42
+ *
43
+ * @example
44
+ * ```typescript
45
+ * if (!requirePublicAccess(req, res, pipeline)) return;
46
+ * await pipelineService.delete(id, orgId, userId);
47
+ * ```
48
+ */
49
+ function requirePublicAccess(req, res, resource) {
50
+ if (!(0, auth_1.isSystemAdmin)(req) && resource.accessModifier !== pipeline_1.AccessModifier.PRIVATE) {
51
+ (0, response_1.sendError)(res, 403, 'Only system admins can modify public resources.', error_codes_1.ErrorCode.INSUFFICIENT_PERMISSIONS);
52
+ return false;
53
+ }
54
+ return true;
55
+ }
56
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWNjZXNzLWhlbHBlcnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaGVscGVycy9hY2Nlc3MtaGVscGVycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsK0NBQStDO0FBQy9DLHNDQUFzQzs7QUF3QnRDLGdEQU9DO0FBbUJELGtEQWVDO0FBOURELDZDQUFtRDtBQUNuRCxzREFBaUQ7QUFDakQsZ0RBQW1EO0FBQ25ELGdEQUE4QztBQUU5Qzs7Ozs7Ozs7Ozs7Ozs7O0dBZUc7QUFDSCxTQUFnQixrQkFBa0IsQ0FDaEMsTUFBUyxFQUNULEdBQVk7SUFFWixPQUFPLENBQUMsSUFBQSxvQkFBYSxFQUFDLEdBQUcsQ0FBQztRQUN4QixDQUFDLENBQUMsRUFBRSxHQUFHLE1BQU0sRUFBRSxjQUFjLEVBQUUseUJBQWMsQ0FBQyxPQUFPLEVBQUU7UUFDdkQsQ0FBQyxDQUFDLE1BQU0sQ0FBQztBQUNiLENBQUM7QUFFRDs7Ozs7Ozs7Ozs7Ozs7OztHQWdCRztBQUNILFNBQWdCLG1CQUFtQixDQUNqQyxHQUFZLEVBQ1osR0FBYSxFQUNiLFFBQXFDO0lBRXJDLElBQUksQ0FBQyxJQUFBLG9CQUFhLEVBQUMsR0FBRyxDQUFDLElBQUksUUFBUSxDQUFDLGNBQWMsS0FBSyx5QkFBYyxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQzlFLElBQUEsb0JBQVMsRUFDUCxHQUFHLEVBQ0gsR0FBRyxFQUNILGlEQUFpRCxFQUNqRCx1QkFBUyxDQUFDLHdCQUF3QixDQUNuQyxDQUFDO1FBQ0YsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBQ0QsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCB0eXBlIHsgUmVxdWVzdCwgUmVzcG9uc2UgfSBmcm9tICdleHByZXNzJztcbmltcG9ydCB7IGlzU3lzdGVtQWRtaW4gfSBmcm9tICcuLi9taWRkbGV3YXJlL2F1dGgnO1xuaW1wb3J0IHsgRXJyb3JDb2RlIH0gZnJvbSAnLi4vdHlwZXMvZXJyb3ItY29kZXMnO1xuaW1wb3J0IHsgQWNjZXNzTW9kaWZpZXIgfSBmcm9tICcuLi90eXBlcy9waXBlbGluZSc7XG5pbXBvcnQgeyBzZW5kRXJyb3IgfSBmcm9tICcuLi91dGlscy9yZXNwb25zZSc7XG5cbi8qKlxuICogQXBwbHkgYWNjZXNzIGNvbnRyb2wgdG8gYSBmaWx0ZXIgb2JqZWN0LlxuICpcbiAqIE5vbi1zeXN0ZW0tYWRtaW5zIGFyZSByZXN0cmljdGVkIHRvICdwcml2YXRlJyAob3JnLXNjb3BlZCkgcmVzb3VyY2VzLlxuICogU3lzdGVtIGFkbWlucyBzZWUgYWxsIGFjY2VzcyBtb2RpZmllcnMuXG4gKlxuICogQHBhcmFtIGZpbHRlciAtIFF1ZXJ5IGZpbHRlciB0byBtb2RpZnlcbiAqIEBwYXJhbSByZXEgLSBFeHByZXNzIHJlcXVlc3QgKHVzZWQgdG8gY2hlY2sgYWRtaW4gc3RhdHVzKVxuICogQHJldHVybnMgRmlsdGVyIHdpdGggYWNjZXNzTW9kaWZpZXIgYXBwbGllZCBmb3Igbm9uLWFkbWluc1xuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjb25zdCBlZmZlY3RpdmVGaWx0ZXIgPSBhcHBseUFjY2Vzc0NvbnRyb2woZmlsdGVyLCByZXEpO1xuICogY29uc3QgcmVzdWx0cyA9IGF3YWl0IHNlcnZpY2UuZmluZChlZmZlY3RpdmVGaWx0ZXIsIG9yZ0lkKTtcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gYXBwbHlBY2Nlc3NDb250cm9sPFQgZXh0ZW5kcyB7IGFjY2Vzc01vZGlmaWVyPzogc3RyaW5nIH0+KFxuICBmaWx0ZXI6IFQsXG4gIHJlcTogUmVxdWVzdCxcbik6IFQge1xuICByZXR1cm4gIWlzU3lzdGVtQWRtaW4ocmVxKVxuICAgID8geyAuLi5maWx0ZXIsIGFjY2Vzc01vZGlmaWVyOiBBY2Nlc3NNb2RpZmllci5QUklWQVRFIH1cbiAgICA6IGZpbHRlcjtcbn1cblxuLyoqXG4gKiBDaGVjayB3aGV0aGVyIGEgbm9uLWFkbWluIHVzZXIgbWF5IG1vZGlmeSBhIHB1YmxpYyByZXNvdXJjZS5cbiAqXG4gKiBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgcmVxdWVzdCBtYXkgcHJvY2VlZC4gUmV0dXJucyBgZmFsc2VgIGFuZCBzZW5kc1xuICogYSA0MDMgcmVzcG9uc2UgaWYgdGhlIHVzZXIgbGFja3MgcGVybWlzc2lvbi5cbiAqXG4gKiBAcGFyYW0gcmVxIC0gRXhwcmVzcyByZXF1ZXN0XG4gKiBAcGFyYW0gcmVzIC0gRXhwcmVzcyByZXNwb25zZVxuICogQHBhcmFtIHJlc291cmNlIC0gUmVzb3VyY2Ugd2l0aCBhbiBhY2Nlc3NNb2RpZmllciBmaWVsZFxuICogQHJldHVybnMgYHRydWVgIGlmIGFjY2VzcyBpcyBhbGxvd2VkLCBgZmFsc2VgIGlmIGJsb2NrZWQgKHJlc3BvbnNlIGFscmVhZHkgc2VudClcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogaWYgKCFyZXF1aXJlUHVibGljQWNjZXNzKHJlcSwgcmVzLCBwaXBlbGluZSkpIHJldHVybjtcbiAqIGF3YWl0IHBpcGVsaW5lU2VydmljZS5kZWxldGUoaWQsIG9yZ0lkLCB1c2VySWQpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlUHVibGljQWNjZXNzKFxuICByZXE6IFJlcXVlc3QsXG4gIHJlczogUmVzcG9uc2UsXG4gIHJlc291cmNlOiB7IGFjY2Vzc01vZGlmaWVyPzogc3RyaW5nIH0sXG4pOiBib29sZWFuIHtcbiAgaWYgKCFpc1N5c3RlbUFkbWluKHJlcSkgJiYgcmVzb3VyY2UuYWNjZXNzTW9kaWZpZXIgIT09IEFjY2Vzc01vZGlmaWVyLlBSSVZBVEUpIHtcbiAgICBzZW5kRXJyb3IoXG4gICAgICByZXMsXG4gICAgICA0MDMsXG4gICAgICAnT25seSBzeXN0ZW0gYWRtaW5zIGNhbiBtb2RpZnkgcHVibGljIHJlc291cmNlcy4nLFxuICAgICAgRXJyb3JDb2RlLklOU1VGRklDSUVOVF9QRVJNSVNTSU9OUyxcbiAgICApO1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICByZXR1cm4gdHJ1ZTtcbn1cbiJdfQ==
@@ -0,0 +1,16 @@
1
+ import type { Response } from 'express';
2
+ /**
3
+ * Generic record normalizer - ensures array fields are always arrays
4
+ * @param record - The record to normalize
5
+ * @param arrayFields - Fields that should be arrays
6
+ * @returns Normalized record with array fields guaranteed to be arrays
7
+ */
8
+ export declare function normalizeArrayFields<T extends Record<string, unknown>>(record: T, arrayFields: (keyof T)[]): T;
9
+ /**
10
+ * Generic entity not-found response
11
+ * Sends standardized 404 response for missing entities
12
+ * @param res - Express response object
13
+ * @param entityName - Name of the entity type (e.g., "Pipeline", "Plugin")
14
+ * @returns Express response
15
+ */
16
+ export declare function sendEntityNotFound(res: Response, entityName: string): void;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ // Copyright 2026 Pipeline Builder Contributors
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.normalizeArrayFields = normalizeArrayFields;
6
+ exports.sendEntityNotFound = sendEntityNotFound;
7
+ const error_codes_1 = require("../types/error-codes");
8
+ const response_1 = require("../utils/response");
9
+ /**
10
+ * Generic record normalizer - ensures array fields are always arrays
11
+ * @param record - The record to normalize
12
+ * @param arrayFields - Fields that should be arrays
13
+ * @returns Normalized record with array fields guaranteed to be arrays
14
+ */
15
+ function normalizeArrayFields(record, arrayFields) {
16
+ const normalized = { ...record };
17
+ for (const field of arrayFields) {
18
+ if (field in normalized && !Array.isArray(normalized[field])) {
19
+ normalized[field] = [];
20
+ }
21
+ }
22
+ return normalized;
23
+ }
24
+ /**
25
+ * Generic entity not-found response
26
+ * Sends standardized 404 response for missing entities
27
+ * @param res - Express response object
28
+ * @param entityName - Name of the entity type (e.g., "Pipeline", "Plugin")
29
+ * @returns Express response
30
+ */
31
+ function sendEntityNotFound(res, entityName) {
32
+ (0, response_1.sendError)(res, 404, `${entityName} not found.`, error_codes_1.ErrorCode.NOT_FOUND);
33
+ }
34
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3J1ZC1oZWxwZXJzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2hlbHBlcnMvY3J1ZC1oZWxwZXJzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDOztBQVl0QyxvREFXQztBQVNELGdEQUVDO0FBL0JELHNEQUFpRDtBQUNqRCxnREFBOEM7QUFFOUM7Ozs7O0dBS0c7QUFDSCxTQUFnQixvQkFBb0IsQ0FDbEMsTUFBUyxFQUNULFdBQXdCO0lBRXhCLE1BQU0sVUFBVSxHQUFHLEVBQUUsR0FBRyxNQUFNLEVBQUUsQ0FBQztJQUNqQyxLQUFLLE1BQU0sS0FBSyxJQUFJLFdBQVcsRUFBRSxDQUFDO1FBQ2hDLElBQUksS0FBSyxJQUFJLFVBQVUsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUM1RCxVQUFzQyxDQUFDLEtBQWUsQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUNoRSxDQUFDO0lBQ0gsQ0FBQztJQUNELE9BQU8sVUFBVSxDQUFDO0FBQ3BCLENBQUM7QUFFRDs7Ozs7O0dBTUc7QUFDSCxTQUFnQixrQkFBa0IsQ0FBQyxHQUFhLEVBQUUsVUFBa0I7SUFDbEUsSUFBQSxvQkFBUyxFQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxVQUFVLGFBQWEsRUFBRSx1QkFBUyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0FBQ3ZFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuaW1wb3J0IHR5cGUgeyBSZXNwb25zZSB9IGZyb20gJ2V4cHJlc3MnO1xuaW1wb3J0IHsgRXJyb3JDb2RlIH0gZnJvbSAnLi4vdHlwZXMvZXJyb3ItY29kZXMnO1xuaW1wb3J0IHsgc2VuZEVycm9yIH0gZnJvbSAnLi4vdXRpbHMvcmVzcG9uc2UnO1xuXG4vKipcbiAqIEdlbmVyaWMgcmVjb3JkIG5vcm1hbGl6ZXIgLSBlbnN1cmVzIGFycmF5IGZpZWxkcyBhcmUgYWx3YXlzIGFycmF5c1xuICogQHBhcmFtIHJlY29yZCAtIFRoZSByZWNvcmQgdG8gbm9ybWFsaXplXG4gKiBAcGFyYW0gYXJyYXlGaWVsZHMgLSBGaWVsZHMgdGhhdCBzaG91bGQgYmUgYXJyYXlzXG4gKiBAcmV0dXJucyBOb3JtYWxpemVkIHJlY29yZCB3aXRoIGFycmF5IGZpZWxkcyBndWFyYW50ZWVkIHRvIGJlIGFycmF5c1xuICovXG5leHBvcnQgZnVuY3Rpb24gbm9ybWFsaXplQXJyYXlGaWVsZHM8VCBleHRlbmRzIFJlY29yZDxzdHJpbmcsIHVua25vd24+PihcbiAgcmVjb3JkOiBULFxuICBhcnJheUZpZWxkczogKGtleW9mIFQpW10sXG4pOiBUIHtcbiAgY29uc3Qgbm9ybWFsaXplZCA9IHsgLi4ucmVjb3JkIH07XG4gIGZvciAoY29uc3QgZmllbGQgb2YgYXJyYXlGaWVsZHMpIHtcbiAgICBpZiAoZmllbGQgaW4gbm9ybWFsaXplZCAmJiAhQXJyYXkuaXNBcnJheShub3JtYWxpemVkW2ZpZWxkXSkpIHtcbiAgICAgIChub3JtYWxpemVkIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KVtmaWVsZCBhcyBzdHJpbmddID0gW107XG4gICAgfVxuICB9XG4gIHJldHVybiBub3JtYWxpemVkO1xufVxuXG4vKipcbiAqIEdlbmVyaWMgZW50aXR5IG5vdC1mb3VuZCByZXNwb25zZVxuICogU2VuZHMgc3RhbmRhcmRpemVkIDQwNCByZXNwb25zZSBmb3IgbWlzc2luZyBlbnRpdGllc1xuICogQHBhcmFtIHJlcyAtIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0XG4gKiBAcGFyYW0gZW50aXR5TmFtZSAtIE5hbWUgb2YgdGhlIGVudGl0eSB0eXBlIChlLmcuLCBcIlBpcGVsaW5lXCIsIFwiUGx1Z2luXCIpXG4gKiBAcmV0dXJucyBFeHByZXNzIHJlc3BvbnNlXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzZW5kRW50aXR5Tm90Rm91bmQocmVzOiBSZXNwb25zZSwgZW50aXR5TmFtZTogc3RyaW5nKTogdm9pZCB7XG4gIHNlbmRFcnJvcihyZXMsIDQwNCwgYCR7ZW50aXR5TmFtZX0gbm90IGZvdW5kLmAsIEVycm9yQ29kZS5OT1RfRk9VTkQpO1xufVxuIl19
@@ -0,0 +1,4 @@
1
+ export * from './crud-helpers';
2
+ export * from './access-helpers';
3
+ export * from './mask-helpers';
4
+ export * from './sse-helpers';
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ // Copyright 2026 Pipeline Builder Contributors
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
5
+ if (k2 === undefined) k2 = k;
6
+ var desc = Object.getOwnPropertyDescriptor(m, k);
7
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
8
+ desc = { enumerable: true, get: function() { return m[k]; } };
9
+ }
10
+ Object.defineProperty(o, k2, desc);
11
+ }) : (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ o[k2] = m[k];
14
+ }));
15
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
17
+ };
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ __exportStar(require("./crud-helpers"), exports);
20
+ __exportStar(require("./access-helpers"), exports);
21
+ __exportStar(require("./mask-helpers"), exports);
22
+ __exportStar(require("./sse-helpers"), exports);
23
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaGVscGVycy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsK0NBQStDO0FBQy9DLHNDQUFzQzs7Ozs7Ozs7Ozs7Ozs7OztBQUV0QyxpREFBK0I7QUFDL0IsbURBQWlDO0FBQ2pDLGlEQUErQjtBQUMvQixnREFBOEIiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuZXhwb3J0ICogZnJvbSAnLi9jcnVkLWhlbHBlcnMnO1xuZXhwb3J0ICogZnJvbSAnLi9hY2Nlc3MtaGVscGVycyc7XG5leHBvcnQgKiBmcm9tICcuL21hc2staGVscGVycyc7XG5leHBvcnQgKiBmcm9tICcuL3NzZS1oZWxwZXJzJztcbiJdfQ==
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Mask the middle digits of a sensitive identifier.
3
+ * Preserves the first and last `visible` characters, replacing the rest with asterisks.
4
+ *
5
+ * @param value - The string to mask
6
+ * @param visible - Number of characters to keep visible on each side (default: 4)
7
+ * @returns Masked string, or '****' if the input is too short
8
+ *
9
+ * @example maskId('123456789012') → '1234****9012'
10
+ */
11
+ export declare function maskId(value: string, visible?: number): string;
12
+ /**
13
+ * One-way hash of a sensitive identifier using SHA-256.
14
+ * Returns a deterministic, fixed-length hex string that cannot be reversed.
15
+ *
16
+ * @param value - The sensitive value to hash (e.g. AWS account number)
17
+ * @param length - Number of hex characters to return (default: 12, matching AWS account length)
18
+ * @returns Truncated SHA-256 hex digest
19
+ *
20
+ * @example hashId('123456789012') → 'a1b2c3d4e5f6'
21
+ */
22
+ export declare function hashId(value: string, length?: number): string;
23
+ /**
24
+ * Replace the AWS account number in an ARN with its SHA-256 hash.
25
+ * Both the deploy registration and event ingestion sides call this function,
26
+ * so registry lookups still match — the real account never reaches the database.
27
+ *
28
+ * ARN format: `arn:partition:service:region:account:resource`
29
+ *
30
+ * @example hashAccountInArn('arn:aws:codepipeline:us-east-1:123456789012:my-pipeline')
31
+ * → 'arn:aws:codepipeline:us-east-1:a1b2c3d4e5f6:my-pipeline'
32
+ */
33
+ export declare function hashAccountInArn(arn: string): string;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ // Copyright 2026 Pipeline Builder Contributors
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.maskId = maskId;
6
+ exports.hashId = hashId;
7
+ exports.hashAccountInArn = hashAccountInArn;
8
+ const crypto_1 = require("crypto");
9
+ /**
10
+ * Mask the middle digits of a sensitive identifier.
11
+ * Preserves the first and last `visible` characters, replacing the rest with asterisks.
12
+ *
13
+ * @param value - The string to mask
14
+ * @param visible - Number of characters to keep visible on each side (default: 4)
15
+ * @returns Masked string, or '****' if the input is too short
16
+ *
17
+ * @example maskId('123456789012') → '1234****9012'
18
+ */
19
+ function maskId(value, visible = 4) {
20
+ if (!value || value.length <= visible * 2)
21
+ return '****';
22
+ return value.slice(0, visible) + '*'.repeat(value.length - visible * 2) + value.slice(-visible);
23
+ }
24
+ /**
25
+ * One-way hash of a sensitive identifier using SHA-256.
26
+ * Returns a deterministic, fixed-length hex string that cannot be reversed.
27
+ *
28
+ * @param value - The sensitive value to hash (e.g. AWS account number)
29
+ * @param length - Number of hex characters to return (default: 12, matching AWS account length)
30
+ * @returns Truncated SHA-256 hex digest
31
+ *
32
+ * @example hashId('123456789012') → 'a1b2c3d4e5f6'
33
+ */
34
+ function hashId(value, length = 12) {
35
+ return (0, crypto_1.createHash)('sha256').update(value).digest('hex').slice(0, length);
36
+ }
37
+ /**
38
+ * Replace the AWS account number in an ARN with its SHA-256 hash.
39
+ * Both the deploy registration and event ingestion sides call this function,
40
+ * so registry lookups still match — the real account never reaches the database.
41
+ *
42
+ * ARN format: `arn:partition:service:region:account:resource`
43
+ *
44
+ * @example hashAccountInArn('arn:aws:codepipeline:us-east-1:123456789012:my-pipeline')
45
+ * → 'arn:aws:codepipeline:us-east-1:a1b2c3d4e5f6:my-pipeline'
46
+ */
47
+ function hashAccountInArn(arn) {
48
+ const parts = arn.split(':');
49
+ if (parts.length < 5 || !parts[4])
50
+ return arn;
51
+ parts[4] = hashId(parts[4]);
52
+ return parts.join(':');
53
+ }
54
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFzay1oZWxwZXJzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2hlbHBlcnMvbWFzay1oZWxwZXJzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDOztBQWN0Qyx3QkFHQztBQVlELHdCQUVDO0FBWUQsNENBS0M7QUE5Q0QsbUNBQW9DO0FBRXBDOzs7Ozs7Ozs7R0FTRztBQUNILFNBQWdCLE1BQU0sQ0FBQyxLQUFhLEVBQUUsT0FBTyxHQUFHLENBQUM7SUFDL0MsSUFBSSxDQUFDLEtBQUssSUFBSSxLQUFLLENBQUMsTUFBTSxJQUFJLE9BQU8sR0FBRyxDQUFDO1FBQUUsT0FBTyxNQUFNLENBQUM7SUFDekQsT0FBTyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxPQUFPLENBQUMsR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxNQUFNLEdBQUcsT0FBTyxHQUFHLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQztBQUNsRyxDQUFDO0FBRUQ7Ozs7Ozs7OztHQVNHO0FBQ0gsU0FBZ0IsTUFBTSxDQUFDLEtBQWEsRUFBRSxNQUFNLEdBQUcsRUFBRTtJQUMvQyxPQUFPLElBQUEsbUJBQVUsRUFBQyxRQUFRLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLENBQUM7QUFDM0UsQ0FBQztBQUVEOzs7Ozs7Ozs7R0FTRztBQUNILFNBQWdCLGdCQUFnQixDQUFDLEdBQVc7SUFDMUMsTUFBTSxLQUFLLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUM3QixJQUFJLEtBQUssQ0FBQyxNQUFNLEdBQUcsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztRQUFFLE9BQU8sR0FBRyxDQUFDO0lBQzlDLEtBQUssQ0FBQyxDQUFDLENBQUMsR0FBRyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDNUIsT0FBTyxLQUFLLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0FBQ3pCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuaW1wb3J0IHsgY3JlYXRlSGFzaCB9IGZyb20gJ2NyeXB0byc7XG5cbi8qKlxuICogTWFzayB0aGUgbWlkZGxlIGRpZ2l0cyBvZiBhIHNlbnNpdGl2ZSBpZGVudGlmaWVyLlxuICogUHJlc2VydmVzIHRoZSBmaXJzdCBhbmQgbGFzdCBgdmlzaWJsZWAgY2hhcmFjdGVycywgcmVwbGFjaW5nIHRoZSByZXN0IHdpdGggYXN0ZXJpc2tzLlxuICpcbiAqIEBwYXJhbSB2YWx1ZSAtIFRoZSBzdHJpbmcgdG8gbWFza1xuICogQHBhcmFtIHZpc2libGUgLSBOdW1iZXIgb2YgY2hhcmFjdGVycyB0byBrZWVwIHZpc2libGUgb24gZWFjaCBzaWRlIChkZWZhdWx0OiA0KVxuICogQHJldHVybnMgTWFza2VkIHN0cmluZywgb3IgJyoqKionIGlmIHRoZSBpbnB1dCBpcyB0b28gc2hvcnRcbiAqXG4gKiBAZXhhbXBsZSBtYXNrSWQoJzEyMzQ1Njc4OTAxMicpIOKGkiAnMTIzNCoqKio5MDEyJ1xuICovXG5leHBvcnQgZnVuY3Rpb24gbWFza0lkKHZhbHVlOiBzdHJpbmcsIHZpc2libGUgPSA0KTogc3RyaW5nIHtcbiAgaWYgKCF2YWx1ZSB8fCB2YWx1ZS5sZW5ndGggPD0gdmlzaWJsZSAqIDIpIHJldHVybiAnKioqKic7XG4gIHJldHVybiB2YWx1ZS5zbGljZSgwLCB2aXNpYmxlKSArICcqJy5yZXBlYXQodmFsdWUubGVuZ3RoIC0gdmlzaWJsZSAqIDIpICsgdmFsdWUuc2xpY2UoLXZpc2libGUpO1xufVxuXG4vKipcbiAqIE9uZS13YXkgaGFzaCBvZiBhIHNlbnNpdGl2ZSBpZGVudGlmaWVyIHVzaW5nIFNIQS0yNTYuXG4gKiBSZXR1cm5zIGEgZGV0ZXJtaW5pc3RpYywgZml4ZWQtbGVuZ3RoIGhleCBzdHJpbmcgdGhhdCBjYW5ub3QgYmUgcmV2ZXJzZWQuXG4gKlxuICogQHBhcmFtIHZhbHVlIC0gVGhlIHNlbnNpdGl2ZSB2YWx1ZSB0byBoYXNoIChlLmcuIEFXUyBhY2NvdW50IG51bWJlcilcbiAqIEBwYXJhbSBsZW5ndGggLSBOdW1iZXIgb2YgaGV4IGNoYXJhY3RlcnMgdG8gcmV0dXJuIChkZWZhdWx0OiAxMiwgbWF0Y2hpbmcgQVdTIGFjY291bnQgbGVuZ3RoKVxuICogQHJldHVybnMgVHJ1bmNhdGVkIFNIQS0yNTYgaGV4IGRpZ2VzdFxuICpcbiAqIEBleGFtcGxlIGhhc2hJZCgnMTIzNDU2Nzg5MDEyJykg4oaSICdhMWIyYzNkNGU1ZjYnXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBoYXNoSWQodmFsdWU6IHN0cmluZywgbGVuZ3RoID0gMTIpOiBzdHJpbmcge1xuICByZXR1cm4gY3JlYXRlSGFzaCgnc2hhMjU2JykudXBkYXRlKHZhbHVlKS5kaWdlc3QoJ2hleCcpLnNsaWNlKDAsIGxlbmd0aCk7XG59XG5cbi8qKlxuICogUmVwbGFjZSB0aGUgQVdTIGFjY291bnQgbnVtYmVyIGluIGFuIEFSTiB3aXRoIGl0cyBTSEEtMjU2IGhhc2guXG4gKiBCb3RoIHRoZSBkZXBsb3kgcmVnaXN0cmF0aW9uIGFuZCBldmVudCBpbmdlc3Rpb24gc2lkZXMgY2FsbCB0aGlzIGZ1bmN0aW9uLFxuICogc28gcmVnaXN0cnkgbG9va3VwcyBzdGlsbCBtYXRjaCDigJQgdGhlIHJlYWwgYWNjb3VudCBuZXZlciByZWFjaGVzIHRoZSBkYXRhYmFzZS5cbiAqXG4gKiBBUk4gZm9ybWF0OiBgYXJuOnBhcnRpdGlvbjpzZXJ2aWNlOnJlZ2lvbjphY2NvdW50OnJlc291cmNlYFxuICpcbiAqIEBleGFtcGxlIGhhc2hBY2NvdW50SW5Bcm4oJ2Fybjphd3M6Y29kZXBpcGVsaW5lOnVzLWVhc3QtMToxMjM0NTY3ODkwMTI6bXktcGlwZWxpbmUnKVxuICogICDihpIgJ2Fybjphd3M6Y29kZXBpcGVsaW5lOnVzLWVhc3QtMTphMWIyYzNkNGU1ZjY6bXktcGlwZWxpbmUnXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBoYXNoQWNjb3VudEluQXJuKGFybjogc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3QgcGFydHMgPSBhcm4uc3BsaXQoJzonKTtcbiAgaWYgKHBhcnRzLmxlbmd0aCA8IDUgfHwgIXBhcnRzWzRdKSByZXR1cm4gYXJuO1xuICBwYXJ0c1s0XSA9IGhhc2hJZChwYXJ0c1s0XSk7XG4gIHJldHVybiBwYXJ0cy5qb2luKCc6Jyk7XG59XG4iXX0=
@@ -0,0 +1,13 @@
1
+ import type { Request, Response } from 'express';
2
+ /**
3
+ * Set SSE response headers and flush.
4
+ * Returns an `aborted()` function to check if the client disconnected.
5
+ */
6
+ export declare function initSSEStream(req: Request, res: Response, timeoutMs: number): {
7
+ aborted: () => boolean;
8
+ };
9
+ /**
10
+ * Classify AI generation errors and send the appropriate HTTP response or SSE event.
11
+ * If headers are already sent (streaming), writes an SSE error event and ends the response.
12
+ */
13
+ export declare function handleAIError(res: Response, message: string, fallbackMessage: string): void;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ // Copyright 2026 Pipeline Builder Contributors
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.initSSEStream = initSSEStream;
6
+ exports.handleAIError = handleAIError;
7
+ const response_1 = require("../utils/response");
8
+ /**
9
+ * Set SSE response headers and flush.
10
+ * Returns an `aborted()` function to check if the client disconnected.
11
+ */
12
+ function initSSEStream(req, res, timeoutMs) {
13
+ res.setHeader('Content-Type', 'text/event-stream');
14
+ res.setHeader('Cache-Control', 'no-cache');
15
+ res.setHeader('Connection', 'keep-alive');
16
+ res.setHeader('X-Accel-Buffering', 'no');
17
+ res.setTimeout(timeoutMs);
18
+ res.flushHeaders();
19
+ let _aborted = false;
20
+ req.on('close', () => { _aborted = true; });
21
+ return { aborted: () => _aborted };
22
+ }
23
+ /**
24
+ * Classify AI generation errors and send the appropriate HTTP response or SSE event.
25
+ * If headers are already sent (streaming), writes an SSE error event and ends the response.
26
+ */
27
+ function handleAIError(res, message, fallbackMessage) {
28
+ if (!res.headersSent) {
29
+ if (message.includes('not configured') || message.includes('API key')) {
30
+ return (0, response_1.sendInternalError)(res, 'AI generation is not configured for the requested provider');
31
+ }
32
+ if (message.includes('not available for provider')) {
33
+ return (0, response_1.sendBadRequest)(res, message);
34
+ }
35
+ return (0, response_1.sendInternalError)(res, fallbackMessage, { details: message });
36
+ }
37
+ res.write(`data: ${JSON.stringify({ type: 'error', message })}\n\n`);
38
+ res.end();
39
+ }
40
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3NlLWhlbHBlcnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaGVscGVycy9zc2UtaGVscGVycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsK0NBQStDO0FBQy9DLHNDQUFzQzs7QUFTdEMsc0NBVUM7QUFNRCxzQ0FZQztBQWxDRCxnREFBc0U7QUFFdEU7OztHQUdHO0FBQ0gsU0FBZ0IsYUFBYSxDQUFDLEdBQVksRUFBRSxHQUFhLEVBQUUsU0FBaUI7SUFDMUUsR0FBRyxDQUFDLFNBQVMsQ0FBQyxjQUFjLEVBQUUsbUJBQW1CLENBQUMsQ0FBQztJQUNuRCxHQUFHLENBQUMsU0FBUyxDQUFDLGVBQWUsRUFBRSxVQUFVLENBQUMsQ0FBQztJQUMzQyxHQUFHLENBQUMsU0FBUyxDQUFDLFlBQVksRUFBRSxZQUFZLENBQUMsQ0FBQztJQUMxQyxHQUFHLENBQUMsU0FBUyxDQUFDLG1CQUFtQixFQUFFLElBQUksQ0FBQyxDQUFDO0lBQ3pDLEdBQUcsQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDMUIsR0FBRyxDQUFDLFlBQVksRUFBRSxDQUFDO0lBQ25CLElBQUksUUFBUSxHQUFHLEtBQUssQ0FBQztJQUNyQixHQUFHLENBQUMsRUFBRSxDQUFDLE9BQU8sRUFBRSxHQUFHLEVBQUUsR0FBRyxRQUFRLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDNUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxHQUFHLEVBQUUsQ0FBQyxRQUFRLEVBQUUsQ0FBQztBQUNyQyxDQUFDO0FBRUQ7OztHQUdHO0FBQ0gsU0FBZ0IsYUFBYSxDQUFDLEdBQWEsRUFBRSxPQUFlLEVBQUUsZUFBdUI7SUFDbkYsSUFBSSxDQUFDLEdBQUcsQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUNyQixJQUFJLE9BQU8sQ0FBQyxRQUFRLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxPQUFPLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUM7WUFDdEUsT0FBTyxJQUFBLDRCQUFpQixFQUFDLEdBQUcsRUFBRSw0REFBNEQsQ0FBQyxDQUFDO1FBQzlGLENBQUM7UUFDRCxJQUFJLE9BQU8sQ0FBQyxRQUFRLENBQUMsNEJBQTRCLENBQUMsRUFBRSxDQUFDO1lBQ25ELE9BQU8sSUFBQSx5QkFBYyxFQUFDLEdBQUcsRUFBRSxPQUFPLENBQUMsQ0FBQztRQUN0QyxDQUFDO1FBQ0QsT0FBTyxJQUFBLDRCQUFpQixFQUFDLEdBQUcsRUFBRSxlQUFlLEVBQUUsRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztJQUN2RSxDQUFDO0lBQ0QsR0FBRyxDQUFDLEtBQUssQ0FBQyxTQUFTLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3JFLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQztBQUNaLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuaW1wb3J0IHR5cGUgeyBSZXF1ZXN0LCBSZXNwb25zZSB9IGZyb20gJ2V4cHJlc3MnO1xuaW1wb3J0IHsgc2VuZEJhZFJlcXVlc3QsIHNlbmRJbnRlcm5hbEVycm9yIH0gZnJvbSAnLi4vdXRpbHMvcmVzcG9uc2UnO1xuXG4vKipcbiAqIFNldCBTU0UgcmVzcG9uc2UgaGVhZGVycyBhbmQgZmx1c2guXG4gKiBSZXR1cm5zIGFuIGBhYm9ydGVkKClgIGZ1bmN0aW9uIHRvIGNoZWNrIGlmIHRoZSBjbGllbnQgZGlzY29ubmVjdGVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaW5pdFNTRVN0cmVhbShyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UsIHRpbWVvdXRNczogbnVtYmVyKTogeyBhYm9ydGVkOiAoKSA9PiBib29sZWFuIH0ge1xuICByZXMuc2V0SGVhZGVyKCdDb250ZW50LVR5cGUnLCAndGV4dC9ldmVudC1zdHJlYW0nKTtcbiAgcmVzLnNldEhlYWRlcignQ2FjaGUtQ29udHJvbCcsICduby1jYWNoZScpO1xuICByZXMuc2V0SGVhZGVyKCdDb25uZWN0aW9uJywgJ2tlZXAtYWxpdmUnKTtcbiAgcmVzLnNldEhlYWRlcignWC1BY2NlbC1CdWZmZXJpbmcnLCAnbm8nKTtcbiAgcmVzLnNldFRpbWVvdXQodGltZW91dE1zKTtcbiAgcmVzLmZsdXNoSGVhZGVycygpO1xuICBsZXQgX2Fib3J0ZWQgPSBmYWxzZTtcbiAgcmVxLm9uKCdjbG9zZScsICgpID0+IHsgX2Fib3J0ZWQgPSB0cnVlOyB9KTtcbiAgcmV0dXJuIHsgYWJvcnRlZDogKCkgPT4gX2Fib3J0ZWQgfTtcbn1cblxuLyoqXG4gKiBDbGFzc2lmeSBBSSBnZW5lcmF0aW9uIGVycm9ycyBhbmQgc2VuZCB0aGUgYXBwcm9wcmlhdGUgSFRUUCByZXNwb25zZSBvciBTU0UgZXZlbnQuXG4gKiBJZiBoZWFkZXJzIGFyZSBhbHJlYWR5IHNlbnQgKHN0cmVhbWluZyksIHdyaXRlcyBhbiBTU0UgZXJyb3IgZXZlbnQgYW5kIGVuZHMgdGhlIHJlc3BvbnNlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaGFuZGxlQUlFcnJvcihyZXM6IFJlc3BvbnNlLCBtZXNzYWdlOiBzdHJpbmcsIGZhbGxiYWNrTWVzc2FnZTogc3RyaW5nKTogdm9pZCB7XG4gIGlmICghcmVzLmhlYWRlcnNTZW50KSB7XG4gICAgaWYgKG1lc3NhZ2UuaW5jbHVkZXMoJ25vdCBjb25maWd1cmVkJykgfHwgbWVzc2FnZS5pbmNsdWRlcygnQVBJIGtleScpKSB7XG4gICAgICByZXR1cm4gc2VuZEludGVybmFsRXJyb3IocmVzLCAnQUkgZ2VuZXJhdGlvbiBpcyBub3QgY29uZmlndXJlZCBmb3IgdGhlIHJlcXVlc3RlZCBwcm92aWRlcicpO1xuICAgIH1cbiAgICBpZiAobWVzc2FnZS5pbmNsdWRlcygnbm90IGF2YWlsYWJsZSBmb3IgcHJvdmlkZXInKSkge1xuICAgICAgcmV0dXJuIHNlbmRCYWRSZXF1ZXN0KHJlcywgbWVzc2FnZSk7XG4gICAgfVxuICAgIHJldHVybiBzZW5kSW50ZXJuYWxFcnJvcihyZXMsIGZhbGxiYWNrTWVzc2FnZSwgeyBkZXRhaWxzOiBtZXNzYWdlIH0pO1xuICB9XG4gIHJlcy53cml0ZShgZGF0YTogJHtKU09OLnN0cmluZ2lmeSh7IHR5cGU6ICdlcnJvcicsIG1lc3NhZ2UgfSl9XFxuXFxuYCk7XG4gIHJlcy5lbmQoKTtcbn1cbiJdfQ==
package/lib/index.d.ts ADDED
@@ -0,0 +1,57 @@
1
+ /**
2
+ * @module @pipeline-builder/api-core
3
+ *
4
+ * Core API utilities shared across all services.
5
+ *
6
+ * **Middleware**
7
+ * - requireAuth, optionalAuth, requireOrganization, requireAdmin — JWT authentication
8
+ * - isSystemOrg, isSystemAdmin — authorization helpers
9
+ *
10
+ * **Types**
11
+ * - ErrorCode, ErrorCodeStatus — standardized error code enum and status mapping
12
+ * - RequestIdentity — parsed JWT identity
13
+ * - ServiceConfig, RequestOptions, HttpResponse — HTTP client types
14
+ * - QuotaType, QuotaCheckResult — quota service types
15
+ * - PipelineType, ComputeType, AccessModifier — pipeline domain types
16
+ * - FeatureFlags, BillingPlan — feature and billing types
17
+ *
18
+ * **Utilities**
19
+ * - createLogger — Winston-based structured logger factory
20
+ * - sendSuccess, sendError, sendPaginated, sendBadRequest, sendInternalError — HTTP response helpers
21
+ * - getParam, getRequiredParam, getParams, getOrgId, getAuthHeader — request parameter extraction
22
+ * - parseQueryBoolean, parseQueryInt, parseQueryString — query string parsing
23
+ * - getIdentity, validateIdentity — identity extraction from requests
24
+ * - errorMessage — safe error-to-string conversion
25
+ *
26
+ * **Constants**
27
+ * - HTTP status codes, AI provider identifiers, time constants
28
+ *
29
+ * **Services**
30
+ * - InternalHttpClient, createSafeClient — internal service-to-service HTTP client
31
+ * - createQuotaService — quota enforcement client factory
32
+ * - CacheService — in-memory TTL cache
33
+ * - ComplianceClient — compliance service client
34
+ * - EntityEventEmitter — domain event pub/sub
35
+ *
36
+ * **Errors**
37
+ * - AppError, NotFoundError, ForbiddenError — typed HTTP error classes
38
+ *
39
+ * **Validation**
40
+ * - Zod-based request validation schemas and middleware
41
+ *
42
+ * **Routes**
43
+ * - Health check route factory
44
+ *
45
+ * **OpenAPI**
46
+ * - Schema registry and spec generation
47
+ */
48
+ export * from './types';
49
+ export * from './constants';
50
+ export * from './utils';
51
+ export * from './helpers';
52
+ export * from './services';
53
+ export * from './middleware';
54
+ export * from './routes';
55
+ export * from './errors';
56
+ export * from './validation';
57
+ export * from './openapi';
package/lib/index.js ADDED
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ // Copyright 2026 Pipeline Builder Contributors
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
5
+ if (k2 === undefined) k2 = k;
6
+ var desc = Object.getOwnPropertyDescriptor(m, k);
7
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
8
+ desc = { enumerable: true, get: function() { return m[k]; } };
9
+ }
10
+ Object.defineProperty(o, k2, desc);
11
+ }) : (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ o[k2] = m[k];
14
+ }));
15
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
17
+ };
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ /**
20
+ * @module @pipeline-builder/api-core
21
+ *
22
+ * Core API utilities shared across all services.
23
+ *
24
+ * **Middleware**
25
+ * - requireAuth, optionalAuth, requireOrganization, requireAdmin — JWT authentication
26
+ * - isSystemOrg, isSystemAdmin — authorization helpers
27
+ *
28
+ * **Types**
29
+ * - ErrorCode, ErrorCodeStatus — standardized error code enum and status mapping
30
+ * - RequestIdentity — parsed JWT identity
31
+ * - ServiceConfig, RequestOptions, HttpResponse — HTTP client types
32
+ * - QuotaType, QuotaCheckResult — quota service types
33
+ * - PipelineType, ComputeType, AccessModifier — pipeline domain types
34
+ * - FeatureFlags, BillingPlan — feature and billing types
35
+ *
36
+ * **Utilities**
37
+ * - createLogger — Winston-based structured logger factory
38
+ * - sendSuccess, sendError, sendPaginated, sendBadRequest, sendInternalError — HTTP response helpers
39
+ * - getParam, getRequiredParam, getParams, getOrgId, getAuthHeader — request parameter extraction
40
+ * - parseQueryBoolean, parseQueryInt, parseQueryString — query string parsing
41
+ * - getIdentity, validateIdentity — identity extraction from requests
42
+ * - errorMessage — safe error-to-string conversion
43
+ *
44
+ * **Constants**
45
+ * - HTTP status codes, AI provider identifiers, time constants
46
+ *
47
+ * **Services**
48
+ * - InternalHttpClient, createSafeClient — internal service-to-service HTTP client
49
+ * - createQuotaService — quota enforcement client factory
50
+ * - CacheService — in-memory TTL cache
51
+ * - ComplianceClient — compliance service client
52
+ * - EntityEventEmitter — domain event pub/sub
53
+ *
54
+ * **Errors**
55
+ * - AppError, NotFoundError, ForbiddenError — typed HTTP error classes
56
+ *
57
+ * **Validation**
58
+ * - Zod-based request validation schemas and middleware
59
+ *
60
+ * **Routes**
61
+ * - Health check route factory
62
+ *
63
+ * **OpenAPI**
64
+ * - Schema registry and spec generation
65
+ */
66
+ // Types
67
+ __exportStar(require("./types"), exports);
68
+ // Constants
69
+ __exportStar(require("./constants"), exports);
70
+ // Utils
71
+ __exportStar(require("./utils"), exports);
72
+ // Helpers
73
+ __exportStar(require("./helpers"), exports);
74
+ // Services
75
+ __exportStar(require("./services"), exports);
76
+ // Middleware
77
+ __exportStar(require("./middleware"), exports);
78
+ // Routes
79
+ __exportStar(require("./routes"), exports);
80
+ // Errors
81
+ __exportStar(require("./errors"), exports);
82
+ // Validation
83
+ __exportStar(require("./validation"), exports);
84
+ // OpenAPI
85
+ __exportStar(require("./openapi"), exports);
86
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7Ozs7Ozs7Ozs7Ozs7Ozs7QUFFdEM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0E4Q0c7QUFFSCxRQUFRO0FBQ1IsMENBQXdCO0FBRXhCLFlBQVk7QUFDWiw4Q0FBNEI7QUFFNUIsUUFBUTtBQUNSLDBDQUF3QjtBQUV4QixVQUFVO0FBQ1YsNENBQTBCO0FBRTFCLFdBQVc7QUFDWCw2Q0FBMkI7QUFFM0IsYUFBYTtBQUNiLCtDQUE2QjtBQUU3QixTQUFTO0FBQ1QsMkNBQXlCO0FBRXpCLFNBQVM7QUFDVCwyQ0FBeUI7QUFFekIsYUFBYTtBQUNiLCtDQUE2QjtBQUU3QixVQUFVO0FBQ1YsNENBQTBCIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbi8qKlxuICogQG1vZHVsZSBAcGlwZWxpbmUtYnVpbGRlci9hcGktY29yZVxuICpcbiAqIENvcmUgQVBJIHV0aWxpdGllcyBzaGFyZWQgYWNyb3NzIGFsbCBzZXJ2aWNlcy5cbiAqXG4gKiAqKk1pZGRsZXdhcmUqKlxuICogLSByZXF1aXJlQXV0aCwgb3B0aW9uYWxBdXRoLCByZXF1aXJlT3JnYW5pemF0aW9uLCByZXF1aXJlQWRtaW4g4oCUIEpXVCBhdXRoZW50aWNhdGlvblxuICogLSBpc1N5c3RlbU9yZywgaXNTeXN0ZW1BZG1pbiDigJQgYXV0aG9yaXphdGlvbiBoZWxwZXJzXG4gKlxuICogKipUeXBlcyoqXG4gKiAtIEVycm9yQ29kZSwgRXJyb3JDb2RlU3RhdHVzIOKAlCBzdGFuZGFyZGl6ZWQgZXJyb3IgY29kZSBlbnVtIGFuZCBzdGF0dXMgbWFwcGluZ1xuICogLSBSZXF1ZXN0SWRlbnRpdHkg4oCUIHBhcnNlZCBKV1QgaWRlbnRpdHlcbiAqIC0gU2VydmljZUNvbmZpZywgUmVxdWVzdE9wdGlvbnMsIEh0dHBSZXNwb25zZSDigJQgSFRUUCBjbGllbnQgdHlwZXNcbiAqIC0gUXVvdGFUeXBlLCBRdW90YUNoZWNrUmVzdWx0IOKAlCBxdW90YSBzZXJ2aWNlIHR5cGVzXG4gKiAtIFBpcGVsaW5lVHlwZSwgQ29tcHV0ZVR5cGUsIEFjY2Vzc01vZGlmaWVyIOKAlCBwaXBlbGluZSBkb21haW4gdHlwZXNcbiAqIC0gRmVhdHVyZUZsYWdzLCBCaWxsaW5nUGxhbiDigJQgZmVhdHVyZSBhbmQgYmlsbGluZyB0eXBlc1xuICpcbiAqICoqVXRpbGl0aWVzKipcbiAqIC0gY3JlYXRlTG9nZ2VyIOKAlCBXaW5zdG9uLWJhc2VkIHN0cnVjdHVyZWQgbG9nZ2VyIGZhY3RvcnlcbiAqIC0gc2VuZFN1Y2Nlc3MsIHNlbmRFcnJvciwgc2VuZFBhZ2luYXRlZCwgc2VuZEJhZFJlcXVlc3QsIHNlbmRJbnRlcm5hbEVycm9yIOKAlCBIVFRQIHJlc3BvbnNlIGhlbHBlcnNcbiAqIC0gZ2V0UGFyYW0sIGdldFJlcXVpcmVkUGFyYW0sIGdldFBhcmFtcywgZ2V0T3JnSWQsIGdldEF1dGhIZWFkZXIg4oCUIHJlcXVlc3QgcGFyYW1ldGVyIGV4dHJhY3Rpb25cbiAqIC0gcGFyc2VRdWVyeUJvb2xlYW4sIHBhcnNlUXVlcnlJbnQsIHBhcnNlUXVlcnlTdHJpbmcg4oCUIHF1ZXJ5IHN0cmluZyBwYXJzaW5nXG4gKiAtIGdldElkZW50aXR5LCB2YWxpZGF0ZUlkZW50aXR5IOKAlCBpZGVudGl0eSBleHRyYWN0aW9uIGZyb20gcmVxdWVzdHNcbiAqIC0gZXJyb3JNZXNzYWdlIOKAlCBzYWZlIGVycm9yLXRvLXN0cmluZyBjb252ZXJzaW9uXG4gKlxuICogKipDb25zdGFudHMqKlxuICogLSBIVFRQIHN0YXR1cyBjb2RlcywgQUkgcHJvdmlkZXIgaWRlbnRpZmllcnMsIHRpbWUgY29uc3RhbnRzXG4gKlxuICogKipTZXJ2aWNlcyoqXG4gKiAtIEludGVybmFsSHR0cENsaWVudCwgY3JlYXRlU2FmZUNsaWVudCDigJQgaW50ZXJuYWwgc2VydmljZS10by1zZXJ2aWNlIEhUVFAgY2xpZW50XG4gKiAtIGNyZWF0ZVF1b3RhU2VydmljZSDigJQgcXVvdGEgZW5mb3JjZW1lbnQgY2xpZW50IGZhY3RvcnlcbiAqIC0gQ2FjaGVTZXJ2aWNlIOKAlCBpbi1tZW1vcnkgVFRMIGNhY2hlXG4gKiAtIENvbXBsaWFuY2VDbGllbnQg4oCUIGNvbXBsaWFuY2Ugc2VydmljZSBjbGllbnRcbiAqIC0gRW50aXR5RXZlbnRFbWl0dGVyIOKAlCBkb21haW4gZXZlbnQgcHViL3N1YlxuICpcbiAqICoqRXJyb3JzKipcbiAqIC0gQXBwRXJyb3IsIE5vdEZvdW5kRXJyb3IsIEZvcmJpZGRlbkVycm9yIOKAlCB0eXBlZCBIVFRQIGVycm9yIGNsYXNzZXNcbiAqXG4gKiAqKlZhbGlkYXRpb24qKlxuICogLSBab2QtYmFzZWQgcmVxdWVzdCB2YWxpZGF0aW9uIHNjaGVtYXMgYW5kIG1pZGRsZXdhcmVcbiAqXG4gKiAqKlJvdXRlcyoqXG4gKiAtIEhlYWx0aCBjaGVjayByb3V0ZSBmYWN0b3J5XG4gKlxuICogKipPcGVuQVBJKipcbiAqIC0gU2NoZW1hIHJlZ2lzdHJ5IGFuZCBzcGVjIGdlbmVyYXRpb25cbiAqL1xuXG4vLyBUeXBlc1xuZXhwb3J0ICogZnJvbSAnLi90eXBlcyc7XG5cbi8vIENvbnN0YW50c1xuZXhwb3J0ICogZnJvbSAnLi9jb25zdGFudHMnO1xuXG4vLyBVdGlsc1xuZXhwb3J0ICogZnJvbSAnLi91dGlscyc7XG5cbi8vIEhlbHBlcnNcbmV4cG9ydCAqIGZyb20gJy4vaGVscGVycyc7XG5cbi8vIFNlcnZpY2VzXG5leHBvcnQgKiBmcm9tICcuL3NlcnZpY2VzJztcblxuLy8gTWlkZGxld2FyZVxuZXhwb3J0ICogZnJvbSAnLi9taWRkbGV3YXJlJztcblxuLy8gUm91dGVzXG5leHBvcnQgKiBmcm9tICcuL3JvdXRlcyc7XG5cbi8vIEVycm9yc1xuZXhwb3J0ICogZnJvbSAnLi9lcnJvcnMnO1xuXG4vLyBWYWxpZGF0aW9uXG5leHBvcnQgKiBmcm9tICcuL3ZhbGlkYXRpb24nO1xuXG4vLyBPcGVuQVBJXG5leHBvcnQgKiBmcm9tICcuL29wZW5hcGknO1xuIl19
@@ -0,0 +1,50 @@
1
+ import { Request, Response, NextFunction } from 'express';
2
+ export interface RequireAuthOptions {
3
+ /**
4
+ * Allow x-org-id/x-org-name headers to override the JWT's organization fields.
5
+ *
6
+ * **SECURITY WARNING:** When enabled, a caller can set `x-org-id` to ANY
7
+ * organization ID, effectively impersonating that org. This MUST only be
8
+ * used on routes that are:
9
+ * 1. Internal service-to-service routes (not exposed to end users)
10
+ * 2. Behind network isolation (container network, VPC, etc.)
11
+ *
12
+ * NEVER enable this on user-facing API routes. If unsure, leave it disabled.
13
+ */
14
+ allowOrgHeaderOverride?: boolean;
15
+ }
16
+ /** JWT auth middleware. Use directly or call with options. */
17
+ export declare function requireAuth(req: Request, res: Response, next: NextFunction): void;
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
+ /**
22
+ * Requires admin role. Use after requireAuth.
23
+ * Permits users whose per-org role is 'admin' or 'owner'.
24
+ */
25
+ export declare function requireAdmin(req: Request, res: Response, next: NextFunction): void;
26
+ /** Organization ID/name that identifies the system (super-admin) tenant. */
27
+ export declare const SYSTEM_ORG_ID: string;
28
+ /**
29
+ * Check if an orgId or orgName matches the system org.
30
+ * Use this instead of comparing directly against SYSTEM_ORG_ID,
31
+ * because the JWT orgId is a database ID (e.g. MongoDB ObjectId)
32
+ * while SYSTEM_ORG_ID is the well-known name "system".
33
+ */
34
+ export declare function isSystemOrgId(orgId?: string, orgName?: string): boolean;
35
+ export declare function isSystemOrg(req: Request): boolean;
36
+ /**
37
+ * Check if the request is from a system admin.
38
+ * A system admin has per-org role 'admin' or 'owner' in the system organization.
39
+ */
40
+ export declare function isSystemAdmin(req: Request): boolean;
41
+ /** Requires system admin (admin role + system organization). */
42
+ export declare function requireSystemAdmin(req: Request, res: Response, next: NextFunction): void;
43
+ /**
44
+ * Require a specific feature flag. Use after requireAuth.
45
+ * Checks the `features` array in the JWT payload (set at token issuance).
46
+ * System org users always pass (all features enabled).
47
+ */
48
+ export declare function requireFeature(feature: string): (req: Request, res: Response, next: NextFunction) => void;
49
+ /** Only system admins can set access to 'public'; everyone else gets 'private'. */
50
+ export declare function resolveAccessModifier(req: Request, requested: string | undefined): 'public' | 'private';